1
0
mirror of https://github.com/simh/simh.git synced 2026-05-02 06:15:23 +00:00

Notes For V3.3

RESTRICTION: The HP DS disk is not debugged.  DO NOT enable this
feature for normal operations.
WARNING: Massive changes in the PDP-11 make all previous SAVEd
file obsolete.  Do not attempt to use a PDP-11 SAVE file from a
prior release with V3.3!

1. New Features in 3.3

1.1 SCP

- Added -p (powerup) qualifier to RESET
- Changed SET <unit> ONLINE/OFFLINE to SET <unit> ENABLED/DISABLED
- Moved SET DEBUG under SET CONSOLE hierarchy
- Added optional parameter value to SHOW command
- Added output file option to SHOW command

1.2 PDP-11

- Separated RH Massbus adapter from RP controller
- Added TU tape support
- Added model emulation framework
- Added model details

1.3 VAX

- Separated out CVAX-specific features from core instruction simulator
- Implemented capability for CIS, octaword, compatibility mode instructions
- Added instruction display and parse for compatibility mode
- Changed SET CPU VIRTUAL=n to SHOW CPU VIRTUAL=n
- Added =n optional parameter to SHOW CPU HISTORY

1.4 Unibus/Qbus simulators (PDP-11, VAX, PDP-10)

- Simplified DMA API's
- Modified DMA peripherals to use simplified API's

1.5 HP2100 (all changes from Dave Bryan)

CPU	- moved MP into its own device; added MP option jumpers
	- modified DMA to allow disabling
	- modified SET CPU 2100/2116 to truncate memory > 32K
	- added -F switch to SET CPU to force memory truncation
	- modified WRU to be REG_HRO
	- added BRK and DEL to save console settings

DR	- provided protected tracks and "Writing Enabled" status bit
	- added "parity error" status return on writes for 12606
	- added track origin test for 12606
	- added SCP test for 12606
	- added "Sector Flag" status bit
	- added "Read Inhibit" status bit for 12606
	- added TRACKPROT modifier

LPS	- added SET OFFLINE/ONLINE, POWEROFF/POWERON
	- added fast/realistic timing
	- added debug printouts

LPT	- added SET OFFLINE/ONLINE, POWEROFF/POWERON

PTR	- added paper tape loop mode, DIAG/READER modifiers to PTR
	- added PV_LEFT to PTR TRLLIM register

CLK	- modified CLK to permit disable

1.6 IBM 1401, IBM 1620, Interdata 16b, SDS 940, PDP-10

- Added instruction history

1.7 H316, PDP-15, PDP-8

- Added =n optional value to SHOW CPU HISTORY

2. Bugs Fixed in 3.3

2.1 SCP

- Fixed comma-separated SET options (from Dave Bryan)
- Fixed duplicate HELP displays with user-specified commands

2.2 PDP-10

- Replicated RP register state per drive
- Fixed TU to set FCE on short record
- Fixed TU to return bit<15> in drive type
- Fixed TU format specification, 1:0 are don't cares
- Fixed TU handling of TMK status
- Fixed TU handling of DONE, ATA at end of operation
- Implemented TU write check

2.3 PDP-11

- Replicated RP register state per drive
- Fixed RQ, TQ to report correct controller type and stage 1 configuration
  flags on a Unibus system
- Fixed HK CS2<output_ready> flag

2.4 VAX

- Fixed parsing of indirect displacement modes in instruction input

2.5 HP2100 (all fixes from Dave Bryan)

CPU	- fixed S-register behavior on 2116
	- fixed LIx/MIx behavior for DMA on 2116 and 2100
	- fixed LIx/MIx behavior for empty I/O card slots

DP	- fixed enable/disable from either device
	- fixed ANY ERROR status for 12557A interface
	- fixed unattached drive status for 12557A interface
	- status cmd without prior STC DC now completes (12557A)
	- OTA/OTB CC on 13210A interface also does CLC CC
	- fixed RAR model
	- fixed seek check on 13210 if sector out of range

DQ	- fixed enable/disable from either device
	- shortened xtime from 5 to 3 (drive avg 156KW/second)
	- fixed not ready/any error status
	- fixed RAR model

DR	- fixed enable/disable from either device
	- fixed sector return in status word
	- fixed DMA last word write, incomplete sector fill value
	- fixed 12610 SFC operation
	- fixed current-sector determination

IPL	- fixed enable/disable from either device

LPS	- fixed status returns for error conditions
	- fixed handling of non-printing characters
	- fixed handling of characters after column 80
	- improved timing model accuracy for RTE

LPT	- fixed status returns for error conditions
	- fixed TOF handling so form remains on line 0

SYS	- fixed display of CCA/CCB/CCE instructions

2.5 PDP-15

FPP	- fixed URFST to mask low 9b of fraction
	- fixed exception PC setting
This commit is contained in:
Bob Supnik
2004-11-23 15:49:00 -08:00
committed by Mark Pizzolato
parent 2e00e1122f
commit b6393b36b4
131 changed files with 20920 additions and 4845 deletions

View File

@@ -25,6 +25,7 @@
cpu KS10 central processor
10-Nov-04 RMS Added instruction history
08-Oct-02 RMS Revised to build dib_tab dynamically
Added SHOW IOSPACE
30-Dec-01 RMS Added old PC queue
@@ -136,6 +137,15 @@
#define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_PC 0x40000000
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
a10 pc;
a10 ea;
d10 ir;
d10 ac; };
d10 *M = NULL; /* memory */
d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */
d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */
@@ -178,6 +188,9 @@ a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
jmp_buf save_env;
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
extern int32 sim_int_char;
extern int32 sim_interval;
@@ -189,6 +202,8 @@ extern UNIT tim_unit;
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);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
d10 adjsp (d10 val, a10 ea);
void ibp (a10 ea, int32 pflgs);
d10 ldb (a10 ea, int32 pflgs);
@@ -375,6 +390,8 @@ MTAB cpu_mod[] = {
{ UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
NULL, &show_iospace },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } };
DEVICE cpu_dev = {
@@ -742,7 +759,14 @@ for (indrct = inst, i = 0; i < ind_max; i++) { /* calc eff addr */
if (TST_IND (indrct)) indrct = Read (ea, MM_EA);
else break; }
if (i >= ind_max)
ABORT (STOP_IND); /* too many ind? stop */
ABORT (STOP_IND); /* too many ind? stop */
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].pc = pager_PC | HIST_PC;
hst[hst_p].ea = ea;
hst[hst_p].ir = inst;
hst[hst_p].ac = AC(ac); }
switch (op) { /* case on opcode */
/* UUO's (0000 - 0077) - checked against KS10 ucode */
@@ -2100,3 +2124,63 @@ if (rptr == NULL) return;
for (i = 0; i < AC_NUM; i++, rptr++) rptr->loc = (void *) (acbase + i);
return;
}
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 k, di, lnt;
char *cptr = (char *) desc;
t_stat r;
t_value sim_eval;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC AC EA IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
fprintf (st, "%06o ", h->pc & AMASK);
fprintf (st, "%012o ", h->ac);
fprintf (st, "%06o ", h->ea);
sim_eval = h->ir;
if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %012o", h->ir);
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View File

@@ -619,9 +619,6 @@ typedef struct pdp_dib DIB;
#define UNIBUS TRUE /* 18b only */
#define FST 0 /* Unibus 1 */
#define MAP 1 /* Unibus 3 */
#define DEV_RDX 8 /* default device radix */
/* I/O page layout */
@@ -739,10 +736,11 @@ typedef struct pdp_dib DIB;
/* Function prototypes */
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf, t_bool ub);
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool ub);
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool ub);
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool ub);
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf);
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf);
t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc);

View File

@@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: PDP-10 Simulator Usage
Date: 15-Jun-2004
Date: 15-Nov-2004
COPYRIGHT NOTICE
@@ -174,6 +174,17 @@ control registers for the interrupt system.
WRU 8 interrupt character
REG[0:127] 36 fast memory blocks
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 Pager
The pager contains the page maps for executive and user mode. The
@@ -417,7 +428,7 @@ to set the drive type to one of six disk types, or autosize:
The type options can be used only when a unit is not attached to a file.
Note that TOPS-10 V7.03 supported only the RP06 and RM03; V7.04 added
support for the RP07. TOPS-20 V4.1 also supported only the RP06 and
RM03. Units can be set ONLINE or OFFLINE.
RM03. Units can be set ENABLED or DISABLED.
The RP controller implements these registers:
@@ -467,7 +478,7 @@ the ability to make units write enabled or locked.
SET TUn LOCKED set unit n write locked
SET TUn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE.
Units can also be set ENABLED or DISABLED.
The magnetic tape controller implements these registers:

View File

@@ -394,7 +394,7 @@ for (i = 0; dibp = dib_tab[i]; i++ ) {
UBNXM_FAIL (pa, mode);
}
/* Mapped read and write routines - used by word-oriented Unibus devices */
/* Mapped read and write routines - used by standard Unibus devices on Unibus 1 */
a10 Map_Addr10 (a10 ba, int32 ub)
{
@@ -407,23 +407,23 @@ pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;
return pa10;
}
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf, t_bool ub)
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
{
uint32 lim;
a10 pa10;
lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
*buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
}
return 0;
}
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool ub)
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
{
uint32 lim;
a10 pa10;
@@ -431,16 +431,16 @@ a10 pa10;
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
for ( ; ba < lim; ba = ba + 2) { /* by words */
pa10 = Map_Addr10 (ba, ub); /* map addr */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
*buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
}
return 0;
}
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool ub)
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
{
uint32 lim;
a10 pa10;
@@ -448,16 +448,16 @@ static d10 mask = 0377;
lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |
(((d10) *buf++) << ubashf[ba & 3]); }
return 0;
}
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool ub)
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)
{
uint32 lim;
a10 pa10;
@@ -466,9 +466,9 @@ d10 val;
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
val = *buf++; /* get data */
if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;

View File

@@ -373,7 +373,7 @@ if ((fnc == FNC_PR) && (dvlnt == 0)) {
return SCPE_OK; }
for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
if (Map_ReadW (ba, 2, &wd10, MAP)) { /* get word, err? */
if (Map_ReadW (ba, 2, &wd10)) { /* get word, err? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
update_lpcs (CSA_ERR); /* set done */
break; }

View File

@@ -25,6 +25,7 @@
rp RH/RP/RM moving head disks
20-Sep-04 RMS Fixed bugs in replicated state, RP vs RM accuracy
04-Jan-04 RMS Changed sim_fsize calling sequence
23-Jul-03 RMS Fixed bug in read header stub
25-Apr-03 RMS Revised for extended file support
@@ -72,6 +73,8 @@
#define RP_MAXFR 32768 /* max transfer */
#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) drv_tab[d].sect)))
#define MBA_RP_CTRL 0 /* RP drive */
#define MBA_RM_CTRL 1 /* RM drive */
/* Flags in the unit flags word */
@@ -255,6 +258,8 @@
In theory, each drive can be a different type. The size field in
each unit selects the drive capacity for each drive and thus the
drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.
The RP07, despite its name, uses an RM-style controller.
*/
#define RM03_DTYPE 0
@@ -300,20 +305,21 @@
#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD)
struct drvtyp {
int sect; /* sectors */
int surf; /* surfaces */
int cyl; /* cylinders */
int size; /* #blocks */
int devtype; /* device type */
int32 sect; /* sectors */
int32 surf; /* surfaces */
int32 cyl; /* cylinders */
int32 size; /* #blocks */
int32 devtype; /* device type */
int32 ctrl; /* ctrl type */
};
struct drvtyp drv_tab[] = {
{ RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV },
{ RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV },
{ RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV },
{ RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV },
{ RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV },
{ RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV },
{ RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, MBA_RM_CTRL },
{ RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, MBA_RP_CTRL },
{ RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, MBA_RM_CTRL },
{ RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, MBA_RP_CTRL },
{ RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, MBA_RM_CTRL },
{ RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, MBA_RM_CTRL },
{ 0 } };
extern d10 *M; /* memory */
@@ -326,18 +332,20 @@ extern UNIT cpu_unit;
int32 rpcs1 = 0; /* control/status 1 */
int32 rpwc = 0; /* word count */
int32 rpba = 0; /* bus address */
int32 rpda = 0; /* track/sector */
int32 rpcs2 = 0; /* control/status 2 */
int32 rpds[RP_NUMDR] = { 0 }; /* drive status */
int32 rper1[RP_NUMDR] = { 0 }; /* error status 1 */
int32 rpdb = 0; /* data buffer */
int32 rpmr = 0; /* maint register */
int32 rpof = 0; /* offset */
int32 rpdc = 0; /* cylinder */
int32 rper2 = 0; /* error status 2 */
int32 rper3 = 0; /* error status 3 */
int32 rpec1 = 0; /* ECC correction 1 */
int32 rpec2 = 0; /* ECC correction 2 */
uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */
uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */
uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */
uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */
uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */
uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */
uint16 rpof[RP_NUMDR] = { 0 }; /* offset */
uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */
uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */
uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */
uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */
uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */
int32 rpiff = 0; /* INTR flip/flop */
int32 rp_stopioe = 1; /* stop on error */
int32 rp_swait = 10; /* seek time */
@@ -345,6 +353,7 @@ int32 rp_rwait = 10; /* rotate time */
static int32 reg_in_drive[32] = {
0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static char *rp_mapnam[MBA_RM_CTRL + 1] = { "RP", "RM" };
t_stat rp_rd (int32 *data, int32 PA, int32 access);
t_stat rp_wr (int32 data, int32 PA, int32 access);
@@ -354,6 +363,7 @@ t_stat rp_reset (DEVICE *dptr);
t_stat rp_boot (int32 unitno, DEVICE *dptr);
t_stat rp_attach (UNIT *uptr, char *cptr);
t_stat rp_detach (UNIT *uptr);
void set_rper (int32 flag, int32 drv);
void update_rpcs (int32 flags, int32 drv);
void rp_go (int32 drv, int32 fnc);
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
@@ -391,18 +401,20 @@ REG rp_reg[] = {
{ ORDATA (RPCS1, rpcs1, 16) },
{ ORDATA (RPWC, rpwc, 16) },
{ ORDATA (RPBA, rpba, 16) },
{ ORDATA (RPDA, rpda, 16) },
{ ORDATA (RPCS2, rpcs2, 16) },
{ ORDATA (RPDB, rpdb, 16) },
{ BRDATA (RPDA, rpda, 8, 16, RP_NUMDR) },
{ BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) },
{ BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) },
{ ORDATA (RPOF, rpof, 16) },
{ ORDATA (RPDC, rpdc, 16) },
{ ORDATA (RPER2, rper2, 16) },
{ ORDATA (RPER3, rper3, 16) },
{ ORDATA (RPEC1, rpec1, 16) },
{ ORDATA (RPEC2, rpec2, 16) },
{ ORDATA (RPMR, rpmr, 16) },
{ ORDATA (RPDB, rpdb, 16) },
{ BRDATA (RPHR, rmhr, 8, 16, RP_NUMDR) },
{ BRDATA (RPOF, rpof, 8, 16, RP_NUMDR) },
{ BRDATA (RPDC, rpdc, 8, 16, RP_NUMDR) },
{ BRDATA (RPER2, rper2, 8, 16, RP_NUMDR) },
{ BRDATA (RPER3, rper3, 8, 16, RP_NUMDR) },
{ BRDATA (RPEC1, rpec1, 8, 16, RP_NUMDR) },
{ BRDATA (RPEC2, rpec2, 8, 16, RP_NUMDR) },
{ BRDATA (RMMR, rpmr, 8, 16, RP_NUMDR) },
{ BRDATA (RMMR2, rmmr2, 8, 16, RP_NUMDR) },
{ FLDATA (IFF, rpiff, 0) },
{ FLDATA (INT, int_req, INT_V_RP) },
{ FLDATA (SC, rpcs1, CSR_V_ERR) },
@@ -497,7 +509,7 @@ case 002: /* RPBA */
*data = rpba = rpba & ~BA_MBZ;
break;
case 003: /* RPDA */
*data = rpda = rpda & ~DA_MBZ;
*data = rpda[drv] = rpda[drv] & ~DA_MBZ;
break;
case 004: /* RPCS2 */
*data = rpcs2 = (rpcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR;
@@ -520,7 +532,7 @@ case 011: /* RPDB */
*data = rpdb;
break;
case 012: /* RPMR */
*data = rpmr;
*data = rpmr[drv];
break;
case 013: /* RPDT */
*data = drv_tab[dtype].devtype;
@@ -529,28 +541,34 @@ case 014: /* RPSN */
*data = 020 | (drv + 1);
break;
case 015: /* RPOF */
*data = rpof = rpof & ~OF_MBZ;
*data = rpof[drv] = rpof[drv] & ~OF_MBZ;
break;
case 016: /* RPDC */
*data = rpdc = rpdc & ~DC_MBZ;
*data = rpdc[drv] = rpdc[drv] & ~DC_MBZ;
break;
case 017: /* RPCC, RMHR */
*data = rp_unit[drv].CYL;
if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is CC */
*data = rp_unit[drv].CYL;
else *data = rmhr[drv] ^ 0177777; /* RM is HR */
break;
case 020: /* RPER2, RMMR2 */
*data = rper2;
if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER2 */
*data = rper2[drv];
else *data = rmmr2[drv]; /* RM is MR2 */
break;
case 021: /* RPER3, RMER2 */
*data = rper3;
if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER3 */
*data = rper3[drv];
else *data = rper2[drv]; /* RM is ER2 */
break;
case 022: /* RPEC1 */
*data = rpec1;
*data = rpec1[drv];
break;
case 023: /* RPEC2 */
*data = rpec2;
*data = rpec2[drv];
break;
default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILR;
set_rper (ER1_ILR, drv);
update_rpcs (0, drv);
break; }
return SCPE_OK;
@@ -558,11 +576,12 @@ return SCPE_OK;
t_stat rp_wr (int32 data, int32 PA, int32 access)
{
int32 cs1f, drv, i, j;
int32 cs1f, drv, dtype, i, j;
UNIT *uptr;
cs1f = 0; /* no int on cs1 upd */
drv = GET_UNIT (rpcs2); /* get current unit */
dtype = GET_DTYPE (rp_unit[drv].flags); /* get drive type */
uptr = rp_dev.units + drv; /* get unit */
j = (PA >> 1) & 037; /* get reg offset */
if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */
@@ -570,9 +589,10 @@ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */
update_rpcs (CS1_SC, drv); /* request intr */
return SCPE_OK; }
if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */
rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */
set_rper (ER1_RMR, drv); /* won't write */
update_rpcs (0, drv);
return SCPE_OK; }
rmhr[drv] = data;
switch (j) { /* decode PA<5:1> */
case 000: /* RPCS1 */
@@ -591,7 +611,7 @@ case 000: /* RPCS1 */
rpcs2 = rpcs2 | CS2_NED; /* set error flag */
cs1f = CS1_SC; } /* req interrupt */
else if (sim_is_active (uptr))
rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */
set_rper (ER1_RMR, drv); /* won't write */
else if (data & CS1_GO) { /* start op */
uptr->FUNC = GET_FNC (data); /* set func */
if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */
@@ -610,9 +630,8 @@ case 002: /* RPBA */
rpba = data & ~BA_MBZ;
break;
case 003: /* RPDA */
if (access == WRITEB) data = (PA & 1)?
(rpda & 0377) | (data << 8): (rpda & ~0377) | data;
rpda = data & ~DA_MBZ;
if ((access == WRITEB) && (PA & 1)) data = data << 8;
rpda[drv] = data & ~DA_MBZ;
break;
case 004: /* RPCS2 */
if ((access == WRITEB) && (PA & 1)) data = data << 8;
@@ -626,8 +645,8 @@ case 004: /* RPCS2 */
drv = GET_UNIT (rpcs2);
break;
case 006: /* RPER1 */
if (access == WRITEB) break;
rper1[drv] = rper1[drv] & data;
if ((access == WRITEB) && (PA & 1)) data = data << 8;
rper1[drv] = data;
break;
case 007: /* RPAS */
if ((access == WRITEB) && (PA & 1)) break;
@@ -640,32 +659,28 @@ case 011: /* RPDB */
rpdb = data;
break;
case 012: /* RPMR */
if (access == WRITEB) data = (PA & 1)?
(rpmr & 0377) | (data << 8): (rpmr & ~0377) | data;
rpmr = data;
if ((access == WRITEB) && (PA & 1)) data = data << 8;
rpmr[drv] = data;
break;
case 015: /* RPOF */
if (access == WRITEB) data = (PA & 1)?
(rpof & 0377) | (data << 8): (rpof & ~0377) | data;
rpof = data & ~OF_MBZ;
rpof[drv] = data & ~OF_MBZ;
break;
case 016: /* RPDC */
if (access == WRITEB) data = (PA & 1)?
(rpdc & 0377) | (data << 8): (rpdc & ~0377) | data;
rpdc = data & ~DC_MBZ;
if ((access == WRITEB) && (PA & 1)) data = data << 8;
rpdc[drv] = data & ~DC_MBZ;
break;
case 005: /* RPDS */
case 010: /* RPLA */
case 013: /* RPDT */
case 014: /* RPSN */
case 017: /* RPDC, RMHR */
case 020: /* RPER2, RMMN2 */
case 017: /* RPCC, RMHR */
case 020: /* RPER2, RMMR2 */
case 021: /* RPER3, RMER2 */
case 022: /* RPEC1 */
case 023: /* RPEC2 */
break; /* read only */
default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILR;
set_rper (ER1_ILR, drv);
break; } /* end switch */
update_rpcs (cs1f, drv); /* update status */
return SCPE_OK;
@@ -684,26 +699,25 @@ if (uptr->flags & UNIT_DIS) { /* nx unit? */
update_rpcs (CS1_SC, drv); /* request intr */
return; }
if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */
rper1[drv] = rper1[drv] | ER1_ILF; /* not allowed */
rpds[drv] = rpds[drv] | DS_ATA; /* set attention */
set_rper (ER1_ILF, drv); /* set err, ATN */
update_rpcs (CS1_SC, drv); /* request intr */
return; }
dtype = GET_DTYPE (uptr->flags); /* get drive type */
rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */
dc = rpdc; /* assume seek, sch */
dc = rpdc[drv]; /* assume seek, sch */
switch (fnc) { /* case on function */
case FNC_DCLR: /* drive clear */
rpda = 0; /* clear disk addr */
rper1[drv] = rper2 = rper3 = 0; /* clear errors */
rpda[drv] = 0; /* clear disk addr */
rper1[drv] = rper2[drv] = rper3[drv] = 0; /* clear errors */
case FNC_NOP: /* no operation */
case FNC_RELEASE: /* port release */
return;
case FNC_PRESET: /* read-in preset */
rpdc = 0; /* clear disk addr */
rpda = 0;
rpof = 0; /* clear offset */
rpdc[drv] = 0; /* clear disk addr */
rpda[drv] = 0;
rpof[drv] = 0; /* clear offset */
case FNC_PACK: /* pack acknowledge */
rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */
return;
@@ -711,7 +725,7 @@ case FNC_PACK: /* pack acknowledge */
case FNC_OFFSET: /* offset mode */
case FNC_RETURN:
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
set_rper (ER1_UNS, drv); /* unsafe */
break; }
rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */
sim_activate (uptr, rp_swait); /* time operation */
@@ -723,12 +737,12 @@ case FNC_RECAL: /* recalibrate */
case FNC_SEEK: /* seek */
case FNC_SEARCH: /* search */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
set_rper (ER1_UNS, drv); /* unsafe */
break; }
if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */
(GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */
rper1[drv] = rper1[drv] | ER1_IAE;
(GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */
set_rper (ER1_IAE, drv);
break; }
rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */
t = abs (dc - uptr->CYL); /* cyl diff */
@@ -743,14 +757,14 @@ case FNC_WCHK: /* write check */
case FNC_READ: /* read */
case FNC_READH: /* read headers */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
set_rper (ER1_UNS, drv); /* unsafe */
break; }
rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */
rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE);
if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */
(GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */
rper1[drv] = rper1[drv] | ER1_IAE;
(GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */
set_rper (ER1_IAE, drv);
break; }
rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */
sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL)));
@@ -758,9 +772,8 @@ case FNC_READH: /* read headers */
return;
default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILF; /* not supported */
set_rper (ER1_ILF, drv); /* not supported */
break; }
rpds[drv] = rpds[drv] | DS_ATA; /* error, set attn */
update_rpcs (CS1_SC, drv); /* req intr */
return;
}
@@ -815,7 +828,7 @@ case FNC_SEEK: /* seek */
case FNC_WRITE: /* write */
if (uptr->flags & UNIT_WPRT) { /* write locked? */
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */
set_rper (ER1_WLE, drv); /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; }
case FNC_WCHK: /* write check */
@@ -823,9 +836,9 @@ case FNC_READ: /* read */
case FNC_READH: /* read headers */
ba = GET_UAE (rpcs1) | rpba; /* get byte addr */
wc10 = (0200000 - rpwc) >> 1; /* get PDP-10 wc */
da = GET_DA (rpdc, rpda, dtype) * RP_NUMWD; /* get disk addr */
da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */
if ((da + wc10) > drv_tab[dtype].size) { /* disk overrun? */
rper1[drv] = rper1[drv] | ER1_AOE;
set_rper (ER1_AOE, drv);
if (wc10 > (drv_tab[dtype].size - da))
wc10 = drv_tab[dtype].size - da; }
@@ -884,13 +897,13 @@ case FNC_READH: /* read headers */
da = da + twc10 + (RP_NUMWD - 1);
if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST;
da = da / RP_NUMWD;
rpda = da % drv_tab[dtype].sect;
rpda[drv] = da % drv_tab[dtype].sect;
da = da / drv_tab[dtype].sect;
rpda = rpda | ((da % drv_tab[dtype].surf) << DA_V_SF);
rpdc = da / drv_tab[dtype].surf;
rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF);
rpdc[drv] = da / drv_tab[dtype].surf;
if (err != 0) { /* error? */
rper1[drv] = rper1[drv] | ER1_PAR; /* set drive error */
set_rper (ER1_PAR, drv); /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
perror ("RP I/O error");
clearerr (uptr->fileref);
@@ -901,6 +914,16 @@ case FNC_WRITEH: /* write headers stub */
return SCPE_OK;
}
/* Set drive error */
void set_rper (int32 flag, int32 drv)
{
rper1[drv] = rper1[drv] | flag;
rpds[drv] = rpds[drv] | DS_ATA;
rpcs1 = rpcs1 | CS1_SC;
return;
}
/* Controller status update
Check for done transition
@@ -921,7 +944,8 @@ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0;
else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM;
if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL;
else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY);
if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA;
if (rper1[drv] | rper2[drv] | rper3[drv])
rpds[drv] = rpds[drv] | DS_ERR;
else rpds[drv] = rpds[drv] & ~DS_ERR;
rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag;
@@ -955,10 +979,7 @@ UNIT *uptr;
rpcs1 = CS1_DVA | CS1_DONE;
rpcs2 = CS2_IR | CS2_OR;
rpba = rpda = 0;
rpof = rpdc = 0;
rper2 = rper3 = 0;
rpec1 = rpec2 = 0;
rpba = rpwc = 0;
rpiff = 0; /* clear CSTB INTR */
int_req = int_req & ~INT_RP; /* clear intr req */
for (i = 0; i < RP_NUMDR; i++) {
@@ -969,7 +990,17 @@ for (i = 0; i < RP_NUMDR; i++) {
DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);
else if (uptr->flags & UNIT_DIS) rpds[i] = 0;
else rpds[i] = DS_DPR;
rper1[i] = 0; }
rper1[i] = 0;
rper2[i] = 0;
rper3[i] = 0;
rpda[i] = 0;
rpdc[i] = 0;
rpmr[i] = 0;
rpof[i] = 0;
rpec1[i] = 0;
rpec2[i] = 0;
rmmr2[i] = 0;
rmhr[i] = 0; }
return SCPE_OK;
}
@@ -1021,8 +1052,10 @@ return detach_unit (uptr);
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 dtype = GET_DTYPE (val);
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = drv_tab[GET_DTYPE (val)].size;
uptr->capac = drv_tab[dtype].size;
return SCPE_OK;
}

View File

@@ -25,6 +25,12 @@
tu RH11/TM03/TU45 magtape
23-Oct-04 RMS Fixed setting done on non data transfers
01-Oct-04 RMS Modified to set FCE on read short record, eof
Implemented write check
TM03 uses only den<2> for validity test
TMK is cleared by new motion command, not DCLR
14-Sep-04 RMS Fixed RIP value
25-Apr-03 RMS Revised for extended file support
28-Mar-03 RMS Added multiformat support
28-Feb-03 RMS Revised for magtape library
@@ -85,13 +91,14 @@
#define USTAT u3 /* unit status */
#define UDENS u4 /* unit density */
#define UD_UNK 0 /* unknown */
#define MT_MAXFR (1 << 16) /* max data buf */
#define MT_MAXFR (1 << 16) /* max data buf */
/* MTCS1 - 172440 - control/status 1 */
#define CS1_GO CSR_GO /* go */
#define CS1_V_FNC 1 /* function pos */
#define CS1_M_FNC 037 /* function mask */
#define CS1_N_FNC (CS1_M_FNC + 1)
#define CS1_FNC (CS1_M_FNC << CS1_V_FNC)
#define FNC_NOP 000 /* no operation */
#define FNC_UNLOAD 001 /* unload */
@@ -146,7 +153,7 @@
#define CS2_NEM 0004000 /* nx mem err */
#define CS2_NEF 0010000 /* nx fmter err */
#define CS2_PE 0020000 /* parity err NI */
#define CS2_WCE 0040000 /* write chk err NI */
#define CS2_WCE 0040000 /* write chk err */
#define CS2_DLT 0100000 /* data late NI */
#define CS2_MBZ (CS2_CLR | CS2_WCE)
#define CS2_RW (CS2_FMTR | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE)
@@ -214,6 +221,7 @@
/* MTDT - 172466 - drive type */
#define DT_NSA 0100000 /* not sect addr */
#define DT_TAPE 0040000 /* tape */
#define DT_PRES 0002000 /* slave present */
#define DT_TM03 0000040 /* TM03 formatter */
@@ -243,6 +251,7 @@
#define TC_ACC 0100000 /* accelerating NI */
#define TC_RW 0013777
#define TC_MBZ 0004000
#define TC_RIP ((TC_800 << TC_V_DEN) || (TC_10C << TC_V_FMT))
#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)
#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)
#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)
@@ -280,6 +289,8 @@ extern int32 int_vec[32];
extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */
extern int32 ubcs[UBANUM];
extern UNIT cpu_unit;
extern int32 sim_switches;
extern FILE *sim_deb;
int32 tucs1 = 0; /* control/status 1 */
int32 tuwc = 0; /* word count */
@@ -304,8 +315,11 @@ int32 reg_in_fmtr1[32] = { /* rmr if write + go */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int32 fmt_test[16] = { /* fmt bytes/10 wd */
5, 0, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32 den_test[8] = { /* valid densities */
0, 0, 0, 1, 1, 0, 0, 0 };
static char *tu_fname[CS1_N_FNC] = {
"NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",
"RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",
"20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",
"WRITE", "31", "32", "33", "READF", "35", "36" "READR" };
static uint8 *xbuf = NULL; /* xfer buffer */
t_stat tu_rd (int32 *data, int32 PA, int32 access);
@@ -317,6 +331,7 @@ t_stat tu_attach (UNIT *uptr, char *cptr);
t_stat tu_detach (UNIT *uptr);
t_stat tu_boot (int32 unitno, DEVICE *dptr);
void tu_go (int32 drv);
void set_tuer (int32 flag);
void update_tucs (int32 flag, int32 drv);
t_stat tu_map_err (UNIT *uptr, t_stat st);
@@ -381,7 +396,7 @@ DEVICE tu_dev = {
TU_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &tu_reset,
&tu_boot, &tu_attach, &tu_detach,
&tu_dib, DEV_UBUS };
&tu_dib, DEV_UBUS | DEV_DEBUG };
/* I/O dispatch routine, I/O addresses 17772440 - 17772472 */
@@ -435,8 +450,8 @@ case 012: /* MTMR */
*data = tumr;
break;
case 013: /* MTDT */
*data = DT_TAPE | DT_TM03 | ((tu_unit[drv].flags & UNIT_DIS)?
DT_OFF: (DT_PRES | DT_TU45));
*data = DT_NSA | DT_TAPE | DT_TM03 |
((tu_unit[drv].flags & UNIT_DIS)? DT_OFF: (DT_PRES | DT_TU45));
break;
case 014: /* MTSN */
*data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1);
@@ -445,7 +460,7 @@ case 015: /* MTTC */
*data = tutc = tutc & ~TC_MBZ;
break;
default: /* all others */
tuer = tuer | ER_ILR;
set_tuer (ER_ILR);
update_tucs (0, drv);
break; }
return SCPE_OK;
@@ -464,7 +479,7 @@ if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */
update_tucs (CS1_SC, drv); /* request intr */
return SCPE_OK; }
if (reg_in_fmtr1[j] && ((tucs1 & CS1_DONE) == 0)) { /* formatter busy? */
tuer = tuer | ER_RMR; /* won't write */
set_tuer (ER_RMR); /* won't write */
update_tucs (0, drv);
return SCPE_OK; }
@@ -485,7 +500,7 @@ case 000: /* MTCS1 */
tucs2 = tucs2 | CS2_NEF; /* set error flag */
cs1f = CS1_SC; } /* req interrupt */
else if (tucs1 & CS1_GO) { /* busy? */
if (tucs1 & CS1_DONE) tuer = tuer | ER_RMR;
if (tucs1 & CS1_DONE) set_tuer (ER_RMR);
else tucs2 = tucs2 | CS2_PGE; }
else {
tucs1 = (tucs1 & ~CS1_DRV) | (data & CS1_DRV);
@@ -544,7 +559,7 @@ case 013: /* MTDT */
case 014: /* MTSN */
break; /* read only */
default: /* all others */
tuer = tuer | ER_ILR;
set_tuer (ER_ILR);
break; } /* end switch */
update_tucs (cs1f, drv); /* update status */
return SCPE_OK;
@@ -560,10 +575,12 @@ UNIT *uptr;
fnc = GET_FNC (tucs1); /* get function */
den = GET_DEN (tutc); /* get density */
uptr = tu_dev.units + drv; /* get unit */
if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
">>TU%d STRT: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos);
if ((fnc != FNC_FCLR) && /* not clear & err */
((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */
tuer = tuer | ER_ILF; /* set error flag */
tufs = tufs | FS_ATA; /* exception */
set_tuer (ER_ILF); /* set err, ATN */
tucs1 = tucs1 & ~CS1_GO; /* clear go */
update_tucs (CS1_SC, drv); /* request intr */
return; }
@@ -574,45 +591,48 @@ switch (fnc) { /* case on function */
case FNC_FCLR: /* drive clear */
tuer = 0; /* clear errors */
tutc = tutc & ~TC_FCS; /* clear fc status */
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_TMK | FS_ERR);
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
sim_cancel (uptr); /* reset drive */
uptr->USTAT = 0;
case FNC_NOP:
tucs1 = tucs1 & ~CS1_GO; /* no operation */
return;
case FNC_RIP: /* read-in preset */
tutc = TC_800; /* density = 800 */
tutc = TC_RIP; /* density = 800 */
sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
tu_unit[0].USTAT = 0;
tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return;
case FNC_UNLOAD: /* unload */
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS;
set_tuer (ER_UNS);
break; }
detach_unit (uptr);
uptr->USTAT = FS_REW;
sim_activate (uptr, tu_time);
tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return;
case FNC_REWIND:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS;
set_tuer (ER_UNS);
break; }
uptr->USTAT = FS_PIP | FS_REW;
sim_activate (uptr, tu_time);
tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return;
case FNC_SPACEF:
space_test = FS_EOT;
case FNC_SPACER:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS;
set_tuer (ER_UNS);
break; }
if ((tufs & space_test) || ((tutc & TC_FCS) == 0)) {
tuer = tuer | ER_NXF;
set_tuer (ER_NXF);
break; }
uptr->USTAT = FS_PIP;
goto GO_XFER;
@@ -620,36 +640,30 @@ case FNC_SPACER:
case FNC_WCHKR: /* wchk = read */
case FNC_READR: /* read rev */
if (tufs & FS_BOT) { /* beginning of tape? */
tuer = tuer | ER_NXF;
set_tuer (ER_NXF);
break; }
goto DATA_XFER;
case FNC_WRITE: /* write */
if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */
((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */
tuer = tuer | ER_NXF;
set_tuer (ER_NXF);
break; }
case FNC_WREOF: /* write tape mark */
case FNC_ERASE: /* erase */
if (sim_tape_wrp (uptr)) { /* write locked? */
tuer = tuer | ER_NXF;
set_tuer (ER_NXF);
break; }
case FNC_WCHKF: /* wchk = read */
case FNC_READF: /* read */
DATA_XFER:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS;
set_tuer (ER_UNS);
break; }
if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */
tuer = tuer | ER_FER;
break; }
if (den_test[den] == 0) { /* invalid density? */
tuer = tuer | ER_NXF;
set_tuer (ER_FER);
break; }
if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */
/* else if (uptr->UDENS != den) { /* density mismatch? */
/* tuer = tuer | ER_NXF;
/* break; } */
uptr->USTAT = 0;
tucs1 = tucs1 & ~CS1_DONE; /* clear done */
GO_XFER:
@@ -660,10 +674,9 @@ GO_XFER:
return;
default: /* all others */
tuer = tuer | ER_ILF; /* not supported */
set_tuer (ER_ILF); /* not supported */
break; } /* end case function */
tucs1 = tucs1 & ~CS1_GO; /* clear go */
tufs = tufs | FS_ATA; /* set attn */
update_tucs (CS1_SC, drv); /* set intr */
return;
}
@@ -677,7 +690,7 @@ return;
t_stat tu_svc (UNIT *uptr)
{
int32 f, fmt, i, j, k, wc10, ba10;
int32 fnc, fmt, i, j, k, wc10, ba10;
int32 ba, fc, wc, drv, mpa10, vpn;
d10 val, v[4];
t_mtrlnt tbc;
@@ -691,7 +704,7 @@ if (uptr->USTAT & FS_REW) { /* rewind or unload? */
update_tucs (CS1_SC, drv); /* update status */
return SCPE_OK; }
f = GET_FNC (tucs1); /* get command */
fnc = GET_FNC (tucs1); /* get command */
fmt = GET_FMT (tutc); /* get format */
ba = GET_UAE (tucs1) | tuba; /* get bus address */
wc = 0200000 - tuwc; /* get word count */
@@ -700,7 +713,7 @@ wc10 = wc >> 1; /* 10 word count */
ba10 = ba >> 2; /* 10 word addr */
uptr->USTAT = 0; /* clear status */
switch (f) { /* case on function */
switch (fnc) { /* case on function */
/* Unit service - non-data transfer commands - set ATA when done */
@@ -712,7 +725,7 @@ case FNC_SPACEF: /* space forward */
break; }
}
while (tufc != 0);
if (tufc) tuer = tuer | ER_FCE;
if (tufc) set_tuer (ER_FCE);
else tutc = tutc & ~TC_FCS;
tufs = tufs | FS_ATA;
break;
@@ -725,7 +738,7 @@ case FNC_SPACER: /* space reverse */
break; }
}
while (tufc != 0);
if (tufc) tuer = tuer | ER_FCE;
if (tufc) set_tuer (ER_FCE);
else tutc = tutc & ~TC_FCS;
tufs = tufs | FS_ATA;
break;
@@ -770,11 +783,15 @@ case FNC_WCHKF: /* wcheck = read */
for (k = 0; k < 4; k++) v[k] = xbuf[j++];
val = (v[0] << 28) | (v[1] << 20) | (v[2] << 12) | (v[3] << 4);
if (fmt == TC_10C) val = val | ((d10) xbuf[j++] & 017);
if (f == FNC_READF) M[mpa10] = val;
if (fnc == FNC_READF) M[mpa10] = val; /* read? store */
else if (M[mpa10] != val) { /* wchk, mismatch? */
tucs2 = tucs2 | CS2_WCE; /* flag, stop */
break; }
mpa10 = mpa10 + 1; } /* end for */
tufc = tbc & 0177777;
tuwc = (tuwc + (i << 1)) & 0177777;
ba = ba + (i << 2);
if (tuwc) set_tuer (ER_FCE); /* short record? */
break;
case FNC_WRITE: /* write */
@@ -813,20 +830,38 @@ case FNC_WCHKR: /* wcheck = read */
val = ((fmt == TC_10C)? (((d10) xbuf [--j]) & 017): 0);
for (k = 0; k < 4; i++) v[k] = xbuf[--j];
val = val | (v[0] << 4) | (v[1] << 12) | (v[2] << 20) | (v[3] << 28);
if (f == FNC_READR) M[mpa10] = val;
if (fnc == FNC_READR) M[mpa10] = val; /* read? store */
else if (M[mpa10] != val) { /* wchk, mismatch? */
tucs2 = tucs2 | CS2_WCE; /* flag, stop */
break; }
mpa10 = mpa10 - 1; } /* end for */
tufc = tbc & 0177777;
tuwc = (tuwc + (i << 1)) & 0177777;
ba = ba - (i << 2);
if (tuwc) set_tuer (ER_FCE); /* short record? */
break; } /* end case */
tucs1 = (tucs1 & ~CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE);
tuba = ba & 0177777; /* update mem addr */
tucs1 = tucs1 & ~CS1_GO; /* clear go */
update_tucs (CS1_DONE, drv);
if (fnc >= FNC_XFER) update_tucs (CS1_DONE, drv); /* data xfer? */
else update_tucs (CS1_SC, drv); /* no, set attn */
if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
">>TU%d DONE: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos);
return SCPE_OK;
}
/* Formatter error */
void set_tuer (int32 flag)
{
tuer = tuer | flag;
tufs = tufs | FS_ATA;
tucs1 = tucs1 | CS1_SC;
return;
}
/* Controller status update
Check for done transition
@@ -877,29 +912,30 @@ t_stat tu_map_err (UNIT *uptr, t_stat st)
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* not attached */
tuer = tuer | ER_NXF; /* can't execute */
set_tuer (ER_NXF); /* can't execute */
case MTSE_OK: /* no error */
return SCPE_IERR;
case MTSE_TMK: /* end of file */
tufs = tufs | FS_TMK;
set_tuer (ER_FCE); /* also sets FCE */
break;
case MTSE_IOERR: /* IO error */
tuer = tuer | ER_VPE; /* flag error */
set_tuer (ER_VPE); /* flag error */
if (tu_stopioe) return SCPE_IOERR;
break;
case MTSE_INVRL: /* invalid rec lnt */
tuer = tuer | ER_VPE; /* flag error */
set_tuer (ER_VPE); /* flag error */
return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */
tuer = tuer | ER_CRC; /* set crc err */
set_tuer (ER_CRC); /* set crc err */
break;
case MTSE_EOM: /* end of medium */
tuer = tuer | ER_OPI; /* incomplete */
set_tuer (ER_OPI); /* incomplete */
break;
case MTSE_BOT: /* reverse into BOT */
break;
case MTSE_WRP: /* write protect */
tuer = tuer | ER_NXF; /* can't execute */
set_tuer (ER_NXF); /* can't execute */
break; }
return SCPE_OK;
}
@@ -913,9 +949,13 @@ UNIT *uptr;
tucs1 = CS1_DVA | CS1_DONE;
tucs2 = CS2_IR | CS2_OR;
tuba = tufc = 0;
tutc = tuer = 0;
tuba = 0;
tuwc = 0;
tufc = 0;
tuer = 0;
tufs = FS_FPR | FS_RDY;
if (sim_switches & SWMASK ('P')) tutc = 0; /* powerup? clr TC */
else tutc = tutc & ~TC_FCS; /* no, clr <fcs> */
tuiff = 0; /* clear CSTB INTR */
int_req = int_req & ~INT_TU; /* clear interrupt */
for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */