diff --git a/VAX/vax730_defs.h b/VAX/vax730_defs.h index 92227c62..cfcb327d 100644 --- a/VAX/vax730_defs.h +++ b/VAX/vax730_defs.h @@ -124,6 +124,9 @@ #define INITMEMSIZE (1 << MAXMEMWIDTH) /* initial memory size */ #define MEMSIZE (cpu_unit.capac) #define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) +#define MEM_MODIFIERS { UNIT_MSIZE, (1u << 20), NULL, "1M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 21), NULL, "2M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 22), NULL, "4M", &cpu_set_size } /* Unibus I/O registers */ diff --git a/VAX/vax750_cmi.c b/VAX/vax750_cmi.c new file mode 100644 index 00000000..7b05f5dd --- /dev/null +++ b/VAX/vax750_cmi.c @@ -0,0 +1,736 @@ +/* vax750_cmi.c: VAX 11/750 CMI + + Copyright (c) 2010-2011, Matt Burke + This module incorporates code from SimH, Copyright (c) 2004-2011, 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 + THE AUTHOR(S) 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(s) of the author(s) shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author(s). + + This module contains the VAX 11/750 system-specific registers and devices. + + cmi bus controller + + 21-Oct-2012 MB First Version +*/ + +#include "vax_defs.h" + +/* 11/750 specific IPRs */ + +#define CMIERR_CRD 0x00000001 +#define CMIERR_LEB 0x00000002 +#define CMIERR_RDS 0x00000004 +#define CMIERR_ME 0x00000008 +#define CMIERR_TBH 0x00000010 +#define CMIERR_TBG0DE 0x00000100 +#define CMIERR_TBG1DE 0x00000200 +#define CMIERR_TBG0TE 0x00000400 +#define CMIERR_TBG1TE 0x00000800 +#define CMIERR_V_MODE 16 +#define CMIERR_M_MODE 0x3 +#define CMIERR_MODE (CMIERR_M_MODE << CMIERR_V_MODE) +#define CMIERR_REF 0x00040000 +#define CMIERR_RM 0x00080000 +#define CMIERR_EN 0x00100000 + +/* System registers */ + +/* VAX-11/750 boot device definitions */ + +struct boot_dev { + char *name; + int32 code; + int32 let; + }; + +uint32 nexus_req[NEXUS_HLVL]; /* nexus int req */ +uint32 cmi_err = 0; +uint32 cmi_cadr = 0; +char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ + +static t_stat (*nexusR[NEXUS_NUM])(int32 *dat, int32 ad, int32 md); +static t_stat (*nexusW[NEXUS_NUM])(int32 dat, int32 ad, int32 md); + +static struct boot_dev boot_tab[] = { + { "RP", BOOT_MB, 0 }, + { "HK", BOOT_HK, 0 }, + { "RL", BOOT_RL, 0 }, + { "RQ", BOOT_UDA, 1 << 24 }, + { "TQ", BOOT_TK, 1 << 24 }, + { "TD", BOOT_TD, 0 }, + { NULL } + }; + +extern int32 R[16]; +extern int32 PSL; +extern int32 ASTLVL, SISR; +extern int32 mapen, pme, trpirq; +extern int32 in_ie; +extern int32 mchk_va, mchk_ref; +extern int32 crd_err, mem_err, hlt_pin; +extern int32 tmr_int, tti_int, tto_int, csi_int, cso_int; +extern jmp_buf save_env; +extern int32 p1; +extern int32 sim_switches; +extern DEVICE *sim_devices[]; +extern FILE *sim_log; +extern CTAB *sim_vm_cmd; + +t_stat cmi_reset (DEVICE *dptr); +void cmi_set_tmo (void); +t_stat vax750_boot (int32 flag, char *ptr); +t_stat vax750_boot_parse (int32 flag, char *ptr); +t_stat cpu_boot (int32 unitno, DEVICE *dptr); + +extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); +extern int32 iccs_rd (void); +extern int32 nicr_rd (void); +extern int32 icr_rd (t_bool interp); +extern int32 todr_rd (void); +extern int32 rxcs_rd (void); +extern int32 rxdb_rd (void); +extern int32 txcs_rd (void); +extern int32 csrs_rd (void); +extern int32 csrd_rd (void); +extern int32 csts_rd (void); +extern void iccs_wr (int32 dat); +extern void nicr_wr (int32 dat); +extern void todr_wr (int32 dat); +extern void rxcs_wr (int32 dat); +extern void txcs_wr (int32 dat); +extern void txdb_wr (int32 dat); +extern void csrs_wr (int32 dat); +extern void csts_wr (int32 dat); +extern void cstd_wr (int32 dat); +extern void init_mbus_tab (void); +extern void init_ubus_tab (void); +extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp); +extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp); +extern void uba_eval_int (void); +extern int32 uba_get_ubvector (int32 lvl); +extern void uba_ioreset (void); + +/* CMI data structures + + cmi_dev CMI device descriptor + cmi_unit CMI unit + cmi_reg CMI register list +*/ + +UNIT cmi_unit = { UDATA (NULL, 0, 0) }; + +REG cmi_reg[] = { + { HRDATA (NREQ14, nexus_req[0], 16) }, + { HRDATA (NREQ15, nexus_req[1], 16) }, + { HRDATA (NREQ16, nexus_req[2], 16) }, + { HRDATA (NREQ17, nexus_req[3], 16) }, + { HRDATA (CMIERR, cmi_err, 32) }, + { NULL } + }; + +DEVICE cmi_dev = { + "CMI", &cmi_unit, cmi_reg, NULL, + 1, 16, 16, 1, 16, 8, + NULL, NULL, &cmi_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* Special boot command, overrides regular boot */ + +CTAB vax750_cmd[] = { + { "BOOT", &vax750_boot, RU_BOOT, + "bo{ot} {/R5:flg} boot device\n" }, + { NULL } + }; + +/* The VAX 11/750 has three sources of interrupts + + - internal device interrupts (CPU, console, clock) + - nexus interupts (e.g., memory controller, MBA, UBA) + - external device interrupts (Unibus) + + Internal devices vector to fixed SCB locations. + + Nexus interrupts vector to an SCB location based on this + formula: SCB_NEXUS + ((IPL - 0x14) * 0x40) + (TR# * 0x4) + + External device interrupts do not vector directly. + Instead, the interrupt handler for a given UBA IPL + reads a vector register that contains the Unibus vector + for that IPL. + +/* Find highest priority vectorable interrupt */ + +int32 eval_int (void) +{ +int32 ipl = PSL_GETIPL (PSL); +int32 i, t; + +static const int32 sw_int_mask[IPL_SMAX] = { + 0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */ + 0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */ + 0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */ + 0xE000, 0xC000, 0x8000 /* C - E */ + }; + +if (hlt_pin) /* hlt pin int */ + return IPL_HLTPIN; +if ((ipl < IPL_MEMERR) && mem_err) /* mem err int */ + return IPL_MEMERR; +if ((ipl < IPL_CRDERR) && crd_err) /* crd err int */ + return IPL_CRDERR; +if ((ipl < IPL_CLKINT) && tmr_int) /* clock int */ + return IPL_CLKINT; +uba_eval_int (); /* update UBA */ +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= ipl) /* at ipl? no int */ + return 0; + if (nexus_req[i - IPL_HMIN]) /* req != 0? int */ + return i; + } +if ((ipl < IPL_TTINT) && (tti_int || tto_int || csi_int || cso_int)) /* console int */ + return IPL_TTINT; +if (ipl >= IPL_SMAX) /* ipl >= sw max? */ + return 0; +if ((t = SISR & sw_int_mask[ipl]) == 0) + return 0; /* eligible req */ +for (i = IPL_SMAX; i > ipl; i--) { /* check swre int */ + if ((t >> i) & 1) /* req != 0? int */ + return i; + } +return 0; +} + +/* Return vector for highest priority hardware interrupt at IPL lvl */ + +int32 get_vector (int32 lvl) +{ +int32 i, l; + +if (lvl == IPL_MEMERR) { /* mem error? */ + mem_err = 0; + return SCB_MEMERR; + } +if (lvl == IPL_CRDERR) { /* CRD error? */ + crd_err = 0; + return SCB_CRDERR; + } +if (lvl == IPL_CLKINT) { /* clock? */ + tmr_int = 0; /* clear req */ + return SCB_INTTIM; /* return vector */ + } +if (lvl > IPL_HMAX) { /* error req lvl? */ + ABORT (STOP_UIPL); /* unknown intr */ + } +if ((lvl <= IPL_HMAX) && (lvl >= IPL_HMIN)) { /* nexus? */ + l = lvl - IPL_HMIN; + if (nexus_req[l] & (1u << TR_UBA)) { /* unibus int? */ + nexus_req[l] = nexus_req[l] & ~(1u << TR_UBA); + return uba_get_ubvector(l); + } + for (i = 0; nexus_req[l] && (i < NEXUS_NUM); i++) { + if ((nexus_req[l] >> i) & 1) { + nexus_req[l] = nexus_req[l] & ~(1u << i); + return SCB_NEXUS + (l << 6) + (i << 2); /* return vector */ + } + } + } +if (lvl == IPL_TTINT) { /* console? */ + if (tti_int) { /* input? */ + tti_int = 0; /* clear req */ + return SCB_TTI; /* return vector */ + } + if (tto_int) { /* output? */ + tto_int = 0; /* clear req */ + return SCB_TTO; /* return vector */ + } + if (csi_int) { /* input? */ + csi_int = 0; /* clear req */ + return SCB_CSI; /* return vector */ + } + if (cso_int) { /* output? */ + cso_int = 0; /* clear req */ + return SCB_CSO; /* return vector */ + } + } +return 0; +} + +/* Read 750-specific IPR's */ + +int32 ReadIPR (int32 rg) +{ +int32 val; + +switch (rg) { + + case MT_ICCS: /* ICCS */ + val = iccs_rd (); + break; + + case MT_NICR: /* NICR */ + val = nicr_rd (); + break; + + case MT_ICR: /* ICR */ + val = icr_rd (FALSE); + break; + + case MT_TODR: /* TODR */ + val = todr_rd (); + break; + + case MT_ACCS: /* ACCS (not impl) */ + val = 0; + break; + + case MT_RXCS: /* RXCS */ + val = rxcs_rd (); + break; + + case MT_RXDB: /* RXDB */ + val = rxdb_rd (); + break; + + case MT_TXCS: /* TXCS */ + val = txcs_rd (); + break; + + case MT_CADR: /* CADR */ + val = cmi_cadr; + break; + + case MT_CAER: /* CAER (not impl) */ + val = 0; + break; + + case MT_MCESR: /* MCESR (not impl) */ + val = 0; + break; + + case MT_CMIE: /* CMIE */ + val = cmi_err; + break; + + case MT_CSRS: /* CSRS */ + val = csrs_rd (); + break; + + case MT_CSRD: /* CSRD */ + val = csrd_rd (); + break; + + case MT_CSTS: /* CSTS */ + val = csts_rd (); + break; + + case MT_TBDR: /* TBDR */ + val = 0; + break; + + case MT_SID: /* SID */ + val = VAX750_SID | VAX750_MICRO | VAX750_HWREV; + break; + + default: + RSVD_OPND_FAULT; + } + +return val; +} + +/* Write 750-specific IPR's */ + +void WriteIPR (int32 rg, int32 val) +{ +switch (rg) { + + case MT_ICCS: /* ICCS */ + iccs_wr (val); + break; + + case MT_NICR: /* NICR */ + nicr_wr (val); + break; + + case MT_TODR: /* TODR */ + todr_wr (val); + break; + + case MT_ACCS: /* ACCS (not impl) */ + break; + + case MT_RXCS: /* RXCS */ + rxcs_wr (val); + break; + + case MT_TXCS: /* TXCS */ + txcs_wr (val); + break; + + case MT_TXDB: /* TXDB */ + txdb_wr (val); + break; + + case MT_CADR: /* CADR */ + cmi_cadr = (val & 0x1); + break; + + case MT_CAER: /* CAER (not impl) */ + break; + + case MT_MCESR: /* MCESR (not impl) */ + break; + + case MT_IORESET: /* IORESET */ + uba_ioreset (); + break; + + case MT_CSRS: /* CSRS */ + csrs_wr (val); + break; + + case MT_CSTS: /* CSTS */ + csts_wr (val); + break; + + case MT_CSTD: /* CSTD */ + cstd_wr (val); + break; + + case MT_TBDR: /* TBDR */ + break; + + default: + RSVD_OPND_FAULT; + } + +return; +} + +/* ReadReg - read register space + + Inputs: + pa = physical address + lnt = length (BWLQ) + Output: + longword of data +*/ + +int32 ReadReg (int32 pa, int32 lnt) +{ +int32 nexus, val; + +if (ADDR_IS_REG (pa)) { /* reg space? */ + nexus = NEXUS_GETNEX (pa); /* get nexus */ + if (nexusR[nexus] && /* valid? */ + (nexusR[nexus] (&val, pa, lnt) == SCPE_OK)) { + SET_IRQL; + return val; + } + } +cmi_set_tmo (); /* timeout */ +MACH_CHECK (MCHK_BPE); /* machine check */ +return 0; +} + +/* WriteReg - write register space + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (BWLQ) + Outputs: + none +*/ + +void WriteReg (int32 pa, int32 val, int32 lnt) +{ +int32 nexus; + +if (ADDR_IS_REG (pa)) { /* reg space? */ + nexus = NEXUS_GETNEX (pa); /* get nexus */ + if (nexusW[nexus] && /* valid? */ + (nexusW[nexus] (val, pa, lnt) == SCPE_OK)) { + SET_IRQL; + return; + } + } +cmi_set_tmo (); /* timeout */ +mem_err = 1; /* interrupt */ +SET_IRQL; +return; +} + +/* Set CMI timeout */ + +void cmi_set_tmo () +{ +if ((cmi_err & CMIERR_ME) == 0) { /* not yet set? */ + if (mchk_ref == REF_V) /* virt? add mode */ + cmi_err |= CMIERR_REF | (PSL_GETCUR (PSL) << CMIERR_V_MODE); + cmi_err |= CMIERR_ME; /* set tmo flag */ + } +else cmi_err |= CMIERR_LEB; /* yes, multiple */ +return; +} + +/* Machine check + + Error status word format + <2:0> = ASTLVL + <3> = PME + <6:4> = arith trap code + Rest will be zero +*/ + +int32 machine_check (int32 p1, int32 opc, int32 cc, int32 delta) +{ +int32 acc, err; +err = (GET_TRAP (trpirq) << 4) | (pme << 3) | ASTLVL; /* error word */ +if (p1 == MCHK_BPE) /* bus error? */ + cc = intexc (SCB_MCHK, cc, 0, IE_EXC); /* take normal exception */ +else + cc = intexc (SCB_MCHK, cc, 0, IE_SVE); /* take severe exception */ +acc = ACC_MASK (KERN); /* in kernel mode */ +in_ie = 1; +SP = SP - 44; /* push 11 words */ +Write (SP, 40, L_LONG, WA); /* # bytes */ +Write (SP + 4, p1, L_LONG, WA); /* error code */ +Write (SP + 8, mchk_va, L_LONG, WA); /* VA register */ +Write (SP + 12, 0, L_LONG, WA); /* Fault PC */ +Write (SP + 16, 0, L_LONG, WA); /* MDR */ +Write (SP + 20, 0, L_LONG, WA); /* saved mode reg */ +Write (SP + 24, 0, L_LONG, WA); /* read lock timeout */ +Write (SP + 28, 0, L_LONG, WA); /* TB group parity error reg */ +Write (SP + 32, 0, L_LONG, WA); /* cache error reg */ +Write (SP + 36, cmi_err, L_LONG, WA); /* bus error reg */ +Write (SP + 40, 0, L_LONG, WA); /* MCESR */ +in_ie = 0; +cmi_err = cmi_err & ~CMIERR_ME; /* clr CMIERR etc */ +return cc; +} + +/* Console entry - only reached if CONHALT is set (AUTORESTART is set) */ + +int32 con_halt (int32 code, int32 cc) +{ +if ((cpu_boot_cmd[0] == 0) || /* saved boot cmd? */ + (vax750_boot_parse (0, cpu_boot_cmd) != SCPE_OK) || /* reparse the boot cmd */ + (reset_all (0) != SCPE_OK) || /* reset the world */ + (cpu_boot (0, NULL) != SCPE_OK)) /* set up boot code */ + ABORT (STOP_BOOT); /* any error? */ +printf ("Rebooting...\n"); +if (sim_log) + fprintf (sim_log, "Rebooting...\n"); +return cc; +} + +/* Special boot command - linked into SCP by initial reset + + Syntax: BOOT {/R5:val} + + Sets up R0-R5, calls SCP boot processor with effective BOOT CPU +*/ + +t_stat vax750_boot (int32 flag, char *ptr) +{ +t_stat r; + +r = vax750_boot_parse (flag, ptr); /* parse the boot cmd */ +if (r != SCPE_OK) /* error? */ + return r; +strncpy (cpu_boot_cmd, ptr, CBUFSIZE); /* save for reboot */ +return run_cmd (flag, "CPU"); +} + +/* Parse boot command, set up registers - also used on reset */ + +t_stat vax750_boot_parse (int32 flag, char *ptr) +{ +char gbuf[CBUFSIZE]; +char *slptr, *regptr; +int32 i, r5v, unitno; +DEVICE *dptr; +UNIT *uptr; +DIB *dibp; +uint32 ba; +t_stat r; + +regptr = get_glyph (ptr, gbuf, 0); /* get glyph */ +if (slptr = strchr (gbuf, '/')) { /* found slash? */ + regptr = strchr (ptr, '/'); /* locate orig */ + *slptr = 0; /* zero in string */ + } +dptr = find_unit (gbuf, &uptr); /* find device */ +if ((dptr == NULL) || (uptr == NULL)) + return SCPE_ARG; +dibp = (DIB *) dptr->ctxt; /* get DIB */ +if (dibp == NULL) + ba = 0; +else + ba = dibp->ba; +unitno = (int32) (uptr - dptr->units); +r5v = 0; +if ((strncmp (regptr, "/R5:", 4) == 0) || + (strncmp (regptr, "/R5=", 4) == 0) || + (strncmp (regptr, "/r5:", 4) == 0) || + (strncmp (regptr, "/r5=", 4) == 0)) { + r5v = (int32) get_uint (regptr + 4, 16, LMASK, &r); + if (r != SCPE_OK) + return r; + } +else if (*regptr != 0) + return SCPE_ARG; +for (i = 0; boot_tab[i].name != NULL; i++) { + if (strcmp (dptr->name, boot_tab[i].name) == 0) { + R[0] = boot_tab[i].code; + if (dptr->flags & DEV_MBUS) { + R[1] = (NEXUSBASE + (TR_MBA0 * NEXUSSIZE)); + R[2] = unitno; + } + else { + R[1] = ba; + R[2] = (ba & UBADDRMASK); + } + R[3] = unitno; + R[4] = 0; + R[5] = r5v; + return SCPE_OK; + } + } +return SCPE_NOFNC; +} + +/* Bootstrap - finish up bootstrap process */ + +t_stat cpu_boot (int32 unitno, DEVICE *dptr) +{ +t_stat r; + +printf ("Loading boot code from vmb.exe\n"); +if (sim_log) fprintf (sim_log, + "Loading boot code from vmb.exe\n"); +r = load_cmd (0, "-O vmb.exe 200"); +if (r != SCPE_OK) + return r; +SP = PC = 512; +return SCPE_OK; +} + +/* CMI reset */ + +t_stat cmi_reset (DEVICE *dptr) +{ +sim_vm_cmd = vax750_cmd; +cmi_err = CMIERR_EN; +cmi_cadr = 0; +return SCPE_OK; +} + +/* Show nexus */ + +t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "nexus=%d", val); +return SCPE_OK; +} + +/* Init nexus tables */ + +void init_nexus_tab (void) +{ +uint32 i; + +for (i = 0; i < NEXUS_NUM; i++) { + nexusR[i] = NULL; + nexusW[i] = NULL; + } +return; +} + +/* Build nexus tables + + Inputs: + dptr = pointer to device + dibp = pointer to DIB + Outputs: + status +*/ + + +t_stat build_nexus_tab (DEVICE *dptr, DIB *dibp) +{ +uint32 idx; + +if ((dptr == NULL) || (dibp == NULL)) + return SCPE_IERR; +idx = dibp->ba; +if (idx >= NEXUS_NUM) + return SCPE_IERR; +if ((nexusR[idx] && dibp->rd && /* conflict? */ + (nexusR[idx] != dibp->rd)) || + (nexusW[idx] && dibp->wr && + (nexusW[idx] != dibp->wr))) { + printf ("Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba); + if (sim_log) + fprintf (sim_log, "Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba); + return SCPE_STOP; + } +if (dibp->rd) /* set rd dispatch */ + nexusR[idx] = dibp->rd; +if (dibp->wr) /* set wr dispatch */ + nexusW[idx] = dibp->wr; +return SCPE_OK; +} + +/* Build dib_tab from device list */ + +t_stat build_dib_tab (void) +{ +uint32 i; +DEVICE *dptr; +DIB *dibp; +t_stat r; + +init_nexus_tab (); +init_ubus_tab (); +init_mbus_tab (); +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ + if (dptr->flags & DEV_NEXUS) { /* Nexus? */ + if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */ + return r; + } + else if (dptr->flags & DEV_MBUS) { /* Massbus? */ + if (r = build_mbus_tab (dptr, dibp)) + return r; + } + else { /* no, Unibus device */ + if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */ + return r; + } /* end else */ + } /* end if enabled */ + } /* end for */ +return SCPE_OK; +} diff --git a/VAX/vax750_defs.h b/VAX/vax750_defs.h new file mode 100644 index 00000000..0ba24e7c --- /dev/null +++ b/VAX/vax750_defs.h @@ -0,0 +1,453 @@ +/* vax750_defs.h: VAX 750 model-specific definitions file + + Copyright (c) 2010-2011, Matt Burke + This module incorporates code from SimH, Copyright (c) 2004-2008, 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 + THE AUTHOR(S) 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(s) of the author(s) shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author(s). + + 21-Oct-2012 MB First Version + + This file covers the VAX 11/750, the second VAX. + + System memory map + + 00 0000 - 7F FFFF main memory + 80 0000 - EF FFFF reserved + F0 0000 - F0 FFFF writeable control store + F1 0000 - F1 FFFF reserved + F2 0000 - F2 0010 memory controller + F2 0400 - F2 07FF bootstrap ROM + F2 8000 - F2 88FF Massbus adapter 0 + F2 A000 - F2 A8FF Massbus adapter 1 + F2 C000 - F2 C8FF Massbus adapter 2 + F3 0000 - F3 09FF Unibus adapter 0 + F3 2000 - F3 29FF Unibus adapter 1 +*/ + +#ifndef FULL_VAX +#define FULL_VAX 1 +#endif + +#ifndef _VAX_750_DEFS_H_ +#define _VAX_750_DEFS_H_ 1 + +/* Microcode constructs */ + +#define VAX750_SID (2 << 24) /* system ID */ +#define VAX750_MICRO (99 << 8) /* ucode revision */ +#define VAX750_HWREV (156) /* hw revision */ +#define CON_HLTPIN 0x0200 /* external CPU halt */ +#define CON_HLTINS 0x0600 /* HALT instruction */ +#define MCHK_CSPE 0x01 /* control store parity error */ +#define MCHK_BPE 0x02 /* bus error or tb/cache parity error */ +#define VER_FPLA 0x0C /* FPLA version */ +#define VER_WCSP (VER_FPLA) /* WCS primary version */ +#define VER_WCSS 0x12 /* WCS secondary version */ +#define VER_PCS ((VER_WCSS >> 4) & 0x3) /* PCS version */ + +/* Interrupts */ + +#define IPL_HMAX 0x17 /* highest hwre level */ +#define IPL_HMIN 0x14 /* lowest hwre level */ +#define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */ +#define IPL_SMAX 0xF /* highest swre level */ + +/* Nexus constants */ + +#define NEXUS_NUM 16 /* number of nexus */ +#define MCTL_NUM 2 /* number of mem ctrl */ +#define MBA_NUM 2 /* number of MBA's */ +#define TR_MCTL 0 /* nexus assignments */ +#define TR_MBA0 4 +#define TR_MBA1 5 +#define TR_UBA 8 +#define TR_CI 15 +#define NEXUS_HLVL (IPL_HMAX - IPL_HMIN + 1) +#define SCB_NEXUS 0x100 /* nexus intr base */ +#define SBI_FAULTS 0xFC000000 /* SBI fault flags */ + +/* Internal I/O interrupts - relative except for clock and console */ + +#define IPL_CLKINT 0x18 /* clock IPL */ +#define IPL_TTINT 0x14 /* console IPL */ + +#define IPL_MCTL0 (0x15 - IPL_HMIN) +#define IPL_MCTL1 (0x15 - IPL_HMIN) +#define IPL_UBA (0x15 - IPL_HMIN) +#define IPL_MBA0 (0x15 - IPL_HMIN) +#define IPL_MBA1 (0x15 - IPL_HMIN) +#define IPL_CI (0x15 - IPL_HMIN) + +/* Nexus interrupt macros */ + +#define SET_NEXUS_INT(dv) nexus_req[IPL_##dv] |= (1 << TR_##dv) +#define CLR_NEXUS_INT(dv) nexus_req[IPL_##dv] &= ~(1 << TR_##dv) + +/* Machine specific IPRs */ + +#define MT_CSRS 28 /* Console storage */ +#define MT_CSRD 29 +#define MT_CSTS 30 +#define MT_CSTD 31 +#define MT_CMIE 23 /* CMI error */ +#define MT_TBDR 36 /* TB disable */ +#define MT_CADR 37 /* Cache disable */ +#define MT_MCESR 38 /* MCHK err sts */ +#define MT_CAER 39 /* Cache error */ +#define MT_ACCS 40 /* FPA control */ +#define MT_IORESET 55 /* Unibus Init */ + +/* Machine specific reserved operand tests */ + +/* 780 microcode patch 37 - only test LR<23:0> for appropriate length */ + +#define ML_LR_TEST(r) if (((uint32)((r) & 0xFFFFFF)) > 0x200000) RSVD_OPND_FAULT + +/* 780 microcode patch 38 - only test PxBR<31>=1, PxBR<30> = 0, and xBR<1:0> = 0 */ + +#define ML_PXBR_TEST(r) if (((((uint32)(r)) & 0x80000000) == 0) || \ + ((((uint32)(r)) & 0x40000003) != 0)) RSVD_OPND_FAULT +#define ML_SBR_TEST(r) if ((((uint32)(r)) & 0xC0000003) != 0) RSVD_OPND_FAULT + +/* 780 microcode patch 78 - only test xCBB<1:0> = 0 */ + +#define ML_PA_TEST(r) if ((((uint32)(r)) & 0x00000003) != 0) RSVD_OPND_FAULT + +#define LP_AST_TEST(r) if ((r) > AST_MAX) RSVD_OPND_FAULT +#define LP_MBZ84_TEST(r) if ((((uint32)(r)) & 0xF8C00000) != 0) RSVD_OPND_FAULT +#define LP_MBZ92_TEST(r) if ((((uint32)(r)) & 0x7FC00000) != 0) RSVD_OPND_FAULT + +/* Memory */ + +#define MAXMEMWIDTH 21 /* max mem, 16k chips */ +#define MAXMEMSIZE (1 << MAXMEMWIDTH) +#define MAXMEMWIDTH_X 23 /* max mem, 64k chips */ +#define MAXMEMSIZE_X (1 << MAXMEMWIDTH_X) +#define INITMEMSIZE (1 << MAXMEMWIDTH) /* initial memory size */ +#define MEMSIZE (cpu_unit.capac) +#define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) +#define MEM_MODIFIERS { UNIT_MSIZE, (1u << 20), NULL, "1M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 21), NULL, "2M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 22), NULL, "4M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size } + +/* Unibus I/O registers */ + +#define UBADDRWIDTH 18 /* Unibus addr width */ +#define UBADDRSIZE (1u << UBADDRWIDTH) /* Unibus addr length */ +#define UBADDRMASK (UBADDRSIZE - 1) /* Unibus addr mask */ +#define IOPAGEAWIDTH 13 /* IO addr width */ +#define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */ +#define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */ +#define UBADDRBASE 0xFC0000 /* Unibus addr base */ +#define IOPAGEBASE 0xFFE000 /* IO page base */ +#define ADDR_IS_IO(x) ((((uint32) (x)) >= UBADDRBASE) && \ + (((uint32) (x)) < (UBADDRBASE + UBADDRSIZE))) +#define ADDR_IS_IOP(x) (((uint32) (x)) >= IOPAGEBASE) + +/* Nexus register space */ + +#define REGAWIDTH 19 /* REG addr width */ +#define REG_V_NEXUS 13 /* nexus number */ +#define REG_M_NEXUS 0xF +#define REG_V_OFS 2 /* register number */ +#define REG_M_OFS 0x7FF +#define REGSIZE (1u << REGAWIDTH) /* REG length */ +#define REGBASE 0xF00000 /* REG addr base */ +#define ADDR_IS_REG(x) ((((uint32) (x)) >= REGBASE) && \ + (((uint32) (x)) < (REGBASE + REGSIZE))) +#define NEXUSBASE (REGBASE + 0x20000) +#define NEXUSSIZE 0x2000 +#define NEXUS_GETNEX(x) (((x) >> REG_V_NEXUS) & REG_M_NEXUS) +#define NEXUS_GETOFS(x) (((x) >> REG_V_OFS) & REG_M_OFS) + +/* ROM address space in memory controllers */ + +#define ROMAWIDTH 12 /* ROM addr width */ +#define ROMSIZE (1u << ROMAWIDTH) /* ROM size */ +#define ROMBASE (REGBASE + (TR_MCTL << REG_V_NEXUS) + 0x400) +#define ADDR_IS_ROM(x) ((((uint32) (x)) >= ROMBASE) && \ + (((uint32) (x)) < (ROMBASE + ROMSIZE))) + +/* Other address spaces */ + +#define ADDR_IS_CDG(x) (0) +#define ADDR_IS_NVR(x) (0) + +/* Unibus I/O modes */ + +#define READ 0 /* PDP-11 compatibility */ +#define WRITE (L_WORD) +#define WRITEB (L_BYTE) + +/* Common CSI flags */ + +#define CSR_V_GO 0 /* go */ +#define CSR_V_IE 6 /* interrupt enable */ +#define CSR_V_DONE 7 /* done */ +#define CSR_V_BUSY 11 /* busy */ +#define CSR_V_ERR 15 /* error */ +#define CSR_GO (1u << CSR_V_GO) +#define CSR_IE (1u << CSR_V_IE) +#define CSR_DONE (1u << CSR_V_DONE) +#define CSR_BUSY (1u << CSR_V_BUSY) +#define CSR_ERR (1u << CSR_V_ERR) + +/* Timers */ + +#define TMR_CLK 0 /* 100Hz clock */ + +/* I/O system definitions */ + +#define DZ_MUXES 4 /* max # of DZV muxes */ +#define DZ_LINES 8 /* lines per DZV mux */ +#define VH_MUXES 4 /* max # of DHQ muxes */ +#define DLX_LINES 16 /* max # of KL11/DL11's */ +#define DCX_LINES 16 /* max # of DC11's */ +#define MT_MAXFR (1 << 16) /* magtape max rec */ + +#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ +#define DEV_V_MBUS (DEV_V_UF + 1) /* Massbus */ +#define DEV_V_NEXUS (DEV_V_UF + 2) /* Nexus */ +#define DEV_V_FLTA (DEV_V_UF + 3) /* flt addr */ +#define DEV_V_CI (DEV_V_UF + 4) /* CI */ +#define DEV_V_FFUF (DEV_V_UF + 5) /* first free flag */ +#define DEV_UBUS (1u << DEV_V_UBUS) +#define DEV_MBUS (1u << DEV_V_MBUS) +#define DEV_NEXUS (1u << DEV_V_NEXUS) +#define DEV_CI (1u << DEV_V_CI) +#define DEV_FLTA (1u << DEV_V_FLTA) +#define DEV_QBUS (0) +#define DEV_Q18 (0) + +#define UNIBUS TRUE /* Unibus only */ + +#define DEV_RDX 16 /* default device radix */ + +/* Device information block + + For Massbus devices, + ba = Massbus number + lnt = Massbus ctrl type + ack[0] = abort routine + + For Nexus devices, + ba = Nexus number + lnt = number of consecutive nexi */ + +#define VEC_DEVMAX 4 /* max device vec */ + +typedef struct { + uint32 ba; /* base addr */ + uint32 lnt; /* length */ + t_stat (*rd)(int32 *dat, int32 ad, int32 md); + t_stat (*wr)(int32 dat, int32 ad, int32 md); + int32 vnum; /* vectors: number */ + int32 vloc; /* locator */ + int32 vec; /* value */ + int32 (*ack[VEC_DEVMAX])(void); /* ack routine */ + } DIB; + +/* Unibus I/O page layout - XUB,RQB,RQC,RQD float based on number of DZ's + Massbus devices (RP, TU) do not appear in the Unibus IO page */ + +#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ +#define IOLN_DZ 010 +#define IOBA_XUB (IOPAGEBASE + 000330 + (020 * (DZ_MUXES / 2))) +#define IOLN_XUB 010 +#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2))) +#define IOLN_RQB 004 +#define IOBA_RQC (IOPAGEBASE + IOBA_RQB + IOLN_RQB) +#define IOLN_RQC 004 +#define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC) +#define IOLN_RQD 004 +#define IOBA_RQ (IOPAGEBASE + 012150) /* UDA50 */ +#define IOLN_RQ 004 +#define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ +#define IOLN_TS 004 +#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ +#define IOLN_RL 012 +#define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */ +#define IOLN_XQ 020 +#define IOBA_XQB (IOPAGEBASE + 014460) /* 2nd DEQNA/DELQA */ +#define IOLN_XQB 020 +#define IOBA_TQ (IOPAGEBASE + 014500) /* TMSCP */ +#define IOLN_TQ 004 +#define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */ +#define IOLN_XU 010 +#define IOBA_CR (IOPAGEBASE + 017160) /* CD/CR/CM */ +#define IOLN_CR 010 +#define IOBA_RX (IOPAGEBASE + 017170) /* RX11 */ +#define IOLN_RX 004 +#define IOBA_RY (IOPAGEBASE + 017170) /* RXV21 */ +#define IOLN_RY 004 +#define IOBA_QDSS (IOPAGEBASE + 017400) /* QDSS */ +#define IOLN_QDSS 002 +#define IOBA_HK (IOPAGEBASE + 017440) /* RK611 */ +#define IOLN_HK 040 +#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ +#define IOLN_LPT 004 +#define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */ +#define IOLN_PTR 004 +#define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */ +#define IOLN_PTP 004 + +/* Interrupt assignments; within each level, priority is right to left */ + +#define INT_V_DZRX 0 /* BR5 */ +#define INT_V_DZTX 1 +#define INT_V_HK 2 +#define INT_V_RL 3 +#define INT_V_RQ 4 +#define INT_V_TQ 5 +#define INT_V_TS 6 +#define INT_V_RY 7 +#define INT_V_XU 8 + +#define INT_V_LPT 0 /* BR4 */ +#define INT_V_PTR 1 +#define INT_V_PTP 2 +#define INT_V_CR 3 + +#define INT_DZRX (1u << INT_V_DZRX) +#define INT_DZTX (1u << INT_V_DZTX) +#define INT_HK (1u << INT_V_HK) +#define INT_RL (1u << INT_V_RL) +#define INT_RQ (1u << INT_V_RQ) +#define INT_TQ (1u << INT_V_TQ) +#define INT_TS (1u << INT_V_TS) +#define INT_RY (1u << INT_V_RY) +#define INT_XU (1u << INT_V_XU) +#define INT_LPT (1u << INT_V_LPT) +#define INT_PTR (1u << INT_V_PTR) +#define INT_PTP (1u << INT_V_PTP) +#define INT_CR (1u << INT_V_CR) + +#define IPL_DZRX (0x15 - IPL_HMIN) +#define IPL_DZTX (0x15 - IPL_HMIN) +#define IPL_HK (0x15 - IPL_HMIN) +#define IPL_RL (0x15 - IPL_HMIN) +#define IPL_RQ (0x15 - IPL_HMIN) +#define IPL_TQ (0x15 - IPL_HMIN) +#define IPL_TS (0x15 - IPL_HMIN) +#define IPL_RY (0x15 - IPL_HMIN) +#define IPL_XU (0x15 - IPL_HMIN) +#define IPL_LPT (0x14 - IPL_HMIN) +#define IPL_PTR (0x14 - IPL_HMIN) +#define IPL_PTP (0x14 - IPL_HMIN) +#define IPL_CR (0x14 - IPL_HMIN) + +/* Device vectors */ + +#define VEC_QBUS 0 +#define VEC_Q 0x200 +#define VEC_PTR (VEC_Q + 0070) +#define VEC_PTP (VEC_Q + 0074) +#define VEC_XQ (VEC_Q + 0120) +#define VEC_XU (VEC_Q + 0120) +#define VEC_RQ (VEC_Q + 0154) +#define VEC_RL (VEC_Q + 0160) +#define VEC_LPT (VEC_Q + 0200) +#define VEC_HK (VEC_Q + 0210) +#define VEC_TS (VEC_Q + 0224) +#define VEC_CR (VEC_Q + 0230) +#define VEC_TQ (VEC_Q + 0260) +#define VEC_RX (VEC_Q + 0264) +#define VEC_RY (VEC_Q + 0264) +#define VEC_DZRX (VEC_Q + 0300) +#define VEC_DZTX (VEC_Q + 0304) + +/* Interrupt macros */ + +#define IVCL(dv) ((IPL_##dv * 32) + INT_V_##dv) +#define NVCL(dv) ((IPL_##dv * 32) + TR_##dv) +#define IREQ(dv) int_req[IPL_##dv] +#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv) +#define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv) +#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ + +/* Logging */ + +#define LOG_CPU_I 0x1 /* intexc */ +#define LOG_CPU_R 0x2 /* REI */ +#define LOG_CPU_P 0x4 /* context */ + +/* Massbus definitions */ + +#define MBA_RP (TR_MBA0 - TR_MBA0) /* MBA for RP */ +#define MBA_TU (TR_MBA1 - TR_MBA0) /* MBA for TU */ +#define MBA_RMASK 0x1F /* max 32 reg */ +#define MBE_NXD 1 /* nx drive */ +#define MBE_NXR 2 /* nx reg */ +#define MBE_GOE 3 /* err on GO */ + +/* Boot definitions */ + +#define BOOT_MB 0 /* device codes */ +#define BOOT_HK 1 /* for VMB */ +#define BOOT_RL 2 +#define BOOT_UDA 17 +#define BOOT_TK 18 +#define BOOT_CI 32 +#define BOOT_TD 64 + +/* Function prototypes for virtual memory interface */ + +int32 Read (uint32 va, int32 lnt, int32 acc); +void Write (uint32 va, int32 val, int32 lnt, int32 acc); + +/* Function prototypes for physical memory interface (inlined) */ + +SIM_INLINE int32 ReadB (uint32 pa); +SIM_INLINE int32 ReadW (uint32 pa); +SIM_INLINE int32 ReadL (uint32 pa); +SIM_INLINE int32 ReadLP (uint32 pa); +SIM_INLINE void WriteB (uint32 pa, int32 val); +SIM_INLINE void WriteW (uint32 pa, int32 val); +SIM_INLINE void WriteL (uint32 pa, int32 val); +void WriteLP (uint32 pa, int32 val); + +/* Function prototypes for I/O */ + +int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); +int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); +int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); +int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); + +int32 mba_rdbufW (uint32 mbus, int32 bc, uint16 *buf); +int32 mba_wrbufW (uint32 mbus, int32 bc, uint16 *buf); +int32 mba_chbufW (uint32 mbus, int32 bc, uint16 *buf); +int32 mba_get_bc (uint32 mbus); +void mba_upd_ata (uint32 mbus, uint32 val); +void mba_set_exc (uint32 mbus); +void mba_set_don (uint32 mbus); +void mba_set_enbdis (uint32 mbus, t_bool dis); +t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc); + +t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc); + +void sbi_set_errcnf (void); +int32 clk_cosched (int32 wait); + +#include "pdp11_io_lib.h" + +#endif diff --git a/VAX/vax750_mem.c b/VAX/vax750_mem.c new file mode 100644 index 00000000..a3755bd0 --- /dev/null +++ b/VAX/vax750_mem.c @@ -0,0 +1,207 @@ +/* vax750_mem.c: VAX 11/750 memory controllers + + Copyright (c) 2010-2012, Matt Burke + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + mctl MS750 memory controller + + 21-Oct-2012 MB First Version +*/ + +#include "vax_defs.h" + +/* Memory adapter register 0 */ + +#define MCSR0_OF 0x00 +#define MCSR0_ES 0x0000007F /* Error syndrome */ +#define MCSR0_V_EP 9 +#define MCSR0_M_EP 0x7FFF +#define MCSR0_EP (MCSR0_M_EP << MCSR0_V_EP) /* Error page */ +#define MCSR0_CRD 0x20000000 /* Corrected read data */ +#define MCSR0_RDSH 0x40000000 /* Read data subs high */ +#define MCSR0_RDS 0x80000000 /* Read data substitute */ +#define MCSR0_RS (MCSR0_CRD | MCSR0_RDSH | MCSR0_RDS) + +/* Memory adapter register 1 */ + +#define MCSR1_OF 0x01 +#define MCSR1_CS 0x0000007F /* Check syndrome */ +#define MCSR1_V_EP 9 +#define MCSR1_M_EP 0x7FFF +#define MCSR1_EP (MCSR1_M_EP << MCSR1_V_EP) /* Page mode address */ +#define MCSR1_ECCD 0x02000000 /* ECC disable */ +#define MCSR1_DIAG 0x04000000 /* Diag mode */ +#define MCSR1_PM 0x08000000 /* Page mode */ +#define MCSR1_CRE 0x10000000 /* CRD enable */ +#define MCSR1_RW (MCSR1_CS | MCSR1_ECCD | MCSR1_DIAG | \ + MCSR1_PM | MCSR1_CRE) + +/* Memory adapter register 2 */ + +#define MCSR2_OF 0x02 +#define MCSR2_M_MAP 0xFFFF /* Memory present */ +#define MCSR2_INIT 0x00010000 /* Cold/warm restart flag */ +#define MCSR2_V_SA 17 +#define MCSR2_M_SA 0x7F /* Start address */ +#define MCSR2_V_CS 24 +#define MCSR2_CS (1u << MCSR2_V_CS) /* Chip size */ +#define MCSR2_MBZ 0xFF000000 + +/* Debug switches */ + +#define MCTL_DEB_RRD 0x01 /* reg reads */ +#define MCTL_DEB_RWR 0x02 /* reg writes */ + +#define MEM_SIZE_16K (1u << 17) /* Board size (16k chips) */ +#define MEM_SIZE_64K (1u << 19) /* Board size (64k chips) */ +#define MEM_BOARD_MASK(x,y) ((1u << (uint32)(x/y)) - 1) +#define MEM_64K_MASK 0x5555 + +extern UNIT cpu_unit; +extern FILE *sim_log, *sim_deb; + +uint32 mcsr0 = 0; +uint32 mcsr1 = 0; +uint32 mcsr2 = 0; + +t_stat mctl_reset (DEVICE *dptr); +t_stat mctl_rdreg (int32 *val, int32 pa, int32 mode); +t_stat mctl_wrreg (int32 val, int32 pa, int32 mode); + +/* MCTL data structures + + mctl_dev MCTL device descriptor + mctl_unit MCTL unit + mctl_reg MCTL register list +*/ + +DIB mctl_dib[] = { TR_MCTL, 0, &mctl_rdreg, &mctl_wrreg, 0 }; + +UNIT mctl_unit = { UDATA (NULL, 0, 0) }; + +REG mctl_reg[] = { + { NULL } + }; + +MTAB mctl_mod[] = { + { MTAB_XTD|MTAB_VDV, TR_MCTL, "NEXUS", NULL, + NULL, &show_nexus }, + { 0 } + }; + +DEBTAB mctl_deb[] = { + { "REGREAD", MCTL_DEB_RRD }, + { "REGWRITE", MCTL_DEB_RWR }, + { NULL, 0 } + }; + +DEVICE mctl_dev = { + "MCTL", &mctl_unit, mctl_reg, mctl_mod, + 1, 16, 16, 1, 16, 8, + NULL, NULL, &mctl_reset, + NULL, NULL, NULL, + &mctl_dib, DEV_NEXUS | DEV_DEBUG, 0, + mctl_deb, 0, 0 + }; + +/* Memory controller register read */ + +t_stat mctl_rdreg (int32 *val, int32 pa, int32 lnt) +{ +int32 ofs; +ofs = NEXUS_GETOFS (pa); /* get offset */ + +switch (ofs) { /* case on offset */ + + case MCSR0_OF: /* CSR0 */ + *val = mcsr0; + break; + + case MCSR1_OF: /* CSR1 */ + *val = mcsr1; + break; + + case MCSR2_OF: /* CSR2 */ + *val = mcsr2 & ~MCSR2_MBZ; + break; + + default: + return SCPE_NXM; + } + +if (DEBUG_PRI (mctl_dev, MCTL_DEB_RRD)) + fprintf (sim_deb, ">>MCTL: reg %d read, value = %X\n", ofs, *val); + +return SCPE_OK; +} + +/* Memory controller register write */ + +t_stat mctl_wrreg (int32 val, int32 pa, int32 lnt) +{ +int32 ofs; + +ofs = NEXUS_GETOFS (pa); /* get offset */ + +switch (ofs) { /* case on offset */ + + case MCSR0_OF: /* CSR0 */ + mcsr0 = mcsr0 & ~(MCSR0_RS & val); + break; + + case MCSR1_OF: /* CSR1 */ + mcsr1 = val & MCSR1_RW; + break; + + case MCSR2_OF: /* CSR2 */ + break; + + default: + return SCPE_NXM; + } + +if (DEBUG_PRI (mctl_dev, MCTL_DEB_RWR)) + fprintf (sim_deb, ">>MCTL: reg %d write, value = %X\n", ofs, val); + +return SCPE_OK; +} + +/* Used by CPU */ + +void rom_wr_B (int32 pa, int32 val) +{ +return; +} + +/* Memory controller reset */ + +t_stat mctl_reset (DEVICE *dptr) +{ +mcsr0 = 0; +mcsr1 = 0; +if (MEMSIZE > MAXMEMSIZE) /* More than 2MB? */ + mcsr2 = MCSR2_INIT | (MEM_BOARD_MASK(MEMSIZE, MEM_SIZE_64K) & MEM_64K_MASK) | MCSR2_CS; /* Use 64k chips */ +else + mcsr2 = MCSR2_INIT | MEM_BOARD_MASK(MEMSIZE, MEM_SIZE_16K); /* Use 16k chips */ +return SCPE_OK; +} diff --git a/VAX/vax750_stddev.c b/VAX/vax750_stddev.c new file mode 100644 index 00000000..a98b7ce7 --- /dev/null +++ b/VAX/vax750_stddev.c @@ -0,0 +1,1097 @@ +/* vax750_stddev.c: VAX 11/750 standard I/O devices + + Copyright (c) 2010-2012, Matt Burke + This module incorporates code from SimH, Copyright (c) 1998-2011, 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 + THE AUTHOR(S) 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(s) of the author(s) shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author(s). + + tti console input + tto console output + td console TU58 + todr TODR clock + tmr interval timer + + 21-Oct-2012 MB First Version +*/ + +#include "vax_defs.h" +#include + +/* Terminal definitions */ + +#define RXCS_RD (CSR_DONE + CSR_IE) /* terminal input */ +#define RXCS_WR (CSR_IE) +#define RXDB_ERR 0x8000 /* error */ +#define RXDB_OVR 0x4000 /* overrun */ +#define RXDB_FRM 0x2000 /* framing error */ +#define TXCS_RD (CSR_DONE + CSR_IE) /* terminal output */ +#define TXCS_WR (CSR_IE) +#define TXDB_V_SEL 8 /* unit select */ +#define TXDB_M_SEL 0xF +#define TXDB_MISC 0xF /* console misc */ +#define MISC_MASK 0xFF /* console data mask */ +#define MISC_SWDN 0x1 /* software done */ +#define MISC_BOOT 0x2 /* reboot */ +#define MISC_CLWS 0x3 /* clear warm start */ +#define MISC_CLCS 0x4 /* clear cold start */ +#define TXDB_SEL (TXDB_M_SEL << TXDB_V_SEL) /* non-terminal */ +#define TXDB_GETSEL(x) (((x) >> TXDB_V_SEL) & TXDB_M_SEL) +#define CSTS_BRK 0x1 +#define CSTS_RD (CSR_DONE + CSR_IE + CSTS_BRK) /* terminal output */ +#define CSTS_WR (CSR_IE + CSTS_BRK) + +/* Clock definitions */ + +#define TMR_CSR_ERR 0x80000000 /* error W1C */ +#define TMR_CSR_DON 0x00000080 /* done W1C */ +#define TMR_CSR_IE 0x00000040 /* int enb RW */ +#define TMR_CSR_SGL 0x00000020 /* single WO */ +#define TMR_CSR_XFR 0x00000010 /* xfer WO */ +#define TMR_CSR_RUN 0x00000001 /* run RW */ +#define TMR_CSR_RD (TMR_CSR_W1C | TMR_CSR_WR) +#define TMR_CSR_W1C (TMR_CSR_ERR | TMR_CSR_DON) +#define TMR_CSR_WR (TMR_CSR_IE | TMR_CSR_RUN) +#define TMR_INC 10000 /* usec/interval */ +#define CLK_DELAY 5000 /* 100 Hz */ +#define TMXR_MULT 1 /* 100 Hz */ + +/* TU58 definitions */ + +#define UNIT_V_WLK (UNIT_V_UF) /* write locked */ +#define UNIT_WLK (1u << UNIT_V_UF) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ + +#define TD_NUMBLK 512 /* blocks/tape */ +#define TD_NUMBY 512 /* bytes/block */ +#define TD_SIZE (TD_NUMBLK * TD_NUMBY) /* bytes/tape */ + +#define TD_OPDAT 001 /* Data */ +#define TD_OPCMD 002 /* Command */ +#define TD_OPINI 004 /* INIT */ +#define TD_OPBOO 010 /* Bootstrap */ +#define TD_OPCNT 020 /* Continue */ +#define TD_OPXOF 023 /* XOFF */ + +#define TD_CMDNOP 0000 /* NOP */ +#define TD_CMDINI 0001 /* INIT */ +#define TD_CMDRD 0002 /* Read */ +#define TD_CMDWR 0003 /* Write */ +#define TD_CMDPOS 0005 /* Position */ +#define TD_CMDDIA 0007 /* Diagnose */ +#define TD_CMDGST 0010 /* Get Status */ +#define TD_CMDSST 0011 /* Set Status */ +#define TD_CMDMRSP 0012 /* MRSP Request */ +#define TD_CMDEND 0100 /* END */ + +#define TD_STSOK 0000 /* Normal success */ +#define TD_STSRTY 0001 /* Success with retries */ +#define TD_STSFAIL 0377 /* Failed selftest */ +#define TD_STSPO 0376 /* Partial operation (end of medium) */ +#define TD_STSBUN 0370 /* Bad unit number */ +#define TD_STSNC 0367 /* No cartridge */ +#define TD_STSWP 0365 /* Write protected */ +#define TD_STSDCE 0357 /* Data check error */ +#define TD_STSSE 0340 /* Seek error (block not found) */ +#define TD_STSMS 0337 /* Motor stopped */ +#define TD_STSBOP 0320 /* Bad opcode */ +#define TD_STSBBN 0311 /* Bad block number (>511) */ + +#define TD_GETOPC 0 /* get opcode state */ +#define TD_GETLEN 1 /* get length state */ +#define TD_GETDATA 2 /* get data state */ + +#define TD_IDLE 0 /* idle state */ +#define TD_READ 1 /* read */ +#define TD_READ1 2 /* fill buffer */ +#define TD_READ2 3 /* empty buffer */ +#define TD_WRITE 4 /* write */ +#define TD_WRITE1 5 /* write */ +#define TD_WRITE2 6 /* write */ +#define TD_END 7 /* empty buffer */ +#define TD_END1 8 /* empty buffer */ +#define TD_INIT 9 /* empty buffer */ + +int32 tti_csr = 0; /* control/status */ +int32 tti_buf = 0; /* buffer */ +int32 tti_int = 0; /* interrupt */ +int32 tto_csr = 0; /* control/status */ +int32 tto_buf = 0; /* buffer */ +int32 tto_int = 0; /* interrupt */ + +int32 csi_csr = 0; /* control/status */ +int32 csi_buf = 0; /* buffer */ +int32 csi_int = 0; /* interrupt */ +int32 cso_csr = 0; /* control/status */ +int32 cso_buf = 0; /* buffer */ +int32 cso_int = 0; /* interrupt */ +int32 cso_state = 0; /* state */ + +int32 tmr_iccs = 0; /* interval timer csr */ +uint32 tmr_icr = 0; /* curr interval */ +uint32 tmr_nicr = 0; /* next interval */ +uint32 tmr_inc = 0; /* timer increment */ +int32 tmr_sav = 0; /* timer save */ +int32 tmr_int = 0; /* interrupt */ +int32 tmr_use_100hz = 1; /* use 100Hz for timer */ +int32 clk_tps = 100; /* ticks/second */ +int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ +int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ +int32 todr_reg = 0; /* TODR register */ + +int32 td_swait = 100; /* seek, per block */ +int32 td_cwait = 150; /* command time */ +int32 td_xwait = 180; /* tr set time */ +int32 td_iwait = 180; /* init time */ +uint8 td_ibuf[TD_NUMBY] = { 0 }; /* input buffer */ +int32 td_ibptr = 0; /* input buffer pointer */ +int32 td_ilen = 0; /* input length */ +uint8 td_obuf[TD_NUMBY] = { 0 }; /* output buffer */ +int32 td_obptr = 0; /* output buffer pointer */ +int32 td_olen = 0; /* output length */ +int32 td_block = 0; /* current block number */ +int32 td_txsize = 0; /* remaining transfer size */ +int32 td_offset = 0; /* offset into current transfer */ +int32 td_state = TD_IDLE; +int32 td_ecode = 0; /* end packet success code */ + +extern int32 sim_switches; +extern jmp_buf save_env; + +t_stat tti_svc (UNIT *uptr); +t_stat tto_svc (UNIT *uptr); +t_stat clk_svc (UNIT *uptr); +t_stat tmr_svc (UNIT *uptr); +t_stat tti_reset (DEVICE *dptr); +t_stat tto_reset (DEVICE *dptr); +t_stat clk_reset (DEVICE *dptr); +t_stat tmr_reset (DEVICE *dptr); +t_stat td_svc (UNIT *uptr); +t_stat td_reset (DEVICE *dptr); +int32 icr_rd (t_bool interp); +void tmr_incr (uint32 inc); +void tmr_sched (void); +t_stat todr_resync (void); +t_stat txdb_misc_wr (int32 data); +void td_process_packet(); +t_bool td_test_xfr (UNIT *uptr, int32 state); + +extern int32 con_halt (int32 code, int32 cc); + +/* TTI data structures + + tti_dev TTI device descriptor + tti_unit TTI unit descriptor + tti_reg TTI register list +*/ + +UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_8B, 0), 0 }; + +REG tti_reg[] = { + { HRDATA (RXDB, tti_buf, 16) }, + { HRDATA (RXCS, tti_csr, 16) }, + { FLDATA (INT, tti_int, 0) }, + { FLDATA (DONE, tti_csr, CSR_V_DONE) }, + { FLDATA (IE, tti_csr, CSR_V_IE) }, + { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, + { NULL } + }; + +MTAB tti_mod[] = { + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { 0 } + }; + +DEVICE tti_dev = { + "TTI", &tti_unit, tti_reg, tti_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &tti_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* TTO data structures + + tto_dev TTO device descriptor + tto_unit TTO unit descriptor + tto_reg TTO register list +*/ + +UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_8B, 0), SERIAL_OUT_WAIT }; + +REG tto_reg[] = { + { HRDATA (TXDB, tto_buf, 16) }, + { HRDATA (TXCS, tto_csr, 16) }, + { FLDATA (INT, tto_int, 0) }, + { FLDATA (DONE, tto_csr, CSR_V_DONE) }, + { FLDATA (IE, tto_csr, CSR_V_IE) }, + { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT + REG_NZ }, + { NULL } + }; + +MTAB tto_mod[] = { + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { 0 } + }; + +DEVICE tto_dev = { + "TTO", &tto_unit, tto_reg, tto_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &tto_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* TODR and TMR data structures */ + +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; /* 100Hz */ + +REG clk_reg[] = { + { DRDATA (TODR, todr_reg, 32), PV_LEFT }, + { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TPS, clk_tps, 8), REG_HIDDEN + REG_NZ + PV_LEFT }, + { NULL } + }; + +DEVICE clk_dev = { + "TODR", &clk_unit, clk_reg, NULL, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &clk_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */ + +REG tmr_reg[] = { + { HRDATA (ICCS, tmr_iccs, 32) }, + { HRDATA (ICR, tmr_icr, 32) }, + { HRDATA (NICR, tmr_nicr, 32) }, + { HRDATA (INCR, tmr_inc, 32), REG_HIDDEN }, + { HRDATA (SAVE, tmr_sav, 32), REG_HIDDEN }, + { FLDATA (USE100HZ, tmr_use_100hz, 0), REG_HIDDEN }, + { FLDATA (INT, tmr_int, 0) }, + { NULL } + }; + +DEVICE tmr_dev = { + "TMR", &tmr_unit, tmr_reg, NULL, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &tmr_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* TU58 data structures + + td_dev RX device descriptor + td_unit RX unit list + td_reg RX register list + td_mod RX modifier list +*/ + +UNIT td_unit = { UDATA (&td_svc, + UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, TD_SIZE) }; + +REG td_reg[] = { + { HRDATA (ECODE, td_ecode, 8) }, + { HRDATA (BLK, td_block, 8) }, + { DRDATA (STATE, td_state, 4), REG_RO }, + { DRDATA (BPTR, td_obptr, 7) }, + { DRDATA (CTIME, td_cwait, 24), PV_LEFT }, + { DRDATA (STIME, td_swait, 24), PV_LEFT }, + { DRDATA (XTIME, td_xwait, 24), PV_LEFT }, + { NULL } + }; + +MTAB td_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { 0 } + }; + +DEVICE td_dev = { + "TD", &td_unit, td_reg, td_mod, + 1, DEV_RDX, 20, 1, DEV_RDX, 8, + NULL, NULL, &td_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* Console storage MxPR routines + + csrs_rd/wr input control/status + csrd_rd input buffer + csts_rd/wr output control/status + cstd_wr output buffer +*/ + +int32 csrs_rd (void) +{ +return (csi_csr & RXCS_RD); +} + +void csrs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) + cso_int = 0; +else if ((csi_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + csi_int = 1; +csi_csr = (csi_csr & ~RXCS_WR) | (data & RXCS_WR); +return; +} + +int32 csrd_rd (void) +{ +int32 t = csi_buf; /* char + error */ + +csi_csr = csi_csr & ~CSR_DONE; /* clr done */ +csi_buf = csi_buf & BMASK; /* clr errors */ +csi_int = 0; +return t; +} + +int32 csts_rd (void) +{ +return (cso_csr & TXCS_RD); +} + +void csts_wr (int32 data) +{ +if ((cso_csr & CSTS_BRK) && !(data & CSTS_BRK)) { + td_ibptr = 0; + td_ibuf[td_ibptr++] = TD_OPINI; + td_process_packet(); /* check packet */ + } +if ((data & CSR_IE) == 0) + cso_int = 0; +else if ((cso_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + cso_int = 1; +cso_csr = (cso_csr & ~CSTS_WR) | (data & CSTS_WR); +return; +} + +void cstd_wr (int32 data) +{ +cso_buf = data & WMASK; /* save data */ +cso_csr = cso_csr & ~CSR_DONE; /* clear flag */ +cso_int = 0; /* clear int */ + +switch (cso_state) { + + case TD_GETOPC: + td_ibptr = 0; + td_ibuf[td_ibptr++] = cso_buf; + td_process_packet(); /* check packet */ + break; + + case TD_GETLEN: + td_ibuf[td_ibptr++] = cso_buf; + td_ilen = cso_buf + 4; /* packet length + header + checksum */ + cso_state = TD_GETDATA; + break; + + case TD_GETDATA: + td_ibuf[td_ibptr++] = cso_buf; + if (td_ibptr >= td_ilen) { + cso_state = TD_GETOPC; + td_process_packet(); + } + break; + } + +cso_csr = cso_csr | CSR_DONE; /* set input flag */ +if (cso_csr & CSR_IE) + cso_int = 1; +return; +} + +void td_process_packet() +{ +int32 opcode = td_ibuf[0]; + +switch (opcode) { + + case TD_OPDAT: + if (td_state != TD_WRITE1) { /* expecting data? */ + printf("TU58 protocol error 1\n"); + return; + } + if (td_ibptr < 2) { /* whole packet read? */ + cso_state = TD_GETLEN; /* get rest of packet */ + return; + } + td_state = TD_WRITE2; + sim_activate (&td_unit, td_cwait); /* sched command */ + break; + + case TD_OPCMD: + if (td_state != TD_IDLE) { /* expecting command? */ + printf("TU58 protocol error 2\n"); + return; + } + if (td_ibptr < 2) { /* whole packet read? */ + cso_state = TD_GETLEN; /* get rest of packet */ + return; + } + switch (td_ibuf[2]) { + case TD_CMDNOP: /* NOP */ + case TD_CMDGST: /* Get status */ + case TD_CMDSST: /* Set status */ + td_state = TD_END; /* All treated as NOP */ + td_ecode = TD_STSOK; + td_offset = 0; + sim_activate (&td_unit, td_cwait); /* sched command */ + break; + + case TD_CMDINI: + printf("Warning: TU58 command 'INIT' not implemented\n"); + break; + + case TD_CMDRD: + td_block = ((td_ibuf[11] << 8) | td_ibuf[10]); + td_txsize = ((td_ibuf[9] << 8) | td_ibuf[8]); + td_state = TD_READ; + td_offset = 0; + sim_activate (&td_unit, td_cwait); /* sched command */ + break; + + case TD_CMDWR: + td_block = ((td_ibuf[11] << 8) | td_ibuf[10]); + td_txsize = ((td_ibuf[9] << 8) | td_ibuf[8]); + td_state = TD_WRITE; + td_offset = 0; + sim_activate (&td_unit, td_cwait); /* sched command */ + break; + + case TD_CMDPOS: + printf("Warning: TU58 command 'Position' not implemented\n"); + break; + + case TD_CMDDIA: + printf("Warning: TU58 command 'Diagnose' not implemented\n"); + break; + + case TD_CMDMRSP: + csi_buf = TD_OPDAT; + csi_csr = csi_csr | CSR_DONE; /* set input flag */ + if (csi_csr & CSR_IE) + csi_int = 1; + break; + } + break; + + case TD_OPINI: + sim_cancel (&td_unit); + td_ibptr = 0; + td_obptr = 0; + td_olen = 0; + td_offset = 0; + td_txsize = 0; + cso_state = TD_GETOPC; + td_state = TD_INIT; + sim_activate (&td_unit, td_iwait); /* sched command */ + break; + + case TD_OPBOO: + if (td_state != TD_IDLE) { + printf("TU58 protocol error 3\n"); + return; + } + if (td_ibptr < 2) { /* whole packet read? */ + td_ilen = 2; + cso_state = TD_GETDATA; /* get rest of packet */ + return; + } + td_block = 0; + td_txsize = 512; + td_state = TD_READ; + td_offset = 0; + sim_activate (&td_unit, td_cwait); /* sched command */ + break; + + case TD_OPCNT: + break; + + default: + //printf("TU58: Unknown opcode %d\n", opcode); + break; + } +} + +/* Terminal MxPR routines + + rxcs_rd/wr input control/status + rxdb_rd input buffer + txcs_rd/wr output control/status + txdb_wr output buffer +*/ + +int32 rxcs_rd (void) +{ +return (tti_csr & RXCS_RD); +} + +void rxcs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) + tto_int = 0; +else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + tti_int = 1; +tti_csr = (tti_csr & ~RXCS_WR) | (data & RXCS_WR); +return; +} + +int32 rxdb_rd (void) +{ +int32 t = tti_buf; /* char + error */ + +tti_csr = tti_csr & ~CSR_DONE; /* clr done */ +tti_buf = tti_buf & BMASK; /* clr errors */ +tti_int = 0; +return t; +} + +int32 txcs_rd (void) +{ +return (tto_csr & TXCS_RD); +} + +void txcs_wr (int32 data) +{ +if ((data & CSR_IE) == 0) + tto_int = 0; +else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + tto_int = 1; +tto_csr = (tto_csr & ~TXCS_WR) | (data & TXCS_WR); +return; +} + +void txdb_wr (int32 data) +{ +tto_buf = data & WMASK; /* save data */ +tto_csr = tto_csr & ~CSR_DONE; /* clear flag */ +tto_int = 0; /* clear int */ +if (tto_buf & TXDB_SEL) /* console? */ + txdb_misc_wr (tto_buf); +else sim_activate (&tto_unit, tto_unit.wait); /* no, console terminal */ +return; +} + +/* Terminal input service (poll for character) */ + +t_stat tti_svc (UNIT *uptr) +{ +int32 c; + +sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ + return c; +if (c & SCPE_BREAK) /* break? */ + tti_buf = RXDB_ERR | RXDB_FRM; +else tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); +uptr->pos = uptr->pos + 1; +tti_csr = tti_csr | CSR_DONE; +if (tti_csr & CSR_IE) + tti_int = 1; +return SCPE_OK; +} + +/* Terminal input reset */ + +t_stat tti_reset (DEVICE *dptr) +{ +tti_buf = 0; +tti_csr = 0; +tti_int = 0; +sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); +csi_buf = 0; +csi_csr = 0; +csi_int = 0; +return SCPE_OK; +} + +/* Terminal output service (output character) */ + +t_stat tto_svc (UNIT *uptr) +{ +int32 c; +t_stat r; + +if ((tto_buf & TXDB_SEL) == 0) { /* for console? */ + c = sim_tt_outcvt (tto_buf, TT_GET_MODE (uptr->flags)); + if (c >= 0) { + if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ + sim_activate (uptr, uptr->wait); /* retry */ + return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ + } + } + uptr->pos = uptr->pos + 1; + } +tto_csr = tto_csr | CSR_DONE; +if (tto_csr & CSR_IE) + tto_int = 1; +return SCPE_OK; +} + +/* Terminal output reset */ + +t_stat tto_reset (DEVICE *dptr) +{ +tto_buf = 0; +tto_csr = CSR_DONE; +tto_int = 0; +sim_cancel (&tto_unit); /* deactivate unit */ +return SCPE_OK; +} + +/* Programmable timer + + The architected VAX timer, which increments at 1Mhz, cannot be + accurately simulated due to the overhead that would be required + for 1M clock events per second. Instead, a hidden calibrated + 100Hz timer is run (because that's what VMS expects), and a + hack is used for the interval timer. + + When the timer is started, the timer interval is inspected. + + if the interval is >= 10msec, then the 100Hz timer drives the + next interval + if the interval is < 10mec, then count instructions + + If the interval register is read, then its value between events + is interpolated using the current instruction count versus the + count when the most recent event started, the result is scaled + to the calibrated system clock, unless the interval being timed + is less than a calibrated system clock tick (or the calibrated + clock is running very slowly) at which time the result will be + the elapsed instruction count. +*/ + +int32 iccs_rd (void) +{ +return tmr_iccs & TMR_CSR_RD; +} + +void iccs_wr (int32 val) +{ +if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */ + sim_cancel (&tmr_unit); /* cancel timer */ + tmr_use_100hz = 0; + if (tmr_iccs & TMR_CSR_RUN) /* run 1 -> 0? */ + tmr_icr = icr_rd (TRUE); /* update itr */ + } +tmr_iccs = tmr_iccs & ~(val & TMR_CSR_W1C); /* W1C csr */ +tmr_iccs = (tmr_iccs & ~TMR_CSR_WR) | /* new r/w */ + (val & TMR_CSR_WR); +if (val & TMR_CSR_XFR) tmr_icr = tmr_nicr; /* xfr set? */ +if (val & TMR_CSR_RUN) { /* run? */ + if (val & TMR_CSR_XFR) /* new tir? */ + sim_cancel (&tmr_unit); /* stop prev */ + if (!sim_is_active (&tmr_unit)) /* not running? */ + tmr_sched (); /* activate */ + } +else if (val & TMR_CSR_SGL) { /* single step? */ + tmr_incr (1); /* incr tmr */ + if (tmr_icr == 0) /* if ovflo, */ + tmr_icr = tmr_nicr; /* reload tir */ + } +if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */ + (TMR_CSR_DON | TMR_CSR_IE)) + tmr_int = 0; +return; +} + +int32 icr_rd (t_bool interp) +{ +uint32 delta; + +if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */ + delta = sim_grtime () - tmr_sav; /* delta inst */ + if (tmr_use_100hz && (tmr_poll > TMR_INC)) /* scale large int */ + delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll); + if (delta >= tmr_inc) + delta = tmr_inc - 1; + return tmr_icr + delta; + } +return tmr_icr; +} + +int32 nicr_rd () +{ +return tmr_nicr; +} + +void nicr_wr (int32 val) +{ +tmr_nicr = val; +} + +/* 100Hz base clock unit service */ + +t_stat clk_svc (UNIT *uptr) +{ +tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ +sim_activate (&clk_unit, tmr_poll); /* reactivate unit */ +tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ +todr_reg = todr_reg + 1; /* incr TODR */ +if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ + tmr_incr (TMR_INC); /* do timer service */ +return SCPE_OK; +} + +/* Interval timer unit service */ + +t_stat tmr_svc (UNIT *uptr) +{ +tmr_incr (tmr_inc); /* incr timer */ +return SCPE_OK; +} + +/* Timer increment */ + +void tmr_incr (uint32 inc) +{ +uint32 new_icr = (tmr_icr + inc) & LMASK; /* add incr */ + +if (new_icr < tmr_icr) { /* ovflo? */ + tmr_icr = 0; /* now 0 */ + if (tmr_iccs & TMR_CSR_DON) /* done? set err */ + tmr_iccs = tmr_iccs | TMR_CSR_ERR; + else tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */ + if (tmr_iccs & TMR_CSR_RUN) { /* run? */ + tmr_icr = tmr_nicr; /* reload */ + tmr_sched (); /* reactivate */ + } + if (tmr_iccs & TMR_CSR_IE) /* ie? set int req */ + tmr_int = 1; + else tmr_int = 0; + } +else { + tmr_icr = new_icr; /* no, update icr */ + if (tmr_iccs & TMR_CSR_RUN) /* still running? */ + tmr_sched (); /* reactivate */ + } +return; +} + +/* Timer scheduling */ + +void tmr_sched (void) +{ +tmr_sav = sim_grtime (); /* save intvl base */ +tmr_inc = (~tmr_icr + 1); /* inc = interval */ +if (tmr_inc == 0) tmr_inc = 1; +if (tmr_inc < TMR_INC) { /* 100Hz multiple? */ + sim_activate (&tmr_unit, tmr_inc); /* schedule timer */ + tmr_use_100hz = 0; + } +else tmr_use_100hz = 1; /* let clk handle */ +return; +} + +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&clk_unit); +return (t? t - 1: wait); +} + +/* 100Hz clock reset */ + +t_stat clk_reset (DEVICE *dptr) +{ +tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */ +sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */ +tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ +return SCPE_OK; +} + +/* Interval timer reset */ + +t_stat tmr_reset (DEVICE *dptr) +{ +tmr_iccs = 0; +tmr_icr = 0; +tmr_nicr = 0; +tmr_int = 0; +tmr_use_100hz = 1; +sim_cancel (&tmr_unit); /* cancel timer */ +todr_resync (); /* resync TODR */ +return SCPE_OK; +} + +/* TODR routines */ + +int32 todr_rd (void) +{ +return todr_reg; +} + +void todr_wr (int32 data) +{ +todr_reg = data; +return; +} + +t_stat todr_resync (void) +{ +uint32 base; +time_t curr; +struct tm *ctm; + +curr = time (NULL); /* get curr time */ +if (curr == (time_t) -1) /* error? */ + return SCPE_NOFNC; +ctm = localtime (&curr); /* decompose */ +if (ctm == NULL) /* error? */ + return SCPE_NOFNC; +base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; +todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */ +return SCPE_OK; +} + +/* Console write, txdb<11:8> != 0 (console unit) */ + +t_stat txdb_misc_wr (int32 data) +{ +int32 sel = TXDB_GETSEL (data); /* get selection */ + +sim_activate (&tto_unit, tto_unit.wait); /* set up timeout */ +if (sel == TXDB_MISC) { /* misc function? */ + switch (data & MISC_MASK) { /* case on function */ + case MISC_CLWS: + case MISC_CLCS: + break; + case MISC_SWDN: + ABORT (STOP_SWDN); + break; + case MISC_BOOT: + con_halt (0, 0); /* set up reboot */ + break; + } + } +return SCPE_OK; +} + +t_stat td_svc (UNIT *uptr) +{ +int32 i, t, data_size; +uint16 c, w; +uint32 da; +int8 *fbuf = uptr->filebuf; + +switch (td_state) { /* case on state */ + + case TD_IDLE: /* idle */ + return SCPE_IERR; /* done */ + + case TD_READ: case TD_WRITE: /* read, write */ + if (td_test_xfr (uptr, td_state)) { /* transfer ok? */ + t = abs (td_block - 0); /* # blocks to seek */ + if (t == 0) /* minimum 1 */ + t = 1; + td_state++; /* set next state */ + sim_activate (uptr, td_swait * t); /* schedule seek */ + break; + } + else td_state = TD_END; + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_READ1: /* build data packet */ + da = (td_block * 512) + td_offset; /* get tape address */ + if (td_txsize > 128) /* Packet length */ + data_size = 128; + else data_size = td_txsize; + td_txsize = td_txsize - data_size; + td_offset = td_offset + data_size; + + td_obptr = 0; + td_obuf[td_obptr++] = TD_OPDAT; /* Data packet */ + td_obuf[td_obptr++] = data_size; /* Data length */ + for (i = 0; i < data_size; i++) /* copy sector to buf */ + td_obuf[td_obptr++] = fbuf[da + i]; + c = 0; + for (i = 0; i < (data_size + 2); i++) { /* Calculate checksum */ + w = (td_obuf[i] << ((i & 0x1) ? 8 : 0)); + c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); + } + td_obuf[td_obptr++] = (c & 0xFF); /* Checksum L */ + td_obuf[td_obptr++] = ((c >> 8) & 0xFF); /* Checksum H */ + td_olen = td_obptr; + td_obptr = 0; + td_state = TD_READ2; /* go empty */ + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_READ2: /* send data packet to host */ + if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ + csi_buf = td_obuf[td_obptr++]; /* get next byte */ + csi_csr = csi_csr | CSR_DONE; /* set input flag */ + if (csi_csr & CSR_IE) + csi_int = 1; + if (td_obptr >= td_olen) { /* buffer empty? */ + if (td_txsize > 0) + td_state = TD_READ1; + else + td_state = TD_END; + } + } + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_WRITE1: /* send continue */ + if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ + csi_buf = TD_OPCNT; + csi_csr = csi_csr | CSR_DONE; /* set input flag */ + if (csi_csr & CSR_IE) + csi_int = 1; + break; + } + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_WRITE2: /* write data to buffer */ + da = (td_block * 512) + td_offset; /* get tape address */ + td_olen = td_ibuf[1]; + for (i = 0; i < td_olen; i++) /* write data to buffer */ + fbuf[da + i] = td_ibuf[i + 2]; + td_offset += td_olen; + td_txsize -= td_olen; + da = da + td_olen; + if (da > uptr->hwmark) /* update hwmark */ + uptr->hwmark = da; + if (td_txsize > 0) + td_state = TD_WRITE1; + else { /* check whole number of blocks written */ + if (td_olen = (512 - (td_offset % 512)) != 512) { + for (i = 0; i < td_olen; i++) + fbuf[da + i] = 0; /* zero fill */ + da = da + td_olen; + if (da > uptr->hwmark) /* update hwmark */ + uptr->hwmark = da; + } + td_state = TD_END; + } + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_END: /* build end packet */ + td_obptr = 0; + td_obuf[td_obptr++] = TD_OPCMD; /* Command packet */ + td_obuf[td_obptr++] = 0xA; /* ** Need definition ** */ + td_obuf[td_obptr++] = TD_CMDEND; + td_obuf[td_obptr++] = td_ecode; /* Success code */ + td_obuf[td_obptr++] = 0; /* Unit number */ + td_obuf[td_obptr++] = 0; /* Not used */ + td_obuf[td_obptr++] = 0; /* Sequence L (not used) */ + td_obuf[td_obptr++] = 0; /* Sequence H (not used) */ + td_obuf[td_obptr++] = (td_offset & 0xFF); /* Byte count L */ + td_obuf[td_obptr++] = ((td_offset >> 8) & 0xFF);/* Byte count H */ + td_obuf[td_obptr++] = 0; /* Summary status L */ + td_obuf[td_obptr++] = 0; /* Summary status H */ + c = 0; + for (i = 0; i < (0xA + 2); i++) { /* Calculate checksum */ + w = (td_obuf[i] << ((i & 0x1) ? 8 : 0)); + c = c + w + ( (uint32)((uint32)c + (uint32)w) > 0xFFFF ? 1 : 0); + } + td_obuf[td_obptr++] = c & 0xFF; /* Checksum L */ + td_obuf[td_obptr++] = (c >> 8) & 0xFF; /* Checksum H */ + td_olen = td_obptr; + td_obptr = 0; + td_state = TD_END1; /* go empty */ + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_END1: /* send end packet to host */ + if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ + csi_buf = td_obuf[td_obptr++]; /* get next byte */ + csi_csr = csi_csr | CSR_DONE; /* set input flag */ + if (csi_csr & CSR_IE) + csi_int = 1; + if (td_obptr >= td_olen) { /* buffer empty? */ + td_state = TD_IDLE; + break; + } + } + sim_activate (uptr, td_xwait); /* schedule next */ + break; + + case TD_INIT: + if ((csi_csr & CSR_DONE) == 0) { /* prev data taken? */ + csi_buf = TD_OPCNT; + csi_csr = csi_csr | CSR_DONE; /* set input flag */ + if (csi_csr & CSR_IE) + csi_int = 1; + td_state = TD_IDLE; + break; + } + sim_activate (uptr, td_xwait); /* schedule next */ + break; + } +return SCPE_OK; +} + +/* Test for data transfer okay */ + +t_bool td_test_xfr (UNIT *uptr, int32 state) +{ +if ((uptr->flags & UNIT_BUF) == 0) /* not buffered? */ + td_ecode = TD_STSNC; +else if (td_block >= TD_NUMBLK) /* bad block? */ + td_ecode = TD_STSBBN; +else if ((state == TD_WRITE) && (uptr->flags & UNIT_WPRT)) /* write and locked? */ + td_ecode = TD_STSWP; +else { + td_ecode = TD_STSOK; + return TRUE; + } +return FALSE; +} + +/* Reset */ + +t_stat td_reset (DEVICE *dptr) +{ +cso_buf = 0; +cso_csr = CSR_DONE; +cso_int = 0; +cso_state = TD_GETOPC; +td_ibptr = 0; +td_obptr = 0; +td_olen = 0; +td_offset = 0; +td_txsize = 0; +sim_cancel (&td_unit); +return SCPE_OK; +} diff --git a/VAX/vax750_syslist.c b/VAX/vax750_syslist.c new file mode 100644 index 00000000..b339104b --- /dev/null +++ b/VAX/vax750_syslist.c @@ -0,0 +1,125 @@ +/* vax750_syslist.c: VAX 11/750 device list + + Copyright (c) 2010-2012, Matt Burke + This module incorporates code from SimH, Copyright (c) 1998-2008, 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 + THE AUTHOR(S) 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(s) of the author(s) shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author(s). + + 21-Oct-2012 MB First Version +*/ + +#include "vax_defs.h" + +char sim_name[] = "VAX750"; + +extern DEVICE cpu_dev; +extern DEVICE tlb_dev; +extern DEVICE cmi_dev; +extern DEVICE mctl_dev; +extern DEVICE uba_dev; +extern DEVICE mba_dev[MBA_NUM]; +extern DEVICE clk_dev; +extern DEVICE tmr_dev; +extern DEVICE tti_dev, tto_dev; +extern DEVICE td_dev; +extern DEVICE cr_dev; +extern DEVICE lpt_dev; +extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; +extern DEVICE rl_dev; +extern DEVICE hk_dev; +extern DEVICE rp_dev; +extern DEVICE ry_dev; +extern DEVICE ts_dev; +extern DEVICE tq_dev; +extern DEVICE tu_dev; +extern DEVICE dz_dev; +extern DEVICE xu_dev, xub_dev; + +extern int32 sim_switches; +extern UNIT cpu_unit; +extern void WriteB (uint32 pa, int32 val); + +DEVICE *sim_devices[] = { + &cpu_dev, + &tlb_dev, + &cmi_dev, + &mctl_dev, + &uba_dev, + &mba_dev[0], + &mba_dev[1], + &clk_dev, + &tmr_dev, + &tti_dev, + &tto_dev, + &td_dev, + &dz_dev, + &cr_dev, + &lpt_dev, + &rp_dev, + &rl_dev, + &hk_dev, + &rq_dev, + &rqb_dev, + &rqc_dev, + &rqd_dev, + &ry_dev, + &tu_dev, + &ts_dev, + &tq_dev, + &xu_dev, + &xub_dev, + NULL + }; + +/* Binary loader + + The binary loader handles absolute system images, that is, system + images linked /SYSTEM. These are simply a byte stream, with no + origin or relocation information. + + -o for memory, specify origin +*/ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +t_stat r; +int32 val; +uint32 origin, limit; + +if (flag) /* dump? */ + return SCPE_ARG; +origin = 0; /* memory */ +limit = (uint32) cpu_unit.capac; +if (sim_switches & SWMASK ('O')) { /* origin? */ + origin = (int32) get_uint (cptr, 16, 0xFFFFFFFF, &r); + if (r != SCPE_OK) + return SCPE_ARG; + } + +while ((val = getc (fileref)) != EOF) { /* read byte stream */ + if (origin >= limit) /* NXM? */ + return SCPE_NXM; + WriteB (origin, val); /* memory */ + origin = origin + 1; + } +return SCPE_OK; +} diff --git a/VAX/vax750_uba.c b/VAX/vax750_uba.c new file mode 100644 index 00000000..c915c094 --- /dev/null +++ b/VAX/vax750_uba.c @@ -0,0 +1,687 @@ +/* vax750_uba.c: VAX 11/750 Unibus adapter + + Copyright (c) 2010-2011, Matt Burke + This module incorporates code from SimH, Copyright (c) 2004-2008, 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 + THE AUTHOR(S) 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(s) of the author(s) shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author(s). + + uba DW750 Unibus adapter + + 21-Oct-2012 MB First Version +*/ + +#include "vax_defs.h" + +/* Unibus adapter */ + +#define UBA_NDPATH 16 /* number of data paths */ +#define UBA_NMAPR 496 /* number of map reg */ + +/* Unibus adapter configuration register */ + +#define UBACNF_OF 0x00 +#define UBACNF_CODE 0x00000028 /* adapter code */ + +/* Control/Status registers */ + +#define UBACSR1_OF 0x01 +#define UBACSR2_OF 0x02 +#define UBACSR3_OF 0x03 +#define UBACSR_PUR 0x00000001 /* Purge request */ +#define UBACSR_UCE 0x20000000 /* Uncorrectable err */ +#define UBACSR_NXM 0x40000000 /* NXM */ +#define UBACSR_ERR 0x80000000 /* Error flag */ +#define UBACSR_RD (UBACSR_PUR | UBACSR_UCE | UBACSR_NXM | \ + UBACSR_ERR) +#define UBACSR_WR 0 + +/* Map registers */ + +#define UBAMAP_OF 0x200 +#define UBAMAP_VLD 0x80000000 /* valid */ +#define UBAMAP_LWAE 0x04000000 /* LW access enb - ni */ +#define UBAMAP_ODD 0x02000000 /* odd byte */ +#define UBAMAP_V_DP 21 /* data path */ +#define UBAMAP_M_DP 0xF +#define UBAMAP_DP (UBAMAP_M_DP << UBAMAP_V_DP) +#define UBAMAP_GETDP(x) (((x) >> UBAMAP_V_DP) & UBAMAP_M_DP) +#define UBAMAP_PAG 0x001FFFFF +#define UBAMAP_RD (0x86000000 | UBAMAP_DP | UBAMAP_PAG) +#define UBAMAP_WR (UBAMAP_RD) + +/* Debug switches */ + +#define UBA_DEB_RRD 0x01 /* reg reads */ +#define UBA_DEB_RWR 0x02 /* reg writes */ +#define UBA_DEB_MRD 0x04 /* map reads */ +#define UBA_DEB_MWR 0x08 /* map writes */ +#define UBA_DEB_XFR 0x10 /* transfers */ +#define UBA_DEB_ERR 0x20 /* errors */ + +int32 int_req[IPL_HLVL] = { 0 }; /* intr, IPL 14-17 */ +uint32 uba_csr1 = 0; /* csr reg 1 */ +uint32 uba_csr2 = 0; /* csr reg 2 */ +uint32 uba_csr3 = 0; /* csr reg 3 */ +uint32 uba_int = 0; /* UBA interrupt */ +uint32 uba_map[UBA_NMAPR] = { 0 }; /* map registers */ +int32 autcon_enb = 1; /* autoconfig enable */ + +extern int32 trpirq; +extern int32 autcon_enb; +extern jmp_buf save_env; +extern DEVICE *sim_devices[]; +extern UNIT cpu_unit; +extern uint32 nexus_req[NEXUS_HLVL]; +extern int32 sim_switches; +extern FILE *sim_log, *sim_deb; +extern int32 p1; +extern int32 fault_PC; /* fault PC */ +extern int32 mem_err; + +t_stat uba_reset (DEVICE *dptr); +t_stat uba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw); +t_stat uba_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw); +t_stat uba_rdreg (int32 *val, int32 pa, int32 mode); +t_stat uba_wrreg (int32 val, int32 pa, int32 lnt); +int32 uba_get_ubvector (int32 lvl); +void uba_eval_int (void); +void uba_ioreset (void); +t_bool uba_map_addr (uint32 ua, uint32 *ma); +t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat uba_show_virt (FILE *st, UNIT *uptr, int32 val, void *desc); + +extern int32 eval_int (void); +extern t_stat build_dib_tab (void); +extern void cmi_set_tmo (void); + +/* Unibus IO page dispatches */ + +t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); +t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); + +/* Unibus interrupt request to interrupt action map */ + +int32 (*int_ack[IPL_HLVL][32])(); /* int ack routines */ + +/* Unibus interrupt request to vector map */ + +int32 int_vec[IPL_HLVL][32]; /* int req to vector */ + +/* Unibus adapter data structures + + uba_dev UBA device descriptor + uba_unit UBA units + uba_reg UBA register list +*/ + +DIB uba_dib = { TR_UBA, 0, &uba_rdreg, &uba_wrreg, 0, 0 }; + +UNIT uba_unit = { UDATA (0, 0, 0) }; + +REG uba_reg[] = { + { HRDATA (IPL14, int_req[0], 32), REG_RO }, + { HRDATA (IPL15, int_req[1], 32), REG_RO }, + { HRDATA (IPL16, int_req[2], 32), REG_RO }, + { HRDATA (IPL17, int_req[3], 32), REG_RO }, + { HRDATA (CSR1, uba_csr1, 32) }, + { HRDATA (CSR2, uba_csr2, 32) }, + { HRDATA (CSR3, uba_csr3, 32) }, + { FLDATA (INT, uba_int, 0) }, + { FLDATA (NEXINT, nexus_req[IPL_UBA], TR_UBA) }, + { BRDATA (MAP, uba_map, 16, 32, 496) }, + { FLDATA (AUTOCON, autcon_enb, 0), REG_HRO }, + { NULL } + }; + +MTAB uba_mod[] = { + { MTAB_XTD|MTAB_VDV, TR_UBA, "NEXUS", NULL, + NULL, &show_nexus }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, + NULL, &show_iospace }, + { MTAB_XTD|MTAB_VDV, 1, "AUTOCONFIG", "AUTOCONFIG", + &set_autocon, &show_autocon }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG", + &set_autocon, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL, + NULL, &uba_show_virt }, + { 0 } + }; + +DEBTAB uba_deb[] = { + { "REGREAD", UBA_DEB_RRD }, + { "REGWRITE", UBA_DEB_RWR }, + { "MAPREAD", UBA_DEB_MRD }, + { "MAPWRITE", UBA_DEB_MWR }, + { "XFER", UBA_DEB_XFR }, + { "ERROR", UBA_DEB_ERR }, + { NULL, 0 } + }; + +DEVICE uba_dev = { + "UBA", &uba_unit, uba_reg, uba_mod, + 1, 16, UBADDRWIDTH, 2, 16, 16, + &uba_ex, &uba_dep, &uba_reset, + NULL, NULL, NULL, + &uba_dib, DEV_NEXUS | DEV_DEBUG, 0, + uba_deb, 0, 0 + }; + +/* Read Unibus adapter register - aligned lw only */ + +t_stat uba_rdreg (int32 *val, int32 pa, int32 lnt) +{ +int32 idx, ofs; + +if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ + printf (">>UBA: invalid adapter read mask, pa = %X, lnt = %d\r\n", pa, lnt); + /* FIXME: set appropriate error bits */ + return SCPE_OK; + } +ofs = NEXUS_GETOFS (pa); /* get offset */ +if (ofs >= UBAMAP_OF) { /* map? */ + idx = ofs - UBAMAP_OF; + if (idx >= UBA_NMAPR) /* valid? */ + return SCPE_NXM; + *val = uba_map[idx] & UBAMAP_RD; + if (DEBUG_PRI (uba_dev, UBA_DEB_MRD)) + fprintf (sim_deb, ">>UBA: map %d read, value = %X at PC = %08X\n", idx, *val, fault_PC); + return SCPE_OK; + } + +switch (ofs) { /* case on offset */ + + case UBACNF_OF: /* Config Reg */ + *val = UBACNF_CODE; + break; + + case UBACSR1_OF: /* CSR1 */ + *val = (uba_csr1 & UBACSR_RD); + break; + + case UBACSR2_OF: /* CSR2 */ + *val = (uba_csr2 & UBACSR_RD); + break; + + case UBACSR3_OF: /* CSR3 */ + *val = (uba_csr3 & UBACSR_RD); + break; + + default: + return SCPE_NXM; + } + +if (DEBUG_PRI (uba_dev, UBA_DEB_RRD)) + fprintf (sim_deb, ">>UBA: reg %d read, value = %X at PC = %08X\n", ofs, *val, fault_PC); +return SCPE_OK; +} + +/* Write Unibus adapter register */ + +t_stat uba_wrreg (int32 val, int32 pa, int32 lnt) +{ +int32 idx, ofs; + +if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ + printf (">>UBA: invalid adapter write mask, pa = %X, lnt = %d\r\n", pa, lnt); + /* FIXME: set appropriate error bits */ + return SCPE_OK; + } +ofs = NEXUS_GETOFS (pa); /* get offset */ +if (ofs >= UBAMAP_OF) { /* map? */ + idx = ofs - UBAMAP_OF; + if (idx >= UBA_NMAPR) /* valid? */ + return SCPE_NXM; + uba_map[idx] = val & UBAMAP_WR; + if (DEBUG_PRI (uba_dev, UBA_DEB_MWR)) + fprintf (sim_deb, ">>UBA: map %d write, value = %X at PC = %08X\n", idx, val, fault_PC); + return SCPE_OK; + } + +switch (ofs) { /* case on offset */ + + case UBACNF_OF: /* Config Reg */ + break; + + case UBACSR1_OF: /* CSR1 */ + uba_csr1 = (val & UBACSR_WR); + break; + + case UBACSR2_OF: /* CSR2 */ + uba_csr2 = (val & UBACSR_WR); + break; + + case UBACSR3_OF: /* CSR3 */ + uba_csr3 = (val & UBACSR_WR); + break; + + default: + return SCPE_NXM; + break; + } + +if (DEBUG_PRI (uba_dev, UBA_DEB_RWR)) + fprintf (sim_deb, ">>UBA: reg %d write, value = %X at PC = %08X\n", ofs, val, fault_PC); +return SCPE_OK; +} + +/* Read and write Unibus I/O space */ + +int32 ReadUb (uint32 pa) +{ +int32 idx, val; + +if (ADDR_IS_IOP (pa)) { /* iopage,!init */ + idx = (pa & IOPAGEMASK) >> 1; + if (iodispR[idx]) { + iodispR[idx] (&val, pa, READ); + return val; + } + } +cmi_set_tmo(); +MACH_CHECK(MCHK_BPE); +return 0; +} + +void WriteUb (uint32 pa, int32 val, int32 mode) +{ +int32 idx; + +if (ADDR_IS_IOP (pa)) { /* iopage,!init */ + idx = (pa & IOPAGEMASK) >> 1; + if (iodispW[idx]) { + iodispW[idx] (val, pa, mode); + return; + } + } +cmi_set_tmo(); +mem_err = 1; /* interrupt */ +SET_IRQL; +return; +} + +/* ReadIO - read from IO - UBA only responds to byte, aligned word + + Inputs: + pa = physical address + lnt = length (BWLQ) + Output: + longword of data +*/ + +int32 ReadIO (uint32 pa, int32 lnt) +{ +uint32 iod; + +if ((lnt == L_BYTE) || /* byte? */ + ((lnt == L_WORD) && ((pa & 1) == 0))) { /* aligned word? */ + iod = ReadUb (pa); /* DATI from Unibus */ + if (pa & 2) /* position */ + iod = iod << 16; + } +else { + printf (">>UBA: invalid read mask, pa = %x, lnt = %d\n", pa, lnt); + /* FIXME: set appropriate error bits */ + iod = 0; + } +SET_IRQL; +return iod; +} + +/* WriteIO - write to IO - UBA only responds to byte, aligned word + + Inputs: + pa = physical address + val = data to write, right justified in 32b longword + lnt = length (BWL) + Outputs: + none +*/ + +void WriteIO (uint32 pa, int32 val, int32 lnt) +{ +if (lnt == L_BYTE) /* byte? DATOB */ + WriteUb (pa, val, WRITEB); +else if ((lnt == L_WORD) && ((pa & 1) == 0)) /* aligned word? */ + WriteUb (pa, val, WRITE); /* DATO */ +else { + printf (">>UBA: invalid write mask, pa = %x, lnt = %d\n", pa, lnt); + /* FIXME: set appropriate error bits */ + } +SET_IRQL; /* update ints */ +return; +} + +/* Update UBA nexus interrupts */ + +void uba_eval_int (void) +{ +int32 i; + +for (i = 0; i < (IPL_HMAX - IPL_HMIN); i++) /* clear all UBA req */ + nexus_req[i] &= ~(1 << TR_UBA); +for (i = 0; i < (IPL_HMAX - IPL_HMIN); i++) { + if (int_req[i]) + nexus_req[i] |= (1 << TR_UBA); + } +if (uba_int) /* adapter int? */ + SET_NEXUS_INT (UBA); +return; +} + +/* Return vector for Unibus interrupt at relative IPL level [0-3] */ + +int32 uba_get_ubvector (int32 lvl) +{ +int32 i, vec; + +vec = 0; +if ((lvl == (IPL_UBA - IPL_HMIN)) && uba_int) { /* UBA lvl, int? */ + uba_int = 0; /* clear int */ + } +for (i = 0; int_req[lvl] && (i < 32); i++) { + if ((int_req[lvl] >> i) & 1) { + int_req[lvl] = int_req[lvl] & ~(1u << i); + if (int_ack[lvl][i]) + return (vec | int_ack[lvl][i]()); + return (vec | int_vec[lvl][i]); + } + } +return vec; +} + +/* Unibus I/O buffer routines + + Map_ReadB - fetch byte buffer from memory + Map_ReadW - fetch word buffer from memory + Map_WriteB - store byte buffer into memory + Map_WriteW - store word buffer into memory +*/ + +int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf) +{ +int32 i, j, pbc; +uint32 ma, dat; + +ba = ba & UBADDRMASK; /* mask UB addr */ +for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ + if (!uba_map_addr (ba + i, &ma)) /* page inv or NXM? */ + return (bc - i); + pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */ + if (pbc > (bc - i)) /* limit to rem xfr */ + pbc = bc - i; + if (DEBUG_PRI (uba_dev, UBA_DEB_XFR)) + fprintf (sim_deb, ">>UBA: 8b read, ma = %X, bc = %X\n", ma, pbc); + if ((ma | pbc) & 3) { /* aligned LW? */ + for (j = 0; j < pbc; ma++, j++) { /* no, do by bytes */ + *buf++ = ReadB (ma); + } + } + else { /* yes, do by LW */ + for (j = 0; j < pbc; ma = ma + 4, j = j + 4) { + dat = ReadL (ma); /* get lw */ + *buf++ = dat & BMASK; /* low 8b */ + *buf++ = (dat >> 8) & BMASK; /* next 8b */ + *buf++ = (dat >> 16) & BMASK; /* next 8b */ + *buf++ = (dat >> 24) & BMASK; + } + } + } +return 0; +} + +int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf) +{ +int32 i, j, pbc; +uint32 ma, dat; + +ba = ba & UBADDRMASK; /* mask UB addr */ +bc = bc & ~01; +for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ + if (!uba_map_addr (ba + i, &ma)) /* page inv or NXM? */ + return (bc - i); + pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */ + if (pbc > (bc - i)) /* limit to rem xfr */ + pbc = bc - i; + if (DEBUG_PRI (uba_dev, UBA_DEB_XFR)) + fprintf (sim_deb, ">>UBA: 16b read, ma = %X, bc = %X\n", ma, pbc); + if ((ma | pbc) & 1) { /* aligned word? */ + for (j = 0; j < pbc; ma++, j++) { /* no, do by bytes */ + if ((i + j) & 1) { /* odd byte? */ + *buf = (*buf & BMASK) | (ReadB (ma) << 8); + buf++; + } + else *buf = (*buf & ~BMASK) | ReadB (ma); + } + } + else if ((ma | pbc) & 3) { /* aligned LW? */ + for (j = 0; j < pbc; ma = ma + 2, j = j + 2) { /* no, words */ + *buf++ = ReadW (ma); /* get word */ + } + } + else { /* yes, do by LW */ + for (j = 0; j < pbc; ma = ma + 4, j = j + 4) { + dat = ReadL (ma); /* get lw */ + *buf++ = dat & WMASK; /* low 16b */ + *buf++ = (dat >> 16) & WMASK; /* high 16b */ + } + } + } +return 0; +} + +int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf) +{ +int32 i, j, pbc; +uint32 ma, dat; + +ba = ba & UBADDRMASK; /* mask UB addr */ +for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ + if (!uba_map_addr (ba + i, &ma)) /* page inv or NXM? */ + return (bc - i); + pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */ + if (pbc > (bc - i)) /* limit to rem xfr */ + pbc = bc - i; + if (DEBUG_PRI (uba_dev, UBA_DEB_XFR)) + fprintf (sim_deb, ">>UBA: 8b write, ma = %X, bc = %X\n", ma, pbc); + if ((ma | pbc) & 3) { /* aligned LW? */ + for (j = 0; j < pbc; ma++, j++) { /* no, do by bytes */ + WriteB (ma, *buf); + buf++; + } + } + else { /* yes, do by LW */ + for (j = 0; j < pbc; ma = ma + 4, j = j + 4) { + dat = (uint32) *buf++; /* get low 8b */ + dat = dat | (((uint32) *buf++) << 8); /* merge next 8b */ + dat = dat | (((uint32) *buf++) << 16); /* merge next 8b */ + dat = dat | (((uint32) *buf++) << 24); /* merge hi 8b */ + WriteL (ma, dat); /* store lw */ + } + } + } +return 0; +} + +int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf) +{ +int32 i, j, pbc; +uint32 ma, dat; + +ba = ba & UBADDRMASK; /* mask UB addr */ +bc = bc & ~01; +for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ + if (!uba_map_addr (ba + i, &ma)) /* page inv or NXM? */ + return (bc - i); + pbc = VA_PAGSIZE - VA_GETOFF (ma); /* left in page */ + if (pbc > (bc - i)) /* limit to rem xfr */ + pbc = bc - i; + if (DEBUG_PRI (uba_dev, UBA_DEB_XFR)) + fprintf (sim_deb, ">>UBA: 16b write, ma = %X, bc = %X\n", ma, pbc); + if ((ma | pbc) & 1) { /* aligned word? */ + for (j = 0; j < pbc; ma++, j++) { /* no, bytes */ + if ((i + j) & 1) { + WriteB (ma, (*buf >> 8) & BMASK); + buf++; + } + else WriteB (ma, *buf & BMASK); + } + } + else if ((ma | pbc) & 3) { /* aligned LW? */ + for (j = 0; j < pbc; ma = ma + 2, j = j + 2) { /* no, words */ + WriteW (ma, *buf); /* write word */ + buf++; + } + } + else { /* yes, do by LW */ + for (j = 0; j < pbc; ma = ma + 4, j = j + 4) { + dat = (uint32) *buf++; /* get low 16b */ + dat = dat | (((uint32) *buf++) << 16); /* merge hi 16b */ + WriteL (ma, dat); /* store LW */ + } + } + } +return 0; +} + +/* Map an address via the translation map */ + +t_bool uba_map_addr (uint32 ua, uint32 *ma) +{ +uint32 ublk, umap; + +ublk = ua >> VA_V_VPN; /* Unibus blk */ +if (ublk >= UBA_NMAPR) /* unimplemented? */ + return FALSE; +umap = uba_map[ublk]; /* get map */ +if (umap & UBAMAP_VLD) { /* valid? */ + *ma = ((umap & UBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (ua); + if ((umap & UBAMAP_DP) && (umap & UBAMAP_ODD)) /* buffered dp? */ + *ma = *ma + 1; /* byte offset? */ + return (ADDR_IS_MEM (*ma)); /* legit addr */ + } +return FALSE; +} + +/* Map an address via the translation map - console version (no status changes) */ + +t_bool uba_map_addr_c (uint32 ua, uint32 *ma) +{ +uint32 ublk, umap; + +ublk = ua >> VA_V_VPN; /* Unibus blk */ +if (ublk >= UBA_NMAPR) /* unimplemented? */ + return FALSE; +umap = uba_map[ublk]; /* get map */ +if (umap & UBAMAP_VLD) { /* valid? */ + *ma = ((umap & UBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (ua); + if ((umap & UBAMAP_DP) && (umap & UBAMAP_ODD)) /* buffered dp? */ + *ma = *ma + 1; /* byte offset? */ + return TRUE; /* legit addr */ + } +return FALSE; +} + +/* Reset Unibus devices */ + +void uba_ioreset (void) +{ +int32 i; +DEVICE *dptr; + +for (i = 0; sim_devices[i] != NULL; i++) { /* reset Unibus */ + dptr = sim_devices[i]; + if (dptr->reset && (dptr->flags & DEV_UBUS)) + dptr->reset (dptr); + } +return; +} + +/* Reset Unibus adapter */ + +t_stat uba_reset (DEVICE *dptr) +{ +int32 i; + +for (i = 0; i < IPL_HLVL; i++) { + nexus_req[i] &= ~(1 << TR_UBA); + int_req[i] = 0; + } +for (i = 0; i < UBA_NMAPR; i++) + uba_map[i] = 0; +uba_csr1 = 0; +uba_csr2 = 0; +uba_csr3 = 0; +return SCPE_OK; +} + +/* Memory examine via map (word only) */ + +t_stat uba_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw) +{ +uint32 ua = (uint32) exta, pa; + +if ((vptr == NULL) || (ua >= UBADDRSIZE)) + return SCPE_ARG; +if (uba_map_addr_c (ua, &pa) && ADDR_IS_MEM (pa)) { + *vptr = (uint32) ReadW (pa); + return SCPE_OK; + } +return SCPE_NXM; +} + +/* Memory deposit via map (word only) */ + +t_stat uba_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw) +{ +uint32 ua = (uint32) exta, pa; + +if (ua >= UBADDRSIZE) + return SCPE_ARG; +if (uba_map_addr_c (ua, &pa) && ADDR_IS_MEM (pa)) { + WriteW (pa, (int32) val); + return SCPE_OK; + } +return SCPE_NXM; +} + +/* Show UBA virtual address */ + +t_stat uba_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_stat r; +char *cptr = (char *) desc; +uint32 ua, pa; + +if (cptr) { + ua = (uint32) get_uint (cptr, 16, UBADDRSIZE - 1, &r); + if (r == SCPE_OK) { + if (uba_map_addr_c (ua, &pa)) + fprintf (of, "Unibus %-X = physical %-X\n", ua, pa); + else fprintf (of, "Unibus %-X: invalid mapping\n", ua); + return SCPE_OK; + } + } +fprintf (of, "Invalid argument\n"); +return SCPE_OK; +} diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index b1308753..274bce9f 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -150,6 +150,12 @@ #define INITMEMSIZE (1 << MAXMEMWIDTH) /* initial memory size */ #define MEMSIZE (cpu_unit.capac) #define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) +#define MEM_MODIFIERS { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 25) + (1u << 24), NULL, "48M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 27), NULL, "128M", &cpu_set_size } /* Unibus I/O registers */ diff --git a/VAX/vax780_mba.c b/VAX/vax7x0_mba.c similarity index 96% rename from VAX/vax780_mba.c rename to VAX/vax7x0_mba.c index afe264c4..14aa9966 100644 --- a/VAX/vax780_mba.c +++ b/VAX/vax7x0_mba.c @@ -1,4 +1,4 @@ -/* vax780_mba.c: VAX 11/780 Massbus adapter +/* vax7x0_mba.c: VAX 11/780 snf VAX 11/750 Massbus adapter Copyright (c) 2004-2008, Robert M Supnik @@ -272,7 +272,9 @@ t_stat r; mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */ if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ printf (">>MBA%d: invalid adapter read mask, pa = %X, lnt = %d\r\n", mb, pa, lnt); +#if defined(VAX_780) sbi_set_errcnf (); /* err confirmation */ +#endif return SCPE_OK; } if (mb >= MBA_NUM) /* valid? */ @@ -365,7 +367,9 @@ t_bool cs1dt; mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */ if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ printf (">>MBA%d: invalid adapter write mask, pa = %X, lnt = %d\r\n", mb, pa, lnt); +#if defined(VAX_780) sbi_set_errcnf (); /* err confirmation */ +#endif return SCPE_OK; } if (mb >= MBA_NUM) /* valid? */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 7009a386..9730cf0e 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -473,21 +473,7 @@ MTAB cpu_mod[] = { { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &cpu_set_idle, &cpu_show_idle }, { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, -#if defined (VAX_730) - { UNIT_MSIZE, (1u << 20), NULL, "1M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 21), NULL, "2M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 22), NULL, "4M", &cpu_set_size }, -#endif - { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 25) + (1u << 24), NULL, "48M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 27), NULL, "128M", &cpu_set_size }, -#if !defined (VAX_780) - { UNIT_MSIZE, (1u << 28), NULL, "256M", &cpu_set_size }, - { UNIT_MSIZE, (1u << 29), NULL, "512M", &cpu_set_size }, -#endif + MEM_MODIFIERS, /* Model specific memory modifiers from vaxXXX_defs.h */ { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL, diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index 64e8ec33..ba73fc4a 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -721,6 +721,8 @@ enum opcodes { #if defined (VAX_780) #include "vax780_defs.h" +#elif defined (VAX_750) +#include "vax750_defs.h" #elif defined (VAX_730) #include "vax730_defs.h" #else diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 85e9459d..e0c06198 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -117,6 +117,15 @@ #define INITMEMSIZE (1 << 24) /* initial memory size */ #define MEMSIZE (cpu_unit.capac) #define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE) +#define MEM_MODIFIERS { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 25) + (1u << 24), NULL, "48M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 27), NULL, "128M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 28), NULL, "256M", &cpu_set_size }, \ + { UNIT_MSIZE, (1u << 29), NULL, "512M", &cpu_set_size } + /* Cache diagnostic space */ diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index 6e5f1d82..fc14324e 100644 --- a/Visual Studio Projects/Simh.sln +++ b/Visual Studio Projects/Simh.sln @@ -70,6 +70,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX730", "VAX730.vcproj", " {D40F3AF1-EEE7-4432-9807-2AD287B490F8} = {D40F3AF1-EEE7-4432-9807-2AD287B490F8} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX750", "VAX750.vcproj", "{43A9CF64-5705-4FB7-B837-ED9AAFF97DAC}" + ProjectSection(ProjectDependencies) = postProject + {D40F3AF1-EEE7-4432-9807-2AD287B490F8} = {D40F3AF1-EEE7-4432-9807-2AD287B490F8} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -196,6 +201,10 @@ Global {C526F7F2-9476-44BC-B1E9-9522B693BEA7}.Debug|Win32.Build.0 = Debug|Win32 {C526F7F2-9476-44BC-B1E9-9522B693BEA7}.Release|Win32.ActiveCfg = Release|Win32 {C526F7F2-9476-44BC-B1E9-9522B693BEA7}.Release|Win32.Build.0 = Release|Win32 + {43A9CF64-5705-4FB7-B837-ED9AAFF97DAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {43A9CF64-5705-4FB7-B837-ED9AAFF97DAC}.Debug|Win32.Build.0 = Debug|Win32 + {43A9CF64-5705-4FB7-B837-ED9AAFF97DAC}.Release|Win32.ActiveCfg = Release|Win32 + {43A9CF64-5705-4FB7-B837-ED9AAFF97DAC}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Visual Studio Projects/VAX730.vcproj b/Visual Studio Projects/VAX730.vcproj index 8f806715..f82b08cb 100644 --- a/Visual Studio Projects/VAX730.vcproj +++ b/Visual Studio Projects/VAX730.vcproj @@ -428,17 +428,13 @@ > - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index a2425a5f..09051630 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -314,10 +314,6 @@ RelativePath="..\VAX\vax780_fload.c" > - - @@ -338,6 +334,10 @@ RelativePath="..\VAX\vax780_uba.c" > + + @@ -451,10 +451,6 @@ RelativePath="..\VAX\vax_defs.h" > - -