// computer.cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "useful.h" #include "codes.h" #include "debhelplib.h" #define O_BINARY 0 bool fulltrace = false; using namespace std; const string hexchars = "0123456789ABCDEF"; string aschar(char v) { string s; if (v >= ' ' && v <= '~') return s + v; if (v == '\n') return "\\n"; if (v == '\t') return "\\t"; if (v == '\'') return "\\'"; if (v == 127) return "\\d"; return s + '\\' + hexchars[(v >> 4) & 0xF] + hexchars[v & 0xF]; } string aschars(unsigned int v) { string s = "'"; s += aschar((v >> 24) & 0xFF); s += aschar((v >> 16) & 0xFF); s += aschar((v >> 8) & 0xFF); s += aschar(v & 0xFF); return s + "'"; } struct nistringstream { string line; int pos, len; string seps; bool takeone, failed; void reset(string s) { line = s; len = s.length(); pos = 0; seps = ""; failed = false; takeone = false; } nistringstream(string s) { reset(s); } int tellg() { return pos; } void seekg(int p) { pos = p; seps = ""; takeone = false; failed = false; } void clear() { failed = false; } bool fail() const { return failed; } string str() const { return line; } void str(const string & s) { reset(s); } const char * c_str() const { return line.c_str(); } void setseps(string s) { seps = s; } bool issep(char c) { for (int i = 0; i < seps.length(); i += 1) if (seps[i] == c) return true; return false; } nistringstream & operator>>(string & res) { while (pos < len && line[pos] <= ' ') pos += 1; if (pos == len) { failed = true; takeone = false; res = ""; seps = ""; return * this; } res = ""; if (takeone) { res = line[pos]; pos += 1; seps = ""; takeone = false; return * this; } while (true) { if (pos == len) return * this; char c = line[pos]; if (c <= ' ') { seps = ""; takeone = false; return * this; } if (issep(c)) { if (res == "") { res = c; pos += 1; return * this; } takeone = true; return * this; } res += c; pos += 1; } } }; string interrupt_words(int n) { string r = "Interrupt "; r += int_to_string(n); r += ' '; if (n < 0 || n >= num_interrupts) r += "(INCORRECT CODE)"; else r += interrupt_name[n]; return r; } const char * interrupt_desc(int n) { if (n < 0 || n >= num_interrupts) return "(no description)"; else return interrupt_description[n]; } helper hel; struct decoded_instruction { int whole_value; int opcode, mainreg, indirect, indexreg, number, notes; bool wasread; decoded_instruction(); decoded_instruction(int memval); decoded_instruction(int op, int mr, int ind, int ir, int n); void decode(int memval); string printable(int force = 0); }; struct device { int filenum; string filename; int mode; int size; device(); }; struct network { int unit, sock, port; }; class rangeaccumulator; class ranges { protected: struct node { int min, max; node * left, * right; node(int a, int b, node * c = NULL, node * d = NULL) { min = a; max = b; left = c; right = d; } }; node * root; void print(node * n); bool process_all(node * n, rangeaccumulator * r); void insert(node * & n, int a, int b); node * findandremovesmallest(node * & n); node * findandremove(node * & n, int v); void clear(node * & n); public: ranges(); void print(); bool process_all(rangeaccumulator * r); void add(int a, int b); void clear(); }; struct loaditem { string fname, ext; unsigned int where, end; bool haswhere; loaditem(string f, string e, unsigned int w) { fname = f; ext = e; where = w; end = 0; haswhere = true; } loaditem(string f, string e) { fname = f; ext = e; end = 0; haswhere = false; } }; struct monitoritem { char type; int addr, orig; monitoritem(char t, int a, int o) { type = t; addr = a; orig = o; } }; bool quiet = false, autoexit = false, zeromode = false; string hex(unsigned int n, int digs = 8) { string r; int shift = digs * 4 - 4; while (shift >= 0) { int d = (n >> shift) & 0xF; if (d == 0 && ! zeromode) r += 'o'; else if (d <= 9) r += (char)(d + '0'); else r += (char)(d + 'A' - 10); shift -= 4; } return r; } struct pairqueue { static const int size = 32; unsigned int pre[size], post[size], pc[size]; int sig[size]; char kind[size]; int num, last, pos, given; void reset() { num = 0; last = 0; pos = 0; given = 0; } pairqueue() { reset(); } void add(char k, unsigned int a, unsigned int b, unsigned int c, int d) { kind[last] = k; pre[last] = a; post[last] = b; pc[last] = c; sig[last] = d; last += 1; if (last >= size) last = 0; if (num < size) num += 1; } int scan() { pos = last - num; if (pos < 0) pos += size; given = 0; return num; } bool next(char & k, unsigned int & a, unsigned int & b, unsigned int & c, int & d) { if (given >= num) return false; k = kind[pos]; a = pre[pos]; b = post[pos]; c = pc[pos]; d = sig[pos]; given += 1; pos += 1; if (pos >= size) pos = 0; return true; } }; struct operand { char kind; int index; bool haso, excl; int offset; }; struct computer { static const int maximum_memory = 10 * 1024 * 1024; int memory_in_use, consecctrlc; int _registers[16], effective_address, oldinterrupt, interrupt_being_processed; int flr, flz, fln, flsys, flvm, flint, flem, fetch_pc, fcode, intsp; int sr_pdbr, sr_intvec, sr_cgbr, sr_cglen, sr_debug, sr_syssp, sr_sysfp; int sr_watch, sr_exitcode, sr_ipl, sr_emgret; int intframe[num_interrupts]; int ignorecall1, ignorecall2, ignorecall3, ignorecall4, ignoreret1, ignoreret2, ignoreret3, ignoreret4; unsigned int sr_timer; long long unsigned int execount, sumexecount, execount_subtract; char aside_buffer[1000]; bool tryingtostop, traceints, tracecalls, timer_ignored, keybd_ignored, nodebinfo; vector toload; vector monitors; int ab_n, ab_b, ab_e, begin; int trailcount, pctrail[16], intrtrail[16]; int intrcount, interrupt_fromline, intrnum[16]; double starttime, startrt; ranges memranges; int * memory[0x10000]; const char * freason; byte * ipaddress; bool stepping, runwild, reallyhalted, brokeninterrupt, breaking, starting, loaded_any, savedbpt3; decoded_instruction current_instruction; int interrupt_code, interrupt_address, interrupt_detail, int_pc, countdown; int start_break, loadplace, bpts, bpt1, bpt2, bpt3, savebpt3, init_pc; int intrsaved_watch, watching_involved, watch_cause, saved_watch, special_action; static const int max_devices = 8; device ddiscs[max_devices+1]; device dtapes[max_devices+1]; static const int max_nets = 2; network * dnets[max_nets+1]; pairqueue intevents; computer(); ~computer(); void reset(); int & registers(int r); int & sysregisters(int r); int & usrregisters(int r); int get_flag(int f); void set_flag(int f, int v); bool is_user_flagmask(int fm); bool is_user_flag(int f); int get_special_register(int r); void set_special_register(int r, int v); const char * special_register_name(int r); void physical_memory_create(int address); bool physical_memory_exists(int address); int physical_memory_read(int address); void physical_memory_write(int address, int value); void physical_memory_clear(int page_address); int read_a_bit(int f, int n, unsigned int addr); int write_a_bit(int f, int n, unsigned int addr); int read_a_block(int f, unsigned int addr); int write_a_block(int f, unsigned int addr, int nbytes); int * real_memory_address(unsigned int a); int translate(int address); int memory_read(int address); int safe_read(int address); bool memory_can_read(int address); bool checked_memory_read(int addr, int & value); bool check_memory_block(int addr); void memory_write(int address, int value); string string_from_memory(int addr, int maxlen); int read_operand(); void write_operand(int value); void fetch(); void execute(); bool fetch_for_step(); void process_dash_c_command_line(string givecmdline); void obey_command(string init, nistringstream & cmd, bool normalend); bool read_initialisation(istream & f); bool read_initialisation(); void load_required_files(); bool get_users_command(char * command, int & linelen, bool & normalend); int combine_flags(); void decombine_flags(int f); int loadfile(loaditem * li, unsigned int dfltwhere, string & fn); int read_file_to_memory(int f, unsigned int address); bool get_parameter_block(int addr, int size, int params[]); void put_parameter(int addr, int which, int value); int perform_io_operation(int operation, int addr); bool check_operand(string s, operand & o); bool operand_refers_to_memory(operand & o, int & where, bool physonly); bool evaluate_operand(const operand & o, int & val, bool physonly, bool noisy); string enstring_operand(const operand & o); bool set_operand(const operand & o, int val, bool physonly, bool noisy); char operand_or_value(string s, operand & o, int & v, bool physonly, bool noisy); void check_monitors(); void aside_buffer_add(char c); char aside_buffer_take(); bool aside_buffer_any(); void aside_buffer_clear(); string aside_buffer_see_all(); void aside_buffer_to_kbb(); void kbb_to_aside_buffer(); void sigint(int fromline, int ic, int addr); int start_network(int unit, int port); void stop_network(int unit); void saywatch(int ic, bool & said); void report_on_error_interrupt(); bool prepare_interrupt(int fromline, int ic); bool debugread(int address, int & value, bool physonly, bool noisy); bool debugwrite(int address, int value, bool physonly, bool noisy); void debugshow(nistringstream & iss, bool physonly, char option); void debugset(nistringstream & iss, bool physonly); bool debug_command(bool noisy = true); void handle_here(int here, int reladdr, const char * relname); void actual_show_range(unsigned int a1, unsigned int a2, bool physonly, char kind, char option, int reladdr, const char * relname); bool calculate(nistringstream & iss, int & result, bool physonly); void debprintall(); void postdebinfo(); void debinfo(int force = 0); void vm_show(int virtaddr); void printinterrupt(int fromline, int level, int fpc); }; class rangeaccumulator { protected: computer & comp; int address, max, given; public: rangeaccumulator(computer & c, int addr, int m); void reset(int addr, int m); bool handle(int min, int max); int get_given(); }; const int PAGE_PROT = PAGE_VALID | PAGE_SYSTEM; const int PAGE_USR_VALID = PAGE_PROT ^ PAGE_SYSTEM; byte * get_ip_address() { int pi[2], p, s; char * ipaddress = NULL; pipe(pi); if (fork() == 0) { close(1); dup(pi[1]); close(pi[0]); execlp("ifconfig", "ifconfig", NULL); } FILE * fin = fdopen(pi[0], "r"); close(pi[1]); while (true) { char line[1000]; char * s = fgets(line, 999, fin); if (s == NULL) break; char * p = strstr(line, "inet "); if (p == NULL) continue; char * q = strstr(p+7, " "); * q = 0; if (strcmp(p+5, "127.0.0.1") == 0) continue; if (ipaddress != NULL) cout << "WARNING: Multiple IP addresses found, using " << ipaddress << "\n"; else ipaddress = strdup(p+5); } p = wait(& s); fclose(fin); close(pi[0]); close(pi[1]); if (ipaddress == NULL) { cout << "WARNING: No IP address found, using 127.0.0.1\n"; ipaddress = strdup("127.0.0.1"); } byte * res = new byte[4]; sscanf(ipaddress, "%hhd.%hhd.%hhd.%hhd", &res[0], &res[1], &res[2], &res[3]); return res; } void spleep(int ln, int n) { // printf("sleep(%d) from %d\n", n, ln); sleep(n); } void uspleep(int ln, int n) { // printf("usleep(%d) at %d\n", n, ln); usleep(n); } string charstring(string pre, int d, string post) { string r = pre; for (int sh = 0; sh < 32; sh += 8) { int c = (d >> sh) & 0xFF; if (c == 0) continue; if (c < ' ' || c > '~') return ""; r += (char) c; } return r + post; } decoded_instruction::decoded_instruction() { decode(0); } decoded_instruction::decoded_instruction(int memval) { decode(memval); } void decoded_instruction::decode(int memval) { whole_value = memval; opcode = (memval >> 25) & 0x7F; indirect = (memval >> 24) & 0x01; mainreg = (memval >> 20) & 0x0F; indexreg = (memval >> 16) & 0x0F; number = memval & 0xFFFF; notes = instruction_notes[opcode]; wasread = true; if (number & 0x8000) number |= 0xFFFF0000; } decoded_instruction::decoded_instruction(int op, int mr, int ind, int ir, int n) { opcode = op; mainreg = mr; indirect = ind; indexreg = ir; number = n; wasread = true; whole_value = ((opcode & 0x7F) << 25) | ((indirect & 0x01) << 24) | ((mainreg & 0x0F) << 20) | ((indexreg & 0x0F) <<16) | (number & 0xFFFF); } string decoded_instruction::printable(int force) { if (! wasread) return "unreadable"; bool tr = false; string answer = " "; answer += instruction_name[opcode]; int note = instruction_notes[opcode]; answer += ' '; while (answer.length() < 8) answer += ' '; if (mainreg != 0 || ! (note & OPCODENOTE_NOREG)) { if (note & OPCODENOTE_CONDCODE) answer += condcodes[mainreg]; else { answer += " "; answer += register_name[mainreg]; } answer += ", "; } else answer += " "; if (indirect) answer += "["; if (indexreg != 0) { answer += register_name[indexreg]; if (number != 0) { if (force == 16) if (number >= 0) { answer += '+'; answer += hex(number, 4); } else { answer += '-'; answer += hex(- number, 4); } else { if (number >= 0) answer += '+'; answer += int_to_string(number); } tr = true; } } else if (indexreg == 0 && ! indirect && (note & OPCODENOTE_SPECREG) && number >= 0 && number < num_specregs) answer += specregs[number]; else if (indexreg == 0 && ! indirect && (note & OPCODENOTE_FLAG) && number >= 0 && number < num_flags) answer += flags[number]; else { if (force == 16) { if (number >= 0) answer += hex(number, 4); else { answer += '-'; answer += hex(- number, 4); } } else answer += int_to_string(number); tr = true; } if (indirect) answer += ']'; string z = " "; int wanted = 24 - answer.length(); answer += z.substr(0, wanted); if (tr && force == 0) { answer += " // Ox"; answer += hex(number, 4); answer += " "; } else answer += " "; if (opcode == OP_BREAK || opcode == OP_TYPE && indexreg == 0 && ! indirect) answer += charstring(" '", number, "'"); return answer; } static FILE * keyboardfile = NULL; bool k_any_ready() { if (keyboardfile!=NULL) return true; return kbd_any_ready(); } int k_read_char() { if (keyboardfile == NULL) return read_keyboard_char(); int c = fgetc(keyboardfile); if (c==EOF) { fclose(keyboardfile); keyboardfile = NULL; return -1; } return c; } const char * mons[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; const char * days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; struct discview { struct brastart { int reps, patpos; brastart(int r, int p) { reps=r; patpos=p; } }; vector bras; byte block[512]; int blocknum; int fd, discnum; int pos, poswas, charsonline; vector patternnames, patterns; string pattern; discview() { blocknum = -1; fd = -1; discnum = -1; pos = 0; poswas = 0; charsonline = 0; pattern = ""; } void setdisc(int n, int f) { fd = f; discnum = n; blocknum = -1; } bool setblock(int bn, int f = -1) { if (bn == blocknum) return true; if (fd == -1) fd = f; blocknum = -1; if (fd < 0) { printf("No file selected\n"); return false; } int n = lseek(fd, bn * 512, SEEK_SET); if (n != bn * 512) { printf("no such block in selected disc\n"); return false; } n=read(fd, block, 512); if (n != 512) { printf("no such block in selected disc\n"); return false; } blocknum = bn; return true; } string stringof(int n, string p) { string s = ""; for (int i = 0; i < n; i += 1) s += p; return s; } bool setpattern(string nm) { for (int i = 0; i < patternnames.size(); i += 1) { if (patternnames[i] == nm) { pattern = patterns[i]; return true; } } string base, ext, fn = nm; prepare_filename(nm, base, ext); if (ext == "") fn = base + ".pat"; FILE * pf = fopen(fn.c_str(), "r"); if (pf == NULL) { if (same(nm, "bytes")) pattern = "512*x"; else if (same(nm, "chars")) pattern = "512*c"; else if (same(nm, "ints")) pattern = "128*i"; else if (same(nm, "hex")) pattern = "128*w"; else if (same(nm, "code")) pattern = "128*d"; else if (nm[0] == '=') pattern = nm.substr(1); else { bool any = false, ok = false; int i = 0; while (i < nm.length()) { char c = nm[i]; if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_') { any = true; i += 1; } else if (c == '=') { ok = any; break; } else break; } if (! ok || i + 1 >= nm.length()) { printf("No such pattern file as '%s' and no such pattern as '%s'\n", fn.c_str(), nm.c_str()); return false; } pattern = nm.substr(i + 1); nm = nm.substr(0, i); for (int j = 0; j < patternnames.size(); j += 1) if (patternnames[j] == nm) { patterns[j] = pattern; return true; } patternnames.push_back(nm); patterns.push_back(pattern); return true; } return true; } string s = ""; while (1) { int c = fgetc(pf); if (c == EOF) break; s += (char)c; } fclose(pf); patternnames.push_back(nm); patterns.push_back(s); pattern = s; return true; } void newline() { printf("\n"); charsonline = 0; } void printchar(char c, bool canbreak = true) { if (c < ' ' && c != '\n' && c != '\t' || c > '~') return; if (charsonline == 0) printf("%3d: ", poswas); if (c == '\n') { putchar('\\'); putchar('n'); charsonline += 2; } else if (c == '\t') { putchar('\\'); putchar('t'); charsonline += 2; } else { putchar(c); charsonline += 1; } if (charsonline > 100 && canbreak) newline(); } void printnicechar(char c, bool canbreak = true) { if (charsonline == 0) printf("%3d: ", poswas); string s = visiblechar(c); printf("%s", s.c_str()); charsonline += s.length(); if (charsonline > 100 && canbreak) newline(); } void printspace() { if (charsonline > 99) newline(); else if (charsonline > 0) { printf(" "); charsonline += 1; } } void printcharnobreak(char c) { printchar(c, false); } void tab() { if (charsonline > 92) { newline(); return; } while (charsonline % 8 != 7) { printf(" "); charsonline += 1; } printf(" "); charsonline += 1; } void pwholestr(const char * s) { int n = strlen(s); if (charsonline + n > 100) newline(); for (int i = 0; i < n; i += 1) printchar(s[i]); } void printdate(int d) { time_t now = d + 946702800; tm * t = localtime(& now); if (charsonline + 26 > 100) newline(); printchar('['); pwholestr(days[t->tm_wday]); printspace(); printint(t->tm_mday, 2); printspace(); pwholestr(mons[t->tm_mon]); printspace(); printint(t->tm_year + 1900, 4); printspace(); printint(t->tm_hour, 2); printchar(':'); if (t->tm_min < 10) printchar('0'); printint(t->tm_min); printchar(':'); if (t->tm_sec < 10) printchar('0'); printint(t->tm_sec); printchar(']'); } void printinstr(int v) { decoded_instruction di(v); string s = di.printable(); if (charsonline + s.length() > 100) newline(); pwholestr(s.c_str()); } void startnewscan() { pos = 0; poswas = 0; charsonline = 0; bras.clear(); } int getbyte() { poswas = pos; pos += 1; if (pos < 513) return (int) block[poswas]; return 0; } int getshort() { int n = getbyte(); n |= getbyte() << 8; if (n & 0x8000) n |= 0xFFFF0000; poswas = pos - 2; return n; } int getint() { int n = getshort() & 0xFFFF; n |= getshort() << 16; poswas = pos - 4; return n; } void printint(int n, int sz = 0) { char s[30]; if (sz == 0) sprintf(s, "%d", n); else sprintf(s, "%*d", sz, n); n = strlen(s); for (int i = 0; i < n - 1; i += 1) printcharnobreak(s[i]); if (n > 0) printchar(s[n - 1]); } void printhex(int n, int bytes) { char s[12]; sprintf(s, "%0*X", bytes * 2, n); n = strlen(s); for (int i = 0; i < n - 1; i += 1) printcharnobreak(s[i]); if (n > 0) printchar(s[n - 1]); } void show() { string patt = pattern; char inquote = 0, last = 0; bool nextfunny = false; int numsofar = 0, repeats = 1; startnewscan(); for (int i = 0; i < patt.length(); i += 1) { char c = patt[i]; if (c == '\'' || c == '\"') { poswas = pos; if (c == inquote) inquote = 0; else if (inquote == 0) inquote = c; else printchar(c); repeats = 1; } else if (inquote != 0) { poswas = pos; if (c == '\\') { i += 1; if (i < patt.length()) c = patt[i]; if (c == 'n') newline(); else if (c == 't') tab(); else { printcharnobreak('\\'); printchar(c); } } else printchar(c); } else if (c == '\n') { poswas = pos; repeats = 1; } else if (c == '_') printchar(' '); else if (c >= '0' && c <= '9') { if (last >= '0' && last <= '9') numsofar = 10 * numsofar + c - '0'; else numsofar = c - '0'; } else if (c == '*') { repeats = numsofar; numsofar = 0; } else if (c == '(') { if (numsofar != 0) repeats = numsofar; numsofar = 0; bras.push_back(brastart(repeats, i)); repeats = 1; } else if (c == ')') { if (bras.size() == 0) { printf("\nUnmatched ) in pattern\n"); break; } brastart & bs = bras.back(); bs.reps -= 1; if (bs.reps > 0) i = bs.patpos; else bras.pop_back(); repeats = 1; } else if (c == 'a') { for (int j = 0; j < repeats; j += 1) printnicechar(getbyte()); repeats = 1; } else if (c == 'c') { for (int j = 0; j < repeats; j += 1) printchar(getbyte()); repeats = 1; } else if (c == 'b') { for (int j = 0; j < repeats; j += 1) { printint(getbyte()); printspace(); } repeats = 1; } else if (c == 'x') { for (int j = 0; j < repeats; j += 1) { printhex(getbyte(), 1); printspace(); } repeats = 1; } else if (c == 's') { for (int j = 0; j < repeats; j += 1) { printint(getshort()); printspace(); } repeats = 1; } else if (c == 'i') { for (int j = 0; j < repeats; j += 1) { if (numsofar == 0) printint(getint()); else printint(getint(), numsofar); printspace(); } numsofar = 0; repeats = 1; } else if (c == 'w') { for (int j = 0; j < repeats; j += 1) { printhex(getint(), 4); printspace(); } numsofar = 0; repeats = 1; } else if (c == 'g') { for (int j = 0; j < repeats; j += 1) getbyte(); repeats = 1; } else if (c == 't') { for (int j = 0; j < repeats; j += 1) printdate(getint()); repeats = 1; } else if (c == 'd') { if (charsonline > 0) newline(); for (int j = 0; j < repeats; j += 1) { printinstr(getint()); newline(); } repeats = 1; } else { poswas = pos; for (int j = 0; j < repeats; j += 1) printchar(c); repeats = 1; } last = c; } if (bras.size() != 0) printf("\nUnmatched ( in pattern"); if (pos > 512) printf("\nPattern was longer than 512 bytes"); else if (pos < 512) printf("\nPattern was shorter than 512 bytes"); printf("\n"); } }; discview dview; device::device() { filenum = -1; filename = ""; mode = 0; size = 0; } void ranges::print(node * n) { if (n != NULL) { print(n->left); cout << n->min << " to " << n->max << "\n"; print(n->right); } } bool ranges::process_all(node * n, rangeaccumulator * r) { bool ok; if (n != NULL) { ok = process_all(n->left, r); if (! ok) return false; ok = r->handle(n->min, n->max); if (! ok) return false; ok = process_all(n->right, r); if (! ok) return false; } return true; } void ranges::insert(node * & n, int a, int b) { if (n == NULL) n = new node(a, b); else { if (b < n->min) insert(n->left, a, b); else insert(n->right, a, b); } } ranges::node * ranges::findandremovesmallest(node * & n) { if (n->left == NULL) { node * result = n; n = n->right; result->right = NULL; return result; } return findandremovesmallest(n->left); } ranges::node * ranges::findandremove(node * & n, int v) { if (n == NULL) return NULL; else if (v >= n->min && v <= n->max) { node * result = n; if (n->right == NULL) n = n->left; else if (n->left == NULL) n = n->right; else { node * x = findandremovesmallest(n->right); x->left = result->left; x->right = result->right; n = x; } return result; } else if (v < n->min) return findandremove(n->left, v); else return findandremove(n->right, v); } void ranges::clear(node * & n) { if (n != NULL) { clear(n->left); clear(n->right); delete n; n = NULL; } } ranges::ranges() { root = NULL; } void ranges::print() { print(root); } bool ranges::process_all(rangeaccumulator * r) { return process_all(root, r); } void ranges::add(int a, int b) { node * L = findandremove(root, a - 1); node * R = findandremove(root, b + 1); if (L != NULL) { a = L->min; delete L; } if (R != NULL) { b = R->max; delete R; } insert(root, a, b); } void ranges::clear() { clear(root); } void rangeaccumulator::reset(int addr, int m) { address = addr; max = m; given = 0; } rangeaccumulator::rangeaccumulator(computer & c, int addr, int m): comp(c) { reset(addr, m); } bool rangeaccumulator::handle(int minad, int maxad) { given += 2; if (given - 1 <= max) { int v = comp.memory_read(address); comp.memory_write(address, minad); if (comp.interrupt_code != 0) return false; address += 1; comp.memory_write(address, maxad); if (comp.interrupt_code != 0) { comp.memory_write(address - 1, v); return false; } address += 1; } return true; } int rangeaccumulator::get_given() { return given; } computer::computer() { for (int i = 0; i < 0x10000; i += 1) memory[i] = NULL; begin = -1; ipaddress = get_ip_address(); reset(); } computer::~computer() { for (int i = 0; i < 0x10000; i += 1) if (memory[i] != NULL) delete[] memory[i]; } bool kbd_rdy = false, control_c = false; static unsigned int max_mem = 0, first_free = 0; void computer::reset() { for (int i = 0; i < 0x10000; i += 1) { if (memory[i] != NULL) delete[] memory[i]; memory[i] = NULL; } for (int i = 0; i < num_interrupts; i += 1) intframe[i] = 0; memranges.clear(); for (int i = 0; i < 14; i += 1) _registers[i] = 0; for (int i = 0; i < max_nets; i += 1) dnets[i] = NULL; intevents.reset(); tryingtostop = false; freason = ""; fcode = 0; nodebinfo = false; traceints = false; tracecalls = false; ignorecall1 = 0; ignoreret1 = 0; ignorecall2 = 0; ignoreret2 = 0; ignorecall3 = 0; ignoreret3 = 0; ignorecall4 = 0; ignoreret4 = 0; init_pc = -1; loaded_any = false; starting = false; start_break = 0; loadplace = 0x400; _registers[15] = loadplace; breaking = false; stepping = false; runwild = false; special_action = 0; watching_involved = 0; intrsaved_watch = 0; saved_watch = 0; watch_cause = 0; brokeninterrupt = false; execount = 0; sumexecount = 0; execount_subtract = 0; starttime = 0.0; startrt = 0.0; intrcount = 0; interrupt_fromline = 0; flr = 0; flz = 0; fln = 0; flsys = 1; flvm = 0; flint = 0; flem = 0; sr_pdbr = 0; sr_intvec = 0; sr_cgbr = 0; sr_cglen = 0; sr_debug = 0; sr_timer = 0; sr_syssp = 0; sr_sysfp = 0, sr_watch = 0, sr_exitcode = 0; sr_ipl = 0; sr_emgret = 0; bpts = 0; bpt1 = 0; bpt2 = 0; bpt3 = 0; savebpt3 = 0; savedbpt3 = false; timer_ignored = false; keybd_ignored = false; memory_in_use = 0; intsp = 0; interrupt_code = 0; interrupt_address = 0; interrupt_detail = 0; fetch_pc = loadplace; effective_address = 0; oldinterrupt = 0; interrupt_being_processed = 0; reallyhalted = false; consecctrlc = 0; countdown = 0; aside_buffer_clear(); current_instruction.decode(0); } void computer::aside_buffer_clear() { ab_n = 0; ab_b = 0; ab_e = 0; } void computer::aside_buffer_add(char c) { aside_buffer[ab_e] = c; ab_e += 1; if (ab_e >= 1000) ab_e = 0; if (ab_n < 1000) ab_n += 1; } char computer::aside_buffer_take() { if (ab_n <= 0) return 0; char c = aside_buffer[ab_b]; ab_b += 1; if (ab_b >= 1000) ab_b = 0; ab_n -= 1; return c; } bool computer::aside_buffer_any() { return ab_n > 0; } string computer::aside_buffer_see_all() { string s = ""; int p = ab_b, n = ab_n; while (n > 0) { char c = aside_buffer[p]; s += visiblechar(c); n -= 1; p += 1; if (p >= 1000) p = 0; } return s; } void computer::aside_buffer_to_kbb() { while (aside_buffer_any()) { char c = aside_buffer_take(); kb_getter(c); } } void computer::kbb_to_aside_buffer() { while (kbd_any_ready()) { char c = read_keyboard_char(); aside_buffer_add(c); } } int & computer::registers(int r) { if (flsys) { if (r == SP) return sr_syssp; if (r == FP) return sr_sysfp; return _registers[r]; } else return _registers[r]; } int & computer::sysregisters(int r) { if (r == SP) return sr_syssp; if (r == FP) return sr_sysfp; return _registers[r]; } int & computer::usrregisters(int r) { return _registers[r]; } int computer::combine_flags() { int r = sr_ipl & 0x1F; if (flr) r |= FLAGMASK_R; if (flz) r |= FLAGMASK_Z; if (fln) r |= FLAGMASK_N; if (flsys) r |= FLAGMASK_SYS; if (flvm) r |= FLAGMASK_VM; if (flem) r |= FLAGMASK_EM; if (flint) r |= FLAGMASK_INT; return r; } void computer::decombine_flags(int f) { sr_ipl = f & 0x1F; flr = 0; if (f & FLAGMASK_R) flr = 1; flz = 0; if (f & FLAGMASK_Z) flz = 1; fln = 0; if (f & FLAGMASK_N) fln = 1; flsys = 0; if (f & FLAGMASK_SYS) flsys = 1; flvm = 0; if (f & FLAGMASK_VM) flvm = 1; flem = 0; if (f & FLAGMASK_EM) flem = 1; flint = 0; if (f & FLAGMASK_INT) flint = 1; } int computer::get_flag(int f) { if (f == FLAG_R) return flr; if (f == FLAG_Z) return flz; if (f == FLAG_N) return fln; if (f == FLAG_SYS) return flsys; if (f == FLAG_VM) return flvm; if (f == FLAG_EM) return flem; if (f == FLAG_INT) return flint; return 0; } bool computer::is_user_flagmask(int f) { if (f & ~ (FLAGMASK_Z | FLAGMASK_N)) return false; return true; } bool computer::is_user_flag(int f) { return is_user_flagmask(1 << f); } void computer::set_flag(int f, int v) { if (f == FLAG_R) flr = v; else if (f == FLAG_Z) flz = v; else if (f == FLAG_N) fln = v; else if (f == FLAG_SYS) flsys = v; else if (f == FLAG_VM) flvm = v; else if (f == FLAG_EM) flem = v; else if (f == FLAG_INT) flint = v; } const char * computer::special_register_name(int i) { if (i < 0 || i >= num_specregs) return "???"; return specregs[i]; } int computer::get_special_register(int i) { if (i == SR_FLAGS) return combine_flags(); else if (i == SR_PDBR) return sr_pdbr; else if (i == SR_INTVEC) return sr_intvec; else if (i == SR_CGBR) return sr_cgbr; else if (i == SR_EMGRET) return sr_emgret; else if (i == SR_EXITCODE) return sr_exitcode; else if (i == SR_CGLEN) return sr_cglen; else if (i == SR_DEBUG) return sr_debug; else if (i == SR_TIMER) return sr_timer; else if (i == SR_SYSSP) return sr_syssp; else if (i == SR_SYSFP) return sr_sysfp; else if (i == SR_USRSP) return _registers[SP]; else if (i == SR_USRFP) return _registers[FP]; else if (i == SR_WATCH) return sr_watch; else if (i == SR_IPL) return sr_ipl; else return 0; } void computer::set_special_register(int i, int v) { if (i == SR_FLAGS) decombine_flags(v); else if (i == SR_PDBR) sr_pdbr = v; else if (i == SR_INTVEC) sr_intvec = v; else if (i == SR_CGBR) sr_cgbr = v; else if (i == SR_EMGRET) sr_emgret = v; else if (i == SR_EXITCODE) sr_exitcode = v; else if (i == SR_CGLEN) sr_cglen = v; else if (i == SR_DEBUG) sr_debug = v; else if (i == SR_TIMER) sr_timer = v; else if (i == SR_SYSSP) sr_syssp = v; else if (i == SR_SYSFP) sr_sysfp = v; else if (i == SR_USRSP) _registers[SP] = v; else if (i == SR_USRFP) _registers[FP] = v; else if (i == SR_WATCH) sr_watch = v; else if (i == SR_IPL) sr_ipl = v & 0x1F; } void computer::vm_show(int address) { printf("\n"); if (! flvm) printf(" Virtual Memory is OFF\n"); printf(" PDBR Page Directory Base Register = %s\n", hex(sr_pdbr).c_str()); fflush(stdout); if (sr_pdbr == 0) return; int dir = (address >> 22) & 0x3FF; int pg = (address >> 11) & 0x7FF; int offs = address & 0x7FF; printf(" Virtual Address %s = table %d, page %d, word %d\n", hex(address).c_str(), dir, pg, offs); int ptaddr = physical_memory_read(sr_pdbr + dir); printf(" [%s+%d = %s] = %s = page table address (physical page %d)\n", hex(sr_pdbr).c_str(), dir, hex(sr_pdbr + dir).c_str(), hex(ptaddr).c_str(), ptaddr >> 11); if (ptaddr == 0) { printf(" No page table, translation can not proceed\n"); fflush(stdout); return; } ptaddr &= 0xFFFFF800; int pgaddr = physical_memory_read(ptaddr + pg); printf(" [%s+%d = %s] = %s = page table entry (physical page %d)\n", hex(ptaddr).c_str(), pg, hex(ptaddr + pg).c_str(), hex(pgaddr).c_str(), pgaddr >> 11); printf(" %s = %s + %s :", hex(pgaddr).c_str(), hex(pgaddr & 0xFFFFF800).c_str(), hex(pgaddr & 0x7FF, 3).c_str()); if (pgaddr & PAGE_VALID) printf(" VALID"); else { printf(" page NOT Valid\n"); fflush(stdout); return; } if (pgaddr & PAGE_SYSTEM) printf(", SYSTEM mode access only\n"); else printf(", USER and SYSTEM mode access\n"); int physaddr = (pgaddr & 0xFFFFF800) + offs; int content = physical_memory_read(physaddr); printf(" Physical Address = %s, content = %s = %d\n", hex(physaddr).c_str(), hex(content).c_str(), content); fflush(stdout); } void computer::sigint(int fromline, int ic, int addr) { if (stepping && interrupt_code != 0) printf("\n**** interupt signal %d from %s when interrupt code already = %d from %s\n", ic, hex(addr).c_str(), interrupt_code, hex(interrupt_address).c_str()); if (traceints) { printf("\nTI: %s when PC = %s signalled (SSP %s), relevant address %s\n", interrupt_words(ic).c_str(), hex(fetch_pc).c_str(), hex(sr_syssp).c_str(), hex(addr).c_str()); printf("AAAA C0000004: %X\n", safe_read(0xC0000004)); fflush(stdout); } _registers[15] = fetch_pc; interrupt_code = ic; interrupt_address = addr; interrupt_fromline = fromline; } int computer::translate(int address) { if (! flvm) return address; int dir = (address >> 22) & 0x3FF; int pg = (address >> 11) & 0x7FF; int offs = address & 0x7FF; int ptaddr = physical_memory_read(sr_pdbr + dir); if (flsys) { if ((ptaddr & PAGE_VALID) == 0) { sigint(__LINE__, INT_PAGEFAULT, address); return 0; } int pgaddr = physical_memory_read((ptaddr & 0xFFFFF800) + pg); if ((pgaddr & PAGE_VALID) == 0) { sigint(__LINE__, INT_PAGEFAULT, address); return 0; } return (pgaddr & 0xFFFFF800) + offs; } else { if ((ptaddr & PAGE_VALID) == 0) { sigint(__LINE__, INT_PAGEFAULT, address); return 0; } int pgaddr = physical_memory_read((ptaddr & 0xFFFFF800) + pg); if ((pgaddr & PAGE_PROT) != PAGE_USR_VALID) { if (pgaddr & PAGE_VALID) sigint(__LINE__, INT_PAGEPRIV, address); else sigint(__LINE__, INT_PAGEFAULT, address); return 0; } return (pgaddr & 0xFFFFF800) + offs; } } bool computer::memory_can_read(int address) { if (flvm) { interrupt_code = 0; address = translate(address); if (interrupt_code != 0) return false; } return physical_memory_exists(address); } bool computer::check_memory_block(int addr) { if (! memory_can_read(addr)) return false; if (! memory_can_read(addr + 127)) return false; return true; } int computer::memory_read(int address) { if (flvm) { address = translate(address); if (interrupt_code != 0) return 0; } return physical_memory_read(address); } int computer::safe_read(int address) { int os = flsys; flsys = 1; int v = memory_read(address); flsys = os; return v; } int * computer::real_memory_address(unsigned int addr) { if (flvm) { interrupt_code = 0; addr = translate(addr); if (interrupt_code != 0) return NULL; } int blocknum = (addr >> 16) & 0xFFFF, offset = addr & 0xFFFF; if (memory[blocknum] == NULL) return NULL; return memory[blocknum] + offset; } void computer::memory_write(int address, int value) { if (sr_watch && address == sr_watch) { sigint(__LINE__, INT_WATCH, address); return; } if (flvm) { address=translate(address); if (interrupt_code != 0) return; } physical_memory_write(address, value); } void computer::physical_memory_create(int baseaddress) { int blocknum = (baseaddress >> 16) & 0xFFFF; if (memory_in_use >= maximum_memory) { printf("\nYou're being too greedy with memory!\n"); sigint(__LINE__, INT_MEMORY, baseaddress); return; } if (memory[blocknum] == NULL) { memory[blocknum] = new (nothrow) int[0x10000]; if (memory[blocknum] == NULL) { printf("\nYou're being too greedy with memory!\n"); sigint(__LINE__, INT_MEMORY, baseaddress); return; } memranges.add(baseaddress, baseaddress + 0xFFFF); } } bool computer::physical_memory_exists(int address) { int blocknum = (address >> 16) & 0xFFFF; if (memory[blocknum] == NULL) return false; return true; } int computer::physical_memory_read(int address) { int blocknum = (address >> 16) & 0xFFFF, offset = address & 0xFFFF; if (memory[blocknum] == NULL) return 0; return memory[blocknum][offset]; } void computer::physical_memory_write(int address, int value) { int blocknum = (address >> 16) & 0xFFFF, offset = address & 0xFFFF; if (memory[blocknum] == NULL) { if (sr_intvec != 0) sigint(__LINE__, INT_MEMORY, address); return; } memory[blocknum][offset] = value; } void computer::physical_memory_clear(int address) // page containing address { int blocknum = (address >> 16) & 0xFFFF, offset = address & 0xF800; if (memory[blocknum] == NULL) { if (sr_intvec != 0) sigint(__LINE__, INT_MEMORY, address); return; } bzero(memory[blocknum] + offset, 8192); } void computer::fetch() { if (countdown > 0) { countdown -= 1; if (countdown == 0 && runwild) { runwild = false; stepping = true; } } if (brokeninterrupt) return; interrupt_code = 0; interrupt_address = 0; int & pc = registers(PC); if (pc == sr_debug && pc != 0) { interrupt_address = pc; interrupt_detail = 0; bool ok = prepare_interrupt(__LINE__, INT_DEBUG); if (ok) return; } if (bpts && runwild && execount != 0) { if (pc == bpt1 || pc == bpt2 || pc == bpt3) { if (starting) { if (start_break != 0) { bpts = 1; if (start_break != 0) printf("restoring break-point 3 to original value %s\n", hex(start_break).c_str()); bpt3 = start_break; } else { bpts = 0; bpt3 = 0; } starting = false; start_break = 0; } else if (pc != 0) { int n = 1; if (pc == bpt2) n = 2; else if (pc == bpt3) n = 3; if (n == 3 && savedbpt3) { bpt3 = savebpt3; savebpt3 = 0; savedbpt3 = false; printf("Returned from skipped-over call, break-point 3 restored to %s\n", hex(bpt3).c_str()); fflush(stdout); bpts = bpt1 != 0 || bpt2 != 0 || bpt3 != 0; } else { printf("\n\nBREAK-POINT %d REACHED AT %s\n", n, hex(pc).c_str()); fflush(stdout); } } runwild = false; countdown = 0; stepping = true; breaking = true; return; } } fetch_pc = pc; int code = memory_read(pc); if (interrupt_code!=0) { interrupt_address = pc; current_instruction.whole_value = 0; current_instruction.wasread = false; return; } current_instruction.decode(code); pc += 1; effective_address = current_instruction.number; int ir = current_instruction.indexreg; if (ir != 0) effective_address += registers(current_instruction.indexreg); } int computer::read_operand() { if (current_instruction.indirect) { int v = memory_read(effective_address); if (interrupt_code!=0) v = 0; return v; } return effective_address; } void computer::write_operand(int value) { if (!current_instruction.indirect) { if (current_instruction.number == 0) { registers(current_instruction.indexreg) = value; return; } sigint(__LINE__, INT_UNWROP, fetch_pc); return; } memory_write(effective_address, value); } string computer::string_from_memory(int address, int maxlen) { string s = ""; for (int j = 0; j < maxlen || maxlen == 0; j += 1) { int v = memory_read(address + ( j >> 2)); if (interrupt_code != 0) return ""; int shft = (j & 3) * 8; char c = (v >> shft) & 0xFF; if (c == 0) break; s += c; } return s; } bool computer::get_parameter_block(int addr, int size, int params[]) { for (int i = 0; i < size; i += 1) { params[i] = memory_read(addr + i); if (interrupt_code != 0) return false; } return true; } void computer::put_parameter(int addr, int which, int value) { memory_write(addr + which, value); } int computer::start_network(int unit, int port) { network * n = new network(); n->unit = unit; dnets[unit] = n; n->sock = socket(AF_INET, SOCK_DGRAM, 0); if (n->sock < 0) { perror("socket"); return ERR_CANTCREATE; } struct sockaddr_in local; local.sin_len = sizeof(local); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(port); int r = 0; r = bindat(AT_FDCWD, n->sock, (struct sockaddr *) & local, sizeof(local)); if (r < 0) { perror("bindat"); return ERR_CANTCREATE; } unsigned int size = sizeof(local); getsockname(n->sock, (struct sockaddr *) & local, & size); n->port = ntohs(local.sin_port); return 0; } void computer::stop_network(int unit) { close(dnets[unit]->sock); } float decode_float(int n) { union { float fv; int iv; } converter; converter.iv = n; return converter.fv; } int encode_float(float n) { union { float fv; int iv; } converter; converter.fv = (float) n; return converter.iv; } int computer::perform_io_operation(int operation, int paramaddr) { if (! flsys) { sigint(__LINE__, INT_PRIVOP, fetch_pc); return -1; } int params[16]; int buffer[128]; switch (operation) { case IO_DISCCHECK: { bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; if (unit < 1 || unit > max_devices) return ERR_DEVNUMBER; return ddiscs[unit].size; } case IO_DISCCLEAR: { int r; bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; if (unit < 1 || unit > max_devices || ddiscs[unit].filenum < 0) return ERR_DEVNUMBER; close(ddiscs[unit].filenum); r = unlink(ddiscs[unit].filename.c_str()); if (r < 0) return ERR_DEVFAILED; int df = open(ddiscs[unit].filename.c_str(), O_RDWR | O_CREAT | O_BINARY, 0600); if (df < 0) return ERR_DEVFAILED; if (unit == dview.discnum) dview.setdisc(unit, df); ddiscs[unit].filenum = df; ddiscs[unit].mode = 'A'; return ddiscs[unit].size; } case IO_DISCREAD: { bool ok = get_parameter_block(paramaddr, 3, params); if (! ok) return ERR_READPARAMS; int unit = params[0], blockn = params[1], address = params[2]; int blockpos = blockn * 512; if (unit < 1 || unit > max_devices || ddiscs[unit].filenum < 0) return ERR_DEVNUMBER; if (blockn < 0 || blockn + 1 > ddiscs[unit].size) return ERR_POSITION; if (! check_memory_block(address)) return ERR_MEMORY; int n = lseek(ddiscs[unit].filenum, blockpos, SEEK_SET); n = read_a_block(ddiscs[unit].filenum, address); if (n < 0) return n; return 1; } case IO_DISCWRITE: { bool ok = get_parameter_block(paramaddr, 3, params); if (! ok) return ERR_READPARAMS; int unit = params[0], blockn = params[1], address = params[2]; int blockpos = blockn * 512; if (unit < 1 || unit > max_devices || ddiscs[unit].filenum < 0) return ERR_DEVNUMBER; if (blockn < 0 || blockn + 1 > ddiscs[unit].size) return ERR_POSITION; if (! check_memory_block(address)) return ERR_MEMORY; int n = lseek(ddiscs[unit].filenum, blockpos, SEEK_SET); n = write_a_block(ddiscs[unit].filenum, address, 512); if (n < 0) return n; return 1; } case IO_NETSS: { bool ok = get_parameter_block(paramaddr, 3, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; int onoff = params[1]; int address = params[2]; if (unit < 1 || unit > max_nets) return ERR_DEVNUMBER; if (onoff) { if (dnets[unit] != NULL) return ERR_INUSE; memory_write(address, 0); if (interrupt_code != 0) return ERR_MEMORY; int port = memory_read(address+1); if (interrupt_code != 0) return ERR_MEMORY; int r = start_network(unit, port); if (r < 0) return r; int a = * (int *)ipaddress, p = dnets[unit]->port; memory_write(address, a); memory_write(address + 1, p); } else { if (dnets[unit] == NULL) return ERR_DEVNUMBER; stop_network(unit); } return 1; } case IO_NETSEND: { bool ok = get_parameter_block(paramaddr, 4, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; int to = params[1]; int data = params[2]; int nbytes = params[3]; if (unit < 1 || unit > max_nets) return ERR_DEVNUMBER; if (dnets[unit] == NULL) return ERR_DEVNUMBER; if (nbytes < 0 || nbytes > 1024) return ERR_BADPARAM; int buffer[300]; int toaddr = memory_read(to); int toport = memory_read(to + 1); if (interrupt_code != 0) return ERR_MEMORY; int nwords = (nbytes + 3) / 4; if (nwords > 300) nwords = 300; for (int i = 0; i < nwords; i += 1) { buffer[i] = memory_read(data + i); if (interrupt_code != 0) return ERR_MEMORY; } struct sockaddr_in remote; remote.sin_len = sizeof(remote); remote.sin_family = AF_INET; remote.sin_addr.s_addr = toaddr; remote.sin_port = htons(toport); int r = sendto(dnets[unit]->sock, buffer, nbytes, MSG_EOR, (struct sockaddr *) & remote, sizeof(remote)); if (r < 0) return ERR_DEVFAILED; return 1; } case IO_NETRECV: { bool ok = get_parameter_block(paramaddr, 4, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; int from = params[1]; int data = params[2]; int maxwords = params[3]; if (unit < 1 || unit > max_nets) return ERR_DEVNUMBER; if (dnets[unit] == NULL) return ERR_DEVNUMBER; pollfd fds[1]; fds[0].fd = dnets[unit]->sock; fds[0].events = POLLIN | POLLRDNORM; fds[0].revents = 0; int r = poll(fds, 1, 0); if (r < 0) return ERR_DEVFAILED; if (r == 0) return ERR_NODATA; if ((fds[0].revents & POLLRDNORM) == 0) return ERR_NODATA; int buffer[300]; struct sockaddr_in remote; bzero(& remote, sizeof(remote)); unsigned int size = sizeof(remote); int nbytes = recvfrom(dnets[unit]->sock, buffer, sizeof(buffer), 0, (struct sockaddr *) & remote, & size); if (nbytes < 0) return ERR_DEVFAILED; memory_write(from, * (int *) & remote.sin_addr); memory_write(from + 1, ntohs(remote.sin_port)); if (interrupt_code != 0) return ERR_MEMORY; int nwords = (nbytes + 3) / 4; if (nwords > maxwords) nwords = maxwords; for (int i = 0; i < nwords; i += 1) { memory_write(data + i, buffer[i]); if (interrupt_code != 0) return ERR_MEMORY; } return nbytes; } case IO_TAPECHECK: { bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; if (unit < 1 || unit > max_devices) return ERR_DEVNUMBER; if (dtapes[unit].filenum >= 0) return dtapes[unit].mode; return 0; } case IO_TAPEREAD: { bool ok = get_parameter_block(paramaddr, 2, params); if (! ok) return ERR_READPARAMS; int unit = params[0], address = params[1]; if (unit < 1 || unit > max_devices || dtapes[unit].filenum < 0) return ERR_DEVNUMBER; if (! check_memory_block(address)) return ERR_MEMORY; int n = read_a_block(dtapes[unit].filenum, address); if (n < 0) return n; return n; } case IO_TAPEWRITE: { bool ok = get_parameter_block(paramaddr, 3, params); if (! ok) return ERR_READPARAMS; int unit = params[0], address = params[1], nbytes = params[2]; int nwords = (nbytes + 3) / 4; if (unit < 1 || unit > max_devices || dtapes[unit].filenum < 0) return ERR_DEVNUMBER; if (! check_memory_block(address)) return ERR_MEMORY; int n = write_a_block(dtapes[unit].filenum, address, nbytes); if (n < 0) return n; if (n != nbytes) return ERR_DEVFAILED; return nbytes; } case IO_TAPEREWIND: { bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; if (unit < 1 || unit > max_devices || dtapes[unit].filenum < 0) return ERR_DEVNUMBER; int n = lseek(dtapes[unit].filenum, 0, SEEK_SET); return 1; } case IO_TAPELOAD: { bool ok = get_parameter_block(paramaddr, 3, params); if (! ok) return ERR_READPARAMS; int unit = params[0], address = params[1], tmode = toupper(params[2]), fn; if (unit < 1 || unit > max_devices) return ERR_DEVNUMBER; if (tmode != 'R' && tmode != 'W') return ERR_BADPARAM; if (dtapes[unit].filenum >= 0) return ERR_INUSE; string fname = string_from_memory(address, 500); if (interrupt_code != 0) return ERR_MEMORY; if (tmode == 'W') fn = open(fname.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); else fn = open(fname.c_str(), O_RDONLY | O_BINARY); if (fn >= 0) { dtapes[unit].filenum = fn; dtapes[unit].filename = fname; dtapes[unit].mode = tmode; dtapes[unit].size = 1; } else { dtapes[unit].filenum = -1; dtapes[unit].filename = ""; dtapes[unit].mode = 0; dtapes[unit].size = 0; return ERR_NOTFOUND; } return 1; } case IO_TAPELOADFILE: { bool ok = get_parameter_block(paramaddr, 2, params); if (! ok) return ERR_READPARAMS; int addrname = params[0], address = params[1], fn; interrupt_code = 0; string fname = string_from_memory(addrname, 500); if (interrupt_code != 0) return ERR_MEMORY; fn = open(fname.c_str(), O_RDONLY | O_BINARY); if (fn < 0) return ERR_NOTFOUND; int r = read_file_to_memory(fn, address); close(fn); return r; } case IO_TAPELENGTH: { bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int unit = params[0], fn; if (unit < 1 || unit > max_devices) return ERR_DEVNUMBER; if (dtapes[unit].filenum <= 0) return ERR_NOTFOUND; struct stat info; ok = fstat(dtapes[unit].filenum, & info); if (ok < 0) return ERR_NOTFOUND; return info.st_size; } case IO_TAPESTAT: { bool ok = get_parameter_block(paramaddr, 2, params); if (! ok) return ERR_READPARAMS; int name = params[0], ptr = params[1]; string fname = string_from_memory(name, 500); if (interrupt_code != 0) return ERR_MEMORY; struct stat info; ok = stat(fname.c_str(), & info); if (ok < 0) return ERR_NOTFOUND; int i = info.st_birthtim.tv_sec - 946702800; memory_write(ptr, i); if (interrupt_code != 0) return ERR_MEMORY; i = info.st_mtim.tv_sec - 946702800; memory_write(ptr + 1, i); if (interrupt_code != 0) return ERR_MEMORY; i = (int)info.st_size; memory_write(ptr + 2, i); if (interrupt_code != 0) return ERR_MEMORY; return 1; } case IO_TAPEUNLOAD: { bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int unit = params[0]; if (unit < 1 || unit > max_devices) return ERR_DEVNUMBER; if (dtapes[unit].filenum < 0) return ERR_NOTFOUND; close(dtapes[unit].filenum); dtapes[unit].filenum = -1; dtapes[unit].filename = ""; dtapes[unit].mode = 0; dtapes[unit].size = 0; return 1; } case IO_TERMIN: { bool ok = get_parameter_block(paramaddr, 2, params); if (! ok) return ERR_READPARAMS; int maxnum = params[0], address = params[1], num = 0; while (num < maxnum) { int c = 0; if (stepping) { if (aside_buffer_any()) c = aside_buffer_take(); } else { if (k_any_ready()) c = k_read_char(); } int i=num >> 2, j = num & 3, v; if (j == 0) v = c & 0xFF; else { int kmask = ~ (0xFF << (j * 8)); v = memory_read(address + i) & kmask; v |= (c & 0xFF) << (j * 8); } memory_write(address + i, v); if (interrupt_code != 0) return ERR_MEMORY; if (c == 0) break; num += 1; } return num; } case IO_TERMOUT: { bool ok = get_parameter_block(paramaddr, 2, params); if (! ok) return ERR_READPARAMS; int maxnum = params[0], address = params[1]; string s = string_from_memory(address, maxnum); if (interrupt_code != 0) return ERR_MEMORY; if (stepping) printf("OUTPUT: '%s'\n\n", visiblestring(s).c_str()); else printf("%s", s.c_str()); fflush(stdout); return s.length(); } case IO_SECONDS: { time_t t = time(NULL); return t - 946702800; } case IO_USECONDS: { bool ok = get_parameter_block(paramaddr, 1, params); if (! ok) return ERR_READPARAMS; int address = params[0]; struct timeval tv; struct timezone tz; gettimeofday(& tv, & tz); tm * parts = localtime(& tv.tv_sec); tv.tv_sec -= 946702800; memory_write(address, tv.tv_sec); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 1, tv.tv_usec); if (interrupt_code != 0) return ERR_MEMORY; return 1; } case IO_DATETIME: { time_t t; bool ok = get_parameter_block(paramaddr, 2, params); if (! ok) return ERR_READPARAMS; if (params[0] == -1) t = time(NULL); else t = params[0] + 946702800; int address = params[1]; tm * now = localtime(& t); memory_write(address, 1900 + now->tm_year); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 1, 1 + now->tm_mon); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 2, now->tm_mday); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 3, now->tm_wday); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 4, now->tm_hour); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 5, now->tm_min); if (interrupt_code != 0) return ERR_MEMORY; memory_write(address + 6, now->tm_sec); if (interrupt_code != 0) return ERR_MEMORY; return 1; } case IO_FLOATFORMAT: { bool ok = get_parameter_block(paramaddr, 3, params); if (! ok) return ERR_READPARAMS; float val = decode_float(params[0]); int formatv = params[1], resultv = params[2]; string format = string_from_memory(formatv, 500); if (interrupt_code != 0) return ERR_MEMORY; snprintf((char *)buffer, 510, format.c_str(), val); int nch = strlen((char *)buffer); int wholes = (nch + 1) / 4, remain = (nch + 1) % 4; interrupt_code = 0; for (int i = 0; i < wholes; i += 1) { memory_write(resultv, buffer[i]); if (interrupt_code != 0) return ERR_MEMORY; resultv += 1; } if (remain != 0) { int last = buffer[wholes]; if (remain == 1) last = 0; else if (remain == 2) last &= 0xFF; else if (remain == 3) last &= 0xFFFF; memory_write(resultv, last); if (interrupt_code != 0) return ERR_MEMORY; } return 1; } default: return ERR_BADCODE; } } void decode_selector_sro(int v, int & size, int & toright, int & offset) { size = v & 31; if (size == 0) size = 32; toright = (v >> 5) & 31; offset = v >> 10; } int encode_selector_sro(int size, int toright, int offset) { if (size == 32) size = 0; return (offset << 10) | ((toright & 31) << 5) | (size & 31); } void computer::printinterrupt(int fromline, int ic, int fpc) { if (ic < 0 || ic >= num_interrupts) printf("\nMYSTERY INTERRUPT NUMBER %d (L%d from L%d)\n", ic, fromline, interrupt_fromline); else printf("\nINTERRUPT %s: %s (L%d from L%d)\n", interrupt_words(ic).c_str(), interrupt_desc(ic), fromline, interrupt_fromline); printf(" code=%d, address=%s, detail=%d, from PC %s\n", ic, hex(interrupt_address).c_str(), interrupt_detail, hex(fpc).c_str()); if (ic == INT_INTRFAULT) if (fcode == 0) printf(" extra reason: %s\n", freason); else printf(" extra reason: %s, %s: %s\n", freason, interrupt_words(fcode).c_str(), interrupt_desc(fcode)); fflush(stdout); } void computer::saywatch(int ic, bool & said) { if (said) return; if (ic == INT_WATCH || ic == INT_DEBUG) { if (ic == INT_WATCH) printf("\n\nWATCH LOCATION %s = %d ABOUT TO BE OVERWRITTEN\n\n", hex(sr_watch).c_str(), sr_watch); else printf("\n\nDEBUG BREAK LOCATION %s = %d REACHED\n\n", hex(sr_debug).c_str(), sr_debug); said = true; } } bool computer::prepare_interrupt(int fromline, int ic) { bool said = false, saidorig = false, saidnew = false, ok; unsigned int sp0 = sr_syssp, pc0 = fetch_pc; int ic0 = ic; if (ic < 0 || ic >= num_interrupts) ic = 0; int oic = ic, ic_stored, dest; oldinterrupt = 0; interrupt_code = 0; if (ic == INT_TIMER) sr_timer = 0; if (sr_ipl == INT_PAGEFAULT && ic == INT_PAGEFAULT) { if (traceints) printf("TI: PAGEFAULT during PAGEFAULT processing converted to PAGEFAULT2\n"); ic = INT_PAGEFAULT2; } if (ic < sr_ipl) { if (traceints) { printf("TI: lower priority %s while processing %s\n", interrupt_words(ic).c_str(), interrupt_words(sr_ipl).c_str()); if (ic >= 0 && ic < num_interrupts) printf(" %s will be ignored (SSP = %s)\n", interrupt_name[ic], hex(sr_syssp).c_str()); } if (ic == INT_TIMER) timer_ignored = true; else if (ic == INT_KEYBD) keybd_ignored = true; intevents.add('X', sp0, sr_syssp, pc0, ic0); return false; } if (stepping) saywatch(ic, said); if (! flint || sr_intvec == 0) { saywatch(ic, said); if (ic == INT_WATCH) { if (traceints) { printf("TI: INT flag = 0 or INTVEC = 0: interrupt WATCH will cause a stop\n"); fflush(stdout); } saved_watch = sr_watch; special_action = 1; watch_cause = INT_WATCH; sr_watch = 0; } else if (ic == INT_DEBUG) { if (traceints) { printf("TI: INT flag = 0 or INTVEC = 0: interrupt DEBUG will cause a stop\n"); fflush(stdout); } saved_watch = sr_debug; special_action = 1; watch_cause = INT_DEBUG; sr_debug = 0; } else if (ic == INT_KEYBD) { if (traceints) { printf("TI: INT flag = 0 or INTVEC = 0: interrupt KEYBD ignored (SSP %s)\n", hex(sr_syssp).c_str()); fflush(stdout); } intevents.add('X', sp0, sr_syssp, pc0, ic0); return false; } else if (ic == INT_RTERROR) { bool ok = hel.ready(); if (! ok) ok = debug_command(false); if (! ok) cout << "\nRun-time error but debugging information is not present\n"; else hel.report_on_error(_registers, pctrail[(trailcount - 2) & 15]); if (autoexit) exit(1); } else if (flint) { printinterrupt(fromline, ic, fetch_pc); interrupt_detail = oic; freason = "interrupt vector register is zero"; fcode = oic; printinterrupt(fromline, INT_INTRFAULT, fetch_pc); if (traceints) { printf("TI: INTVEC = 0, interrupt %s will cause a stop\n", interrupt_words(ic).c_str()); fflush(stdout); } } else { printinterrupt(fromline, ic, fetch_pc); if (traceints) { printf("TI: INT flag = 0, interrupt %s will cause a stop\n", interrupt_words(ic).c_str()); fflush(stdout); } } stepping = true; breaking = true; if (runwild) check_monitors(); runwild = false; autoexit = false; intevents.add('T', sp0, sr_syssp, pc0, ic0); return true; } if (stepping) { saywatch(ic, said); printinterrupt(fromline, ic, fetch_pc); saidorig = true; } intrcount += 1; intrtrail[intrcount & 15] = trailcount; intrnum[intrcount & 15] = ic; int oflsys = flsys, oflags = combine_flags(); registers(15) = fetch_pc; if (traceints) printf("TI: interrupt %s from PC = %s (SSP %s) being processed: %s\n", interrupt_words(ic).c_str(), hex(fetch_pc).c_str(), hex(sr_syssp).c_str(), interrupt_desc(ic)); flsys = 1; if (oflsys) for (int i = 0; i < 15 && interrupt_code == 0; i += 1) memory_write(sr_syssp - i - 1, sysregisters(i)); else for (int i = 0; i < 15 && interrupt_code == 0; i += 1) memory_write(sr_syssp - i - 1, usrregisters(i)); if (interrupt_code == 0) memory_write(sr_syssp - 16, interrupt_detail); if (interrupt_code == 0) memory_write(sr_syssp - 17, interrupt_address); if (interrupt_code == 0) { memory_write(sr_syssp - 18, ic); ic_stored = ic; } int ic_location = sr_syssp - 18; if (interrupt_code == 0) memory_write(sr_syssp - 19, oflags); if (interrupt_code == 0) memory_write(sr_syssp - 20, 38); if (interrupt_code == 0) { if (oflsys) memory_write(sr_syssp - 21, sysregisters(15)); else memory_write(sr_syssp - 21, usrregisters(15)); } if (interrupt_code != 0) { if (traceints) { printf(" Unable to push registers when processing interrupt %s\n", interrupt_words(ic).c_str()); fflush(stdout); } saywatch(oic, said); if (! saidorig) { printinterrupt(fromline, oic, fetch_pc); saidorig = true; } freason = "Unable to push registers onto system stack"; fcode = oic; ic = INT_SYSSTKFL; if (! saidnew) { printinterrupt(fromline, ic, fetch_pc); saidnew = true; } if (traceints) printf(" Attempting emergency jump to SYSSTKFL handler\n"); if (! physical_memory_exists(sr_intvec + ic)) { if (traceints) printf(" Interrupt vector address %s for SYSSTKFL does not exist\n", hex(sr_intvec + ic).c_str()); } else { dest = physical_memory_read(sr_intvec + ic); if (dest == 0) { if (traceints) printf(" Interrupt vector entry for SYSSTKFL is zero\n"); } else { flem = 1; set_special_register(SR_EMGRET, registers(PC) + 1); registers(PC) = dest; intframe[ic] = sr_syssp; if (traceints) printf(" Emergency jump to %s to process SYSSTKFL\n", hex(dest).c_str()); intevents.add('U', sp0, sr_syssp, pc0, ic0); return true; } } ic = INT_INTRFAULT; if (! saidnew) { printinterrupt(fromline, ic, fetch_pc); saidnew = true; } if (traceints) printf(" Attempting emergency jump to INTRFAULT handler\n"); if (! physical_memory_exists(sr_intvec + ic)) { if (traceints) printf(" Interrupt vector address %s for INTRFAULT does not exist\n", hex(sr_intvec + ic).c_str()); } else { dest = physical_memory_read(sr_intvec + ic); if (dest == 0) { if (traceints) printf(" Interrupt vector entry for INTRFAULT is zero\n"); } else { flem = 1; set_special_register(SR_EMGRET, registers(PC) + 1); registers(PC) = dest; intframe[ic] = sr_syssp; if (traceints) printf(" Emergency jump to %s to process INTRFAULT\n", hex(dest).c_str()); intevents.add('E', sp0, sr_syssp, pc0, ic0); return true; } } if (traceints) printf(" No emergency actions available, stopping.\n"); interrupt_code = 0; stepping = true; breaking = true; if (runwild) check_monitors(); runwild = false; flsys = oflsys; if (oic == INT_WATCH) { saved_watch = sr_watch; special_action = 1; watch_cause = INT_WATCH; sr_watch = 0; } else if (oic == INT_DEBUG) { saved_watch = sr_debug; special_action = 1; watch_cause = INT_DEBUG; sr_debug = 0; } tryingtostop = true; intevents.add('T', sp0, sr_syssp, pc0, ic0); autoexit = false; return true; } dest = 0; if (physical_memory_exists(sr_intvec + ic)) { dest = physical_memory_read(sr_intvec + ic); if (dest == 0) { if (traceints) printf(" Interrupt vector entry for %s is zero, switching to INTRFAULT\n", interrupt_words(ic).c_str()); freason = "Interrupt vector entry is zero"; } } else { if (traceints) printf(" Interrupt vector address %s for %s does not exist, switching to INTRFAULT\n", hex(sr_intvec + ic).c_str(), interrupt_words(ic).c_str()); freason = "Unable to read interrupt vector"; } if (dest == 0) { oldinterrupt = oic; interrupt_detail = oic; fcode = oic; if (stepping) saywatch(oic, said); if (stepping && ! saidorig) { printinterrupt(fromline, oic, fetch_pc); saidorig = true; } ic = INT_INTRFAULT; if (stepping && ! saidnew) { printinterrupt(fromline, ic, fetch_pc); saidnew = true; } memory_write(ic_location, ic); intframe[ic] = sr_syssp; ic_stored = ic; dest = 0; if (physical_memory_exists(sr_intvec + ic)) { dest = physical_memory_read(sr_intvec + ic); if (dest == 0) { if (traceints) printf(" Interrupt vector entry for INTRFAULT is zero, stopping.\n"); freason = "Interrupt vector entry is zero"; } } else { if (traceints) printf(" Interrupt vector address %s for INTRFAULT does not exist, stopping.\n", hex(sr_intvec + ic).c_str()); freason = "Unable to read interrupt vector"; } if (dest == 0) { saywatch(oic, said); if (! saidorig) { printinterrupt(fromline, oic, fetch_pc); saidorig = true; } interrupt_code = 0; printinterrupt(fromline, INT_INTRFAULT, fetch_pc); saidnew = true; stepping = true; breaking = true; if (runwild) check_monitors(); runwild = false; flsys = oflsys; if (oic == INT_WATCH) { saved_watch = sr_watch; special_action = 1; watch_cause = INT_WATCH; sr_watch = 0; } else if (oic == INT_DEBUG) { saved_watch = sr_debug; special_action = 1; watch_cause = INT_DEBUG; sr_debug = 0; } intevents.add('T', sp0, sr_syssp, pc0, ic0); autoexit = false; return true; } } if (ic == INT_WATCH) { intrsaved_watch = sr_watch; special_action = 0; watch_cause = INT_WATCH; saved_watch = 0; sr_watch = 0; } else if (ic == INT_DEBUG) { intrsaved_watch = sr_debug; watch_cause = INT_DEBUG; special_action = 0; saved_watch = 0; sr_debug = 0; } interrupt_being_processed = ic; sr_syssp -= 21; intsp = sr_syssp; intframe[ic] = sr_syssp; sr_ipl = ic; if (traceints) { printf(" Interrupt %s: calling interrupt handler at %s\n", interrupt_words(ic).c_str(), hex(dest).c_str()); fflush(stdout); } registers(PC) = dest; intevents.add('I', sp0, sr_syssp, pc0, ic0); return true; } void computer::execute() { int & pc = _registers[PC]; trailcount += 1; pctrail[trailcount & 15] = pc - 1; if (fulltrace) printf("execute - %08X - 1: %s r%d %d\n", pc, instruction_name[current_instruction.opcode], current_instruction.mainreg, current_instruction.number); if (interrupt_code != 0) { bool ok = prepare_interrupt(__LINE__, interrupt_code); if (ok) return; } int opcode = current_instruction.opcode; int mainregnum = current_instruction.mainreg; int & mainreg = registers(mainregnum); int operand = read_operand(); if (interrupt_code != 0) { if (opcode != OP_PHLOAD && opcode != OP_PHSTORE) { pc -= 1; bool ok = prepare_interrupt(__LINE__, interrupt_code); if (ok) return; } } execount += 1; switch (opcode) { case OP_HALT: { if (flsys) { flr = 0; reallyhalted = true; check_monitors(); } else sigint(__LINE__, INT_HALT, registers(PC)); break; } case OP_BAD0: case OP_BAD1: { sigint(__LINE__, INT_UNIMPOP, fetch_pc); break; } case OP_NOP: break; case OP_LOAD: { mainreg = operand; break; } case OP_LOADH: { mainreg &= 0xFFFF; mainreg |= operand<<16; break; } case OP_STORE: { write_operand(mainreg); break; } case OP_INC: { write_operand(operand + 1); break; } case OP_DEC: { write_operand(operand - 1); break; } case OP_ADD: { mainreg += operand; break; } case OP_SUB: { mainreg -= operand; break; } case OP_MUL: { mainreg *= operand; break; } case OP_DIV: { if (operand == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg /= operand; break; } case OP_MOD: { if (operand == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg %= operand; break; } case OP_UMUL: { unsigned int r = mainreg, o = operand; mainreg = r * o; break; } case OP_UDIV: { unsigned int r = mainreg, o = operand; if (o == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg = r / o; break; } case OP_UMOD: { unsigned int r = mainreg, o = operand; if (o == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg = r % o; break; } case OP_RSUB: { mainreg = operand - mainreg; break; } case OP_RDIV: { if (mainreg == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg = operand / mainreg; break; } case OP_RMOD: { if (mainreg == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg = operand % mainreg; break; } case OP_AND: { mainreg &= operand; break; } case OP_OR: { mainreg |= operand; break; } case OP_XOR: { mainreg ^= operand; break; } case OP_NOT: { mainreg = ~ operand; break; } case OP_SHL: { int bits = (mainreg >> (32 - operand)) & ((1 << operand) - 1); mainreg <<= operand; if (bits == 0) flz = 1; else flz = 0; break; } case OP_SHR: { int bits = mainreg & ((1 << operand) - 1); unsigned int r = mainreg; mainreg = r >> operand; if (bits == 0) flz = 1; else flz = 0; break; } case OP_COMP: { flz = 0; fln = 0; if (mainreg == operand) flz = 1; else if (mainreg < operand) fln = 1; break; } case OP_UCOMP: { unsigned int r = mainreg, o = operand; flz = 0; fln = 0; if (r == o) flz = 1; else if (r < o) fln = 1; break; } case OP_COMPZ: { flz = 0; fln = 0; if (operand == 0) flz = 1; else if (operand < 0) fln = 1; break; } case OP_TBIT: { int mask = 1 << operand; if ((mainreg & mask) == 0) flz = 0; else flz = 1; break; } case OP_SBIT: { int mask = 1 << operand; mainreg |= mask; break; } case OP_CBIT: { int mask = 1 << operand; mainreg &= ~ mask; break; } case OP_JUMP: { if (pc == operand + 1) uspleep(__LINE__, 10000); pc = operand; break; } case OP_JZER: { if (mainreg == 0) { if (pc == operand + 1) uspleep(__LINE__, 10000); pc = operand; } break; } case OP_JPOS: { if (mainreg >= 0) { if (pc == operand + 1) uspleep(__LINE__, 10000); pc = operand; } break; } case OP_JNEG: { if (mainreg < 0) { if (pc == operand + 1) uspleep(__LINE__, 10000); pc = operand; } break; } case OP_JCOND: { int jump = 0; if (mainregnum == COND_EQL) { if (flz) jump = 1; } else if (mainregnum == COND_NEQ) { if (! flz) jump = 1; } else if (mainregnum == COND_LSS) { if (fln) jump = 1; } else if (mainregnum == COND_LEQ) { if (flz || fln) jump = 1; } else if (mainregnum == COND_GTR) { if (!flz && !fln) jump = 1; } else if (mainregnum == COND_GEQ) { if (!fln) jump = 1; } else { sigint(__LINE__, INT_BADOP, fetch_pc); break; } if (jump) { if (pc == operand + 1) uspleep(__LINE__, 10000); pc = operand; } break; } case OP_GETFL: { mainreg = get_flag(operand); break; } case OP_SETFL: { int val = 0; if (mainreg != 0) val = 1; if (is_user_flag(operand) || flsys) set_flag(operand, val); else sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } case OP_GETSR: { mainreg = get_special_register(operand); break; } case OP_SETSR: { if (flsys) { set_special_register(operand, mainreg); if ((operand == SR_WATCH && watch_cause == INT_WATCH) || (operand == SR_DEBUG && watch_cause == INT_DEBUG)) { intrsaved_watch = 0; special_action = 0; saved_watch = 0; watch_cause = 0; watching_involved = 0; } } else sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } case OP_PUSH: { int & sp = registers(SP); memory_write(sp - 1, operand); if (interrupt_code == 0) sp -= 1; break; } case OP_POP: { int & sp = registers(SP); int value = memory_read(sp); if (interrupt_code == 0) write_operand(value); if (interrupt_code == 0) sp += 1; break; } case OP_MPUSH: { int & sp = registers(SP); int osp = sp; for (int i = 0, mask = 1; i < 16; i += 1, mask <<= 1) if (operand & mask) { memory_write(sp - 1, registers(i)); if (interrupt_code != 0) { sp = osp; break; } sp -= 1; } break; } case OP_MPOP: { int & sp = registers(SP); int pops[16], count = 0, osp = sp; for (int i = 15, mask = 0x8000; i >= 0; i -= 1, mask >>= 1) if (operand & mask) { pops[count] = memory_read(sp + count); if (interrupt_code != 0) break; count += 1; } if (interrupt_code != 0) break; sp += count; count = 0; for (int i = 15, mask = 0x8000; i >= 0; i -= 1, mask >>= 1) if (operand & mask) { registers(i) = pops[count]; count += 1; } break; } case OP_CALL: { int & sp = registers(SP); if (tracecalls) { if (pc - 1 == ignorecall1) ignoreret1 = pc; else if (pc - 1 == ignorecall2) ignoreret2 = pc; else if (pc - 1 == ignorecall3) ignoreret3 = pc; else if (pc - 1 == ignorecall4) ignoreret4 = pc; else printf("\nTC: CALL instruction at %s when SP = %s jumping to %s\n", hex(pc - 1).c_str(), hex(sp).c_str(), hex(operand).c_str()); } memory_write(sp - 1, pc); if (interrupt_code == 0) { sp -= 1; pc = operand; } break; } case OP_RET: { int & sp = registers(SP); int addr = memory_read(sp); if (tracecalls) if (addr == ignoreret1) ignoreret1 = 0; else if (addr == ignoreret2) ignoreret2 = 0; else if (addr == ignoreret3) ignoreret3 = 0; else if (addr == ignoreret4) ignoreret4 = 0; else printf("\nTC: RET instruction at %s returning to %s with SP = %s\n", hex(pc - 1).c_str(), hex(addr).c_str(), hex(sp + 1).c_str()); if (interrupt_code == 0) { sp += 1; pc = addr; } break; } case OP_LDCH: { int charnum = mainreg; int wordnum = charnum / 4; charnum -= 4 * wordnum; int shift = charnum * 8; int word = memory_read(operand + wordnum); if (interrupt_code == 0) mainreg = (word >> shift) & 0xFF; break; } case OP_LBITO: { int bitnum = mainreg; int wordnum = bitnum / 32; bitnum -= 32 * wordnum; int word = memory_read(operand + wordnum); if (interrupt_code == 0) mainreg = (word >> bitnum) & 1; break; } case OP_LBITF: { mainreg = (operand >> mainreg) & 1; break; } case OP_STCH: { int charnum = mainreg; int wordnum = charnum / 4; charnum -= 4 * wordnum; int shift = charnum * 8; int word = memory_read(operand + wordnum); word &= ~ (0xFF << shift); word |= (_registers[0] & 0xFF) << shift; if (interrupt_code == 0) memory_write(operand + wordnum, word); break; } case OP_SBITO: { int bitnum = mainreg; int wordnum = bitnum / 32; bitnum -= 32 * wordnum; int word = memory_read(operand + wordnum); word &= ~ (1 << bitnum); word |= (_registers[0] & 1) << bitnum; if (interrupt_code == 0) memory_write(operand + wordnum, word); break; } case OP_SBITF: { int val = operand & ~ (1 << mainreg); val |= (_registers[0] & 1) << mainreg; write_operand(val); break; } case OP_PERI: { if (! flsys) { sigint(__LINE__, INT_PRIVOP, fetch_pc); return; } int operation = memory_read(operand); if (interrupt_code != 0) break; int result = perform_io_operation(operation, operand + 1); if (interrupt_code == 0) mainreg = result; break; } case OP_FLAGSJ: { if (flsys) { decombine_flags(mainreg); pc = operand; } else sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } case OP_PAUSE: { unsigned int instrs = 4000000000, oprd = operand; int t1, t2, r; if (sr_timer > 0) { if (oprd < 307690) instrs = oprd * 13000LL; if (sr_timer <= instrs) { instrs = sr_timer; sr_timer = 2; } else { sr_timer -= instrs; if (sr_timer < 2) sr_timer = 2; } t1 = instrs / 13000000; t2 = instrs % 13000000 / 13 * 1000; } else { t1 = oprd / 1000; t2 = oprd % 1000 * 1000000; } timespec request, remaining; request.tv_sec = t1; request.tv_nsec = t2; unsigned long long int instrq = t1 * 13000000ull + t2 / 1000ull * 13ull; remaining.tv_sec = 0; remaining.tv_nsec = 0; r = nanosleep(& request, & remaining); unsigned long long int instrm = remaining.tv_sec * 13000000ull + remaining.tv_nsec / 1000ull * 13ull; execount += instrq - instrm; while (true) { int v = 0; if ((remaining.tv_nsec <= 0 && remaining.tv_sec <= 0) || ! wrong_signal_happened() || interrupt_code != 0) break; if (sr_intvec != 0 && kbd_rdy && (v = physical_memory_read(sr_intvec + INT_KEYBD)) != 0) break; clear_wrong_signal(); request = remaining; remaining.tv_sec = 0; remaining.tv_nsec = 0; instrq = request.tv_sec * 13000000ull + request.tv_nsec / 1000ull * 13ull; r = nanosleep(& request, & remaining); instrm = remaining.tv_sec * 13000000ull + remaining.tv_nsec / 1000ull * 13ull; execount += instrq - instrm; } break; } case OP_BREAK: { runwild = false; string s; if (operand == 0) printf("\n\nBREAK INSTRUCTION REACHED\n"); else printf("\n\nBREAK INSTRUCTION NUMBER %d%s REACHED\n", operand, charstring(" or '", operand, "'").c_str()); fflush(stdout); pc -= 1; stepping = true; check_monitors(); breaking = true; countdown = 0; break; } case OP_IRET: { unsigned int pc0 = fetch_pc, sp0 = sr_syssp; if (! flsys) { if (traceints) { printf("\nTI: IRET instruction at %s (SSP %s) when SYS flag is zero, signalling PRIVOP\n", hex(fetch_pc).c_str(), hex(sr_syssp).c_str()); fflush(stdout); } intevents.add('Q', sp0, sr_syssp, pc0, 0); sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } int flags, addr, tosys = 0, r[15], oldsp, thecode; oldsp = sr_syssp; intsp = 0; flags = memory_read(oldsp + 2); thecode = memory_read(oldsp + 3); if (interrupt_code != 0) { if (traceints) { printf("\nTI: IRET instruction at %s (SSP %s), stack at address %s or %s unreadable\n", hex(fetch_pc).c_str(), hex(sr_syssp).c_str(), hex(oldsp + 2).c_str(), hex(oldsp + 3).c_str()); fflush(stdout); } intevents.add('Q', sp0, sr_syssp, pc0, 0); return; } intframe[thecode] = 0; if (flags & FLAGMASK_SYS) tosys = 1; for (int i = 0; i < 15 && interrupt_code == 0; i+=1) r[i] = memory_read(oldsp + 20 - i); int backpc = memory_read(oldsp); if (interrupt_code != 0) { if (traceints && thecode != 0) { printf("\nTI: IRET instruction at %s (SSP %s) for interrupt %s: can not pop saved state from stack\n", hex(fetch_pc).c_str(), hex(sr_syssp).c_str(), interrupt_words(thecode).c_str()); fflush(stdout); } intevents.add('Q', sp0, sr_syssp, pc0, 0); return; } intframe[thecode] = 0; if (tosys) { sysregisters(15) = backpc; for (int i = 0; i < 15; i += 1) sysregisters(i) = r[i]; } else { usrregisters(15) = backpc; for (int i = 0; i < 15; i += 1) usrregisters(i) = r[i]; sr_syssp += 21; } decombine_flags(flags); if (intrsaved_watch) { if (watch_cause == INT_WATCH) { sr_watch = 0; saved_watch = 0; special_action = 1; } else if (watch_cause == INT_DEBUG) { sr_debug = 0; saved_watch = 0; special_action = 1; } watching_involved = 2; } interrupt_being_processed = get_special_register(SR_IPL); if (traceints && thecode != 0) { printf("\nTI: IRET instruction at %s (SSP %s), end of processing interrupt %s:\n return to %s at %s, SYS = %d\n", hex(fetch_pc).c_str(), hex(sr_syssp).c_str(), interrupt_words(thecode).c_str(), interrupt_being_processed == 0 ? "regular code" : interrupt_words(interrupt_being_processed).c_str(), hex(backpc).c_str(), flsys); fflush(stdout); } if (INT_KEYBD < INT_TIMER) { if (timer_ignored && INT_TIMER > interrupt_being_processed) { interrupt_code = INT_TIMER; timer_ignored = false; } else if (keybd_ignored && INT_KEYBD > interrupt_being_processed) { interrupt_code = INT_KEYBD; keybd_ignored = false; } } else { if (keybd_ignored && INT_KEYBD > interrupt_being_processed) { interrupt_code = INT_KEYBD; keybd_ignored = false; } else if (timer_ignored && INT_TIMER > interrupt_being_processed) { interrupt_code = INT_TIMER; timer_ignored = false; } } intevents.add('R', sp0, sr_syssp, pc0, 0); break; } case OP_SYSCALL: { unsigned int pc0 = fetch_pc, sp0 = sr_syssp; int ic0 = operand; if (operand < 0 || operand >= sr_cglen || sr_cgbr == 0) { sigint(__LINE__, INT_BADCALL, fetch_pc); interrupt_detail = operand; intevents.add('F', sp0, sr_syssp, pc0, ic0); break; } int dest = physical_memory_read(sr_cgbr + operand); if (interrupt_code != 0) { intevents.add('F', sp0, sr_syssp, pc0, ic0); return; } int ofl = combine_flags(), fromsys = flsys; flsys = 1; if (fromsys) for (int i = 0; i < 15 && interrupt_code == 0; i += 1) memory_write(sr_syssp - i - 1, sysregisters(i)); else for (int i = 0; i < 15 && interrupt_code == 0; i += 1) memory_write(sr_syssp - i - 1, usrregisters(i)); if (interrupt_code == 0) memory_write(sr_syssp - 16, mainregnum); if (interrupt_code == 0) memory_write(sr_syssp - 17, operand); if (interrupt_code == 0) memory_write(sr_syssp - 18, 0); if (interrupt_code == 0) memory_write(sr_syssp - 19, ofl); if (interrupt_code == 0) memory_write(sr_syssp - 20, 38); if (fromsys) memory_write(sr_syssp - 21, sysregisters(15)); else memory_write(sr_syssp - 21, usrregisters(15)); if (interrupt_code != 0) flsys = fromsys; sr_syssp -= 21; pc = dest; intevents.add('S', sp0, sr_syssp, pc0, ic0); break; } case OP_ATAS: { int v = operand; write_operand(1); if (interrupt_code != 0) return; mainreg = v; if (v == 1) uspleep(__LINE__, 10000); break; } case OP_PMEMR: { if (mainreg < 2) { rangeaccumulator * r = new rangeaccumulator(* this, 0, 0); memranges.process_all(r); if (interrupt_code == 0) mainreg = r->get_given() + 2; delete r; break; } int o = memory_read(operand); memory_write(operand, 0); if (interrupt_code != 0) break; memory_write(operand + 1, first_free - 1); if (interrupt_code != 0) { memory_write(operand, o); break; } rangeaccumulator * r = new rangeaccumulator(* this, operand + 2, mainreg - 3); memranges.process_all(r); if (interrupt_code == 0) mainreg = r->get_given() + 2; delete r; break; } case OP_PHLOAD: { if (flsys == 0) { sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } mainreg = physical_memory_read(operand); break; } case OP_PHSTORE: { if (flsys == 0) { sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } physical_memory_write(operand, mainreg); break; } case OP_CLRPP: { if (flsys == 0) { sigint(__LINE__, INT_PRIVOP, fetch_pc); break; } physical_memory_clear(operand); if (sr_timer != 0) { sr_timer -= 20; if (sr_timer < 2) sr_timer = 2; } break; } case OP_VTRAN: { int r = translate(operand); if (interrupt_code == 0) mainreg = r; break; } case OP_MOVE: { int num = registers(0); int src = mainreg; int dst = operand; if (current_instruction.indirect || current_instruction.number) { sigint(__LINE__, INT_BADOP, fetch_pc); break; } for (int i = 0; num > 0; i += 1) { if (interrupt_code != 0) break; if ((i & 7) == 6) { if (sr_timer == 2) break; else if (sr_timer > 2) sr_timer -= 1; i = 0; } int v = memory_read(src); if (interrupt_code != 0) break; memory_write(dst, v); if (interrupt_code != 0) break; src += 1; dst += 1; num -= 1; } registers(0) = num; mainreg = src; write_operand(dst); if (num > 0) pc -= 1; break; } case OP_ZERO: { int num = mainreg; int dst = operand; if (current_instruction.indirect || current_instruction.number) { sigint(__LINE__, INT_BADOP, fetch_pc); break; } for (int i = 0; num > 0; i += 1) { if (interrupt_code != 0) break; if ((i & 7) == 6) { if (sr_timer == 2) break; else if (sr_timer > 2) sr_timer -= 1; } memory_write(dst, 0); if (interrupt_code != 0) break; dst += 1; num -= 1; } mainreg = num; write_operand(dst); if (num > 0) pc -= 1; break; } case OP_FFNZ: { int last = operand; int i = 0, val = 1; bool found = false; if (interrupt_code != 0) break; while (mainreg <= last) { if ((i & 7) == 6) { if (sr_timer == 2) break; else if (sr_timer > 2) sr_timer -= 1; } val = memory_read(mainreg); if (interrupt_code != 0) break; if (val != 0) { found = true; break; } mainreg += 1; i += 1; } if (interrupt_code != 0) break; if (found) break; if (mainreg <= last) pc -= 1; else mainreg = -1; break; } case OP_SIGN: { if (operand < 0) mainreg = -1; else if (operand == 0) mainreg = 0; else mainreg = 1; break; } case OP_FADD: { mainreg = encode_float(decode_float(mainreg) + decode_float(operand)); break; } case OP_FSUB: { mainreg = encode_float(decode_float(mainreg) - decode_float(operand)); break; } case OP_FMUL: { mainreg = encode_float(decode_float(mainreg) * decode_float(operand)); break; } case OP_FDIV: { float fop = decode_float(operand); if (fop == 0) { sigint(__LINE__, INT_DIVZERO, fetch_pc); break; } mainreg=encode_float(decode_float(mainreg) / fop); break; } case OP_FCOMP: { flz = 0; fln = 0; float fm = decode_float(mainreg), fo = decode_float(operand); if (fm == fo) flz = 1; else if (fm < fo) fln = 1; break; } case OP_FCOMPZ: { flz = 0; fln = 0; float fz = (float) 0.0, fo = decode_float(operand); if (fo == fz) flz = 1; else if (fo < fz) fln = 1; break; } case OP_FIX: { mainreg = (int) decode_float(operand); break; } case OP_ALFIX: { float f = decode_float(operand); int i; if (f - floorf(f) == 0.5f) i = lroundf(ceilf(f)); else i = lroundf(f); mainreg = i; break; } case OP_FRND: { mainreg = encode_float(roundf(decode_float(operand))); break; } case OP_FLOAT: { mainreg = encode_float(operand); break; } case OP_FLOG: { float f = decode_float(operand); if (f < 0.0) { sigint(__LINE__, INT_FLTNEG, fetch_pc); break; } f = logf(f); mainreg = encode_float(f); break; } case OP_FEXP: { mainreg = encode_float(expf(decode_float(operand))); break; } case OP_FSQRT: { float f = decode_float(operand); if (f < 0.0) { sigint(__LINE__, INT_FLTNEG, fetch_pc); break; } f = sqrtf(f); mainreg = encode_float(f); break; } case OP_FSIN: { mainreg = encode_float(sinf(decode_float(operand))); break; } case OP_FCOS: { mainreg = encode_float(cosf(decode_float(operand))); break; } case OP_FABS: { mainreg = encode_float(fabsf(decode_float(operand))); break; } case OP_FATAN: { mainreg = encode_float(atanf(decode_float(operand))); break; } case OP_FLOOR: { mainreg = lroundf(floorf(decode_float(operand))); break; } case OP_FSIGN: { float f = decode_float(operand); if (f < 0) mainreg = -1; else if (f == 0) mainreg = 0; else mainreg = 1; break; } case OP_FGOOD: { float f = decode_float(operand); if (isnormal(f)) flz = 1; else flz = 0; break; } case OP_FFO: { bool found = false; unsigned int mask = 0x80000000; for (int i = 31; i >= 0; i -= 1) { if ((operand & mask) != 0) { mainreg = i; flz = 0; fln = 0; found = true; break; } mask >>= 1; } if (! found) { mainreg =- 1; flz = 1; fln = 1; } break; } case OP_FLZ: { bool found = false; unsigned int mask = 1; for (int i = 0; i < 32; i += 1) { if ((operand & mask) == 0) { mainreg = i; flz = 0; fln = 0; found = true; break; } mask <<= 1; } if (! found) { mainreg =- 1; flz = 1; fln = 1; } break; } case OP_RAND: { mainreg = random() & 0x7FFFFFFF; break; } case OP_TRACE: { printf("[%s: TRACE %d", hex(pc - 1).c_str(), operand); char c[5]; unsigned int n = operand, i = 0; while (n > 0 && i < 4) { int x = n & 0xFF; if (x > 0 && x < 32 || x > 126) { i = 0; break; } c[i] = x; n >>= 8; i += 1; } if (i == 1) printf(" '%c'", c[0]); else if (i == 2) printf(" '%c%c'", c[1], c[0]); else if (i == 3) printf(" '%c%c%c'", c[2], c[1], c[0]); else if (i == 4) printf(" '%c%c%c%c'", c[3], c[2], c[1], c[0]); if (mainregnum != 0) printf(", %s = %s = %d", register_name[mainregnum], hex(mainreg).c_str(), mainreg); printf("]\n"); fflush(stdout); break; } case OP_TYPE: { if (stepping) printf("OUTPUT: '%s'\n\n", visiblechar(operand & 0xFF).c_str()); else printf("%c", operand & 0xFF); fflush(stdout); break; } case OP_INCH: { if (k_any_ready()) write_operand(k_read_char()); else write_operand(-1); break; } case OP_ANDN: { mainreg &= ~ operand; break; } case OP_ORN: { mainreg |= ~ operand; break; } case OP_NEG: { mainreg = - operand; break; } case OP_SEXT: { int bit = mainreg & (1 << operand), mask; if (bit == 0) { mask = ((1 << operand) - 1); mainreg &= mask; } else { mask = ~ ((bit << 1) - 1); mainreg |= mask; } break; } case OP_FNEG: { mainreg = encode_float(0.0 - decode_float(operand)); break; } case OP_ROTL: { int bits = (mainreg >> (32 - operand)) & ((1 << operand) - 1); mainreg <<= operand; mainreg |= bits; break; } case OP_ROTR: { int bits = mainreg & ((1 << operand) - 1); unsigned int r = mainreg; mainreg = r >> operand; mainreg |= bits << (32-operand); break; } case OP_ASR: { int bits = mainreg & ((1 << operand) - 1); mainreg >>= operand; if (bits == 0) flz = 1; else flz = 0; break; } case OP_EXBR: { int size, toleft, offset, mask, toright; decode_selector_sro(mainreg, size, toright, offset); mask = ((1 << size) - 1) << toright; toleft = 32 - size - toright; registers(0) = ((operand & mask) << toleft) >> (toright + toleft); break; } case OP_UEXBR: { int size, offset, mask, toright; unsigned int val = operand; decode_selector_sro(mainreg, size, toright, offset); mask = ((1 << size) - 1) << toright; registers(0) = (val & mask) >> toright; break; } case OP_EXBRV: { int size, toleft, offset, mask, toright, val; decode_selector_sro(mainreg, size, toright, offset); val = memory_read(operand + offset); if (interrupt_code != 0) break; mask = ((1 << size) - 1) << toright; toleft = 32 - size - toright; registers(0) = ((val & mask) << toleft) >> (toright + toleft); break; } case OP_UEXBRV: { int size, offset, mask, toright; unsigned int val; decode_selector_sro(mainreg, size, toright, offset); val = memory_read(operand + offset); if (interrupt_code != 0) break; mask = ((1 << size) - 1) << toright; registers(0) = (val & mask) >> toright; break; } case OP_DPBR: { int size, toright, offset, nmask, omask, val; decode_selector_sro(mainreg, size, toright, offset); nmask = (1 << size) - 1; omask = ~ (nmask << toright); val = (operand & omask) | ((registers(0) & nmask) << toright); write_operand(val); break; } case OP_DPBRV: { int size, toright, offset, nmask, omask, val; decode_selector_sro(mainreg, size, toright, offset); nmask = (1 << size) - 1; omask = ~ (nmask << toright); val = memory_read(operand + offset); if (interrupt_code != 0) break; val = (val & omask) | ((registers(0) & nmask) << toright); memory_write(operand + offset, val); break; } case OP_ADJS: { int size, toright, offset; decode_selector_sro(mainreg, size, toright, offset); if (operand > 0) { int maxinc = (32 - toright - size) / size; if (operand <= maxinc) toright += size * operand; else { int remain = operand - maxinc - 1; int nperw = 32 / size; offset += 1 + remain / nperw; remain %= nperw; toright = size * remain; } } else if (operand < 0) { int maxdec = toright / size; int remain = - operand; if (remain <= maxdec) toright -= remain * size; else { remain -= maxdec + 1; int nperw = 32 / size; offset -= 1 + remain / nperw; remain %= nperw; toright = 32 - 32 % size - size * (remain + 1); } } mainreg = encode_selector_sro(size, toright, offset); break; } case OP_TICKS: { unsigned long long int v; if (mainregnum == 1) { v = memory_read(operand + 1); v <<= 32; v |= memory_read(operand); if (interrupt_code == 0) execount_subtract = sumexecount + execount - v; break; } else { v = sumexecount + execount - execount_subtract; memory_write(operand, v & 0xFFFFFFFFll); if (interrupt_code == 0) memory_write(operand + 1, (v >> 32) & 0xFFFFFFFFll); break; } } case OP_INTR: { interrupt_detail = mainreg; sigint(__LINE__, operand, fetch_pc); break; } default: { sigint(__LINE__, INT_UNIMPOP, fetch_pc); break; } } if (flr == 0 && ! reallyhalted) { autoexit = false; runwild = false; stepping = true; breaking = true; } } int computer::read_a_bit(int f, int n, unsigned int addr) { int * p = real_memory_address(addr); if (p == NULL) return ERR_MEMORY; int r = read(f, p, n); if (r < 0) return ERR_DEVFAILED; begin = *((int *)p + n / 4 - 1); return r; } int computer::write_a_bit(int f, int n, unsigned int addr) { int * p = real_memory_address(addr); if (p == NULL) return ERR_MEMORY; int r = write(f, p, n); if (r < 0) return ERR_DEVFAILED; return r; } int computer::read_a_block(int f, unsigned int address) { int offset = address & 0x7F; int wanted = 512 - offset * 4; int r1 = read_a_bit(f, wanted, address); if (r1 < 0) return ERR_DEVFAILED; if (r1 < wanted) return r1; wanted = 512 - r1; int r2 = 0; if (wanted > 0) { r2 = read_a_bit(f, wanted, address + (r1 + 3) / 4); if (r2 < 0) return ERR_DEVFAILED; } return r1 + r2; } int computer::write_a_block(int f, unsigned int address, int nbytes) { int offset = address & 0x7F; int maxtowrite = 512 - offset * 4; int wanted = maxtowrite; if (nbytes == 0) return 0; if (nbytes < wanted) wanted = nbytes; int r1 = write_a_bit(f, wanted, address); if (r1 < wanted) return r1; wanted = nbytes - r1; int r2 = 0; if (wanted > 0) { r2 = write_a_bit(f, wanted, address + (r1 + 3) / 4); if (r2 < wanted) return ERR_DEVFAILED; } return r1 + r2; } int computer::read_file_to_memory(int f, unsigned int address) { int total = 0, wanted, offset, r; off_t length = lseek(f, 0, SEEK_END); lseek(f, 0, SEEK_SET); offset = address & 0x7F; if (offset != 0) { wanted = 512 - offset * 4; r = read_a_bit(f, wanted, address); if (r < 0) return r; total += r; if (r < wanted) return (total + 3) / 4; address += (r + 3) / 4; length -= r; } while (length >= 512) { r = read_a_bit(f, 512, address); if (r < 0) return r; total += r; if (r < 512) return (total + 3) / 4; address += 128; length -= 512; } if (length > 0) { r = read_a_bit(f, length, address); if (r < 0) return r; total += r; } return (total + 3) / 4; } int computer::loadfile(loaditem * li, unsigned int dfltwhere, string & fullname) { bool isdll = false; string fname = li->fname; int fi; if (li->ext != "") { fname = fname + '.' + li->ext; if (li->ext == "dll") isdll = true; fullname = fname; fi = open(fname.c_str(), O_RDONLY); } else { fullname = fname + ".exe"; fi = open(fullname.c_str(), O_RDONLY); if (fi < 0) { fullname = fname + ".dll"; fi = open(fullname.c_str(), O_RDONLY); if (fi >= 0) isdll = true; else { fullname = fname; fi = open(fullname.c_str(), O_RDONLY); } } } if (fi < 0) { printf("can not load '%s': neither %s.exe nor %s.dll nor %s found\n", fname.c_str(), fname.c_str(), fname.c_str(), fname.c_str()); return ERR_NOTFOUND; } unsigned int addr = dfltwhere; if (li->haswhere) addr = li->where; unsigned int first = addr; li->where = addr; li->haswhere = true; int r = read_file_to_memory(fi, addr); if (r < 0) { close(fi); const char * err = "Unknown cause"; if (r == ERR_DEVFAILED) err = "Read from file failed"; else if (r == ERR_MEMORY) err = "Memory was not writable"; printf("\nLoading %s failed: %s\n\n", fullname.c_str(), err); return r; } close(fi); if (li->ext == "" && fullname == fname) printf("\nWarning: the name of the file loaded, %s, has no extension. Could it be a unix executable?\n\n", fullname.c_str()); li->fname = fullname; addr += r; if (addr > first_free) first_free = addr; li->end = addr - 1; if (! loaded_any) { if (init_pc == -1) { init_pc = first; fetch_pc = first; } if (isdll) { int num = memory_read(first) & 0xFFFF; begin += num + 1; } } loaded_any = true; fflush(stdout); return addr; } const char * display_any(int v, bool woulddec) { static char s[32]; if (woulddec) sprintf(s, "%-10d", v); else sprintf(s, "%s ", hex(v).c_str()); return s; } const char * display_hex(int v, bool woulddec) { static char s[32]; sprintf(s, "%s ", hex(v).c_str()); return s; } const char * display_dec(int v, bool woulddec) { static char s[32]; sprintf(s, "%-10d", v); return s; } const char * display_float(int v, bool woulddec) { float f = decode_float(v); static char s[32]; sprintf(s, "%e", f); return s; } void computer::debinfo(int force) { const char * (* sh)(int, bool) = display_any; if (force == 10) sh = display_dec; else if (force == 16) sh = display_hex; else if (force == 99) sh = display_float; putchar('\n'); for (int i = 0; i < 16; i += 1) { int j = ((i & 3) << 2) | ((i >> 2) & 3); int v = registers(j); printf(" %-3s= %s", register_name[j], sh(v, j <= 12 && v >= -9999 && v <= 9999)); if (j == SP) { if (current_instruction.notes & OPCODENOTE_USESSSP) { if (flsys) printf(" USRSP = %s", sh(_registers[SP], false)); else printf(" SYSSP = %s", sh(sr_syssp, false)); } } else if (j == FP) { if (current_instruction.notes & OPCODENOTE_USESSSP) { if (flsys) printf(" USRFP = %s", sh(_registers[FP], false)); else printf(" SYSFP = %s", sh(sr_sysfp, false)); } } if (i % 4 == 3) printf("\n"); } if (current_instruction.notes & OPCODENOTE_SPECREG) printf(" %s = %s\n", special_register_name(effective_address), sh(get_special_register(effective_address), false)); int cf = combine_flags(); if (force == 10) printf(" FLAGS = %d: ", cf); else printf(" FLAGS = %s: ", hex(cf).c_str()); for (int i = 5; i < num_flags; i += 1) { if (! (cf & (1 << i))) printf("~"); if (flags[i][0] == '$') printf("%s ", flags[i] + 1); else printf("%s ", flags[i]); } if (force == 16) printf("IPL = %s\n", hex(cf & 0x1F).substr(6).c_str()); else printf("IPL = %d\n", cf & 0x1F); if (current_instruction.indexreg != 0 && current_instruction.number != 0) { int v = registers(current_instruction.indexreg) + current_instruction.number; if (force == 10) printf(" %s%+0d = %d\n", register_name[current_instruction.indexreg], current_instruction.number, v); else if (force == 16) if (current_instruction.number >= 0) printf(" %s+%s = %s\n", register_name[current_instruction.indexreg], hex(current_instruction.number, 4).c_str(), hex(v).c_str()); else printf(" %s-%s = %s\n", register_name[current_instruction.indexreg], hex(- current_instruction.number, 4).c_str(), hex(v).c_str()); else printf(" %s%+0d = %s = %d\n", register_name[current_instruction.indexreg], current_instruction.number, hex(v).c_str(), v); } if (current_instruction.notes & OPCODENOTE_FLOATO) { if (current_instruction.indirect) { int v = memory_read(effective_address); if (force == 10) printf(" [%d] = %d = %s = %e\n", effective_address, v, aschars(v).c_str(), decode_float(v)); else if (force == 16) printf(" [%s] = %s = %s = %e\n", hex(effective_address).c_str(), hex(v).c_str(), aschars(v).c_str(), decode_float(v)); else printf(" [%s = %d] = %d = %s = %e\n", hex(effective_address).c_str(), effective_address, v, aschars(v).c_str(), decode_float(v)); } else printf(" operand = %e\n", decode_float(effective_address)); } else if (current_instruction.indirect) { int v = memory_read(effective_address); unsigned int uv = v; if (force == 10) printf(" [%d] = %d = %s\n", effective_address, v, aschars(v).c_str()); else if (force == 16) printf(" [%s] = %s = %s \n", hex(effective_address).c_str(), hex(uv).c_str(), aschars(v).c_str()); else printf(" [%s = %d] = %s = %d = %s\n", hex(effective_address).c_str(), effective_address, hex(uv).c_str(), v, aschars(v).c_str()); } if (current_instruction.notes & OPCODENOTE_FLOATR) printf(" %s = %f\n", register_name[current_instruction.mainreg], decode_float(registers(current_instruction.mainreg))); if (force == 10) printf("\n%d: (%d) %s ", fetch_pc, current_instruction.whole_value, current_instruction.printable(10).c_str()); else if (force == 16) printf("\n%s: (%s) %s ", hex(fetch_pc).c_str(), hex(current_instruction.whole_value).c_str(), current_instruction.printable(16).c_str()); else printf("\n%s: (%s) %s ", hex(fetch_pc).c_str(), hex(current_instruction.whole_value).c_str(), current_instruction.printable(0).c_str()); fflush(stdout); } void computer::postdebinfo() { if (current_instruction.notes & OPCODENOTE_FLOATR) printf(" %s = %e\n", register_name[current_instruction.mainreg], decode_float(registers(current_instruction.mainreg))); else if (current_instruction.notes & OPCODENOTE_SPECREG) printf(" %s = %s\n", special_register_name(effective_address), hex(get_special_register(effective_address)).c_str()); else if (current_instruction.mainreg != 0) printf(" %s = %s = %d\n", register_name[current_instruction.mainreg], hex(registers(current_instruction.mainreg)).c_str(), registers(current_instruction.mainreg)); if (current_instruction.indirect) { int v = memory_read(effective_address); unsigned int uv = v; printf(" [%s = %d] = %d = %s = %s\n", hex(effective_address).c_str(), effective_address, v, hex(uv).c_str(), aschars(v).c_str()); } fflush(stdout); } bool computer::read_initialisation(istream & f) { string line, item; bool hadversion = false; bool bad = false; for (int lnnum = 1; true; lnnum += 1) { getline(f, line); if (f.fail()) break; istringstream iss(line); iss >> item; if (iss.fail()) continue; if (item[0] == '/' && item[1] == '/') continue; if (same(item, "quiet")) quiet = true; else if (same(item, "random")) srandomdev(); else if (same(item, "version")) { long long int ourversion = 0; iss >> ourversion; if (ourversion < newversion) warn(); hadversion = true; } else if (same(item, "memory")) { int from, to; iss >> item; if (iss.fail()) { fprintf(stderr, "system.setup line %d, no address after 'memory'\n", lnnum); bad = true; break; } bool ok = string_to_int(item, from, 16); if (! ok) { fprintf(stderr, "system.setup line %d, '%s' not a number\n", lnnum, item.c_str()); bad = true; break; } iss >> item; if (iss.fail()) to = from; else if (same(item, "to")) { iss >> item; if (iss.fail()) { fprintf(stderr, "system.setup line %d, no address after 'to'\n", lnnum); bad = true; break; } bool ok = string_to_int(item, to, 16); if (! ok) { fprintf(stderr, "system.setup line %d, '%s' not a number\n", lnnum, item.c_str()); bad = true; break; } } if (ok) { iss >> item; if (! iss.fail()) ok = false; } if (! ok) { fprintf(stderr, "system.setup line %d, memory parameter confused '%s'\n", lnnum, item.c_str()); bad = true; break; } unsigned int a1 = from & 0xFFFF0000, a2 = to & 0xFFFF0000; if (a1 > a2) { fprintf(stderr, "system.setup line %d, memory range starts higher than it ends\n", lnnum); bad = true; break; } for (unsigned int a = a1; a <= a2; a += 0x10000) { physical_memory_create(a); if (interrupt_code != 0) { fprintf(stderr, "system.setup line %d, failed to create memory at address %s, maybe asking for too much\n", lnnum, hex(a).c_str()); bad = true; break; } } if (a1 == 0) max_mem = (a2 | 0xFFFF) + 1; } else if (same(item, "load")) { int address; iss >> item; if (iss.fail()) { fprintf(stderr, "system.setup line %d, no file name or at after 'load'\n", lnnum); bad = true; break; } if (item == "at") { iss >> item; if (iss.fail()) { fprintf(stderr, "system.setup line %d, no value after 'load at'\n", lnnum); bad = true; break; } bool ok = string_to_int(item, address, 16); if (! ok) { fprintf(stderr, "system.setup line %d, '%s' not a number\n", lnnum, item.c_str()); bad = true; break; } iss >> item; if (! iss.fail()) { fprintf(stderr, "system.setup line %d, start parameter confused '%s'\n", lnnum, item.c_str()); bad = true; break; } if (! quiet) printf("set load address to %s\n", hex(address).c_str()); loadplace = address; } else { string name, ext; bool hadat = false; prepare_filename(item, name, ext); if (ext == "b") ext = ""; iss >> item; if (iss.fail()) hadat = false; else if (! same(item, "at")) { fprintf(stderr, "system.setup line %d, no 'at' after 'load %s'\n", lnnum, name.c_str()); bad = true; break; } else { iss >> item; if (iss.fail()) { fprintf(stderr, "system.setup line %d, no address after 'at'\n", lnnum); bad = true; break; } bool ok = string_to_int(item, address, 16); if (! ok) { fprintf(stderr, "system.setup line %d, '%s' not a number\n", lnnum, item.c_str()); bad = true; break; } hadat = true; } iss >> item; if (! iss.fail()) { fprintf(stderr, "system.setup line %d, load parameter confused '%s'\n", lnnum, item.c_str()); bad = true; break; } if (hadat) toload.push_back(new loaditem(name, ext, address)); else toload.push_back(new loaditem(name, ext)); } } else if (same(item, "sp") || same(item, "pc") || same(item, "fp")) { int regnum = -1; for (int i = 0; i < 16; i += 1) { if (same(item, register_name[i])) { regnum = i; break; } } if (regnum != -1) { int value; iss >> item; if (iss.fail()) { fprintf(stderr, "system.setup line %d, no value after '%s'\n", lnnum, register_name[regnum]); bad = true; break; } bool ok = string_to_int(item, value, 16); if (! ok) { fprintf(stderr, "system.setup line %d, '%s' not a number\n", lnnum, item.c_str()); bad = true; break; } iss >> item; if (! iss.fail()) { fprintf(stderr, "system.setup line %d, %s parameter confused '%s'\n", lnnum, register_name[regnum], item.c_str()); bad = true; break; } if (! quiet) printf("set %s to %s\n", register_name[regnum], hex(value).c_str()); if (regnum == 15) { init_pc = value; fetch_pc = value; } usrregisters(regnum) = value; sysregisters(regnum) = value; } else { fprintf(stderr, "system.setup line %d, '%s' unknown parameter\n", lnnum, item.c_str()); bad = true; break; } } else if (same(item, "disc")) { int unit, size; string name; iss >> unit; if (iss.fail()) { fprintf(stderr, "system.setup line %d, unit number required after 'disc'\n", lnnum); bad = true; break; } if (unit < 1 || unit > max_devices) { fprintf(stderr, "system.setup line %d, range for unit number is 1 to %d\n", lnnum, max_devices); bad = true; break; } iss >> name; if (iss.fail()) { fprintf(stderr, "system.setup line %d, name required after 'disc %d'\n", lnnum, unit); bad = true; break; } iss >> size; if (iss.fail()) { fprintf(stderr, "system.setup line %d, size (in blocks) required after 'disc %d %s'\n", lnnum, unit, name.c_str()); bad = true; break; } string fname, base, ext; prepare_filename(name, base, ext); if (ext == "") fname = base + ".disc"; else fname = name; int df = open(fname.c_str(), O_RDWR | O_CREAT | O_BINARY, 0600); if (df < 0) { fprintf(stderr, "system.setup line %d, failed to find/create '%s'\n", lnnum, name.c_str()); bad = true; break; } if (! quiet) printf("disc %d from file '%s', maximum %d blocks\n", unit, fname.c_str(), size); if (unit == 1) dview.setdisc(1, df); ddiscs[unit].filenum = df; ddiscs[unit].filename = fname; ddiscs[unit].mode = 'A'; ddiscs[unit].size = size; } } if (! hadversion) { warn(); return false; } return ! bad; } bool computer::read_initialisation() { ifstream f("system.setup"); int r = true; if (f.fail()) { ifstream g("/usr/local/bcpl/system.setup"); if (g.fail()) { fprintf(stderr, "Can not find any 'system.setup' file\n"); return false; } if (! quiet) fprintf(stderr, "No 'system.setup' in current directory, copying '/usr/local/bcpl/system.setup'\n"); ofstream h("system.setup"); while (true) { string s; getline(g, s); if (g.fail()) break; h << s << "\n"; } g.close(); h.close(); ifstream e("system.setup"); if (e.fail()) { fprintf(stderr, "Copying failed, can not read 'system.setup' file\n"); return false; } bool r = read_initialisation(e); e.close(); } else { bool r = read_initialisation(f); f.close(); } return r; } void unixigint(int a) { if (control_c) exit(1); control_c = true; } string computer::enstring_operand(const operand & o) { string s = ""; char t[16]; if (o.kind == '?') return "???"; if (o.excl) s += '!'; if (o.kind == 'N') { s += hex(o.offset); return s; } if (o.kind == 'R') s += register_name[o.index]; else if (o.kind == 'S') s += specregs[o.index] + 1; else if (o.kind == 'F') { s += 'F'; s += flags[o.index] + 1; } if (o.haso) { sprintf(t, "%+d", o.offset); s += t; } return s; } bool computer::check_operand(string s, operand & o) { bool ok; int n; o.kind = '?'; o.index = 0; o.haso = false; o.excl = false; o.offset = 0; makeupper(s); if (s[0] == '!') { o.excl = true; s = s.substr(1); } size_t p = s.find_first_of("+-"); if (p == 0) { ok = string_to_int(s.substr(1), o.offset, 16); if (! ok) return false; if (s[0] == '-') o.offset = - o.offset; o.kind = 'N'; return true; } if (p != string::npos) { char sign = s[p]; string off = s.substr(p + 1); s = s.substr(0, p); ok = string_to_int(off, o.offset, 10); if (! ok) return false; if (sign == '-') o.offset = - o.offset; o.haso = true; } for (int i = 0; i < 16; i += 1) if (s == register_name[i]) { o.index = i; o.kind = 'R'; return true; } for (int i = 0; i < num_specregs; i += 1) if (s == specregs[i] + 1) { o.index = i; o.kind = 'S'; return true; } if (o.haso) return false; if (s[0] == 'F') { s = s.substr(1); for (int i = 5; i < num_flags; i += 1) if (s == flags[i] + 1) { o.index = i; o.kind = 'F'; return true; } return false; } ok = string_to_int(s, n, 16); if (ok) { o.kind = 'N'; o.offset = n; return true; } if (s.length() < 6) return false; ok = string_to_int(s.substr(5), n, 10); if (! ok) return false; o.kind = 'R'; o.index = 14; o.haso = true; s = s.substr(0, 5); if (same(s, "LOCAL")) { o.offset = - n; return true; } if (same(s, "PARAM")) { o.offset = n + 2; return true; } return false; } bool computer::operand_refers_to_memory(operand & o, int & where, bool physonly) { if (o.excl) { int w; o.excl = false; bool ok = evaluate_operand(o, w, physonly, false); o.excl = true; if (! ok) return false; return debugread(w, where, physonly, false); } if (o.kind == 'N') return false; if (o.kind == 'R' && o.haso) { where = registers(o.index) + o.offset; return true; } if (o.kind == 'S' && o.haso) { where = get_special_register(o.index) + o.offset; return true; } return false; } bool computer::evaluate_operand(const operand & o, int & val, bool physonly, bool noisy) { int n; bool ok; if (o.kind == 'N') n = o.offset; else if (o.kind == 'R') n = registers(o.index); else if (o.kind == 'S') n = get_special_register(o.index); else if (o.kind == 'F') n = get_flag(o.index); if (o.haso) n += o.offset; if (o.excl) { ok = debugread(n, val, physonly, noisy); if (! ok) return false; } else val = n; return true; } bool computer::set_operand(const operand & o, int val, bool physonly, bool noisy) { int n = 0, addr; bool ok; if (o.kind == 'S' && ! o.haso && ! o.excl) { set_special_register(o.index, val); if ((o.index == SR_WATCH && watch_cause == INT_WATCH) || (o.index == SR_DEBUG && watch_cause == INT_DEBUG)) { intrsaved_watch = 0; special_action = 0; saved_watch = 0; watch_cause = 0; watching_involved = 0; } return true; } if (o.kind == 'R' && ! o.haso && ! o.excl) { registers(o.index) = val; return true; } if (o.kind == 'F' && ! o.haso && ! o.excl) { set_flag(o.index, val); return true; } if (o.kind == 'S') n = get_special_register(o.index); else if (o.kind == 'R') n = registers(o.index); else if (o.kind == 'F') n = get_flag(o.index); if (o.haso) n += o.offset; if (o.kind == 'N') n = o.offset; if (o.excl) { ok = debugread(n, addr, physonly, noisy); if (! ok) return false; return debugwrite(addr, val, physonly, noisy); } else return debugwrite(n, val, physonly, noisy); } char computer::operand_or_value(string s, operand & o, int & val, bool physonly, bool noisy) { bool ok = check_operand(s, o); if (ok) { ok = evaluate_operand(o, val, physonly, noisy); if (! ok) return 'X'; return 'O'; } if (begins(s, "?")) { if (! hel.ready()) { ok = debug_command(); if (! ok) return 'X'; } vector v; s = s.substr(1); string error = hel.lookup_symbol(s, v); if (error != "") { printf("\n%s\n\n", error.c_str()); return 'X'; } if (v.size() > 1) { if (noisy) printf("multiple definitions for symbol %s, use file/function to disambiguate\n", s.c_str()); return 'X'; } val = v[0]->location; return 'U'; } if (begins(s, "f?")) { if (! hel.ready()) { ok = debug_command(); if (! ok) return 'X'; } s = s.substr(2); string exef = ""; size_t p = s.find('/'); if (p != string::npos) { exef = s.substr(0, p); s = s.substr(p + 1); } vector v; hel.find_file_name(s, exef, v); if (v.size() == 0) { if (noisy) { if (exef == "") printf("the file %s has not been loaded\n", s.c_str()); else printf("the file %s has not been loaded from %s\n", s.c_str(), exef.c_str()); } return 'X'; } if (v.size() > 1) { if (noisy) printf("the file %s was loaded from more than one executable, use exe/file to disambiguate\n", s.c_str()); return 'X'; } val = v[0]->start; return 'I'; } if (noisy) printf("\n%s: not recognised\n\n", s.c_str()); return 'X'; } bool computer::calculate(nistringstream & iss, int & outvalue, bool physonly) { vector stack; operand o; int value; bool ok; string s; while (true) { iss >> s; if (iss.fail()) break; char t = operand_or_value(s, o, value, physonly, false); if (t == 'O' || t == 'U' || t == 'I') { stack.push_back(value); continue; } else if (s == "+" || s == "-" || s == "*" || s == "/" || same(s, "rem") || s == "<<" || s == ">>") { if (stack.size() < 2) { printf("\noperator %s when only %d items on the stack\n\n", s.c_str(), stack.size()); return false; } int b = stack.back(); stack.pop_back(); int a = stack.back(); stack.pop_back(); if (s == "+") stack.push_back(a + b); else if (s == "-") stack.push_back(a - b); else if (s == "*") stack.push_back(a * b); else if (s == "/") { if (b == 0) { printf("\ndivision by zero\n\n"); return false; } stack.push_back(a / b); } else if (same(s, "rem")) { if (b == 0) { printf("\nmodulo zero\n\n"); return false; } stack.push_back(a % b); } else if (s == "<<") stack.push_back(a << b); else if (s == ">>") stack.push_back(a >> b); } else if (s == "!") { if (stack.size() < 1) { printf("\noperator ! on empty stack\n\n"); return false; } int a = stack.back(), b; stack.pop_back(); ok = debugread(a, b, physonly, true); if (! ok) return false; stack.push_back(b); } else { printf("\nunrecognised symbol %s, valid operators are + - * / rem << >> !\n\n", s.c_str()); return false; } } if (stack.size() == 0) { printf("\ninvalid formula, stack is empty\n\n"); return false; } if (stack.size() > 1) { printf("\ninvalid formula, %d things left on the stack\n\n", stack.size()); return false; } outvalue = stack.back(); return true; } void computer::handle_here(int here, int reladdr, const char * relname) { if (here == reladdr && relname[0] != 0) printf(" %-3s ", relname); else if (here == registers(FP)) printf(" FP "); else if (here == registers(SP)) printf(" SP "); else if (here == registers(PC)) printf(" PC "); else printf(" "); } void computer::actual_show_range(unsigned int a1, unsigned int a2, bool physonly, char kind, char option, int reladdr, const char * relname) { bool backwards = false, ok; int num, v; if (kind == ':') { if (a2 < 0) { backwards = true; num = - a2; } else num = a2; } else { if (a2 < a1) { backwards = true; num = a1 - a2 + 1; } else num = a2 - a1 + 1; } if (num > 500) { printf("\nthat's too much to print, it will be limited to 500 items\n\n"); num = 500; } if (backwards) for (int i = 0; i < num; i += 1) { int a = a1 - i; ok = debugread(a, v, physonly, false); handle_here(a, reladdr, relname); if (! ok) printf("%s: unreadable\n", hex(a).c_str()); else if (option == 'D') { decoded_instruction di(v); printf("%s: %s = %-10d [%s] = %s\n", hex(a).c_str(), hex(v).c_str(), v, di.printable().c_str(), aschars(v).c_str()); } else printf("%s: %s = %-10d = %s\n", hex(a).c_str(), hex(v).c_str(), v, aschars(v).c_str()); } else for (int i = 0; i < num; i += 1) { int a = a1 + i; ok = debugread(a, v, physonly, false); handle_here(a, reladdr, relname); if (! ok) printf("%s: unreadable\n", hex(a).c_str()); else if (option == 'D') { decoded_instruction di(v); printf("%s: %s = %-12d [%s] = %s\n", hex(a).c_str(), hex(v).c_str(), v, di.printable().c_str(), aschars(v).c_str()); } else printf("%s: %s = %-12d = %s\n", hex(a).c_str(), hex(v).c_str(), v, aschars(v).c_str()); } printf("\n"); } void computer::debugshow(nistringstream & iss, bool physonly, char option) { string s, orig; bool ok, colonhad = false, backwards = false, relpc = false, couldbe = false; operand o1, o2; int v1, v2, len, reladdr = 0; const char * relname = " "; iss.setseps(":"); iss >> s; if (iss.fail()) { printf("nothing to show\n\n"); return; } char t = operand_or_value(s, o1, v1, physonly, true); if (t == 'X') return; orig = s; if (o1.kind == 'R') { if (o1.index == 15) option = 'D'; reladdr = registers(o1.index); relname = register_name[o1.index]; } iss >> s; if (iss.fail()) { if (t == 'U' || t == 'I' || o1.kind == 'N' && ! o1.excl) printf("\n %s = %-12d;", hex(v1).c_str(), v1); else printf("\n %s = %s = %-12d;", enstring_operand(o1).c_str(), hex(v1).c_str(), v1); ok = true; if (physonly || ! flvm) { if (physical_memory_exists(v1)) v2 = memory_read(v1); else ok = false; } else { interrupt_code = 0; v2 = memory_read(v1); if (interrupt_code != 0) ok = false; interrupt_code = 0; } if (ok) { if (option == 'D') { decoded_instruction di(v2); printf(" %s: %s = %-12d [%s] = %s\n", hex(v1).c_str(), hex(v2).c_str(), v2, di.printable().c_str(), aschars(v2).c_str()); } else printf(" %s: %s = %-12d = %s\n\n", hex(v1).c_str(), hex(v2).c_str(), v2, aschars(v2).c_str()); } else printf(" %s: unreadable\n\n", hex(v1).c_str()); return; } if (same(s, "for") || s == ":") { iss >> s; if (iss.fail()) { printf("\nFOR or : must be followed by a number\n\n"); return; } ok = string_to_int(s, v2, 10); if (! ok) { printf("\n%s: not recognised as a number\n\n", s.c_str()); return; } actual_show_range(v1, v2, physonly, ':', option, reladdr, relname); } else if (same(s, "to") || s == "-") { iss >> s; if (iss.fail()) { printf("\nneed an address after TO\n\n"); return; } char t = operand_or_value(s, o2, v2, physonly, true); if (t == 'X') return; actual_show_range(v1, v2, physonly, '-', option, reladdr, relname); } else { printf("\n%s: not understood\n\n", s.c_str()); return; } } bool computer::debugread(int address, int & value, bool physonly, bool noisy) { interrupt_code = 0; if (physonly) { if (! physical_memory_exists(address)) { if (noisy) printf("\nthere is no memory installed at location %s\n\n", hex(address).c_str()); return false; } value = physical_memory_read(address); return true; } if (! flvm && ! physical_memory_exists(address)) { if (noisy) printf("\nthere is no memory installed at location %s\n\n", hex(address).c_str()); return false; } value = memory_read(address); if (interrupt_code != 0) { if (noisy) printf("memory at %s can not be read: %s: %s\n", hex(address).c_str(), interrupt_words(interrupt_code).c_str(), interrupt_desc(interrupt_code)); interrupt_code = 0; return false; } return true; } bool computer::debugwrite(int address, int value, bool physonly, bool noisy) { interrupt_code = 0; if (physonly) { if (! physical_memory_exists(address)) { if (noisy) printf("\nthere is no memory installed at location %s\n\n", hex(address).c_str()); return false; } physical_memory_write(address, value); return true; } if (! flvm && ! physical_memory_exists(address)) { if (noisy) printf("\nthere is no memory installed at location %s\n\n", hex(address).c_str()); return false; } memory_write(address, value); if (interrupt_code != 0) { if (noisy) printf("memory at %s can not be written: %s: %s\n", hex(address).c_str(), interrupt_words(interrupt_code).c_str(), interrupt_desc(interrupt_code)); interrupt_code = 0; return false; } return true; } void computer::debugset(nistringstream & iss, bool physonly) { string s; operand o; bool ok; int v, where, orig; iss.setseps("="); iss >> s; if (iss.fail()) { printf("\nnothing to set\n\n"); return; } char t = operand_or_value(s, o, v, physonly, true); if (t == 'X') return; if (t == 'I') { printf("\nyou can't overwrite a file this way\n\n"); return; } if (t == 'U') { o.kind = 'N'; o.offset = v; } bool relpc = o.kind == 'R' && o.index == 15; int p = iss.tellg(); iss.setseps("="); iss >> s; if (iss.fail()) { printf("\nno value to set it to\n\n"); return; } if (s == "=") ok = calculate(iss, v, physonly); else { iss.seekg(p); ok = calculate(iss, v, physonly); } if (! ok) return; if (o.kind == 'N') { if (o.excl) { ok = debugread(o.offset, where, physonly, true); if (! ok) { printf("%s: unreadable\n\n", hex(o.offset).c_str()); return; } ok = debugwrite(where, v, physonly, true); if (! ok) { printf("%s: unwritable\n\n", hex(where).c_str()); return; } ok = debugread(where, v, physonly, true); if (! ok) { printf("%s: unreadable\n\n", hex(where).c_str()); return; } printf("\n !%s: %s set to %s = %d\n\n", hex(o.offset).c_str(), hex(where).c_str(), hex(v).c_str(), v); return; } else { ok = debugwrite(o.offset, v, physonly, true); if (! ok) { printf("%s: unwritable\n\n", hex(o.offset).c_str()); return; } ok = debugread(o.offset, v, physonly, true); if (! ok) { printf("%s: unreadable\n\n", hex(o.offset).c_str()); return; } printf("\n %s set to %s = %d\n\n", hex(o.offset).c_str(), hex(v).c_str(), v); return; } } if (o.excl) { o.excl = false; evaluate_operand(o, orig, physonly, true); o.excl = true; } bool reftom = operand_refers_to_memory(o, where, physonly); ok = set_operand(o, v, physonly, true); if (! ok) { printf("\n%s: unwritable\n\n", enstring_operand(o).c_str()); return; } if (reftom) { ok = debugread(where, v, physonly, true); if (! ok) { printf("\n%s: unreadable\n\n", hex(where).c_str()); return; } if (o.excl) { o.excl = false; printf("\n %s", enstring_operand(o).c_str()); o.excl = true; printf(" = %s", hex(orig).c_str()); } else printf("\n %s", enstring_operand(o).c_str()); printf(": %s set to %s = %d", hex(where).c_str(), hex(v).c_str(), v); if (relpc) { decoded_instruction di(v); printf(" [%s]", di.printable().c_str()); } printf("\n\n"); } else { evaluate_operand(o, v, physonly, true); printf("\n %s set to %s = %d\n\n", enstring_operand(o).c_str(), hex(v).c_str(), v); } } void computer::debprintall() /* { printf("\n"); for (int i = 0; i < 16; i += 1) { int j = ((i & 3) << 2) | ((i >> 2) & 3); int v = registers(j); if (j > 12 || v < -9999 || v > 9999) printf(" %-3s= %s", register_name[j], hex(v).c_str()); else printf(" %-3s= %-10d", register_name[j], v); if (i % 4 == 3) printf("\n"); } printf("FLAGS %s: R=%d Z=%d N=%d SYS=%d EM=%d VM=%d INT=%d\n", hex(combine_flags()).c_str(), flr, flz, fln, flsys, flem, flvm, flint); */ { debinfo(0); printf(" PDBR = %s, INTVEC = %s, CGBR = %s, EXITCODE = %d, EMGRET = %s\n", hex(sr_pdbr).c_str(), hex(sr_intvec).c_str(), hex(sr_cgbr).c_str(), sr_exitcode, hex(sr_emgret).c_str()); printf(" DEBUG = %s, TIMER = %s, CGLEN = %d, WATCH = %s, IPL = %d", hex(sr_debug).c_str(), hex(sr_timer).c_str(), sr_cglen, hex(sr_watch).c_str(), sr_ipl); if (sr_ipl > 0 && sr_ipl < num_interrupts) printf(" = %s", interrupt_name[sr_ipl]); putchar('\n'); printf("SYS: SP = %s, FP = %s\n", hex(sr_syssp).c_str(), hex(sr_sysfp).c_str()); printf("USR: SP = %s, FP = %s\n", hex(_registers[SP]).c_str(), hex(_registers[FP]).c_str()); printf("\n"); } struct keybacks { static const int numlines = 32; string lines[numlines]; int newest, looking = -1; keybacks() { newest = 0; } void bringtofront(int ln) { string tomove = lines[ln]; int prev = newest - 1; if (prev < 0) prev += numlines; int next = ln + 1; while (ln != prev) { if (next == numlines) next = 0; lines[ln] = lines[next]; ln = next; next += 1; } lines[prev] = tomove; } void commit(string s) { looking = -1; if (s == "") return; for (int i = 0; i < numlines; i += 1) if (lines[i] == s) { bringtofront(i); return; } lines[newest] = s; newest += 1; if (newest == numlines) newest = 0; } void print() { int curr = newest; for (int i = 0; i < numlines; i += 1) { cout << curr << ": " << lines[curr]; if (curr == looking) cout << " <="; cout << "\n"; curr += 1; if (curr == numlines) curr = 0; } } string uparrow() { if (looking == -1) looking = newest - 1; else looking -= 1; if (looking < 0) looking = numlines - 1; return lines[looking]; } string downarrow() { if (looking == -1) return ""; looking += 1; if (looking == numlines) looking = 0; if (looking == newest) { looking = -1; return ""; } return lines[looking]; } }; keybacks backl; void computer::check_monitors() { int newv; bool said = false; for (int i = 0; i < monitors.size(); i += 1) { monitoritem * mi = monitors[i]; if (mi->type == 'r') { newv = registers(mi->addr); if (newv != mi->orig) { if (! said) { putchar('\n'); said = true; } printf("%s has changed from %s = %d to %s = %d\n", register_name[mi->addr], hex(mi->orig).c_str(), mi->orig, hex(newv).c_str(), newv); mi->orig = newv; } } else if (mi->type == 's') { newv = get_special_register(mi->addr); if (newv != mi->orig) { if (! said) { putchar('\n'); said = true; } printf("%s has changed from %s = %d to %s = %d\n", specregs[mi->addr] + 1, hex(mi->orig).c_str(), mi->orig, hex(newv).c_str(), newv); mi->orig = newv; } } else { newv = memory_read(mi->addr); if (newv != mi->orig) { if (! said) { putchar('\n'); said = true; } printf("%s has changed from %s = %d to %s = %d\n", hex(mi->addr).c_str(), hex(mi->orig).c_str(), mi->orig, hex(newv).c_str(), newv); mi->orig = newv; } } } if (said) putchar('\n'); } bool computer::debug_command(bool noisy) { if (toload.size() == 0) { printf("can't debug, no executables have been loaded\n\n"); return false; } if (hel.ready()) hel.clear(); for (int i = 0; i < toload.size(); i += 1) { loaditem * li = toload[i]; if (noisy) printf("Preparing definitions from %s, loaded at %s\n", li->fname.c_str(), hex(li->where).c_str()); bool ok = hel.readalldli(li->fname, li->where); if (! ok) { if (noisy) printf("failed\n\n"); hel.clear(); return false; } } hel.process(); if (noisy) printf("\n"); return true; } bool computer::checked_memory_read(int addr, int & value) { if (! memory_can_read(addr)) return false; value = memory_read(addr); return true; } void computer::obey_command(string init, nistringstream & cmd, bool normalend) { string nxt; bool isphysonly = false; if (same(init, "ph")) { isphysonly = true; cmd >> init; if (cmd.fail()) { printf("\nph needs to be immedialtely followed by another command\n\n"); return; } } int v0, nxtpos = cmd.tellg(); operand o0; bool wasoperand = false; char t = operand_or_value(init, o0, v0, isphysonly, false); if (t != 'X') { wasoperand = true; cmd.setseps("=:"); } else if (init == "?") cmd.setseps(":"); cmd >> nxt; if (same(init, "s") || same(init, "step")) { int num = 0; if (! cmd.fail()) { bool ok = string_to_int(nxt, num, 10); if (! ok) { printf("\n%s: Incomprehensible\n\n", nxt.c_str()); return; } else if (num > 0) countdown = num; stepping = true; } if (! stepping) { flr = true; stepping = true; return; } if (current_instruction.opcode == OP_BREAK) return; execute(); if (special_action) { if (watching_involved) { if (watching_involved == 1) { sr_watch = intrsaved_watch; special_action = 0; intrsaved_watch = 0; saved_watch = 0; watching_involved = 0; } else watching_involved = 1; } else if (saved_watch) { if (watch_cause == INT_WATCH) sr_watch = saved_watch; else if (watch_cause == INT_DEBUG) sr_debug = saved_watch; special_action = 0; intrsaved_watch = 0; watching_involved = 0; saved_watch = 0; } } check_monitors(); postdebinfo(); printf("\n"); return; } _registers[PC] = fetch_pc; if (same(init, "none")) return; else if (same(init, "mode")) { bool on; const char * ons; putchar('\n'); if (cmd.fail()) { printf("x: autoexit (exit emulator when program terminates) %s\n", autoexit ? "on" : "off"); printf("z: zeromode (print hexadecimal with 0 instead of o) %s\n", zeromode ? "on" : "off"); putchar('\n'); return; } cmd.seekg(nxtpos); while (true) { on = true; ons = "on"; cmd >> nxt; if (cmd.fail()) break; makelower(nxt); for (int i = 0; i < nxt.length(); i += 1) { char c = nxt[i]; if (c == '+') { on = true; ons = "on"; } else if (c == '-') { on = false; ons = "off"; } else if (c == 'z') { zeromode = on; printf("print hexadecimal with 0 instead of o: zeromode %s\n", ons); } else if (c == 'x') { autoexit = on; printf("exit emulator when program terminates: autoexit %s\n", ons); } else { printf("'%c' not understood as a mode\n\n", c); return; } } } putchar('\n'); } else if (same(init, "start")) { starting = 1; start_break = 0; if (bpts) start_break = bpt3; if (bpt3 != 0) printf("temporarily setting break-point 3 to %s\n", hex(bpt3).c_str()); bpt3 = init_pc + begin; bpts = 1; flr = true; runwild = true; stepping = false; aside_buffer_to_kbb(); sumexecount += execount; execount = 0; starttime = getcputime(); startrt = getrealtime(); return; } else if (same(init, "trace")) { int value = true, s = 0; makelower(nxt); if (cmd.fail()) { printf("\n"); if (traceints && tracecalls) printf("interrupts and function calls and returns are currently being traced\n"); else if (traceints) printf("interrupts are currently being traced\n"); else if (tracecalls) printf("function calls/returns are currently being traced\n"); else printf("nothing is currently being traced\n"); if (ignorecall1 != 0) { printf("calls to address %s are being ignored", hex(ignorecall1).c_str()); if (ignoreret1 != 0) printf(", as are returns to %s", hex(ignoreret1).c_str()); putchar('\n'); } if (ignorecall2 != 0) { printf("calls to address %s are being ignored", hex(ignorecall2).c_str()); if (ignoreret2 != 0) printf(", as are returns to %s", hex(ignoreret2).c_str()); putchar('\n'); } if (ignorecall3 != 0) { printf("calls to address %s are being ignored", hex(ignorecall3).c_str()); if (ignoreret3 != 0) printf(", as are returns to %s", hex(ignoreret3).c_str()); putchar('\n'); } if (ignorecall4 != 0) { printf("calls to address %s are being ignored", hex(ignorecall4).c_str()); if (ignoreret4 != 0) printf(", as are returns to %s", hex(ignoreret4).c_str()); putchar('\n'); } putchar('\n'); return; } if (nxt[0] == '+') nxt = nxt.substr(1); else if (nxt[0] == '-') { value = false; nxt = nxt.substr(1); } if (same(nxt, "ints")) { traceints = value; printf("\ninterrupts will now be traced\n\n"); } else if (same(nxt, "calls")) { tracecalls = value; printf("\ncalls and returns will now be traced\n\n"); } else if (same(nxt, "ignore")) { if (! value) { printf("-ignore doesn't mean anything\n"); return; } bool on = true; cmd >> nxt; if (nxt[0] == '-') { on = false; nxt = nxt.substr(1); } else if (nxt[0] == '+') nxt = nxt.substr(1); operand o; char t = operand_or_value(nxt, o, value, isphysonly, true); if (t == 'X') return; if (on) { if (ignorecall1 == 0) { ignorecall1 = value; ignoreret1 = 0; } else if (ignorecall2 == 0) { ignorecall2 = value; ignoreret2 = 0; } else if (ignorecall3 == 0) { ignorecall3 = value; ignoreret3 = 0; } else if (ignorecall4 == 0) { ignorecall4 = value; ignoreret4 = 0; } else { printf("\nonly four functions can be ignored at a time\n\n"); return; } printf("\nignoring calls ot %s\n\n", hex(value).c_str()); } else { if (ignorecall1 == value) { ignorecall1 = 0; ignoreret1 = 0; } else if (ignorecall2 == value) { ignorecall2 = 0; ignoreret2 = 0; } else if (ignorecall3 == value) { ignorecall3 = 0; ignoreret3 = 0; } else if (ignorecall4 == value) { ignorecall4 = 0; ignoreret4 = 0; } else { printf("\n%s is not currently being ignored\n\n", hex(value).c_str()); return; } printf("\nno longer ignoring calls to %s\n\n", hex(value).c_str()); } } else printf("\n%s after trace command, only ints, calls, and ignore are allowed\n\n", nxt.c_str()); return; } else if (same(init, "load")) { string item = nxt; int address; unsigned int uaddr; bool hadat = false; if (cmd.fail()) { printf("load filename [[at] address]\n"); return; } string name, ext; prepare_filename(item, name, ext); if (ext == "b") ext = ""; cmd >> item; if (cmd.fail()) hadat = false; if (same(item, "at")) { cmd >> item; if (cmd.fail()) { printf("no address after 'at'\n"); return; } } operand o; char t = operand_or_value(item, o, address, isphysonly, true); if (t == 'X') printf("\n%s: not a valid address\n\n", item.c_str()); hadat = true; cmd >> item; if (! cmd.fail()) { printf("\nload parameter confused '%s'\n\n", item.c_str()); return; } uaddr = address; loaditem * li; bool first = ! loaded_any; if (hadat) li = new loaditem(name, ext, address); else li = new loaditem(name, ext); string fn; int oflsys = flsys; flsys = 1; uaddr = loadfile(li, first_free, fn); if (uaddr >= ERR_LOWEST) { printf("\ncould not load file %s\n\n", fn.c_str()); flsys = oflsys; return; } if (hel.ready()) hel.clear(); toload.push_back(li); printf("\nloaded %s from %s to %s\n", fn.c_str(), hex(li->where).c_str(), hex(li->end).c_str()); if (uaddr > first_free) first_free = address; printf("free memory now starts at address %s\n\n", hex(first_free).c_str()); if (first) { _registers[PC] = init_pc; fetch_pc = init_pc; } flsys = oflsys; } else if (same(init, "echo")) { while (true) { for (int i = 0; i < nxt.length(); i += 1) { char c = nxt[i]; if (c >= ' ' && c <= '~') printf("%c", c); else printf("%s", visiblechar(c).c_str()); } cmd >> nxt; if (cmd.fail()) break; putchar(' '); } putchar('\n'); putchar('\n'); fflush(stdout); return; } else if (same(init, "keys")) { while (true) { if (! kbd_rdy && ! control_c) { uspleep(__LINE__, 100000); continue; } if (control_c) break; char ch = read_keyboard_char(); printf("[%d]", ch); fflush(stdout); } putchar('\n'); putchar('\n'); return; } else if (same(init, "break")) { if (cmd.fail()) { printf("\nnot enough information\n\n"); return; } int num = nxt[0] - '0', bpn; if (nxt.length() != 1 || num < 0 || num > 3) { printf("\nbad breakpoint number\n\n"); return; } cmd >> nxt; if (! cmd.fail()) { if (num == 0) { printf("\nthere is no breakpoint 0\n\n"); return; } if (same(nxt, "next")) bpn = _registers[PC] + 1; else { operand o; char t = operand_or_value(nxt, o, bpn, isphysonly, true); if (t == 'X') return; } } if (num == 0) { bpts = 0; bpt1 = 0; bpt2 = 0; bpt3 = 0; printf("\nall break-points cleared\n\n"); } else { if (num == 1) bpt1 = bpn; else if (num == 2) bpt2 = bpn; else if (num == 3) bpt3 = bpn; if (bpn == 0) printf("\nbreak-point %d cleared\n\n", num); else printf("\nbreak-point %d set to %s\n\n", num, hex(bpn).c_str()); } if (bpt1 == 0 && bpt2 == 0 && bpt3 == 0) bpts = 0; else bpts = 1; if (watch_cause == INT_DEBUG) { watch_cause = 0; special_action = 0; saved_watch = 0; intrsaved_watch = 0; } return; } else if (same(init, "monitor")) { putchar('\n'); if (cmd.fail()) { if (monitors.size() == 0) { printf("Nothing is currently being monitored\n\n"); return; } for (int i = 0; i < monitors.size(); i += 1) { monitoritem * mi = monitors[i]; if (mi->type == 'r') printf("%s is being monitored for changes from %s = %d\n", register_name[mi->addr], hex(mi->orig).c_str(), mi->orig); else if (mi->type == 's') printf("%s is being monitored for changes from %s = %d\n", specregs[mi->addr] + 1, hex(mi->orig).c_str(), mi->orig); else printf("%s is being monitored for changes from %s = %d\n", hex(mi->addr).c_str(), hex(mi->orig).c_str(), mi->orig); } putchar('\n'); return; } for ( ; ! cmd.fail(); cmd >> nxt) { int val = 0; makelower(nxt); monitoritem * mi = NULL; if (same(nxt, "none")) { monitors.clear(); printf("all monitors cancelled\n\n"); continue; } bool on = true; if (nxt[0] == '+') nxt = nxt.substr(1); if (nxt[0] == '-') { on = false; nxt = nxt.substr(1); } makeupper(nxt); for (int i = 0; i < 16; i += 1) { if (nxt == register_name[i]) { mi = new monitoritem('r', i, registers(i)); break; } } for (int i = 0; i < num_specregs; i += 1) { if (nxt == specregs[i] + 1) { mi = new monitoritem('s', i, get_special_register(i)); break; } } if (mi == NULL) { int cont; operand o; char t = operand_or_value(nxt, o, val, isphysonly, true); if (t == 'X') continue; interrupt_code = 0; cont = memory_read(val); if (interrupt_code != 0) { printf("memory address %s is not readable\n\n", hex(val).c_str()); continue; } mi = new monitoritem('m', val, cont); if (t == 'V') val = 0; } int foundat = -1; for (int i = 0; i < monitors.size(); i += 1) { if (monitors[i]->type == mi->type && monitors[i]->addr == mi->addr) { foundat = i; break; } } if (foundat == -1 && ! on) { printf("%s was not being monitored\n\n", nxt.c_str()); delete mi; } else if (! on) { delete monitors[foundat]; monitors.erase(monitors.begin() + foundat); printf("%s not being monitored any more\n\n", nxt.c_str()); delete mi; } else { printf("%s ", nxt.c_str()); if (val != 0) printf("%s ", hex(val).c_str()); if (foundat != -1) { monitors[foundat]->orig = mi->orig; printf("now "); delete mi; mi = monitors[foundat]; } else monitors.push_back(mi); printf("being monitored for changes from %s = %d\n", hex(mi->orig).c_str(), mi->orig); } } putchar('\n'); } else if (same(init, "setwa")) { int num; if (cmd.fail()) { if (sr_watch == 0) printf("\nno watch-point is set\n\n"); else printf("\nthe watch-point is %s\n\n", hex(sr_watch).c_str()); return; } operand o; char t = operand_or_value(nxt, o, num, isphysonly, true); if (t == 'X') return; sr_watch = num; if (num == 0) printf("\nwatch-point cleared\n\n"); else printf("\nwatch-point set to %s\n\n", hex(num).c_str()); if (watch_cause == INT_WATCH) { saved_watch = 0; intrsaved_watch = 0; watch_cause = 0; special_action = 0; } return; } else if (same(init, "count")) { printf("\n%llu instructions, %llu since last start or run\n", sumexecount + execount, execount); double t = getcputime() - starttime; printf("%.3f real CPU seconds", t); if (execount > 0 && t > 0.0) printf(": %.0f instructions per CPU second", execount / t); printf("\n"); t = getrealtime() - startrt; printf("%.3f elapsed seconds", t); if (execount > 0 && t > 0.0) printf(": %.0f instructions per real-time second", execount / t); printf("\n\n"); return; } else if (same(init, "r") || same(init, "run") || same(init, "over")) { int isover = same(init, "over"); if (! cmd.fail()) { int num; bool ok = ! isover; if (ok) ok = string_to_int(nxt, num, 10); if (! ok) { printf("\n%s: incomprehensible\n\n", nxt.c_str()); return; } else countdown = num; } flr = true; runwild = true; stepping = false; aside_buffer_to_kbb(); if (current_instruction.opcode == OP_BREAK) _registers[PC] += 1; sumexecount += execount; execount = 0; starttime = getcputime(); startrt = getrealtime(); if (isover) { savebpt3 = bpt3; savedbpt3 = true; bpt3 = registers(15) + 1; bpts = 1; printf("\nbreak-point 3 temporarily set to %s\n\n", hex(bpt3).c_str()); } return; } else if (same(init, "trail")) { int oflsys = flsys; flsys = 1; printf("\ntrace of last 16 PC values:\n"); for (int i = -15; i <= 0; i += 1) { unsigned int pcv = pctrail[(trailcount + i) & 15]; interrupt_code = 0; decoded_instruction ins(memory_read(pcv)); if (interrupt_code != 0) printf(" %s: unreadable", hex(pcv).c_str()); else printf(" %s: %s", hex(pcv).c_str(), ins.printable().c_str()); for (int j = 0; j < 16; j += 1) if (intrtrail[j] == trailcount + i) { int ic = intrnum[j]; if (ic < 0 || ic >= num_interrupts) printf(" - interrupted by MYSTERY INTERRUPT %d", ic); else printf(" - interrupted by %s: %s", interrupt_words(ic).c_str(), interrupt_desc(ic)); break; } printf("\n"); fflush(stdout); } putchar('\n'); interrupt_code = 0; flsys = oflsys; return; } else if (same(init, "int")) { int code; bool ok = ! cmd.fail() && string_to_int(nxt, code, 10); if (! ok) { makeupper(nxt); for (int i = 1; i < num_interrupts; i += 1) if (nxt == interrupt_name[i] + 4) { code = i; ok = true; break; } } if (! ok || code <= 0 || code >= num_interrupts) printf("\n%s: no such interrupt\n\n", nxt.c_str()); else { printf("\nsignalling interrupt code %d: %s: %s\n\n", code, interrupt_name[code], interrupt_desc(code)); prepare_interrupt(__LINE__, code); } return; } else if (same(init, "input")) { while (true) { for (int i = 0; i < nxt.length(); i += 1) aside_buffer_add(nxt[i]); cmd >> nxt; if (cmd.fail()) break; aside_buffer_add(' '); } if (normalend) aside_buffer_add('\n'); printf("\ninput buffer contains \"%s\"\n\n", aside_buffer_see_all().c_str()); return; } else if (same(init, "disc")) { int dn = 0; bool ok = ! cmd.fail() && string_to_int(nxt, dn, 10); if (! ok || dn <= 0 || dn > max_devices || ddiscs[dn].filenum < 0) printf("\ndisc unit %d not present\n\n", dn); else { dview.setdisc(dn, ddiscs[dn].filenum); printf("\ndisc %d ready for examination\n\n", dn); } return; } else if (same(init, "block")) { string pn; cmd >> pn; if (cmd.fail()) { printf("\nsay \"block \"\n\n"); return; } int blockn; bool ok = string_to_int(nxt, blockn, 10); if (blockn < 0) ok = false; if (ok) ok = dview.setblock(blockn, ddiscs[1].filenum); if (! ok) { printf("\n%s: not a valid block number for this disc\n\n", nxt.c_str()); return; } ok = dview.setpattern(pn); if (! ok) return; dview.show(); return; } else if (same(init, "show")) { int oflsys = flsys; flsys = 1; cmd.seekg(nxtpos); cmd.setseps(":"); debugshow(cmd, isphysonly, 'S'); flsys = oflsys; } else if (init[0] == '?') { int oflsys = flsys; flsys = 1; cmd.clear(); cmd.seekg(nxtpos); debugshow(cmd, isphysonly, 'S'); flsys = oflsys; } else if (same(init, "set")) { int oflsys = flsys; flsys = 1; cmd.seekg(nxtpos); cmd.setseps("="); debugset(cmd, isphysonly); flsys = oflsys; } else if (same(init, "decode")) { int oflsys = flsys; flsys = 1; cmd.seekg(nxtpos); cmd.setseps(":"); debugshow(cmd, isphysonly, 'D'); flsys = oflsys; } else if (same(init, "frame")) { int oflsys = flsys; flsys = 1; string s; int fnum = 0; putchar('\n'); cmd.seekg(nxtpos); cmd >> s; if (! cmd.fail()) { bool ok = string_to_int(s, fnum, 10); if (! ok) { printf("%s is not a valid number\n\n", s.c_str()); flsys = oflsys; return; } } if (fnum < 0) { printf("frame numbers can not be negative\n\n"); flsys = oflsys; return; } bool ok = true; int fp = registers(FP), sp = registers(SP), i; if (sp > fp) { printf("current stack frame has been corrupted, SP = %s > FP = %s\n\n", hex(sp).c_str(), hex(fp).c_str()); flsys = oflsys; return; } for (i = 0; i < fnum; i += 1) { int prevfp, prevsp, na2, x; if (fp == 0) { ok = false; break; } if (! checked_memory_read(fp, prevfp)) { ok = false; break; } if (! checked_memory_read(fp + 2, na2)) { ok = false; break; } prevsp = fp + na2 / 2 + 3; if (! checked_memory_read(prevsp - 1, x)) { ok = false; break; } fp = prevfp; sp = prevsp; if (sp > fp) { printf("stack frame %+d has been corrupted, SP = %s > FP = %s\n\n", hex(sp).c_str(), hex(fp).c_str()); flsys = oflsys; return; } } if (fp == 0 || ! ok) { printf("stack frame %d does not exist\n\n", fnum); flsys = oflsys; return; } int narg = memory_read(fp + 2) >> 1; unsigned int a1 = fp + narg + 2; unsigned int a2 = sp; if (a1 - a2 > 498) { printf("the stack frame consists of %d words, that's too many\n", a1 - a2 + 1); printf("use the show command with a specific range, such as show fp+20 to fp-25\n\n"); flsys = oflsys; return; } for (unsigned int a = a1; a >= a2; a -= 1) { int v = memory_read(a); if (a == fp) printf(" FP "); else if (a == sp) printf(" SP "); else printf(" "); printf("%s: %s = %-14d", hex(a).c_str(), hex(v).c_str(), v); if (a == fp) printf("saved FP\n"); else if (a == fp + 1) printf("saved PC\n"); else if (a == fp + 2) printf("numbargs = %d, lhs = %d\n", v / 2, v & 1); else if (a == fp + 3) printf("parameter 1\n"); else if (a == a1) printf("parameter %d\n", narg); else if (a == fp - 1) printf("local 1\n"); else if (a == a2) printf("local %d\n", fp - a2); else putchar('\n'); } putchar('\n'); flsys = oflsys; return; } else if (same(init, "hex")) { int oflsys = flsys; flsys = 1; debinfo(16); nodebinfo = true; flsys = oflsys; } else if (same(init, "dec")) { int oflsys = flsys; flsys = 1; debinfo(10); nodebinfo = true; flsys = oflsys; } else if (same(init, "vm")) { int addr; operand o; if (cmd.fail()) { printf("\nvm command requires a valid address\n\n"); return; } int oflsys = flsys; flsys = 1; char t = operand_or_value(nxt, o, addr, isphysonly, true); if (t == 'X') { flsys = oflsys; return; } vm_show(addr); putchar('\n'); flsys = oflsys; return; } else if (same(init, "showint")) { if (! flint) printf("\ninterrupt processing is not enabled\n"); printf("\ninterrupt vector physical address %s\n", hex(sr_intvec).c_str()); if (sr_intvec == 0) { printf(" zero: interrupt vector not set\n\n"); return; } int oflsys = flsys; flsys = 1; if (flint && sr_ipl == 0) printf("No interrupt is currently being processed\n"); else if (sr_ipl != 0) { printf("interrupt %s is currently being processed: %s\n", interrupt_words(interrupt_being_processed).c_str(), interrupt_desc(interrupt_being_processed)); int theic = memory_read(intsp + 3); int thead = memory_read(intsp + 4); int thedt = memory_read(intsp + 5); int thepc = memory_read(intsp); printf(" code %d, address %s, detail %s = %d, saved PC = %s\n\n", theic, hex(thead).c_str(), hex(thedt).c_str(), thedt, hex(thepc).c_str()); } if (! (physical_memory_exists(sr_intvec) && physical_memory_exists(sr_intvec + num_interrupts - 1))) { printf(" Vector not all contained within existing physical memory\n\n"); flsys = oflsys; return; } for (int i = 0; i < num_interrupts; i += 1) { printf(" %2d, ", i); const char * s = interrupt_name[i]; int dest = physical_memory_read(sr_intvec+i); if (dest == 0) printf("0 - not set "); else { interrupt_code = 0; memory_read(dest); printf("%s ", hex(dest).c_str()); if (interrupt_code != 0) printf("(not Readable)"); } printf(" (%s)\n", s+1); } bool any = false; for (int i = 1; i < interrupt_being_processed; i += 1) if (intframe[i] != 0) { if (! any) printf("\nthe following interrupts were interrupted by a higher priority one:\n"); any = true; printf(" %s, at SYSSP = %s: %s\n", interrupt_words(i).c_str(), hex(intframe[i]).c_str(), interrupt_desc(i)); } if (any) printf(" %s, currently being processed, at SYSSP = %s: %s\n", interrupt_words(interrupt_being_processed).c_str(), hex(intframe[interrupt_being_processed]).c_str(), interrupt_desc(interrupt_being_processed)); flsys = oflsys; interrupt_code = 0; putchar('\n'); flsys = oflsys; return; } else if (same(init, "intstate")) { int oflsys = flsys; flsys = 1; putchar('\n'); int nin = intevents.scan(); if (nin > 0) { unsigned int opc, osp0, osp1; int sig0; char k0; printf("Last %d interrupt-related events, most recent shown last\n", nin); while (true) { bool ok = intevents.next(k0, osp0, osp1, opc, sig0); if (! ok) break; printf("At PC %s, SSP was %s became %s, code %3d: ", hex(opc).c_str(), hex(osp0).c_str(), hex(osp1).c_str(), sig0); if (k0 == 'I') printf("Interrupt signalled"); else if (k0 == 'S') printf("SYSCALL executed "); else if (k0 == 'R') printf("IRET executed "); else if (k0 == 'X') printf("interrupt ignored "); else if (k0 == 'E') printf("interrupt emergency"); else if (k0 == 'Q') printf("IRET failed "); else if (k0 == 'F') printf("SYSCALL failed "); else if (k0 == 'T') printf("interrupt failed "); else printf("(bad code %c) ", k0); if (k0 == 'I' || k0 == 'X' || k0 == 'T') if (sig0 > 0 && sig0 < num_interrupts) printf(" int: %s", interrupt_name[sig0] + 4); else printf(" (incorrect interrupt code)"); printf("\n"); } printf("\n"); } if (flint == 0) printf("the INT flag is 0. If interrupts are not being processed this will be useless\n"); if (sr_ipl == 0) printf("IPL is 0. If an interrupt is not being processed this will be useless\n"); if (intsp == 0) { printf("definitely not in interrupt processing, no state to display\n\n"); flsys = oflsys; return; } interrupt_code = 0; memory_read(intsp); memory_read(intsp + 20); if (interrupt_code != 0) { printf("stack frame (from %s to %s) is unreadable\n\n", hex(intsp).c_str(), hex(intsp + 20).c_str()); flsys = oflsys; return; } int ic = memory_read(intsp + 3); printf(" %s: saved R0 = %s = %d\n", hex(intsp + 20).c_str(), hex(memory_read(intsp + 20)).c_str(), memory_read(intsp + 20)); printf(" %s: saved R1 = %s = %d\n", hex(intsp + 19).c_str(), hex(memory_read(intsp + 19)).c_str(), memory_read(intsp + 19)); printf(" %s: saved R2 = %s = %d\n", hex(intsp + 18).c_str(), hex(memory_read(intsp + 18)).c_str(), memory_read(intsp + 18)); printf(" %s: saved R3 = %s = %d\n", hex(intsp + 17).c_str(), hex(memory_read(intsp + 17)).c_str(), memory_read(intsp + 17)); printf(" %s: saved R4 = %s = %d\n", hex(intsp + 16).c_str(), hex(memory_read(intsp + 16)).c_str(), memory_read(intsp + 16)); printf(" %s: saved R5 = %s = %d\n", hex(intsp + 15).c_str(), hex(memory_read(intsp + 15)).c_str(), memory_read(intsp + 15)); printf(" %s: saved R6 = %s = %d\n", hex(intsp + 14).c_str(), hex(memory_read(intsp + 14)).c_str(), memory_read(intsp + 14)); printf(" %s: saved R7 = %s = %d\n", hex(intsp + 13).c_str(), hex(memory_read(intsp + 13)).c_str(), memory_read(intsp + 13)); printf(" %s: saved R8 = %s = %d\n", hex(intsp + 12).c_str(), hex(memory_read(intsp + 12)).c_str(), memory_read(intsp + 12)); printf(" %s: saved R9 = %s = %d\n", hex(intsp + 11).c_str(), hex(memory_read(intsp + 11)).c_str(), memory_read(intsp + 11)); printf(" %s: saved R10 = %s = %d\n", hex(intsp + 10).c_str(), hex(memory_read(intsp + 10)).c_str(), memory_read(intsp + 10)); printf(" %s: saved R11 = %s = %d\n", hex(intsp + 9).c_str(), hex(memory_read(intsp + 9)).c_str(), memory_read(intsp + 9)); printf(" %s: saved R12 = %s = %d\n", hex(intsp + 8).c_str(), hex(memory_read(intsp + 8)).c_str(), memory_read(intsp + 8)); printf(" %s: saved SP = %s = %d\n", hex(intsp + 7).c_str(), hex(memory_read(intsp + 7)).c_str(), memory_read(intsp + 7)); printf(" %s: saved FP = %s = %d\n", hex(intsp + 6).c_str(), hex(memory_read(intsp + 6)).c_str(), memory_read(intsp + 6)); printf(" %s: int detail = %s = %d\n", hex(intsp + 5).c_str(), hex(memory_read(intsp + 5)).c_str(), memory_read(intsp + 5)); printf(" %s: int addr = %s = %d\n", hex(intsp + 4).c_str(), hex(memory_read(intsp + 4)).c_str(), memory_read(intsp + 4)); if (ic >= 0 && ic < num_interrupts) printf(" %s: int code = %d = %s: %s\n", hex(intsp + 3).c_str(), ic, interrupt_name[ic], interrupt_description[ic]); else printf(" %s: int code = %d: invalid interrupt code\n", hex(intsp + 3).c_str(), ic); int f = memory_read(intsp + 2); printf(" %s: saved flags = %s =", hex(intsp + 2).c_str(), hex(f).c_str()); if (f & FLAGMASK_R) printf(" R"); else printf(" ~R"); if (f & FLAGMASK_Z) printf(" Z"); else printf(" ~Z"); if (f & FLAGMASK_N) printf(" N"); else printf(" ~N"); if (f & FLAGMASK_SYS) printf(" SYS"); else printf(" ~SYS"); if (f & FLAGMASK_EM) printf(" EM"); else printf(" ~EM"); if (f & FLAGMASK_VM) printf(" VM"); else printf(" ~VM"); if (f & FLAGMASK_INT) printf(" INT"); else printf(" ~INT"); printf(", IPL was %d\n", f & 0x1F); printf(" %s: %s = %d: should be 38\n", hex(intsp + 1).c_str(), hex(memory_read(intsp + 1)).c_str(), memory_read(intsp + 1)); printf(" %s: saved PC = %s = %d\n", hex(intsp).c_str(), hex(memory_read(intsp)).c_str(), memory_read(intsp)); printf("\n"); flsys = oflsys; return; } else if (same(init, "bt")) { int num = 25, fp, na2, oldsp; bool ok; if (! cmd.fail()) { ok = string_to_int(nxt, num, 10); if (! ok) { printf("\n%s: invalid number\n\n", nxt.c_str()); return; } } int oflsys = flsys; flsys = 1; fp = registers(FP); if (! checked_memory_read(fp + 2, na2)) { printf("memory at %s [FP + 2] is not readable, the stack seems to be corrupted\n", hex(fp + 2).c_str()); flsys = oflsys; return; } oldsp = fp + na2 / 2 + 3; printf("\nLast %d saved PC, FP, and SP values, current first:\n", num); printf(" 0: PC = %s, FP = %s, SP = %s\n", hex(registers(PC)).c_str(), hex(fp).c_str(), hex(registers(SP)).c_str()); for (int i = 1; i < num; i += 1) { int oldpc, newfp, na2, x; if (fp == 0) break; if (! checked_memory_read(fp, newfp)) { printf("memory at %s [FP] is not readable, the stack seems to be corrupted\n", hex(fp).c_str()); break; } if (newfp == 0) break; if (! checked_memory_read(fp + 1, oldpc)) { printf("memory at %s [FP+1] is not readable, the stack seems to be corrupted\n", hex(fp + 1).c_str()); break; } if (! checked_memory_read(newfp + 2, na2)) { printf("memory at %s [FP+2] is not readable, the stack seems to be corrupted\n", hex(fp + 2).c_str()); break; } printf("%6d: PC = %s, FP = %s, SP = %s\n", i, hex(oldpc).c_str(), hex(newfp).c_str(), hex(oldsp).c_str()); fp = newfp; oldsp = fp + na2 / 2 + 3; } putchar('\n'); flsys = oflsys; return; } else if (same(init, "showcg")) { putchar('\n'); if (sr_cgbr == 0) { printf(" zero: call gate vector not set\n\n"); return; } if (! (physical_memory_exists(sr_cgbr) && physical_memory_exists(sr_cgbr + sr_cglen - 1))) { printf(" vector not all contained within existing physical memory\n\n"); return; } printf("call gate vector physical address %s, length %d, zeros not shown:\n", hex(sr_cgbr).c_str(), sr_cglen); int oflsys = flsys; flsys = 1; for (int i = 0; i < sr_cglen; i += 1) { int dest = physical_memory_read(sr_cgbr + i); if (dest == 0) continue; interrupt_code = 0; memory_read(dest); if (interrupt_code != 0) printf(" %3d: %s - not readable\n", i, hex(dest).c_str()); else printf(" %3d: %s\n", i, hex(dest).c_str()); } flsys = oflsys; interrupt_code = 0; printf("\n"); return; } else if (same(init, "showvm")) { putchar('\n'); if (sr_pdbr == 0) { printf("PDBR is zero, no page directory\n\n"); return; } set shown; printf("page directory in pp %d physical address %s", sr_pdbr >> 11, hex(sr_pdbr).c_str()); if ((sr_pdbr & 1023) != 0) { printf(", INVALID\n\n"); return; } shown.insert(sr_pdbr); printf(", VM is %s\n", flvm ? "ON" : "OFF"); int oflsys = flsys, pd = sr_pdbr; flsys = 1; for (int pdi = 1023; pdi >= 0; pdi -= 1) { int pde = physical_memory_read(pd + pdi); if (pde == 0) continue; printf(" %-4d: ", pdi); if ((pde & PAGE_VALID) == 0) { printf("%s, not valid\n", hex(pde).c_str()); continue; } int pta = pde >> 11 << 11, pba = pdi << 22; printf("for VAs %s to %s, %s, pp %d at %s", hex(pba).c_str(), hex(pba + (1 << 22) - 1).c_str(), (pde & PAGE_SYSTEM) ? "SYS" : "usr", pta >> 11, hex(pta, 8).c_str()); if (shown.find(pta) != shown.end()) { printf(" - already shown\n"); continue; } printf("\n"); shown.insert(pta); for (int pti = 2047; pti >= 0; pti -= 1) { int pte = physical_memory_read(pta + pti); if (pte == 0) continue; printf(" %-4d: ", pti); if ((pte & PAGE_VALID) == 0) { printf("%s, not valid\n", hex(pte).c_str()); continue; } int pa = pte >> 11 << 11, pbb = pba + (pti << 11); printf("for VAs %s to %s, %s, pp %d at %s", hex(pbb).c_str(), hex(pbb + (1 << 11) - 1).c_str(), (pte & PAGE_SYSTEM) ? "SYS" : "usr", pa >> 11, hex(pa).c_str()); if (shown.find(pa) != shown.end()) printf(" - already shown"); printf("\n"); } } printf("\n"); flsys = oflsys; return; } else if (init[0] == '=') { int v, oflsys = flsys; flsys = 1; cmd.seekg(nxtpos); bool ok = calculate(cmd, v, isphysonly); if (ok) printf("\nthe result is %s = %d\n\n", hex(v).c_str(), v); flsys = oflsys; return; } else if (same(init, "float")) { if (cmd.fail()) { debinfo(99); nodebinfo = true; return; } int v; string_to_int(nxt, v, 16); float f = decode_float(v); printf("\n%d decodes to %e\n\n", v, f); return; } else if (same(init, "fix")) { float f = stof(nxt); int v = encode_float(f); printf("\n%e decodes to %s = %d\n\n", f, hex(v).c_str(), v); return; } else if (same(init, "what")) { putchar('\n'); int n = 0; makeupper(nxt); for (int i = 0; i < 16; i += 1) if (nxt == register_name[i]) { printf("register %d\n", i); n += 1; } for (int i = 0; i < num_specregs; i += 1) if (nxt == specregs[i] + 1) { printf("special register %d\n", i); n += 1; } for (int i = 0; i < num_condcodes; i += 1) if (nxt == condcodes[i]) { printf("condition code %d\n", i); n += 1; } for (int i = 0; i < num_iocommands; i += 1) if (nxt == iocommands[i] + 1) { printf("i/o command %d\n", i); n += 1; } for (int i = 5; i < num_flags; i += 1) if (nxt == flags[i] + 1) { printf("flag %d\n", i); n += 1; } for (int i = 0; i < num_interrupts; i += 1) if (nxt == interrupt_name[i] + 4) { printf("interrupt %d\n", i); n += 1; } for (int i = 0; i < num_opcodes; i += 1) if (nxt == instruction_name[i]) { printf("instruction number %d, or %s\n", i, hex(i << 25).c_str()); n += 1; } for (int i = 0; i < num_errors; i += 1) if (nxt == errors[i] + 4) { printf("error code %d\n", i); n += 1; } if (n == 0) printf("%s: unknown\n", nxt.c_str()); printf("\n"); } else if (same(init, "pause")) { stepping = false; return; } else if (same(init, "all")) { int oflsys = flsys; flsys = 1; debprintall(); flsys = oflsys; return; } else if (same(init, "loaded")) { putchar('\n'); if (cmd.fail()) { for (int i = 0; i < toload.size(); i += 1) printf("loaded %s from %s to %s\n", toload[i]->fname.c_str(), hex(toload[i]->where).c_str(), toload[i]->end == 0 ? "(unknown)" : hex(toload[i]->end).c_str()); printf("free memory starts at address %s\n", hex(first_free).c_str()); } else { string fname = nxt, addrs; int addr, end = 0; if (fname[0] == '-') { fname = fname.substr(1); for (int i = 0; i < toload.size(); i += 1) { string bsn, ext; string f = toload[i]->fname; prepare_filename(f, bsn, ext); if (f == fname || bsn == fname) { delete toload[i]; toload.erase(toload.begin() + i); if (hel.ready()) hel.clear(); return; } } printf("%s is not in the list of loaded files\n", fname.c_str()); return; } operand o; char t; cmd >> addrs; if (cmd.fail()) { printf("\naddress needed\n\n"); t = 'X'; addrs = "\\n"; return; } t = operand_or_value(addrs, o, addr, isphysonly, true); if (t == 'X') return; cmd >> addrs; if (cmd.fail()) { printf("\nan address range is needed\n\n"); return; } if (same(addrs, "TO")) cmd >> addrs; if (cmd.fail()) { printf("\naddress needed\n"); t = 'X'; addrs = "\\n"; return; } t = operand_or_value(addrs, o, end, isphysonly, true); if (t == 'X') return; loaditem * li = new loaditem(fname, "", addr); toload.push_back(li); if (hel.ready()) hel.clear(); bool isdll = false; if (fname.length() > 4 && fname.substr(fname.length() - 4) == ".dll") isdll = true; if (end >= first_free) first_free = end + 1; if (! loaded_any) { if (init_pc == -1) { init_pc = addr; fetch_pc = addr; } if (isdll) { int num = memory_read(addr) & 0xFFFF; begin += num + 1; } } loaded_any = true; printf("free memory now starts at address %s\n", hex(first_free).c_str()); } putchar('\n'); } else if (same(init, "sh")) { const char * s = getenv("SHELL"); if (s == NULL) s = "/bin/tcsh"; printf("\nJust type exit when you're done.\n"); fflush(stdout); normal_keyboard(); int p = fork(), st; if (p == 0) { execlp(s, s, NULL); printf("Could not start shell '%s'\n", s); exit(1); } p = wait(& st); interrupt_driven_keyboard(& kbd_rdy); putchar('\n'); } else if (same(init, "debug")) debug_command(); else if (same(init, "find")) { int addr; bool ok; if (cmd.fail()) { printf("\nfind what?\n\n"); return; } if (! hel.ready()) { ok = debug_command(); if (! ok) return; } if (nxt[0] == '?') nxt = nxt.substr(1); if (nxt[0] == ':') { if (nxt[1] == '?') hel.lookup_symbol_and_display(nxt.substr(2)); else hel.lookup_symbol_and_display(nxt.substr(1)); return; } operand o; char t = operand_or_value(nxt, o, addr, isphysonly, false); if (t == 'X') hel.lookup_symbol_and_display(nxt); else hel.find_address_and_display(addr); putchar('\n'); } else if (same(init, "findfile")) { int addr; bool ok; if (cmd.fail()) { printf("\nfind which file?\n\n"); return; } if (! hel.ready()) { ok = debug_command(); if (! ok) return; } if ((nxt[0] == 'f' || nxt[0] == 'F') && nxt[1] == '?') nxt = nxt.substr(2); hel.find_file_and_display(nxt); putchar('\n'); } else if (same(init, "x")) { if (stepping) { stepping = false; return; } else exit(0); } else if (same(init, "q") || same(init, "exit") || same(init, "quit")) exit(0); else if (wasoperand) { bool failed = cmd.fail(); cmd.clear(); cmd.seekg(0); if (failed) { debugshow(cmd, isphysonly, 'S'); return; } if (nxt == "=") { cmd.setseps("="); debugset(cmd, isphysonly); } else if (same(nxt, "TO") || same(nxt, "FOR") || nxt == ":" || nxt == "-") { cmd.setseps(":"); debugshow(cmd, isphysonly, 'S'); } else { int v; bool ok = calculate(cmd, v, isphysonly); if (ok) printf("\nthe result is %s = %d\n\n", hex(v).c_str(), v); } } else { printf("\nunrecognised command '%s'\n\n", init.c_str()); fflush(stdout); return; } } void computer::load_required_files() { int oflsys = flsys; flsys = 1; unsigned int addr = loadplace; for (int i = 0; i < toload.size(); i += 1) { string fn; unsigned int x = loadfile(toload[i], addr, fn); if (x >= ERR_LOWEST) { fprintf(stderr, "Could not load file %s\n", fn.c_str()); exit(1); } if (! quiet) printf("Loaded file %s from %s to %s\n", fn.c_str(), hex(addr).c_str(), hex(x - 1).c_str()); addr = x; } first_free = addr; if (! quiet) printf("free memory starts at address %s\n", hex(first_free).c_str()); if (init_pc != -1) _registers[PC] = init_pc; fetch_pc = _registers[PC]; flsys = oflsys; } void computer::process_dash_c_command_line(string givecmdline) { int begin = 0x150, theword = 0, wordpos = 0, itempos = 0x110, chars = 0, wordmax = givecmdline.length(); int pos = begin; for (int i = 0; i < wordmax; i += 1) { unsigned char ch = givecmdline[i]; if (ch == '\\' && i < wordmax - 1) { i += 1; ch = givecmdline[i]; if (ch == ' ') ch = 128; else if (ch == 'n') ch = '\n'; else if (ch == 't') ch = '\t'; else if (ch == '\\') ch = '\\'; else if (ch == '\'') ch = '\''; else if (ch == '\"') ch = '\"'; } if (ch == ' ') { if (chars == 0) continue; physical_memory_write(pos, theword); wordpos = 0; theword = 0; physical_memory_write(itempos, begin); itempos += 1; pos += 1; begin = pos; chars = 0; if (itempos >= 0x14D) { fprintf(stderr, "Too many items in the command line\n"); exit(1); } continue; } if (ch == 128) ch = ' '; theword |= ch << wordpos; wordpos += 8; chars += 1; if (wordpos == 32) { physical_memory_write(pos, theword); wordpos = 0; theword = 0; pos += 1; } if (pos >= 0x3FD) { fprintf(stderr, "Command line too long\n"); exit(1); } } if (chars > 0) { physical_memory_write(pos, theword); pos += 1; physical_memory_write(itempos, begin); itempos += 1; } physical_memory_write(pos, 0); physical_memory_write(itempos, 0); } bool computer::get_users_command(char * command, int & linelen, bool & normalend) { int escstate = 0, posonline = 0, lineextra = 2; const char * prompt = "> "; if (stepping) { prompt = "stepping> "; lineextra = 10; } printf("%s", prompt); fflush(stdout); linelen = 0; while (1) { if (! kbd_rdy && ! control_c) { uspleep(__LINE__, 100000); continue; } if (control_c) { kbb_to_aside_buffer(); clear_keyboard_buffer(); printf("[control-c]\n"); fflush(stdout); consecctrlc += 1; if (consecctrlc >= 2) exit(1); control_c = false; if (stepping) { strcpy(command, "x"); linelen = 1; break; } else { strcpy(command, "control-c"); linelen = 9; break; } } char ch = read_keyboard_char(); printf("\033[C\033[D"); fflush(stdout); if (escstate == 0) { if (ch == 27) { escstate = 1; continue; } } else if (escstate == 1) { if (ch == 91) { escstate = 2; continue; } else if (ch == 27) { escstate = 0; normalend = false; putchar('\n'); ch = 27; break; } else escstate = 0; } else if (escstate == 2) { if (ch == 65) { string s = backl.uparrow(); strcpy(command, s.c_str()); linelen = s.length(); printf("\033[2K\033[%dD%s%s", posonline + lineextra, prompt, command); fflush(stdout); posonline = linelen; escstate = 0; continue; } else if (ch == 66) { string s = backl.downarrow(); strcpy(command, s.c_str()); linelen = s.length(); printf("\033[2K\033[%dD%s%s", posonline + lineextra, prompt, command); fflush(stdout); posonline = linelen; escstate = 0; continue; } else if (ch == 67) { if (posonline < linelen) { printf("\033[C"); fflush(stdout); posonline += 1; } escstate = 0; continue; } else if (ch == 68) { if (posonline > 0) { printf("\033[D"); fflush(stdout); posonline -= 1; } escstate = 0; continue; } else if (ch == 27) { escstate = 1; continue; } else escstate = 0; } if (ch == '\b' || ch == 127) { if (posonline > 0) { for (int i = posonline; i < linelen; i += 1) command[i - 1] = command[i]; linelen -= 1; posonline -= 1; command[linelen] = 0; if (linelen == posonline) printf("\033[2K\033[%dD%s%s", posonline + lineextra + 1, prompt, command); else printf("\033[2K\033[%dD%s%s\033[%dD", posonline + lineextra + 1, prompt, command, linelen - posonline); } fflush(stdout); continue; } else if (ch == 'D' - 64) { if (posonline < linelen) { for (int i = posonline; i < linelen; i += 1) command[i] = command[i + 1]; linelen -= 1; if (linelen == posonline) printf("\033[2K\033[%dD%s%s", posonline + lineextra, prompt, command); else printf("\033[2K\033[%dD%s%s\033[%dD", posonline + lineextra, prompt, command, linelen - posonline); } fflush(stdout); continue; } else if (ch == 'E' - 64) { if (posonline < linelen) { printf("\033[%dC", linelen - posonline); fflush(stdout); posonline = linelen; } continue; } else if (ch == 'A' - 64) { if (posonline > 0) { printf("\033[%dD", posonline); fflush(stdout); posonline = 0; } continue; } else if (ch == 'X' - 64) { linelen = 0; printf("\033[2K\033[%dD%s", posonline + lineextra, prompt); posonline = 0; fflush(stdout); continue; } else if (ch >= 128) { } else if (ch == '\n') { printf("\033[%dC\n", linelen - posonline); posonline = linelen; command[linelen] = 0; fflush(stdout); if (linelen > 0) backl.commit(command); break; } else if (ch >= ' ') { if (linelen < 997) { for (int i = linelen; i > posonline; i -= 1) command[i] = command[i - 1]; command[posonline] = ch; posonline += 1; linelen += 1; command[linelen] = 0; if (linelen == posonline) printf("\033[2K\033[%dD%s%s", posonline + lineextra, prompt, command); else printf("\033[2K\033[%dD%s%s\033[%dD", posonline + lineextra, prompt, command, linelen - posonline); fflush(stdout); } } else { } } while (linelen > 0 && command[linelen-1] <= ' ') linelen -= 1; command[linelen] = 0; if (linelen == 0 && normalend) { if (stepping) putchar('\n'); strcpy(command, "step"); linelen = 4; } if (strcmp(command, "control-c") == 0) { stepping = false; return false; } else consecctrlc = 0; return true; } bool computer::fetch_for_step() { int oflsys = flsys; flsys = 1; if (brokeninterrupt) { printf("****debinfo for brokeninterrupt\n"); if (! nodebinfo) debinfo(0); brokeninterrupt = false; } else if (interrupt_code != 0 && ! tryingtostop) { bool ok = prepare_interrupt(__LINE__, interrupt_code); if (ok) { flsys = oflsys; return false; } } fetch(); if (interrupt_code != 0 && ! tryingtostop) { bool ok = prepare_interrupt(__LINE__, interrupt_code); if (ok) { flsys = oflsys; return false; } } breaking = false; if (! nodebinfo) debinfo(0); nodebinfo = false; putchar('\n'); flsys = oflsys; return true; } int main(int argc, char * argv[]) { computer c; bool fileoncmdline = false; bool autorun = false, script = false; ifstream scriptf; string filename = "", fileext = "", givecmdline = ""; // section process unix command line for (int i = 1; i < argc; i += 1) { char * arg = argv[i]; if (arg[0] == '-') { if (arg[1] == 'i' && arg[2] == 0 && i + 1 < argc) { i += 1; keyboardfile = fopen(argv[i], "r"); if (keyboardfile == NULL) { fprintf(stderr, "File '%s' not readable\n", argv[i]); exit(1); } } else if (arg[1] == 'c' && arg[2] == 0 && i + 1 < argc) { i += 1; givecmdline = argv[i]; } else if (strcmp(arg + 1, "ign") == 0 && i + 1 < argc) { i += 1; int v; bool ok = string_to_int(argv[i], v, 16); if (! ok) { fprintf(stderr, "%s on command line: address required after -ign\n", argv[i]); exit(1); } if (c.ignorecall1 == 0) c.ignorecall1 = v; else if (c.ignorecall2 == 0) c.ignorecall2 = v; else if (c.ignorecall3 == 0) c.ignorecall3 = v; else if (c.ignorecall4 == 0) c.ignorecall4 = v; else { printf("-ign may only be used four times\n"); exit(1); } } else if (arg[1] == 'p' && arg[2] == 0 && i + 1 < argc) { i += 1; scriptf.open(argv[i]); if (scriptf.fail()) { fprintf(stderr, "File '%s' is not readable\n", argv[i]); exit(1); } script = true; } else if (arg[1] == 't' && arg[2] != 0 && arg[3] == 0) { if (arg[2] == 'i') c.traceints = true; else if (arg[2] == 'c') c.tracecalls = true; else { fprintf(stderr, "Bad option '%s' on command line\n", arg); exit(1); } } else { bool saids = false, saidr = false; for (int j = 1; true; j+=1) { char c = arg[j]; if (c == 0) break; else if (c == 'r') saidr = true; else if (c == 's') saids = true; else if (c == 'q') quiet = true; else if (c == 'z') zeromode = true; else { fprintf(stderr, "Bad option '%s' on command line\n", arg); exit(1); } } if (saidr) { autorun = true; autoexit = true; } if (saids) autoexit = false; } } else if (filename == "") { prepare_filename(arg, filename, fileext); fileoncmdline = true; } else { fprintf(stderr, "Multiple file names on command line: '%s' and '%s'\n", filename.c_str(), arg); exit(1); } } if (c.ignorecall1 != 0 && ! c.tracecalls) { fprintf(stderr, "-ign only allowed on command line in conjunction with -ti\n"); exit(1); } if (script) { autorun = false; autoexit = false; } if (fileoncmdline) c.toload.push_back(NULL); // section initialise and load bool ok = c.read_initialisation(); if (! ok) { fprintf(stderr, "Initialisation failed\n"); exit(1); } if (fileoncmdline) c.toload[0] = new loaditem(filename, fileext, c.loadplace); c.load_required_files(); // section a tiny bit more initialisation c.trailcount = 0; c.intrcount = 0; for (int i = 0; i < 16; i += 1) { c.pctrail[i] = 0; c.intrtrail[i] = 0; c.intrnum[i] = 0; } c.process_dash_c_command_line(givecmdline); interrupt_driven_keyboard(& kbd_rdy); signal(SIGINT, unixigint); int linelen = 0, controlccount = 0; c.runwild = false; if (autorun) { c.runwild = true; c.flr = true; } c.sr_watch = 0; c.sr_debug = 0; c.starttime = getcputime(); c.startrt = getrealtime(); // section big loop char command[1000]; while (true) { if (c.flr == false || control_c) { if (autoexit && c.reallyhalted) break; if (c.runwild || c.stepping) { printf("\nPROCESSOR HALTED when PC = %s\n", hex(c._registers[PC] - 1).c_str()); fflush(stdout); } clear_keyboard_buffer(); c.aside_buffer_clear(); if (control_c) { c.consecctrlc += 1; c.stepping = false; } control_c = false; if (c.runwild) c.check_monitors(); c.runwild = false; } // section run wild if (c.runwild) { c.fetch(); if (c.breaking) { c.check_monitors(); continue; } if (control_c) { c.runwild = false; c.stepping = true; c.breaking = true; c.kbb_to_aside_buffer(); c.check_monitors(); continue; } if (c.flint && c.sr_ipl < INT_KEYBD && kbd_rdy && c.interrupt_code == 0) { if (c.traceints) { printf("TI: interrupt KEYBD signalled when PC = %s (SSP %s)\n", hex(c.fetch_pc).c_str(), hex(c.sr_syssp).c_str()); fflush(stdout); } c.interrupt_code = INT_KEYBD; bool ok = c.prepare_interrupt(__LINE__, INT_KEYBD); if (ok) continue; } if (c.sr_timer > 1) { c.sr_timer -= 1; if (c.sr_timer == 1 && c.interrupt_code == 0) { if (c.traceints) { printf("\nTI: interrupt TIMER signalled when PC = %s (SSP %s)\n", hex(c.fetch_pc).c_str(), hex(c.sr_syssp).c_str()); fflush(stdout); } c.interrupt_code = INT_TIMER; bool ok = c.prepare_interrupt(__LINE__, INT_TIMER); if (ok) continue; } } c.execute(); if (c.special_action) { if (c.watching_involved) { if (c.watching_involved == 1) { if (c.watch_cause == INT_WATCH) c.sr_watch = c.intrsaved_watch; else c.sr_debug = c.intrsaved_watch; c.intrsaved_watch = 0; c.special_action = 0; c.saved_watch = 0; c.watch_cause = 0; c.watching_involved = 0; } else c.watching_involved = 1; } else if (c.saved_watch) { if (c.watch_cause == INT_WATCH) c.sr_watch = c.saved_watch; else if (c.watch_cause == INT_DEBUG) c.sr_debug = c.saved_watch; c.special_action = 0; c.intrsaved_watch = 0; c.watch_cause = 0; c.watching_involved = 0; c.saved_watch = 0; } } if (c.interrupt_code != 0) { c.fetch_pc = c._registers[15]; c.prepare_interrupt(__LINE__, c.interrupt_code); continue; } continue; } else // section fetch in preparation for single step { if (c.stepping) c.fetch_for_step(); // section get user's command c.tryingtostop = false; bool normalend = true; if (script) { string line; getline(scriptf, line); if (scriptf.fail()) { scriptf.close(); script = false; line = ""; } linelen = line.length(); if (linelen > 998) { printf("line from script too long\n"); line = ""; } strcpy(command, line.c_str()); printf("script> %s\n", command); fflush(stdout); bool empty = true; for (int i = 0; i < linelen; i += 1) if (command[i] > ' ') { empty = false; break; } if (empty) command[0] = 0; if (command[0] == 0) { strcpy(command, "none"); linelen = 4; } } else if (c.stepping && c.countdown > 0 && !control_c) strcpy(command, "step"); else { bool ok = c.get_users_command(command, linelen, normalend); if (! ok) continue; } nistringstream cmd(command); cmd.setseps("=?"); string init; cmd >> init; // section obey command controlccount = 0; if (same(init, "obey")) { if (script) { printf("Already obeying a script, obeys can't be nested\n"); continue; } string fnm; cmd >> fnm; if (cmd.fail()) { printf("need a script file name\n"); continue; } scriptf.open(fnm); if (scriptf.fail()) printf("File '%s' can not be read.\n", fnm.c_str()); else script = true; continue; } if (init != "") c.obey_command(init, cmd, normalend); } } exit(c.sr_exitcode); }