I1620: Add deferred IO mode for slow devices

The major change is the implementation of deferred IO - a more
accurate implementation of the 1620's "stop in its tracks" IO model.
When a device uses deferred IO, instruction execution is suspended
until the IO completes successfully. Operator interruptions, errors,
and so on do not return to instruction execution; this only occurs if
the IO completes successfully or the command SET CPU RELEASE is given
(equivalent of pressing the RELEASE button). Otherwise, the current IO
operation continues to execute.

Only the console typewriter and paper tape reader/punch currently
implement deferred IO; there are operational issues with those devices
that require more accurate modeling. The card reader/punch, line
printer, and disk still execute IO "instantaneously". It's not all
that hard to convert an instantaneous device to deferred operation,
but there's no point in doing so (and possibly introducing new bugs)
unless there's an actual operational issue. The 1620 doesn't have
overlapped IO, so programs can't tell the difference, by and large.

A number of other issues have been addressed as well, including the
bizarre "treat RM as 0 in the Q field" required by MI-015; the
treatment of non-existent indicators as always off; and various other
tweaks.

I've run CU01 (again), which at least gives typewriter and paper-tape
IO a basic workout; and it works. I leave more detailed testing to
people who know the machine better than I do.

The documentation has been updated to include Tom's detailed breakdown
of IO handling for all IO operations on the typewriter, paper-tape
reader/punch, card reader/punch, and line printer.
This commit is contained in:
Bob Supnik 2017-05-29 13:34:55 -07:00 committed by Mark Pizzolato
parent df627b0cb1
commit a750171c30
7 changed files with 428 additions and 353 deletions

View file

@ -433,7 +433,7 @@ switch (op) { /* decode op */
case OP_DN: case OP_DN:
/* DN punches all characters the same as WN except that a flagged /* DN punches all characters the same as WN except that a flagged
zero is punched as a hypehen (-) instead of a flagged zero is punched as a hyphen (-) instead of a flagged
zero ([). Punching begins at the P address and continues until zero ([). Punching begins at the P address and continues until
the last digit of the storage module containing the P address the last digit of the storage module containing the P address
has been punched. If the amount of data to be punched is an has been punched. If the amount of data to be punched is an

View file

@ -26,6 +26,7 @@
This CPU module incorporates code and comments from the 1620 simulator by This CPU module incorporates code and comments from the 1620 simulator by
Geoff Kuenning, with his permission. Geoff Kuenning, with his permission.
26-May-17 RMS Added deferred IO mode for slow devices
20-May-17 RMS Changed to commit PC on certain stops 20-May-17 RMS Changed to commit PC on certain stops
Added SET CPU RELEASE command Added SET CPU RELEASE command
Undefined indicators don't throw an error (Dave Wise) Undefined indicators don't throw an error (Dave Wise)
@ -82,6 +83,20 @@
it was nicknamed CADET (Can't Add, Doesn't Even Try). The Model 2 does it was nicknamed CADET (Can't Add, Doesn't Even Try). The Model 2 does
adds in hardware and uses the add table memory for index registers. adds in hardware and uses the add table memory for index registers.
The 1620 has no concept of overlapped IO. When an IO instruction is
issued, instruction execution is suspended until the IO is complete.
For "fast" devices, like the disk, IO is done in an instantaneous burst.
"Slow" devices have the option of going character-by-character, with
delays in between. This allows for operator intervention, such as
^E or changing paper tapes.
The simulated IO state for character-by-character IO is:
cpuio_mode set if IO in progress
cpuio_opc saved IO opcode
cpuio_cnt character counter; increments
PAR P address; increments
This routine is the instruction decode routine for the IBM 1620. This routine is the instruction decode routine for the IBM 1620.
It is called from the simulator control program to execute It is called from the simulator control program to execute
instructions in simulated memory, starting at the simulated PC. instructions in simulated memory, starting at the simulated PC.
@ -135,6 +150,9 @@ uint32 idxe = 0; /* index enable */
uint32 idxb = 0; /* index band */ uint32 idxb = 0; /* index band */
uint32 io_stop = 1; /* I/O stop */ uint32 io_stop = 1; /* I/O stop */
uint32 ar_stop = 1; /* arith stop */ uint32 ar_stop = 1; /* arith stop */
uint32 cpuio_inp = 0; /* IO in progress */
uint32 cpuio_opc = 0;
uint32 cpuio_cnt = 0;
int32 ind_max = 16; /* iadr nest limit */ int32 ind_max = 16; /* iadr nest limit */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */ int32 pcq_p = 0; /* PC queue ptr */
@ -227,6 +245,9 @@ REG cpu_reg[] = {
{ FLDATA (WRCHK, ind[IN_WRCHK], 0) }, { FLDATA (WRCHK, ind[IN_WRCHK], 0) },
{ FLDATA (ARSTOP, ar_stop, 0) }, { FLDATA (ARSTOP, ar_stop, 0) },
{ FLDATA (IOSTOP, io_stop, 0) }, { FLDATA (IOSTOP, io_stop, 0) },
{ FLDATA (IOINP, cpuio_inp, 0), REG_RO },
{ DRDATA (IOOPC, cpuio_opc, 6), REG_RO },
{ DRDATA (IOCNT, cpuio_cnt, 16), REG_RO },
{ BRDATA (IND, ind, 10, 1, NUM_IND) }, { BRDATA (IND, ind, 10, 1, NUM_IND) },
{ FLDATA (IAE, iae, 0) }, { FLDATA (IAE, iae, 0) },
{ FLDATA (IDXE, idxe, 0) }, { FLDATA (IDXE, idxe, 0) },
@ -349,7 +370,7 @@ const int32 op_table[100] = {
0, 0,
IF_IDX + IF_VPA + IF_VQA, /* 70: MA */ IF_IDX + IF_VPA + IF_VQA, /* 70: MA */
IF_EDT + IF_VPA + IF_VQA, /* MF */ IF_EDT + IF_VPA + IF_VQA, /* MF */
IF_EDT + IF_VPA + IF_VQA, /* MF */ IF_EDT + IF_VPA + IF_VQA, /* TNS */
IF_EDT + IF_VPA + IF_VQA, /* TNF */ IF_EDT + IF_VPA + IF_VQA, /* TNF */
0, 0,
0, 0,
@ -517,6 +538,10 @@ while (reason == SCPE_OK) { /* loop until halted */
if ((reason = sim_process_event ())) if ((reason = sim_process_event ()))
break; break;
} }
if (cpuio_inp != 0) { /* IO in progress? */
sim_interval = sim_interval - 1; /* tick & continue */
continue;
}
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */ reason = STOP_IBKPT; /* stop simulation */
@ -1082,6 +1107,8 @@ for (i = 0; commit_pc[i] != 0; i++) { /* check stop code */
actual_PC = PC; /* save cur PC for RLS */ actual_PC = PC; /* save cur PC for RLS */
pcq_r->qptr = pcq_p; /* update pc q ptr */ pcq_r->qptr = pcq_p; /* update pc q ptr */
upd_ind (); upd_ind ();
if (cpuio_inp != 0) /* flag IO in progress */
sim_printf ("\r\nIO in progress");
return reason; return reason;
} }
@ -2131,6 +2158,28 @@ M[d] = M[d] | sign; /* set result sign */
return SCPE_OK; return SCPE_OK;
} }
/* Set and clear IO in progress */
t_stat cpuio_set_inp (uint32 op, UNIT *uptr)
{
cpuio_inp = 1;
cpuio_opc = op;
cpuio_cnt = 0;
if (uptr != NULL)
sim_activate_abs (uptr, uptr->wait);
return SCPE_OK;
}
t_stat cpuio_clr_inp (UNIT *uptr)
{
cpuio_inp = 0;
cpuio_opc = 0;
cpuio_cnt = 0;
if (uptr != NULL)
sim_cancel (uptr);
return SCPE_OK;
}
/* Reset routine */ /* Reset routine */
t_stat cpu_reset (DEVICE *dptr) t_stat cpu_reset (DEVICE *dptr)
@ -2142,6 +2191,8 @@ PR1 = IR2 = 1; /* invalidate PR1,IR2 */
ind[0] = 0; ind[0] = 0;
for (i = IN_SW4 + 1; i < NUM_IND; i++) /* init indicators */ for (i = IN_SW4 + 1; i < NUM_IND; i++) /* init indicators */
ind[i] = 0; ind[i] = 0;
if (cpuio_inp != 0) /* IO in progress? */
cpu_set_release (NULL, 0, NULL, NULL); /* clear IO */
if (cpu_unit.flags & IF_IA) /* indirect enabled? */ if (cpu_unit.flags & IF_IA) /* indirect enabled? */
iae = 1; iae = 1;
else iae = 0; else iae = 0;
@ -2164,8 +2215,21 @@ return SCPE_OK;
t_stat cpu_set_release (UNIT *uptr, int32 val, CONST char *cptr, void *desc) t_stat cpu_set_release (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{ {
if (actual_PC == ADDR_A (saved_PC, INST_LEN)) { /* one instr ahead? */ uint32 i;
saved_PC = actual_PC; /* return */ DEVICE *dptr;
if (cpuio_inp != 0) { /* IO in progress? */
cpuio_inp = 0;
cpuio_opc = 0;
cpuio_cnt = 0;
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
if (((dptr->flags & DEV_DEFIO) != 0) && (dptr->reset != NULL))
dptr->reset (dptr);
}
sim_printf ("IO operation canceled\n");
}
else if (actual_PC == ADDR_A (saved_PC, INST_LEN)) { /* one instr ahead? */
saved_PC = actual_PC;
sim_printf ("New PC = %05d\n", saved_PC); sim_printf ("New PC = %05d\n", saved_PC);
} }
else sim_printf ("PC unchanged\n"); else sim_printf ("PC unchanged\n");

View file

@ -27,6 +27,7 @@
I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate
Archives for their help in gathering documentation about the IBM 1620. Archives for their help in gathering documentation about the IBM 1620.
23-May-17 RMS MARCHK is indicator 8, not 18 (Dave Wise)
19-May-17 RMS Added option for Model I diagnostic mode (Dave Wise) 19-May-17 RMS Added option for Model I diagnostic mode (Dave Wise)
05-Feb-15 TFM Added definitions for flagged RM, GM, NB 05-Feb-15 TFM Added definitions for flagged RM, GM, NB
22-May-10 RMS Added check for 64b definitions 22-May-10 RMS Added check for 64b definitions
@ -113,6 +114,7 @@
#define IN_SW4 4 /* sense switch 4 */ #define IN_SW4 4 /* sense switch 4 */
#define IN_RDCHK 6 /* read check (I/O error) */ #define IN_RDCHK 6 /* read check (I/O error) */
#define IN_WRCHK 7 /* write check (I/O error) */ #define IN_WRCHK 7 /* write check (I/O error) */
#define IN_MARCHK 8 /* MAR check - diag only */
#define IN_LAST 9 /* last card was just read */ #define IN_LAST 9 /* last card was just read */
#define IN_HP 11 /* high or positive result */ #define IN_HP 11 /* high or positive result */
#define IN_EZ 12 /* equal or zero result */ #define IN_EZ 12 /* equal or zero result */
@ -121,7 +123,6 @@
#define IN_EXPCHK 15 /* floating exponent check */ #define IN_EXPCHK 15 /* floating exponent check */
#define IN_MBREVEN 16 /* even parity check */ #define IN_MBREVEN 16 /* even parity check */
#define IN_MBRODD 17 /* odd parity check */ #define IN_MBRODD 17 /* odd parity check */
#define IN_MARCHK 18 /* MAR check - diag only */
#define IN_ANYCHK 19 /* any of read, write, even/odd */ #define IN_ANYCHK 19 /* any of read, write, even/odd */
#define IN_PRCHK 25 /* printer check */ #define IN_PRCHK 25 /* printer check */
#define IN_IXN 30 /* IX neither */ #define IN_IXN 30 /* IX neither */
@ -235,6 +236,15 @@ enum opcodes {
OP_BBT = 90, OP_BMK, OP_ORF, OP_ANDF, OP_CPLF, /* 90 - 99 */ OP_BBT = 90, OP_BMK, OP_ORF, OP_ANDF, OP_CPLF, /* 90 - 99 */
OP_EORF, OP_OTD, OP_DTO }; OP_EORF, OP_OTD, OP_DTO };
/* Device flags */
#define DEV_DEFIO (1 << (DEV_V_UF + 0))
/* Function declarations */
t_stat cpuio_set_inp (uint32 op, UNIT *uptr);
t_stat cpuio_clr_inp (UNIT *uptr);
extern const int8 cdr_to_alp[128]; extern const int8 cdr_to_alp[128];
extern const int8 alp_to_cdp[256]; extern const int8 alp_to_cdp[256];

View file

@ -26,6 +26,8 @@
ptr 1621 paper tape reader ptr 1621 paper tape reader
ptp 1624 paper tape punch ptp 1624 paper tape punch
26-May-17 RMS Added deferred IO
25-May-17 RMS Fixed treatment of X0C82 on RN (Tom McBride)
18-May-17 RMS Separated EOF error from other IO errors (Dave Wise) 18-May-17 RMS Separated EOF error from other IO errors (Dave Wise)
23-Feb-15 TFM Fixed RA, RBPT to preserve flags on RM at end (Tom McBride) 23-Feb-15 TFM Fixed RA, RBPT to preserve flags on RM at end (Tom McBride)
09-Feb-15 TFM Fixed numerous translation problems (Tom McBride) 09-Feb-15 TFM Fixed numerous translation problems (Tom McBride)
@ -45,17 +47,23 @@
#define PT_C 0x10 /* C */ #define PT_C 0x10 /* C */
#define PT_FD 0x7F /* deleted */ #define PT_FD 0x7F /* deleted */
static uint32 ptr_mode = 0; /* normal/binary */
static uint32 ptp_mode = 0;
extern uint8 M[MAXMEMSIZE]; extern uint8 M[MAXMEMSIZE];
extern uint8 ind[NUM_IND]; extern uint8 ind[NUM_IND];
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern uint32 io_stop; extern uint32 io_stop;
extern uint32 PAR, cpuio_opc, cpuio_cnt;
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr); t_stat ptr_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr); t_stat ptr_boot (int32 unitno, DEVICE *dptr);
t_stat ptr_read (uint8 *c, t_bool ignfeed); t_stat ptr_read (uint8 *c, t_bool ignfeed);
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr); t_stat ptp_reset (DEVICE *dptr);
t_stat ptp_write (uint32 c); t_stat ptp_write (uint32 c);
t_stat ptp_num (uint32 pa, uint32 len, t_bool dump); t_stat ptp_num (void);
/* PTR data structures /* PTR data structures
@ -65,11 +73,13 @@ t_stat ptp_num (uint32 pa, uint32 len, t_bool dump);
*/ */
UNIT ptr_unit = { UNIT ptr_unit = {
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT
}; };
REG ptr_reg[] = { REG ptr_reg[] = {
{ FLDATA (BIN, ptr_mode, 0) },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ NULL } { NULL }
}; };
@ -77,7 +87,8 @@ DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL, "PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8, 1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset, NULL, NULL, &ptr_reset,
&ptr_boot, NULL, NULL &ptr_boot, NULL, NULL,
NULL, DEV_DEFIO
}; };
/* PTP data structures /* PTP data structures
@ -88,11 +99,13 @@ DEVICE ptr_dev = {
*/ */
UNIT ptp_unit = { UNIT ptp_unit = {
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, SERIAL_OUT_WAIT)
}; };
REG ptp_reg[] = { REG ptp_reg[] = {
{ FLDATA (BIN, ptp_mode, 0) },
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ NULL } { NULL }
}; };
@ -100,7 +113,8 @@ DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL, "PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8, 1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset, NULL, NULL, &ptp_reset,
NULL, NULL, NULL NULL, NULL, NULL,
NULL, DEV_DEFIO
}; };
/* Data tables */ /* Data tables */
@ -136,7 +150,7 @@ const int8 ptr_to_num[128] = {
-1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* XO */ -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* XO */
0x08, -1, -1, 0x0B, -1, -1, -1, -1, 0x08, -1, -1, 0x0B, -1, -1, -1, -1,
0x10, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* XOC */ 0x10, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* XOC */
-1, 0x09, 0x0A, -1, 0x0C, -1, -1, -1 /* X0C82 is not defined but will treat as RM (tfm) */ -1, 0x09, 0x1A, -1, 0x0C, -1, -1, -1 /* X0C82 treated as flagged RM, RN only (tfm) */
}; };
/* Paper tape read (7b) to alphameric (two digits) */ /* Paper tape read (7b) to alphameric (two digits) */
@ -206,116 +220,116 @@ const int8 alp_to_ptp[256] = {
-1, -1, -1, -1, -1, -1, -1, -1 -1, -1, -1, -1, -1, -1, -1, -1
}; };
/* Paper tape reader IO routine /* Paper tape reader IO init routine */
t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
if ((op != OP_RN) && (op != OP_RA)) /* RN & RA only */
return STOP_INVFNC;
if ((ptr_unit.flags & UNIT_ATT) == 0) /* catch unattached */
return SCPE_UNATT;
ptr_mode = 0;
cpuio_set_inp (op, &ptr_unit);
return SCPE_OK;
}
/* Binary paper tape reader IO init routine */
t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
if (op != OP_RA) /* RA only */
return STOP_INVFNC;
if ((ptr_unit.flags & UNIT_ATT) == 0) /* catch unattached */
return SCPE_UNATT;
ptr_mode = 1;
cpuio_set_inp (op, &ptr_unit);
return SCPE_OK;
}
/* Paper tape unit service
- If over the limit, cancel IO and return error.
- If unattached, reschedule and return error.
- Transfer a digit/character.
- Hard errors halt the operation and the system. - Hard errors halt the operation and the system.
- Parity errors place an invalid character in memory and set - Parity errors place an invalid character in memory and set
RDCHK, but the read continues until end of record. If IO RDCHK, but the read continues until end of record. If IO
stop is set, the system then halts. stop is set, the system then halts.
*/ */
t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1) t_stat ptr_svc (UNIT *uptr)
{ {
uint32 i = 0; t_stat r;
int8 mc;
uint8 ptc; uint8 ptc;
t_stat r, sta; int8 mc;
sta = SCPE_OK; if (cpuio_cnt >= MEMSIZE) { /* over the limit? */
switch (op) { /* case on op */ cpuio_clr_inp (uptr); /* done */
return STOP_RWRAP;
}
sim_activate (uptr, uptr->wait); /* sched another xfer */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return SCPE_UNATT;
switch (cpuio_opc) {
case OP_RN: /* read numeric */ case OP_RN: /* read numeric */
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
r = ptr_read (&ptc, TRUE); /* read frame */ r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
if (ptc & PT_EL) { /* end record? */ if (ptc & PT_EL) { /* end record? */
M[pa] = REC_MARK; /* store rec mark */ M[PAR] = REC_MARK; /* store rec mark */
return sta; /* done */ break;
} }
mc = ptr_to_num[ptc]; /* translate char */ mc = ptr_to_num[ptc]; /* translate char */
if ((bad_par[ptc]) || (mc < 0)) { /* bad par. or char? */ if ((bad_par[ptc]) || (mc < 0)) { /* bad par. or char? */
ind[IN_RDCHK] = 1; /* set read check */ ind[IN_RDCHK] = 1; /* set read check */
if (io_stop) /* set return status */ mc = 0; /* store zero */
sta = STOP_INVCHR;
M[pa] = 0; /* store zero */
} }
else M[pa] = mc; /* stor translated char */ M[PAR] = mc; /* store translated char */
PP (pa); /* incr mem addr */ PP (PAR); /* incr mem addr */
} cpuio_cnt++;
break; return SCPE_OK;
case OP_RA: /* read alphameric */ case OP_RA: /* read alphameric */
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = ptr_read (&ptc, TRUE); /* read frame */ r = ptr_read (&ptc, TRUE); /* read frame */
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
if (ptc & PT_EL) { /* end record? */ if (ptc & PT_EL) { /* end record? */
M[pa] = (M[pa] & FLAG) | REC_MARK; /* store alpha RM .. */ M[PAR] = (M[PAR] & FLAG) | REC_MARK; /* store alpha RM */
M[pa - 1] = M[pa - 1] & FLAG; /* ..and preserve flags */ M[PAR - 1] = M[PAR - 1] & FLAG; /* and preserve flags */
return sta; /* done */ break;
} }
if (ptr_mode == 0) { /* normal mode? */
mc = ptr_to_alp[ptc]; /* translate */ mc = ptr_to_alp[ptc]; /* translate */
if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */ if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
ind[IN_RDCHK] = 1; /* set read check */ ind[IN_RDCHK] = 1; /* set read check */
if (io_stop) /* set return status */
sta = STOP_INVCHR;
mc = 0; /* store blank */ mc = 0; /* store blank */
} }
M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */ M[PAR] = (M[PAR] & FLAG) | (mc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT); M[PAR - 1] = (M[PAR - 1] & FLAG) | ((mc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); /* incr mem addr */
} }
break; else { /* binary mode */
if (bad_par[ptc]) /* bad parity? */
default: /* invalid function */
return STOP_INVFNC;
}
return STOP_RWRAP;
}
/* Binary paper tape reader IO routine - see above for error handling */
t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
uint32 i;
uint8 ptc;
t_stat r, sta;
if ((cpu_unit.flags & IF_BIN) == 0)
return STOP_INVIO;
sta = SCPE_OK;
switch (op) { /* case on op */
case OP_RA: /* read alphameric */
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = ptr_read (&ptc, FALSE); /* read frame */
if (r != SCPE_OK) /* error? */
return r;
if (ptc & PT_EL) { /* end record? */
M[pa] = (M[pa] & FLAG) | REC_MARK; /* store alpha RM .. */
M[pa - 1] = M[pa - 1] & FLAG; /* ..and preserve flags */
return sta; /* done */
}
if (bad_par[ptc]) { /* bad parity? */
ind[IN_RDCHK] = 1; /* set read check */ ind[IN_RDCHK] = 1; /* set read check */
if (io_stop) /* set return status */ M[PAR] = (M[PAR] & FLAG) | (ptc & 07); /* store 2 digits */
sta = STOP_INVCHR; M[PAR - 1] = (M[PAR - 1] & FLAG) |
}
M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) |
(((ptc >> 4) & 06) | ((ptc >> 3) & 1)); (((ptc >> 4) & 06) | ((ptc >> 3) & 1));
pa = ADDR_A (pa, 2); /* incr mem addr */
} }
break; PAR = ADDR_A (PAR, 2); /* incr mem addr */
cpuio_cnt = cpuio_cnt + 2;
return SCPE_OK;
default: /* invalid function */ default: /* invalid function */
return STOP_INVFNC; break;
} }
return STOP_RWRAP; /* IO is complete */
cpuio_clr_inp (uptr); /* clear IO in progress */
if ((ind[IN_RDCHK] != 0) && (io_stop != 0)) /* parity error? */
return STOP_INVCHR;
return SCPE_OK;
} }
/* Read ptr frame - all errors are 'hard' errors and halt the system */ /* Read ptr frame - all errors are 'hard' errors and halt the system */
@ -324,11 +338,6 @@ t_stat ptr_read (uint8 *c, t_bool ignfeed)
{ {
int32 temp; int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_RDCHK] = 1; /* no, error */
return SCPE_UNATT;
}
do { do {
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */
ind[IN_RDCHK] = 1; /* err, rd chk */ ind[IN_RDCHK] = 1; /* err, rd chk */
@ -352,6 +361,8 @@ return SCPE_OK;
t_stat ptr_reset (DEVICE *dptr) t_stat ptr_reset (DEVICE *dptr)
{ {
sim_cancel (&ptr_unit);
ptr_mode = 0;
return SCPE_OK; return SCPE_OK;
} }
@ -375,123 +386,121 @@ saved_PC = BOOT_START;
return SCPE_OK; return SCPE_OK;
} }
/* Paper tape punch IO routine /* Paper tape punch IO init routine */
- Hard errors halt the operation and the system.
- Parity errors stop the operation and set WRCHK.
If IO stop is set, the system then halts.
*/
t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1) t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{ {
uint32 i; if ((op != OP_WN) && (op != OP_WA) && (op != OP_DN))
return STOP_INVFNC;
if ((ptp_unit.flags & UNIT_ATT) == 0) /* catch unattached */
return SCPE_UNATT;
ptp_mode = 0;
cpuio_set_inp (op, &ptp_unit);
return SCPE_OK;
}
/* Binary paper tape punch IO init routine */
t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
if (op != OP_WA) /* WA only */
return STOP_INVFNC;
if ((ptp_unit.flags & UNIT_ATT) == 0) /* catch unattached */
return SCPE_UNATT;
ptp_mode = 1;
cpuio_set_inp (op, &ptp_unit);
return SCPE_OK;
}
/* Paper tape punch unit service routine */
t_stat ptp_svc (UNIT *uptr)
{
int8 ptc; int8 ptc;
uint8 z, d; uint8 z, d;
t_stat r; t_stat r;
switch (op) { /* decode op */ if ((cpuio_opc != OP_DN) && (cpuio_cnt >= MEMSIZE)) { /* wrap, ~dump? */
cpuio_clr_inp (uptr); /* done */
return STOP_RWRAP;
}
sim_activate (uptr, uptr->wait); /* sched another xfer */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return SCPE_UNATT;
switch (cpuio_opc) { /* decode op */
case OP_DN: case OP_DN:
return ptp_num (pa, 20000 - (pa % 20000), TRUE);/* dump numeric */ if ((cpuio_cnt != 0) && ((PAR % 20000) == 0)) /* done? */
break;
return ptp_num (); /* write numeric */
case OP_WN: case OP_WN:
return ptp_num (pa, 0, FALSE); /* punch numeric */ if ((M[PAR] & REC_MARK) == REC_MARK) /* end record? */
break;
return ptp_num (); /* write numeric */
case OP_WA: case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ d = M[PAR] & DIGIT; /* get digit */
d = M[pa] & DIGIT; /* get digit */ z = M[PAR - 1] & DIGIT; /* get zone */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */ break; /* end record */
if (ptp_mode == 0) { /* normal mode */
ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */ ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
if (ptc < 0) { /* bad char? */ if (ptc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* write check */ ind[IN_WRCHK] = 1; /* write check */
CRETIOE (io_stop, STOP_INVCHR); CRETIOE (io_stop, STOP_INVCHR);
} }
r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) /* error? */
return r;
pa = ADDR_A (pa, 2); /* incr mem addr */
} }
break; else { /* binary mode */
default: /* invalid function */
return STOP_INVFNC;
}
return STOP_RWRAP;
}
/* Binary paper tape punch IO routine - see above for error handling */
t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{
uint32 i;
uint8 ptc, z, d;
t_stat r;
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
switch (op) { /* decode op */
case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
d = M[pa] & DIGIT; /* get digit */
z = M[pa - 1] & DIGIT; /* get zone */
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
return ptp_write (PT_EL); /* end record */
ptc = ((z & 06) << 4) | ((z & 01) << 3) | (d & 07); ptc = ((z & 06) << 4) | ((z & 01) << 3) | (d & 07);
if (bad_par[ptc]) /* set parity */ if (bad_par[ptc]) /* set parity */
ptc = ptc | PT_C; ptc = ptc | PT_C;
}
r = ptp_write (ptc); /* write char */ r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
pa = ADDR_A (pa, 2); /* incr mem addr */ PAR = ADDR_A (PAR, 2); /* incr mem addr */
} cpuio_cnt = cpuio_cnt + 2;
break; return SCPE_OK;
default: /* invalid function */ default: /* invalid function */
return STOP_INVFNC; break;
} }
return STOP_RWRAP; /* IO is complete */
ptp_write (PT_EL); /* write record mark */
cpuio_clr_inp (uptr); /* IO complete */
return SCPE_OK;
} }
/* Punch tape numeric - cannot generate parity errors */ /* Punch tape numeric - cannot generate parity errors */
t_stat ptp_num (uint32 pa, uint32 len, t_bool dump) t_stat ptp_num (void)
{ {
t_stat r; t_stat r;
uint8 d; uint8 d;
uint32 i;
int8 ptc; int8 ptc;
for (i = 0; i < MEMSIZE; i++) { /* stop runaway */ d = M[PAR] & (FLAG | DIGIT); /* get char */
d = M[pa] & (FLAG | DIGIT); /* get char */ ptc = num_to_ptp[d]; /* translate digit */
if (dump? (len-- == 0): /* dump: end reached? */ if (ptc < 0) { /* bad char? */
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
return ptp_write (PT_EL); /* end record */
ptc = num_to_ptp[d]; /* translate digit */
if (ptc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* write check */ ind[IN_WRCHK] = 1; /* write check */
CRETIOE(io_stop, STOP_INVCHR); CRETIOE(io_stop, STOP_INVCHR);
} }
r = ptp_write(ptc); /* write char */ r = ptp_write (ptc); /* write char */
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
PP (pa); /* incr mem addr */ PP (PAR); /* incr mem addr */
} cpuio_cnt++;
return STOP_RWRAP; return SCPE_OK;
} }
/* Write ptp frame - all errors are hard errors */ /* Write ptp frame - all errors are hard errors */
t_stat ptp_write (uint32 c) t_stat ptp_write (uint32 c)
{ {
if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
ind[IN_WRCHK] = 1; /* no, error */
return SCPE_UNATT;
}
if (putc (c, ptp_unit.fileref) == EOF) { /* write char */ if (putc (c, ptp_unit.fileref) == EOF) { /* write char */
ind[IN_WRCHK] = 1; /* error? */ ind[IN_WRCHK] = 1; /* error? */
sim_perror ("PTP I/O error"); sim_perror ("PTP I/O error");
@ -506,5 +515,7 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr) t_stat ptp_reset (DEVICE *dptr)
{ {
sim_cancel (&ptp_unit);
ptp_mode = 0;
return SCPE_OK; return SCPE_OK;
} }

View file

@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
25-May-17 RMS Tweaks and corrections from Tom McBride
18-May-17 RMS Changed fprint_val to handle undefined opcodes on stops 18-May-17 RMS Changed fprint_val to handle undefined opcodes on stops
19-Mar-12 RMS Fixed declaration of CCT (Mark Pizzolato) 19-Mar-12 RMS Fixed declaration of CCT (Mark Pizzolato)
*/ */
@ -272,7 +273,7 @@ struct opc opcode[] = {
{ "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 }, { "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 },
{ "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 }, { "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 },
{ "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 }, { "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 },
{ "CPFL", 94+I_2, 0 }, { "EORF", 95+I_2, 0 }, { "CPLF", 94+I_2, 0 }, { "EORF", 95+I_2, 0 },
{ "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 }, { "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 },
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };
@ -399,7 +400,7 @@ if (opcode[i].str == NULL) { /* invalid opcode */
if (I_GETQP (opfl) == I_M_QNP) /* Q no print? */ if (I_GETQP (opfl) == I_M_QNP) /* Q no print? */
qmp = 0; qmp = 0;
fprintf (of, "%s", opcode[i].str); /* print opcode */ fprintf (of, "%-4s", opcode[i].str); /* print opcode */
if (I_GETPP (opfl) == I_M_PP) /* P required? */ if (I_GETPP (opfl) == I_M_PP) /* P required? */
fprint_addr (of, ' ', &val[I_P], I_M_QX); fprint_addr (of, ' ', &val[I_P], I_M_QX);
else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */ else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */

View file

@ -25,6 +25,7 @@
tty console typewriter tty console typewriter
26-May-17 RMS Added deferred IO
18-May-17 RMS Fixed keyboard interrupt problem for Linux 18-May-17 RMS Fixed keyboard interrupt problem for Linux
Added input backspace for Model II Added input backspace for Model II
04-May-17 DW Revised tab calculation algorithm 04-May-17 DW Revised tab calculation algorithm
@ -46,8 +47,13 @@
#define TTO_COLMAX 80 #define TTO_COLMAX 80
#define UF_V_1DIG (UNIT_V_UF) #define UF_V_1DIG (UNIT_V_UF)
#define UF_1DIG (1 << UF_V_1DIG) #define UF_1DIG (1 << UF_V_1DIG)
#define UTTI 0
#define UTTO 1
uint32 tti_unlock = 0; /* expecting input */
uint32 tti_flag = 0; /* flag typed */
int32 tto_col = 1; /* one-based, char loc to print next */
int32 tto_col = 1; /* One-based, char cell we will print to next */
uint8 tto_tabs[TTO_COLMAX + 1] = { /* Zero-based access, one-based UI */ uint8 tto_tabs[TTO_COLMAX + 1] = { /* Zero-based access, one-based UI */
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0,
@ -66,15 +72,12 @@ extern uint8 M[MAXMEMSIZE];
extern uint8 ind[NUM_IND]; extern uint8 ind[NUM_IND];
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern uint32 io_stop; extern uint32 io_stop;
extern volatile int32 stop_cpu; extern uint32 cpuio_inp, cpuio_opc, cpuio_cnt, PAR;
void tti_unlock (void); t_stat tto_num (void);
t_stat tti_rnum (int8 *c);
t_stat tti_ralp (int8 *c);
t_stat tti_read (int8 *c);
t_stat tto_num (uint32 pa, uint32 len, t_bool dump);
t_stat tto_write (uint32 c); t_stat tto_write (uint32 c);
t_stat tty_svc (UNIT *uptr); t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tty_reset (DEVICE *dptr); t_stat tty_reset (DEVICE *dptr);
t_stat tty_set_fixtabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat tty_set_fixtabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
@ -85,11 +88,17 @@ t_stat tty_set_fixtabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
tty_reg TTY register list tty_reg TTY register list
*/ */
UNIT tty_unit = { UDATA (&tty_svc, 0, 0), KBD_POLL_WAIT }; UNIT tty_unit[] = {
{ UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }
};
REG tty_reg[] = { REG tty_reg[] = {
{ FLDATA (UNLOCK, tti_unlock, 0) },
{ FLDATA (FLAG, tti_flag, 0), REG_HRO },
{ DRDATA (COL, tto_col, 7) }, { DRDATA (COL, tto_col, 7) },
{ DRDATA (TIME, tty_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (KTIME, tty_unit[UTTI].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TTIME, tty_unit[UTTO].wait, 24), REG_NZ + PV_LEFT },
{ NULL } { NULL }
}; };
@ -108,10 +117,11 @@ MTAB tty_mod[] = {
}; };
DEVICE tty_dev = { DEVICE tty_dev = {
"TTY", &tty_unit, tty_reg, tty_mod, "TTY", tty_unit, tty_reg, tty_mod,
1, 10, 31, 1, 8, 7, 2, 10, 31, 1, 8, 7,
NULL, NULL, &tty_reset, NULL, NULL, &tty_reset,
NULL, NULL, NULL NULL, NULL, NULL,
NULL, DEV_DEFIO
}; };
/* Data tables */ /* Data tables */
@ -239,12 +249,6 @@ const char alp_to_tto[256] = {
t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1) t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1)
{ {
t_addr i;
uint8 d;
int8 ttc;
t_stat r, sta;
sta = SCPE_OK;
switch (op) { /* case on op */ switch (op) { /* case on op */
case OP_K: /* control */ case OP_K: /* control */
@ -271,174 +275,177 @@ switch (op) { /* case on op */
default: default:
return STOP_INVFNC; return STOP_INVFNC;
} }
return SCPE_OK;
case OP_RN: /* read numeric */
tti_unlock (); /* unlock keyboard */
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
r = tti_rnum (&ttc); /* read char */
if (r != SCPE_OK) /* error? */
return r;
if (ttc == 0x7F) /* end record? */
return SCPE_OK;
if (ttc == 0x7E) { /* backspace? */
MM (pa); /* decr mem addr */
}
else { /* normal char */
M[pa] = ttc & (FLAG | DIGIT); /* store char */
PP (pa); /* incr mem addr */
}
}
break; break;
case OP_RA: /* read alphameric */
tti_unlock ();
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
r = tti_ralp (&ttc); /* read char */
if (r != SCPE_OK) /* error? */
return r;
if (ttc == 0x7F) /* end record? */
return SCPE_OK;
if (ttc == 0x7E) { /* backspace? */
pa = ADDR_A (pa, -2); /* decr mem addr*/
}
else { /* normal char */
M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */
M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT);
pa = ADDR_A (pa, 2); /* incr mem addr */
}
}
break;
case OP_DN:
return tto_num (pa, 20000 - (pa % 20000), TRUE);/* dump numeric */
case OP_WN: case OP_WN:
return tto_num (pa, 0, FALSE); /* type numeric */ case OP_DN:
case OP_WA: case OP_WA:
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ cpuio_set_inp (op, &tty_unit[UTTO]); /* set IO in progress */
d = M[pa] & DIGIT; /* get digit */ break;
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? done */
return sta; case OP_RN:
d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */ case OP_RA:
ttc = alp_to_tto[d]; /* translate */ tti_unlock = 1; /* unlock keyboard */
if (ttc < 0) { /* bad char? */ tti_flag = 0; /* init flag */
ind[IN_WRCHK] = 1; /* set write check */ tto_write ('>'); /* prompt user */
if (io_stop) /* set return status */ cpuio_set_inp (op, NULL); /* set IO in progress */
sta = STOP_INVCHR;
}
tto_write (ttc & 0x7F); /* write */
pa = ADDR_A (pa, 2); /* incr mem addr */
}
break; break;
default: /* invalid function */ default: /* invalid function */
return STOP_INVFNC; return STOP_INVFNC;
} }
return STOP_RWRAP; return SCPE_OK;
} }
/* Read numerically - cannot generate parity errors */ /* Input unit service - OP can be RA or RN */
t_stat tti_rnum (int8 *c) t_stat tti_svc (UNIT *uptr)
{ {
int8 raw, flg = 0; int32 temp;
int8 raw, c;
const char *cp; const char *cp;
t_stat r;
*c = -1; /* no char yet */ sim_activate (uptr, uptr->wait); /* continue poll */
do { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
r = tti_read (&raw); /* get char */ return temp;
if (r != SCPE_OK) /* error? */ if (tti_unlock == 0) /* expecting input? */
return r; return SCPE_OK; /* no, ignore */
if (raw == '\r') /* return? mark */ raw = (int8) temp;
*c = 0x7F;
else if (((raw == '\b') || (raw == 0x7F)) && /* backspace or del? */ if (raw == '\r') { /* return? */
((cpu_unit.flags & IF_MII) != 0)) { /* on model 2? */
*c = 0x7E; /* mark */
raw = '-'; /* print minus */
}
else if ((raw == '~') || (raw == '`')) /* flag? mark */
flg = FLAG;
else if ((cp = strchr (tti_to_num, raw)) != 0) /* legal? */
*c = tti_position_to_internal[(cp - tti_to_num)] | flg; /* assemble char */
else raw = 007; /* beep! */
tto_write (raw); /* echo */ tto_write (raw); /* echo */
} while (*c == -1); tti_unlock = 0; /* no more input */
cpuio_clr_inp (NULL);
return SCPE_OK;
}
if (cpuio_opc == OP_RN) { /* RN? */
if (((raw == '\b') || (raw == 0x7F)) && /* backspace or del? */
((cpu_unit.flags & IF_MII) != 0)) { /* on model 2? */
tto_write ('-'); /* print minus */
MM (PAR); /* decr mem addr */
return SCPE_OK;
}
else if ((raw == '~') || (raw == '`')) { /* flag? mark */
tto_write (raw);
tti_flag = FLAG;
return SCPE_OK;
}
else if ((cp = strchr (tti_to_num, raw)) == 0) { /* invalid? */
tto_write ('\a'); /* beep! */
return SCPE_OK;
}
tto_write (raw); /* echo */
if (cpuio_cnt >= MEMSIZE) { /* wrap around? */
tti_unlock = 0; /* no more input */
cpuio_clr_inp (NULL);
return STOP_RWRAP;
}
c = tti_position_to_internal[(cp - tti_to_num)] | tti_flag; /* assemble char */
M[PAR] = c & (FLAG | DIGIT); /* store char */
tti_flag = 0; /* re-init flag */
PP (PAR); /* incr mem addr */
cpuio_cnt++;
}
else { /* RA */
if (((raw == '\b') || (raw == 0x7F)) && /* backspace or del? */
((cpu_unit.flags & IF_MII) != 0)) { /* on model 2? */
tto_write ('-'); /* print minus */
PAR = ADDR_A (PAR, -2); /* decr mem addr*/
return SCPE_OK;
}
else if (tti_to_alp[raw] < 0) { /* illegal char? */
tto_write ('\a'); /* beep! */
return SCPE_OK;
}
tto_write (raw); /* echo */
if (cpuio_cnt >= MEMSIZE) { /* wrap around? */
tti_unlock = 0; /* no more input */
cpuio_clr_inp (NULL);
return STOP_RWRAP;
}
c = tti_to_alp[raw]; /* xlate */
M[PAR] = (M[PAR] & FLAG) | (c & DIGIT); /* store 2 digits */
M[PAR - 1] = (M[PAR - 1] & FLAG) | ((c >> 4) & DIGIT);
PAR = ADDR_A (PAR, 2); /* incr mem addr */
cpuio_cnt = cpuio_cnt + 2;
}
return SCPE_OK; return SCPE_OK;
} }
/* Read alphamerically - cannot generate parity errors */ /* Output unit service */
t_stat tti_ralp (int8 *c) t_stat tto_svc (UNIT *uptr) {
{
int8 raw;
t_stat r;
*c = -1; /* no char yet */ uint8 d;
do { int8 ttc;
r = tti_read (&raw); /* get char */ t_stat sta = SCPE_OK;
if (r != SCPE_OK) /* error? */
return r; if ((cpuio_opc != OP_DN) && (cpuio_cnt >= MEMSIZE)) { /* wrap, ~dump? */
if (raw == '\r') /* return? mark */ cpuio_clr_inp (uptr); /* done */
*c = 0x7F; return STOP_RWRAP;
else if (((raw == '\b') || (raw == 0x7F)) && /* backspace or del? */
((cpu_unit.flags & IF_MII) != 0)) { /* on model 2? */
*c = 0x7E; /* mark */
raw = '-'; /* print minus */
} }
else if (tti_to_alp[raw] >= 0) /* legal char? */ sim_activate (uptr, uptr->wait); /* sched another xfer */
*c = tti_to_alp[raw]; /* xlate */
else raw = 007; /* beep! */
tto_write (raw); /* echo */
} while (*c == -1);
return SCPE_OK;
}
/* Read from keyboard */ switch (cpuio_opc) { /* decode op */
t_stat tti_read (int8 *c) case OP_DN:
{ if ((cpuio_cnt != 0) && ((PAR % 20000) == 0)) /* done? */
int32 t; break;
return tto_num (); /* write numeric */
do { case OP_WN:
if (stop_cpu != 0) /* stop? */ if ((M[PAR] & REC_MARK) == REC_MARK) /* end record? */
return SCPE_STOP; break;
t = sim_poll_kbd (); /* get character */ return tto_num (); /* write numeric */
} while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */
if (t < SCPE_KFLAG) /* error? */ case OP_WA:
return t; d = M[PAR] & DIGIT; /* get digit */
*c = t & 0177; /* store character */ if ((d & REC_MARK) == REC_MARK) /* 8-2 char? done */
return SCPE_OK; break;
d = ((M[PAR - 1] & DIGIT) << 4) | d; /* get digit pair */
ttc = alp_to_tto[d]; /* translate */
if (ttc < 0) { /* bad char? */
ind[IN_WRCHK] = 1; /* set write check */
if (io_stop) /* set return status */
sta = STOP_INVCHR;
break;
}
tto_write (ttc & 0x7F); /* write */
PAR = ADDR_A (PAR, 2); /* incr mem addr */
cpuio_cnt = cpuio_cnt + 2;
return SCPE_OK;
default:
return SCPE_IERR;
}
cpuio_clr_inp (uptr); /* clear IO in progress */
return sta;
} }
/* Write numerically - cannot generate parity errors */ /* Write numerically - cannot generate parity errors */
t_stat tto_num (uint32 pa, uint32 len, t_bool dump) t_stat tto_num (void)
{ {
t_stat r; t_stat r;
uint8 d; uint8 d;
uint32 i;
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ d = M[PAR]; /* get char */
d = M[pa]; /* get char */ if (tty_unit[UTTO].flags & UF_1DIG) /* how display flagged digits? */
if (dump? (len-- == 0): /* dump: end reached? */ r = tto_write (num_to_tto[d & (DIGIT|FLAG)]); /* single digit display */
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */ else {
return SCPE_OK; /* end operation */
if (tty_unit.flags & UF_1DIG) /* how display flagged digits? */
r = tto_write (num_to_tto[d]); /* single digit display */
else {
if (d & FLAG) /* flag? */ if (d & FLAG) /* flag? */
tto_write ('`'); /* write flag indicator */ tto_write ('`'); /* write flag indicator */
r = tto_write (num_to_tto[d & DIGIT]); /* write the digit */ r = tto_write (num_to_tto[d & DIGIT]); /* write the digit */
} }
if (r != SCPE_OK) /* write error? */ if (r != SCPE_OK) /* write error? */
return r; return r;
PP (pa); /* incr mem addr */ PP (PAR); /* incr mem addr */
} cpuio_cnt++;
return STOP_RWRAP; return SCPE_OK;
} }
/* Wrap line, if needed, prior to character output */ /* Wrap line, if needed, prior to character output */
@ -468,7 +475,7 @@ else if (c == '\r') { /* return? */
sim_putchar ('\n'); sim_putchar ('\n');
tto_col = 1; /* back to LMargin */ tto_col = 1; /* back to LMargin */
} }
else if ((c == '\n') || (c == 007)) { /* non-spacing? */ else if ((c == '\n') || (c == '\a')) { /* non-spacing? */
sim_putchar (c); sim_putchar (c);
} }
else if (c == '\b') { /* backspace? */ else if (c == '\b') { /* backspace? */
@ -485,35 +492,17 @@ else { /* normal */
return SCPE_OK; return SCPE_OK;
} }
/* Unit service - polls for WRU */
t_stat tty_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&tty_unit, tty_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
return temp;
return SCPE_OK;
}
/* Reset routine */ /* Reset routine */
t_stat tty_reset (DEVICE *dptr) t_stat tty_reset (DEVICE *dptr)
{ {
sim_activate (&tty_unit, tty_unit.wait); /* activate poll */ sim_activate (&tty_unit[UTTI], tty_unit[UTTI].wait); /* activate poll */
sim_cancel (&tty_unit[UTTO]); /* cancel output */
tti_unlock = tti_flag = 0; /* tty locked */
tto_col = 1; tto_col = 1;
return SCPE_OK; return SCPE_OK;
} }
/* TTI unlock - signals that we are ready for keyboard input */
void tti_unlock (void)
{
tto_write ('>');
return;
}
/* Set tab stops at fixed modulus */ /* Set tab stops at fixed modulus */
t_stat tty_set_fixtabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc) t_stat tty_set_fixtabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc)

Binary file not shown.