diff --git a/VAX/vax730_defs.h b/VAX/vax730_defs.h new file mode 100644 index 00000000..961bcb34 --- /dev/null +++ b/VAX/vax730_defs.h @@ -0,0 +1,400 @@ +/* vax730_defs.h: VAX 730 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). + + 29-Mar-2011 MB First Version + + This file covers the VAX 11/730, the third VAX. + + System memory map + + 00 0000 - EF FFFF main memory + F0 0000 - F1 FFFF reserved + F2 0000 - F3 FFFF nexus register space + F4 0000 - FB FFFF reserved + FC 0000 - FF FFFF Unibus address space +*/ + +#ifndef FULL_VAX +#define FULL_VAX 1 +#endif + +#ifndef _VAX_730_DEFS_H_ +#define _VAX_730_DEFS_H_ 1 + +/* Microcode constructs */ + +#define VAX730_SID (3 << 24) /* system ID */ +#define VAX730_MICRO (123 << 8) /* ucode revision */ +#define CON_HLTPIN 0x0200 /* external CPU halt */ +#define CON_HLTINS 0x0600 /* HALT instruction */ +#define MCHK_NXM 0x08 /* NXM */ +#define MCHK_IIA 0x0A /* illegal i/o addr */ +#define MCHK_IUA 0x0B /* illegal unibus addr */ + +/* 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 TR_MCTL 0 /* nexus assignments */ +#define TR_UBA 3 +#define NEXUS_HLVL (IPL_HMAX - IPL_HMIN + 1) +#define SCB_NEXUS 0x100 /* nexus intr base */ + +/* Internal I/O interrupts - relative except for clock and console */ + +#define IPL_CLKINT 0x18 /* clock IPL */ +#define IPL_TTINT 0x14 /* console IPL */ +#define IPL_CSINT 0x14 /* console storage IPL */ +#define IPL_UBA (0x15 - IPL_HMIN) + +/* Machine specific IPRs */ + +#define MT_CSRS 28 /* Console storage */ +#define MT_CSRD 29 +#define MT_CSTS 30 +#define MT_CSTD 31 +#define MT_CDR 37 /* Cache disable */ +#define MT_MCESR 38 /* MCHK err sts */ +#define MT_ACCS 40 /* FPA control */ +#define MT_ACCR 41 /* FPA maint */ +#define MT_SBIFS 48 /* SBI fault status */ +#define MT_SBIS 49 /* SBI silo */ +#define MT_SBISC 50 /* SBI silo comparator */ +#define MT_SBIMT 51 /* SBI maint */ +#define MT_SBIER 52 /* SBI error */ +#define MT_SBITA 53 /* SBI timeout addr */ +#define MT_SBIQC 54 /* SBI timeout clear */ +#define MT_UBINIT 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 and xBR<1:0> = 0 */ + +#define ML_PXBR_TEST(r) if ((((r) & 0x80000000) == 0) || \ + ((r) & 0x00000003)) RSVD_OPND_FAULT +#define ML_SBR_TEST(r) if ((r) & 0x00000003) RSVD_OPND_FAULT + +/* 780 microcode patch 78 - only test xCBB<1:0> = 0 */ + +#define ML_PA_TEST(r) if ((r) & 0x00000003) RSVD_OPND_FAULT + +#define LP_AST_TEST(r) if ((r) > AST_MAX) RSVD_OPND_FAULT +#define LP_MBZ84_TEST(r) if ((r) & 0xF8C00000) RSVD_OPND_FAULT +#define LP_MBZ92_TEST(r) if ((r) & 0x7FC00000) 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) + +/* 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 UBAMAPWIDTH 11 /* Unibus map width */ +#define UBAMAPSIZE 0x7FC /* Unibus map length */ +#define UBADDRBASE 0xFC0000 /* Unibus addr base */ +#define IOPAGEBASE 0xFFE000 /* IO page base */ +#define UBAMAPBASE 0xF26800 /* Unibus map base */ +#define ADDR_IS_IO(x) ((((uint32) (x)) >= UBADDRBASE) && \ + (((uint32) (x)) < (UBADDRBASE + UBADDRSIZE))) +#define ADDR_IS_IOP(x) (((uint32) (x)) >= IOPAGEBASE) +#define ADDR_IS_IOM(x) ((((uint32) (x)) >= UBAMAPBASE) && \ + (((uint32) (x)) < (UBAMAPBASE + UBAMAPSIZE))) + +/* 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 NEXUS_GETNEX(x) (((x) >> REG_V_NEXUS) & REG_M_NEXUS) +#define NEXUS_GETOFS(x) (((x) >> REG_V_OFS) & REG_M_OFS) + +/* Other address spaces */ + +#define ADDR_IS_ROM(x) (0) +#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_NEXUS (DEV_V_UF + 1) /* Nexus */ +#define DEV_V_FLTA (DEV_V_UF + 2) /* flt addr */ +#define DEV_V_FFUF (DEV_V_UF + 3) /* first free flag */ +#define DEV_UBUS (1u << DEV_V_UBUS) +#define DEV_NEXUS (1u << DEV_V_NEXUS) +#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 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 */ + +#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_RB (IOPAGEBASE + 015606) /* RB730 */ +#define IOLN_RB 002 +#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_RB 4 +#define INT_V_RQ 5 +#define INT_V_TQ 6 +#define INT_V_TS 7 +#define INT_V_RY 8 +#define INT_V_XU 9 + +#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_RB (1u << INT_V_RB) +#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_RB (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_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_RB (VEC_Q + 0250) +#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 */ + +/* Boot definitions */ + +#define BOOT_MB 0 /* device codes */ +#define BOOT_HK 1 /* for VMB */ +#define BOOT_RL 2 +#define BOOT_RB 3 +#define BOOT_UDA 17 +#define BOOT_TK 18 +#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); + +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/vax730_mem.c b/VAX/vax730_mem.c new file mode 100644 index 00000000..5c819203 --- /dev/null +++ b/VAX/vax730_mem.c @@ -0,0 +1,196 @@ +/* vax730_mem.c: VAX 11/730 memory adapter + + Copyright (c) 2010-2011, 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 + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of 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. + + This module contains the VAX 11/730 memory controller registers. + + mctl MS730 memory adapter + + 29-Mar-2011 MB First Version + +*/ + +#include "vax_defs.h" + +/* Memory adapter register 0 */ + +#define MCSR0_OF 0x00 +#define MCSR0_ES 0x0000007F /* Error syndrome */ +#define MCSR0_V_FPN 9 +#define MCSR0_M_FPN 0x7FFF +#define MCSR0_FPN (MCSR0_M_FPN << MCSR0_V_FPN) /* Failing page number */ + +/* Memory adapter register 1 */ + +#define MCSR1_OF 0x01 +#define MCSR1_RW 0x3E000000 +#define MCSR1_MBZ 0x01FFFF80 + +/* Memory adapter register 2 */ + +#define MCSR2_OF 0x02 +#define MCSR2_M_MAP 0xFFFF; +#define MCSR2_V_CS 24 +#define MCSR2_CS (1u << MCSR2_V_CS) +#define MCSR2_MBZ 0xFEFF0000 + +/* 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) + +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); + +/* MCTLx data structures + + mctlx_dev MCTLx device descriptor + mctlx_unit MCTLx unit + mctlx_reg MCTLx register list +*/ + +DIB mctl_dib[] = { TR_MCTL, 0, &mctl_rdreg, &mctl_wrreg, 0 }; + +UNIT mctl_unit = { UDATA (NULL, 0, 0) }; + +REG mctl_reg[] = { + { HRDATA (CSR0, mcsr0, 32) }, + { HRDATA (CSR1, mcsr1, 32) }, + { HRDATA (CSR2, mcsr2, 32) }, + { 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 & ~MCSR1_MBZ; + 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 */ + 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 and loader */ + +void rom_wr_B (int32 pa, int32 val) +{ +return; +} + +/* MEMCTL reset */ + +t_stat mctl_reset (DEVICE *dptr) +{ +mcsr0 = 0; +mcsr1 = 0; +mcsr2 = 0; +if (MEMSIZE > MAXMEMSIZE) /* More than 2MB? */ + mcsr2 = mcsr2 | MEM_BOARD_MASK(MEMSIZE, MEM_SIZE_64K) | MCSR2_CS; /* Use 64k chips */ +else + mcsr2 = mcsr2 | MEM_BOARD_MASK(MEMSIZE, MEM_SIZE_16K); /* Use 16k chips */ +return SCPE_OK; +} diff --git a/VAX/vax730_rb.c b/VAX/vax730_rb.c new file mode 100644 index 00000000..18aebbaf --- /dev/null +++ b/VAX/vax730_rb.c @@ -0,0 +1,670 @@ +/* vax730_rb.c: RB730 disk simulator + + Copyright (c) 2010-2011, Matt Burke + This module incorporates code from SimH, Copyright (c) 1993-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). + + rb RB730 - RB02/RB80 disk controller + + 29-Mar-2011 MB First Version + + The RB730 is a four drive disk subsystem consisting of up to three RL02 + drives (known as RB02) and one optional RA80 drive (known as RB80). + + Unlike the RL11 controller seeks are not done relative to the current + disk address. + + The RB730 has two regiter address spaces: + + - One dummy 16-bit register in unibus I/O space to allow the controller to + be detected by SYSGEN autoconfigure (and others). + - Eight 32-bit registers in the unibus controller space for the actual + device control. +*/ + +#include "vax_defs.h" + +/* Constants */ + +#define RB02_NUMWD 128 /* words/sector */ +#define RB02_NUMSC 40 /* sectors/track */ +#define RB02_NUMSF 2 /* tracks/cylinder */ +#define RB02_NUMCY 512 /* cylinders/drive */ +#define RB02_SIZE (RB02_NUMCY * RB02_NUMSF * \ + RB02_NUMSC * RB02_NUMWD) /* words/drive */ +#define RB80_NUMWD 256 /* words/sector */ +#define RB80_NUMSC 32 /* sectors/track */ +#define RB80_NUMSF 14 /* tracks/cylinder */ +#define RB80_NUMCY 559 /* cylinders/drive */ +#define RB80_SIZE (RB80_NUMCY * RB80_NUMSF * \ + RB80_NUMSC * RB80_NUMWD) /* words/drive */ + +#define RB_NUMWD(u) ((u->flags & UNIT_RB80) ? RB80_NUMWD : RB02_NUMWD) +#define RB_NUMSC(u) ((u->flags & UNIT_RB80) ? RB80_NUMSC : RB02_NUMSC) +#define RB_NUMSF(u) ((u->flags & UNIT_RB80) ? RB80_NUMSF : RB02_NUMSF) +#define RB_NUMCY(u) ((u->flags & UNIT_RB80) ? RB80_NUMCY : RB02_NUMCY) +#define RB_SIZE(u) ((u->flags & UNIT_RB80) ? RB80_SIZE : RB02_SIZE) + +#define RB_NUMDR 4 /* drives/controller */ +#define RB_MAXFR (1 << 16) /* max transfer */ + +/* Flags in the unit flags word */ + +#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_V_RB80 (UNIT_V_UF + 1) /* RB02 vs RB80 */ +#define UNIT_V_DUMMY (UNIT_V_UF + 2) /* dummy flag */ +#define UNIT_DUMMY (1 << UNIT_V_DUMMY) +#define UNIT_WLK (1u << UNIT_V_WLK) +#define UNIT_RB80 (1u << UNIT_V_RB80) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protected */ + +/* Parameters in the unit descriptor */ + +#define TRK u3 /* current track */ +#define STAT u4 /* status */ +#define SIP u5 /* seek in progress */ + +/* RBDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */ + +#define RB02DS_LOAD 0 /* no cartridge */ +#define RB02DS_LOCK 5 /* lock on */ +#define RB02DS_BHO 0000010 /* brushes home NI */ +#define RB02DS_HDO 0000020 /* heads out NI */ +#define RB02DS_CVO 0000040 /* cover open NI */ +#define RB02DS_HD 0000100 /* head select ^ */ +#define RB02DS_DSE 0000400 /* drv sel err NI */ +#define RB02DS_VCK 0001000 /* vol check * */ +#define RB02DS_WGE 0002000 /* wr gate err * */ +#define RB02DS_SPE 0004000 /* spin err * */ +#define RB02DS_STO 0010000 /* seek time out NI */ +#define RB02DS_WLK 0020000 /* wr locked */ +#define RB02DS_HCE 0040000 /* hd curr err NI */ +#define RB02DS_WDE 0100000 /* wr data err NI */ +#define RB02DS_ATT (RB02DS_HDO+RB02DS_BHO+RB02DS_LOCK) /* att status */ +#define RB02DS_UNATT (RB02DS_CVO+RB02DS_LOAD) /* unatt status */ +#define RB02DS_ERR (RB02DS_WDE+RB02DS_HCE+RB02DS_STO+RB02DS_SPE+RB02DS_WGE+ \ + RB02DS_VCK+RB02DS_DSE) /* errors bits */ + +#define RB80DS_SCNT 0x0000000F +#define RB80DS_FLT 0x00000100 +#define RB80DS_PLV 0x00000200 +#define RB80DS_SKE 0x00000400 +#define RB80DS_OCY 0x00000800 +#define RB80DS_RDY 0x00001000 +#define RB80DS_WLK 0x00002000 + +/* RBCS */ + +#define RBCS_DRDY 0x00000001 /* drive ready */ +#define RBCS_M_FUNC 0x7 /* function */ +#define RBCS_NOP 0 +#define RBCS_WCHK 1 +#define RBCS_GSTA 2 +#define RBCS_SEEK 3 +#define RBCS_RHDR 4 +#define RBCS_WRITE 5 +#define RBCS_READ 6 +#define RBCS_RNOHDR 7 +#define RBCS_V_FUNC 1 +#define RBCS_M_DRIVE 0x3 +#define RBCS_V_DRIVE 8 +#define RBCS_INCMP 0x00000400 /* incomplete */ +#define RBCS_CRC 0x00000800 /* CRC error */ +#define RBCS_DLT 0x00001000 /* data late */ +#define RBCS_HDE 0x00001400 /* header error */ +#define RBCS_NXM 0x00002000 /* non-exist memory */ +#define RBCS_DRE 0x00004000 /* drive error */ +#define RBCS_ERR 0x00008000 /* error summary */ +#define RBCS_ALLERR (RBCS_ERR+RBCS_DRE+RBCS_NXM+RBCS_CRC+RBCS_INCMP) +#define RBCS_M_ATN 0xF +#define RBCS_V_ATN 16 +#define RBCS_ATN (RBCS_M_ATN << RBCS_V_ATN) +#define RBCS_M_ECC 0x2 +#define RBCS_V_ECC 20 +#define RBCS_SSI 0x00400000 +#define RBCS_SSE 0x00800000 +#define RBCS_IRQ 0x01000000 +#define RBCS_MTN 0x02000000 +#define RBCS_R80 0x04000000 +#define RBCS_ASI 0x08000000 +#define RBCS_TOI 0x10000000 +#define RBCS_FMT 0x20000000 +#define RBCS_MATN 0x80000000 +//#define RBCS_RW 0001716 /* read/write */ +#define RBCS_RW ((RBCS_M_FUNC << RBCS_V_FUNC) + \ + CSR_IE + CSR_DONE + \ + (RBCS_M_DRIVE << RBCS_V_DRIVE) + \ + RBCS_SSI + RBCS_MTN + RBCS_ASI + \ + RBCS_TOI + RBCS_FMT + RBCS_MATN) +#define RBCS_C0 RBCS_SSE +#define RBCS_C1 (rbcs & RBCS_MATN) ? RBCS_IRQ : \ + ((RBCS_M_ATN << RBCS_V_ATN) + RBCS_IRQ) +#define GET_FUNC(x) (((x) >> RBCS_V_FUNC) & RBCS_M_FUNC) +#define GET_DRIVE(x) (((x) >> RBCS_V_DRIVE) & RBCS_M_DRIVE) + +/* RBBA */ + +#define RBBA_RW 0x0003FFFF + +/* RBBC */ + +/* RBMP */ + +#define RBMP_MRK 0x00000001 +#define RBMP_GST 0x00000002 +#define RBMP_RST 0x00000008 + +/* RBDA */ + +#define RBDA_V_SECT 0 /* sector */ +#define RBDA_M_SECT 0xFF +#define RBDA_V_TRACK 8 /* track */ +#define RBDA_M_TRACK 0xFF +#define RBDA_V_CYL 16 /* cylinder */ +#define RBDA_M_CYL 0xFFFF +#define RBDA_TRACK (RBDA_M_TRACK << RBDA_V_TRACK) +#define RBDA_CYL (RBDA_M_CYL << RBDA_V_CYL) +#define GET_SECT(x) (((x) >> RBDA_V_SECT) & RBDA_M_SECT) +#define GET_CYL(x) (((x) >> RBDA_V_CYL) & RBDA_M_CYL) +#define GET_TRACK(x) (((x) >> RBDA_V_TRACK) & RBDA_M_TRACK) +//#define GET_DA(x) ((GET_CYL(x) * RB02_NUMSF * GET_TRACK (x) * RB02_NUMSC) + GET_SECT (x)) +#define GET_DA(x,u) ((GET_TRACK (x) * RB_NUMCY(u) * RB_NUMSC(u) * RB_NUMWD(u)) + \ + (GET_CYL(x) * RB_NUMSC(u) * RB_NUMWD(u)) + \ + (GET_SECT (x) * RB_NUMWD(u))) + +#define DBG_REG 0x0001 /* registers */ +#define DBG_CMD 0x0002 /* commands */ +#define DBG_RD 0x0004 /* disk reads */ +#define DBG_WR 0x0008 /* disk writes */ + +extern int32 int_req[IPL_HLVL]; + +uint16 *rbxb = NULL; /* xfer buffer */ +int32 rbcs = 0; /* control/status */ +int32 rbba = 0; /* memory address */ +int32 rbbc = 0; /* bytes count */ +int32 rbda = 0; /* disk addr */ +int32 rbmp = 0, rbmp1 = 0, rbmp2 = 0; /* mp register queue */ +int32 rb_swait = 150; /* seek wait */ +int32 rb_mwait = 300; /* seek wait */ +int32 rb_cwait = 50; /* seek wait */ + +t_stat rb_rd16 (int32 *data, int32 PA, int32 access); +t_stat rb_wr16 (int32 data, int32 PA, int32 access); +t_stat rb_rd32 (int32 *data, int32 PA, int32 access); +t_stat rb_wr32 (int32 data, int32 PA, int32 access); +t_stat rb_svc (UNIT *uptr); +t_stat rb_reset (DEVICE *dptr); +void rb_set_done (int32 error); +t_stat rb_attach (UNIT *uptr, char *cptr); +t_stat rb_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rb_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); + +/* RB730 data structures + + rb_dev RB device descriptor + rb_unit RB unit list + rb_reg RB register list + rb_mod RB modifier list +*/ + +DIB rb_dib = { + IOBA_RB, IOLN_RB, &rb_rd16, &rb_wr16, + 1, IVCL (RB), VEC_RB, { NULL } }; + +UNIT rb_unit[] = { + { UDATA (&rb_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_RB80, RB80_SIZE) }, + { UDATA (&rb_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RB02_SIZE) }, + { UDATA (&rb_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RB02_SIZE) }, + { UDATA (&rb_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RB02_SIZE) }, + }; + +REG rb_reg[] = { + { NULL } + }; + +DEBTAB rb_debug[] = { + {"REG", DBG_REG}, + {"CMD", DBG_CMD}, + {"RD", DBG_RD}, + {"WR", DBG_WR}, + {0} +}; + +MTAB rb_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rb_set_bad }, + { (UNIT_RB80+UNIT_ATT), UNIT_ATT, "RB02", NULL, NULL }, + { (UNIT_RB80+UNIT_ATT), (UNIT_RB80+UNIT_ATT), "RB80", NULL, NULL }, + { (UNIT_RB80+UNIT_ATT), 0, "RB02", NULL, NULL }, + { (UNIT_RB80+UNIT_ATT), UNIT_RB80, "RB80", NULL, NULL }, + { (UNIT_RB80), 0, NULL, "RB02", &rb_set_size }, + { (UNIT_RB80), UNIT_RB80, NULL, "RB80", &rb_set_size }, + { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { 0 } + }; + +DEVICE rb_dev = { + "RB", rb_unit, rb_reg, rb_mod, + RB_NUMDR, DEV_RDX, T_ADDR_W, 1, DEV_RDX, 16, + NULL, NULL, &rb_reset, + NULL, &rb_attach, NULL, + &rb_dib, DEV_DISABLE | DEV_UBUS | DEV_DEBUG, 0, + rb_debug, 0, 0 + }; + +/* I/O dispatch routines + + 17775606 RBDCS dummy csr to trigger sysgen +*/ + +t_stat rb_rd16 (int32 *data, int32 PA, int32 access) +{ +*data = 0; +return SCPE_OK; +} + +t_stat rb_wr16 (int32 data, int32 PA, int32 access) +{ +return SCPE_OK; +} + +t_stat rb_rd32 (int32 *data, int32 PA, int32 access) +{ +UNIT *uptr; + +switch ((PA >> 2) & 07) { + + case 0: /* RBCS */ + if (rbcs & RBCS_ALLERR) + rbcs = rbcs | RBCS_ERR; + uptr = rb_dev.units + GET_DRIVE (rbcs); + if ((sim_is_active (uptr)) || (uptr->flags & UNIT_DIS)) + rbcs = rbcs & ~RBCS_DRDY; + else rbcs = rbcs | RBCS_DRDY; /* see if ready */ + if (uptr->flags & UNIT_RB80) + rbcs = rbcs | RBCS_R80; + else rbcs = rbcs & ~RBCS_R80; + *data = rbcs; + break; + + case 1: /* RBBA */ + *data = rbba & RBBA_RW; + break; + + case 2: /* RBBC */ + *data = rbbc; + break; + + case 3: /* RBDA */ + *data = rbda; + break; + + case 4: /* RBMP */ + *data = rbmp; + rbmp = rbmp1; /* ripple data */ + rbmp1 = rbmp2; + break; + + case 5: /* ECCPS */ + case 6: /* ECCPT */ + case 7: /* INIT */ + *data = 0; + break; + } + +sim_debug(DBG_REG, &rb_dev, "reg %d read, value = %X\n", (PA >> 2) & 07, *data); + +return SCPE_OK; +} + +t_stat rb_wr32 (int32 data, int32 PA, int32 access) +{ +UNIT *uptr; + +sim_debug(DBG_REG, &rb_dev, "reg %d write, value = %X\n", (PA >> 2) & 07, data); + +switch ((PA >> 2) & 07) { + + case 0: /* CSR */ + if (rbcs & RBCS_ALLERR) + rbcs = rbcs | RBCS_ERR; + uptr = rb_dev.units + GET_DRIVE (data); + if ((sim_is_active (uptr)) || (uptr->flags & UNIT_DIS)) + rbcs = rbcs & ~RBCS_DRDY; + else rbcs = rbcs | RBCS_DRDY; /* see if ready */ + if (uptr->flags & UNIT_RB80) + rbcs = rbcs | RBCS_R80; + else rbcs = rbcs & ~RBCS_R80; + + rbcs = rbcs & ~(data & RBCS_C1); + rbcs = rbcs & ~(~data & RBCS_C0); + rbcs = (rbcs & ~RBCS_RW) | (data & RBCS_RW); + if (data & RBCS_ATN) CLR_INT (RB); + + if ((data & CSR_DONE) || (sim_is_active (uptr))) /* ready set? */ + return SCPE_OK; + + CLR_INT (RB); /* clear interrupt */ + rbcs = rbcs & ~RBCS_ALLERR; /* clear errors */ + uptr->SIP = 0; + if (uptr->flags & UNIT_DIS) { + rbcs = rbcs | (1u << (RBCS_V_ATN + GET_DRIVE (rbcs))); + rb_set_done (RBCS_ERR | RBCS_INCMP); + break; + } + switch (GET_FUNC (rbcs)) { /* case on RBCS<3:1> */ + case RBCS_NOP: /* nop */ + rb_set_done (0); + break; + case RBCS_SEEK: /* seek */ + sim_activate (uptr, rb_swait); + break; + default: /* data transfer */ + sim_activate (uptr, rb_cwait); /* activate unit */ + break; + } /* end switch func */ + break; + + case 1: /* BAR */ + rbba = data & RBBA_RW; + break; + + case 2: /* BCR */ + rbbc = data; + break; + + case 3: /* DAR */ + rbda = data; + break; + + case 4: /* MPR */ + rbmp = rbmp1 = rbmp2 = data; + break; + + case 5: /* ECCPS */ + case 6: /* ECCPT */ + break; + + case 7: /* INIT */ + return rb_reset(&rb_dev); + } + +return SCPE_OK; +} + +/* Service unit timeout + + If seek in progress, complete seek command + Else complete data transfer command + + The unit control block contains the function and cylinder for + the current command. +*/ + +t_stat rb_svc (UNIT *uptr) +{ +int32 curr, newc, swait; +int32 err, wc, maxwc, t; +int32 i, func, da, awc; +uint32 ma; +uint16 comp; + +func = GET_FUNC (rbcs); /* get function */ +if (func == RBCS_GSTA) { /* get status */ + sim_debug(DBG_CMD, &rb_dev, "Get Status\n"); + if (uptr->flags & UNIT_RB80) { + rbmp = uptr->STAT | RB80DS_PLV; + if (uptr->flags & UNIT_ATT) + rbmp = rbmp | RB80DS_RDY | RB80DS_OCY; + if (uptr->flags & UNIT_WPRT) + rbmp = rbmp | RB80DS_WLK; + } + else { + if (rbmp & RBMP_RST) + uptr->STAT = uptr->STAT & ~RB02DS_ERR; + rbmp = uptr->STAT | (uptr->flags & UNIT_ATT)? RB02DS_ATT: RB02DS_UNATT; + if (uptr->flags & UNIT_WPRT) + rbmp = rbmp | RB02DS_WLK; + } + rbmp2 = rbmp1 = rbmp; + rb_set_done (0); /* done */ + return SCPE_OK; + } + +if (func == RBCS_RHDR) { /* read header? */ + sim_debug(DBG_CMD, &rb_dev, "Read Header\n"); + rbmp = (uptr->TRK & RBDA_TRACK) | GET_SECT (rbda); + rbmp1 = rbmp2 = 0; + rbcs = rbcs | (1 << (RBCS_V_ATN + GET_DRIVE (rbcs))); + rb_set_done (0); /* done */ + return SCPE_OK; + } + +if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ + rbcs = rbcs & ~RBCS_DRDY; /* clear drive ready */ + rbcs = rbcs | (1u << (RBCS_V_ATN + GET_DRIVE (rbcs))); + if ((uptr->flags & UNIT_RB80) == 0) + uptr->STAT = uptr->STAT | RB02DS_SPE; /* spin error */ + rb_set_done (RBCS_ERR | RBCS_INCMP); /* flag error */ + //return IORETURN (rl_stopioe, SCPE_UNATT); + return SCPE_OK; + } + +if ((func == RBCS_WRITE) && (uptr->flags & UNIT_WPRT)) { + if ((uptr->flags & UNIT_RB80) == 0) + uptr->STAT = uptr->STAT | RB02DS_WGE; /* write and locked */ + rb_set_done (RBCS_ERR | RBCS_DRE); + return SCPE_OK; + } + +if (func == RBCS_SEEK) { /* seek? */ + if (uptr->SIP == 0) { + sim_debug(DBG_CMD, &rb_dev, "Seek, CYL=%d, TRK=%d, SECT=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda)); + uptr->SIP = 1; + if (rbda == 0xFFFFFFFF) swait = rb_swait; + else { + curr = GET_CYL (uptr->TRK); /* current cylinder */ + newc = GET_CYL (rbda); /* offset */ + uptr->TRK = (newc << RBDA_V_CYL); /* put on track */ + swait = rb_cwait * abs (newc - curr); + if (swait < rb_mwait) swait = rb_mwait; + } + sim_activate (uptr, swait); + rbcs = rbcs | (1 << (RBCS_V_ATN + GET_DRIVE (rbcs))); + rbcs = rbcs | RBCS_IRQ; + rb_set_done(0); + return SCPE_OK; + } + else { + sim_debug(DBG_CMD, &rb_dev, "Seek done\n"); + rbcs = rbcs | (1 << (RBCS_V_ATN + GET_DRIVE (rbcs))); + uptr->SIP = 0; + rb_set_done (0); /* done */ + return SCPE_OK; + } + } + +if (((func != RBCS_RNOHDR) && ((uptr->TRK & RBDA_CYL) != (rbda & RBDA_CYL))) + || (GET_SECT (rbda) >= RB_NUMSC(uptr))) { /* bad cyl or sector? */ + sim_debug(DBG_CMD, &rb_dev, "Invalid cylinder or sector, CYL=%d, TRK=%d, SECT=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda)); + rb_set_done (RBCS_ERR | RBCS_HDE | RBCS_INCMP); /* wrong cylinder? */ + return SCPE_OK; + } + +ma = rbba; /* get mem addr */ +da = GET_DA (rbda, uptr); /* get disk addr */ +wc = ((rbbc * -1) >> 1); /* get true wc */ + +maxwc = (RB_NUMSC(uptr) - GET_SECT (rbda)) * RB_NUMWD(uptr); /* max transfer */ +if (wc > maxwc) /* track overrun? */ + wc = maxwc; +err = sim_fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + +if ((func >= RBCS_READ) && (err == 0)) { /* read (no hdr)? */ + sim_debug(DBG_CMD, &rb_dev, "Read, CYL=%d, TRK=%d, SECT=%d, WC=%d, DA=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda), wc, da); + i = sim_fread (rbxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); + for ( ; i < wc; i++) /* fill buffer */ + rbxb[i] = 0; + if (t = Map_WriteW (ma, wc << 1, rbxb)) { /* store buffer */ + rbcs = rbcs | RBCS_ERR | RBCS_NXM; /* nxm */ + wc = wc - t; /* adjust wc */ + } + } /* end read */ + +if ((func == RBCS_WRITE) && (err == 0)) { /* write? */ + sim_debug(DBG_CMD, &rb_dev, "Write, CYL=%d, TRK=%d, SECT=%d, WC=%d, DA=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda), wc, da); + if (t = Map_ReadW (ma, wc << 1, rbxb)) { /* fetch buffer */ + rbcs = rbcs | RBCS_ERR | RBCS_NXM; /* nxm */ + wc = wc - t; /* adj xfer lnt */ + } + if (wc) { /* any xfer? */ + awc = (wc + (RB_NUMWD(uptr) - 1)) & ~(RB_NUMWD(uptr) - 1); /* clr to */ + for (i = wc; i < awc; i++) /* end of blk */ + rbxb[i] = 0; + sim_fwrite (rbxb, sizeof (uint16), awc, uptr->fileref); + err = ferror (uptr->fileref); + } + } /* end write */ + +if ((func == RBCS_WCHK) && (err == 0)) { /* write check? */ + sim_debug(DBG_CMD, &rb_dev, "WCheck, CYL=%d, TRK=%d, SECT=%d, WC=%d, DA=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda), wc, da); + i = sim_fread (rbxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); + for ( ; i < wc; i++) /* fill buffer */ + rbxb[i] = 0; + awc = wc; /* save wc */ + for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */ + if (Map_ReadW (ma + (wc << 1), 2, &comp)) { /* mem wd */ + rbcs = rbcs | RBCS_ERR | RBCS_NXM; /* nxm */ + break; + } + if (comp != rbxb[wc]) /* check to buf */ + rbcs = rbcs | RBCS_ERR | RBCS_CRC; + } /* end for */ + } /* end wcheck */ + +rbbc = (rbbc + (wc << 1)); /* final byte count */ +if (rbbc != 0) { /* completed? */ + rbcs = rbcs | RBCS_ERR | RBCS_INCMP; + } +ma = ma + (wc << 1); /* final byte addr */ +rbba = ma & RBBA_RW; +rbda = rbda + ((wc + (RB_NUMWD(uptr) - 1)) / RB_NUMWD(uptr)); +rb_set_done (0); + +if (err != 0) { /* error? */ + perror ("RB I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; + } +return SCPE_OK; +} + +/* Set done and possibly errors */ + +void rb_set_done (int32 status) +{ +rbcs = rbcs | status | CSR_DONE; /* set done */ +rbcs = rbcs | RBCS_IRQ; +if (rbcs & CSR_IE) { + sim_debug(DBG_CMD, &rb_dev, "Done, INT\n"); + SET_INT (RB); + } +else { + sim_debug(DBG_CMD, &rb_dev, "Done, no INT\n"); + CLR_INT (RB); + } +return; +} + +/* Device reset */ + +t_stat rb_reset (DEVICE *dptr) +{ +int32 i; +UNIT *uptr; + +rbcs = CSR_DONE; +rbda = rbba = rbbc = rbmp = 0; +CLR_INT (RB); +for (i = 0; i < RB_NUMDR; i++) { + uptr = rb_dev.units + i; + sim_cancel (uptr); + uptr->STAT = 0; + uptr->SIP = 0; + } +if (rbxb == NULL) + rbxb = (uint16 *) calloc (RB_MAXFR, sizeof (uint16)); +if (rbxb == NULL) + return SCPE_MEM; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat rb_attach (UNIT *uptr, char *cptr) +{ +uint32 p; +t_stat r; + +uptr->capac = (uptr->flags & UNIT_RB80)? RB80_SIZE: RB02_SIZE; +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) /* error? */ + return r; +uptr->TRK = 0; /* cylinder 0 */ +if ((uptr->flags & UNIT_RB80) == 0) + uptr->STAT = RB02DS_VCK; /* new volume */ +if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ + if (uptr->flags & UNIT_RO) /* if ro, done */ + return SCPE_OK; + return pdp11_bad_block (uptr, RB_NUMSC(uptr), RB_NUMWD(uptr)); + } +return SCPE_OK; +} + +/* Set size routine */ + +t_stat rb_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; +uptr->capac = (val & UNIT_RB80)? RB80_SIZE: RB02_SIZE; +return SCPE_OK; +} + +/* Set bad block routine */ + +t_stat rb_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +return pdp11_bad_block (uptr, RB_NUMSC(uptr), RB_NUMWD(uptr)); +} diff --git a/VAX/vax730_stddev.c b/VAX/vax730_stddev.c new file mode 100644 index 00000000..f68b7a7e --- /dev/null +++ b/VAX/vax730_stddev.c @@ -0,0 +1,1107 @@ +/* vax730_stddev.c: VAX 11/730 standard I/O devices + + Copyright (c) 2010-2011, 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). + + tti console input + tto console output + td console TU58 + todr TODR clock + tmr interval timer + + 29-Mar-2011 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_V_SEL 8 /* unit select */ +#define RXDB_M_SEL 0xF +#define RXDB_TERM 0x0 /* console terminal */ +#define RXDB_MISC 0xF /* console misc */ +#define RXDB_ERR 0x8000 /* 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_TERM 0x0 /* console terminal */ +#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_unitno = 0; /* active unit number */ +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); + +/* 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) }, + { 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, + 2, 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_dev.units[td_unitno], 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_unitno = td_ibuf[4]; + td_state = TD_END; /* All treated as NOP */ + td_ecode = TD_STSOK; + td_offset = 0; + sim_activate (&td_dev.units[td_unitno], td_cwait); /* sched command */ + break; + + case TD_CMDINI: + printf("Warning: TU58 command 'INIT' not implemented\n"); + break; + + case TD_CMDRD: + td_unitno = td_ibuf[4]; + 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_dev.units[td_unitno], td_cwait); /* sched command */ + break; + + case TD_CMDWR: + td_unitno = td_ibuf[4]; + 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_dev.units[td_unitno], 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: /* MRSP supported? */ + csi_buf = TD_OPDAT; /* TP_OPCMD = yes, TP_OPDAT = no */ + 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_dev.units[0]); + sim_cancel (&td_dev.units[1]); + 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_dev.units[0], 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_unitno = td_ibuf[1]; + td_block = 0; + td_txsize = 512; + td_state = TD_READ; + td_offset = 0; + sim_activate (&td_dev.units[td_unitno], 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 mailbox? */ + txdb_misc_wr (tto_buf); +sim_activate (&tto_unit, tto_unit.wait); /* no, console */ +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; +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)); +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 */ + +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: + ABORT (STOP_BOOT); + 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 = CALC_DA (td_block); /* get tape address */ + 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++] = td_unitno; /* 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_dev.units[0]); +sim_cancel (&td_dev.units[1]); +return SCPE_OK; +} diff --git a/VAX/vax730_sys.c b/VAX/vax730_sys.c new file mode 100644 index 00000000..3b1b78b7 --- /dev/null +++ b/VAX/vax730_sys.c @@ -0,0 +1,665 @@ +/* vax730_sys.c: VAX 11/730 system-specific logic + + 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). + + This module contains the VAX 11/730 system-specific registers and devices. + + sysb system bus controller + + 29-Mar-2011 MB First Version + +*/ + +#include "vax_defs.h" + +#ifndef DONT_USE_INTERNAL_ROM +#include "vax780_vmb_exe.h" +#endif + +static char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ + +/* VAX-11/730 boot device definitions */ + +struct boot_dev { + char *name; + int32 code; + int32 let; + }; + +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[] = { + { "HK", BOOT_HK, 0 }, + { "RL", BOOT_RL, 0 }, + { "RQ", BOOT_UDA, 1 << 24 }, + { "RQB", BOOT_UDA, 1 << 24 }, + { "RQC", BOOT_UDA, 1 << 24 }, + { "RQD", BOOT_UDA, 1 << 24 }, + { "TQ", BOOT_TK, 1 << 24 }, + { "TD", BOOT_TD, 0 }, + { "RB", BOOT_RB, 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 sysb_reset (DEVICE *dptr); +t_stat vax730_boot (int32 flag, char *ptr); +t_stat vax730_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_ubus_tab (void); +extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp); +extern int32 ubamap_rd (int32 pa); +extern void ubamap_wr (int32 pa, int32 val, int32 lnt); +extern t_bool uba_eval_int (int32 lvl); +extern int32 uba_get_ubvector (int32 lvl); + +/* SYSB data structures + + sysb_dev SYSB device descriptor + sysb_unit SYSB unit + sysb_reg SYSB register list +*/ + +UNIT sysb_unit = { UDATA (NULL, 0, 0) }; + +REG sysb_reg[] = { + { BRDATA (BOOTCMD, cpu_boot_cmd, 16, 8, CBUFSIZE), REG_HRO }, + { NULL } + }; + +DEVICE sysb_dev = { + "SYSB", &sysb_unit, sysb_reg, NULL, + 1, 16, 16, 1, 16, 8, + NULL, NULL, &sysb_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* Special boot command, overrides regular boot */ + +CTAB vax730_cmd[] = { + { "BOOT", &vax730_boot, RU_BOOT, + "bo{ot} {/R5:flg} boot device\n" }, + { NULL } + }; + +/* The VAX 11/730 has two sources of interrupts + + - internal device interrupts (CPU, console, clock, console storage) + - external device interrupts (Unibus) + +/* 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_CLKINT) && tmr_int) /* clock int */ + return IPL_CLKINT; +for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */ + if (i <= ipl) /* at ipl? no int */ + return 0; + if (uba_eval_int(i - IPL_HMIN)) + return i; + } +if ((ipl < IPL_TTINT) && (tti_int || tto_int)) /* console int */ + return IPL_TTINT; +if ((ipl < IPL_CSINT) && (csi_int || cso_int)) /* console storage int */ + return IPL_CSINT; +if (ipl >= IPL_SMAX) /* ipl >= sw max? */ + return 0; +if ((t = SISR & sw_int_mask[ipl]) == 0) /* eligible req */ + return 0; +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 l; + +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 (uba_eval_int(l)) + return uba_get_ubvector(l); + } +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 (lvl == IPL_CSINT) { /* console storage? */ + 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 730-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_SID: /* SID */ + val = VAX730_SID | VAX730_MICRO; + break; + + case MT_MCESR: /* MCESR (not impl) */ + val = 0; + 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_CDR: /* CDR */ + case MT_SBIFS: /* SBIFS */ + case MT_SBIS: /* SBIS */ + case MT_SBISC: /* SBISC */ + case MT_SBIMT: /* SBIMT */ + case MT_SBIER: /* SBIER */ + case MT_SBITA: /* SBITA */ + val = 0; + break; + + default: + RSVD_OPND_FAULT; + } + +return val; +} + +/* Write 730-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_MCESR: /* MCESR (not impl) */ + break; + + case MT_UBINIT: /* UBINIT (not impl) */ + 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_CDR: /* CDR */ + case MT_SBIFS: /* SBIFS */ + case MT_SBISC: /* SBISC */ + case MT_SBIMT: /* SBIMT */ + case MT_SBIER: /* SBIER */ + case MT_SBIQC: /* SBIQC */ + 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; + } + } +MACH_CHECK (MCHK_NXM); +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; + } + } +MACH_CHECK (MCHK_NXM); +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, nxm; + +nxm = ((p1 == MCHK_NXM) || (p1 == MCHK_IIA) || (p1 == MCHK_IUA)); +if (nxm) + 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 - 16; /* push 4 words */ +Write (SP, 12, L_LONG, WA); /* # bytes */ +Write (SP + 4, p1, L_LONG, WA); /* mcheck type */ +if (nxm) + Write (SP + 8, mchk_va, L_LONG, WA); /* NXM addr */ +else + Write (SP + 8, 0, L_LONG, WA); /* first parameter */ +Write (SP + 12, 0, L_LONG, WA); /* second parameter */ +in_ie = 0; +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? */ + (vax730_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 vax730_boot (int32 flag, char *ptr) +{ +t_stat r; + +r = vax730_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 vax730_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 (boot_tab[i].code == BOOT_RB) /* vector set by console for RB730 */ + R[0] = R[0] | ((VEC_RB - VEC_Q) << 16); + R[1] = TR_UBA; + R[2] = boot_tab[i].let | (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) { +#ifndef DONT_USE_INTERNAL_ROM + FILE *f; + + if (f = sim_fopen ("vmb.exe", "wb")) { + printf ("Saving boot code to vmb.exe\n"); + if (sim_log) + fprintf (sim_log, "Saving boot code to vmb.exe\n"); + sim_fwrite (vax780_vmb_exe, sizeof(vax780_vmb_exe[0]), sizeof(vax780_vmb_exe)/sizeof(vax780_vmb_exe[0]), f); + fclose (f); + 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) + SP = PC = 512; + } +#endif + return r; + } +SP = PC = 512; +return SCPE_OK; +} + +/* SYSB reset */ + +t_stat sysb_reset (DEVICE *dptr) +{ +sim_vm_cmd = vax730_cmd; +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 (); +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 { /* 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/vax730_syslist.c b/VAX/vax730_syslist.c new file mode 100644 index 00000000..f0ce5b84 --- /dev/null +++ b/VAX/vax730_syslist.c @@ -0,0 +1,130 @@ +/* vax730_syslist.c: VAX 730 device list + + Copyright (c) 2010-2011, 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). + + 29-Mar-2011 MB First Version +*/ + +#include "vax_defs.h" + +char sim_name[] = "VAX730"; + +extern DEVICE cpu_dev; +extern DEVICE tlb_dev; +extern DEVICE sysb_dev; +extern DEVICE mctl_dev; +extern DEVICE uba_dev; +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 rb_dev; +extern DEVICE rl_dev; +extern DEVICE hk_dev; +extern DEVICE ry_dev; +extern DEVICE ts_dev; +extern DEVICE tq_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, + &sysb_dev, + &mctl_dev, + &uba_dev, + &clk_dev, + &tmr_dev, + &tti_dev, + &tto_dev, + &td_dev, + &dz_dev, + &cr_dev, + &lpt_dev, + &rl_dev, + &hk_dev, + &rq_dev, + &rqb_dev, + &rqc_dev, + &rqd_dev, + &rb_dev, + &ry_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. + + -r load ROM0 + -s load ROM1 + -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 (sim_switches & SWMASK ('R')) { /* ROM0? */ + return SCPE_NXM; + } + else if (sim_switches & SWMASK ('S')) { /* ROM1? */ + return SCPE_NXM; + } + else { + if (origin >= limit) /* NXM? */ + return SCPE_NXM; + WriteB (origin, val); /* memory */ + } + origin = origin + 1; + } +return SCPE_OK; +} diff --git a/VAX/vax730_uba.c b/VAX/vax730_uba.c new file mode 100644 index 00000000..6f62419a --- /dev/null +++ b/VAX/vax730_uba.c @@ -0,0 +1,667 @@ +/* vax730_uba.c: VAX 11/730 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 DW730 Unibus adapter + + 29-Mar-2011 MB First Version +*/ + +#include "vax_defs.h" + +/* Unibus adapter */ + +#define UBA_NMAPR 496 /* number of map reg */ + +/* Unibus configuration register */ + +#define UBACNF_OF 0x00 +#define UBACNF_CODE 0x00000028 /* adapter code */ + +/* Data path registers */ + +#define UBADPR_OF 0x01 + +/* Control & Status register */ + +#define UBACSR_OF 0x04 +#define UBACSR_WNV 0x00004000 /* write not valid */ +#define UBACSR_TBPAR 0x00008000 /* TB parity err */ +#define UBACSR_NXM 0x00010000 /* UB NXM */ +#define UBACSR_RDS 0x80000000 /* UB read data subs */ + +/* Vector registers - read only */ + +#define UBA_UVEC 0x80000000 + +/* RB730 registers */ + +#define RB730_OF 0x80 +#define RB730_LN 8 + +/* 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_csr = 0; /* control & status reg */ +uint32 uba_fmer = 0; /* failing map reg */ +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 int32 sim_switches; +extern FILE *sim_log, *sim_deb; +extern int32 p1; + +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); +t_bool uba_eval_int (int32 lvl); +void uba_ubpdn (int32 time); +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 t_stat rb_rd32 (int32 *data, int32 PA, int32 access); +extern t_stat rb_wr32 (int32 data, int32 PA, int32 access); + +/* 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 (CSR, uba_csr, 32) }, + { 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 error bit? + return SCPE_OK; + } +ofs = NEXUS_GETOFS (pa); /* get offset */ +if (ofs >= UBAMAP_OF) { /* map? */ + idx = ofs - UBAMAP_OF; + if (idx >= UBA_NMAPR) return SCPE_NXM; /* valid? */ + *val = uba_map[idx] & UBAMAP_RD; + if (DEBUG_PRI (uba_dev, UBA_DEB_MRD)) + fprintf (sim_deb, ">>UBA: map %d read, value = %X\n", idx, *val); + return SCPE_OK; + } +if (ofs >= RB730_OF) { /* RB730? */ + idx = ofs - RB730_OF; + if (idx >= RB730_LN) return SCPE_NXM; /* valid? */ + return rb_rd32 (val, pa, lnt); + } + +switch (ofs) { /* case on offset */ + + case UBACNF_OF: /* Config Reg */ + *val = UBACNF_CODE; + break; + + case UBADPR_OF + 0: /* DP Regs */ + case UBADPR_OF + 1: + case UBADPR_OF + 2: + *val = 0x0; /* Not used on 11/730 */ + break; + + case UBACSR_OF: /* CSR */ + *val = uba_csr; + break; + + default: + return SCPE_NXM; + } + +if (DEBUG_PRI (uba_dev, UBA_DEB_RRD)) + fprintf (sim_deb, ">>UBA: reg %d read, value = %X\n", ofs, *val); +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 error bit? + return SCPE_OK; + } +ofs = NEXUS_GETOFS (pa); /* get offset */ +if (ofs >= UBAMAP_OF) { /* map? */ + idx = ofs - UBAMAP_OF; + if (idx >= UBA_NMAPR) return SCPE_NXM; /* valid? */ + uba_map[idx] = val & UBAMAP_WR; + if (DEBUG_PRI (uba_dev, UBA_DEB_MWR)) + fprintf (sim_deb, ">>UBA: map %d write, value = %X\n", idx, val); + return SCPE_OK; + } +if (ofs >= RB730_OF) { /* RB730? */ + idx = ofs - RB730_OF; + if (idx >= RB730_LN) return SCPE_NXM; /* valid? */ + return rb_wr32 (val, pa, lnt); + } + +switch (ofs) { /* case on offset */ + + case UBACNF_OF: /* Config Reg */ + case UBADPR_OF + 0: /* DP Regs */ + case UBADPR_OF + 1: + case UBADPR_OF + 2: + break; /* ignore writes */ + + case UBACSR_OF: /* CSR */ + if(val & 0x10000) uba_csr = 0; + break; + + default: + return SCPE_NXM; + } + +if (DEBUG_PRI (uba_dev, UBA_DEB_RWR)) + fprintf (sim_deb, ">>UBA: reg %d write, value = %X\n", ofs, val); +return SCPE_OK; +} + +/* Read and write Unibus I/O space */ + +int32 ReadUb (uint32 pa) +{ +int32 idx, val; + +if (ADDR_IS_IOP (pa)) { /* iopage */ + idx = (pa & IOPAGEMASK) >> 1; + if (iodispR[idx]) { + iodispR[idx] (&val, pa, READ); + return val; + } + } +MACH_CHECK(MCHK_IIA); +return 0; +} + +void WriteUb (uint32 pa, int32 val, int32 mode) +{ +int32 idx; + +if (ADDR_IS_IOP (pa)) { /* iopage */ + idx = (pa & IOPAGEMASK) >> 1; + if (iodispW[idx]) { + iodispW[idx] (val, pa, mode); + return; + } + } +MACH_CHECK(MCHK_IIA); +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 error bit? + 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 error bit? + } +SET_IRQL; /* update ints */ +return; +} + +/* Update UBA nexus interrupts */ + +t_bool uba_eval_int (int32 lvl) +{ +return (int_req[lvl] != 0); +} + +/* Return vector for Unibus interrupt at relative IPL level [0-3] */ + +int32 uba_get_ubvector (int32 lvl) +{ +int32 i, vec; + +vec = 0; +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; +} + +/* Unibus power fail routines */ + +void uba_ubpdn (int32 time) +{ +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++) { + int_req[i] = 0; + } +for (i = 0; i < UBA_NMAPR; i++) + uba_map[i] = 0; +uba_csr = 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_sbi.c b/VAX/vax780_sbi.c index f047184f..a4ad4739 100644 --- a/VAX/vax780_sbi.c +++ b/VAX/vax780_sbi.c @@ -106,7 +106,7 @@ uint32 sbi_sc = 0; /* SBI silo comparator * uint32 sbi_mt = 0; /* SBI maintenance */ uint32 sbi_er = 0; /* SBI error status */ uint32 sbi_tmo = 0; /* SBI timeout addr */ -char cpu_boot_cmd[CBUFSIZE] = { 0 }; /* boot command */ +static 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); diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 87492442..7009a386 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -473,6 +473,11 @@ 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 }, diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index a6087fef..bc825598 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -720,6 +720,8 @@ enum opcodes { #if defined (VAX_780) #include "vax780_defs.h" +#elif defined (VAX_730) +#include "vax730_defs.h" #else #include "vaxmod_defs.h" #endif diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index c855bee0..6e5f1d82 100644 --- a/Visual Studio Projects/Simh.sln +++ b/Visual Studio Projects/Simh.sln @@ -65,6 +65,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SWTP", "SWTP.vcproj", "{0AB EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BuildROMs", "BuildROMs.vcproj", "{D40F3AF1-EEE7-4432-9807-2AD287B490F8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VAX730", "VAX730.vcproj", "{C526F7F2-9476-44BC-B1E9-9522B693BEA7}" + ProjectSection(ProjectDependencies) = postProject + {D40F3AF1-EEE7-4432-9807-2AD287B490F8} = {D40F3AF1-EEE7-4432-9807-2AD287B490F8} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -187,6 +192,10 @@ Global {D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Debug|Win32.Build.0 = Debug|Win32 {D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Release|Win32.ActiveCfg = Release|Win32 {D40F3AF1-EEE7-4432-9807-2AD287B490F8}.Release|Win32.Build.0 = Release|Win32 + {C526F7F2-9476-44BC-B1E9-9522B693BEA7}.Debug|Win32.ActiveCfg = Debug|Win32 + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Visual Studio Projects/VAX730.vcproj b/Visual Studio Projects/VAX730.vcproj new file mode 100644 index 00000000..1b150d31 --- /dev/null +++ b/Visual Studio Projects/VAX730.vcproj @@ -0,0 +1,431 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/descrip.mms b/descrip.mms index 4b0c1a14..c66050c7 100644 --- a/descrip.mms +++ b/descrip.mms @@ -3,6 +3,7 @@ # Modified By: Mark Pizzolato / mark@infocomm.com # Norman Lastovica / norman.lastovica@oracle.com # Camiel Vanderhoeven / camiel@camicom.com +# Matt Burke / scope.matthew@btinternet.com # # This MMS/MMK build script is used to compile the various simulators in # the SIMH package for OpenVMS using DEC C v6.0-001(AXP), v6.5-001(AXP), @@ -40,6 +41,7 @@ # SDS Just Build The SDS 940. # SWTP Just Build The SWTP. # VAX Just Build The DEC VAX. +# VAX730 Just Build The DEC VAX730. # VAX780 Just Build The DEC VAX780. # CLEAN Will Clean Files Back To Base Kit. # @@ -551,6 +553,35 @@ VAX_OPTIONS = /INCL=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ VAX_SIMH_LIB = $(SIMH_LIB) .ENDIF +# Digital Equipment VAX730 Simulator Definitions. +# +VAX730_DIR = SYS$DISK:[.VAX] +VAX730_LIB1 = $(LIB_DIR)VAX730L1-$(ARCH).OLB +VAX730_SOURCE1 = $(VAX730_DIR)VAX_CPU.C,$(VAX730_DIR)VAX_CPU1.C,\ + $(VAX730_DIR)VAX_FPA.C,$(VAX730_DIR)VAX_CIS.C,\ + $(VAX730_DIR)VAX_OCTA.C,$(VAX730_DIR)VAX_CMODE.C,\ + $(VAX730_DIR)VAX_MMU.C,$(VAX730_DIR)VAX_SYS.C,\ + $(VAX730_DIR)VAX_SYSCM.C,$(VAX730_DIR)VAX730_STDDEV.C,\ + $(VAX730_DIR)VAX730_SYS.C,$(VAX730_DIR)VAX730_MEM.C,\ + $(VAX730_DIR)VAX730_UBA.C,$(VAX730_DIR)VAX730_RB.C,\ + $(VAX730_DIR)VAX730_SYSLIST.C +VAX730_LIB2 = $(LIB_DIR)VAX730L2-$(ARCH).OLB +VAX730_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ + $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ + $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_HK.C,\ + $(PDP11_DIR)PDP11_IO_LIB.C +.IFDEF ALPHA_OR_IA64 +VAX730_OPTIONS = /INCL=($(SIMH_DIR),$(VAX730_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_730=1") +VAX730_SIMH_LIB = $(SIMH_LIB64) +.ELSE +VAX730_OPTIONS = /INCL=($(SIMH_DIR),$(VAX730_DIR),$(PDP11_DIR)$(PCAP_INC))\ + /DEF=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS),"VAX_730=1") +VAX730_SIMH_LIB = $(SIMH_LIB) +.ENDIF + # Digital Equipment VAX780 Simulator Definitions. # VAX780_DIR = SYS$DISK:[.VAX] @@ -597,8 +628,8 @@ I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS)) # .IFDEF ALPHA_OR_IA64 ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ - ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX780 SDS \ - I7094 SWTP + ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX730 VAX780 \ + SDS I7094 SWTP $! No further actions necessary .ELSE # @@ -1011,6 +1042,28 @@ $(VAX_LIB2) : $(VAX_SOURCE2) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +$(VAX730_LIB1) : $(VAX730_SOURCE1) + $! + $! Building The $(VAX730_LIB1) Library. + $! + $ $(CC)$(VAX780_OPTIONS)/OBJ=$(VAX730_DIR) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(VAX730_LIB2) : $(VAX730_SOURCE2) + $! + $! Building The $(VAX730_LIB2) Library. + $! + $ $(CC)$(VAX780_OPTIONS)/OBJ=$(VAX730_DIR) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + $(VAX780_LIB1) : $(VAX780_SOURCE1) $! $! Building The $(VAX780_LIB1) Library. @@ -1401,6 +1454,21 @@ $(BIN_DIR)VAX-$(ARCH).EXE : $(SIMH_MAIN) $(VAX_SIMH_LIB) $(PCAP_LIBD) $(VAX_LIB1 $(VAX_SIMH_LIB)/LIBRARY$(PCAP_LIBR) $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* +VAX730 : $(BIN_DIR)VAX730-$(ARCH).EXE + $! VAX730 done + +$(BIN_DIR)VAX730-$(ARCH).EXE : $(SIMH_MAIN) $(VAX730_SIMH_LIB) $(PCAP_LIBD) $(VAX730_LIB1) $(VAX730_LIB2) $(PCAP_EXECLET) + $! + $! Building The $(BIN_DIR)VAX730-$(ARCH).EXE Simulator. + $! + $ $(CC)$(VAX730_OPTIONS)/OBJ=$(BLD_DIR) SCP.C + $ LINK $(LINK_DEBUG)$(LINK_SECTION_BINDING)- + /EXE=$(BIN_DIR)VAX730-$(ARCH).EXE - + $(BLD_DIR)SCP.OBJ,- + $(VAX730_LIB1)/LIBRARY,$(VAX730_LIB2)/LIBRARY,- + $(VAX730_SIMH_LIB)/LIBRARY$(PCAP_LIBR) + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + VAX780 : $(BIN_DIR)VAX780-$(ARCH).EXE $! VAX780 done diff --git a/makefile b/makefile index 05dcee42..4539475f 100644 --- a/makefile +++ b/makefile @@ -45,8 +45,8 @@ ifeq ($(WIN32),) OS_CCDEFS += -DSIM_ASYNCH_IO -DUSE_READER_THREAD OS_LDFLAGS += -lpthread endif - ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi)) - ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h; then echo readline_h; fi)) + ifeq (readline,$(shell if $(TEST) -e /usr/lib/libreadline.$(LIBEXT) -o -e /usr/lib64/libreadline.$(LIBEXT) -o -e /opt/sfw/lib/libreadline.a; then echo readline; fi)) + ifeq (readline_h,$(shell if $(TEST) -e /usr/include/readline/readline.h -o -e /usr/include/readline.h; then echo readline_h; fi)) # Use Locally installed and available readline support ifeq (ncurses,$(shell if $(TEST) -e /usr/lib/libncurses.$(LIBEXT) -o -e /opt/sfw/lib/libncurses.a; then echo ncurses; fi)) OS_CCDEFS += -DHAVE_READLINE @@ -194,6 +194,19 @@ VAX = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c ${VAXD}/vax_io.c \ VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX730 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax730_stddev.c ${VAXD}/vax730_sys.c \ + ${VAXD}/vax730_mem.c ${VAXD}/vax730_uba.c ${VAXD}/vax730_rb.c \ + ${VAXD}/vax730_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_hk.c ${PDP11D}/pdp11_io_lib.c +VAX730_OPT = -DVM_VAX -DVAX_730 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} + + VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ @@ -355,7 +368,7 @@ SWTP_OPT = -I ${SWTPD} # Build everything # ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ - vax vax780 nova eclipse hp2100 i1401 i1620 s3 \ + vax vax730 vax780 nova eclipse hp2100 i1401 i1620 s3 \ altair altairz80 gri i7094 ibm1130 id16 \ id32 sds lgp h316 swtp @@ -437,6 +450,12 @@ ${BIN}vax${EXE} : ${VAX} ${SIM} ${BUILD_ROMS} ${MKDIRBIN} ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ ${LDFLAGS} +vax730 : ${BIN}vax730${EXE} + +${BIN}vax730${EXE} : ${VAX730} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${VAX730} ${SIM} ${VAX730_OPT} -o $@ ${LDFLAGS} + vax780 : ${BIN}vax780${EXE} ${BIN}vax780${EXE} : ${VAX780} ${SIM} ${BUILD_ROMS}