commit - 8474506aed47f619c495303dae5adcf5c05f424a
commit + fdcac03ecc2b688689139142ef824f67d698bf1e
blob - 19a15523fb781332227e1286e6a38f3cf06a3bf8
blob + 246a0b3c260dcc8699dce5d2e7ac06a156c1f137
--- hackem.c
+++ hackem.c
/*
+ * 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.
*/
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) {
/* 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;