From bdcb29dbd005e587fc4cdfe6361c0eb727f905ae Mon Sep 17 00:00:00 2001 From: tzlil Date: Tue, 31 Oct 2023 19:40:36 +0200 Subject: runhaskell Simulator.hs < program.mc --- assembler.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ compiler.c | 333 ------------------------------------------------------------ program.mc | 10 ++ 3 files changed, 343 insertions(+), 333 deletions(-) create mode 100644 assembler.c delete mode 100644 compiler.c create mode 100644 program.mc diff --git a/assembler.c b/assembler.c new file mode 100644 index 0000000..18983be --- /dev/null +++ b/assembler.c @@ -0,0 +1,333 @@ +/* Assembler for LC */ + +#include +#include +#include +#define MAXLINELENGTH 1000 +#define MAXNUMLABELS 65536 +#define MAXLABELLENGTH 7 /* includes the null character termination */ + +#define ADD 0 +#define NAND 1 +#define LW 2 +#define SW 3 +#define BEQ 4 +#define JALR 5 +#define HALT 6 +#define NOOP 7 + +/* + * Read and parse a line of the assembly-language file. Fields are returned + * in label, opcode, arg0, arg1, arg2 (these strings must have memory already + * allocated to them). + * + * Return values: + * 0 if reached end of file + * 1 if all went well + * + * exit(1) if line is too long. + */ +int +readAndParse(FILE *inFilePtr, char *label, char *opcode, char *arg0, + char *arg1, char *arg2) +{ + char line[MAXLINELENGTH]; + char *ptr = line; + + /* delete prior values */ + label[0] = opcode[0] = arg0[0] = arg1[0] = arg2[0] = '\0'; + + /* read the line from the assembly-language file */ + if (fgets(line, MAXLINELENGTH, inFilePtr) == NULL) { + /* reached end of file */ + return(0); + } + + /* check for line too long */ + if (strlen(line) == MAXLINELENGTH-1) { + printf("error: line too long\n"); + exit(1); + } + + /* is there a label? */ + ptr = line; + if (sscanf(ptr, "%[^\t\n ]", label)) { + /* successfully read label; advance pointer over the label */ + ptr += strlen(label); + } + + /* + * Parse the rest of the line. Would be nice to have real regular + * expressions, but scanf will suffice. + */ + sscanf(ptr, "%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]", + opcode, arg0, arg1, arg2); + return(1); +} + +int +translateSymbol(char labelArray[MAXNUMLABELS][MAXLABELLENGTH], + int labelAddress[MAXNUMLABELS], int numLabels, char *symbol) +{ + int i; + + /* search through address label table */ + for (i=0; i=numLabels) { + printf("error: missing label %s\n", symbol); + exit(1); + } + + return(labelAddress[i]); +} + +int +isNumber(char *string) +{ + /* return 1 if string is a number */ + int i; + return( (sscanf(string, "%d", &i)) == 1); +} + +/* + * Test register argument; make sure it's in range and has no bad characters. + */ +void +testRegArg(char *arg) +{ + int num; + char c; + + if (atoi(arg) < 0 || atoi(arg) > 7) { + printf("error: register out of range\n"); + exit(2); + } + if (sscanf(arg, "%d%c", &num, &c) != 1) { + printf("bad character in register argument\n"); + exit(2); + } +} + +/* + * Test addressField argument. + */ +void +testAddrArg(char *arg) +{ + int num; + char c; + + /* test numeric addressField */ + if (isNumber(arg)) { + if (sscanf(arg, "%d%c", &num, &c) != 1) { + printf("bad character in addressField\n"); + exit(2); + } + } +} + +/* + * main function + */ +int +main(int argc, char *argv[]) +{ + char *inFileString, *outFileString; + FILE *inFilePtr, *outFilePtr; + int address; + char label[MAXLINELENGTH], opcode[MAXLINELENGTH], arg0[MAXLINELENGTH], + arg1[MAXLINELENGTH], arg2[MAXLINELENGTH], argTmp[MAXLINELENGTH]; + int i; + int numLabels=0; + int num; + int addressField; + + char labelArray[MAXNUMLABELS][MAXLABELLENGTH]; + int labelAddress[MAXNUMLABELS]; + + if (argc != 3) { + printf("error: usage: %s \n", + argv[0]); + exit(1); + } + + inFileString = argv[1]; + outFileString = argv[2]; + + inFilePtr = fopen(inFileString, "r"); + if (inFilePtr == NULL) { + printf("error in opening %s\n", inFileString); + exit(1); + } + outFilePtr = fopen(outFileString, "w"); + if (outFilePtr == NULL) { + printf("error in opening %s\n", outFileString); + exit(1); + } + + /* map symbols to addresses */ + + /* assume address start at 0 */ + for (address=0; readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2); + address++) { + /* + printf("%d: label=%s, opcode=%s, arg0=%s, arg1=%s, arg2=%s\n", + address, label, opcode, arg0, arg1, arg2); + */ + + /* check for illegal opcode */ + if (strcmp(opcode, "add") && strcmp(opcode, "nand") && + strcmp(opcode, "lw") && strcmp(opcode, "sw") && + strcmp(opcode, "beq") && strcmp(opcode, "jalr") && + strcmp(opcode, "halt") && strcmp(opcode, "noop") && + strcmp(opcode, ".fill") ) { + printf("error: unrecognized opcode %s at address %d\n", opcode, + address); + exit(1); + } + + /* check register fields */ + if (!strcmp(opcode, "add") || !strcmp(opcode, "nand") || + !strcmp(opcode, "lw") || !strcmp(opcode, "sw") || + !strcmp(opcode, "beq") || !strcmp(opcode, "jalr")) { + testRegArg(arg0); + testRegArg(arg1); + } + if (!strcmp(opcode, "add") || !strcmp(opcode, "nand")) { + testRegArg(arg2); + } + + /* check addressField */ + if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") || + !strcmp(opcode, "beq")) { + testAddrArg(arg2); + } + if (!strcmp(opcode, ".fill")) { + testAddrArg(arg0); + } + + /* check for enough arguments */ + if ( (strcmp(opcode, "halt") && strcmp(opcode, "noop") && + strcmp(opcode, ".fill") && strcmp(opcode, "jalr") + && arg2[0]=='\0') || + (!strcmp(opcode, "jalr") && arg1[0]=='\0') || + (!strcmp(opcode, ".fill") && arg0[0]=='\0')) { + printf("error at address %d: not enough arguments\n", address); + exit(2); + } + + if (label[0] != '\0') { + /* check for labels that are too long */ + if (strlen(label) >= MAXLABELLENGTH) { + printf("label too long\n"); + exit(2); + } + + /* make sure label starts with letter */ + if (! sscanf(label, "%[a-zA-Z]", argTmp) ) { + printf("label doesn't start with letter\n"); + exit(2); + } + + /* make sure label consists of only letters and numbers */ + sscanf(label, "%[a-zA-Z0-9]", argTmp); + if (strcmp(argTmp, label)) { + printf("label has character other than letters and numbers\n"); + exit(2); + } + + /* look for duplicate label */ + for (i=0; i= MAXNUMLABELS) { + printf("error: too many labels (label=%s)\n", label); + exit(2); + } + + strcpy(labelArray[numLabels], label); + labelAddress[numLabels++] = address; + } + } + + for (i=0; i 32767) { + printf("error: offset %d out of range\n", addressField); + exit(1); + } + + /* truncate the offset field, in case it's negative */ + addressField = addressField & 0xFFFF; + + if (!strcmp(opcode, "beq")) { + num = (BEQ << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) + | addressField; + } else { + /* lw or sw */ + if (!strcmp(opcode, "lw")) { + num = (LW << 22) | (atoi(arg0) << 19) | + (atoi(arg1) << 16) | addressField; + } else { + num = (SW << 22) | (atoi(arg0) << 19) | + (atoi(arg1) << 16) | addressField; + } + } + } else if (!strcmp(opcode, ".fill")) { + if (!isNumber(arg0)) { + num = translateSymbol(labelArray, labelAddress, numLabels, + arg0); + } else { + num = atoi(arg0); + } + } + /* printf("(address %d): %d (hex 0x%x)\n", address, num, num); */ + fprintf(outFilePtr, "%d\n", num); + } + + exit(0); +} + diff --git a/compiler.c b/compiler.c deleted file mode 100644 index 18983be..0000000 --- a/compiler.c +++ /dev/null @@ -1,333 +0,0 @@ -/* Assembler for LC */ - -#include -#include -#include -#define MAXLINELENGTH 1000 -#define MAXNUMLABELS 65536 -#define MAXLABELLENGTH 7 /* includes the null character termination */ - -#define ADD 0 -#define NAND 1 -#define LW 2 -#define SW 3 -#define BEQ 4 -#define JALR 5 -#define HALT 6 -#define NOOP 7 - -/* - * Read and parse a line of the assembly-language file. Fields are returned - * in label, opcode, arg0, arg1, arg2 (these strings must have memory already - * allocated to them). - * - * Return values: - * 0 if reached end of file - * 1 if all went well - * - * exit(1) if line is too long. - */ -int -readAndParse(FILE *inFilePtr, char *label, char *opcode, char *arg0, - char *arg1, char *arg2) -{ - char line[MAXLINELENGTH]; - char *ptr = line; - - /* delete prior values */ - label[0] = opcode[0] = arg0[0] = arg1[0] = arg2[0] = '\0'; - - /* read the line from the assembly-language file */ - if (fgets(line, MAXLINELENGTH, inFilePtr) == NULL) { - /* reached end of file */ - return(0); - } - - /* check for line too long */ - if (strlen(line) == MAXLINELENGTH-1) { - printf("error: line too long\n"); - exit(1); - } - - /* is there a label? */ - ptr = line; - if (sscanf(ptr, "%[^\t\n ]", label)) { - /* successfully read label; advance pointer over the label */ - ptr += strlen(label); - } - - /* - * Parse the rest of the line. Would be nice to have real regular - * expressions, but scanf will suffice. - */ - sscanf(ptr, "%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]%*[\t\n\r ]%[^\t\n\r ]", - opcode, arg0, arg1, arg2); - return(1); -} - -int -translateSymbol(char labelArray[MAXNUMLABELS][MAXLABELLENGTH], - int labelAddress[MAXNUMLABELS], int numLabels, char *symbol) -{ - int i; - - /* search through address label table */ - for (i=0; i=numLabels) { - printf("error: missing label %s\n", symbol); - exit(1); - } - - return(labelAddress[i]); -} - -int -isNumber(char *string) -{ - /* return 1 if string is a number */ - int i; - return( (sscanf(string, "%d", &i)) == 1); -} - -/* - * Test register argument; make sure it's in range and has no bad characters. - */ -void -testRegArg(char *arg) -{ - int num; - char c; - - if (atoi(arg) < 0 || atoi(arg) > 7) { - printf("error: register out of range\n"); - exit(2); - } - if (sscanf(arg, "%d%c", &num, &c) != 1) { - printf("bad character in register argument\n"); - exit(2); - } -} - -/* - * Test addressField argument. - */ -void -testAddrArg(char *arg) -{ - int num; - char c; - - /* test numeric addressField */ - if (isNumber(arg)) { - if (sscanf(arg, "%d%c", &num, &c) != 1) { - printf("bad character in addressField\n"); - exit(2); - } - } -} - -/* - * main function - */ -int -main(int argc, char *argv[]) -{ - char *inFileString, *outFileString; - FILE *inFilePtr, *outFilePtr; - int address; - char label[MAXLINELENGTH], opcode[MAXLINELENGTH], arg0[MAXLINELENGTH], - arg1[MAXLINELENGTH], arg2[MAXLINELENGTH], argTmp[MAXLINELENGTH]; - int i; - int numLabels=0; - int num; - int addressField; - - char labelArray[MAXNUMLABELS][MAXLABELLENGTH]; - int labelAddress[MAXNUMLABELS]; - - if (argc != 3) { - printf("error: usage: %s \n", - argv[0]); - exit(1); - } - - inFileString = argv[1]; - outFileString = argv[2]; - - inFilePtr = fopen(inFileString, "r"); - if (inFilePtr == NULL) { - printf("error in opening %s\n", inFileString); - exit(1); - } - outFilePtr = fopen(outFileString, "w"); - if (outFilePtr == NULL) { - printf("error in opening %s\n", outFileString); - exit(1); - } - - /* map symbols to addresses */ - - /* assume address start at 0 */ - for (address=0; readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2); - address++) { - /* - printf("%d: label=%s, opcode=%s, arg0=%s, arg1=%s, arg2=%s\n", - address, label, opcode, arg0, arg1, arg2); - */ - - /* check for illegal opcode */ - if (strcmp(opcode, "add") && strcmp(opcode, "nand") && - strcmp(opcode, "lw") && strcmp(opcode, "sw") && - strcmp(opcode, "beq") && strcmp(opcode, "jalr") && - strcmp(opcode, "halt") && strcmp(opcode, "noop") && - strcmp(opcode, ".fill") ) { - printf("error: unrecognized opcode %s at address %d\n", opcode, - address); - exit(1); - } - - /* check register fields */ - if (!strcmp(opcode, "add") || !strcmp(opcode, "nand") || - !strcmp(opcode, "lw") || !strcmp(opcode, "sw") || - !strcmp(opcode, "beq") || !strcmp(opcode, "jalr")) { - testRegArg(arg0); - testRegArg(arg1); - } - if (!strcmp(opcode, "add") || !strcmp(opcode, "nand")) { - testRegArg(arg2); - } - - /* check addressField */ - if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") || - !strcmp(opcode, "beq")) { - testAddrArg(arg2); - } - if (!strcmp(opcode, ".fill")) { - testAddrArg(arg0); - } - - /* check for enough arguments */ - if ( (strcmp(opcode, "halt") && strcmp(opcode, "noop") && - strcmp(opcode, ".fill") && strcmp(opcode, "jalr") - && arg2[0]=='\0') || - (!strcmp(opcode, "jalr") && arg1[0]=='\0') || - (!strcmp(opcode, ".fill") && arg0[0]=='\0')) { - printf("error at address %d: not enough arguments\n", address); - exit(2); - } - - if (label[0] != '\0') { - /* check for labels that are too long */ - if (strlen(label) >= MAXLABELLENGTH) { - printf("label too long\n"); - exit(2); - } - - /* make sure label starts with letter */ - if (! sscanf(label, "%[a-zA-Z]", argTmp) ) { - printf("label doesn't start with letter\n"); - exit(2); - } - - /* make sure label consists of only letters and numbers */ - sscanf(label, "%[a-zA-Z0-9]", argTmp); - if (strcmp(argTmp, label)) { - printf("label has character other than letters and numbers\n"); - exit(2); - } - - /* look for duplicate label */ - for (i=0; i= MAXNUMLABELS) { - printf("error: too many labels (label=%s)\n", label); - exit(2); - } - - strcpy(labelArray[numLabels], label); - labelAddress[numLabels++] = address; - } - } - - for (i=0; i 32767) { - printf("error: offset %d out of range\n", addressField); - exit(1); - } - - /* truncate the offset field, in case it's negative */ - addressField = addressField & 0xFFFF; - - if (!strcmp(opcode, "beq")) { - num = (BEQ << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) - | addressField; - } else { - /* lw or sw */ - if (!strcmp(opcode, "lw")) { - num = (LW << 22) | (atoi(arg0) << 19) | - (atoi(arg1) << 16) | addressField; - } else { - num = (SW << 22) | (atoi(arg0) << 19) | - (atoi(arg1) << 16) | addressField; - } - } - } else if (!strcmp(opcode, ".fill")) { - if (!isNumber(arg0)) { - num = translateSymbol(labelArray, labelAddress, numLabels, - arg0); - } else { - num = atoi(arg0); - } - } - /* printf("(address %d): %d (hex 0x%x)\n", address, num, num); */ - fprintf(outFilePtr, "%d\n", num); - } - - exit(0); -} - diff --git a/program.mc b/program.mc new file mode 100644 index 0000000..8f5e3ec --- /dev/null +++ b/program.mc @@ -0,0 +1,10 @@ +8454151 +9043971 +655361 +16842754 +16842749 +29360128 +25165824 +5 +-1 +2 -- cgit 1.4.1