X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=minsk.c;h=50038f6697ed40d61d3b45865ab11908383ab4cd;hb=HEAD;hp=6e9845776d70cbba96aca232b067f88d9db76ee8;hpb=ada822fbaf721f3c9744f4498cbe4fb63edefdf0;p=minsk.git diff --git a/minsk.c b/minsk.c index 6e98457..50038f6 100644 --- a/minsk.c +++ b/minsk.c @@ -16,6 +16,7 @@ #define _GNU_SOURCE #define UNUSED __attribute__((unused)) +#define NORETURN __attribute__((noreturn)) #undef ENABLE_DAEMON_MODE @@ -31,15 +32,24 @@ static int trace; static int cpu_quota = -1; static int print_quota = -1; +static int english; +static int memblocks = 1; static void (*error_hook)(char *msg); // Minsk-2 has 37-bit words in sign-magnitude representation (bit 36 = sign) typedef unsigned long long int word; +#define MEM_SIZE 4096 #define WORD_MASK 01777777777777ULL #define SIGN_MASK 01000000000000ULL #define VAL_MASK 00777777777777ULL +typedef struct loc +{ + int block; + int address; +} loc; + static int wsign(word w) { return (w & SIGN_MASK) ? -1 : 1; @@ -51,6 +61,7 @@ static word wabs(word w) } #define WF(w) (wsign(w) < 0 ? '-' : '+'), wabs(w) +#define LF(a) (a.block), (a.address) static long long wtoll(word w) { @@ -149,60 +160,56 @@ static word wfromfloat(double x, int normalized) return w; } -static word mem[4096]; +static word **mem; -static word rd(int addr) +static word rd(loc addr) { - word val = addr ? mem[addr] : 0; + word val = addr.address ? mem[addr.block][addr.address] : 0; if (trace > 2) - printf("\tRD %04o = %c%012llo\n", addr, WF(val)); + printf("\tRD %d:%04o = %c%012llo\n", LF(addr), WF(val)); return val; } -static void wr(int addr, word val) +static void wr(loc addr, word val) { assert(!(val & ~(WORD_MASK))); if (trace > 2) - printf("\tWR %04o = %c%012llo\n", addr, WF(val)); - mem[addr] = val; + printf("\tWR %d:%04o = %c%012llo\n", LF(addr), WF(val)); + mem[addr.block][addr.address] = val; } static int lino; -static void parse_error(char *msg) +NORETURN static void parse_error(char *russian_msg, char *english_msg) { if (error_hook) error_hook("Parse error"); - printf("Ошибка входа (стр. %d): %s\n", lino, msg); + + if (english) + printf("Parse error (line %d): %s\n", lino, english_msg); + else + printf("Ошибка входа (стр. %d): %s\n", lino, russian_msg); exit(0); } static void parse_in(void) { char line[80]; - int addr = 0; + loc addr = { 0, 0 }; while (fgets(line, sizeof(line), stdin)) { lino++; char *eol = strchr(line, '\n'); if (!eol) - parse_error("Строка слишком долгая"); + parse_error("Строка слишком долгая", "Line too long"); *eol = 0; if (eol > line && eol[-1] == '\r') *--eol = 0; char *c = line; if (!c[0] || c[0] == ';') - { - if (!strncmp(c, ";daji_zor_i_litva=", 18)) - { - trace = atoi(c+18); - if (error_hook) - error_hook("Secret tracing switch flipped"); - } - continue; - } + continue; if (c[0] == '.') return; @@ -210,20 +217,20 @@ static void parse_in(void) if (c[0] == '@') { c++; - addr = 0; + addr.address = 0; for (int i=0; i<4; i++) { while (*c == ' ') c++; if (*c >= '0' && *c <= '7') - addr = 8*addr + *c++ - '0'; + addr.address = 8*addr.address + *c++ - '0'; else - parse_error("Плохая цифра"); + parse_error("Плохая цифра", "Invalid number"); } while (*c == ' ') c++; if (*c) - parse_error("Адрес слишком долгий"); + parse_error("Адрес слишком долгий", "Address too long"); continue; } @@ -231,7 +238,7 @@ static void parse_in(void) if (*c == '-') w = 1; else if (*c != '+') - parse_error("Плохой знак"); + parse_error("Плохой знак", "Invalid sign"); c++; for (int i=0; i<12; i++) { @@ -240,14 +247,14 @@ static void parse_in(void) if (*c >= '0' && *c <= '7') w = 8*w + *c++ - '0'; else - parse_error("Плохая цифра"); + parse_error("Плохая цифра", "Invalid number"); } while (*c == ' ') c++; if (*c) - parse_error("Номер слишком долгий"); - wr(addr++, w); - addr &= 07777; + parse_error("Номер слишком долгий", "Number too long"); + wr(addr, w); + addr.address = (addr.address+1) & 07777; } } @@ -256,27 +263,36 @@ static word r1, r2, current_ins; static int ip = 00050; // Standard program start location static int prev_ip; -static void stop(char *reason, char *notice) +NORETURN static void stop(char *russian_reason, char *english_reason) { if (error_hook) - error_hook(notice); - printf("Машина остановлена -- %s\n", reason); - printf("СчАК:%04o См:%c%012llo Р1:%c%012llo Р2:%c%012llo\n", prev_ip, WF(acc), WF(r1), WF(r2)); + error_hook(english_reason); + + if (english) + { + printf("System stopped -- %s\n", english_reason); + printf("IP:%04o ACC:%c%012llo R1:%c%012llo R2:%c%012llo\n", prev_ip, WF(acc), WF(r1), WF(r2)); + } + else + { + printf("Машина остановлена -- %s\n", russian_reason); + printf("СчАК:%04o См:%c%012llo Р1:%c%012llo Р2:%c%012llo\n", prev_ip, WF(acc), WF(r1), WF(r2)); + } exit(0); } -static void over(void) +NORETURN static void over(void) { stop("Аварийный останов", "Overflow"); } -static void notimp(void) +NORETURN static void notimp(void) { acc = current_ins; stop("Устройство разбитое", "Not implemented"); } -static void noins(void) +NORETURN static void noins(void) { acc = current_ins; stop("Эту команду не знаю", "Illegal instruction"); @@ -347,7 +363,7 @@ static void print_line(int r) fflush(stdout); } -static void print_ins(int x, int y) +static void print_ins(int x, loc y) { word yy = rd(y); int pos = x & 0177; @@ -450,32 +466,33 @@ static void run(void) { r2 = acc; prev_ip = ip; - word w = mem[ip]; + word w = mem[0][ip]; current_ins = w; int op = (w >> 30) & 0177; // Operation code - int ax = (w >> 28) & 3; // Address extensions not supported + int ax = (w >> 28) & 3; // Address extensions supported in Minsk-22 mode 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) + loc x = { ax >> 1, (w >> 12) & 07777 }; // Operands (original form) + loc y = { ax & 1, w & 07777 }; + loc xi=x, yi=y; // (indexed form) if (trace) - printf("@%04o %c%02o %02o %04o %04o\n", + printf("@%04o %c%02o %02o %d:%04o %d:%04o\n", ip, (w & SIGN_MASK) ? '-' : '+', (int)((w >> 30) & 077), (int)((w >> 24) & 077), - x, - y); + LF(x), + LF(y)); if (ix) { if (op != 0120) { - word i = rd(ix); - xi = (xi + (int)((i >> 12) & 07777)) & 07777; - yi = (yi + (int)(i & 07777)) & 07777; + loc iaddr = { 0, ix }; + word i = rd(iaddr); + xi.address = (xi.address + (int)((i >> 12) & 07777)) & 07777; + yi.address = (yi.address + (int)(i & 07777)) & 07777; if (trace > 2) - printf("\tIndexing -> %04o %04o\n", xi, yi); + printf("\tIndexing -> %d:%04o %d:%04o\n", LF(xi), LF(yi)); } } ip = (ip+1) & 07777; @@ -532,7 +549,7 @@ static void run(void) astore(wfromfloat(f, 0)); } - if (ax) + if (ax && memblocks == 1) // Reject address extensions if we only have 1 memory block op = -1; switch (op) { @@ -659,7 +676,8 @@ static void run(void) case 0120: // Loop if (!ix) noins(); - a = r1 = rd(ix); + loc iaddr = { 0, ix }; + a = r1 = rd(iaddr); aa = (a >> 24) & 017777; if (!aa) break; @@ -667,36 +685,36 @@ static void run(void) acc = ((aa-1) << 24) | (((((a >> 12) & 07777) + (b >> 12) & 07777) & 07777) << 12) | (((a & 07777) + (b & 07777)) & 07777); - wr(ix, acc); - ip = x; + wr(iaddr, acc); + ip = x.address; break; case 0130: // Jump wr(y, r2); - ip = x; + ip = x.address; break; case 0131: // Jump to subroutine - wr(y, acc = ((030ULL << 30) | ((ip & 07777ULL) << 12))); - ip = x; + wr(y, acc = ((0130ULL << 30) | ((ip & 07777ULL) << 12))); + ip = x.address; break; case 0132: // Jump if positive if (wsign(r2) >= 0) - ip = x; + ip = x.address; else - ip = y; + ip = y.address; break; case 0133: // Jump if overflow // Since we always trap on overflow, this instruction always jumps to the 1st address - ip = x; + ip = x.address; break; case 0134: // Jump if zero if (!wabs(r2)) - ip = y; + ip = y.address; else - ip = x; + ip = x.address; break; case 0135: // Jump if key pressed // No keys are ever pressed, so always jump to 2nd - ip = y; + ip = y.address; break; case 0136: // Interrupt masking notimp(); @@ -709,7 +727,7 @@ static void run(void) case 0160 ... 0161: // I/O notimp(); case 0162: // Printing - print_ins(x, y); + print_ins(x.address, y); break; case 0163: // I/O notimp(); @@ -764,7 +782,8 @@ static void run(void) if (!wabs(a)) { wr(yi, 0); - wr((yi+1) & 07777, 0); + loc yinc = { yi.block, (yi.address+1) & 07777 }; + wr(yinc, 0); acc = 0; } else @@ -779,7 +798,8 @@ static void run(void) } acc |= a; wr(yi, acc); - wr((yi+1) & 07777, i); + loc yinc = { yi.block, (yi.address+1) & 07777 }; + wr(yinc, i); } break; case 0176: // Population count @@ -801,11 +821,9 @@ static void run(void) } } -static void die(char *msg) +NORETURN static void die(char *msg) { - fprintf(stderr, "minsk: "); - fprintf(stderr, msg); - fputc('\n', stderr); + fprintf(stderr, "minsk: %s\n", msg); exit(1); } @@ -1254,39 +1272,61 @@ static void setproctitle_init(int argc UNUSED, char **argv UNUSED) #endif -static void init_memory(void) +static void init_memory(int set_password) { - // For the contest, we fill the whole memory with -00 00 0000 0000 (HALT), - // not +00 00 0000 0000 (NOP). Otherwise, an empty program would reveal - // the location of the password :) - for (int i=0; i<4096; i++) - mem[i] = 01000000000000ULL; - - // Store the password - int pos = 02655; - mem[pos++] = 0574060565373; - mem[pos++] = 0371741405340; - mem[pos++] = 0534051524017; + mem = malloc(memblocks * sizeof(word *)); + for (int i=0; i Enable tracing of program execution\n\ ---cpu-quota= Set CPU quota to instructions\n\ ---print-quota= Set printer quota to lines\n\ +-d, --daemon Run as daemon and listen for network connections\n\ +-n, --nofork When run with --daemon, avoid forking\n\ +"); + #endif + fprintf(stderr, "\ +-e, --english Print messages in English\n\ +-s, --set-password Put hidden password in memory\n\ +-u, --upgrade Upgrade the Minsk-2 to the Minsk-22\n\ +-t, --trace= Enable tracing of program execution\n\ +-q, --cpu-quota= Set CPU quota to instructions\n\ +-p, --print-quota= Set printer quota to lines\n\ "); exit(1); } @@ -1296,8 +1336,9 @@ int main(int argc, char **argv) int opt; int daemon_mode = 0; int do_fork = 1; + int set_password = 0; - while ((opt = getopt_long(argc, argv, "", longopts, NULL)) >= 0) + while ((opt = getopt_long(argc, argv, "q:desunp:t:", longopts, NULL)) >= 0) switch (opt) { case 'd': @@ -1306,6 +1347,15 @@ int main(int argc, char **argv) case 'n': do_fork = 0; break; + case 'e': + english = 1; + break; + case 's': + set_password = 1; + break; + case 'u': + memblocks = 2; + break; case 'p': print_quota = atoi(optarg); break; @@ -1322,12 +1372,13 @@ int main(int argc, char **argv) usage(); setproctitle_init(argc, argv); - init_memory(); + init_memory(set_password); if (daemon_mode) run_as_daemon(do_fork); parse_in(); run(); + return 0; }