diff --git a/PDP10/ka10_auxcpu.c b/PDP10/ka10_auxcpu.c index f003100..336724a 100644 --- a/PDP10/ka10_auxcpu.c +++ b/PDP10/ka10_auxcpu.c @@ -246,7 +246,7 @@ static int transaction (unsigned char *request, unsigned char *response) return 0; } -int auxcpu_read (int addr, t_uint64 *data) +int auxcpu_read (t_addr addr, t_uint64 *data) { unsigned char request[12]; unsigned char response[12]; @@ -292,7 +292,7 @@ int auxcpu_read (int addr, t_uint64 *data) return 0; } -int auxcpu_write (int addr, t_uint64 data) +int auxcpu_write (t_addr addr, t_uint64 data) { unsigned char request[12]; unsigned char response[12]; diff --git a/PDP10/ka10_ch10.c b/PDP10/ka10_ch10.c index 0d682d8..2393635 100644 --- a/PDP10/ka10_ch10.c +++ b/PDP10/ka10_ch10.c @@ -335,8 +335,6 @@ void ch10_command (uint32 data) t_stat ch10_devio(uint32 dev, uint64 *data) { - DEVICE *dptr = &imx_dev; - switch(dev & 07) { case CONO: sim_debug (DBG_REG, &ch10_dev, "CONO %012llo %012llo \n", *data, ch10_status); diff --git a/PDP10/ka10_iii.c b/PDP10/ka10_iii.c new file mode 100644 index 0000000..2796cee --- /dev/null +++ b/PDP10/ka10_iii.c @@ -0,0 +1,623 @@ +/* ka10_iii.c: Triple III display processor. + + Copyright (c) 2013-2019, 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 "kx10_defs.h" +#ifndef NUM_DEVS_III +#define NUM_DEVS_III 0 +#endif + +#if NUM_DEVS_III > 0 +#include "display/display.h" + + +#define III_DEVNUM 0430 + +#define STATUS u3 +#define MAR u4 +#define PIA u5 +#define POS u6 + +/* CONO Bits */ +#define SET_PIA 000000010 /* Set if this bit is zero */ +#define STOP 000000020 /* Stop processor after instruction */ +#define CONT 000000040 /* Start execution at address */ +#define F 000000100 /* Clear flags */ +#define SET_MSK 000360000 /* Set mask */ +#define RST_MSK 007400000 /* Reset mask */ + +/* CONI Bits */ +#define PIA_MSK 000000007 +#define INST_HLT 000000010 /* Halt instruction */ +#define WRAP_ENB 000000020 /* Wrap around mask */ +#define EDGE_ENB 000000040 /* Edge interrupt mask */ +#define LIGH_ENB 000000100 /* Light pen enable mask */ +#define CLK_STOP 000000200 /* Clock stop */ +#define CLK_BIT 000001000 /* Clock */ +#define NXM_BIT 000002000 /* Non-existent memory */ +#define IRQ_BIT 000004000 /* Interrupt pending */ +#define DATAO_LK 000010000 /* PDP10 gave DATAO when running */ +#define LIGHT_FLG 000020000 /* Light pen flag */ +#define WRAP_FLG 000040000 /* Wrap around flag */ +#define EDGE_FLG 000100000 /* Edge overflow */ +#define HLT_FLG 000200000 /* Not running */ + +#define WRAP_MSK 00001 +#define EDGE_MSK 00002 +#define LIGH_MSK 00004 +#define HLT_MSK 00010 +#define WRP_FBIT 00020 +#define EDG_FBIT 00040 +#define LIT_FBIT 00100 +#define CTL_FBIT 00200 +#define HLT_FBIT 00400 +#define NXM_FLG 01000 +#define DATA_FLG 02000 +#define RUN_FLG 04000 + +#define TSS_INST 012 /* Test */ +#define LVW_INST 006 /* Long Vector */ +#define SVW_INST 002 /* Short vector */ +#define JMP_INST 000 /* Jump or Halt */ +#define JSR_INST 004 /* JSR(1) or JMS(0), SAVE(3) */ +#define RES_INST 014 /* Restore */ +#define SEL_INST 010 /* Select instruction */ + +#define CSIZE 00000000007 /* Current char size */ +#define CBRT 00000000070 /* Current brightness */ +#define POS_Y 00000377700 +#define POS_X 01777400000 +#define CSIZE_V 0 +#define CBRT_V 3 +#define POS_X_V 6 +#define POS_Y_V 16 + +/* + * Character map. + * M(x,y) moves pointer to x,y. + * V(x,y) draws a vector between current pointer and x,y. + * All characters start at 0,6 and end at 8,6. + * In the map there are up to 18 points per character. For a character a M(0,0) indicates + * that drawing is done and a move to 8,6 should be done. + */ +#define M(x,y) (x << 4)|y|0000 +#define V(x,y) (x << 4)|y|0200 + +uint8 map[128][18] = { + { 0 }, + { M(0,9), V(3,6), V(3,14), M(3,6), V(6,9) }, + { M(6,6), V(3,9), V(1,9), V(0,8), V(0,7), V(1,6), V(3,6), V(6,9) }, + { V(2,8), V(2,13), V(3,14), V(5,14), V(6,13), V(6,12), V(5,11), V(2,11), M(5,11), + V(6,10), V(6,9), V(5,8), V(3,8), V(2,9) }, + { M(0,8), V(3,11), V(6,8) }, + { M(0,10), V(6,10), V(6,7) }, + { M(3,9), V(2,10), V(1,10), V(0,9), V(0,7), V(1,6), V(2,6), V(3,7), M(2,8), V(0,8) }, + { M(0,10), V(6,10), M(4,10), V(4,6), M(2,6), V(2,10) }, + { V(3,9), M(0,11), V(1,11), V(6,6) }, + { M(0,11), V(1,12), V(2,12), V(5,9), V(5,7), V(4,6), V(3,6), V(2,7), V(2,8), V(6,12) }, + { M(2,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7), V(4,9), V(3,10), V(2,10), + V(2,12), V(4,12) }, + { M(0,7), V(1,6), V(2,6), V(3,7), V(3,12), V(4,13), V(5,13), V(6,12) }, + { M(0,9), V(4,9), M(2,11), V(2,7), M(0,7), V(4,7) }, + { M(0,8), V(0,7), V(1,6), V(3,6), V(4,7), V(4,9), V(3,10), V(1,10), V(0,9), V(0,8), + V(4,8), M(2,10), V(2,6) }, + { M(0,10), V(1,9), V(2,9), V(4,11), V(5,11), V(6,10), V(5,9), V(4,9), V(2,11), V(1,11), + V(0,10) }, + { M(4,8), V(3,9), V(1,9), V(0,8), V(0,7), V(1,6), V(3,6), V(4,7), V(4,10), V(2,12), + V(1,12) }, + { M(3,11), V(1,11), V(0,10), V(0,8), V(1,7), V(3,7) }, + { M(0,11), V(2,11), V(3,10), V(3,8), V(2,7), V(0,7) }, + { M(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,7) }, + { M(0,10), V(0,8), V(1,7), V(3,7), V(4,8), V(4,10) }, + { M(0,13), V(0,8), V(2,6), V(4,6), V(6,8), V(6,13), M(0,10), V(6,10) }, + { V(6,6), V(6,14), V(0,14), M(2,10), V(6,10) }, + { V(4,10), M(0,10), V(4,6), M(3,6), V(1,6), V(0,7), V(0,9), V(1,10), V(3,10), V(4,9), + V(4,7), V(3,6) }, + { M(2,8), V(0,10), V(2,12), M(0,10), V(6,10), M(4,12), V(6,10), V(4,8) }, + { M(0,5), V(6,5) }, + { M(0,10), V(6,10), M(3,13), V(6,10), V(3,7) }, + { M(0,12), V(2,14), V(4,12), V(6,14) }, + { V(6,12), M(0,10), V(6,10), M(0,8), V(6,8) }, + { V(3,6), M(3,7), V(0,10), V(3,13) }, + { V(3,6), M(0,7), V(3,10), V(0,13) }, + { M(0,7), V(6,7), M(6,9), V(0,9), M(0,11), V(6,11) }, + { M(0,11), V(3,8), V(6,11) }, + { 0, }, + { M(2,6), V(2,7), M(2,8), V(2,13) }, + { M(2,12), V(2,14), M(4,14), V(4,12) }, + { M(2,7), V(2,13), M(4,13), V(4,7), M(6,9), V(0,9), M(0,11), V(6,11) }, + { M(0,8), V(2,6), V(4,6), V(6,8), V(4,10), V(2,10), V(0,12), V(2,14), V(4,14), V(6,12), + M(4,14), V(4,6), M(2,6), V(2,14) }, + { V(6,12), V(1,12), V(0,11), V(0,10), V(1,9), V(2,9), V(3,10), V(3,11), V(2,12), M(4,9), + V(3,8), V(3,7), V(4,6), V(5,6), V(6,7), V(6,8), V(5,9), V(4,9) }, + { M(6,6), V(1,11), V(1,13), V(2,14), V(3,14), V(4,13), V(0,9), V(0,7), V(1,6), V(3,6), + V(5,8) }, + { M(2,12), V(4,14) }, + { M(2,6), V(0,8), V(0,12), V(2,14) }, + { V(2,8), V(2,12), V(0,14) }, + { M(1,8), V(5,12), M(3,13), V(3,7), M(5,8), V(1,12), M(0,10), V(6,10) }, + { M(2,7), V(2,11), M(0,9), V(4,9) }, + { M(0,7), V(1,6), V(1,5), V(0,4) }, + { M(0,9), V(4,9) }, + { M(2,6), V(3,6), V(3,7), V(2,7), V(2,6) }, + { V(6,12) }, + { M(0,7), V(6,13), M(6,12), V(4,14), V(2,14), V(0,12), V(0,8), V(2,6), V(4,6), V(6,8), + V(6,12) }, + { M(1,12), V(3,14), V(3,6) }, + { M(0,13), V(1,14), V(4,14), V(6,12), V(6,11), V(5,10), V(2,10), V(0,8), V(0,6), V(6,6) }, + { M(0,14), V(6,14), V(6,12), V(4,10), V(5,10), V(6,9), V(6,7), V(5,6), V(0,6) }, + { M(5,6), V(5,14), V(0,9), V(6,9) }, + { M(0,7), V(1,6), V(4,6), V(6,8), V(6,9), V(5,10), V(1,10), V(0,9), V(0,14), V(6,14) }, + { M(0,9), V(1,10), V(5,10), V(6,9), V(6,7), V(5,6), V(1,6), V(0,7), V(0,10), V(4,14) }, + { V(6,12), V(6,14), V(0,14) }, + { M(1,10), V(0,9), V(0,7), V(1,6), V(5,6), V(6,7), V(6,9), V(5,10), V(6,11), V(6,13), + V(5,14), V(1,14), V(0,13), V(0,11), V(1,10), V(5,10) }, + { M(2,6), V(6,10), V(6,13), V(5,14), V(1,14), V(0,13), V(0,11), V(1,10), V(5,10), + V(6,11) }, + { M(2,6), V(3,6), V(3,7), V(2,7), V(2,6), M(2,10), V(3,10), V(3,11), V(2,11), V(2,10) }, + { M(2,7), V(3,6), V(3,5), V(2,4), M(2,10), V(3,10), V(3,11), V(2,11), V(2,10) }, + { M(3,7), V(0,10), V(3,13) }, + { M(0,8), V(6,8), M(6,10), V(0,10) }, + { M(0,7), V(3,10), V(0,13) }, + { M(0,13), V(1,14), V(2,13), V(2,12), V(1,11), V(1,8), M(1,7), V(1,6) }, + { M(1,6), V(0,7), V(0,11), V(1,12), V(5,12), V(6,11), V(6,8), V(5,7), V(4,8), V(4,11), + M(4,10), V(3,11), V(2,11), V(1,10), V(1,9), V(2,8), V(3,8), V(4,9) }, + { V(0,12), V(2,14), V(4,14), V(6,12), V(6,9), V(0,9), V(6,9), V(6,6) }, + { V(0,14), V(5,14), V(6,13), V(6,11), V(5,10), V(0,10), V(5,10), V(6,9), V(6,7), V(5,6), + V(0,6) }, + { M(6,13), V(5,14), V(2,14), V(0,12), V(0,8), V(2,6), V(5,6), V(6,7) }, + { V(0,14), V(4,14), V(6,12), V(6,8), V(4,6), V(0,6) }, + { M(6,6), V(0,6), V(0,10), V(4,10), V(0,10), V(0,14), V(6,14) }, + { V(0,10), V(4,10), V(0,10), V(0,14), V(6,14) }, + { M(6,13), V(5,14), V(2,14), V(0,12), V(0,8), V(2,6), V(4,6), V(6,8), V(6,10), V(4,10) }, + { V(0,14), V(0,10), V(6,10), V(6,14), V(6,6) }, + { M(1,6), V(5,6), V(3,6), V(3,14), V(1,14), V(5,14) }, + { M(1,9), V(1,7), V(2,6), V(3,6), V(4,7), V(4,14), V(2,14), V(6,14) }, + { V(0,14), V(0,8), V(6,14), V(2,10), V(6,6) }, + { M(0,14), V(0,6), V(6,6) }, + { V(0,14), V(3,11), V(6,14), V(6,6) }, + { V(0,14), V(0,13), V(6,7), V(6,6), V(6,14) }, + { M(0,8), V(0,12), V(2,14), V(4,14), V(6,12), V(6,8), V(4,6), V(2,6), V(0,8) }, + { V(0,14), V(5,14), V(6,13), V(6,11), V(5,10), V(0,10) }, + { M(0,8), V(0,12), V(2,14), V(4,14), V(6,12), V(6,8), V(4,6), V(2,6), V(0,8), M(3,9), + V(6,6) }, + { V(0,14), V(5,14), V(6,13), V(6,11), V(5,10), V(0,10), V(2,10), V(6,6) }, + { M(0,8), V(2,6), V(4,6), V(6,8), V(4,10), V(2,10), V(0,12), V(2,14), V(4,14), V(6,12) }, + { M(3,6), V(3,14), V(0,14), V(6,14) }, + { M(0,14), V(0,7), V(1,6), V(5,6), V(6,7), V(6,14) }, + { M(0,14), V(0,9), V(3,6), V(6,9), V(6,14) }, + { M(0,14), V(0,6), V(3,9), V(6,6), V(6,14) }, + { V(0,7), V(6,13), V(6,14), M(0,14), V(0,13), V(6,7), V(6,6) }, + { M(0,14), V(3,11), V(6,14), V(3,11), V(3,6) }, + { M(0,14), V(6,14), V(6,13), V(0,7), V(0,6), V(6,6) }, + { M(3,5), V(0,5), V(0,15), V(3,15) }, + { M(0,12), V(6,6) }, + { M(0,5), V(3,5), V(3,15), V(0,15) }, + { M(0,11), V(3,14), V(6,11), M(3,14), V(3,6) }, + { M(3,7), V(0,10), V(3,13), M(0,10), V(6,10) }, + { M(2,14), V(4,12) }, + { M(0,9), V(1,10), V(3,10), V(4,9), V(4,6), M(4,8), V(3,9), V(1,9), V(0,8), V(0,7), + V(1,6), V(3,6), V(4,7) }, + { V(0,13), M(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6), V(0,7) }, + { M(4,9), V(3,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7) }, + { M(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6), V(0,7), M(4,6), + V(4,13) }, + { M(4,7), V(3,6), V(1,6), V(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,8), V(0,8) }, + { M(2,6), V(2,12), V(3,13), V(4,13), V(5,12), M(0,11), V(4,11) }, + { M(4,9), V(3,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7), M(4,10), V(4,5), + V(3,4), V(1,4), V(0,5) }, + { V(0,13), M(0,9), V(1,10), V(3,10), V(4,9), V(4,6) }, + { M(3,12), V(3,11), M(3,10), V(3,7), V(4,6), V(5,6) }, + { M(3,12), V(3,11), M(3,10), V(3,5), V(2,4), V(1,3) }, + { V(0,13), M(0,8), V(2,10), M(0,8), V(2,6) }, + { M(2,6), V(2,13) }, + { V(0,10), M(0,9), V(1,10), V(2,10), V(3,9), V(3,6), M(3,9), V(4,10), V(5,10), V(6,9), + V(6,6) }, + { V(0,10), M(0,9), V(1,10), V(2,10), V(3,9), V(3,6) }, + { M(0,7), V(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6), V(0,7) }, + { M(0,4), V(0,10), M(0,9), V(1,10), V(3,10), V(4,9), V(4,7), V(3,6), V(1,6), V(0,7) }, + { M(4,9), V(3,10), V(1,10), V(0,9), V(0,7), V(1,6), V(3,6), V(4,7), M(4,10), V(4,4) }, + { V(0,10), M(0,9), V(1,10), V(3,10), V(4,9) }, + { M(0,7), V(1,6), V(3,6), V(4,7), V(3,8), V(1,8), V(0,9), V(1,10), V(3,10), V(4,9) }, + { M(2,13), V(2,7), V(3,6), V(4,6), V(5,7), M(1,11), V(3,11) }, + { M(0,10), V(0,7), V(1,6), V(3,6), V(4,7), V(4,10), V(4,6) }, + { M(0,9), V(3,6), V(6,9) }, + { M(0,10), V(0,6), V(2,8), V(4,6), V(4,10) }, + { V(4,10), M(0,10), V(4,6) }, + { M(0,9), V(3,6), M(6,9), V(1,4), V(0,4) }, + { M(0,10), V(4,10), V(0,6), V(4,6) }, + { M(3,15), V(2,14), V(2,12), V(0,10), V(2,8), V(2,6), V(3,5) }, + { M(2,4), V(2,14) }, + { M(3,6), V(0,9), V(3,12), V(6,9), V(3,6) }, + { M(0,15), V(1,14), V(1,12), V(3,10), V(1,8), V(1,6), V(0,5) }, + { M(0,12), V(6,6) }, +}; + +uint64 iii_instr; /* Currently executing instruction */ +int iii_sel; /* Select mask */ + +t_stat iii_devio(uint32 dev, uint64 *data); +t_stat iii_svc(UNIT *uptr); +static void draw_point(int x, int y, int b); +static void draw_line(int x1, int y1, int x2, int y2, int b); +t_stat iii_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *iii_description (DEVICE *dptr); + +DIB iii_dib = { III_DEVNUM, 1, iii_devio, NULL}; + +UNIT iii_unit[] = { + {UDATA (&iii_svc, UNIT_IDLE, 0) }, + { 0 } + }; + + +MTAB iii_mod[] = { + { 0 } + }; + +DEVICE iii_dev = { + "III", iii_unit, NULL, iii_mod, + 2, 10, 31, 1, 8, 8, + NULL, NULL, NULL, + NULL, NULL, NULL, &iii_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS, 0, dev_debug, + NULL, NULL, &iii_help, NULL, NULL, &iii_description + }; + +int status; +t_stat iii_devio(uint32 dev, uint64 *data) { + UNIT *uptr = &iii_unit[0]; + switch(dev & 3) { + case CONI: + *data = (((uint64)iii_sel) << 18) | (uint64)(uptr->PIA); + if ((iii_instr & 037) == 0) + *data |= INST_HLT; + *data |= (uptr->STATUS & 07) << 4; + if (uptr->STATUS & NXM_FLG) + *data |= NXM_BIT; + if (uptr->STATUS & DATA_FLG) + *data |= DATAO_LK; + if ((uptr->STATUS & RUN_FLG) == 0) + *data |= HLT_FLG; + if (uptr->STATUS & WRP_FBIT) + *data |= WRAP_FLG; + if (uptr->STATUS & EDG_FBIT) + *data |= EDGE_FLG; + if (uptr->STATUS & LIT_FBIT) + *data |= LIGHT_FLG; + sim_debug(DEBUG_CONI, &iii_dev, "III %03o CONI %06o\n", dev, (uint32)*data); + break; + case CONO: + if (*data & SET_PIA) + uptr->PIA = (int)(*data&PIA_MSK); + if (*data & F) + uptr->STATUS &= ~(WRP_FBIT|EDG_FBIT|LIT_FBIT|DATA_FLG|NXM_FLG); + uptr->STATUS &= ~(017 & ((*data >> 14) ^ (*data >> 10))); + uptr->STATUS ^= (017 & (*data >> 10)); + if (*data & STOP) + uptr->STATUS |= RUN_FLG; + if (*data & CONT) { + uptr->STATUS &= ~RUN_FLG; + iii_instr = M[uptr->MAR]; + sim_activate(uptr, 10); + } + sim_debug(DEBUG_CONO, &iii_dev, "III %03o CONO %06o\n", dev, (uint32)*data); + break; + case DATAI: + sim_debug(DEBUG_DATAIO, &iii_dev, "III %03o DATAI %06o\n", dev, (uint32)*data); + break; + case DATAO: + if (uptr->STATUS & RUN_FLG) + uptr->STATUS |= DATA_FLG; + else { + iii_instr = *data; + sim_activate(uptr, 10); + } + sim_debug(DEBUG_DATAIO, &iii_dev, "III %03o DATAO %06o\n", dev, (uint32)*data); + break; + } + return SCPE_OK; +} + +t_stat +iii_svc (UNIT *uptr) +{ + uint64 temp; + int A; + int ox, oy, nx, ny, br, sz; + int i, j, ch; + switch(iii_instr & 017) { + case 000: /* JMP and HLT */ + if (iii_instr & 020) { + uptr->MAR = (iii_instr >> 18) & RMASK; + } else { + uptr->STATUS &= ~RUN_FLG; + } + break; + case 001: + case 003: + case 005: + case 007: + case 011: + case 013: + case 015: + case 017: /* Draw 4 characters */ + /* Extract X,Y,Bright and Size */ + sz = (uptr->POS & CSIZE) >> CSIZE_V; + br = (uptr->POS & CBRT) >> CBRT_V; + ox = (uptr->POS & POS_X) >> POS_X_V; + oy = (uptr->POS & POS_Y) >> POS_Y_V; + for (i = 29; i >= 1; i -= 7) { + /* Extract character and compute initial point */ + int cx, cy; + uint8 v; + ch = (iii_instr >> i) & 0177; + cx = ox; + cy = oy + (6 * sz); + /* Scan map and draw lines as needed */ + for(j = 0; j < 18; j++) { + v = map[i][j]; + if (v == 0) + break; + nx = cx + (((v >> 4) & 07) * sz); + ny = cy + ((v & 017) * sz); + if (v & 0200) + draw_line(cx, cy, nx, ny, br); + cx = nx; + cy = ny; + } + ox += 8 * sz; + } + /* Repack to new position. */ + uptr->POS = (POS_X & (nx << POS_X_V)) | + (POS_Y & (ny << POS_Y_V)) | + (uptr->POS & (CBRT|CSIZE)); + break; + + case 002: /* Short Vector */ + /* Extract X,Y,Bright and Size */ + sz = (uptr->POS & CSIZE) >> CSIZE_V; + br = (uptr->POS & CBRT) >> CBRT_V; + ox = (uptr->POS & POS_X) >> POS_X_V; + oy = (uptr->POS & POS_Y) >> POS_Y_V; + /* Do first point */ + nx = (iii_instr >> 29) & 077; + ny = (iii_instr >> 22) & 077; + /* Sign extend */ + if (nx & 0100) + nx |= 03700; + if (ny & 0100) + ny |= 03700; + /* Compute relative position. */ + nx += ox; + ny += oy; + if ((iii_instr & 010000000LL) == 0) { /* Check if visible */ + if ((iii_instr & 004000000LL) == 0) { /* Draw a line */ + draw_line(ox, oy, nx, ny, br); + } else { + draw_point(nx, ny, br); + } + } + /* Do second point */ + nx = (iii_instr >> 13) & 0177; + ny = (iii_instr >> 6) & 0177; + /* Sign extend */ + if (nx & 0100) + nx |= 03700; + if (ny & 0100) + ny |= 03700; + /* Compute relative position. */ + nx += ox; + ny += oy; + if ((iii_instr & 040) == 0) { /* Check if visible */ + if ((iii_instr & 020) == 0) { /* Draw a line */ + draw_line(ox, oy, nx, ny, br); + } else { + draw_point(nx, ny, br); + } + } + /* Repack to new position. */ + uptr->POS = (POS_X & (nx << POS_X_V)) | + (POS_Y & (ny << POS_Y_V)) | + (uptr->POS & (CBRT|CSIZE)); + break; + + case 004: /* JSR, JMS, SAVE */ + temp = (((uint64)uptr->MAR) << 18) | 020 /* | CPC */; + A = (iii_instr >> 18) & RMASK; + if ((iii_instr & 030) != 030) { + M[A] = temp; + A++; + } + if ((iii_instr & 020) != 020) { + temp = uptr->STATUS & 0377; + temp |= ((uint64)uptr->POS) << 8; + M[A] = temp; + A++; + } + if ((iii_instr & 030) != 030) { + uptr->MAR = A; + } + break; + + case 006: /* Long Vector */ + /* Extract X,Y,Bright and Size */ + sz = (uptr->POS & CSIZE) >> CSIZE_V; + br = (uptr->POS & CBRT) >> CBRT_V; + ox = (uptr->POS & POS_X) >> POS_X_V; + oy = (uptr->POS & POS_Y) >> POS_Y_V; + /* Update sizes if needed */ + if (((iii_instr >> 9) & CSIZE) != 0) + sz = (iii_instr >> 9) & CSIZE; + if (((iii_instr >> 12) & 7) != 0) + br = (iii_instr > 12) & 7; + nx = (iii_instr >> 25) & 03777; + ny = (iii_instr >> 15) & 03777; + if ((iii_instr & 0100) == 0) { /* Relative mode */ + nx += ox; + ny += oy; + } + if ((iii_instr & 040) == 0) { /* Check if visible */ + if ((iii_instr & 020) == 0) /* Draw a line */ + draw_line(ox, oy, nx, ny, br); + else + draw_point(nx, ny, br); + } + /* Repack to new position. */ + uptr->POS = (POS_X & (nx << POS_X_V)) | + (POS_Y & (ny << POS_Y_V)) | + (CBRT & (br << CBRT_V)) | + (CSIZE & (sz << CSIZE_V)); + break; + + case 010: /* Select instruction */ + break; + + case 012: /* Test instruction */ + A = (uptr->STATUS & (int32)(iii_instr >> 12) & 0377) != 0; + uptr->STATUS &= ~(0377 & ((iii_instr >> 28) ^ (iii_instr >> 20))); + uptr->STATUS ^= (0377 & (iii_instr >> 20)); + if (A ^ ((iii_instr & 020) != 0)) + uptr->MAR++; + break; + + case 014: /* Restore */ + A = (iii_instr >> 18) & RMASK; + temp = M[A]; + if ((iii_instr & 020) != 0) { + uptr->STATUS &= ~0377; + uptr->STATUS |= temp & 0377; + } + if ((iii_instr & 040) != 0) { + uptr->POS = (temp >> 8) & (POS_X|POS_Y|CBRT|CSIZE); + } + break; + + case 016: /* Nop */ + break; + } + if (uptr->STATUS & RUN_FLG) { + iii_instr = M[uptr->MAR]; + uptr->MAR++; + uptr->MAR &= RMASK; + sim_activate(uptr, 10); + } + return SCPE_OK; +} + + +/* Draw a point at x,y with intensity b. */ +/* X and Y runs from -512 to 512. */ +static void +draw_point(int x, int y, int b) +{ + display_point(x, y, b, 0); +} + +/* Draw a line between two points */ +static void +draw_line(int x1, int y1, int x2, int y2, int b) +{ + int dx, px; + int dy, py; + int i, p; + int minx, miny; + int maxx, maxy; + + dx = x1 - x2; + dy = y1 - y2; + if (x1 < 0) { + dx = -1; + px = -x1; + } else if (x1 > 0) { + dx = 1; + px = x1; + } else { + dx = 0; + px = 0; + } + + if (y1 < 0) { + dy = -1; + py = -y1; + } else if (y1 > 0) { + dy = 1; + py = y1; + } else { + dy = 0; + py = 0; + } + + if (dx == 0) { + /* Vertical line */ + for (i = 1; i < py; i++) { + dy += dy; + draw_point(dx, dy, b); + } + } else if (dy == 0) { + /* Horizontal line */ + for (i = 1; i < px; i++) { + dx += dx; + draw_point(dx, dy, b); + } + } else if (py > px) { + /* More horizontal */ + p = 2 * px - py; + for (i = 1; i < py; i++) { + if (p > 0) { + dx += dx; + p += (2 * px) - (2 * py); + } else { + p += 2 * px; + } + dy += dy; + draw_point(dx, dy, b); + } + } else { + /* More vertical */ + p = 2 * py - px; + for (i = 1; i < px; i++) { + if (p > 0) { + dy += dy; + p += (2 * py) - (2 * px); + } else { + p += 2 * py; + } + dx += dx; + draw_point(dx, dy, b); + } + } +} + +t_stat iii_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +return SCPE_OK; +} + +const char *iii_description (DEVICE *dptr) +{ + return "Triple III Display"; +} +#endif diff --git a/PDP10/ka10_pmp.c b/PDP10/ka10_pmp.c index ea3e69b..66839a4 100644 --- a/PDP10/ka10_pmp.c +++ b/PDP10/ka10_pmp.c @@ -142,7 +142,7 @@ #define DK_MSK_SKNONE 0x18 /* Allow no seeks */ #define DK_MSK_SK 0x18 /* Seek mask */ -#define POS u4 +#define POS u4 /* u4 */ /* Holds the current track and head */ #define DK_V_TRACK 8 @@ -348,9 +348,9 @@ uint64 pmp_status; /* CONI status for device 500 */ int pmp_statusb; uint32 pmp_cmd_hold; /* Command hold register */ uint32 pmp_wc_hold; /* Word count hold */ -uint32 pmp_addr_hold; /* Address register hold */ +t_addr pmp_addr_hold; /* Address register hold */ uint32 pmp_wc; /* Current word count register */ -uint32 pmp_addr; /* Current address register */ +t_addr pmp_addr; /* Current address register */ uint64 pmp_data; /* Data assembly register */ int pmp_cnt; /* Character count in asm register */ int pmp_cmd; /* Current command */ @@ -382,7 +382,7 @@ t_stat pmp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); const char *pmp_description (DEVICE *dptr); -DIB pmp_dib[] = { +DIB pmp_dib[] = { {PMP_DEV, 2, &pmp_devio, NULL}}; @@ -433,13 +433,13 @@ pmp_devio(uint32 dev, uint64 *data) { if ((pmp_statusb & (WCMA_LD|CMD_LD)) != (WCMA_LD|CMD_LD)) *data |= HOLD_EMPTY; if (pmp_cur_unit != NULL) - *data |= ((uint64)GET_UADDR(pmp_cur_unit->flags)) << 24; + *data |= ((uint64)GET_UADDR(pmp_cur_unit->flags)) << 24; if ((pmp_status & (NXM_ERR|CHA_ERR|SEL_ERR)) != 0) *data |= UNU_END; sim_debug(DEBUG_CONI, &pmp_dev, "PMP %03o CONI %012llo PC=%o\n", dev, *data, PC); break; - + case CONO: sim_debug(DEBUG_CONO, &pmp_dev, "PMP %03o CONO %012llo PC=%06o\n", dev, *data, PC); @@ -597,9 +597,8 @@ chan_read_byte(uint8 *data) { pmp_statusb |= TRANS_CH; /* Tranfer in progress */ /* Read in next work if buffer is in empty status */ if (pmp_cnt & BUFF_EMPTY) { - if (pmp_addr >= (int)MEMSIZE) + if (Mem_read_word(pmp_addr, &pmp_data, 0)) return pmp_posterror(NXM_ERR); - pmp_data = M[pmp_addr]; sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_read %06o %012llo\n", pmp_addr, pmp_data); pmp_addr++; pmp_cnt = 0; @@ -616,10 +615,9 @@ chan_read_byte(uint8 *data) { if ((pmp_cnt & 0xf) > 0x3) { if ((pmp_cnt & 0xf) == 0x4) { /* Split byte */ byte = (pmp_data << 4) & 0xf0; - if (pmp_addr >= (int)MEMSIZE) + if (Mem_read_word(pmp_addr, &pmp_data, 0)) return pmp_posterror(NXM_ERR); - pmp_data = M[pmp_addr]; - sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_read %06o %012llo\n", pmp_addr, pmp_data); + sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_read %06o %012llo\n", pmp_addr, pmp_data); pmp_addr++; xfer = 1; /* Read in a word */ byte |= pmp_data & 0xf; @@ -639,7 +637,7 @@ chan_read_byte(uint8 *data) { } else if (xfer) { pmp_wc ++; } - if (pmp_wc & 07000000) + if (pmp_wc & 07000000) pmp_cnt |= BUFF_CHNEND; return 0; #if 0 @@ -693,11 +691,10 @@ chan_write_byte(uint8 *data) { pmp_cnt |= BUFF_DIRTY; if ((pmp_cnt & 03) == 0) { pmp_cnt &= ~(BUFF_DIRTY|7); - if (pmp_addr >= (int)MEMSIZE) + if (Mem_write_word(pmp_addr, &pmp_data, 0)) return pmp_posterror(NXM_ERR); - M[pmp_addr] = pmp_data; - sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo\n", pmp_addr, pmp_data); - pmp_addr++; + sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo\n", pmp_addr, pmp_data); + pmp_addr++; xfer = 1; } } else { @@ -705,9 +702,8 @@ chan_write_byte(uint8 *data) { if ((pmp_cnt & 0xf) == 0x4) { /* Split byte */ pmp_data &= ~0xf; pmp_data |= (uint64)((*data >> 4) & 0xf); - if (pmp_addr >= (int)MEMSIZE) + if (Mem_write_word(pmp_addr, &pmp_data, 0)) return pmp_posterror(NXM_ERR); - M[pmp_addr] = pmp_data; sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo %2x\n", pmp_addr, pmp_data, pmp_cnt); pmp_addr++; xfer = 1; /* Read in a word */ @@ -726,9 +722,8 @@ chan_write_byte(uint8 *data) { pmp_cnt++; if ((pmp_cnt & 0xf) == 9) { pmp_cnt = BUFF_EMPTY; - if (pmp_addr >= (int)MEMSIZE) + if (Mem_write_word(pmp_addr, &pmp_data, 0)) return pmp_posterror(NXM_ERR); - M[pmp_addr] = pmp_data; sim_debug(DEBUG_DETAIL, &pmp_dev, "chan_write %06o %012llo %2x\n", pmp_addr, pmp_data, pmp_cnt); pmp_addr++; xfer = 1; /* Read in a word */ @@ -774,16 +769,15 @@ chan_end(uint8 flags) { /* Flush buffer if there was any change */ if (pmp_cnt & BUFF_DIRTY) { pmp_cnt = BUFF_EMPTY; - if (pmp_addr >= (int)MEMSIZE) { + if (Mem_write_word(pmp_addr, &pmp_data, 0)) { (void) pmp_posterror(NXM_ERR); return; } - M[pmp_addr] = pmp_data; sim_debug(DEBUG_DATA, &pmp_dev, "chan_write %012llo\n", pmp_data); pmp_addr++; } pmp_statusb &= ~TRANS_CH; /* Clear transfer in progress */ - pmp_statusb |= IDLE_CH; + pmp_statusb |= IDLE_CH; pmp_status |= NEW_STS | CHN_END | ((uint64)flags) << 5; if (pmp_status & (BSY|UNIT_CHK)) @@ -798,7 +792,7 @@ chan_end(uint8 flags) { if (pmp_cmd & DATCH_ON) { (void) pmp_posterror(CHA_ERR); return; - } + } if (pmp_cmd & CMDCH_ON) { pmp_startcmd(); diff --git a/PDP10/ka10_ten11.c b/PDP10/ka10_ten11.c index 1ff255b..df87ab9 100644 --- a/PDP10/ka10_ten11.c +++ b/PDP10/ka10_ten11.c @@ -239,7 +239,7 @@ static int transaction (unsigned char *request, unsigned char *response) return 0; } -static int read_word (int addr, int *data) +static int read_word (t_addr addr, int *data) { unsigned char request[8]; unsigned char response[8]; @@ -285,7 +285,7 @@ static int read_word (int addr, int *data) return 0; } -int ten11_read (int addr, uint64 *data) +int ten11_read (t_addr addr, uint64 *data) { int offset = addr & 01777; int word1, word2; @@ -328,7 +328,7 @@ int ten11_read (int addr, uint64 *data) return 0; } -static int write_word (int addr, uint16 data) +static int write_word (t_addr addr, uint16 data) { unsigned char request[8]; unsigned char response[8]; @@ -366,7 +366,7 @@ static int write_word (int addr, uint16 data) return 0; } -int ten11_write (int addr, uint64 data) +int ten11_write (t_addr addr, uint64 data) { int offset = addr & 01777; diff --git a/PDP10/kl10_fe.c b/PDP10/kl10_fe.c new file mode 100644 index 0000000..9a3c2b4 --- /dev/null +++ b/PDP10/kl10_fe.c @@ -0,0 +1,2463 @@ +/* kl10_fe.c: KL-10 front end (console terminal) simulator + + Copyright (c) 2013-2019, 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 "kx10_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +#if KL +#define UNIT_DUMMY (1 << UNIT_V_UF) + +#define DTE_DEVNUM 0200 +#define DEV_V_OS (DEV_V_UF + 1) /* Type RSX10/RSX20 */ +#define DEV_M_OS (1 << DEV_V_OS) +#define TYPE_RSX10 (0 << DEV_V_OS) +#define TYPE_RSX20 (1 << DEV_V_OS) + + + +/* DTE10 CONI bits */ + +#define DTE_RM 00100000 /* Restricted mode */ +#define DTE_D11 00040000 /* Dead-11 */ +#define DTE_11DB 00020000 /* TO11 Door bell request */ +#define DTE_10DB 00001000 /* TO10 Door bell request */ +#define DTE_11ER 00000400 /* Error during TO11 transfer */ +#define DTE_11DN 00000100 /* TO 11 transfer done */ +#define DTE_10DN 00000040 /* TO 10 transfer done */ +#define DTE_10ER 00000020 /* Error during TO10 transfer */ +#define DTE_PIE 00000010 /* PIO enabled */ +#define DTE_PIA 00000007 /* PI channel assigment */ + +/* internal flags */ +#define DTE_11RELD 01000000 /* Reload 11. */ +#define DTE_TO11 02000000 /* Transfer to 11 */ +#define DTE_SEC 04000000 /* In secondary protocol */ +#define DTE_IND 010000000 /* Next transfer will be indirect */ +#define DTE_SIND 020000000 /* Send indirect data next */ + +/* DTE CONO bits */ +#define DTE_CO11DB 0020000 /* Set TO11 Door bell */ +#define DTE_CO11CR 0010000 /* Clear reload 11 button */ +#define DTE_CO11SR 0004000 /* Set reload 11 button */ +#define DTE_CO10DB 0001000 /* Clear TO10 Door bell */ +#define DTE_CO11CL 0000100 /* Clear TO11 done and error */ +#define DTE_CO10CL 0000040 /* Clear TO10 done and error */ +#define DTE_PIENB 0000020 /* Load PI and enable bit */ + +/* DTE DATAO */ +#define DTE_TO10IB 010000 /* Interrupt after transfer */ +#define DTE_TO10BC 007777 /* Byte count for transfer */ + +/* Secondary protocol addresses */ +#define SEC_DTFLG 0444 /* Operation complete flag */ +#define SEC_DTCLK 0445 /* Clock interrupt flag */ +#define SEC_DTCI 0446 /* Clock interrupt instruction */ +#define SEC_DTT11 0447 /* 10 to 11 argument */ +#define SEC_DTF11 0450 /* 10 from 11 argument */ +#define SEC_DTCMD 0451 /* To 11 command word */ +#define SEC_DTSEQ 0452 /* Operation sequence number */ +#define SEC_DTOPR 0453 /* Operational DTE # */ +#define SEC_DTCHR 0454 /* Last typed character */ +#define SEC_DTMTD 0455 /* Monitor tty output complete flag */ +#define SEC_DTMTI 0456 /* Monitor tty input flag */ +#define SEC_DTSWR 0457 /* 10 switch register */ + +#define SEC_PGMCTL 00400 +#define SEC_ENDPASS 00404 +#define SEC_LOOKUP 00406 +#define SEC_RDWRD 00407 +#define SEC_RDBYT 00414 +#define SEC_ESEC 00440 +#define SEC_EPRI 00500 +#define SEC_ERTM 00540 +#define SEC_CLKCTL 01000 +#define SEC_CLKOFF 01000 +#define SEC_CLKON 01001 +#define SEC_CLKWT 01002 +#define SEC_CLKRD 01003 +#define SEC_RDSW 01400 +#define SEC_CLRDDT 03000 +#define SEC_SETDDT 03400 +#define SEC_MONO 04000 +#define SEC_MONON 04400 +#define SEC_SETPRI 05000 +#define SEC_RTM 05400 +#define SEC_CMDMSK 07400 +#define DTE_MON 00000001 /* Save in unit1 STATUS */ +#define SEC_CLK 00000002 /* Clock enabled */ +#define ITS_ON 00000004 /* ITS Is alive */ + +/* Primary or Queued protocol addresses */ +#define PRI_CMTW_0 0 +#define PRI_CMTW_PPT 1 /* Pointer to com region */ +#define PRI_CMTW_STS 2 /* Status word */ +#define PRI_CMT_PWF SMASK /* Power failure */ +#define PRI_CMT_L11 BIT1 /* Load 11 */ +#define PRI_CMT_INI BIT2 /* Init */ +#define PRI_CMT_TST BIT3 /* Valid examine bit */ +#define PRI_CMT_QP 020000000LL /* Do Queued protocol */ +#define PRI_CMT_FWD 001000000LL /* Do full word transfers */ +#define PRI_CMT_IP RSIGN /* Indirect transfer */ +#define PRI_CMT_TOT 0200000LL /* TOIT bit */ +#define PRI_CMT_10IC 0177400LL /* TO10 IC for queued transfers */ +#define PRI_CMT_11IC 0000377LL /* TO11 IC for queued transfers */ +#define PRI_CMTW_CNT 3 /* Queue Count */ +#define PRI_CMTW_KAC 5 /* Keep alive count */ +#define PRI_IND_FLG 0100000 /* Flag function as indirect */ + +#define PRI_EM2EI 001 /* Initial message to 11 */ +#define PRI_EM2TI 002 /* Replay to initial message. */ +#define PRI_EMSTR 003 /* String data */ +#define PRI_EMLNC 004 /* Line-Char */ +#define PRI_EMRDS 005 /* Request device status */ +#define PRI_EMOPS 006 +#define PRI_EMHDS 007 /* Here is device status */ +#define PRI_EMRDT 011 /* Request Date/Time */ +#define PRI_EMHDR 012 /* Here is date and time */ +#define PRI_EMFLO 013 /* Flush output */ +#define PRI_EMSNA 014 /* Send all (ttys) */ +#define PRI_EMDSC 015 /* Dataset connect */ +#define PRI_EMHUD 016 /* Hang up dataset */ +#define PRI_EMLBE 017 /* Acknowledge line */ +#define PRI_EMXOF 020 /* XOFF line */ +#define PRI_EMXON 021 /* XON line */ +#define PRI_EMHLS 022 /* Here is line speeds */ +#define PRI_EMHLA 023 /* Here is line allocation */ +#define PRI_EMRBI 024 /* Reboot information */ +#define PRI_EMAKA 025 /* Ack ALL */ +#define PRI_EMTDO 026 /* Turn device On/Off */ +#define PRI_EMEDR 027 /* Enable/Disable line */ +#define PRI_EMLDR 030 /* Load LP RAM */ +#define PRI_EMLDV 031 /* Load LP VFU */ + +#define PRI_EMCTY 001 /* Device code for CTY */ +#define PRI_EMDL1 002 /* DL11 */ +#define PRI_EMDH1 003 /* DH11 #1 */ +#define PRI_EMDLS 004 /* DLS (all ttys combined) */ +#define PRI_EMLPT 005 /* Front end LPT */ +#define PRI_EMCDR 006 /* CDR */ +#define PRI_EMCLK 007 /* Clock */ +#define PRI_EMFED 010 /* Front end device */ +#define PRI_CTYDV 000 /* Line number for CTY */ +#define NUM_DLS 5 /* Number of first DH Line */ + +#if KL_ITS +/* ITS Timesharing protocol locations */ +#define ITS_DTEVER 0400 /* Protocol version and number of devices */ +#define ITS_DTECHK 0401 /* Increment at 60Hz. Ten setom 2 times per second */ +#define ITS_DTEINP 0402 /* Input from 10 to 11. Line #, Count */ +#define ITS_DTEOUT 0403 /* Output from 10 to 11 Line #, Count */ +#define ITS_DTELSP 0404 /* Line # to set speed of */ +#define ITS_DTELPR 0405 /* Parameter */ +#define ITS_DTEOST 0406 /* Line # to start output on */ +#define ITS_DTETYI 0410 /* Received char (Line #, char) */ +#define ITS_DTEODN 0411 /* Output done (Line #, buffer size) */ +#define ITS_DTEHNG 0412 /* Hangup/dialup */ +#endif + +#define TMR_RTC 2 + +extern int32 tmxr_poll; +t_stat dte_devio(uint32 dev, uint64 *data); +t_addr dte_devirq(uint32 dev, t_addr addr); +void dte_second(UNIT *uptr); +void dte_primary(UNIT *uptr); +#if KL_ITS +void dte_its(UNIT *uptr); +#endif +void dte_transfer(UNIT *uptr); +void dte_function(UNIT *uptr); +void dte_input(); +int dte_start(UNIT *uptr); +int dte_queue(int func, int dev, int dcnt, uint16 *data); +t_stat dtei_svc (UNIT *uptr); +t_stat dte_svc (UNIT *uptr); +t_stat dteo_svc (UNIT *uptr); +t_stat dtertc_srv(UNIT * uptr); +t_stat dte_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat dte_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat dte_reset (DEVICE *dptr); +t_stat dte_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat dte_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *dte_description (DEVICE *dptr); +extern uint64 SW; /* Switch register */ + +CONST char *pri_name[] = { "(0)", "EM2EI", "EM2TI", "EMSTR", "EMLNC", "EMRDS", "(6)", + "EMHDS", "(10)", "EMRDT", "EMHDR", "EMFLO", "EMSNA", "EMDSC", "EMHUD", + "EMLBE", "EMXOF", "EMXON", "EMHLS", "EMHLA", "EMRBI", "EMAKA", "EMTDO", + "EMEDR", "EMLDR", "EMLDV" }; + +#if KL_ITS +#define QITS (cpu_unit[0].flags & UNIT_ITSPAGE) +#else +#define QITS 0 +#endif + +#define STATUS u3 +#define CNT u4 + +extern uint32 eb_ptr; +static int32 rtc_tps = 60; +uint16 rtc_tick; +uint16 rtc_wait = 0; + +struct _dte_queue { + int dptr; /* Pointer to working item */ + uint16 cnt; /* Number of bytes in packet */ + uint16 func; /* Function code */ + uint16 dev; /* Dev code */ + uint16 spare; /* Dev code */ + uint16 dcnt; /* Data count */ + uint16 data[258]; /* Data packet */ + uint16 sdev; /* Secondary device code */ + uint16 sz; /* Byte size */ +} dte_in[32], dte_out[32]; + +int dte_in_ptr; +int dte_in_cmd; +int dte_out_ptr; +int dte_out_res; +int dte_base; /* Base */ +int dte_off; /* Our offset */ +int dte_dt10_off; /* Offset to 10 deposit region */ +int dte_et10_off; /* Offset to 10 examine region */ +int dte_et11_off; /* Offset to 11 examine region */ +int dte_proc_num; /* Our processor number */ + +struct _buffer { + int in_ptr; /* Insert pointer */ + int out_ptr; /* Remove pointer */ + char buff[256]; /* Buffer */ +} cty_in, cty_out; +int cty_done; + +#define full(q) ((((q)->in_ptr + 1) & 0xff) == (q)->out_ptr) +#define empty(q) ((q)->in_ptr == (q)->out_ptr) +#define not_empty(q) ((q)->in_ptr != (q)->out_ptr) +#define inco(q) (q)->out_ptr = ((q)->out_ptr + 1) & 0xff +#define inci(q) (q)->in_ptr = ((q)->in_ptr + 1) & 0xff + +DIB dte_dib[] = { + { DTE_DEVNUM|000, 1, dte_devio, dte_devirq}, +}; + +MTAB dte_mod[] = { + { UNIT_DUMMY, 0, NULL, "STOP", &dte_stop_os }, + { 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, "7p", "7P", &tty_set_mode }, + {MTAB_XTD|MTAB_VDV, TYPE_RSX10, NULL, "RSX10", &dte_set_type, NULL, + NULL, "Sets DTE to RSX10 mode"}, + {MTAB_XTD|MTAB_VDV, TYPE_RSX20, "RSX20", "RSX20", &dte_set_type, &dte_show_type, + NULL, "Sets DTE to RSX20 mode"}, + { 0 } + }; + +UNIT dte_unit[] = { + { UDATA (&dte_svc, TT_MODE_7B, 0), 100}, + { UDATA (&dteo_svc, TT_MODE_7B, 0), 100}, + { UDATA (&dtei_svc, TT_MODE_7B|UNIT_DIS, 0), 1000 }, + { UDATA (&dtertc_srv, UNIT_IDLE|UNIT_DIS, 0), 1000 } + }; + + +DEVICE dte_dev = { + "CTY", dte_unit, NULL, dte_mod, + 4, 10, 31, 1, 8, 8, + NULL, NULL, &dte_reset, + NULL, NULL, NULL, &dte_dib, DEV_DEBUG, 0, dev_debug, + NULL, NULL, &dte_help, NULL, NULL, &dte_description + }; + + + +#ifndef NUM_DEVS_LP20 +#define NUM_DEVS_LP20 0 +#endif + +#if (NUM_DEVS_LP20 > 0) + +#define COL u4 +#define POS u5 +#define LINE u6 +#define LPST us9 +#define LPCNT us10 + +#define EOFFLG 001 /* Tops 20 wants EOF */ +#define HDSFLG 002 /* Tell Tops 20 The current device status */ +#define ACKFLG 004 /* Post an acknowwledge message */ +#define INTFLG 010 /* Send interrupt */ +#define DELFLG 020 /* Previous character was delimiter */ + +#define MARGIN 6 + +#define UNIT_V_CT (UNIT_V_UF + 0) +#define UNIT_UC (1 << UNIT_V_CT) +#define UNIT_CT (3 << UNIT_V_CT) + + + +t_stat lp20_svc (UNIT *uptr); +t_stat lp20_reset (DEVICE *dptr); +t_stat lp20_attach (UNIT *uptr, CONST char *cptr); +t_stat lp20_detach (UNIT *uptr); +t_stat lp20_setlpp(UNIT *, int32, CONST char *, void *); +t_stat lp20_getlpp(FILE *, UNIT *, int32, CONST void *); +t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr); +const char *lp20_description (DEVICE *dptr); + +char lp20_buffer[134 * 3]; + +#define LP20_RAM_RAP 010000 /* RAM Parity */ +#define LP20_RAM_INT 04000 /* Interrrupt bit */ +#define LP20_RAM_DEL 02000 /* Delimiter bit */ +#define LP20_RAM_TRN 01000 /* Translation bite */ +#define LP20_RAM_PI 00400 /* Paper Instruction */ +#define LP20_RAM_CHR 00377 /* Character translation */ + +uint16 lp20_vfu[256]; +uint16 lp20_ram[256]; +uint16 lp20_dvfu[] = { /* Default VFU */ + /* 66 line page with 6 line margin */ + 00377, /* Line 0 8 7 6 5 4 3 2 1 */ + 00220, /* Line 1 8 5 */ + 00224, /* Line 2 8 5 3 */ + 00230, /* Line 3 8 5 4 */ + 00224, /* Line 4 8 5 3 */ + 00220, /* Line 5 8 5 */ + 00234, /* Line 6 8 5 4 3 */ + 00220, /* Line 7 8 5 */ + 00224, /* Line 8 8 5 3 */ + 00230, /* Line 9 8 5 4 */ + 00264, /* Line 10 8 6 5 3 */ + 00220, /* Line 11 8 5 */ + 00234, /* Line 12 8 5 4 3 */ + 00220, /* Line 13 8 5 */ + 00224, /* Line 14 8 5 3 */ + 00230, /* Line 15 8 5 4 */ + 00224, /* Line 16 8 5 3 */ + 00220, /* Line 17 8 5 */ + 00234, /* Line 18 8 5 4 3 */ + 00220, /* Line 19 8 5 */ + 00364, /* Line 20 8 7 6 5 3 */ + 00230, /* Line 21 8 5 4 */ + 00224, /* Line 22 8 5 3 */ + 00220, /* Line 23 8 5 */ + 00234, /* Line 24 8 5 4 3 */ + 00220, /* Line 25 8 5 */ + 00224, /* Line 26 8 5 3 */ + 00230, /* Line 27 8 5 4 */ + 00224, /* Line 28 8 5 3 */ + 00220, /* Line 29 8 5 */ + 00276, /* Line 30 8 6 5 4 3 2 */ + 00220, /* Line 31 8 5 */ + 00224, /* Line 32 8 5 3 */ + 00230, /* Line 33 8 5 4 */ + 00224, /* Line 34 8 5 3 */ + 00220, /* Line 35 8 5 */ + 00234, /* Line 36 8 5 4 3 */ + 00220, /* Line 37 8 5 */ + 00224, /* Line 38 8 5 3 */ + 00230, /* Line 39 8 5 4 */ + 00364, /* Line 40 8 7 6 5 3 */ + 00220, /* Line 41 8 5 */ + 00234, /* Line 42 8 5 4 3 */ + 00220, /* Line 43 8 5 */ + 00224, /* Line 44 8 5 3 */ + 00230, /* Line 45 8 5 4 */ + 00224, /* Line 46 8 5 3 */ + 00220, /* Line 47 8 5 */ + 00234, /* Line 48 8 5 4 3 */ + 00220, /* Line 49 8 5 */ + 00264, /* Line 50 8 6 5 3 */ + 00230, /* Line 51 8 5 4 */ + 00224, /* Line 52 8 5 3 */ + 00220, /* Line 53 8 5 */ + 00234, /* Line 54 8 5 4 3 */ + 00220, /* Line 55 8 5 */ + 00224, /* Line 56 8 5 3 */ + 00230, /* Line 57 8 5 4 */ + 00224, /* Line 58 8 5 3 */ + 00220, /* Line 59 8 5 */ + 00020, /* Line 60 5 */ + 00020, /* Line 61 5 */ + 00020, /* Line 62 5 */ + 00020, /* Line 63 5 */ + 00020, /* Line 64 5 */ + 04020, /* Line 65 12 5 */ + 010000, /* End of form */ +}; + +struct _buffer lp20_queue; + +/* LPT data structures + + lp20_dev LPT device descriptor + lp20_unit LPT unit descriptor + lp20_reg LPT register list +*/ + +UNIT lp20_unit = { + UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 66), 100 + }; + +REG lp20_reg[] = { + { BRDATA(BUFF, lp20_buffer, 16, 8, sizeof(lp20_buffer)), REG_HRO}, + { NULL } +}; + +MTAB lp20_mod[] = { + {UNIT_CT, 0, "Lower case", "LC", NULL}, + {UNIT_CT, UNIT_UC, "Upper case", "UC", NULL}, + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE", + &lp20_setlpp, &lp20_getlpp, NULL, "Number of lines per page"}, + { 0 } +}; + +DEVICE lp20_dev = { + "LP20", &lp20_unit, lp20_reg, lp20_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &lp20_reset, + NULL, &lp20_attach, &lp20_detach, + NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, &lp20_help, NULL, NULL, &lp20_description +}; +#endif + +#ifndef NUM_DEVS_TTY +#define NUM_DEVS_TTY 0 +#endif + +#if (NUM_DEVS_TTY > 0) + +struct _buffer tty_out[NUM_LINES_TTY], tty_in[NUM_LINES_TTY]; +TMLN tty_ldsc[NUM_LINES_TTY] = { 0 }; /* Line descriptors */ +TMXR tty_desc = { NUM_LINES_TTY, 0, 0, tty_ldsc }; +int tty_connect[NUM_LINES_TTY]; +int tty_done[NUM_LINES_TTY]; +int tty_enable = 0; +extern int32 tmxr_poll; + +t_stat ttyi_svc (UNIT *uptr); +t_stat ttyo_svc (UNIT *uptr); +t_stat tty_reset (DEVICE *dptr); +t_stat tty_set_modem (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat tty_show_modem (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat tty_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat tty_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat tty_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat tty_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat tty_attach (UNIT *uptr, CONST char *cptr); +t_stat tty_detach (UNIT *uptr); +t_stat tty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr); +const char *tty_description (DEVICE *dptr); + +/* TTY data structures + + tty_dev TTY device descriptor + tty_unit TTY unit descriptor + tty_reg TTY register list +*/ + +UNIT tty_unit[] = { + { UDATA (&ttyi_svc, TT_MODE_7B+UNIT_IDLE+UNIT_DISABLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT}, + { UDATA (&ttyo_svc, TT_MODE_7B+UNIT_IDLE+UNIT_DIS, 0), KBD_POLL_WAIT}, + }; + +REG tty_reg[] = { + { DRDATA (TIME, tty_unit[0].wait, 24), REG_NZ + PV_LEFT }, + { NULL } + }; + +MTAB tty_mod[] = { + { TT_MODE, TT_MODE_KSR, "KSR", "KSR", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &tty_desc, "Disconnect a specific line" }, + { UNIT_ATT, UNIT_ATT, "SUMMARY", NULL, + NULL, &tmxr_show_summ, (void *) &tty_desc, "Display a summary of line states" }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &tmxr_show_cstat, (void *) &tty_desc, "Display current connections" }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &tmxr_show_cstat, (void *) &tty_desc, "Display multiplexer statistics" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n", + &tty_setnl, &tmxr_show_lines, (void *) &tty_desc, "Set number of lines" }, + { MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file", + &tty_set_log, NULL, (void *)&tty_desc }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG", + &tty_set_nolog, NULL, (void *)&tty_desc, "Disable logging on designated line" }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL, + NULL, &tty_show_log, (void *)&tty_desc, "Display logging for all lines" }, + { 0 } + }; + +DEVICE tty_dev = { + "TTY", tty_unit, tty_reg, tty_mod, + 2, 10, 31, 1, 8, 8, + &tmxr_ex, &tmxr_dep, &tty_reset, + NULL, &tty_attach, &tty_detach, + NULL, DEV_NET | DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, &tty_help, NULL, NULL, &tty_description + }; +#endif + + +t_stat dte_devio(uint32 dev, uint64 *data) { + uint32 res; + switch(dev & 3) { + case CONI: + *data = (uint64)(dte_unit[0].STATUS) & RMASK; + sim_debug(DEBUG_CONI, &dte_dev, "CTY %03o CONI %06o\n", dev, (uint32)*data); + break; + case CONO: + res = (uint32)(*data & RMASK); + clr_interrupt(dev); + if (res & DTE_PIENB) { + dte_unit[0].STATUS &= ~(DTE_PIA|DTE_PIE); + dte_unit[0].STATUS |= res & (DTE_PIA|DTE_PIE); + } + if (res & DTE_CO11CL) + dte_unit[0].STATUS &= ~(DTE_11DN|DTE_11ER); + if (res & DTE_CO10CL) { + dte_unit[0].STATUS &= ~(DTE_10DN|DTE_10ER); + dte_start(&dte_unit[0]); + } + if (res & DTE_CO10DB) + dte_unit[0].STATUS &= ~(DTE_10DB); + if (res & DTE_CO11CR) + dte_unit[0].STATUS &= ~(DTE_11RELD); + if (res & DTE_CO11SR) + dte_unit[0].STATUS |= (DTE_11RELD); + if (res & DTE_CO11DB) { + sim_debug(DEBUG_CONO, &dte_dev, "CTY Ring 11 DB\n"); + dte_unit[0].STATUS |= DTE_11DB; + sim_activate(&dte_unit[0], 200); + } + if (dte_unit[0].STATUS & (DTE_10DB|DTE_11DN|DTE_10DN|DTE_11ER|DTE_10ER)) + set_interrupt(dev, dte_unit[0].STATUS); + sim_debug(DEBUG_CONO, &dte_dev, "CTY %03o CONO %06o %06o\n", dev, + (uint32)*data, PC); + break; + case DATAI: + sim_debug(DEBUG_DATAIO, &dte_dev, "CTY %03o DATAI %06o\n", dev, + (uint32)*data); + break; + case DATAO: + sim_debug(DEBUG_DATAIO, &dte_dev, "CTY %03o DATAO %06o\n", dev, + (uint32)*data); + if (*data == 01365) { + dte_unit[0].STATUS |= DTE_SEC|DTE_10ER; + dte_unit[0].STATUS &= ~(DTE_10DB|DTE_IND|DTE_11DB); + break; + } + dte_unit[0].CNT = (*data & (DTE_TO10IB|DTE_TO10BC)); + dte_unit[0].STATUS |= DTE_TO11; + sim_activate(&dte_unit[0], 10); + break; + } + return SCPE_OK; +} + +/* Handle KL style interrupt vectors */ +t_addr +dte_devirq(uint32 dev, t_addr addr) { + return 0142; +} + +/* Handle TO11 interrupts */ +t_stat dte_svc (UNIT *uptr) +{ + /* Did the 10 knock? */ + if (uptr->STATUS & DTE_11DB) { + /* If in secondary mode, do that protocol */ + if (uptr->STATUS & DTE_SEC) + dte_second(uptr); + else + dte_primary(uptr); /* Retrieve data */ + } else if (uptr->STATUS & DTE_TO11) { + /* Does 10 want us to send it what we have? */ + dte_transfer(uptr); + } + return SCPE_OK; +} + +/* Handle secondary protocol */ +void dte_second(UNIT *uptr) { + uint64 word; + int32 ch; + uint32 base = 0; + +#if KI_22BIT +#if KL_ITS + if (!QITS) +#endif + base = eb_ptr; +#endif + /* read command */ + word = M[SEC_DTCMD + base]; +#if KL_ITS + if (word == 0 && QITS && (uptr->STATUS & ITS_ON) != 0) { + dte_its(uptr); + uptr->STATUS &= ~DTE_11DB; + return; + } +#endif + /* Do it */ + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY secondary %012llo\n", word); + switch(word & SEC_CMDMSK) { + default: + case SEC_MONO: /* Ouput character in monitor mode */ + ch = (int32)(word & 0177); + if (full(&cty_out)) { + sim_activate(uptr, 200); + return; + } + if (ch != 0) { + cty_out.buff[cty_out.in_ptr] = ch & 0x7f; + inci(&cty_out); + sim_activate(&dte_unit[1], 200); + } + M[SEC_DTCHR + base] = ch; + M[SEC_DTMTD + base] = FMASK; + break; + + case SEC_SETPRI: +enter_pri: + if (Mem_examine_word(0, 0, &word)) + break; + dte_proc_num = (word >> 24) & 037; + dte_base = dte_proc_num + 1; + dte_off = dte_base + (word & 0177777); + dte_dt10_off = 16; + dte_et10_off = dte_dt10_off + 16; + dte_et11_off = dte_base + 16; + uptr->STATUS &= ~DTE_SEC; + dte_in_ptr = dte_out_ptr = 0; + dte_in_cmd = dte_out_res = 0; + cty_done = 0; + /* Start input process */ + M[SEC_DTCMD + base] = 0; + M[SEC_DTFLG + base] = FMASK; + uptr->STATUS &= ~DTE_11DB; + return; + + case SEC_SETDDT: /* Read character from console */ + if (empty(&cty_in)) { + M[SEC_DTF11 + base] = 0; + M[SEC_DTMTI + base] = FMASK; + break; + } + ch = cty_in.buff[cty_in.out_ptr]; + inco(&cty_in); + M[SEC_DTF11 + base] = 0177 & ch; + M[SEC_DTMTI + base] = FMASK; + break; + + case SEC_CLRDDT: /* Clear DDT input mode */ + uptr->STATUS &= ~DTE_MON; + break; + + case SEC_MONON: + uptr->STATUS |= DTE_MON; + break; + + case SEC_RDSW: /* Read switch register */ + M[SEC_DTSWR + base] = SW; + M[SEC_DTF11 + base] = SW; + break; + + case SEC_PGMCTL: /* Program control: Used by KLDCP */ + switch(word) { + case SEC_ENDPASS: + case SEC_LOOKUP: + case SEC_RDWRD: + case SEC_RDBYT: + break; + case SEC_ESEC: + goto enter_pri; + case SEC_EPRI: + case SEC_ERTM: + break; + } + break; + + case SEC_CLKCTL: /* Clock control: Used by KLDCP */ + switch(word) { + case SEC_CLKOFF: + dte_unit[3].STATUS &= ~SEC_CLK; + break; + case SEC_CLKWT: + rtc_wait = (uint16)(M[SEC_DTT11 + base] & 0177777); + /* Fall Through */ + + case SEC_CLKON: + dte_unit[3].STATUS |= SEC_CLK; + rtc_tick = 0; + break; + case SEC_CLKRD: + M[SEC_DTF11+base] = rtc_tick; + break; + } + break; + } + /* Acknowledge command */ + M[SEC_DTCMD + base] = 0; + M[SEC_DTFLG + base] = FMASK; + uptr->STATUS &= ~DTE_11DB; + if (dte_dev.flags & TYPE_RSX20) { + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, dte_unit[0].STATUS); + } +} + +#if KL_ITS +/* Process ITS Ioeleven locations */ +void dte_its(UNIT *uptr) { + uint64 word; + char ch; + uint16 data; + int cnt; + int ln; + + /* Check for input Start */ + word = M[ITS_DTEINP]; + if ((word & SMASK) == 0) { + M[ITS_DTEINP] = FMASK; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEINP = %012llo\n", word); + } + /* Check for output Start */ + word = M[ITS_DTEOUT]; + if ((word & SMASK) == 0) { + cnt = word & 017777; + ln = ((word >> 18) & 077) - 1; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEOUT = %012llo\n", word); + while (cnt > 0) { + if (ln < 0) { + if (full(&cty_out)) + return; + if (!Mem_read_byte(0, &data, 1)) + return; + ch = data & 0177; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %x\n", ch); + cty_out.buff[cty_out.in_ptr] = ch; + inci(&cty_out); + cnt--; + if (! sim_is_active(&dte_unit[1])) + sim_activate(&dte_unit[1], 50); +#if (NUM_DEVS_TTY > 0) + } else { + struct _buffer *otty = &tty_out[ln]; + if (full(otty)) + return; + if (!Mem_read_byte(0, &data, 1)) + return; + ch = data & 0177; + sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %x %d\n", ch, ln); + otty->buff[otty->in_ptr] = ch; + inci(otty); + cnt--; +#endif + } + } + M[ITS_DTEOUT] = FMASK; + uptr->STATUS |= DTE_11DN; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEOUT = %012llo\n", word); + } + /* Check for line speed */ + word = M[ITS_DTELSP]; + if ((word & SMASK) == 0) { /* Ready? */ + M[ITS_DTELSP] = FMASK; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTELSP = %012llo %012llo\n", word, M[ITS_DTELPR]); + } + dte_input(); + /* Check for output Start */ + word = M[ITS_DTEOST]; + if ((word & SMASK) == 0) { + if (word == 0) + cty_done++; +#if (NUM_DEVS_TTY > 0) + else if (word > 0 && word < tty_desc.lines) { + tty_done[word-1] = 1; + } +#endif + M[ITS_DTEOST] = FMASK; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEOST = %012llo\n", word); + } +} +#endif + +/* Handle primary protocol */ +void dte_primary(UNIT *uptr) { + uint64 word, iword; + int s; + int cnt; + struct _dte_queue *in; + uint16 data1, *dp; + + if ((uptr->STATUS & DTE_11DB) == 0) + return; + + /* Check if there is room for another packet */ + if (((dte_in_ptr + 1) & 0x1f) == dte_in_cmd) { + /* If not reschedule ourselves */ + sim_activate(uptr, 100); + return; + } + uptr->STATUS &= ~(DTE_11DB); + clr_interrupt(DTE_DEVNUM); + /* Check status word to see if valid */ + if (Mem_examine_word(0, dte_et11_off + PRI_CMTW_STS, &word)) { + uint32 base; +error: + base = 0; +#if KI_22BIT +#if KL_ITS + if (!QITS) +#endif + base = eb_ptr; +#endif + /* If we can't read it, go back to secondary */ + M[SEC_DTFLG + base] = FMASK; + uptr->STATUS |= DTE_SEC; + uptr->STATUS &= ~DTE_11DB; + if (dte_dev.flags & TYPE_RSX20) { + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, dte_unit[0].STATUS); + } + sim_debug(DEBUG_DETAIL, &dte_dev, "DTE: error %012llo\n", word); + return; + } + + if ((word & PRI_CMT_QP) == 0) { + goto error; + } + in = &dte_in[dte_in_ptr]; + /* Check if indirect */ + if ((word & PRI_CMT_IP) != 0) { + /* Transfer from 10 */ + if ((uptr->STATUS & DTE_IND) == 0) { + fprintf(stderr, "DTE out of sync\n\r"); + return; + } + /* Get size of transfer */ + if (Mem_examine_word(0, dte_et11_off + PRI_CMTW_CNT, &iword)) + goto error; + sim_debug(DEBUG_EXP, &dte_dev, "DTE: count: %012llo\n", iword); + in->dcnt = (uint16)(iword & 0177777); + /* Read in data */ + dp = &in->data[0]; + for (cnt = in->dcnt; cnt > 0; cnt --) { + /* Read in data */ + s = Mem_read_byte(0, dp, 0); + if (s == 0) + goto error; + in->sz = s; + sim_debug(DEBUG_DATA, &dte_dev, + "DTE: Read Idata: %06o %03o %03o %06o cnt=%o\n", + *dp, *dp >> 8, *dp & 0377, + ((*dp & 0377) << 8) | ((*dp >> 8) & 0377), cnt); + dp++; + if (s <= 8) + cnt--; + } + uptr->STATUS &= ~DTE_IND; + dte_in_ptr = (dte_in_ptr + 1) & 0x1f; + } else { + /* Transfer from 10 */ + in->dptr = 0; + in->dcnt = 0; + /* Read in count */ + if (!Mem_read_byte(0, &data1, 0)) + goto error; + in->cnt = data1; + cnt = in->cnt-2; + if (!Mem_read_byte(0, &data1, 0)) + goto error; + in->func = data1; + cnt -= 2; + if (!Mem_read_byte(0, &data1, 0)) + goto error; + in->dev = data1; + cnt -= 2; + if (!Mem_read_byte(0, &data1, 0)) + goto error; + in->spare = data1; + cnt -= 2; + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read CMD: %o c=%o f=%o %s d=%o\n", + dte_in_ptr, in->cnt, in->func, + ((in->func & 0377) > PRI_EMLDV)?"***": + pri_name[in->func & 0377], in->dev); + dp = &in->data[0]; + for (; cnt > 0; cnt -=2) { + /* Read in data */ + if (!Mem_read_byte(0, dp, 0)) + goto error; + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Read data: %06o %03o %03o\n", + *dp, *dp >> 8, *dp & 0377); + dp++; + in->dcnt += 2; + } + if (in->func & PRI_IND_FLG) { + uptr->STATUS |= DTE_IND; + in->dcnt = in->data[0]; + in->sdev = (in->dcnt >> 8) & 0377; + in->dcnt &= 0377; + word |= PRI_CMT_TOT; + if (Mem_deposit_word(0, dte_dt10_off + PRI_CMTW_STS, &word)) + goto error; + } else { + dte_in_ptr = (dte_in_ptr + 1) & 0x1f; + } + } + word &= ~PRI_CMT_TOT; + if (Mem_deposit_word(0, dte_dt10_off + PRI_CMTW_STS, &word)) + goto error; + uptr->STATUS |= DTE_11DN; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + dte_function(uptr); +} + +/* Process primary protocol packets */ +void +dte_function(UNIT *uptr) +{ + uint16 data1[32]; + int32 ch; + struct _dte_queue *cmd; + int func; + int dev; + + /* Check if queue is empty */ + while (dte_in_cmd != dte_in_ptr) { + if (((dte_out_res + 1) & 0x1f) == dte_out_ptr) { + sim_debug(DEBUG_DATA, &dte_dev, "DTE: func out full %d %d\n", + dte_out_res, dte_out_ptr); + return; + } + cmd = &dte_in[dte_in_cmd]; + dev = cmd->dev & 0377; + func = cmd->func & 0377; + sim_debug(DEBUG_DATA, &dte_dev, + "DTE: func %o %02o %s dev %o cnt %d dcnt %d\n", + dte_in_cmd, func, (func > PRI_EMLDV) ? "***" : pri_name[func], + cmd->dev, cmd->dcnt, cmd->dptr ); + switch (func) { + case PRI_EM2EI: /* Initial message to 11 */ + data1[0] = PRI_CTYDV; + if (dte_queue(PRI_EM2TI, PRI_EMCTY, 1, data1) == 0) + return; +#if (NUM_DEVS_LP20 > 0) + data1[0] = 140; + if (dte_queue(PRI_EMHLA, PRI_EMLPT, 1, data1) == 0) + return; +#endif + data1[0] = 0; + if (dte_queue(PRI_EMAKA, PRI_EMCLK, 1, data1) == 0) + return; + break; + + case PRI_EM2TI: /* Replay to initial message. */ + case PRI_EMLBE: /* Acknowledge line */ + /* Should never get these */ + break; + + case PRI_EMHDR: /* Here is date and time */ + /* Ignore this function */ + break; + + case PRI_EMRDT: /* Request Date/Time */ + { + time_t t = time(NULL); + struct tm *tm = localtime(&t); + int yr = tm->tm_year + 1900; + int tim = (((tm->tm_hour * 60) + tm->tm_min) * 60) + + tm->tm_sec; + data1[0] = 0177777; + data1[1] = ((yr & 0377) << 8) | ((yr >> 8) & 0377); + data1[2] = (tm->tm_mon) + ((tm->tm_mday - 1) << 8); + data1[3] = (((tm->tm_wday + 6) % 7)) + + (tm->tm_isdst ? 0200 << 8 : 0); + tim >>= 1; + data1[4] = ((tim & 0377) << 8) | ((tim >> 8) & 0377); + if (dte_queue(PRI_EMHDR | PRI_IND_FLG, PRI_EMCLK, 6, data1) == 0) + return; + } + break; + + case PRI_EMSTR: /* String data */ + +#if (NUM_DEVS_LP20 > 0) + /* Handle printer data */ + if (dev == PRI_EMLPT) { + uptr->LPST &= ~(EOFFLG); + if (!sim_is_active(&lp20_unit)) + sim_activate(&lp20_unit, 1000); + while (cmd->dptr < cmd->dcnt) { + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + if (full(&lp20_queue)) + return; + lp20_queue.buff[lp20_queue.in_ptr] = ch; + inci(&lp20_queue); + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; + sim_debug(DEBUG_DETAIL, &dte_dev, "LP20 done\n"); + break; + } +#endif + + /* Handle terminal data */ + if (dev == PRI_EMDLS) { + int ln = cmd->sdev; + struct _buffer *otty; + if (ln == PRI_CTYDV) + goto cty; +#if (NUM_DEVS_TTY > 0) + ln -= NUM_DLS; + if (ln > 0 && ln >= tty_desc.lines) + break; + otty = &tty_out[ln]; + if (cmd->sz > 8) + cmd->dcnt += cmd->dcnt; + while (cmd->dptr < cmd->dcnt) { + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + if (ch != 0) { + if (full(otty)) + return; + otty->buff[otty->in_ptr] = ch; + inci(otty); + sim_debug(DEBUG_DATA, &dte_dev, "TTY queue %o %d\n", + ch, ln); + } + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; +#endif + break; + } + + if (dev == PRI_EMCTY) { +cty: + sim_activate(&dte_unit[1], 100); + data1[0] = 0; + if (cmd->sz > 8) + cmd->dcnt += cmd->dcnt; + while (cmd->dptr < cmd->dcnt) { + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + if (ch != 0) { + ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); + if (full(&cty_out)) + return; + cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); + inci(&cty_out); + sim_debug(DEBUG_DATA, &dte_dev,"CTY queue %o\n",ch); + } + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; + } + break; + + case PRI_EMSNA: /* Send all (ttys) */ + /* Handle terminal data */ + if (dev == PRI_EMDLS || dev == PRI_EMCTY) { + struct _buffer *otty; + int ln; + while (cmd->dptr < cmd->dcnt) { + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + if (ch != 0) { + sim_debug(DEBUG_DATA, &dte_dev, "SNA queue %o\n", ch); + ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); + if (!(full(&cty_out))) { + cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); + inci(&cty_out); + } +#if (NUM_DEVS_TTY > 0) + for(ln = 0; ln <= tty_desc.lines; ln++) { + otty = &tty_out[ln]; + if (!(full(otty))) { + otty->buff[otty->in_ptr] = ch; + inci(otty); + } + } +#endif + } + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; + data1[0] = 0; + } + break; + + case PRI_EMLNC: /* Line-Char */ + if (dev == PRI_EMDLS) { + sim_activate(&dte_unit[1], 100); + while (cmd->dptr < cmd->dcnt) { + int ln; + ch = (int32)(cmd->data[cmd->dptr >> 1]); + ln = (ch >> 8); + ch &= 0177; + if (ch != 0 && ln == PRI_CTYDV) { + ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); + cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); + inci(&cty_out); + if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) + return; + sim_debug(DEBUG_DATA, &dte_dev, "CTY queue %o\n", ch); + } else + if (ch != 0 && ln >= NUM_DLS && ln <= tty_desc.lines) { + struct _buffer *otty; + ln -= NUM_DLS; + otty = &tty_out[ln]; + if (full(otty)) + return; + otty->buff[otty->in_ptr] = ch; + inci(otty); + sim_debug(DEBUG_DATA, &dte_dev, "TTY queue %o %d\n", ch, ln); + } + cmd->dptr+=2; + } + if (cmd->dptr != cmd->dcnt) + return; + } + break; + + case PRI_EMOPS: +#if (NUM_DEVS_LP20 > 0) + if (dev == PRI_EMLPT) { + lp20_unit.LINE = 0; + } +#endif + break; + + case PRI_EMRDS: /* Request device status */ + if (dev == PRI_EMLPT) { + if (cmd->data[0] != 0) { + data1[0] = 2 << 8; + data1[1] = 0; + data1[2] = 0; + if (dte_queue(PRI_EMHDS+PRI_IND_FLG, PRI_EMLPT, + 3, data1) == 0) + return; + } else { +#if (NUM_DEVS_LP20 > 0) + lp20_unit.LPST |= HDSFLG; + if (!sim_is_active(&lp20_unit)) + sim_activate(&lp20_unit, 1000); +#else + data1[0] = 2 << 8; + data1[1] = 0; + data1[2] = 0; + if (dte_queue(PRI_EMHDS+PRI_IND_FLG, PRI_EMLPT, + 3, data1) == 0) + return; +#endif + } + } + if (dev == PRI_EMCTY) { + data1[0] = 0; + data1[1] = 0; + if (dte_queue(PRI_EMHDS+PRI_IND_FLG, PRI_EMCTY, + 3, data1) == 0) + return; + } + if (dev == PRI_EMDH1) { + data1[0] = 0; + data1[1] = 0; + if (dte_queue(PRI_EMHDS+PRI_IND_FLG, PRI_EMDH1, + 3, data1) == 0) + return; + } + break; + + case PRI_EMHDS: /* Here is device status */ +#if (NUM_DEVS_LP20 > 0) + if (dev == PRI_EMLPT) { + sim_debug(DEBUG_DETAIL, &dte_dev, "LPT HDS %06o %06o %06o\n", + cmd->data[0], cmd->data[1], cmd->data[2]); + if (cmd->data[0] & 040) { + lp20_unit.LPST |= EOFFLG; + lp20_unit.LPCNT = 0; + } + lp20_unit.LPST |= HDSFLG; + sim_debug(DEBUG_DETAIL, &dte_dev, "LPT HDS %06o \n", + lp20_unit.LPST); + if (!sim_is_active(&lp20_unit)) + sim_activate(&lp20_unit, 1000); + } +#endif + break; + case PRI_EMLDV: /* Load LP VFU */ +#if (NUM_DEVS_LP20 > 0) + if (dev == PRI_EMLPT) { + int ln = lp20_unit.LPCNT; + while (cmd->dptr < cmd->dcnt) { + uint16 d = cmd->data[cmd->dptr++]; + if (d == (0357 << 8)) + lp20_vfu[ln++] = 010000; /* Signal end of page */ + else + lp20_vfu[ln++] = ((d >> 8) & 077)|((d <<6) & 07700); + } + lp20_unit.LPCNT = ln; + for (ln = 0; ln < 256; ln++) + sim_debug(DEBUG_DETAIL, &lp20_dev, + "LP20 VFU %02d => %04o\n", ln, lp20_vfu[ln]); + data1[0] = 0; + if (dte_queue(PRI_EMLBE, PRI_EMLPT, 1, data1) == 0) + sim_activate(uptr, 1000); + } +#endif + break; + + case PRI_EMLDR: /* Load LP RAM */ +#if (NUM_DEVS_LP20 > 0) + if (dev == PRI_EMLPT) { + int ln = lp20_unit.LPCNT; + for (;cmd->dptr < cmd->dcnt; cmd->dptr++, ln++) { + if (ln < 256) + lp20_ram[ln] = cmd->data[cmd->dptr]; + } + lp20_unit.LPCNT = ln; + for (ln = 0; ln < 256; ln++) + sim_debug(DEBUG_DETAIL, &lp20_dev, + "LP20 RAM %02x => %04x\n", ln, lp20_ram[ln]); + data1[0] = 0; + if (dte_queue(PRI_EMLBE, PRI_EMLPT, 1, data1) == 0) + sim_activate(uptr, 1000); + } +#endif + break; + + + case PRI_EMFLO: /* Flush output */ +#if (NUM_DEVS_TTY > 0) + if (dev == PRI_EMDLS) { + int ln = cmd->data[0] - NUM_DLS; + + sim_debug(DEBUG_DETAIL, &dte_dev, "Flush out %d %o\n", + ln, cmd->data[0]); + if (ln == (NUM_DLS - PRI_CTYDV)) + cty_out.in_ptr = cty_out.out_ptr = 0; + else + tty_out[ln].in_ptr = tty_out[ln].out_ptr = 0; + data1[0] = (ln + NUM_DLS) | (PRI_EMDLS << 8); + if (dte_queue(PRI_EMLBE, PRI_EMDLS, 1, data1) == 0) + return; + } +#endif +#if (NUM_DEVS_LP20 > 0) + if ((cmd->dev & 0377) == PRI_EMLPT) { + data1[0] = cmd->data[0]; + if (dte_queue(PRI_EMLBE, PRI_EMLPT, 1, data1) == 0) + return; + } +#endif + break; + + case PRI_EMDSC: /* Dataset connect */ + break; + + case PRI_EMHUD: /* Hang up dataset */ +#if (NUM_DEVS_TTY > 0) + if (dev == PRI_EMDLS) { + int ln = cmd->sdev - NUM_DLS; + if (ln >= 0) { + TMLN *lp = &tty_ldsc[ln]; + tmxr_linemsg (lp, "\r\nLine Hangup\r\n"); + tmxr_reset_ln(lp); + tty_connect[ln] = 0; + } + } + break; + + case PRI_EMXOF: /* XOFF line */ + if (dev == PRI_EMDLS) { + int ln = cmd->sdev - NUM_DLS; + if (ln >= 0) { + tty_ldsc[ln].rcve = 0; + } + } + break; + + case PRI_EMXON: /* XON line */ + if (dev == PRI_EMDLS) { + int ln = cmd->sdev - NUM_DLS; + if (ln >= 0) { + tty_ldsc[ln].rcve = 1; + } + } + break; + + case PRI_EMHLS: /* Here is line speeds */ + if (dev == PRI_EMDLS) { + int ln = cmd->sdev - NUM_DLS; + sim_debug(DEBUG_DETAIL, &tty_dev, "HDL %o o=%d i=%d %o\n", + ln, cmd->data[0], cmd->data[1], cmd->data[2]); + } + break; + + case PRI_EMHLA: /* Here is line allocation */ + case PRI_EMRBI: /* Reboot information */ + case PRI_EMAKA: /* Ack ALL */ + case PRI_EMTDO: /* Turn device On/Off */ + break; + + case PRI_EMEDR: /* Enable/Disable line */ + if (cmd->dev == PRI_EMDH1) { + /* Zero means enable, no-zero means disable */ + tty_enable = !((cmd->data[0] >> 8) & 0xff); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY enable %x\n", + tty_enable); + if (tty_enable) { + sim_activate(&tty_unit[0], 1000); + sim_activate(&tty_unit[1], 1000); + } else { + sim_cancel(&tty_unit[0]); + sim_cancel(&tty_unit[1]); + } + } + break; +#endif + default: + break; + } + /* Mark command as finished */ + cmd->cnt = 0; + dte_in_cmd = (dte_in_cmd + 1) & 0x1F; + } +} + +/* + * Handle primary protocol, + * Send to 10 when requested. + */ +void dte_transfer(UNIT *uptr) { + uint16 cnt; + uint16 scnt; + struct _dte_queue *out; + uint16 *dp; + + /* Check if Queue empty */ + if (dte_out_res == dte_out_ptr) + return; + + out = &dte_out[dte_out_ptr]; + uptr->STATUS &= ~DTE_TO11; + clr_interrupt(DTE_DEVNUM); + + /* Compute how much 10 wants us to send */ + scnt = ((uptr->CNT ^ DTE_TO10BC) + 1) & DTE_TO10BC; + /* Check if indirect */ + if ((uptr->STATUS & DTE_SIND) != 0) { + /* Transfer indirect */ + cnt = out->dcnt; + dp = &out->data[0]; + if (cnt > scnt) /* Only send as much as we are allowed */ + cnt = scnt; + for (; cnt > 0; cnt -= 2) { + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Send Idata: %06o %03o %03o\n", + *dp, *dp >> 8, *dp & 0377); + if (Mem_write_byte(0, dp) == 0) + goto error; + dp++; + } + uptr->STATUS &= ~DTE_SIND; + } else { + sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d send CMD: [%o] %o %o %o\n", + dte_out_ptr, dte_out_res, scnt, out->cnt, out->func, out->dev); + /* Get size of packet */ + cnt = out->cnt; + if ((out->func & PRI_IND_FLG) == 0) + cnt += out->dcnt; + /* If it will not fit, request indirect */ + if (cnt > scnt) { /* If not enough space request indirect */ + out->func |= PRI_IND_FLG; + cnt = scnt; + } + /* Write out header */ + if (!Mem_write_byte(0, &cnt)) + goto error; + if (!Mem_write_byte(0, &out->func)) + goto error; + cnt -= 2; + if (!Mem_write_byte(0, &out->dev)) + goto error; + cnt -= 2; + if (!Mem_write_byte(0, &out->spare)) + goto error; + cnt -= 2; + if (out->func & PRI_IND_FLG) { + uint16 dwrd = out->dcnt; + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Indirect %o %o\n", cnt, + out->dcnt); + dwrd |= (out->sdev << 8); + if (!Mem_write_byte(0, &dwrd)) + goto error; + uptr->STATUS |= DTE_SIND; + goto done; + } + cnt -= 2; + dp = &out->data[0]; + for (; cnt > 0; cnt -= 2) { + sim_debug(DEBUG_DATA, &dte_dev, "DTE: Send data: %06o %03o %03o\n", + *dp, *dp >> 8, *dp & 0377); + if (!Mem_write_byte(0, dp)) + goto error; + dp++; + } + } + out->cnt = 0; + dte_out_ptr = (dte_out_ptr + 1) & 0x1f; +done: + uptr->STATUS |= DTE_10DN; + set_interrupt(DTE_DEVNUM, uptr->STATUS); +error: + return; +} + +/* Process input from CTY and TTY's to 10. */ +void +dte_input() +{ + uint16 data1; + uint16 dataq[32]; + int n; + int ln; + int save_ptr; + char ch; + UNIT *uptr = &dte_unit[0]; + +#if KL_ITS + if (QITS && (uptr->STATUS & ITS_ON) != 0) { + uint64 word; + word = M[ITS_DTEODN]; + /* Check if ready for output done */ + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEODN = %012llo %d\n", word, + cty_done); + if ((word & SMASK) != 0) { + if (cty_done) { + word = 64LL; + cty_done--; +#if (NUM_DEVS_TTY > 0) + } else { + for (ln = 0; ln < tty_desc.lines; ln++) { + if (tty_done[ln]) { + word = (((uint64)ln + 1) << 18); + word |=(tty_connect[ln])? 64: 1; + tty_done[ln] = 0; + break; + } + } +#endif + } + if ((word & SMASK) == 0) { + M[ITS_DTEODN] = word; + /* Tell 10 something is ready */ + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEODN = %012llo\n", + word); + } + } + /* Check if ready for any input */ + word = M[ITS_DTETYI]; + if ((word & SMASK) != 0) { + /* CTY first. */ + if (not_empty(&cty_in)) { + ch = cty_in.buff[cty_in.out_ptr]; + inco(&cty_in); + word = (uint64)ch; +#if (NUM_DEVS_TTY > 0) + } else { + ln = uptr->CNT; + while ((word & SMASK) != 0) { + if (not_empty(&tty_in[ln])) { + ch = tty_in[ln].buff[tty_in[ln].out_ptr]; + inco(&tty_in[ln]); + word = ((uint64)(ln+1) << 18) | (uint64)ch; + } + ln++; + if (ln >= tty_desc.lines) + ln = 0; + if (ln == uptr->CNT) + break; + } + uptr->CNT = ln; +#endif + } + if ((word & SMASK) == 0) { + M[ITS_DTETYI] = word; + /* Tell 10 something is ready */ + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTETYI = %012llo\n", + word); + } + } +#if (NUM_DEVS_TTY > 0) + /* Check ready for hang up message */ + word = M[ITS_DTEHNG]; + if ((word & SMASK) != 0) { + for (ln = 0; ln < tty_desc.lines; ln++) { + if (tty_connect[ln] != tty_ldsc[ln].conn) { + if (tty_ldsc[ln].conn) + word = 015500 + ln + 1; + else + word = ln + 1; + tty_connect[ln] = tty_ldsc[ln].conn; + tty_done[ln] = tty_ldsc[ln].conn; + break; + } + } + /* Tell 10 something is ready */ + if ((word & SMASK) == 0) { + M[ITS_DTEHNG] = word; + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS DTEHNG = %012llo\n", + word); + } + } +#endif + } else +#endif + if ((uptr->STATUS & DTE_SEC) == 0) { + /* Check if CTY done with input */ + if (cty_done) { + data1 = PRI_CTYDV; + if (dte_queue(PRI_EMLBE, PRI_EMDLS, 1, &data1) == 0) + return; + cty_done--; + } + /* Grab a chunck of input from CTY if any */ + n = 0; + save_ptr = cty_in.out_ptr; + while (not_empty(&cty_in) && n < 32) { + ch = cty_in.buff[cty_in.out_ptr]; + inco(&cty_in); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY recieve %02x\n", ch); + dataq[n++] = (PRI_CTYDV << 8) | ch; + } + if (n > 0 && dte_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) { + /* Restore the input pointer */ + cty_in.out_ptr = save_ptr; + return; + } +#if (NUM_DEVS_TTY > 0) + n = 0; + /* While we have room for one more packet, + * grab as much input as we can */ + for (ln = 0; ln < tty_desc.lines && + ((dte_out_res + 1) & 0x1f) != dte_out_ptr; ln++) { + struct _buffer *itty = &tty_in[ln]; + while (not_empty(itty)) { + ch = itty->buff[itty->out_ptr]; + inco(itty); + dataq[n++] = ((ln + NUM_DLS) << 8) | ch; + if (n == 32) { + if (dte_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) + return; + n = 0; + continue; + } + } + } + if (n > 0 && dte_queue(PRI_EMLNC, PRI_EMDLS, n, dataq) == 0) + return; + n = 0; + for (ln = 0; ln < tty_desc.lines; ln++) { + data1 = (ln + NUM_DLS) | (PRI_EMDLS << 8); + if (tty_connect[ln] != tty_ldsc[ln].conn) { + if (tty_ldsc[ln].conn) + n = PRI_EMDSC; + else + n = PRI_EMHUD; + if (dte_queue(n, PRI_EMDLS, 1, &data1) == 0) + return; + tty_connect[ln] = tty_ldsc[ln].conn; + } + if (tty_done[ln]) { + if (dte_queue(PRI_EMLBE, PRI_EMDLS, 1, &data1) == 0) + return; + tty_done[ln] = 0; + } + } +#endif + } +} + +/* + * Queue up a packet to send to 10. + */ +int +dte_queue(int func, int dev, int dcnt, uint16 *data) +{ + uint16 *dp; + struct _dte_queue *out; + + /* Check if room in queue for this packet. */ + if (((dte_out_res + 1) & 0x1f) == dte_out_ptr) { + sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d out full\n", dte_out_res, dte_out_ptr); + return 0; + } + out = &dte_out[dte_out_res]; + out->cnt = 10; + out->func = func; + out->dev = dev; + out->dcnt = (dcnt-1)*2; + out->spare = 0; + sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d queue resp: %o (%o) f=%o %s d=%o\n", + dte_out_ptr, dte_out_res, out->cnt, out->dcnt, out->func, + (out->func > PRI_EMLDV)? "***":pri_name[out->func], out->dev); + for (dp = &out->data[0]; dcnt > 0; dcnt--) { + *dp++ = *data++; + } + /* Advance pointer to next function */ + dte_out_res = (dte_out_res + 1) & 0x1f; + return 1; +} + + +/* + * If anything in queue, start a transfer, if one is not already + * pending. + */ +int +dte_start(UNIT *uptr) +{ + uint64 word; + int dcnt; + + /* Check if queue empty */ + if (dte_out_ptr == dte_out_res) + return 1; + + /* If there is interrupt pending, just return */ + if ((uptr->STATUS & (DTE_IND|DTE_10DB|DTE_11DB)) != 0) + return 1; + if (Mem_examine_word(0, dte_et11_off + PRI_CMTW_STS, &word)) { +error: + /* If we can't read it, go back to secondary */ + uptr->STATUS |= DTE_SEC|DTE_10ER; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + return 0; + } + /* Bump count of messages sent */ + word = (word & ~(PRI_CMT_10IC|PRI_CMT_IP)) | ((word + 0400) & PRI_CMT_10IC); + word &= ~PRI_CMT_FWD; + if ((uptr->STATUS & DTE_SIND) != 0) + word |= PRI_CMT_IP; + if (Mem_deposit_word(0, dte_dt10_off + PRI_CMTW_STS, &word)) + goto error; + dcnt = dte_out[dte_out_ptr].cnt; + if ((dte_out[dte_out_ptr].func & PRI_IND_FLG) == 0) + dcnt += dte_out[dte_out_ptr].dcnt; + /* Tell 10 something is ready */ + if ((uptr->STATUS & DTE_SIND) != 0) { + dcnt = dte_out[dte_out_ptr].dcnt; + } + sim_debug(DEBUG_DATA, &dte_dev, "DTE: start: %012llo %o\n", word, dcnt); + word = (uint64)dcnt; + if (Mem_deposit_word(0, dte_dt10_off + PRI_CMTW_CNT, &word)) + goto error; + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, uptr->STATUS); + return 1; +} + + +/* Check for input from CTY and put on queue. */ +t_stat dtei_svc (UNIT *uptr) +{ + int32 ch; + uint32 base = 0; + UNIT *optr = &dte_unit[0]; + +#if KI_22BIT +#if KL_ITS + if (!QITS) +#endif + base = eb_ptr; +#endif + sim_clock_coschedule (uptr, tmxr_poll); + dte_input(); + if ((optr->STATUS & (DTE_SEC)) == 0) { + dte_function(uptr); /* Process queue */ + dte_start(optr); + } + + + /* If we have room see if any new lines */ + while (!full(&cty_in)) { + ch = sim_poll_kbd (); + if (ch & SCPE_KFLAG) { + ch = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (uptr->flags)); + cty_in.buff[cty_in.in_ptr] =ch & 0377; + inci(&cty_in); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY char %o '%c'\n", ch, + ((ch > 040 && ch < 0177)? ch: '.')); + } else + break; + } + + /* If Monitor input, place in buffer */ + if ((optr->STATUS & (DTE_SEC|DTE_MON)) == (DTE_SEC|DTE_MON) && + not_empty(&cty_in) && M[SEC_DTMTI + base] == 0) { + ch = cty_in.buff[cty_in.out_ptr]; + inco(&cty_in); + M[SEC_DTF11 + base] = ch; + M[SEC_DTMTI + base] = FMASK; + if (dte_dev.flags & TYPE_RSX20) { + uptr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, dte_unit[0].STATUS); + } + } + return SCPE_OK; +} + +/* Handle output of characters to CTY. Started whenever there is output pending */ +t_stat dteo_svc (UNIT *uptr) +{ + uint32 base = 0; + UNIT *optr = &dte_unit[0]; + +#if KI_22BIT +#if KL_ITS + if (!QITS) +#endif + base = eb_ptr; +#endif + /* Flush out any pending CTY output */ + while(not_empty(&cty_out)) { + char ch = cty_out.buff[cty_out.out_ptr]; + if (ch != 0) { + if (sim_putchar(ch) != SCPE_OK) { + sim_activate(uptr, 1000); + return SCPE_OK;; + } + } + inco(&cty_out); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY outch %o '%c'\n", ch, + ((ch > 040 && ch < 0177)? ch: '.')); + } + cty_done++; + return SCPE_OK; +} + + +/* Handle FE timer interrupts. And keepalive counts */ +t_stat +dtertc_srv(UNIT * uptr) +{ + UNIT *optr = &dte_unit[0]; + + sim_activate_after(uptr, 1000000/rtc_tps); + /* Check if clock requested */ + if (uptr->STATUS & SEC_CLK) { + rtc_tick++; + if (rtc_wait != 0) { + rtc_wait--; + } else { + UNIT *optr = &dte_unit[0]; + uint32 base = 0; +#if KI_22BIT + base = eb_ptr; +#endif + /* Set timer flag */ + M[SEC_DTCLK + base] = FMASK; + optr->STATUS |= DTE_10DB; + set_interrupt(DTE_DEVNUM, optr->STATUS); + sim_debug(DEBUG_EXP, &dte_dev, "CTY tick %x %x %06o\n", + rtc_tick, rtc_wait, optr->STATUS); + } + } +#if KL_ITS + /* Check if Timesharing is running */ + if (QITS) { + uint64 word; + + word = (M[ITS_DTECHK] + 1) & FMASK; + if (word == 0) { + optr->STATUS |= ITS_ON; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS ON\n"); + sim_activate(&tty_unit[0], 1000); + sim_activate(&tty_unit[1], 1000); + } else if (word >= (15 * 60)) { + optr->STATUS &= ~ITS_ON; + word = 15 * 60; + sim_cancel(&tty_unit[0]); + sim_cancel(&tty_unit[1]); + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY ITS OFF\n"); + } + M[ITS_DTECHK] = word; + } else +#endif + + /* Update out keep alive timer if in secondary protocol */ + if ((optr->STATUS & DTE_SEC) == 0) { + int addr = 0144 + eb_ptr; + uint64 word; + + (void)Mem_examine_word(0, dte_et11_off + PRI_CMTW_STS, &word); + addr = (M[addr+1] + dte_off + PRI_CMTW_KAC) & RMASK; + word = M[addr]; + word = (word + 1) & FMASK; + M[addr] = word; + sim_debug(DEBUG_EXP, &dte_dev, "CTY keepalive %06o %012llo %06o\n", + addr, word, optr->STATUS); + } + + return SCPE_OK; +} + + +t_stat dte_reset (DEVICE *dptr) +{ + dte_unit[0].STATUS = DTE_SEC; + dte_unit[1].STATUS = 0; + dte_unit[2].STATUS = 0; + dte_unit[3].STATUS = 0; + cty_done = 0; + sim_rtcn_init_unit (&dte_unit[3], 1000, TMR_RTC); + sim_activate(&dte_unit[3], 1000); + sim_activate(&dte_unit[2], 1000); + return SCPE_OK; +} + + +t_stat +dte_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) + return SCPE_IERR; + dptr->flags &= ~DEV_M_OS; + dptr->flags |= val; + return SCPE_OK; +} + +t_stat +dte_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + DEVICE *dptr; + + if (uptr == NULL) + return SCPE_IERR; + + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + fprintf (st, "%s", (dptr->flags & TYPE_RSX20) ? "RSX20" : "RSX10"); + return SCPE_OK; +} + + +/* Stop operating system */ + +t_stat dte_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + M[CTY_SWITCH] = 1; /* tell OS to stop */ + return SCPE_OK; +} + +t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + dte_unit[0].flags = (dte_unit[0].flags & ~TT_MODE) | val; + return SCPE_OK; +} + +t_stat dte_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "To stop the cpu use the command:\n\n"); +fprintf (st, " sim> SET CTY STOP\n\n"); +fprintf (st, "This will write a 1 to location %03o, causing TOPS10 to stop\n\n", CTY_SWITCH); +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, &dte_dev); +return SCPE_OK; +} + +const char *dte_description (DEVICE *dptr) +{ + return "Console TTY Line"; +} + + +#if (NUM_DEVS_LP20 > 0) + +void +lp20_printline(UNIT *uptr, int nl) { + int trim = 0; + uint16 data1 = 1; + /* Trim off trailing blanks */ + while (uptr->COL >= 0 && lp20_buffer[uptr->COL - 1] == ' ') { + uptr->COL--; + trim = 1; + } + lp20_buffer[uptr->COL] = '\0'; + sim_debug(DEBUG_DETAIL, &lp20_dev, "LP output %d %d [%s]\n", uptr->COL, nl, + lp20_buffer); + /* Stick a carraige return and linefeed as needed */ + if (uptr->COL != 0 || trim) + lp20_buffer[uptr->COL++] = '\r'; + if (nl != 0) { + lp20_buffer[uptr->COL++] = '\n'; + uptr->LINE++; + } + if (nl > 0 && lp20_vfu[uptr->LINE] == 010000) { + lp20_buffer[uptr->COL++] = '\f'; + uptr->LINE = 1; + } else if (nl < 0 && uptr->LINE >= (int32)uptr->capac) { + uptr->LINE = 1; + } + + sim_fwrite(&lp20_buffer, 1, uptr->COL, uptr->fileref); + uptr->pos += uptr->COL; + uptr->COL = 0; + return; +} + + +/* Unit service */ +void +lp20_output(UNIT *uptr, char c) { + + if (c == 0) + return; + if (uptr->COL == 132) + lp20_printline(uptr, 1); + if ((uptr->flags & UNIT_UC) && (c & 0140) == 0140) + c &= 0137; + else if (c >= 040 && c < 0177) { /* If printable */ + lp20_buffer[uptr->COL++] = c; + } if (c == 011) { /* Tab */ + lp20_buffer[uptr->COL++] = ' '; + while ((uptr->COL & 07) != 0) + lp20_buffer[uptr->COL++] = ' '; + } + return; +} + +t_stat lp20_svc (UNIT *uptr) +{ + char ch; + uint16 ram_ch; + uint16 data1[5]; + int l = uptr->LINE; + + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_OK; + if (dte_dev.flags & TYPE_RSX20 && uptr->LPST & HDSFLG) { + data1[0] = 0; + + data1[1] = (uptr->LINE == 1) ? 01<<8: 0; + sim_debug(DEBUG_DETAIL, &dte_dev, "LPT status %06o \n", uptr->LPST); + if (uptr->LPST & EOFFLG) { + data1[0] |= 040 << 8; + uptr->LPCNT = 0; + } + if (uptr->LPST & INTFLG) { + data1[1] |= 02 << 8; + uptr->LPCNT = 0; + } + data1[2] = 0110200; //0100220; + if (dte_queue(PRI_EMHDS+PRI_IND_FLG, PRI_EMLPT, 4, data1) == 0) + sim_activate(uptr, 1000); + uptr->LPST &= ~(HDSFLG); + } + + if (empty(&lp20_queue)) + return SCPE_OK; + while (not_empty(&lp20_queue)) { + ch = lp20_queue.buff[lp20_queue.out_ptr]; + inco(&lp20_queue); + ram_ch = lp20_ram[ch]; + + /* If previous was delimiter or translation do it */ + if (uptr->LPST & DELFLG || (ram_ch &(LP20_RAM_DEL|LP20_RAM_TRN)) != 0) { + ch = ram_ch & LP20_RAM_CHR; + uptr->LPST &= ~DELFLG; + if (ram_ch & LP20_RAM_DEL) + uptr->LPST |= DELFLG; + } + /* Flag if interrupt set */ + if (ram_ch & LP20_RAM_INT) + uptr->LPST |= HDSFLG|INTFLG; + /* Check if paper motion */ + if (ram_ch & LP20_RAM_PI) { + int lines = 0; /* Number of new lines to output */ + /* Print any buffered line */ + lp20_printline(uptr, (ram_ch & 037) != 020); + sim_debug(DEBUG_DETAIL, &lp20_dev, "LP deque %02x %04x\n", + ch, ram_ch); + if ((ram_ch & 020) == 0) { /* Find channel mark in output */ + while ((lp20_vfu[uptr->LINE] & (1 << (ram_ch & 017))) == 0) { + sim_debug(DEBUG_DETAIL, &lp20_dev, + "LP skip chan %04x %04x %d\n", + lp20_vfu[uptr->LINE], ram_ch, uptr->LINE); + if (lp20_vfu[uptr->LINE] & 010000) { /* Hit bottom of form */ + sim_fwrite("\014", 1, 1, uptr->fileref); + uptr->pos++; + lines = 0; + uptr->LINE = 1; + break; + } + lines++; + uptr->LINE++; + } + } else { + while ((ram_ch & 017) != 0) { + sim_debug(DEBUG_DETAIL, &lp20_dev, + "LP skip line %04x %04x %d\n", + lp20_vfu[uptr->LINE], ram_ch, uptr->LINE); + if (lp20_vfu[uptr->LINE] & 010000) { /* Hit bottom of form */ + sim_fwrite("\014", 1, 1, uptr->fileref); + uptr->pos++; + lines = 0; + uptr->LINE = 1; + } + lines++; + uptr->LINE++; + ram_ch--; + } + } + for(;lines > 0; lines--) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->pos+=2; + } + } else if (ch != 0) { + sim_debug(DEBUG_DETAIL, &lp20_dev, "LP deque %02x '%c' %04x\n", + ch, ch, ram_ch); + lp20_output(uptr, ch); + } + } + if (empty(&lp20_queue)) { + data1[0] = 0; + if (dte_queue(PRI_EMLBE, PRI_EMLPT, 1, data1) == 0) + sim_activate(uptr, 1000); + if (dte_dev.flags & TYPE_RSX20) { + if (uptr->LINE == 0) { + uptr->LPST |= HDSFLG; + sim_activate(uptr, 1000); + } + } + } + return SCPE_OK; +} + +/* Reset routine */ + +t_stat lp20_reset (DEVICE *dptr) +{ + UNIT *uptr = &lp20_unit; + int i; + uptr->POS = 0; + uptr->COL = 0; + uptr->LINE = 1; + /* Clear RAM & VFU */ + for (i = 0; i < 256; i++) { + lp20_ram[i] = 0; + lp20_vfu[i] = 0; + } + + /* Load default VFU into VFU */ + memcpy(&lp20_vfu, lp20_dvfu, sizeof(lp20_dvfu)); + lp20_ram[012] = LP20_RAM_TRN|LP20_RAM_PI|7; /* Line feed, print line, space one line */ + lp20_ram[013] = LP20_RAM_TRN|LP20_RAM_PI|6; /* Vertical tab, Skip mod 20 */ + lp20_ram[014] = LP20_RAM_TRN|LP20_RAM_PI|0; /* Form feed, skip to top of page */ + lp20_ram[015] = LP20_RAM_TRN|LP20_RAM_PI|020; /* Carrage return */ + lp20_ram[020] = LP20_RAM_TRN|LP20_RAM_PI|1; /* Skip half page */ + lp20_ram[021] = LP20_RAM_TRN|LP20_RAM_PI|2; /* Skip even lines */ + lp20_ram[022] = LP20_RAM_TRN|LP20_RAM_PI|3; /* Skip triple lines */ + lp20_ram[023] = LP20_RAM_TRN|LP20_RAM_PI|4; /* Skip one line */ + lp20_ram[024] = LP20_RAM_TRN|LP20_RAM_PI|5; + sim_cancel (&lp20_unit); /* deactivate unit */ + return SCPE_OK; +} + +/* Attach routine */ + +t_stat lp20_attach (UNIT *uptr, CONST char *cptr) +{ + return attach_unit (uptr, cptr); +} + +/* Detach routine */ + +t_stat lp20_detach (UNIT *uptr) +{ + return detach_unit (uptr); +} + +/* + * Line printer routines + */ + +t_stat +lp20_setlpp(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + t_value i; + t_stat r; + if (cptr == NULL) + return SCPE_ARG; + if (uptr == NULL) + return SCPE_IERR; + i = get_uint (cptr, 10, 100, &r); + if (r != SCPE_OK) + return SCPE_ARG; + uptr->capac = (t_addr)i; + uptr->LINE = 0; + return SCPE_OK; +} + +t_stat +lp20_getlpp(FILE *st, UNIT *uptr, int32 v, CONST void *desc) +{ + if (uptr == NULL) + return SCPE_IERR; + fprintf(st, "linesperpage=%d", uptr->capac); + return SCPE_OK; +} + +t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr) +{ +fprintf (st, "Line Printer (LPT)\n\n"); +fprintf (st, "The line printer (LPT) writes data to a disk file. The POS register specifies\n"); +fprintf (st, "the number of the next data item to be written. Thus, by changing POS, the\n"); +fprintf (st, "user can backspace or advance the printer.\n"); +fprintf (st, "The Line printer can be configured to any number of lines per page with the:\n"); +fprintf (st, " sim> SET %s0 LINESPERPAGE=n\n\n", dptr->name); +fprintf (st, "The default is 66 lines per page.\n\n"); +fprintf (st, "The device address of the Line printer can be changed\n"); +fprintf (st, " sim> SET %s0 DEV=n\n\n", dptr->name); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +const char *lp20_description (DEVICE *dptr) +{ + return "LP20 line printer" ; +} + +#endif + +#if (NUM_DEVS_TTY > 0) + +/* Unit service */ +t_stat ttyi_svc (UNIT *uptr) +{ + int32 ln; + TMLN *lp; + int flg; + + if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; + + sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */ + + /* If we have room see if any new lines */ + ln = tmxr_poll_conn (&tty_desc); /* look for connect */ + if (ln >= 0) { + tty_ldsc[ln].rcve = 1; + sim_debug(DEBUG_DETAIL, &tty_dev, "TTY line connect %d\n", ln); + } + + tmxr_poll_tx(&tty_desc); + tmxr_poll_rx(&tty_desc); + + /* Scan each line for input */ + for (ln = 0; ln < tty_desc.lines; ln++) { + struct _buffer *iptr = &tty_in[ln]; + lp = &tty_ldsc[ln]; + if (lp->conn == 0) + continue; + flg = 1; + while (flg && !full(iptr)) { + /* Spool up as much as we have room for */ + int32 ch = tmxr_getc_ln(lp); + if ((ch & TMXR_VALID) != 0) { + ch = sim_tt_inpcvt (ch, + TT_GET_MODE(tty_unit[0].flags) | TTUF_KSR); + iptr->buff[iptr->in_ptr] = ch & 0377; + inci(iptr); + sim_debug(DEBUG_DETAIL, &tty_dev, "TTY recieve %d: %o\n", + ln, ch); + } else + flg = 0; + } + } + + return SCPE_OK; +} + +/* Output whatever we can */ +t_stat ttyo_svc (UNIT *uptr) +{ + t_stat r; + int32 ln; + int n = 0; + TMLN *lp; + + if ((tty_unit[0].flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; + + sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */ + + for (ln = 0; ln < tty_desc.lines; ln++) { + struct _buffer *optr = &tty_out[ln]; + lp = &tty_ldsc[ln]; + if (lp->conn == 0) { + if (not_empty(optr)) { + optr->out_ptr = optr->in_ptr = 0; + tty_done[ln] = 1; + } + continue; + } + if (empty(optr)) + continue; + while (not_empty(optr)) { + int32 ch = optr->buff[optr->out_ptr]; + ch = sim_tt_outcvt(ch, TT_GET_MODE (tty_unit[0].flags) | TTUF_KSR); + sim_debug(DEBUG_DATA, &tty_dev, "TTY: %d output %o\n", ln, ch); + r = tmxr_putc_ln (lp, ch); + if (r == SCPE_OK) + inco(optr); + else if (r == SCPE_LOST) { + optr->out_ptr = optr->in_ptr = 0; + continue; + } else + continue; + } + tty_done[ln] = 1; + } + return SCPE_OK; +} + +/* Reset routine */ + +t_stat tty_reset (DEVICE *dptr) +{ + return SCPE_OK; +} + + +/* SET LINES processor */ + +t_stat tty_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + int32 newln, i, t; + t_stat r; + + if (cptr == NULL) + return SCPE_ARG; + newln = (int32) get_uint (cptr, 10, NUM_LINES_TTY, &r); + if ((r != SCPE_OK) || (newln == tty_desc.lines)) + return r; + if ((newln == 0) || (newln >= NUM_LINES_TTY) || (newln % 16) != 0) + return SCPE_ARG; + if (newln < tty_desc.lines) { + for (i = newln, t = 0; i < tty_desc.lines; i++) + t = t | tty_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < tty_desc.lines; i++) { + if (tty_ldsc[i].conn) { + tmxr_linemsg (&tty_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_send_buffered_data (&tty_ldsc[i]); + } + tmxr_detach_ln (&tty_ldsc[i]); /* completely reset line */ + } + } + if (tty_desc.lines < newln) + memset (tty_ldsc + tty_desc.lines, 0, + sizeof(*tty_ldsc)*(newln-tty_desc.lines)); + tty_desc.lines = newln; + return tty_reset (&tty_dev); /* setup lines and auto config */ +} + +/* SET LOG processor */ + +t_stat tty_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + t_stat r; + char gbuf[CBUFSIZE]; + int32 ln; + + if (cptr == NULL) + return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, '='); + if ((cptr == NULL) || (*cptr == 0) || (gbuf[0] == 0)) + return SCPE_ARG; + ln = (int32) get_uint (gbuf, 10, tty_desc.lines, &r); + if ((r != SCPE_OK) || (ln >= tty_desc.lines)) + return SCPE_ARG; + return tmxr_set_log (NULL, ln, cptr, desc); +} + +/* SET NOLOG processor */ + +t_stat tty_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + t_stat r; + int32 ln; + + if (cptr == NULL) + return SCPE_ARG; + ln = (int32) get_uint (cptr, 10, tty_desc.lines, &r); + if ((r != SCPE_OK) || (ln >= tty_desc.lines)) + return SCPE_ARG; + return tmxr_set_nolog (NULL, ln, NULL, desc); +} + +/* SHOW LOG processor */ + +t_stat tty_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + int32 i; + + for (i = 0; i < tty_desc.lines; i++) { + fprintf (st, "line %d: ", i); + tmxr_show_log (st, NULL, i, desc); + fprintf (st, "\n"); + } + return SCPE_OK; +} + + +/* Attach routine */ + +t_stat tty_attach (UNIT *uptr, CONST char *cptr) +{ +t_stat reason; + +reason = tmxr_attach (&tty_desc, uptr, cptr); +if (reason != SCPE_OK) + return reason; +sim_activate (uptr, tmxr_poll); +return SCPE_OK; +} + +/* Detach routine */ + +t_stat tty_detach (UNIT *uptr) +{ + int32 i; + t_stat reason; +reason = tmxr_detach (&tty_desc, uptr); +for (i = 0; i < tty_desc.lines; i++) + tty_ldsc[i].rcve = 0; +sim_cancel (uptr); +return reason; +} + +t_stat tty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "DC10E Terminal Interfaces\n\n"); +fprintf (st, "The DC10 supported up to 8 blocks of 8 lines. Modem control was on a seperate\n"); +fprintf (st, "line. The simulator supports this by setting modem control to a fixed offset\n"); +fprintf (st, "from the given line. The number of lines is specified with a SET command:\n\n"); +fprintf (st, " sim> SET DC LINES=n set number of additional lines to n [8-32]\n\n"); +fprintf (st, "Lines must be set in multiples of 8.\n"); +fprintf (st, "The default offset for modem lines is 32. This can be changed with\n\n"); +fprintf (st, " sim> SET DC MODEM=n set offset for modem control to n [8-32]\n\n"); +fprintf (st, "Modem control must be set larger then the number of lines\n"); +fprintf (st, "The ATTACH command specifies the port to be used:\n\n"); +tmxr_attach_help (st, dptr, uptr, flag, 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.\n"); +fprintf (st, "Finally, each line supports output logging. The SET DCn LOG command enables\n"); +fprintf (st, "logging on a line:\n\n"); +fprintf (st, " sim> SET DCn LOG=filename log output of line n to filename\n\n"); +fprintf (st, "The SET DCn NOLOG command disables logging and closes the open log file,\n"); +fprintf (st, "if any.\n\n"); +fprintf (st, "Once DC is attached and the simulator is running, the terminals listen for\n"); +fprintf (st, "connections on the specified port. They assume that the incoming connections\n"); +fprintf (st, "are Telnet connections. The connections remain open until disconnected either\n"); +fprintf (st, "by the Telnet client, a SET DC DISCONNECT command, or a DETACH DC command.\n\n"); +fprintf (st, "Other special commands:\n\n"); +fprintf (st, " sim> SHOW DC CONNECTIONS show current connections\n"); +fprintf (st, " sim> SHOW DC STATISTICS show statistics for active connections\n"); +fprintf (st, " sim> SET DCn DISCONNECT disconnects the specified line.\n"); +fprint_reg_help (st, &tty_dev); +fprintf (st, "\nThe additional terminals do not support save and restore. All open connections\n"); +fprintf (st, "are lost when the simulator shuts down or DC is detached.\n"); +return SCPE_OK; +} + +const char *tty_description (DEVICE *dptr) +{ +return "DC10E asynchronous line interface"; +} + +#endif +#endif diff --git a/PDP10/kl10_nia.c b/PDP10/kl10_nia.c new file mode 100644 index 0000000..8456409 --- /dev/null +++ b/PDP10/kl10_nia.c @@ -0,0 +1,1672 @@ +/* kl10_NIA.c: NIA 20 Network interface. + + Copyright (c) 2019, 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. + + This emulates the MIT-AI/ML/MC Host/IMP interface. +*/ + + +#include "kx10_defs.h" +#include "sim_ether.h" + +#if NUM_DEVS_NIA > 0 +#define NIA_DEVNUM (0540 + (5 * 4)) + +/* NIA Bits */ + +/* CONI */ +#define NIA_PPT 0400000000000LL /* Port present */ +#define NIA_DCC 0100000000000LL /* Diag CSR */ +#define NIA_CPE 0004000000000LL /* CRAM Parity error */ +#define NIA_MBE 0002000000000LL /* MBUS error */ +#define NIA_ILD 0000100000000LL /* Idle */ +#define NIA_DCP 0000040000000LL /* Disable complete */ +#define NIA_ECP 0000020000000LL /* Enable complete */ +#define NIA_PID 0000007000000LL /* Port ID */ + +/* CONO/ CONI */ +#define NIA_CPT 0000000400000LL /* Clear Port */ +#define NIA_SEB 0000000200000LL /* Diag Select EBUF */ +#define NIA_GEB 0000000100000LL /* Diag Gen Ebus PE */ +#define NIA_LAR 0000000040000LL /* Diag select LAR */ +#define NIA_SSC 0000000020000LL /* Diag Single Cycle */ +#define NIA_EPE 0000000004000LL /* Ebus parity error */ +#define NIA_FQE 0000000002000LL /* Free Queue Error */ +#define NIA_DME 0000000001000LL /* Data mover error */ +#define NIA_CQA 0000000000400LL /* Command Queue Available */ +#define NIA_RQA 0000000000200LL /* Response Queue Available */ +#define NIA_DIS 0000000000040LL /* Disable */ +#define NIA_ENB 0000000000020LL /* Enable */ +#define NIA_MRN 0000000000010LL /* RUN */ +#define NIA_PIA 0000000000007LL /* PIA */ + +#define NIA_LRA 0400000000000LL /* Load Ram address */ +#define NIA_RAR 0377760000000LL /* Microcode address mask */ +#define NIA_MSB 0000020000000LL /* Half word select */ + +/* PCB Offsets */ +#define PCB_CQI 0 /* Command queue interlock */ +#define PCB_CQF 1 /* Command queue flink */ +#define PCB_CQB 2 /* Command queue blink */ +#define PCB_RS0 3 /* Reserved */ +#define PCB_RSI 4 /* Response queue interlock */ +#define PCB_RSF 5 /* Response queue flink */ +#define PCB_RSB 6 /* Response queue blink */ +#define PCB_RS1 7 /* Reserved */ +#define PCB_UPI 010 /* Unknown protocol queue interlock */ +#define PCB_UPF 011 /* Unknown protocol queue flink */ +#define PCB_UPB 012 /* Unknown protocol queue blink */ +#define PCB_UPL 013 /* Unknown protocol queue length */ +#define PCB_RS2 014 /* Reserved */ +#define PCB_PTT 015 /* Protocol Type Table */ +#define PCB_MCT 016 /* Multicast Table */ +#define PCB_RS3 017 /* Reserved */ +#define PCB_ER0 020 /* Error Log out 0 */ +#define PCB_ER1 021 /* Error Log out 1 */ +#define PCB_EPA 022 /* EPT Channel logout word 1 address */ +#define PCB_EPW 023 /* EPT Channel logout word 1 contents */ +#define PCB_PCB 024 /* PCB Base Address */ +#define PCB_PIA 025 /* PIA */ +#define PCB_RS4 026 /* Reserved */ +#define PCB_CCW 027 /* Channel command word */ +#define PCB_RCB 030 /* Counters base address */ + +#define CHNERR 07762 +#define SLFTST 07751 +#define INTERR 07750 +#define EBSERR 07752 + +/* 12 Bit Shift */ +#define NIA_CMD_SND 0001 /* Send a datagram */ +#define NIA_CMD_LMAC 0002 /* Load Multicast table */ +#define NIA_CMD_LPTT 0003 /* Load Protocol Type table */ +#define NIA_CMD_RCNT 0004 /* Read counts */ +#define NIA_CMD_RCV 0005 /* Received datagram */ +#define NIA_CMD_WPLI 0006 /* Write PLI */ +#define NIA_CMD_RPLI 0007 /* Read PLI */ +#define NIA_CMD_RNSA 0010 /* Read Station Address */ +#define NIA_CMD_WNSA 0011 /* Write Station Address */ + +/* 20 Bit shift */ +#define NIA_FLG_RESP 0001 /* Command wants a response */ +#define NIA_FLG_CLRC 0002 /* Clear counters (Read counters) */ +#define NIA_FLG_BSD 0010 /* Send BSD packet */ +#define NIA_FLG_PAD 0040 /* Send pad */ +#define NIA_FLG_ICRC 0100 /* Send use host CRC */ +#define NIA_FLG_PACK 0200 /* Send Pack */ +#define NIA_STS_CPE 0200 /* CRAM PE */ +#define NIA_STS_SR 0100 /* Send receive */ +#define NIA_STS_ERR 0001 /* Error bits valid */ + +/* 28 bit shift ERR +1 */ +#define NIA_ERR_ECL 000 /* Excessive collisions */ +#define NIA_ERR_CAR 001 /* Carrier check failed */ +#define NIA_ERR_COL 002 /* Collision detect failed */ +#define NIA_ERR_SHT 003 /* Short circuit */ +#define NIA_ERR_OPN 004 /* Open circuit */ +#define NIA_ERR_LNG 005 /* Frame to long */ +#define NIA_ERR_RMT 006 /* Remote failure */ +#define NIA_ERR_BLK 007 /* Block check error */ +#define NIA_ERR_FRM 010 /* Framing error */ +#define NIA_ERR_OVR 011 /* Data Overrun */ +#define NIA_ERR_PRO 012 /* Unrecongized protocol */ +#define NIA_ERR_RUN 013 /* Frame too short */ +#define NIA_ERR_WCZ 030 /* Word count not zero */ +#define NIA_ERR_QLV 031 /* Queue length violation */ +#define NIA_ERR_PLI 032 /* Illegal PLI function */ +#define NIA_ERR_UNK 033 /* Unknown command */ +#define NIA_ERR_BLV 034 /* Buffer length violation */ +#define NIA_ERR_PAR 036 /* Parity error */ +#define NIA_ERR_INT 037 /* Internal error */ + +/* Counters */ +#define NIA_CNT_BR 000 /* Bytes received */ +#define NIA_CNT_BX 001 /* Bytes transmitted */ +#define NIA_CNT_FR 002 /* Frames received */ +#define NIA_CNT_FX 003 /* Frames transmitted */ +#define NIA_CNT_MCB 004 /* Multicast bytes received */ +#define NIA_CNT_MCF 005 /* Multicast frames received */ +#define NIA_CNT_FXD 006 /* Frames xmitted, initially deferred */ +#define NIA_CNT_FXS 007 /* Frames xmitted, single collision */ +#define NIA_CNT_FXM 010 /* Frames xmitted, multiple collisions */ +#define NIA_CNT_XF 011 /* Transmit failures */ +#define NIA_CNT_XFM 012 /* Transmit failure bit mask */ +#define NIA_XFM_LOC 04000 /* B24 - Loss of carrier */ +#define NIA_XFM_XBP 02000 /* B25 - Xmit buffer parity error */ +#define NIA_XFM_RFD 01000 /* B26 - Remote failure to defer */ +#define NIA_XFM_XFL 00400 /* B27 - Xmitted frame too long */ +#define NIA_XFM_OC 00200 /* B28 - Open circuit */ +#define NIA_XFM_SC 00100 /* B29 - Short circuit */ +#define NIA_XFM_CCF 00040 /* B30 - Collision detect check failed */ +#define NIA_XFM_EXC 00020 /* B31 - Excessive collisions */ + +#define NIA_CNT_CDF 013 /* Carrier detect check failed */ +#define NIA_CNT_RF 014 /* Receive failures */ +#define NIA_CNT_RFM 015 /* Receive failure bit mask */ +#define NIA_RFM_FLE 0400 /* B27 - free list parity error */ +#define NIA_RFM_NFB 0200 /* B28 - no free buffers */ +#define NIA_RFM_FTL 0100 /* B29 - frame too long */ +#define NIA_RFM_FER 0040 /* B30 - framing error */ +#define NIA_RFM_BCE 0020 /* B31 - block check error */ + +#define NIA_CNT_DUN 016 /* Discarded unknown */ +#define NIA_CNT_D01 017 /* Discarded position 1 */ +#define NIA_CNT_D02 020 /* Discarded position 2 */ +#define NIA_CNT_D03 021 /* Discarded position 3 */ +#define NIA_CNT_D04 022 /* Discarded position 4 */ +#define NIA_CNT_D05 023 /* Discarded position 5 */ +#define NIA_CNT_D06 024 /* Discarded position 6 */ +#define NIA_CNT_D07 025 /* Discarded position 7 */ +#define NIA_CNT_D08 026 /* Discarded position 8 */ +#define NIA_CNT_D09 027 /* Discarded position 9 */ +#define NIA_CNT_D10 030 /* Discarded position 10 */ +#define NIA_CNT_D11 031 /* Discarded position 11 */ +#define NIA_CNT_D12 032 /* Discarded position 12 */ +#define NIA_CNT_D13 033 /* Discarded position 13 */ +#define NIA_CNT_D14 034 /* Discarded position 14 */ +#define NIA_CNT_D15 035 /* Discarded position 15 */ +#define NIA_CNT_D16 036 /* Discarded position 16 */ +#define NIA_CNT_UFD 037 /* Unrecognized frame dest */ +#define NIA_CNT_DOV 040 /* Data overrun */ +#define NIA_CNT_SBU 041 /* System buffer unavailable */ +#define NIA_CNT_UBU 042 /* User buffer unavailable */ +#define NIA_CNT_RS0 043 /* Pli reg rd par error,,pli parity error */ +#define NIA_CNT_RS1 044 /* Mover parity error,,cbus parity error */ +#define NIA_CNT_RS2 045 /* Ebus parity error,,ebus que parity error */ +#define NIA_CNT_RS3 046 /* Channel error,,spur channel error */ +#define NIA_CNT_RS4 047 /* Spur xmit attn error,,cbus req timout error */ +#define NIA_CNT_RS5 050 /* Ebus req timeout error,,csr grnt timeout error */ +#define NIA_CNT_RS6 051 /* Used buff parity error,,xmit buff parity error */ +#define NIA_CNT_RS7 052 /* Reserved for ucode */ +#define NIA_CNT_RS8 053 /* Reserved for ucode */ +#define NIA_CNT_LEN 054 /* # of counters */ + +#ifdef _MSC_VER +# define PACKED_BEGIN __pragma( pack(push, 1) ) +# define PACKED_END __pragma( pack(pop) ) +# define QEMU_PACKED +#else +# define PACKED_BEGIN +#if defined(_WIN32) +# define PACKED_END __attribute__((gcc_struct, packed)) +# define QEMU_PACKED __attribute__((gcc_struct, packed)) +#else +# define PACKED_END __attribute__((packed)) +# define QEMU_PACKED __attribute__((packed)) +#endif +#endif + +typedef uint32 in_addr_T; + +#define ETHTYPE_ARP 0x0806 +#define ETHTYPE_IP 0x0800 + +PACKED_BEGIN +struct nia_eth_hdr { + ETH_MAC dest; + ETH_MAC src; + uint16 type; +} PACKED_END; + +/* + * Structure of an internet header, naked of options. + */ +PACKED_BEGIN +struct ip { + uint8 ip_v_hl; /* version,header length */ + uint8 ip_tos; /* type of service */ + uint16 ip_len; /* total length */ + uint16 ip_id; /* identification */ + uint16 ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + uint8 ip_ttl; /* time to live */ + uint8 ip_p; /* protocol */ + uint16 ip_sum; /* checksum */ + in_addr_T ip_src; + in_addr_T ip_dst; /* source and dest address */ +} PACKED_END; + +#define TCP_PROTO 6 +PACKED_BEGIN +struct tcp { + uint16 tcp_sport; /* Source port */ + uint16 tcp_dport; /* Destination port */ + uint32 seq; /* Sequence number */ + uint32 ack; /* Ack number */ + uint16 flags; /* Flags */ +#define TCP_FL_FIN 0x01 +#define TCP_FL_SYN 0x02 +#define TCP_FL_RST 0x04 +#define TCP_FL_PSH 0x08 +#define TCP_FL_ACK 0x10 +#define TCP_FL_URG 0x20 + uint16 window; /* Window size */ + uint16 chksum; /* packet checksum */ + uint16 urgent; /* Urgent pointer */ +} PACKED_END; + +#define UDP_PROTO 17 +PACKED_BEGIN +struct udp { + uint16 udp_sport; /* Source port */ + uint16 udp_dport; /* Destination port */ + uint16 len; /* Length */ + uint16 chksum; /* packet checksum */ +} PACKED_END; + +PACKED_BEGIN +struct udp_hdr { + in_addr_T ip_src; + in_addr_T ip_dst; /* source and dest address */ + uint8 zero; + uint8 proto; /* Protocol */ + uint16 hlen; /* Length of header and data */ +} PACKED_END; + +#define ICMP_PROTO 1 +PACKED_BEGIN +struct icmp { + uint8 type; /* Type of packet */ + uint8 code; /* Code */ + uint16 chksum; /* packet checksum */ +} PACKED_END; + +PACKED_BEGIN +struct ip_hdr { + struct nia_eth_hdr ethhdr; + struct ip iphdr; +} PACKED_END; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 +#define ARP_HWTYPE_ETH 1 + +PACKED_BEGIN +struct arp_hdr { + struct nia_eth_hdr ethhdr; + uint16 hwtype; + uint16 protocol; + uint8 hwlen; + uint8 protolen; + uint16 opcode; + ETH_MAC shwaddr; + in_addr_T sipaddr; + ETH_MAC dhwaddr; + in_addr_T dipaddr; + uint8 padding[18]; +} PACKED_END; + +struct nia_device { + ETH_PCALLBACK rcallback; /* read callback routine */ + ETH_PCALLBACK wcallback; /* write callback routine */ + ETH_MAC mac; /* Hardware MAC addresses */ + ETH_DEV etherface; + ETH_QUE ReadQ; + ETH_PACK rec_buff; /* Buffer for recieved packet */ + ETH_PACK snd_buff; /* Buffer for sending packet */ + t_addr cmd_entry; /* Pointer to current command entry */ + t_addr cmd_rply; /* Pointer to reply entry */ + uint8 cmd_status; /* Status feild of current command */ + t_addr rec_entry; /* Pointer to current recieve entry */ + t_addr pcb; /* Address of PCB */ + t_addr rcb; /* Read count buffer address */ +#define cmd_hdr pcb /* Command queue is at PCB */ + t_addr resp_hdr; /* Head of response queue */ + t_addr unk_hdr; /* Unknown protocol free queue */ + int unk_len; /* Length of Unknown entries */ + t_addr ptt_addr; /* Address of Protocol table */ + t_addr mcast_addr; /* Address of Multicast table */ + int pia; /* Interrupt channel */ + t_addr cnt_addr; /* Address of counters */ + uint64 pcnt[NIA_CNT_LEN]; /* Counters */ + + int ptt_n; /* Number of Protocol entries */ + uint16 ptt_proto[17]; /* Protocol for entry */ + t_addr ptt_head[17]; /* Head of protocol queue */ + int macs_n; /* Number of multi-cast addresses */ + ETH_MAC macs[20]; /* Watched Multi-cast addresses */ + int amc; /* Recieve all multicast packets */ + int prmsc; /* Recieve all packets */ + int h4000; /* Heart beat detection */ + int rar; + uint64 ebuf; + uint64 status; /* Status of device. */ + uint32 uver[4]; /* Version information */ + int r_pkt; /* Packet pending */ +} nia_data; + + +extern int32 tmxr_poll; + +static CONST ETH_MAC broadcast_ethaddr = {0xff,0xff,0xff,0xff,0xff,0xff}; + +t_stat nia_devio(uint32 dev, uint64 *data); +void nia_start(); +void nia_stop(); +void nia_enable(); +void nia_disable(); +void nia_load_ptt(); +void nia_load_mcast(); +void nia_error(int); +t_stat nia_eth_srv(UNIT *); +t_stat nia_rec_srv(UNIT *); +t_stat nia_cmd_srv(UNIT *); +t_stat nia_reset (DEVICE *dptr); +t_stat nia_show_mac (FILE* st, UNIT* uptr, int32 val, CONST void* desc); +t_stat nia_set_mac (UNIT* uptr, int32 val, CONST char* cptr, void* desc); +t_stat nia_attach (UNIT * uptr, CONST char * cptr); +t_stat nia_detach (UNIT * uptr); +t_stat nia_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); +const char *nia_description (DEVICE *dptr); + +struct rh_if nia_rh = { NULL, NULL, NULL}; + +UNIT nia_unit[] = { + {UDATA(nia_eth_srv, UNIT_IDLE+UNIT_ATTABLE, 0)}, /* 0 */ + {UDATA(nia_rec_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 1 */ + {UDATA(nia_cmd_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 2 */ +}; + +REG nia_reg[] = { + {BRDATA(DATA, &nia_data, 16, 8, sizeof(struct nia_device)), REG_HRO}, + {0} +}; + + +#define nia_cmd_uptr (&nia_unit[2]) /* Unit for processing commands */ +#define nia_recv_uptr (&nia_unit[0]) /* Unit doing receive digestion */ +#define nia_proc_uptr (&nia_unit[1]) /* Unit doing receive dispatching */ + +DIB nia_dib = {NIA_DEVNUM | RH20_DEV, 1, &nia_devio, NULL, &nia_rh }; + +MTAB nia_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", + &nia_set_mac, &nia_show_mac, NULL, "MAC address" }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "ETH", NULL, NULL, + ð_show, NULL, "Display attachedable devices" }, + { 0 } + }; + +/* Simulator debug controls */ +DEBTAB nia_debug[] = { + {"CMD", DEBUG_CMD, "Show command execution to devices"}, + {"DATA", DEBUG_DATA, "Show data transfers"}, + {"DETAIL", DEBUG_DETAIL, "Show details about device"}, + {"EXP", DEBUG_EXP, "Show exception information"}, + {"CONI", DEBUG_CONI, "Show coni instructions"}, + {"CONO", DEBUG_CONO, "Show coni instructions"}, + {"DATAIO", DEBUG_DATAIO, "Show datai and datao instructions"}, + {"IRQ", DEBUG_IRQ, "Show IRQ requests"}, +#define DEBUG_ARP (DEBUG_IRQ<<1) + {"ARP", DEBUG_ARP, "Show ARP activities"}, +#define DEBUG_TCP (DEBUG_ARP<<1) + {"TCP", DEBUG_TCP, "Show TCP packet activities"}, +#define DEBUG_UDP (DEBUG_TCP<<1) + {"UDP", DEBUG_UDP, "Show UDP packet activities"}, +#define DEBUG_ICMP (DEBUG_UDP<<1) + {"ICMP", DEBUG_ICMP, "Show ICMP packet activities"}, +#define DEBUG_ETHER (DEBUG_ICMP<<1) + {"ETHER", DEBUG_ETHER, "Show ETHER activities"}, + {0, 0} +}; + +DEVICE nia_dev = { + "NI", nia_unit, nia_reg, nia_mod, + 3, 8, 0, 1, 8, 36, + NULL, NULL, &nia_reset, NULL, &nia_attach, &nia_detach, + &nia_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, nia_debug, + NULL, NULL, &nia_help, NULL, NULL, &nia_description +}; + +t_stat nia_devio(uint32 dev, uint64 *data) +{ + DEVICE *dptr = &nia_dev; + UNIT *uptr = nia_cmd_uptr; + + switch(dev & 03) { + case CONO: + if (*data & NIA_CPT) + nia_reset(dptr); + + nia_data.status &= ~(NIA_SEB|NIA_LAR|NIA_SSC|NIA_DIS|NIA_ENB|NIA_PIA); + nia_data.status |= *data & (NIA_SEB|NIA_LAR|NIA_SSC|NIA_DIS|NIA_ENB|NIA_PIA); + nia_data.status &= ~(*data & (NIA_EPE|NIA_FQE|NIA_DME|NIA_RQA)); + clr_interrupt(NIA_DEVNUM); + if (*data & NIA_MRN) { + if ((nia_data.status & NIA_MRN) == 0) + nia_start(); + } else { + if ((nia_data.status & NIA_MRN) != 0) + nia_stop(); + } + if (*data & NIA_ENB) { + if ((nia_data.status & NIA_MRN) != 0 && + (nia_data.status & NIA_ECP) == 0) + nia_enable(); + else + nia_data.status |= NIA_ECP; + } else + nia_data.status &= ~NIA_ECP; + if (*data & NIA_DIS) { + if ((nia_data.status & NIA_MRN) != 0 && + (nia_data.status & NIA_DCP) == 0) + nia_disable(); + else + nia_data.status |= NIA_DCP; + } else + nia_data.status &= ~NIA_DCP; + if (*data & NIA_CQA && + (nia_data.status & NIA_CQA) == 0 && + (nia_data.status & NIA_MRN) != 0) { + nia_data.status |= NIA_CQA; + sim_activate(uptr, 200); + } + if (nia_data.status & (NIA_CPE|NIA_RQA)) + set_interrupt(NIA_DEVNUM, nia_data.status & NIA_PIA); + sim_debug(DEBUG_CONO, dptr, "NIA %03o CONO %06o PC=%06o %012llo\n", dev, + (uint32)(*data & RMASK), PC, nia_data.status); + break; + case CONI: + *data = nia_data.status|NIA_PPT|NIA_PID; + sim_debug(DEBUG_CONI, dptr, "NIA %03o CONI %012llo PC=%o\n", dev, + *data, PC); + break; + case DATAO: + if (nia_data.status & NIA_SEB) { + nia_data.ebuf = *data; + } else { + if (*data & NIA_LRA) { + nia_data.rar = (uint32)((*data & NIA_RAR) >> 22); + sim_debug(DEBUG_DETAIL, dptr, "NIA %03o set RAR=%o\n", + dev, nia_data.rar); + } else { + if (nia_data.rar >= 0274 && nia_data.rar <= 0277) + nia_data.uver[nia_data.rar - 0274] = (uint32)(*data & RMASK); + sim_debug(DEBUG_DETAIL, dptr, "NIA %03o set data=%o %06o\n", + dev, nia_data.rar, (uint32)(*data & RMASK)); + } + } + sim_debug(DEBUG_DATAIO, dptr, "NIA %03o DATO %012llo PC=%o\n", + dev, *data, PC); + break; + case DATAI: + if (nia_data.status & NIA_SEB) { + *data = nia_data.ebuf; + } else { + if (nia_data.status & NIA_LAR) { + *data = ((uint64)nia_data.rar) << 20; + *data &= ~NIA_MSB; + *data |= NIA_LRA; + } else if (nia_data.rar >= 0274 && nia_data.rar <= 0277) { + *data = (uint64)nia_data.uver[nia_data.rar - 0274]; + } + } + sim_debug(DEBUG_DATAIO, dptr, "NIA %03o DATI %012llo PC=%o\n", + dev, *data, PC); + break; + } + + return SCPE_OK; +} + +static char * +ipv4_inet_ntoa(struct in_addr ip) +{ + static char str[20]; + + if (sim_end) + sprintf (str, "%d.%d.%d.%d", ip.s_addr & 0xFF, + (ip.s_addr >> 8) & 0xFF, + (ip.s_addr >> 16) & 0xFF, + (ip.s_addr >> 24) & 0xFF); + else + sprintf (str, "%d.%d.%d.%d", (ip.s_addr >> 24) & 0xFF, + (ip.s_addr >> 16) & 0xFF, + (ip.s_addr >> 8) & 0xFF, + ip.s_addr & 0xFF); + return str; +} + +/* + * Set error code and stop. + */ +void nia_error(int err) +{ + nia_data.rar = err; + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA error %03o\n", err); + nia_data.status |= NIA_CPE; + set_interrupt(NIA_DEVNUM, nia_data.status & NIA_PIA); + nia_stop(); +} + +/* + * Start NIA device, load in 2 words using RH20 mode. + */ +void nia_start() +{ + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA start\n"); + /* Set up RH20 to read 2 words */ + nia_rh.stcr = BIT7; + nia_rh.imode = 2; + rh20_setup(&nia_rh); + /* Read PCB address */ + if (!rh_read(&nia_rh)) { + nia_error(CHNERR); + return; + } + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA PCB %012llo %o\n", nia_rh.buf, + nia_rh.wcr); + nia_data.pcb = (t_addr)(nia_rh.buf & AMASK); + nia_data.resp_hdr = (t_addr)((nia_rh.buf + 4) & AMASK); + nia_data.unk_hdr = (t_addr)((nia_rh.buf + 8) & AMASK); + /* Read PIA value */ + if (!rh_read(&nia_rh)) { + nia_error(CHNERR); + return; + } + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA PIA %012llo %o\n", nia_rh.buf, + nia_rh.wcr); + nia_data.pia = (int)(nia_rh.buf & 7); + nia_data.status |= NIA_MRN; + memcpy(&nia_data.macs[0], &nia_data.mac, sizeof (ETH_MAC)); + memcpy(&nia_data.macs[1], &broadcast_ethaddr, sizeof(ETH_MAC)); +} + +void nia_stop() +{ + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA stop\n"); + nia_data.status &= ~NIA_MRN; +} + +/* + * Enable NIA 20. + * + * Read in PTT and MACS table. + */ +void nia_enable() +{ + uint64 word; + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA enable\n"); + /* Load pointers to various table */ + if (Mem_read_word(nia_data.unk_hdr + PCB_UPL, &word, 0)) { + nia_error(EBSERR); + return; + } + nia_data.unk_len = (int)(word & AMASK); + /* Load PTT */ + if (Mem_read_word(nia_data.pcb + PCB_PTT, &word, 0)) { + nia_error(EBSERR); + return; + } + nia_data.ptt_addr = (t_addr)(word & AMASK); + nia_load_ptt(); + /* Load MCT */ + if (Mem_read_word(nia_data.pcb + PCB_MCT, &word, 0)) { + nia_error(EBSERR); + return; + } + nia_data.mcast_addr = (t_addr)(word & AMASK); + nia_load_mcast(); + /* Load read count buffer address */ + if (Mem_read_word(nia_data.pcb + PCB_RCB, &word, 0)) { + nia_error(EBSERR); + return; + } + nia_data.rcb = (t_addr)(word & AMASK); + nia_data.status |= NIA_ECP; + nia_data.status &= ~NIA_DCP; +} + +/* + * Disable NIA 20. + */ +void nia_disable() +{ + nia_data.status |= NIA_DCP; + nia_data.status &= ~NIA_ECP; +} + +/* + * Copy a MAC address from string to memory word. + */ +void nia_cpy_mac(uint64 word1, uint64 word2, ETH_MAC *mac) +{ + ETH_MAC m; + m[0] = (unsigned char)((word1 >> 28) & 0xff); + m[1] = (unsigned char)((word1 >> 20) & 0xff); + m[2] = (unsigned char)((word1 >> 12) & 0xff); + m[3] = (unsigned char)((word1 >> 4) & 0xff); + m[4] = (unsigned char)((word2 >> 28) & 0xff); + m[5] = (unsigned char)((word2 >> 20) & 0xff); + memcpy(mac, &m, sizeof(ETH_MAC)); +} + +/* + * Copy memory to a packet. + */ +uint8 *nia_cpy_to(t_addr addr, uint8 *data, int len) +{ + uint64 word; + /* Copy full words */ + while (len > 3) { + word = M[addr++]; + *data++ = (uint8)((word >> 28) & 0xff); + *data++ = (uint8)((word >> 20) & 0xff); + *data++ = (uint8)((word >> 12) & 0xff); + *data++ = (uint8)((word >> 4) & 0xff); + len -= 4; + } + /* Grab last partial word */ + if (len) { + word = M[addr++]; + switch (len) { + case 3: + *data++ = (uint8)((word >> 28) & 0xff); + *data++ = (uint8)((word >> 20) & 0xff); + *data++ = (uint8)((word >> 12) & 0xff); + break; + case 2: + *data++ = (uint8)((word >> 28) & 0xff); + *data++ = (uint8)((word >> 20) & 0xff); + break; + case 1: + *data++ = (uint8)((word >> 28) & 0xff); + break; + } + } + return data; +} + +/* + * Copy a packet to memory. + */ +uint8 *nia_cpy_from(t_addr addr, uint8 *data, int len) +{ + uint64 word; + + /* Copy full words */ + while (len > 3) { + word = (uint64)(*data++) << 28; + word |= (uint64)(*data++) << 20; + word |= (uint64)(*data++) << 12; + word |= (uint64)(*data++) << 4; + M[addr++] = word; + len -= 4; + } + /* Copy last partial word */ + if (len) { + switch (len) { + case 3: + word = (uint64)(*data++) << 28; + word |= (uint64)(*data++) << 20; + word |= (uint64)(*data++) << 12; + break; + case 2: + word = (uint64)(*data++) << 28; + word |= (uint64)(*data++) << 20; + break; + case 1: + word = (uint64)(*data++) << 28; + break; + } + } + M[addr++] = word; + return data; +} + +/* + * Get next entry off a queue. + * Return entry in *entry and 1 if successfull. + * Returns 0 if fail, queue locked or memory out of bounds. + */ +int nia_getq(t_addr head, t_addr *entry) +{ + uint64 temp; + t_addr flink; + t_addr nlink; + *entry = 0; /* For safty */ + + /* Try and get lock */ + if (Mem_read_word(head, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + /* Check if entry locked */ + if ((temp & SMASK) == 0) + return 0; + + /* Increment lock here */ + + /* Get head of queue */ + if (Mem_read_word(head + 1, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + flink = (t_addr)(temp & AMASK); + /* Check if queue empty */ + if (flink == (head+1)) { + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA empty %08o\n", head); + /* Decrement lock here */ + return 1; + } + /* Get link to next entry */ + if (Mem_read_word(flink + 1, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + nlink = (t_addr)(temp & AMASK); + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA head: q=%08o f=%08o n=%08o\n", + head, flink, nlink); + /* Set Head Flink to point to next */ + temp = (uint64)nlink; + if (Mem_write_word(head+1, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + /* Set Next Blink to head */ + temp = (uint64)(head + 1); + if (Mem_write_word(nlink+1, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + /* Return entry */ + *entry = flink; + + /* Decrement lock here */ + return 1; +} + + +/* + * Put entry on head of queue. + * Return entry in *entry and 1 if successfull. + * Returns 0 if fail, queue locked or memory out of bounds. + */ +int nia_putq(t_addr head, t_addr *entry) +{ + uint64 temp; + t_addr blink; + + /* Try and get lock */ + if (Mem_read_word(head, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + /* Check if entry locked */ + if ((temp & SMASK) == 0) + return 0; + + /* Increment lock here */ + + /* Hook entry into tail of queue */ + if (Mem_read_word(head + 2, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + + blink = (t_addr)(temp & AMASK); /* Get back link */ + /* Get link to previous entry */ + temp = (uint64)*entry; + if (Mem_write_word(blink, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + /* Old forward is new */ + if (Mem_write_word(head+2, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + + /* Flink is head of queue */ + temp = (uint64)(head+1); + if (Mem_write_word(*entry, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + + /* Back link points to previous */ + temp = (uint64)blink; + if (Mem_write_word(*entry+1, &temp, 0)) { + nia_error(EBSERR); + return 0; + } + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA put: q=%08o i=%08o b=%08o\n", + head, *entry, blink); + *entry = 0; + /* Decement lock here */ + + /* Check if Queue was empty, and response queue */ + if (blink == (head+1) && head == nia_data.resp_hdr) { + nia_data.status |= NIA_RQA; + set_interrupt(NIA_DEVNUM, nia_data.pia); + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA set response\n"); + } + return 1; +} + + +/* + * Load in the protocol type table + */ +void nia_load_ptt() +{ + int i; + int n = 0; + t_addr addr = nia_data.ptt_addr; + + for (i = 0; i < 17; i++) { + uint64 word1, word2; + + /* Get entry */ + if (Mem_read_word(addr++, &word1, 0)) { + nia_error(EBSERR); + return; + } + if (Mem_read_word(addr++, &word2, 0)) { + nia_error(EBSERR); + return; + } + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load ptt%d: %012llo %012llo\n\r", + n, word1, word2); + if (word1 & SMASK) { + uint16 type; + type = (uint16)(word1 >> 12) & 0xff; + type |= (uint16)(word1 << 4) & 0xff00; + nia_data.ptt_proto[n] = type; + nia_data.ptt_head[n] = (t_addr)(word2 &AMASK) - 1; + n++; + } + addr++; + } + for (i = 0; i < n; i++) + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load ptt%d: %04x %010o\n\r", + n, nia_data.ptt_proto[i], nia_data.ptt_head[i]); + nia_data.ptt_n = n; +} + +/* + * Load in the multi-cast table + */ +void nia_load_mcast() +{ + int i; + int n = 0; + char buffer[20]; + t_addr addr = nia_data.mcast_addr; + + /* Start with our own address. */ + memcpy(&nia_data.macs[n], &nia_data.mac, sizeof (ETH_MAC)); + n++; + memcpy(&nia_data.macs[n], &broadcast_ethaddr, sizeof (ETH_MAC)); + n++; + for (i = 0; i < 17; i++) { + uint64 word1, word2; + + if (Mem_read_word(addr++, &word1, 0)) { + nia_error(EBSERR); + return; + } + if (Mem_read_word(addr++, &word2, 0)) { + nia_error(EBSERR); + return; + } + if (word2 & 1) { + nia_cpy_mac(word1, word2, &nia_data.macs[n]); + n++; + } + } + for(i = 0; i< n; i++) { + eth_mac_fmt(&nia_data.macs[i], buffer); + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load mcast%d: %s\n\r",i,buffer); + } + nia_data.macs_n = n - 2; + if (nia_recv_uptr->flags & UNIT_ATT) + eth_filter (&nia_data.etherface, n, nia_data.macs, nia_data.amc, + nia_data.prmsc); +} + +/* + * Pretty print a packet for debugging. + */ +void nia_packet_debug(struct nia_device *nia, const char *action, + ETH_PACK *packet) { + struct nia_eth_hdr *eth = (struct nia_eth_hdr *)&packet->msg[0]; + struct arp_hdr *arp = (struct arp_hdr *)eth; + struct ip *ip = (struct ip *)&packet->msg[sizeof(struct nia_eth_hdr)]; + struct udp *udp; + struct tcp *tcp; + struct icmp *icmp; + uint8 *payload; + struct in_addr ipaddr; + size_t len; + int flag; + char src_ip[20]; + char dst_ip[20]; + char src_port[8]; + char dst_port[8]; + char flags[64]; + static struct tcp_flag_bits { + const char *name; + uint16 bitmask; + } bits[] = { + {"FIN", TCP_FL_FIN}, + {"SYN", TCP_FL_SYN}, + {"RST", TCP_FL_RST}, + {"PSH", TCP_FL_PSH}, + {"ACK", TCP_FL_ACK}, + {"URG", TCP_FL_URG}, + {NULL, 0} + }; + static const char *icmp_types[] = { + "Echo Reply", // Type 0 + "Type 1 - Unassigned", + "Type 2 - Unassigned", + "Destination Unreachable", // Type 3 + "Source Quench (Deprecated)", // Type 4 + "Redirect", // Type 5 + "Type 6 - Alternate Host Address (Deprecated)", + "Type 7 - Unassigned", + "Echo Request", // Type 8 + "Router Advertisement", // Type 9 + "Router Selection", // Type 10 + "Time Exceeded", // Type 11 + "Type 12 - Parameter Problem", + "Type 13 - Timestamp", + "Type 14 - Timestamp Reply", + "Type 15 - Information Request (Deprecated)", + "Type 16 - Information Reply (Deprecated)", + "Type 17 - Address Mask Request (Deprecated)", + "Type 18 - Address Mask Reply (Deprecated)", + "Type 19 - Reserved (for Security)", + "Type 20 - Reserved (for Robustness Experiment)", + "Type 21 - Reserved (for Robustness Experiment)", + "Type 22 - Reserved (for Robustness Experiment)", + "Type 23 - Reserved (for Robustness Experiment)", + "Type 24 - Reserved (for Robustness Experiment)", + "Type 25 - Reserved (for Robustness Experiment)", + "Type 26 - Reserved (for Robustness Experiment)", + "Type 27 - Reserved (for Robustness Experiment)", + "Type 28 - Reserved (for Robustness Experiment)", + "Type 29 - Reserved (for Robustness Experiment)", + "Type 30 - Traceroute (Deprecated)", + "Type 31 - Datagram Conversion Error (Deprecated)", + "Type 32 - Mobile Host Redirect (Deprecated)", + "Type 33 - IPv6 Where-Are-You (Deprecated)", + "Type 34 - IPv6 I-Am-Here (Deprecated)", + "Type 35 - Mobile Registration Request (Deprecated)", + "Type 36 - Mobile Registration Reply (Deprecated)", + "Type 37 - Domain Name Request (Deprecated)", + "Type 38 - Domain Name Reply (Deprecated)", + "Type 39 - SKIP (Deprecated)", + "Type 40 - Photuris", + "Type 41 - ICMP messages utilized by experimental mobility protocols such as Seamoby", + "Type 42 - Extended Echo Request", + "Type 43 - Extended Echo Reply" + }; + + if (ntohs(eth->type) == ETHTYPE_ARP) { + struct in_addr in_addr; + const char *arp_op = (ARP_REQUEST == ntohs(arp->opcode)) ? "REQUEST" : ((ARP_REPLY == ntohs(arp->opcode)) ? "REPLY" : "Unknown"); + char eth_src[20], eth_dst[20]; + char arp_shwaddr[20], arp_dhwaddr[20]; + char arp_sipaddr[20], arp_dipaddr[20]; + + if (!(nia_dev.dctrl & DEBUG_ARP)) + return; + eth_mac_fmt(&arp->ethhdr.src, eth_src); + eth_mac_fmt(&arp->ethhdr.dest, eth_dst); + eth_mac_fmt(&arp->shwaddr, arp_shwaddr); + memcpy(&in_addr, &arp->sipaddr, sizeof(in_addr)); + strlcpy(arp_sipaddr, ipv4_inet_ntoa(in_addr), sizeof(arp_sipaddr)); + eth_mac_fmt(&arp->dhwaddr, arp_dhwaddr); + memcpy(&in_addr, &arp->dipaddr, sizeof(in_addr)); + strlcpy(arp_dipaddr, ipv4_inet_ntoa(in_addr), sizeof(arp_dipaddr)); + sim_debug(DEBUG_ARP, &nia_dev, + "%s %s EthDst=%s EthSrc=%s shwaddr=%s sipaddr=%s dhwaddr=%s dipaddr=%s\n", + action, arp_op, eth_dst, eth_src, arp_shwaddr, arp_sipaddr, arp_dhwaddr, arp_dipaddr); + return; + } + if (ntohs(eth->type) != ETHTYPE_IP) { + payload = (uint8 *)&packet->msg[sizeof(struct nia_eth_hdr)]; + len = packet->len - sizeof(struct nia_eth_hdr); + sim_data_trace(&nia_dev, nia_unit, payload, "", len, "", DEBUG_DATA); + return; + } + if (!(nia_dev.dctrl & (DEBUG_TCP|DEBUG_UDP|DEBUG_ICMP))) + return; + memcpy(&ipaddr, &ip->ip_src, sizeof(ipaddr)); + strlcpy(src_ip, ipv4_inet_ntoa(ipaddr), sizeof(src_ip)); + memcpy(&ipaddr, &ip->ip_dst, sizeof(ipaddr)); + strlcpy(dst_ip, ipv4_inet_ntoa(ipaddr), sizeof(dst_ip)); + payload = (uint8 *)&packet->msg[sizeof(struct nia_eth_hdr) + (ip->ip_v_hl & 0xf) * 4]; + switch (ip->ip_p) { + case UDP_PROTO: + udp = (struct udp *)payload; + snprintf(src_port, sizeof(src_port), "%d", ntohs(udp->udp_sport)); + snprintf(dst_port, sizeof(dst_port), "%d", ntohs(udp->udp_dport)); + sim_debug(DEBUG_UDP, &nia_dev, "%s %d byte packet from %s:%s to %s:%s\n", action, + ntohs(udp->len), src_ip, src_port, dst_ip, dst_port); + if (udp->len && (nia_dev.dctrl & DEBUG_UDP)) + sim_data_trace(&nia_dev, nia_unit, payload + sizeof(struct udp), "", + ntohs(udp->len), "", DEBUG_DATA); + break; + case TCP_PROTO: + tcp = (struct tcp *)payload; + snprintf(src_port, sizeof(src_port), "%d", ntohs(tcp->tcp_sport)); + snprintf(dst_port, sizeof(dst_port), "%d", ntohs(tcp->tcp_dport)); + strlcpy(flags, "", sizeof(flags)); + for (flag=0; bits[flag].name; flag++) { + if (ntohs(tcp->flags) & bits[flag].bitmask) { + if (*flags) + strlcat(flags, ",", sizeof(flags)); + strlcat(flags, bits[flag].name, sizeof(flags)); + } + + } + len = ntohs(ip->ip_len) - ((ip->ip_v_hl & 0xf) * 4 + (ntohs(tcp->flags) >> 12) * 4); + sim_debug(DEBUG_TCP, &nia_dev, "%s %s%s %d byte packet from %s:%s to %s:%s\n", action, + flags, *flags ? ":" : "", (int)len, src_ip, src_port, dst_ip, dst_port); + if (len && (nia_dev.dctrl & DEBUG_TCP)) + sim_data_trace(&nia_dev, nia_unit, payload + 4 * (ntohs(tcp->flags) >> 12), "", len, "", DEBUG_DATA); + break; + case ICMP_PROTO: + icmp = (struct icmp *)payload; + len = ntohs(ip->ip_len) - (ip->ip_v_hl & 0xf) * 4; + sim_debug(DEBUG_ICMP, &nia_dev, "%s %s %d byte packet from %s to %s\n", action, + (icmp->type < sizeof(icmp_types)/sizeof(icmp_types[0])) ? icmp_types[icmp->type] : "", (int)len, src_ip, dst_ip); + if (len && (nia_dev.dctrl & DEBUG_ICMP)) + sim_data_trace(&nia_dev, nia_unit, payload + sizeof(struct icmp), "", len, "", DEBUG_DATA); + break; + } +} + + +/* + * Send out a packet. + */ +int nia_send_pkt(uint64 cmd) +{ + uint64 word1, word2; + struct nia_eth_hdr *hdr = (struct nia_eth_hdr *)(&nia_data.snd_buff.msg[0]); + uint8 *data = &nia_data.snd_buff.msg[sizeof(struct nia_eth_hdr)]; + ETH_MAC dest; + uint16 type; + int len; + int blen; + + /* Read packet length */ + if (Mem_read_word(nia_data.cmd_entry + 4, &word1, 0)) { + nia_error(EBSERR); + return 0; + } + len = (int)(word1 & 0177777); + blen = len + sizeof(struct nia_eth_hdr); + /* Check for runt packet */ + if (blen < ETH_MIN_PACKET && (cmd & (NIA_FLG_PAD << 8)) == 0) { + return NIA_ERR_RUN; + } + /* Check for too long of a packet */ + if (blen > ETH_MAX_PACKET) { + nia_data.pcnt[NIA_CNT_XF]++; + nia_data.pcnt[NIA_CNT_XFM] |= NIA_XFM_XFL; + return NIA_ERR_LNG; + } + /* If unit not attached, nothing more we can do */ + if ((nia_recv_uptr->flags & UNIT_ATT) == 0) + return 0; + /* Read protocol type */ + if (Mem_read_word(nia_data.cmd_entry + 5, &word1, 0)) { + nia_error(EBSERR); + return 0; + } + type = (uint16)(word1 >> 12) & 0xff; + type |= (uint16)(word1 << 4) & 0xff00; + hdr->type = htons(type); + + /* Load destination address */ + if (Mem_read_word(nia_data.cmd_entry + 7, &word1, 0)) { + nia_error(EBSERR); + return 0; + } + if (Mem_read_word(nia_data.cmd_entry + 8, &word2, 0)) { + nia_error(EBSERR); + return 0; + } + nia_cpy_mac(word1, word2, &dest); + memcpy(hdr->dest, dest, sizeof(ETH_MAC)); + /* Copy our address over */ + memcpy(hdr->src, nia_data.mac, sizeof(ETH_MAC)); + /* Set packet length */ + nia_data.snd_buff.len = len + sizeof(struct nia_eth_hdr); + /* Copy over rest of packet */ + if (cmd & (NIA_FLG_BSD << 8)) { + if (Mem_read_word(nia_data.cmd_entry + 9, &word1, 0)) { + nia_error(EBSERR); + return 0; + } + while (len > 0) { + uint64 tlen; + /* Read pointer to buffer */ + if (Mem_read_word((t_addr)(word1 & AMASK), &word2, 0)) { + nia_error(EBSERR); + return 0; + } + /* Read length */ + if (Mem_read_word((t_addr)((word1+2) & AMASK), &tlen, 0)) { + nia_error(EBSERR); + return 0; + } + blen = (int)(tlen & 0177777); + data = nia_cpy_to((t_addr)(word2 & AMASK), data, blen); + len -= blen; + if (Mem_read_word((t_addr)((word1 + 1) & AMASK), &word1, 0)) { + nia_error(EBSERR); + return 0; + } + } + } else { + data = nia_cpy_to(nia_data.cmd_entry + 9, data, len); + } + if (((cmd & (NIA_FLG_PAD << 8)) != 0) && + nia_data.snd_buff.len < ETH_MIN_PACKET) { + while (nia_data.snd_buff.len < ETH_MIN_PACKET) { + *data = 0; + nia_data.snd_buff.len++; + } + } + nia_packet_debug(&nia_data, "send", &nia_data.snd_buff); + if (eth_write(&nia_data.etherface, &nia_data.snd_buff, NULL) != SCPE_OK) { + nia_data.pcnt[NIA_CNT_XF]++; + nia_data.pcnt[NIA_CNT_XFM] |= NIA_XFM_LOC; + } + nia_data.pcnt[NIA_CNT_BX] += nia_data.snd_buff.len; + nia_data.pcnt[NIA_CNT_FX] ++; + return 0; +} + +/* + * Process commands. + */ +t_stat nia_cmd_srv(UNIT * uptr) +{ + t_addr free_q = nia_data.unk_hdr; + uint64 word1, word2; + uint32 cmd; + int len, i; + int err; + + /* See if we have command that we could not respond too */ + if (nia_data.cmd_entry != 0) { + /* Have to put this either on response queue or free queue */ + if (nia_putq(nia_data.cmd_rply, &nia_data.cmd_entry) == 0){ + sim_activate(uptr, 200); /* Reschedule ourselves to deal with it */ + return SCPE_OK; + } + nia_data.cmd_rply = 0; + } + + /* Check if we are running */ + if ((nia_data.status & NIA_MRN) == 0 || (nia_data.status & NIA_CQA) == 0) { + return SCPE_OK; + } + + /* or no commands pending, just idle out */ + /* Try to get command off queue */ + if (nia_getq(nia_data.cmd_hdr, &nia_data.cmd_entry) == 0) { + sim_activate(uptr, 200); /* Reschedule ourselves to deal with it */ + return SCPE_OK; + } + + /* Check if we got one */ + if (nia_data.cmd_entry == 0) { + /* Nothing to do */ + nia_data.status &= ~NIA_CQA; + return SCPE_OK; + } + + /* Get command */ + if (Mem_read_word(nia_data.cmd_entry + 3, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + cmd = (uint32)(word1 >> 12); + /* Save initial status */ + nia_data.cmd_status = ((uint8)(cmd >> 16)) & 0xff; + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA cmd: %08x\n", cmd); + cmd &= 0xffff; + len = 5; + /* Preform function of command */ + switch(cmd & 0xff) { + case NIA_CMD_SND: /* Send a datagram */ + err = nia_send_pkt(cmd); + if (err != 0) + cmd |= ((err<<1)|1) << 16; + cmd |= NIA_STS_SR << 16; + len = 10; + break; + case NIA_CMD_LPTT: /* Load Protocol Type table */ + nia_load_ptt(); + break; + case NIA_CMD_LMAC: /* Load Multicast table */ + nia_load_mcast(); + break; + case NIA_CMD_RCNT: /* Read counts */ + for (i = 0; i < NIA_CNT_LEN; i++) { + word1 = nia_data.pcnt[i]; + if (Mem_write_word(nia_data.cnt_addr + i, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + if ((cmd & (NIA_FLG_CLRC << 20)) != 0) + nia_data.pcnt[i] = 0; + } + break; + case NIA_CMD_WPLI: /* Write PLI */ + break; + case NIA_CMD_RPLI: /* Read PLI */ + break; + case NIA_CMD_RNSA: /* Read Station Address */ + len = 8; + word1 = ((uint64)nia_data.mac[0]) << 28; + word1 |= ((uint64)nia_data.mac[1]) << 20; + word1 |= ((uint64)nia_data.mac[2]) << 12; + word1 |= ((uint64)nia_data.mac[3]) << 4; + word2 = ((uint64)nia_data.mac[4]) << 28; + word2 |= ((uint64)nia_data.mac[5]) << 20; + if (Mem_write_word(nia_data.cmd_entry + 4, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + if (Mem_write_word(nia_data.cmd_entry + 5, &word2, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + word1 = (uint64)((nia_data.amc << 2)| (nia_data.h4000 << 1) + | nia_data.prmsc); + /* Micro code version, PTT len MACS len */ + word2 = (nia_data.uver[3] << 12) |(0xF << 6)|0xF; + if (Mem_write_word(nia_data.cmd_entry + 6, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + if (Mem_write_word(nia_data.cmd_entry + 7, &word2, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + break; + case NIA_CMD_WNSA: /* Write Station Address */ + len = 8; + if (Mem_read_word(nia_data.cmd_entry + 4, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + if (Mem_read_word(nia_data.cmd_entry + 5, &word2, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + nia_cpy_mac(word1, word2, &nia_data.mac); + if (Mem_read_word(nia_data.cmd_entry + 6, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + if (Mem_read_word(nia_data.cmd_entry + 7, &word2, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + nia_data.prmsc = (int)(word1 & 1); + nia_data.h4000 = (int)((word1 & 2) != 0); + nia_data.amc = (int)((word1 & 4) != 0); + memcpy(&nia_data.macs[0], &nia_data.mac, sizeof (ETH_MAC)); + if (nia_recv_uptr->flags & UNIT_ATT) + eth_filter (&nia_data.etherface, nia_data.macs_n + 2, + nia_data.macs, 0, 0); + break; + + case NIA_CMD_RCV: /* Received datagram */ + default: /* Invalid command */ + cmd |= ((NIA_ERR_UNK<<1)|1) << 16; + break; + } + + nia_data.cmd_rply = nia_data.unk_hdr; + word1 = ((uint64)cmd) << 12; + if (Mem_write_word(nia_data.cmd_entry + 3, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + if (((cmd >> 16) & 1) != 0 || (cmd & (NIA_FLG_RESP << 8)) != 0) { + nia_data.cmd_rply = nia_data.resp_hdr; + } else if ((cmd & 0xff) == NIA_CMD_SND) { + if (Mem_read_word(nia_data.cmd_entry + 5, &word1, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + nia_data.cmd_rply = (t_addr)(word1 & AMASK); + } + for(i = 0; i < len; i++) + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA rcmd: %d %09llx %012llo\n", + i, M[nia_data.cmd_entry + i], M[nia_data.cmd_entry + i]); + (void)nia_putq(nia_data.cmd_rply, &nia_data.cmd_entry); + sim_activate(uptr, 500); + return SCPE_OK; +} + + +int +nia_rec_pkt() +{ + struct nia_eth_hdr *hdr; + uint16 type; + int i; + int len; + t_addr queue; + t_addr bsd; + uint64 word; + uint8 *data; + + /* See if we have received packet to process */ + if (nia_data.rec_entry != 0) { + /* Have to put this response queue */ + if (nia_putq(nia_data.resp_hdr, &nia_data.rec_entry) == 0) + return 0; + } + + /* If no pending packet, return success */ + if (nia_data.r_pkt == 0) + return 1; + + /* Determine which queue to get free packet from */ + hdr = (struct nia_eth_hdr *)(&nia_data.rec_buff.msg[0]); + type = ntohs(hdr->type); + + queue = nia_data.unk_hdr; + for (i = 0; i < nia_data.ptt_n; i++) { + if (nia_data.ptt_proto[i] == type) { + queue = nia_data.ptt_head[i]; + break; + } + } + + /* Try to grab place to save packet */ + if (nia_getq(queue, &nia_data.rec_entry) == 0) + return 0; /* Indicate packet not processed */ + + /* If we queue empty, just drop packet */ + if (nia_data.rec_entry == 0) { + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA drop packet\n"); + nia_data.r_pkt = 0; /* Drop packet it queue empty */ + if (queue == nia_data.unk_hdr) + nia_data.pcnt[NIA_CNT_DUN]++; + else + nia_data.pcnt[NIA_CNT_D01 + i]++; + nia_data.pcnt[NIA_CNT_UBU] += nia_data.rec_buff.len; + nia_data.status |= NIA_FQE; + set_interrupt(NIA_DEVNUM, nia_data.status & NIA_PIA); + return 1; /* We did what we could with it. */ + } + + /* Get some information about packet */ + len = nia_data.rec_buff.len - sizeof(struct nia_eth_hdr); + data = &nia_data.rec_buff.msg[sizeof(struct nia_eth_hdr)]; + + /* Got one, now fill in data */ + word = (uint64)(NIA_CMD_RCV << 12); + if (Mem_write_word(nia_data.rec_entry + 3, &word, 0)) { + nia_error(EBSERR); + return SCPE_OK; + } + word = (uint64)len; + if (Mem_write_word(nia_data.rec_entry + 4, &word, 0)) { + nia_error(EBSERR); + return 0; + } + (void)nia_cpy_from(nia_data.rec_entry + 5, + (uint8 *)&hdr->dest, sizeof(ETH_MAC)); + (void)nia_cpy_from(nia_data.rec_entry + 7, + (uint8 *)&hdr->src, sizeof(ETH_MAC)); + word = (uint64)(((type & 0xff00) >> 4) | + ((type & 0xff) << 12)); + if (Mem_write_word(nia_data.rec_entry + 9, &word, 0)) { + nia_error(EBSERR); + return 0; + } + if (Mem_read_word(nia_data.rec_entry + 10, &word, 0)) { + nia_error(EBSERR); + return 0; + } + bsd = (t_addr)(word & AMASK); + while (len > 0) { + int blen; + /* Get length of segment */ + if (Mem_read_word(bsd+2, &word, 0)) { + nia_error(EBSERR); + return 0; + } + blen = (int)(word & 0177777); + if (blen > len) + blen = len; + /* Get address of where to put data */ + if (Mem_read_word(bsd, &word, 0)) { + nia_error(EBSERR); + return 0; + } + data = nia_cpy_from((t_addr)(word & AMASK), data, blen); + len -= blen; + /* Get pointer to next segment */ + if (Mem_read_word(bsd+1, &word, 0)) { + nia_error(EBSERR); + return 0; + } + bsd = (t_addr)(word & AMASK); + } + + for(i = 0; i < 10; i++) + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA recv: %d %09llx %012llo\n", + i, M[nia_data.rec_entry + i], M[nia_data.rec_entry + i]); + /* All done with packet */ + nia_data.r_pkt = 0; + /* Put on response queue */ + return nia_putq(nia_data.resp_hdr, &nia_data.rec_entry); +} + +/* + * Receive ether net packets. + */ +t_stat nia_eth_srv(UNIT * uptr) +{ + struct nia_eth_hdr *hdr; + uint16 type; + + /* Check if we need to get a packet */ + while (nia_data.r_pkt == 0) { + if (eth_read(&nia_data.etherface, &nia_data.rec_buff, NULL) <= 0) + return SCPE_OK; + + nia_packet_debug(&nia_data, "recv", &nia_data.rec_buff); + hdr = (struct nia_eth_hdr *)(&nia_data.rec_buff.msg[0]); + type = ntohs(hdr->type); + /* Check if we are running */ + if ((nia_data.status & NIA_MRN) == 0) { + sim_debug(DEBUG_DETAIL, &nia_dev, + "NIA read packet - not running: %d %04x\n", + nia_data.rec_buff.len, type); + return SCPE_OK; + } + + sim_debug(DEBUG_DETAIL, &nia_dev, "NIA read packet: %d %04x\n", + nia_data.rec_buff.len, type); + nia_data.r_pkt = 1; /* Mark packet buffer full */ + nia_data.pcnt[NIA_CNT_BR] += nia_data.rec_buff.len; + nia_data.pcnt[NIA_CNT_FR] ++; + if (hdr->dest[0] & 1) { + nia_data.pcnt[NIA_CNT_MCB] += nia_data.rec_buff.len; + nia_data.pcnt[NIA_CNT_MCF] ++; + } + + /* Try to process the packet */ + if (nia_rec_pkt() == 0) { + sim_activate(nia_proc_uptr, 100); + return SCPE_OK; + } + } + return SCPE_OK; +} + +/* + * Handle delayed packets. + */ +t_stat nia_rec_srv(UNIT * uptr) +{ + + /* Process what we have */ + if (nia_rec_pkt() == 0) { + sim_activate(uptr, 100); + return SCPE_OK; + } + /* See if we can pick up any more packets */ + return nia_eth_srv(nia_recv_uptr); +} + + + +t_stat nia_show_mac (FILE* st, UNIT* uptr, int32 val, CONST void* desc) +{ + char buffer[20]; + eth_mac_fmt(&nia_data.mac, buffer); + fprintf(st, "MAC=%s", buffer); + return SCPE_OK; +} + +t_stat nia_set_mac (UNIT* uptr, int32 val, CONST char* cptr, void* desc) +{ + t_stat status; + + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + + status = eth_mac_scan_ex(&nia_data.mac, cptr, uptr); + if (status != SCPE_OK) + return status; + + return SCPE_OK; +} + +t_stat nia_reset (DEVICE *dptr) +{ + int i; + + for (i = 0; i < 6; i++) { + if (nia_data.mac[i] != 0) + break; + } + if (i == 6) { /* First call to reset? */ + /* Set a default MAC address in a BBN assigned OID range no longer in use */ + nia_set_mac (dptr->units, 0, "00:00:02:00:00:00/24", NULL); + } + return SCPE_OK; +} + +/* attach device: */ +t_stat nia_attach(UNIT* uptr, CONST char* cptr) +{ + t_stat status; + char* tptr; + char buf[32]; + + tptr = (char *) malloc(strlen(cptr) + 1); + if (tptr == NULL) return SCPE_MEM; + strcpy(tptr, cptr); + + memcpy(&nia_data.macs[0], &nia_data.mac, sizeof (ETH_MAC)); + memcpy(&nia_data.macs[1], &broadcast_ethaddr, 6); + status = eth_open(&nia_data.etherface, cptr, &nia_dev, DEBUG_ETHER); + if (status != SCPE_OK) { + free(tptr); + return status; + } + eth_mac_fmt(&nia_data.mac, buf); /* format ethernet mac address */ + if (SCPE_OK != eth_check_address_conflict (&nia_data.etherface, + &nia_data.mac)) { + eth_close(&nia_data.etherface); + free(tptr); + return sim_messagef (SCPE_NOATT, + "%s: MAC Address Conflict on LAN for address %s\n", + nia_dev.name, buf); + } + if (SCPE_OK != eth_filter(&nia_data.etherface, 2, nia_data.macs, 0, 0)) { + eth_close(&nia_data.etherface); + free(tptr); + return sim_messagef (SCPE_NOATT, + "%s: Can't set packet filter for MAC Address %s\n", + nia_dev.name, buf); + } + + uptr->filename = tptr; + uptr->flags |= UNIT_ATT; + eth_setcrc(&nia_data.etherface, 1); /* Enable CRC */ + + /* init read queue (first time only) */ + status = ethq_init(&nia_data.ReadQ, 8); + if (status != SCPE_OK) { + eth_close(&nia_data.etherface); + uptr->filename = NULL; + free(tptr); + return sim_messagef (status, "%s: Can't initialize receive queue\n", + nia_dev.name); + } + + + /* Allow Asynchronous inbound packets */ + eth_set_async (&nia_data.etherface, 0); + return SCPE_OK; +} + +/* detach device: */ + +t_stat nia_detach(UNIT* uptr) +{ + + if (uptr->flags & UNIT_ATT) { + eth_close (&nia_data.etherface); + free(uptr->filename); + uptr->filename = NULL; + uptr->flags &= ~UNIT_ATT; + } + return SCPE_OK; +} + +t_stat nia_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "NIA interface\n\n"); +fprintf (st, "The NIA interfaces to the network. Setting MAC defines default MAC address\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +eth_attach_help(st, dptr, uptr, flag, cptr); +return SCPE_OK; +} + +const char *nia_description (DEVICE *dptr) +{ + return "KL NIA interface"; +} +#endif + diff --git a/PDP10/kx10_cpu.c b/PDP10/kx10_cpu.c index 1104236..4a2f0c6 100644 --- a/PDP10/kx10_cpu.c +++ b/PDP10/kx10_cpu.c @@ -1,6 +1,6 @@ /* ka10_cpu.c: PDP-10 CPU simulator - Copyright (c) 2011-2017, Richard Cornwell + Copyright (c) 2011-2019, Richard Cornwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Richard Cornwell - cpu KA10/KL10 central processor + cpu KA10/KI10/KL10 central processor The 36b system family had six different implementions: PDP-6, KA10, KI10, @@ -100,14 +100,17 @@ #define HIST_PC 0x40000000 #define HIST_PC2 0x80000000 +#define HIST_PCE 0x20000000 #define HIST_MIN 64 -#define HIST_MAX 500000 +#define HIST_MAX 5000000 #define TMR_RTC 0 #define TMR_QUA 1 uint64 M[MAXMEMSIZE]; /* Memory */ -#if KI +#if KL +uint64 FM[128]; /* Fast memory register */ +#elif KI uint64 FM[64]; /* Fast memory register */ #else uint64 FM[16]; /* Fast memory register */ @@ -117,8 +120,8 @@ uint64 MQ; /* Extension to AR */ uint64 BR; /* Secondary operand */ uint64 AD; /* Address Data */ uint64 MB; /* Memory Bufer Register */ -uint32 AB; /* Memory address buffer */ -uint32 PC; /* Program counter */ +t_addr AB; /* Memory address buffer */ +t_addr PC; /* Program counter */ uint32 IR; /* Instruction register */ uint64 MI; /* Monitor lights */ uint32 FLAGS; /* Flags */ @@ -131,7 +134,7 @@ int SC; /* Shift count */ int SCAD; /* Shift count extension */ int FE; /* Exponent */ #if KA | PDP6 -int Pl, Ph, Rl, Rh, Pflag; /* Protection registers */ +t_addr Pl, Ph, Rl, Rh, Pflag; /* Protection registers */ int push_ovf; /* Push stack overflow */ int mem_prot; /* Memory protection flag */ #endif @@ -152,6 +155,7 @@ int pi_enable; /* Interrupts enabled */ int parity_irq; /* Parity interupt */ int pi_pending; /* Interrupt pending. */ int pi_enc; /* Flag for pi */ +int pi_vect; /* Last pi location used for IRQ */ int apr_irq; /* Apr Irq level */ int clk_en; /* Enable clock interrupts */ int clk_irq; /* Clock interrupt */ @@ -159,19 +163,42 @@ int pi_restore; /* Restore previous level */ int pi_hold; /* Hold onto interrupt */ int modify; /* Modify cycle */ int xct_flag; /* XCT flags */ -#if KI +#if KI | KL uint64 ARX; /* Extension to AR */ uint64 BRX; /* Extension to BR */ uint64 ADX; /* Extension to AD */ -uint32 ub_ptr; /* User base pointer */ -uint32 eb_ptr; /* Executive base pointer */ +t_addr ub_ptr; /* User base pointer */ +t_addr eb_ptr; /* Executive base pointer */ uint8 fm_sel; /* User fast memory block */ int32 apr_serial = -1; /* CPU Serial number */ int inout_fail; /* In out fail flag */ +#if KL +int ext_ac; /* Extended instruction AC */ +uint8 prev_ctx; /* Previous AC context */ +uint16 irq_enable; /* Apr IRQ enable bits */ +uint16 irq_flags; /* Apr IRQ bits */ +int mtr_irq; /* Timer IRQ */ +int mtr_enable; /* Enable Timer */ +int mtr_flags; /* Flags for accounting */ +int tim_per; /* Timer period */ +int tim_val; /* Current timer value */ +int rtc_tim; /* Time till next 60hz clock */ +uint32 brk_addr; /* Address break */ +int brk_flags; /* Break flags */ +int t20_page; /* Tops 20 paging selected */ +int ptr_flg; /* Access to pointer value */ +int extend = 0; /* Process extended instruction */ +int sect; /* Actual resolved section */ +int cur_sect; /* Current section */ +int prev_sect; /* Previous section */ +int pc_sect; /* Program counter section */ +int glb_sect; /* Global section access */ +#else int small_user; /* Small user flag */ +#endif int user_addr_cmp; /* User address compare flag */ #endif -#if KI | ITS | BBN +#if KI | KL | ITS | BBN uint32 e_tlb[512]; /* Executive TLB */ uint32 u_tlb[546]; /* User TLB */ int page_enable; /* Enable paging */ @@ -204,26 +231,39 @@ uint64 opc; /* Saved PC and Flags */ uint64 mar; /* Memory address compare */ uint32 qua_time; /* Quantum clock value */ #endif +#if KL_ITS +#define dbr1 FM[(6<<4)|1] +#define dbr2 FM[(6<<4)|2] +#define dbr3 FM[(6<<4)|3] +#define dbr4 FM[(6<<4)|4] +#define jpc FM[(6<<4)|15] +#define mar brk_addr; +#endif + int watch_stop; /* Stop at memory watch point */ int maoff = 0; /* Offset for traps */ uint16 dev_irq[128]; /* Pending irq by device */ t_stat (*dev_tab[128])(uint32 dev, uint64 *data); -int (*dev_irqv[128])(uint32 dev, int addr); +t_addr (*dev_irqv[128])(uint32 dev, t_addr addr); t_stat rtc_srv(UNIT * uptr); int32 rtc_tps = 60; #if ITS t_stat qua_srv(UNIT * uptr); int32 qua_tps = 125000; #endif +#if KL +t_stat tim_srv(UNIT * uptr); +#endif int32 tmxr_poll = 10000; /* Physical address range for Rubin 10-11 interface. */ #define T11RANGE(addr) ((addr) >= 03040000) /* Physical address range for auxiliary PDP-6. */ -extern int auxcpu_base; -#define AUXCPURANGE(addr) ((addr) >= auxcpu_base && (addr) < (auxcpu_base + 040000)) +#define AUXCPURANGE(addr) ((addr) >= 03000000 && (addr) < 03040000) + +/* List of RH10 & RH20 devices */ DEVICE *rh_devs[] = { #if (NUM_DEVS_RS > 0) &rsa_dev, @@ -242,19 +282,16 @@ DEVICE *rh_devs[] = { #endif #if (NUM_DEVS_TU > 0) &tua_dev, +#endif +#if (NUM_DEVS_NIA > 0) + &nia_dev, #endif NULL, }; - -struct rh_dev rh[] = { - { 0270, NULL, }, - { 0274, NULL, }, - { 0360, NULL, }, - { 0364, NULL, }, - { 0370, NULL, }, - { 0374, NULL, }, - { 0, NULL, }, -}; +/* RH10 device numbers */ +int rh_nums[] = { 0270, 0274, 0360, 0364, 0370, 0374, 0}; +/* Maps RH10 & RH20 device number to DEVICE structure */ +struct rh_dev rh[8]; typedef struct { uint32 pc; @@ -264,6 +301,7 @@ typedef struct { uint32 flags; uint64 mb; uint64 fmb; + uint16 prev_sect; } InstHistory; int32 hst_p = 0; /* history pointer */ @@ -272,13 +310,16 @@ InstHistory *hst = NULL; /* instruction history */ /* Forward and external declarations */ +#if KL +int do_extend(uint32 IA); +#endif t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc); -#if KI +#if KI | KL t_stat cpu_set_serial (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, CONST void *desc); #endif @@ -286,6 +327,13 @@ t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); const char *cpu_description (DEVICE *dptr); void set_ac_display (uint64 *acbase); +#if KA +int (*Mem_read)(int flag, int cur_context, int fetch); +int (*Mem_write)(int flag, int cur_context); +#else +int Mem_read(int flag, int cur_context, int fetch); +int Mem_write(int flag, int cur_context); +#endif t_bool build_dev_tab (void); @@ -300,6 +348,9 @@ t_bool build_dev_tab (void); UNIT cpu_unit[] = { { UDATA (&rtc_srv, UNIT_IDLE|UNIT_FIX|UNIT_BINK|UNIT_TWOSEG, 256 * 1024) }, #if ITS { UDATA (&qua_srv, UNIT_IDLE|UNIT_DIS, 0) } +#endif +#if KL + { UDATA (&tim_srv, UNIT_IDLE|UNIT_DIS, 0) } #endif }; @@ -322,7 +373,9 @@ REG cpu_reg[] = { { ORDATA (FM15, FM[015], 36) }, { ORDATA (FM16, FM[016], 36) }, { ORDATA (FM17, FM[017], 36) }, -#if KI +#if KL + { BRDATA (FM, &FM[0], 8, 36, 128)}, +#elif KI { BRDATA (FM, &FM[0], 8, 36, 64)}, #else { BRDATA (FM, &FM[0], 8, 36, 16)}, @@ -368,21 +421,31 @@ REG cpu_reg[] = { #if KI { ORDATAD (UB, ub_ptr, 18, "User Base Pointer") }, { ORDATAD (EB, eb_ptr, 18, "Executive Base Pointer") }, +#endif +#if KL + { ORDATAD (UB, ub_ptr, 22, "User Base Pointer") }, + { ORDATAD (EB, eb_ptr, 22, "Executive Base Pointer") }, +#endif +#if KI | KL { ORDATAD (FMSEL, fm_sel, 8, "Register set select") }, { ORDATAD (SERIAL, apr_serial, 10, "System Serial Number") }, { FLDATA (INOUT, inout_fail, 0), REG_RO}, +#if KI { FLDATA (SMALL, small_user, 0), REG_RO}, +#endif { FLDATA (ADRCMP, user_addr_cmp, 0), REG_HRO}, #endif -#if KI | ITS | BBN +#if KL | KI | ITS | BBN { FLDATAD (PAGE_ENABLE, page_enable, 0, "Paging enabled")}, { FLDATAD (PAGE_FAULT, page_fault, 0, "Page fault"), REG_RO}, { ORDATAD (AC_STACK, ac_stack, 18, "AC Stack"), REG_RO}, { ORDATAD (PAGE_RELOAD, pag_reload, 18, "Page reload"), REG_HRO}, { ORDATAD (FAULT_DATA, fault_data, 36, "Page fault data"), REG_RO}, { FLDATAD (TRP_FLG, trap_flag, 0, "Trap flag"), REG_HRO}, +#if !KL { ORDATAD (LST_PAGE, last_page, 9, "Last page"), REG_HRO}, #endif +#endif #if BBN { FLDATAD (EXEC_MAP, exec_map, 0, "Executive mapping"), REG_RO}, { FLDATAD (NXT_WR, next_write, 0, "Map next write"), REG_RO}, @@ -401,6 +464,28 @@ REG cpu_reg[] = { { ORDATAD (OPC, opc, 36, "Saved PC and flags")}, { ORDATAD (MAR, mar, 18, "Memory address register")}, { ORDATAD (QUA_TIME, qua_time, 36, "Quantum timer"), REG_RO}, +#endif +#if KL + { ORDATAD (EXT_AC, ext_ac, 4, "Extended Instruction AC"), REG_HRO}, + { ORDATAD (PREV_CTX, prev_ctx, 5, "Previous context"), REG_HRO}, + { ORDATAD (ITQ_EN, irq_enable, 16, "Interrupt enable"), REG_HRO}, + { ORDATAD (ITQ_FLGS, irq_flags, 16, "Interrupt Flags"), REG_HRO}, + { ORDATAD (MTR_IRQ, mtr_irq, 1, "Timer IRQ"), REG_HRO}, + { ORDATAD (MTR_EN, mtr_enable, 1, "Timer Enable"), REG_HRO}, + { ORDATAD (MTR_FLGS, mtr_flags, 3, "Timer Flags"), REG_HRO}, + { ORDATAD (TIM_PER, tim_per, 12, "Timer period"), REG_HRO}, + { ORDATAD (TIM_VAl, tim_val, 12, "Timer period"), REG_HRO}, + { ORDATAD (RTC_TIM, rtc_tim, 12, "RTC timer"), REG_HRO}, + { ORDATAD (BRK_ADDR, brk_addr, 18, "Break address"), REG_HRO}, + { ORDATAD (BRK_FLGS, brk_flags, 18, "Break address"), REG_HRO}, + { ORDATAD (T20_PAGE, t20_page, 1, "TOPS20 paging"), REG_HRO}, + { ORDATAD (PTR_FLG, ptr_flg, 1, "Accessing pointer"), REG_HRO}, + { ORDATAD (EXTEND, extend, 1, "Execute Extend"), REG_HRO}, + { ORDATAD (SECT, sect, 12, "access section"), REG_HRO}, + { ORDATAD (CUR_SECT, cur_sect, 12, "Current section"), REG_HRO}, + { ORDATAD (PREV_SECT, prev_sect, 12, "Previous section"), REG_HRO}, + { ORDATAD (PC_SECT, pc_sect, 12, "PC section"), REG_HRO}, + { ORDATAD (GLB_SECT, glb_sect, 1, "Global section"), REG_HRO}, #endif { NULL } }; @@ -428,13 +513,20 @@ MTAB cpu_mod[] = { #if KI|KL { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SERIAL", "SERIAL", &cpu_set_serial, &cpu_show_serial, NULL, "CPU Serial Number" }, +#if KL + { UNIT_M_PAGE, 0, "KL10A", "KL10A", NULL, NULL, NULL, + "Base KL10"}, + { UNIT_M_PAGE, UNIT_KL10B, "KL10B", "KL10B", NULL, NULL, NULL, + "Extended addressing support for KL10"}, +#endif #endif #if KA { UNIT_M_PAGE, 0, "ONESEG", "ONESEG", NULL, NULL, NULL, "One Relocation Register"}, { UNIT_M_PAGE, UNIT_TWOSEG, "TWOSEG", "TWOSEG", NULL, NULL, NULL, "Two Relocation Registers"}, -#if ITS +#endif +#if ITS | KL_ITS { UNIT_M_PAGE, UNIT_ITSPAGE, "ITS", "ITS", NULL, NULL, NULL, "Paging hardware for ITS"}, #endif @@ -454,6 +546,7 @@ MTAB cpu_mod[] = { { UNIT_M_MPX, 0, NULL, "NOMPX", NULL, NULL, NULL, "Disables the MPX device"}, #endif +#if PDP6 | KA | KI { UNIT_MAOFF, UNIT_MAOFF, "MAOFF", "MAOFF", NULL, NULL, NULL, "Interrupts relocated to 140"}, { UNIT_MAOFF, 0, NULL, "NOMAOFF", NULL, NULL, NULL, @@ -539,7 +632,7 @@ int opflags[] = { /* Double precsision math */ /* UJEN */ /* UUO101 */ /* GFAD */ /* GFSB */ 0, 0, 0, 0, - /* JSYS */ /* ADJSP */ /* GFMP */ /*GFDV */ + /* JSYS */ /* ADJSP */ /* GFMP */ /* GFDV */ 0, 0, 0, 0, /* DFAD */ /* DFSB */ /* DFMP */ /* DFDV */ 0, 0, 0, 0, @@ -781,7 +874,7 @@ int opflags[] = { #define SMEAR_SIGN(x) x = ((x) & SMASK) ? (x) | EXPO : (x) & MANT #define GET_EXPO(x) ((((x) & SMASK) ? 0377 : 0 ) \ ^ (((x) >> 27) & 0377)) -#if KI +#if KI | KL #define AOB(x) ((x + 1) & RMASK) | ((x + 01000000LL) & (C1|LMASK)) #define SOB(x) ((x + RMASK) & RMASK) | ((x + LMASK) & (C1|LMASK)); #else @@ -793,8 +886,12 @@ int opflags[] = { #define QTEN11 (ten11_unit[0].flags & UNIT_ATT) #define QAUXCPU (auxcpu_unit[0].flags & UNIT_ATT) #else +#if KL_ITS +#define QITS (cpu_unit[0].flags & UNIT_ITSPAGE) +#else #define QITS 0 #endif +#endif #if BBN #define QBBN (cpu_unit[0].flags & UNIT_BBNPAGE) #else @@ -805,6 +902,49 @@ int opflags[] = { #else #define QWAITS 0 #endif +#if KL +#define QKLB (cpu_unit[0].flags & UNIT_KL10B) +#else +#define QKLB 0 +#endif + +#if KL +struct _byte { + int p; + int s; +} _byte_adj[] = { + { /* 37 */ 36, 6 }, /* 45 */ + { /* 38 */ 30, 6 }, /* 46 */ + { /* 39 */ 24, 6 }, /* 47 */ + { /* 40 */ 18, 6 }, /* 50 */ + { /* 41 */ 12, 6 }, /* 51 */ + { /* 42 */ 6, 6 }, /* 52 */ + { /* 43 */ 0, 6 }, /* 53 */ + + { /* 44 */ 36, 8 }, /* 54 */ + { /* 45 */ 28, 8 }, /* 55 */ + { /* 46 */ 20, 8 }, /* 56 */ + { /* 47 */ 12, 8 }, /* 57 */ + { /* 48 */ 4, 8 }, /* 60 */ + + { /* 49 */ 36, 7 }, /* 61 */ + { /* 50 */ 29, 7 }, /* 62 */ + { /* 51 */ 22, 7 }, /* 63 */ + { /* 52 */ 15, 7 }, /* 64 */ + { /* 53 */ 8, 7 }, /* 65 */ + { /* 54 */ 1, 7 }, /* 66 */ + + { /* 55 */ 36, 9 }, /* 67 */ + { /* 56 */ 27, 9 }, /* 70 */ + { /* 57 */ 18, 9 }, /* 71 */ + { /* 58 */ 9, 9 }, /* 72 */ + { /* 59 */ 0, 9 }, /* 73 */ + + { /* 60 */ 36,18 }, /* 74 */ + { /* 61 */ 18,18 }, /* 75 */ + { /* 62 */ 0,18 } /* 76 */ +}; +#endif #if ITS /* @@ -1013,8 +1153,9 @@ t_stat dev_pi(uint32 dev, uint64 *data) { } if (res & 0400) /* Bit 27 */ pi_enable = 0; - if (res & 01000) /* Bit 26 */ + if (res & 01000) { /* Bit 26 */ PIE &= ~(*data & 0177); + } if (res & 02000) /* Bit 25 */ PIE |= (*data & 0177); if (res & 04000) { /* Bit 24 */ @@ -1025,15 +1166,17 @@ t_stat dev_pi(uint32 dev, uint64 *data) { if (res & 020000 && cpu_unit[0].flags & UNIT_MPX) mpx_enable = 1; #endif -#if KI +#if KI | KL if (res & 020000) { /* Bit 22 */ PIR &= ~(*data & 0177); } #endif +#if !KL if (res & 040000) /* Bit 21 */ parity_irq = 1; if (res & 0100000) /* Bit 20 */ parity_irq = 0; +#endif check_apr_irq(); sim_debug(DEBUG_CONO, &cpu_dev, "CONO PI %012llo\n", *data); break; @@ -1042,19 +1185,51 @@ t_stat dev_pi(uint32 dev, uint64 *data) { res = PIE; res |= (pi_enable << 7); res |= (PIH << 8); -#if KI +#if KI | KL res |= ((uint64)(PIR) << 18); #endif +#if !KL res |= (parity_irq << 15); +#endif *data = res; sim_debug(DEBUG_CONI, &cpu_dev, "CONI PI %012llo\n", *data); break; case DATAO: +#if KL + if (dev & 040) { /* SBDIAG */ + AB = (AB + 1) & RMASK; + res = 0; + if (((*data >> 31) & 030) == 010) { + int mc = MEMSIZE / 262144; + int c = (*data >> 31) & 07; + int s = 0; + if (c < mc) { + switch(*data & 037) { + case 0: res = 06000000000LL; break; + case 1: res = 00500000000LL; break; + case 2: res = 0; break; + case 012: + res = 0; + s = (int)(0176000 & *data) << 6; + s /= 262144; + if (s != c) + res = 010000000LL; + break; + default: res = 0; break; + } + } + } + MB = res; + (void)Mem_write(0, 0); + break; + } +#else MI = *data; #ifdef PANDA_LIGHTS /* Set lights */ ka10_lights_main (*data); +#endif #endif break; @@ -1081,6 +1256,425 @@ t_stat null_dev(uint32 dev, uint64 *data) { return SCPE_OK; } +#if KL +static int timer_irq, timer_flg; + +void +update_times(int tim) +{ + uint64 temp; + if (page_enable) { + temp = (M[eb_ptr + 0511] & CMASK) + (tim << 12); + if (temp & SMASK) + M[eb_ptr + 0510] = (M[eb_ptr+0510] + 1) & FMASK; + M[eb_ptr + 0511] = temp & CMASK; + if (FLAGS & USER) { + temp = (M[ub_ptr + 0506] & CMASK) + (tim << 12); + if (temp & SMASK) + M[ub_ptr + 0505] = (M[ub_ptr+0505] + 1) & FMASK; + M[ub_ptr + 0506] = temp & CMASK; + } + } +} + +/* + * Page device for KL10. + */ +t_stat dev_pag(uint32 dev, uint64 *data) { + uint64 res = 0; + int i; + switch(dev & 03) { + case CONI: + res = (eb_ptr >> 9); + if (page_enable) + res |= 020000; + if (t20_page) + res |= 040000; + *data = res; + sim_debug(DEBUG_CONI, &cpu_dev, "CONI PAG %012llo\n", *data); + break; + + case CONO: + eb_ptr = (*data & 017777) << 9; + for (i = 0; i < 512; i++) { + e_tlb[i] = 0; + u_tlb[i] = 0; + } + for (;i < 546; i++) + u_tlb[i] = 0; + page_enable = (*data & 020000) != 0; + t20_page = (*data & 040000) != 0; + sim_debug(DEBUG_CONO, &cpu_dev, "CONO PAG %012llo\n", *data); + break; + + case DATAO: + if (dev & 040) { /* CLRPT */ + int page = (RMASK & AB) >> 9; + int i; + + page &= ~7; + /* Map the page */ + for(i = 0; i < 8; i++) { + u_tlb[page+i] = 0; + e_tlb[page+i] = 0; + } + /* If not user do exec mappping */ + if (!t20_page && (page & 0740) == 0340) { + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + for(i = 0; i < 8; i++) + u_tlb[page+i] = 0; + } + } else { + res = *data; + if (res & SMASK) { + fm_sel = (uint8)(res >> 23) & 0160; + prev_ctx = (res >> 20) & 0160; + } + if (QKLB && (res & BIT1) != 0) { + /* Load previous section */ + prev_sect = (res >> 18) & 037; + } + if (res & BIT2) { + if ((res & RSIGN) == 0) { + int t; + double us = sim_activate_time_usecs (&cpu_unit[0]); + t = rtc_tim - ((int)us); + update_times(t); + rtc_tim = ((int)us); + } + ub_ptr = (res & 017777) << 9; + for (i = 0; i < 512; i++) { + u_tlb[i] = 0; + e_tlb[i] = 0; + } + for (;i < 546; i++) + u_tlb[i] = 0; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, + "DATAO PAG %012llo ebr=%06o ubr=%06o\n", + *data, eb_ptr, ub_ptr); + } + break; + + case DATAI: + if (dev & 040) { + /* Convert to MMU */ + } + res = (ub_ptr >> 9); + /* Set previous section */ + res |= ((uint64)(prev_ctx & 0160)) << 20; + res |= ((uint64)(fm_sel & 0160)) << 23; + res |= SMASK|BIT1|BIT2; + if (QKLB) + res |= ((uint64)prev_sect & 037) << 18; + *data = res; + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI PAG %012llo\n", *data); + break; + } + return SCPE_OK; +} + +/* + * Cache control. + * All operations set sweep done. + */ +t_stat dev_cca(uint32 dev, uint64 *data) { + irq_flags |= 020; + *data = 0; + check_apr_irq(); + return SCPE_OK; +} + + +/* + * Check if the last operation caused a APR IRQ to be generated. + */ +void check_apr_irq() { + if (pi_enable && apr_irq) { + int flg = 0; + clr_interrupt(0); + flg = irq_enable & irq_flags; + if (flg) + set_interrupt(0, apr_irq); + } +} + + +/* + * APR device for KL10. + */ +t_stat dev_apr(uint32 dev, uint64 *data) { + uint64 res = 0; + + switch(dev & 03) { + case CONI: + /* Read trap conditions */ + res = irq_flags | apr_irq; + res |= ((uint64)irq_enable) << 18; + if (irq_flags & irq_enable) + res |= 010; + *data = res; + sim_debug(DEBUG_CONI, &cpu_dev, "CONI APR %012llo\n", *data); + break; + + case CONO: + /* Set trap conditions */ + res = *data; + apr_irq = res & 07; + clr_interrupt(0); + if (res & 0200000) + reset_all(1); + if (res & 0100000) { /* Enable interrupts */ + irq_enable |= 07760 & res; + } + if (res & 0040000) { /* Disable interrupts */ + irq_enable &= ~(07760 & res); + } + if (res & 0020000) { /* Clear interrupt */ + irq_flags &= ~(07760 & res); + } + if (res & 0010000) { /* Set interrupt */ + irq_flags |= (07760 & res); + } + check_apr_irq(); + sim_debug(DEBUG_CONO, &cpu_dev, "CONO APR %012llo\n", *data); + break; + + case DATAO: + brk_addr = *data & RMASK; + brk_flags = 017 & (*data >> 23); + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAO APR %012llo\n", *data); + break; + + case DATAI: + if (dev & 040) { + /* APRID */ + AR = SMASK| (500LL << 18); /* MC level 500 */ + /* Bit 0 for TOPS-20 paging */ + /* Bit 1 for extended addressing */ + /* Bit 2 Exotic microcode */ + /* Bit 3 KL10B */ + /* Bit 4 PMOVE/PMOVEM or ITS Style Paging */ + /* Bit 5 Tops-20 R5 microcode */ +#if KL_ITS + if (QITS) + AR |= 00020000000000LL; +#endif + /* Bit 18 50hz */ + /* Bit 19 Cache */ + /* Bit 20 Channel? */ + /* Bit 21 Extended KL10 */ + /* Bit 22 Master Osc */ + if (QKLB) + AR |= BIT1|BIT4|040000; + AR |= (uint64)((apr_serial == -1) ? DEF_SERIAL : apr_serial); + sim_debug(DEBUG_DATAIO, &cpu_dev, "APRID BLKI %012llo\n", MB); + } else { + *data = ((uint64)brk_flags) << 23; + *data |= (uint64)brk_addr; + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI APR %012llo\n", *data); + } + break; + } + return SCPE_OK; +} + +/* + * MTR device for KL10. + */ +t_stat dev_mtr(uint32 dev, uint64 *data) { + uint64 res = 0; + + switch(dev & 03) { + case CONI: + /* Reader meters */ + *data = mtr_irq; + if (mtr_enable) + *data |= 02000; + *data |= (uint64)(mtr_flags << 12); + sim_debug(DEBUG_CONI, &cpu_dev, "CONI MTR %012llo\n", *data); + break; + + case CONO: + /* WRTIME */ + mtr_irq = *data & 07; + if (*data & 02000) + mtr_enable = 1; + if (*data & 04000) + mtr_enable = 0; + if (*data & RSIGN) + mtr_flags = (*data >> 12) & 07; + clr_interrupt(4 << 2); + if (tim_val & 030000) + set_interrupt(4 << 2, mtr_irq); + sim_debug(DEBUG_CONO, &cpu_dev, "CONO MTR %012llo\n", *data); + break; + + case DATAO: + /* MUUO */ + if (dev & 040) { + sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKO MTR %012llo\n", *data); + } else { + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAO MTR %012llo\n", *data); + } + break; + + case DATAI: + if (dev & 040) { + /* RDMACT */ + /* Read memory accounting */ + if (page_enable) { + sim_interval--; + res = M[ub_ptr + 0507]; + sim_interval--; + BR = (M[ub_ptr + 0506] & CMASK); + } else { + res = 0 << 12; + BR = 0; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKI MTR %012llo\n", *data); + } else { + /* RDEACT */ + /* Read executive accounting */ + int t; + double us = sim_activate_time_usecs (&cpu_unit[0]); + t = rtc_tim - ((int)us); + update_times(t); + rtc_tim = ((int)us); + if (page_enable) { + sim_interval--; + res = M[ub_ptr + 0505]; + sim_interval--; + BR = (M[ub_ptr + 0504] & CMASK); + } else { + res = 0; + BR = t << 12; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI MTR %012llo\n", *data); + } + *data = res; + break; + } + return SCPE_OK; +} + +/* + * TIM device for KL10. + */ +t_stat dev_tim(uint32 dev, uint64 *data) { + uint64 res; + double us; + UNIT *uptr = &cpu_unit[1 + ITS]; + + /* Update current timer count */ + if (sim_is_active(uptr)) { + us = sim_activate_time_usecs (uptr) / 10; + /* Check if going to period or overflow */ + if (tim_val & 0100000) + tim_val = (tim_val & 0070000) + tim_per - (int)us; + else + tim_val = (tim_val & 0070000) + 010000 - (int)us; + } + clr_interrupt(4 << 2); + switch(dev & 03) { + case CONI: + /* Interval counter */ + res = tim_per; + res |= tim_val & 070000; + res |= ((uint64)(tim_val & 07777)) << 18; + *data = res; + sim_debug(DEBUG_CONI, &cpu_dev, "CONI TIM %012llo\n", *data); + return SCPE_OK; + + case CONO: + /* Interval counter */ + sim_cancel(uptr); + tim_val &= 037777; /* Clear run bit */ + tim_per = *data & 07777; + if (*data & 020000) /* Clear overflow and done */ + tim_val &= 07777; + if (*data & 0400000) /* Clear counter */ + tim_val = 0; + if (*data & 040000) /* Enable counter */ + tim_val |= 040000; + sim_debug(DEBUG_CONO, &cpu_dev, "CONO TIM %012llo\n", *data); + break; + + case DATAO: + if (dev & 040) { + /* WRPAE */ + /* Write performance enables */ + sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKO TIM %012llo\n", *data); + } else { + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAO TIM %012llo\n", *data); + } + return SCPE_OK; + + case DATAI: + if (dev & 040) { + /* RDPERF */ + /* Read process execution time */ + int t; + us = sim_activate_time_usecs (&cpu_unit[0]); + t = rtc_tim - ((int)us); + update_times(t); + rtc_tim = ((int)us); + if (page_enable) { + sim_interval--; + res = (M[ub_ptr + 0505]); + sim_interval--; + BR = M[ub_ptr + 0504]; + } else { + res = 0 << 12; + BR = t; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "BLKI TIM %012llo\n", *data); + } else { + /* RDTIME */ + int t; + us = sim_activate_time_usecs (&cpu_unit[0]); + t = rtc_tim - ((int)us); + update_times(t); + rtc_tim = ((int)us); + if (page_enable) { + sim_interval--; + res = (M[eb_ptr + 0510]); + sim_interval--; + BR = M[eb_ptr + 0511]; + } else { + res = 0; + BR = t << 12; + } + sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI TIM %012llo\n", *data); + } + *data = res; + return SCPE_OK; + } + /* If timer is on, figure out when it will go off */ + if (tim_val & 040000) { + /* If we have already passed time, schedule to overflow */ + if ((tim_val & 07777) >= tim_per) { + us = (float)((010000 - (tim_val & 07777)) * 10); + tim_val &= 0077777; + } else { + us = (float)((tim_per - (tim_val & 07777)) * 10); + tim_val |= 0100000; + } + (void)sim_activate_after_d(uptr, us); + } + if (tim_val & 030000) + set_interrupt(4 << 2, mtr_irq); + return SCPE_OK; +} + +t_addr +tim_irq(uint32 dev, t_addr addr) +{ + return 0514; +} + +#endif #if KI static int timer_irq, timer_flg; @@ -1123,8 +1717,8 @@ t_stat dev_pag(uint32 dev, uint64 *data) { e_tlb[i] = u_tlb[i] = 0; for (;i < 546; i++) u_tlb[i] = 0; - user_addr_cmp = (res & 00020000000000LL) != 0; - small_user = (res & 00040000000000LL) != 0; + user_addr_cmp = (res & BIT4) != 0; + small_user = (res & BIT3) != 0; fm_sel = (uint8)(res >> 29) & 060; } pag_reload = 0; @@ -1139,9 +1733,9 @@ t_stat dev_pag(uint32 dev, uint64 *data) { res |= 020000; res |= ((uint64)(ub_ptr)) << 9; if (user_addr_cmp) - res |= 00020000000000LL; + res |= BIT4; if (small_user) - res |= 00040000000000LL; + res |= BIT3; res |= ((uint64)(fm_sel)) << 29; *data = res; sim_debug(DEBUG_DATAIO, &cpu_dev, "DATAI PAG %012llo\n", *data); @@ -1247,11 +1841,13 @@ t_stat dev_pag(uint32 dev, uint64 *data) { case 0: /* Clear page tables, reload from 71 & 72 */ for (i = 0; i < 512; i++) e_tlb[i] = u_tlb[i] = 0; + sim_interval--; res = M[071]; mon_base_reg = (res & 03777) << 9; ac_stack = (res >> 9) & 0760; user_base_reg = (res >> 9) & 03777000; user_limit = page_limit[(res >> 30) & 07]; + sim_interval--; pur = M[072]; break; @@ -1417,10 +2013,268 @@ sim_debug(DEBUG_DATAIO, &cpu_dev, "Rl=%06o Pl=%06o, Rh=%06o, Ph=%06o\n", Rl, Pl, } #endif +#if KL +int +load_tlb(int uf, int page, int wr) +{ + uint64 data; + +#if KL_ITS + if (QITS && t20_page) { + uint64 dbr; + int pg; + + dbr = (uf)? ((page & 0400) ? dbr2 : dbr1) : + ((page & 0400) ? dbr3 : dbr4) ; + pg = (page & 0377) >> 2; /* 2 1024 word page entries */ + sim_interval--; + data = M[dbr + pg]; + if ((page & 02) == 0) + data &= ~0160000000000LL; + else + data &= ~0160000LL; + M[dbr + pg] = data; + if ((page & 02) == 0) + data >>= 18; + data &= RMASK; + pg = 0; + switch(data >> 16) { + case 0: + fault_data = 033LL << 30; + page_fault = 1; + return 0; /* No access */ + case 1: /* Read Only */ + case 2: /* R/W First */ + if (wr) { + fault_data = 024LL << 30; + page_fault = 1; + return 0; + } + pg = KL_PAG_A; + break; + case 3: pg = KL_PAG_A|KL_PAG_W; break; /* R/W */ + } + pg |= (data & 017777) << 1; + /* Create 2 page table entries. */ + if (uf) { + u_tlb[page & 0776] = pg; + u_tlb[(page & 0776)|1] = pg|1; + data = u_tlb[page]; + } else { + e_tlb[page & 0776] = pg; + e_tlb[(page & 0776)|1] = pg|1; + data = e_tlb[page]; + } + } else +#endif +#define PG_PUB 0040000 +#define PG_WRT 0020000 +#define PG_KEP 0010000 +#define PG_CAC 0004000 +#define PG_STG (0000077LL << 18) +#define PG_IDX 0000777 + +#define PG_MASK 0000003777777LL +#define PG_AGE 0770000000000LL +#define PG_PAG 0017777 + if (t20_page) { /* Start with full access */ + int acc_bits = PG_PUB|PG_WRT|PG_KEP|PG_CAC; + uint64 spt = FM[(06<<4)|3] & PG_MASK; + uint64 cst = FM[(06<<4)|2] & PG_MASK; + uint64 cst_msk = FM[(06<<4)|0]; + uint64 cst_dat = FM[(06<<4)|1]; + uint64 cst_val = 0; + int index; + int pg; +#if EPT440 + int base = 0440; +#else + int base = 0540; +#endif + + /* Get segment pointer */ + /* And save it */ + if (QKLB) + base = 0540 + (sect & 037); + sim_interval--; + if (uf) + data = M[ub_ptr + base]; + else + data = M[eb_ptr + base]; + /* Find correct page table */ +sect_loop: + switch ((data >> 33) & 07) { + default: /* Invalid page */ + fault_data = 0; + page_fault = 1; + return 0; + case 1: /* Direct page */ + /* Bit 4 = execute */ + /* Bit 3 = Write */ + /* Bit 2 = Read */ + acc_bits &= (data >> 18) & RMASK; + break; + + case 2: /* Shared page */ + acc_bits &= (data >> 18) & RMASK; + sim_interval--; + index = data & RMASK; + data = M[index + spt]; + break; + + case 3: /* Indirect page */ + acc_bits &= (data >> 18) & RMASK; + index = (data >> 18) & PG_IDX; + sim_interval--; + data = M[(data & RMASK) + spt]; + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & PG_PAG; + sim_interval--; + data = M[(pg << 9) | index]; + goto sect_loop; + } + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & PG_PAG; + + /* Update CST entry if needed */ + if (cst) { + sim_interval--; + cst_val = M[cst + pg]; + if ((cst_val & PG_AGE) == 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + M[cst + pg] = (cst_val & cst_msk) | cst_dat; + } + + /* Get address of page */ + sim_interval--; + data = M[(pg << 9) | page]; +pg_loop: + + /* Decode map pointer */ + switch ((data >> 33) & 07) { + default: /* Invalid page */ + fault_data = 0; + page_fault = 1; + return 0; + case 1: /* Direct page */ + /* Bit 4 = execute */ + /* Bit 3 = Write */ + /* Bit 2 = Read */ + acc_bits &= (data >> 18) & RMASK; + break; + + case 2: /* Shared page */ + acc_bits &= (data >> 18) & RMASK; + sim_interval--; + index = data & RMASK; + data = M[index + spt]; + break; + + case 3: /* Indirect page */ + acc_bits &= (data >> 18) & RMASK; + index = (data >> 18) & PG_IDX; + sim_interval--; + data = M[(data & RMASK) + spt]; + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & RMASK; + sim_interval--; + data = M[(pg << 9) | index]; + goto pg_loop; + } + + /* Now have final page */ + if ((data & PG_STG) != 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + pg = data & PG_PAG; + /* Check outside of memory */ + /* Update CST entry if needed */ + if (cst) { + sim_interval--; + cst_val = M[cst + pg]; + if ((cst_val & PG_AGE) == 0) { + fault_data = 0; + page_fault = 1; + return 0; + } + if (acc_bits & PG_WRT) { + if (wr) + cst_val |= 1; + } else if (wr) { /* Trying to write and not writable */ + fault_data = 0 /* Write fault */; + page_fault = 1; + return 0; + } + M[cst + pg] = (cst_val & cst_msk) | cst_dat; + } else { + if (acc_bits & PG_WRT) { + cst_val = 1; + } + } + /* Now construct a TBL entry */ + /* A = accessable */ + /* P = public */ + /* W = writable */ + /* S = user */ + /* C = cache */ + data = pg | KL_PAG_A; + if (acc_bits & PG_PUB) + data |= KL_PAG_P; /* P */ + if (acc_bits & PG_WRT) { + if (cst_val & 1) + data |= KL_PAG_W; /* Set Modified page */ + data |= KL_PAG_S; /* Set Writeable bit */ + } + if (acc_bits & PG_CAC) + data |= KL_PAG_C; + if (QKLB) + data |= (sect & 037) << 18; + /* And save it */ + if (uf) + u_tlb[page] = data & (SECTM|RMASK); + else + e_tlb[page] = data & (SECTM|RMASK); + } else { + + /* Map the page */ + sim_interval--; + if (uf) { + data = M[ub_ptr + (page >> 1)]; + u_tlb[page & 01776] = (uint32)(RMASK & (data >> 18)); + u_tlb[page | 1] = (uint32)(RMASK & data); + data = u_tlb[page]; + } else { + if (page & 0400) + data = M[eb_ptr + (page >> 1)]; + else + data = M[eb_ptr + (page >> 1) + 0600]; + e_tlb[page & 01776] = (uint32)(RMASK & (data >> 18)); + e_tlb[page | 1] = (uint32)(RMASK & data); + data = e_tlb[page]; + } + } + return (int)(data); +} -#if KI /* - * Handle page lookup on KI10 + * Handle page lookup on KL10 * * addr is address to look up. * flag is set for pi cycle and user overide. @@ -1429,47 +2283,452 @@ sim_debug(DEBUG_DATAIO, &cpu_dev, "Rl=%06o Pl=%06o, Rh=%06o, Ph=%06o\n", Rl, Pl, * cur_context is set when access should ignore xct_flag * fetch is set for instruction fetches. */ -int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch) { - uint64 data; +int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { + int data; int base = 0; int page = (RMASK & addr) >> 9; int uf = (FLAGS & USER) != 0; + int pub = (FLAGS & PUBLIC) != 0; int upmp = 0; - if (page_fault) - return 0; - /* If paging is not enabled, address is direct */ if (!page_enable) { *loc = addr; return 1; } - /* If fetching byte data, use write access */ - if (BYF5 && (IR & 06) == 6) - wr = 1; + /* Handle address breaks */ + if (addr == brk_addr && uf == (brk_flags & 1) && (FLAGS & ADRFLT) == 0) { + if ((fetch && (brk_flags & 010) != 0) || + (!fetch && !wr && (brk_flags & 04) != 0) || + (wr && (brk_flags & 02) != 0)) { + fault_data = ((uint64)addr) | 023LL << 30 |((uf)?SMASK:0); + page_fault = 1; + return 0; + } + } /* If this is modify instruction use write access */ wr |= modify; /* Figure out if this is a user space access */ - if (flag) + + /* AC = 1 use BYF5 */ + /* AC = 2 use ptr_flg */ + /* AC = 4 all general access */ + /* AC = 8 only in cur_context EA calculations */ + if (flag) { uf = 0; - else if (xct_flag != 0 && !cur_context && !uf) { - if (((xct_flag & 2) != 0 && wr != 0) || - ((xct_flag & 1) != 0 && (wr == 0 || modify))) { - uf = (FLAGS & USERIO) != 0; - } + sect = 0; + } else if (xct_flag != 0 && !fetch) { + if (((xct_flag & 8) != 0 && cur_context && !ptr_flg) || + ((xct_flag & 4) != 0 && !cur_context && !BYF5 && !ptr_flg) || + ((xct_flag & 2) != 0 && !cur_context && ptr_flg) || + ((xct_flag & 1) != 0 && !cur_context && BYF5 )) { + uf = (FLAGS & USERIO) != 0; + pub = (FLAGS & PRV_PUB) != 0; + + if ((xct_flag & 014) == 04 && !ptr_flg && glb_sect == 0) + sect = prev_sect; + if ((xct_flag & 03) == 01 && BYF5 && glb_sect == 0) + sect = prev_sect; + } } - /* If user, check if small user enabled */ - if (uf) { - if (small_user && (page & 0340) != 0) { - fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) | 020LL; + /* Check if invalid section */ + if (QKLB && t20_page && (sect & 07740) != 0) { + fault_data = (027LL << 30) | (((uint64)sect) << 18) | (uint64)addr; + if (uf) /* U */ + fault_data |= SMASK; /* BIT0 */ + page_fault = 1; + return 0; + } + + /* Handle KI paging odditiy */ + if (!uf && !t20_page && (page & 0740) == 0340) { + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + upmp = 1; + } + + /* Map the page */ + if (uf || upmp) + data = u_tlb[page]; + else + data = e_tlb[page]; + + if (QKLB && t20_page && ((data >> 18) & 037) != sect) + data = 0; + /* If not valid, go refill it */ + if (data == 0) { + data = load_tlb(uf | upmp, page, wr); + if (data == 0 && page_fault) { + fault_data |= ((uint64)addr); + if (uf) /* U */ + fault_data |= SMASK; +#if KL_ITS + if (QITS) + return 0; +#endif + fault_data |= BIT8; + if (QKLB && t20_page) + fault_data |= (((uint64)sect) << 18); + if (fault_data & BIT1) + return 0; + if (wr) /* T */ + fault_data |= BIT5; /* BIT5 */ + return 0; + } + } + + /* Check if we need to modify TLB entry for TOPS 20 */ + if (t20_page && (data & KL_PAG_A) && (wr & ((data & KL_PAG_W) == 0)) && (data & KL_PAG_S)) { + uint64 cst = FM[(06<<4)|2] & PG_MASK; + uint64 cst_msk = FM[(06<<4)|0]; + uint64 cst_dat = FM[(06<<4)|1]; + /* Update CST entry if needed */ + if (cst) { + uint64 cst_val; + int pg = data & 017777; + sim_interval--; + cst_val = M[cst + pg]; + M[cst + pg] = (cst_msk & cst_val) | cst_dat | 1; + } + data |= KL_PAG_W; + /* Map the page */ + if (uf || upmp) + u_tlb[page] = data; + else + e_tlb[page] = data; + } + + /* create location. */ + *loc = ((data & 017777) << 9) + (addr & 0777); + + /* If PUBLIC and private page, make sure we are fetching a Portal */ + if ((data & KL_PAG_A) && !flag && pub && ((data & KL_PAG_P) == 0) && + (!fetch || !OP_PORTAL(M[*loc]))) { + /* Handle public violation */ + fault_data = ((uint64)addr) | 021LL << 30 | BIT8 |((uf)?SMASK:0); + if (QKLB && t20_page) + fault_data |= (((uint64)sect) << 18); + page_fault = 1; + return 0; + } + + + /* Check for access error */ + if ((data & KL_PAG_A) == 0 || (wr & ((data & KL_PAG_W) == 0))) { +#if KL_ITS + if (QITS) { + /* Remap the flag bits */ + if (uf) { /* U */ + u_tlb[page] = 0; + } else { + e_tlb[page] = 0; + } + if ((data & KL_PAG_A) == 0) { + fault_data = ((uint64)addr) | 033LL << 30 |((uf)?SMASK:0); + } else { + fault_data = ((uint64)addr) | 024LL << 30 |((uf)?SMASK:0); + } page_fault = 1; return 0; } +#endif + fault_data = BIT8 | (uint64)addr; + if (QKLB && t20_page) + fault_data |= (((uint64)sect) << 18); + /* Remap the flag bits */ + if (uf) { /* U */ + fault_data |= SMASK; /* BIT0 */ + u_tlb[page] = 0; + } else { + e_tlb[page] = 0; + } + if (data & KL_PAG_C) /* C */ + fault_data |= BIT7; /* BIT7 */ + if (data & KL_PAG_P) /* P */ + fault_data |= BIT6; /* BIT6 */ + if (wr) /* T */ + fault_data |= BIT5; /* BIT5 */ + if (data & KL_PAG_S) /* S */ + fault_data |= BIT4; /* BIT4 */ + if (data & KL_PAG_W) /* W */ + fault_data |= BIT3; /* BIT3 */ + if (data & KL_PAG_A) /* A */ + fault_data |= BIT2; /* BIT2 */ + page_fault = 1; + return 0; + } + + + /* If fetching from public page, set public flag */ + if (fetch && ((data & KL_PAG_P) != 0)) + FLAGS |= PUBLIC; + return 1; +} + +/* + * Register access on KL 10 + */ +uint64 get_reg(int reg) { + return FM[fm_sel|(reg & 017)]; +} + +void set_reg(int reg, uint64 value) { + FM[fm_sel|(reg & 017)] = value; +} + +int Mem_read(int flag, int cur_context, int fetch) { + t_addr addr; + + if (AB < 020 && ((QKLB && (glb_sect == 0 || sect == 0 || + (glb_sect && sect == 1))) || !QKLB)) { + if (xct_flag != 0 && !fetch) { + if (((xct_flag & 8) != 0 && cur_context && !ptr_flg) || + ((xct_flag & 4) != 0 && !cur_context && !BYF5 && !ptr_flg) || + ((xct_flag & 2) != 0 && !cur_context && ptr_flg) || + ((xct_flag & 1) != 0 && !cur_context && BYF5 )) { + MB = FM[prev_ctx|AB]; + return 0; + } + } + /* Check if invalid section */ + if (QKLB && t20_page && !flag && (sect & 07740) != 0) { + fault_data = (027LL << 30) | (uint64)AB | (((uint64)sect) << 18); + if (USER==0) /* U */ + fault_data |= SMASK; /* BIT0 */ + page_fault = 1; + return 0; + } + MB = get_reg(AB); } else { + if (!page_lookup(AB, flag, &addr, 0, cur_context, fetch)) + return 1; + if (addr >= (int)MEMSIZE) { + irq_flags |= 02000; + return 1; + } + if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) + watch_stop = 1; + sim_interval--; + MB = M[addr]; + } + return 0; +} + +int Mem_write(int flag, int cur_context) { + t_addr addr; + + if (AB < 020 && ((QKLB && (glb_sect == 0 || sect == 0 || + (glb_sect && sect == 1))) || !QKLB)) { + if (xct_flag != 0) { + if (((xct_flag & 8) != 0 && cur_context && !ptr_flg) || + ((xct_flag & 4) != 0 && !cur_context && !BYF5 && !ptr_flg) || + ((xct_flag & 2) != 0 && !cur_context && ptr_flg) || + ((xct_flag & 1) != 0 && !cur_context && BYF5 )) { + FM[prev_ctx|AB] = MB; + return 0; + } + } + /* Check if invalid section */ + if (QKLB && t20_page && !flag && (sect & 07740) != 0) { + fault_data = (027LL << 30) | (uint64)AB | (((uint64)sect) << 18); + if (USER==0) /* U */ + fault_data |= SMASK; /* BIT0 */ + page_fault = 1; + return 0; + } + set_reg(AB, MB); + } else { + if (!page_lookup(AB, flag, &addr, 1, cur_context, 0)) + return 1; + if (addr >= (int)MEMSIZE) { + irq_flags |= 02000; + return 1; + } + if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) + watch_stop = 1; + sim_interval--; + M[addr] = MB; + } + return 0; +} + +/* executive page table lookup */ +int exec_page_lookup(t_addr addr, int wr, t_addr *loc) +{ + int data; + int page = (RMASK & addr) >> 9; + int upmp = 0; + int sav_sect = sect; + + /* If paging is not enabled, address is direct */ + if (!page_enable) { + *loc = addr; + return 0; + } + + /* Handle KI paging odditiy */ + if (!t20_page && (page & 0740) == 0340) { + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + upmp = 1; + } + + /* Map the page */ + if (upmp) + data = u_tlb[page]; + else + data = e_tlb[page]; + + /* If not valid, go refill it */ + if (data == 0 || (data & 037) != 0) { + sect = 0; + data = load_tlb(upmp, page, wr); + if (data == 0) { + page_fault = 0; + return 1; + } + sect = sav_sect; + } + *loc = ((data & 017777) << 9) + (addr & 0777); + return 0; +} + +int Mem_examine_word(int n, int wrd, uint64 *data) { + t_addr addr = 0144 + (8 * n) + eb_ptr; + int base = 0; + + if (addr >= MEMSIZE) + return 1; + if (M[addr] == 0 || wrd > M[addr]) + return 1; + addr = (M[addr+1] + wrd) & RMASK; + if (exec_page_lookup(addr, 0, &addr)) + return 1; + *data = M[addr]; + return 0; +} + +int Mem_deposit_word(int n, int wrd, uint64 *data) { + t_addr addr = 0146 + (8 * n) + eb_ptr; + int base = 0; + + if (addr >= MEMSIZE) + return 1; + if (M[addr] == 0 || wrd > M[addr]) + return 1; + addr = (M[addr+1] + wrd) & RMASK; + if (exec_page_lookup(addr, 1, &addr)) + return 1; + M[addr] = *data; + return 0; +} + +/* + * Read in 16 bits of data from a byte pointer. + */ +int Mem_read_byte(int n, uint16 *data, int byte) { + t_addr addr; + uint64 val; + uint64 msk; + int p, s, np; + int need = byte? 8: 16; + + *data = 0; + while (need > 0) { + addr = 0140 + (8 * n) + eb_ptr; + if (addr >= MEMSIZE) + return 0; + val = M[addr]; + s = (val >> 24) & 077; + p = (((val >> 30) & 077) + (0777 ^ s) + 1) & 0777; + if (p & 0400) { + p = np = (36 + (0777 ^ s) + 1) & 0777; + val = (val & LMASK) | ((val + 1) & RMASK); + } else + np = p; + np &= 077; + val &= PMASK; + val |= (uint64)(np) << 30; + M[addr] = val; + addr = val & RMASK; + if (exec_page_lookup((int)(val & RMASK), 0, &addr)) + return 0; + /* Generate mask for given size */ + msk = (uint64)(1) << s; + msk--; + val = M[addr]; + val = (val >> p) & msk; + if (s > 8) + need -= 16; + else + need -= 8; + *data |= val << need; + } + return s; +} + +int Mem_write_byte(int n, uint16 *data) { + t_addr addr; + uint64 val; + uint64 msk; + int p, s, np; + int need = 16; + uint16 dat = *data; + + dat = ((dat >> 8) & 0377) | ((dat & 0377) << 8); + while (need > 0) { + addr = 0141 + (8 * n) + eb_ptr; + if (addr >= MEMSIZE) + return 0; + val = M[addr]; + if (val == 0) + return 1; + s = (val >> 24) & 077; + p = (((val >> 30) & 077) + (0777 ^ s) + 1) & 0777; + if (p & 0400) { + p = np = (36 + (0777 ^ s) + 1) & 0777; + val = (val & LMASK) | ((val + 1) & RMASK); + } else + np = p; + np &= 077; + val &= PMASK; + val |= (uint64)(np) << 30; + M[addr] = val; + addr = val & RMASK; + if (exec_page_lookup((int)(val & RMASK), 1, &addr)) + return 0; + /* Generate mask for given size */ + msk = (uint64)(1) << s; + msk--; + msk <<= p; + val = M[addr]; + val &= CM(msk); + val |= msk & (((uint64)(dat >> (need - s))) << p); + M[addr] = val; + need -= s; + } + return s; +} + +#endif + +#if KI +/* + * Load the TLB entry, used for both page_lookup and MAP. + * Do not call this for direct map executive pages. + */ +int +load_tlb(int uf, int page) +{ + uint64 data; + int base = 0; + int upmp = 0; + + if (!uf) { /* Handle system mapping */ /* Pages 340-377 via UBR */ if ((page & 0740) == 0340) { @@ -1480,21 +2739,12 @@ int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch base = 1; /* Pages 000-037 direct map */ } else { - /* Check if supervisory mode */ - *loc = addr; - /* If PUBLIC and private page, make sure we are fetching a Portal */ - if (!flag && ((FLAGS & PUBLIC) != 0) && - (!fetch || (M[addr] & 00777040000000LL) != 0254040000000LL)) { - /* Handle public violation */ - fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) - | 021LL; - page_fault = 1; - return !wr; - } - return 1; + /* Return what MAP wants to see */ + return (KI_PAG_A | KI_PAG_X | page); } } /* Map the page */ + sim_interval--; if (base) { data = e_tlb[page]; if (data == 0) { @@ -1519,23 +2769,94 @@ int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch else last_page = ((page ^ 0777) << 1); } + return (int)(data & RMASK); +} + +/* + * Handle page lookup on KI10 + * + * addr is address to look up. + * flag is set for pi cycle and user overide. + * loc is final address. + * wr indicates whether cycle is read or write. + * cur_context is set when access should ignore xct_flag + * fetch is set for instruction fetches. + */ +int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { + int data; + int base = 0; + int page = (RMASK & addr) >> 9; + int uf = (FLAGS & USER) != 0; + int pub = (FLAGS & PUBLIC) != 0; + + if (page_fault) + return 0; + + /* If paging is not enabled, address is direct */ + if (!page_enable) { + *loc = addr; + return 1; + } + + /* If fetching byte data, use write access */ + if (BYF5 && (IR & 06) == 6) + wr = 1; + + /* If this is modify instruction use write access */ + wr |= modify; + + /* Figure out if this is a user space access */ + if (flag) + uf = 0; + else if (xct_flag != 0 && !cur_context) { + if (((xct_flag & 2) != 0 && wr != 0) || + ((xct_flag & 1) != 0 && (wr == 0 || modify))) { + uf = (FLAGS & USERIO) != 0; + pub = (FLAGS & PRV_PUB) != 0; + } + } + + /* If user, check if small user enabled */ + if (uf) { + if (small_user && (page & 0340) != 0) { + fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) | 020LL; + page_fault = 1; + return 0; + } + } + + /* Handle direct pages */ + if (!uf && page < 0340) { + /* Check if supervisory mode */ + *loc = addr; + /* If PUBLIC and private page, make sure we are fetching a Portal */ + if (!flag && pub && + (!fetch || (M[addr] & 00777040000000LL) != 0254040000000LL)) { + /* Handle public violation */ + fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) + | 021LL; + page_fault = 1; + return !wr; + } + return 1; + } + data = load_tlb(uf, page); *loc = ((data & 017777) << 9) + (addr & 0777); /* Check for access error */ - if ((data & RSIGN) == 0 || (wr & ((data & 0100000) == 0))) { + if ((data & KI_PAG_A) == 0 || (wr & ((data & KI_PAG_W) == 0))) { page = (RMASK & addr) >> 9; fault_data = ((((uint64)(page))<<18) | ((uint64)(uf) << 27)) & LMASK; - fault_data |= (data & 0400000) ? 010LL : 0LL; /* A */ - fault_data |= (data & 0100000) ? 004LL : 0LL; /* W */ - fault_data |= (data & 0040000) ? 002LL : 0LL; /* S */ + fault_data |= (data & KI_PAG_A) ? 010LL : 0LL; /* A */ + fault_data |= (data & KI_PAG_W) ? 004LL : 0LL; /* W */ + fault_data |= (data & KI_PAG_S) ? 002LL : 0LL; /* S */ fault_data |= wr; page_fault = 1; return 0; } /* If PUBLIC and private page, make sure we are fetching a Portal */ - if (!flag && ((FLAGS & PUBLIC) != 0) && ((data & 0200000) == 0) && - (!fetch || (M[*loc] & 00777040000000LL) != 0254040000000LL)) { + if (!flag && pub && ((data & KI_PAG_P) == 0) && (!fetch || !OP_PORTAL(M[*loc]))) { /* Handle public violation */ fault_data = (((uint64)(page))<<18) | ((uint64)(uf) << 27) | 021LL; page_fault = 1; @@ -1543,7 +2864,7 @@ int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch } /* If fetching from public page, set public flag */ - if (fetch && ((data & 0200000) != 0)) + if (fetch && ((data & KI_PAG_P) != 0)) FLAGS |= PUBLIC; return 1; } @@ -1565,47 +2886,8 @@ void set_reg(int reg, uint64 value) { FM[reg & 017] = value; } -/* - * Read a location directly from memory. - * - * Return of 0 if successful, 1 if there was an error. - */ -int Mem_read_nopage() { - if (AB < 020) { - MB = FM[AB]; - } else { - sim_interval--; - if (AB >= (int)MEMSIZE) { - nxm_flag = 1; - return 1; - } - MB = M[AB]; - } - return 0; -} - -/* - * Write a directly to a location in memory. - * - * Return of 0 if successful, 1 if there was an error. - */ -int Mem_write_nopage() { - - if (AB < 020) { - FM[AB] = MB; - } else { - sim_interval--; - if (AB >= (int)MEMSIZE) { - nxm_flag = 1; - return 1; - } - M[AB] = MB; - } - return 0; -} - int Mem_read(int flag, int cur_context, int fetch) { - int addr; + t_addr addr; if (AB < 020) { if (FLAGS & USER) { @@ -1626,7 +2908,6 @@ int Mem_read(int flag, int cur_context, int fetch) { MB = get_reg(AB); } else { read: - sim_interval--; if (!page_lookup(AB, flag, &addr, 0, cur_context, fetch)) return 1; if (addr >= (int)MEMSIZE) { @@ -1635,13 +2916,14 @@ read: } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) watch_stop = 1; + sim_interval--; MB = M[addr]; } return 0; } int Mem_write(int flag, int cur_context) { - int addr; + t_addr addr; if (AB < 020) { if (FLAGS & USER) { @@ -1665,7 +2947,6 @@ int Mem_write(int flag, int cur_context) { set_reg(AB, MB); } else { write: - sim_interval--; if (!page_lookup(AB, flag, &addr, 1, cur_context, 0)) return 1; if (addr >= (int)MEMSIZE) { @@ -1674,6 +2955,7 @@ write: } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) watch_stop = 1; + sim_interval--; M[addr] = MB; } return 0; @@ -1698,11 +2980,12 @@ int its_load_tlb(uint32 reg, int page, uint32 *tlb) { fault_data |= 0200; return 1; } - if (entry > (int)MEMSIZE) { + if (entry >= (int)MEMSIZE) { nxm_flag = 1; fault_data |= 0400; return 1; } + sim_interval--; data = M[entry]; if (page & 1) { data &= ~036000LL; @@ -1724,7 +3007,7 @@ int its_load_tlb(uint32 reg, int page, uint32 *tlb) { * Translation logic for KA10 */ -int page_lookup_its(int addr, int flag, int *loc, int wr, int cur_context, int fetch) { +int page_lookup_its(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { uint64 data; int base = 0; int page = (RMASK & addr) >> 10; @@ -1748,7 +3031,7 @@ int page_lookup_its(int addr, int flag, int *loc, int wr, int cur_context, int f /* Figure out if this is a user space access */ if (flag) uf = 0; - else if (xct_flag != 0 && !cur_context && !uf) { + else if (xct_flag != 0 && !cur_context) { if (((xct_flag & 2) != 0 && wr != 0) || ((xct_flag & 1) != 0 && (wr == 0 || modify))) { uf = 1; @@ -1856,16 +3139,15 @@ fault: * Return of 0 if successful, 1 if there was an error. */ int Mem_read_its(int flag, int cur_context, int fetch) { - int addr; + t_addr addr; if (AB < 020) { - if ((xct_flag & 1) != 0 && !cur_context && (FLAGS & USER) == 0) { + if ((xct_flag & 1) != 0 && !cur_context) { MB = M[(ac_stack & 01777777) + AB]; return 0; } MB = get_reg(AB); } else { - sim_interval--; if (!page_lookup_its(AB, flag, &addr, 0, cur_context, fetch)) return 1; #if NUM_DEVS_TEN11 > 0 @@ -1892,6 +3174,7 @@ int Mem_read_its(int flag, int cur_context, int fetch) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) watch_stop = 1; + sim_interval--; MB = M[addr]; } return 0; @@ -1903,16 +3186,15 @@ int Mem_read_its(int flag, int cur_context, int fetch) { * Return of 0 if successful, 1 if there was an error. */ int Mem_write_its(int flag, int cur_context) { - int addr; + t_addr addr; if (AB < 020) { - if ((xct_flag & 2) != 0 && !cur_context && (FLAGS & USER) == 0) { + if ((xct_flag & 2) != 0 && !cur_context) { M[(ac_stack & 01777777) + AB] = MB; return 0; } set_reg(AB, MB); } else { - sim_interval--; if (!page_lookup_its(AB, flag, &addr, 1, cur_context, 0)) return 1; #if NUM_DEVS_TEN11 > 0 @@ -1939,6 +3221,7 @@ int Mem_write_its(int flag, int cur_context) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) watch_stop = 1; + sim_interval--; M[addr] = MB; } return 0; @@ -1946,7 +3229,7 @@ int Mem_write_its(int flag, int cur_context) { #endif #if BBN -int page_lookup_bbn(int addr, int flag, int *loc, int wr, int cur_context, int fetch) { +int page_lookup_bbn(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { /* Group 0, 01 = 00 bit 2 = Age 00x 0100000 bit 3 = Age 02x 0040000 @@ -2008,7 +3291,7 @@ int page_lookup_bbn(int addr, int flag, int *loc, int wr, int cur_context, int f if (flag) uf = 0; else { - if (QWAITS && xct_flag != 0 && !fetch && !uf) { + if (QWAITS && xct_flag != 0 && !fetch) { if (xct_flag & 010 && cur_context) /* Indirect */ uf = 1; if (xct_flag & 004 && wr == 0) /* XR */ @@ -2016,7 +3299,7 @@ int page_lookup_bbn(int addr, int flag, int *loc, int wr, int cur_context, int f if (xct_flag & 001 && (wr == 1 || BYF5)) /* XW or XLB or XDB */ uf = 1; } - if (!QWAITS && (FLAGS & EXJSYS) == 0 && uf == 0 && !fetch && xct_flag != 0) { + if (!QWAITS && (FLAGS & EXJSYS) == 0 && xct_flag != 0 && !fetch) { if (xct_flag & 010 && cur_context) uf = 1; if (xct_flag & 004 && wr == 0) @@ -2050,6 +3333,7 @@ lookup: goto fault_bbn; } base = user_base_reg; + sim_interval--; tlb_data = u_tlb[page]; } else { /* 000 - 077 resident map */ @@ -2064,6 +3348,7 @@ lookup: base = mon_base_reg; else base = 03000; + sim_interval--; tlb_data = e_tlb[page]; } if (tlb_data != 0) { @@ -2086,6 +3371,7 @@ access: /* Map the page */ match = 0; while (!match) { + sim_interval--; data = M[base + map]; switch ((data >> 34) & 03) { @@ -2150,6 +3436,7 @@ access: goto fault_bbn; } /* Update CST */ + sim_interval--; data = M[04000 + (tlb_data & 03777)]; if ((data & 00700000000000LL) == 0) { fault_data = 0100000 >> ((data >> 31) & 03); @@ -2204,14 +3491,13 @@ fault_bbn: * Return of 0 if successful, 1 if there was an error. */ int Mem_read_bbn(int flag, int cur_context, int fetch) { - int addr; + t_addr addr; /* If not doing any special access, just access register */ if (AB < 020 && ((xct_flag == 0 || fetch || cur_context || (FLAGS & USER) != 0))) { MB = get_reg(AB); return 0; } - sim_interval--; if (!page_lookup_bbn(AB, flag, &addr, 0, cur_context, fetch)) return 1; if (addr < 020) { @@ -2224,6 +3510,7 @@ int Mem_read_bbn(int flag, int cur_context, int fetch) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) watch_stop = 1; + sim_interval--; MB = M[addr]; return 0; } @@ -2234,14 +3521,13 @@ int Mem_read_bbn(int flag, int cur_context, int fetch) { * Return of 0 if successful, 1 if there was an error. */ int Mem_write_bbn(int flag, int cur_context) { - int addr; + t_addr addr; /* If not doing any special access, just access register */ if (AB < 020 && ((xct_flag == 0 || cur_context || (FLAGS & USER) != 0))) { set_reg(AB, MB); return 0; } - sim_interval--; if (!page_lookup_bbn(AB, flag, &addr, 1, cur_context, 0)) return 1; if (addr < 020) { @@ -2254,13 +3540,14 @@ int Mem_write_bbn(int flag, int cur_context) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) watch_stop = 1; + sim_interval--; M[addr] = MB; return 0; } #endif #if WAITS -int page_lookup_waits(int addr, int flag, int *loc, int wr, int cur_context, int fetch) { +int page_lookup_waits(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { int uf = (FLAGS & USER) != 0; /* If this is modify instruction use write access */ @@ -2269,7 +3556,7 @@ int page_lookup_waits(int addr, int flag, int *loc, int wr, int cur_context, int /* Figure out if this is a user space access */ if (flag) uf = 0; - else if (xct_flag != 0 && !fetch && !uf) { + else if (xct_flag != 0 && !fetch) { if (xct_flag & 010 && cur_context) /* Indirect */ uf = 1; if (xct_flag & 004 && wr == 0) /* XR */ @@ -2298,13 +3585,12 @@ int page_lookup_waits(int addr, int flag, int *loc, int wr, int cur_context, int } int Mem_read_waits(int flag, int cur_context, int fetch) { - int addr; + t_addr addr; if (AB < 020 && ((xct_flag == 0 || fetch || cur_context || (FLAGS & USER) != 0))) { MB = get_reg(AB); return 0; } - sim_interval--; if (!page_lookup_waits(AB, flag, &addr, 0, cur_context, fetch)) return 1; if (addr >= (int)MEMSIZE) { @@ -2313,6 +3599,7 @@ int Mem_read_waits(int flag, int cur_context, int fetch) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) watch_stop = 1; + sim_interval--; MB = M[addr]; return 0; } @@ -2324,15 +3611,13 @@ int Mem_read_waits(int flag, int cur_context, int fetch) { */ int Mem_write_waits(int flag, int cur_context) { - int addr; - + t_addr addr; /* If not doing any special access, just access register */ if (AB < 020 && ((xct_flag == 0 || cur_context || (FLAGS & USER) != 0))) { set_reg(AB, MB); return 0; } - sim_interval--; if (!page_lookup_waits(AB, flag, &addr, 1, cur_context, 0)) return 1; if (addr >= (int)MEMSIZE) { @@ -2341,12 +3626,13 @@ int Mem_write_waits(int flag, int cur_context) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) watch_stop = 1; + sim_interval--; M[addr] = MB; return 0; } #endif -int page_lookup_ka(int addr, int flag, int *loc, int wr, int cur_context, int fetch) { +int page_lookup_ka(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { if (!flag && (FLAGS & USER) != 0) { if (addr <= Pl) { *loc = (addr + Rl) & RMASK; @@ -2368,12 +3654,11 @@ int page_lookup_ka(int addr, int flag, int *loc, int wr, int cur_context, int fe } int Mem_read_ka(int flag, int cur_context, int fetch) { - int addr; + t_addr addr; if (AB < 020) { MB = get_reg(AB); } else { - sim_interval--; if (!page_lookup_ka(AB, flag, &addr, 0, cur_context, fetch)) return 1; if (addr >= (int)MEMSIZE) { @@ -2382,6 +3667,7 @@ int Mem_read_ka(int flag, int cur_context, int fetch) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('R'))) watch_stop = 1; + sim_interval--; MB = M[addr]; } return 0; @@ -2394,12 +3680,11 @@ int Mem_read_ka(int flag, int cur_context, int fetch) { */ int Mem_write_ka(int flag, int cur_context) { - int addr; + t_addr addr; if (AB < 020) { set_reg(AB, MB); } else { - sim_interval--; if (!page_lookup_ka(AB, flag, &addr, 1, cur_context, 0)) return 1; if (addr >= (int)MEMSIZE) { @@ -2408,13 +3693,12 @@ int Mem_write_ka(int flag, int cur_context) { } if (sim_brk_summ && sim_brk_test(AB, SWMASK('W'))) watch_stop = 1; + sim_interval--; M[addr] = MB; } return 0; } -int (*Mem_read)(int flag, int cur_context, int fetch); -int (*Mem_write)(int flag, int cur_context); #endif #if PDP6 @@ -2519,7 +3803,7 @@ t_stat dev_apr(uint32 dev, uint64 *data) { #define get_reg(reg) FM[(reg) & 017] #define set_reg(reg, value) FM[(reg) & 017] = value -int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch) { +int page_lookup(t_addr addr, int flag, t_addr *loc, int wr, int cur_context, int fetch) { if (!flag && (FLAGS & USER) != 0) { if (addr <= Pl) { *loc = (addr + Rl) & RMASK; @@ -2534,12 +3818,12 @@ int page_lookup(int addr, int flag, int *loc, int wr, int cur_context, int fetch } int Mem_read(int flag, int cur_context, int fetch) { - int addr; + t_addr addr; + sim_interval--; if (AB < 020) { MB = get_reg(AB); } else { - sim_interval--; if (!page_lookup(AB, flag, &addr, 0, cur_context, fetch)) return 1; if (addr >= (int)MEMSIZE) { @@ -2560,12 +3844,12 @@ int Mem_read(int flag, int cur_context, int fetch) { */ int Mem_write(int flag, int cur_context) { - int addr; + t_addr addr; + sim_interval--; if (AB < 020) { set_reg(AB, MB); } else { - sim_interval--; if (!page_lookup(AB, flag, &addr, 1, cur_context, 0)) return 1; if (addr >= (int)MEMSIZE) { @@ -2580,6 +3864,81 @@ int Mem_write(int flag, int cur_context) { } #endif +/* + * Read a location directly from memory. + * + * Return of 0 if successful, 1 if there was an error. + */ +int Mem_read_nopage() { + if (AB < 020) { + MB = get_reg(AB); + } else { + if (AB >= (int)MEMSIZE) { +#if KL + irq_flags |= 02000; +#else + nxm_flag = 1; +#endif + return 1; + } + sim_interval--; + MB = M[AB]; + } + return 0; +} + +/* + * Write a directly to a location in memory. + * + * Return of 0 if successful, 1 if there was an error. + */ +int Mem_write_nopage() { + if (AB < 020) { + set_reg(AB, MB); + } else { + if (AB >= (int)MEMSIZE) { +#if KL + irq_flags |= 02000; +#else + nxm_flag = 1; +#endif + return 1; + } + sim_interval--; + M[AB] = MB; + } + return 0; +} + +/* + * Access main memory. Returns 0 if access ok, 1 if out of memory range. + * On KI10 and KL10, optional EPT flag indicates address relative to ept. + */ +int Mem_read_word(t_addr addr, uint64 *data, int ept) +{ +#if KL | KI + if (ept) + addr += eb_ptr; +#endif + if (addr >= MEMSIZE) + return 1; + *data = M[addr]; + return 0; +} + +int Mem_write_word(t_addr addr, uint64 *data, int ept) +{ +#if KL | KI + if (ept) + addr += eb_ptr; +#endif + if (addr >= MEMSIZE) + return 1; + M[addr] = *data; + return 0; +} + + /* * Function to determine number of leading zero bits in a work */ @@ -2603,6 +3962,7 @@ int pi_rq; /* Interrupt request */ int pi_ov; /* Overflow during PI cycle */ int pi_cycle; /* Executing an interrupt */ int ind; /* Indirect bit */ +int ix; int f_load_pc; /* Load AB from PC at start of instruction */ int f_inst_fetch; /* Fetch new instruction */ int f_pc_inh; /* Inhibit PC increment after instruction */ @@ -2614,7 +3974,7 @@ int flag1; int flag3; int instr_count = 0; /* Number of instructions to execute */ uint32 IA; -#if ITS +#if ITS | KL_ITS char one_p_arm = 0; /* One proceed arm */ #endif @@ -2639,6 +3999,9 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */ BYF5 = 0; #if KI | KL page_fault = 0; +#if KL + ptr_flg = 0; +#endif #endif #if ITS if (QITS) { @@ -2646,11 +4009,15 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */ set_quantum(); } #endif - watch_stop = 0; +#if KL_ITS + if (QITS) + one_p_arm = 0; +#endif + watch_stop = 0; - while ( reason == 0) { /* loop until ABORT */ - AIO_CHECK_EVENT; /* queue async events */ - if (sim_interval <= 0) { /* check clock queue */ + while ( reason == 0) { /* loop until ABORT */ + AIO_CHECK_EVENT; /* queue async events */ + if (sim_interval <= 0) { /* check clock queue */ if ((reason = sim_process_event()) != SCPE_OK) {/* error? stop sim */ #if ITS if (QITS) @@ -2677,6 +4044,12 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */ xct_flag = 0; #if KI | KL trap_flag = 0; +#if KL + sect = cur_sect = pc_sect; + glb_sect = 0; + extend = 0; + ptr_flg = 0; +#endif #endif AB = PC; uuo_cycle = 0; @@ -2696,11 +4069,16 @@ fetch: } } #endif - if (Mem_read(pi_cycle | uuo_cycle, 1, 1)) { +#if KA | PDP6 pi_rq = check_irq_level(); if (pi_rq) goto st_pi; +#endif +#if KL + if (((fault_data >> 30) & 037) == 021) + PC = (PC + 1) & RMASK; +#endif goto last; } @@ -2709,6 +4087,9 @@ no_fetch: AC = (MB >> 23) & 017; AD = MB; /* Save for historical sake */ IA = AB; +#if KL + glb_sect = 0; +#endif i_flags = opflags[IR]; BYF5 = 0; } @@ -2716,17 +4097,46 @@ no_fetch: #if KI | KL /* Handle page fault and traps */ if (page_enable && trap_flag == 0 && (FLAGS & (TRP1|TRP2))) { - AB = 0420 + ((FLAGS & (TRP1|TRP2)) >> 2); - trap_flag = FLAGS & (TRP1|TRP2); - FLAGS &= ~(TRP1|TRP2); - pi_cycle = 1; - AB += (FLAGS & USER) ? ub_ptr : eb_ptr; - Mem_read_nopage(); - goto no_fetch; + if (FLAGS & ADRFLT) { +#if KL_ITS + if (QITS && (FLAGS & (TRP1|TRP2|ADRFLT)) == (TRP1|TRP2|ADRFLT)) + one_p_arm = 1; +#endif + FLAGS &= ~ADRFLT; + } else { + AB = 0420 + ((FLAGS & (TRP1|TRP2)) >> 2); + trap_flag = FLAGS & (TRP1|TRP2); + FLAGS &= ~(TRP1|TRP2); + pi_cycle = 1; + AB += (FLAGS & USER) ? ub_ptr : eb_ptr; + Mem_read_nopage(); + goto no_fetch; + } } #endif +#if KL + /* If we are doing a PXCT with E1 or E2 set, change section */ + if (QKLB && t20_page) { + if (xct_flag != 0) { + if (((xct_flag & 8) != 0 && !ptr_flg) || + ((xct_flag & 2) != 0 && ptr_flg) +/* The following two lines are needed for Tops20 V3 */ +#if 1 + || ((xct_flag & 014) == 04 && !ptr_flg && prev_sect == 0) || + ((xct_flag & 03) == 01 && ptr_flg && prev_sect == 0) +#endif + ) + sect = cur_sect = prev_sect; + } + /* Short cut for extended pointer address */ + if (ptr_flg && (glb_sect || cur_sect != 0) && (AR & BIT12) != 0) { /* Full pointer */ + ind = 1; /* Allow us to read word, xDB has already bumped AB */ + goto in_loop; + } + } +#endif /* Handle indirection repeat until no longer indirect */ do { if ((!pi_cycle) & pi_pending @@ -2736,31 +4146,121 @@ no_fetch: ) { pi_rq = check_irq_level(); } - ind = (MB & 020000000) != 0; + ind = TST_IND(MB) != 0; AR = MB; AB = MB & RMASK; - if (MB & 017000000) { - AR = MB = (AB + get_reg((MB >> 18) & 017)) & FMASK; + ix = GET_XR(MB); + if (ix) { +#if KL + if (((xct_flag & 8) != 0 && !ptr_flg) || + ((xct_flag & 2) != 0 && ptr_flg)) + AR = FM[prev_ctx|ix]; + else + AR = get_reg(ix); + /* Check if extended indexing */ + if (QKLB && t20_page && cur_sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { + AR = (AR + ((AB & RSIGN) ? SECTM|((uint64)AB): (uint64)AB)) & (SECTM|RMASK); + sect = cur_sect = (AR >> 18) & 07777; + glb_sect = 1; + AB = 0; + } else + glb_sect = 0; + /* For KL */ + AR = MB = (AB + AR) & FMASK; +#else + /* For KA & KI */ + AR = MB = (AB + get_reg(ix)) & FMASK; +#endif AB = MB & RMASK; } - if (IR != 0254) - AR &= RMASK; - if (ind & !pi_rq) - if (Mem_read(pi_cycle | uuo_cycle, 1, 0)) +#if KL +in_loop: +#endif + if (ind & !pi_rq) { + if (Mem_read(pi_cycle | uuo_cycle, 1, 0)) goto last; +#if KL + /* Check if extended indexing */ + if (QKLB && t20_page && (cur_sect != 0 || glb_sect)) { + if (MB & SMASK || cur_sect == 0) { /* Instruction format IFIW */ + if (MB & BIT1 && cur_sect != 0) { /* Illegal index word */ + fault_data = 024LL << 30 | (((FLAGS & USER) != 0)?SMASK:0) | + (AR & RMASK) | ((uint64)cur_sect << 18); + page_fault = 1; + goto last; + } + ind = TST_IND(MB) != 0; + ix = GET_XR(MB); + AB = MB & RMASK; + if (ix) { + if (((xct_flag & 8) != 0 && !ptr_flg) || + ((xct_flag & 2) != 0 && ptr_flg)) + AR = FM[prev_ctx|ix]; + else + AR = get_reg(ix); + /* Check if extended indexing */ + if (cur_sect == 0 || (AR & SMASK) != 0 || (AR & SECTM) == 0) { + /* Local index word */ + AR = (AR + AB) & RMASK; + glb_sect = 0; + } else { + AR = (AR + AB) & FMASK; + glb_sect = 1; + sect = cur_sect = (AR >> 18) & 07777; + } + MB = AR; + } else { + glb_sect = 0; + if ((MB & RMASK) < 020) + sect = cur_sect = 1; + AR = MB; + } + AB = AR & RMASK; + } else { /* Extended index EFIW */ + ind = (MB & BIT1) != 0; + ix = (MB >> 30) & 017; + AB = MB & (SECTM|RMASK); + if (ix) { + if (((xct_flag & 8) != 0 && !ptr_flg) || + ((xct_flag & 2) != 0 && ptr_flg)) + AR = FM[prev_ctx|ix]; + else + AR = get_reg(ix); + if ((AR & SMASK) != 0 || (AR & SECTM) == 0) { /* Local index word */ + AR = AB + (((AR & RSIGN) ? 0: 0)|(AR & RMASK)); + } else + AR = AR + AB; + AR &= FMASK; + MB = AR; + } else + AR = MB; + sect = cur_sect = (AR >> 18) & 07777; + AB = AR & RMASK; + glb_sect = 1; + } + if (ind) + goto in_loop; + } +#endif + } /* Handle events during a indirect loop */ - AIO_CHECK_EVENT; /* queue async events */ + AIO_CHECK_EVENT; /* queue async events */ if (sim_interval-- <= 0) { if ((reason = sim_process_event()) != SCPE_OK) { return reason; } } } while (ind & !pi_rq); + if (IR != 0254) { + AR &= RMASK; + } /* If there is a interrupt handle it. */ if (pi_rq) { +#if KA | PDP6 st_pi: +#endif sim_debug(DEBUG_IRQ, &cpu_dev, "trap irq %o %03o %03o \n", pi_enc, PIR, PIH); pi_cycle = 1; @@ -2768,8 +4268,12 @@ st_pi: pi_hold = 0; pi_ov = 0; AB = 040 | (pi_enc << 1) | maoff; -#if KI | KL xct_flag = 0; +#if KI | KL +#if KL + sect = cur_sect = 0; + extend = 0; +#endif /* * Scan through the devices and allow KI devices to have first * hit at a given level. @@ -2777,13 +4281,21 @@ st_pi: for (f = 0; f < 128; f++) { if (dev_irqv[f] != 0 && dev_irq[f] & (0200 >> pi_enc)) { AB = dev_irqv[f](f << 2, AB); + if (dev_irqv[f] != 0) + sim_debug(DEBUG_IRQ, &cpu_dev, "vect irq %o %03o %06o\n", + pi_enc, dev_irq[f], AB); break; } } - AB |= eb_ptr; + if (AB & RSIGN) + AB &= 0777; + else + AB |= eb_ptr; + pi_vect = AB; Mem_read_nopage(); goto no_fetch; #else + pi_vect = AB; goto fetch; #endif } @@ -2798,29 +4310,45 @@ st_pi: #endif /* Check if possible idle loop */ - if (sim_idle_enab && + if (sim_idle_enab && (((FLAGS & USER) != 0 && PC < 020 && AB < 020 && (IR & 0760) == 0340) || (uuo_cycle && (IR & 0740) == 0 && IA == 041))) { sim_idle (TMR_RTC, FALSE); } /* Update history */ - if (hst_lnt) { + if (hst_lnt && PC > 017) { hst_p = hst_p + 1; if (hst_p >= hst_lnt) { hst_p = 0; } hst[hst_p].pc = HIST_PC | ((BYF5)? (HIST_PC2|PC) : IA); hst[hst_p].ea = AB; +#if KL + if (extend) + hst[hst_p].pc |= HIST_PCE; + hst[hst_p].pc |= (pc_sect << 18); + hst[hst_p].ea |= (sect << 18); +#endif hst[hst_p].ir = AD; - hst[hst_p].flags = (FLAGS << 5) |(clk_flg << 2) | (nxm_flag << 1) + hst[hst_p].flags = (FLAGS << 5) +#if KA | KI | PDP6 + |(clk_flg << 2) | (nxm_flag << 1) #if KA | PDP6 | (mem_prot << 4) | (push_ovf << 3) #endif #if PDP6 | ill_op #endif +#endif +#if KL + | (fm_sel >> 4) +#endif + ; +#if KL + hst[hst_p].prev_sect = prev_sect; +#endif hst[hst_p].ac = get_reg(AC); } @@ -2833,7 +4361,16 @@ st_pi: sac_inh = 0; modify = 0; f_pc_inh = 0; - +#if KL + if (extend) { + if (IR == 0 || IR > 031 || AC != 0 || do_extend(IA)) { + IR = 0123; + AC = ext_ac; + goto muuo; + } + goto last; + } +#endif /* Load pseudo registers based on flags */ if (i_flags & (FCEPSE|FCE)) { if (i_flags & FCEPSE) @@ -2852,7 +4389,7 @@ st_pi: BR = get_reg(AC); } - if (hst_lnt) { + if (hst_lnt && PC >= 020) { hst[hst_p].mb = AR; } @@ -2868,35 +4405,124 @@ st_pi: /* Process the instruction */ switch (IR) { +#if KL + case 0052: /* PMOVE */ + case 0053: /* PMOVEM */ + if (QKLB && t20_page && (FLAGS & USER) == 0) { + if (Mem_read(0, 0, 0)) + goto last; + AB = MB & (SECTM|RMASK); + if (IR & 1) { + MB = get_reg(AC); + if (Mem_write_nopage()) + goto last; + } else { + if (Mem_read_nopage()) + goto last; + set_reg(AC, MB); + } + break; + } + /* Fall through */ +#else + case 0052: case 0053: + /* Fall through */ +#endif muuo: case 0000: /* UUO */ case 0040: case 0041: case 0042: case 0043: case 0044: case 0045: case 0046: case 0047: - case 0050: case 0051: case 0052: case 0053: + case 0050: case 0051: case 0054: case 0055: case 0056: case 0057: case 0060: case 0061: case 0062: case 0063: case 0064: case 0065: case 0066: case 0067: case 0070: case 0071: case 0072: case 0073: +#if !KL_ITS case 0074: case 0075: case 0076: case 0077: +#endif /* MUUO */ #if KI | KL - case 0100: case 0101: case 0102: case 0103: - case 0104: case 0105: case 0106: case 0107: - case 0123: + case 0100: /* UJEN */ + case 0101: case 0102: case 0103: + case 0104: /* JSYS */ + case 0106: + case 0107: +#if !KL_ITS case 0247: /* UUO */ +#endif unasign: + /* Save Opcode */ +#if KL + if (QKLB && t20_page) { + AR = (uint64)AB; /* Save address */ + if (pc_sect != 0) { + if (glb_sect == 0 && AB < 020) + AR |= BIT17; + else + AR |= ((uint64)cur_sect) << 18; + } + MB = (((uint64)((IR << 9) | (AC << 5))) | ((uint64)(FLAGS) << 23)) & FMASK; + if ((FLAGS & USER) == 0) { + MB &= ~SMASK; + MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + MB |= (uint64)(prev_sect); + } + } else +#endif MB = ((uint64)(IR) << 27) | ((uint64)(AC) << 23) | (uint64)(AB); AB = ub_ptr | 0424; +#if KL + /* If single sections KL10 UUO starts at 425 */ + if (!QKLB && !QITS && t20_page) + AB = AB + 1; +#endif Mem_write_nopage(); - AB |= 1; + /* Save flags */ + AB++; +#if KL + if (QKLB && t20_page) + MB = ((uint64)(pc_sect) << 18) | ((PC + (trap_flag == 0)) & RMASK); + else { + MB = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + (trap_flag == 0)) & RMASK); + if ((FLAGS & USER) == 0) { + MB &= ~SMASK; + MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + } + } +#else MB = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + (trap_flag == 0)) & RMASK); if ((FLAGS & USER) == 0) { MB &= ~SMASK; MB |= (FLAGS & PRV_PUB) ? SMASK : 0; } +#endif Mem_write_nopage(); +#if KL + extend = 0; + if (QKLB && t20_page) { /* Save address */ + if (pc_sect != 0 && glb_sect == 0 && AR < 020) + AR |= BIT17; + else + AR |= ((uint64)cur_sect) << 18; + MB = AR; + AB ++; + Mem_write_nopage(); + } + /* Save context */ + AB ++; + MB = SMASK| + ((uint64)(fm_sel & 0160) << 23) | + ((uint64)(prev_ctx & 0160) << 20) | + (ub_ptr >> 9); + if (QKLB && t20_page) { + MB |= BIT1|((uint64)(prev_sect & 037) << 18); + prev_sect = pc_sect & 037; + } + Mem_write_nopage(); +#endif + /* Read in new PC and flags */ FLAGS &= ~ (PRV_PUB|BYTI|ADRFLT|TRP1|TRP2); AB = ub_ptr | 0430; if (trap_flag != 0) @@ -2906,12 +4532,21 @@ unasign: if (FLAGS & USER) AB |= 4; Mem_read_nopage(); + +#if KL + if (QKLB && t20_page) { + pc_sect = (MB >> 18) & 00037; + FLAGS = 0; + } else +#endif FLAGS = (MB >> 23) & 017777; /* If transistioning from user to executive adjust flags */ - if ((FLAGS & USER) != 0 && (AB & 4) != 0) - FLAGS |= USERIO; - if ((FLAGS & USER) == 0 && (AB & 2 || (FLAGS & OVR) != 0)) - FLAGS |= PRV_PUB|OVR; + if ((FLAGS & USER) == 0) { + if ((AB & 4) != 0) + FLAGS |= USERIO; + if ((AB & 2 || (FLAGS & OVR) != 0)) + FLAGS |= PRV_PUB|OVR; + } PC = MB & RMASK; f_pc_inh = 1; break; @@ -2928,12 +4563,48 @@ unasign: case 0024: case 0025: case 0026: case 0027: case 0030: case 0031: case 0032: case 0033: case 0034: case 0035: case 0036: case 0037: +#if KL + /* LUUO's in non-zero section are different */ + if (QKLB && t20_page && pc_sect != 0) { + /* Save Effective address */ + if (pc_sect != 0 && glb_sect == 0 && AR < 020) + AR = BIT17; + else + AR = ((uint64)cur_sect) << 18; + AR |= AB; /* Save address */ + /* Grab address of LUUO block from user base 420 */ + AB = ((FLAGS & USER) ? ub_ptr : eb_ptr) + 0420; + Mem_read_nopage(); + /* Now save like MUUO */ + AB = MB & (SECTM|RMASK); + MB = (((uint64)((IR << 9) | (AC << 5))) | ((uint64)(FLAGS) << 23)) & FMASK; + if ((FLAGS & USER) == 0) { + MB &= ~SMASK; + MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + } + Mem_write_nopage(); + /* Save PC */ + AB++; + MB = ((uint64)(pc_sect) << 18) | ((PC + (trap_flag == 0)) & RMASK); + Mem_write_nopage(); + MB = AR; + AB ++; + Mem_write_nopage(); + AB ++; + /* Read PC */ + Mem_read_nopage(); + pc_sect = (MB >> 18) & 07777; + PC = MB & RMASK; + f_pc_inh = 1; + break; + } +#endif #if PDP6 ill_op = 1; ex_uuo_sync = 1; #endif MB = ((uint64)(IR) << 27) | ((uint64)(AC) << 23) | (uint64)(AB); -#if KI | KL +#if KI if ((FLAGS & USER) == 0) { AB = eb_ptr + 040; Mem_write_nopage(); @@ -2957,8 +4628,87 @@ unasign: #endif f_pc_inh = 1; break; +#if KL_ITS + case 0074: /* XCTR */ + case 0075: /* XCTRI */ + if (QITS && (FLAGS & USER) == 0) { + f_load_pc = 0; + f_pc_inh = 1; + xct_flag = AC; + break; + } + goto unasign; + + case 0076: /* LMR */ + if (QITS && (FLAGS & USER) == 0) { + /* Load store ITS pager info */ + if ((AB + 8) >= MEMSIZE) { + break; + } + MB = M[AB]; /* WD 0 */ + jpc = (MB & RMASK); + AB = (AB + 1) & RMASK; + MB = M[AB]; /* WD 1 */ + brk_addr = MB & RMASK; + brk_flags = 017 & (MB >> 23); + AB = (AB + 1) & RMASK; + MB = M[AB]; /* WD 2 */ + FM[(6<<4)|0] = MB; + AB = (AB + 1) & RMASK; + MB = M[AB]; /* WD 3 */ + dbr1 = MB; + AB = (AB + 1) & RMASK; + MB = M[AB]; /* WD 4 */ + dbr2 = MB; + for (f = 0; f < 512; f++) + u_tlb[f] = 0; + break; + } + goto unasign; + case 0077: /* SPM */ + if (QITS && (FLAGS & USER) == 0) { + if ((AB + 8) >= MEMSIZE) { + break; + } + MB = (uint64)jpc; + M[AB] = MB; /* WD 0 */ + AB = (AB + 1) & RMASK; + MB = (uint64)brk_addr; + MB |= ((uint64)brk_flags) << 23; + M[AB] = MB; /* WD 1 */ + AB = (AB + 1) & RMASK; + MB = FM[(6<<4)|0]; + M[AB] = MB; /* WD 2 */ + AB = (AB + 1) & RMASK; + MB = dbr1; + M[AB] = MB; /* WD 3 */ + AB = (AB + 1) & RMASK; + MB = dbr2; + M[AB] = MB; /* WD 4 */ + break; + } + goto unasign; +#endif + #if KI | KL +#if KL + case 0105: /* ADJSP */ + BR = get_reg(AC); + if (QKLB && t20_page && pc_sect != 0 && (BR & SMASK) == 0 && (BR & SECTM) != 0) { + AD = (((AR & RSIGN)?(LMASK|AR):AR) + BR) & (SECTM|RMASK); + AD |= BR & ~(SECTM|RMASK); + } else { + AD = (BR + AR) & RMASK; + AD |= (BR & LMASK) + ((AR << 18) & LMASK); + if (QKLB && pc_sect == 0 && ((BR ^ AD) & SMASK) != 0) + FLAGS |= TRP2; + } + i_flags = SAC; + AR = AD & FMASK; + break; +#endif + case 0110: /* DFAD */ case 0111: /* DFSB */ /* On Load AR,MQ has memory operand */ @@ -3155,8 +4905,13 @@ dpnorm: if ((AR & 0777) == 0777) AR &= (FPFMASK << 8); } +#if KL + while (((AR & (FPSBIT|FPNBIT)) == (FPSBIT|FPNBIT)) || + ((AR & (FPSBIT|FPNBIT)) == 0)) { +#else if (((AR & (FPSBIT|FPNBIT)) == (FPSBIT|FPNBIT)) || ((AR & (FPSBIT|FPNBIT)) == 0)) { +#endif SC --; AR <<= 1; if (MQ & BIT1) @@ -3165,6 +4920,16 @@ dpnorm: MQ &= FMASK; nrf = 1; } +#if KL + /* Handle special minus case */ + if (AR == (FPHBIT|FPSBIT)) { + SC += 1; + if (AR & 1) + MQ |= SMASK; + MQ >>= 1; + AR = (AR & FPHBIT) | (AR >> 1); + } +#endif } else { AR = MQ = 0; SC = 0; @@ -3216,13 +4981,18 @@ dpnorm: SMEAR_SIGN(BR); BR <<= 35; BR |= MB & CMASK; +#if KL + /* One extra bit for KL */ + AR <<= 1; + BR <<= 1; +#endif /* Make both positive */ flag1 = 0; - if (AR & FPSBIT) { + if (AR & FPHBIT) { AR = (FPFMASK ^ AR) + 1; flag1 = 1; } - if (BR & FPSBIT) { + if (BR & FPHBIT) { BR = (FPFMASK ^ BR) + 1; flag1 = !flag1; } @@ -3250,7 +5020,7 @@ dpnorm: FLAGS |= FLTUND|OVR|FLTOVR|TRP1; /* Do divide */ AD = 0; - for (FE = 0; FE < 62; FE++) { + for (FE = 0; FE < (62 + KL); FE++) { AD <<= 1; if (AR >= BR) { AR = AR - BR; @@ -3259,15 +5029,24 @@ dpnorm: AR <<= 1; } AR = AD; + /* Fix sign of result */ if (flag1) { AR = (AR ^ FPFMASK) + 1; } +#if KL + else + AR++; /* Round on KL */ + AR = (AR & FPHBIT) | (AR >> 1); /* Remove extra bit */ +#endif + /* Check potential overflow */ if (((SC & 0400) != 0) ^ ((SC & 0200) != 0) || SC == 0600) fxu_hold_set = 1; + /* Normalize */ while (((AR & FPHBIT) != 0) != ((AR & FPSBIT) != 0)) { SC += 1; AR = (AR & FPHBIT) | (AR >> 1); } + /* Extract halfs from 64bit word */ MQ = (AR & CMASK); AR >>= 35; AR &= MMASK; @@ -3279,6 +5058,7 @@ dpnorm: FLAGS |= FLTUND; } } + /* Add in exponent */ SCAD = SC ^ ((AR & SMASK) ? 0377 : 0); AR &= SMASK|MMASK; if (AR != 0 || MQ != 0) @@ -3288,11 +5068,275 @@ dpnorm: set_reg(AC+1, MQ); break; +#if KL + case 0114: /* DADD */ + flag1 = flag3 = 0; + /* AR,ARX = AC BR,BX = mem */ + /* AR High */ + if (Mem_read(0, 0, 0)) + goto last; + BR = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + BRX = MB; + AR = get_reg(AC); + ARX = get_reg(AC + 1); + /* Add numbers */ + ARX = (ARX & CMASK) + (BRX & CMASK); + f = (ARX & SMASK) != 0; + if (((AR & CMASK) + (BR & CMASK) + f) & SMASK) { + FLAGS |= CRY1; + flag1 = 1; + } + AR = AR + BR + f; + if (AR & C1) { + if (!pi_cycle) + FLAGS |= CRY0; + flag3 = 1; + } + AR &= FMASK; + if (flag1 != flag3) { + if (!pi_cycle) + FLAGS |= OVR|TRP1; + check_apr_irq(); + } + ARX &= CMASK; + ARX |= AR & SMASK; + set_reg(AC, AR); + set_reg(AC+1, ARX); + break; + + case 0115: /* DSUB */ + flag1 = flag3 = 0; + /* AR,AX = AC BR,BX = mem */ + /* AR High */ + if (Mem_read(0, 0, 0)) + goto last; + BR = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + BRX = MB; + AR = get_reg(AC); + ARX = get_reg(AC + 1); + /* Add numbers */ + ARX = (ARX & CMASK) + CCM(BRX) + 1; + f = (ARX & SMASK) != 0; + if (((AR & CMASK) + CCM(BR) + f) & SMASK) { + FLAGS |= CRY1; + flag1 = 1; + } + AR = AR + CM(BR) + f; + if (AR & C1) { + if (!pi_cycle) + FLAGS |= CRY0; + flag3 = 1; + } + AR &= FMASK; + if (flag1 != flag3) { + if (!pi_cycle) + FLAGS |= OVR|TRP1; + check_apr_irq(); + } + ARX &= CMASK; + ARX |= AR & SMASK; + set_reg(AC, AR); + set_reg(AC+1, ARX); + break; + + case 0116: /* DMUL */ + flag1 = flag3 = 0; + /* AR,ARX = AC BR,BRX = mem */ + /* AR High */ + if (Mem_read(0, 0, 0)) + goto last; + BR = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + BRX = MB; + AR = get_reg(AC); + ARX = get_reg(AC + 1); + /* Make BR,BRX positive */ + if (BR & SMASK) { + /* Low */ + BRX = CCM(BRX) + 1; /* Low */ + /* High */ + BR = (CM(BR) + ((BRX & SMASK) != 0)) & FMASK; + flag1 = 1; + /* Can only occur if 2**-70 */ + if (BR & SMASK) + FLAGS |= OVR|TRP1; + } + /* Make AR,ARX positive */ + if (AR & SMASK) { + /* Low */ + ARX = CCM(ARX) + 1; /* Low */ + /* High */ + AR = (CM(AR) + ((ARX & SMASK) != 0)) & FMASK; + flag1 ^= 1; + /* Can only occur if 2**-70 */ + if (AR & SMASK) + FLAGS |= OVR|TRP1; + } + /* Form product in AD,ADX,BR,BX */ + AD = ADX = 0; + BRX &= CMASK; /* Clear sign of BX */ + ARX &= CMASK; + /* Compute product */ + for (SC = 70; SC >= 0; SC--) { + /* Shift MQ,MB,BR,BX right one */ + f = (BRX & 1); + if (BR & 1) + BRX |= SMASK; + if (ADX & 1) + BR |= SMASK; + if (AD & 1) + ADX |= SMASK; + BRX >>= 1; + BR >>= 1; + ADX >>= 1; + AD >>= 1; + if (f) { /* Add AR,ARX to AD,ADX */ + ADX = ADX + ARX; + AD = AD + AR + ((ADX & SMASK) != 0); + ADX &= CMASK; + } + } + /* If minus, negate whole thing */ + if (flag1) { + BRX = CCM(BRX) + 1; /* Low */ + BR = CCM(BR) + ((BRX & SMASK) != 0); + ADX = CCM(ADX) + ((BR & SMASK) != 0); + AD = CM(AD) + ((ADX & SMASK) != 0); + } + /* Copy signs */ + BRX &= CMASK; + BR &= CMASK; + ADX &= CMASK; + AD &= FMASK; + BRX |= AD & SMASK; + BR |= AD & SMASK; + ADX |= AD & SMASK; + /* Save results */ + set_reg(AC, AD); + set_reg(AC+1, ADX); + set_reg(AC+2, BR); + set_reg(AC+3, BRX); + break; + + case 0117: /* DDIV */ + flag1 = flag3 = 0; + /* AR,ARX = AC BR,BRX = mem */ + /* AR High */ + if (Mem_read(0, 0, 0)) + goto last; + BR = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + BRX = MB; + /* Make BR,BX positive */ + if (BR & SMASK) { + /* Low */ + BRX = CCM(BRX) + 1; /* Low */ + /* High */ + BR = (CM(BR) + ((BRX & SMASK) != 0)) & FMASK; + flag1 = 1; + /* Can only occur if 2**-70 */ + if (BR & SMASK) { + FLAGS |= OVR|TRP1; + } + } + if ((BR | BRX) == 0) { + FLAGS |= NODIV; + break; + } + /* Get dividend */ + AR = get_reg(AC); + ARX = get_reg(AC + 1); + MB = get_reg(AC + 2); + MQ = get_reg(AC + 3); + + /* Make MQ,MB,AR,ARX positive */ + if (AR & SMASK) { + /* Low */ + MQ = CCM(MQ) + 1; + MB = CCM(MB) + ((MQ & SMASK) != 0); + ARX = CCM(ARX) + ((MB & SMASK) != 0); + AR = (CM(AR) + ((ARX & SMASK) != 0)) & FMASK; + flag1 ^= 1; + flag3 = 1; + if (AR & SMASK) { + FLAGS |= OVR|TRP1; + } + } + MQ &= CMASK; + MB &= CMASK; + ARX &= CMASK; + /* Precheck divide ok */ + ADX = ARX + CCM(BRX) + 1; + AD = AR + CM(BR) + ((ADX & SMASK) != 0); + if ((AD & C1) != 0) { + FLAGS |= OVR|TRP1|NODIV; + break; + } + /* Do divide */ + for (SC = 70; SC > 0; SC--) { + AR <<= 1; + ARX <<= 1; + MB <<= 1; + MQ <<= 1; + if (ARX & SMASK) + AR |= 1; + if (MB & SMASK) + ARX |= 1; + if (MQ & SMASK) + MB |= 1; + ARX &= CMASK; + MB &= CMASK; + MQ &= CMASK; + ADX = ARX + CCM(BRX) + 1; + AD = AR + CM(BR) + ((ADX & SMASK) != 0); + if ((AD & SMASK) == 0) { + ARX = ADX; + AR = AD & CMASK; + MQ |= 1; + } + } + BRX &= CMASK; /* Clear sign of BX */ + ARX &= CMASK; + /* Set sign of quotent */ + if (flag1) { + MQ = CCM(MQ) + 1; + MB = CM(MB) + ((MQ & SMASK) != 0); + MQ &= CMASK; + MB &= FMASK; + } + /* Set sign or remainder */ + if (flag3) { + ARX = CCM(ARX) + 1; /* Low */ + AR = CM(AR) + ((ARX & SMASK) != 0); + ARX &= CMASK; + AR &= FMASK; + } + MQ |= MB & SMASK; + ARX |= AR & SMASK; + /* Save results */ + set_reg(AC, MB); + set_reg(AC+1, MQ); + set_reg(AC+2, AR); + set_reg(AC+3, ARX); + break; + +#else case 0114: /* DADD */ case 0115: /* DSUB */ case 0116: /* DMUL */ case 0117: /* DDIV */ goto unasign; +#endif case 0120: /* DMOVE */ if (Mem_read(0, 0, 0)) @@ -3313,16 +5357,53 @@ dpnorm: AB = (AB + 1) & RMASK; if (Mem_read(0, 0, 0)) goto last; - MQ = ((MB & CMASK) ^ CMASK) + 1; /* Low */ + MQ = CCM(MB) + 1; /* Low */ /* High */ - AR = (CM(AR) + ((MQ & SMASK) != 0)) & FMASK; +#if KL + if ((CCM(AR) + ((MQ & SMASK) != 0)) & SMASK) { + FLAGS |= CRY1; + flag1 = 1; + } +#endif + AR = (CM(AR) + ((MQ & SMASK) != 0)); MQ &= CMASK; +#if KL + if (AR & C1) { + FLAGS |= CRY0; + flag3 = 1; + } + if (flag1 != flag3 && !pi_cycle) { + FLAGS |= OVR|TRP1; + check_apr_irq(); + } + if ((AR == SMASK && MQ == 0) && !pi_cycle) + FLAGS |= TRP1; +#endif + AR &= FMASK; set_reg(AC, AR); set_reg(AC+1, MQ); break; + case 0123: /* Extend */ +#if KL + /* Handle like xct */ + f_load_pc = 0; + f_pc_inh = 1; + extend = 1; + ext_ac = AC; + BR = AB; /* Save address of instruction */ + if (Mem_read(0, 1, 0)) + goto last; + goto no_fetch; +#else + goto unasign; +#endif + case 0124: /* DMOVEM */ AR = get_reg(AC); +#if KL + MQ = get_reg(AC + 1); +#endif /* Handle each half as seperate instruction */ if ((FLAGS & BYTI) == 0) { MB = AR; @@ -3330,13 +5411,15 @@ dpnorm: goto last; FLAGS |= BYTI; } +#if !KL MQ = get_reg(AC + 1); +#endif if ((FLAGS & BYTI)) { AB = (AB + 1) & RMASK; MB = MQ; + FLAGS &= ~BYTI; if (Mem_write(0, 0)) goto last; - FLAGS &= ~BYTI; } break; @@ -3346,15 +5429,42 @@ dpnorm: /* Handle each half as seperate instruction */ if ((FLAGS & BYTI) == 0) { BR = AR = CM(AR); - BR = (BR + 1); - MQ = (((MQ & CMASK) ^ CMASK) + 1); - if (MQ & SMASK) + BR = BR + 1; + MQ = CCM(MQ) + 1; + if (MQ & SMASK) { +#if KL + if ((CCM(get_reg(AC)) + 1) & SMASK) { + FLAGS |= CRY1; + flag1 = 1; + } +#endif AR = BR; +#if KL + if (AR & C1) { + FLAGS |= CRY0; + flag3 = 1; + } + if (flag1 != flag3 && !pi_cycle) { + FLAGS |= OVR|TRP1; + check_apr_irq(); + } + if ((AR == SMASK && MQ == 0) && !pi_cycle) + FLAGS |= TRP1; +#endif + } AR &= FMASK; MB = AR; if (Mem_write(0, 0)) goto last; FLAGS |= BYTI; +#if KL + AB = (AB + 1) & RMASK; + MB = MQ & CMASK; + if (Mem_write(0, 0)) + goto last; + FLAGS &= ~BYTI; + break; +#endif } if ((FLAGS & BYTI)) { MQ = get_reg(AC + 1); @@ -3446,7 +5556,7 @@ dpnorm: /* Load store ITS pager info */ /* AC & 1 = Store */ if (AC & 1) { - if ((AB + 8) > MEMSIZE) { + if ((AB + 8) >= MEMSIZE) { fault_data |= 0400; mem_prot = 1; break; @@ -3479,7 +5589,7 @@ dpnorm: MB = (uint64)ac_stack; M[AB] = MB; } else { - if ((AB + 8) > MEMSIZE) { + if ((AB + 8) >= MEMSIZE) { fault_data |= 0400; mem_prot = 1; break; @@ -3498,10 +5608,9 @@ dpnorm: AB = (AB + 1) & RMASK; MB = M[AB]; /* WD 3 */ /* Store Quantum */ - qua_time = MB & (RMASK|BIT17); + qua_time = MB & RMASK; set_quantum(); fault_data = (MB >> 18) & RMASK; - fault_data &= ~1; /* Clear high quantum bit */ mem_prot = 0; if ((fault_data & 0777772) != 0) mem_prot = 1; @@ -3611,7 +5720,7 @@ dpnorm: goto unasign; case 0247: /* UUO or ITS CIRC instruction */ -#if ITS +#if ITS | KL_ITS if (QITS) { BR = AR; AR = get_reg(AC); @@ -3651,9 +5760,9 @@ dpnorm: goto ufa; } #endif - + /* UUO */ - case 0105: case 0106: case 0107: + case 0105: case 0106: case 0107: case 0110: case 0111: case 0112: case 0113: case 0114: case 0115: case 0116: case 0117: case 0120: case 0121: case 0122: case 0123: @@ -3681,35 +5790,167 @@ unasign: #endif case 0133: /* IBP/ADJBP */ +#if KL + if (AC != 0) { /* ADJBP */ + if (Mem_read(0, 0, 0)) + goto last; + AR = MB; + SC = (AR >> 24) & 077; /* S */ + if (SC) { + int bpw, left, newb, adjw, adjb; + + FE = (AR >> 30) & 077; /* P */ + f = 0; + if (QKLB && t20_page && pc_sect != 0 && FE > 36) { + if (FE == 077) + goto muuo; + f = 1; + SC = _byte_adj[(FE - 37)].s; + FE = _byte_adj[(FE - 37)].p; + } + left = (36 - FE) / SC; /* Number bytes left (36 - P)/S */ + bpw = left + (FE / SC); /* Bytes per word */ + if (bpw == 0) { + FLAGS |= OVR|NODIV|TRP1; + break; + } + BR = get_reg(AC); /* Grab amount to move */ + /* Make BR into native integer */ + if (BR & RSIGN) + adjw = -((int)(CM(BR) + 1) & RMASK); + else + adjw = (int)(BR & RMASK); + newb = adjw + left; /* Adjust to word boundry */ + adjw = newb / bpw; /* Number of words to move */ + adjb = (newb >= 0)? newb % bpw: -((-newb) % bpw); + if (adjb <= 0) { + adjb += bpw; /* Move forward */ + adjw--; + } + FE = 36 - (adjb * SC) - ((36 - FE) % SC); /* New P */ + if (f) { + /* Short pointer */ + for (f = 0; f < 28; f++) { + if (_byte_adj[f].s == SC && _byte_adj[f].p == FE) { + FE = f + 37; + break; + } + } + AR = (((uint64)(FE & 077)) << 30) | /* Make new BP */ + ((AR + adjw) & (SECTM|RMASK)); + set_reg(AC, AR); + break; + } else if (QKLB && t20_page && pc_sect != 0 && (AR & BIT12) != 0) { + /* Full pointer */ + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + AR = (((uint64)(FE & 077)) << 30) | /* Make new BP */ + (AR & PMASK); /* S and below */ + if (MB & SMASK) { + if (MB & BIT1) { + fault_data = 024LL << 30 | (((FLAGS & USER) != 0)?SMASK:0) | + (AB & RMASK) | ((uint64)cur_sect << 18); + page_fault = 1; + goto last; + } + BR = ((MB + adjw) & RMASK) | (MB & LMASK); + } else + BR = ((MB + adjw) & (SECTM|RMASK)) | (MB & ~(SECTM|RMASK)); + set_reg(AC, AR); + set_reg(AC+1, BR); + break; + } + AR = (((uint64)(FE & 077)) << 30) | /* Make new BP */ + (AR & PMASK & LMASK) | /* S,IX,I */ + ((AR + adjw) & RMASK); + } + set_reg(AC, AR); + break; + } +#endif case 0134: /* ILDB */ case 0136: /* IDPB */ if ((FLAGS & BYTI) == 0) { /* BYF6 */ +#if KL + if (Mem_read(0, 0, 0)) { +#else modify = 1; if (Mem_read(0, !QITS, 0)) { +#endif #if PDP6 FLAGS |= BYTI; #endif goto last; } AR = MB; + SCAD = (AR >> 30) & 077; +#if KL + if (QKLB && t20_page && pc_sect != 0 && SCAD > 36) { /* Extended pointer */ + f = SCAD - 37; + if (SCAD == 077) + goto muuo; + SC = _byte_adj[f].s; + SCAD = (_byte_adj[f].p + (0777 ^ SC) + 1) & 0777; + f++; + if (SCAD & 0400) { + SCAD = ((0777 ^ SC) + 044 + 1) & 0777; + AR++; + for(f = 0; f < 28; f++) { + if (_byte_adj[f].s == SC && _byte_adj[f].p == SCAD) + break; + } + } + AR &= (SECTM|RMASK); + AR |= ((uint64)(f + 37)) << 30; + MB = AR; + if (Mem_write(0, 0)) + goto last; + goto ld_ptr; + } +#endif SC = (AR >> 24) & 077; - SCAD = (((AR >> 30) & 077) + (0777 ^ SC) + 1) & 0777; + SCAD = (SCAD + (0777 ^ SC) + 1) & 0777; if (SCAD & 0400) { - SC = ((0777 ^ ((AR >> 24) & 077)) + 044 + 1) & 0777; -#if KI | KL + SCAD = ((0777 ^ SC) + 044 + 1) & 0777; +#if KL + if (QKLB && t20_page && pc_sect != 0 && (AR & BIT12) != 0) { /* Full pointer */ + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + if (MB & SMASK) { + if (MB & BIT1) { + fault_data = 024LL << 30 | (((FLAGS & USER) != 0)?SMASK:0) | + (AB & RMASK) | ((uint64)cur_sect << 18); + page_fault = 1; + goto last; + } + MB = ((MB + 1) & RMASK) | (MB & LMASK); + } else + MB = ((MB + 1) & (SECTM|RMASK)) | (MB & ~(SECTM|RMASK)); + if (Mem_write(0,0)) + goto last; + AB = (AB - 1) & RMASK; + } else + AR = (AR & LMASK) | ((AR + 1) & RMASK); +#elif KI AR = (AR & LMASK) | ((AR + 1) & RMASK); #else AR = (AR + 1) & FMASK; #endif - } else - SC = SCAD; + } AR &= PMASK; - AR |= (uint64)(SC & 077) << 30; + AR |= (uint64)(SCAD & 077) << 30; MB = AR; +#if KL + if (Mem_write(0, 0)) +#else if (Mem_write(0, !QITS)) +#endif goto last; if ((IR & 04) == 0) break; + modify = 0; goto ldb_ptr; } /* Fall through */ @@ -3717,42 +5958,84 @@ unasign: case 0135:/* LDB */ case 0137:/* DPB */ if ((FLAGS & BYTI) == 0 || !BYF5) { +#if KL + if (Mem_read(0, 0, 0)) +#else if (Mem_read(0, !QITS, 0)) +#endif goto last; AR = MB; + SC = (AR >> 24) & 077; + SCAD = (AR >> 30) & 077; +#if KL + if (QKLB && t20_page && pc_sect != 0 && SCAD > 36) { /* Extended pointer */ + f = SCAD - 37; + if (SCAD == 077) + goto muuo; + SC = _byte_adj[f].s; + SCAD = _byte_adj[f].p; +ld_ptr: + glb_sect = 1; + sect = (AR >> 18) & 07777; + FLAGS |= BYTI; + BYF5 = 1; + goto ld_exe; + } +#endif ldb_ptr: - SC = (AR >> 30) & 077; - MQ = (uint64)(1) << ( 077 & (AR >> 24)); - MQ -= 1; f_load_pc = 0; f_inst_fetch = 0; f_pc_inh = 1; +#if KL_ITS + if (QITS && one_p_arm) { + FLAGS |= ADRFLT; + one_p_arm = 0; + } +#endif FLAGS |= BYTI; BYF5 = 1; +#if KL + ptr_flg = 1; + if (QKLB && t20_page && (SC < 36) && + pc_sect != 0 && (glb_sect || cur_sect != 0) && + (AR & BIT12) != 0) { + /* Full pointer */ + AB = (AB + 1) & RMASK; + } else + glb_sect = 0; +#endif #if ITS if (QITS && pi_cycle == 0 && mem_prot == 0) { opc = PC | (FLAGS << 18); } #endif } else { - AB = AR & RMASK; +#if KL + ptr_flg = 0; +ld_exe: +#else if ((IR & 06) == 6) modify = 1; +#endif + AB = AR & RMASK; + MQ = (uint64)(1) << SC; + MQ -= 1; if (Mem_read(0, 0, 0)) goto last; AR = MB; if ((IR & 06) == 4) { - AR = AR >> SC; + AR = AR >> SCAD; AR &= MQ; set_reg(AC, AR); } else { BR = get_reg(AC); - BR = BR << SC; - MQ = MQ << SC; + BR = BR << SCAD; + MQ = MQ << SCAD; AR &= CM(MQ); AR |= BR & MQ; MB = AR & FMASK; - Mem_write(0, 0); + if (Mem_write(0, 0)) + goto last; } FLAGS &= ~BYTI; BYF5 = 0; @@ -3780,16 +6063,18 @@ ldb_ptr: case 0132:/* FSC */ SC = ((AB & RSIGN) ? 0400 : 0) | (AB & 0377); SCAD = GET_EXPO(AR); +#if KL + SC |= (SC & 0400) ? 0777000 : 0; + SCAD |= (SC & 0400) ? 0777000 : 0; + SC = SCAD + SC; +#else SC = (SCAD + SC) & 0777; +#endif flag1 = 0; if (AR & SMASK) flag1 = 1; -#if !PDP6 - SMEAR_SIGN(AR); - AR <<= 34; - goto fnorm; -#else +#if PDP6 if (((SC & 0400) != 0) ^ ((SC & 0200) != 0)) fxu_hold_set = 1; if ((SC & 0400) != 0 && !pi_cycle) { @@ -3805,6 +6090,10 @@ ldb_ptr: AR &= SMASK|MMASK; AR |= ((uint64)((SC) & 0377)) << 27; break; +#else + SMEAR_SIGN(AR); + AR <<= 34; + goto fnorm; #endif @@ -3860,6 +6149,9 @@ ufa: /* Get exponent */ SC = GET_EXPO(AR); +#if KL + SC |= (SC & 0400) ? 0777000 : 0; /* Extend sign */ +#endif /* Smear the signs */ SMEAR_SIGN(AR); SMEAR_SIGN(BR); @@ -3898,8 +6190,10 @@ fnorm: #if !PDP6 AR &= ~077; /* Save one extra bit */ #endif +#if !KL if (((SC & 0400) != 0) ^ ((SC & 0200) != 0)) fxu_hold_set = 1; +#endif if (IR != 0130) { /* !UFA */ fnormx: while (AR != 0 && ((AR & FPSBIT) != 0) == ((AR & FPNBIT) != 0) && @@ -3913,14 +6207,14 @@ fnormx: } /* Handle edge case of a - and overflow bit */ if ((AR & 000777777777600000000000LL) == (FPSBIT|FPNBIT)) { - SC += 1; + SC ++; AR = (AR & FPHBIT) | (AR >> 1); } if (!nrf && ((IR & 04) != 0)) { f = (AR & FP1BIT) != 0; if ((AR & FPRBIT2) != 0) { #if !PDP6 - /* FADR & FSBR do not rount if negative and equal round */ + /* FADR & FSBR do not round if negative and equal round */ /* FMPR does not round if result negative and equal round */ if (((IR & 070) != 070 && (AR & FPSBIT) != 0 && @@ -3952,6 +6246,13 @@ fnormx: AR = MQ = 0; SC = 0; } +#if KL + if (!pi_cycle && (SC & 0400) != 0) { + FLAGS |= OVR|FLTOVR|TRP1; + if ((SC & RSIGN) != 0) + FLAGS |= FLTUND; + } +#else if (((SC & 0400) != 0) && !pi_cycle) { FLAGS |= OVR|FLTOVR|TRP1; #if !PDP6 @@ -3962,6 +6263,7 @@ fnormx: #endif check_apr_irq(); } +#endif SCAD = SC ^ ((AR & SMASK) ? 0377 : 0); AR &= SMASK|MMASK; AR |= ((uint64)(SCAD & 0377)) << 27; @@ -4008,7 +6310,11 @@ fnormx: SC = (((BR & SMASK) ? 0777 : 0) ^ (BR >> 27)) & 0777; SC += (((AR & SMASK) ? 0777 : 0) ^ (AR >> 27)) & 0777; SC += 0600; +#if KL + SC |= (SC & 0400) ? 0777000 : 0; /* Extend sign */ +#else SC &= 0777; +#endif /* Make positive and compute result sign */ flag1 = 0; flag3 = 0; @@ -4067,7 +6373,6 @@ fnormx: if (BR & SMASK) { BR = CM(BR) + 1; flag1 = 1; - flag3 = 1; } if (AR & SMASK) { if ((AR & MMASK) == 0) { @@ -4077,7 +6382,11 @@ fnormx: AR = CM(AR) + 1; flag1 = !flag1; } +#if KL + SC = (SC + ((0777 ^ SCAD) + 1) + 0201); +#else SC = (SC + ((0777 ^ SCAD) + 1) + 0201) & 0777; +#endif /* Clear exponents */ AR &= MMASK; BR &= MMASK; @@ -4094,6 +6403,32 @@ fnormx: AR = BR / AR; if (AR != 0) { #if !PDP6 +#if KL + if (flag1) { + AR = ((AR ^ FMASK) + 1) & FMASK; + } + AR = (AR >> 1) | (AR & SMASK); + if (IR & 04) { + AR++; + flag3 = AR & 1; + } + AR = (AR >> 1) | (AR & SMASK); + while (AR != 0 && ((AR & SMASK) != 0) == ((AR & BIT8) != 0) && + ((AR & BIT8) != 0) == ((AR & BIT9) != 0)) { + AR <<= 1; + AR |= flag3; + flag3 = 0; + SC--; + } + AR &= FMASK; + if ((SC & 01600) != 1600) + fxu_hold_set = 1; + if (AR == (SMASK|EXPO)) { + AR = (AR >> 1) | (AR & SMASK); + SC ++; + } + AR &= SMASK|MMASK; +#else if ((AR & BIT7) != 0) { AR >>= 1; } else { @@ -4109,6 +6444,7 @@ fnormx: AR <<= 1; SC--; } +#endif #else if (flag1) { AR = ((AR ^ FMASK) + 1) & FMASK; @@ -4152,7 +6488,7 @@ fnormx: } check_apr_irq(); } -#if !PDP6 +#if !PDP6 & !KL if (flag1) { AR = ((AR ^ MMASK) + 1) & MMASK; AR |= SMASK; @@ -4398,7 +6734,7 @@ left: case 0213: /* MOVNS */ flag1 = flag3 = 0; AD = CM(AR) + 1; - if ((((AR & CMASK) ^ CMASK) + 1) & SMASK) { + if ((CCM(AR) + 1) & SMASK) { #if !PDP6 FLAGS |= CRY1; #endif @@ -4505,7 +6841,7 @@ left: break; /* Done */ } -#if !PDP6 +#if !PDP6 if (AR == SMASK && BR == 1) { FLAGS |= OVR|NODIV; /* Overflow and No Divide */ sac_inh=1; /* Don't touch AC */ @@ -4654,8 +6990,8 @@ left: #if !PDP6 SC = 0; if (AR != 0) { -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -4768,9 +7104,15 @@ left: case 0251: /* BLT */ BR = AB; do { - AIO_CHECK_EVENT; /* queue async events */ + AIO_CHECK_EVENT; /* queue async events */ if (sim_interval <= 0) { - sim_process_event(); + if ((reason = sim_process_event()) != SCPE_OK) { + f_pc_inh = 1; + f_load_pc = 0; + f_inst_fetch = 0; + set_reg(AC, AR); + break; + } } /* Allow for interrupt */ if (pi_pending) { @@ -4784,7 +7126,13 @@ left: } } AB = (AR >> 18) & RMASK; +#if KL + BYF5 = 1; +#endif if (Mem_read(0, 0, 0)) { +#if KL + BYF5 = 0; +#endif #if ITS /* On ITS if access error, allow for skip */ if (QITS && (xct_flag & 04) != 0) @@ -4795,15 +7143,21 @@ left: AR = AOB(AR) & FMASK; #endif f_pc_inh = 1; -#if KA & ITS +#if KA | PDP6 +#if ITS if (QITS) set_reg(AC, AR); +#endif #else set_reg(AC, AR); #endif goto last; } AB = (AR & RMASK); +#if KL + BYF5 = 0; + set_reg(AC, AOB(AR)); +#endif if (Mem_write(0, 0)) { #if ITS /* On ITS if access error, allow for skip */ @@ -4815,9 +7169,11 @@ left: AR = AOB(AR) & FMASK; #endif f_pc_inh = 1; -#if KA & ITS +#if KA | PDP6 +#if ITS if (QITS) set_reg(AC, AR); +#endif #else set_reg(AC, AR); #endif @@ -4831,8 +7187,8 @@ left: case 0252: /* AOBJP */ AR = AOB(AR); if ((AR & SMASK) == 0) { -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -4845,8 +7201,8 @@ left: case 0253: /* AOBJN */ AR = AOB(AR); if ((AR & SMASK) != 0) { -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -4857,6 +7213,166 @@ left: break; case 0254: /* JRST */ /* AR Frm PC */ +#if KL +#if KL_ITS + if (uuo_cycle | pi_cycle) { + if (QITS && one_p_arm) { + FLAGS |= ADRFLT; + one_p_arm = 0; + } + } +#endif + switch (AC) { + case 000: /* JRST */ + break; + case 001: /* PORTAL */ + FLAGS &= ~(PUBLIC|PRV_PUB); + break; + case 005: /* XJRSTF */ +xjrstf: + if (Mem_read(0, 0, 0)) + goto last; + BR = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 0, 0)) + goto last; + AR = MB; /* Get PC. */ + if (QKLB && t20_page) { + pc_sect = (AR >> 18) & 07777; + if (AC != 07 && (FLAGS & USER) == 0 && ((BR >> 23) & USER) == 0) + prev_sect = BR & 037; + } + BR = BR >> 23; /* Move flags into position */ + goto jrstf; + + case 006: /* XJEN */ + case 012: /* JEN */ + /* Restore interrupt level. */ + if ((FLAGS & (USER|USERIO)) == USER || + (FLAGS & (USER|PUBLIC)) == PUBLIC) { + goto muuo; + } else { + pi_restore = 1; + } + if (AC == 06) + goto xjrstf; + /* Fall through */ + + case 002: /* JRSTF */ + BR = AR >> 23; /* Move into position */ +jrstf: +#if KL_ITS + if (QITS) + f = FLAGS & (TRP1|TRP2); +#endif + FLAGS &= ~(OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0|TRP1|TRP2|PCHNG|ADRFLT); + /* If executive mode, copy USER and UIO */ + if ((FLAGS & (PUBLIC|USER)) == 0) + FLAGS |= BR & (USER|USERIO|PUBLIC); + /* Can always clear UIO */ + if ((BR & USERIO) == 0) + FLAGS &= ~USERIO; + FLAGS |= BR & (OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0|\ + TRP1|TRP2|PUBLIC|PCHNG|ADRFLT); + FLAGS &= ~PRV_PUB; + if ((FLAGS & USER) == 0) { + FLAGS |= (BR & OVR) ? PRV_PUB : 0; + } +#if KL_ITS + if (QITS) + FLAGS |= f; +#endif + check_apr_irq(); + break; + + case 017: /* Invalid */ +#if KL_ITS + if (QITS) { + BR = AR >> 23; /* Move into position */ + pi_enable = 1; + goto jrstf; + } +#endif + goto muuo; + + case 007: /* XPCW */ + MB = (((uint64)FLAGS) << 23) & FMASK; + /* Save Previous Public context */ + if ((FLAGS & USER) == 0) { + MB &= ~SMASK; + MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + if (QKLB && t20_page) + MB |= (uint64)(prev_sect & 037); + } + if (uuo_cycle | pi_cycle) { + FLAGS &= ~(USER|PUBLIC); /* Clear USER */ + sect = 0; /* Force section zero on IRQ */ + } + if (Mem_write(0, 0)) + goto last; + AB = (AB + 1) & RMASK; + if (QKLB && t20_page) + MB = (((((uint64)pc_sect) << 18) | PC) + !pi_cycle) & (SECTM|RMASK); + else + MB = (PC + !pi_cycle) & (RMASK); + if (Mem_write(0, 0)) + goto last; + AB = (AB + 1) & RMASK; + goto xjrstf; + + case 015: /* XJRST */ + if (Mem_read(0, 0, 0)) + goto last; + AR = MB; /* Get PC. */ + if (QKLB && t20_page) { + pc_sect = (AR >> 18) & 07777; + } + break; + + case 014: /* SFM */ + MB = (((uint64)FLAGS) << 23) & FMASK; + if ((FLAGS & USER) == 0) { + MB &= ~SMASK; + MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + if (QKLB && t20_page) + MB |= (uint64)(prev_sect & 037); + } + (void)Mem_write(0, 0); + goto last; + + case 003: /* Invalid */ + case 011: /* Invalid */ + case 013: /* Invalid */ + case 016: /* Invalid */ + goto muuo; + + case 004: /* HALT */ + if ((FLAGS & (USER|USERIO)) == USER || + (FLAGS & (USER|PUBLIC)) == PUBLIC) { + goto muuo; + } else { + reason = STOP_HALT; + } + break; + case 010: /* JEN */ + /* Restore interrupt level. */ + if ((FLAGS & (USER|USERIO)) == USER || + (FLAGS & (USER|PUBLIC)) == PUBLIC) { + goto muuo; + } else { + pi_restore = 1; + } + break; + } +#if KL_ITS + if (QITS && (FLAGS & USER)) { + jpc = PC; + } +#endif + PC = AR & RMASK; + if (QKLB && t20_page && glb_sect) + pc_sect = (AR >> 18) & 07777; +#else if (uuo_cycle | pi_cycle) { FLAGS &= ~USER; /* Clear USER */ #if ITS @@ -4868,7 +7384,7 @@ left: } /* JEN */ if (AC & 010) { /* Restore interrupt level. */ -#if KI | KL +#if KI if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) { #else @@ -4881,7 +7397,7 @@ left: } /* HALT */ if (AC & 04) { -#if KI | KL +#if KI if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) { #else @@ -4893,7 +7409,7 @@ left: } } #if ITS - if ((FLAGS & USER) && QITS) { + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -4901,7 +7417,7 @@ left: PC_CHANGE /* JRSTF */ if (AC & 02) { - FLAGS &= ~(OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0|TRP1|TRP2|PCHNG); + FLAGS &= ~(OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0|TRP1|TRP2|PCHNG|ADRFLT); AR >>= 23; /* Move into position */ /* If executive mode, copy USER and UIO */ if ((FLAGS & (PUBLIC|USER)) == 0) @@ -4914,7 +7430,7 @@ left: user_io = (FLAGS & USERIO) != 0; #endif FLAGS |= AR & (OVR|NODIV|FLTUND|BYTI|FLTOVR|CRY1|CRY0|\ - TRP1|TRP2|PUBLIC|PCHNG); + TRP1|TRP2|PUBLIC|PCHNG|ADRFLT); #if ITS if (QITS) FLAGS |= AR & (PURE|ONEP); @@ -4928,19 +7444,20 @@ left: } if (AC & 01) { /* Enter User Mode */ -#if KI | KL +#if KI FLAGS &= ~(PUBLIC|PRV_PUB); #else FLAGS |= USER; #endif } +#endif f_pc_inh = 1; break; case 0255: /* JFCL */ if ((FLAGS >> 9) & AC) { -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -4971,20 +7488,93 @@ left: FLAGS |= ONEP; one_p_arm = 0; } +#endif +#if KL_ITS + if (QITS && one_p_arm) { + FLAGS |= ADRFLT; + one_p_arm = 0; + } #endif break; case 0257: /* MAP */ #if KI | KL f = AB >> 9; + flag1 = (FLAGS & USER) != 0; + flag3 = 0; +#if KL + /* Invalid in user unless USERIO set, or not in supervisor mode */ + if ((FLAGS & (USER|USERIO)) == USER || (FLAGS & (USER|PUBLIC)) == PUBLIC) + goto muuo; + + /* Figure out if this is a user space access */ + if (xct_flag & 4) { + flag1 = (FLAGS & USERIO) != 0; + sect = prev_sect; + } + + /* Check if Paging Enabled */ + if (!page_enable) { + AR = AB; /* direct map */ + if (flag1) /* U */ + AR |= SMASK; /* BIT0 */ + AR |= BIT2|BIT3|BIT4|BIT8; + set_reg(AC, AR); + break; + } + + /* Check if access to register */ + if (AB < 020 && ((QKLB && + (glb_sect == 0 || sect == 0 || (glb_sect && sect == 1))) || !QKLB)) { + AR = AB; /* direct map */ + if (flag1) /* U */ + AR |= SMASK; /* BIT0 */ + AR |= BIT2|BIT3|BIT4|BIT8; + set_reg(AC, AR); + break; + } + + /* Handle KI paging odditiy */ + if (!flag1 && !t20_page && (f & 0740) == 0340) { + /* Pages 340-377 via UBT */ + f += 01000 - 0340; + flag3 = 1; + } + + AR = load_tlb(flag1 | flag3, f, 0); + if (page_fault) { + page_fault = 0; + AR |= fault_data; + if (flag1) /* U */ + AR |= SMASK; + set_reg(AC, AR); + break; + } + BR = AR; + /* Remap the flag bits */ + if (BR & KL_PAG_A) { /* A */ + AR = ((AR & 017777LL) << 9) + (AB & 0777); + if (flag1) /* U */ + AR |= SMASK; /* BIT0 */ + AR |= BIT2; /* BIT2 */ + if (BR & KL_PAG_P) /* P */ + AR |= BIT6; /* BIT6 */ + if (BR & KL_PAG_W) /* W */ + AR |= BIT3; /* BIT3 */ + if (BR & KL_PAG_S) /* S */ + AR |= BIT4; /* BIT4 */ + if (BR & KL_PAG_C) /* C */ + AR |= BIT7; /* BIT7 */ + } else + AR = (f & 01740) ? 0 : 0377777LL; + AR |= BIT8; +#else /* Check if Paging Enabled */ if (!page_enable || AB < 020) { AR = 0020000LL + f; /* direct map */ set_reg(AC, AR); break; } - flag1 = (FLAGS & USER) != 0; - /* Figure out if this is a user space access */ if (xct_flag != 0 && !flag1) { if ((xct_flag & 2) != 0) { @@ -4992,7 +7582,6 @@ left: } } - flag3 = 0; /* If user, check if small user enabled */ if (flag1) { if (small_user && (f & 0340) != 0) { @@ -5000,78 +7589,52 @@ left: set_reg(AC, AR); break; } - } else { - /* Handle system mapping */ - /* Pages 340-377 via UBR */ - if ((f & 0740) == 0340) { - f += 01000 - 0340; - flag3 = 2; - /* Pages 400-777 via EBR */ - } else if (f & 0400) { - flag3 = 1; - /* Pages 000-037 direct map */ - } else { - AR = 0020000LL + f; /* direct map */ - set_reg(AC, AR); - break; - } } - /* Map the page */ - if (flag3&1) { - AR = e_tlb[f]; - if (AR == 0) { - AR = M[eb_ptr + (f >> 1)]; - e_tlb[f & 0776] = RMASK & (AR >> 18); - e_tlb[f | 1] = RMASK & AR; - AR = e_tlb[f]; - if (AR == 0) { - AR = 0437777; - set_reg(AC, AR); - break; - } - pag_reload = ((pag_reload + 1) & 037) | 040; - } - last_page = ((f ^ 0777) << 1) | 1; + + /* Get translation */ + AR = load_tlb(flag1, f); + if (AR == 0) { + AR = 0437777LL; } else { - AR = u_tlb[f]; - if (AR == 0) { - AR = M[ub_ptr + (f >> 1)]; - u_tlb[f & 01776] = RMASK & (AR >> 18); - u_tlb[f | 1] = RMASK & AR; - AR = u_tlb[f]; - if (AR == 0) { - AR = 0437777; - set_reg(AC, AR); - break; - } - pag_reload = ((pag_reload + 1) & 037) | 040; - } - if (flag3 & 2) - last_page = (((f-0440) ^ 0777) << 1) | 1; - else - last_page = ((f ^ 0777) << 1); + if ((AR & 0400000LL) == 0) + AR &= 0437777LL; /* Return valid entry for page */ + AR ^= 0400000LL; /* Flip access status. */ } - if ((AR & 0400000LL) == 0) - AR &= 0437777LL; /* Return valid entry for page */ - AR ^= 0400000LL; /* Flip access status. */ +#endif set_reg(AC, AR); #endif break; /* Stack, JUMP */ case 0260: /* PUSHJ */ /* AR Frm PC */ +#if KL + if (QKLB && t20_page && pc_sect != 0) + MB = ((uint64)pc_sect << 18) + (PC + !pi_cycle); + else { +#endif MB = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + !pi_cycle) & RMASK); -#if KI +#if KI | KL if ((FLAGS & USER) == 0) { MB &= ~SMASK; MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + MB &= FMASK; + } +#if KL } #endif - BR = AB; +#endif +#if KL + BYF5 = 1; + f = glb_sect; + if (QKLB && t20_page && pc_sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { + AR = (AR + 1) & FMASK; + sect = (AR >> 18) & 07777; + glb_sect = 1; + } else { + sect = pc_sect; + glb_sect = 0; +#endif AR = AOB(AR); - AB = AR & RMASK; - if (Mem_write(uuo_cycle | pi_cycle, 0)) - goto last; FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2); if (AR & C1) { #if KI | KL @@ -5082,6 +7645,14 @@ left: check_apr_irq(); #endif } +#if KL + } +#endif + AB = AR & RMASK; + if (hst_lnt) + hst[hst_p].mb = MB; + if (Mem_write(uuo_cycle | pi_cycle, 0)) + goto last; #if !PDP6 if (uuo_cycle | pi_cycle) { FLAGS &= ~(USER|PUBLIC); /* Clear USER */ @@ -5093,10 +7664,14 @@ left: #endif } #endif -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } +#endif +#if KL + if (QKLB && t20_page && f) + pc_sect = cur_sect; #endif PC = BR & RMASK; PC_CHANGE @@ -5104,6 +7679,14 @@ left: break; case 0261: /* PUSH */ +#if KL + BYF5 = 1; + if (QKLB && t20_page &&pc_sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { + AR = (AR + 1) & FMASK; + sect = (AR >> 18) & 07777; + } else { + sect = pc_sect; +#endif AR = AOB(AR); AB = AR & RMASK; if (AR & C1) { @@ -5115,19 +7698,57 @@ left: check_apr_irq(); #endif } +#if KL + } +#endif MB = BR; + if (hst_lnt) + hst[hst_p].mb = MB; if (Mem_write(0, 0)) goto last; break; case 0262: /* POP */ +#if KL + BYF5 = 1; /* Tell PXCT that this is stack */ + flag1 = glb_sect; + glb_sect = 0; + sect = pc_sect; + if (QKLB && t20_page) { + if ((xct_flag & 1) != 0) + sect = prev_sect; + if (sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { + sect = (AR >> 18) & 07777; + glb_sect = 1; + } + } +#endif AB = AR & RMASK; if (Mem_read(0, 0, 0)) goto last; - AR = SOB(AR); + if (hst_lnt) + hst[hst_p].mb = MB; AB = BR & RMASK; +#if KL + BYF5 = 0; /* Now back to data */ + if (QKLB && t20_page) { + sect = cur_sect; + glb_sect = flag1; + } +#endif if (Mem_write(0, 0)) goto last; +#if KL + if (QKLB && t20_page) { + if ((xct_flag & 1) != 0) + sect = prev_sect; + if (sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { + AR = (AR - 1) & FMASK; + break; + } + } +#endif + AR = SOB(AR); if ((AR & C1) == 0) { #if KI | KL if (!pi_cycle) @@ -5141,16 +7762,46 @@ left: case 0263: /* POPJ */ AB = AR & RMASK; +#if KL + BYF5 = 1; /* Tell PXCT that this is stack */ + glb_sect = 0; + sect = pc_sect; + if (QKLB && t20_page && (xct_flag & 1) != 0) + sect = prev_sect; + if (QKLB && t20_page && sect != 0 && (AR & SMASK) == 0 && (AR & SECTM) != 0) { + sect = (AR >> 18) & 07777; + glb_sect = 1; + AR = (AR - 1) & FMASK; + } else +#endif + AR = SOB(AR); + if (Mem_read(0, 0, 0)) goto last; -#if ITS - if ((FLAGS & USER) && QITS) { + if (hst_lnt) { +#if KL + hst[hst_p].ea = AB | (sect << 18); +#else + hst[hst_p].ea = AB; +#endif + hst[hst_p].mb = MB; + } +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif + f_pc_inh = 1; PC_CHANGE PC = MB & RMASK; - AR = SOB(AR); +#if KL + BYF5 = 0; /* Tell PXCT that this is stack */ + if (QKLB && t20_page && pc_sect != 0) { + pc_sect = (MB >> 18) & 07777; + if ((AR & SMASK) == 0 && (AR & SECTM) != 0) + break; + } +#endif if ((AR & C1) == 0) { #if KI | KL if (!pi_cycle) @@ -5160,16 +7811,23 @@ left: check_apr_irq(); #endif } - f_pc_inh = 1; break; case 0264: /* JSR */ /* AR Frm PC */ +#if KL + if (QKLB && t20_page && pc_sect != 0) + MB = ((uint64)pc_sect << 18) + (PC + !pi_cycle); + else { +#endif MB = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + !pi_cycle) & RMASK); -#if KI +#if KI | KL if ((FLAGS & USER) == 0) { MB &= ~SMASK; MB |= (FLAGS & PRV_PUB) ? SMASK : 0; } +#if KL + } +#endif #endif #if PDP6 if (ill_op | uuo_cycle | pi_cycle | ex_uuo_sync) { @@ -5183,37 +7841,59 @@ left: if (Mem_write(0, 0)) goto last; FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2); -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif PC_CHANGE +#if KL + if (QKLB && t20_page) { + AR = AR + 1; + if (AR & BIT17) + cur_sect++; + if (glb_sect) + pc_sect = cur_sect; + PC = AR & RMASK; + } else +#endif PC = (AR + 1) & RMASK; f_pc_inh = 1; break; case 0265: /* JSP */ /* AR Frm PC */ +#if KL + if (QKLB && t20_page && pc_sect != 0) + AD = ((uint64)pc_sect << 18) + (PC + !pi_cycle); + else { +#endif AD = (((uint64)(FLAGS) << 23) & LMASK) | ((PC + !pi_cycle) & RMASK); FLAGS &= ~ (BYTI|ADRFLT|TRP1|TRP2); -#if KI +#if KI | KL if ((FLAGS & USER) == 0) { AD &= ~SMASK; AD |= (FLAGS & PRV_PUB) ? SMASK : 0; } +#if KL + } +#endif #endif #if !PDP6 if (uuo_cycle | pi_cycle) { FLAGS &= ~(USER|PUBLIC); /* Clear USER */ } #endif -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif PC_CHANGE +#if KL + if (QKLB && t20_page && glb_sect) + pc_sect = cur_sect; +#endif PC = AR & RMASK; AR = AD; f_pc_inh = 1; @@ -5226,12 +7906,16 @@ left: FLAGS &= ~(USER|PUBLIC); /* Clear USER */ } #endif -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif PC_CHANGE +#if KL + if (QKLB && t20_page && glb_sect) + pc_sect = cur_sect; +#endif PC = AR & RMASK; AR = BR; break; @@ -5242,8 +7926,8 @@ left: if (Mem_read(uuo_cycle | pi_cycle, 0, 0)) goto last; set_reg(AC, MB); -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -5279,7 +7963,7 @@ left: case 0276: /* SUBM */ case 0277: /* SUBB */ flag1 = flag3 = 0; - if ((((AR & CMASK) ^ CMASK) + (BR & CMASK) + 1) & SMASK) { + if ((CCM(AR) + (BR & CMASK) + 1) & SMASK) { FLAGS |= CRY1; flag1 = 1; } @@ -5397,8 +8081,8 @@ jump_op: f |= ((AD == 0) << 1); f = f & IR; if (((IR & 04) != 0) == (f == 0)) { -#if ITS - if ((FLAGS & USER) && QITS) { +#if ITS | KL_ITS + if (QITS && (FLAGS & USER)) { jpc = PC; } #endif @@ -5455,7 +8139,7 @@ skip_op: PC_CHANGE PC = (PC + 1) & RMASK; #if KI | KL - } else if (pi_cycle) { + } else if (trap_flag == 0 && pi_cycle) { pi_ov = pi_hold = 1; #endif } @@ -5483,8 +8167,17 @@ skip_op: AR = AR & CM(BR); /* ANDCA */ break; - case 0414: /* SETM */ case 0415: /* SETMI */ +#if KL + /* XMOVEI for extended addressing */ + if (QKLB && t20_page && pc_sect != 0) { + if (glb_sect == 0 && AR < 020) + AR |= BIT17; + else + AR |= ((uint64)cur_sect) << 18; + } +#endif + case 0414: /* SETM */ case 0416: /* SETMM */ case 0417: /* SETMB */ /* SETM */ @@ -5579,8 +8272,19 @@ skip_op: BR = SWAP_AR; /* Fall Through */ - case 0500: /* HLL */ case 0501: /* HLLI */ +#if KL + /* XHLLI for extended addressing */ + if (QKLB && t20_page && IR == 0501 && pc_sect != 0) { + if (glb_sect == 0 && AR < 020) + AR = BIT17; + else + AR = ((uint64)cur_sect) << 18; + } + /* Fall Through */ +#endif + + case 0500: /* HLL */ case 0502: /* HLLM */ case 0504: /* HRL */ case 0505: /* HRLI */ @@ -5770,7 +8474,7 @@ test_op: case 0764: case 0765: case 0766: case 0767: case 0770: case 0771: case 0772: case 0773: case 0774: case 0775: case 0776: case 0777: -#if KI +#if KI | KL if (!pi_cycle && ((((FLAGS & (USER|USERIO)) == USER) && (IR & 040) == 0) || ((FLAGS & (USER|PUBLIC)) == PUBLIC))) { @@ -5783,10 +8487,41 @@ test_op: goto muuo; } else { int d = ((IR & 077) << 1) | ((AC & 010) != 0); +#if KL + if (d == 3) { + irq_flags |= 020; + goto last; + } +#endif fetch_opr: switch(AC & 07) { case 0: /* 00 BLKI */ case 2: /* 10 BLKO */ +#if KL + /* For KL10 special devices treat like DATAI/DATAO */ + if (d <= 05) { + if (AC & 02) { + if (d == 1 || d == 4) { + if (Mem_read(pi_cycle, 0, 0)) + goto last; + AR = MB; + } + dev_tab[d](040|DATAO|(d<<2), &AR); + } else { + dev_tab[d](040|DATAI|(d<<2), &AR); + MB = AR; + if (Mem_write(pi_cycle, 0)) + goto last; + if (d == 4 || d == 5) { + AB = (AB + 1) & RMASK; + MB = BR; + if (Mem_write(pi_cycle, 0)) + goto last; + } + } + break; + } +#endif if (Mem_read(pi_cycle, 0, 0)) goto last; AR = MB; @@ -5812,6 +8547,14 @@ fetch_opr: MB = AR; if (Mem_write(pi_cycle, 0)) goto last; +#if KL + if (d == 4 || d == 5) { /* DATAI TIM, MTR is two words */ + AB = (AB + 1) & RMASK; + MB = BR; + if (Mem_write(pi_cycle, 0)) + goto last; + } +#endif break; case 3: /* 14 DATAO */ if (Mem_read(pi_cycle, 0, 0)) @@ -5860,8 +8603,8 @@ fetch_opr: set_reg(AC+1, MQ); } - if (hst_lnt) { - hst[hst_p].fmb = AR; + if (hst_lnt && PC >= 020) { + hst[hst_p].fmb = (i_flags & SAC) ? AR: MB; } last: @@ -5874,9 +8617,82 @@ last: goto fetch; } #endif -#if KI | KL +#if KL /* Handle page fault and traps */ if (page_enable && page_fault) { + page_fault = 0; + BYF5 = 0; +#if KL_ITS + if (QITS) { + AB = eb_ptr | 0500; + FM[(6<<4)|0] = fault_data; + } else +#endif + AB = ub_ptr | 0500; + if (!QKLB && !QITS && t20_page) + AB++; + MB = fault_data; + Mem_write_nopage(); + AB++; + /* If fault on trap, kill the pi_cycle flag */ + if (trap_flag) + pi_cycle = 0; + FLAGS |= trap_flag & (TRP1|TRP2); + trap_flag = (TRP1|TRP2); + MB = (((uint64)(FLAGS) << 23) & LMASK); + if ((FLAGS & USER) == 0) { + MB &= ~SMASK; + MB |= (FLAGS & PRV_PUB) ? SMASK : 0; + } + if (QKLB && t20_page) { + if ((FLAGS & USER) == 0) + MB |= (uint64)(prev_sect & 037); + } else + MB |= (PC & RMASK); + Mem_write_nopage(); + AB++; + if (QKLB && t20_page) { + MB = (((uint64)pc_sect) << 18) | (PC & RMASK); + Mem_write_nopage(); + AB++; + } + flag1 = flag3 = 0; + if (FLAGS & PUBLIC) + flag3 = 1; + if (FLAGS & USER) + flag1 = 1; + Mem_read_nopage(); + if (QKLB && t20_page) + FLAGS = 0; + else + FLAGS = (MB >> 23) & 017777; + /* If transistioning from user to executive adjust flags */ + if ((FLAGS & USER) == 0) { + if (flag1) + FLAGS |= USERIO; + if (flag3) + FLAGS |= PRV_PUB; + } + PC = MB & RMASK; + if (QKLB && t20_page) + pc_sect = (MB >> 18) & 07777; + xct_flag = 0; + f_load_pc = 1; + f_pc_inh = 1; + if (pi_cycle) { + pi_cycle = 0; + irq_flags |= 01000; + FM[(7 << 4) | 2] = fault_data; + pi_enable = 0; + } + } +#endif +#if KI + /* Handle page fault and traps */ + if (page_enable && page_fault) { + if (pi_cycle) { + inout_fail = 1; + } page_fault = 0; AB = ub_ptr + ((FLAGS & USER) ? 0427 : 0426); MB = fault_data; @@ -5893,6 +8709,7 @@ last: #if KI | KL if (!f_pc_inh && (trap_flag == 0) && !pi_cycle) { + FLAGS &= ~ADRFLT; #else if (!f_pc_inh && !pi_cycle) { #endif @@ -5910,20 +8727,19 @@ last: /* Dismiss an interrupt */ if (pi_cycle) { #if KI | KL - if (page_enable && page_fault) { - page_fault = 0; - inout_fail = 1; - } + if (trap_flag != 0) { + pi_hold = pi_ov = 0; + f_pc_inh = 0; + trap_flag = 0; + } #endif - if ((IR & 0700) == 0700 && ((AC & 04) == 0)) { pi_hold = pi_ov; if ((!pi_hold) & f_inst_fetch) { pi_cycle = 0; } else { - AB = 040 | (pi_enc << 1) | pi_ov | maoff; + AB = pi_vect | pi_ov; #if KI | KL - AB |= eb_ptr; Mem_read_nopage(); #else Mem_read(1, 0, 1); @@ -5934,11 +8750,10 @@ last: if ((IR & 0700) == 0700) { (void)check_irq_level(); } - AB = 040 | (pi_enc << 1) | pi_ov | maoff; + AB = pi_vect | pi_ov; pi_ov = 0; pi_hold = 0; #if KI | KL - AB |= eb_ptr; Mem_read_nopage(); #else Mem_read(1, 0, 1); @@ -5985,6 +8800,1157 @@ if (QITS) return reason; } +#if KL + +/* Handle indirection for extended byte instructions */ +int +do_byte_setup(int n, int wr, int *pos, int *sz) +{ + uint64 val1; + uint64 val2; + uint64 temp; + int s; + int p; + int np; + int ix; + int ind; + + /* Get pointer */ + val1 = get_reg(n+1); + val2 = get_reg(n+2); + /* Extract index */ + *sz = s = (val1 >> 24) & 077; + p = (val1 >> 30) & 077; + np = (p + (0777 ^ s) + 1) & 0777; + /* Advance pointer */ + if (QKLB && t20_page && pc_sect != 0) { + if (p > 36) { /* Extended pointer */ + int i = p - 37; + *sz = s = _byte_adj[i].s; + p = _byte_adj[i].p; + np = p = (p + (0777 ^ s) + 1) & 0777; + val2 = val1 & (SECTM|RMASK); /* Convert to long pointer */ + val1 = ((uint64)s << 24) | BIT12; + if (p & 0400) { + np = p = ((0777 ^ s) + 044 + 1) & 0777; + val2 = (val2 & ~(SECTM|RMASK)) | ((val2 + 1) & (SECTM|RMASK)); + } + ind = 0; + ix = 0; + MB = val2 & (SECTM|RMASK); + sect = (MB >> 18) & 07777; + glb_sect = 1; + } else if ((val1 & BIT12) != 0) { /* Full pointer */ + if (np & 0400) { + np = p = ((0777 ^ s) + 044 + 1) & 0777; + if (val2 & SMASK) + val2 = (val2 & LMASK) | ((val2 + 1) & RMASK); + else + val2 = (val2 & ~(SECTM|RMASK)) | ((val2 + 1) & (SECTM|RMASK)); + } + if (val2 & SMASK) { + if (val2 & BIT1) { + fault_data = 024LL << 30 | (((FLAGS & USER) != 0)?SMASK:0) | + (val2 & RMASK) | ((uint64)sect << 18); + page_fault = 1; + return 1; + } + ind = TST_IND(val2) != 0; + ix = GET_XR(val2); + MB = (val2 & RMASK) | ((val2 & RSIGN)? LMASK:0); + sect = cur_sect; + glb_sect = 0; + } else { + ind = (val2 & BIT1) != 0; + ix = (val2 >> 30) & 017; + MB = val2 & (SECTM|RMASK); + sect = (MB >> 18) & 07777; + glb_sect = 1; + } + } else { + if (np & 0400) { + np = p = ((0777 ^ s) + 044 + 1) & 0777; + val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); + } + ix = GET_XR(val1); + ind = TST_IND(val1) != 0; + MB = (val1 & RMASK) | ((val1 & RSIGN)? LMASK:0); + sect = cur_sect; + glb_sect = 0; + } + } else { + if (np & 0400) { + np = p = ((0777 ^ s) + 044 + 1) & 0777; + val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); + } + ix = GET_XR(val1); + ind = TST_IND(val1) != 0; + MB = (val1 & RMASK) | ((val1 & RSIGN)? LMASK:0); + sect = cur_sect; + glb_sect = 0; + } + *pos = np & 077; + + AB = MB & RMASK; + if (ix) { + temp = get_reg(ix); + /* Check if extended indexing */ + if (QKLB && t20_page && glb_sect != 0 && (temp & SMASK) == 0 && (temp & SECTM) != 0) { + temp = (temp + MB) & (SECTM|RMASK); + sect = (temp >> 18) & 07777; + MB = 0; + glb_sect = 1; + } else + glb_sect = 0; + temp = MB = (MB + temp) & FMASK; + AB = MB & RMASK; + } + while (ind & !check_irq_level()) { + if (Mem_read(0, 1, 0)) { + return 1; + } + /* Check if extended indexing */ + if (QKLB && sect != 0) { + if (MB & SMASK) { /* Instruction format IFIW */ + if (MB & BIT1) { /* Illegal index word */ + fault_data = 024LL << 30 | (((FLAGS & USER) != 0)?SMASK:0) | + (temp & RMASK) | ((uint64)sect << 18); + page_fault = 1; + return 1; + } + glb_sect = 0; + ix = GET_XR(MB); + ind = TST_IND(MB) != 0; + AB = MB & RMASK; + if (ix) { + temp = get_reg(ix); + /* Check if extended indexing */ + if ((temp & SMASK) != 0 || (temp & SECTM) == 0) { /* Local index word */ + temp = (temp + AB) & RMASK; + } else { + temp = (temp + AB) & FMASK; + glb_sect = 1; + sect = cur_sect = (temp >> 18) & 07777; + } + MB = temp; + } else + temp = MB; + AB = temp & RMASK; + } else { /* Extended index EFIW */ + ind = (MB & BIT1) != 0; + ix = (MB >> 30) & 017; + AB = MB & (SECTM|RMASK); + if (ix) { + temp = get_reg(ix); + if ((temp & SMASK) != 0 || (temp & SECTM) == 0) { /* Local index word */ + temp = AB + (((temp & RSIGN) ? 0: 0)|(temp & RMASK)); + } else + temp = temp + AB; + temp &= FMASK; + MB = temp; + } else + temp = MB; + sect = cur_sect = (temp >> 18) & 07777; + AB = temp & RMASK; + glb_sect = 1; + } + } else { + ix = GET_XR(MB); + ind = TST_IND(MB) != 0; + AB = MB & RMASK; + if (ix) { + temp = get_reg(ix); + /* Check if extended indexing */ + if (QKLB && sect != 0 && (temp & SMASK) == 0 && (temp & SECTM) != 0) { + temp = (temp + ((AB & RSIGN) ? + SECTM|((uint64)AB): (uint64)AB)) & (SECTM|RMASK); + sect = (temp >> 18) & 07777; + MB = 0; + glb_sect = 1; + AB = 0; + } else + glb_sect = 0; + temp = MB = (MB + temp) & FMASK; + AB = MB & RMASK; + } + } +#if 0 + /* Handle events during a indirect loop */ + if (sim_interval-- <= 0) { + if (sim_process_event() != SCPE_OK) { + return -1; + } + } +#endif + }; + /* Update pointer */ + val1 &= PMASK; + val1 |= (uint64)(np) << 30; + + /* Save pointer */ + set_reg(n+1, val1); + set_reg(n+2, val2); + + modify = wr; + /* Read final value */ + if (Mem_read(0, 0, 0)) { + modify = ptr_flg = BYF5 = 0; + return 1; + } + modify = 0; + return 0; +} + +/* Get data from pointer */ +int +load_byte(int n, uint64 *data, uint64 fill, int cnt) +{ + uint64 val1, msk; + int s, p; + + /* Check if should return fill */ + val1 = get_reg(n); + if (cnt && (val1 & MANT) == 0) { + *data = fill; + return 1; + } + + /* Fetch Pointer word */ + ptr_flg = 1; + if (do_byte_setup(n, 0, &p, &s)) + goto back; + + ptr_flg = 0; + /* Generate mask for given size */ + msk = (uint64)(1) << s; + msk--; + *data = (MB >> p) & msk; + if (cnt) { + /* Decrement count */ + val1 = get_reg(n); + val1--; + set_reg(n, val1); + } + + return 1; + +back: + ptr_flg = 0; + val1 = get_reg(n+1); + val1 &= PMASK; + val1 |= (uint64)(p + s) << 30; + set_reg(n+1, val1); + return 0; +} + +/* Store data into pointer */ +int +store_byte(int n, uint64 data, int cnt) +{ + uint64 val1, msk; + int s, p; + + /* Fetch Pointer word */ + BYF5 = 1; + if (do_byte_setup(n, 1, &p, &s)) + goto back; + + /* Generate mask for given size */ + msk = (uint64)(1) << s; + msk--; + msk <<= p; + MB &= CM(msk); + MB |= msk & ((uint64)(data) << p); + if (Mem_write(0, 0)) + goto back; + + BYF5 = 0; + if (cnt) { + /* Decrement count */ + val1 = get_reg(n); + val1--; + set_reg(n, val1); + } + + return 1; + +back: + BYF5 = 0; + val1 = get_reg(n+1); + val1 &= PMASK; + val1 |= (uint64)(p + s) << 30; + set_reg(n+1, val1); + return 0; +} + +void +get_mask(int n, uint64 *msk) +{ + uint64 val; + int s; + /* Get pointer */ + val = get_reg(n+1); + /* Extract index */ + s = (val >> 24) & 077; + + /* Generate mask for given size */ + *msk = ((uint64)(1) << s) - 1; +} + +/* Adjust a pointer to be valid */ +void +adj_byte(int n) +{ + uint64 val1, val2; + int s, p, np; + + /* Get pointer */ + val1 = get_reg(n+1); + val2 = get_reg(n+2); + /* Extract index */ + s = (val1 >> 24) & 077; + p = (val1 >> 30) & 077; + /* Advance pointer */ + np = (p + (0777 ^ s) + 1) & 0777; + if (QKLB && t20_page && pc_sect != 0) { + if (p > 36) { /* Extended pointer */ + int i = p - 37; + s = _byte_adj[i].s; + p = _byte_adj[i].p; + val2 = val1 & (SECTM|RMASK); /* Convert to long pointer */ + val1 = ((uint64)s << 24) | BIT12; + /* Save pointer */ + set_reg(n+1, val1); + set_reg(n+2, val2); + return; + } else if ((val1 & BIT12) != 0) { /* Full pointer */ + if (np & 0400) + val2 = (val2 & ~(SECTM|RMASK)) | ((val2 + 1) & (SECTM|RMASK)); + } else { + if (np & 0400) + val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); + } + } else { + if (np & 0400) + val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); + } + if ((np & 0400) == 0) + return; + /* Update pointer */ + val1 &= PMASK; + val1 |= (uint64)(044) << 30; + + /* Save pointer */ + set_reg(n+1, val1); + set_reg(n+2, val2); +} + + +/* Advance a pointer by 1 */ +void +adv_byte(int n) +{ + uint64 val1, val2; + int s, p, np; + + /* Check if should return fill */ + val1 = get_reg(n); + if ((val1 & MANT) == 0) + return; + /* Decrement count */ + val1--; + set_reg(n, val1); + + /* Get pointer */ + val1 = get_reg(n+1); + val2 = get_reg(n+2); + /* Extract index */ + s = (val1 >> 24) & 077; + p = (val1 >> 30) & 077; + /* Advance pointer */ + np = (p + (0777 ^ s) + 1) & 0777; + if (QKLB && t20_page && pc_sect != 0) { + if (p > 36) { /* Extended pointer */ + int i = p - 37; + s = _byte_adj[i].s; + p = _byte_adj[i].p; + np = (p + (0777 ^ s) + 1) & 0777; + val2 = val1 & (SECTM|RMASK); /* Convert to long pointer */ + val1 = ((uint64)s << 24) | BIT12; + if (np & 0400) { + np = ((0777 ^ s) + 044 + 1) & 0777; + val2 = (val2 & ~(SECTM|RMASK)) | ((val2 + 1) & (SECTM|RMASK)); + } + } else if ((val1 & BIT12) != 0) { /* Full pointer */ + if (np & 0400) { + np = ((0777 ^ s) + 044 + 1) & 0777; + val2 = (val2 & ~(SECTM|RMASK)) | ((val2 + 1) & (SECTM|RMASK)); + } + } else { + if (np & 0400) { + np = ((0777 ^ s) + 044 + 1) & 0777; + val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); + } + } + } else { + if (np & 0400) { + np = ((0777 ^ s) + 044 + 1) & 0777; + val1 = (val1 & LMASK) | ((val1 + 1) & RMASK); + } + } + np &= 077; + /* Update pointer */ + val1 &= PMASK; + val1 |= (uint64)(np) << 30; + + /* Save pointer */ + set_reg(n+1, val1); + set_reg(n+2, val2); +} + +/* back a pointer by 1 */ +void +bak_byte(int n, int cnt) +{ + uint64 val; + int s, p; + + /* Increment count */ + if (cnt) { + val = get_reg(n); + val++; + set_reg(n, val); + } + + /* Get pointer */ + val = get_reg(n+1); + /* Extract index */ + s = (val >> 24) & 077; + p = (((val >> 30) & 077) + (s)) & 0777; + /* Advance pointer */ + /* Update pointer */ + val &= PMASK; + val |= (uint64)(p) << 30; + MB = val; + + /* Save pointer */ + set_reg(n+1, val); +} + +/* Preform a table lookup operation */ +int +do_xlate(uint32 tbl, uint64 val, int mask) +{ + uint64 reg; + int f; + + AB = (tbl + (val >> 1)) & RMASK; + if (Mem_read(0, 0, 0)) { + /* Backup ext_ac */ + return -2; + } + if ((val & 1) == 0) + MB >>= 18; + val = MB & mask; + reg = get_reg(ext_ac); + f = 1; + switch ((MB >> 15) & 07) { + case 0: + if ((reg & SMASK) == 0) /* If S */ + f = 0; + break; + case 1: f = -1; /* Terminate */ + break; + case 2: + if ((reg & SMASK) == 0) /* If S, clear M */ + f = 0; + reg &= ~BIT2; + break; + case 3: + if ((reg & SMASK) == 0) /* If S, set M */ + f = 0; + reg |= BIT2; + break; + case 4: + reg |= SMASK|BIT1; /* Set S & N */ + break; + case 5: + f = -1; /* Terminate, set N */ + reg |= BIT1; + break; + case 6: + reg |= SMASK|BIT1; /* Set S, N, Clear M */ + reg &= ~BIT2; + break; + case 7: + reg |= SMASK|BIT1|BIT2; /* Set S, N, M */ + break; + } + set_reg(ext_ac, reg); + return f; +} + +/* Table of powers of 10 for CVTBD opcodes */ +uint64 pow10_tab[22][2] = { + /* 0: */ 0000000000000LL, 0000000000001LL, + /* 1: */ 0000000000000LL, 0000000000012LL, + /* 2: */ 0000000000000LL, 0000000000144LL, + /* 3: */ 0000000000000LL, 0000000001750LL, + /* 4: */ 0000000000000LL, 0000000023420LL, + /* 5: */ 0000000000000LL, 0000000303240LL, + /* 6: */ 0000000000000LL, 0000003641100LL, + /* 7: */ 0000000000000LL, 0000046113200LL, + /* 8: */ 0000000000000LL, 0000575360400LL, + /* 9: */ 0000000000000LL, 0007346545000LL, + /* 10: */ 0000000000000LL, 0112402762000LL, + /* 11: */ 0000000000002LL, 0351035564000LL, + /* 12: */ 0000000000035LL, 0032451210000LL, + /* 13: */ 0000000000443LL, 0011634520000LL, + /* 14: */ 0000000005536LL, 0142036440000LL, + /* 15: */ 0000000070657LL, 0324461500000LL, + /* 16: */ 0000001070336LL, 0115760200000LL, + /* 17: */ 0000013064257LL, 0013542400000LL, + /* 18: */ 0000157013326LL, 0164731000000LL, + /* 19: */ 0002126162140LL, 0221172000000LL, + /* 20: */ 0025536165705LL, 0254304000000LL, + /* 21: */ 0330656232670LL, 0273650000000LL +}; + +/* + * Process extended instruction. + * + * On entry BR = address of instruction. + * AB = value of E0. + * IR = opcode. + */ +int +do_extend(uint32 ia) +{ + uint64 fill1, fill2; + uint64 val1, val2; + uint64 msk; + uint64 reg; + int xlat_sect; + int f, i; + + + switch(IR) { + case 001: /* CMPSL */ + case 002: /* CMPSE */ + case 003: /* CMPSLE */ + case 005: /* CMPSGE */ + case 006: /* CMPSN */ + case 007: /* CMPSG */ + if (((get_reg(ext_ac) | get_reg(ext_ac+3)) & EMASK) != 0) + return 1; + /* Fetch filler values */ + AB = (ia + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill1 = MB; + AB = (AB + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill2 = MB; + + /* Compare the strings */ + f = 2; + while (((get_reg(ext_ac) | get_reg(ext_ac+3)) & MANT) != 0) { + if (!load_byte(ext_ac, &val1, fill1, 1)) { + return 0; + } + if (!load_byte(ext_ac+3, &val2, fill2, 1)) { + /* Backup ext_ac */ + bak_byte(ext_ac, 1); + return 0; + } + if (val1 != val2) { + f = (val1 < val2) ? 1: 0; + break; + } + } + /* Check if we should skip */ + switch (IR & 7) { + case 1: f = (f == 1); break; + case 2: f = (f == 2); break; + case 3: f = (f != 0); break; + case 5: f = (f != 1); break; + case 6: f = (f != 2); break; + case 7: f = (f == 0); break; + default: f = 0; break; + } + /* Skip if conditions match */ + if (f) + PC = (PC + 1) & RMASK; + return 0; + + case 004: /* EDIT */ + val2 = MB; /* Save address of translate table */ + if (QKLB && pc_sect != 0 && glb_sect) + xlat_sect = (val2 >> 18) & 07777; + else + xlat_sect = cur_sect; + /* Fetch filler values */ + AB = (ia + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill1 = MB; + /* Get floating character */ + AB = (AB + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill2 = MB; + f = 1; + while (f) { + int a; + + /* Read in pattern control */ + reg = get_reg(ext_ac); + AB = reg & RMASK; + if (QKLB && pc_sect != 0) { + sect = (reg >> 18) & 07777; + glb_sect = 1; + } else { + sect = cur_sect; + glb_sect = 0; + } + if (Mem_read(0, 0, 0)) + return 0; + i = (reg >> 30) & 03; + reg &= ~(3LL << 30); /* Clear byte number */ + val1 = (MB >> ((3 - i) * 9)) & 0777; + i++; + if (i > 3) { + if (QKLB && pc_sect != 0) + reg = (reg & ~(SECTM|RMASK)) | ((reg + 1) & (SECTM|RMASK)); + else + reg = (reg & LMASK) | ((reg+1) & RMASK); + i = 0; + } + reg |= ((uint64)i) << 30; + i = 0; + a = 0; + switch ((val1 >> 6) & 07) { + case 0: /* Individual options */ + switch (val1 & 077) { + case 0: /* Stop */ + f = 0; + break; + case 1: /* SELECT */ + if (!load_byte(ext_ac, &val1, 0, 0)) + return 0; + a = 1; + AB = (val2 + (val1 >> 1)) & RMASK; + sect = xlat_sect; + if (Mem_read(0, 0, 0)) + return 0; + if ((val1 & 1) == 0) + MB >>= 18; + val1 = MB & 07777; + switch ((MB >> 15) & 07) { + case 0: + func0: + if ((reg & SMASK) != 0) { /* If S */ + i = 1; + } else if (fill1 != 0) { + val1 = fill1; + i = 1; + } + break; + case 1: + set_reg(ext_ac, reg); + return 0; /* Next */ + case 2: + reg &= ~BIT2; /* If S, clear M */ + goto func0; + case 3: + reg |= BIT2; /* If S, set M */ + goto func0; + case 4: + func4: + if ((reg & SMASK) == 0) { + adj_byte(ext_ac+3); + reg |= SMASK; + AR = get_reg(ext_ac+3); + if (QKLB && pc_sect != 0) { + sect = (AR >> 18) & 07777; + glb_sect = 1; + } else { + sect = cur_sect; + glb_sect = 0; + } + AB = AR & RMASK; + MB = get_reg(ext_ac+4); + if (Mem_write(0, 0)) + return 0; + if (QKLB && pc_sect != 0 && (MB & BIT12) != 0) { + AB = (++AR) & RMASK; + sect = (AR >> 18) & 07777; + MB = get_reg(ext_ac+5); + if (Mem_write(0,0)) + return 0; + } + if (fill2 != 0) { + if (!store_byte(ext_ac+3, fill1, 0)) { + return 0; + } + } + } + i = 1; + reg |= SMASK|BIT1; /* Set S & N */ + break; + case 5: + reg |= BIT1; + break; + case 6: + reg &= ~BIT2; /* Clear M */ + goto func4; + case 7: + reg |= BIT2; /* Set M */ + goto func4; + } + break; + case 2: /* Set signifigance */ + if ((reg & SMASK) == 0) { + AR = get_reg(ext_ac+3); + if (QKLB && pc_sect != 0) { + sect = (AR >> 18) & 07777; + glb_sect = 1; + } else { + sect = cur_sect; + glb_sect = 0; + } + AB = AR & RMASK; + MB = get_reg(ext_ac+4); + if (Mem_write(0, 0)) + return 0; + if (QKLB && pc_sect != 0 && (MB & BIT12) != 0) { + AB = (++AR) & RMASK; + sect = (AR >> 18) & 07777; + MB = get_reg(ext_ac+5); + if (Mem_write(0,0)) + return 0; + } + if (fill2 != 0) { + val1 = fill2; + i = 1; + } + } + reg |= SMASK; + break; + case 3: /* Field separater */ + reg &= ~(SMASK|BIT1|BIT2); /* Clear S & N */ + break; + case 4: /* Exchange Mark */ + AR = get_reg(ext_ac+3); + if (QKLB && pc_sect != 0) { + sect = (AR >> 18) & 07777; + glb_sect = 1; + } else { + sect = cur_sect; + glb_sect = 0; + } + AB = AR & RMASK; + if (Mem_read(0, 0, 0)) + return 0; + BR = MB; + MB = get_reg(ext_ac+4); + /* Make sure byte pointers are same size */ + if (QKLB && (MB & BIT12) != (BR & BIT12)) + return 0; + if (Mem_write(0, 0)) + return 0; + if (QKLB && pc_sect != 0 && (BR & BIT12) != 0) { + AB = (AR + 1) & RMASK; + sect = ((AR + 1)>> 18) & 07777; + if (Mem_read(0, 0, 0)) { + AB = AR & RMASK; /* Restore lower pointer */ + sect = (AR >> 18) & 07777; + MB = BR; + (void)Mem_write(0, 0); + return 0; + } + AD = MB; + MB = get_reg(ext_ac+5); + if (Mem_write(0, 0)) { + AB = AR & RMASK; /* Restore lower pointer */ + sect = (AR >> 18) & 07777; + MB = BR; + (void)Mem_write(0, 0); + return 0; + } + set_reg(ext_ac+5, AD); + } + set_reg(ext_ac+4, BR); + break; + case 5: + i = 0; + break; + } + break; + case 1: /* Insert Message char */ + if ((reg & SMASK) != 0) { + AB = (ia + (val1 & 077) + 1) & RMASK; + sect = cur_sect; + if (Mem_read(0, 0, 0)) + return 0; + i = 1; + val1 = MB; + } else if (fill1 != 0) { + i = 1; + val1 = fill1; + } + break; + case 5: /* Skip on M */ + if ((reg & BIT2) != 0) + goto skipa; + break; + case 6: /* Skip on N */ + if ((reg & BIT1) == 0) + break; + case 7: /* Skip allways */ + skipa: + /* Compute new byte number */ + val1 = (val1 & 077) + 1; + val2 = ((reg >> 30) & 03) + val1; + reg &= ~(3LL << 30); /* Clear byte number */ + reg += (val2 >> 2); + reg |= (val2 & 3) << 30; + i = 0; + default: + break; + } + if (i) { + if (!store_byte(ext_ac+3, val1, 0)) { + if (a) + bak_byte(ext_ac, 0); + return 0; + } + } + set_reg(ext_ac, reg); + } + PC = (PC + 1) & RMASK; + break; + + case 010: /* CVTDBO */ + case 011: /* CVTDBT */ + if (QKLB && pc_sect != 0 && glb_sect) + xlat_sect = (AR >> 18) & 07777; + else + xlat_sect = cur_sect; + val2 = ((AR & RSIGN) ? LMASK : 0) | (AR & RMASK); + /* Check if conversion started */ + if ((get_reg(ext_ac) & SMASK) == 0) { + set_reg(ext_ac+3, 0); + set_reg(ext_ac+4, 0); + } + AR = get_reg(ext_ac + 3); + ARX = get_reg(ext_ac + 4); + if (IR == 010) { + fill2 = get_reg(ext_ac); + fill2 |= SMASK; + set_reg(ext_ac, fill2); + } + while ((get_reg(ext_ac) & MANT) != 0) { + if (!load_byte(ext_ac, &val1, 0, 1)) { + set_reg(ext_ac+3, AR); + set_reg(ext_ac+4, ARX); + return 0; + } + if (IR == 010) { + val1 = (val1 + val2) & FMASK; + } else { + sect = xlat_sect; + f = do_xlate((uint32)(val2 & RMASK), val1, 017); + if (f < 0) + break; + if (f) + val1 = MB & 017; + } + if ((val1 & RSIGN) != 0 || val1 > 9) { + ARX = (ARX & CMASK) | (AR & SMASK); + set_reg(ext_ac+3, AR); + set_reg(ext_ac+4, ARX); + return 0; + } + /* Multiply by 2 */ + AR <<= 1; + ARX <<= 1; + if (ARX & SMASK) + AR |= 1; + ARX &= CMASK; + /* Compute times 4 */ + BR = (AR << 2) | ((ARX >> 33) & 03); + BRX = (ARX << 2) & CMASK; + ARX = (ARX & CMASK) + (BRX & CMASK) + val1; + f = (ARX >> 35); + AR = AR + BR + f; + ARX &= CMASK; + AR &= FMASK; + } + ARX &= CMASK; + if ((get_reg(ext_ac) & MANT) == 0) { + PC = (PC + 1) & RMASK; + if (get_reg(ext_ac) & BIT2) { + ARX = CCM(ARX) + 1; + AR = CM(AR) + ((ARX & SMASK) != 0); + } + } + ARX = (ARX & CMASK) | (AR & SMASK); + AR &= FMASK; + set_reg(ext_ac+3, AR); + set_reg(ext_ac+4, ARX); + break; + case 012: /* CVTBDO */ + case 013: /* CVTBDT */ + /* Save E1 */ + if (IR == 012) + val2 = ((AR & RSIGN) ? LMASK : 0) | (AR & RMASK); + else { + val2 = AB; + if (QKLB && pc_sect != 0 && glb_sect) + xlat_sect = (AR >> 18) & 07777; + else + xlat_sect = cur_sect; + } + /* Get fill */ + AB = (ia + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill1 = MB; + AR = get_reg(ext_ac); + ARX = get_reg(ext_ac + 1); + reg = get_reg(ext_ac + 3); + /* Set M bit if minus */ + if ((AR & SMASK) != 0 && (reg & BIT2) == 0) { + reg |= BIT2; + ARX = CCM(ARX) + 1; + AR = CM(AR) + ((ARX & SMASK) != 0); + } + ARX &= CMASK; + /* Set N bit if non-zero number */ + if ((AR | ARX) != 0) + reg |= BIT1; + set_reg(ext_ac+3, reg); + /* Compute number of digits needed for value */ + for (f = 0; f < 22; f++) { + BRX = ARX + CCM(pow10_tab[f][1]) + 1; + BR = AR + CM(pow10_tab[f][0]) + ((BRX & SMASK) != 0); + if ((BR & C1) == 0) + break; + } + if (f == 0) + f = 1; + /* Check if room to save it */ + if (f > (reg & MANT)) + return 0; + /* Fill out left justify */ + /* If L, fill leading zeros with fill char */ + while ((reg & SMASK) != 0 && (reg & MANT) > f) { + if (!store_byte(ext_ac + 3, fill1, 1)) + return 0; + reg = get_reg(ext_ac + 3); + } + /* Insert correct digit */ + for (f--; f >= 0; f--) { + /* Subtract closest power of 10 */ + for (i = 0; i < 10; i++) { + BRX = ARX + CCM(pow10_tab[f][1]) + 1; + BR = AR + CM(pow10_tab[f][0]) + ((BRX & SMASK) != 0); + if ((BR & C1) == 0) + break; + ARX = BRX & CMASK; + AR = BR & FMASK; + } + val1 = (uint64)i; + if (IR == 013) { + /* Read first translation entry */ + AB = (val1 + val2) & RMASK; + sect = xlat_sect; + if (Mem_read(0, 0, 0)) { + set_reg(ext_ac + 3, (reg & (SMASK|EXPO)) | (f+1)); + return 0; + } + val1 = MB; + if (f == 0 && (get_reg(ext_ac + 3) & BIT2) != 0) + val1 >>= 12; + val1 &= 07777; + } else + val1 += val2; + if (!store_byte(ext_ac + 3, val1, 1)) { + set_reg(ext_ac + 3, (reg & (SMASK|EXPO)) | (f+1)); + return 0; + } + set_reg(ext_ac, AR); + set_reg(ext_ac+1, ARX); + } + reg = get_reg(ext_ac+3); + reg &= SMASK|EXPO; + set_reg(ext_ac+3, reg); + set_reg(ext_ac, 0); + set_reg(ext_ac+1, 0); + PC = (PC + 1) & RMASK; + break; + case 014: /* MOVSO */ + case 015: /* MOVST */ + case 016: /* MOVSLJ */ + get_mask(ext_ac+3, &msk); + if ((((get_reg(ext_ac) & (077LL << 26))| get_reg(ext_ac+3)) & EMASK) != 0) + return 1; + if (IR == 014) { + val2 = ((AR & RSIGN) ? LMASK : 0) | (AR & RMASK); + } else if (IR == 015) { + AB = ia; + if (QKLB) { + if (pc_sect != 0 && glb_sect) + xlat_sect = (AR >> 18) & 07777; + else + xlat_sect = cur_sect; + } else + xlat_sect = 0; + if (Mem_read(0, 1, 0)) + return 0; + val2 = MB; + } else { + val2 = AB; + } + /* Fetch filler values */ + AB = (ia + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill1 = MB; + while ((get_reg(ext_ac) & MANT) != 0) { + if ((get_reg(ext_ac+3) & MANT) == 0) + return 0; + if (!load_byte(ext_ac, &val1, fill1, 1)) + return 0; + if (IR == 014) { + val1 = (val1 + val2) & FMASK; + /* Check if in range */ + if ((val1 & ~msk) != 0) + return 0; + } else if (IR == 015) { + sect = xlat_sect; + f = do_xlate((uint32)(val2), val1, 07777); + if (f < 0) + return 0; + if (f) + val1 = MB & 07777; + } + if (!store_byte(ext_ac+3, val1, 1)) { + bak_byte(ext_ac, 1); + return 0; + } + } + while ((get_reg(ext_ac+3) & MANT) != 0) { + if (!store_byte(ext_ac+3, fill1, 1)) + return 0; + } + PC = (PC + 1) & RMASK; + break; + + case 017: /* MOVSRJ */ + /* Fetch filler values */ + if (((get_reg(ext_ac) | get_reg(ext_ac+3)) & EMASK) != 0) + return 1; + AB = (ia + 1) & RMASK; + if (Mem_read(0, 1, 0)) + return 0; + fill1 = MB; + /* While source is larger, skip source */ + val2 = get_reg(ext_ac+3); + while (val2 != 0 && get_reg(ext_ac) > val2) + adv_byte(ext_ac); + + /* While destination is larger, fill destination */ + while (val2 != 0 && get_reg(ext_ac) < val2) { + if (!store_byte(ext_ac+3, fill1, 1)) { + return 0; + } + val2 = get_reg(ext_ac+3); + } + /* Copy rest of string */ + while (get_reg(ext_ac+3)) { + if (!load_byte(ext_ac, &val1, fill1, 1)) + return 0; + if (!store_byte(ext_ac+3, val1, 1)) { + /* Backup ext_ac */ + bak_byte(ext_ac, 1); + return 0; + } + } + PC = (PC + 1) & RMASK; + break; + + case 020: /* XBLT */ + if (QKLB) { + glb_sect = 1; + reg = get_reg(ext_ac); + val1 = get_reg(ext_ac + 1); + val2 = get_reg(ext_ac + 2); + while (reg != 0) { + if (reg & SMASK) { + val1 = (val1 - 1) & (SECTM|RMASK); + sect = (val1 >> 18) & 00037; + AB = val1 & RMASK; + ptr_flg = 1; + if (Mem_read(0, 0, 0)) { + val1 = (val1 + 1) & (SECTM|RMASK); + goto xblt_done; + } + val2 = (val2 - 1) & (SECTM|RMASK); + sect = (val2 >> 18) & 00037; + AB = val2 & RMASK; + ptr_flg = 0; + BYF5 = 1; + if (Mem_write(0, 0)) { + val1 = (val1 + 1) & (SECTM|RMASK); + val2 = (val2 + 1) & (SECTM|RMASK); + goto xblt_done; + } + BYF5 = 0; + reg = (reg + 1) & FMASK; + } else { + sect = (val1 >> 18) & 00037; + AB = val1 & RMASK; + ptr_flg = 1; + if (Mem_read(0, 0, 0)) + goto xblt_done; + sect = (val2 >> 18) & 00037; + AB = val2 & RMASK; + ptr_flg = 0; + BYF5 = 1; + if (Mem_write(0, 0)) + goto xblt_done; + val1 = (val1 + 1) & (SECTM|RMASK); + val2 = (val2 + 1) & (SECTM|RMASK); + reg = (reg - 1) & FMASK; + BYF5 = 0; + } + } +xblt_done: + ptr_flg = BYF5 = 0; + set_reg(ext_ac, reg); + set_reg(ext_ac + 1, val1); + set_reg(ext_ac + 2, val2); + return 0; + } + case 021: /* GSNGL */ + case 022: /* GDBLE */ + case 023: /* GDFIX */ + case 024: /* GFIX */ + case 025: /* GDFIXR */ + case 026: /* GFIXR */ + case 027: /* DGFLTR */ + case 030: /* GFLTR */ + case 031: /* GFSC */ + default: + return 1; + } + return 0; +} +#endif + t_stat rtc_srv(UNIT * uptr) { @@ -5992,11 +9958,17 @@ rtc_srv(UNIT * uptr) t = sim_rtcn_calb (rtc_tps, TMR_RTC); sim_activate_after(uptr, 1000000/rtc_tps); tmxr_poll = t/2; +#if PDP6 | KA | KI clk_flg = 1; if (clk_en) { sim_debug(DEBUG_CONO, &cpu_dev, "CONO timmer\n"); set_interrupt(4, clk_irq); } +#endif +#if KL + update_times(rtc_tim); + rtc_tim = (1000000/rtc_tps); +#endif return SCPE_OK; } @@ -6012,10 +9984,29 @@ qua_srv(UNIT * uptr) } #endif +#if KL +t_stat +tim_srv(UNIT * uptr) +{ + double us; + + /* See if we are counting to overflow or period */ + if (tim_val & 0100000) { + tim_val = 020000 | tim_per; + us = (double)((010000 - tim_per) * 10); + } else { + tim_val = 0130000; + us = (double)(tim_per * 10); + } + set_interrupt(4 << 2, mtr_irq); + (void)sim_activate_after_d(uptr, us); + return SCPE_OK; +} +#endif /* * This sequence of instructions is a mix that hopefully - * represents a resonable instruction set that is a close + * represents a resonable instruction set that is a close * estimate to the normal calibrated result. */ @@ -6031,6 +10022,7 @@ static const char *pdp10_clock_precalibrate_commands[] = { t_stat cpu_reset (DEVICE *dptr) { int i; +sim_debug(DEBUG_CONO, dptr, "CPU reset\n"); BYF5 = uuo_cycle = 0; #if KA | PDP6 Pl = Ph = 01777; @@ -6051,7 +10043,11 @@ pi_restore = pi_hold = 0; #if KI | KL ub_ptr = eb_ptr = 0; pag_reload = ac_stack = 0; +#if KI fm_sel = small_user = user_addr_cmp = page_enable = 0; +#else +fm_sel = prev_ctx = user_addr_cmp = page_enable = 0; +#endif #endif #if BBN exec_map = 0; @@ -6063,6 +10059,11 @@ sim_brk_dflt = SWMASK ('E'); sim_clock_precalibrate_commands = pdp10_clock_precalibrate_commands; sim_rtcn_init_unit (&cpu_unit[0], cpu_unit[0].wait, TMR_RTC); sim_activate(&cpu_unit[0], 10000); +#if ITS +if (QITS) { + sim_rtcn_init_unit (&cpu_unit[1], cpu_unit[1].wait, TMR_RTC); +} +#endif #if MPX_DEV mpx_enable = 0; #endif @@ -6081,14 +10082,34 @@ if (vptr == NULL) if (ea < 020) *vptr = FM[ea] & FMASK; else { +#if KL | KI if (sw & SWMASK ('V')) { - if (ea >= MAXMEMSIZE) - return SCPE_REL; + int uf = ((sw & SWMASK('U')) != 0); + int page = ea >> 9; + uint32 tlb; +#if KL + if (!uf && !t20_page && (page & 0740) == 0340) { +#else + if (!uf && (page & 0740) == 0340) { +#endif + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + uf = 1; } + if (uf) + tlb = u_tlb[page]; + else + tlb = e_tlb[page]; + if ((tlb & RSIGN) == 0) + return 4; + ea = ((tlb & 017777) << 9) + (ea & 0777); + } +#endif + if (ea >= MEMSIZE) return SCPE_NXM; *vptr = M[ea] & FMASK; - } +} return SCPE_OK; } @@ -6099,10 +10120,29 @@ t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) if (ea < 020) FM[ea] = val & FMASK; else { +#if KL | KI if (sw & SWMASK ('V')) { - if (ea >= MAXMEMSIZE) - return SCPE_REL; + int uf = ((sw & SWMASK('U')) != 0); + int page = ea >> 9; + uint32 tlb; +#if KL + if (!uf && !t20_page && (page & 0740) == 0340) { +#else + if (!uf && (page & 0740) == 0340) { +#endif + /* Pages 340-377 via UBT */ + page += 01000 - 0340; + uf = 1; } + if (uf) + tlb = u_tlb[page]; + else + tlb = e_tlb[page]; + if ((tlb & RSIGN) == 0) + return 4; + ea = ((tlb & 017777) << 9) + (ea & 0777); + } +#endif if (ea >= MEMSIZE) return SCPE_NXM; M[ea] = val & FMASK; @@ -6139,6 +10179,8 @@ t_bool build_dev_tab (void) DEVICE *dptr; DIB *dibp; uint32 i, j, d; +int rh20; +int rh_idx; /* Set trap offset based on MAOFF flag */ maoff = (cpu_unit[0].flags & UNIT_MAOFF)? 0100 : 0; @@ -6180,32 +10222,58 @@ dev_tab[0] = &dev_apr; dev_tab[1] = &dev_pi; #if KI | KL dev_tab[2] = &dev_pag; +#if KL +dev_tab[3] = &dev_cca; +dev_tab[4] = &dev_tim; +dev_irqv[4] = &tim_irq; +dev_tab[5] = &dev_mtr; +#endif #endif #if BBN if (QBBN) dev_tab[024>>2] = &dev_pag; #endif -/* Assign all RH10 devices */ -for (j = i = 0; (dptr = rh_devs[i]) != NULL; i++) { + +/* Assign all RH10 & RH20 devices */ +rh20 = 0540; +rh_idx = 0; +for (i = 0; (dptr = rh_devs[i]) != NULL; i++) { dibp = (DIB *) dptr->ctxt; if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ - if (rh[j].dev_num == 0) - break; - d = rh[j].dev_num; + d = dibp->dev_num; /* Check type */ + if (d & RH10_DEV) { /* Skip RH10 devices */ + d = rh_nums[rh_idx]; + if (d == 0) { + sim_printf ("To many RH10 devices %s\n", sim_dname (dptr)); + return TRUE; + } +#if KL + } else if (d & RH20_DEV) { /* RH20, grab next device */ +#if NUM_DEVS_NIA > 0 + /* If NIA20 installed, skip this slot */ + if ((nia_dev.flags & DEV_DIS) == 0 && dptr != &nia_dev && + rh20 == (((DIB *)nia_dev.ctxt)->dev_num & 0777)) + rh20 += 4; + /* If NIA20, then assign it to it's requested address */ + if ((nia_dev.flags & DEV_DIS) == 0 && dptr == &nia_dev) + d = dibp->dev_num & 0777; + else +#endif + d = rh20; + rh20 += 4; +#endif + } dev_tab[(d >> 2)] = dibp->io; dev_irqv[(d >> 2)] = dibp->irq; - rh[j].dev = dptr; - j++; + rh[rh_idx].dev_num = d; + rh[rh_idx].dev = dptr; + rh[rh_idx].rh = dibp->rh; + dibp->rh->devnum = d; + rh_idx++; } } -/* Make sure all are assigned */ -if (j == 4 && rh_devs[i] != NULL) { - sim_printf ("To many RH10 devices %s\n", sim_dname (dptr)); - return TRUE; -} - /* Assign all remaining devices */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { dibp = (DIB *) dptr->ctxt; @@ -6213,7 +10281,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { for (j = 0; j < dibp->num_devs; j++) { /* loop thru disp */ if (dibp->io) { /* any dispatch? */ d = dibp->dev_num; - if (d & RH10_DEV) /* Skip RH10 devices */ + if (d & (RH10_DEV|RH20_DEV)) /* Skip RH10 & RH20 devices */ continue; if (dev_tab[(d >> 2) + j] != &null_dev) { /* already filled? */ @@ -6312,14 +10380,24 @@ else lnt = hst_lnt; di = hst_p - lnt; /* work forward */ if (di < 0) di = di + hst_lnt; -fprintf (st, "PC AC EA AR RES FLAGS IR\n\n"); +fprintf (st, "PC AC EA AR RES FLAGS IR\n\n"); for (k = 0; k < lnt; k++) { /* print specified */ h = &hst[(++di) % hst_lnt]; /* entry pointer */ if (h->pc & HIST_PC) { /* instruction? */ - fprintf (st, "%06o ", h->pc & 0777777); +#if KL + if (QKLB) + fprintf(st, "%08o ", h->pc & 0777777777); + else +#endif + fprintf (st, "%06o ", h->pc & 0777777); fprint_val (st, h->ac, 8, 36, PV_RZRO); fputs (" ", st); - fprintf (st, "%06o ", h->ea); +#if KL + if (QKLB) + fprintf(st, "%08o ", h->ea & 0777777777); + else +#endif + fprintf (st, "%06o ", h->ea); fputs (" ", st); fprint_val (st, h->mb, 8, 36, PV_RZRO); fputs (" ", st); @@ -6327,10 +10405,14 @@ for (k = 0; k < lnt; k++) { /* print specified */ fputs (" ", st); #if KI | KL fprintf (st, "%c%06o ", ((h->flags & (PRV_PUB << 5))? 'p':' '), h->flags & 0777777); + fprintf (st, "%02o ", h->prev_sect); #else fprintf (st, "%06o ", h->flags); #endif - if ((h->pc & HIST_PC2) == 0) { + if ((h->pc & HIST_PCE) != 0) { + sim_eval = h->ir; + fprint_val (st, sim_eval, 8, 36, PV_RZRO); + } else if ((h->pc & HIST_PC2) == 0) { sim_eval = h->ir; fprint_val (st, sim_eval, 8, 36, PV_RZRO); fputs (" ", st); @@ -6361,7 +10443,7 @@ const char * cpu_description (DEVICE *dptr) { #if KL - return "KL10A CPU"; + return "KL10 CPU"; #endif #if KI return "KI10 CPU"; diff --git a/PDP10/kx10_defs.h b/PDP10/kx10_defs.h index 13c453c..730a0fe 100644 --- a/PDP10/kx10_defs.h +++ b/PDP10/kx10_defs.h @@ -46,16 +46,12 @@ #define KI 0 #endif -#ifndef KLA -#define KLA 0 +#ifndef KL +#define KL 0 #endif -#ifndef KLB -#define KLB 0 -#endif - -#ifndef KL /* Either KL10A or KL10B */ -#define KL (KLA+KLB) +#if KL +#define EPT440 0 /* Force KL10 to use as 440 section address */ #endif #if (PDP6 + KA + KI + KL) != 1 @@ -81,6 +77,11 @@ #define WAITS KA #endif +/* Support for ITS on KL */ +#ifndef KL_ITS +#define KL_ITS KL +#endif + #ifndef PDP6_DEV /* Include PDP6 devices */ #define PDP6_DEV PDP6|WAITS #endif @@ -161,12 +162,19 @@ extern DEBTAB crd_debug[]; #define XMASK 03777777777777LL #define EMASK 00777000000000LL #define MMASK 00000777777777LL +#define SECTM 00007777000000LL #define BIT1 00200000000000LL +#define BIT2 00100000000000LL +#define BIT3 00040000000000LL +#define BIT4 00020000000000LL +#define BIT5 00010000000000LL +#define BIT6 00004000000000LL #define BIT7 00002000000000LL #define BIT8 00001000000000LL #define BIT9 00000400000000LL #define BIT10 00000200000000LL #define BIT10_35 00000377777777LL +#define BIT12 00000040000000LL #define BIT17 00000001000000LL #define MANT 00000777777777LL #define EXPO 00377000000000LL @@ -181,6 +189,7 @@ extern DEBTAB crd_debug[]; #define FPRBIT1 00000000000200000000000LL #define CM(x) (FMASK ^ (x)) +#define CCM(x) ((CMASK ^ (x)) & CMASK) #define INST_V_OP 27 /* opcode */ #define INST_M_OP 0777 @@ -205,6 +214,8 @@ extern DEBTAB crd_debug[]; #define LRZ(x) (((x) >> 18) & RMASK) #define JRST1 (((uint64)OP_JRST << 27) + 1) +#define OP_PORTAL(x) (((x) & 00777740000000LL) == 0254040000000LL) + #if PDP6 #define NODIV 000000 #define FLTUND 000000 @@ -275,6 +286,12 @@ extern DEBTAB crd_debug[]; #define AMASK 00000017777777LL #define WMASK 0037777LL #define CSHIFT 22 +#if KL +#define RH20_WMASK 003777LL +#define RH20_XFER SMASK +#define RH20_HALT BIT1 +#define RH20_REV BIT2 +#endif #else #define AMASK RMASK #define WMASK RMASK @@ -285,11 +302,19 @@ extern DEBTAB crd_debug[]; #define PI_ENABLE 0000000010 /* Clear DONE */ #define BUSY 0000000020 /* STOP */ #define CCW_COMP 0000000040 /* Write Final CCW */ +/* RH10 / RH20 interrupt */ +#define IADR_ATTN 0000000000040LL /* Interrupt on attention */ +#define IARD_RAE 0000000000100LL /* Interrupt on register access error */ +#define CCW_COMP_1 0000000040000LL /* Control word written. */ #if KI #define DEF_SERIAL 514 /* Default DEC test machine */ #endif +#if KL +#define DEF_SERIAL 1025 /* Default DEC test machine */ +#endif + #if BBN #define BBN_PAGE 0000017777777LL #define BBN_TRPPG 0000017000000LL @@ -306,13 +331,36 @@ extern DEBTAB crd_debug[]; #define BBN_MERGE 0161740000000LL #endif +#if KL +/* KL10 TLB paging bits */ +#define KL_PAG_A 0400000 /* Access */ +#define KL_PAG_P 0200000 /* Public */ +#define KL_PAG_W 0100000 /* Writable (M Tops 20) */ +#define KL_PAG_S 0040000 /* Software (W Writable Tops 20) */ +#define KL_PAG_C 0020000 /* Cacheable */ +#endif + +#if KI +/* KI10 TLB paging bits */ +#define KI_PAG_A 0400000 /* Access */ +#define KI_PAG_P 0200000 /* Public */ +#define KI_PAG_W 0100000 /* Writable */ +#define KI_PAG_S 0040000 /* Software */ +#define KI_PAG_X 0020000 /* Reserved */ +#endif + /* Flags for CPU unit */ #define UNIT_V_MSIZE (UNIT_V_UF + 0) #define UNIT_MSIZE (0177 << UNIT_V_MSIZE) #define UNIT_V_MAOFF (UNIT_V_MSIZE + 8) #define UNIT_V_PAGE (UNIT_V_MAOFF + 1) #define UNIT_MAOFF (1 << UNIT_V_MAOFF) +#if KL +#define UNIT_KL10B (1 << UNIT_V_PAGE) +#define UNIT_TWOSEG (0) +#else #define UNIT_TWOSEG (1 << UNIT_V_PAGE) +#endif #define UNIT_ITSPAGE (2 << UNIT_V_PAGE) #define UNIT_BBNPAGE (4 << UNIT_V_PAGE) #define UNIT_M_PAGE (007 << UNIT_V_PAGE) @@ -322,7 +370,29 @@ extern DEBTAB crd_debug[]; #define UNIT_V_MPX (UNIT_V_WAITS + 1) #define UNIT_M_MPX (1 << UNIT_V_MPX) #define UNIT_MPX (UNIT_M_MPX) /* MPX Device for ITS */ +#define CNTRL_V_RH (UNIT_V_UF + 4) +#define CNTRL_M_RH 7 +#define GET_CNTRL_RH(x) (((x) >> CNTRL_V_RH) & CNTRL_M_RH) +#define CNTRL_RH(x) (((x) & CNTRL_M_RH) << CNTRL_V_RH) +#define DEV_V_RH (DEV_V_UF + 1) /* Type RH20 */ +#define DEV_M_RH (1 << DEV_V_RH) +#define TYPE_RH10 (0 << DEV_V_RH) +#define TYPE_RH20 (1 << DEV_V_RH) +#if KL +/* DTE memory access functions, n = DTE# */ +extern int Mem_examine_word(int n, int wrd, uint64 *data); +extern int Mem_deposit_word(int n, int wrd, uint64 *data); +extern int Mem_read_byte(int n, uint16 *data, int byte); +extern int Mem_write_byte(int n, uint16 *data); +#endif + +/* + * Access main memory. Returns 0 if access ok, 1 if out of memory range. + * On KI10 and KL10, optional EPT flag indicates address relative to ept. + */ +extern int Mem_read_word(t_addr addr, uint64 *data, int ept); +extern int Mem_write_word(t_addr addr, uint64 *data, int ept); #if MPX_DEV extern void set_interrupt_mpx(int dev, int lvl, int mpx); @@ -338,8 +408,15 @@ extern void set_pi_hold(); extern UNIT cpu_unit[]; extern UNIT ten11_unit[]; extern UNIT auxcpu_unit[]; -extern DEVICE cpu_dev; +#if KL +extern DEVICE dte_dev; +extern DEVICE lp20_dev; +extern DEVICE tty_dev; +extern DEVICE nia_dev; +#else extern DEVICE cty_dev; +#endif +extern DEVICE cpu_dev; extern DEVICE mt_dev; extern DEVICE dpa_dev; extern DEVICE dpb_dev; @@ -365,6 +442,7 @@ extern DEVICE pmp_dev; extern DEVICE dk_dev; extern DEVICE pd_dev; extern DEVICE dpy_dev; +extern DEVICE iii_dev; extern DEVICE imx_dev; extern DEVICE imp_dev; extern DEVICE ch10_dev; @@ -387,41 +465,67 @@ extern t_stat (*dev_tab[128])(uint32 dev, t_uint64 *data); #define VEC_DEVMAX 8 /* max device vec */ +/* DF10 Interface */ +struct df10 { + uint32 status; /* DF10 status word */ + uint32 cia; /* Initial transfer address */ + uint32 ccw; /* Next control word address */ + uint32 wcr; /* CUrrent word count */ + uint32 cda; /* Current transfer address */ + uint32 devnum; /* Device number */ + t_uint64 buf; /* Data buffer */ + uint8 nxmerr; /* Bit to set for NXM */ + uint8 ccw_comp; /* Have we written out CCW */ +} ; + +/* RH10/RH20 Interface */ +struct rh_if { + void (*dev_write)(DEVICE *dptr, struct rh_if *rh, int reg, uint32 data); + uint32 (*dev_read)(DEVICE *dptr, struct rh_if *rh, int reg); + void (*dev_reset)(DEVICE *dptr); + t_uint64 buf; /* Data buffer */ + uint32 status; /* DF10 status word */ + uint32 cia; /* Initial transfer address */ + uint32 ccw; /* Current word count */ + uint32 wcr; + uint32 cda; /* Current transfer address */ + uint32 devnum; /* Device number */ + int ivect; /* Interrupt vector */ + uint8 imode; /* Mode of vector */ + int cop; /* RH20 Channel operator */ + uint32 sbar; /* RH20 Starting address */ + uint32 stcr; /* RH20 Count */ + uint32 pbar; + uint32 ptcr; + int reg; /* Last register selected */ + int drive; /* Last drive selected */ + int rae; /* Access register error */ + int attn; /* Attention bits */ + int xfer_drive; /* Current transfering drive */ +}; + /* Device context block */ struct pdp_dib { uint32 dev_num; /* device address */ uint32 num_devs; /* length */ t_stat (*io)(uint32 dev, t_uint64 *data); - int (*irq)(uint32 dev, int addr); + t_addr (*irq)(uint32 dev, t_addr addr); + struct rh_if *rh; }; - + #define RH10_DEV 01000 +#define RH20_DEV 02000 struct rh_dev { uint32 dev_num; DEVICE *dev; + struct rh_if *rh; }; - typedef struct pdp_dib DIB; - -/* DF10 Interface */ -struct df10 { - uint32 status; - uint32 cia; - uint32 ccw; - uint32 wcr; - uint32 cda; - uint32 devnum; - t_uint64 buf; - uint8 nxmerr; - uint8 ccw_comp; -} ; - - -void df10_setirq(struct df10 *df) ; -void df10_writecw(struct df10 *df) ; -void df10_finish_op(struct df10 *df, int flags) ; +void df10_setirq(struct df10 *df); +void df10_writecw(struct df10 *df); +void df10_finish_op(struct df10 *df, int flags); void df10_setup(struct df10 *df, uint32 addr); int df10_fetch(struct df10 *df); int df10_read(struct df10 *df); @@ -432,8 +536,27 @@ int dct_write(int u, t_uint64 *data, int c); int dct_is_connect(int u); #endif -int ten11_read (int addr, t_uint64 *data); -int ten11_write (int addr, t_uint64 data); +/* Define RH10/RH20 functions */ +t_stat rh_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat rh_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat rh_devio(uint32 dev, t_uint64 *data); +t_addr rh_devirq(uint32 dev, t_addr addr); +#if KL +void rh20_setup(struct rh_if *rhc); +#endif +void rh_setup(struct rh_if *rh, uint32 addr); +void rh_setattn(struct rh_if *rh, int unit); +void rh_error(struct rh_if *rh); +int rh_blkend(struct rh_if *rh); +void rh_setirq(struct rh_if *rh); +void rh_writecw(struct rh_if *rh, int nxm); +void rh_finish_op(struct rh_if *rh, int flags); +int rh_read(struct rh_if *rh); +int rh_write(struct rh_if *rh); + + +int ten11_read (t_addr addr, t_uint64 *data); +int ten11_write (t_addr addr, t_uint64 data); /* Console lights. */ extern void ka10_lights_init (void); @@ -441,14 +564,20 @@ extern void ka10_lights_main (t_uint64); extern void ka10_lights_set_aux (int); extern void ka10_lights_clear_aux (int); -int auxcpu_read (int addr, t_uint64 *); -int auxcpu_write (int addr, t_uint64); +int auxcpu_read (t_addr addr, t_uint64 *); +int auxcpu_write (t_addr addr, t_uint64); /* I/O system parameters */ #define NUM_DEVS_LP 1 +#if KL +#define NUM_DEVS_PT 0 +#define NUM_DEVS_CR 0 +#define NUM_DEVS_CP 0 +#else #define NUM_DEVS_PT 1 #define NUM_DEVS_CR 1 #define NUM_DEVS_CP 1 +#endif #define NUM_DEVS_DPY USE_DISPLAY #define NUM_DEVS_WCNSLS USE_DISPLAY #if PDP6_DEV @@ -461,16 +590,31 @@ int auxcpu_write (int addr, t_uint64); #if !PDP6 #define NUM_DEVS_DC 1 #define NUM_DEVS_MT 1 +#if KL +#define NUM_DEVS_RC 0 +#define NUM_DEVS_DT 0 +#define NUM_DEVS_DK 0 +#define NUM_DEVS_DP 0 +#define NUM_DEVS_LP20 1 +#define NUM_DEVS_TTY 1 +#define NUM_LINES_TTY 40 +#define NUM_DEVS_NIA 1 +#else #define NUM_DEVS_RC 1 #define NUM_DEVS_DT 1 #define NUM_DEVS_DK 1 #define NUM_DEVS_DP 2 +#define NUM_DEVS_LP20 0 +#define NUM_DEVS_TTY 0 +#define NUM_DEVS_NIA 0 +#endif #define NUM_DEVS_RP 4 #define NUM_DEVS_RS 1 #define NUM_DEVS_TU 1 #define NUM_DEVS_PMP WAITS #define NUM_DEVS_DKB WAITS -#define NUM_DEVS_PD ITS +#define NUM_DEVS_III 0 /* (WAITS * USE_DISPLAY) *//* Disabled until working */ +#define NUM_DEVS_PD ITS | KL_ITS #define NUM_DEVS_IMX ITS #define NUM_DEVS_STK ITS #define NUM_DEVS_TK10 ITS @@ -478,7 +622,7 @@ int auxcpu_write (int addr, t_uint64); #define NUM_DEVS_TEN11 ITS #define NUM_DEVS_AUXCPU ITS #define NUM_DEVS_IMP 1 -#define NUM_DEVS_CH10 ITS +#define NUM_DEVS_CH10 ITS | KL_ITS #define NUM_DEVS_DPK ITS #define NUM_DEVS_AI ITS #endif diff --git a/PDP10/kx10_df.c b/PDP10/kx10_df.c index ceeb46e..90564ea 100644 --- a/PDP10/kx10_df.c +++ b/PDP10/kx10_df.c @@ -1,6 +1,6 @@ -/* ka10_df.c: DF10 common routines. +/* kx10_df.c: DF10 common routines. - Copyright (c) 2015-2017, Richard Cornwell + Copyright (c) 2015-2019, Richard Cornwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,18 +23,24 @@ #include "kx10_defs.h" + +/* Set an IRQ for a DF10 device */ void df10_setirq(struct df10 *df) { df->status |= PI_ENABLE; set_interrupt(df->devnum, df->status); } +/* Generate the DF10 complete word */ void df10_writecw(struct df10 *df) { + uint64 wrd; df->status |= 1 << df->ccw_comp; if (df->wcr != 0) df->cda++; - M[df->cia|1] = ((uint64)(df->ccw & WMASK) << CSHIFT) | ((uint64)(df->cda) & AMASK); + wrd = ((uint64)(df->ccw & WMASK) << CSHIFT) | ((uint64)(df->cda) & AMASK); + (void)Mem_write_word(df->cia|1, &wrd, 0); } +/* Finish off a DF10 transfer */ void df10_finish_op(struct df10 *df, int flags) { df->status &= ~BUSY; df->status |= flags; @@ -42,6 +48,7 @@ void df10_finish_op(struct df10 *df, int flags) { df10_setirq(df); } +/* Setup for a DF10 transfer */ void df10_setup(struct df10 *df, uint32 addr) { df->cia = addr & ICWA; df->ccw = df->cia; @@ -50,24 +57,23 @@ void df10_setup(struct df10 *df, uint32 addr) { df->status &= ~(1 << df->ccw_comp); } +/* Fetch the next IO control word */ int df10_fetch(struct df10 *df) { uint64 data; - if (df->ccw > MEMSIZE) { + if (Mem_read_word(df->ccw, &data, 0)) { df10_finish_op(df, df->nxmerr); return 0; } - data = M[df->ccw]; while((data & (WMASK << CSHIFT)) == 0) { if ((data & AMASK) == 0 || (uint32)(data & AMASK) == df->ccw) { df10_finish_op(df,0); return 0; } df->ccw = (uint32)(data & AMASK); - if (df->ccw > MEMSIZE) { + if (Mem_read_word(df->ccw, &data, 0)) { df10_finish_op(df, 1<nxmerr); return 0; } - data = M[df->ccw]; } #if KA & ITS if (cpu_unit[0].flags & UNIT_ITSPAGE) { @@ -84,6 +90,7 @@ int df10_fetch(struct df10 *df) { return 1; } +/* Read next word */ int df10_read(struct df10 *df) { uint64 data; if (df->wcr == 0) { @@ -102,7 +109,10 @@ int df10_read(struct df10 *df) { else #endif df->cda = (uint32)((df->cda + 1) & AMASK); - data = M[df->cda]; + if (Mem_read_word(df->cda, &data, 0)) { + df10_finish_op(df, 1<nxmerr); + return 0; + } } else { data = 0; } @@ -113,6 +123,7 @@ int df10_read(struct df10 *df) { return 1; } +/* Write next word */ int df10_write(struct df10 *df) { if (df->wcr == 0) { if (!df10_fetch(df)) @@ -130,7 +141,10 @@ int df10_write(struct df10 *df) { else #endif df->cda = (uint32)((df->cda + 1) & AMASK); - M[df->cda] = df->buf; + if (Mem_write_word(df->cda, &df->buf, 0)) { + df10_finish_op(df, 1<nxmerr); + return 0; + } } if (df->wcr == 0) { return df10_fetch(df); diff --git a/PDP10/kx10_dp.c b/PDP10/kx10_dp.c index 2f41a4f..75496e4 100644 --- a/PDP10/kx10_dp.c +++ b/PDP10/kx10_dp.c @@ -423,7 +423,6 @@ t_stat dp_devio(uint32 dev, uint64 *data) { if (*data & BUSY) { /* Stop controller */ sim_cancel(uptr); - uptr->STATUS &= ~BUSY; df10_finish_op(df10, 0); } /* Clear flags */ @@ -722,7 +721,7 @@ t_stat dp_svc (UNIT *uptr) CLR_BUF(uptr); } if (r) - sim_activate(uptr, 25); + sim_activate(uptr, 40); else { uptr->STATUS &= ~(SRC_DONE|END_CYL|BUSY); uptr->UFLAGS |= DONE; diff --git a/PDP10/kx10_dt.c b/PDP10/kx10_dt.c index 15e4643..a665020 100644 --- a/PDP10/kx10_dt.c +++ b/PDP10/kx10_dt.c @@ -1061,6 +1061,7 @@ dt_boot(int32 unit_num, DEVICE * dptr) addr = (addr + 1) & RMASK; word = ((uint64)fbuf[off++]) << 18; word |= (uint64)fbuf[off++]; +fprintf(stderr, "%06o %012llo %06o\n\r", addr, word, wc); if (addr < 020) FM[addr] = word; else @@ -1073,6 +1074,7 @@ dt_boot(int32 unit_num, DEVICE * dptr) uptr->DSTATE = (1 << DTC_V_BLK) | DTC_BLOCK | DTC_MOT; sim_activate(uptr,30000); PC = word & RMASK; +fprintf(stderr, "%06o\n\r", PC); return SCPE_OK; } diff --git a/PDP10/kx10_imp.c b/PDP10/kx10_imp.c index a5f73c0..bdfbadb 100644 --- a/PDP10/kx10_imp.c +++ b/PDP10/kx10_imp.c @@ -451,6 +451,7 @@ static CONST ETH_MAC broadcast_ethaddr = {0xff,0xff,0xff,0xff,0xff,0xff}; static CONST in_addr_T broadcast_ipaddr = {0xffffffff}; t_stat imp_devio(uint32 dev, uint64 *data); +t_addr imp_devirq(uint32 dev, t_addr addr); t_stat imp_srv(UNIT *); t_stat imp_eth_srv(UNIT *); t_stat imp_tim_srv(UNIT *); @@ -503,7 +504,13 @@ UNIT imp_unit[] = { {UDATA(imp_eth_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ {UDATA(imp_tim_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ }; -DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio, NULL}; +DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio, +#if KL + &imp_devirq, +#else + NULL +#endif +}; MTAB imp_mod[] = { { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", @@ -562,10 +569,13 @@ DEBTAB imp_debug[] = { {0, 0} }; - +REG imp_reg[] = { + {BRDATA(DATA, &imp_data, 16, 8, sizeof(struct imp_device)), REG_HRO}, + {0} +}; DEVICE imp_dev = { - "IMP", imp_unit, NULL, imp_mod, + "IMP", imp_unit, imp_reg, imp_mod, 3, 8, 0, 1, 8, 36, NULL, NULL, &imp_reset, NULL, &imp_attach, &imp_detach, &imp_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, imp_debug, @@ -635,6 +645,7 @@ t_stat imp_devio(uint32 dev, uint64 *data) uptr->STATUS |= IMPIHE; if (*data & IMPLHW) /* Last host word. */ uptr->STATUS |= IMPLHW; + check_interrupts(uptr); break; case TYPE_BBN: break; @@ -731,6 +742,20 @@ t_stat imp_devio(uint32 dev, uint64 *data) return SCPE_OK; } +#if KL +/* Handle KL style interrupt vectors for ITS */ +t_addr +imp_devirq(uint32 dev, t_addr addr) { + if ((cpu_unit[0].flags & UNIT_ITSPAGE) != 0 && (imp_data.pia & 7) == 1) { + if (imp_unit[0].STATUS & IMPID && (imp_unit[0].STATUS & IMPLW) == 0) + return 070|RSIGN; + if (imp_unit[0].STATUS & IMPOD) + return 072|RSIGN; + } + return addr; +} +#endif + t_stat imp_srv(UNIT * uptr) { DEVICE *dptr = find_dev_from_unit(uptr); diff --git a/PDP10/kx10_rh.c b/PDP10/kx10_rh.c new file mode 100644 index 0000000..924ea6e --- /dev/null +++ b/PDP10/kx10_rh.c @@ -0,0 +1,801 @@ +/* kx10_rh.c: RH10/RH20 interace routines. + + Copyright (c) 2015-2019, 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 "kx10_defs.h" + + +/* CONI Flags */ +#define IADR_ATTN 0000000000040LL /* Interrupt on attention */ +#define IARD_RAE 0000000000100LL /* Interrupt on register access error */ +#define DIB_CBOV 0000000000200LL /* Control bus overrun */ +#define CXR_PS_FAIL 0000000002000LL /* Power supply fail (not implemented) */ +#define CXR_ILC 0000000004000LL /* Illegal function code */ +#define CR_DRE 0000000010000LL /* Or Data and Control Timeout */ +#define DTC_OVER 0000000020000LL /* DF10 did not supply word on time (not implemented) */ +#define CCW_COMP_1 0000000040000LL /* Control word written. */ +#define CXR_CHAN_ER 0000000100000LL /* Channel Error */ +#define CXR_EXC 0000000200000LL /* Error in drive transfer */ +#define CXR_DBPE 0000000400000LL /* Device Parity error (not implemented) */ +#define CXR_NXM 0000001000000LL /* Channel non-existent memory (not implemented) */ +#define CXR_CWPE 0000002000000LL /* Channel Control word parity error (not implemented) */ +#define CXR_CDPE 0000004000000LL /* Channel Data Parity Error (not implemented) */ +#define CXR_SD_RAE 0000200000000LL /* Register access error */ +#define CXR_ILFC 0000400000000LL /* Illegal CXR function code */ +#define B22_FLAG 0004000000000LL /* 22 bit channel */ +#define CC_CHAN_PLS 0010000000000LL /* Channel transfer pulse (not implemented) */ +#define CC_CHAN_ACT 0020000000000LL /* Channel in use */ +#define CC_INH 0040000000000LL /* Disconnect channel */ +#define CB_FULL 0200000000000LL /* Set when channel buffer is full (not implemented) */ +#define AR_FULL 0400000000000LL /* Set when AR is full (not implemented) */ + +/* RH20 CONI Flags */ +#define RH20_PCR_FULL 0000000000020LL /* Primary command file full */ +#define RH20_ATTN_ENA 0000000000040LL /* Attention enable */ +#define RH20_SCR_FULL 0000000000100LL /* Secondary command full */ +#define RH20_ATTN 0000000000200LL /* Attention */ +#define RH20_MASS_ENA 0000000000400LL /* Mass bus enable */ +#define RH20_DATA_OVR 0000000001000LL /* Data overrun */ +#define RH20_CHAN_RDY 0000000002000LL /* Channel ready to start */ +#define RH20_RAE 0000000004000LL /* Register access error */ +#define RH20_DR_RESP 0000000010000LL /* Drive no response */ +#define RH20_CHAN_ERR 0000000020000LL /* Channel error */ +#define RH20_SHRT_WC 0000000040000LL /* Short word count */ +#define RH20_LONG_WC 0000000100000LL /* Long word count */ +#define RH20_DR_EXC 0000000200000LL /* Exception */ +#define RH20_DATA_PRI 0000000400000LL /* Data parity error */ +#define RH20_SBAR 0000001000000LL /* SBAR set */ +#define RH20_XEND 0000002000000LL /* Transfer ended */ + +/* CONO Flags */ +#define ATTN_EN 0000000000040LL /* enable attention interrupt. */ +#define REA_EN 0000000000100LL /* enable register error interrupt */ +#define CBOV_CLR 0000000000200LL /* Clear CBOV */ +#define CONT_RESET 0000000002000LL /* Clear All error bits */ +#define ILC_CLR 0000000004000LL /* Clear ILC and SD RAE */ +#define DRE_CLR 0000000010000LL /* Clear CR_CBTO and CR_DBTO */ +#define OVER_CLR 0000000020000LL /* Clear DTC overrun */ +#define WRT_CW 0000000040000LL /* Write control word */ +#define CHN_CLR 0000000100000LL /* Clear Channel Error */ +#define DR_EXC_CLR 0000000200000LL /* Clear DR_EXC */ +#define DBPE_CLR 0000000400000LL /* Clear CXR_DBPE */ + +/* RH20 CONO Flags */ +#define RH20_DELETE_SCR 0000000000100LL /* Clear SCR */ +#define RH20_RCLP 0000000000200LL /* Reset command list */ +#define RH20_MASS_EN 0000000000400LL /* Mass bus enable */ +#define RH20_XFER_CLR 0000000001000LL /* Clear XFER error */ +#define RH20_CLR_MBC 0000000002000LL /* Clear MBC */ +#define RH20_CLR_RAE 0000000004000LL /* Clear RAE error */ + +/* DATAO/DATAI */ +#define CR_REG 0770000000000LL /* Register number */ +#define LOAD_REG 0004000000000LL /* Load register */ +#define CR_MAINT_MODE 0000100000000LL /* Maint mode... not implemented */ +#define CR_DRIVE 0000007000000LL +#define CR_GEN_EVD 0000000400000LL /* Enable Parity */ +#define CR_DXES 0000000200000LL /* Disable DXES errors */ +#define CR_INAD 0000000077600LL +#define CR_WTEVM 0000000000100LL /* Verify Parity */ +#define CR_FUNC 0000000000076LL +#define CR_GO 0000000000001LL + +#define IRQ_VECT 0000000000777LL /* Interupt vector */ +#define IRQ_KI10 0000002000000LL +#define IRQ_KA10 0000001000000LL +#define FNC_XFER 024 /* >=? data xfr */ + +/* Status register settings */ +#define DS_OFF 0000001 /* offset mode */ +#define DS_VV 0000100 /* volume valid */ +#define DS_DRY 0000200 /* drive ready */ +#define DS_DPR 0000400 /* drive present */ +#define DS_PGM 0001000 /* programable NI */ +#define DS_LST 0002000 /* last sector */ +#define DS_WRL 0004000 /* write locked */ +#define DS_MOL 0010000 /* medium online */ +#define DS_PIP 0020000 /* pos in progress */ +#define DS_ERR 0040000 /* error */ +#define DS_ATA 0100000 /* attention active */ + +/* RH20 channel status flags */ +#define RH20_MEM_PAR 00200000000000LL /* Memory parity error */ +#define RH20_NADR_PAR 00100000000000LL /* Address parity error */ +#define RH20_NOT_WC0 00040000000000LL /* Word count not zero */ +#define RH20_NXM_ERR 00020000000000LL /* Non existent memory */ +#define RH20_LAST_ERR 00000400000000LL /* Last transfer error */ +#define RH20_ERROR 00000200000000LL /* RH20 error */ +#define RH20_LONG_STS 00000100000000LL /* Did not reach wc */ +#define RH20_SHRT_STS 00000040000000LL /* WC reached zero */ +#define RH20_OVER 00000020000000LL /* Overrun error */ + +/* 0-37 mass bus register. + 70 SBAR, block address. + 71 STCR, neg block count, func + 72 PBAR + 73 PTCR + 74 IVIR Interrupt vector address. + 75 Diags read. + 76 Diags write. + 77 Status (tra,cb test, bar test, ev par, r/w, exc,ebl, 0, attn, sclk +*/ + +/* + * CCW 000..... New channel comand list pointer HALT. + 010..... Next CCW Address JUMP + 1xycount-address. x=halt last xfer, y=reverse +*/ + +extern uint32 eb_ptr; + +t_stat +rh_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + DEVICE *dptr; + DIB *dibp; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) + return SCPE_IERR; + dibp = (DIB *) dptr->ctxt; + dptr->flags &= ~DEV_M_RH; + dptr->flags |= val; + dibp->dev_num &= ~(RH10_DEV|RH20_DEV); + dibp->dev_num |= (val) ? RH20_DEV: RH10_DEV; + return SCPE_OK; +} + +t_stat rh_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + DEVICE *dptr; + + if (uptr == NULL) + return SCPE_IERR; + + dptr = find_dev_from_unit(uptr); + if (dptr == NULL) + return SCPE_IERR; + fprintf (st, "%s", (dptr->flags & TYPE_RH20) ? "RH20" : "RH10"); + return SCPE_OK; +} + + +t_stat rh_devio(uint32 dev, uint64 *data) { + DEVICE *dptr = NULL; + struct rh_if *rhc = NULL; + int drive; + + for (drive = 0; rh[drive].dev_num != 0; drive++) { + if (rh[drive].dev_num == (dev & 0774)) { + rhc = rh[drive].rh; + dptr = rh[drive].dev; + break; + } + } + if (rhc == NULL) + return SCPE_OK; +#if KL + if (dptr->flags & TYPE_RH20) { + switch(dev & 3) { + case CONI: + *data = rhc->status & RMASK; + if (rhc->attn != 0) + *data |= RH20_ATTN; + if (rhc->rae != 0) + *data |= RH20_RAE; + sim_debug(DEBUG_CONI, dptr, "%s %03o CONI %06o PC=%o %o\n", + dptr->name, dev, (uint32)*data, PC, rhc->attn); + return SCPE_OK; + + case CONO: + clr_interrupt(dev); + /* Clear flags */ + if (*data & RH20_CLR_MBC) { + if (rhc->dev_reset != NULL) + rhc->dev_reset(dptr); + rhc->attn = 0; + rhc->imode = 2; + } + rhc->status &= ~(07LL|IADR_ATTN|RH20_MASS_EN); + rhc->status |= *data & (07LL|IADR_ATTN|RH20_MASS_EN); + if (*data & RH20_DELETE_SCR) + rhc->status &= ~(RH20_SBAR|RH20_SCR_FULL); + if (*data & (RH20_RCLP|RH20_CLR_MBC)) + rhc->cia = eb_ptr | (rhc->devnum - 0540); + if (*data & (RH20_CLR_RAE|RH20_CLR_MBC)) + rhc->rae = 0; + if (*data & PI_ENABLE) + rhc->status &= ~PI_ENABLE; + if (((rhc->status & IADR_ATTN) != 0 && rhc->attn != 0) + || (rhc->status & PI_ENABLE)) + set_interrupt(rhc->devnum, rhc->status); + sim_debug(DEBUG_CONO, dptr, "%s %03o CONO %06o PC=%06o %06o\n", + dptr->name, dev, (uint32)*data, PC, rhc->status); + return SCPE_OK; + + case DATAI: + *data = 0; + if (rhc->status & BUSY && rhc->reg != 04) { + rhc->status |= CC_CHAN_ACT; + return SCPE_OK; + } + if (rhc->reg < 040) { + int parity; + *data = (uint64)(rhc->dev_read(dptr, rhc, rhc->reg) & 0177777); + parity = (int)((*data >> 8) ^ *data); + parity = (parity >> 4) ^ parity; + parity = (parity >> 2) ^ parity; + parity = ((parity >> 1) ^ parity) & 1; + *data |= ((uint64)(!parity)) << 16; + *data |= ((uint64)(rhc->drive)) << 18; + *data |= BIT10; + } else if ((rhc->reg & 070) != 070) { + rhc->rae = 1; + break; + } else { + switch(rhc->reg & 07) { + case 0: *data = rhc->sbar; break; + case 1: *data = rhc->stcr; break; + case 2: *data = rhc->pbar; break; + case 3: *data = rhc->ptcr; break; + case 4: *data = rhc->ivect; break; + case 5: + case 6: break; + case 7: *data = 0; break; + } + } + *data |= ((uint64)(rhc->reg)) << 30; + sim_debug(DEBUG_DATAIO, dptr, "%s %03o DATI %012llo %d PC=%06o\n", + dptr->name, dev, *data, rhc->drive, PC); + return SCPE_OK; + + case DATAO: + sim_debug(DEBUG_DATAIO, dptr, "%s %03o DATO %012llo PC=%06o %06o\n", + dptr->name, dev, *data, PC, rhc->status); + rhc->reg = ((int)(*data >> 30)) & 077; + rhc->imode |= 2; + if (rhc->reg < 040) + rhc->drive = (int)(*data >> 18) & 07; + if (*data & LOAD_REG) { + if (rhc->reg < 040) { + clr_interrupt(dev); + /* Check if access error */ + if (rhc->rae & (1 << rhc->drive) && (*data & BIT9) == 0) { + set_interrupt(rhc->devnum, rhc->status); + return SCPE_OK; + } + rhc->dev_write(dptr, rhc, rhc->reg & 037, (int)(*data & 0777777)); + if (((rhc->status & IADR_ATTN) != 0 && rhc->attn != 0) + || (rhc->status & PI_ENABLE)) + set_interrupt(rhc->devnum, rhc->status); + /* Check if access error */ + if (rhc->rae & (1 << rhc->drive) && (*data & BIT9) == 0) + set_interrupt(rhc->devnum, rhc->status); + else + rhc->rae &= ~(1 << rhc->drive); + } else if ((rhc->reg & 070) != 070) { + if ((*data & BIT9) == 0) { + rhc->rae = (1 << rhc->drive); + set_interrupt(rhc->devnum, rhc->status); + } + } else { + switch(rhc->reg & 07) { + case 0: + rhc->sbar = (*data) & (CR_DRIVE|RMASK); + rhc->status |= RH20_SBAR; + break; + case 1: + rhc->stcr = (*data) & (BIT10|BIT7|CR_DRIVE|RMASK); + rhc->status |= RH20_SCR_FULL; + break; + case 4: + rhc->ivect = (*data & IRQ_VECT); + break; + case 2: + case 3: + case 5: + case 6: + case 7: + break; + } + } + } + } + if ((rhc->status & (RH20_SCR_FULL|RH20_PCR_FULL)) == (RH20_SCR_FULL)) + rh20_setup(rhc); + return SCPE_OK; + } +#endif + switch(dev & 3) { + case CONI: + *data = rhc->status & ~(IADR_ATTN|IARD_RAE); + if (rhc->attn != 0 && (rhc->status & IADR_ATTN)) + *data |= IADR_ATTN; + if (rhc->rae != 0 && (rhc->status & IARD_RAE)) + *data |= IARD_RAE; +#if KI_22BIT + *data |= B22_FLAG; +#endif + sim_debug(DEBUG_CONI, dptr, "%s %03o CONI %06o PC=%o %o\n", + dptr->name, dev, (uint32)*data, PC, rhc->attn); + return SCPE_OK; + + case CONO: + clr_interrupt(dev); + rhc->status &= ~(07LL|IADR_ATTN|IARD_RAE); + rhc->status |= *data & (07LL|IADR_ATTN|IARD_RAE); + /* Clear flags */ + if (*data & CONT_RESET && rhc->dev_reset != NULL) + rhc->dev_reset(dptr); + if (*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)) + rhc->status &= ~(*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)); + if (*data & OVER_CLR) + rhc->status &= ~(DTC_OVER); + if (*data & CBOV_CLR) + rhc->status &= ~(DIB_CBOV); + if (*data & CXR_ILC) + rhc->status &= ~(CXR_ILFC|CXR_SD_RAE); + if (*data & WRT_CW) + rh_writecw(rhc, 0); + if (*data & PI_ENABLE) + rhc->status &= ~PI_ENABLE; + if (rhc->status & PI_ENABLE) + set_interrupt(dev, rhc->status); + if ((rhc->status & IADR_ATTN) != 0 && rhc->attn != 0) + set_interrupt(dev, rhc->status); + sim_debug(DEBUG_CONO, dptr, "%s %03o CONO %06o PC=%06o %06o\n", + dptr->name, dev, (uint32)*data, PC, rhc->status); + return SCPE_OK; + + case DATAI: + *data = 0; + if (rhc->status & BUSY && rhc->reg != 04) { + rhc->status |= CC_CHAN_ACT; + return SCPE_OK; + } + if (rhc->reg == 040) { + *data = (uint64)(rhc->dev_read(dptr, rhc, 0) & 077); + *data |= ((uint64)(rhc->cia)) << 6; + *data |= ((uint64)(rhc->xfer_drive)) << 18; + } else if (rhc->reg == 044) { + *data = (uint64)rhc->ivect; + if (rhc->imode) + *data |= IRQ_KI10; + else + *data |= IRQ_KA10; + } else if (rhc->reg == 054) { + *data = (uint64)(rhc->rae); + } else if ((rhc->reg & 040) == 0) { + int parity; + *data = (uint64)(rhc->dev_read(dptr, rhc, rhc->reg) & 0177777); + parity = (int)((*data >> 8) ^ *data); + parity = (parity >> 4) ^ parity; + parity = (parity >> 2) ^ parity; + parity = ((parity >> 1) ^ parity) & 1; + *data |= ((uint64)(parity ^ 1)) << 17; + *data |= ((uint64)(rhc->drive)) << 18; + } + *data |= ((uint64)(rhc->reg)) << 30; + sim_debug(DEBUG_DATAIO, dptr, "%s %03o DATI %012llo %d PC=%06o\n", + dptr->name, dev, *data, rhc->drive, PC); + return SCPE_OK; + + case DATAO: + sim_debug(DEBUG_DATAIO, dptr, "%s %03o DATO %012llo PC=%06o %06o\n", + dptr->name, dev, *data, PC, rhc->status); + rhc->reg = ((int)(*data >> 30)) & 077; + rhc->imode &= ~2; + if (rhc->reg < 040 && rhc->reg != 04) { + rhc->drive = (int)(*data >> 18) & 07; + } + if (*data & LOAD_REG) { + if (rhc->reg == 040) { + if ((*data & 1) == 0) { + return SCPE_OK; + } + + if (rhc->status & BUSY) { + rhc->status |= CC_CHAN_ACT; + return SCPE_OK; + } + + rhc->status &= ~(CCW_COMP_1|PI_ENABLE); + if (((*data >> 1) & 037) < FNC_XFER) { + rhc->status |= CXR_ILC; + rh_setirq(rhc); + sim_debug(DEBUG_DATAIO, dptr, + "%s %03o command abort %012llo, %d PC=%06o %06o\n", + dptr->name, dev, *data, rhc->drive, PC, rhc->status); + return SCPE_OK; + } + /* Check if access error */ + if (rhc->rae & (1 << rhc->drive)) + return SCPE_OK; + /* Start command */ + rh_setup(rhc, (uint32)(*data >> 6)); + rhc->xfer_drive = (int)(*data >> 18) & 07; + rhc->dev_write(dptr, rhc, 0, (uint32)(*data & 077)); + sim_debug(DEBUG_DATAIO, dptr, + "%s %03o command %012llo, %d PC=%06o %06o\n", + dptr->name, dev, *data, rhc->drive, PC, rhc->status); + } else if (rhc->reg == 044) { + /* Set KI10 Irq vector */ + rhc->ivect = (int)(*data & IRQ_VECT); + rhc->imode = (*data & IRQ_KI10) != 0; + } else if (rhc->reg == 050) { + ; /* Diagnostic access to mass bus. */ + } else if (rhc->reg == 054) { + /* clear flags */ + rhc->rae &= ~(*data & 0377); + if (rhc->rae == 0) + clr_interrupt(dev); + } else if ((rhc->reg & 040) == 0) { + rhc->drive = (int)(*data >> 18) & 07; + /* Check if access error */ + if (rhc->rae & (1 << rhc->drive)) { + return SCPE_OK; + } + rhc->dev_write(dptr, rhc, rhc->reg & 037, (int)(*data & 0777777)); + } + } + clr_interrupt(dev); + if (((rhc->status & (IADR_ATTN|BUSY)) == IADR_ATTN && rhc->attn != 0) + || (rhc->status & PI_ENABLE)) + set_interrupt(rhc->devnum, rhc->status); + return SCPE_OK; + } + return SCPE_OK; /* Unreached */ +} + +/* Handle KI and KL style interrupt vectors */ +t_addr +rh_devirq(uint32 dev, t_addr addr) { + DEVICE *dptr = NULL; + struct rh_if *rhc = NULL; + int drive; + + for (drive = 0; rh[drive].dev_num != 0; drive++) { + if (rh[drive].dev_num == (dev & 0774)) { + rhc = rh[drive].rh; + break; + } + } + if (rhc != NULL) { + if (rhc->imode == 1) /* KI10 Style */ + addr = RSIGN | rhc->ivect; + else if (rhc->imode == 2) /* RH20 style */ + addr = rhc->ivect; + } + return addr; +} + +/* Set the attention flag for a unit */ +void rh_setattn(struct rh_if *rhc, int unit) +{ + rhc->attn |= 1<status & BUSY) == 0 && (rhc->status & IADR_ATTN) != 0) + set_interrupt(rhc->devnum, rhc->status); +} + +void rh_error(struct rh_if *rhc) +{ + if (rhc->imode == 2) + rhc->status |= RH20_DR_EXC; +} + +/* Decrement block count for RH20, nop for RH10 */ +int rh_blkend(struct rh_if *rhc) +{ +#if KL + if (rhc->imode == 2) { +//fprintf(stderr, "RH blkend %o\n\r", rhc->cia); + rhc->cia = (rhc->cia + 1) & 01777; + if (rhc->cia == 0) { + rhc->status |= RH20_XEND; + return 1; + } + } +#endif + return 0; +} + +/* Set an IRQ for a DF10 device */ +void rh_setirq(struct rh_if *rhc) { + rhc->status |= PI_ENABLE; + set_interrupt(rhc->devnum, rhc->status); +} + +/* Generate the DF10 complete word */ +void rh_writecw(struct rh_if *rhc, int nxm) { + uint64 wrd1; +#if KL + if (rhc->imode == 2) { + uint32 chan = (rhc->devnum - 0540); + int wc = ((rhc->wcr ^ RH20_WMASK) + 1) & RH20_WMASK; + rhc->status |= RH20_CHAN_RDY; + rhc->status &= ~(RH20_PCR_FULL); + if (wc != 0 || (rhc->status & RH20_XEND) == 0 || + (rhc->ptcr & BIT10) != 0 || nxm) { + uint64 wrd2; + wrd1 = SMASK|(uint64)(rhc->ccw); + if ((rhc->ptcr & BIT10) == 0 || (rhc->status & RH20_DR_EXC) != 0) + return; + if (nxm) { + wrd1 |= RH20_NXM_ERR; + rhc->status |= RH20_CHAN_ERR; + } + if (wc != 0) { + wrd1 |= RH20_NOT_WC0; + if (rhc->status & RH20_XEND) { + wrd1 |= RH20_LONG_STS; + if ((rhc->ptcr & 070) == 060) { /* Write command */ + rhc->status |= RH20_LONG_WC|RH20_CHAN_ERR; + } + } + } else if ((rhc->status & RH20_XEND) == 0) { + wrd1 |= RH20_SHRT_STS; + if ((rhc->ptcr & 070) == 060) { /* Write command */ + rhc->status |= RH20_SHRT_WC|RH20_CHAN_ERR; + } + } + /* No error and not storing */ + if ((rhc->status & RH20_CHAN_ERR) == 0 && (rhc->ptcr & BIT10) == 0) + return; + wrd1 |= RH20_NADR_PAR; + wrd2 = ((uint64)rhc->cop << 33) | (((uint64)wc) << CSHIFT) | + ((uint64)(rhc->cda) & AMASK); + (void)Mem_write_word(chan+1, &wrd1, 1); + (void)Mem_write_word(chan+2, &wrd2, 1); +//fprintf(stderr, "RH20 final %012llo %012llo %06o\n\r", wrd1, wrd2, wc); + } + return; + } +#endif + if (nxm) + rhc->status |= CXR_NXM; + rhc->status |= CCW_COMP_1; + if (rhc->wcr != 0) + rhc->cda++; + wrd1 = ((uint64)(rhc->ccw & WMASK) << CSHIFT) | ((uint64)(rhc->cda) & AMASK); + (void)Mem_write_word(rhc->cia|1, &wrd1, 0); +} + +/* Finish off a DF10 transfer */ +void rh_finish_op(struct rh_if *rhc, int nxm) { +#if KL + if (rhc->imode != 2) +#endif + rhc->status &= ~BUSY; + rh_writecw(rhc, nxm); + rh_setirq(rhc); +#if KL + if (rhc->imode == 2 && + (rhc->status & (RH20_SCR_FULL|RH20_PCR_FULL)) == (RH20_SCR_FULL) && + (rhc->status & (RH20_DR_EXC|RH20_CHAN_ERR)) == 0) + rh20_setup(rhc); +#endif +} + +#if KL +/* Set up for a RH20 transfer */ +void rh20_setup(struct rh_if *rhc) +{ + DEVICE *dptr = NULL; + int reg; + + for (reg = 0; rh[reg].dev_num != 0; reg++) { + if (rh[reg].rh == rhc) { + dptr = rh[reg].dev; + break; + } + } + if (dptr == 0) + return; + rhc->pbar = rhc->sbar; + rhc->ptcr = rhc->stcr; + /* Read drive status */ + rhc->drive = (rhc->ptcr >> 18) & 07; + rhc->status &= ~(RH20_DATA_OVR|RH20_CHAN_RDY|RH20_DR_RESP|RH20_CHAN_ERR|RH20_SHRT_WC|\ + RH20_LONG_WC|RH20_DR_EXC|RH20_SCR_FULL|PI_ENABLE|RH20_XEND); + rhc->status |= RH20_PCR_FULL; + if (rhc->status & RH20_SBAR) { + rhc->drive = (rhc->pbar >> 18) & 07; + if (rhc->dev_write != NULL) + rhc->dev_write(dptr, rhc, 5, (rhc->pbar & 0177777)); + rhc->status &= ~RH20_SBAR; + } + if (rhc->ptcr & BIT7) { /* If RCPL reset I/O pointers */ + rhc->ccw = eb_ptr + (rhc->devnum - 0540); + rhc->wcr = 0; + } + /* Hold block count in cia */ + rhc->drive = (rhc->ptcr >> 18) & 07; + rhc->cia = (rhc->ptcr >> 6) & 01777; + if (rhc->dev_write != NULL) + rhc->dev_write(dptr, rhc, 0, (rhc->ptcr & 077)); + rhc->cop = 0; + rhc->wcr = 0; + rhc->status &= ~RH20_CHAN_RDY; +//fprintf(stderr, "RH setup %06o %06o %o\n\r", rhc->ptcr, rhc->ccw, rhc->cia); +} +#endif + +/* Setup for a DF10 transfer */ +void rh_setup(struct rh_if *rhc, uint32 addr) +{ + rhc->cia = addr & ICWA; + rhc->ccw = rhc->cia; + rhc->wcr = 0; + rhc->status |= BUSY; +} + + +/* Fetch the next IO control word */ +int rh_fetch(struct rh_if *rhc) { + uint64 data; + int reg; + DEVICE *dptr = NULL; + + for (reg = 0; rh[reg].dev_num != 0; reg++) { + if (rh[reg].rh == rhc) { + dptr = rh[reg].dev; + break; + } + } +#if KL + if (rhc->imode == 2 && (rhc->cop & 2) != 0) { + return 0; + } +#endif + if (Mem_read_word(rhc->ccw, &data, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + sim_debug(DEBUG_EXP, dptr, "%s fetch %06o %012llo\n\r", dptr->name, rhc->ccw, data); +#if KL + if (rhc->imode == 2) { + while((data & RH20_XFER) == 0) { + rhc->ccw = (uint32)(data & AMASK); + if ((data & (BIT1|BIT2)) == 0) { + return 0; + } + if (Mem_read_word(rhc->ccw, &data, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + sim_debug(DEBUG_EXP, dptr, "%s fetch2 %06o %012llo\n\r", dptr->name, rhc->ccw, data); +//fprintf(stderr, "RH20 fetch2 %06o %012llo\n\r", rhc->ccw, data); + } + rhc->wcr = (((data >> CSHIFT) & RH20_WMASK) ^ WMASK) + 1; + rhc->cda = (data & AMASK); + rhc->cop = (data >> 33) & 07; + rhc->ccw = (uint32)((rhc->ccw + 1) & AMASK); + return 1; + } +#endif + while((data & (WMASK << CSHIFT)) == 0) { + if ((data & AMASK) == 0 || (uint32)(data & AMASK) == rhc->ccw) { + rh_finish_op(rhc, 0); + return 0; + } + rhc->ccw = (uint32)(data & AMASK); + if (Mem_read_word(rhc->ccw, &data, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + sim_debug(DEBUG_EXP, dptr, "%s fetch2 %06o %012llo\n\r", dptr->name, rhc->ccw, data); + } + rhc->wcr = (uint32)((data >> CSHIFT) & WMASK); + rhc->cda = (uint32)(data & AMASK); + rhc->ccw = (uint32)((rhc->ccw + 1) & AMASK); + return 1; +} + +/* Read next word */ +int rh_read(struct rh_if *rhc) { + uint64 data; + if (rhc->wcr == 0) { + if (!rh_fetch(rhc)) + return 0; + } + rhc->wcr = (uint32)((rhc->wcr + 1) & WMASK); + if (rhc->cda != 0) { + if (rhc->cda > MEMSIZE) { + rh_finish_op(rhc, 1); + return 0; + } +#if KL + if (rhc->imode == 2) { + if (Mem_read_word(rhc->cda, &data, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + if (rhc->cop & 01) + rhc->cda = (uint32)((rhc->cda - 1) & AMASK); + else + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + } else { + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + if (Mem_read_word(rhc->cda, &data, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + } +#else + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + if (Mem_read_word(rhc->cda, &data, 0)) { + rh_finish_op(rhc, 1); + return 0; + } +#endif + } else { + data = 0; + } + rhc->buf = data; + if (rhc->wcr == 0) { + return rh_fetch(rhc); + } + return 1; +} + +/* Write next word */ +int rh_write(struct rh_if *rhc) { + if (rhc->wcr == 0) { + if (!rh_fetch(rhc)) + return 0; + } + rhc->wcr = (uint32)((rhc->wcr + 1) & WMASK); + if (rhc->cda != 0) { + if (rhc->cda > MEMSIZE) { + rh_finish_op(rhc, 1); + return 0; + } +#if KL + if (rhc->imode == 2) { + if (Mem_write_word(rhc->cda, &rhc->buf, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + if (rhc->cop & 01) + rhc->cda = (uint32)((rhc->cda - 1) & AMASK); + else + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + } else { + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + if (Mem_write_word(rhc->cda, &rhc->buf, 0)) { + rh_finish_op(rhc, 1); + return 0; + } + } +#else + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + if (Mem_write_word(rhc->cda, &rhc->buf, 0)) { + rh_finish_op(rhc, 1); + return 0; + } +#endif + } + if (rhc->wcr == 0) { + return rh_fetch(rhc); + } + return 1; +} + diff --git a/PDP10/kx10_rp.c b/PDP10/kx10_rp.c index 29ec6b4..4512573 100644 --- a/PDP10/kx10_rp.c +++ b/PDP10/kx10_rp.c @@ -1,6 +1,6 @@ /* ka10_rp.c: Dec RH10 RP04/5/6 - Copyright (c) 2013-2017, Richard Cornwell + Copyright (c) 2013-2019, Richard Cornwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -32,7 +32,6 @@ #define CLR_BUF(u) u->hwmark = 0xFFFFFFFF #define RP_NUMWD 128 /* 36bit words/sec */ -#define RP_DEVNUM 0270 /* First device number */ #define NUM_UNITS_RP 8 /* Flags in the unit flags word */ @@ -45,71 +44,13 @@ #define DTYPE(x) (((x) & UNIT_M_DTYPE) << UNIT_V_DTYPE) #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ -#define CNTRL_V_CTYPE (UNIT_V_UF + 4) -#define CNTRL_M_CTYPE 7 -#define GET_CNTRL(x) (((x) >> CNTRL_V_CTYPE) & CNTRL_M_CTYPE) -#define CNTRL(x) (((x) & CNTRL_M_CTYPE) << CNTRL_V_CTYPE) /* Parameters in the unit descriptor */ - -/* CONI Flags */ -#define IADR_ATTN 0000000000040LL /* Interrupt on attention */ -#define IARD_RAE 0000000000100LL /* Interrupt on register access error */ -#define DIB_CBOV 0000000000200LL /* Control bus overrun */ -#define CXR_PS_FAIL 0000000002000LL /* Power supply fail (not implemented) */ -#define CXR_ILC 0000000004000LL /* Illegal function code */ -#define CR_DRE 0000000010000LL /* Or Data and Control Timeout */ -#define DTC_OVER 0000000020000LL /* DF10 did not supply word on time (not implemented) */ -#define CCW_COMP_1 0000000040000LL /* Control word written. */ -#define CXR_CHAN_ER 0000000100000LL /* Channel Error */ -#define CXR_EXC 0000000200000LL /* Error in drive transfer */ -#define CXR_DBPE 0000000400000LL /* Device Parity error (not implemented) */ -#define CXR_NXM 0000001000000LL /* Channel non-existent memory (not implemented) */ -#define CXR_CWPE 0000002000000LL /* Channel Control word parity error (not implemented) */ -#define CXR_CDPE 0000004000000LL /* Channel Data Parity Error (not implemented) */ -#define CXR_SD_RAE 0000200000000LL /* Register access error */ -#define CXR_ILFC 0000400000000LL /* Illegal CXR function code */ -#define B22_FLAG 0004000000000LL /* 22 bit channel */ -#define CC_CHAN_PLS 0010000000000LL /* Channel transfer pulse (not implemented) */ -#define CC_CHAN_ACT 0020000000000LL /* Channel in use */ -#define CC_INH 0040000000000LL /* Disconnect channel */ -#define CB_FULL 0200000000000LL /* Set when channel buffer is full (not implemented) */ -#define AR_FULL 0400000000000LL /* Set when AR is full (not implemented) */ - -/* CONO Flags */ -#define ATTN_EN 0000000000040LL /* enable attention interrupt. */ -#define REA_EN 0000000000100LL /* enable register error interrupt */ -#define CBOV_CLR 0000000000200LL /* Clear CBOV */ -#define CONT_RESET 0000000002000LL /* Clear All error bits */ -#define ILC_CLR 0000000004000LL /* Clear ILC and SD RAE */ -#define DRE_CLR 0000000010000LL /* Clear CR_CBTO and CR_DBTO */ -#define OVER_CLR 0000000020000LL /* Clear DTC overrun */ -#define WRT_CW 0000000040000LL /* Write control word */ -#define CHN_CLR 0000000100000LL /* Clear Channel Error */ -#define DR_EXC_CLR 0000000200000LL /* Clear DR_EXC */ -#define DBPE_CLR 0000000400000LL /* Clear CXR_DBPE */ - -/* DATAO/DATAI */ -#define CR_REG 0770000000000LL /* Register number */ -#define LOAD_REG 0004000000000LL /* Load register */ -#define CR_MAINT_MODE 0000100000000LL /* Maint mode... not implemented */ -#define CR_DRIVE 0000007000000LL -#define CR_GEN_EVD 0000000400000LL /* Enable Parity */ -#define CR_DXES 0000000200000LL /* Disable DXES errors */ -#define CR_INAD 0000000077600LL -#define CR_WTEVM 0000000000100LL /* Verify Parity */ -#define CR_FUNC 0000000000076LL -#define CR_GO 0000000000001LL - -#define IRQ_VECT 0000000000177LL /* Interupt vector */ -#define IRQ_KI10 0000002000000LL -#define IRQ_KA10 0000001000000LL - #define CMD u3 /* u3 low */ /* RPC - 00 - control */ -#define CS1_GO CR_GO /* go */ +#define CS1_GO 1 /* go */ #define CS1_V_FNC 1 /* function pos */ #define CS1_M_FNC 037 /* function mask */ #define CS1_FNC (CS1_M_FNC << CS1_V_FNC) @@ -191,7 +132,7 @@ /* RPDT - 06 - drive type */ /* RPLA - 07 - look ahead register */ - +#define LA_REG us9 #define LA_V_SC 6 /* sector pos */ /* RPER2 - 10 - error status 2 - drive unsafe conditions - unimplemented */ @@ -283,21 +224,11 @@ struct drvtyp rp_drv_tab[] = { }; -struct df10 rp_df10[NUM_DEVS_RP]; -int rp_xfer_drive[NUM_DEVS_RP]; -uint64 rp_buf[NUM_DEVS_RP][RP_NUMWD]; -int rp_reg[NUM_DEVS_RP]; -int rp_ivect[NUM_DEVS_RP]; -int rp_imode[NUM_DEVS_RP]; -int rp_drive[NUM_DEVS_RP]; -int rp_rae[NUM_DEVS_RP]; -int rp_attn[NUM_DEVS_RP]; -extern int readin_flag; - t_stat rp_devio(uint32 dev, uint64 *data); int rp_devirq(uint32 dev, int addr); -void rp_write(int ctlr, int unit, int reg, uint32 data); -uint32 rp_read(int ctlr, int unit, int reg); +void rp_write(DEVICE *dptr, struct rh_if *rh, int reg, uint32 data); +uint32 rp_read(DEVICE *dptr, struct rh_if *rh, int reg); +void rp_rst(DEVICE *dptr); t_stat rp_svc(UNIT *); t_stat rp_boot(int32, DEVICE *); void rp_ini(UNIT *, t_bool); @@ -308,92 +239,107 @@ t_stat rp_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat rp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); const char *rp_description (DEVICE *dptr); +uint64 rp_buf[NUM_DEVS_RP][RP_NUMWD]; UNIT rp_unit[] = { /* Controller 1 */ { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(0), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(0), RP06_SIZE) }, #if (NUM_DEVS_RP > 1) /* Controller 2 */ { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(1), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(1), RP06_SIZE) }, #if (NUM_DEVS_RP > 2) /* Controller 3 */ { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(2), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(2), RP06_SIZE) }, #if (NUM_DEVS_RP > 3) /* Controller 4 */ { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL(3), RP06_SIZE) }, + UNIT_ROABLE+DTYPE(RP06_DTYPE)+CNTRL_RH(3), RP06_SIZE) }, #endif #endif #endif }; +struct rh_if rp_rh[NUM_DEVS_RP] = { + { &rp_write, &rp_read, &rp_rst}, + { &rp_write, &rp_read, &rp_rst}, + { &rp_write, &rp_read, &rp_rst}, + { &rp_write, &rp_read, &rp_rst} +}; + DIB rp_dib[] = { - {RH10_DEV, 1, &rp_devio, &rp_devirq}, - {RH10_DEV, 1, &rp_devio, &rp_devirq}, - {RH10_DEV, 1, &rp_devio, &rp_devirq}, - {RH10_DEV, 1, &rp_devio, &rp_devirq}}; + {RH10_DEV, 1, &rh_devio, &rh_devirq, &rp_rh[0]}, + {RH10_DEV, 1, &rh_devio, &rh_devirq, &rp_rh[1]}, + {RH10_DEV, 1, &rh_devio, &rh_devirq, &rp_rh[2]}, + {RH10_DEV, 1, &rh_devio, &rh_devirq, &rp_rh[3]}}; + MTAB rp_mod[] = { +#if KL + {MTAB_XTD|MTAB_VDV, TYPE_RH10, NULL, "RH10", &rh_set_type, NULL, + NULL, "Sets controller to RH10" }, + {MTAB_XTD|MTAB_VDV, TYPE_RH20, "RH20", "RH20", &rh_set_type, &rh_show_type, + NULL, "Sets controller to RH20"}, +#endif {UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL}, {UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL}, {UNIT_DTYPE, (RP07_DTYPE << UNIT_V_DTYPE), "RP07", "RP07", &rp_set_type }, @@ -403,23 +349,20 @@ MTAB rp_mod[] = { }; REG rpa_reg[] = { - {ORDATA(IVECT, rp_ivect[0], 18)}, - {FLDATA(IMODE, rp_imode[0], 0)}, - {ORDATA(XFER, rp_xfer_drive[0], 3), REG_HRO}, - {ORDATA(DRIVE, rp_drive[0], 3), REG_HRO}, - {ORDATA(REG, rp_reg[0], 6), REG_RO}, - {ORDATA(RAE, rp_rae[0], 8), REG_RO}, - {ORDATA(ATTN, rp_attn[0], 8), REG_RO}, - {FLDATA(READIN, readin_flag, 0), REG_HRO}, - {ORDATA(STATUS, rp_df10[0].status, 18), REG_RO}, - {ORDATA(CIA, rp_df10[0].cia, 18)}, - {ORDATA(CCW, rp_df10[0].ccw, 18)}, - {ORDATA(WCR, rp_df10[0].wcr, 18)}, - {ORDATA(CDA, rp_df10[0].cda, 18)}, - {ORDATA(DEVNUM, rp_df10[0].devnum, 9), REG_HRO}, - {ORDATA(BUF, rp_df10[0].buf, 36), REG_HRO}, - {ORDATA(NXM, rp_df10[0].nxmerr, 8), REG_HRO}, - {ORDATA(COMP, rp_df10[0].ccw_comp, 8), REG_HRO}, + {ORDATA(IVECT, rp_rh[0].ivect, 18)}, + {FLDATA(IMODE, rp_rh[0].imode, 0)}, + {ORDATA(XFER, rp_rh[0].xfer_drive, 3), REG_HRO}, + {ORDATA(DRIVE, rp_rh[0].drive, 3), REG_HRO}, + {ORDATA(REG, rp_rh[0].reg, 6), REG_RO}, + {ORDATA(RAE, rp_rh[0].rae, 8), REG_RO}, + {ORDATA(ATTN, rp_rh[0].attn, 8), REG_RO}, + {ORDATA(STATUS, rp_rh[0].status, 18), REG_RO}, + {ORDATA(CIA, rp_rh[0].cia, 18)}, + {ORDATA(CCW, rp_rh[0].ccw, 18)}, + {ORDATA(WCR, rp_rh[0].wcr, 18)}, + {ORDATA(CDA, rp_rh[0].cda, 18)}, + {ORDATA(DEVNUM, rp_rh[0].devnum, 9), REG_HRO}, + {ORDATA(BUF, rp_rh[0].buf, 36), REG_HRO}, {BRDATA(BUFF, &rp_buf[0][0], 16, 64, RP_NUMWD), REG_HRO}, {0} }; @@ -434,22 +377,20 @@ DEVICE rpa_dev = { #if (NUM_DEVS_RP > 1) REG rpb_reg[] = { - {ORDATA(IVECT, rp_ivect[1], 18)}, - {FLDATA(IMODE, rp_imode[1], 0)}, - {ORDATA(XFER, rp_xfer_drive[1], 3), REG_HRO}, - {ORDATA(DRIVE, rp_drive[1], 3), REG_HRO}, - {ORDATA(REG, rp_reg[1], 6), REG_RO}, - {ORDATA(RAE, rp_rae[1], 8), REG_RO}, - {ORDATA(ATTN, rp_attn[1], 8), REG_RO}, - {ORDATA(STATUS, rp_df10[1].status, 18), REG_RO}, - {ORDATA(CIA, rp_df10[1].cia, 18)}, - {ORDATA(CCW, rp_df10[1].ccw, 18)}, - {ORDATA(WCR, rp_df10[1].wcr, 18)}, - {ORDATA(CDA, rp_df10[1].cda, 18)}, - {ORDATA(DEVNUM, rp_df10[1].devnum, 9), REG_HRO}, - {ORDATA(BUF, rp_df10[1].buf, 36), REG_HRO}, - {ORDATA(NXM, rp_df10[1].nxmerr, 8), REG_HRO}, - {ORDATA(COMP, rp_df10[1].ccw_comp, 8), REG_HRO}, + {ORDATA(IVECT, rp_rh[1].ivect, 18)}, + {FLDATA(IMODE, rp_rh[1].imode, 0)}, + {ORDATA(XFER, rp_rh[1].xfer_drive, 3), REG_HRO}, + {ORDATA(DRIVE, rp_rh[1].drive, 3), REG_HRO}, + {ORDATA(REG, rp_rh[1].reg, 6), REG_RO}, + {ORDATA(RAE, rp_rh[1].rae, 8), REG_RO}, + {ORDATA(ATTN, rp_rh[1].attn, 8), REG_RO}, + {ORDATA(STATUS, rp_rh[1].status, 18), REG_RO}, + {ORDATA(CIA, rp_rh[1].cia, 18)}, + {ORDATA(CCW, rp_rh[1].ccw, 18)}, + {ORDATA(WCR, rp_rh[1].wcr, 18)}, + {ORDATA(CDA, rp_rh[1].cda, 18)}, + {ORDATA(DEVNUM, rp_rh[1].devnum, 9), REG_HRO}, + {ORDATA(BUF, rp_rh[1].buf, 36), REG_HRO}, {BRDATA(BUFF, &rp_buf[1][0], 16, 64, RP_NUMWD), REG_HRO}, {0} }; @@ -464,22 +405,20 @@ DEVICE rpb_dev = { #if (NUM_DEVS_RP > 2) REG rpc_reg[] = { - {ORDATA(IVECT, rp_ivect[2], 18)}, - {FLDATA(IMODE, rp_imode[2], 0)}, - {ORDATA(XFER, rp_xfer_drive[2], 3), REG_HRO}, - {ORDATA(DRIVE, rp_drive[2], 3), REG_HRO}, - {ORDATA(REG, rp_reg[2], 6), REG_RO}, - {ORDATA(RAE, rp_rae[2], 8), REG_RO}, - {ORDATA(ATTN, rp_attn[2], 8), REG_RO}, - {ORDATA(STATUS, rp_df10[2].status, 18), REG_RO}, - {ORDATA(CIA, rp_df10[2].cia, 18)}, - {ORDATA(CCW, rp_df10[2].ccw, 18)}, - {ORDATA(WCR, rp_df10[2].wcr, 18)}, - {ORDATA(CDA, rp_df10[2].cda, 18)}, - {ORDATA(DEVNUM, rp_df10[2].devnum, 9), REG_HRO}, - {ORDATA(BUF, rp_df10[2].buf, 36), REG_HRO}, - {ORDATA(NXM, rp_df10[2].nxmerr, 8), REG_HRO}, - {ORDATA(COMP, rp_df10[2].ccw_comp, 8), REG_HRO}, + {ORDATA(IVECT, rp_rh[2].ivect, 18)}, + {FLDATA(IMODE, rp_rh[2].imode, 0)}, + {ORDATA(XFER, rp_rh[2].xfer_drive, 3), REG_HRO}, + {ORDATA(DRIVE, rp_rh[2].drive, 3), REG_HRO}, + {ORDATA(REG, rp_rh[2].reg, 6), REG_RO}, + {ORDATA(RAE, rp_rh[2].rae, 8), REG_RO}, + {ORDATA(ATTN, rp_rh[2].attn, 8), REG_RO}, + {ORDATA(STATUS, rp_rh[2].status, 18), REG_RO}, + {ORDATA(CIA, rp_rh[2].cia, 18)}, + {ORDATA(CCW, rp_rh[2].ccw, 18)}, + {ORDATA(WCR, rp_rh[2].wcr, 18)}, + {ORDATA(CDA, rp_rh[2].cda, 18)}, + {ORDATA(DEVNUM, rp_rh[2].devnum, 9), REG_HRO}, + {ORDATA(BUF, rp_rh[2].buf, 36), REG_HRO}, {BRDATA(BUFF, &rp_buf[2][0], 16, 64, RP_NUMWD), REG_HRO}, {0} }; @@ -494,22 +433,20 @@ DEVICE rpc_dev = { #if (NUM_DEVS_RP > 3) REG rpd_reg[] = { - {ORDATA(IVECT, rp_ivect[3], 18)}, - {FLDATA(IMODE, rp_imode[3], 0)}, - {ORDATA(XFER, rp_xfer_drive[3], 3), REG_HRO}, - {ORDATA(DRIVE, rp_drive[3], 3), REG_HRO}, - {ORDATA(REG, rp_reg[3], 6), REG_RO}, - {ORDATA(RAE, rp_rae[3], 8), REG_RO}, - {ORDATA(ATTN, rp_attn[3], 8), REG_RO}, - {ORDATA(STATUS, rp_df10[3].status, 18), REG_RO}, - {ORDATA(CIA, rp_df10[3].cia, 18)}, - {ORDATA(CCW, rp_df10[3].ccw, 18)}, - {ORDATA(WCR, rp_df10[3].wcr, 18)}, - {ORDATA(CDA, rp_df10[3].cda, 18)}, - {ORDATA(DEVNUM, rp_df10[3].devnum, 9), REG_HRO}, - {ORDATA(BUF, rp_df10[3].buf, 36), REG_HRO}, - {ORDATA(NXM, rp_df10[3].nxmerr, 8), REG_HRO}, - {ORDATA(COMP, rp_df10[3].ccw_comp, 8), REG_HRO}, + {ORDATA(IVECT, rp_rh[3].ivect, 18)}, + {FLDATA(IMODE, rp_rh[3].imode, 0)}, + {ORDATA(XFER, rp_rh[3].xfer_drive, 3), REG_HRO}, + {ORDATA(DRIVE, rp_rh[3].drive, 3), REG_HRO}, + {ORDATA(REG, rp_rh[3].reg, 6), REG_RO}, + {ORDATA(RAE, rp_rh[3].rae, 8), REG_RO}, + {ORDATA(ATTN, rp_rh[3].attn, 8), REG_RO}, + {ORDATA(STATUS, rp_rh[3].status, 18), REG_RO}, + {ORDATA(CIA, rp_rh[3].cia, 18)}, + {ORDATA(CCW, rp_rh[3].ccw, 18)}, + {ORDATA(WCR, rp_rh[3].wcr, 18)}, + {ORDATA(CDA, rp_rh[3].cda, 18)}, + {ORDATA(DEVNUM, rp_rh[3].devnum, 9), REG_HRO}, + {ORDATA(BUF, rp_rh[3].buf, 36), REG_HRO}, {BRDATA(BUFF, &rp_buf[3][0], 16, 64, RP_NUMWD), REG_HRO}, {0} }; @@ -540,214 +477,48 @@ DEVICE *rp_devs[] = { }; -t_stat rp_devio(uint32 dev, uint64 *data) { - int ctlr = -1; - DEVICE *dptr = NULL; - struct df10 *df10; - int drive; - - for (drive = 0; rh[drive].dev_num != 0; drive++) { - if (rh[drive].dev_num == (dev & 0774)) { - dptr = rh[drive].dev; - break; - } - } - if (dptr == NULL) - return SCPE_OK; - ctlr = GET_CNTRL(dptr->units[0].flags); - df10 = &rp_df10[ctlr]; - df10->devnum = dev; - switch(dev & 3) { - case CONI: - *data = df10->status & ~(IADR_ATTN|IARD_RAE); - if (rp_attn[ctlr] != 0 && (df10->status & IADR_ATTN)) - *data |= IADR_ATTN; - if (rp_rae[ctlr] != 0 && (df10->status & IARD_RAE)) - *data |= IARD_RAE; -#if KI_22BIT - *data |= B22_FLAG; -#endif - sim_debug(DEBUG_CONI, dptr, "RP %03o CONI %06o PC=%o %o\n", - dev, (uint32)*data, PC, rp_attn[ctlr]); - return SCPE_OK; - - case CONO: - clr_interrupt(dev); - df10->status &= ~(07LL|IADR_ATTN|IARD_RAE); - df10->status |= *data & (07LL|IADR_ATTN|IARD_RAE); - /* Clear flags */ - if (*data & CONT_RESET) { - UNIT *uptr=dptr->units; - for(drive = 0; drive < NUM_UNITS_RP; drive++, uptr++) { - uptr->CMD &= DS_MOL|DS_WRL|DS_DPR|DS_DRY|DS_VV|076; - uptr->DA &= 003400177777; - uptr->CCYL &= 0177777; - uptr->ERR2 = 0; - uptr->ERR3 = 0; - } - } - if (*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)) - df10->status &= ~(*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)); - if (*data & OVER_CLR) - df10->status &= ~(DTC_OVER); - if (*data & CBOV_CLR) - df10->status &= ~(DIB_CBOV); - if (*data & CXR_ILC) - df10->status &= ~(CXR_ILFC|CXR_SD_RAE); - if (*data & WRT_CW) - df10_writecw(df10); - if (*data & PI_ENABLE) - df10->status &= ~PI_ENABLE; - if (df10->status & PI_ENABLE) - set_interrupt(dev, df10->status); - if ((df10->status & IADR_ATTN) != 0 && rp_attn[ctlr] != 0) - set_interrupt(dev, df10->status); - sim_debug(DEBUG_CONO, dptr, "RP %03o CONO %06o %d PC=%06o %06o\n", - dev, (uint32)*data, ctlr, PC, df10->status); - return SCPE_OK; - - case DATAI: - *data = 0; - if (df10->status & BUSY && rp_reg[ctlr] != 04) { - df10->status |= CC_CHAN_ACT; - return SCPE_OK; - } - if (rp_reg[ctlr] == 040) { - *data = (uint64)(rp_read(ctlr, rp_drive[ctlr], 0) & 077); - *data |= ((uint64)(df10->cia)) << 6; - *data |= ((uint64)(rp_xfer_drive[ctlr])) << 18; - } else if (rp_reg[ctlr] == 044) { - *data = (uint64)rp_ivect[ctlr]; - if (rp_imode[ctlr]) - *data |= IRQ_KI10; - else - *data |= IRQ_KA10; - } else if (rp_reg[ctlr] == 054) { - *data = (uint64)(rp_rae[ctlr]); - } else if ((rp_reg[ctlr] & 040) == 0) { - int parity; - *data = (uint64)(rp_read(ctlr, rp_drive[ctlr], rp_reg[ctlr]) & 0177777); - parity = (int)((*data >> 8) ^ *data); - parity = (parity >> 4) ^ parity; - parity = (parity >> 2) ^ parity; - parity = ((parity >> 1) ^ parity) & 1; - *data |= ((uint64)(parity ^ 1)) << 17; - *data |= ((uint64)(rp_drive[ctlr])) << 18; - } - *data |= ((uint64)(rp_reg[ctlr])) << 30; - sim_debug(DEBUG_DATAIO, dptr, "RP %03o DATI %012llo, %d %d PC=%06o\n", - dev, *data, ctlr, rp_drive[ctlr], PC); - return SCPE_OK; - - case DATAO: - sim_debug(DEBUG_DATAIO, dptr, "RP %03o DATO %012llo, %d PC=%06o %06o\n", - dev, *data, ctlr, PC, df10->status); - rp_reg[ctlr] = ((int)(*data >> 30)) & 077; - if (rp_reg[ctlr] < 040 && rp_reg[ctlr] != 04) { - rp_drive[ctlr] = (int)(*data >> 18) & 07; - } - if (*data & LOAD_REG) { - if (rp_reg[ctlr] == 040) { - if ((*data & 1) == 0) { - return SCPE_OK; - } - - if (df10->status & BUSY) { - df10->status |= CC_CHAN_ACT; - return SCPE_OK; - } - - df10->status &= ~(1 << df10->ccw_comp); - df10->status &= ~PI_ENABLE; - if (((*data >> 1) & 037) < FNC_XFER) { - df10->status |= CXR_ILC; - df10_setirq(df10); - sim_debug(DEBUG_DATAIO, dptr, - "RP %03o command abort %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, rp_drive[ctlr], PC, df10->status); - return SCPE_OK; - } - /* Start command */ - df10_setup(df10, (uint32)(*data >> 6)); - rp_xfer_drive[ctlr] = (int)(*data >> 18) & 07; - rp_write(ctlr, rp_drive[ctlr], 0, (uint32)(*data & 077)); - sim_debug(DEBUG_DATAIO, dptr, - "RP %03o command %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, rp_drive[ctlr], PC, df10->status); - } else if (rp_reg[ctlr] == 044) { - /* Set KI10 Irq vector */ - rp_ivect[ctlr] = (int)(*data & IRQ_VECT); - rp_imode[ctlr] = (*data & IRQ_KI10) != 0; - } else if (rp_reg[ctlr] == 050) { - ; /* Diagnostic access to mass bus. */ - } else if (rp_reg[ctlr] == 054) { - /* clear flags */ - rp_rae[ctlr] &= ~(*data & 0377); - if (rp_rae[ctlr] == 0) - clr_interrupt(dev); - } else if ((rp_reg[ctlr] & 040) == 0) { - rp_drive[ctlr] = (int)(*data >> 18) & 07; - /* Check if access error */ - if (rp_rae[ctlr] & (1 << rp_drive[ctlr])) { - return SCPE_OK; - } - rp_write(ctlr, rp_drive[ctlr], rp_reg[ctlr] & 037, - (int)(*data & 0777777)); - } - } - return SCPE_OK; - } - return SCPE_OK; /* Unreached */ -} - -/* Handle KI and KL style interrupt vectors */ -int -rp_devirq(uint32 dev, int addr) { - DEVICE *dptr = NULL; - int drive; - - for (drive = 0; rh[drive].dev_num != 0; drive++) { - if (rh[drive].dev_num == (dev & 0774)) { - dptr = rh[drive].dev; - break; - } - } - if (dptr != NULL) { - drive = GET_CNTRL(dptr->units[0].flags); - return (rp_imode[drive] ? rp_ivect[drive] : addr); - } - return addr; +void +rp_rst(DEVICE *dptr) +{ + UNIT *uptr=dptr->units; + int drive; + for(drive = 0; drive < NUM_UNITS_RP; drive++, uptr++) { + uptr->CMD &= DS_MOL|DS_WRL|DS_DPR|DS_DRY|DS_VV|076; + uptr->DA &= 003400177777; + uptr->CCYL &= 0177777; + uptr->ERR2 = 0; + uptr->ERR3 = 0; + } } void -rp_write(int ctlr, int unit, int reg, uint32 data) { +rp_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) { int i; - DEVICE *dptr = rp_devs[ctlr]; + int unit = rhc->drive; UNIT *uptr = &dptr->units[unit]; - struct df10 *df10 = &rp_df10[ctlr]; int dtype = GET_DTYPE(uptr->flags); - if ((uptr->CMD & CR_GO) && reg != 04) { + if ((uptr->CMD & CS1_GO) && reg != 04) { uptr->CMD |= (ER1_RMR << 16)|DS_ERR; return; } switch(reg) { case 000: /* control */ - sim_debug(DEBUG_DETAIL, dptr, "RP%o %d Status=%06o\n", unit, ctlr, uptr->CMD); + sim_debug(DEBUG_DETAIL, dptr, "%s%o Status=%06o\n", dptr->name, unit, uptr->CMD); /* Set if drive not writable */ if (uptr->flags & UNIT_WLK) uptr->CMD |= DS_WRL; /* If drive not ready don't do anything */ if ((uptr->CMD & DS_DRY) == 0) { uptr->CMD |= (ER1_RMR << 16)|DS_ERR; - sim_debug(DEBUG_DETAIL, dptr, "RP%o %d not ready\n", unit, ctlr); + sim_debug(DEBUG_DETAIL, dptr, "%s%o not ready\n", dptr->name, unit); return; } /* Check if GO bit set */ if ((data & 1) == 0) { uptr->CMD &= ~076; uptr->CMD |= data & 076; - sim_debug(DEBUG_DETAIL, dptr, "RP%o %d no go\n", unit, ctlr); + sim_debug(DEBUG_DETAIL, dptr, "%s%o no go\n", dptr->name, unit); return; /* No, nop */ } uptr->CMD &= DS_ATA|DS_VV|DS_DPR|DS_MOL|DS_WRL; @@ -779,16 +550,13 @@ rp_write(int ctlr, int unit, int reg, uint32 data) { if (GET_CY(uptr->DA) >= rp_drv_tab[dtype].cyl || GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { - rp_attn[ctlr] &= ~(1<attn &= ~(1<CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; uptr->CMD &= ~DS_PIP; - df10->status &= ~BUSY; - if ((df10->status & IADR_ATTN) != 0 && rp_attn[ctlr] != 0) - df10_setirq(df10); break; } - uptr->CMD |= CR_GO; + uptr->CMD |= CS1_GO; CLR_BUF(uptr); uptr->DATAPTR = 0; break; @@ -796,14 +564,12 @@ rp_write(int ctlr, int unit, int reg, uint32 data) { case FNC_DCLR: /* drive clear */ uptr->CMD |= DS_DRY; - uptr->CMD &= ~(DS_ATA|CR_GO); + uptr->CMD &= ~(DS_ATA|CS1_GO); uptr->DA &= 003400177777; uptr->CCYL &= 0177777; uptr->ERR2 = 0; uptr->ERR3 = 0; - rp_attn[ctlr] &= ~(1<status & IADR_ATTN) != 0 && rp_attn[ctlr] != 0) - df10_setirq(df10); + rhc->attn &= ~(1<flags & UNIT_ATT) != 0) uptr->CMD |= DS_VV; uptr->CMD |= DS_DRY; - if ((df10->status & IADR_ATTN) != 0 && rp_attn[ctlr] != 0) - df10_setirq(df10); break; default: uptr->CMD |= DS_DRY|DS_ERR|DS_ATA; uptr->CMD |= (ER1_ILF << 16); - rp_attn[ctlr] |= (1<status & IADR_ATTN) != 0 && rp_attn[ctlr] != 0) - df10_setirq(df10); + rhc->attn |= (1<CMD & CR_GO) + if (uptr->CMD & CS1_GO) sim_activate(uptr, 1000); - clr_interrupt(df10->devnum); - if ((df10->status & (IADR_ATTN|BUSY)) == IADR_ATTN && rp_attn[ctlr] != 0) - df10_setirq(df10); - sim_debug(DEBUG_DETAIL, dptr, "RP%o AStatus=%06o\n", unit, uptr->CMD); + sim_debug(DEBUG_DETAIL, dptr, "%s%o AStatus=%06o\n", dptr->name, unit, uptr->CMD); return; case 001: /* status */ break; @@ -849,14 +608,11 @@ rp_write(int ctlr, int unit, int reg, uint32 data) { case 004: /* atten summary */ for (i = 0; i < 8; i++) { if (data & (1<units[i]; + u->CMD &= ~DS_ATA; + rhc->attn &= ~(1<devnum); break; case 005: /* sector/track */ uptr->DA &= 0177777; @@ -892,15 +648,14 @@ rp_write(int ctlr, int unit, int reg, uint32 data) { break; default: uptr->CMD |= (ER1_ILR<<16)|DS_ERR; - rp_rae[ctlr] &= ~(1<rae |= 1 << unit; } } uint32 -rp_read(int ctlr, int unit, int reg) { - DEVICE *dptr = rp_devs[ctlr]; +rp_read(DEVICE *dptr, struct rh_if *rhc, int reg) { + int unit = rhc->drive; UNIT *uptr = &dptr->units[unit]; - struct df10 *df10; uint32 temp = 0; int i; @@ -909,11 +664,10 @@ rp_read(int ctlr, int unit, int reg) { } switch(reg) { case 000: /* control */ - df10 = &rp_df10[ctlr]; temp = uptr->CMD & 076; if (uptr->flags & UNIT_ATT) temp |= CS1_DVA; - if (df10->status & BUSY || uptr->CMD & CR_GO) + if (uptr->CMD & CS1_GO) temp |= CS1_GO; break; case 001: /* status */ @@ -926,7 +680,8 @@ rp_read(int ctlr, int unit, int reg) { break; case 004: /* atten summary */ for (i = 0; i < 8; i++) { - if (rp_unit[(ctlr * 8) + i].CMD & DS_ATA) { + UNIT *u = &dptr->units[i]; + if (u->CMD & DS_ATA) { temp |= 1 << i; } } @@ -947,7 +702,8 @@ rp_read(int ctlr, int unit, int reg) { temp = uptr->CCYL & 0177777; break; case 010: /* serial no */ - temp = (020 * ctlr) + (unit + 1); + i = GET_CNTRL_RH(uptr->flags); + temp = (020 * i) + (unit + 1); break; case 014: /* error register 2 */ temp = uptr->ERR2; @@ -956,12 +712,16 @@ rp_read(int ctlr, int unit, int reg) { temp = uptr->ERR3; break; case 007: /* look ahead */ + uptr->LA_REG += 0100; + uptr->LA_REG &= 07700; + temp = uptr->LA_REG; + break; case 016: /* ecc position */ case 017: /* ecc pattern */ break; default: uptr->CMD |= (ER1_ILR<<16); - rp_rae[ctlr] &= ~(1<rae |= 1 << unit; } return temp; } @@ -969,34 +729,35 @@ rp_read(int ctlr, int unit, int reg) { t_stat rp_svc (UNIT *uptr) { - int dtype = GET_DTYPE(uptr->flags); - int ctlr = GET_CNTRL(uptr->flags); - int unit; - DEVICE *dptr; - struct df10 *df; - int cyl = GET_CY(uptr->DA); - int diff, da; - t_stat r; + int dtype = GET_DTYPE(uptr->flags); + int ctlr = GET_CNTRL_RH(uptr->flags); + int cyl = GET_CY(uptr->DA); + int unit; + DEVICE *dptr; + struct rh_if *rhc; + int diff, da; + int sts; - /* Find dptr, and df10 */ dptr = rp_devs[ctlr]; + rhc = &rp_rh[ctlr]; unit = uptr - dptr->units; - df = &rp_df10[ctlr]; if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ uptr->CMD |= (ER1_UNS << 16) | DS_ATA|DS_ERR; /* set drive error */ if (GET_FNC(uptr->CMD) >= FNC_XFER) { /* xfr? set done */ - df->status &= ~BUSY; - df10_setirq(df); + rh_setirq(rhc); + } else { + rh_setattn(rhc, unit); } return (SCPE_OK); } /* Check if seeking */ if (uptr->CMD & DS_PIP) { - sim_debug(DEBUG_DETAIL, dptr, "RP%o seek %d %d\n", unit, cyl, uptr->CCYL); + sim_debug(DEBUG_DETAIL, dptr, "%s%o seek %d %d\n", dptr->name, unit, cyl, uptr->CCYL); if (cyl >= rp_drv_tab[dtype].cyl) { uptr->CMD &= ~DS_PIP; uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; + rh_setattn(rhc, unit); } diff = cyl - (uptr->CCYL & 01777); if (diff < 0) { @@ -1048,31 +809,27 @@ t_stat rp_svc (UNIT *uptr) if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) uptr->CMD |= (ER1_IAE << 16)|DS_ERR; - rp_attn[ctlr] |= 1<CMD |= DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - if ((df->status & (IADR_ATTN|BUSY)) == IADR_ATTN) - df10_setirq(df); - sim_debug(DEBUG_DETAIL, dptr, "RP%o seekdone %d %o\n", unit, cyl, uptr->CMD); + uptr->CMD &= ~CS1_GO; + rh_setattn(rhc, unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o seekdone %d %o\n", dptr->name, unit, cyl, uptr->CMD); break; case FNC_SEARCH: /* search */ if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) uptr->CMD |= (ER1_IAE << 16)|DS_ERR; - rp_attn[ctlr] |= 1<CMD |= DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - if ((df->status & (IADR_ATTN|BUSY)) == IADR_ATTN) - df10_setirq(df); - sim_debug(DEBUG_DETAIL, dptr, "RP%o searchdone %d %o\n", unit, cyl, uptr->CMD); + uptr->CMD &= ~CS1_GO; + rh_setattn(rhc, unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o searchdone %d %o\n", dptr->name, unit, cyl, uptr->CMD); break; case FNC_READ: /* read */ case FNC_READH: /* read w/ headers */ case FNC_WCHK: /* write check */ if (uptr->CMD & DS_ERR) { - sim_debug(DEBUG_DETAIL, dptr, "RP%o read error\n", unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error\n", dptr->name, unit); goto rd_end; } @@ -1082,12 +839,12 @@ t_stat rp_svc (UNIT *uptr) if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - df10_finish_op(df, 0); - sim_debug(DEBUG_DETAIL, dptr, "RP%o readx done\n", unit); + uptr->CMD &= ~CS1_GO; + rh_finish_op(rhc, 0); + sim_debug(DEBUG_DETAIL, dptr, "%s%o readx done\n", dptr->name, unit); return SCPE_OK; } - sim_debug(DEBUG_DETAIL, dptr, "RP%o read (%d,%d,%d)\n", unit, cyl, + sim_debug(DEBUG_DETAIL, dptr, "%s%o read (%d,%d,%d)\n", dptr->name, unit, cyl, GET_SF(uptr->DA), GET_SC(uptr->DA)); da = GET_DA(uptr->DA, dtype) * RP_NUMWD; (void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET); @@ -1099,24 +856,24 @@ t_stat rp_svc (UNIT *uptr) uptr->DATAPTR = 0; /* On read headers, transfer 2 words to start */ if (GET_FNC(uptr->CMD) == FNC_READH) { - df->buf = (((uint64)cyl) << 18) | + rhc->buf = (((uint64)cyl) << 18) | ((uint64)((GET_SF(uptr->DA) << 8) | GET_SF(uptr->DA))); - sim_debug(DEBUG_DATA, dptr, "RP%o read word h1 %012llo %09o %06o\n", - unit, df->buf, df->cda, df->wcr); - if (df10_write(df) == 0) + sim_debug(DEBUG_DATA, dptr, "%s%o read word h1 %012llo %09o %06o\n", + dptr->name, unit, rhc->buf, rhc->cda, rhc->wcr); + if (rh_write(rhc) == 0) goto rd_end; - df->buf = ((uint64)((020 * ctlr) + (unit + 1)) << 18) | (uint64)(unit); - sim_debug(DEBUG_DATA, dptr, "RP%o read word h2 %012llo %09o %06o\n", - unit, df->buf, df->cda, df->wcr); - if (df10_write(df) == 0) + rhc->buf = ((uint64)((020 * ctlr) + (unit + 1)) << 18) | (uint64)(unit); + sim_debug(DEBUG_DATA, dptr, "%s%o read word h2 %012llo %09o %06o\n", + dptr->name, unit, rhc->buf, rhc->cda, rhc->wcr); + if (rh_write(rhc) == 0) goto rd_end; } } - df->buf = rp_buf[ctlr][uptr->DATAPTR++]; - sim_debug(DEBUG_DATA, dptr, "RP%o read word %d %012llo %09o %06o\n", - unit, uptr->DATAPTR, df->buf, df->cda, df->wcr); - if (df10_write(df)) { + rhc->buf = rp_buf[ctlr][uptr->DATAPTR++]; + sim_debug(DEBUG_DATA, dptr, "%s%o read word %d %012llo %09o %06o\n", + dptr->name, unit, uptr->DATAPTR, rhc->buf, rhc->cda, rhc->wcr); + if (rh_write(rhc)) { if (uptr->DATAPTR == RP_NUMWD) { /* Increment to next sector. Set Last Sector */ uptr->DATAPTR = 0; @@ -1131,14 +888,18 @@ t_stat rp_svc (UNIT *uptr) uptr->CMD |= DS_PIP; } } + if (rh_blkend(rhc)) + goto rd_end; } - sim_activate(uptr, 50); + sim_activate(uptr, 10); } else { rd_end: - sim_debug(DEBUG_DETAIL, dptr, "RP%o read done\n", unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o read done\n", dptr->name, unit); uptr->CMD |= DS_DRY; - uptr->CMD &= ~CR_GO; - df10_finish_op(df, 0); + uptr->CMD &= ~CS1_GO; + if (uptr->DATAPTR == RP_NUMWD) + (void)rh_blkend(rhc); + rh_finish_op(rhc, 0); return SCPE_OK; } break; @@ -1146,7 +907,7 @@ rd_end: case FNC_WRITE: /* write */ case FNC_WRITEH: /* write w/ headers */ if (uptr->CMD & DS_ERR) { - sim_debug(DEBUG_DETAIL, dptr, "RP%o read error\n", unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error\n", dptr->name, unit); goto wr_end; } @@ -1154,41 +915,43 @@ rd_end: if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rp_drv_tab[dtype].surf) { uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - df10_finish_op(df, 0); - sim_debug(DEBUG_DETAIL, dptr, "RP%o writex done\n", unit); + uptr->CMD &= ~CS1_GO; + rh_finish_op(rhc, 0); + sim_debug(DEBUG_DETAIL, dptr, "%s%o writex done\n", dptr->name, unit); return SCPE_OK; } /* On Write headers, transfer 2 words to start */ if (GET_FNC(uptr->CMD) == FNC_WRITEH) { - if (df10_read(df) == 0) + if (rh_read(rhc) == 0) goto wr_end; - sim_debug(DEBUG_DATA, dptr, "RP%o write word h1 %012llo %06o\n", - unit, df->buf, df->wcr); - if (df10_read(df) == 0) + sim_debug(DEBUG_DATA, dptr, "%s%o write word h1 %012llo %06o\n", + dptr->name, unit, rhc->buf, rhc->wcr); + if (rh_read(rhc) == 0) goto wr_end; - sim_debug(DEBUG_DATA, dptr, "RP%o write word h2 %012llo %06o\n", - unit, df->buf, df->wcr); + sim_debug(DEBUG_DATA, dptr, "%s%o write word h2 %012llo %06o\n", + dptr->name, unit, rhc->buf, rhc->wcr); } uptr->DATAPTR = 0; uptr->hwmark = 0; } - r = df10_read(df); - sim_debug(DEBUG_DATA, dptr, "RP%o write word %d %012llo %06o\n", - unit, uptr->DATAPTR, df->buf, df->wcr); - rp_buf[ctlr][uptr->DATAPTR++] = df->buf; - if (r == 0 || uptr->DATAPTR == RP_NUMWD) { + sts = rh_read(rhc); + sim_debug(DEBUG_DATA, dptr, "%s%o write word %d %012llo %06o %06o\n", + dptr->name, unit, uptr->DATAPTR, rhc->buf, rhc->cda, rhc->wcr); + rp_buf[ctlr][uptr->DATAPTR++] = rhc->buf; + if (sts == 0) { while (uptr->DATAPTR < RP_NUMWD) rp_buf[ctlr][uptr->DATAPTR++] = 0; - sim_debug(DEBUG_DETAIL, dptr, "RP%o write (%d,%d,%d)\n", unit, cyl, - GET_SF(uptr->DA), GET_SC(uptr->DA)); + } + if (uptr->DATAPTR == RP_NUMWD) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o write (%d,%d,%d)\n", dptr->name, + unit, cyl, GET_SF(uptr->DA), GET_SC(uptr->DA)); da = GET_DA(uptr->DA, dtype) * RP_NUMWD; (void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET); (void)sim_fwrite (&rp_buf[ctlr][0], sizeof(uint64), RP_NUMWD, uptr->fileref); uptr->DATAPTR = 0; CLR_BUF(uptr); - if (r) { + if (sts) { uptr->DA += 1 << DA_V_SC; if (GET_SC(uptr->DA) >= rp_drv_tab[dtype].sect) { uptr->DA &= (DA_M_SF << DA_V_SF) | (DC_M_CY << DC_V_CY); @@ -1199,16 +962,18 @@ rd_end: uptr->CMD |= DS_PIP; } } - } + } + if (rh_blkend(rhc)) + goto wr_end; } - if (r) { - sim_activate(uptr, 50); + if (sts) { + sim_activate(uptr, 10); } else { wr_end: sim_debug(DEBUG_DETAIL, dptr, "RP%o write done\n", unit); uptr->CMD |= DS_DRY; - uptr->CMD &= ~CR_GO; - df10_finish_op(df, 0); + uptr->CMD &= ~CS1_GO; + rh_finish_op(rhc, 0); return SCPE_OK; } break; @@ -1236,12 +1001,9 @@ rp_reset(DEVICE * rptr) { int ctlr; for (ctlr = 0; ctlr < NUM_DEVS_RP; ctlr++) { - rp_df10[ctlr].devnum = rp_dib[ctlr].dev_num; - rp_df10[ctlr].nxmerr = 19; - rp_df10[ctlr].ccw_comp = 14; - rp_df10[ctlr].status = 0; - rp_attn[ctlr] = 0; - rp_rae[ctlr] = 0; + rp_rh[ctlr].status = 0; + rp_rh[ctlr].attn = 0; + rp_rh[ctlr].rae = 0; } return SCPE_OK; } @@ -1251,19 +1013,31 @@ t_stat rp_boot(int32 unit_num, DEVICE * rptr) { UNIT *uptr = &rptr->units[unit_num]; - int ctlr = GET_CNTRL(uptr->flags); - DEVICE *dptr; - struct df10 *df; + int ctlr = GET_CNTRL_RH(uptr->flags); + struct rh_if *rhc = &rp_rh[ctlr]; + DEVICE *dptr = rp_devs[ctlr]; uint32 addr; uint32 ptr = 0; - uint64 word; int wc; - - df = &rp_df10[ctlr]; - dptr = rp_devs[ctlr]; + uint64 word; +#if KL + int sect; + /* KL does not support readin, so fake it by reading in sectors 4 to 7 */ + /* Possible in future fine boot loader in FE file system */ + addr = (MEMSIZE - 512) & RMASK; + for (sect = 4; sect <= 7; sect++) { + (void)sim_fseek(uptr->fileref, (sect * RP_NUMWD) * sizeof(uint64), SEEK_SET); + (void)sim_fread (&rp_buf[0][0], sizeof(uint64), RP_NUMWD, uptr->fileref); + ptr = 0; + for(wc = RP_NUMWD; wc > 0; wc--) { + word = rp_buf[0][ptr++]; + M[addr++] = word; + } + } + word = (MEMSIZE - 512) & RMASK; +#else (void)sim_fseek(uptr->fileref, 0, SEEK_SET); (void)sim_fread (&rp_buf[0][0], sizeof(uint64), RP_NUMWD, uptr->fileref); - uptr->CMD |= DS_VV; addr = rp_buf[0][ptr] & RMASK; wc = (rp_buf[0][ptr++] >> 18) & RMASK; while (wc != 0) { @@ -1278,11 +1052,12 @@ rp_boot(int32 unit_num, DEVICE * rptr) addr = rp_buf[0][ptr] & RMASK; wc = (rp_buf[0][ptr++] >> 18) & RMASK; word = rp_buf[0][ptr++]; - - rp_reg[ctlr] = 040; - rp_drive[ctlr] = uptr - dptr->units; - df->status |= CCW_COMP_1|PI_ENABLE; +#endif PC = word & RMASK; + uptr->CMD |= DS_VV; + rhc->reg = 040; + rhc->drive = uptr - dptr->units; + rhc->status |= CCW_COMP_1|PI_ENABLE; return SCPE_OK; } @@ -1303,14 +1078,17 @@ t_stat rp_attach (UNIT *uptr, CONST char *cptr) if (rptr == 0) return SCPE_OK; dib = (DIB *) rptr->ctxt; - ctlr = dib->dev_num & 014; + for (ctlr = 0; rh[ctlr].dev_num != 0; ctlr++) { + if (rh[ctlr].dev == rptr) + break; + } uptr->DA = 0; uptr->CMD &= ~DS_VV; uptr->CMD |= DS_DPR|DS_MOL|DS_DRY; if (uptr->flags & UNIT_WLK) uptr->CMD |= DS_WRL; - rp_df10[ctlr].status |= PI_ENABLE; - set_interrupt(dib->dev_num, rp_df10[ctlr].status); + rp_rh[ctlr].status |= PI_ENABLE; + set_interrupt(dib->dev_num, rp_rh[ctlr].status); return SCPE_OK; } diff --git a/PDP10/kx10_rs.c b/PDP10/kx10_rs.c index d550c27..d334edc 100644 --- a/PDP10/kx10_rs.c +++ b/PDP10/kx10_rs.c @@ -1,6 +1,6 @@ /* ka10_rs.c: Dec RH10 RS04 - Copyright (c) 2017, Richard Cornwell + Copyright (c) 2017-2019, Richard Cornwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,8 @@ #endif #if (NUM_DEVS_RS > 0) +#define BUF_EMPTY(u) (u->hwmark == 0xFFFFFFFF) +#define CLR_BUF(u) u->hwmark = 0xFFFFFFFF #define RS_NUMWD 128 /* 36bit words/sec */ #define NUM_UNITS_RS 8 @@ -42,72 +44,14 @@ #define DTYPE(x) (((x) & UNIT_M_DTYPE) << UNIT_V_DTYPE) #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ -#define CNTRL_V_CTYPE (UNIT_V_UF + 4) -#define CNTRL_M_CTYPE 7 -#define GET_CNTRL(x) (((x) >> CNTRL_V_CTYPE) & CNTRL_M_CTYPE) -#define CNTRL(x) (((x) & CNTRL_M_CTYPE) << CNTRL_V_CTYPE) /* Parameters in the unit descriptor */ - -/* CONI Flags */ -#define IADR_ATTN 0000000000040LL /* Interrupt on attention */ -#define IARD_RAE 0000000000100LL /* Interrupt on register access error */ -#define DIB_CBOV 0000000000200LL /* Control bus overrun */ -#define CXR_PS_FAIL 0000000002000LL /* Power supply fail (not implemented) */ -#define CXR_ILC 0000000004000LL /* Illegal function code */ -#define CR_DRE 0000000010000LL /* Or Data and Control Timeout */ -#define DTC_OVER 0000000020000LL /* DF10 did not supply word on time (not implemented) */ -#define CCW_COMP_1 0000000040000LL /* Control word written. */ -#define CXR_CHAN_ER 0000000100000LL /* Channel Error */ -#define CXR_EXC 0000000200000LL /* Error in drive transfer */ -#define CXR_DBPE 0000000400000LL /* Device Parity error (not implemented) */ -#define CXR_NXM 0000001000000LL /* Channel non-existent memory (not implemented) */ -#define CXR_CWPE 0000002000000LL /* Channel Control word parity error (not implemented) */ -#define CXR_CDPE 0000004000000LL /* Channel Data Parity Error (not implemented) */ -#define CXR_SD_RAE 0000200000000LL /* Register access error */ -#define CXR_ILFC 0000400000000LL /* Illegal CXR function code */ -#define B22_FLAG 0004000000000LL /* 22 bit channel */ -#define CC_CHAN_PLS 0010000000000LL /* Channel transfer pulse (not implemented) */ -#define CC_CHAN_ACT 0020000000000LL /* Channel in use */ -#define CC_INH 0040000000000LL /* Disconnect channel */ -#define CB_FULL 0200000000000LL /* Set when channel buffer is full (not implemented) */ -#define AR_FULL 0400000000000LL /* Set when AR is full (not implemented) */ - -/* CONO Flags */ -#define ATTN_EN 0000000000040LL /* enable attention interrupt. */ -#define REA_EN 0000000000100LL /* enable register error interrupt */ -#define CBOV_CLR 0000000000200LL /* Clear CBOV */ -#define CONT_RESET 0000000002000LL /* Clear All error bits */ -#define ILC_CLR 0000000004000LL /* Clear ILC and SD RAE */ -#define DRE_CLR 0000000010000LL /* Clear CR_CBTO and CR_DBTO */ -#define OVER_CLR 0000000020000LL /* Clear DTC overrun */ -#define WRT_CW 0000000040000LL /* Write control word */ -#define CHN_CLR 0000000100000LL /* Clear Channel Error */ -#define DR_EXC_CLR 0000000200000LL /* Clear DR_EXC */ -#define DBPE_CLR 0000000400000LL /* Clear CXR_DBPE */ - -/* DATAO/DATAI */ -#define CR_REG 0770000000000LL /* Register number */ -#define LOAD_REG 0004000000000LL /* Load register */ -#define CR_MAINT_MODE 0000100000000LL /* Maint mode... not implemented */ -#define CR_DRIVE 0000007000000LL -#define CR_GEN_EVD 0000000400000LL /* Enable Parity */ -#define CR_DXES 0000000200000LL /* Disable DXES errors */ -#define CR_INAD 0000000077600LL -#define CR_WTEVM 0000000000100LL /* Verify Parity */ -#define CR_FUNC 0000000000076LL -#define CR_GO 0000000000001LL - -#define IRQ_VECT 0000000000177LL /* Interupt vector */ -#define IRQ_KI10 0000002000000LL -#define IRQ_KA10 0000001000000LL - #define CMD u3 /* u3 low */ /* RSC - 00 - control */ -#define CS1_GO CR_GO /* go */ +#define CS1_GO 1 /* go */ #define CS1_V_FNC 1 /* function pos */ #define CS1_M_FNC 037 /* function mask */ #define CS1_FNC (CS1_M_FNC << CS1_V_FNC) @@ -228,21 +172,10 @@ struct drvtyp rs_drv_tab[] = { }; -struct df10 rs_df10[NUM_DEVS_RS]; -uint32 rs_xfer_drive[NUM_DEVS_RS]; uint64 rs_buf[NUM_DEVS_RS][RS_NUMWD]; -int rs_reg[NUM_DEVS_RS]; -int rs_ivect[NUM_DEVS_RS]; -int rs_imode[NUM_DEVS_RS]; -int rs_drive[NUM_DEVS_RS]; -int rs_rae[NUM_DEVS_RS]; -int rs_attn[NUM_DEVS_RS]; -extern int readin_flag; - -t_stat rs_devio(uint32 dev, uint64 *data); -int rs_devirq(uint32 dev, int addr); -void rs_write(int ctlr, int unit, int reg, uint32 data); -uint32 rs_read(int ctlr, int unit, int reg); +void rs_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data); +uint32 rs_read(DEVICE *dptr, struct rh_if *rhc, int reg); +void rs_rst(DEVICE *dptr); t_stat rs_svc(UNIT *); t_stat rs_boot(int32, DEVICE *); void rs_ini(UNIT *, t_bool); @@ -258,28 +191,38 @@ const char *rs_description (DEVICE *dptr); UNIT rs_unit[] = { /* Controller 1 */ { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, { UDATA (&rs_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL(0), RS04_SIZE) }, + UNIT_ROABLE+DTYPE(RS04_DTYPE)+CNTRL_RH(0), RS04_SIZE) }, +}; + +struct rh_if rs_rh[] = { + { &rs_write, &rs_read, &rs_rst}, }; DIB rs_dib[] = { - {RH10_DEV, 1, &rs_devio, &rs_devirq} + {RH10_DEV, 1, &rh_devio, &rh_devirq, &rs_rh[0]} }; MTAB rs_mod[] = { +#if KL + {MTAB_XTD|MTAB_VDV, TYPE_RH10, NULL, "RH10", &rh_set_type, NULL, + NULL, "Sets controller to RH10" }, + {MTAB_XTD|MTAB_VDV, TYPE_RH20, "RH20", "RH20", &rh_set_type, &rh_show_type, + NULL, "Sets controller to RH20"}, +#endif {UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL}, {UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL}, {UNIT_DTYPE, (RS03_DTYPE << UNIT_V_DTYPE), "RS03", "RS03", &rs_set_type }, @@ -288,23 +231,20 @@ MTAB rs_mod[] = { }; REG rsa_reg[] = { - {ORDATA(IVECT, rs_ivect[0], 18)}, - {FLDATA(IMODE, rs_imode[0], 0)}, - {ORDATA(XFER, rs_xfer_drive[0], 3), REG_HRO}, - {ORDATA(DRIVE, rs_drive[0], 3), REG_HRO}, - {ORDATA(REG, rs_reg[0], 6), REG_RO}, - {ORDATA(RAE, rs_rae[0], 8), REG_RO}, - {ORDATA(ATTN, rs_attn[0], 8), REG_RO}, - {FLDATA(READIN, readin_flag, 0), REG_HRO}, - {ORDATA(STATUS, rs_df10[0].status, 18), REG_RO}, - {ORDATA(CIA, rs_df10[0].cia, 18)}, - {ORDATA(CCW, rs_df10[0].ccw, 18)}, - {ORDATA(WCR, rs_df10[0].wcr, 18)}, - {ORDATA(CDA, rs_df10[0].cda, 18)}, - {ORDATA(DEVNUM, rs_df10[0].devnum, 9), REG_HRO}, - {ORDATA(BUF, rs_df10[0].buf, 36), REG_HRO}, - {ORDATA(NXM, rs_df10[0].nxmerr, 8), REG_HRO}, - {ORDATA(COMP, rs_df10[0].ccw_comp, 8), REG_HRO}, + {ORDATA(IVECT, rs_rh[0].ivect, 18)}, + {FLDATA(IMODE, rs_rh[0].imode, 0)}, + {ORDATA(XFER, rs_rh[0].xfer_drive, 3), REG_HRO}, + {ORDATA(DRIVE, rs_rh[0].drive, 3), REG_HRO}, + {ORDATA(REG, rs_rh[0].reg, 6), REG_RO}, + {ORDATA(RAE, rs_rh[0].rae, 8), REG_RO}, + {ORDATA(ATTN, rs_rh[0].attn, 8), REG_RO}, + {ORDATA(STATUS, rs_rh[0].status, 18), REG_RO}, + {ORDATA(CIA, rs_rh[0].cia, 18)}, + {ORDATA(CCW, rs_rh[0].ccw, 18)}, + {ORDATA(WCR, rs_rh[0].wcr, 18)}, + {ORDATA(CDA, rs_rh[0].cda, 18)}, + {ORDATA(DEVNUM, rs_rh[0].devnum, 9), REG_HRO}, + {ORDATA(BUF, rs_rh[0].buf, 36), REG_HRO}, {BRDATA(BUFF, &rs_buf[0][0], 16, 64, RS_NUMWD), REG_HRO}, {0} }; @@ -322,213 +262,44 @@ DEVICE *rs_devs[] = { }; -t_stat rs_devio(uint32 dev, uint64 *data) { - int ctlr = -1; - DEVICE *dptr = NULL; - struct df10 *df10; - int drive; - - for (drive = 0; rh[drive].dev_num != 0; drive++) { - if (rh[drive].dev_num == (dev & 0774)) { - dptr = rh[drive].dev; - break; - } - } - if (dptr == NULL) - return SCPE_OK; - ctlr = GET_CNTRL(dptr->units[0].flags); - df10 = &rs_df10[ctlr]; - df10->devnum = dev; - switch(dev & 3) { - case CONI: - *data = df10->status & ~(IADR_ATTN|IARD_RAE); - if (rs_attn[ctlr] != 0 && (df10->status & IADR_ATTN)) - *data |= IADR_ATTN; - if (rs_rae[ctlr] != 0 && (df10->status & IARD_RAE)) - *data |= IARD_RAE; -#if KI_22BIT - *data |= B22_FLAG; -#endif - sim_debug(DEBUG_CONI, dptr, "RS %03o CONI %06o PC=%o %o\n", - dev, (uint32)*data, PC, rs_attn[ctlr]); - return SCPE_OK; - - case CONO: - clr_interrupt(dev); - df10->status &= ~(07LL|IADR_ATTN|IARD_RAE); - df10->status |= *data & (07LL|IADR_ATTN|IARD_RAE); - /* Clear flags */ - if (*data & CONT_RESET) { - UNIT *uptr=dptr->units; - for(drive = 0; drive < NUM_UNITS_RS; drive++, uptr++) { - uptr->CMD &= DS_MOL|DS_WRL|DS_DPR|DS_DRY|DS_VV|076; - uptr->DA &= 003400177777; - } - } - if (*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)) - df10->status &= ~(*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)); - if (*data & OVER_CLR) - df10->status &= ~(DTC_OVER); - if (*data & CBOV_CLR) - df10->status &= ~(DIB_CBOV); - if (*data & CXR_ILC) - df10->status &= ~(CXR_ILFC|CXR_SD_RAE); - if (*data & WRT_CW) - df10_writecw(df10); - if (*data & PI_ENABLE) - df10->status &= ~PI_ENABLE; - if (df10->status & PI_ENABLE) - set_interrupt(dev, df10->status); - if ((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0) - set_interrupt(dev, df10->status); - sim_debug(DEBUG_CONO, dptr, "RS %03o CONO %06o %d PC=%06o %06o\n", - dev, (uint32)*data, ctlr, PC, df10->status); - return SCPE_OK; - - case DATAI: - *data = 0; - if (df10->status & BUSY && rs_reg[ctlr] != 04) { - df10->status |= CC_CHAN_ACT; - return SCPE_OK; - } - if (rs_reg[ctlr] == 040) { - *data = (uint64)(rs_read(ctlr, rs_drive[ctlr], 0) & 077); - *data |= ((uint64)(df10->cia)) << 6; - *data |= ((uint64)(rs_xfer_drive[ctlr])) << 18; - } else if (rs_reg[ctlr] == 044) { - *data = (uint64)rs_ivect[ctlr]; - if (rs_imode[ctlr]) - *data |= IRQ_KI10; - else - *data |= IRQ_KA10; - } else if (rs_reg[ctlr] == 054) { - *data = (uint64)(rs_rae[ctlr]); - } else if ((rs_reg[ctlr] & 040) == 0) { - int parity; - - *data = (uint64)(rs_read(ctlr, rs_drive[ctlr], rs_reg[ctlr]) & 0177777); - parity = (int)((*data >> 8) ^ *data); - parity = (parity >> 4) ^ parity; - parity = (parity >> 2) ^ parity; - parity = ((parity >> 1) ^ parity) & 1; - *data |= ((uint64)(parity ^ 1)) << 17; - *data |= ((uint64)(rs_drive[ctlr])) << 18; - } - *data |= ((uint64)(rs_reg[ctlr])) << 30; - sim_debug(DEBUG_DATAIO, dptr, "RS %03o DATI %012llo, %d %d PC=%06o\n", - dev, *data, ctlr, rs_drive[ctlr], PC); - return SCPE_OK; - - case DATAO: - sim_debug(DEBUG_DATAIO, dptr, "RS %03o DATO %012llo, %d PC=%06o %06o\n", - dev, *data, ctlr, PC, df10->status); - rs_reg[ctlr] = ((int)(*data >> 30)) & 077; - if (rs_reg[ctlr] < 040 && rs_reg[ctlr] != 04) { - rs_drive[ctlr] = (int)(*data >> 18) & 07; - } - if (*data & LOAD_REG) { - if (rs_reg[ctlr] == 040) { - if ((*data & 1) == 0) { - return SCPE_OK; - } - - if (df10->status & BUSY) { - df10->status |= CC_CHAN_ACT; - return SCPE_OK; - } - - df10->status &= ~(1 << df10->ccw_comp); - df10->status &= ~PI_ENABLE; - if (((*data >> 1) & 077) < FNC_XFER) { - df10->status |= CXR_ILC; - df10_setirq(df10); - sim_debug(DEBUG_DATAIO, dptr, - "RS %03o command abort %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, rs_drive[ctlr], PC, df10->status); - return SCPE_OK; - } - - /* Start command */ - df10_setup(df10, (uint32)(*data >> 6)); - rs_xfer_drive[ctlr] = (int)(*data >> 18) & 07; - rs_write(ctlr, rs_drive[ctlr], 0, (uint32)(*data & 077)); - sim_debug(DEBUG_DATAIO, dptr, - "RS %03o command %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, rs_drive[ctlr], PC, df10->status); - } else if (rs_reg[ctlr] == 044) { - /* Set KI10 Irq vector */ - rs_ivect[ctlr] = (int)(*data & IRQ_VECT); - rs_imode[ctlr] = (*data & IRQ_KI10) != 0; - } else if (rs_reg[ctlr] == 050) { - ; /* Diagnostic access to mass bus. */ - } else if (rs_reg[ctlr] == 054) { - /* clear flags */ - rs_rae[ctlr] &= ~(*data & 0377); - if (rs_rae[ctlr] == 0) - clr_interrupt(dev); - } else if ((rs_reg[ctlr] & 040) == 0) { - rs_drive[ctlr] = (int)(*data >> 18) & 07; - /* Check if access error */ - if (rs_rae[ctlr] & (1 << rs_drive[ctlr])) { - return SCPE_OK; - } - rs_drive[ctlr] = (int)(*data >> 18) & 07; - rs_write(ctlr, rs_drive[ctlr], rs_reg[ctlr] & 037, - (int)(*data & 0777777)); - } - } - return SCPE_OK; - } - return SCPE_OK; /* Unreached */ -} - -/* Handle KI and KL style interrupt vectors */ -int -rs_devirq(uint32 dev, int addr) { - DEVICE *dptr = NULL; - int drive; - - for (drive = 0; rh[drive].dev_num != 0; drive++) { - if (rh[drive].dev_num == (dev & 0774)) { - dptr = rh[drive].dev; - break; - } - } - if (dptr != NULL) { - drive = GET_CNTRL(dptr->units[0].flags); - return (rs_imode[drive] ? rs_ivect[drive] : addr); - } - return addr; +void +rs_rst(DEVICE *dptr) +{ + UNIT *uptr=dptr->units; + int drive; + for(drive = 0; drive < NUM_UNITS_RS; drive++, uptr++) { + uptr->CMD &= DS_MOL|DS_WRL|DS_DPR|DS_DRY|DS_VV|076; + uptr->DA &= 003400177777; + } } void -rs_write(int ctlr, int unit, int reg, uint32 data) { +rs_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) { int i; - DEVICE *dptr = rs_devs[ctlr]; - struct df10 *df10 = &rs_df10[ctlr]; + int unit = rhc->drive; UNIT *uptr = &dptr->units[unit]; - if ((uptr->CMD & CR_GO) && reg != 04) { + if ((uptr->CMD & CS1_GO) && reg != 04) { uptr->CMD |= (ER1_RMR << 16)|DS_ERR; return; } switch(reg) { case 000: /* control */ - sim_debug(DEBUG_DETAIL, dptr, "RSA%o %d Status=%06o\n", unit, ctlr, uptr->CMD); + sim_debug(DEBUG_DETAIL, dptr, "%s%o Status=%06o\n", dptr->name, unit, uptr->CMD); /* Set if drive not writable */ if (uptr->flags & UNIT_WLK) uptr->CMD |= DS_WRL; /* If drive not ready don't do anything */ if ((uptr->CMD & DS_DRY) == 0) { uptr->CMD |= (ER1_RMR << 16)|DS_ERR; - sim_debug(DEBUG_DETAIL, dptr, "RSA%o %d busy\n", unit, ctlr); + sim_debug(DEBUG_DETAIL, dptr, "%s%o busy\n", dptr->name, unit); return; } /* Check if GO bit set */ if ((data & 1) == 0) { uptr->CMD &= ~076; uptr->CMD |= data & 076; - sim_debug(DEBUG_DETAIL, dptr, "RSA%o %d no go\n", unit, ctlr); + sim_debug(DEBUG_DETAIL, dptr, "%s%o no go\n", dptr->name, unit); return; /* No, nop */ } uptr->CMD &= DS_ATA|DS_VV|DS_DPR|DS_MOL|DS_WRL; @@ -542,7 +313,8 @@ rs_write(int ctlr, int unit, int reg, uint32 data) { case FNC_WCHK: /* write check */ case FNC_WRITE: /* write */ case FNC_READ: /* read */ - uptr->CMD |= DS_PIP|CR_GO; + uptr->CMD |= DS_PIP|CS1_GO; + CLR_BUF(uptr); uptr->DATAPTR = 0; break; @@ -551,30 +323,26 @@ rs_write(int ctlr, int unit, int reg, uint32 data) { if ((uptr->flags & UNIT_ATT) != 0) uptr->CMD |= DS_VV; uptr->CMD |= DS_DRY; - df10_setirq(df10); + rh_setirq(rhc); break; case FNC_DCLR: /* drive clear */ uptr->CMD |= DS_DRY; - uptr->CMD &= ~(DS_ATA|CR_GO); - rs_attn[ctlr] = 0; - clr_interrupt(df10->devnum); + uptr->CMD &= ~(DS_ATA|CS1_GO); + rhc->attn = 0; + clr_interrupt(rhc->devnum); for (i = 0; i < 8; i++) { - if (rs_unit[(ctlr * 8) + i].CMD & DS_ATA) - rs_attn[ctlr] = 1; + if (dptr->units[i].CMD & DS_ATA) + rhc->attn |= 1 << i; } - if ((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0) - df10_setirq(df10); break; default: uptr->CMD |= DS_DRY|DS_ERR|DS_ATA; uptr->CMD |= (ER1_ILF << 16); - if ((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0) - df10_setirq(df10); } - if (uptr->CMD & CR_GO) + if (uptr->CMD & CS1_GO) sim_activate(uptr, 100); - sim_debug(DEBUG_DETAIL, dptr, "RSA%o AStatus=%06o\n", unit, uptr->CMD); + sim_debug(DEBUG_DETAIL, dptr, "%s%o AStatus=%06o\n", dptr->name, unit, uptr->CMD); return; case 001: /* status */ break; @@ -587,17 +355,13 @@ rs_write(int ctlr, int unit, int reg, uint32 data) { case 003: /* maintenance */ break; case 004: /* atten summary */ - rs_attn[ctlr] = 0; + rhc->attn = 0; for (i = 0; i < 8; i++) { if (data & (1<units[i].CMD &= ~DS_ATA; + if (dptr->units[i].CMD & DS_ATA) + rhc->attn |= 1 << i; } - clr_interrupt(df10->devnum); - if (((df10->status & IADR_ATTN) != 0 && rs_attn[ctlr] != 0) || - (df10->status & PI_ENABLE)) - df10_setirq(df10); break; case 005: /* sector/track */ uptr->DA = data & 0177777; @@ -607,14 +371,13 @@ rs_write(int ctlr, int unit, int reg, uint32 data) { break; default: uptr->CMD |= (ER1_ILR<<16)|DS_ERR; - rs_rae[ctlr] &= ~(1<rae |= 1 << unit; } } uint32 -rs_read(int ctlr, int unit, int reg) { - DEVICE *dptr = rs_devs[ctlr]; - struct df10 *df10 = &rs_df10[ctlr]; +rs_read(DEVICE *dptr, struct rh_if *rhc, int reg) { + int unit = rhc->drive; UNIT *uptr = &dptr->units[unit]; uint32 temp = 0; int i; @@ -628,7 +391,7 @@ rs_read(int ctlr, int unit, int reg) { temp = uptr->CMD & 077; if (uptr->flags & UNIT_ATT) temp |= CS1_DVA; - if ((df10->status & BUSY) == 0 && (uptr->CMD & CR_GO) == 0) + if ((uptr->CMD & CS1_GO) == 0) temp |= CS1_GO; break; case 001: /* status */ @@ -639,7 +402,7 @@ rs_read(int ctlr, int unit, int reg) { break; case 004: /* atten summary */ for (i = 0; i < 8; i++) { - if (rs_unit[(ctlr * 8) + i].CMD & DS_ATA) { + if (dptr->units[i].CMD & DS_ATA) { temp |= 1 << i; } } @@ -655,7 +418,7 @@ rs_read(int ctlr, int unit, int reg) { break; default: uptr->CMD |= (ER1_ILR<<16); - rs_rae[ctlr] &= ~(1<rae |= 1 << unit; } return temp; } @@ -663,22 +426,21 @@ rs_read(int ctlr, int unit, int reg) { t_stat rs_svc (UNIT *uptr) { - int dtype = GET_DTYPE(uptr->flags); - int ctlr = GET_CNTRL(uptr->flags); - int unit; - DEVICE *dptr; - struct df10 *df; - int da; - t_stat r; + int dtype = GET_DTYPE(uptr->flags); + int ctlr = GET_CNTRL_RH(uptr->flags); + int unit; + DEVICE *dptr; + struct rh_if *rhc; + int da; + int sts; /* Find dptr, and df10 */ dptr = rs_devs[ctlr]; + rhc = &rs_rh[ctlr]; unit = uptr - dptr->units; - df = &rs_df10[ctlr]; if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ uptr->CMD |= (ER1_UNS << 16) | DS_ATA|DS_ERR; /* set drive error */ - df->status &= ~BUSY; - df10_setirq(df); + rh_setirq(rhc); return (SCPE_OK); } @@ -693,42 +455,35 @@ t_stat rs_svc (UNIT *uptr) case FNC_DCLR: /* drive clear */ break; case FNC_PRESET: /* read-in preset */ - rs_attn[ctlr] = 1; uptr->CMD |= DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - df->status &= ~BUSY; - if (df->status & IADR_ATTN) - df10_setirq(df); - sim_debug(DEBUG_DETAIL, dptr, "RSA%o seekdone\n", unit); + uptr->CMD &= ~CS1_GO; + rh_setattn(rhc, unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o seekdone\n", dptr->name, unit); break; case FNC_SEARCH: /* search */ if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf) uptr->CMD |= (ER1_IAE << 16)|DS_ERR; - rs_attn[ctlr] = 1; uptr->CMD |= DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - df->status &= ~BUSY; - if ((df->status & (IADR_ATTN|BUSY)) == IADR_ATTN) - df10_setirq(df); - sim_debug(DEBUG_DETAIL, dptr, "RSA%o searchdone\n", unit); + uptr->CMD &= ~CS1_GO; + rh_setattn(rhc, unit); + sim_debug(DEBUG_DETAIL, dptr, "%s%o searchdone\n", dptr->name, unit); break; case FNC_READ: /* read */ case FNC_WCHK: /* write check */ - if (uptr->DATAPTR == 0) { + if (BUF_EMPTY(uptr)) { int wc; if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf) { uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; - df->status &= ~BUSY; - uptr->CMD &= ~CR_GO; - sim_debug(DEBUG_DETAIL, dptr, "RSA%o readx done\n", unit); - df10_finish_op(df, 0); + uptr->CMD &= ~CS1_GO; + sim_debug(DEBUG_DETAIL, dptr, "%s%o readx done\n", dptr->name, unit); + rh_finish_op(rhc, 0); return SCPE_OK; } - sim_debug(DEBUG_DETAIL, dptr, "RSA%o read (%d,%d)\n", unit, + sim_debug(DEBUG_DETAIL, dptr, "%s%o read (%d,%d)\n", dptr->name, unit, GET_SC(uptr->DA), GET_SF(uptr->DA)); da = GET_DA(uptr->DA, dtype) * RS_NUMWD; (void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET); @@ -737,15 +492,17 @@ t_stat rs_svc (UNIT *uptr) while (wc < RS_NUMWD) rs_buf[ctlr][wc++] = 0; uptr->hwmark = RS_NUMWD; + uptr->DATAPTR = 0; } - df->buf = rs_buf[ctlr][uptr->DATAPTR++]; - sim_debug(DEBUG_DATA, dptr, "RSA%o read word %d %012llo %09o %06o\n", - unit, uptr->DATAPTR, df->buf, df->cda, df->wcr); - if (df10_write(df)) { - if (uptr->DATAPTR == uptr->hwmark) { + rhc->buf = rs_buf[ctlr][uptr->DATAPTR++]; + sim_debug(DEBUG_DATA, dptr, "%s%o read word %d %012llo %09o %06o\n", + dptr->name, unit, uptr->DATAPTR, rhc->buf, rhc->cda, rhc->wcr); + if (rh_write(rhc)) { + if (uptr->DATAPTR == RS_NUMWD) { /* Increment to next sector. Set Last Sector */ uptr->DATAPTR = 0; + CLR_BUF(uptr); uptr->DA += 1 << DA_V_SC; if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect) { uptr->DA &= (DA_M_SF << DA_V_SF); @@ -753,43 +510,53 @@ t_stat rs_svc (UNIT *uptr) if (GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf) uptr->CMD |= DS_LST; } + if (rh_blkend(rhc)) + goto rd_end; } - sim_activate(uptr, 20); + sim_activate(uptr, 10); } else { - sim_debug(DEBUG_DETAIL, dptr, "RSA%o read done\n", unit); +rd_end: + sim_debug(DEBUG_DETAIL, dptr, "%s%o read done\n", dptr->name, unit); uptr->CMD |= DS_DRY; - uptr->CMD &= ~CR_GO; - df10_finish_op(df, 0); + uptr->CMD &= ~CS1_GO; + if (uptr->DATAPTR == RS_NUMWD) + (void)rh_blkend(rhc); + rh_finish_op(rhc, 0); return SCPE_OK; } break; case FNC_WRITE: /* write */ - if (uptr->DATAPTR == 0) { + if (BUF_EMPTY(uptr)) { if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect || GET_SF(uptr->DA) >= rs_drv_tab[dtype].surf) { uptr->CMD |= (ER1_IAE << 16)|DS_ERR|DS_DRY|DS_ATA; - uptr->CMD &= ~CR_GO; - sim_debug(DEBUG_DETAIL, dptr, "RSA%o writex done\n", unit); - df10_finish_op(df, 0); + uptr->CMD &= ~CS1_GO; + sim_debug(DEBUG_DETAIL, dptr, "%s%o writex done\n", dptr->name, unit); + rh_finish_op(rhc, 0); return SCPE_OK; } + uptr->DATAPTR = 0; + uptr->hwmark = 0; } - r = df10_read(df); - rs_buf[ctlr][uptr->DATAPTR++] = df->buf; - sim_debug(DEBUG_DATA, dptr, "RSA%o write word %d %012llo %09o %06o\n", - unit, uptr->DATAPTR, df->buf, df->cda, df->wcr); - if (r == 0 || uptr->DATAPTR == RS_NUMWD) { + sts = rh_read(rhc); + rs_buf[ctlr][uptr->DATAPTR++] = rhc->buf; + sim_debug(DEBUG_DATA, dptr, "%s%o write word %d %012llo %09o %06o\n", + dptr->name, unit, uptr->DATAPTR, rhc->buf, rhc->cda, rhc->wcr); + if (sts == 0) { while (uptr->DATAPTR < RS_NUMWD) rs_buf[ctlr][uptr->DATAPTR++] = 0; - sim_debug(DEBUG_DETAIL, dptr, "RSA%o write (%d,%d)\n", unit, + } + if (uptr->DATAPTR == RS_NUMWD) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o write (%d,%d)\n", dptr->name, unit, GET_SC(uptr->DA), GET_SF(uptr->DA)); da = GET_DA(uptr->DA, dtype) * RS_NUMWD; (void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET); (void)sim_fwrite (&rs_buf[ctlr][0], sizeof(uint64), RS_NUMWD, uptr->fileref); uptr->DATAPTR = 0; - if (r) { + CLR_BUF(uptr); + if (sts) { uptr->DA += 1 << DA_V_SC; if (GET_SC(uptr->DA) >= rs_drv_tab[dtype].sect) { uptr->DA &= (DA_M_SF << DA_V_SF); @@ -798,14 +565,17 @@ t_stat rs_svc (UNIT *uptr) uptr->CMD |= DS_LST; } } + if (rh_blkend(rhc)) + goto wr_end; } - if (r) { - sim_activate(uptr, 20); + if (sts) { + sim_activate(uptr, 10); } else { - sim_debug(DEBUG_DETAIL, dptr, "RSA%o write done\n", unit); +wr_end: + sim_debug(DEBUG_DETAIL, dptr, "%s%o write done\n", dptr->name, unit); uptr->CMD |= DS_DRY; - uptr->CMD &= ~CR_GO; - df10_finish_op(df, 0); + uptr->CMD &= ~CS1_GO; + rh_finish_op(rhc, 0); return SCPE_OK; } break; @@ -833,12 +603,9 @@ rs_reset(DEVICE * rstr) { int ctlr; for (ctlr = 0; ctlr < NUM_DEVS_RS; ctlr++) { - rs_df10[ctlr].devnum = rs_dib[ctlr].dev_num; - rs_df10[ctlr].nxmerr = 19; - rs_df10[ctlr].ccw_comp = 14; - rs_df10[ctlr].status = 0; - rs_attn[ctlr] = 0; - rs_rae[ctlr] = 0; + rs_rh[ctlr].status = 0; + rs_rh[ctlr].attn = 0; + rs_rh[ctlr].rae = 0; } return SCPE_OK; } @@ -848,16 +615,16 @@ t_stat rs_boot(int32 unit_num, DEVICE * rptr) { UNIT *uptr = &rptr->units[unit_num]; - int ctlr = GET_CNTRL(uptr->flags); + int ctlr = GET_CNTRL_RH(uptr->flags); + struct rh_if *rhc; DEVICE *dptr; - struct df10 *df; uint32 addr; uint32 ptr = 0; uint64 word; int wc; - df = &rs_df10[ctlr]; dptr = rs_devs[ctlr]; + rhc = &rs_rh[ctlr]; (void)sim_fseek(uptr->fileref, 0, SEEK_SET); (void)sim_fread (&rs_buf[0][0], sizeof(uint64), RS_NUMWD, uptr->fileref); uptr->CMD |= DS_VV; @@ -875,9 +642,9 @@ rs_boot(int32 unit_num, DEVICE * rptr) addr = rs_buf[0][ptr] & RMASK; wc = (rs_buf[0][ptr++] >> 18) & RMASK; word = rs_buf[0][ptr++]; - rs_reg[ctlr] = 040; - rs_drive[ctlr] = uptr - dptr->units; - df->status |= CCW_COMP_1|PI_ENABLE; + rhc->reg = 040; + rhc->drive = uptr - dptr->units; + rhc->status |= CCW_COMP_1|PI_ENABLE; PC = word & RMASK; return SCPE_OK; @@ -901,14 +668,17 @@ t_stat rs_attach (UNIT *uptr, CONST char *cptr) if (rstr == 0) return SCPE_OK; dib = (DIB *) rstr->ctxt; - ctlr = dib->dev_num & 014; + for (ctlr = 0; rh[ctlr].dev_num != 0; ctlr++) { + if (rh[ctlr].dev == rstr) + break; + } uptr->DA = 0; uptr->CMD &= ~DS_VV; uptr->CMD |= DS_DPR|DS_MOL|DS_DRY; if (uptr->flags & UNIT_WLK) uptr->CMD |= DS_WRL; - rs_df10[ctlr].status |= PI_ENABLE; - set_interrupt(dib->dev_num, rs_df10[ctlr].status); + rs_rh[ctlr].status |= PI_ENABLE; + set_interrupt(dib->dev_num, rs_rh[ctlr].status); return SCPE_OK; } diff --git a/PDP10/kx10_sys.c b/PDP10/kx10_sys.c index d9e0faf..10bf9f3 100644 --- a/PDP10/kx10_sys.c +++ b/PDP10/kx10_sys.c @@ -3,7 +3,7 @@ Copyright (c) 2005-2009, Robert M Supnik - Copyright (c) 2011-2018, Richard Cornwell + Copyright (c) 2011-2019, Richard Cornwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -42,11 +42,8 @@ sim_load binary loader */ -#if KLB -char sim_name[] = "KL-10B"; -#endif -#if KLA -char sim_name[] = "KL-10A"; +#if KL +char sim_name[] = "KL-10"; #endif #if KI char sim_name[] = "KI-10"; @@ -68,6 +65,9 @@ DEVICE *sim_devices[] = { #if PDP6 | KA | KI &cty_dev, #endif +#if KL + &dte_dev, +#endif #if (NUM_DEVS_PT > 0) &ptp_dev, &ptr_dev, @@ -75,6 +75,9 @@ DEVICE *sim_devices[] = { #if (NUM_DEVS_LP > 0) &lpt_dev, #endif +#if (NUM_DEVS_LP20 > 0) + &lp20_dev, +#endif #if (NUM_DEVS_CR > 0) &cr_dev, #endif @@ -141,6 +144,9 @@ DEVICE *sim_devices[] = { #if (NUM_DEVS_DC > 0) &dc_dev, #endif +#if (NUM_DEVS_TTY > 0) + &tty_dev, +#endif #if (NUM_DEVS_DCS > 0) &dcs_dev, #endif @@ -156,9 +162,15 @@ DEVICE *sim_devices[] = { &wcnsls_dev, #endif #endif +#if (NUM_DEVS_III > 0) + &iii_dev, +#endif #if NUM_DEVS_IMP > 0 &imp_dev, #endif +#if NUM_DEVS_NIA > 0 + &nia_dev, +#endif #if NUM_DEVS_CH10 > 0 &ch10_dev, #endif @@ -197,7 +209,8 @@ DEVICE *sim_devices[] = { const char *sim_stop_messages[] = { "Unknown error", "HALT instruction", - "Breakpoint" + "Breakpoint", + "Invalid access" }; /* Simulator debug controls */ @@ -232,6 +245,7 @@ DEBTAB crd_debug[] = { #define FMT_E 3 /* EXE */ #define FMT_D 4 /* WAITS DMP */ #define FMT_I 5 /* ITS SBLK */ +#define FMT_B 6 /* EXB format */ #define EXE_DIR 01776 /* EXE directory */ #define EXE_VEC 01775 /* EXE entry vec */ @@ -510,19 +524,28 @@ return SCPE_OK; } -int get_word(FILE *fileref, uint64 *word) +int get_word(FILE *fileref, uint64 *word, int ftype) { - char cbuf[5]; + char cbuf[5]; - if (sim_fread(cbuf, 1, 5, fileref) != 5) + if (sim_fread(cbuf, 1, 5, fileref) != 5) return 1; - *word = ((uint64)(cbuf[0]) << 29) | - ((uint64)(cbuf[1]) << 22) | - ((uint64)(cbuf[2]) << 15) | - ((uint64)(cbuf[3]) << 8) | - ((uint64)(cbuf[4] & 0177) << 1) | - ((uint64)(cbuf[4] & 0200) >> 7); - return 0; + if (ftype) { + *word = ((uint64)(cbuf[0] & 0177) << 29) | + ((uint64)(cbuf[1] & 0177) << 22) | + ((uint64)(cbuf[2] & 0177) << 15) | + ((uint64)(cbuf[3] & 0177) << 8) | + ((uint64)(cbuf[4] & 0177) << 1); + if (cbuf[4] & 0200) + *word |= 1; + } else { + *word = ((uint64)(cbuf[0] & 0377) << 28) | + ((uint64)(cbuf[1] & 0377) << 20) | + ((uint64)(cbuf[2] & 0377) << 12) | + ((uint64)(cbuf[3] & 0377) << 4) | + (uint64)(cbuf[4] & 017); + } + return 0; } /* SAV file loader @@ -538,14 +561,14 @@ int get_word(FILE *fileref, uint64 *word) JRST start */ -t_stat load_sav (FILE *fileref) +t_stat load_sav (FILE *fileref, int ftype) { uint64 data; uint32 pa; int32 wc; for ( ;; ) { /* loop */ - if (get_word(fileref, &data)) + if (get_word(fileref, &data, ftype)) return SCPE_OK; wc = (int32)(data >> 18); pa = (uint32) (data & RMASK); @@ -559,7 +582,7 @@ t_stat load_sav (FILE *fileref) pa &= RMASK; wc++; wc &= RMASK; - if (get_word(fileref, &data)) + if (get_word(fileref, &data, ftype)) return SCPE_FMT; M[pa] = data; } /* end if count*/ @@ -594,7 +617,7 @@ t_stat load_sav (FILE *fileref) #define PAG_V_PN 9 #define DIRSIZ (2 * PAG_SIZE) -t_stat load_exe (FILE *fileref) +t_stat load_exe (FILE *fileref, int ftype) { uint64 data, dirbuf[DIRSIZ], pagbuf[PAG_SIZE], entbuf[2]; int32 ndir, entvec, i, j, k, cont, bsz, bty, rpt, wc; @@ -604,8 +627,9 @@ uint32 ma; ndir = entvec = 0; /* no dir, entvec */ cont = 1; do { - wc = sim_fread (&data, sizeof (uint64), 1, fileref);/* read blk hdr */ - if (wc == 0) /* error? */ + + wc = get_word(fileref, &data, ftype); + if (wc != 0) /* error? */ return SCPE_FMT; bsz = (int32) ((data & RMASK) - 1); /* get count */ if (bsz < 0) /* zero? */ @@ -616,9 +640,11 @@ do { case EXE_DIR: /* directory */ if (ndir != 0) /* got one */ return SCPE_FMT; - ndir = sim_fread (dirbuf, sizeof (uint64), bsz, fileref); - if (ndir < bsz) /* error */ - return SCPE_FMT; + for (i = 0; i < bsz; i++) { + if (get_word(fileref, &dirbuf[i], ftype)) + return SCPE_FMT; + } + ndir = bsz; break; case EXE_PDV: /* optional */ @@ -628,9 +654,11 @@ do { case EXE_VEC: /* entry vec */ if (bsz != 2) /* must be 2 wds */ return SCPE_FMT; - entvec = sim_fread (entbuf, sizeof (uint64), bsz, fileref); - if (entvec < 2) /* error? */ - return SCPE_FMT; + for (i = 0; i < bsz; i++) { + if (get_word(fileref, &entbuf[i], ftype)) + return SCPE_FMT; + } + entvec = bsz; cont = 0; /* stop */ break; @@ -651,10 +679,11 @@ for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */ rpt = ((int32) ((dirbuf[i + 1] >> 27) + 1)) & 0777; /* repeat count */ for (j = 0; j < rpt; j++, mpage++) { /* loop thru rpts */ if (fpage) { /* file pages? */ - (void)sim_fseek (fileref, (fpage << PAG_V_PN) * sizeof (uint64), SEEK_SET); - wc = sim_fread (pagbuf, sizeof (uint64), PAG_SIZE, fileref); - if (wc < PAG_SIZE) - return SCPE_FMT; + (void)sim_fseek (fileref, (fpage << PAG_V_PN) * 5, SEEK_SET); + for (k = 0; k < PAG_SIZE; k++) { + if (get_word(fileref, &pagbuf[k], ftype)) + break; + } fpage++; } ma = mpage << PAG_V_PN; /* mem addr */ @@ -667,18 +696,103 @@ for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */ } /* end directory */ if (entvec && entbuf[1]) PC = (int32) (entbuf[1] & RMASK); /* start addr */ +else if (entvec == 0) + PC = (int32) (M[0120] & RMASK); return SCPE_OK; } +static int exb_pos = -1; +int get_exb_byte (FILE *fileref, int *byt, int ftype) +{ + static uint64 word; + + exb_pos++; + switch(exb_pos & 3) { + case 0: if (get_word(fileref, &word, ftype)) + return 1; + *byt = ((word >> 18) & 0377); + break; + case 1: *byt = ((word >> 26) & 0377); + break; + case 2: *byt = ((word >> 0) & 0377); + break; + case 3: *byt = ((word >> 8) & 0377); + break; + } + return 0; +} + +t_stat load_exb (FILE *fileref, int ftype) +{ + int odd = 0; + int pos = 0; + int wc; + int byt; + uint64 word; + t_addr addr; + + exb_pos = -1; + for ( ;; ) { + /* All records start on even byte */ + if (odd && get_exb_byte (fileref, &byt, ftype)) + return SCPE_FMT; + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + wc = byt; + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + wc |= byt << 8; + wc -= 4; + odd = wc & 1; + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + addr = byt; + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + addr |= byt << 8; + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + addr |= byt << 16; + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + addr |= byt << 24; + /* Empty record gives start address */ + if (wc == 0) { + PC = addr; + return SCPE_OK; + } + pos = 0; + for (; wc > 0; wc--, pos++) { + if (get_exb_byte(fileref, &byt, ftype)) + return SCPE_FMT; + switch(pos) { + case 0: word = ((uint64)byt); break; + case 1: word |= ((uint64)byt) << 8; break; + case 2: word |= ((uint64)byt) << 16; break; + case 3: word |= ((uint64)byt) << 24; break; + case 4: word |= ((uint64)(byt & 017)) << 32; + M[addr++] = word; + pos = -1; + break; + } + } + } + return SCPE_FMT; +} + /* Master loader */ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) { uint64 data; int32 wc, fmt; +int ftype; extern int32 sim_switches; fmt = 0; /* no fmt */ +ftype = 0; +if (sim_switches & SWMASK ('C')) /* -c? core dump */ + ftype = 1; if (sim_switches & SWMASK ('R')) /* -r? */ fmt = FMT_R; else if (sim_switches & SWMASK ('S')) /* -s? */ @@ -689,12 +803,16 @@ else if (sim_switches & SWMASK ('D')) /* -d? */ fmt = FMT_D; else if (sim_switches & SWMASK ('I')) /* -i? */ fmt = FMT_I; +else if (sim_switches & SWMASK ('B')) /* -b? */ + fmt = FMT_B; else if (match_ext (fnam, "RIM")) /* .RIM? */ fmt = FMT_R; else if (match_ext (fnam, "SAV")) /* .SAV? */ fmt = FMT_S; else if (match_ext (fnam, "EXE")) /* .EXE? */ fmt = FMT_E; +else if (match_ext (fnam, "EXB")) /* .EXB? */ + fmt = FMT_B; else if (match_ext (fnam, "DMP")) /* .DMP? */ fmt = FMT_D; else if (match_ext (fnam, "BIN")) /* .BIN? */ @@ -716,16 +834,19 @@ switch (fmt) { /* case fmt */ return load_rim (fileref); case FMT_S: /* SAV */ - return load_sav (fileref); + return load_sav (fileref, ftype); case FMT_E: /* EXE */ - return load_exe (fileref); + return load_exe (fileref, ftype); case FMT_D: /* DMP */ return load_dmp (fileref); case FMT_I: /* SBLK */ return load_sblk (fileref); + + case FMT_B: /* EXB */ + return load_exb (fileref, ftype); } printf ("Can't determine load file format\n"); @@ -759,13 +880,22 @@ static const char *opcode[] = { "LUUO10", "LUUO11", "LUUO12", "LUUO13", "LUUO14", "LUUO15", "LUUO16", "LUUO17", "LUUO20", "LUUO21", "LUUO22", "LUUO23", "LUUO24", "LUUO25", "LUUO26", "LUUO27", "LUUO30", "LUUO31", "LUUO32", "LUUO33", "LUUO34", "LUUO35", "LUUO36", "LUUO37", -"MUUO40", "MUUO41", "MUUO42", "MUUO43", "MUUO44", "MUUO45", "MUUO46", "MUUO47", -"MUUO50", "MUUO51", "MUUO52", "MUUO53", "MUUO54", "MUUO55", "MUUO56", "MUUO57", -"MUUO60", "MUUO61", "MUUO62", "MUUO63", "MUUO64", "MUUO65", "MUUO66", "MUUO67", -"MUUO70", "MUUO71", "MUUO72", "MUUO73", "MUUO74", "MUUO75", "MUUO76", "MUUO77", +"CALL", "INITI", "MUUO42", "MUUO43", "MUUO44", "MUUO45", "MUUO46", "CALLI", +#if KL +"OPEN", "TTCALL", "PMOVE", "PMOVEM", "MUUO54", "RENAME", "IN", "OUT", +#else +"OPEN", "TTCALL", "MUUO52", "MUUO53", "MUUO54", "RENAME", "IN", "OUT", +#endif +"SETSTS", "STATO", "STATUS", "GETSTS", "INBUF", "OUTBUF", "INPUT", "OUTPUT", +"CLOSE", "RELEAS", "MTAPE", "UGETF", "USETI", "USETO", "LOOKUP", "ENTER", -"UJEN", "MUUO101", "MUUO102", "JSYS", "MUUO104", "MUUO105", "MUUO106", +#if KL +"UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ", "DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV", +#else +"UJEN", "MUUO101", "MUUO102", "JSYS", "MUUO104", "MUUO105", "MUUO106", +"DFAD", "DFSB", "DFMP", "DFDV", "MUUO114", "MUUO115", "MUUO116", "MUUO117", +#endif "DMOVE", "DMOVN", "FIX", "EXTEND", "DMOVEM", "DMOVNM", "FIXR", "FLTR", "UFA", "DFN", "FSC", "ADJBP", "ILDB", "LDB", "IDPB", "DPB", "FAD", "FADL", "FADM", "FADB", "FADR", "FADRL", "FADRM", "FADRB", diff --git a/PDP10/kx10_tu.c b/PDP10/kx10_tu.c index ae7d1de..87cc20e 100644 --- a/PDP10/kx10_tu.c +++ b/PDP10/kx10_tu.c @@ -1,6 +1,6 @@ /* ka10_tu.c: Dec RH10 TM03/TU10 tape controller - Copyright (c) 2017, Richard Cornwell + Copyright (c) 2017-2019, Richard Cornwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -39,69 +39,12 @@ /* Flags in the unit flags word */ #define TU_UNIT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE -#define CNTRL_V_CTYPE (MTUF_V_UF) -#define CNTRL_M_CTYPE 7 -#define GET_CNTRL(x) (((x) >> CNTRL_V_CTYPE) & CNTRL_M_CTYPE) -#define CNTRL(x) (((x) & CNTRL_M_CTYPE) << CNTRL_V_CTYPE) - -/* CONI Flags */ -#define IADR_ATTN 0000000000040LL /* Interrupt on attention */ -#define IARD_RAE 0000000000100LL /* Interrupt on register access error */ -#define DIB_CBOV 0000000000200LL /* Control bus overrun */ -#define CXR_PS_FAIL 0000000002000LL /* Power supply fail (not implemented) */ -#define CXR_ILC 0000000004000LL /* Illegal function code */ -#define CR_DRE 0000000010000LL /* Or Data and Control Timeout */ -#define DTC_OVER 0000000020000LL /* DF10 did not supply word on time (not implemented) */ -#define CCW_COMP_1 0000000040000LL /* Control word written. */ -#define CXR_CHAN_ER 0000000100000LL /* Channel Error */ -#define CXR_EXC 0000000200000LL /* Error in drive transfer */ -#define CXR_DBPE 0000000400000LL /* Device Parity error (not implemented) */ -#define CXR_NXM 0000001000000LL /* Channel non-existent memory (not implemented) */ -#define CXR_CWPE 0000002000000LL /* Channel Control word parity error (not implemented) */ -#define CXR_CDPE 0000004000000LL /* Channel Data Parity Error (not implemented) */ -#define CXR_SD_RAE 0000200000000LL /* Register access error */ -#define CXR_ILFC 0000400000000LL /* Illegal CXR function code */ -#define B22_FLAG 0004000000000LL /* 22 bit channel */ -#define CC_CHAN_PLS 0010000000000LL /* Channel transfer pulse (not implemented) */ -#define CC_CHAN_ACT 0020000000000LL /* Channel in use */ -#define CC_INH 0040000000000LL /* Disconnect channel */ -#define CB_FULL 0200000000000LL /* Set when channel buffer is full (not implemented) */ -#define AR_FULL 0400000000000LL /* Set when AR is full (not implemented) */ - -/* CONO Flags */ -#define ATTN_EN 0000000000040LL /* enable attention interrupt. */ -#define REA_EN 0000000000100LL /* enable register error interrupt */ -#define CBOV_CLR 0000000000200LL /* Clear CBOV */ -#define CONT_RESET 0000000002000LL /* Clear All error bits */ -#define ILC_CLR 0000000004000LL /* Clear ILC and SD RAE */ -#define DRE_CLR 0000000010000LL /* Clear CR_CBTO and CR_DBTO */ -#define OVER_CLR 0000000020000LL /* Clear DTC overrun */ -#define WRT_CW 0000000040000LL /* Write control word */ -#define CHN_CLR 0000000100000LL /* Clear Channel Error */ -#define DR_EXC_CLR 0000000200000LL /* Clear DR_EXC */ -#define DBPE_CLR 0000000400000LL /* Clear CXR_DBPE */ - -/* DATAO/DATAI */ -#define CR_REG 0770000000000LL /* Register number */ -#define LOAD_REG 0004000000000LL /* Load register */ -#define CR_MAINT_MODE 0000100000000LL /* Maint mode... not implemented */ -#define CR_DRIVE 0000007000000LL -#define CR_GEN_EVD 0000000400000LL /* Enable Parity */ -#define CR_DXES 0000000200000LL /* Disable DXES errors */ -#define CR_INAD 0000000077600LL -#define CR_WTEVM 0000000000100LL /* Verify Parity */ -#define CR_FUNC 0000000000076LL -#define CR_GO 0000000000001LL - -#define IRQ_VECT 0000000000177LL /* Interupt vector */ -#define IRQ_KI10 0000002000000LL -#define IRQ_KA10 0000001000000LL #define CMD u3 /* u3 low */ /* TUC - 00 - control */ -#define CS1_GO CR_GO /* go */ +#define CS1_GO 1 /* go */ #define CS1_V_FNC 1 /* function pos */ #define CS1_M_FNC 037 /* function mask */ #define CS1_FNC (CS1_M_FNC << CS1_V_FNC) @@ -179,7 +122,7 @@ /* TUDT - 06 - drive type */ -/* TULA - 07 - look ahead register */ +/* TULA - 07 - Check Character */ /* TUSN - 10 - serial number */ @@ -213,24 +156,14 @@ #define CPOS u4 #define DATAPTR u6 -struct df10 tu_df10[NUM_DEVS_TU]; -int tu_xfer_drive[NUM_DEVS_TU]; uint8 tu_buf[NUM_DEVS_TU][TU_NUMFR]; -int tu_reg[NUM_DEVS_TU]; -int tu_ivect[NUM_DEVS_TU]; -int tu_imode[NUM_DEVS_TU]; -int tu_drive[NUM_DEVS_TU]; -int tu_rae[NUM_DEVS_TU]; -int tu_attn[NUM_DEVS_TU]; uint16 tu_frame[NUM_DEVS_TU]; uint16 tu_tcr[NUM_DEVS_TU]; -extern int readin_flag; static uint64 tu_boot_buffer; -t_stat tu_devio(uint32 dev, uint64 *data); -int tu_devirq(uint32 dev, int addr); -void tu_write(int ctlr, int unit, int reg, uint32 data); -uint32 tu_read(int ctlr, int unit, int reg); +void tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data); +uint32 tu_read(DEVICE *dptr, struct rh_if *rhc, int reg); +void tu_rst(DEVICE *dptr); t_stat tu_srv(UNIT *); t_stat tu_boot(int32, DEVICE *); void tu_ini(UNIT *, t_bool); @@ -244,21 +177,31 @@ const char *tu_description (DEVICE *dptr); UNIT tu_unit[] = { /* Controller 1 */ - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, - { UDATA (&tu_srv, TU_UNIT+CNTRL(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, + { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, +}; + +struct rh_if tu_rh[NUM_DEVS_TU] = { + { &tu_write, &tu_read} }; DIB tu_dib[] = { - {RH10_DEV, 1, &tu_devio, &tu_devirq} + {RH10_DEV, 1, &rh_devio, &rh_devirq, &tu_rh[0]} }; MTAB tu_mod[] = { +#if KL + {MTAB_XTD|MTAB_VDV, TYPE_RH10, NULL, "RH10", &rh_set_type, NULL, + NULL, "Sets controller to RH10" }, + {MTAB_XTD|MTAB_VDV, TYPE_RH20, "RH20", "RH20", &rh_set_type, &rh_show_type, + NULL, "Sets controller to RH20"}, +#endif {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL}, {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL}, {MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", @@ -271,31 +214,28 @@ MTAB tu_mod[] = { }; REG tua_reg[] = { - {ORDATA(IVECT, tu_ivect[0], 18)}, - {FLDATA(IMODE, tu_imode[0], 0)}, + {ORDATA(IVECT, tu_rh[0].ivect, 18)}, + {FLDATA(IMODE, tu_rh[0].imode, 0)}, {ORDATA(FRAME, tu_frame[0], 16)}, {ORDATA(TCR, tu_tcr[0], 16)}, - {ORDATA(XFER, tu_xfer_drive[0], 3), REG_HRO}, - {ORDATA(DRIVE, tu_drive[0], 3), REG_HRO}, - {ORDATA(REG, tu_reg[0], 6), REG_RO}, - {ORDATA(RAE, tu_rae[0], 8), REG_RO}, - {ORDATA(ATTN, tu_attn[0], 8), REG_RO}, - {FLDATA(READIN, readin_flag, 0), REG_HRO}, - {ORDATA(STATUS, tu_df10[0].status, 18), REG_RO}, - {ORDATA(CIA, tu_df10[0].cia, 18)}, - {ORDATA(CCW, tu_df10[0].ccw, 18)}, - {ORDATA(WCR, tu_df10[0].wcr, 18)}, - {ORDATA(CDA, tu_df10[0].cda, 18)}, - {ORDATA(DEVNUM, tu_df10[0].devnum, 9), REG_HRO}, - {ORDATA(BUF, tu_df10[0].buf, 36), REG_HRO}, - {ORDATA(NXM, tu_df10[0].nxmerr, 8), REG_HRO}, - {ORDATA(COMP, tu_df10[0].ccw_comp, 8), REG_HRO}, + {ORDATA(XFER, tu_rh[0].xfer_drive, 3), REG_HRO}, + {ORDATA(DRIVE, tu_rh[0].drive, 3), REG_HRO}, + {ORDATA(REG, tu_rh[0].reg, 6), REG_RO}, + {ORDATA(RAE, tu_rh[0].rae, 8), REG_RO}, + {ORDATA(ATTN, tu_rh[0].attn, 8), REG_RO}, + {ORDATA(STATUS, tu_rh[0].status, 18), REG_RO}, + {ORDATA(CIA, tu_rh[0].cia, 18)}, + {ORDATA(CCW, tu_rh[0].ccw, 18)}, + {ORDATA(WCR, tu_rh[0].wcr, 18)}, + {ORDATA(CDA, tu_rh[0].cda, 18)}, + {ORDATA(DEVNUM, tu_rh[0].devnum, 9), REG_HRO}, + {ORDATA(BUF, tu_rh[0].buf, 36), REG_HRO}, {BRDATA(BUFF, &tu_buf[0][0], 16, 64, TU_NUMFR), REG_HRO}, {0} -}; +}; DEVICE tua_dev = { - "TUA", tu_unit, NULL, tu_mod, + "TUA", tu_unit, tua_reg, tu_mod, NUM_UNITS_TU, 8, 18, 1, 8, 36, NULL, NULL, &tu_reset, &tu_boot, &tu_attach, &tu_detach, &tu_dib[0], DEV_DISABLE | DEV_DEBUG | DEV_TAPE, 0, dev_debug, @@ -307,196 +247,25 @@ DEVICE *tu_devs[] = { &tua_dev, }; - -t_stat tu_devio(uint32 dev, uint64 *data) { - int ctlr = -1; - DEVICE *dptr = NULL; - struct df10 *df10; - int drive; - - for (drive = 0; rh[drive].dev_num != 0; drive++) { - if (rh[drive].dev_num == (dev & 0774)) { - dptr = rh[drive].dev; - break; - } - } - - if (dptr == NULL) - return SCPE_OK; - ctlr = GET_CNTRL(dptr->units[0].flags); - df10 = &tu_df10[ctlr]; - df10->devnum = dev; - switch(dev & 3) { - case CONI: - *data = df10->status & ~(IADR_ATTN|IARD_RAE); - if (tu_attn[ctlr] != 0 && (df10->status & IADR_ATTN)) - *data |= IADR_ATTN; - if (tu_rae[ctlr] != 0 && (df10->status & IARD_RAE)) - *data |= IARD_RAE; -#if KI_22BIT - *data |= B22_FLAG; -#endif - sim_debug(DEBUG_CONI, dptr, "TU %03o CONI %06o PC=%o %o\n", - dev, (uint32)*data, PC, tu_attn[ctlr]); - return SCPE_OK; - - case CONO: - clr_interrupt(dev); - df10->status &= ~07LL; - df10->status |= *data & (07LL|IADR_ATTN|IARD_RAE); - /* Clear flags */ - if (*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)) - df10->status &= ~(*data & (DBPE_CLR|DR_EXC_CLR|CHN_CLR)); - if (*data & OVER_CLR) - df10->status &= ~(DTC_OVER); - if (*data & CBOV_CLR) - df10->status &= ~(DIB_CBOV); - if (*data & CXR_ILC) - df10->status &= ~(CXR_ILFC|CXR_SD_RAE); - if (*data & WRT_CW) - df10_writecw(df10); - if (*data & PI_ENABLE) - df10->status &= ~PI_ENABLE; - if (df10->status & PI_ENABLE) - set_interrupt(dev, df10->status); - if ((df10->status & IADR_ATTN) != 0 && tu_attn[ctlr] != 0) - set_interrupt(dev, df10->status); - sim_debug(DEBUG_CONO, dptr, "TU %03o CONO %06o %d PC=%06o %06o\n", - dev, (uint32)*data, ctlr, PC, df10->status); - return SCPE_OK; - - case DATAI: - *data = 0; - if (df10->status & BUSY && tu_reg[ctlr] != 04) { - df10->status |= CC_CHAN_ACT; - return SCPE_OK; - } - if (tu_reg[ctlr] == 040) { - *data = (uint64)(tu_read(ctlr, tu_drive[ctlr], 0) & 077); - *data |= ((uint64)(df10->cia)) << 6; - *data |= ((uint64)(tu_xfer_drive[ctlr])) << 18; - } else if (tu_reg[ctlr] == 044) { - *data = (uint64)tu_ivect[ctlr]; - if (tu_imode[ctlr]) - *data |= IRQ_KI10; - else - *data |= IRQ_KA10; - } else if (tu_reg[ctlr] == 054) { - *data = (uint64)(tu_rae[ctlr]); - } else if ((tu_reg[ctlr] & 040) == 0) { - *data = (uint64)(tu_read(ctlr, tu_drive[ctlr], tu_reg[ctlr]) & 0177777); - *data |= ((uint64)(tu_drive[ctlr])) << 18; - } - *data |= ((uint64)(tu_reg[ctlr])) << 30; - sim_debug(DEBUG_DATAIO, dptr, "TU %03o DATI %012llo, %d %d PC=%06o\n", - dev, *data, ctlr, tu_drive[ctlr], PC); - return SCPE_OK; - - case DATAO: - sim_debug(DEBUG_DATAIO, dptr, "TU %03o DATO %012llo, %d PC=%06o %06o\n", - dev, *data, ctlr, PC, df10->status); - tu_reg[ctlr] = ((int)(*data >> 30)) & 077; - if (tu_reg[ctlr] < 040 && tu_reg[ctlr] != 04) { - tu_drive[ctlr] = (int)(*data >> 18) & 07; - } - if (*data & LOAD_REG) { - if (tu_reg[ctlr] == 040) { - if ((*data & 1) == 0) { - return SCPE_OK; - } - if (df10->status & BUSY) { - df10->status |= CC_CHAN_ACT; - sim_debug(DEBUG_DATAIO, dptr, - "TU %03o command busy %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, tu_drive[ctlr], PC, df10->status); - return SCPE_OK; - } - - df10->status &= ~(1 << df10->ccw_comp); - df10->status &= ~PI_ENABLE; - if (((*data >> 1) & 077) < FNC_XFER) { - df10->status |= CXR_ILC; - df10_setirq(df10); - sim_debug(DEBUG_DATAIO, dptr, - "TU %03o command abort %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, tu_drive[ctlr], PC, df10->status); - return SCPE_OK; - } - /* Check if access error */ - if (tu_rae[ctlr] & (1 << tu_drive[ctlr])) { - return SCPE_OK; - } - - /* Start command */ - df10_setup(df10, (uint32)(*data >> 6)); - tu_xfer_drive[ctlr] = (int)(*data >> 18) & 07; - tu_write(ctlr, tu_drive[ctlr], 0, (uint32)(*data & 077)); - sim_debug(DEBUG_DATAIO, dptr, - "TU %03o command %012llo, %d[%d] PC=%06o %06o\n", - dev, *data, ctlr, tu_drive[ctlr], PC, df10->status); - } else if (tu_reg[ctlr] == 044) { - /* Set KI10 Irq vector */ - tu_ivect[ctlr] = (int)(*data & IRQ_VECT); - tu_imode[ctlr] = (*data & IRQ_KI10) != 0; - } else if (tu_reg[ctlr] == 050) { - ; /* Diagnostic access to mass bus. */ - } else if (tu_reg[ctlr] == 054) { - /* clear flags */ - tu_rae[ctlr] &= ~(*data & 0377); - if (tu_rae[ctlr] == 0) - clr_interrupt(dev); - } else if ((tu_reg[ctlr] & 040) == 0) { - tu_drive[ctlr] = (int)(*data >> 18) & 07; - /* Check if access error */ - if (tu_rae[ctlr] & (1 << tu_drive[ctlr])) { - return SCPE_OK; - } - tu_drive[ctlr] = (int)(*data >> 18) & 07; - tu_write(ctlr, tu_drive[ctlr], tu_reg[ctlr] & 037, - (int)(*data & 0777777)); - } - } - return SCPE_OK; - } - return SCPE_OK; /* Unreached */ -} - -/* Handle KI and KL style interrupt vectors */ -int -tu_devirq(uint32 dev, int addr) { - DEVICE *dptr = NULL; - int drive; - - for (drive = 0; rh[drive].dev_num != 0; drive++) { - if (rh[drive].dev_num == (dev & 0774)) { - dptr = rh[drive].dev; - break; - } - } - if (dptr != NULL) { - drive = GET_CNTRL(dptr->units[0].flags); - return (tu_imode[drive] ? tu_ivect[drive] : addr); - } - return addr; -} - void -tu_write(int ctlr, int unit, int reg, uint32 data) { - UNIT *uptr = &tu_unit[(ctlr * 8) + (tu_tcr[ctlr] & 07)]; - DEVICE *dptr = tu_devs[ctlr]; - struct df10 *df10 = &tu_df10[ctlr]; +tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) { + int ctlr = GET_CNTRL_RH(dptr->units[0].flags); + int unit = tu_tcr[ctlr] & 07; + UNIT *uptr = &dptr->units[unit]; int i; - if (uptr->CMD & CR_GO) { + if (rhc->drive != 0) /* Only one unit at 0 */ + return; + + if (uptr->CMD & CS1_GO) { uptr->STATUS |= (ER1_RMR); return; } switch(reg) { case 000: /* control */ - sim_debug(DEBUG_DETAIL, dptr, "TUA%o %d Status=%06o\n", - unit, ctlr, uptr->STATUS); - df10->status &= ~(1 << df10->ccw_comp); + sim_debug(DEBUG_DETAIL, dptr, "%s%o %d Status=%06o\n", + dptr->name, unit, ctlr, uptr->STATUS); if ((data & 01) != 0 && (uptr->flags & UNIT_ATT) != 0) { uptr->CMD = data & 076; switch (GET_FNC(data)) { @@ -507,45 +276,51 @@ tu_write(int ctlr, int unit, int reg, uint32 data) { case FNC_READ: /* read */ case FNC_READREV: /* read w/ headers */ tu_frame[ctlr] = 0; + tu_tcr[ctlr] |= TC_FCS; + /* Fall through */ + + case FNC_WRITE: /* write */ + case FNC_SPACEF: /* Space forward */ + case FNC_SPACEB: /* Space backward */ + if ((tu_tcr[ctlr] & TC_FCS) == 0) { + uptr->STATUS |= ER1_NEF; + break; + } /* Fall through */ case FNC_ERASE: /* Erase gap */ - case FNC_WRITE: /* write */ case FNC_WTM: /* Write tape mark */ - case FNC_SPACEF: /* Space forward */ - case FNC_SPACEB: /* Space backward */ case FNC_WCHK: /* write check */ case FNC_REWIND: /* rewind */ case FNC_UNLOAD: /* unload */ case FNC_WCHKREV: /* write w/ headers */ - uptr->CMD |= CS_PIP|CR_GO; - uptr->CMD &= ~CS_TM; + uptr->CMD |= CS_PIP|CS1_GO; + rhc->attn = 0; + for (i = 0; i < 8; i++) { + if (dptr->units[i].CMD & CS_ATA) + rhc->attn = 1; + } CLR_BUF(uptr); uptr->DATAPTR = 0; - df10->status &= ~PI_ENABLE; sim_activate(uptr, 100); break; case FNC_DCLR: /* drive clear */ - uptr->CMD &= ~(CS_ATA|CR_GO|CS_TM); + uptr->CMD &= ~(CS_ATA|CS1_GO|CS_TM); uptr->STATUS = 0; - tu_attn[ctlr] = 0; - clr_interrupt(df10->devnum); + rhc->status &= ~PI_ENABLE; + rhc->attn = 0; for (i = 0; i < 8; i++) { - if (tu_unit[(ctlr * 8) + i].CMD & CS_ATA) - tu_attn[ctlr] = 1; + if (dptr->units[i].CMD & CS_ATA) + rhc->attn = 1; } - if ((df10->status & IADR_ATTN) != 0 && tu_attn[ctlr] != 0) - df10_setirq(df10); break; default: uptr->STATUS |= (ER1_ILF); uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - if ((df10->status & IADR_ATTN) != 0) - df10_setirq(df10); + rhc->attn = 1; } - sim_debug(DEBUG_DETAIL, dptr, "TUA%o AStatus=%06o\n", unit, + sim_debug(DEBUG_DETAIL, dptr, "%s%o AStatus=%06o\n", dptr->name, unit, uptr->CMD); } return; @@ -558,20 +333,17 @@ tu_write(int ctlr, int unit, int reg, uint32 data) { case 003: /* maintenance */ break; case 004: /* atten summary */ - tu_attn[ctlr] = 0; + rhc->attn = 0; for (i = 0; i < 8; i++) { if (data & (1<units[i].CMD &= ~CS_ATA; + if (dptr->units[i].CMD & CS_ATA) + rhc->attn = 1; } - clr_interrupt(df10->devnum); - if (((df10->status & IADR_ATTN) != 0 && tu_attn[ctlr] != 0) || - (df10->status & PI_ENABLE)) - df10_setirq(df10); break; case 005: /* frame count */ tu_frame[ctlr] = data & 0177777; + tu_tcr[ctlr] |= TC_FCS; break; case 006: /* drive type */ case 007: /* look ahead */ @@ -581,43 +353,45 @@ tu_write(int ctlr, int unit, int reg, uint32 data) { default: uptr->STATUS |= ER1_ILR; uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - tu_rae[ctlr] |= (1<status & IADR_ATTN) != 0) - df10_setirq(df10); + rhc->attn = 1; + rhc->rae = 1; } } uint32 -tu_read(int ctlr, int unit, int reg) { - UNIT *uptr = &tu_unit[(ctlr * 8) + (tu_tcr[ctlr] & 07)]; - struct df10 *df10 = &tu_df10[ctlr]; - uint32 temp = 0; - int i; +tu_read(DEVICE *dptr, struct rh_if *rhc, int reg) { + int ctlr = GET_CNTRL_RH(dptr->units[0].flags); + int unit = tu_tcr[ctlr] & 07; + UNIT *uptr = &dptr->units[unit]; + uint32 temp = 0; + int i; + + if (rhc->drive != 0) /* Only one unit at 0 */ + return 0; switch(reg) { case 000: /* control */ temp = uptr->CMD & 076; if (uptr->flags & UNIT_ATT) temp |= CS1_DVA; - if (df10->status & BUSY || uptr->CMD & CR_GO) + if (uptr->CMD & CS1_GO) temp |= CS1_GO; break; case 001: /* status */ temp = DS_DPR; - if (tu_attn[ctlr] != 0) + if (uptr->CMD & CS_ATA) temp |= DS_ATA; if (uptr->CMD & CS_CHANGE) temp |= DS_SSC; if ((uptr->STATUS & 0177777) != 0) - temp |= DS_ERR|DS_ATA; + temp |= DS_ERR; if ((uptr->flags & UNIT_ATT) != 0) { temp |= DS_MOL; if (uptr->CMD & CS_TM) temp |= DS_TM; if (uptr->flags & MTUF_WLK) temp |= DS_WRL; - if ((uptr->CMD & (CS_MOTION|CS_PIP|CR_GO)) == 0) + if ((uptr->CMD & (CS_MOTION|CS_PIP|CS1_GO)) == 0) temp |= DS_DRY; if (sim_tape_bot(uptr)) temp |= DS_BOT; @@ -634,7 +408,7 @@ tu_read(int ctlr, int unit, int reg) { break; case 004: /* atten summary */ for (i = 0; i < 8; i++) { - if (tu_unit[(ctlr * 8) + i].CMD & CS_ATA) { + if (dptr->units[i].CMD & CS_ATA) { temp |= 1 << i; } } @@ -643,7 +417,7 @@ tu_read(int ctlr, int unit, int reg) { temp = tu_frame[ctlr]; break; case 006: /* drive type */ - temp = 040054; + temp = 042054; break; case 011: /* tape control register */ temp = tu_tcr[ctlr]; @@ -657,10 +431,8 @@ tu_read(int ctlr, int unit, int reg) { default: uptr->STATUS |= (ER1_ILR); uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - tu_rae[ctlr] |= (1<status & IADR_ATTN) != 0) - df10_setirq(df10); + rhc->attn = 1; + rhc->rae = 1; } return temp; } @@ -669,8 +441,9 @@ tu_read(int ctlr, int unit, int reg) { /* Map simH errors into machine errors */ void tu_error(UNIT * uptr, t_stat r) { - int ctlr = GET_CNTRL(uptr->flags); - DEVICE *dptr = tu_devs[ctlr]; + int ctlr = GET_CNTRL_RH(uptr->flags); + DEVICE *dptr = tu_devs[ctlr]; + struct rh_if *rhc = &tu_rh[ctlr]; switch (r) { case MTSE_OK: /* no error */ @@ -707,211 +480,214 @@ void tu_error(UNIT * uptr, t_stat r) break; } - if (uptr->CMD & CS_ATA) { - tu_attn[ctlr] = 1; - } - uptr->CMD &= ~(CS_MOTION|CS_PIP|CR_GO); + if (uptr->CMD & CS_ATA) + rh_setattn(rhc, 0); + if (GET_FNC(uptr->CMD) >= FNC_XFER && uptr->CMD & (CS_ATA | CS_TM)) + rh_error(rhc); + uptr->CMD &= ~(CS_MOTION|CS_PIP|CS1_GO); sim_debug(DEBUG_EXP, dptr, "Setting status %d\n", r); } /* Handle processing of tape requests. */ t_stat tu_srv(UNIT * uptr) { - int ctlr = GET_CNTRL(uptr->flags); - int unit; - DEVICE *dptr; - struct df10 *df; - t_stat r; - t_mtrlnt reclen; - uint8 ch; - int cc; - int cc_max; + int ctlr = GET_CNTRL_RH(uptr->flags); + int unit; + struct rh_if *rhc; + DEVICE *dptr; + t_stat r; + t_mtrlnt reclen; + uint8 ch; + int cc; + int cc_max; /* Find dptr, and df10 */ dptr = tu_devs[ctlr]; + rhc = &tu_rh[ctlr]; unit = uptr - dptr->units; - df = &tu_df10[ctlr]; cc_max = (4 + ((tu_tcr[ctlr] & TC_FMTSEL) == 0)); if ((uptr->flags & UNIT_ATT) == 0) { tu_error(uptr, MTSE_UNATT); /* attached? */ - df10_setirq(df); + rh_setirq(rhc); return SCPE_OK; } switch (GET_FNC(uptr->CMD)) { case FNC_NOP: case FNC_DCLR: - sim_debug(DEBUG_DETAIL, dptr, "TU%o nop\n", unit); - tu_error(uptr, MTSE_OK); /* Nop */ - df10_setirq(df); - return SCPE_OK; + sim_debug(DEBUG_DETAIL, dptr, "%s%o nop\n", dptr->name, unit); + tu_error(uptr, MTSE_OK); /* Nop */ + rh_setirq(rhc); + return SCPE_OK; case FNC_REWIND: - sim_debug(DEBUG_DETAIL, dptr, "TU%o rewind\n", unit); - if (uptr->CMD & CR_GO) { - sim_activate(uptr,40000); - uptr->CMD |= CS_MOTION; - uptr->CMD &= ~(CR_GO); - } else { + sim_debug(DEBUG_DETAIL, dptr, "%s%o rewind\n", dptr->name, unit); + if (uptr->CMD & CS1_GO) { + sim_activate(uptr,40000); + uptr->CMD |= CS_MOTION; + uptr->CMD &= ~(CS1_GO); + } else { uptr->CMD &= ~(CS_MOTION|CS_PIP); uptr->CMD |= CS_CHANGE|CS_ATA; - tu_attn[ctlr] = 1; - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - tu_error(uptr, sim_tape_rewind(uptr)); - } - return SCPE_OK; + rh_setattn(rhc, 0); + (void)sim_tape_rewind(uptr); + } + return SCPE_OK; case FNC_UNLOAD: - sim_debug(DEBUG_DETAIL, dptr, "TU%o unload\n", unit); - uptr->CMD &= ~(CR_GO); - uptr->CMD |= CS_CHANGE|CS_ATA; - tu_attn[ctlr] = 1; - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - tu_error(uptr, sim_tape_detach(uptr)); - return SCPE_OK; + sim_debug(DEBUG_DETAIL, dptr, "%s%o unload\n", dptr->name, unit); + uptr->CMD |= CS_CHANGE|CS_ATA; + tu_error(uptr, sim_tape_detach(uptr)); + return SCPE_OK; case FNC_WCHKREV: case FNC_READREV: - if (BUF_EMPTY(uptr)) { - uptr->CMD &= ~CS_PIP; - if ((r = sim_tape_rdrecr(uptr, &tu_buf[ctlr][0], &reclen, - TU_NUMFR)) != MTSE_OK) { - sim_debug(DEBUG_DETAIL, dptr, "TU%o read error %d\n", unit, r); - if (r == MTSE_BOT) - uptr->STATUS |= ER1_NEF; - tu_error(uptr, r); - df10_finish_op(df, 0); - } else { - sim_debug(DEBUG_DETAIL, dptr, "TU%o read %d\n", unit, reclen); - uptr->CMD |= CS_MOTION; - uptr->hwmark = reclen; - uptr->DATAPTR = uptr->hwmark-1; - uptr->CPOS = cc_max; - df->buf = 0; - sim_activate(uptr, 100); - } - return SCPE_OK; - } - if (uptr->DATAPTR >= 0) { - tu_frame[ctlr]++; - cc = (8 * (3 - uptr->CPOS)) + 4; - ch = tu_buf[ctlr][uptr->DATAPTR]; - if (cc < 0) - df->buf |= (uint64)(ch & 0x0f); - else - df->buf |= (uint64)(ch & 0xff) << cc; - uptr->DATAPTR--; - uptr->CPOS--; - if (uptr->CPOS == 0) { - uptr->CPOS = cc_max; - if (GET_FNC(uptr->CMD) == FNC_READREV && - df10_write(df) == 0) { - tu_error(uptr, MTSE_OK); - return SCPE_OK; - } - sim_debug(DEBUG_DATA, dptr, "TU%o readrev %012llo\n", - unit, df->buf); - df->buf = 0; - } - } else { - if (uptr->CPOS != cc_max) - df10_write(df); - tu_error(uptr, MTSE_OK); - return SCPE_OK; - } - break; + if (BUF_EMPTY(uptr)) { + uptr->CMD &= ~CS_PIP; + if ((r = sim_tape_rdrecr(uptr, &tu_buf[ctlr][0], &reclen, + TU_NUMFR)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r); + if (r == MTSE_BOT) + uptr->STATUS |= ER1_NEF; + tu_error(uptr, r); + rh_finish_op(rhc, 0); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read %d\n", dptr->name, unit, reclen); + uptr->CMD |= CS_MOTION; + uptr->hwmark = reclen; + uptr->DATAPTR = uptr->hwmark-1; + uptr->CPOS = cc_max; + rhc->buf = 0; + sim_activate(uptr, 100); + } + return SCPE_OK; + } + if (uptr->DATAPTR >= 0) { + tu_frame[ctlr]++; + cc = (8 * (3 - uptr->CPOS)) + 4; + ch = tu_buf[ctlr][uptr->DATAPTR]; + if (cc < 0) + rhc->buf |= (uint64)(ch & 0x0f); + else + rhc->buf |= (uint64)(ch & 0xff) << cc; + uptr->DATAPTR--; + uptr->CPOS--; + if (uptr->CPOS == 0) { + uptr->CPOS = cc_max; + if (GET_FNC(uptr->CMD) == FNC_READREV && rh_write(rhc) == 0) { + tu_error(uptr, MTSE_OK); + rh_finish_op(rhc, 0); + return SCPE_OK; + } + sim_debug(DEBUG_DATA, dptr, "%s%o readrev %012llo\n", + dptr->name, unit, rhc->buf); + rhc->buf = 0; + } + } else { + if (uptr->CPOS != cc_max) + rh_write(rhc); + (void)rh_blkend(rhc); + tu_error(uptr, MTSE_OK); + rh_finish_op(rhc, 0); + return SCPE_OK; + } + break; case FNC_WCHK: case FNC_READ: - if (BUF_EMPTY(uptr)) { - uptr->CMD &= ~CS_PIP; - uptr->CMD |= CS_MOTION; - if ((r = sim_tape_rdrecf(uptr, &tu_buf[ctlr][0], &reclen, - TU_NUMFR)) != MTSE_OK) { - sim_debug(DEBUG_DETAIL, dptr, "TU%o read error %d\n", unit, r); - tu_error(uptr, r); - df10_finish_op(df, 0); - } else { - sim_debug(DEBUG_DETAIL, dptr, "TU%o read %d\n", unit, reclen); - uptr->hwmark = reclen; - uptr->DATAPTR = 0; - uptr->CPOS = 0; - df->buf = 0; - sim_activate(uptr, 100); - } - return SCPE_OK; - } - if ((uint32)uptr->DATAPTR < uptr->hwmark) { - tu_frame[ctlr]++; - cc = (8 * (3 - uptr->CPOS)) + 4; - ch = tu_buf[ctlr][uptr->DATAPTR]; - if (cc < 0) - df->buf |= (uint64)(ch & 0x0f); - else - df->buf |= (uint64)(ch & 0xff) << cc; - uptr->DATAPTR++; - uptr->CPOS++; - if (uptr->CPOS == cc_max) { - uptr->CPOS = 0; - if (GET_FNC(uptr->CMD) == FNC_READ && - df10_write(df) == 0) { - tu_error(uptr, MTSE_OK); - return SCPE_OK; - } - sim_debug(DEBUG_DATA, dptr, "TU%o read %012llo\n", - unit, df->buf); - df->buf = 0; - } - } else { - if (uptr->CPOS != 0) { - sim_debug(DEBUG_DATA, dptr, "TU%o read %012llo\n", - unit, df->buf); - df10_write(df); - } - tu_error(uptr, MTSE_OK); - df10_finish_op(df, 0); - return SCPE_OK; - } - break; + if (BUF_EMPTY(uptr)) { + uptr->CMD &= ~CS_PIP; + uptr->CMD |= CS_MOTION; + if ((r = sim_tape_rdrecf(uptr, &tu_buf[ctlr][0], &reclen, + TU_NUMFR)) != MTSE_OK) { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r); + if (r == MTSE_TMK) + uptr->STATUS |= ER1_FCE; + tu_error(uptr, r); + rh_finish_op(rhc, 0); + } else { + sim_debug(DEBUG_DETAIL, dptr, "%s%o read %d %d\n", dptr->name, unit, reclen, uptr->pos); + uptr->hwmark = reclen; + uptr->DATAPTR = 0; + uptr->CPOS = 0; + rhc->buf = 0; + sim_activate(uptr, 100); + } + return SCPE_OK; + } + if ((uint32)uptr->DATAPTR < uptr->hwmark) { + tu_frame[ctlr]++; + cc = (8 * (3 - uptr->CPOS)) + 4; + ch = tu_buf[ctlr][uptr->DATAPTR]; + if (cc < 0) + rhc->buf |= (uint64)(ch & 0x0f); + else + rhc->buf |= (uint64)(ch & 0xff) << cc; + uptr->DATAPTR++; + uptr->CPOS++; + if (uptr->CPOS == cc_max) { + uptr->CPOS = 0; + if (GET_FNC(uptr->CMD) == FNC_READ && rh_write(rhc) == 0) { + tu_error(uptr, MTSE_OK); + if (uptr->DATAPTR == uptr->hwmark) + (void)rh_blkend(rhc); + rh_finish_op(rhc, 0); + return SCPE_OK; + } + sim_debug(DEBUG_DATA, dptr, "%s%o read %012llo %d\n", + dptr->name, unit, rhc->buf, uptr->DATAPTR); + rhc->buf = 0; + } + } else { + if (uptr->CPOS != 0) { + sim_debug(DEBUG_DATA, dptr, "%s%o readf %012llo\n", + dptr->name, unit, rhc->buf); + rh_write(rhc); + } + if (tu_frame[ctlr] != 0) + uptr->STATUS |= ER1_FCE; + tu_error(uptr, MTSE_OK); + (void)rh_blkend(rhc); + rh_finish_op(rhc, 0); + return SCPE_OK; + } + break; case FNC_WRITE: if (BUF_EMPTY(uptr)) { uptr->CMD &= ~CS_PIP; if (tu_frame[ctlr] == 0) { uptr->STATUS |= ER1_NEF; - uptr->CMD &= ~(CR_GO); uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; + rhc->attn = 1; tu_error(uptr, MTSE_OK); - df10_finish_op(df, 0); + rh_finish_op(rhc, 0); return SCPE_OK; } if ((uptr->flags & MTUF_WLK) != 0) { tu_error(uptr, MTSE_WRP); - df10_finish_op(df, 0); + rh_finish_op(rhc, 0); return SCPE_OK; } uptr->CMD |= CS_MOTION; - sim_debug(DEBUG_EXP, dptr, "TU%o Init write\n", unit); + sim_debug(DEBUG_EXP, dptr, "%s%o Init write\n", dptr->name, unit); uptr->hwmark = 0; uptr->CPOS = 0; uptr->DATAPTR = 0; - df->buf = 0; + rhc->buf = 0; } - if (tu_frame[ctlr] != 0 && uptr->CPOS == 0 && df10_read(df) == 0) + if (tu_frame[ctlr] != 0 && uptr->CPOS == 0 && rh_read(rhc) == 0) uptr->CPOS |= 010; if ((uptr->CMD & CS_MOTION) != 0) { if (uptr->CPOS == 0) - sim_debug(DEBUG_DATA, dptr, "TU%o write %012llo\n", - unit, df->buf); + sim_debug(DEBUG_DATA, dptr, "%s%o write %012llo\n", + dptr->name, unit, rhc->buf); /* Write next char out */ cc = (8 * (3 - (uptr->CPOS & 07))) + 4; if (cc < 0) - ch = df->buf & 0x0f; + ch = rhc->buf & 0x0f; else - ch = (df->buf >> cc) & 0xff; + ch = (rhc->buf >> cc) & 0xff; tu_buf[ctlr][uptr->DATAPTR] = ch; uptr->DATAPTR++; uptr->hwmark = uptr->DATAPTR; @@ -920,99 +696,95 @@ t_stat tu_srv(UNIT * uptr) uptr->CPOS &= 010; } tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1); - if (tu_frame[ctlr] == 0) + if (tu_frame[ctlr] == 0) { uptr->CPOS = 010; + tu_tcr[ctlr] &= ~(TC_FCS); + } } if (uptr->CPOS == 010) { - /* Write out the block */ - reclen = uptr->hwmark; - r = sim_tape_wrrecf(uptr, &tu_buf[ctlr][0], reclen); - sim_debug(DEBUG_DETAIL, dptr, "TU%o Write %d %d\n", - unit, reclen, uptr->CPOS); - uptr->DATAPTR = 0; - uptr->hwmark = 0; - df10_finish_op(df,0 ); - tu_error(uptr, r); /* Record errors */ - return SCPE_OK; + /* Write out the block */ + reclen = uptr->hwmark; + r = sim_tape_wrrecf(uptr, &tu_buf[ctlr][0], reclen); + sim_debug(DEBUG_DETAIL, dptr, "%s%o Write %d %d\n", + dptr->name, unit, reclen, uptr->CPOS); + uptr->DATAPTR = 0; + uptr->hwmark = 0; + (void)rh_blkend(rhc); + tu_error(uptr, r); /* Record errors */ + rh_finish_op(rhc,0 ); + return SCPE_OK; } break; case FNC_WTM: - if ((uptr->flags & MTUF_WLK) != 0) { - tu_error(uptr, MTSE_WRP); - } else { - tu_error(uptr, sim_tape_wrtmk(uptr)); - } - uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - sim_debug(DEBUG_DETAIL, dptr, "TU%o WTM\n", unit); - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - return SCPE_OK; + uptr->CMD &= ~CS_PIP; + uptr->CMD |= CS_ATA; + if ((uptr->flags & MTUF_WLK) != 0) { + tu_error(uptr, MTSE_WRP); + } else { + tu_error(uptr, sim_tape_wrtmk(uptr)); + } + sim_debug(DEBUG_DETAIL, dptr, "%s%o WTM\n", dptr->name, unit); + return SCPE_OK; case FNC_ERASE: - if ((uptr->flags & MTUF_WLK) != 0) { - tu_error(uptr, MTSE_WRP); - } else { - tu_error(uptr, sim_tape_wrgap(uptr, 35)); - } - uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - sim_debug(DEBUG_DETAIL, dptr, "TU%o ERG\n", unit); - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - return SCPE_OK; + uptr->CMD &= ~CS_PIP; + uptr->CMD |= CS_ATA; + if ((uptr->flags & MTUF_WLK) != 0) { + tu_error(uptr, MTSE_WRP); + } else { + tu_error(uptr, sim_tape_wrgap(uptr, 35)); + } + sim_debug(DEBUG_DETAIL, dptr, "%s%o ERG\n", dptr->name, unit); + return SCPE_OK; case FNC_SPACEF: case FNC_SPACEB: - sim_debug(DEBUG_DETAIL, dptr, "TU%o space %o\n", unit, GET_FNC(uptr->CMD)); - if (tu_frame[ctlr] == 0) { - uptr->STATUS |= ER1_NEF; - uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - tu_error(uptr, MTSE_OK); - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - return SCPE_OK; - } - uptr->CMD |= CS_MOTION; - /* Always skip at least one record */ - if (GET_FNC(uptr->CMD) == FNC_SPACEF) - r = sim_tape_sprecf(uptr, &reclen); - else - r = sim_tape_sprecr(uptr, &reclen); - switch (r) { - case MTSE_OK: /* no error */ - break; + sim_debug(DEBUG_DETAIL, dptr, "%s%o space %o\n", dptr->name, unit, GET_FNC(uptr->CMD)); + uptr->CMD &= ~CS_PIP; + if (tu_frame[ctlr] == 0) { + uptr->STATUS |= ER1_NEF; + uptr->CMD |= CS_ATA; + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } + uptr->CMD |= CS_MOTION; + /* Always skip at least one record */ + if (GET_FNC(uptr->CMD) == FNC_SPACEF) + r = sim_tape_sprecf(uptr, &reclen); + else + r = sim_tape_sprecr(uptr, &reclen); + tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1); + switch (r) { + case MTSE_OK: /* no error */ + break; - case MTSE_BOT: /* beginning of tape */ - uptr->STATUS |= ER1_NEF; - /* Fall Through */ + case MTSE_BOT: /* beginning of tape */ + uptr->STATUS |= ER1_NEF; + /* Fall Through */ - case MTSE_TMK: /* tape mark */ - case MTSE_EOM: /* end of medium */ - if (tu_frame[ctlr] != 0) - uptr->STATUS |= ER1_FCE; - uptr->CMD &= ~(CR_GO); - uptr->CMD |= CS_ATA; - tu_attn[ctlr] = 1; - /* Stop motion if we recieve any of these */ - tu_error(uptr, r); - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - return SCPE_OK; - } - tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1); - if (tu_frame[ctlr] == 0) { - tu_error(uptr, MTSE_OK); - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); - return SCPE_OK; - } else - sim_activate(uptr, 5000); - return SCPE_OK; + case MTSE_TMK: /* tape mark */ + case MTSE_EOM: /* end of medium */ + if (tu_frame[ctlr] != 0) + uptr->STATUS |= ER1_FCE; + else + tu_tcr[ctlr] &= ~(TC_FCS); + uptr->CMD |= CS_ATA; + /* Stop motion if we recieve any of these */ + tu_error(uptr, r); + return SCPE_OK; + } + if (tu_frame[ctlr] == 0) { + uptr->CMD |= CS_ATA; + tu_error(uptr, MTSE_OK); + return SCPE_OK; + } else { + tu_tcr[ctlr] &= ~(TC_FCS); + sim_activate(uptr, reclen * 50); + } + return SCPE_OK; } - sim_activate(uptr, 200); + sim_activate(uptr, 20); return SCPE_OK; } @@ -1024,11 +796,8 @@ tu_reset(DEVICE * dptr) { int ctlr; for (ctlr = 0; ctlr < NUM_DEVS_TU; ctlr++) { - tu_df10[ctlr].devnum = tu_dib[ctlr].dev_num; - tu_df10[ctlr].nxmerr = 19; - tu_df10[ctlr].ccw_comp = 14; - tu_attn[ctlr] = 0; - tu_rae[ctlr] = 0; + tu_rh[ctlr].attn = 0; + tu_rh[ctlr].rae = 0; } return SCPE_OK; } @@ -1102,20 +871,15 @@ tu_boot(int32 unit_num, DEVICE * dptr) t_stat tu_attach(UNIT * uptr, CONST char *file) { t_stat r; - int ctlr = GET_CNTRL(uptr->flags); - struct df10 *df; - - /* Find df10 */ - df = &tu_df10[ctlr]; + int ctlr = GET_CNTRL_RH(uptr->flags); + struct rh_if *rhc = &tu_rh[ctlr]; uptr->CMD = 0; uptr->STATUS = 0; r = sim_tape_attach_ex(uptr, file, 0, 0); if (r == SCPE_OK) { uptr->CMD = CS_ATA|CS_CHANGE; - tu_attn[ctlr] = 1; - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); + rh_setattn(rhc, 0); } return r; } @@ -1123,16 +887,13 @@ tu_attach(UNIT * uptr, CONST char *file) t_stat tu_detach(UNIT * uptr) { - int ctlr = GET_CNTRL(uptr->flags); - struct df10 *df; + int ctlr = GET_CNTRL_RH(uptr->flags); + struct rh_if *rhc = &tu_rh[ctlr]; /* Find df10 */ - df = &tu_df10[ctlr]; uptr->STATUS = 0; uptr->CMD = CS_ATA|CS_CHANGE; - tu_attn[ctlr] = 1; - if ((df->status & IADR_ATTN) != 0) - df10_setirq(df); + rh_setattn(rhc, 0); return sim_tape_detach(uptr); } diff --git a/README.md b/README.md index d06d307..c49f0d0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Coverity Scan Build Status](https://scan.coverity.com/projects/12020/badge.svg)](https://scan.coverity.com/projects/rcornwell-sims) -This is a working copy of my Burroughs B5500, Dec PDP6, KA10, KI10, SEL32, IBM 360 and IBM7000 -series simulators for SimH. +This is a working copy of my Burroughs B5500, Dec PDP6, KA10, KI10, KL10, SEL32, IBM 360 +and IBM7000 series simulators for SimH. # Stable released simulators. @@ -64,7 +64,14 @@ Latest status for I7000 Cpus: Emulates a dual CPU B5500 with up to 32K of memory. I can support either DFX disks or dual disks up to 20 units. Up to 16 magnetic tapes drives is support. 2 Card readers - a card punch and a pair of line printers. + a card punch and a pair of line printers. Will run MCP XIII and XV. + + * Up to either 10 disks with DFX support or 20 disks without. + * Up to 16 magnetic tape drives. + * Dual card reader. + * Dual Line printer. + * Single card punch. + * Up to 32 terminal lines. # Dec PDP6 @@ -88,76 +95,60 @@ The PDP6 runs TOPS 10 4.5 off Dectape. Type 340 graphics display. -# Dec KA10 & KI10 +# Dec KA10 & KI10 & KL10 -These are nearing release. Please report any issues that you find in them. - -The KA10 sim has successfully run Tops 10 4.5, 5.03 and Tops 10 6.03. -The KI10 sim has successfully run Tops 10 6.03 with VMSER -The KA10 sim has successfully run ITS. -The KA10 sim has successfully run WAITS (with and without BBN pager). +The KA10 sim has successfully run Tops 10 4.5, 5.03 and 6.03, ITS and WAITS. +The KI10 sim has successfully run Tops 10 6.03 with VMSER. +The KL10 sim has successfully run Tops 10 6.03-7.03, ITS and Tops 20 V2-V7. Disk * RC10 RD10/RM10 * RP10 RP01/RP02/RP03 - * RH10 RP04/RP06/RP07 (RP07 not supported under 6.03). - * RH10 RS04 + * RH10/RH20 RP04/RP06/RP07 (RP07 not supported under 6.03). + * RH10/RH20 RS04 * PMP (P. PETIT'S IBM CHANNEL) * System Concepts DC-10 IBM 2314 Tape * TM10A or B - * RH10 TM03/TU16 + * RH10/RH20 TM03/TU16 * TD10 Dectape Paper Tape * Punch * Reader - DC10E terminal mux. - Morton tty Mux for ITS. - Knight Kludge mux for ITS. + * DC10E terminal mux. + * Morton tty Mux for ITS. + * Knight Kludge mux for ITS. + * Terminals on KL10 Front End. - IMP networking support for ITS and TENEX. - CH10 networking support for ITS. + * LP10 Line printer. + * LP20 Line printer on KL10 Front End. - 340 Display Station support. + * IMP networking support for ITS and TENEX. + * NIA20 networking support for KL10. + * CH10 networking support for ITS. - Optional support for PDP6 devices (standard if WAITS included). + * 340 Display Station support. + * III Display support for WAITS (in progress). + + * Optional support for PDP6 devices (standard if WAITS included). The RP10 supports boot (actual hardware did not), by reading in Blocks 4-7 and transfering to the loaded value. RC10, RH10, TM10 support readin mode. - Support for KL10A will be started in the summer. - -# Development Simulators. - -# Dec KL10 - -Still in initial coding stages. - - Disk - * RH10 RP04/RP06/RP07 - * RH10 RS04 - * RH20 RP04/RP06/RP07 - * RH20 RS04 - - Tape - * TM10A or B - * RH10 TM03/TU16 - * RH20 TM03/TU16 - - DC10E terminal mux. - Terminals attached to front end processor - - IMP networking support for ITS and TENEX. - # ICL 1900 simulator. This is a new simulator. Will pass 1904E/1905E CPU diagnostics (FLIT). Will boot paper tape executive E4BM and tape executive E6RM. Still need to add more devices and test with Goerge 2 and 3. + The CPU can be configured for model A, B or C type system. Or models 1901 throgh 1909. +Paging is currently not supported. Both standard interface and older non-standard interface +are supported on most device. + + # IBM 360 simulator. Currently will run IPL TOS/360, DOS/360, OS/360. TSO support still in progress. @@ -186,18 +177,14 @@ The current test version is for the SEL 32/27, 32/67, 32/87, 32/97 computers. Support for 32/55, 32/75, V6, and V9 computers may be added in the future. This simulator is co-authors with James C. Bevier. I did the initial parts of the simulator, James took it to a working simulator, I am assisting him -in maintaining and enhancing the simulator. - -# SEL Concept/32 - -This simulator is running a test version of MPX-32 1.5F. It is capable of -creating a disk image of the O/S from a SDT tape. The disk image can be -booted, initialized, and run many of the MPX utilities; including OPCOM & TSM. -Eight terminals can be used to access TSM via Telnet port 4747. Initial -support has been added for excess 64 floating point arithmetic. More testing -is still required. The sim32disk.gz can be uncompressed and booted with the -sel32.27.sim32.disk.ini initialization file. The sim32sdt.tap.gz file can -also be uncompressed and started with the sel32.27.sim32.tape.ini initialization -file to install from tape. +in maintaining and enhancing the simulator. This simulator is running a test +version of MPX-32 1.5F. It is capable of creating a disk image of the O/S +from a SDT tape. The disk image can be booted, initialized, and run many of +the MPX utilities; including OPCOM & TSM. Eight terminals can be used to +access TSM via Telnet port 4747. Initial support has been added for excess +64 floating point arithmetic. More testing is still required. The sim32disk.gz +can be uncompressed and booted with the sel32.27.sim32.disk.ini initialization file. +The sim32sdt.tap.gz file can also be uncompressed and started with the +sel32.27.sim32.tape.ini initialization file to install from tape. diff --git a/display/display.c b/display/display.c index 5ad0691..22efa6e 100644 --- a/display/display.c +++ b/display/display.c @@ -975,6 +975,18 @@ display_init(enum display_type type, int sf, void *dptr) fprintf(stderr, "Display initialization failed\r\n"); return 0; } + +void +display_close(void *dptr) +{ + if (!initialized) + return; + + free (points); + ws_shutdown(); + + initialized = 0; +} void display_reset(void) diff --git a/display/display.h b/display/display.h index 391bf4e..239d102 100644 --- a/display/display.h +++ b/display/display.h @@ -65,6 +65,11 @@ enum display_type { */ extern int display_init(enum display_type, int scale, void *dptr); +/* + * close display + */ +extern void display_close(void *dptr); + /* return size of virtual display */ extern int display_xpoints(void); extern int display_ypoints(void); diff --git a/doc/ka10_doc.doc b/doc/ka10_doc.doc index 58e8d19..637e825 100644 Binary files a/doc/ka10_doc.doc and b/doc/ka10_doc.doc differ diff --git a/doc/ki10_doc.doc b/doc/ki10_doc.doc index 42c1f6b..c772f57 100644 Binary files a/doc/ki10_doc.doc and b/doc/ki10_doc.doc differ diff --git a/doc/kl10_doc.doc b/doc/kl10_doc.doc new file mode 100644 index 0000000..e118495 Binary files /dev/null and b/doc/kl10_doc.doc differ diff --git a/makefile b/makefile index fc55a25..498c419 100644 --- a/makefile +++ b/makefile @@ -109,8 +109,8 @@ endif ifneq (,$(or $(findstring pdp6,${MAKECMDGOALS}),$(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS}))) VIDEO_USEFUL = true endif -# building the KA10 or KI10 networking can be used. -ifneq (,$(or $(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS}))) +# building the KA10, KI10 or KL10 networking can be used. +ifneq (,$(or $(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS},$(findstring pdp10-kl,${MAKECMDGOALS})))) NETWORK_USEFUL = true endif # building the PDP-7 needs video support @@ -2023,13 +2023,13 @@ KA10 = ${KA10D}/kx10_cpu.c ${KA10D}/kx10_sys.c ${KA10D}/kx10_df.c \ ${KA10D}/kx10_rp.c ${KA10D}/kx10_rc.c ${KA10D}/kx10_dt.c \ ${KA10D}/kx10_dk.c ${KA10D}/kx10_cr.c ${KA10D}/kx10_cp.c \ ${KA10D}/kx10_tu.c ${KA10D}/kx10_rs.c ${KA10D}/ka10_pd.c \ - ${KA10D}/kx10_imp.c ${KA10D}/ka10_tk10.c \ + ${KA10D}/kx10_rh.c ${KA10D}/kx10_imp.c ${KA10D}/ka10_tk10.c \ ${KA10D}/ka10_mty.c ${KA10D}/ka10_imx.c ${KA10D}/ka10_ch10.c \ ${KA10D}/ka10_stk.c ${KA10D}/ka10_ten11.c ${KA10D}/ka10_auxcpu.c \ $(KA10D)/ka10_pmp.c ${KA10D}/ka10_dkb.c ${KA10D}/pdp6_dct.c \ ${KA10D}/pdp6_dtc.c ${KA10D}/pdp6_mtc.c ${KA10D}/pdp6_dsk.c \ ${KA10D}/pdp6_dcs.c ${KA10D}/ka10_dpk.c ${KA10D}/kx10_dpy.c \ - ${PDP10D}/ka10_ai.c ${DISPLAYL} ${DISPLAY340} + ${PDP10D}/ka10_ai.c ${KA10D}/ka10_iii.c ${DISPLAYL} ${DISPLAY340} KA10_OPT = -DKA=1 -DUSE_INT64 -I ${KA10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KA10_DISPLAY_OPT} ifneq (${PANDA_LIGHTS},) # ONLY for Panda display. @@ -2045,7 +2045,7 @@ endif KI10 = ${KI10D}/kx10_cpu.c ${KI10D}/kx10_sys.c ${KI10D}/kx10_df.c \ ${KI10D}/kx10_dp.c ${KI10D}/kx10_mt.c ${KI10D}/kx10_cty.c \ ${KI10D}/kx10_lp.c ${KI10D}/kx10_pt.c ${KI10D}/kx10_dc.c \ - ${KI10D}/kx10_rp.c ${KI10D}/kx10_rc.c \ + ${KI10D}/kx10_rh.c ${KI10D}/kx10_rp.c ${KI10D}/kx10_rc.c \ ${KI10D}/kx10_dt.c ${KI10D}/kx10_dk.c ${KI10D}/kx10_cr.c \ ${KI10D}/kx10_cp.c ${KI10D}/kx10_tu.c ${KI10D}/kx10_rs.c \ ${KI10D}/kx10_imp.c ${KI10D}/kx10_dpy.c ${DISPLAYL} ${DISPLAY340} @@ -2057,6 +2057,14 @@ KI10 += ${KA10D}/ka10_lights.c KI10_LDFLAGS = -lusb-1.0 endif +KL10D = ${SIMHD}/PDP10 +KL10 = ${KL10D}/kx10_cpu.c ${KL10D}/kx10_sys.c ${KL10D}/kx10_df.c \ + ${KL10D}/kx10_mt.c ${KL10D}/kx10_dc.c ${KL10D}/kx10_rh.c \ + ${KL10D}/kx10_rp.c ${KL10D}/kx10_tu.c ${KL10D}/kx10_rs.c \ + ${KL10D}/kx10_imp.c ${KL10D}/kl10_fe.c ${KL10D}/ka10_pd.c \ + ${KL10D}/ka10_ch10.c ${KL10D}/kx10_lp.c ${KL10D}/kl10_nia.c +KL10_OPT = -DKL=1 -DUSE_INT64 -I $(KL10D) -DUSE_SIM_CARD ${NETWORK_OPT} + ATT3B2D = ${SIMHD}/3B2 ATT3B2 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_mmu.c \ ${ATT3B2D}/3b2_iu.c ${ATT3B2D}/3b2_if.c \ @@ -2131,7 +2139,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ scelbi 3b2 i701 i704 i7010 i7070 i7080 i7090 \ sigma uc15 pdp10-ka pdp10-ki pdp6 -ALL = b5500 i701 i704 i7010 i7070 i7080 i7090 pdp10-ka pdp10-ki ibm360 ibm360_32 icl1900 pdp6 sel32 +ALL = b5500 i701 i704 i7010 i7070 i7080 i7090 pdp10-ka pdp10-ki pdp10-kl ibm360 ibm360_32 icl1900 pdp6 sel32 all : ${ALL} @@ -2965,6 +2973,15 @@ ifneq (,$(call find_test,${PDP10D},ki10)) $@ $(call find_test,${PDP10D},ki10) ${TEST_ARG} endif +pdp10-kl : ${BIN}pdp10-kl${EXE} + +${BIN}pdp10-kl${EXE} : ${KL10} ${SIM} + ${MKDIRBIN} + ${CC} ${KL10} ${SIM} ${KL10_OPT} ${CC_OUTSPEC} ${LDFLAGS} +ifneq (,$(call find_test,${PDP10D},kl10)) + $@ $(call find_test,${PDP10D},kl10) ${TEST_ARG} +endif + # Front Panel API Demo/Test program frontpaneltest : ${BIN}frontpaneltest${EXE}