/* ** E21.C -- Emulator for HP 21XX computers */ /****************************************************/ #include #include /****************************************************/ #define MXCORE 16384 #define MXLOAD MXCORE - 64 /****************************************************/ unsigned int core[MXCORE]; unsigned int p; unsigned int s; unsigned int extend; unsigned int ovflow; unsigned int run; void (*iofuncs[64])(unsigned int i); /****************************************************/ long stats[64]; /****************************************************/ int tty; int tty_flag; int tty_control; unsigned int tty_iob; unsigned int tty_mode; /****************************************************/ int reader; int reader_flag; int reader_control; int reader_drive; unsigned int reader_iob; FILE *reader_fp; int reader_eot; /****************************************************/ int punch; FILE *punch_fp; /****************************************************/ void null_iofunc (unsigned int i) { } /****************************************************/ void sc1_iofunc (unsigned int i) { /* ** Execute I/O instruction for select code 1 */ int r,control; switch ((i>>6) & 7) { case 000: /***** HLT *****/ if (i & 01000) ovflow=0; run=0; break; case 001: /***** STF, CLF *****/ if (i & 01000) ovflow=0; else ovflow=1; break; case 002: /***** SFC *****/ if (!ovflow) p++; if (i & 01000) ovflow=0; break; case 003: /***** SFS *****/ if (ovflow) p++; if (i & 01000) ovflow=0; break; case 004: /***** MIA, MIB *****/ r = (i>>11) & 1; core[r] |= s; if (i & 01000) ovflow=0; break; case 005: /***** LIA, LIB *****/ r = (i>>11) & 1; core[r] = s; if (i & 01000) ovflow=0; break; case 006: /***** OTA, OTB *****/ r = (i>>11) & 1; s = core[r]; if (i & 01000) ovflow=0; break; case 007: /***** STC, CLC *****/ if (i & 04000) control=0; else control=1; if (i & 01000) ovflow=0; break; } } /****************************************************/ void tty_iofunc (unsigned int i) { /* ** Execute I/O instruction for teletype */ int reg; reg = (i>>11) & 1; switch ((i>>6) & 7) { case 000: /***** HLT *****/ if (i & 01000) tty_flag=0; run=0; break; case 001: /***** STF, CLF *****/ if (i & 01000) tty_flag=0; else tty_flag=1; break; case 002: /***** SFC *****/ if (!tty_flag) p++; if (i & 01000) tty_flag=0; /* Not sure */ break; case 003: /***** SFS *****/ if (tty_flag) p++; if (i & 01000) tty_flag=0; /* Not sure */ break; case 004: /***** MIA, MIB *****/ core[reg] |= tty_iob; if (i & 01000) tty_flag=0; break; case 005: /***** LIA, LIB *****/ core[reg] = tty_iob; if (i & 01000) tty_flag=0; break; case 006: /***** OTA, OTB *****/ tty_iob = core[reg]; if (tty_iob & 0x8000) { tty_mode = tty_iob; } else if (tty_iob < 256) { #if 0 printf ("%c", tty_iob & 127); tty_iob = 255; #endif } if (i & 01000) tty_flag=0; break; case 007: /***** STC, CLC *****/ if (i & 04000) tty_control=0; else { tty_control=1; } if (i & 01000) tty_flag=0; break; } } /****************************************************/ void do_tty () { /* ** Simulate teletype */ int ch; #ifdef UNIX ch = ttypoll(); if (ch >= 0) { #else if (kbhit()) { ch = getchar(); #endif if (tty_mode & 040000) { if (ch == 10) ch = 13; /* Convert newline to c.r. */ #if 0 printf ("<%d>",ch); #endif if (tty_mode & 030000) { #ifdef UNIX ttyputc(ch); fsync(1); #else putchar(ch); #endif } tty_iob = ch; tty_flag = 1; } } else if (!(tty_mode & 040000) && !tty_flag) { ch = tty_iob & 0177; #if 0 if (ch < 32) printf ("<%d>",ch); #endif #ifdef UNIX if (ch) ttyputc (ch); fsync(1); #else if (ch) putchar (ch); #endif tty_iob = 255; tty_flag = 1; } } /****************************************************/ void do_reader () { /* ** Simulate high speed reader */ char name[100]; int ch; if (reader_drive && !reader_fp) { #ifdef UNIX ttyputs ("Enter name of file to read: "); ttygets (name, sizeof(name)); #else printf ("Enter name of file to read: "); gets (name); #endif reader_fp = fopen (name,"rb"); if (!reader_fp) { printf ("Can't open file %s\n", name); } } if (reader_drive && reader_fp && !reader_eot) { reader_iob = getc (reader_fp); if (reader_iob == -1) { printf ("END_OF_TAPE\n"); reader_eot = 1; } else { ch = reader_iob & 127; #if 0 printf ("<%d>",reader_iob); #endif if (ch>=32 && ch<=126) printf ("%c",ch); if (ch==10) printf ("\n"); reader_drive = 0; reader_flag = 1; } } } /****************************************************/ void reader_iofunc (unsigned int i) { /* ** Execute I/O instruction for high speed reader */ int reg; reg = (i>>11) & 1; switch ((i>>6) & 7) { case 000: /***** HLT *****/ if (i & 01000) reader_flag=0; run=0; break; case 001: /***** STF, CLF *****/ if (i & 01000) reader_flag=0; else reader_flag=1; break; case 002: /***** SFC *****/ if (!reader_flag) p++; if (i & 01000) reader_flag=0; break; case 003: /***** SFS *****/ if (reader_flag) p++; if (i & 01000) reader_flag=0; break; case 004: /***** MIA, MIB *****/ core[reg] |= reader_iob; if (i & 01000) reader_flag=0; break; case 005: /***** LIA, LIB *****/ core[reg] = reader_iob; if (i & 01000) reader_flag=0; break; case 006: /***** OTA, OTB *****/ if (i & 01000) reader_flag=0; break; case 007: /***** STC, CLC *****/ if (i & 04000) { reader_control=0; reader_drive=0; } else { reader_control=1; reader_drive=1; } if (i & 01000) reader_flag=0; break; } } /****************************************************/ void punch_iofunc (unsigned int i) { /* ** Execute I/O instruction for high speed punch */ static int flag=0,control=0,mode=0; static FILE *fp=0; int reg,iob; if (!i) { if (fp) fclose (fp); fp=0; return; } if (!fp) { fp = fopen ("PUNCH.OUT","wb"); if (!fp) { printf ("Can't create PUNCH.OUT\n"); exit(); } } reg = (i>>11) & 1; switch ((i>>6) & 7) { case 000: /***** HLT *****/ if (i & 01000) flag=0; run=0; break; case 001: /***** STF, CLF *****/ if (i & 01000) flag=0; else flag=1; break; case 002: /***** SFC *****/ if (!flag) p++; if (i & 01000) flag=0; break; case 003: /***** SFS *****/ flag=1; if (flag) p++; if (i & 01000) flag=0; break; case 004: /***** MIA, MIB *****/ core[reg] |= 0; if (i & 01000) flag=0; break; case 005: /***** LIA, LIB *****/ core[reg] = 0; if (i & 01000) flag=0; break; case 006: /***** OTA, OTB *****/ iob = core[reg]; putc (iob, fp); if (i & 01000) flag=0; break; case 007: /***** STC, CLC *****/ if (i & 04000) control=0; else { control=1; } if (i & 01000) flag=0; break; } } /****************************************************/ #define INDIRECT(m) { \ m = core[m]; \ while (m & 0100000) { \ m = core[m & 077777]; \ } \ } /****************************************************/ unsigned int add16 (x,y) /* ** Perform 16 bit addition, setting extend ** and overflow bits as required. */ unsigned int x,y; { unsigned int z; z = x + y; if ((x & 0x8000) && (y & 0x8000)) { extend=1; } if (((x & 0x8000) || (y & 0x8000)) && (z & 0x8000) == 0) { extend=1; } if ((x & 0x8000) == (y & 0x8000) && (z & 0x8000) != (x & 0x8000)) { ovflow=1; } return (z & 0xFFFF); } /****************************************************/ unsigned int srg (f, sp1) /* ** Perform shift-rotate group sub function */ unsigned int f,sp1; { unsigned int tmp; switch (f & 7) { case 0: /***** ALS *****/ sp1 = ((sp1<<1) & 077777) | (sp1 & 0100000); break; case 1: /***** ARS *****/ sp1 = ((sp1>>1) & 077777) | (sp1 & 0100000); break; case 2: /***** RAL *****/ sp1 = ((sp1<<1) & 0177777) | (sp1>>15); break; case 3: /***** RAR *****/ sp1 = (sp1>>1) | ((sp1 & 1) << 15); break; case 4: /***** ALR *****/ sp1 = (sp1<<1) & 077777; break; case 5: /***** ERA *****/ tmp = sp1 & 1; sp1 = (extend << 15) | (sp1>>1); extend = tmp; break; case 6: /***** ELA *****/ tmp = sp1>>15; sp1 = (sp1<<1) | extend; extend = tmp; sp1 = sp1 & 0177777; break; case 7: /***** ALF *****/ sp1 = ((sp1<<4) & 0177777) | (sp1>>12); break; } return (sp1); } /******************************************************/ unsigned int asg (i,sp1) /* ** Perform Alter Skip group function */ unsigned int i,sp1; { int skip=0; /* ** CLA, CMA, CCA (also CLB, CMB, CCB) */ if (i & 00400) sp1 = 0; if (i & 01000) sp1 ^= 0177777; if (!(i&1)) { /* ** non-RSS */ if ((i & 040) && (extend==0)) skip=1; /* SEZ */ if (i & 00100) extend = 0; /* CLE */ if (i & 00200) extend ^= 1; /* CME */ if ((i & 020) && (sp1 & 0x8000)==0) skip=1; /* SSA */ if ((i & 010) && (sp1 & 1)==0) skip=1; /* SLA */ if (i & 004) sp1 = add16(sp1,1); /* INA */ if ((i & 002) && (sp1==0)) skip=1; /* SZA */ } else { /* ** RSS */ if ((i & 040) && (extend!=0)) skip=1; /* SEZ,RSS */ if (i & 00100) extend = 0; /* CLE */ if (i & 00200) extend ^= 1; /* CME */ if ((i & 031) == 031) { if ((sp1 & 0x8001) == 0x8001) skip=1; /* SSA,SLA,RSS */ } else { if ((i & 020) && (sp1 & 0x8000)!=0) skip=1; /* SSA,RSS */ if ((i & 010) && (sp1 & 1)!=0) skip=1; /* SLA,RSS */ } if (i & 004) sp1 = add16(sp1,1); /* INA */ if ((i & 002) && (sp1!=0)) skip=1; /* SZA,RSS */ if ((i & 073) == 001) skip=1; /* RSS */ } if (skip) p++; return (sp1); } /******************************************************/ void run_cpu (limit) int limit; { register unsigned int i; register unsigned int m; register unsigned int sp1; register unsigned int f; while (limit && run) { limit--; i = core[p]; f = i>>10; stats[f]++; if (i & 070000) { /** MRG **/ m = i & 0101777; if (i & 02000) m |= (p & 076000); while (m & 0100000) { m = core[m & 077777]; } switch ((i >> 11) & 15) { case 0: case 1: break; case 2: /* AND */ core[0] &= core[m]; p++; break; case 3: /* JSB */ core[m] = p+1; p = m+1; break; case 4: /* XOR */ core[0] ^= core[m]; p++; break; case 5: /* JMP */ p = m; break; case 6: /* IOR */ core[0] |= core[m]; p++; break; case 7: /* ISZ */ sp1 = (core[m] + 1) & 0177777; core[m] = sp1; if (!sp1) p++; p++; break; case 8: /* ADA */ core[0] = add16 (core[0], core[m]); p++; break; case 9: /* ADB */ core[1] = add16 (core[1], core[m]); p++; break; case 10: /* CPA */ if (core[0] != core[m]) p++; p++; break; case 11: /* CPB */ if (core[1] != core[m]) p++; p++; break; case 12: /* LDA */ core[0] = core[m]; p++; break; case 13: /* LDB */ core[1] = core[m]; p++; break; case 14: /* STA */ core[m] = core[0]; p++; break; case 15: /* STB */ core[m] = core[1]; p++; break; } } else if ((i & 0102000) == 002000) { /** ASG **/ if (!(i & 004000)) { core[0] = asg (i, core[0]); p++; } else { core[1] = asg (i, core[1]); p++; } } else if ((i & 0102000) == 000000) { /** SRG **/ if (!(i & 004000)) { sp1 = core[0]; if (i & 01000) sp1 = srg (i>>6, sp1); if (i & 040) extend=0; if (i & 010) if ((sp1 & 1)==0) p++; if (i & 020) sp1 = srg (i, sp1); core[0] = sp1; p++; } else { sp1 = core[1]; if (i & 01000) sp1 = srg (i>>6, sp1); if (i & 040) extend=0; if (i & 010) if ((sp1 & 1)==0) p++; if (i & 020) sp1 = srg (i, sp1); core[1] = sp1; p++; } } else if ((i & 0102000) == 0102000) { /** IOG **/ sp1 = i & 077; if (iofuncs[sp1]) { (iofuncs[sp1])(i); } else { printf ("SC=%2o\n", sp1); iofuncs[sp1] = null_iofunc; } if (!(i & 0700)) { printf ("HALT %6o\n", i); run=0; } if (limit > 3) limit=3; p++; } else { /** EAG **/ run = 0; } } } /****************************************************/ reset () { long ii; for (ii=0; ii=0 && dig ' ') { out[nn++] = line[lp++]; } out[nn]=0; } /****************************************************/ examine_registers () { printf ("P=%5o I=%6o A=%6o B=%6o E=%1o OV=%1o\n", p, core[p], core[0], core[1], extend, ovflow); } /****************************************************/ examine_memory () { long ii, loc, count; err_count=0; parse_arg (&loc); if (err_count) return; if (end_of_line()) count=1; else { while (line[lp]==' ') lp++; parse_arg (&count); if (err_count) return; } for (ii=0; ii32) fname[ii++]=line[lp++]; fname[ii]=0; fp = fopen (fname, "rb"); if (!fp) { printf ("File '%s' not found!\n\n", fname); return; } nbchecked = 0; maxnull = 10000; done = 0; while (!done) { count = fgetc (fp); if (count == EOF) { printf ("Unexpected EOF!\n"); done = 1; } else if (!count) { maxnull--; if (!maxnull) done=1; } else { dummy = fgetc (fp); addr = (fgetc(fp) << 8) | fgetc(fp); sum = addr; for (ii=0; ii= MXLOAD) { printf ("Load address exceeds %o\n", MXLOAD); return; } core[addr++] = data & 0xFFFFL; sum = sum + data; nbchecked++; } data = (fgetc(fp) << 8) | fgetc(fp); if (sum != data) { printf ("Checksum Error!\n"); done = 1; } else { maxnull = 10; } } } printf ("%d words loaded\n", nbchecked); } /****************************************************/ run_command () { long start; int limit; if (!end_of_line()) { err_count=0; parse_arg (&start); if (err_count) return; p = start; } run = 1; while (run) { limit = 1000; run_cpu (limit); do_tty (); do_reader (); } examine_registers (); } /****************************************************/ single_step () { int limit; run=1; limit=1; run_cpu (limit); run=0; examine_registers (); } /****************************************************/ show_stats () { int i; long total=0; for (i=0; i<64; i++) { if (!(i&7)) printf ("\n"); printf ("%9ld ", stats[i]); total += stats[i]; } printf ("\n"); printf ("TOTAL INSTRUCTIONS = %ld\n", total); } /****************************************************/ print_help () { printf ("Commands are:\n"); printf (" RESET Clear all memory\n"); printf (" STATS Show instruction stats\n"); printf (" LOAD Load program into memory\n"); printf (" RUN
Run program\n"); printf (" E
Examine memory\n"); printf (" ER Examine registers\n"); printf (" S Single step\n"); printf (" Q Quit\n"); } /****************************************************/ command () { char cmd[100]; int done; done=0; while (!done) { #ifdef UNIX ttyputs ("U-2100> "); ttygets (line, sizeof(line)); if (1) { #else printf ("2100> "); if (!fgets(line, sizeof(line), stdin)) { printf ("\n"); done=1; } else { #endif lp=0; parse_token (cmd); if (cmd[0]=='\0') done=0; else if (!strcmp(cmd,"RESET")) reset(); else if (!strcmp(cmd,"STATS")) show_stats(); else if (!strcmp(cmd,"LOAD")) load_command(); else if (!strcmp(cmd,"RUN")) run_command(); else if (!strcmp(cmd,"E")) examine_memory(); else if (!strcmp(cmd,"ER")) examine_registers (); else if (!strcmp(cmd,"S")) single_step (); else if (!strcmp(cmd,"Q")) done=1; else if (!strcmp(cmd,"?")) print_help(); else printf ("Unknown command - Enter ? for help\n"); } } } /****************************************************/ main () { #ifdef UNIX ttyraw(); #endif reset (); /* Initialize registers and memory */ command (); punch_iofunc (0); #ifdef UNIX ttyrestore(); #endif return (0); } /****************************************************/