diff --git a/PDP10/ka10_iii.c b/PDP10/ka10_iii.c index b57c56d..2796cee 100644 --- a/PDP10/ka10_iii.c +++ b/PDP10/ka10_iii.c @@ -1,623 +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 +/* 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/kl10_fe.c b/PDP10/kl10_fe.c index 9e7be88..3031978 100644 --- a/PDP10/kl10_fe.c +++ b/PDP10/kl10_fe.c @@ -1,2118 +1,2118 @@ -/* 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_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_EMACK 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 */ - -#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 */ - -char *pri_name[] = { "(0)", "EM2EI", "EM2TI", "EMSTR", "EMLNC", "EMRDS", "(6)", - "EMHDS", "(10)", "EMRDT", "EMHDR", "EMFLO", "EMSNA", "EMDSC", "EMHUD", - "EMACK", "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[256]; /* 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; - -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_LP -#define NUM_DEVS_LP 0 -#endif - -#if (NUM_DEVS_LP > 0) - -#define COL u4 -#define POS u5 -#define LINE u6 - -#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 lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); -t_stat lpt_attach (UNIT *uptr, CONST char *cptr); -t_stat lpt_detach (UNIT *uptr); -t_stat lpt_setlpp(UNIT *, int32, CONST char *, void *); -t_stat lpt_getlpp(FILE *, UNIT *, int32, CONST void *); -t_stat lpt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, - const char *cptr); -const char *lpt_description (DEVICE *dptr); - -char lpt_buffer[134 * 3]; - -struct _buffer lpt_queue; - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_reg LPT register list -*/ - -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 66), 100 - }; - -REG lpt_reg[] = { - { BRDATA(BUFF, lpt_buffer, 16, 8, sizeof(lpt_buffer)), REG_HRO}, - { NULL } -}; - -MTAB lpt_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", - &lpt_setlpp, &lpt_getlpp, NULL, "Number of lines per page"}, - { 0 } -}; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lpt_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &lpt_reset, - NULL, &lpt_attach, &lpt_detach, - NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, - NULL, NULL, &lpt_help, NULL, NULL, &lpt_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); - 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 (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) { - sim_activate(uptr, 200); - return; - } - if (ch != 0) { - ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); - cty_out.buff[cty_out.in_ptr] = (char)(word & 0x7f); - cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; - 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; - break; - case SEC_SETDDT: /* Read character from console */ - if (cty_in.in_ptr == cty_in.out_ptr) { - M[SEC_DTF11 + base] = 0; - M[SEC_DTMTI + base] = FMASK; - break; - } - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - 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 (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) - 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; - cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; - 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 (((otty->in_ptr + 1) & 0xff) == otty->out_ptr) - 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; - otty->in_ptr = (otty->in_ptr + 1) & 0xff; - 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); - } - 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\n", - *dp, *dp >> 8, *dp & 0377, ((*dp & 0377) << 8) | ((*dp >> 8) & 0377)); - 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->sdev = in->dcnt = in->data[0]; - 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; - - /* 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]; - 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_LP > 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_EMACK: /* 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_LP > 0) - /* Handle printer data */ - if (cmd->dev == PRI_EMLPT) { - if (!sim_is_active(&lpt_unit)) - sim_activate(&lpt_unit, 1000); - while (cmd->dptr < cmd->dcnt) { - if (((lpt_queue.in_ptr + 1) & 0xff) == lpt_queue.out_ptr) - return; - ch = (int32)(cmd->data[cmd->dptr >> 1]); - if ((cmd->dptr & 1) == 0) - ch >>= 8; - ch &= 0177; - lpt_queue.buff[lpt_queue.in_ptr] = ch; - lpt_queue.in_ptr = (lpt_queue.in_ptr + 1) & 0xff; - cmd->dptr++; - } - if (cmd->dptr != cmd->dcnt) - return; - break; - } -#endif - -#if (NUM_DEVS_TTY > 0) - /* Handle terminal data */ - if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377); - struct _buffer *otty; - if (ln == PRI_CTYDV) - goto cty; - ln -= 2; - 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) { - if (((otty->in_ptr + 1) & 0xff) == otty->out_ptr) - return; - ch = (int32)(cmd->data[cmd->dptr >> 1]); - if ((cmd->dptr & 1) == 0) - ch >>= 8; - ch &= 0177; - if (ch != 0) { - sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %o %d\n", ch, ln); - otty->buff[otty->in_ptr] = ch; - otty->in_ptr = (otty->in_ptr + 1) & 0xff; - } - cmd->dptr++; - } - if (cmd->dptr != cmd->dcnt) - return; - break; - } -#endif - /* Fall through */ - case PRI_EMSNA: /* Send all (ttys) */ - if (cmd->dev != PRI_EMCTY) - break; -cty: - sim_activate(&dte_unit[1], 100); - data1[0] = 0; - if (cmd->sz > 8) - cmd->dcnt += cmd->dcnt; - while (cmd->dptr < cmd->dcnt) { - if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) - return; - ch = (int32)(cmd->data[cmd->dptr >> 1]); - if ((cmd->dptr & 1) == 0) - ch >>= 8; - ch &= 0177; - if (ch != 0) { - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %o\n", ch); - ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); - cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); - cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; - } - cmd->dptr++; - } - if (cmd->dptr != cmd->dcnt) - return; - break; - - case PRI_EMLNC: /* Line-Char */ - if (cmd->dev == PRI_EMDLS) { - sim_activate(&dte_unit[1], 100); - while (cmd->dptr < cmd->dcnt) { - int ln; - if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) - return; - ch = (int32)(cmd->data[cmd->dptr >> 1]); - ln = (ch >> 8); - ch &= 0177; - if (ch != 0 && ln == 0) { - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %o\n", ch); - ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); - cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); - cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; - } - cmd->dptr+=2; - } - if (cmd->dptr != cmd->dcnt) - return; - } - break; - - case PRI_EMRDS: /* Request device status */ -#if (NUM_DEVS_LP > 0) - if (cmd->dev == PRI_EMLPT) { - data1[0] = 0; - if (dte_queue(PRI_EMHDS, PRI_EMLPT, 1, data1) == 0) - return; - } -#endif - if (cmd->dev == PRI_EMCTY) { - data1[0] = 0; - if (dte_queue(PRI_EMHDS, PRI_EMCTY, 1, data1) == 0) - return; - } - if (cmd->dev == PRI_EMDH1) { - data1[0] = 0; - if (dte_queue(PRI_EMHDS, PRI_EMDH1, 1, data1) == 0) - return; - } - break; - - case PRI_EMHDS: /* Here is device status */ - break; - -#if (NUM_DEVS_TTY > 0) - case PRI_EMFLO: /* Flush output */ - if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 2;; - tty_out[ln].in_ptr = tty_out[ln].out_ptr = 0; - } - break; - case PRI_EMDSC: /* Dataset connect */ - break; - case PRI_EMHUD: /* Hang up dataset */ - if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 2; - 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 ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 2; - tty_ldsc[ln].rcve = 0; - } - break; - case PRI_EMXON: /* XON line */ - if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 2; - tty_ldsc[ln].rcve = 1; - } - break; - case PRI_EMHLS: /* Here is line speeds */ - if ((cmd->dev & 0377) == PRI_EMDLS) { - int ln = ((cmd->sdev >> 8) & 0377) - 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]; - 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 - case PRI_EMLDR: /* Load LP RAM */ - case PRI_EMLDV: /* Load LP VFU */ - 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\n", - dte_out_ptr, dte_out_res, 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) { -sim_debug(DEBUG_DATA, &dte_dev, "DTE: Indirect %o %o\n", cnt, out->dcnt); - if (!Mem_write_byte(0, &out->dcnt)) - 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 (cty_in.in_ptr != cty_in.out_ptr) { - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - word = (uint64)ch; -#if (NUM_DEVS_TTY > 0) - } else { - ln = uptr->CNT; - while ((word & SMASK) != 0) { - if (tty_in[ln].in_ptr != tty_in[ln].out_ptr) { - ch = tty_in[ln].buff[tty_in[ln].out_ptr]; - tty_in[ln].out_ptr = (tty_in[ln].out_ptr + 1) & 0xff; - 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_EMACK, 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 (cty_in.in_ptr != cty_in.out_ptr && n < 32) { - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - 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++) { - while (tty_in[ln].in_ptr != tty_in[ln].out_ptr) { - ch = tty_in[ln].buff[tty_in[ln].out_ptr]; - tty_in[ln].out_ptr = (tty_in[ln].out_ptr + 1) & 0xff; - dataq[n++] = ((ln + 2) << 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++) { - if (tty_connect[ln] != tty_ldsc[ln].conn) { - data1 = ln + 2; - 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]) { - data1 = ln + 2; - if (dte_queue(PRI_EMACK, 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 %s %o\n", - dte_out_ptr, dte_out_res, out->cnt, 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); - 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 */ - word = (uint64)dcnt; - if ((uptr->STATUS & DTE_SIND) != 0) { - word = (uint64)(dte_out[dte_out_ptr].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 (((cty_in.in_ptr + 1) & 0xff) != cty_in.out_ptr) { - 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; - cty_in.in_ptr = (cty_in.in_ptr + 1) & 0xff; - 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) && - cty_in.in_ptr != cty_in.out_ptr && M[SEC_DTMTI + base] == 0) { - ch = cty_in.buff[cty_in.out_ptr]; - cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; - 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(cty_out.in_ptr != cty_out.out_ptr) { - 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;; - } - } - cty_out.out_ptr = (cty_out.out_ptr + 1) & 0xff; - sim_debug(DEBUG_DETAIL, &dte_dev, "CTY outch %o '%c'\n", ch, - ((ch > 040 && ch < 0177)? ch: '.')); - } - cty_done++; - dte_input(); - 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_LP > 0) - -void -lpt_printline(UNIT *uptr, int nl) { - int trim = 0; - uint16 data1 = 1; - /* Trim off trailing blanks */ - while (uptr->COL >= 0 && lpt_buffer[uptr->POS - 1] == ' ') { - uptr->COL--; - uptr->POS--; - trim = 1; - } - lpt_buffer[uptr->POS] = '\0'; - sim_debug(DEBUG_DETAIL, &lpt_dev, "LP output %d %d [%s]\n", uptr->COL, nl, lpt_buffer); - /* Stick a carraige return and linefeed as needed */ - if (uptr->COL != 0 || trim) - lpt_buffer[uptr->POS++] = '\r'; - if (nl != 0) { - lpt_buffer[uptr->POS++] = '\n'; - uptr->LINE++; - } - if (nl > 0 && uptr->LINE >= ((int32)uptr->capac - MARGIN)) { - lpt_buffer[uptr->POS++] = '\f'; - uptr->LINE = 0; - } else if (nl < 0 && uptr->LINE >= (int32)uptr->capac) { - uptr->LINE = 0; - } - - sim_fwrite(&lpt_buffer, 1, uptr->POS, uptr->fileref); - uptr->pos += uptr->POS; - uptr->COL = 0; - uptr->POS = 0; - return; -} - - -/* Unit service */ -void -lpt_output(UNIT *uptr, char c) { - - if (c == 0) - return; - if (uptr->COL == 132) - lpt_printline(uptr, 1); - if ((uptr->flags & UNIT_UC) && (c & 0140) == 0140) - c &= 0137; - else if (c >= 040 && c < 0177) { - lpt_buffer[uptr->POS++] = c; - uptr->COL++; - } - return; -} - -t_stat lpt_svc (UNIT *uptr) -{ - char c; - uint16 data1 = 0; - - if ((uptr->flags & UNIT_ATT) == 0) - return SCPE_OK; - - while (((lpt_queue.out_ptr + 1) & 0xff) != lpt_queue.in_ptr) { - c = lpt_queue.buff[lpt_queue.out_ptr]; - lpt_queue.out_ptr = (lpt_queue.out_ptr + 1) & 0xff; - if (c < 040) { /* Control character */ - switch(c) { - case 011: /* Horizontal tab, space to 8'th column */ - lpt_output(uptr, ' '); - while ((uptr->COL & 07) != 0) - lpt_output(uptr, ' '); - break; - case 015: /* Carriage return, print line */ - lpt_printline(uptr, 0); - break; - case 012: /* Line feed, print line, space one line */ - lpt_printline(uptr, 1); - break; - case 014: /* Form feed, skip to top of page */ - lpt_printline(uptr, 0); - sim_fwrite("\014", 1, 1, uptr->fileref); - uptr->pos++; - uptr->LINE = 0; - break; - case 013: /* Vertical tab, Skip mod 20 */ - lpt_printline(uptr, 1); - while((uptr->LINE % 20) != 0) { - sim_fwrite("\r\n", 1, 2, uptr->fileref); - uptr->pos+=2; - uptr->LINE++; - } - break; - case 020: /* Skip half page */ - lpt_printline(uptr, 1); - while((uptr->LINE % 30) != 0) { - sim_fwrite("\r\n", 1, 2, uptr->fileref); - uptr->pos+=2; - uptr->LINE++; - } - break; - case 021: /* Skip even lines */ - lpt_printline(uptr, 1); - while((uptr->LINE % 2) != 0) { - sim_fwrite("\r\n", 1, 2, uptr->fileref); - uptr->pos+=2; - uptr->LINE++; - } - break; - case 022: /* Skip triple lines */ - lpt_printline(uptr, 1); - while((uptr->LINE % 3) != 0) { - sim_fwrite("\r\n", 1, 2, uptr->fileref); - uptr->pos+=2; - uptr->LINE++; - } - break; - case 023: /* Skip one line */ - lpt_printline(uptr, -1); - break; - default: /* Ignore */ - break; - } - } else { - sim_debug(DEBUG_DETAIL, &lpt_dev, "LP deque %02x '%c'\n", c, c); - lpt_output(uptr, c); - } - } - if (dte_queue(PRI_EMACK, PRI_EMLPT, 1, &data1) == 0) - sim_activate(uptr, 1000); - return SCPE_OK; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ - UNIT *uptr = &lpt_unit; - uptr->POS = 0; - uptr->COL = 0; - uptr->LINE = 1; - sim_cancel (&lpt_unit); /* deactivate unit */ - return SCPE_OK; -} - -/* Attach routine */ - -t_stat lpt_attach (UNIT *uptr, CONST char *cptr) -{ - return attach_unit (uptr, cptr); -} - -/* Detach routine */ - -t_stat lpt_detach (UNIT *uptr) -{ - return detach_unit (uptr); -} - -/* - * Line printer routines - */ - -t_stat -lpt_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 -lpt_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 lpt_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 *lpt_description (DEVICE *dptr) -{ - return "LPT0 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 && ((iptr->in_ptr + 1) & 0xff) != iptr->out_ptr) { - /* 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; - iptr->in_ptr = (iptr->in_ptr + 1) & 0xff; - 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) - continue; - if (optr->out_ptr == optr->in_ptr) - continue; - while (optr->out_ptr != optr->in_ptr) { - 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) - optr->out_ptr = (optr->out_ptr + 1) & 0xff; - 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 +/* 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_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_EMACK 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 */ + +#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 */ + +char *pri_name[] = { "(0)", "EM2EI", "EM2TI", "EMSTR", "EMLNC", "EMRDS", "(6)", + "EMHDS", "(10)", "EMRDT", "EMHDR", "EMFLO", "EMSNA", "EMDSC", "EMHUD", + "EMACK", "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[256]; /* 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; + +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_LP +#define NUM_DEVS_LP 0 +#endif + +#if (NUM_DEVS_LP > 0) + +#define COL u4 +#define POS u5 +#define LINE u6 + +#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 lpt_svc (UNIT *uptr); +t_stat lpt_reset (DEVICE *dptr); +t_stat lpt_attach (UNIT *uptr, CONST char *cptr); +t_stat lpt_detach (UNIT *uptr); +t_stat lpt_setlpp(UNIT *, int32, CONST char *, void *); +t_stat lpt_getlpp(FILE *, UNIT *, int32, CONST void *); +t_stat lpt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr); +const char *lpt_description (DEVICE *dptr); + +char lpt_buffer[134 * 3]; + +struct _buffer lpt_queue; + +/* LPT data structures + + lpt_dev LPT device descriptor + lpt_unit LPT unit descriptor + lpt_reg LPT register list +*/ + +UNIT lpt_unit = { + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 66), 100 + }; + +REG lpt_reg[] = { + { BRDATA(BUFF, lpt_buffer, 16, 8, sizeof(lpt_buffer)), REG_HRO}, + { NULL } +}; + +MTAB lpt_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", + &lpt_setlpp, &lpt_getlpp, NULL, "Number of lines per page"}, + { 0 } +}; + +DEVICE lpt_dev = { + "LPT", &lpt_unit, lpt_reg, lpt_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &lpt_reset, + NULL, &lpt_attach, &lpt_detach, + NULL, DEV_DISABLE | DEV_DEBUG, 0, dev_debug, + NULL, NULL, &lpt_help, NULL, NULL, &lpt_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); + 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 (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) { + sim_activate(uptr, 200); + return; + } + if (ch != 0) { + ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); + cty_out.buff[cty_out.in_ptr] = (char)(word & 0x7f); + cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; + 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; + break; + case SEC_SETDDT: /* Read character from console */ + if (cty_in.in_ptr == cty_in.out_ptr) { + M[SEC_DTF11 + base] = 0; + M[SEC_DTMTI + base] = FMASK; + break; + } + ch = cty_in.buff[cty_in.out_ptr]; + cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; + 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 (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) + 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; + cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; + 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 (((otty->in_ptr + 1) & 0xff) == otty->out_ptr) + 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; + otty->in_ptr = (otty->in_ptr + 1) & 0xff; + 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); + } + 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\n", + *dp, *dp >> 8, *dp & 0377, ((*dp & 0377) << 8) | ((*dp >> 8) & 0377)); + 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->sdev = in->dcnt = in->data[0]; + 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; + + /* 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]; + 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_LP > 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_EMACK: /* 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_LP > 0) + /* Handle printer data */ + if (cmd->dev == PRI_EMLPT) { + if (!sim_is_active(&lpt_unit)) + sim_activate(&lpt_unit, 1000); + while (cmd->dptr < cmd->dcnt) { + if (((lpt_queue.in_ptr + 1) & 0xff) == lpt_queue.out_ptr) + return; + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + lpt_queue.buff[lpt_queue.in_ptr] = ch; + lpt_queue.in_ptr = (lpt_queue.in_ptr + 1) & 0xff; + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; + break; + } +#endif + +#if (NUM_DEVS_TTY > 0) + /* Handle terminal data */ + if ((cmd->dev & 0377) == PRI_EMDLS) { + int ln = ((cmd->sdev >> 8) & 0377); + struct _buffer *otty; + if (ln == PRI_CTYDV) + goto cty; + ln -= 2; + 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) { + if (((otty->in_ptr + 1) & 0xff) == otty->out_ptr) + return; + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + if (ch != 0) { + sim_debug(DEBUG_DETAIL, &dte_dev, "TTY queue %o %d\n", ch, ln); + otty->buff[otty->in_ptr] = ch; + otty->in_ptr = (otty->in_ptr + 1) & 0xff; + } + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; + break; + } +#endif + /* Fall through */ + case PRI_EMSNA: /* Send all (ttys) */ + if (cmd->dev != PRI_EMCTY) + break; +cty: + sim_activate(&dte_unit[1], 100); + data1[0] = 0; + if (cmd->sz > 8) + cmd->dcnt += cmd->dcnt; + while (cmd->dptr < cmd->dcnt) { + if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) + return; + ch = (int32)(cmd->data[cmd->dptr >> 1]); + if ((cmd->dptr & 1) == 0) + ch >>= 8; + ch &= 0177; + if (ch != 0) { + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %o\n", ch); + ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); + cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); + cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; + } + cmd->dptr++; + } + if (cmd->dptr != cmd->dcnt) + return; + break; + + case PRI_EMLNC: /* Line-Char */ + if (cmd->dev == PRI_EMDLS) { + sim_activate(&dte_unit[1], 100); + while (cmd->dptr < cmd->dcnt) { + int ln; + if (((cty_out.in_ptr + 1) & 0xff) == cty_out.out_ptr) + return; + ch = (int32)(cmd->data[cmd->dptr >> 1]); + ln = (ch >> 8); + ch &= 0177; + if (ch != 0 && ln == 0) { + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY queue %o\n", ch); + ch = sim_tt_outcvt( ch, TT_GET_MODE(uptr->flags)); + cty_out.buff[cty_out.in_ptr] = (char)(ch & 0xff); + cty_out.in_ptr = (cty_out.in_ptr + 1) & 0xff; + } + cmd->dptr+=2; + } + if (cmd->dptr != cmd->dcnt) + return; + } + break; + + case PRI_EMRDS: /* Request device status */ +#if (NUM_DEVS_LP > 0) + if (cmd->dev == PRI_EMLPT) { + data1[0] = 0; + if (dte_queue(PRI_EMHDS, PRI_EMLPT, 1, data1) == 0) + return; + } +#endif + if (cmd->dev == PRI_EMCTY) { + data1[0] = 0; + if (dte_queue(PRI_EMHDS, PRI_EMCTY, 1, data1) == 0) + return; + } + if (cmd->dev == PRI_EMDH1) { + data1[0] = 0; + if (dte_queue(PRI_EMHDS, PRI_EMDH1, 1, data1) == 0) + return; + } + break; + + case PRI_EMHDS: /* Here is device status */ + break; + +#if (NUM_DEVS_TTY > 0) + case PRI_EMFLO: /* Flush output */ + if ((cmd->dev & 0377) == PRI_EMDLS) { + int ln = ((cmd->sdev >> 8) & 0377) - 2;; + tty_out[ln].in_ptr = tty_out[ln].out_ptr = 0; + } + break; + case PRI_EMDSC: /* Dataset connect */ + break; + case PRI_EMHUD: /* Hang up dataset */ + if ((cmd->dev & 0377) == PRI_EMDLS) { + int ln = ((cmd->sdev >> 8) & 0377) - 2; + 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 ((cmd->dev & 0377) == PRI_EMDLS) { + int ln = ((cmd->sdev >> 8) & 0377) - 2; + tty_ldsc[ln].rcve = 0; + } + break; + case PRI_EMXON: /* XON line */ + if ((cmd->dev & 0377) == PRI_EMDLS) { + int ln = ((cmd->sdev >> 8) & 0377) - 2; + tty_ldsc[ln].rcve = 1; + } + break; + case PRI_EMHLS: /* Here is line speeds */ + if ((cmd->dev & 0377) == PRI_EMDLS) { + int ln = ((cmd->sdev >> 8) & 0377) - 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]; + 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 + case PRI_EMLDR: /* Load LP RAM */ + case PRI_EMLDV: /* Load LP VFU */ + 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\n", + dte_out_ptr, dte_out_res, 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) { +sim_debug(DEBUG_DATA, &dte_dev, "DTE: Indirect %o %o\n", cnt, out->dcnt); + if (!Mem_write_byte(0, &out->dcnt)) + 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 (cty_in.in_ptr != cty_in.out_ptr) { + ch = cty_in.buff[cty_in.out_ptr]; + cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; + word = (uint64)ch; +#if (NUM_DEVS_TTY > 0) + } else { + ln = uptr->CNT; + while ((word & SMASK) != 0) { + if (tty_in[ln].in_ptr != tty_in[ln].out_ptr) { + ch = tty_in[ln].buff[tty_in[ln].out_ptr]; + tty_in[ln].out_ptr = (tty_in[ln].out_ptr + 1) & 0xff; + 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_EMACK, 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 (cty_in.in_ptr != cty_in.out_ptr && n < 32) { + ch = cty_in.buff[cty_in.out_ptr]; + cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; + 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++) { + while (tty_in[ln].in_ptr != tty_in[ln].out_ptr) { + ch = tty_in[ln].buff[tty_in[ln].out_ptr]; + tty_in[ln].out_ptr = (tty_in[ln].out_ptr + 1) & 0xff; + dataq[n++] = ((ln + 2) << 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++) { + if (tty_connect[ln] != tty_ldsc[ln].conn) { + data1 = ln + 2; + 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]) { + data1 = ln + 2; + if (dte_queue(PRI_EMACK, 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 %s %o\n", + dte_out_ptr, dte_out_res, out->cnt, 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); + 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 */ + word = (uint64)dcnt; + if ((uptr->STATUS & DTE_SIND) != 0) { + word = (uint64)(dte_out[dte_out_ptr].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 (((cty_in.in_ptr + 1) & 0xff) != cty_in.out_ptr) { + 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; + cty_in.in_ptr = (cty_in.in_ptr + 1) & 0xff; + 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) && + cty_in.in_ptr != cty_in.out_ptr && M[SEC_DTMTI + base] == 0) { + ch = cty_in.buff[cty_in.out_ptr]; + cty_in.out_ptr = (cty_in.out_ptr + 1) & 0xff; + 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(cty_out.in_ptr != cty_out.out_ptr) { + 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;; + } + } + cty_out.out_ptr = (cty_out.out_ptr + 1) & 0xff; + sim_debug(DEBUG_DETAIL, &dte_dev, "CTY outch %o '%c'\n", ch, + ((ch > 040 && ch < 0177)? ch: '.')); + } + cty_done++; + dte_input(); + 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_LP > 0) + +void +lpt_printline(UNIT *uptr, int nl) { + int trim = 0; + uint16 data1 = 1; + /* Trim off trailing blanks */ + while (uptr->COL >= 0 && lpt_buffer[uptr->POS - 1] == ' ') { + uptr->COL--; + uptr->POS--; + trim = 1; + } + lpt_buffer[uptr->POS] = '\0'; + sim_debug(DEBUG_DETAIL, &lpt_dev, "LP output %d %d [%s]\n", uptr->COL, nl, lpt_buffer); + /* Stick a carraige return and linefeed as needed */ + if (uptr->COL != 0 || trim) + lpt_buffer[uptr->POS++] = '\r'; + if (nl != 0) { + lpt_buffer[uptr->POS++] = '\n'; + uptr->LINE++; + } + if (nl > 0 && uptr->LINE >= ((int32)uptr->capac - MARGIN)) { + lpt_buffer[uptr->POS++] = '\f'; + uptr->LINE = 0; + } else if (nl < 0 && uptr->LINE >= (int32)uptr->capac) { + uptr->LINE = 0; + } + + sim_fwrite(&lpt_buffer, 1, uptr->POS, uptr->fileref); + uptr->pos += uptr->POS; + uptr->COL = 0; + uptr->POS = 0; + return; +} + + +/* Unit service */ +void +lpt_output(UNIT *uptr, char c) { + + if (c == 0) + return; + if (uptr->COL == 132) + lpt_printline(uptr, 1); + if ((uptr->flags & UNIT_UC) && (c & 0140) == 0140) + c &= 0137; + else if (c >= 040 && c < 0177) { + lpt_buffer[uptr->POS++] = c; + uptr->COL++; + } + return; +} + +t_stat lpt_svc (UNIT *uptr) +{ + char c; + uint16 data1 = 0; + + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_OK; + + while (((lpt_queue.out_ptr + 1) & 0xff) != lpt_queue.in_ptr) { + c = lpt_queue.buff[lpt_queue.out_ptr]; + lpt_queue.out_ptr = (lpt_queue.out_ptr + 1) & 0xff; + if (c < 040) { /* Control character */ + switch(c) { + case 011: /* Horizontal tab, space to 8'th column */ + lpt_output(uptr, ' '); + while ((uptr->COL & 07) != 0) + lpt_output(uptr, ' '); + break; + case 015: /* Carriage return, print line */ + lpt_printline(uptr, 0); + break; + case 012: /* Line feed, print line, space one line */ + lpt_printline(uptr, 1); + break; + case 014: /* Form feed, skip to top of page */ + lpt_printline(uptr, 0); + sim_fwrite("\014", 1, 1, uptr->fileref); + uptr->pos++; + uptr->LINE = 0; + break; + case 013: /* Vertical tab, Skip mod 20 */ + lpt_printline(uptr, 1); + while((uptr->LINE % 20) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->pos+=2; + uptr->LINE++; + } + break; + case 020: /* Skip half page */ + lpt_printline(uptr, 1); + while((uptr->LINE % 30) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->pos+=2; + uptr->LINE++; + } + break; + case 021: /* Skip even lines */ + lpt_printline(uptr, 1); + while((uptr->LINE % 2) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->pos+=2; + uptr->LINE++; + } + break; + case 022: /* Skip triple lines */ + lpt_printline(uptr, 1); + while((uptr->LINE % 3) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->pos+=2; + uptr->LINE++; + } + break; + case 023: /* Skip one line */ + lpt_printline(uptr, -1); + break; + default: /* Ignore */ + break; + } + } else { + sim_debug(DEBUG_DETAIL, &lpt_dev, "LP deque %02x '%c'\n", c, c); + lpt_output(uptr, c); + } + } + if (dte_queue(PRI_EMACK, PRI_EMLPT, 1, &data1) == 0) + sim_activate(uptr, 1000); + return SCPE_OK; +} + +/* Reset routine */ + +t_stat lpt_reset (DEVICE *dptr) +{ + UNIT *uptr = &lpt_unit; + uptr->POS = 0; + uptr->COL = 0; + uptr->LINE = 1; + sim_cancel (&lpt_unit); /* deactivate unit */ + return SCPE_OK; +} + +/* Attach routine */ + +t_stat lpt_attach (UNIT *uptr, CONST char *cptr) +{ + return attach_unit (uptr, cptr); +} + +/* Detach routine */ + +t_stat lpt_detach (UNIT *uptr) +{ + return detach_unit (uptr); +} + +/* + * Line printer routines + */ + +t_stat +lpt_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 +lpt_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 lpt_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 *lpt_description (DEVICE *dptr) +{ + return "LPT0 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 && ((iptr->in_ptr + 1) & 0xff) != iptr->out_ptr) { + /* 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; + iptr->in_ptr = (iptr->in_ptr + 1) & 0xff; + 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) + continue; + if (optr->out_ptr == optr->in_ptr) + continue; + while (optr->out_ptr != optr->in_ptr) { + 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) + optr->out_ptr = (optr->out_ptr + 1) & 0xff; + 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/kx10_rh.c b/PDP10/kx10_rh.c index 414acf4..de2bc8b 100644 --- a/PDP10/kx10_rh.c +++ b/PDP10/kx10_rh.c @@ -1,776 +1,776 @@ -/* 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; -void rh20_setup(struct rh_if *rhc); -void rh_setup(struct rh_if *rh, uint32 addr); -void rh_writecw(struct rh_if *rh, int nxm); - - -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; - rhc->devnum = dev & 0774; -#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->imode = 2; - rhc->status = 0; - } - 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) { -#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 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; - rhc->status |= RH20_CHAN_ERR; - if ((rhc->ptcr & 010) == 0) /* Write command */ - rhc->status |= RH20_LONG_WC; - } - } else if ((rhc->status & RH20_XEND) == 0) { - wrd1 |= RH20_SHRT_STS; - rhc->status |= RH20_CHAN_ERR; - if ((rhc->ptcr & 010) == 0) /* Write command */ - rhc->status |= RH20_SHRT_WC; - } - wrd1 |= RH20_NADR_PAR; - M[eb_ptr|chan|1] = wrd1; - M[eb_ptr|chan|2] = ((uint64)rhc->cop << 33) | - (((uint64)wc) << CSHIFT) | - ((uint64)(rhc->cda) & AMASK); -//fprintf(stderr, "RH20 final %012llo %012llo %06o\n\r", M[eb_ptr|chan|1], M[eb_ptr|chan|2], wc); - } - return; - } -#endif - if (nxm) - rhc->status |= CXR_NXM; - rhc->status |= CCW_COMP_1; - if (rhc->wcr != 0) - rhc->cda++; - M[rhc->cia|1] = ((uint64)(rhc->ccw & WMASK) << CSHIFT) | ((uint64)(rhc->cda) & AMASK); -} - -/* 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)) - rh20_setup(rhc); -#endif -} - -#if KL -/* Set up for a RH20 transfer */ -void rh20_setup(struct rh_if *rhc) -{ - int reg; - DEVICE *dptr; - - 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; -// reg = rhc->dev_read(dptr, rhc, 1); - // if ((reg & (DS_DRY|DS_DPR|DS_ERR)) != (DS_DRY|DS_DPR)) - // return; - if (rhc->status & RH20_SBAR) { - rhc->drive = (rhc->pbar >> 18) & 07; - 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; - 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; -#if KL - if (rhc->imode == 2 && (rhc->cop & 2) != 0) { -// rh_finish_op(rhc, 0); - return 0; - } -#endif - if (rhc->ccw > MEMSIZE) { - rh_finish_op(rhc, 1); - return 0; - } - data = M[rhc->ccw]; -#if KL - if (rhc->imode == 2) { -//fprintf(stderr, "RH20 fetch %06o %012llo\n\r", rhc->ccw, data); - while((data & RH20_XFER) == 0) { - rhc->ccw = (uint32)(data & AMASK); - if ((data & (BIT1|BIT2)) == 0) { -// rh_finish_op(rhc, 0); - return 0; - } - if (rhc->ccw > MEMSIZE) { - rh_finish_op(rhc, 1); - return 0; - } - data = M[rhc->ccw]; -//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 (rhc->ccw > MEMSIZE) { - rh_finish_op(rhc, 1); - return 0; - } - data = M[rhc->ccw]; - } - 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) { - data = M[rhc->cda]; - 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); - data = M[rhc->cda]; - } -#else - rhc->cda = (uint32)((rhc->cda + 1) & AMASK); - data = M[rhc->cda]; -#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) { - M[rhc->cda] = rhc->buf; - 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); - M[rhc->cda] = rhc->buf; - } -#else - rhc->cda = (uint32)((rhc->cda + 1) & AMASK); - M[rhc->cda] = rhc->buf; -#endif - } - if (rhc->wcr == 0) { - return rh_fetch(rhc); - } - return 1; -} - +/* 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; +void rh20_setup(struct rh_if *rhc); +void rh_setup(struct rh_if *rh, uint32 addr); +void rh_writecw(struct rh_if *rh, int nxm); + + +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; + rhc->devnum = dev & 0774; +#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->imode = 2; + rhc->status = 0; + } + 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) { +#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 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; + rhc->status |= RH20_CHAN_ERR; + if ((rhc->ptcr & 010) == 0) /* Write command */ + rhc->status |= RH20_LONG_WC; + } + } else if ((rhc->status & RH20_XEND) == 0) { + wrd1 |= RH20_SHRT_STS; + rhc->status |= RH20_CHAN_ERR; + if ((rhc->ptcr & 010) == 0) /* Write command */ + rhc->status |= RH20_SHRT_WC; + } + wrd1 |= RH20_NADR_PAR; + M[eb_ptr|chan|1] = wrd1; + M[eb_ptr|chan|2] = ((uint64)rhc->cop << 33) | + (((uint64)wc) << CSHIFT) | + ((uint64)(rhc->cda) & AMASK); +//fprintf(stderr, "RH20 final %012llo %012llo %06o\n\r", M[eb_ptr|chan|1], M[eb_ptr|chan|2], wc); + } + return; + } +#endif + if (nxm) + rhc->status |= CXR_NXM; + rhc->status |= CCW_COMP_1; + if (rhc->wcr != 0) + rhc->cda++; + M[rhc->cia|1] = ((uint64)(rhc->ccw & WMASK) << CSHIFT) | ((uint64)(rhc->cda) & AMASK); +} + +/* 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)) + rh20_setup(rhc); +#endif +} + +#if KL +/* Set up for a RH20 transfer */ +void rh20_setup(struct rh_if *rhc) +{ + int reg; + DEVICE *dptr; + + 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; +// reg = rhc->dev_read(dptr, rhc, 1); + // if ((reg & (DS_DRY|DS_DPR|DS_ERR)) != (DS_DRY|DS_DPR)) + // return; + if (rhc->status & RH20_SBAR) { + rhc->drive = (rhc->pbar >> 18) & 07; + 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; + 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; +#if KL + if (rhc->imode == 2 && (rhc->cop & 2) != 0) { +// rh_finish_op(rhc, 0); + return 0; + } +#endif + if (rhc->ccw > MEMSIZE) { + rh_finish_op(rhc, 1); + return 0; + } + data = M[rhc->ccw]; +#if KL + if (rhc->imode == 2) { +//fprintf(stderr, "RH20 fetch %06o %012llo\n\r", rhc->ccw, data); + while((data & RH20_XFER) == 0) { + rhc->ccw = (uint32)(data & AMASK); + if ((data & (BIT1|BIT2)) == 0) { +// rh_finish_op(rhc, 0); + return 0; + } + if (rhc->ccw > MEMSIZE) { + rh_finish_op(rhc, 1); + return 0; + } + data = M[rhc->ccw]; +//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 (rhc->ccw > MEMSIZE) { + rh_finish_op(rhc, 1); + return 0; + } + data = M[rhc->ccw]; + } + 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) { + data = M[rhc->cda]; + 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); + data = M[rhc->cda]; + } +#else + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + data = M[rhc->cda]; +#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) { + M[rhc->cda] = rhc->buf; + 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); + M[rhc->cda] = rhc->buf; + } +#else + rhc->cda = (uint32)((rhc->cda + 1) & AMASK); + M[rhc->cda] = rhc->buf; +#endif + } + if (rhc->wcr == 0) { + return rh_fetch(rhc); + } + return 1; +} +