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