/* sim4.c - replace acc and ip with ten general registers %r0 to %r9 */ /* Last modified on June 29, 2012 */ /* usage "sim4 < test.sim4", up to 100 cycles with trace */ #include /* printf() function available */ #include /* exit() function declared */ #define MEMSIZE 1000 /* 1000 words of memory */ #define WORDSIZE 4 /* each word is 4 digits */ #define WORDLIMIT 9999 /* change this if you change WORDSIZE */ #define MAXCNT 1000 /* limit execution to 1000 instructions */ /* SIM1 operation codes (plus JMP) with format naaa where */ /* aaa is a 3-digit address and n is as follows: */ #define HALT 0 /* halt processor */ #define LD 1 /* load %r0 (%r0=M[aaa]) */ #define ST 2 /* store %r0 (M[aaa]=%r0) */ #define ADD 3 /* add to %r0 (%r0=%r0+M[aaa]) */ #define SUB 4 /* sub from %r0 (%r0=%r0-M[aaa]) */ #define LDA 5 /* load address (%r0=aaa) */ #define JMP 6 /* jump (branch) to address */ #define SKIPSET 7 /* skip instructions */ #define ONEREG 8 /* one register instructions */ #define TWOREG 9 /* two register instructions */ /* SIM2 skip operation codes with format 7n0r where r is a general */ /* register and n is as follows: */ #define SKIP 0 /* unconditional skip */ #define SKEQ 1 /* skip if %r equals 0 */ #define SKNE 2 /* skip if %r not equal to 0 */ #define SKGT 3 /* skip if %r greater than 0 */ #define SKGE 4 /* skip if %r greater or equal to 0 */ #define SKLT 5 /* skip if %r less than 0 */ #define SKLE 6 /* skip if %r less than or equal to 0 */ /* One register operation codes (format 8n0r, where r is a general */ /* register (%r0 to %r9) and n is as follows: */ #define IN 0 /* input a 4-digit number into %r */ #define OUT 1 /* output the 4-digit number from %r */ #define CLR 2 /* clear register r (%r = 0) */ #define INC 3 /* increment (add 1) to %r (%r++) */ #define DEC 4 /* decrement (subtract 1) from %r */ #define NEG 5 /* negate %rn (%r = -%r) */ #define SHFTL 6 /* shift %r left (%r=%r*10) */ #define SHFTR 7 /* shift %r right (%r=%r/10) */ /* return is (pop %r9) */ /* Two register operation codes %r0 to %r9 (%r0=acc,%r7=sp,%r8=lk,%r9=ip) */ /* with format 9nsd, where: */ /* s is the first (source) general register */ /* d is the second (destination) register */ /* n is as follows */ #define MVRR 0 /* load from register, Rs => Rd */ #define MVMR 1 /* load using reg addr, memory(Rs) => Rd */ #define MVRM 2 /* store using reg adr, Rs => memory(Rd) */ #define EXCH 3 /* exchange values in Rs and Rd, Rs <=> Rd */ #define ADDR 4 /* add register, Rs + Rd => Rd */ #define SUBR 5 /* subtract register, Rd - Rs => Rd */ /* function declarations */ void panic(char *pmessage); /* found impossible condition, C code broken */ void trace(); /* output a trace line */ void readcode(); /* input a machine language program */ void fetch(); /* fetch a machine language instruction */ void execute(); /* execute a machine language instruction */ void skipop(); /* process skip operation codes */ void onereg(); /* process one-register operation codes */ void tworeg(); /* process two-register opcodes */ /* external variables (declared outside any function, available to all) */ int memory[MEMSIZE]; int regs[10]; int inst, cnt; int digit1, digit2, digit3, digit4, digit234; /* Start of main program (where execution begins) */ int main(int argc, char *argv[]) { int i; /* local variables known only in main() */ /* Initialize memory and processor registers */ for (i = 0; i < MEMSIZE; i++) { memory[i]=0; } for (i = 0; i < 10; i++) { regs[i]=0; } cnt = 0; /* number of instructions executed so far */ readcode(); /* input a SIM4 machine language program */ /* Main loop - fetch next instruction, decode, and execute */ while (++cnt <= MAXCNT) { /* limit execution to MAXCNT instructions */ fetch(); execute(); } /* end of while loop */ /* Normal exit is via HALT instruction, only reach here if cnt >= MAXCNT */ printf("Processor executed more than %d instructions\n", MAXCNT); trace(); exit(1); } /* end of main() */ /* Fetch instruction from memory and update program counter */ void fetch() { if ( (regs[9] < 0) || (regs[9] > 999) ) /* 0 <= ip <= 999 or panic */ panic("%r9 out of range"); inst = memory[regs[9]]; /* get instruction from memory */ if ( (inst < 0) || (inst > 9999) ) /* 0 <= mem <= 9999 or panic */ panic("memory value out of range"); trace(); regs[9] = (regs[9]+1)%MEMSIZE; /* increment ip (wrap if > 999) */ /* Break apart the machine language instruction into digits */ digit4 = inst%10; /* if inst = 5678, digit4 = 8 */ digit3 = (inst/10)%10; /* digit3 = 7 */ digit2 = (inst/100)%10; /* digit2 = 6 */ digit1 = inst/1000; /* digit1 = 5 */ digit234 = inst - 1000*digit1; /* and digit234 = 678 */ } /* end of fetch() */ /* Process opcodes 0 to 9 with switch statement */ void execute() { int temp; switch ( digit1 ) { case HALT: /* HALT instruction */ printf("Processor executed HALT instruction\n"); trace(); exit(0); case LD: /* load %r0 */ regs[0] = memory[digit234]; break; case ST: /* store %r0 */ memory[digit234] = regs[0]; break; case ADD: /* add to %r0 */ regs[0] = regs[0] + memory[digit234]; regs[0] = regs[0] % (WORDLIMIT + 1); /* wrap if regs[0] > 9999 */ break; case SUB: /* subtract from %r0 */ temp = (WORDLIMIT+1) - memory[digit234]; /* negate */ regs[0] = regs[0] + temp; /* and add */ regs[0] = regs[0] % (WORDLIMIT+1); /* wrap if %r0 > 9999 */ break; case LDA: /* load address into %r0 */ regs[0] = digit234; break; case JMP: /* jump instruction */ regs[9] = digit234; break; case SKIPSET: /* skip instructions */ skipop(); break; case ONEREG: /* one register inst */ onereg(); break; case TWOREG: /* two register inst */ tworeg(); break; default: /* should never get here */ printf("Illegal operation code, instruction %i \n", inst); trace(); exit(1); } /* end of switch ( digit1 ) */ return; } /* end of execute */ /* process "skip" instructions with format 7n0r where r is the */ /* register we are testing and n equals digit2 */ void skipop() { int reg; /* local variable */ if (digit3 != 0) { printf("Illegal skip instruction, instruction %i \n", inst); trace(); exit(1); } reg = regs[digit4]; /* register we are testing */ switch ( digit2 ) { case SKIP: /* unconditional skip */ regs[9] = regs[9] + 1; break; case SKEQ: /* skip if reg == 0 */ if (reg == 0) regs[9] = regs[9] + 1; break; case SKNE: /* skip if reg != 0 */ if (reg != 0) regs[9] = regs[9] + 1; break; case SKGT: /* skip if reg > 0 (0001-4999) */ if (reg > 0 && reg < 5000) regs[9] = regs[9] + 1; break; case SKGE: /* skip if reg >= 0 (0000-4999) */ if (reg >= 0 && reg < 5000) regs[9] = regs[9] + 1; break; case SKLT: /* skip if reg < 0 (5000-9999) */ if (reg >= 5000) regs[9] = regs[9] + 1; break; case SKLE: /* skip if reg <= 0 (5000-0000) */ if (reg >= 5000 || reg == 0) regs[9] = regs[9] + 1; break; default: printf("Illegal skip code, instruction %i \n", inst); trace(); exit(1); } /* end of "8n0x" switch */ regs[9] = regs[9] % MEMSIZE; /* wrap if regs[9] > 999 */ return; /* finished processing legal skip instruction */ } /* end of skipop() */ /* single register operation codes (format 8n0r) */ /* process register instructions with format 8n0r where r is */ /* the register being used and n specifies the instruction. */ void onereg() { int reg; /* local variable for register value */ if (digit3 != 0) { printf("Illegal single register instruction %i \n", inst); trace(); exit(1); } reg = regs[digit4]; switch ( digit2 ) { case IN: /* input a four digit number to reg */ printf("Input a 4-digit number - "); if (scanf("%i", ®) < 1) { printf("\nEOF on input, exiting\n"); trace(); exit(1); } if ( (reg < 0) || (reg > WORDLIMIT) ) { printf("\nIllegal input value of %d, exiting\n", reg); trace(); exit(1); } printf("%d\n", reg); regs[digit4] = reg; break; case OUT: /* output a four digit number from reg */ printf("Output from program - %4.4i\n", reg); break; case CLR: /* clear (zero) reg */ regs[digit4] = 0; break; case INC: /* increment reg */ regs[digit4] = (reg + 1) % (WORDLIMIT+1); break; case DEC: /* reg--, e.g. (1234+9999) mod 1000 = 1233 */ regs[digit4] = (reg + WORDLIMIT) % (WORDLIMIT + 1); break; case NEG: /* -reg, e.g. (10000-9999) mod 10000 = 0001 */ reg = (WORDLIMIT+1) - reg; /* (10000-0000) mod 10000 = 0000 */ regs[digit4] = reg % (WORDLIMIT + 1); break; case SHFTL: /* shift left (or multiply by 10) */ regs[digit4] = (reg * 10) % (WORDLIMIT+1); break; case SHFTR: /* shift right (or multiply by 10) */ regs[digit4] = reg / 10; break; default: printf("Illegal one register instruction %i \n", inst); trace(); exit(1); } /* end of "8n0r" switch */ regs[7] = regs[7] % MEMSIZE; /* make sure %sp has legal address */ regs[8] = regs[8] % MEMSIZE; /* make sure %lk has legal address */ regs[9] = regs[9] % MEMSIZE; /* make sure %ip has legal address */ return; /* finished processing single reg instruction */ } /* end of onereg() */ /* Two register operation codes (format 9nsd) */ void tworeg() { int sreg, dreg, temp; /* local variables */ sreg = regs[digit3]; dreg = regs[digit4]; switch ( digit2 ) { case MVRR: /* Rd = Rs */ regs[digit4] = sreg; break; case MVMR: /* Rd = memory[Rs] */ if (sreg > 999) { printf("Illegal memory reference via register %d, exiting\n", digit3); trace(); exit; } regs[digit4] = memory[sreg]; break; case MVRM: /* memory[Rd] = Rs */ if (dreg > 999) { printf("Illegal memory reference via register %d, exiting\n", digit3); trace(); exit; } memory[dreg] = sreg; break; case EXCH: /* exchange Rs and Rd */ regs[digit3] = dreg; regs[digit4] = sreg; break; case ADDR: /* Ry = Ry + Rx */ dreg = dreg + sreg; regs[digit4] = dreg % (WORDLIMIT + 1); /* wrap if reg > 9999 */ break; case SUBR: /* Ry = Ry - Rx */ temp = (WORDLIMIT+1) - sreg; /* temp = -sreg */ dreg = dreg + temp; /* */ regs[digit4] = dreg % (WORDLIMIT+1); /* wrap if regy > 9999 */ break; default: printf("Illegal register instruction %i \n", inst); trace(); exit(1); } /* end of "9nxy" switch */ regs[7] = regs[7] % MEMSIZE; /* make sure %sp has legal address */ regs[8] = regs[8] % MEMSIZE; /* make sure %lk has legal address */ regs[9] = regs[9] % MEMSIZE; /* make sure %ip has legal address */ return; /* finished processing two register instructions */ } /* end of tworeg() */ /* function to input a machine language program */ void readcode() { #define MAXLINE 80 int addr, value, items; char line[MAXLINE]; while (1) { if ( (fgets(line, sizeof(line), stdin) ) <= 0) { /* read until EOF */ printf("End of file encountered, exiting\n"); exit(1); } printf("%s", line); /* print all lines */ if (line[0] == '#') { /* ignore comment */ continue; } items = sscanf(line, "%d %d" , &addr, &value); /* up to two ints */ switch (items) { case 0: /* illegal line, print and ignore */ printf("illegal input ignorred\n"); continue; case 1: /* one number is starting address */ if ( (addr < 000) || (addr > 999) ) { printf("illegal starting address %d, exiting\n", addr); exit(1); } else { regs[9] = addr; /* so initialize ip and return */ printf("Starting execution of SIM program at address %3.3d\n", regs[9]); return; } case 2: /* two numbers, address and value */ if ( (addr < 000) || (addr > 999) ) { printf("illegal memory address %d, exiting\n", addr); exit(1); } if ( (value < 000) || (value > 9999) ) { printf("illegal memory value %d, exiting\n", value); exit(1); } memory[addr]=value; /* place value in memory */ } /* end switch */ } /* end of while */ } /* end of readcode() */ /* display a single line of trace output */ void trace() { printf("cnt=%d, %%r9=%3.3d, inst=%4.4d, %%r0=%4.4d, " "%%r1=%4.4d, %%r2=%4.4d, %%r7=%4.4d, %%r8=%4.4d\n", cnt, regs[9], inst, regs[0], regs[1], regs[2], regs[7], regs[8]); } /* end of trace() */ /* panic - impossible condition (fire the programmer) */ void panic(char *pmessage) { trace(); printf("PANIC - %s, exiting\n", pmessage); exit(2); } /* end of panic() */