From 8c00d94be4ea35872e051a8b94ded7b21779a9ae Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Mon, 12 Aug 2019 07:51:52 -0700 Subject: [PATCH] KA10: General update. Added BASE option to auxcpu to move memory region. Fix errors in Card Reader/Card Punch translation and operation. Fixed problems with ITS quantum timer. Added support for System Concepts DC10 disk controller (Lars). Fixed errors in Line Printer control codes. Added support for Lines per page to LP10. Fixed issues with 7 track tapes on TM10. Updated user guides --- PDP10/ka10_ai.c | 1035 ++++++++++++++++++++++++ PDP10/ka10_auxcpu.c | 27 + PDP10/ka10_stk.c | 6 +- PDP10/ka10_ten11.c | 6 +- PDP10/kx10_cp.c | 24 +- PDP10/kx10_cpu.c | 28 +- PDP10/kx10_cr.c | 43 +- PDP10/kx10_dc.c | 2 +- PDP10/kx10_defs.h | 3 + PDP10/kx10_lp.c | 119 ++- PDP10/kx10_mt.c | 28 +- PDP10/kx10_sys.c | 9 +- Visual Studio Projects/PDP10-KA.vcproj | 4 + descrip.mms | 2 +- doc/ka10_doc.doc | Bin 211456 -> 215040 bytes doc/ki10_doc.doc | Bin 147968 -> 148992 bytes makefile | 3 +- 17 files changed, 1282 insertions(+), 57 deletions(-) create mode 100644 PDP10/ka10_ai.c diff --git a/PDP10/ka10_ai.c b/PDP10/ka10_ai.c new file mode 100644 index 00000000..263bafa5 --- /dev/null +++ b/PDP10/ka10_ai.c @@ -0,0 +1,1035 @@ +/* ka10_ai.c: Systems Concepts DC-10 disk control + + Copyright (c) 2019, Lars Brinkhoff + + 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 + LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This disk controller was probably only ever used with the MIT AI + Lab PDP-10. Since the device name DC is alreay claimed, we call + this AI. +*/ + +#include "kx10_defs.h" + +#ifndef NUM_DEVS_AI +#define NUM_DEVS_AI 0 +#endif + + +#if (NUM_DEVS_AI > 0) + +/* Disk pack geometry. The track format is software defined. ITS and + SALV makes it hold two sectors with 1024 words of regular data and + 4 extra words. */ +#define SECTOR_SIZE 1024 +#define SECTORS 2 +#define SURFACES 20 +#define MEMOREX_CYLINDERS 203 +#define CALCOMP_CYLINDERS (2 * MEMOREX_CYLINDERS) +#define CYLINDER_SIZE (SECTOR_SIZE * SECTORS * SURFACES) +#define MEMOREX_SIZE (CYLINDER_SIZE * MEMOREX_CYLINDERS) +#define CALCOMP_SIZE (CYLINDER_SIZE * CALCOMP_CYLINDERS) + +/* The real sector size, including 2 header words, 4 extra data words, + and 2 checksum words. */ +#define SECTOR_REAL_SIZE (SECTOR_SIZE + 8) +/* A track actually has some more free space. Cylinder 0, surface 0 + has a readin block there. */ +#define TRACK_REAL_SIZE ((SECTORS + 1) * SECTOR_REAL_SIZE) +#define CYLINDER_REAL_SIZE (SURFACES * TRACK_REAL_SIZE) + +#define AI_DEVNUM 0610 /* First device number; 614 also used. */ +#define AI_NAME "AI" +#define NUM_UNITS 16 /* Hardware units, but ITS only supports 8. */ + +/* All bit definitions are from the ITS file SYSTEM; DC10 DEFS27. */ + +/* CONI DC0 */ +#define DASSGN 0400000000000LL /* ASSIGNED TO PROC (WITH SWITCH) */ +#define DPIRQC 0400000 /* PI REQ BEING GENERATED */ +#define DSSRQ 0200000 /* SEEK REQUEST */ +#define DSDEEB 0010000 /* ENABLE INTERRUPT ON DATA ERROR OR READ/ COMP ERROR */ +#define DSSERR 0004000 /* ERROR FLAG */ +#define DSSAEB 0002000 /* ATTENTION ENABLE FLAG */ +#define DSSATT 0001000 /* ATTENTION FLAG */ +#define DSIENB 0000400 /* IDLE FLAG ENABLE */ +#define DSSRUN 0000200 /* RUN */ +#define DSSACT 0000100 /* ACTIVE */ +#define DSSCEB 0000040 /* CHANNEL ENABLE */ +#define DSSCHF 0000020 /* CHANNEL FLAG */ +#define DSSCFL 0000010 /* CPU FLAG */ + +/* CONO DC0 */ +#define DCSET 0400000 /* SET SELECTED */ +#define DCCLR 0200000 /* CLEAR SELECTED */ +#define DCCSET 0600000 /* RESET CONTROLLER THEN SET SELECTED */ +#define DCDENB 0010000 /* DATA ERROR ENABLE */ +#define DCERR 0004000 /* SET ERROR FLAG OR CLEAR ALL ERRORS */ +#define DCATEB 0002000 /* ATTENTION ENABLE */ +#define DCCATT 0001000 /* CLEAR ATTENTION */ +#define DCSSRQ 0001000 /* SET SEEK REQUEST */ +#define DCIENB 0000400 /* IDLE ENABLE */ +#define DCSTAR 0000200 /* START (SET) */ +#define DCSSTP 0000200 /* STOP (CLEAR) */ +#define DCSGL 0000100 /* DO SINGLE COMMAND */ +#define DCCENB 0000040 /* CHANNEL ENABLE */ +#define DCCFLG 0000020 /* CHANNEL FLAG */ +#define DCCPUF 0000010 /* CPU FLAG */ + +/* Bits to set or clear with DCSET or DCCLR. */ +#define SET_MASK (DCDENB|DCERR|DCATEB|DCIENB|DCSTAR) +#define CLEAR_MASK (DCDENB|DCERR|DCATEB|DCCATT|DCIENB|DCSSTP) + +/* CONI DC1 */ +#define DIPE 04000 /* INTERNAL PARITY ERROR */ +#define DRLNER 02000 /* RECORD LENGTH */ +#define DRCER 01000 /* READ COMPARE ERROR */ +#define DOVRRN 00400 /* OVERRUN */ +#define DCKSER 00200 /* CKSUM OR DECODER ERR */ +#define DWTHER 00100 /* WATCHDOG TIMER */ +#define DFUNSF 00040 /* FILE UNSAFE, SEEK INCOMPLETE OR END OR DSK */ +#define DOFFL 00020 /* OFF LINE OR MULT SEL */ +#define DPROT 00010 /* WRT KEY OR RD ONLY OR PROTECT */ +#define DDOBSY 00004 /* DATAO WHEN BSY */ +#define DNXM 00002 /* NON-EX MEM */ +#define DCPERR 00001 /* CORE PARITY ERR */ + +/* Channel commands */ +#define DUNENB 0020000000000LL /* ENABLE LOAD UNIT FIELD */ +#define DCMD 0740000000000LL +#define DCOPY 0040000000000LL /* COPY */ +#define DCCOMP 0100000000000LL /* COMPARE */ +#define DCSKIP 0140000000000LL /* SKIP */ +#define DOPR 0200000000000LL /* BASIC OPR */ +#define DSDRST 0240000000000LL /* STORE DRIVE STATUS */ +#define DALU 0300000000000LL /* BASIC ALU OP CODE */ +#define DRC 0400000000000LL /* READ COMPARE */ +#define DWRITE 0440000000000LL /* WRITE */ +#define DREAD 0500000000000LL /* READ */ +#define DSEEK 0540000000000LL /* SEEK */ +#define DRCC 0600000000000LL /* READ COMPARE CONTINUOUS */ +#define DWRITC 0640000000000LL /* WRITE CONTINUOUS */ +#define DREADC 0700000000000LL /* READ CONTINUOUS */ +#define DSPC 0740000000000LL /* Special command. */ + +#define DHLT 0 /* 0 IN 4.9-4.5 = JUMP AND IN 3.5,3.6 = HALT */ +#define DXCT 0000020000000LL /* XCT */ +#define DJMP 0000040000000LL /* JUMP */ +#define DJSR 0000060000000LL /* JSR */ +#define DJMASK 0000060000000LL + +/* OPR */ +#define DOHXFR 0400000000LL /* HALT DURING XFER (SO MB WILL BE SAFE) */ + +/* Special command, E condition (wait). */ +#define DSWIDX 0020000000LL /* WAIT UNTIL INDEX PULSE */ +#define DSWSEC 0040000000LL /* WAIT UNTIL SECTOR PULSE */ +#define DSWINF 0060000000LL /* NEVER (USE WITH G=3 OR 7) */ +/* Special command, F condition (other wait). */ +#define DSWNUL 0014000000LL /* NO WAIT */ +/* Special command, G operation. */ +#define DSCRHD 0200000000LL /* READ HEADER WORDS */ +#define DSRCAL 0300000000LL /* (RECALIBRATE) */ +#define DSCWIM 0500000000LL /* WRITE IMAGE */ + +/* ALU */ +#define DLCC 010000000LL /* OP FROM CC, STORE IN CC */ +#define DLDBWC 030000000LL /* OP A FROM DB, STORE IN WC */ + +#define WC 0037774000000LL /* Word count. */ +#define ADDR 0000003777777LL /* Address field. */ + +/* Drive status. */ + +#define DDSWC 040000000LL /* WRITE CURRENT SENSED */ +#define DDSUNS 020000000LL /* DRIVE UNSAFE */ +#define DDSRDO 010000000LL /* READ ONLY */ +#define DDSSIC 004000000LL /* SEEK INCOMPLETE */ +#define DDSRDY 002000000LL /* DRIVE READY */ +#define DDSONL 001000000LL /* DRIVE ON LINE */ +#define DDSSEL 000400000LL /* DRIVE SELECTED */ + +enum { + MODE_ERROR = 0, + MODE_WRITE, /* Write sector data. */ + MODE_READ, /* Read sector data. */ + MODE_READ_HEADERS, /* Read sector headers. */ + MODE_COMPARE, /* Compare sector data. */ + MODE_IMAGE /* Write raw image. */ +}; + +enum image_state { + IMAGE_GAP, /* Empty bits (ones) between sectors. */ + IMAGE_PREAMBLE, /* Bit pattern before sector header. */ + IMAGE_HEADER, /* Sector header, in FM encoding. */ + IMAGE_POSTAMBLE, /* Empty bits (ones). */ + IMAGE_POSTAMBLE2, /* A "01" to start the sector data. */ + IMAGE_SECTOR, /* Sector data, in FM encoding. */ + IMAGE_ERROR, +}; + +static enum image_state image_state = IMAGE_ERROR; +static int image_count, image_sector_length; + +static t_stat ai_devio(uint32 dev, uint64 *data); +static t_stat ai_svc(UNIT *); +static t_stat ai_reset(DEVICE *); +static t_stat ai_attach(UNIT *, CONST char *); +static t_stat ai_detach(UNIT *); +static t_stat ai_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, + const char *cptr); +static const char *ai_description (DEVICE *dptr); + + +UNIT ai_unit[] = { + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, + { UDATA (&ai_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, CALCOMP_SIZE) }, +}; + +DIB ai_dib = { AI_DEVNUM, 2, &ai_devio, NULL }; + +MTAB ai_mod[] = { + {0} +}; + +DEBTAB ai_debug[] = { + {"IRQ", DEBUG_IRQ, "Debug IRQ requests"}, + {"CMD", DEBUG_CMD, "Show command execution to devices"}, + {"DATA", DEBUG_DATA, "Show data transfers"}, + {"DETAIL", DEBUG_DETAIL, "Show details about device"}, + {"EXP", DEBUG_EXP, "Show exception information"}, + {"CONI", DEBUG_CONI, "Show CONI instructions"}, + {"CONO", DEBUG_CONO, "Show CONO instructions"}, + {"DATAIO", DEBUG_DATAIO, "Show DATAI and DATAO instructions"}, + {0, 0} +}; + +static UNIT *channel_unit = ai_unit; +static int latency_unit = 0; +static int channel_pc = 0; +static int channel_status = 0; +static uint64 channel_errors = 0; +static int channel_cc = 0; +static int channel_wc = 0; +static int channel_mode = MODE_ERROR; +static int channel_delay; +static int channel_default_delay = 1000; +static int channel_seek_initial = 25000; /* Milliseconds. */ +static int channel_seek_delay = 500; /* Per cylinder travelled. */ +static int channel_cylinder = 0; + +REG ai_reg[] = { + {ORDATA(PC, channel_pc, 20)}, + {ORDATA(STS, channel_status, 18)}, + {ORDATA(ERR, channel_errors, 12)}, + {ORDATA(CC, channel_cc, 20)}, + {ORDATA(WC, channel_wc, 12)}, + {ORDATA(SI, channel_seek_initial, 32)}, + {ORDATA(SD, channel_seek_delay, 32)}, + {ORDATA(CYL, channel_cylinder, 9)}, + {0} +}; + +DEVICE ai_dev = { + AI_NAME, ai_unit, ai_reg, ai_mod, + NUM_UNITS, 8, 18, 1, 8, 36, + NULL, NULL, &ai_reset, NULL, &ai_attach, &ai_detach, + &ai_dib, DEV_DISABLE | DEV_DEBUG, 0, ai_debug, + NULL, NULL, &ai_help, NULL, NULL, &ai_description +}; + +static void clear_interrupt (void) +{ + if ((channel_status & (DSDEEB|DSSERR)) == (DSDEEB|DSSERR) + || (channel_status & (DSSAEB|DSSATT)) == (DSSAEB|DSSATT) + || (channel_status & (DSIENB|DSSRUN)) == DSIENB) { + channel_status |= DPIRQC; + sim_debug(DEBUG_IRQ, &ai_dev, "Set interrupt: %06o\n", channel_status); + set_interrupt (AI_DEVNUM, channel_status); + } else { + channel_status &= ~DPIRQC; + sim_debug(DEBUG_IRQ, &ai_dev, "Clear interrupt\n"); + clr_interrupt (AI_DEVNUM); + } +} + +static void channel_error (int errors) +{ + channel_errors |= errors; + channel_status |= DSSERR; + if (channel_status & DSDEEB) { + channel_status |= DPIRQC; + sim_debug(DEBUG_IRQ, &ai_dev, "Set error interrupt\n"); + set_interrupt (AI_DEVNUM, channel_status); + } +} + +static void channel_seek (const char *cmd, uint64 data, int offset) +{ + int cyl, sur, sec, x; + int da; + + if (data & DUNENB) + channel_unit = &ai_unit[(data >> 033) & 017]; + + cyl = (data >> 11) & 0777; + sur = (data >> 6) & 037; + sec = data & 077; + + if (cyl >= CALCOMP_CYLINDERS && sur >= SURFACES && sec >= SECTORS) { + sim_debug(DEBUG_EXP, &ai_dev, "Seek outside geometry\n"); + channel_error (DOVRRN); + return; + } + + da = SECTOR_REAL_SIZE * sec; + da += TRACK_REAL_SIZE * sur; + da += CYLINDER_REAL_SIZE * cyl; + da += offset; + if (channel_unit->flags & UNIT_ATT) { + (void)sim_fseek(channel_unit->fileref, da * sizeof(uint64), SEEK_SET); + x = channel_cylinder - cyl; + if (x < 0) + x = -x; + if (x > 0) + channel_delay = channel_seek_initial + x * channel_seek_delay; + channel_cylinder = cyl; + sim_debug(DEBUG_CMD, &ai_dev, "%s: unit %d seek %d (%d,%d,%d)\n", + cmd, (int)(channel_unit - ai_unit), channel_delay, + cyl, sur, sec); + } else { + sim_debug(DEBUG_EXP, &ai_dev, "Drive offline\n"); + channel_error (DOFFL); + } +} + +static void channel_special (uint64 data) +{ + if (data & DUNENB) + channel_unit = &ai_unit[(data >> 033) & 017]; + + switch (data & 0700000000LL) { + case DSCRHD: + channel_mode = MODE_READ_HEADERS; + channel_seek ("READ HEADER WORDS", data, 0); + break; + case DSRCAL: + sim_debug(DEBUG_CMD, &ai_dev, "Command: (RECALIBRATE)\n"); + channel_status |= DSSATT; + channel_errors &= ~(017LL << 036); + channel_errors |= (channel_unit - ai_unit) << 036; + if (channel_status & DSSAEB) { + channel_status |= DPIRQC; + sim_debug(DEBUG_IRQ, &ai_dev, "Set attention interrupt\n"); + set_interrupt (AI_DEVNUM, channel_status); + } + break; + case DSCWIM: + if ((channel_unit->flags & UNIT_ATT) == 0) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive offline\n"); + channel_error (DOFFL); + } else if (channel_unit->flags & UNIT_RO) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive read only\n"); + channel_error (DPROT); + } else { + channel_mode = MODE_IMAGE; + image_state = IMAGE_GAP; + image_count = 0; + channel_seek ("WRITE IMAGE", data, 0); + } + break; + default: + sim_debug(DEBUG_CMD, &ai_dev, "(unknown special: %012llo)\n", data); + break; + } +} + +static void channel_alu (uint64 data) +{ + switch (data & 034000000LL) { + case DLCC: + channel_cc = data & ADDR; + sim_debug(DEBUG_CMD, &ai_dev, "ALU: OP FROM CC, STORE IN CC: %o\n", channel_cc); + break; + case DLDBWC: + channel_wc = data & 07777; + sim_debug(DEBUG_CMD, &ai_dev, "ALU: OP A FROM DB, STORE IN WC: %o\n", channel_wc); + break; + default: + sim_debug(DEBUG_CMD, &ai_dev, "ALU: (unkownn)\n"); + break; + } +} + +static void print_data (uint64 *data, int n) +{ + int i; + for (i = 0; i < n; i++) + sim_debug(DEBUG_DATA, &ai_dev, "Data %012llo\n", + *data++); +} + +static t_stat sim_fcompare (void *x, size_t m, size_t n, FILE *f) +{ + static uint64 buf[10240]; + + if ((channel_unit->flags & UNIT_ATT) == 0) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive offline\n"); + channel_error (DOFFL); + return SCPE_OK; + } + + (void)sim_fread (buf, m, n, f); + sim_debug(DEBUG_DATA, &ai_dev, "Memory contents:\n"); + print_data ((uint64 *)x, n); + sim_debug(DEBUG_DATA, &ai_dev, "Disk contents:\n"); + print_data (buf, n); + if (memcmp (x, buf, m * n) != 0) { + sim_debug(DEBUG_EXP, &ai_dev, "Compare failed.\n"); + channel_error (DRCER); + } + return SCPE_OK; +} + +/* The WRITE IMAGE command writes the sector headers as 56 continuous + bits. However, the READ HEADERS command presents them as 28-bit + halves, each right aligned in a 36-bit word. The image file stores + the first format, so here we need to split the words apart. Also + skip over the sector data to get to next header. */ +static t_stat sim_freadh (uint64 *x, size_t n, FILE *f) +{ + uint64 buf[2]; + size_t i; + + if ((channel_unit->flags & UNIT_ATT) == 0) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive offline\n"); + channel_error (DOFFL); + return SCPE_OK; + } + + for (i = 0; i < n; i++) { + if ((i & 1) == 0) { + (void)sim_fread (buf, sizeof (uint64), 2, f); + (void)sim_fseek(f, (SECTOR_REAL_SIZE-2) * sizeof(uint64), SEEK_CUR); + x[i] = buf[0] >> 8; + } else { + x[i] = (buf[0] & 0377) << 20; + x[i] |= buf[1] >> 16; + } + } + + return SCPE_OK; +} + +/* The track data fields are in somthing close to FM encoding. Here + we decode three bits at a time to yeild two bits of data. When 36 + data bits have been decoded, output a word to the image file. */ +static void decode_fm (int bit, FILE *f) +{ + static int state = 0; + static uint64 word = 0; + static int n = 0; + static int bits = 1; + + bits = (bits << 1) + bit; + state++; + + if (state != 3) + return; + + word <<= 2; + + switch (bits & 017) { + case 005: + case 007: + word |= (bits >> 4) & 2; + word |= (bits >> 1) & 1; + break; + case 012: + case 016: + break; + case 013: + case 015: + case 017: + word |= (bits >> 1) & 3; + break; + default: + sim_debug(DEBUG_EXP, &ai_dev, "Error in FM encoding: %o\n", bits); + channel_error (DCKSER); + break; + } + + state = 0; + n += 2; + + //sim_debug(DEBUG_DETAIL, &ai_dev, "FM: %o, %d, %012llo\n", + // bits, n, word); + + if (n == 36) { + //sim_debug(DEBUG_DETAIL, &ai_dev, "Data: %012llo\n", word); + (void)sim_fwrite (&word, sizeof word, 1, f); + n = 0; + word = 0; + } +} + +/* Decode a bit stream from the WRITE IMAGE command. */ +static void decode_bit (int bit, FILE *f) +{ + static const int preamble_bits[] = { 1, 0, 1, 0, 1 }; + + //sim_debug(DEBUG_DETAIL, &ai_dev, "Image: bit %o\n", bit); + + switch (image_state) { + case IMAGE_GAP: + if (bit == 0) { + sim_debug(DEBUG_DETAIL, &ai_dev, "Image: %d gap bits\n", + image_count); + image_state = IMAGE_PREAMBLE; + image_count = 0; + } else { + image_count++; + } + break; + case IMAGE_PREAMBLE: + if (bit != preamble_bits[image_count % 5]) { + sim_debug(DEBUG_DETAIL, &ai_dev, "Image: error in preamble bit %d\n", + image_count); + image_state = IMAGE_ERROR; + break; + } + image_count++; + if (image_count == 5*8) { + sim_debug(DEBUG_DETAIL, &ai_dev, "Image: preamble ok\n"); + image_state = IMAGE_HEADER; + image_count = 0; + } + break; + case IMAGE_HEADER: + decode_fm (bit, f); + image_count++; + if (image_count == 108) { + t_offset pos; + uint64 header[2]; + image_state = IMAGE_POSTAMBLE; + image_count = 0; + pos = sim_ftell (channel_unit->fileref); + (void)sim_fseeko(channel_unit->fileref, pos - 2 * sizeof(uint64), SEEK_SET); + (void)sim_fread(header, sizeof(uint64), 2, channel_unit->fileref); + (void)sim_fseeko(channel_unit->fileref, pos, SEEK_SET); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: key %03llo\n", + (header[0] >> 28) & 0377); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: cylinder %lld\n", + (header[0] >> 19) & 0777); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: surface %lld\n", + (header[0] >> 14) & 037); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: sector %lld\n", + (header[0] >> 8) & 077); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: indirect %llo\n", + (header[0] >> 7) & 1); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: software protect %llo\n", + (header[0] >> 6) & 1); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: hardware protect %llo\n", + (header[0] >> 5) & 1); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: parity %llo\n", + header[0] & 3); + image_sector_length = 040000 - ((header[1] >> 16) & 037777); + sim_debug(DEBUG_DETAIL, &ai_dev, "Header: length %o\n", + image_sector_length); + if (image_sector_length > 02004) { + sim_debug(DEBUG_EXP, &ai_dev, "Record length error\n"); + channel_error (DRLNER); + image_state = IMAGE_SECTOR; + } + image_sector_length += 2; /* Checksum */ + image_sector_length *= 54; /* 36-bit words, FM coded. */ + } + break; + case IMAGE_POSTAMBLE: + image_count++; + if (bit == 0) { + sim_debug(DEBUG_DETAIL, &ai_dev, "Image: %d gap bits\n", + image_count); + image_state = IMAGE_POSTAMBLE2; + image_count = 0; + } + break; + case IMAGE_POSTAMBLE2: + if (bit == 0) { + sim_debug(DEBUG_DETAIL, &ai_dev, "Image: error in postamble\n"); + image_state = IMAGE_ERROR; + } else { + image_state = IMAGE_SECTOR; + } + break; + case IMAGE_SECTOR: + decode_fm (bit, f); + image_count++; + if (image_count == image_sector_length) { + image_state = IMAGE_GAP; + image_count = 0; + } + break; + case IMAGE_ERROR: + break; + } +} + +static void decode_image (uint64 *data, int n, FILE *f) +{ + int i, j; + for (i = 0; i < n; i++) { + for (j = 35; j >= 0; j--) + decode_bit ((int)(*data >> j) & 1, f); + data++; + } +} + +static int check_nxm (uint64 data, int *n, uint64 *data2, int *n2) +{ + unsigned int addr = data & ADDR; + *data2 = 0; + *n2 = 0; + if (addr + *n > MEMSIZE) { + if (MEMSIZE < (ADDR+1)) { + sim_debug(DEBUG_EXP, &ai_dev, "Access outside core memory\n"); + *n = MEMSIZE - addr; + channel_error (DNXM); + return 1; + } else { + /* Access wraps around 21-bit address. */ + *n2 = addr + *n - MEMSIZE; + *data2 = 0; + *n = MEMSIZE - addr; + return 0; + } + } + return 0; +} + +/* Execute one channel instruction. It may come from a channel + program in core, or from a DATAO DC0, */ +static void channel_command (uint64 data) +{ + struct timespec ts; + int latency_timer; + int n, n2; + uint64 data2; + int nxm = 0; + + if ((data & (DCMD|DUNENB)) == 0) { + switch (data & DJMASK) { + case DHLT: + sim_debug(DEBUG_CMD, &ai_dev, "Command: DHLT\n"); + channel_status &= ~(DSSRUN|DSSACT); + if (channel_status & DSIENB) { + channel_status |= DPIRQC; + sim_debug(DEBUG_IRQ, &ai_dev, "Set idle interrupt\n"); + set_interrupt (AI_DEVNUM, channel_status); + } + break; + case DXCT: + sim_debug(DEBUG_CMD, &ai_dev, "Command: XCT\n"); + break; + case DJMP: + channel_status |= DSSRUN|DSSACT; + sim_activate(ai_unit, channel_default_delay); + clear_interrupt (); + if ((data & 014000000LL) == 004000000LL) { + sim_debug(DEBUG_CMD, &ai_dev, "Command: JUMP DAOJNC: %o\n", + channel_cc); + channel_cc++; + if (channel_cc != ADDR+1) + channel_pc = data & ADDR; + } else { + sim_debug(DEBUG_CMD, &ai_dev, "Command: JUMP\n"); + channel_pc = data & ADDR; + } + break; + case DJSR: + sim_debug(DEBUG_CMD, &ai_dev, "Command: JSR\n"); + n = 1; + if (check_nxm (data, &n, &data2, &n2)) + break; + M[data & ADDR] = (channel_pc + (channel_unit - ai_unit)) << 036; + channel_pc++; + channel_status |= DSSRUN|DSSACT; + sim_activate(ai_unit, channel_default_delay); + break; + } + return; + } + + switch (data & DCMD) { + case DCOPY: + n = (data & WC) >> 20; + if (n == 0) + n = channel_wc; + n = 010000 - n; + sim_debug(DEBUG_CMD, &ai_dev, "COPY %d words to/from %012llo.\n", + n, data & ADDR); + if ((channel_unit->flags & UNIT_ATT) == 0) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive offline\n"); + channel_error (DOFFL); + break; + } + nxm = check_nxm (data, &n, &data2, &n2); + switch (channel_mode) { + case MODE_READ: + (void)sim_fread (&M[data & ADDR], sizeof(uint64), n, + channel_unit->fileref); + if (nxm) + break; + (void)sim_fread (&M[data2], sizeof(uint64), n2, + channel_unit->fileref); + print_data (&M[data & ADDR], n); + break; + case MODE_READ_HEADERS: + (void)sim_freadh (&M[data & ADDR], n, channel_unit->fileref); + if (nxm) + break; + (void)sim_freadh (&M[data2], n2, channel_unit->fileref); + break; + case MODE_WRITE: + if (channel_unit->flags & UNIT_RO) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive read only\n"); + channel_error (DPROT); + } else { + (void)sim_fwrite (&M[data & ADDR], sizeof(uint64), n, + channel_unit->fileref); + if (nxm) + break; + (void)sim_fwrite (&M[data2], sizeof(uint64), n2, + channel_unit->fileref); + } + break; + case MODE_COMPARE: + (void)sim_fcompare (&M[data & ADDR], sizeof(uint64), n, + channel_unit->fileref); + if (nxm) + break; + (void)sim_fcompare (&M[data2], sizeof(uint64), n2, + channel_unit->fileref); + /* If at the end of the sector, skip to next sector. */ + if ((sim_ftell (channel_unit->fileref) / sizeof(uint64)) + % SECTOR_REAL_SIZE == 1030) + (void)sim_fseek(channel_unit->fileref, 4 * sizeof(uint64), SEEK_CUR); + break; + case MODE_IMAGE: + decode_image (&M[data & ADDR], n, channel_unit->fileref); + break; + default: + break; + } + break; + case DCCOMP: + n = (data & WC) >> 20; + if (n == 0) + n = channel_wc; + n = 010000 - n; + sim_debug(DEBUG_CMD, &ai_dev, "COMPARE %d words\n", n); + if ((channel_unit->flags & UNIT_ATT) == 0) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive offline\n"); + channel_error (DOFFL); + break; + } + nxm = check_nxm (data, &n, &data2, &n2); + (void)sim_fcompare (&M[data & ADDR], sizeof(uint64), n, + channel_unit->fileref); + if (nxm) + break; + (void)sim_fcompare (&M[data2], sizeof(uint64), n2, + channel_unit->fileref); + break; + case DCSKIP: + n = 010000 - ((data & WC) >> 20); + sim_debug(DEBUG_CMD, &ai_dev, "SKIP %o words\n", n); + (void)sim_fseek(channel_unit->fileref, n * sizeof(uint64), SEEK_CUR); + break; + case DOPR: + if (data & DOHXFR) + sim_debug(DEBUG_CMD, &ai_dev, "OPR: Hang during xfer\n"); + else + sim_debug(DEBUG_CMD, &ai_dev, "OPR ...\n"); + break; + case DSDRST: + if (data & DUNENB) + channel_unit = &ai_unit[(data >> 033) & 017]; + + sim_debug(DEBUG_CMD, &ai_dev, + "DSDRST, store unit %d status in %012llo.\n", + (int)(channel_unit - ai_unit), data & ADDR); + + n = 1; + if (check_nxm (data, &n, &data2, &n2)) + break; + + (void)clock_gettime(CLOCK_REALTIME, &ts); + latency_timer = ts.tv_nsec / 100000; + latency_timer %= 254; + M[data & ADDR] = latency_timer & 0377; + M[data & ADDR] |= channel_cylinder << 8; + if (channel_unit->flags & UNIT_ATT) + /* Drive online. */ + M[data & ADDR] |= DDSONL; + if (channel_unit->flags & UNIT_RO) + /* Drive read-only. */ + M[data & ADDR] |= DDSRDO; + break; + case DALU: + channel_alu (data); + break; + case DRC: + channel_mode = MODE_COMPARE; + channel_seek ("READ COMPARE", data, 2); + break; + case DWRITE: + if (channel_unit->flags & UNIT_RO) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive read only\n"); + channel_error (DPROT); + channel_mode = MODE_ERROR; + } else { + channel_mode = MODE_WRITE; + channel_seek ("WRITE", data, 2); + } + break; + case DREAD: + channel_mode = MODE_READ; + channel_seek ("READ", data, 2); + break; + case DSEEK: + channel_seek ("SEEK", data, 2); + break; + case DRCC: + channel_mode = MODE_COMPARE; + channel_seek ("READ COMPARE CONTINUOUS", data, 2); + break; + case DWRITC: + if (channel_unit->flags & UNIT_RO) { + sim_debug(DEBUG_EXP, &ai_dev, "Drive read only\n"); + channel_error (DPROT); + channel_mode = MODE_ERROR; + } else { + channel_mode = MODE_WRITE; + channel_seek ("WRITE CONTINUOUS", data, 2); + } + break; + case DREADC: + channel_mode = MODE_READ; + channel_seek ("READ CONTINUOUS", data, 2); + break; + case DSPC: + channel_special (data); + break; + default: + sim_debug(DEBUG_CMD, &ai_dev, "(unknown command: %012llo)\n", data); + break; + } +} + +/* Process one channel instruction and update the channel state. */ +static void channel_run (void) +{ + uint64 data, data2; + int n = 1, n2; + if (check_nxm (channel_pc, &n, &data2, &n2)) + return; + data = M[channel_pc]; + //sim_debug(DEBUG_CMD, &ai_dev, "Channel PC=%06o %012llo\n", + // channel_pc, data); + channel_pc++; + channel_command (data); +} + +t_stat ai_devio(uint32 dev, uint64 *data) { + struct timespec ts; + int latency_timer; + + switch(dev & 7) { + case CONI: + *data = channel_status; + sim_debug(DEBUG_CONI, &ai_dev, "DC0, PC=%06o %012llo\n", PC, *data); + return SCPE_OK; + + case CONO: + sim_debug(DEBUG_CONO, &ai_dev, "DC0, PC=%06o %012llo\n", PC, *data); + if ((*data & DCCSET) == DCCSET) { + sim_debug(DEBUG_CMD, &ai_dev, "Reset controller then set selected.\n"); + ai_reset (&ai_dev); + } + channel_status &= ~7; + channel_status |= *data & 7; + if (*data & DCSET) { + channel_status |= *data & SET_MASK; + if (*data & DCSSRQ) + channel_status |= DSSRQ; + sim_debug(DEBUG_CMD, &ai_dev, "Set bits: %012llo -> %06o\n", + *data & SET_MASK, channel_status); + } else if (*data & DCCLR) { + channel_status &= ~(*data & CLEAR_MASK); + sim_debug(DEBUG_CMD, &ai_dev, "Clear bits: %012llo -> %06o\n", + *data & CLEAR_MASK, channel_status); + if (*data & DCERR) + channel_errors = 0; + } + clear_interrupt (); + return SCPE_OK; + + case DATAI: + *data = 0; + sim_debug(DEBUG_DATAIO, &ai_dev, "DATAI DC0, PC=%06o %012llo\n", + PC, *data); + return SCPE_OK; + + case DATAO: + sim_debug(DEBUG_DATAIO, &ai_dev, "DATAO DC0, PC=%06o %012llo\n", + PC, *data); + if (channel_status & (DSSRUN|DSSACT)) { + sim_debug(DEBUG_EXP, &ai_dev, "DATAO when busy\n"); + channel_error (DDOBSY); + } else + channel_command (*data); + return SCPE_OK; + + case CONI|4: + /* Latency timer, timer unit, attention unit. */ + (void)clock_gettime(CLOCK_REALTIME, &ts); + latency_timer = ts.tv_nsec / 100000; + latency_timer %= 254; + *data = (latency_timer << 022) + | (latency_unit << 032) | channel_errors; + sim_debug(DEBUG_CONI, &ai_dev, "DC1, PC=%06o %012llo\n", PC, *data); + return SCPE_OK; + + case CONO|4: + sim_debug(DEBUG_CONO, &ai_dev, "DC1, PC=%06o %012llo\n", PC, *data); + sim_debug(DEBUG_CMD, &ai_dev, "Latency timer set to unit %llo\n", *data); + latency_unit = *data & 7; + return SCPE_OK; + + case DATAI|4: + *data = 0; + sim_debug(DEBUG_DATAIO, &ai_dev, "DATAI DC1, PC=%06o %012llo\n", + PC, *data); + return SCPE_OK; + + case DATAO|4: + sim_debug(DEBUG_DATAIO, &ai_dev, "DATAO DC1, PC=%06o %012llo\n", + PC, *data); + return SCPE_OK; + } + return SCPE_OK; /* Unreached */ +} + +t_stat ai_svc (UNIT *uptr) +{ + int i; + channel_delay = channel_default_delay; + for (i = 0; (channel_status & DSSRUN) && i < 10; i++) + channel_run (); + if (channel_status & DSSRUN) + sim_activate(uptr, channel_delay); + return SCPE_OK; +} + +t_stat +ai_reset(DEVICE *dptr) +{ + channel_status = 0; + channel_errors = 0; + channel_pc = 0; + channel_cc = 0; + channel_wc = 0; + channel_mode = 0; + return SCPE_OK; +} + +/* Device attach */ +t_stat ai_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + DEVICE *rptr; + DIB *dib; + + r = attach_unit (uptr, cptr); + if (r != SCPE_OK) + return r; + rptr = find_dev_from_unit(uptr); + if (rptr == 0) + return SCPE_OK; + dib = (DIB *) rptr->ctxt; + set_interrupt(dib->dev_num, 0); + return SCPE_OK; +} + +/* Device detach */ +t_stat ai_detach (UNIT *uptr) +{ + if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; + if (sim_is_active (uptr)) /* unit active? */ + sim_cancel (uptr); /* cancel operation */ + return detach_unit (uptr); +} + +t_stat ai_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +fprintf (st, "Systems Concepts DC-10\n\n"); +fprint_set_help (st, dptr); +fprint_show_help (st, dptr); +fprint_reg_help (st, dptr); +return SCPE_OK; +} + +const char *ai_description (DEVICE *dptr) +{ + return "Systems Concepts DC-10 disk controller"; +} + + +#endif diff --git a/PDP10/ka10_auxcpu.c b/PDP10/ka10_auxcpu.c index b3352577..fcda5e81 100644 --- a/PDP10/ka10_auxcpu.c +++ b/PDP10/ka10_auxcpu.c @@ -54,12 +54,15 @@ static int pia = 0; static int status = 0; +t_value auxcpu_base = 03000000; static t_stat auxcpu_devio(uint32 dev, t_uint64 *data); static t_stat auxcpu_svc (UNIT *uptr); static t_stat auxcpu_reset (DEVICE *dptr); static t_stat auxcpu_attach (UNIT *uptr, CONST char *ptr); static t_stat auxcpu_detach (UNIT *uptr); +static t_stat auxcpu_set_base (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +static t_stat auxcpu_show_base (FILE *st, UNIT *uptr, int32 val, CONST void *desc); static t_stat auxcpu_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); static const char *auxcpu_description (DEVICE *dptr); @@ -73,6 +76,8 @@ static REG auxcpu_reg[] = { }; static MTAB auxcpu_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "base address", "BASE", + &auxcpu_set_base, &auxcpu_show_base }, { 0 } }; @@ -389,4 +394,26 @@ t_stat auxcpu_devio(uint32 dev, t_uint64 *data) return SCPE_OK; } + +static t_stat auxcpu_set_base (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + t_stat r; + t_value x; + + if (cptr == NULL || *cptr == 0) + return SCPE_ARG; + + x = get_uint (cptr, 8, 03777777, &r); + if (r != SCPE_OK) + return SCPE_ARG; + + auxcpu_base = x; + return SCPE_OK; +} + +static t_stat auxcpu_show_base (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + fprintf (st, "Base: %llo", auxcpu_base); + return SCPE_OK; +} #endif diff --git a/PDP10/ka10_stk.c b/PDP10/ka10_stk.c index cb423397..98911033 100644 --- a/PDP10/ka10_stk.c +++ b/PDP10/ka10_stk.c @@ -24,12 +24,14 @@ */ #include -#include "sim_video.h" -#include "display/display.h" #include "kx10_defs.h" #ifdef USE_DISPLAY #if NUM_DEVS_STK > 0 + +#include "sim_video.h" +#include "display/display.h" + #define STK_DEVNUM 070 /* CONI/O bits. */ diff --git a/PDP10/ka10_ten11.c b/PDP10/ka10_ten11.c index 81863c98..b7f817d1 100644 --- a/PDP10/ka10_ten11.c +++ b/PDP10/ka10_ten11.c @@ -262,7 +262,11 @@ static int read_word (int addr, int *data) build (request, (addr >> 8) & 0377); build (request, (addr) & 0377); - transaction (request, response); + if (transaction (request, response) == -1) { + /* Network error. */ + *data = 0; + return 0; + } switch (response[0]) { diff --git a/PDP10/kx10_cp.c b/PDP10/kx10_cp.c index f8750f18..a0e910a1 100644 --- a/PDP10/kx10_cp.c +++ b/PDP10/kx10_cp.c @@ -34,7 +34,7 @@ #include "sim_defs.h" #if (NUM_DEVS_CP > 0) -#define UNIT_CDP UNIT_ATTABLE | UNIT_DISABLE | MODE_029 +#define UNIT_CDP UNIT_ATTABLE | UNIT_DISABLE | MODE_026 #define CP_DEVNUM 0110 @@ -92,7 +92,7 @@ uint16 cp_buffer[80]; DIB cp_dib = { CP_DEVNUM, 1, cp_devio, NULL}; -UNIT cp_unit = {UDATA(cp_srv, UNIT_CDP, 0), 600 }; +UNIT cp_unit = {UDATA(cp_srv, UNIT_CDP, 0), 2000 }; MTAB cp_mod[] = { {MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", @@ -121,6 +121,7 @@ DEVICE cp_dev = { t_stat cp_devio(uint32 dev, uint64 *data) { UNIT *uptr = &cp_unit; + uint16 col; switch(dev & 3) { case CONI: @@ -170,7 +171,24 @@ t_stat cp_devio(uint32 dev, uint64 *data) { *data = 0; break; case DATAO: - cp_buffer[uptr->COL++] = *data & 0xfff; + col = *data & 0xfff; + switch(col) { + case 04006: col = 03000; break; /* ! - */ + case 01022: col = 00006; break; /* " - */ + case 01012: col = 01202; break; /* # - */ + case 01006: col = 01042; break; /* % - */ + case 02006: col = 05000; break; /* & - */ + case 00012: col = 00042; break; /* ' - */ + case 03000: col = 00022; break; /* : - */ + case 01202: col = 02012; break; /* ; - */ + case 02012: col = 00012; break; /* > - */ + case 05000: col = 04202; break; /* ? - */ + case 02022: col = 04022; break; /* [ - */ + case 00006: col = 01012; break; /* \ - */ + case 04022: col = 02022; break; /* ] - */ + case 00022: col = 00202; break; /* ^ - */ + } + cp_buffer[uptr->COL++] = col; uptr->STATUS &= ~DATA_REQ; clr_interrupt(dev); sim_debug(DEBUG_DATAIO, &cp_dev, "CP: DATAO %012llo %d\n", *data, diff --git a/PDP10/kx10_cpu.c b/PDP10/kx10_cpu.c index 60b10fcc..b93bda28 100644 --- a/PDP10/kx10_cpu.c +++ b/PDP10/kx10_cpu.c @@ -221,7 +221,8 @@ int32 tmxr_poll = 10000; /* Physical address range for Rubin 10-11 interface. */ #define T11RANGE(addr) ((addr) >= 03040000) /* Physical address range for auxiliary PDP-6. */ -#define AUXCPURANGE(addr) ((addr) >= 03000000 && (addr) < 03040000) +extern int auxcpu_base; +#define AUXCPURANGE(addr) ((addr) >= auxcpu_base && (addr) < (auxcpu_base + 040000)) DEVICE *rh_devs[] = { #if (NUM_DEVS_RS > 0) @@ -813,12 +814,12 @@ int opflags[] = { void set_quantum() { + double us; sim_cancel(&cpu_unit[1]); - if ((qua_time & RSIGN) == 0) { - double us; - us = (double)(RSIGN - qua_time); - (void)sim_activate_after_d(&cpu_unit[1], us); - } + if (qua_time & BIT17) + return; + us = (double)(BIT17 - qua_time); + (void)sim_activate_after_d(&cpu_unit[1], us); } /* @@ -830,7 +831,10 @@ load_quantum() if (sim_is_active(&cpu_unit[1])) { double us; us = sim_activate_time_usecs (&cpu_unit[1]); - qua_time = RSIGN - (uint32)us; + if ((uint32)us > BIT17) + qua_time = BIT17; + else + qua_time = (BIT17 - (uint32)us) & RMASK; sim_cancel(&cpu_unit[1]); } } @@ -841,11 +845,11 @@ load_quantum() uint32 get_quantum() { - uint32 t = 0; + uint32 t = qua_time; if (sim_is_active(&cpu_unit[1])) { double us; us = sim_activate_time_usecs (&cpu_unit[1]); - t = RSIGN - (uint32)us; + t = (BIT17 - (uint32)us) & RMASK; } return t; } @@ -3491,9 +3495,10 @@ dpnorm: AB = (AB + 1) & RMASK; MB = M[AB]; /* WD 3 */ /* Store Quantum */ - qua_time = MB & RMASK; + qua_time = MB & (RMASK|BIT17); set_quantum(); fault_data = (MB >> 18) & RMASK; + fault_data &= ~1; /* Clear high quantum bit */ mem_prot = 0; if ((fault_data & 0777772) != 0) mem_prot = 1; @@ -5997,9 +6002,8 @@ qua_srv(UNIT * uptr) { if ((fault_data & 1) == 0 && pi_enable && !pi_pending && (FLAGS & USER) != 0) { mem_prot = 1; - fault_data |= 1; } - qua_time = RSIGN; + qua_time = BIT17; return SCPE_OK; } #endif diff --git a/PDP10/kx10_cr.c b/PDP10/kx10_cr.c index ef1bc18a..be886cbf 100644 --- a/PDP10/kx10_cr.c +++ b/PDP10/kx10_cr.c @@ -34,7 +34,7 @@ #include "sim_defs.h" #if (NUM_DEVS_CR > 0) -#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_029 +#define UNIT_CDR UNIT_ATTABLE | UNIT_RO | UNIT_DISABLE | MODE_029 | MODE_LOWER #define CR_DEVNUM 0150 @@ -94,7 +94,7 @@ uint16 cr_buffer[80]; DIB cr_dib = { CR_DEVNUM, 1, cr_devio, NULL}; UNIT cr_unit = { - UDATA(cr_srv, UNIT_CDR, 0), 300, + UDATA(cr_srv, UNIT_CDR, 0), 2000, }; MTAB cr_mod[] = { @@ -136,7 +136,7 @@ t_stat cr_devio(uint32 dev, uint64 *data) { case CONO: clr_interrupt(dev); - sim_debug(DEBUG_CONO, &cr_dev, "CR: CONO %012llo\n", *data); + sim_debug(DEBUG_CONO, &cr_dev, "CR: CONO %012llo PC=%06o\n", *data, PC); if (*data & CLR_READER) { uptr->STATUS = 0; if (!CARD_RDY(uptr)) @@ -171,7 +171,9 @@ t_stat cr_devio(uint32 dev, uint64 *data) { case DATAI: clr_interrupt(dev); if (uptr->STATUS & DATA_RDY) { - *data = uptr->DATA; + *data = uptr->DATA & ~RSIGN; + if (uptr->DATA & RSIGN) + *data |= SMASK; sim_debug(DEBUG_DATAIO, &cr_dev, "CR: DATAI %012llo\n", *data); uptr->STATUS &= ~DATA_RDY; } else @@ -215,7 +217,7 @@ cr_srv(UNIT *uptr) { case CDSE_EMPTY: sim_debug(DEBUG_EXP, &cr_dev, "CR: card empty\n"); uptr->STATUS &= ~(CARD_IN_READ|READING); - uptr->STATUS |= HOPPER_EMPTY|TROUBLE|STOP; + uptr->STATUS |= HOPPER_EMPTY|TROUBLE; if (uptr->STATUS & TROUBLE_EN) set_interrupt(CR_DEVNUM, uptr->STATUS); return SCPE_OK; @@ -238,14 +240,43 @@ cr_srv(UNIT *uptr) { /* Copy next column over */ if (uptr->STATUS & CARD_IN_READ) { + uint32 data; + int i; if (uptr->COL >= 80) { uptr->STATUS &= ~(CARD_IN_READ|READING); + if (sim_card_input_hopper_count(uptr) == 0) + uptr->STATUS |= HOPPER_EMPTY; uptr->STATUS |= END_CARD; set_interrupt(CR_DEVNUM, uptr->STATUS); sim_activate(uptr, uptr->wait); return SCPE_OK; } - uptr->DATA = cr_buffer[uptr->COL++]; + data = cr_buffer[uptr->COL++]; + switch(data) { + case 0x482: data = 0x806; break; /* ! - 12 8 7 */ + case 0xA00: data = 0x882; break; /* [ - 12 8 2 */ + case 0x882: data = 0x482; break; /* ] - 11 8 2 */ + case 0x405: data = 0xa00; break; /* { - 12 0 */ + case 0x600: data = 0xc00; break; /* | - 12 11 */ + case 0x805: data = 0x600; break; /* } - 11 0 */ + case 0x806: data = 0x700; break; /* ~ - 11 0 1 */ + } + uptr->DATA = data; + /* Generate upper 18 bits of data */ + uptr->DATA |= ((data & 0x001) << 25) | + ((data & 0xe00) << 13) | + ((data & 0x002) << 20); + for (i = 1; i <= 7; i++) { + if (data & 0x100) { + /* Set flag it more then one punch */ + if ((uptr->DATA & 07000000) != 0){ + uptr->DATA |= (int32)RSIGN; + break; + } + uptr->DATA |= i << 18; + } + data <<= 1; + } if (uptr->STATUS & DATA_RDY) { uptr->STATUS |= DATA_MISS; } diff --git a/PDP10/kx10_dc.c b/PDP10/kx10_dc.c index 54001e46..f54ce793 100644 --- a/PDP10/kx10_dc.c +++ b/PDP10/kx10_dc.c @@ -107,7 +107,7 @@ const char *dc_description (DEVICE *dptr); DIB dc_dib = { DC_DEVNUM, 1, &dc_devio, NULL }; UNIT dc_unit = { - UDATA (&dc_svc, TT_MODE_7B+UNIT_IDLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT + UDATA (&dc_svc, TT_MODE_7B+UNIT_IDLE+UNIT_DISABLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG dc_reg[] = { diff --git a/PDP10/kx10_defs.h b/PDP10/kx10_defs.h index 26f2b5e0..13c453cb 100644 --- a/PDP10/kx10_defs.h +++ b/PDP10/kx10_defs.h @@ -167,6 +167,7 @@ extern DEBTAB crd_debug[]; #define BIT9 00000400000000LL #define BIT10 00000200000000LL #define BIT10_35 00000377777777LL +#define BIT17 00000001000000LL #define MANT 00000777777777LL #define EXPO 00377000000000LL #define FPHBIT 01000000000000000000000LL @@ -375,6 +376,7 @@ extern DEVICE dkb_dev; extern DEVICE auxcpu_dev; extern DEVICE dpk_dev; extern DEVICE wcnsls_dev; /* MIT Spacewar Consoles */ +extern DEVICE ai_dev; extern DEVICE dct_dev; /* PDP6 devices. */ extern DEVICE dtc_dev; extern DEVICE mtc_dev; @@ -478,6 +480,7 @@ int auxcpu_write (int addr, t_uint64); #define NUM_DEVS_IMP 1 #define NUM_DEVS_CH10 ITS #define NUM_DEVS_DPK ITS +#define NUM_DEVS_AI ITS #endif /* Global data */ diff --git a/PDP10/kx10_lp.c b/PDP10/kx10_lp.c index ceb0ecf9..fc1aafbe 100644 --- a/PDP10/kx10_lp.c +++ b/PDP10/kx10_lp.c @@ -40,6 +40,8 @@ #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_UTF8 (2 << UNIT_V_CT) @@ -62,6 +64,10 @@ 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_setdev(UNIT *, int32, CONST char *, void *); +t_stat lpt_getdev(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); @@ -79,7 +85,7 @@ uint8 lpt_chbuf[5]; /* Read in Character buffers */ DIB lpt_dib = { LP_DEVNUM, 1, &lpt_devio, NULL }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), 100 + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 66), 100 }; REG lpt_reg[] = { @@ -94,6 +100,10 @@ MTAB lpt_mod[] = { {UNIT_CT, 0, "Lower case", "LC", NULL}, {UNIT_CT, UNIT_UC, "Upper case", "UC", NULL}, {UNIT_CT, UNIT_UTF8, "UTF8 ouput", "UTF8", NULL}, + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE", + &lpt_setlpp, &lpt_getlpp, NULL, "Number of lines per page"}, + {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DEV", "DEV", + &lpt_setdev, &lpt_getdev, NULL, "Device address of printer defualt 124"}, { 0 } }; @@ -174,11 +184,19 @@ lpt_printline(UNIT *uptr, int nl) { /* Stick a carraige return and linefeed as needed */ if (uptr->COL != 0 || trim) lpt_buffer[uptr->POS++] = '\r'; - if (nl) { + 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; if (ferror (uptr->fileref)) { /* error? */ @@ -231,6 +249,8 @@ 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; if ((uptr->flags & UNIT_UTF8) && c < 040) { @@ -250,8 +270,6 @@ lpt_output(UNIT *uptr, char c) { lpt_buffer[uptr->POS++] = c; uptr->COL++; } - if (uptr->COL == 132) - lpt_printline(uptr, 1); return; } @@ -265,6 +283,7 @@ t_stat lpt_svc (UNIT *uptr) set_interrupt(LP_DEVNUM, uptr->STATUS); return SCPE_OK; } + if ((uptr->flags & UNIT_ATT) == 0) { uptr->STATUS |= ERR_FLG; set_interrupt(LP_DEVNUM, (uptr->STATUS >> 3)); @@ -300,45 +319,47 @@ t_stat lpt_svc (UNIT *uptr) break; case 012: /* Line feed, print line, space one line */ lpt_printline(uptr, 1); - uptr->LINE++; 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 even lines */ + 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 021: /* Skip third lines */ + 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 022: /* Skip one line */ - lpt_printline(uptr, 1); - sim_fwrite("\r\n", 1, 2, uptr->fileref); - uptr->LINE+=2; - break; - case 023: /* Skip every 10 lines */ - lpt_printline(uptr, 1); - while((uptr->LINE % 10) != 0) { - sim_fwrite("\r\n", 1, 2, uptr->fileref); - uptr->LINE++; - } + case 023: /* Skip one line */ + lpt_printline(uptr, -1); break; default: /* Ignore */ break; @@ -388,12 +409,74 @@ 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_setdev(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, 8, 01000, &r); + if (r != SCPE_OK) + return SCPE_ARG; + if ((i & 03) != 0) + return SCPE_ARG; + lpt_dib.dev_num = (int)i; + return SCPE_OK; +} + +t_stat +lpt_getdev(FILE *st, UNIT *uptr, int32 v, CONST void *desc) +{ + if (uptr == NULL) + return SCPE_IERR; + fprintf(st, "dev=%03o", lpt_dib.dev_num); + 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); diff --git a/PDP10/kx10_mt.c b/PDP10/kx10_mt.c index 0ce3ee87..9e45039f 100644 --- a/PDP10/kx10_mt.c +++ b/PDP10/kx10_mt.c @@ -240,6 +240,8 @@ t_stat mt_devio(uint32 dev, uint64 *data) { res |= ((uint64)wr_eor) << 21; if (dptr->flags & MTDF_TYPEB) res |= 7LL; /* Force DATA PIA to 7 on type B */ + if (cpu_unit[0].flags & UNIT_ITSPAGE) + res |= SMASK; *data = res; sim_debug(DEBUG_CONI, dptr, "MT CONI %03o status %06o %o %o PC=%06o\n", dev, (uint32)res, mt_sel_unit, mt_pia, PC); @@ -613,7 +615,7 @@ t_stat mt_srv(UNIT * uptr) if (uptr->flags & MTUF_7TRK) { cc = 6 * (5 - uptr->CPOS); ch = mt_buffer[uptr->BPOS]; - if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^ + if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^ (ch & 0x40) ^ parity_table[ch & 0x3f]) != 0) { mt_status |= PARITY_ERR; } @@ -692,8 +694,8 @@ t_stat mt_srv(UNIT * uptr) if ((uptr->CNTRL & MT_BRFUL) != 0) { if (uptr->flags & MTUF_7TRK) { ch = mt_buffer[uptr->BPOS]; - if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^ - parity_table[ch & 0x3f]) != (ch & 0x40)) { + if ((((uptr->CNTRL & ODD_PARITY) ? 0x40 : 0) ^ (ch & 0x40) ^ + parity_table[ch & 0x3f]) != 0) { mt_status |= PARITY_ERR; } mt_buffer[uptr->BPOS] &= 0x3f; @@ -869,16 +871,22 @@ t_stat mt_srv(UNIT * uptr) } void mt_read_word(UNIT *uptr) { - int i, cc, ch; + int i, cc, ch, cc_max; mt_df10.buf = 0; - for(i = 0; i <= 4; i++) { - cc = (8 * (3 - i)) + 4; + cc_max = (uptr->flags & MTUF_7TRK) ? 5: 4; + for(i = 0; i <= cc_max; i++) { ch = mt_buffer[uptr->BPOS]; - if (cc < 0) - mt_df10.buf |= (uint64)(ch & 0x3f); - else - mt_df10.buf |= (uint64)(ch & 0xff) << cc; + if (uptr->flags & MTUF_7TRK) { + cc = 6 * (5 - i); + mt_df10.buf |= (uint64)(ch & 0x3f) << cc; + } else { + cc = (8 * (3 - i)) + 4; + if (cc < 0) + mt_df10.buf |= (uint64)(ch & 0x3f); + else + mt_df10.buf |= (uint64)(ch & 0xff) << cc; + } uptr->BPOS++; } } diff --git a/PDP10/kx10_sys.c b/PDP10/kx10_sys.c index 534942c5..d9e0faff 100644 --- a/PDP10/kx10_sys.c +++ b/PDP10/kx10_sys.c @@ -187,6 +187,9 @@ DEVICE *sim_devices[] = { #endif #if NUM_DEVS_DPK > 0 &dpk_dev, +#endif +#if NUM_DEVS_AI > 0 + &ai_dev, #endif NULL }; @@ -385,14 +388,16 @@ t_stat load_sblk (FILE *fileref) and then comes the data. Last is a checksum word. */ while (get_evac (fileref, &word) == 0 && (word & SMASK)) { check = word; - count = (int)((((word >> 18) ^ RMASK) + 1) & RMASK); + count = (word >> 18) & RMASK; addr = word & RMASK; - while (count-- > 0) { + while (count != 0) { if (get_evac (fileref, &word)) return SCPE_FMT; M[addr++] = word; check = (check << 1) + (check >> 35) + word; check &= FMASK; + count++; + count &= RMASK; } if (get_evac (fileref, &word)) return SCPE_FMT; diff --git a/Visual Studio Projects/PDP10-KA.vcproj b/Visual Studio Projects/PDP10-KA.vcproj index 975736b7..6b1a13b5 100644 --- a/Visual Studio Projects/PDP10-KA.vcproj +++ b/Visual Studio Projects/PDP10-KA.vcproj @@ -193,6 +193,10 @@ Name="Source Files" Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" > + + diff --git a/descrip.mms b/descrip.mms index 51711e50..6acbcaef 100644 --- a/descrip.mms +++ b/descrip.mms @@ -655,7 +655,7 @@ KA10_SOURCE = $(KA10_DIR)KX10_CPU.C,\ $(KA10_DIR)PDP6_DTC.C,$(KA10_DIR)PDP6_MTC.C,\ $(KA10_DIR)PDP6_DSK.C,$(KA10_DIR)PDP6_DCS.C,\ $(KA10_DIR)KA10_DPK.C,$(KA10_DIR)KX10_DPY.C,\ - $(SIMH_DIR)SIM_CARD.C + $(KA10_DIR)KA10_AI.C,$(SIMH_DIR)SIM_CARD.C KA10_OPTIONS = /INCL=($(SIMH_DIR),$(KA10_DIR))\ /DEF=($(CC_DEFS),"KA=1","USE_INT64=1","USE_SIM_CARD=1"$(PCAP_DEFS)) diff --git a/doc/ka10_doc.doc b/doc/ka10_doc.doc index caa10026180adbff7417081fcf5fe3ec5ec07684..9bdca481ee7a7932a2ae24aebf77d59d40de30a6 100644 GIT binary patch delta 22789 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 z zA!)ZOkqt?`l@!~sJr>^+Qb5v54dNiPMpY4OBQNP9fe#CUk>qGhq?WdAk>+>g;pqV`#^?zpZ_Ok&$;;?~cNb0Pl z%Sx*3W=LwRq{Z5f29FeR0u)xthkVwsPEwb=l?BO`l}y<_NS18g$JT@6yKxSjV&pL* zACfLBsj|f&RhBGSyF$Z^P=DvJ3Q3jS2T7HUJ#1G4+Xu;)&G_V8A^!|U zWFiaGKjlq~ZQ}q0NubSaJNpUGxr&p+yPB`$(`G?(X@?=Zkq*hJ9sbP1iCKphJj@Hp zt*wIO)=FNjLgw?f6d;3=;N#t zB>h!VUM1aCZhmQ3wRI0MsQ)_oG&SDdt9w}9_HwvO3y^}64=cH_`Dlma!xo|P8(J7` z-`M(aC8rd3dON(MO_dvKwu2uLsla|(3n9n_2Ln#$jV0BTj`N{Sr^?vXSc7Kl#{uZy zjyiN$7Wz88uSLpOM~p=h3Q&o|h#Fu~u>}n{fg}IJ$HgE$<|Mm0oQLc>6-k`G*4*UY zpDyr#+ynGnKF61uZg^bd(BmSbmmwK7Ll$x(rfIwva;?Kb7rA9m=Tc?V?^o@V?^W-Lyj2_A|W}( zkMU8jgRT+7GDHl6Vm`zek`d!Njzh$-46?2gF^ofu!x#~{_WOK!R6uh#+x)#=KkEJb zxzD-h+~=Ni&%K`WeQtK4Q}!9h!eFgv_pD=@_VXGi-Fm&#?7NkUP)cPl|IgAFEFau( zt9?x2_4Ox1YX)x!b9V4utCXEm&6c?yQ4a-7QL5cXDYx5|>bg^@#s`#2eMG75?<;jU zQK^h1r94<+(aTDeZc%E}>qOem8w0dl;1G#m8RBFT#izffAg4cRt`#4Oj2s% zG^NS{l}aYhfyGL#d{C(d*hecBk8-#@q*NBV5Er9VG0r04VWkRj6cb{VT8vT*B9`qd zLLU;AC{=}1SoEk;8y{6>)y|8+IHfYt3XjK>O2K|O#4DAE<5i+z+WWgsfC57tLlK+*7C;B%>Cm z<^3~kCE5|3s#H3Pa0q7+@+?)4a-6_0LeofxTJ*sEIrbjP;kAltL^1j?<42SSa|I9G z@J?512?}rop3k$@*oO%jtbi0W!28D(j-pKV%nP)s)udlb8$|0%O08N)mF7@I>)GYG zd`^2D-k{W;eCqrarJ^>H*CyKMtJJ@10riSDglwUKY-QJMBctskETWJdRM9S_f=b8) z;bl|{CYCGJiGnw&s!F9=cGKwg&=&TR`CFugbFEVPJ4$V-XTuLrB?qah_o(-yw2x-W z`G7{y+CqjOvap>69b|Tr6}o6RA5rH$?7lySY_b~+j8>lZlj`cUNk6-3RE&dZH;Wk03dod5`cmr?ZKXBuXN;x3{ z8OX#N_;>sXj*c7>n2TqThkX17J?O6to0Xc01X!>Yhj13>Fw2dWhE%+Uckvzu;W3Fr0uRDBfrmu=4F7`H(1H`_ z!rxx3arAZ8EI!jcO@Wm4?(~_K4H2F-+0zH?EZG48HJvjKUT6MTQcqLrJ2RB3yhEw) zl62|aN-D_TpUhZVf z?$ci1oZzKLDT{Z)bf;#0Bzt*aPev#Bx~$_R?NWXDm=|q1eTSW;dPAON zQSQj=n*4kR&62nw+A?v2o#l==cT4t~2{ro0Zrzf!G1d}(r)@#}tE>EL!uIys)#SfD z7$n(Sw)F;E(m$HB`7b?|-oGSR7MzN*Y&w-vQ`M(y(=ya^Y)_hcO08BIyn0GyB8^w6 z>S`jqEJ(qBxWg4Ff=7py`oKl)^{X_g8$miucr*KF=j zyV)r6(&DUf4qB3FpRO&lb2|6smtTq<8r{b3#b!9%mN4&10MvbUbSS*v`6 zTtbaEf2hS7F^lz9+1q7?wo<#ryqO+ddid=q!VEg;04&65x|)G8-HjLZorP@VpbX`Z zE4)fLyK~}%E5Z2Ow#au)q2C-OzeW*nphA@n?IEQ64 zw-rc2JsNNjjqsnsmw{Z?exU|>FPreai5R1Lohg#U* z!dU_n;D|J=LOSZvfP-j+zZc&I0a$~z$nxUcm(7bVbfX8cQ`v2ZLp*9xhy8H(=F|aC zcp(ef$U!eop%49txs|-I1XZZU9_)p?5Bb2;%)=_ABLkUe$A5jnF8{|DBTs*|J$+<* zI%a$N(Dw8@+tYitr{CC~YHUwx+#kFDr(9ZG-2J@obx=miGuj%ni5jsBUKFIFr0foK z!f_f667o+ES7aa)t8oNJ(To;^`qBn52RpF~#VCQ@bc%%ol8}s*NWl>tHS^Gnb5Qhq zI_!{)l}JGmc48Nbq0=wg!5*_Q2XhgIT_{EgTG57fbU-@Da73UGn_=F zi2Ll*flt+^>XhxN%l6b^dup*g9kx9kv^~|?p7z+DDn1?H3-QOk{tIV-vHO0(nD@77 zB=`lFQ)3gTOWr?W!?WCk1qA zs6`$8@1nCq00L2fLTrY4h=*aE#W^esrkNlKt!P6#IuOS7MmQpngIwexAE(fVegucm zq!5bP*p4FXL@nyDAN3(LA)oJXnffAIW3=KGlMl|6tj-Usz}x7??8mn&tw`n(oku9K6>n5vn4$@`2c<3Im^)8yFnL6^M$DW}-6pZ9XA9{c{g zW8a$|HJ|T>BjsB)p>8qVD_YTs0V7eBp+r4|8-c<3&0$P=GBcLphG11>NX@Lo7!>eBg^kh`|aZp#MZQO&sXorkEcA*K|YA-~6vy_!Z0gRS*9iBb)K4#>N-4dyGH* zM4M=ilY;D*(iY*2i3ouVea=M~mO_R>laP#UkRj1xl%O0HXn_oqcH%fZ9_I=XzVJf; z0uh2x%zc~#CX5%WA>*n!$i;rh7;6&_K~JD)f+_%V0Er)WGSDbSH$w8C% zoOu%*H06ALDT~aq>~YzuBRB;ap&rIrcs$82f{fDmAs$I6g^XTTp&F+lBiW4NsI!>8 zj4DC|B9VuDY=Y-FEc_BmJ>Bzu#6hVf<_hKJ9&!_q3*8um zjLUl@@$C?cC6ICYbjYm9#rhco{z8iSBY2=`=mf|-XT zBtvE;vXO%$IEq%tOvM1sVBrrrVz2}sD1<>5YdQ1Eb<@|5EZDzQ8eQW1~G())wI(! zv{Uq~QU9cRdC~YH-8niSGiLIy;X!#EeHimz4H`dqi5~ggpK7-lT`y@<%}Zq^neqrm z2v#8-`Phg5xM+3?2`(&@?(`N1pNBnPgSuH$;?x{>44=zCGS!TgwP zLD>d+B~;)jnlS{K%JR$Sn<5d*kc&K2L#Daf&<^icI99O$3z3f|^q?2^8)*lKgiMPS zV)I7ocN;I9H_;g21z-3f87q;A)yP6NDo}|!>_-z0!RJ+WF;1Wl6AQ=>ix7vk$VVxv z(TWZ;51k18KeR~fFXZ%y1~~kTo(5}?g=Vy%-ooeT#Bl^~p$#A!F^~!Ak-Gdl_3+jD z)L{3>XF;~7kw;s#+a8Y{<65Z?$J)r`LN>~%U$5O|)V!kIEVbuk9;r>WL`sa@O6iD2 zJeHyoRj5Y;ns5l7+t@V-L=eIdjvUC0< z!721%7-tbt#Ak>>EK-n)DpaE$4LF3u2-v~KVJ^ZDg$3A-B9xs9de-{kAV7dx>FmGG~m ztHNyLA`hj%rfkGjQ!tW|0{h+UO1L5enaD;Ly3vo=J@lK{Yvy4eoNHJCbM{hch(b9k zuooV0(dw`UYtfDloZH79uu?cyq6vrL_BO{PA|QbsXVnn@^WQ)E)n7(l+m;w>U)FNX zk|Grq`^goZIF55r?@%JDPz{HA&a?9|Rx_;fO#P%F&1>975!Kbf#E@V$?O#d~pzs zaC@JNo%cQ1KfH)+qL2D5eH6}M@VAEh2JMttf?{%i&$q-*)T04@M`;)cK{yhSh!se} z03?3EkwzbYKx7~jn^BED(3@$c@P-eZKcMqP5Q0Bo@8s|z7o|9eMl5RKFhCNL(E^E2 z=tDm;KBORQ#ul7L#UE+SC}?MIp&S($fW$O7|A`ikImkhB2i4aRPis3y)gb9O3(_hEIBkmQg!d%PiX0*Vqi|T+6{4oQ;2*GAZ zu*EKvq6}52hW-(I5YBLeJG|k8bVz{4YOFyk+CJtxq32`v?ipSTBCdx$ix#w^3*GSj zGgXaH%tka~un7g&g<_OJB0$bT^-_g!g$F#b5rx={`oECRDe^gGW)JZq6=^t%xqoF3 zViDr86x&gR3RI#IP0;)J=5Rn8+7a+MZ4E1s1m9u407kBE`g_Jd887`*TOTAJSAD_G zghZrxDouIA2Z0De2tpC5tU;T!4(;J>4r~|pqaI6cU>hLQj$5z|Lr(PG7;@$ryIk2> zXmaBK#bF$QOixx=zh9vJQk!2fiB{xJML=c_Wrk2@0%cB4=H6tEP3F?Fyr{IPY^*oU z9x|ns;lqx%&M(vsXy2VUjh2OCUz+iB_LU#yLndcr5@w4(E%SCNbp|bGCd(l61Tr5W zr;%x&DudD^k-Ut5oXceik&DQ$q2uUc+1GP3}DMZb>1x6NeH_HGL9_c z#fKo{#XZQnn>H|?&5dHS7Sc?<#{u=g*kW$iI*hzREh6MyTG7Qny2H`GJ)M8}Y9+VcEJesbZVzN2R|auq09OWY2NoMao~D^bMSIVSH^v#5d#_fm2uy}v3Xqi z&Hct*McNc?P@)cuPwn+dMsbmL3x(}3(jskz-EJ@WWg`bNmMr7Q5_LE(TU$=fDr{v(X|58}=l~g=mXYcBXv4Kw`%tSksuT3Pjay&W zPP$0U<5I|gwG395kITYE!XYal{T zyKDT%5?|R38SIvU?l{AxbTo5U3B8PmjD5?vcX7;Ro9`;2nI(|%a2X3fdwCic3Eeyg z^)TCy1jD6LYaP26oFuX{5zCNaI8|!x7eD@$_IK^*_%)7cT@y*z3>ik3A@m7`OZ6pr zPKf2?2^m@UHJqx)*F_>x zmq143WnjGM@+1n z&L#Y|12SSSqxFG?%i&AP35?^a1u}>)1NfPjCz0UY)sS(08PjjQJc-2iwn2vaWtiW? zaB04zAdkoB_93JHGV-5tc@l{XPK8Ve$Yj9&%acgpa6M#>K;{P=441Y`3Uc7;X98r} zK&A{5FH7PnVaLm`0!fewgGzFQxw@D3 zV`G|}YRtL1hs5-3@LW&N;HORY)4rFiaqKxT8>(|XmWm%H{Y{*2AOafiYvLydR$Rv|Y zFkQ2>9$>fzxT>UrYU2+igX;uG=gTPJ-YlF;^$qd<*3r>|t$6pzpgW9d% z^GR-%BDmjqQGUGZv`_bmb>0HhvO>&9t>-mkE zkxBCJhs@~8Z0`87Y|UurcFoo3ALMNH&B~B`-5`_1GC_PT%8+~)K_;GM()n92gL;vC zb0Cx1GLb#LjBl}CC`9!gddZkSL;r)ZEM0dpZgkNdzey!gpcFC)nTeNK z_-k9Bk1|Oik&vl=ndTo~;J4HAB;Pg2frJiRi!vnN2FT>UO#EMqG9=%ANI-!E6I_cj zBwsH`kiybyQ3j1n@=bsQKuGYz`0p|H2wE?{XELB=WC$fq}{-g>1wYcrNGPf4C5OGH&-~8Q#O%6z5De<}cIm z9@I7&^Ooqh7-#+UTfRv@HCfp&rOX6mpa>G;vfa2VRG(rEnxVI7lVrgzNX$zoB;I9Q z0$FeZ5&&}{_+?xIiH7loM8jN&gc+A$1s^0qLSrt3#f(cJaWWNX#7K+`&tns~$nQ~4 zLtz zh6LD1aLv$_Q%mL&cQXu$yBUeOvAP85f74tf_9h+@<{}|3O$N)ayp0n5atIRrG7|Y> zxP6?VI&r2$jX{*fW*TL!y}o0&0wX~Wv(oj zkeC!mNQ{KTv{_xkWVwXIv_nE-BpfEr>JmBfMR*+#35gjAhq1au$Z`pbX@Z2sNJvbG z)n$P!m#~;nNLb8BNQ~7bN|sA#OdcdMW+W=cwtS{U$F!goZK!{mGXi>X2KFgj;bXhe zzge4Njf~anHD_7i0dM%F7|u)dAKdVw-On7C-}H`Gn03t(Jx_C$9~?(v0Tv=T#c++& zA0JI;Fiv~7_1AIw!*Yty zb=Z%CI0X5T^Jhjx6=Neo8MMrKOZD*4)oq0zSgOz0JSF7-&fqNcXE=o5_l)70pual0 zl9U;vP4VM1e?(y+vLHXDe%Oe}qqKQ>x~H)?QGaI4iVcZ+gf>MI<)8#*XoLLzI?RYD zkrhj1#bx^Z(G_i*`G;ltENzOU?7$#~5tPb^8NS}yk}?G0h{P(SM-AvcV;+I(c464as| z$00YJxY~SVozqZ1qJw}3SakxHDZ-A@KN7nIzKLW7~a&MHY$S0rf+=Eq8kbyO*g4|x^Dze#l zKAT!rYd{n93_3`RJ$cPrraM{gw7Xdj_GzQX`Pl0fS;Y}<@PH5GCNEc+jjR%Y2rR$~ z$bDkQW^?6>CP|r!P1uZDG~ny4Eh!J;1bX4l7@{}6-rADV2jN%%2||~<+I+3G-6drj zR>7WsjBZC!rr}4oiDwUj#IonVV63Xvy{zHY`ax}~M73{( zM72vqdkZ9*U2e5gxpkgtijih#aYi5fUVWYBDN*cRkSKPEV9$U=upeG)cpukiTVwX=)taxwvLAuO zvIo4xmLmwYkhu2Nmn8Ll)~9Oq9a@k?xJz{V1jIoi+)qIw+|wZu?h@TD5$&ti8F!uG znnpIx`dFR*hUO{v4@!r`wM$HU2PBp~Fz5Ux?PrrbC8|9L63s4=?7JWl><;V4r1F(} z5KVw1B(7cJ*d>NNAB}L$9SN|phBvU=JtctM4HB>}!RiH&0QJb1&*yoNlD#EVJqi-4 zo(l;SmmqNo5Fg%PC19sZ^OPv@vydopi4b1_i4fnDe?BYOubvVsz84ZJ?(+&)dXPBr zjjxPJ9A&4+NB8OD>J>3PPl&**N(n}_wE`>E^YCQTAtE`jA$kbrXESIG_j*!1d1 zn>E6Z>Y+y31e25Y;7GX7qwnfoV>5ousxLDh)Jz`w`I7!Hz=C_<)jg&=a1$t1j4D(^ zg4Mgw4GCCxEwEi6g`bhjq7ELO*vG>?#kA#-S3LL`uMX&L*7sWUd$c?3?;m?@B)6Ax zgBKPf8WQ&|x16dnX4T2u{IJfE)WVT8RhDK$BI3(X4vC6y!)2)hWNAA(AYt+nA}`_b z5*jZd@e&R%q3|JFqydqaZKbGMyuAf3`8B|JS35|%C@>4T84bO}dq-EJknF3nd$(j^={>gODJSO^JA zmr!&GLysyt-vgbX75PT7M1s*J5Pc6M09}I5gCIfYMLW)??vgfF#FCwmsB?)pp8$zE zmx%L-T~_aIHsDSPJ5Pdynyc5S;$rsI>-3#yMH>bnxB5C`%<`m{BYy36>$5$&MVl&1 zgAs#5Y{q^_82Pxm>7^#UW$9T+fO+gMsP})RUxZ%9{wtIEh_R-f(l={U<%VJrNWgX! zVIKxCF5f}UvHYu2%TiZ_ARQUl1-WtAWqEtc(&Lc0_2de+9e!_e zn4#cJtM`D^VgYZe;9kjj8*`A297qs*S>?s!CDeFeSoh>Qz`@A%FnJhD|EfgL@)yO((E9&cN@DF-|#JMsw^$S zJ~+HZ^FshqFgEplBXuZCQ?U)LXoG~_4`WQ~k-ewQv&@?7V`Tf8+^t*A>8aXnlIrw6 zw#-UTf_UUWg7gnTZaVj0TNj)B-+I9GmNre^O5DCgaE^(rY_A}qV%^xqV$I_j0Fd1 zoM<>;^|qHp5{Z8h5`iDoz#c^ia^QQ=>g^zjB>Y}N?j_v50upK;^&Yul;d`S!y_KGR zvv#jU;Fmz6@7>=gX%kxo3AUF&`ZKQ>h^OY$IL^%7Da4GF1l zZ5f+Ng6rEL!SxbYzZw!)Kk(t0RK6p(2W06WB;0-go7y=jA))qX+RvYV-A(j`5_CTZ z3AoQi9`Yf9_qiRC?|s(g9;Vl{Ai3RO`!Tk@lU;M1U4aV!bcW^o|xOOE+Q@dNAQMn}b9g zf!*IZ1h4>ESayc<{--pkL5_WF9<(*L#2{0N<}CN2+=3#U7&M%Fw3Ei)f=zy!GTdgF z`kYU&ybHYu{mkkdVw$G$S@3sE&Ca2p(HS8O1($qQz_LPY2lFQ5*5fBfN{2IwF8NIE zfw>bU@c(?=dbi8HF=s%2%pgBxNQeB8ArSIQh5g`{3f9}hOb#O(d9SHCKz_R5rEEW4 vn9cJX%taW&5dpcaZIrSGgqx0DuT3^S|E|fbJ@Lz*EHG(Wv$5uWQ{Mjt*HB!O diff --git a/doc/ki10_doc.doc b/doc/ki10_doc.doc index 06a99b2da1e5aec0fa8690acd9af951101bfdacb..42c1f6bd94847f45ad5842c7a29afa059499a339 100644 GIT binary patch delta 13871 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 Kqv#&fmj4DQ=PL66 diff --git a/makefile b/makefile index bd016ca0..8b30f740 100644 --- a/makefile +++ b/makefile @@ -1915,7 +1915,8 @@ KA10 = ${KA10D}/kx10_cpu.c ${KA10D}/kx10_sys.c ${KA10D}/kx10_df.c \ ${KA10D}/ka10_ten11.c ${KA10D}/ka10_auxcpu.c $(KA10D)/ka10_pmp.c \ ${KA10D}/ka10_dkb.c ${KA10D}/pdp6_dct.c ${KA10D}/pdp6_dtc.c \ ${KA10D}/pdp6_mtc.c ${KA10D}/pdp6_dsk.c ${KA10D}/pdp6_dcs.c \ - ${KA10D}/ka10_dpk.c ${KA10D}/kx10_dpy.c ${DISPLAYL} $(DISPLAY340) + ${KA10D}/ka10_dpk.c ${KA10D}/kx10_dpy.c ${PDP10D}/ka10_ai.c \ + ${DISPLAYL} $(DISPLAY340) KA10_OPT = -DKA=1 -DUSE_INT64 -I $(KA10D) -DUSE_SIM_CARD ${NETWORK_OPT} $(DISPLAY_OPT) $(KA10_DISPLAY_OPT) ifneq ($(PANDA_LIGHTS),) # ONLY for Panda display.