1
0
mirror of https://github.com/open-simh/simh.git synced 2026-05-05 07:33:56 +00:00

Notes For V3.4-0

The memory layout for the Interdata simulators has been changed.
Do not use Interdata SAVE files from prior revisions with V3.4.

1. New Features in 3.4

1.1 SCP and Libraries

- Revised interpretation of fprint_sym, fparse_sym returns
- Revised syntax for SET DEBUG
- DO command nesting allowed to ten levels

1.2 Interdata

- Revised memory model to be 16b instead of 8b

1.3 HP2100

- Added Fast FORTRAN Processor instructions
- Added SET OFFLINE/ONLINE and SET UNLOAD/LOAD commands to tapes and disks

2. Bugs Fixed in 3.4-0

2.1 Interdata

- Fixed bug in show history routine (from Mark Hittinger)
- Fixed bug in initial memory allocation

2.2 PDP-10

- Fixed TU bug, ERASE and WREOF should not clear done (reported by
  Rich Alderson)
- Fixed TU error reporting

2.3 PDP-11

- Fixed TU error reporting
This commit is contained in:
Bob Supnik
2005-05-03 04:10:00 -07:00
committed by Mark Pizzolato
parent 098200a126
commit ec60bbf329
62 changed files with 4332 additions and 7632 deletions

View File

@@ -1,403 +0,0 @@
/* vax780_defs.h: VAX 780 model-specific definitions file
Copyright (c) 2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This file covers the VAX 11/780, the first VAX.
System memory map
0000 0000 - 1FFF FFFF main memory
2000 0000 - 2001 FFFF nexus register space
2002 0000 - 200F FFFF reserved
2010 0000 - 2013 FFFF Unibus address space, Unibus 0
2014 0000 - 2017 FFFF Unibus address space, Unibus 1
2018 0000 - 201B FFFF Unibus address space, Unibus 2
201C 0000 - 201F FFFF Unibus address space, Unibus 3
2020 0000 - 3FFF FFFF reserved
*/
/* Microcode constructs */
#ifndef FULL_VAX
#define FULL_VAX 1
#endif
#ifndef _VAX_780_DEFS_H_
#define _VAX_780_DEFS_H_ 1
#define VAX780_SID (1 << 24) /* system ID */
#define VAX780_ECO (7 << 19) /* ucode revision */
#define VAX780_PLANT (0 << 12) /* plant (Salem NH) */
#define VAX780_SN (1234)
#define CON_HLTPIN 0x0200 /* external CPU halt */
#define CON_HLTINS 0x0600 /* HALT instruction */
#define MCHK_RD_F 0x00 /* read fault */
#define MCHK_RD_A 0xF4 /* read abort */
#define MCHK_IBUF 0x0D /* read istream */
/* Interrupts */
#define IPL_HMAX 0x17 /* highest hwre level */
#define IPL_HMIN 0x14 /* lowest hwre level */
#define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */
#define IPL_SMAX 0xF /* highest swre level */
/* Nexus constants */
#define NEXUS_NUM 16 /* number of nexus */
#define MCTL_NUM 2 /* number of mem ctrl */
#define MBA_NUM 2 /* number of MBA's */
#define TR_MCTL0 1 /* nexus assignments */
#define TR_MCTL1 2
#define TR_UBA 3
#define TR_MBA0 8
#define TR_MBA1 9
#define NEXUS_HLVL (IPL_HMAX - IPL_HMIN + 1)
#define SCB_NEXUS 0x100 /* nexus intr base */
#define SBI_FAULTS 0xFC000000 /* SBI fault flags */
/* Internal I/O interrupts - relative except for clock and console */
#define IPL_CLKINT 0x18 /* clock IPL */
#define IPL_TTINT 0x14 /* console IPL */
#define IPL_MCTL0 (0x15 - IPL_HMIN)
#define IPL_MCTL1 (0x15 - IPL_HMIN)
#define IPL_UBA (0x15 - IPL_HMIN)
#define IPL_MBA0 (0x15 - IPL_HMIN)
#define IPL_MBA1 (0x15 - IPL_HMIN)
/* Nexus interrupt macros */
#define SET_NEXUS_INT(dv) nexus_req[IPL_##dv] |= (1 << TR_##dv)
#define CLR_NEXUS_INT(dv) nexus_req[IPL_##dv] &= ~(1 << TR_##dv)
/* Machine specific IPRs */
#define MT_ACCS 40 /* FPA control */
#define MT_ACCR 41 /* FPA maint */
#define MT_WCSA 44 /* WCS address */
#define MT_WCSD 45 /* WCS data */
#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_MBRK 60 /* microbreak */
/* Memory */
#define MAXMEMWIDTH 23 /* max mem, MS780C */
#define MAXMEMSIZE (1 << MAXMEMWIDTH)
#define MAXMEMWIDTH_X 27 /* max mem, MS780E */
#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 UBADDRBASE 0x20100000 /* Unibus addr base */
#define IOPAGEBASE 0x2013E000 /* IO page base */
#define ADDR_IS_IO(x) ((((uint32) (x)) >= UBADDRBASE) && \
(((uint32) (x)) < (UBADDRBASE + UBADDRSIZE)))
#define ADDR_IS_IOP(x) (((uint32) (x)) >= IOPAGEBASE)
/* Nexus register space */
#define REGAWIDTH 17 /* 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 0x20000000 /* 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)
/* ROM address space in memory controllers */
#define ROMAWIDTH 12 /* ROM addr width */
#define ROMSIZE (1u << ROMAWIDTH) /* ROM size */
#define ROM0BASE (REGBASE + (TR_MCTL0 << REG_V_NEXUS) + 0x1000)
#define ROM1BASE (REGBASE + (TR_MCTL1 << REG_V_NEXUS) + 0x1000)
#define ADDR_IS_ROM0(x) ((((uint32) (x)) >= ROM0BASE) && \
(((uint32) (x)) < (ROM0BASE + ROMSIZE)))
#define ADDR_IS_ROM1(x) ((((uint32) (x)) >= ROM1BASE) && \
(((uint32) (x)) < (ROM1BASE + ROMSIZE)))
#define ADDR_IS_ROM(x) (ADDR_IS_ROM0 (x) || ADDR_IS_ROM1 (x))
/* Other address spaces */
#define ADDR_IS_CDG(x) (0)
#define ADDR_IS_NVR(x) (0)
/* Unibus I/O modes */
#define READ 0 /* PDP-11 compatibility */
#define WRITE (L_WORD)
#define WRITEB (L_BYTE)
/* Common CSI flags */
#define CSR_V_GO 0 /* go */
#define CSR_V_IE 6 /* interrupt enable */
#define CSR_V_DONE 7 /* done */
#define CSR_V_BUSY 11 /* busy */
#define CSR_V_ERR 15 /* error */
#define CSR_GO (1u << CSR_V_GO)
#define CSR_IE (1u << CSR_V_IE)
#define CSR_DONE (1u << CSR_V_DONE)
#define CSR_BUSY (1u << CSR_V_BUSY)
#define CSR_ERR (1u << CSR_V_ERR)
/* Timers */
#define TMR_CLK 0 /* 100Hz clock */
/* I/O system definitions */
#define DZ_MUXES 4 /* max # of DZV muxes */
#define DZ_LINES 8 /* lines per DZV mux */
#define VH_MUXES 4 /* max # of DHQ muxes */
#define MT_MAXFR (1 << 16) /* magtape max rec */
#define AUTO_LNT 34 /* autoconfig ranks */
#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */
#define DEV_V_MBUS (DEV_V_UF + 1) /* Massbus */
#define DEV_V_NEXUS (DEV_V_UF + 2) /* Nexus */
#define DEV_V_FLTA (DEV_V_UF + 3) /* flt addr */
#define DEV_V_FFUF (DEV_V_UF + 4) /* first free flag */
#define DEV_UBUS (1u << DEV_V_UBUS)
#define DEV_MBUS (1u << DEV_V_MBUS)
#define DEV_NEXUS (1u << DEV_V_NEXUS)
#define DEV_FLTA (1u << DEV_V_FLTA)
#define DEV_QBUS (0)
#define DEV_Q18 (0)
#define UNIBUS TRUE /* Unibus only */
#define DEV_RDX 16 /* default device radix */
/* Device information block
For Massbus devices,
ba = Massbus number
lnt = Massbus ctrl type
ack[0] = abort routine
For Nexus devices,
ba = Nexus number
lnt = number of consecutive nexi */
#define VEC_DEVMAX 4 /* max device vec */
struct pdp_dib {
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 */
};
typedef struct pdp_dib DIB;
/* Unibus I/O page layout - XUB,RQB,RQC,RQD float based on number of DZ's
Massbus devices (RP, TU) do not appear in the Unibus IO page */
#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */
#define IOLN_DZ 010
#define IOBA_XUB (IOPAGEBASE + 000330 + (020 * (DZ_MUXES / 2)))
#define IOLN_XUB 010
#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2)))
#define IOLN_RQB 004
#define IOBA_RQC (IOPAGEBASE + IOBA_RQB + IOLN_RQB)
#define IOLN_RQC 004
#define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC)
#define IOLN_RQD 004
#define IOBA_RQ (IOPAGEBASE + 012150) /* UDA50 */
#define IOLN_RQ 004
#define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */
#define IOLN_TS 004
#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */
#define IOLN_RL 012
#define IOBA_TQ (IOPAGEBASE + 014500) /* TMSCP */
#define IOLN_TQ 004
#define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */
#define IOLN_XU 010
#define IOBA_RX (IOPAGEBASE + 017170) /* RX11 */
#define IOLN_RX 004
#define IOBA_RY (IOPAGEBASE + 017170) /* RXV21 */
#define IOLN_RY 004
#define IOBA_HK (IOPAGEBASE + 017440) /* RK611 */
#define IOLN_HK 040
#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */
#define IOLN_LPT 004
#define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */
#define IOLN_PTR 004
#define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */
#define IOLN_PTP 004
/* Interrupt assignments; within each level, priority is right to left */
#define INT_V_DZRX 0 /* BR5 */
#define INT_V_DZTX 1
#define INT_V_HK 2
#define INT_V_RL 3
#define INT_V_RQ 4
#define INT_V_TQ 5
#define INT_V_TS 6
#define INT_V_RY 7
#define INT_V_XU 8
#define INT_V_LPT 0 /* BR4 */
#define INT_V_PTR 1
#define INT_V_PTP 2
#define INT_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_PTR (1u << INT_V_PTR)
#define INT_PTP (1u << INT_V_PTP)
#define INT_LPT (1u << INT_V_LPT)
#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_PTR (0x14 - IPL_HMIN)
#define IPL_PTP (0x14 - IPL_HMIN)
#define IPL_LPT (0x14 - IPL_HMIN)
/* Device vectors */
#define VEC_Q 0000
#define VEC_PTR 0070
#define VEC_PTP 0074
#define VEC_XU 0120
#define VEC_RQ 0154
#define VEC_RL 0160
#define VEC_LPT 0200
#define VEC_HK 0210
#define VEC_TS 0224
#define VEC_TQ 0260
#define VEC_RX 0264
#define VEC_RY 0264
#define VEC_DZRX 0300
#define VEC_DZTX 0304
/* Autoconfigure ranks */
#define RANK_DZ 8
#define RANK_RL 14
#define RANK_RX 18
#define RANK_XU 25
#define RANK_RQ 26
#define RANK_TQ 30
#define RANK_VH 32
/* Interrupt macros */
#define IVCL(dv) ((IPL_##dv * 32) + INT_V_##dv)
#define NVCL(dv) ((IPL_##dv * 32) + TR_##dv)
#define IREQ(dv) int_req[IPL_##dv]
#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv)
#define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
/* Logging */
#define LOG_CPU_I 0x1 /* intexc */
#define LOG_CPU_R 0x2 /* REI */
#define LOG_CPU_P 0x4 /* context */
/* Massbus definitions */
#define MBA_RP (TR_MBA0 - TR_MBA0) /* MBA for RP */
#define MBA_TU (TR_MBA1 - TR_MBA0) /* MBA for TU */
#define MBA_RMASK 0x1F /* max 32 reg */
#define MBE_NXD 1 /* nx drive */
#define MBE_NXR 2 /* nx reg */
#define MBE_GOE 3 /* err on GO */
/* Boot definitions */
#define BOOT_MB 0 /* device codes */
#define BOOT_HK 1 /* for VMB */
#define BOOT_RL 2
#define BOOT_UDA 17
#define BOOT_TK 18
/* Function prototypes for I/O */
t_bool map_addr (uint32 qa, uint32 *ma);
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 set_addr (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat auto_config (uint32 rank, uint32 num);
int32 mba_rdbufW (uint32 mbus, int32 bc, uint16 *buf);
int32 mba_wrbufW (uint32 mbus, int32 bc, uint16 *buf);
int32 mba_chbufW (uint32 mbus, int32 bc, uint16 *buf);
int32 mba_get_bc (uint32 mbus);
void mba_upd_ata (uint32 mbus, uint32 val);
void mba_set_exc (uint32 mbus);
void mba_set_don (uint32 mbus);
t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,696 +0,0 @@
/* vax780_mba.c: VAX 11/780 Massbus adapter
Copyright (c) 2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mba0, mba1 RH780 Massbus adapter
*/
#include "vax_defs.h"
/* Massbus */
#define MBA_NMAPR 256 /* number of map reg */
#define MBA_V_RTYPE 10 /* nexus addr: reg type */
#define MBA_M_RTYPE 0x3
#define MBART_INT 0x0 /* internal */
#define MBART_EXT 0x1 /* external */
#define MBART_MAP 0x2 /* map */
#define MBA_V_INTOFS 2 /* int reg: reg ofs */
#define MBA_M_INTOFS 0xFF
#define MBA_V_DRV 7 /* ext reg: drive num */
#define MBA_M_DRV 0x7
#define MBA_V_DEVOFS 2 /* ext reg: reg ofs */
#define MBA_M_DEVOFS 0x1F
#define MBA_RTYPE(x) (((x) >> MBA_V_RTYPE) & MBA_M_RTYPE)
#define MBA_INTOFS(x) (((x) >> MBA_V_INTOFS) & MBA_M_INTOFS)
#define MBA_EXTDRV(x) (((x) >> MBA_V_DRV) & MBA_M_DRV)
#define MBA_EXTOFS(x) (((x) >> MBA_V_DEVOFS) & MBA_M_DEVOFS)
/* Massbus configuration register */
#define MBACNF_OF 0x0
#define MBACNF_ADPDN 0x00800000 /* adap pdn - ni */
#define MBACNF_ADPUP 0x00400000 /* adap pup - ni */
#define MBACNF_CODE 0x00000020
#define MBACNF_RD (SBI_FAULTS|MBACNF_W1C)
#define MBACNF_W1C 0x00C00000
/* Control register */
#define MBACR_OF 0x1
#define MBACR_MNT 0x00000008 /* maint */
#define MBACR_IE 0x00000004 /* int enable */
#define MBACR_ABORT 0x00000002 /* abort */
#define MBACR_INIT 0x00000001
#define MBACR_RD 0x0000000E
#define MBACR_WR 0x0000000E
/* Status register */
#define MBASR_OF 0x2
#define MBASR_DTBUSY 0x80000000 /* DT busy RO */
#define MBASR_NRCONF 0x40000000 /* no conf - ni W1C */
#define MBASR_CRD 0x20000000 /* CRD - ni W1C */
#define MBASR_CBH 0x00800000 /* CBHUNG - ni W1C */
#define MBASR_PGE 0x00080000 /* prog err - W1C int */
#define MBASR_NFD 0x00040000 /* nx drive - W1C int */
#define MBASR_MCPE 0x00020000 /* ctl perr - ni W1C int */
#define MBASR_ATA 0x00010000 /* attn - W1C int */
#define MBASR_SPE 0x00004000 /* silo perr - ni W1C int */
#define MBASR_DTCMP 0x00002000 /* xfr done - W1C int */
#define MBASR_DTABT 0x00001000 /* abort - W1C int */
#define MBASR_DLT 0x00000800 /* dat late - ni W1C abt */
#define MBASR_WCEU 0x00000400 /* wrchk upper - W1C abt */
#define MBASR_WCEL 0x00000200 /* wrchk lower - W1C abt */
#define MBASR_MXF 0x00000100 /* miss xfr - ni W1C abt */
#define MBASR_MBEXC 0x00000080 /* except - ni W1C abt */
#define MBASR_MBDPE 0x00000040 /* dat perr - ni W1C abt */
#define MBASR_MAPPE 0x00000020 /* map perr - ni W1C abt */
#define MBASR_INVM 0x00000010 /* inv map - W1C abt */
#define MBASR_ERCONF 0x00000008 /* err conf - ni W1C abt */
#define MBASR_RDS 0x00000004 /* RDS - ni W1C abt */
#define MBASR_ITMO 0x00000002 /* timeout - W1C abt */
#define MBASR_RTMO 0x00000001 /* rd timeout - W1C abt */
#define MBASR_RD 0xE08F7FFF
#define MBASR_W1C 0x608F7FFF
#define MBASR_ABORTS 0x00000FFF
#define MBASR_INTR 0x000F7000
/* Virtual address register */
#define MBAVA_OF 0x3
#define MBAVA_RD 0x0001FFFF
#define MBAVA_WR (MBAVA_RD)
/* Byte count */
#define MBABC_OF 0x4
#define MBABC_RD 0xFFFFFFFF
#define MBABC_WR 0x0000FFFF
#define MBABC_V_CNT 16 /* active count */
/* Diagnostic register */
#define MBADR_OF 0x5
#define MBADR_RD 0xFFFFFFFF
#define MBADR_WR 0xFFC00000
/* Selected map entry - read only */
#define MBASMR_OF 0x6
#define MBASMR_RD (MBAMAP_RD)
/* Command register (SBI) - read only */
#define MBACMD_OF 0x7
/* External registers */
#define MBA_CS1 0x00 /* device CSR1 */
#define MBA_CS1_WR 0x3F /* writeable bits */
#define MBA_CS1_DT 0x28 /* >= for data xfr */
/* Map registers */
#define MBAMAP_VLD 0x80000000 /* valid */
#define MBAMAP_PAG 0x001FFFFF
#define MBAMAP_RD (MBAMAP_VLD | MBAMAP_PAG)
#define MBAMAP_WR (MBAMAP_RD)
struct mbctx {
uint32 cnf; /* config reg */
uint32 cr; /* control reg */
uint32 sr; /* status reg */
uint32 va; /* virt addr */
uint32 bc; /* byte count */
uint32 dr; /* diag reg */
uint32 smr; /* sel map reg */
uint32 map[MBA_NMAPR]; /* map */
};
typedef struct mbctx MBACTX;
MBACTX massbus[MBA_NUM];
extern uint32 nexus_req[NEXUS_HLVL];
extern UNIT cpu_unit;
extern FILE *sim_log;
extern int32 sim_switches;
t_stat mba_reset (DEVICE *dptr);
t_stat mba_rdreg (int32 *val, int32 pa, int32 mode);
t_stat mba_wrreg (int32 val, int32 pa, int32 lnt);
t_bool mba_map_addr (uint32 va, uint32 *ma, uint32 mb);
void mba_set_int (uint32 mb);
void mba_clr_int (uint32 mb);
void mba_upd_sr (uint32 set, uint32 clr, uint32 mb);
DEVICE mba0_dev, mba1_dev;
DIB mba0_dib, mba1_dib;
extern int32 ReadB (uint32 pa);
extern int32 ReadW (uint32 pa);
extern int32 ReadL (uint32 pa);
extern void WriteB (uint32 pa, int32 val);
extern void WriteW (uint32 pa, int32 val);
extern void WriteL (uint32 pa, int32 val);
/* Maps */
static MBACTX *ctxmap[MBA_NUM] = { &massbus[0], &massbus[1] };
static DEVICE *devmap[MBA_NUM] = { &mba0_dev, &mba1_dev };
/* Massbus register dispatches */
static t_stat (*mbregR[MBA_NUM])(int32 *dat, int32 ad, int32 md);
static t_stat (*mbregW[MBA_NUM])(int32 dat, int32 ad, int32 md);
static int32 (*mbabort[MBA_NUM])(void);
/* Massbus adapter data structures
mba_dev UBA device descriptor
mba_unit UBA units
mba_reg UBA register list
*/
DIB mba0_dib = { TR_MBA0, 0, &mba_rdreg, &mba_wrreg, 0, NVCL (MBA0) };
UNIT mba0_unit = { UDATA (NULL, 0, 0) };
REG mba0_reg[] = {
{ HRDATA (CNFR, massbus[0].cnf, 32) },
{ HRDATA (CR, massbus[0].cr, 4) },
{ HRDATA (SR, massbus[0].sr, 32) },
{ HRDATA (VA, massbus[0].va, 17) },
{ HRDATA (BC, massbus[0].bc, 32) },
{ HRDATA (DR, massbus[0].dr, 32) },
{ HRDATA (SMR, massbus[0].dr, 32) },
{ BRDATA (MAP, massbus[0].map, 16, 32, MBA_NMAPR) },
{ FLDATA (NEXINT, nexus_req[IPL_MBA0], TR_MBA0) },
{ NULL } };
MTAB mba0_mod[] = {
{ MTAB_XTD|MTAB_VDV, TR_MBA0, "NEXUS", NULL,
NULL, &show_nexus },
{ 0 } };
DEVICE mba0_dev = {
"MBA0", &mba0_unit, mba0_reg, mba0_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &mba_reset,
NULL, NULL, NULL,
&mba0_dib, DEV_NEXUS };
DIB mba1_dib = { TR_MBA1, 0, &mba_rdreg, &mba_wrreg, 0, NVCL (MBA0) };
UNIT mba1_unit = { UDATA (NULL, 0, 0) };
MTAB mba1_mod[] = {
{ MTAB_XTD|MTAB_VDV, TR_MBA1, "NEXUS", NULL,
NULL, &show_nexus },
{ 0 } };
REG mba1_reg[] = {
{ HRDATA (CNFR, massbus[1].cnf, 32) },
{ HRDATA (CR, massbus[1].cr, 4) },
{ HRDATA (SR, massbus[1].sr, 32) },
{ HRDATA (VA, massbus[1].va, 17) },
{ HRDATA (BC, massbus[1].bc, 32) },
{ HRDATA (DR, massbus[1].dr, 32) },
{ HRDATA (SMR, massbus[1].dr, 32) },
{ BRDATA (MAP, massbus[1].map, 16, 32, MBA_NMAPR) },
{ FLDATA (NEXINT, nexus_req[IPL_MBA1], TR_MBA1) },
{ NULL } };
DEVICE mba1_dev = {
"MBA1", &mba1_unit, mba1_reg, mba1_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &mba_reset,
NULL, NULL, NULL,
&mba1_dib, DEV_NEXUS };
/* Read Massbus adapter register */
t_stat mba_rdreg (int32 *val, int32 pa, int32 mode)
{
int32 mb, ofs, drv, rtype;
t_stat r;
MBACTX *mbp;
mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */
if (mb >= MBA_NUM) return SCPE_NXM; /* valid? */
mbp = ctxmap[mb]; /* get context */
rtype = MBA_RTYPE (pa); /* get reg type */
switch (rtype) { /* case on type */
case MBART_INT: /* internal */
ofs = MBA_INTOFS (pa); /* check range */
switch (ofs) {
case MBACNF_OF: /* CNF */
*val = (mbp->cnf & MBACNF_RD) | MBACNF_CODE;
break;
case MBACR_OF: /* CR */
*val = mbp->cr & MBACR_RD;
break;
case MBASR_OF: /* SR */
*val = mbp->sr & MBASR_RD;
break;
case MBAVA_OF: /* VA */
*val = mbp->va & MBAVA_RD;
break;
case MBABC_OF: /* BC */
*val = mbp->bc & MBABC_RD;
break;
case MBADR_OF: /* DR */
*val = mbp->dr & MBADR_RD;
break;
case MBASMR_OF: /* SMR */
*val = mbp->smr & MBASMR_RD;
break;
case MBACMD_OF: /* CMD */
*val = 0;
break;
default:
return SCPE_NXM;
}
break;
case MBART_EXT: /* external */
if (!mbregR[mb]) return SCPE_NXM; /* device there? */
drv = MBA_EXTDRV (pa); /* get dev num */
ofs = MBA_EXTOFS (pa); /* get reg offs */
r = mbregR[mb] (val, ofs, drv); /* call device */
if (r == MBE_NXD) mba_upd_sr (MBASR_NFD, 0, mb);/* nx drive? */
else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
break;
case MBART_MAP: /* map */
ofs = MBA_INTOFS (pa);
*val = mbp->map[ofs] & MBAMAP_RD;
break;
default:
return SCPE_NXM; }
return SCPE_OK;
}
/* Write Massbus adapter register */
t_stat mba_wrreg (int32 val, int32 pa, int32 lnt)
{
int32 mb, ofs, drv, rtype;
t_stat r;
t_bool cs1dt;
MBACTX *mbp;
mb = NEXUS_GETNEX (pa) - TR_MBA0; /* get MBA */
if (mb >= MBA_NUM) return SCPE_NXM; /* valid? */
mbp = ctxmap[mb]; /* get context */
rtype = MBA_RTYPE (pa); /* get reg type */
switch (rtype) { /* case on type */
case MBART_INT: /* internal */
ofs = MBA_INTOFS (pa); /* check range */
switch (ofs) {
case MBACNF_OF: /* CNF */
mbp->cnf = mbp->cnf & ~(val & MBACNF_W1C);
break;
case MBACR_OF: /* CR */
if (val & MBACR_INIT) /* init? */
mba_reset (devmap[mb]); /* reset MBA */
if ((val & MBACR_ABORT) && (mbp->sr & MBASR_DTBUSY)) {
if (mbabort[mb]) mbabort[mb] (); /* abort? */
mba_upd_sr (MBASR_DTABT, 0, mb); }
if ((val & MBACR_MNT) && (mbp->sr & MBASR_DTBUSY)) {
mba_upd_sr (MBASR_PGE, 0, mb); /* mnt & xfer? */
val = val & ~MBACR_MNT; }
if ((val & MBACR_IE) == 0) mba_clr_int (mb);
mbp->cr = (mbp->cr & ~MBACR_WR) | (val & MBACR_WR);
break;
case MBASR_OF: /* SR */
mbp->sr = mbp->sr & ~(val & MBASR_W1C);
break;
case MBAVA_OF: /* VA */
if (mbp->sr & MBASR_DTBUSY) /* err if xfr */
mba_upd_sr (MBASR_PGE, 0, mb);
else mbp->va = val & MBAVA_WR;
break;
case MBABC_OF: /* BC */
if (mbp->sr & MBASR_DTBUSY) /* err if xfr */
mba_upd_sr (MBASR_PGE, 0, mb);
else {
val = val & MBABC_WR;
mbp->bc = (val << MBABC_V_CNT) | val;
}
break;
case MBADR_OF: /* DR */
mbp->dr = (mbp->dr & ~MBADR_WR) | (val & MBADR_WR);
break;
default:
return SCPE_NXM;
}
break;
case MBART_EXT: /* external */
if (!mbregW[mb]) return SCPE_NXM; /* device there? */
drv = MBA_EXTDRV (pa); /* get dev num */
ofs = MBA_EXTOFS (pa); /* get reg offs */
cs1dt = (ofs == MBA_CS1) && (val & CSR_GO) && /* starting xfr? */
((val & MBA_CS1_WR) >= MBA_CS1_DT);
if (cs1dt && (mbp->sr & MBASR_DTBUSY)) { /* xfr while busy? */
mba_upd_sr (MBASR_PGE, 0, mb); /* prog error */
break;
}
r = mbregW[mb] (val, ofs, drv); /* write dev reg */
if (r == MBE_NXD) mba_upd_sr (MBASR_NFD, 0, mb);/* nx drive? */
else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
if (cs1dt && (r == SCPE_OK)) /* did dt start? */
mbp->sr = (mbp->sr | MBASR_DTBUSY) & ~MBASR_W1C;
break;
case MBART_MAP: /* map */
ofs = MBA_INTOFS (pa);
mbp->map[ofs] = val & MBAMAP_WR;
break;
default:
return SCPE_NXM; }
return SCPE_OK;
}
/* Massbus I/O routine
mb_rdbufW - fetch word buffer from memory
mb_wrbufW - store word buffer into memory
mb_chbufW - compare word buffer with memory
Returns number of bytes successfully transferred/checked
*/
int32 mba_rdbufW (uint32 mb, int32 bc, uint16 *buf)
{
MBACTX *mbp;
int32 i, j, ba, mbc, pbc;
uint32 pa, dat;
if (mb >= MBA_NUM) return 0; /* valid MBA? */
mbp = ctxmap[mb]; /* get context */
ba = mbp->va; /* get virt addr */
mbc = ((MBABC_WR + 1) - (mbp->bc >> MBABC_V_CNT)) & MBABC_WR; /* get Mbus bc */
if (bc > mbc) bc = mbc; /* use smaller */
for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
if (!mba_map_addr (ba + i, &pa, mb)) break; /* page inv? */
if (!ADDR_IS_MEM (pa)) { /* NXM? */
mba_upd_sr (MBASR_RTMO, 0, mb);
break; }
pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
if ((pa | pbc) & 1) { /* aligned word? */
for (j = 0; j < pbc; pa++, j++) { /* no, bytes */
if ((i + j) & 1) { /* odd byte? */
*buf = (*buf & BMASK) | (ReadB (pa) << 8);
buf++;
}
else *buf = (*buf & ~BMASK) | ReadB (pa);
}
}
else if ((pa | pbc) & 3) { /* aligned LW? */
for (j = 0; j < pbc; pa = pa + 2, j = j + 2) { /* no, words */
*buf++ = ReadW (pa); /* get word */
}
}
else { /* yes, do by LW */
for (j = 0; j < pbc; pa = pa + 4, j = j + 4) {
dat = ReadL (pa); /* get lw */
*buf++ = dat & WMASK; /* low 16b */
*buf++ = (dat >> 16) & WMASK; /* high 16b */
}
}
}
return i;
}
int32 mba_wrbufW (uint32 mb, int32 bc, uint16 *buf)
{
MBACTX *mbp;
int32 i, j, ba, mbc, pbc;
uint32 pa, dat;
if (mb >= MBA_NUM) return 0; /* valid MBA? */
mbp = ctxmap[mb]; /* get context */
ba = mbp->va; /* get virt addr */
mbc = ((MBABC_WR + 1) - (mbp->bc >> MBABC_V_CNT)) & MBABC_WR; /* get Mbus bc */
if (bc > mbc) bc = mbc; /* use smaller */
for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
if (!mba_map_addr (ba + i, &pa, mb)) break; /* page inv? */
if (!ADDR_IS_MEM (pa)) { /* NXM? */
mba_upd_sr (MBASR_RTMO, 0, mb);
break; }
pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
if ((pa | pbc) & 1) { /* aligned word? */
for (j = 0; j < pbc; pa++, j++) { /* no, bytes */
if ((i + j) & 1) {
WriteB (pa, (*buf >> 8) & BMASK);
buf++; }
else WriteB (pa, *buf & BMASK);
}
}
else if ((pa | pbc) & 3) { /* aligned LW? */
for (j = 0; j < pbc; pa = pa + 2, j = j + 2) { /* no, words */
WriteW (pa, *buf); /* write word */
buf++;
}
}
else { /* yes, do by LW */
for (j = 0; j < pbc; pa = pa + 4, j = j + 4) {
dat = (uint32) *buf++; /* get low 16b */
dat = dat | (((uint32) *buf++) << 16); /* merge hi 16b */
WriteL (pa, dat); /* store LW */
}
}
}
return i;
}
int32 mba_chbufW (uint32 mb, int32 bc, uint16 *buf)
{
MBACTX *mbp;
int32 i, j, ba, mbc, pbc;
uint32 pa, dat, cmp;
if (mb >= MBA_NUM) return 0; /* valid MBA? */
mbp = ctxmap[mb]; /* get context */
ba = mbp->va; /* get virt addr */
mbc = ((MBABC_WR + 1) - (mbp->bc >> MBABC_V_CNT)) & MBABC_WR; /* get Mbus bc */
if (bc > mbc) bc = mbc; /* use smaller */
for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
if (!mba_map_addr (ba + i, &pa, mb)) break; /* page inv? */
if (!ADDR_IS_MEM (pa)) { /* NXM? */
mba_upd_sr (MBASR_RTMO, 0, mb);
break; }
pbc = VA_PAGSIZE - VA_GETOFF (pa); /* left in page */
if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
for (j = 0; j < pbc; j++, pa++) { /* byte by byte */
cmp = ReadB (pa);
if ((i + j) & 1) dat = (*buf++ >> 8) & BMASK;
else dat = *buf & BMASK;
if (cmp != dat) {
mba_upd_sr ((j & 1)? MBASR_WCEU: MBASR_WCEL, 0, mb);
break;
} /* end if */
} /* end for j */
} /* end for i */
return i;
}
/* Map an address via the translation map */
t_bool mba_map_addr (uint32 va, uint32 *ma, uint32 mb)
{
MBACTX *mbp = ctxmap[mb];
uint32 vblk = (va >> VA_V_VPN); /* map index */
uint32 mmap = mbp->map[vblk]; /* get map */
mbp->smr = mmap; /* save map reg */
if (mmap & MBAMAP_VLD) { /* valid? */
*ma = ((mmap & MBAMAP_PAG) << VA_V_VPN) + VA_GETOFF (va);
return 1; } /* legit addr */
mba_upd_sr (MBASR_INVM, 0, mb); /* invalid map */
return 0;
}
/* Device access, status, and interrupt routines */
void mba_set_don (uint32 mb)
{
mba_upd_sr (MBASR_DTCMP, 0, mb);
return;
}
void mba_upd_ata (uint32 mb, uint32 val)
{
if (val) mba_upd_sr (MBASR_ATA, 0, mb);
else mba_upd_sr (0, MBASR_ATA, mb);
return;
}
void mba_set_exc (uint32 mb)
{
mba_upd_sr (MBASR_MBEXC, 0, mb);
return;
}
int32 mba_get_bc (uint32 mb)
{
MBACTX *mbp;
if (mb >= MBA_NUM) return 0;
mbp = ctxmap[mb];
return (((MBABC_WR + 1) - (mbp->bc >> MBABC_V_CNT)) & MBABC_WR);
}
void mba_set_int (uint32 mb)
{
DEVICE *dptr;
DIB *dibp;
if (mb >= MBA_NUM) return;
dptr = devmap[mb];
dibp = (DIB *) dptr->ctxt;
nexus_req[dibp->vloc >> 5] |= (1u << (dibp->vloc & 0x1F));
return;
}
void mba_clr_int (uint32 mb)
{
DEVICE *dptr;
DIB *dibp;
if (mb >= MBA_NUM) return;
dptr = devmap[mb];
dibp = (DIB *) dptr->ctxt;
nexus_req[dibp->vloc >> 5] &= ~(1u << (dibp->vloc & 0x1F));
return;
}
void mba_upd_sr (uint32 set, uint32 clr, uint32 mb)
{
MBACTX *mbp;
if (mb >= MBA_NUM) return;
mbp = ctxmap[mb];
if (set & MBASR_ABORTS) set |= (MBASR_DTCMP|MBASR_DTABT);
if (set & (MBASR_DTCMP|MBASR_DTABT)) mbp->sr &= ~MBASR_DTBUSY;
mbp->sr = (mbp->sr | set) & ~clr;
if ((set & MBASR_INTR) && (mbp->cr & MBACR_IE))
mba_set_int (mb);
return;
}
/* Reset Massbus adapter */
t_stat mba_reset (DEVICE *dptr)
{
int32 i, mb;
DIB *dibp;
MBACTX *mbp;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
mb = dibp->ba - TR_MBA0;
if ((mb < 0) || (mb >= MBA_NUM)) return SCPE_IERR;
mbp = ctxmap[mb];
mbp->cnf = 0;
mbp->cr = mbp->cr & MBACR_MNT;
mbp->sr = 0;
mbp->bc = 0;
mbp->va = 0;
mbp->dr = 0;
mbp->smr = 0;
if (sim_switches & SWMASK ('P')) {
for (i = 0; i < MBA_NMAPR; i++) mbp->map[i] = 0;
}
if (mbabort[mb]) mbabort[mb] (); /* reset device */
return SCPE_OK;
}
/* Show Massbus adapter number */
t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc)
{
DEVICE *dptr = find_dev_from_unit (uptr);
DIB *dibp;
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
fprintf (st, "Massbus adapter %d", dibp->ba);
return SCPE_OK;
}
/* Init Mbus tables */
void init_mbus_tab (void)
{
uint32 i;
for (i = 0; i < MBA_NUM; i++) {
mbregR[i] = NULL;
mbregW[i] = NULL;
mbabort[i] = NULL;
}
return;
}
/* Build dispatch tables */
t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp)
{
uint32 idx;
if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */
idx = dibp->ba; /* Mbus # */
if (idx >= MBA_NUM) return SCPE_STOP;
if ((mbregR[idx] && dibp->rd && /* conflict? */
(mbregR[idx] != dibp->rd)) ||
(mbregW[idx] && dibp->wr &&
(mbregW[idx] != dibp->wr)) ||
(mbabort[idx] && dibp->ack[0] &&
(mbabort[idx] != dibp->ack[0]))) {
printf ("Massbus %s assignment conflict at %d\n",
sim_dname (dptr), dibp->ba);
if (sim_log) fprintf (sim_log,
"Massbus %s assignment conflict at %d\n",
sim_dname (dptr), dibp->ba);
return SCPE_STOP;
}
if (dibp->rd) mbregR[idx] = dibp->rd; /* set rd dispatch */
if (dibp->wr) mbregW[idx] = dibp->wr; /* set wr dispatch */
if (dibp->ack[0]) mbabort[idx] = dibp->ack[0]; /* set abort dispatch */
return SCPE_OK;
}

View File

@@ -1,901 +0,0 @@
/* vax780_sbimem.c: VAX 11/780 SBI and memory controller
Copyright (c) 2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This module contains the VAX 11/780 system-specific registers and devices.
mctl0, mctl1 MS780C/E memory controllers
sbi bus controller
*/
#include "vax_defs.h"
/* 11/780 specific IPRs */
/* Writeable control store */
#define WCSA_RW 0xFFFF /* writeable */
#define WCSA_ADDR 0x1FFF /* addr */
#define WCSA_CTR 0x6000 /* counter */
#define WCSA_CTR_INC 0x2000 /* increment */
#define WCSA_CTR_MAX 0x6000 /* max value */
#define WCSD_RD_VAL 0xFF /* fixed read val */
#define WCSD_WR 0xFFFFFFFF /* write */
#define MBRK_RW 0x1FFF /* microbreak */
/* System registers */
#define SBIFS_RD (0x031F0000|SBI_FAULTS) /* SBI faults */
#define SBIFS_WR 0x03140000
#define SBIFS_W1C 0x00080000
#define SBISC_RD 0xFFFF0000 /* SBI silo comp */
#define SBISC_WR 0x7FFF0000
#define SBISC_LOCK 0x80000000 /* lock */
#define SBIMT_RD 0xFFFFFF00 /* SBI maint */
#define SBIMT_WR 0xFFFFF900
#define SBIER_CRDIE 0x00008000 /* SBI error, CRD IE */
#define SBIER_CRD 0x00004000 /* CRD */
#define SBIER_RDS 0x00002000 /* RDS */
#define SBIER_TMO 0x00001000 /* timeout */
#define SBIER_STA 0x00000C00 /* timeout status (0) */
#define SBIER_CNF 0x00000100 /* error confirm */
#define SBIER_IBRDS 0x00000080
#define SBIER_IBTMO 0x00000040
#define SBIER_IBSTA 0x00000030
#define SBIER_IBCNF 0x00000008
#define SBIER_MULT 0x00000004 /* multiple errors */
#define SBIER_FREE 0x00000002 /* SBI free */
#define SBIER_RD 0x0000FDFE
#define SBIER_WR 0x00008000
#define SBIER_W1C 0x000070C0
#define SBIER_TMOW1C (SBIER_TMO|SBIER_STA|SBIER_CNF|SBIER_MULT)
#define SBIER_IBTW1C (SBIER_IBTMO|SBIER_STA|SBIER_IBCNF)
#define SBITMO_V_MODE 30 /* mode */
#define SBITMO_VIRT 0x20000000 /* physical */
/* Memory controller register A */
#define MCRA_OF 0x0
#define MCRA_SUMM 0x00100000 /* err summ (MS780E) */
#define MCRA_C_SIZE 0x00007C00 /* array size - fixed */
#define MCRA_V_SIZE 9
#define MCRA_ILVE 0x00000100 /* interleave wr enab */
#define MCRA_TYPE 0x000000F8 /* type */
#define MCRA_C_TYPE 0x00000010 /* 16k uninterleaved */
#define MCRA_E_TYPE 0x0000006A /* 256k upper + lower */
#define MCRA_ILV 0x00000007 /* interleave */
#define MCRA_RD (0x00107FFF|SBI_FAULTS)
#define MCRA_WR 0x00000100
/* Memory controller register B */
#define MCRB_OF 0x1
#define MCRB_FP 0xF0000000 /* file pointers */
#define MCRB_V_SA 15 /* start addr */
#define MCRB_M_SA 0x1FFF
#define MCRB_SA (MCRB_M_SA << MCRB_V_SA)
#define MCRB_SAE 0x00004000 /* start addr wr enab */
#define MCRB_INIT 0x00003000 /* init state */
#define MCRB_REF 0x00000400 /* refresh */
#define MCRB_ECC 0x000003FF /* ECC for diags */
#define MCRB_RD 0xFFFFF7FF
#define MCRB_WR 0x000043FF
/* Memory controller register C,D */
#define MCRC_OF 0x2
#define MCRD_OF 0x3
#define MCRC_DCRD 0x40000000 /* disable CRD */
#define MCRC_HER 0x20000000 /* high error rate */
#define MCRC_ERL 0x10000000 /* log error */
#define MCRC_C_ER 0x0FFFFFFF /* MS780C error */
#define MCRC_E_PE1 0x00080000 /* MS780E par ctl 1 */
#define MCRC_E_PE0 0x00040000 /* MS780E par ctl 0 */
#define MCRC_E_CRD 0x00000200 /* MS780E CRD */
#define MCRC_E_PEW 0x00000100 /* MS780E par err wr */
#define MCRC_E_USEQ 0x00000080 /* MS780E seq err */
#define MCRC_C_RD 0x7FFFFFFF
#define MCRC_E_RD 0x700C0380
#define MCRC_WR 0x40000000
#define MCRC_C_W1C 0x30000000
#define MCRC_E_W1C 0x300C0380
#define MCRMAX_OF 0x4
#define MCRROM_OF 0x400
/* VAX-11/780 boot device definitions */
struct boot_dev {
char *name;
int32 code;
int32 let;
};
uint32 wcs_addr = 0;
uint32 wcs_data = 0;
uint32 wcs_mbrk = 0;
uint32 nexus_req[NEXUS_HLVL]; /* nexus int req */
uint32 sbi_fs = 0; /* SBI fault status */
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 */
uint32 mcr_a[MCTL_NUM];
uint32 mcr_b[MCTL_NUM];
uint32 mcr_c[MCTL_NUM];
uint32 mcr_d[MCTL_NUM];
uint32 rom_lw[MCTL_NUM][ROMSIZE >> 2];
static t_stat (*nexusR[NEXUS_NUM])(int32 *dat, int32 ad, int32 md);
static t_stat (*nexusW[NEXUS_NUM])(int32 dat, int32 ad, int32 md);
static struct boot_dev boot_tab[] = {
{ "RP", BOOT_MB, 0 },
{ "HK", BOOT_HK, 0 },
{ "RL", BOOT_RL, 0 },
{ "RQ", BOOT_UDA, 'A' << 24 },
{ "TQ", BOOT_TK, 'A' << 24 },
{ 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 cpu_extmem;
extern int32 crd_err, mem_err, hlt_pin;
extern int32 tmr_int, tti_int, tto_int;
extern jmp_buf save_env;
extern int32 p1;
extern int32 sim_switches;
extern UNIT cpu_unit;
extern DEVICE *sim_devices[];
extern FILE *sim_log;
extern CTAB *sim_vm_cmd;
t_stat sbi_reset (DEVICE *dptr);
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);
void sbi_set_tmo (int32 pa);
t_stat vax780_boot (int32 flag, char *ptr);
void uba_eval_int (void);
extern void Write (uint32 va, int32 val, int32 lnt, int32 acc);
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 (void);
extern int32 todr_rd (void);
extern int32 rxcs_rd (void);
extern int32 rxdb_rd (void);
extern int32 txcs_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 init_mbus_tab (void);
extern void init_ubus_tab (void);
extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp);
extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp);
/* SBI data structures
sbi_dev SBI device descriptor
sbi_unit SBI unit
sbi_reg SBI register list
*/
UNIT sbi_unit = { UDATA (NULL, 0, 0) };
REG sbi_reg[] = {
{ HRDATA (NREQ14, nexus_req[0], 16) },
{ HRDATA (NREQ15, nexus_req[1], 16) },
{ HRDATA (NREQ16, nexus_req[2], 16) },
{ HRDATA (NREQ17, nexus_req[3], 16) },
{ HRDATA (WCSA, wcs_addr, 16) },
{ HRDATA (WCSD, wcs_data, 32) },
{ HRDATA (MBRK, wcs_mbrk, 13) },
{ HRDATA (SBIFS, sbi_fs, 32) },
{ HRDATA (SBISC, sbi_sc, 32) },
{ HRDATA (SBIMT, sbi_mt, 32) },
{ HRDATA (SBIER, sbi_er, 32) },
{ HRDATA (SBITMO, sbi_tmo, 32) },
{ NULL } };
DEVICE sbi_dev = {
"SBI", &sbi_unit, sbi_reg, NULL,
1, 16, 16, 1, 16, 8,
NULL, NULL, &sbi_reset,
NULL, NULL, NULL,
NULL, 0 };
/* MCTLx data structures
mctlx_dev MCTLx device descriptor
mctlx_unit MCTLx unit
mctlx_reg MCTLx register list
*/
DIB mctl0_dib[] = { TR_MCTL0, 0, &mctl_rdreg, &mctl_wrreg, 0 };
UNIT mctl0_unit = { UDATA (NULL, 0, 0) };
REG mctl0_reg[] = {
{ HRDATA (CRA, mcr_a[0], 32) },
{ HRDATA (CRB, mcr_b[0], 32) },
{ HRDATA (CRC, mcr_c[0], 32) },
{ HRDATA (CRD, mcr_d[0], 32) },
{ BRDATA (ROM, rom_lw[0], 16, 32, ROMSIZE >> 2) },
{ NULL } };
MTAB mctl0_mod[] = {
{ MTAB_XTD|MTAB_VDV, TR_MCTL0, "NEXUS", NULL,
NULL, &show_nexus },
{ 0 } };
DEVICE mctl0_dev = {
"MCTL0", &mctl0_unit, mctl0_reg, mctl0_mod,
1, 16, 16, 1, 16, 8,
NULL, NULL, &mctl_reset,
NULL, NULL, NULL,
&mctl0_dib, DEV_NEXUS };
DIB mctl1_dib[] = { TR_MCTL1, 0, &mctl_rdreg, &mctl_wrreg, 0 };
UNIT mctl1_unit = { UDATA (NULL, 0, 0) };
MTAB mctl1_mod[] = {
{ MTAB_XTD|MTAB_VDV, TR_MCTL1, "NEXUS", NULL,
NULL, &show_nexus },
{ 0 } };
REG mctl1_reg[] = {
{ HRDATA (CRA, mcr_a[1], 32) },
{ HRDATA (CRB, mcr_b[1], 32) },
{ HRDATA (CRC, mcr_c[1], 32) },
{ HRDATA (CRD, mcr_d[1], 32) },
{ BRDATA (ROM, rom_lw[1], 16, 32, ROMSIZE >> 2) },
{ NULL } };
DEVICE mctl1_dev = {
"MCTL1", &mctl1_unit, mctl1_reg, mctl1_mod,
1, 16, 16, 1, 16, 8,
NULL, NULL, &mctl_reset,
NULL, NULL, NULL,
&mctl1_dib, DEV_NEXUS };
DIB mctl_dib[] = { TR_MCTL0, 2, &mctl_rdreg, &mctl_wrreg, 0 };
/* Special boot command, overrides regular boot */
CTAB vax780_cmd[] = {
{ "BOOT", &vax780_boot, RU_BOOT,
"bo{ot} <device>{/R5:flg} boot device\n" },
{ NULL } };
/* The VAX 11/780 has three sources of interrupts
- internal device interrupts (CPU, console, clock)
- nexus interupts (e.g., memory controller, MBA, UBA)
- external device interrupts (Unibus)
Internal devices vector to fixed SCB locations.
Nexus interrupts vector to an SCB location based on this
formula: SCB_NEXUS + ((IPL - 0x14) * 0x40) + (TR# * 0x4)
External device interrupts do not vector directly.
Instead, the interrupt handler for a given UBA IPL
reads a vector register that contains the Unibus vector
for that IPL.
/* Find highest priority vectorable interrupt */
int32 eval_int (void)
{
int32 ipl = PSL_GETIPL (PSL);
int32 i, t;
static const int32 sw_int_mask[IPL_SMAX] = {
0xFFFE, 0xFFFC, 0xFFF8, 0xFFF0, /* 0 - 3 */
0xFFE0, 0xFFC0, 0xFF80, 0xFF00, /* 4 - 7 */
0xFE00, 0xFC00, 0xF800, 0xF000, /* 8 - B */
0xE000, 0xC000, 0x8000 }; /* C - E */
if (hlt_pin) return IPL_HLTPIN; /* hlt pin int */
if ((ipl < IPL_MEMERR) && mem_err) return IPL_MEMERR; /* mem err int */
if ((ipl < IPL_CRDERR) && crd_err) return IPL_CRDERR; /* crd err int */
if ((ipl < IPL_CLKINT) && tmr_int) return IPL_CLKINT; /* clock int */
uba_eval_int (); /* update UBA */
for (i = IPL_HMAX; i >= IPL_HMIN; i--) { /* chk hwre int */
if (i <= ipl) return 0; /* at ipl? no int */
if (nexus_req[i - IPL_HMIN]) return i; } /* req != 0? int */
if ((ipl < IPL_TTINT) && (tti_int || tto_int)) /* console int */
return IPL_TTINT;
if (ipl >= IPL_SMAX) return 0; /* ipl >= sw max? */
if ((t = SISR & sw_int_mask[ipl]) == 0) return 0; /* eligible req */
for (i = IPL_SMAX; i > ipl; i--) { /* check swre int */
if ((t >> i) & 1) return i; } /* req != 0? int */
return 0;
}
/* Return vector for highest priority hardware interrupt at IPL lvl */
int32 get_vector (int32 lvl)
{
int32 i;
int32 l = lvl - IPL_HMIN;
if (lvl == IPL_MEMERR) { /* mem error? */
mem_err = 0;
return SCB_MEMERR; }
if (lvl == IPL_CRDERR) { /* CRD error? */
crd_err = 0;
return SCB_CRDERR; }
if ((lvl == IPL_CLKINT) && tmr_int) { /* 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? */
for (i = 0; nexus_req[l] && (i < NEXUS_NUM); i++) {
if ((nexus_req[l] >> i) & 1) {
nexus_req[l] = nexus_req[l] & ~(1u << i);
return SCB_NEXUS + (l << 6) + (i << 2); /* return vector */
}
}
}
if (lvl == IPL_TTINT) { /* console? */
if (tti_int) { /* input? */
tti_int = 0; /* clear req */
return SCB_TTI; } /* return vector */
if (tto_int) { /* output? */
tto_int = 0; /* clear req */
return SCB_TTO; } /* return vector */
}
return 0;
}
/* Read 780-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 ();
break;
case MT_TODR: /* TODR */
val = todr_rd ();
break;
case MT_ACCS: /* ACCS (not impl) */
val = 0;
break;
case MT_WCSA: /* WCSA */
val = wcs_addr & WCSA_RW;
break;
case MT_WCSD: /* WCSD */
val = WCSD_RD_VAL;
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_TXDB: /* TXDB */
val = 0;
break;
case MT_SBIFS: /* SBIFS */
val = sbi_fs & SBIFS_RD;
break;
case MT_SBIS: /* SBIS */
val = 0;
break;
case MT_SBISC: /* SBISC */
val = sbi_sc & SBISC_RD;
break;
case MT_SBIMT: /* SBIMT */
val = sbi_mt & SBIMT_RD;
break;
case MT_SBIER: /* SBIER */
val = sbi_er & SBIER_RD;
break;
case MT_SBITA: /* SBITA */
val = sbi_tmo;
break;
case MT_MBRK: /* MBRK */
val = wcs_mbrk & MBRK_RW;
break;
case MT_SID: /* SID */
val = VAX780_SID | VAX780_ECO | VAX780_PLANT | VAX780_SN;
break;
default:
RSVD_OPND_FAULT;
}
return val;
}
/* Write 780-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_WCSA: /* WCSA */
wcs_addr = val & WCSA_RW;
break;
case MT_WCSD: /* WCSD */
wcs_data = val & WCSD_WR;
wcs_addr = (wcs_addr & ~WCSA_CTR) |
((wcs_addr + WCSA_CTR_INC) & WCSA_CTR);
if ((wcs_addr & WCSA_CTR) == WCSA_CTR_MAX)
wcs_addr = (wcs_addr & ~WCSA_ADDR) |
((wcs_addr + 1) & WCSA_ADDR);
break;
case MT_RXCS: /* RXCS */
rxcs_wr (val);
break;
case MT_RXDB: /* RXDB */
break;
case MT_TXCS: /* TXCS */
txcs_wr (val);
break;
case MT_TXDB: /* TXDB */
txdb_wr (val);
break;
case MT_SBIFS: /* SBIFS */
sbi_fs = (sbi_fs & ~SBIFS_WR) | (val & SBIFS_WR);
sbi_fs = sbi_fs & ~(val & SBIFS_W1C);
break;
case MT_SBISC: /* SBISC */
sbi_sc = (sbi_sc & ~(SBISC_LOCK|SBISC_WR)) | (val & SBISC_WR);
break;
case MT_SBIMT: /* SBIMT */
sbi_mt = (sbi_mt & ~SBIMT_WR) | (val & SBIMT_WR);
break;
case MT_SBIER: /* SBIER */
sbi_er = (sbi_er & ~SBIER_WR) | (val & SBIER_WR);
sbi_er = sbi_er & ~(val & SBIER_W1C);
if (val & SBIER_TMO) sbi_er = sbi_er & ~SBIER_TMOW1C;
if (val & SBIER_IBTMO) sbi_er = sbi_er & ~SBIER_IBTW1C;
if ((sbi_er & SBIER_CRDIE) && (sbi_er & SBIER_CRD))
crd_err = 1;
else crd_err = 0;
break;
case MT_SBIQC:
// tbd /* SBIQC */
break;
case MT_MBRK: /* MBRK */
wcs_mbrk = val & MBRK_RW;
break;
default:
RSVD_OPND_FAULT;
}
return;
}
/* ReadReg - read register space
Inputs:
pa = physical address
lnt = length (BWLQ) - ignored
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;
}
}
sbi_set_tmo (pa); /* timeout */
MACH_CHECK (MCHK_RD_F); /* machine check */
return 0;
}
/* WriteReg - write register space
Inputs:
pa = physical address
val = data to write, right justified in 32b longword
lnt = length (BWLQ)
Outputs:
none
*/
void WriteReg (int32 pa, int32 val, int32 lnt)
{
int32 nexus;
if (ADDR_IS_REG (pa)) { /* reg space? */
nexus = NEXUS_GETNEX (pa); /* get nexus */
if (nexusW[nexus] && /* valid? */
(nexusW[nexus] (val, pa, lnt) == SCPE_OK)) {
SET_IRQL;
return;
}
}
sbi_set_tmo (pa); /* timeout */
mem_err = 1; /* interrupt */
eval_int ();
return;
}
/* Set SBI timeout */
void sbi_set_tmo (int32 pa)
{
if ((sbi_er & SBIER_TMO) == 0) { /* not yet set? */
sbi_tmo = pa >> 2; /* save addr */
if (mchk_ref == REF_V) sbi_tmo |= SBITMO_VIRT | /* virt? add mode */
(PSL_GETCUR (PSL) << SBITMO_V_MODE);
sbi_er |= SBIER_TMO; } /* set tmo flag */
else sbi_er |= SBIER_MULT; /* yes, multiple */
return;
}
/* Memory controller register read */
t_stat mctl_rdreg (int32 *val, int32 pa, int32 mode)
{
int32 mctl, ofs;
mctl = NEXUS_GETNEX (pa) - TR_MCTL0; /* get mctl num */
ofs = NEXUS_GETOFS (pa); /* get offset */
if (ofs >= MCRROM_OF) { /* ROM? */
*val = rom_lw[mctl][ofs - MCRROM_OF]; /* get lw */
return SCPE_OK;
}
if (ofs >= MCRMAX_OF) return SCPE_NXM; /* in range? */
switch (ofs) {
case MCRA_OF: /* CR A */
*val = mcr_a[mctl] & MCRA_RD;
break;
case MCRB_OF: /* CR B */
*val = (mcr_b[mctl] & MCRB_RD) | MCRB_INIT;
break;
case MCRC_OF: /* CR C */
*val = mcr_c[mctl] & (cpu_extmem? MCRC_E_RD: MCRC_C_RD);
break;
case MCRD_OF: /* CR D */
if (!cpu_extmem) return SCPE_NXM; /* MS780E only */
*val = mcr_d[mctl] & MCRC_E_RD;
break;
}
return SCPE_OK;
}
/* Memory controller register write */
t_stat mctl_wrreg (int32 val, int32 pa, int32 mode)
{
int32 mctl, ofs, mask;
mctl = NEXUS_GETNEX (pa) - TR_MCTL0; /* get mctl num */
ofs = NEXUS_GETOFS (pa); /* get offset */
if (ofs >= MCRMAX_OF) return SCPE_NXM; /* in range? */
switch (ofs) {
case MCRA_OF: /* CR A */
mask = MCRA_WR | ((val & MCRA_ILVE)? MCRA_ILV: 0);
mcr_a[mctl] = (mcr_a[mctl] & ~mask) | (val & mask);
break;
case MCRB_OF: /* CR B */
mask = MCRB_WR | ((val & MCRB_SAE)? MCRB_SA: 0);
mcr_b[mctl] = (mcr_b[mctl] & ~mask) | (val & mask);
break;
case MCRC_OF: /* CR C */
mcr_c[mctl] = ((mcr_c[mctl] & MCRC_WR) | (val & MCRC_WR)) &
~(val & (cpu_extmem? MCRC_E_W1C: MCRC_C_W1C));
break;
case MCRD_OF: /* CR D */
if (!cpu_extmem) return SCPE_NXM; /* MS780E only */
mcr_d[mctl] = ((mcr_d[mctl] & MCRC_WR) | (val & MCRC_WR)) &
~(val & MCRC_E_W1C);
break;
}
return SCPE_OK;
}
/* Used by CPU and loader */
void rom_wr_B (int32 pa, int32 val)
{
uint32 mctl = NEXUS_GETNEX (pa) - TR_MCTL0; /* get mctl num */
uint32 ofs = NEXUS_GETOFS (pa) - MCRROM_OF; /* get offset */
int32 sc = (pa & 3) << 3;
rom_lw[mctl][ofs] = ((val & 0xFF) << sc) | (rom_lw[mctl][ofs] & ~(0xFF << sc));
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 acc, err;
err = (GET_TRAP (trpirq) << 4) | (pme << 3) | ASTLVL; /* error word */
cc = intexc (SCB_MCHK, cc, 0, IE_SVE); /* take exception */
acc = ACC_MASK (KERN); /* in kernel mode */
in_ie = 1;
SP = SP - 44; /* push 11 words */
Write (SP, 40, L_LONG, WA); /* # bytes */
Write (SP + 4, p1, L_LONG, WA); /* mcheck type */
Write (SP + 8, err, L_LONG, WA); /* CPU error status */
Write (SP + 12, 0, L_LONG, WA); /* uPC */
Write (SP + 16, mchk_va, L_LONG, WA); /* VA */
Write (SP + 20, 0, L_LONG, WA); /* D register */
Write (SP + 24, mapen, L_LONG, WA); /* TB status 1 */
Write (SP + 28, 0, L_LONG, WA); /* TB status 2 */
Write (SP + 32, sbi_tmo, L_LONG, WA); /* SBI timeout addr */
Write (SP + 36, 0, L_LONG, WA); /* cache status */
Write (SP + 40, sbi_er, L_LONG, WA); /* SBI error */
in_ie = 0;
return cc;
}
/* Console entry */
int32 con_halt (int32 code, int32 cc)
{
ABORT (STOP_HALT);
return cc;
}
/* Special boot command - linked into SCP by initial reset
Syntax: BOOT <device>{/R5:val}
Sets up R0-R5, calls SCP boot processor with effective BOOT CPU
*/
t_stat vax780_boot (int32 flag, char *ptr)
{
char gbuf[CBUFSIZE];
char *slptr, *regptr;
int32 i, r5v, unitno;
DEVICE *dptr;
UNIT *uptr;
DIB *dibp;
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) return SCPE_ARG;
unitno = uptr - dptr->units;
r5v = 0;
if ((strncmp (regptr, "/R5:", 4) == 0) ||
(strncmp (regptr, "/R5=", 4) == 0) ||
(strncmp (regptr, "/r5:", 4) == 0) ||
(strncmp (regptr, "/r5=", 4) == 0)) {
r5v = (int32) get_uint (regptr + 4, 16, LMASK, &r);
if (r != SCPE_OK) return r; }
else if (*regptr != 0) return SCPE_ARG;
for (i = 0; boot_tab[i].name != NULL; i++) {
if (strcmp (dptr->name, boot_tab[i].name) == 0) {
R[0] = boot_tab[i].code;
if (dptr->flags & DEV_MBUS) {
R[1] = dibp->ba + TR_MBA0;
R[2] = unitno;
}
else {
R[1] = TR_UBA;
R[2] = boot_tab[i].let | (dibp->ba & UBADDRMASK);
}
R[3] = unitno;
R[4] = 0;
R[5] = r5v;
return run_cmd (flag, "CPU");
}
}
return SCPE_NOFNC;
}
/* Bootstrap - finish up bootstrap process */
t_stat cpu_boot (int32 unitno, DEVICE *dptr)
{
t_stat r;
printf ("Loading boot code from vmb780.bin\n");
if (sim_log) fprintf (sim_log,
"Loading boot code from vmb780.bin\n");
r = load_cmd (0, "-O vmb780.bin 200");
if (r != SCPE_OK) return r;
SP = PC = 512;
return SCPE_OK;
}
/* SBI reset */
t_stat sbi_reset (DEVICE *dptr)
{
wcs_addr = 0;
wcs_data = 0;
wcs_mbrk = 0;
sbi_fs = 0;
sbi_sc = 0;
sbi_mt = 0;
sbi_er = 0;
sbi_tmo = 0;
sim_vm_cmd = vax780_cmd;
return SCPE_OK;
}
/* MEMCTL reset */
t_stat mctl_reset (DEVICE *dptr)
{
int32 i, amb;
amb = (MEMSIZE / 2) >> 20; /* array size MB */
for (i = 0; i < MCTL_NUM; i++) { /* init for MS780C */
if (cpu_extmem) { /* extended memory? */
mcr_a[i] = (amb << MCRA_V_SIZE) | MCRA_E_TYPE;
mcr_b[i] = MCRB_INIT | ((i * amb) << MCRB_V_SA);
}
else {
mcr_a[i] = MCRA_C_SIZE | MCRA_C_TYPE;
mcr_b[i] = MCRB_INIT | (i << 21);
}
mcr_c[i] = 0;
mcr_d[i] = 0;
}
return SCPE_OK;
}
/* Show nexus */
t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc)
{
fprintf (st, "nexus=%d", val);
return SCPE_OK;
}
/* Init nexus tables */
void init_nexus_tab (void)
{
uint32 i;
for (i = 0; i < NEXUS_NUM; i++) {
nexusR[i] = NULL;
nexusW[i] = NULL;
}
return;
}
/* Build nexus tables
Inputs:
dptr = pointer to device
dibp = pointer to DIB
Outputs:
status
*/
t_stat build_nexus_tab (DEVICE *dptr, DIB *dibp)
{
uint32 idx;
if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR;
idx = dibp->ba;
if (idx >= NEXUS_NUM) return SCPE_IERR;
if ((nexusR[idx] && dibp->rd && /* conflict? */
(nexusR[idx] != dibp->rd)) ||
(nexusW[idx] && dibp->wr &&
(nexusW[idx] != dibp->wr))) {
printf ("Nexus %s conflict at %d\n",
sim_dname (dptr), dibp->ba);
if (sim_log) fprintf (sim_log,
"Nexus %s conflict at %d\n",
sim_dname (dptr), dibp->ba);
return SCPE_STOP;
}
if (dibp->rd) nexusR[idx] = dibp->rd; /* set rd dispatch */
if (dibp->wr) nexusW[idx] = dibp->wr; /* set wr dispatch */
return SCPE_OK;
}
/* Build dib_tab from device list */
t_stat build_dib_tab (void)
{
uint32 i;
DEVICE *dptr;
DIB *dibp;
t_stat r;
init_nexus_tab ();
init_ubus_tab ();
init_mbus_tab ();
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
if (dptr->flags & DEV_NEXUS) { /* Nexus? */
if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */
return r;
}
else if (dptr->flags & DEV_MBUS) { /* Massbus? */
if (r = build_mbus_tab (dptr, dibp))
return r;
}
else { /* no, Unibus device */
if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */
return r;
} /* end else */
} /* end if enabled */
} /* end for */
return SCPE_OK;
}

View File

@@ -1,851 +0,0 @@
/* vax780_stddev.c: VAX 11/780 standard I/O devices
Copyright (c) 1998-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
tti console input
tto console output
rx console floppy
todr TODR clock
tmr interval timer
08-Sep-04 RMS Cloned from vax_stddev.c, vax_sysdev.c, and pdp11_rx.c
The console floppy protocol is based on the description in the 1982 VAX
Architecture Reference Manual:
TXDB<11:8> = 0 -> normal console output
TXDB<11:8> = 1 -> data output to floppy
TXDB<11:8> = 9 -> command output to floppy
TXDB<11:8> = F -> flag output (e.g., reboot)
RXDB<11:8> = 0 -> normal terminal input
RXDB<11:8> = 1 -> data input from floppy
RXDB<11:8> = 2 -> status input from floppy
RXDB<11:8> = 9 -> "command" input from floppy (protocol error)
*/
#include "vax_defs.h"
#include <time.h>
/* Terminal definitions */
#define RXCS_RD (CSR_DONE + CSR_IE) /* terminal input */
#define RXCS_WR (CSR_IE)
#define RXDB_ERR 0x8000 /* error */
#define RXDB_OVR 0x4000 /* overrun */
#define RXDB_FRM 0x2000 /* framing error */
#define RXDB_RBR 0x0400 /* receive break */
#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_FDAT 0x1 /* floppy data */
#define TXDB_FCMD 0x9 /* floppy cmd */
#define TXDB_MISC 0xF /* console misc */
#define TXDB_SEL (TXDB_M_SEL << TXDB_V_SEL) /* non-terminal */
#define TXDB_GETSEL(x) (((x) >> TXDB_V_SEL) & TXDB_M_SEL)
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B mode */
#define UNIT_8B (1 << UNIT_V_8B)
/* 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 2 /* 50 Hz */
/* Floppy definitions */
#define FL_NUMTR 77 /* tracks/disk */
#define FL_M_TRACK 0377
#define FL_NUMSC 26 /* sectors/track */
#define FL_M_SECTOR 0177
#define FL_NUMBY 128 /* bytes/sector */
#define FL_SIZE (FL_NUMTR * FL_NUMSC * FL_NUMBY) /* bytes/disk */
#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 FL_IDLE 0 /* idle state */
#define FL_RWDS 1 /* rw, sect next */
#define FL_RWDT 2 /* rw, track next */
#define FL_READ 3 /* read */
#define FL_READ1 4
#define FL_WRITE 5 /* write */
#define FL_WRITE1 6
#define FL_FILL 7 /* fill buffer */
#define FL_EMPTY 8 /* empty buffer */
#define FL_READSTA 9 /* read status */
#define FL_DONE 10 /* cmd done */
#define FL_V_FNC 0 /* floppy function */
#define FL_M_FNC 0xFF
#define FL_FNCRD 0x0 /* read */
#define FL_FNCWR 0x1 /* write */
#define FL_FNCRS 0x2 /* read status */
#define FL_FNCWD 0x3 /* write del data */
#define FL_FNCCA 0x4 /* cancel */
#define FL_CDATA 0x100 /* returned data */
#define FL_CDONE 0x200 /* completion code */
#define FL_STACRC 0x001 /* status bits */
#define FL_STAPAR 0x002
#define FL_STAINC 0x004
#define FL_STADDA 0x040
#define FL_STAERR 0x080
#define FL_CPROT 0x905 /* protocol error */
#define FL_MISC 0xF00 /* misc communications */
#define FL_SWDN 0x1 /* software done */
#define FL_BOOT 0x2 /* reboot */
#define FL_CLWS 0x3 /* clear warm start */
#define FL_CLCS 0x4 /* clear cold start */
#define FL_GETFNC(x) (((x) >> FL_V_FNC) & FL_M_FNC)
#define TRACK u3 /* current track */
#define CALC_DA(t,s) (((t) * FL_NUMSC) + ((s) - 1)) * FL_NUMBY
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 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 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 fl_fnc = 0; /* function */
int32 fl_esr = 0; /* error status */
int32 fl_ecode = 0; /* error code */
int32 fl_track = 0; /* desired track */
int32 fl_sector = 0; /* desired sector */
int32 fl_state = FL_IDLE; /* controller state */
int32 fl_stopioe = 1; /* stop on error */
int32 fl_swait = 100; /* seek, per track */
int32 fl_cwait = 50; /* command time */
int32 fl_xwait = 20; /* tr set time */
uint8 fl_buf[FL_NUMBY] = { 0 }; /* sector buffer */
int32 fl_bptr = 0; /* buffer pointer */
extern int32 sim_switches;
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 fl_svc (UNIT *uptr);
t_stat fl_reset (DEVICE *dptr);
int32 icr_rd (t_bool interp);
void tmr_incr (uint32 inc);
void tmr_sched (void);
t_stat todr_powerup (void);
t_stat fl_wr_txdb (int32 data);
t_bool fl_test_xfr (UNIT *uptr, t_bool wr);
void fl_protocol_error (void);
/* TTI data structures
tti_dev TTI device descriptor
tti_unit TTI unit descriptor
tti_reg TTI register list
*/
UNIT tti_unit = { UDATA (&tti_svc, UNIT_8B, 0), KBD_POLL_WAIT };
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), REG_NZ + PV_LEFT },
{ NULL } };
MTAB tti_mod[] = {
{ UNIT_8B, UNIT_8B, "8b", "8B", NULL },
{ UNIT_8B, 0 , "7b", "7B", 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, UNIT_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 },
{ NULL } };
MTAB tto_mod[] = {
{ UNIT_8B, UNIT_8B, "8b", "8B", NULL },
{ UNIT_8B, 0 , "7b", "7B", 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, 0, 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 (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 };
/* RX01 data structures
fl_dev RX device descriptor
fl_unit RX unit list
fl_reg RX register list
fl_mod RX modifier list
*/
UNIT fl_unit = { UDATA (&fl_svc,
UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, FL_SIZE) };
REG fl_reg[] = {
{ HRDATA (FNC, fl_fnc, 8) },
{ HRDATA (ES, fl_esr, 8) },
{ HRDATA (ECODE, fl_ecode, 8) },
{ HRDATA (TA, fl_track, 8) },
{ HRDATA (SA, fl_sector, 8) },
{ DRDATA (STATE, fl_state, 4), REG_RO },
{ DRDATA (BPTR, fl_bptr, 7) },
{ DRDATA (CTIME, fl_cwait, 24), PV_LEFT },
{ DRDATA (STIME, fl_swait, 24), PV_LEFT },
{ DRDATA (XTIME, fl_xwait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, fl_stopioe, 0) },
{ BRDATA (DBUF, fl_buf, 16, 8, FL_NUMBY) },
{ NULL } };
MTAB fl_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ 0 } };
DEVICE fl_dev = {
"RX", &fl_unit, fl_reg, fl_mod,
1, DEV_RDX, 20, 1, DEV_RDX, 8,
NULL, NULL, &fl_reset,
NULL, NULL, NULL,
NULL, 0 };
/* 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) fl_wr_txdb (tto_buf); /* floppy? */
else 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 (&tti_unit, tti_unit.wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
if (c & SCPE_BREAK) /* break? */
tti_buf = RXDB_ERR | RXDB_FRM | RXDB_RBR;
else tti_buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177);
tti_unit.pos = tti_unit.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 (&tti_unit, tti_unit.wait); /* activate unit */
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 = tto_buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
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 */
tto_unit.pos = tto_unit.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
gross hack is used for the interval timer.
When the timer is started, the timer interval is inspected.
if (int < 0 and small) then testing timer, count instructions.
Small is determined by when the requested interval is less
than the size of a 100Hz system clock tick.
if (int >= 0 or large) then counting a real interval, schedule
clock events at 100Hz using calibrated clock delay. When
the remaining time value gets small enough, behave like
the small case above.
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 */
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_inc == TMR_INC) && /* scale large int */
(tmr_poll > TMR_INC))
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)
{
int32 t;
t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
tmr_poll = t; /* set tmr poll */
tmxr_poll = t * TMXR_MULT; /* set mux poll */
todr_reg = todr_reg + 1; /* incr TODR */
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) tmr_int = 1; /* ie? set int req */
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)
{
int32 clk_time = sim_is_active (&clk_unit) - 1;
int32 tmr_time;
tmr_sav = sim_grtime (); /* save intvl base */
if (tmr_icr > (0xFFFFFFFFu - TMR_INC)) { /* short interval? */
tmr_inc = (~tmr_icr + 1); /* inc = interval */
tmr_time = tmr_inc; }
else { tmr_inc = TMR_INC; /* usec/interval */
tmr_time = tmr_poll; }
if (tmr_time == 0) tmr_time = 1;
if ((tmr_inc = TMR_INC) && (tmr_time > clk_time)) {
/* Align scheduled event to be identical to the event for the next clock
tick. This lets us always see a consistent calibrated value, both for
this scheduling, AND for any query of the current timer register that
may happen in tmr_icr_rd (). This presumes that sim_activate will
queue the interval timer behind the event for the 100Hz clock tick. */
tmr_inc = (uint32) (((double) clk_time * TMR_INC) / tmr_poll);
tmr_time = clk_time; }
sim_activate (&tmr_unit, tmr_time);
return;
}
/* 100Hz clock reset */
t_stat clk_reset (DEVICE *dptr)
{
int32 t;
t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */
sim_activate (&clk_unit, t); /* activate 100Hz unit */
tmr_poll = t; /* set tmr poll */
tmxr_poll = t * 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;
sim_cancel (&tmr_unit); /* cancel timer */
if (sim_switches & SWMASK ('P')) todr_powerup (); /* powerup? set 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_powerup (void)
{
uint32 base;
time_t curr;
struct tm *ctm;
curr = time (NULL); /* get curr time */
if (curr == (time_t) -1) return SCPE_NOFNC; /* error? */
ctm = localtime (&curr); /* decompose */
if (ctm == NULL) return SCPE_NOFNC; /* error? */
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 fl_wr_txdb (int32 data)
{
int32 sel = TXDB_GETSEL (data); /* get selection */
if (sel == TXDB_FCMD) { /* floppy command? */
fl_fnc = FL_GETFNC (data); /* get function */
if (fl_state != FL_IDLE) switch (fl_fnc) { /* cmd in prog? */
case FL_FNCCA: /* cancel? */
sim_cancel (&fl_unit); /* stop op */
fl_state = FL_DONE;
break;
default: /* all others */
fl_protocol_error ();
return SCPE_OK;
}
else switch (fl_fnc) { /* idle, case */
case FL_FNCRS: /* read status */
fl_state = FL_READSTA;
break;
case FL_FNCCA: /* cancel, nop */
fl_state = FL_DONE;
break;
case FL_FNCRD: case FL_FNCWR: /* data xfer */
case FL_FNCWD:
fl_esr = 0; /* clear errors */
fl_ecode = 0;
fl_bptr = 0; /* init buffer */
fl_state = FL_RWDS; /* sector next */
break;
default: /* all others */
fl_protocol_error ();
return SCPE_OK;
}
sim_activate (&fl_unit, fl_cwait); /* sched command */
} /* end command */
else if (sel == TXDB_FDAT) { /* floppy data? */
switch (fl_state) { /* data */
case FL_RWDS: /* expecting sector */
fl_sector = data & FL_M_SECTOR;
fl_state = FL_RWDT;
break;
case FL_RWDT: /* expecting track */
fl_track = data & FL_M_TRACK;
if (fl_fnc == FL_FNCRD) fl_state = FL_READ;
else fl_state = FL_FILL;
break;
case FL_FILL: /* expecting wr data */
fl_buf[fl_bptr++] = data & BMASK;
if (fl_bptr >= FL_NUMBY) fl_state = FL_WRITE;
break;
default:
fl_protocol_error ();
return SCPE_OK;
}
sim_activate (&fl_unit, fl_xwait); /* schedule xfer */
} /* end else data */
else sim_activate (&tto_unit, tto_unit.wait); /* discard for now */
return SCPE_OK;
}
/* Unit service; the action to be taken depends on the transfer state:
FL_IDLE Should never get here
FL_RWDS Set TXCS<done> (driver sends sector, sets FL_RWDT)
FL_RWDT Set TXCS<done> (driver sends track, sets FL_READ/FL_FILL)
FL_READ Set TXCS<done>, schedule FL_READ1
FL_READ1 Read sector, schedule FL_EMPTY
FL_EMPTY Copy data to RXDB, set RXCS<done>
if fl_bptr >= max, schedule completion, else continue
FL_FILL Set TXCS<done> (driver sends next byte, sets FL_WRITE)
FL_WRITE Set TXCS<done>, schedule FL_WRITE1
FL_WRITE1 Write sector, schedule FL_DONE
FL_DONE Copy requested data to TXDB, set FL_IDLE
*/
t_stat fl_svc (UNIT *uptr)
{
int32 i, t;
uint32 da;
int8 *fbuf = uptr->filebuf;
switch (fl_state) { /* case on state */
case FL_IDLE: /* idle */
return SCPE_IERR; /* done */
case FL_READ: case FL_WRITE: /* read, write */
fl_state = fl_state + 1; /* set next state */
t = abs (fl_track - uptr->TRACK); /* # tracks to seek */
if (t == 0) t = 1; /* minimum 1 */
sim_activate (uptr, fl_swait * t); /* schedule seek */
/* fall thru, set flag */
case FL_RWDS: case FL_RWDT: case FL_FILL: /* rwds, rwdt, fill */
tto_csr = tto_csr | CSR_DONE; /* set output done */
if (tto_csr & CSR_IE) tto_int = 1;
break;
case FL_READ1: /* read, seek done */
if (fl_test_xfr (uptr, FALSE)) { /* transfer ok? */
da = CALC_DA (fl_track, fl_sector); /* get disk address */
for (i = 0; i < FL_NUMBY; i++) /* copy sector to buf */
fl_buf[i] = fbuf[da + i];
tti_buf = fl_esr | FL_CDONE; /* completion code */
tti_csr = tti_csr | CSR_DONE; /* set input flag */
if (tti_csr & CSR_IE) tti_int = 1;
fl_state = FL_EMPTY; } /* go empty */
else fl_state = FL_DONE; /* error? cmd done */
sim_activate (uptr, fl_xwait); /* schedule next */
break;
case FL_EMPTY: /* empty buffer */
if ((tti_csr & CSR_DONE) == 0) { /* prev data taken? */
tti_buf = FL_CDATA | fl_buf[fl_bptr++]; /* get next byte */
tti_csr = tti_csr | CSR_DONE; /* set input flag */
if (tti_csr & CSR_IE) tti_int = 1;
if (fl_bptr >= FL_NUMBY) { /* buffer empty? */
fl_state = FL_IDLE; /* cmd done */
break;
}
}
sim_activate (uptr, fl_xwait); /* schedule next */
break;
case FL_WRITE1: /* write, seek done */
if (fl_test_xfr (uptr, TRUE)) { /* transfer ok? */
da = CALC_DA (fl_track, fl_sector); /* get disk address */
for (i = 0; i < FL_NUMBY; i++) /* copy buf to sector */
fbuf[da + i] = fl_buf[i];
da = da + FL_NUMBY;
if (da > uptr->hwmark) uptr->hwmark = da; /* update hwmark */
}
if (fl_fnc == FL_FNCWD) fl_esr |= FL_STADDA; /* wrdel? set status*/
fl_state = FL_DONE; /* command done */
sim_activate (uptr, fl_xwait); /* schedule */
break;
case FL_DONE: /* command done */
if (tti_csr & CSR_DONE) /* input buf empty? */
sim_activate (uptr, fl_xwait); /* no, wait */
else { /* yes */
tti_buf = fl_esr | FL_CDONE; /* completion code */
tti_csr = tti_csr | CSR_DONE; /* set input flag */
if (tti_csr & CSR_IE) tti_int = 1;
fl_state = FL_IDLE; /* floppy idle */
}
break;
case FL_READSTA: /* read status */
if ((tti_csr & CSR_DONE) == 0) { /* input buf empty? */
tti_buf = fl_ecode; /* return err code */
tti_csr = tti_csr | CSR_DONE; /* set input flag */
if (tti_csr & CSR_IE) tti_int = 1;
fl_state = FL_DONE; /* command done */
}
sim_activate (uptr, fl_xwait);
break;
}
return SCPE_OK;
}
/* Test for data transfer okay */
t_bool fl_test_xfr (UNIT *uptr, t_bool wr)
{
if ((uptr->flags & UNIT_BUF) == 0) /* not buffered? */
fl_ecode = 0110;
else if (fl_track >= FL_NUMTR) /* bad track? */
fl_ecode = 0040; /* done, error */
else if ((fl_sector == 0) || (fl_sector > FL_NUMSC)) /* bad sect? */
fl_ecode = 0070; /* done, error */
else if (wr && (uptr->flags & UNIT_WPRT)) /* write and locked? */
fl_ecode = 0100; /* done, error */
else { uptr->TRACK = fl_track; /* now on track */
return TRUE; }
fl_esr = fl_esr | FL_STAERR; /* set error */
return FALSE;
}
/* Set protocol error */
void fl_protocol_error (void)
{
if ((tto_csr & CSR_DONE) == 0) { /* output busy? */
tto_csr = tto_csr | CSR_DONE; /* set done */
if (tto_csr & CSR_IE) tto_int = 1; }
if ((tti_csr & CSR_DONE) == 0) { /* input idle? */
tti_csr = tti_csr | CSR_DONE; /* set done */
if (tti_csr & CSR_IE) tti_int = 1; }
tti_buf = FL_CPROT; /* status */
fl_state = FL_IDLE; /* floppy idle */
return;
}
/* Reset */
t_stat fl_reset (DEVICE *dptr)
{
fl_esr = FL_STAINC;
fl_ecode = 0; /* clear error */
fl_sector = 0; /* clear addr */
fl_track = 0;
fl_state = FL_IDLE; /* ctrl idle */
fl_bptr = 0;
sim_cancel (&fl_unit); /* cancel drive */
fl_unit.TRACK = 0;
return SCPE_OK;
}

View File

@@ -1,130 +0,0 @@
/* vax_syslist.c: VAX device list
Copyright (c) 1998-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
01-Oct-2004 RMS Cloned from vax_sys.c
*/
#include "vax_defs.h"
char sim_name[] = "VAX780 (pre-Beta developers preview)";
extern DEVICE cpu_dev;
extern DEVICE tlb_dev;
extern DEVICE sbi_dev;
extern DEVICE mctl0_dev, mctl1_dev;
extern DEVICE uba_dev;
extern DEVICE mba0_dev, mba1_dev;
extern DEVICE clk_dev;
extern DEVICE tmr_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE fl_dev;
extern DEVICE lpt_dev;
extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
extern DEVICE rl_dev;
extern DEVICE hk_dev;
extern DEVICE rp_dev;
extern DEVICE ry_dev;
extern DEVICE ts_dev;
extern DEVICE tq_dev;
extern DEVICE tu_dev;
extern DEVICE dz_dev;
extern DEVICE xu_dev, xub_dev;
extern int32 sim_switches;
extern UNIT cpu_unit;
extern void WriteB (int32 pa, int32 val);
extern void rom_wr_B (int32 pa, int32 val);
DEVICE *sim_devices[] = {
&cpu_dev,
&tlb_dev,
&sbi_dev,
&mctl0_dev,
&mctl1_dev,
&uba_dev,
&mba0_dev,
&mba1_dev,
&clk_dev,
&tmr_dev,
&tti_dev,
&tto_dev,
&fl_dev,
&dz_dev,
&lpt_dev,
&rp_dev,
&rl_dev,
&hk_dev,
&rq_dev,
&rqb_dev,
&rqc_dev,
&rqd_dev,
&ry_dev,
&tu_dev,
&ts_dev,
&tq_dev,
&xu_dev,
&xub_dev,
NULL };
/* Binary loader
The binary loader handles absolute system images, that is, system
images linked /SYSTEM. These are simply a byte stream, with no
origin or relocation information.
-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) return SCPE_ARG; /* dump? */
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? */
if (origin >= ROMSIZE) return SCPE_NXM;
rom_wr_B (ROM0BASE + origin, val); }
else if (sim_switches & SWMASK ('S')) { /* ROM1? */
if (origin >= ROMSIZE) return SCPE_NXM;
rom_wr_B (ROM1BASE + origin, val); }
else {
if (origin >= limit) return SCPE_NXM; /* NXM? */
WriteB (origin, val); } /* memory */
origin = origin + 1; }
return SCPE_OK;
}

File diff suppressed because it is too large Load Diff

View File

@@ -408,8 +408,8 @@ case CRC:
*/
case MOVP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if (op[0] > 31) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[0], op[1], &dst, acc); /* read source */
cc = WriteDstr (op[0], op[2], &dst, 0, acc) | /* write dest */
(cc & CC_C); /* preserve C */
@@ -445,8 +445,8 @@ case ADDP4: case SUBP4:
op[4] = op[2]; /* copy dst */
op[5] = op[3];
case ADDP6: case SUBP6:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[2] > 31) || (op[4] > 31))
if ((PSL & PSL_FPD) || (op[0] > 31) ||
(op[2] > 31) || (op[4] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[0], op[1], &src1, acc); /* get src1 */
ReadDstr (op[2], op[3], &src2, acc); /* get src2 */
@@ -498,8 +498,8 @@ case ADDP6: case SUBP6:
*/
case MULP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[2] > 31) || (op[4] > 31))
if ((PSL & PSL_FPD) || (op[0] > 31) ||
(op[2] > 31) || (op[4] > 31))
RSVD_OPND_FAULT;
dst = Dstr_zero; /* clear result */
if (ReadDstr (op[0], op[1], &src1, acc) && /* read src1, src2 */
@@ -548,8 +548,8 @@ case MULP:
*/
case DIVP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[2] > 31) || (op[4] > 31))
if ((PSL & PSL_FPD) || (op[0] > 31) ||
(op[2] > 31) || (op[4] > 31))
RSVD_OPND_FAULT;
ldivr = ReadDstr (op[0], op[1], &src1, acc); /* get divisor */
if (ldivr == 0) { /* divisor = 0? */
@@ -613,8 +613,8 @@ case CMPP3:
op[3] = op[2]; /* reposition ops */
op[2] = op[0];
case CMPP4:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[2] > 31)) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31) || (op[2] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[0], op[1], &src1, acc); /* get src1 */
ReadDstr (op[1], op[2], &src2, acc); /* get src2 */
cc = 0;
@@ -651,8 +651,8 @@ case CMPP4:
*/
case ASHP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[1] > 31) || (op[4] > 31)) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[1] > 31) || (op[4] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[1], op[2], &src1, acc); /* get source */
V = 0; /* init V */
shift = op[0]; /* get shift count */
@@ -695,8 +695,8 @@ case ASHP:
*/
case CVTPL:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if (op[0] > 31) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[0], op[1], &src1, acc); /* get source */
V = result = 0; /* clear V, result */
for (i = (DSTRLNT * 8) - 1; i > 0; i--) { /* loop thru digits */
@@ -737,8 +737,8 @@ case CVTPL:
*/
case CVTLP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if (op[1] > 31) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[1] > 31))
RSVD_OPND_FAULT;
dst = Dstr_zero; /* clear result */
result = op[0];
if ((result & LSIGN) != 0) {
@@ -775,8 +775,8 @@ case CVTLP:
*/
case CVTSP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[2] > 31)) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31) || (op[2] > 31))
RSVD_OPND_FAULT;
dst = Dstr_zero; /* clear result */
t = Read (op[1], L_BYTE, RA); /* read source sign */
if (t == C_MINUS) dst.sign = 1; /* sign -, */
@@ -815,8 +815,8 @@ case CVTSP:
*/
case CVTPS:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[2] > 31)) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31) || (op[2] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[0], op[1], &dst, acc); /* get src */
ProbeDstr (op[2], op[3], WA); /* test dst write */
Write (op[3], dst.sign? C_MINUS: C_PLUS, L_BYTE, WA);
@@ -851,8 +851,8 @@ case CVTPS:
*/
case CVTTP:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[3] > 31)) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31) || (op[3] > 31))
RSVD_OPND_FAULT;
dst = Dstr_zero; /* clear result */
for (i = 1; i <= op[0]; i++) { /* loop thru char */
c = Read ((op[1] + op[0] - i) & LMASK, L_BYTE, RA); /* read char */
@@ -897,17 +897,17 @@ case CVTTP:
*/
case CVTPT:
if (PSL & PSL_FPD) RSVD_INST_FAULT;
if ((op[0] > 31) || (op[3] > 31)) RSVD_OPND_FAULT;
if ((PSL & PSL_FPD) || (op[0] > 31) || (op[3] > 31))
RSVD_OPND_FAULT;
ReadDstr (op[0], op[1], &dst, acc); /* get source */
ProbeDstr (op[3], op[4], WA); /* test writeability */
for (i = 1; i <= op[3]; i++) { /* loop thru chars */
if (i != op[3]) { /* not last? */
if (i != 1) { /* not last? */
d = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */
c = d + C_ZERO; /* convert */
}
else { /* translate last */
t = Read ((op[1] + op[0]) & LMASK, L_BYTE, RA);
t = Read ((op[1] + (op[0] / 2)) & LMASK, L_BYTE, RA);
c = Read ((op[2] + t) & LMASK, L_BYTE, RA);
}
Write ((op[4] + op[3] - i) & LMASK, c, L_BYTE, WA);
@@ -971,8 +971,8 @@ case EDITPC:
}
else { /* new instr */
if (op[0] > 31) RSVD_OPND_FAULT; /* lnt > 31? */
d = Read ((op[1] + (op[0] / 2)) & LMASK, L_BYTE, RA) & 0xF;
if ((d == 0xB) || (d == 0xD)) {
t = Read ((op[1] + (op[0] / 2)) & LMASK, L_BYTE, RA) & 0xF;
if ((t == 0xB) || (t == 0xD)) {
cc = CC_N | CC_Z;
sign = C_MINUS;
}

View File

@@ -81,6 +81,8 @@ int32 op_mulh (int32 *opnd, int32 *hf);
int32 op_divh (int32 *opnd, int32 *hf);
int32 op_emodh (int32 *opnd, int32 *hflt, int32 *intgr, int32 *flg);
void op_polyh (int32 *opnd, int32 acc);
void h_write_b (int32 spec, int32 va, int32 val, int32 acc);
void h_write_w (int32 spec, int32 va, int32 val, int32 acc);
void h_write_l (int32 spec, int32 va, int32 val, int32 acc);
void h_write_q (int32 spec, int32 va, int32 vl, int32 vh, int32 acc);
void h_write_o (int32 spec, int32 va, int32 *val, int32 acc);
@@ -90,7 +92,6 @@ void vax_hmod (UFPH *a, int32 *intgr, int32 *flg);
void vax_hdiv (UFPH *a, UFPH *b);
void qp_add (UQP *a, UQP *b);
void qp_inc (UQP *a);
void qp_sub (UQP *a, UQP *b);
void qp_lsh (UQP *a, uint32 sc);
void qp_rsh (UQP *a, uint32 sc);
void qp_rsh_s (UQP *a, uint32 sc, uint32 neg);
@@ -110,7 +111,7 @@ static int32 z_octa[4] = { 0, 0, 0, 0 };
int32 op_octa (int32 *opnd, int32 cc, int32 opc, int32 acc, int32 spec, int32 va)
{
int32 r, rh, temp, flg, rn;
int32 r, rh, temp, flg;
int32 r_octa[4];
switch (opc) {
@@ -173,12 +174,14 @@ case MOVO:
h_write_o (spec, va, opnd, acc); /* write src */
CC_IIZP_O (opnd[0], opnd[1], opnd[2], opnd[3]); /* set cc's */
break;
case MOVH:
if (r = op_tsth (opnd[0])) /* test for 0 */
h_write_o (spec, va, opnd, acc); /* nz, write result */
else h_write_o (spec, va, z_octa, acc); /* zero, write 0 */
CC_IIZP_FP (r); /* set cc's */
break;
case MNEGH:
if (r = op_tsth (opnd[0])) { /* test for 0 */
opnd[0] = opnd[0] ^ FPSIGN; /* nz, invert sign */
@@ -211,11 +214,13 @@ case CVTBH:
h_write_o (spec, va, r_octa, acc); /* write reslt */
CC_IIZZ_FP (r); /* set cc's */
break;
case CVTWH:
r = op_cvtih (SXTW (opnd[0]), r_octa); /* convert */
h_write_o (spec, va, r_octa, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case CVTLH:
r = op_cvtih (opnd[0], r_octa); /* convert */
h_write_o (spec, va, r_octa, acc); /* write result */
@@ -232,22 +237,18 @@ case CVTLH:
case CVTHB:
r = op_cvthi (opnd, &temp, opc) & BMASK; /* convert */
if (spec > (GRN | nPC)) Write (va, r, L_BYTE, WA);
else {
rn = spec & 0xF;
R[rn] = (R[rn] & ~BMASK) | r; }
h_write_b (spec, va, r, acc); /* write result */
CC_IIZZ_B (r); /* set cc's */
cc = cc | temp; /* or in V */
break;
case CVTHW:
r = op_cvthi (opnd, &temp, opc) & WMASK; /* convert */
if (spec > (GRN | nPC)) Write (va, r, L_WORD, WA);
else {
rn = spec & 0xF;
R[rn] = (R[rn] & ~WMASK) | r; }
h_write_w (spec, va, r, acc); /* write result */
CC_IIZZ_W (r); /* set cc's */
cc = cc | temp; /* or in V */
break;
case CVTHL: case CVTRHL:
r = op_cvthi (opnd, &temp, opc) & LMASK; /* convert */
h_write_l (spec, va, r, acc); /* write result */
@@ -282,6 +283,7 @@ case CVTDH:
h_write_o (spec, va, r_octa, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case CVTGH:
r = op_cvtgh (opnd[0], opnd[1], r_octa); /* convert */
h_write_o (spec, va, r_octa, acc); /* write result */
@@ -301,11 +303,13 @@ case CVTHF:
h_write_l (spec, va, r, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case CVTHD:
r = op_cvthfd (opnd, &rh); /* convert */
h_write_q (spec, va, r, rh, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case CVTHG:
r = op_cvthg (opnd, &rh); /* convert */
h_write_q (spec, va, r, rh, acc); /* write result */
@@ -334,16 +338,19 @@ case ADDH2: case ADDH3:
h_write_o (spec, va, r_octa, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case SUBH2: case SUBH3:
r = op_addh (opnd, r_octa, TRUE); /* subtract */
h_write_o (spec, va, r_octa, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case MULH2: case MULH3:
r = op_mulh (opnd, r_octa); /* multiply */
h_write_o (spec, va, r_octa, acc); /* write result */
CC_IIZZ_FP (r); /* set cc's */
break;
case DIVH2: case DIVH3:
r = op_divh (opnd, r_octa); /* divide */
h_write_o (spec, va, r_octa, acc); /* write result */
@@ -649,12 +656,9 @@ if ((a->exp < b->exp) || /* |s1| < |s2|? */
}
ediff = a->exp - b->exp; /* exp diff */
if (a->sign ^ b->sign) { /* eff sub? */
if (ediff) { /* exp diff? */
qp_neg (&b->frac); /* negate fraction */
qp_rsh_s (&b->frac, ediff, 1); /* signed right */
qp_add (&a->frac, &b->frac); /* "add" frac */
}
else qp_sub (&a->frac, &b->frac); /* a >= b */
qp_neg (&b->frac); /* negate fraction */
if (ediff) qp_rsh_s (&b->frac, ediff, 1); /* denormalize */
qp_add (&a->frac, &b->frac); /* "add" frac */
h_normh (a); /* normalize */
}
else { if (ediff) qp_rsh (&b->frac, ediff); /* add, denormalize */
@@ -738,7 +742,7 @@ return;
void vax_hdiv (UFPH *a, UFPH *b)
{
int32 i;
UQP quo = { 0, 0, 0, 0 };
UQP ndvr, quo = { 0, 0, 0, 0 };
if (a->exp == 0) FLT_DZRO_FAULT; /* divr = 0? */
if (b->exp == 0) return; /* divd = 0? */
@@ -746,11 +750,14 @@ b->sign = b->sign ^ a->sign; /* result sign */
b->exp = b->exp - a->exp + H_BIAS + 1; /* unbiased exp */
qp_rsh (&a->frac, 1); /* allow 1 bit left */
qp_rsh (&b->frac, 1);
ndvr = a->frac; /* copy divisor */
qp_neg (&ndvr); /* and negate */
for (i = 0; i < 128; i++) { /* divide loop */
qp_lsh (&quo, 1); /* shift quo */
if (qp_cmp (&b->frac, &a->frac) >= 0) { /* div step ok? */
qp_sub (&b->frac, &a->frac); /* subtract */
quo.f0 = quo.f0 + 1; } /* quo bit = 1 */
qp_add (&b->frac, &ndvr); /* "subtract" */
quo.f0 = quo.f0 + 1; /* quo bit = 1 */
}
qp_lsh (&b->frac, 1); /* shift divd */
}
b->frac = quo;
@@ -803,15 +810,6 @@ r->f3 = (~r->f3 + (r->f2 == 0)) & LMASK;
return;
}
void qp_sub (UQP *a, UQP *b)
{
UQP nb = *b;
qp_neg (&nb);
qp_add (a, &nb);
return;
}
void qp_lsh (UQP *r, uint32 sc)
{
if (sc >= 128) r->f3 = r->f2 = r->f1 = r->f0 = 0; /* > 127? result 0 */
@@ -1050,6 +1048,28 @@ hflt[3] = WORDSWAP (r->frac.f0);
return hflt[0];
}
void h_write_b (int32 spec, int32 va, int32 val, int32 acc)
{
int32 rn;
if (spec > (GRN | nPC)) Write (va, val, L_BYTE, WA);
else { rn = spec & 0xF;
R[rn] = (R[rn] & ~BMASK) | val;
}
return;
}
void h_write_w (int32 spec, int32 va, int32 val, int32 acc)
{
int32 rn;
if (spec > (GRN | nPC)) Write (va, val, L_WORD, WA);
else { rn = spec & 0xF;
R[rn] = (R[rn] & ~WMASK) | val;
}
return;
}
void h_write_l (int32 spec, int32 va, int32 val, int32 acc)
{
if (spec > (GRN | nPC)) Write (va, val, L_LONG, WA);
@@ -1064,11 +1084,13 @@ int32 rn, mstat;
if (spec > (GRN | nPC)) {
if (Test (va + 7, WA, &mstat) >= 0)
Write (va, vl, L_LONG, WA);
Write (va + 4, vh, L_LONG, WA); }
Write (va + 4, vh, L_LONG, WA);
}
else { rn = spec & 0xF;
if (rn >= nSP) RSVD_ADDR_FAULT;
R[rn] = vl;
R[rn + 1] = vh; }
R[rn + 1] = vh;
}
return;
}
@@ -1081,13 +1103,15 @@ if (spec > (GRN | nPC)) {
Write (va, val[0], L_LONG, WA);
Write (va + 4, val[1], L_LONG, WA);
Write (va + 8, val[2], L_LONG, WA);
Write (va + 12, val[3], L_LONG, WA); }
Write (va + 12, val[3], L_LONG, WA);
}
else { rn = spec & 0xF;
if (rn >= nAP) RSVD_ADDR_FAULT;
R[rn] = val[0];
R[rn + 1] = val[1];
R[rn + 2] = val[2];
R[rn + 3] = val[3]; }
R[rn + 3] = val[3];
}
return;
}

View File

@@ -1,6 +1,6 @@
/* vax_sysdev.c: VAX 3900 system-specific logic
Copyright (c) 1998-2004, Robert M Supnik
Copyright (c) 1998-2005, 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"),
@@ -32,6 +32,7 @@
cso console storage output
sysd system devices (SSC miscellany)
10-Mar-05 RMS Fixed bug in timer schedule routine (from Mark Hittinger)
30-Sep-04 RMS Moved CADR, MSER, CONPC, CONPSL, machine_check, cpu_boot,
con_halt here from vax_cpu.c
Moved model-specific IPR's here from vax_cpu1.c
@@ -1283,7 +1284,7 @@ if (tmr_tir[tmr] > (0xFFFFFFFFu - TMR_INC)) { /* short interval? */
else { tmr_inc[tmr] = TMR_INC; /* usec/interval */
tmr_time = tmr_poll; }
if (tmr_time == 0) tmr_time = 1;
if ((tmr_inc[tmr] = TMR_INC) && (tmr_time > clk_time)) {
if ((tmr_inc[tmr] == TMR_INC) && (tmr_time > clk_time)) {
/* Align scheduled event to be identical to the event for the next clock
tick. This lets us always see a consistent calibrated value, both for