commit fdcac03ecc2b688689139142ef824f67d698bf1e from: Sven M. Hallberg date: Sat Sep 10 13:48:51 2022 UTC factor cpu() out of main commit - 8474506aed47f619c495303dae5adcf5c05f424a commit + fdcac03ecc2b688689139142ef824f67d698bf1e blob - 19a15523fb781332227e1286e6a38f3cf06a3bf8 blob + 246a0b3c260dcc8699dce5d2e7ac06a156c1f137 --- hackem.c +++ hackem.c @@ -165,6 +165,70 @@ alu(uint16_t x, uint16_t y, uint16_t comp) /* + * Central Processing Unit. + */ + +uint16_t A, D, PC; /* registers */ + +int +cpu(uint16_t instr) +{ + uint16_t a, comp, ddd, jjj; /* instruction parts */ + uint16_t result, y; + + if (bit(instr, 15)) { /* C-instruction */ + /* decode instruction */ + jjj = bits(instr, 0, 3); + ddd = bits(instr, 3, 3); + comp = bits(instr, 6, 6); + a = bits(instr, 12, 1); + + /* switch ALU input between A and M */ + if (a) + y = readmem(A); + else + y = A; + + /* perform computation */ + result = alu(D, y, comp); + + /* distribute result to destinations */ + if (bit(ddd, 0)) /* M */ + writemem(A, result); + if (bit(ddd, 1)) /* D */ + D = result; + if (bit(ddd, 2)) /* A */ + A = result; + + /* + * Terminate on idiomatic infinite loops. I.e. an + * unconditional jump without any assignment that leads + * (a) directly to itself or (b) to an immediately + * preceding instruction that loads its own address. + * + * (a) @END (b) (END) + * (END) @END + * 0;JMP 0;JMP + */ + if (ddd == 0 && jjj == 7 && + (A == PC || (A == PC - 1 && rom[A] == A))) + return 0; /* stop */ + + /* perform jump if required */ + if ((bit(jjj, 0) && positive(result)) || + (bit(jjj, 1) && result == 0) || + (bit(jjj, 2) && negative(result))) + PC = A - 1; + } else /* A-instruction */ + A = instr; + PC++; + + device_ticks(); /* time-based I/O updates */ + return 1; /* keep running */ +} + + +/* * Main program. */ @@ -217,10 +281,8 @@ usage(void) int main(int argc, char *argv[]) { - uint16_t A, D, PC; /* registers */ - uint16_t a, comp, ddd, jjj; /* instruction parts */ - uint16_t result, instr, y; - int fd, c; + int fd, c; + uint16_t instr; /* process command line flags */ while ((c = getopt(argc, argv, "t:")) != -1) { @@ -251,66 +313,20 @@ main(int argc, char *argv[]) /* print header line to trace file, if applicable */ tracehdr(); + /* initialization */ + A = D = PC = 0; + /* the main loop */ - A = D = 0; - for (PC = 0; ; T++, PC++) { - instr = rom[PC]; + for (T = 0; ; T++) { + instr = rom[PC]; /* fetch instruction */ + trace(PC, instr, A, D); /* output cur. CPU state */ + if (!cpu(instr)) /* execute instruction */ + break; /* terminate */ - /* print CPU state to trace file, if applicable */ - trace(PC, instr, A, D); - - if (bit(instr, 15)) { /* C-instruction */ - /* decode instruction */ - jjj = bits(instr, 0, 3); - ddd = bits(instr, 3, 3); - comp = bits(instr, 6, 6); - a = bits(instr, 12, 1); - - /* switch ALU input between A and M */ - if (a) - y = readmem(A); - else - y = A; - - /* perform computation */ - result = alu(D, y, comp); - - /* distribute result to destinations */ - if (bit(ddd, 0)) /* M */ - writemem(A, result); - if (bit(ddd, 1)) /* D */ - D = result; - if (bit(ddd, 2)) /* A */ - A = result; - - /* - * Terminate on idiomatic infinite loops. I.e. an - * unconditional jump without any assignment that leads - * (a) directly to itself or (b) to an immediately - * preceding instruction that loads its own address. - * - * (a) @END (b) (END) - * (END) @END - * 0;JMP 0;JMP - */ - if (ddd == 0 && jjj == 7 && - (A == PC || (A == PC - 1 && rom[A] == A))) - break; - - /* perform jump if required */ - if ((bit(jjj, 0) && positive(result)) || - (bit(jjj, 1) && result == 0) || - (bit(jjj, 2) && negative(result))) - PC = A - 1; - } else /* A-instruction */ - A = instr; - - device_ticks(); /* time-based I/O updates */ - // XXX tick delay } - /* return success in trace mode */ + /* always return success in trace mode */ if (tfile) return 0;