From a809a48b569ddd3d98ff96768c07e0ea91dfbea9 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Sat, 11 Aug 2018 00:08:28 -0400 Subject: [PATCH] ICL1900: Added support for standard I/O and console device. --- ICL1900/Makefile | 3 +- ICL1900/div.c | 36 ++++ ICL1900/icl1900_cpu.c | 240 +++++++++++++++----------- ICL1900/icl1900_cty.c | 347 ++++++++++++++++++++++++++++++++++++++ ICL1900/icl1900_defs.h | 18 +- ICL1900/icl1900_stdio.c | 365 ++++++++++++++++++++++++++++++++++++++++ ICL1900/icl1900_sys.c | 2 +- 7 files changed, 902 insertions(+), 109 deletions(-) create mode 100644 ICL1900/div.c create mode 100644 ICL1900/icl1900_cty.c create mode 100644 ICL1900/icl1900_stdio.c diff --git a/ICL1900/Makefile b/ICL1900/Makefile index 8833eb8..26420fe 100755 --- a/ICL1900/Makefile +++ b/ICL1900/Makefile @@ -1087,7 +1087,8 @@ DISPLAYD = display # Emulator source files and compile time options # ICL1900D = ./ -ICL1900 = ${ICL1900D}icl1900_cpu.c ${ICL1900D}icl1900_sys.c +ICL1900 = ${ICL1900D}icl1900_cpu.c ${ICL1900D}icl1900_sys.c ${ICL1900D}icl1900_stdio.c \ + ${ICL1900D}icl1900_cty.c ICL1900_OPT = -I.. -DUSE_SIM_CARD # diff --git a/ICL1900/div.c b/ICL1900/div.c new file mode 100644 index 0000000..960f32e --- /dev/null +++ b/ICL1900/div.c @@ -0,0 +1,36 @@ +#include +#include + +#define N 24 +#define B0 (1<>= 1; if (RF & 1) /* Multiply and Round */ RP |= B0; RB = 0; for(RK = 23; RK != 0; RK--) { - if (temp2) + if (n) RB += RA; - temp2 = RP & 1; + n = RP & 1; RP >>= 1; if (RB & 1) RP |= B0; @@ -681,11 +682,11 @@ obey: RB >>= 1; } - if (temp2) { + if (n) { RB += (RA ^ FMASK) + 1; } - temp2 = RP & 1; /* Check for MPR */ - if (temp2 && RP & B0) + n = RP & 1; /* Check for MPR */ + if (n && RP & B0) RB++; RP >>= 1; if (RF == OP_MPA) { @@ -765,7 +766,7 @@ obey: 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) + if (RA == FMASK && RP == 1 && RB == 0) /* Flag special case */ f=1; if (RA == 0) { /* Exit on zero divisor */ /* VI */ @@ -774,7 +775,7 @@ obey: break; } BCarry = (RP & B0) != 0; - temp = (RP | RB) == 0; /* Save zero dividend */ + n = (RP | RB) == 0; /* Save zero dividend */ /* Setup for specific divide order code */ /* V11 */ if (RF & 2) { /* DVS */ @@ -791,20 +792,20 @@ obey: /* First partial remainder */ /* V12 */ if (((RB ^ RA) & B0) == 0) { - temp2 = RB + (RA ^ FMASK) + 1; + RS = RB + (RA ^ FMASK) + 1; RK=1; } else { - temp2 = RB + RA; + RS = RB + RA; RK=0; } - if (((temp2 ^ RA) & B0) != 0) + if (((RS ^ RA) & B0) != 0) BCarry = 1; BCarry = RK != BCarry; RP <<= 1; - if (((temp2 ^ RA) & B0) == 0) { + if (((RS ^ RA) & B0) == 0) { RP |= 1; } - RB = temp2 << 1; + RB = RS << 1; if (RP & BM1) RB |= 1; RB &= FMASK; @@ -813,16 +814,16 @@ obey: /* Main divide loop */ /* V13 */ for (RK = 22; RK != 0; RK--) { - if (((temp2 ^ RA) & B0) == 0) { - temp2 = RB + (RA ^ FMASK) + 1; + if (((RS ^ RA) & B0) == 0) { + RS = RB + (RA ^ FMASK) + 1; } else { - temp2 = RB + RA; + RS = RB + RA; } RP <<= 1; - if (((temp2 ^ RA) & B0) == 0) { + if (((RS ^ RA) & B0) == 0) { RP |= 1; } - RB = temp2 << 1; + RB = RS << 1; if (RP & BM1) RB |= 1; RB &= FMASK; @@ -831,13 +832,13 @@ obey: } /* Final product */ - if (((temp2 ^ RA) & B0) == 0) { /* V14 */ - temp2 = RB + (RA ^ FMASK) + 1; + if (((RS ^ RA) & B0) == 0) { /* V14 */ + RS = RB + (RA ^ FMASK) + 1; } else { - temp2 = RB + RA; + RS = RB + RA; } RP <<= 1; - if (((temp2 ^ RA) & B0) == 0) { + if (((RS ^ RA) & B0) == 0) { RP |= 1; } RP &= FMASK; @@ -856,9 +857,9 @@ obey: //fprintf(stderr, "DVD5: %08o %08o %08o \n\r", RA, RP, RB); /* Form final partial product */ if (RA & B0) { - temp2 = (RB + (RA ^ FMASK) + 1) & FMASK; + RS = (RB + (RA ^ FMASK) + 1) & FMASK; //fprintf(stderr, "DVD5: %08o %08o %08o %08o\n\r", RA, RP, RB, RT); - if (temp2 == 0) { + if (RS == 0) { RB = 0; goto dvd1; } @@ -883,7 +884,7 @@ dvd1: BCarry = 1; dvd2: //fprintf(stderr, "DVD7: %08o %08o %08o \n\r", RA, RP, RB); - if (temp) + if (n) BCarry = 0; if (BCarry) BV = 1; @@ -1130,15 +1131,15 @@ branch: RK = RB & 01777; BCarry = 0; while (RK != 0) { - temp2 = 0; + n = 0; switch (m) { - case 0: temp2 = (RA & B0) != 0; break; + case 0: n = (RA & B0) != 0; break; case 1: break; case 2: case 3: temp = RA & B0; } RA <<= 1; - RA |= temp2; + RA |= n; if ((m & 2) && temp != (RA & B0)) BV = 1; RA &= FMASK; @@ -1175,9 +1176,9 @@ branch: if (RB & B0) RA |= 1; RB &= M23; - temp2 = (RA & B0) != 0; + n = (RA & B0) != 0; temp = (RA & BM1) != 0; - if (temp2 != temp) + if (n != temp) BV = 1; } RA &= FMASK; @@ -1191,23 +1192,23 @@ branch: case OP_SRL: /* Shift Right */ m = (RB >> 10) & 03; RK = RB & 01777; - temp2 = RA & B0; + RT = RA & B0; BCarry = 0; switch(m) { case 0: break; - case 1: temp2 = 0; break; + case 1: RT = 0; break; case 2: break; case 3: if (BV) { - temp2 = B0 ^ temp2; + RT = B0 ^ RT; BV = 0; } } while (RK != 0) { if (m == 0) - temp2 = (RA & 1) ? B0 : 0; + RT = (RA & 1) ? B0 : 0; temp = RA & 1; RA >>= 1; - RA |= temp2; + RA |= RT; RK--; } if (m > 1 && temp == 1) @@ -1220,9 +1221,9 @@ branch: RK = RB & 01777; RB = XR[(RX+1) & 07]; BCarry = 0; - temp2 = RA & B0; + RT = RA & B0; if (m == 3 && RK != 0 && BV) { - temp2 = B0^temp2; + RT = B0^RT; BV = 0; } while (RK != 0) { @@ -1247,7 +1248,7 @@ branch: if (RA & 1) RB |= B1; RA >>= 1; - RA |= temp2; + RA |= RT; } RK--; } @@ -1268,12 +1269,12 @@ branch: RA = RB = 0; } else if (BV) { RT++; - temp2 = (RA & B0) ^ B0; + RP = (RA & B0) ^ B0; if (RA & 1 && RF & 1) RB |= B0; RB >>= 1; RA >>= 1; - RA |= temp2; + RA |= RP; } else if (RA != 0 || RB != 0) { /* Shift left until sign and B1 not same */ while ((((RA >> 1) ^ RA) & B1) == 0) { @@ -1297,8 +1298,7 @@ branch: RB += 0400; if (RB & B0) { RB = RP; - temp2 = (RA & M23) +1; - if (temp2 & B0) + if (((RA & M23) + 1) & B0) RA = RB = 0; } RB = (RB & MMASK) | (RT & M9); @@ -1363,6 +1363,17 @@ branch: break; case OP_MODE: /* Set Mode */ +#if 0 /* Stevenage Machines */ + if (exe_mode && RX == 1) + temp = RB; /* Set interrupt enable mode */ + else +/* On Stevenage Machines 002 -> 020 Add Datum */ +/* On Stevenage Machines 004 -> 000 unused */ +/* On Stevenage Machines 010 -> 000 unused */ +/* On Stevenage Machines 020 -> Extended store mode */ +/* On Stevenage Machines 040 -> 000 unused */ +/* On Stevenage Machines 0100 -> Carry */ +#endif if (exe_mode) Mode = RB & 077; else @@ -1530,24 +1541,27 @@ branch: } //fprintf(stderr, "FAD5: %08o %08o %08o %08o %08o\n\r", RA, RB, RC, faccl, facch); /* Add the numbers */ - temp2 = (faccl & B0) != 0; /* Save signs */ + n = (faccl & B0) != 0; /* Save signs */ if (RA & B0) - temp2 |= 2; + n |= 2; faccl += RA; facch += RB; if (facch & B0) { facch &= M23; faccl ++; } - temp = (faccl & B0) != 0; + /* Sign of result */ + if ((faccl & B0) != 0) + n |= 4; //fprintf(stderr, "FAD6: %08o %08o %08o %d %d\n\r", faccl, facch, RC, temp, temp2); - if ((temp2 == 3 && temp == 0) || (temp2 == 0 && temp != 0)) { + /* Result sign not equal same sign as addens */ + if (n == 3 || n == 4) { if (faccl & 1) facch |= B0; faccl >>= 1; facch >>= 1; facch &= MMASK; - if (!temp) + if ((n & 4) == 0) faccl |= B0; /* Set sign */ e1++; //fprintf(stderr, "FAD6a: %08o %08o %08o %d %d\n\r", faccl, facch, RC, temp, temp2); @@ -1579,7 +1593,7 @@ fn: faccl ++; facch &= M23; faccl &= FMASK; - temp2 = (faccl & B0) != 0; +// temp2 = (faccl & B0) != 0; /* renormalize if things changed */ if ((RX & 2) == 0 && (((faccl >> 1) ^ faccl) & B1) == 0) { e1--; @@ -1665,35 +1679,35 @@ fexp: } } //fprintf(stderr, "FMP2: %08o %08o %08o %08o %08o %03o %d %o\n\r", RA, RB, RC, faccl, facch, e1, e1, f); - temp = faccl; - temp2 = facch; + RT = faccl; + RP = facch; faccl = facch = 0; /* Clear product */ /* Do actual multiply */ for(RK = 37; RK != 0; RK--) { /* If High order bit one, add in RB,RA */ - if (temp2 & B15) { + if (RP & B15) { facch += RB; faccl += RA; if (facch & B0) faccl++; facch &= M23; } - /* Shift faccl,fach,temp,t right one */ - if (temp & 1) - temp2 |= B0; + /* Shift faccl,fach,RT,t right one */ + if (RT & 1) + RP |= B0; if (facch & 1) - temp |= B0; + RT |= B0; if (faccl & 1) facch |= B0; - temp2 >>= 1; - temp >>= 1; + RP >>= 1; + RT >>= 1; facch >>= 1; faccl >>= 1; -//fprintf(stderr, "FMP3: %08o %08o %08o %08o %08o %08o %08o %02o\n\r", RA, RB, RC, faccl, facch, temp, temp2, RK); +//fprintf(stderr, "FMP3: %08o %08o %08o %08o %08o %08o %08o %02o\n\r", RA, RB, RC, faccl, facch, RT, RP, RK); } /* Check if still negative multiplican */ - if (temp2 & B15) { + if (RP & B15) { facch += RB; faccl += RA; if (facch & B0) @@ -1705,20 +1719,20 @@ fexp: if ((RX & 2) == 0 && faccl == 0 && facch != 0) { while ((faccl & B1) == 0) { e1--; - temp2 <<= 1; - temp <<= 1; + RP <<= 1; + RT <<= 1; facch <<= 1; faccl <<= 1; - if (temp2 & B0) - temp |= 1; - if (temp & B0) + if (RP & B0) + RT |= 1; + if (RT & B0) facch |= 1; if (facch & B0) faccl |= 1; faccl &= FMASK; facch &= M23; - temp &= M23; - temp2 &= M23; + RT &= M23; + RP &= M23; } } /* Fix up if over flow */ @@ -1806,36 +1820,36 @@ fexp: } RA ^= M23; /* precompliment */ RB ^= M23; - temp2 = faccl; /* Set dividend into upper half */ - temp = facch; + RP = faccl; /* Set dividend into upper half */ + RT = facch; faccl = 0; facch = 0; n = 0; /* DO actual divide */ for (RK=46; RK != 0; RK--) { uint32 t0, t1; - t0 = temp + RB + 1; - t1 = temp2 + RA; + t0 = RT + RB + 1; + t1 = RP + RA; if (t0 & B0) t1++; if (n || (t1 & B0)) { - temp = t0; - temp2 = t1; + RT = t0; + RP = t1; facch |= 1; } facch <<= 1; faccl <<= 1; - temp <<= 1; - temp2 <<= 1; + RT <<= 1; + RP <<= 1; if (facch & B0) faccl |= 1; - if (temp & B0) - temp2 |= 1; - n = (temp2 & B0) != 0; - temp &= M23; - temp2 &= M23; + if (RT & B0) + RP |= 1; + n = (RP & B0) != 0; + RT &= M23; + RP &= M23; facch &= M23; -//fprintf(stderr, "FDV3: %08o %08o %08o %08o %08o %08o %08o %02o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, temp2, temp, RK,t1, t0, n); +//fprintf(stderr, "FDV3: %08o %08o %08o %08o %08o %08o %08o %02o %08o %08o %o\n\r", RA, RB, RC, faccl, facch, RP, RT, RK,t1, t0, n); } /* If rounding and positive and negative result, adjust */ if (((RX & 2) == 0 || f == 0) && faccl & B0) { @@ -1908,6 +1922,12 @@ fexp: case 0150: case 0151: + case 0160: /* Stevenage machines */ /* Load accumulators */ + case 0161: /* Stevenage machines */ /* Store accumulators */ + 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 */ if (exe_mode) { break; } @@ -1916,19 +1936,26 @@ fexp: RA = 0; switch(RB) { case 1: RA = SR1; break; - case 2: RA = SR2; break; - case 3: RA = SR3; break; - case 64: RA = SR64; SR64 = 0; break; - case 65: RA = SR65; SR65 = 0; break; + case 2: ctyi_cmd(0, &RA); break; + case 3: ctyo_cmd(0, &RA); break; + case 64: RA = SR64; SR64 &= 003777777; break; + case 65: RA = SR65; break; } XR[RX] = RA; -fprintf(stderr, "RD SR %o %08o\n\r", RB, RA); +//fprintf(stderr, "RD SR %o %08o\n\r", RB, RA); break; } /* Fall through */ case 0171: /* Write special register */ if (exe_mode) { -fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); +//fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); + RT = 0; + switch(RB) { + case 2: ctyi_cmd(RA, &RT); break; + case 3: ctyo_cmd(RA, &RT); break; + } + XR[RX] = RT; + break; } /* Fall through */ @@ -1950,7 +1977,7 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); Mode &= ~(EJM|AM22|EXTRC); Mode |= (EJM|AM22|EXTRC) & RA; adrmask = (Mode & AM22) ? M22 : M15; -//fprintf(stderr, "Load limit: %08o D:=%08o %02o\n\r", RL, RD, Mode); +fprintf(stderr, "Load limit: %08o D:=%08o %02o\n\r", RL, RD, Mode); #endif if (RF & 1) /* Check if 172 or 173 order code */ break; @@ -1962,7 +1989,7 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); if ((Mode & AM22) && (RA & B3)) Mode |= 1; Mem_read(RD+8, &RC, 0); /* Restore C register */ -//fprintf(stderr, "Load PC: %08o D:=%08o z=%08o\n\r", RC, RD, RA); +fprintf(stderr, "Load PC: %08o D:=%08o z=%08o\n\r", RC, RD, RA); if ((Mode & AM22) == 0 && (RA & B3)) Mode |= 1; BV = (RC & B0) != 0; @@ -1976,6 +2003,15 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); /* Fall through */ case 0174: /* Send control character to peripheral */ if (exe_mode) { + RT = RB; + chan_send_cmd(RB, RA & 077, &RB); +fprintf(stderr, "CMD %04o %04o %08o\n\r", RT, RB, RA); + m = (m == 0) ? 3 : (XR[m] >> 22) & 3; + m = 6 * (3 - m); + RB = (RB & 077) << m; + RA &= ~(077 << m); + RA |= RB; + XR[RX] = RA; break; } /* Fall through */ @@ -1987,7 +2023,7 @@ fprintf(stderr, "WR SR %o %08o\n\r", RB, RA); /* Fall through */ case 0177: /* Test Datum and Limit */ if (exe_mode) { - if (RA < RG || RA > RL) + if (RA < RD || RA >= RL) BCarry = 1; break; } diff --git a/ICL1900/icl1900_cty.c b/ICL1900/icl1900_cty.c new file mode 100644 index 0000000..73b74cb --- /dev/null +++ b/ICL1900/icl1900_cty.c @@ -0,0 +1,347 @@ +/* icl1900_cty.c: ICL1900 front end (console terminal) 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" + +extern int32 tmxr_poll; +t_stat ctyi_svc (UNIT *uptr); +t_stat ctyo_svc (UNIT *uptr); +t_stat cty_reset (DEVICE *dptr); +t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *cty_description (DEVICE *dptr); + +#define CMD u3 +#define STATUS u4 +#define HOLD u5 + +#define START 01 +#define STOP 02 +#define END 000001 +#define BUSY 000040 +#define INPUT 000100 +#define CANCEL 000200 +#define ACCEPT 000400 +#define F1 001000 +#define F2 002000 +#define F3 004000 +#define F4 010000 +#define F5 020000 + +UNIT cty_unit[] = { + { UDATA (&ctyo_svc, TT_MODE_7P, 0), 10000 }, + { UDATA (&ctyi_svc, TT_MODE_7P|UNIT_IDLE, 0), 0 }, + }; + + +MTAB cty_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode }, + { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode }, + { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode }, + { TT_MODE, TT_MODE_7P, "7b", "7P", &tty_set_mode }, + { 0 } + }; + +DEVICE cty_dev = { + "CTY", cty_unit, NULL, cty_mod, + 2, 8, 22, 1, 8, 22, + NULL, NULL, &cty_reset, + NULL, NULL, NULL, NULL, DEV_DEBUG, 0, dev_debug, + NULL, NULL, &cty_help, NULL, NULL, &cty_description + }; + +/* + * Commands: + * Bit 0 = start. + * Bit 1 = stop. + * + * Responses: + * Bit 0 = End of Transfer + * Bit 5 = Busy + * Bit 6 = Input Button Pushed. + * Bit 7 = Cancel Button Pushed. + * Bit 8 = Accept Button Pushed. + * Bit 9 = F1 + * Bit 10 = F2 + * Bit 11 = F3 + * Bit 12 = F4 + * Bit 13 = F5 + * + * 00xxxx -> 011xxxx + * 01xxxx -> 010xxxx + * 10xxxx -> 100xxxx + * 11xxxx -> 101xxxx + * + */ +t_stat ctyo_cmd(uint32 cmd, uint32 *resp) { + if ((cmd & START) != 0 && (cty_unit[0].STATUS & BUSY) == 0) + sim_activate(&cty_unit[0], cty_unit[0].wait); + cty_unit[0].CMD |= cmd; + *resp = cty_unit[0].STATUS; + cty_unit[0].STATUS &= BUSY; + chan_clr_done(3); +} + +t_stat ctyi_cmd(uint32 cmd, uint32 *resp) { + cty_unit[1].CMD |= cmd; + *resp = cty_unit[1].STATUS; + cty_unit[1].STATUS &= BUSY; + chan_clr_done(2); +} + +t_stat ctyo_svc (UNIT *uptr) +{ + t_stat r; + uint8 ch; + int eor; + + if (uptr->CMD & START) { + uptr->STATUS &= ~END; + uptr->STATUS |= BUSY; + chan_clr_done(3); + } + if (uptr->CMD & STOP) { + uptr->STATUS |= END; + uptr->STATUS &= ~BUSY; + chan_set_done(3); + } + uptr->CMD = 0; + /* Check if we had a held characteter */ + if (uptr->HOLD != 0) { + if ((r = sim_putchar_s (uptr->HOLD)) == SCPE_STALL) { + r = SCPE_OK; + } else { + if (uptr->HOLD == '\r') + uptr->HOLD = '\n'; + else + uptr->HOLD = 0; + } + sim_activate (uptr, uptr->wait); /* try again */ + return r; + } + + if (uptr->STATUS & BUSY) { + eor = chan_output_char(3, &ch, 0); + 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; + } + if (ch == 0137) { + ch = '\r'; + uptr->HOLD = '\n'; + } + ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags)) ; + if ((r = sim_putchar_s (ch)) == SCPE_STALL) { /* output; error? */ + uptr->HOLD = ch; + r = SCPE_OK; + } + if (eor) { + uptr->STATUS &= ~BUSY; + uptr->STATUS |= END; + chan_set_done(3); + } + sim_activate (uptr, uptr->wait); /* try again */ + } + return SCPE_OK; +} + +t_stat ctyi_svc (UNIT *uptr) +{ + t_stat r; + uint8 ch; + int eor; + + sim_clock_coschedule (uptr, tmxr_poll); + + if (uptr->CMD & START) { + uptr->STATUS &= ~END; + uptr->STATUS |= BUSY; + chan_clr_done(2); + } + if (uptr->CMD & STOP) { + uptr->STATUS |= END; + uptr->STATUS &= ~BUSY; + chan_set_done(2); + } + uptr->CMD = 0; +/* Handle input */ + + r = sim_poll_kbd(); + if (r & SCPE_KFLAG) { + ch = 0177 & sim_tt_inpcvt(r & 0377, TT_GET_MODE (uptr->flags)); + if (uptr->HOLD) { + if (ch >= '1' && ch <= '5') { + chan_set_done(2); + uptr->STATUS |= (F1 << (ch - '1')); + } else { + sim_putchar('\007'); + } + uptr->HOLD = 0; + return SCPE_OK; + } + if ((uptr->STATUS & BUSY) != 0) { + /* Handle end of buffer */ + switch (ch) { + case '\r': + case '\n': + sim_debug(DEBUG_DATA, &cty_dev, ": ent\n"); + sim_putchar('\r'); + sim_putchar('\n'); + uptr->STATUS |= ACCEPT|END; + uptr->STATUS &= ~BUSY; + chan_set_done(2); + break; + + case 033: /* function key n key */ + uptr->HOLD = 1; + break; + + case 030: /* ^X Post input interrupt */ + sim_debug(DEBUG_CMD, &cty_dev, ": inp\n"); + uptr->STATUS |= INPUT|END; + uptr->STATUS &= ~BUSY; + uptr->HOLD = 0; + chan_set_done(2); + break; + + case 03: /* ^C */ + case 025: /* ^U clear line */ + uptr->STATUS |= CANCEL|END; + uptr->STATUS &= ~BUSY; + uptr->HOLD = 0; + chan_set_done(2); + break; + + default: + sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch); + if (ch >= 0140) + ch -= 040; + if (ch >= 0100) + ch -= 040; + else if (ch >= 060) + ch -= 060; + else if (ch >= 040) + ch -= 020; + else { + sim_putchar('\007'); + break; + } + eor = chan_input_char(2, &ch, 0); + 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; + } + ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags)) ; + sim_putchar (ch); + if (eor) { + uptr->STATUS &= ~BUSY; + uptr->STATUS |= END; + chan_set_done(2); + } + break; + } + } else { + /* Handle end of buffer */ + switch (ch) { + case 033: /* function key n key */ + uptr->HOLD = 1; + break; + + case 030: /* ^X Post input interrupt */ + sim_debug(DEBUG_CMD, &cty_dev, ": inp\n"); + uptr->STATUS |= INPUT; + uptr->HOLD = 0; + chan_set_done(2); + break; + + case 03: /* ^C */ + case 025: /* ^U clear line */ + uptr->STATUS |= CANCEL; + uptr->HOLD = 0; + chan_set_done(2); + break; + + default: + sim_debug(DEBUG_DATA, &cty_dev, ": key '%c'\n", ch); + sim_putchar('\007'); + } + } + } + + return SCPE_OK; +} + +/* Reset */ + +t_stat cty_reset (DEVICE *dptr) +{ + cty_unit[0].CMD = 0; + cty_unit[1].CMD = 0; + cty_unit[0].STATUS = 0; + cty_unit[1].STATUS = 0; + chan_clr_done(2); + chan_clr_done(3); + sim_clock_coschedule (&cty_unit[1], tmxr_poll); + + return SCPE_OK; +} + + +t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val; + cty_unit[1].flags = (cty_unit[1].flags & ~TT_MODE) | val; + return SCPE_OK; +} + +t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n"); +fprintf (st, " mode input characters output characters\n\n"); +fprintf (st, " UC lower case converted lower case converted to upper case,\n"); +fprintf (st, " to upper case, high-order bit cleared,\n"); +fprintf (st, " high-order bit cleared non-printing characters suppressed\n"); +fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n"); +fprintf (st, " non-printing characters suppressed\n"); +fprintf (st, " 7B high-order bit cleared high-order bit cleared\n"); +fprintf (st, " 8B no changes no changes\n\n"); +fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n"); +fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n"); +fprint_reg_help (st, &cty_dev); +return SCPE_OK; +} + +const char *cty_description (DEVICE *dptr) +{ + return "Console TTY Line"; + +} + diff --git a/ICL1900/icl1900_defs.h b/ICL1900/icl1900_defs.h index f34d443..ad21bd0 100755 --- a/ICL1900/icl1900_defs.h +++ b/ICL1900/icl1900_defs.h @@ -57,6 +57,8 @@ extern uint32 M[]; /* Main Memory */ extern DEBTAB dev_debug[]; +extern uint32 SR64; +extern uint32 SR65; /* Returns from device commands */ #define SCPE_BUSY (1) /* Device is active */ @@ -174,6 +176,8 @@ t_opcode; #define B1 020000000 #define B2 010000000 #define B3 004000000 +#define B4 002000000 +#define B5 001000000 #define B8 000100000 #define B15 000001000 #define B16 000000400 @@ -190,6 +194,8 @@ t_opcode; #define CHAR_DEV 0 /* Device transfers via characters */ #define WORD_DEV 1 /* Device transfers via words */ +#define SPEC_HES 2 /* Special transfer */ +#define LONG_BLK 4 /* Long block device */ struct icl_dib { uint8 channel; /* Channel number */ @@ -200,11 +206,13 @@ struct icl_dib { typedef struct icl_dib DIB; /* Hessitation operations */ -int chan_write_char(uint8 channel, uint8 data); -int chan_read_char(uint8 channel, uint8 *data); -int chan_write_word(uint8 channel, uint32 data); -int chan_read_word(uint8 channel, uint32 *data); -int chan_end(uint8 channel); +extern void chan_send_cmd(int dev, uint32 cmd, uint32 *resp); +extern int chan_input_char(int dev, uint8 *data, int eor); +extern int chan_output_char(int dev, uint8 *data, int eor); +extern int chan_input_word(int dev, uint32 *data, int eor); +extern int chan_output_word(int dev, uint32 *data, int eor); +extern void chan_set_done(int dev); +extern void chan_clr_done(int dev); /* Console tty device routines */ extern t_stat ctyi_cmd(uint32 cmd, uint32 *resp); diff --git a/ICL1900/icl1900_stdio.c b/ICL1900/icl1900_stdio.c new file mode 100644 index 0000000..b137ed7 --- /dev/null +++ b/ICL1900/icl1900_stdio.c @@ -0,0 +1,365 @@ +/* icl1900_stdio.c: ICL 1900 standard I/O devices + + 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. + +*/ + +#include "icl1900_defs.h" + +/* Define style bits */ + +#define OUTPUT B0 /* Input/Output flag */ +#define BACKWARD B1 /* Forward/Backword */ +#define WORDCCW B2 /* Character/Word */ +#define MULTICHN B3 /* Single/Multi Channel */ +#define CWRECHARGE B4 /* Recharge CW when empty */ +#define GATHER B5 /* Gather */ + + +DIB *devs[32]; /* Pointer to device DIB entry */ + +/* Fake DIB entries for the CTY devices */ +DIB ctyi_dib = { 2, CHAR_DEV, ctyi_cmd}; +DIB ctyo_dib = { 3, CHAR_DEV, ctyo_cmd}; +DIB nul1_dib = { 22, 0, 0}; +DIB nul2_dib = { 23, 0, 0}; + +uint32 cw0; /* Holding registers for current control word */ +uint32 cw1; + +t_stat +chan_set_devs() +{ + int i; + + /* Clear device table */ + for (i = 0; i < sizeof(devs)/sizeof(DIB *); i++) + devs[i] = NULL; + + devs[22-4] = &nul1_dib; /* Add in hidden channels */ + devs[23-4] = &nul2_dib; + /* Scan all devices and assign to channel */ + for(i = 0; sim_devices[i] != NULL; i++) { + DIB *dibp = (DIB *) sim_devices[i]->ctxt; + int chan; + + /* Check if device a channel device */ + if (dibp == NULL) + continue; + /* If device is disabled, don't add it */ + if (sim_devices[i]->flags & DEV_DIS) + continue; + chan = dibp->channel - 4; + if (chan < 0) + continue; + if (devs[chan] != NULL) { + fprintf(stderr, "Conflict between devices %d %s\n", chan, sim_devices[i]->name); + } else { + devs[chan] = dibp; + } + } + return SCPE_OK; +} + + +/* Set the device onto a given channel */ +t_stat +set_chan(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + int newchan; + t_stat r; + + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + dibp = (DIB *) dptr->ctxt; + + if (dibp == NULL) + return SCPE_IERR; + newchan = get_uint(cptr, 10, 37, &r); + if (r != SCPE_OK) + return r; + if (newchan < 4) /* Lowest channel is 4 */ + return SCPE_ARG; + newchan -= 4; + if (dibp == devs[dibp->channel-4]) + devs[dibp->channel-4] = NULL; + /* If device is disabled, set to whatever the user wants */ + if (dptr->flags & DEV_DIS) { + dibp->channel = newchan; + return SCPE_OK; + } + + if (devs[newchan] != NULL) { + devs[newchan] = dibp; + dibp->channel = newchan+4; + return SCPE_OK; + } else { + fprintf(stderr, "Device already on channel %d\n", newchan+4); + devs[dibp->channel] = dibp; + } + return SCPE_ARG; +} + +/* Print the channel the device is on */ +t_stat +get_chan(FILE *st, UNIT *uptr, int32 v, CONST void *desc) +{ + DEVICE *dptr; + DIB *dibp; + int chan; + + if (uptr == NULL) + return SCPE_IERR; + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + dibp = (DIB *) dptr->ctxt; + if (dibp == NULL) + return SCPE_IERR; + fprintf(st, "Chan=%d", dibp->channel); + return SCPE_OK; +} + +int +get_ccw(int dev, uint32 *addr, uint8 type) { + int cw_addr = 256+4*dev; +#if 0 + cw0 = M[64+dev]; +#endif + cw0 = M[cw_addr]; + cw1 = M[cw_addr+1]; + *addr = cw1; + if (cw0 & WORDCCW) { + if (cw0 & BACKWARD) + cw1 = ((cw1 + M22) & M22) | (cw1 & CMASK); + else + cw1 = ((cw1 + 1) & M22) | (cw1 & CMASK); + } else { + if (cw0 & BACKWARD) { + if (cw1 & CMASK) { + cw1 -= B1; + } else { + cw1 = ((cw1 - 1) & M22) | CMASK; + } + } else { + if ((cw1 & CMASK) == CMASK) { + cw1 = (cw1 + 1) & M22; + } else { + cw1 += B1; + } + } + } + cw0 = ((cw0 - 1) & M15) | (cw0 & CNTMSK); + if ((cw0 & M15) == 0) { + if ((cw0 & (CWRECHARGE|GATHER)) == (CWRECHARGE)) { + cw0 = M[cw_addr+2]; + cw1 = M[cw_addr+3]; + } else if ((cw0 & GATHER) != 0) { + int a; + if ((cw0 & CWRECHARGE) != 0) + M[cw_addr+3] = M[cw_addr+2]; + a = M[cw_addr+3]; + cw0 = M[a & M22]; + cw1 = M[(a + 1) & M22]; + M[cw_addr+3] = ((a + 2) & M22) | (a & CMASK); + } + M[cw_addr] = cw0; + M[cw_addr+1] = cw1; + return (cw0 & M15) == 0; + } + M[cw_addr] = cw0; + M[cw_addr+1] = cw1; + return 0; +} + +/* Hessitation operations */ +void +chan_send_cmd(int dev, uint32 cmd, uint32 *resp) { + DIB *dibp = NULL; + int d = dev & 077; + + if (dev >= 4 && dev <= 36) + dibp = devs[d - 4]; + else if (dev == 3) + dibp = &ctyo_dib; + else if (dev == 2) + dibp = &ctyi_dib; + + *resp = 0; + if (dibp != NULL && dibp->dev_cmd != NULL) { + t_stat r; + + r = (dibp->dev_cmd)((dev & 07700) | cmd, resp); + } +} + +/* Transfer date between device and memory */ +int +chan_input_char(int dev, uint8 *data, int eor) { + int r; + int c; + DIB *dibp = NULL; + uint32 addr; + uint32 mb; + + + /* Figure out DIB to find out type of device */ + if (dev >= 4 && dev <= 36) + dibp = devs[dev - 4]; + else if (dev == 3) + dibp = &ctyo_dib; + else if (dev == 2) + dibp = &ctyi_dib; + + /* Make sure device assigne here */ + if (dibp == NULL || dibp->dev_cmd == NULL) + return -1; + + /* Check if right type */ + if ((dibp->type & WORD_DEV) != 0) + return -2; + + /* Get address of next character. */ + r = get_ccw(dev, &addr, dibp->type); + c = (addr >> 22) & 3; + c = 6 * (3 - c); + mb = M[addr & M22]; + mb &= ~(077 << c); + mb |= ((uint32)(*data) & 077) << c; + M[addr & M22] = mb; + return r; +} + +int +chan_output_char(int dev, uint8 *data, int eor) { + int r; + int c; + DIB *dibp = NULL; + uint32 addr; + uint32 mb; + + + /* Figure out DIB to find out type of device */ + if (dev >= 4 && dev <= 36) + dibp = devs[dev - 4]; + else if (dev == 3) + dibp = &ctyo_dib; + else if (dev == 2) + dibp = &ctyi_dib; + + /* Make sure device assigne here */ + if (dibp == NULL || dibp->dev_cmd == NULL) + return -1; + + /* Check if right type */ + if ((dibp->type & WORD_DEV) != 0) + return -2; + + /* Get address of next character. */ + r = get_ccw(dev, &addr, dibp->type); + c = (addr >> 22) & 3; + c = 6 * (3 - c); + mb = M[addr & M22]; + *data = (uint8)(mb >> c) & 077; + return r; +} + +int +chan_input_word(int dev, uint32 *data, int eor) { + int r; + DIB *dibp = NULL; + uint32 addr; + + + /* Figure out DIB to find out type of device */ + if (dev >= 4 && dev <= 36) + dibp = devs[dev - 4]; + else if (dev == 3) + dibp = &ctyo_dib; + else if (dev == 2) + dibp = &ctyi_dib; + + /* Make sure device assigne here */ + if (dibp == NULL || dibp->dev_cmd == NULL) + return -1; + + /* Check if right type */ + if ((dibp->type & WORD_DEV) == 0) + return -2; + + /* Get address of next word. */ + r = get_ccw(dev, &addr, dibp->type); + M[addr & M22] = *data; + return r; +} + +int +chan_output_word(int dev, uint32 *data, int eor) { + int r; + DIB *dibp = NULL; + uint32 addr; + + + /* Figure out DIB to find out type of device */ + if (dev >= 4 && dev <= 36) + dibp = devs[dev - 4]; + else if (dev == 3) + dibp = &ctyo_dib; + else if (dev == 2) + dibp = &ctyi_dib; + + /* Make sure device assigne here */ + if (dibp == NULL || dibp->dev_cmd == NULL) + return -1; + + /* Check if right type */ + if ((dibp->type & WORD_DEV) == 0) + return -2; + + /* Get address of next word. */ + r = get_ccw(dev, &addr, dibp->type); + *data = M[addr & M22]; + return r; +} + +void +chan_set_done(int dev) { + if (dev < 22) + SR64 |= B2 >> dev; + else + SR65 |= B1 >> (dev - 24); +} + +void +chan_clr_done(int dev) { + if (dev < 22) + SR64 &= ~(B2 >> dev); + else + SR65 &= ~(B1 >> (dev - 24)); +} + + diff --git a/ICL1900/icl1900_sys.c b/ICL1900/icl1900_sys.c index 43f0374..5265c81 100755 --- a/ICL1900/icl1900_sys.c +++ b/ICL1900/icl1900_sys.c @@ -46,7 +46,7 @@ int32 sim_emax = 1; DEVICE *sim_devices[] = { &cpu_dev, -// &cty_dev, + &cty_dev, #if NUM_DEVS_CDR > 0 &cdr_dev, #endif