PDP11: TC11 - Revised to model TCCM correctly
As reported by Josh Dersch in #358 Read hardware notes: - While the TCCM error bit is a real flop, it is supposed to reflect the OR of the TCST error bits at all time, so it is updated on read. - A read of TCDT while the function is RALL clears DONE. Write hardware notes: - The TC11 behaves much more like a traditional DECtape controller than a typical PDP11 peripheral. In particular, execution is initiated/controlled by any write to TCCM, rather than setting the GO (DO) bit. Unless the function is STOP or STOP ALL, writing TCCM will put the selected tape in motion. - Writing GO (DO) clears DONE (READY) and the error flops in TCST. - Writing a 0 to ERROR clears the error flops in TCST. Because it is write 0 to clear (later controllers used write 1 to clear), the simulator has to know whether ERROR is actually written. - STOP ALL ignores select errors. Every other function is rejected if there is a select error. - An illegal operation (setting ILO) will stop the selected tape. - A write of TCDT while the function is RALL, WALL, or WTMK clears DONE (READY). RALL should not be included, but it saved a gate not to prevent it. - Because DONE (READY) may not be clear when an operation completes and DONE (READY) is set, the DT_SETDONE must test for DONE (READY) not being already set.
This commit is contained in:
parent
9a69fa8b49
commit
0a0bad9139
1 changed files with 73 additions and 41 deletions
112
PDP11/pdp11_tc.c
112
PDP11/pdp11_tc.c
|
@ -1,6 +1,6 @@
|
||||||
/* pdp11_tc.c: PDP-11 DECtape simulator
|
/* pdp11_tc.c: PDP-11 DECtape simulator
|
||||||
|
|
||||||
Copyright (c) 1993-2013, Robert M Supnik
|
Copyright (c) 1993-2016, Robert M Supnik
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
tc TC11/TU56 DECtape
|
tc TC11/TU56 DECtape
|
||||||
|
|
||||||
|
04-Dec-13 RMS Revised to model TCCM correctly (Josh Dersch)
|
||||||
23-Oct-13 RMS Revised for new boot setup routine
|
23-Oct-13 RMS Revised for new boot setup routine
|
||||||
23-Jun-06 RMS Fixed switch conflict in ATTACH
|
23-Jun-06 RMS Fixed switch conflict in ATTACH
|
||||||
10-Feb-06 RMS READ sets extended data bits in TCST (Alan Frisbie)
|
10-Feb-06 RMS READ sets extended data bits in TCST (Alan Frisbie)
|
||||||
|
@ -274,11 +275,11 @@ extern int32 int_req[IPL_HLVL];
|
||||||
#define LOG_RW 0x2
|
#define LOG_RW 0x2
|
||||||
#define LOG_BL 0x4
|
#define LOG_BL 0x4
|
||||||
|
|
||||||
#define DT_SETDONE tccm = tccm | CSR_DONE; \
|
#define DT_SETDONE if ((tccm & (CSR_DONE|CSR_IE)) == CSR_IE) \
|
||||||
if (tccm & CSR_IE) \
|
SET_INT (DTA); \
|
||||||
SET_INT (DTA)
|
tccm = tccm | CSR_DONE
|
||||||
#define DT_CLRDONE tccm = tccm & ~CSR_DONE; \
|
#define DT_CLRDONE CLR_INT (DTA); \
|
||||||
CLR_INT (DTA)
|
tccm = tccm & ~CSR_DONE
|
||||||
#define ABS(x) (((x) < 0)? (-(x)): (x))
|
#define ABS(x) (((x) < 0)? (-(x)): (x))
|
||||||
|
|
||||||
int32 tcst = 0; /* status */
|
int32 tcst = 0; /* status */
|
||||||
|
@ -411,7 +412,14 @@ DEVICE dt_dev = {
|
||||||
&dt_description
|
&dt_description
|
||||||
};
|
};
|
||||||
|
|
||||||
/* IO dispatch routines, I/O addresses 17777340 - 17777350 */
|
/* IO dispatch routines, I/O addresses 17777340 - 17777350
|
||||||
|
|
||||||
|
Read hardware notes:
|
||||||
|
|
||||||
|
- While the TCCM error bit is a real flop, it is supposed to reflect
|
||||||
|
the OR of the TCST error bits at all time, so it is updated on read.
|
||||||
|
- A read of TCDT while the function is RALL clears DONE.
|
||||||
|
*/
|
||||||
|
|
||||||
t_stat dt_rd (int32 *data, int32 PA, int32 access)
|
t_stat dt_rd (int32 *data, int32 PA, int32 access)
|
||||||
{
|
{
|
||||||
|
@ -456,6 +464,28 @@ switch (j) {
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Write hardware notes:
|
||||||
|
|
||||||
|
- The TC11 behaves much more like a traditional DECtape controller
|
||||||
|
than a typical PDP11 peripheral. In particular, execution is
|
||||||
|
initiated/controlled by any write to TCCM, rather than setting
|
||||||
|
the GO (DO) bit. Unless the function is STOP or STOP ALL, writing
|
||||||
|
TCCM will put the selected tape in motion.
|
||||||
|
- Writing GO (DO) clears DONE (READY) and the error flops in TCST.
|
||||||
|
- Writing a 0 to ERROR clears the error flops in TCST. Because it
|
||||||
|
is write 0 to clear (later controllers used write 1 to clear),
|
||||||
|
the simulator has to know whether ERROR is actually written.
|
||||||
|
- STOP ALL ignores select errors. Every other function is rejected
|
||||||
|
if there is a select error.
|
||||||
|
- An illegal operation (setting ILO) will stop the selected tape.
|
||||||
|
- A write of TCDT while the function is RALL, WALL, or WTMK clears
|
||||||
|
DONE (READY). RALL should not be included, but it saved a gate
|
||||||
|
not to prevent it.
|
||||||
|
- Because DONE (READY) may not be clear when an operation completes
|
||||||
|
and DONE (READY) is set, the DT_SETDONE must test for DONE (READY)
|
||||||
|
not being already set.
|
||||||
|
*/
|
||||||
|
|
||||||
t_stat dt_wr (int32 data, int32 PA, int32 access)
|
t_stat dt_wr (int32 data, int32 PA, int32 access)
|
||||||
{
|
{
|
||||||
int32 i, j, unum, old_tccm, fnc;
|
int32 i, j, unum, old_tccm, fnc;
|
||||||
|
@ -473,42 +503,44 @@ switch (j) {
|
||||||
case 001: /* TCCM */
|
case 001: /* TCCM */
|
||||||
old_tccm = tccm; /* save prior */
|
old_tccm = tccm; /* save prior */
|
||||||
if (access == WRITEB)
|
if (access == WRITEB)
|
||||||
data = (PA & 1)? (tccm & 0377) | (data << 8): (tccm & ~0377) | data;
|
data = (PA & 1)? ((tccm & 0377) | (data << 8)): ((tccm & ~0377) | data);
|
||||||
if ((data & CSR_IE) == 0)
|
if ((data & CSR_IE) == 0) /* clearing IE? */
|
||||||
CLR_INT (DTA);
|
CLR_INT (DTA); /* clear intr */
|
||||||
else if ((((tccm & CSR_IE) == 0) && (tccm & CSR_DONE)) ||
|
else if ((tccm & (CSR_DONE|CSR_IE)) == CSR_DONE) /* setting, DON'IE = DON? */
|
||||||
(data & CSR_DONE)) SET_INT (DTA);
|
SET_INT (DTA); /* set intr */
|
||||||
tccm = (tccm & ~CSR_RW) | (data & CSR_RW);
|
tccm = (tccm & ~CSR_RW) | (data & CSR_RW); /* merge data */
|
||||||
if ((data & CSR_GO) && (tccm & CSR_DONE)) { /* new cmd? */
|
if ((data & CSR_GO) != 0) { /* GO (DO) set? */
|
||||||
tcst = tcst & ~STA_ALLERR; /* clear errors */
|
tcst = tcst & ~STA_ALLERR; /* clear errors */
|
||||||
tccm = tccm & ~(CSR_ERR | CSR_DONE); /* clear done, err */
|
tccm = tccm & ~(CSR_ERR|CSR_DONE); /* clear done, err flops */
|
||||||
CLR_INT (DTA); /* clear int */
|
|
||||||
if ((old_tccm ^ tccm) & CSR_UNIT)
|
|
||||||
dt_deselect (old_tccm);
|
|
||||||
unum = CSR_GETUNIT (tccm); /* get drive */
|
|
||||||
fnc = CSR_GETFNC (tccm); /* get function */
|
|
||||||
if (fnc == FNC_STOP) { /* stop all? */
|
|
||||||
sim_activate (&dt_dev.units[DT_TIMER], dt_ctime);
|
|
||||||
for (i = 0; i < DT_NUMDR; i++)
|
|
||||||
dt_stopunit (dt_dev.units + i); /* stop unit */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
uptr = dt_dev.units + unum;
|
|
||||||
if (uptr->flags & UNIT_DIS) /* disabled? */
|
|
||||||
dt_seterr (uptr, STA_SEL); /* select err */
|
|
||||||
if ((fnc == FNC_WMRK) || /* write mark? */
|
|
||||||
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
|
|
||||||
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
|
|
||||||
dt_seterr (uptr, STA_ILO); /* illegal op */
|
|
||||||
if (!(tccm & CSR_ERR))
|
|
||||||
dt_newsa (tccm);
|
|
||||||
}
|
}
|
||||||
else if ((tccm & CSR_ERR) == 0) { /* clear err? */
|
else if (((data & CSR_ERR) == 0) && /* error bit clear? */
|
||||||
tcst = tcst & ~STA_RWERR;
|
((access != WRITEB) || ((PA & 1) != 0))) { /* not write low byte? */
|
||||||
if (tcst & STA_ALLERR)
|
tcst = tcst & ~STA_ALLERR; /* clear errors */
|
||||||
tccm = tccm | CSR_ERR;
|
tccm = tccm & ~CSR_ERR; /* clear err flop */
|
||||||
}
|
}
|
||||||
break;
|
if (((old_tccm ^ tccm) & CSR_UNIT) != 0) /* unit change? */
|
||||||
|
dt_deselect (old_tccm); /* deselect all */
|
||||||
|
unum = CSR_GETUNIT (tccm); /* get drive */
|
||||||
|
fnc = CSR_GETFNC (tccm); /* get function */
|
||||||
|
if (fnc == FNC_STOP) { /* stop all? */
|
||||||
|
sim_activate (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */
|
||||||
|
for (i = 0; i < DT_NUMDR; i++) /* loop thru units */
|
||||||
|
dt_stopunit (dt_dev.units + i); /* stop unit */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uptr = dt_dev.units + unum;
|
||||||
|
if (uptr->flags & UNIT_DIS) /* disabled? */
|
||||||
|
dt_seterr (uptr, STA_SEL); /* select err */
|
||||||
|
if ((fnc == FNC_WMRK) || /* write mark? */
|
||||||
|
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
|
||||||
|
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
|
||||||
|
dt_seterr (uptr, STA_ILO); /* illegal op */
|
||||||
|
if ((tccm & CSR_ERR) != 0) { /* error? */
|
||||||
|
dt_stopunit (uptr); /* stop the unit */
|
||||||
|
DT_SETDONE; /* set done at once */
|
||||||
|
}
|
||||||
|
else dt_newsa (tccm); /* new function */
|
||||||
|
break;
|
||||||
|
|
||||||
case 002: /* TCWC */
|
case 002: /* TCWC */
|
||||||
tcwc = data; /* word write only! */
|
tcwc = data; /* word write only! */
|
||||||
|
|
Loading…
Add table
Reference in a new issue