From eaf766e7ff787a1bfa6174c2c7e1da62726e4984 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Mon, 27 Nov 2023 16:29:21 -0500 Subject: [PATCH] I7000: Fix some bugs in card reader and magnetic tape controller. --- I7000/i7000_cdr.c | 18 ++++++++--- I7000/i7000_mt.c | 80 ++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 32 deletions(-) diff --git a/I7000/i7000_cdr.c b/I7000/i7000_cdr.c index 39c355f..2c4923d 100644 --- a/I7000/i7000_cdr.c +++ b/I7000/i7000_cdr.c @@ -122,8 +122,10 @@ uint32 cdr_cmd(UNIT * uptr, uint16 cmd, uint16 dev) uptr->u5 &= ~0xF0000; uptr->u5 |= stk << 16; #endif - if (uptr->u5 & (URCSTA_EOF|URCSTA_ERR)) + if (uptr->u5 & (URCSTA_EOF|URCSTA_ERR)) { + uptr->u5 &= ~(URCSTA_EOF|URCSTA_ERR); return SCPE_IOERR; + } /* Process commands */ switch(cmd) { @@ -141,15 +143,19 @@ uint32 cdr_cmd(UNIT * uptr, uint16 cmd, uint16 dev) #endif break; default: + sim_debug(DEBUG_CMD, &cdr_dev, "%d: CMD none %02o\n", u, cmd); chan_set_attn(chan); return SCPE_IOERR; } /* If at eof, just return EOF */ - if (uptr->u5 & URCSTA_EOF) { + if (sim_card_eof(uptr)) { + uint16 *image = (uint16 *)(uptr->up7); chan_set_eof(chan); chan_set_attn(chan); - return SCPE_OK; + uptr->u5 &= ~(URCSTA_EOF|URCSTA_ERR); + (void)sim_read_card(uptr, image); + return SCPE_IOERR; } uptr->u5 |= URCSTA_READ; @@ -256,6 +262,10 @@ cdr_srv(UNIT *uptr) { #endif ch = sim_hol_to_bcd(image[uptr->u4]); + /* Handle 7-9 to generate 20 */ + if (ch == 012 && image[uptr->u4] == 0202) { + ch = 020; + } /* Handle invalid punch */ if (ch == 0x7f) { @@ -288,7 +298,7 @@ cdr_srv(UNIT *uptr) { uptr->u4++; break; } - sim_debug(DEBUG_DATA, &cdr_dev, "%d: Char > %02o\n", u, ch); + sim_debug(DEBUG_DATA, &cdr_dev, "%d: Char > %04o %02o\n", u, image[uptr->u4-1], ch); sim_activate(uptr, 10); } return SCPE_OK; diff --git a/I7000/i7000_mt.c b/I7000/i7000_mt.c index 3751c9d..ab62bf9 100644 --- a/I7000/i7000_mt.c +++ b/I7000/i7000_mt.c @@ -78,6 +78,8 @@ #define MT_EOR 002000 /* Set EOR on next record */ #define MT_UNLOAD 004000 /* Unload when rewind done */ #define MT_EGAP 010000 /* Write extended gap on next write */ +#define MT_LWR 020000 /* Last command was a write */ +#define MT_CLRIND 040000 /* On I7010 flag for SKR to clear indicator */ /* u6 holds the current buffer position */ @@ -238,9 +240,9 @@ UNIT mta_unit[] = { }; MTAB mt_mod[] = { - { MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED", + { MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED", &set_writelock, &show_writelock, NULL, "Write ring in place" }, - { MTAB_XTD|MTAB_VUN, 1, NULL, "LOCKED", + { MTAB_XTD|MTAB_VUN, 1, NULL, "LOCKED", &set_writelock, NULL, NULL, "no Write ring in place" }, {MTUF_LDN, 0, "high density", "HIGH", &mt_tape_density, NULL, NULL, "556 BPI"}, @@ -393,7 +395,7 @@ uint32 mt_cmd(UNIT * uptr, uint16 cmd, uint16 dev) /* If drive is offline or not attached return not ready */ if ((uptr->flags & (UNIT_ATT | MTUF_ONLINE)) != (UNIT_ATT | MTUF_ONLINE)) { - sim_printf("Attempt to access offline unit %s%d\n\r", dptr->name, unit); + sim_messagef(SCPE_OK, "Attempt to access offline unit %s%d\n\r", dptr->name, unit); return SCPE_IOERR; } /* Check if drive is ready to recieve a command */ @@ -798,7 +800,7 @@ t_stat mt_srv(UNIT * uptr) switch (cmd) { case 0: /* No command, stop tape */ uptr->u5 |= MT_RDY; /* Ready since command is done */ - mt_chan[chan] &= ~MTC_BSY; + mt_chan[chan] &= ~MTC_BSY; sim_debug(DEBUG_DETAIL, dptr, "Idle unit=%d\n", unit); return SCPE_OK; @@ -821,6 +823,7 @@ t_stat mt_srv(UNIT * uptr) /* Fall through */ case MT_RDSB: + uptr->u5 &= ~MT_LWR; /* Not write command */ /* Post EOR */ if (uptr->u5 & MT_EOR) { sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d post EOR\n", unit); @@ -901,13 +904,14 @@ t_stat mt_srv(UNIT * uptr) uptr->u3++; /* Do BCD translation */ if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { + sim_debug(DEBUG_DETAIL, dptr, "%s parity error %d %03o\n", + (cmd == MT_RDS) ? "BCD" : "Binary", uptr->u3-1, ch); #ifdef I7010 if (astmode) ch = 054; -#else - chan_set_attn(chan); #endif chan_set_error(chan); + } #if I7090 | I704 | I701 /* Not needed on decimal machines */ @@ -973,6 +977,7 @@ t_stat mt_srv(UNIT * uptr) mode = 0100; /* fall through */ case MT_WRSB: + uptr->u5 |= MT_LWR; /* write command */ if (uptr->u5 & MT_EGAP) { sim_debug(DEBUG_DETAIL, dptr, "Write extended Gap unit=%d\n", unit); uptr->u5 &= ~MT_EGAP; @@ -985,6 +990,8 @@ t_stat mt_srv(UNIT * uptr) (uptr->u6 > BUFFSIZE) ? DEV_WEOR : 0)) { case TIME_ERROR: #if I7090 | I701 | I704 + uptr->u5 &= ~MT_CMDMSK; + uptr->u5 |= MT_SKIP; /* If no data was written, simulate a write gap */ if (uptr->u6 == 0) { r = sim_tape_wrgap(uptr, 35); @@ -994,7 +1001,6 @@ t_stat mt_srv(UNIT * uptr) } } #endif - chan_set_attn(chan); /* fall through */ case END_RECORD: @@ -1035,6 +1041,7 @@ t_stat mt_srv(UNIT * uptr) return SCPE_OK; case MT_RDB: + uptr->u5 &= ~MT_LWR; /* not write command */ /* If tape mark pending, return it */ if (chan_test(chan, DEV_FULL) == 0 && uptr->u5 & MT_MARK) { sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d post ", unit); @@ -1117,6 +1124,7 @@ t_stat mt_srv(UNIT * uptr) return SCPE_OK; case MT_WEF: + uptr->u5 &= ~MT_LWR; /* not write command */ if (uptr->u5 & MT_EGAP) { sim_debug(DEBUG_DETAIL, dptr, "Write extended Gap unit=%d\n", unit); uptr->u5 &= ~MT_EGAP; @@ -1138,8 +1146,17 @@ t_stat mt_srv(UNIT * uptr) case MT_BSR: sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit); + /* If last command was a write, put extended gap on tape */ + if (uptr->u5 & MT_LWR) { + sim_debug(DEBUG_DETAIL, dptr, "Write extended Gap unit=%d bsr\n", unit); + r = sim_tape_wrgap(uptr, 35); + uptr->u5 &= ~MT_LWR; + sim_activate(uptr, 10*T3_us); + return SCPE_OK; + } + /* Clear tape mark, command, idle since we will need to change dir */ - uptr->u5 &= ~(MT_CMDMSK | MT_EOT | MT_RDY); + uptr->u5 &= ~(MT_CMDMSK | MT_EOT | MT_RDY | MT_LWR); r = sim_tape_sprecr(uptr, &reclen); if (r != MTSE_BOT) uptr->u3 -= GAP_LEN; @@ -1147,8 +1164,6 @@ t_stat mt_srv(UNIT * uptr) if (r == MTSE_TMK) { #ifdef I7080 chan_set_eof(chan); -#else - /* We don't set EOF on BSR */ #endif sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); sim_activate(uptr, T2_us); @@ -1160,7 +1175,7 @@ t_stat mt_srv(UNIT * uptr) return SCPE_OK; case MT_BSF: - uptr->u5 &= ~(MT_IDLE | MT_RDY | MT_EOT); + uptr->u5 &= ~(MT_IDLE | MT_RDY | MT_EOT | MT_LWR); r = sim_tape_sprecr(uptr, &reclen); if (r != MTSE_BOT) uptr->u3 -= GAP_LEN; @@ -1179,39 +1194,47 @@ t_stat mt_srv(UNIT * uptr) case MT_SKR: sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit); - /* Clear tape mark, command, idle since we will need to change dir */ - uptr->u5 &= ~(MT_CMDMSK | MT_EOT); - uptr->u5 |= (MT_RDY | MT_IDLE); + if (uptr->u5 & MT_CLRIND) { + sim_debug(DEBUG_DETAIL, dptr, "clear ind\n"); +#if I7010 + if ((uptr->u5 & MT_MARK) == 0) { + chan_clear(chan, STA_PEND); + } +#endif + chan_clear(chan, STA_TWAIT); + uptr->u5 &= ~(MT_CMDMSK | MT_EOT | MT_LWR | MT_MARK | MT_CLRIND); + uptr->u5 |= (MT_RDY | MT_IDLE); + mt_chan[chan] &= ~MTC_BSY; + sim_activate(uptr, (uptr->u6 * T1_us) + T2_us); + return SCPE_OK; + } + uptr->u5 |= (MT_CLRIND); r = sim_tape_sprecf(uptr, &reclen); uptr->u3 += GAP_LEN; - mt_chan[chan] &= ~MTC_BSY; -#if I7010 | I7080 + uptr->u6 = reclen; +#if I7080 chan_clear(chan, STA_TWAIT); #endif #ifdef I7010 chan_set(chan, STA_PEND); -#else +#endif /* We are like read that transfers nothing */ chan_set(chan, DEV_REOR); -#endif /* We don't set EOF on SKR */ if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); - sim_activate(uptr, T1_us); + uptr->u5 |= MT_MARK; + uptr->u6 = 1; + sim_activate(uptr, 2*T1_us); return SCPE_OK; -#ifdef I7010 - } else if (r == MTSE_EOM) { - chan_set(chan, STA_PEND); -#endif } sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen); - uptr->u3 += reclen; - sim_activate(uptr, (reclen * T1_us)); + sim_activate(uptr, 2*T1_us); break; case MT_ERG: sim_debug(DEBUG_DETAIL, dptr, "Erase unit=%d\n", unit); - uptr->u5 &= ~(MT_CMDMSK|MT_MARK); + uptr->u5 &= ~(MT_CMDMSK|MT_MARK|MT_LWR); uptr->u5 |= (MT_RDY | MT_IDLE); #if I7010 | I7080 chan_clear(chan, STA_TWAIT); @@ -1225,7 +1248,7 @@ t_stat mt_srv(UNIT * uptr) case MT_REW: sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d %d %d\n", unit, uptr->u3, uptr->u3 / ((uptr->flags & MTUF_LDN) ? 200 : 555) / 1200); - uptr->u5 &= ~(MT_CMDMSK | MT_IDLE | MT_RDY); + uptr->u5 &= ~(MT_CMDMSK | MT_IDLE | MT_RDY | MT_LWR); if ((uptr->u3 / ((uptr->flags & MTUF_LDN) ? 200 : 555) / 1200) > 2) { uptr->u5 |= MT_HREW; sim_activate(uptr, us_to_ticks(5000000)); @@ -1238,7 +1261,7 @@ t_stat mt_srv(UNIT * uptr) case MT_RUN: sim_debug(DEBUG_DETAIL, dptr, "Unload unit=%d\n", unit); - uptr->u5 &= ~(MT_CMDMSK | MT_IDLE | MT_RDY); + uptr->u5 &= ~(MT_CMDMSK | MT_IDLE | MT_RDY | MT_LWR); uptr->u5 |= MT_UNLOAD; if ((uptr->u3 / ((uptr->flags & MTUF_LDN) ? 200 : 555) / 1200) > 2) { uptr->u5 |= MT_HREW; @@ -1350,6 +1373,7 @@ mt_attach(UNIT * uptr, CONST char *file) if ((r = sim_tape_attach_ex(uptr, file, 0, 0)) != SCPE_OK) return r; + sim_tape_set_dens(uptr, (uptr->flags == MTUF_LDN) ? MT_DENS_200 : MT_DENS_556, NULL, NULL); uptr->u3 = 0; uptr->u5 |= MT_RDY; uptr->flags |= MTUF_ONLINE;