#include #include #include #include "CAL16.mem.h" #include "CAL16.proc.h" /* Machine State */ word_t pc; word_t r[16]; /* Interpreter state */ int quiet = 0; typedef void execOpFun_t(word_t instr); typedef void printOpFun_t(word_t instr, word_t pc); typedef struct opSpec { int op; char *mne; execOpFun_t *exec; printOpFun_t *print; } OpSpec_t; void execRR(word_t instr); void execRI4(word_t instr); void execRI4jr(word_t instr); void execRI4mem(word_t instr); void execRI8(word_t instr); void execJ12(word_t instr); void execSyscall(word_t instr); void execUndef(word_t instr); void printRR(word_t instr, word_t pc); void printIM(word_t instr, word_t pc); void printMem(word_t instr, word_t pc); void printBr(word_t instr, word_t pc); void printRI8(word_t instr, word_t pc); void printJmp(word_t instr, word_t pc); void printUndef(word_t instr, word_t pc); void printSyscall(word_t instr, word_t pc); enum {OPadd=0, OPor, OPxor, OPand, OPaddi, OProtr, OPst, OPld, OPldi, OPsyscall, OPbneg, OPbz, OPjr, OPunused2, OPunused3, OPjmp}; /* Dispatch table. Order must be identical to above enum */ OpSpec_t decode[16] = { {0, "add", execRR, printRR}, {1, "or", execRR, printRR}, {2, "xor", execRR, printRR}, {3, "and", execRR, printRR}, {4, "addi", execRI4, printIM}, {5, "rotr", execRI4, printIM}, {6, "st" , execRI4mem, printMem}, {7, "ld" , execRI4mem, printMem}, {8, "ldi", execRI8, printRI8}, {9, "syscall", execSyscall, printSyscall}, {10, "bneg",execRI8, printBr}, {11, "bz", execRI8, printBr}, {12, "jr", execRI4jr, printMem}, {13, "uu", execUndef, printUndef}, {14, "uu", execUndef, printUndef}, {15, "jmp", execJ12, printJmp} }; int digit (word_t instr, int digitindex) { return (instr >> (4 * (3 - digitindex))) & 0xf; } int immedArg (word_t instr) { return instr & 0x00ff; } int jumpArg (word_t instr) { return instr & 0xfff; } int signExtended4 (int n) { if (n & 0x8) { return (n | 0xfff0); } else { return n; } } int signExtended8 (int n) { if (n & 0x80) { return (n | 0xff00); } else { return n; } } /* Print functions */ void printRR(word_t instr, word_t pc) { int opcode = digit(instr,0); int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int reg2index = digit (instr, 3); printf("%s $%d $%d $%d",decode[opcode].mne, destIndex, reg1index, reg2index); } void printIM(word_t instr, word_t pc) { int opcode = digit(instr,0); int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int off4 = digit (instr, 3); printf("%s $%d $%d %d",decode[opcode].mne, destIndex, reg1index, off4); } void printMem(word_t instr, word_t pc) { int opcode = digit(instr,0); int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int off4 = digit (instr, 3); printf("%s $%d %d($%d)",decode[opcode].mne, destIndex, off4, reg1index); } void printBr(word_t instr, word_t pc) { int opcode = digit(instr,0); int reg1index = digit (instr, 1); int off8 = signExtended8(immedArg (instr)); printf("%s $%d @%X",decode[opcode].mne, reg1index, pc+2*off8); } void printRI8(word_t instr, word_t pc) { int opcode = digit(instr,0); int reg1index = digit (instr, 1); unsigned int off8 = immedArg (instr); printf("%s $%d %d",decode[opcode].mne, reg1index, off8); } void printJmp(word_t instr, word_t pc) { int opcode = digit(instr,0); unsigned int off12 = jumpArg (instr); /* word address */ unsigned int npc = (pc & 0xE000) | (off12 << 1); printf("%s %0X (%d)",decode[opcode].mne, npc, npc); } void printUndef(word_t instr, word_t pc) { int opcode = digit(instr,0); unsigned int off12 = jumpArg (instr); /* word address */ printf("%s %d",decode[opcode].mne, off12); } void printSyscall(word_t instr, word_t pc) { int opcode = digit(instr,0); printf("%s",decode[opcode].mne); } void dumpAll () { int wordAddr; word_t instr = fromMem (pc); int opcode = digit (instr, 0); word_t val; printf ("pc: %04x (%04d)\tinst: %04x - ", pc, pc, fromMem(pc)); // printInst(fromMem(pc)); decode[opcode].print(instr, pc); printf ("\nregs:\n"); printf ("0: %04x\t1: %04x\t2: %04x\t3: %04x\n", r[0], r[1], r[2], r[3]); printf ("4: %04x\t5: %04x\t6: %04x\t7: %04x\n", r[4], r[5], r[6], r[7]); printf ("8: %04x\t9: %04x\tA: %04x\tB: %04x\n", r[8], r[9], r[10], r[11]); printf ("C: %04x\tD: %04x\tE: %04x\tF: %04x\n", r[12], r[13], r[14], r[15]); printf ("\n"); printf ("nonzero memory:\n"); for (wordAddr=0; wordAddr<32768; wordAddr++) { val = fromMem(wordAddr << 1); if (val != 0) { if ((wordAddr << 1) == pc) printf("*"); printf ("%04x: %04X (%d)\n", wordAddr<<1, val, val); } } printf ("-----\n"); } /* Execute Reg-Reg Instruction */ void execRR(word_t instr) { int opcode = digit(instr,0); int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int reg2index = digit (instr, 3); // printf("execRR %s\n", decode[opcode].mne); if (destIndex) { switch (opcode) { case OPadd: r[destIndex] = (r[reg1index] + r[reg2index]) & 0xffff; break; case OPor: r[destIndex] = (r[reg1index] | r[reg2index]) & 0xffff; break; case OPxor: r[destIndex] = (r[reg1index] ^ r[reg2index]) & 0xffff; break; case OPand: r[destIndex] = (r[reg1index] & r[reg2index]) & 0xffff; break; default: fprintf (stderr, "BAD opcode %04x\n", pc); } } pc += 2; }; void execRI4(word_t instr) { int opcode = digit(instr, 0); int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int off4 = digit (instr, 3); word_t newRight, newLeft; // printf("execRI4 %s\n", decode[opcode].mne); switch (opcode) { case OPaddi: if (destIndex) r[destIndex] = (r[reg1index] + signExtended4 (off4)) & 0xffff; break; case OProtr: /* rotr */ newRight = r[reg1index] >> off4; newLeft = r[reg1index] << (16-off4); if (destIndex) r[destIndex] = (newLeft | newRight) & 0xffff; break; } pc += 2; } void execRI4jr(word_t instr) { int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int off4 = digit (instr, 3); if (destIndex) r[destIndex] = pc; pc = (r[reg1index] + signExtended4 (off4)) & 0xffff; if (pc & 1) { fprintf (stderr, "jumping to a nonaligned address %04x\n", pc); exit (1); } } void execRI4mem(word_t instr) { int opcode = digit(instr, 0); int reg1index = digit (instr, 1); int destIndex = digit (instr, 2); int off4 = digit (instr, 3); word_t effAddr = r[reg1index]+signExtended4(off4); // printf("execRI4mem %s\n", decode[opcode].mne); if (effAddr & 1) { fprintf (stderr, "accessing a nonaligned address %04x\n", pc); exit (1); } switch (opcode) { case OPld: /* ld */ if (destIndex) r[destIndex] = fromMem (effAddr); break; case OPst: /* st */ toMem (effAddr, r[destIndex]); break; } pc += 2; } void execRI8(word_t instr) { int opcode = digit(instr,0); int destIndex = digit (instr, 1); unsigned int off8 = immedArg (instr); // printf("execRI8 %s\n", decode[opcode].mne); switch (opcode) { case OPldi: /* ldi */ if (destIndex) r[destIndex] = off8; pc += 2; break; case OPbneg: /* bneg */ if (r[destIndex] & 0x8000) { pc = (pc + 2*signExtended8(off8)) & 0xffff; } else { pc += 2; } break; case OPbz: /* bz */ if (r[destIndex] == 0) { pc = (pc + 2 * signExtended8 (off8)) & 0xffff; } else { pc += 2; } break; } } void execJ12(word_t instr) { unsigned int off12 = jumpArg (instr); /* word address */ pc = ((unsigned) ((0xe000 & pc) | (2*off12))); } void execUndef(word_t instr) { int opcode = digit(instr,0); fprintf (stderr, "opcode %d not implemented\n", opcode); exit (1); } void execSyscall(word_t instr) { fprintf (stdout, "Program terminated\n"); dumpAll (); exit (1); } void prompt() { int c; printf("q,x,ret: "); c = getchar(); if (c == 'q') exit (0); if (c == 'x') quiet = 1; while ((c != EOF) && (c != '\n')) c = getchar(); } /* Instruction cycle */ void procRun() { word_t instr; int opcode; dumpAll (); prompt(); while (1) { instr = fromMem (pc); /* Fetch */ opcode = digit (instr, 0); decode[opcode].exec(instr); /* Decode, Op fetch, execute, next */ if (!quiet) { dumpAll (); prompt(); } } } void procReset() { int k; r[0] = 0; for (k=1; k<16; k++) { r[k] = 0xffff; } pc = 0; /* pc is a byte address */ }