diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h index e04bdb3f..a95d28e4 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -169,6 +169,7 @@ #define MTA 0 /* magtape */ #define TC02 0 /* DECtape */ #define TTY1 16 /* second Teletype(s) */ +#define UC15 0 /* UC15 */ #define BRMASK 0377400 /* bounds mask */ #define BRMASK_XVM 0777400 /* bounds mask, XVM */ #endif diff --git a/PDP18B/pdp18b_dr15.c b/PDP18B/pdp18b_dr15.c new file mode 100644 index 00000000..03ad18df --- /dev/null +++ b/PDP18B/pdp18b_dr15.c @@ -0,0 +1,338 @@ +/* pdp18b_dr15.c: DR15C simulator + + Copyright (c) 2016, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dr PDP-15 DR15C interface for UC15 system + + The DR15C provides control communications with the DR11Cs in the UC15. + Its state consists of an 18b register (the Task Control Block Pointer), + a one bit flag (TCBP acknowledge, not wired to interrupt), four interrupt + requests wired to API, four interrupt vectors for the API levels, and an + API interrupt enable/disable flag. + + The PDP15 and UC15 use a master/save communications protocol. + - The PDP15 initiates a request to the PDP11 by writing TCBP and + clearing TCBP acknowledge. This alerts/interrupts the PDP11. + - The PDP11 reads TCBP. This sets TCBP acknowledge. + - The PDP11 processes the request. + - The PDP11 signals completion by writing a vector into one of + four API request levels. + - The PDP15 is interrupted, and the request is considered complete. + + The DR15 must "call out" to the UC15 to signal two conditions: + - a new TCBP has been written + - API requests have been updated + + The UC15 must "call in" to the DR15 for two reasons: + - the TCBP has been read + - an API interrupt is requested + + The DR15 and UC15 use a shared memory section and ATOMIC operations + to communicate. Shared state is maintained in shared memory, with one + side having read/write access, the other read-only. Actions are + implemented by setting signals with an atomic compare-and-swap. + The signals may be polled with non-atomic operations but must be + verified with an atomic compare-and-swap. + + Debug hooks - when DEBUG is turned on, the simulator will print + information relating to PIREX operation. +*/ + +#include "pdp18b_defs.h" +#include "uc15_defs.h" + +/* Declarations */ + +extern int32 int_hwre[API_HLVL+1]; +extern int32 api_vec[API_HLVL][32]; +extern int32 *M; +extern UNIT cpu_unit; + +uint32 dr15_tcbp = 0; /* buffer = TCB ptr */ +int32 dr15_tcb_ack = 0; /* TCBP write ack */ +int32 dr15_ie = 0; /* int enable */ +uint32 dr15_int_req = 0; /* int req 0-3 */ +int32 dr15_poll = 3; /* polling interval */ +SHMEM *uc15_shmem = NULL; /* shared state identifier */ +int32 *uc15_shstate = NULL; /* shared state base */ +SHMEM *pdp15_shmem = NULL; /* PDP15 mem identifier */ + +DEVICE dr15_dev; +int32 dr60 (int32 dev, int32 pulse, int32 AC); +int32 dr61 (int32 dev, int32 pulse, int32 AC); +t_stat dr15_reset (DEVICE *dptr); +void dr15_set_clr_ie (int32 val); +t_stat dr15_svc (UNIT *uptr); +t_stat dr15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat dr15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat dr15_attach (UNIT *uptr, CONST char *cptr); +t_stat dr15_detach (UNIT *uptr); + +t_stat uc15_new_api (int32 val); /* callouts */ +t_stat uc15_tcbp_wr (int32 val); + +/* DR15 data structures + + dr15_dev DR15 device descriptor + dr15_unit DR15 unit descriptor + dr15_reg DR15 register list +*/ + +DIB dr15_dib = { DEV_DR, 2 ,NULL, { &dr60, &dr61 } }; + +UNIT dr15_unit = { + UDATA (&dr15_svc, UNIT_FIX+UNIT_BINK+UNIT_ATTABLE, UC15_STATE_SIZE) + }; + +REG dr15_reg[] = { + { ORDATA (TCBP, dr15_tcbp, ADDRSIZE) }, + { FLDATA (TCBACK, dr15_tcb_ack, 0) }, + { FLDATA (IE, dr15_ie, 0) }, + { ORDATA (REQ, dr15_int_req, 4) }, + { FLDATA (API0, int_hwre[API_DR0], INT_V_DR) }, + { FLDATA (API1, int_hwre[API_DR1], INT_V_DR) }, + { FLDATA (API2, int_hwre[API_DR2], INT_V_DR) }, + { FLDATA (API3, int_hwre[API_DR3], INT_V_DR) }, + { ORDATA (APIVEC0, api_vec[API_DR0][INT_V_DR], 7) }, + { ORDATA (APIVEC1, api_vec[API_DR1][INT_V_DR], 7) }, + { ORDATA (APIVEC2, api_vec[API_DR2][INT_V_DR], 7) }, + { ORDATA (APIVEC3, api_vec[API_DR3][INT_V_DR], 7) }, + { DRDATA (POLL, dr15_poll, 10), REG_NZ }, + { ORDATA (DEVNO, dr15_dib.dev, 6), REG_HRO }, + { NULL } + }; + +MTAB dr15_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", NULL, &show_devno }, + { 0 } + }; + +DEVICE dr15_dev = { + "DR", &dr15_unit, dr15_reg, dr15_mod, + 1, 8, 10, 1, 8, 32, + &dr15_ex, &dr15_dep, &dr15_reset, + NULL, &dr15_attach, &dr15_detach, + &dr15_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG + }; + +/* IOT routines */ + +int32 dr60 (int32 dev, int32 pulse, int32 AC) +{ +int32 subdev = (pulse >> 4) & 03; + +if (((pulse & 01) != 0) && (dr15_tcb_ack != 0)) /* SIOA */ + AC |= IOT_SKP; +if ((pulse & 02) != 0) /* CIOP */ + dr15_tcb_ack = 0; +if ((pulse & 04) != 0) { /* LIOR */ + dr15_tcbp = AC & AMASK; /* top bit zero */ + uc15_tcbp_wr (dr15_tcbp); /* inform UC15 */ + } +return AC; +} + +int32 dr61 (int32 dev, int32 pulse, int32 AC) +{ +int32 subdev = (pulse >> 4) & 03; + +if (pulse & 01) { /* SAPIn */ + if (((dr15_int_req >> subdev) & 01) != 0) + AC = AC | IOT_SKP; + } +if (pulse & 02) { + if (subdev == 0) /* RDRS */ + AC |= dr15_ie; + else if (subdev == 1) + dr15_set_clr_ie (AC & 1); + } +if (pulse & 04) { /* CAPI */ + int32 old_int_req = dr15_int_req; + dr15_int_req &= ~(1 << subdev); /* clear local req */ + int_hwre[subdev] &= ~INT_DR; /* clear hwre req */ + if (dr15_int_req != old_int_req) /* state change? */ + uc15_new_api (dr15_int_req); /* inform UC15 */ + } +return AC; +} + +/* Set/clear interrupt enable */ + +void dr15_set_clr_ie (int32 val) +{ +int32 i; + +dr15_ie = val; +for (i = 0; i < 4; i++) { + if ((dr15_ie != 0) && (((dr15_int_req >> i) & 01) != 0)) + int_hwre[i] |= INT_DR; + else int_hwre[i] &= ~INT_DR; + } +return; +} + +/* Routines to inform UC15 of state changes */ + +t_stat uc15_new_api (int32 req) +{ +UC15_SHARED_WR (UC15_API_SUMM, req); /* new value */ +UC15_ATOMIC_CAS (UC15_API_UPD, 0, 1); /* signal UC15 */ +return SCPE_OK; +} + +t_stat uc15_tcbp_wr (int32 tcbp) +{ +UC15_SHARED_WR (UC15_TCBP, tcbp); /* new value */ +UC15_ATOMIC_CAS (UC15_TCBP_WR, 0, 1); /* signal UC15 */ +if (DEBUG_PRS (dr15_dev)) { + uint32 apiv, apil, fnc, tsk; + t_bool spl; + + apiv = (M[tcbp] >> 8) & 0377; + apil = M[tcbp] & 0377; + fnc = (M[tcbp + 1] >> 8) & 0377; + spl = (M[tcbp + 1] & 0200) != 0; + tsk = (M[tcbp + 1] & 0177); + fprintf (sim_deb, ">> DR15: TCB write, API = %o/%d, fnc = %o, %s task = %o, eventvar = %o\n", + apiv, apil, fnc, spl? "Spooled": "Unspooled", tsk, M[tcbp + 2]); + fprintf (sim_deb, "Additional parameters = %o %o %o %o %o\n", + M[tcbp + 3], M[tcbp + 4], M[tcbp + 5], M[tcbp + 6], M[tcbp + 7]); + } +return SCPE_OK; +} + +/* Routine to poll for state changes from UC15 */ + +t_stat dr15_svc (UNIT *uptr) +{ +int32 i, t; +uint32 old_int_req = dr15_int_req; + +t = UC15_SHARED_RD (UC15_TCBP_RD); /* TCBP read? */ +if ((t != 0) && UC15_ATOMIC_CAS (UC15_TCBP_RD, 1, 0)) /* for real? clear */ + dr15_tcb_ack = 1; /* set ack */ +for (i = 0; i < 4; i++) { /* API req */ + t = UC15_SHARED_RD (UC15_API_REQ + (i * UC15_API_VEC_MUL)); + if ((t != 0) && /* API req? for real? */ + UC15_ATOMIC_CAS (UC15_API_REQ + (i * UC15_API_VEC_MUL), 1, 0)) { + api_vec[i][INT_V_DR] = UC15_SHARED_RD (UC15_API_VEC + (i * UC15_API_VEC_MUL)) & 0177; + dr15_int_req |= (1u << i); + if (dr15_ie != 0) + int_hwre[i] |= INT_DR; + if (DEBUG_PRS (dr15_dev)) + fprintf (sim_deb, ">>DR15: API request, API = %o/%d\n", + api_vec[i][INT_V_DR], i); + } /* end if changed */ + } /* end for */ +if (dr15_int_req != old_int_req) /* changes? */ + uc15_new_api (dr15_int_req); /* inform UC15 */ +sim_activate (uptr, dr15_poll); /* next poll */ +return SCPE_OK; +} + +/* Reset routine + + Aside from performing a device reset, this routine sets up shared + UC15 state and shared PDP15 main memory. It also writes the size + of PDP15 main memory (in PDP11 bytes) into the shared state region. +*/ + +t_stat dr15_reset (DEVICE *dptr) +{ +int32 i; +t_stat r; +void *basead; + +dr15_int_req = 0; /* clear API req */ +dr15_ie = 1; /* IE inits to 1 */ +dr15_tcb_ack = 1; /* TCBP ack inits to 1 */ +dr15_int_req = 0; +for (i = 0; i < 4; i++) { /* clear intr and vectors */ + int_hwre[i] &= ~INT_DR; + api_vec[i][INT_V_DR] = 0; + } +sim_cancel (dptr->units); +if ((dptr->flags & DEV_DIS) != 0) /* disabled? */ + return SCPE_OK; + +if (uc15_shmem == NULL) { /* allocate shared state */ + r = sim_shmem_open ("UC15SharedState", UC15_STATE_SIZE * sizeof (int32), &uc15_shmem, &basead); + if (r != SCPE_OK) + return r; + uc15_shstate = (int32 *) basead; + } +if (pdp15_shmem == NULL) { /* allocate shared memory */ + r = sim_shmem_open ("PDP15MainMemory", MAXMEMSIZE * sizeof (int32), &pdp15_shmem, &basead); + if (r != SCPE_OK) + return r; + free (M); /* release normal memory */ + M = (int32 *) basead; + } +UC15_SHARED_WR (UC15_PDP15MEM, cpu_unit.capac << 1); /* write mem size to shared state */ +uc15_new_api (dr15_int_req); /* inform UC15 of new API (and mem) */ +sim_activate (dptr->units, dr15_poll); /* start polling */ +return SCPE_OK; +} + +/* Shared state ex/mod routines for debug */ + +t_stat dr15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= UC15_STATE_SIZE) + return SCPE_NXM; +if (vptr != NULL) { + if (uc15_shmem != NULL) + *vptr = UC15_SHARED_RD ((int32) addr); + else *vptr = 0; + } +return SCPE_OK; +} + +t_stat dr15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= UC15_STATE_SIZE) + return SCPE_NXM; +if (uc15_shmem != NULL) + UC15_SHARED_WR ((int32) addr, (int32) val); +return SCPE_OK; +} + +/* Fake attach routine to kill attach attempts */ + +t_stat dr15_attach (UNIT *uptr, CONST char *cptr) +{ +return SCPE_NOFNC; +} + +/* Shutdown detach routine to release shared memories */ + +t_stat dr15_detach (UNIT *uptr) +{ +if ((sim_switches & SIM_SW_SHUT) == 0) /* only if shutdown */ + return SCPE_NOFNC; +sim_shmem_close (uc15_shmem); /* release shared state */ +sim_shmem_close (pdp15_shmem); /* release shared mem */ +return SCPE_OK; +} + diff --git a/Visual Studio Projects/PDP15.vcproj b/Visual Studio Projects/PDP15.vcproj index 97e37997..96093bb5 100644 --- a/Visual Studio Projects/PDP15.vcproj +++ b/Visual Studio Projects/PDP15.vcproj @@ -35,6 +35,9 @@ + @@ -116,6 +119,9 @@ + @@ -192,6 +198,10 @@ RelativePath="..\PDP18B\pdp18b_cpu.c" > + + diff --git a/makefile b/makefile index 5f446c69..47c84e87 100644 --- a/makefile +++ b/makefile @@ -1169,7 +1169,7 @@ PDP18B = ${PDP18BD}/pdp18b_dt.c ${PDP18BD}/pdp18b_drm.c ${PDP18BD}/pdp18b_cpu.c ${PDP18BD}/pdp18b_lp.c ${PDP18BD}/pdp18b_mt.c ${PDP18BD}/pdp18b_rf.c \ ${PDP18BD}/pdp18b_rp.c ${PDP18BD}/pdp18b_stddev.c ${PDP18BD}/pdp18b_sys.c \ ${PDP18BD}/pdp18b_rb.c ${PDP18BD}/pdp18b_tt1.c ${PDP18BD}/pdp18b_fpp.c \ - ${PDP18BD}/pdp18b_g2tty.c + ${PDP18BD}/pdp18b_g2tty.c ${PDP18BD}/pdp18b_dr15.c PDP4_OPT = -DPDP4 -I ${PDP18BD} PDP7_OPT = -DPDP7 -I ${PDP18BD}