simh-testsetgenerator/Interdata/id32_cpu.c
Bob Supnik 2bcd1e7c4c Notes For V2.10-2
1. New Features in 2.10-2

The build procedures have changed.  There is only one UNIX makefile.
To compile without Ethernet support, simply type

	gmake {target|all}

To compile with Ethernet support, type

	gmake USE_NETWORK=1 {target|all}

The Mingw batch files require Mingw release 2 and invoke the Unix
makefile.  There are still separate batch files for compilation
with or without Ethernet support.

1.1 SCP and Libraries

- The EVAL command will evaluate a symbolic type-in and display
  it in numeric form.
- The ! command (with no arguments) will launch the host operating
  system command shell.  The ! command (with an argument) executes
  the argument as a host operating system command.  (Code from
  Mark Pizzolato)
- Telnet sessions now recognize BREAK.  How a BREAK is transmitted
  dependent on the particular Telnet client.  (Code from Mark
  Pizzolato)
- The sockets library includes code for active connections as
  well as listening connections.
- The RESTORE command will restore saved memory size, if the
  simulator supports dynamic memory resizing.

1.2 PDP-1

- The PDP-1 supports the Type 24 serial drum (based on recently
  discovered documents).

1.3 18b PDP's

- The PDP-4 supports the Type 24 serial drum (based on recently
  discovered documents).

1.4 PDP-11

- The PDP-11 implements a stub DEUNA/DELUA (XU).  The real XU
  module will be included in a later release.

1.5 PDP-10

- The PDP-10 implements a stub DEUNA/DELUA (XU).  The real XU
  module will be included in a later release.

1.6 HP 2100

- The IOP microinstruction set is supported for the 21MX as well
  as the 2100.
- The HP2100 supports the Access Interprocessor Link (IPL).

1.7 VAX

- If the VAX console is attached to a Telnet session, BREAK is
  interpreted as console halt.
- The SET/SHOW HISTORY commands enable and display a history of
  the most recently executed instructions.  (Code from Mark
  Pizzolato)

1.8 Terminals Multiplexors

- BREAK detection was added to the HP, DEC, and Interdata terminal
  multiplexors.

1.9 Interdata 16b and 32b

- First release.  UNIX is not yet working.

1.10 SDS 940

- First release.

2. Bugs Fixed in 2.10-2

- PDP-11 console must default to 7b for early UNIX compatibility.
- PDP-11/VAX TMSCP emulator was using the wrong packet length for
  read/write end packets.
- Telnet IAC+IAC processing was fixed, both for input and output
  (found by Mark Pizzolato).
- PDP-11/VAX Ethernet setting flag bits wrong for chained
  descriptors (found by Mark Pizzolato).

3. New Features in 2.10 vs prior releases

3.1 SCP and Libraries

- The VT emulation package has been replaced by the capability
  to remote the console to a Telnet session.  Telnet clients
  typically have more complete and robust VT100 emulation.
- Simulated devices may now have statically allocated buffers,
  in addition to dynamically allocated buffers or disk-based
  data stores.
- The DO command now takes substitutable arguments (max 9).
  In command files, %n represents substitutable argument n.
- The initial command line is now interpreted as the command
  name and substitutable arguments for a DO command.  This is
  backward compatible to prior versions.
- The initial command line parses switches.  -Q is interpreted
  as quiet mode; informational messages are suppressed.
- The HELP command now takes an optional argument.  HELP <cmd>
  types help on the specified command.
- Hooks have been added for implementing GUI-based consoles,
  as well as simulator-specific command extensions.  A few
  internal data structures and definitions have changed.
- Two new routines (tmxr_open_master, tmxr_close_master) have
  been added to sim_tmxr.c.  The calling sequence for
  sim_accept_conn has been changed in sim_sock.c.
- The calling sequence for the VM boot routine has been modified
  to add an additional parameter.
- SAVE now saves, and GET now restores, controller and unit flags.
- Library sim_ether.c has been added for Ethernet support.

3.2 VAX

- Non-volatile RAM (NVR) can behave either like a memory or like
  a disk-based peripheral.  If unattached, it behaves like memory
  and is saved and restored by SAVE and RESTORE, respectively.
  If attached, its contents are loaded from disk by ATTACH and
  written back to disk at DETACH and EXIT.
- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape) has been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from vax_stddev.c and
  now references a common implementation file, dec_pt.h.
- Examine and deposit switches now work on all devices, not just
  the CPU.
- Device address conflicts are not detected until simulation starts.

3.3 PDP-11

- SHOW <device> VECTOR displays the device's interrupt vector.
  Most devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk),
  RX211 (double density floppy), and KW11P programmable clock
  have been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from pdp11_stddev.c and
  now references a common implementation file, dec_pt.h.
- Device bootstraps now use the actual CSR specified by the
  SET ADDRESS command, rather than just the default CSR.  Note
  that PDP-11 operating systems may NOT support booting with
  non-standard addresses.
- Specifying more than 256KB of memory, or changing the bus
  configuration, causes all peripherals that are not compatible
  with the current bus configuration to be disabled.
- Device address conflicts are not detected until simulation starts.

3.4 PDP-10

- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The RX211 (double density floppy) has been added; it is off
  by default.
- The paper tape now references a common implementation file,
  dec_pt.h.
- Device address conflicts are not detected until simulation starts.

3.5 PDP-1

- DECtape (then known as MicroTape) support has been added.
- The line printer and DECtape can be disabled and enabled.

3.6 PDP-8

- The RX28 (double density floppy) has been added as an option to
  the existing RX8E controller.
- SHOW <device> DEVNO displays the device's device number.  Most
  devices allow the device number to be changed with SET <device>
  DEVNO=nnn.
- Device number conflicts are not detected until simulation starts.

3.7 IBM 1620

- The IBM 1620 simulator has been released.

3.8 AltairZ80

- A hard drive has been added for increased storage.
- Several bugs have been fixed.

3.9 HP 2100

- The 12845A has been added and made the default line printer (LPT).
  The 12653A has been renamed LPS and is off by default.  It also
  supports the diagnostic functions needed to run the DCPC and DMS
  diagnostics.
- The 12557A/13210A disk defaults to the 13210A (7900/7901).
- The 12559A magtape is off by default.
- New CPU options (EAU/NOEAU) enable/disable the extended arithmetic
  instructions for the 2116.  These instructions are standard on
  the 2100 and 21MX.
- New CPU options (MPR/NOMPR) enable/disable memory protect for the
  2100 and 21MX.
- New CPU options (DMS/NODMS) enable/disable the dynamic mapping
  instructions for the 21MX.
- The 12539 timebase generator autocalibrates.

3.10 Simulated Magtapes

- Simulated magtapes recognize end of file and the marker
  0xFFFFFFFF as end of medium.  Only the TMSCP tape simulator
  can generate an end of medium marker.
- The error handling in simulated magtapes was overhauled to be
  consistent through all simulators.

3.11 Simulated DECtapes

- Added support for RT11 image file format (256 x 16b) to DECtapes.

4. Bugs Fixed in 2.10 vs prior releases

- TS11/TSV05 was not simulating the XS0_MOT bit, causing failures
  under VMS.  In addition, two of the CTL options were coded
  interchanged.
- IBM 1401 tape was not setting a word mark under group mark for
  load mode reads.  This caused the diagnostics to crash.
- SCP bugs in ssh_break and set_logon were fixed (found by Dave
  Hittner).
- Numerous bugs in the HP 2100 extended arithmetic, floating point,
  21MX, DMS, and IOP instructions were fixed.  Bugs were also fixed
  in the memory protect and DMS functions.  The moving head disks
  (DP, DQ) were revised to simulate the hardware more accurately.
  Missing functions in DQ (address skip, read address) were added.
- PDP-10 tape wouldn't boot, and then wouldn't read (reported by
  Michael Thompson and Harris Newman, respectively)
- PDP-1 typewriter is half duplex, with only one shift state for
  both input and output (found by Derek Peschel)

5. General Notes

WARNING: V2.10 has reorganized and renamed some of the definition
files for the PDP-10, PDP-11, and VAX.  Be sure to delete all
previous source files before you unpack the Zip archive, or
unpack it into a new directory structure.

WARNING: V2.10 has a new, more comprehensive save file format.
Restoring save files from previous releases will cause 'invalid
register' errors and loss of CPU option flags, device enable/
disable flags, unit online/offline flags, and unit writelock
flags.

WARNING: If you are using Visual Studio .NET through the IDE,
be sure to turn off the /Wp64 flag in the project settings, or
dozens of spurious errors will be generated.

WARNING: Compiling Ethernet support under Windows requires
extra steps; see the Ethernet readme file.  Ethernet support is
currently available only for Windows, Linux, NetBSD, and OpenBSD.
2011-04-15 08:33:56 -07:00

2025 lines
67 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* id32_cpu.c: Interdata 32b CPU simulator
Copyright (c) 2000-2002, 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.
The register state for an Interdata 32b CPU is:
REG[0:F][2]<0:31> general register sets
F[0:7]<0:31> single precision floating point registers
D[0:7]<0:63> double precision floating point registers
PSW<0:63> processor status word, including
STAT<0:11> status flags
CC<0:3> condition codes
PC<0:31> program counter
int_req[n]<0:31> interrupt requests
int_enb[n]<0:31> interrupt enables
The Interdata 32b systems have seven instruction formats: register to
register, short format, register and memory (three formats), and register
and immediate (two formats). The formats are:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | R2 | register-register
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | N | short format
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | RX | register-memory 1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (absolute 14b)
| 0| 0| address |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | RX | register-memory 2
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (relative)
| 1| address |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | RX | register-memory 3
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (double index)
| 0| 1| 0| 0| RX2 | address hi |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| address lo |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | RX | register-immediate 1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| immediate |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | R1 | RX | register-immediate 2
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| immediate hi |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| immediate lo |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
For register-memory 1 and register-immediate 1 and 2 an instructions, an
effective address is calculated as follows:
effective addr = address + RX (if RX > 0)
For register-memory 2, an effective address is calculated as follows:
effective addr = address + PC + RX (if RX > 0)
For register-memory 3, an effective address is calculated as follows:
effective addr = address + RX (if RX > 0) + RX2 (if RX2 > 0)
Register-memory instructions can access an address space of 16M bytes.
*/
/* This routine is the instruction decode routine for the Interdata CPU.
It is called from the simulator control program to execute
instructions in simulated memory, starting at the simulated PC.
It runs until 'reason' is set non-zero.
General notes:
1. Reasons to stop. The simulator can be stopped by:
HALT instruction
breakpoint encountered
wait state and no I/O outstanding
invalid instruction
I/O error in I/O simulator
2. Interrupts. Each device has an interrupt armed flag, an interrupt
request flag, and an interrupt enabled flag. To facilitate evaluation,
all interrupt requests are kept in int_req, and all enables in int_enb.
Interrupt armed flags are local to devices. If external interrupts are
enabled in the PSW, and a request is pending, an interrupt occurs.
3. Non-existent memory. On the Interdata 32b, reads to non-existent
memory return zero, and writes are ignored. In the simulator, the
largest possible memory is instantiated and initialized to zero.
Thus, only writes need be checked against actual memory size.
4. Adding I/O devices. These modules must be modified:
id_defs.h add device interrupt definitions
id32_sys.c add sim_devices table entry
*/
#include "id_defs.h"
#include <setjmp.h>
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = oPC
#define VAMASK VAMASK32
#define NRSETS 2 /* 2 gen reg sets */
#define PSW_MASK PSW_x32
#define ABORT(val) longjmp (save_env, (val))
#define MPRO (-1)
#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */
#define UNIT_V_DPFP (UNIT_V_UF + 1)
#define UNIT_V_832 (UNIT_V_UF + 2)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define UNIT_DPFP (1 << UNIT_V_DPFP)
#define UNIT_832 (1 << UNIT_V_832)
#define UNIT_TYPE (UNIT_DPFP | UNIT_832)
#define SEXT32(x) (((x) & SIGN32)? ((int32) ((x) | ~0x7FFFFFFF)): \
((int32) ((x) & 0x7FFFFFFF)))
#define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | ~0x7FFF)): \
((int32) ((x) & 0x7FFF)))
#define SEXT15(x) (((x) & 0x4000)? ((int32) ((x) | ~0x3FFF)): \
((int32) ((x) & 0x3FFF)))
#define CC_GL_16(x) if ((x) & SIGN16) cc = CC_L; \
else if (x) cc = CC_G; \
else cc = 0
#define CC_GL_32(x) if ((x) & SIGN32) cc = CC_L; \
else if (x) cc = CC_G; \
else cc = 0
#define BUILD_PSW(x) (((PSW & ~CC_MASK) | (x)) & PSW_MASK)
#define NEG(x) ((~(x) + 1) & DMASK32)
#define ABS(x) (((x) & SIGN32)? NEG (x): (x))
#define DNEG(x,y) y = NEG (y); \
x = (~(x) + (y == 0)) & DMASK32
uint32 GREG[16 * NRSETS] = { 0 }; /* general registers */
uint32 *M = NULL; /* memory */
uint32 *R = &GREG[0]; /* working reg set */
uint32 F[8] = { 0 }; /* sp fp registers */
dpr_t D[8] = { 0 }; /* dp fp registers */
uint32 PSW = 0; /* processor status word */
uint32 PC = 0; /* program counter */
uint32 oPC = 0; /* PC at inst start */
uint32 SR = 0; /* switch register */
uint32 DR = 0; /* display register */
uint32 DRX = 0; /* display extension */
uint32 drmod = 0; /* mode */
uint32 srpos = 0; /* switch register pos */
uint32 drpos = 0; /* display register pos */
uint32 mac_reg[MAC_LNT] = { 0 }; /* mac registers */
uint32 mac_sta = 0; /* mac status */
uint32 int_req[INTSZ] = { 0 }; /* interrupt requests */
uint32 int_enb[INTSZ] = { 0 }; /* interrupt enables */
uint32 qevent = 0; /* events */
uint32 stop_inst = 0; /* stop on ill inst */
uint32 stop_wait = 0; /* stop on wait */
uint32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
uint32 dec_flgs = 0; /* decode flags */
uint32 fp_in_hwre = 0; /* ucode vs hwre fp */
uint32 pawidth = PAWIDTH32; /* addr mask */
uint32 cpu_log = 0; /* debug logging */
jmp_buf save_env; /* abort handler */
struct BlockIO blk_io; /* block I/O status */
uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };
extern int32 sim_interval;
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern UNIT pic_unit, lfc_unit, pas_unit; /* timers */
extern FILE *sim_log;
uint32 ReadB (uint32 loc, uint32 rel);
uint32 ReadH (uint32 loc, uint32 rel);
void WriteB (uint32 loc, uint32 val, uint32 rel);
void WriteH (uint32 loc, uint32 val, uint32 rel);
uint32 RelocT (uint32 va, uint32 base, uint32 rel, uint32 *pa);
uint32 int_auto (uint32 dev, uint32 cc);
uint32 addtoq (uint32 ea, uint32 val, uint32 flg);
uint32 remfmq (uint32 ea, uint32 r1, uint32 flg);
uint32 exception (uint32 loc, uint32 cc, uint32 flg);
uint32 newPSW (uint32 val);
uint32 testsysq (uint32 cc);
uint32 display (uint32 dev, uint32 op, uint32 dat);
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc);
void set_r_display (uint32 *rbase);
extern t_bool devtab_init (void);
extern void int_eval (void);
extern uint32 int_getdev (void);
extern void sch_cycle (uint32 ch);
extern t_bool sch_blk (uint32 dev);
extern uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea);
extern uint32 f_fix32 (uint32 op, uint32 r1, uint32 r2);
extern uint32 f_flt32 (uint32 op, uint32 r1, uint32 r2);
/* Instruction decoding table */
const uint16 decrom[256] = {
0, /* 00 */
OP_RR, /* BALR */
OP_RR, /* BTCR */
OP_RR, /* BFCR */
OP_RR, /* NR */
OP_RR, /* CLR */
OP_RR, /* OR */
OP_RR, /* XR */
OP_RR, /* LR */
OP_RR, /* CR */
OP_RR, /* AR */
OP_RR, /* SR */
OP_RR, /* MHR */
OP_RR, /* DHR */
0, 0, /* 0E:0F */
OP_NO, /* SRLS */
OP_NO, /* SLLS */
OP_RR, /* CHVR */
0, 0, 0, 0, 0, /* 13:17 */
OP_RR | OP_PRV, /* LPSWR */
0, 0, 0, /* 19:1B */
OP_RR, /* MR */
OP_RR, /* DR */
0, 0, /* 1E:1F */
OP_NO, /* BTBS */
OP_NO, /* BTFS */
OP_NO, /* BFBS */
OP_NO, /* BFFS */
OP_NO, /* LIS */
OP_NO, /* LCS */
OP_NO, /* AIS */
OP_NO, /* SIS */
OP_NO, /* LER */
OP_NO, /* CER */
OP_NO, /* AER */
OP_NO, /* SER */
OP_NO, /* MER */
OP_NO, /* DER */
OP_NO, /* FXR */
OP_NO, /* FLR */
0, /* MPBSR - 8/32C */
0, /* 31 */
0, /* PBR - 8/32C */
0, /* 33 */
OP_RR, /* EXHR */
0, 0, 0, /* 35:37 */
OP_NO | OP_DPF, /* LDR */
OP_NO | OP_DPF, /* CDR */
OP_NO | OP_DPF, /* ADR */
OP_NO | OP_DPF, /* SDR */
OP_NO | OP_DPF, /* MDR */
OP_NO | OP_DPF, /* DDR */
OP_NO | OP_DPF, /* FXDR */
OP_NO | OP_DPF, /* FLDR */
OP_RX, /* STH */
OP_RX, /* BAL */
OP_RX, /* BTC */
OP_RX, /* BFC */
OP_RXH, /* NH */
OP_RXH, /* CLH */
OP_RXH, /* OH */
OP_RXH, /* XH */
OP_RXH, /* LH */
OP_RXH, /* CH */
OP_RXH, /* AH */
OP_RXH, /* SH */
OP_RXH, /* MH */
OP_RXH, /* DH */
0, 0, /* 4E:4F */
OP_RX, /* ST */
OP_RXF, /* AM */
0, 0, /* 52:53 */
OP_RXF, /* N */
OP_RXF, /* CL */
OP_RXF, /* O */
OP_RXF, /* X */
OP_RXF, /* L */
OP_RXF, /* C */
OP_RXF, /* A */
OP_RXF, /* S */
OP_RXF, /* M */
OP_RXF, /* D */
OP_RX, /* CRC12 */
OP_RX, /* CRC16 */
OP_RX, /* STE */
OP_RXH, /* AHM */
0, /* PB - 8/32C */
OP_RX, /* LRA */
OP_RX, /* ATL */
OP_RX, /* ABL */
OP_RX, /* RTL */
OP_RX, /* RBL */
OP_RX, /* LE */
OP_RX, /* CE */
OP_RX, /* AE */
OP_RX, /* SE */
OP_RX, /* ME */
OP_RX, /* DE */
0, 0, /* 6E:6F */
OP_RX | OP_DPF, /* STD */
OP_RX, /* SME */
OP_RX, /* LME */
OP_RX, /* LHL */
OP_RX, /* TBT */
OP_RX, /* SBT */
OP_RX, /* RBT */
OP_RX, /* CBT */
OP_RX | OP_DPF, /* LD */
OP_RX | OP_DPF, /* CD */
OP_RX | OP_DPF, /* AD */
OP_RX | OP_DPF, /* SD */
OP_RX | OP_DPF, /* MD */
OP_RX | OP_DPF, /* DD */
OP_RX | OP_DPF, /* STMD */
OP_RX | OP_DPF, /* LMD */
0, 0, 0, 0, 0, 0, 0, 0, /* 80:8F */
0, 0, 0, 0, 0, 0, 0, 0,
OP_NO, /* SRHLS */
OP_NO, /* SLHLS */
OP_NO, /* STBR */
OP_NO, /* LDBR */
OP_NO, /* EXBR */
OP_NO | OP_PRV, /* EPSR */
OP_RR | OP_PRV, /* WBR */
OP_RR | OP_PRV, /* RBR */
OP_RR | OP_PRV, /* WHR */
OP_RR | OP_PRV, /* RHR */
OP_RR | OP_PRV, /* WDR */
OP_RR | OP_PRV, /* RDR */
0, /* 9C */
OP_RR | OP_PRV, /* SSR */
OP_RR | OP_PRV, /* OCR */
0, /* 9F */
0, 0, 0, 0, 0, 0, 0, 0, /* A0:AF */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, /* B0:BF */
0, 0, 0, 0, 0, 0, 0, 0,
OP_RX, /* BXH */
OP_RX, /* BXLE */
OP_RXF | OP_PRV, /* LPSW */
OP_RI1, /* THI */
OP_RI1, /* NHI */
OP_RI1, /* CLHI */
OP_RI1, /* OHI */
OP_RI1, /* XHI */
OP_RI1, /* LHI */
OP_RI1, /* CHI */
OP_RI1, /* AHI */
OP_RI1, /* SHI */
OP_RI1, /* SRHL */
OP_RI1, /* SLHL */
OP_RI1, /* SRHA */
OP_RI1, /* SLHA */
OP_RX, /* STM */
OP_RX, /* LM */
OP_RX, /* STB */
OP_RX, /* LDB */
OP_RX, /* CLB */
OP_RX | OP_PRV, /* AL */
OP_RXF | OP_PRV, /* WB */
OP_RXF | OP_PRV, /* RB */
OP_RX | OP_PRV, /* WH */
OP_RX | OP_PRV, /* RH */
OP_RX | OP_PRV, /* WD */
OP_RX | OP_PRV, /* RD */
0, /* DC */
OP_RX | OP_PRV, /* SS */
OP_RX | OP_PRV, /* OC */
0, /* DF */
OP_RXH, /* TS */
OP_RX, /* SVC */
OP_RI1 | OP_PRV, /* SINT */
OP_RX | OP_PRV, /* SCP */
0, 0, /* E4:E5 */
OP_RX, /* LA */
OP_RXF, /* TLATE */
0, 0, /* E8:E9 */
OP_RI1, /* RRL */
OP_RI1, /* RLL */
OP_RI1, /* SRL */
OP_RI1, /* SLL */
OP_RI1, /* SRA */
OP_RI1, /* SLA */
0, 0, 0, /* F0:F2 */
OP_RI2, /* TI */
OP_RI2, /* NI */
OP_RI2, /* CLI */
OP_RI2, /* OI */
OP_RI2, /* XI */
OP_RI2, /* LI */
OP_RI2, /* CI */
OP_RI2, /* AI */
OP_RI2, /* SI */
0, 0, 0, 0 }; /* FC:FF */
/* CPU data structures
cpu_dev CPU device descriptor
cpu_unit CPU unit descriptor
cpu_reg CPU register list
cpu_mod CPU modifiers list
*/
DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX | UNIT_BINK, MAXMEMSIZE32) };
REG cpu_reg[] = {
{ HRDATA (PC, PC, 20) },
{ HRDATA (OPC, oPC, 20), REG_HRO },
{ HRDATA (R0, GREG[0], 32) },
{ HRDATA (R1, GREG[1], 32) },
{ HRDATA (R2, GREG[2], 32) },
{ HRDATA (R3, GREG[3], 32) },
{ HRDATA (R4, GREG[4], 32) },
{ HRDATA (R5, GREG[5], 32) },
{ HRDATA (R6, GREG[6], 32) },
{ HRDATA (R7, GREG[7], 32) },
{ HRDATA (R8, GREG[8], 32) },
{ HRDATA (R9, GREG[9], 32) },
{ HRDATA (R10, GREG[10], 32) },
{ HRDATA (R11, GREG[11], 32) },
{ HRDATA (R12, GREG[12], 32) },
{ HRDATA (R13, GREG[13], 32) },
{ HRDATA (R14, GREG[14], 32) },
{ HRDATA (R15, GREG[15], 32) },
{ HRDATA (FR0, F[0], 32) },
{ HRDATA (FR2, F[1], 32) },
{ HRDATA (FR4, F[2], 32) },
{ HRDATA (FR6, F[3], 32) },
{ HRDATA (FR8, F[4], 32) },
{ HRDATA (FR10, F[5], 32) },
{ HRDATA (FR12, F[6], 32) },
{ HRDATA (FR14, F[7], 32) },
{ HRDATA (D0H, D[0].h, 32) },
{ HRDATA (D0L, D[0].l, 32) },
{ HRDATA (D2H, D[1].h, 32) },
{ HRDATA (D2L, D[1].l, 32) },
{ HRDATA (D4H, D[2].h, 32) },
{ HRDATA (D4L, D[2].l, 32) },
{ HRDATA (D6H, D[3].h, 32) },
{ HRDATA (D6L, D[3].l, 32) },
{ HRDATA (D8H, D[4].h, 32) },
{ HRDATA (D8L, D[4].l, 32) },
{ HRDATA (D10H, D[5].h, 32) },
{ HRDATA (D10L, D[5].l, 32) },
{ HRDATA (D12L, D[6].l, 32) },
{ HRDATA (D12H, D[6].h, 32) },
{ HRDATA (D14H, D[7].h, 32) },
{ HRDATA (D14L, D[7].l, 32) },
{ HRDATA (PSW, PSW, 16) },
{ HRDATA (CC, PSW, 4) },
{ HRDATA (SR, SR, 32) },
{ HRDATA (DR, DR, 32) },
{ HRDATA (DRX, DRX, 8) },
{ FLDATA (DRMOD, drmod, 0) },
{ FLDATA (SRPOS, srpos, 0) },
{ HRDATA (DRPOS, drpos, 3) },
{ BRDATA (IRQ, int_req, 16, 32, INTSZ) },
{ BRDATA (IEN, int_enb, 16, 32, INTSZ) },
{ BRDATA (MACREG, mac_reg, 16, 32, MAC_LNT) },
{ HRDATA (MACSTA, mac_sta, 5) },
{ HRDATA (QEVENT, qevent, 4), REG_HRO },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (STOP_WAIT, stop_wait, 0) },
{ BRDATA (PCQ, pcq, 16, 20, PCQ_SIZE), REG_RO+REG_CIRC },
{ HRDATA (PCQP, pcq_p, 6), REG_HRO },
{ HRDATA (WRU, sim_int_char, 8) },
{ HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN },
{ HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO },
{ HRDATA (BLKIOC, blk_io.cur, 20), REG_HRO },
{ HRDATA (BLKIOE, blk_io.end, 20), REG_HRO },
{ BRDATA (GREG, GREG, 16, 32, 16 * NRSETS) },
{ NULL } };
MTAB cpu_mod[] = {
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
{ UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size },
{ UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size },
{ UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size },
{ UNIT_TYPE, 0, "7/32, single precision fp", "732", NULL },
{ UNIT_DPFP, UNIT_DPFP, NULL, "DPFP", NULL },
{ UNIT_TYPE, UNIT_DPFP, "7/32, double precision fp", NULL, NULL },
{ UNIT_TYPE, UNIT_DPFP | UNIT_832, "8/32", "832", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
&cpu_set_consint, NULL, NULL },
{ 0 } };
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 16, 20, 1, 16, 8,
&cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL,
&cpu_dib, 0 };
t_stat sim_instr (void)
{
volatile uint32 cc; /* set before setjmp */
t_stat reason; /* set after setjmp */
int abortval;
/* Restore register state */
if (devtab_init ()) return SCPE_STOP; /* check conflicts */
if (cpu_unit.flags & (UNIT_DPFP | UNIT_832)) {
fp_in_hwre = 1; /* fp in hwre */
dec_flgs = 0; } /* all instr ok */
else { fp_in_hwre = 0; /* fp in ucode */
dec_flgs = OP_DPF; } /* sp only */
int_eval (); /* eval interrupts */
cc = newPSW (PSW & PSW_MASK); /* split PSW, eval wait */
sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */
sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */
sim_rtcn_init (pas_unit.wait, TMR_PAS); /* init pas */
reason = 0;
/* Abort handling
If an abort occurs in memory protection, the relocation routine
executes a longjmp to this area OUTSIDE the main simulation loop.
Memory protection errors are the only sources of aborts in the
Interdata 32b systems. All referenced variables must be globals,
and all sim_instr scoped automatic variables must be volatile or
set after the call on setjmp.
*/
abortval = setjmp (save_env); /* set abort hdlr */
if (abortval != 0) { /* mem mgt abort? */
qevent = qevent | EV_MAC; /* set MAC intr */
if (cpu_unit.flags & UNIT_832) PC = oPC; } /* 832? restore PC */
/* Event handling */
while (reason == 0) { /* loop until halted */
uint32 dev, drom, opnd, inc, lim, bufa;
uint32 op, r1, r1p1, r2, rx2, ea;
uint32 mpy, mpc, dvr;
uint32 i, rslt, rlo, t;
int32 sr, st;
if (sim_interval <= 0) { /* check clock queue */
if (reason = sim_process_event ()) break;
int_eval (); }
if (qevent) { /* any events? */
if (qevent & EV_MAC) { /* MAC interrupt? */
qevent = 0; /* clr all events */
cc = exception (MPRPSW, cc, 0); /* take exception */
int_eval (); /* re-eval intr */
continue; }
if (qevent & EV_BLK) { /* block I/O in prog? */
dev = blk_io.dfl & DEV_MAX; /* get device */
cc = dev_tab[dev] (dev, IO_SS, 0) & 0xF; /* sense status */
if (cc == STA_BSY) { /* just busy? */
sim_interval = 0; /* force I/O event */
continue; }
else if (cc == 0) { /* ready, no err? */
if (blk_io.dfl & BL_RD) { /* read? */
t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
if ((t == 0) && (blk_io.dfl & BL_LZ)) continue;
blk_io.dfl = blk_io.dfl & ~BL_LZ; /* non-zero seen */
WriteB (blk_io.cur, t, VW); } /* write mem */
else { /* write */
t = ReadB (blk_io.cur, VR); /* read mem */
dev_tab[dev] (dev, IO_WD, t); } /* put byte */
if (blk_io.cur != blk_io.end) { /* more to do? */
blk_io.cur = (blk_io.cur + 1) & VAMASK; /* incr addr */
continue; } }
qevent = qevent & ~EV_BLK; /* clr blk I/O flag */
int_eval (); /* re-eval intr */
continue; }
if ((qevent & EV_INT) && (PSW & PSW_EXI)) { /* interrupt? */
dev = int_getdev (); /* get int dev */
cc = int_auto (dev, cc); /* do auto intr */
int_eval (); /* re-eval intr */
continue; }
if (PSW & PSW_WAIT) { /* wait state? */
t = sim_qcount (); /* events in queue */
if ((t == 0) || ((t == 1) && stop_wait)) /* empty, or kbd only? */
reason = STOP_WAIT; /* then stop */
else sim_interval = 0; /* force check */
continue; }
qevent = 0; } /* no events */
/* Instruction fetch and decode */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
sim_interval = sim_interval - 1;
t = ReadH (oPC = PC, VE); /* fetch instr */
op = (t >> 8) & 0xFF; /* extract op,R1,R2 */
r1 = (t >> 4) & 0xF;
r2 = t & 0xF;
drom = decrom[op]; /* get decode flags */
if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */
if (stop_inst) reason = STOP_RSRV; /* stop or */
else cc = exception (ILOPSW, cc, 0); /* exception */
continue; }
if ((drom & OP_PRV) && (PSW & PSW_PRO)) { /* priv & protected? */
cc = exception (ILOPSW, cc, 0); /* exception */
continue; }
switch (drom & OP_MASK) { /* decode instruction */
case OP_NO: /* no operand */
opnd = r2; /* assume short */
PC = (PC + 2) & VAMASK; /* increment PC */
break;
case OP_RR: /* reg-reg */
ea = opnd = R[r2]; /* operand is R2 */
PC = (PC + 2) & VAMASK; /* increment PC */
break;
case OP_RI1: /* reg-imm 1 */
t = ReadH ((PC + 2) & VAMASK, VE); /* fetch immed */
opnd = SEXT16 (t); /* sign extend */
if (r2) opnd = (opnd + R[r2]) & DMASK32; /* index calculation */
PC = (PC + 4) & VAMASK; /* increment PC */
break;
case OP_RI2: /* reg-imm 2 */
t = ReadH ((PC + 2) & VAMASK, VE); /* fetch imm hi */
opnd = t << 16; /* shift to place */
t = ReadH ((PC + 4) & VAMASK, VE); /* fetch imm lo */
opnd = opnd | t; /* complete imm */
if (r2) opnd = (opnd + R[r2]) & DMASK32; /* index calculation */
PC = (PC + 6) & VAMASK; /* increment PC */
break;
case OP_RX: case OP_RXH: case OP_RXF: /* reg-mem */
t = ReadH ((PC + 2) & VAMASK, VE); /* fetch addr */
if ((t & 0xC000) == 0) { /* displacement? */
PC = (PC + 4) & VAMASK; /* increment PC */
ea = t; } /* abs 14b displ */
else if (t & 0x8000) { /* relative? */
PC = (PC + 4) & VAMASK; /* increment PC */
ea = PC + SEXT15 (t); } /* add to incr PC */
else { /* absolute */
rx2 = (t >> 8) & 0xF; /* get second index */
ea = (t & 0xFF) << 16; /* shift to place */
t = ReadH ((PC + 4) & VAMASK, VE); /* fetch addr lo */
ea = ea | t; /* finish addr */
if (rx2) ea = ea + R[rx2]; /* index calc 2 */
PC = (PC + 6) & VAMASK; } /* increment PC */
if (r2) ea = ea + R[r2]; /* index calculation */
ea = ea & VAMASK;
if ((drom & OP_MASK) == OP_RXF) /* get fw operand? */
opnd = ReadF (ea, VR); /* read fullword */
else if ((drom & OP_MASK) == OP_RXH) { /* get hw operand? */
t = ReadH (ea, VR); /* read halfword */
opnd = SEXT16 (t); } /* sign extend */
else opnd = ea; /* for sloppy code */
break;
case OP_UNDEF:
return SCPE_IERR; }
if (qevent & EV_MAC) continue; /* MAC abort on fetch? */
switch (op) { /* case on opcode */
/* Load/store instructions */
case 0x08: /* LR - RR */
case 0x24: /* LIS - NO */
case 0x48: /* LH - RXH */
case 0x58: /* L - RXF */
case 0xC8: /* LHI - RI1 */
case 0xF8: /* LI - RI2 */
R[r1] = opnd; /* load operand */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0x73: /* LHL - RX */
R[r1] = ReadH (ea, VR); /* get op, zero ext */
CC_GL_32 (R[r1]); /* set G, L */
break;
case 0x25: /* LCS - NO */
R[r1] = NEG (opnd); /* load complement */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0xE6: /* LA - RX */
R[r1] = ea; /* load addr */
break;
case 0x63: /* LRA - RX */
cc = RelocT (R[r1] & VAMASK, ea, VR, &R[r1]); /* test reloc */
break;
case 0x40: /* STH - RX */
WriteH (ea, R[r1] & DMASK16, VW); /* store register */
break;
case 0x50: /* ST - RX */
WriteF (ea, R[r1], VW); /* store register */
break;
case 0xD1: /* LM - RX */
for ( ; r1 <= 0xF; r1++) { /* loop thru reg */
R[r1] = ReadF (ea, VR); /* load register */
ea = (ea + 4) & VAMASK; } /* incr mem addr */
break;
case 0xD0: /* STM - RX */
for ( ; r1 <= 0xF; r1++) { /* loop thru reg */
WriteF (ea, R[r1], VW); /* store register */
ea = (ea + 4) & VAMASK; } /* incr mem addr */
break;
case 0xE0: /* TS - RXH */
CC_GL_16 (opnd); /* set cc's */
WriteH (ea, opnd | SIGN16, VW); /* set MSB */
break;
case 0x93: /* LDBR - NO */
R[r1] = R[r2] & DMASK8; /* load byte */
break;
case 0xD3: /* LDB - RX */
R[r1] = ReadB (ea, VR); /* load byte */
break;
case 0x92: /* STBR - NO */
R[r2] = (R[r2] & ~DMASK8) | (R[r1] & DMASK8); /* store byte */
break;
case 0xD2: /* STB - RX */
WriteB (ea, R[r1] & DMASK8, VW); /* store byte */
break;
case 0x34: /* EXHR - NO */
R[r1] = ((R[r2] >> 16) & DMASK16) | ((R[r2] & DMASK16) << 16);
break;
case 0x94: /* EXBR - NO */
R[r1] = (R[r1] & ~DMASK16) |
((R[r2] >> 8) & DMASK8) | ((R[r2] & DMASK8) << 8);
break;
/* Control instructions */
case 0x01: /* BALR - RR */
case 0x41: /* BAL - RX */
PCQ_ENTRY; /* save old PC */
R[r1] = PC; /* save cur PC */
PC = ea; /* branch */
break;
case 0x02: /* BTCR - RR */
case 0x42: /* BTC - RX */
if (cc & r1) { /* test CC's */
PCQ_ENTRY; /* branch if true */
PC = ea; }
break;
case 0x20: /* BTBS - NO */
if (cc & r1) { /* test CC's */
PCQ_ENTRY; /* branch if true */
PC = (oPC - r2 - r2) & VAMASK; }
break;
case 0x21: /* BTFS - NO */
if (cc & r1) { /* test CC's */
PCQ_ENTRY; /* branch if true */
PC = (oPC + r2 + r2) & VAMASK; }
break;
case 0x03: /* BFCR - RR */
case 0x43: /* BFC - RX */
if ((cc & r1) == 0) { /* test CC's */
PCQ_ENTRY; /* branch if false */
PC = ea; }
break;
case 0x22: /* BFBS - NO */
if ((cc & r1) == 0) { /* test CC's */
PCQ_ENTRY; /* branch if false */
PC = (oPC - r2 - r2) & VAMASK; }
break;
case 0x23: /* BFFS - NO */
if ((cc & r1) == 0) { /* test CC's */
PCQ_ENTRY; /* branch if false */
PC = (oPC + r2 + r2) & VAMASK; }
break;
case 0xC0: /* BXH - RX */
inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */
lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */
R[r1] = (R[r1] + inc) & DMASK32; /* R1 = R1 + inc */
if (R[r1] > lim) { /* if R1 > lim */
PCQ_ENTRY; /* branch */
PC = ea; }
break;
case 0xC1: /* BXLE - RS */
inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */
lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */
R[r1] = (R[r1] + inc) & DMASK32; /* R1 = R1 + inc */
if (R[r1] <= lim) { /* if R1 <= lim */
PCQ_ENTRY; /* branch */
PC = ea; }
break;
/* Logical instructions */
case 0x04: /* NR - RR */
case 0x44: /* NH - RXH */
case 0x54: /* N - RXF */
case 0xC4: /* NHI - RI1 */
case 0xF4: /* NI - RI2 */
R[r1] = R[r1] & opnd; /* result */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0x06: /* OR - RR */
case 0x46: /* OH - RXH */
case 0x56: /* O - RXF */
case 0xC6: /* OHI - RI1 */
case 0xF6: /* OI - RI2 */
R[r1] = R[r1] | opnd; /* result */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0x07: /* XR - RR */
case 0x47: /* XH - RXH */
case 0x57: /* X - RXF */
case 0xC7: /* XHI - RI1 */
case 0xF7: /* XI - RI2 */
R[r1] = R[r1] ^ opnd; /* result */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0xC3: /* THI - RI1 */
case 0xF3: /* TI - RI2 */
rslt = R[r1] & opnd; /* result */
CC_GL_32 (rslt); /* set G, L */
break;
case 0x05: /* CLR - RR */
case 0x45: /* CLH - RXH */
case 0x55: /* CL - RXF */
case 0xC5: /* CLHI - RI1 */
case 0xF5: /* CI - RI2 */
rslt = (R[r1] - opnd) & DMASK32; /* result */
CC_GL_32 (rslt); /* set G,L */
if (R[r1] < opnd) cc = cc | CC_C; /* set C if borrow */
if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) cc = cc | CC_V;
break;
case 0xD4: /* CLB - RX */
opnd = ReadB (ea, VR); /* get operand */
t = R[r1] & DMASK8;
rslt = (t - opnd) & DMASK16; /* result */
CC_GL_16 (rslt); /* set G,L 16b */
if (t < opnd) cc = cc | CC_C; /* set C if borrow */
break;
case 0x12: /* CHVR - RR */
t = cc & CC_C; /* save C */
R[r1] = (SEXT16 (opnd & DMASK16)) & DMASK32; /* result */
CC_GL_32 (R[r1]); /* set G, L */
if (R[r1] != opnd) cc = cc | CC_V; /* wont fit? set V */
cc = cc | t; /* restore C */
break;
/* Shift instructions */
case 0xCC: /* SRHL - RI1 */
opnd = opnd & 0xF; /* shift count */
case 0x90: /* SRHLS - NO */
rslt = (R[r1] & DMASK16) >> opnd; /* result */
CC_GL_16 (rslt); /* set G,L 16b */
if (opnd && (((R[r1] & DMASK16) >> (opnd - 1)) & 1)) cc = cc | CC_C;
R[r1] = (R[r1] & ~DMASK16) | rslt; /* store result */
break;
case 0xCD: /* SLHL - RI1 */
opnd = opnd & 0xF; /* shift count */
case 0x91: /* SLHLS - NO */
rslt = R[r1] << opnd; /* result */
CC_GL_16 (rslt & DMASK16); /* set G,L 16b */
if (opnd && (rslt & 0x10000)) cc = cc | CC_C; /* set C if shft out */
R[r1] = (R[r1] & ~DMASK16) | (rslt & DMASK16); /* store result */
break;
case 0xCE: /* SRHA - RI1 */
opnd = opnd & 0xF; /* shift count */
rslt = (SEXT16 (R[r1]) >> opnd) & DMASK16; /* result */
CC_GL_16 (rslt); /* set G,L 16b */
if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
R[r1] = (R[r1] & ~DMASK16) | rslt; /* store result */
break;
case 0xCF: /* SLHA - RI1 */
opnd = opnd & 0xF; /* shift count */
rslt = R[r1] << opnd; /* raw result */
R[r1] = (R[r1] & ~MMASK16) | (rslt & MMASK16);
CC_GL_16 (R[r1] & DMASK16); /* set G,L 16b */
if (opnd && (rslt & SIGN16)) cc = cc | CC_C; /* set C if shft out */
break;
case 0xEC: /* SRL - RI1 */
opnd = opnd & 0x1F; /* shift count */
case 0x10: /* SRLS - NO */
rslt = R[r1] >> opnd; /* result */
CC_GL_32 (rslt); /* set G,L */
if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
R[r1] = rslt; /* store result */
break;
case 0xED: /* SLL - RI1 */
opnd = opnd & 0x1F; /* shift count */
case 0x11: /* SLLS - NO */
rslt = (R[r1] << opnd) & DMASK32; /* result */
CC_GL_32 (rslt); /* set G,L */
if (opnd && ((R[r1] << (opnd - 1)) & SIGN32)) cc = cc | CC_C;
R[r1] = rslt; /* store result */
break;
case 0xEE: /* SRA - RI1 */
opnd = opnd & 0x1F; /* shift count */
rslt = (SEXT32 (R[r1]) >> opnd) & DMASK32; /* result */
CC_GL_32 (rslt); /* set G,L */
if (opnd && ((R[r1] >> (opnd - 1)) & 1)) cc = cc | CC_C;
R[r1] = rslt; /* store result */
break;
case 0xEF: /* SLA - RI1 */
opnd = opnd & 0x1F; /* shift count */
rslt = (R[r1] << opnd) & DMASK32; /* raw result */
R[r1] = (R[r1] & SIGN32) | (rslt & MMASK32); /* arith result */
CC_GL_32 (R[r1]); /* set G,L */
if (opnd && (rslt & SIGN32)) cc = cc | CC_C; /* set C if shft out */
break;
case 0xEA: /* RRL - RI1 */
opnd = opnd & 0x1F; /* shift count */
if (opnd) R[r1] = (R[r1] >> opnd) | /* if cnt > 0 */
((R[r1] << (32 - opnd)) & DMASK32); /* rotate */
CC_GL_32 (R[r1]); /* set G,L */
break;
case 0xEB: /* RLL - RI1 */
opnd = opnd & 0x1F; /* shift count */
if (opnd) R[r1] = ((R[r1] << opnd) & DMASK32) | /* if cnt > 0 */
(R[r1] >> (32 - opnd)); /* rotate */
CC_GL_32 (R[r1]); /* set G,L */
break;
/* Bit instructions */
case 0x74: /* TBT - RX */
t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */
ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */
opnd = ReadH (ea, VR); /* read HW */
if (opnd & t) cc = CC_G; /* test bit */
else cc = 0;
break;
case 0x75: /* SBT - RX */
t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */
ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */
opnd = ReadH (ea, VR); /* read HW */
WriteH (ea, opnd | t, VW); /* set bit, rewr */
if (opnd & t) cc = CC_G; /* test bit */
else cc = 0;
break;
case 0x76: /* RBT - RX */
t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */
ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */
opnd = ReadH (ea, VR); /* read HW */
WriteH (ea, opnd & ~t, VW); /* clr bit, rewr */
if (opnd & t) cc = CC_G; /* test bit */
else cc = 0;
break;
case 0x77: /* CBT - RX */
t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */
ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */
opnd = ReadH (ea, VR); /* read HW */
WriteH (ea, opnd ^ t, VW); /* com bit, rewr */
if (opnd & t) cc = CC_G; /* test bit */
else cc = 0;
break;
/* Arithmetic instructions */
case 0x0A: /* AR - RR */
case 0x26: /* AIS - NO */
case 0x4A: /* AH - RXH */
case 0x5A: /* A - RXF */
case 0xCA: /* AHI - RI1 */
case 0xFA: /* AI - RI2 */
rslt = (R[r1] + opnd) & DMASK32; /* result */
CC_GL_32 (rslt); /* set G,L */
if (rslt < opnd) cc = cc | CC_C; /* set C if carry */
if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN32) cc = cc | CC_V;
R[r1] = rslt;
break;
case 0x51: /* AM - RXF */
rslt = (R[r1] + opnd) & DMASK32; /* result */
WriteF (ea, rslt, VW); /* write result */
CC_GL_32 (rslt); /* set G,L */
if (rslt < opnd) cc = cc | CC_C; /* set C if carry */
if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN32) cc = cc | CC_V;
break;
case 0x61: /* AHM - RXH */
rslt = (R[r1] + opnd) & DMASK16; /* result */
WriteH (ea, rslt, VW); /* write result */
CC_GL_16 (rslt); /* set G,L 16b */
if (rslt < (opnd & DMASK16)) cc = cc | CC_C; /* set C if carry */
if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) cc = cc | CC_V;
break;
case 0x0B: /* SR - RR */
case 0x27: /* SIS - NO */
case 0x4B: /* SH - RXH */
case 0x5B: /* S - RXF */
case 0xCB: /* SHI - RI1 */
case 0xFB: /* SI - RI2 */
rslt = (R[r1] - opnd) & DMASK32; /* result */
CC_GL_32 (rslt); /* set G,L */
if (R[r1] < opnd) cc = cc | CC_C; /* set C if borrow */
if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) cc = cc | CC_V;
R[r1] = rslt;
break;
case 0x09: /* CR - RR */
case 0x49: /* CH - RXH */
case 0x59: /* C - RXF */
case 0xC9: /* CHI - RI1 */
case 0xF9: /* CI - RI2 */
if (R[r1] == opnd) cc = 0; /* =? */
else if ((R[r1] ^ opnd) & SIGN32) /* unlike signs? */
cc = (R[r1] & SIGN32)? (CC_C | CC_L): CC_G;
else cc = (R[r1] > opnd)? CC_G: (CC_C | CC_L); /* like signs */
if (((R[r1] ^ opnd) & (~opnd ^ (R[r1] - opnd))) & SIGN32)
cc = cc | CC_V;
break;
case 0x0C: /* MHR - RR */
case 0x4C: /* MH - RXH */
R[r1] = (SEXT16 (R[r1]) * SEXT16 (opnd)) & DMASK32; /* multiply */
break;
case 0x1C: /* MR - RR */
case 0x5C: /* M - RXF */
r1p1 = (r1 + 1) & 0xF;
mpc = ABS (opnd); /* |mpcnd| */
mpy = ABS (R[r1p1]); /* |mplyr| */
rslt = rlo = 0; /* clr result */
for (i = 0; i < 32; i++) { /* develop 32b */
t = 0; /* no cout */
if (mpy & 1) { /* cond add */
rslt = (rslt + mpc) & DMASK32;
if (rslt < mpc) t = SIGN32; }
rlo = (rlo >> 1) | ((rslt & 1) << 31); /* shift result */
rslt = (rslt >> 1) | t;
mpy = mpy >> 1; } /* shift mpylr */
if ((opnd ^ R[r1p1]) & SIGN32) {
DNEG (rslt, rlo); }
R[r1] = rslt; /* store result */
R[r1p1] = rlo;
break;
case 0x0D: /* DHR - RR */
case 0x4D: /* DH - RXH */
r1p1 = (r1 + 1) & 0xF;
opnd = opnd & DMASK16; /* force HW opnd */
if (opnd) { /* if divisor != 0 */
st = SEXT32 (R[r1]) / SEXT16 (opnd); /* quotient */
sr = SEXT32 (R[r1]) % SEXT16 (opnd); } /* remainder */
if (opnd && (st < 0x8000) && (st >= -0x8000)) { /* if quo fits */
R[r1] = sr & DMASK32; /* store remainder */
R[r1p1] = st & DMASK32; } /* store quotient */
else if (PSW & PSW_AFI) /* div fault enabled? */
cc = exception (AFIPSW, cc, 0); /* exception */
break;
case 0x1D: /* DR - RR */
case 0x5D: /* D - RXF */
r1p1 = (r1 + 1) & 0xF;
rslt = R[r1]; /* get dividend */
rlo = R[r1p1];
if (R[r1] & SIGN32) { DNEG (rslt, rlo); } /* |divd| */
dvr = ABS (opnd); /* |divr| */
if (rslt < dvr) { /* will div work? */
uint32 quos = R[r1] ^ opnd; /* expected sign */
for (i = t = 0; i < 32; i++) { /* 32 iterations */
rslt = ((rslt << 1) & DMASK32) | /* shift divd */
((rlo >> 31) & 1);
rlo = (rlo << 1) & DMASK32;
t = (t << 1) & DMASK32; /* shift quo */
if (rslt >= dvr) { /* subtract work? */
rslt = rslt - dvr; /* divd -= divr */
t = t | 1; } } /* set quo bit */
if (quos & SIGN32) t = NEG (t); /* res -? neg quo */
if (R[r1] & SIGN32) rslt = NEG (rslt); /* adj rem sign */
if (t && ((t ^ quos) & SIGN32)) { /* res sign wrong? */
if (PSW & PSW_AFI) /* if enabled, */
cc = exception (AFIPSW, cc, 0); /* exception */
break; }
R[r1] = rslt; /* store rem */
R[r1p1] = t; } /* store quo */
else if (PSW & PSW_AFI) /* div fault enabled? */
cc = exception (AFIPSW, cc, 0); /* exception */
break;
/* Floating point instructions */
case 0x28: /* LER - NO */
case 0x38: /* LDR - NO */
case 0x68: /* LE - RX */
case 0x78: /* LD - RX */
cc = f_l (op, r1, r2, ea); /* load */
if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */
cc = exception (AFIPSW, cc, 1);
break;
case 0x29: /* CER - NO */
case 0x39: /* CDR - NO */
case 0x69: /* CE - RX */
case 0x79: /* CD - RX */
cc = f_c (op, r1, r2, ea); /* compare */
break;
case 0x2A: /* AER - NO */
case 0x2B: /* SER - NO */
case 0x3A: /* ADR - NO */
case 0x3B: /* SDR - NO */
case 0x6A: /* AE - RX */
case 0x6B: /* SE - RX */
case 0x7A: /* AD - RX */
case 0x7B: /* SD - RX */
cc = f_as (op, r1, r2, ea); /* add/sub */
if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */
cc = exception (AFIPSW, cc, 1);
break;
case 0x2C: /* MER - NO */
case 0x3C: /* MDR - NO */
case 0x6C: /* ME - RX */
case 0x7C: /* MD - RX */
cc = f_m (op, r1, r2, ea); /* multiply */
if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */
cc = exception (AFIPSW, cc, 1);
break;
case 0x2D: /* DER - NO */
case 0x3D: /* DDR - NO */
case 0x6D: /* DE - RX */
case 0x7D: /* DD - RX */
cc = f_d (op, r1, r2, ea); /* perform divide */
if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */
cc = exception (AFIPSW, cc, 1);
break;
case 0x2E: /* FXR - NO */
case 0x3E: /* FXDR - NO */
cc = f_fix32 (op, r1, r2); /* cvt to integer */
break;
case 0x2F: /* FLR - NO */
case 0x3F: /* FLDR - NO */
cc = f_flt32 (op, r1, r2); /* cvt to floating */
break;
case 0x60: /* STE - RX */
t = ReadFReg (r1); /* get sp reg */
WriteF (ea, t, VW); /* write */
break;
case 0x70: /* STD - RX */
WriteF (ea, D[r1 >> 1].h, VW); /* write hi */
WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, VW); /* write lo */
break;
case 0x71: /* STME - RX */
for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
t = ReadFReg (r1); /* get sp reg */
WriteF (ea, t, VW); /* write */
ea = (ea + 4) & VAMASK; } /* incr mem addr */
break;
case 0x72: /* LME - RX */
for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
t = ReadF (ea, VR); /* get value */
WriteFReg (r1, t); /* write reg */
ea = (ea + 4) & VAMASK; } /* incr mem addr */
break;
case 0x7E: /* STMD - RX */
for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
WriteF (ea, D[r1 >> 1].h, VW); /* write register */
WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, VW);
ea = (ea + 8) & VAMASK; } /* incr mem addr */
break;
case 0x7F: /* LMD - RX */
for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */
D[r1 >> 1].h = ReadF (ea, VR); /* load register */
D[r1 >> 1].l = ReadF ((ea + 4) & VAMASK, VR);
ea = (ea + 8) & VAMASK; } /* incr mem addr */
break;
/* Miscellaneous */
case 0xE1: /* SVC - RX */
PCQ_ENTRY; /* effective branch */
t = BUILD_PSW (cc); /* save PSW */
cc = newPSW (ReadF (SVNPS32, P)); /* get new PSW */
R[13] = ea & 0xFFFFFF; /* parameter */
R[14] = t; /* old PSW */
R[15] = PC; /* old PC */
PC = ReadH (SVNPC + r1 + r1, P); /* new PC */
if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log,
">>SVC: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
pcq[pcq_p], t, PC, PSW);
break;
case 0xE2: /* SINT - RI1 */
dev = opnd & DEV_MAX; /* get dev */
cc = int_auto (dev, cc); /* auto int */
int_eval ();
break;
case 0xE3: /* SCP - RX */
opnd = ReadH (ea, VR); /* zero ext operand */
if (opnd & CCW32_B1) t = ea + CCB32_B1C; /* point to buf */
else t = ea + CCB32_B0C;
sr = ReadH (t & VAMASK, VR); /* get count */
sr = SEXT16 (sr); /* sign extend */
if (sr <= 0) { /* <= 0? */
bufa = ReadF ((t + 2) & VAMASK, VR); /* get buf end */
if (opnd & CCW32_WR) /* write? */
R[r1] = ReadB ((bufa + sr) & VAMASK, VR); /* R1 gets mem */
else WriteB ((bufa + sr) & VAMASK, R[r1], VW); /* read, R1 to mem */
sr = sr + 1; /* inc count */
CC_GL_32 (sr & DMASK32); /* set cc's */
WriteH (t & VAMASK, sr & DMASK16, VW); /* rewrite */
if ((sr > 0) && !(opnd & CCW32_FST)) /* buf switch? */
WriteH (ea, opnd ^ CCW32_B1, VW); /* flip CCW bit */
} /* end if */
else cc = CC_V;
break;
case 0x18: /* LPSWR - RR */
PCQ_ENTRY; /* effective branch */
PC = R[(r2 + 1) & 0xF] & VAMASK; /* new PC (old reg set) */
if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log,
">>LPSWR: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
pcq[pcq_p], BUILD_PSW (cc), PC, opnd);
cc = newPSW (opnd); /* new PSW */
if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
break;
case 0xC2: /* LPSW - RXF */
PCQ_ENTRY; /* effective branch */
PC = ReadF ((ea + 4) & VAMASK, VR) & VAMASK; /* new PC */
if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log,
">>LPSW: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
pcq[pcq_p], BUILD_PSW (cc), PC, opnd);
cc = newPSW (opnd); /* new PSW */
if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
break;
case 0x95: /* EPSR - NO */
R[r1] = BUILD_PSW (cc); /* save PSW */
cc = newPSW (R[r2]); /* load new PSW */
if (PSW & PSW_SQI) cc = testsysq (cc); /* test for q */
break;
case 0x64: /* ATL - RX */
case 0x65: /* ABL - RX */
cc = addtoq (ea, R[r1], op & 1); /* add to q */
break;
case 0x66: /* RTL - RX */
case 0x67: /* RBL - RX */
cc = remfmq (ea, r1, op & 1); /* rem from q */
break;
case 0x5E: /* CRC12 - RXH */
opnd = ReadH (ea, VR); /* zero ext opnd */
t = (R[r1] & 0x3F) ^ opnd;
for (i = 0; i < 6; i++) {
if (t & 1) t = (t >> 1) ^ 0x0F01;
else t = t >> 1; }
WriteH (ea, t, VW);
break;
case 0x5F: /* CRC16 - RXH */
opnd = ReadH (ea, VR); /* zero ext opnd */
t = (R[r1] & 0xFF) ^ opnd;
for (i = 0; i < 8; i++) {
if (t & 1) t = (t >> 1) ^ 0xA001;
else t = t >> 1; }
WriteH (ea, t, VW);
break;
case 0xE7: /* TLATE - RXF */
t = (opnd + ((R[r1] & DMASK8) << 1)) & VAMASK; /* table entry */
rslt = ReadH (t, VR); /* get entry */
if (rslt & SIGN16) R[r1] = rslt & DMASK8; /* direct xlate? */
else { PCQ_ENTRY; /* branch */
PC = rslt << 1; }
break;
/* I/O instructions */
case 0xDE: /* OC - RX */
opnd = ReadB (ea, VR); /* fetch operand */
case 0x9E: /* OCR - RR */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) {
dev_tab[dev] (dev, IO_ADR, 0); /* select */
dev_tab[dev] (dev, IO_OC, opnd & DMASK8); /* send command */
cc = 0; }
else cc = CC_V;
int_eval (); /* re-eval intr */
break;
case 0xDA: /* WD - RX */
opnd = ReadB (ea, VR); /* fetch operand */
case 0x9A: /* WDR - RR */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) {
dev_tab[dev] (dev, IO_ADR, 0); /* select */
dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send data */
cc = 0; }
else cc = CC_V;
int_eval (); /* re-eval intr */
break;
case 0xD8: /* WH - RX */
opnd = ReadH (ea, VR); /* fetch operand */
case 0x98: /* WHR - RR */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) {
if (dev_tab[dev] (dev, IO_ADR, 0)) /* select; hw ok? */
dev_tab[dev] (dev, IO_WH, opnd & DMASK16); /* send data */
else { /* byte only */
dev_tab[dev] (dev, IO_WD, (opnd >> 8) & DMASK8); /* hi */
dev_tab[dev] (dev, IO_WD, opnd & DMASK8); } /* send lo byte */
cc = 0; }
else cc = CC_V;
int_eval (); /* re-eval intr */
break;
case 0x9B: /* RDR - RR */
case 0xDB: /* RD - RX */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
dev_tab[dev] (dev, IO_ADR, 0); /* select */
t = dev_tab[dev] (dev, IO_RD, 0); /* get data */
cc = 0; }
else { /* no */
t = 0;
cc = CC_V; }
if (OP_TYPE (op) != OP_RR) WriteB (ea, t, VW); /* RX or RR? */
else R[r2] = t & DMASK8;
int_eval (); /* re-eval intr */
break;
case 0x99: /* RHR - RR */
case 0xD9: /* RH - RS */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
if (dev_tab[dev] (dev, IO_ADR, 0)) /* select, hw ok? */
t = dev_tab[dev] (dev, IO_RH, 0); /* get data */
else { /* byte only */
rslt = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
t = (rslt << 8) | t; } /* merge */
cc = 0; }
else { /* no */
t = 0;
cc = CC_V; }
if (OP_TYPE (op) != OP_RR) WriteH (ea, t, VW); /* RX or RR? */
else R[r2] = t & DMASK16;
int_eval (); /* re-eval intr */
break;
case 0x9D: /* SSR - RR */
case 0xDD: /* SS - RS */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
dev_tab[dev] (dev, IO_ADR, 0); /* select */
t = dev_tab[dev] (dev, IO_SS, 0); } /* get status */
else t = STA_EX; /* no */
if (OP_TYPE (op) != OP_RR) WriteB (ea, t, VW); /* RX or RR? */
else R[r2] = t & DMASK8;
cc = t & 0xF;
int_eval (); /* re-eval intr */
break;
/* Block I/O instructions
On a real Interdata system, the block I/O instructions can't be
interrupted or stopped. To model this behavior, while allowing
the instructions to go back through fetch for I/O processing and
WRU testing, the simulator implements a 'block I/O in progress'
flag and status block. If a block I/O is in progress, normal
interrupts and fetches are suppressed until the block I/O is done.
*/
case 0x96: /* WBR - RR */
case 0xD6: /* WB - RXF */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
if (OP_TYPE (op) != OP_RR)
lim = ReadF ((ea + 4) & VAMASK, VR);
else lim = R[(r2 + 1) & 0xF];
if (opnd > lim) cc = 0; /* start > end? */
else { /* no, start I/O */
dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
blk_io.dfl = dev; /* set status block */
blk_io.cur = opnd;
blk_io.end = lim;
qevent = qevent | EV_BLK; } } /* I/O in prog */
else cc = CC_V; /* nx dev */
break;
case 0x97: /* RBR - RR */
case 0xD7: /* RB - RXF */
dev = R[r1] & DEV_MAX;
if (DEV_ACC (dev)) { /* dev exist? */
if (OP_TYPE (op) != OP_RR)
lim = ReadF ((ea + 4) & VAMASK, VR);
else lim = R[(r2 + 1) & 0xF];
if (opnd > lim) cc = 0; /* start > end? */
else { /* no, start I/O */
dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
blk_io.dfl = dev | BL_RD; /* set status block */
blk_io.cur = opnd;
blk_io.end = lim;
qevent = qevent | EV_BLK; } } /* I/O in prog */
else cc = CC_V; /* nx dev */
break;
case 0xD5: /* AL - RX */
dev = ReadB (AL_DEV, P); /* get device */
t = ReadB (AL_IOC, P); /* get command */
if (DEV_ACC (dev)) { /* dev exist? */
if (AL_BUF > ea) cc = 0; /* start > end? */
else { /* no, start I/O */
dev_tab[dev] (dev, IO_ADR, 0); /* select dev */
dev_tab[dev] (dev, IO_OC, t); /* start dev */
blk_io.dfl = dev | BL_RD | BL_LZ; /* set status block */
blk_io.cur = AL_BUF;
blk_io.end = ea;
qevent = qevent | EV_BLK; } } /* I/O in prog */
else cc = CC_V; /* nx dev */
break; } /* end switch */
} /* end while */
/* Simulation halted */
PSW = BUILD_PSW (cc);
PC = PC & VAMASK;
set_r_display (R);
pcq_r->qptr = pcq_p; /* update pc q ptr */
return reason;
}
/* Load new PSW */
uint32 newPSW (uint32 val)
{
uint32 rs = PSW_GETREG (val); /* register set */
R = &GREG[rs * 16]; /* set register set */
PSW = val & PSW_MASK; /* store PSW */
int_eval (); /* update intreq */
if (PSW & PSW_WAIT) qevent = qevent | EV_WAIT; /* wait state? */
else qevent = qevent & ~EV_WAIT;
if (PSW & PSW_EXI) SET_ENB (v_DS); /* enable/disable */
else CLR_ENB (v_DS); /* console intr */
return PSW & CC_MASK;
}
/* Exception handler - 7/32 always uses register set 0 */
uint32 exception (uint32 loc, uint32 cc, uint32 flg)
{
int32 oldPSW = BUILD_PSW (cc); /* save old PSW */
int32 oldPC = PC; /* save old PC */
cc = newPSW (ReadF (loc, P)); /* new PSW */
PC = ReadF (loc + 4, P) & VAMASK; /* new PC */
if (cpu_unit.flags & UNIT_832) { /* 8/32? */
R[14] = oldPSW; /* PSW to new 14 */
R[15] = oldPC; } /* PC to new 15 */
else { GREG[14] = oldPSW; /* 7/32, PSW to set 0 14 */
GREG[15] = oldPC; } /* PC to set 0 15 */
if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log,
">>Exc %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
loc, oldPC, oldPSW, PC, PSW | cc | flg);
return cc | flg; /* return CC */
}
/* Test for queue interrupts - system queue addresses are physical */
uint32 testsysq (uint32 cc)
{
int32 qb = ReadF (SQP, P); /* get sys q addr */
int32 usd = ReadH (qb + Q32_USD, P); /* get use count */
if (usd) { /* entries? */
cc = exception (SQTPSW, cc, 0); /* take sysq exc */
if (cpu_unit.flags & UNIT_832) R[13] = qb; /* R13 = sys q addr */
else GREG[13] = qb; }
return cc;
}
/* Add to queue */
uint32 addtoq (uint32 ea, uint32 val, uint32 flg)
{
uint32 slt, usd, wra, t;
t = ReadF (ea, VR); /* slots/used */
slt = (t >> 16) & DMASK16; /* # slots */
usd = t & DMASK16; /* # used */
if (usd >= slt) return CC_V; /* list full? */
usd = (usd + 1) & DMASK16; /* inc # used */
WriteH (ea + Q32_USD, usd, VW); /* rewrite */
if (flg) { /* ABL? */
wra = ReadH ((ea + Q32_BOT) & VAMASK, VR); /* get bottom */
t = wra + 1; /* adv bottom */
if (t >= slt) t = 0; /* wrap if necc */
WriteH ((ea + Q32_BOT) & VAMASK, t, VW); } /* rewrite bottom */
else { wra = ReadH ((ea + Q32_TOP) & VAMASK, VR); /* ATL, get top */
if (wra == 0) wra = (slt - 1) & DMASK16; /* wrap if necc */
else wra = wra - 1; /* dec top */
WriteH ((ea + Q32_TOP) & VAMASK, wra, VW); } /* rewrite top */
WriteF ((ea + Q32_BASE + (wra * Q32_SLNT)) & VAMASK, val, VW); /* write slot */
return 0;
}
/* Remove from queue */
uint32 remfmq (uint32 ea, uint32 r1, uint32 flg)
{
uint32 slt, usd, rda, t;
t = ReadF (ea, VR); /* get slots/used */
slt = (t >> 16) & DMASK16; /* # slots */
usd = t & DMASK16; /* # used */
if (usd == 0) return CC_V; /* empty? */
usd = usd - 1; /* dec used */
WriteH (ea + Q32_USD, usd & DMASK16, VW); /* rewrite */
if (flg) { /* RBL? */
rda = ReadH ((ea + Q32_BOT) & VAMASK, VR); /* get bottom */
if (rda == 0) rda = (slt - 1) & DMASK16; /* wrap if necc */
else rda = rda - 1; /* dec bottom */
WriteH ((ea + Q32_BOT) & VAMASK, rda, VW); } /* rewrite bottom */
else { rda = ReadH ((ea + Q32_TOP) & VAMASK, VR); /* RTL, get top */
t = rda + 1; /* adv top */
if (t >= slt) t = 0; /* wrap if necc */
WriteH ((ea + Q32_TOP) & VAMASK, t, VW); } /* rewrite top */
R[r1] = ReadF ((ea + Q32_BASE + (rda * Q32_SLNT)) & VAMASK, VR); /* read slot */
if (usd) return CC_G;
else return 0;
}
/* Automatic interrupt processing */
uint32 int_auto (uint32 dev, uint32 cc)
{
uint32 addr, vec, by, ccw, ccwa, ccwb;
uint32 i, hw, tblad, tblen, bufe, st, t;
int32 bufc;
uint32 oldPSW = BUILD_PSW (cc);
vec = ReadH (INTSVT + dev + dev, P); /* get vector */
newPSW (0x2800); /* new PSW */
R[0] = oldPSW; /* save old PSW */
R[1] = PC; /* save PC */
R[2] = dev; /* set dev # */
if (DBG_LOG (LOG_CPU_C)) fprintf (sim_log,
">>Int %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n",
dev, PC, oldPSW, vec, 0x2800);
if (DEV_ACC (dev)) { /* dev exist? */
hw = dev_tab[dev] (dev, IO_ADR, 0); /* select, get hw */
R[3] = st = dev_tab[dev] (dev, IO_SS, 0); } /* sense status */
else { hw = 0;
R[3] = CC_V; }
if ((vec & 1) == 0) { /* immed int? */
PC = vec; /* new PC */
return PSW & CC_MASK; } /* exit */
R[4] = ccwa = vec & ~1; /* save CCW addr */
ccw = ReadH (ccwa, VR); /* read CCW */
if ((ccw & CCW32_EXE) == 0) { /* exec clr? */
PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */
return 0; } /* CC = 0 */
if (!DEV_ACC (dev) || (st & CCW32_STA (ccw))) { /* bad status? */
PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */
return CC_L; } /* CC = L */
if (ccw & CCW32_FST) { /* fast mode? */
t = ReadH (ccwa + CCB32_B0C, VR); /* get count */
bufc = SEXT16 (t); /* sign ext */
if (bufc <= 0) { /* still valid? */
bufe = ReadF (ccwa + CCB32_B0E, VR); /* get end addr */
addr = (bufe + bufc) & VAMASK;
if (hw) { /* halfword? */
if (ccw & CCW32_WR) { /* write? */
t = ReadH (addr, VR); /* get hw */
dev_tab[dev] (dev, IO_WH, t); } /* send to dev */
else { /* read */
t = dev_tab[dev] (dev, IO_RH, 0); /* get hw */
WriteH (addr, t, VW); } /* write to mem */
bufc = bufc + 2; } /* adv buf cnt */
else { /* byte */
if (ccw & CCW32_WR) { /* write? */
t = ReadB (addr, VR); /* get byte */
dev_tab[dev] (dev, IO_WD, t); } /* send to dev */
else { /* read */
t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */
WriteB (addr, t, VW); } /* write to mem */
bufc = bufc + 1; } /* adv buf cnt */
WriteH (ccwa + CCB32_B0C, bufc & DMASK16, VW);/* rewrite cnt */
if (bufc > 0) {
PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */
return CC_G; } /* CC = G */
} /* end if bufc <= 0 */
} /* end fast */
else { /* slow mode */
if (ccw & CCW32_B1) ccwb = ccwa + CCB32_B1C; /* which buf? */
else ccwb = ccwa + CCB32_B0C;
t = ReadH (ccwb, VR); /* get count */
bufc = SEXT16 (t); /* sign ext */
if (bufc <= 0) { /* still valid? */
bufe = ReadF (ccwb + 2, VR); /* get end addr */
addr = (bufe + bufc) & VAMASK;
if (ccw & CCW32_WR) { /* write? */
by = ReadB (addr, VR); /* byte fm mem */
if (ccw & CCW32_TL) { /* translate? */
tblad = ReadF (ccwa + CCB32_TAB, VR);/* get tbl addr */
tblen = (tblad + (by << 1)) & VAMASK; /* tbl entry addr */
t = ReadH (tblen, VR); /* get tbl entry */
if ((t & SIGN16) == 0) { /* special xlate? */
PC = t << 1; /* change PC */
R[3] = by; /* untrans char */
return 0; } /* CC = 0 */
by = t & DMASK8; } /* replace */
dev_tab[dev] (dev, IO_WD, by); } /* write to dev */
else { /* read */
by = dev_tab[dev] (dev, IO_RD, 0); /* get from dev */
if (ccw & CCW32_TL) { /* translate? */
tblad = ReadF (ccwa + CCB32_TAB, VR);/* get tbl addr */
tblen = (tblad + (by << 1)) & VAMASK; /* tbl entry addr */
t = ReadH (tblen, VR); /* get tbl entry */
if ((t & SIGN16) == 0) { /* special xlate? */
PC = t << 1; /* change PC */
R[3] = by; /* untrans char */
return 0; } /* CC = 0 */
WriteB (addr, t & DMASK8, VW); } /* wr trans */
else WriteB (addr, by, VW); } /* wr orig */
t = ReadH (ccwa + CCB32_CHK, VR); /* get check wd */
t = t ^ by; /* start LRC */
if (ccw & CCW32_CRC) { /* CRC? */
for (i = 0; i < 8; i++) {
if (t & 1) t = (t >> 1) ^ 0xA001;
else t = t >> 1; } }
WriteH (ccwa + CCB32_CHK, t, VW); /* rewrite chk wd */
bufc = bufc + 1; /* adv buf cnt */
WriteH (ccwb, bufc & DMASK16, VW); /* rewrite cnt */
if (bufc > 0) { /* cnt pos? */
ccw = ccw ^ CCW32_B1; /* flip buf */
WriteH (ccwa, ccw, VW); /* rewrite */
PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */
return CC_G; } /* CC = G */
} /* end if bufc */
} /* end slow */
PC = R[1]; /* restore PC */
return newPSW (R[0]); /* restore PSW, CC */
}
/* Display register device */
uint32 display (uint32 dev, uint32 op, uint32 dat)
{
int t;
switch (op) {
case IO_ADR: /* select */
if (!drmod) drpos = srpos = 0; /* norm mode? clr */
return BY; /* byte only */
case IO_OC: /* command */
op = op & 0xC0;
if (op == 0x40) { /* x40 = inc */
drmod = 1;
drpos = srpos = 0; } /* init cntrs */
else if (op == 0x80) drmod = 0; /* x80 = norm */
break;
case IO_WD: /* write */
if (drpos < 4)
DR = (DR & ~(DMASK8 << (drpos * 8))) | (dat << (drpos * 8));
else if (drpos == 4) DRX = dat;
drpos = (drpos + 1) & 0x7;
break;
case IO_RD: /* read */
t = (SR >> (srpos * 8)) & DMASK8;
srpos = srpos ^ 1;
return t;
case IO_SS: /* status */
return 0x80; }
return 0;
}
/* Relocation and protection */
uint32 Reloc (uint32 va, uint32 rel)
{
uint32 seg, off, mapr, lim;
seg = VA_GETSEG (va); /* get seg num */
off = VA_GETOFF (va); /* get offset */
mapr = mac_reg[seg]; /* get seg reg */
lim = GET_SRL (mapr); /* get limit */
if (off >= lim) { /* limit viol? */
mac_sta = MACS_L; /* set status */
ABORT (MPRO); } /* abort */
if ((mapr & SR_PRS) == 0) { /* not present? */
mac_sta = MACS_NP; /* set status */
ABORT (MPRO); } /* abort */
if ((rel == VE) && (mapr & SR_EXP)) { /* exec, prot? */
mac_sta = MACS_EX; /* set status */
qevent = qevent | EV_MAC; } /* req intr */
if ((rel == VW) && (mapr & (SR_WPI | SR_WRP))) { /* write, prot? */
if (mapr & SR_WRP) { /* write abort? */
mac_sta = MACS_WP; /* set status */
ABORT (MPRO); } /* abort */
else { /* write intr */
mac_sta = MACS_WI; /* set status */
qevent = qevent | EV_MAC; } } /* req intr */
return (off + (mapr & SRF_MASK)) & PAMASK32; /* relocate */
}
uint32 RelocT (uint32 va, uint32 base, uint32 rel, uint32 *pa)
{
uint32 seg, off, mapr, lim;
seg = VA_GETSEG (va); /* get seg num */
off = VA_GETOFF (va); /* get offset */
mapr = ReadF ((base + (seg << 2)) & VAMASK, rel); /* get seg reg */
lim = GET_SRL (mapr); /* get limit */
if (off >= lim) return CC_C; /* limit viol? */
if ((mapr & SR_PRS) == 0) return CC_V; /* not present? */
*pa = off + (mapr & SRF_MASK); /* translate */
if (mapr & (SR_WRP | SR_WPI)) return CC_G; /* write prot? */
if (mapr & SR_EXP) return CC_L; /* exec prot? */
return 0; /* ok */
}
/* Memory interface routines
ReadB read byte (processor)
ReadH read halfword (processor)
ReadF read fullword (processor)
WriteB write byte (processor)
WriteH write halfword (processor)
WriteF write fullword (processor)
IOReadB read byte (IO)
IOWriteB write byte (IO)
*/
uint32 ReadB (uint32 loc, uint32 rel)
{
uint32 val;
uint32 sc = (3 - (loc & 3)) << 3;
if ((PSW & PSW_REL) == 0) { /* reloc off? */
val = M[loc >> 2]; /* get mem word */
if ((loc & ~03) == MAC_STA) { /* MAC status? */
val = mac_sta; /* read it */
qevent = qevent & ~EV_MAC; } } /* clr MAC intr */
else if (rel == 0) val = M[loc >> 2]; /* phys ref? */
else { uint32 pa = Reloc (loc, rel); /* relocate */
val = M[pa >> 2]; }
return (val >> sc) & DMASK8;
}
uint32 ReadH (uint32 loc, uint32 rel)
{
uint32 val;
if ((PSW & PSW_REL) == 0) { /* reloc off? */
val = M[loc >> 2]; /* get mem word */
if ((loc & ~03) == MAC_STA) { /* MAC status? */
val = mac_sta; /* read it */
qevent = qevent & ~EV_MAC; } } /* clr MAC intr */
else if (rel == 0) val = M[loc >> 2]; /* phys ref? */
else { uint32 pa = Reloc (loc, rel); /* relocate */
val = M[pa >> 2]; }
return (val >> ((loc & 2)? 0: 16)) & DMASK16;
}
uint32 ReadF (uint32 loc, uint32 rel)
{
uint32 val;
if ((PSW & PSW_REL) == 0) { /* reloc off? */
val = M[loc >> 2]; /* get mem word */
if ((loc & ~03) == MAC_STA) { /* MAC status? */
val = mac_sta; /* read it */
qevent = qevent & ~EV_MAC; } } /* clr MAC intr */
else if (rel == 0) val = M[loc >> 2]; /* phys ref? */
else { uint32 pa = Reloc (loc, rel); /* relocate */
val = M[pa >> 2]; }
return val;
}
void WriteB (uint32 loc, uint32 val, uint32 rel)
{
uint32 pa = loc;
uint32 sc = (3 - (loc & 3)) << 3;
val = val & DMASK8;
if ((PSW & PSW_REL) == 0) { /* reloc off? */
uint32 idx = (pa - MAC_BASE) >> 2; /* check for MAC */
if (idx <= MAC_LNT) {
if (idx < MAC_LNT) mac_reg[idx] =
((mac_reg[idx] & ~(DMASK8 << sc)) | (val << sc)) & SR_MASK;
else {
mac_sta = 0;
qevent = qevent & ~EV_MAC; } } }
else if (rel != 0) pa = Reloc (loc, rel); /* !phys? relocate */
if (MEM_ADDR_OK (pa)) M[pa >> 2] =
(M[pa >> 2] & ~(DMASK8 << sc)) | (val << sc);
return;
}
void WriteH (uint32 loc, uint32 val, uint32 rel)
{
uint32 pa = loc;
val = val & DMASK16;
if ((PSW & PSW_REL) == 0) { /* reloc off? */
uint32 idx = (pa - MAC_BASE) >> 2; /* check for MAC */
if (idx <= MAC_LNT) {
if (idx < MAC_LNT) mac_reg[idx] = ((loc & 2)?
((mac_reg[idx] & ~DMASK16) | val):
((mac_reg[idx] & DMASK16) | (val << 16))) & SR_MASK;
else {
mac_sta = 0;
qevent = qevent & ~EV_MAC; } } }
else if (rel != 0) pa = Reloc (loc, rel); /* !phys? relocate */
if (MEM_ADDR_OK (pa)) M[pa >> 2] = (loc & 2)?
((M[pa >> 2] & ~DMASK16) | val):
((M[pa >> 2] & DMASK16) | (val << 16));
return;
}
void WriteF (uint32 loc, uint32 val, uint32 rel)
{
uint32 pa = loc;
if (loc & 2) {
WriteH (loc & VAMASK, (val >> 16) & DMASK16, rel);
WriteH ((loc + 2) & VAMASK, val & DMASK16, rel);
return; }
if ((PSW & PSW_REL) == 0) { /* reloc off? */
uint32 idx = (pa - MAC_BASE) >> 2; /* check for MAC */
if (idx <= MAC_LNT) {
if (idx < MAC_LNT) mac_reg[idx] = val & SR_MASK;
else {
mac_sta = 0;
qevent = qevent & ~EV_MAC; } } }
else if (rel != 0) pa = Reloc (loc, rel); /* !phys? relocate */
if (MEM_ADDR_OK (pa)) M[pa >> 2] = val & DMASK32;
return;
}
uint32 IOReadB (uint32 loc)
{
uint32 sc = (3 - (loc & 3)) << 3;
return (M[loc >> 2] >> sc) & DMASK8;
}
void IOWriteB (uint32 loc, uint32 val)
{
uint32 sc = (3 - (loc & 3)) << 3;
val = val & DMASK8;
M[loc >> 2] = (M[loc >> 2] & ~(DMASK8 << sc)) | (val << sc);
return;
}
/* Reset routine */
t_stat cpu_reset (DEVICE *dptr)
{
qevent = 0; /* no events */
mac_sta = 0; /* clear MAC */
newPSW (0); /* PSW = 0 */
set_r_display (R);
DR = 0; /* clear display */
drmod = 0;
blk_io.dfl = blk_io.cur = blk_io.end = 0; /* no block I/O */
sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init bkpts */
if (M == NULL) M = calloc (MAXMEMSIZE32 >> 1, sizeof (uint16));
if (M == NULL) return SCPE_MEM;
pcq_r = find_reg ("PCQ", NULL, dptr); /* init PCQ */
if (pcq_r) pcq_r->qptr = 0;
else return SCPE_IERR;
return SCPE_OK;
}
/* Memory examine */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) {
int32 cc = RelocT (addr, MAC_BASE, P, &addr);
if (cc & (CC_C | CC_V)) return SCPE_NXM; }
if (addr >= MEMSIZE) return SCPE_NXM;
if (vptr != NULL) *vptr = IOReadB (addr);
return SCPE_OK;
}
/* Memory deposit */
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) {
int32 cc = RelocT (addr, MAC_BASE, P, &addr);
if (cc & (CC_C | CC_V)) return SCPE_NXM; }
if (addr >= MEMSIZE) return SCPE_NXM;
IOWriteB (addr, val & 0xFF);
return SCPE_OK;
}
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 mc = 0;
t_addr i;
if ((val <= 0) || (val > MAXMEMSIZE32) || ((val & 0xFFFF) != 0))
return SCPE_ARG;
for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE32; i = i + 4) M[i >> 2] = 0;
return SCPE_OK;
}
/* Set current R pointers for SCP */
void set_r_display (uint32 *rbase)
{
extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr);
REG *rptr;
int32 i;
rptr = find_reg ("R0", NULL, &cpu_dev);
if (rptr == NULL) return;
for (i = 0; i < 16; i++, rptr++) rptr->loc = (void *) (rbase + i);
return;
}
/* Set console interrupt */
t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (PSW & PSW_EXI) SET_INT (v_DS);
return SCPE_OK;
}