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:
committed by
Mark Pizzolato
parent
098200a126
commit
ec60bbf329
@@ -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
|
||||
1079
VAX/vax780_doc.txt
1079
VAX/vax780_doc.txt
File diff suppressed because it is too large
Load Diff
696
VAX/vax780_mba.c
696
VAX/vax780_mba.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
1104
VAX/vax780_uba.c
1104
VAX/vax780_uba.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user