diff --git a/ICL1900/icl1900_cpu.c b/ICL1900/icl1900_cpu.c index 9a7050f..e42008d 100644 --- a/ICL1900/icl1900_cpu.c +++ b/ICL1900/icl1900_cpu.c @@ -34,14 +34,11 @@ #include "sim_timer.h" #define UNIT_V_MSIZE (UNIT_V_UF + 0) -#define UNIT_MSIZE (7 << UNIT_V_MSIZE) +#define UNIT_MSIZE (0x1ff << UNIT_V_MSIZE) #define MEMAMOUNT(x) (x << UNIT_V_MSIZE) -#define UNIT_V_MODEL (UNIT_V_MSIZE + 4) +#define UNIT_V_MODEL (UNIT_V_MSIZE + 9) #define UNIT_MODEL (0x3f << UNIT_V_MODEL) #define MODEL(x) (UNIT_MODEL & (x << UNIT_V_MODEL)) -#define UNIT_FLOAT (0x40 << UNIT_V_MODEL) -#define UNIT_MULT (0x100 << UNIT_V_MODEL) -#define OPTION_MASK (0x140 << UNIT_V_MODEL) #define TMR_RTC 1 @@ -72,28 +69,28 @@ #define MOD4 12 /* A2 OPT */ #define MOD4A 13 /* C2 OPT */ #define MOD4E 14 /* C2 OPT */ -#define MOD4F 12+32 -#define MOD4S 15 /* Ax OPT */ -#define MOD5 16 /* A2 FP */ -#define MOD5A 17 /* Ax FP */ -#define MOD5E 18 /* C2 FP */ -#define MOD5F 16+32 -#define MOD5S 19 /* Ax FP */ -#define MOD6 20 /* C2 OPT */ -#define MOD6A 21 /* Ax OPT 076 131 */ -#define MOD6E 22 /* Ax OPT 076 */ -#define MOD6F 20+32 -#define MOD6S 23 /* Ax OPT */ -#define MOD7 24 /* C2 FP */ -#define MOD7A 25 /* Ax FP */ -#define MOD7E 26 /* Ax FP */ -#define MOD7F 24+32 -#define MOD7S 27 /* Ax FP */ -#define MOD8 28 /* Ax FP */ -#define MOD8A 29 /* Ax FP */ -#define MOD8S 30 /* Ax FP */ -#define MOD9 31 /* A2 FP */ -#define MODXF 32 /* C2 FP */ +#define MOD4F 15 +#define MOD4S 16 /* Ax OPT */ +#define MOD5 17 /* A2 FP */ +#define MOD5A 18 /* Ax FP */ +#define MOD5E 19 /* C2 FP */ +#define MOD5F 20 +#define MOD5S 21 /* Ax FP */ +#define MOD6 22 /* C2 OPT */ +#define MOD6A 23 /* Ax OPT 076 131 */ +#define MOD6E 24 /* Ax OPT 076 */ +#define MOD6F 25 +#define MOD6S 26 /* Ax OPT */ +#define MOD7 27 /* C2 FP */ +#define MOD7A 28 /* Ax FP */ +#define MOD7E 29 /* Ax FP */ +#define MOD7F 30 +#define MOD7S 31 /* Ax FP */ +#define MOD8 32 /* Ax FP */ +#define MOD8A 33 /* Ax FP */ +#define MOD8S 34 /* Ax FP */ +#define MOD9 35 /* A2 FP */ +#define MODXF 36 /* C2 FP */ @@ -172,8 +169,12 @@ t_stat cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat cpu_show_float(FILE * st, UNIT * uptr, int32 val, + CONST void *desc); t_stat cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc); +t_stat cpu_show_mult(FILE * st, UNIT * uptr, int32 val, + CONST void *desc); t_stat cpu_show_hist(FILE * st, UNIT * uptr, int32 val, CONST void *desc); t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr, @@ -239,7 +240,7 @@ uint8 io_flags = EXT_IO; */ UNIT cpu_unit[] = - {{ UDATA(rtc_srv, MODEL(MOD4A)|UNIT_MULT|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }}; + {{ UDATA(rtc_srv, MODEL(MOD4A)|MEMAMOUNT(7)|UNIT_IDLE, MAXMEMSIZE ), 16667 }}; REG cpu_reg[] = { {ORDATAD(C, RC, 22, "Instruction code"), REG_FIT}, @@ -253,17 +254,6 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(0), NULL, "4K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(1), NULL, "8K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(3), NULL, "16K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(11), NULL, "48K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(15), NULL, "64K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(23), NULL, "96K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(31), NULL, "128K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(63), NULL, "256K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(127), NULL, "512K", &cpu_set_size}, - {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(254), NULL, "1024K", &cpu_set_size}, /* Stevenage */ {UNIT_MODEL, MODEL(MOD1), "1901", "1901", &cpu_set_model, NULL, NULL}, {UNIT_MODEL, MODEL(MOD1A), "1901A", "1901A", &cpu_set_model, NULL, NULL}, @@ -296,10 +286,21 @@ MTAB cpu_mod[] = { {UNIT_MODEL, MODEL(MOD7F), "1907F", "1907F", &cpu_set_model, NULL, NULL}, {UNIT_MODEL, MODEL(MOD8A), "1908A", "1908A", &cpu_set_model, NULL, NULL}, {UNIT_MODEL, MODEL(MOD9), "1909", "1909", &cpu_set_model, NULL, NULL}, - {UNIT_FLOAT, 0, "NOFLOAT", "NOFLOAT", &cpu_set_float, NULL, NULL}, - {UNIT_FLOAT, UNIT_FLOAT, "FLOAT", "FLOAT", &cpu_set_float, NULL, NULL}, - {UNIT_MULT, 0, "NOMULT", "NOMULT", &cpu_set_mult, NULL, NULL}, - {UNIT_MULT, UNIT_MULT, "MULT", "MULT", &cpu_set_mult, NULL, NULL}, + {MTAB_XTD|MTAB_VDV, 0, NULL, "NOFLOAT", &cpu_set_float, NULL, NULL, "Disable floating point"}, + {MTAB_XTD|MTAB_VDV, 1, "FLOAT", "FLOAT", &cpu_set_float, &cpu_show_float, NULL, "Enable floating point"}, + {MTAB_XTD|MTAB_VDV, 0, NULL, "NOMULT", &cpu_set_mult, NULL, NULL, "Disable hardware multiply"}, + {MTAB_XTD|MTAB_VDV, 1, "MULT", "MULT", &cpu_set_mult, &cpu_show_mult, NULL, "Enable hardware multiply"}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(0), NULL, "4K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(1), NULL, "8K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(3), NULL, "16K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(7), NULL, "32K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(11), NULL, "48K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(15), NULL, "64K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(23), NULL, "96K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(31), NULL, "128K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(63), NULL, "256K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(127), NULL, "512K", &cpu_set_size}, + {UNIT_MSIZE|MTAB_VDV, MEMAMOUNT(254), NULL, "1024K", &cpu_set_size}, {MTAB_VDV, 0, "MEMORY", NULL, NULL, &cpu_show_size}, {MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, {MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, @@ -324,10 +325,10 @@ uint8 Mem_test(uint32 addr) { addr &= M22; if (!exe_mode) { - if (addr < 8) + if (addr < 8) return 0; addr = addr + RD; - } else if (addr < 8) + } else if (addr < 8) return 0; if (!exe_mode && RL && (addr < RD || addr >= RL)) { @@ -441,13 +442,15 @@ sim_instr(void) intr: if (!exe_mode && (SR64 | SR65) != 0) { - if (CPU_TYPE < TYPE_C1 && !exe_mode) + if (CPU_TYPE < TYPE_C1 && !exe_mode) RC += RD; exe_mode = 1; loading = 0; /* Store registers */ - Mem_write(RD+13, &facch, 0); /* Save F.P.U. */ - Mem_write(RD+12, &faccl, 0); + if (cpu_flags & FLOAT) { + Mem_write(RD+13, &facch, 0); /* Save F.P.U. */ + Mem_write(RD+12, &faccl, 0); + } RA = 0; /* Build ZSTAT */ if (cpu_flags & SV) { Mem_read(RD+9, &RA, 0); @@ -458,12 +461,14 @@ intr: if (BCarry) RA |= B1; } else { - if (Zero) - RA |= B3; - if (OPIP | PIP) - RA |= B2; + if (CPU_TYPE >= TYPE_C1) { + if (Zero) + RA |= B3; + if (OPIP | PIP) + RA |= B2; + Mem_write(RD+9, &RA, 0); + } } - Mem_write(RD+9, &RA, 0); RA = RC & adrmask; if (BV) RA |= B0; @@ -885,10 +890,7 @@ obey: RP = XR[(RX+1) & 7]; /* VR */ RA = RB; /* Divisor to RA */ RB = XR[RX]; /* Dividend to RB/RP */ - f =0; -//fprintf(stderr, "DVD: %08o %08o %08o - %3o C=%08o\n\r", RA, RP, RB, RF, RC); - if (RA == FMASK && RP == 1 && RB == 0) /* Flag special case */ - f=1; +//fprintf(stderr, "DVD0: %08o %08o %08o - %3o C=%08o\n\r", RA, RB, RP, RF, RC); if (RA == 0) { /* Exit on zero divisor */ /* VI */ BV = 1; @@ -897,21 +899,41 @@ obey: BCarry = 0; break; } - BCarry = (RP & B0) != 0; - n = (RP | RB) == 0; /* Save zero dividend */ /* Setup for specific divide order code */ /* V11 */ if (RF & 2) { /* DVS */ - if (BCarry) { + if (RP & B0) { /* RC22 */ /* Sign extend RB */ RB = FMASK; } else { RB = 0; } } + +// { +// long int divsor; +// long int dividend; +// int sign; +// +// dividend = (((long int)(RB)) << 23) | (long int)(RP); +// if (RB & B0) { +// dividend |= 0xffff800000000000; +// } +// sign = 1; +// divsor = (long int)(RA); +// if (RA & B0) { +// divsor |= 0xffffffffff000000; +// sign = -1; +// } +//fprintf(stderr, "DVD1: %08o %08o %08o %ld (%lo) / %ld (%lo) = %ld (%lo) m %ld (%lo) %o\n\r", RA, RB, RP, +// dividend, dividend, divsor, divsor, dividend/divsor, dividend/divsor, +// sign* (dividend%divsor), sign *(dividend % divsor), BV); +//} + BCarry = 0; + if ((RB | RP) == 0) + goto dvd_zero; RP <<= 1; RP &= FMASK; BCarry = 0; -//fprintf(stderr, "DVD1: %08o %08o %08o \n\r", RA, RP, RB); /* First partial remainder */ /* V12 */ if (((RB ^ RA) & B0) == 0) { @@ -921,12 +943,14 @@ obey: RS = RB + RA; RK=0; } + /* Check if potiential overflow */ if (((RS ^ RA) & B0) != 0) BCarry = 1; BCarry = RK != BCarry; + /* Shift left quotent and remainder */ RP <<= 1; if (((RS ^ RA) & B0) == 0) { - RP |= 1; + RP |= 1; /* First quotient digit */ } RB = RS << 1; if (RP & BM1) @@ -951,7 +975,7 @@ obey: RB |= 1; RB &= FMASK; RP &= FMASK; -//fprintf(stderr, "DVD3: %08o %08o %08o \n\r", RA, RP, RB); +//fprintf(stderr, "DVD3: %08o %08o %08o %08o \n\r", RA, RP, RB, RS); } /* Final product */ @@ -965,61 +989,58 @@ obey: RP |= 1; } RP &= FMASK; -//fprintf(stderr, "DVD4: %08o %08o %08o \n\r", RA, RP, RB); - - /* Final Remainder */ - if (RP & 1) { - RB = (RB + (RA ^ FMASK) + 1) & FMASK; - } else { - RB = (RB + RA) & FMASK; - } + RB = RS & FMASK; +//fprintf(stderr, "DVD4: %08o %08o %08o %08o \n\r", RA, RP, RB, RS); /* End correction */ if ((RP & 1) == 0) { RB = (RB + RA) & FMASK; } //fprintf(stderr, "DVD5: %08o %08o %08o \n\r", RA, RP, RB); - /* Form final partial product */ - if (RA & B0) { - RS = (RB + (RA ^ FMASK) + 1) & FMASK; -//fprintf(stderr, "DVD5: %08o %08o %08o %08o\n\r", RA, RP, RB, RT); - if (RS == 0) { - RB = 0; - goto dvd1; - } - } - if ((RF & 1) == 0) /* DVR */ - goto dvd2; - if (RB == 0) - goto dvd2; - RT = RB + (RA ^ FMASK) + 1; -//fprintf(stderr, "DVDA: %08o %08o %08o %08o \n\r", RA, RP, RB, RT); - RA = RB; - if ((((RT + RA) ^ RA) & B0) != 0) - goto dvd2; - RB = RT & FMASK; -dvd1: -//fprintf(stderr, "DVD6: %08o %08o %08o \n\r", RA, RP, RB); - RT = RP; - RP++; - if ((RT ^ RP) & B0) - BCarry = !BCarry; - if (RP & BM1) - BCarry = 1; -dvd2: + if ((RF & 1) == 0 || RB == 0) { //fprintf(stderr, "DVD7: %08o %08o %08o \n\r", RA, RP, RB); - if (n) - BCarry = 0; + /* If remainder same as divisor, bump quotent zero remainder */ + if (RB == RA) { + RT = RP; + RP++; + if ((RT & B0) != (RP & B0)) + BCarry = !BCarry; + RB = 0; + } + } else { /* DVR */ + RT = RB + (RA ^ FMASK) + 1; +//fprintf(stderr, "DVDA: %08o %08o %08o %08o \n\r", RA, RP, RB, RT); + RA = RB; + if ((((RT + RA) ^ RA) & B0) == 0) { + RB = RT & FMASK; +//fprintf(stderr, "DVD6: %08o %08o %08o \n\r", RA, RP, RB); + RT = RP; + RP++; + if ((RT ^ RP) & B0) + BCarry = !BCarry; + if (RP & BM1) + BCarry = 1; + } + } +dvd_zero: + /* Set overflow if BCarry still set */ if (BCarry) { BV = 1; if (!exe_mode && (Mode & 7) == 4) SR64 |= B2; } BCarry = 0; - if (f) { - RB = 0; - RP = FMASK; -//fprintf(stderr, "DVD8: %08o %08o %08o \n\r", RA, RP, RB); - } +// { +// int32 a; +// int32 b; +// +// a = RB; +// if (RB & B0) +// a |= 0xff000000; +// b = RP; +// if (RP & B0) +// b |= 0xff000000; +//fprintf(stderr, "DVD8: q=%08o(%d) r=%08o(%d) %d %d %d\n\r", RP, b, RB, a, BV); +//} XR[RX] = RB & FMASK; XR[(RX+1) & 7] = RP & FMASK; break; @@ -1518,7 +1539,7 @@ norm1: /* Not on A*/ case OP_SMO: /* Supplementary Modifier - BC */ - if (CPU_TYPE < TYPE_B1) + if (CPU_TYPE < TYPE_C1) goto voluntary; if (OPIP) { /* Error */ SR64 |= B1; @@ -1528,7 +1549,7 @@ norm1: goto intr; } PIP = 1; - break; + goto fetch; case OP_NULL: /* No Operation */ if (!exe_mode && RX == 7 && (Mode & 7) > 0 && (Mode & 7) < 5) @@ -2128,7 +2149,7 @@ fexp: case 0151: case 0160: /* Stevenage machines */ /* Load accumulators */ case 0161: /* Stevenage machines */ /* Store accumulators */ - case 0162: /* Stevenage machines */ + case 0162: /* Stevenage machines */ case 0163: /* Stevenage machines */ /* Stope and Display */ case 0164: /* Stevenage machines */ /* Search List N for Word X */ case 0165: /* Stevenage machines */ /* Parity Search */ @@ -2143,7 +2164,7 @@ fexp: case 1: RA = SR1; break; case 64: RA = SR64; SR64 &= 003777777; break; case 65: RA = SR65; break; - default: if (RB < 64) + default: if (RB < 64) chan_nsi_status(RB, &RA); break; } @@ -2154,7 +2175,7 @@ fexp: case 0171: /* Write special register */ if (exe_mode) { //fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); - if (RB < 64) + if (RB < 64) chan_nsi_cmd(RB, RA); break; } @@ -2240,25 +2261,27 @@ voluntary: reason = SCPE_STOP; break; } - if (CPU_TYPE < TYPE_C1 && !exe_mode) + if (CPU_TYPE < TYPE_C1 && !exe_mode) RC += RD; exe_mode = 1; /* Store registers */ Mem_write(RD+13, &facch, 0); /* Save F.P.U. */ Mem_write(RD+12, &faccl, 0); - RA = 0; /* Build ZSTAT */ - if (Zero) - RA |= B3; - if (OPIP) - RA |= B2; - Mem_write(RD+9, &RA, 0); + if (CPU_TYPE >= TYPE_C1) { + RA = 0; /* Build ZSTAT */ + if (Zero) + RA |= B3; + if (OPIP) + RA |= B2; + Mem_write(RD+9, &RA, 0); + } RA = RC; if (BV) RA |= B0; if (BCarry) RA |= B1; /* Type A & B */ - if (CPU_TYPE < TYPE_C1 && Zero) + if (CPU_TYPE < TYPE_C1 && Zero) RA |= B8; Mem_write(RD+8, &RA, 0); for (n = 0; n < 8; n++) @@ -2382,12 +2405,8 @@ cpu_set_model(UNIT * uptr, int32 val, CONST char *cptr, void *desc) cpu_flags = ptr->cpu_flags; io_flags = ptr->io_flags; rtc_tps = ptr->ticker; - cpu_unit[0].flags &= ~(UNIT_MODEL|UNIT_FLOAT|UNIT_MULT); + cpu_unit[0].flags &= ~(UNIT_MODEL); cpu_unit[0].flags |= MODEL(val); - if (cpu_flags & FLOAT) - cpu_unit[0].flags |= UNIT_FLOAT; - if (cpu_flags & MULT) - cpu_unit[0].flags |= UNIT_MULT; return SCPE_OK; } } @@ -2398,10 +2417,6 @@ t_stat cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc) { int32 oval = val; - if (val == 0 && (cpu_flags & (FLOAT_OPT|FLOAT)) == FLOAT) - val = UNIT_FLOAT; - cpu_unit[0].flags &= ~UNIT_FLOAT; - cpu_unit[0].flags |= val; cpu_flags &= ~FLOAT; if (val) cpu_flags |= FLOAT; @@ -2410,14 +2425,17 @@ cpu_set_float(UNIT * uptr, int32 val, CONST char *cptr, void *desc) return SCPE_OK; } +t_stat +cpu_show_float(FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + fprintf(st, "%s", (cpu_flags & FLOAT) ? "FLOAT":"NOFLOAT"); + return SCPE_OK; +} + t_stat cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc) { int32 oval = val; - if (val == 0 && (cpu_flags & (MULT_OPT|MULT)) == MULT) - val = UNIT_MULT; - cpu_unit[0].flags &= ~UNIT_MULT; - cpu_unit[0].flags |= val; cpu_flags &= ~MULT; if (val) cpu_flags |= MULT; @@ -2425,6 +2443,13 @@ cpu_set_mult(UNIT * uptr, int32 val, CONST char *cptr, void *desc) return SCPE_ARG; return SCPE_OK; } + +t_stat +cpu_show_mult(FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + fprintf(st, "%s", (cpu_flags & MULT) ? "MULT":"NOMULT"); + return SCPE_OK; +} /* Handle execute history */ diff --git a/ICL1900/icl1900_cty.c b/ICL1900/icl1900_cty.c index a5c7bda..b7c08ef 100644 --- a/ICL1900/icl1900_cty.c +++ b/ICL1900/icl1900_cty.c @@ -42,7 +42,7 @@ DIB cty_dib = { CHAR_DEV, NULL, cty_cmd, cty_status}; #define CMD u3 #define STATUS u4 #define HOLD u5 - + #define START 01 #define STOP 02 #define END 000001 @@ -104,7 +104,7 @@ DEVICE cty_dev = { void cty_cmd(int dev, uint32 cmd) { int u = 0; - if (dev > 3) + if (dev > 3) return; if (dev == 2) u++; @@ -113,8 +113,8 @@ void cty_cmd(int dev, uint32 cmd) { cty_unit[u].STATUS |= BUSY; if (!u) sim_activate(&cty_unit[u], cty_unit[u].wait); - } - else if (cmd & STOP) { + } + else if (cmd & STOP) { cty_unit[u].STATUS &= ~BUSY; } cty_unit[u].STATUS &= BUSY; @@ -124,7 +124,7 @@ void cty_cmd(int dev, uint32 cmd) { void cty_status(int dev, uint32 *resp) { int u = 0; - if (dev > 3) + if (dev > 3) return; if (dev == 2) u++; @@ -142,7 +142,7 @@ t_stat ctyo_svc (UNIT *uptr) /* Check if we had a held characteter */ if (uptr->HOLD != 0) { if ((r = sim_putchar_s (uptr->HOLD)) == SCPE_STALL) { - r = SCPE_OK; + r = SCPE_OK; } else { if (uptr->HOLD == '\r') uptr->HOLD = '\n'; @@ -153,7 +153,7 @@ t_stat ctyo_svc (UNIT *uptr) return r; } - if (uptr->STATUS & BUSY) { + if (uptr->STATUS & BUSY) { eor = chan_output_char(GET_UADDR(uptr->flags), &ch, 0); switch (ch & 060) { case 000: ch = 0060 | (ch & 017); break; @@ -238,7 +238,7 @@ t_stat ctyi_svc (UNIT *uptr) default: sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch); - if (ch >= 0140) + if (ch >= 0140) ch -= 040; if (ch >= 0100) ch -= 040; @@ -286,7 +286,7 @@ t_stat ctyi_svc (UNIT *uptr) uptr->HOLD = 0; chan_set_done(GET_UADDR(uptr->flags)); break; - + default: sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch); sim_putchar('\007'); diff --git a/ICL1900/icl1900_defs.h b/ICL1900/icl1900_defs.h index 213cf04..f3d7a98 100755 --- a/ICL1900/icl1900_defs.h +++ b/ICL1900/icl1900_defs.h @@ -32,9 +32,9 @@ #define NUM_DEVS_PTP 2 #define NUM_DEVS_CDR 0 #define NUM_DEVS_CDP 0 -#define NUM_DEVS_LPR 0 +#define NUM_DEVS_LPR 1 #define NUM_DEVS_CON 0 -#define NUM_DEVS_MT 0 /* 1971 SI tape drives */ +#define NUM_DEVS_MT 4 /* 1971 SI tape drives */ #define NUM_DEVS_MTA 8 /* 1974 NSI tape drives */ #define NUM_DEVS_DSK 0 #define NUM_DEVS_DTC 0 diff --git a/ICL1900/icl1900_lp.c b/ICL1900/icl1900_lp.c new file mode 100644 index 0000000..dae8708 --- /dev/null +++ b/ICL1900/icl1900_lp.c @@ -0,0 +1,352 @@ +/* icl1900_lp.c: ICL1900 Line Printer simulator + + Copyright (c) 2018, Richard Cornwell + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Richard Cornwell shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Richard Cornwell + +*/ + +#include "icl1900_defs.h" + +#ifndef NUM_DEVS_LPR +#define NUM_DEVS_LPR 0 +#endif + +#define UNIT_V_TYPE (UNIT_V_UF + 1) +#define UNIT_TYPE (0x1f << UNIT_V_TYPE) +#define GET_TYPE(x) ((UNIT_TYPE & (x)) >> UNIT_V_TYPE) +#define SET_TYPE(x) (UNIT_TYPE & ((x) << UNIT_V_TYPE)) + +#define NSI_TYPE(x) ((GET_TYPE(x) & 1) == 0) +#define SI_TYPE(x) ((GET_TYPE(x) & 1) != 0) +#define LW_96(x) ((GET_TYPE(x) & 06) == 0) +#define LW_120(x) ((GET_TYPE(x) & 06) == 2) +#define LW_160(x) ((GET_TYPE(x) & 06) == 4) + +#define CMD u3 +#define STATUS u4 +#define MOTION u5 + +#define AUTO 00100 +#define PRINT 00040 +#define SPACE 00010 + +#define TERMINATE 0001 +#define OPAT 0002 +#define ERROR 0004 +#define BUSY 0040 +#define DISC 0100 + + +#if (NUM_DEVS_LPR > 0) + +#define T1930_1 0 +#define T1930_2 2 +#define T1931_1 1 +#define T1931_2 3 +#define T1932_1 1+8 +#define T1932_2 3+8 +#define T1933_1 1+12 +#define T1933_2 3+12 +#define T1933_3 5+12 + +#define UNIT_LPR(x) UNIT_ADDR(x)|SET_TYPE(T1931_2)|UNIT_ATTABLE|\ + UNIT_DISABLE|UNIT_TEXT + + +void lpr_cmd (int dev, uint32 cmd, uint32 *resp); +void lpr_nsi_cmd (int dev, uint32 cmd); +void lpr_nsi_status (int dev, uint32 *resp); +t_stat lpr_svc (UNIT *uptr); +t_stat lpr_reset (DEVICE *dptr); +t_stat lpr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +CONST char *lpr_description (DEVICE *dptr); + +DIB lpr_dib = { CHAR_DEV, &lpr_cmd, &lpr_nsi_cmd, &lpr_nsi_status }; + +UNIT lpr_unit[] = { + { UDATA (&lpr_svc, UNIT_LPR(11), 0), 10000 }, + { UDATA (&lpr_svc, UNIT_LPR(13), 0), 10000 }, + }; + + +MTAB lpr_mod[] = { + { UNIT_TYPE, SET_TYPE(T1930_1), "1930/1", "1930/1", NULL, NULL, "ICL 1930/1 NSI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1930_2), "1930/2", "1930/2", NULL, NULL, "ICL 1930/2 NSI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1931_1), "1931/1", "1931/1", NULL, NULL, "ICL 1931/1 SI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1931_2), "1931/2", "1931/2", NULL, NULL, "ICL 1931/2 SI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1932_1), "1932/1", "1932/1", NULL, NULL, "ICL 1932/1 SI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1932_2), "1932/2", "1932/2", NULL, NULL, "ICL 1932/2 SI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1933_1), "1933/1", "1933/1", NULL, NULL, "ICL 1933/1 SI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1933_2), "1933/2", "1933/2", NULL, NULL, "ICL 1933/2 SI 1000LPM printer."}, + { UNIT_TYPE, SET_TYPE(T1933_3), "1933/3", "1933/3", NULL, NULL, "ICL 1933/3 SI 1000LPM printer."}, + {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV", &set_chan, &get_chan, NULL, "Device Number"}, + { 0 } + }; + +DEVICE lpr_dev = { + "LP", lpr_unit, NULL, lpr_mod, + NUM_DEVS_PTP, 8, 22, 1, 8, 22, + NULL, NULL, &lpr_reset, NULL, &attach_unit, &detach_unit, + &lpr_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, &lpr_help, NULL, NULL, &lpr_description + }; + +/* + * Command codes + * + * 011010 Write + * 000010 AutoWrite + * 010000 Send Q. + * 010100 Send P. + * 011110 Disconnect. + */ + + +void lpr_cmd(int dev, uint32 cmd, uint32 *resp) { + int i; + UNIT *uptr = NULL; + + *resp = 0; + /* Find the unit from dev */ + for (i = 0; i < lpr_dev.numunits; i++) { + if (GET_UADDR(lpr_unit[i].flags) == dev) { + uptr = &lpr_unit[i]; + break; + } + } + + /* Should not happen, but just in case */ + if (uptr == NULL) + return; + + /* Ignore this command if not a SI device */ + if (NSI_TYPE(uptr->flags)) + return; + + if ((uptr->flags & UNIT_ATT) == 0) + return; + + if (cmd == 032 || cmd == 02) { /* Command */ + if (uptr->STATUS & BUSY) { + *resp = 3; + return; + } + uptr->CMD = (cmd == 02) ? AUTO: 0; + uptr->STATUS = BUSY; + sim_activate(uptr, uptr->wait); + chan_clr_done(GET_UADDR(uptr->flags)); + *resp = 5; + } else if (cmd == SEND_Q) { + if ((uptr->flags & UNIT_ATT) == 0) + *resp = 040; + if (uptr->STATUS & 06) + *resp = 040; + *resp |= uptr->STATUS & TERMINATE; + } else if (cmd == SEND_P) { /* Send P */ + if ((uptr->flags & UNIT_ATT) != 0) + *resp = (uptr->STATUS & ERROR) | 1; + uptr->STATUS = 0; + chan_clr_done(GET_UADDR(uptr->flags)); + } else if (cmd == DISCO) { /* Disconnect */ + uptr->STATUS |= DISC; + *resp = 5; + } + sim_debug(DEBUG_CMD, &lpr_dev, "CMD: %03o %03o %03o\n", cmd, uptr->CMD, uptr->STATUS); +} + +/* + * Command codes + * + * xxxx01 Start print. + * xxxx10 Stop print. + */ +void lpr_nsi_cmd(int dev, uint32 cmd) { + int i; + UNIT *uptr = NULL; + + /* Find the unit from dev */ + for (i = 0; i < NUM_DEVS_PTP; i++) { + if (GET_UADDR(lpr_unit[i].flags) == dev) { + uptr = &lpr_unit[i]; + break; + } + } + + /* Should not happen, but just in case */ + if (uptr == NULL) + return; + + /* Ignore this command if not a SI device */ + if (SI_TYPE(uptr->flags)) + return; + + + if (cmd & 02) { + if (uptr->STATUS & BUSY) + uptr->STATUS |= DISC; + return; + } + + if (cmd & 01) { + if (uptr->CMD & BUSY || (uptr->flags & UNIT_ATT) == 0) { + uptr->STATUS |= OPAT; + chan_set_done(GET_UADDR(uptr->flags)); + return; + } + uptr->CMD |= 0; + uptr->STATUS = BUSY; + sim_activate(uptr, uptr->wait); + chan_clr_done(GET_UADDR(uptr->flags)); + sim_debug(DEBUG_CMD, &lpr_dev, "CMD: %03o %03o %03o\n", cmd, uptr->CMD, uptr->STATUS); + } +} + +/* + * NSI Status bits. + * + * 001 End. + * 002 Opat. + * 004 ERROR + * 020 ACCEPT + * 040 BUSY + */ +void lpr_nsi_status(int dev, uint32 *resp) { + int i; + UNIT *uptr = NULL; + + *resp = 0; + /* Find the unit from dev */ + for (i = 0; i < NUM_DEVS_PTP; i++) { + if (GET_UADDR(lpr_unit[i].flags) == dev) { + uptr = &lpr_unit[i]; + break; + } + } + + /* Should not happen, but just in case */ + if (uptr == NULL) + return; + + /* Ignore this command if not a SI device */ + if (SI_TYPE(uptr->flags)) + return; + + *resp = uptr->STATUS & 077; + uptr->STATUS &= BUSY|DISCO ; + chan_clr_done(GET_UADDR(uptr->flags)); + sim_debug(DEBUG_CMD, &lpr_dev, "ST: %08o %03o %03o\n", *resp, uptr->CMD, uptr->STATUS); +} + + + +t_stat lpr_svc (UNIT *uptr) +{ + t_stat r; + uint8 ch; + int data; + char buffer[200]; + int i; + int len; + int eor; + + /* Handle a disconnect request */ + if (uptr->STATUS & DISC) { + uptr->STATUS &= ~(BUSY|DISC); + uptr->STATUS |= TERMINATE; + chan_set_done(GET_UADDR(uptr->flags)); + return SCPE_OK; + } + /* If not busy, false schedule, just exit */ + if ((uptr->STATUS & BUSY) == 0) + return SCPE_OK; + + /* Check if attached */ + if ((uptr->flags & UNIT_ATT) == 0) { + uptr->STATUS = ERROR|TERMINATE; + chan_set_done(GET_UADDR(uptr->flags)); + return SCPE_OK; + } + + len = 96; + if (LW_120(uptr->flags)) + len = 120; + else if (LW_160(uptr->flags)) + len = 160; + for (i = 0; i < len && eor == 0; i++) { + eor = chan_output_char(GET_UADDR(uptr->flags), &ch, 0); + sim_debug(DEBUG_DATA, &lpr_dev, "DATA: %03o\n", ch); + switch (ch & 060) { + case 000: ch = 0060 | (ch & 017); break; + case 020: ch = 0040 | (ch & 017); break; + case 040: ch = 0100 | (ch & 017); break; + case 060: ch = 0120 | (ch & 017); break; + } + buffer[i] = ch; + } + buffer[i++] = '\r'; + buffer[i++] = '\n'; + buffer[i++] = '\0'; + + sim_fwrite(&buffer, 1, i, uptr->fileref); + /* Check if Done */ + if (eor) { + uptr->STATUS |= TERMINATE; + uptr->STATUS &= ~(BUSY|DISC); + chan_set_done(GET_UADDR(uptr->flags)); + return SCPE_OK; + } + return SCPE_OK; +} + + +/* Reset */ + +t_stat lpr_reset (DEVICE *dptr) +{ + UNIT *uptr = dptr->units; + int unit; + + for (unit = 0; unit < NUM_DEVS_PTP; unit++, uptr++) { + uptr->STATUS = 0; + chan_clr_done(GET_UADDR(uptr->flags)); + } + return SCPE_OK; +} + + +t_stat lpr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "The Paper Tape Punch can be set to one of two modes: 7P, or 7B.\n\n"); +fprintf (st, " mode \n"); +fprintf (st, " 7P Process even parity input tapes. \n"); +fprintf (st, " 7B Ignore parity of input data.\n"); +fprintf (st, "The default mode is 7B.\n"); +return SCPE_OK; +} + +CONST char *lpr_description (DEVICE *dptr) +{ + return "PTP"; + +} +#endif diff --git a/ICL1900/icl1900_mt.c b/ICL1900/icl1900_mt.c new file mode 100644 index 0000000..9079966 --- /dev/null +++ b/ICL1900/icl1900_mt.c @@ -0,0 +1,584 @@ +/* icl1900_mt.c: ICL1900 2504 mag tape drive simulator. + + Copyright (c) 2018, Richard Cornwell + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Richard Cornwell shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Richard Cornwell + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32b byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. + +*/ + +#include "icl1900_defs.h" +#include "sim_tape.h" + +#if (NUM_DEVS_MT > 0) +#define BUFFSIZE (64 * 1024) +#define UNIT_MT UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE + +#define CMD u3 /* Command */ +#define STATUS u4 +#define POS u6 /* Position within buffer */ + + +/* Command is packed follows: + * + * Lower 3 bits is command. + * Next bit is binary/BCD. + * Next bit is disconnect flag. + * Top 16 bits are count. + */ + +#define MT_CMD 077 + +#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF) +#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF + +#define MT_NOP 000 +#define MT_FSF 001 /* No Qualifier */ +#define MT_BSR 002 /* Qualifier */ +#define MT_BSF 003 /* Qualifier */ +#define MT_REV_READ 011 /* Qualifier */ +#define MT_WRITEERG 012 /* Qualifier */ +#define MT_WTM 013 /* Qualifier */ +#define MT_TEST 014 /* Qualifier */ +#define MT_REW 016 /* No Qualifier */ +#define MT_READ 031 /* Qualifier */ +#define MT_WRITE 032 /* Qualifier */ +#define MT_RUN 036 /* No Qualifier */ +#define MT_BOOT 037 /* No Qualifier */ + +#define MT_QUAL 0100 /* Qualifier expected */ +#define MT_BUSY 0200 /* Device running command */ + +#define ST1_OK 00100 /* Unit OK */ +#define ST1_WARN 00200 /* Warning, EOT, BOT, TM */ +#define ST1_ERR 00400 /* Parity error, blank, no unit */ +#define ST1_CORERR 01000 /* Corrected error */ +#define ST1_LONG 02000 /* Long Block */ +#define ST1_P2 040 /* P2 Status */ + +#define ST2_ROWS 0030000 /* Number of rows read */ +#define ST2_BLNK 0040000 /* Blank Tape */ + +#define STQ_TERM 001 /* Operation terminated */ +#define STQ_WRP 002 /* Write ring present */ +#define STQ_ACCP 004 /* Handler accepted order */ +#define STQ_S1 010 /* Controller ready to accept */ +#define STQ_S2 020 /* Controller ready to accept */ +#define STQ_P1 040 /* P1 Status on */ + + +int mt_busy; /* Indicates that controller is talking to a drive */ +int mt_drive; /* Indicates last selected drive */ +uint8 mt_buffer[BUFFSIZE]; +void mt_cmd (int dev, uint32 cmd, uint32 *resp); +t_stat mt_svc (UNIT *uptr); +t_stat mt_reset (DEVICE *dptr); +t_stat mt_boot (int32 unit_num, DEVICE * dptr); +t_stat mt_attach(UNIT *, CONST char *); +t_stat mt_detach(UNIT *); +t_stat mt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +CONST char *mt_description (DEVICE *dptr); + +DIB mt_dib = { WORD_DEV|MULT_DEV, &mt_cmd, NULL, NULL }; + + +MTAB mt_mod[] = { + {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL}, + {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL}, + {MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL}, + {MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", + &set_chan, &get_chan, NULL, "Device Number"}, + {0} +}; + +UNIT mt_unit[] = { + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 0 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 1 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 2 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 3 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 4 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 5 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 6 */ + {UDATA(&mt_svc, UNIT_MT, 0) }, /* 7 */ +}; + +DEVICE mt_dev = { + "MT", mt_unit, NULL, mt_mod, + NUM_DEVS_MT, 8, 22, 1, 8, 22, + NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach, + &mt_dib, DEV_DISABLE | DEV_DEBUG | UNIT_ADDR(20), 0, dev_debug, + NULL, NULL, &mt_help, NULL, NULL, &mt_description + }; + +void mt_cmd(int dev, uint32 cmd, uint32 *resp) { + UNIT *uptr = &mt_unit[mt_drive]; + *resp = 0; + if (dev & 0400) { + mt_drive = cmd & 07; + return; + } + if ((uptr->flags & UNIT_ATT) == 0) { + uptr->CMD = 0; + return; + } + if (uptr->CMD & MT_QUAL) { + *resp = 5; + uptr->CMD &= ~MT_QUAL; + } else { + switch(cmd & 070) { + case 000: if (cmd == 0) { + *resp = 5; + return; + } + uptr->CMD = cmd; + if (cmd != 1) + uptr->CMD |= MT_QUAL; + break; + case 010: uptr->CMD = cmd; + if (cmd < 016) + uptr->CMD |= MT_QUAL; + break; + case 020: if (cmd == SEND_Q) { + if (!sim_tape_wrp(uptr)) + uptr->STATUS |= STQ_WRP; + *resp = uptr->STATUS & 037; + if (uptr->STATUS & 0777700) + *resp |= STQ_P1; + } else if (cmd == SEND_P) { + *resp = (uptr->STATUS >> 6) & 037; + if (uptr->STATUS & 0770000) + *resp |= ST1_P2; + } else if (cmd == SEND_P2) { + *resp = (uptr->STATUS >> 12) & 037; + } + return; + case 030: uptr->CMD = cmd; + if (cmd < 036) + uptr->CMD |= MT_QUAL; + break; + default: + return; + } + } + sim_debug(DEBUG_CMD, &mt_dev, "Cmd: unit=%d %02o\n", mt_drive, uptr->CMD); + if (uptr->flags & MT_BUSY) { + *resp = 3; + return; + } + if ((uptr->CMD & MT_QUAL) == 0) { + sim_debug(DEBUG_CMD, &mt_dev, "Cmd: unit=%d start %02o\n", mt_drive, uptr->CMD); + mt_busy = 1; + CLR_BUF(uptr); + uptr->POS = 0; + uptr->CMD |= MT_BUSY; + uptr->STATUS = ST1_OK|STQ_ACCP; + sim_activate(uptr, 100); + } + *resp = 5; +} + +t_stat mt_svc (UNIT *uptr) +{ + DEVICE *dptr = &mt_dev; + int unit = (uptr - dptr->units); + int dev = GET_UADDR(dptr->flags); + t_mtrlnt reclen; + t_stat r; + uint8 ch; + uint32 word; + int i; + int stop; + int eor; + + /* If not busy, false schedule, just exit */ + if ((uptr->CMD & MT_BUSY) == 0) + return SCPE_OK; + switch (uptr->CMD & MT_CMD) { + case MT_BOOT: + case MT_READ: + /* If empty buffer, fill */ + if (BUF_EMPTY(uptr)) { + sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d ", unit); + if ((r = sim_tape_rdrecf(uptr, &mt_buffer[0], &reclen, + BUFFSIZE)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r); + uptr->STATUS = ST1_OK|STQ_TERM; + if (r == MTSE_TMK) + uptr->STATUS |= ST1_WARN; + else if (r == MTSE_WRP) + uptr->STATUS |= ST1_ERR; + else if (r == MTSE_EOM) + uptr->STATUS |= ST1_WARN; + else + uptr->STATUS |= ST1_ERR; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + uptr->hwmark = reclen; + sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); + } + stop = 0; + /* Grab three chars off buffer */ + word = 0; + for(i = 16; i >= 0; i-=8) { + if (uptr->POS >= uptr->hwmark) { + /* Add in fill characters */ + if (i == 8) { + stop = 2; + } else if (i == 16) { + stop = 1; + } + break; + } + word |= (uint32)mt_buffer[uptr->POS++] << i; + } + sim_debug(DEBUG_DATA, dptr, "unit=%d read %08o\n", unit, word); + eor = chan_input_word(dev, &word, 0); + if (eor || uptr->POS >= uptr->hwmark) { + uptr->STATUS = (stop << 12) | ST1_OK|STQ_TERM; + if (uptr->POS < uptr->hwmark) + uptr->STATUS |= ST1_LONG; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + sim_activate(uptr, 100); + break; + + case MT_WRITEERG: /* Write and Erase */ + case MT_WRITE: + /* Check if write protected */ + if (sim_tape_wrp(uptr)) { + uptr->STATUS = ST1_OK|STQ_TERM|ST1_ERR; + uptr->CMD &= ~MT_BUSY; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + + eor = chan_output_word(dev, &word, 0); + sim_debug(DEBUG_DATA, dptr, "unit=%d write %08o\n", unit, word); + + /* Put three chars in buffer */ + word = 0; + for(i = 16; i >= 0; i-=8) { + mt_buffer[uptr->POS++] = (uint8)((word >> i) & 0xff); + } + uptr->hwmark = uptr->POS; + if (eor) { + /* Done with transfer */ + reclen = uptr->hwmark; + sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d chars\n", + unit, reclen); + r = sim_tape_wrrecf(uptr, &mt_buffer[0], reclen); + uptr->STATUS = ST1_OK|STQ_TERM; + if (r != MTSE_OK) + uptr->STATUS |= ST1_ERR; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + sim_activate(uptr, 100); + break; + + case MT_REV_READ: + /* If empty buffer, fill */ + if (BUF_EMPTY(uptr)) { + if (sim_tape_bot(uptr)) { + uptr->STATUS = ST1_OK|ST1_WARN|STQ_TERM; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + sim_debug(DEBUG_DETAIL, dptr, "Read rev unit=%d ", unit); + if ((r = sim_tape_rdrecr(uptr, &mt_buffer[0], &reclen, + BUFFSIZE)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r); + uptr->STATUS = ST1_OK|STQ_TERM; + if (r == MTSE_TMK) + uptr->STATUS |= ST1_WARN; + else if (r == MTSE_WRP) + uptr->STATUS |= ST1_ERR; + else if (r == MTSE_EOM) + uptr->STATUS |= ST1_WARN; + else + uptr->STATUS |= ST1_ERR; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + uptr->POS = reclen; + uptr->hwmark = reclen; + sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); + } + /* Grab three chars off buffer */ + word = 0; + for(i = 0; i <= 16; i+=8) { + word |= (uint32)mt_buffer[--uptr->POS] << i; + if (uptr->POS == 0) { + stop = 1; + break; + } + } + sim_debug(DEBUG_DATA, dptr, "unit=%d read %08o\n", unit, word); + eor = chan_input_word(dev, &word, 0); + if (eor || uptr->POS == 0) { + uptr->STATUS = (stop << 12) | ST1_OK|STQ_TERM; + if (uptr->POS != 0) + uptr->STATUS |= ST1_LONG; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + sim_activate(uptr, 100); + break; + + case MT_FSF: + switch(uptr->POS) { + case 0: + uptr->POS ++; + sim_activate(uptr, 500); + break; + case 1: + sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit); + r = sim_tape_sprecf(uptr, &reclen); + if (r == MTSE_TMK) { + uptr->POS++; + sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); + sim_activate(uptr, 50); + } else if (r == MTSE_EOM) { + uptr->POS++; + uptr->STATUS = ST1_WARN; + sim_activate(uptr, 50); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen); + sim_activate(uptr, 10 + (10 * reclen)); + } + break; + case 2: + uptr->STATUS = ST1_OK|(ST1_WARN & uptr->STATUS) | STQ_TERM; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + } + break; + + case MT_WTM: + if (uptr->POS == 0) { + if (sim_tape_wrp(uptr)) { + uptr->STATUS = ST1_OK|ST1_ERR|STQ_TERM; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + uptr->POS ++; + sim_activate(uptr, 500); + } else { + sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit); + r = sim_tape_wrtmk(uptr); + uptr->STATUS = ST1_OK|STQ_TERM; + if (r != MTSE_OK) + uptr->STATUS |= ST1_ERR; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + } + break; + + case MT_BSR: + switch (uptr->POS ) { + case 0: + if (sim_tape_bot(uptr)) { + uptr->STATUS = ST1_OK|ST1_WARN|STQ_TERM; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + break; + } + uptr->POS ++; + sim_activate(uptr, 500); + break; + case 1: + sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit); + r = sim_tape_sprecr(uptr, &reclen); + /* We don't set EOF on BSR */ + uptr->STATUS = ST1_OK|STQ_TERM; + if (r == MTSE_TMK || r == MTSE_BOT) { + uptr->STATUS |= ST1_WARN; + } + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + } + break; + + case MT_BSF: + switch (uptr->POS ) { + case 0: + if (sim_tape_bot(uptr)) { + uptr->STATUS = ST1_OK|ST1_WARN|STQ_TERM; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + break; + } + uptr->POS ++; + sim_activate(uptr, 500); + break; + case 1: + sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit); + r = sim_tape_sprecr(uptr, &reclen); + /* We don't set EOF on BSR */ + if (r == MTSE_TMK || r == MTSE_BOT) { + uptr->POS++; + sim_activate(uptr, 50); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%d \n", reclen); + sim_activate(uptr, 10 + (10 * reclen)); + } + break; + case 2: + uptr->STATUS = ST1_OK|STQ_TERM; + uptr->CMD = 0; + mt_busy = 0; + chan_set_done(dev); + } + break; + + case MT_REW: + if (uptr->POS == 0) { + uptr->POS ++; + sim_activate(uptr, 30000); + mt_busy = 0; + } else { + sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d\n", unit); + r = sim_tape_rewind(uptr); + uptr->CMD = 0; + uptr->STATUS = ST1_OK|STQ_TERM; + chan_set_done(dev); + } + break; + + } + return SCPE_OK; +} + + +/* Reset */ + +t_stat mt_reset (DEVICE *dptr) +{ + UNIT *uptr = dptr->units; + int unit; + + for (unit = 0; unit < dptr->numunits; unit++, uptr++) { + uptr->CMD = 0; + uptr->STATUS = 0; + if ((uptr->flags & UNIT_ATT) != 0) + uptr->STATUS = ST1_OK; + mt_busy = 0; + } + chan_clr_done(GET_UADDR(dptr->flags)); + return SCPE_OK; +} + +/* Boot from given device */ +t_stat +mt_boot(int32 unit_num, DEVICE * dptr) +{ + UNIT *uptr = &dptr->units[unit_num]; + int chan = GET_UADDR(dptr->flags); + + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; /* attached? */ + + M[64 + chan] = 0; + M[256 + 4 * chan] = B2; + M[257 + 4 * chan] = 020; + loading = 1; + mt_busy = 1; + CLR_BUF(uptr); + uptr->CMD = MT_BUSY|MT_BOOT; + uptr->STATUS = ST1_OK|STQ_ACCP; + sim_activate (uptr, 100); + return SCPE_OK; +} + +t_stat +mt_attach(UNIT * uptr, CONST char *file) +{ + t_stat r; + DEVICE *dptr = &mt_dev; + int unit = (uptr - dptr->units); + + if ((r = sim_tape_attach_ex(uptr, file, 0, 0)) != SCPE_OK) + return r; + uptr->STATUS = ST1_OK; + return SCPE_OK; +} + +t_stat +mt_detach(UNIT * uptr) +{ + uptr->STATUS = 0; + return sim_tape_detach(uptr); +} + + +t_stat mt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cmt) +{ +fprintf (st, "The Paper Tape Reader can be set to one of twp modes: 7P, or 7B.\n\n"); +fprintf (st, " mode \n"); +fprintf (st, " 7P Process even parity input tapes. \n"); +fprintf (st, " 7B Ignore parity of input data.\n"); +fprintf (st, "The default mode is 7B.\n"); +return SCPE_OK; +} + +CONST char *mt_description (DEVICE *dptr) +{ + return "MT"; + +} +#endif diff --git a/ICL1900/icl1900_mta.c b/ICL1900/icl1900_mta.c index b898812..341df23 100644 --- a/ICL1900/icl1900_mta.c +++ b/ICL1900/icl1900_mta.c @@ -1,691 +1,698 @@ -/* icl1900_mta.c: ICL1900 1974 mag tape drive simulator. - - Copyright (c) 2018, Richard Cornwell - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Richard Cornwell shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Richard Cornwell - - Magnetic tapes are represented as a series of variable records - of the form: - - 32b byte count - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b byte count - - If the byte count is odd, the record is padded with an extra byte - of junk. File marks are represented by a byte count of 0. - -*/ - -#include "icl1900_defs.h" -#include "sim_tape.h" - -#if (NUM_DEVS_MTA > 0) -#define BUFFSIZE (64 * 1024) -#define MTUF_9TR (1 << MTUF_V_UF) -#define UNIT_MTA UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | MTUF_9TR -#define DEV_BUF_NUM(x) (((x) & 07) << DEV_V_UF) -#define GET_DEV_BUF(x) (((x) >> DEV_V_UF) & 07) - -#define CMD u3 /* Command */ -#define STATUS u4 -#define ADDR u5 /* Transfer address read from M[64+n] */ -#define POS u6 /* Position within buffer */ - - -/* Command is packed follows: - * - * Lower 3 bits is command. - * Next bit is binary/BCD. - * Next bit is disconnect flag. - * Top 16 bits are count. - */ - -#define MT_CMD 007 -#define BCD 010 -#define DISC 020 - -#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF) -#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF - -#define MT_READ 0 -#define MT_WRITE 1 -#define MT_REV_READ 2 -#define MT_WRITEERG 3 -#define MT_SKIPF 4 -#define MT_WTM 5 -#define MT_SKIPB 6 -#define MT_REW 7 - -#define MT_TRCNT M15 -#define MT_STOP B3 -#define MT_START B4 -#define MT_BCD B5 - -/* Error status word */ -#define TERMINATE 000000001 /* Transfer complete */ -#define OPAT 000000002 /* Operator attention */ -#define PARITY 000000004 /* Parity error */ -#define HESFAIL 000000010 /* Failed to transfer word in time */ -#define ACCEPT 000000020 /* Ready for command */ -#define BUSY 000000040 /* Device busy */ -#define CBUSY 000000100 /* Controller Busy */ -#define WPROT 000001000 /* Write protect */ -#define BOT 000002000 /* Beginning of Tape */ -#define EOT 000004000 /* End of Tape. */ -#define OFFLINE 000040000 /* Device offline */ -#define LONGBLK 000100000 /* Long block */ -#define FILLWRD 000200000 /* Block short filled with stop */ -#define MARK 000400000 /* Tape mark sensed */ -#define DENS 014000000 -#define CHAR 060000000 /* Count of character read */ - -int mta_busy; /* Indicates that controller is talking to a drive */ -uint8 mta_buffer[BUFFSIZE]; -void mta_nsi_cmd (int dev, uint32 cmd); -void mta_nsi_status (int dev, uint32 *resp); -t_stat mta_svc (UNIT *uptr); -t_stat mta_reset (DEVICE *dptr); -t_stat mta_boot (int32 unit_num, DEVICE * dptr); -t_stat mta_attach(UNIT *, CONST char *); -t_stat mta_detach(UNIT *); -t_stat mta_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); -CONST char *mta_description (DEVICE *dptr); - -DIB mta_dib = { WORD_DEV|BLK_DEV, NULL, &mta_nsi_cmd, &mta_nsi_status }; - - -MTAB mta_mod[] = { - {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL}, - {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL}, - {MTUF_9TR, 0, "7 track", "7T", NULL}, - {MTUF_9TR, MTUF_9TR, "9 track", "9T", NULL}, - {MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL}, - {MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", - &set_chan, &get_chan, NULL, "Device Number"}, - {0} -}; - -UNIT mta_unit[] = { - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 0 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 1 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 2 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 3 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 4 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 5 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 6 */ - {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 7 */ -}; - -DEVICE mta_dev = { - "MTA", mta_unit, NULL, mta_mod, - NUM_DEVS_MTA, 8, 22, 1, 8, 22, - NULL, NULL, &mta_reset, &mta_boot, &mta_attach, &mta_detach, - &mta_dib, DEV_DISABLE | DEV_DEBUG | UNIT_ADDR(030), 0, dev_debug, - NULL, NULL, &mta_help, NULL, NULL, &mta_description - }; - -void mta_nsi_cmd(int dev, uint32 cmd) { - int d; - UNIT *uptr; - - d = dev - GET_UADDR(mta_dev.flags); - sim_debug(DEBUG_CMD, &mta_dev, "CMD: %d: %d c=%08o\n", dev, d, cmd); - if (d < 0 || d > mta_dev.numunits) - return; - uptr = &mta_dev.units[d]; - - if (cmd & MT_STOP) { - uptr->CMD |= DISC; - return; - } - - if (cmd & MT_START) { - if (mta_busy) - return; - if ((uptr->STATUS & BUSY) || (uptr->flags & UNIT_ATT) == 0) { - uptr->STATUS |= OPAT; - chan_set_done(GET_UADDR(uptr->flags)); - return; - } - uptr->CMD = (cmd & MT_TRCNT) << 16; - uptr->CMD |= (cmd >> 15) & 07; - if (cmd & MT_BCD) - uptr->CMD |= BCD; - uptr->STATUS = BUSY; - uptr->ADDR = M[64 + dev] & M15; /* Get transfer address */ - uptr->POS = 0; - CLR_BUF(uptr); - mta_busy = 1; - sim_activate(uptr, 100); - chan_clr_done(GET_UADDR(uptr->flags)); - } -} - -void mta_nsi_status(int dev, uint32 *resp) { - int d; - UNIT *uptr; - - *resp = 0; - d = dev - GET_UADDR(mta_dev.flags); - if (d < 0 || d > mta_dev.numunits) - return; - uptr = &mta_dev.units[d]; - - *resp = uptr->STATUS; - if (mta_busy) - *resp |= CBUSY; - /* Set hard status bits. */ - if ((uptr->flags & UNIT_ATT) == 0) - *resp |= OFFLINE; - if (sim_tape_wrp(uptr)) - *resp |= WPROT; - if (sim_tape_bot(uptr)) - *resp |= BOT; - if (sim_tape_eot(uptr)) - *resp |= EOT; - sim_debug(DEBUG_CMD, &mta_dev, "STAT: %d: %d c=%08o\n", dev, d, *resp); - chan_clr_done(dev); -} - -t_stat mta_svc (UNIT *uptr) -{ - DEVICE *dptr = &mta_dev; - int unit = (uptr - dptr->units); - int dev = unit + GET_UADDR(dptr->flags); - t_mtrlnt reclen; - t_stat r; - uint8 ch; - uint32 word; - int i; - int stop; - uint8 mode; - - /* Handle a disconnect request */ - if (uptr->CMD & DISC) { - uptr->STATUS &= ~BUSY; - mta_busy = 0; - chan_set_done(dev); - return SCPE_OK; - } - /* If not busy, false schedule, just exit */ - if ((uptr->STATUS & BUSY) == 0) - return SCPE_OK; - - switch (uptr->CMD & MT_CMD) { - case MT_READ: - /* If empty buffer, fill */ - if (BUF_EMPTY(uptr)) { - sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d ", unit); - if ((r = sim_tape_rdrecf(uptr, &mta_buffer[0], &reclen, - BUFFSIZE)) != MTSE_OK) { - sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r); - if (r == MTSE_TMK) - uptr->STATUS |= MARK; - else if (r == MTSE_WRP) - uptr->STATUS |= WPROT; - else if (r == MTSE_EOM) - uptr->STATUS |= EOT; - else if (r == MTSE_UNATT) - uptr->STATUS |= OFFLINE|OPAT; - else - uptr->STATUS |= OPAT; - uptr->STATUS |= TERMINATE; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - chan_set_done(dev); - return SCPE_OK; - } - uptr->hwmark = reclen; - sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); - } - stop = 0; - if (uptr->flags & MTUF_9TR) { - /* Grab three chars off buffer */ - word = 0; - uptr->STATUS &= ~CMASK; - for(i = 16; i >= 0; i-=8) { - if (uptr->POS >= uptr->hwmark) { - /* Add in fill characters */ - stop = 1; - if (i == 8) { - uptr->STATUS += B2|B1; - word |= 074; - } else if (i == 16) { - uptr->STATUS += B1; - word |= 07474; - } - break; - } - word |= (uint32)mta_buffer[uptr->POS++] << i; - } - uptr->STATUS |= BM1; - } else { - /* Grab four chars and check parity */ - word = 0; - mode = (uptr->CMD & BCD) ? 0 : 0100; - uptr->STATUS &= ~CMASK; - for(i = 18; i >= 0; i-=6) { - if (stop || uptr->POS >= uptr->hwmark) { - stop = 1; - ch = 074; - } else { - ch = mta_buffer[uptr->POS++]; - if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { - sim_debug(DEBUG_DETAIL, dptr, "Parity error unit=%d %d %03o\n", - unit, uptr->POS-1, ch); - uptr->STATUS |= PARITY; - break; - } - uptr->STATUS += B1; - } - word |= (ch & 077) << i; - } - } - sim_debug(DEBUG_DATA, dptr, "unit=%d %08o read %08o\n", unit, uptr->ADDR, word); - if (stop || (uptr->STATUS & (CMASK|BM1)) != 0) { - M[uptr->ADDR++] = word; - uptr->ADDR &= M15; - uptr->CMD -= 1 << 16; - if (stop || (uptr->CMD & (M15 << 16)) == 0 || uptr->POS >= uptr->hwmark) { - /* Done with transfer */ - sim_debug(DEBUG_DETAIL, dptr, "unit=%d %08o left %08o\n", unit, uptr->ADDR, - uptr->CMD >> 16); - if ((uptr->CMD & (M15 << 16)) == 0 && uptr->POS < uptr->hwmark) - uptr->STATUS |= LONGBLK; - if ((uptr->CMD & BCD) != 0 && (uptr->CMD & (M15 << 16)) != 0 - && uptr->POS >= uptr->hwmark) { - uptr->STATUS |= FILLWRD; - M[uptr->ADDR++] = 074747474; - uptr->ADDR &= M15; - } - uptr->STATUS |= TERMINATE; - uptr->STATUS &= ~BUSY; - M[64 + dev] = uptr->ADDR; /* Get transfer address */ - mta_busy = 0; - uptr->STATUS &= FMASK; - chan_set_done(dev); - return SCPE_OK; - } - uptr->STATUS &= FMASK; - } - sim_activate(uptr, 100); - break; - - case MT_WRITEERG: /* Write and Erase */ - case MT_WRITE: - /* Check if write protected */ - if (sim_tape_wrp(uptr)) { - uptr->STATUS |= WPROT; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - uptr->STATUS &= FMASK; - chan_set_done(dev); - return SCPE_OK; - } - - word = M[uptr->ADDR++]; - uptr->ADDR &= M15; - uptr->CMD -= 1 << 16; - sim_debug(DEBUG_DATA, dptr, "unit=%d %08o write %08o\n", unit, uptr->ADDR, word); - - stop = 0; - if (uptr->flags & MTUF_9TR) { - /* Put three chars in buffer */ - word = 0; - uptr->STATUS &= ~CMASK; - for(i = 16; i >= 0; i-=8) { - mta_buffer[uptr->POS++] = (uint8)((word >> i) & 0xff); - uptr->STATUS += B1; - } - /* Check if end character detected */ - if ((uptr->CMD & BCD) != 0) { - for (i = 0; i <= 18; i+= 6) { - if (((word >> i) & 077) == 074) { - uptr->POS--; - uptr->STATUS -= B1; - stop = 1; - } - } - } - } else { - /* Put four chars and generate parity */ - word = 0; - mode = (uptr->CMD & BCD) ? 0 : 0100; - uptr->STATUS &= ~CMASK; - for(i = 18; i >= 0; i-=6) { - ch = (uint8)((word >> i) & 077); - if ((uptr->CMD & BCD) != 0 && ch == 074) { - stop = 1; - break; - } - ch |= parity_table[ch] ^ mode; - mta_buffer[uptr->POS++] = ch; - uptr->STATUS += B1; - } - } - uptr->STATUS &= FMASK; - uptr->hwmark = uptr->POS; - if (stop || (uptr->CMD & (M15 << 16)) == 0) { - /* Done with transfer */ - reclen = uptr->hwmark; - sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d chars\n", - unit, reclen); - r = sim_tape_wrrecf(uptr, &mta_buffer[0], reclen); - if (r != MTSE_OK) - uptr->STATUS |= OPAT; - uptr->STATUS |= TERMINATE; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - uptr->STATUS &= FMASK; - M[64 + dev] = uptr->ADDR; /* Set transfer address */ - chan_set_done(dev); - return SCPE_OK; - } - sim_activate(uptr, 100); - break; - - case MT_REV_READ: - /* If empty buffer, fill */ - if (BUF_EMPTY(uptr)) { - if (sim_tape_bot(uptr)) { - uptr->STATUS |= OPAT|TERMINATE; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - chan_set_done(dev); - return SCPE_OK; - } - sim_debug(DEBUG_DETAIL, dptr, "Read rev unit=%d ", unit); - if ((r = sim_tape_rdrecr(uptr, &mta_buffer[0], &reclen, - BUFFSIZE)) != MTSE_OK) { - sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r); - if (r == MTSE_TMK) - uptr->STATUS |= MARK; - else if (r == MTSE_WRP) - uptr->STATUS |= WPROT; - else if (r == MTSE_EOM) - uptr->STATUS |= EOT; - else if (r == MTSE_UNATT) - uptr->STATUS |= OFFLINE|OPAT; - else - uptr->STATUS |= OPAT; - uptr->STATUS |= TERMINATE; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - chan_set_done(dev); - return SCPE_OK; - } - uptr->POS = reclen; - uptr->ADDR += (uptr->CMD >> 16) + 1; - uptr->hwmark = reclen; - sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); - } - if (uptr->flags & MTUF_9TR) { - /* Grab three chars off buffer */ - word = 0; - uptr->STATUS &= ~CMASK; - for(i = 0; i <= 16; i+=8) { - word |= (uint32)mta_buffer[--uptr->POS] << i; - if (uptr->POS == 0) { - stop = 1; - break; - } - } - uptr->STATUS |= BM1; - } else { - /* Grab four chars and check parity */ - word = 0; - mode = (uptr->CMD & BCD) ? 0 : 0100; - uptr->STATUS &= ~CMASK; - for(i = 0; i <= 16; i+=6) { - if (uptr->POS == 0) { - ch = 074; - stop = 1; - } else { - ch = mta_buffer[--uptr->POS]; - if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { - sim_debug(DEBUG_DETAIL, dptr, "Parity error unit=%d %d %03o\n", - unit, uptr->POS, ch); - uptr->STATUS |= PARITY; - break; - } - uptr->STATUS += B1; - } - word |= (ch & 077) << i; - } - } - sim_debug(DEBUG_DATA, dptr, "unit=%d %08o read %08o\n", unit, uptr->ADDR, word); - if (stop || (uptr->STATUS & (CMASK|BM1)) != 0) { - uptr->ADDR = (uptr->ADDR - 1) & M15; - M[uptr->ADDR] = word; - uptr->CMD -= 1 << 16; - if (stop || (uptr->CMD & (M15 << 16)) == 0 || uptr->POS == 0) { - sim_debug(DEBUG_DETAIL, dptr, "unit=%d %08o left %08o\n", unit, uptr->ADDR, - uptr->CMD >> 16); - /* Done with transfer */ - if ((uptr->CMD & (M15 << 16)) == 0 && uptr->POS != 0) - uptr->STATUS |= LONGBLK; - if ((uptr->CMD & BCD) != 0 && (uptr->CMD & (M15 << 16)) != 0 - && uptr->POS != 0) { - uptr->STATUS |= FILLWRD; - uptr->ADDR = (uptr->ADDR - 1) & M15; - M[uptr->ADDR] = 074747474; - uptr->ADDR &= M15; - } - uptr->STATUS |= TERMINATE; - uptr->STATUS &= ~BUSY; - M[64 + dev] = uptr->ADDR; /* Set transfer address */ - mta_busy = 0; - uptr->STATUS &= FMASK; - chan_set_done(dev); - return SCPE_OK; - } - uptr->STATUS &= FMASK; - } - sim_activate(uptr, 100); - break; - - case MT_SKIPF: - switch(uptr->POS) { - case 0: - uptr->POS ++; - sim_activate(uptr, 500); - break; - case 1: - sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit); - r = sim_tape_sprecf(uptr, &reclen); - if (r == MTSE_TMK) { - uptr->POS++; - sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); - sim_activate(uptr, 50); - } else if (r == MTSE_EOM) { - uptr->POS++; - uptr->STATUS |= EOT; - sim_activate(uptr, 50); - } else { - sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen); - sim_activate(uptr, 10 + (10 * reclen)); - } - break; - case 2: - uptr->STATUS &= ~BUSY; - uptr->STATUS |= TERMINATE; -// uptr->STATUS |= TERMINATE|MARK; - mta_busy = 0; - chan_set_done(dev); - } - break; - - case MT_WTM: - if (uptr->POS == 0) { - if (sim_tape_wrp(uptr)) { - uptr->STATUS |= WPROT|OPAT|TERMINATE; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - uptr->STATUS &= FMASK; - chan_set_done(dev); - break; - } - uptr->POS ++; - sim_activate(uptr, 500); - } else { - sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit); - r = sim_tape_wrtmk(uptr); - if (r != MTSE_OK) - uptr->STATUS |= OPAT; - uptr->STATUS &= ~BUSY; - uptr->STATUS |= TERMINATE; - mta_busy = 0; - chan_set_done(dev); - } - break; - - case MT_SKIPB: - switch (uptr->POS ) { - case 0: - if (sim_tape_bot(uptr)) { - uptr->STATUS |= OPAT|TERMINATE; - uptr->STATUS &= ~BUSY; - mta_busy = 0; - chan_set_done(dev); - break; - } - uptr->POS ++; - sim_activate(uptr, 500); - break; - case 1: - sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit); - r = sim_tape_sprecr(uptr, &reclen); - /* We don't set EOF on BSR */ - if (r == MTSE_TMK || r == MTSE_BOT) { - uptr->POS++; - sim_activate(uptr, 50); - } else { - sim_debug(DEBUG_DETAIL, dptr, "%d \n", reclen); - sim_activate(uptr, 10 + (10 * reclen)); - } - break; - case 2: - uptr->STATUS &= ~BUSY; - uptr->STATUS |= TERMINATE|MARK; - mta_busy = 0; - chan_set_done(dev); - } - break; - - case MT_REW: - if (uptr->POS == 0) { - uptr->POS ++; - sim_activate(uptr, 30000); - mta_busy = 0; - } else { - sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d\n", unit); - r = sim_tape_rewind(uptr); - uptr->STATUS &= ~BUSY; - uptr->STATUS |= TERMINATE; - chan_set_done(dev); - } - break; - - } - return SCPE_OK; -} - - -/* Reset */ - -t_stat mta_reset (DEVICE *dptr) -{ - UNIT *uptr = dptr->units; - int unit; - - for (unit = 0; unit < dptr->numunits; unit++, uptr++) { - uptr->CMD = 0; - uptr->STATUS = 0; - if ((uptr->flags & UNIT_ATT) == 0) - uptr->STATUS |= OFFLINE; - mta_busy = 0; - chan_clr_done(GET_UADDR(dptr->flags)+unit); - } - return SCPE_OK; -} - -/* Boot from given device */ -t_stat -mta_boot(int32 unit_num, DEVICE * dptr) -{ - UNIT *uptr = &dptr->units[unit_num]; - - if ((uptr->flags & UNIT_ATT) == 0) - return SCPE_UNATT; /* attached? */ - - uptr->ADDR = 0; - uptr->CMD = MT_READ; - uptr->STATUS = BUSY; - loading = 1; - sim_activate (uptr, uptr->wait); - return SCPE_OK; -} - -t_stat -mta_attach(UNIT * uptr, CONST char *file) -{ - t_stat r; - DEVICE *dptr = &mta_dev; - int unit = (uptr - dptr->units); - - if ((r = sim_tape_attach_ex(uptr, file, 0, 0)) != SCPE_OK) - return r; - uptr->STATUS &= ~OFFLINE; - uptr->STATUS = ACCEPT; -// chan_set_done(unit + GET_UADDR(dptr->flags)); - return SCPE_OK; -} - -t_stat -mta_detach(UNIT * uptr) -{ - uptr->STATUS |= OFFLINE; - return sim_tape_detach(uptr); -} - - -t_stat mta_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cmta) -{ -fprintf (st, "The Paper Tape Reader can be set to one of twp modes: 7P, or 7B.\n\n"); -fprintf (st, " mode \n"); -fprintf (st, " 7P Process even parity input tapes. \n"); -fprintf (st, " 7B Ignore parity of input data.\n"); -fprintf (st, "The default mode is 7B.\n"); -return SCPE_OK; -} - -CONST char *mta_description (DEVICE *dptr) -{ - return "PTR"; - -} -#endif +/* icl1900_mta.c: ICL1900 1974 mag tape drive simulator. + + Copyright (c) 2018, Richard Cornwell + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Richard Cornwell shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Richard Cornwell + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32b byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. + +*/ + +#include "icl1900_defs.h" +#include "sim_tape.h" + +#if (NUM_DEVS_MTA > 0) +#define BUFFSIZE (64 * 1024) +#define MTUF_9TR (1 << MTUF_V_UF) +#define UNIT_MTA UNIT_ATTABLE | UNIT_DISABLE | UNIT_ROABLE | MTUF_9TR +#define DEV_BUF_NUM(x) (((x) & 07) << DEV_V_UF) +#define GET_DEV_BUF(x) (((x) >> DEV_V_UF) & 07) + +#define CMD u3 /* Command */ +#define STATUS u4 +#define ADDR u5 /* Transfer address read from M[64+n] */ +#define POS u6 /* Position within buffer */ + + +/* Command is packed follows: + * + * Lower 3 bits is command. + * Next bit is binary/BCD. + * Next bit is disconnect flag. + * Top 16 bits are count. + */ + +#define MT_CMD 007 +#define BCD 010 +#define DISC 020 + +#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF) +#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF + +#define MT_READ 0 +#define MT_WRITE 1 +#define MT_REV_READ 2 +#define MT_WRITEERG 3 +#define MT_SKIPF 4 +#define MT_WTM 5 +#define MT_SKIPB 6 +#define MT_REW 7 + +#define MT_TRCNT M15 +#define MT_STOP B3 +#define MT_START B4 +#define MT_BCD B5 + +/* Error status word */ +#define TERMINATE 000000001 /* Transfer complete */ +#define OPAT 000000002 /* Operator attention */ +#define PARITY 000000004 /* Parity error */ +#define HESFAIL 000000010 /* Failed to transfer word in time */ +#define ACCEPT 000000020 /* Ready for command */ +#define BUSY 000000040 /* Device busy */ +#define CBUSY 000000100 /* Controller Busy */ +#define WPROT 000001000 /* Write protect */ +#define BOT 000002000 /* Beginning of Tape */ +#define EOT 000004000 /* End of Tape. */ +#define OFFLINE 000040000 /* Device offline */ +#define LONGBLK 000100000 /* Long block */ +#define FILLWRD 000200000 /* Block short filled with stop */ +#define MARK 000400000 /* Tape mark sensed */ +#define DENS 014000000 +#define CHAR 060000000 /* Count of character read */ + +int mta_busy; /* Indicates that controller is talking to a drive */ +uint8 mta_buffer[BUFFSIZE]; +void mta_nsi_cmd (int dev, uint32 cmd); +void mta_nsi_status (int dev, uint32 *resp); +t_stat mta_svc (UNIT *uptr); +t_stat mta_reset (DEVICE *dptr); +t_stat mta_boot (int32 unit_num, DEVICE * dptr); +t_stat mta_attach(UNIT *, CONST char *); +t_stat mta_detach(UNIT *); +t_stat mta_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +CONST char *mta_description (DEVICE *dptr); + +DIB mta_dib = { WORD_DEV|BLK_DEV, NULL, &mta_nsi_cmd, &mta_nsi_status }; + + +MTAB mta_mod[] = { + {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL}, + {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL}, + {MTUF_9TR, 0, "7 track", "7T", NULL}, + {MTUF_9TR, MTUF_9TR, "9 track", "9T", NULL}, + {MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL}, + {MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", + &set_chan, &get_chan, NULL, "Device Number"}, + {0} +}; + +UNIT mta_unit[] = { + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 0 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 1 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 2 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 3 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 4 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 5 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 6 */ + {UDATA(&mta_svc, UNIT_MTA, 0) }, /* 7 */ +}; + +DEVICE mta_dev = { + "MTA", mta_unit, NULL, mta_mod, + NUM_DEVS_MTA, 8, 22, 1, 8, 22, + NULL, NULL, &mta_reset, &mta_boot, &mta_attach, &mta_detach, + &mta_dib, DEV_DISABLE | DEV_DEBUG | UNIT_ADDR(030), 0, dev_debug, + NULL, NULL, &mta_help, NULL, NULL, &mta_description + }; + +void mta_nsi_cmd(int dev, uint32 cmd) { + int d; + UNIT *uptr; + + d = dev - GET_UADDR(mta_dev.flags); + sim_debug(DEBUG_CMD, &mta_dev, "CMD: %d: %d c=%08o\n", dev, d, cmd); + if (d < 0 || d > mta_dev.numunits) + return; + uptr = &mta_dev.units[d]; + + if (cmd & MT_STOP) { + uptr->CMD |= DISC; + return; + } + + if (cmd & MT_START) { + if (mta_busy) + return; + if ((uptr->STATUS & BUSY) || (uptr->flags & UNIT_ATT) == 0) { + uptr->STATUS |= OPAT; + chan_set_done(GET_UADDR(uptr->flags)); + return; + } + uptr->CMD = (cmd & MT_TRCNT) << 16; + uptr->CMD |= (cmd >> 15) & 07; + if (cmd & MT_BCD) + uptr->CMD |= BCD; + uptr->STATUS = BUSY; + uptr->ADDR = M[64 + dev] & M15; /* Get transfer address */ + uptr->POS = 0; + CLR_BUF(uptr); + mta_busy = 1; + sim_activate(uptr, 100); + chan_clr_done(GET_UADDR(uptr->flags)); + } +} + +void mta_nsi_status(int dev, uint32 *resp) { + int d; + UNIT *uptr; + + *resp = 0; + d = dev - GET_UADDR(mta_dev.flags); + if (d < 0 || d > mta_dev.numunits) + return; + uptr = &mta_dev.units[d]; + + *resp = uptr->STATUS; + if (mta_busy) + *resp |= CBUSY; + /* Set hard status bits. */ + if ((uptr->flags & UNIT_ATT) == 0) + *resp |= OFFLINE; + if (sim_tape_wrp(uptr)) + *resp |= WPROT; + if (sim_tape_bot(uptr)) + *resp |= BOT; + if (sim_tape_eot(uptr)) + *resp |= EOT; + sim_debug(DEBUG_CMD, &mta_dev, "STAT: %d: %d c=%08o\n", dev, d, *resp); + chan_clr_done(dev); +} + +t_stat mta_svc (UNIT *uptr) +{ + DEVICE *dptr = &mta_dev; + int unit = (uptr - dptr->units); + int dev = unit + GET_UADDR(dptr->flags); + t_mtrlnt reclen; + t_stat r; + uint8 ch; + uint32 word; + int i; + int stop; + uint8 mode; + + /* Handle a disconnect request */ + if (uptr->CMD & DISC) { + uptr->STATUS &= ~BUSY; + mta_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + /* If not busy, false schedule, just exit */ + if ((uptr->STATUS & BUSY) == 0) + return SCPE_OK; + + switch (uptr->CMD & MT_CMD) { + case MT_READ: + /* If empty buffer, fill */ + if (BUF_EMPTY(uptr)) { + sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d ", unit); + if ((r = sim_tape_rdrecf(uptr, &mta_buffer[0], &reclen, + BUFFSIZE)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r); + if (r == MTSE_TMK) + uptr->STATUS |= MARK; + else if (r == MTSE_WRP) + uptr->STATUS |= WPROT; + else if (r == MTSE_EOM) + uptr->STATUS |= EOT; + else if (r == MTSE_UNATT) + uptr->STATUS |= OFFLINE|OPAT; + else + uptr->STATUS |= OPAT; + uptr->STATUS |= TERMINATE; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + uptr->hwmark = reclen; + sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); + } + stop = 0; + if (uptr->flags & MTUF_9TR) { + /* Grab three chars off buffer */ + word = 0; + uptr->STATUS &= ~CMASK; + for(i = 16; i >= 0; i-=8) { + if (uptr->POS >= uptr->hwmark) { + /* Add in fill characters */ + stop = 1; + if (i == 8) { + uptr->STATUS += B2|B1; + word |= 074; + } else if (i == 16) { + uptr->STATUS += B1; + word |= 07474; + } + break; + } + word |= (uint32)mta_buffer[uptr->POS++] << i; + } + uptr->STATUS |= BM1; + } else { + /* Grab four chars and check parity */ + word = 0; + mode = (uptr->CMD & BCD) ? 0 : 0100; + uptr->STATUS &= ~CMASK; + for(i = 18; i >= 0; i-=6) { + if (stop || uptr->POS >= uptr->hwmark) { + stop = 1; + ch = 074; + } else { + ch = mta_buffer[uptr->POS++]; + if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { + sim_debug(DEBUG_DETAIL, dptr, "Parity error unit=%d %d %03o\n", + unit, uptr->POS-1, ch); + uptr->STATUS |= PARITY; + break; + } + uptr->STATUS += B1; + } + word |= (ch & 077) << i; + } + } + sim_debug(DEBUG_DATA, dptr, "unit=%d %08o read %08o\n", unit, uptr->ADDR, word); + if (stop || (uptr->STATUS & (CMASK|BM1)) != 0) { + if (uptr->ADDR < 8) + XR[uptr->ADDR] = word; + M[uptr->ADDR++] = word; + uptr->ADDR &= M15; + uptr->CMD -= 1 << 16; + if (stop || (uptr->CMD & (M15 << 16)) == 0 || uptr->POS >= uptr->hwmark) { + /* Done with transfer */ + sim_debug(DEBUG_DETAIL, dptr, "unit=%d %08o left %08o\n", unit, uptr->ADDR, + uptr->CMD >> 16); + if ((uptr->CMD & (M15 << 16)) == 0 && uptr->POS < uptr->hwmark) + uptr->STATUS |= LONGBLK; + if ((uptr->CMD & BCD) != 0 && (uptr->CMD & (M15 << 16)) != 0 + && uptr->POS >= uptr->hwmark) { + uptr->STATUS |= FILLWRD; + M[uptr->ADDR++] = 074747474; + uptr->ADDR &= M15; + } + uptr->STATUS |= TERMINATE; + uptr->STATUS &= ~BUSY; + M[64 + dev] = uptr->ADDR; /* Get transfer address */ + mta_busy = 0; + uptr->STATUS &= FMASK; + chan_set_done(dev); + return SCPE_OK; + } + uptr->STATUS &= FMASK; + } + sim_activate(uptr, 100); + break; + + case MT_WRITEERG: /* Write and Erase */ + case MT_WRITE: + /* Check if write protected */ + if (sim_tape_wrp(uptr)) { + uptr->STATUS |= WPROT; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + uptr->STATUS &= FMASK; + chan_set_done(dev); + return SCPE_OK; + } + + word = M[uptr->ADDR++]; + uptr->ADDR &= M15; + uptr->CMD -= 1 << 16; + sim_debug(DEBUG_DATA, dptr, "unit=%d %08o write %08o\n", unit, uptr->ADDR, word); + + stop = 0; + if (uptr->flags & MTUF_9TR) { + /* Put three chars in buffer */ + word = 0; + uptr->STATUS &= ~CMASK; + for(i = 16; i >= 0; i-=8) { + mta_buffer[uptr->POS++] = (uint8)((word >> i) & 0xff); + uptr->STATUS += B1; + } + /* Check if end character detected */ + if ((uptr->CMD & BCD) != 0) { + for (i = 0; i <= 18; i+= 6) { + if (((word >> i) & 077) == 074) { + uptr->POS--; + uptr->STATUS -= B1; + stop = 1; + } + } + } + } else { + /* Put four chars and generate parity */ + word = 0; + mode = (uptr->CMD & BCD) ? 0 : 0100; + uptr->STATUS &= ~CMASK; + for(i = 18; i >= 0; i-=6) { + ch = (uint8)((word >> i) & 077); + if ((uptr->CMD & BCD) != 0 && ch == 074) { + stop = 1; + break; + } + ch |= parity_table[ch] ^ mode; + mta_buffer[uptr->POS++] = ch; + uptr->STATUS += B1; + } + } + uptr->STATUS &= FMASK; + uptr->hwmark = uptr->POS; + if (stop || (uptr->CMD & (M15 << 16)) == 0) { + /* Done with transfer */ + reclen = uptr->hwmark; + sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d chars\n", + unit, reclen); + r = sim_tape_wrrecf(uptr, &mta_buffer[0], reclen); + if (r != MTSE_OK) + uptr->STATUS |= OPAT; + uptr->STATUS |= TERMINATE; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + uptr->STATUS &= FMASK; + M[64 + dev] = uptr->ADDR; /* Set transfer address */ + chan_set_done(dev); + return SCPE_OK; + } + sim_activate(uptr, 100); + break; + + case MT_REV_READ: + /* If empty buffer, fill */ + if (BUF_EMPTY(uptr)) { + if (sim_tape_bot(uptr)) { + uptr->STATUS |= OPAT|TERMINATE; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + sim_debug(DEBUG_DETAIL, dptr, "Read rev unit=%d ", unit); + if ((r = sim_tape_rdrecr(uptr, &mta_buffer[0], &reclen, + BUFFSIZE)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, " error %d\n", r); + if (r == MTSE_TMK) + uptr->STATUS |= MARK; + else if (r == MTSE_WRP) + uptr->STATUS |= WPROT; + else if (r == MTSE_EOM) + uptr->STATUS |= EOT; + else if (r == MTSE_UNATT) + uptr->STATUS |= OFFLINE|OPAT; + else + uptr->STATUS |= OPAT; + uptr->STATUS |= TERMINATE; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + chan_set_done(dev); + return SCPE_OK; + } + uptr->POS = reclen; + uptr->ADDR += (uptr->CMD >> 16) + 1; + uptr->hwmark = reclen; + sim_debug(DEBUG_DETAIL, dptr, "Block %d chars\n", reclen); + } + if (uptr->flags & MTUF_9TR) { + /* Grab three chars off buffer */ + word = 0; + uptr->STATUS &= ~CMASK; + for(i = 0; i <= 16; i+=8) { + word |= (uint32)mta_buffer[--uptr->POS] << i; + if (uptr->POS == 0) { + stop = 1; + break; + } + } + uptr->STATUS |= BM1; + } else { + /* Grab four chars and check parity */ + word = 0; + mode = (uptr->CMD & BCD) ? 0 : 0100; + uptr->STATUS &= ~CMASK; + for(i = 0; i <= 16; i+=6) { + if (uptr->POS == 0) { + ch = 074; + stop = 1; + } else { + ch = mta_buffer[--uptr->POS]; + if ((parity_table[ch & 077] ^ (ch & 0100) ^ mode) == 0) { + sim_debug(DEBUG_DETAIL, dptr, "Parity error unit=%d %d %03o\n", + unit, uptr->POS, ch); + uptr->STATUS |= PARITY; + break; + } + uptr->STATUS += B1; + } + word |= (ch & 077) << i; + } + } + sim_debug(DEBUG_DATA, dptr, "unit=%d %08o read %08o\n", unit, uptr->ADDR, word); + if (stop || (uptr->STATUS & (CMASK|BM1)) != 0) { + uptr->ADDR = (uptr->ADDR - 1) & M15; + if (uptr->ADDR < 8) + XR[uptr->ADDR] = word; + M[uptr->ADDR] = word; + uptr->CMD -= 1 << 16; + if (stop || (uptr->CMD & (M15 << 16)) == 0 || uptr->POS == 0) { + sim_debug(DEBUG_DETAIL, dptr, "unit=%d %08o left %08o\n", unit, uptr->ADDR, + uptr->CMD >> 16); + /* Done with transfer */ + if ((uptr->CMD & (M15 << 16)) == 0 && uptr->POS != 0) + uptr->STATUS |= LONGBLK; + if ((uptr->CMD & BCD) != 0 && (uptr->CMD & (M15 << 16)) != 0 + && uptr->POS != 0) { + uptr->STATUS |= FILLWRD; + uptr->ADDR = (uptr->ADDR - 1) & M15; + M[uptr->ADDR] = 074747474; + uptr->ADDR &= M15; + } + uptr->STATUS |= TERMINATE; + uptr->STATUS &= ~BUSY; + M[64 + dev] = uptr->ADDR; /* Set transfer address */ + mta_busy = 0; + uptr->STATUS &= FMASK; + chan_set_done(dev); + return SCPE_OK; + } + uptr->STATUS &= FMASK; + } + sim_activate(uptr, 100); + break; + + case MT_SKIPF: + switch(uptr->POS) { + case 0: + uptr->POS ++; + sim_activate(uptr, 500); + break; + case 1: + sim_debug(DEBUG_DETAIL, dptr, "Skip rec unit=%d ", unit); + r = sim_tape_sprecf(uptr, &reclen); + if (r == MTSE_TMK) { + uptr->POS++; + sim_debug(DEBUG_DETAIL, dptr, "MARK\n"); + sim_activate(uptr, 50); + } else if (r == MTSE_EOM) { + uptr->POS++; + uptr->STATUS |= EOT; + sim_activate(uptr, 50); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%d\n", reclen); + sim_activate(uptr, 10 + (10 * reclen)); + } + break; + case 2: + uptr->STATUS &= ~BUSY; + uptr->STATUS |= TERMINATE; +// uptr->STATUS |= TERMINATE|MARK; + mta_busy = 0; + chan_set_done(dev); + } + break; + + case MT_WTM: + if (uptr->POS == 0) { + if (sim_tape_wrp(uptr)) { + uptr->STATUS |= WPROT|OPAT|TERMINATE; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + uptr->STATUS &= FMASK; + chan_set_done(dev); + break; + } + uptr->POS ++; + sim_activate(uptr, 500); + } else { + sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit); + r = sim_tape_wrtmk(uptr); + if (r != MTSE_OK) + uptr->STATUS |= OPAT; + uptr->STATUS &= ~BUSY; + uptr->STATUS |= TERMINATE; + mta_busy = 0; + chan_set_done(dev); + } + break; + + case MT_SKIPB: + switch (uptr->POS ) { + case 0: + if (sim_tape_bot(uptr)) { + uptr->STATUS |= OPAT|TERMINATE; + uptr->STATUS &= ~BUSY; + mta_busy = 0; + chan_set_done(dev); + break; + } + uptr->POS ++; + sim_activate(uptr, 500); + break; + case 1: + sim_debug(DEBUG_DETAIL, dptr, "Backspace rec unit=%d ", unit); + r = sim_tape_sprecr(uptr, &reclen); + /* We don't set EOF on BSR */ + if (r == MTSE_TMK || r == MTSE_BOT) { + uptr->POS++; + sim_activate(uptr, 50); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%d \n", reclen); + sim_activate(uptr, 10 + (10 * reclen)); + } + break; + case 2: + uptr->STATUS &= ~BUSY; + uptr->STATUS |= TERMINATE|MARK; + mta_busy = 0; + chan_set_done(dev); + } + break; + + case MT_REW: + if (uptr->POS == 0) { + uptr->POS ++; + sim_activate(uptr, 30000); + mta_busy = 0; + } else { + sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d\n", unit); + r = sim_tape_rewind(uptr); + uptr->STATUS &= ~BUSY; + uptr->STATUS |= TERMINATE; + chan_set_done(dev); + } + break; + + } + return SCPE_OK; +} + + +/* Reset */ + +t_stat mta_reset (DEVICE *dptr) +{ + UNIT *uptr = dptr->units; + int unit; + + for (unit = 0; unit < dptr->numunits; unit++, uptr++) { + uptr->CMD = 0; + uptr->STATUS = 0; + if ((uptr->flags & UNIT_ATT) == 0) + uptr->STATUS |= OFFLINE; + mta_busy = 0; + chan_clr_done(GET_UADDR(dptr->flags)+unit); + } + return SCPE_OK; +} + +/* Boot from given device */ +t_stat +mta_boot(int32 unit_num, DEVICE * dptr) +{ + UNIT *uptr = &dptr->units[unit_num]; + + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; /* attached? */ + + uptr->ADDR = 0; + uptr->CMD = MT_READ; + uptr->STATUS = BUSY; + uptr->POS = 0; + CLR_BUF(uptr); + loading = 1; + mta_busy = 1; + sim_activate (uptr, uptr->wait); + return SCPE_OK; +} + +t_stat +mta_attach(UNIT * uptr, CONST char *file) +{ + t_stat r; + DEVICE *dptr = &mta_dev; + int unit = (uptr - dptr->units); + + if ((r = sim_tape_attach_ex(uptr, file, 0, 0)) != SCPE_OK) + return r; + uptr->STATUS &= ~OFFLINE; + uptr->STATUS = ACCEPT; +// chan_set_done(unit + GET_UADDR(dptr->flags)); + return SCPE_OK; +} + +t_stat +mta_detach(UNIT * uptr) +{ + uptr->STATUS |= OFFLINE; + return sim_tape_detach(uptr); +} + + +t_stat mta_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cmta) +{ +fprintf (st, "The Paper Tape Reader can be set to one of twp modes: 7P, or 7B.\n\n"); +fprintf (st, " mode \n"); +fprintf (st, " 7P Process even parity input tapes. \n"); +fprintf (st, " 7B Ignore parity of input data.\n"); +fprintf (st, "The default mode is 7B.\n"); +return SCPE_OK; +} + +CONST char *mta_description (DEVICE *dptr) +{ + return "PTR"; + +} +#endif diff --git a/ICL1900/icl1900_stdio.c b/ICL1900/icl1900_stdio.c index 950f289..345c5b2 100644 --- a/ICL1900/icl1900_stdio.c +++ b/ICL1900/icl1900_stdio.c @@ -50,7 +50,7 @@ chan_set_devs() devs[i] = NULL; /* Add in hidden channels */ - devs[22] = &nul_dib; + devs[22] = &nul_dib; devs[23] = &nul_dib; /* Scan all devices and assign to channel */ for(i = 0; sim_devices[i] != NULL; i++) { @@ -64,7 +64,7 @@ chan_set_devs() continue; if (dibp->type & BLK_DEV) { int f = 1; - + chan = GET_UADDR(sim_devices[i]->flags); /* Make sure it is in range */ if (chan < 2 || (chan + sim_devices[i]->numunits) > 36) @@ -76,13 +76,13 @@ chan_set_devs() fprintf(stderr, "Conflict between devices %d %s\n", chan+j, sim_devices[i]->name); f = 0; } - } + } if (f) { for (j = 0; j < sim_devices[i]->numunits; j++) { if (sim_devices[i]->units[j].flags & UNIT_DIS) continue; devs[chan+j] = dibp; - } + } } } else if (dibp->type & MULT_DEV) { chan = GET_UADDR(sim_devices[i]->flags); @@ -136,7 +136,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc) if (dptr == NULL) return SCPE_IERR; dibp = (DIB *) dptr->ctxt; - + if (dibp == NULL) return SCPE_IERR; new_chan = get_uint(cptr, 10, 37, &r); @@ -160,7 +160,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc) for (i = 0; i < dptr->numunits; i++) { if (dptr->units[i].flags & UNIT_DIS) continue; - if (devs[cur_chan+i] == dibp) + if (devs[cur_chan+i] == dibp) devs[cur_chan] = NULL; } } else if (dibp->type & MULT_DEV) { @@ -181,7 +181,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc) } return SCPE_OK; } - + if (dibp->type & BLK_DEV) { dptr->flags &= ~UNIT_M_ADDR; dptr->flags |= UNIT_ADDR(new_chan); @@ -210,7 +210,7 @@ set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc) /* Print the channel the device is on */ t_stat -get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc) +get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc) { DEVICE *dptr; DIB *dibp; @@ -236,7 +236,7 @@ get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc) return SCPE_OK; } -int +int get_ccw(int dev, uint32 *addr, uint8 type) { int cw_addr; uint32 cw0; /* Holding registers for current control word */ @@ -248,7 +248,7 @@ get_ccw(int dev, uint32 *addr, uint8 type) { cw1 = M[cw_addr+1]; *addr = cw1; if (cw0 & WORDCCW) { - if (cw0 & BACKWARD) + if (cw0 & BACKWARD) cw1 = ((cw1 + M22) & M22) | (cw1 & CMASK); else cw1 = ((cw1 + 1) & M22) | (cw1 & CMASK); @@ -274,7 +274,7 @@ get_ccw(int dev, uint32 *addr, uint8 type) { cw1 = M[cw_addr+3]; } else if ((cw0 & GATHER) != 0) { int a; - if ((cw0 & CWRECHARGE) != 0) + if ((cw0 & CWRECHARGE) != 0) M[cw_addr+3] = M[cw_addr+2]; a = M[cw_addr+3]; cw0 = M[a & M22]; @@ -328,7 +328,7 @@ chan_nsi_cmd(int dev, uint32 cmd) { if (dibp != NULL && dibp->nsi_cmd != NULL) { (dibp->nsi_cmd)(dev, cmd); - } + } } /* Talk to non-standard interface devices */ @@ -339,7 +339,7 @@ chan_nsi_status(int dev, uint32 *resp) { *resp = 0; if (dibp != NULL && dibp->nsi_cmd != NULL) { (dibp->nsi_status)(dev, resp); - } + } } @@ -351,7 +351,7 @@ chan_send_cmd(int dev, uint32 cmd, uint32 *resp) { *resp = 0; if (dibp != NULL && dibp->si_cmd != NULL) { (dibp->si_cmd)(dev, cmd, resp); - } + } } /* Transfer date between device and memory */ @@ -384,8 +384,7 @@ chan_input_char(int dev, uint8 *data, int eor) { mb |= ((uint32)(*data) & 077) << c; if (addr < 8) XR[addr] = mb; - else - M[addr] = mb; + M[addr] = mb; return r; } @@ -437,8 +436,7 @@ chan_input_word(int dev, uint32 *data, int eor) { addr &= M22; if (addr < 8) XR[addr] = *data; - else - M[addr] = *data; + M[addr] = *data; return r; } @@ -468,7 +466,7 @@ chan_output_word(int dev, uint32 *data, int eor) { void chan_set_done(int dev) { - if (dev < 22) + if (dev < 22) SR64 |= B2 >> dev; else SR65 |= B1 >> (dev - 23); @@ -476,7 +474,7 @@ chan_set_done(int dev) { void chan_clr_done(int dev) { - if (dev < 22) + if (dev < 22) SR64 &= ~(B2 >> dev); else SR65 &= ~(B1 >> (dev - 23)); diff --git a/ICL1900/icl1900_sys.c b/ICL1900/icl1900_sys.c index b300e01..fb44615 100755 --- a/ICL1900/icl1900_sys.c +++ b/ICL1900/icl1900_sys.c @@ -92,8 +92,8 @@ DEBTAB dev_debug[] = { }; -uint8 parity_table[64] = { - /* 0 1 2 3 4 5 6 7 */ +uint8 parity_table[64] = { + /* 0 1 2 3 4 5 6 7 */ 0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100, 0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000, @@ -105,7 +105,7 @@ uint8 parity_table[64] = { }; uint8 mem_to_ascii[64] = { - /* x0 x1 x2 x3 x4 x5 x6 x7 */ + /* x0 x1 x2 x3 x4 x5 x6 x7 */ '0', '1', '2', '3', '4', '5', '6', '7', /* 0x */ '8', '9', ':', ';', '<', '=', '>', '?', /* 1x */ ' ', '!', '"', '#', '\\', '%', '&', '\'', /* 2x */ @@ -174,19 +174,17 @@ sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag) if (buffer[j] == '\n') break; image[j] = ascii_to_mem[buffer[j]]; - if (image[j] < 0) { + if (image[j] < 0) { fprintf(stderr, "Char %c: %s", buffer[j], buffer); return SCPE_FMT; } } for (j = 0; j < 64; ) { data = 0; - for (k = 0; k < 4; k++) + for (k = 0; k < 4; k++) data = (data << 6) | image[j++]; - fprintf(stderr, "Addr: %06o %08o\n\r", addr, data); - if (addr < 8) - XR[addr++] = data; -else + if (addr < 8) + XR[addr++] = data; M[addr++] = data; } } @@ -199,7 +197,7 @@ else if (buffer[j] == '\n') break; image[j] = ascii_to_mem[buffer[j]]; - if (image[j] < 0) { + if (image[j] < 0) { fprintf(stderr, "Char %c: %s", buffer[j], buffer); return SCPE_FMT; } @@ -211,24 +209,24 @@ else switch(image[3]) { case 0: checksum = 0; - for (j = 0; j < 4; j++) + for (j = 0; j < 4; j++) checksum = (checksum << 6) | image[j]; addr = 0; - for (; j < 8; j++) + for (; j < 8; j++) addr = (addr << 6) | image[j]; checksum += addr; for (i = 3; i < image[1]; i++) { data = 0; - for (k = 0; k < 4; k++) + for (k = 0; k < 4; k++) data = (data << 6) | image[j++]; checksum += data; M[addr++] = data; } data = 0; - for (k = 0; k < 4; k++) + for (k = 0; k < 4; k++) data = (data << 6) | image[j++]; data = FMASK & (checksum + data); - if (data != 0) + if (data != 0) fprintf(stderr, "Check %08o %08o: %s", addr, data, buffer); break; case 1: @@ -237,24 +235,24 @@ else case 2: case 3: checksum = 0; - for (j = 0; j < 4; j++) + for (j = 0; j < 4; j++) checksum = (checksum << 6) | image[j]; addr = 0; - for (; j < 8; j++) + for (; j < 8; j++) addr = (addr << 6) | image[j]; checksum += addr; RC = addr; data = 0; for (i = 3; i < image[1]; i++) { data = 0; - for (k = 0; k < 4; k++) + for (k = 0; k < 4; k++) data = (data << 6) | image[j++]; checksum += data; } - for (k = 0; k < 4; k++) + for (k = 0; k < 4; k++) data = (data << 6) | image[j++]; data = FMASK & (checksum + data); - if (data != 0) + if (data != 0) fprintf(stderr, "Check %08o %08o: %s", addr, data, buffer); break; case 4: @@ -282,134 +280,134 @@ else /* Opcodes */ t_opcode ops[] = { - "LDX", TYPE_A, /* Load to X */ - "ADX", TYPE_A, /* Add to X */ - "NGX", TYPE_A, /* Negative to X */ - "SBX", TYPE_A, /* Subtract from X */ - "LDXC", TYPE_A, /* Load into X with carry */ - "ADXC", TYPE_A, /* Add to X with carry */ - "NGXC", TYPE_A, /* Negative to X with carry */ - "SBXC", TYPE_A, /* Subtract from X with carry */ - "STO", TYPE_A, /* Store contents of X */ - "ADS", TYPE_A, /* Add X to store */ - "NGS", TYPE_A, /* Negative into Store */ - "SBS", TYPE_A, /* Subtract from store */ - "STOC", TYPE_A, /* Store contents of X with carry */ - "ADSC", TYPE_A, /* Add X to store with carry */ - "NGSC", TYPE_A, /* Negative into Store with carry */ - "SBSC", TYPE_A, /* Subtract from store with carry */ - "ANDX", TYPE_A, /* Logical AND into X */ - "ORX", TYPE_A, /* Logical OR into X */ - "ERX", TYPE_A, /* Logical XOR into X */ - "OBEY", TYPE_A, /* Obey instruction at N */ - "LDCH", TYPE_A, /* Load Character to X */ - "LDEX", TYPE_A, /* Load Exponent */ - "TXU", TYPE_A, /* Test X unequal */ - "TXL", TYPE_A, /* Test X Less */ - "ANDS", TYPE_A, /* Logical AND into store */ - "ORS", TYPE_A, /* Logical OR into store */ - "ERS", TYPE_A, /* Logical XOR into store */ - "STOZ", TYPE_A, /* Store Zero */ - "DCH", TYPE_A, /* Deposit Character to X */ - "DEX", TYPE_A, /* Deposit Exponent */ - "DSA", TYPE_A, /* Deposit Short Address */ - "DLA", TYPE_A, /* Deposit Long Address */ - "MPY", TYPE_A, /* Multiply */ - "MPR", TYPE_A, /* Multiply and Round */ - "MPA", TYPE_A, /* Multiply and Accumulate */ - "CDB", TYPE_A, /* Convert Decimal to Binary */ - "DVD", TYPE_A, /* Unrounded Double Length Divide */ - "DVR", TYPE_A, /* Rounded Double Length Divide */ - "DVS", TYPE_A, /* Single Length Divide */ - "CBD", TYPE_A, /* Convert Binary to Decimal */ - "BZE", TYPE_B, /* Branch if X is Zero */ - "BZE", TYPE_B, - "BNZ", TYPE_B, /* Branch if X is not Zero */ - "BNZ", TYPE_B, - "BPZ", TYPE_B, /* Branch if X is Positive or zero */ - "BPZ", TYPE_B, - "BNG", TYPE_B, /* Branch if X is Positive or zero */ - "BNG", TYPE_B, - "BUX", TYPE_B, /* Branch on Unit indexing */ - "BUX", TYPE_B, - "BDX", TYPE_B, /* Branch on Double Indexing */ - "BDX", TYPE_B, - "BCHX", TYPE_B, /* Branch on Character Indexing */ - "BCHX", TYPE_B, - "BCT", TYPE_B, /* Branch on Count - BC */ - "BCT", TYPE_B, - "CALL", TYPE_B, /* Call Subroutine */ - "CALL", TYPE_B, - "EXIT", TYPE_B, /* Exit Subroutine */ - "EXIT", TYPE_B, - NULL, TYPE_D, /* Branch unconditional */ - NULL, TYPE_D, - "BFP", TYPE_B, /* Branch state of floating point accumulator */ - "BFP", TYPE_B, - "LDN", TYPE_A, /* Load direct to X */ - "ADN", TYPE_A, /* Add direct to X */ - "NGN", TYPE_A, /* Negative direct to X */ - "SBN", TYPE_A, /* Subtract direct from X */ - "LDNC", TYPE_A, /* Load direct into X with carry */ - "ADNC", TYPE_A, /* Add direct to X with carry */ - "NGNC", TYPE_A, /* Negative direct to X with carry */ - "SBNC", TYPE_A, /* Subtract direct from X with carry */ - "SL", TYPE_C, /* Shift Left */ - "SLD", TYPE_C, /* Shift Left Double */ - "SR", TYPE_C, /* Shift Right */ - "SRD", TYPE_C, /* Shift Right Double */ - "NORM", TYPE_A, /* Nomarlize Single -2 +FP */ - "NORMD", TYPE_A, /* Normalize Double -2 +FP */ - "MVCH", TYPE_A, /* Move Characters - BC */ - "SMO", TYPE_A, /* Supplementary Modifier - BC */ - "ANDN", TYPE_A, /* Logical AND direct into X */ - "ORN", TYPE_A, /* Logical OR direct into X */ - "ERN", TYPE_A, /* Logical XOR direct into X */ - "NULL", TYPE_A, /* No Operation */ - "LDCT", TYPE_A, /* Load Count */ - "MODE", TYPE_A, /* Set Mode */ - "MOVE", TYPE_A, /* Copy N words */ - "SUM", TYPE_A, /* Sum N words */ - "FLOAT", TYPE_A, /* Convert Fixed to Float +FP */ - "FIX", TYPE_A, /* Convert Float to Fixed +FP */ - "FAD", TYPE_A, /* Floating Point Add +FP */ - "FSB", TYPE_A, /* Floating Point Subtract +FP */ - "FMPY", TYPE_A, /* Floating Point Multiply +FP */ - "FDVD", TYPE_A, /* Floating Point Divide +FP */ - "LFP", TYPE_A, /* Load Floating Point +FP */ - "SFP", TYPE_A, /* Store Floating Point +FP */ - "140", TYPE_A, - "141", TYPE_A, - "142", TYPE_A, - "143", TYPE_A, - "144", TYPE_A, - "145", TYPE_A, - "146", TYPE_A, - "147", TYPE_A, - "150", TYPE_A, - "151", TYPE_A, - "152", TYPE_A, - "153", TYPE_A, - "154", TYPE_A, - "155", TYPE_A, - "156", TYPE_A, - "157", TYPE_A, - "160", TYPE_A, - "161", TYPE_A, - "162", TYPE_A, - "163", TYPE_A, - "164", TYPE_A, - "165", TYPE_A, - "166", TYPE_A, - "167", TYPE_A, - "170", TYPE_A, - "171", TYPE_A, - "172", TYPE_A, - "173", TYPE_A, - "174", TYPE_A, - "175", TYPE_A, - "176", TYPE_A, - "177", TYPE_A, + "LDX", TYPE_A, /* Load to X */ + "ADX", TYPE_A, /* Add to X */ + "NGX", TYPE_A, /* Negative to X */ + "SBX", TYPE_A, /* Subtract from X */ + "LDXC", TYPE_A, /* Load into X with carry */ + "ADXC", TYPE_A, /* Add to X with carry */ + "NGXC", TYPE_A, /* Negative to X with carry */ + "SBXC", TYPE_A, /* Subtract from X with carry */ + "STO", TYPE_A, /* Store contents of X */ + "ADS", TYPE_A, /* Add X to store */ + "NGS", TYPE_A, /* Negative into Store */ + "SBS", TYPE_A, /* Subtract from store */ + "STOC", TYPE_A, /* Store contents of X with carry */ + "ADSC", TYPE_A, /* Add X to store with carry */ + "NGSC", TYPE_A, /* Negative into Store with carry */ + "SBSC", TYPE_A, /* Subtract from store with carry */ + "ANDX", TYPE_A, /* Logical AND into X */ + "ORX", TYPE_A, /* Logical OR into X */ + "ERX", TYPE_A, /* Logical XOR into X */ + "OBEY", TYPE_A, /* Obey instruction at N */ + "LDCH", TYPE_A, /* Load Character to X */ + "LDEX", TYPE_A, /* Load Exponent */ + "TXU", TYPE_A, /* Test X unequal */ + "TXL", TYPE_A, /* Test X Less */ + "ANDS", TYPE_A, /* Logical AND into store */ + "ORS", TYPE_A, /* Logical OR into store */ + "ERS", TYPE_A, /* Logical XOR into store */ + "STOZ", TYPE_A, /* Store Zero */ + "DCH", TYPE_A, /* Deposit Character to X */ + "DEX", TYPE_A, /* Deposit Exponent */ + "DSA", TYPE_A, /* Deposit Short Address */ + "DLA", TYPE_A, /* Deposit Long Address */ + "MPY", TYPE_A, /* Multiply */ + "MPR", TYPE_A, /* Multiply and Round */ + "MPA", TYPE_A, /* Multiply and Accumulate */ + "CDB", TYPE_A, /* Convert Decimal to Binary */ + "DVD", TYPE_A, /* Unrounded Double Length Divide */ + "DVR", TYPE_A, /* Rounded Double Length Divide */ + "DVS", TYPE_A, /* Single Length Divide */ + "CBD", TYPE_A, /* Convert Binary to Decimal */ + "BZE", TYPE_B, /* Branch if X is Zero */ + "BZE", TYPE_B, + "BNZ", TYPE_B, /* Branch if X is not Zero */ + "BNZ", TYPE_B, + "BPZ", TYPE_B, /* Branch if X is Positive or zero */ + "BPZ", TYPE_B, + "BNG", TYPE_B, /* Branch if X is Positive or zero */ + "BNG", TYPE_B, + "BUX", TYPE_B, /* Branch on Unit indexing */ + "BUX", TYPE_B, + "BDX", TYPE_B, /* Branch on Double Indexing */ + "BDX", TYPE_B, + "BCHX", TYPE_B, /* Branch on Character Indexing */ + "BCHX", TYPE_B, + "BCT", TYPE_B, /* Branch on Count - BC */ + "BCT", TYPE_B, + "CALL", TYPE_B, /* Call Subroutine */ + "CALL", TYPE_B, + "EXIT", TYPE_B, /* Exit Subroutine */ + "EXIT", TYPE_B, + NULL, TYPE_D, /* Branch unconditional */ + NULL, TYPE_D, + "BFP", TYPE_B, /* Branch state of floating point accumulator */ + "BFP", TYPE_B, + "LDN", TYPE_A, /* Load direct to X */ + "ADN", TYPE_A, /* Add direct to X */ + "NGN", TYPE_A, /* Negative direct to X */ + "SBN", TYPE_A, /* Subtract direct from X */ + "LDNC", TYPE_A, /* Load direct into X with carry */ + "ADNC", TYPE_A, /* Add direct to X with carry */ + "NGNC", TYPE_A, /* Negative direct to X with carry */ + "SBNC", TYPE_A, /* Subtract direct from X with carry */ + "SL", TYPE_C, /* Shift Left */ + "SLD", TYPE_C, /* Shift Left Double */ + "SR", TYPE_C, /* Shift Right */ + "SRD", TYPE_C, /* Shift Right Double */ + "NORM", TYPE_A, /* Nomarlize Single -2 +FP */ + "NORMD", TYPE_A, /* Normalize Double -2 +FP */ + "MVCH", TYPE_A, /* Move Characters - BC */ + "SMO", TYPE_A, /* Supplementary Modifier - BC */ + "ANDN", TYPE_A, /* Logical AND direct into X */ + "ORN", TYPE_A, /* Logical OR direct into X */ + "ERN", TYPE_A, /* Logical XOR direct into X */ + "NULL", TYPE_A, /* No Operation */ + "LDCT", TYPE_A, /* Load Count */ + "MODE", TYPE_A, /* Set Mode */ + "MOVE", TYPE_A, /* Copy N words */ + "SUM", TYPE_A, /* Sum N words */ + "FLOAT", TYPE_A, /* Convert Fixed to Float +FP */ + "FIX", TYPE_A, /* Convert Float to Fixed +FP */ + "FAD", TYPE_A, /* Floating Point Add +FP */ + "FSB", TYPE_A, /* Floating Point Subtract +FP */ + "FMPY", TYPE_A, /* Floating Point Multiply +FP */ + "FDVD", TYPE_A, /* Floating Point Divide +FP */ + "LFP", TYPE_A, /* Load Floating Point +FP */ + "SFP", TYPE_A, /* Store Floating Point +FP */ + "140", TYPE_A, + "141", TYPE_A, + "142", TYPE_A, + "143", TYPE_A, + "144", TYPE_A, + "145", TYPE_A, + "146", TYPE_A, + "147", TYPE_A, + "150", TYPE_A, + "151", TYPE_A, + "152", TYPE_A, + "153", TYPE_A, + "154", TYPE_A, + "155", TYPE_A, + "156", TYPE_A, + "157", TYPE_A, + "160", TYPE_A, + "161", TYPE_A, + "162", TYPE_A, + "163", TYPE_A, + "164", TYPE_A, + "165", TYPE_A, + "166", TYPE_A, + "167", TYPE_A, + "170", TYPE_A, + "171", TYPE_A, + "172", TYPE_A, + "173", TYPE_A, + "174", TYPE_A, + "175", TYPE_A, + "176", TYPE_A, + "177", TYPE_A, }; char *type_d[] = { "BRN", "BVS", "BVSR", "BVC", "BVCR", "BCS", "BCC", "BVCI" }; @@ -426,7 +424,7 @@ print_opcode(FILE * of, t_value val) int m; int n; t_opcode *tab; - + op = 0177 & (val >> 14);; x = 07 & (val >> 21); m = 03 & (val >> 12); @@ -496,7 +494,7 @@ fprint_sym(FILE * of, t_addr addr, t_value * val, UNIT * uptr, int32 sw) return SCPE_OK; } -int +int find_opcode(char *op, int *val) { int i; @@ -513,10 +511,10 @@ find_opcode(char *op, int *val) return -1; } } - if (op[i] == 0 && v <= 0177) + if (op[i] == 0 && v <= 0177) return v; for(i = 0; i <= 0177; i++) { - if (ops[i].name != '\0' && sim_strcasecmp(op, ops[i].name) == 0) + if (ops[i].name != '\0' && sim_strcasecmp(op, ops[i].name) == 0) return i; } for(i = 0; i < 8; i++) { @@ -593,12 +591,12 @@ if (sw & SWMASK ('M')) { *val = (0177 & op) << 14; if (x >= 0) *val |= (07 & x) << 21; - + switch (ops[op].type) { case TYPE_A: /* OP x m/n or OP x /n */ if (m > 0) *val |= (m & 03) << 12; - if (*cptr == '/') { + if (*cptr == '/') { cptr++; n = get_uint(cptr, 8, 07777, &r); if (r != SCPE_OK) @@ -610,7 +608,7 @@ if (sw & SWMASK ('M')) { if (m >= 0) return SCPE_ARG; *val |= (m & 03) << 12; - if (*cptr == '/') { + if (*cptr == '/') { cptr++; n = get_uint(cptr, 8, 077777, &r); if (r != SCPE_OK) @@ -621,7 +619,7 @@ if (sw & SWMASK ('M')) { case TYPE_C: /* OP x m/c+n or OP X /c+n */ if (m > 0) *val |= (m & 03) << 12; - if (*cptr == '/') { + if (*cptr == '/') { cptr++; for (i = 0; i< 4; i++) { if (type_c[i] == *cptr) { @@ -629,7 +627,7 @@ if (sw & SWMASK ('M')) { break; } } - if (*cptr != '+') + if (*cptr != '+') return SCPE_ARG; cptr++; n = get_uint(cptr, 8, 01777, &r); @@ -646,7 +644,7 @@ if (sw & SWMASK ('M')) { } if (m >= 0 || x >= 0) return SCPE_ARG; - if (*cptr == '/') { + if (*cptr == '/') { cptr++; n = get_uint(cptr, 8, 077777, &r); if (r != SCPE_OK) diff --git a/ICL1900/icl1900_tp.c b/ICL1900/icl1900_tp.c index 275ec5c..3dce5c8 100644 --- a/ICL1900/icl1900_tp.c +++ b/ICL1900/icl1900_tp.c @@ -91,7 +91,7 @@ * p101xxxx Alpha + 11xxxx xxxx < 4 * p110xxxx Beta + 10xxxx * p111xxxx Beta + 11xxxx xxxx < 4 - * + * * Two modes Alpha and Beta. Delta is always output. * * Graphics mode translation. @@ -162,7 +162,7 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) { *resp = 0; /* Find the unit from dev */ - for (i = 0; i < NUM_DEVS_PTP; i++) { + for (i = 0; i < ptp_dev.numunits; i++) { if (GET_UADDR(ptp_unit[i].flags) == dev) { uptr = &ptp_unit[i]; break; @@ -183,7 +183,7 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) { cmd &= 077; switch(cmd & 070) { case 010: /* Command */ - if ((uptr->flags & UNIT_ATT) == 0) + if ((uptr->flags & UNIT_ATT) == 0) break; if (uptr->CMD & BUSY) { *resp = 3; @@ -200,13 +200,13 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) { break; case 020: if (cmd == 020) { /* Send Q */ - if ((uptr->flags & UNIT_ATT) == 0) + if ((uptr->flags & UNIT_ATT) == 0) *resp = 040; if (uptr->STATUS & 06) *resp = 040; *resp |= uptr->STATUS & TERMINATE; } else if (cmd == 024) { /* Send P */ - if ((uptr->flags & UNIT_ATT) != 0) + if ((uptr->flags & UNIT_ATT) != 0) *resp = (uptr->STATUS & ERROR) | 1; uptr->STATUS = 0; chan_clr_done(GET_UADDR(uptr->flags)); @@ -219,7 +219,7 @@ void ptp_cmd(int dev, uint32 cmd, uint32 *resp) { } break; - default: + default: break; } } @@ -238,7 +238,7 @@ void ptp_nsi_cmd(int dev, uint32 cmd) { UNIT *uptr = NULL; /* Find the unit from dev */ - for (i = 0; i < NUM_DEVS_PTP; i++) { + for (i = 0; i < ptp_dev.numunits; i++) { if (GET_UADDR(ptp_unit[i].flags) == dev) { uptr = &ptp_unit[i]; break; @@ -296,7 +296,7 @@ void ptp_nsi_status(int dev, uint32 *resp) { *resp = 0; /* Find the unit from dev */ - for (i = 0; i < NUM_DEVS_PTP; i++) { + for (i = 0; i < ptp_dev.numunits; i++) { if (GET_UADDR(ptp_unit[i].flags) == dev) { uptr = &ptp_unit[i]; break; @@ -373,7 +373,7 @@ t_stat ptp_svc (UNIT *uptr) if (uptr->CMD & DELTA_MODE) { uptr->CMD &= ~DELTA_MODE; data = ch; - if (ch & 040) + if (ch & 040) data |= 0174 ^ ((ch & 020) << 1); } else if (uptr->CMD & ALPHA_MODE) { data = ch & 017; @@ -391,7 +391,7 @@ t_stat ptp_svc (UNIT *uptr) case 0040: data |= 0140; break; case 0060: data |= 0160; break; } - } + } } } if (data != 0) { @@ -402,7 +402,7 @@ t_stat ptp_svc (UNIT *uptr) ch = ch ^ (ch << 2); ch = ch ^ (ch << 1); data |= ch; - } + } fputc(data, uptr->fileref); uptr->pos = ftell(uptr->fileref); if (ferror (uptr->fileref)) { diff --git a/ICL1900/icl1900_tr.c b/ICL1900/icl1900_tr.c index 2775376..a86a6fe 100644 --- a/ICL1900/icl1900_tr.c +++ b/ICL1900/icl1900_tr.c @@ -93,7 +93,7 @@ * p101xxxx Alpha + 11xxxx xxxx < 4 * p110xxxx Beta + 10xxxx * p111xxxx Beta + 11xxxx xxxx < 4 - * + * * Two modes Alpha and Beta. Delta is always output. * * Graphics mode translation. @@ -165,7 +165,7 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) { *resp = 0; /* Find the unit from dev */ - for (i = 0; i < NUM_DEVS_PTR; i++) { + for (i = 0; i < ptr_dev.numunits; i++) { if (GET_UADDR(ptr_unit[i].flags) == dev) { uptr = &ptr_unit[i]; break; @@ -180,12 +180,12 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) { if (NSI_TYPE(uptr->flags)) return; - if ((uptr->flags & UNIT_ATT) == 0) + if ((uptr->flags & UNIT_ATT) == 0) return; cmd &= 077; switch(cmd & 070) { case 010: /* Command */ - if ((uptr->flags & UNIT_ATT) == 0) + if ((uptr->flags & UNIT_ATT) == 0) break; if (uptr->CMD & BUSY) { *resp = 3; @@ -201,13 +201,13 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) { break; case 020: if (cmd == 020) { /* Send Q */ - if ((uptr->flags & UNIT_ATT) != 0) + if ((uptr->flags & UNIT_ATT) != 0) *resp = 040; if (uptr->STATUS & 06) *resp = 040; *resp |= uptr->STATUS & TERMINATE; } else if (cmd == 024) { /* Send P */ - if ((uptr->flags & UNIT_ATT) != 0) + if ((uptr->flags & UNIT_ATT) != 0) *resp = (uptr->STATUS & ERROR) | 1; uptr->STATUS = 0; chan_clr_done(GET_UADDR(uptr->flags)); @@ -220,7 +220,7 @@ void ptr_cmd(int dev, uint32 cmd, uint32 *resp) { } break; - default: + default: break; } } @@ -240,7 +240,7 @@ void ptr_nsi_cmd(int dev, uint32 cmd) { UNIT *uptr = NULL; /* Find the unit from dev */ - for (i = 0; i < NUM_DEVS_PTR; i++) { + for (i = 0; i < ptr_dev.numunits; i++) { if (GET_UADDR(ptr_unit[i].flags) == dev) { uptr = &ptr_unit[i]; break; @@ -276,7 +276,7 @@ void ptr_nsi_cmd(int dev, uint32 cmd) { uptr->CMD |= STOP_CHAR; if (cmd & 020) uptr->CMD |= BIN_MODE; - if ((cmd & 040) == 0) + if ((cmd & 040) == 0) uptr->CMD |= IGN_BLNK; uptr->CMD |= BUSY; uptr->STATUS = 0; @@ -300,7 +300,7 @@ void ptr_nsi_status(int dev, uint32 *resp) { *resp = 0; /* Find the unit from dev */ - for (i = 0; i < NUM_DEVS_PTR; i++) { + for (i = 0; i < ptr_dev.numunits; i++) { if (GET_UADDR(ptr_unit[i].flags) == dev) { uptr = &ptr_unit[i]; break; @@ -352,7 +352,7 @@ t_stat ptr_svc (UNIT *uptr) if ((uptr->CMD & STOP_CHAR) != 0 && uptr->HOLD == 032) uptr->STATUS |= TERMINATE; } - + /* Read next charater */ if ((uptr->flags & UNIT_ATT) == 0 || feof(uptr->fileref) || @@ -369,10 +369,10 @@ t_stat ptr_svc (UNIT *uptr) ch = data ^ (data >> 4); ch = ch ^ (ch >> 2); ch = ch ^ (ch >> 1); - if (ch != 0) + if (ch != 0) uptr->STATUS = TERMINATE | ERROR; chan_set_done(GET_UADDR(uptr->flags)); - } + } data &= 0177; if ((data == 0 || data == 0177) && (uptr->CMD & IGN_BLNK) != 0) { sim_activate (uptr, uptr->wait); /* try again */ @@ -423,7 +423,7 @@ t_stat ptr_svc (UNIT *uptr) break; } case 0100: - if ((uptr->CMD & 1) == BETA_MODE) + if ((uptr->CMD & 1) == BETA_MODE) shift = ALPHA_SHIFT; uptr->CMD |= ALPHA_MODE; ch = 040 | (data & 037); @@ -435,7 +435,7 @@ t_stat ptr_svc (UNIT *uptr) break; } case 0120: - if ((uptr->CMD & 1) == ALPHA_MODE) + if ((uptr->CMD & 1) == ALPHA_MODE) shift = BETA_SHIFT; uptr->CMD &= ~ALPHA_MODE; ch = 040 | (data & 037); @@ -498,7 +498,7 @@ ptr_boot(int32 unit_num, DEVICE * dptr) M[64 + chan] = 0; M[256 + 4 * chan] = 0; - M[257 + 4 * chan] = 020; + M[257 + 4 * chan] = 0; loading = 1; uptr->CMD = BUSY|ALPHA_MODE|BIN_MODE|IGN_BLNK; sim_activate (uptr, uptr->wait); diff --git a/ICL1900/tapeconv.c b/ICL1900/tapeconv.c index 866fccb..09c1aca 100755 --- a/ICL1900/tapeconv.c +++ b/ICL1900/tapeconv.c @@ -10,7 +10,7 @@ #define TAPE_IRG 0200 #define BCD_TM 017 - + unsigned char buffer[TAPE_BUFFER_SIZE]; char *xlat; /* Pointer to translate table */ int eor = 0; /* Report eor */ @@ -125,7 +125,7 @@ int read_tape(FILE *f, int *len) { *len = -1; return 1; } - if (lastchar != 0xff) + if (lastchar != 0xff) buffer[sz++] = lastchar; lastchar = 0xff; while(fread(&ch, sizeof(unsigned char), 1, f) == 1) { @@ -146,7 +146,7 @@ int read_tape(FILE *f, int *len) { } else { unsigned char xlen[4]; int i; - if (fread(&xlen, sizeof(unsigned char), 4, f) != 4) + if (fread(&xlen, sizeof(unsigned char), 4, f) != 4) return 0; /* Convert to number */ sz = xlen[0]; @@ -269,27 +269,14 @@ int main(int argc, char *argv[]) { } /* Process records of the file */ while(read_tape(tape, &sz)) { - if (sz == -2) + if (sz == -2) break; if (sz == -1) { puts("*EOF*"); write_mark(otape); } else { -// p = buffer; - // col = 0; -// for(i = 0; i < sz; i++) { -// char ch = *p++; -// if (parity_table[ch & 077] == (ch & 0100)) -// col ++; -// } - // if (col == sz) { -// p = buffer; -// for(i = 0; i < sz; i++) -// putchar(xlat[*p++ & 077]); -// putchar('\n'); -// } else - for (i = 0; i < sz; i+=3) - printf("%08o ", (buffer[i] << 16) | (buffer[i+1] << 8) | buffer[i+2]); + for (i = 0; i < sz; i+=3) + printf("%08o ", (buffer[i] << 16) | (buffer[i+1] << 8) | buffer[i+2]); printf("\n"); write_block(otape, sz, buffer); }