diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index 4a7a3aaa..98b2e08c 100644 --- a/I1620/i1620_cd.c +++ b/I1620/i1620_cd.c @@ -433,7 +433,7 @@ switch (op) { /* decode op */ case OP_DN: /* 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 the last digit of the storage module containing the P address has been punched. If the amount of data to be punched is an diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c index 1ad0e410..26e81a26 100644 --- a/I1620/i1620_cpu.c +++ b/I1620/i1620_cpu.c @@ -26,6 +26,7 @@ This CPU module incorporates code and comments from the 1620 simulator by 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 Added SET CPU RELEASE command 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 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. It is called from the simulator control program to execute instructions in simulated memory, starting at the simulated PC. @@ -135,6 +150,9 @@ uint32 idxe = 0; /* index enable */ uint32 idxb = 0; /* index band */ uint32 io_stop = 1; /* I/O 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 */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ @@ -227,6 +245,9 @@ REG cpu_reg[] = { { FLDATA (WRCHK, ind[IN_WRCHK], 0) }, { FLDATA (ARSTOP, ar_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) }, { FLDATA (IAE, iae, 0) }, { FLDATA (IDXE, idxe, 0) }, @@ -349,7 +370,7 @@ const int32 op_table[100] = { 0, 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, /* TNS */ IF_EDT + IF_VPA + IF_VQA, /* TNF */ 0, 0, @@ -517,6 +538,10 @@ while (reason == SCPE_OK) { /* loop until halted */ if ((reason = sim_process_event ())) 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? */ 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 */ pcq_r->qptr = pcq_p; /* update pc q ptr */ upd_ind (); +if (cpuio_inp != 0) /* flag IO in progress */ + sim_printf ("\r\nIO in progress"); return reason; } @@ -2131,6 +2158,28 @@ M[d] = M[d] | sign; /* set result sign */ 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 */ t_stat cpu_reset (DEVICE *dptr) @@ -2142,6 +2191,8 @@ PR1 = IR2 = 1; /* invalidate PR1,IR2 */ ind[0] = 0; for (i = IN_SW4 + 1; i < NUM_IND; i++) /* init indicators */ 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? */ iae = 1; else iae = 0; @@ -2164,8 +2215,21 @@ return SCPE_OK; 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? */ - saved_PC = actual_PC; /* return */ +uint32 i; +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); } else sim_printf ("PC unchanged\n"); diff --git a/I1620/i1620_defs.h b/I1620/i1620_defs.h index b796c4a7..f1783b01 100644 --- a/I1620/i1620_defs.h +++ b/I1620/i1620_defs.h @@ -27,6 +27,7 @@ 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. + 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) 05-Feb-15 TFM Added definitions for flagged RM, GM, NB 22-May-10 RMS Added check for 64b definitions @@ -113,6 +114,7 @@ #define IN_SW4 4 /* sense switch 4 */ #define IN_RDCHK 6 /* read 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_HP 11 /* high or positive result */ #define IN_EZ 12 /* equal or zero result */ @@ -121,7 +123,6 @@ #define IN_EXPCHK 15 /* floating exponent check */ #define IN_MBREVEN 16 /* even 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_PRCHK 25 /* printer check */ #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_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 alp_to_cdp[256]; diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c index 35bd1632..f4b5c0ed 100644 --- a/I1620/i1620_pt.c +++ b/I1620/i1620_pt.c @@ -26,6 +26,8 @@ ptr 1621 paper tape reader 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) 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) @@ -45,17 +47,23 @@ #define PT_C 0x10 /* C */ #define PT_FD 0x7F /* deleted */ +static uint32 ptr_mode = 0; /* normal/binary */ +static uint32 ptp_mode = 0; + extern uint8 M[MAXMEMSIZE]; extern uint8 ind[NUM_IND]; extern UNIT cpu_unit; 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_boot (int32 unitno, DEVICE *dptr); t_stat ptr_read (uint8 *c, t_bool ignfeed); +t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); 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 @@ -65,11 +73,13 @@ t_stat ptp_num (uint32 pa, uint32 len, t_bool dump); */ 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[] = { + { FLDATA (BIN, ptr_mode, 0) }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -77,7 +87,8 @@ DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL + &ptr_boot, NULL, NULL, + NULL, DEV_DEFIO }; /* PTP data structures @@ -88,11 +99,13 @@ DEVICE ptr_dev = { */ UNIT ptp_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) + UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, SERIAL_OUT_WAIT) }; REG ptp_reg[] = { + { FLDATA (BIN, ptp_mode, 0) }, { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -100,7 +113,8 @@ DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL + NULL, NULL, NULL, + NULL, DEV_DEFIO }; /* Data tables */ @@ -136,7 +150,7 @@ const int8 ptr_to_num[128] = { -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* XO */ 0x08, -1, -1, 0x0B, -1, -1, -1, -1, 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) */ @@ -206,116 +220,116 @@ const int8 alp_to_ptp[256] = { -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. - Parity errors place an invalid character in memory and set RDCHK, but the read continues until end of record. If IO 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; -int8 mc; +t_stat r; uint8 ptc; -t_stat r, sta; +int8 mc; -sta = SCPE_OK; -switch (op) { /* case on op */ +if (cpuio_cnt >= MEMSIZE) { /* over the limit? */ + 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 */ - for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ - r = ptr_read (&ptc, TRUE); /* read frame */ - if (r != SCPE_OK) /* error? */ - return r; - if (ptc & PT_EL) { /* end record? */ - M[pa] = REC_MARK; /* store rec mark */ - return sta; /* done */ - } - mc = ptr_to_num[ptc]; /* translate char */ - if ((bad_par[ptc]) || (mc < 0)) { /* bad par. or char? */ - ind[IN_RDCHK] = 1; /* set read check */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - M[pa] = 0; /* store zero */ - } - else M[pa] = mc; /* stor translated char */ - PP (pa); /* incr mem addr */ + r = ptr_read (&ptc, TRUE); /* read frame */ + if (r != SCPE_OK) /* error? */ + return r; + if (ptc & PT_EL) { /* end record? */ + M[PAR] = REC_MARK; /* store rec mark */ + break; } - break; + mc = ptr_to_num[ptc]; /* translate char */ + if ((bad_par[ptc]) || (mc < 0)) { /* bad par. or char? */ + ind[IN_RDCHK] = 1; /* set read check */ + mc = 0; /* store zero */ + } + M[PAR] = mc; /* store translated char */ + PP (PAR); /* incr mem addr */ + cpuio_cnt++; + return SCPE_OK; case OP_RA: /* read alphameric */ - for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */ - r = ptr_read (&ptc, TRUE); /* 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 */ - } + r = ptr_read (&ptc, TRUE); /* read frame */ + if (r != SCPE_OK) /* error? */ + return r; + if (ptc & PT_EL) { /* end record? */ + M[PAR] = (M[PAR] & FLAG) | REC_MARK; /* store alpha RM */ + M[PAR - 1] = M[PAR - 1] & FLAG; /* and preserve flags */ + break; + } + if (ptr_mode == 0) { /* normal mode? */ mc = ptr_to_alp[ptc]; /* translate */ if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */ ind[IN_RDCHK] = 1; /* set read check */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; mc = 0; /* store blank */ } - M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */ - M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT); - pa = ADDR_A (pa, 2); /* incr mem addr */ + M[PAR] = (M[PAR] & FLAG) | (mc & DIGIT); /* store 2 digits */ + M[PAR - 1] = (M[PAR - 1] & FLAG) | ((mc >> 4) & DIGIT); } - break; - - 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? */ + else { /* binary mode */ + if (bad_par[ptc]) /* bad parity? */ ind[IN_RDCHK] = 1; /* set read check */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - } - M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */ - M[pa - 1] = (M[pa - 1] & FLAG) | - (((ptc >> 4) & 06) | ((ptc >> 3) & 1)); - pa = ADDR_A (pa, 2); /* incr mem addr */ + M[PAR] = (M[PAR] & FLAG) | (ptc & 07); /* store 2 digits */ + M[PAR - 1] = (M[PAR - 1] & FLAG) | + (((ptc >> 4) & 06) | ((ptc >> 3) & 1)); } - break; + PAR = ADDR_A (PAR, 2); /* incr mem addr */ + cpuio_cnt = cpuio_cnt + 2; + return SCPE_OK; 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 */ @@ -324,11 +338,6 @@ t_stat ptr_read (uint8 *c, t_bool ignfeed) { int32 temp; -if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */ - ind[IN_RDCHK] = 1; /* no, error */ - return SCPE_UNATT; - } - do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */ ind[IN_RDCHK] = 1; /* err, rd chk */ @@ -352,6 +361,8 @@ return SCPE_OK; t_stat ptr_reset (DEVICE *dptr) { +sim_cancel (&ptr_unit); +ptr_mode = 0; return SCPE_OK; } @@ -375,123 +386,121 @@ saved_PC = BOOT_START; return SCPE_OK; } -/* Paper tape punch IO 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. -*/ +/* Paper tape punch IO init routine */ 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; uint8 z, d; 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: - 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: - 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: - 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 */ + d = M[PAR] & DIGIT; /* get digit */ + z = M[PAR - 1] & DIGIT; /* get zone */ + if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ + break; /* end record */ + if (ptp_mode == 0) { /* normal mode */ ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */ if (ptc < 0) { /* bad char? */ ind[IN_WRCHK] = 1; /* write check */ 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; - - 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 */ + else { /* binary mode */ ptc = ((z & 06) << 4) | ((z & 01) << 3) | (d & 07); if (bad_par[ptc]) /* set parity */ ptc = ptc | PT_C; - r = ptp_write (ptc); /* write char */ - if (r != SCPE_OK) /* error? */ - return r; - pa = ADDR_A (pa, 2); /* incr mem addr */ } - break; + r = ptp_write (ptc); /* write char */ + if (r != SCPE_OK) /* error? */ + return r; + PAR = ADDR_A (PAR, 2); /* incr mem addr */ + cpuio_cnt = cpuio_cnt + 2; + return SCPE_OK; 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 */ -t_stat ptp_num (uint32 pa, uint32 len, t_bool dump) +t_stat ptp_num (void) { t_stat r; uint8 d; -uint32 i; int8 ptc; -for (i = 0; i < MEMSIZE; i++) { /* stop runaway */ - d = M[pa] & (FLAG | DIGIT); /* get char */ - if (dump? (len-- == 0): /* dump: end reached? */ - ((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 */ - CRETIOE(io_stop, STOP_INVCHR); - } - r = ptp_write(ptc); /* write char */ - if (r != SCPE_OK) /* error? */ - return r; - PP (pa); /* incr mem addr */ +d = M[PAR] & (FLAG | DIGIT); /* get char */ +ptc = num_to_ptp[d]; /* translate digit */ +if (ptc < 0) { /* bad char? */ + ind[IN_WRCHK] = 1; /* write check */ + CRETIOE(io_stop, STOP_INVCHR); } -return STOP_RWRAP; +r = ptp_write (ptc); /* write char */ +if (r != SCPE_OK) /* error? */ + return r; +PP (PAR); /* incr mem addr */ +cpuio_cnt++; +return SCPE_OK; } /* Write ptp frame - all errors are hard errors */ 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 */ ind[IN_WRCHK] = 1; /* error? */ sim_perror ("PTP I/O error"); @@ -506,5 +515,7 @@ return SCPE_OK; t_stat ptp_reset (DEVICE *dptr) { +sim_cancel (&ptp_unit); +ptp_mode = 0; return SCPE_OK; } diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c index 194f8943..af50632e 100644 --- a/I1620/i1620_sys.c +++ b/I1620/i1620_sys.c @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings 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 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 }, { "BBT", 90+I_2, 0 }, { "BMK", 91+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 }, { NULL, 0, 0 } }; @@ -399,7 +400,7 @@ if (opcode[i].str == NULL) { /* invalid opcode */ if (I_GETQP (opfl) == I_M_QNP) /* Q no print? */ 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? */ fprint_addr (of, ' ', &val[I_P], I_M_QX); else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */ diff --git a/I1620/i1620_tty.c b/I1620/i1620_tty.c index 5b1abda3..45c8f01e 100644 --- a/I1620/i1620_tty.c +++ b/I1620/i1620_tty.c @@ -25,6 +25,7 @@ tty console typewriter + 26-May-17 RMS Added deferred IO 18-May-17 RMS Fixed keyboard interrupt problem for Linux Added input backspace for Model II 04-May-17 DW Revised tab calculation algorithm @@ -46,8 +47,13 @@ #define TTO_COLMAX 80 #define UF_V_1DIG (UNIT_V_UF) #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 */ 0,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 UNIT cpu_unit; extern uint32 io_stop; -extern volatile int32 stop_cpu; +extern uint32 cpuio_inp, cpuio_opc, cpuio_cnt, PAR; -void tti_unlock (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_num (void); 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_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 */ -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[] = { + { FLDATA (UNLOCK, tti_unlock, 0) }, + { FLDATA (FLAG, tti_flag, 0), REG_HRO }, { 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 } }; @@ -108,10 +117,11 @@ MTAB tty_mod[] = { }; DEVICE tty_dev = { - "TTY", &tty_unit, tty_reg, tty_mod, - 1, 10, 31, 1, 8, 7, + "TTY", tty_unit, tty_reg, tty_mod, + 2, 10, 31, 1, 8, 7, NULL, NULL, &tty_reset, - NULL, NULL, NULL + NULL, NULL, NULL, + NULL, DEV_DEFIO }; /* Data tables */ @@ -239,12 +249,6 @@ const char alp_to_tto[256] = { 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 */ case OP_K: /* control */ @@ -271,174 +275,177 @@ switch (op) { /* case on op */ default: 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; - 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: - return tto_num (pa, 0, FALSE); /* type numeric */ - + case OP_DN: case OP_WA: - for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ - d = M[pa] & DIGIT; /* get digit */ - if ((d & REC_MARK) == REC_MARK) /* 8-2 char? done */ - return sta; - d = ((M[pa - 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; - } - tto_write (ttc & 0x7F); /* write */ - pa = ADDR_A (pa, 2); /* incr mem addr */ - } - break; + cpuio_set_inp (op, &tty_unit[UTTO]); /* set IO in progress */ + break; + + case OP_RN: + case OP_RA: + tti_unlock = 1; /* unlock keyboard */ + tti_flag = 0; /* init flag */ + tto_write ('>'); /* prompt user */ + cpuio_set_inp (op, NULL); /* set IO in progress */ + break; default: /* invalid function */ 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; -t_stat r; -*c = -1; /* no char yet */ -do { - r = tti_read (&raw); /* get char */ - if (r != SCPE_OK) /* error? */ - return r; - if (raw == '\r') /* return? mark */ - *c = 0x7F; - 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 ((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! */ +sim_activate (uptr, uptr->wait); /* continue poll */ +if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ + return temp; +if (tti_unlock == 0) /* expecting input? */ + return SCPE_OK; /* no, ignore */ +raw = (int8) temp; + +if (raw == '\r') { /* return? */ 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; } -/* Read alphamerically - cannot generate parity errors */ +/* Output unit service */ -t_stat tti_ralp (int8 *c) -{ -int8 raw; -t_stat r; +t_stat tto_svc (UNIT *uptr) { -*c = -1; /* no char yet */ -do { - r = tti_read (&raw); /* get char */ - if (r != SCPE_OK) /* error? */ - return r; - if (raw == '\r') /* return? mark */ - *c = 0x7F; - 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? */ - *c = tti_to_alp[raw]; /* xlate */ - else raw = 007; /* beep! */ - tto_write (raw); /* echo */ - } while (*c == -1); -return SCPE_OK; -} +uint8 d; +int8 ttc; +t_stat sta = SCPE_OK; -/* Read from keyboard */ +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 */ -t_stat tti_read (int8 *c) -{ -int32 t; +switch (cpuio_opc) { /* decode op */ -do { - if (stop_cpu != 0) /* stop? */ - return SCPE_STOP; - t = sim_poll_kbd (); /* get character */ - } while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */ -if (t < SCPE_KFLAG) /* error? */ - return t; -*c = t & 0177; /* store character */ -return SCPE_OK; + case OP_DN: + if ((cpuio_cnt != 0) && ((PAR % 20000) == 0)) /* done? */ + break; + return tto_num (); /* write numeric */ + + case OP_WN: + if ((M[PAR] & REC_MARK) == REC_MARK) /* end record? */ + break; + return tto_num (); /* write numeric */ + + case OP_WA: + d = M[PAR] & DIGIT; /* get digit */ + if ((d & REC_MARK) == REC_MARK) /* 8-2 char? done */ + 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 */ -t_stat tto_num (uint32 pa, uint32 len, t_bool dump) +t_stat tto_num (void) { t_stat r; uint8 d; -uint32 i; -for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ - d = M[pa]; /* get char */ - if (dump? (len-- == 0): /* dump: end reached? */ - ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */ - 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? */ - tto_write ('`'); /* write flag indicator */ - r = tto_write (num_to_tto[d & DIGIT]); /* write the digit */ - } - if (r != SCPE_OK) /* write error? */ - return r; - PP (pa); /* incr mem addr */ - } -return STOP_RWRAP; +d = M[PAR]; /* get char */ +if (tty_unit[UTTO].flags & UF_1DIG) /* how display flagged digits? */ + r = tto_write (num_to_tto[d & (DIGIT|FLAG)]); /* single digit display */ +else { + if (d & FLAG) /* flag? */ + tto_write ('`'); /* write flag indicator */ + r = tto_write (num_to_tto[d & DIGIT]); /* write the digit */ + } +if (r != SCPE_OK) /* write error? */ + return r; +PP (PAR); /* incr mem addr */ +cpuio_cnt++; +return SCPE_OK; } /* Wrap line, if needed, prior to character output */ @@ -459,7 +466,7 @@ t_stat tto_write (uint32 c) if (c == '\t') { /* tab? */ tto_wrap(); do { - sim_putchar(' '); /* use spaces */ + sim_putchar(' '); /* use spaces */ tto_col++; } while (!(tto_col > TTO_COLMAX || tto_tabs[tto_col-1] == 1)); } @@ -468,7 +475,7 @@ else if (c == '\r') { /* return? */ sim_putchar ('\n'); 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); } else if (c == '\b') { /* backspace? */ @@ -485,35 +492,17 @@ else { /* normal */ 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 */ 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; 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 */ t_stat tty_set_fixtabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc) diff --git a/doc/i1620_doc.doc b/doc/i1620_doc.doc index 3176da96..d1fc66a2 100644 Binary files a/doc/i1620_doc.doc and b/doc/i1620_doc.doc differ