#include #include #define MAXLINELENGTH 1000 #define MAXNUMLABELS 10000 #define MAXLABELLENGTH 16 #define OP_SHIFT 13 #define A_SHIFT 10 #define B_SHIFT 7 #define ADD 0 #define ADDI 1 #define NAND 2 #define LUI 3 #define SW 4 #define LW 5 #define BEQ 6 #define JALR 7 #define EXT 7 // EXTENDED overlapped with JALR char * readAndParse(FILE *, char *, char **, char **, char **, char **, char **); int isNumber(char *); #define ntoi(str) strtol(str, NULL, 0) char Labels[MAXNUMLABELS][MAXLABELLENGTH]; short Addresses[MAXNUMLABELS]; short NumValidLabels=0; #define MAX_ARGUMENTS 3 #define MAX_INSTYPES 3 char *formats[ MAX_INSTYPES ][ 16 ] = { { "three-operand", "three-operand", "three-operand", "add", "addi", "nand", "lw", "sw", "beq", NULL, }, { "two-operand", "two-operand", NULL, "jalr" "lui", "lli", "movi", NULL, }, { "one-operand", NULL, NULL, ".fill", ".space", "sys", "exc", NULL, }, }; enum extended_types { EXT_NONE, EXT_SYSCALL, EXT_MFSPR, EXT_MTSPR, EXT_RFU1, EXT_RFU2, EXT_RFU3, EXT_EXCEPTION, }; enum exception_types { EXC_NONE, EXC_HALT, EXC_TLBMISS, EXC_SIGSEGV, EXC_INVALID, }; short get_label_address(s) char *s; { int i; for (i=0; i 7) { fprintf(stderr, "error: register value [%s/%hd] out of range\n", s, reg); exit(0); } return (short)(reg & 0x7); } short imm(s) char *s; { short imm; /* if s is symbolic, then translate into an address */ if (isNumber(s)) { imm = ntoi(s); } else { imm = get_label_address(s); } if (imm < -64 || imm > 63) { fprintf(stderr, "error: offset %hd out of range\n", imm); exit(1); } return imm & 0x7f; } short raw(s) char *s; { short imm; /* if s is symbolic, then translate into an address */ if (isNumber(s)) { imm = ntoi(s); } else { imm = get_label_address(s); } return imm; } main(int argc, char *argv[]) { char *inFileString, *outFileString; FILE *inFilePtr, *outFilePtr; short address; char *label, *opcode, *arg0, *arg1, *arg2; char *statusString; char lineString[MAXLINELENGTH+1]; short i,j; short num; short immediateValue; if (argc != 3) { fprintf(stderr, "error: usage: %s \n", argv[0]); exit(1); } inFileString = argv[1]; outFileString = argv[2]; inFilePtr = fopen(inFileString, "r"); if (inFilePtr == NULL) { fprintf(stderr, "error in opening %s\n", inFileString); exit(1); } outFilePtr = fopen(outFileString, "w"); if (outFilePtr == NULL) { fprintf(stderr, "error in opening %s\n", outFileString); exit(1); } /* PASS ONE -- map symbols to addresses */ /* assume address start at 0 */ address = 0; while(readAndParse(inFilePtr, lineString, &label, &opcode, &arg0, &arg1, &arg2) != NULL) { for (i=0; i= MAXNUMLABELS) { /* we will exceed the size of the array */ fprintf(stderr, "error: too many labels (label=%s)\n", label); exit(1); } if (strlen(label) >= MAXLABELLENGTH) { /* we will exceed the size of the label storage */ fprintf(stderr, "error: label [%s] too long (max: %d chars)\n", label, MAXLABELLENGTH-1); exit(1); } strcpy(Labels[NumValidLabels], label); Addresses[NumValidLabels] = address; NumValidLabels++; } else { /* duplicate label -- terminate */ fprintf(stderr, "error: duplicate label %s \n", label); exit(1); } } if (!strcmp(opcode, "movi")) { address+=2; } else if (!strcmp(opcode, ".space")) { if (isNumber(arg0)) { address += ntoi(arg0); } else { fprintf(stderr, "error: .space needs integer argument\n"); exit(1); } } else { address++; } } /* PASS TWO -- print machine code, with symbols filled in as addresses */ rewind(inFilePtr); address = 0; while(readAndParse(inFilePtr, lineString, &label, &opcode, &arg0, &arg1, &arg2) != NULL) { if (!strcmp(opcode, "add")) { num = (ADD << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT) | reg(arg2); } else if (!strcmp(opcode, "addi")) { num = (ADDI << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT) | imm(arg2); } else if (!strcmp(opcode, "nand")) { num = (NAND << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT) | reg(arg2); } else if (!strcmp(opcode, "lui")) { num = (LUI << OP_SHIFT) | (reg(arg0) << A_SHIFT) | ((raw(arg1) >> 6) & 0x3ff); } else if (!strcmp(opcode, "lw")) { num = (LW << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT) | imm(arg2); } else if (!strcmp(opcode, "sw")) { num = (SW << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT) | imm(arg2); } else if (!strcmp(opcode, "jalr")) { num = (JALR << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT); } else if (!strcmp(opcode, "beq")) { /* if arg2 is symbolic, then translate into an address */ if (isNumber(arg2)) { immediateValue = ntoi(arg2); } else { immediateValue = get_label_address(arg2) - address - 1; } if (immediateValue < -64 || immediateValue > 63) { fprintf(stderr, "error: offset %hd out of range\n", immediateValue); exit(1); } num = (BEQ << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg1) << B_SHIFT) | (immediateValue & 0x7f); } else if (!strcmp(opcode, "nop")) { num = (ADD << OP_SHIFT) | (reg("0") << A_SHIFT) | (reg("0") << B_SHIFT) | reg("0"); } else if (!strcmp(opcode, "halt")) { num = (EXT << OP_SHIFT) | (reg("0") << A_SHIFT) | (reg("0") << B_SHIFT) | (EXT_EXCEPTION << 4) | EXC_HALT; } else if (!strcmp(opcode, "sys")) { num = (EXT << OP_SHIFT) | (reg("0") << A_SHIFT) | (reg("0") << B_SHIFT) | (EXT_SYSCALL << 4) | (raw(arg0) & 0xf); } else if (!strcmp(opcode, "exc")) { num = (EXT << OP_SHIFT) | (reg("0") << A_SHIFT) | (reg("0") << B_SHIFT) | (EXT_EXCEPTION << 4) | (raw(arg0) & 0xf); } else if (!strcmp(opcode, "lli")) { num = (ADDI << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg0) << B_SHIFT) | (raw(arg1) & 0x3f); } else if (!strcmp(opcode, "movi")) { num = (LUI << OP_SHIFT) | (reg(arg0) << A_SHIFT) | ((raw(arg1) >> 6) & 0x3ff); fprintf(outFilePtr, "%04hx\n", num); address++; num = (ADDI << OP_SHIFT) | (reg(arg0) << A_SHIFT) | (reg(arg0) << B_SHIFT) | (raw(arg1) & 0x3f); } else if (!strcmp(opcode, ".fill")) { num = raw(arg0); } else if (!strcmp(opcode, ".space")) { i = raw(arg0); num = 0; if (i > 1) { for ( ; i>1; i--) { fprintf(outFilePtr, "%04hx\n", num); address++; } } else if (i <= 0) { fprintf(stderr, "error: argument %hd out of range for .space\n", i); exit(1); } /* this falls through for the last 0 value printed out */ } else { fprintf(stderr, "error: unrecognized opcode [%s] at address %d\n", opcode, address); exit(1); } fprintf(outFilePtr, "%04hx\n", num); address++; } } char * readAndParse(FILE *inFilePtr, char *lineString, char **labelPtr, char **opcodePtr, char **arg0Ptr, char **arg1Ptr, char **arg2Ptr) { /* read and parse a line note that lineString must point to allocated memory, so that *labelPtr, *opcodePtr, and *argXPtr won't be pointing to readAndParse's memory also note that *labelPtr, *opcodePtr, and *argXPtr only point to memory in lineString. When lineString changes, so will *labelPtr, *opcodePtr, and *argXPtr returns NULL if at end-of-file */ char *statusString, *firsttoken; statusString = fgets(lineString, MAXLINELENGTH, inFilePtr); if (statusString != NULL) { firsttoken = strtok(lineString, " \t\n"); if (firsttoken == NULL || firsttoken[0] == '#') { return readAndParse(inFilePtr, lineString, labelPtr, opcodePtr, arg0Ptr, arg1Ptr, arg2Ptr); } else if (firsttoken[strlen(firsttoken) - 1] == ':') { *labelPtr = firsttoken; *opcodePtr = strtok(NULL, " \t\n"); firsttoken[strlen(firsttoken) - 1] = '\0'; } else { *labelPtr = NULL; *opcodePtr = firsttoken; } *arg0Ptr = strtok(NULL, ", \t\n"); *arg1Ptr = strtok(NULL, ", \t\n"); *arg2Ptr = strtok(NULL, ", \t\n"); } return(statusString); } int isNumber(char *string) { /* return 1 if string is a number */ int i; return( (sscanf(string, "%d", &i)) == 1); }