]> mj.ucw.cz Git - minsk.git/commitdiff
Initial commit
authorMartin Mares <mj@ucw.cz>
Mon, 27 Dec 2010 16:10:43 +0000 (17:10 +0100)
committerMartin Mares <mj@ucw.cz>
Mon, 27 Dec 2010 16:10:43 +0000 (17:10 +0100)
Makefile [new file with mode: 0644]
in1 [new file with mode: 0644]
in2 [new file with mode: 0644]
minsk.c [new file with mode: 0644]
rus [new file with mode: 0644]
test1.in [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
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 (file)
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 (file)
index 0000000..08e2665
--- /dev/null
+++ b/minsk.c
@@ -0,0 +1,459 @@
+/*
+ *     Minsk-2 Emulator
+ *
+ *     (c) 2010 Martin Mares <mj@ucw.cz>
+ */
+
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+// 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 (file)
index 0000000..2f99c34
--- /dev/null
+++ b/rus
@@ -0,0 +1,3 @@
+йцук енгш щзхъ
+фыва прол джэ
+ячсм итьб ю
diff --git a/test1.in b/test1.in
new file mode 100644 (file)
index 0000000..40d0df2
--- /dev/null
+++ b/test1.in
@@ -0,0 +1 @@
+@12345