PDP-10 update

Implement keep-alive and os-requested reload functions of FE.
Preserve HW config flags during (re-) boot.
Allow IPL30 device to interrupt.
Add 18-bit DMA functions.
Implement DMA to/from I/O space.
Optimize DMA memory mapping - once per page, not once per byte.
Teach SHOW IO to report vectors and BR levels as well as CSR addresses.
Add DUP and KDP to Autoconfigure table.
This commit is contained in:
Timothe Litt 2013-07-04 23:56:24 -04:00
parent 8df4e2a3fd
commit 0e939d29e8
6 changed files with 456 additions and 82 deletions

View file

@ -151,6 +151,10 @@ typedef struct {
d10 ac; d10 ac;
} InstHistory; } 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 *M = NULL; /* memory */
d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */ d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */
d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */ d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */
@ -708,6 +712,9 @@ xct_cnt = 0; /* count XCT's */
if (sim_interval <= 0) { /* check clock queue */ if (sim_interval <= 0) { /* check clock queue */
if ((i = sim_process_event ())) /* error? stop sim */ if ((i = sim_process_event ())) /* error? stop sim */
ABORT (i); ABORT (i);
if (fe_xct)
qintr = -1;
else
pi_eval (); /* eval pi system */ pi_eval (); /* eval pi system */
} }
@ -715,12 +722,35 @@ if (sim_interval <= 0) { /* check clock queue */
On the KS10, only JSR and XPCW are allowed as interrupt instructions. On the KS10, only JSR and XPCW are allowed as interrupt instructions.
Because of exec mode addressing, and unconditional processing of flags, Because of exec mode addressing, and unconditional processing of flags,
they are explicitly emulated here. 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) { if (qintr) {
int32 vec, uba; int32 vec, uba;
pager_pi = TRUE; /* flag in pi seq */ 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 */ mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */
if (mb == 0) /* invalid? stop */ if (mb == 0) /* invalid? stop */
ABORT (STOP_ZERINT); ABORT (STOP_ZERINT);
@ -750,9 +780,16 @@ if (qintr) {
JUMP (rs[1]); /* set new PC */ JUMP (rs[1]); /* set new PC */
set_newflags (rs[0], FALSE); /* set new flags */ set_newflags (rs[0], FALSE); /* set new flags */
} }
else ABORT (STOP_ILLINT); /* invalid instr */ 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_act = pi_act | pi_l2bit[qintr]; /* set level active */
pi_eval (); /* eval pi system */ pi_eval (); /* eval pi system */
}
pager_pi = FALSE; /* end of sequence */ pager_pi = FALSE; /* end of sequence */
if (sim_interval) /* charge for instr */ if (sim_interval) /* charge for instr */
sim_interval--; sim_interval--;

View file

@ -114,7 +114,8 @@ typedef t_int64 d10; /* PDP-10 data (36b) */
#define STOP_XCT 9 /* XCT loop */ #define STOP_XCT 9 /* XCT loop */
#define STOP_ILLIOC 10 /* invalid UBA num */ #define STOP_ILLIOC 10 /* invalid UBA num */
#define STOP_ASTOP 11 /* address stop */ #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 PAGE_FAIL -1 /* page fail */
#define INTERRUPT -2 /* interrupt */ #define INTERRUPT -2 /* interrupt */
#define ABORT(x) longjmp (save_env, (x)) /* abort */ #define ABORT(x) longjmp (save_env, (x)) /* abort */
@ -708,7 +709,6 @@ typedef struct pdp_dib DIB;
#define INT_V_PTP 25 #define INT_V_PTP 25
#define INT_V_LP20 26 /* LPT20 */ #define INT_V_LP20 26 /* LPT20 */
#define INT_V_CR 27 /* CD20 (CD11) */ #define INT_V_CR 27 /* CD20 (CD11) */
#define INT_V_CR 27 /* CD20 (CD11) */
#define INT_V_DUPRX 28 /* DUP11 */ #define INT_V_DUPRX 28 /* DUP11 */
#define INT_V_DUPTX 29 #define INT_V_DUPTX 29
@ -748,7 +748,7 @@ typedef struct pdp_dib DIB;
#define INT_IPL7 0x0000000F /* int level masks */ #define INT_IPL7 0x0000000F /* int level masks */
#define INT_IPL6 0x000000F0 #define INT_IPL6 0x000000F0
#define INT_IPL5 0x000FFF00 #define INT_IPL5 0x000FFF00
#define INT_IPL4 0x3FF00000 #define INT_IPL4 0x7FF00000
#define VEC_Q 0000 /* vector base */ #define VEC_Q 0000 /* vector base */
#define VEC_PTR 0070 /* interrupt vectors */ #define VEC_PTR 0070 /* interrupt vectors */
@ -772,8 +772,10 @@ typedef struct pdp_dib DIB;
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *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_WriteB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *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 (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc);

View file

@ -47,8 +47,13 @@ extern int32 apr_flg;
extern int32 tmxr_poll; extern int32 tmxr_poll;
t_stat fei_svc (UNIT *uptr); t_stat fei_svc (UNIT *uptr);
t_stat feo_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_reset (DEVICE *dptr);
t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); 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 /* 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 fei_unit fe_unit[0]
#define feo_unit fe_unit[1] #define feo_unit fe_unit[1]
#define kaf_unit fe_unit[2]
UNIT fe_unit[] = { UNIT fe_unit[] = {
{ UDATA (&fei_svc, UNIT_IDLE, 0), 0 }, { 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[] = { REG fe_reg[] = {
@ -82,7 +89,7 @@ MTAB fe_mod[] = {
DEVICE fe_dev = { DEVICE fe_dev = {
"FE", fe_unit, fe_reg, fe_mod, "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, &fe_reset,
NULL, NULL, NULL NULL, NULL, NULL
}; };
@ -123,7 +130,9 @@ XPP RLWORD,31 ;RELOAD WORD [FE_KEEPA]
DRMPAR==1B9 ;DRAM PAR ERR DETECT ENABLED DRMPAR==1B9 ;DRAM PAR ERR DETECT ENABLED
CASHEN==1B10 ;CACHE ENABLED CASHEN==1B10 ;CACHE ENABLED
MILSEN==1B11 ;1MSEC ENABLED MILSEN==1B11 ;1MSEC ENABLED
KPALIV==377B28 ;KEEP ALIVE WORD TRPENA==1B12 ;TRAPS ENABLED
MFGMOD==1B13 ;MANUFACTURING MODE
KPALIV==377B27 ;KEEP ALIVE WORD CHECKED EVERY 1 SEC, AFTER 15, FAIL
; Why reload (8080->10) ; Why reload (8080->10)
AUTOBT==1B32 ;BOOT SWITCH OR POWER UP CONDITION AUTOBT==1B32 ;BOOT SWITCH OR POWER UP CONDITION
PWRFAL==1B33 ;POWER FAIL restart (Start at 70) PWRFAL==1B33 ;POWER FAIL restart (Start at 70)
@ -196,6 +205,87 @@ apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK; 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 <rld> 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 */ /* Reset */
t_stat fe_reset (DEVICE *dptr) t_stat fe_reset (DEVICE *dptr)
@ -206,9 +296,12 @@ fei_unit.buf = feo_unit.buf = 0;
M[FE_CTYIN] = M[FE_CTYOUT] = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0;
M[FE_KLININ] = M[FE_KLINOUT] = 0; M[FE_KLININ] = M[FE_KLINOUT] = 0;
M[FE_KEEPA] = INT64_C(0003700000000); 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); apr_flg = apr_flg & ~(APRF_ITC | APRF_CON);
sim_activate (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); sim_activate (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll));
sim_activate_after (&kaf_unit, kaf_unit.wait);
return SCPE_OK; return SCPE_OK;
} }

View file

@ -79,17 +79,23 @@
#define AUTO_CSRMAX 04000 #define AUTO_CSRMAX 04000
#define AUTO_VECBASE 0300 #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 XBA_MBZ 0400000 /* ba mbz */
#define eaRB (ea & ~1) #define eaRB (ea & ~1)
#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377) #define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)
#define UBNXM_FAIL(pa,op) \ #define UBNXM_FAIL(pa,op) \
n = iocmap[GET_IOUBA (pa)]; \ n = ADDR2UBA (pa); \
if (n >= 0) \ if (n >= 0) \
ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \ ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \
pager_word = PF_HARD | PF_VIRT | PF_IO | \ pager_word = PF_HARD | PF_VIRT | PF_IO | \
((op == WRITEB)? PF_BYTE: 0) | \ ((op == WRITEB)? PF_BYTE: 0) | \
(TSTF (F_USR)? PF_USER: 0) | (pa); \ (TSTF (F_USR)? PF_USER: 0) | (pa); \
ABORT (PAGE_FAIL) 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 */ /* Unibus adapter data */
@ -401,131 +407,349 @@ return;
simulator and the 32b world of the device simulators. 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; uint32 pa = (uint32) ba;
int32 i, n, val; int32 i, val;
DIB *dibp; DIB *dibp;
for (i = 0; (dibp = dib_tab[i]); i++ ) { for (i = 0; (dibp = dib_tab[i]); i++ ) {
if ((pa >= dibp->ba) && if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) { (pa < (dibp->ba + dibp->lnt))) {
dibp->rd (&val, pa, READ); dibp->rd (&val, pa, access);
pi_eval (); pi_eval ();
*data = val;
return SCPE_OK;
}
}
return SCPE_NXM;
}
d10 ReadIO (a10 ea)
{
uint32 pa = (uint32) ea;
int32 n, val;
if (UBReadIO (&val, pa, READ) == SCPE_OK)
return ((d10) val); return ((d10) val);
}
}
UBNXM_FAIL (pa, READ); 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) void WriteIO (a10 ea, d10 val, int32 mode)
{ {
uint32 pa = (uint32) ea; uint32 pa = (uint32) ea;
int32 i, n; int32 n;
DIB *dibp;
for (i = 0; (dibp = dib_tab[i]); i++ ) { if (UBWriteIO ((int32) val, (int32) pa, mode) == SCPE_OK)
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->wr ((int32) val, pa, mode);
pi_eval ();
return; return;
}
}
UBNXM_FAIL (pa, mode); 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; a10 pa10;
int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */ int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */
int32 ubm;
if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || /* invalid map? */ if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ)) { /* Validate bus address */
((ubmap[ub][vpn] & UMAP_VLD) == 0)) if (ubmp)
*ubmp = 0;
return -1; 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; return pa10;
} }
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf) int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 lim; uint32 lim, cp, np;
a10 pa10; a10 pa10;
if ((ba & ~((IO_M_UBA<<IO_V_UBA)|0017777)) == 0760000)
{ /* IOPAGE: device register read */
int32 csr;
while (bc) {
if (UBReadIO (&csr, ba & ~1, READ) != SCPE_OK)
break;
*buf++ = (ba &1)? ((csr >> 8) & 0xff): csr & 0xff;
ba++;
bc--;
}
return bc;
}
lim = ba + bc; lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */ for ( cp = ~ba ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */ 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? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */ return (lim - ba); /* return bc */
} }
cp = np;
}
*buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377); *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
if ((ba & 3) == 3)
pa10++;
} }
return 0; return 0;
} }
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf) int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 lim; uint32 lim, cp, np;
a10 pa10; a10 pa10;
if ((ba & ~((IO_M_UBA<<IO_V_UBA)|0017777)) == 0760000)
{ /* IOPAGE: device register read */
int32 csr;
if ((ba & 1) || (bc & 1))
return bc;
while (bc) {
if (UBReadIO (&csr, ba, READ) != SCPE_OK)
break;
*buf++ = (uint16)csr;
ba += 2;
bc -= 2;
}
return bc;
}
ba = ba & ~01; /* align start */ ba = ba & ~01; /* align start */
lim = ba + (bc & ~01); lim = ba + (bc & ~01);
for ( ; ba < lim; ba = ba + 2) { /* by words */ for ( cp = ~ba; ba < lim; ba = ba + 2) { /* by words */
pa10 = Map_Addr10 (ba, 1); /* map addr */ 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? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */ return (lim - ba); /* return bc */
} }
cp = np;
}
*buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777); *buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
if (ba & 2 )
pa10++;
} }
return 0; 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<<IO_V_UBA)|0017777)) == 0760000)
{ /* IOPAGE: device register read */
int32 csr;
if ((ba & 1) || (bc & 1))
return bc;
while (bc) {
if (UBReadIO (&csr, ba, READ) != SCPE_OK)
break;
*buf++ = (uint32)csr;
ba += 2;
bc -= 2;
}
return bc;
}
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
for ( cp = ~ba; ba < lim; ba = ba + 2) { /* by words */
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++ = (uint32) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0777777);
if (ba & 2 )
pa10++;
}
return 0;
}
/* Byte-mode writes */
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf) int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 lim; uint32 lim, cp, np;
a10 pa10; a10 pa10;
d10 mask; d10 mask;
if ((ba & ~((IO_M_UBA<<IO_V_UBA)|0017777)) == 0760000)
{ /* IOPAGE: device register write */
while (bc) {
if (UBWriteIO (*buf++ & 0xff, ba, WRITEB) != SCPE_OK)
break;
ba++;
bc--;
}
return bc;
}
lim = ba + bc; lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */ for ( cp = ~ba; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */ 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? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */ return (lim - ba); /* return bc */
} }
mask = 0377; cp = np;
M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) | }
(((d10) *buf++) << ubashf[ba & 3]); if( (ba&3) == 0 ) { /* byte 0 writes memory; other bytes & <0:1,18:19> 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++;
}
} }
return 0; return 0;
} }
/* Word mode writes; 16-bit data */
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf) int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 lim; uint32 lim, cp, np;
int32 ubm;
a10 pa10; a10 pa10;
d10 val; d10 val;
if ((ba & ~((IO_M_UBA<<IO_V_UBA)|0017777)) == 0760000)
{ /* IOPAGE: device register write */
if ((ba & 1) || (bc &1))
return bc;
while (bc) {
if (UBWriteIO (*buf++ & 0xffff, ba, WRITE) != SCPE_OK)
break;
ba += 2;
bc -= 2;
}
return bc;
}
ba = ba & ~01; /* align start */ ba = ba & ~01; /* align start */
lim = ba + (bc & ~01); lim = ba + (bc & ~01);
for ( ; ba < lim; ba += 2) { /* by bytes */ for ( cp = ~ba; ba < lim; ba+= 2) { /* by words */
pa10 = Map_Addr10 (ba, 1); /* map addr */ np = UBMPAGE (ba);
if (np != cp) { /* New (or first) page? */
pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */ return (lim - ba); /* return bc */
} }
val = *buf++; /* get data */ cp = np;
if (ba & 2) }
val = *buf++; /* get 16-bit data, clearing <17:16> */
if (ubm & UMAP_RRV ) { /* Read reverse preserves even word */
if (ba & 2) {
M[pa10] = (M[pa10] & INT64_C(0777777000000)) | val; M[pa10] = (M[pa10] & INT64_C(0777777000000)) | val;
else M[pa10] = (M[pa10] & INT64_C(0000000777777)) | (val << 18); 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 */
}
} }
return 0; 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<<IO_V_UBA)|0017777)) == 0760000)
{ /* IOPAGE: device register write */
if ((ba & 1) || (bc &1))
return bc;
while (bc) {
if (UBWriteIO (*buf++ & 0777777, ba, WRITE) != SCPE_OK)
break;
ba += 2;
bc -= 2;
}
return bc;
}
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
for ( cp = ~ba; ba < lim; ba+= 2) { /* by words */
np = UBMPAGE (ba);
if (np != cp) { /* New (or first) page? */
pa10 = Map_Addr10 (ba, 1, &ubm); /* 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;
}
val = *buf++; /* get 18-bit data */
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 */
}
}
return 0;
}
/* Evaluate Unibus priority interrupts */ /* Evaluate Unibus priority interrupts */
int32 pi_ub_eval () int32 pi_ub_eval ()
@ -905,6 +1129,8 @@ while (done == 0) { /* sort ascending */
} }
} }
} /* end while */ } /* end while */
fprintf (st, " Address Vector BR Device\n"
"----------------- -------- -- ------\n");
for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ for (i = 0; dib_tab[i] != NULL; i++) { /* print table */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) { if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) {
@ -912,9 +1138,25 @@ for (i = 0; dib_tab[i] != NULL; i++) { /* print table */
break; break;
} }
} }
fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba, fprintf (st, "%07o - %07o ", dib_tab[i]->ba,
dib_tab[i]->ba + dib_tab[i]->lnt - 1, dib_tab[i]->ba + dib_tab[i]->lnt - 1);
dptr? sim_dname (dptr): "CPU"); 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; return SCPE_OK;
} }
@ -929,7 +1171,7 @@ return SCPE_OK;
devices with static addresses and addresses(and vectors) in floating devices with static addresses and addresses(and vectors) in floating
address space is #ifdef'd out below. These addresses have been address space is #ifdef'd out below. These addresses have been
used historically in the PDP10 simulator so their fixed addresses 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. expect them to be using these fixed address and vectors.
A minus number of vectors indicates a field that should be calculated A minus number of vectors indicates a field that should be calculated
@ -961,6 +1203,10 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */
{0017550}, {0070} }, /* PC11 reader - fx CSR, fx VEC */ {0017550}, {0070} }, /* PC11 reader - fx CSR, fx VEC */
{ { "PTP" }, 1, 1, 0, 0, { { "PTP" }, 1, 1, 0, 0,
{0017554}, {0074} }, /* PC11 punch - fx CSR, fx VEC */ {0017554}, {0074} }, /* PC11 punch - fx CSR, fx VEC */
{ { "DUP" }, 1, 2, 0, 0,
{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 #else
{ { "QBA" }, 1, 0, 0, 0, { { "QBA" }, 1, 0, 0, 0,
{017500} }, /* doorbell - fx CSR, no VEC */ {017500} }, /* doorbell - fx CSR, no VEC */

View file

@ -335,6 +335,8 @@ extern int32 int_req;
extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */ extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */
extern int32 ubcs[UBANUM]; extern int32 ubcs[UBANUM];
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern uint32 fe_bootrh;
extern int32 fe_bootunit;
int32 rpcs1 = 0; /* control/status 1 */ int32 rpcs1 = 0; /* control/status 1 */
int32 rpwc = 0; /* word count */ int32 rpwc = 0; /* word count */
@ -1363,15 +1365,12 @@ uptr = rp_dev.units + unitno;
if (!(uptr->flags & UNIT_ATT)) if (!(uptr->flags & UNIT_ATT))
return SCPE_NOATT; return SCPE_NOATT;
M[FE_RHBASE] = rp_dib.ba; M[FE_RHBASE] = fe_bootrh = rp_dib.ba;
M[FE_UNIT] = unitno; M[FE_UNIT] = fe_bootunit = unitno;
assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its));
if (sim_switches & SWMASK ('A')) M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0);
M[FE_KEEPA] = ((d10) 010); /* <32>: Autoboot */
else
M[FE_KEEPA] = 0;
for (i = 0; i < BOOT_LEN; i++) for (i = 0; i < BOOT_LEN; i++)
M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i];

View file

@ -1382,10 +1382,7 @@ assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its));
M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT); M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT);
tu_unit[unitno].pos = 0; tu_unit[unitno].pos = 0;
if (sim_switches & SWMASK ('A')) M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0);
M[FE_KEEPA] = ((d10) 010); /* <32>: Autoboot */
else
M[FE_KEEPA] = 0;
for (i = 0; i < BOOT_LEN; i++) for (i = 0; i < BOOT_LEN; i++)
M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i];