diff --git a/.gitignore b/.gitignore index d958df61..3eff3bd3 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,9 @@ obj/ [Rr]elease*/ _ReSharper*/ [Tt]est[Rr]esult* -*.o +*.o +*~ +*# BIN/ ipch/ # We only care about specific files in the Visual Studio Projects diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c index b0645fa2..926eac90 100644 --- a/Ibm1130/ibm1130_cpu.c +++ b/Ibm1130/ibm1130_cpu.c @@ -798,7 +798,7 @@ t_stat sim_instr (void) CCC--; } C = (CCC != 0); - WriteIndex(TAG, ReadIndex(TAG) & 0xFF00 | CCC); /* put 6 bits back into low byte of index register */ + WriteIndex(TAG, (ReadIndex(TAG) & 0xFF00) | CCC); /* put 6 bits back into low byte of index register */ break; } /* if TAG == 0, fall through and treat like normal shift SLT */ @@ -842,8 +842,8 @@ t_stat sim_instr (void) while (CCC > 0) { xbit = (ACC & 0x0001) << 15; abit = (ACC & 0x8000); - ACC = (ACC >> 1) & 0x7FFF | abit; - EXT = (EXT >> 1) & 0x7FFF | xbit; + ACC = ((ACC >> 1) & 0x7FFF) | abit; + EXT = ((EXT >> 1) & 0x7FFF) | xbit; CCC--; } break; @@ -852,8 +852,8 @@ t_stat sim_instr (void) while (CCC > 0) { abit = (EXT & 0x0001) << 15; xbit = (ACC & 0x0001) << 15; - ACC = (ACC >> 1) & 0x7FFF | abit; - EXT = (EXT >> 1) & 0x7FFF | xbit; + ACC = ((ACC >> 1) & 0x7FFF) | abit; + EXT = ((EXT >> 1) & 0x7FFF) | xbit; CCC--; } break; diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 4a66f701..057cf7b6 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -151,6 +151,10 @@ typedef struct { d10 ac; } InstHistory; +extern a10 fe_xct; /* Front-end forced XCT */ +extern DEVICE pag_dev; +extern t_stat pag_reset (DEVICE *dptr); + d10 *M = NULL; /* memory */ d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */ d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */ @@ -708,19 +712,45 @@ xct_cnt = 0; /* count XCT's */ if (sim_interval <= 0) { /* check clock queue */ if ((i = sim_process_event ())) /* error? stop sim */ ABORT (i); - pi_eval (); /* eval pi system */ + if (fe_xct) + qintr = -1; + else + pi_eval (); /* eval pi system */ } /* PI interrupt (Unibus or system flags). On the KS10, only JSR and XPCW are allowed as interrupt instructions. Because of exec mode addressing, and unconditional processing of flags, they are explicitly emulated here. + On a keep-alive failure, the console (fe) forces the CPU 'XCT' the + instruction at exec 71. This is close enough to an interrupt that it is + treated as one here. TOPS-10 and TOPS-20 use JSR or XPCW, which are + really the only sensible instructions, as diagnosing a KAF requires the + PC/FLAGS of the fault. + On a reload-request from the OS, the fe loads the bootstrap code and sets + saved_PC. Here, the CPU is partially reset and redirected. (Preserving + PC history, among other things.) The FE has already reset IO. */ if (qintr) { int32 vec, uba; pager_pi = TRUE; /* flag in pi seq */ - if ((vec = pi_ub_vec (qintr, &uba))) { /* Unibus interrupt? */ + if (fe_xct) { /* Console forced execute? */ + qintr = 0; + if (fe_xct == 1) { /* Forced reload */ + PC = saved_PC; /* Bootstrap PC */ + pager_pi = FALSE; + ebr = ubr = 0; /* Exec mode, paging & PI off */ + pag_reset (&pag_dev); + pi_on = pi_enb = pi_act= pi_prq = + apr_enb = apr_flg = apr_lvl = its_1pr = 0; + rlog = 0; + set_newflags (0, FALSE); + fe_xct = 0; + continue; + } + inst = ReadE(fe_xct); /* Exec address of instruction */ + } else if ((vec = pi_ub_vec (qintr, &uba))) { /* Unibus interrupt? */ mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */ if (mb == 0) /* invalid? stop */ ABORT (STOP_ZERINT); @@ -750,9 +780,16 @@ if (qintr) { JUMP (rs[1]); /* set new PC */ set_newflags (rs[0], FALSE); /* set new flags */ } - else ABORT (STOP_ILLINT); /* invalid instr */ - pi_act = pi_act | pi_l2bit[qintr]; /* set level active */ - pi_eval (); /* eval pi system */ + else { + fe_xct = 0; + ABORT (STOP_ILLINT); /* invalid instr */ + } + if (fe_xct) + fe_xct = 0; + else { + pi_act = pi_act | pi_l2bit[qintr]; /* set level active */ + pi_eval (); /* eval pi system */ + } pager_pi = FALSE; /* end of sequence */ if (sim_interval) /* charge for instr */ sim_interval--; diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index fb18a1f5..126e5504 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -114,7 +114,8 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define STOP_XCT 9 /* XCT loop */ #define STOP_ILLIOC 10 /* invalid UBA num */ #define STOP_ASTOP 11 /* address stop */ -#define STOP_UNKNOWN 12 /* unknown stop */ +#define STOP_CONSOLE 12 /* FE halt */ +#define STOP_UNKNOWN 13 /* unknown stop */ #define PAGE_FAIL -1 /* page fail */ #define INTERRUPT -2 /* interrupt */ #define ABORT(x) longjmp (save_env, (x)) /* abort */ @@ -746,7 +747,7 @@ typedef struct pdp_dib DIB; #define INT_IPL7 0x0000000F /* int level masks */ #define INT_IPL6 0x000000F0 #define INT_IPL5 0x000FFF00 -#define INT_IPL4 0x3FF00000 +#define INT_IPL4 0x7FF00000 #define VEC_Q 0000 /* vector base */ #define VEC_PTR 0070 /* interrupt vectors */ @@ -768,8 +769,10 @@ typedef struct pdp_dib DIB; int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); +int32 Map_ReadW18 (uint32 ba, int32 bc, uint32 *buf); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); +int32 Map_WriteW18 (uint32 ba, int32 bc, uint32 *buf); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c index 80d4a436..0097af27 100644 --- a/PDP10/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -47,8 +47,13 @@ extern int32 apr_flg; extern int32 tmxr_poll; t_stat fei_svc (UNIT *uptr); t_stat feo_svc (UNIT *uptr); +static t_stat kaf_svc (UNIT *uptr); t_stat fe_reset (DEVICE *dptr); t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); +a10 fe_xct = 0; +uint32 fe_bootrh = 0; +int32 fe_bootunit = -1; +extern DIB *dib_tab[]; /* FE data structures @@ -59,10 +64,12 @@ t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); #define fei_unit fe_unit[0] #define feo_unit fe_unit[1] +#define kaf_unit fe_unit[2] UNIT fe_unit[] = { { UDATA (&fei_svc, UNIT_IDLE, 0), 0 }, - { UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT } + { UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT }, + { UDATA (&kaf_svc, 0, 0), (1*1000*1000) } }; REG fe_reg[] = { @@ -82,7 +89,7 @@ MTAB fe_mod[] = { DEVICE fe_dev = { "FE", fe_unit, fe_reg, fe_mod, - 2, 10, 31, 1, 8, 8, + 3, 10, 31, 1, 8, 8, NULL, NULL, &fe_reset, NULL, NULL, NULL }; @@ -113,6 +120,48 @@ DEVICE fe_dev = { input character). */ +/* Here is the definition of the communications area: +XPP RLWORD,31 ;RELOAD WORD [FE_KEEPA] + KSRLD==1B4 ;RELOAD REQUEST (8080 will reload -10 if this is set) + KPACT==1B5 ;KEEP ALIVE ACTIVE (8080 reloads -10 if KPALIV doesn't change) + KLACT==1B6 ;KLINIK ACTIVE (Remote diagnosis line enabled) + PAREN==1B7 ;PARITY ERROR DETECT ENABLED + CRMPAR==1B8 ;CRAM PAR ERR DETECT ENABLED + DRMPAR==1B9 ;DRAM PAR ERR DETECT ENABLED + CASHEN==1B10 ;CACHE ENABLED + MILSEN==1B11 ;1MSEC ENABLED + TRPENA==1B12 ;TRAPS ENABLED + MFGMOD==1B13 ;MANUFACTURING MODE + KPALIV==377B27 ;KEEP ALIVE WORD CHECKED EVERY 1 SEC, AFTER 15, FAIL + ; Why reload (8080->10) + AUTOBT==1B32 ;BOOT SWITCH OR POWER UP CONDITION + PWRFAL==1B33 ;POWER FAIL restart (Start at 70) + FORREL==1B34 ;FORCED RELOAD + KEPFAL==1B35 ;KEEP ALIVE FAILURE (XCT exec 71) + +XPP CTYIWD,32 ;CTY INPUT WORD [FE_CTYIN] + CTYICH==377B35 ;CTY INPUT CHARACTER + CTYIVL==1B27 ;INPUT VALID BIT (Actually, this is an 8-bit function code) + +XPP CTYOWD,33 ;CTY OUTPUT WORD [FE_CTYOUT] + CTYOCH==377B35 ;CTY OUTPUT CHARACTER + CTYOVL==1B27 ;OUTPUT VALID FLAG + +XPP KLIIWD,34 ;KLINIK INPUT WORD [FE_KLININ] + KLIICH==377B35 ;KLINIK INPUT CHARACTER + KLIIVL==1B27 ;KLINIK INPUT VALID (Historical) + KLICHR==1B27 ;KLINIK CHARACTER + KLIINI==2B27 ;KLINIK INITED + KLICAR==3B27 ;CARRIER LOST + + +XPP KLIOWD,35 ;KLINIK OUTPUT WORD [FE_KLINOUT] + KLIOCH==377B35 ;KLINIK OUTPUT CHARACTER + KLIOVL==1B27 ;KLINIK OUTPUT VALID (Historical) + KLOCHR==1B27 ;KLINIK CHARACTER AVAILABLE + KLIHUP==2B27 ;KLINIK HANGUP REQUEST +*/ + void fe_intr (void) { if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */ @@ -156,15 +205,103 @@ apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ return SCPE_OK; } +/* Keep-alive service + * If the 8080 detects the 'force reload' bit, it initiates a disk + * boot. IO is reset, but memory is preserved. + * + * If the keep-alive enable bit is set, the -10 updates the keep-alive + * count field every second. The 8080 also checks the word every second. + * If the 8080 finds that the count hasn't changed for 15 consecutive seconds, + * a Keep-Alive Failure is declared. This forces the -10 to execute the + * contents of exec location 71 to collect status and initiate error recovery. + */ +static t_stat kaf_svc (UNIT *uptr) +{ +if (M[FE_KEEPA] & INT64_C(0020000000000)) { /* KSRLD - "Forced" (actually, requested) reload */ + uint32 oldsw = sim_switches; + DEVICE *bdev = NULL; + int32 i; + + sim_switches &= ~SWMASK ('P'); + reset_all (4); /* RESET IO starting with UBA */ + sim_switches = oldsw; + + M[FE_KEEPA] &= ~INT64_C(0030000177777); /* Clear KAF, RLD, KPALIV & reason + * 8080 ucode actually clears HW + * status too, but that's a bug. */ + M[FE_KEEPA] |= 02; /* Reason = FORREL */ + fei_unit.buf = feo_unit.buf = 0; + M[FE_CTYIN] = M[FE_CTYOUT] = 0; + M[FE_KLININ] = M[FE_KLINOUT] = 0; + + /* The 8080 has the disk RH address & unit in its memory, even if + * the previous boot was from tape. It has no NVM, so the last opr + * selection will do here. The case of DS MT would require a + * SET FE command. It's not a common case. + */ + + /* The device may have been detached, disabled or reconfigured since boot time. + * Therefore, search for it by CSR address & validate that it's bootable. + * If there are problems, the processor is halted. + */ + + for (i = 0; fe_bootrh && (bdev = sim_devices[i]) != NULL; i++ ) { + DIB *dibp = (DIB *)bdev->ctxt; + if (dibp && (fe_bootrh >= dibp->ba) && + (fe_bootrh < (dibp->ba + dibp->lnt))) { + break; + } + } + + fe_xct = 2; + if ((bdev != NULL) && (fe_bootunit >= 0) && (fe_bootunit < (int32) bdev->numunits)) { + UNIT *bunit = bdev->units + fe_bootunit; + + if (!(bunit->flags & UNIT_DIS) && (bunit->flags & UNIT_ATTABLE) && (bunit->flags & UNIT_ATT)) { + if (bdev->boot (fe_bootunit, bdev) == SCPE_OK) /* boot the device */ + fe_xct = 1; + } + } + } +else if (M[FE_KEEPA] & INT64_C(0010000000000)) { /* KPACT */ + d10 kav = M[FE_KEEPA] & INT64_C(0000000177400); /* KPALIV */ + if (kaf_unit.u3 != (uint32)kav) { + kaf_unit.u3 = (uint32)kav; + kaf_unit.u4 = 0; + } + else if (++kaf_unit.u4 >= 15) { + kaf_unit.u4 = 0; + M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0000000000377)) | 01; /* RSN = KAF (leaves enabled) */ + fei_unit.buf = feo_unit.buf = 0; + M[FE_CTYIN] = M[FE_CTYOUT] = 0; + M[FE_KLININ] = M[FE_KLINOUT] = 0; + fe_xct = 071; + } + } + +sim_activate_after (&kaf_unit, kaf_unit.wait); +if (fe_xct == 2) { + fe_xct = 0; + return STOP_CONSOLE; + } +return SCPE_OK; +} /* Reset */ t_stat fe_reset (DEVICE *dptr) { tmxr_set_console_units (&fe_unit[0], &fe_unit[1]); fei_unit.buf = feo_unit.buf = 0; + M[FE_CTYIN] = M[FE_CTYOUT] = 0; +M[FE_KLININ] = M[FE_KLINOUT] = 0; + +M[FE_KEEPA] = INT64_C(0003740000000); /* PARITY STOP, CRM, DP PAREN, CACHE EN, 1MSTMR, TRAPEN */ +kaf_unit.u3 = 0; +kaf_unit.u4 = 0; apr_flg = apr_flg & ~(APRF_ITC | APRF_CON); sim_activate (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); +sim_activate_after (&kaf_unit, kaf_unit.wait); return SCPE_OK; } diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index ba9e8b90..019aa99d 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -79,17 +79,23 @@ #define AUTO_CSRMAX 04000 #define AUTO_VECBASE 0300 +#define UBMPAGE(x) (x & (PAG_VPN<<2)) /* UBA Map page field of 11 address */ #define XBA_MBZ 0400000 /* ba mbz */ #define eaRB (ea & ~1) #define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377) #define UBNXM_FAIL(pa,op) \ - n = iocmap[GET_IOUBA (pa)]; \ + n = ADDR2UBA (pa); \ if (n >= 0) \ ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \ pager_word = PF_HARD | PF_VIRT | PF_IO | \ ((op == WRITEB)? PF_BYTE: 0) | \ (TSTF (F_USR)? PF_USER: 0) | (pa); \ ABORT (PAGE_FAIL) +/* Is Unibus address mapped to host memory */ +#define HOST_MAPPED(ub,ba) ((ubmap[ub][PAG_GETVPN(((ba) & 0777777) >> 2)] & UMAP_VLD) != 0) + +/* Translate UBA number in a PA to UBA index. 1,,* -> ubmap[0], all others -> ubmap[1] */ +#define ADDR2UBA(x) (iocmap[GET_IOUBA (x)]) /* Unibus adapter data */ @@ -401,131 +407,349 @@ return; simulator and the 32b world of the device simulators. */ -d10 ReadIO (a10 ea) +static t_stat UBReadIO (int32 *data, int32 ba, int32 access) { -uint32 pa = (uint32) ea; -int32 i, n, val; +uint32 pa = (uint32) ba; +int32 i, val; DIB *dibp; for (i = 0; (dibp = dib_tab[i]); i++ ) { if ((pa >= dibp->ba) && (pa < (dibp->ba + dibp->lnt))) { - dibp->rd (&val, pa, READ); + dibp->rd (&val, pa, access); pi_eval (); - return ((d10) val); + *data = val; + return SCPE_OK; } } -UBNXM_FAIL (pa, READ); +return SCPE_NXM; +} + +d10 ReadIO (a10 ea) +{ +uint32 pa = (uint32) ea; +int32 n, val; + + if (UBReadIO (&val, pa, READ) == SCPE_OK) + return ((d10) val); + UBNXM_FAIL (pa, READ); +} + + +static t_stat UBWriteIO (int32 data, int32 ba, int32 access) +{ +uint32 pa = (uint32) ba; +int32 i; +DIB *dibp; + +for (i = 0; (dibp = dib_tab[i]); i++ ) { + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + dibp->wr (data, ba, access); + pi_eval (); + return SCPE_OK; + } + } +return SCPE_NXM; } void WriteIO (a10 ea, d10 val, int32 mode) { uint32 pa = (uint32) ea; -int32 i, n; -DIB *dibp; +int32 n; -for (i = 0; (dibp = dib_tab[i]); i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - dibp->wr ((int32) val, pa, mode); - pi_eval (); - return; - } - } +if (UBWriteIO ((int32) val, (int32) pa, mode) == SCPE_OK) + return; UBNXM_FAIL (pa, mode); } -/* Mapped read and write routines - used by standard Unibus devices on Unibus 1 */ +/* Mapped read and write routines - used by standard Unibus devices on Unibus 1 + * I/O space accesses will work. Note that Unibus addresses with bit 17 set can + * not be mapped by the UBA, so I/O space (and more) can not be mapped to host memory. + */ -a10 Map_Addr10 (a10 ba, int32 ub) +a10 Map_Addr10 (a10 ba, int32 ub, int32 *ubmp) { a10 pa10; int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */ - -if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || /* invalid map? */ - ((ubmap[ub][vpn] & UMAP_VLD) == 0)) +int32 ubm; + +if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ)) { /* Validate bus address */ + if (ubmp) + *ubmp = 0; return -1; -pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK; +} +ubm = ubmap[ub][vpn]; +if (ubmp) + *ubmp = ubm; + +if ((ubm & UMAP_VLD) == 0) /* Ensure map entry is valid */ + return -1; +pa10 = (ubm + PAG_GETOFF (ba >> 2)) & PAMASK; return pa10; } int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf) { -uint32 lim; +uint32 lim, cp, np; a10 pa10; +if ((ba & ~((IO_M_UBA<> 8) & 0xff): csr & 0xff; + ba++; + bc--; + } + return bc; +} lim = ba + bc; -for ( ; ba < lim; ba++) { /* by bytes */ - pa10 = Map_Addr10 (ba, 1); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - return (lim - ba); /* return bc */ +for ( cp = ~ba ; ba < lim; ba++) { /* by bytes */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ + return (lim - ba); /* return bc */ + } + cp = np; } *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377); + if ((ba & 3) == 3) + pa10++; } return 0; } int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf) { -uint32 lim; +uint32 lim, cp, np; a10 pa10; +if ((ba & ~((IO_M_UBA<> ((ba & 2)? 0: 18)) & 0177777); + if (ba & 2 ) + pa10++; } return 0; } +/* Word reads returning 18-bit data */ + +int32 Map_ReadW18 (uint32 ba, int32 bc, uint32 *buf) +{ +uint32 lim, cp, np; +a10 pa10; + +if ((ba & ~((IO_M_UBA<> ((ba & 2)? 0: 18)) & 0777777); + if (ba & 2 ) + pa10++; + } +return 0; +} + +/* Byte-mode writes */ + int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf) { -uint32 lim; +uint32 lim, cp, np; a10 pa10; d10 mask; -lim = ba + bc; -for ( ; ba < lim; ba++) { /* by bytes */ - pa10 = Map_Addr10 (ba, 1); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - return (lim - ba); /* return bc */ +if ((ba & ~((IO_M_UBA< of M[] are undefined. */ + M[pa10] = ((d10) *buf++) << 18; /* Clears undefined bits */ + } else { /* RPW - clear byte position, and UB<17:16> of correct 1/2 word when writing high byte */ + mask = 0377<< ubashf[ba & 3]; + if (ba & 1) + mask |= INT64_C(0000000600000) << ((ba & 2)? 0 : 18); + M[pa10] = (M[pa10] & ~mask) | (((d10) *buf++) << ubashf[ba & 3]); + if ((ba & 3) == 3) + pa10++; } - mask = 0377; - M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) | - (((d10) *buf++) << ubashf[ba & 3]); } return 0; } +/* Word mode writes; 16-bit data */ + int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf) { -uint32 lim; +uint32 lim, cp, np; +int32 ubm; a10 pa10; d10 val; +if ((ba & ~((IO_M_UBA< */ + if (ubm & UMAP_RRV ) { /* Read reverse preserves even word */ + if (ba & 2) { + M[pa10] = (M[pa10] & INT64_C(0777777000000)) | val; + pa10++; + } else + M[pa10] = (M[pa10] & INT64_C(0000000777777)) | (val << 18); /* preserve */ + } else { /* Not RRV */ + if (ba & 2) { /* Write odd preserves even word */ + M[pa10] = (M[pa10] & INT64_C(0777777000000)) | val; + pa10++; + } else + M[pa10] = val << 18; /* Write even clears odd */ } - val = *buf++; /* get data */ - if (ba & 2) - M[pa10] = (M[pa10] & INT64_C(0777777000000)) | val; - else M[pa10] = (M[pa10] & INT64_C(0000000777777)) | (val << 18); } return 0; } + +/* Word mode writes; 18-bit data */ + +int32 Map_WriteW18 (uint32 ba, int32 bc, uint32 *buf) +{ +uint32 lim, cp, np; +int32 ubm; +a10 pa10; +d10 val; + +if ((ba & ~((IO_M_UBA<ctxt) == dib_tab[i]) { @@ -912,9 +1138,25 @@ for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ break; } } - fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba, - dib_tab[i]->ba + dib_tab[i]->lnt - 1, - dptr? sim_dname (dptr): "CPU"); + fprintf (st, "%07o - %07o ", dib_tab[i]->ba, + dib_tab[i]->ba + dib_tab[i]->lnt - 1); + if (dib_tab[i]->vec == 0) + fprintf (st, " "); + else { + fprintf (st, "%03o", dib_tab[i]->vec); + if (dib_tab[i]->vnum > 1) + fprintf (st, "-%03o", dib_tab[i]->vec + (4 * (dib_tab[i]->vnum - 1))); + else + fprintf (st, " "); + fprintf (st, "%1s", (dib_tab[i]->vnum >= AUTO_VECBASE)? "*": " "); + } + if (dib_tab[i]->vec || dib_tab[i]->vloc) + fprintf (st, " %2u", (dib_tab[i]->vloc<=3)? 7: + (dib_tab[i]->vloc<=7)? 6: + (dib_tab[i]->vloc<=19)? 5: 4); + else + fprintf (st, " "); + fprintf (st, " %s\n", dptr? sim_dname (dptr): "CPU"); } return SCPE_OK; } @@ -929,7 +1171,7 @@ return SCPE_OK; devices with static addresses and addresses(and vectors) in floating address space is #ifdef'd out below. These addresses have been used historically in the PDP10 simulator so their fixed addresses - are retained for consistency with OS configurations which probably + are retained for consistency with OS configurations which expect them to be using these fixed address and vectors. A minus number of vectors indicates a field that should be calculated @@ -962,9 +1204,9 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ { { "PTP" }, 1, 1, 0, 0, {0017554}, {0074} }, /* PC11 punch - fx CSR, fx VEC */ { { "DUP" }, 1, 2, 0, 0, - {0000300}, {0300} }, /* DUP11 bit sync - fx CSR, fx VEC */ - { { "KMC" }, 1, 2, 0, 0, - {0000540}, {0540} }, /* KMC11 comm - fx CSR, fx VEC */ + {0000300}, {0570} }, /* DUP11 bit sync - fx CSR, fx VEC */ + { { "KDP" }, 1, 2, 0, 0, + {0000540}, {0540} }, /* KMC11-A comm IOP-DUP ucode - fx CSR, fx VEC */ #else { { "QBA" }, 1, 0, 0, 0, {017500} }, /* doorbell - fx CSR, no VEC */ diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index 9d6e2a96..9a8366c4 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -25,6 +25,8 @@ lp20 line printer + 23-Jun-13 TL Add optical VFU support and fix some inconsistencies + with the hardware. Add documentation. 29-May-13 TL Force append when an existing file is attached. Previously over-wrote file from the top. 19-Jan-07 RMS Added UNIT_TEXT flag @@ -39,25 +41,52 @@ 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Added enable/disable support 30-Nov-01 RMS Added extended SET/SHOW support + + References: + EK-LP20-TM-004 LP20 LINE PRINTER SYSTEM MANUAL + B-TC-LP20-0-1 MP0006 LP20 Field Maintenance Print Set + DpC255137D Dataproducts Corp Maintenance Guide Vol. I + 300LPM/600 LPM Line Printers. + LP2SER.MAC TOPS-10 Device driver + LPKSDV.MAC TOPS-20 Device driver + LP20.MAC TOPS-10/20 VFU/RAM utility + LPTSPL/LPTSUB.MAC TOPS-10/20 GALAXY spooler */ #include "pdp10_defs.h" +/* Time (seconds) of idleness before data flushed to attached file. */ +#ifndef LP20_IDLE_TIME +#define LP20_IDLE_TIME (10) +#endif + +/* The LP20 has the following CSR assignments: + * Unit No. 1: 775400, Vector: 754 + * Unit No. 2: 775420, Vector: 750 + * + * Note that the KS only supported one LP20. + * Note also that the vector assigned to unit 2 is lower than unit 1's. + */ + #define UNIT_DUMMY (1 << UNIT_V_UF) #define LP_WIDTH 132 /* printer width */ - +#define DEFAULT_LPI 6 /* default lines-per-inch of LPT */ /* DAVFU RAM */ #define DV_SIZE 143 /* DAVFU size */ #define DV_DMASK 077 /* data mask per byte */ #define DV_TOF 0 /* top of form channel */ +#define DV_BOF 11 /* bottom of form channel */ #define DV_MAX 11 /* max channel number */ +#define MIN_VFU_LEN 2 /* minimum VFU length (in inches) */ +#define VFU_LEN_VALID(lines, lpi) ((lines) >= (lpi * MIN_VFU_LEN)) /* Translation RAM */ #define TX_SIZE 256 /* translation RAM */ #define TX_AMASK (TX_SIZE - 1) -#define TX_DMASK 07777 +#define TX_DMASK 007777 +#define TX_PARITY 010000 /* Parity bit (emulated: 'valid'; unwritten has bad 'parity') */ #define TX_V_FL 8 /* flags */ #define TX_M_FL 017 /* define TX_INTR 04000 *//* interrupt */ @@ -106,13 +135,13 @@ #define CSB_GOE 0000001 /* go error */ #define CSB_DTE 0000002 /* DEM timing error NI */ #define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */ -#define CSB_RPE 0000010 /* RAM parity error NI */ +#define CSB_RPE 0000010 /* RAM parity error */ #define CSB_MPE 0000020 /* MEM parity error NI */ #define CSB_LPE 0000040 /* LPT parity error NI */ #define CSB_DVOF 0000100 /* DAVFU not ready */ #define CSB_OFFL 0000200 /* offline */ #define CSB_TEST 0003400 /* test mode */ -#define CSB_OVFU 0004000 /* optical VFU NI */ +#define CSB_OVFU 0004000 /* optical VFU */ #define CSB_PBIT 0010000 /* data parity bit NI */ #define CSB_NRDY 0020000 /* printer error NI */ #define CSB_LA180 0040000 /* LA180 printer NI */ @@ -120,7 +149,7 @@ #define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE) #define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL) #define CSB_RW CSB_TEST -#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\ +#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | \ CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD) /* LPBA (765404) */ @@ -141,39 +170,128 @@ /* LPCSUM/LPPDAT (765516) */ -extern d10 *M; /* main memory */ extern int32 int_req; -int32 lpcsa = 0; /* control/status A */ -int32 lpcsb = 0; /* control/status B */ -int32 lpba = 0; /* bus address */ -int32 lpbc = 0; /* byte count */ -int32 lppagc = 0; /* page count */ -int32 lprdat = 0; /* RAM data */ -int32 lpcbuf = 0; /* character buffer */ -int32 lpcolc = 0; /* column count */ -int32 lppdat = 0; /* printer data */ -int32 lpcsum = 0; /* checksum */ -int32 dvptr = 0; /* davfu pointer */ -int32 dvlnt = 0; /* davfu length */ -int32 lp20_irq = 0; /* int request */ -int32 lp20_stopioe = 0; /* stop on error */ -int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ -int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ +static int32 lpcsa = 0; /* control/status A */ +static int32 lpcsb = CSB_DVOF; /* control/status B */ +static int32 lpba = 0; /* bus address */ +static int32 lpbc = 0; /* byte count */ +static int32 lppagc = 0; /* page count */ +static int32 lprdat = 0; /* RAM data */ +static int32 lpcbuf = 0; /* character buffer */ +static int32 lpcolc = 0; /* column count */ +static int32 lppdat = 0; /* printer data */ +static int32 lpcsum = 0; /* checksum */ +static int32 dvptr = 0; /* davfu pointer */ +static int32 dvlnt = 0; /* davfu length */ +static int32 lp20_irq = 0; /* int request */ +static int32 lp20_stopioe = 0; /* stop on error */ +static int32 dvld = 0; +static int32 dvld_hold = 0; +static int32 lpi = DEFAULT_LPI; /* Printer's LPI. */ +static int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ +static int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ DEVICE lp20_dev; -t_stat lp20_rd (int32 *data, int32 pa, int32 access); -t_stat lp20_wr (int32 data, int32 pa, int32 access); -int32 lp20_inta (void); -t_stat lp20_svc (UNIT *uptr); -t_stat lp20_reset (DEVICE *dptr); -t_stat lp20_attach (UNIT *uptr, char *ptr); -t_stat lp20_detach (UNIT *uptr); -t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc); -t_bool lp20_print (int32 c); -t_bool lp20_adv (int32 c, t_bool advdvu); -t_bool lp20_davfu (int32 c); -void update_lpcs (int32 flg); +static t_stat lp20_rd (int32 *data, int32 pa, int32 access); +static t_stat lp20_wr (int32 data, int32 pa, int32 access); +static int32 lp20_inta (void); +static t_stat lp20_svc (UNIT *uptr); +static t_stat idle_svc (UNIT *uptr); +static void set_flush_timer (UNIT *uptr); +static t_stat lp20_reset (DEVICE *dptr); +static t_stat lp20_init (DEVICE *dptr); +static t_stat lp20_attach (UNIT *uptr, char *ptr); +static t_stat lp20_detach (UNIT *uptr); +static t_stat lp20_set_lpi (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat lp20_show_lpi (FILE *st, UNIT *up, int32 v, void *dp); +static t_stat lp20_set_vfu_type (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat lp20_show_vfu_type (FILE *st, UNIT *up, int32 v, void *dp); +static t_stat lp20_show_vfu (FILE *st, UNIT *up, int32 v, void *dp); +static t_stat lp20_set_tof (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_bool lp20_print (int32 c); +static t_bool lp20_adv (int32 c, t_bool advdvu); +static t_bool lp20_davfu (int32 c); +static void update_lpcs (int32 flg); +static void change_rdy (int32 setrdy, int32 clrrdy); +static int16 evenbits (int16 value); +static t_stat lp20_help (FILE *st, struct sim_device *dptr, + struct sim_unit *uptr, int32 flag, char *cptr); +static char *lp20_description (DEVICE *dptr); + +/* DEC standard VFU tape for 'optical' VFU default. + * Note that this must be <= DV_SIZE as we copy it into the DAVFU. + */ +static const int16 defaultvfu[] = { /* Generated by vfu.pl per DEC HRM */ + /* 66 line page with 6 line margin */ + 00377, /* Line 0 8 7 6 5 4 3 2 1 */ + 00220, /* Line 1 8 5 */ + 00224, /* Line 2 8 5 3 */ + 00230, /* Line 3 8 5 4 */ + 00224, /* Line 4 8 5 3 */ + 00220, /* Line 5 8 5 */ + 00234, /* Line 6 8 5 4 3 */ + 00220, /* Line 7 8 5 */ + 00224, /* Line 8 8 5 3 */ + 00230, /* Line 9 8 5 4 */ + 00264, /* Line 10 8 6 5 3 */ + 00220, /* Line 11 8 5 */ + 00234, /* Line 12 8 5 4 3 */ + 00220, /* Line 13 8 5 */ + 00224, /* Line 14 8 5 3 */ + 00230, /* Line 15 8 5 4 */ + 00224, /* Line 16 8 5 3 */ + 00220, /* Line 17 8 5 */ + 00234, /* Line 18 8 5 4 3 */ + 00220, /* Line 19 8 5 */ + 00364, /* Line 20 8 7 6 5 3 */ + 00230, /* Line 21 8 5 4 */ + 00224, /* Line 22 8 5 3 */ + 00220, /* Line 23 8 5 */ + 00234, /* Line 24 8 5 4 3 */ + 00220, /* Line 25 8 5 */ + 00224, /* Line 26 8 5 3 */ + 00230, /* Line 27 8 5 4 */ + 00224, /* Line 28 8 5 3 */ + 00220, /* Line 29 8 5 */ + 00276, /* Line 30 8 6 5 4 3 2 */ + 00220, /* Line 31 8 5 */ + 00224, /* Line 32 8 5 3 */ + 00230, /* Line 33 8 5 4 */ + 00224, /* Line 34 8 5 3 */ + 00220, /* Line 35 8 5 */ + 00234, /* Line 36 8 5 4 3 */ + 00220, /* Line 37 8 5 */ + 00224, /* Line 38 8 5 3 */ + 00230, /* Line 39 8 5 4 */ + 00364, /* Line 40 8 7 6 5 3 */ + 00220, /* Line 41 8 5 */ + 00234, /* Line 42 8 5 4 3 */ + 00220, /* Line 43 8 5 */ + 00224, /* Line 44 8 5 3 */ + 00230, /* Line 45 8 5 4 */ + 00224, /* Line 46 8 5 3 */ + 00220, /* Line 47 8 5 */ + 00234, /* Line 48 8 5 4 3 */ + 00220, /* Line 49 8 5 */ + 00264, /* Line 50 8 6 5 3 */ + 00230, /* Line 51 8 5 4 */ + 00224, /* Line 52 8 5 3 */ + 00220, /* Line 53 8 5 */ + 00234, /* Line 54 8 5 4 3 */ + 00220, /* Line 55 8 5 */ + 00224, /* Line 56 8 5 3 */ + 00230, /* Line 57 8 5 4 */ + 00224, /* Line 58 8 5 3 */ + 00220, /* Line 59 8 5 */ + 00020, /* Line 60 5 */ + 00020, /* Line 61 5 */ + 00020, /* Line 62 5 */ + 00020, /* Line 63 5 */ + 00020, /* Line 64 5 */ + 04020, /* Line 65 12 5 */ +}; /* LP data structures @@ -182,28 +300,71 @@ void update_lpcs (int32 flg); lp20_reg LPT register list */ -DIB lp20_dib = { +static DIB lp20_dib = { IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr, 1, IVCL (LP20), VEC_LP20, { &lp20_inta } }; -UNIT lp20_unit = { - UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT +/* Actual device timing varies depending on the printer. + * Printers used with the LP20 include both drum and band printers. + * Nominal speeds ranged from 200 LPM to 1250 LPM. Besides speed, + * the major variants were: Optical vs DAVFU, 64 vs. 96 character + * band/drum, and scientific vs. EDP fonts. Scientific used slashed + * Z and 0; EDP did not. All supported 132 colum output at a pitch + * of 10 CPI. Some had operator switch-selectable vertical pitches + * for either 6 or 8 LPI. Paper and ribbon are hit by a hammer onto + * the rotating drum when the desired character is in front of the + * hammer. Thus, a line that contains all the characters on a drum + * would take one full revolution to print, plus paper motion time. + * (Assuming no overstrikes.) At 100 RPM, this translates to 16.7 ms + * printing + 41 ms motion for the LP05. The math works out to 1,040 + * LPM, but the rated speeds account for slew in the margins and some + * overstrikes (most commonly underline.) One could construct data + * patterns that overlapped some paper motion with unused character + * time on the drum. So the LP10, with 14 ms line advance could + * print the alphabet using 1/2 a rotation and move the paper in the + * other half - about 50% faster than rated speed. Bands move the + * characters horizontally (similar to chain/train printers), but + * the basic timing constraints are similar. + * + * Timing for several printers: a/b is 64/96 character set value. + * LP05 LP07 LP10 LP14 + * Line advance: 41 ms 12.5 ms 14 ms 20 ms + * Slew: 20 ips 60 ips 35 ips 22.5 @8LPi/30 @6 + * Drum Rotation: 1000/600 RPM band 1800/1200 1280/857 + * Rated LPM: 230/300 1220/905 1250/925 890/650 + * Weight lb/kg 340/154 800/363 800/363 420/191 + * + * There is a variant that was designed to drive an LA180 with either + * a 7 or 8 bit parallel interface. The prints label it 'not a standard + * product'. It's not implemented in this emulation. + */ + +static UNIT lp20_idle; +static UNIT lp20_unit = { + UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT, + 0, 0, 0, 0, &lp20_idle, + }; +static UNIT lp20_idle = { + UDATA (&idle_svc, UNIT_DIS, 0), 1000000, LP20_IDLE_TIME, + 0, 0, 0, &lp20_unit, }; -REG lp20_reg[] = { +static REG lp20_reg[] = { { ORDATA (LPCSA, lpcsa, 16) }, { ORDATA (LPCSB, lpcsb, 16) }, { ORDATA (LPBA, lpba, 16) }, { ORDATA (LPBC, lpbc, 12) }, { ORDATA (LPPAGC, lppagc, 12) }, - { ORDATA (LPRDAT, lprdat, 12) }, + { ORDATA (LPRDAT, lprdat, 13) }, { ORDATA (LPCBUF, lpcbuf, 8) }, { ORDATA (LPCOLC, lpcolc, 8) }, { ORDATA (LPPDAT, lppdat, 8) }, { ORDATA (LPCSUM, lpcsum, 8) }, { ORDATA (DVPTR, dvptr, 7) }, { ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ }, + { ORDATA (DVLD, dvld, 2), REG_RO | REG_HIDDEN }, + { ORDATA (DVLDH, dvld_hold, 6), REG_RO | REG_HIDDEN }, { FLDATA (INT, int_req, INT_V_LP20) }, { FLDATA (IRQ, lp20_irq, 0) }, { FLDATA (ERR, lpcsa, CSR_V_ERR) }, @@ -212,19 +373,29 @@ REG lp20_reg[] = { { DRDATA (POS, lp20_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lp20_stopioe, 0) }, - { BRDATA (TXRAM, txram, 8, 12, TX_SIZE) }, + { BRDATA (TXRAM, txram, 8, 13, TX_SIZE) }, { BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) }, + { DRDATA (LPI, lpi, 8), REG_RO | REG_HIDDEN }, { ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO }, { ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO }, { NULL } }; -MTAB lp20_mod[] = { - { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu }, +static MTAB lp20_mod[] = { { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", &set_vec, &show_vec, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "VFU", NULL, NULL, &lp20_show_vfu, + NULL, "Display VFU tape/contents" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "VFUTYPE", "VFUTYPE={DAVFU|OPTICAL{=tapefile}}", + &lp20_set_vfu_type, &lp20_show_vfu_type, NULL, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_VALO, 0, "LPI", "LPI={6-LPI|8-LPI}", &lp20_set_lpi, &lp20_show_lpi, + NULL, "Printer vertical lines per inch" }, + { UNIT_DUMMY, 0, NULL, "TOPOFFORM", &lp20_set_tof, NULL, + NULL, "Advance to top-of-form" }, + { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu, NULL, + NULL, "Clear the VFU & Translation RAM" }, { 0 } }; @@ -233,7 +404,8 @@ DEVICE lp20_dev = { 1, 10, 31, 1, 8, 8, NULL, NULL, &lp20_reset, NULL, &lp20_attach, &lp20_detach, - &lp20_dib, DEV_DISABLE | DEV_UBUS + &lp20_dib, DEV_DISABLE | DEV_UBUS, 0, + NULL, NULL, NULL, &lp20_help, NULL, NULL, &lp20_description, }; /* Line printer routines @@ -246,17 +418,21 @@ DEVICE lp20_dev = { lp20_detach process detach */ -t_stat lp20_rd (int32 *data, int32 pa, int32 access) +static t_stat lp20_rd (int32 *data, int32 pa, int32 access) { update_lpcs (0); /* update csr's */ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ case 00: /* LPCSA */ *data = lpcsa = lpcsa & ~CSA_MBZ; + if (lpcsb & CSB_OVFU) /* Optical: no DAVFU present */ + *data &= ~CSA_DVON; break; case 01: /* LPCSB */ *data = lpcsb = lpcsb & ~CSB_MBZ; + if (lpcsb & CSB_OVFU) + *data &= ~CSB_DVOF; break; case 02: /* LPBA */ @@ -272,7 +448,11 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ break; case 05: /* LPRDAT */ - *data = lprdat = lprdat & RDAT_MASK; + *data = lprdat & RDAT_MASK; + if (evenbits(*data)) + *data |= TX_PARITY; + if (((lprdat & TX_PARITY) == 0) && (lpcsa & CSA_PAR)) /* Data invalid & parity checked? */ + *data ^= TX_PARITY; /* Invalid: Provide bad parity */ break; case 06: /* LPCOLC/LPCBUF */ @@ -287,7 +467,7 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ return SCPE_OK; } -t_stat lp20_wr (int32 data, int32 pa, int32 access) +static t_stat lp20_wr (int32 data, int32 pa, int32 access) { update_lpcs (0); /* update csr's */ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ @@ -295,13 +475,18 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ case 00: /* LPCSA */ if (access == WRITEB) data = (pa & 1)? (lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data; + /* In hardware, a write that sets GO must not change any other + * bits in CSRA due to timing restrictions. Modifying any bits in + * CSRA while GO is set "may destroy the contents of the checksum register + * and produce other undesirable effects." + */ if (data & CSA_ECLR) { /* error clear? */ lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */ lpcsb = lpcsb & ~CSB_ECLR; /* clear err */ sim_cancel (&lp20_unit); /* cancel I/O */ } if (data & CSA_INIT) /* init? */ - lp20_reset (&lp20_dev); + lp20_init (&lp20_dev); if (data & CSA_GO) { /* go set? */ if ((lpcsa & CSA_GO) == 0) { /* not set before? */ if (lpcsb & CSB_ERR) @@ -312,6 +497,10 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ } else sim_cancel (&lp20_unit); /* go clr, stop DMA */ lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW); + if (dvld && (CSA_GETFNC (lpcsa) != FNC_DVU)) { /* DVU load aborted */ + change_rdy (0, CSA_DVON); /* Mark DVU off-line and empty */ + dvlnt = 0; + } break; case 01: /* LPCSB */ @@ -334,13 +523,14 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ if (access == WRITEB) data = (pa & 1)? (lppagc & 0377) | (data << 8): (lppagc & ~0377) | data; lppagc = data & PAGC_MASK; + lpcsa &= ~CSA_PZRO; /* Note that even if at TOF, PZRO does not set */ break; case 05: /* LPRDAT */ if (access == WRITEB) data = (pa & 1)? (lprdat & 0377) | (data << 8): (lprdat & ~0377) | data; lprdat = data & RDAT_MASK; - txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */ + txram[lpcbuf & TX_AMASK] = lprdat | TX_PARITY; /* load RAM and mark valid */ break; case 06: /* LPCOLC/LPCBUF */ @@ -389,10 +579,9 @@ return SCPE_OK; } */ -t_stat lp20_svc (UNIT *uptr) +static t_stat lp20_svc (UNIT *uptr) { -int32 fnc, i, tbc, temp, txst; -int32 dvld = -2; /* must be even */ +int32 fnc, i, tbc, txst; uint16 wd10; t_bool cont; a10 ba; @@ -412,7 +601,7 @@ if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) { update_lpcs (CSA_ERR); return IORETURN (lp20_stopioe, SCPE_UNATT); } -if ((fnc == FNC_PR) && (dvlnt == 0)) { +if ((fnc == FNC_PR) && (lpcsb & CSB_DVOF)) { update_lpcs (CSA_ERR); return SCPE_OK; } @@ -430,37 +619,76 @@ for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) { /* Translation RAM load */ case FNC_RAM: /* RAM load */ - txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK; + txram[(i >> 1) & TX_AMASK] = (wd10 & TX_DMASK) | TX_PARITY; break; /* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by a start (354 to 356) and stop (357) byte pair. If the number of bytes loaded is odd, or no bytes are loaded, the DAVFU is invalid. + Thus, with DVU load mode set in CSRA, there are three states: + 0) Inactive 2) Start code seen,even byte 3) Start code seen, odd byte. + Normally, only a start or a stop code should be seen in (0), but any other + code that is received is ignored. A stop without a corresponding start is + legal, and specified to reset the current line pointer to 0 without + modifying the content of the RAM. + The DAVFU is physically in the printer, so printers with an optical + VFU see load data as normal data to be printed. The LP20 logic inhibits + the translation RAM in this mode, so any translation will not occur. + This is an unexpected condition; the OS/User should check the optical + VFU bit before attempting to load a DAVFU. */ case FNC_DVU: /* DVU load */ - if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */ - dvld = dvlnt = 0; /* reset lnt */ - else if (lpcbuf == 0357) { /* stop DVU load? */ - dvptr = 0; /* reset ptr */ - if (dvld & 1) /* if odd, invalid */ - dvlnt = 0; + if (lpcsb & CSB_OVFU) { + /* OS should not attempt to load VFU if printer has Optical VFU. + * The DAVFU is in the printer, so it will see the attempted load + * as print data. The LP20 inhibits translation. + */ + cont = lp20_print (lpcbuf); + break; } - else if (dvld == 0) { /* even state? */ - temp = lpcbuf & DV_DMASK; - dvld = 1; + if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) { /* start DVU load? */ + dvlnt = 0; /* reset lnt */ + dvld = 2; /* Load is active, even */ + if (lpcbuf == 0354) + lpi = 6; + else if (lpcbuf == 0355) + lpi = 8; } - else if (dvld == 1) { /* odd state? */ - if (dvlnt < DV_SIZE) - davfu[dvlnt++] = temp | ((lpcbuf & DV_DMASK) << 6); + else if (lpcbuf == 0357) { /* stop DVU load? */ + dvptr = 0; /* reset ptr */ dvld = 0; + if ((dvld & 1) || !VFU_LEN_VALID(dvlnt, lpi)) { /* if odd or invalid length */ + dvlnt = 0; + change_rdy (0, CSA_DVON); + } + else change_rdy(CSA_DVON, 0); + } + else if (dvld == 2) { /* even state? */ + dvld_hold = lpcbuf & DV_DMASK; + dvld = 3; + } + else if (dvld == 3) { /* odd state? */ + if (dvlnt < DV_SIZE) { + davfu[dvlnt++] = dvld_hold | ((lpcbuf & DV_DMASK) << 6); + dvld = 2; + } + else { + change_rdy (0, CSA_DVON); + dvlnt = dvld = 0; + } } break; -/* Print characters */ +/* Print characters through the translation RAM */ case FNC_PR: /* print */ lprdat = txram[lpcbuf]; /* get RAM char */ + if (((lprdat & TX_PARITY) == 0) && (lpcsa & CSA_PAR)) { /* Check for valid */ + lpcsb |= CSB_RPE; /* Declare RAM parity error */ + cont = FALSE; + break; + } txst = (TX_GETFL (lprdat) << 1) | /* get state */ ((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */ if (lprdat & TX_DELH) @@ -494,6 +722,10 @@ for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) { break; } /* end case function */ } /* end for */ +if (lpcolc == 0) + set_flush_timer (&lp20_unit); +else + sim_cancel ((UNIT *)lp20_unit.up7); lpba = ba & 0177777; lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE); lpbc = (lpbc + i) & BC_MASK; @@ -517,7 +749,7 @@ return SCPE_OK; Return TRUE to continue printing, FALSE to stop */ -t_bool lp20_print (int32 c) +static t_bool lp20_print (int32 c) { t_bool r = TRUE; int32 i, rpt = 1; @@ -530,7 +762,7 @@ if (lppdat == 012) /* LF? adv carriage */ if (lppdat == 014) /* FF? top of form */ return lp20_davfu (DV_TOF); if (lppdat == 015) /* CR? reset col cntr */ - lpcolc = 0; + lpcolc = -1; else if (lppdat == 011) { /* TAB? simulate */ lppdat = ' '; /* with spaces */ if (lpcolc >= 128) { @@ -552,35 +784,50 @@ lpcolc = lpcolc + rpt; return r; } -t_bool lp20_adv (int32 cnt, t_bool dvuadv) +static t_bool lp20_adv (int32 cnt, t_bool dvuadv) { int32 i; +int stoppc = FALSE; if (cnt == 0) return TRUE; + +if (lpcsb & CSB_DVOF) + return FALSE; + +/* This logic has changed because it did not account for the case of more than one TOF + * occuring in the advance. Consider a tape with odd/even pages, and a slew channel that + * stops on the even. If we slew from the bottom of the even, we will pass the TOF of the + * odd page and stop on the odd; seeing a second TOF. + */ + lpcolc = 0; /* reset col cntr */ -for (i = 0; i < cnt; i++) +for (i = 0; i < cnt; i++) { /* print 'n' newlines; each can complete a page */ fputc ('\n', lp20_unit.fileref); -lp20_unit.pos = ftell (lp20_unit.fileref); /* print 'n' newlines */ -if (dvuadv) /* update DAVFU ptr */ - dvptr = (dvptr + cnt) % dvlnt; -if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */ - if ((lppagc = (lppagc - 1) & PAGC_MASK)) { /* decr page cntr */ - lpcsa = lpcsa & ~CSA_PZRO; /* update status */ - return TRUE; - } - else { - lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ - return FALSE; - } + if (dvuadv) { /* update DAVFU ptr */ + dvptr = (dvptr + cnt) % dvlnt; + if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */ + lppagc = (lppagc - 1) & PAGC_MASK; /* decr page cntr */ + if (lppagc == 0) { + lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ + stoppc = TRUE; + } + } /* At TOF */ + } /* update pointer */ } +lp20_unit.pos = ftell (lp20_unit.fileref); +if (stoppc) /* Crossed one or more TOFs? */ + return FALSE; + return TRUE; } -t_bool lp20_davfu (int32 cnt) +static t_bool lp20_davfu (int32 cnt) { int i; +if (lpcsb & CSB_DVOF) + return FALSE; if (cnt > DV_MAX) /* inval chan? */ cnt = 7; for (i = 0; i < dvlnt; i++) { /* search DAVFU */ @@ -593,68 +840,120 @@ for (i = 0; i < dvlnt; i++) { /* search DAVFU */ if (lpcolc) /* TOF, need newline? */ lp20_adv (1, FALSE); fputc ('\f', lp20_unit.fileref); /* print form feed */ - lp20_unit.pos = ftell (lp20_unit.fileref); - if ((lppagc = (lppagc - 1) & PAGC_MASK)) { /* decr page cntr */ - lpcsa = lpcsa & ~CSA_PZRO; /* update status */ + lp20_unit.pos = ftell (lp20_unit.fileref); + lppagc = (lppagc - 1) & PAGC_MASK; /* decr page cntr */ + if (lppagc != 0) return TRUE; - } else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ return FALSE; } } } /* end for */ -dvlnt = 0; /* DAVFU error */ +change_rdy (0,CSA_DVON); /* Code to channel with no channel stop */ return FALSE; } /* Update LPCSA, optionally request interrupt */ -void update_lpcs (int32 flg) +static void update_lpcs (int32 flg) { if (flg) /* set int req */ lp20_irq = 1; -lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL | CSA_DVON); -lpcsb = (lpcsb | CSB_OFFL | CSB_DVOF) & ~CSB_MBZ; +lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL); +lpcsb = (lpcsb | CSB_OFFL) & ~CSB_MBZ; if (lp20_unit.flags & UNIT_ATT) { lpcsa = lpcsa | CSA_ONL; lpcsb = lpcsb & ~CSB_OFFL; } else lpcsa = lpcsa & ~CSA_DONE; -if (dvlnt) { - lpcsa = lpcsa | CSA_DVON; - lpcsb = lpcsb & ~CSB_DVOF; - } if (lpcsb & CSB_ERR) lpcsa = lpcsa | CSA_ERR; if ((lpcsa & CSA_IE) && lp20_irq) - int_req = int_req | INT_LP20; -else int_req = int_req & ~INT_LP20; + SET_INT (LP20); +else CLR_INT (LP20); return; } +/* Set and clear READY bits in csa. + * used for bits where a transition should cause an interrupt. + * also updates corresponding bits in csb. + */ +static void change_rdy (int32 setrdy, int32 clrrdy) +{ +int32 newcsa = (lpcsa | setrdy) & ~clrrdy; + +if ((newcsa ^ lpcsa) & (CSA_ONL | CSA_DVON) && !sim_is_active (&lp20_unit)) { + lp20_irq |= 1; + if (newcsa & CSA_IE) + SET_INT(LP20); + } +/* CSA_ERR is handled in update_csa */ + +if (newcsa & CSA_DVON) + lpcsb &= ~CSB_DVOF; +else + lpcsb |= CSB_DVOF; +if (newcsa & CSA_ONL) + lpcsb &= ~CSB_OFFL; +else + lpcsb |= CSB_OFFL; + +lpcsa = newcsa; +} + /* Acknowledge interrupt (clear internal request) */ -int32 lp20_inta (void) +static int32 lp20_inta (void) { lp20_irq = 0; /* clear int req */ return lp20_dib.vec; } + +/* Simulator RESET + * Note that this does not reset the printer's DAVFU or the + * translation RAM, which survive system bootstraps. + * (SET VFUCLEAR will do that.) + * + */ + t_stat lp20_reset (DEVICE *dptr) { -lpcsa = CSA_DONE; -lpcsb = 0; + /* On power-up reset, clear DAVFU & RAM. Set DAVFU off-line. */ +if (sim_switches & SWMASK ('P')) { + memset (davfu, 0, sizeof(davfu)); + memset (txram, 0, sizeof(txram)); + dvlnt = dvptr = dvld= 0; + lpcsa &= ~CSA_DVON; + lpcsb |= CSB_DVOF; + lpi = DEFAULT_LPI; +} + +return lp20_init (dptr); +} + +/* Local init does NOT initialize the DAVFU/TRANSLATION RAMs. + * They are in the printer, which reset does not reach. + */ + +t_stat lp20_init (DEVICE *dptr) +{ +lpcsa = (lpcsa & CSA_DVON) | CSA_DONE; +lpcsb = lpcsb & (CSB_OVFU | CSB_DVOF); lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */ lprdat = lppdat = lpcbuf = lpcsum = 0; lp20_irq = 0; /* clear int req */ -dvptr = 0; /* reset davfu ptr */ sim_cancel (&lp20_unit); /* deactivate unit */ +if (sim_is_active ((UNIT *)lp20_unit.up7)) { + fflush (lp20_unit.fileref); + sim_cancel ((UNIT *)lp20_unit.up7); + } update_lpcs (0); /* update status */ return SCPE_OK; } -t_stat lp20_attach (UNIT *uptr, char *cptr) +static t_stat lp20_attach (UNIT *uptr, char *cptr) { t_stat reason; @@ -663,6 +962,16 @@ if (reason == SCPE_OK) { sim_fseek (uptr->fileref, 0, SEEK_END); uptr->pos = (t_addr)sim_ftell (uptr->fileref); } +if (lpcsa & CSA_DVON) { + int i; + for (i = 0; i < dvlnt; i++) { /* Align VFU with new file */ + if (davfu[dvptr] & (1 << DV_TOF)) + break; + dvptr = (dvptr +1) % dvlnt; + } + if (!(davfu[dvptr] & (1 << DV_TOF))) /* No TOP channel -> bad VFU */ + change_rdy (0, CSA_DVON); +} if (lpcsa & CSA_ONL) /* just file chg? */ return reason; if (sim_is_active (&lp20_unit)) /* busy? no int */ @@ -671,12 +980,16 @@ else update_lpcs (CSA_MBZ); /* interrupt */ return reason; } -t_stat lp20_detach (UNIT *uptr) +static t_stat lp20_detach (UNIT *uptr) { t_stat reason; if (!(uptr->flags & UNIT_ATT)) /* attached? */ return SCPE_OK; +if (sim_is_active ((UNIT *)lp20_unit.up7)) { + fflush (lp20_unit.fileref); + sim_cancel ((UNIT *)lp20_unit.up7); +} reason = detach_unit (uptr); sim_cancel (&lp20_unit); lpcsa = lpcsa & ~CSA_GO; @@ -684,15 +997,329 @@ update_lpcs (CSA_MBZ); return reason; } -t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc) +/* Set a timer after which, if idle, the IO buffer will be flushed. + * This allows simulator users to see their output. + * The timeout is in seconds; this is problematic with sim_activate timers. + * So u3 contains the number of seconds desired, and u4 the number to go. + */ +static void set_flush_timer (UNIT *uptr) { +uptr = (UNIT *)uptr->up7; +uptr->u4 = uptr->u3; +uptr->u5 = (int32)time(NULL); +sim_cancel(uptr); +sim_activate_after (uptr, uptr->wait); +} + +static t_stat idle_svc (UNIT *uptr) +{ +if (--uptr->u4 > 0) { + sim_activate_after (uptr, uptr->wait); + return SCPE_OK; +} +uptr = (UNIT *)uptr->up7; +fflush (uptr->fileref); +return SCPE_OK; +} + +static t_stat lp20_set_vfu_type (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +char *fname, *cp; +FILE *vfile; +int sum = 0; + +if (!cptr || !*cptr) + return SCPE_ARG; + +fname = strchr (cptr, '='); +if (fname) + *fname++ = '\0'; + +for (cp = cptr; *cp; cp++) + *cp = toupper (*cp); + +if (strncmp (cptr, "DAVFU", strlen(cptr)) == 0) { /* set lp20 vfutype=davfu: Switch to DAVFU, empty */ + if (fname && *fname) + return SCPE_ARG; + if (!(lpcsb & CSB_OVFU)) /* No change */ + return SCPE_OK; + if (uptr->flags & UNIT_ATT) + return SCPE_NOATT; + + lpcsb &= ~CSB_OVFU; + change_rdy (0, CSA_DVON); + dvptr = 0; + dvlnt = 0; + return SCPE_OK; +} + +if (strncmp (cptr, "OPTICAL", strlen(cptr)) != 0) + return SCPE_ARG; + +if (!fname || !*fname) { /* set lp20 vfutype=optical */ + if ((uptr->flags & UNIT_ATT) && !(lpcsb & CSB_OVFU)) + return SCPE_NOATT; + + lpcsb |= CSB_OVFU; + change_rdy (CSA_DVON, 0); + memcpy (davfu, defaultvfu, sizeof defaultvfu); + dvlnt = sizeof (defaultvfu) / sizeof (defaultvfu[0]); + dvptr = 0; + return SCPE_OK; +} + +/* set lp20 vfutype=optical=file + * This is OK when attached, so long as not changing from DAVFU. + * Read an optical tape file. These are line-oriented ASCII files: + * # ! ; comment + * lno: [ch [ch]...] Define line lno (0-length-1 with punches in + * channel(s) ch (1-12) + * Not required to be in order, if a lno appears more than once, the entries + * are ORed. (You can't unpunch a tape.) + * The highest lno defines the VFU length. Note that there is confusion about + * whether line numbers start at one or at zero. The HRM uses 0. Some of the + * utilitites use 1. We stick with 0 here.. + */ + +if (!(lpcsb & CSB_OVFU) && (uptr->flags & UNIT_ATT)) /* Changing device out from under OS */ + return SCPE_NOATT; + +vfile = sim_fopen( fname, "r" ); +if (vfile == NULL) { + return SCPE_OPENERR; +} +memset (davfu, 0, sizeof davfu); +dvptr = dvlnt = 0; + +while (!feof(vfile)) { + int32 line, hole; + int c; + + /* Discard comments */ + c = fgetc(vfile); + if (c == EOF) + break; + if ((c == '#') || (c == ';') || (c == '!')) { + while (!feof(vfile) && (c != '\n')) + c = fgetc(vfile); + continue; + } + ungetc(c, vfile); + + /* Read a line number */ + c = fscanf (vfile, " %u:", &line); + if (c == EOF) + break; + if ((c < 1) || (line < 0) || (line >= (sizeof (davfu)/sizeof davfu[0]))) + goto fmt_err; + if (line+1 > dvlnt) + dvlnt = line+1; + + /* Read channel numbers for current line */ + while (!feof(vfile)) { + do { + c = fgetc (vfile); + } while (isspace(c) && (c != '\n')); + if ((c == '\n') || (c == EOF)) + break; + ungetc(c, vfile); + c = fscanf (vfile, "%u", &hole); + if ((c == EOF) || (c < 1) || (c > 12)) + goto fmt_err; + sum |= (davfu[line] |= 1 << (hole -1)); + } /* End of line */ + } /* EOF */ + +/* Validate VFU content */ +if (!(sum & (1 << DV_TOF))) /* Verify that at least one punch is in the TOF channel. */ + goto fmt_err; +if (!VFU_LEN_VALID(dvlnt, lpi)) /* Verify VFU has minimum number of lines */ + goto fmt_err; + +fclose(vfile); +lpcsb |= CSB_OVFU; +change_rdy (CSA_DVON, 0); +return SCPE_OK; + +fmt_err: +dvlnt = 0; +change_rdy (0, CSA_DVON); +fclose(vfile); +return SCPE_FMT; +} + +static t_stat lp20_show_vfu_type (FILE *st, UNIT *up, int32 v, void *dp) +{ +if (lpcsb & CSB_OVFU) + fprintf (st, "optical VFU"); +else + fprintf (st, "DAVFU"); + +if (lpcsa & CSA_DVON) + fprintf (st, " loaded: %u lines, %.1f in", dvlnt, (((double)dvlnt)/lpi)); +else + fprintf (st, " not ready"); + +return SCPE_OK; +} + +static t_stat lp20_set_lpi (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newlpi; + +if (uptr->flags & UNIT_ATT) + return SCPE_NOATT; + +if (!cptr || !*cptr) + newlpi = DEFAULT_LPI; +else if (!strcmp (cptr, "6") || !strcmp (cptr, "6-LPI")) + newlpi = 6; +else if (!strcmp (cptr, "8") || !strcmp (cptr, "8-LPI")) + newlpi = 8; +else + return SCPE_ARG; + +if ((lpcsa & CSA_DVON) && !VFU_LEN_VALID(dvlnt, newlpi)) + return SCPE_ARG; + +lpi = newlpi; +return SCPE_OK; +} + +static t_stat lp20_show_lpi (FILE *st, UNIT *up, int32 v, void *dp) +{ +fprintf (st, "%u LPI", lpi); + +return SCPE_OK; +} + +static t_stat lp20_show_vfu (FILE *st, UNIT *up, int32 v, void *dp) +{ +int l, c, sum; + +if (lpcsb & CSB_OVFU) + fprintf (st, "Tape"); +else + fprintf (st, "DAFVU"); + +if (lpcsb & CSB_DVOF) { + fprintf (st, " is not loaded\n"); + return SCPE_OK; + } + +fprintf (st, " contains:\n" + " 1 1 1\n" + "line 2 1 0 9 8 7 6 5 4 3 2 1\n" + "---- - - - - - - - - - - - -\n"); +sum = 0; +for (l = 0; l < dvlnt; l++) { + if ( l && !(l % 5) ) + fputc ('\n', st); + fprintf (st, "%4u", l); + for (c = DV_MAX; c >= 0; c--) + fprintf (st, " %c", (davfu[l] & (1 << c))? ((c >= 9)? 'X': '1'+c) : ' '); + fputc ('\n', st); + sum |= davfu[l]; + } + +if (!(sum & (1 << DV_TOF))) { + fprintf (st, "? No stop in channel %u (Top-of-Form)\n", DV_TOF+1); + } +if (!(sum & (1 << DV_BOF))) { + fprintf (st, "%% No stop in channel %u (Bottom-of-Form)\n", DV_BOF+1); + } + +return SCPE_OK; +} +static t_stat lp20_set_tof (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 s_lpcsa = lpcsa; +int32 s_lppagc = lppagc; + +if (cptr && *cptr) + return SCPE_ARG; + +if (!(uptr->flags & UNIT_ATT)) + return SCPE_NOATT; + +if (lpcsb & CSB_DVOF) + return SCPE_INCOMP; + +lp20_davfu (DV_TOF); +lppagc = s_lppagc; +lpcsa = s_lpcsa; + +return SCPE_OK; +} + +static int16 evenbits (int16 value) +{ +int16 even = 1; +while (value) { + even ^= 1; + value &= value-1; + } +return even; +} + +static t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc) { int i; -if (!get_yn ("Clear DAVFU? [N]", FALSE)) +if (!get_yn ("Clear DAVFU & RAM? [N]", FALSE)) return SCPE_OK; for (i = 0; i < DV_SIZE; i++) davfu[i] = 0; -dvlnt = dvptr = 0; +for (i = 0; i < TX_SIZE; i++) + txram[i] = 0; +dvlnt = dvptr = dvld= 0; +change_rdy (0, CSA_DVON); update_lpcs (0); return SCPE_OK; } + +static t_stat lp20_help (FILE *st, struct sim_device *dptr, + struct sim_unit *uptr, int32 flag, char *cptr) +{ +fprintf (st, + "The LP20 DMA line printer controller is a UNIBUS device developed by the 36-bit product line.\n" + "The controller is used in the KS10, in PDP-11 based remote stations and in the KL10 console.\n" + "Several models of line printer can be (and were) attached to the LP20; with the long lines\n" + "option, up to 100 feet from the controller. Each LP20 controls one line printer.\n\n" + "Besides DMA, the LP20 incorporates a translation RAM that can handle case translation and more\n" + "sophisticated processing, such as representing control characters as ^x and FORTRAN carriage\n" + "control. In the former case, special characters are flagged for OS attention with an interrupt.\n" + "But FORTRAN carriage control can be handled entirely by the hardware. The RAM is loaded by\n" + "the host procesor. The LP20 supports printers with the traditional paper tape VFU, which is \n" + "used to define vertical motion. It also suports the DAVFU, (direct access) which is the electronic\n" + "equivalent of the optical tape. The DAVFU is more convenient for operators, as the print spooler\n" + "changes it automatically to match the forms. The traditional paper tape was read for every line\n" + "printed. Later printers read the tape at power-up (or change) and cached the data in on-board RAM.\n" + "This reduced wear on the tape (and the operator), and provides an example of hardware emulating hardware.\n\n" + "Emulator specifics:\n" + "The emulator can be configured with either a optical or a DAVFU. When the optical VFU is configured\n" + "a default tape is provided, which is setup for a 66 line page with a 60 line printable area, and\n" + "the DEC standard channels punched. (These correspond to FORTRAN carriage control.)\n\n" + "A custom optical tape can be configured with the SET lp20 VFUTYPE=OPTICAL=filename command. This will\n" + "load an ASCII file into the VFU, which has the following format:\n" + " #. ; ! at the beginning of a line are comments, and ignored.\n" + " line: n,m,o\n" + " These lines indicate the channels to be punched in each line. That is, that the paper\n" + " motion will stop when a \"move to channel n\" command is received.\n" + " The line number is decimal, between 0 and the page length -1.\n" + " The channel number can be between 1 and 12 - although most printers supported only 1-8\n" + " Channel 0 is the TOP OF FORM channel, and must be punched in at least one line.\n\n" + " Channel 12 is the BOTTOM OF FORM channel. Some printers use this to allow completion of the\n" + " last page when PAPER OUT is detected. Paper out sensors tended to alert early.\n" + " SET LP20 VFUTYPE=DAVFU (the default) configures the LP20 for a printer with a DAVFU.\n" + "\n" + "SET LP20 TOPOFFORM advances the paper to the top of the next page by slewing to VFU channel 0, as\n" + "does the TOP OF FORM button on a physical printer.\n" + "The DAVFU and translation RAMs survive RESET unless RESET -P is used. SET LP20 CLEARVFU is\n" + "provided to clear them independently.\n"); + +return SCPE_OK; +} +static char *lp20_description (DEVICE *dptr) +{ + return "DMA Line Printer controller"; +} diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c index 623a4358..9a38ebc0 100644 --- a/PDP10/pdp10_mdfp.c +++ b/PDP10/pdp10_mdfp.c @@ -803,7 +803,7 @@ if (r->sign) { /* negate? */ if (fdvneg) { /* fdvr special? */ val[1] = ~val[1] & MMASK; /* 1's comp */ val[0] = ~val[0] & DMASK; - } + } else { /* 2's comp */ DMOVN (val); } diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index 1adab24b..e65bd9a3 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -70,10 +70,12 @@ #include "pdp10_defs.h" #include +#include #define RP_NUMDR 8 /* #drives */ #define RP_NUMWD 128 /* 36b words/sector */ #define RP_MAXFR 32768 /* max transfer */ +#define SPINUP_DLY (1000*1000) /* Spinup delay, usec */ #define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ ((double) drv_tab[d].sect))) #define MBA_RP_CTRL 0 /* RP drive */ @@ -85,7 +87,9 @@ #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ #define UNIT_M_DTYPE 7 #define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ -#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */ +#define UNIT_V_UTS (UNIT_V_UF + 5) /* Up to speed */ +#define UNIT_UTS (1u << UNIT_V_UTS) +#define UNIT_V_DUMMY (UNIT_V_UF + 6) /* dummy flag */ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define UNIT_AUTO (1 << UNIT_V_AUTO) @@ -239,8 +243,8 @@ GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs)) /* RPCC - 176736 - current cylinder */ -/* RPER2 - 176740 - error status 2 - drive unsafe conditions - unimplemented */ -/* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */ +/* RPER2 - 176740 - error status 2 - drive unsafe conditions */ +/* RPER3 - 176742 - error status 3 - more unsafe conditions */ /* RPEC1 - 176744 - ECC status 1 - unimplemented */ /* RPEC2 - 176746 - ECC status 2 - unimplemented */ @@ -331,6 +335,8 @@ extern int32 int_req; extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */ extern int32 ubcs[UBANUM]; extern UNIT cpu_unit; +extern uint32 fe_bootrh; +extern int32 fe_bootunit; int32 rpcs1 = 0; /* control/status 1 */ int32 rpwc = 0; /* word count */ @@ -622,7 +628,7 @@ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ update_rpcs (CS1_SC, drv); /* request intr */ return SCPE_OK; } -if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */ +if (reg_in_drive[j] && sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) { /* unit busy? */ set_rper (ER1_RMR, drv); /* won't write */ update_rpcs (0, drv); return SCPE_OK; @@ -650,7 +656,7 @@ switch (j) { /* decode PA<5:1> */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ cs1f = CS1_SC; /* req interrupt */ } - else if (sim_is_active (uptr)) + else if (sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) set_rper (ER1_RMR, drv); /* won't write */ else if (data & CS1_GO) { /* start op */ uptr->FUNC = GET_FNC (data); /* set func */ @@ -793,12 +799,16 @@ switch (fnc) { /* case on function */ rpda[drv] = 0; rpof[drv] = 0; /* clear offset */ case FNC_PACK: /* pack acknowledge */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ + set_rper (ER1_UNS, drv); /* unsafe */ + break; + } rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */ return; case FNC_OFFSET: /* offset mode */ case FNC_RETURN: - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ set_rper (ER1_UNS, drv); /* unsafe */ break; } @@ -811,7 +821,7 @@ switch (fnc) { /* case on function */ dc = 0; /* seek to 0 */ case FNC_SEEK: /* seek */ case FNC_SEARCH: /* search */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ set_rper (ER1_UNS, drv); /* unsafe */ break; } @@ -834,7 +844,7 @@ switch (fnc) { /* case on function */ case FNC_WCHK: /* write check */ case FNC_READ: /* read */ case FNC_READH: /* read headers */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ set_rper (ER1_UNS, drv); /* unsafe */ break; } @@ -877,6 +887,13 @@ static d10 dbuf[RP_MAXFR]; dtype = GET_DTYPE (uptr->flags); /* get drive type */ drv = (int32) (uptr - rp_dev.units); /* get drv number */ +if ((uptr->flags & UNIT_UTS) == 0) { /* Transition to up-to-speed */ + uptr->flags |= UNIT_UTS; + rpds[drv] = DS_ATA | DS_MOL | DS_DPR | DS_RDY | + ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + update_rpcs (CS1_SC, drv); + return SCPE_OK; + } rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ switch (uptr->FUNC) { /* case on function */ @@ -893,6 +910,8 @@ switch (uptr->FUNC) { /* case on function */ case FNC_UNLOAD: /* unload */ rp_detach (uptr); /* detach unit */ + rpds[drv] &= ~DS_ATA; /* Unload does not interrupt */ + update_rpcs (0, drv); break; case FNC_RECAL: /* recalibrate */ @@ -1048,7 +1067,7 @@ uptr = rp_dev.units + drv; /* get unit */ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0; else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; -if (rp_unit[drv].flags & UNIT_ATT) +if (rp_unit[drv].flags & UNIT_UTS) rpds[drv] = rpds[drv] | DS_MOL; else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); if (rper1[drv] | rper2[drv] | rper3[drv]) @@ -1057,15 +1076,17 @@ else rpds[drv] = rpds[drv] & ~DS_ERR; rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; rpcs1 = rpcs1 | (uptr->FUNC << CS1_V_FNC); -if (sim_is_active (uptr)) +if (sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) rpcs1 = rpcs1 | CS1_GO; if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC; else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC; for (i = 0; i < RP_NUMDR; i++) { - if (rpds[i] & DS_ATA) + if (rpds[i] & DS_ATA) { rpcs1 = rpcs1 | CS1_SC; + break; + } } if (rpiff || ((rpcs1 & CS1_SC) && (rpcs1 & CS1_DONE) && (rpcs1 & CS1_IE))) int_req = int_req | INT_RP; @@ -1096,14 +1117,23 @@ rpiff = 0; /* clear CSTB INTR */ int_req = int_req & ~INT_RP; /* clear intr req */ for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; - sim_cancel (uptr); uptr->CYL = uptr->FUNC = 0; if (uptr->flags & UNIT_ATT) - rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); - else if (uptr->flags & UNIT_DIS) - rpds[i] = 0; - else rpds[i] = DS_DPR; + if (uptr->flags & UNIT_UTS) { + sim_cancel (uptr); + rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | + ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + } else { + if (!sim_is_active (uptr)) + sim_activate_after (uptr, SPINUP_DLY); + rpds[i] = DS_DPR | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + } + else { + sim_cancel (uptr); + if (uptr->flags & UNIT_DIS) + rpds[i] = 0; + else rpds[i] = DS_DPR; + } rper1[i] = 0; rper2[i] = 0; rper3[i] = 0; @@ -1123,19 +1153,16 @@ return SCPE_OK; t_stat rp_attach (UNIT *uptr, char *cptr) { -int32 drv, i, p; +int32 i, p; t_stat r; uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); -rper1[drv] = 0; -update_rpcs (CS1_SC, drv); - +sim_cancel (uptr); +uptr->flags &= ~UNIT_UTS; +sim_activate_after (uptr, SPINUP_DLY); if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ return SCPE_OK; if ((p = sim_fsize (uptr->fileref)) == 0) @@ -1147,6 +1174,7 @@ for (i = 0; drv_tab[i].sect != 0; i++) { return SCPE_OK; } } +/* File is larger than max known disk. This should probably fail. */ return SCPE_OK; } @@ -1163,12 +1191,14 @@ rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) | DS_ATA; if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ - rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ - if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ - rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */ + if (uptr->flags & UNIT_UTS) { + rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ + if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ + rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */ + } } -if (!sim_is_running) /* from console? */ - update_rpcs (CS1_SC, drv); /* request intr */ +uptr->flags &= ~UNIT_UTS; +update_rpcs (0, drv); /* request intr */ return detach_unit (uptr); } @@ -1184,111 +1214,164 @@ uptr->capac = drv_tab[dtype].size; return SCPE_OK; } -/* Device bootstrap */ +/* Device bootstrap + * The DEC and ITS versions are word-for-word identical, except that + * the DEC RDIO/WRIO are replaced by IORDQ and IOWRQ. This is hand + * assembled code, so please always make changes in both. + * Due to a typo in the KS Console rom, block 010 is read for the + * alternate HOM block. The correct block is 012. For compatibiliy, + * we will do what the hardware did first, what's right if it fails (as it will). + */ #define BOOT_START 0377000 /* start */ #define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10)) static const d10 boot_rom_dec[] = { - INT64_C(0515040000001), /* boot:hrlzi 1,1 ; uba # */ + INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # */ INT64_C(0201000140001), /* movei 0,140001 ; vld,fst,pg 1 */ INT64_C(0713001000000)+(IOBA_UBMAP+1 & RMASK), /* wrio 0,763001(1); set ubmap */ - INT64_C(0435040000000)+(IOBA_RP & RMASK), /* iori 1,776700 ; rh addr */ - INT64_C(0202040000000)+FE_RHBASE, /* movem 1,FE_RHBASE */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ INT64_C(0713001000010), /* wrio 0,10(1) ; ->RPCS2 */ + INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ + INT64_C(0713241000010), /* wrio 5,10(1) ; select ->RPCS2 */ + + INT64_C(0712001000012), /*10 rdio 0,12(1) ; RPDS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377010), /* jrst .-3 ; wait */ + INT64_C(0201000000377), /* movei 0,377 ; All units */ + INT64_C(0713001000016), /* wrio 0,16(1) ; Clear on-line attns */ INT64_C(0201000000021), /* movei 0,21 ; preset */ INT64_C(0713001000000), /* wrio 0,0(1) ; ->RPCS1 */ - INT64_C(0201100000001), /* movei 2,1 ; blk #1 */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ + + INT64_C(0201100000001), /*20 movei 2,1 ; blk #1 */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ INT64_C(0204140001000), /* movs 3,1000 ; id word */ INT64_C(0306140505755), /* cain 3,sixbit /HOM/ */ - INT64_C(0254000377023), /* jrst .+6 ; match */ + INT64_C(0254000377032), /* jrst pg ; match */ INT64_C(0201100000010), /* movei 2,10 ; blk #10 */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ INT64_C(0204140001000), /* movs 3,1000 ; id word */ - INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ - INT64_C(0254200377022), /* halt . ; inv home */ - INT64_C(0336100001103), /* skipn 2,1103 ; pg of ptrs */ - INT64_C(0254200377024), /* halt . ; inv ptr */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ + + INT64_C(0302140505755), /*30 caie 3,sixbit /HOM/ */ + INT64_C(0254000377061), /* jrst alt2 ; inv home */ + INT64_C(0336100001103), /* pg: skipn 2,1103 ; pg of ptrs */ + INT64_C(0254200377033), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ INT64_C(0336100001004), /* skipn 2,1004 ; mon boot */ - INT64_C(0254200377027), /* halt . ; inv ptr */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ - INT64_C(0254000001000), /* jrst 1000 ; start */ - INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt */ - INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ + INT64_C(0254200377036), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + + INT64_C(0254000001000), /*40 jrst 1000 ; start */ + INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt 1P = -512*2 */ + INT64_C(0201200004000), /* movei 4,4000 ; 11 addr => M[1000] */ INT64_C(0200300000002), /* move 6,2 */ INT64_C(0242300777750), /* lsh 6,-24. ; cyl */ INT64_C(0713141000002), /* wrio 3,2(1) ; ->RPWC */ INT64_C(0713201000004), /* wrio 4,4(1) ; ->RPBA */ INT64_C(0713101000006), /* wrio 2,6(1) ; ->RPDA */ - INT64_C(0713241000010), /* wrio 5,10(1) ; ->RPCS2 */ - INT64_C(0713301000034), /* wrio 6,34(1) ; ->RPDC */ + + INT64_C(0713301000034), /*50 wrio 6,34(1) ; ->RPDC */ INT64_C(0201000000071), /* movei 0,71 ; read+go */ INT64_C(0713001000000), /* wrio 0,0(1) ; ->RPCS1 */ INT64_C(0712341000000), /* rdio 7,0(1) ; read csr */ INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377046), /* jrst .-2 ; loop */ + INT64_C(0254000377053), /* jrst .-2 ; loop */ INT64_C(0602340100000), /* trne 7,100000 ; test err */ - INT64_C(0254200377052), /* halt */ - INT64_C(0254017000000), /* jrst 0(17) ; return */ + INT64_C(0254200377057), /* halt . */ + + INT64_C(0254017000000), /*60 jrst 0(17) ; return */ + INT64_C(0201100000012), /*alt2: movei 2,10. ; blk #10. */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ + INT64_C(0254200377065), /* halt . ; inv home */ + INT64_C(0254000377032), /* jrst pg ; Read ptrs */ }; static const d10 boot_rom_its[] = { - INT64_C(0515040000001), /* boot:hrlzi 1,1 ; uba # */ + INT64_C(0510040000001)+FE_RHBASE, /* boot:hllzi 1,FE_RHBASE ; uba # */ INT64_C(0201000140001), /* movei 0,140001 ; vld,fst,pg 1 */ INT64_C(0715000000000)+(IOBA_UBMAP+1 & RMASK), /* iowrq 0,763001 ; set ubmap */ - INT64_C(0435040000000)+(IOBA_RP & RMASK), /* iori 1,776700 ; rh addr */ - INT64_C(0202040000000)+FE_RHBASE, /* movem 1,FE_RHBASE */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ INT64_C(0715001000010), /* iowrq 0,10(1) ; ->RPCS2 */ + INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ + INT64_C(0715241000010), /* iowrq 5,10(1) ; ->RPCS2 */ + + INT64_C(0711001000012), /*10 iordq 0,12(1) ; RPDS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377010), /* jrst .-3 ; wait */ + INT64_C(0201000000377), /* movei 0,377 ; All units */ + INT64_C(0715001000016), /* iowrq 0,16(1) ; Clear on-line attns */ INT64_C(0201000000021), /* movei 0,21 ; preset */ INT64_C(0715001000000), /* iowrq 0,0(1) ; ->RPCS1 */ - INT64_C(0201100000001), /* movei 2,1 ; blk #1 */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ + + INT64_C(0201100000001), /*20 movei 2,1 ; blk #1 */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ INT64_C(0204140001000), /* movs 3,1000 ; id word */ INT64_C(0306140505755), /* cain 3,sixbit /HOM/ */ - INT64_C(0254000377023), /* jrst .+6 ; match */ + INT64_C(0254000377032), /* jrst pg ; match */ INT64_C(0201100000010), /* movei 2,10 ; blk #10 */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ INT64_C(0204140001000), /* movs 3,1000 ; id word */ - INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ - INT64_C(0254200377022), /* halt . ; inv home */ - INT64_C(0336100001103), /* skipn 2,1103 ; pg of ptrs */ - INT64_C(0254200377024), /* halt . ; inv ptr */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ + + INT64_C(0302140505755), /*30 caie 3,sixbit /HOM/ */ + INT64_C(0254000377061), /* jrst alt2 ; inv home */ + INT64_C(0336100001103), /* pg: skipn 2,1103 ; pg of ptrs */ + INT64_C(0254200377033), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ INT64_C(0336100001004), /* skipn 2,1004 ; mon boot */ - INT64_C(0254200377027), /* halt . ; inv ptr */ - INT64_C(0265740377032), /* jsp 17,rdbl ; read */ - INT64_C(0254000001000), /* jrst 1000 ; start */ - INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt */ + INT64_C(0254200377036), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + + INT64_C(0254000001000), /*40 jrst 1000 ; start */ + INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt 1P = -512 *2 */ INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ INT64_C(0200300000002), /* move 6,2 */ INT64_C(0242300777750), /* lsh 6,-24. ; cyl */ INT64_C(0715141000002), /* iowrq 3,2(1) ; ->RPWC */ INT64_C(0715201000004), /* iowrq 4,4(1) ; ->RPBA */ INT64_C(0715101000006), /* iowrq 2,6(1) ; ->RPDA */ - INT64_C(0715241000010), /* iowrq 5,10(1) ; ->RPCS2 */ - INT64_C(0715301000034), /* iowrq 6,34(1) ; ->RPDC */ + + INT64_C(0715301000034), /*50 iowrq 6,34(1) ; ->RPDC */ INT64_C(0201000000071), /* movei 0,71 ; read+go */ INT64_C(0715001000000), /* iowrq 0,0(1) ; ->RPCS1 */ INT64_C(0711341000000), /* iordq 7,0(1) ; read csr */ INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377046), /* jrst .-2 ; loop */ + INT64_C(0254000377053), /* jrst .-2 ; loop */ INT64_C(0602340100000), /* trne 7,100000 ; test err */ - INT64_C(0254200377052), /* halt */ - INT64_C(0254017000000), /* jrst 0(17) ; return */ + INT64_C(0254200377057), /* halt */ + + INT64_C(0254017000000), /*60 jrst 0(17) ; return */ + INT64_C(0201100000012), /* alt2:movei 2,10. ; blk #10. */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ + INT64_C(0254200377065), /* halt . ; inv home */ + INT64_C(0254000377032), /* jrst pg ; Read ptrs */ }; t_stat rp_boot (int32 unitno, DEVICE *dptr) { size_t i; extern a10 saved_PC; +UNIT *uptr; + +unitno &= CS2_M_UNIT; +uptr = rp_dev.units + unitno; +if (!(uptr->flags & UNIT_ATT)) + return SCPE_NOATT; + +M[FE_RHBASE] = fe_bootrh = rp_dib.ba; +M[FE_UNIT] = fe_bootunit = unitno; + +assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); + +M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0); -M[FE_UNIT] = unitno & CS2_M_UNIT; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; saved_PC = BOOT_START; diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 48748f5a..b8c25aff 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -110,6 +110,7 @@ const char *sim_stop_messages[] = { "Nested XCT limit exceeded", "Invalid I/O controller", "Address stop", + "Console FE halt", "Panic stop" }; diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index c3d8b79d..d5de0a21 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -41,42 +41,102 @@ #include "pdp10_defs.h" #include +/* The KS timer works off a 4.100 MHz (243.9024 nsec) oscillator that + * is independent of all other system timing. + * + * Two pieces of timekeeping hardware are exposed to the OS. + * o The interval timer, which can interrupt at a programmed interval. + * o The timebase, which records time (71 bits). + * + * The clock is architecturally readable in units of 243.9024 nsec via + * the timebase. The implementation is somewhat different. + * + * The instructions that update the clocks specify time in these units. + * + * However, both timekeepers are incremented by the microcode when + * a 12 bit counter overflows; e.g. at a period of 999.0244 usec. + * Thus, the granularity of timer interrupts is approximately 1 msec. + * + * The OS programs the interval timer to interrupt as though the + * the 12 least significant bits mattered. Thus, for a (roughly) + * 1 msec interval, it would program 1 * 4096 into the interval timer. + * The sign bit is not used, so 35-12 = 23 bits for the maximum interval, + * which is 139.674 minutes. If any of the least significant bits + * are non-zero, the interval is extended by 1 * 4096 counts. + * + * The timer merely sets the INTERVAL DONE flag in the APR flags. + * Whether that actually causes an interrupt is controlled by the + * APR interrupt enable for the flag and by the PI system. + * + * The flag is readable as an APR condition by RDAPR, and CONSO/Z APR,. + * The flag is cleared by WRAPR 1b22!1b30 (clear, count done). + * + * The timebase is maintained with the 12 LSB zero in a workspace + * register. When read by the OS, the actual value of the 10 MSB of + * the hardware counter is inserted into those bits, providing increased + * resolution. Although the system reference manual says otherwise, the + * two LSB of the counter are read as zero by the microcode (DPM2), so + * bits <70:71> of the timebase are also read as zero by software. + * + * When the OS sets the timebase, the 12 LSB that it supplies are ignored. + * + * The timebase is typically used for accurate time of day and CPU runtime + * accounting. The simulator adjusts the equivalent of the 12-bit counter, + * so CPU time will reflect simulator wall clock, not simulated machine cycles. + * Since time of day must be accurate, this may result in the OS reporting + * CPU times that are unrealistically faster - or slower - than on the + * real hardware. + * + * This module also implements the TCU, a battery backed-up TOY clock + * that was supported by TOPS-10, but not sold by DEC. + */ + /* Invariants */ #define TIM_HW_FREQ 4100000 /* 4.1Mhz */ -#define TIM_HWRE_MASK 07777 +#define TIM_HWRE_MASK 07777 /* Timer field of timebase */ +#define TIM_BASE_RAZ 03 /* Timer bits read as zero by ucode */ #define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */ #define UNIT_Y2K (1u << UNIT_V_Y2K) +#define TIM_TMXR_FREQ 60 /* Target frequency (HZ) for tmxr polls */ + + /* Estimate of simulator instructions/sec for initialization and fixed timing. + * This came from prior magic constant of 8000 at 60 tics/sec. + * The machine was marketed as ~ 300KIPs, which would imply 3 usec/instr. + * So 8,000 instructions should take ~24 msec. This would indicate that + * the simulator from which this came was ~1.4 x the speed of the real + * hardware. Current milage will vary. + */ +#define TIM_WAIT_IPS 480000 + /* Clock mode TOPS-10/ITS */ -#define TIM_TPS_T10 60 -#define TIM_WAIT_T10 8000 -#define TIM_MULT_T10 1 -#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10) +#define TIM_TPS_T10 60 /* Initial frequency guess for TOPS-10 (close, not exact) */ +#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10) /* ITS PC sampling and user runtime interval */ /* Clock mode TOPS-20/KLAD */ -#define TIM_TPS_T20 1001 -#define TIM_WAIT_T20 500 -#define TIM_MULT_T20 16 +#define TIM_TPS_T20 1000 /* Initial estimate for TOPS-20 - 1msec seems fast? */ /* Probability function for TOPS-20 idlelock */ #define PROB(x) (((rand() * 100) / RAND_MAX) >= (x)) -d10 tim_base[2] = { 0, 0 }; /* 71b timebase */ -d10 tim_ttg = 0; /* time to go */ -d10 tim_period = 0; /* period */ +static d10 tim_base[2] = { 0, 0 }; /* 71b timebase */ +static d10 tim_interval = 0; /* value programmed into the clock */ +static d10 tim_period = 0; /* period in HW ticks adjusted for non-zero LSBs */ +static d10 tim_new_period = 0; /* period for the next interval */ +static int32 tim_mult; /* Multiple of interval timer period at which tmxr is polled */ + d10 quant = 0; /* ITS quantum */ -int32 tim_mult = TIM_MULT_T10; /* tmxr poll mult */ -int32 tim_t20_prob = 33; /* TOPS-20 prob */ +static int32 tim_t20_prob = 33; /* TOPS-20 prob */ -/* Exported variables */ +/* Exported variables - initialized by set CPU model and reset */ -int32 clk_tps = TIM_TPS_T10; /* clock ticks/sec */ -int32 tmr_poll = TIM_WAIT_T10; /* clock poll */ -int32 tmxr_poll = TIM_WAIT_T10 * TIM_MULT_T10; /* term mux poll */ +int32 clk_tps; /* Interval clock ticks/sec */ +int32 tmr_poll; /* SimH instructions/clock service */ +int32 tmxr_poll; /* SimH instructions/term mux poll */ extern int32 apr_flg, pi_act; extern UNIT cpu_unit; @@ -85,10 +145,11 @@ extern a10 pager_PC; extern int32 t20_idlelock; DEVICE tim_dev; -t_stat tcu_rd (int32 *data, int32 PA, int32 access); -t_stat tim_svc (UNIT *uptr); -t_stat tim_reset (DEVICE *dptr); -void tim_incr_base (d10 *base, d10 incr); +static t_stat tcu_rd (int32 *data, int32 PA, int32 access); +static t_stat tim_svc (UNIT *uptr); +static t_stat tim_reset (DEVICE *dptr); +static t_bool update_interval (d10 new_interval); +static void tim_incr_base (d10 *base, d10 incr); extern d10 Read (a10 ea, int32 prv); extern d10 ReadM (a10 ea, int32 prv); @@ -106,11 +167,10 @@ extern t_stat wr_nop (int32 data, int32 PA, int32 access); DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 }; -UNIT tim_unit = { UDATA (&tim_svc, UNIT_IDLE, 0), TIM_WAIT_T10 }; +static UNIT tim_unit = { UDATA (&tim_svc, UNIT_IDLE, 0), 0 }; -REG tim_reg[] = { +static REG tim_reg[] = { { BRDATA (TIMEBASE, tim_base, 8, 36, 2) }, - { ORDATA (TTG, tim_ttg, 36) }, { ORDATA (PERIOD, tim_period, 36) }, { ORDATA (QUANT, quant, 36) }, { DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT }, @@ -122,7 +182,7 @@ REG tim_reg[] = { { NULL } }; -MTAB tim_mod[] = { +static MTAB tim_mod[] = { { UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL }, { UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL }, { MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL, @@ -140,26 +200,53 @@ DEVICE tim_dev = { /* Timer instructions */ -/* Timer - if the timer is running at less than hardware frequency, - need to interpolate the value by calculating how much of the current - clock tick has elapsed, and what that equates to in msec. */ +/* Timebase - the timer is always running at less than hardware frequency, + * need to interpolate the value by calculating how much of the current + * clock tick has elapsed, and what that equates to in sysfreq units. + */ t_bool rdtim (a10 ea, int32 prv) { d10 tempbase[2]; +int32 used; +d10 incr; -ReadM (INCA (ea), prv); /* check 2nd word */ tempbase[0] = tim_base[0]; /* copy time base */ tempbase[1] = tim_base[1]; -if (tim_mult != TIM_MULT_T20) { /* interpolate? */ - int32 used; - d10 incr; - used = tmr_poll - (sim_activate_time (&tim_unit) - 1); - incr = (d10) (((double) used * TIM_HW_FREQ) / - ((double) tmr_poll * (double) clk_tps)); - tim_incr_base (tempbase, incr); - } -tempbase[0] = tempbase[0] & ~((d10) TIM_HWRE_MASK); /* clear low 12b */ + +/* used = time remaining in this service interval (instructions) + * poll = instructions in the whole service interval. + * incr = fraction of interval consumed * HW ticks per interval. + * Thus, incr is approximate number of HW ticks to add to the timebase + * value returned. This does NOT update the timebase. + */ +used = tmr_poll - (sim_activate_time (&tim_unit) - 1); +incr = (d10) (((double) used * TIM_HW_FREQ) / + ((double) tmr_poll * (double) tim_period)); +tim_incr_base (tempbase, incr); + +/* Although the two LSB of the counter contribute carry to the + * value, they are read as zero by microcode, and thus cleared here. + * + * The reason that these bits are forced to zero in the hardware is + * that the counter is in a different clock domain from the microcode. + * To make the domain crossing, the microcode reads the counter + * until two consecutive values match. + * + * Since the microcode cycle time is 300 nsec, the LSBs of the + * counter run too fast (244 nsec) for the strategy to work. + * Ignoring the two LSB ensures that the value can't change any + * faster than ~976 nsec, which guarantees a stable value can be + * obtained in at most three attempts. + */ +tempbase[1] &= ~((d10) TIM_BASE_RAZ); + +/* If the destination is arranged so that the first word is OK, but + * the second pagefaults, the value will be half-written. As we + * expect the PFH to restart the instruction, the both halves will + * be written the second time. We could read and write back both + * halves to avoid this, but the hardware doesn't seem to either. + */ Write (ea, tempbase[0], prv); Write (INCA(ea), tempbase[1], prv); return FALSE; @@ -168,39 +255,71 @@ return FALSE; t_bool wrtim (a10 ea, int32 prv) { tim_base[0] = Read (ea, prv); -tim_base[1] = CLRS (Read (INCA (ea), prv)); +tim_base[1] = CLRS (Read (INCA (ea), prv) & ~((d10) TIM_HWRE_MASK)); return FALSE; } t_bool rdint (a10 ea, int32 prv) { -Write (ea, tim_period, prv); +Write (ea, tim_interval, prv); return FALSE; } +/* write a new interval timer period (in timer ticks). + * This does not clear the harware counter, so the first + * completion can come up to ~1 msc later than the new + * period. + */ + t_bool wrint (a10 ea, int32 prv) { -tim_period = Read (ea, prv); -tim_ttg = tim_period; +tim_interval = CLRS (Read (ea, prv)); +return update_interval (tim_interval); +} + +static t_bool update_interval (d10 new_interval) +{ +tim_new_period = CLRS (new_interval + ((new_interval & TIM_HWRE_MASK)? 010000 : 0)); +if (!(tim_new_period & ~TIM_HWRE_MASK)) + tim_new_period = 010000; + +clk_tps = (int32) (0.5 + ( ((double)TIM_HW_FREQ) / (double)tim_new_period )); + +/* tmxr is polled every tim_mult clks. Compute the divisor matching the target. */ + +tim_mult = (clk_tps <= TIM_TMXR_FREQ)? 1 : ((clk_tps + (TIM_TMXR_FREQ-1)) / TIM_TMXR_FREQ); + +/* Estimate instructions/tick for fixed timing */ + +tim_unit.wait = TIM_WAIT_IPS / clk_tps; + +tmxr_poll = tim_unit.wait * tim_mult; + +/* The next tim_svc will update the activation time. + * + */ return FALSE; } -/* Timer service - the timer is only serviced when the 'ttg' register - has reached 0 based on the expected frequency of clock interrupts. */ +/* Timer service - the timer is only serviced when the interval + * programmed in tim_period by wrint expires. If the interval + * changes, the timebase update is based on the previous interval. + * The interval calibration is based on what the new interval will be. + */ -t_stat tim_svc (UNIT *uptr) +static t_stat tim_svc (UNIT *uptr) { if (cpu_unit.flags & UNIT_KLAD) /* diags? */ tmr_poll = uptr->wait; /* fixed clock */ else tmr_poll = sim_rtc_calb (clk_tps); /* else calibrate */ sim_activate (uptr, tmr_poll); /* reactivate unit */ tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ -tim_incr_base (tim_base, tim_period); /* incr time base */ -tim_ttg = tim_period; /* reload */ +tim_incr_base (tim_base, tim_period); /* incr time base based on period of expired interval */ +tim_period = tim_new_period; /* If interval has changed, update period */ apr_flg = apr_flg | APRF_TIM; /* request interrupt */ if (Q_ITS) { /* ITS? */ if (pi_act == 0) - quant = (quant + TIM_ITS_QUANT) & DMASK; + quant = (quant + TIM_ITS_QUANT) & DMASK; if (TSTS (pcst)) { /* PC sampling? */ WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */ pcst = AOB (pcst); /* add 1,,1 */ @@ -211,7 +330,7 @@ else if (t20_idlelock && PROB (100 - tim_t20_prob)) return SCPE_OK; } -void tim_incr_base (d10 *base, d10 incr) +static void tim_incr_base (d10 *base, d10 incr) { base[1] = base[1] + incr; /* add on incr */ base[0] = base[0] + (base[1] >> 35); /* carry to high */ @@ -222,12 +341,28 @@ return; /* Timer reset */ -t_stat tim_reset (DEVICE *dptr) +static t_stat tim_reset (DEVICE *dptr) { sim_register_clock_unit (&tim_unit); /* declare clock unit */ -tim_period = 0; /* clear timer */ -tim_ttg = 0; + +tim_base[0] = tim_base[1] = 0; /* clear timebase (HW does) */ +/* HW does not initialize the interval timer, so the rate at which the timer flag + * sets is random. No sensible user would enable interrupts or check the flag without + * setting an interval. The timebase is intialized to zero by microcode intialization. + * It increments based on the overflow, so it would be reasonable for a user to just + * read it twice and subtract the values to determine elapsed time. + * + * Simply to keep the simulator overhead down until the interval timer is initialized + * by the OS or diagnostic, we will set the internal interval to ~17 msec here. + * This allows the service routine to increment the timebase, and gives RDTIME an + * baseline for its interpolation. + */ +tim_interval = 0; +clk_tps = 60; +update_interval(17*4096); + apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ + tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */ sim_activate (&tim_unit, tmr_poll); /* activate unit */ tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ @@ -240,27 +375,32 @@ t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc) { if (val & (UNIT_T20|UNIT_KLAD)) { clk_tps = TIM_TPS_T20; - uptr->wait = TIM_WAIT_T20; - tmr_poll = TIM_WAIT_T20; - tim_mult = TIM_MULT_T20; + update_interval(((d10)(1000*4096))/clk_tps); + tmr_poll = tim_unit.wait; uptr->flags = uptr->flags | UNIT_Y2K; } else { clk_tps = TIM_TPS_T10; - uptr->wait = TIM_WAIT_T10; - tmr_poll = TIM_WAIT_T10; - tim_mult = TIM_MULT_T10; + update_interval (((d10)(1000*4096))/clk_tps); + tmr_poll = tim_unit.wait; if (Q_ITS) uptr->flags = uptr->flags | UNIT_Y2K; else uptr->flags = uptr->flags & ~UNIT_Y2K; } -tmxr_poll = tmr_poll * tim_mult; return SCPE_OK; } -/* Time of year clock */ +/* Time of year clock + * + * The hardware clock was never sold by DEC, but support for it exists + * in TOPS-10. Code was also available for RSX20F to read and report the + * to the OS via its20F's SETSPD task. This implements only the read functions. + * + * The manufacturer's manual can be found at + * http://bitsavers.trailing-edge.com/pdf/digitalPathways/tcu-150.pdf + */ -t_stat tcu_rd (int32 *data, int32 PA, int32 access) +static t_stat tcu_rd (int32 *data, int32 PA, int32 access) { time_t curtim; struct tm *tptr; diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index e33e8884..eb0cd890 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -92,6 +92,7 @@ #include "pdp10_defs.h" #include "sim_tape.h" +#include #define TU_NUMFM 1 /* #formatters */ #define TU_NUMDR 8 /* #drives */ @@ -99,6 +100,9 @@ #define UDENS u4 /* unit density */ #define UD_UNK 0 /* unknown */ #define MT_MAXFR (1 << 16) /* max data buf */ +#define TU_STATEFLAGS u5 /* Simulator state flags */ +#define TUS_ATTPENDING 0000001 /* Attach pending */ +#define SPINUPDLY 100*1000 /* 100 msec */ /* MTCS1 - 172440 - control/status 1 */ @@ -665,13 +669,18 @@ switch (fnc) { /* case on function */ tuer = 0; /* clear errors */ tutc = tutc & ~TC_FCS; /* clear fc status */ tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); - sim_cancel (uptr); /* reset drive */ + if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING)) + sim_cancel (uptr); /* stop motion, not on-line delay */ uptr->USTAT = 0; case FNC_NOP: tucs1 = tucs1 & ~CS1_GO; /* no operation */ return; case FNC_RIP: /* read-in preset */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ + set_tuer (ER_UNS); + break; + } tutc = TC_RIP; /* density = 800 */ sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ tu_unit[0].USTAT = 0; @@ -680,7 +689,7 @@ switch (fnc) { /* case on function */ return; case FNC_UNLOAD: /* unload */ - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -692,7 +701,7 @@ switch (fnc) { /* case on function */ return; case FNC_REWIND: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -703,7 +712,7 @@ switch (fnc) { /* case on function */ return; case FNC_SPACEF: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -715,7 +724,7 @@ switch (fnc) { /* case on function */ goto GO_XFER; case FNC_SPACER: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -728,7 +737,7 @@ switch (fnc) { /* case on function */ case FNC_WREOF: /* write tape mark */ case FNC_ERASE: /* erase */ - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -762,7 +771,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKF: /* wchk = read */ case FNC_READF: /* read */ DATA_XFER: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -807,6 +816,17 @@ t_mtrlnt tbc; t_stat st, r = SCPE_OK; drv = (int32) (uptr - tu_dev.units); /* get drive # */ + +/* Set MOL for a delayed attach */ +if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) { + uptr->TU_STATEFLAGS &= ~TUS_ATTPENDING; /* Allow transition to on-line */ + tufs = tufs | FS_ATA | FS_SSC; /* set attention */ + if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ + tufs = tufs | FS_SAT; /* set slave attn */ + update_tucs (CS1_SC, drv); /* update status */ + return SCPE_OK; +} + if (uptr->USTAT & FS_REW) { /* rewind or unload? */ sim_tape_rewind (uptr); /* rewind tape */ uptr->USTAT = 0; /* clear status */ @@ -1019,17 +1039,21 @@ if ((flag & ~tucs1) & CS1_DONE) /* DONE 0 to 1? */ tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ if (GET_FMTR (tucs2) == 0) { /* formatter present? */ tufs = (tufs & ~FS_DYN) | FS_FPR; - if (tu_unit[drv].flags & UNIT_ATT) { - tufs = tufs | FS_MOL | tu_unit[drv].USTAT; - if (tu_unit[drv].UDENS == TC_1600) - tufs = tufs | FS_PE; - if (sim_tape_wrp (&tu_unit[drv])) - tufs = tufs | FS_WRL; - if (!act) { - if (sim_tape_bot (&tu_unit[drv])) - tufs = tufs | FS_BOT; - if (sim_tape_eot (&tu_unit[drv])) - tufs = tufs | FS_EOT; + if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line timer running? */ + act = 0; /* Not a tape motion op */ + else { + if (tu_unit[drv].flags & UNIT_ATT) { + tufs = tufs | FS_MOL | tu_unit[drv].USTAT; + if (tu_unit[drv].UDENS == TC_1600) + tufs = tufs | FS_PE; + if (sim_tape_wrp (&tu_unit[drv])) + tufs = tufs | FS_WRL; + if (!act) { + if (sim_tape_bot (&tu_unit[drv])) + tufs = tufs | FS_BOT; + if (sim_tape_eot (&tu_unit[drv])) + tufs = tufs | FS_EOT; + } } } if (tuer) @@ -1139,7 +1163,11 @@ int_req = int_req & ~INT_TU; /* clear interrupt */ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ uptr = tu_dev.units + u; sim_tape_reset (uptr); /* clear pos flag */ - sim_cancel (uptr); /* cancel activity */ + if (!uptr->TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line must survive massbus clear */ + sim_cancel (uptr); /* cancel activity */ + else if (!sim_is_active(uptr) ) + sim_activate_after(uptr, SPINUPDLY); + uptr->USTAT = 0; } if (xbuf == NULL) @@ -1161,10 +1189,20 @@ if (r != SCPE_OK) return r; uptr->USTAT = 0; /* clear unit status */ uptr->UDENS = UD_UNK; /* unknown density */ +/* Delay setting MOL since we may have just detached a previous file. + * In that case, the OS must see MOL clear, so that it will know that the + * drive was off-line. This ensures that the OS will detect a tape change. + * 100 msec should suffice - though a real operator would take longer! + * Here, we ensure that the off-line transition from detach causes an attention + * interrupt. The on-line transition will happen later. + */ tufs = tufs | FS_ATA | FS_SSC; /* set attention */ if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ tufs = tufs | FS_SAT; /* set slave attn */ +uptr->TU_STATEFLAGS |= TUS_ATTPENDING; update_tucs (CS1_SC, drv); /* update status */ +sim_cancel(uptr); +sim_activate_after (uptr,SPINUPDLY); return r; } @@ -1179,93 +1217,149 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */ if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ tuer = tuer | ER_UNS; /* set formatter error */ - if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */ + if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) + uptr->TU_STATEFLAGS &= ~TUS_ATTPENDING; + else if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */ tucs1 = tucs1 | CS1_DONE | CS1_TRE; /* set done, err */ } uptr->USTAT = 0; /* clear status flags */ tufs = tufs | FS_ATA | FS_SSC; /* set attention */ +if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ + tufs = tufs | FS_SAT; /* set slave attn */ +uptr->flags &= ~UNIT_ATT; /* Ensure MOL is cleared */ update_tucs (CS1_SC, drv); /* update status */ +uptr->flags |= UNIT_ATT; return sim_tape_detach (uptr); } /* Device bootstrap */ +/* Note that the dec and ITS boot code is word for word identical, + * except for the IO instructions. The ITS instructions encode the + * UBA number. No attempt is made to allow UBA selection under ITS, + * though it should work with the DEC rom. + * The sequence is: + * controller clear - to clear controller errors + * formatter select - to gain access to the formatter registers. (since only + * one formatter is supported, and it's assumed to be zero, this isn't strictly + * necessary. But maybe someday...) + * wait for MOL to appear. + * Drive clear - to clear any errors in the transport, including attention from on-line. + * Space forward one file - this is the KS CPU microcode, which the simulator doesn't + * use. + * Read the preboot (next level bootstrap) from the tape into page 1. + * Each operation produces erors - for one, the frame count is not exact. + * They are cleared, and the expected ones ignored. If no unexpected + * errors are encountered, control is transferred to the preboot. + */ #define BOOT_START 0377000 /* start */ #define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10)) static const d10 boot_rom_dec[] = { - INT64_C(0515040000003), /* boot:hrlzi 1,3 ; uba # */ + INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # */ INT64_C(0201000040001), /* movei 0,40001 ; vld,pg 1 */ INT64_C(0713001000000)+(IOBA_UBMAP+1 & RMASK), /* wrio 0,763001(1); set ubmap */ - INT64_C(0435040000000)+(IOBA_TU & RMASK), /* iori 1,772440 ; rh addr */ - INT64_C(0202040000000)+FE_RHBASE, /* movem 1,FE_RHBASE */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ INT64_C(0713001000010), /* wrio 0,10(1) ; ->MTFS */ + INT64_C(0200300000000)+FE_UNIT, /* move 6,FE_UNIT ; fmtr */ + INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTCS2 */ + + INT64_C(0200240000000)+FE_MTFMT, /*10 move 5,FE_MTFMT ; slave, dens, fmt */ + INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC */ + INT64_C(0712001000012), /* rdio 0,12(1) ; MTFS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377012), /* jrst .-3 ; wait */ + INT64_C(0201000000011), /* movei 0,11 ; clr+go */ + INT64_C(0713001000000), /* wrio 0,0(1) ; ->MTCS1 */ + + INT64_C(0201000000377), /*20 movei 0,1 ; Formatter */ + INT64_C(0242006000000), /* lsh 0,(6) ; attn bit */ + INT64_C(0713001000016), /* wrio 0,16(1) ; Clear on-line attn */ INT64_C(0201100000031), /* movei 2,31 ; space f */ - INT64_C(0265740377014), /* jsp 17,tpop ; skip ucode */ + INT64_C(0265740377030), /* jsp 17,tpop ; skip ucode */ INT64_C(0201100000071), /* movei 2,71 ; read f */ - INT64_C(0265740377014), /* jsp 17,tpop ; read boot */ + INT64_C(0265740377030), /* jsp 17,tpop ; read boot */ INT64_C(0254000001000), /* jrst 1000 ; start */ - INT64_C(0200000000000)+FE_MTFMT, /* tpop:move 0,FE_MTFMT ; den,fmt,slv */ - INT64_C(0713001000032), /* wrio 0,32(1) ; ->MTTC */ + + /*30 */ + INT64_C(0713241000032), /* tpop:wrio 5,32(1) ; ->MTTC */ INT64_C(0201000000011), /* movei 0,11 ; clr+go */ INT64_C(0713001000000), /* wrio 0,0(1) ; ->MTCS1 */ INT64_C(0201140176000), /* movei 3,176000 ; wd cnt */ - INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0200240000000)+FE_MTFMT, /* move 5,FE_MTFMT ; unit */ - INT64_C(0201300000000), /* movei 6,0 ; fmtr */ INT64_C(0713141000002), /* wrio 3,2(1) ; ->MTWC */ + INT64_C(0201200004000), /* movei 4,4000 ; addr */ INT64_C(0713201000004), /* wrio 4,4(1) ; ->MTBA */ - INT64_C(0713301000006), /* wrio 6,6(1) ; ->MTFC */ - INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTFS */ - INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC */ - INT64_C(0713101000000), /* wrio 2,0(1) ; ->MTCS1 */ + INT64_C(0400400000000), /* setz 10, ; max fc */ + + INT64_C(0713401000006), /*40 wrio 10,6(1) ; ->MTFC */ + INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTCS2 reset errs */ + INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC reset errs */ + INT64_C(0713101000000), /* wrio 2,0(1) ; OP ->MTCS1 */ INT64_C(0712341000012), /* rdio 7,12(1) ; read FS */ INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377032), /* jrst .-2 ; loop */ + INT64_C(0254000377044), /* jrst .-2 ; loop */ INT64_C(0606340040000), /* trnn 7,40000 ; test err */ - INT64_C(0254017000000), /* jrst 0(17) ; return */ + + INT64_C(0254017000000), /*50 jrst 0(17) ; return */ INT64_C(0712341000014), /* rdio 7,14(1) ; read err */ INT64_C(0302340001000), /* caie 7,1000 ; fce? */ - INT64_C(0254200377052), /* halt */ + INT64_C(0254200377053), /* halt . */ INT64_C(0254017000000), /* jrst 0(17) ; return */ }; static const d10 boot_rom_its[] = { - INT64_C(0515040000003), /* boot:hrlzi 1,3 ; uba # - not used */ + INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # - not used */ INT64_C(0201000040001), /* movei 0,40001 ; vld,pg 1 */ INT64_C(0714000000000)+(IOBA_UBMAP+1 & RMASK), /* iowri 0,763001 ; set ubmap */ - INT64_C(0435040000000)+(IOBA_TU & RMASK), /* iori 1,772440 ; rh addr */ - INT64_C(0202040000000)+FE_RHBASE, /* movem 1,FE_RHBASE */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ INT64_C(0714001000010), /* iowri 0,10(1) ; ->MTFS */ + INT64_C(0200300000000)+FE_UNIT, /* move 6,FE_UNIT ; fmtr */ + INT64_C(0714301000010), /* iowri 6,10(1) ; ->MTFS */ + + INT64_C(0200240000000)+FE_MTFMT, /*20 move 5,FE_MTFMT ; slave, dens, fmt */ + INT64_C(0714241000032), /* iowri 5,32(1) ; ->MTTC */ + INT64_C(0710001000012), /* iordi 0,12(1) ; read FS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377012), /* jrst .-3 ; wait */ + INT64_C(0201000000011), /* movei 0,11 ; clr+go */ + INT64_C(0714001000000), /* iowri 0,0(1) ; ->MTCS1 */ + + INT64_C(0201000000377), /*30 movei 0,1 ; Formatter */ + INT64_C(0242006000000), /* lsh 0,(6) ; attn bit */ + INT64_C(0714001000016), /* iowri 0,16(1) ; Clear on-line attn */ INT64_C(0201100000031), /* movei 2,31 ; space f */ - INT64_C(0265740377014), /* jsp 17,tpop ; skip ucode */ + INT64_C(0265740377030), /* jsp 17,tpop ; skip ucode */ INT64_C(0201100000071), /* movei 2,71 ; read f */ - INT64_C(0265740377014), /* jsp 17,tpop ; read boot */ + INT64_C(0265740377030), /* jsp 17,tpop ; read boot */ INT64_C(0254000001000), /* jrst 1000 ; start */ - INT64_C(0200000000000)+FE_MTFMT, /* tpop:move 0,FE_MTFMT ; den,fmt,slv */ - INT64_C(0714001000032), /* iowri 0,32(1) ; ->MTTC */ + + /*30 */ + INT64_C(0714241000032), /* tpop:iowri 5,32(1) ; ->MTTC */ INT64_C(0201000000011), /* movei 0,11 ; clr+go */ INT64_C(0714001000000), /* iowri 0,0(1) ; ->MTCS1 */ INT64_C(0201140176000), /* movei 3,176000 ; wd cnt */ - INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0200240000000)+FE_MTFMT, /* move 5,FE_MTFMT ; unit */ - INT64_C(0201300000000), /* movei 6,0 ; fmtr */ INT64_C(0714141000002), /* iowri 3,2(1) ; ->MTWC */ + INT64_C(0201200004000), /* movei 4,4000 ; addr */ INT64_C(0714201000004), /* iowri 4,4(1) ; ->MTBA */ - INT64_C(0714301000006), /* iowri 6,6(1) ; ->MTFC */ + INT64_C(0400400000000), /* setz 10, ; max fc */ + + INT64_C(0714401000006), /*40 iowri 10,6(1) ; ->MTFC */ INT64_C(0714301000010), /* iowri 6,10(1) ; ->MTFS */ INT64_C(0714241000032), /* iowri 5,32(1) ; ->MTTC */ INT64_C(0714101000000), /* iowri 2,0(1) ; ->MTCS1 */ INT64_C(0710341000012), /* iordi 7,12(1) ; read FS */ INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377032), /* jrst .-2 ; loop */ + INT64_C(0254000377044), /* jrst .-2 ; loop */ INT64_C(0606340040000), /* trnn 7,40000 ; test err */ - INT64_C(0254017000000), /* jrst 0(17) ; return */ + + INT64_C(0254017000000), /*50 jrst 0(17) ; return */ INT64_C(0710341000014), /* iordi 7,14(1) ; read err */ INT64_C(0302340001000), /* caie 7,1000 ; fce? */ - INT64_C(0254200377052), /* halt */ + INT64_C(0254200377053), /* halt . */ INT64_C(0254017000000), /* jrst 0(17) ; return */ }; @@ -1273,10 +1367,23 @@ t_stat tu_boot (int32 unitno, DEVICE *dptr) { size_t i; extern a10 saved_PC; +UNIT *uptr; + +unitno &= TC_M_UNIT; +uptr = tu_unit + unitno; +if (!(uptr->flags & UNIT_ATT)) + return SCPE_NOATT; + +M[FE_RHBASE] = tu_dib.ba; +M[FE_UNIT] = 0; /* Only one formatter in this implementation */ + +assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); -M[FE_UNIT] = 0; M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT); tu_unit[unitno].pos = 0; + +M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0); + for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; saved_PC = BOOT_START; diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index 57d3c252..935d2fb5 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -1,6 +1,6 @@ /* pdp11_cpumod.c: PDP-11 CPU model-specific features - Copyright (c) 2004-2008, Robert M Supnik + Copyright (c) 2004-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ system PDP-11 model-specific registers + 06-Jun-13 RMS Fixed change model to set memory size last 20-May-08 RMS Added JCSR default for KDJ11B, KDJ11E 22-Apr-08 RMS Fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE (Walter Mueller) @@ -1090,14 +1091,14 @@ if (val >= MOD_MAX) return SCPE_IERR; if (val == (int32) cpu_model) return SCPE_OK; -if (MEMSIZE > cpu_tab[val].maxm) - cpu_set_size (uptr, cpu_tab[val].maxm, NULL, NULL); -if (MEMSIZE > cpu_tab[val].maxm) - return SCPE_INCOMP; cpu_model = val; cpu_type = 1u << cpu_model; cpu_opt = cpu_tab[cpu_model].std; cpu_set_bus (cpu_opt); +if (MEMSIZE > cpu_tab[val].maxm) + cpu_set_size (uptr, cpu_tab[val].maxm, NULL, NULL); +if (MEMSIZE > cpu_tab[val].maxm) + return SCPE_INCOMP; reset_all (0); /* reset world */ return SCPE_OK; } diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index 28e6c1bf..5faea762 100644 --- a/PDP11/pdp11_cr.c +++ b/PDP11/pdp11_cr.c @@ -1,4 +1,4 @@ -/* pdp11_cr.c: CR/CM/CD-11 card reader simulator +/* pdp11_cr.c: CR/CM/CD-11/CD20 card reader simulator Copyright (c) 2005-2010, John A. Dundas III Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu @@ -28,7 +28,7 @@ ------------------------------------------------------------------------------ - cr CR11/CD11 punched and mark sense card reader for SIMH + cr CR11/CD11/CD20 punched and mark sense card reader for SIMH The CR11 controller is also compatible with the CM11-F, CME11, and CMS11. Information necessary to create this simulation was gathered from @@ -51,8 +51,16 @@ http://www.cs.uiowa.edu/~jones/cards/ Paul Mattes' x026 keypunch simulator http://x3270.bgp.nu/x026.html - CD2SER.MAC - TOPS card reader driver source + CD2SER.MAC - TOPS-10 card reader driver source http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac + CDRIVE.MAC - TOPS GALAXY card reader spooler + http://pdp-10.trailing-edge.com/BB-BT99U-BB_1990/03/10,7/galaxy/cdrive/cdrive.mac + SPRINT.MAC - TOPS GALAXY control card interpreter + http://pdp-10.trailing-edge.com/BB-H138C-BM/01/galaxy-sources/sprint.mac + CDKSDV.MAC - TOPS-20 card reader driver source + http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/cdksdv.mac + PROKS.MAC - TOPS-20 bit definitions + http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/proks.mac The Card Image format code and documentation is adapted from Prof. Jones's site, with his permission. Please see his site for additional @@ -88,7 +96,8 @@ Don't have any information about Unix or Ultrix-11 yet. Same for VAX Unices. - TOPS: only the CD11 is supported, under the name CD20. + TOPS: only the CD20 variant of the CD11 is supported. CD20 implies + ECOs (at least) for Data Buffer status and augmented image mode. Revision History: 23-Feb-13 JGP Added DEC version of the 026 codepage @@ -174,28 +183,52 @@ 08-Jan-05 JAD Original creation and testing */ +/* Configuration notes: + * Keep VM_arch symbols here and use them only to select features. + * CR attributes use generic symbols so device support is easy to change, + * e.g. if software is discovered that uses a previously unsupported option. + * Conventions: + * *_ONLY (AND *_req) means feature * is unconditionally present/required. + * *_OK means feature * is selectable at runtime. + * neither means feature is not present. + * To support only one controller model, define _ONLY. + * To support more than one, define them all as _OK. + * Don't mix "_ONLY" and "_OK" for the same feature. You won't like it. + * + * The CD/CR will work on any UNIBUS, and the CR will also work on a QBUS. + * The configuration options used here are more restrictive to reflect + * known software support, as this reduces user configuration errors/confusion. + */ + #if defined (VM_PDP10) /* PDP10 version */ #include "pdp10_defs.h" extern int32 int_req; #define DFLT_DIS (DEV_DIS) -#define DFLT_CR11 (0) /* CD11 only */ -#define DFLT_CPM 1000 - +#define DFLT_TYPE (UNIT_CD20) /* CD20 (CD11) only */ +#define CD20_ONLY (1) +#define DFLT_CPM 1200 +#define AIECO_REQ (1) /* Requires Augmented Image ECO */ #elif defined (VM_VAX) /* VAX version */ #include "vax_defs.h" extern int32 int_req[IPL_HLVL]; #define DFLT_DIS (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ -#define DFLT_CR11 (UNIT_CR11) /* CR11 only */ +#define DFLT_TYPE (UNIT_CR11) /* CR11 only */ +#define CR11_ONLY (1) #define DFLT_CPM 285 - #else /* PDP-11 version */ #include "pdp11_defs.h" extern int32 int_req[IPL_HLVL]; #define DFLT_DIS (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ -#define DFLT_CR11 (UNIT_CR11) /* Default, but changable */ +#define DFLT_TYPE (UNIT_CR11) /* Default, but changable */ #define DFLT_CPM 285 +#define CD20_OK (1) +#define AIECO_OK (1) /* Augmented Image ECO optional */ +#define CR11_OK (1) +#define CD11_OK (1) #endif +/* **** No VM_xxx macros should be referenced after this line **** */ + /* create a int32 constant from four characters */ #define I4C(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) #define I4C_CBN I4C ('C','B','N',' ') @@ -203,10 +236,46 @@ extern int32 int_req[IPL_HLVL]; #define I4C_H82 I4C ('H','8','2',' ') #define I4C_H40 I4C ('H','4','0',' ') -#define UNIT_V_CR11 (UNIT_V_UF + 0) -#define UNIT_CR11 (1u << UNIT_V_CR11) -#define UNIT_V_AUTOEOF (UNIT_V_UF + 1) +#define UNIT_V_TYPE (UNIT_V_UF + 0) /* Bit-encoded 2-bit field */ +#define UNIT_TYPE (3u << UNIT_V_TYPE) +#define UNIT_CR11 (1u << UNIT_V_TYPE) +#define UNIT_CD20 (2u << UNIT_V_TYPE) + +#define UNIT_V_AUTOEOF (UNIT_V_UF + 2) #define UNIT_AUTOEOF (1u << UNIT_V_AUTOEOF) +#define UNIT_V_RDCHECK (UNIT_V_UF + 3) +#define UNIT_RDCHECK (1u << UNIT_V_RDCHECK) +#define UNIT_V_AIECO (UNIT_V_UF + 4) +#define UNIT_AIECO (1u << UNIT_V_AIECO) + +/* Tests for which device is being emulated. + * Note that CD20 is a CD11 + mandatory ECOs. CD11_CTL will be true for both. + */ +#if defined (CD11_ONLY) || defined (CD20_ONLY) +#define CR11_CTL(up) (0) +#define CD11_CTL(up) (1) +#elif defined (CR11_ONLY) +#define CR11_CTL(up) (1) +#define CD11_CTL(up) (0) +#else +#define CR11_CTL(up) ((up)->flags & UNIT_CR11) +#define CD11_CTL(up) (!CR11_CTL(up)) +#endif + +#if defined (CD20_ONLY) +#define CD20_CTL(up) (1) +#elif defined (CD20_OK) +#define CD20_CTL(up) ((up)->flags & UNIT_CD20) +#else +#define CD20_CTL(up) (0) +#endif + +/* Configuration */ +#if defined (AIECO_REQ) +#define DFLT_AIECO (UNIT_AIECO) +#else +#define DFLT_AIECO (0) +#endif #include #define ERROR (00404) @@ -254,19 +323,22 @@ extern int32 int_req[IPL_HLVL]; /* CD */ /* also use CSR_ERR, CSR_IE, and CSR_GO */ -#define CDCSR_V_RDRCHK 14 /* reader check */ +/* ERR */ +#define CDCSR_V_RDRCHK 14 /* reader check: HOPPER,STACK,PICK,READ */ #define CDCSR_V_EOF 13 /* CD11-E EOF button */ #define CDCSR_V_OFFLINE 12 /* off line */ -#define CDCSR_V_DATAERR 11 /* data error */ +#define CDCSR_V_DATAERR 11 /* data packing error */ #define CDCSR_V_LATE 10 /* data late */ #define CDCSR_V_NXM 9 /* non-existent memory */ #define CDCSR_V_PWRCLR 8 /* power clear */ #define CDCSR_V_RDY 7 /* ready */ -#define CDCSR_V_XBA17 5 +/* IE */ +#define CDCSR_V_XBA17 5 /* NPR bus address bits<17:16> */ #define CDCSR_V_XBA16 4 #define CDCSR_V_ONLINE 3 /* on line transition */ #define CDCSR_V_HOPPER 2 /* hopper check */ #define CDCSR_V_PACK 1 /* data packing */ +/* GO */ #define CDCSR_RDRCHK (1u << CDCSR_V_RDRCHK) #define CDCSR_EOF (1u << CDCSR_V_EOF) @@ -282,6 +354,8 @@ extern int32 int_req[IPL_HLVL]; #define CDCSR_HOPPER (1u << CDCSR_V_HOPPER) #define CDCSR_PACK (1u << CDCSR_V_PACK) +#define CDCSR_ANYERR (CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM) + #define CDCSR_IMP (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | \ CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | \ CDCSR_PWRCLR | CDCSR_RDY | CSR_IE | \ @@ -291,6 +365,23 @@ extern int32 int_req[IPL_HLVL]; #define CDCSR_RW (CDCSR_PWRCLR | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | \ CDCSR_PACK | CSR_GO) +/* CD11 second status register bits. Valid only when not busy. All + * also set CDCSR_RDRCK (and CSR_ERR) + */ + +#define CDDB_V_READ 14 /* Read check (extra punches, not readER check) */ +#define CDDB_V_PICK 13 /* Pick check (card present, not grabbed) */ +#define CDDB_V_STACK 12 /* Card did not arrive in stacker */ + +/* N.B. Per TOPS-20 driver, which references CD11 manual and printset: + * Stacker full is indicated by: + * CDCSR_RDRCHK && !(CDDB_READ|CDDB_PICK|CDDB_STACK) + */ +#define CDDB_READ (1U << CDDB_V_READ) +#define CDDB_PICK (1u << CDDB_V_PICK) +#define CDDB_STACK (1u << CDDB_V_STACK) + + /* Blower state values */ #define BLOW_OFF (0) /* steady state off */ #define BLOW_START (1) /* starting up */ @@ -299,32 +390,53 @@ extern int32 int_req[IPL_HLVL]; /* Card Reader state */ static char *cardFormat = "unknown"; -static t_bool (*readRtn)(FILE *, int16 *, char *, char *); +static t_bool (*readRtn)(UNIT *, int16 *, char *, char *); static char ascii_code[4096]; /* 2^12 possible values */ static int currCol; /* current column when reading */ static int colStart; /* starting column */ static int colEnd; /* ending column */ -static int table = 3; /* character translation table */ -static const int *codeTbl = o29_code; /* punch translation table */ +static const int *codeTbl = /* punch translation table */ +#if defined(CD20_ONLY) || (defined(DFLT_TYPE) && (DFLT_TYPE == UNIT_CD20)) + o29_decascii_code; +#else + o29_code; +#endif +static struct trans { + const char *const name; + const int *const table; +} transcodes[] = { + { "DEFAULT", o29_code, }, + { "026", o26_dec_code, }, + { "026FTN", o26_ftn_code, }, + { "026DECASCII", o26_decascii_code, }, + { "029", o29_code, }, + { "EBCDIC", EBCDIC_code, }, + { "026DEC", o26_dec_code, }, + { "029DECASCII", o29_decascii_code }, +}; +#define NTRANS (sizeof transcodes /sizeof transcodes[0]) + static int32 blowerState = BLOW_OFF; /* reader vacuum/blower motor */ -static int32 spinUp = 3000; /* blower spin-up time: 3 seconds */ -static int32 spinDown = 2000; /* blower spin-down time: 2 seconds */ -static t_bool EOFcard = FALSE; /* played special card yet? */ +static int32 spinUp = 3000000; /* blower spin-up time: 3 seconds (usec) */ +static int32 spinDown = 2000000; /* blower spin-down time: 2 seconds (usec) */ +static int EOFcard = 0; /* played special card yet? */ +static t_bool eofPending = FALSE; /* Manual EOF switch pressed */ static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */ /* card image in various formats */ static int16 hcard[82]; /* Hollerith format */ static char ccard[82]; /* DEC compressed format */ static char acard[82]; /* ASCII format */ /* CR/CM registers */ -static int32 crs = 0; /* control/status */ +static int32 crs = CSR_ERR | CRCSR_OFFLINE | CRCSR_SUPPLY; /* control/status */ static int32 crb1 = 0; /* 12-bit Hollerith characters */ static int32 crb2 = 0; /* 8-bit compressed characters */ static int32 crm = 0; /* CMS maintenance register */ /* CD registers */ -static int32 cdst = 0; /* control/status */ +static int32 cdst = CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER; /* Control/status - off-line until attached */ static int32 cdcc = 0; /* column count */ static int32 cdba = 0; /* current address, low 16 bits */ static int32 cddb = 0; /* data, 2nd status */ +static int32 cddbs = 0; /* second status bits (or with cddb) */ /* forward references */ DEVICE cr_dev; @@ -336,11 +448,14 @@ t_stat cr_reset (DEVICE *); t_stat cr_attach (UNIT *, char *); t_stat cr_detach (UNIT *); t_stat cr_set_type (UNIT *, int32, char *, void *); +t_stat cr_set_aieco (UNIT *, int32, char *, void *); t_stat cr_show_format (FILE *, UNIT *, int32, void *); t_stat cr_set_rate (UNIT *, int32, char *, void *); t_stat cr_show_rate (FILE *, UNIT *, int32, void *); t_stat cr_set_reset (UNIT *, int32, char *, void *); t_stat cr_set_stop (UNIT *, int32, char *, void *); +t_stat cr_set_eof (UNIT *, int32, char *, void *); +t_stat cr_show_eof (FILE *, UNIT *, int32, void *); t_stat cr_set_trans (UNIT *, int32, char*, void *); t_stat cr_show_trans (FILE *, UNIT *, int32, void *); static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); @@ -364,19 +479,23 @@ static DIB cr_dib = { IOBA_AUTO, IOLN_CR, &cr_rd, &cr_wr, static UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+ - DFLT_CR11+UNIT_AUTOEOF, 0), - (60 * 1000) / DFLT_CPM }; + DFLT_TYPE+UNIT_AUTOEOF+UNIT_RDCHECK+DFLT_AIECO, 0), + (60 * 1000000) / (DFLT_CPM * 80) }; static const REG cr_reg[] = { { GRDATAD (BUF, cr_unit.buf, DEV_RDX, 8, 0, "ASCII value of last column processed") }, +#if defined (CR11_OK) || defined (CR11_ONLY) { GRDATAD (CRS, crs, DEV_RDX, 16, 0, "CR11 status register") }, { GRDATAD (CRB1, crb1, DEV_RDX, 16, 0, "CR11 12-bit Hollerith character") }, { GRDATAD (CRB2, crb2, DEV_RDX, 16, 0, "CR11 8-bit compressed character") }, { GRDATAD (CRM, crm, DEV_RDX, 16, 0, "CR11 maintenance register") }, +#endif +#if defined (CD11_OK) || defined (CD11_ONLY) || defined (CD20_OK) || defined (CD20_ONLY) { GRDATAD (CDST, cdst, DEV_RDX, 16, 0, "CD11 control/status register") }, { GRDATAD (CDCC, cdcc, DEV_RDX, 16, 0, "CD11 column count") }, { GRDATAD (CDBA, cdba, DEV_RDX, 16, 0, "CD11 current bus address") }, { GRDATAD (CDDB, cddb, DEV_RDX, 16, 0, "CD11 data buffer, 2nd status") }, +#endif { GRDATAD (BLOWER, blowerState, DEV_RDX, 2, 0, "blower state value") }, { FLDATAD (INT, IREQ (CR), INT_V_CR, "interrupt pending flag") }, { FLDATAD (ERR, crs, CSR_V_ERR, "error flag (CRS<15>)") }, @@ -387,26 +506,52 @@ static const REG cr_reg[] = { { GRDATA (DEVVEC, cr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; -static const MTAB cr_mod[] = { -#if defined (VM_PDP11) - { UNIT_CR11, UNIT_CR11, "CR11", "CR11", +static char *translation_help = NULL; +static MTAB cr_mod[] = { +#if defined (CR11_OK) + { UNIT_TYPE, UNIT_CR11, "CR11", "CR11", &cr_set_type, NULL, NULL, "Set device type to CR11" }, - { UNIT_CR11, 0, "CD11", "CD11", +#endif +#if defined (CD11_OK) + { UNIT_TYPE, 0, "CD11", "CD11", &cr_set_type, NULL, NULL, "Set device type to CD11" }, -#else - { UNIT_CR11, UNIT_CR11, "CR11", NULL }, - { UNIT_CR11, 0, "CD11", NULL }, +#endif +#if defined (CD20_OK) + { UNIT_TYPE, UNIT_CD20, "CD20", "CD20", + &cr_set_type, NULL, NULL, "Set device type to CD20" }, +#endif +#if defined (CR11_ONLY) || defined (CD11_ONLY) || defined (CD20_ONLY) + { UNIT_TYPE, UNIT_CR11, "CR11", NULL, }, + { UNIT_TYPE, 0, "CD11", NULL, }, + { UNIT_TYPE, UNIT_CD20, "CD20", NULL, }, +#endif +#if defined (AIECO_OK) + { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|UNIT_AIECO), "augmented image ECO", "AIECO", + &cr_set_aieco, NULL, NULL, "Enable CD20 augmented image ECO" }, + { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|0), "standard", "NOAIECO", + &cr_set_aieco, NULL, NULL, "Disable CD20 augmented image ECO" }, #endif { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", NULL, NULL, NULL, "Enable auto EOF mode" }, { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", NULL, NULL, NULL, "Disable auto EOF mode" }, +#if !defined (CR11_ONLY) + { UNIT_RDCHECK, UNIT_RDCHECK, "read check", "RDCHECK", + NULL, NULL, NULL, "Enable read check errors" }, + { UNIT_RDCHECK, 0, "no read check", "NORDCHECK", + NULL, NULL, NULL, "Disable read check errors" }, +#endif + /* card reader STOP switch */ + { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", + &cr_set_stop, NULL, NULL, "Pulse reader Stop button" }, /* card reader RESET switch */ { MTAB_XTD|MTAB_VDV, 0, NULL, "RESET", &cr_set_reset, NULL, NULL, "Pulse reader reset button" }, - /* card reader STOP switch */ - { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", - &cr_set_stop, NULL, NULL, "Pulse reader Stop button" }, +#if !defined (CR11_ONLY) + /* card reader EOF switch */ + { MTAB_XTD|MTAB_VDV, MTAB_XTD|MTAB_VDV, "EOF pending", "EOF", + &cr_set_eof, &cr_show_eof, NULL, "Pulse reader EOF button" }, +#endif { MTAB_XTD|MTAB_VUN, 0, "FORMAT", NULL, NULL, &cr_show_format, NULL, "Set reader input format" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 006, "ADDRESS", "ADDRESS", @@ -416,7 +561,7 @@ static const MTAB cr_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "RATE", "RATE={DEFAULT|200..1200}", &cr_set_rate, &cr_show_rate, NULL, "Display input rate" }, { MTAB_XTD|MTAB_VDV, 0, "TRANSLATION", - "TRANSLATION={DEFAULT|026|026FTN|029|EBCDIC|026DEC}", + NULL, &cr_set_trans, &cr_show_trans, NULL, "Display translation mode" }, { 0 } }; @@ -443,6 +588,12 @@ TRUE if a card was read (possibly with errors) and FALSE if the "hopper is empty" (EOF) or fatal file errors prevented any portion of a card from being read. +Note that the hopper becomes empty when the last card moves to the +read station. Thus hopper empty without an error means that data +from that card is valid. Thus hopper empty is first signalled when +the NEXT card read would return EOF. Reads after that will return +some error bit. + Errors other than EOF are signaled out of band in the controller state variables. Possible errors are data in columns 0 or 81 (signalled as read check; currently these columns are ignored), or @@ -453,142 +604,143 @@ check". Retry 3 times. After that, give up with error. */ -static t_bool readCardImage ( FILE *fp, +/* Common handling for end of file and errors on input */ + +static t_bool fileEOF ( UNIT *uptr, + int16 *hcard, + char *ccard, + char *acard, + int32 cddbsBits ) +{ + int col; + + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "hopper empty\n"); + + if (!EOFcard && (uptr->flags & UNIT_AUTOEOF) && !ferror(uptr->fileref)) { + EOFcard = -1; + /* Generate EOD card, which empties the hopper */ + for (col = 1; col <= 8; col++) { + hcard[col] = PUNCH_EOD; + ccard[col] = h2c_code[PUNCH_EOD]; + acard[col] = ' '; + } + while (col <= colEnd) { + hcard[col] = PUNCH_SPACE; + ccard[col] = PUNCH_SPACE; + acard[col] = ' '; + col++; + } + /* The CR11 doesn't set SUPPPLY at this time, but waits until the EOF card is done. */ + cdst |= CDCSR_HOPPER; + return (TRUE); + } + /* Not auto EOF, or EOF already handled. This is an attempt to read + * with an empty hopper. Report a pick, read or stacker check as well + * as hopper empty to indicate that no data was transfered. One might + * think that cdcc unchanged would be sufficient, but that's not what + * the OSs check. + */ + + crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; + crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); + + cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; + cddbs |= cddbsBits; + + if (((uptr->flags & UNIT_AUTOEOF) || eofPending) && !ferror(uptr->fileref)) { + cdst |= CDCSR_EOF; + eofPending = FALSE; + } + return (FALSE); +} + +static t_bool readCardImage ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { int c1, c2, c3, col; + FILE *fp = uptr->fileref; if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "readCardImage pos %d\n", (int) ftell (fp)); - /* get card header bytes */ - c1 = fgetc (fp); - c2 = fgetc (fp); - c3 = fgetc (fp); - cr_unit.pos = ftell (fp); - /* check for EOF */ - if (c1 == EOF) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "hopper empty\n"); - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - return (TRUE); - } - crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - return (FALSE); - } - /* check for valid header */ - if ((c2 == EOF) || (c3 == EOF) || ((c1 & 0x80) == 0) || - ((c2 & 0x80) == 0) || ((c3 & 0x80) == 0)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "header error\n"); - /* unexpected EOF or format problems */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } - assert (colStart < colEnd); - assert (colStart >= 0); - assert (colEnd <= 81); - for (col = colStart; col < colEnd; ) { - int16 i; - /* get 3 bytes */ + do { + /* get card header bytes */ c1 = fgetc (fp); c2 = fgetc (fp); c3 = fgetc (fp); - cr_unit.pos = ftell (fp); - if (ferror (fp) || feof (fp)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "file error\n"); -/* signal error; unexpected EOF, format problems, or file error(s) */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } - /* convert to 2 columns */ - i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; - hcard[col] = i; - ccard[col] = h2c_code[i]; - acard[col] = ascii_code[i]; - col++; + uptr->pos = ftell (fp); + /* check for EOF */ + if (c1 == EOF) + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); + + /* check for valid card header */ + if ((c2 == EOF) || (c3 == EOF) || ((c1 & c2 & c3 & 0x80) == 0) ) { + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "header error\n"); + /* unexpected EOF or format problems */ + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); + } + + /* Read card image into internal buffer */ + + assert (colStart < colEnd); + assert (colStart >= 0); + assert (colEnd <= 81); + for (col = colStart; col < colEnd; ) { + int16 i; + int c1, c2, c3; + /* get 3 bytes */ + c1 = fgetc (fp); + c2 = fgetc (fp); + c3 = fgetc (fp); + uptr->pos = ftell (fp); + if (ferror (fp) || (c1 == EOF) || (c2 == EOF) || (c3 == EOF)) { + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "file error\n"); + /* signal error; unexpected EOF, format problems, or file error(s) */ + return fileEOF (uptr, hcard, ccard, acard, ferror(fp)? CDDB_READ: CDDB_PICK); + } + /* convert to 2 columns */ + i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; + hcard[col] = i; + ccard[col] = h2c_code[i]; + acard[col] = ascii_code[i]; + col++; + + i = (((c2 & 017) << 8) | c3) & 0xFFF; + hcard[col] = i; + ccard[col] = h2c_code[i]; + acard[col] = ascii_code[i]; + col++; + } + } while ((c3 & 0x3f) == 0x3f); /* Skip metacards (Revised Jones spec) */ - i = (((c2 & 017) << 8) | c3) & 0xFFF; - hcard[col] = i; - ccard[col] = h2c_code[i]; - acard[col] = ascii_code[i]; - col++; - } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "successfully loaded card\n"); return (TRUE); } -static t_bool readColumnBinary ( FILE *fp, +static t_bool readColumnBinary ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { int col; + FILE *fp = uptr->fileref; for (col = colStart; col <= colEnd; col++) { - int16 i; - i = fgetc (fp) & 077; - i |= ((fgetc (fp) & 077) << 6); - cr_unit.pos = ftell (fp); - if (feof (fp)) { - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - return (TRUE); - } - crs |= CSR_ERR | CRCSR_SUPPLY | - CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - return (FALSE); - } - if (ferror (fp)) { - /* signal error */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } + int c1, c2; + uint16 i; + c1 = fgetc (fp); + c2 = fgetc (fp); + uptr->pos = ftell (fp); + if (c1 == EOF) + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); + if ((c2 == EOF) || ferror(fp)) + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); + i = (c1 & 077) | ((c2 & 077) << 6); hcard[col] = i; ccard[col] = h2c_code[i]; acard[col] = ascii_code[i]; @@ -600,16 +752,17 @@ static t_bool readColumnBinary ( FILE *fp, Should this routine perform special handling of non-printable, (e.g., control) characters or characters that have no encoded -representation? +representation? (In DEC026/DEC029 they all do...) */ -static t_bool readCardASCII ( FILE *fp, +static t_bool readCardASCII ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { - int c = 0, col; + int c = 0, col, peek; + FILE *fp = uptr->fileref; assert (colStart < colEnd); assert (colStart >= 1); @@ -621,40 +774,26 @@ static t_bool readCardASCII ( FILE *fp, switch (c = fgetc (fp)) { case EOF: if (ferror (fp)) { - /* signal error */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - cr_unit.pos = ftell (fp); - return (FALSE); + uptr->pos = ftell (fp); + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); } if (col == colStart) { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "hopper empty\n"); - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - c = '\n'; - goto fill_card; - } - crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - cr_unit.pos = ftell (fp); - return (FALSE); + uptr->pos = ftell (fp); + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); } /* fall through */ case '\r': + peek = fgetc (uptr->fileref); + if ((peek != EOF) && (peek != '\n')) + ungetc (peek, uptr->fileref); + goto fill; case '\n': - fill_card: + peek = fgetc (uptr->fileref); + if ((peek != EOF) && (peek != '\r')) + ungetc (peek, uptr->fileref); + fill: while (col <= colEnd) { hcard[col] = PUNCH_SPACE; ccard[col] = PUNCH_SPACE; @@ -678,7 +817,7 @@ static t_bool readCardASCII ( FILE *fp, if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "error character at column %d (%c)\n", - col, c & 0177); + col, c & 0177); } ccard[col] = h2c_code[hcard[col]]; acard[col] = c; @@ -690,12 +829,22 @@ static t_bool readCardASCII ( FILE *fp, if (c != '\n' && c != '\r') { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "truncating card\n"); - do c = fgetc (fp); - while ((c != EOF) && (c != '\n') && (c != '\r')); + c = fgetc (fp); + while (c != EOF) { + if ((c == '\n') || (c == '\r')) { + peek = fgetc (uptr->fileref); + if (peek == EOF) + break; + if (((c == '\n') && (peek != '\r')) || ((c == '\r') && (peek != '\n'))) + ungetc (peek, uptr->fileref); + break; + } + c = fgetc (fp); + } } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "successfully loaded card\n"); - cr_unit.pos = ftell (fp); + uptr->pos = ftell (fp); return (TRUE); } @@ -711,39 +860,8 @@ static void initTranslation (void) int32 i; memset (ascii_code, '~', sizeof (ascii_code)); - switch (table) { - case 1: - codeTbl = o26_comm_code; - for (i = ' '; i < '`'; i++) - ascii_code[o26_comm_code[i]] = i; - break; - case 2: - codeTbl = o26_ftn_code; - for (i = ' '; i < '`'; i++) - ascii_code[o26_ftn_code[i]] = i; - break; - case 3: - codeTbl = o29_code; - for (i = ' '; i < '`'; i++) - ascii_code[o29_code[i]] = i; - break; - case 4: - codeTbl = EBCDIC_code; - for (i = 0; i < 0177; i++) - ascii_code[EBCDIC_code[i]] = i; - break; - case 5: - codeTbl = o26_dec_code; - for (i = 0; i < 0177; i++) - ascii_code[EBCDIC_code[i]] = i; - break; - default: - /* can't happen */ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, - "bad CR translation initialization value\n"); - break; - } + for (i = 0; i < 0177; i++) + ascii_code[codeTbl[i]] = i; } /* @@ -833,11 +951,11 @@ t_stat cr_rd ( int32 *data, { switch ((PA >> 1) & 03) { case 0: /* CSR */ - if (cdst & (077000)) + if (cdst & (CDCSR_ANYERR)) cdst |= CSR_ERR; else cdst &= ~CSR_ERR; - *data = (cr_unit.flags & UNIT_CR11) ? + *data = (CR11_CTL(&cr_unit)) ? crs & CRCSR_IMP : cdst & CDCSR_IMP; /* CR: if error removed, clear 15, 14, 11, 10 */ if (DEBUG_PRS (cr_dev)) @@ -845,11 +963,11 @@ t_stat cr_rd ( int32 *data, crs, cdst); break; case 1: - /* Get word of data from crb1 (Hollerith code) */ - *data = (cr_unit.flags & UNIT_CR11) ? crb1 : cdcc; + /* Get word of data from crb1 (Hollerith code) or CD11 CC */ + *data = (CR11_CTL(&cr_unit)) ? crb1 : cdcc; crs &= ~CRCSR_COLRDY; if (DEBUG_PRS (cr_dev)) { - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) fprintf (sim_deb, "cr_rd crb1 %06o '%c' %d\n", crb1, cr_unit.buf, cr_unit.buf); else @@ -859,11 +977,11 @@ t_stat cr_rd ( int32 *data, crb1 = 0; break; case 2: - /* Get word of data from crb2 (DEC Compressed) */ - *data = (cr_unit.flags & UNIT_CR11) ? crb2 : cdba; + /* Get word of data from crb2 (DEC Compressed) or CD11 BA */ + *data = (CR11_CTL(&cr_unit)) ? crb2 : cdba; crs &= ~CRCSR_COLRDY; if (DEBUG_PRS (cr_dev)) { - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) fprintf (sim_deb, "cr_rd crb2 %06o\n", crb2); else fprintf (sim_deb, "\r\ncr_rd cdba %06o\n", cdba); @@ -872,12 +990,14 @@ t_stat cr_rd ( int32 *data, break; case 3: default: - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) /* CR11 maintenance */ *data = crm; - else - *data = 0100000 | (cdst & CDCSR_RDRCHK) | - (cdst & CDCSR_OFFLINE) ? - cddb & 0777 : 0777; + else /* CD11 data buffer/status. Note this implementation returns extended + * status even while busy (rather than the zone). Might be wrong. + */ + *data = 0100000 | (cddbs & (CDDB_READ|CDDB_PICK|CDDB_STACK)) | + ((crs & CRCSR_BUSY) ? + cddb & 0777 : 0777); if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_rd crm %06o cddb %06o data %06o\n", crm, cddb, *data); @@ -892,7 +1012,7 @@ t_stat cr_wr ( int32 data, { switch ((PA >> 1) & 03) { case 0: - if (cr_unit.flags & UNIT_CR11) { + if (CR11_CTL(&cr_unit)) { /* ignore high-byte writes */ if (PA & 1) break; @@ -902,66 +1022,107 @@ t_stat cr_wr ( int32 data, if (!(data & CSR_IE)) CLR_INT (CR); crs = (crs & ~CRCSR_RW) | (data & CRCSR_RW); - /* Clear status bits after CSR load */ + /* Clear status bits after CSR load */ crs &= ~(CSR_ERR | CRCSR_ONLINE | CRCSR_CRDDONE | CRCSR_TIMERR); + if (crs & CRCSR_OFFLINE) + crs |= CSR_ERR; if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr data %06o crs %06o\n", data, crs); if (data & CSR_GO) { if (blowerState != BLOW_ON) { blowerState = BLOW_START; - sim_activate (&cr_unit, spinUp); + sim_activate_after (&cr_unit, spinUp); } else { - sim_activate (&cr_unit, cr_unit.wait); - } + sim_activate_after (&cr_unit, cr_unit.wait); + } } - } else { + } else { /* CD11 */ + if (access == WRITEB) + data = (PA & 1)? (((data & 0xff)<<8) | (cdst & 0x00ff)): + ((data & 0x00ff) | (cdst & 0xFF00)); + if (data & CDCSR_PWRCLR) { CLR_INT (CR); sim_cancel (&cr_unit); - cdst &= ~(CDCSR_RDRCHK |CDCSR_OFFLINE | - CDCSR_RDY | CDCSR_HOPPER); - cdst |= CDCSR_RDY; cdcc = 0; cdba = 0; + cddb = 0; + cddbs = 0; + if (!(cr_unit.flags & UNIT_ATT)) { /* Clear troublesome bits, but leave error/offline */ + cdst &= ~(CSR_IE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | + CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK); + cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK; + cddbs |= CDDB_STACK; + break; + } + + crs &= ~CRCSR_BUSY; + cdst &= (CDCSR_OFFLINE | CDCSR_RDY | CDCSR_HOPPER); + if( (cr_unit.flags & UNIT_ATT) && !feof(cr_unit.fileref) && !ferror(cr_unit.fileref) ) + cdst &= ~(CDCSR_HOPPER); + if (cdst & (CDCSR_ANYERR)) + cdst |= CSR_ERR; + cdst |= CDCSR_RDY; break; } - if (!(data & CSR_IE)) + + if (data & CSR_GO) { + /* To simplify the service code, don't start if CDCC == 0. + * In the hardware, it's not sensible... + */ + if ((crs & CRCSR_BUSY) || (cdcc == 0)) { + cdst |= (CDCSR_RDRCHK | CDCSR_HOPPER | CSR_ERR); + } else { + cdst &= ~(CDCSR_RDRCHK | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | CDCSR_ONLINE); + cdst = (cdst & ~(CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK | CDCSR_HOPPER)) + | (data & (CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK)); + cddbs &= ~(CDDB_READ|CDDB_PICK|CDDB_STACK); + + /* Always attempt to start. If not attached, errors will set after delay */ + if (!(cdst & CDCSR_HOPPER) ) + cdst &= ~(CSR_ERR); + if (blowerState != BLOW_ON) { + blowerState = BLOW_START; + sim_activate_after (&cr_unit, spinUp); + } else { + sim_activate_after (&cr_unit, cr_unit.wait); + } + } + } else { + cdst = (cdst & ~(CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | + CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)) + |(data & (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | + CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)); + } + /* Apparently the hardware does not SET_INT if ready/online are already set. If it did, TOPS-10's driver wouldn't work */ + if (!(cdst & CSR_IE)) CLR_INT (CR); - cdst = (cdst & ~CDCSR_RW) | (data & CDCSR_RW); + if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr data %06o cdst %06o\n", data, cdst); - if (data & CSR_GO) { - if (blowerState != BLOW_ON) { - sim_activate (&cr_unit, spinUp); - blowerState = BLOW_START; - } else { - sim_activate (&cr_unit, cr_unit.wait); - } - } } break; case 1: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr cdcc %06o\n", data); - if (cr_unit.flags & UNIT_CR11) - break; - cdcc = data & 0177777; + if (CD11_CTL(&cr_unit)) + cdcc = data & 0177777; break; case 2: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr crba %06o\n", data); - if (cr_unit.flags & UNIT_CR11) - break; - cdba = data & 0177777; + if (CD11_CTL(&cr_unit)) + cdba = data & 0177777; break; case 3: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr cddb/crm %06o\n", data); /* ignore writes to cddb */ - if (!(cr_unit.flags & UNIT_CR11)) + if (CD11_CTL(&cr_unit)) break; + /* fixup data for byte writes and read-modify-write */ if (access == WRITEB) data = (PA & 1) ? @@ -996,7 +1157,8 @@ t_stat cr_svc ( UNIT *uptr ) { uint32 pa; uint8 c; - uint16 w; + uint16 w; + int n; /* Blower stopping: set it to OFF and do nothing */ if (blowerState == BLOW_STOP) { @@ -1007,45 +1169,120 @@ t_stat cr_svc ( UNIT *uptr ) if (blowerState == BLOW_START) blowerState = BLOW_ON; - /* (almost) anything we do now will cause a CR interrupt */ - if (crs & CSR_IE) + /* (almost) anything we do now will cause a CR (But not a CD) interrupt */ + if ((CR11_CTL(uptr)) && (crs & CSR_IE)) SET_INT (CR); - /* Unit not attached, or error status => do nothing */ - if (!(uptr->flags & UNIT_ATT) || (crs & CSR_ERR) || (cdst & CSR_ERR)) + /* Unit not attached, or error status while idle */ + if (!(uptr->flags & UNIT_ATT) || (!(crs & CRCSR_BUSY) && ((CR11_CTL(uptr)?crs : cdst) & CSR_ERR))) { + if (CD11_CTL(uptr)) { + if (!(uptr->flags & UNIT_ATT)){ + cdst |= (CDCSR_HOPPER | CDCSR_RDRCHK | CDCSR_OFFLINE | CSR_ERR); + cddbs |= CDDB_STACK; + } + if (cdst & CSR_IE) + SET_INT (CR); + } return (SCPE_OK); + } /* End of card: unit busy and column past end column */ if ((crs & CRCSR_BUSY) && (currCol > colEnd)) { /* clear busy state and set card done bit */ - crs &= ~(CRCSR_BUSY | CSR_GO | CRCSR_COLRDY); + crs &= ~(CRCSR_BUSY | CRCSR_COLRDY); crs |= CRCSR_CRDDONE; - /* Check CD11 error status */ - if (cdst & (CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM)) - cdst |= CSR_ERR; - if (DEBUG_PRS (cr_dev)) + + if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_svc card done\n"); - return (SCPE_OK); + + /* Check CD11 error status that stops transfers */ + if (CD11_CTL(uptr) && (cdst & (CDCSR_LATE | CDCSR_NXM))) { + cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDY | CDCSR_RDRCHK; + SET_INT (CR); + return (SCPE_OK); + } + + if (CR11_CTL(uptr)) + return (SCPE_OK); + + /* If a CD11 gets this far, an interrupt is required. If CDCC != 0, + * continue reading the next card. + */ + SET_INT (CR); + if (cdcc == 0) + return (SCPE_OK); } - /* Unit not busy: try to read a card */ + /* If unit is not busy: try to read a card */ if (!(crs & CRCSR_BUSY)) { crs &= ~CRCSR_CRDDONE; /* This line WAS commented out - JGP 2013.02.05 */ - /* Call the appropriate read card routine. */ - /* If no card is read (FALSE return), stop the show */ - if (!readRtn (uptr->fileref, hcard, ccard, acard)) { - blowerState = BLOW_STOP; - sim_activate (uptr, spinDown); + + /* Call the appropriate read card routine. + * If no card is read (FALSE return), we tried to read with an empty hopper. + * The card read routine set the appropriate error bits. Shutdown. + */ + if (!readRtn (uptr, hcard, ccard, acard)) { + if (CD11_CTL(uptr)) { +readFault: + blowerState = BLOW_STOP; + cdst |= CDCSR_RDY; + if (cdst & (CDCSR_RDRCHK | CDCSR_HOPPER)) + cdst |= CSR_ERR | CDCSR_OFFLINE; + if (cdst & CSR_IE) + SET_INT (CR); + } + sim_activate_after (uptr, spinDown); return (SCPE_OK); - } else { - /* Card read: reset column counter and assert BUSY */ - currCol = colStart; - crs |= CRCSR_BUSY; + } + + /* Card read: reset column counter and assert BUSY */ + currCol = colStart; + crs |= CRCSR_BUSY; + + /* Update status if this read emptied hopper. + * The CR11 doesn't set SUPPLY until after the last card is read. + */ + + /* I/O error status bits have been set during read. + * Look ahead to see if another card is in file. + */ + n = feof (uptr->fileref); + if (n) + n = EOF; + else { + n = fgetc (uptr->fileref); + if (n != EOF) + ungetc (n, uptr->fileref); + } + + if ((n == EOF) && ((EOFcard > 0) || !(uptr->flags & UNIT_AUTOEOF))) { + /* EOF and generated EOFcard sent or not an autoEOF unit. + * Set status to reflect last card taken. + */ + cdst |= (CDCSR_RDRCHK | CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER); + if (eofPending) { + cdst |= CDCSR_EOF; + eofPending = FALSE; + } + } + if (EOFcard) + EOFcard = 1; + + if (CD11_CTL(uptr)) { + /* Handle read check: punches in col 0 or 81/last (DEC only did 80 cols, but...) */ + if ((uptr->flags & UNIT_RDCHECK) && + (((colStart == 0) && (hcard[0] != 0)) || ((colEnd & 1) && (hcard[colEnd] != 0)))) { + cdst |= (CDCSR_RDRCHK | CSR_ERR); + cddbs |= CDDB_READ; + if (1) /* 0 if read check should transfer card */ + goto readFault; + } + /* CDDB_PICK, CDDB_STACK, flags & UNIT_CR11) && (crs & CRCSR_COLRDY)) + if (CR11_CTL(uptr) && (crs & CRCSR_COLRDY)) crs |= CSR_ERR | CRCSR_TIMERR; /* Update the "buffer" registers with current column */ @@ -1054,7 +1291,7 @@ t_stat cr_svc ( UNIT *uptr ) uptr->buf = acard[currCol] & 0377; /* Helpful for debug: ASCII value */ /* CD11 specific code follows */ - if (!(uptr->flags & UNIT_CR11)) { + if (CD11_CTL(uptr)) { pa = cdba | ((cdst & 060) << 12); /* The implementation of _NXM here is not quite the same as I interpret @@ -1067,38 +1304,61 @@ code detects and flags the NXM condition but allows attempts at subsequent memory writes, thus insuring the address registers are incremented properly. If this causes problems, I'll fix it. */ - if (cdst & CDCSR_PACK) { + if (cdst & CDCSR_PACK) c = cddb = ccard[currCol] & 0377; - if (Map_WriteB (pa, 1, &c)) - cdst |= CDCSR_NXM; - pa = (pa + 1) & 0777777; - } else { - w = cddb = hcard[currCol] & 07777; - if (Map_WriteW (pa, 2, &w)) - cdst |= CDCSR_NXM; - pa = (pa + 2) & 0777777; + else + w = cddb = hcard[currCol] & 07777; /* Punched zones: <12><11><0><1><2><3><4><5><6><7><8><9> */ + + if (cdcc == 0) /* Transfer requires CC non-zero */ + cdst |= CDCSR_LATE; + else { + if (cdst & CDCSR_PACK) { + if (Map_WriteB (pa, 1, &c)) + cdst |= CDCSR_NXM; + pa = (pa + 1) & 0777777; + } else { + /* "Augmented Image" - provides full column binary and packed encoding in 15 bits. + * Bits <14:12> encode which zone, if any, of 1-7 is punched. 0 => none, otherwise zone #. + * Bit 15 set indicates that more than one punch occured in zones 1-7; in this case the packed + * encoding is not valid. (Card may be binary data.) + * This was probably an ECO to the CD11. TOPS-10/20 depend on it, so it's definitely in the CD20. + */ + if (uptr->flags & UNIT_AIECO) { + uint16 z; + w |= ((ccard[currCol] & 07) << 12); /* Encode zones 1..7 - same as 'packed' format */ + z = w & 0774; + if ((z & -z) != z) /* More than one punch in 1..7 */ + w |= 0100000; /* sets Hollerith (encoding) failure (not an error) */ + } + if (Map_WriteW (pa, 2, &w)) + cdst |= CDCSR_NXM; + pa = (pa + 2) & 0777777; + } + cdba = pa & 0177777; + cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | + ((pa & 0600000) >> 12); + cdcc = (cdcc + 1) & 0177777; + /* Interrupt at end of buffer; read continues to end of card. + * If this is the last column, defer interrupt so end doesn't interrupt again. + */ + if ((cdcc == 0) && (cdst & CSR_IE) && (currCol < colEnd)) + SET_INT (CR); } - cdba = pa & 0177777; - cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | - ((pa & 0600000) >> 12); - cdcc = (cdcc + 1) & 0177777; -#if 0 - if (!(cdst & CSR_IE) && !(crs & CRCSR_CRDDONE)) + } else { /* CR11 */ + /* Handle EJECT bit: if set DO NOT assert COLRDY */ + /* nor interrupt */ + if ((crs & CRCSR_EJECT)) { CLR_INT (CR); -#endif + } else { + crs |= CRCSR_COLRDY; + } } - + /* CD11 and CR11 */ currCol++; /* advance the column counter */ - /* Handle EJECT bit: if set DO NOT assert COLRDY */ - /* nor interrupt */ - if (!(crs & CRCSR_EJECT)) { - crs |= CRCSR_COLRDY; - } else { - CLR_INT (CR); - } + /* Schedule next service cycle */ - sim_activate (uptr, uptr->wait); + sim_activate_after (uptr, uptr->wait); return (SCPE_OK); } @@ -1106,10 +1366,33 @@ t_stat cr_reset ( DEVICE *dptr ) { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_reset\n"); + + if (!translation_help) { + int i; + const char trans_hlp[] = "TRANSLATION={"; + size_t size = sizeof(trans_hlp) +1; + + for ( i = 0; i < NTRANS; i++ ) + size += strlen (transcodes[i].name)+1; + translation_help = (char *)malloc (size ); + strcpy(translation_help, trans_hlp); + for (i = 0; i < NTRANS; i++) { + strcat(translation_help, transcodes[i].name); + strcat(translation_help,"|"); + } + strcpy(translation_help+strlen(translation_help)-1, "}"); + for (i = 0; i < (sizeof cr_mod / sizeof cr_mod[0]); i++ ) + if (cr_mod[i].pstring && !strcmp(cr_mod[i].pstring, "TRANSLATION")) { + cr_mod[i].mstring = translation_help; + break; + } + } cr_unit.buf = 0; currCol = 1; crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_TIMERR|CRCSR_ONLINE|CRCSR_BUSY| CRCSR_COLRDY|CSR_IE|CRCSR_EJECT|CSR_GO); + if (crs & (CRCSR_OFFLINE)) + crs |= CSR_ERR; crb1 = 0; crb2 = 0; crm = 0; @@ -1117,23 +1400,31 @@ t_stat cr_reset ( DEVICE *dptr ) CDCSR_NXM|CSR_IE|CDCSR_XBA17|CDCSR_XBA16|CDCSR_ONLINE| CDCSR_PACK|CSR_GO); cdst |= CDCSR_RDY; + if (cdst & CDCSR_ANYERR) + cdst |= CSR_ERR; cdcc = 0; cdba = 0; cddb = 0; + /* ATTACHed doesn't mean ONLINE; set CR reset (pushing the reset switch) + * is what puts the reader on-line. Reset doesn't control fingers. + */ if ((cr_unit.flags & UNIT_ATT) && !feof (cr_unit.fileref)) { - crs |= CRCSR_ONLINE; /* non-standard */ - crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE); + if (!(crs & CRCSR_OFFLINE)) + crs |= CRCSR_ONLINE; /* non-standard */ + crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY ); cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); + cddbs = 0; } else { cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - crs = CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE; + cddbs |= CDDB_STACK; + crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY; } sim_cancel (&cr_unit); /* deactivate unit */ if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; - sim_activate (&cr_unit, spinDown); + sim_activate_after (&cr_unit, spinDown); } - EOFcard = FALSE; + EOFcard = 0; CLR_INT (CR); /* TBD: flush current card */ /* init uptr->wait ? */ @@ -1166,20 +1457,6 @@ t_stat cr_attach ( UNIT *uptr, setupCardFile(uptr, sim_switches); } - /* Old code, with status bit changes */ - /* - if (!(uptr->flags & UNIT_ATT)) { - crs &= ~CRCSR_ONLINE; - crs |= CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY; - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - } else { - setupCardFile (uptr, sim_switches); - crs |= CRCSR_ONLINE; - crs &= ~(CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY); - cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); - EOFcard = FALSE; - } - */ return (reason); } @@ -1193,11 +1470,12 @@ t_stat cr_detach ( UNIT *uptr ) cardFormat = "unknown"; if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; - sim_activate (uptr, spinDown); + sim_activate_after (uptr, spinDown); } return (detach_unit (uptr)); } +#if defined (CR11_OK) || defined (CD11_OK) || defined (CD20_OK) t_stat cr_set_type ( UNIT *uptr, int32 val, char *cptr, @@ -1206,19 +1484,40 @@ t_stat cr_set_type ( UNIT *uptr, DEVICE *dptr = find_dev_from_unit (uptr); /* disallow type change if currently attached */ + if (uptr->flags & UNIT_ATT) return (SCPE_NOFNC); if (val == UNIT_CR11) { dptr->flags |= DEV_QBUS; /* Can be a Qbus device - programmed I/O only */ - } else { /* CD11 is 18bit DMA device */ + } else { /* CD11/CD20 are 18bit DMA devices */ if (!UNIBUS) return SCPE_NOFNC; dptr->flags &= ~DEV_QBUS; /* Not on a Qbus (22bit) */ } - cpm = (val & UNIT_CR11) ? 285 : 1000; - uptr->wait = (60 * 1000) / cpm; + cpm = (val & UNIT_CR11) ? 285 : ((val & UNIT_CD20)? 1200 :1000); + uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. + * Readers are rated in card/min for 80 column cards */ + transcodes[0].table = (val & UNIT_CD20)? o29_decascii_code : o29_code; + return (SCPE_OK); } +#endif + +#if defined (AIECO_OK) +t_stat cr_set_aieco ( UNIT *uptr, + int32 val, + char *cptr, + void *desc ) +{ + /* disallow eco change if currently attached or not CD20 */ + + if (uptr->flags & UNIT_ATT || !CD20_CTL(uptr)) + return (SCPE_NOFNC); + + uptr->flags = (uptr->flags & ~UNIT_AIECO) | (val & UNIT_AIECO); + return (SCPE_OK); +} +#endif t_stat cr_show_format ( FILE *st, UNIT *uptr, @@ -1240,7 +1539,7 @@ t_stat cr_set_rate ( UNIT *uptr, if (!cptr) return (SCPE_MISVAL); if (strcmp (cptr, "DEFAULT") == 0) - i = (uptr->flags & UNIT_CR11) ? 285 : 1000; + i = CR11_CTL(uptr) ? 285 : (CD20_CTL(uptr)? 1200 :1000); else i = (int32) get_uint (cptr, 10, 0xFFFFFFFF, &status); if (status == SCPE_OK) { @@ -1248,7 +1547,8 @@ t_stat cr_set_rate ( UNIT *uptr, status = SCPE_ARG; else { cpm = i; - uptr->wait = (60 * 1000) / cpm; + uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. + * Readers are rated in card/min for 80 column cards */ } } return (status); @@ -1266,6 +1566,8 @@ t_stat cr_show_rate ( FILE *st, /* simulate pressing the card reader RESET button */ /* Per CR11 docs, transition to ONLINE, reset card */ /* reader logic. */ +/* RESET is somewhat of a misnomer; START is the function */ + t_stat cr_set_reset ( UNIT *uptr, int32 val, char *cptr, @@ -1288,8 +1590,13 @@ t_stat cr_set_reset ( UNIT *uptr, cdst |= CDCSR_ONLINE; cdst &= ~(CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK | CDCSR_HOPPER | CDCSR_EOF); + /* I don't think the hardware clears these errors, but TOPS-10 seems to expect it. + * Since we know the reader is idle, and this is OPR intervention, it seems safe. + */ + cdst &= ~(CDCSR_LATE | CDCSR_NXM); + /* Assert interrupt if interrupts enabled */ - if ((crs & CSR_IE) || (cdst & CSR_IE)) { + if ((CR11_CTL(uptr)?crs : cdst) & CSR_IE) { SET_INT (CR); if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_set_reset setting interrupt\n"); @@ -1303,12 +1610,13 @@ t_stat cr_set_reset ( UNIT *uptr, cdcc = 0; cdba = 0; cddb = 0; - EOFcard = FALSE; + cddbs = 0; + EOFcard = 0; /* start up the blower if the hopper is not empty if (blowerState != BLOW_ON) { blowerState = BLOW_START; - sim_activate(uptr, spinUp); + sim_activate_after(uptr, spinUp); } */ return (SCPE_OK); @@ -1325,9 +1633,9 @@ t_stat cr_set_stop ( UNIT *uptr, fprintf (sim_deb, "set_stop\n"); crs &= ~CRCSR_ONLINE; crs |= CSR_ERR | CRCSR_OFFLINE; - cdst |= CDCSR_OFFLINE; + cdst |= CSR_ERR | CDCSR_OFFLINE; /* CD11 does not appear to interrupt on STOP. */ - if (crs & CSR_IE) + if (CR11_CTL(uptr) && (crs & CSR_IE)) SET_INT (CR); if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; @@ -1335,9 +1643,28 @@ t_stat cr_set_stop ( UNIT *uptr, return (SCPE_OK); } -static const char * const trans[] = { - "unknown", "026", "026FTN", "029", "EBCDIC", "026DEC" -}; +/* simulate pressing the card reader EOF button */ + +t_stat cr_set_eof ( UNIT *uptr, + int32 val, + char *cptr, + void *desc ) +{ + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "set_eof\n"); + eofPending = 1; + + return (SCPE_OK); +} + +t_stat cr_show_eof ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + fprintf (st, (eofPending? "EOF pending": "no EOF pending")); + return (SCPE_OK); +} t_stat cr_set_trans ( UNIT *uptr, int32 val, @@ -1348,17 +1675,14 @@ t_stat cr_set_trans ( UNIT *uptr, if (!cptr) return (SCPE_MISVAL); - if (strcmp (cptr, "DEFAULT") == 0) - i = 3; - else { - for (i = 1; i < 6; i++) { - if (strcmp (cptr, trans[i]) == 0) - break; - } + + for (i = 0; i < NTRANS; i++) { + if (strcmp (cptr, transcodes[i].name) == 0) + break; } - if (i < 1 || i > 5) + if (i >= NTRANS) return (SCPE_ARG); - table = i; + codeTbl = transcodes[i].table; initTranslation (); /* reinitialize tables */ return (SCPE_OK); } @@ -1368,32 +1692,66 @@ t_stat cr_show_trans ( FILE *st, int32 val, void *desc ) { - fprintf (st, "translation=%s", trans[table]); + int i; + for (i = 1; i < NTRANS; i++ ) + if (transcodes[i].table == codeTbl) { + fprintf (st, "translation=%s", transcodes[i].name); + return SCPE_OK; + } + fprintf (st, "translation=%s", transcodes[0].name); return (SCPE_OK); } +/* Only used from here to EOF, so not passing size of string. + * This ugliness is more maintainable than a preprocessor mess. + */ + +static void cr_supported ( char *string, int32 *bits ) +{ +int32 crtypes = 0; +#define MAXDESCRIP sizeof ("CR11/CD11/CD20/") /* sizeof includes \0 */ +char devtype[MAXDESCRIP] = ""; + +#if defined (CR11_ONLY) || defined (CR11_OK) + crtypes |= 1; +#endif +#if defined (CD11_ONLY) || defined (CD11_OK) + crtypes |= 2; +#endif +#if defined (CD20_ONLY) || defined (CD20_OK) + crtypes |= 4; +#endif + +if (string) { + if (crtypes & 1) + strcat (devtype, "CR11/"); + if (crtypes & 2) + strcat (devtype, "CD11/"); + if (crtypes & 4) + strcat (devtype, "CD20/"); + devtype[strlen(devtype)-1] = '\0'; + strcpy (string, devtype); +} +if (bits) + *bits = crtypes; +return; +} + static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -#if defined(VM_PDP11) -char *devtype = "CR11/CD11"; -#else -char *devtype = (DFLT_CR11) ? "CR11" : "CD11"; -#endif +char devtype[MAXDESCRIP]; +int32 crtypes; +cr_supported (devtype, &crtypes); fprintf (st, "%s Card Reader (CR)\n\n", devtype); -#if defined(VM_PDP11) -fprintf (st, "The card reader (CR) implements a single controller (either the CR11 or the\n"); -fprintf (st, "CD11) and a card reader (e.g., Documation M200, GDI Model 100) by reading a\n"); +fprintf (st, "The card reader (CR) implements a single controller (the model(s) shown\n"); +fprintf (st, "above) and a card reader (e.g., Documation M200, GDI Model 100) by reading a\n"); fprintf (st, "file and presenting lines or cards to the simulator. Card decks may be\n"); fprintf (st, "represented by plain text ASCII files, card image files, or column binary\n"); fprintf (st, "files.\n\n"); -#else -fprintf (st, "The card reader (CR) implements a single controller (the %s) and a\n", devtype); -fprintf (st, "card reader (e.g., Documation M200, GDI Model 100) by reading a file and\n"); -fprintf (st, "presenting lines or cards to the simulator. Card decks may be represented\n"); -fprintf (st, "by plain text ASCII files, card image files, or column binary files.\n"); -#endif -fprintf (st, "The CR11 controller is also compatible with the CM11-F, CME11, and CMS11.\n\n"); + +fprintf (st, "The controller is also compatible with the CM11-F, CME11, and CMS11.\n\n"); + fprintf (st, "Card image files are a file format designed by Douglas W. Jones at the\n"); fprintf (st, "University of Iowa to support the interchange of card deck data. These files\n"); fprintf (st, "have a much richer information carrying capacity than plain ASCII files. Card\n"); @@ -1401,43 +1759,64 @@ fprintf (st, "Image files can contain such interchange information as card-stock fprintf (st, "corner cuts, special artwork, as well as the binary punch data representing all\n"); fprintf (st, "12 columns. Complete details on the format, as well as sample code, are\n"); fprintf (st, "available at Prof. Jones's site: http://www.cs.uiowa.edu/~jones/cards/.\n\n"); -#if defined (VM_PDP11) -fprintf (st, "The card reader device an be configured to support either of the two\n"); -fprintf (st, "controllers supported by DEC:\n\n"); -fprintf (st, " SET CR CR11 set controller type to CR11\n"); -fprintf (st, " SET CR CD11 set controller type to CD11\n\n"); -fprintf (st, "The controller type must be set before attaching a virtual card deck to the\n"); -fprintf (st, "device. You may NOT change controller type once a file is attached.\n\n"); -fprintf (st, "The primary differences between these two controllers are summarized in the\n"); -fprintf (st, "table below. By default, CR11 simulation is selected.\n\n"); -fprintf (st, " CR11 CD11\n"); -fprintf (st, " BR 6 4\n"); -fprintf (st, " registers 4 3\n"); -fprintf (st, " data transfer BR DMA\n"); -fprintf (st, " card rate 200-600 1000-1200\n"); -fprintf (st, " hopper cap. <= 1000 1000-2250\n"); -fprintf (st, " cards Mark-sense & punched only\n"); -fprintf (st, " punched\n\n"); -fprintf (st, "The CD11 simulation includes the Rev. J modification to make the CDDB act as\n"); -fprintf (st, "a second status register during non-data transfer periods.\n\n"); + +if ((crtypes & -crtypes) != crtypes) { + fprintf (st, "The card reader device an be configured to emulate the following\n"); + fprintf (st, "controller models with these commands:\n\n"); + if (crtypes & 1) + fprintf (st, " SET CR CR11 set controller type to CR11\n"); + if (crtypes & 2) + fprintf (st, " SET CR CD11 set controller type to CD11\n"); + if (crtypes & 4) { + fprintf (st, " SET CR CD20 set controller type to CD20\n"); +#if defined (AIECO_OK) + fprintf (st, " SET CR AIECO emulate the CD20 \"augmented image\" ECO\n"); + fprintf (st, " default is %semulated.\n", (DFLT_AIECO? "":"not ")); #endif -fprintf (st, "Examples of the CR11 include the M8290 and M8291 (CMS11). All card readers use\n"); -fprintf (st, "a common vector at 0230 and CSR at 177160. Even though the CR11 is normally\n"); -fprintf (st, "configured as a BR6 device, it is configured for BR4 in this simulation.\n\n"); +} + fprintf (st, "\nThe controller type must be set before attaching a virtual card deck to the\n"); + fprintf (st, "device. You may NOT change controller type once a file is attached.\n\n"); + fprintf (st, "The primary differences between the controllers are summarized in the\n"); + fprintf (st, "table below. By default, %s simulation is selected.\n\n", + (DFLT_TYPE & UNIT_CD20)? "CD20": ((DFLT_TYPE & UNIT_CR11)? "CR11" : "CD11")); + fprintf (st, " CR11 CD11/CD20\n"); + fprintf (st, " BR 6 4\n"); + fprintf (st, " registers 4 3\n"); + fprintf (st, " data transfer BR DMA\n"); + fprintf (st, " card rate 200-600 1000-1200\n"); + fprintf (st, " hopper cap. <= 1000 1000-2250\n"); + fprintf (st, " cards Mark-sense & punched only\n"); + fprintf (st, " punched\n\n"); + fprintf (st, "The CD11 simulation includes the Rev. J modification to make the CDDB act as\n"); + fprintf (st, "a second status register during non-data transfer periods.\n\n"); +} +if (crtypes & 1) { + fprintf (st, "Examples of the CR11 include the M8290 and M8291 (CMS11). All card readers use\n"); + fprintf (st, "a common vector at 0230 and CSR at 177160. Even though the CR11 is normally\n"); + fprintf (st, "configured as a BR6 device, it is configured for BR4 in this simulation.\n\n"); +} fprintf (st, "The card reader supports ASCII, card image, and column binary format card\n"); fprintf (st, "\"decks.\" When reading plain ASCII files, lines longer than 80 characters are\n"); fprintf (st, "silently truncated. Card image support is included for 80 column Hollerith,\n"); -fprintf (st, "82 column Hollerith (silently ignoring columns 0 and 81), and 40 column\n"); -fprintf (st, "Hollerith (mark-sense) cards. Column binary supports 80 column card images\n"); -fprintf (st, "only. All files are attached read-only (as if the -R switch were given).\n\n"); +fprintf (st, "82 column Hollerith, and 40 column Hollerith (mark-sense) cards. \n"); +fprintf (st, "Column binary supports 80 column card images only.\n"); +if (crtypes & 6) { + fprintf (st, "The CD11/CD20 optionally check columns 0/81/41 for punches, which produce\n"); + fprintf( st, "read check errors. As verifiers may produce these, this can be controlled:\n"); + fprintf( st, " SET CR RDCHECK - Enable read check errors (default)\n"); + fprintf( st, " SET CR NORDCHECK - Disable read check errors\n\n"); +} +fprintf (st, "All files are attached read-only (as if the -R switch were given).\n"); fprintf (st, " ATTACH -A CR file is ASCII text\n"); fprintf (st, " ATTACH -B CR file is column binary\n"); fprintf (st, " ATTACH -I CR file is card image format\n\n"); + fprintf (st, "If no flags are given, the file extension is evaluated. If the filename ends\n"); fprintf (st, "in .TXT, the file is treated as ASCII text. If the filename ends in .CBN, the\n"); fprintf (st, "file is treated as column binary. Otherwise, the CR driver looks for a card\n"); fprintf (st, "image header. If a correct header is found the file is treated as card image\n"); fprintf (st, "format, otherwise it is treated as ASCII text.\n\n"); + fprintf (st, "The correct character translation MUST be set if a plain text file is to be\n"); fprintf (st, "used for card deck input. The correct translation SHOULD be set to allow\n"); fprintf (st, "correct ASCII debugging of a card image or column binary input deck. Depending\n"); @@ -1445,28 +1824,46 @@ fprintf (st, "upon the operating system in use, how it was generated, and how th fprintf (st, "will be read and used, the translation must be set correctly so that the proper\n"); fprintf (st, "character set is used by the driver. Use the following command to explicitly\n"); fprintf (st, "set the correct translation:\n\n"); -fprintf (st, " SET TRANSLATION={DEFAULT|026|026FTN|026DEC|029|EBCDIC}\n\n"); +fprintf (st, " SET TRANSLATION={DEFAULT|026|026FTN|026DEC|026DECASCII|029|029DECASCII|EBCDIC}\n\n"); fprintf (st, "This command should be given after a deck is attached to the simulator. The\n"); fprintf (st, "mappings above are completely described at\n"); fprintf (st, " http://www.cs.uiowa.edu/~jones/cards/codes.html.\n"); -fprintf (st, "Note that DEC typically used 029 or 026FTN mappings.\n\n"); +fprintf (st, "Note that early DEC software typically used 029 or 026FTN mappings.\n"); +fprintf (st, "Later systems used the 026DECASCII and/or 029DECASCII mappings, which include all 7-bit ASCII characters\n"); fprintf (st, "DEC operating systems used a variety of methods to determine the end of a deck\n"); fprintf (st, "(recognizing that 'hopper empty' does not necessarily mean the end of a deck.\n"); fprintf (st, "Below is a summary of the various operating system conventions for signaling\n"); -fprintf (st, "end of deck:\n\n"); +fprintf (st, "end of deck (or end of file with multi-file batch systems):\n\n"); fprintf (st, " RT-11: 12-11-0-1-6-7-8-9 punch in column 1\n"); fprintf (st, " RSTS/E: 12-11-0-1 or 12-11-0-1-6-7-8-9 punch in column 1\n"); fprintf (st, " RSX: 12-11-0-1-6-7-8-9 punch in first 8 columns\n"); fprintf (st, " VMS: 12-11-0-1-6-7-8-9 punch in first 8 columns\n"); fprintf (st, " TOPS: 12-11-0-1 or 12-11-0-1-6-7-8-9 punch in column 1\n\n"); fprintf (st, "Using the AUTOEOF setting, the card reader can be set to automatically generate\n"); -fprintf (st, "an EOF card consisting of the 12-11-0-1-6-7-8-9 punch in columns 1-8. When set\n"); -fprintf (st, "to CD11 mode, this switch also enables automatic setting of the EOF bit in the\n"); -fprintf (st, "controller after the EOF card has been processed. [The CR11 does not have a\n"); -fprintf (st, "similar capability.] By default AUTOEOF is enabled.\n\n"); -fprintf (st, "The default card reader rate for the CR11 is 285 cpm. The reader rate can be\n"); -fprintf (st, "set to its default value or to anywhere in the range 200 to 1200 cpm. This\n"); -fprintf (st, "rate may be changed while the unit is attached.\n\n"); +fprintf (st, "an EOF card consisting of the 12-11-0-1-6-7-8-9 punch in columns 1-8. "); +if (crtypes & 6) { + fprintf (st, "When set,\nThe %s ", ((crtypes & 6) == 2)? "CD11": ((crtypes & 6) == 4)? "CD20": "CD11/CD20"); + + fprintf (st, "will automatically set the EOF bit in the\n"); + fprintf (st, "controller after the EOF card has been processed. By default AUTOEOF is enabled.\n"); + fprintf (st, "The controller also supports an EOF switch that will set the EOF bit when the\n"); + fprintf (st, "hopper empties. The switch resets each time the hopper empties. The SET EOF command emulates this.\n"); + if (crtypes &1) + fprintf (st, "The CR11 does not support the EOF switch/bit.\n"); + else + fprintf (st, "\n"); +} +fprintf (st, "The default card reader rate for the "); +if (crtypes & 4) { + fprintf (st, "CD20 is 1200"); + if (crtypes != 4) + fprintf (st, " and for the "); +} +if (crtypes & 3) + fprintf (st, "CR/CD11 is 285"); +fprintf (st, " cpm.\n"); +fprintf (st, "The reader rate can be set to its default value or to anywhere in the range\n"); +fprintf (st, "of 200 to 1200 cpm.This rate may be changed while the unit is attached.\n\n"); fprintf (st, "It is standard operating procedure for operators to load a card deck and press\n"); fprintf (st, "the momentary action RESET button to clear any error conditions and alert the\n"); fprintf (st, "processor that a deck is available to read. Use the SET CR RESET command to\n"); @@ -1478,15 +1875,18 @@ fprintf (st, "simulate pressing the card reader STOP button.\n\n"); fprintf (st, "The simulator does not support the BOOT command. The simulator does not\n"); fprintf (st, "stop on file I/O errors. Instead the controller signals a reader check to\n"); fprintf (st, "the CPU.\n"); + fprint_reg_help (st, dptr); return SCPE_OK; } char *cr_description (DEVICE *dptr) - { -#if defined(VM_PDP11) - return "CR11/CD11 card reader"; -#else - return (DFLT_CR11) ? "CR11 card reader" : "CD11 card reader"; -#endif - } +{ + /* Not thread-safe, but malloc() would be leak. */ + static char desc[MAXDESCRIP+sizeof(" card reader")-1] = ""; + if (desc[0] == '\0') { + cr_supported (desc, NULL); + strcat (desc, " card reader"); + } + return desc; +} diff --git a/PDP11/pdp11_cr_dat.h b/PDP11/pdp11_cr_dat.h index d8342f58..2dce182a 100644 --- a/PDP11/pdp11_cr_dat.h +++ b/PDP11/pdp11_cr_dat.h @@ -10,14 +10,14 @@ * * author: Douglas Jones, jones@cs.uiowa.edu * revisions: - * March 5, 1996 - * Feb 18, 1997 to add 026 and EBCDIC converstion tables - * Jan 10, 2005, (JAD) Added 'static const' to the array - * definitions. - * Jan 11, 2005, (JAD) Create the h2c_code array. - * Jan 14, 2005, (JAD) Added the special DEC code for 'end of deck' - * (12-11-0-1-6-7-8-9) to the o29_code array at position 26. (^Z). - * Should I add this to the other arrays? + * March 5, 1996 + * Feb 18, 1997 to add 026 and EBCDIC converstion tables + * Jan 10, 2005, (JAD) Added 'static const' to the array + * definitions. + * Jan 11, 2005, (JAD) Create the h2c_code array. + * Jan 14, 2005, (JAD) Added the special DEC code for 'end of deck' + * (12-11-0-1-6-7-8-9) to the o29_code array at position 26. (^Z). + * Should I add this to the other arrays? * Feb 24, 2007, (JGP) Added the DEC version of the 026 codepage and * fixed some DEC029 codes. */ @@ -28,618 +28,655 @@ translate lower case to upper case. As a result of this modification, inversion of this table should be done with care! */ static const int o29_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,04006,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ - 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,04202,02006,02202,04006,01022, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,04000,ERROR,02000,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,04006,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ + 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,04202,02006,02202,04006,01022, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,04000,ERROR,02000,ERROR,ERROR /* xyz{|}~ */ + }; /* Bare bones 026 kepunch encodings */ static const int o26_ftn_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,ERROR,ERROR,ERROR,02102,ERROR,ERROR,00042, /* !"#$%&' */ - 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,ERROR,ERROR,ERROR,00102,ERROR,ERROR, /* 89:;<=>? */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,ERROR,ERROR,ERROR,02102,ERROR,ERROR,00042, /* !"#$%&' */ + 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,ERROR,ERROR,ERROR,00102,ERROR,ERROR, /* 89:;<=>? */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ + }; static const int o26_comm_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,ERROR,ERROR,00102,02102,01042,04000,ERROR, /* !"#$%&' */ - ERROR,ERROR,02042,ERROR,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,ERROR,ERROR,04042,ERROR,ERROR,ERROR, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,ERROR,ERROR,00102,02102,01042,04000,ERROR, /* !"#$%&' */ + ERROR,ERROR,02042,ERROR,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,ERROR,ERROR,04042,ERROR,ERROR,ERROR, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ + }; /* 026DEC translation, according to RSX-11M-PLUS and Micro/RSX */ /* I/O Drivers Reference manual - AA-JS11A-TC */ static const int o26_dec_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,04006,01022,01102,02102,01006,02006,00012, /* !"#$%&' */ - 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,02202,01202,04012,00102,02012,04202, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,02022,00006,04022,00022,00202, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,04000,ERROR,02000,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,04006,01022,01102,02102,01006,02006,00012, /* !"#$%&' */ + 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,02202,01202,04012,00102,02012,04202, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,02022,00006,04022,00022,00202, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,04000,ERROR,02000,ERROR,ERROR /* xyz{|}~ */ + }; /* FULL EBCDIC, from Appendix C of System 360 Programming by Alex Thomas, 1977, Reinhart Press, San Francisco. Codes not in that table have been left compatable with DEC's 029 table. Some control codes have been left out */ static const int EBCDIC_code[] = { - 05403,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - 02011,04021,01021,ERROR,04041,02021,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,01201,ERROR,ERROR,ERROR, /* chars */ - 00000,02202,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ - 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,04202,02006,01202,04006,01022, /* XYZ[\]^_ */ - ERROR,05400,05200,05100,05040,05020,05010,05004, /* `abcdefg */ - 05002,05001,06400,06200,06100,06040,06020,06010, /* hijklmno */ - 06004,06002,06001,03200,03100,03040,03020,03010, /* pqrstuvw */ - 03004,03002,03001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; - -static const int h2c_code[4096] = { - 0000, 0020, 0010, 0030, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0004, 0024, 0014, 0034, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0002, 0022, 0012, 0032, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0001, 0021, 0011, 0031, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0040, 0060, 0050, 0070, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0044, 0064, 0054, 0074, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0042, 0062, 0052, 0072, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0041, 0061, 0051, 0071, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0100, 0120, 0110, 0130, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0104, 0124, 0114, 0134, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0102, 0122, 0112, 0132, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0101, 0121, 0111, 0131, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0140, 0160, 0150, 0170, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0144, 0164, 0154, 0174, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0142, 0162, 0152, 0172, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0141, 0161, 0151, 0171, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0200, 0220, 0210, 0230, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0204, 0224, 0214, 0234, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0202, 0222, 0212, 0232, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0201, 0221, 0211, 0231, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0240, 0260, 0250, 0270, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0244, 0264, 0254, 0274, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0242, 0262, 0252, 0272, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0241, 0261, 0251, 0271, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0300, 0320, 0310, 0330, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0304, 0324, 0314, 0334, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0302, 0322, 0312, 0332, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0301, 0321, 0311, 0331, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0340, 0360, 0350, 0370, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0344, 0364, 0354, 0374, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0342, 0362, 0352, 0372, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0341, 0361, 0351, 0371, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 05403,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + 02011,04021,01021,ERROR,04041,02021,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,01201,ERROR,ERROR,ERROR, /* chars */ + 00000,02202,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ + 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,04202,02006,01202,04006,01022, /* XYZ[\]^_ */ + ERROR,05400,05200,05100,05040,05020,05010,05004, /* `abcdefg */ + 05002,05001,06400,06200,06100,06040,06020,06010, /* hijklmno */ + 06004,06002,06001,03200,03100,03040,03020,03010, /* pqrstuvw */ + 03004,03002,03001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ + }; +/* DEC's 026 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ +static const int o26_decascii_code[] = { + 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, + 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, + 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, + 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, + 00000, 04006, 01022, 01012, 02102, 01006, 02006, 00012, + 01042, 04042, 02042, 04000, 01102, 02000, 04102, 01400, + 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, + 00002, 00001, 02202, 01202, 04012, 00102, 02012, 04202, + 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, + 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, + 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, + 01004, 01002, 01001, 02022, 00006, 04022, 00022, 00202, + 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, + 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, + 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, + 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, +}; +/* DEC's 029 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ +static const int o29_decascii_code[] = { + 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, + 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, + 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, + 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, + 00000, 04006, 00006, 00102, 02102, 01042, 04000, 00022, + 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400, + 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, + 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006, + 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, + 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, + 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, + 01004, 01002, 01001, 04202, 01202, 02202, 02006, 01022, + 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, + 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, + 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, + 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, +}; +static const int h2c_code[4096] = { + 0000, 0020, 0010, 0030, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0004, 0024, 0014, 0034, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0002, 0022, 0012, 0032, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0001, 0021, 0011, 0031, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0040, 0060, 0050, 0070, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0044, 0064, 0054, 0074, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0042, 0062, 0052, 0072, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0041, 0061, 0051, 0071, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0100, 0120, 0110, 0130, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0104, 0124, 0114, 0134, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0102, 0122, 0112, 0132, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0101, 0121, 0111, 0131, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0140, 0160, 0150, 0170, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0144, 0164, 0154, 0174, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0142, 0162, 0152, 0172, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0141, 0161, 0151, 0171, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0200, 0220, 0210, 0230, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0204, 0224, 0214, 0234, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0202, 0222, 0212, 0232, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0201, 0221, 0211, 0231, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0240, 0260, 0250, 0270, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0244, 0264, 0254, 0274, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0242, 0262, 0252, 0272, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0241, 0261, 0251, 0271, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0300, 0320, 0310, 0330, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0304, 0324, 0314, 0334, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0302, 0322, 0312, 0332, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0301, 0321, 0311, 0331, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0340, 0360, 0350, 0370, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0344, 0364, 0354, 0374, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0342, 0362, 0352, 0372, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0341, 0361, 0351, 0371, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, }; diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 222ef3c0..e6b180fd 100644 --- a/PDP11/pdp11_dc.c +++ b/PDP11/pdp11_dc.c @@ -278,7 +278,7 @@ if (ln > DCX_MAXMUX) /* validate line number switch ((PA >> 1) & 03) { /* decode PA<2:1> */ case 00: /* dci csr */ - if (dci_csr[ln] & DCICSR_ALLERR) + if (dci_csr[ln] & DCICSR_ALLERR) dci_csr[ln] |= DCICSR_ERR; else dci_csr[ln] &= ~DCICSR_ERR; *data = dci_csr[ln] & DCICSR_RD; diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index e1eecd2f..9fde51a3 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -484,7 +484,6 @@ typedef struct { #define DCX_LINES 16 /* max # of DC11's */ #define DUP_LINES 8 /* max # of DUP11/DPV11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ #define DIB_MAX 100 /* max DIBs */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ diff --git a/PDP11/pdp11_dmc.c b/PDP11/pdp11_dmc.c index ae74ad53..d01cdf56 100644 --- a/PDP11/pdp11_dmc.c +++ b/PDP11/pdp11_dmc.c @@ -906,7 +906,7 @@ t_stat dmc_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cp fprintf (st, "The communication line performs input and output through a TCP session\n"); fprintf (st, "connected to a user-specified port. The ATTACH command specifies the"); fprintf (st, "port to be used:\n\n"); - fprintf (st, " sim> ATTACH %s {interface:}port set up listening port\n\n", dptr->name); + fprintf (st, " sim> ATTACH %s {interface:}port set up listening port\n\n", dptr->name); fprintf (st, "where port is a decimal number between 1 and 65535 that is not being used for\n"); fprintf (st, "other TCP/IP activities. An ATTACH is required even if in PRIMARY mode. \n\n"); return SCPE_OK; diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index 50a1e4b3..c1aeeb3f 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -897,15 +897,15 @@ fprintf (st, "%s Terminal Multiplexer (DZ)\n\n", devtype); fprintf (st, "The %s is a %d line terminal multiplexor. Up to %d %s's (%d lines) are\n", devtype, DZ_LINES, MAX_DZ_MUXES, devtype, DZ_LINES*MAX_DZ_MUXES); fprintf (st, "supported. The default number of lines is %d. The number of lines can\n", DZ_LINES*DZ_MUXES); fprintf (st, "be changed with the command\n\n"); -fprintf (st, " sim> SET %s LINES=n set line count to n\n\n", dptr->name); +fprintf (st, " sim> SET %s LINES=n set line count to n\n\n", dptr->name); fprintf (st, "The line count must be a multiple of %d, with a maximum of %d.\n\n", DZ_LINES, DZ_LINES*MAX_DZ_MUXES); fprintf (st, "The %s supports three character processing modes, 7P, 7B, and 8B:\n\n", devtype); -fprintf (st, " mode input characters output characters\n"); -fprintf (st, " =============================================\n"); -fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n"); -fprintf (st, " non-printing characters suppressed\n"); -fprintf (st, " 7B high-order bit cleared high-order bit cleared\n"); -fprintf (st, " 8B no changes no changes\n\n"); +fprintf (st, " mode input characters output characters\n"); +fprintf (st, " =============================================\n"); +fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n"); +fprintf (st, " non-printing characters suppressed\n"); +fprintf (st, " 7B high-order bit cleared high-order bit cleared\n"); +fprintf (st, " 8B no changes no changes\n\n"); fprintf (st, "The default is 8B.\n\n"); fprintf (st, "The %s supports logging on a per-line basis. The command\n\n", devtype); fprintf (st, " sim> SET %s LOG=n=filename\n\n", dptr->name); @@ -921,9 +921,9 @@ fprintf (st, "are Telnet connections. The connection remains open until disconn fprintf (st, "simulated program, the Telnet client, a SET %s DISCONNECT command, or a\n", dptr->name); fprintf (st, "DETACH %s command.\n\n", dptr->name); fprintf (st, "Other special %s commands:\n\n", dptr->name); -fprintf (st, " sim> SHOW %s CONNECTIONS show current connections\n", dptr->name); -fprintf (st, " sim> SHOW %s STATISTICS show statistics for active connections\n", dptr->name); -fprintf (st, " sim> SET %s DISCONNECT=linenumber disconnects the specified line.\n\n\n", dptr->name); +fprintf (st, " sim> SHOW %s CONNECTIONS show current connections\n", dptr->name); +fprintf (st, " sim> SHOW %s STATISTICS show statistics for active connections\n", dptr->name); +fprintf (st, " sim> SET %s DISCONNECT=linenumber disconnects the specified line.\n\n\n", dptr->name); fprintf (st, "All open connections are lost when the simulator shuts down or the %s is\n", dptr->name); fprintf (st, "detached.\n\n"); dz_help_attach (st, dptr, uptr, flag, cptr); @@ -937,7 +937,7 @@ char *devtype = (UNIBUS) ? "DZ11" : "DZV11"; tmxr_attach_help (st, dptr, uptr, flag, cptr); fprintf (st, "The terminal lines perform input and output through Telnet sessions connected\n"); fprintf (st, "to a user-specified port. The ATTACH command specifies the port to be used:\n\n"); -fprintf (st, " sim> ATTACH {-am} %s {interface:}port set up listening port\n\n", dptr->name); +fprintf (st, " sim> ATTACH {-am} %s {interface:}port set up listening port\n\n", dptr->name); fprintf (st, "where port is a decimal number between 1 and 65535 that is not being used for\n"); fprintf (st, "other TCP/IP activities. The optional switch -m turns on the %s's modem\n", devtype); fprintf (st, "controls; the optional switch -a turns on active disconnects (disconnect\n"); diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 4b8a9993..ad08bab1 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -745,7 +745,7 @@ if (IR & 000740) { /* defined? */ if (CPUT (CPUT_03)) /* 11/03 reads word */ ReadW (exta | R[reg]); ABORT (TRAP_ILL); - } + } FEC = 0; /* no errors */ FPS = FPS_IU|FPS_IV; /* trap ovf,unf */ @@ -782,7 +782,7 @@ switch ((IR >> 3) & 3) { /* case IR<5:3> */ V = N = C = 1; /* set cc's */ setTRAP (TRAP_FPE); /* set trap */ return SCPE_OK; - } + } else divfp11 (&fac, &fsrc); break; } diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index 247e6b26..e997e86b 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -214,7 +214,7 @@ BITFIELD hk_da_bits[] = { #define CS2_MBZ (CS2_CLR) #define CS2_RW 0000037 #define CS2_ERR (CS2_UFE | CS2_MDS | CS2_PGE | CS2_NEM | \ - CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) + CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) #define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT) BITFIELD hk_cs2_bits[] = { @@ -959,9 +959,9 @@ if (fnc_cyl[fnc] && /* need valid cyl */ ((GET_CY (hkdc) >= HK_CYL (uptr)) || /* bad cylinder */ (GET_SF (hkda) >= HK_NUMSF) || /* bad surface */ (GET_SC (hkda) >= HK_NUMSC))) { /* or bad sector? */ - hk_cmderr (ER_IAE, drv); /* illegal addr */ - return; - } + hk_cmderr (ER_IAE, drv); /* illegal addr */ + return; + } hkcs1 = (hkcs1 | CS1_GO) & ~CS1_DONE; /* set go, clear done */ switch (fnc) { /* case on function */ @@ -1144,7 +1144,7 @@ switch (fnc) { /* case on function */ for (i = wc; i < awc; i++) /* fill buf */ hkxb[i] = 0; if (wc && !err) { /* write buf */ - fxwrite (hkxb, sizeof (uint16), wc, uptr->fileref); + fxwrite (hkxb, sizeof (uint16), awc, uptr->fileref); err = ferror (uptr->fileref); } } /* end if wr */ diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 0c69b1d6..2f3ca19d 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -298,9 +298,77 @@ t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) uint32 i, j; DEVICE *dptr; DIB *dibp; +uint32 maxaddr, maxname; +int32 maxvec, vecwid; +char valbuf[40]; if (build_dib_tab ()) /* build IO page */ return SCPE_OK; + +maxaddr = 0; +maxvec = 0; +maxname = 0; + +for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ + size_t l; + if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ + dibp = iodibp[i]; /* DIB for block */ + for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { + if (((DIB*) sim_devices[j]->ctxt) == dibp) { + dptr = sim_devices[j]; /* locate device */ + break; + } /* end if */ + } /* end for j */ + if ((dibp->ba+ dibp->lnt - 1) > maxaddr) + maxaddr = dibp->ba+ dibp->lnt - 1; + if (dibp->vec > maxvec) + maxvec = dibp->vec; + l = strlen (dptr? sim_dname (dptr): "CPU"); + if (l>maxname) + maxname = (int32)l; + } /* end if */ + } /* end for i */ +maxaddr = fprint_val (NULL, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); +sprintf (valbuf, "%03o", maxvec); +vecwid = maxvec = (int32) strlen (valbuf); +if (vecwid < 3) + vecwid = 3; + +j = strlen ("Address"); +i = (maxaddr*2)+3+1; +if (i <= j) + i = 0; +else + i -= j; +maxaddr = i+j; +fprintf (st, "%*.*sAddress%*.*s", i/2, i/2, " ", (i/2)+i%2, (i/2)+i%2, " "); + +j = strlen ("Vector"); +i = ((maxvec*2)+1+1); +if (i <= j) + i = 0; +else + i -= j; +maxvec = i+j; +fprintf (st, " %*.*sVector%*.*s", i/2, i/2, " ", (i/2)+i%2, (i/2)+i%2, " "); + +fprintf (st, " BR Device\n"); +for (i = 0; i < maxaddr; i++) + fputc ('-', st); +fprintf (st, " "); +for (i = 0; i < (uint32)maxvec; i++) + fputc ('-', st); + +fprintf (st, " -- "); + +i = strlen ("Device"); +if (maxname < i) + maxname = i; + +for (i = 0; i < maxname; i++) + fputc ('-', st); +fputc ('\n', st); + for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ dibp = iodibp[i]; /* DIB for block */ @@ -313,9 +381,23 @@ for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); fprintf (st, " - "); fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT); - fprintf (st, "%c\t%s\n", /* print block entry */ - (dibp->ba < IOPAGEBASE + AUTO_CSRBASE + AUTO_CSRMAX)? '*': ' ', - dptr? sim_dname (dptr): "CPU"); + fprintf (st, "%c ", /* print block entry */ + (dibp->ba < IOPAGEBASE + AUTO_CSRBASE + AUTO_CSRMAX)? '*': ' '); + if (dibp->vec == 0) + fprintf (st, "%*s", ((vecwid*2)+1+1), " "); + else { + fprintf (st, "%0*o", vecwid, dibp->vec); + if (dibp->vnum > 1) + fprintf (st, "-%0*o", vecwid, dibp->vec + (4 * (dibp->vnum - 1))); + else + fprintf (st, " %*s", vecwid, " "); + fprintf (st, "%1s", (dibp->vnum >= AUTO_VECBASE)? "*": " "); + } + if (dibp->vnum || dibp->vloc) + fprintf (st, " %2u", dibp->vloc/32); + else + fprintf (st, " "); + fprintf (st, " %s\n", dptr? sim_dname (dptr): "CPU"); } /* end if */ } /* end for i */ return SCPE_OK; @@ -497,7 +579,7 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */ {017340}, {0214} }, /* TC11 */ { { "TA" }, 1, 1, 0, 0, {017500}, {0260} }, /* TA11 */ - { { NULL }, 1, 2, 64, 8, + { { "QVSS" }, 1, 2, 64, 8, {017200} }, /* QVSS - fx CSR */ { { NULL }, 1, 1, 8, 4 }, /* VS31 */ { { NULL }, 1, 1, 0, 4, diff --git a/PDP11/pdp11_ke.c b/PDP11/pdp11_ke.c index d2c91058..6a302381 100644 --- a/PDP11/pdp11_ke.c +++ b/PDP11/pdp11_ke.c @@ -38,13 +38,13 @@ /* KE11A I/O address offsets 0177300 - 0177316 */ #define KE_DIV 000 /* divide */ -#define KE_AC 002 /* accumulator */ -#define KE_MQ 004 /* MQ */ -#define KE_MUL 006 /* multiply */ -#define KE_SC 010 /* step counter */ -#define KE_NOR 012 /* normalize */ -#define KE_LSH 014 /* logical shift */ -#define KE_ASH 016 /* arithmetic shift */ +#define KE_AC 002 /* accumulator */ +#define KE_MQ 004 /* MQ */ +#define KE_MUL 006 /* multiply */ +#define KE_SC 010 /* step counter */ +#define KE_NOR 012 /* normalize */ +#define KE_LSH 014 /* logical shift */ +#define KE_ASH 016 /* arithmetic shift */ /* Status register */ @@ -76,7 +76,7 @@ uint32 ke_set_SR (void); DIB ke_dib = { IOBA_AUTO, IOLN_KE, &ke_rd, &ke_wr, 0 }; UNIT ke_unit = { - UDATA (NULL, UNIT_DISABLE, 0) + UDATA (NULL, UNIT_DISABLE, 0) }; REG ke_reg[] = { @@ -237,9 +237,9 @@ switch (PA & 017) { /* decode PA<3:0> */ case KE_NOR: /* normalize */ for (ke_SC = 0; ke_SC < 31; ke_SC++) { /* max 31 shifts */ - if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */ + if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */ (GET_SIGN_W (ke_AC ^ (ke_AC << 1)))) /* AC<15> != AC<14>? */ - break; + break; ke_AC = ((ke_AC << 1) | (ke_MQ >> 15)) & DMASK; ke_MQ = (ke_MQ << 1) & DMASK; } diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c index c79d41a6..e11c7195 100644 --- a/PDP11/pdp11_rf.c +++ b/PDP11/pdp11_rf.c @@ -366,7 +366,7 @@ do { update_rfcs (0, RFDAE_NXM); break; } - fbuf[da] = dat; /* write word */ + fbuf[da] = dat; /* write word */ rf_dbr = dat; if (da >= uptr->hwmark) uptr->hwmark = da + 1; diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index af865465..4c71319a 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -430,9 +430,9 @@ if (((uptr->flags & UNIT_ATT) == 0) || /* not att or busy? */ } if ((rkcs & RKCS_FMT) && /* format and */ (func != RKCS_READ) && (func != RKCS_WRITE)) { /* not read or write? */ - rk_set_done (RKER_PGE); - return; - } + rk_set_done (RKER_PGE); + return; + } if ((func == RKCS_WRITE) && /* write and locked? */ (uptr->flags & UNIT_WPRT)) { rk_set_done (RKER_WLK); @@ -650,7 +650,7 @@ if (error != 0) { rkcs = rkcs | RKCS_ERR; if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR; - } + } if (rkcs & CSR_IE) { /* int enable? */ rkintq = rkintq | RK_CTLI; /* set ctrl int */ SET_INT (RK); /* request int */ diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 22ffbc8a..99bcd817 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -175,7 +175,7 @@ extern UNIT cpu_unit; #define RLCS_WRITE (5) #define RLCS_READ (6) #define RLCS_RNOHDR (7) -#define RLCS_SPECIAL (8) /* internal function, drive state */ +#define RLCS_SPECIAL (8) /* internal function, drive state */ #define RLCS_V_FUNC (1) #define RLCS_M_MEX (03) /* memory extension */ #define RLCS_V_MEX (4) @@ -381,11 +381,11 @@ static const char * const state[] = { /* I/O dispatch routines, I/O addresses 17774400 - 17774411 - 17774400 RLCS read/write - 17774402 RLBA read/write - 17774404 RLDA read/write - 17774406 RLMP read/write - 17774410 RLBAE read/write + 17774400 RLCS read/write + 17774402 RLBA read/write + 17774404 RLDA read/write + 17774406 RLMP read/write + 17774410 RLBAE read/write */ t_stat rl_rd (int32 *data, int32 PA, int32 access) @@ -395,7 +395,7 @@ UNIT *uptr; switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); + rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); /* The DRDY signal is sent by the selected drive to indicate that it is ready to read or write or seek. It is sent when the heads are @@ -513,7 +513,7 @@ bit is cleared by software. If set, check for interrupts and return. if (newc != curr) uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SEEK; /* move the positioner */ /* TBD: if a head switch, sector should be RL_NUMSC/2? */ - uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ + uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0); /* Real timing: @@ -782,7 +782,7 @@ was removed in a later ECO. uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_BRUSH; } else { uptr->STAT |= RLDS_BHO; - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; } sim_activate (uptr, 200 * rl_swait); break; @@ -810,7 +810,7 @@ Initiated by depressing the Run (LOAD) switch. */ case RLDS_UNL: /* unload pressed, heads unloaded, spin down */ uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_DOWN; - uptr->STAT &= ~RLDS_HDO; /* retract heads */ + uptr->STAT &= ~RLDS_HDO; /* retract heads */ /* actual time is ~30 seconds */ sim_activate (uptr, 200 * rl_swait); break; @@ -866,7 +866,7 @@ if (uptr->FNC == RLCS_RNOHDR) { } else { /* bad cyl or sector? */ if (((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL)) || (GET_SECT (rlda) >= RL_NUMSC)) { - rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ + rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ return (SCPE_OK); } da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ @@ -1148,7 +1148,7 @@ t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc) t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) { char *s = "RLV12"; - + if (UNIBUS) s = "RL11"; else if (rl_dev.flags & DEV_RLV11) diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index 09fa42b4..d66391a7 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -31,7 +31,7 @@ to boot. 17-May-07 RMS CS1 DVA resides in device, not MBA 21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter - 12-Nov-05 RMS Fixed DriveClear, does not clear disk address + 12-Nov-05 RMS Fixed DriveClear, does not clear disk address 16-Aug-05 RMS Fixed C++ declaration and cast problems 18-Mar-05 RMS Added attached test to detach routine 12-Sep-04 RMS Cloned from pdp11_rp.c diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index ca782439..e00ce750 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1448,7 +1448,7 @@ if (cp->csta < CST_UP) { /* still init? */ if ((cp->saw & SA_S4H_LF) && cp->perr) rq_plf (cp, cp->perr); cp->perr = 0; - } + } break; } /* end switch */ @@ -1675,9 +1675,9 @@ if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */ (tpkt = uptr->cpkt) && /* queued pkt? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ (GETP (tpkt, CMD_OPC, OPC) >= OP_ACC)) { /* rd/wr cmd? */ - cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL]; - cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH]; - } + cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL]; + cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH]; + } else { cp->pak[pkt].d[GCS_STSL] = 0; /* return 0 */ cp->pak[pkt].d[GCS_STSH] = 0; @@ -3094,7 +3094,7 @@ fprintf (st, "ability to set units write enabled or write locked, and to set the fprintf (st, "type to one of many disk types:\n"); fprint_set_help (st, dptr); fprintf (st, "set RQn RAUSER{=n} Set disk type to RA82 with n MB's\n"); -fprintf (st, "set -L RQn RAUSER{=n} Set disk type to RA82 with n LBN's\n\n"); +fprintf (st, "set -L RQn RAUSER{=n} Set disk type to RA82 with n LBN's\n\n"); fprintf (st, "The type options can be used only when a unit is not attached to a file.\n"); fprintf (st, "RAUSER is a \"user specified\" disk; the user can specify the size of the\n"); fprintf (st, "disk in either MB (1000000 bytes) or logical block numbers (LBN's, 512 bytes\n"); diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index c81ef757..b7f065c8 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -185,9 +185,9 @@ DIB ry_dib = { UNIT ry_unit[] = { { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - RY_SIZE) }, + RY_SIZE) }, { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - RY_SIZE) } + RY_SIZE) } }; REG ry_reg[] = { @@ -485,59 +485,59 @@ switch (ry_state) { /* case on state */ sim_activate (uptr, ry_cwait * 100); /* schedule operation */ break; - case SDXFR: /* erase disk */ - for (i = 0; i < (int32) uptr->capac; i++) + case SDXFR: /* erase disk */ + for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0; - uptr->hwmark = (uint32) uptr->capac; - if (ry_csr & RYCS_DEN) + uptr->hwmark = (uint32) uptr->capac; + if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN; - else uptr->flags = uptr->flags & ~UNIT_DEN; - ry_done (0, 0); - break; + else uptr->flags = uptr->flags & ~UNIT_DEN; + ry_done (0, 0); + break; - case ESBA: - ry_ba = ry_dbr; /* save WC */ - ry_state = ESXFR; /* next state */ - sim_activate (uptr, ry_cwait); /* schedule xfer */ - return SCPE_OK; + case ESBA: + ry_ba = ry_dbr; /* save WC */ + ry_state = ESXFR; /* next state */ + sim_activate (uptr, ry_cwait); /* schedule xfer */ + return SCPE_OK; - case ESXFR: - estat[0] = ry_ecode; /* fill 8B status */ - estat[1] = ry_wc; - estat[2] = ry_unit[0].TRACK; - estat[3] = ry_unit[1].TRACK; - estat[4] = ry_track; - estat[5] = ry_sector; - estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | - ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | + case ESXFR: + estat[0] = ry_ecode; /* fill 8B status */ + estat[1] = ry_wc; + estat[2] = ry_unit[0].TRACK; + estat[3] = ry_unit[1].TRACK; + estat[4] = ry_track; + estat[5] = ry_sector; + estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | + ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | ((uptr->flags & UNIT_ATT)? 0040: 0) | ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) | ((ry_csr & RYCS_DEN)? 0001: 0); - estat[7] = uptr->TRACK; - t = Map_WriteB (ba, 8, estat); /* DMA to memory */ - ry_done (t? RYES_NXM: 0, 0); /* done */ - break; + estat[7] = uptr->TRACK; + t = Map_WriteB (ba, 8, estat); /* DMA to memory */ + ry_done (t? RYES_NXM: 0, 0); /* done */ + break; - case CMD_COMPLETE: /* command complete */ - ry_done (0, 0); - break; + case CMD_COMPLETE: /* command complete */ + ry_done (0, 0); + break; - case INIT_COMPLETE: /* init complete */ - ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ - ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ - if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ - ry_done (RYES_ID, 0010); /* init done, error */ - break; - } - da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ - for (i = 0; i < bps; i++) /* read sector */ - rx2xb[i] = fbuf[da + i]; - ry_done (RYES_ID, 0); /* set done */ - if ((ry_unit[1].flags & UNIT_ATT) == 0) + case INIT_COMPLETE: /* init complete */ + ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ + ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ + if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ + ry_done (RYES_ID, 0010); /* init done, error */ + break; + } + da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ + for (i = 0; i < bps; i++) /* read sector */ + rx2xb[i] = fbuf[da + i]; + ry_done (RYES_ID, 0); /* set done */ + if ((ry_unit[1].flags & UNIT_ATT) == 0) ry_ecode = 0020; - break; - } /* end case state */ + break; + } /* end case state */ return SCPE_OK; } diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index 2d6dc8a6..0be6a39b 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -29,7 +29,7 @@ 18-Apr-12 RMS Modified to use clock coscheduling 20-May-08 RMS Standardized clock delay at 1mips 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock - 29-Oct-06 RMS Synced keyboard and clock + 29-Oct-06 RMS Synced keyboard and clock Added clock coscheduling support 05-Jul-06 RMS Added UC only support for early DOS/RSTS 22-Nov-05 RMS Revised for new terminal processing routines diff --git a/PDP11/pdp11_ta.c b/PDP11/pdp11_ta.c index afbe7238..012a98c4 100644 --- a/PDP11/pdp11_ta.c +++ b/PDP11/pdp11_ta.c @@ -1,6 +1,6 @@ /* pdp11_ta.c: PDP-11 cassette tape simulator - Copyright (c) 2007-2008, Robert M Supnik + Copyright (c) 2007-2013, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,7 +24,9 @@ in this Software without prior written authorization from Robert M Supnik. ta TA11/TU60 cassette tape - + + 06-Jun-13 RMS Reset must set RDY (Ian Hammond) + Added CAPS-11 bootstrap (Ian Hammond) 06-Aug-07 RMS Foward op at BOT skips initial file gap Magnetic tapes are represented as a series of variable records @@ -129,6 +131,7 @@ t_stat ta_svc (UNIT *uptr); t_stat ta_reset (DEVICE *dptr); t_stat ta_attach (UNIT *uptr, char *cptr); t_stat ta_detach (UNIT *uptr); +t_stat ta_boot (int32 unitno, DEVICE *dptr); void ta_go (void); t_stat ta_map_err (UNIT *uptr, t_stat st); UNIT *ta_busy (void); @@ -143,7 +146,6 @@ uint32 ta_crc (uint8 *buf, uint32 cnt); ta_reg TA register list ta_mod TA modifier list */ - #define IOLN_TA 004 DIB ta_dib = { @@ -197,8 +199,8 @@ DEVICE ta_dev = { "TA", ta_unit, ta_reg, ta_mod, TA_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &ta_reset, - NULL, &ta_attach, &ta_detach, - &ta_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_TAPE + &ta_boot, &ta_attach, &ta_detach, + &ta_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_UBUS | DEV_TAPE }; /* I/O dispatch routines, I/O addresses 17777500 - 17777503 @@ -445,8 +447,8 @@ switch (uptr->FNC) { /* case on function */ ta_cs |= TACS_RDY; /* set ready */ ta_updsta (uptr); /* update status */ if (DEBUG_PRS (ta_dev)) - fprintf (sim_deb, ">>TA done: op=%o, status = %o, pos=%d\n", - uptr->FNC, ta_cs, uptr->pos); + fprintf (sim_deb, ">>TA done: op=%o, status = %o, dstatus = %o, pos=%d\n", + uptr->FNC, ta_cs, uptr->UST, uptr->pos); return r; } @@ -565,7 +567,7 @@ t_stat ta_reset (DEVICE *dptr) uint32 u; UNIT *uptr; -ta_cs = 0; +ta_cs = TACS_RDY; /* init sets RDY */ ta_idb = 0; ta_odb = 0; ta_write = 0; @@ -611,3 +613,54 @@ ta_updsta (NULL); uptr->UST = 0; return r; } + +/* Bootstrap routine */ + +#define BOOT_START 01000 /* start */ +#define BOOT_ENTRY (BOOT_START) +#define BOOT_CSR (BOOT_START + 002) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) + +static const uint16 boot_rom[] = { +0012700, /* mov #tacs,r0 */ +0177500, +0005010, /* clr (r0) */ +0010701, /* 3$: mov pc,r1 */ +0062701, /* add #20-here,r1 */ +0000052, +0012702, /* mov #375,r2 */ +0000375, +0112103, /* movb (r1)+,r3 */ +0112110, /* 5$: movb (r1)+,(r0) */ +0100413, /* bmi 15$ */ +0130310, /* 10$: bitb r3,(r0) */ +0001776, /* beq 10$ */ +0105202, /* incb r2 */ +0100772, /* bmi 5$ */ +0116012, /* movb 2(r0),r2 */ +0000002, +0120337, /* cmpb r3,@#0 */ +0000000, +0001767, /* beq 10$ */ +0000000, /* 12$: halt */ +0000755, /* br 3$ */ +0005710, /* 15$: tst (r0) */ +0100774, /* bmi 12$ */ +0005007, /* clr pc */ +0017640, /* $20: (data) */ +0002415, +0112024 +}; + +t_stat ta_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; +extern uint16 *M; + +for (i = 0; i < BOOT_LEN; i++) + M[(BOOT_START >> 1) + i] = boot_rom[i]; +M[BOOT_CSR >> 1] = ta_dib.ba & DMASK; +saved_PC = BOOT_ENTRY; +return SCPE_OK; +} diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index d18f21b9..d3b09511 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -25,7 +25,7 @@ tc TC11/TU56 DECtape - 23-Jun-06 RMS Fixed switch conflict in ATTACH + 23-Jun-06 RMS Fixed switch conflict in ATTACH 10-Feb-06 RMS READ sets extended data bits in TCST (Alan Frisbie) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs @@ -265,10 +265,10 @@ #define LOG_BL 0x4 #define DT_SETDONE tccm = tccm | CSR_DONE; \ - if (tccm & CSR_IE) \ + if (tccm & CSR_IE) \ SET_INT (DTA) #define DT_CLRDONE tccm = tccm & ~CSR_DONE; \ - CLR_INT (DTA) + CLR_INT (DTA) #define ABS(x) (((x) < 0)? (-(x)): (x)) extern uint16 *M; /* memory */ @@ -708,7 +708,7 @@ switch (fnc) { /* case function */ if (dir) newpos = DT_BLK2LN (blk + 1, uptr) - DT_CSMLN - DT_WSIZE; else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); - } + } if (fnc == FNC_WALL) sim_activate /* write all? */ (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ if (DEBUG_PRI (dt_dev, LOG_RW) || @@ -783,13 +783,13 @@ if (mot & DTS_DIR) /* update pos */ else uptr->pos = uptr->pos + delta; if (((int32) uptr->pos < 0) || ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP)) - dt_seterr (uptr, STA_SEL); /* error */ - return TRUE; - } + detach_unit (uptr); /* off reel? */ + uptr->STATE = uptr->pos = 0; + unum = (int32) (uptr - dt_dev.units); + if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP)) + dt_seterr (uptr, STA_SEL); /* error */ + return TRUE; + } return FALSE; } @@ -1303,7 +1303,7 @@ if (sim_is_active (uptr)) { /* active? cancel op */ tccm = tccm | CSR_ERR | CSR_DONE; if (tccm & CSR_IE) SET_INT (DTA); - } + } uptr->STATE = uptr->pos = 0; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index c50b4aa4..d6d15b0d 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -639,7 +639,7 @@ int32 u = uptr - tm_dev.units; if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr))) - uptr->USTAT = uptr->USTAT | STA_WLK; + uptr->USTAT = uptr->USTAT | STA_WLK; else uptr->USTAT = uptr->USTAT & ~STA_WLK; if (u == GET_UNIT (tm_cmd)) tm_updcsta (uptr); diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index aac008af..b82ff0bd 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -744,7 +744,7 @@ switch (fnc) { /* case on function */ for (i = j = 0; j < xbc; j = j + 1) { xbuf[i++] = wbuf[j] & 0377; xbuf[i++] = (wbuf[j] >> 8) & 0377; - } + } tbc = xbc; } if ((st = sim_tape_wrrecf (uptr, xbuf, tbc))) /* write rec, err? */ diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index 5ab8a1e9..2bde9bbe 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -1575,35 +1575,35 @@ fprintf (st, "and output of characters.\n\n"); fprintf (st, "By default, the DHV11 mode is selected, though DHU11 mode is recommended\n"); fprintf (st, "for applications that can support it. The %s controller may be adjusted\n", dptr->name); fprintf (st, "on a per controller basis as follows:\n\n"); -fprintf (st, " sim> SET %sn DHU use the DHU programming mode\n", dptr->name); -fprintf (st, " sim> SET %sn DHV use the DHV programming mode\n\n", dptr->name); +fprintf (st, " sim> SET %sn DHU use the DHU programming mode\n", dptr->name); +fprintf (st, " sim> SET %sn DHV use the DHV programming mode\n\n", dptr->name); fprintf (st, "DMA output is supported. In a real %s, DMA is not initiated immediately\n", devtype); fprintf (st, "upon receipt of TX.DMA.START but is dependent upon some internal processes.\n"); fprintf (st, "The %s controller mimics this behavior by default. It may be desirable to\n", dptr->name); fprintf (st, "alter this and start immediately, though this may not be compatible with all\n"); fprintf (st, "operating systems and diagnostics. You can change the behavior of the %s\n", dptr->name); fprintf (st, "controller as follows:\n\n"); -fprintf (st, " sim> SET %sn NORMAL use normal DMA procedures\n", dptr->name); -fprintf (st, " sim> SET %sn FASTDMA set DMA to initiate immediately\n\n", dptr->name); +fprintf (st, " sim> SET %sn NORMAL use normal DMA procedures\n", dptr->name); +fprintf (st, " sim> SET %sn FASTDMA set DMA to initiate immediately\n\n", dptr->name); fprintf (st, "The number of lines (and therefore the number of %s devices\n", devtype); fprintf (st, "simulated) can be changed with the command:\n\n"); -fprintf (st, " sim> SET %s LINES=n set line count to n\n\n", dptr->name); +fprintf (st, " sim> SET %s LINES=n set line count to n\n\n", dptr->name); fprintf (st, "The line count must be a multiple of %d, with a maximum of %d.\n\n", VH_LINES, VH_LINES*VH_MUXES); fprintf (st, "Modem and auto-disconnect support may be set on an individual controller\n"); fprintf (st, "basis. The SET MODEM command directs the controller to report modem status\n"); fprintf (st, "changes to the computer. The SET HANGUP command turns on active disconnects\n"); fprintf (st, "(disconnect session if computer clears Data Terminal Ready).\n\n"); -fprintf (st, " sim> SET %sn [NO]MODEM disable/enable modem control\n", dptr->name); -fprintf (st, " sim> SET %sn [NO]HANGUP disable/enable disconnect on DTR drop\n\n", dptr->name); +fprintf (st, " sim> SET %sn [NO]MODEM disable/enable modem control\n", dptr->name); +fprintf (st, " sim> SET %sn [NO]HANGUP disable/enable disconnect on DTR drop\n\n", dptr->name); fprintf (st, "Once the %s devuce is attached and the simulator is running, the %s will\n", dptr->name, dptr->name); fprintf (st, "listen for connections on the specified port. It assumes that the incoming\n"); fprintf (st, "connections are Telnet connections. The connection remains open until\n"); fprintf (st, "disconnected by the simulated program, the Telnet client, a SET %s DISCONNECT\n", dptr->name); fprintf (st, "command, or a DETACH %s command.\n\n", dptr->name); fprintf (st, "Other special %s commands:\n\n", dptr->name); -fprintf (st, " sim> SHOW %s CONNECTIONS show current connections\n", dptr->name); -fprintf (st, " sim> SHOW %s STATISTICS show statistics for active connections\n", dptr->name); -fprintf (st, " sim> SET %s DISCONNECT=linenumber disconnects the specified line.\n\n", dptr->name); +fprintf (st, " sim> SHOW %s CONNECTIONS show current connections\n", dptr->name); +fprintf (st, " sim> SHOW %s STATISTICS show statistics for active connections\n", dptr->name); +fprintf (st, " sim> SET %s DISCONNECT=linenumber disconnects the specified line.\n\n", dptr->name); fprintf (st, "The %s does not support save and restore. All open connections are lost\n", devtype); fprintf (st, "when the simulator shuts down or the %s is detached.\n\n", dptr->name); vh_help_attach (st, dptr, uptr, flag, cptr); diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index 5edea3c9..36f83f6d 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -326,7 +326,7 @@ struct xq_device xqb = { #define IOLN_XQ 020 DIB xqa_dib = { IOBA_AUTO, IOLN_XQ, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; + 1, IVCL (XQ), 0, { &xq_int } }; UNIT xqa_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -382,7 +382,7 @@ REG xqa_reg[] = { }; DIB xqb_dib = { IOBA_AUTO, IOLN_XQ, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; + 1, IVCL (XQ), 0, { &xq_int } }; UNIT xqb_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -1381,7 +1381,7 @@ t_stat xq_process_xbdl(CTLR* xq) else { if (xq->var->coalesce_latency == 0) xq_svc(&xq->unit[0]); /* service any received data */ - } + } sim_debug(DBG_WRN, xq->dev, "XBDL completed processing write\n"); } /* loopback/non-loopback */ diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index db1495f8..f29cc82f 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -56,7 +56,7 @@ probably need to be converted to Map_ReadW and Map_WriteW calls. 4) Some jerkiness seen during interactive I/O with remote systems; this is probably attributable to changed polling times from when - the poll duration was standardized for idling support. + the poll duration was standardized for idling support. ------------------------------------------------------------------------------ @@ -222,11 +222,11 @@ DEBTAB xu_debug[] = { DEVICE xu_dev = { - "XU", xua_unit, xua_reg, xu_mod, - 2, XU_RDX, 8, 1, XU_RDX, 8, - &xu_ex, &xu_dep, &xu_reset, - NULL, &xu_attach, &xu_detach, - &xua_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG | DEV_ETHER, + "XU", xua_unit, xua_reg, xu_mod, + 2, XU_RDX, 8, 1, XU_RDX, 8, + &xu_ex, &xu_dep, &xu_reset, + NULL, &xu_attach, &xu_detach, + &xua_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG | DEV_ETHER, 0, xu_debug, NULL, NULL, &xu_help, NULL, NULL, &xu_description }; @@ -234,7 +234,7 @@ DEVICE xu_dev = { #define IOLN_XU 010 DIB xub_dib = { IOBA_AUTO, IOLN_XU, &xu_rd, &xu_wr, - 1, IVCL (XU), 0, { &xu_int } }; + 1, IVCL (XU), 0, { &xu_int } }; UNIT xub_unit[] = { { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } /* receive timer */ @@ -530,7 +530,7 @@ t_stat xu_process_local (CTLR* xu, ETH_PACK* pack) void xu_read_callback(CTLR* xu, int status) { if (DBG_PCK & xu->dev->dctrl) - eth_packet_trace_ex(xu->var->etherface, xu->var->read_buffer.msg, xu->var->read_buffer.len, "xu-recvd", DBG_DAT & xu->dev->dctrl, DBG_PCK); + eth_packet_trace_ex(xu->var->etherface, xu->var->read_buffer.msg, xu->var->read_buffer.len, "xu-recvd", DBG_DAT & xu->dev->dctrl, DBG_PCK); /* process any packets locally that can be */ status = xu_process_local (xu, &xu->var->read_buffer); @@ -826,19 +826,19 @@ int32 xu_command(CTLR* xu) case FC_NOOP: break; - case FC_RDPA: /* read default physical address */ + case FC_RDPA: /* read default physical address */ wstatus = Map_WriteB(xu->var->pcbb + 2, 6, xu->var->mac); if (wstatus) return PCSR0_PCEI + 1; break; - case FC_RPA: /* read current physical address */ + case FC_RPA: /* read current physical address */ wstatus = Map_WriteB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]); if (wstatus) return PCSR0_PCEI + 1; break; - case FC_WPA: /* write current physical address */ + case FC_WPA: /* write current physical address */ rstatus = Map_ReadB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]); if (xu->var->pcb[1] & 1) return PCSR0_PCEI; @@ -874,7 +874,7 @@ int32 xu_command(CTLR* xu) } break; - case FC_RRF: /* read ring format */ + case FC_RRF: /* read ring format */ if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) return PCSR0_PCEI; xu->var->udb[0] = xu->var->tdrb & 0177776; @@ -891,7 +891,7 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI+1; break; - case FC_WRF: /* write ring format */ + case FC_WRF: /* write ring format */ if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) return PCSR0_PCEI; if ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING) @@ -975,14 +975,14 @@ int32 xu_command(CTLR* xu) memset(stats, 0, sizeof(struct xu_stats)); break; - case FC_RMODE: /* read mode register */ + case FC_RMODE: /* read mode register */ value = xu->var->mode; wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value); if (wstatus) return PCSR0_PCEI + 1; break; - case FC_WMODE: /* write mode register */ + case FC_WMODE: /* write mode register */ value = xu->var->mode; xu->var->mode = xu->var->pcb[1]; sim_debug(DBG_TRC, xu->dev, "FC_WMODE: mode=%04x\n", xu->var->mode); @@ -998,8 +998,8 @@ int32 xu_command(CTLR* xu) xu->var->setup.promiscuous); break; - case FC_RSTAT: /* read extended status */ - case FC_RCSTAT: /* read and clear extended status */ + case FC_RSTAT: /* read extended status */ + case FC_RCSTAT: /* read and clear extended status */ value = xu->var->stat; wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value); value = 10; @@ -1010,7 +1010,7 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI + 1; if (fnc == FC_RCSTAT) - xu->var->stat &= 0377; /* clear high byte */ + xu->var->stat &= 0377; /* clear high byte */ break; case FC_RSID: /* read system id parameters */ @@ -1079,7 +1079,7 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI + 1; break; - default: /* Unknown (unimplemented) command. */ + default: /* Unknown (unimplemented) command. */ printf("%s: unknown ancilliary command 0%o requested !\n", xu->dev->name, fnc); return PCSR0_PCEI; break; @@ -1160,7 +1160,7 @@ void xu_process_receive(CTLR* xu) if (item->packet.len < ETH_MIN_PACKET) { int len = item->packet.len; memset (&item->packet.msg[len], 0, ETH_MIN_PACKET - len); - item->packet.len = ETH_MIN_PACKET; + item->packet.len = ETH_MIN_PACKET; } } @@ -1344,7 +1344,7 @@ void xu_process_transmit(CTLR* xu) wstatus = eth_write(xu->var->etherface, &xu->var->write_buffer, xu->var->wcallback); if (wstatus) xu->var->pcsr0 |= PCSR0_PCEI; - else + else if (DBG_PCK & xu->dev->dctrl) eth_packet_trace_ex(xu->var->etherface, xu->var->write_buffer.msg, xu->var->write_buffer.len, "xu-write", DBG_DAT & xu->dev->dctrl, DBG_PCK); } @@ -1432,38 +1432,38 @@ void xu_port_command (CTLR* xu) sim_debug(DBG_TRC, xu->dev, "xu_port_command(), Command = %s [0%o]\n", commands[command], command); switch (command) { /* cases in order of most used to least used */ - case CMD_PDMD: /* POLLING DEMAND */ + case CMD_PDMD: /* POLLING DEMAND */ /* process transmit buffers, receive buffers are done in the service timer */ xu_process_transmit(xu); xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_GETCMD: /* GET COMMAND */ + case CMD_GETCMD: /* GET COMMAND */ xu_command(xu); xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_GETPCBB: /* GET PCB-BASE */ + case CMD_GETPCBB: /* GET PCB-BASE */ xu->var->pcbb = (xu->var->pcsr3 << 16) | xu->var->pcsr2; xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_SELFTEST: /* SELFTEST */ + case CMD_SELFTEST: /* SELFTEST */ /* - SELFTEST is a <=15-second self diagnostic test, setting various - error flags and the DONE (DNI) flag when complete. For simulation - purposes, signal completion immediately with no errors. This - inexact behavior could be incompatible with any guest machine - diagnostics that are expecting to be able to monitor the - controller's progress through the diagnostic testing. - */ + SELFTEST is a <=15-second self diagnostic test, setting various + error flags and the DONE (DNI) flag when complete. For simulation + purposes, signal completion immediately with no errors. This + inexact behavior could be incompatible with any guest machine + diagnostics that are expecting to be able to monitor the + controller's progress through the diagnostic testing. + */ xu->var->pcsr0 |= PCSR0_DNI; xu->var->pcsr0 &= ~PCSR0_USCI; xu->var->pcsr0 &= ~PCSR0_FATL; xu->var->pcsr1 = STATE_READY; break; - case CMD_START: /* START */ + case CMD_START: /* START */ if (state == STATE_READY) { xu->var->pcsr1 &= ~PCSR1_STATE; xu->var->pcsr1 |= STATE_RUNNING; @@ -1487,7 +1487,7 @@ void xu_port_command (CTLR* xu) xu->var->pcsr0 |= PCSR0_PCEI; break; - case CMD_STOP: /* STOP */ + case CMD_STOP: /* STOP */ if (state == STATE_RUNNING) { xu->var->pcsr1 &= ~PCSR1_STATE; xu->var->pcsr1 |= STATE_READY; @@ -1575,7 +1575,7 @@ t_stat xu_wr(int32 data, int32 PA, int32 access) sim_debug(DBG_REG, xu->dev, "xu_wr(), PCSR%d, data=%08x, PA=%08x, access=%d[%s]\n", reg, data, PA, access, desc); switch (reg) { case 00: - /* Clear write-one-to-clear interrupt bits */ + /* Clear write-one-to-clear interrupt bits */ if (access == WRITEB) { data &= 0377; if (PA & 1) { @@ -1622,11 +1622,11 @@ t_stat xu_wr(int32 data, int32 PA, int32 access) break; case 02: - xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */ + xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */ break; case 03: - xu->var->pcsr3 = data & 0000003; /* store significant bits */ + xu->var->pcsr3 = data & 0000003; /* store significant bits */ break; } return SCPE_OK; @@ -1766,7 +1766,7 @@ void xu_dump_rxring (CTLR* xu) for (i=0; ivar->rdrb + (xu->var->relen * 2) * i; - t_stat rstatus = Map_ReadW (ba, 8, rxhdr); /* get rxring entry[i] */ + t_stat rstatus = Map_ReadW (ba, 8, rxhdr); /* get rxring entry[i] */ int own = (rxhdr[2] & RXR_OWN) >> 15; int len = rxhdr[0]; uint32 addr = rxhdr[1] + ((rxhdr[2] & 3) << 16); @@ -1783,7 +1783,7 @@ void xu_dump_txring (CTLR* xu) for (i=0; ivar->tdrb + (xu->var->telen * 2) * i; - t_stat tstatus = Map_ReadW (ba, 8, txhdr); /* get rxring entry[i] */ + t_stat tstatus = Map_ReadW (ba, 8, txhdr); /* get rxring entry[i] */ int own = (txhdr[2] & RXR_OWN) >> 15; int len = txhdr[0]; uint32 addr = txhdr[1] + ((txhdr[2] & 3) << 16); diff --git a/README.md b/README.md index 9047c52d..af81c5df 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ VAX/11 730 VAX/11 750 VAX 8600/8650 - MicroVAX I - MicroVAX II + MicroVAX I & VAXStation I + MicroVAX II & VAXStation II rtVAX 1000 (or Industrial VAX 620) #### Howard Harte has implemented a Lincoln Labs TX-0 simulator. @@ -50,6 +50,8 @@ A remote console session will close when an EOF character is entered (i.e. ^D or DHU11 (device VH) on Unibus systems now has 16 ports per multiplexer. MicroVAX 3900 and MicroVAX II have SET CPU AUTOBOOT option MicroVAX 3900 has a SET CPU MODEL=(MicroVAX|VAXServer) command to change between system types + MicroVAX I has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types + MicroVAX II has a SET CPU MODEL=(MicroVAX|VAXSTATION) command to change between system types #### Terminal Multiplexer additions Added support for TCP connections using IPv4 and/or IPv6. @@ -153,8 +155,8 @@ The "!" command (execute a command on the local OS), now returns the command's e HELP dev HELP dev ATTACH - HELP dev SET - HELP dev SHOW + HELP dev SET (aka HELP SET dev) + HELP dev SHOW (aka HELP SHOW dev) HELP dev REGISTERS #### Generic scp support Clock Coscheduling as opposed to per simulator implementations. diff --git a/VAX/vax610_defs.h b/VAX/vax610_defs.h index 1b59789a..1dbd6f67 100644 --- a/VAX/vax610_defs.h +++ b/VAX/vax610_defs.h @@ -83,6 +83,20 @@ #define MT_MBRK 60 /* microbreak */ #define MT_MAX 63 /* last valid IPR */ +/* CPU */ + +#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "LEDS", NULL, \ + NULL, &cpu_show_leds, NULL, "Display the CPU LED values" }, \ + { MTAB_XTD|MTAB_VDV, 0, "MODEL", "MODEL={MICROVAX|VAXSTATION}", \ + &cpu_set_model, &cpu_show_model, NULL, "Set/Show the simulator CPU Model" } + +/* QVSS memory space */ + +#define QVMAWIDTH 18 /* QVSS mem addr width */ +#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ +#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ +#define QVMBASE 0x3C0000 /* QVSS mem base */ + /* Memory */ #define MAXMEMWIDTH 22 /* max mem, KA610 */ @@ -90,8 +104,9 @@ #define MAXMEMWIDTH_X 22 /* max mem, KA610 */ #define MAXMEMSIZE_X (1 << MAXMEMWIDTH_X) #define INITMEMSIZE (1 << 22) /* initial memory size */ +#define VS_MEMSIZE (((cpu_unit.capac > QVMBASE) ? QVMBASE : cpu_unit.capac)) #define MEMSIZE (cpu_unit.capac) -#define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) +#define ADDR_IS_MEM(x) (((uint32) (x)) < (sys_model ? VS_MEMSIZE : MEMSIZE)) #undef PAMASK #define PAMASK 0x203FFFFF /* KA610 needs a special mask */ #define MEM_MODIFIERS { UNIT_MSIZE, (1u << 19), NULL, "512K", &cpu_set_size, NULL, NULL, "Set Memory to 512K bytes" },\ @@ -101,10 +116,6 @@ { UNIT_MSIZE, (1u << 22), NULL, "4M", &cpu_set_size, NULL, NULL, "Set Memory to 4M bytes" }, \ { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "MEMORY", NULL, NULL, &cpu_show_memory, NULL, "Display memory configuration" } extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); -#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "LEDS", NULL, \ - NULL, &cpu_show_leds, NULL, "Display the CPU LED values" }, \ - { MTAB_XTD|MTAB_VDV, 0, "MODEL", NULL, \ - NULL, &cpu_show_model, NULL, "Display the simulator CPU Model" } /* Qbus I/O page */ @@ -159,10 +170,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define DZ_MUXES 4 /* max # of DZV muxes */ #define DZ_LINES 4 /* lines per DZV mux */ #define VH_MUXES 4 /* max # of DHQ muxes */ -#define DLX_LINES 16 /* max # of KL11/DL11's */ -#define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ #define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ @@ -309,6 +317,10 @@ typedef struct { #define LOG_CPU_R 0x2 /* REI */ #define LOG_CPU_P 0x4 /* context */ +/* System model */ + +extern int32 sys_model; + /* Function prototypes for virtual memory interface */ int32 Read (uint32 va, int32 lnt, int32 acc); diff --git a/VAX/vax610_io.c b/VAX/vax610_io.c index 47bd1089..306cb700 100644 --- a/VAX/vax610_io.c +++ b/VAX/vax610_io.c @@ -222,8 +222,8 @@ for (i = 0; int_req[l] && (i < 32); i++) { if ((int_req[l] >> i) & 1) { int_req[l] = int_req[l] & ~(1u << i); if (int_ack[l][i]) - return int_ack[l][i](); - return int_vec[l][i]; + return int_ack[l][i](); + return int_vec[l][i]; } } return 0; diff --git a/VAX/vax610_sysdev.c b/VAX/vax610_sysdev.c index e1e01057..de3c9f59 100644 --- a/VAX/vax610_sysdev.c +++ b/VAX/vax610_sysdev.c @@ -55,9 +55,10 @@ extern int32 int_req[IPL_HLVL]; extern jmp_buf save_env; extern int32 p1; extern int32 trpirq, mem_err; +extern DEVICE vc_dev, lk_dev, vs_dev; int32 conisp, conpc, conpsl; /* console reg */ -int32 sys_model = 0; +int32 sys_model = 0; /* MicroVAX or VAXstation */ char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ static struct boot_dev boot_tab[] = { @@ -74,6 +75,8 @@ t_stat vax610_boot_parse (int32 flag, char *ptr); t_stat cpu_boot (int32 unitno, DEVICE *dptr); extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); +extern int32 vc_mem_rd (int32 pa); +extern void vc_mem_wr (int32 pa, int32 val, int32 lnt); extern int32 iccs_rd (void); extern int32 todr_rd (void); extern int32 rxcs_rd (void); @@ -277,7 +280,7 @@ struct reglink { /* register linkage */ }; struct reglink regtable[] = { -/* { QVMBASE, QVMBASE+QVMSIZE, &qv_mem_rd, &qv_mem_wr }, */ + { QVMBASE, QVMBASE+QVMSIZE, &vc_mem_rd, &vc_mem_wr }, { 0, 0, NULL, NULL } }; @@ -411,7 +414,7 @@ if (gbuf[0]) { if (unitno == -1) continue; R[0] = boot_tab[i].code | (('0' + unitno) << 24); - R[1] = 0xC0; + R[1] = (sys_model ? 0x80 : 0xC0); R[2] = 0; R[3] = 0; R[4] = 0; @@ -421,7 +424,7 @@ if (gbuf[0]) { } else { R[0] = 0; - R[1] = 0xC0; + R[1] = (sys_model ? 0x80 : 0xC0); R[2] = 0; R[3] = 0; R[4] = 0; @@ -499,12 +502,39 @@ return "system devices"; t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) { +#if defined(HAVE_LIBSDL) +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (!*cptr)) + return SCPE_ARG; +cptr = get_glyph (cptr, gbuf, 0); +if (MATCH_CMD(gbuf, "MICROVAX") == 0) { + sys_model = 0; + vc_dev.flags = vc_dev.flags | DEV_DIS; /* disable QVSS */ + lk_dev.flags = lk_dev.flags | DEV_DIS; /* disable keyboard */ + vs_dev.flags = vs_dev.flags | DEV_DIS; /* disable mouse */ + strcpy (sim_name, "MicroVAX I (KA610)"); + reset_all (0); /* reset everything */ + } +else if (MATCH_CMD(gbuf, "VAXSTATION") == 0) { + sys_model = 1; + vc_dev.flags = vc_dev.flags & ~DEV_DIS; /* enable QVSS */ + lk_dev.flags = lk_dev.flags & ~DEV_DIS; /* enable keyboard */ + vs_dev.flags = vs_dev.flags & ~DEV_DIS; /* enable mouse */ + strcpy (sim_name, "VAXStation I (KA610)"); + reset_all (0); /* reset everything */ + } +else + return SCPE_ARG; +return SCPE_OK; +#else return SCPE_NOFNC; +#endif } t_stat cpu_print_model (FILE *st) { -fprintf (st, "MicroVAX I"); +fprintf (st, (sys_model ? "VAXstation I" : "MicroVAX I")); return SCPE_OK; } diff --git a/VAX/vax610_syslist.c b/VAX/vax610_syslist.c index c44f2700..2c8c182e 100644 --- a/VAX/vax610_syslist.c +++ b/VAX/vax610_syslist.c @@ -29,7 +29,7 @@ #include "vax_defs.h" -char sim_name[] = "MicroVAX I (KA610)"; +char sim_name[32] = "MicroVAX I (KA610)"; extern DEVICE cpu_dev; extern DEVICE mctl_dev; @@ -47,6 +47,9 @@ extern DEVICE tq_dev; extern DEVICE dz_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE vh_dev; +extern DEVICE vc_dev; +extern DEVICE lk_dev; +extern DEVICE vs_dev; extern void WriteB (uint32 pa, int32 val); extern UNIT cpu_unit; @@ -64,6 +67,11 @@ DEVICE *sim_devices[] = { &vh_dev, &cr_dev, &lpt_dev, +#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL) + &lk_dev, + &vs_dev, + &vc_dev, +#endif &rl_dev, &rq_dev, &rqb_dev, diff --git a/VAX/vax630_defs.h b/VAX/vax630_defs.h index 00c13b61..30214c6a 100644 --- a/VAX/vax630_defs.h +++ b/VAX/vax630_defs.h @@ -89,6 +89,17 @@ #define MT_MBRK 60 /* microbreak */ #define MT_MAX 63 /* last valid IPR */ +/* CPU */ + +#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "MODEL", "MODEL={MICROVAX|VAXSTATION}", \ + &cpu_set_model, &cpu_show_model, NULL, "Set/Show the simulator CPU Model" }, \ + { MTAB_XTD|MTAB_VDV, 0, "DIAG", "DIAG={FULL|MIN}", \ + &sysd_set_diag, &sysd_show_diag, NULL, "Set/Show boot rom diagnostic mode" }, \ + { MTAB_XTD|MTAB_VDV, 0, "AUTOBOOT", "AUTOBOOT", \ + &sysd_set_halt, &sysd_show_halt, NULL, "Enable autoboot (Disable Halt)" }, \ + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "NOAUTOBOOT", "NOAUTOBOOT", \ + &sysd_set_halt, &sysd_show_halt, NULL, "Disable autoboot (Enable Halt)" } + /* Memory */ #define MAXMEMWIDTH 24 /* max mem, std KA655 */ @@ -107,14 +118,6 @@ { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size, NULL, NULL, "Set Memory to 16M bytes" }, \ { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "MEMORY", NULL, NULL, &cpu_show_memory, NULL, "Display memory configuration" } extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); -#define CPU_MODEL_MODIFIERS { MTAB_XTD|MTAB_VDV, 0, "MODEL", NULL, \ - NULL, &cpu_show_model, NULL, "Display the simulator CPU Model" }, \ - { MTAB_XTD|MTAB_VDV, 0, "DIAG", "DIAG={FULL|MIN}", \ - &sysd_set_diag, &sysd_show_diag, NULL, "Set/Show boot rom diagnostic mode" }, \ - { MTAB_XTD|MTAB_VDV, 0, "AUTOBOOT", "AUTOBOOT", \ - &sysd_set_halt, &sysd_show_halt, NULL, "Enable autoboot (Disable Halt)" }, \ - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "NOAUTOBOOT", "NOAUTOBOOT", \ - &sysd_set_halt, &sysd_show_halt, NULL, "Disable autoboot (Enable Halt)" } /* Qbus I/O page */ @@ -165,6 +168,13 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define ADDR_IS_QBM(x) ((((uint32) (x)) >= QBMBASE) && \ (((uint32) (x)) < (QBMBASE + QBMSIZE))) +/* QVSS memory space */ + +#define QVMAWIDTH 18 /* QVSS mem addr width */ +#define QVMSIZE (1u << QVMAWIDTH) /* QVSS mem length */ +#define QVMAMASK (QVMSIZE - 1) /* QVSS mem addr mask */ +#define QVMBASE 0x303C0000 /* QVSS mem base */ + /* Other address spaces */ #define ADDR_IS_CDG(x) (0) @@ -207,10 +217,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define DZ_MUXES 4 /* max # of DZV muxes */ #define DZ_LINES 4 /* lines per DZV mux */ #define VH_MUXES 4 /* max # of DHQ muxes */ -#define DLX_LINES 16 /* max # of KL11/DL11's */ -#define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ #define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ @@ -333,8 +340,8 @@ typedef struct { #define IPL_QDSS (0x14 - IPL_HMIN) #define IPL_CR (0x14 - IPL_HMIN) #define IPL_QVSS (0x14 - IPL_HMIN) -#define IPL_DMCRX (0x15 - IPL_HMIN) -#define IPL_DMCTX (0x15 - IPL_HMIN) +#define IPL_DMCRX (0x14 - IPL_HMIN) +#define IPL_DMCTX (0x14 - IPL_HMIN) #define IPL_HMAX 0x17 /* highest hwre level */ #define IPL_HMIN 0x14 /* lowest hwre level */ diff --git a/VAX/vax630_io.c b/VAX/vax630_io.c index e341234d..1b53a1b9 100644 --- a/VAX/vax630_io.c +++ b/VAX/vax630_io.c @@ -263,8 +263,8 @@ for (i = 0; int_req[l] && (i < 32); i++) { if ((int_req[l] >> i) & 1) { int_req[l] = int_req[l] & ~(1u << i); if (int_ack[l][i]) - return int_ack[l][i](); - return int_vec[l][i]; + return int_ack[l][i](); + return int_vec[l][i]; } } return 0; diff --git a/VAX/vax630_sysdev.c b/VAX/vax630_sysdev.c index eb9916ef..8ba3c985 100644 --- a/VAX/vax630_sysdev.c +++ b/VAX/vax630_sysdev.c @@ -55,7 +55,7 @@ #define UNIT_NODELAY (1u << UNIT_V_NODELAY) t_stat vax630_boot (int32 flag, char *ptr); -int32 sys_model = 0; +int32 sys_model = 0; /* MicroVAX or VAXstation */ /* Special boot command, overrides regular boot */ @@ -106,8 +106,8 @@ CTAB vax630_cmd[] = { #define MSER_MCD1 0x00000200 /* Mem Code 1 */ #define MSER_MBZ 0xFFFFFC04 #define MSER_RD (MSER_PE | MSER_WWP | MSER_LEB | \ - MSER_DQPE | MSER_CQPE | MSER_CLPE | \ - MSER_NXM | MSER_MCD0 | MSER_MCD1) + MSER_DQPE | MSER_CQPE | MSER_CLPE | \ + MSER_NXM | MSER_MCD0 | MSER_MCD1) #define MSER_WR (MSER_PE | MSER_WWP) #define MSER_RS (MSER_LEB | MSER_DQPE | MSER_CQPE | MSER_CLPE | MSER_NXM) @@ -139,6 +139,7 @@ extern UNIT clk_unit; extern jmp_buf save_env; extern int32 p1; extern int32 tmr_poll; +extern DEVICE vc_dev, lk_dev, vs_dev; uint32 *rom = NULL; /* boot ROM */ uint32 *nvr = NULL; /* non-volatile mem */ @@ -182,6 +183,8 @@ extern int32 qbmap_rd (int32 pa); extern void qbmap_wr (int32 pa, int32 val, int32 lnt); extern int32 qbmem_rd (int32 pa); extern void qbmem_wr (int32 pa, int32 val, int32 lnt); +extern int32 vc_mem_rd (int32 pa); +extern void vc_mem_wr (int32 pa, int32 val, int32 lnt); extern int32 wtc_rd (int32 pa); extern void wtc_wr (int32 pa, int32 val, int32 lnt); extern void wtc_set_valid (void); @@ -409,7 +412,7 @@ fprintf (st, "Read-only memory (ROM)\n\n"); fprintf (st, "The boot ROM consists of a single unit, simulating the 64KB boot ROM. It has\n"); fprintf (st, "no registers. The boot ROM is loaded with a binary byte stream using the \n"); fprintf (st, "LOAD -r command:\n\n"); -fprintf (st, " LOAD -r KA630.BIN load ROM image KA630.BIN\n\n"); +fprintf (st, " LOAD -r KA630.BIN load ROM image KA630.BIN\n\n"); fprintf (st, "When the simulator starts running (via the BOOT command), if the ROM has\n"); fprintf (st, "not yet been loaded, an attempt will be made to automatically load the\n"); fprintf (st, "ROM image from the file ka655x.bin in the current working directory.\n"); @@ -708,7 +711,7 @@ struct reglink regtable[] = { { ROMBASE, ROMBASE+ROMSIZE+ROMSIZE, &rom_rd, NULL }, { NVRBASE, NVRBASE+NVRSIZE, &nvr_rd, &nvr_wr }, { KABASE, KABASE+KASIZE, &ka_rd, &ka_wr }, -/* { QVMBASE, QVMBASE+QVMSIZE, &qv_mem_rd, &qv_mem_wr }, */ + { QVMBASE, QVMBASE+QVMSIZE, &vc_mem_rd, &vc_mem_wr }, { QBMBASE, QBMBASE+QBMSIZE, &qbmem_rd, &qbmem_wr }, { 0, 0, NULL, NULL } }; @@ -825,8 +828,8 @@ p2 = mchk_va + 4; /* save vap */ st = 0; if (p1 & 0x80) { /* mref? */ cc = intexc (SCB_MCHK, cc, 0, IE_EXC); /* take normal exception */ - if (!(ka_mser & MSER_CQPE) && !(ka_mser & MSER_CLPE)) - ka_mser |= MSER_NXM; + if (!(ka_mser & MSER_CQPE) && !(ka_mser & MSER_CLPE)) + ka_mser |= MSER_NXM; } else cc = intexc (SCB_MCHK, cc, 0, IE_SVE); /* take severe exception */ acc = ACC_MASK (KERN); /* in kernel mode */ @@ -957,12 +960,44 @@ ka_diag_full = 0; return SCPE_OK; } +t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +#if defined(HAVE_LIBSDL) +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (!*cptr)) + return SCPE_ARG; +cptr = get_glyph (cptr, gbuf, 0); +if (MATCH_CMD(gbuf, "MICROVAX") == 0) { + sys_model = 0; + vc_dev.flags = vc_dev.flags | DEV_DIS; /* disable QVSS */ + lk_dev.flags = lk_dev.flags | DEV_DIS; /* disable keyboard */ + vs_dev.flags = vs_dev.flags | DEV_DIS; /* disable mouse */ + strcpy (sim_name, "MicroVAX II (KA630)"); + reset_all (0); /* reset everything */ + } +else if (MATCH_CMD(gbuf, "VAXSTATION") == 0) { + sys_model = 1; + vc_dev.flags = vc_dev.flags & ~DEV_DIS; /* enable QVSS */ + lk_dev.flags = lk_dev.flags & ~DEV_DIS; /* enable keyboard */ + vs_dev.flags = vs_dev.flags & ~DEV_DIS; /* enable mouse */ + strcpy (sim_name, "VAXStation II (KA630)"); + reset_all (0); /* reset everything */ + } +else + return SCPE_ARG; +return SCPE_OK; +#else +return SCPE_NOFNC; +#endif +} + t_stat cpu_print_model (FILE *st) { #if defined(VAX_620) fprintf (st, "rtVAX 1000"); #else -fprintf (st, "MicroVAX II"); +fprintf (st, (sys_model ? "VAXstation II" : "MicroVAX II")); #endif return SCPE_OK; } diff --git a/VAX/vax630_syslist.c b/VAX/vax630_syslist.c index 425ac3bb..11a25a4f 100644 --- a/VAX/vax630_syslist.c +++ b/VAX/vax630_syslist.c @@ -32,7 +32,7 @@ #if defined(VAX_620) char sim_name[] = "rtVAX1000 (KA620)"; #else -char sim_name[] = "MicroVAX II (KA630)"; +char sim_name[32] = "MicroVAX II (KA630)"; #endif extern DEVICE cpu_dev; @@ -53,6 +53,9 @@ extern DEVICE tq_dev; extern DEVICE dz_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE vh_dev; +extern DEVICE vc_dev; +extern DEVICE lk_dev; +extern DEVICE vs_dev; extern void WriteB (uint32 pa, int32 val); extern void rom_wr_B (int32 pa, int32 val); @@ -73,6 +76,11 @@ DEVICE *sim_devices[] = { &vh_dev, &cr_dev, &lpt_dev, +#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL) + &lk_dev, + &vs_dev, + &vc_dev, +#endif &rl_dev, &rq_dev, &rqb_dev, diff --git a/VAX/vax730_rb.c b/VAX/vax730_rb.c index 5ca41ae3..869816af 100644 --- a/VAX/vax730_rb.c +++ b/VAX/vax730_rb.c @@ -103,7 +103,7 @@ #define RB02DS_ATT (RB02DS_HDO+RB02DS_BHO+RB02DS_LOCK) /* att status */ #define RB02DS_UNATT (RB02DS_CVO+RB02DS_LOAD) /* unatt status */ #define RB02DS_ERR (RB02DS_WDE+RB02DS_HCE+RB02DS_STO+RB02DS_SPE+RB02DS_WGE+ \ - RB02DS_VCK+RB02DS_DSE) /* errors bits */ + RB02DS_VCK+RB02DS_DSE) /* errors bits */ #define RB80DS_SCNT 0x0000000F #define RB80DS_FLT 0x00000100 diff --git a/VAX/vax730_stddev.c b/VAX/vax730_stddev.c index ad86deaa..088ba6e1 100644 --- a/VAX/vax730_stddev.c +++ b/VAX/vax730_stddev.c @@ -1070,15 +1070,15 @@ int32 sel = TXDB_GETSEL (data); /* get selection */ if (sel == TXDB_MISC) { /* misc function? */ switch (data & MISC_MASK) { /* case on function */ - case MISC_CLWS: + case MISC_CLWS: case MISC_CLCS: break; - case MISC_SWDN: + case MISC_SWDN: ABORT (STOP_SWDN); break; - case MISC_BOOT: + case MISC_BOOT: ABORT (STOP_BOOT); break; } diff --git a/VAX/vax730_syslist.c b/VAX/vax730_syslist.c index 23b0ea54..3aee3c09 100644 --- a/VAX/vax730_syslist.c +++ b/VAX/vax730_syslist.c @@ -85,10 +85,10 @@ DEVICE *sim_devices[] = { &tq_dev, &xu_dev, &xub_dev, - &dmc_dev[0], - &dmc_dev[1], - &dmc_dev[2], - &dmc_dev[3], + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], &dup_dev, NULL }; diff --git a/VAX/vax730_uba.c b/VAX/vax730_uba.c index 26c53e55..e19563d7 100644 --- a/VAX/vax730_uba.c +++ b/VAX/vax730_uba.c @@ -270,7 +270,7 @@ switch (ofs) { /* case on offset */ case UBADPR_OF + 2: break; /* ignore writes */ - case UBACSR_OF: /* CSR */ + case UBACSR_OF: /* CSR */ if(val & 0x10000) uba_csr = 0; break; diff --git a/VAX/vax750_syslist.c b/VAX/vax750_syslist.c index ae815b99..4e378a0a 100644 --- a/VAX/vax750_syslist.c +++ b/VAX/vax750_syslist.c @@ -90,10 +90,10 @@ DEVICE *sim_devices[] = { &tq_dev, &xu_dev, &xub_dev, - &dmc_dev[0], - &dmc_dev[1], - &dmc_dev[2], - &dmc_dev[3], + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], &dup_dev, NULL }; diff --git a/VAX/vax780_fload.c b/VAX/vax780_fload.c index b4f94c08..fc304f74 100644 --- a/VAX/vax780_fload.c +++ b/VAX/vax780_fload.c @@ -68,10 +68,10 @@ /* RT11 directory entry offsets */ #define DE_STATUS 0 /* status (odd byte) */ -#define TENTAT 001 /* tentative */ -#define EMPTY 002 -#define PERM 004 -#define ENDSEG 010 /* end of segment */ +#define TENTAT 001 /* tentative */ +#define EMPTY 002 +#define PERM 004 +#define ENDSEG 010 /* end of segment */ #define DE_NAME 1 /* file name */ #define DE_FLNT 4 /* file length */ #define DE_SIZE 7 /* entry size in words */ diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 767a4144..28bf7a50 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -92,10 +92,10 @@ DEVICE *sim_devices[] = { &tq_dev, &xu_dev, &xub_dev, - &dmc_dev[0], - &dmc_dev[1], - &dmc_dev[2], - &dmc_dev[3], + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], &dup_dev, NULL }; diff --git a/VAX/vax860_abus.c b/VAX/vax860_abus.c index 768ac31c..0f55fbf4 100644 --- a/VAX/vax860_abus.c +++ b/VAX/vax860_abus.c @@ -466,29 +466,29 @@ switch (rg) { val = VAX860_SID | VAX860_TYP | VAX860_ECO | VAX860_PLANT | VAX860_SN; break; - case MT_PAMACC: /* PAMACC */ + case MT_PAMACC: /* PAMACC */ val = pamm[pamloc >> 20]; val = val | (pamloc & PAMACC_ADDR); - break; + break; - case MT_PAMLOC: /* PAMLOC */ - val = pamloc & PAMLOC_ADDR; - break; + case MT_PAMLOC: /* PAMLOC */ + val = pamloc & PAMLOC_ADDR; + break; - case MT_MDCTL: /* MDCTL */ - val = mdctl & MDCTL_RW; + case MT_MDCTL: /* MDCTL */ + val = mdctl & MDCTL_RW; - case MT_EHSR: /* EHSR */ - val = ehsr & EHSR_VMSE; - break; + case MT_EHSR: /* EHSR */ + val = ehsr & EHSR_VMSE; + break; - case MT_CSWP: /* CSWP */ + case MT_CSWP: /* CSWP */ val = cswp & 0xF; - break; + break; - case MT_MERG: /* MERG */ + case MT_MERG: /* MERG */ val = 0; - break; + break; case MT_STXCS: /* STXCS */ val = stxcs_rd (); @@ -536,42 +536,42 @@ switch (rg) { case MT_TXDB: /* TXDB */ txdb_wr (val); - break; + break; - case MT_PAMACC: /* PAMACC (not impl) */ - break; + case MT_PAMACC: /* PAMACC (not impl) */ + break; - case MT_PAMLOC: /* PAMLOC */ - pamloc = val & PAMLOC_ADDR; - break; + case MT_PAMLOC: /* PAMLOC */ + pamloc = val & PAMLOC_ADDR; + break; - case MT_MDCTL: /* MDCTL */ - mdctl = val & MDCTL_RW; - break; + case MT_MDCTL: /* MDCTL */ + mdctl = val & MDCTL_RW; + break; - case MT_EHSR: /* EHSR */ + case MT_EHSR: /* EHSR */ ehsr = val & EHSR_VMSE; - break; + break; - case MT_CSWP: /* CSWP */ + case MT_CSWP: /* CSWP */ cswp = val & 0xF; - break; + break; - case MT_MERG: /* MERG (not impl) */ - break; + case MT_MERG: /* MERG (not impl) */ + break; case MT_CRBT: /* CRBT (not impl) */ break; case MT_STXCS: /* STXCS */ - stxcs_wr (val); + stxcs_wr (val); break; case MT_STXDB: /* STXDB */ - stxdb_wr (val); + stxdb_wr (val); break; - default: + default: RSVD_OPND_FAULT; } @@ -613,7 +613,7 @@ return 0; void WriteReg (int32 pa, int32 val, int32 lnt) { if (ADDR_IS_SBIA (pa)) { /* SBI adapter space? */ - sbia_wr (pa, val, lnt); + sbia_wr (pa, val, lnt); SET_IRQL; return; } diff --git a/VAX/vax860_sbia.c b/VAX/vax860_sbia.c index 8c08a2c1..47c652ef 100644 --- a/VAX/vax860_sbia.c +++ b/VAX/vax860_sbia.c @@ -134,42 +134,42 @@ DEVICE sbia_dev = { int32 sbia_rd (int32 pa, int32 lnt) { - int32 rg = (pa >> 2) & 0x1F; + int32 rg = (pa >> 2) & 0x1F; - switch (rg) { - case 0: /* SBICNF */ + switch (rg) { + case 0: /* SBICNF */ return 0x00400010; /* 8MB + SBIA Abus code */ - case 1: /* SBICSR */ - return sbi_csr; + case 1: /* SBICSR */ + return sbi_csr; - case 2: /* SBIES (not impl) */ - case 3: /* SBIDCR (not impl) */ - case 4: /* DMAI CMD (not impl) */ - case 5: /* DMAI ID (not impl) */ - case 6: /* DMAA CMD (not impl) */ - case 7: /* DMAA ID (not impl) */ - case 8: /* DMAB CMD (not impl) */ - case 9: /* DMAB ID (not impl) */ - case 0xa: /* DMAC CMD (not impl) */ - case 0xb: /* DMAC ID (not impl) */ - case 0xc: /* SBIS (not impl) */ - return 0; + case 2: /* SBIES (not impl) */ + case 3: /* SBIDCR (not impl) */ + case 4: /* DMAI CMD (not impl) */ + case 5: /* DMAI ID (not impl) */ + case 6: /* DMAA CMD (not impl) */ + case 7: /* DMAA ID (not impl) */ + case 8: /* DMAB CMD (not impl) */ + case 9: /* DMAB ID (not impl) */ + case 0xa: /* DMAC CMD (not impl) */ + case 0xb: /* DMAC ID (not impl) */ + case 0xc: /* SBIS (not impl) */ + return 0; - case 0xd: /* SBIER */ - return sbi_er & SBIER_RD; + case 0xd: /* SBIER */ + return sbi_er & SBIER_RD; - case 0xe: /* SBITA */ - return sbi_tmo; + case 0xe: /* SBITA */ + return sbi_tmo; - case 0xf: /* SBIFS */ - return sbi_fs & SBIFS_RD; + case 0xf: /* SBIFS */ + return sbi_fs & SBIFS_RD; - case 0x10: /* SBISC */ - return sbi_sc & SBISC_RD; + case 0x10: /* SBISC */ + return sbi_sc & SBISC_RD; - case 0x11: /* SBIMT */ - return sbi_mt & SBIMT_RD; + case 0x11: /* SBIMT */ + return sbi_mt & SBIMT_RD; default: /* Anything else is not impl */ return 0; @@ -179,31 +179,31 @@ int32 sbia_rd (int32 pa, int32 lnt) void sbia_wr (int32 pa, int32 val, int32 lnt) { - int32 rg = (pa >> 2) & 0x1F; + int32 rg = (pa >> 2) & 0x1F; - switch (rg) { - case 0: /* SBICNF */ + switch (rg) { + case 0: /* SBICNF */ break; - case 1: /* SBICSR */ + case 1: /* SBICSR */ printf ("sbi_csr wr: %08X\n", val); sbi_csr = sbi_csr & SBICSR_WR; break; - case 2: /* SBIES (not impl) */ - case 3: /* SBIDCR (not impl) */ - case 4: /* DMAI CMD (not impl) */ - case 5: /* DMAI ID (not impl) */ - case 6: /* DMAA CMD (not impl) */ - case 7: /* DMAA ID (not impl) */ - case 8: /* DMAB CMD (not impl) */ - case 9: /* DMAB ID (not impl) */ - case 0xa: /* DMAC CMD (not impl) */ - case 0xb: /* DMAC ID (not impl) */ - case 0xc: /* SBIS (not impl) */ + case 2: /* SBIES (not impl) */ + case 3: /* SBIDCR (not impl) */ + case 4: /* DMAI CMD (not impl) */ + case 5: /* DMAI ID (not impl) */ + case 6: /* DMAA CMD (not impl) */ + case 7: /* DMAA ID (not impl) */ + case 8: /* DMAB CMD (not impl) */ + case 9: /* DMAB ID (not impl) */ + case 0xa: /* DMAC CMD (not impl) */ + case 0xb: /* DMAC ID (not impl) */ + case 0xc: /* SBIS (not impl) */ break; - case 0xd: /* SBIER */ + case 0xd: /* SBIER */ sbi_er = (sbi_er & ~SBIER_WR) | (val & SBIER_WR); sbi_er = sbi_er & ~(val & SBIER_W1C); if (val & SBIER_TMO) @@ -215,22 +215,22 @@ void sbia_wr (int32 pa, int32 val, int32 lnt) else crd_err = 0; break; - case 0xe: /* SBITA */ + case 0xe: /* SBITA */ break; - case 0xf: /* SBIFS */ + case 0xf: /* SBIFS */ sbi_fs = (sbi_fs & ~SBIFS_WR) | (val & SBIFS_WR); sbi_fs = sbi_fs & ~(val & SBIFS_W1C); break; - case 0x10: /* SBISC */ + case 0x10: /* SBISC */ sbi_sc = (sbi_sc & ~(SBISC_LOCK|SBISC_WR)) | (val & SBISC_WR); break; - case 0x11: /* SBIMT */ + case 0x11: /* SBIMT */ sbi_mt = (sbi_mt & ~SBIMT_WR) | (val & SBIMT_WR); break; - } + } return; } diff --git a/VAX/vax860_stddev.c b/VAX/vax860_stddev.c index ee67f5ce..387dceb8 100644 --- a/VAX/vax860_stddev.c +++ b/VAX/vax860_stddev.c @@ -189,7 +189,7 @@ #define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */ #define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */ #define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \ - RLDS_VCK+RLDS_DSE) /* errors bits */ + RLDS_VCK+RLDS_DSE) /* errors bits */ int32 tti_csr = 0; /* control/status */ int32 tti_buf = 0; /* buffer */ @@ -526,33 +526,33 @@ cso_csr = cso_csr & ~STXCS_STS; switch (fnc) { case RLFC_NOP: - break; + break; case RLFC_CONT: rlcs_bcnt = 0; case RLFC_STS: - rlcs_state = RL_STATUS; + rlcs_state = RL_STATUS; cso_csr = cso_csr & ~CSR_DONE; /* clear done */ - sim_activate (&rlcs_unit, rlcs_swait); - break; + sim_activate (&rlcs_unit, rlcs_swait); + break; case RLFC_ABORT: - rlcs_state = RL_ABORT; + rlcs_state = RL_ABORT; cso_csr = cso_csr & ~CSR_DONE; /* clear done */ - sim_activate (&rlcs_unit, rlcs_swait); - break; + sim_activate (&rlcs_unit, rlcs_swait); + break; case RLFC_WRITE: rlcs_state = RL_WRITE; cso_csr = cso_csr & ~CSR_DONE; /* clear done */ - sim_activate (&rlcs_unit, rlcs_swait); - break; + sim_activate (&rlcs_unit, rlcs_swait); + break; case RLFC_READ: rlcs_state = RL_READ; cso_csr = cso_csr & ~CSR_DONE; /* clear done */ - sim_activate (&rlcs_unit, rlcs_swait); - break; + sim_activate (&rlcs_unit, rlcs_swait); + break; default: printf ("CS: Unknown Command: %d\n", fnc); @@ -1095,7 +1095,7 @@ switch (rlcs_state) { case RL_IDLE: return SCPE_IERR; - case RL_READ: + case RL_READ: if ((cso_csr & CSR_DONE) == 0) { /* buf ready? */ if (rlcs_bcnt == 0) { /* read in whole block */ if ((uptr->flags & UNIT_ATT) == 0) { /* Attached? */ @@ -1127,7 +1127,7 @@ switch (rlcs_state) { break; } sim_activate (uptr, rlcs_swait); /* schedule next */ - break; + break; case RL_WRITE: if ((uptr->flags & UNIT_ATT) == 0) { /* Attached? */ @@ -1156,21 +1156,21 @@ switch (rlcs_state) { csi_int = 1; break; - case RL_ABORT: + case RL_ABORT: if ((cso_csr & CSR_DONE) == 0) { /* buf ready? */ cso_csr = cso_csr | CSR_DONE | /* aborted */ (RLST_ABORT << STXCS_V_STS); cso_buf = 0; rlcs_bcnt = 0; - rlcs_state = RL_IDLE; + rlcs_state = RL_IDLE; if (cso_csr & CSR_IE) csi_int = 1; break; } sim_activate (uptr, rlcs_swait); /* schedule next */ - break; + break; - case RL_STATUS: + case RL_STATUS: if ((cso_csr & CSR_DONE) == 0) { /* buf ready? */ switch (rlcs_sts_reg) { /* which register? */ @@ -1194,14 +1194,14 @@ switch (rlcs_state) { } cso_csr = cso_csr | CSR_DONE | /* returning status */ (RLST_STS << STXCS_V_STS); - rlcs_state = RL_IDLE; + rlcs_state = RL_IDLE; if (cso_csr & CSR_IE) csi_int = 1; break; } sim_activate (uptr, rlcs_swait); /* schedule next */ - break; - } + break; + } return SCPE_OK; } diff --git a/VAX/vax860_syslist.c b/VAX/vax860_syslist.c index 2038f046..49d7db0f 100644 --- a/VAX/vax860_syslist.c +++ b/VAX/vax860_syslist.c @@ -72,7 +72,7 @@ DEVICE *sim_devices[] = { &tmr_dev, &tti_dev, &tto_dev, - &rlcs_dev, + &rlcs_dev, &dz_dev, &vh_dev, &cr_dev, @@ -90,10 +90,10 @@ DEVICE *sim_devices[] = { &tq_dev, &xu_dev, &xub_dev, - &dmc_dev[0], - &dmc_dev[1], - &dmc_dev[2], - &dmc_dev[3], + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], &dup_dev, NULL }; diff --git a/VAX/vax_2681.c b/VAX/vax_2681.c new file mode 100644 index 00000000..bd285bd7 --- /dev/null +++ b/VAX/vax_2681.c @@ -0,0 +1,347 @@ +/* vax_2681.c: 2681 DUART Simulator + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 11-Jun-2013 MB First version +*/ + +#include "vax_2681.h" + +#define CMD_ERX 0x0001 /* Enable receiver */ +#define CMD_DRX 0x0002 /* Disable receiver */ +#define CMD_ETX 0x0004 /* Enable transmitter */ +#define CMD_DTX 0x0008 /* Disable transmitter */ +#define CMD_V_CMD 4 /* Command */ +#define CMD_M_CMD 0x7 + +#define STS_RXR 0x0001 /* Receiver ready */ +#define STS_FFL 0x0002 /* FIFO full */ +#define STS_TXR 0x0004 /* Transmitter ready */ +#define STS_TXE 0x0008 /* Transmitter empty */ +#define STS_OER 0x0010 /* Overrun error */ +#define STS_PER 0x0020 /* Parity error */ +#define STS_FER 0x0040 /* Framing error */ +#define STS_RXB 0x0080 /* Received break */ + +#define ISTS_TAI 0x0001 /* Transmitter ready A */ +#define ISTS_RAI 0x0002 /* Receiver ready A */ +#define ISTS_CBA 0x0004 /* Change in break A */ +#define ISTS_CRI 0x0008 /* Counter ready */ +#define ISTS_TBI 0x0010 /* Transmitter ready B */ +#define ISTS_RBI 0x0020 /* Receiver ready B */ +#define ISTS_CBB 0x0040 /* Change in break B */ +#define ISTS_IPC 0x0080 /* Interrupt port change */ + +#define MODE_V_CHM 6 /* Channel mode */ +#define MODE_M_CHM 0x3 + +#define PORT_A 0 +#define PORT_B 1 + +void ua2681_update_rxi (UART2681 *ctx); +void ua2681_update_txi (UART2681 *ctx); + + +void ua2681_wr (UART2681 *ctx, uint32 rg, uint32 data) +{ +uint32 mp; + +switch (rg) { + + case 0: /* mode 1A,2A */ + mp = ctx->port[PORT_A].mode_ptr; + ctx->port[PORT_A].mode[mp++] = data & 0xFF; + if (mp >= 2) mp = 0; + ctx->port[PORT_A].mode_ptr = mp; + break; + + case 1: /* status/clock A */ + /* Used to set baud rate - NI */ + break; + + case 2: /* command A */ + if (data & CMD_ETX) /* enable transmitter */ + ctx->port[PORT_A].cmd |= CMD_ETX; + else if (data & CMD_DTX) /* disable transmitter */ + ctx->port[PORT_A].cmd &= ~CMD_ETX; + + if (data & CMD_ERX) /* enable receiver */ + ctx->port[PORT_A].cmd |= CMD_ERX; + else if (data & CMD_DRX) /* disable receiver */ + ctx->port[PORT_A].cmd &= ~CMD_ERX; + + switch ((data >> CMD_V_CMD) & CMD_M_CMD) { + case 1: + ctx->port[PORT_A].mode_ptr = 0; + break; + + case 2: + ctx->port[PORT_A].cmd &= ~CMD_ERX; + ctx->port[PORT_A].sts &= ~STS_RXR; + break; + + case 3: + ctx->port[PORT_A].sts &= ~STS_TXR; + break; + + case 4: + ctx->port[PORT_A].sts &= ~(STS_FER | STS_PER | STS_OER); + break; + } + ua2681_update_rxi (ctx); + ua2681_update_txi (ctx); + break; + + case 3: /* tx/rx buf A */ + if (((ctx->port[PORT_A].mode[1] >> MODE_V_CHM) & MODE_M_CHM) == 0x2) { /* Maint */ + ctx->port[PORT_A].buf = data & 0xFF; + ctx->port[PORT_A].sts |= STS_RXR; + ctx->ists |= 0x2; + } + else { + if (ctx->port[PORT_A].put_char != NULL) + ctx->port[PORT_A].put_char (data); + } + ua2681_update_txi (ctx); + break; + + case 5: /* interrupt status/mask */ + ctx->imask = data & 0xFF; + break; + + case 8: /* mode 1B,2B */ + mp = ctx->port[PORT_B].mode_ptr; + ctx->port[PORT_B].mode[mp++] = data & 0xFF; + if (mp >= 2) mp = 0; + ctx->port[PORT_B].mode_ptr = mp; + break; + + case 9: /* status/clock B */ + /* Used to set baud rate - NI */ + break; + + case 10: /* command B */ + if (data & CMD_ETX) /* enable transmitter */ + ctx->port[PORT_B].cmd |= CMD_ETX; + else if (data & CMD_DTX) /* disable transmitter */ + ctx->port[PORT_B].cmd &= ~CMD_ETX; + + if (data & CMD_ERX) /* enable receiver */ + ctx->port[PORT_B].cmd |= CMD_ERX; + else if (data & CMD_DRX) /* disable receiver */ + ctx->port[PORT_B].cmd &= ~CMD_ERX; + + switch ((data >> CMD_V_CMD) & CMD_M_CMD) { + case 1: /* reset mode pointer */ + ctx->port[PORT_B].mode_ptr = 0; + break; + + case 2: + ctx->port[PORT_B].cmd &= ~CMD_ERX; + ctx->port[PORT_B].sts &= ~STS_RXR; + break; + + case 3: + ctx->port[PORT_B].sts &= ~STS_TXR; + break; + + case 4: + ctx->port[PORT_B].sts &= ~(STS_FER | STS_PER | STS_OER); + break; + } + ua2681_update_rxi (ctx); + ua2681_update_txi (ctx); + break; + + case 11: /* tx/rx buf B (mouse) */ + if (((ctx->port[PORT_B].mode[1] >> MODE_V_CHM) & MODE_M_CHM) == 0x2) { /* Maint */ + ctx->port[PORT_B].buf = data & 0xFF; + ctx->port[PORT_B].sts |= STS_RXR; + ctx->ists |= 0x20; + } + else { + if (ctx->port[PORT_B].put_char != NULL) + ctx->port[PORT_B].put_char (data); + } + ua2681_update_txi (ctx); + break; + + default: /* NI */ + break; + } +} + +uint32 ua2681_rd(UART2681 *ctx, uint32 rg) +{ +uint32 data; + +switch (rg) { + + case 0: /* mode 1A,2A */ + data = ctx->port[PORT_A].mode[ctx->port[PORT_A].mode_ptr]; + ctx->port[PORT_A].mode_ptr++; + if (ctx->port[PORT_A].mode_ptr >= 2) ctx->port[PORT_A].mode_ptr = 0; + break; + + case 1: /* status/clock A */ + data = ctx->port[PORT_A].sts; + break; + + case 3: /* tx/rx buf A */ + data = ctx->port[PORT_A].buf; + ctx->port[PORT_A].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RAI; + ua2681_update_rxi (ctx); + break; + + case 5: /* interrupt status/mask */ + data = ctx->ists; + break; + + case 8: /* mode 1B,2B */ + data = ctx->port[PORT_B].mode[ctx->port[PORT_B].mode_ptr]; + ctx->port[PORT_B].mode_ptr++; + if (ctx->port[PORT_B].mode_ptr >= 2) ctx->port[PORT_B].mode_ptr = 0; + break; + + case 9: /* status/clock B */ + data = ctx->port[PORT_B].sts; + break; + + case 11: /* tx/rx buf B */ + data = ctx->port[PORT_B].buf; + ctx->port[PORT_B].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RBI; + ua2681_update_rxi (ctx); + break; + + default: /* NI */ + data = 0; + break; + } + +return data; +} + +void ua2681_update_txi (UART2681 *ctx) +{ +if (ctx->port[PORT_A].cmd & CMD_ETX) { /* Transmitter A enabled? */ + ctx->port[PORT_A].sts |= STS_TXR; /* ready */ + ctx->port[PORT_A].sts |= STS_TXE; /* empty */ + ctx->ists |= ISTS_TAI; /* set int */ + } +else { + ctx->port[PORT_A].sts &= ~STS_TXR; /* clear ready */ + ctx->port[PORT_A].sts &= ~STS_TXE; /* clear empty */ + ctx->ists &= ~ISTS_TAI; /* clear int */ + } +if (ctx->port[PORT_B].cmd & CMD_ETX) { /* Transmitter B enabled? */ + ctx->port[PORT_B].sts |= STS_TXR; /* ready */ + ctx->port[PORT_B].sts |= STS_TXE; /* empty */ + ctx->ists |= ISTS_TBI; /* set int */ + } +else { + ctx->port[PORT_B].sts &= ~STS_TXR; /* clear ready */ + ctx->port[PORT_B].sts &= ~STS_TXE; /* clear empty */ + ctx->ists &= ~ISTS_TBI; /* clear int */ + } +if ((ctx->ists & ctx->imask) > 0) /* unmasked ints? */ + ctx->set_int (1); +else ctx->set_int (0); +} + +void ua2681_update_rxi (UART2681 *ctx) +{ +uint8 c; +t_stat r; + +if (ctx->port[PORT_A].cmd & CMD_ERX) { + if (((ctx->port[PORT_A].sts & STS_RXR) == 0) && + (ctx->port[PORT_A].get_char != NULL)) { + r = ctx->port[PORT_A].get_char (&c); + if (r == SCPE_OK) { + ctx->port[PORT_A].buf = c; + ctx->port[PORT_A].sts |= STS_RXR; + ctx->ists |= ISTS_RAI; + } + else { + ctx->port[PORT_A].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RAI; + } + } + } +else { + ctx->port[PORT_A].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RAI; + } + +if (ctx->port[PORT_B].cmd & CMD_ERX) { + if (((ctx->port[PORT_B].sts & STS_RXR) == 0) && + (ctx->port[PORT_B].get_char != NULL)) { + r = ctx->port[PORT_B].get_char (&c); + if (r == SCPE_OK) { + ctx->port[PORT_B].buf = c; + ctx->port[PORT_B].sts |= STS_RXR; + ctx->ists |= ISTS_RBI; + } + else { + ctx->port[PORT_B].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RBI; + } + } + } +else { + ctx->port[PORT_B].sts &= ~STS_RXR; + ctx->ists &= ~ISTS_RBI; + } + +if ((ctx->ists & ctx->imask) > 0) + ctx->set_int (1); +else ctx->set_int (0); +} + +t_stat ua2681_svc (UART2681 *ctx) +{ +ua2681_update_rxi (ctx); +return SCPE_OK; +} + +t_stat ua2681_reset (UART2681 *ctx) +{ +ctx->ists = 0; +ctx->imask = 0; + +ctx->port[PORT_A].sts = 0; +ctx->port[PORT_A].mode[0] = 0; +ctx->port[PORT_A].mode[1] = 0; +ctx->port[PORT_A].mode_ptr = 0; +ctx->port[PORT_A].buf = 0; + +ctx->port[PORT_B].sts = 0; +ctx->port[PORT_B].mode[0] = 0; +ctx->port[PORT_B].mode[1] = 0; +ctx->port[PORT_B].mode_ptr = 0; +ctx->port[PORT_B].buf = 0; +return SCPE_OK; +} diff --git a/VAX/vax_2681.h b/VAX/vax_2681.h new file mode 100644 index 00000000..7351ca9a --- /dev/null +++ b/VAX/vax_2681.h @@ -0,0 +1,57 @@ +/* vax_2681.h: 2681 DUART Simulator + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 11-Jun-2013 MB First version +*/ + +#include "sim_defs.h" + +typedef t_stat (*put_char_t)(uint8); +typedef t_stat (*get_char_t)(uint8*); +typedef void (*set_int_t)(uint32); + +struct uart2681_port_t { + put_char_t put_char; + get_char_t get_char; + uint32 sts; + uint32 cmd; + uint32 mode[2]; + uint32 mode_ptr; + uint32 buf; + }; + +struct uart2681_t { + set_int_t set_int; + struct uart2681_port_t port[2]; + uint32 ists; + uint32 imask; + }; + +typedef struct uart2681_t UART2681; + +void ua2681_wr (UART2681 *ctx, uint32 rg, uint32 data); +uint32 ua2681_rd (UART2681 *ctx, uint32 rg); +t_stat ua2681_svc (UART2681 *ctx); +t_stat ua2681_reset (UART2681 *ctx); diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 9f1e31ac..da5dc8f4 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1480,7 +1480,7 @@ for ( ;; ) { default: RSVD_ADDR_FAULT; /* end case idxspec */ - } + } switch (disp & (DR_ACMASK|DR_SPFLAG|DR_LNMASK)) { /* case acc+lnt */ case VB: @@ -2954,7 +2954,7 @@ for ( ;; ) { if (op7 < 0) { Read (op8, L_BYTE, WA); Read ((op8 + 7) & LMASK, L_BYTE, WA); - } + } if (op5 >= 0) R[op5] = temp; else Write (op6, temp, L_LONG, WA); @@ -2970,7 +2970,7 @@ for ( ;; ) { if (op7 < 0) { Read (op8, L_BYTE, WA); Read ((op8 + 7) & LMASK, L_BYTE, WA); - } + } if (op5 >= 0) R[op5] = temp; else Write (op6, temp, L_LONG, WA); diff --git a/VAX/vax_io.c b/VAX/vax_io.c index f498a3ec..58a761a6 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -387,7 +387,7 @@ if (lnt < L_LONG) { int32 t = cqbic_rd (pa); nval = ((val & mask) << sc) | (t & ~(mask << sc)); val = val << sc; - } + } else nval = val; switch (rg) { diff --git a/VAX/vax_lk.c b/VAX/vax_lk.c new file mode 100644 index 00000000..5afe3242 --- /dev/null +++ b/VAX/vax_lk.c @@ -0,0 +1,828 @@ +/* vax_lk.c: DEC Keyboard (LK201) + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + lk LK201 keyboard + + 11-Jun-2013 MB First version +*/ + +#include "vax_defs.h" +#include "sim_video.h" + +/* States */ + +#define LK_IDLE 0 +#define LK_RECV 1 +#define LK_SEND 2 + +/* Key group moding */ + +#define LK_MODE_DOWN 0 +#define LK_MODE_AUTODOWN 1 +#define LK_MODE_NONE 2 +#define LK_MODE_DOWNUP 3 + +/* Scan codes */ + +typedef struct { + int8 group; + int8 code; +} LK_KEYDATA; + +LK_KEYDATA LK_KEY_UNKNOWN = { 0, 0 }; +LK_KEYDATA LK_KEY_TR_0 = { 1, 0xEF }; +LK_KEYDATA LK_KEY_TR_1 = { 1, 0xC0 }; +LK_KEYDATA LK_KEY_TR_2 = { 1, 0xC5 }; +LK_KEYDATA LK_KEY_TR_3 = { 1, 0xCB }; +LK_KEYDATA LK_KEY_TR_4 = { 1, 0xD0 }; +LK_KEYDATA LK_KEY_TR_5 = { 1, 0xD6 }; +LK_KEYDATA LK_KEY_TR_6 = { 1, 0xDB }; +LK_KEYDATA LK_KEY_TR_7 = { 1, 0xE0 }; +LK_KEYDATA LK_KEY_TR_8 = { 1, 0xE5 }; +LK_KEYDATA LK_KEY_TR_9 = { 1, 0xEA }; +LK_KEYDATA LK_KEY_A = { 1, 0xC2 }; +LK_KEYDATA LK_KEY_B = { 1, 0xD9 }; +LK_KEYDATA LK_KEY_C = { 1, 0xCE }; +LK_KEYDATA LK_KEY_D = { 1, 0xCD }; +LK_KEYDATA LK_KEY_E = { 1, 0xCC }; +LK_KEYDATA LK_KEY_F = { 1, 0xD2 }; +LK_KEYDATA LK_KEY_G = { 1, 0xD8 }; +LK_KEYDATA LK_KEY_H = { 1, 0xDD }; +LK_KEYDATA LK_KEY_I = { 1, 0xE6 }; +LK_KEYDATA LK_KEY_J = { 1, 0xE2 }; +LK_KEYDATA LK_KEY_K = { 1, 0xE7 }; +LK_KEYDATA LK_KEY_L = { 1, 0xEC }; +LK_KEYDATA LK_KEY_M = { 1, 0xE3 }; +LK_KEYDATA LK_KEY_N = { 1, 0xDE }; +LK_KEYDATA LK_KEY_O = { 1, 0xEB }; +LK_KEYDATA LK_KEY_P = { 1, 0xF0 }; +LK_KEYDATA LK_KEY_Q = { 1, 0xC1 }; +LK_KEYDATA LK_KEY_R = { 1, 0xD1 }; +LK_KEYDATA LK_KEY_S = { 1, 0xC7 }; +LK_KEYDATA LK_KEY_T = { 1, 0xD7 }; +LK_KEYDATA LK_KEY_U = { 1, 0xE1 }; +LK_KEYDATA LK_KEY_V = { 1, 0xD3 }; +LK_KEYDATA LK_KEY_W = { 1, 0xC6 }; +LK_KEYDATA LK_KEY_X = { 1, 0xC8 }; +LK_KEYDATA LK_KEY_Y = { 1, 0xDC }; +LK_KEYDATA LK_KEY_Z = { 1, 0xC3 }; +LK_KEYDATA LK_KEY_SPACE = { 1, 0xD4 }; +LK_KEYDATA LK_KEY_SEMICOLON = { 1, 0xF2 }; +LK_KEYDATA LK_KEY_PLUS = { 1, 0xF5 }; +LK_KEYDATA LK_KEY_COMMA = { 1, 0xE8 }; +LK_KEYDATA LK_KEY_UBAR = { 1, 0xF9 }; +LK_KEYDATA LK_KEY_PERIOD = { 1, 0xED }; +LK_KEYDATA LK_KEY_QMARK = { 1, 0xF3 }; +LK_KEYDATA LK_KEY_QUOTE = { 1, 0xFB }; +LK_KEYDATA LK_KEY_LBRACE = { 1, 0xFA }; +LK_KEYDATA LK_KEY_RBRACE = { 1, 0xF6 }; +LK_KEYDATA LK_KEY_VBAR = { 1, 0xF7 }; +LK_KEYDATA LK_KEY_TILDE = { 1, 0xBF }; +LK_KEYDATA LK_KEY_KP_0 = { 2, 0x92 }; +LK_KEYDATA LK_KEY_KP_1 = { 2, 0x96 }; +LK_KEYDATA LK_KEY_KP_2 = { 2, 0x97 }; +LK_KEYDATA LK_KEY_KP_3 = { 2, 0x98 }; +LK_KEYDATA LK_KEY_KP_4 = { 2, 0x99 }; +LK_KEYDATA LK_KEY_KP_5 = { 2, 0x9A }; +LK_KEYDATA LK_KEY_KP_6 = { 2, 0x9B }; +LK_KEYDATA LK_KEY_KP_7 = { 2, 0x9D }; +LK_KEYDATA LK_KEY_KP_8 = { 2, 0x9E }; +LK_KEYDATA LK_KEY_KP_9 = { 2, 0x9F }; +LK_KEYDATA LK_KEY_KP_PF1 = { 2, 0xA1 }; +LK_KEYDATA LK_KEY_KP_PF2 = { 2, 0xA2 }; +LK_KEYDATA LK_KEY_KP_PF3 = { 2, 0xA3 }; +LK_KEYDATA LK_KEY_KP_PF4 = { 2, 0xA4 }; +LK_KEYDATA LK_KEY_KP_HYPHEN = { 2, 0xA0 }; +LK_KEYDATA LK_KEY_KP_COMMA = { 2, 0x9C }; +LK_KEYDATA LK_KEY_KP_PERIOD = { 2, 0x94 }; +LK_KEYDATA LK_KEY_KP_ENTER = { 2, 0x95 }; +LK_KEYDATA LK_KEY_DELETE = { 3, 0xBC }; +LK_KEYDATA LK_KEY_TAB = { 3, 0xBE }; +LK_KEYDATA LK_KEY_RETURN = { 4, 0xBD }; +LK_KEYDATA LK_KEY_META = { 5, 0xB1 }; +LK_KEYDATA LK_KEY_LOCK = { 5, 0xB0 }; +LK_KEYDATA LK_KEY_SHIFT = { 6, 0xAE }; +LK_KEYDATA LK_KEY_CTRL = { 6, 0xAF }; +LK_KEYDATA LK_KEY_LEFT = { 7, 0xA7 }; +LK_KEYDATA LK_KEY_RIGHT = { 7, 0xA8 }; +LK_KEYDATA LK_KEY_UP = { 8, 0xAA }; +LK_KEYDATA LK_KEY_DOWN = { 8, 0xA9 }; +LK_KEYDATA LK_KEY_REMOVE = { 9, 0x8C }; +LK_KEYDATA LK_KEY_NEXT_SCREEN= { 9, 0x8F }; +LK_KEYDATA LK_KEY_PREV_SCREEN= { 9, 0x8E }; +LK_KEYDATA LK_KEY_INSERT_HERE= { 9, 0x8B }; +LK_KEYDATA LK_KEY_FIND = { 9, 0x8A }; +LK_KEYDATA LK_KEY_SELECT = { 9, 0x8D }; +LK_KEYDATA LK_KEY_F1 = { 10, 0x56 }; +LK_KEYDATA LK_KEY_F2 = { 10, 0x57 }; +LK_KEYDATA LK_KEY_F3 = { 10, 0x58 }; +LK_KEYDATA LK_KEY_F4 = { 10, 0x59 }; +LK_KEYDATA LK_KEY_F5 = { 10, 0x5A }; +LK_KEYDATA LK_KEY_F6 = { 11, 0x64 }; +LK_KEYDATA LK_KEY_F7 = { 11, 0x65 }; +LK_KEYDATA LK_KEY_F8 = { 11, 0x66 }; +LK_KEYDATA LK_KEY_F9 = { 11, 0x67 }; +LK_KEYDATA LK_KEY_F10 = { 11, 0x68 }; +LK_KEYDATA LK_KEY_F11 = { 12, 0x71 }; +LK_KEYDATA LK_KEY_F12 = { 12, 0x72 }; + +#define LK_BUF_LEN 100 + +#define LK_SEND_CHAR(c) lk_sbuf[lk_stptr++] = c; \ + if (lk_stptr == LK_BUF_LEN) lk_stptr = 0 + +/* Debugging Bitmaps */ + +#define DBG_SERIAL 0x0001 /* serial port data */ +#define DBG_CMD 0x0002 /* commands */ + +t_bool lk_repeat = TRUE; /* autorepeat flag */ +t_bool lk_trpti = FALSE; /* temp repeat inhibit */ +int32 lk_keysdown = 0; /* no of keys held down */ +uint8 lk_sbuf[LK_BUF_LEN]; /* send buffer */ +int32 lk_shptr = 0; /* send buf head ptr */ +int32 lk_stptr = 0; /* send buf tail ptr */ +uint8 lk_rbuf[10]; /* receive buffer */ +int32 lk_rbuf_p = 0; /* receive buffer ptr */ +int32 lk_mode[15]; /* mode of each key group */ + +DEVICE lk_dev; +t_stat lk_wr (uint8 c); +t_stat lk_rd (uint8 *c); +t_stat lk_reset (DEVICE *dptr); +void lk_reset_mode (void); +void lk_cmd (void); +void lk_poll (void); + +/* LK data structures + + lk_dev LK device descriptor + lk_unit LK unit list + lk_reg LK register list + lk_mod LK modifier list + lk_debug LK debug list +*/ + +DEBTAB lk_debug[] = { + {"SERIAL", DBG_SERIAL}, + {"CMD", DBG_CMD}, + {0} + }; + +UNIT lk_unit = { UDATA (NULL, 0, 0) }; + +REG lk_reg[] = { + { NULL } + }; + +MTAB lk_mod[] = { + { 0 } + }; + +DEVICE lk_dev = { + "LK", &lk_unit, lk_reg, lk_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &lk_reset, + NULL, NULL, NULL, + NULL, DEV_DIS | DEV_DEBUG, 0, + lk_debug + }; + +/* Incoming data on serial line */ + +t_stat lk_wr (uint8 c) +{ +sim_debug (DBG_SERIAL, &lk_dev, "vax -> lk: %02X\n", c); +if (c == 0) + return SCPE_OK; +lk_rbuf[lk_rbuf_p++] = c; +if (lk_rbuf_p == 10) { /* too long? */ + lk_rbuf_p = 0; + LK_SEND_CHAR(0xB6); /* input error */ + return SCPE_OK; + } +if (c & 0x80) /* cmd terminator? */ + lk_cmd(); /* process cmd */ +return SCPE_OK; +} + +/* Outgoing data on serial line */ + +t_stat lk_rd (uint8 *c) +{ +if (lk_shptr == lk_stptr) + lk_poll (); +if (lk_shptr == lk_stptr) { + *c = 0; + return SCPE_EOF; + } +else { + *c = lk_sbuf[lk_shptr++]; + sim_debug (DBG_SERIAL, &lk_dev, "lk -> vax: %02X (%s)\n", *c, + (lk_shptr != lk_stptr) ? "more" : "end"); + if (lk_shptr == LK_BUF_LEN) + lk_shptr = 0; /* ring buffer wrap */ + return SCPE_OK; + } +} + +void lk_cmd () +{ +int32 i, group, mode; + +if (lk_rbuf[0] & 1) { /* peripheral command */ + switch (lk_rbuf[0]) { + + case 0x11: + sim_debug (DBG_CMD, &lk_dev, "LED on\n"); + break; + + case 0x13: + sim_debug (DBG_CMD, &lk_dev, "LED off\n"); + break; + + case 0x89: + sim_debug (DBG_CMD, &lk_dev, "inhibit keyboard transmission\n"); + break; + + case 0x8B: + sim_debug (DBG_CMD, &lk_dev, "resume keyboard transmission\n"); + lk_shptr = lk_stptr = 0; + break; + + case 0x99: + sim_debug (DBG_CMD, &lk_dev, "disable keyclick\n"); + break; + + case 0x1B: + sim_debug (DBG_CMD, &lk_dev, "enable keyclick, volume = \n"); + break; + + case 0xB9: + sim_debug (DBG_CMD, &lk_dev, "disable ctrl keyclick\n"); + break; + + case 0xBB: + sim_debug (DBG_CMD, &lk_dev, "enable ctrl keyclick\n"); + break; + + case 0x9F: + sim_debug (DBG_CMD, &lk_dev, "sound keyclick\n"); + break; + + case 0xA1: + sim_debug (DBG_CMD, &lk_dev, "disable bell\n"); + break; + + case 0x23: + sim_debug (DBG_CMD, &lk_dev, "enable bell, volume = \n"); + break; + + case 0xA7: + sim_debug (DBG_CMD, &lk_dev, "sound bell\n"); + break; + + case 0xC1: + sim_debug (DBG_CMD, &lk_dev, "temporary auto-repeat inhibit\n"); + lk_trpti = TRUE; + break; + + case 0xE3: + sim_debug (DBG_CMD, &lk_dev, "enable auto-repeat across keyboard\n"); + lk_repeat = TRUE; + break; + + case 0xE1: + sim_debug (DBG_CMD, &lk_dev, "disable auto-repeat across keyboard\n"); + lk_repeat = FALSE; + break; + + case 0xD9: + sim_debug (DBG_CMD, &lk_dev, "change all auto-repeat to down only\n"); + for (i = 0; i <= 15; i++) { + if (lk_mode[i] == LK_MODE_AUTODOWN) + lk_mode[i] = LK_MODE_DOWN; + } + break; + + case 0xAB: + sim_debug (DBG_CMD, &lk_dev, "request keyboard ID\n"); + LK_SEND_CHAR (0x01); + LK_SEND_CHAR (0x00); + break; + + case 0xFD: + sim_debug (DBG_CMD, &lk_dev, "jump to power-up\n"); + LK_SEND_CHAR (0x01); + LK_SEND_CHAR (0x00); + LK_SEND_CHAR (0x00); + LK_SEND_CHAR (0x00); + break; + + case 0xCB: + sim_debug (DBG_CMD, &lk_dev, "jump to test mode\n"); + break; + + case 0xD3: + sim_debug (DBG_CMD, &lk_dev, "reinstate defaults\n"); + lk_reset_mode (); + lk_repeat = TRUE; + lk_trpti = FALSE; + LK_SEND_CHAR (0xBA); /* Mode change ACK */ + break; + + default: + printf ("lk: unknown cmd %02X\n", lk_rbuf[0]); + break; + } + } + else { + group = (lk_rbuf[0] >> 3) & 0xF; + if (group < 15) { + sim_debug (DBG_CMD, &lk_dev, "set group %d, ", group); + mode = (lk_rbuf[0] >> 1) & 0x3; + lk_mode[group] = mode; + switch (mode) { + case LK_MODE_DOWN: + sim_debug (DBG_CMD, &lk_dev, "mode = DOWN\n"); + break; + + case LK_MODE_AUTODOWN: + sim_debug (DBG_CMD, &lk_dev, "mode = AUTODOWN\n"); + break; + + case LK_MODE_DOWNUP: + sim_debug (DBG_CMD, &lk_dev, "mode = DOWNUP\n"); + break; + } + LK_SEND_CHAR (0xBA); /* Mode change ACK */ + } + else + sim_debug (DBG_CMD, &lk_dev, "set auto-repeat timing\n"); + } + lk_rbuf_p = 0; +} + +LK_KEYDATA lk_map_key (int key) +{ +LK_KEYDATA lk_key; + +switch (key) { + + case SIM_KEY_F1: + lk_key = LK_KEY_F1; + break; + + case SIM_KEY_F2: + lk_key = LK_KEY_F2; + break; + + case SIM_KEY_F3: + lk_key = LK_KEY_F3; + break; + + case SIM_KEY_F4: + lk_key = LK_KEY_F4; + break; + + case SIM_KEY_F5: + lk_key = LK_KEY_F5; + break; + + case SIM_KEY_F6: + lk_key = LK_KEY_F6; + break; + + case SIM_KEY_F7: + lk_key = LK_KEY_F7; + break; + + case SIM_KEY_F8: + lk_key = LK_KEY_F8; + break; + + case SIM_KEY_F9: + lk_key = LK_KEY_F9; + break; + + case SIM_KEY_F10: + lk_key = LK_KEY_F10; + break; + + case SIM_KEY_F11: + lk_key = LK_KEY_F11; + break; + + case SIM_KEY_F12: + lk_key = LK_KEY_F12; + break; + + case SIM_KEY_0: + lk_key = LK_KEY_TR_0; + break; + + case SIM_KEY_1: + lk_key = LK_KEY_TR_1; + break; + + case SIM_KEY_2: + lk_key = LK_KEY_TR_2; + break; + + case SIM_KEY_3: + lk_key = LK_KEY_TR_3; + break; + + case SIM_KEY_4: + lk_key = LK_KEY_TR_4; + break; + + case SIM_KEY_5: + lk_key = LK_KEY_TR_5; + break; + + case SIM_KEY_6: + lk_key = LK_KEY_TR_6; + break; + + case SIM_KEY_7: + lk_key = LK_KEY_TR_7; + break; + + case SIM_KEY_8: + lk_key = LK_KEY_TR_8; + break; + + case SIM_KEY_9: + lk_key = LK_KEY_TR_9; + break; + + case SIM_KEY_A: + lk_key = LK_KEY_A; + break; + + case SIM_KEY_B: + lk_key = LK_KEY_B; + break; + + case SIM_KEY_C: + lk_key = LK_KEY_C; + break; + + case SIM_KEY_D: + lk_key = LK_KEY_D; + break; + + case SIM_KEY_E: + lk_key = LK_KEY_E; + break; + + case SIM_KEY_F: + lk_key = LK_KEY_F; + break; + + case SIM_KEY_G: + lk_key = LK_KEY_G; + break; + + case SIM_KEY_H: + lk_key = LK_KEY_H; + break; + + case SIM_KEY_I: + lk_key = LK_KEY_I; + break; + + case SIM_KEY_J: + lk_key = LK_KEY_J; + break; + + case SIM_KEY_K: + lk_key = LK_KEY_K; + break; + + case SIM_KEY_L: + lk_key = LK_KEY_L; + break; + + case SIM_KEY_M: + lk_key = LK_KEY_M; + break; + + case SIM_KEY_N: + lk_key = LK_KEY_N; + break; + + case SIM_KEY_O: + lk_key = LK_KEY_O; + break; + + case SIM_KEY_P: + lk_key = LK_KEY_P; + break; + + case SIM_KEY_Q: + lk_key = LK_KEY_Q; + break; + + case SIM_KEY_R: + lk_key = LK_KEY_R; + break; + + case SIM_KEY_S: + lk_key = LK_KEY_S; + break; + + case SIM_KEY_T: + lk_key = LK_KEY_T; + break; + + case SIM_KEY_U: + lk_key = LK_KEY_U; + break; + + case SIM_KEY_V: + lk_key = LK_KEY_V; + break; + + case SIM_KEY_W: + lk_key = LK_KEY_W; + break; + + case SIM_KEY_X: + lk_key = LK_KEY_X; + break; + + case SIM_KEY_Y: + lk_key = LK_KEY_Y; + break; + + case SIM_KEY_Z: + lk_key = LK_KEY_Z; + break; + + case SIM_KEY_BACKQUOTE: + lk_key = LK_KEY_TILDE; + break; + + case SIM_KEY_MINUS: + lk_key = LK_KEY_UBAR; + break; + + case SIM_KEY_EQUALS: + lk_key = LK_KEY_PLUS; + break; + + case SIM_KEY_LEFT_BRACKET: + lk_key = LK_KEY_LBRACE; + break; + + case SIM_KEY_RIGHT_BRACKET: + lk_key = LK_KEY_RBRACE; + break; + + case SIM_KEY_SEMICOLON: + lk_key = LK_KEY_SEMICOLON; + break; + + case SIM_KEY_SINGLE_QUOTE: + lk_key = LK_KEY_QUOTE; + break; + + case SIM_KEY_BACKSLASH: + lk_key = LK_KEY_VBAR; + break; + + case SIM_KEY_LEFT_BACKSLASH: + case SIM_KEY_COMMA: + lk_key = LK_KEY_COMMA; + break; + + case SIM_KEY_PERIOD: + lk_key = LK_KEY_PERIOD; + break; + + case SIM_KEY_SLASH: + lk_key = LK_KEY_QMARK; + break; + + /* case SIM_KEY_PRINT: */ + /* case SIM_KEY_PAUSE: */ + /* case SIM_KEY_ESC: */ + + case SIM_KEY_BACKSPACE: + lk_key = LK_KEY_DELETE; + break; + + case SIM_KEY_TAB: + lk_key = LK_KEY_TAB; + break; + + case SIM_KEY_ENTER: + lk_key = LK_KEY_RETURN; + break; + + case SIM_KEY_SPACE: + lk_key = LK_KEY_SPACE; + break; + + case SIM_KEY_INSERT: + lk_key = LK_KEY_FIND; + break; + + case SIM_KEY_DELETE: + lk_key = LK_KEY_SELECT; + break; + + case SIM_KEY_HOME: + lk_key = LK_KEY_INSERT_HERE; + break; + + case SIM_KEY_END: + lk_key = LK_KEY_PREV_SCREEN; + break; + + case SIM_KEY_PAGE_UP: + lk_key = LK_KEY_REMOVE; + break; + + case SIM_KEY_PAGE_DOWN: + lk_key = LK_KEY_NEXT_SCREEN; + break; + + case SIM_KEY_UP: + lk_key = LK_KEY_UP; + break; + + case SIM_KEY_DOWN: + lk_key = LK_KEY_DOWN; + break; + + case SIM_KEY_LEFT: + lk_key = LK_KEY_LEFT; + break; + + case SIM_KEY_RIGHT: + lk_key = LK_KEY_RIGHT; + break; + + case SIM_KEY_CAPS_LOCK: + lk_key = LK_KEY_LOCK; + break; + + case SIM_KEY_NUM_LOCK: + lk_key = LK_KEY_KP_PF1; + break; + + case SIM_KEY_SCRL_LOCK: + + case SIM_KEY_ALT_L: + case SIM_KEY_ALT_R: + lk_key = LK_KEY_META; + break; + + case SIM_KEY_CTRL_L: + case SIM_KEY_CTRL_R: + lk_key = LK_KEY_CTRL; + break; + + case SIM_KEY_SHIFT_L: + case SIM_KEY_SHIFT_R: + lk_key = LK_KEY_SHIFT; + break; + + case SIM_KEY_WIN_L: + case SIM_KEY_WIN_R: + case SIM_KEY_MENU: + lk_key = LK_KEY_UNKNOWN; + break; + + case SIM_KEY_KP_ADD: + case SIM_KEY_KP_SUBTRACT: + case SIM_KEY_KP_END: + case SIM_KEY_KP_DOWN: + case SIM_KEY_KP_PAGE_DOWN: + case SIM_KEY_KP_LEFT: + case SIM_KEY_KP_RIGHT: + case SIM_KEY_KP_HOME: + case SIM_KEY_KP_UP: + case SIM_KEY_KP_PAGE_UP: + case SIM_KEY_KP_INSERT: + case SIM_KEY_KP_DELETE: + case SIM_KEY_KP_5: + case SIM_KEY_KP_ENTER: + case SIM_KEY_KP_MULTIPLY: + case SIM_KEY_KP_DIVIDE: + + case SIM_KEY_UNKNOWN: + lk_key = LK_KEY_UNKNOWN; + break; + + default: + lk_key = LK_KEY_UNKNOWN; + break; + } +return lk_key; +} + +void lk_reset_mode (void) +{ +lk_mode[1] = LK_MODE_AUTODOWN; /* 1 = 48 graphic keys, spacebar */ +lk_mode[2] = LK_MODE_AUTODOWN; /* 2 = numeric keypad */ +lk_mode[3] = LK_MODE_AUTODOWN; /* 3 = delete character */ +lk_mode[4] = LK_MODE_DOWN; /* 4 = return, tab */ +lk_mode[5] = LK_MODE_DOWN; /* 5 = lock, compose */ +lk_mode[6] = LK_MODE_DOWNUP; /* 6 = shift, ctrl */ +lk_mode[7] = LK_MODE_AUTODOWN; /* 7 = horizontal cursors */ +lk_mode[8] = LK_MODE_AUTODOWN; /* 8 = vertical cursors */ +lk_mode[9] = LK_MODE_DOWNUP; /* 9 = six basic editing keys */ +lk_mode[10] = LK_MODE_AUTODOWN; /* 10 = function keys: f1 - f5 */ +lk_mode[11] = LK_MODE_AUTODOWN; /* 11 = function keys: f6 - f10 */ +lk_mode[12] = LK_MODE_AUTODOWN; /* 12 = function keys: f11 - f14 */ +lk_mode[13] = LK_MODE_AUTODOWN; /* 13 = function keys: help, do */ +lk_mode[14] = LK_MODE_AUTODOWN; /* 14 = function keys: f17 - f20 */ +} + +t_stat lk_reset (DEVICE *dptr) +{ +lk_rbuf_p = 0; +lk_keysdown = 0; +lk_repeat = TRUE; +lk_trpti = FALSE; +lk_shptr = 0; +lk_stptr = 0; +lk_reset_mode (); +return SCPE_OK; +} + +void lk_poll (void) +{ +SIM_KEY_EVENT ev; +LK_KEYDATA lk_key; +int32 mode; + +if (vid_poll_kb (&ev) != SCPE_OK) + return; + +lk_key = lk_map_key (ev.key); +mode = lk_mode[lk_key.group]; + +if (lk_trpti && (ev.state != SIM_KEYPRESS_REPEAT)) + lk_trpti = FALSE; + +switch (mode) { + + case LK_MODE_DOWN: + if (ev.state == SIM_KEYPRESS_DOWN) { + LK_SEND_CHAR (lk_key.code); + } + break; + + case LK_MODE_AUTODOWN: + if (ev.state == SIM_KEYPRESS_DOWN) { + LK_SEND_CHAR (lk_key.code); + } + else if ((ev.state == SIM_KEYPRESS_REPEAT) && lk_repeat && !lk_trpti) { + LK_SEND_CHAR (0xB4); + } + break; + + case LK_MODE_DOWNUP: + if (ev.state == SIM_KEYPRESS_DOWN) { + lk_keysdown++; + LK_SEND_CHAR (lk_key.code); + } + else { + lk_keysdown--; + if (lk_keysdown > 0) { + LK_SEND_CHAR (lk_key.code); + } + else { + LK_SEND_CHAR (0xB3); /* LK_ALLUP */ + } + } + break; + } +} diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index 19865134..a7fffc58 100644 --- a/VAX/vax_sys.c +++ b/VAX/vax_sys.c @@ -764,7 +764,7 @@ if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */ for (vp = lnt - 1; vp >= 0; vp--) { c = (int32) val[vp] & 0x7F; fprintf (of, (c < 0x20)? "<%02X>": "%c", c); - } + } return -(lnt - 1); /* return # chars */ } diff --git a/VAX/vax_syscm.c b/VAX/vax_syscm.c index 46225523..883286d2 100644 --- a/VAX/vax_syscm.c +++ b/VAX/vax_syscm.c @@ -27,7 +27,7 @@ 22-May-10 RMS Fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) 12-Nov-06 RMS Fixed operand order in EIS instructions (W.F.J. Mueller) - 27-Sep-05 RMS Fixed warnings compiling with 64b addresses + 27-Sep-05 RMS Fixed warnings compiling with 64b addresses 15-Sep-04 RMS Cloned from pdp11_sys.c */ @@ -686,6 +686,6 @@ if (*cptr != 0) return SCPE_ARG; /* junk at end? */ for (i = j = 0; i < 3; i++, j = j + 2) { bytes[j] = val[i] & BMASK; bytes[j + 1] = (val[i] >> 8) & BMASK; - } + } return ((2 * (n1 + n2)) - 1); } diff --git a/VAX/vax_vc.c b/VAX/vax_vc.c new file mode 100644 index 00000000..b519cd72 --- /dev/null +++ b/VAX/vax_vc.c @@ -0,0 +1,834 @@ +/* vax_vc.c: QVSS video simulator (VCB01) + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + vc Qbus video subsystem + + 11-Jun-2013 MB First version +*/ + +#include "vax_defs.h" +#include "sim_video.h" +#include "vax_2681.h" + +/* CSR - control/status register */ + +BITFIELD vc_csr_bits[] = { + BIT(MOD), /* Monitor size */ +#define CSR_V_MDO 0 +#define CSR_MOD (1<> 5) | (y << 5)) /* index into framebuffer */ +#define CUR_X (vc_curx & 0x3FF) /* cursor X */ +#define CUR_Y ((vc_crtc[CRTC_CAH] * \ + (vc_crtc[CRTC_MSCN] + 1)) + \ + vc_crtc[CRTC_CSCS]) /* cursor Y */ +#define CUR_V ((vc_crtc[CRTC_CSCS] & 0x20) == 0) /* cursor visible */ +#define CUR_F (vc_csr & CSR_FNC) /* cursor function */ + +#define IOLN_QVSS 0100 + +extern int32 int_req[IPL_HLVL]; +extern int32 tmxr_poll; /* calibrated delay */ + +extern t_stat lk_wr (uint8 c); +extern t_stat lk_rd (uint8 *c); +extern t_stat vs_wr (uint8 c); +extern t_stat vs_rd (uint8 *c); + +struct vc_int_t { + uint32 ptr; + uint32 vec[8]; /* Interrupt vectors */ + uint32 irr; /* Interrupt request */ + uint32 imr; /* Interrupt mask */ + uint32 isr; /* Interrupt status */ + uint32 acr; /* Auto-clear mask */ + uint32 mode; + }; + +struct vc_int_t vc_intc; /* Interrupt controller */ + +uint32 vc_csr = 0; /* Control/status */ +uint32 vc_curx = 0; /* Cursor X-position */ +uint32 vc_cur_x = 0; /* Last cursor X-position */ +uint32 vc_cur_y = 0; /* Last cursor Y-position */ +uint32 vc_cur_f = 0; /* Last cursor function */ +t_bool vc_cur_v = FALSE; /* Last cursor visible */ +uint32 vc_mpos = 0; /* Mouse position */ +uint32 vc_crtc[CRTC_SIZE]; /* CRTC registers */ +uint32 vc_crtc_p = 0; /* CRTC pointer */ +uint32 vc_icdr = 0; /* Interrupt controller data */ +uint32 vc_icsr = 0; /* Interrupt controller status */ +uint32 vc_map[1024]; /* Scanline map */ +uint32 vc_buf[(1u << 16)]; /* Video memory */ +uint8 vc_cur[256]; /* Cursor image */ + +DEVICE vc_dev; +t_stat vc_rd (int32 *data, int32 PA, int32 access); +t_stat vc_wr (int32 data, int32 PA, int32 access); +t_stat vc_svc (UNIT *uptr); +t_stat vc_reset (DEVICE *dptr); +t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc); +void vc_powerdown (void); +void vc_setint (int32 src); +int32 vc_inta (void); +void vc_clrint (int32 src); +void vc_uart_int (uint32 set); +t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +char *vc_description (DEVICE *dptr); + + +/* QVSS data structures + + vc_dev QVSS device descriptor + vc_unit QVSS unit list + vc_reg QVSS register list + vc_mod QVSS modifier list +*/ + +DIB vc_dib = { + IOBA_AUTO, IOLN_QVSS, &vc_rd, &vc_wr, + 2, IVCL (QVSS), VEC_AUTO, { &vc_inta, &vc_inta } + }; + +/* Debugging Bisim_tmaps */ + +#define DBG_REG 0x0100 /* register activity */ +#define DBG_INT0 0x0001 /* interrupt 0 */ +#define DBG_INT1 0x0002 /* interrupt 1 */ +#define DBG_INT2 0x0004 /* interrupt 2 */ +#define DBG_INT3 0x0008 /* interrupt 3 */ +#define DBG_INT4 0x0010 /* interrupt 4 */ +#define DBG_INT5 0x0020 /* interrupt 5 */ +#define DBG_INT6 0x0040 /* interrupt 6 */ +#define DBG_INT7 0x0080 /* interrupt 7 */ +#define DBG_INT 0x00FF /* interrupt 0-7 */ + +DEBTAB vc_debug[] = { + {"REG", DBG_REG}, + {"DUART", DBG_INT0}, + {"VSYNC", DBG_INT1}, + {"MOUSE", DBG_INT2}, + {"CSTRT", DBG_INT3}, + {"MBA", DBG_INT4}, + {"MBB", DBG_INT5}, + {"MBC", DBG_INT6}, + {"SPARE", DBG_INT7}, + {"INT", DBG_INT0|DBG_INT1|DBG_INT2|DBG_INT3|DBG_INT4|DBG_INT5|DBG_INT6|DBG_INT7}, + {0} + }; + +UNIT vc_unit = { UDATA (&vc_svc, UNIT_IDLE, 0) }; + +REG vc_reg[] = { + { HRDATADF (CSR, vc_csr, 16, "Control and status register", vc_csr_bits) }, + { HRDATAD (CURX, vc_curx, 9, "Cursor X-position") }, + { HRDATAD (MPOS, vc_mpos, 16, "Mouse position register") }, + { HRDATAD (ICDR, vc_icdr, 16, "Interrupt controller data register") }, + { HRDATADF (ICSR, vc_icsr, 16, "Interrupt controller command/status register", vc_icsr_bits) }, + { HRDATAD (IRR, vc_intc.irr, 8, "Interrupt controller request") }, + { HRDATAD (IMR, vc_intc.imr, 8, "Interrupt controller mask") }, + { HRDATAD (ISR, vc_intc.isr, 8, "Interrupt controller status") }, + { HRDATAD (ACR, vc_intc.acr, 8, "Interrupt controller Auto-clear mask") }, + { HRDATADF (MODE, vc_intc.mode, 8, "Interrupt controller mode", vc_ic_mode_bits) }, + { HRDATA (IPTR, vc_intc.ptr, 8), REG_HRO }, + { BRDATA (VEC, vc_intc.vec, 16, 32, 8) }, + { BRDATAD (CRTC, vc_crtc, 16, 8, CRTC_SIZE, "CRTC registers") }, + { HRDATAD (CRTCP, vc_crtc_p, 8, "CRTC pointer") }, + { BRDATAD (MAP, vc_map, 16, 16, 1024, "Scanline map") }, + { NULL } + }; + +MTAB vc_mod[] = { + { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLE", + &vc_set_enable, NULL, NULL, "Enable VCB01 (QVSS)" }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLE", + &vc_set_enable, NULL, NULL, "Disable VCB01 (QVSS)" }, + { MTAB_XTD|MTAB_VDV, 0, "RELEASEKEY", NULL, + NULL, &vid_show_release_key, NULL, "Display the window focus release key" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL, "Bus address" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL, "Interrupt vector" }, + { 0 } + }; + +DEVICE vc_dev = { + "QVSS", &vc_unit, vc_reg, vc_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &vc_reset, + NULL, NULL, NULL, + &vc_dib, DEV_DIS | DEV_QBUS | DEV_DEBUG, 0, + vc_debug, NULL, NULL, &vc_help, NULL, NULL, + &vc_description + }; + +UART2681 vc_uart = { + &vc_uart_int, + { { &lk_wr, &lk_rd }, { &vs_wr, &vs_rd } } + }; + +char *vc_regnames[] = { + "CSR", /* +0 */ + "CUR-X", /* +2 */ + "MPOS", /* +4 */ + "", /* +6 spare */ + "CRTCA", /* +8 */ + "CRTCD", /* +10 */ + "ICDR", /* +12 */ + "ICSR", /* +14 */ + "", /* +16 spare */ + "", /* +18 spare */ + "", /* +20 spare */ + "", /* +22 spare */ + "", /* +24 spare */ + "", /* +26 spare */ + "", /* +28 spare */ + "", /* +30 spare */ + "UART1A2A", /* +32 */ + "UARTSTCLA", /* +34 */ + "UARTCMDA", /* +36 */ + "UARTBUFA", /* +38 */ + "", /* +40 spare */ + "UARTIMSK", /* +42 */ + "", /* +44 spare */ + "", /* +46 spare */ + "UART1B2B", /* +48 */ + "UARTSTCLB", /* +50 */ + "UARTCMDB", /* +52 */ + "UARTBUFB", /* +54 */ + "", /* +56 spare */ + "", /* +56 spare */ + "", /* +58 spare */ + "", /* +60 spare */ + "", /* +62 spare */ +}; + +t_stat vc_rd (int32 *data, int32 PA, int32 access) +{ +uint32 rg = (PA >> 1) & 0x1F; +uint32 crtc_rg, i; + +*data = 0; +switch ((PA >> 1) & 0x1F) { /* decode PA<1> */ + + case 0: /* CSR */ + *data = vc_csr; + break; + + case 1: /* Cursor X */ + *data = 0; + break; + + case 2: /* Mouse position */ + *data = vc_mpos; + break; + + case 4: /* CRTC addr ptr */ + *data = vc_crtc_p; + break; + + case 5: /* CRTC data */ + crtc_rg = vc_crtc_p & CRTCP_REG; + *data = vc_crtc[crtc_rg]; + if ((crtc_rg == CRTC_LPPL) || (crtc_rg == CRTC_LPPH)) + vc_crtc_p &= ~CRTCP_LPF; /* Clear light pen full */ + break; + + case 6: /* ICDR */ + switch ((vc_intc.mode & ICM_M_RP) >> ICM_V_RP) { + + case 0: /* ISR */ + *data = vc_intc.isr; + break; + + case 1: /* IMR */ + *data = vc_intc.imr; + break; + + case 2: /* IRR */ + *data = vc_intc.irr; + break; + + case 3: /* ACR */ + *data = vc_intc.acr; + break; + } + break; + + case 7: /* ICSR */ + *data = vc_icsr | 0x40; /* Chip enabled */ + *data |= (vc_intc.mode & ICM_PM) ? 0x20 : 0; /* Priority mode */ + *data |= (vc_intc.mode & ICM_IM) ? 0x10 : 0; /* Interrupt mode */ + *data |= (vc_intc.mode & ICM_MM) ? 0x8 : 0; /* Master mask */ + if (vc_icsr & 0x80) { /* Group int pending */ + for (i = 0; i < 8; i++) { + if (vc_intc.isr & (1u << i)) { + *data |= i; + break; + } + } + } + break; + + case 16: /* UART mode 1A,2A */ + case 17: /* UART status/clock A */ + case 18: /* UART command A */ + case 19: /* UART tx/rx buf A */ + case 21: /* UART interrupt status/mask */ + case 24: /* UART mode 1B,2B */ + case 25: /* UART status/clock B */ + case 26: /* UART command B */ + case 27: /* UART tx/rx buf B */ + *data = ua2681_rd (&vc_uart, (rg - 16)); + break; + + default: /* Spares */ + break; + } /* end switch PA */ +sim_debug (DBG_REG, &vc_dev, "vc_rd(%s) data=0x%04X\n", vc_regnames[(PA >> 1) & 0x1F], *data); +return SCPE_OK; +} + +t_stat vc_wr (int32 data, int32 PA, int32 access) +{ +uint32 rg = (PA >> 1) & 0x1F; +uint32 crtc_rg; + +sim_debug (DBG_REG, &vc_dev, "vc_wr(%s) data=0x%04X\n", vc_regnames[(PA >> 1) & 0x1F], data); +switch ((PA >> 1) & 0x1F) { /* decode PA<1> */ + + case 0: /* CSR */ + vc_csr = (vc_csr & ~CSR_RW) | (data & CSR_RW); + break; + + case 1: /* Cursor X */ + vc_curx = data; + break; + + case 2: /* Mouse position */ + break; + + case 4: /* CRTC addr ptr */ + vc_crtc_p = (vc_crtc_p & ~CRTCP_RW) | (data & CRTCP_RW); + break; + + case 5: /* CRTC data */ + crtc_rg = vc_crtc_p & CRTCP_REG; + vc_crtc[crtc_rg] = data & BMASK; + break; + + case 6: /* ICDR */ + if (vc_intc.ptr == 8) /* IMR */ + vc_intc.imr = data & 0xFFFF; + else if (vc_intc.ptr == 9) /* ACR */ + vc_intc.acr = data & 0xFFFF; + else + vc_intc.vec[vc_intc.ptr] = data & 0xFFFF; /* Vector */ + break; + + case 7: /* ICSR */ + switch ((data >> 4) & 0xF) { + + case 0: /* Reset */ + vc_intc.imr = 0xFF; + vc_intc.irr = 0; + vc_intc.isr = 0; + vc_intc.acr = 0; + break; + + case 2: /* Clear IRR & IMR */ + if (data & 0x8) { /* one bit */ + vc_intc.irr &= ~(1u << (data & 0x7)); + vc_intc.imr &= ~(1u << (data & 0x7)); + } + else { /* all bits */ + vc_intc.irr = 0; + vc_intc.imr = 0; + } + break; + + case 3: /* Set IMR */ + if (data & 0x8) /* one bit */ + vc_intc.imr |= (1u << (data & 0x7)); + else /* all bits */ + vc_intc.imr = 0xFF; + break; + + case 4: /* Clear IRR */ + if (data & 0x8) /* one bit */ + vc_intc.irr &= ~(1u << (data & 0x7)); + else /* all bits */ + vc_intc.irr = 0; + break; + + case 6: /* Clear highest priority ISR */ + break; + + case 7: /* Clear ISR */ + if (data & 0x8) /* one bit */ + vc_intc.isr &= ~(1u << (data & 0x7)); + else /* all bits */ + vc_intc.isr = 0; + break; + + case 8: /* Load mode bits */ + case 9: + vc_intc.mode &= ~0x1F | (data & 0x1F); + break; + + case 10: /* Control mode bits */ + vc_intc.mode &= ~0x60 | ((data << 3) & 0x60); /* mode<06:05> = data<03:02> */ + if (((data & 0x3) == 0x1) || ((data & 0x3) == 2)) + vc_intc.mode &= ~0x80 | ((data << 7) & 0x80); + break; + + case 11: /* Preselect IMR */ + vc_intc.ptr = 8; + break; + + case 12: /* Preselect ACR */ + vc_intc.ptr = 9; + break; + + case 14: /* Preselect response mem */ + vc_intc.ptr = (data & 0x7); + break; + } + break; + + case 16: /* UART mode 1A,2A */ + case 17: /* UART status/clock A */ + case 18: /* UART command A */ + case 19: /* UART tx/rx buf A (keyboard) */ + case 21: /* UART interrupt status/mask */ + case 24: /* UART mode 1B,2B */ + case 25: /* UART status/clock B */ + case 26: /* UART command B */ + case 27: /* UART tx/rx buf B (mouse) */ + ua2681_wr (&vc_uart, (rg - 16), data); + break; + + default: /* Spares */ + break; + } + +return SCPE_OK; +} + +int32 vc_mem_rd (int32 pa) +{ +uint32 rg = (pa >> 2) & 0xFFFF; +return vc_buf[rg]; +} + +void vc_mem_wr (int32 pa, int32 val, int32 lnt) +{ +uint32 rg = (pa >> 2) & 0xFFFF; +int32 nval, i; +int32 sc; +uint32 scrln, bufln; +uint32 idx; + +if (lnt < L_LONG) { + int32 mask = (lnt == L_WORD)? 0xFFFF: 0xFF; + int32 t = vc_buf[rg]; + sc = (pa & 3) << 3; + nval = ((val & mask) << sc) | (t & ~(mask << sc)); + } +else nval = val; + +if (rg >= 0xFFF8) { /* cursor image */ + idx = (pa << 3) & 0xFF; /* get byte index */ + for (i = 0; i < (lnt << 3); i++) + vc_cur[idx++] = (val >> i) & 1; /* 1bpp to 8bpp */ + } +else if (rg >= 0xFE00) { /* scanline map */ + if (vc_buf[rg] != nval) { + scrln = (pa >> 1) & 0x3FF; /* screen line */ + sc = (scrln & 1) ? 16 : 0; /* odd line? (upper word) */ + bufln = (nval >> sc) & 0x7FF; /* buffer line */ + vc_map[scrln] = bufln; /* update map */ + + if (lnt > L_WORD) { /* remapping 2 lines? */ + scrln++; /* next screen line */ + bufln = (val >> 16) & 0x7FF; /* buffer line */ + vc_map[scrln] = bufln; /* update map */ + } + } + } +bufln = rg / 32; +for (scrln = 0; scrln < 1024; scrln++) { + if ((vc_map[scrln] & 0x7FF) == bufln) { + vc_map[scrln] = vc_map[scrln] & ~VCMAP_VLD; /* invalidate map */ + } + } +vc_buf[rg] = nval; +} + +SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2) +{ +uint32 ln; +for (ln = y1; ln < y2; ln++) + vc_map[ln] = vc_map[ln] & ~VCMAP_VLD; /* invalidate map entry */ +} + +void vc_checkint (void) +{ +uint32 i; +uint32 msk = (vc_intc.irr & ~vc_intc.imr); /* unmasked interrutps */ +vc_icsr &= ~(ICSR_GRI|ICSR_M_IRRVEC); /* clear GRI & vector */ + +if ((vc_intc.mode & 0x80) && ~(vc_intc.mode & 0x4)) { /* group int MM & not polled */ + for (i = 0; i < 8; i++) { + if (msk & (1u << i)) { + vc_icsr |= (ICSR_GRI | i); + } + } + if ((vc_csr & CSR_IEN) && (vc_icsr & ICSR_GRI)) { + if (!(int_req[IPL_QVSS] & (INT_QVSS))) + sim_debug (DBG_INT, &vc_dev, "vc_checkint(SET_INT) icsr=0x%x\n", vc_icsr); + SET_INT (QVSS); + } + else { + if ((int_req[IPL_QVSS] & (INT_QVSS))) + sim_debug (DBG_INT, &vc_dev, "vc_checkint(CLR_INT)\n"); + CLR_INT (QVSS); + } + } +else { + if ((int_req[IPL_QVSS] & (INT_QVSS))) + sim_debug (DBG_INT, &vc_dev, "vc_checkint(CLR_INT)\n"); + CLR_INT (QVSS); + } +} + +void vc_clrint (int32 src) +{ +uint32 msk = (1u << src); +vc_intc.irr &= ~msk; +vc_intc.isr &= ~msk; +sim_debug (msk, &vc_dev, "vc_clrint(%d)\n", src); +vc_checkint (); +} + +void vc_setint (int32 src) +{ +uint32 msk = (1u << src); +vc_intc.irr |= msk; +sim_debug (msk, &vc_dev, "vc_setint(%d)\n", src); +vc_checkint (); +} + +void vc_uart_int (uint32 set) +{ +if (set) + vc_setint (IRQ_DUART); +else + vc_clrint (IRQ_DUART); +} + +int32 vc_inta (void) +{ +uint32 i; +uint32 msk = (vc_intc.irr & ~vc_intc.imr); /* unmasked interrutps */ +int32 result; + +for (i = 0; i < 8; i++) { + if (msk & (1u << i)) { + vc_intc.irr &= ~(1u << i); + if (vc_intc.acr & (1u << i)) + vc_intc.isr &= ~(1u << i); + else vc_intc.isr |= (1u << i); + vc_checkint(); + result = (vc_intc.vec[i] + VEC_Q); + sim_debug (DBG_INT, &vc_dev, "Int Ack Vector: 0%03o (0x%X)\n", result, result); + return result; + } + } +sim_debug (DBG_INT, &vc_dev, "Int Ack Vector: 0%03o\n", 0); +return 0; /* no intr req */ +} + +t_stat vc_svc (UNIT *uptr) +{ +t_bool updated = FALSE; /* flag for refresh */ +uint8 line[1024]; +uint32 ln, col, off; +uint8 *cur; + +vc_crtc_p = vc_crtc_p ^ CRTCP_VB; /* Toggle VBI */ +vc_crtc_p = vc_crtc_p | CRTCP_LPF; /* Light pen full */ + +if (vc_cur_v != CUR_V) { /* visibility changed? */ + if (CUR_V) /* visible? */ + vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ + else + vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */ + } +else if (vc_cur_y != CUR_Y) { /* moved (Y)? */ + vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ + vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */ + } +else if ((vc_cur_x != CUR_X) || (vc_cur_f != CUR_F)) { /* moved (X) or mask changed? */ + vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ + } + +vc_cur_x = CUR_X; /* store cursor data */ +vc_cur_y = CUR_Y; +vc_cur_v = CUR_V; +vc_cur_f = CUR_F; + +for (ln = 0; ln < VC_YSIZE; ln++) { + if ((vc_map[ln] & VCMAP_VLD) == 0) { /* line invalid? */ + off = vc_map[ln] * 32; /* get video buf offet */ + for (col = 0; col < 1024; col++) + line[col] = (vc_buf[off + (col >> 5)] >> col) & 1; /* 1bpp to 8bpp */ + if (CUR_V) { /* cursor visible? */ + if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */ + cur = &vc_cur[((ln - CUR_Y) << 4)]; /* get image base */ + for (col = 0; col < 16; col++) { + if (CUR_F) /* mask function */ + line[CUR_X + col] = line[CUR_X + col] | cur[col]; + else + line[CUR_X + col] = line[CUR_X + col] & ~cur[col]; + line [CUR_X + col] = line[CUR_X + col] & 1; + } + } + } + vid_draw (0, ln, 1024, 1, &line[0]); /* update line */ + updated = TRUE; + vc_map[ln] = vc_map[ln] | VCMAP_VLD; /* set valid */ + } + } + +if (updated) /* video updated? */ + vid_refresh (); /* put to screen */ + +ua2681_svc (&vc_uart); /* service DUART */ +vc_setint (IRQ_VSYNC); /* VSYNC int */ +sim_activate (uptr, tmxr_poll); /* reactivate */ +return SCPE_OK; +} + +t_stat vc_reset (DEVICE *dptr) +{ +uint32 i; +t_stat r; + +CLR_INT (QVSS); /* clear int req */ +sim_cancel (&vc_unit); /* stop poll */ +ua2681_reset (&vc_uart); /* reset DUART */ + +vc_intc.ptr = 0; /* interrupt controller */ +vc_intc.irr = 0; +vc_intc.imr = 0xFF; +vc_intc.isr = 0; +vc_intc.acr = 0; +vc_intc.mode = 0x80; +vc_icsr = 0; + +vc_csr = (((QVMBASE >> QVMAWIDTH) & ((1<flags & DEV_DIS) + return vid_close (); + +if (!vid_active) { + r = vid_open (VC_XSIZE, VC_YSIZE); /* display size */ + if (r != SCPE_OK) + return r; + printf ("QVSS Display Created. "); + vid_show_release_key (stdout, NULL, 0, NULL); + printf ("\n"); + if (sim_log) { + fprintf (sim_log, "QVSS Display Created. "); + vid_show_release_key (sim_log, NULL, 0, NULL); + fprintf (sim_log, "\n"); + } + } +sim_activate_abs (&vc_unit, tmxr_poll); +return auto_config (NULL, 0); /* run autoconfig */ +} + +t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +return cpu_set_model (NULL, 0, (val ? "VAXSTATION" : "MICROVAX"), NULL); +} + +t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +fprintf (st, "VCB01 Monochrome Video Subsystem (%s)\n\n", dptr->name); +fprintf (st, "Use the Control-Right-Shift key combination to regain focus from the simulated\n"); +fprintf (st, "video display\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +char *vc_description (DEVICE *dptr) +{ +return "VCB01 Monochrome Graphics Adapter"; +} diff --git a/VAX/vax_vs.c b/VAX/vax_vs.c new file mode 100644 index 00000000..bc9adb33 --- /dev/null +++ b/VAX/vax_vs.c @@ -0,0 +1,210 @@ +/* vax_vs.c: DEC Mouse/Tablet (VSXXX) + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + vs VSXXX-nn pointing device + + 11-Jun-2013 MB First version +*/ + +#include "vax_defs.h" +#include "sim_video.h" + +#define VSXXX_IDLE 0 +#define VSXXX_RECV 1 +#define VSXXX_SEND 2 +#define VSXXX_TEST 3 + +#define VSXXX_PROMPT 0 +#define VSXXX_INC 1 + +/* Debugging Bitmaps */ + +#define DBG_SERIAL 0x0001 /* serial port data */ +#define DBG_CMD 0x0002 /* commands */ + +int32 vs_state = VSXXX_IDLE; +int32 vs_mode = VSXXX_PROMPT; +int32 vs_bptr = 0; +int32 vs_datalen = 0; +int32 vs_x = 0; /* X-axis motion */ +int32 vs_y = 0; /* Y-axis motion */ +t_bool vs_l = 0; /* Left button state */ +t_bool vs_m = 0; /* Middle button state */ +t_bool vs_r = 0; /* Right button state */ +uint8 vs_buf[10]; + +DEVICE vs_dev; +t_stat vs_wr (uint8 c); +t_stat vs_rd (uint8 *c); +t_stat vs_reset (DEVICE *dptr); +void vs_cmd (int32 c); +void vs_sendupd (void); +void vs_poll (void); + + +/* VS data structures + + vs_dev VS device descriptor + vs_unit VS unit list + vs_reg VS register list + vs_mod VS modifier list + vs_debug VS debug list +*/ + +DEBTAB vs_debug[] = { + {"SERIAL", DBG_SERIAL}, + {"CMD", DBG_CMD}, + {0} + }; + +UNIT vs_unit = { UDATA (NULL, 0, 0) }; + +REG vs_reg[] = { + { NULL } + }; + +MTAB vs_mod[] = { + { 0 } + }; + +DEVICE vs_dev = { + "VS", &vs_unit, vs_reg, vs_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &vs_reset, + NULL, NULL, NULL, + NULL, DEV_DIS | DEV_DEBUG, 0, + vs_debug + }; + + +t_stat vs_wr (uint8 c) +{ +if (vs_state != VSXXX_TEST) { + vs_bptr = 0; + vs_state = VSXXX_IDLE; + vs_datalen = 0; + vs_cmd (c); + } +return SCPE_OK; +} + +t_stat vs_rd (uint8 *c) +{ +if (vs_state == VSXXX_IDLE) + vs_poll (); +switch (vs_state) { + + case VSXXX_IDLE: + *c = 0; + return SCPE_EOF; + + case VSXXX_SEND: + case VSXXX_TEST: + *c = vs_buf[vs_bptr++]; + sim_debug (DBG_SERIAL, &vs_dev, "mouse -> vax: %02X\n", *c); + if (vs_bptr == vs_datalen) { + vs_state = VSXXX_IDLE; + } + return SCPE_OK; + } +return SCPE_EOF; +} + +void vs_cmd (int32 c) +{ +sim_debug (DBG_SERIAL, &vs_dev, "vax -> mouse: %c\n", c); +switch (c) { + + case 0x52: /* R */ + sim_debug (DBG_CMD, &vs_dev, "set mode incremental\n", c); + vs_mode = VSXXX_INC; + break; + + case 0x44: /* D */ + sim_debug (DBG_CMD, &vs_dev, "set mode prompt\n", c); + vs_mode = VSXXX_PROMPT; + break; + + case 0x50: /* P */ + sim_debug (DBG_CMD, &vs_dev, "poll\n", c); + vs_mode = VSXXX_PROMPT; + vs_sendupd (); + break; + + case 0x54: /* T */ + sim_debug (DBG_CMD, &vs_dev, "test\n", c); + vs_reset (&vs_dev); + vs_state = VSXXX_TEST; + vs_buf[0] = 0xA0; /* send ID */ + vs_buf[1] = 0x12; + vs_buf[2] = 0x00; + vs_buf[3] = 0x00; + vs_bptr = 0; + vs_state = VSXXX_SEND; + vs_datalen = 4; + break; + } +} + +t_stat vs_reset (DEVICE *dptr) +{ +vs_bptr = 0; +vs_state = VSXXX_IDLE; +vs_datalen = 0; +vs_mode = VSXXX_PROMPT; +return SCPE_OK; +} + +void vs_sendupd (void) +{ +vs_buf[0] = 0x80; +vs_buf[0] |= (((vs_x >= 0) ? 1 : 0) << 4); /* sign bits */ +vs_buf[0] |= (((vs_y >= 0) ? 1 : 0) << 3); +vs_buf[0] |= (((vs_l) ? 1 : 0) << 2); /* button states */ +vs_buf[0] |= (((vs_m) ? 1 : 0) << 1); +vs_buf[0] |= ((vs_r) ? 1 : 0); +vs_buf[1] = (abs(vs_x)) & 0x7F; /* motion */ +vs_buf[2] = (abs(vs_y)) & 0x7F; +vs_bptr = 0; +vs_state = VSXXX_SEND; +vs_datalen = 3; +} + +void vs_poll (void) +{ +SIM_MOUSE_EVENT ev; + +if (vid_poll_mouse (&ev) != SCPE_OK) + return; +if (vs_state == VSXXX_IDLE) { + vs_x = ev.x_rel; + vs_y = ev.y_rel; + vs_l = ev.b1_state; + vs_m = ev.b2_state; + vs_r = ev.b3_state; + if (vs_mode == VSXXX_INC) + vs_sendupd (); + } +} diff --git a/VAX/vax_watch.c b/VAX/vax_watch.c index 873a12f2..28051db3 100644 --- a/VAX/vax_watch.c +++ b/VAX/vax_watch.c @@ -222,8 +222,8 @@ t_stat wtc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { fprintf (st, "Watch Chip (WTC)\n\n"); fprintf (st, "The WTC simulates the MC146818 watch chip. It recognizes the following options:\n\n"); -fprintf (st, " SET WTC TIME=STD standard time mode\n"); -fprintf (st, " SET WTC TIME=VMS VMS time mode\n\n"); +fprintf (st, " SET WTC TIME=STD standard time mode\n"); +fprintf (st, " SET WTC TIME=VMS VMS time mode\n\n"); fprintf (st, "When running in standard mode the current year reported by the watch chip is\n"); fprintf (st, "determined by the date/time of the host system. When running in VMS mode the\n"); fprintf (st, "year is fixed at 1982, which is one of the conditions VMS expects in order to\n"); diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 2d73f8d7..9ab73332 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -258,10 +258,7 @@ extern t_stat cpu_show_memory (FILE* st, UNIT* uptr, int32 val, void* desc); #define DZ_MUXES 4 /* max # of DZV muxes */ #define DZ_LINES 4 /* lines per DZV mux */ #define VH_MUXES 4 /* max # of DHQ muxes */ -#define DLX_LINES 16 /* max # of KL11/DL11's */ -#define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ #define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ diff --git a/Visual Studio Projects/0ReadMe_Projects.txt b/Visual Studio Projects/0ReadMe_Projects.txt index 24445549..c892c0b6 100644 --- a/Visual Studio Projects/0ReadMe_Projects.txt +++ b/Visual Studio Projects/0ReadMe_Projects.txt @@ -18,6 +18,7 @@ For Example, the directory structure should look like: .../simh/simhv38-2-rc1/BIN/Nt/Win32-Release/vax.exe .../simh/windows-build/pthreads/pthread.h .../simh/windows-build/winpcap/WpdPack/Include/pcap.h + .../simh/windows-build/libSDL/SDL-1.2.15/include/SDL.h The contents of the windows-build directory can be downloaded from: @@ -47,5 +48,5 @@ in this directory. If you are using a version of Visual Studio beyond Visual Studio 2008, then your later version of Visual Studio will automatically convert the Visual -Studio 2008 project fils. You should ignore any warnings produced by the +Studio 2008 project files. You should ignore any warnings produced by the conversion process. diff --git a/Visual Studio Projects/BuildAll.cmd b/Visual Studio Projects/BuildAll.cmd index 07ca92a3..06e2a1bf 100644 --- a/Visual Studio Projects/BuildAll.cmd +++ b/Visual Studio Projects/BuildAll.cmd @@ -34,7 +34,7 @@ for /F "usebackq tokens=3" %%i in (`findstr/C:"#define SIM_VERSION_MODE" ..\sim_ if "%_SIM_PATCH%" equ "-0" set _SIM_PATCH= set _ZipName=simh-%_SIM_MAJOR%.%_SIM_MINOR%%_SIM_PATCH%%_SIM_VERSION_MODE%--%D_YYYY%-%D_MM%-%D_DD%-%GIT_COMMIT_ID:~0,8%.zip set _ZipPath=..\..\%BIN_REPO%\ -vcbuild /rebuild Simh.sln "Release|Win32" +vcbuild /M2 /useenv /rebuild Simh.sln "Release|Win32" if exist "%ProgramFiles%\7-Zip\7z.exe" "%ProgramFiles%\7-Zip\7z.exe" a -tzip "%_ZipPath%%_ZipName%" "..\BIN\NT\Win32-Release\*.exe" if exist "%ProgramFiles(x86)%\7-Zip\7z.exe" "%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip "%_ZipPath%%_ZipName%" "..\BIN\NT\Win32-Release\*.exe" if exist "%PROGRAMW6432%\7-Zip\7z.exe" "%PROGRAMW6432%\7-Zip\7z.exe" a -tzip "%_ZipPath%%_ZipName%" "..\BIN\NT\Win32-Release\*.exe" diff --git a/Visual Studio Projects/VAX610.vcproj b/Visual Studio Projects/MicroVAX1.vcproj similarity index 79% rename from Visual Studio Projects/VAX610.vcproj rename to Visual Studio Projects/MicroVAX1.vcproj index 20b904b4..23f284c6 100644 --- a/Visual Studio Projects/VAX610.vcproj +++ b/Visual Studio Projects/MicroVAX1.vcproj @@ -2,9 +2,9 @@ @@ -19,7 +19,7 @@ + + @@ -324,6 +328,10 @@ RelativePath="..\VAX\vax610_syslist.c" > + + @@ -344,6 +352,10 @@ RelativePath="..\VAX\vax_fpa.c" > + + @@ -360,6 +372,14 @@ RelativePath="..\VAX\vax_syscm.c" > + + + + + + + + diff --git a/Visual Studio Projects/VAX630.vcproj b/Visual Studio Projects/MicroVAX2.vcproj similarity index 79% rename from Visual Studio Projects/VAX630.vcproj rename to Visual Studio Projects/MicroVAX2.vcproj index 9de1010e..9688b042 100644 --- a/Visual Studio Projects/VAX630.vcproj +++ b/Visual Studio Projects/MicroVAX2.vcproj @@ -2,9 +2,9 @@ @@ -19,7 +19,7 @@ + + @@ -320,6 +324,10 @@ RelativePath="..\VAX\vax630_syslist.c" > + + @@ -340,6 +348,10 @@ RelativePath="..\VAX\vax_fpa.c" > + + @@ -356,6 +368,14 @@ RelativePath="..\VAX\vax_syscm.c" > + + + + @@ -437,10 +457,18 @@ RelativePath="..\sim_tmxr.h" > + + + + diff --git a/Visual Studio Projects/Pre-Build-Event.cmd b/Visual Studio Projects/Pre-Build-Event.cmd index e582f3ba..17cd1a88 100644 --- a/Visual Studio Projects/Pre-Build-Event.cmd +++ b/Visual Studio Projects/Pre-Build-Event.cmd @@ -12,7 +12,10 @@ rem ROM images are consistent with the ROM images from which they rem are derived. rem BUILD To validate that the required dependent libraries and include rem files are available in the directory ..\..\windows-build\ -rem These libraries currently include winpcap and pthreads. +rem These libraries currently include winpcap and pthreads and +rem optionally SDL. +rem LIBSDL To validate that the required dependent SDL libraries and include +rem files are available in the directory ..\..\windows-build\ rem rem In addition to the optional activities mentioned above, other activities rem are also performed. These include: @@ -30,6 +33,7 @@ if "%1" == "" goto _done_args set _arg= if /I "%1" == "ROM" set _arg=ROM if /I "%1" == "BUILD" set _arg=BUILD +if /I "%1" == "LIBSDL" set _arg=LIBSDL if "%_arg%" == "" echo *** warning *** unknown parameter %0 if not "%_arg%" == "" set _X_%_arg%=%_arg% shift @@ -56,15 +60,27 @@ popd :_check_build if "%_X_BUILD%" == "" goto _done_build if exist ../../windows-build-windows-build move ../../windows-build-windows-build ../../windows-build >NUL -if not exist ../../windows-build/winpcap/Wpdpack/Include/pcap.h goto _notice -if not exist ../../windows-build/pthreads/pthread.h goto _notice +if not exist ../../windows-build/winpcap/Wpdpack/Include/pcap.h goto _notice1 +if not exist ../../windows-build/pthreads/pthread.h goto _notice1 +if "%_X_LIBSDL%" == "" goto _done_build +if not exist ../../windows-build/libSDL/SDL-1.2.15/include/SDL.h goto _notice2 +if not exist "../../windows-build/libSDL/Microsoft DirectX SDK (June 2010)/Lib/x86/dxguid.lib" goto _notice2 goto _done_build -:_notice +:_notice1 echo **************************************************** echo **************************************************** echo ** The required build support is not available. ** echo **************************************************** echo **************************************************** +goto _ProjectInfo +:_notice2 +echo **************************************************** +echo **************************************************** +echo ** The required build support is out of date. ** +echo **************************************************** +echo **************************************************** +goto _ProjectInfo +:_ProjectInfo type 0ReadMe_Projects.txt exit 1 :_done_build diff --git a/Visual Studio Projects/VAX.vcproj b/Visual Studio Projects/VAX.vcproj index 40c27377..b1dd60ee 100644 --- a/Visual Studio Projects/VAX.vcproj +++ b/Visual Studio Projects/VAX.vcproj @@ -70,7 +70,7 @@ Name="VCLinkerTool" AdditionalOptions="/fixed:no" AdditionalDependencies="wsock32.lib winmm.lib" - OutputFile="$(OutDir)\MicroVAX3900.exe" + OutputFile="$(OutDir)\VAX.exe" LinkIncremental="1" AdditionalLibraryDirectories=""../../windows-build/winpcap/Wpdpack/Lib/"" GenerateDebugInformation="true" @@ -101,7 +101,7 @@ diff --git a/Visual Studio Projects/VAX620.vcproj b/Visual Studio Projects/rtVAX1000.vcproj similarity index 88% rename from Visual Studio Projects/VAX620.vcproj rename to Visual Studio Projects/rtVAX1000.vcproj index f6d45114..f65bc75d 100644 --- a/Visual Studio Projects/VAX620.vcproj +++ b/Visual Studio Projects/rtVAX1000.vcproj @@ -2,9 +2,9 @@ @@ -19,7 +19,7 @@ + + @@ -320,6 +324,10 @@ RelativePath="..\VAX\vax630_syslist.c" > + + @@ -340,6 +348,10 @@ RelativePath="..\VAX\vax_fpa.c" > + + @@ -356,6 +368,14 @@ RelativePath="..\VAX\vax_syscm.c" > + + + + @@ -437,10 +457,18 @@ RelativePath="..\sim_tmxr.h" > + + + + diff --git a/doc/pdp10_doc.doc b/doc/pdp10_doc.doc index f85e6dc9..2edf6e7d 100644 Binary files a/doc/pdp10_doc.doc and b/doc/pdp10_doc.doc differ diff --git a/makefile b/makefile index 8d6e5370..ac1edcba 100644 --- a/makefile +++ b/makefile @@ -54,13 +54,18 @@ BUILD_SINGLE := $(MAKECMDGOALS) $(BLANK_SUFFIX) ifneq (,$(or $(findstring pdp11,$(MAKECMDGOALS)),$(findstring vax,$(MAKECMDGOALS)),$(findstring all,$(MAKECMDGOALS)))) NETWORK_USEFUL = true + ifneq (,$(or $(findstring microvax1,$(MAKECMDGOALS)),$(findstring microvax2,$(MAKECMDGOALS)))) + VIDEO_USEFUL = true + endif ifneq (,$(findstring all,$(MAKECMDGOALS))$(word 2,$(MAKECMDGOALS))) BUILD_MULTIPLE = s + VIDEO_USEFUL = true endif else ifeq ($(MAKECMDGOALS),) # default target is all NETWORK_USEFUL = true + VIDEO_USEFUL = true BUILD_MULTIPLE = s BUILD_SINGLE := all $(BUILD_SINGLE) endif @@ -308,6 +313,23 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) OS_CCDEFS += -DHAVE_FNMATCH endif endif + ifneq (,$(call find_include,SDL/SDL)) + ifneq (,$(call find_lib,SDL)) + OS_CCDEFS += -DHAVE_LIBSDL -I$(dir $(call find_include,SDL/SDL)) + OS_LDFLAGS += -lSDL + $(info using libSDL: $(call find_lib,SDL) $(call find_include,SDL/SDL)) + endif + endif + ifneq (,$(VIDEO_USEFUL)) + ifeq (,$(findstring HAVE_LIBSDL,$(OS_CCDEFS))) + $(info *** Warning ***) + $(info *** Warning *** The simulator$(BUILD_MULTIPLE) you are building could provide more) + $(info *** Warning *** functionality if video support were available on your system.) + $(info *** Warning *** Install the development components of libSDL and rebuild) + $(info *** Warning *** your simulator to enable this extra functionality.) + $(info *** Warning ***) + endif + endif ifneq (,$(NETWORK_USEFUL)) ifneq (,$(call find_include,pcap)) ifneq (,$(call find_lib,$(PCAPLIB))) @@ -495,8 +517,28 @@ else NETWORK_FEATURES = - dynamic networking support using libpcap components found in the MinGW directories endif endif - OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) - OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) + ifneq (,$(VIDEO_USEFUL)) + ifeq (libSDL,$(shell if exist ..\windows-build\libSDL\SDL-1.2.15\include\SDL.h echo libSDL)) + OS_CCDEFS += -DHAVE_LIBSDL -I..\windows-build\libSDL\SDL-1.2.15\include + OS_LDFLAGS += -lSDL -lSDLmain -L..\windows-build\libSDL\SDL-1.2.15\lib + VIDEO_FEATURES = - video capabilities provided by libSDL (Simple Directmedia Layer) + else + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info ** This build could produce simulators with video capabilities. **) + $(info ** However, the required files to achieve this can't be found on **) + $(info ** this system. Download the file: **) + $(info ** https://github.com/simh/windows-build/archive/windows-build.zip **) + $(info ** Refer to the file: **) + $(info ** "Visual Studio Projects\0ReadMe_Projects.txt" for where to place **) + $(info ** the 'windows-build' folder extracted from that zip file. **) + $(info ***********************************************************************) + $(info ***********************************************************************) + $(info .) + endif + endif + OS_CCDEFS += -fms-extensions $(PTHREADS_CCDEFS) + OS_LDFLAGS += -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe ifneq (binexists,$(shell if exist BIN echo binexists)) MKDIRBIN = if not exist BIN mkdir BIN @@ -582,6 +624,9 @@ ifneq (clean,$(MAKECMDGOALS)) ifneq (,$(NETWORK_FEATURES)) $(info *** $(NETWORK_FEATURES).) endif + ifneq (,$(VIDEO_FEATURES)) + $(info *** $(VIDEO_FEATURES).) + endif ifneq (,$(GIT_COMMIT_ID)) $(info ***) $(info *** git commit id is $(GIT_COMMIT_ID).) @@ -613,7 +658,8 @@ LDFLAGS := $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) # BIN = BIN/ SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ - sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c + sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c \ + sim_video.c # @@ -684,25 +730,27 @@ VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OP VAX610 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ - ${VAXD}/vax610_stddev.c ${VAXD}/vax610_sysdev.c \ - ${VAXD}/vax610_io.c ${VAXD}/vax610_syslist.c ${VAXD}/vax610_mem.c \ + ${VAXD}/vax610_stddev.c ${VAXD}/vax610_sysdev.c ${VAXD}/vax610_io.c \ + ${VAXD}/vax610_syslist.c ${VAXD}/vax610_mem.c ${VAXD}/vax_vc.c \ + ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_2681.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_io_lib.c -VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX610_OPT = -DVM_VAX -DVAX_610 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} VAX630 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ ${VAXD}/vax_watch.c ${VAXD}/vax630_stddev.c ${VAXD}/vax630_sysdev.c \ - ${VAXD}/vax630_io.c ${VAXD}/vax630_syslist.c \ + ${VAXD}/vax630_io.c ${VAXD}/vax630_syslist.c ${VAXD}/vax_vc.c \ + ${VAXD}/vax_lk.c ${VAXD}/vax_vs.c ${VAXD}/vax_2681.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_io_lib.c VAX620_OPT = -DVM_VAX -DVAX_620 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} -VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX630_OPT = -DVM_VAX -DVAX_630 -DUSE_INT64 -DUSE_ADDR64 -DUSE_SIM_VIDEO -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ diff --git a/scp.c b/scp.c index 57252fbc..a1be25a4 100644 --- a/scp.c +++ b/scp.c @@ -221,6 +221,7 @@ #include "sim_tape.h" #include "sim_ether.h" #include "sim_serial.h" +#include "sim_video.h" #include "sim_sock.h" #include #include @@ -1310,8 +1311,27 @@ GET_SWITCHES (cptr); if (*cptr) { cptr = get_glyph (cptr, gbuf, 0); if ((cmdp = find_cmd (gbuf))) { - if (*cptr) - return SCPE_2MARG; + if (*cptr) { + if ((cmdp->action == &set_cmd) || (cmdp->action == &show_cmd)) { + DEVICE *dptr; + UNIT *uptr; + t_stat r; + + cptr = get_glyph (cptr, gbuf, 0); + dptr = find_unit (gbuf, &uptr); + if (dptr == NULL) { + dptr = find_dev (gbuf); + if (dptr == NULL) + return SCPE_2MARG; + } + r = help_dev_help (stdout, dptr, uptr, (cmdp->action == &set_cmd) ? "SET" : "SHOW"); + if (sim_log) + help_dev_help (stdout, dptr, uptr, (cmdp->action == &set_cmd) ? "SET" : "SHOW"); + return r; + } + else + return SCPE_2MARG; + } if (cmdp->help) { fputs (cmdp->help, stdout); if (sim_log) @@ -2506,7 +2526,7 @@ char gbuf[CBUFSIZE], *cvptr; DEVICE *dptr; UNIT *uptr; MTAB *mptr; -SHTAB *shtb, *shptr; +SHTAB *shtb = NULL, *shptr; static SHTAB show_glob_tab[] = { { "CONFIGURATION", &show_config, 0 }, @@ -2616,7 +2636,7 @@ while (*cptr != 0) { /* do all mods */ } /* end if */ } /* end for */ if (mptr->mask == 0) { /* no match? */ - if ((shptr = find_shtab (shtb, gbuf))) /* global match? */ + if (shtb && (shptr = find_shtab (shtb, gbuf))) /* global match? */ shptr->action (ofile, dptr, uptr, shptr->arg, cptr); else return SCPE_ARG; } /* end if */ @@ -2811,6 +2831,9 @@ if (flag) { fprintf (st, "\n\t\tMemory Access: %s Endian", sim_end ? "Little" : "Big"); fprintf (st, "\n\t\tMemory Pointer Size: %d bits", (int)sizeof(dptr)*8); fprintf (st, "\n\t\t%s", sim_toffset_64 ? "Large File (>2GB) support" : "No Large File support"); +#if defined (USE_SIM_VIDEO) + fprintf (st, "\n\t\tSDL Video support: %s", vid_version()); +#endif fprintf (st, "\n\t\tOS clock tick size: %dms", os_tick_size); #if defined(__VMS) if (1) { @@ -3633,12 +3656,15 @@ if (dptr == NULL) /* found dev? */ return SCPE_NXDEV; if (uptr == NULL) /* valid unit? */ return SCPE_NXUN; -if ((uptr->flags & UNIT_ATT) && /* already attached? */ - !(uptr->dynflags & UNIT_ATTMULT)) { /* and only single attachable */ - r = scp_detach_unit (dptr, uptr); /* detach it */ - if (r != SCPE_OK) /* error? */ - return r; - } +if (uptr->flags & UNIT_ATT) /* already attached? */ + if (!(uptr->dynflags & UNIT_ATTMULT) && /* and only single attachable */ + !(dptr->flags & DEV_DONTAUTO)) { /* and auto detachable */ + r = scp_detach_unit (dptr, uptr); /* detach it */ + if (r != SCPE_OK) /* error? */ + return r; + } + else + return SCPE_ALATT; /* Already attached */ sim_trim_endspc (cptr); /* trim trailing spc */ return scp_attach_unit (dptr, uptr, cptr); /* attach */ } @@ -4627,7 +4653,6 @@ return sim_cancel (&sim_step_unit); void int_handler (int sig) { stop_cpu = 1; -sim_interval = 0; /* should speed up stop detection */ return; } @@ -6073,6 +6098,8 @@ return val; format = leading zeroes format Outputs: status = error status + if stream is NULL, returns length of output that would + have been generated. */ t_stat fprint_val (FILE *stream, t_value val, uint32 radix, @@ -6109,6 +6136,8 @@ switch (format) { dbuf[MAX_WIDTH - (digit * 4)] = ','; d = d - commas; if (width > MAX_WIDTH) { + if (!stream) + return width; fprintf (stream, "%*s", -((int)width), dbuf); return SCPE_OK; } @@ -6129,6 +6158,8 @@ switch (format) { d = MAX_WIDTH - (ndigits + commas); break; } +if (!stream) + return strlen(dbuf+d); if (fputs (&dbuf[d], stream) == EOF) return SCPE_IOERR; return SCPE_OK; @@ -6138,7 +6169,7 @@ return SCPE_OK; sim_activate add entry to event queue sim_activate_abs add entry to event queue even if event already scheduled - sim_activate_notbefure add entry to event queue even if event already scheduled + sim_activate_notbefore add entry to event queue even if event already scheduled but not before the specified time sim_activate_after add entry to event queue after a specified amount of wall time sim_cancel remove entry from event queue diff --git a/sim_console.c b/sim_console.c index 544e45b8..ed06631c 100644 --- a/sim_console.c +++ b/sim_console.c @@ -155,8 +155,8 @@ int32 sim_del_char = '\b'; /* delete character */ #else int32 sim_del_char = 0177; #endif -static t_stat sim_con_poll_svc (UNIT *uptr); /* console connection poll routine */ -static t_stat sim_con_reset (DEVICE *dptr); /* console reset routine */ +static t_stat sim_con_poll_svc (UNIT *uptr); /* console connection poll routine */ +static t_stat sim_con_reset (DEVICE *dptr); /* console reset routine */ UNIT sim_con_unit = { UDATA (&sim_con_poll_svc, 0, 0) }; /* console connection unit */ /* debugging bitmaps */ #define DBG_TRC TMXR_DBG_TRC /* trace routine calls */ @@ -319,9 +319,9 @@ while (*cptr != 0) { return SCPE_OK; } -t_stat sim_rem_con_poll_svc (UNIT *uptr); /* remote console connection poll routine */ -t_stat sim_rem_con_data_svc (UNIT *uptr); /* remote console connection data routine */ -t_stat sim_rem_con_reset (DEVICE *dptr); /* remote console reset routine */ +t_stat sim_rem_con_poll_svc (UNIT *uptr); /* remote console connection poll routine */ +t_stat sim_rem_con_data_svc (UNIT *uptr); /* remote console connection data routine */ +t_stat sim_rem_con_reset (DEVICE *dptr); /* remote console reset routine */ UNIT sim_rem_con_unit[2] = { { UDATA (&sim_rem_con_poll_svc, 0, 0) }, /* remote console connection polling unit */ { UDATA (&sim_rem_con_data_svc, 0, 0) }}; /* console data handling unit */ @@ -418,9 +418,10 @@ if (c >= 0) { /* poll connect */ TMLN *lp = &sim_rem_con_tmxr.ldsc[c]; char wru_name[8]; - sim_activate_after(uptr+1, 1000000); /* start data poll after 100ms */ + sim_activate_after(uptr+1, 1000000); /* start data poll after 1 second */ lp->rcve = 1; /* rcv enabled */ sim_rem_buf_ptr[c] = 0; /* start with empty command buffer */ + sim_rem_single_mode[c] = FALSE; /* in single command mode */ if (isprint(sim_int_char&0xFF)) sprintf(wru_name, "'%c'", sim_int_char&0xFF); else @@ -521,7 +522,7 @@ t_bool got_command; t_bool close_session = FALSE; TMLN *lp; char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], *cptr, *argv[1] = {NULL}; -CTAB *cmdp; +CTAB *cmdp = NULL; uint32 read_start_time; t_offset cmd_log_start; @@ -580,6 +581,9 @@ for (i=(was_stepping ? sim_rem_step_line : 0); tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeout); } else { + if ((c == '\n') || /* Ignore bare LF between commands (Microsoft Telnet bug) */ + (c == '\r')) /* Ignore empty commands */ + continue; if ((c == '\004') || (c == '\032')) { /* EOF character (^D or ^Z) ? */ tmxr_linemsgf (lp, "\r\nGoodbye\r\n"); tmxr_send_buffered_data (lp); /* flush any buffered data */ @@ -820,6 +824,7 @@ for (i=(was_stepping ? sim_rem_step_line : 0); tmxr_linemsgf (lp, "\r\nGoodbye\r\n"); tmxr_send_buffered_data (lp); /* flush any buffered data */ tmxr_reset_ln (lp); + sim_rem_single_mode[i] = FALSE; } } if (stepping) diff --git a/sim_defs.h b/sim_defs.h index 1612c6ab..b2e25b81 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -178,7 +178,7 @@ typedef unsigned long t_uint64; #define t_uint64 unsigned long long #endif /* end 64b */ #ifndef INT64_C -#define INT64_C(x) x ## LL +#define INT64_C(x) x ## LL #endif #if defined (USE_INT64) /* 64b data */ @@ -384,15 +384,17 @@ struct sim_device { #define DEV_V_TYPE 4 /* Attach type */ #define DEV_S_TYPE 3 /* Width of Type Field */ #define DEV_V_SECTORS 7 /* Unit Capacity is in 512byte sectors */ +#define DEV_V_DONTAUTO 8 /* Do not auto detach already attached units */ #define DEV_V_UF_31 12 /* user flags, V3.1 */ #define DEV_V_UF 16 /* user flags */ #define DEV_V_RSV 31 /* reserved */ -#define DEV_DIS (1 << DEV_V_DIS) /* device can be set enabled or disabled */ -#define DEV_DISABLE (1 << DEV_V_DISABLE) /* device is currently disabled */ +#define DEV_DIS (1 << DEV_V_DIS) /* device is currently disabled */ +#define DEV_DISABLE (1 << DEV_V_DISABLE) /* device can be set enabled or disabled */ #define DEV_DYNM (1 << DEV_V_DYNM) /* device requires call on msize routine to change memory size */ #define DEV_DEBUG (1 << DEV_V_DEBUG) /* device supports SET DEBUG command */ #define DEV_SECTORS (1 << DEV_V_SECTORS) /* capacity is 512 byte sectors */ +#define DEV_DONTAUTO (1 << DEV_V_DONTAUTO) /* Do not auto detach already attached units */ #define DEV_NET 0 /* Deprecated - meaningless */ diff --git a/sim_ether.c b/sim_ether.c index dce87473..d9fed3a2 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1229,11 +1229,11 @@ int pcap_sendpacket(pcap_t* handle, const u_char* msg, int len) #if defined(_WIN32) || defined(__CYGWIN__) /* extracted from WinPcap's Packet32.h */ struct _PACKET_OID_DATA { - uint32 Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h - ///< for a complete list of valid codes. - uint32 Length; ///< Length of the data field - uint8 Data[1]; ///< variable-lenght field that contains the information passed to or received - ///< from the adapter. + uint32 Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + uint32 Length; ///< Length of the data field + uint8 Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. }; typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; typedef void **LPADAPTER; diff --git a/sim_fio.c b/sim_fio.c index a7fbec10..e9222b1c 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -283,10 +283,10 @@ switch (whence) { break; case SEEK_END: - if (_fstati64 (_fileno (st), &statb)) - return (-1); - fileaddr = statb.st_size + offset; - break; + if (_fstati64 (_fileno (st), &statb)) + return (-1); + fileaddr = statb.st_size + offset; + break; case SEEK_CUR: if (fgetpos (st, &fileaddr)) return (-1); diff --git a/sim_rev.h b/sim_rev.h index 745280d9..7eb068f2 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -238,7 +238,7 @@ patch date module(s) and fix(es) pdp11_io.c: - fixed Qbus interrupts to treat all IO devices (except clock) as BR4 - - fixed order of int_internal (Jordi Guillaumes i Pons) + - fixed order of int_internal (Jordi Guillaumes i Pons) ppd11_rf.c - fixed bug in updating mem addr extension (Peter Schorn) diff --git a/sim_serial.c b/sim_serial.c index 15dee496..d9b5fdb2 100644 --- a/sim_serial.c +++ b/sim_serial.c @@ -536,7 +536,7 @@ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_ DWORD dwType; DWORD dwValueNameSize = sizeof(list[ports].desc); DWORD dwDataSize = sizeof(list[ports].name); - + /* Enumerate all the values underneath HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM */ while (RegEnumValueA(hSERIALCOMM, dwIndex, list[ports].desc, &dwValueNameSize, NULL, &dwType, (BYTE *)list[ports].name, &dwDataSize) == ERROR_SUCCESS) { /* String values with non-zero size are the interesting ones */ diff --git a/sim_video.c b/sim_video.c new file mode 100644 index 00000000..27d62c71 --- /dev/null +++ b/sim_video.c @@ -0,0 +1,796 @@ +/* sim_video.c: Bitmap video output + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 11-Jun-2013 MB First version +*/ + +#include "sim_video.h" + +t_bool vid_active = FALSE; + +#if HAVE_LIBSDL +#include +#include + +extern int32 sim_is_running; + +#define EVENT_REDRAW 1 /* redraw event for SDL */ +#define EVENT_CLOSE 2 /* close event for SDL */ +#define MAX_EVENTS 20 /* max events in queue */ + +typedef struct { + SIM_KEY_EVENT events[MAX_EVENTS]; + SDL_sem *sem; + int32 head; + int32 tail; + int32 count; + } KEY_EVENT_QUEUE; + +typedef struct { + SIM_MOUSE_EVENT events[MAX_EVENTS]; + SDL_sem *sem; + int32 head; + int32 tail; + int32 count; + t_bool b1_state; + t_bool b2_state; + t_bool b3_state; + } MOUSE_EVENT_QUEUE; + +int vid_thread (void* arg); + +t_bool vid_key_state[SDLK_LAST]; +t_bool vid_mouse_captured; +int32 vid_width; +int32 vid_height; +SDL_Surface *vid_image; /* video buffer */ +SDL_Surface *vid_window; /* window handle */ +SDL_Thread *vid_thread_id; /* event thread handle */ +SDL_Color vid_palette[256]; +KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ +MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ + +t_stat vid_open (uint32 width, uint32 height) +{ +if (!vid_active) { + vid_active = TRUE; + vid_width = width; + vid_height = height; + vid_mouse_captured = FALSE; + + vid_key_events.head = 0; + vid_key_events.tail = 0; + vid_key_events.count = 0; + vid_key_events.sem = SDL_CreateSemaphore (1); + vid_mouse_events.head = 0; + vid_mouse_events.tail = 0; + vid_mouse_events.count = 0; + vid_mouse_events.sem = SDL_CreateSemaphore (1); + + vid_thread_id = SDL_CreateThread (vid_thread, NULL); + if (vid_thread_id == NULL) { + vid_active = FALSE; + return SCPE_OPENERR; + } + + vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0); + + vid_palette[0].r = 0; + vid_palette[0].g = 0; + vid_palette[0].b = 0; + vid_palette[1].r = 255; + vid_palette[1].g = 255; + vid_palette[1].b = 255; + SDL_SetColors (vid_image, vid_palette, 0, 2); + + memset (&vid_key_state, 0, sizeof(vid_key_state)); + } +return SCPE_OK; +} + +t_stat vid_close (void) +{ +SDL_Event user_event; + +if (vid_active) { + vid_active = FALSE; + user_event.type = SDL_USEREVENT; + user_event.user.code = EVENT_CLOSE; + user_event.user.data1 = NULL; + user_event.user.data2 = NULL; + + SDL_PushEvent (&user_event); + } +return SCPE_OK; +} + +t_stat vid_poll_kb (SIM_KEY_EVENT *ev) +{ +if (SDL_SemTryWait (vid_key_events.sem) == 0) { /* get lock */ + if (vid_key_events.count > 0) { /* events in queue? */ + *ev = vid_key_events.events[vid_key_events.head++]; + vid_key_events.count--; + if (vid_key_events.head == MAX_EVENTS) + vid_key_events.head = 0; + SDL_SemPost (vid_key_events.sem); + return SCPE_OK; + } + SDL_SemPost (vid_key_events.sem); + } +return SCPE_EOF; +} + +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) +{ +if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count > 0) { + *ev = vid_mouse_events.events[vid_mouse_events.head++]; + vid_mouse_events.count--; + if (vid_mouse_events.head == MAX_EVENTS) + vid_mouse_events.head = 0; + SDL_SemPost (vid_mouse_events.sem); + return SCPE_OK; + } + SDL_SemPost (vid_mouse_events.sem); + } +return SCPE_EOF; +} + +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf) +{ +int32 i, j; +uint8* pix; + +pix = (uint8 *)vid_image->pixels; +pix = pix + (y * vid_width) + x; + +for (i = y; i < (y + h); i++) { + for (j = x; j < (x + w); j++) { + *pix++ = *buf++; + } + pix = pix + vid_width; + } +} + +void vid_refresh (void) +{ +SDL_Event user_event; + +user_event.type = SDL_USEREVENT; +user_event.user.code = EVENT_REDRAW; +user_event.user.data1 = NULL; +user_event.user.data2 = NULL; + +SDL_PushEvent (&user_event); +} + +int vid_map_key (int key) +{ +switch (key) { + + case SDLK_BACKSPACE: + return SIM_KEY_BACKSPACE; + + case SDLK_TAB: + return SIM_KEY_TAB; + + case SDLK_RETURN: + return SIM_KEY_ENTER; + + case SDLK_PAUSE: + return SIM_KEY_PAUSE; + + case SDLK_ESCAPE: + return SIM_KEY_ESC; + + case SDLK_SPACE: + return SIM_KEY_SPACE; + + case SDLK_QUOTE: + return SIM_KEY_SINGLE_QUOTE; + + case SDLK_COMMA: + return SIM_KEY_COMMA; + + case SDLK_MINUS: + return SIM_KEY_MINUS; + + case SDLK_PERIOD: + return SIM_KEY_PERIOD; + + case SDLK_SLASH: + return SIM_KEY_SLASH; + + case SDLK_0: + return SIM_KEY_0; + + case SDLK_1: + return SIM_KEY_1; + + case SDLK_2: + return SIM_KEY_2; + + case SDLK_3: + return SIM_KEY_3; + + case SDLK_4: + return SIM_KEY_4; + + case SDLK_5: + return SIM_KEY_5; + + case SDLK_6: + return SIM_KEY_6; + + case SDLK_7: + return SIM_KEY_7; + + case SDLK_8: + return SIM_KEY_8; + + case SDLK_9: + return SIM_KEY_9; + + case SDLK_SEMICOLON: + return SIM_KEY_SEMICOLON; + + case SDLK_EQUALS: + return SIM_KEY_EQUALS; + + case SDLK_LEFTBRACKET: + return SIM_KEY_LEFT_BRACKET; + + case SDLK_BACKSLASH: + return SIM_KEY_BACKSLASH; + + case SDLK_RIGHTBRACKET: + return SIM_KEY_RIGHT_BRACKET; + + case SDLK_BACKQUOTE: + return SIM_KEY_BACKQUOTE; + + case SDLK_a: + return SIM_KEY_A; + + case SDLK_b: + return SIM_KEY_B; + + case SDLK_c: + return SIM_KEY_C; + + case SDLK_d: + return SIM_KEY_D; + + case SDLK_e: + return SIM_KEY_E; + + case SDLK_f: + return SIM_KEY_F; + + case SDLK_g: + return SIM_KEY_G; + + case SDLK_h: + return SIM_KEY_H; + + case SDLK_i: + return SIM_KEY_I; + + case SDLK_j: + return SIM_KEY_J; + + case SDLK_k: + return SIM_KEY_K; + + case SDLK_l: + return SIM_KEY_L; + + case SDLK_m: + return SIM_KEY_M; + + case SDLK_n: + return SIM_KEY_N; + + case SDLK_o: + return SIM_KEY_O; + + case SDLK_p: + return SIM_KEY_P; + + case SDLK_q: + return SIM_KEY_Q; + + case SDLK_r: + return SIM_KEY_R; + + case SDLK_s: + return SIM_KEY_S; + + case SDLK_t: + return SIM_KEY_T; + + case SDLK_u: + return SIM_KEY_U; + + case SDLK_v: + return SIM_KEY_V; + + case SDLK_w: + return SIM_KEY_W; + + case SDLK_x: + return SIM_KEY_X; + + case SDLK_y: + return SIM_KEY_Y; + + case SDLK_z: + return SIM_KEY_Z; + + case SDLK_DELETE: + return SIM_KEY_DELETE; + + case SDLK_KP0: + return SIM_KEY_KP_INSERT; + + case SDLK_KP1: + return SIM_KEY_KP_END; + + case SDLK_KP2: + return SIM_KEY_KP_DOWN; + + case SDLK_KP3: + return SIM_KEY_KP_PAGE_DOWN; + + case SDLK_KP4: + return SIM_KEY_KP_LEFT; + + case SDLK_KP5: + return SIM_KEY_KP_5; + + case SDLK_KP6: + return SIM_KEY_KP_RIGHT; + + case SDLK_KP7: + return SIM_KEY_KP_HOME; + + case SDLK_KP8: + return SIM_KEY_KP_UP; + + case SDLK_KP9: + return SIM_KEY_KP_PAGE_UP; + + case SDLK_KP_PERIOD: + return SIM_KEY_KP_DELETE; + + case SDLK_KP_DIVIDE: + return SIM_KEY_KP_DIVIDE; + + case SDLK_KP_MULTIPLY: + return SIM_KEY_KP_MULTIPLY; + + case SDLK_KP_MINUS: + return SIM_KEY_KP_SUBTRACT; + + case SDLK_KP_PLUS: + return SIM_KEY_KP_ADD; + + case SDLK_KP_ENTER: + return SIM_KEY_KP_ENTER; + + case SDLK_UP: + return SIM_KEY_UP; + + case SDLK_DOWN: + return SIM_KEY_DOWN; + + case SDLK_RIGHT: + return SIM_KEY_RIGHT; + + case SDLK_LEFT: + return SIM_KEY_LEFT; + + case SDLK_INSERT: + return SIM_KEY_INSERT; + + case SDLK_HOME: + return SIM_KEY_HOME; + + case SDLK_END: + return SIM_KEY_END; + + case SDLK_PAGEUP: + return SIM_KEY_PAGE_UP; + + case SDLK_PAGEDOWN: + return SIM_KEY_PAGE_DOWN; + + case SDLK_F1: + return SIM_KEY_F1; + + case SDLK_F2: + return SIM_KEY_F2; + + case SDLK_F3: + return SIM_KEY_F3; + + case SDLK_F4: + return SIM_KEY_F4; + + case SDLK_F5: + return SIM_KEY_F5; + + case SDLK_F6: + return SIM_KEY_F6; + + case SDLK_F7: + return SIM_KEY_F7; + + case SDLK_F8: + return SIM_KEY_F8; + + case SDLK_F9: + return SIM_KEY_F9; + + case SDLK_F10: + return SIM_KEY_F10; + + case SDLK_F11: + return SIM_KEY_F11; + + case SDLK_F12: + return SIM_KEY_F12; + + case SDLK_NUMLOCK: + return SIM_KEY_NUM_LOCK; + + case SDLK_CAPSLOCK: + return SIM_KEY_CAPS_LOCK; + + case SDLK_SCROLLOCK: + return SIM_KEY_SCRL_LOCK; + + case SDLK_RSHIFT: + return SIM_KEY_SHIFT_R; + + case SDLK_LSHIFT: + return SIM_KEY_SHIFT_L; + + case SDLK_RCTRL: + return SIM_KEY_CTRL_R; + + case SDLK_LCTRL: + return SIM_KEY_CTRL_L; + + case SDLK_RALT: + return SIM_KEY_ALT_R; + + case SDLK_LALT: + return SIM_KEY_ALT_L; + + case SDLK_RMETA: + return SIM_KEY_ALT_R; + + case SDLK_LMETA: + return SIM_KEY_WIN_L; + + case SDLK_LSUPER: + return SIM_KEY_WIN_L; + + case SDLK_RSUPER: + return SIM_KEY_WIN_R; + + case SDLK_PRINT: + return SIM_KEY_PRINT; + + case SDLK_BREAK: + return SIM_KEY_PAUSE; + + case SDLK_MENU: + return SIM_KEY_MENU; + + default: + return SIM_KEY_UNKNOWN; + } +} + +void vid_key (SDL_KeyboardEvent *event) +{ +SIM_KEY_EVENT ev; + +if (vid_mouse_captured) { + static Uint8 *KeyStates = NULL; + static int numkeys; + + if (!KeyStates) + KeyStates = SDL_GetKeyState(&numkeys); + if ((event->state == SDL_PRESSED) && KeyStates[SDLK_RSHIFT] && (KeyStates[SDLK_LCTRL] || KeyStates[SDLK_RCTRL])) { + SDL_WM_GrabInput (SDL_GRAB_OFF); /* relese cursor */ + SDL_ShowCursor (SDL_ENABLE); /* show cursor */ + vid_mouse_captured = FALSE; + return; + } + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_key_events.sem) == 0) { + if (vid_key_events.count < MAX_EVENTS) { + if (event->state == SDL_PRESSED) { + if (!vid_key_state[event->keysym.sym]) { /* Key was not down before */ + vid_key_state[event->keysym.sym] = TRUE; + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_DOWN; + } + else { + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_REPEAT; + } + } + else { + vid_key_state[event->keysym.sym] = FALSE; + ev.key = vid_map_key (event->keysym.sym); + ev.state = SIM_KEYPRESS_UP; + } + vid_key_events.events[vid_key_events.tail++] = ev; + vid_key_events.count++; + if (vid_key_events.tail == MAX_EVENTS) + vid_key_events.tail = 0; + } + SDL_SemPost (vid_key_events.sem); + } +} + +void vid_mouse_move (SDL_MouseMotionEvent *event) +{ +SDL_Event dummy_event; +int32 cx; +int32 cy; +SIM_MOUSE_EVENT ev; + +if (!vid_mouse_captured) + return; + +if ((event->x == 0) || + (event->y == 0) || + (event->x == (vid_width - 1)) || + (event->y == (vid_height - 1))) { /* reached edge of window? */ + cx = vid_width / 2; + cy = vid_height / 2; + SDL_WarpMouse (cx, cy); /* back to centre */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count < MAX_EVENTS) { + ev.x_rel = event->xrel; + ev.y_rel = (-event->yrel); + ev.b1_state = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; + ev.b2_state = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; + ev.b3_state = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; + vid_mouse_events.b1_state = ev.b1_state; + vid_mouse_events.b2_state = ev.b2_state; + vid_mouse_events.b3_state = ev.b3_state; + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } + SDL_SemPost (vid_mouse_events.sem); + } +} + +void vid_mouse_button (SDL_MouseButtonEvent *event) +{ +SDL_Event dummy_event; +int32 cx; +int32 cy; +SIM_MOUSE_EVENT ev; +t_bool state; + +if (!vid_mouse_captured) { + if ((event->state == SDL_PRESSED) && + (event->button == SDL_BUTTON_LEFT)) { /* left click and cursor not captured? */ + SDL_WM_GrabInput (SDL_GRAB_ON); /* lock cursor to window */ + SDL_ShowCursor (SDL_DISABLE); /* hide cursor */ + cx = vid_width / 2; + cy = vid_height / 2; + SDL_WarpMouse (cx, cy); /* move cursor to centre of window */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; + vid_mouse_captured = TRUE; + } + return; + } +if (!sim_is_running) + return; +if (SDL_SemWait (vid_mouse_events.sem) == 0) { + if (vid_mouse_events.count < MAX_EVENTS) { + state = (event->state == SDL_PRESSED) ? TRUE : FALSE; + ev.x_rel = 0; + ev.y_rel = 0; + switch (event->button) { + case SDL_BUTTON_LEFT: + vid_mouse_events.b1_state = state; + break; + case SDL_BUTTON_MIDDLE: + vid_mouse_events.b2_state = state; + break; + case SDL_BUTTON_RIGHT: + vid_mouse_events.b3_state = state; + break; + } + ev.b1_state = vid_mouse_events.b1_state; + ev.b2_state = vid_mouse_events.b2_state; + ev.b3_state = vid_mouse_events.b3_state; + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } + SDL_SemPost (vid_mouse_events.sem); + } +} + +void vid_update (void) +{ +SDL_Rect vid_dst; + +vid_dst.x = 0; +vid_dst.y = 0; +vid_dst.w = vid_width; +vid_dst.h = vid_height; + +SDL_BlitSurface (vid_image, NULL, vid_window, &vid_dst); +SDL_UpdateRects (vid_window, 1, &vid_dst); +} + +int vid_thread (void* arg) +{ +int vid_bpp = 8; +int vid_flags = 0; +SDL_Event event; + +if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0) { + return SCPE_OPENERR; + } + +vid_window = SDL_SetVideoMode (vid_width, vid_height, vid_bpp, vid_flags); + +if (vid_window == NULL) { + return SCPE_OPENERR; + } + +if (SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL) < 0) { + return SCPE_OPENERR; + } + +SDL_WM_SetCaption (&sim_name[0], &sim_name[0]); + +while (vid_active) { + if (SDL_WaitEvent (&event)) { + switch (event.type) { + + case SDL_KEYDOWN: + case SDL_KEYUP: + vid_key ((SDL_KeyboardEvent*)&event); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + vid_mouse_button ((SDL_MouseButtonEvent*)&event); + break; + + case SDL_MOUSEMOTION: + vid_mouse_move ((SDL_MouseMotionEvent*)&event); + break; + + case SDL_USEREVENT: + if (event.user.code == EVENT_REDRAW) + vid_update (); + break; + + default: + break; + } + } + } +SDL_Quit (); +return 0; +} + +const char *vid_version(void) +{ +static char SDLVersion[80]; +const SDL_version *ver = SDL_Linked_Version(); + +sprintf(SDLVersion, "SDL Version %d.%d.%d", ver->major, ver->minor, ver->patch); +return (const char *)SDLVersion; +} + +t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +return SCPE_NOFNC; +} + +t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +fprintf (st, "ReleaseKey=Ctrl-Right-Shift"); +return SCPE_OK; +} + +#else + +/* Non-implemented versions */ + +t_stat vid_open (uint32 width, uint32 height) +{ +return SCPE_NOFNC; +} + +t_stat vid_close (void) +{ +return SCPE_OK; +} + +t_stat vid_poll_kb (SIM_KEY_EVENT *ev) +{ +return SCPE_EOF; +} + +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) +{ +return SCPE_EOF; +} + +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf) +{ +return; +} + +void vid_refresh (void) +{ +return; +} + +const char *vid_version (void) +{ +return "No Video Support"; +} + +t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +return SCPE_NOFNC; +} + +t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +fprintf (st, "no release key"); +return SCPE_OK; +} + + +#endif diff --git a/sim_video.h b/sim_video.h new file mode 100644 index 00000000..939f31f4 --- /dev/null +++ b/sim_video.h @@ -0,0 +1,183 @@ +/* sim_video.c: Bitmap video output + + Copyright (c) 2011-2013, Matt Burke + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 11-Jun-2013 MB First version +*/ + +#ifndef _SIM_VIDEO_H_ +#define _SIM_VIDEO_H_ 0 + +#include "sim_defs.h" + +#define SIM_KEYPRESS_DOWN 0 /* key states */ +#define SIM_KEYPRESS_UP 1 +#define SIM_KEYPRESS_REPEAT 2 + + +#define SIM_KEY_F1 0 /* key syms */ +#define SIM_KEY_F2 1 +#define SIM_KEY_F3 2 +#define SIM_KEY_F4 3 +#define SIM_KEY_F5 4 +#define SIM_KEY_F6 5 +#define SIM_KEY_F7 6 +#define SIM_KEY_F8 7 +#define SIM_KEY_F9 8 +#define SIM_KEY_F10 9 +#define SIM_KEY_F11 10 +#define SIM_KEY_F12 11 + +#define SIM_KEY_0 12 +#define SIM_KEY_1 13 +#define SIM_KEY_2 14 +#define SIM_KEY_3 15 +#define SIM_KEY_4 16 +#define SIM_KEY_5 17 +#define SIM_KEY_6 18 +#define SIM_KEY_7 19 +#define SIM_KEY_8 20 +#define SIM_KEY_9 21 + +#define SIM_KEY_A 22 +#define SIM_KEY_B 23 +#define SIM_KEY_C 24 +#define SIM_KEY_D 25 +#define SIM_KEY_E 26 +#define SIM_KEY_F 27 +#define SIM_KEY_G 28 +#define SIM_KEY_H 29 +#define SIM_KEY_I 30 +#define SIM_KEY_J 31 +#define SIM_KEY_K 32 +#define SIM_KEY_L 33 +#define SIM_KEY_M 34 +#define SIM_KEY_N 35 +#define SIM_KEY_O 36 +#define SIM_KEY_P 37 +#define SIM_KEY_Q 38 +#define SIM_KEY_R 39 +#define SIM_KEY_S 40 +#define SIM_KEY_T 41 +#define SIM_KEY_U 42 +#define SIM_KEY_V 43 +#define SIM_KEY_W 44 +#define SIM_KEY_X 45 +#define SIM_KEY_Y 46 +#define SIM_KEY_Z 47 + +#define SIM_KEY_BACKQUOTE 48 +#define SIM_KEY_MINUS 49 +#define SIM_KEY_EQUALS 50 +#define SIM_KEY_LEFT_BRACKET 51 +#define SIM_KEY_RIGHT_BRACKET 52 +#define SIM_KEY_SEMICOLON 53 +#define SIM_KEY_SINGLE_QUOTE 54 +#define SIM_KEY_BACKSLASH 55 +#define SIM_KEY_LEFT_BACKSLASH 56 +#define SIM_KEY_COMMA 57 +#define SIM_KEY_PERIOD 58 +#define SIM_KEY_SLASH 59 + +#define SIM_KEY_PRINT 60 +#define SIM_KEY_SCRL_LOCK 61 +#define SIM_KEY_PAUSE 62 + +#define SIM_KEY_ESC 63 +#define SIM_KEY_BACKSPACE 64 +#define SIM_KEY_TAB 65 +#define SIM_KEY_ENTER 66 +#define SIM_KEY_SPACE 67 +#define SIM_KEY_INSERT 68 +#define SIM_KEY_DELETE 69 +#define SIM_KEY_HOME 70 +#define SIM_KEY_END 71 +#define SIM_KEY_PAGE_UP 72 +#define SIM_KEY_PAGE_DOWN 73 +#define SIM_KEY_UP 74 +#define SIM_KEY_DOWN 75 +#define SIM_KEY_LEFT 76 +#define SIM_KEY_RIGHT 77 + +#define SIM_KEY_CAPS_LOCK 78 +#define SIM_KEY_NUM_LOCK 79 + +#define SIM_KEY_ALT_L 80 +#define SIM_KEY_ALT_R 81 +#define SIM_KEY_CTRL_L 82 +#define SIM_KEY_CTRL_R 83 +#define SIM_KEY_SHIFT_L 84 +#define SIM_KEY_SHIFT_R 85 +#define SIM_KEY_WIN_L 86 +#define SIM_KEY_WIN_R 87 +#define SIM_KEY_MENU 88 + +#define SIM_KEY_KP_ADD 89 +#define SIM_KEY_KP_SUBTRACT 90 +#define SIM_KEY_KP_END 91 +#define SIM_KEY_KP_DOWN 92 +#define SIM_KEY_KP_PAGE_DOWN 93 +#define SIM_KEY_KP_LEFT 94 +#define SIM_KEY_KP_RIGHT 95 +#define SIM_KEY_KP_HOME 96 +#define SIM_KEY_KP_UP 97 +#define SIM_KEY_KP_PAGE_UP 98 +#define SIM_KEY_KP_INSERT 99 +#define SIM_KEY_KP_DELETE 100 +#define SIM_KEY_KP_5 101 +#define SIM_KEY_KP_ENTER 102 +#define SIM_KEY_KP_MULTIPLY 103 +#define SIM_KEY_KP_DIVIDE 104 + +#define SIM_KEY_UNKNOWN 200 + +struct mouse_event { + uint32 x_rel; /* X axis relative motion */ + uint32 y_rel; /* Y axis relative motion */ + t_bool b1_state; /* state of button 1 */ + t_bool b2_state; /* state of button 2 */ + t_bool b3_state; /* state of button 3 */ + }; + +struct key_event { + uint32 key; /* key sym */ + uint32 state; /* key state change */ + }; + +typedef struct mouse_event SIM_MOUSE_EVENT; +typedef struct key_event SIM_KEY_EVENT; + +t_stat vid_open (uint32 width, uint32 height); +t_stat vid_close (void); +t_stat vid_poll_kb (SIM_KEY_EVENT *ev); +t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev); +void vid_draw (int32 x, int32 y, int32 w, int32 h, uint8 *buf); +void vid_refresh (void); +const char *vid_version (void); +t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, void* desc); + +extern t_bool vid_active; + +#endif