/* Code for the simulated toy machine, a simulated architecture supporting variable-length partitions. THIS CODE IS TAKEN from Professor Ernie Davis with permission. */ #include #include #include #define RAMSIZE 262144 /* 2**18 address space */ #define NUMREGS 16 #define NAMESIZE 32 /* maximum size of process name */ /* Global variables for the simulated architecture --- DO NOT CHANGE */ int mem[RAMSIZE], /* Core memory */ regs[NUMREGS], /* Number of registers */ base, /* Base register */ limit; /* limit register */ char codes[16][4] = /* Abbreviations for opcodes */ { "LOA", "STO", "CPR", "LOI", "STI", "ADD", "SUB", "MUL", "DIV", "ICR", "DCR", "GTR", "JMP", "IFZ", "JMI", "TRP" }; /* Other global variables */ int debug = 0, /* Level of debugging */ error = 0, /* Error flag */ terminate = 0, /* Termination flag */ maxinst = -1, /* Maximum number of instructions */ procindex = 0; /* Index of process */ char procname[NAMESIZE]; /* name of process */ /* Extract the flags from the command line: base, debug, and maxinst. The index of the STM filename in the command is returned as the value. */ int parse_flags(argc,argv) int argc; char *argv[]; { int ibase = 0, idebug = 0, imax=0, ifilename=1; /* Positions of arguments in command line */ int i; for (i=1; i<9; i=i+2) { if (argv[i][0] == '-') switch (argv[i][1]) { case 'b': ibase = i+1; break; case 'd': idebug = i+1; break; case 'm': imax = i+1; break; } else { ifilename = i; break; } } if (ibase) base=atoi(argv[ibase]); if (idebug) debug=atoi(argv[idebug]); if (imax) maxinst=atoi(argv[imax]); return(ifilename); } /* Load the STML code into memory */ /* It is assumed that STML files are correctly formatted; therefore, this does no error checking */ /* NOTE: You are allowed to change this function for project 1; however, there is no need to do so. */ void load_stm(filename) char filename[]; { int count = base, /* Address */ inst; /* Instruction */ char line[240]; /* max length of line in STM file */ int i; FILE *fp; fp = fopen(filename, "r"); /* Open the STM file */ if (fp == NULL) { printf("File name error %s\n", filename); error = 1; } fgets(procname, NAMESIZE, fp); /* read process name */ procname[strlen(procname)-1] = '\0'; /* get rid of carriage return at end */ fgets(line,240,fp); /* read length of partition */ limit=atoi(line); if (debug == 2) { printf("Process %s index %i loading from base %i length %i\n", procname, procindex, base, limit); printf("Physical address / Virtual address / Instruction\n"); } while (!feof(fp)) { /* read code and load into memory */ fgets(line,240,fp); if (isdigit(line[0])) { sscanf(line, "%i", &mem[count]); count++; } } if (debug==2) for (i=base; i= 0) && (reladd < limit)) return(reladd+base); else { error = 1; printf("Error: Address out of bounds\n"); return(0); } } /* Display STM instruction for level-2 debugging */ void show_inst(op, ra, ad, rb, rc, rd) int op, ra, ad, rb, rc, rd; { printf("Process %i %s instruction 0x%X : %3s", procindex, procname, regs[0], codes[op]); switch(op) { case 0: case 1: case 13: printf(" R%i Address 0x%X", ra, ad); break; case 12: printf(" Address 0x%X", ad); break; case 2: case 3: case 4: printf(" R%i R%i", ra, rb); break; case 5: case 6: case 7: case 11: printf(" R%i R%i R%i", ra, rb, rc); break; case 8: printf(" R%i R%i R%i R%i", ra, rb, rc, rd); break; case 9: case 10: case 14: printf(" R%i ", ra); break; } printf("\n"); } /* Decompose an STM instruction into its components */ /* Note: This is considered part of the "hardware" of the virtual machine. You may not change it in any of the projects. */ void get_inst(inst, pop, pra, pad, prb, prc, prd) int inst, *pop, *pra, *pad, *prb, *prc, *prd; { *pop = inst % 16; inst = inst / 16; *pra = inst % 16; inst = inst / 16; *pad = inst % RAMSIZE; *prb = inst % 16; inst = inst / 16; *prc = inst % 16; inst = inst / 16; *prd = inst % 16; if (debug == 2) show_inst(*pop, *pra, *pad, *prb, *prc, *prd); } /* Execute an STM instruction. This is what does the actual work of carrying out the STM code */ /* Note: This is considered part of the "hardware" of the virtual machine. You may not change it in any of the projects. */ int exec_inst(op, ra, ad, rb, rc, rd) int op, ra, ad, rb, rc, rd; { int regrep = 0; /* Flag for repeated registers */ int trap = 0; switch (op) { case 0: regs[ra] = mem[phys_address(ad)]; break; case 1: mem[phys_address(ad)] = regs[ra]; break; case 2: regs[ra] = regs[rb]; break; case 3: regs[ra] = mem[phys_address(regs[rb])]; break; case 4: mem[phys_address(regs[ra])] = regs[rb]; break; case 5: regs[rc] = regs[ra] + regs[rb]; break; case 6: regs[rc] = regs[ra] - regs[rb]; break; case 7: regs[rc] = regs[ra] * regs[rb]; break; case 8: if (regs[rb] == 0) { printf("Arithmetic error: Divide by zero\n"); error = 1; } else { regs[rc] = regs[ra] / regs[rb]; regs[rd] = regs[ra] % regs[rb]; } break; case 9: regs[ra]++; break; case 10: regs[ra]--; break; case 11: regs[rc] = (regs[ra] > regs[rb]); break; case 12: regs[0] = ad; break; case 13: if (regs[ra] == 0) regs[0] = ad; break; case 14: regs[0] = regs[ra]; break; case 15: trap = 1; break; } return(trap); } /* Execute a trap */ void exec_trap() { int iread; if (debug) printf("Process %s index %i Trap: ", procname, procindex); switch(regs[15]) { case 0: terminate=1; if (debug) printf(" Terminate\n"); break; case 1: if (debug) printf(" Read\n"); iread = scanf("%i",®s[14]); if (debug) printf(" READ %i\n", regs[14]); if (iread ==1) regs[13]=1; else if (iread==EOF) regs[13]=0; else error=1; break; case 2: if (debug) printf("\n WRITE: "); printf("%i \n",regs[14]); break; default: printf("Invalid trap code\n"); error=1; break; } } /* fetch and execute an instruction of STM code */ void exec_stm() { int opcode, rega, ad, regb, regc, regd; /* Components of STML instruction */ int trap; /* flag that code executes a trap */ int padd; /* physical address */ int i; padd=phys_address(regs[0]); if (debug == 2) { printf("Registers: "); for (i=0; i<16; i++) printf(" %3i", regs[i]); printf("\n"); printf("address 0x%X instruction 0x%X\n", regs[0], mem[padd]); } get_inst(mem[padd], &opcode, ®a, &ad, ®b, ®c, ®d); /* fetch instruction */ if (!error) { regs[0]++; /* increment PC */ if (regs[0] >= limit) error=1; else { trap = exec_inst(opcode, rega, ad, regb, regc, regd); /*execute*/ if (trap) exec_trap(); /* handle trap */ } } } /* main: initialize, load, execute */ int main(argc, argv) int argc; char *argv[]; { int i; initialize(argc,argv); for (i=0; !error && !terminate && (i != maxinst); i++) exec_stm(); return 0; }