4 * (c) 2010 Martin Mares <mj@ucw.cz>
11 * - debugging/play mode
12 * - implement printing
14 * - we probably have to disable NOP
24 // Minsk-2 has 37-bit words in sign-magnitude representation (bit 36 = sign)
25 typedef unsigned long long int word;
27 #define WORD_MASK 01777777777777ULL
28 #define SIGN_MASK 01000000000000ULL
29 #define VAL_MASK 00777777777777ULL
31 static int wsign(word w)
33 return (w & SIGN_MASK) ? -1 : 1;
36 static word wabs(word w)
41 #define WF(w) (wsign(w) < 0 ? '-' : '+'), wabs(w)
43 static long long wtoll(word w)
51 static word wfromll(long long x)
53 word w = ((x < 0) ? -x : x) & VAL_MASK;
59 static double wtofrac(word w)
61 return (double)wtoll(w) / (double)(1ULL << 36);
64 static word wfromfrac(double d)
66 return wfromll((long long)(d * (double)(1ULL << 36)));
69 static int inrange(long long x)
71 return (x >= -(long long)VAL_MASK && x <= (long long)VAL_MASK);
74 static int fracinrange(double d)
76 return (d > -1. && d < 1.);
79 static int wexp(word w)
82 return (w & 0100 ? -exp : exp);
85 static word mem[4096];
87 static word rd(int addr)
89 word val = addr ? mem[addr] : 0;
91 printf("\tRD %04o = %c%012llo\n", addr, WF(val));
95 static void wr(int addr, word val)
97 assert(!(val & ~(WORD_MASK)));
99 printf("\tWR %04o = %c%012llo\n", addr, WF(val));
105 static void parse_error(char *msg)
107 printf("Ошибка входа (стр. %d): %s\n", lino, msg);
111 static void parse_in(void)
116 while (fgets(line, sizeof(line), stdin))
119 char *eol = strchr(line, '\n');
121 parse_error("Строка слишком долгая");
129 for (int i=0; i<4; i++)
133 if (*c >= '0' && *c <= '7')
134 addr = 8*addr + *c++ - '0';
136 parse_error("Плохая цифва");
141 parse_error("Адрес слишком долгий");
149 parse_error("Плохой знак");
151 for (int i=0; i<12; i++)
155 if (*c >= '0' && *c <= '7')
156 w = 8*w + *c++ - '0';
158 parse_error("Плохая цифва");
163 parse_error("Номер слишком долгий");
170 static word r1, r2, current_ins;
171 static int flag_zero = 0;
172 static int ip = 00050; // Standard program start location
175 static void stop(char *reason)
177 printf("MACHINE STOPPED -- %s\n", reason);
178 printf("IP:%04o ACC:%c%012llo R1:%c%012llo R2:%c%012llo\n", prev_ip, WF(acc), WF(r1), WF(r2));
182 static void over(void)
187 static void nofpu(void)
193 static void notimp(void)
196 stop("NOT IMPLEMENTED");
199 static void noins(void)
202 stop("ILLEGAL INSTRUCTION");
205 static void print_ins(int x, int y)
209 int r = (x >> 9) & 7;
213 // r bit 0 = line feed
214 // r bit 1 = clear buffer
221 case 0: // Decimal float
222 case 1: // Octal number
223 case 2: // Decimal fixed
224 case 3: // Decimal unsigned
225 case 4: // One Russian symbol
226 case 5: // Russian text
227 case 6: // One Latin symbol
228 case 7: // Latin text
233 static void run(void)
242 int op = (w >> 30) & 0177; // Operation code
243 int ax = (w >> 28) & 3; // Address extensions not supported
244 int ix = (w >> 24) & 15; // Indexing
245 int x = (w >> 12) & 07777; // Operands (original form)
247 int xi=x, yi=y; // (indexed form)
249 printf("@%04o %c%02o %02o %04o %04o\n",
251 (w & SIGN_MASK) ? '-' : '+',
252 (int)((w >> 30) & 077),
253 (int)((w >> 24) & 077),
261 xi = (xi + (int)((i >> 12) & 07777)) & 07777;
262 yi = (yi + (int)(i & 07777)) & 07777;
264 printf("\tIndexing -> %04o %04o\n", xi, yi);
269 /* Arithmetic operations */
272 long long aa, bb, cc;
276 auto void afetch(void);
286 auto void astore(word result);
287 void astore(word result)
300 case 004 ... 007: // XOR
304 case 010 ... 013: // FIX addition
306 cc = wtoll(a) + wtoll(b);
311 case 014 ... 017: // FP addition
313 case 020 ... 023: // FIX subtraction
315 cc = wtoll(a) - wtoll(b);
320 case 024 ... 027: // FP subtraction
322 case 030 ... 033: // FIX multiplication
324 // XXX: We ignore the rounding mode settings
325 cd = wtofrac(a) * wtofrac(b);
326 astore(wfromfrac(cd));
328 case 034 ... 037: // FP multiplication
330 case 040 ... 043: // division
335 stop("DIVISION BY ZERO");
337 if (!fracinrange(cd))
339 astore(wfromfrac(cd));
341 case 044 ... 047: // FP division
343 case 050 ... 053: // FIX subtraction of abs values
345 cc = wabs(a) - wabs(b);
350 case 054 ... 057: // FP subtraction of abs values
352 case 060 ... 063: // Shift logical
355 if (i <= -37 || i >= 37)
358 astore((a << i) & WORD_MASK);
362 case 064 ... 067: // Shift arithmetical
366 if (i <= -36 || i >= 36)
369 cc = (aa << i) & VAL_MASK;
372 astore((a & SIGN_MASK) | wfromll(cc));
374 case 070 ... 073: // And
378 case 074 ... 077: // Or
387 case 0103: // I/O magtape
389 case 0104: // Disable rounding
391 case 0105: // Enable rounding
393 case 0106: // Interrupt control
395 case 0107: // Reverse tape
398 wr(yi, r1 = acc = rd(xi));
400 case 0111: // Move negative
401 wr(yi, acc = (r1 = rd(xi)) ^ SIGN_MASK);
403 case 0112: // Move absolute value
404 wr(yi, acc = (r1 = rd(xi)) & VAL_MASK);
406 case 0113: // Read from keyboard
408 case 0114: // Copy sign
409 wr(yi, acc = rd(yi) ^ ((r1 = rd(xi)) & SIGN_MASK));
411 case 0115: // Read code from R1 (obscure)
413 case 0116: // Copy exponent
415 case 0117: // I/O teletype
421 aa = (a >> 24) & 017777;
424 b = rd(y); // (a mountain range near Prague)
425 acc = ((aa-1) << 24) |
426 (((((a >> 12) & 07777) + (b >> 12) & 07777) & 07777) << 12) |
427 (((a & 07777) + (b & 07777)) & 07777);
435 case 0131: // Jump to subroutine
436 wr(y, acc = ((030ULL << 30) | ((ip & 07777ULL) << 12)));
439 case 0132: // Jump if positive
445 case 0133: // Jump if overflow
446 // Since we always trap on overflow, this instruction always jumps to the 1st address
449 case 0134: // Jump if zero
455 case 0135: // Jump if key pressed
456 // No keys are ever pressed, so always jump to 2nd
459 case 0136: // Interrupt masking
461 case 0137: // Used only when reading from tape
463 case 0140 ... 0147: // I/O
465 case 0150 ... 0154: // I/O
467 case 0160 ... 0161: // I/O
469 case 0162: // Printing
474 case 0170: // FIX multiplication, bottom part
476 if (wtofrac(a) * wtofrac(b) >= .1/(1ULL << 32))
478 acc = wfromll(((unsigned long long)wabs(a) * (unsigned long long)wabs(b)) & VAL_MASK);
479 // XXX: What should be the sign? The book does not define that.
486 stop("DIVISION BY ZERO");
492 case 0172: // Add exponents
494 case 0173: // Sub exponents
496 case 0174: // Addition in one's complement
503 // XXX: The effect on the accumulator is undocumented, but likely to be as follows:
506 case 0175: // Normalization
508 case 0176: // Population count
511 for (int i=0; i<36; i++)
514 // XXX: Guessing that acc gets a copy of the result
524 printf("\tACC:%c%012llo R1:%c%012llo R2:%c%012llo Z:%d\n", WF(acc), WF(r1), WF(r2), flag_zero);