mirror of
https://github.com/simh/simh.git
synced 2026-01-25 19:56:25 +00:00
Notes For V2.8
1. New Features
1.1 Directory and documentation
- Only common files (SCP and libraries) are in the top level
directory. Individual simulator files are in their individual
directories.
- simh_doc.txt has been split up. simh_doc.txt now documents
only SCP. The individual simulators are documented in separate
text files in their own directories.
- mingw_build.bat is a batch file for the MINGW/gcc environment
that will build all the simulators, assuming the root directory
structure is at c:\sim.
- Makefile is a UNIX make file for the gcc environment that will
build all the simulators, assuming the root directory is at
c:\sim.
1.2 SCP
- DO <file name> executes the SCP commands in the specified file.
- Replicated registers in unit structures can now be declared as
arrays for examine, modify, save, and restore. Most replicated
unit registers (for example, mag tape position registers) have
been changed to arrays.
- The ADD/REMOVE commands have been replaced by SET unit ONLINE
and SET unit OFFLINE, respectively.
- Register names that are unique within an entire simulator do
not have to be prefaced with the device name.
- The ATTACH command can attach files read only, either under
user option (-r), or because the attached file is ready only.
- The SET/SHOW capabilities have been extended. New forms include:
SET <dev> param{=value}{ param ...}
SET <unit> param{=value}{ param ...}
SHOW <dev> {param param ...}
SHOW <unit> {param param ...}
- Multiple breakpoints have been implemented. Breakpoints are
set/cleared/displayed by:
BREAK addr_list{[count]}
NOBREAK addr_list
SHOW BREAK addr_list
1.3 PDP-11 simulator
- Unibus map implemented, with 22b RP controller (URH70) or 18b
RP controller (URH11) (in debug).
- All DMA peripherals rewritten to use map.
- Many peripherals modified for source sharing with VAX.
- RQDX3 implemented.
- Bugs fixed in RK11 and RL11 write check.
1.4 PDP-10 simulator
- ITS 1-proceed implemented.
- Bugs fixed in ITS PC sampling and LPMR
1.5 18b PDP simulator
- Interrupts split out to multiple levels to allow easier
expansion.
1.5 IBM System 3 Simulator
- Written by Charles (Dutch) Owen.
1.6 VAX Simulator (in debug)
- Simulates MicroVAX 3800 (KA655) with 16MB-64MB memory, RQDX3,
RLV12, TSV11, DZV11, LPV11, PCV11.
- CDROM capability has been added to the RQDX3, to allow testing
with VMS hobbyist images.
1.7 SDS 940 Simulator (not tested)
- Simulates SDS 940, 16K-64K memory, fixed and moving head
disk, magtape, line printer, console.
1.8 Altair Z80
- Revised from Charles (Dutch) Owen's original by Peter Schorn.
- MITS 8080 with full Z80 simulation.
- 4K and 8K BASIC packages, Prolog package.
1.9 Interdata
The I4 simulator has been withdrawn for major rework. Look for
a complete 16b/32b Interdata simulator sometime next year.
2. Release Notes
2.1 SCP
SCP now allows replicated registers in unit structures to be
modelled as arrays. All replicated register declarations have
been replaced by register array declarations. As a result,
save files from prior revisions will generate errors after
restoring main memory.
2.2 PDP-11
The Unibus map code is in debug. The map was implemented primarily
to allow source sharing with the VAX, which requires a DMA map.
DMA devices work correctly with the Unibus map disabled.
The RQDX3 simulator has run a complete RSTS/E SYSGEN, with multiple
drives, and booted the completed system from scratch.
2.3 VAX
The VAX simulator will run the boot code up to the >>> prompt. It
can successfully process a SHOW DEVICE command. It runs the HCORE
instruction diagnostic. It can boot the hobbyist CD through SYSBOOT
and through the date/time dialog and restore the hobbyist CD, using
standalone backup. On the boot of the restored disk, it gets to the
date/time dialog, and then crashes.
2.4 SDS 940
The SDS 940 is untested, awaiting real code.
2.5 GCC Optimization
At -O2 and above, GCC does not correctly compile the simulators which
use setjmp-longjmp (PDP-11, PDP-10, VAX). A working hypothesis is
that optimized state maintained in registers is being used in the
setjmp processing routine. On the PDP-11 and PDP-10, all of this
state has been either made global, or volatile, to encourage GCC to
keep the state up to date in memory. The VAX is still vulnerable.
3. Work list
3.1 SCP
- Better ENABLE/DISABLE.
3.2 PDP-11 RQDX3
Software mapped mode, RCT read simulation, VMS debug.
This commit is contained in:
committed by
Mark Pizzolato
parent
654937fc88
commit
701f0fe028
2081
PDP10/pdp10_cpu.c
Normal file
2081
PDP10/pdp10_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
666
PDP10/pdp10_defs.h
Normal file
666
PDP10/pdp10_defs.h
Normal file
@@ -0,0 +1,666 @@
|
||||
/* pdp10_defs.h: PDP-10 simulator definitions
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
23-Oct-01 RMS New IO page address constants
|
||||
19-Oct-01 RMS Added DZ definitions
|
||||
07-Sep-01 RMS Revised for PDP-11 multi-level interrupts
|
||||
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
|
||||
29-Aug-01 RMS Corrected models and dates (found by Lars Brinkhoff)
|
||||
01-Jun-01 RMS Updated DZ11 vector definitions
|
||||
19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Digital Equipment Corporation's 36b family had six implementations:
|
||||
|
||||
name mips comments
|
||||
|
||||
PDP-6 0.25 Original 36b implementation, 1964
|
||||
KA10 0.38 First PDP-10, flip chips, 1967
|
||||
KI10 0.72 First paging system, flip chip + MSI, 1972
|
||||
KL10 1.8 First ECL system, ECL 10K, 1975
|
||||
KL10B 1.8 Expanded addressing, ECL 10K, 1978
|
||||
KS10 0.3 Last 36b system, 2901 based, 1979
|
||||
|
||||
In addition, it ran four major (incompatible) operating systems:
|
||||
|
||||
name company comments
|
||||
|
||||
TOPS-10 DEC Original timesharing system
|
||||
ITS MIT "Incompatible Timesharing System"
|
||||
TENEX BBN ARPA-sponsored, became
|
||||
TOPS-20 DEC Commercial version of TENEX
|
||||
|
||||
All of the implementations differ from one another, in instruction set,
|
||||
I/O structure, and memory management. Further, each of the operating
|
||||
systems customized the microcode of the paging systems (KI10, KL10, KS10)
|
||||
for additional instructions and specialized memory management. As a
|
||||
result, there is no "reference implementation" for the 36b family that
|
||||
will run all programs and all operating systems. The conditionalization
|
||||
and generality needed to support the full matrix of models and operating
|
||||
systems, and to support 36b hardware on 32b data types, is beyond the
|
||||
scope of this project.
|
||||
|
||||
Instead, this simulator emulates one model -- the KS10. It has the best
|
||||
documentation and allows reuse of some of the Unibus peripheral emulators
|
||||
written for the PDP-11 simulator. Further, the simulator requires that
|
||||
the underlying compiler support 64b integer data types, allowing 36b data
|
||||
to be maintained in a single data item. Lastly, the simulator implements
|
||||
the maximum memory size, so that NXM's never happen.
|
||||
*/
|
||||
|
||||
/* Data types */
|
||||
|
||||
typedef int32 a10; /* PDP-10 addr (30b) */
|
||||
typedef t_int64 d10; /* PDP-10 data (36b) */
|
||||
|
||||
/* Abort codes, used to sort out longjmp's back to the main loop
|
||||
Codes > 0 are simulator stop codes
|
||||
Codes < 0 are internal aborts
|
||||
Code = 0 stops execution for an interrupt check
|
||||
*/
|
||||
|
||||
#define STOP_HALT 1 /* halted */
|
||||
#define STOP_IBKPT 2 /* breakpoint */
|
||||
#define STOP_ILLEG 3 /* illegal instr */
|
||||
#define STOP_ILLINT 4 /* illegal intr inst */
|
||||
#define STOP_PAGINT 5 /* page fail in intr */
|
||||
#define STOP_ZERINT 6 /* zero vec in intr */
|
||||
#define STOP_NXMPHY 7 /* nxm on phys ref */
|
||||
#define STOP_IND 8 /* indirection loop */
|
||||
#define STOP_XCT 9 /* XCT loop */
|
||||
#define STOP_ILLIOC 10 /* invalid UBA num */
|
||||
#define STOP_MTRLNT 11 /* invalid mt rec lnt */
|
||||
#define STOP_ASTOP 12 /* address stop */
|
||||
#define STOP_UNKNOWN 13 /* unknown stop */
|
||||
#define PAGE_FAIL -1 /* page fail */
|
||||
#define INTERRUPT -2 /* interrupt */
|
||||
#define ABORT(x) longjmp (save_env, (x)) /* abort */
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
|
||||
|
||||
/* Return codes from eXTEND */
|
||||
|
||||
#define XT_MUUO 0 /* invalid operation */
|
||||
#define XT_SKIP 1 /* skip return */
|
||||
#define XT_NOSK 2 /* no skip return */
|
||||
|
||||
/* Operating system flags, kept in cpu_unit.flags */
|
||||
|
||||
#define UNIT_V_ITS (UNIT_V_UF) /* ITS */
|
||||
#define UNIT_ITS (1 << UNIT_V_ITS)
|
||||
#define UNIT_V_T20V41 (UNIT_V_UF + 1) /* TOPS-20 V4.1 */
|
||||
#define UNIT_T20V41 (1 << UNIT_V_T20V41)
|
||||
#define ITS (cpu_unit.flags & UNIT_ITS)
|
||||
|
||||
/* Architectural constants */
|
||||
|
||||
#define PASIZE 20 /* phys addr width */
|
||||
#define MAXMEMSIZE (1 << PASIZE) /* maximum memory */
|
||||
#define PAMASK ((1 << PASIZE) - 1)
|
||||
#define MEMSIZE MAXMEMSIZE /* fixed, KISS */
|
||||
#define MEM_ADDR_NXM(x) ((x) >= MEMSIZE)
|
||||
#define VASIZE 18 /* virtual addr width */
|
||||
#define AMASK ((1 << VASIZE) - 1) /* virtual addr mask */
|
||||
#define LMASK 0777777000000 /* left mask */
|
||||
#define LSIGN 0400000000000 /* left sign */
|
||||
#define RMASK 0000000777777 /* right mask */
|
||||
#define RSIGN 0000000400000 /* right sign */
|
||||
#define DMASK 0777777777777 /* data mask */
|
||||
#define SIGN 0400000000000 /* sign */
|
||||
#define MMASK 0377777777777 /* magnitude mask */
|
||||
#define ONES 0777777777777
|
||||
#define MAXPOS 0377777777777
|
||||
#define MAXNEG 0400000000000
|
||||
|
||||
/* Instruction format */
|
||||
|
||||
#define INST_V_OP 27 /* opcode */
|
||||
#define INST_M_OP 0777
|
||||
#define INST_V_DEV 26
|
||||
#define INST_M_DEV 0177 /* device */
|
||||
#define INST_V_AC 23 /* AC */
|
||||
#define INST_M_AC 017
|
||||
#define INST_V_IND 22 /* indirect */
|
||||
#define INST_IND (1 << INST_V_IND)
|
||||
#define INST_V_XR 18 /* index */
|
||||
#define INST_M_XR 017
|
||||
#define OP_JRST 0254 /* JRST */
|
||||
#define AC_XPCW 07 /* XPCW */
|
||||
#define OP_JSR 0264 /* JSR */
|
||||
#define GET_OP(x) ((int32) (((x) >> INST_V_OP) & INST_M_OP))
|
||||
#define GET_DEV(x) ((int32) (((x) >> INST_V_DEV) & INST_M_DEV))
|
||||
#define GET_AC(x) ((int32) (((x) >> INST_V_AC) & INST_M_AC))
|
||||
#define TST_IND(x) ((x) & INST_IND)
|
||||
#define GET_XR(x) ((int32) (((x) >> INST_V_XR) & INST_M_XR))
|
||||
#define GET_ADDR(x) ((a10) ((x) & AMASK))
|
||||
|
||||
/* Byte pointer format */
|
||||
|
||||
#define BP_V_P 30 /* position */
|
||||
#define BP_M_P 077
|
||||
#define BP_P 0770000000000
|
||||
#define BP_V_S 24 /* size */
|
||||
#define BP_M_S 077
|
||||
#define BP_S 0007700000000
|
||||
#define GET_P(x) ((int32) (((x) >> BP_V_P) & BP_M_P))
|
||||
#define GET_S(x) ((int32) (((x) >> BP_V_S) & BP_M_S))
|
||||
#define PUT_P(b,x) (((b) & ~BP_P) | ((((t_int64) (x)) & BP_M_P) << BP_V_P))
|
||||
|
||||
/* Flags (stored in their own halfword) */
|
||||
|
||||
#define F_V_AOV 17 /* arithmetic ovflo */
|
||||
#define F_V_C0 16 /* carry 0 */
|
||||
#define F_V_C1 15 /* carry 1 */
|
||||
#define F_V_FOV 14 /* floating ovflo */
|
||||
#define F_V_FPD 13 /* first part done */
|
||||
#define F_V_USR 12 /* user mode */
|
||||
#define F_V_UIO 11 /* user I/O mode */
|
||||
#define F_V_PUB 10 /* public mode */
|
||||
#define F_V_AFI 9 /* addr fail inhibit */
|
||||
#define F_V_T2 8 /* trap 2 */
|
||||
#define F_V_T1 7 /* trap 1 */
|
||||
#define F_V_FXU 6 /* floating exp unflo */
|
||||
#define F_V_DCK 5 /* divide check */
|
||||
#define F_AOV (1 << F_V_AOV)
|
||||
#define F_C0 (1 << F_V_C0)
|
||||
#define F_C1 (1 << F_V_C1)
|
||||
#define F_FOV (1 << F_V_FOV)
|
||||
#define F_FPD (1 << F_V_FPD)
|
||||
#define F_USR (1 << F_V_USR)
|
||||
#define F_UIO (1 << F_V_UIO)
|
||||
#define F_PUB (1 << F_V_PUB)
|
||||
#define F_AFI (1 << F_V_AFI)
|
||||
#define F_T2 (1 << F_V_T2)
|
||||
#define F_T1 (1 << F_V_T1)
|
||||
#define F_TR (F_T1 | F_T2)
|
||||
#define F_FXU (1 << F_V_FXU)
|
||||
#define F_DCK (1 << F_V_DCK)
|
||||
#define F_1PR (F_AFI) /* ITS: 1-proceed */
|
||||
#define F_MASK 0777740 /* all flags */
|
||||
#define SETF(x) flags = flags | (x)
|
||||
#define CLRF(x) flags = flags & ~(x)
|
||||
#define TSTF(x) (flags & (x))
|
||||
#define GET_TRAPS(x) (((x) & (F_T2 | F_T1)) >> F_V_T1)
|
||||
|
||||
/* Priority interrupt system */
|
||||
|
||||
#define PI_CPRQ 020000 /* drop prog req */
|
||||
#define PI_INIT 010000 /* clear pi system */
|
||||
#define PI_SPRQ 004000 /* set prog req */
|
||||
#define PI_SENB 002000 /* set enables */
|
||||
#define PI_CENB 001000 /* clear enables */
|
||||
#define PI_CON 000400 /* turn off pi system */
|
||||
#define PI_SON 000200 /* turn on pi system */
|
||||
#define PI_M_LVL 000177 /* level mask */
|
||||
#define PI_V_PRQ 18 /* in CONI */
|
||||
#define PI_V_ACT 8
|
||||
#define PI_V_ON 7
|
||||
#define PI_V_ENB 0
|
||||
|
||||
/* Arithmetic processor flags */
|
||||
|
||||
#define APR_SENB 0100000 /* set enable */
|
||||
#define APR_CENB 0040000 /* clear enable */
|
||||
#define APR_CFLG 0020000 /* clear flag */
|
||||
#define APR_SFLG 0010000 /* set flag */
|
||||
#define APR_IRQ 0000010 /* int request */
|
||||
#define APR_M_LVL 0000007 /* pi level */
|
||||
#define APR_V_FLG 4 /* system flags */
|
||||
#define APR_M_FLG 0377
|
||||
#define APRF_ITC (002000 >> APR_V_FLG) /* int console flag */
|
||||
#define APRF_NXM (000400 >> APR_V_FLG) /* nxm flag */
|
||||
#define APRF_TIM (000040 >> APR_V_FLG) /* timer request */
|
||||
#define APRF_CON (000020 >> APR_V_FLG) /* console int */
|
||||
#define APR_GETF(x) (((x) >> APR_V_FLG) & APR_M_FLG)
|
||||
|
||||
/* Virtual address, DEC paging */
|
||||
|
||||
#define PAG_V_OFF 0 /* offset - must be 0 */
|
||||
#define PAG_N_OFF 9 /* page offset width */
|
||||
#define PAG_SIZE 01000 /* page offset size */
|
||||
#define PAG_M_OFF 0777 /* mask for offset */
|
||||
#define PAG_V_PN PAG_N_OFF /* page number */
|
||||
#define PAG_N_PPN (PASIZE - PAG_N_OFF) /* phys pageno width */
|
||||
#define PAG_M_PPN 03777 /* phys pageno mask */
|
||||
#define PAG_PPN 03777000
|
||||
#define PAG_N_VPN (VASIZE - PAG_N_OFF) /* virt pageno width */
|
||||
#define PAG_M_VPN 0777 /* virt pageno mask */
|
||||
#define PAG_VPN 0777000
|
||||
#define PAG_GETOFF(x) ((x) & PAG_M_OFF)
|
||||
#define PAG_GETVPN(x) (((x) >> PAG_V_PN) & PAG_M_VPN)
|
||||
#define PAG_XPTEPA(p,x) (((p) + PAG_GETOFF (x)) & PAMASK)
|
||||
#define PAG_PTEPA(p,x) (((((int32) (p)) & PTE_PPMASK) << PAG_V_PN) + PAG_GETOFF (x))
|
||||
|
||||
/* Page table entry, TOPS-10 paging */
|
||||
|
||||
#define PTE_T10_A 0400000 /* T10: access */
|
||||
#define PTE_T10_P 0200000 /* T10: public */
|
||||
#define PTE_T10_W 0100000 /* T10: writeable */
|
||||
#define PTE_T10_S 0040000 /* T10: software */
|
||||
#define PTE_T10_C 0020000 /* T10: cacheable */
|
||||
#define PTE_PPMASK PAG_M_PPN
|
||||
|
||||
/* Page table entry, TOPS-20 paging */
|
||||
|
||||
#define PTE_T20_V_TYP 33 /* T20: pointer type */
|
||||
#define PTE_T20_M_TYP 07
|
||||
#define T20_NOA 0 /* no access */
|
||||
#define T20_IMM 1 /* immediate */
|
||||
#define T20_SHR 2 /* shared */
|
||||
#define T20_IND 3 /* indirect */
|
||||
#define PTE_T20_W 0020000000000 /* T20: writeable */
|
||||
#define PTE_T20_C 0004000000000 /* T20: cacheable */
|
||||
#define PTE_T20_STM 0000077000000 /* T20: storage medium */
|
||||
#define PTE_T20_V_PMI 18 /* page map index */
|
||||
#define PTE_T20_M_PMI 0777
|
||||
#define T20_GETTYP(x) ((int32) (((x) >> PTE_T20_V_TYP) & PTE_T20_M_TYP))
|
||||
#define T20_GETPMI(x) ((int32) (((x) >> PTE_T20_V_PMI) & PTE_T20_M_PMI))
|
||||
|
||||
/* CST entry, TOPS-20 paging */
|
||||
|
||||
#define CST_AGE 0770000000000 /* age field */
|
||||
#define CST_M 0000000000001 /* modified */
|
||||
|
||||
/* Page fail word, DEC paging */
|
||||
|
||||
#define PF_USER 0400000000000 /* user mode */
|
||||
#define PF_HARD 0200000000000 /* nx I/O reg */
|
||||
#define PF_NXM 0370000000000 /* nx memory */
|
||||
#define PF_T10_A 0100000000000 /* T10: pte A bit */
|
||||
#define PF_T10_W 0040000000000 /* T10: pte W bit */
|
||||
#define PF_T10_S 0020000000000 /* T10: pte S bit */
|
||||
#define PF_T20_DN 0100000000000 /* T20: eval done */
|
||||
#define PF_T20_M 0040000000000 /* T20: modified */
|
||||
#define PF_T20_W 0020000000000 /* T20: writeable */
|
||||
#define PF_WRITE 0010000000000 /* write reference */
|
||||
#define PF_PUB 0004000000000 /* pte public bit */
|
||||
#define PF_C 0002000000000 /* pte C bit */
|
||||
#define PF_VIRT 0001000000000 /* pfl: virt ref */
|
||||
#define PF_NXMP 0001000000000 /* nxm: phys ref */
|
||||
#define PF_IO 0000200000000 /* I/O reference */
|
||||
#define PF_BYTE 0000020000000 /* I/O byte ref */
|
||||
|
||||
/* Virtual address, ITS paging */
|
||||
|
||||
#define ITS_V_OFF 0 /* offset - must be 0 */
|
||||
#define ITS_N_OFF 10 /* page offset width */
|
||||
#define ITS_SIZE 02000 /* page offset size */
|
||||
#define ITS_M_OFF 01777 /* mask for offset */
|
||||
#define ITS_V_PN ITS_N_OFF /* page number */
|
||||
#define ITS_N_PPN (PASIZE- ITS_N_OFF) /* phys pageno width */
|
||||
#define ITS_M_PPN 01777 /* phys pageno mask */
|
||||
#define ITS_PPN 03776000
|
||||
#define ITS_N_VPN (VASIZE - ITS_N_OFF) /* virt pageno width */
|
||||
#define ITS_M_VPN 0377 /* virt pageno mask */
|
||||
#define ITS_VPN 0776000
|
||||
#define ITS_GETVPN(x) (((x) >> ITS_V_PN) & ITS_M_VPN)
|
||||
|
||||
/* Page table entry, ITS paging */
|
||||
|
||||
#define PTE_ITS_V_ACC 16 /* access field */
|
||||
#define PTE_ITS_M_ACC 03
|
||||
#define ITS_ACC_NO 0 /* no access */
|
||||
#define ITS_ACC_RO 1 /* read only */
|
||||
#define ITS_ACC_RWF 2 /* read-write first */
|
||||
#define ITS_ACC_RW 3 /* read write */
|
||||
#define PTE_ITS_AGE 0020000 /* age */
|
||||
#define PTE_ITS_C 0010000 /* cacheable */
|
||||
#define PTE_ITS_PPMASK ITS_M_PPN
|
||||
#define ITS_GETACC(x) (((x) >> PTE_ITS_V_ACC) & PTE_ITS_M_ACC)
|
||||
|
||||
/* Page fail word, ITS paging */
|
||||
|
||||
#define PF_ITS_WRITE 0010000000000 /* write reference */
|
||||
#define PF_ITS_V_ACC 28 /* access from PTE */
|
||||
|
||||
/* Page table fill operations */
|
||||
|
||||
#define PTF_RD 0 /* read check */
|
||||
#define PTF_WR 1 /* write check */
|
||||
#define PTF_MAP 2 /* map instruction */
|
||||
#define PTF_CON 4 /* console access */
|
||||
|
||||
/* User base register */
|
||||
|
||||
#define UBR_SETACB 0400000000000 /* set AC blocks */
|
||||
#define UBR_SETUBR 0100000000000 /* set UBR */
|
||||
#define UBR_V_CURAC 27 /* current AC block */
|
||||
#define UBR_V_PRVAC 24 /* previous AC block */
|
||||
#define UBR_M_AC 07
|
||||
#define UBR_ACBMASK 0007700000000
|
||||
#define UBR_V_UBR 0 /* user base register */
|
||||
#define UBR_N_UBR 11
|
||||
#define UBR_M_UBR 03777
|
||||
#define UBR_UBRMASK 0000000003777
|
||||
#define UBR_GETCURAC(x) ((int32) (((x) >> UBR_V_CURAC) & UBR_M_AC))
|
||||
#define UBR_GETPRVAC(x) ((int32) (((x) >> UBR_V_PRVAC) & UBR_M_AC))
|
||||
#define UBR_GETUBR(x) ((int32) (((x) >> UBR_V_UBR) & PAG_M_PPN))
|
||||
#define UBRWORD (ubr | UBR_SETACB | UBR_SETUBR)
|
||||
|
||||
/* Executive base register */
|
||||
|
||||
#define EBR_V_T20P 14 /* TOPS20 paging */
|
||||
#define EBR_T20P (1u << EBR_V_T20P)
|
||||
#define EBR_V_PGON 13 /* enable paging */
|
||||
#define EBR_PGON (1u << EBR_V_PGON)
|
||||
#define EBR_V_EBR 0 /* exec base register */
|
||||
#define EBR_N_EBR 11
|
||||
#define EBR_M_EBR 03777
|
||||
#define EBR_MASK (EBR_T20P | EBR_PGON | (EBR_M_EBR << EBR_V_EBR))
|
||||
#define EBR_GETEBR(x) ((int32) (((x) >> EBR_V_EBR) & PAG_M_PPN))
|
||||
#define PAGING (ebr & EBR_PGON)
|
||||
#define T20 (ebr & EBR_T20P)
|
||||
|
||||
/* AC and mapping contexts
|
||||
|
||||
There are only two real contexts for selecting the AC block and
|
||||
the memory map: current and previous. However, PXCT allows the
|
||||
choice of current versus previous to be made selectively for
|
||||
various parts of an instruction. The PXCT flags are kept in a
|
||||
dynamic CPU variable.
|
||||
*/
|
||||
|
||||
#define EA_PXCT 010 /* eff addr calc */
|
||||
#define OPND_PXCT 004 /* operand, bdst */
|
||||
#define EABP_PXCT 002 /* bp eff addr calc */
|
||||
#define BSTK_PXCT 001 /* stk, bp op, bsrc */
|
||||
#define XSRC_PXCT 002 /* extend source */
|
||||
#define XDST_PXCT 001 /* extend destination */
|
||||
#define MM_CUR 000 /* current context */
|
||||
#define MM_EA (pflgs & EA_PXCT)
|
||||
#define MM_OPND (pflgs & OPND_PXCT)
|
||||
#define MM_EABP (pflgs & EABP_PXCT)
|
||||
#define MM_BSTK (pflgs & BSTK_PXCT)
|
||||
|
||||
/* Accumulator access. The AC blocks are kept in array acs[AC_NBLK * AC_NUM].
|
||||
Two pointers are provided to the bases of the current and previous blocks.
|
||||
Macro AC selects the current AC block; macro XR selects current or previous,
|
||||
depending on whether the selected bit in the "pxct in progress" flag is set.
|
||||
*/
|
||||
|
||||
#define AC_NUM 16 /* # AC's/block */
|
||||
#define AC_NBLK 8 /* # AC blocks */
|
||||
#define AC(r) (ac_cur[r]) /* AC select current */
|
||||
#define XR(r,prv) ((prv)? ac_prv[r]: ac_cur[r]) /* AC select context */
|
||||
#define ADDAC(x,i) (((x) + (i)) & INST_M_AC)
|
||||
#define P1 ADDAC (ac, 1)
|
||||
|
||||
/* User process table entries */
|
||||
|
||||
#define UPT_T10_UMAP 0000 /* T10: user map */
|
||||
#define UPT_T10_X340 0400 /* T10: exec 340-377 */
|
||||
#define UPT_TRBASE 0420 /* trap base */
|
||||
#define UPT_MUUO 0424 /* MUUO block */
|
||||
#define UPT_MUPC 0425 /* caller's PC */
|
||||
#define UPT_T10_CTX 0426 /* T10: context */
|
||||
#define UPT_T20_UEA 0426 /* T20: address */
|
||||
#define UPT_T20_CTX 0427 /* T20: context */
|
||||
#define UPT_ENPC 0430 /* MUUO new PC, exec */
|
||||
#define UPT_1PO 0432 /* ITS 1-proc: old PC */
|
||||
#define UPT_1PN 0433 /* ITS 1-proc: new PC */
|
||||
#define UPT_UNPC 0434 /* MUUO new PC, user */
|
||||
#define UPT_NPCT 1 /* PC offset if trap */
|
||||
#define UPT_T10_PAG 0500 /* T10: page fail blk */
|
||||
#define UPT_T20_PFL 0500 /* T20: page fail wd */
|
||||
#define UPT_T20_OFL 0501 /* T20: flags */
|
||||
#define UPT_T20_OPC 0502 /* T20: old PC */
|
||||
#define UPT_T20_NPC 0503 /* T20: new PC */
|
||||
#define UPT_T20_SCTN 0540 /* T20: section 0 ptr */
|
||||
|
||||
/* Exec process table entries */
|
||||
|
||||
#define EPT_PIIT 0040 /* PI interrupt table */
|
||||
#define EPT_UBIT 0100 /* Unibus intr table */
|
||||
#define EPT_T10_X400 0200 /* T10: exec 400-777 */
|
||||
#define EPT_TRBASE 0420 /* trap base */
|
||||
#define EPT_ITS_PAG 0440 /* ITS: page fail blk */
|
||||
#define EPT_T20_SCTN 0540 /* T20: section 0 ptr */
|
||||
#define EPT_T10_X000 0600 /* T10: exec 0 - 337 */
|
||||
|
||||
/* Microcode constants */
|
||||
|
||||
#define UC_INHCST 0400000000000 /* inhibit CST update */
|
||||
#define UC_UBABLT 0040000000000 /* BLTBU and BLTUB */
|
||||
#define UC_KIPAGE 0020000000000 /* "KI" paging */
|
||||
#define UC_KLPAGE 0010000000000 /* "KL" paging */
|
||||
#define UC_VERDEC (0130 << 18) /* ucode version */
|
||||
#define UC_VERITS (262u << 18)
|
||||
#define UC_SERDEC 4097 /* serial number */
|
||||
#define UC_SERITS 1729
|
||||
#define UC_AIDDEC (UC_INHCST | UC_UBABLT | UC_KIPAGE | UC_KLPAGE | \
|
||||
UC_VERDEC | UC_SERDEC)
|
||||
#define UC_AIDITS (UC_KIPAGE | UC_VERITS | UC_SERITS)
|
||||
#define UC_HSBDEC 0376000 /* DEC initial HSB */
|
||||
#define UC_HSBITS 0000500 /* ITS initial HSB */
|
||||
|
||||
/* Front end communications region */
|
||||
|
||||
#define FE_SWITCH 030 /* halt switch */
|
||||
#define FE_KEEPA 031 /* keep alive */
|
||||
#define FE_CTYIN 032 /* console in */
|
||||
#define FE_CTYOUT 033 /* console out */
|
||||
#define FE_KLININ 034 /* KLINIK in */
|
||||
#define FE_KLINOUT 035 /* KLINIK out */
|
||||
#define FE_RHBASE 036 /* boot: RH11 addr */
|
||||
#define FE_UNIT 037 /* boot: unit num */
|
||||
#define FE_MTFMT 040 /* boot: magtape params */
|
||||
#define FE_CVALID 0400 /* char valid flag */
|
||||
|
||||
/* Halfword operations */
|
||||
|
||||
#define ADDL(x,y) (((x) + ((y) << 18)) & LMASK)
|
||||
#define ADDR(x,y) (((x) + (y)) & RMASK)
|
||||
#define INCL(x) ADDL (x, 1)
|
||||
#define INCR(x) ADDR (x, 1)
|
||||
#define AOB(x) (INCL (x) | INCR(x))
|
||||
#define SUBL(x,y) (((x) - ((y) << 18)) & LMASK)
|
||||
#define SUBR(x,y) (((x) - (y)) & RMASK)
|
||||
#define DECL(x) SUBL (x, 1)
|
||||
#define DECR(x) SUBR (x, 1)
|
||||
#define SOB(x) (DECL (x) | DECR(x))
|
||||
#define LLZ(x) ((x) & LMASK)
|
||||
#define RLZ(x) (((x) << 18) & LMASK)
|
||||
#define RRZ(x) ((x) & RMASK)
|
||||
#define LRZ(x) (((x) >> 18) & RMASK)
|
||||
#define LIT8(x) (((x) & RSIGN)? \
|
||||
(((x) & 0377)? (-(x) & 0377): 0400): ((x) & 0377))
|
||||
|
||||
/* Fullword operations */
|
||||
|
||||
#define INC(x) (((x) + 1) & DMASK)
|
||||
#define DEC(x) (((x) - 1) & DMASK)
|
||||
#define SWP(x) ((((x) << 18) & LMASK) | (((x) >> 18) & RMASK))
|
||||
#define XWD(x,y) (((((d10) (x)) << 18) & LMASK) | (((d10) (y)) & RMASK))
|
||||
#define SETS(x) ((x) | SIGN)
|
||||
#define CLRS(x) ((x) & ~SIGN)
|
||||
#define TSTS(x) ((x) & SIGN)
|
||||
#define NEG(x) (-(x) & DMASK)
|
||||
#define ABS(x) (TSTS (x)? NEG(x): (x))
|
||||
#define SXT(x) (TSTS (x)? (x) | ~DMASK: (x))
|
||||
|
||||
/* Doubleword operations (on 2-word arrays) */
|
||||
|
||||
#define DMOVN(rs) rs[1] = (-rs[1]) & MMASK; \
|
||||
rs[0] = (~rs[0] + (rs[1] == 0)) & DMASK
|
||||
#define MKDNEG(rs) rs[1] = SETS (-rs[1]) & DMASK; \
|
||||
rs[0] = (~rs[0] + (rs[1] == MAXNEG)) & DMASK
|
||||
#define DCMPGE(a,b) ((a[0] > b[0]) || ((a[0] == b[0]) && (a[1] >= b[1])))
|
||||
|
||||
/* Address operations */
|
||||
|
||||
#define ADDA(x,i) (((x) + (i)) & AMASK)
|
||||
#define INCA(x) ADDA (x, 1)
|
||||
|
||||
/* Unibus adapter control/status register */
|
||||
|
||||
#define UBCS_TMO 0400000 /* timeout */
|
||||
#define UBCS_BMD 0200000 /* bad mem data NI */
|
||||
#define UBCS_PAR 0100000 /* parity error NI */
|
||||
#define UBCS_NXD 0040000 /* nx device */
|
||||
#define UBCS_HI 0004000 /* irq on BR7 or BR6 */
|
||||
#define UBCS_LO 0002000 /* irq on BR5 or BR4 */
|
||||
#define UBCS_PWR 0001000 /* power low NI */
|
||||
#define UBCS_DXF 0000200 /* disable xfer NI*/
|
||||
#define UBCS_INI 0000100 /* Unibus init */
|
||||
#define UBCS_RDZ 0030500 /* read as zero */
|
||||
#define UBCS_RDW 0000277 /* read/write bits */
|
||||
#define UBCS_V_LHI 3 /* hi pri irq level */
|
||||
#define UBCS_V_LLO 0 /* lo pri irq level */
|
||||
#define UBCS_M_PRI 07
|
||||
#define UBCS_GET_HI(x) (((x) >> UBCS_V_LHI) & UBCS_M_PRI)
|
||||
#define UBCS_GET_LO(x) (((x) >> UBCS_V_LLO) & UBCS_M_PRI)
|
||||
|
||||
/* Unibus adapter page map */
|
||||
|
||||
#define UBANUM 2 /* # of Unibus adapters */
|
||||
#define UMAP_ASIZE 6 /* address size */
|
||||
#define UMAP_MEMSIZE (1 << UMAP_ASIZE) /* length */
|
||||
#define UMAP_AMASK (UMAP_MEMSIZE - 1)
|
||||
#define UMAP_V_RRV 30 /* read reverse */
|
||||
#define UMAP_V_DSB 29 /* 16b on NPR read */
|
||||
#define UMAP_V_FST 28 /* fast transfer */
|
||||
#define UMAP_V_VLD 27 /* valid flag */
|
||||
#define UMAP_RRV (1 << UMAP_V_RRV)
|
||||
#define UMAP_DSB (1 << UMAP_V_DSB)
|
||||
#define UMAP_FST (1 << UMAP_V_FST)
|
||||
#define UMAP_VLD (1 << UMAP_V_VLD)
|
||||
#define UMAP_V_FLWR 14 /* flags as written */
|
||||
#define UMAP_V_FLRD 27 /* flags as stored */
|
||||
#define UMAP_M_FL 017
|
||||
#define UMAP_V_PNWR 0 /* page num, write */
|
||||
#define UMAP_V_PNRD 9 /* page num, read */
|
||||
#define UMAP_M_PN 03777
|
||||
#define UMAP_MASK ((UMAP_M_FL << UMAP_V_FLRD) | (UMAP_M_PN << UMAP_V_PNRD))
|
||||
#define UMAP_POSFL(x) (((x) & (UMAP_M_FL << UMAP_V_FLWR)) \
|
||||
<< (UMAP_V_FLRD - UMAP_V_FLWR))
|
||||
#define UMAP_POSPN(x) (((x) & (UMAP_M_PN << UMAP_V_PNWR)) \
|
||||
<< (UMAP_V_PNRD - UMAP_V_PNWR))
|
||||
|
||||
/* Unibus I/O constants */
|
||||
|
||||
#define READ 0 /* PDP11 compatible */
|
||||
/* #define READC 1 /* console read */
|
||||
#define WRITE 2
|
||||
/* #define WRITEC 3 /* console write */
|
||||
#define WRITEB 4
|
||||
#define IO_V_UBA 18 /* UBA in I/O addr */
|
||||
#define IO_N_UBA 16 /* max num of UBA's */
|
||||
#define IO_M_UBA (IO_N_UBA - 1)
|
||||
#define IO_UBA1 (1 << IO_V_UBA)
|
||||
#define IO_UBA3 (3 << IO_V_UBA)
|
||||
#define GET_IOUBA(x) (((x) >> IO_V_UBA) & IO_M_UBA)
|
||||
|
||||
/* DZ11 parameters */
|
||||
|
||||
#define DZ_MUXES 1 /* # of muxes */
|
||||
#define DZ_LINES 8 /* lines per mux */
|
||||
|
||||
/* I/O page layout */
|
||||
|
||||
#define IOBA_DZ 0760010 /* DZ11 */
|
||||
#define IOLN_DZ (010 * DZ_MUXES)
|
||||
#define IOBA_TCU 0760770 /* TCU150 */
|
||||
#define IOLN_TCU 006
|
||||
#define IOBA_UBMAP 0763000 /* Unibus map */
|
||||
#define IOLN_UBMAP 0100
|
||||
#define IOBA_UBCS 0763100 /* Unibus c/s reg */
|
||||
#define IOLN_UBCS 001
|
||||
#define IOBA_UBMNT 0763101 /* Unibus maint reg */
|
||||
#define IOLN_UBMNT 001
|
||||
#define IOBA_TU 0772440 /* RH11/tape */
|
||||
#define IOLN_TU 034
|
||||
#define IOBA_RP 0776700 /* RH11/disk */
|
||||
#define IOLN_RP 050
|
||||
#define IOBA_LP20 0775400 /* LP20 */
|
||||
#define IOLN_LP20 020
|
||||
#define IOBA_PT 0777550 /* PC11 */
|
||||
#define IOLN_PT 010
|
||||
|
||||
/* Common Unibus CSR 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)
|
||||
|
||||
/* I/O system definitions, lifted from the PDP-11 simulator
|
||||
Interrupt assignments, priority is right to left
|
||||
|
||||
<3:0> = BR7
|
||||
<7:4> = BR6
|
||||
<19:8> = BR5
|
||||
<30:20> = BR4
|
||||
*/
|
||||
|
||||
#define INT_V_RP 6 /* RH11/RP,RM drives */
|
||||
#define INT_V_TU 7 /* RH11/TM03/TU45 */
|
||||
#define INT_V_DZRX 16 /* DZ11 */
|
||||
#define INT_V_DZTX 17
|
||||
#define INT_V_PTR 24 /* PC11 */
|
||||
#define INT_V_PTP 25
|
||||
#define INT_V_LP20 26 /* LPT20 */
|
||||
|
||||
#define INT_RP (1u << INT_V_RP)
|
||||
#define INT_TU (1u << INT_V_TU)
|
||||
#define INT_DZRX (1u << INT_V_DZRX)
|
||||
#define INT_DZTX (1u << INT_V_DZTX)
|
||||
#define INT_PTR (1u << INT_V_PTR)
|
||||
#define INT_PTP (1u << INT_V_PTP)
|
||||
#define INT_LP20 (1u << INT_V_LP20)
|
||||
|
||||
#define IPL_RP 6 /* int levels */
|
||||
#define IPL_TU 6
|
||||
#define IPL_DZRX 5
|
||||
#define IPL_DZTX 5
|
||||
#define IPL_PTR 4
|
||||
#define IPL_PTP 4
|
||||
#define IPL_LP20 4
|
||||
|
||||
#define INT_UB1 INT_RP /* on Unibus 1 */
|
||||
#define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */
|
||||
|
||||
#define INT_IPL7 0x0000000F /* int level masks */
|
||||
#define INT_IPL6 0x000000F0
|
||||
#define INT_IPL5 0x000FFF00
|
||||
#define INT_IPL4 0x3FF00000
|
||||
|
||||
#define VEC_PTR 0070 /* interrupt vectors */
|
||||
#define VEC_PTP 0074
|
||||
#define VEC_TU 0224
|
||||
#define VEC_RP 0254
|
||||
#define VEC_DZRX 0340
|
||||
#define VEC_DZTX 0344
|
||||
#define VEC_LP20 0754
|
||||
|
||||
#define IREQ(dv) int_req
|
||||
#define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv)
|
||||
#define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv)
|
||||
526
PDP10/pdp10_doc.txt
Normal file
526
PDP10/pdp10_doc.txt
Normal file
@@ -0,0 +1,526 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: PDP-10 Simulator Usage
|
||||
Date: 1-Dec-01
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2001, written by Robert M Supnik
|
||||
Copyright (c) 1993-2001, 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 memorandum documents the PDP-10 simulator.
|
||||
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
To compile the PDP-10, you must define USE_INT64 as part of the compilation
|
||||
command line.
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_sock.h
|
||||
sim_tmxr.h
|
||||
dec_dz.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_rev.c
|
||||
sim_sock.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/pdp10/ pdp10_defs.h
|
||||
pdp10_cpu.c
|
||||
pdp10_dz.c
|
||||
pdp10_fe.c
|
||||
pdp10_ksio.c
|
||||
pdp10_lp20.c
|
||||
pdp10_mdfp.c
|
||||
pdp10_pag.c
|
||||
pdp10_pt.c
|
||||
pdp10_rp.c
|
||||
pdp10_sys.c
|
||||
pdp10_tu.c
|
||||
pdp10_xtnd.c
|
||||
|
||||
2. PDP-10 Features
|
||||
|
||||
The PDP-10 simulator is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU KS10 CPU with 1MW of memory
|
||||
PAG paging unit (translation maps)
|
||||
UBA Unibus adapters (translation maps)
|
||||
FE console
|
||||
TIM timer
|
||||
PTR,PTP PC11 paper tape reader/punch
|
||||
DZ DZ11 8-line terminal multiplexor
|
||||
LP20 LP20 line printer
|
||||
RP RH11/RP04/RP05/RP06/RP07/RM03/RM05/RM80 controller with
|
||||
eight drives
|
||||
TU RH11/TM02/TU45 controller with eight drives
|
||||
|
||||
The PTR/PTP are initially DISABLEd. The DZ11 can also be DISABLEd.
|
||||
|
||||
The PDP-10 simulator implements several unique stop condition:
|
||||
|
||||
- illegal instruction (000) in kernel mode
|
||||
- indirect addressing nesting exceeds limit
|
||||
- execute chaining exceeds limit
|
||||
- page fail or other error in interrupt sequence
|
||||
- illegal instruction in interrupt sequence
|
||||
- invalid vector pointer in interrupt sequence
|
||||
- invalid Unibus adapter number
|
||||
- non-existent exec or user page table address
|
||||
|
||||
The PDP-10 loader supports RIM10B format paper tapes, SAV binary files, and
|
||||
EXE binary files. LOAD switches -r, -s, -e specify RIM10, SAV, EXE format,
|
||||
respectively. If no switch is specified, the LOAD command checks the file
|
||||
extension; .RIM, .SAV, .EXE specify RIM10, SAV, EXE format, respectively.
|
||||
If no switch specified, and no extension matches, the LOAD command checks
|
||||
the file format to try to determine the file type.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
The CPU options allow the user to specify standard microcode, standard
|
||||
microcode with a bug fix for a boostrap problem in TOPS-20 V4.1, or ITS
|
||||
microcode
|
||||
|
||||
SET CPU STANDARD Standard microcode
|
||||
SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix
|
||||
SET CPU ITS ITS compatible microcode
|
||||
|
||||
CPU registers include the visible state of the processor as well as the
|
||||
control registers for the interrupt system.
|
||||
|
||||
name size comments
|
||||
|
||||
PC 18 program counter
|
||||
FLAGS 18 processor flags (<13:17> unused)
|
||||
AC0..AC17 36 accumulators
|
||||
IR 36 instruction register
|
||||
EBR 18 executive base register
|
||||
PGON 1 paging enabled flag
|
||||
T20P 1 TOPS-20 paging
|
||||
UBR 18 user base register
|
||||
CURAC 3 current AC block
|
||||
PRVAC 3 previous AC block
|
||||
SPT 36 shared pointer table
|
||||
CST 36 core status table
|
||||
PUR 36 process update register
|
||||
CSTM 36 CST mask
|
||||
HSB 18 halt status block address
|
||||
DBR1 18 descriptor base register 1 (ITS)
|
||||
DBR2 18 descriptor base register 2 (ITS)
|
||||
DBR3 18 descriptor base register 3 (ITS)
|
||||
DBR4 18 descriptor base register 4 (ITS)
|
||||
PIENB 7 PI levels enabled
|
||||
PIACT 7 PI levels active
|
||||
PIPRQ 7 PI levels with program requests
|
||||
PIIOQ 7 PI levels with IO requests
|
||||
PIAPR 7 PI levels with APR requests
|
||||
APRENB 8 APR flags enabled
|
||||
APRFLG 8 APR flags active
|
||||
APRLVL 3 PI level for APR interrupt
|
||||
IND_MAX 8 indirect address nesting limit
|
||||
XCT_MAX 8 execute chaining limit
|
||||
OLDPC 18 PC prior to last transfer instruction
|
||||
WRU 8 interrupt character
|
||||
REG[0:127] 36 fast memory blocks
|
||||
|
||||
2.2 Pager
|
||||
|
||||
The pager contains the page maps for executive and user mode. The
|
||||
executive page map is the memory space for unit 0, the user page map the
|
||||
memory space for unit 1. A page map entry is 32 bits wide and has the
|
||||
following format:
|
||||
|
||||
bit content
|
||||
--- -------
|
||||
31 page is writeable
|
||||
30 entry is valid
|
||||
29:19 mbz
|
||||
18:9 physical page base address
|
||||
8:0 mbz
|
||||
|
||||
The pager has no registers.
|
||||
|
||||
2.3 Unibus Adapters
|
||||
|
||||
The Unibus adapters link the system I/O devices to the CPU. Unibus
|
||||
adapter 1 (UBA1) is unit 0, and Unibus adapter 3 is unit 1. The
|
||||
adapter's Unibus map is the memory space of the corresponding unit.
|
||||
|
||||
The Unibus Adapter has the following registers:
|
||||
|
||||
name size comments
|
||||
|
||||
INTREQ 32 interrupt requests
|
||||
UB1CS 16 Unibus adapter 1 control/status
|
||||
UB3CS 16 Unibus adapter 3 control/status
|
||||
|
||||
2.4 Front End (FE)
|
||||
|
||||
The front end is the system console. The keyboard input is unit 0,
|
||||
the console output is unit 1. It supports two options:
|
||||
|
||||
SET FE STOP halts the PDP-10 operating system
|
||||
SET FE CTLC simulates typing ^C (for Windoze)
|
||||
|
||||
The front end has the following registers:
|
||||
|
||||
name size comments
|
||||
|
||||
IBUF 8 input buffer
|
||||
ICOUNT 31 count of input characters
|
||||
ITIME 24 keyboard polling interval
|
||||
OBUF 8 output buffer
|
||||
OCOUNT 31 count of output characters
|
||||
OTIME 24 console output response time
|
||||
|
||||
2.5 Timer (TIM)
|
||||
|
||||
The timer (TIM) implements the system timer, the interval timer, and
|
||||
the time of day clock used to get the date and time at system startup.
|
||||
Because most PDP-10 software is not Y2K compliant, the timer implements
|
||||
one option
|
||||
|
||||
SET TIM NOY2K software not Y2K compliant, limit time
|
||||
of day clock to 1999 (default)
|
||||
SET TIM Y2K software is Y2K compliant
|
||||
|
||||
The timer has the following registers:
|
||||
|
||||
name size comments
|
||||
|
||||
TIMBASE 59 time base (double precision)
|
||||
TTG 36 time to go (remaining time) for interval
|
||||
PERIOD 36 reset value for interval
|
||||
QUANT 36 quantum timer (ITS only)
|
||||
TIME 24 tick delay
|
||||
DIAG 1 use fixed tick delay instead of autocalibration
|
||||
|
||||
Unless the DIAG flag is set, the timer autocalibrates; the tick delay
|
||||
is adjusted up or down so that the time base tracks actual elapsed time.
|
||||
This may cause time-dependent diagnostics to report errors.
|
||||
|
||||
2.6 PC11 Paper Tape Reader (PTR)
|
||||
|
||||
The paper tape reader (PTR) reads data from a disk file. The POS
|
||||
register specifies the number of the next data item to be read. Thus,
|
||||
by changing POS, the user can backspace or advance the reader.
|
||||
|
||||
The paper tape reader implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
CSR 16 control/status register
|
||||
INT 1 interrupt pending flag
|
||||
ERR 1 error flag (CSR<15>)
|
||||
BUSY 1 busy flag (CSR<11>)
|
||||
DONE 1 device done flag (CSR<7>)
|
||||
IE 1 interrupt enable flag (CSR<6>)
|
||||
POS 31 position in the input file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
end of file 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
|
||||
2.7 PC11 Paper Tape Punch (PTP)
|
||||
|
||||
The paper tape punch (PTP) writes data to a disk file. The POS
|
||||
register specifies the number of the next data item to be written.
|
||||
Thus, by by changing POS, the user can backspace or advance the punch.
|
||||
|
||||
The paper tape punch implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
CSR 16 control/status register
|
||||
INT 1 interrupt pending flag
|
||||
ERR 1 error flag (CSR<15>)
|
||||
DONE 1 device done flag (CSR<7>)
|
||||
IE 1 interrupt enable flag (CSR<6>)
|
||||
POS 31 position in the input or output file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.8 DZ11 Terminal Multiplexor (DZ)
|
||||
|
||||
The DZ11 is an 8-line terminal multiplexor. The terminal lines perform
|
||||
input and output through Telnet sessions connected to a user-specified
|
||||
port. The ATTACH command specifies the port to be used:
|
||||
|
||||
ATTACH {-am} DZ <port>(cr) -- set up listening port
|
||||
|
||||
where port is a decimal number between 1 and 65535 that is not being used
|
||||
for other TCP/IP activities. The optional switch -m turns on the DZ11's
|
||||
modem controls; the optional switch -a turns on active disconnects
|
||||
(disconnect session if computer clears Data Terminal Ready).
|
||||
|
||||
Once the DZ is attached and the simulator is running, the DZ will listen
|
||||
for connections on the specified port. It assumes that the incoming
|
||||
connections are Telnet connections. The connection remains open until
|
||||
disconnected either by the simulated program or by the Telnet client.
|
||||
|
||||
The SHOW DZ LINESTATUS command displays the current connections to the DZ.
|
||||
|
||||
The DZ11 implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
CSR 16 control/status register
|
||||
RBUF 16 receive buffer
|
||||
LPR 16 line parameter register
|
||||
TCR 16 transmission control register
|
||||
MSR 16 modem status register
|
||||
TDR 16 transmit data register
|
||||
SAENB 1 silo alarm enabled
|
||||
MDMTCL 1 modem control enabled
|
||||
AUTODS 1 autodisconnect enabled
|
||||
RPOS0..7 32 count of characters received
|
||||
TPOS0..7 32 count of characters transmitted
|
||||
|
||||
The DZ11 does not support save and restore. All open connections are
|
||||
lost when the simulator shuts down or the DZ is detached.
|
||||
|
||||
2.9 RH11 Adapter, RM02/03/05/80, RP04/05/06/07 drives (RP)
|
||||
|
||||
The RP controller implements the Massbus 18b (RH11) direct interface for
|
||||
large disk drives. It is more abstract than other device simulators, with
|
||||
just enough detail to run operating system drivers. In addition, the RP
|
||||
controller conflates the details of the RM series controllers with the RP
|
||||
series controllers, although there were detailed differences.
|
||||
|
||||
RP options include the ability to set units write enabled or write locked,
|
||||
to set the drive type to one of six disk types, or autosize:
|
||||
|
||||
SET RPn LOCKED set unit n write locked
|
||||
SET RPn ENABLED set unit n write enabled
|
||||
SET RPn RM03 set type to RM03
|
||||
SET RPn RM05 set type to RM05
|
||||
SET RPn RM80 set type to RM80
|
||||
SET RPn RP04 set type to RP04
|
||||
SET RPn RP06 set type to RP06
|
||||
SET RPn RP07 set type to RP07
|
||||
SET RPn AUTOSIZE set type based on file size at attach
|
||||
|
||||
The type options can be used only when a unit is not attached to a file.
|
||||
Note that TOPS-10 V7.03 only supported the RP06 and RM03; V7.04 added
|
||||
support for the RP07. Units can be REMOVEd or ADDed to the configuration.
|
||||
|
||||
The RP controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
RPCS1 16 control/status 1
|
||||
RPWC 16 word count
|
||||
RPBA 16 bus address
|
||||
RPDA 16 desired surface, sector
|
||||
RPCS2 16 control/status 2
|
||||
RPDS[0:7] 16 drive status, drives 0-7
|
||||
RPER1[0:7] 16 drive errors, drives 0-7
|
||||
RPOF 16 offset
|
||||
RPDC 8 desired cylinder
|
||||
RPER2 16 error status 2
|
||||
RPER3 16 error status 3
|
||||
RPEC1 16 ECC syndrome 1
|
||||
RPEC2 16 ECC syndrome 2
|
||||
RPMR 16 maintenance register
|
||||
RPDB 16 data buffer
|
||||
IFF 1 transfer complete interrupt request flop
|
||||
INT 1 interrupt pending flag
|
||||
SC 1 special condition (CSR1<15>)
|
||||
DONE 1 device done flag (CSR1<7>)
|
||||
IE 1 interrupt enable flag (CSR1<6>)
|
||||
STIME 24 seek time, per cylinder
|
||||
RTIME 24 rotational delay
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 disk not ready
|
||||
|
||||
end of file x assume rest of disk is zero
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.10 RH11 Adapter, TM02 Formatter, TU45 Magnetic Tape (TU)
|
||||
|
||||
The magnetic tape simulator simulates an RH11 Massbus adapter with one
|
||||
TM02 formatter and up to eight TU45 drives. Magnetic tape options include
|
||||
the ability to make units write enabled or locked.
|
||||
|
||||
SET TUn LOCKED set unit n write locked
|
||||
SET TUn ENABLED set unit n write enabled
|
||||
|
||||
Units can also be REMOVEd or ADDed to the configuration.
|
||||
|
||||
The magnetic tape controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
MTCS1 16 control/status 1
|
||||
MTBA 16 memory address
|
||||
MTWC 16 word count
|
||||
MTFC 16 frame count
|
||||
MTCS2 16 control/status 2
|
||||
MTFS 16 formatter status
|
||||
MTER 16 error status
|
||||
MTCC 16 check character
|
||||
MTDB 16 data buffer
|
||||
MTMR 16 maintenance register
|
||||
MTTC 16 tape control register
|
||||
INT 1 interrupt pending flag
|
||||
DONE 1 device done flag
|
||||
IE 1 interrupt enable flag
|
||||
STOP_IOE 1 stop on I/O error
|
||||
TIME 24 delay
|
||||
UST[0:7] 16 unit status, units 0-7
|
||||
POS[0:7] 31 position, units 0-7
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached tape not ready
|
||||
|
||||
end of file (read or space) end of physical tape
|
||||
(write) ignored
|
||||
|
||||
OS I/O error report error and stop
|
||||
|
||||
2.11 LP20 DMA Line Printer (LP20)
|
||||
|
||||
The LP20 is a DMA-based line printer controller. There is one
|
||||
line printer option to clear the vertical forms unit (VFU).
|
||||
|
||||
SET LP20 VFUCLEAR clear the vertical forms unit
|
||||
|
||||
The LP20 implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
LPCSA 16 control/status register A
|
||||
LPCSB 16 control/status register B
|
||||
LPBA 16 bus address register
|
||||
LPBC 12 byte count register
|
||||
LPPAGC 12 page count register
|
||||
LPRDAT 12 RAM data register
|
||||
LPCBUF 8 character buffer register
|
||||
LPCOLC 8 column counter register
|
||||
LPPDAT 8 printer data register
|
||||
LPCSUM 8 checksum register
|
||||
DVPTR 7 vertical forms unit pointer
|
||||
DVLNT 7 vertical forms unit length
|
||||
INT 1 interrupt request
|
||||
ERR 1 error flag
|
||||
DONE 1 done flag
|
||||
IE 1 interrupt enable flag
|
||||
POS 31 position in output file
|
||||
TIME 24 response time
|
||||
STOP_IOE 1 stop on I/O error
|
||||
TXRAM[0:255] 12 translation RAM
|
||||
DAVFU[0:142] 12 vertical forms unit array
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of paper
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.12 Symbolic Display and Input
|
||||
|
||||
The PDP-10 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-a display as ASCII character
|
||||
-c display as (sixbit) character string
|
||||
-p display as packed (seven bit) string
|
||||
-m display instruction mnemonics
|
||||
-v interpret address as virtual
|
||||
-e force executive mode
|
||||
-u force user mode
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or -a ASCII character
|
||||
" or -c sixbit string
|
||||
# or -p packed seven bit string
|
||||
alphabetic instruction mnemonic
|
||||
numeric octal number
|
||||
|
||||
Instruction input uses standard PDP-10 assembler syntax. There are three
|
||||
instruction classes: memory reference, memory reference with AC, and I/O.
|
||||
|
||||
Memory reference instructions have the format
|
||||
|
||||
memref {@}address{(index)}
|
||||
|
||||
memory reference with AC instructions have the format
|
||||
|
||||
memac ac,{@}address{(index)}
|
||||
|
||||
and I/O instructions have the format
|
||||
|
||||
io device,{@}address{(index)}
|
||||
|
||||
where @ signifies indirect. The address is a signed octal number in the
|
||||
range 0 - 0777777. The ac and index are unsigned octal numbers in the
|
||||
range 0-17. The device is either a recognized device mnemonic (APR, PI,
|
||||
TIM) or an octal number in the range 0 - 0177.
|
||||
|
||||
The simulator recognizes the standard MACRO alternate mnemonics (CLEAR
|
||||
for SETZ, OR for IORI), the individual definitions for JRST and JFCL
|
||||
variants, and the extended instruction mnemonics.
|
||||
30
PDP10/pdp10_dz.c
Normal file
30
PDP10/pdp10_dz.c
Normal file
@@ -0,0 +1,30 @@
|
||||
/* pdp10_dz.c: DZ11 terminal multiplexor simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
dz DZ11 terminal multiplexor
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include "dec_dz.h"
|
||||
164
PDP10/pdp10_fe.c
Normal file
164
PDP10/pdp10_fe.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/* pdp10_fe.c: PDP-10 front end (console terminal) simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
fe KS10 console front end
|
||||
|
||||
30-Nov-01 RMS Added extended SET/SHOW support
|
||||
23-Oct-01 RMS New IO page address constants
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#define UNIT_DUMMY (1 << UNIT_V_UF)
|
||||
|
||||
extern d10 *M;
|
||||
extern int32 apr_flg;
|
||||
t_stat fei_svc (UNIT *uptr);
|
||||
t_stat feo_svc (UNIT *uptr);
|
||||
t_stat fe_reset (DEVICE *dptr);
|
||||
t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat fe_ctrl_c (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* FE data structures
|
||||
|
||||
fe_dev FE device descriptor
|
||||
fe_unit FE unit descriptor
|
||||
fe_reg FE register list
|
||||
*/
|
||||
|
||||
#define fei_unit fe_unit[0]
|
||||
#define feo_unit fe_unit[1]
|
||||
|
||||
UNIT fe_unit[] = {
|
||||
{ UDATA (&fei_svc, 0, 0), KBD_POLL_WAIT },
|
||||
{ UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT } };
|
||||
|
||||
REG fe_reg[] = {
|
||||
{ ORDATA (IBUF, fei_unit.buf, 8) },
|
||||
{ DRDATA (ICOUNT, fei_unit.pos, 31), REG_RO + PV_LEFT },
|
||||
{ DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ ORDATA (OBUF, feo_unit.buf, 8) },
|
||||
{ DRDATA (OCOUNT, feo_unit.pos, 31), REG_RO + PV_LEFT },
|
||||
{ DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
MTAB fe_mod[] = {
|
||||
{ UNIT_DUMMY, 0, NULL, "STOP", &fe_stop_os },
|
||||
{ UNIT_DUMMY, 0, NULL, "CTRL-C", &fe_ctrl_c },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE fe_dev = {
|
||||
"FE", fe_unit, fe_reg, fe_mod,
|
||||
2, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &fe_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Front end processor (console terminal)
|
||||
|
||||
Communications between the KS10 and its front end is based on an in-memory
|
||||
status block and two interrupt lines: interrupt-to-control (APR_ITC) and
|
||||
interrupt-from-console (APR_CON). When the KS10 wants to print a character
|
||||
on the terminal,
|
||||
|
||||
1. It places a character, plus the valid flag, in FE_CTYOUT.
|
||||
2. It interrupts the front end processor.
|
||||
3. The front end processor types the character and then zeroes FE_CTYOUT.
|
||||
4. The front end procesor interrupts the KS10.
|
||||
|
||||
When the front end wants to send an input character to the KS10,
|
||||
|
||||
1. It places a character, plus the valid flag, in FE_CTYIN.
|
||||
2. It interrupts the KS10.
|
||||
3. It waits for the KS10 to take the character and clear the valid flag.
|
||||
4. It can then send more input (the KS10 may signal this by interrupting
|
||||
the front end).
|
||||
|
||||
Note that the protocol has both ambiguity (interrupt to the KS10 may mean
|
||||
character printed, or input character available, or both) and lack of
|
||||
symmetry (the KS10 does not inform the front end that it has taken an
|
||||
input character).
|
||||
*/
|
||||
|
||||
void fe_intr (void)
|
||||
{
|
||||
if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */
|
||||
feo_unit.buf = (int32) M[FE_CTYOUT] & 0177; /* pick it up */
|
||||
sim_putchar (feo_unit.buf); /* type it */
|
||||
feo_unit.pos = feo_unit.pos + 1;
|
||||
sim_activate (&feo_unit, feo_unit.time); } /* sched completion */
|
||||
else if ((M[FE_CTYIN] & FE_CVALID) == 0) { /* input char taken? */
|
||||
sim_cancel (&fei_unit); /* sched immediate */
|
||||
sim_activate (&fei_unit, 0); }; /* keyboard poll */
|
||||
return;
|
||||
}
|
||||
|
||||
t_stat feo_svc (UNIT *uptr)
|
||||
{
|
||||
M[FE_CTYOUT] = 0; /* clear char */
|
||||
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat fei_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&fei_unit, fei_unit.wait); /* continue poll */
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
|
||||
fei_unit.buf = temp & 0177;
|
||||
fei_unit.pos = fei_unit.pos + 1;
|
||||
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
|
||||
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
|
||||
t_stat fe_reset (DEVICE *dptr)
|
||||
{
|
||||
fei_unit.buf = feo_unit.buf = 0;
|
||||
M[FE_CTYIN] = M[FE_CTYOUT] = 0;
|
||||
apr_flg = apr_flg & ~(APRF_ITC | APRF_CON);
|
||||
sim_activate (&fei_unit, fei_unit.wait); /* start input poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Stop operating system */
|
||||
|
||||
t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Enter control-C for Windoze */
|
||||
|
||||
t_stat fe_ctrl_c (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
fei_unit.buf = 003; /* control-C */
|
||||
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
|
||||
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
|
||||
return SCPE_OK;
|
||||
}
|
||||
551
PDP10/pdp10_ksio.c
Normal file
551
PDP10/pdp10_ksio.c
Normal file
@@ -0,0 +1,551 @@
|
||||
/* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
uba Unibus adapters
|
||||
|
||||
23-Sep-01 RMS New IO page address constants
|
||||
07-Sep-01 RMS Revised device disable mechanism
|
||||
25-Aug-01 RMS Enabled DZ11
|
||||
21-Aug-01 RMS Updated DZ11 disable
|
||||
01-Jun-01 RMS Updated DZ11 vectors
|
||||
12-May-01 RMS Fixed typo
|
||||
|
||||
The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While
|
||||
nominally four adapters are supported, in practice only 1 and 3
|
||||
are implemented. The disks are placed on adapter 1, the rest of
|
||||
the I/O devices on adapter 3.
|
||||
|
||||
In theory, we should maintain completely separate Unibuses, with
|
||||
distinct PI systems. In practice, this simulator has so few devices
|
||||
that we can get away with a single PI system, masking for which
|
||||
devices are on adapter 1, and which on adapter 3. The Unibus
|
||||
implementation is modeled on the Qbus in the PDP-11 simulator and
|
||||
is described there.
|
||||
|
||||
The I/O subsystem is programmed by I/O instructions which create
|
||||
Unibus operations (read, read pause, write, write byte). DMA is
|
||||
the responsibility of the I/O device simulators, which also implement
|
||||
Unibus to physical memory mapping.
|
||||
|
||||
The priority interrupt subsystem (and other privileged functions)
|
||||
is programmed by I/O instructions with internal devices codes
|
||||
(opcodes 700-702). These are dispatched here, although many are
|
||||
handled in the memory management unit or elsewhere.
|
||||
|
||||
The ITS instructions are significantly different from the TOPS-10/20
|
||||
instructions. They do not use the extended address calculation but
|
||||
instead provide instruction variants (Q for Unibus adapter 1, I for
|
||||
Unibus adapter 3) which insert the Unibus adapter number into the
|
||||
effective address.
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#define eaRB (ea & ~1)
|
||||
#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)
|
||||
#define UBNXM_FAIL(pa,op) \
|
||||
n = iocmap[GET_IOUBA (pa)]; \
|
||||
if (n >= 0) ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \
|
||||
pager_word = PF_HARD | PF_VIRT | PF_IO | \
|
||||
((op == WRITEB)? PF_BYTE: 0) | \
|
||||
(TSTF (F_USR)? PF_USER: 0) | (pa); \
|
||||
ABORT (PAGE_FAIL)
|
||||
|
||||
/* Unibus adapter data */
|
||||
|
||||
int32 ubcs[UBANUM] = { 0 }; /* status registers */
|
||||
int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */
|
||||
int32 int_req = 0; /* interrupt requests */
|
||||
|
||||
/* Map IO controller numbers to Unibus adapters: -1 = non-existent */
|
||||
|
||||
static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */
|
||||
-1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
static const int32 ubabr76[UBANUM] = {
|
||||
INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6) };
|
||||
static const int32 ubabr54[UBANUM] = {
|
||||
INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4) };
|
||||
|
||||
extern d10 *ac_cur;
|
||||
extern d10 pager_word;
|
||||
extern int32 flags, pi_l2bit[8];
|
||||
extern UNIT cpu_unit;
|
||||
extern jmp_buf save_env;
|
||||
|
||||
extern d10 Read (a10 ea);
|
||||
extern void pi_eval ();
|
||||
extern t_stat dz_rd (int32 *data, int32 addr, int32 access);
|
||||
extern t_stat dz_wr (int32 data, int32 addr, int32 access);
|
||||
extern int32 dz_enb;
|
||||
extern t_stat pt_rd (int32 *data, int32 addr, int32 access);
|
||||
extern t_stat pt_wr (int32 data, int32 addr, int32 access);
|
||||
extern int32 pt_enb;
|
||||
extern t_stat lp20_rd (int32 *data, int32 addr, int32 access);
|
||||
extern t_stat lp20_wr (int32 data, int32 addr, int32 access);
|
||||
extern int32 lp20_inta (void);
|
||||
extern t_stat rp_rd (int32 *data, int32 addr, int32 access);
|
||||
extern t_stat rp_wr (int32 data, int32 addr, int32 access);
|
||||
extern int32 rp_inta (void);
|
||||
extern t_stat tu_rd (int32 *data, int32 addr, int32 access);
|
||||
extern t_stat tu_wr (int32 data, int32 addr, int32 access);
|
||||
extern int32 tu_inta (void);
|
||||
extern t_stat tcu_rd (int32 *data, int32 addr, int32 access);
|
||||
t_stat ubmap_rd (int32 *data, int32 addr, int32 access);
|
||||
t_stat ubmap_wr (int32 data, int32 addr, int32 access);
|
||||
t_stat ubs_rd (int32 *data, int32 addr, int32 access);
|
||||
t_stat ubs_wr (int32 data, int32 addr, int32 access);
|
||||
t_stat rd_zro (int32 *data, int32 addr, int32 access);
|
||||
t_stat wr_nop (int32 data, int32 addr, int32 access);
|
||||
t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat uba_reset (DEVICE *dptr);
|
||||
d10 ReadIO (a10 ea);
|
||||
void WriteIO (a10 ea, d10 val, int32 mode);
|
||||
|
||||
/* Unibus adapter data structures
|
||||
|
||||
uba_dev UBA device descriptor
|
||||
uba_unit UBA units
|
||||
uba_reg UBA register list
|
||||
*/
|
||||
|
||||
UNIT uba_unit[] = {
|
||||
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) } };
|
||||
|
||||
REG uba_reg[] = {
|
||||
{ ORDATA (INTREQ, int_req, 32), REG_RO },
|
||||
{ ORDATA (UB1CS, ubcs[0], 18) },
|
||||
{ ORDATA (UB3CS, ubcs[1], 18) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE uba_dev = {
|
||||
"UBA", uba_unit, uba_reg, NULL,
|
||||
UBANUM, 8, UMAP_ASIZE, 1, 8, 32,
|
||||
&uba_ex, &uba_dep, &uba_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* PDP-11 I/O structures */
|
||||
|
||||
struct iolink { /* I/O page linkage */
|
||||
int32 low; /* low I/O addr */
|
||||
int32 high; /* high I/O addr */
|
||||
int32 *enb; /* enable flag */
|
||||
t_stat (*read)(); /* read routine */
|
||||
t_stat (*write)(); }; /* write routine */
|
||||
|
||||
/* Table of I/O devices and corresponding read/write routines
|
||||
The expected Unibus adapter number is included as the high 2 bits */
|
||||
|
||||
struct iolink iotable[] = {
|
||||
{ IO_UBA1+IOBA_RP, IO_UBA1+IOBA_RP+IOLN_RP,
|
||||
NULL, &rp_rd, &rp_wr }, /* disk */
|
||||
{ IO_UBA3+IOBA_TU, IO_UBA3+IOBA_TU+IOLN_TU,
|
||||
NULL, &tu_rd, &tu_wr }, /* mag tape */
|
||||
{ IO_UBA3+IOBA_DZ, IO_UBA3+IOBA_DZ+IOLN_DZ,
|
||||
&dz_enb, &dz_rd, &dz_wr }, /* terminal mux */
|
||||
{ IO_UBA3+IOBA_LP20, IO_UBA3+IOBA_LP20+IOLN_LP20,
|
||||
NULL, &lp20_rd, &lp20_wr }, /* line printer */
|
||||
{ IO_UBA3+IOBA_PT, IO_UBA3+IOBA_PT+IOLN_PT,
|
||||
&pt_enb, &pt_rd, &pt_wr }, /* paper tape */
|
||||
{ IO_UBA1+IOBA_UBMAP, IO_UBA1+IOBA_UBMAP+IOLN_UBMAP,
|
||||
NULL, &ubmap_rd, &ubmap_wr }, /* Unibus 1 map */
|
||||
{ IO_UBA3+IOBA_UBMAP, IO_UBA3+IOBA_UBMAP+IOLN_UBMAP,
|
||||
NULL, &ubmap_rd, &ubmap_wr }, /* Unibus 3 map */
|
||||
{ IO_UBA1+IOBA_UBCS, IO_UBA1+IOBA_UBCS+IOLN_UBCS,
|
||||
NULL, &ubs_rd, &ubs_wr }, /* Unibus 1 c/s */
|
||||
{ IO_UBA3+IOBA_UBCS, IO_UBA3+IOBA_UBCS+IOLN_UBCS,
|
||||
NULL, &ubs_rd, &ubs_wr }, /* Unibus 3 c/s */
|
||||
{ IO_UBA1+IOBA_UBMNT, IO_UBA1+IOBA_UBMNT+IOLN_UBMNT,
|
||||
NULL, &rd_zro, &wr_nop }, /* Unibus 1 maint */
|
||||
{ IO_UBA3+IOBA_UBMNT, IO_UBA3+IOBA_UBMNT+IOLN_UBMNT,
|
||||
NULL, &rd_zro, &wr_nop }, /* Unibus 3 maint */
|
||||
{ IO_UBA3+IOBA_TCU, IO_UBA3+IOBA_TCU+IOLN_TCU,
|
||||
NULL, &tcu_rd, &wr_nop }, /* TCU150 */
|
||||
{ 00100000, 00100000, NULL, &rd_zro, &wr_nop }, /* Mem sys stat */
|
||||
{ 0, 0, 0, NULL, NULL } };
|
||||
|
||||
/* Interrupt request to interrupt action map */
|
||||
|
||||
int32 (*int_ack[32])() = { /* int ack routines */
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, &rp_inta, &tu_inta,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, &lp20_inta, NULL, NULL, NULL, NULL, NULL };
|
||||
|
||||
/* Interrupt request to vector map */
|
||||
|
||||
int32 int_vec[32] = { /* int req to vector */
|
||||
0, 0, 0, 0, 0, 0, VEC_RP, VEC_TU,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
VEC_DZRX, VEC_DZTX, 0, 0, 0, 0, 0, 0,
|
||||
VEC_PTR, VEC_PTP, VEC_LP20, 0, 0, 0, 0, 0 };
|
||||
|
||||
/* IO 710 (DEC) TIOE - test I/O word, skip if zero
|
||||
(ITS) IORDI - read word from Unibus 3
|
||||
returns TRUE if skip, FALSE otherwise
|
||||
*/
|
||||
|
||||
t_bool io710 (int32 ac, a10 ea)
|
||||
{
|
||||
d10 val;
|
||||
|
||||
if (ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
|
||||
else { /* TIOE */
|
||||
val = ReadIO (ea); /* read word */
|
||||
if ((AC(ac) & val) == 0) return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* IO 711 (DEC) TION - test I/O word, skip if non-zero
|
||||
(ITS) IORDQ - read word from Unibus 1
|
||||
returns TRUE if skip, FALSE otherwise
|
||||
*/
|
||||
|
||||
t_bool io711 (int32 ac, a10 ea)
|
||||
{
|
||||
d10 val;
|
||||
|
||||
if (ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
|
||||
else { /* TION */
|
||||
val = ReadIO (ea); /* read word */
|
||||
if ((AC(ac) & val) != 0) return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* IO 712 (DEC) RDIO - read I/O word, addr in ea
|
||||
(ITS) IORD - read I/O word, addr in M[ea]
|
||||
*/
|
||||
|
||||
d10 io712 (a10 ea)
|
||||
{
|
||||
return ReadIO (ea); /* RDIO, IORD */
|
||||
}
|
||||
|
||||
/* IO 713 (DEC) WRIO - write I/O word, addr in ea
|
||||
(ITS) IOWR - write I/O word, addr in M[ea]
|
||||
*/
|
||||
|
||||
void io713 (d10 val, a10 ea)
|
||||
{
|
||||
WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */
|
||||
return;
|
||||
}
|
||||
|
||||
/* IO 714 (DEC) BSIO - set bit in I/O address
|
||||
(ITS) IOWRI - write word to Unibus 3
|
||||
*/
|
||||
|
||||
void io714 (d10 val, a10 ea)
|
||||
{
|
||||
d10 temp;
|
||||
|
||||
val = val & 0177777;
|
||||
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
|
||||
else {
|
||||
temp = ReadIO (ea); /* BSIO */
|
||||
temp = temp | val;
|
||||
WriteIO (ea, temp, WRITE); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* IO 715 (DEC) BCIO - clear bit in I/O address
|
||||
(ITS) IOWRQ - write word to Unibus 1
|
||||
*/
|
||||
|
||||
void io715 (d10 val, a10 ea)
|
||||
{
|
||||
d10 temp;
|
||||
|
||||
val = val & 0177777;
|
||||
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
|
||||
else {
|
||||
temp = ReadIO (ea); /* BCIO */
|
||||
temp = temp & ~val;
|
||||
WriteIO (ea, temp, WRITE); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* IO 720 (DEC) TIOEB - test I/O byte, skip if zero
|
||||
(ITS) IORDBI - read byte from Unibus 3
|
||||
returns TRUE if skip, FALSE otherwise
|
||||
*/
|
||||
|
||||
t_bool io720 (int32 ac, a10 ea)
|
||||
{
|
||||
d10 val;
|
||||
|
||||
if (ITS) { /* IORDBI */
|
||||
val = ReadIO (IO_UBA3 | eaRB);
|
||||
AC(ac) = GETBYTE (ea, val); }
|
||||
else { /* TIOEB */
|
||||
val = ReadIO (eaRB);
|
||||
val = GETBYTE (ea, val);
|
||||
if ((AC(ac) & val) == 0) return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* IO 721 (DEC) TIONB - test I/O word, skip if non-zero
|
||||
(ITS) IORDBQ - read word from Unibus 1
|
||||
returns TRUE if skip, FALSE otherwise
|
||||
*/
|
||||
|
||||
t_bool io721 (int32 ac, a10 ea)
|
||||
{
|
||||
d10 val;
|
||||
|
||||
if (ITS) { /* IORDBQ */
|
||||
val = ReadIO (IO_UBA1 | eaRB);
|
||||
AC(ac) = GETBYTE (ea, val); }
|
||||
else { /* TIONB */
|
||||
val = ReadIO (eaRB);
|
||||
val = GETBYTE (ea, val);
|
||||
if ((AC(ac) & val) != 0) return TRUE; }
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* IO 722 (DEC) RDIOB - read I/O byte, addr in ea
|
||||
(ITS) IORDB - read I/O byte, addr in M[ea]
|
||||
*/
|
||||
|
||||
d10 io722 (a10 ea)
|
||||
{
|
||||
d10 val;
|
||||
|
||||
val = ReadIO (eaRB); /* RDIOB, IORDB */
|
||||
return GETBYTE (ea, val);
|
||||
}
|
||||
|
||||
/* IO 723 (DEC) WRIOB - write I/O byte, addr in ea
|
||||
(ITS) IOWRB - write I/O byte, addr in M[ea]
|
||||
*/
|
||||
|
||||
void io723 (d10 val, a10 ea)
|
||||
{
|
||||
WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */
|
||||
return;
|
||||
}
|
||||
|
||||
/* IO 724 (DEC) BSIOB - set bit in I/O byte address
|
||||
(ITS) IOWRBI - write byte to Unibus 3
|
||||
*/
|
||||
|
||||
void io724 (d10 val, a10 ea)
|
||||
{
|
||||
d10 temp;
|
||||
|
||||
val = val & 0377;
|
||||
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
|
||||
else {
|
||||
temp = ReadIO (eaRB); /* BSIOB */
|
||||
temp = GETBYTE (ea, temp);
|
||||
temp = temp | val;
|
||||
WriteIO (ea, temp, WRITEB); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* IO 725 (DEC) BCIOB - clear bit in I/O byte address
|
||||
(ITS) IOWRBQ - write byte to Unibus 1
|
||||
*/
|
||||
|
||||
void io725 (d10 val, a10 ea)
|
||||
{
|
||||
d10 temp;
|
||||
|
||||
val = val & 0377;
|
||||
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
|
||||
else {
|
||||
temp = ReadIO (eaRB); /* BCIOB */
|
||||
temp = GETBYTE (ea, temp);
|
||||
temp = temp & ~val;
|
||||
WriteIO (ea, temp, WRITEB); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read and write I/O devices.
|
||||
These routines are the linkage between the 64b world of the main
|
||||
simulator and the 32b world of the device simulators.
|
||||
*/
|
||||
|
||||
d10 ReadIO (a10 ea)
|
||||
{
|
||||
int32 n, pa, val;
|
||||
struct iolink *p;
|
||||
|
||||
pa = (int32) ea; /* cvt addr to 32b */
|
||||
for (p = &iotable[0]; p -> low != 0; p++ ) {
|
||||
if ((pa >= p -> low) && (pa < p -> high) &&
|
||||
((p -> enb == NULL) || *p -> enb)) {
|
||||
p -> read (&val, pa, READ);
|
||||
pi_eval ();
|
||||
return ((d10) val); } }
|
||||
UBNXM_FAIL (pa, READ);
|
||||
}
|
||||
|
||||
void WriteIO (a10 ea, d10 val, int32 mode)
|
||||
{
|
||||
int32 n, pa;
|
||||
struct iolink *p;
|
||||
|
||||
pa = (int32) ea; /* cvt addr to 32b */
|
||||
for (p = &iotable[0]; p -> low != 0; p++ ) {
|
||||
if ((pa >= p -> low) && (pa < p -> high) &&
|
||||
((p -> enb == NULL) || *p -> enb)) {
|
||||
p -> write ((int32) val, pa, mode);
|
||||
pi_eval ();
|
||||
return; } }
|
||||
UBNXM_FAIL (pa, mode);
|
||||
}
|
||||
|
||||
/* Evaluate Unibus priority interrupts */
|
||||
|
||||
int32 pi_ub_eval ()
|
||||
{
|
||||
int32 i, lvl;
|
||||
|
||||
for (i = lvl = 0; i < UBANUM; i++) {
|
||||
if (int_req & ubabr76[i])
|
||||
lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
|
||||
if (int_req & ubabr54[i])
|
||||
lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])]; }
|
||||
return lvl;
|
||||
}
|
||||
|
||||
/* Return Unibus device vector
|
||||
|
||||
Takes as input the request level calculated by pi_eval
|
||||
If there is an interrupting Unibus device at that level, return its vector,
|
||||
otherwise, returns 0
|
||||
*/
|
||||
|
||||
int32 pi_ub_vec (int32 rlvl, int32 *uba)
|
||||
{
|
||||
int32 i, masked_irq;
|
||||
|
||||
for (i = masked_irq = 0; i < UBANUM; i++) {
|
||||
if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */
|
||||
(masked_irq = int_req & ubabr76[i])) break;
|
||||
if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */
|
||||
(masked_irq = int_req & ubabr54[i])) break; }
|
||||
*uba = (i << 1) + 1; /* store uba # */
|
||||
for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */
|
||||
if ((masked_irq >> i) & 1) {
|
||||
int_req = int_req & ~(1u << i); /* clear req */
|
||||
if (int_ack[i]) return int_ack[i]();
|
||||
return int_vec[i]; } } /* return vector */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unibus adapter map routines */
|
||||
|
||||
t_stat ubmap_rd (int32 *val, int32 pa, int32 mode)
|
||||
{
|
||||
int32 n = iocmap[GET_IOUBA (pa)];
|
||||
|
||||
if (n < 0) ABORT (STOP_ILLIOC);
|
||||
*val = ubmap[n][pa & UMAP_AMASK];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ubmap_wr (int32 val, int32 pa, int32 mode)
|
||||
{
|
||||
int32 n = iocmap[GET_IOUBA (pa)];
|
||||
|
||||
if (n < 0) ABORT (STOP_ILLIOC);
|
||||
ubmap[n][pa & UMAP_AMASK] = UMAP_POSFL (val) | UMAP_POSPN (val);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Unibus adapter control/status routines */
|
||||
|
||||
t_stat ubs_rd (int32 *val, int32 pa, int32 mode)
|
||||
{
|
||||
int32 n = iocmap[GET_IOUBA (pa)];
|
||||
|
||||
if (n < 0) ABORT (STOP_ILLIOC);
|
||||
if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
|
||||
if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
|
||||
*val = ubcs[n] = ubcs[n] & ~UBCS_RDZ;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ubs_wr (int32 val, int32 pa, int32 mode)
|
||||
{
|
||||
int32 n = iocmap[GET_IOUBA (pa)];
|
||||
|
||||
if (n < 0) ABORT (STOP_ILLIOC);
|
||||
if (val & UBCS_INI) {
|
||||
reset_all (5); /* start after UBA */
|
||||
ubcs[n] = val & UBCS_DXF; }
|
||||
else ubcs[n] = val & UBCS_RDW;
|
||||
if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
|
||||
if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Unibus adapter read zero/write ignore routines */
|
||||
|
||||
t_stat rd_zro (int32 *val, int32 pa, int32 mode)
|
||||
{
|
||||
*val = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat wr_nop (int32 val, int32 pa, int32 mode)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 uba = uptr - uba_unit;
|
||||
|
||||
if (addr >= UMAP_MEMSIZE) return SCPE_NXM;
|
||||
*vptr = ubmap[uba][addr];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 uba = uptr - uba_unit;
|
||||
|
||||
if (addr >= UMAP_MEMSIZE) return SCPE_NXM;
|
||||
ubmap[uba][addr] = (int32) val & UMAP_MASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat uba_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i, uba;
|
||||
|
||||
int_req = 0;
|
||||
for (uba = 0; uba < UBANUM; uba++) {
|
||||
ubcs[uba] = 0;
|
||||
for (i = 0; i < UMAP_MEMSIZE; i++) ubmap[uba][i] = 0; }
|
||||
pi_eval ();
|
||||
return SCPE_OK;
|
||||
}
|
||||
584
PDP10/pdp10_lp20.c
Normal file
584
PDP10/pdp10_lp20.c
Normal file
@@ -0,0 +1,584 @@
|
||||
/* pdp10_lp20.c: PDP-10 LP20 line printer simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
lp20 line printer
|
||||
|
||||
30-Nov-01 RMS Added extended SET/SHOW support
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
|
||||
#define UNIT_DUMMY (1 << UNIT_V_UF)
|
||||
#define LP_WIDTH 132 /* printer width */
|
||||
|
||||
/* DAVFU RAM */
|
||||
|
||||
#define DV_SIZE 143 /* DAVFU size */
|
||||
#define DV_DMASK 077 /* data mask per byte */
|
||||
#define DV_TOF 0 /* top of form channel */
|
||||
#define DV_MAX 11 /* max channel number */
|
||||
|
||||
/* Translation RAM */
|
||||
|
||||
#define TX_SIZE 256 /* translation RAM */
|
||||
#define TX_AMASK (TX_SIZE - 1)
|
||||
#define TX_DMASK 07777
|
||||
#define TX_V_FL 8 /* flags */
|
||||
#define TX_M_FL 017
|
||||
/* define TX_INTR 04000 /* interrupt */
|
||||
#define TX_DELH 02000 /* delimiter */
|
||||
/* define TX_XLAT 01000 /* translate */
|
||||
/* define TX_DVFU 00400 /* DAVFU */
|
||||
#define TX_SLEW 00020 /* chan vs slew */
|
||||
#define TX_VMASK 00017 /* spacing mask */
|
||||
#define TX_CHR 0 /* states: pr char */
|
||||
#define TX_RAM 1 /* pr translation */
|
||||
#define TX_DVU 2 /* DAVFU action */
|
||||
#define TX_INT 3 /* interrupt */
|
||||
#define TX_GETFL(x) (((x) >> TX_V_FL) & TX_M_FL)
|
||||
|
||||
/* LPCSRA (765400) */
|
||||
|
||||
#define CSA_GO 0000001 /* go */
|
||||
#define CSA_PAR 0000002 /* parity enable NI */
|
||||
#define CSA_V_FNC 2 /* function */
|
||||
#define CSA_M_FNC 03
|
||||
#define FNC_PR 0 /* print */
|
||||
#define FNC_TST 1 /* test */
|
||||
#define FNC_DVU 2 /* load DAVFU */
|
||||
#define FNC_RAM 3 /* load translation RAM */
|
||||
#define FNC_INTERNAL 1 /* internal function */
|
||||
#define CSA_FNC (CSA_M_FNC << CSA_V_FNC)
|
||||
#define CSA_V_UAE 4 /* Unibus addr extension */
|
||||
#define CSA_UAE (03 << CSA_V_UAE)
|
||||
#define CSA_IE 0000100 /* interrupt enable */
|
||||
#define CSA_DONE 0000200 /* done */
|
||||
#define CSA_INIT 0000400 /* init */
|
||||
#define CSA_ECLR 0001000 /* clear errors */
|
||||
#define CSA_DELH 0002000 /* delimiter hold */
|
||||
#define CSA_ONL 0004000 /* online */
|
||||
#define CSA_DVON 0010000 /* DAVFU online */
|
||||
#define CSA_UNDF 0020000 /* undefined char */
|
||||
#define CSA_PZRO 0040000 /* page counter zero */
|
||||
#define CSA_ERR 0100000 /* error */
|
||||
#define CSA_RW (CSA_DELH | CSA_IE | CSA_UAE | CSA_FNC | CSA_PAR | CSA_GO)
|
||||
#define CSA_MBZ (CSA_ECLR | CSA_INIT)
|
||||
#define CSA_GETUAE(x) (((x) & CSA_UAE) << (16 - CSA_V_UAE))
|
||||
#define CSA_GETFNC(x) (((x) >> CSA_V_FNC) & CSA_M_FNC)
|
||||
|
||||
/* LPCSRB (765402) */
|
||||
|
||||
#define CSB_GOE 0000001 /* go error */
|
||||
#define CSB_DTE 0000002 /* DEM timing error NI */
|
||||
#define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */
|
||||
#define CSB_RPE 0000010 /* RAM parity error NI */
|
||||
#define CSB_MPE 0000020 /* MEM parity error NI */
|
||||
#define CSB_LPE 0000040 /* LPT parity error NI */
|
||||
#define CSB_DVOF 0000100 /* DAVFU not ready */
|
||||
#define CSB_OFFL 0000200 /* offline */
|
||||
#define CSB_TEST 0003400 /* test mode */
|
||||
#define CSB_OVFU 0004000 /* optical VFU NI */
|
||||
#define CSB_PBIT 0010000 /* data parity bit NI */
|
||||
#define CSB_NRDY 0020000 /* printer error NI */
|
||||
#define CSB_LA180 0040000 /* LA180 printer NI */
|
||||
#define CSB_VLD 0100000 /* valid data NI */
|
||||
#define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE)
|
||||
#define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL)
|
||||
#define CSB_RW CSB_TEST
|
||||
#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\
|
||||
CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD)
|
||||
|
||||
/* LPBA (765404) */
|
||||
|
||||
#define XBA_MBZ 0400000 /* addr<17> must be 0 */
|
||||
|
||||
/* LPBC (765506) */
|
||||
|
||||
#define BC_MASK 0007777 /* <15:12> MBZ */
|
||||
|
||||
/* LPPAGC (765510) */
|
||||
|
||||
#define PAGC_MASK 0007777 /* <15:12> MBZ */
|
||||
|
||||
/* LPRDAT (765512) */
|
||||
|
||||
#define RDAT_MASK 0007777 /* <15:12> MBZ */
|
||||
|
||||
/* LPCOLC/LPCBUF (765514) */
|
||||
|
||||
/* LPCSUM/LPPDAT (765516) */
|
||||
|
||||
extern d10 *M; /* main memory */
|
||||
extern int32 int_req;
|
||||
extern int32 ubcs[UBANUM]; /* UBA csr */
|
||||
extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* UBA map */
|
||||
int32 lpcsa = 0; /* control/status A */
|
||||
int32 lpcsb = 0; /* control/status B */
|
||||
int32 lpba = 0; /* bus address */
|
||||
int32 lpbc = 0; /* byte count */
|
||||
int32 lppagc = 0; /* page count */
|
||||
int32 lprdat = 0; /* RAM data */
|
||||
int32 lpcbuf = 0; /* character buffer */
|
||||
int32 lpcolc = 0; /* column count */
|
||||
int32 lppdat = 0; /* printer data */
|
||||
int32 lpcsum = 0; /* checksum */
|
||||
int32 dvptr = 0; /* davfu pointer */
|
||||
int32 dvlnt = 0; /* davfu length */
|
||||
int32 lp20_irq = 0; /* int request */
|
||||
int32 lp20_stopioe = 0; /* stop on error */
|
||||
int16 txram[TX_SIZE] = { 0 }; /* translation RAM */
|
||||
int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */
|
||||
t_stat lp20_svc (UNIT *uptr);
|
||||
t_stat lp20_reset (DEVICE *dptr);
|
||||
t_stat lp20_attach (UNIT *uptr, char *ptr);
|
||||
t_stat lp20_detach (UNIT *uptr);
|
||||
t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_bool lp20_print (int32 c);
|
||||
t_bool lp20_adv (int32 c, t_bool advdvu);
|
||||
t_bool lp20_davfu (int32 c);
|
||||
void update_lpcs (int32 flg);
|
||||
|
||||
/* LP data structures
|
||||
|
||||
lp20_dev LPT device descriptor
|
||||
lp20_unit LPT unit descriptor
|
||||
lp20_reg LPT register list
|
||||
*/
|
||||
|
||||
UNIT lp20_unit = {
|
||||
UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG lp20_reg[] = {
|
||||
{ ORDATA (LPCSA, lpcsa, 16) },
|
||||
{ ORDATA (LPCSB, lpcsb, 16) },
|
||||
{ ORDATA (LPBA, lpba, 16) },
|
||||
{ ORDATA (LPBC, lpbc, 12) },
|
||||
{ ORDATA (LPPAGC, lppagc, 12) },
|
||||
{ ORDATA (LPRDAT, lprdat, 12) },
|
||||
{ ORDATA (LPCBUF, lpcbuf, 8) },
|
||||
{ ORDATA (LPCOLC, lpcolc, 8) },
|
||||
{ ORDATA (LPPDAT, lppdat, 8) },
|
||||
{ ORDATA (LPCSUM, lpcsum, 8) },
|
||||
{ ORDATA (DVPTR, dvptr, 7) },
|
||||
{ ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ },
|
||||
{ FLDATA (INT, int_req, INT_V_LP20) },
|
||||
{ FLDATA (IRQ, lp20_irq, 0) },
|
||||
{ FLDATA (ERR, lpcsa, CSR_V_ERR) },
|
||||
{ FLDATA (DONE, lpcsa, CSR_V_DONE) },
|
||||
{ FLDATA (IE, lpcsa, CSR_V_IE) },
|
||||
{ DRDATA (POS, lp20_unit.pos, 31), PV_LEFT },
|
||||
{ DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, lp20_stopioe, 0) },
|
||||
{ BRDATA (TXRAM, txram, 8, 12, TX_SIZE) },
|
||||
{ BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB lp20_mod[] = {
|
||||
{ UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE lp20_dev = {
|
||||
"LP20", &lp20_unit, lp20_reg, lp20_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &lp20_reset,
|
||||
NULL, &lp20_attach, &lp20_detach };
|
||||
|
||||
/* Line printer routines
|
||||
|
||||
lp20_rd I/O page read
|
||||
lp20_wr I/O page write
|
||||
lp20_svc process event (printer ready)
|
||||
lp20_reset process reset
|
||||
lp20_attach process attach
|
||||
lp20_detach process detach
|
||||
*/
|
||||
|
||||
t_stat lp20_rd (int32 *data, int32 pa, int32 access)
|
||||
{
|
||||
update_lpcs (0); /* update csr's */
|
||||
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
|
||||
case 00: /* LPCSA */
|
||||
*data = lpcsa = lpcsa & ~CSA_MBZ;
|
||||
break;
|
||||
case 01: /* LPCSB */
|
||||
*data = lpcsb = lpcsb & ~CSB_MBZ;
|
||||
break;
|
||||
case 02: /* LPBA */
|
||||
*data = lpba;
|
||||
break;
|
||||
case 03: /* LPBC */
|
||||
*data = lpbc = lpbc & BC_MASK;
|
||||
break;
|
||||
case 04: /* LPPAGC */
|
||||
*data = lppagc = lppagc & PAGC_MASK;
|
||||
break;
|
||||
case 05: /* LPRDAT */
|
||||
*data = lprdat = lprdat & RDAT_MASK;
|
||||
break;
|
||||
case 06: /* LPCOLC/LPCBUF */
|
||||
*data = (lpcolc << 8) | lpcbuf;
|
||||
break;
|
||||
case 07: /* LPCSUM/LPPDAT */
|
||||
*data = (lpcsum << 8) | lppdat;
|
||||
break; } /* end case PA */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat lp20_wr (int32 data, int32 pa, int32 access)
|
||||
{
|
||||
update_lpcs (0); /* update csr's */
|
||||
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
|
||||
case 00: /* LPCSA */
|
||||
if (access == WRITEB) data = (pa & 1)?
|
||||
(lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;
|
||||
if (data & CSA_ECLR) { /* error clear? */
|
||||
lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */
|
||||
lpcsb = lpcsb & ~CSB_ECLR; /* clear err */
|
||||
sim_cancel (&lp20_unit); } /* cancel I/O */
|
||||
if (data & CSA_INIT) lp20_reset (&lp20_dev); /* init? */
|
||||
if (data & CSA_GO) { /* go set? */
|
||||
if ((lpcsa & CSA_GO) == 0) { /* not set before? */
|
||||
if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;
|
||||
lpcsum = 0; /* clear checksum */
|
||||
sim_activate (&lp20_unit, lp20_unit.time); } }
|
||||
else sim_cancel (&lp20_unit); /* go clr, stop DMA */
|
||||
lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);
|
||||
break;
|
||||
case 01: /* LPCSB */
|
||||
break; /* ignore writes to TEST */
|
||||
case 02: /* LPBA */
|
||||
if (access == WRITEB) data = (pa & 1)?
|
||||
(lpba & 0377) | (data << 8): (lpba & ~0377) | data;
|
||||
lpba = data;
|
||||
break;
|
||||
case 03: /* LPBC */
|
||||
if (access == WRITEB) data = (pa & 1)?
|
||||
(lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;
|
||||
lpbc = data & BC_MASK;
|
||||
lpcsa = lpcsa & ~CSA_DONE;
|
||||
break;
|
||||
case 04: /* LPPAGC */
|
||||
if (access == WRITEB) data = (pa & 1)?
|
||||
(lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;
|
||||
lppagc = data & PAGC_MASK;
|
||||
break;
|
||||
case 05: /* LPRDAT */
|
||||
if (access == WRITEB) data = (pa & 1)?
|
||||
(lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;
|
||||
lprdat = data & RDAT_MASK;
|
||||
txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */
|
||||
break;
|
||||
case 06: /* LPCOLC/LPCBUF */
|
||||
if ((access == WRITEB) && (pa & 1)) /* odd byte */
|
||||
lpcolc = data & 0377;
|
||||
else { lpcbuf = data & 0377; /* even byte, word */
|
||||
if (access == WRITE) lpcolc = (data >> 8) & 0377; }
|
||||
break;
|
||||
case 07: /* LPCSUM/LPPDAT */
|
||||
break; } /* read only */
|
||||
update_lpcs (0);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Line printer service
|
||||
|
||||
The translation RAM case table is derived from the LP20 spec and
|
||||
verified against the LP20 RAM simulator in TOPS10 7.04 LPTSPL.
|
||||
The equations are:
|
||||
|
||||
flags := inter, delim, xlate, paper, delim_hold (from CSRA)
|
||||
actions : = print_input, print_xlate, davfu_action, interrupt
|
||||
|
||||
if (inter) {
|
||||
if (!xlate || delim || delim_hold) interrupt;
|
||||
else if (paper) davfu_action;
|
||||
else print_xlate; }
|
||||
else if (paper) {
|
||||
if (xlate || delim || delim_hold) davfu_action;
|
||||
else print_input; }
|
||||
else {
|
||||
if (xlate || delim || delim_hold) print_xlate;
|
||||
else print_input; }
|
||||
*/
|
||||
|
||||
t_stat lp20_svc (UNIT *uptr)
|
||||
{
|
||||
int32 fnc, i, tbc, vpn, temp, txst, wd10;
|
||||
int32 dvld = -2; /* must be even */
|
||||
int32 err = 0;
|
||||
t_bool cont;
|
||||
a10 ba, pa10;
|
||||
|
||||
static const uint32 txcase[32] = {
|
||||
TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
|
||||
TX_RAM, TX_RAM, TX_DVU, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
|
||||
TX_INT, TX_INT, TX_INT, TX_INT, TX_RAM, TX_INT, TX_DVU, TX_INT,
|
||||
TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT };
|
||||
|
||||
lpcsa = lpcsa & ~CSA_GO;
|
||||
ba = CSA_GETUAE (lpcsa) | lpba;
|
||||
fnc = CSA_GETFNC (lpcsa);
|
||||
tbc = 010000 - lpbc;
|
||||
if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) {
|
||||
update_lpcs (CSA_ERR);
|
||||
IORETURN (lp20_stopioe, SCPE_UNATT); }
|
||||
if ((fnc == FNC_PR) && (dvlnt == 0)) {
|
||||
update_lpcs (CSA_ERR);
|
||||
return SCPE_OK; }
|
||||
|
||||
for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
|
||||
vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */
|
||||
if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) ||
|
||||
((ubmap[1][vpn] & UMAP_VLD) == 0)) { /* invalid map? */
|
||||
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
|
||||
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
|
||||
update_lpcs (CSA_ERR); /* set done */
|
||||
break; }
|
||||
pa10 = (ubmap[1][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;
|
||||
if (MEM_ADDR_NXM (pa10)) { /* nxm? */
|
||||
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
|
||||
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
|
||||
update_lpcs (CSA_ERR); /* set done */
|
||||
break; }
|
||||
wd10 = (int32) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
|
||||
lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */
|
||||
lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */
|
||||
switch (fnc) { /* switch on function */
|
||||
|
||||
/* Translation RAM load */
|
||||
|
||||
case FNC_RAM: /* RAM load */
|
||||
txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;
|
||||
break;
|
||||
|
||||
/* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by
|
||||
a start (354 to 356) and stop (357) byte pair. If the number of bytes
|
||||
loaded is odd, or no bytes are loaded, the DAVFU is invalid.
|
||||
*/
|
||||
|
||||
case FNC_DVU: /* DVU load */
|
||||
if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */
|
||||
dvld = dvlnt = 0; /* reset lnt */
|
||||
else if (lpcbuf == 0357) { /* stop DVU load? */
|
||||
dvptr = 0; /* reset ptr */
|
||||
if (dvld & 1) dvlnt = 0; } /* if odd, invalid */
|
||||
else if (dvld == 0) { /* even state? */
|
||||
temp = lpcbuf & DV_DMASK;
|
||||
dvld = 1; }
|
||||
else if (dvld == 1) { /* odd state? */
|
||||
if (dvlnt < DV_SIZE) davfu[dvlnt++] =
|
||||
temp | ((lpcbuf & DV_DMASK) << 6);
|
||||
dvld = 0; }
|
||||
break;
|
||||
|
||||
/* Print characters */
|
||||
|
||||
case FNC_PR: /* print */
|
||||
lprdat = txram[lpcbuf]; /* get RAM char */
|
||||
txst = (TX_GETFL (lprdat) << 1) | /* get state */
|
||||
((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */
|
||||
if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;
|
||||
else lpcsa = lpcsa & ~CSA_DELH;
|
||||
lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */
|
||||
switch (txcase[txst]) { /* case on state */
|
||||
case TX_CHR: /* take char */
|
||||
cont = lp20_print (lpcbuf);
|
||||
break;
|
||||
case TX_RAM: /* take translation */
|
||||
cont = lp20_print (lprdat);
|
||||
break;
|
||||
case TX_DVU: /* DAVFU action */
|
||||
if (lprdat & TX_SLEW)
|
||||
cont = lp20_adv (lprdat & TX_VMASK, TRUE);
|
||||
else cont = lp20_davfu (lprdat & TX_VMASK);
|
||||
break;
|
||||
case TX_INT: /* interrupt */
|
||||
lpcsa = lpcsa | CSA_UNDF; /* set flag */
|
||||
cont = FALSE; /* force stop */
|
||||
break; } /* end case char state */
|
||||
break;
|
||||
case FNC_TST: /* test */
|
||||
break; } /* end case function */
|
||||
} /* end for */
|
||||
lpba = ba & 0177777;
|
||||
lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE);
|
||||
lpbc = (lpbc + i) & BC_MASK;
|
||||
if (lpbc) update_lpcs (CSA_MBZ); /* intr, but not done */
|
||||
else update_lpcs (CSA_DONE); /* intr and done */
|
||||
if ((fnc == FNC_PR) && ferror (lp20_unit.fileref)) {
|
||||
perror ("LP I/O error");
|
||||
clearerr (uptr -> fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Print routines
|
||||
|
||||
lp20_print print a character
|
||||
lp20_adv advance n lines
|
||||
lp20_davfu advance to channel on VFU
|
||||
|
||||
Return TRUE to continue printing, FALSE to stop
|
||||
*/
|
||||
|
||||
t_bool lp20_print (int32 c)
|
||||
{
|
||||
t_bool r = TRUE;
|
||||
int32 i, rpt = 1;
|
||||
|
||||
lppdat = c & 0177; /* mask char to 7b */
|
||||
if (lppdat == 000) return TRUE; /* NUL? no op */
|
||||
if (lppdat == 012) return lp20_adv (1, TRUE); /* LF? adv carriage */
|
||||
if (lppdat == 014) return lp20_davfu (DV_TOF); /* FF? top of form */
|
||||
if (lppdat == 015) lpcolc = 0; /* CR? reset col cntr */
|
||||
else if (lppdat == 011) { /* TAB? simulate */
|
||||
lppdat = ' '; /* with spaces */
|
||||
if (lpcolc >= 128) {
|
||||
r = lp20_adv (1, TRUE); /* eol? adv carriage */
|
||||
rpt = 8; } /* adv to col 9 */
|
||||
else rpt = 8 - (lpcolc & 07); } /* else adv 1 to 8 */
|
||||
else { if (lppdat < 040) lppdat = ' '; /* cvt non-prnt to spc */
|
||||
if (lpcolc >= LP_WIDTH) /* line full? */
|
||||
r = lp20_adv (1, TRUE); } /* adv carriage */
|
||||
for (i = 0; i < rpt; i++) putc (lppdat, lp20_unit.fileref);
|
||||
lp20_unit.pos = lp20_unit.pos + rpt;
|
||||
lpcolc = lpcolc + rpt;
|
||||
return r;
|
||||
}
|
||||
|
||||
t_bool lp20_adv (int32 cnt, t_bool dvuadv)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (cnt == 0) return TRUE;
|
||||
lpcolc = 0; /* reset col cntr */
|
||||
for (i = 0; i < cnt; i++) putc ('\n', lp20_unit.fileref);
|
||||
lp20_unit.pos = lp20_unit.pos + cnt; /* print 'n' newlines */
|
||||
if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */
|
||||
if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */
|
||||
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
|
||||
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
|
||||
return TRUE; }
|
||||
else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
|
||||
return FALSE; } }
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
t_bool lp20_davfu (int32 cnt)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cnt > DV_MAX) cnt = 7; /* inval chan? */
|
||||
for (i = 0; i < dvlnt; i++) { /* search DAVFU */
|
||||
dvptr = dvptr + 1; /* adv DAVFU ptr */
|
||||
if (dvptr >= dvlnt) dvptr = 0; /* wrap at end */
|
||||
if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */
|
||||
if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */
|
||||
if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */
|
||||
putc ('\f', lp20_unit.fileref); /* print form feed */
|
||||
lp20_unit.pos = lp20_unit.pos + 1;
|
||||
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
|
||||
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
|
||||
return TRUE; }
|
||||
else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
|
||||
return FALSE; } }
|
||||
} /* end for */
|
||||
dvlnt = 0; /* DAVFU error */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Update LPCSA, optionally request interrupt */
|
||||
|
||||
void update_lpcs (int32 flg)
|
||||
{
|
||||
if (flg) lp20_irq = 1; /* set int req */
|
||||
lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL | CSA_DVON);
|
||||
lpcsb = (lpcsb | CSB_OFFL | CSB_DVOF) & ~CSB_MBZ;
|
||||
if (lp20_unit.flags & UNIT_ATT) {
|
||||
lpcsa = lpcsa | CSA_ONL;
|
||||
lpcsb = lpcsb & ~CSB_OFFL; }
|
||||
else lpcsa = lpcsa & ~CSA_DONE;
|
||||
if (dvlnt) {
|
||||
lpcsa = lpcsa | CSA_DVON;
|
||||
lpcsb = lpcsb & ~CSB_DVOF; }
|
||||
if (lpcsb & CSB_ERR) lpcsa = lpcsa | CSA_ERR;
|
||||
if ((lpcsa & CSA_IE) && lp20_irq) int_req = int_req | INT_LP20;
|
||||
else int_req = int_req & ~INT_LP20;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Acknowledge interrupt (clear internal request) */
|
||||
|
||||
int32 lp20_inta (void)
|
||||
{
|
||||
lp20_irq = 0; /* clear int req */
|
||||
return VEC_LP20;
|
||||
}
|
||||
|
||||
t_stat lp20_reset (DEVICE *dptr)
|
||||
{
|
||||
lpcsa = CSA_DONE;
|
||||
lpcsb = 0;
|
||||
lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */
|
||||
lprdat = lppdat = lpcbuf = lpcsum = 0;
|
||||
lp20_irq = 0; /* clear int req */
|
||||
dvptr = 0; /* reset davfu ptr */
|
||||
sim_cancel (&lp20_unit); /* deactivate unit */
|
||||
update_lpcs (0); /* update status */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat lp20_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat reason;
|
||||
|
||||
reason = attach_unit (uptr, cptr); /* attach file */
|
||||
if (lpcsa & CSA_ONL) return reason; /* just file chg? */
|
||||
if (sim_is_active (&lp20_unit)) update_lpcs (0); /* busy? no int */
|
||||
else update_lpcs (CSA_MBZ); /* interrupt */
|
||||
return reason;
|
||||
}
|
||||
|
||||
t_stat lp20_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat reason;
|
||||
|
||||
reason = detach_unit (uptr);
|
||||
sim_cancel (&lp20_unit);
|
||||
lpcsa = lpcsa & ~CSA_GO;
|
||||
update_lpcs (CSA_MBZ);
|
||||
return reason;
|
||||
}
|
||||
|
||||
t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!get_yn ("Clear DAVFU? [N]", FALSE)) return SCPE_OK;
|
||||
for (i = 0; i < DV_SIZE; i++) davfu[i] = 0;
|
||||
dvlnt = dvptr = 0;
|
||||
update_lpcs (0);
|
||||
return SCPE_OK;
|
||||
}
|
||||
684
PDP10/pdp10_mdfp.c
Normal file
684
PDP10/pdp10_mdfp.c
Normal file
@@ -0,0 +1,684 @@
|
||||
/* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
Instructions handled in this module:
|
||||
imul integer multiply
|
||||
idiv integer divide
|
||||
mul multiply
|
||||
div divide
|
||||
dmul double precision multiply
|
||||
ddiv double precision divide
|
||||
fad(r) floating add (and round)
|
||||
fsb(r) floating subtract (and round)
|
||||
fmp(r) floating multiply (and round)
|
||||
fdv(r) floating divide and round
|
||||
fsc floating scale
|
||||
fix(r) floating to fixed (and round)
|
||||
fltr fixed to floating and round
|
||||
dfad double precision floating add/subtract
|
||||
dfmp double precision floating multiply
|
||||
dfdv double precision floating divide
|
||||
|
||||
The PDP-10 stores double (quad) precision integers in sequential
|
||||
AC's or memory locations. Integers are stored in 2's complement
|
||||
form. Only the sign of the high order word matters; the signs
|
||||
in low order words are ignored on input and set to the sign of
|
||||
the result on output. Quad precision integers exist only in the
|
||||
AC's as the result of a DMUL or the dividend of a DDIV.
|
||||
|
||||
0 00000000011111111112222222222333333
|
||||
0 12345678901234567890123456789012345
|
||||
+-+-----------------------------------+
|
||||
|S| high order integer | AC(n), A
|
||||
+-+-----------------------------------+
|
||||
|S| low order integer | AC(n + 1), A + 1
|
||||
+-+-----------------------------------+
|
||||
|S| low order integer | AC(n + 2)
|
||||
+-+-----------------------------------+
|
||||
|S| low order integer | AC(n + 3)
|
||||
+-+-----------------------------------+
|
||||
|
||||
The PDP-10 supports two floating point formats: single and double
|
||||
precision. In both, the exponent is 8 bits, stored in excess
|
||||
128 notation. The fraction is expected to be normalized. A
|
||||
single precision floating point number has 27 bits of fraction;
|
||||
a double precision number has 62 bits of fraction (the sign
|
||||
bit of the second word is ignored and is set to zero).
|
||||
|
||||
In a negative floating point number, the exponent is stored in
|
||||
one's complement form, the fraction in two's complement form.
|
||||
|
||||
0 00000000 011111111112222222222333333
|
||||
0 12345678 901234567890123456789012345
|
||||
+-+--------+---------------------------+
|
||||
|S|exponent| high order fraction | AC(n), A
|
||||
+-+--------+---------------------------+
|
||||
|0| low order fraction | AC(n + 1), A + 1
|
||||
+-+------------------------------------+
|
||||
|
||||
Note that treatment of the sign is different for double precision
|
||||
integers and double precision floating point. DMOVN (implemented
|
||||
as an inline macro) follows floating point conventions.
|
||||
|
||||
The original PDP-10 CPU (KA10) used a different format for double
|
||||
precision numbers and included certain instructions to make
|
||||
software support easier. These instructions were phased out in
|
||||
the KL10 and KS10 and are treated as MUUO's.
|
||||
|
||||
The KL10 added extended precision (11-bit exponent) floating point
|
||||
format (so-called G floating). These instructions were not
|
||||
implemented in the KS10 and are treated as MUUO's.
|
||||
|
||||
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
|
||||
10-Aug-01 RMS Removed register in declarations
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
struct ufp { /* unpacked fp number */
|
||||
int32 sign; /* sign */
|
||||
int32 exp; /* exponent */
|
||||
t_uint64 fhi; /* fraction high */
|
||||
t_uint64 flo; }; /* for double prec */
|
||||
|
||||
typedef struct ufp UFP;
|
||||
|
||||
#define MSK32 0xFFFFFFFF
|
||||
#define FIT27 (DMASK - 0x07FFFFFF)
|
||||
#define FIT32 (DMASK - MSK32)
|
||||
#define SFRC TRUE /* frac 2's comp */
|
||||
#define AFRC FALSE /* frac abs value */
|
||||
|
||||
/* In packed floating point number */
|
||||
|
||||
#define FP_BIAS 0200 /* exponent bias */
|
||||
#define FP_N_FHI 27 /* # of hi frac bits */
|
||||
#define FP_V_FHI 0 /* must be zero */
|
||||
#define FP_M_FHI 0000777777777
|
||||
#define FP_N_EXP 8 /* # of exp bits */
|
||||
#define FP_V_EXP (FP_V_FHI + FP_N_FHI)
|
||||
#define FP_M_EXP 0377
|
||||
#define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */
|
||||
#define FP_N_FLO 35 /* # of lo frac bits */
|
||||
#define FP_V_FLO 0 /* must be zero */
|
||||
#define FP_M_FLO 0377777777777
|
||||
#define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1))
|
||||
#define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP))
|
||||
#define GET_FPHI(x) ((x) & FP_M_FHI)
|
||||
#define GET_FPLO(x) ((x) & FP_M_FLO)
|
||||
|
||||
/* In unpacked floating point number */
|
||||
|
||||
#define FP_N_GUARD 1 /* # of guard bits */
|
||||
#define FP_V_UFLO FP_N_GUARD /* <35:1> */
|
||||
#define FP_V_URNDD (FP_V_UFLO - 1) /* dp round bit */
|
||||
#define FP_V_UFHI (FP_V_UFLO + FP_N_FLO) /* <62:36> */
|
||||
#define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */
|
||||
#define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */
|
||||
#define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */
|
||||
#define FP_UFHI 0x7FFFFFF000000000
|
||||
#define FP_UFLO 0x0000000FFFFFFFFE
|
||||
#define FP_UFRAC 0x7FFFFFFFFFFFFFFE
|
||||
#define FP_URNDD 0x0000000000000001
|
||||
#define FP_URNDS 0x0000000800000000
|
||||
#define FP_UNORM 0x4000000000000000
|
||||
#define FP_UCRY 0x8000000000000000
|
||||
#define FP_ONES 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
#define UNEG(x) ((~x) + 1)
|
||||
#define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0)
|
||||
|
||||
extern d10 *ac_cur; /* current AC block */
|
||||
extern int32 flags; /* flags */
|
||||
void mul (d10 a, d10 b, d10 *rs);
|
||||
void funpack (d10 h, d10 l, UFP *r, t_bool sgn);
|
||||
void fnorm (UFP *r, t_int64 rnd);
|
||||
d10 fpack (UFP *r, d10 *lo, t_bool fdvneg);
|
||||
|
||||
/* Integer multiply - checked against KS-10 ucode */
|
||||
|
||||
d10 imul (d10 a, d10 b)
|
||||
{
|
||||
d10 rs[2];
|
||||
|
||||
if ((a == SIGN) && (b == SIGN)) { /* KS10 hack */
|
||||
SETF (F_AOV | F_T1); /* -2**35 squared */
|
||||
return SIGN; }
|
||||
mul (a, b, rs); /* mpy, dprec result */
|
||||
if (rs[0] && (rs[0] != ONES)) { /* high not all sign? */
|
||||
rs[1] = TSTS (a ^ b)? SETS (rs[1]): CLRS (rs[1]); /* set sign */
|
||||
SETF (F_AOV | F_T1); } /* overflow */
|
||||
return rs[1];
|
||||
}
|
||||
|
||||
/* Integer divide, return quotient, remainder - checked against KS10 ucode
|
||||
The KS10 does not recognize -2^35/-1 as an error. Instead, it produces
|
||||
2^35 (that is, -2^35) as the incorrect result.
|
||||
*/
|
||||
|
||||
t_bool idiv (d10 a, d10 b, d10 *rs)
|
||||
{
|
||||
d10 dvd = ABS (a); /* make ops positive */
|
||||
d10 dvr = ABS (b);
|
||||
|
||||
if (dvr == 0) { /* divide by 0? */
|
||||
SETF (F_DCK | F_AOV | F_T1); /* set flags, return */
|
||||
return FALSE; }
|
||||
rs[0] = dvd / dvr; /* get quotient */
|
||||
rs[1] = dvd % dvr; /* get remainder */
|
||||
if (TSTS (a ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
|
||||
if (TSTS (a)) rs[1] = NEG (rs[1]); /* sign of remainder */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Multiply, return double precision result - checked against KS10 ucode */
|
||||
|
||||
void mul (d10 s1, d10 s2, d10 *rs)
|
||||
{
|
||||
t_uint64 a = ABS (s1);
|
||||
t_uint64 b = ABS (s2);
|
||||
t_uint64 t, u, r;
|
||||
|
||||
if ((a == 0) || (b == 0)) { /* operand = 0? */
|
||||
rs[0] = rs[1] = 0; /* result 0 */
|
||||
return; }
|
||||
if ((a & FIT32) || (b & FIT32)) { /* fit in 64b? */
|
||||
t = a >> 18; /* no, split in half */
|
||||
a = a & RMASK; /* "dp" multiply */
|
||||
u = b >> 18;
|
||||
b = b & RMASK;
|
||||
r = (a * b) + (((a * u) + (b * t)) << 18); /* low is only 35b */
|
||||
rs[0] = ((t * u) << 1) + (r >> 35); /* so lsh hi 1 */
|
||||
rs[1] = r & MMASK; }
|
||||
else { r = a * b; /* fits, native mpy */
|
||||
rs[0] = r >> 35; /* split at bit 35 */
|
||||
rs[1] = r & MMASK; }
|
||||
|
||||
if (TSTS (s1 ^ s2)) { MKDNEG (rs); } /* result -? */
|
||||
else if (TSTS (rs[0])) { /* result +, 2**70? */
|
||||
SETF (F_AOV | F_T1); /* overflow */
|
||||
rs[1] = SETS (rs[1]); } /* consistent - */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Divide, return quotient and remainder - checked against KS10 ucode
|
||||
Note that the initial divide check catches the case -2^70/-2^35;
|
||||
thus, the quotient can have at most 35 bits.
|
||||
*/
|
||||
|
||||
t_bool divi (int32 ac, d10 b, d10 *rs)
|
||||
{
|
||||
int32 p1 = ADDAC (ac, 1);
|
||||
d10 dvr = ABS (b); /* make divr positive */
|
||||
t_int64 t;
|
||||
int32 i;
|
||||
d10 dvd[2];
|
||||
|
||||
dvd[0] = AC(ac); /* divd high */
|
||||
dvd[1] = CLRS (AC(p1)); /* divd lo, clr sgn */
|
||||
if (TSTS (AC(ac))) { DMOVN (dvd); } /* make divd positive */
|
||||
if (dvd[0] >= dvr) { /* divide fail? */
|
||||
SETF (F_AOV | F_DCK | F_T1); /* set flags, return */
|
||||
return FALSE; }
|
||||
if (dvd[0] & FIT27) { /* fit in 63b? */
|
||||
for (i = 0, rs[0] = 0; i < 35; i++) { /* 35 quotient bits */
|
||||
dvd[0] = (dvd[0] << 1) | ((dvd[1] >> 34) & 1);
|
||||
dvd[1] = (dvd[1] << 1) & MMASK; /* shift dividend */
|
||||
rs[0] = rs[0] << 1; /* shift quotient */
|
||||
if (dvd[0] >= dvr) { /* subtract work? */
|
||||
dvd[0] = dvd[0] - dvr; /* quo bit is 1 */
|
||||
rs[0] = rs[0] + 1; } }
|
||||
rs[1] = dvd[0]; } /* store remainder */
|
||||
else { t = (dvd[0] << 35) | dvd[1]; /* concatenate */
|
||||
rs[0] = t / dvr; /* quotient */
|
||||
rs[1] = t % dvr; } /* remainder */
|
||||
if (TSTS (AC(ac) ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
|
||||
if (TSTS (AC(ac))) rs[1] = NEG (rs[1]); /* sign of remainder */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Double precision multiply. This is done the old fashioned way. Cross
|
||||
product multiplies would be a lot faster but would require more code.
|
||||
*/
|
||||
|
||||
void dmul (int32 ac, d10 *mpy)
|
||||
{
|
||||
int32 p1 = ADDAC (ac, 1);
|
||||
int32 p2 = ADDAC (ac, 2);
|
||||
int32 p3 = ADDAC (ac, 3);
|
||||
int32 i;
|
||||
d10 mpc[2], sign;
|
||||
|
||||
mpc[0] = AC(ac); /* mplcnd hi */
|
||||
mpc[1] = CLRS (AC(p1)); /* mplcnd lo, clr sgn */
|
||||
sign = mpc[0] ^ mpy[0]; /* sign of result */
|
||||
if (TSTS (mpc[0])) { DMOVN (mpc); } /* get abs (mpcnd) */
|
||||
if (TSTS (mpy[0])) { DMOVN (mpy); } /* get abs (mpyer) */
|
||||
else mpy[1] = CLRS (mpy[1]); /* clear mpy lo sign */
|
||||
AC(ac) = AC(p1) = AC(p2) = AC(p3) = 0; /* clear AC's */
|
||||
if (((mpy[0] | mpy[1]) == 0) || ((mpc[0] | mpc[1]) == 0)) return;
|
||||
for (i = 0; i < 71; i++) { /* 71 mpyer bits */
|
||||
if (i) { /* shift res, mpy */
|
||||
AC(p3) = (AC(p3) >> 1) | ((AC(p2) & 1) << 34);
|
||||
AC(p2) = (AC(p2) >> 1) | ((AC(p1) & 1) << 34);
|
||||
AC(p1) = (AC(p1) >> 1) | ((AC(ac) & 1) << 34);
|
||||
AC(ac) = AC(ac) >> 1;
|
||||
mpy[1] = (mpy[1] >> 1) | ((mpy[0] & 1) << 34);
|
||||
mpy[0] = mpy[0] >> 1; }
|
||||
if (mpy[1] & 1) { /* if mpy lo bit = 1 */
|
||||
AC(p1) = AC(p1) + mpc[1];
|
||||
AC(ac) = AC(ac) + mpc[0] + (TSTS (AC(p1) != 0));
|
||||
AC(p1) = CLRS (AC(p1)); } }
|
||||
if (TSTS (sign)) { /* result minus? */
|
||||
AC(p3) = (-AC(p3)) & MMASK; /* quad negate */
|
||||
AC(p2) = (~AC(p2) + (AC(p3) == 0)) & MMASK;
|
||||
AC(p1) = (~AC(p1) + (AC(p2) == 0)) & MMASK;
|
||||
AC(ac) = (~AC(ac) + (AC(p1) == 0)) & DMASK; }
|
||||
else if (TSTS (AC(ac))) SETF (F_AOV | F_T1); /* wrong sign */
|
||||
if (TSTS (AC(ac))) { /* if result - */
|
||||
AC(p1) = SETS (AC(p1)); /* make signs consistent */
|
||||
AC(p2) = SETS (AC(p2));
|
||||
AC(p3) = SETS (AC(p3)); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Double precision divide - checked against KS10 ucode */
|
||||
|
||||
void ddiv (int32 ac, d10 *dvr)
|
||||
{
|
||||
int32 i, cryin;
|
||||
d10 sign, qu[2], dvd[4];
|
||||
|
||||
dvd[0] = AC(ac); /* save dividend */
|
||||
for (i = 1; i < 4; i++) dvd[i] = CLRS (AC(ADDAC (ac, i)));
|
||||
sign = AC(ac) ^ dvr[0]; /* sign of result */
|
||||
if (TSTS (AC(ac))) { /* get abs (dividend) */
|
||||
for (i = 3, cryin = 1; i > 0; i--) { /* negate quad */
|
||||
dvd[i] = (~dvd[i] + cryin) & MMASK; /* comp + carry in */
|
||||
if (dvd[i]) cryin = 0; } /* next carry in */
|
||||
dvd[0] = (~dvd[0] + cryin) & DMASK; }
|
||||
if (TSTS (dvr[0])) { DMOVN (dvr); } /* get abs (divisor) */
|
||||
else dvr[1] = CLRS (dvr[1]);
|
||||
if (DCMPGE (dvd, dvr)) { /* will divide work? */
|
||||
SETF (F_AOV | F_DCK | F_T1); /* no, set flags */
|
||||
return; }
|
||||
qu[0] = qu[1] = 0; /* clear quotient */
|
||||
for (i = 0; i < 70; i++) { /* 70 quotient bits */
|
||||
dvd[0] = ((dvd[0] << 1) | ((dvd[1] >> 34) & 1)) & DMASK;;
|
||||
dvd[1] = ((dvd[1] << 1) | ((dvd[2] >> 34) & 1)) & MMASK;
|
||||
dvd[2] = ((dvd[2] << 1) | ((dvd[3] >> 34) & 1)) & MMASK;
|
||||
dvd[3] = (dvd[3] << 1) & MMASK; /* shift dividend */
|
||||
qu[0] = (qu[0] << 1) | ((qu[1] >> 34) & 1); /* shift quotient */
|
||||
qu[1] = (qu[1] << 1) & MMASK;
|
||||
if (DCMPGE (dvd, dvr)) { /* subtract work? */
|
||||
dvd[0] = dvd[0] - dvr[0] - (dvd[1] < dvr[1]);
|
||||
dvd[1] = (dvd[1] - dvr[1]) & MMASK; /* do subtract */
|
||||
qu[1] = qu[1] + 1; } } /* set quotient bit */
|
||||
if (TSTS (sign) && (qu[0] | qu[1])) { MKDNEG (qu); }
|
||||
if (TSTS (AC(ac)) && (dvd[0] | dvd[1])) { MKDNEG (dvd); }
|
||||
AC(ac) = qu[0]; /* quotient */
|
||||
AC(ADDAC(ac, 1)) = qu[1];
|
||||
AC(ADDAC(ac, 2)) = dvd[0]; /* remainder */
|
||||
AC(ADDAC(ac, 3)) = dvd[1];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Single precision floating add - checked against KS10 ucode
|
||||
The KS10 shifts the smaller operand regardless of the exponent diff.
|
||||
This code will not shift more than 63 places; shifts beyond that
|
||||
cannot change the value of the smaller operand.
|
||||
|
||||
If the signs of the operands are the same, the result sign is the
|
||||
same as the source sign; the sign of the result fraction is actually
|
||||
part of the data. If the signs of the operands are different, the
|
||||
result sign is determined by the fraction sign.
|
||||
*/
|
||||
|
||||
d10 fad (d10 op1, d10 op2, t_bool rnd, int32 inv)
|
||||
{
|
||||
int32 ediff;
|
||||
UFP a, b, t;
|
||||
|
||||
if (inv) op2 = NEG (op2); /* subtract? -b */
|
||||
if (op1 == 0) funpack (op2, 0, &a, AFRC); /* a = 0? result is b */
|
||||
else if (op2 == 0) funpack (op1, 0, &a, AFRC); /* b = 0? result is a */
|
||||
else { funpack (op1, 0, &a, SFRC); /* unpack operands */
|
||||
funpack (op2, 0, &b, SFRC); /* fracs are 2's comp */
|
||||
ediff = a.exp - b.exp; /* get exp diff */
|
||||
if (ediff < 0) { /* a < b? switch */
|
||||
t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
ediff = -ediff; }
|
||||
if (ediff > 63) ediff = 63; /* cap diff at 63 */
|
||||
if (ediff) b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */
|
||||
a.fhi = a.fhi + b.fhi; /* add fractions */
|
||||
if (a.sign ^ b.sign) { /* add or subtract? */
|
||||
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
|
||||
a.fhi = UNEG (a.fhi); /* complement result */
|
||||
a.sign = 1; } /* result is - */
|
||||
else a.sign = 0; } /* result is + */
|
||||
else { if (a.sign) a.fhi = UNEG (a.fhi); /* add, src -? comp */
|
||||
if (a.fhi & FP_UCRY) { /* check for carry */
|
||||
a.fhi = a.fhi >> 1; /* flo won't be used */
|
||||
a.exp = a.exp + 1; } } }
|
||||
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
|
||||
return fpack (&a, NULL, FALSE);
|
||||
}
|
||||
|
||||
/* Single precision floating multiply. Because the fractions are 27b,
|
||||
a 64b multiply can be used for the fraction multiply. The 27b
|
||||
fractions are positioned 0'frac'0000, resulting in 00'hifrac'0..0.
|
||||
The extra 0 is accounted for by biasing the result exponent.
|
||||
*/
|
||||
|
||||
#define FP_V_SPM (FP_V_UFHI - (32 - FP_N_FHI - 1))
|
||||
d10 fmp (d10 op1, d10 op2, t_bool rnd)
|
||||
{
|
||||
UFP a, b;
|
||||
|
||||
funpack (op1, 0, &a, AFRC); /* unpack operands */
|
||||
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
|
||||
if ((a.fhi == 0) || (b.fhi == 0)) return 0; /* either 0? */
|
||||
a.sign = a.sign ^ b.sign; /* result sign */
|
||||
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
|
||||
a.fhi = (a.fhi >> FP_V_SPM) * (b.fhi >> FP_V_SPM); /* high 27b of result */
|
||||
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
|
||||
return fpack (&a, NULL, FALSE);
|
||||
}
|
||||
|
||||
/* Single precision floating divide. Because the fractions are 27b, a
|
||||
64b divide can be used for the fraction divide. Note that 28b-29b
|
||||
of fraction are developed; the code will do one special normalize to
|
||||
make sure that the 28th bit is not lost. Also note the special
|
||||
treatment of negative quotients with non-zero remainders; this
|
||||
implements the note on p2-23 of the Processor Reference Manual.
|
||||
*/
|
||||
|
||||
t_bool fdv (d10 op1, d10 op2, d10 *rs, t_bool rnd)
|
||||
{
|
||||
UFP a, b;
|
||||
t_uint64 savhi;
|
||||
t_bool rem = FALSE;
|
||||
|
||||
funpack (op1, 0, &a, AFRC); /* unpack operands */
|
||||
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
|
||||
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
|
||||
SETF (F_AOV | F_DCK | F_FOV | F_T1);
|
||||
return FALSE; }
|
||||
if (savhi = a.fhi) { /* dvd = 0? quo = 0 */
|
||||
a.sign = a.sign ^ b.sign; /* result sign */
|
||||
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
|
||||
a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */
|
||||
if (a.sign && (savhi != (a.fhi * (b.fhi >> (FP_N_FHI + 1)))))
|
||||
rem = TRUE; /* KL/KS hack */
|
||||
a.fhi = a.fhi << (FP_V_UNORM - FP_N_FHI - 1); /* put quo in place */
|
||||
if ((a.fhi & FP_UNORM) == 0) { /* normalize 1b */
|
||||
a.fhi = a.fhi << 1; /* before masking */
|
||||
a.exp = a.exp - 1; }
|
||||
a.fhi = a.fhi & (FP_UFHI | FP_URNDS); } /* mask quo to 28b */
|
||||
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
|
||||
*rs = fpack (&a, NULL, rem); /* pack result */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Single precision floating scale. */
|
||||
|
||||
d10 fsc (d10 val, a10 ea)
|
||||
{
|
||||
int32 sc = LIT8 (ea);
|
||||
UFP a;
|
||||
|
||||
if (val == 0) return 0;
|
||||
funpack (val, 0, &a, AFRC); /* unpack operand */
|
||||
if (ea & RSIGN) a.exp = a.exp - sc; /* adjust exponent */
|
||||
else a.exp = a.exp + sc;
|
||||
fnorm (&a, 0); /* renormalize */
|
||||
return fpack (&a, NULL, FALSE); /* pack result */
|
||||
}
|
||||
|
||||
/* Float integer operand and round */
|
||||
|
||||
d10 fltr (d10 mb)
|
||||
{
|
||||
UFP a;
|
||||
d10 val = ABS (mb);
|
||||
|
||||
a.sign = GET_FPSIGN (mb); /* get sign */
|
||||
a.exp = FP_BIAS + 36; /* initial exponent */
|
||||
a.fhi = val << (FP_V_UNORM - 35); /* left justify op */
|
||||
a.flo = 0;
|
||||
fnorm (&a, FP_URNDS); /* normalize, round */
|
||||
return fpack (&a, NULL, FALSE); /* pack result */
|
||||
}
|
||||
|
||||
/* Fix and truncate/round floating operand */
|
||||
|
||||
void fix (int32 ac, d10 mb, t_bool rnd)
|
||||
{
|
||||
int32 sc;
|
||||
t_uint64 so;
|
||||
UFP a;
|
||||
|
||||
funpack (mb, 0, &a, AFRC); /* unpack operand */
|
||||
if (a.exp > (FP_BIAS + FP_N_FHI + FP_N_EXP)) SETF (F_AOV | F_T1);
|
||||
else if (a.exp < (FP_BIAS - 1)) AC(ac) = 0;
|
||||
else { sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1;
|
||||
AC(ac) = a.fhi >> sc;
|
||||
if (rnd) {
|
||||
so = a.fhi << (64 - sc);
|
||||
if (so >= (0x8000000000000000 + a.sign)) AC(ac) = AC(ac) + 1; }
|
||||
if (a.sign) AC(ac) = NEG (AC(ac)); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Double precision floating add/subtract
|
||||
Since a.flo is 0, adding b.flo is just a copy - this is incorporated into
|
||||
the denormalization step. If there's no denormalization, bflo is zero too.
|
||||
*/
|
||||
|
||||
void dfad (int32 ac, d10 *rs, int32 inv)
|
||||
{
|
||||
int32 p1 = ADDAC (ac, 1);
|
||||
int32 ediff;
|
||||
UFP a, b, t;
|
||||
|
||||
if (inv) { DMOVN (rs); } /* subtract? -b */
|
||||
if ((AC(ac) | AC(p1)) == 0) funpack (rs[0], rs[1], &a, AFRC);
|
||||
/* a == 0? sum = b */
|
||||
else if ((rs[0] | rs[1]) == 0) funpack (AC(ac), AC(p1), &a, AFRC);
|
||||
/* b == 0? sum = a */
|
||||
else {
|
||||
funpack (AC(ac), AC(p1), &a, SFRC); /* unpack operands */
|
||||
funpack (rs[0], rs[1], &b, SFRC);
|
||||
ediff = a.exp - b.exp; /* get exp diff */
|
||||
if (ediff < 0) { /* a < b? switch */
|
||||
t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
ediff = -ediff; }
|
||||
if (ediff > 127) ediff = 127; /* cap diff at 127 */
|
||||
if (ediff > 63) { /* diff > 63? */
|
||||
a.flo = (t_int64) b.fhi >> (ediff - 64); /* b hi to a lo */
|
||||
b.fhi = b.sign? FP_ONES: 0; } /* hi = all sign */
|
||||
else if (ediff) { /* diff <= 63 */
|
||||
a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff));
|
||||
b.fhi = (t_int64) b.fhi >> ediff; } /* shift b (signed) */
|
||||
a.fhi = a.fhi + b.fhi; /* do add */
|
||||
if (a.sign ^ b.sign) { /* add or subtract? */
|
||||
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
|
||||
DUNEG (a); /* complement result */
|
||||
a.sign = 1; } /* result is - */
|
||||
else a.sign = 0; } /* result is + */
|
||||
else { if (a.sign) { DUNEG (a); }; /* add, src -? comp */
|
||||
if (a.fhi & FP_UCRY) { /* check for carry */
|
||||
a.fhi = a.fhi >> 1; /* flo won't be used */
|
||||
a.exp = a.exp + 1; } } }
|
||||
fnorm (&a, FP_URNDD); /* normalize, round */
|
||||
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Double precision floating multiply
|
||||
The 62b fractions are multiplied, with cross products, to produce a
|
||||
124b fraction with two leading and two trailing 0's. Because the
|
||||
product has 2 leading 0's, instead of the normal 1, an extra
|
||||
normalization step is needed. Accordingly, the exponent calculation
|
||||
increments the result exponent, to compensate for normalization.
|
||||
*/
|
||||
|
||||
void dfmp (int32 ac, d10 *rs)
|
||||
{
|
||||
int32 p1 = ADDAC (ac, 1);
|
||||
t_uint64 xh, xl, yh, yl, mid;
|
||||
UFP a, b;
|
||||
|
||||
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
|
||||
funpack (rs[0], rs[1], &b, AFRC);
|
||||
if ((a.fhi == 0) || (b.fhi == 0)) { /* either 0? result 0 */
|
||||
AC(ac) = AC(p1) = 0;
|
||||
return; }
|
||||
a.sign = a.sign ^ b.sign; /* result sign */
|
||||
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
|
||||
xh = a.fhi >> 32; /* split 62b fracs */
|
||||
xl = a.fhi & MSK32; /* into 32b halves */
|
||||
yh = b.fhi >> 32;
|
||||
yl = b.fhi & MSK32;
|
||||
a.fhi = xh * yh; /* hi xproduct */
|
||||
a.flo = xl * yl; /* low xproduct */
|
||||
mid = (xh * yl) + (yh * xl); /* fits in 64b */
|
||||
a.flo = a.flo + (mid << 32); /* add mid lo to lo */
|
||||
a.fhi = a.fhi + ((mid >> 32) & MSK32) + (a.flo < (mid << 32));
|
||||
fnorm (&a, FP_URNDD); /* normalize, round */
|
||||
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Double precision floating divide
|
||||
This algorithm develops a full 62 bits of quotient, plus one rounding
|
||||
bit, in the low order 63b of a 64b number. To do this, we must assure
|
||||
that the initial divide step generates a 1. If it would fail, shift
|
||||
the dividend left and decrement the result exponent accordingly.
|
||||
*/
|
||||
|
||||
void dfdv (int32 ac, d10 *rs)
|
||||
{
|
||||
int32 p1 = ADDAC (ac, 1);
|
||||
int32 i;
|
||||
t_uint64 qu = 0;
|
||||
UFP a, b;
|
||||
|
||||
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
|
||||
funpack (rs[0], rs[1], &b, AFRC);
|
||||
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
|
||||
SETF (F_AOV | F_DCK | F_FOV | F_T1);
|
||||
return; }
|
||||
if (a.fhi) { /* dvd = 0? quo = 0 */
|
||||
a.sign = a.sign ^ b.sign; /* result sign */
|
||||
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
|
||||
if (a.fhi < b.fhi) { /* make sure initial */
|
||||
a.fhi = a.fhi << 1; /* divide step will work */
|
||||
a.exp = a.exp - 1; }
|
||||
for (i = 0; i < 63; i++) { /* 63b of quotient */
|
||||
qu = qu << 1; /* shift quotient */
|
||||
if (a.fhi >= b.fhi) { /* will div work? */
|
||||
a.fhi = a.fhi - b.fhi; /* sub, quo = 1 */
|
||||
qu = qu + 1; }
|
||||
a.fhi = a.fhi << 1; } /* shift dividend */
|
||||
a.fhi = qu; }
|
||||
fnorm (&a, FP_URNDD); /* normalize, round */
|
||||
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unpack floating point operand */
|
||||
|
||||
void funpack (d10 h, d10 l, UFP *r, t_bool sgn)
|
||||
{
|
||||
d10 fphi, fplo;
|
||||
|
||||
r -> sign = GET_FPSIGN (h);
|
||||
r -> exp = GET_FPEXP (h);
|
||||
fphi = GET_FPHI (h);
|
||||
fplo = GET_FPLO (l);
|
||||
r -> fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO);
|
||||
r -> flo = 0;
|
||||
if (r -> sign) {
|
||||
r -> exp = r -> exp ^ FP_M_EXP;
|
||||
if (sgn) r -> fhi = r -> fhi | FP_UCRY; /* ext sign */
|
||||
else { if (r -> fhi) r -> fhi = UNEG (r -> fhi) & FP_UFRAC;
|
||||
else { r -> exp = r -> exp + 1;
|
||||
r -> fhi = FP_UNORM; } } }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normalize and optionally round floating point operand */
|
||||
|
||||
void fnorm (UFP *a, t_int64 rnd)
|
||||
{
|
||||
int32 i;
|
||||
static t_uint64 normmask[6] = {
|
||||
0x6000000000000000, 0x7800000000000000, 0x7F80000000000000,
|
||||
0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF };
|
||||
static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 };
|
||||
|
||||
if ((a -> fhi | a -> flo) == 0) { /* if fraction = 0 */
|
||||
a -> sign = a -> exp = 0; /* result is 0 */
|
||||
return; }
|
||||
while ((a -> fhi & FP_UNORM) == 0) { /* normalized? */
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (a -> fhi & normmask[i]) break; }
|
||||
a -> fhi = (a -> fhi << normtab[i]) | (a -> flo >> (64 - normtab[i]));
|
||||
a -> flo = a -> flo << normtab[i];
|
||||
a -> exp = a -> exp - normtab[i]; }
|
||||
if (rnd) { /* rounding? */
|
||||
a -> fhi = a -> fhi + rnd; /* add round const */
|
||||
if (a -> fhi & FP_UCRY) { /* if carry out, */
|
||||
a -> fhi = a -> fhi >> 1; /* renormalize */
|
||||
a -> exp = a -> exp + 1; } }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pack floating point result */
|
||||
|
||||
d10 fpack (UFP *r, d10 *lo, t_bool fdvneg)
|
||||
{
|
||||
d10 val[2];
|
||||
|
||||
if (r -> exp < 0) SETF (F_AOV | F_FOV | F_FXU | F_T1);
|
||||
else if (r -> exp > FP_M_EXP) SETF (F_AOV | F_FOV | F_T1);
|
||||
val[0] = (((((d10) r -> exp) & FP_M_EXP) << FP_V_EXP) |
|
||||
((r -> fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK;
|
||||
if (lo) val[1] = ((r -> fhi & FP_UFLO) >> FP_V_UFLO) & MMASK;
|
||||
else val[1] = 0;
|
||||
if (r -> sign) { /* negate? */
|
||||
if (fdvneg) { /* fdvr special? */
|
||||
val[1] = ~val[1] & MMASK; /* 1's comp */
|
||||
val[0] = ~val[0] & DMASK; }
|
||||
else { DMOVN (val); } } /* 2's comp */
|
||||
if (lo) *lo = val[1];
|
||||
return val[0];
|
||||
}
|
||||
799
PDP10/pdp10_pag.c
Normal file
799
PDP10/pdp10_pag.c
Normal file
@@ -0,0 +1,799 @@
|
||||
/* pdp10_pag.c: PDP-10 paging subsystem simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
pag KS10 pager
|
||||
|
||||
02-Dec-01 RMS Fixed bug in ITS LPMR (found by Dave Conroy)
|
||||
21-Aug-01 RMS Fixed bug in ITS paging (found by Miriam Lennox)
|
||||
Removed register from declarations
|
||||
19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug
|
||||
03-May-01 RMS Fixed bug in indirect page table pointer processing
|
||||
29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR
|
||||
|
||||
The pager consists of a standard hardware part (the translation
|
||||
tables) and an operating-system specific page table fill routine.
|
||||
|
||||
There are two translation tables, one for executive mode and one
|
||||
for user mode. Each table consists of 512 page table entries,
|
||||
one for each page in the 18b virtual address space. Each pte
|
||||
contains (in the hardware) a valid bit, a writeable bit, an
|
||||
address space bit (executive or user), and a cacheable bit, plus
|
||||
the physical page number corresponding to the virtual page. In
|
||||
the simulator, the pte is expanded for rapid processing of normal
|
||||
reads and writes. An expanded pte contains a valid bit, a writeable
|
||||
bit, and the physical page number shifted left by the page size.
|
||||
|
||||
Expanded pte meaning
|
||||
0 invalid
|
||||
>0 read only
|
||||
<0 read write
|
||||
|
||||
There is a third, physical table, which is used in place of the
|
||||
executive and user tables if paging is off. Its entries are always
|
||||
valid and always writeable.
|
||||
|
||||
To translate a virtual to physical address, the simulator uses
|
||||
the virtual page number to index into the appropriate page table.
|
||||
If the page table entry (pte) is not valid, the page fill routine
|
||||
is called to see if the entry is merely not filled or is truly
|
||||
inaccessible. If the pte is valid but not writeable, and the
|
||||
reference is a write reference, the page fill routine is also
|
||||
called to see if the reference can be resolved.
|
||||
|
||||
The page fill routine is operating system dependent. Three styles
|
||||
of paging are supported:
|
||||
|
||||
TOPS10 known in the KS10 microcode as KI10 paging,
|
||||
used by earlier versions of TOPS10
|
||||
TOPS20 known in the KS10 microcode as KL10 paging,
|
||||
used by later versions of TOPS10, and TOPS20
|
||||
ITS used only by ITS
|
||||
|
||||
TOPS10 vs TOPS20 is selected by a bit in the EBR; ITS paging is
|
||||
"hardwired" (it required different microcode).
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
/* Page table (contains expanded pte's) */
|
||||
|
||||
#define PTBL_ASIZE PAG_N_VPN
|
||||
#define PTBL_MEMSIZE (1 << PTBL_ASIZE) /* page table size */
|
||||
#define PTBL_AMASK (PTBL_MEMSIZE - 1)
|
||||
#define PTBL_M (1u << 31) /* must be sign bit */
|
||||
#define PTBL_V (1u << 30)
|
||||
#define PTBL_MASK (PAG_PPN | PTBL_M | PTBL_V)
|
||||
|
||||
/* NXM processing */
|
||||
|
||||
#define REF_V 0 /* ref is virt */
|
||||
#define REF_P 1 /* ref is phys */
|
||||
#define PF_OK 0 /* pfail ok */
|
||||
#define PF_TR 1 /* pfail trap */
|
||||
|
||||
extern d10 *M;
|
||||
extern d10 acs[AC_NBLK * AC_NUM];
|
||||
extern d10 *ac_cur, *ac_prv, *last_pa;
|
||||
extern a10 epta, upta;
|
||||
extern int32 flags;
|
||||
extern d10 pager_word;
|
||||
extern int32 apr_flg;
|
||||
extern d10 ebr, ubr, hsb;
|
||||
extern d10 spt, cst, cstm, pur;
|
||||
extern a10 dbr1, dbr2, dbr3, dbr4;
|
||||
extern d10 pcst, quant;
|
||||
extern t_bool paging;
|
||||
extern UNIT cpu_unit;
|
||||
extern jmp_buf save_env;
|
||||
extern int32 test_int (void);
|
||||
extern int32 pi_eval (void);
|
||||
|
||||
int32 eptbl[PTBL_MEMSIZE]; /* exec page table */
|
||||
int32 uptbl[PTBL_MEMSIZE]; /* user page table */
|
||||
int32 physptbl[PTBL_MEMSIZE]; /* phys page table */
|
||||
int32 *ptbl_cur, *ptbl_prv;
|
||||
int32 save_ea;
|
||||
|
||||
int32 ptbl_fill (a10 ea, int32 *ptbl, int32 mode);
|
||||
t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat pag_reset (DEVICE *dptr);
|
||||
void pag_nxm (a10 pa, int32 phys, int32 trap);
|
||||
|
||||
/* Pager data structures
|
||||
|
||||
pag_dev pager device descriptor
|
||||
pag_unit pager units
|
||||
pager_reg pager register list
|
||||
*/
|
||||
|
||||
UNIT pag_unit[] = {
|
||||
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) } };
|
||||
|
||||
REG pag_reg[] = {
|
||||
{ ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE pag_dev = {
|
||||
"PAG", pag_unit, pag_reg, NULL,
|
||||
2, 8, PTBL_ASIZE, 1, 8, 32,
|
||||
&pag_ex, &pag_dep, &pag_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Memory read and write routines
|
||||
|
||||
Read - read current or previous, read checking
|
||||
ReadM - read current or previous, write checking
|
||||
ReadE - read exec
|
||||
ReadP - read physical
|
||||
Write - write current or previous
|
||||
WriteE - write exec
|
||||
WriteP - write physical
|
||||
AccChk - test accessibility of virtual address
|
||||
*/
|
||||
|
||||
d10 Read (a10 ea, int32 prv)
|
||||
{
|
||||
int32 pa, vpn, xpte;
|
||||
|
||||
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
|
||||
vpn = PAG_GETVPN (ea); /* get page num */
|
||||
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
|
||||
if (xpte == 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_RD);
|
||||
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
|
||||
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
|
||||
return M[pa]; /* return data */
|
||||
}
|
||||
|
||||
d10 ReadM (a10 ea, int32 prv)
|
||||
{
|
||||
int32 pa, vpn, xpte;
|
||||
|
||||
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
|
||||
vpn = PAG_GETVPN (ea); /* get page num */
|
||||
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
|
||||
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
|
||||
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
|
||||
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
|
||||
return M[pa]; /* return data */
|
||||
}
|
||||
|
||||
d10 ReadE (a10 ea)
|
||||
{
|
||||
int32 pa, vpn, xpte;
|
||||
|
||||
if (ea < AC_NUM) return AC(ea); /* AC? use current */
|
||||
if (!PAGING) return M[ea]; /* phys? no mapping */
|
||||
vpn = PAG_GETVPN (ea); /* get page num */
|
||||
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
|
||||
if (xpte == 0) xpte = ptbl_fill (ea, eptbl, PTF_RD);
|
||||
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
|
||||
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
|
||||
return M[pa]; /* return data */
|
||||
}
|
||||
|
||||
d10 ReadP (a10 ea)
|
||||
{
|
||||
if (ea < AC_NUM) return AC(ea); /* AC request */
|
||||
if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
|
||||
return M[ea]; /* return data */
|
||||
}
|
||||
|
||||
void Write (a10 ea, d10 val, int32 prv)
|
||||
{
|
||||
int32 pa, vpn, xpte;
|
||||
|
||||
if (ea < AC_NUM) { /* AC request */
|
||||
if (prv) ac_prv[ea] = val; /* write AC */
|
||||
else ac_cur[ea] = val; }
|
||||
else { vpn = PAG_GETVPN (ea); /* get page num */
|
||||
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
|
||||
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
|
||||
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
|
||||
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
|
||||
else M[pa] = val; } /* write data */
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteE (a10 ea, d10 val)
|
||||
{
|
||||
int32 pa, vpn, xpte;
|
||||
|
||||
if (ea < AC_NUM) AC(ea) = val; /* AC? use current */
|
||||
else if (!PAGING) M[ea] = val; /* phys? no mapping */
|
||||
else { vpn = PAG_GETVPN (ea); /* get page num */
|
||||
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
|
||||
if (xpte >= 0) xpte = ptbl_fill (ea, eptbl, PTF_WR);
|
||||
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
|
||||
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
|
||||
else M[pa] = val; } /* write data */
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteP (a10 ea, d10 val)
|
||||
{
|
||||
if (ea < AC_NUM) AC(ea) = val; /* AC request */
|
||||
else { if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
|
||||
M[ea] = val; } /* memory */
|
||||
return;
|
||||
}
|
||||
|
||||
t_bool AccViol (a10 ea, int32 prv, int32 mode)
|
||||
{
|
||||
int32 vpn, xpte;
|
||||
|
||||
if (ea < AC_NUM) return FALSE; /* AC request */
|
||||
vpn = PAG_GETVPN (ea); /* get page num */
|
||||
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
|
||||
if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */
|
||||
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP);
|
||||
if (xpte) return FALSE; /* accessible */
|
||||
return TRUE; /* not accessible */
|
||||
}
|
||||
|
||||
void pag_nxm (a10 pa, int32 phys, int32 trap)
|
||||
{
|
||||
apr_flg = apr_flg | APRF_NXM; /* set APR flag */
|
||||
pi_eval (); /* eval intr */
|
||||
pager_word = PF_NXM | (phys? PF_NXMP: 0) |
|
||||
(TSTF (F_USR)? PF_USER: 0) | ((d10) pa);
|
||||
if (PAGING && trap) ABORT (PAGE_FAIL); /* trap? */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Page table fill
|
||||
|
||||
This routine is called if the page table is invalid, or on a write
|
||||
reference if the page table is read only. If the access is allowed
|
||||
it stores the pte in the page table entry and returns an expanded
|
||||
pte for use by the caller. Otherwise, it generates a page fail.
|
||||
|
||||
Notes:
|
||||
- If called from the console, invalid references return a pte
|
||||
of 0, and the page table entry is not filled.
|
||||
- If called from MAP, invalid references return a pte of 0. The
|
||||
page fail word is properly set up.
|
||||
*/
|
||||
|
||||
#define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) return 0; \
|
||||
ABORT (PAGE_FAIL)
|
||||
#define READPT(x,y) if (MEM_ADDR_NXM (y)) { \
|
||||
pag_nxm (y, REF_P, PF_OK); \
|
||||
PAGE_FAIL_TRAP; } \
|
||||
x = ReadP (y)
|
||||
|
||||
int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode)
|
||||
{
|
||||
|
||||
/* ITS paging is based on conventional page tables. ITS divides each address
|
||||
space into a 128K high and low section, and uses different descriptor base
|
||||
pointers (dbr) for each. ITS pages are twice the size of DEC standard;
|
||||
therefore, the fill routine fills two page table entries and returns the pte
|
||||
that maps the correct ITS half page. This allows the DEC paging macros to
|
||||
be used in the normal path read-write routines.
|
||||
|
||||
ITS has no MAP instruction, therefore, physical NXM traps are ok.
|
||||
*/
|
||||
|
||||
if (ITS) { /* ITS paging */
|
||||
int32 acc, decvpn, pte, vpn, ptead, xpte;
|
||||
d10 ptewd;
|
||||
|
||||
vpn = ITS_GETVPN (ea); /* get ITS pagno */
|
||||
if (tbl == uptbl)
|
||||
ptead = ((ea & RSIGN)? dbr2: dbr1) + ((vpn >> 1) & 077);
|
||||
else ptead = ((ea & RSIGN)? dbr3: dbr4) + ((vpn >> 1) & 077);
|
||||
ptewd = ReadP (ptead); /* get PTE pair */
|
||||
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
|
||||
acc = ITS_GETACC (pte); /* get access */
|
||||
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
|
||||
((mode & PTF_WR)? PF_ITS_WRITE: 0) | (acc << PF_ITS_V_ACC);
|
||||
if ((acc != ITS_ACC_NO) && (!(mode & PTF_WR) || (acc == ITS_ACC_RW))) {
|
||||
pte = pte & ~PTE_ITS_AGE; /* clear age */
|
||||
if (vpn & 1) WriteP (ptead, (ptewd & LMASK) | pte);
|
||||
else WriteP (ptead, (ptewd & RMASK) | (((d10) pte) << 18));
|
||||
xpte = ((pte & PTE_ITS_PPMASK) << ITS_V_PN) | PTBL_V |
|
||||
((acc == ITS_ACC_RW)? PTBL_M: 0);
|
||||
decvpn = PAG_GETVPN (ea); /* get tlb idx */
|
||||
if (!(mode & PTF_CON)) {
|
||||
tbl[decvpn & ~1] = xpte; /* map lo ITS page */
|
||||
tbl[decvpn | 1] = xpte + PAG_SIZE; } /* map hi */
|
||||
return (xpte + ((decvpn & 1)? PAG_SIZE: 0)); }
|
||||
PAGE_FAIL_TRAP;
|
||||
} /* end ITS paging */
|
||||
|
||||
/* TOPS-10 paging - checked against KS10 microcode
|
||||
|
||||
TOPS-10 paging is also based on conventional page tables. The user page
|
||||
tables are arranged contiguously at the beginning of the user process table;
|
||||
however, the executive page tables are scattered through the executive and
|
||||
user process tables.
|
||||
*/
|
||||
|
||||
else if (!T20) { /* TOPS-10 paging */
|
||||
int32 pte, vpn, ptead, xpte;
|
||||
d10 ptewd;
|
||||
|
||||
vpn = PAG_GETVPN (ea); /* get virt page num */
|
||||
if (tbl == uptbl) ptead = upta + UPT_T10_UMAP + (vpn >> 1);
|
||||
else if (vpn < 0340) ptead = epta + EPT_T10_X000 + (vpn >> 1);
|
||||
else if (vpn < 0400) ptead = upta + UPT_T10_X340 + ((vpn - 0340) >> 1);
|
||||
else ptead = epta + EPT_T10_X400 + ((vpn - 0400) >> 1);
|
||||
READPT (ptewd, ptead); /* get PTE pair */
|
||||
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
|
||||
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
|
||||
((mode & PTF_WR)? PF_WRITE: 0) |
|
||||
((pte & PTE_T10_A)? PF_T10_A |
|
||||
((pte & PTE_T10_S)? PF_T10_S: 0): 0);
|
||||
if (mode & PTF_MAP) pager_word = pager_word | /* map? add to pf wd */
|
||||
((pte & PTE_T10_W)? PF_T10_W: 0) | /* W, S, C bits */
|
||||
((pte & PTE_T10_S)? PF_T10_S: 0) |
|
||||
((pte & PTE_T10_C)? PF_C: 0);
|
||||
if ((pte & PTE_T10_A) && (!(mode & PTF_WR) || (pte & PTE_T10_W))) {
|
||||
xpte = ((pte & PTE_PPMASK) << PAG_V_PN) | /* calc exp pte */
|
||||
PTBL_V | ((pte & PTE_T10_W)? PTBL_M: 0);
|
||||
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
|
||||
return xpte; }
|
||||
PAGE_FAIL_TRAP;
|
||||
} /* end TOPS10 paging */
|
||||
|
||||
/* TOPS-20 paging - checked against KS10 ucode.
|
||||
|
||||
TOPS-20 paging has three phases:
|
||||
|
||||
1. Starting at EPT/UPT + 540 + section number, chase section pointers to
|
||||
get the pointer to the section page table. In the KS10, because there
|
||||
is only one section, the microcode caches the result of this evaluation.
|
||||
Also, the evaluation of indirect pointers is simplified, as the section
|
||||
table index is ignored.
|
||||
|
||||
2. Starting with the page map pointer, chase page pointers to get the
|
||||
pointer to the page. The KS10 allows the operating system to inhibit
|
||||
updating of the CST (base address = 0).
|
||||
|
||||
3. Use the page pointer to get the CST entry. If a write reference to
|
||||
a writeable page, set CST_M. If CST_M is set, set M in page table.
|
||||
*/
|
||||
|
||||
else { /* TOPS-20 paging */
|
||||
int32 pmi, vpn, xpte;
|
||||
int32 flg, t;
|
||||
t_bool stop;
|
||||
a10 pa, csta;
|
||||
d10 ptr, cste;
|
||||
d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */
|
||||
|
||||
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
|
||||
((mode & PTF_WR)? PF_WRITE: 0); /* set page fail word */
|
||||
|
||||
/* First phase - evaluate section pointers - returns a ptr to a page map
|
||||
As a single section machine, the KS10 short circuits this part of the
|
||||
process. In particular, the indirect pointer calculation assumes that
|
||||
the section table index will be 0. It adds the full pointer (not just
|
||||
the right half) to the SPT base. If the section index is > 0, the
|
||||
result is a physical memory address > 256KW. Depending on the size of
|
||||
memory, the SPT fetch may or may not generate a NXM page fail. The
|
||||
KS10 then ignores the section table index in fetching the next pointer.
|
||||
|
||||
The KS10 KL10 memory management diagnostic (dskec.sav) tests for this
|
||||
behavior with a section index of 3. However, this would be a legal
|
||||
physical address in a system with 1MW. Accordingly, the simulator
|
||||
special cases non-zero section indices (which can't work in any case)
|
||||
to generate the right behavior for the diagnostic.
|
||||
*/
|
||||
|
||||
vpn = PAG_GETVPN (ea); /* get virt page num */
|
||||
pa = (tbl == uptbl)? upta + UPT_T20_SCTN: epta + EPT_T20_SCTN;
|
||||
READPT (ptr, pa & PAMASK); /* get section 0 ptr */
|
||||
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval section ptrs */
|
||||
acc = acc & ptr; /* cascade acc bits */
|
||||
switch (T20_GETTYP (ptr)) { /* case on ptr type */
|
||||
case T20_NOA: /* no access */
|
||||
default: /* undefined type */
|
||||
PAGE_FAIL_TRAP; /* page fail */
|
||||
case T20_IMM: /* immediate */
|
||||
stop = TRUE; /* exit */
|
||||
break;
|
||||
case T20_SHR: /* shared */
|
||||
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
|
||||
READPT (ptr, pa & PAMASK); /* get SPT entry */
|
||||
stop = TRUE; /* exit */
|
||||
break;
|
||||
case T20_IND: /* indirect */
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
pmi = T20_GETPMI (ptr); /* get sect tbl idx */
|
||||
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
|
||||
if (pmi) { /* for dskec */
|
||||
pag_nxm ((pmi << 18) | pa, REF_P, PF_OK);
|
||||
PAGE_FAIL_TRAP; }
|
||||
READPT (ptr, pa & PAMASK); /* get SPT entry */
|
||||
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; }
|
||||
pa = PAG_PTEPA (ptr, pmi); /* index off page */
|
||||
READPT (ptr, pa & PAMASK); /* get pointer */
|
||||
break; /* continue in loop */
|
||||
} /* end case */
|
||||
} /* end for */
|
||||
|
||||
/* Second phase - found page map ptr, evaluate page pointers */
|
||||
|
||||
pa = PAG_PTEPA (ptr, vpn); /* get ptbl address */
|
||||
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval page ptrs */
|
||||
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-res? */
|
||||
if (cst) { /* cst really there? */
|
||||
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
|
||||
READPT (cste, csta); /* get CST entry */
|
||||
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
|
||||
cste = (cste & cstm) | pur; /* update entry */
|
||||
WriteP (csta, cste); } /* rewrite */
|
||||
READPT (ptr, pa & PAMASK); /* get pointer */
|
||||
acc = acc & ptr; /* cascade acc bits */
|
||||
switch (T20_GETTYP (ptr)) { /* case on ptr type */
|
||||
case T20_NOA: /* no access */
|
||||
default: /* undefined type */
|
||||
PAGE_FAIL_TRAP; /* page fail */
|
||||
case T20_IMM: /* immediate */
|
||||
stop = TRUE; /* exit */
|
||||
break;
|
||||
case T20_SHR: /* shared */
|
||||
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
|
||||
READPT (ptr, pa & PAMASK); /* get SPT entry */
|
||||
stop = TRUE; /* exit */
|
||||
break;
|
||||
case T20_IND: /* indirect */
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
pmi = T20_GETPMI (ptr); /* get section index */
|
||||
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
|
||||
READPT (ptr, pa & PAMASK); /* get SPT entry */
|
||||
pa = PAG_PTEPA (ptr, pmi); /* index off page */
|
||||
break; /* continue in loop */
|
||||
} /* end case */
|
||||
} /* end for */
|
||||
|
||||
/* Last phase - have final page pointer, check modifiability */
|
||||
|
||||
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-resident? */
|
||||
if (cst) { /* CST really there? */
|
||||
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
|
||||
READPT (cste, csta); /* get CST entry */
|
||||
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
|
||||
cste = (cste & cstm) | pur; } /* update entry */
|
||||
else cste = 0; /* no, entry = 0 */
|
||||
pager_word = pager_word | PF_T20_DN; /* set eval done */
|
||||
xpte = ((int32) ((ptr & PTE_PPMASK) << PAG_V_PN)) | PTBL_V;
|
||||
if (mode & PTF_WR) { /* write? */
|
||||
if (acc & PTE_T20_W) { /* writable? */
|
||||
xpte = xpte | PTBL_M; /* set PTE M */
|
||||
cste = cste | CST_M; } /* set CST M */
|
||||
else { PAGE_FAIL_TRAP; } } /* no, trap */
|
||||
if (cst) WriteP (csta, cste); /* write CST entry */
|
||||
if (mode & PTF_MAP) pager_word = pager_word | /* map? more in pf wd */
|
||||
((xpte & PTBL_M)? PF_T20_M: 0) | /* M, W, C bits */
|
||||
((acc & PTE_T20_W)? PF_T20_W: 0) |
|
||||
((acc & PTE_T20_C)? PF_C: 0);
|
||||
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
|
||||
return xpte;
|
||||
} /* end TOPS20 paging */
|
||||
}
|
||||
|
||||
/* Set up pointers for AC, memory, and process table access */
|
||||
|
||||
void set_dyn_ptrs (void)
|
||||
{
|
||||
int32 t;
|
||||
|
||||
if (PAGING) {
|
||||
ac_cur = &acs[UBR_GETCURAC (ubr) * AC_NUM];
|
||||
ac_prv = &acs[UBR_GETPRVAC (ubr) * AC_NUM];
|
||||
if (TSTF (F_USR)) ptbl_cur = ptbl_prv = &uptbl[0];
|
||||
else { ptbl_cur = &eptbl[0];
|
||||
ptbl_prv = TSTF (F_UIO)? &uptbl[0]: &eptbl[0]; } }
|
||||
else { ac_cur = ac_prv = &acs[0];
|
||||
ptbl_cur = ptbl_prv = &physptbl[0]; }
|
||||
t = EBR_GETEBR (ebr);
|
||||
epta = t << PAG_V_PN;
|
||||
if (ITS) upta = (int32) ubr & PAMASK;
|
||||
else { t = UBR_GETUBR (ubr);
|
||||
upta = t << PAG_V_PN; }
|
||||
return;
|
||||
}
|
||||
|
||||
/* MAP instruction, TOPS-10 and TOPS-20 only
|
||||
|
||||
According to the KS-10 ucode, map with paging disabled sets
|
||||
"accessible, writeable, software", regardless of whether
|
||||
TOPS-10 or TOPS-20 paging is implemented
|
||||
*/
|
||||
|
||||
d10 map (a10 ea, int32 prv)
|
||||
{
|
||||
int32 xpte;
|
||||
d10 val = (TSTF (F_USR)? PF_USER: 0);
|
||||
|
||||
if (!PAGING) return (val | PF_T10_A | PF_T10_W | PF_T10_S | ea);
|
||||
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_MAP); /* get exp pte */
|
||||
if (xpte) val = (pager_word & ~PAMASK) | PAG_XPTEPA (xpte, ea);
|
||||
else { if (pager_word & PF_HARD) val = pager_word; /* hard error */
|
||||
else val = val | PF_VIRT | ea; } /* inaccessible */
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Mapping routine for console */
|
||||
|
||||
a10 conmap (a10 ea, int32 mode, int32 sw)
|
||||
{
|
||||
int32 xpte, *tbl;
|
||||
|
||||
if (!PAGING) return ea;
|
||||
set_dyn_ptrs (); /* in case changed */
|
||||
if (sw & SWMASK ('E')) tbl = eptbl;
|
||||
else if (sw & SWMASK ('U')) tbl = uptbl;
|
||||
else tbl = ptbl_cur;
|
||||
xpte = ptbl_fill (ea, tbl, mode);
|
||||
if (xpte) return PAG_XPTEPA (xpte, ea);
|
||||
else return MAXMEMSIZE;
|
||||
}
|
||||
|
||||
/* Common pager instructions */
|
||||
|
||||
t_bool clrpt (a10 ea, int32 prv)
|
||||
{
|
||||
int32 vpn = PAG_GETVPN (ea); /* get page num */
|
||||
|
||||
if (ITS) { /* ITS? */
|
||||
uptbl[vpn & ~1] = 0; /* clear double size */
|
||||
uptbl[vpn | 1] = 0; /* entries in */
|
||||
eptbl[vpn & ~1] = 0; /* both page tables */
|
||||
eptbl[vpn | 1] = 0; }
|
||||
else { uptbl[vpn] = 0; /* clear entries in */
|
||||
eptbl[vpn] = 0; } /* both page tables */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrebr (a10 ea, int32 prv)
|
||||
{
|
||||
ebr = ea & EBR_MASK; /* store EBR */
|
||||
pag_reset (&pag_dev); /* clear page tables */
|
||||
set_dyn_ptrs (); /* set dynamic ptrs */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdebr (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, (ebr & EBR_MASK), prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrubr (a10 ea, int32 prv)
|
||||
{
|
||||
d10 val = Read (ea, prv);
|
||||
d10 ubr_mask = (ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */
|
||||
|
||||
if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */
|
||||
else val = val & ~UBR_ACBMASK; /* no, keep old val */
|
||||
if (val & UBR_SETUBR) { /* set UBR? */
|
||||
ubr = ubr & ~ubr_mask;
|
||||
pag_reset (&pag_dev); } /* yes, clr pg tbls */
|
||||
else val = val & ~ubr_mask; /* no, keep old val */
|
||||
ubr = (ubr | val) & (UBR_ACBMASK | ubr_mask);
|
||||
set_dyn_ptrs ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdubr (a10 ea, int32 prv)
|
||||
{
|
||||
ubr = ubr & (UBR_ACBMASK | (ITS? PAMASK: UBR_UBRMASK));
|
||||
Write (ea, UBRWORD, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrhsb (a10 ea, int32 prv)
|
||||
{
|
||||
hsb = Read (ea, prv) & PAMASK;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdhsb (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, hsb, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* TOPS20 pager instructions */
|
||||
|
||||
t_bool wrspb (a10 ea, int32 prv)
|
||||
{
|
||||
spt = Read (ea, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdspb (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, spt, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrcsb (a10 ea, int32 prv)
|
||||
{
|
||||
cst = Read (ea, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdcsb (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, cst, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrpur (a10 ea, int32 prv)
|
||||
{
|
||||
pur = Read (ea, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdpur (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, pur, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrcstm (a10 ea, int32 prv)
|
||||
{
|
||||
cstm = Read (ea, prv);
|
||||
if ((cpu_unit.flags & UNIT_T20V41) && (ea == 040127))
|
||||
cstm = 0770000000000;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdcstm (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, cstm, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* ITS pager instructions
|
||||
The KS10 does not implement the JPC option.
|
||||
*/
|
||||
|
||||
t_bool clrcsh (a10 ea, int32 prv)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool ldbr1 (a10 ea, int32 prv)
|
||||
{
|
||||
dbr1 = ea;
|
||||
pag_reset (&pag_dev);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool sdbr1 (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, dbr1, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool ldbr2 (a10 ea, int32 prv)
|
||||
{
|
||||
dbr2 = ea;
|
||||
pag_reset (&pag_dev);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool sdbr2 (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, dbr2, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool ldbr3 (a10 ea, int32 prv)
|
||||
{
|
||||
dbr3 = ea;
|
||||
pag_reset (&pag_dev);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool sdbr3 (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, dbr3, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool ldbr4 (a10 ea, int32 prv)
|
||||
{
|
||||
dbr4 = ea;
|
||||
pag_reset (&pag_dev);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool sdbr4 (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, dbr4, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrpcst (a10 ea, int32 prv)
|
||||
{
|
||||
pcst = Read (ea, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdpcst (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, pcst, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool lpmr (a10 ea, int32 prv)
|
||||
{
|
||||
d10 val;
|
||||
|
||||
val = Read (ADDA (ea, 2), prv);
|
||||
dbr1 = (a10) (Read (ea, prv) & AMASK);
|
||||
dbr2 = (a10) (Read (ADDA (ea, 1), prv) & AMASK);
|
||||
quant = val;
|
||||
pag_reset (&pag_dev);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool spm (a10 ea, int32 prv)
|
||||
{
|
||||
|
||||
ReadM (ADDA (ea, 2), prv);
|
||||
Write (ea, dbr1, prv);
|
||||
Write (ADDA (ea, 1), dbr2, prv);
|
||||
Write (ADDA (ea, 2), quant, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 tbln = uptr - pag_unit;
|
||||
|
||||
if (addr >= PTBL_MEMSIZE) return SCPE_NXM;
|
||||
*vptr = tbln? uptbl[addr]: eptbl[addr];;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 tbln = uptr - pag_unit;
|
||||
|
||||
if (addr >= PTBL_MEMSIZE) return SCPE_NXM;
|
||||
if (tbln) uptbl[addr] = (int32) val & PTBL_MASK;
|
||||
else eptbl[addr] = (int32) val & PTBL_MASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat pag_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < PTBL_MEMSIZE; i++) {
|
||||
eptbl[i] = uptbl[i] = 0;
|
||||
physptbl[i] = (i << PAG_V_PN) + PTBL_M + PTBL_V; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
284
PDP10/pdp10_pt.c
Normal file
284
PDP10/pdp10_pt.c
Normal file
@@ -0,0 +1,284 @@
|
||||
/* pdp10_pt.c: PDP-10 Unibus paper tape reader/punch simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
ptr paper tape reader
|
||||
ptp paper tape punch
|
||||
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
07-Sep-01 RMS Revised disable mechanism
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
|
||||
#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */
|
||||
#define PTRCSR_RW (CSR_IE)
|
||||
#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */
|
||||
#define PTPCSR_RW (CSR_IE)
|
||||
|
||||
extern int32 int_req;
|
||||
int32 ptr_csr = 0; /* control/status */
|
||||
int32 ptr_stopioe = 0; /* stop on error */
|
||||
int32 ptp_csr = 0; /* control/status */
|
||||
int32 ptp_stopioe = 0; /* stop on error */
|
||||
int32 pt_enb = 0; /* device enable */
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
t_stat ptr_attach (UNIT *uptr, char *ptr);
|
||||
t_stat ptr_detach (UNIT *uptr);
|
||||
t_stat ptp_attach (UNIT *uptr, char *ptr);
|
||||
t_stat ptp_detach (UNIT *uptr);
|
||||
|
||||
/* PTR data structures
|
||||
|
||||
ptr_dev PTR device descriptor
|
||||
ptr_unit PTR unit descriptor
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
UNIT ptr_unit = {
|
||||
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
|
||||
SERIAL_IN_WAIT };
|
||||
|
||||
REG ptr_reg[] = {
|
||||
{ ORDATA (CSR, ptr_csr, 16) },
|
||||
{ ORDATA (BUF, ptr_unit.buf, 8) },
|
||||
{ FLDATA (INT, int_req, INT_V_PTR) },
|
||||
{ FLDATA (ERR, ptr_csr, CSR_V_ERR) },
|
||||
{ FLDATA (BUSY, ptr_csr, CSR_V_BUSY) },
|
||||
{ FLDATA (DONE, ptr_csr, CSR_V_DONE) },
|
||||
{ FLDATA (IE, ptr_csr, CSR_V_IE) },
|
||||
{ DRDATA (POS, ptr_unit.pos, 31), PV_LEFT },
|
||||
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
|
||||
{ FLDATA (*DEVENB, pt_enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
NULL, &ptr_attach, &ptr_detach };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
ptp_dev PTP device descriptor
|
||||
ptp_unit PTP unit descriptor
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ ORDATA (BUF, ptp_unit.buf, 8) },
|
||||
{ ORDATA (CSR, ptp_csr, 16) },
|
||||
{ FLDATA (INT, int_req, INT_V_PTP) },
|
||||
{ FLDATA (ERR, ptp_csr, CSR_V_ERR) },
|
||||
{ FLDATA (DONE, ptp_csr, CSR_V_DONE) },
|
||||
{ FLDATA (IE, ptp_csr, CSR_V_IE) },
|
||||
{ DRDATA (POS, ptp_unit.pos, 31), PV_LEFT },
|
||||
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
||||
{ FLDATA (*DEVENB, pt_enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, &ptp_attach, &ptp_detach };
|
||||
|
||||
/* Standard I/O dispatch routine, I/O addresses 17777550-17777557
|
||||
|
||||
17777550 ptr CSR
|
||||
17777552 ptr buffer
|
||||
17777554 ptp CSR
|
||||
17777556 ptp buffer
|
||||
|
||||
Note: Word access routines filter out odd addresses. Thus,
|
||||
an odd address implies an (odd) byte access.
|
||||
*/
|
||||
|
||||
t_stat pt_rd (int32 *data, int32 PA, int32 access)
|
||||
{
|
||||
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
|
||||
case 0: /* ptr csr */
|
||||
*data = ptr_csr & PTRCSR_IMP;
|
||||
return SCPE_OK;
|
||||
case 1: /* ptr buf */
|
||||
ptr_csr = ptr_csr & ~CSR_DONE;
|
||||
int_req = int_req & ~INT_PTR;
|
||||
*data = ptr_unit.buf & 0377;
|
||||
return SCPE_OK;
|
||||
case 2: /* ptp csr */
|
||||
*data = ptp_csr & PTPCSR_IMP;
|
||||
return SCPE_OK;
|
||||
case 3: /* ptp buf */
|
||||
*data = ptp_unit.buf;
|
||||
return SCPE_OK; }
|
||||
return SCPE_NXM; /* can't get here */
|
||||
}
|
||||
|
||||
t_stat pt_wr (int32 data, int32 PA, int32 access)
|
||||
{
|
||||
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
|
||||
case 0: /* ptr csr */
|
||||
if (PA & 1) return SCPE_OK;
|
||||
if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTR;
|
||||
else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE)))
|
||||
int_req = int_req | INT_PTR;
|
||||
if (data & CSR_GO) {
|
||||
ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY;
|
||||
int_req = int_req & ~INT_PTR;
|
||||
if (ptr_unit.flags & UNIT_ATT) /* data to read? */
|
||||
sim_activate (&ptr_unit, ptr_unit.wait);
|
||||
else sim_activate (&ptr_unit, 0); } /* error if not */
|
||||
ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW);
|
||||
return SCPE_OK;
|
||||
case 1: /* ptr buf */
|
||||
return SCPE_OK;
|
||||
case 2: /* ptp csr */
|
||||
if (PA & 1) return SCPE_OK;
|
||||
if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTP;
|
||||
else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE)))
|
||||
int_req = int_req | INT_PTP;
|
||||
ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW);
|
||||
return SCPE_OK;
|
||||
case 3: /* ptp buf */
|
||||
if ((PA & 1) == 0) ptp_unit.buf = data & 0377;
|
||||
ptp_csr = ptp_csr & ~CSR_DONE;
|
||||
int_req = int_req & ~INT_PTP;
|
||||
if (ptp_unit.flags & UNIT_ATT) /* file to write? */
|
||||
sim_activate (&ptp_unit, ptp_unit.wait);
|
||||
else sim_activate (&ptp_unit, 0); /* error if not */
|
||||
return SCPE_OK; } /* end switch PA */
|
||||
return SCPE_NXM; /* can't get here */
|
||||
}
|
||||
|
||||
/* Paper tape reader routines
|
||||
|
||||
ptr_svc process event (character ready)
|
||||
ptr_reset process reset
|
||||
ptr_attach process attach
|
||||
ptr_detach process detach
|
||||
*/
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY;
|
||||
if (ptr_csr & CSR_IE) int_req = int_req | INT_PTR;
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0)
|
||||
return IORETURN (ptr_stopioe, SCPE_UNATT);
|
||||
if ((temp = getc (ptr_unit.fileref)) == EOF) {
|
||||
if (feof (ptr_unit.fileref)) {
|
||||
if (ptr_stopioe) printf ("PTR end of file\n");
|
||||
else return SCPE_OK; }
|
||||
else perror ("PTR I/O error");
|
||||
clearerr (ptr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR;
|
||||
ptr_unit.buf = temp & 0377;
|
||||
ptr_unit.pos = ptr_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
ptr_unit.buf = 0;
|
||||
ptr_csr = 0;
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR;
|
||||
int_req = int_req & ~INT_PTR;
|
||||
sim_cancel (&ptr_unit);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ptr_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat reason;
|
||||
|
||||
reason = attach_unit (uptr, cptr);
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR;
|
||||
else ptr_csr = ptr_csr & ~CSR_ERR;
|
||||
return reason;
|
||||
}
|
||||
|
||||
t_stat ptr_detach (UNIT *uptr)
|
||||
{
|
||||
ptr_csr = ptr_csr | CSR_ERR;
|
||||
return detach_unit (uptr);
|
||||
}
|
||||
|
||||
/* Paper tape punch routines
|
||||
|
||||
ptp_svc process event (character punched)
|
||||
ptp_reset process reset
|
||||
ptp_attach process attach
|
||||
ptp_detach process detach
|
||||
*/
|
||||
|
||||
t_stat ptp_svc (UNIT *uptr)
|
||||
{
|
||||
ptp_csr = ptp_csr | CSR_ERR | CSR_DONE;
|
||||
if (ptp_csr & CSR_IE) int_req = int_req | INT_PTP;
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0)
|
||||
return IORETURN (ptp_stopioe, SCPE_UNATT);
|
||||
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) {
|
||||
perror ("PTP I/O error");
|
||||
clearerr (ptp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
ptp_csr = ptp_csr & ~CSR_ERR;
|
||||
ptp_unit.pos = ptp_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
ptp_unit.buf = 0;
|
||||
ptp_csr = CSR_DONE;
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR;
|
||||
int_req = int_req & ~INT_PTP;
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ptp_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat reason;
|
||||
|
||||
reason = attach_unit (uptr, cptr);
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR;
|
||||
else ptp_csr = ptp_csr & ~CSR_ERR;
|
||||
return reason;
|
||||
}
|
||||
|
||||
t_stat ptp_detach (UNIT *uptr)
|
||||
{
|
||||
ptp_csr = ptp_csr | CSR_ERR;
|
||||
return detach_unit (uptr);
|
||||
}
|
||||
1121
PDP10/pdp10_rp.c
Normal file
1121
PDP10/pdp10_rp.c
Normal file
File diff suppressed because it is too large
Load Diff
792
PDP10/pdp10_sys.c
Normal file
792
PDP10/pdp10_sys.c
Normal file
@@ -0,0 +1,792 @@
|
||||
/* pdp10_sys.c: PDP-10 simulator interface
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
17-Sep-01 RMS Removed multiconsole support
|
||||
25-Aug-01 RMS Enabled DZ11
|
||||
27-May-01 RMS Added multiconsole support
|
||||
29-Apr-01 RMS Fixed format for RDPCST, WRPCST
|
||||
Added CLRCSH for ITS
|
||||
03-Apr-01 RMS Added support for loading EXE files
|
||||
19-Mar-01 RMS Added support for loading SAV files
|
||||
30-Oct-00 RMS Added support for examine to file
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev, pag_dev;
|
||||
extern DEVICE tim_dev, fe_dev, uba_dev;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE rp_dev, tu_dev;
|
||||
extern DEVICE dz_dev;
|
||||
extern DEVICE lp20_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern d10 *M;
|
||||
extern a10 saved_PC;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words for examine
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "PDP-10";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 1;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&pag_dev,
|
||||
&tim_dev,
|
||||
&fe_dev,
|
||||
&uba_dev,
|
||||
&ptr_dev,
|
||||
&ptp_dev,
|
||||
&lp20_dev,
|
||||
&dz_dev,
|
||||
&rp_dev,
|
||||
&tu_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Illegal instruction",
|
||||
"Illegal interrupt instruction",
|
||||
"Paging error in interrupt",
|
||||
"Zero vector table",
|
||||
"NXM on UPT/EPT reference",
|
||||
"Nested indirect address limit exceeded",
|
||||
"Nested XCT limit exceeded",
|
||||
"Invalid I/O controller",
|
||||
"Invalid magtape record length",
|
||||
"Address stop",
|
||||
"Panic stop" };
|
||||
|
||||
/* Binary loader, supports RIM10, SAV, EXE */
|
||||
|
||||
#define FMT_R 1 /* RIM10 */
|
||||
#define FMT_S 2 /* SAV */
|
||||
#define FMT_E 3 /* EXE */
|
||||
|
||||
#define EXE_DIR 01776 /* EXE directory */
|
||||
#define EXE_VEC 01775 /* EXE entry vec */
|
||||
#define EXE_PDV 01774 /* EXE ignored */
|
||||
#define EXE_END 01777 /* EXE end
|
||||
|
||||
/* RIM10 loader
|
||||
|
||||
RIM10 format is a binary paper tape format (all data frames
|
||||
are 200 or greater). It consists of blocks containing
|
||||
|
||||
-count,,origin-1
|
||||
word
|
||||
:
|
||||
word
|
||||
checksum (includes IOWD)
|
||||
:
|
||||
JRST start
|
||||
*/
|
||||
|
||||
d10 getrimw (FILE *fileref)
|
||||
{
|
||||
int32 i, tmp;
|
||||
d10 word;
|
||||
|
||||
word = 0;
|
||||
for (i = 0; i < 6;) {
|
||||
if ((tmp = getc (fileref)) == EOF) return -1;
|
||||
if (tmp & 0200) {
|
||||
word = (word << 6) | ((d10) tmp & 077);
|
||||
i++; } }
|
||||
return word;
|
||||
}
|
||||
|
||||
t_stat load_rim (FILE *fileref)
|
||||
{
|
||||
d10 count, cksm, data;
|
||||
a10 pa;
|
||||
int32 op;
|
||||
|
||||
for ( ;; ) { /* loop until JRST */
|
||||
count = cksm = getrimw (fileref); /* get header */
|
||||
if (count < 0) return SCPE_FMT; /* read err? */
|
||||
if (TSTS (count)) { /* hdr = IOWD? */
|
||||
for ( ; TSTS (count); count = AOB (count)) {
|
||||
data = getrimw (fileref); /* get data wd */
|
||||
if (data < 0) return SCPE_FMT;
|
||||
cksm = cksm + data; /* add to cksm */
|
||||
pa = ((a10) count + 1) & AMASK; /* store */
|
||||
M[pa] = data; } /* end for */
|
||||
data = getrimw (fileref); /* get cksm */
|
||||
if (data < 0) return SCPE_FMT;
|
||||
if ((cksm + data) & DMASK) return SCPE_CSUM; /* test cksm */
|
||||
} /* end if count */
|
||||
else { op = GET_OP (count); /* not IOWD */
|
||||
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
|
||||
saved_PC = (a10) count & AMASK; /* set PC */
|
||||
return SCPE_OK; } /* end else */
|
||||
} /* end for */
|
||||
return SCPE_FMT;
|
||||
}
|
||||
|
||||
/* SAV file loader
|
||||
|
||||
SAV format is a disk file format (36b words). It consists of
|
||||
blocks containing:
|
||||
|
||||
-count,,origin-1
|
||||
word
|
||||
:
|
||||
word
|
||||
:
|
||||
JRST start
|
||||
*/
|
||||
|
||||
t_stat load_sav (FILE *fileref)
|
||||
{
|
||||
d10 count, data;
|
||||
a10 pa;
|
||||
int32 wc, op;
|
||||
|
||||
for ( ;; ) { /* loop */
|
||||
wc = fxread (&count, sizeof (d10), 1, fileref); /* read IOWD */
|
||||
if (wc == 0) return SCPE_OK; /* done? */
|
||||
if (TSTS (count)) { /* IOWD? */
|
||||
for ( ; TSTS (count); count = AOB (count)) {
|
||||
wc = fxread (&data, sizeof (d10), 1, fileref);
|
||||
if (wc == 0) return SCPE_FMT;
|
||||
pa = ((a10) count + 1) & AMASK; /* store data */
|
||||
M[pa] = data; } /* end for */
|
||||
} /* end if count*/
|
||||
else { op = GET_OP (count); /* not IOWD */
|
||||
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
|
||||
saved_PC = (a10) count & AMASK; /* set PC */
|
||||
return SCPE_OK; } /* end else */
|
||||
} /* end for */
|
||||
return SCPE_FMT;
|
||||
}
|
||||
|
||||
/* EXE file loader
|
||||
|
||||
EXE format is a disk file format (36b words). It consists of
|
||||
blocks containing:
|
||||
|
||||
block type,,total words = n
|
||||
n - 1 data words
|
||||
|
||||
Block types are
|
||||
|
||||
EXE_DIR (1776) directory
|
||||
EXE_VEC (1775) entry vector
|
||||
EXE_PDV (1774) optional blocks
|
||||
EXE_END (1777) end block
|
||||
|
||||
The directory blocks are the most important and contain doubleword
|
||||
page loading information:
|
||||
|
||||
word0<0:8> = flags
|
||||
<9:35> = page in file (0 if 0 page)
|
||||
word1<0:8> = repeat count - 1
|
||||
<9:35> = page in memory
|
||||
*/
|
||||
|
||||
#define DIRSIZ (2 * PAG_SIZE)
|
||||
|
||||
t_stat load_exe (FILE *fileref)
|
||||
{
|
||||
d10 data, dirbuf[DIRSIZ], pagbuf[PAG_SIZE], entbuf[2];
|
||||
int32 ndir, entvec, i, j, k, cont, bsz, bty, rpt, wc;
|
||||
int32 fpage, mpage;
|
||||
a10 ma;
|
||||
|
||||
ndir = entvec = 0; /* no dir, entvec */
|
||||
cont = 1;
|
||||
do { wc = fxread (&data, sizeof (d10), 1, fileref); /* read blk hdr */
|
||||
if (wc == 0) return SCPE_FMT; /* error? */
|
||||
bsz = (int32) ((data & RMASK) - 1); /* get count */
|
||||
if (bsz <= 0) return SCPE_FMT; /* zero? */
|
||||
bty = (int32) LRZ (data); /* get type */
|
||||
switch (bty) { /* case type */
|
||||
case EXE_DIR: /* directory */
|
||||
if (ndir) return SCPE_FMT; /* got one */
|
||||
ndir = fxread (dirbuf, sizeof (d10), bsz, fileref);
|
||||
if (ndir < bsz) return SCPE_FMT; /* error */
|
||||
break;
|
||||
case EXE_PDV: /* ??? */
|
||||
fseek (fileref, bsz * sizeof (d10), SEEK_CUR);
|
||||
break;
|
||||
case EXE_VEC: /* entry vec */
|
||||
if (bsz != 2) return SCPE_FMT; /* must be 2 wds */
|
||||
entvec = fxread (entbuf, sizeof (d10), bsz, fileref);
|
||||
if (entvec < 2) return SCPE_FMT; /* error? */
|
||||
cont = 0; /* stop */
|
||||
break;
|
||||
case EXE_END: /* end */
|
||||
if (bsz != 0) return SCPE_FMT; /* must be hdr */
|
||||
cont = 0; /* stop */
|
||||
break;
|
||||
default:
|
||||
return SCPE_FMT; } /* end switch */
|
||||
} /* end do */
|
||||
while (cont);
|
||||
|
||||
for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */
|
||||
fpage = (int32) (dirbuf[i] & RMASK); /* file page */
|
||||
mpage = (int32) (dirbuf[i + 1] & RMASK); /* memory page */
|
||||
rpt = (int32) ((dirbuf[i + 1] >> 27) + 1); /* repeat count */
|
||||
for (j = 0; j < rpt; j++, mpage++) { /* loop thru rpts */
|
||||
if (fpage) { /* file pages? */
|
||||
fseek (fileref, (fpage << PAG_V_PN) * sizeof (d10), SEEK_SET);
|
||||
wc = fxread (pagbuf, sizeof (d10), PAG_SIZE, fileref);
|
||||
if (wc < PAG_SIZE) return SCPE_FMT;
|
||||
fpage++; }
|
||||
ma = mpage << PAG_V_PN; /* mem addr */
|
||||
for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */
|
||||
if (MEM_ADDR_NXM (ma)) return SCPE_NXM;
|
||||
M[ma] = fpage? (pagbuf[k] & DMASK): 0;
|
||||
} /* end copy */
|
||||
} /* end rpt */
|
||||
} /* end directory */
|
||||
if (entvec && entbuf[1])
|
||||
saved_PC = (int32) entbuf[1] & RMASK; /* start addr */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Master loader */
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
d10 data;
|
||||
int32 wc, fmt;
|
||||
extern int32 sim_switches;
|
||||
extern t_bool match_ext (char *fnam, char *ext);
|
||||
|
||||
fmt = 0; /* no fmt */
|
||||
if (sim_switches & SWMASK ('R')) fmt = FMT_R; /* -r? */
|
||||
else if (sim_switches & SWMASK ('S')) fmt = FMT_S; /* -s? */
|
||||
else if (sim_switches & SWMASK ('E')) fmt = FMT_E; /* -e? */
|
||||
else if (match_ext (fnam, "RIM")) fmt = FMT_R; /* .RIM? */
|
||||
else if (match_ext (fnam, "SAV")) fmt = FMT_S; /* .SAV? */
|
||||
else if (match_ext (fnam, "EXE")) fmt = FMT_E; /* .EXE? */
|
||||
else { wc = fxread (&data, sizeof (d10), 1, fileref); /* read hdr */
|
||||
if (wc == 0) return SCPE_FMT; /* error? */
|
||||
if (LRZ (data) == EXE_DIR) fmt = FMT_E; /* EXE magic? */
|
||||
else if (TSTS (data)) fmt = FMT_S; /* SAV magic? */
|
||||
fseek (fileref, 0, SEEK_SET); } /* rewind */
|
||||
switch (fmt) { /* case fmt */
|
||||
case FMT_R: /* RIM */
|
||||
return load_rim (fileref);
|
||||
case FMT_S: /* SAV */
|
||||
return load_sav (fileref);
|
||||
case FMT_E: /* EXE */
|
||||
return load_exe (fileref); }
|
||||
printf ("Can't determine load file format\n");
|
||||
return SCPE_FMT;
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
|
||||
#define I_V_FL 39 /* inst class */
|
||||
#define I_M_FL 03 /* class mask */
|
||||
#define I_ITS 004000000000000 /* ITS flag */
|
||||
#define I_AC 000000000000000 /* AC, address */
|
||||
#define I_OP 010000000000000 /* address only */
|
||||
#define I_IO 020000000000000 /* classic I/O */
|
||||
#define I_V_AC 00
|
||||
#define I_V_OP 01
|
||||
#define I_V_IO 02
|
||||
|
||||
static const d10 masks[] = {
|
||||
0777000000000, 0777740000000,
|
||||
0700340000000, 0777777777777 };
|
||||
|
||||
static const char *opcode[] = {
|
||||
"XCTR", "XCTI", /* ITS only */
|
||||
"IORDI", "IORDQ", "IORD", "IOWR", "IOWRI", "IOWRQ",
|
||||
"IORDBI", "IORDBQ", "IORDB", "IOWRB", "IOWRBI", "IOWRBQ",
|
||||
"CLRCSH", "RDPCST", "WRPCST",
|
||||
"SDBR1", "SDBR2", "SDBR3", "SDBR4", "SPM",
|
||||
"LDBR1", "LDBR2", "LDBR3", "LDBR4", "LPMR",
|
||||
|
||||
"PORTAL", "JRSTF", "HALT", /* AC defines op */
|
||||
"XJRSTF", "XJEN", "XPCW",
|
||||
"JEN", "SFM", "XJRST", "IBP",
|
||||
"JFOV", "JCRY1", "JCRY0", "JCRY", "JOV",
|
||||
|
||||
"APRID", "WRAPR", "RDAPR", "WRPI", "RDPI", "RDUBR", "CLRPT", "WRUBR",
|
||||
"WREBR", "RDEBR",
|
||||
"RDSPB", "RDCSB", "RDPUR", "RDCSTM", "RDTIM", "RDINT", "RDHSB",
|
||||
"WRSPB", "WRCSB", "WRPUR", "WRCSTM", "WRTIM", "WRINT", "WRHSB",
|
||||
|
||||
"LUUO01", "LUUO02", "LUUO03", "LUUO04", "LUUO05", "LUUO06", "LUUO07",
|
||||
"LUUO10", "LUUO11", "LUUO12", "LUUO13", "LUUO14", "LUUO15", "LUUO16", "LUUO17",
|
||||
"LUUO20", "LUUO21", "LUUO22", "LUUO23", "LUUO24", "LUUO25", "LUUO26", "LUUO27",
|
||||
"LUUO30", "LUUO31", "LUUO32", "LUUO33", "LUUO34", "LUUO35", "LUUO36", "LUUO37",
|
||||
"MUUO40", "MUUO41", "MUUO42", "MUUO43", "MUUO44", "MUUO45", "MUUO46", "MUUO47",
|
||||
"MUUO50", "MUUO51", "MUUO52", "MUUO53", "MUUO54", "MUUO55", "MUUO56", "MUUO57",
|
||||
"MUUO60", "MUUO61", "MUUO62", "MUUO63", "MUUO64", "MUUO65", "MUUO66", "MUUO67",
|
||||
"MUUO70", "MUUO71", "MUUO72", "MUUO73", "MUUO74", "MUUO75", "MUUO76", "MUUO77",
|
||||
|
||||
"UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ",
|
||||
"DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV",
|
||||
"DMOVE", "DMOVN", "FIX", "EXTEND", "DMOVEM", "DMOVNM", "FIXR", "FLTR",
|
||||
"UFA", "DFN", "FSC", "ADJBP", "ILDB", "LDB", "IDPB", "DPB",
|
||||
"FAD", "FADL", "FADM", "FADB", "FADR", "FADRL", "FADRM", "FADRB",
|
||||
"FSB", "FSBL", "FSBM", "FSBB", "FSBR", "FSBRL", "FSBRM", "FSBRB",
|
||||
"FMP", "FMPL", "FMPM", "FMPB", "FMPR", "FMPRL", "FMPRM", "FMPRB",
|
||||
"FDV", "FDVL", "FDVM", "FDVB", "FDVR", "FDVRL", "FDVRM", "FDVRB",
|
||||
|
||||
"MOVE", "MOVEI", "MOVEM", "MOVES", "MOVS", "MOVSI", "MOVSM", "MOVSS",
|
||||
"MOVN", "MOVNI", "MOVNM", "MOVNS", "MOVM", "MOVMI", "MOVMM", "MOVMS",
|
||||
"IMUL", "IMULI", "IMULM", "IMULB", "MUL", "MULI", "MULM", "MULB",
|
||||
"IDIV", "IDIVI", "IDIVM", "IDIVB", "DIV", "DIVI", "DIVM", "DIVB",
|
||||
"ASH", "ROT", "LSH", "JFFO", "ASHC", "ROTC", "LSHC", "CIRC",
|
||||
"EXCH", "BLT", "AOBJP", "AOBJN", "JRST", "JFCL", "XCT", "MAP",
|
||||
"PUSHJ", "PUSH", "POP", "POPJ", "JSR", "JSP", "JSA", "JRA",
|
||||
"ADD", "ADDI", "ADDM", "ADDB", "SUB", "SUBI", "SUBM", "SUBB",
|
||||
|
||||
"CAI", "CAIL", "CAIE", "CAILE", "CAIA", "CAIGE", "CAIN", "CAIG",
|
||||
"CAM", "CAML", "CAME", "CAMLE", "CAMA", "CAMGE", "CAMN", "CAMG",
|
||||
"JUMP", "JUMPL", "JUMPE", "JUMPLE", "JUMPA", "JUMPGE", "JUMPN", "JUMPG",
|
||||
"SKIP", "SKIPL", "SKIPE", "SKIPLE", "SKIPA", "SKIPGE", "SKIPN", "SKIPG",
|
||||
"AOJ", "AOJL", "AOJE", "AOJLE", "AOJA", "AOJGE", "AOJN", "AOJG",
|
||||
"AOS", "AOSL", "AOSE", "AOSLE", "AOSA", "AOSGE", "AOSN", "AOSG",
|
||||
"SOJ", "SOJL", "SOJE", "SOJLE", "SOJA", "SOJGE", "SOJN", "SOJG",
|
||||
"SOS", "SOSL", "SOSE", "SOSLE", "SOSA", "SOSGE", "SOSN", "SOSG",
|
||||
|
||||
"SETZ", "SETZI", "SETZM", "SETZB", "AND", "ANDI", "ANDM", "ANDB",
|
||||
"ANDCA", "ANDCAI", "ANDCAM", "ANDCAB", "SETM", "SETMI", "SETMM", "SETMB",
|
||||
"ANDCM", "ANDCMI", "ANDCMM", "ANDCMB", "SETA", "SETAI", "SETAM", "SETAB",
|
||||
"XOR", "XORI", "XORM", "XORB", "IOR", "IORI", "IORM", "IORB",
|
||||
"ANDCB", "ANDCBI", "ANDCBM", "ANDCBB", "EQV", "EQVI", "EQVM", "EQVB",
|
||||
"SETCA", "SETCAI", "SETCAM", "SETCAB", "ORCA", "ORCAI", "ORCAM", "ORCAB",
|
||||
"SETCM", "SETCMI", "SETCMM", "SETCMB", "ORCM", "ORCMI", "ORCMM", "ORCMB",
|
||||
"ORCB", "ORCBI", "ORCBM", "ORCBB", "SETO", "SETOI", "SETOM", "SETOB",
|
||||
|
||||
"HLL", "HLLI", "HLLM", "HLLS", "HRL", "HRLI", "HRLM", "HRLS",
|
||||
"HLLZ", "HLLZI", "HLLZM", "HLLZS", "HRLZ", "HRLZI", "HRLZM", "HRLZS",
|
||||
"HLLO", "HLLOI", "HLLOM", "HLLOS", "HRLO", "HRLOI", "HRLOM", "HRLOS",
|
||||
"HLLE", "HLLEI", "HLLEM", "HLLES", "HRLE", "HRLEI", "HRLEM", "HRLES",
|
||||
"HRR", "HRRI", "HRRM", "HRRS", "HLR", "HLRI", "HLRM", "HLRS",
|
||||
"HRRZ", "HRRZI", "HRRZM", "HRRZS", "HLRZ", "HLRZI", "HLRZM", "HLRZS",
|
||||
"HRRO", "HRROI", "HRROM", "HRROS", "HLRO", "HLROI", "HLROM", "HLROS",
|
||||
"HRRE", "HRREI", "HRREM", "HRRES", "HLRE", "HLREI", "HLREM", "HLRES",
|
||||
|
||||
"TRN", "TLN", "TRNE", "TLNE", "TRNA", "TLNA", "TRNN", "TLNN",
|
||||
"TDN", "TSN", "TDNE", "TSNE", "TDNA", "TSNA", "TDNN", "TSNN",
|
||||
"TRZ", "TLZ", "TRZE", "TLZE", "TRZA", "TLZA", "TRZN", "TLZN",
|
||||
"TDZ", "TSZ", "TDZE", "TSZE", "TDZA", "TSZA", "TDZN", "TSZN",
|
||||
"TRC", "TLC", "TRCE", "TLCE", "TRCA", "TLCA", "TRCN", "TLCN",
|
||||
"TDC", "TSC", "TDCE", "TSCE", "TDCA", "TSCA", "TDCN", "TSCN",
|
||||
"TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON",
|
||||
"TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON",
|
||||
|
||||
"UMOVE", "UMOVEM", /* KS10 I/O */
|
||||
"TIOE", "TION", "RDIO", "WRIO",
|
||||
"BSIO", "BCIO", "BLTBU", "BLTUB",
|
||||
"TIOEB", "TIONB", "RDIOB", "WRIOB",
|
||||
"BSIOB", "BCIOB",
|
||||
|
||||
"BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */
|
||||
"CONO", "CONI", "CONSZ", "CONSO",
|
||||
|
||||
"CLEAR", "CLEARI", "CLEARM", "CLEARB",
|
||||
"OR", "ORI", "ORM", "ORB", "XMOVEI", "XHLLI", /* alternate ops */
|
||||
|
||||
"CMPSL", "CMPSE", "CMPSLE", /* extended ops */
|
||||
"EDIT", "CMPSGE", "CMPSN", "CMPSG",
|
||||
"CVTDBO", "CVTDBT", "CVTBDO", "CVTBDT",
|
||||
"MOVSO", "MOVST", "MOVSLJ", "MOVSRJ",
|
||||
"XBLT", "GSNGL", "GDBLE", "GDFIX",
|
||||
"GFIX", "GDFIXR", "GFIXR", "DGFLTR",
|
||||
"GFLTR", "GFSC",
|
||||
|
||||
NULL };
|
||||
|
||||
static const d10 opc_val[] = {
|
||||
0102000000000+I_AC+I_ITS, 0103000000000+I_AC+I_ITS,
|
||||
0710000000000+I_AC+I_ITS, 0711000000000+I_AC+I_ITS, 0712000000000+I_AC+I_ITS,
|
||||
0713000000000+I_AC+I_ITS, 0714000000000+I_AC+I_ITS, 0715000000000+I_AC+I_ITS,
|
||||
0720000000000+I_AC+I_ITS, 0721000000000+I_AC+I_ITS, 0722000000000+I_AC+I_ITS,
|
||||
0723000000000+I_AC+I_ITS, 0724000000000+I_AC+I_ITS, 0725000000000+I_AC+I_ITS,
|
||||
0701000000000+I_OP+I_ITS, 0701440000000+I_OP+I_ITS, 0701540000000+I_OP+I_ITS,
|
||||
0702000000000+I_OP+I_ITS, 0702040000000+I_OP+I_ITS,
|
||||
0702100000000+I_OP+I_ITS, 0702140000000+I_OP+I_ITS, 0702340000000+I_OP+I_ITS,
|
||||
0702400000000+I_OP+I_ITS, 0702440000000+I_OP+I_ITS,
|
||||
0702500000000+I_OP+I_ITS, 0702540000000+I_OP+I_ITS, 0702740000000+I_OP+I_ITS,
|
||||
|
||||
0254040000000+I_OP, 0254100000000+I_OP,
|
||||
0254200000000+I_OP, 0254240000000+I_OP, 0254300000000+I_OP, 0254340000000+I_OP,
|
||||
0254500000000+I_OP, 0254600000000+I_OP, 0254640000000+I_OP, 0133000000000+I_OP,
|
||||
0255040000000+I_OP, 0255100000000+I_OP, 0255200000000+I_OP, 0255300000000+I_OP,
|
||||
0255400000000+I_OP,
|
||||
|
||||
0700000000000+I_OP, 0700200000000+I_OP, 0700240000000+I_OP, 0700600000000+I_OP,
|
||||
0700640000000+I_OP, 0701040000000+I_OP, 0701100000000+I_OP, 0701140000000+I_OP,
|
||||
0701200000000+I_OP, 0701240000000+I_OP,
|
||||
0702000000000+I_OP, 0702040000000+I_OP, 0702100000000+I_OP, 0702140000000+I_OP,
|
||||
0702200000000+I_OP, 0702240000000+I_OP, 0702300000000+I_OP,
|
||||
0702400000000+I_OP, 0702440000000+I_OP, 0702500000000+I_OP, 0702540000000+I_OP,
|
||||
0702600000000+I_OP, 0702640000000+I_OP, 0702700000000+I_OP,
|
||||
|
||||
0001000000000+I_AC, 0002000000000+I_AC, 0003000000000+I_AC,
|
||||
0004000000000+I_AC, 0005000000000+I_AC, 0006000000000+I_AC, 0007000000000+I_AC,
|
||||
0010000000000+I_AC, 0011000000000+I_AC, 0012000000000+I_AC, 0013000000000+I_AC,
|
||||
0014000000000+I_AC, 0015000000000+I_AC, 0016000000000+I_AC, 0017000000000+I_AC,
|
||||
0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC,
|
||||
0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC,
|
||||
0030000000000+I_AC, 0031000000000+I_AC, 0032000000000+I_AC, 0033000000000+I_AC,
|
||||
0034000000000+I_AC, 0035000000000+I_AC, 0036000000000+I_AC, 0037000000000+I_AC,
|
||||
0040000000000+I_AC, 0041000000000+I_AC, 0042000000000+I_AC, 0043000000000+I_AC,
|
||||
0044000000000+I_AC, 0045000000000+I_AC, 0046000000000+I_AC, 0047000000000+I_AC,
|
||||
0050000000000+I_AC, 0051000000000+I_AC, 0052000000000+I_AC, 0053000000000+I_AC,
|
||||
0054000000000+I_AC, 0055000000000+I_AC, 0056000000000+I_AC, 0057000000000+I_AC,
|
||||
0060000000000+I_AC, 0061000000000+I_AC, 0062000000000+I_AC, 0063000000000+I_AC,
|
||||
0064000000000+I_AC, 0065000000000+I_AC, 0066000000000+I_AC, 0067000000000+I_AC,
|
||||
0070000000000+I_AC, 0071000000000+I_AC, 0072000000000+I_AC, 0073000000000+I_AC,
|
||||
0074000000000+I_AC, 0075000000000+I_AC, 0076000000000+I_AC, 0077000000000+I_AC,
|
||||
|
||||
0100000000000+I_AC, 0102000000000+I_AC, 0103000000000+I_AC,
|
||||
0104000000000+I_AC, 0105000000000+I_AC, 0106000000000+I_AC, 0107000000000+I_AC,
|
||||
0110000000000+I_AC, 0111000000000+I_AC, 0112000000000+I_AC, 0113000000000+I_AC,
|
||||
0114000000000+I_AC, 0115000000000+I_AC, 0116000000000+I_AC, 0117000000000+I_AC,
|
||||
0120000000000+I_AC, 0121000000000+I_AC, 0122000000000+I_AC, 0123000000000+I_AC,
|
||||
0124000000000+I_AC, 0125000000000+I_AC, 0126000000000+I_AC, 0127000000000+I_AC,
|
||||
0130000000000+I_AC, 0131000000000+I_AC, 0132000000000+I_AC, 0133000000000+I_AC,
|
||||
0134000000000+I_AC, 0135000000000+I_AC, 0136000000000+I_AC, 0137000000000+I_AC,
|
||||
0140000000000+I_AC, 0141000000000+I_AC, 0142000000000+I_AC, 0143000000000+I_AC,
|
||||
0144000000000+I_AC, 0145000000000+I_AC, 0146000000000+I_AC, 0147000000000+I_AC,
|
||||
0150000000000+I_AC, 0151000000000+I_AC, 0152000000000+I_AC, 0153000000000+I_AC,
|
||||
0154000000000+I_AC, 0155000000000+I_AC, 0156000000000+I_AC, 0157000000000+I_AC,
|
||||
0160000000000+I_AC, 0161000000000+I_AC, 0162000000000+I_AC, 0163000000000+I_AC,
|
||||
0164000000000+I_AC, 0165000000000+I_AC, 0166000000000+I_AC, 0167000000000+I_AC,
|
||||
0170000000000+I_AC, 0171000000000+I_AC, 0172000000000+I_AC, 0173000000000+I_AC,
|
||||
0174000000000+I_AC, 0175000000000+I_AC, 0176000000000+I_AC, 0177000000000+I_AC,
|
||||
|
||||
0200000000000+I_AC, 0201000000000+I_AC, 0202000000000+I_AC, 0203000000000+I_AC,
|
||||
0204000000000+I_AC, 0205000000000+I_AC, 0206000000000+I_AC, 0207000000000+I_AC,
|
||||
0210000000000+I_AC, 0211000000000+I_AC, 0212000000000+I_AC, 0213000000000+I_AC,
|
||||
0214000000000+I_AC, 0215000000000+I_AC, 0216000000000+I_AC, 0217000000000+I_AC,
|
||||
0220000000000+I_AC, 0221000000000+I_AC, 0222000000000+I_AC, 0223000000000+I_AC,
|
||||
0224000000000+I_AC, 0225000000000+I_AC, 0226000000000+I_AC, 0227000000000+I_AC,
|
||||
0230000000000+I_AC, 0231000000000+I_AC, 0232000000000+I_AC, 0233000000000+I_AC,
|
||||
0234000000000+I_AC, 0235000000000+I_AC, 0236000000000+I_AC, 0237000000000+I_AC,
|
||||
0240000000000+I_AC, 0241000000000+I_AC, 0242000000000+I_AC, 0243000000000+I_AC,
|
||||
0244000000000+I_AC, 0245000000000+I_AC, 0246000000000+I_AC, 0247000000000+I_AC+I_ITS,
|
||||
0250000000000+I_AC, 0251000000000+I_AC, 0252000000000+I_AC, 0253000000000+I_AC,
|
||||
0254000000000+I_AC, 0255000000000+I_AC, 0256000000000+I_AC, 0257000000000+I_AC,
|
||||
0260000000000+I_AC, 0261000000000+I_AC, 0262000000000+I_AC, 0263000000000+I_AC,
|
||||
0264000000000+I_AC, 0265000000000+I_AC, 0266000000000+I_AC, 0267000000000+I_AC,
|
||||
0270000000000+I_AC, 0271000000000+I_AC, 0272000000000+I_AC, 0273000000000+I_AC,
|
||||
0274000000000+I_AC, 0275000000000+I_AC, 0276000000000+I_AC, 0277000000000+I_AC,
|
||||
|
||||
0300000000000+I_AC, 0301000000000+I_AC, 0302000000000+I_AC, 0303000000000+I_AC,
|
||||
0304000000000+I_AC, 0305000000000+I_AC, 0306000000000+I_AC, 0307000000000+I_AC,
|
||||
0310000000000+I_AC, 0311000000000+I_AC, 0312000000000+I_AC, 0313000000000+I_AC,
|
||||
0314000000000+I_AC, 0315000000000+I_AC, 0316000000000+I_AC, 0317000000000+I_AC,
|
||||
0320000000000+I_AC, 0321000000000+I_AC, 0322000000000+I_AC, 0323000000000+I_AC,
|
||||
0324000000000+I_AC, 0325000000000+I_AC, 0326000000000+I_AC, 0327000000000+I_AC,
|
||||
0330000000000+I_AC, 0331000000000+I_AC, 0332000000000+I_AC, 0333000000000+I_AC,
|
||||
0334000000000+I_AC, 0335000000000+I_AC, 0336000000000+I_AC, 0337000000000+I_AC,
|
||||
0340000000000+I_AC, 0341000000000+I_AC, 0342000000000+I_AC, 0343000000000+I_AC,
|
||||
0344000000000+I_AC, 0345000000000+I_AC, 0346000000000+I_AC, 0347000000000+I_AC,
|
||||
0350000000000+I_AC, 0351000000000+I_AC, 0352000000000+I_AC, 0353000000000+I_AC,
|
||||
0354000000000+I_AC, 0355000000000+I_AC, 0356000000000+I_AC, 0357000000000+I_AC,
|
||||
0360000000000+I_AC, 0361000000000+I_AC, 0362000000000+I_AC, 0363000000000+I_AC,
|
||||
0364000000000+I_AC, 0365000000000+I_AC, 0366000000000+I_AC, 0367000000000+I_AC,
|
||||
0370000000000+I_AC, 0371000000000+I_AC, 0372000000000+I_AC, 0373000000000+I_AC,
|
||||
0374000000000+I_AC, 0375000000000+I_AC, 0376000000000+I_AC, 0377000000000+I_AC,
|
||||
|
||||
0400000000000+I_AC, 0401000000000+I_AC, 0402000000000+I_AC, 0403000000000+I_AC,
|
||||
0404000000000+I_AC, 0405000000000+I_AC, 0406000000000+I_AC, 0407000000000+I_AC,
|
||||
0410000000000+I_AC, 0411000000000+I_AC, 0412000000000+I_AC, 0413000000000+I_AC,
|
||||
0414000000000+I_AC, 0415000000000+I_AC, 0416000000000+I_AC, 0417000000000+I_AC,
|
||||
0420000000000+I_AC, 0421000000000+I_AC, 0422000000000+I_AC, 0423000000000+I_AC,
|
||||
0424000000000+I_AC, 0425000000000+I_AC, 0426000000000+I_AC, 0427000000000+I_AC,
|
||||
0430000000000+I_AC, 0431000000000+I_AC, 0432000000000+I_AC, 0433000000000+I_AC,
|
||||
0434000000000+I_AC, 0435000000000+I_AC, 0436000000000+I_AC, 0437000000000+I_AC,
|
||||
0440000000000+I_AC, 0441000000000+I_AC, 0442000000000+I_AC, 0443000000000+I_AC,
|
||||
0444000000000+I_AC, 0445000000000+I_AC, 0446000000000+I_AC, 0447000000000+I_AC,
|
||||
0450000000000+I_AC, 0451000000000+I_AC, 0452000000000+I_AC, 0453000000000+I_AC,
|
||||
0454000000000+I_AC, 0455000000000+I_AC, 0456000000000+I_AC, 0457000000000+I_AC,
|
||||
0460000000000+I_AC, 0461000000000+I_AC, 0462000000000+I_AC, 0463000000000+I_AC,
|
||||
0464000000000+I_AC, 0465000000000+I_AC, 0466000000000+I_AC, 0467000000000+I_AC,
|
||||
0470000000000+I_AC, 0471000000000+I_AC, 0472000000000+I_AC, 0473000000000+I_AC,
|
||||
0474000000000+I_AC, 0475000000000+I_AC, 0476000000000+I_AC, 0477000000000+I_AC,
|
||||
|
||||
0500000000000+I_AC, 0501000000000+I_AC, 0502000000000+I_AC, 0503000000000+I_AC,
|
||||
0504000000000+I_AC, 0505000000000+I_AC, 0506000000000+I_AC, 0507000000000+I_AC,
|
||||
0510000000000+I_AC, 0511000000000+I_AC, 0512000000000+I_AC, 0513000000000+I_AC,
|
||||
0514000000000+I_AC, 0515000000000+I_AC, 0516000000000+I_AC, 0517000000000+I_AC,
|
||||
0520000000000+I_AC, 0521000000000+I_AC, 0522000000000+I_AC, 0523000000000+I_AC,
|
||||
0524000000000+I_AC, 0525000000000+I_AC, 0526000000000+I_AC, 0527000000000+I_AC,
|
||||
0530000000000+I_AC, 0531000000000+I_AC, 0532000000000+I_AC, 0533000000000+I_AC,
|
||||
0534000000000+I_AC, 0535000000000+I_AC, 0536000000000+I_AC, 0537000000000+I_AC,
|
||||
0540000000000+I_AC, 0541000000000+I_AC, 0542000000000+I_AC, 0543000000000+I_AC,
|
||||
0544000000000+I_AC, 0545000000000+I_AC, 0546000000000+I_AC, 0547000000000+I_AC,
|
||||
0550000000000+I_AC, 0551000000000+I_AC, 0552000000000+I_AC, 0553000000000+I_AC,
|
||||
0554000000000+I_AC, 0555000000000+I_AC, 0556000000000+I_AC, 0557000000000+I_AC,
|
||||
0560000000000+I_AC, 0561000000000+I_AC, 0562000000000+I_AC, 0563000000000+I_AC,
|
||||
0564000000000+I_AC, 0565000000000+I_AC, 0566000000000+I_AC, 0567000000000+I_AC,
|
||||
0570000000000+I_AC, 0571000000000+I_AC, 0572000000000+I_AC, 0573000000000+I_AC,
|
||||
0574000000000+I_AC, 0575000000000+I_AC, 0576000000000+I_AC, 0577000000000+I_AC,
|
||||
|
||||
0600000000000+I_AC, 0601000000000+I_AC, 0602000000000+I_AC, 0603000000000+I_AC,
|
||||
0604000000000+I_AC, 0605000000000+I_AC, 0606000000000+I_AC, 0607000000000+I_AC,
|
||||
0610000000000+I_AC, 0611000000000+I_AC, 0612000000000+I_AC, 0613000000000+I_AC,
|
||||
0614000000000+I_AC, 0615000000000+I_AC, 0616000000000+I_AC, 0617000000000+I_AC,
|
||||
0620000000000+I_AC, 0621000000000+I_AC, 0622000000000+I_AC, 0623000000000+I_AC,
|
||||
0624000000000+I_AC, 0625000000000+I_AC, 0626000000000+I_AC, 0627000000000+I_AC,
|
||||
0630000000000+I_AC, 0631000000000+I_AC, 0632000000000+I_AC, 0633000000000+I_AC,
|
||||
0634000000000+I_AC, 0635000000000+I_AC, 0636000000000+I_AC, 0637000000000+I_AC,
|
||||
0640000000000+I_AC, 0641000000000+I_AC, 0642000000000+I_AC, 0643000000000+I_AC,
|
||||
0644000000000+I_AC, 0645000000000+I_AC, 0646000000000+I_AC, 0647000000000+I_AC,
|
||||
0650000000000+I_AC, 0651000000000+I_AC, 0652000000000+I_AC, 0653000000000+I_AC,
|
||||
0654000000000+I_AC, 0655000000000+I_AC, 0656000000000+I_AC, 0657000000000+I_AC,
|
||||
0660000000000+I_AC, 0661000000000+I_AC, 0662000000000+I_AC, 0663000000000+I_AC,
|
||||
0664000000000+I_AC, 0665000000000+I_AC, 0666000000000+I_AC, 0667000000000+I_AC,
|
||||
0670000000000+I_AC, 0671000000000+I_AC, 0672000000000+I_AC, 0673000000000+I_AC,
|
||||
0674000000000+I_AC, 0675000000000+I_AC, 0676000000000+I_AC, 0677000000000+I_AC,
|
||||
|
||||
0704000000000+I_AC, 0705000000000+I_AC,
|
||||
0710000000000+I_AC, 0711000000000+I_AC, 0712000000000+I_AC, 0713000000000+I_AC,
|
||||
0714000000000+I_AC, 0715000000000+I_AC, 0716000000000+I_AC, 0717000000000+I_AC,
|
||||
0720000000000+I_AC, 0721000000000+I_AC, 0722000000000+I_AC, 0723000000000+I_AC,
|
||||
0724000000000+I_AC, 0725000000000+I_AC,
|
||||
|
||||
0700000000000+I_IO, 0700040000000+I_IO, 0700100000000+I_IO, 0700140000000+I_IO,
|
||||
0700200000000+I_IO, 0700240000000+I_IO, 0700300000000+I_IO, 0700340000000+I_IO,
|
||||
|
||||
0400000000000+I_AC, 0401000000000+I_AC, 0402000000000+I_AC, 0403000000000+I_AC,
|
||||
0434000000000+I_AC, 0435000000000+I_AC, 0436000000000+I_AC, 0437000000000+I_AC,
|
||||
0415000000000+I_AC, 0501000000000+I_AC,
|
||||
|
||||
0001000000000+I_AC, 0002000000000+I_AC, 0003000000000+I_AC,
|
||||
0004000000000+I_AC, 0005000000000+I_AC, 0006000000000+I_AC, 0007000000000+I_AC,
|
||||
0010000000000+I_AC, 0011000000000+I_AC, 0012000000000+I_AC, 0013000000000+I_AC,
|
||||
0014000000000+I_AC, 0015000000000+I_AC, 0016000000000+I_AC, 0017000000000+I_AC,
|
||||
0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC,
|
||||
0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC,
|
||||
0030000000000+I_AC, 0031000000000+I_AC,
|
||||
-1 };
|
||||
|
||||
#define NUMDEV 6
|
||||
|
||||
static const char *devnam[NUMDEV] = {
|
||||
"APR", "PI", "PAG", "CCA", "TIM", "MTR"};
|
||||
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to values
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = status code
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
#define SIXTOASC(x) ((x) + 040)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 i, j, c, cflag, ac, xr, y, dev;
|
||||
d10 inst;
|
||||
|
||||
inst = val[0];
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
if (inst > 0377) return SCPE_ARG;
|
||||
fprintf (of, FMTASC ((int32) (inst & 0177)));
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('C')) { /* character? */
|
||||
for (i = 30; i >= 0; i = i - 6) {
|
||||
c = (int32) ((inst >> i) & 077);
|
||||
fprintf (of, "%c", SIXTOASC (c)); }
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('P')) { /* packed? */
|
||||
for (i = 29; i >= 0; i = i - 7) {
|
||||
c = (int32) ((inst >> i) & 0177);
|
||||
fprintf (of, FMTASC (c)); }
|
||||
return SCPE_OK; }
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
|
||||
/* Instruction decode */
|
||||
|
||||
ac = GET_AC (inst);
|
||||
xr = GET_XR (inst);
|
||||
y = GET_ADDR (inst);
|
||||
dev = GET_DEV (inst);
|
||||
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
|
||||
if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */
|
||||
(((opc_val[i] & I_ITS) == 0) || ITS)) {
|
||||
fprintf (of, "%s ", opcode[i]); /* opcode */
|
||||
switch (j) { /* case on class */
|
||||
case I_V_AC: /* AC + address */
|
||||
fprintf (of, "%-o,", ac); /* print AC, fall thru */
|
||||
case I_V_OP: /* address only */
|
||||
if (inst & INST_IND) fprintf (of, "@");
|
||||
if (xr) fprintf (of, "%-o(%-o)", y, xr);
|
||||
else fprintf (of, "%-o", y);
|
||||
break;
|
||||
case I_V_IO: /* I/O */
|
||||
if (dev < NUMDEV) fprintf (of, "%s,", devnam[dev]);
|
||||
else fprintf (of, "%-o,", dev);
|
||||
if (inst & INST_IND) fprintf (of, "@");
|
||||
if (xr) fprintf (of, "%-o(%-o)", y, xr);
|
||||
else fprintf (of, "%-o", y);
|
||||
break; } /* end case */
|
||||
return SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Get operand, including indirect and index
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
*status = pointer to error status
|
||||
Outputs:
|
||||
val = output value
|
||||
*/
|
||||
|
||||
t_value get_opnd (char *cptr, t_stat *status)
|
||||
{
|
||||
int32 sign = 0;
|
||||
t_value val, xr = 0, ind = 0;
|
||||
char *tptr;
|
||||
|
||||
*status = SCPE_ARG; /* assume fail */
|
||||
if (*cptr == '@') {
|
||||
ind = INST_IND;
|
||||
cptr++; }
|
||||
if (*cptr == '+') cptr++;
|
||||
else if (*cptr == '-') {
|
||||
sign = 1;
|
||||
cptr++; }
|
||||
val = strtotv (cptr, &tptr, 8);
|
||||
if (val > 0777777) return 0;
|
||||
if (sign) val = (~val + 1) & 0777777;
|
||||
cptr = tptr;
|
||||
if (*cptr == '(') {
|
||||
cptr++;
|
||||
xr = strtotv (cptr, &tptr, 8);
|
||||
if ((cptr == tptr) || (*tptr != ')') ||
|
||||
(xr > AC_NUM) || (xr == 0)) return 0;
|
||||
cptr = ++tptr; }
|
||||
if (*cptr == 0) *status = SCPE_OK;
|
||||
return (ind | (xr << 18) | val);
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 cflag, i, j;
|
||||
t_value ac, dev;
|
||||
t_stat r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
while (isspace (*cptr)) cptr++;
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (cptr[i] == 0) {
|
||||
for (j = i + 1; j <= 6; j++) cptr[j] = 0;
|
||||
break; } }
|
||||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (t_value) cptr[0];
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
for (i = 0; i < 6; i++) {
|
||||
val[0] = (val[0] << 6);
|
||||
if (cptr[i]) val[0] = val[0] |
|
||||
((t_value) ((cptr[i] + 040) & 077)); }
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('P')) || ((*cptr == '#') && cptr++)) { /* packed string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
for (i = 0; i < 5; i++) val[0] = (val[0] << 7) | ((t_value) cptr[i]);
|
||||
val[0] = val[0] << 1;
|
||||
return SCPE_OK; }
|
||||
|
||||
/* Symbolic input, continued */
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i] == NULL) return SCPE_ARG;
|
||||
val[0] = opc_val[i] & DMASK; /* get value */
|
||||
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
|
||||
switch (j) { /* case on class */
|
||||
case I_V_AC: /* AC + operand */
|
||||
if (strchr (cptr, ',')) { /* AC specified? */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
|
||||
if (gbuf[0]) { /* can be omitted */
|
||||
ac = get_uint (gbuf, 8, AC_NUM - 1, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | (ac << INST_V_AC); } }
|
||||
case I_V_OP: /* operand */
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
val[0] = val[0] | get_opnd (gbuf, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
break;
|
||||
case I_V_IO: /* I/O */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
|
||||
for (dev = 0; (dev < NUMDEV) && (strcmp (devnam[dev], gbuf) != 0); dev++);
|
||||
if (dev >= NUMDEV) {
|
||||
dev = get_uint (gbuf, 8, INST_M_DEV, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG; }
|
||||
val[0] = val[0] | (dev << INST_V_DEV);
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
val[0] = val[0] | get_opnd (gbuf, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
break; } /* end case */
|
||||
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
191
PDP10/pdp10_tim.c
Normal file
191
PDP10/pdp10_tim.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/* pdp10_tim.c: PDP-10 tim subsystem simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
tim timer subsystem
|
||||
|
||||
02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy)
|
||||
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
|
||||
17-Jul-01 RMS Moved function prototype
|
||||
04-Jul-01 RMS Added DZ11 support
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include <time.h>
|
||||
|
||||
#define TIM_N_HWRE 12 /* hwre bits */
|
||||
#define TIM_HWRE 0000000010000 /* hwre incr */
|
||||
#define TIM_DELAY 500
|
||||
#define TIM_TPS 1001 /* ticks per sec */
|
||||
#define DZ_MULT (TIM_TPS / 60) /* DZ poll multiplier */
|
||||
#define TB_MASK 037777777777777777777; /* 71 - 12 bits */
|
||||
#define UNIT_V_Y2K (UNIT_V_UF) /* Y2K compliant OS */
|
||||
#define UNIT_Y2K (1u << UNIT_V_Y2K)
|
||||
|
||||
extern int32 apr_flg, pi_act;
|
||||
extern UNIT cpu_unit;
|
||||
extern d10 pcst;
|
||||
extern a10 pager_PC;
|
||||
t_int64 timebase = 0; /* 71b timebase */
|
||||
d10 ttg = 0; /* time to go */
|
||||
d10 period = 0; /* period */
|
||||
d10 quant = 0; /* ITS quantum */
|
||||
int32 diagflg = 0; /* diagnostics? */
|
||||
int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */
|
||||
|
||||
t_stat tim_svc (UNIT *uptr);
|
||||
t_stat tim_reset (DEVICE *dptr);
|
||||
extern d10 Read (a10 ea, int32 prv);
|
||||
extern d10 ReadM (a10 ea, int32 prv);
|
||||
extern void Write (a10 ea, d10 val, int32 prv);
|
||||
extern void WriteP (a10 ea, d10 val);
|
||||
extern int32 pi_eval (void);
|
||||
|
||||
/* TIM data structures
|
||||
|
||||
tim_dev TIM device descriptor
|
||||
tim_unit TIM unit descriptor
|
||||
tim_reg TIM register list
|
||||
*/
|
||||
|
||||
UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_DELAY };
|
||||
|
||||
REG tim_reg[] = {
|
||||
{ ORDATA (TIMEBASE, timebase, 71 - TIM_N_HWRE) },
|
||||
{ ORDATA (TTG, ttg, 36) },
|
||||
{ ORDATA (PERIOD, period, 36) },
|
||||
{ ORDATA (QUANT, quant, 36) },
|
||||
{ DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (DIAG, diagflg, 0) },
|
||||
{ FLDATA (Y2K, tim_unit.flags, UNIT_V_Y2K), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tim_mod[] = {
|
||||
{ UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL },
|
||||
{ UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tim_dev = {
|
||||
"TIM", &tim_unit, tim_reg, tim_mod,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &tim_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Timer instructions */
|
||||
|
||||
t_bool rdtim (a10 ea, int32 prv)
|
||||
{
|
||||
ReadM (INCA (ea), prv);
|
||||
Write (ea, (timebase >> (35 - TIM_N_HWRE)) & DMASK, prv);
|
||||
Write (INCA(ea), (timebase << TIM_N_HWRE) & MMASK, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrtim (a10 ea, int32 prv)
|
||||
{
|
||||
timebase = (Read (ea, prv) << (35 - TIM_N_HWRE)) |
|
||||
(CLRS (Read (INCA (ea), prv)) >> TIM_N_HWRE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool rdint (a10 ea, int32 prv)
|
||||
{
|
||||
Write (ea, period, prv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool wrint (a10 ea, int32 prv)
|
||||
{
|
||||
period = Read (ea, prv);
|
||||
ttg = period;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Timer routines
|
||||
|
||||
tim_svc process event (timer tick)
|
||||
tim_reset process reset
|
||||
*/
|
||||
|
||||
t_stat tim_svc (UNIT *uptr)
|
||||
{
|
||||
int32 t;
|
||||
|
||||
t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */
|
||||
sim_activate (&tim_unit, t); /* reactivate unit */
|
||||
tmxr_poll = t * DZ_MULT; /* set mux poll */
|
||||
timebase = (timebase + 1) & TB_MASK; /* increment timebase */
|
||||
ttg = ttg - TIM_HWRE; /* decrement timer */
|
||||
if (ttg <= 0) { /* timeout? */
|
||||
ttg = period; /* reload */
|
||||
apr_flg = apr_flg | APRF_TIM; } /* request interrupt */
|
||||
if (ITS) { /* ITS? */
|
||||
if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK;
|
||||
if (TSTS (pcst)) { /* PC sampling? */
|
||||
WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */
|
||||
pcst = AOB (pcst); } /* add 1,,1 */
|
||||
} /* end ITS */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tim_reset (DEVICE *dptr)
|
||||
{
|
||||
period = ttg = 0; /* clear timer */
|
||||
apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */
|
||||
sim_activate (&tim_unit, tim_unit.wait); /* activate unit */
|
||||
tmxr_poll = tim_unit.wait * DZ_MULT; /* set mux poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Time of year clock */
|
||||
|
||||
t_stat tcu_rd (int32 *data, int32 PA, int32 access)
|
||||
{
|
||||
time_t curtim;
|
||||
struct tm *tptr;
|
||||
|
||||
curtim = time (NULL); /* get time */
|
||||
tptr = localtime (&curtim); /* decompose */
|
||||
if (tptr == NULL) return SCPE_NXM; /* Y2K prob? */
|
||||
if ((tptr -> tm_year > 99) && !(tim_unit.flags & UNIT_Y2K))
|
||||
tptr -> tm_year = 99;
|
||||
|
||||
switch ((PA >> 1) & 03) { /* decode PA<3:1> */
|
||||
case 0: /* year/month/day */
|
||||
*data = (((tptr -> tm_year) & 0177) << 9) |
|
||||
(((tptr -> tm_mon + 1) & 017) << 5) |
|
||||
((tptr -> tm_mday) & 037);
|
||||
return SCPE_OK;
|
||||
case 1: /* hour/minute */
|
||||
*data = (((tptr -> tm_hour) & 037) << 8) |
|
||||
((tptr -> tm_min) & 077);
|
||||
return SCPE_OK;
|
||||
case 2: /* second */
|
||||
*data = (tptr -> tm_sec) & 077;
|
||||
return SCPE_OK;
|
||||
case 3: /* status */
|
||||
*data = CSR_DONE;
|
||||
return SCPE_OK; }
|
||||
return SCPE_NXM; /* can't get here */
|
||||
}
|
||||
1061
PDP10/pdp10_tu.c
Normal file
1061
PDP10/pdp10_tu.c
Normal file
File diff suppressed because it is too large
Load Diff
638
PDP10/pdp10_xtnd.c
Normal file
638
PDP10/pdp10_xtnd.c
Normal file
@@ -0,0 +1,638 @@
|
||||
/* pdp10_xtnd.c: PDP-10 extended instruction simulator
|
||||
|
||||
Copyright (c) 1993-2001, 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.
|
||||
|
||||
12-May-01 RMS Fixed compiler warning in xlate
|
||||
|
||||
Instructions handled in this module:
|
||||
MOVSLJ move string left justified
|
||||
MOVSO move string offset
|
||||
MOVST move string translated
|
||||
MOVSRJ move string right justified
|
||||
CMPSL compare string, skip on less
|
||||
CMPSE compare string, skip on equal
|
||||
CMPSLE compare string, skip on less or equal
|
||||
CMPSGE compare string, skip on greater or equal
|
||||
CMPSN compare string, skip on unequal
|
||||
CMPSG compare string, skip on greater
|
||||
CVTDBO convert decimal to binary offset
|
||||
CVTDBT convert decimal to binary translated
|
||||
CVTBDO convert binary to decimal offset
|
||||
CVTBDT convert binary to decimal translated
|
||||
EDIT edit
|
||||
|
||||
The PDP-10 extended instructions deal with non-binary data types,
|
||||
particularly byte strings and decimal strings. (In the KL10, the
|
||||
extended instructions include G floating support as well.) They
|
||||
are very complicated microcoded subroutines that can potentially
|
||||
run for a very long time. Accordingly, the instructions must test
|
||||
for interrupts as well as page faults, and be prepared to restart
|
||||
from either.
|
||||
|
||||
In general, the simulator attempts to keep the AC block up to date,
|
||||
so that page fails and interrupts can be taken directly at any point.
|
||||
If the AC block is not up to date, memory accessibility must be tested
|
||||
before the actual read or write is done.
|
||||
|
||||
The extended instruction routine returns a status code as follows:
|
||||
XT_NOSK no skip completion
|
||||
XT_SKIP skip completion
|
||||
XT_MUUO invalid extended instruction
|
||||
*/
|
||||
|
||||
#include "pdp10_defs.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#define MM_XSRC (pflgs & XSRC_PXCT)
|
||||
#define MM_XDST (pflgs & XDST_PXCT)
|
||||
#define MM_EA_XSRC ((pflgs & EA_PXCT) && MM_XSRC)
|
||||
#define MM_EA_XDST ((pflgs & EA_PXCT) && MM_XDST)
|
||||
|
||||
#define XT_CMPSL 001 /* opcodes */
|
||||
#define XT_CMPSE 002
|
||||
#define XT_CMPSLE 003
|
||||
#define XT_EDIT 004
|
||||
#define XT_CMPSGE 005
|
||||
#define XT_CMPSN 006
|
||||
#define XT_CMPSG 007
|
||||
#define XT_CVTDBO 010
|
||||
#define XT_CVTDBT 011
|
||||
#define XT_CVTBDO 012
|
||||
#define XT_CVTBDT 013
|
||||
#define XT_MOVSO 014
|
||||
#define XT_MOVST 015
|
||||
#define XT_MOVSLJ 016
|
||||
#define XT_MOVSRJ 017
|
||||
|
||||
/* Translation control */
|
||||
|
||||
#define XT_LFLG 0400000000000 /* L flag */
|
||||
#define XT_SFLG 0400000000000 /* S flag */
|
||||
#define XT_NFLG 0200000000000 /* N flag */
|
||||
#define XT_MFLG 0100000000000 /* M flag */
|
||||
|
||||
/* Translation table */
|
||||
|
||||
#define XT_V_CODE 15 /* translation op */
|
||||
#define XT_M_CODE 07
|
||||
#define XT_BYMASK 07777 /* byte mask */
|
||||
#define XT_DGMASK 017 /* digit mask */
|
||||
#define XT_GETCODE(x) ((int32) (((x) >> XT_V_CODE) & XT_M_CODE))
|
||||
|
||||
/* AC masks */
|
||||
|
||||
#define XLNTMASK 0000777777777 /* length */
|
||||
#define XFLGMASK 0700000000000 /* flags */
|
||||
#define XT_MBZ 0777000000000 /* must be zero */
|
||||
#define XT_MBZE 0047777000000 /* must be zero, edit */
|
||||
|
||||
/* Register change log */
|
||||
|
||||
#define XT_N_RLOG 5 /* entry width */
|
||||
#define XT_M_RLOG ((1 << XT_N_RLOG) - 1) /* entry mask */
|
||||
#define XT_O_RLOG 1 /* entry offset */
|
||||
#define XT_INSRLOG(x,v) v = ((v << XT_N_RLOG) | (((x) + XT_O_RLOG) & XT_M_RLOG))
|
||||
#define XT_REMRLOG(x,v) x = (v & XT_M_RLOG) - XT_O_RLOG; \
|
||||
v = v >> XT_N_RLOG
|
||||
|
||||
/* Edit */
|
||||
|
||||
#define ED_V_PBYN 30 /* pattern byte # */
|
||||
#define ED_M_PBYN 03
|
||||
#define ED_PBYNO 0040000000000 /* overflow bit */
|
||||
#define ED_GETPBYN(x) ((int32) (((x) >> ED_V_PBYN) & ED_M_PBYN))
|
||||
#define ED_V_POPC 6 /* pattern byte opcode */
|
||||
#define ED_M_PAT 0777 /* pattern byte mask */
|
||||
#define ED_M_NUM 0077 /* number for msg, etc */
|
||||
#define ED_PBYTE(x,y) ((int32) (((x) >> (27 - (ED_GETPBYN (y) * 9))) & ED_M_PAT))
|
||||
#define ED_STOP 0000 /* stop */
|
||||
#define ED_SELECT 0001 /* select source */
|
||||
#define ED_SIGST 0002 /* start significance */
|
||||
#define ED_FLDSEP 0003 /* field separator */
|
||||
#define ED_EXCHMD 0004 /* exchange mark, dst */
|
||||
#define ED_MESSAG 0100 /* message */
|
||||
#define ED_SKPM 0500 /* skip if M */
|
||||
#define ED_SKPN 0600 /* skip if N */
|
||||
#define ED_SKPA 0700 /* skip always */
|
||||
|
||||
extern d10 *ac_cur; /* current AC block */
|
||||
extern d10 bytemask[64];
|
||||
extern int32 flags;
|
||||
extern int32 rlog;
|
||||
extern jmp_buf save_env;
|
||||
|
||||
extern d10 Read (int32 ea, int32 prv);
|
||||
extern void Write (int32 ea, d10 val, int32 prv);
|
||||
extern a10 calc_ea (d10 inst, int32 prv);
|
||||
extern int32 test_int (void);
|
||||
d10 incbp (d10 bp);
|
||||
d10 incloadbp (int32 ac, int32 pflgs);
|
||||
void incstorebp (d10 val, int32 ac, int32 pflgs);
|
||||
d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 pflgs);
|
||||
void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs);
|
||||
|
||||
static const d10 pwrs10[23][2] = {
|
||||
0, 0,
|
||||
0, 1,
|
||||
0, 10,
|
||||
0, 100,
|
||||
0, 1000,
|
||||
0, 10000,
|
||||
0, 100000,
|
||||
0, 1000000,
|
||||
0, 10000000,
|
||||
0, 100000000,
|
||||
0, 1000000000,
|
||||
0, 10000000000,
|
||||
2, 31280523264,
|
||||
29, 3567587328,
|
||||
291, 1316134912,
|
||||
2910, 13161349120,
|
||||
29103, 28534276096,
|
||||
291038, 10464854016,
|
||||
2910383, 1569325056,
|
||||
29103830, 15693250560,
|
||||
291038304, 19493552128,
|
||||
2910383045, 23136829440,
|
||||
29103830456, 25209864192 };
|
||||
|
||||
int xtend (int32 ac, int32 ea, int32 pflgs)
|
||||
{
|
||||
d10 b1, b2, ppi;
|
||||
d10 xinst, xoff, digit, f1, f2, rs[2];
|
||||
d10 xflgs = 0;
|
||||
a10 e1, entad;
|
||||
int32 p1 = ADDAC (ac, 1);
|
||||
int32 p3 = ADDAC (ac, 3);
|
||||
int32 p4 = ADDAC (ac, 4);
|
||||
int32 flg, i, s2, t, pp, pat, xop, xac, ret;
|
||||
|
||||
xinst = Read (ea, MM_OPND); /* get extended instr */
|
||||
xop = GET_OP (xinst); /* get opcode */
|
||||
xac = GET_AC (xinst); /* get AC */
|
||||
if (xac || (xop == 0) || (xop > XT_MOVSRJ)) return XT_MUUO;
|
||||
rlog = 0; /* clear log */
|
||||
switch (xop) { /* case on opcode */
|
||||
|
||||
/* String compares - checked against KS10 ucode
|
||||
If both strings are zero length, they are considered equal.
|
||||
Both source and destination lengths are MBZ checked.
|
||||
|
||||
AC = source1 length
|
||||
AC + 1 = source1 byte pointer
|
||||
AC + 3 = source2 length
|
||||
AC + 4 = source2 byte pointer
|
||||
*/
|
||||
|
||||
case XT_CMPSL: /* CMPSL */
|
||||
case XT_CMPSE: /* CMPSE */
|
||||
case XT_CMPSLE: /* CMPSLE */
|
||||
case XT_CMPSGE: /* CMPSGE */
|
||||
case XT_CMPSN: /* CMPSN */
|
||||
case XT_CMPSG: /* CMPSG */
|
||||
if ((AC(ac) | AC(p3)) & XT_MBZ) return XT_MUUO; /* check length MBZ */
|
||||
f1 = Read (ADDA (ea, 1), MM_OPND) & bytemask[GET_S (AC(p1))];
|
||||
f2 = Read (ADDA (ea, 2), MM_OPND) & bytemask[GET_S (AC(p4))];
|
||||
b1 = b2 = 0;
|
||||
for (flg = 0; (AC(ac) | AC(p3)) && (b1 == b2); flg++) {
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
rlog = 0; /* clear log */
|
||||
if (AC(ac)) b1 = incloadbp (p1, pflgs); /* src1 */
|
||||
else b1 = f1;
|
||||
if (AC(p3)) b2 = incloadbp (p4, pflgs); /* src2 */
|
||||
else b2 = f2;
|
||||
if (AC(ac)) AC(ac) = (AC(ac) - 1) & XLNTMASK;
|
||||
if (AC(p3)) AC(p3) = (AC(p3) - 1) & XLNTMASK; }
|
||||
switch (xop) {
|
||||
case XT_CMPSL: return (b1 < b2)? XT_SKIP: XT_NOSK;
|
||||
case XT_CMPSE: return (b1 == b2)? XT_SKIP: XT_NOSK;
|
||||
case XT_CMPSLE: return (b1 <= b2)? XT_SKIP: XT_NOSK;
|
||||
case XT_CMPSGE: return (b1 >= b2)? XT_SKIP: XT_NOSK;
|
||||
case XT_CMPSN: return (b1 != b2)? XT_SKIP: XT_NOSK;
|
||||
case XT_CMPSG: return (b1 > b2)? XT_SKIP: XT_NOSK; }
|
||||
return XT_MUUO;
|
||||
|
||||
/* Convert binary to decimal instructions - checked against KS10 ucode
|
||||
There are no MBZ tests.
|
||||
|
||||
AC'AC + 1 = double precision integer source
|
||||
AC + 3 = flags and destination length
|
||||
AC + 4 = destination byte pointer
|
||||
*/
|
||||
|
||||
case XT_CVTBDO: /* CVTBDO */
|
||||
case XT_CVTBDT: /* CVTBDT */
|
||||
e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */
|
||||
if (xop == XT_CVTBDO) /* offset? */
|
||||
xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */
|
||||
rs[0] = AC(ac); /* get src opnd */
|
||||
rs[1] = CLRS (AC(p1));
|
||||
if (!TSTF (F_FPD)) { /* set up done yet? */
|
||||
if (TSTS (AC(ac))) { DMOVN (rs); } /* get abs value */
|
||||
for (i = 22; i > 1; i--) { /* find field width */
|
||||
if (DCMPGE (rs, pwrs10[i])) break; }
|
||||
if (i > (AC(p3) & XLNTMASK)) return XT_NOSK;
|
||||
if ((i < (AC(p3) & XLNTMASK)) && (AC(p3) & XT_LFLG)) {
|
||||
f1 = Read (ADDA (ea, 1), MM_OPND);
|
||||
filldst (f1, p3, (AC(p3) & XLNTMASK) - i, pflgs); }
|
||||
else AC(p3) = (AC(p3) & XFLGMASK) | i;
|
||||
if (TSTS (AC(ac))) AC(p3) = AC(p3) | XT_MFLG;
|
||||
if (AC(ac) | AC(p1)) AC(p3) = AC(p3) | XT_NFLG;
|
||||
AC(ac) = rs[0]; /* update state */
|
||||
AC(p1) = rs[1];
|
||||
SETF (F_FPD); } /* mark set up done */
|
||||
|
||||
/* Now do actual binary to decimal conversion */
|
||||
|
||||
for (flg = 0; AC(p3) & XLNTMASK; flg++) {
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
rlog = 0; /* clear log */
|
||||
i = (int32) AC(p3) & XLNTMASK; /* get length */
|
||||
if (i > 22) i = 22; /* put in range */
|
||||
for (digit = 0; (digit < 10) && DCMPGE (rs, pwrs10[i]); digit++) {
|
||||
rs[0] = rs[0] - pwrs10[i][0] - (rs[1] < pwrs10[i][1]);
|
||||
rs[1] = (rs[1] - pwrs10[i][1]) & MMASK; }
|
||||
if (xop == XT_CVTBDO) digit = (digit + xoff) & DMASK;
|
||||
else { f1 = Read (e1 + (int32) digit, MM_OPND);
|
||||
if ((i == 1) && (AC(p3) & XT_LFLG)) f1 = f1 >> 18;
|
||||
digit = f1 & RMASK; }
|
||||
incstorebp (digit, p4, pflgs); /* store digit */
|
||||
AC(ac) = rs[0]; /* mem access ok */
|
||||
AC(p1) = rs[1]; /* update state */
|
||||
AC(p3) = (AC(p3) & XFLGMASK) | ((AC(p3) - 1) & XLNTMASK); }
|
||||
CLRF (F_FPD); /* clear FPD */
|
||||
return XT_SKIP;
|
||||
|
||||
/* Convert decimal to binary instructions - checked against KS10 ucode
|
||||
There are no MBZ tests.
|
||||
|
||||
AC = flags and source length
|
||||
AC + 1 = source byte pointer
|
||||
AC + 3'AC + 4 = double precision integer result
|
||||
*/
|
||||
|
||||
case XT_CVTDBT: /* CVTDBT */
|
||||
case XT_CVTDBO: /* CVTDBO */
|
||||
e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */
|
||||
if ((AC(ac) & XT_SFLG) == 0) AC(p3) = AC(p4) = 0; /* !S? clr res */
|
||||
else AC(p4) = CLRS (AC(p4)); /* clear low sign */
|
||||
if (xop == XT_CVTDBO) { /* offset? */
|
||||
xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */
|
||||
AC(ac) = AC(ac) | XT_SFLG; } /* set S flag */
|
||||
xflgs = AC(ac) & XFLGMASK; /* get xlation flags */
|
||||
for (flg = 0; AC(ac) & XLNTMASK; flg++) {
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
rlog = 0; /* clear log */
|
||||
b1 = incloadbp (p1, pflgs); /* get byte */
|
||||
if (xop == XT_CVTDBO) b1 = (b1 + xoff) & DMASK;
|
||||
else { b1 = xlate (b1, e1, &xflgs, MM_OPND);
|
||||
if (b1 < 0) { /* terminated? */
|
||||
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
|
||||
if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4));
|
||||
return XT_NOSK; }
|
||||
if (xflgs & XT_SFLG) b1 = b1 & XT_DGMASK;
|
||||
else b1 = 0; }
|
||||
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
|
||||
if ((b1 < 0) || (b1 > 9)) { /* bad digit? done */
|
||||
if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4));
|
||||
return XT_NOSK; }
|
||||
AC(p4) = (AC(p4) * 10) + b1; /* base * 10 + digit */
|
||||
AC(p3) = ((AC(p3) * 10) + (AC(p4) >> 35)) & DMASK;
|
||||
AC(p4) = AC(p4) & MMASK; }
|
||||
if (AC(ac) & XT_MFLG) {
|
||||
AC(p4) = -AC(p4) & MMASK;
|
||||
AC(p3) = (~AC(p3) + (AC(p4) == 0)) & DMASK; }
|
||||
if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4));
|
||||
return XT_SKIP;
|
||||
|
||||
/* String move instructions - checked against KS10 ucode
|
||||
Only the destination length is MBZ checked.
|
||||
|
||||
AC = flags (MOVST only) and source length
|
||||
AC + 1 = source byte pointer
|
||||
AC + 3 = destination length
|
||||
AC + 4 = destination byte pointer
|
||||
*/
|
||||
|
||||
case XT_MOVSO: /* MOVSO */
|
||||
case XT_MOVST: /* MOVST */
|
||||
case XT_MOVSRJ: /* MOVSRJ */
|
||||
case XT_MOVSLJ: /* MOVSLJ */
|
||||
if (AC(p3) & XT_MBZ) return XT_MUUO; /* test dst lnt MBZ */
|
||||
f1 = Read (ADDA (ea, 1), MM_OPND); /* get fill */
|
||||
switch (xop) { /* case on instr */
|
||||
case XT_MOVSO: /* MOVSO */
|
||||
AC(ac) = AC(ac) & XLNTMASK; /* trim src length */
|
||||
xoff = calc_ea (xinst, MM_EA); /* get offset */
|
||||
if (xoff & RSIGN) xoff = xoff | LMASK; /* sign extend 18b */
|
||||
s2 = GET_S (AC(p4)); /* get dst byte size */
|
||||
break;
|
||||
case XT_MOVST: /* MOVST */
|
||||
e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */
|
||||
break;
|
||||
case XT_MOVSRJ: /* MOVSRJ */
|
||||
AC(ac) = AC(ac) & XLNTMASK; /* trim src length */
|
||||
if (AC(p3) == 0) return (AC(ac)? XT_NOSK: XT_SKIP);
|
||||
if (AC(ac) > AC(p3)) { /* adv src ptr */
|
||||
for (flg = 0; AC(ac) > AC(p3); flg++) {
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
AC(p1) = incbp (AC(p1));
|
||||
AC(ac) = (AC(ac) - 1) & XLNTMASK; } }
|
||||
else if (AC(ac) < AC(p3))
|
||||
filldst (f1, p3, AC(p3) - AC(ac), pflgs);
|
||||
break;
|
||||
case XT_MOVSLJ: /* MOVSLJ */
|
||||
AC(ac) = AC(ac) & XLNTMASK; /* trim src length */
|
||||
break; }
|
||||
|
||||
xflgs = AC(ac) & XFLGMASK; /* get xlation flags */
|
||||
if (AC(p3) == 0) return (AC(ac)? XT_NOSK: XT_SKIP);
|
||||
for (flg = 0; AC(p3) & XLNTMASK; flg++) {
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
rlog = 0; /* clear log */
|
||||
if (AC(ac) & XLNTMASK) { /* any source? */
|
||||
b1 = incloadbp (p1, pflgs); /* src byte */
|
||||
if (xop == XT_MOVSO) { /* offset? */
|
||||
b1 = (b1 + xoff) & DMASK; /* test fit */
|
||||
if (b1 & ~bytemask[s2]) {
|
||||
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
|
||||
return XT_NOSK; } }
|
||||
else if (xop == XT_MOVST) { /* translate? */
|
||||
b1 = xlate (b1, e1, &xflgs, MM_OPND);
|
||||
if (b1 < 0) { /* upd flags in AC */
|
||||
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
|
||||
return XT_NOSK; }
|
||||
if (xflgs & XT_SFLG) b1 = b1 & XT_BYMASK;
|
||||
else b1 = -1; } }
|
||||
else b1 = f1;
|
||||
if (b1 >= 0) { /* valid byte? */
|
||||
incstorebp (b1, p4, pflgs); /* store byte */
|
||||
AC(p3) = (AC(p3) - 1) & XLNTMASK; } /* update state */
|
||||
if (AC(ac) & XLNTMASK) AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); }
|
||||
return (AC(ac) & XLNTMASK)? XT_NOSK: XT_SKIP;
|
||||
|
||||
/* Edit - checked against KS10 ucode
|
||||
Only the flags/pattern pointer word is MBZ checked.
|
||||
|
||||
AC = flags, pattern pointer
|
||||
AC + 1 = source byte pointer
|
||||
AC + 3 = mark address
|
||||
AC + 4 = destination byte pointer
|
||||
*/
|
||||
|
||||
case XT_EDIT: /* EDIT */
|
||||
if (AC(ac) & XT_MBZE) return XT_MUUO; /* check pattern MBZ */
|
||||
xflgs = AC(ac) & XFLGMASK; /* get xlation flags */
|
||||
e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */
|
||||
for (ppi = 1, ret = -1, flg = 0; ret < 0; flg++, ppi = 1) {
|
||||
if (flg && (t = test_int ())) ABORT (t);
|
||||
rlog = 0; /* clear log */
|
||||
pp = (int32) AC(ac) & AMASK; /* get pattern ptr */
|
||||
b1 = Read (pp, MM_OPND); /* get pattern word */
|
||||
pat = ED_PBYTE (b1, AC(ac)); /* get pattern byte */
|
||||
switch ((pat < 0100)? pat: ((pat >> ED_V_POPC) + 0100)) {
|
||||
case ED_STOP: /* stop */
|
||||
ret = XT_SKIP; /* exit loop */
|
||||
break;
|
||||
case ED_SELECT: /* select source */
|
||||
b1 = incloadbp (p1, pflgs); /* get src */
|
||||
entad = (e1 + ((int32) b1 >> 1)) & AMASK;
|
||||
f1 = ((Read (entad, MM_OPND) >> ((b1 & 1)? 0: 18)) & RMASK);
|
||||
i = XT_GETCODE (f1);
|
||||
if (i & 2) xflgs =
|
||||
(i & 1)? xflgs | XT_MFLG: xflgs & ~XT_MFLG;
|
||||
switch (i) {
|
||||
case 00: case 02: case 03:
|
||||
if (xflgs & XT_SFLG) f1 = f1 & XT_BYMASK;
|
||||
else { f1 = Read (INCA (ea), MM_OPND);
|
||||
if (f1 == 0) break; }
|
||||
incstorebp (f1, p4, pflgs);
|
||||
break;
|
||||
case 01:
|
||||
ret = XT_NOSK; /* exit loop */
|
||||
break;
|
||||
case 04: case 06: case 07:
|
||||
xflgs = xflgs | XT_NFLG;
|
||||
f1 = f1 & XT_BYMASK;
|
||||
if ((xflgs & XT_SFLG) == 0) {
|
||||
f2 = Read (ADDA (ea, 2), MM_OPND);
|
||||
Write ((a10) AC(p3), AC(p4), MM_OPND);
|
||||
if (f2) incstorebp (f2, p4, pflgs);
|
||||
xflgs = xflgs | XT_SFLG; }
|
||||
incstorebp (f1, p4, pflgs);
|
||||
break;
|
||||
case 05:
|
||||
xflgs = xflgs | XT_NFLG;
|
||||
ret = XT_NOSK; /* exit loop */
|
||||
break; } /* end case xlate op */
|
||||
break;
|
||||
case ED_SIGST: /* start significance */
|
||||
if ((xflgs & XT_SFLG) == 0) {
|
||||
f2 = Read (ADDA (ea, 2), MM_OPND);
|
||||
Write ((a10) AC(p3), AC(p4), MM_OPND);
|
||||
if (f2) incstorebp (f2, p4, pflgs);
|
||||
xflgs = xflgs | XT_SFLG; }
|
||||
break;
|
||||
case ED_FLDSEP: /* separate fields */
|
||||
xflgs = 0;
|
||||
break;
|
||||
case ED_EXCHMD: /* exchange */
|
||||
f2 = Read ((int32) (AC(p3) & AMASK), MM_OPND);
|
||||
Write ((int32) (AC(p3) & AMASK), AC(p4), MM_OPND);
|
||||
AC(p4) = f2;
|
||||
break;
|
||||
case (0100 + (ED_MESSAG >> ED_V_POPC)): /* message */
|
||||
if (xflgs & XT_SFLG)
|
||||
f1 = Read (ea + (pat & ED_M_NUM) + 1, MM_OPND);
|
||||
else { f1 = Read (ea + 1, MM_OPND);
|
||||
if (f1 == 0) break; }
|
||||
incstorebp (f1, p4, pflgs);
|
||||
break;
|
||||
case (0100 + (ED_SKPM >> ED_V_POPC)): /* skip on M */
|
||||
if (xflgs & XT_MFLG) ppi = (pat & ED_M_NUM) + 2;
|
||||
break;
|
||||
case (0100 + (ED_SKPN >> ED_V_POPC)): /* skip on N */
|
||||
if (xflgs & XT_NFLG) ppi = (pat & ED_M_NUM) + 2;
|
||||
break;
|
||||
case (0100 + (ED_SKPA >> ED_V_POPC)): /* skip always */
|
||||
ppi = (pat & ED_M_NUM) + 2;
|
||||
break;
|
||||
default: /* NOP or undefined */
|
||||
break; } /* end case pttrn op */
|
||||
AC(ac) = AC(ac) + ((ppi & ED_M_PBYN) << ED_V_PBYN);
|
||||
AC(ac) = AC(ac) + (ppi >> 2) + ((AC(ac) & ED_PBYNO)? 1: 0);
|
||||
AC(ac) = xflgs | (AC(ac) & ~(XT_MBZE | XFLGMASK)); }
|
||||
return ret; } /* end case xop */
|
||||
return XT_MUUO;
|
||||
}
|
||||
|
||||
/* Supporting subroutines */
|
||||
|
||||
/* Increment byte pointer, register version */
|
||||
|
||||
d10 incbp (d10 bp)
|
||||
{
|
||||
int32 p, s;
|
||||
|
||||
p = GET_P (bp); /* get P and S */
|
||||
s = GET_S (bp);
|
||||
p = p - s; /* adv P */
|
||||
if (p < 0) { /* end of word? */
|
||||
bp = (bp & LMASK) | (INCR (bp)); /* increment addr */
|
||||
p = (36 - s) & 077; } /* reset P */
|
||||
bp = PUT_P (bp, p); /* store new P */
|
||||
return bp;
|
||||
}
|
||||
|
||||
/* Increment and load byte, extended version - uses register log */
|
||||
|
||||
d10 incloadbp (int32 ac, int32 pflgs)
|
||||
{
|
||||
a10 ba;
|
||||
d10 bp, wd;
|
||||
int32 p, s;
|
||||
|
||||
bp = AC(ac) = incbp (AC(ac)); /* increment bp */
|
||||
XT_INSRLOG (ac, rlog); /* log change */
|
||||
p = GET_P (bp); /* get P and S */
|
||||
s = GET_S (bp);
|
||||
ba = calc_ea (bp, MM_EA_XSRC); /* calc bp eff addr */
|
||||
wd = Read (ba, MM_XSRC); /* read word */
|
||||
wd = (wd >> p) & bytemask[s]; /* get byte */
|
||||
return wd;
|
||||
}
|
||||
|
||||
/* Increment and deposit byte, extended version - uses register log */
|
||||
|
||||
void incstorebp (d10 val, int32 ac, int32 pflgs)
|
||||
{
|
||||
a10 ba;
|
||||
d10 bp, wd, mask;
|
||||
int32 p, s;
|
||||
|
||||
bp = AC(ac) = incbp (AC(ac)); /* increment bp */
|
||||
XT_INSRLOG (ac, rlog); /* log change */
|
||||
p = GET_P (bp); /* get P and S */
|
||||
s = GET_S (bp);
|
||||
ba = calc_ea (bp, MM_EA_XDST); /* calc bp eff addr */
|
||||
wd = Read (ba, MM_XDST); /* read, write test */
|
||||
mask = bytemask[s] << p; /* shift mask, val */
|
||||
val = val << p;
|
||||
wd = (wd & ~mask) | (val & mask); /* insert byte */
|
||||
Write (ba, wd & DMASK, MM_XDST);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Translate byte
|
||||
|
||||
Arguments
|
||||
by = byte to translate
|
||||
tblad = virtual address of translation table
|
||||
*xflgs = pointer to word containing translation flags
|
||||
prv = previous mode flag for table lookup
|
||||
Returns
|
||||
xby = >= 0, translated byte
|
||||
< 0, terminate translation
|
||||
*/
|
||||
|
||||
d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 prv)
|
||||
{
|
||||
a10 ea;
|
||||
int32 tcode;
|
||||
d10 tblent;
|
||||
|
||||
ea = (tblad + ((int32) by >> 1)) & AMASK;
|
||||
tblent = ((Read (ea, prv) >> ((by & 1)? 0: 18)) & RMASK);
|
||||
tcode = XT_GETCODE (tblent); /* get xlate code */
|
||||
switch (tcode) {
|
||||
case 00:
|
||||
return (*xflgs & XT_SFLG)? tblent: by;
|
||||
case 01:
|
||||
break;
|
||||
case 02:
|
||||
*xflgs = *xflgs & ~XT_MFLG;
|
||||
return (*xflgs & XT_SFLG)? tblent: by;
|
||||
case 03:
|
||||
*xflgs = *xflgs | XT_MFLG;
|
||||
return (*xflgs & XT_SFLG)? tblent: by;
|
||||
case 04:
|
||||
*xflgs = *xflgs | XT_SFLG | XT_NFLG;
|
||||
return tblent;
|
||||
case 05:
|
||||
*xflgs = *xflgs | XT_NFLG;
|
||||
break;
|
||||
case 06:
|
||||
*xflgs = (*xflgs | XT_SFLG | XT_NFLG) & ~XT_MFLG;
|
||||
return tblent;
|
||||
case 07:
|
||||
*xflgs = *xflgs | XT_SFLG | XT_NFLG | XT_MFLG;
|
||||
return tblent; } /* end case xlate code */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill out the destination string
|
||||
|
||||
Arguments:
|
||||
fill = fill
|
||||
ac = 2 word AC block (length, byte pointer)
|
||||
cnt = fill count
|
||||
pflgs = PXCT flags
|
||||
*/
|
||||
|
||||
void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs)
|
||||
{
|
||||
int32 i, t;
|
||||
int32 p1 = ADDA (ac, 1);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (i && (t = test_int ())) ABORT (t);
|
||||
rlog = 0; /* clear log */
|
||||
incstorebp (fill, p1, pflgs);
|
||||
AC(ac) = (AC(ac) & XFLGMASK) | ((AC(ac) - 1) & XLNTMASK); }
|
||||
rlog = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clean up after page fault
|
||||
|
||||
Arguments:
|
||||
logv = register change log
|
||||
|
||||
For each register in logv, decrement the register's contents as
|
||||
though it were a byte pointer. Note that the KS10 does <not>
|
||||
do a full decrement calculation but merely adds S to P.
|
||||
*/
|
||||
|
||||
void xtcln (int32 logv)
|
||||
{
|
||||
int32 p, reg;
|
||||
|
||||
while (logv) {
|
||||
XT_REMRLOG (reg, logv); /* get next reg */
|
||||
if ((reg >= 0) && (reg < AC_NUM)) {
|
||||
p = GET_P (AC(reg)) + GET_S (AC(reg)); /* get p + s */
|
||||
AC(reg) = PUT_P (AC(reg), p); } /* p <- p + s */
|
||||
}
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user