diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4b5eb8b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +os: + - linux +# - osx +language: c +dist: trusty +sudo: required +env: + - CPU=ka10 TYPE340=0 + - CPU=ka10 TYPE340=1 + - CPU=ki10 TYPE340=0 +install: sh -ex dependencies.sh install_linux +script: make $CPU TYPE340=$TYPE340 +notifications: + email: lars@nocrew.org diff --git a/PDP10/ka10_auxcpu.c b/PDP10/ka10_auxcpu.c new file mode 100644 index 0000000..bf20c55 --- /dev/null +++ b/PDP10/ka10_auxcpu.c @@ -0,0 +1,397 @@ +/* ka10_auxcpu.c: Auxiliary processor. + + 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 an auxiliary processor + through shared memory and inter-processor interrupts. +*/ + +#include "ka10_defs.h" +#include "sim_tmxr.h" + +#ifndef NUM_DEVS_AUXCPU +#define NUM_DEVS_AUXCPU 0 +#endif + +#if NUM_DEVS_AUXCPU > 0 +#include +#include +#include +//#include +//#include +//#include +//#include + + +/* External bus interface. */ +#define DATO 1 +#define DATI 2 +#define ACK 3 +#define ERR 4 +#define TIMEOUT 5 +#define IRQ 6 + +/* Simulator time units for a Unibus memory cycle. */ +#define AUXCPU_MEM_CYCLE 100 + +/* Interprocessor interrupt device. */ +#define AUXCPU_DEVNUM 020 + +#define AUXCPU_POLL 1000 + + +static int pia = 0; +static int status = 0; + +static t_stat auxcpu_devio(uint32 dev, 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_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +static const char *auxcpu_description (DEVICE *dptr); + +UNIT auxcpu_unit[1] = { + { UDATA (&auxcpu_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 }, +}; + +static REG auxcpu_reg[] = { + { DRDATAD (POLL, auxcpu_unit[0].wait, 24, "poll interval"), PV_LEFT }, + { NULL } +}; + +static MTAB auxcpu_mod[] = { + { 0 } +}; + +#define DBG_TRC 1 +#define DBG_CMD 2 + +static DEBTAB auxcpu_debug[] = { + {"TRACE", DBG_TRC, "Routine trace"}, + {"CMD", DBG_CMD, "Command Processing"}, + {0}, +}; + +DEVICE auxcpu_dev = { + "AUXCPU", auxcpu_unit, auxcpu_reg, auxcpu_mod, + 1, 8, 16, 2, 8, 16, + NULL, /* examine */ + NULL, /* deposit */ + &auxcpu_reset, /* reset */ + NULL, /* boot */ + auxcpu_attach, /* attach */ + auxcpu_detach, /* detach */ + NULL, /* context */ + DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX, + DBG_CMD, /* debug control */ + auxcpu_debug, /* debug flags */ + NULL, /* memory size chage */ + NULL, /* logical name */ + NULL, /* help */ + &auxcpu_attach_help, /* attach help */ + NULL, /* help context */ + &auxcpu_description, /* description */ +}; + +static TMLN auxcpu_ldsc; /* line descriptor */ +static TMXR auxcpu_desc = { 1, 0, 0, &auxcpu_ldsc }; /* mux descriptor */ + +static t_stat auxcpu_reset (DEVICE *dptr) +{ + sim_debug(DBG_TRC, dptr, "auxcpu_reset()\n"); + + auxcpu_unit[0].flags |= UNIT_ATTABLE | UNIT_IDLE; + auxcpu_desc.packet = TRUE; + auxcpu_desc.notelnet = TRUE; + auxcpu_desc.buffered = 2048; + + if (auxcpu_unit[0].flags & UNIT_ATT) + sim_activate (&auxcpu_unit[0], 1000); + else + sim_cancel (&auxcpu_unit[0]); + + return SCPE_OK; +} + +static t_stat auxcpu_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 (&auxcpu_desc, uptr, cptr, FALSE); + if (r != SCPE_OK) /* error? */ + return r; + sim_debug(DBG_TRC, &auxcpu_dev, "activate connection\n"); + sim_activate (uptr, 10); /* start poll */ + uptr->flags |= UNIT_ATT; + return SCPE_OK; +} + +static t_stat auxcpu_detach (UNIT *uptr) +{ + t_stat r; + + if (!(uptr->flags & UNIT_ATT)) + return SCPE_OK; + sim_cancel (uptr); + r = tmxr_detach (&auxcpu_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 auxcpu_svc (UNIT *uptr) +{ + tmxr_poll_rx (&auxcpu_desc); + if (auxcpu_ldsc.rcve && !auxcpu_ldsc.conn) { + auxcpu_ldsc.rcve = 0; + tmxr_reset_ln (&auxcpu_ldsc); + } + + /* If incoming interrput => status |= 010 */ + if (status & 010) + set_interrupt(AUXCPU_DEVNUM, pia); + else + clr_interrupt(AUXCPU_DEVNUM); + + if (tmxr_poll_conn(&auxcpu_desc) >= 0) { + sim_debug(DBG_CMD, &auxcpu_dev, "got connection\n"); + auxcpu_ldsc.rcve = 1; + uptr->wait = AUXCPU_POLL; + } + sim_activate (uptr, uptr->wait); + return SCPE_OK; +} + +static t_stat auxcpu_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 connects a secondary processor that is sharing memory with the.\n" + " primary.\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 *auxcpu_description (DEVICE *dptr) +{ + return "Auxiliary processor"; +} + +static int error (const char *message) +{ + sim_debug (DBG_TRC, &auxcpu_dev, "%s\r\n", message); + sim_debug (DBG_TRC, &auxcpu_dev, "CLOSE\r\n"); + auxcpu_ldsc.rcve = 0; + tmxr_reset_ln (&auxcpu_ldsc); + return -1; +} + +static int transaction (unsigned char *request, unsigned char *response) +{ + const uint8 *auxcpu_request; + size_t size; + t_stat stat; + + stat = tmxr_put_packet_ln (&auxcpu_ldsc, request + 1, (size_t)request[0]); + if (stat != SCPE_OK) + return error ("Write error in transaction"); + + do { + tmxr_poll_rx (&auxcpu_desc); + stat = tmxr_get_packet_ln (&auxcpu_ldsc, &auxcpu_request, &size); + } while (stat != SCPE_OK || size == 0); + + if (size > 7) + return error ("Malformed transaction"); + + memcpy (response, auxcpu_request, size); + return 0; +} + +int auxcpu_read (int addr, uint64 *data) +{ + unsigned char request[12]; + unsigned char response[12]; + + sim_interval -= AUXCPU_MEM_CYCLE; + + if ((auxcpu_unit[0].flags & UNIT_ATT) == 0) { + *data = 0; + return 0; + } + + addr &= 037777; + + memset (request, 0, sizeof request); + build (request, DATI); + build (request, addr); + build (request, addr >> 8); + build (request, addr >> 16); + + transaction (request, response); + + switch (response[0]) + { + case ACK: + *data = (uint64)response[1]; + *data |= (uint64)response[2] << 8; + *data |= (uint64)response[3] << 16; + *data |= (uint64)response[4] << 24; + *data |= (uint64)response[5] << 32; + break; + case ERR: + fprintf (stderr, "AUXCPU: Read error %06o\r\n", addr); + *data = 0; + break; + case TIMEOUT: + fprintf (stderr, "AUXCPU: Read timeout %06o\r\n", addr); + *data = 0; + break; + default: + return error ("Protocol error"); + } + + return 0; +} + +int auxcpu_write (int addr, uint64 data) +{ + unsigned char request[12]; + unsigned char response[12]; + + sim_interval -= AUXCPU_MEM_CYCLE; + + if ((ten11_unit[0].flags & UNIT_ATT) == 0) { + return 0; + } + + addr &= 037777; + + memset (request, 0, sizeof request); + build (request, DATO); + build (request, addr); + build (request, addr >> 8); + build (request, addr >> 16); + build (request, data); + build (request, data >> 8); + build (request, data >> 16); + build (request, data >> 24); + build (request, data >> 32); + + transaction (request, response); + + switch (response[0]) + { + case ACK: + break; + case ERR: + fprintf (stderr, "AUXCPU: Write error %06o\r\n", addr); + break; + case TIMEOUT: + fprintf (stderr, "AUXCPU: Write timeout %06o\r\n", addr); + break; + default: + return error ("Protocol error"); + } + + return 0; +} + +static int auxcpu_interrupt (void) +{ + unsigned char request[12]; + unsigned char response[12]; + memset (request, 0, sizeof request); + + sim_debug(DEBUG_IRQ, &auxcpu_dev, "PDP-10 interrupting the PDP-6\n"); + + build (request, IRQ); + + transaction (request, response); + + switch (response[1]) + { + case ACK: + break; + case ERR: + case TIMEOUT: + fprintf (stderr, "AUXCPU: Interrupt error or timeout\r\n"); + break; + default: + return error ("Protocol error"); + } + + return 0; +} + +t_stat auxcpu_devio(uint32 dev, uint64 *data) +{ + DEVICE *dptr = &auxcpu_dev; + + switch(dev & 07) { + case CONO: + sim_debug(DEBUG_CONO, &auxcpu_dev, "CONO %012llo\n", *data); + pia = *data & 7; + if (*data & 010) + { + // Clear interrupt from the PDP-6. + status &= ~010; + clr_interrupt(AUXCPU_DEVNUM); + } + if (*data & 020) + auxcpu_interrupt (); + break; + case CONI: + *data = (status & 010) | pia; + sim_debug(DEBUG_CONI, &auxcpu_dev, "CONI %012llo\n", *data); + break; + case DATAI: + *data = 0; + sim_debug(DEBUG_CONI, &auxcpu_dev, "DATAI %012llo\n", *data); + break; + case DATAO: + sim_debug(DEBUG_CONI, &auxcpu_dev, "DATAO %012llo\n", *data); + break; + } + + return SCPE_OK; +} +#endif diff --git a/PDP10/ka10_cpu.c b/PDP10/ka10_cpu.c index 6a7419a..3304e27 100644 --- a/PDP10/ka10_cpu.c +++ b/PDP10/ka10_cpu.c @@ -217,7 +217,9 @@ int32 qua_tps = 125000; int32 tmxr_poll = 10000; /* Physical address range for Rubin 10-11 interface. */ -#define T11RANGE(addr) ((addr) >= 03000000) +#define T11RANGE(addr) ((addr) >= 03040000) +/* Physical address range for auxiliary PDP-6. */ +#define AUXCPURANGE(addr) ((addr) >= 03000000 && (addr) < 03040000) DEVICE *rh_devs[] = { #if (NUM_DEVS_RS > 0) @@ -686,6 +688,7 @@ int opflags[] = { #if ITS #define QITS (cpu_unit[0].flags & UNIT_ITSPAGE) #define QTEN11 (ten11_unit[0].flags & UNIT_ATT) +#define QAUXCPU (auxcpu_unit[0].flags & UNIT_ATT) #else #define QITS 0 #endif @@ -1682,6 +1685,13 @@ int Mem_read_its(int flag, int cur_context, int fetch) { } return 0; } + if (AUXCPURANGE(addr) && QAUXCPU) { + if (auxcpu_read (addr, &MB)) { + nxm_flag = 1; + return 1; + } + return 0; + } if (addr >= (int)MEMSIZE) { nxm_flag = 1; return 1; @@ -1716,6 +1726,13 @@ int Mem_write_its(int flag, int cur_context) { } return 0; } + if (AUXCPURANGE(addr) && QAUXCPU) { + if (auxcpu_write (addr, MB)) { + nxm_flag = 1; + return 1; + } + return 0; + } if (addr >= (int)MEMSIZE) { nxm_flag = 1; return 1; diff --git a/PDP10/ka10_defs.h b/PDP10/ka10_defs.h index 53b6ddb..62e112c 100644 --- a/PDP10/ka10_defs.h +++ b/PDP10/ka10_defs.h @@ -299,6 +299,7 @@ extern void restore_pi_hold(); extern void set_pi_hold(); extern UNIT cpu_unit[]; extern UNIT ten11_unit[]; +extern UNIT auxcpu_unit[]; extern DEVICE cpu_dev; extern DEVICE cty_dev; extern DEVICE mt_dev; @@ -331,6 +332,7 @@ extern DEVICE stk_dev; extern DEVICE tk10_dev; extern DEVICE mty_dev; extern DEVICE ten11_dev; +extern DEVICE auxcpu_dev; extern DEVICE wcnsls_dev; /* MIT Spacewar Consoles */ extern t_stat (*dev_tab[128])(uint32 dev, uint64 *data); @@ -386,6 +388,8 @@ extern void ka10_lights_main (uint64); extern void ka10_lights_set_aux (int); extern void ka10_lights_clear_aux (int); +int auxcpu_read (int addr, uint64 *); +int auxcpu_write (int addr, uint64); /* I/O system parameters */ #define NUM_DEVS_MT 1 @@ -407,6 +411,7 @@ extern void ka10_lights_clear_aux (int); #define NUM_DEVS_TK10 ITS #define NUM_DEVS_MTY ITS #define NUM_DEVS_TEN11 ITS +#define NUM_DEVS_AUXCPU ITS #define NUM_DEVS_DPY USE_DISPLAY #define NUM_DEVS_WCNSLS USE_DISPLAY #define NUM_DEVS_IMP 1 diff --git a/PDP10/ka10_sys.c b/PDP10/ka10_sys.c index cb6530c..4c5c85b 100644 --- a/PDP10/ka10_sys.c +++ b/PDP10/ka10_sys.c @@ -154,6 +154,9 @@ DEVICE *sim_devices[] = { #endif #if NUM_DEVS_TEN11 > 0 &ten11_dev, +#endif +#if NUM_DEVS_AUXCPU > 0 + &auxcpu_dev, #endif NULL }; diff --git a/dependencies.sh b/dependencies.sh new file mode 100644 index 0000000..141d325 --- /dev/null +++ b/dependencies.sh @@ -0,0 +1,11 @@ +install_linux() { + sudo apt-get update -myq + sudo apt-get install -y libegl1-mesa-dev libgles2-mesa-dev + sudo apt-get install -y libx11-dev libxt-dev libsdl2-dev +} + +install_osx() { + true +} + +"$1" diff --git a/makefile b/makefile index 591a79b..f120e66 100644 --- a/makefile +++ b/makefile @@ -1203,7 +1203,8 @@ KA10 = ${KA10D}/ka10_cpu.c ${KA10D}/ka10_sys.c ${KA10D}/ka10_df.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_imp.c ${KA10D}/ka10_stk.c ${KA10D}/ka10_ten11.c + ${KA10D}/ka10_imp.c ${KA10D}/ka10_stk.c ${KA10D}/ka10_ten11.c \ + ${KA10D}/ka10_auxcpu.c KA10_OPT = -DKA=1 -DUSE_INT64 -I $(KA10D) -DUSE_SIM_CARD ${NETWORK_OPT} ifneq ($(TYPE340),)