From: Martin Mares Date: Mon, 27 Dec 2010 16:10:43 +0000 (+0100) Subject: Initial commit X-Git-Tag: v1.0~35 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=f976f7150cca2e04b6485bd49be9f227db0ff881;p=minsk.git Initial commit --- f976f7150cca2e04b6485bd49be9f227db0ff881 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fb4ef7b --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +CC=gcc +LD=gcc +CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99 + +all: minsk + +clean: + rm -f `find . -name "*~" -or -name "*.[oa]" -or -name core -or -name .depend -or -name .#*` diff --git a/in1 b/in1 new file mode 100644 index 0000000..8f0d893 --- /dev/null +++ b/in1 @@ -0,0 +1,4 @@ +@0050 ++110000510052 +-123412341234 ++432100001111 diff --git a/in2 b/in2 new file mode 100644 index 0000000..8c830a1 --- /dev/null +++ b/in2 @@ -0,0 +1,14 @@ +@0050 +-100010000005 ++100000000000 ++120510000000 +-200500521000 +-000000000000 +@1000 ++000500010000 ++000000000001 ++000000000002 ++000000000003 ++000000000004 ++000000000005 ++000000000006 diff --git a/minsk.c b/minsk.c new file mode 100644 index 0000000..08e2665 --- /dev/null +++ b/minsk.c @@ -0,0 +1,459 @@ +/* + * Minsk-2 Emulator + * + * (c) 2010 Martin Mares + */ + +/* + * TODO: + * - time limit + * - error messages + * - debugging/play mode + * - implement shifts + * - which instructions should modify the accumulator? + * - implement printing + * - floating point? + * - simulate R1 and R2? + */ + +#include +#include +#include +#include + +// Minsk-2 has 37-bit words in sign-magnitude representation (bit 36 = sign) +typedef unsigned long long int word; + +#define WORD_MASK 01777777777777ULL +#define SIGN_MASK 01000000000000ULL +#define VAL_MASK 00777777777777ULL + +static int wsign(word w) +{ + return (w & SIGN_MASK) ? -1 : 1; +} + +static word wabs(word w) +{ + return w & VAL_MASK; +} + +#define WF(w) (wsign(w) < 0 ? '-' : '+'), wabs(w) + +static long long wtoll(word w) +{ + if (wsign(w) < 0) + return -wabs(w); + else + return wabs(w); +} + +static word wfromll(long long x) +{ + word w = ((x < 0) ? -x : x) & VAL_MASK; + if (x < 0) + w |= SIGN_MASK; + return w; +} + +static double wtofrac(word w) +{ + return (double)wtoll(w) / (double)(1ULL << 36); +} + +static word wfromfrac(double d) +{ + return wfromll((long long)(d * (double)(1ULL << 36))); +} + +static int inrange(long long x) +{ + return (x >= -(long long)VAL_MASK && x <= (long long)VAL_MASK); +} + +static int fracinrange(double d) +{ + return (d > -1. && d < 1.); +} + +static word mem[4096]; + +static word rd(int addr) +{ + word val = addr ? mem[addr] : 0; + printf("\tRD %04o = %c%012llo\n", addr, WF(val)); + return val; +} + +static void wr(int addr, word val) +{ + assert(!(val & ~(WORD_MASK))); + printf("\tWR %04o = %c%012llo\n", addr, WF(val)); + mem[addr] = val; +} + +static int lino; + +static void parse_error(char *msg) +{ + printf("Ошибка входа (стр. %d): %s\n", lino, msg); + exit(1); +} + +static void parse_in(void) +{ + char line[80]; + int addr = 0; + + while (fgets(line, sizeof(line), stdin)) + { + lino++; + char *eol = strchr(line, '\n'); + if (!eol) + parse_error("Строка слишком долгая"); + *eol = 0; + + char *c = line; + if (c[0] == '@') + { + c++; + addr = 0; + for (int i=0; i<4; i++) + { + while (*c == ' ') + c++; + if (*c >= '0' && *c <= '7') + addr = 8*addr + *c++ - '0'; + else + parse_error("Плохая цифва"); + } + while (*c == ' ') + c++; + if (*c) + parse_error("Адрес слишком долгий"); + continue; + } + + word w = 0; + if (*c == '-') + w = 1; + else if (*c != '+') + parse_error("Плохой знак"); + c++; + for (int i=0; i<12; i++) + { + while (*c == ' ') + c++; + if (*c >= '0' && *c <= '7') + w = 8*w + *c++ - '0'; + else + parse_error("Плохая цифва"); + } + while (*c == ' ') + c++; + if (*c) + parse_error("Номер слишком долгий"); + wr(addr++, w); + addr &= 07777; + } +} + +static word acc, prev_acc; +static int flag_zero = 0; +static int ip = 00050; // Standard program start location +static int prev_ip; + +static void stop(char *reason) +{ + printf("MACHINE STOPPED -- %s\n", reason); + printf("IP:%04o ACC:%c%012llo\n", prev_ip, WF(acc)); + exit(0); +} + +static void over(void) +{ + stop("OVERFLOW"); +} + +static void nofpu(void) +{ + stop("NO FPU"); +} + +static void notimp(void) +{ + stop("NOT IMPLEMENTED"); +} + +static void noins(void) +{ + stop("ILLEGAL INSTRUCTION"); +} + +static void run(void) +{ + for (;;) + { + prev_acc = acc; + prev_ip = ip; + word w = mem[ip]; + + int op = (w >> 30) & 0177; // Operation code + int ax = (w >> 28) & 3; // Address extensions not supported + int ix = (w >> 24) & 15; // Indexing + int x = (w >> 12) & 07777; // Operands (original form) + int y = w & 07777; + int xi=x, yi=y; // (indexed form) + printf("@%04o %c%02o %02o %04o %04o\n", + ip, + (w & SIGN_MASK) ? '-' : '+', + (int)((w >> 30) & 077), + (int)((w >> 24) & 077), + x, + y); + if (ix) + { + if (op != 0120) + { + word i = rd(ix); + xi = (xi + (int)((i >> 12) & 07777)) & 07777; + yi = (yi + (int)(i & 07777)) & 07777; + printf("\tIndexing -> %04o %04o\n", xi, yi); + } + } + ip = (ip+1) & 07777; + + /* Arithmetic operations */ + + word a, b, c; + long long aa, bb, cc; + double ad, bd, cd; + + auto void afetch(void); + void afetch(void) + { + if (op & 2) + a = prev_acc; + else + a = rd(yi); + b = rd(xi); + } + + auto void astore(word result); + void astore(word result) + { + acc = result; + if (op & 1) + wr(yi, acc); + } + + if (ax) + op = -1; + switch (op) + { + case 000: // NOP + break; + case 004 ... 007: // XOR + afetch(); + astore(a^b); + break; + case 010 ... 013: // FIX addition + afetch(); + cc = wtoll(a) + wtoll(b); + if (!inrange(cc)) + over(); + astore(wfromll(cc)); + break; + case 014 ... 017: // FP addition + nofpu(); + case 020 ... 023: // FIX subtraction + afetch(); + cc = wtoll(a) - wtoll(b); + if (!inrange(cc)) + over(); + astore(wfromll(cc)); + break; + case 024 ... 027: // FP subtraction + nofpu(); + case 030 ... 033: // FIX multiplication + afetch(); + cd = wtofrac(a) * wtofrac(b); + // FIXME: Rounding? + astore(wfromfrac(cd)); + break; + case 034 ... 037: // FP multiplication + nofpu(); + case 040 ... 043: // division + afetch(); + ad = wtofrac(a); + bd = wtofrac(b); + if (!wabs(b)) + stop("DIVISION BY ZERO"); + cd = ad / bd; + if (!fracinrange(cd)) + over(); + astore(wfromfrac(cd)); + break; + case 044 ... 047: // FP division + nofpu(); + case 050 ... 053: // subtraction of abs values + afetch(); + cc = wabs(a) - wabs(b); + if (!inrange(cc)) + over(); + astore(wfromll(cc)); + break; + case 054 ... 057: // FP subtraction of abs values + nofpu(); + case 060 ... 063: // Shift logical + notimp(); // XXX + case 064 ... 067: // Shift arithmetical + notimp(); // XXX + case 070 ... 073: // And + afetch(); + astore(a&b); + break; + case 074 ... 077: // Or + afetch(); + astore(a|b); + break; + + case 0100: // Halt + // r1 = rd(x); + acc = rd(y); + stop("HALTED"); + case 0103: // I/O magtape + notimp(); + case 0104: // Disable rounding + notimp(); + case 0105: // Enable rounding + notimp(); + case 0106: // Interrupt control + notimp(); + case 0107: // Reverse tape + notimp(); + case 0110: // Move + wr(yi, rd(xi)); + break; + case 0111: // Move negative + wr(yi, rd(xi) ^ SIGN_MASK); + break; + case 0112: // Move absolute value + wr(yi, rd(xi) & VAL_MASK); + break; + case 0113: // Read from keyboard + notimp(); + case 0114: // Copy sign + wr(yi, rd(yi) ^ (rd(xi) & SIGN_MASK)); + break; + case 0115: // Read code from R1 (obscure) + notimp(); + case 0116: // Copy exponent + nofpu(); + case 0117: // I/O teletype + notimp(); + case 0120: // Loop + if (!ix) + noins(); + a = rd(ix); + aa = (a >> 24) & 017777; + if (!aa) + break; + b = rd(y); // (a mountain range near Prague) + wr(ix, ((aa-1) << 24) | + (((((a >> 12) & 07777) + (b >> 12) & 07777) & 07777) << 12) | + (((a & 07777) + (b & 07777)) & 07777)); + ip = x & 07777; + break; + case 0130: // Jump + wr(y, prev_acc); + ip = x & 07777; + break; + case 0131: // Jump to subroutine + wr(y, (030ULL << 30) | ((ip & 07777ULL) << 12)); + ip = x & 07777; + break; + case 0132: // Jump if positive + if (wsign(prev_acc) >= 0) + ip = x & 07777; + else + ip = y & 07777; + break; + case 0133: // Jump if overflow + // Since we always trap on overflow, this instruction always jumps to the 1st address + ip = x & 07777; + break; + case 0134: // Jump if zero + if (flag_zero) + ip = y & 07777; + else + ip = x & 07777; + break; + case 0135: // Jump if key pressed + // No keys are ever pressed, so always jump to 2nd + ip = y & 07777; + break; + case 0136: // Interrupt masking + notimp(); + case 0137: // Used only when reading from tape + notimp(); + case 0140 ... 0147: // I/O + notimp(); + case 0150 ... 0154: // I/O + notimp(); + case 0160 ... 0163: // I/O + notimp(); + case 0170: // FIX multiplication, bottom part + afetch(); + acc = wfromll(((unsigned long long)wabs(a) * (unsigned long long)wabs(b)) & VAL_MASK); + // XXX: What should be the sign? The book does not define that. + break; + case 0171: // Modulo + afetch(); + aa = wabs(a); + bb = wabs(b); + if (!bb) + stop("DIVISION BY ZERO"); + cc = aa % bb; + if (wsign(b) < 0) + cc = -cc; + acc = wfromll(cc); + break; + case 0172: // Add exponents + nofpu(); + case 0173: // Sub exponents + nofpu(); + case 0174: // Addition in one's complement + a = rd(xi); + b = rd(yi); + c = a + b; + if (c > VAL_MASK) + c = c - VAL_MASK; + // XXX: What happens with the accumulator? + wr(yi, c); + break; + case 0175: // Normalization + nofpu(); + case 0176: // Population count + a = rd(xi); + cc = 0; + for (int i=0; i<36; i++) + if (a & (1ULL << i)) + cc++; + wr(yi, wfromll(cc)); + break; + default: + noins(); + } + + flag_zero = !acc; + printf("\tACC:%c%012llo Z:%d\n", WF(acc), flag_zero); + } +} + +int main(void) +{ + parse_in(); + run(); + return 0; +} diff --git a/rus b/rus new file mode 100644 index 0000000..2f99c34 --- /dev/null +++ b/rus @@ -0,0 +1,3 @@ +йцук енгш щзхъ +фыва прол джэ +ячсм итьб ю diff --git a/test1.in b/test1.in new file mode 100644 index 0000000..40d0df2 --- /dev/null +++ b/test1.in @@ -0,0 +1 @@ +@12345