simh v2.5a

This commit is contained in:
Bob Supnik 2001-11-06 20:47:00 -08:00 committed by Mark Pizzolato
parent 9af6fd21e7
commit 062d217c67
53 changed files with 2446 additions and 1061 deletions

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
26-Nov-00 RMS Fixed bug in dual device number routine
21-Nov-00 RMS Fixed bug in reset routine
15-Oct-00 RMS Added dynamic device number support
The register state for the HP 2100 CPU is:
@ -1325,7 +1327,7 @@ return (stop_dev << IOT_V_REASON) | dat;
t_stat cpu_reset (DEVICE *dptr)
{
AR = BR = 0;
saved_AR = saved_BR = 0;
XR = YR = 0;
E = 0;
O = 0;
@ -1441,7 +1443,7 @@ return SCPE_OK;
t_stat hp_setdev2 (UNIT *uptr, int32 ord)
{
int32 olddev;
int32 i, olddev;
t_stat r;
olddev = infotab[ord].devno;
@ -1449,6 +1451,11 @@ if ((r = hp_setdev (uptr, ord)) != SCPE_OK) return r;
if (infotab[ord].devno == DEVMASK) {
infotab[ord].devno = olddev;
return SCPE_ARG; }
for (i = 0; infotab[i].devno != 0; i++) {
if ((i != (ord + 1)) &&
((infotab[ord].devno + 1) == infotab[i].devno)) {
infotab[ord].devno = olddev;
return SCPE_ARG; } }
infotab[ord + 1].devno = infotab[ord].devno + 1;
return SCPE_OK;
}

View file

@ -47,7 +47,7 @@
#define AMASK (MAXMEMSIZE - 1) /* address mask */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Machine architecture */
/* Architectural constants */
#define SIGN 0100000 /* sign */
#define DMASK 0177777 /* data mask */
@ -86,29 +86,7 @@ struct DMA { /* DMA channel */
int32 cw3; /* word count */
};
/* I/O macros */
#define INT_V(x) ((x) & 037) /* device bit pos */
#define INT_M(x) (1u << INT_V (x)) /* device bit mask */
#define setCMD(D) dev_cmd[(D)/32] = dev_cmd[(D)/32] | INT_M ((D))
#define clrCMD(D) dev_cmd[(D)/32] = dev_cmd[(D)/32] & ~INT_M (D)
#define setCTL(D) dev_ctl[(D)/32] = dev_ctl[(D)/32] | INT_M ((D))
#define clrCTL(D) dev_ctl[(D)/32] = dev_ctl[(D)/32] & ~INT_M (D)
#define setFBF(D) dev_fbf[(D)/32] = dev_fbf[(D)/32] | INT_M (D)
#define clrFBF(D) dev_fbf[(D)/32] = dev_fbf[(D)/32] & ~INT_M (D)
#define setFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] | INT_M (D); \
setFBF(D)
#define clrFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] & ~INT_M (D); \
clrFBF(D)
#define CMD(D) ((dev_cmd[(D)/32] >> INT_V (D)) & 1)
#define CTL(D) ((dev_ctl[(D)/32] >> INT_V (D)) & 1)
#define FLG(D) ((dev_flg[(D)/32] >> INT_V (D)) & 1)
#define FBF(D) ((dev_fbf[(D)/32] >> INT_V (D)) & 1)
#define IOT_V_REASON 16
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* I/O instruction sub-opcodes */
/* I/O sub-opcodes */
#define ioHLT 0 /* halt */
#define ioFLG 1 /* set/clear flag */
@ -146,6 +124,8 @@ struct DMA { /* DMA channel */
#define MTC 021 /* mag tape control */
#define DPD 022 /* disk pack data */
#define DPC 023 /* disk pack control */
#define DPBD 024 /* second disk pack data */
#define DPBC 025 /* second disk pack control */
/* Dynamic device information table */
@ -169,5 +149,29 @@ struct hpdev {
#define inMTC 6
#define inDPD 7
#define inDPC 8
#define inDPBD 9
#define inDPBC 10
#define UNIT_DEVNO (1 << UNIT_V_UF) /* dummy flag */
/* I/O macros */
#define INT_V(x) ((x) & 037) /* device bit pos */
#define INT_M(x) (1u << INT_V (x)) /* device bit mask */
#define setCMD(D) dev_cmd[(D)/32] = dev_cmd[(D)/32] | INT_M ((D))
#define clrCMD(D) dev_cmd[(D)/32] = dev_cmd[(D)/32] & ~INT_M (D)
#define setCTL(D) dev_ctl[(D)/32] = dev_ctl[(D)/32] | INT_M ((D))
#define clrCTL(D) dev_ctl[(D)/32] = dev_ctl[(D)/32] & ~INT_M (D)
#define setFBF(D) dev_fbf[(D)/32] = dev_fbf[(D)/32] | INT_M (D)
#define clrFBF(D) dev_fbf[(D)/32] = dev_fbf[(D)/32] & ~INT_M (D)
#define setFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] | INT_M (D); \
setFBF(D)
#define clrFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] & ~INT_M (D); \
clrFBF(D)
#define CMD(D) ((dev_cmd[(D)/32] >> INT_V (D)) & 1)
#define CTL(D) ((dev_ctl[(D)/32] >> INT_V (D)) & 1)
#define FLG(D) ((dev_flg[(D)/32] >> INT_V (D)) & 1)
#define FBF(D) ((dev_fbf[(D)/32] >> INT_V (D)) & 1)
#define IOT_V_REASON 16
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */

View file

@ -24,6 +24,9 @@
in this Software without prior written authorization from Robert M Supnik.
dp 12557A cartridge disk system
29-Nov-00 RMS Made variable names unique
21-Nov-00 RMS Fixed flag, buffer power up state
*/
#include "hp2100_defs.h"
@ -108,11 +111,11 @@ int32 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */
int32 dpc_stime = 10; /* seek time */
int32 dpc_ctime = 10; /* command time */
int32 dpc_xtime = 5; /* xfer time */
int32 rarc = 0, rarh = 0, rars = 0; /* record addr */
int32 dpc_rarc = 0, dpc_rarh = 0, dpc_rars = 0; /* record addr */
int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */
int32 dpc_obuf = 0; /* cch buffers */
int32 dpbptr = 0; /* buffer ptr */
unsigned int16 dbuf[DP_NUMWD]; /* sector buffer */
int32 dp_ptr = 0; /* buffer ptr */
unsigned int16 dp_buf[DP_NUMWD]; /* sector buffer */
t_stat dpc_svc (UNIT *uptr);
t_stat dpc_reset (DEVICE *dptr);
@ -140,7 +143,7 @@ REG dpd_reg[] = {
{ FLDATA (CTL, infotab[inDPD].ctl, 0) },
{ FLDATA (FLG, infotab[inDPD].flg, 0) },
{ FLDATA (FBF, infotab[inDPD].fbf, 0) },
{ DRDATA (BPTR, dpbptr, DP_W_NUMWD) },
{ DRDATA (BPTR, dp_ptr, DP_W_NUMWD) },
{ ORDATA (DEVNO, infotab[inDPD].devno, 6), REG_RO },
{ NULL } };
@ -167,9 +170,9 @@ UNIT dpc_unit[] = {
REG dpc_reg[] = {
{ ORDATA (OBUF, dpc_obuf, 16) },
{ ORDATA (BUSY, dpc_busy, 3), REG_RO },
{ ORDATA (RARC, rarc, 8) },
{ ORDATA (RARH, rarh, 2) },
{ ORDATA (RARS, rars, 4) },
{ ORDATA (RARC, dpc_rarc, 8) },
{ ORDATA (RARH, dpc_rarh, 2) },
{ ORDATA (RARS, dpc_rars, 4) },
{ ORDATA (CNT, dpc_cnt, 5) },
{ FLDATA (CMD, infotab[inDPC].cmd, 0) },
{ FLDATA (CTL, infotab[inDPC].ctl, 0) },
@ -344,7 +347,7 @@ switch (uptr -> FNC) { /* case function */
case FNC_SEEK: /* seek, need cyl */
if (CMD (devd)) { /* dch active? */
rarc = DA_GETCYL (dpd_obuf); /* take cyl word */
dpc_rarc = DA_GETCYL (dpd_obuf); /* take cyl word */
setFLG (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
uptr -> FNC = FNC_SEEK1; } /* advance state */
@ -352,14 +355,14 @@ case FNC_SEEK: /* seek, need cyl */
return SCPE_OK;
case FNC_SEEK1: /* seek, need hd/sec */
if (CMD (devd)) { /* dch active? */
rarh = DA_GETHD (dpd_obuf); /* get head */
rars = DA_GETSC (dpd_obuf); /* get sector */
dpc_rarh = DA_GETHD (dpd_obuf); /* get head */
dpc_rars = DA_GETSC (dpd_obuf); /* get sector */
setFLG (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
st = abs (rarc - uptr -> CYL) * dpc_stime; /* calc cyl diff */
st = abs (dpc_rarc - uptr -> CYL) * dpc_stime; /* calc diff */
if (st == 0) st = dpc_xtime; /* min time */
sim_activate (uptr, st); /* schedule op */
uptr -> CYL = rarc; /* on cylinder */
uptr -> CYL = dpc_rarc; /* on cylinder */
dpc_busy = 0; /* ctrl is free */
uptr -> FNC = FNC_SEEK2; } /* advance state */
else sim_activate (uptr, dpc_xtime); /* no, wait more */
@ -376,7 +379,7 @@ case FNC_SEEK2: /* seek done */
case FNC_AR: /* arec, need cyl */
if (CMD (devd)) { /* dch active? */
rarc = DA_GETCYL (dpd_obuf); /* take cyl word */
dpc_rarc = DA_GETCYL (dpd_obuf); /* take cyl word */
setFLG (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
uptr -> FNC = FNC_AR1; } /* advance state */
@ -384,8 +387,8 @@ case FNC_AR: /* arec, need cyl */
return SCPE_OK;
case FNC_AR1: /* arec, need hd/sec */
if (CMD (devd)) { /* dch active? */
rarh = DA_GETHD (dpd_obuf); /* get head */
rars = DA_GETSC (dpd_obuf); /* get sector */
dpc_rarh = DA_GETHD (dpd_obuf); /* get head */
dpc_rars = DA_GETSC (dpd_obuf); /* get sector */
setFLG (devd); /* set dch flg */
clrCMD (devd); } /* clr dch cmd */
else { sim_activate (uptr, dpc_xtime); /* no, wait more */
@ -404,17 +407,17 @@ case FNC_STA: /* read status */
return SCPE_OK;
case FNC_REF: /* refine sector */
if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC))
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC))
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
else { for (i = 0; i < DP_NUMWD; i++) dbuf[i] = 0;
da = GETDA (rarc, rarh, rars); /* get address */
rars = rars + 1; /* incr sector */
if (rars >= DP_NUMSC) { /* end of trk? */
rars = 0; /* wrap to */
rarh = rarh ^ 1; } /* next surf */
else { for (i = 0; i < DP_NUMWD; i++) dp_buf[i] = 0;
da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */
dpc_rars = dpc_rars + 1; /* incr sector */
if (dpc_rars >= DP_NUMSC) { /* end of trk? */
dpc_rars = 0; /* wrap to */
dpc_rarh = dpc_rarh ^ 1; } /* next surf */
if (err = fseek (uptr -> fileref, da * sizeof (int16),
SEEK_SET)) break;
fxwrite (dbuf, sizeof (int16), DP_NUMWD, uptr -> fileref);
fxwrite (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref);
err = ferror (uptr -> fileref); }
break;
@ -428,40 +431,40 @@ case FNC_CHK: /* check, need cnt */
else sim_activate (uptr, dpc_xtime); /* wait more */
return SCPE_OK;
case FNC_CHK1:
if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC))
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC))
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
else { maxsc = ((2 - (rarh & 1)) * DP_NUMSC) - rars;
else { maxsc = ((2 - (dpc_rarh & 1)) * DP_NUMSC) - dpc_rars;
if (dpc_cnt > maxsc) { /* too many sec? */
dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
rarh = rarh & ~1; /* rar = 0/2, 0 */
rars = 0; }
else { i = rars + dpc_cnt; /* final sector */
rars = i % DP_NUMSC; /* reposition */
rarh = rarh ^ ((i / DP_NUMSC) & 1); } }
dpc_rarh = dpc_rarh & ~1; /* rar = 0/2, 0 */
dpc_rars = 0; }
else { i = dpc_rars + dpc_cnt; /* final sector */
dpc_rars = i % DP_NUMSC; /* reposition */
dpc_rarh = dpc_rarh ^ ((i / DP_NUMSC) & 1); } }
break; /* done */
case FNC_RD: /* read */
if (!CMD (devd)) break; /* dch clr? done */
if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR;
if (dpbptr == 0) { /* new sector? */
if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC)) {
if (dp_ptr == 0) { /* new sector? */
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) {
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
break; }
if (dpc_eoc) { /* end of cyl? */
dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
break; }
da = GETDA (rarc, rarh, rars); /* get address */
rars = rars + 1; /* incr address */
if (rars >= DP_NUMSC) { /* end of trk? */
rars = 0; /* wrap to */
rarh = rarh ^ 1; /* next cyl */
dpc_eoc = ((rarh & 1) == 0); } /* calc eoc */
da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */
dpc_rars = dpc_rars + 1; /* incr address */
if (dpc_rars >= DP_NUMSC) { /* end of trk? */
dpc_rars = 0; /* wrap to */
dpc_rarh = dpc_rarh ^ 1; /* next cyl */
dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
if (err = fseek (uptr -> fileref, da * sizeof (int16),
SEEK_SET)) break;
fxread (dbuf, sizeof (int16), DP_NUMWD, uptr -> fileref);
fxread (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break; }
dpd_ibuf = dbuf[dpbptr++]; /* get word */
if (dpbptr >= DP_NUMWD) dpbptr = 0; /* wrap if last */
dpd_ibuf = dp_buf[dp_ptr++]; /* get word */
if (dp_ptr >= DP_NUMWD) dp_ptr = 0; /* wrap if last */
setFLG (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
sim_activate (uptr, dpc_xtime); /* sched next word */
@ -472,24 +475,24 @@ case FNC_WD: /* write */
dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */
break; } /* done */
if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR;
dbuf[dpbptr++] = dpd_obuf; /* store word */
dp_buf[dp_ptr++] = dpd_obuf; /* store word */
if (!CMD (devd)) { /* dch clr? done */
for ( ; dpbptr < DP_NUMWD; dpbptr++) dbuf[dpbptr] = 0; }
if (dpbptr >= DP_NUMWD) { /* buffer full? */
if ((uptr -> CYL != rarc) || (rars >= DP_NUMSC)) {
for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dp_buf[dp_ptr] = 0; }
if (dp_ptr >= DP_NUMWD) { /* buffer full? */
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) {
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
break; }
da = GETDA (rarc, rarh, rars); /* get address */
rars = rars + 1; /* incr address */
if (rars >= DP_NUMSC) { /* end of trk? */
rars = 0; /* wrap to */
rarh = rarh ^ 1; /* next cyl */
dpc_eoc = ((rarh & 1) == 0); } /* calc eoc */
da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */
dpc_rars = dpc_rars + 1; /* incr address */
if (dpc_rars >= DP_NUMSC) { /* end of trk? */
dpc_rars = 0; /* wrap to */
dpc_rarh = dpc_rarh ^ 1; /* next cyl */
dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
if (err = fseek (uptr -> fileref, da * sizeof (int16),
SEEK_SET)) return TRUE;
fwrite (dbuf, sizeof (int16), DP_NUMWD, uptr -> fileref);
fwrite (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break;
dpbptr = 0; }
dp_ptr = 0; }
if (CMD (devd)) { /* dch active? */
setFLG (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
@ -517,7 +520,7 @@ if (dev && ((dpc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */
setFLG (dev); /* set cch flag */
clrCMD (dev); } /* clr cch cmd */
else { dpc_busy = drv + 1; /* set busy */
dpbptr = 0; /* init buf ptr */
dp_ptr = 0; /* init buf ptr */
dpc_eoc = 0; /* clear end cyl */
dpc_unit[drv].FNC = fnc; /* save function */
sim_activate (&dpc_unit[drv], time); } /* activate unit */
@ -533,12 +536,12 @@ int32 i;
dpd_ibuf = dpd_obuf = 0; /* clear buffers */
dpc_busy = dpc_obuf = 0;
dpc_eoc = 0;
dpbptr = 0;
rarc = rarh = rars = 0; /* clear rar */
dp_ptr = 0;
dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear rar */
infotab[inDPC].cmd = infotab[inDPD].cmd = 0; /* clear cmd */
infotab[inDPC].ctl = infotab[inDPD].ctl = 0; /* clear ctl */
infotab[inDPC].fbf = infotab[inDPD].fbf = 0; /* clear flg */
infotab[inDPC].flg = infotab[inDPD].flg = 0; /* clear fbf */
infotab[inDPC].fbf = infotab[inDPD].fbf = 1; /* set fbf */
infotab[inDPC].flg = infotab[inDPD].flg = 1; /* set fbf */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
sim_cancel (&dpc_unit[i]); /* cancel activity */
dpc_unit[i].FNC = 0; /* clear function */
@ -588,7 +591,7 @@ return SCPE_OK;
t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= DP_NUMWD) return SCPE_NXM;
if (vptr != NULL) *vptr = dbuf[addr] & DMASK;
if (vptr != NULL) *vptr = dp_buf[addr] & DMASK;
return SCPE_OK;
}
@ -597,6 +600,6 @@ return SCPE_OK;
t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= DP_NUMWD) return SCPE_NXM;
dbuf[addr] = val & DMASK;
dp_buf[addr] = val & DMASK;
return SCPE_OK;
}

View file

@ -25,6 +25,8 @@
lpt 12653A line printer
21-Nov-00 RMS Fixed flag, fbf power up state
Added command flop
15-Oct-00 RMS Added variable device number support
*/
@ -54,7 +56,7 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 7) },
{ FLDATA (CMD, infotab[inLPT].cmd, 0), REG_HRO },
{ FLDATA (CMD, infotab[inLPT].cmd, 0) },
{ FLDATA (CTL, infotab[inLPT].ctl, 0) },
{ FLDATA (FLG, infotab[inLPT].flg, 0) },
{ FLDATA (FBF, infotab[inLPT].fbf, 0) },
@ -102,9 +104,12 @@ case ioMIX: /* merge */
else if (sim_is_active (&lpt_unit)) dat = dat | LPT_BUSY;
break;
case ioCTL: /* control clear/set */
if (IR & AB) { clrCTL (dev); } /* CLC */
else { setCTL (dev); /* STC */
sim_activate (&lpt_unit, /* schedule completion */
if (IR & AB) { /* CLC */
clrCMD (dev); /* clear ctl, cmd */
clrCTL (dev); }
else { setCMD (dev); /* STC */
setCTL (dev); /* set ctl, cmd */
sim_activate (&lpt_unit, /* schedule op */
(lpt_unit.buf < 040)? lpt_unit.wait: lpt_ctime); }
break;
default:
@ -118,9 +123,10 @@ t_stat lpt_svc (UNIT *uptr)
int32 dev;
dev = infotab[inLPT].devno; /* get dev no */
clrCMD (dev); /* clear cmd */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
setFLG (dev); /* set flag */
setFLG (dev); /* set flag, fbf */
if (putc (lpt_unit.buf & 0177, lpt_unit.fileref) == EOF) {
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
@ -134,7 +140,7 @@ return SCPE_OK;
t_stat lpt_reset (DEVICE *dptr)
{
infotab[inLPT].cmd = infotab[inLPT].ctl = 0; /* clear cmd, ctl */
infotab[inLPT].flg = infotab[inLPT].fbf = 0; /* clear flg, fbf*/
infotab[inLPT].flg = infotab[inLPT].fbf = 1; /* set flg, fbf */
lpt_unit.buf = 0;
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;

View file

@ -25,6 +25,7 @@
mt 12559A nine track magnetic tape
30-Nov-00 RMS Made variable names unique
04-Oct-98 RMS V2.4 magtape format
Magnetic tapes are represented as a series of variable records
@ -40,6 +41,9 @@
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
Unusually among HP peripherals, the 12559 does not have a command flop,
and its flag and flag buffer power up as clear rather than set.
*/
#include "hp2100_defs.h"
@ -85,8 +89,8 @@ int32 mtc_1st = 0; /* first svc flop */
int32 mtc_ctime = 1000; /* command wait */
int32 mtc_xtime = 10; /* data xfer time */
int32 mtc_stopioe = 1; /* stop on error */
unsigned int8 dbuf[DBSIZE] = { 0 }; /* data buffer */
t_mtrlnt mtbptr = 0, mtbmax = 0; /* buffer ptrs */
unsigned int8 mt_buf[DBSIZE] = { 0 }; /* data buffer */
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
static const int32 mtc_cmd[] = {
FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM };
@ -113,8 +117,8 @@ REG mtd_reg[] = {
{ FLDATA (CTL, infotab[inMTD].ctl, 0), REG_HRO },
{ FLDATA (FLG, infotab[inMTD].flg, 0) },
{ FLDATA (FBF, infotab[inMTD].fbf, 0), REG_HRO },
{ DRDATA (BPTR, mtbptr, DB_V_SIZE + 1) },
{ DRDATA (BMAX, mtbmax, DB_V_SIZE + 1) },
{ DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },
{ DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },
{ ORDATA (DEVNO, infotab[inMTD].devno, 6), REG_RO },
{ NULL } };
@ -238,7 +242,7 @@ case ioOTX: /* output */
else { sim_activate (&mtc_unit, mtc_ctime); /* start tape */
mtc_fnc = dat; /* save function */
mtc_sta = STA_BUSY; /* unit busy */
mtbptr = 0; /* init buffer ptr */
mt_ptr = 0; /* init buffer ptr */
clrFLG (devc); /* clear flags */
clrFLG (devd);
mtc_1st = 1; /* set 1st flop */
@ -311,13 +315,13 @@ case FNC_FSR: /* space forward */
setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* update status */
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
fxread (&mtbmax, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */
feof (mtc_unit.fileref)) mtc_sta = mtc_sta | STA_EOT;
else if (mtbmax == 0) { /* zero bc? */
else if (mt_max == 0) { /* zero bc? */
mtc_sta = mtc_sta | STA_EOF; /* EOF */
mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); }
else mtc_unit.pos = mtc_unit.pos + ((MTRL (mtbmax) + 1) & ~1) +
else mtc_unit.pos = mtc_unit.pos + ((MTRL (mt_max) + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); /* update position */
break;
case FNC_BSR: /* space reverse */
@ -327,13 +331,13 @@ case FNC_BSR: /* space reverse */
mtc_sta = mtc_sta | STA_BOT; /* update status */
break; }
fseek (mtc_unit.fileref, mtc_unit.pos - sizeof (t_mtrlnt), SEEK_SET);
fxread (&mtbmax, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */
feof (mtc_unit.fileref)) mtc_unit.pos = 0;
else if (mtbmax == 0) { /* zero bc? */
else if (mt_max == 0) { /* zero bc? */
mtc_sta = mtc_sta | STA_EOF; /* EOF */
mtc_unit.pos = mtc_unit.pos - sizeof (t_mtrlnt); }
else mtc_unit.pos = mtc_unit.pos - ((MTRL (mtbmax) + 1) & ~1) -
else mtc_unit.pos = mtc_unit.pos - ((MTRL (mt_max) + 1) & ~1) -
(2 * sizeof (t_mtrlnt)); /* update position */
if (mtc_unit.pos == 0) mtc_sta = mtc_sta | STA_BOT;
break;
@ -344,30 +348,30 @@ case FNC_RC: /* read */
if (mtc_1st) { /* first svc? */
mtc_1st = 0; /* clr 1st flop */
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
fxread (&mtbmax, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
if ((err = ferror (mtc_unit.fileref)) ||
feof (mtc_unit.fileref)) { /* error or eof? */
setFLG (devc); /* set cch flg */
mtc_sta = (mtc_sta | STA_EOT) & ~STA_BUSY;
break; }
if (mtbmax == 0) { /* tape mark? */
if (mt_max == 0) { /* tape mark? */
mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt);
setFLG (devc); /* set cch flg */
mtc_sta = (mtc_sta | STA_EOF) & ~STA_BUSY;
break; }
mtbmax = MTRL (mtbmax); /* ignore errors */
mtc_unit.pos = mtc_unit.pos + ((mtbmax + 1) & ~1) +
mt_max = MTRL (mt_max); /* ignore errors */
mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); /* update position */
if ((mtbmax > DBSIZE) || (mtbmax < 12)) {
if ((mt_max > DBSIZE) || (mt_max < 12)) {
setFLG (devc); /* set cch flg */
mtc_sta = (mtc_sta | STA_PAR) & ~STA_BUSY;
break; }
i = fxread (dbuf, sizeof (int8), mtbmax, mtc_unit.fileref);
for ( ; i < mtbmax; i++) dbuf[i] = 0; /* fill with 0's */
i = fxread (mt_buf, sizeof (int8), mt_max, mtc_unit.fileref);
for ( ; i < mt_max; i++) mt_buf[i] = 0; /* fill with 0's */
err = ferror (mtc_unit.fileref); }
if (mtbptr < mtbmax) { /* more chars? */
if (mt_ptr < mt_max) { /* more chars? */
if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM;
mtc_unit.buf = dbuf[mtbptr++]; /* fetch next */
mtc_unit.buf = mt_buf[mt_ptr++]; /* fetch next */
setFLG (devd); /* set dch flg */
sim_activate (uptr, mtc_xtime); } /* re-activate */
else { setFLG (devc); /* set cch flg */
@ -376,20 +380,20 @@ case FNC_RC: /* read */
case FNC_WC: /* write */
if (mtc_dtf) { /* xfer flop set? */
if (!mtc_1st) { /* not first? */
if (mtbptr < DBSIZE) /* room in buffer? */
dbuf[mtbptr++] = mtc_unit.buf;
if (mt_ptr < DBSIZE) /* room in buffer? */
mt_buf[mt_ptr++] = mtc_unit.buf;
else mtc_sta = mtc_sta | STA_PAR; }
mtc_1st = 0; /* clr 1st flop */
setFLG (devd); /* set dch flag */
sim_activate (uptr, mtc_xtime); /* re-activate */
break; }
if (mtbptr) { /* write buffer */
if (mt_ptr) { /* write buffer */
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
fxwrite (&mtbptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
fxwrite (dbuf, sizeof (int8), mtbptr, mtc_unit.fileref);
fxwrite (&mtbptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
fxwrite (mt_buf, sizeof (int8), mt_ptr, mtc_unit.fileref);
fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
err = ferror (mtc_unit.fileref);
mtc_unit.pos = mtc_unit.pos + ((mtbptr + 1) & ~1) +
mtc_unit.pos = mtc_unit.pos + ((mt_ptr + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* update status */
@ -453,7 +457,7 @@ return SCPE_OK;
t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= DBSIZE) return SCPE_NXM;
if (vptr != NULL) *vptr = dbuf[addr] & 0377;
if (vptr != NULL) *vptr = mt_buf[addr] & 0377;
return SCPE_OK;
}
@ -462,6 +466,6 @@ return SCPE_OK;
t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= DBSIZE) return SCPE_NXM;
dbuf[addr] = val & 0377;
mt_buf[addr] = val & 0377;
return SCPE_OK;
}

View file

@ -23,22 +23,29 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ptr paper tape reader
ptp paper tape punch
tty console
clk 12639C time base generator
ptr 12597A-002 paper tape reader
ptp 12597A-005 paper tape punch
tty 12531C buffered teleprinter interface
clk 12539A/B/C time base generator
21-Nov-00 RMS Fixed flag, buffer power up state
Added status input for ptp, tty
15-Oct-00 RMS Added dynamic device number support
The reader and punch, like most HP devices, have a command flop. The
teleprinter and clock do not.
*/
#include "hp2100_defs.h"
#include <ctype.h>
#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
#define PTP_LOW 0000040 /* low tape */
#define TM_MODE 0100000 /* mode change */
#define TM_KBD 0040000 /* enable keyboard */
#define TM_PRI 0020000 /* enable printer */
#define TM_PUN 0010000 /* enable punch */
#define TP_BUSY 0100000 /* busy */
#define CLK_V_ERROR 4 /* clock overrun */
#define CLK_ERROR (1 << CLK_V_ERROR)
@ -81,7 +88,7 @@ UNIT ptr_unit = {
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (CMD, infotab[inPTR].cmd, 0), REG_HRO },
{ FLDATA (CMD, infotab[inPTR].cmd, 0) },
{ FLDATA (CTL, infotab[inPTR].ctl, 0) },
{ FLDATA (FLG, infotab[inPTR].flg, 0) },
{ FLDATA (FBF, infotab[inPTR].fbf, 0) },
@ -114,7 +121,7 @@ UNIT ptp_unit = {
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (CMD, infotab[inPTP].cmd, 0), REG_HRO },
{ FLDATA (CMD, infotab[inPTP].cmd, 0) },
{ FLDATA (CTL, infotab[inPTP].ctl, 0) },
{ FLDATA (FLG, infotab[inPTP].flg, 0) },
{ FLDATA (FBF, infotab[inPTP].fbf, 0) },
@ -243,8 +250,11 @@ case ioLIX: /* load */
dat = ptr_unit.buf;
break;
case ioCTL: /* control clear/set */
if (IR & AB) { clrCTL (dev); } /* CLC */
else { setCTL (dev); /* STC */
if (IR & AB) { /* CLC */
clrCMD (dev); /* clear cmd, ctl */
clrCTL (dev); }
else { setCMD (dev); /* STC */
setCTL (dev); /* set cmd, ctl */
sim_activate (&ptr_unit, ptr_unit.wait); }
break;
default:
@ -260,6 +270,7 @@ t_stat ptr_svc (UNIT *uptr)
int32 dev, temp;
dev = infotab[inPTR].devno; /* get device no */
clrCMD (dev); /* clear cmd */
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */
@ -280,7 +291,7 @@ return SCPE_OK;
t_stat ptr_reset (DEVICE *dptr)
{
infotab[inPTR].cmd = infotab[inPTR].ctl = 0; /* clear cmd, ctl */
infotab[inPTR].flg = infotab[inPTR].fbf = 0; /* clear flg, fbf */
infotab[inPTR].flg = infotab[inPTR].fbf = 1; /* set flg, fbf */
ptr_unit.buf = 0;
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
@ -340,13 +351,19 @@ case ioSFS: /* skip flag set */
return dat;
case ioLIX: /* load */
dat = 0;
case ioMIX: /* merge */
if ((ptp_unit.flags & UNIT_ATT) == 0)
dat = dat | PTP_LOW; /* out of tape? */
break;
case ioOTX: /* output */
ptp_unit.buf = dat;
break;
case ioCTL: /* control clear/set */
if (IR & AB) { clrCTL (dev); } /* CLC */
else { setCTL (dev); /* STC */
if (IR & AB) { /* CLC */
clrCMD (dev); /* clear cmd, ctl */
clrCTL (dev); }
else { setCMD (dev); /* STC */
setCTL (dev); /* set cmd, ctl */
sim_activate (&ptp_unit, ptp_unit.wait); }
break;
default:
@ -362,7 +379,8 @@ t_stat ptp_svc (UNIT *uptr)
int32 dev;
dev = infotab[inPTP].devno; /* get device no */
setFLG (dev); /* set device flag */
clrCMD (dev); /* clear cmd */
setFLG (dev); /* set flag */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */
@ -378,7 +396,7 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
infotab[inPTP].cmd = infotab[inPTP].ctl = 0; /* clear cmd, ctl */
infotab[inPTP].flg = infotab[inPTP].fbf = 0; /* clear flg, fbf */
infotab[inPTP].flg = infotab[inPTP].fbf = 1; /* set flg, fbf */
ptp_unit.buf = 0;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
@ -401,11 +419,12 @@ case ioSFC: /* skip flag clear */
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & AMASK;
return dat;
case ioLIX: /* load */
dat = 0;
case ioMIX: /* merge */
dat = dat | tty_buf;
break;
case ioLIX: /* load */
dat = tty_buf;
if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO]))
dat = dat | TP_BUSY;
break;
case ioOTX: /* output */
if (dat & TM_MODE) tty_mode = dat;
@ -425,33 +444,10 @@ return dat;
/* Unit service routines */
t_stat tti_svc (UNIT *uptr)
t_stat tto_out (int32 ch)
{
int32 temp, dev;
t_stat ret = SCPE_OK;
dev = infotab[inTTY].devno; /* get device no */
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
temp = temp & 0177;
if ((tty_unit[TTO].flags & UNIT_UC) && islower (temp)) /* force upper case? */
temp = toupper (temp);
if (tty_mode & TM_KBD) { /* keyboard enabled? */
tty_buf = temp; /* put char in buf */
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
setFLG (dev); /* set flag */
if (tty_mode & TM_PRI) sim_putchar (temp); } /* echo? */
return SCPE_OK;
}
t_stat tto_svc (UNIT *uptr)
{
int32 ch, ret, dev;
dev = infotab[inTTY].devno; /* get device no */
ret = SCPE_OK; /* assume ok */
setFLG (dev); /* set done flag */
ch = tty_buf;
tty_buf = 0377; /* defang buf */
if (tty_mode & TM_PRI) { /* printing? */
ret = sim_putchar (ch & 0177); /* output char */
tty_unit[TTO].pos = tty_unit[TTO].pos + 1; }
@ -466,12 +462,41 @@ if (tty_mode & TM_PUN) { /* punching? */
return ret;
}
t_stat tti_svc (UNIT *uptr)
{
int32 temp, dev;
dev = infotab[inTTY].devno; /* get device no */
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
temp = temp & 0177;
if ((tty_unit[TTI].flags & UNIT_UC) && islower (temp)) /* force upper case? */
temp = toupper (temp);
if (tty_mode & TM_KBD) { /* keyboard enabled? */
tty_buf = temp; /* put char in buf */
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
setFLG (dev); /* set flag */
return tto_out (temp); } /* echo or punch? */
return SCPE_OK;
}
t_stat tto_svc (UNIT *uptr)
{
int32 ch, dev;
dev = infotab[inTTY].devno; /* get device no */
setFLG (dev); /* set done flag */
ch = tty_buf;
tty_buf = 0377; /* defang buf */
return tto_out (ch); /* print and/or punch */
}
/* Reset routine */
t_stat tty_reset (DEVICE *dptr)
{
infotab[inTTY].cmd = infotab[inTTY].ctl = 0; /* clear cmd, ctl */
infotab[inTTY].flg = infotab[inTTY].fbf = 0; /* clear flg, fbf */
infotab[inTTY].flg = infotab[inTTY].fbf = 1; /* set flg, fbf */
tty_mode = 0;
tty_buf = 0;
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */
@ -498,6 +523,7 @@ case ioSFS: /* skip flag set */
return dat;
case ioMIX: /* merge */
dat = dat | clk_error;
break;
case ioLIX: /* load */
dat = clk_error;
break;
@ -535,7 +561,7 @@ return SCPE_OK;
t_stat clk_reset (DEVICE *dptr)
{
infotab[inCLK].cmd = infotab[inCLK].ctl = 0; /* clear cmd, ctl */
infotab[inCLK].flg = infotab[inCLK].fbf = 0; /* clear flg, fbf */
infotab[inCLK].flg = infotab[inCLK].fbf = 1; /* set flg, fbf */
clk_error = 0; /* clear error */
clk_select = 0; /* clear select */
sim_cancel (&clk_unit); /* deactivate unit */

View file

@ -1,6 +1,6 @@
/* i1401_cd.c: IBM 1402 card reader/punch
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* i1401_cpu.c: IBM 1401 CPU simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -23,6 +23,10 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
07-Dec-00 RMS Fixed bugs found by Charles Owen
-- 4,7 char NOPs are legal
-- 1 char B is chained BCE
-- MCE moves whole char after first
14-Apr-99 RMS Changed t_addr to unsigned
The register state for the IBM 1401 is:
@ -256,7 +260,7 @@ const int32 op_table[64] = {
L2 | L5, /* select stacker */
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* load */
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* move */
HNOP | L1, /* nop */
HNOP | L1 | L4 | L7, /* nop */
0, /* illegal */
L1 | L4 | L7 | AREQ | BREQ | MR, /* move to record */
L1 | L4 | AREQ | MLS, /* 50: store A addr */
@ -599,16 +603,16 @@ case OP_C: /* compare */
/* Branch instructions A check B check
B 8 char: branch if B char equals d if branch here
B 5 char: branch if indicator[d] is set if branch
B 1/8 char: branch if B char equals d if branch here
B 4 char: unconditional branch if branch
B 5 char: branch if indicator[d] is set if branch
BWZ: branch if (d<0>: B char WM) if branch here
(d<1>: B char zone = d zone)
BBE: branch if B char & d non-zero if branch here
*/
case OP_B: /* branch */
if (ilnt <= 4) { BRANCH; } /* uncond branch? */
if (ilnt == 4) { BRANCH; } /* uncond branch? */
else if (ilnt == 5) { /* branch on ind? */
if (ind[D]) { BRANCH; } /* test indicator */
if (ind_table[D]) ind[D] = 0; } /* reset if needed */
@ -783,6 +787,17 @@ case OP_RF: case OP_PF: /* read, punch feed */
qdollar EPE only; $ seen in body
qaster EPE only; * seen in body
qdecimal EPE only; . seen on first rescan
MCE operates in one to three scans, the first of which has three phases
1 right to left qbody = 0, qawm = 0 => right status
qbody = 1, qawm = 0 => body
qbody = 0, qawm = 1 => left status
2 left to right
3 right to left, extended print end only
The first A field character is masked to its digit part, all others
are copied intact
*/
case OP_MCE: /* edit */
@ -799,7 +814,17 @@ case OP_MCE: /* edit */
qawm = qzero = qbody = 0; /* clear other flags */
qdollar = qaster = qdecimal = 0; /* clear EPE flags */
/* Edit pass 1 - from right to left, under B field control */
/* Edit pass 1 - from right to left, under B field control
* in status or !epe, skip B; else, set qaster, repl with A
$ in status or !epe, skip B; else, set qdollar, repl with A
0 in right status or body, if !qzero, set A WM; set qzero, repl with A
else, if !qzero, skip B; else, if (!B WM) set B WM
blank in right status or body, repl with A; else, skip B
C,R,- in status, blank B; else, skip B
, in status, blank B, else, skip B
& blank B
*/
do { b = M[BS]; /* get B char */
M[BS] = M[BS] & ~WM; /* clr WM */
@ -818,7 +843,7 @@ case OP_MCE: /* edit */
qzero = 1; /* flag supress */
break; }
if (!qzero) t = t | WM; /* first? set WM */
qzero = 1; /* flag suppress */
qzero = 1; /* flag supress */
/* fall through */
case BCD_BLANK: /* blank */
if (qawm) break; /* any A left? */
@ -829,7 +854,7 @@ case OP_MCE: /* edit */
qawm = 1; }
else { qbody = 1; /* in body */
a = M[AS]; MM (AS); /* next A */
t = a & DIGIT; }
t = a & CHAR; }
break;
case BCD_C: case BCD_R: case BCD_MINUS: /* C, R, - */
if (!qsign && !qbody) M[BS] = BCD_BLANK;
@ -847,7 +872,7 @@ case OP_MCE: /* edit */
if (qdollar) reason = STOP_MCE3; /* error if $ */
break; }
/* Edit pass 2 - from left to right, suppressing zeroes */
/* Edit pass 2 - from left to right, supressing zeroes */
do { b = M[++BS]; /* get B char */
switch (b & CHAR) { /* case on B char */

View file

@ -1,6 +1,6 @@
/* i1401_defs.h: IBM 1401 simulator definitions
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -27,7 +27,8 @@
This simulator is based on the 1401 simulator written by Len Fehskens
with assistance from Sarah Lee Harris and Bob Supnik. This one's for
you, Len.
you, Len. I am grateful to Paul Pierce and Charles Owen for their help
in answering questions, gathering source material, and debugging.
*/
#include "sim_defs.h"

View file

@ -1,6 +1,6 @@
/* i1401_iq.c: IBM 1407 inquiry terminal
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* i1401_lp.c: IBM 1403 line printer simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* IBM 1401 magnetic tape simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt
CEO Added tape bootstrap
14-Apr-99 RMS Changed t_addr to unsigned
04-Oct-98 RMS V2.4 magtape format
@ -54,6 +56,7 @@ extern int32 BS, iochk;
extern UNIT cpu_unit;
unsigned int8 dbuf[MAXMEMSIZE * 2]; /* tape buffer */
t_stat mt_reset (DEVICE *dptr);
t_stat mt_boot (int32 unitno);
UNIT *get_unit (int32 unit);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
@ -106,9 +109,9 @@ MTAB mt_mod[] = {
DEVICE mt_dev = {
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR, 10, 31, 1, 8, 6,
MT_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, NULL, NULL };
&mt_boot, NULL, NULL };
/* Function routine
@ -266,3 +269,25 @@ t_stat mt_reset (DEVICE *dptr)
ind[IN_END] = ind[IN_PAR] = ind[IN_TAP] = 0; /* clear indicators */
return SCPE_OK;
}
/* Bootstrap routine */
#define BOOT_START 3980
#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char))
static const unsigned char boot_rom[] = {
OP_LCA + WM, BCD_PERCNT, BCD_U, BCD_ONE,
BCD_ZERO, BCD_ZERO, BCD_ONE, BCD_R, /* LDA %U1 001 R */
OP_B + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* B 001 */
OP_H + WM }; /* HALT */
t_stat mt_boot (int32 unitno)
{
int32 i;
extern int32 saved_IS;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
M[BOOT_START + 3] = unitno & 07;
saved_IS = BOOT_START;
return SCPE_OK;
}

View file

@ -42,6 +42,13 @@
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_WAIT 4 /* wait */
/* Memory */
#define MAXMEMSIZE 65536 /* max memory size */
@ -86,13 +93,6 @@
#define IDOPSW 0x48 /* int div fault old PSW */
#define IDNPSW 0x4C /* int div fault new PSW */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_WAIT 4 /* wait */
/* I/O operations */
#define IO_ADR 0x0 /* address select */
@ -123,7 +123,7 @@
#define STA_EOM 0x2 /* end of medium */
#define STA_DU 0x1 /* device unavailable */
/* Range of implemented device numbers */
/* Device numbers */
#define DEV_LOW 0x01 /* lowest intr dev */
#define DEV_MAX 0xFF /* highest intr dev */
@ -133,6 +133,9 @@
#define TT 0x02 /* teletype */
#define PT 0x03 /* paper tape */
#define CD 0x04 /* card reader */
/* I/O macros */
#define INT_V(d) (1u << ((d) & 0x1F))
#define SET_INT(d) int_req[(d)/32] = int_req[(d)/32] | INT_V (d)
#define CLR_INT(d) int_req[(d)/32] = int_req[(d)/32] & ~INT_V (d)

View file

@ -1,6 +1,6 @@
/* nova_clk.c: NOVA real-time clock simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -23,7 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
24-Sep-97 RMS Fixed bug in unit service (found by Dutch Owen)
24-Sep-97 RMS Fixed bug in unit service (found by Charles Owen)
clk real-time clock
*/
@ -35,8 +35,6 @@ int32 clk_sel = 0; /* selected freq */
int32 clk_alt_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* CLK data structures

View file

@ -23,6 +23,15 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Dec-00 RMS Added Bruce Ray's second terminal
15-Dec-00 RMS Added Charles Owen's CPU bootstrap
08-Dec-00 RMS Changes from Bruce Ray
-- fixed trap test to include Nova 3
-- fixed DIV and DIVS divide by 0
-- fixed RETN to set SP from FP
-- fixed IORST to preserve carry
-- added "secret" Nova 4 PSHN/SAVEN instructions
-- added plotter support
15-Oct-00 RMS Fixed bug in MDV test, added stack, byte, trap instructions
14-Apr-98 RMS Changed t_addr to unsigned
15-Sep-97 RMS Added read and write breakpoints
@ -57,7 +66,7 @@
010 AC2 relative direct MA = AC2 + sext (IR<8:15>)
011 AC3 relative direct MA = AC3 + sext (IR<8:15>)
100 page zero indirect MA = M[zext (IR<8:15>)]
101 PC relative dinirect MA = M[PC + sext (IR<8:15>)]
101 PC relative indirect MA = M[PC + sext (IR<8:15>)]
110 AC2 relative indirect MA = M[AC2 + sext (IR<8:15>)]
111 AC3 relative indirect MA = M[AC3 + sext (IR<8:15>)]
@ -111,6 +120,37 @@
The operate instruction can be microprogrammed to perform operations
on the source and destination AC's and the Carry flag.
Some notes from Bruce Ray:
1. DG uses the value of the autoindex location -before- the
modification to determine if additional indirect address
levels are to be performed. Most DG emulators conform to
this standard, but some vendor machines (i.e. Point 4 Mark 8)
do not.
2. Infinite indirect references may occur on unmapped systems
and can "hang" the hardware. Some DG diagnostics perform
10,000s of references during a single instruction.
3. Nova 3 adds the following instructions to the standard Nova
instruction set:
trap instructions
stack push/pop instructions
save/return instructions
stack register manipulation instructions
unsigned MUL/DIV
4. Nova 4 adds the following instructions to the Nova 3 instruction
set:
signed MUL/DIV
load/store byte
secret (undocumented) stack instructions [PSHN, SAVN]
5. Nova, Nova 3 and Nova 4 unsigned mul/div instructions are the
same instruction code values on all machines.
*/
/* This routine is the instruction decode routine for the NOVA.
@ -203,11 +243,15 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_boot (int32 unitno);
extern int32 ptr (int32 pulse, int32 code, int32 AC);
extern int32 ptp (int32 pulse, int32 code, int32 AC);
extern int32 tti (int32 pulse, int32 code, int32 AC);
extern int32 tto (int32 pulse, int32 code, int32 AC);
extern int32 tti1 (int32 pulse, int32 code, int32 AC);
extern int32 tto1 (int32 pulse, int32 code, int32 AC);
extern int32 clk (int32 pulse, int32 code, int32 AC);
extern int32 plt (int32 pulse, int32 code, int32 AC);
extern int32 lpt (int32 pulse, int32 code, int32 AC);
extern int32 dsk (int32 pulse, int32 code, int32 AC);
extern int32 dkp (int32 pulse, int32 code, int32 AC);
@ -224,7 +268,7 @@ struct ndev dev_table[64] = {
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
{ INT_TTI, PI_TTI, &tti }, { INT_TTO, PI_TTO, &tto }, /* 10 - 17 */
{ INT_PTR, PI_PTR, &ptr }, { INT_PTP, PI_PTP, &ptp },
{ INT_CLK, PI_CLK, &clk }, { 0, 0, &nulldev },
{ INT_CLK, PI_CLK, &clk }, { INT_PLT, PI_PLT, &plt },
{ 0, 0, &nulldev }, { INT_LPT, PI_LPT, &lpt },
{ INT_DSK, PI_DSK, &dsk }, { 0, 0, &nulldev }, /* 20 - 27 */
{ INT_MTA, PI_MTA, &mta }, { 0, 0, &nulldev },
@ -238,7 +282,7 @@ struct ndev dev_table[64] = {
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
{ 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 50 - 57 */
{ INT_TTI1, PI_TTI1, &tti1 }, { INT_TTO1, PI_TTO1, &tto1 }, /* 50 - 57 */
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
{ 0, 0, &nulldev }, { 0, 0, &nulldev },
@ -420,8 +464,8 @@ if (IR & I_OPR) { /* operate? */
break; } /* end switch shift */
switch (I_GETSKP (IR)) { /* decode skip */
case 0: /* nop */
if ((IR & I_NLD) && (cpu_unit.flags & UNIT_BYT)) {
register int32 indf, MA; /* Nova 4 trap */
if ((IR & I_NLD) && (cpu_unit.flags & UNIT_STK)) {
register int32 indf, MA; /* Nova 3 or 4 trap */
old_PC = M[TRP_SAV] = (PC - 1) & AMASK;
MA = TRP_JMP; /* jmp @47 */
for (i = 0, indf = 1; indf && (i < ind_max); i++) {
@ -576,6 +620,7 @@ else { /* IOT */
if (cpu_unit.flags & UNIT_BYT)
AC[dstAC] = (M[AC[pulse] >> 1] >>
((AC[pulse] & 1)? 0: 8)) & 0377;
else AC[dstAC] = 0;
break;
case ioDOA: /* stack ptr */
if (cpu_unit.flags & UNIT_STK) {
@ -584,13 +629,20 @@ else { /* IOT */
break;
case ioDIB: /* push, pop */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) {
if (pulse == iopN) { /* push */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC];
STK_CHECK (SP, 1); }
if (pulse == iopC) {
if (pulse == iopC) { /* pop */
AC[dstAC] = M[SP];
SP = DECA (SP); } }
SP = DECA (SP); }
if ((pulse == iopP) && /* Nova 4 pshn */
(cpu_unit.flags & UNIT_BYT)) {
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC];
if (SP > M[042]) int_req = int_req | INT_STK ;
}
}
break;
case ioDOB: /* store byte */
if (cpu_unit.flags & UNIT_BYT) {
@ -603,7 +655,7 @@ else { /* IOT */
break;
case ioDIC: /* save, return */
if (cpu_unit.flags & UNIT_STK) {
if (pulse == iopN) {
if (pulse == iopN) { /* save */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[0];
SP = INCA (SP);
@ -615,10 +667,11 @@ else { /* IOT */
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) |
(AC[3] & AMASK);
AC[3] = FP = SP;
AC[3] = FP = SP & AMASK;
STK_CHECK (SP, 5); }
if (pulse == iopC) {
if (pulse == iopC) { /* retn */
old_PC = PC;
SP = FP & AMASK;
C = (M[SP] << 1) & CBIT;
PC = M[SP] & AMASK;
SP = DECA (SP);
@ -630,7 +683,27 @@ else { /* IOT */
SP = DECA (SP);
AC[0] = M[SP];
SP = DECA (SP);
FP = AC[3] & AMASK; } }
FP = AC[3] & AMASK; }
if ((pulse == iopP) && /* Nova 4 saven */
(cpu_unit.flags & UNIT_BYT)) {
int32 frameSz = M[PC] ;
PC = INCA (PC) ;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[0];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[1];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = AC[2];
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = FP;
SP = INCA (SP);
if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) |
(AC[3] & AMASK);
AC[3] = FP = SP & AMASK ;
SP = (SP + frameSz) & AMASK ;
if (SP > M[042]) int_req = int_req | INT_STK;
}
}
break;
case ioDOC:
if ((dstAC == 2) && (cpu_unit.flags & UNIT_MDV)) {
@ -643,7 +716,8 @@ else { /* IOT */
AC[0] = (mddata >> 16) & DMASK;
AC[1] = mddata & DMASK; }
if (pulse == iopS) { /* div */
if (uAC0 >= uAC2) C = CBIT;
if ((uAC0 >= uAC2) || (uAC2 == 0))
C = CBIT;
else { C = 0;
mddata = (uAC0 << 16) | uAC1;
AC[1] = mddata / uAC2;
@ -656,7 +730,7 @@ else { /* IOT */
AC[0] = (mddata >> 16) & DMASK;
AC[1] = mddata & DMASK; }
if (pulse == iopN) { /* divs */
if (AC[0] == 0) C = CBIT;
if (AC[2] == 0) C = CBIT;
else { mddata = (SEXT (AC[0]) << 16) | AC[1];
AC[1] = mddata / SEXT (AC[2]);
AC[0] = mddata % SEXT (AC[2]);
@ -738,7 +812,6 @@ return;
t_stat cpu_reset (DEVICE *dptr)
{
C = 0;
int_req = int_req & ~(INT_ION | INT_STK);
pimask = 0;
dev_disable = 0;
@ -787,3 +860,56 @@ MEMSIZE = value;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}
/* Bootstrap routine for CPU */
#define BOOT_START 00000
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
0062677, /* IORST ;reset all I/O */
0060477, /* READS 0 ;read SR into AC0 */
0024026, /* LDA 1,C77 ;get dev mask */
0107400, /* AND 0,1 ;isolate dev code */
0124000, /* COM 1,1 ;- device code - 1 */
0010014, /* LOOP: ISZ OP1 ;device code to all */
0010030, /* ISZ OP2 ;I/O instructions */
0010032, /* ISZ OP3 */
0125404, /* INC 1,1,SZR ;done? */
0000005, /* JMP LOOP ;no, increment again */
0030016, /* LDA 2,C377 ;place JMP 377 into */
0050377, /* STA 2,377 ;location 377 */
0060077, /* OP1: 060077 ;start device (NIOS 0) */
00101102, /* MOVL 0,0,SZC ;test switch 0, low speed? */
0000377, /* C377: JMP 377 ;no - jmp 377 & wait */
0004030, /* LOOP2: JSR GET+1 ;get a frame */
0101065, /* MOVC 0,0,SNR ;is it non-zero? */
0000017, /* JMP LOOP2 ;no, ignore */
0004027, /* LOOP4: JSR GET ;yes, get full word */
0046026, /* STA 1,@C77 ;store starting at 100 */
/* ;2's complement of word ct */
0010100, /* ISZ 100 ;done? */
0000022, /* JMP LOOP4 ;no, get another */
0000077, /* C77: JMP 77 ;yes location ctr and */
/* ;jmp to last word */
0126420, /* GET: SUBZ 1,1 ; clr AC1, set carry */
/* OP2: */
0063577, /* LOOP3: 063577 ;done? (SKPDN 0) - 1 */
0000030, /* JMP LOOP3 ;no -- wait */
0060477, /* OP3: 060477 ;y -- read in ac0 (DIAS 0,0) */
0107363, /* ADDCS 0,1,SNC ;add 2 frames swapped - got 2nd? */
0000030, /* JMP LOOP3 ;no go back after it */
0125300, /* MOVS 1,1 ;yes swap them */
0001400, /* JMP 0,3 ;rtn with full word */
0000000 /* 0 ;padding */
};
t_stat cpu_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
return SCPE_OK;
}

View file

@ -1,4 +1,4 @@
/* nova_defs.h: NOVA simulator definitions
/* nova_defs.h: NOVA/Eclipse simulator definitions
Copyright (c) 1993-2000, Robert M. Supnik
@ -23,22 +23,40 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Dec-00 RMS Added Bruce Ray's second terminal support
10-Dec-00 RMS Added Charles Owen's Eclipse support
08-Dec-00 RMS Added Bruce Ray's plotter support
15-Oct-00 RMS Added stack, byte, trap instructions
14-Apr-99 RMS Changed t_addr to unsigned
16-Mar-95 RMS Added dynamic memory size
06-Dec-95 RMS Added magnetic tape
The author gratefully acknowledges the help of Tom West, Diana
Engelbart, and Carl Friend in resolving questions about the NOVA.
The author gratefully acknowledges the help of Tom West, Diana Englebart,
Carl Friend, Bruce Ray, and Charles Owen in resolving questions about
the NOVA.
*/
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_IND 4 /* indirect loop */
#define STOP_IND_INT 5 /* ind loop, intr */
#define STOP_IND_TRP 6 /* ind loop, trap */
/* Memory */
#if defined (ECLIPSE)
#define MAXMEMSIZE 1048576 /* max memory size */
#else
#define MAXMEMSIZE 32768 /* max memory size */
#endif
#define AMASK 077777 /* logical addr mask */
#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define AMASK (MAXMEMSIZE - 1) /* address mask */
#define A_V_IND 15 /* ind: indirect */
#define A_IND (1 << A_V_IND)
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
@ -50,6 +68,18 @@
#define CBIT (DMASK + 1) /* carry bit */
#define CMASK (CBIT | DMASK) /* carry + data */
/* Reserved memory locations */
#define INT_SAV 0 /* intr saved PC */
#define INT_JMP 1 /* intr jmp @ */
#define STK_JMP 3 /* stack jmp @ */
#define TRP_SAV 046 /* trap saved PC */
#define TRP_JMP 047 /* trap jmp @ */
#define AUTO_INC 020 /* start autoinc */
#define AUTO_DEC 030 /* start autodec */
/* Instruction format */
#define I_OPR 0100000 /* operate */
#define I_M_SRC 03 /* OPR: src AC */
#define I_V_SRC 13
@ -96,30 +126,14 @@
#define I_V_DEV 0
#define I_GETDEV(x) (((x) >> I_V_DEV) & I_M_DEV)
/* Special memory locations */
#define INT_SAV 0 /* intr saved PC */
#define INT_JMP 1 /* intr jmp @ */
#define STK_JMP 3 /* stack jmp @ */
#define TRP_SAV 046 /* trap saved PC */
#define TRP_JMP 047 /* trap jmp @ */
#define AUTO_INC 020 /* start autoinc */
#define AUTO_DEC 030 /* start autodec */
/* Instruction format */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_IND 4 /* indirect loop */
#define STOP_IND_INT 5 /* ind loop, intr */
#define STOP_IND_TRP 6 /* ind loop, trap */
#define I_M_XOP 037 /* XOP: code */
#define I_V_XOP 6
#define I_GETXOP(x) (((x) >> I_V_XOP) & I_M_XOP)
/* IOT return codes */
#define IOT_V_REASON 16 /* set reason */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* IOT fields */
@ -137,14 +151,14 @@
#define iopC 2
#define iopP 3
/* Range of implemented device numbers */
/* Device numbers */
#define DEV_LOW 010 /* lowest intr dev */
#define DEV_HIGH 033 /* highest intr dev */
#define DEV_HIGH 051 /* highest intr dev */
#define DEV_MDV 001 /* multiply/divide */
#define DEV_MAP 003 /* MMPU control */
#define DEV_ECC 002 /* ECC memory control */
#define DEV_CPU 077 /* CPU control */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* I/O structure
@ -174,11 +188,14 @@ struct ndev {
#define INT_V_CLK 7 /* clock */
#define INT_V_PTR 8 /* paper tape reader */
#define INT_V_PTP 9 /* paper tape punch */
#define INT_V_TTI 10 /* keyboard */
#define INT_V_TTO 11 /* terminal */
#define INT_V_STK 13 /* stack overflow */
#define INT_V_NO_ION_PENDING 14 /* ion delay */
#define INT_V_ION 15 /* interrupts on */
#define INT_V_PLT 10 /* plotter */
#define INT_V_TTI 11 /* keyboard */
#define INT_V_TTO 12 /* terminal */
#define INT_V_TTI1 13 /* second keyboard */
#define INT_V_TTO1 14 /* second terminal */
#define INT_V_STK 15 /* stack overflow */
#define INT_V_NO_ION_PENDING 16 /* ion delay */
#define INT_V_ION 17 /* interrupts on */
#define INT_DKP (1 << INT_V_DKP)
#define INT_DSK (1 << INT_V_DSK)
@ -187,8 +204,11 @@ struct ndev {
#define INT_CLK (1 << INT_V_CLK)
#define INT_PTR (1 << INT_V_PTR)
#define INT_PTP (1 << INT_V_PTP)
#define INT_PLT (1 << INT_V_PLT)
#define INT_TTI (1 << INT_V_TTI)
#define INT_TTO (1 << INT_V_TTO)
#define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTO1 (1 << INT_V_TTO1)
#define INT_STK (1 << INT_V_STK)
#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING)
#define INT_ION (1 << INT_V_ION)
@ -204,10 +224,12 @@ struct ndev {
#define PI_CLK 0000004
#define PI_PTR 0000020
#define PI_PTP 0000004
#define PI_PLT 0000010
#define PI_TTI 0000002
#define PI_TTO 0000001
#define PI_TTI1 PI_TTI
#define PI_TTO1 PI_TTO
/* #define PI_CDR 0000040 */
/* #define PI_DCM 0100000 */
/* #define PI_CAS 0000040 */
/* #define PI_PLT 0000010 */
/* #define PI_ADCV 0000002 */

View file

@ -25,11 +25,12 @@
dkp moving head disk
12-Dec-00 RMS Added Eclipse support from Charles Owen
15-Oct-00 RMS Editorial changes
14-Apr-99 RMS Changed t_addr to unsigned
15-Sep-97 RMS Fixed bug in DIB/DOB for new disks
15-Sep-97 RMS Fixed bug in cylinder extraction (found by Dutch Owen)
10-Sep-97 RMS Fixed bug in error reporting (found by Dutch Owen)
15-Sep-97 RMS Fixed bug in cylinder extraction (found by Charles Owen)
10-Sep-97 RMS Fixed bug in error reporting (found by Charles Owen)
25-Nov-96 RMS Defaults to autosize
29-Jun-96 RMS Added unit disable support
*/
@ -275,17 +276,18 @@ int32 dkp_fccy = 0; /* flags/cylinder */
int32 dkp_sta = 0; /* status register */
int32 dkp_swait = 100; /* seek latency */
int32 dkp_rwait = 100; /* rotate latency */
static unsigned int16 tbuf[DKP_NUMWD]; /* transfer buffer */
t_stat dkp_svc (UNIT *uptr);
t_stat dkp_reset (DEVICE *dptr);
t_stat dkp_boot (int32 unitno);
t_stat dkp_attach (UNIT *uptr, char *cptr);
t_stat dkp_go (void);
t_stat dkp_set_size (UNIT *uptr, int32 value);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
#if defined (ECLIPSE)
extern int32 MapAddr (int32 map, int32 addr);
#else
#define MapAddr(m,a) (a)
#endif
/* DKP data structures
@ -542,24 +544,16 @@ return TRUE; /* no error */
else, do read or write
If controller was busy, clear busy, set done, interrupt
NXM calculation: this takes advantage of the 4KW granularity of
memory, versus the 4KW maximum transfer size. The end address
is calculated as an absolute value; thus it may be ok, non-
existant, or greater than 32KW (wraps to first bank).
start addr end addr wc wc1
ok ok unchanged 0
ok nxm MEMSIZE-dkp_ma < 0
ok wrapped MEMSIZE-dkp_ma dkp_ma+wc mod 32K
nxm ok impossible
nxm nxm < 0 < 0
nxm wrapped < 0 dkp-ma+wc mod 32K
Memory access: sectors are read into/written from an intermediate
buffer to allow word-by-word mapping of memory addresses on the
Eclipse. This allows each word written to memory to be tested
for out of range.
*/
t_stat dkp_svc (uptr)
UNIT *uptr;
t_stat dkp_svc (UNIT *uptr)
{
int32 sc, sa, xcsa, wc, wc1, awc, bda;
int32 sc, sa, xcsa, awc, bda;
int32 sx, dx, pa;
int32 dtype, u, err, newsect, newsurf;
t_stat rval;
@ -594,35 +588,28 @@ else { sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */
if ((sa + sc) > xcsa ) { /* across cylinder? */
sc = xcsa - sa; /* limit transfer */
dkp_sta = dkp_sta | STA_XCY; } /* xcyl error */
wc = sc * DKP_NUMWD; /* convert blocks */
bda = sa * DKP_NUMWD * sizeof (short); /* to words, bytes */
if (((t_addr) (dkp_ma + wc)) <= MEMSIZE) wc1 = 0; /* xfer fit? */
else { wc = MEMSIZE - dkp_ma; /* calculate xfer */
wc1 = (dkp_ma + wc) - MAXMEMSIZE; } /* calculate wrap */
err = fseek (uptr -> fileref, bda, SEEK_SET); /* position drive */
if (uptr -> FUNC == FCCY_READ) { /* read? */
if ((wc > 0) && (err == 0)) { /* start in memory? */
awc = fxread (&M[dkp_ma], sizeof (int16), wc, uptr -> fileref);
for ( ; awc < wc; awc++) M[(dkp_ma + awc) & AMASK] = 0;
err = ferror (uptr -> fileref);
dkp_ma = (dkp_ma + wc) & AMASK; }
if ((wc1 > 0) && (err == 0)) { /* memory wrap? */
awc = fxread (&M[0], sizeof (int16), wc1, uptr -> fileref);
for ( ; awc < wc1; awc++) M[0 + awc] = 0;
err = ferror (uptr -> fileref);
dkp_ma = (dkp_ma + wc1) & AMASK; } }
for (sx = 0; sx < sc; sx++) { /* loop thru sectors */
awc = fxread (&tbuf, sizeof(uint16), DKP_NUMWD, uptr -> fileref);
for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0;
if (err = ferror (uptr -> fileref)) break;
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */
pa = MapAddr (0, dkp_ma);
if (MEM_ADDR_OK (pa)) M[pa] = tbuf[dx];
dkp_ma = (dkp_ma + 1) & AMASK; } } }
if (uptr -> FUNC == FCCY_WRITE) { /* write? */
if ((wc > 0) && (err == 0)) { /* start in memory? */
fxwrite (&M[dkp_ma], sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
dkp_ma = (dkp_ma + wc + 2) & AMASK; }
if ((wc1 > 0) && (err == 0)) { /* memory wrap? */
fxwrite (&M[0], sizeof (int16), wc1, uptr -> fileref);
err = ferror (uptr -> fileref);
dkp_ma = (dkp_ma + wc1) & AMASK; } }
for (sx = 0; sx < sc; sx++) { /* loop thru sectors */
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */
pa = MapAddr (0, dkp_ma);
tbuf[dx] = M[pa];
dkp_ma = (dkp_ma + 1) & AMASK; }
fxwrite (&tbuf, sizeof(int16), DKP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break; } }
if (err != 0) {
perror ("DKP I/O error");
@ -646,8 +633,7 @@ return rval;
/* Reset routine */
t_stat dkp_reset (dptr)
DEVICE *dptr;
t_stat dkp_reset (DEVICE *dptr)
{
int32 u;
UNIT *uptr;

View file

@ -25,6 +25,7 @@
dsk fixed head disk
10-Dec-00 RMS Added Eclipse support
15-Oct-00 RMS Editorial changes
14-Apr-99 RMS Changed t_addr to unsigned
@ -85,8 +86,11 @@ int32 dsk_time = 100; /* time per sector */
t_stat dsk_svc (UNIT *uptr);
t_stat dsk_reset (DEVICE *dptr);
t_stat dsk_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
#if defined (ECLIPSE)
extern int32 MapAddr (int32 map, int32 addr);
#else
#define MapAddr(m,a) (a)
#endif
/* DSK data structures
@ -170,8 +174,7 @@ return rval;
t_stat dsk_svc (UNIT *uptr)
{
int32 i, da;
t_addr j;
int32 i, da, pa;
dev_busy = dev_busy & ~INT_DSK; /* clear busy */
dev_done = dev_done | INT_DSK; /* set done */
@ -184,14 +187,14 @@ if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
da = dsk_da * DSK_NUMWD; /* calc disk addr */
if (uptr -> FUNC == iopS) { /* read? */
for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */
j = (dsk_ma + i) & AMASK;
if (MEM_ADDR_OK (j))
M[j] = *(((int16 *) uptr -> filebuf) + da + i); }
pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */
if (MEM_ADDR_OK (pa)) M[pa] =
*(((int16 *) uptr -> filebuf) + da + i); }
dsk_ma = (dsk_ma + DSK_NUMWD) & AMASK; }
if (uptr -> FUNC == iopP) { /* write? */
for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */
*(((int16 *) uptr -> filebuf) + da + i) =
M[(dsk_ma + i) & AMASK]; }
pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */
*(((int16 *) uptr -> filebuf) + da + i) = M[pa]; }
dsk_ma = (dsk_ma + DSK_NUMWD + 3) & AMASK; }
dsk_stat = 0; /* set status */

View file

@ -1,6 +1,6 @@
/* nova_lp.c: NOVA line printer simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -32,8 +32,6 @@ extern int32 int_req, dev_busy, dev_done, dev_disable;
int32 lpt_stopioe = 0; /* stop on error */
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* LPT data structures

View file

@ -25,7 +25,9 @@
mta magnetic tape
10-Dec-00 RMS Added Eclipse support from Charles Owen
15-Oct-00 RMS Editorial changes
11-Nov-98 CEO Removed clear of mta_ma on iopC
04-Oct-98 RMS V2.4 magtape format
18-Jan-97 RMS V2.3 magtape format
29-Jun-96 RMS Added unit disable support
@ -146,11 +148,11 @@ t_stat mta_detach (UNIT *uptr);
int32 mta_updcsta (UNIT *uptr);
void mta_upddsta (UNIT *uptr, int32 newsta);
t_stat mta_vlock (UNIT *uptr, int32 val);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
#if defined (ECLIPSE)
extern int32 MapAddr (int32 map, int32 addr);
#else
#define MapAddr(m,a) (a)
#endif
static const int ctype[32] = { /* c vs r timing */
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
@ -299,7 +301,7 @@ case iopC: /* clear */
dev_busy = dev_busy & ~INT_MTA; /* clear busy */
dev_done = dev_done & ~INT_MTA; /* clear done */
int_req = int_req & ~INT_MTA; /* clear int */
mta_sta = mta_cu = mta_ma = 0; /* clear registers */
mta_sta = mta_cu = 0; /* clear registers */
mta_updcsta (&mta_unit[0]); /* update status */
break; } /* end case pulse */
return rval;
@ -313,7 +315,7 @@ return rval;
t_stat mta_svc (UNIT *uptr)
{
int32 c, i, p, u, err;
int32 c, i, p, u, pa, err;
t_stat rval;
t_mtrlnt cbc, tbc, wc;
unsigned int16 c1, c2;
@ -377,7 +379,8 @@ case CU_READNS: /* read non-stop */
for (i = p = 0; i < wc; i++) { /* copy buf to mem */
c1 = dbuf[p++];
c2 = dbuf[p++];
if (MEM_ADDR_OK (mta_ma)) M[mta_ma] = (c1 << 8) | c2;
pa = MapAddr (0, mta_ma); /* map address */
if (MEM_ADDR_OK (pa)) M[pa] = (c1 << 8) | c2;
mta_ma = (mta_ma + 1) & AMASK; }
mta_wc = (mta_wc + wc) & DMASK;
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
@ -389,8 +392,9 @@ case CU_WRITE: /* write */
tbc = wc * 2; /* io byte count */
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
for (i = p = 0; i < wc; i++) { /* copy to buffer */
dbuf[p++] = (M[mta_ma] >> 8) & 0377;
dbuf[p++] = M[mta_ma] & 0377;
pa = MapAddr (0, mta_ma); /* map address */
dbuf[p++] = (M[pa] >> 8) & 0377;
dbuf[p++] = M[pa] & 0377;
mta_ma = (mta_ma + 1) & AMASK; }
fxwrite (dbuf, sizeof (int8), tbc, uptr -> fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);

110
nova_plt.c Normal file
View file

@ -0,0 +1,110 @@
/* nova_plt.c: NOVA plotter simulator
Copyright (c) 2000, Robert M. Supnik
Written by Bruce Ray and used with his gracious permission.
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
ROBERT M SUPNIK 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 Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "nova_defs.h"
extern int32 int_req, dev_busy, dev_done, dev_disable;
int32 plt_stopioe = 0; /* stop on error */
t_stat plt_svc (UNIT *uptr);
t_stat plt_reset (DEVICE *dptr);
/* PLT data structures
plt_dev PLT device descriptor
plt_unit PLT unit descriptor
plt_reg PLT register list
*/
UNIT plt_unit = {
UDATA (&plt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG plt_reg[] = {
{ ORDATA (BUF, plt_unit.buf, 8) },
{ FLDATA (BUSY, dev_busy, INT_V_PLT) },
{ FLDATA (DONE, dev_done, INT_V_PLT) },
{ FLDATA (DISABLE, dev_disable, INT_V_PLT) },
{ FLDATA (INT, int_req, INT_V_PLT) },
{ DRDATA (POS, plt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, plt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, plt_stopioe, 0) },
{ NULL } };
DEVICE plt_dev = {
"PLT", &plt_unit, plt_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &plt_reset,
NULL, NULL, NULL };
/* plotter: IOT routine */
int32 plt (int32 pulse, int32 code, int32 AC)
{
if (code == ioDOA) plt_unit.buf = AC & 0377;
switch (pulse) { /* decode IR<8:9> */
case iopS: /* start */
dev_busy = dev_busy | INT_PLT; /* set busy */
dev_done = dev_done & ~INT_PLT; /* clear done, int */
int_req = int_req & ~INT_PLT;
sim_activate (&plt_unit, plt_unit.wait); /* activate unit */
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_PLT; /* clear busy */
dev_done = dev_done & ~INT_PLT; /* clear done, int */
int_req = int_req & ~INT_PLT;
sim_cancel (&plt_unit); /* deactivate unit */
break; } /* end switch */
return 0;
}
/* Unit service */
t_stat plt_svc (UNIT *uptr)
{
dev_busy = dev_busy & ~INT_PLT; /* clear busy */
dev_done = dev_done | INT_PLT; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
if ((plt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (plt_stopioe, SCPE_UNATT);
if (putc (plt_unit.buf, plt_unit.fileref) == EOF) {
perror ("PLT I/O error");
clearerr (plt_unit.fileref);
return SCPE_IOERR; }
plt_unit.pos = plt_unit.pos + 1;
return SCPE_OK;
}
/* Reset routine */
t_stat plt_reset (DEVICE *dptr)
{
plt_unit.buf = 0;
dev_busy = dev_busy & ~INT_PLT; /* clear busy */
dev_done = dev_done & ~INT_PLT; /* clear done, int */
int_req = int_req & ~INT_PLT;
sim_cancel (&plt_unit); /* deactivate unit */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* nova_pt.c: NOVA paper tape read/punch simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -35,8 +35,6 @@ t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* PTR data structures

View file

@ -23,6 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Dec-00 RMS Added second terminal support
10-Dec-00 RMS Added Eclipse support
08-Dec-00 BKR Added plotter support
30-Oct-00 RMS Added support for examine to file
15-Oct-00 RMS Added stack, byte, trap instructions
14-Apr-99 RMS Changed t_addr to unsigned
@ -35,8 +38,13 @@
extern DEVICE cpu_dev;
extern UNIT cpu_unit;
#if defined (ECLIPSE)
extern DEVICE map_dev;
#endif
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE plt_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE tti1_dev, tto1_dev;
extern DEVICE clk_dev, lpt_dev;
extern DEVICE dkp_dev, dsk_dev;
extern DEVICE mta_dev;
@ -54,16 +62,28 @@ extern int32 saved_PC;
sim_load binary loader
*/
#if defined (ECLIPSE)
char sim_name[] = "ECLIPSE";
#else
char sim_name[] = "NOVA";
#endif
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = { &cpu_dev,
&ptr_dev, &ptp_dev, &tti_dev, &tto_dev,
&clk_dev, &lpt_dev, &dsk_dev, &dkp_dev,
&mta_dev, NULL };
DEVICE *sim_devices[] = {
&cpu_dev,
#if defined (ECLIPSE)
&map_dev,
#endif
&ptr_dev, &ptp_dev,
&tti_dev, &tto_dev,
&tti1_dev, &tto1_dev,
&clk_dev, &plt_dev,
&lpt_dev, &dsk_dev,
&dkp_dev, &mta_dev,
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
@ -72,7 +92,9 @@ const char *sim_stop_messages[] = {
"Breakpoint",
"Nested indirect address limit exceeded",
"Nested indirect interrupt address limit exceeded",
"Nested indirect trap address limit exceeded" };
"Nested indirect trap address limit exceeded",
"Read breakpoint",
"Write breakpoint" };
/* Binary loader
@ -175,15 +197,24 @@ return ((state == 0) || (state == 8))? SCPE_OK: SCPE_FMT;
/* Symbol tables */
#define I_V_FL 18 /* flag bits */
#define I_M_FL 07 /* flag width */
#define I_V_NPN 0 /* no operands */
#define I_V_R 1 /* reg */
#define I_V_D 2 /* device */
#define I_V_RD 3 /* reg,device */
#define I_V_M 4 /* mem addr */
#define I_V_RM 5 /* reg, mem addr */
#define I_V_RR 6 /* operate */
#define I_V_BY 7 /* byte pointer */
#define I_M_FL 037 /* flag width */
#define I_V_NPN 000 /* no operands */
#define I_V_R 001 /* reg */
#define I_V_D 002 /* device */
#define I_V_RD 003 /* reg,device */
#define I_V_M 004 /* mem addr */
#define I_V_RM 005 /* reg,mem addr */
#define I_V_RR 006 /* operate */
#define I_V_BY 007 /* Nova byte pointer */
#define I_V_2AC 010 /* reg,reg */
#define I_V_RSI 011 /* reg,short imm */
#define I_V_LI 012 /* long imm */
#define I_V_RLI 013 /* reg,long imm */
#define I_V_LM 014 /* long mem addr */
#define I_V_RLM 015 /* reg,long mem addr */
#define I_V_FRM 016 /* flt reg,long mem addr */
#define I_V_FST 017 /* flt long mem, status */
#define I_V_XP 020 /* XOP */
#define I_NPN (I_V_NPN << I_V_FL)
#define I_R (I_V_R << I_V_FL)
#define I_D (I_V_D << I_V_FL)
@ -192,14 +223,64 @@ return ((state == 0) || (state == 8))? SCPE_OK: SCPE_FMT;
#define I_RM (I_V_RM << I_V_FL)
#define I_RR (I_V_RR << I_V_FL)
#define I_BY (I_V_BY << I_V_FL)
#define I_2AC (I_V_2AC << I_V_FL)
#define I_RSI (I_V_RSI << I_V_FL)
#define I_LI (I_V_LI << I_V_FL)
#define I_RLI (I_V_RLI << I_V_FL)
#define I_LM (I_V_LM << I_V_FL)
#define I_RLM (I_V_RLM << I_V_FL)
#define I_FRM (I_V_FRM << I_V_FL)
#define I_FST (I_V_FST << I_V_FL)
#define I_XP (I_V_XP << I_V_FL)
static const int32 masks[] = {
0177777, 0163777, 0177700, 0163700,
0174000, 0160000, 0103770, 0163477 };
0174000, 0160000, 0103770, 0163477,
0103777, 0103777, 0177777, 0163777,
0176377, 0162377, 0103777, 0163777,
0100077 };
static const char *opcode[] = {
"JMP", "JSR", "ISZ", "DSZ",
"LDA", "STA",
#if defined (ECLIPSE)
"ADI", "SBI", "DAD", "DSB",
"IOR", "XOR", "ANC", "XCH",
"SGT", "SGE", "LSH", "DLSH",
"HXL", "HXR", "DHXL", "DHXR",
"BTO", "BTZ", "SBZ", "SZBO",
"LOB", "LRB", "COB", "LDB",
"STB", "PSH", "POP",
"LMP", "SYSC",
"PSHR", "POPB", "BAM", "POPJ",
"RTN", "BLM", "DIVX",
"MUL", "MULS", "DIV", "DIVS",
"SAVE", "RSTR",
"XOP",
"FAS", "FAD", "FSS", "FSD",
"FMS", "FMD", "FDS", "FDD",
"FAMS", "FAMD", "FSMS", "FSMD",
"FMMS", "FMMD", "FDMS", "FDMD",
"FLDS", "FLDD", "FSTS", "FSTD",
"FLAS", "FLMD", "FFAS", "FFMD",
"FNOM", "FRH", "FAB", "FNEG",
"FSCAL", "FEXP", "FINT", "FHLV",
"FNS", "FSA", "FSEQ", "FSNE",
"FSLT", "FSGE", "FSLE", "FSGT",
"FSNM", "FSND", "FSNU", "FSNUD",
"FSNO", "FSNOD", "FSNUO", "FSNER",
"FSST", "FLST",
"FTE", "FTD", "FCLE",
"FPSH", "FPOP",
"FCMP", "FMOV",
"CMV", "CMP", "CTR", "CMT",
"EJMP", "EJSR", "EISZ", "EDSZ",
"ELDA", "ESTA", "ELEF",
"ELDB", "ESTB", "DSPA",
"PSHJ", "CLM", "SNB",
"MSP", "XCT", "HLV",
"IORI", "XORI", "ANDI", "ADDI",
#endif
"COM", "COMZ", "COMO", "COMC",
"COML", "COMZL", "COMOL", "COMCL",
"COMR", "COMZR", "COMOR", "COMCR",
@ -266,10 +347,12 @@ static const char *opcode[] = {
"ANDS#", "ANDZS#", "ANDOS#", "ANDCS#",
"ION", "IOF",
"RDSW", "INTA", "MSKO", "IORST", "HALT",
#if !defined (ECLIPSE)
"MUL", "DIV", "MULS", "DIVS",
"PSHA", "POPA", "SAV", "RET",
"MTSP", "MTFP", "MFSP", "MFFP",
"LDB", "STB",
#endif
"NIO", "NIOS", "NIOC", "NIOP",
"DIA", "DIAS", "DIAC", "DIAP",
"DOA", "DOAS", "DOAC", "DOAP",
@ -283,6 +366,44 @@ static const char *opcode[] = {
static const opc_val[] = {
0000000+I_M, 0004000+I_M, 0010000+I_M, 0014000+I_M,
0020000+I_RM, 0040000+I_RM,
#if defined (ECLIPSE)
0100010+I_RSI, 0100110+I_RSI, 0100210+I_2AC, 0100310+I_2AC,
0100410+I_2AC, 0100510+I_2AC, 0100610+I_2AC, 0100710+I_2AC,
0101010+I_2AC, 0101110+I_2AC, 0101210+I_RSI, 0101310+I_RSI,
0101410+I_RSI, 0101510+I_RSI, 0101610+I_RSI, 0101710+I_RSI,
0102010+I_2AC, 0102110+I_2AC, 0102210+I_2AC, 0102310+I_2AC,
0102410+I_2AC, 0102510+I_2AC, 0102610+I_2AC, 0102710+I_2AC,
0103010+I_2AC, 0103110+I_2AC, 0103210+I_2AC,
0113410+I_NPN, 0103510+I_RSI,
0103710+I_NPN, 0107710+I_NPN, 0113710+I_NPN, 0117710+I_NPN,
0127710+I_NPN, 0133710+I_NPN, 0137710+I_NPN,
0143710+I_NPN, 0147710+I_NPN, 0153710+I_NPN, 0157710+I_NPN,
0163710+I_LI, 0167710+I_NPN,
0100030+I_XP,
0100050+I_2AC, 0100150+I_2AC, 0100250+I_2AC, 0100350+I_2AC,
0100450+I_2AC, 0100550+I_2AC, 0100650+I_2AC, 0100750+I_2AC,
0101050+I_FRM, 0101150+I_FRM, 0101250+I_FRM, 0101350+I_FRM,
0101450+I_FRM, 0101550+I_FRM, 0101650+I_FRM, 0101750+I_FRM,
0102050+I_FRM, 0102150+I_FRM, 0102250+I_FRM, 0102350+I_FRM,
0102450+I_2AC, 0102550+I_FRM, 0102650+I_2AC, 0102750+I_FRM,
0103050+I_R, 0123050+I_R, 0143050+I_R, 0163050+I_R,
0103150+I_R, 0123150+I_R, 0143150+I_R, 0163150+I_R,
0103250+I_NPN, 0107250+I_NPN, 0113250+I_NPN, 0117250+I_NPN,
0123250+I_NPN, 0127250+I_NPN, 0133250+I_NPN, 0137250+I_NPN,
0143250+I_NPN, 0147250+I_NPN, 0153250+I_NPN, 0157250+I_NPN,
0163250+I_NPN, 0167250+I_NPN, 0173250+I_NPN, 0177250+I_NPN,
0103350+I_FST, 0123350+I_FST,
0143350+I_NPN, 0147350+I_NPN, 0153350+I_NPN,
0163350+I_NPN, 0167350+I_NPN,
0103450+I_2AC, 0103550+I_2AC,
0153650+I_NPN, 0157650+I_NPN, 0163650+I_NPN, 0167650+I_NPN,
0102070+I_LM, 0106070+I_LM, 0112070+I_LM, 0116070+I_LM,
0122070+I_RLM, 0142070+I_RLM, 0162070+I_RLM,
0102170+I_RLM, 0122170+I_RLM, 0142170+I_RLM,
0102270+I_LM, 0102370+I_2AC, 0102770+I_2AC,
0103370+I_R, 0123370+I_R, 0143370+I_R,
0103770+I_RLI, 0123770+I_RLI, 0143770+I_RLI, 0163770+I_RLI,
#endif
0100000+I_RR, 0100020+I_RR, 0100040+I_RR, 0100060+I_RR,
0100100+I_RR, 0100120+I_RR, 0100140+I_RR, 0100160+I_RR,
0100200+I_RR, 0100220+I_RR, 0100240+I_RR, 0100260+I_RR,
@ -349,10 +470,12 @@ static const opc_val[] = {
0103710+I_RR, 0103730+I_RR, 0103750+I_RR, 0103770+I_RR,
0060177+I_NPN, 0060277+I_NPN,
0060477+I_R, 0061477+I_R, 0062077+I_R, 0062677+I_NPN, 0063077+I_NPN,
#if !defined (ECLIPSE)
0073301+I_NPN, 0073101+I_NPN, 0077201+I_NPN, 0077001+I_NPN,
0061401+I_R, 0061601+I_R, 0062401+I_NPN, 0062601+I_NPN,
0061001+I_R, 0060001+I_R, 0061201+I_R, 0060201+I_R,
0060401+I_BY, 0062001+I_BY,
#endif
0060000+I_D, 0060100+I_D, 0060200+I_D, 0060300+I_D,
0060400+I_RD, 0060500+I_RD, 0060600+I_RD, 0060700+I_RD,
0061000+I_RD, 0061100+I_RD, 0061200+I_RD, 0061300+I_RD,
@ -368,13 +491,21 @@ static const char *skip[] = {
NULL };
static const char *device[] = {
#if defined (ECLIPSE)
"ERCC", "MAP",
#endif
"TTI", "TTO", "PTR", "PTP", "RTC", "PLT", "CDR", "LPT",
"DSK", "MTA", "DCM", "ADCV", "DKP", "CAS", "CPU",
"DSK", "MTA", "DCM", "ADCV", "DKP", "CAS",
"TTI1", "TTO1", "CPU",
NULL };
static const int32 dev_val[] = {
#if defined (ECLIPSE)
002, 003,
#endif
010, 011, 012, 013, 014, 015, 016, 017,
020, 022, 024, 030, 033, 034, 077,
020, 022, 024, 030, 033, 034,
050, 051, 077,
-1 };
/* Address decode
@ -382,35 +513,41 @@ static const int32 dev_val[] = {
Inputs:
*of = output stream
addr = current PC
inst = instruction to decode
ind = indirect flag
mode = addressing mode
disp = displacement
ext = true if extended address
cflag = true if decoding for CPU
Outputs:
return = error code
*/
t_stat fprint_addr (FILE *of, t_addr addr, int32 inst, int32 cflag)
t_stat fprint_addr (FILE *of, t_addr addr, int32 ind, int32 mode,
int32 disp, t_bool ext, int32 cflag)
{
int32 disp;
int32 dsign, dmax;
if (inst & I_IND) fprintf (of, "@"); /* indirect? */
disp = I_GETDISP (inst); /* displacement */
switch (I_GETMODE (inst)) { /* mode */
case 0: /* page zero */
if (ext) dmax = AMASK + 1; /* get max disp */
else dmax = I_M_DISP + 1;
dsign = dmax >> 1; /* get disp sign */
if (ind) fprintf (of, "@"); /* indirect? */
switch (mode & 03) { /* mode */
case 0: /* absolute */
fprintf (of, "%-o", disp);
break;
case 1: /* PC rel */
if (disp & DISPSIGN) {
if (cflag) fprintf (of, "%-o", (addr + 0177400 + disp) & AMASK);
else fprintf (of, ".-%-o", 0400 - disp); }
if (disp & dsign) {
if (cflag) fprintf (of, "%-o", (addr - (dmax - disp)) & AMASK);
else fprintf (of, ".-%-o", dmax - disp); }
else { if (cflag) fprintf (of, "%-o", (addr + disp) & AMASK);
else fprintf (of, ".+%-o", disp); }
break;
case 2: /* AC2 rel */
if (disp & DISPSIGN) fprintf (of, "-%-o,2", 0400 - disp);
if (disp & dsign) fprintf (of, "-%-o,2", dmax - disp);
else fprintf (of, "%-o,2", disp);
break;
case 3: /* AC3 rel */
if (disp & DISPSIGN) fprintf (of, "-%-o,3", 0400 - disp);
if (disp & dsign) fprintf (of, "-%-o,3", dmax - disp);
else fprintf (of, "%-o,3", disp);
break; } /* end switch */
return SCPE_OK;
@ -431,7 +568,9 @@ return SCPE_OK;
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 cflag, i, j, c1, c2, inst, dv, src, dst, skp, dev, byac;
int32 cflag, i, j, c1, c2, inst, dv, src, dst, skp;
int32 ind, mode, disp, dev;
int32 byac, extind, extdisp, xop;
cflag = (uptr == NULL) || (uptr == &cpu_unit);
c1 = (val[0] >> 8) & 0177;
@ -454,7 +593,14 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
src = I_GETSRC (inst); /* opr fields */
dst = I_GETDST (inst);
skp = I_GETSKP (inst);
ind = inst & I_IND; /* mem ref fields */
mode = I_GETMODE (inst);
disp = I_GETDISP (inst);
dev = I_GETDEV (inst); /* IOT fields */
byac = I_GETPULSE (inst); /* byte fields */
xop = I_GETXOP (inst); /* XOP fields */
extind = val[1] & A_IND; /* extended fields */
extdisp = val[1] & AMASK;
for (dv = 0; (dev_val[dv] >= 0) && (dev_val[dv] != dev); dv++) ;
switch (j) { /* switch on class */
@ -476,19 +622,49 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
break;
case I_V_M: /* addr only */
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, inst, cflag);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
case I_V_RM: /* reg, addr */
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, inst, cflag);
fprint_addr (of, addr, ind, mode, disp, FALSE, cflag);
break;
case I_V_RR: /* operate */
fprintf (of, "%s %-o,%-o", opcode[i], src, dst);
if (skp) fprintf (of, ",%s", skip[skp-1]);
break;
case I_V_BY: /* byte */
byac = I_GETPULSE (inst); /* src = pulse */
fprintf (of, "%s %-o,%-o", opcode[i], byac, dst);
break;
case I_V_2AC: /* reg, reg */
fprintf (of, "%s %-o,%-o", opcode[i], src, dst);
break;
case I_V_RSI: /* reg, short imm */
fprintf (of, "%s %-o,%-o", opcode[i], src + 1, dst);
break;
case I_V_LI: /* long imm */
fprintf (of, "%s %-o", opcode[i], val[1]);
return -1;
case I_V_RLI: /* reg, long imm */
fprintf (of, "%s %-o,%-o", opcode[i], val[1], dst);
return -1;
case I_V_LM: /* long addr */
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag);
return -1;
case I_V_RLM: /* reg, long addr */
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag);
return -1;
case I_V_FRM: /* flt reg, long addr */
fprintf (of, "%s %-o,", opcode[i], dst);
fprint_addr (of, addr, extind, src, extdisp, TRUE, cflag);
return -1;
case I_V_FST: /* flt status */
fprintf (of, "%s ", opcode[i]);
fprint_addr (of, addr, extind, dst, extdisp, AMASK + 1, cflag);
return -1;
case I_V_XP: /* XOP */
fprintf (of, "%s %-o,%-o,%-o", opcode[i], src, dst, xop);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
@ -500,8 +676,9 @@ return SCPE_ARG;
Inputs:
*cptr = pointer to input string
addr = current PC
ext = extended address
cflag = true if parsing for CPU
*val = pointer to output value
val[3] = output array
Outputs:
optr = pointer to next char in input string
NULL if error
@ -514,22 +691,26 @@ return SCPE_ARG;
#define A_SI 020 /* sign seen */
#define A_MI 040 /* - seen */
char *get_addr (char *cptr, t_addr addr, int32 cflag, int32 *val)
char *get_addr (char *cptr, t_addr addr, t_bool ext, int32 cflag, int32 *val)
{
int32 d, r, x, pflag;
t_addr sd;
char gbuf[CBUFSIZE];
int32 dmax, dsign;
*val = 0; /* clear result */
d = 0; /* default no num */
x = 1; /* default PC rel */
if (ext) dmax = AMASK + 1; /* get max disp */
else dmax = I_M_DISP + 1;
dsign = dmax >> 1; /* get disp sign */
val[0] = 0; /* no indirect */
val[1] = 0; /* PC rel */
val[2] = 0; /* no addr */
pflag = cflag & A_FL; /* isolate flag */
if (*cptr == '@') { /* indirect? */
*val = I_IND;
val[0] = 1;
cptr++; }
if (*cptr == '.') { /* relative? */
pflag = pflag | A_PER;
x = 1; /* "index" is PC */
cptr++; }
if (*cptr == '+') { /* + sign? */
pflag = pflag | A_SI;
@ -541,8 +722,7 @@ if (*cptr != 0) { /* number? */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
d = get_uint (gbuf, 8, AMASK, &r);
if (r != SCPE_OK) return NULL;
pflag = pflag | A_NUM;
sd = (pflag & A_MI)? -d: d; }
pflag = pflag | A_NUM; }
if (*cptr != 0) { /* index? */
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
x = get_uint (gbuf, 8, I_M_DST, &r);
@ -551,32 +731,62 @@ if (*cptr != 0) { /* index? */
/* Address parse, continued */
switch (pflag & ~A_MI) { /* case on flags */
case A_NUM: case A_NUM+A_SI: /* ~CPU, (+/-) num */
if (sd <= I_M_DISP) *val = *val + sd;
switch (pflag) { /* case on flags */
case A_NUM: case A_NUM+A_SI: /* ~CPU, (+)num */
if (d < dmax) val[2] = d;
else return NULL;
break;
case A_NUM+A_FL: case A_NUM+A_SI+A_FL: /* CPU, (+/-) num */
if (sd <= I_M_DISP) *val = *val + sd;
else if (((sd >= ((addr - 0200) & AMASK)) &&
(sd <= ((addr + 0177) & AMASK))) ||
(sd >= (addr + 077600)))
*val = *val + 0400 + ((sd - addr) & I_M_DISP);
case A_NUM+A_FL: case A_NUM+A_SI+A_FL: /* CPU, (+)num */
if (d < dmax) val[2] = d;
else if (((d >= (((int32) addr - dsign) & AMASK)) &&
(d < (((int32) addr + dsign) & AMASK))) ||
(d >= ((int32) addr + (-dsign & AMASK)))) {
val[1] = 1; /* PC rel */
val[2] = (d - addr) & (dmax - 1); }
else return NULL;
break;
case A_PER: case A_PER+A_FL: /* .+/- num */
case A_PER+A_SI+A_NUM: case A_PER+A_SI+A_NUM+A_FL:
case A_NX+A_NUM: case A_NX+A_NUM+A_FL: /* (+/-) num, ndx */
case A_NX+A_SI+A_NUM: case A_NX+A_SI+A_NUM+A_FL:
if (((pflag & A_MI) == 0) && (d <= 0177)) *val = *val + (x << 8) + d;
else if ((pflag & A_MI) && (d <= 0200))
*val = *val + (x << 8) + 0400 - d;
case A_PER: case A_PER+A_FL: /* . */
case A_PER+A_SI+A_NUM: case A_PER+A_SI+A_NUM+A_FL: /* . + num */
case A_PER+A_SI+A_MI+A_NUM: /* . - num */
case A_PER+A_SI+A_MI+A_NUM+A_FL:
case A_NX+A_NUM: case A_NX+A_NUM+A_FL: /* num, ndx */
case A_NX+A_SI+A_NUM: case A_NX+A_SI+A_NUM+A_FL: /* +num, ndx */
case A_NX+A_SI+A_MI+A_NUM: /* -num, ndx */
case A_NX+A_SI+A_MI+A_NUM+A_FL:
val[1] = x; /* set mode */
if (((pflag & A_MI) == 0) && (d < dsign)) val[2] = d;
else if ((pflag & A_MI) && (d <= dsign)) val[2] = (dmax - d);
else return NULL;
break;
default:
return NULL; } /* end case */
return cptr;
}
/* Parse two registers
Inputs:
*cptr = input string
term = second terminating character
val = output array
Outputs:
optr = pointer to next char in input string
NULL if error
*/
char *get_2reg (char *cptr, char term, int32 *val)
{
char gbuf[CBUFSIZE];
t_stat r;
cptr = get_glyph (cptr, gbuf, ','); /* get register */
val[0] = get_uint (gbuf, 8, I_M_SRC, &r);
if (r != SCPE_OK) return NULL;
cptr = get_glyph (cptr, gbuf, term); /* get register */
val[1] = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return NULL;
return cptr;
}
/* Symbolic input
@ -592,8 +802,8 @@ return cptr;
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 cflag, d, i, j;
t_stat r;
int32 cflag, d, i, j, amd[3];
t_stat r, rtn;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
@ -609,6 +819,7 @@ if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
/* Instruction parse */
rtn = SCPE_OK; /* assume 1 word */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
@ -638,24 +849,20 @@ case I_V_D: /* IOT dev */
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DEV); }
break;
case I_V_RM: /* mem reg,addr */
case I_V_RM: /* reg, addr */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
case I_V_M:
if ((cptr = get_addr (cptr, addr, cflag, &d)) == NULL) return SCPE_ARG;
val[0] = val[0] | d;
case I_V_M: /* addr */
cptr = get_addr (cptr, addr, FALSE, cflag, amd);
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_IND) | (amd[1] << I_V_MODE) | amd[2];
break;
case I_V_RR: /* operate */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_SRC, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_SRC); /* put in place */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
cptr = get_2reg (cptr, ',', amd); /* get 2 reg */
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST);
if (*cptr != 0) { /* skip? */
cptr = get_glyph (cptr, gbuf, 0); /* get skip */
for (i = 0; (skip[i] != NULL) &&
@ -664,15 +871,80 @@ case I_V_RR: /* operate */
val[0] = val[0] | (i + 1); } /* end for */
break;
case I_V_BY: /* byte */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_PULSE, &r);
cptr = get_2reg (cptr, 0, amd); /* get 2 reg */
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_PULSE) | (amd[1] << I_V_DST);
break;
case I_V_2AC: /* reg, reg */
cptr = get_2reg (cptr, 0, amd); /* get 2 reg */
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST);
break;
case I_V_RSI: /* reg, short imm */
cptr = get_glyph (cptr, gbuf, ','); /* get immediate */
d = get_uint (gbuf, 8, I_M_SRC + 1, &r);
if ((d == 0) || (r != SCPE_OK)) return SCPE_ARG;
val[0] = val[0] | ((d - 1) << I_V_SRC); /* put in place */
cptr = get_glyph (cptr, gbuf, 0); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_PULSE); /* put in place */
val[0] = val[0] | (d << I_V_DST); /* put in place */
break;
case I_V_RLI: /* reg, long imm */
cptr = get_glyph (cptr, gbuf, ','); /* get immediate */
val[1] = get_uint (gbuf, 8, DMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, 0); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
rtn = -1;
break;
case I_V_LI: /* long imm */
cptr = get_glyph (cptr, gbuf, 0); /* get immediate */
val[1] = get_uint (gbuf, 8, DMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
rtn = -1;
break;
case I_V_RLM: /* reg, long mem */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
case I_V_LM: /* long mem */
cptr = get_addr (cptr, addr, TRUE, cflag, amd);
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[1] << I_V_MODE);
val[1] = (amd[0] << A_V_IND) | amd[2];
rtn = -1;
break;
case I_V_FRM: /* flt reg, long mem */
cptr = get_glyph (cptr, gbuf, ','); /* get register */
d = get_uint (gbuf, 8, I_M_DST, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_DST); /* put in place */
cptr = get_addr (cptr, addr, TRUE, cflag, amd);
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[1] << I_V_SRC);
val[1] = (amd[0] << A_V_IND) | amd[2];
rtn = -1;
break;
case I_V_FST: /* flt status */
cptr = get_addr (cptr, addr, TRUE, cflag, amd);
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[1] << I_V_DST);
val[1] = (amd[0] << A_V_IND) | amd[2];
rtn = -1;
break;
case I_V_XP: /* XOP */
cptr = get_2reg (cptr, ',', amd); /* get 2 reg */
if (cptr == NULL) return SCPE_ARG;
val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST);
cptr = get_glyph (cptr, gbuf, 0); /* get argument */
d = get_uint (gbuf, 8, I_M_XOP, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << I_V_XOP);
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* any leftovers? */
return SCPE_OK;
return rtn;
}

View file

@ -1,6 +1,6 @@
/* nova_tt.c: NOVA console terminal simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -37,8 +37,6 @@ t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ttx_setmod (UNIT *uptr, int32 value);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);

245
nova_tt1.c Normal file
View file

@ -0,0 +1,245 @@
/* nova_tt1.c: NOVA second terminal simulator
Copyright (c) 1993-2000, Robert M. Supnik
Written by Bruce Ray and used with his gracious permission.
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
ROBERT M SUPNIK 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 Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
tti1 second terminal input
tto1 second terminal output
*/
#include "nova_defs.h"
#define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */
#define UNIT_DASHER (1 << UNIT_V_DASHER)
extern int32 int_req, dev_busy, dev_done, dev_disable;
int32 tti1_stopioe = 0, tto1_stopioe = 0; /* stop on error */
t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr);
t_stat tto1_reset (DEVICE *dptr);
t_stat tti1_attach (UNIT *uptr, char *ptr);
t_stat tti1_detach (UNIT *uptr);
t_stat ttx1_setmod (UNIT *uptr, int32 value);
/* TTI1 data structures
tti1_dev TTI1 device descriptor
tti1_unit TTI1 unit descriptor
tti1_reg TTI1 register list
ttx1_mod TTI1/TTO1 modifiers list
*/
UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_SEQ+UNIT_ATTABLE, 0), KBD_POLL_WAIT };
REG tti1_reg[] = {
{ ORDATA (BUF, tti1_unit.buf, 8) },
{ FLDATA (BUSY, dev_busy, INT_V_TTI1) },
{ FLDATA (DONE, dev_done, INT_V_TTI1) },
{ FLDATA (DISABLE, dev_disable, INT_V_TTI1) },
{ FLDATA (INT, int_req, INT_V_TTI1) },
{ DRDATA (POS, tti1_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, tti1_stopioe, 0) },
{ FLDATA (MODE, tti1_unit.flags, UNIT_V_DASHER), REG_HRO },
{ NULL } };
MTAB ttx1_mod[] = {
{ UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod },
{ UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod },
{ 0 } };
DEVICE tti1_dev = {
"TTI1", &tti1_unit, tti1_reg, ttx1_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti1_reset,
NULL, &tti1_attach, &tti1_detach };
/* TTO1 data structures
tto1_dev TTO1 device descriptor
tto1_unit TTO1 unit descriptor
tto1_reg TTO1 register list
*/
UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG tto1_reg[] = {
{ ORDATA (BUF, tto1_unit.buf, 8) },
{ FLDATA (BUSY, dev_busy, INT_V_TTO1) },
{ FLDATA (DONE, dev_done, INT_V_TTO1) },
{ FLDATA (DISABLE, dev_disable, INT_V_TTO1) },
{ FLDATA (INT, int_req, INT_V_TTO1) },
{ DRDATA (POS, tto1_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, tto1_stopioe, 0) },
{ FLDATA (MODE, tto1_unit.flags, UNIT_V_DASHER), REG_HRO },
{ NULL } };
DEVICE tto1_dev = {
"TTO1", &tto1_unit, tto1_reg, ttx1_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto1_reset,
NULL, NULL, NULL };
/* Terminal input: IOT routine */
int32 tti1 (int32 pulse, int32 code, int32 AC)
{
int32 iodata;
iodata = (code == ioDIA)? tti1_unit.buf & 0377: 0;
switch (pulse) { /* decode IR<8:9> */
case iopS: /* start */
dev_busy = dev_busy | INT_TTI1; /* set busy */
dev_done = dev_done & ~INT_TTI1; /* clear done, int */
int_req = int_req & ~INT_TTI1;
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_TTI1; /* clear busy */
dev_done = dev_done & ~INT_TTI1; /* clear done, int */
int_req = int_req & ~INT_TTI1;
break; } /* end switch */
return iodata;
}
/* Unit service */
t_stat tti1_svc (UNIT *uptr)
{
int32 temp;
if ((tti1_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (tti1_stopioe, SCPE_UNATT);
sim_activate (&tti1_unit, tti1_unit.wait); /* continue poll */
if ((temp = getc (tti1_unit.fileref)) == EOF) { /* end of file? */
if (feof (tti1_unit.fileref)) {
if (tti1_stopioe) printf ("TTI1 end of file\n");
else return SCPE_OK; }
else perror ("TTI1 input error");
clearerr (tti1_unit.fileref);
return SCPE_IOERR; }
tti1_unit.buf = temp & 0177;
if ((tti1_unit.flags & UNIT_DASHER) && (tti1_unit.buf == '\r'))
tti1_unit.buf = '\n'; /* Dasher: cr -> nl */
dev_busy = dev_busy & ~INT_TTI1; /* clear busy */
dev_done = dev_done | INT_TTI1; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
tti1_unit.pos = tti1_unit.pos + 1;
return SCPE_OK;
}
/* Reset routine */
t_stat tti1_reset (DEVICE *dptr)
{
tti1_unit.buf = 0;
dev_busy = dev_busy & ~INT_TTI1; /* clear busy */
dev_done = dev_done & ~INT_TTI1; /* clear done, int */
int_req = int_req & ~INT_TTI1;
if (tti1_unit.flags & UNIT_ATT) /* attached? */
sim_activate (&tti1_unit, tti1_unit.wait);
else sim_cancel (&tti1_unit);
return SCPE_OK;
}
/* Attach routine */
t_stat tti1_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
if (reason == SCPE_OK) sim_activate (uptr, uptr -> wait);
return reason;
}
/* Detach routine */
t_stat tti1_detach (UNIT *uptr)
{
sim_cancel (uptr);
return detach_unit (uptr);
}
/* Terminal output: IOT routine */
int32 tto1 (int32 pulse, int32 code, int32 AC)
{
if (code == ioDOA) tto1_unit.buf = AC & 0377;
switch (pulse) { /* decode IR<8:9> */
case iopS: /* start */
dev_busy = dev_busy | INT_TTO1; /* set busy */
dev_done = dev_done & ~INT_TTO1; /* clear done, int */
int_req = int_req & ~INT_TTO1;
sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_TTO1; /* clear busy */
dev_done = dev_done & ~INT_TTO1; /* clear done, int */
int_req = int_req & ~INT_TTO1;
sim_cancel (&tto1_unit); /* deactivate unit */
break; } /* end switch */
return 0;
}
/* Unit service */
t_stat tto1_svc (UNIT *uptr)
{
int32 c ;
dev_busy = dev_busy & ~INT_TTO1; /* clear busy */
dev_done = dev_done | INT_TTO1; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
if ((tto1_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (tto1_stopioe, SCPE_UNATT);
c = tto1_unit.buf & 0177;
if ((tto1_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b';
if (putc (c, tto1_unit.fileref) == EOF) {
perror ("TTO1 output error");
clearerr (tto1_unit.fileref);
return SCPE_IOERR; }
tto1_unit.pos = tto1_unit.pos + 1;
return SCPE_OK;
}
/* Reset routine */
t_stat tto1_reset (DEVICE *dptr)
{
tto1_unit.buf = 0;
dev_busy = dev_busy & ~INT_TTO1; /* clear busy */
dev_done = dev_done & ~INT_TTO1; /* clear done, int */
int_req = int_req & ~INT_TTO1;
sim_cancel (&tto1_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx1_setmod (UNIT *uptr, int32 value)
{
tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | value;
tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | value;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp11_cis.c: PDP-11 CIS optional instruction set simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* pdp11_cpu.c: PDP-11 CPU simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* pdp11_defs.h: PDP-11 simulator definitions
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),
@ -30,7 +30,7 @@
#include "sim_defs.h" /* simulator defns */
#include <setjmp.h>
/* Constants */
/* Architectural constants */
#define STKLIM 0400 /* stack limit */
#define VASIZE 0200000 /* 2**16 */
@ -168,15 +168,6 @@ typedef struct fpac fpac_t;
#define CSR_BUSY (1u << CSR_V_BUSY)
#define CSR_ERR (1u << CSR_V_ERR)
/* Simulator stop codes; codes 1:TRAP_V_MAX correspond to traps 0:TRAPMAX-1 */
#define STOP_HALT TRAP_V_MAX + 1 /* HALT instruction */
#define STOP_IBKPT TRAP_V_MAX + 2 /* instruction bkpt */
#define STOP_WAIT TRAP_V_MAX + 3 /* wait, no events */
#define STOP_VECABORT TRAP_V_MAX + 4 /* abort vector read */
#define STOP_SPABORT TRAP_V_MAX + 5 /* abort trap push */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
/* Trap masks, descending priority order, following J-11
An interrupt summary bit is kept with traps, to minimize overhead
*/
@ -231,6 +222,15 @@ typedef struct fpac fpac_t;
#define VEC_PWRFL 0024
#define VEC_FPE 0244
/* Simulator stop codes; codes 1:TRAP_V_MAX correspond to traps 0:TRAPMAX-1 */
#define STOP_HALT TRAP_V_MAX + 1 /* HALT instruction */
#define STOP_IBKPT TRAP_V_MAX + 2 /* instruction bkpt */
#define STOP_WAIT TRAP_V_MAX + 3 /* wait, no events */
#define STOP_VECABORT TRAP_V_MAX + 4 /* abort vector read */
#define STOP_SPABORT TRAP_V_MAX + 5 /* abort trap push */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
/* Interrupt assignments, priority is right to left
<3:0> = BR7, <3> = PIR7

View file

@ -1,6 +1,6 @@
/* pdp11_fp.c: PDP-11 floating point simulator (32b version)
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* RK11 cartridge disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* RL11 (RLV12) cartridge disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* pdp11_rp.c - RP04/05/06/07 RM02/03/05/80 "Massbus style" disk controller
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* pdp11_rx.c: RX11/RX01 floppy disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* PDP-11 magnetic tape simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* pdp18b_cpu.c: 18b PDP CPU simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),
@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
18-Dec-00 RMS Added PDP-9,-15 memm init register
30-Nov-00 RMS Fixed numerous PDP-15 bugs
14-Apr-99 RMS Changed t_addr to unsigned
The 18b PDP family has five distinct architectural variants: PDP-1,
@ -251,7 +253,12 @@ int32 int_req = 0; /* int requests */
int32 iors = 0; /* IORS */
int32 ion = 0; /* int on */
int32 ion_defer = 0; /* int defer */
int32 memm = 0; /* ext mem mode */
int32 memm = 0; /* mem mode */
#if defined (PDP15)
int32 memm_init = 1; /* mem init */
#else
int32 memm_init = 0;
#endif
int32 usmd = 0; /* user mode */
int32 usmdbuf = 0; /* user mode buffer */
int32 trap_pending = 0; /* trap pending */
@ -316,6 +323,7 @@ REG cpu_reg[] = {
{ FLDATA (PRVN, prvn, 0) },
{ FLDATA (TRAPP, trap_pending, 0) },
{ FLDATA (EXTM, memm, 0) },
{ FLDATA (EXTM_INIT, memm_init, 0) },
{ FLDATA (EMIRP, emir_pending, 0) },
{ FLDATA (RESTP, rest_pending, 0) },
{ FLDATA (PWRFL, int_req, INT_V_PWRFL) },
@ -329,6 +337,7 @@ REG cpu_reg[] = {
{ FLDATA (USMD, usmd, 0) },
{ FLDATA (USMDBUF, usmdbuf, 0) },
{ FLDATA (BANKM, memm, 0) },
{ FLDATA (BANKM_INIT, memm_init, 0) },
{ FLDATA (RESP, rest_pending, 0) },
{ FLDATA (PWRFL, int_req, INT_V_PWRFL) },
#endif
@ -344,8 +353,9 @@ MTAB cpu_mod[] = {
#if !defined (PDP4)
{ UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL },
{ UNIT_NOEAE, 0, "EAE", "EAE", NULL },
#endif
#else
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
#endif
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
#if (MAXMEMSIZE > 8192)
{ UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
@ -436,7 +446,8 @@ if (sim_interval <= 0) { /* check clock queue */
/* Protection traps work like interrupts, with these quirks:
PDP-7 extend mode forced on, M[0] = PC, PC = 2
PDP-9, PDP-15 extend/bank mode forced off, M[0/20] = PC, PC = 0/21
PDP-9 extend mode ???, M[0/20] = PC, PC = 0/21
PDP-15 bank mode unchanged, M[0/20] = PC, PC = 0/21
*/
#if defined (PDP7)
@ -448,16 +459,23 @@ if (trap_pending) { /* trap pending? */
memm = 1; /* extend on */
emir_pending = trap_pending = 0; /* emir, trap off */
usmd = 0; } /* protect off */
#endif
#if defined (PDP9) || defined (PDP15)
#elif defined (PDP9)
if (trap_pending) { /* trap pending? */
old_PC = PC; /* save old PC */
MA = ion? 0: 020; /* save in 0 or 20 */
M[MA] = JMS_WORD (1); /* save state */
PC = MA + 1; /* fetch next */
ion = 0; /* interrupts off */
/*??? memm = 0; /* extend off */
emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */
usmd = 0; } /* protect off */
#elif defined (PDP15)
if (trap_pending) { /* trap pending? */
old_PC = PC; /* save old PC */
MA = ion? 0: 020; /* save in 0 or 20 */
M[MA] = JMS_WORD (1); /* save state */
PC = MA + 1; /* fetch next */
ion = 0; /* interrupts off */
memm = 0; /* extend/bank off */
emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */
usmd = 0; } /* protect off */
#endif
@ -467,7 +485,9 @@ if (ion && !ion_defer && int_req) { /* interrupt? */
M[0] = JMS_WORD (usmd); /* save state */
PC = 1; /* fetch next from 1 */
ion = 0; /* interrupts off */
memm = 0; /* extend/bank off */
#if !defined (PDP15) /* except PDP-15, */
memm = 0; /* extend off */
#endif
emir_pending = rest_pending = 0; /* emir, restore off */
usmd = 0; } /* protect off */
@ -561,7 +581,9 @@ if (PC == ibkpt_addr) { /* breakpoint? */
memm = (M[MA] >> 16) & 1; \
usmd = (M[MA] >> 15) & 1; } \
MA = ((IR & damask & ~07) != 00010)? \
(PC & BLKMASK) | (M[MA] & IAMASK): (M[MA] & ADDRMASK)
(PC & BLKMASK) | (M[MA] & IAMASK): (M[MA] & ADDRMASK); \
damask = memm? 017777: 07777; \
epcmask = ADDRMASK & ~damask
#define CHECK_INDEX \
if ((IR & 0010000) && (memm == 0)) MA = (MA + XR) & ADDRMASK
#define CHECK_ADDR_R(x) \
@ -580,8 +602,9 @@ if (PC == ibkpt_addr) { /* breakpoint? */
/* Fetch, decode instruction */
CHECK_ADDR_R (PC); /* validate PC */
IR = M[PC]; /* fetch instruction */
MA = PC; /* fetch at PC */
CHECK_ADDR_R (MA); /* validate addr */
IR = M[MA]; /* fetch instruction */
PC = INCR_ADDR (PC); /* increment PC */
#if defined (PDP9) || defined (PDP15)
if (!ion_defer) usmd = usmdbuf; /* no IOT? load usmd */
@ -591,7 +614,7 @@ xct_count = 0; /* track nested XCT's */
sim_interval = sim_interval - 1;
xct_instr: /* label for XCT */
MA = (PC & epcmask) | (IR & damask); /* effective address */
MA = (MA & epcmask) | (IR & damask); /* effective address */
switch ((IR >> 13) & 037) { /* decode IR<0:4> */
/* LAC: opcode 20 */
@ -767,7 +790,8 @@ case 031: /* JMP, indir */
CHECK_AUTO_INC; /* check auto inc */
#if defined (PDP7) || defined (PDP9)
if (emir_pending && (((M[MA] >> 16) & 1) == 0)) memm = 0;
#elif defined (PDP9)
#endif
#if defined (PDP9)
if (rest_pending) { /* restore pending? */
LAC = ((M[MA] << 1) & 01000000) | (LAC & 0777777);
memm = (M[MA] >> 16) & 1;
@ -1069,14 +1093,18 @@ case 035: /* index operates */
#if defined (PDP15)
t = (IR & 0400)? IR | 0777000: IR & 0377; /* sext immediate */
switch ((IR >> 9) & 017) { /* case on IR<5:8> */
case 000: /* AAS */
LAC = (LAC & 01000000) | ((LAC + t) & 0777777);
if (SEXT (LAC & 0777777) >= SEXT (LR))
PC = INCR_ADDR (PC);
case 001: /* PAX */
XR = LAC & 0777777;
break;
case 002: /* PAL */
LR = LAC & 0777777;
break;
case 003:
LAC = (LAC & 01000000) | ((LAC + t) & 0777777); /* AAC */
case 003: /* AAC */
LAC = (LAC & 01000000) | ((LAC + t) & 0777777);
break;
case 004: /* PXA */
LAC = (LAC & 01000000) | XR;
@ -1094,10 +1122,13 @@ case 035: /* index operates */
case 011: /* PLX */
XR = LR;
break;
case 014: /* CLAC */
LAC = LAC & 01000000;
break;
case 015: /* CLX */
XR = 0;
break;
case 016: /* CLL */
case 016: /* CLLR */
LR = 0;
break;
case 017: /* AXR */
@ -1251,6 +1282,8 @@ case 034: /* IOT */
else if (pulse == 042) rest_pending = 1; /* RES */
else if (pulse == 062) memm = 0; /* DBA */
else if (pulse == 064) memm = 1; /* EBA */
damask = memm? 017777: 07777; /* set dir addr mask */
epcmask = ADDRMASK & ~damask; /* extended PC mask */
break;
#endif
@ -1335,7 +1368,8 @@ eae_ac_sign = 0;
ion = ion_defer = 0;
int_req = int_req & ~INT_PWRFL;
BR = 0;
memm = usmd = usmdbuf = 0;
usmd = usmdbuf = 0;
memm = memm_init;
nexm = prvn = trap_pending = 0;
emir_pending = rest_pending = 0;
return cpu_svc (&cpu_unit);

View file

@ -1,6 +1,6 @@
/* pdp18b_defs.h: 18b PDP simulator definitions
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),
@ -29,7 +29,8 @@
19-Mar-95 RMS Added dynamic memory size
The author gratefully acknowledges the help of Craig St. Clair and
Deb Tevonian in locating archival material about the 18b PDP's
Deb Tevonian in locating archival material about the 18b PDP's, and of
Al Kossow and Max Burnet in making documentation and software available.
*/
#include "sim_defs.h" /* simulator defns */
@ -74,7 +75,14 @@
#define PDP9 0 /* default to PDP-9 */
#endif
/* Memory and peripheral configuration */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_XCT 4 /* nested XCT's */
/* Peripheral configuration */
#if defined (PDP4)
#define ADDRSIZE 13
@ -95,21 +103,23 @@
#define RF 0 /* fixed head disk */
#define RP 0 /* disk pack */
#define MTA 0 /* magtape */
#define BLKMASK 0300000 /* block mask */
#endif
/* Memory */
#define ADDRMASK ((1 << ADDRSIZE) - 1) /* address mask */
#define IAMASK 077777 /* ind address mask */
#define BLKMASK (ADDRMASK & (~IAMASK)) /* block mask */
#define MAXMEMSIZE (1 << ADDRSIZE) /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Simulator stop codes */
/* Architectural constants */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_XCT 4 /* nested XCT's */
#define DMASK 0777777 /* data mask */
#define LINK (DMASK + 1) /* link */
#define LACMASK (LINK | DMASK) /* link + data */
#define SIGN 0400000 /* sign bit */
/* IOT subroutine return codes */

View file

@ -1,6 +1,6 @@
/* pdp18b_drm.c: drum/fixed head disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -399,8 +399,6 @@ char lpt_buf[LPT_BSIZE] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_detach (UNIT *uptr);
int32 lpt_updsta (int32 new);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
@ -434,7 +432,7 @@ DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, &lpt_detach };
NULL, NULL, NULL };
/* LP15 line printer: IOT routines */
@ -463,7 +461,7 @@ return AC;
int32 lpt66 (int32 pulse, int32 AC)
{
if (pulse == 021) lpt_sta = lpt_sta & ~STA_DON; /* LPCD */
if (pulse == 041) lpt_sta = lpt_sta & STA_ALM; /* LPCF */
if (pulse == 041) lpt_sta = lpt_sta = 0; /* LPCF */
lpt_updsta (0); /* update status */
return AC;
}
@ -540,8 +538,7 @@ t_stat lpt_reset (DEVICE *dptr)
{
mode = lcnt = bptr = 0; /* clear controls */
sim_cancel (&lpt_unit); /* deactivate unit */
if (lpt_unit.flags & UNIT_ATT) lpt_sta = 0;
else lpt_sta = STA_ALM;
lpt_sta = 0; /* clear status */
lpt_ie = 1; /* enable interrupts */
lpt_updsta (0); /* update status */
return SCPE_OK;
@ -554,23 +551,4 @@ int32 lpt_iors (void)
return ((lpt_sta & STA_DON)? IOS_LPT: 0);
}
/* Attach routine */
t_stat lpt_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
if (lpt_unit.flags & UNIT_ATT) lpt_sta = lpt_sta & ~STA_ALM;
lpt_updsta (0);
return reason;
}
/* Detach routine */
t_stat lpt_detach (UNIT *uptr)
{
lpt_updsta (STA_ALM);
return detach_unit (uptr);
}
#endif

View file

@ -1,6 +1,6 @@
/* 18b PDP magnetic tape simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -1,6 +1,6 @@
/* pdp18b_rf.c: fixed head disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),
@ -26,6 +26,7 @@
rf RF09/RF09 for PDP-9
RF15/RS09 for PDP-15
30-Nov-99 RMS Added non-zero requirement to rf_time
14-Apr-99 RMS Changed t_addr to unsigned
The RFxx is a head-per-track disk. It uses the multicycle data break
@ -33,7 +34,7 @@
Two timing parameters are provided:
rf_time Interword timing. If 0, treated as 1.
rf_time Interword timing. Must be non-zero.
rf_burst Burst mode. If 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst.
*/
@ -76,9 +77,8 @@
#define RFS_CLR 0000170 /* always clear */
#define RFS_EFLGS (RFS_HDW | RFS_APE | RFS_MXF | RFS_WCE | \
RFS_DPE | RFS_WLO | RFS_NED ) /* error flags */
#define MIN_TIME(x) ((x > 0)? (x): 1)
#define GET_FNC(x) (((x) >> RFS_V_FNC) & RFS_M_FNC)
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (MIN_TIME(x))), \
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) RF_NUMWD)))
#define RF_BUSY (sim_is_active (&rf_unit))
@ -125,7 +125,7 @@ REG rf_reg[] = {
{ ORDATA (WLK5, rf_wlk[5], 16) },
{ ORDATA (WLK6, rf_wlk[6], 16) },
{ ORDATA (WLK7, rf_wlk[7], 16) },
{ DRDATA (TIME, rf_time, 24), PV_LEFT },
{ DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ NULL } };
@ -232,7 +232,7 @@ do { pa = M[RF_MA] = (M[RF_MA] + 1) & ADDRMASK; /* incr mem addr */
while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
sim_activate (&rf_unit, MIN_TIME (rf_time)); /* sched next */
sim_activate (&rf_unit, rf_time); /* sched next */
else rf_updsta (RFS_DON);
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* RP15/RP02 disk pack simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Dec-00 RMS Added PDP-9/15 half duplex support
30-Nov-00 RMS Fixed PDP-4/7 bootstrap loader for 4K systems
30-Oct-00 RMS Standardized register naming
06-Jan-97 RMS Fixed PDP-4 console input
16-Dec-96 RMS Fixed bug in binary ptr service
@ -39,6 +41,7 @@
extern int32 int_req, saved_PC;
extern int32 M[];
extern UNIT cpu_unit;
int32 clk_state = 0;
int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0;
int32 ptp_err = 0, ptp_stopioe = 0;
@ -184,8 +187,14 @@ static const int32 tti_trans[128] = {
#define TTI_MASK ((1 << TTI_WIDTH) - 1)
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
#define UNIT_V_HDX (UNIT_V_UF + 1) /* half duplex */
#define UNIT_HDX (1 << UNIT_V_HDX)
#if defined (PDP4) || defined (PDP7)
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT };
#else
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC + UNIT_HDX, 0), KBD_POLL_WAIT };
#endif
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, TTI_WIDTH) },
@ -195,6 +204,7 @@ REG tti_reg[] = {
{ ORDATA (TTI_STATE, tti_state, (TTI_WIDTH + 3)), REG_HRO },
#else
{ FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO },
{ FLDATA (HDX, tti_unit.flags, UNIT_V_HDX), REG_HRO },
#endif
{ DRDATA (POS, tti_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
@ -204,6 +214,8 @@ MTAB tti_mod[] = {
#if !defined (KSR28)
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_HDX, 0, "full duplex", "FDX", NULL },
{ UNIT_HDX, UNIT_HDX, "half duplex", "HDX", NULL },
#endif
{ 0 } };
@ -392,7 +404,15 @@ ptr_err = 1;
return detach_unit (uptr);
}
/* Bootstrap routine */
#if defined (PDP4) || defined (PDP7)
/* Bootstrap routine, PDP-4 and PDP-7
In a 4K system, the boostrap resides at 7762-7776.
In an 8K or greater system, the bootstrap resides at 17762-17776.
Because the program is so small, simple masking can be
used to remove addr<5> for a 4K system.
*/
#define BOOT_START 017762
#define BOOT_PC 017770
@ -416,12 +436,26 @@ static const int32 boot_rom[] = {
t_stat ptr_boot (int32 unitno)
{
int32 i;
int32 i, mask;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_PC;
if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
else mask = 0777777;
for (i = 0; i < BOOT_LEN; i++)
M[(BOOT_START & mask) + i] = boot_rom[i] & mask;
saved_PC = BOOT_PC & mask;
return SCPE_OK;
}
#else
/* PDP-9 and PDP-15 have built-in hardware RIM loaders */
t_stat ptr_boot (int32 unitno)
{
return SCPE_ARG;
}
#endif
/* Paper tape punch: IOT routine */
@ -519,6 +553,7 @@ else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
temp = temp & 0177;
if ((tti_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp);
if (tti_unit.flags & UNIT_HDX) sim_putchar (temp);
tti_unit.buf = temp | 0200; /* got char */
#endif
int_req = int_req | INT_TTI; /* set flag */

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
30-Nov-00 RMS Added PDP-9,-15 RIM/BIN loader format
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
20-Oct-97 RMS Fixed endian dependence in RIM loader
@ -103,41 +104,125 @@ const char *sim_stop_messages[] = {
"Breakpoint",
"Nested XCT's" };
/* Binary loader
/* Binary loader */
Until someone finds the binary loader documentation,
this implements RIM loader format
*/
int32 getword (FILE *fileref)
int32 getword (FILE *fileref, int32 *hi)
{
int32 i, tmp, word;
int32 word, bits, st, ch;
word = 0;
for (i = 0; i < 3;) {
if ((tmp = getc (fileref)) == EOF) return -1;
if (tmp & 0200) {
word = (word << 6) | (tmp & 077);
i++; } }
word = st = bits = 0;
do { if ((ch = getc (fileref)) == EOF) return -1;
if (ch & 0200) {
word = (word << 6) | (ch & 077);
bits = (bits << 1) | ((ch >> 6) & 1);
st++; } }
while (st < 3);
if (hi != NULL) *hi = bits;
return word;
}
#if defined (PDP4) || defined (PDP7)
/* PDP-4/PDP-7: RIM format only
Tape format
dac addr
data
:
dac addr
data
jmp addr or hlt
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
{
int32 origin, val;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
for (;;) {
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if ((val & 0760000) == 0040000) { /* DAC? */
origin = val & 017777;
if ((val = getword (fileref)) < 0) return SCPE_FMT;
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0760000) == 0600000) {
else if ((val & 0760000) == 0600000) { /* JMP? */
saved_PC = val & 017777;
return SCPE_OK; } }
return SCPE_OK; }
else if (val == 0740040) return SCPE_OK; /* HLT? */
else return SCPE_FMT; } /* error */
return SCPE_FMT; /* error */
}
#else
/* PDP-9/PDP-15: RIM format and BIN format
RIM format (read in address specified externally)
data
:
data
word to execute (bit 1 of last character set)
BIN format (starts after RIM bootstrap)
block/ origin (>= 0)
count
checksum
data
:
data
block/
:
endblock/ origin (< 0)
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
{
extern int32 sim_switches;
int32 i, bits, origin, count, cksum, val;
t_stat r;
char gbuf[CBUFSIZE];
/* RIM loader */
if (sim_switches & SWMASK ('R')) { /* RIM load? */
if (*cptr != 0) { /* more input? */
cptr = get_glyph (cptr, gbuf, 0); /* get origin */
origin = get_uint (gbuf, 8, ADDRMASK, &r);
if (r != SCPE_OK) return r;
if (*cptr != 0) return SCPE_ARG; } /* no more */
else origin = 0200; /* default 200 */
for (bits = 0; (bits & 1) == 0; ) { /* word loop */
if ((val = getword (fileref, &bits)) < 0) return SCPE_FMT;
saved_PC = origin & ADDRMASK; /* save start */
if (MEM_ADDR_OK (origin)) M[origin++] = val; } /* store word */
return SCPE_OK; } /* found word
/* Binary loader */
if (*cptr != 0) return SCPE_ARG; /* no arguments */
do { val = getc (fileref); } /* find end RIM */
while (((val & 0100) == 0) && (val != EOF));
if (val == EOF) rewind (fileref); /* no RIM? rewind */
for (;;) { /* block loop */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (val & SIGN) {
if (val != DMASK) saved_PC = val & 077777;
return SCPE_OK; }
cksum = origin = val; /* save origin */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val; /* add to cksum */
count = (-val) & DMASK; /* save count */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val; /* add to cksum */
for (i = 0; i < count; i++) {
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
if ((cksum & DMASK) != 0) return SCPE_CSUM; }
return SCPE_FMT;
}
#endif
/* Symbol tables */
@ -169,7 +254,7 @@ return SCPE_FMT; /* error */
#define MD(x) ((I_EMD) + ((x) << I_V_DC))
static const int32 masks[] = {
0777777, 0777767, 0740000, 0740000,
0777777, 0777767, 0740000, 0760000,
0763730, 0760000, 0777000, 0777000,
0740700, 0760700, 0777700 };
@ -177,7 +262,21 @@ static const char *opcode[] = {
"CAL", "DAC", "JMS", "DZM", /* mem refs */
"LAC", "XOR", "ADD", "TAD",
"XCT", "ISZ", "AND", "SAD",
"JMP", "LAW",
"JMP",
#if defined (PDP15) /* mem ref ind */
"CAL*", "DAC*", "JMS*", "DZM*", /* normal */
"LAC*", "XOR*", "ADD*", "TAD*",
"XCT*", "ISZ*", "AND*", "SAD*",
"JMP*",
#else
"CAL I", "DAC I", "JMS I", "DZM I", /* decode only */
"LAC I", "XOR I", "ADD I", "TAD I",
"XCT I", "ISZ I", "AND I", "SAD I",
"JMP I",
#endif
"LAW", /* LAW */
"LACQ", "LACS", "ABS", "GSM", "LMQ", /* EAE */
"MUL", "MULS", "DIV", "DIVS",
@ -243,10 +342,11 @@ static const char *opcode[] = {
"LPDI", "LPEI",
#elif defined (PDP15)
"PFSF", "TTS", "SPCO", "CAF",
"DBR", "SKP15", "SBA", "DBA", "EBA",
"PAX", "PAL", "AAC", "PXA",
"AXS", "PXL", "PLA", "PLX",
"CLX", "CLL", "AXR",
"DBR", "SKP15", "RES",
"SBA", "DBA", "EBA",
"AAS", "PAX", "PAL", "AAC",
"PXA", "AXS", "PXL", "PLA",
"PLX", "CLAC","CLX", "CLLR", "AXR",
#endif
"IOT", /* general */
@ -309,7 +409,13 @@ static const int32 opc_val[] = {
0000000+I_MRF, 0040000+I_MRF, 0100000+I_MRF, 0140000+I_MRF,
0200000+I_MRF, 0240000+I_MRF, 0300000+I_MRF, 0340000+I_MRF,
0400000+I_MRF, 0440000+I_MRF, 0500000+I_MRF, 0540000+I_MRF,
0600000+I_MRF, 0760000+I_LAW,
0600000+I_MRF,
0020000+I_MRF, 0060000+I_MRF, 0120000+I_MRF, 0160000+I_MRF,
0220000+I_MRF, 0260000+I_MRF, 0320000+I_MRF, 0360000+I_MRF,
0420000+I_MRF, 0460000+I_MRF, 0520000+I_MRF, 0560000+I_MRF,
0620000+I_MRF,
0760000+I_LAW,
0641002+I_NPN, 0641001+I_NPN, 0644000+I_NPN, 0664000+I_NPN, 0652000+I_NPN,
0653100+MD(022), 0657100+MD(022), 0640300+MD(023), 0644300+MD(023),
@ -375,10 +481,11 @@ static const int32 opc_val[] = {
0706504+I_NPI, 0706604+I_NPI,
#elif defined (PDP15)
0700062+I_NPI, 0703301+I_NPI, 0703341+I_NPI, 0703302+I_NPI,
0703344+I_NPI, 0707741+I_NPI, 0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI,
0721000+I_XR, 0722000+I_XR, 0723000+I_XR9, 0724000+I_XR,
0725000+I_XR9, 0726000+I_XR, 0730000+I_XR, 0731000+I_XR,
0735000+I_XR, 0736000+I_XR, 0737000+I_XR9,
0703344+I_NPI, 0707741+I_NPI, 0707742+I_NPI,
0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI,
0720000+I_XR9, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9,
0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR,
0731000+I_XR, 0734000+I_XR, 0735000+I_XR, 0736000+I_XR, 0737000+I_XR9,
#endif
0700000+I_IOT,
@ -515,21 +622,13 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
ma = (addr & 0760000) | disp; }
else { disp = inst & 007777;
ma = (addr & 0770000) | disp; }
#else
disp = inst & 017777;
ma = (addr & 0760000) | disp;
#endif
#if defined (PDP9) || (PDP15)
if ((disp & ~07) == 00010) ma = ma & 00017;
#endif
#if defined (PDP15)
fprintf (of, "%s%s%-o", opcode[i],
((inst & 0020000)? " @": " "),
fprintf (of, "%s %-o", opcode[i],
(cflag? ma & ADDRMASK: disp));
if (!memm && (inst & 0010000)) fprintf (of, ",X");
#else
fprintf (of, "%s%s%-o", opcode[i],
((inst & 0020000)? " I ": " "),
disp = inst & 017777;
ma = (addr & 0760000) | disp;
fprintf (of, "%s %-o", opcode[i],
(cflag? ma & ADDRMASK: disp));
#endif
break;
@ -635,7 +734,7 @@ if ((sw & SWMASK ('P')) || ((*cptr == '#') && cptr++)) { /* packed string? */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
val[0] = opc_val[i] & 0777777; /* get value */
val[0] = opc_val[i] & DMASK; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
switch (j) { /* case on class */
@ -656,33 +755,30 @@ case I_V_LAW: /* law */
val[0] = val[0] | d;
break;
case I_V_MRF: /* mem ref */
#if !defined (PDP15)
#if defined (PDP15)
if (memm) dmask = 017777;
else dmask = 07777;
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
#else
dmask = 017777;
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
if (strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | 020000;
cptr = get_glyph (cptr, gbuf, 0); }
#else
if (memm) dmask = 017777;
else dmask = 07777;
if (*cptr == '@') { /* indirect? */
val[0] = val[0] | 020000;
cptr++; }
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
#endif
epcmask = ADDRMASK & ~dmask;
d = get_uint (gbuf, 8, ADDRMASK, &r);
epcmask = ADDRMASK & ~dmask; /* get ePC */
d = get_uint (gbuf, 8, ADDRMASK, &r); /* get addr */
if (r != SCPE_OK) return SCPE_ARG;
if (d <= dmask) val[0] = val[0] | d;
if (d <= dmask) val[0] = val[0] | d; /* fit in 12/13b? */
else if (cflag && (((addr ^ d) & epcmask) == 0))
val[0] = val[0] | (d & dmask);
val[0] = val[0] | (d & dmask); /* hi bits = ePC? */
else return SCPE_ARG;
#if defined (PDP15)
if (!memm) {
cptr = get_glyph (cptr, gbuf, 0);
if (gbuf[0] != 0) {
if (strcmp (gbuf, "X") != 0) return SCPE_ARG;
val[0] = val[0] + 010000; } }
val[0] = val[0] | 010000; } }
#endif
break;
case I_V_EMD: /* or'able */
@ -694,7 +790,7 @@ case I_V_NPN: case I_V_NPI: case I_V_IOT: case I_V_OPR:
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] != NULL) {
k = opc_val[i] & 0777777;
k = opc_val[i] & DMASK;
if (((k ^ val[0]) & 0740000) != 0) return SCPE_ARG;
val[0] = val[0] | k; }
else { d = get_sint (gbuf, & sign, &r);

View file

@ -1,6 +1,6 @@
/* pdp1_cpu.c: PDP-1 CPU simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
16-Dec-00 RMS Fixed bug in XCT address calculation
14-Apr-99 RMS Changed t_addr to unsigned
The PDP-1 was Digital's first computer. Although Digital built four
@ -206,7 +207,7 @@
#include "pdp1_defs.h"
#define ILL_ADR_FLAG (1 << ADDRSIZE)
#define ILL_ADR_FLAG (1 << ASIZE)
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MDV (UNIT_V_UF) /* mul/div */
#define UNIT_MDV (1 << UNIT_V_MDV)
@ -232,7 +233,7 @@ int32 stop_inst = 0; /* stop on rsrv inst */
int32 xct_max = 16; /* nested XCT limit */
int32 ind_max = 16; /* nested ind limit */
int32 old_PC = 0; /* old PC */
int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */
int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
@ -294,7 +295,7 @@ int32 sc_map[512] = {
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
REG cpu_reg[] = {
{ ORDATA (PC, PC, ADDRSIZE) },
{ ORDATA (PC, PC, ASIZE) },
{ ORDATA (AC, AC, 18) },
{ ORDATA (IO, IO, 18) },
{ FLDATA (OV, OV, 0) },
@ -308,14 +309,14 @@ REG cpu_reg[] = {
{ FLDATA (SBIP, sbs, SB_V_IP) },
{ FLDATA (IOH, ioh, 0) },
{ FLDATA (IOC, ioc, 0) },
{ ORDATA (OLDPC, old_PC, ADDRSIZE), REG_RO },
{ ORDATA (OLDPC, old_PC, ASIZE), REG_RO },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (SBS_INIT, sbs_init, SB_V_ON) },
{ FLDATA (EXTM_INIT, extm_init, 0) },
{ FLDATA (MDV, cpu_unit.flags, UNIT_V_MDV), REG_HRO },
{ DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },
{ DRDATA (IND_MAX, ind_max, 8), PV_LEFT + REG_NZ },
{ ORDATA (BREAK, ibkpt_addr, ADDRSIZE + 1) },
{ ORDATA (BREAK, ibkpt_addr, ASIZE + 1) },
{ ORDATA (WRU, sim_int_char, 8) },
{ NULL } };
@ -336,7 +337,7 @@ MTAB cpu_mod[] = {
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 8, ADDRSIZE, 1, 8, 18,
1, 8, ASIZE, 1, 8, 18,
&cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL };
@ -382,28 +383,29 @@ if (PC == ibkpt_addr) { /* breakpoint? */
/* Fetch, decode instruction */
IR = M[PC]; /* fetch instruction */
MA = PC; /* PC to MA */
IR = M[MA]; /* fetch instruction */
PC = INCR_ADDR (PC); /* increment PC */
xct_count = 0; /* track nested XCT's */
sim_interval = sim_interval - 1;
xct_instr: /* label for XCT */
if ((IR == 0610001) && ((PC & EPCMASK) == 0) && (sbs & SB_ON)) {
if ((IR == 0610001) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) {
sbs = sbs & ~SB_IP; /* seq debreak */
old_PC = PC; /* save old PC */
OV = (M[1] >> 17) & 1; /* restore OV */
extm = (M[1] >> 16) & 1; /* restore ext mode */
PC = M[1] & ADDRMASK; /* JMP I 1 */
PC = M[1] & AMASK; /* JMP I 1 */
continue; }
op = ((IR >> 13) & 037); /* get opcode */
if ((op < 032) && (op != 007)) { /* mem ref instr */
MA = (PC & EPCMASK) | (IR & DAMASK); /* effective address */
MA = (MA & EPCMASK) | (IR & DAMASK); /* direct address */
if (IR & IA) { /* indirect addr? */
if (extm) MA = M[MA] & ADDRMASK; /* if ext, one level */
if (extm) MA = M[MA] & AMASK; /* if ext, one level */
else { for (i = 0; i < ind_max; i++) { /* count indirects */
t = M[MA]; /* get indirect word */
MA = (PC & EPCMASK) | (t & DAMASK);
MA = (MA & EPCMASK) | (t & DAMASK);
if ((t & IA) == 0) break; }
if (i >= ind_max) { /* indirect loop? */
reason = STOP_IND;

View file

@ -38,20 +38,6 @@
#include "sim_defs.h"
/* Memory and peripheral configuration */
#define ADDRSIZE 16 /* address bits */
#define MAXMEMSIZE (1u << ADDRSIZE) /* max mem size */
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define DAMASK 007777 /* direct addr */
#define EPCMASK (ADDRMASK & ~DAMASK) /* extended addr */
#define IA 010000 /* indirect flag */
#define IO_WAIT 010000 /* I/O sync wait */
#define IO_CPLS 004000 /* cmopletion pulse */
#define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
@ -60,6 +46,23 @@
#define STOP_XCT 4 /* nested XCT's */
#define STOP_IND 5 /* nested indirects */
#define STOP_WAIT 6 /* wait state */
/* Memory */
#define ASIZE 16 /* address bits */
#define MAXMEMSIZE (1u << ASIZE) /* max mem size */
#define AMASK (MAXMEMSIZE - 1) /* address mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Architectural constants */
#define DAMASK 007777 /* direct addr */
#define EPCMASK (AMASK & ~DAMASK) /* extended addr */
#define IA 010000 /* indirect flag */
#define IO_WAIT 010000 /* I/O sync wait */
#define IO_CPLS 004000 /* cmopletion pulse */
#define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */
/* IOT subroutine return codes */

View file

@ -1,6 +1,6 @@
/* pdp1_lp.c: PDP-1 line printer simulator
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2000, 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"),

View file

@ -409,7 +409,7 @@ case I_V_MRF: case I_V_MRI: /* mem ref */
if ((j != I_V_MRI) && strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | IA;
cptr = get_glyph (cptr, gbuf, 0); }
d = get_uint (gbuf, 8, ADDRMASK, &r);
d = get_uint (gbuf, 8, AMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (d <= DAMASK) val[0] = val[0] | d;
else if (cflag && (((addr ^ d) & EPCMASK) == 0))

View file

@ -33,6 +33,12 @@
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
/* Memory */
#define MAXMEMSIZE 32768 /* max memory size */
@ -40,12 +46,6 @@
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
/* IOT subroutine return codes */
#define IOT_V_SKP 12 /* skip */

11
scp.c
View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Dec-00 RMS Fixed find_device for devices ending in numbers
08-Dec-00 RMS V2.5a changes
30-Oct-00 RMS Added output file option to examine
11-Jul-99 RMS V2.5 changes
13-Apr-99 RMS Fixed handling of 32b addresses
@ -259,7 +261,7 @@ static CTAB cmd_table[] = {
/* Main command loop */
printf ("\n%s simulator V2.5\n", sim_name);
printf ("\n%s simulator V2.5a\n", sim_name);
end_test.i = 1; /* test endian-ness */
sim_end = end_test.c[0];
if (sim_emax <= 0) sim_emax = 1;
@ -1656,7 +1658,12 @@ int32 i, lenn, unitno;
t_stat r;
DEVICE *dptr;
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* exact match? */
if (strcmp (cptr, dptr -> name) != 0) continue;
if (iptr != NULL) *iptr = 0;
return sim_devices[i]; }
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */
lenn = strlen (dptr -> name);
if (strncmp (cptr, dptr -> name, lenn) != 0) continue;
cptr = cptr + lenn;

View file

@ -1,6 +1,6 @@
/* scp_tty.c: Operating system-dependent terminal I/O routines.
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2000, 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"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
08-Dec-00 BKR Added OS/2 support
18-Aug-98 RMS Added BeOS support
13-Oct-97 RMS Added NetBSD terminal support
25-Jan-97 RMS Added POSIX terminal I/O support
@ -189,6 +190,52 @@ _putch (c);
return SCPE_OK;
}
#endif
/* OS/2 routines */
#ifdef __OS2__
#define __TTYROUTINES 0
#include <conio.h>
t_stat ttinit (void)
{
return SCPE_OK;
}
t_stat ttrunstate (void)
{
return SCPE_OK;
}
t_stat ttcmdstate (void)
{
return SCPE_OK;
}
t_stat ttclose (void)
{
return SCPE_OK;
}
t_stat sim_poll_kbd (void)
{
int c;
if (!kbhit ()) return SCPE_OK;
c = getch();
if ((c & 0177) == '\b') c = 0177;
if ((c & 0177) == sim_int_char) return SCPE_STOP;
return c | SCPE_KFLAG;
}
t_stat sim_putchar (int32 c)
{
putch (c);
fflush (stdout) ;
return SCPE_OK;
}
#endif
/* BSD UNIX routines */

349
simh.doc
View file

@ -1,81 +1,84 @@
{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f16\froman\fcharset238\fprq2 Times New Roman CE;}{\f17\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f19\froman\fcharset161\fprq2 Times New Roman Greek;}
{\f20\froman\fcharset162\fprq2 Times New Roman Tur;}{\f21\froman\fcharset186\fprq2 Times New Roman Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;
\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{
\widctlpar\adjustright \fs20\cgrid \snext0 Normal;}{\*\cs10 \additive Default Paragraph Font;}}{\*\listtable{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext
\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid22442644}{\list\listtemplateid-1866037950{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers
\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0
\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0
\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
{\f20\froman\fcharset162\fprq2 Times New Roman Tur;}{\f21\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f22\fswiss\fcharset238\fprq2 Arial CE;}{\f23\fswiss\fcharset204\fprq2 Arial Cyr;}{\f25\fswiss\fcharset161\fprq2 Arial Greek;}
{\f26\fswiss\fcharset162\fprq2 Arial Tur;}{\f27\fswiss\fcharset186\fprq2 Arial Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;
\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\widctlpar\adjustright
\fs20\cgrid \snext0 Normal;}{\*\cs10 \additive Default Paragraph Font;}}{\*\listtable{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}
\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid22442644}{\list\listtemplateid-1866037950{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360
\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0
\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers
\'01\'03\'05\'07\'09;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0
\fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1080\li1080
\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440
\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1440\li1440
\jclisttab\tx1440 }{\listname ;}\listid155609463}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720
\jclisttab\tx720 }{\listname ;}\listid602111040}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720
\jclisttab\tx720 }{\listname ;}\listid621424954}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720
\jclisttab\tx720 }{\listname ;}\listid717362522}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720
\jclisttab\tx720 }{\listname ;}\listid1080104542}{\list\listtemplateid-5054418{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;}\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel
\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext
\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0
\fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0
\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1
\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext
\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext
\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listname ;}\listid1262834005}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0
\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1272592440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0
\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1339387548}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1
\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1409111490}{\list\listtemplateid230209238{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat3\levelspace0\levelindent0
{\leveltext\'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-360\li360
\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0
\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0
{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid155609463}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0
\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid602111040}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0
\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid621424954}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1
\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid717362522}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0
\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1080104542}{\list\listtemplateid-5054418{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext
\'01\'00;}{\levelnumbers\'01;}\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel
\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0
{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers
\'01\'03\'05\'07\'09;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080
\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel
\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0
\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listname ;}\listid1262834005}
{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1272592440}
{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1339387548}
{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1409111490}
{\list\listtemplateid230209238{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat3\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1
\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext
\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}
\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-720\li720\jclisttab\tx720 }
{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0
\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0
\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1
\levellegal\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid1502426668}{\list\listtemplateid1706078190
\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1645162521}{\list\listtemplateid1706078190\listsimple
{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid2006126440}{\list\listtemplateid1706078190\listsimple{\listlevel
\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid2076124660}}{\*\listoverridetable{\listoverride\listid155609463
\listoverridecount0\ls1}{\listoverride\listid1409111490\listoverridecount0\ls2}{\listoverride\listid1272592440\listoverridecount0\ls3}{\listoverride\listid2076124660\listoverridecount0\ls4}{\listoverride\listid717362522\listoverridecount0\ls5}
{\listoverride\listid1339387548\listoverridecount0\ls6}{\listoverride\listid621424954\listoverridecount0\ls7}{\listoverride\listid1080104542\listoverridecount0\ls8}{\listoverride\listid1262834005\listoverridecount0\ls9}{\listoverride\listid2006126440
\listoverridecount0\ls10}{\listoverride\listid602111040\listoverridecount0\ls11}{\listoverride\listid22442644\listoverridecount0\ls12}{\listoverride\listid1502426668\listoverridecount0\ls13}{\listoverride\listid1645162521\listoverridecount0\ls14}}{\info
{\title Writing a Simulator for the SIMH System}{\author Bob Supnik}{\operator Bob Supnik}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2000\mo11\dy18\hr18\min39}{\version10}{\edmins391}{\nofpages15}{\nofwords5229}{\nofchars29808}
{\*\company Digital Equipment Corporation}{\nofcharsws0}{\vern113}}\widowctrl\ftnbj\aenddoc\hyphcaps0\formshade\viewkind4\viewscale100\pgbrdrhead\pgbrdrfoot \fet0\sectd \linex0\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang
{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}
{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9
\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 Writing a Simulator for the SIMH System
\par Revised 30-Oct-00 for V2.5
\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid1502426668}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0
\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1645162521}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0
\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid2006126440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1
\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid2076124660}}{\*\listoverridetable{\listoverride\listid155609463\listoverridecount0\ls1}{\listoverride\listid1409111490
\listoverridecount0\ls2}{\listoverride\listid1272592440\listoverridecount0\ls3}{\listoverride\listid2076124660\listoverridecount0\ls4}{\listoverride\listid717362522\listoverridecount0\ls5}{\listoverride\listid1339387548\listoverridecount0\ls6}
{\listoverride\listid621424954\listoverridecount0\ls7}{\listoverride\listid1080104542\listoverridecount0\ls8}{\listoverride\listid1262834005\listoverridecount0\ls9}{\listoverride\listid2006126440\listoverridecount0\ls10}{\listoverride\listid602111040
\listoverridecount0\ls11}{\listoverride\listid22442644\listoverridecount0\ls12}{\listoverride\listid1502426668\listoverridecount0\ls13}{\listoverride\listid1645162521\listoverridecount0\ls14}}{\info{\title Writing a Simulator for the SIMH System}
{\author Bob Supnik}{\operator Bob Supnik}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2000\mo12\dy16\hr23\min48}{\version12}{\edmins414}{\nofpages15}{\nofwords5229}{\nofchars29808}{\*\company Digital Equipment Corporation}{\nofcharsws0}{\vern113}}
\widowctrl\ftnbj\aenddoc\hyphcaps0\formshade\viewkind4\viewscale100\pgbrdrhead\pgbrdrfoot \fet0\sectd \linex0\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}
{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}
{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain
\widctlpar\adjustright \fs20\cgrid {\f1 Writing a Simulator for the SIMH System
\par Revised 30-Nov-00 for V2.5a
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 1.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Overview
\par }\pard \widctlpar\adjustright {\f1
\par SIMH (history simulators) is a set of portable programs, written in C, which simulate various historically interesting computers. This document describes how to design, write, a
nd check out a new simulator for SIMH. It is not an introduction to either the philosophy or external operation of SIMH, and the reader should be familiar with both of those topics before proceeding. Nor is it a guide to the internal design or operation
of SIMH, except insofar as those areas interact with simulator design. Instead, this manual presents and explains the form, meaning, and operation of the interfaces between simulators and the SIMH simulator control package. It also offers some suggestio
ns for utilizing the services SIMH offers and explains the constraints which all simulators operating within SIMH will experience.
\par SIMH (history simulators) is a set of portable programs, written in C, which simulate various historically interesting computers. This document describes how to design, write, and check out a new simulator for SIMH. It is not an introduction to either t
h
e philosophy or external operation of SIMH, and the reader should be familiar with both of those topics before proceeding. Nor is it a guide to the internal design or operation of SIMH, except insofar as those areas interact with simulator design. Inste
a
d, this manual presents and explains the form, meaning, and operation of the interfaces between simulators and the SIMH simulator control package. It also offers some suggestions for utilizing the services SIMH offers and explains the constraints which a
ll simulators operating within SIMH will experience.
\par
\par Some terminology: Each simulator consists of a standard }{\i\f1 simulator control package}{\f1 (SCP), which provides a control framework and utility routines for a simulator; and a unique }{\i\f1 virtual machine}{\f1
(VM), which implements the simulated processor and selected peripherals. A VM consists of multiple }{\i\f1 devices}{\f1 , such as the CPU, paper tape reader, disk controller, etc. Each controller consists of a named state space (called }{\i\f1
registers}{\f1 ) and one or more }{\i\f1 units}{\f1 . Each unit consists of a numbered state space (called a }{\i\f1 data set}{\f1 ). }{\i\f1 }{\f1 The }{\i\f1 host computer}{\f1 is the system on which SIMH runs; the }{\i\f1 target computer}{\f1
\par Some terminology: Each simulator consists of a standard }{\i\f1 simulator control package}{\f1 (SCP), which provides a control framework and utility routines for a simulator; and a unique }{\i\f1 virtual machine}{\f1 (VM), which
implements the simulated processor and selected peripherals. A VM consists of multiple }{\i\f1 devices}{\f1 , such as the CPU, paper tape reader, disk controller, etc. Each controller consists of a named state space (called }{\i\f1 registers}{\f1
) and one or more }{\i\f1 units}{\f1 . Each unit consists of a numbered state space (called a }{\i\f1 data set}{\f1 ). }{\i\f1 }{\f1 The }{\i\f1 host computer}{\f1 is the system on which SIMH runs; the }{\i\f1 target computer}{\f1
is the system being simulated.
\par
\par SIMH is unabashedly based on the MIMIC simulation system, designed in the late 60\rquote s by Len Fehskens, Mike McCarthy, and Bob Supnik. This document is based on MIMIC\rquote s published interface specification, \ldblquote
How to Write a Virtual Machine for the MIMIC Simulation System\rdblquote , by Len Fehskens and Bob Supnik.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Designing a Virtual Machine
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Data Types
\par }\pard \widctlpar\adjustright {\f1
\par SIMH is written in C. The host system must support (at least) 32-bit data types (64-bit data types for the PDP-10 and other large-word target systems). To cope with the vagaries of C data types,
SIMH defines some unambiguous data types for its interfaces:
\par SIMH is written
in C. The host system must support (at least) 32-bit data types (64-bit data types for the PDP-10 and other large-word target systems). To cope with the vagaries of C data types, SIMH defines some unambiguous data types for its interfaces:
\par
\par \tab SIMH data type\tab \tab \tab interpretation in typical C
\par \tab SIMH data type\tab \tab \tab interpretation in typical 32-bit C
\par
\par \tab int8\tab \tab \tab \tab char
\par \tab int16\tab \tab \tab \tab short
\par \tab int32\tab \tab \tab \tab long
\par \tab int64\tab \tab \tab \tab long long, _int64 (system specific)
\par \tab int8, uint8\tab \tab \tab char, unsigned char
\par \tab int16, uint16\tab \tab \tab short, unsigned short
\par \tab int32, uint32\tab \tab \tab int, unsigned int
\par \tab int64, uint64\tab \tab \tab long long, _int64 (system specific)
\par \tab t_addr\tab \tab \tab \tab simulated address, int32
\par \tab t_val\tab \tab \tab \tab simulated value, unsigned int32
\par \tab t_value\tab \tab \tab \tab simulated value, unsigned int32 or int64
\par \tab t_svalue\tab \tab \tab simulated signed value, int32 or int64
\par \tab t_mtrec\tab \tab \tab \tab mag tape record length, int32
\par \tab t_stat\tab \tab \tab \tab status code, int
\par \tab t_bool\tab \tab \tab \tab true/false value, int
@ -85,6 +88,7 @@ SIMH defines some unambiguous data types for its interfaces:
\par \tab }{\b\f1 DEVICE}{\f1 \tab \tab \tab device definition structure
\par \tab }{\b\f1 UNIT}{\f1 \tab \tab \tab \tab unit definition structure
\par \tab }{\b\f1 REG}{\f1 \tab \tab \tab \tab register definition structure
\par \tab }{\b\f1 MTAB}{\f1 \tab \tab \tab \tab modifier definition structure
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 VM Organization
\par }\pard \widctlpar\adjustright {\f1
@ -98,9 +102,9 @@ SIMH defines some unambiguous data types for its interfaces:
\par \tab TTO\tab \tab \tab \tab console output
\par \tab DKP\tab \tab \tab \tab disk pack controller and drives
\par
\par There may
be more than one device per physical hardware entity, as for the console; but for each user-accessible device there must be at least one. One of these devices will have the pre-eminent responsibility for directing simulated operations. Normally, this is
the CPU, but it could be a higher-level entity, such as a bus master.
\par There may be more than one device per physical hardware entity, as for the console;
but for each user-accessible device there must be at least one. One of these devices will have the pre-eminent responsibility for directing simulated operations. Normally, this is the CPU, but it could be a higher-level entity, such as a bus master.
\par
\par The VM actually runs as a subroutine of the simulator control package (SCP). It provides a master routine for running simulated programs and other routines and data structures to implement SCP\rquote
s command and control functions. The interfaces between a VM and SCP are relatively few:
@ -112,7 +116,7 @@ s command and control functions. The interfaces between a VM and SCP are relati
\par \tab int32 }{\b\f1 sim_emax}{\f1 \tab \tab maximum number of words in an instruction
\par \tab DEVICE *}{\b\f1 sim_devices[]}{\f1 \tab table of pointers to simulated devices, NULL terminated
\par \tab char *}{\b\f1 sim_stop_messages[]}{\f1 \tab table of pointers to error messages
\par \tab t_stat }{\b\f1 sim_load}{\f1 (FILE *fref)\tab binary loader subroutine
\par \tab t_stat }{\b\f1 sim_load}{\f1 (\'85)\tab \tab binary loader subroutine
\par \tab t_stat }{\b\f1 sim_inst}{\f1 (void)\tab \tab instruction execution subroutine
\par \tab t_stat }{\b\f1 parse_sym}{\f1 (\'85)\tab \tab symbolic instruction parse subroutine (optional)
\par \tab t_stat }{\b\f1 fprint_sym}{\f1 (\'85)\tab \tab symbolic instruction print subroutine (optional)
@ -120,16 +124,16 @@ s command and control functions. The interfaces between a VM and SCP are relati
\par There is no required organization for VM code. The following convention has been used so far. Let name be the }{\i\f1 name}{\f1 of the real system (i1401 for the IBM 1401; pdp1 for the PDP-1; pdp18b for the other 18-bit PDP\rquote
s; pdp8 for the PDP-8; pdp11 for the PDP11; nova for Nova; hp2100 for the HP 21XX; id4 for the Interdata 4):
\par
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 .h contains definition
s for the particular simulator
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1
.h contains definitions for the particular simulator
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1
_sys.c contains all the SCP interfaces except the instruction simulator
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1
_cpu.c contains the instruction simulator and CPU data structures
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1
_stddev.c contains the peripherals which were standard with the real system.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1
_lp.c contains the line printer.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 _lp.c contains the
line printer.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1
_mt.c contains the mag tape controller and drives, etc.
\par }\pard \fi1440\widctlpar\adjustright {\f1
@ -151,38 +155,38 @@ _mt.c contains the mag tape controller and drives, etc.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Time Base
\par }\pard \widctlpar\adjustright {\f1
\par In order to simulate asynchronous events, such as I/O completion, the VM must define and keep a time base. This can be accurate (for example, nanoseconds of executi
on) or arbitrary (for example, number of instructions executed), but it must be consistently used throughout the VM. All existing VM\rquote s count time in instructions.
\par In order to simulate asynchronous events, such as I/O completion, the VM must define and keep a time base. T
his can be accurate (for example, nanoseconds of execution) or arbitrary (for example, number of instructions executed), but it must be consistently used throughout the VM. All existing VM\rquote s count time in instructions.
\par
\par The CPU is responsible for counting down the event counter }{\b\f1 sim_interval}{\f1 and calling the asynchronous event controller }{\b\f1 sim_process_event}{\f1 . The record keeping for timing is done by SCP.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Memory Organization
\par }\pard \widctlpar\adjustright {\f1
\par The criterion for memory layout is very simple: use the SIMH data type that is as large as (or if necessary, larger than), the word length of
the real machine. Note that the criterion is word length, not addressability: the PDP-11 has byte addressable memory, but it is a 16-bit machine, and its memory is defined as unsigned int16 M[]. It may seem tempting to define memory as a union of int8
and int16 data types, but this would make the resulting VM endian-dependent. Instead, the VM should be based on the underlying word size of the real machine, and byte manipulation should be done explicitly. Examples:
\par The crit
erion for memory layout is very simple: use the SIMH data type that is as large as (or if necessary, larger than), the word length of the real machine. Note that the criterion is word length, not addressability: the PDP-11 has byte addressable memory, bu
t it is a 16-bit machine, and its memory is defined as uint16 M[]. It may seem tempting to define memory as a union of int8 and int16 data types, but this would make the resulting VM endian-dependent. Instead, the VM should be based on the underly
ing word size of the real machine, and byte manipulation should be done explicitly. Examples:
\par
\par \tab Simulator\tab \tab memory size\tab \tab memory declaration
\par
\par \tab IBM 1401\tab \tab 6-bit\tab \tab \tab int8
\par \tab PDP-8\tab \tab \tab 12-bit\tab \tab \tab int16
\par \tab PDP-11, Nova\tab \tab 16-bit\tab \tab \tab int16
\par \tab PDP-10\tab \tab \tab 36-bit\tab \tab \tab int64
\par \tab IBM 1401\tab \tab 6-bit\tab \tab \tab unsigned int8
\par \tab PDP-8\tab \tab \tab 12-bit\tab \tab \tab unsigned int16
\par \tab PDP-11, Nova\tab \tab 16-bit\tab \tab \tab unsigned int16
\par \tab PDP-10\tab \tab \tab 36-bit\tab \tab \tab unsigned int64
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.3\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Interrupt Organization
\par }\pard \widctlpar\adjustright {\f1
\par The design of the VM\rquote s interrupt structure is a complex interaction between efficiency and fidelity to the hardware. If the VM\rquote
s interrupt structure is too abstract, interrupt driven software may not run. On the other hand, if it follows the hardware too literally, it may significantly reduce simulation speed. One rule I can offer is to minimize the fetch-phase cost of i
nterrupts, even if this complicates the (much less frequent) evaluation of the interrupt system following an I/O operation. Another is not to over-generalize; even if the real hardware could support 64 or 256 interrupting devices, the simulators will be
running much smaller configurations. I\rquote ll start with a simple interrupt structure and then offer suggestions for generalization.
\par The design of the VM\rquote s interrupt structure is a complex interaction between efficiency and fidelity to the hardware. If the VM\rquote s interrupt structure is too abstract, interrupt driven software may not
run. On the other hand, if it follows the hardware too literally, it may significantly reduce simulation speed. One rule I can offer is to minimize the fetch-phase cost of interrupts, even if this complicates the (much less frequent) evaluation of the i
nterrupt system following an I/O operation or asynchronous event. Another is not to over-generalize; even if the real hardware could support 64 or 256 interrupting devices, the simulators will be running much smaller configurations. I\rquote
ll start with a simple interrupt structure and then offer suggestions for generalization.
\par
\par In the simplest structure, interrupt requests correspond to device flags and are kept in an interrupt request variable, with o
ne flag per bit. The fetch-phase evaluation of interrupts consists of two steps: are interrupts enabled, and is there an interrupt outstanding? If all the interrupt requests are kept as single-bit flags in a variable, the fetch-phase test is very fast:
\par In the simplest structure, interrupt requests correspond to device flags and are kept in an interrupt request variable, with one flag per bit. The fetch-phase evaluation of interrupts
consists of two steps: are interrupts enabled, and is there an interrupt outstanding? If all the interrupt requests are kept as single-bit flags in a variable, the fetch-phase test is very fast:
\par
\par \tab if (int_enable && int_requests) \{ \'85process interrupt\'85 \}
\par
\par Indeed, if the interrupt enable flag is not visible state, it can be made the highest bit in the interrupt request variable, and the two tests combined:
\par Indeed, the interrupt enable flag can be made the highest bit in the interrupt request variable, and the two tests combined:
\par
\par \tab if (int_requests > INT_ENABLE) \{ \'85process interrupt\'85 \}
\par
@ -191,56 +195,54 @@ ne flag per bit. The fetch-phase evaluation of interrupts consists of two steps
\par \tab set: \tab int_requests = int_requests | DEVICE_FLAG;
\par \tab clear:\tab int_requests = int_requests & ~DEVICE_FLAG;
\par
\par At a slightly higher complexity, interrupt
requests do not correspond directly to device flags but are based on masking the device flags with an enable (or disable) mask. There are now three parallel variables: interrupt requests, device flags, and interrupt enable mask. The fetch-phase test do
es not change; however, the evaluation of whether an interrupt is pending now requires an extra step:
\par At a slightly higher complexity, interrupt requests do
not correspond directly to device flags but are based on masking the device flags with an enable (or disable) mask. There are now three parallel variables: interrupt requests, device flags, and interrupt enable mask. The fetch-phase test does not change
; however, the evaluation of whether an interrupt is pending now requires an extra step:
\par
\par \tab enable:\tab int_requests = device_flags & int_enables;
\par \tab disable:\tab int_requests = device_flags & ~int_disables;
\par
\par If required for interrupt processing, the high
est priority interrupting device can be determined by scanning the interrupt request variable from high priority to low until a set bit is found. The bit position can then be back-mapped through a table to determine the address or interrupt vector of the
interrupting device.
\par If required for interrupt processing, the highest priority
interrupting device can be determined by scanning the interrupt request variable from high priority to low until a set bit is found. The bit position can then be back-mapped through a table to determine the address or interrupt vector of the interrupting
device.
\par
\par At yet higher complexity, the interrupt system may be too complex or too large to evaluate during the fetch-phase. In this case, an interrupt pending flag is created, and it is evaluated by subroutine call whenever a change could occ
ur (start of execution, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common subroutine.
\par At yet higher complexity, the interrupt system may be too complex or too large to evaluate during the fetch-phase. In this case, an interrupt pending flag is created, and it is evaluated by subroutine call whenever a change could occur (start of
execution, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common subroutine.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.4\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 I/O Dispatching
\par }\pard \widctlpar\adjustright {\f1
\par I/O dispatching consists of four steps:
\par
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Identify the I/O command
and analyze for the device address.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Identify the I/O command and
analyze for the device address.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Locate the selected device.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1
Break down the I/O command into standard fields.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Call the device processor.
\par }\pard \widctlpar\adjustright {\f1
\par Analyzing an I/O command is usually easy. Most systems have one or more explicit I/O instructions containing an I
/O command and a device address. Memory mapped I/O is more complicated; the identification of a reference to I/O space becomes part of memory addressing. This usually requires centralizing memory reads and writes into subroutines, rather than as inline
code.
\par Analyzing an I/O command is usually easy. Most systems have one or more explicit I/O instructions containing
an I/O command and a device address. Memory mapped I/O is more complicated; the identification of a reference to I/O space becomes part of memory addressing. This usually requires centralizing memory reads and writes into subroutines, rather than as in
line code.
\par
\par Once an I/O command has been analyzed, the CPU must locate the device subroutine. The simplest way is a large switch statement with hardwired subroutine calls. Slightly more modular is to call through a dispatch table, with NULL entries representin
g non-existant devices. Before calling the device routine, the CPU usually breaks down the I/O command into standard fields. This simplifies writing the peripheral simulator.
\par Once an I/O command has been analyzed, the CPU must locate the device subroutine. The simplest way is a large switch statement with hardwired subroutine calls. Slightly more modular is to call through a dispatch table, with NULL
entries representing non-existent devices. Before calling the device routine, the CPU usually breaks down the I/O command into standard fields. This simplifies writing the peripheral simulator.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.5\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Instruction Execution
\par }\pard \widctlpar\adjustright {\f1
\par Instruction execution is the responsibility of VM subroutine }{\b\f1 sim_instr}{\f1 . It is called from SCP as a result of a RUN, GO, CONT, or BOOT command. It begins executing instructions at the current PC (}{\b\f1 sim_PC}{\f1
points to its register description block) and continues until halted by an error or an external event.
\par
\par Whe
n called, the CPU needs to account for any state changes that the user made. For example, it may need to re-evaluate whether an interrupt is pending, or restore frequently used state to local register variables for efficiency. The actual instruction fet
ch and execute cycle is usually structured as a loop controlled by an error variable, e.g.,
\par When called, the CPU needs to account for any state changes that the user made. For example, it may need to re-evaluate whether an interrupt is pending, or restore frequently used state to local register variables for efficiency. Th
e actual instruction fetch and execute cycle is usually structured as a loop controlled by an error variable, e.g.,
\par
\par \tab reason = 0;
\par \tab do \{ \'85 \} while (reason == 0);\tab or\tab while (reason == 0) \{ \'85 \}
\par
\par Within this loop, the usual order of events is:
\par
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1
If the event timer sim_interval has reached zero, process any timed events. This is done by SCP subroutine sim_process_event (void). Because this is the polling mechanism for user-generated processor halts (^E), errors must be recognized immediately:
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 If the event timer }{\b\f1
sim_interval}{\f1 has reached zero, process any timed events. This is done by SCP subroutine }{\b\f1 sim_process_event}{\f1 . Because this is the polling mechanism for user-generated processor halts (^E), errors must be recognized immediately:
\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1
\par }\pard \li1440\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 if (sim_interval <= 0) \{
\par }\pard \fi720\li1440\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 if (reason = sim_process_event ()) break; \}
@ -267,22 +269,22 @@ The VM should provide some debugging aids. The existing CPU\rquote s all provid
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Peripheral Device Organization
\par }\pard \widctlpar\adjustright {\f1
\par The basic elements of a VM are devices, each corresponding roughly to a real chunk of hardware. A device cons
ists of register-based state and one or more units. Thus a multi-drive disk subsystem is a single device (representing the hardware of the real controller) and one or more units (each representing a single disk drive). Sometimes the device and its unit
are the same entity as, for example, in the case of a paper tape reader. However, a single physical hardware device, such as the console, may be broken up for convenience into separate input and output devices.
\par The basic elements of a VM are devices, ea
ch corresponding roughly to a real chunk of hardware. A device consists of register-based state and one or more units. Thus, a multi-drive disk subsystem is a single device (representing the hardware of the real controller) and one or more units (each r
epresenting a single disk drive). Sometimes the device and its unit are the same entity as, for example, in the case of a paper tape reader. However, a single physical device, such as the console, may be broken up for convenience into separate in
put and output devices.
\par
\par In general, units correspond to individual s
ources of input or output (one tape transport, one A-to-D channel). Units are the basic medium for both device timing and device I/O. Except for the console, all I/O devices are simulated as host-resident files. SCP allows the user to make an explicit
association between a host-resident file and a simulated hardware entity.
\par In general, units correspond to individual sources of input or output (one tape transport, one A-to-D channel). Units are the basic medium for both device timing and device I/O. Except for the console, all I/O devices are simulat
ed as host-resident files. SCP allows the user to make an explicit association between a host-resident file and a simulated hardware entity.
\par
\par Both devices and units have state. Devices operate on }{\i\f1 registers}{\f1 , which contain information about the state of the device, and indirectly, about the state of the units. Units operate on }{\i\f1 data sets}{\f1
, which may be thought of as individual instances of input or output, such as a disk pack or a punched paper tape. In a typical multi-unit device, all units are the same, and the device performs similar operations on all of them, depending o
n which one has been selected by the program being simulated. Schematically:
, which may be thought of as individual instances of input or output, such as a disk pack or a punched paper tape. In a typical multi-unit device, all units are the same, a
nd the device performs similar operations on all of them, depending on which one has been selected by the program being simulated.
\par
\par (Note: SIMH, like MIMIC, restricts registers to devices. This requires replicated registers, for example, disk drive current state, to have unique names in the device name space.)
\par
\par For each structural level, SIMH defines, and the VM must supply, a corresponding data structure. }{\b\f1 device}{\f1 structures correspond to devices, }{\b\f1 reg}{\f1 structures to registers, and }{\b\f1 unit}{\f1
structures to units. These structures are described in detail in section 3.
\par For each structural level, SIMH defines, and the VM must supply, a corresponding data structure. }{\b\f1 device}{\f1 structures correspond to devices, }{\b\f1 reg}{\f1 structures to registers, and }{\b\f1 unit}{\f1 structures to units.
These structures are described in detail in section 4.
\par
\par The primary functions of a peripheral are:
\par
@ -291,16 +293,15 @@ n which one has been selected by the program being simulated. Schematically:
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 device timing
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 data transmission.
\par }\pard \widctlpar\adjustright {\f1
\par Command decoding is fairly obvious. At least one section of the peripheral code module will be devoted to processing directives issued by the
CPU. Typically, the command decoder will be responsible for register and flag manipulation, and for issuing or canceling I/O requests. The former is easy, but the later requires a thorough understanding of device timing.
\par Command decoding is fairly obvious. At least one section of the peripheral code
module will be devoted to processing directives issued by the CPU. Typically, the command decoder will be responsible for register and flag manipulation, and for issuing or canceling I/O requests. The former is easy, but the later requires a thorough un
derstanding of device timing.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Device Timing
\par }\pard \widctlpar\adjustright {\f1
\par The principal pro
blem in I/O device simulation is imitating asynchronous operations in a sequential simulation environment. Fortunately, the timing characteristics of most I/O devices do not vary with external circumstances. The distinction between devices whose timing
i
s externally generated (e.g., console keyboard) and those whose timing is externally generated (disk, paper tape reader) is crucial. With an externally timed device, there is no way to know when an in-progress operation will begin or end; with an interna
lly timed device, given the time when an operation starts, the end time can be calculated.
\par The principal problem in I/O device simulation is imitating asynchronous operations in a sequential simulation environment. Fortuna
tely, the timing characteristics of most I/O devices do not vary with external circumstances. The distinction between devices whose timing is externally generated (e.g., console keyboard) and those whose timing is externally generated (disk, paper tape r
eader) is crucial. With an externally timed device, there is no way to know when an in-progress operation will begin or end; with an internally timed device, given the time when an operation starts, the end time can be calculated.
\par
\par For an internally timed device, the elapsed time between the start and conclusion of an operation is called the wait time. Some typical internally timed devices and their wait times include:
\par
@ -317,13 +318,13 @@ s poll for keyboard input, thus converting the externally timed keyboard to a ps
\par SCP provides the supporting routines for device timing. SCP maintains a list of devices (called }{\i\f1 active devices}{\f1 ) which are in the process of timing out. It also provides routines for querying or manipulating this list (called the }{\i\f1
active queue}{\f1 ). Lastly, it provides a routine for checking for timed-out units and executing a VM-specified action when a time-out occurs.
\par
\par Device timing is done with the UNIT structure, described in section 3. To set up a timed operation, the peripheral calculates a waiting period for a unit and places that unit on the active queue. The CPU counts down the waiting period. When the wai
ting period has expired, sim_process_event removes the unit from the active queue and calls a device subroutine. A device may also cancel an outstanding timed operation and query the state of the queue. The timing subroutines are:
\par Device timing is done with the UNIT structure, described in section 3. To set up a timed operation, the perip
heral calculates a waiting period for a unit and places that unit on the active queue. The CPU counts down the waiting period. When the waiting period has expired, }{\b\f1 sim_process_event}{\f1
removes the unit from the active queue and calls a device subroutine. A device may also cancel an outstanding timed operation and query the state of the queue. The timing subroutines are:
\par
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_activate}{\f1
(U
NIT *uptr, int32 wait). This routine places the specified unit on the active queue with the specified waiting period. A waiting period of 0 is legal; negative waits cause an error. If the unit is already active, the active queue is not changed, and no
error occurs.
(UNIT *uptr, int32 wait). This routine places the specified unit on the active queue with the specified waiting p
eriod. A waiting period of 0 is legal; negative waits cause an error. If the unit is already active, the active queue is not changed, and no error occurs.
\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_cancel}{\f1
(UNIT *uptr). This routine removes the specified unit from the active queue. If the unit is not on the queue, no error occurs.
@ -342,8 +343,8 @@ error occurs.
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Data I/O
\par }\pard \widctlpar\adjustright {\f1
\par For most devices, timing is half the battle (for clocks it is the entire war); the other half is I/O. Except for the console, all I/O devices are simulated as files on the host file system in little-endian format.
SCP provides facilities for associating files with units (ATTACH command) and for reading and writing data from and to devices in a endian- and size-independent way.
\par For most devices, timing is half the battle (for clocks it is the entire war); the other half is I/O. Except for the console, all I/O devices are simulated as files on the host file system in little-endian format. SCP provides facilities for associating
files with units (ATTACH command) and for reading and writing data from and to devices in a endian- and size-independent way.
\par
\par For most devices, the VM designer does not have to be concerned about the formatting of simulated device files. I/O occurs in 1, 2, or 4 byte quantities; SCP automatically chooses the correct data size and corrects for byte ordering. Specific issues:
@ -351,33 +352,34 @@ error occurs.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1
Line printers should write data as 7-bit ASCII, with newlines replacing carriage-return/line-feed sequences.
\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1
Disks should be viewed as linear data sets, from sector 0 of surface 0 of cylinder 0 to the last sector on the disk. This allows easy transcription of real disks to files usable by the simulator.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 Disks should be
viewed as linear data sets, from sector 0 of surface 0 of cylinder 0 to the last sector on the disk. This allows easy transcription of real disks to files usable by the simulator.
\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1
Magtapes, by convention, use a record
based format. Each record consists of a leading 32-bit record length, the record data (padded with a byte of 0 if the record length is odd), and a trailing 32-bit record length. File marks are recorded as one record length of 0.
Magtapes, by convention, use a record based format. Each record consi
sts of a leading 32-bit record length, the record data (padded with a byte of 0 if the record length is odd), and a trailing 32-bit record length. File marks are recorded as one record length of 0.
\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 Cards have 12 bits of da
ta per column, but the data is most conveniently viewed as (ASCII) characters. Existing card reader simulators do not support binary operation.
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1
Cards have 12 bits of data per column, but the data is most conveniently viewed as (ASCII) characters. Existing card reader simulators do not support binary operation.
\par }\pard \widctlpar\adjustright {\f1
\par Data I/O varies between fixed and variable capacity devices, and between buffered and non-buffered devices. A
fixed capacity device differs from a variable capacity device in that the file attached to the former has a maximum size, while the file attached to the latter may expand indefinitely. A buffered device differs from a non-buffered device in that the for
mer buffers its data set in host memory, while the latter maintains it as a file. Most variable capacity devices (such as the paper tape reader and punch) are sequential; all buffered devices are fixed capacity.
\par
\par 2.3.2.1 Reading and Writing Data
\par Data I/O varies between fixed and variable capacity devices, and between buffered and non-buffered devices. A fixed capacity device differ
s from a variable capacity device in that the file attached to the former has a maximum size, while the file attached to the latter may expand indefinitely. A buffered device differs from a non-buffered device in that the former buffers its data set in h
ost memory, while the latter maintains it as a file. Most variable capacity devices (such as the paper tape reader and punch) are sequential; all buffered devices are fixed capacity.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl3\adjustright {\f1 Reading and Writing Data
\par }\pard \widctlpar\adjustright {\f1
\par The ATTACH command creates an association between a host file and an I/O unit. For non-buffered devices, ATTACH stores the file pointer for the host file in the }{\b\f1 fileref}{\f1
field of the UNIT structure. For buffered devices, ATTACH reads the entire host file into an allocated buffer pointed to by the }{\b\f1 filebuf }{\f1 field of the UNIT structure.
\par
\par For non-buffered devices, I/O is done with standard C subroutines plus the SCP routines }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 . }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 are identical in calling sequence and function to fread
and fwrite, respectively, but will correct for endian dependencies. For buffered devices, I/O is done by copying data to or from the allocated buffer. The device code must maintain the number (+1) of the highest address modified in the }{\b\f1 hwmark}{
\f1 field of the UNIT structure. For both the non-buffered and buffered cases, the device must perform all address calculations and positioning operations.
\par For non-buffered devices, I/O is done with standard C subroutines plus the SCP routines }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 . }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1
are identical in calling sequence and function to fread and fwrite, respectively, but
will correct for endian dependencies. For buffered devices, I/O is done by copying data to or from the allocated buffer. The device code must maintain the number (+1) of the highest address modified in the }{\b\f1 hwmark}{\f1
field of the UNIT structure. For both the non-buffered and buffered cases, the device must perform all address calculations and positioning operations.
\par
\par The DETACH command breaks the association between a host file and an I/O unit. For buffered devices, DETACH writes the allocated buffer back to the host file.
\par
\par 2.3.2.2 Console I/O
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl3\adjustright {\f1 Console I/O
\par }\pard \widctlpar\adjustright {\f1
\par SCP provides two routines for console I/O.
\par
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls10\adjustright {\f1 t_stat }{\b\f1 sim_poll_char }{
@ -386,12 +388,12 @@ and fwrite, respectively, but will correct for endian dependencies. For buffere
\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls10\adjustright {\f1 t_stat }{\b\f1 sim_putchar}{\f1
(int32 char). This routine types the specified ASCII character on the console. There are no errors.
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\adjustright {\f1 Data Structures
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 Data Structures
\par }\pard \widctlpar\adjustright {\f1
\par The devices, units, and registers which make up a VM are formally described through a set of data structures which interface the VM to the control portions of SCP. The devices themselves are pointed to by the device list array }{\b\f1 sim_devices[]}{\f1
. Within a device, both units and registers are allocated contiguously as arrays of structures. In addition, many devices allow the user to set or clear options via a modifications table.
\par
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\b\f1 device}{\f1 Structure
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 device}{\f1 Structure
\par }\pard \widctlpar\adjustright {\f1
\par Devices are defined by the }{\b\f1 device}{\f1 structure (typedef }{\b\f1 DEVICE}{\f1 ), which has the following fields:
\par
@ -433,10 +435,10 @@ and fwrite, respectively, but will correct for endian dependencies. For buffere
\par }{\b\f1 attach}{\f1 \tab \tab address of special device attach routine, or NULL if none is required.
\par }{\b\f1 detach}{\f1 \tab \tab address of special device detach routine, or NULL if none is required.
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Examine and Deposit Routines
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Examine and Deposit Routines
\par }\pard \widctlpar\adjustright {\f1
\par For devices which maintain their data sets as host files, SCP implements the examine and deposit data functions. However, devices which maintain their d
ata sets as private state (typically just the CPU) must supply special examine and deposit routines. The calling sequences are:
\par For devices which maintain their data sets as host files, SCP implements the examine and deposit data functions. However, devices which maintain their data sets as private state (typically just the CPU) must supply special examine and deposit routines.
The calling sequences are:
\par
\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 examine_routine}{\f1 (t_val *eval_array, t_addr addr, UNIT *uptr, int32 switches) \endash Copy }{\b\f1 sim_emax}{\f1 consecutive addresses for unit }{\i\f1 uptr}{\f1 , starting at }{\i\f1 addr}{
\f1 , into }{\i\f1 eval_array}{\f1 . The }{\i\f1 switch}{\f1 variable has bit<n> set if the n\rquote th letter was specified as a switch to the examine command.
@ -444,7 +446,7 @@ ata sets as private state (typically just the CPU) must supply special examine a
\par t_stat }{\i\f1 deposit_routine}{\f1 (t_val value, t_addr addr, UNIT *uptr, int32 switches) \endash Store the specified }{\i\f1 value}{\f1 in the specified }{\i\f1 addr}{\f1 for unit }{\i\f1 uptr}{\f1 . The }{\i\f1 switch}{\f1
variable is the same as for the examine routine.
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Reset Routine
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Reset Routine
\par }\pard \widctlpar\adjustright {\f1
\par The reset routine implements the device reset function for the RESET, RUN, and BOOT commands. Its calling sequence is:
\par
@ -452,15 +454,15 @@ ata sets as private state (typically just the CPU) must supply special examine a
\par
\par A typical reset routine clears all device flags and cancels any outstanding timing operations.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.3\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Boot Routine
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1.3\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Boot Routine
\par }\pard \widctlpar\adjustright {\f1
\par If a device responds to a BOOT command, the boot routine implements the bootstrapping function. Its calling sequence is:
\par
\par \tab t_stat boot_routine (int32 unit_number) \endash Bootstrap the specified unit.
\par \tab t_stat }{\i\f1 boot_routine}{\f1 (int32 unit_number) \endash Bootstrap the specified unit.
\par
\par A typical bootstrap routine copies a bootstrap loader into main memory and sets the PC to the starting address of the loader. SCP then starts simulation at the specified address.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.1.4\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Attach and Detach Routines
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1.4\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Attach and Detach Routines
\par }\pard \widctlpar\adjustright {\f1
\par Normally, the ATTACH and DETACH commands are handled by SCP. However, devices which need to pre- or post-process these commands must supply special attach and detach routines. The calling sequences are:
\par
@ -482,7 +484,7 @@ ata sets as private state (typically just the CPU) must supply special examine a
\par \tab return detach_unit (uptr);
\par \}
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\b\f1 unit}{\f1 Structure
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 unit}{\f1 Structure
\par }\pard \widctlpar\adjustright {\b\f1
\par }{\f1 Units are allocated as contiguous array. Each unit is defined with a }{\b\f1 unit}{\f1 structure (typedef }{\b\f1 UNIT}{\f1 ), which has the following fields:
\par
@ -531,7 +533,7 @@ ata sets as private state (typically just the CPU) must supply special examine a
\par
\par defines the line printer as a sequential unit with a wait time of 500.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Unit Flags
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.2.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Unit Flags
\par }\pard \widctlpar\adjustright {\f1
\par The }{\b\f1 flags }{\f1 field contains indicators of current unit status. SIMH defines 11 flags:
\par
@ -549,10 +551,11 @@ ata sets as private state (typically just the CPU) must supply special examine a
\par UNIX_FIX\tab \tab the unit is fixed capacity.
\par UNIT_BINK\tab \tab the unit measures \ldblquote K\rdblquote as 1024, rather than 1000.
\par }\pard \widctlpar\adjustright {\f1
\par Starting at bit position UNIT_V_UF, the remaining flags are device-specific. Device-specific flags are set and cleared with the SET and CLEAR commands, which reference the MTAB array (see below). De
vice-specific flags and UNIT_DIS are not automatically saved and restored; the device must supply a register covering these bits.
\par Starting at bit position UNIT_V_UF, the remaining flags are
device-specific. Device-specific flags are set and cleared with the SET and CLEAR commands, which reference the MTAB array (see below). Device-specific flags and UNIT_DIS are not automatically saved and restored; the device must supply a register cover
ing these bits.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Service Routine
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.2.2\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Service Routine
\par }\pard \widctlpar\adjustright {\f1
\par This routine is called by }{\b\f1 sim_process_event}{\f1 when a unit times out. Its calling sequence is:
\par
@ -560,7 +563,7 @@ vice-specific flags and UNIT_DIS are not automatically saved and restored; the d
\par }\pard \widctlpar\adjustright {\f1
\par The status returned by the service routine is passed by }{\b\f1 sim_process_event}{\f1 back to the CPU.
\par
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.3\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\b\f1 reg}{\f1 Structure
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 reg}{\f1 Structure
\par }\pard \widctlpar\adjustright {\b\f1
\par }{\f1 Registers are allocated as contiguous array, with a NULL register at the end. Each register is defined with a }{\b\f1 reg}{\f1 structure (typedef }{\b\f1 REG}{\f1 ), which has the following fields:
\par
@ -584,8 +587,8 @@ vice-specific flags and UNIT_DIS are not automatically saved and restored; the d
\par }{\b\f1 depth\tab }{\f1 \tab size of data array (normally 1).
\par }{\b\f1 flags}{\f1 \tab \tab flags and formatting information.
\par }\pard \widctlpar\adjustright {\f1
\par The }{\b\f1 depth}{\f1 field is only used with special \ldblquote arrayed registers\rdblquote , like the data buffer in the PDP floppy disk
controller. Arrayed registers cannot be examined or deposited, but all the values in the array will be saved and restored by SAVE and RESTORE.
\par The }{\b\f1 depth}{\f1 field is only used with special \ldblquote arrayed registers\rdblquote , like the data buffer in the PDP floppy disk controller. Arrayed registers cannot be examined or deposited, but all th
e values in the array will be saved and restored by SAVE and RESTORE.
\par
\par Macros }{\b\f1 ORDATA}{\f1 , }{\b\f1 DRDATA}{\f1 , and }{\b\f1 HRDATA}{\f1 define right-justified octal, decimal, and hexidecimal registers, respectively. They are invoked by:
\par
@ -608,7 +611,7 @@ controller. Arrayed registers cannot be examined or deposited, but all the valu
\par \tab REG lpt_reg = \{
\par \tab \tab \{ DRDATA\tab (POS, lpt_unit.pos, 31), PV_LFT \}, \'85 \}
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.3.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Register Flags
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.3.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Register Flags
\par }\pard \widctlpar\adjustright {\f1
\par The }{\b\f1 flags }{\f1 field contains indicators that control register examination and deposit.
\par
@ -622,7 +625,7 @@ controller. Arrayed registers cannot be examined or deposited, but all the valu
\par REG_HRO\tab \tab register is read only and hidden.
\par REG_NZ\tab \tab new register values must be non-zero.
\par
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.4\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\b\f1 mtab}{\f1 Structure
\par {\listtext\pard\plain\b\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.4\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\b\f1 mtab}{\f1 Structure
\par }\pard \widctlpar\adjustright {\b\f1
\par }{\f1 Device-specific SHOW and SET commands are processed using the modifications array, which is allocated as contiguous array, with a NULL at the end. Each possible modification is defined with a }{\b\f1 mtab}{\f1 structure (synonym }{\b\f1 MTAB}{\f1
), which has the following fields:
@ -644,14 +647,14 @@ controller. Arrayed registers cannot be examined or deposited, but all the valu
\par }{\b\f1 mstring}{\f1 \tab pointer to character string to be matched (SET, CLEAR)
\par }{\b\f1 valid}{\f1 \tab address of validation routine, or NULL if none required
\par }\pard \fi-1440\li1440\widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.4.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls13\ilvl2\adjustright {\f1 Validation Routine
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.4.1\tab}}\pard \fi-720\li720\widctlpar\jclisttab\tx720\ls1\ilvl2\adjustright {\f1 Validation Routine
\par }\pard \widctlpar\adjustright {\f1
\par The validation routine is called during SET processing to make sure that the proposed modification is valid. It can make other state changes required by the modification or initiate additional dialogs needed by the modifier. Its calling sequence is:
\par
\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 validation_routine}{\f1 (UNIT *uptr, int32 value) \endash test that }{\i\f1 uptr}{\f1 .}{\b\f1 flags}{\f1 can be set to }{\i\f1 value}{\f1 .
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.5\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\f1 Other Data Structures
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.5\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Other Data Structures
\par }\pard \widctlpar\adjustright {\f1
\par char }{\b\f1 sim_name[]}{\f1 is a character array containing the VM name.
\par
@ -664,15 +667,15 @@ controller. Arrayed registers cannot be examined or deposited, but all the valu
\par char *}{\b\f1 sim_stop_messages[]}{\f1 is an array of pointers to character strings, corresponding to error status returns greater than zero. If }{\b\f1 sim_instr}{\f1 returns status code n > 0, then }{\b\f1 sim_stop_message[n]}{\f1 is printed by SCP.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\adjustright {\f1 VM Provided Routines
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 5.\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\adjustright {\f1 VM Provided Routines
\par }\pard \widctlpar\adjustright {\f1
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\f1 Instruction Execution
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 5.1\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Instruction Execution
\par }\pard \widctlpar\adjustright {\f1
\par Instruction execution is performed by routine }{\b\f1 sim_instr}{\f1 . Its calling sequence is:
\par
\par t_stat }{\b\f1 sim_instr}{\f1 (void) \endash Execute from current PC until error or halt.
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\f1 Binary Load and Dump
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 5.2\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Binary Load and Dump
\par }\pard \widctlpar\adjustright {\f1
\par If the VM responds to the LOAD (or DUMP) command, the loader (dumper) is implemented by routine }{\b\f1 sim_load}{\f1 . Its calling sequence is:
\par
@ -681,7 +684,7 @@ controller. Arrayed registers cannot be examined or deposited, but all the valu
\par }\pard \widctlpar\adjustright {\f1
\par If LOAD or DUMP is not implemented, }{\b\f1 sim_load}{\f1 should simply return SCPE_ARG. The LOAD and DUMP commands open and close the specified file for }{\b\f1 sim_load}{\f1 .
\par
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls13\ilvl1\adjustright {\f1 Symbolic Examination and Deposit
\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 5.3\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360\ls1\ilvl1\adjustright {\f1 Symbolic Examination and Deposit
\par }\pard \widctlpar\adjustright {\f1
\par If the VM provides symbolic examination and deposit of data, it must provide two routines, }{\b\f1 fprint_sym}{\f1 for output and }{\b\f1 parse_sym}{\f1 for input. Their calling sequences are:
\par
@ -691,8 +694,8 @@ controller. Arrayed registers cannot be examined or deposited, but all the valu
\par t_stat }{\b\f1 parse_sym}{\f1 (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 switch) \endash Based on the }{\i\f1 switch}{\f1 variable, parse character string }{\i\f1 cptr}{\f1 for a symbolic value }{\i\f1 val}{\f1 at the specified }{
\i\f1 addr}{\f1 in unit }{\i\f1 uptr}{\f1 .
\par }\pard \widctlpar\adjustright {\f1
\par If symbolic processing is not implemented, or the output value or input string cannot be parsed, these routines should return SCPE_ARG. If the processing was successful and con
sumed more than a single word, then these routines should return extra number of words (not bytes) consumed as a }{\b\f1 negative}{\f1
\par If symbolic processing is not implemented, or the output value or input string cannot be parsed, these routines should return SCPE_ARG. If the processing was successful and consume
d more than a single word, then these routines should return extra number of words (not bytes) consumed as a }{\b\f1 negative}{\f1
number. If the processing was successful and consumed a single word, then these routines should return SCPE_OK. For example, PDP-11 }{\b\f1 parse_sym}{\f1 would respond as follows to various inputs:
\par
\par \tab input\tab \tab \tab \tab return value

View file

@ -1,6 +1,6 @@
To: Users
From: Bob Supnik
Subj: Simulator Usage, V2.5
Subj: Simulator Usage, V2.5a
Date: 1-Jan-01
COPYRIGHT NOTICE
@ -1371,7 +1371,9 @@ CPU Nova CPU with 32KW of memory
- hardware multiply/divide
PTR,PTP paper tape reader/punch
TTI,TTO console terminal
TTI1,TTO1 second terminal
LPT line printer
PLT plotter
CLK real-time clock
DK head-per-track disk controller
DP moving head disk controller with four drives
@ -1406,9 +1408,9 @@ and the size of main memory.
SET CPU 28K set memory size = 28K
SET CPU 32K set memory size = 32K
(Nova 4 = optional multiply/divide, stack, byte, trap instructions)
(Nova 3 = optional multiply/divide, stack instructions)
(MDV = multiply/divide instructions)
(MDV = unsigned multiply/divide instructions)
(Nova 3 = unsigned multiply/divide, stack, trap instructions)
(Nova 4 = unsigned and signed multiply/divide, stack, byte, trap instructions)
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
@ -1460,7 +1462,7 @@ The paper tape reader implements these registers:
Error handling is as follows:
errpr STOP_IOE processed as
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
@ -1550,7 +1552,7 @@ The terminal output implements these registers:
POS 31 number of characters output
TIME 24 time from I/O initiation to interrupt
6.2.5 Programmed I/O Devices (LPT)
6.2.5 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
@ -1594,6 +1596,97 @@ The real-time clock (CLK) implements these registers:
TIME2 24 clock frequency, select = 2
TIME3 24 clock frequency, select = 3
6.2.7 Plotter (PTP)
The plotter (PLT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the plotter.
The plotter implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
6.2.8 Second Terminal Input (TTI1)
The second terminal input (TTI1) reads data from a disk file. When a
file is attached, the second terminal input will read characters at
the interval specified by the TIME register. Detaching the file, or
reaching end of file, stops input. The POS register specifies the
number of the next data item to be read. Thus, by changing POS, the
user can backspace or advance the input stream.
The second terminal input implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 position in the input file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
end of file 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
6.2.9 Second Terminal Output (TTO1)
The second terminal output (TTO1) writes data to a disk file. The
POS register specifies the number of the next data item to be written.
Thus, by changing POS, the user can backspace or advance the output
stream.
The second terminal outpout implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
6.3 Fixed Head Disk (DK)
The fixed head disk controller implements these registers:
@ -2190,8 +2283,10 @@ The 18b PDP simulators implement several unique stop conditions:
- more than XCTMAX nested executes are detected during
instruction execution
The 18b PDP loader supports RIM format tapes. The DUMP command is not
implemented.
The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9
and PDP-15 support both RIM and BIN format tapes. BIN is the default; to
load a RIM format tape, use the -r switch with LOAD. The DUMP command is
not implemented.
8.1 CPU
@ -2235,7 +2330,9 @@ control registers for the interrupt system.
7,9,15 EAE_AC_SIGN 1 EAE AC sign
all L 1 link
7,9 EXTM 1 extend mode
9 EXTM_INIT 1 extend mode value after reset
15 BANKM 1 bank mode
15 BANKM_INIT 1 bank mode value after reset
7 TRAPM 1 trap mode
9,15 USMD 1 user mode
9,15 USMDBUF 1 user mode buffer
@ -2322,8 +2419,13 @@ Error handling is as follows:
8.2.3 Terminal Input (TTI)
The terminal input (TTI) reads from the controling console port. The
input has one option, UC; when set, it automatically converts lower
case input to upper case.
terminal input has one option, UC; when set, it automatically converts
lower case input to upper case.
The PDP-9 and PDP-15 operated the terminal, by default, as half-duplex.
For backward compatibility, on the PDP-9 and PDP-15 the terminal input
has a second option, FDX; when set, it operates the terminal input in
full-duplex mode.
The terminal input implements these registers:
@ -2947,7 +3049,9 @@ or write locked.
SET MTn LOCKED set unit n write locked
SET MTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
Units can also be REMOVEd or ADDed to the configuration. The magnetic
tape simulator supports the BOOT command. The bootstrap reads the first
record off tape, starting at location 1, and then branches to it.
The magnetic tape controller implements these registers:
@ -3094,12 +3198,12 @@ name(s)
CPU 2116, 2100, or 21MX CPU with 32KW memory
DMA0, DMA1 dual channel DMA controller
PTR,PTP paper tape reader/punch
TTY console terminal
LPT LE8E line printer
CLK 12639C time base generator
PTR,PTP 12597A paper tape reader/punch
TTY 12631C buffered teleprinter
LPT 12653A line printer
CLK 12539A/B/C time base generator
DP 12557A cartridge disk controller with four drives
MT 12559 magnetic tape controller with one drives
MT 12559C magnetic tape controller with one drives
The HP2100 simulator implements several unique stop conditions:
@ -3193,7 +3297,7 @@ the higher is automatically set to the lower + 1.
10.4 Programmed I/O Devices
10.4.1 Paper Tape Reader (PTR)
10.4.1 12597A-002 Paper Tape Reader (PTR)
The paper tape reader (PTR) reads data from a disk file. The POS
register specifies the number of the next data item to be read.
@ -3207,6 +3311,7 @@ The paper tape reader implements these registers:
name size comments
BUF 8 last data item processed
CMD 1 reader enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
@ -3227,7 +3332,7 @@ Error handling is as follows:
OS I/O error x report error and stop
10.4.2 Paper Tape Punch (PTP)
10.4.2 12597A-005 Paper Tape Punch (PTP)
The paper tape punch (PTP) writes data to a disk file. The POS
register specifies the number of the next data item to be written.
@ -3238,6 +3343,7 @@ The paper tape punch implements these registers:
name size comments
BUF 8 last data item processed
CMD 1 punch enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
@ -3255,9 +3361,9 @@ Error handling is as follows:
OS I/O error x report error and stop
10.4.3 Console Terminal (TTY)
10.4.3 12631C Buffered Teleprinter (TTY)
The console terminal has three units: keyboard (unit 0), printer
The console teleprinter has three units: keyboard (unit 0), printer
(unit 1), and punch (unit 2). The keyboard reads from, and the
printer writes to, the controlling console port. The punch writes
to a disk file. The keyboard has one option, UC; when set, it
@ -3301,6 +3407,7 @@ The line printer implements these registers:
name size comments
BUF 8 last data item processed
CMD 1 printer enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
@ -3319,7 +3426,7 @@ Error handling is as follows:
OS I/O error x report error and stop
10.4.5 12639C Time Base Generator (CLK)
10.4.5 12539A/B/C Time Base Generator (CLK)
The time base generator (CLK) implements these registers:
@ -3333,9 +3440,9 @@ The time base generator (CLK) implements these registers:
TIME0..TIME7 31 clock intervals, select = 0..7
DEVNO 6 current device number (read only)
10.5 12559C Cartridge Disk (DP)
10.5 12557A Cartridge Disk (DP)
The 12559C cartridge disk has two separate devices, a data channel and
The 12557A cartridge disk has two separate devices, a data channel and
a device controller. The data channel includes a 128-word (one sector)
buffer for reads and writes. The device controller includes the four
disk drives. Disk drives can be REMOVEd or ADDed to the configuration.
@ -3347,8 +3454,8 @@ The data channel implements these registers:
IBUF 16 input buffer
OBUF 16 output buffer
BPTR 7 sector buffer pointer
CMD 1 channel enabled
CTL 1 interrupt enabled
CMD 1 channel enable
CTL 1 interrupt enable
FLG 1 channel ready
FBF 1 channel ready buffer
DEVNO 6 current device number (read only)
@ -3363,8 +3470,8 @@ The device controller implements these registers:
RARH 2 record address register head
RARS 4 record address register sector
CNT 5 check record count
CMD 1 controller enabled
CTL 1 interrupt enabled
CMD 1 controller enable
CTL 1 interrupt enable
FLG 1 controller ready
FBF 1 controller ready buffer
EOC 1 end of cylinder pending
@ -3387,7 +3494,7 @@ Error handling is as follows:
OS I/O error report error and stop
10.6 12557 Magnetic Tape (MT)
10.6 12559C Magnetic Tape (MT)
Magnetic tape options include the ability to make the unit write enabled
or write locked.
@ -3395,7 +3502,7 @@ or write locked.
SET MT LOCKED set unit write locked
SET MT ENABLED set unit write enabled
The 12557 mag tape drive has two separate devices, a data channel and
The 12559C mag tape drive has two separate devices, a data channel and
a device controller. The data channel includes a maximum record sized
buffer for reads and writes. The device controller includes the tape
unit
@ -3715,249 +3822,7 @@ Line printer output is represented by an ASCII file of lines separated by
the newline character. Overprinting is represented by a line ending in
return rather than newline.
Appendix 2: Sample Software
1. PDP-8
1.1 ESI-X
ESI-X is an interactive program for technical computation. It can
execute both immediate commands and stored programs (like BASIC). ESI-X
is provided as both source and as a binary loader format paper-tape
image. For more information see the documentation included with the
program. My thanks to Dave Waks, who wrote the program, and to Paul
Pierce and Tim Litt, who recovered the source from its archival medium.
To load and run ESI-X:
sim> load esix.bin
sim> run 5400
_TYPE 2+2.
2+2 = 4
1.2 FOCAL69
FOCAL69 is an interactive program for technical computations. It can
execute both immediate commands and stored programs (like BASIC). FOCAL69
is provided as a binary loader format paper-tape image. To load and
run FOCAL69:
sim> load focal69.bin
sim> run 200
*TYPE 2+2
= 4.000*
1.3 PDP-8 OS/8
OS/8 is the PDP-8's mass storage-based operating system. It provides a
program development and execution environment for assembler, BASIC, and
FORTRAN programs. OS/8 is provided under license, as is, without fee, by
Digital Equipment Corporation, for non-commercial use only. Please read
the enclosed license agreement for full terms and conditions. This license
agreement must be reproduced with any copy of the OS/8 disk images. My
thanks to Doug Jones of the University of Iowa, who provided the disk
images, and to Digital Equipment Corporation, which provided the license.
To boot and run OS/8:
sim> att rx0 os8sys_rx.dsk
sim> att rx1 os8f4_rx.dsk
sim> boot rx0
.DA dd-mmm-yy
.
Note that OS/8 only recognizes upper case characters. The first disk
(drive 0) is the system disk; it also includes BASIC. The second disk
(drive 1) includes FORTRAN.
2. PDP-11
2.1 UNIX V5, V6, V7
UNIX was first developed on the PDP-7; its first widespread usage was on
the PDP-11. UNIX provides a program development and execution environment
for assembler and C programs. UNIX V5, V7, V7 for the PDP-11 is provided
under license, as is, without fee, by Santa Cruz Organization (SCO), for
non-commercial use only. Please read the enclosed license agreement for
full terms and conditions. This license must be reproduced with any copy
of the UNIX V5, V6, V7 disk images. My thanks to PUPS, the PDP-11 UNIX
Preservation Society of Australia, which provided the disk images, and to
SCO, which provided the license.
2.1.1 UNIX V5
UNIX V5 is contained on a single RK05 disk image. To boot UNIX:
sim> set cpu 18b
sim> att rk0 unix_v5_rk.dsk
sim> boot rk
@unix
login: root
#ls -l
2.1.2 UNIX V6
UNIX V6 is contained on three RK05 disk images. To boot UNIX:
sim> set cpu 18b
sim> att rk0 unix0_v6_rk.dsk
sim> att rk1 unix1_v6_rk.dsk
sim> att rk3 unix3_v6_rk.dsk
sim> boot rk0
@unix
login: root
# ls -l
2.1.3 UNIX V7
NOTE: The V7 disk images with V2.3c and later releases are new and
replace the prior versions, which were corrupt.
UNIX V7 is contained on a single RL02 disk image. To boot UNIX:
sim> set cpu 18b
sim> set rl0 RL02
sim> att rl0 unix_v7_rl.dsk
sim> boot rl0
@boot
New Boot, known devices are hp ht rk rl rp tm vt
: rl(0,0)rl2unix
#
A smaller image is contained on a single RK05 disk image. To boot UNIX:
sim> set cpu 18b
sim> att rk0 unix_v7_rk.dsk
sim> boot rk0
@boot
New Boot, known devices are hp ht rk rl rp tm vt
: rk(0,0)rkunix
# STTY -LCASE
#
2.2 RT-11
RT-11 is the PDP-11's single user operating system. It provides a program
development and execution environment for assembler, BASIC, and FORTRAN
programs. RT-11 is provided under license, as is, without fee, by Mentec
Corporation, for non-commercial use ONLY ON THIS SIMULATOR. Please read
the enclosed license agreement for full terms and conditions. This license
agreement must be reproduced with any copy of the RT-11 disk image. My
thanks to John Wilson, a private collector, who provided the disk image
for RT-11 V4; to Megan Gentry, of Digital Equipment Corporation, who
provided the disk image for RT-11 V5.3; and to Mentec Corporation, which
provided the license.
2.2.1 RT-11 V4
RT-11 is contained in a single RK05 disk image. To boot and run RT-11:
sim> att rk0 rtv4_rk.dsk
sim> boot rk0
For RL, RM, and RP series disks, RT-11 expects to find a manufacturer's bad
block table in the last track of the disk. Therefore, INITialization of a
new (all zero's) disk fails, because there is no valid bad block table. To
create a minimal bad block table, use the SET <unit> BADBLOCK command.
2.2.2 RT-11 V5.3
RT-11 is contained in a single RL02 disk image. To boot and run RT-11:
sim> set rl0 rl02
sim> att rl0 rtv53_rl.dsk
sim> boot rl0
This is a full RT-11 distribution kit. It expects the user to copy the
distribution pack and generate a new system. This requires mounting
blank packs on RL1. When a blank pack is attached to the simulator,
a bad block table must be created with the SET <unit> BADBLOCK command.
3. Nova RDOS
RDOS is the Nova's real-time mass storage operating system. It provides a
program development and execution environment for assembler, BASIC, and
FORTRAN programs. RDOS is provided under license, as is, without fee, by
Data General Corporation, for non-commercial use only. Please read the
enclosed license agreement for full terms and conditions. This license
agreement must be reproduced with any copy of the RDOS disk image. My
thanks to Carl Friend, a private collector, who provided the disk image,
and to Data General Corporation, which provided the license.
To boot and run RDOS:
sim> att dp0 rdos_d31.dsk
sim> set tti dasher
sim> boot dp0
FILENAME? (cr)
DATE (mm/dd/yy)? xx/yy/zz
TIME (hh:mm:ss)? hh:mm:ss
R
list/e
4. PDP-1 LISP
PDP-1 LISP is an interactive interpreter for the Lisp language. It can
execute both interactive commands and stored programs. The startup
instructions for LISP are complicated; see the documentation included
with the program for details. My thanks to Peter Deutsch, who wrote the
program, to Gordon Greene, who typed it in from a printed listing, and
to Paul McJones, who helped with the final debug process.
5. PDP-7 SIM8
PDP-7 SIM8 is a PDP-8 simulator for the PDP-7. It implements an 8K
PDP-8/I with keyboard, teleprinter, reader, punch, and line printer.
It provides an interactive console environment for control and debug
of the simulated PDP-8. For more information see the documentation
included with the program. My thanks to Dave Waks, who wrote the
program, and to Paul Pierce and Tim Litt, who recovered the source
from its archival medium.
To load and run SIM8:
sim> load sim8.rim
sim> run
AC/ 0000
6. 1401 Single Card "Koans"
One of the art forms for the IBM 1401 was packing useful programs into a
single punched card. Three samples are included:
i1401_ctolp.cd prints a card deck on the line printer
i1401_ctopu.cd copies a card deck to the card punch
i1401_hello.cd prints "HELLO WORLD" on the line printer and stops
To use the reproduction cards, simply insert them at the beginning of a
text file, terminated by newline. Attach the modified file to the card
reader, attach a blank file to the output device, and boot the card reader.
7. HP2116 16K BASIC
HP BASIC is a paper-tape centric implementation of BASIC for a 16KW
HP2116. Device numbers correspond to the default simulator settings:
PTR = 10
TTY = 11
PTP = 12
The program is a complete but early BASIC and has one unsual requirement:
all programs must include a valid END statement to run correctly. My
thanks to Jeff Moffatt for providing the program.
To load and run BASIC:
sim> load basic1.abs
sim> run 100
READY
10 PRINT SQR(2)
20 END
RUN
1.41421
Appendix 3: Debug Status
Appendix 2: Debug Status
The debug status of each simulated CPU and device is as follows:
@ -3999,7 +3864,34 @@ legend: y = runs operating system or sample program
Revision History (since Rev 1.1)
Rev 2.5, Jan, 01
Rev 2.5a, Dec, 00
Fixed SCP handling of devices without units
Fixed FLG, FBF initialization in many HP peripherals
Added CMD flop to HP paper tape and line printer
Added status input for HP paper tape punch and TTY
Fixed 1401 bugs found by Dutch Owens
-- 4, 7 char NOPs are legal
-- 1 char B is chained BCE
-- MCE moves whole character, not digit, after first
Added Dutch Owens' 1401 mag tape boot routine
Fixed Nova bugs found by Bruce Ray
-- traps implemented on Nova 3 as well as Nova 4
-- DIV and DIVS 0/0 set carry
-- RETN sets SP from FP at outset
-- IORST does not clear carry
-- Nova 4 implements two undocumented instructions
Added Bruce Ray's Nova plotter and second terminal modules
Added Charles Owen's Eclipse CPU support
Fixed bugs in 18b PDP's
-- XCT indirect address calculation
-- missing index instructions in PDP-15
-- bank mode handling in PDP-15
Added PDP-9/PDP-15 RIM/BIN loader support
Added PDP-9/PDP-15 extend/bank initial state registers
Added PDP-9/PDP-15 half/full duplex support
Moved software documentation to a separate file
Rev 2.5, Nov, 00
Removed Digital and Compaq from copyrights, as
authorized by Compaq Sr VP Bill Strecker
Revised save/restore format for 64b simulators
@ -4146,12 +4038,16 @@ Ken Harrenstein PDP-10 simulator
Bill Haygood PDP-8 information, simulator, and software
Jim Jaeger IBM 1401 information
Doug Jones PDP-8 information, simulator, and software
Al Kossow HP 21xx, Varian 620, TI 990, DEC documentation and software
Don Lewine Nova documentation and legal permissions
Scott McGregor PDP-11 UNIX legal permissions
Jeff Moffatt HP 2100 information, documentation, and software
Alec Muffett Solaris port testing
Dutch Owen Nova moving head disk debugging, Altair simulator
Dutch Owen Nova moving head disk debugging, Altair simulator,
IBM 1401 diagnostics, debugging, and magtape boot
Paul Pierce IBM 1401 diagnostics, media recovery
Bruce Ray Software, documentation, bug fixes, and new devices
for the Nova
Craig St Clair PDP documentation
Richard Schedler Public repository maintenance
Stephen Schultz PDP-11 2.11 BSD debugging

410
simh_swre.txt Normal file
View file

@ -0,0 +1,410 @@
To: Users
From: Bob Supnik
Subj: Sample Software Packages
Date: 1-Jan-01
This memorandum documents the sample software packages available to run
with the SIMH simulators. Many of these packages are available under
limited use licenses; please read the license terms included with the
software.
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2000, written by Robert M Supnik
Copyright (c) 1993-2000, 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"),
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
ROBERT M SUPNIK 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 Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
1. PDP-8
1.1 ESI-X
ESI-X is an interactive program for technical computation. It can
execute both immediate commands and stored programs (like BASIC). ESI-X
is provided as both source and as a binary loader format paper-tape
image. For more information see the documentation included with the
program. My thanks to Dave Waks, who wrote the program, and to Paul
Pierce and Tim Litt, who recovered the source from its archival medium.
To load and run ESI-X:
sim> load esix.bin
sim> run 5400
_TYPE 2+2.
2+2 = 4
1.2 FOCAL69
FOCAL69 is an interactive program for technical computations. It can
execute both immediate commands and stored programs (like BASIC). FOCAL69
is provided as a binary loader format paper-tape image. To load and
run FOCAL69:
sim> load focal69.bin
sim> run 200
*TYPE 2+2
= 4.000*
1.3 PDP-8 OS/8
OS/8 is the PDP-8's mass storage-based operating system. It provides a
program development and execution environment for assembler, BASIC, and
FORTRAN programs. OS/8 is provided under license, as is, without fee, by
Digital Equipment Corporation, for non-commercial use only. Please read
the enclosed license agreement for full terms and conditions. This license
agreement must be reproduced with any copy of the OS/8 disk images. My
thanks to Doug Jones of the University of Iowa, who provided the disk
images, and to Digital Equipment Corporation, which provided the license.
To boot and run OS/8:
sim> att rx0 os8sys_rx.dsk
sim> att rx1 os8f4_rx.dsk
sim> boot rx0
.DA dd-mmm-yy
.
Note that OS/8 only recognizes upper case characters. The first disk
(drive 0) is the system disk; it also includes BASIC. The second disk
(drive 1) includes FORTRAN.
2. PDP-11
2.1 UNIX V5, V6, V7
UNIX was first developed on the PDP-7; its first widespread usage was on
the PDP-11. UNIX provides a program development and execution environment
for assembler and C programs. UNIX V5, V7, V7 for the PDP-11 is provided
under license, as is, without fee, by Santa Cruz Organization (SCO), for
non-commercial use only. Please read the enclosed license agreement for
full terms and conditions. This license must be reproduced with any copy
of the UNIX V5, V6, V7 disk images. My thanks to PUPS, the PDP-11 UNIX
Preservation Society of Australia, which provided the disk images, and to
SCO, which provided the license.
2.1.1 UNIX V5
UNIX V5 is contained on a single RK05 disk image. To boot UNIX:
sim> set cpu 18b
sim> att rk0 unix_v5_rk.dsk
sim> boot rk
@unix
login: root
#ls -l
2.1.2 UNIX V6
UNIX V6 is contained on three RK05 disk images. To boot UNIX:
sim> set cpu 18b
sim> att rk0 unix0_v6_rk.dsk
sim> att rk1 unix1_v6_rk.dsk
sim> att rk3 unix3_v6_rk.dsk
sim> boot rk0
@unix
login: root
# ls -l
2.1.3 UNIX V7
NOTE: The V7 disk images with V2.3c and later releases are new and
replace the prior versions, which were corrupt.
UNIX V7 is contained on a single RL02 disk image. To boot UNIX:
sim> set cpu 18b
sim> set rl0 RL02
sim> att rl0 unix_v7_rl.dsk
sim> boot rl0
@boot
New Boot, known devices are hp ht rk rl rp tm vt
: rl(0,0)rl2unix
#
A smaller image is contained on a single RK05 disk image. To boot UNIX:
sim> set cpu 18b
sim> att rk0 unix_v7_rk.dsk
sim> boot rk0
@boot
New Boot, known devices are hp ht rk rl rp tm vt
: rk(0,0)rkunix
# STTY -LCASE
#
2.2 RT-11
RT-11 is the PDP-11's single user operating system. It provides a program
development and execution environment for assembler, BASIC, and FORTRAN
programs. RT-11 is provided under license, as is, without fee, by Mentec
Corporation, for non-commercial use ONLY ON THIS SIMULATOR. Please read
the enclosed license agreement for full terms and conditions. This license
agreement must be reproduced with any copy of the RT-11 disk image. My
thanks to John Wilson, a private collector, who provided the disk image
for RT-11 V4; to Megan Gentry, of Digital Equipment Corporation, who
provided the disk image for RT-11 V5.3; and to Mentec Corporation, which
provided the license.
2.2.1 RT-11 V4
RT-11 is contained in a single RK05 disk image. To boot and run RT-11:
sim> att rk0 rtv4_rk.dsk
sim> boot rk0
For RL, RM, and RP series disks, RT-11 expects to find a manufacturer's bad
block table in the last track of the disk. Therefore, INITialization of a
new (all zero's) disk fails, because there is no valid bad block table. To
create a minimal bad block table, use the SET <unit> BADBLOCK command.
2.2.2 RT-11 V5.3
RT-11 is contained in a single RL02 disk image. To boot and run RT-11:
sim> set rl0 rl02
sim> att rl0 rtv53_rl.dsk
sim> boot rl0
This is a full RT-11 distribution kit. It expects the user to copy the
distribution pack and generate a new system. This requires mounting
blank packs on RL1. When a blank pack is attached to the simulator,
a bad block table must be created with the SET <unit> BADBLOCK command.
3. Nova RDOS
RDOS is the Nova's real-time mass storage operating system. It provides a
program development and execution environment for assembler, BASIC, and
FORTRAN programs. RDOS is provided under license, as is, without fee, by
Data General Corporation, for non-commercial use only. Please read the
enclosed license agreement for full terms and conditions. This license
agreement must be reproduced with any copy of the RDOS disk image. My
thanks to Carl Friend, a private collector, who provided the disk image,
and to Data General Corporation, which provided the license.
To boot and run RDOS:
sim> att dp0 rdos_d31.dsk
sim> set tti dasher
sim> boot dp0
FILENAME? (cr)
DATE (mm/dd/yy)? xx/yy/zz
TIME (hh:mm:ss)? hh:mm:ss
R
list/e
4. PDP-1 LISP
PDP-1 LISP is an interactive interpreter for the Lisp language. It can
execute both interactive commands and stored programs. The startup
instructions for LISP are complicated; see the documentation included
with the program for details. My thanks to Peter Deutsch, who wrote the
program, to Gordon Greene, who typed it in from a printed listing, and
to Paul McJones, who helped with the final debug process.
5. PDP-7 SIM8
PDP-7 SIM8 is a PDP-8 simulator for the PDP-7. It implements an 8K
PDP-8/I with keyboard, teleprinter, reader, punch, and line printer.
It provides an interactive console environment for control and debug
of the simulated PDP-8. For more information see the documentation
included with the program. My thanks to Dave Waks, who wrote the
program, and to Paul Pierce and Tim Litt, who recovered the source
from its archival medium.
To load and run SIM8:
sim> load sim8.rim
sim> run
AC/ 0000
6. PDP-15 FOCAL
FOCAL15 is an interactive program for technical computations. It can
execute both immediate commands and stored programs (like BASIC). FOCAL15
is provided as a binary loader format paper-tape image. My thanks to Al
Kossow, who provided the binary image. To load and run FOCAL15:
sim> load focal15.bin
sim> run
*TYPE FSQT(2),!
= 1.4142
*
7. IBM 1401
7.1 Single Card "Koans"
One of the art forms for the IBM 1401 was packing useful programs into a
single punched card. Three samples are included:
i1401_ctolp.cd prints a card deck on the line printer
i1401_ctopu.cd copies a card deck to the card punch
i1401_hello.cd prints "HELLO WORLD" on the line printer and stops
To use the reproduction cards, simply insert them at the beginning of a
text file, terminated by newline. Attach the modified file to the card
reader, attach a blank file to the output device, and boot the card reader.
7.2 Diagnostic Tape
The software and writeup were provided by Charles Owens.
This 1401 Diagnostics tape is a bootable tape containing a series of 1401
diagnostics dating from about 1962. The 1407 Inquiry console is not used;
all control is via the front panel.
To run in the simulator, attach thusly:
sim> attach mt1 1401diag.mt
sim> attach lpt errorlist.txt
sim> boot mt1
The simulator will halt with IS = 433. At this point, you can set options
through the sense switches and memory.
D 1252 "1" Will cause headings to print for each test run.
Otherwise no printing will occur unless there are errors.
D SSB 1 Loop if an error is detected.
D SSC 1 Prints all test cases not just errors.
D SSD 1 Repeat the test run over and over.
D SSE 1 Halt if any error is detected, otherwise continue.
When you continue from this halt (use C to CON), the simulator will halt
at 3001. Enter C again and the tape will spin thru a series of basic
CPU diagnostics.
7.3 SPS
The software and writeup were provided by Charles Owens.
sps1.obj and sps2.obj are the object card decks are the "Symbolic
Programming System", a primitive assembler for the 1401 that predates
the better known and more functional Autocoder.
To use SPS, write an SPS program using your favourite editor (two
examples are provided, hello.sps and diaglist.sps). SPS decks are
not free-format, but operands must be placed in columns:
1 - 5 Line Count (optional)
6 - 7 Count (number of characters when defining a constant).
8 - 13 Label (six characters must start with alphabetic).
14 - 16 Opcode: Examples:
A = Add
B = Branch (must be d-mod for conditional)
BWZ = Branch if Wordmark or Zone
C = Compare
CC = Carriage Control (printer)
CS = CLear Storage
CU = Control Unit (e.g. tape)
CW = Clear Workmark
D = Divide
DC = Define Constant (no wordmark)
DCW = Define Constant (starts in 24, length in 6-7)
END = End of program
LCA = Load Characters
H = Halt
M = Multiply
MCE = Move and Edit
MCS = Move and Supress Zeros
MCW = Move Characters
MN = Move Numeric
MZ = Move Zone
ORG = Define Origin Point
P = Punch Card
R = Read Card
S = Subtract
SS = Stacker Select
SW = Set Wordmark
W = Write Line
ZA = Zero and Add
ZS = Zero and Subtract
Tape:
MCW %UX YYY W Write Tape from addr YYY w/o wordmarks)
LCA %UX YYY W Write Tape, Unit X from addr YYY w/wordmarks)
MCW %UX YYY R Read Tape from addr YYY w/o wordmarks)
LCA %UX YYY R Read Tape, Unit X from addr YYY w/wordmarks)
CU %UX M Write Tape Mark
CU %UX E Skip and Blank Tape
CU %UX B Backspace Record
CU %UX R Rewind Tape
CU %UX U Rewind and Unlaod tape
17 - 22 Address for A-operand (label or 4-digit actual address)
23 - 23 blank, + or - to adjust A-operand by a constant
24 - 26 3-digit number to adjust A-operand by if 23 is + or -
27 - 27 Index (?)
28 - 33 Address for B-operand
34 - 34 Blank, + or -
35 - 37 3-digit number of adjust B-address by if 34 is + or -
38 - 38 Index (?)
39 - 39 D-modifier for this instruction. Notes:
/ = Compare is unequal
S = Branch if Compare Equal
T = B is less than A
U = B is greater than A
L = Tape read error
K = Tape end of reel
40 - 55 Comments
The SPS deck should start with an ORG operation to specify where in storage
the program starts, and end with an END card, with an optional A-operand
showing where to start execution.
To assemble an SPS program, place the SPS source between the SPS1.OBJ and
the SPS2.OBJ deck, and another copy of the same source after the SPS2.OBJ
deck (SPS is a two-pass assembler). SPS prints a listing on LPT and punches
an object deck on CDP, ready to run.
A UNIX command script to assemble an SPS deck painlessly is in "sps". To
use the script, enter "sps programname". The script creates programname.lst
for the listing and programname.obj for the object deck. Windows users
are out of luck, for now.
8. HP2116 16K BASIC
HP BASIC is a paper-tape centric implementation of BASIC for a 16KW
HP2116. Device numbers correspond to the default simulator settings:
PTR = 10
TTY = 11
PTP = 12
The program is a complete but early BASIC and has one unsual requirement:
all programs must include a valid END statement to run correctly. My
thanks to Jeff Moffatt for providing the program.
To load and run BASIC:
sim> load basic1.abs
sim> run 100
READY
10 PRINT SQR(2)
20 END
RUN
1.41421
[end simh_swre.txt]