1 /* MIX simulator, copyright 1994 by Darius Bacon */
2 #include "mix.h"
3 #include "asm.h" /* for entry_point */
4 #include "charset.h"
5 #include "io.h"
6 #include "run.h"
7
8 #include <setjmp.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12
stop(const char * message,va_list args)13 static void stop(const char *message, va_list args)
14 {
15 fprintf(stderr, "RUNTIME ERROR: ");
16 vfprintf(stderr, message, args);
17 fprintf(stderr, "\n");
18 print_CPU_state();
19 exit(1);
20 }
21
22 /* --- Execution statistics --- */
23
24 static unsigned long elapsed_time = 0; /* in Tyme units */
25
26 /* --- The CPU state --- */
27
28 Cell memory[memory_size];
29
30 #define A 0
31 #define X 7
32 #define J 8
33 static Cell r[10]; /* the registers; except that r[9] == zero. */
34
35 static int comparison_indicator; /* the overflow toggle is defined in cell.c */
36 static Address pc; /* the program counter */
37
set_initial_state(void)38 void set_initial_state(void)
39 {
40 overflow = false;
41 comparison_indicator = 0;
42 {
43 unsigned i;
44 for (i = 0; i < 10; ++i)
45 r[i] = zero;
46 }
47 pc = entry_point; /*** need to check for no entry point */
48 }
49
print_CPU_state(void)50 void print_CPU_state(void)
51 {
52 printf ("A:");
53 print_cell (r[A]);
54 printf ("\t");
55 { /* Print the index registers: */
56 unsigned i;
57 for (i = 1; i <= 6; ++i)
58 printf ("I%u:%s%04lo ",
59 i, is_negative (r[i]) ? "-" : " ", magnitude (r[i]));
60 }
61 printf ("\nX:");
62 print_cell (r[X]);
63 printf ("\t J: %04lo", magnitude (r[J])); /* (it's always nonnegative) */
64 printf (" PC: %04o", pc);
65 printf (" Flags: %-7s %-8s",
66 comparison_indicator < 0 ? "less" :
67 comparison_indicator == 0 ? "equal" : "greater",
68 overflow ? "overflow" : "");
69 printf (" %11lu elapsed\n", elapsed_time);
70 }
71
72 /* --- The interpreter --- */
73
74 /* --- I've followed Knuth's MIX interpreter quite closely. */
75
76 static jmp_buf escape_k; /* continuation to escape from interpreter */
77
78 /* C, F, M, and V as defined in Knuth: */
79
80 static Byte C;
81 static Byte F;
82 static Cell M;
83
get_V(void)84 static Cell get_V(void)
85 {
86 return field(F, memory[cell_to_address(M)]);
87 }
88
89 /* do_foo performs the action of instruction type foo. */
90
do_nop(void)91 static void do_nop(void) { }
92
do_add(void)93 static void do_add(void) { r[A] = add(r[A], get_V()); }
do_sub(void)94 static void do_sub(void) { r[A] = sub(r[A], get_V()); }
95
do_mul(void)96 static void do_mul(void) { multiply(r[A], get_V(), &r[A], &r[X]); }
do_div(void)97 static void do_div(void) { divide(r[A], r[X], get_V(), &r[A], &r[X]); }
98
do_special(void)99 static void do_special(void)
100 {
101 switch (F) {
102 case 0: { /* NUM */
103 unsigned i;
104 Cell num = zero;
105 Cell ten = ulong_to_cell(10);
106 for (i = 1; i <= 5; ++i)
107 num = add(mul(ten, num), (Cell)(get_byte(i, r[A]) % 10));
108 for (i = 1; i <= 5; ++i)
109 num = add(mul(ten, num), (Cell)(get_byte(i, r[X]) % 10));
110 r[A] = is_negative(r[A]) ? negative(num) : num;
111 break;
112 }
113 case 1: { /* CHAR */
114 unsigned long num = magnitude(r[A]);
115 unsigned z = (unsigned) C_char_to_mix('0');
116 unsigned i;
117 for (i = 5; 0 < i; --i, num /= 10)
118 r[X] = set_byte((Byte) (z + num % 10), i, r[X]);
119 for (i = 5; 0 < i; --i, num /= 10)
120 r[A] = set_byte((Byte) (z + num % 10), i, r[A]);
121 break;
122 }
123 case 2: /* HLT */
124 longjmp(escape_k, 1);
125 default: error("Unknown extended opcode");
126 }
127 }
128
do_shift(void)129 static void do_shift(void)
130 {
131 Cell ignore;
132 unsigned long count = magnitude(M);
133 if (is_negative(M) && count != 0)
134 error("Negative shift count");
135 switch (F) {
136 case 0: /* SLA */
137 shift_left(zero, r[A], count, &ignore, &r[A]);
138 break;
139 case 1: /* SRA */
140 shift_right(r[A], zero, count, &r[A], &ignore);
141 break;
142 case 2: /* SLAX */
143 shift_left(r[A], r[X], count, &r[A], &r[X]);
144 break;
145 case 3: /* SRAX */
146 shift_right(r[A], r[X], count, &r[A], &r[X]);
147 break;
148 case 4: /* SLC */
149 shift_left_circular(r[A], r[X], (unsigned)(count % 10), &r[A], &r[X]);
150 break;
151 case 5: { /* SRC */
152 unsigned c = (10 - count % 10) % 10; /* -count modulo 10 */
153 shift_left_circular(r[A], r[X], c, &r[A], &r[X]);
154 break;
155 }
156 default: error("Unknown extended opcode");
157 }
158 }
159
do_move(void)160 static void do_move(void)
161 {
162 Address from = cell_to_address(M);
163 Address to = cell_to_address(r[1]);
164 unsigned count = F;
165 for (; count != 0; --count) {
166 if (memory_size <= from + count || memory_size <= to + count)
167 error("Address out of range");
168 memory[to + count] = memory[from + count];
169 elapsed_time += 2;
170 }
171 r[1] = address_to_cell(to + count);
172 }
173
do_lda(void)174 static void do_lda(void) { r[A] = get_V(); }
do_ldx(void)175 static void do_ldx(void) { r[X] = get_V(); }
do_ldi(void)176 static void do_ldi(void) {
177 Cell cell = get_V();
178 if (INDEX_MAX < magnitude(cell))
179 error("Magnitude too large for index register: %10o", magnitude(cell));
180 r[C & 7] = cell;
181 }
182
do_ldan(void)183 static void do_ldan(void) { r[A] = negative(get_V()); }
do_ldxn(void)184 static void do_ldxn(void) { r[X] = negative(get_V()); }
do_ldin(void)185 static void do_ldin(void) {
186 Cell cell = get_V();
187 if (INDEX_MAX < magnitude(cell))
188 error("Magnitude too large for index register: %10o", magnitude(cell));
189 r[C & 7] = negative(cell);
190 }
191
do_store(void)192 static void do_store(void)
193 {
194 Address a = cell_to_address(M);
195 memory[a] = set_field(r[C-24], F, memory[a]);
196 }
197
jump(void)198 static void jump(void)
199 {
200 r[J] = address_to_cell(pc);
201 pc = cell_to_address(M);
202 }
203
branch(unsigned condition,int sign)204 static void branch(unsigned condition, int sign)
205 {
206 switch (condition) {
207 case 0: jump(); break;
208 case 1: pc = cell_to_address(M); break;
209 case 2: if (overflow) jump(); overflow = false; break;
210 case 3: if (!overflow) jump(); overflow = false; break;
211 case 4: if (sign < 0) jump(); break;
212 case 5: if (sign == 0) jump(); break;
213 case 6: if (sign > 0) jump(); break;
214 case 7: if (sign >= 0) jump(); break;
215 case 8: if (sign != 0) jump(); break;
216 case 9: if (sign <= 0) jump(); break;
217 default: error("Bad branch condition");
218 }
219 }
220
do_jump(void)221 static void do_jump(void)
222 {
223 branch(F, comparison_indicator);
224 }
225
sign_of_difference(Cell difference)226 static int sign_of_difference(Cell difference)
227 {
228 return magnitude(difference) == 0 ? 0 : is_negative(difference) ? -1 : 1;
229 }
230
do_reg_branch(void)231 static void do_reg_branch(void)
232 {
233 branch(F + 4, sign_of_difference(r[C & 7]));
234 }
235
do_jbus(void)236 static void do_jbus(void)
237 {
238 /* no channel is ever busy, because we're using C's blocking I/O */
239 }
240
do_jred(void)241 static void do_jred(void)
242 {
243 jump(); /* conversely, all channels are always ready */
244 }
245
do_ioc(void)246 static void do_ioc(void) { io_control(F, M); }
do_in(void)247 static void do_in(void) { do_input(F, r[X], cell_to_address(M)); }
do_out(void)248 static void do_out(void) { do_output(F, r[X], cell_to_address(M)); }
249
do_addr_op(void)250 static void do_addr_op(void)
251 {
252 Cell cell;
253 unsigned reg = C & 7;
254 switch (F) {
255 case 0: cell = add(r[reg], M); break;
256 case 1: cell = sub(r[reg], M); break;
257 case 2: cell = M; break;
258 case 3: cell = negative(M); break;
259 default: error("Unknown extended opcode"); cell = zero;
260 }
261 if (reg - 1 < 6) /* same as: 1 <= reg && reg <= 6 */
262 if (INDEX_MAX < magnitude(cell))
263 error("Magnitude too large for index register: %10o",
264 magnitude(cell));
265 r[reg] = cell;
266 }
267
do_compare(void)268 static void do_compare(void)
269 {
270 Flag saved = overflow;
271 Cell difference = sub(field(F, r[C & 7]),
272 field(F, memory[cell_to_address(M)]));
273 comparison_indicator = sign_of_difference(difference);
274 overflow = saved;
275 }
276
277 static const struct {
278 void (*action)(void);
279 unsigned clocks;
280 } op_table[64] = {
281 { do_nop, 1 },
282 { do_add, 2 },
283 { do_sub, 2 },
284 { do_mul, 10 },
285 { do_div, 12 },
286 { do_special, 1 },
287 { do_shift, 2 },
288 { do_move, 1 },
289
290 { do_lda, 2 },
291 { do_ldi, 2 },
292 { do_ldi, 2 },
293 { do_ldi, 2 },
294 { do_ldi, 2 },
295 { do_ldi, 2 },
296 { do_ldi, 2 },
297 { do_ldx, 2 },
298
299 { do_ldan, 2 },
300 { do_ldin, 2 },
301 { do_ldin, 2 },
302 { do_ldin, 2 },
303 { do_ldin, 2 },
304 { do_ldin, 2 },
305 { do_ldin, 2 },
306 { do_ldxn, 2 },
307
308 { do_store, 2 },
309 { do_store, 2 },
310 { do_store, 2 },
311 { do_store, 2 },
312 { do_store, 2 },
313 { do_store, 2 },
314 { do_store, 2 },
315 { do_store, 2 },
316
317 { do_store, 2 },
318 { do_store, 2 },
319 { do_jbus, 1 },
320 { do_ioc, 1 },
321 { do_in, 1 },
322 { do_out, 1 },
323 { do_jred, 1 },
324 { do_jump, 1 },
325
326 { do_reg_branch, 1 },
327 { do_reg_branch, 1 },
328 { do_reg_branch, 1 },
329 { do_reg_branch, 1 },
330 { do_reg_branch, 1 },
331 { do_reg_branch, 1 },
332 { do_reg_branch, 1 },
333 { do_reg_branch, 1 },
334
335 { do_addr_op, 1 },
336 { do_addr_op, 1 },
337 { do_addr_op, 1 },
338 { do_addr_op, 1 },
339 { do_addr_op, 1 },
340 { do_addr_op, 1 },
341 { do_addr_op, 1 },
342 { do_addr_op, 1 },
343
344 { do_compare, 2 },
345 { do_compare, 2 },
346 { do_compare, 2 },
347 { do_compare, 2 },
348 { do_compare, 2 },
349 { do_compare, 2 },
350 { do_compare, 2 },
351 { do_compare, 2 },
352 };
353
run(void)354 void run(void)
355 {
356 install_error_handler(stop);
357 if (setjmp(escape_k) != 0)
358 return;
359 for (;;) {
360 /* print_CPU_state(); */
361 if (memory_size <= pc)
362 error("Program counter out of range: %4o", pc);
363 {
364 Byte I;
365 destructure_cell(memory[pc++], M, I, F, C);
366 if (6 < I)
367 error("Invalid I-field: %u", I);
368 if (I != 0)
369 M = add(M, r[I]); /* (the add can't overflow because the numbers are too small) */
370 op_table[C].action();
371 elapsed_time += op_table[C].clocks;
372 }
373 }
374 }
375