From 40e11301cea465ec321993e414ae8f1ecab872ae Mon Sep 17 00:00:00 2001 From: Lars Brinkhoff Date: Tue, 17 Jul 2018 10:52:20 +0200 Subject: [PATCH] KA10: Rubin 10-11 interface. The Rubin 10-11 interface is shared memory between a PDP-10 and eight Unibuses. --- PDP10/ka10_cpu.c | 22 +++ PDP10/ka10_defs.h | 5 + PDP10/ka10_sys.c | 3 + PDP10/ka10_ten11.c | 405 +++++++++++++++++++++++++++++++++++++++++++++ makefile | 3 +- 5 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 PDP10/ka10_ten11.c diff --git a/PDP10/ka10_cpu.c b/PDP10/ka10_cpu.c index 59e402a..3b9d613 100644 --- a/PDP10/ka10_cpu.c +++ b/PDP10/ka10_cpu.c @@ -216,6 +216,9 @@ int32 qua_tps = 125000; #endif int32 tmxr_poll = 10000; +/* Physical address range for Rubin 10-11 interface. */ +#define T11RANGE(addr) ((addr) >= 03000000) + DEVICE *rh_devs[] = { #if (NUM_DEVS_RS > 0) &rsa_dev, @@ -682,6 +685,7 @@ int opflags[] = { #endif #if ITS #define QITS (cpu_unit[0].flags & UNIT_ITSPAGE) +#define QTEN11 (ten11_unit[0].flags & UNIT_ATT) #else #define QITS 0 #endif @@ -1890,6 +1894,15 @@ read: sim_interval--; if (!page_lookup(AB, flag, &addr, 0, cur_context, fetch)) return 1; +#if ITS + if (QTEN11 && T11RANGE(addr)) { + if (ten11_read (addr, &MB)) { + nxm_flag = 1; + return 1; + } + return 0; + } +#endif if (addr >= (int)MEMSIZE) { nxm_flag = 1; return 1; @@ -1948,6 +1961,15 @@ write: sim_interval--; if (!page_lookup(AB, flag, &addr, 1, cur_context, 0)) return 1; +#if ITS + if (QTEN11 && T11RANGE(addr)) { + if (ten11_write (addr, MB)) { + nxm_flag = 1; + return 1; + } + return 0; + } +#endif if (addr >= (int)MEMSIZE) { nxm_flag = 1; return 1; diff --git a/PDP10/ka10_defs.h b/PDP10/ka10_defs.h index fa549e0..69d4b3f 100644 --- a/PDP10/ka10_defs.h +++ b/PDP10/ka10_defs.h @@ -295,6 +295,7 @@ extern int check_irq_level(); extern void restore_pi_hold(); extern void set_pi_hold(); extern UNIT cpu_unit[]; +extern UNIT ten11_unit[]; extern DEVICE cpu_dev; extern DEVICE cty_dev; extern DEVICE mt_dev; @@ -325,6 +326,7 @@ extern DEVICE imx_dev; extern DEVICE imp_dev; extern DEVICE tk10_dev; extern DEVICE mty_dev; +extern DEVICE ten11_dev; extern DEVICE wcnsls_dev; /* MIT Spacewar Consoles */ extern t_stat (*dev_tab[128])(uint32 dev, uint64 *data); @@ -371,6 +373,8 @@ int df10_fetch(struct df10 *df); int df10_read(struct df10 *df); int df10_write(struct df10 *df); +int ten11_read (int addr, uint64 *data); +int ten11_write (int addr, uint64 data); /* Console lights. */ extern void ka10_lights_init (void); @@ -397,6 +401,7 @@ extern void ka10_lights_clear_aux (int); #define NUM_DEVS_IMX ITS #define NUM_DEVS_TK10 ITS #define NUM_DEVS_MTY ITS +#define NUM_DEVS_TEN11 ITS #define NUM_DEVS_DPY USE_DISPLAY #define NUM_DEVS_WCNSLS USE_DISPLAY #define NUM_DEVS_IMP 0 diff --git a/PDP10/ka10_sys.c b/PDP10/ka10_sys.c index d9d511d..30a4f39 100644 --- a/PDP10/ka10_sys.c +++ b/PDP10/ka10_sys.c @@ -146,6 +146,9 @@ DEVICE *sim_devices[] = { #endif #if NUM_DEVS_MTY > 0 &mty_dev, +#endif +#if NUM_DEVS_TEN11 > 0 + &ten11_dev, #endif NULL }; diff --git a/PDP10/ka10_ten11.c b/PDP10/ka10_ten11.c new file mode 100644 index 0000000..f734c15 --- /dev/null +++ b/PDP10/ka10_ten11.c @@ -0,0 +1,405 @@ +/* ka10_ten11.c: Rubin 10-11 interface. + + Copyright (c) 2018, 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 + RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + This is a device which interfaces with eight Unibuses. It's + specific to the MIT AI lab PDP-10. +*/ + +#include "ka10_defs.h" +#include "sim_tmxr.h" + +#include +#include +#include +#include +#include +#include +#include + + +/* Rubin 10-11 pager. */ +static uint64 ten11_pager[256]; + +/* Physical address of 10-11 control page. */ +#define T11CPA 03776000 + +/* Bits in a 10-11 page table entry. */ +#define T11VALID (0400000000000LL) +#define T11WRITE (0200000000000LL) +#define T11PDP11 (0003400000000LL) +#define T11ADDR (0000377776000LL) +#define T11LIMIT (0000000001777LL) + +/* External Unibus interface. */ +#define DATO 1 +#define DATI 2 +#define ACK 3 +#define ERR 4 +#define TIMEOUT 5 + +#define TEN11_POLL 100 + +/* Simulator time units for a Unibus memory cycle. */ +#define UNIBUS_MEM_CYCLE 100 + + +static t_stat ten11_svc (UNIT *uptr); +static t_stat ten11_reset (DEVICE *dptr); +static t_stat ten11_attach (UNIT *uptr, CONST char *ptr); +static t_stat ten11_detach (UNIT *uptr); +static t_stat ten11_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +static const char *ten11_description (DEVICE *dptr); + +UNIT ten11_unit[1] = { + { UDATA (&ten11_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 }, +}; + +static REG ten11_reg[] = { + { DRDATAD (POLL, ten11_unit[0].wait, 24, "poll interval"), PV_LEFT }, + { NULL } +}; + +static MTAB ten11_mod[] = { + { 0 } +}; + +#define DBG_TRC 1 +#define DBG_CMD 2 + +static DEBTAB ten11_debug[] = { + {"TRACE", DBG_TRC, "Routine trace"}, + {"CMD", DBG_CMD, "Command Processing"}, + {0}, +}; + +DEVICE ten11_dev = { + "TEN11", ten11_unit, ten11_reg, ten11_mod, + 1, 8, 16, 2, 8, 16, + NULL, /* examine */ + NULL, /* deposit */ + &ten11_reset, /* reset */ + NULL, /* boot */ + ten11_attach, /* attach */ + ten11_detach, /* detach */ + NULL, /* context */ + DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX, + DBG_CMD, /* debug control */ + ten11_debug, /* debug flags */ + NULL, /* memory size chage */ + NULL, /* logical name */ + NULL, /* help */ + &ten11_attach_help, /* attach help */ + NULL, /* help context */ + &ten11_description, /* description */ +}; + +static TMLN ten11_ldsc; /* line descriptor */ +static TMXR ten11_desc = { 1, 0, 0, &ten11_ldsc }; /* mux descriptor */ + +static t_stat ten11_reset (DEVICE *dptr) +{ + sim_debug(DBG_TRC, dptr, "ten11_reset()\n"); + + ten11_unit[0].flags |= UNIT_ATTABLE | UNIT_IDLE; + ten11_desc.packet = TRUE; + ten11_desc.notelnet = TRUE; + ten11_desc.buffered = 2048; + + if (ten11_unit[0].flags & UNIT_ATT) + sim_activate (&ten11_unit[0], 1000); + else + sim_cancel (&ten11_unit[0]); + + return SCPE_OK; +} + +static t_stat ten11_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + + if (!cptr || !*cptr) + return SCPE_ARG; + if (!(uptr->flags & UNIT_ATTABLE)) + return SCPE_NOATT; + r = tmxr_attach_ex (&ten11_desc, uptr, cptr, FALSE); + if (r != SCPE_OK) /* error? */ + return r; + sim_debug(DBG_TRC, &ten11_dev, "activate connection\n"); + sim_activate (uptr, 10); /* start poll */ + uptr->flags |= UNIT_ATT; + return SCPE_OK; +} + +static t_stat ten11_detach (UNIT *uptr) +{ + t_stat r; + + if (!(uptr->flags & UNIT_ATT)) + return SCPE_OK; + sim_cancel (uptr); + r = tmxr_detach (&ten11_desc, uptr); + uptr->flags &= ~UNIT_ATT; + free (uptr->filename); + uptr->filename = NULL; + return r; +} + +static void build (unsigned char *request, unsigned char octet) +{ + request[0]++; + request[request[0]] = octet; +} + +static t_stat ten11_svc (UNIT *uptr) +{ + if (tmxr_poll_conn(&ten11_desc) >= 0) { + sim_debug(DBG_CMD, &ten11_dev, "got connection\n"); + ten11_ldsc.rcve = 1; + uptr->wait = TEN11_POLL; + } + sim_activate (uptr, uptr->wait); + return SCPE_OK; +} + +static t_stat ten11_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) +{ +const char helpString[] = + /* The '*'s in the next line represent the standard text width of a help line */ + /****************************************************************************/ + " The %D device is an implementation of the Rubin PDP-10 to PDP-11 interface\n" + " facility. This allows a PDP 10 system to reach into a PDP-11 simulator\n" + " and modify or access the contents of the PDP-11 memory.\n\n" + " The device must be attached to a receive port, this is done by using the\n" + " ATTACH command to specify the receive port number.\n" + "\n" + "+sim> ATTACH %U port\n" + "\n" + ; + + return scp_help (st, dptr, uptr, flag, helpString, cptr); + return SCPE_OK; +} + + +static const char *ten11_description (DEVICE *dptr) +{ + return "Rubin PDP-10 to PDP-11 interface"; +} + +static int error (const char *message) +{ + sim_debug (DBG_TRC, &ten11_dev, "%s\r\n", message); + sim_debug (DBG_TRC, &ten11_dev, "CLOSE\r\n"); + return -1; +} + +static int transaction (unsigned char *request, unsigned char *response) +{ + const uint8 *ten11_request; + size_t size; + t_stat stat; + + stat = tmxr_put_packet_ln (&ten11_ldsc, request + 1, (size_t)request[0]); + if (stat != SCPE_OK) + return error ("Write error in transaction"); + + do { + tmxr_poll_rx (&ten11_desc); + stat = tmxr_get_packet_ln (&ten11_ldsc, &ten11_request, &size); + } while (stat != SCPE_OK || size == 0); + + if (size > 7) + return error ("Malformed transaction"); + + memcpy (response, ten11_request, size); + return 0; +} + +static int read_word (int addr, int *data) +{ + unsigned char request[8]; + unsigned char response[8]; + + sim_interval -= UNIBUS_MEM_CYCLE; + + if ((ten11_unit[0].flags & UNIT_ATT) == 0) { + *data = 0; + return 0; + } + + memset (request, 0, sizeof request); + build (request, DATI); + build (request, addr >> 16); + build (request, addr >> 8); + build (request, addr); + + transaction (request, response); + + switch (response[0]) + { + case ACK: + *data = response[2]; + *data |= response[1] << 8; + sim_debug (DBG_TRC, &ten11_dev, "Read word %06o\n", *data); + break; + case ERR: + fprintf (stderr, "TEN11: Read error %06o\r\n", addr); + *data = 0; + break; + case TIMEOUT: + fprintf (stderr, "TEN11: Read timeout %06o\r\n", addr); + *data = 0; + break; + default: + return error ("Protocol error"); + } + + return 0; +} + +int ten11_read (int addr, uint64 *data) +{ + int offset = addr & 01777; + int word1, word2; + + if (addr >= T11CPA) { + /* Accessing the control page. */ + if (offset >= 0400) { + sim_debug (DBG_TRC, &ten11_dev, + "Control page read NXM: %o @ %o\n", + offset, PC); + return 1; + } + *data = ten11_pager[offset]; + } else { + /* Accessing a memory page. */ + int page = (addr >> 10) & 0377; + uint64 mapping = ten11_pager[page]; + int unibus, uaddr, limit; + + limit = mapping & T11LIMIT; + if ((mapping & T11VALID) == 0 || offset > limit) { + sim_debug (DBG_TRC, &ten11_dev, + "(%o) %07o >= 4,,000000 / %llo / %o > %o\n", + page, addr, (mapping & T11VALID), offset, limit); + return 1; + } + + unibus = (mapping & T11PDP11) >> 26; + uaddr = ((mapping & T11ADDR) >> 10) + offset; + uaddr <<= 2; + + read_word (uaddr, &word1); + read_word (uaddr + 2, &word2); + *data = ((uint64)word1 << 20) | (word2 << 4); + + sim_debug (DBG_TRC, &ten11_dev, + "Read: (%o) %06o -> %012llo\n", + unibus, uaddr, *data); + } + return 0; +} + +static int write_word (int addr, int data) +{ + unsigned char request[8]; + unsigned char response[8]; + + sim_interval -= UNIBUS_MEM_CYCLE; + + if ((ten11_unit[0].flags & UNIT_ATT) == 0) { + return 0; + } + + memset (request, 0, sizeof request); + build (request, DATO); + build (request, addr >> 16); + build (request, addr >> 8); + build (request, addr); + build (request, data >> 8); + build (request, data); + + transaction (request, response); + + switch (response[0]) + { + case ACK: + break; + case ERR: + fprintf (stderr, "TEN11: Write error %06o\r\n", addr); + break; + case TIMEOUT: + fprintf (stderr, "TEN11: Write timeout %06o\r\n", addr); + break; + default: + return error ("Protocol error"); + } + + return 0; +} + +int ten11_write (int addr, uint64 data) +{ + int offset = addr & 01777; + + if (addr >= T11CPA) { + /* Accessing the control page. */ + if (offset >= 0400) { + sim_debug (DBG_TRC, &ten11_dev, + "Control page write NXM: %o @ %o\n", + offset, PC); + return 1; + } + ten11_pager[offset] = data; + sim_debug (DBG_TRC, &ten11_dev, + "Page %03o: %s %s (%llo) %06llo/%04llo\n", + offset, + (data & T11VALID) ? "V" : "I", + (data & T11WRITE) ? "RW" : "R", + (data & T11PDP11) >> 26, + (data & T11ADDR) >> 10, + (data & T11LIMIT)); + } else { + /* Accessing a memory page. */ + int page = (addr >> 10) & 0377; + uint64 mapping = ten11_pager[page]; + int unibus, uaddr, limit; + limit = mapping & T11LIMIT; + if ((mapping & T11VALID) == 0 || offset > limit) { + sim_debug (DBG_TRC, &ten11_dev, + "(%o) %07o >= 4,,000000 / %llo / %o > %o\n", + page, addr, (mapping & T11VALID), offset, limit); + return 1; + } + unibus = (mapping & T11PDP11) >> 26; + uaddr = ((mapping & T11ADDR) >> 10) + offset; + uaddr <<= 2; + sim_debug (DBG_TRC, &ten11_dev, + "Write: (%o) %06o <- %012llo\n", + unibus, uaddr, data); + + if ((data & 010) == 0) + write_word (uaddr, data >> 20); + if ((data & 004) == 0) + write_word (uaddr + 2, data >> 4); + } + return 0; +} diff --git a/makefile b/makefile index 981a309..3375987 100644 --- a/makefile +++ b/makefile @@ -1111,7 +1111,8 @@ KA10 = ${KA10D}/ka10_cpu.c ${KA10D}/ka10_sys.c ${KA10D}/ka10_df.c \ ${KA10D}/ka10_rp.c ${KA10D}/ka10_rc.c ${KA10D}/ka10_dt.c \ ${KA10D}/ka10_dk.c ${KA10D}/ka10_cr.c ${KA10D}/ka10_cp.c \ ${KA10D}/ka10_tu.c ${KA10D}/ka10_rs.c ${KA10D}/ka10_pd.c \ - ${KA10D}/ka10_imx.c ${KA10D}/ka10_tk10.c ${KA10D}/ka10_mty.c + ${KA10D}/ka10_imx.c ${KA10D}/ka10_tk10.c ${KA10D}/ka10_mty.c \ + ${KA10D}/ka10_ten11.c KA10_OPT = -DKA=1 -DUSE_INT64 -I $(KA10D) -DUSE_SIM_CARD # ${KA10D}/ka10_imp.c sim_imp.c sim_ncp.c sim_tun.c