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:
Bob Supnik 2001-12-26 09:38:00 -08:00 committed by Mark Pizzolato
parent 654937fc88
commit 701f0fe028
145 changed files with 23190 additions and 9807 deletions

144
0readme28.txt Normal file
View file

@ -0,0 +1,144 @@
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.

View file

@ -58,8 +58,6 @@
#include "altair_defs.h"
#define ILL_ADR_FLAG 0200000
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */
@ -82,20 +80,19 @@ int32 saved_PC = 0; /* program counter */
int32 SR = 0; /* switch register */
int32 INTE = 0; /* Interrupt Enable */
int32 int_req = 0; /* Interrupt request */
int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */
int32 chip = 0; /* 0 = 8080 chip, 1 = z80 chip */
int32 PCX; /* External view of PC */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
/* function prototypes */
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_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
void setarith(int32 reg);
void setlogical(int32 reg);
void setinc(int32 reg);
@ -234,7 +231,7 @@ int32 bootrom[256] = {
cpu_mod CPU modifiers list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -249,11 +246,10 @@ REG cpu_reg[] = {
{ FLDATA (AC, AC, 16) },
{ FLDATA (S, S, 16) },
{ FLDATA (P, P, 16) },
{ FLDATA (INTE, INTE, 16) },
{ FLDATA (INTE, INTE, 16) },
{ FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO },
{ FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO },
{ ORDATA (SR, SR, 16) },
{ ORDATA (BREAK, ibkpt_addr, 17) },
{ ORDATA (WRU, sim_int_char, 8) },
{ NULL } };
@ -303,10 +299,8 @@ int32 sim_instr (void)
} /* end interrupt */
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save address */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break;
}
@ -1125,7 +1119,8 @@ C = 0;
Z = 0;
saved_PC = 0;
int_req = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -1146,27 +1141,17 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
return SCPE_OK;
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt)
ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}

375
AltairZ80/altairZ80.txt Normal file
View file

@ -0,0 +1,375 @@
Altair 8800 Simulator
=====================
1. Background.
The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800
was announced on the January 1975 cover of Popular Electronics, which
boasted you could buy and build this powerful computer kit for only $397.
The kit consisted at that time of only the parts to build a case, power
supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of
memory. Still, thousands were ordered within the first few months after the
announcement, starting the personal computer revolution as we know it today.
Many laugh at the small size of the that first kit, noting there
were no peripherals and the 256 byte memory size. But the computer was an
open system, and by 1977 MITS and many other small startups had added many
expansion cards to make the Altair quite a respectable little computer. The
"Altair Bus" that made this possible was soon called the S-100 Bus, later
adopted as an industry standard, and eventually became the IEE-696 Bus.
2. Hardware
We are simulating a fairly "loaded" Altair 8800 from about 1977,
with the following configuration:
device simulates
name(s)
CPU Altair 8800 with Intel 8080 CPU board, 62KB
of RAM, 2K of EPROM with start boot ROM.
SIO MITS 88-2SIO Dual Serial Interface Board. Port 1
is assumed to be connected to a serial "glass
TTY" that is your terminal running the Simulator.
PTR Paper Tape Reader attached to port 2 of the 2SIO board.
PTP Paper Tape Punch attached to port 2 of the
2SIO board. This also doubles as a printer port.
DSK MITS 88-DISK Floppy Disk controller with up
to eight drives.
2.1 CPU
We have 2 CPU options that were not present on the original
machine but are useful in the simulator. We also allow you to select
memory sizes, but be aware that some sample software requires the full
64K (i.e. CP/M) and the MITS Disk Basic and Altair DOS require about
a minimum of 24K.
SET CPU 8080 Simulates the 8080 CPU (normal)
SET CPU Z80 Simulates the Z80 CPU. Note that some software (e.g. most
original Altair software such as 4K Basic) requires an 8080 CPU and
will not or not properly run on a Z80. This is mainly due to the use
of the parity flag on the 8080 which has not always the same
semantics on the Z80.
SET CPU ITRAP Causes the simulator to halt if an invalid opcode
is detected (depending on the chosen CPU).
SET CPU NOITRAP Does not stop on an invalid Opcode. This is
how the real 8080 works.
SET CPU 4K
SET CPU 8K
SET CPU 12K
SET CPU 16K
......
SET CPU 64K All these set various CPU memory configurations.
The 2K EPROM at the high end of memory is always
present and will always boot.
The BOOT EPROM card starts at address FF00. Jumping to this address
will always boot drive 0 of the floppy controller. If no valid bootable
software is present there the machine crashes. This is historically
accurate behavior.
The real 8080, on receiving a HLT (Halt) instruction, freezes the processor
and only an interrupt or CPU hardware reset will restore it. The simulator
is alot nicer, it will halt but send you back to the simulator command line.
CPU Registers include the following:
name size comments
PC 16 The Program Counter
AF 16 The accumulator and the flag register
F = S Z - AC - P/V N C
S = Sign flag.
Z = Zero Flag.
AC = Auxillary Carry flag.
P/V = Parity flag on 8080
Parity / Overflow flag on Z80
- = not used (undefined)
N = Internal sign flag
C = Carry flag.
BC 16 The BC register pair. Register B is the high 8 bits,
C is the lower 8 bits
DE 16 The DE register pair. Register D is the high 8 bits,
E is the lower 8 bits.
HL 16 The HL register pair. Register H is the high 8 bits,
L is the lower 8 bits.
AF1 16 The alternate AF register (only on Z80)
BC1 16 The alternate BC register (only on Z80)
DE1 16 The alternate DE register (only on Z80)
HL1 16 The alternate HL register (only on Z80)
IX 16 The IX index register (only on Z80)
IY 16 The IY index register (only on Z80)
IFF 8 Interrupt flag (only on Z80, no effect)
INT 8 Interrupt register (only on Z80, no effect)
SR 16 The front panel switches (use D SR 8 for 4k Basic).
WRU 8 The interrupt character. This starts as 5
(ctrl-E) but some Altair software uses this
keystroke so best to change this to something
exotic such as 035 (which is Ctl-]).
2.2 The Serial I/O Card (2SIO)
This simple programmed I/O device provides 2 serial ports to the
outside world, which could be hardware jumpered to support RS-232 plugs or a
TTY current loop interface. The standard I/O addresses assigned by MITS
was 10-11 (hex) for the first port, and 12-13 (hex) for the second.
We follow this standard in the Simulator.
The simulator directs I/O to/from the first port to the screen. The
second port reads from an attachable "tape reader" file on input, and writes
to an attachable "punch file" on output. These files are considered a
simple stream of 8-bit bytes.
The SIO can be configured in SIMH with the following commands:
SET SIO TTY Bit 8 is set to zero on console output
SET SIO ANSI Bit 8 is not touched on console output
SET SIO ALL Console input support lower- and upper case
SET SIO UPPER Console input is transformed to upper case characters only
(This feature is useful for most Altair software)
SET SIO BS Map the delete character to backspace
SET SIO DEL Map the backspace character to delete
You can also attach the SIO to a port:
ATTACH SIO 23 Console IO goes via a Telnet connection on port 23
DETACH SIO Console IO goes via the regular SIMH console
2.3 The 88-DISK controller.
The MITS 88-DISK is a simple programmed I/O interface to the MITS
8-inch floppy drive, which was basically a Pertec FD-400 with a power
supply and buffer board builtin. The controller supports neither interrupts
nor DMA, so floppy access required the sustained attention of the CPU.
The standard I/O addresses were 8, 9, and 0A (hex), and we follow the
standard. Details on controlling this hardware are in the altair_dsk.c
source file.
The only difference is that the simulated disks may be larger than the
original ones: The original disk had 77 tracks while the simulated disks
support up to 254 tracks (only relevant for CP/M).
For debugging purposes you can set the trace level of some disk I/O
functions. To do so the following bits in TRACE (a register of the disk)
have been defined with the following meaning:
1 Trace all IN and OUT instructions on the disk ports 8 and 9
2 Trace all read and writes to full sectors on the disk
4 Print a message whenever an unnecessary step-in or step out of the
disk head occurs (often an indication of an infinite loop)
8 Print a message whenever the disk head appears to be waiting for a
sector which does not show up (often an indication of an infinite
loop)
For example the command "D TRACE 10" will trace options 2+8 from above.
3. Sample Software
Running an Altair in 1977 you would be running either MITS Disk
Extended BASIC, or the brand new and sexy CP/M Operating System from Digital
Research. Or possibly, you ordered Altair DOS back when it was promised in
1975, and are still waiting for it to be delivered in early 1977.
We have samples of all three for you to check out. We can't go into
the details of how they work, but we'll give you a few hints.
3.1 CP/M Version 2.2
This version is my own port of the standard CP/M to the Altair.
There were some "official" versions but I don't have them. None were
endorsed or sold by MITS to my knowledge, however.
To boot CP/M:
sim> attach dsk altcpm.dsk
sim> go ff00
62K CP/M VERSION 2.2 (ALTAIR 8800)
A>DIR
CP/M feels like DOS, sort of. DIR will work. I have included all
the standard CP/M utilities, plus a few common public-domain ones. I also
include the sources to the customized BIOS and some other small programs.
TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better
DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to
binary format (.COM). ED is a simple editor, #A command will bring the
source file to the buffer, T command will "type" lines, L will move lines,
E exits the editor. 20L20T will move down 20 lines, and type 20. Very
DECish. DDT is the debugger, SUBMIT is a batch-type command processor.
A sample batch file that will assemble and write out the bootable CP/M
image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN".
In order to efficiently transfer files into the CP/M environment use the
included program READ <filename.ext>. If you have a file named foo.ext in
the current directory (i.e. the directory where SIMH is), executing
READ FOO.EXT under CP/M will transfer the file onto the CP/M disk. READ will
only run with Z80 CPU so remember to "SET CPU Z80".
The disk "altcpm.dsk" contains the following files:
Name Ext Size Comment
ABOOT62 ASM 1K Moves CP/M image from MOVCPM location to real location
in memory
ASM COM 8K Standard CP/M assembler
CALC PRO 3K Prolog sample file "Calculator"
CBIOS ASM 8K BIOS for the Altair (used for sysgen)
COPY COM 1K ALTAIR diskette backup program
CPM62 COM 9K CP/M binary (used for sysgen)
DDT COM 5K Dynamic Debugging Tool (Standard CP/M)
DDTZ COM 10K Dynamic Debugging Tool for Z80
DUMP ASM 5K Assembler source for DUMP utility
DUMP COM 1K Dumps the contents of a file in hex (Standard CP/M)
ED COM 7K Line oriented editor (Standard CP/M)
FAMILY PRO 2K Prolog sample file "Family relations"
FORMAT COM 2K Formats a disk
INTEGER PRO 1K Prolog sample file "Integer arithmetic"
KNAKE PRO 2K Prolog sample file "Logic puzzle"
LOAD COM 2K Loads a hex file and produces an executable
(Standard CP/M)
LS COM 3K Directory utility
MOVCPM COM 12K Regenerates the CP/M system for a particular
memory size (Standard CP/M)
PINST COM 4K Terminal installer for PROLOGZ.COM
PIP COM 8K Peripheral Interchange Program for copying files
(Standard CP/M)
PROLOGZ COM 17K Prolog development environment
PROLOGZ TXT 40K PROLOGZ documentation in German
PTD ASM 2K Writes Altair-format memory image to disk
(used for sysgen)
QUEEN PRO 2K Prolog sample file "N Queens problem"
READ COM 2K Reads a file from the SIMH filesystem to CP/M
README TXT 3K This file
STAT COM 6K Provides information about drives, disks and
files (Standard CP/M)
SUBMIT COM 2K Submits a file of commands for batch processing
(Standard CP/M)
SURVEY COM 2K Provides information about memory and IO ports
SYSCOPY COM 2K Copies the reserved tracks between disks
SYSGEN SUB 2K Submit file for generating the CP/M system
XSUB COM 2K Addition to SUBMIT such that all input is read
from the submit file (Standard CP/M)
3.2 MITS Disk Extended BASIC Version 4.1
This was the commonly used software for serious users of the Altair
computer. It is a powerful (but slow) BASIC with some extended commands to
allow it to access and manage the disk. There was no operating system it
ran under. To boot:
sim> set cpu 8080 ;Z80 will not work
sim> attach dsk mbasic.dsk
sim> set sio upper
sim> go ff00
MEMORY SIZE? [return]
LINEPRINTER? C [return]
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
NUMBER OF FILES? 3 [return]
NUMBER OF RANDOM FILES? 2 [return]
44041 BYTES FREE
ALTAIR BASIC REV. 4.1
[DISK EXTENDED VERSION]
COPYRIGHT 1977 BY MITS INC.
OK
MOUNT 0
OK
FILES
3.3 Altair DOS Version 1.0
This was long promised but not delivered until it was almost
irrelevant. A short attempted tour will reveal it to be a dog, far inferior
to CP/M. To boot:
sim> attach dsk altdos.dsk
sim> set sio upper
sim> go ff00
MEMORY SIZE? [return]
INTERRUPTS? N [return]
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
HOW MANY DISK FILES? 3 [return]
HOW MANY RANDOM FILES? 2 [return]
056449 BYTES AVAILABLE
DOS MONITOR VER 1.0
COPYRIGHT 1977 BY MITS INC
.MNT 0
.DIR 0
3.4 Altair 4k Basic
In order to run the famous 4k Basic, use the following commands (the trick
is to get the Switch Register right).
sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU
sim> set sio upper ;4k Basic does not like lower case letters as input
sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits
sim> d sr 8 ;good setting for the Switch Register
sim> load 4kbas.bin ;load it
sim> go ;and go
MEMORY SIZE? [return]
TERMINAL WIDTH? [return]
WANT SIN? [Y]
61911 BYTES FREE
BASIC VERSION 3.2
[4K VERSION]
OK
3.5 Altair 8k Basic
Running 8k Basic follows the procedure for 4k Basic.
sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU
sim> set sio upper ;8k Basic does not like lower case letters as input
sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits
sim> d sr 8 ;good setting for the Switch Register
sim> load 8kbas.bin ;load it
sim> go ;and go
MEMORY SIZE? [A]
WRITTEN FOR ROYALTIES BY MICRO-SOFT
MEMORY SIZE? [return]
TERMINAL WIDTH? [return]
WANT SIN-COS-TAN-ATN? [Y]
58756 BYTES FREE
ALTAIR BASIC REV. 4.0
[EIGHT-K VERSION]
COPYRIGHT 1976 BY MITS INC.
OK
4. Brief summary of all major changes to the original Altair simulator
- Full support for Z80. CP/M software requiring a Z80 CPU now runs
properly. DDTZ and PROLOGZ are included for demonstration purposes.
- Full assembler and dis-assembler support for Z80 and 8080 mnemonics.
Depending on the current setting of the CPU, the appropriate mnemonics
are used.
- The BOOT ROM was changed to fully load the software from disk. The
original code basically loaded a copy of itself from the disk and
executed it.
- ROM and memory size settings are now fully honored. This means that you
cannot write into the ROM or outside the defined RAM (e.g. when the RAM size
was truncated with the SET CPU commands). This feature allows programs which
check for the size of available RAM to run properly (e.g. 4k Basic).
- The console can also be used via Telnet. This is useful when a terminal is
needed which supports cursor control such as a VT100. PROLOGZ for example
has a built-in screen editor which works under Telnet.
- Simplified file exchange for CP/M. Using the READ program under CP/M one
can easily import files into CP/M from the regular file system. Note that PIP
does not work properly on non-text files on PTR.
- The last character read from PTR is always Control-Z (the EOF character for
CP/M). This makes sure that PIP (Peripheral Interchange Program on CP/M) will
terminate properly.
- Fixed a bug in the BIOS warm boot routine which caused CP/M to crash.
- Modified the BIOS for CP/M to support 8 disks.
- Changed from octal to hex which is more concise.

3372
AltairZ80/altairZ80_cpu.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
/* altairZ80_defs.h: MITS Altair simulator definitions
Written by Peter Schorn, 2001
Based on work by Charles E Owen ((c) 1997, Commercial use prohibited)
*/
#include "sim_defs.h" /* simulator definitions */
/* Memory */
#define MAXMEMSIZE 65536 /* max memory size */
#define KB 1024 /* kilo byte */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define bootrom_size 256 /* size of boot rom */
#define bootrom_origin 0xFF00 /* start address of boot rom */
#define BACKSPACE_CHAR 0x08 /* backspace character */
#define DELETE_CHAR 0x7f /* delete character */
#define CONTROLZ_CHAR 26 /* control Z character */
/* Simulator stop codes */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_OPCODE 4
#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */
#define UNIT_CHIP (1 << UNIT_V_CHIP)
#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)

408
AltairZ80/altairZ80_dsk.c Normal file
View file

@ -0,0 +1,408 @@
/* altairZ80_dsk.c: MITS Altair 88-DISK Simulator
Written by Charles E Owen ((c) 1997, Commercial use prohibited)
Minor modifications by Peter Schorn, 2001
The 88_DISK is a 8-inch floppy controller which can control up
to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives.
Each diskette has physically 77 tracks of 32 137-byte sectors
each.
The controller is interfaced to the CPU by use of 3 I/O addreses,
standardly, these are device numbers 10, 11, and 12 (octal).
Address Mode Function
------- ---- --------
10 Out Selects and enables Controller and Drive
10 In Indicates status of Drive and Controller
11 Out Controls Disk Function
11 In Indicates current sector position of disk
12 Out Write data
12 In Read data
Drive Select Out (Device 10 OUT):
+---+---+---+---+---+---+---+---+
| C | X | X | X | Device |
+---+---+---+---+---+---+---+---+
C = If this bit is 1, the disk controller selected by 'device' is
cleared. If the bit is zero, 'device' is selected as the
device being controlled by subsequent I/O operations.
X = not used
Device = value zero thru 15, selects drive to be controlled.
Drive Status In (Device 10 IN):
+---+---+---+---+---+---+---+---+
| R | Z | I | X | X | H | M | W |
+---+---+---+---+---+---+---+---+
W - When 0, write circuit ready to write another byte.
M - When 0, head movement is allowed
H - When 0, indicates head is loaded for read/write
X - not used (will be 0)
I - When 0, indicates interrupts enabled (not used this simulator)
Z - When 0, indicates head is on track 0
R - When 0, indicates that read circuit has new byte to read
Drive Control (Device 11 OUT):
+---+---+---+---+---+---+---+---+
| W | C | D | E | U | H | O | I |
+---+---+---+---+---+---+---+---+
I - When 1, steps head IN one track
O - When 1, steps head OUT one track
H - When 1, loads head to drive surface
U - When 1, unloads head
E - Enables interrupts (ignored this simulator)
D - Disables interrupts (ignored this simulator)
C - When 1 lowers head current (ignored this simulator)
W - When 1, starts Write Enable sequence: W bit on device 10
(see above) will go 1 and data will be read from port 12
until 137 bytes have been read by the controller from
that port. The W bit will go off then, and the sector data
will be written to disk. Before you do this, you must have
stepped the track to the desired number, and waited until
the right sector number is presented on device 11 IN, then
set this bit.
Sector Position (Device 11 IN):
As the sectors pass by the read head, they are counted and the
number of the current one is available in this register.
+---+---+---+---+---+---+---+---+
| X | X | Sector Number | T |
+---+---+---+---+---+---+---+---+
X = Not used
Sector number = binary of the sector number currently under the
head, 0-31.
T = Sector True, is a 1 when the sector is positioned to read or
write.
*/
#include <stdio.h>
#include "altairZ80_defs.h"
#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */
#define UNIT_ENABLE (1 << UNIT_V_ENABLE)
#define DSK_SECTSIZE 137 /* size of sector */
#define DSK_SECT 32 /* sectors per track */
#define TRACKS 254 /* number of tracks,
original Altair has 77 tracks only */
#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT)
#define DSK_SIZE (DSK_TRACSIZE * TRACKS)
#define TRACE_IN_OUT 1
#define TRACE_READ_WRITE 2
#define TRACE_SECTOR_STUCK 4
#define TRACE_TRACK_STUCK 8
t_stat dsk_svc (UNIT *uptr);
t_stat dsk_reset (DEVICE *dptr);
void writebuf();
extern int32 PCX;
extern FILE *sim_log;
/* Global data on status */
int32 cur_disk = 8; /* Currently selected drive */
int32 cur_track[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff};
int32 cur_sect[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff};
int32 cur_byte[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff};
int32 cur_flags[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
int32 trace_flag = 0;
int32 in9_count = 0;
int32 in9_message = FALSE;
char dskbuf[DSK_SECTSIZE]; /* Data Buffer */
int32 dirty = 0; /* 1 when buffer has unwritten data in it */
UNIT *dptr; /* fileref to write dirty buffer to */
/* 88DSK Standard I/O Data Structures */
UNIT dsk_unit[] = {
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) } };
REG dsk_reg[] = {
{ DRDATA (DISK, cur_disk, 4) },
{ ORDATA (TRACE, trace_flag, 8) },
{ DRDATA (IN9, in9_count, 4), REG_RO },
{ NULL } };
DEVICE dsk_dev = {
"DSK", dsk_unit, dsk_reg, NULL,
8, 10, 31, 1, 8, 8,
NULL, NULL, &dsk_reset,
NULL, NULL, NULL };
/* Service routines to handle simlulator functions */
/* service routine - actually gets char & places in buffer */
t_stat dsk_svc (UNIT *uptr)
{
return SCPE_OK;
}
/* Reset routine */
t_stat dsk_reset (DEVICE *dptr)
{
cur_disk = 0;
trace_flag = 0;
in9_count = 0;
in9_message = FALSE;
return SCPE_OK;
}
/* I/O instruction handlers, called from the CPU module when an
IN or OUT instruction is issued.
Each function is passed an 'io' flag, where 0 means a read from
the port, and 1 means a write to the port. On input, the actual
input is passed as the return value, on output, 'data' is written
to the device.
*/
/* Disk Controller Status/Select */
/* IMPORTANT: The status flags read by port 8 IN instruction are
INVERTED, that is, 0 is true and 1 is false. To handle this, the
simulator keeps it's own status flags as 0=false, 1=true; and
returns the COMPLEMENT of the status flags when read. This makes
setting/testing of the flag bits more logical, yet meets the
simulation requirement that they are reversed in hardware.
*/
int32 dsk10(int32 io, int32 data)
{
in9_count = 0;
if (io == 0) { /* IN: return flags */
return ((~cur_flags[cur_disk]) & 0xFF); /* Return the COMPLEMENT! */
}
/* OUT: Controller set/reset/enable/disable */
if (dirty == 1)
writebuf();
if (trace_flag & TRACE_IN_OUT) {
printf("\n[%x] OUT 08: %x", PCX, data);
if (sim_log) {
fprintf(sim_log, "\n[%x] OUT 08: %x", PCX, data);
}
}
cur_disk = data & 0x0F;
if ((((dsk_dev.units + cur_disk) -> flags) & UNIT_ATT) == 0) { /* nothing attached? */
cur_disk = 8;
}
else {
cur_sect[cur_disk] = 0xff; /* reset internal counters */
cur_byte[cur_disk] = 0xff;
cur_flags[cur_disk] = data & 0x80 ? 0 /* Disable drive */ :
(cur_track[cur_disk] == 0 ? 0x5A /* Enable: head move true, track 0 if there */ :
0x1A); /* Enable: head move true */
}
return (0); /* ignored since OUT */
}
/* Disk Drive Status/Functions */
int32 dsk11(int32 io, int32 data)
{
if (io == 0) { /* Read sector position */
in9_count++;
if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2*DSK_SECT) && (!in9_message)) {
in9_message = TRUE;
printf("\n[%x] Looping on sector find %d.\n", PCX, cur_disk);
if (sim_log) {
fprintf(sim_log, "\n[%x] Looping on sector find %d.\n", PCX, cur_disk);
}
}
if (trace_flag & TRACE_IN_OUT) {
printf("\n[%x] IN 09", PCX);
if (sim_log) {
fprintf(sim_log, "\n[%x] IN 09", PCX);
}
}
if (dirty == 1)
writebuf();
if (cur_flags[cur_disk] & 0x04) { /* head loaded? */
cur_sect[cur_disk]++;
if (cur_sect[cur_disk] >= DSK_SECT)
cur_sect[cur_disk] = 0;
cur_byte[cur_disk] = 0xff;
return (((cur_sect[cur_disk] << 1) & 0x3E) /* return 'sector true' bit = 0 (true) */
| 0xC0); /* set on 'unused' bits */
} else {
return (0); /* head not loaded - return 0 */
}
}
in9_count = 0;
/* Drive functions */
if (cur_disk > 7)
return (0); /* no drive selected - can do nothing */
if (trace_flag & TRACE_IN_OUT) {
printf("\n[%x] OUT 09: %x", PCX, data);
if (sim_log) {
fprintf(sim_log, "\n[%x] OUT 09: %x", PCX, data);
}
}
if (data & 0x01) { /* Step head in */
if (trace_flag & TRACE_TRACK_STUCK) {
if (cur_track[cur_disk] == (TRACKS-1)) {
printf("\n[%x] Unnecessary step in for disk %d", PCX, cur_disk);
if (sim_log) {
fprintf(sim_log, "\n[%x] Unnecessary step in for disk %d", PCX, cur_disk);
}
}
}
cur_track[cur_disk]++;
if (cur_track[cur_disk] > (TRACKS-1) )
cur_track[cur_disk] = (TRACKS-1);
if (dirty == 1)
writebuf();
cur_sect[cur_disk] = 0xff;
cur_byte[cur_disk] = 0xff;
}
if (data & 0x02) { /* Step head out */
if (trace_flag & TRACE_TRACK_STUCK) {
if (cur_track[cur_disk] == 0) {
printf("\n[%x] Unnecessary step out for disk %d", PCX, cur_disk);
if (sim_log) {
fprintf(sim_log, "\n[%x] Unnecessary step out for disk %d", PCX, cur_disk);
}
}
}
cur_track[cur_disk]--;
if (cur_track[cur_disk] < 0) {
cur_track[cur_disk] = 0;
cur_flags[cur_disk] |= 0x40; /* track 0 if there */
}
if (dirty == 1)
writebuf();
cur_sect[cur_disk] = 0xff;
cur_byte[cur_disk] = 0xff;
}
if (dirty == 1)
writebuf();
if (data & 0x04) { /* Head load */
cur_flags[cur_disk] |= 0x04; /* turn on head loaded bit */
cur_flags[cur_disk] |= 0x80; /* turn on 'read data available */
}
if (data & 0x08) { /* Head Unload */
cur_flags[cur_disk] &= 0xFB; /* off on 'head loaded' */
cur_flags[cur_disk] &= 0x7F; /* off on 'read data avail */
cur_sect[cur_disk] = 0xff;
cur_byte[cur_disk] = 0xff;
}
/* Interrupts & head current are ignored */
if (data & 0x80) { /* write sequence start */
cur_byte[cur_disk] = 0;
cur_flags[cur_disk] |= 0x01; /* enter new write data on */
}
return (0); /* ignored since OUT */
}
/* Disk Data In/Out*/
inline int32 dskseek(UNIT *xptr) {
return fseek(xptr -> fileref, DSK_TRACSIZE * cur_track[cur_disk] +
DSK_SECTSIZE * cur_sect[cur_disk], SEEK_SET);
}
int32 dsk12(int32 io, int32 data)
{
static int32 i;
UNIT *uptr;
in9_count = 0;
uptr = dsk_dev.units + cur_disk;
if (io == 0) {
if (cur_byte[cur_disk] >= DSK_SECTSIZE) {
/* physically read the sector */
if (trace_flag & TRACE_READ_WRITE) {
printf("\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk], cur_sect[cur_disk]);
if (sim_log) {
fprintf(sim_log, "\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk],
cur_sect[cur_disk]);
}
}
for (i = 0; i < DSK_SECTSIZE; i++) {
dskbuf[i] = 0;
}
dskseek(uptr);
fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
cur_byte[cur_disk] = 0;
}
return (dskbuf[cur_byte[cur_disk]++] & 0xFF);
}
else {
if (cur_byte[cur_disk] >= DSK_SECTSIZE) {
writebuf();
}
else {
dirty = 1;
dptr = uptr;
dskbuf[cur_byte[cur_disk]++] = data & 0xFF;
}
return (0); /* ignored since OUT */
}
}
void writebuf()
{
int32 i, rtn;
i = cur_byte[cur_disk]; /* null-fill rest of sector if any */
while (i < DSK_SECTSIZE) {
dskbuf[i++] = 0;
}
if (trace_flag & TRACE_READ_WRITE) {
printf("\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk,
cur_track[cur_disk], cur_sect[cur_disk]);
if (sim_log) {
fprintf (sim_log, "\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk,
cur_track[cur_disk], cur_sect[cur_disk]);
}
}
if (dskseek(dptr)) {
printf("\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk,
cur_track[cur_disk], cur_sect[cur_disk]);
if (sim_log) {
fprintf(sim_log, "\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk,
cur_track[cur_disk], cur_sect[cur_disk]);
}
}
rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, dptr -> fileref);
if (rtn != 1) {
printf("\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk],
cur_sect[cur_disk], rtn);
if (sim_log) {
fprintf(sim_log, "\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk],
cur_sect[cur_disk], rtn);
}
}
cur_flags[cur_disk] &= 0xFE; /* ENWD off */
cur_byte[cur_disk] = 0xff;
dirty = 0;
}

434
AltairZ80/altairZ80_sio.c Normal file
View file

@ -0,0 +1,434 @@
/* altairZ80_sio: MITS Altair serial I/O card
Written by Peter Schorn, 2001
Based on work by Charles E Owen ((c) 1997, Commercial use prohibited)
These functions support a simulated MITS 2SIO interface card.
The card had two physical I/O ports which could be connected
to any serial I/O device that would connect to a current loop,
RS232, or TTY interface. Available baud rates were jumper
selectable for each port from 110 to 9600.
All I/O is via programmed I/O. Each each has a status port
and a data port. A write to the status port can select
some options for the device (0x03 will reset the port).
A read of the status port gets the port status:
+---+---+---+---+---+---+---+---+
| X X X X X X O I |
+---+---+---+---+---+---+---+---+
I - A 1 in this bit position means a character has been received
on the data port and is ready to be read.
O - A 1 in this bit means the port is ready to receive a character
on the data port and transmit it out over the serial line.
A read to the data port gets the buffered character, a write
to the data port writes the character to the device.
*/
#include <stdio.h>
#include <ctype.h>
#include "altairZ80_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */
#define UNIT_ANSI (1 << UNIT_V_ANSI)
#define UNIT_V_UPPER (UNIT_V_UF + 1) /* uppper case mode */
#define UNIT_UPPER (1 << UNIT_V_UPPER)
#define UNIT_V_BS (UNIT_V_UF + 2) /* map delete to backspace */
#define UNIT_BS (1 << UNIT_V_BS)
#define Terminals 1 /* lines per mux */
TMLN TerminalLines[Terminals] = { { 0 } }; /* we only need one line */
TMXR altairTMXR = {Terminals, 0, &TerminalLines[0] }; /* mux descriptor */
t_stat sio_svc (UNIT *uptr);
t_stat sio_reset (DEVICE *dptr);
t_stat sio_attach (UNIT *uptr, char *cptr);
t_stat sio_detach (UNIT *uptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr);
int32 nulldev(int32 io, int32 data);
int32 simh_dev(int32 io, int32 data);
int32 sio0d(int32 io, int32 data);
int32 sio0s(int32 io, int32 data);
int32 sio1d(int32 io, int32 data);
int32 sio1s(int32 io, int32 data);
void attachCPM();
extern t_stat sim_activate (UNIT *uptr, int32 interval);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
extern t_stat attach_unit (UNIT *uptr, char *cptr);
extern t_bool rtc_avail;
extern FILE *sim_log;
extern int32 sim_switches;
extern uint32 sim_os_msec (void);
extern uint8 M[MAXMEMSIZE];
/* 2SIO Standard I/O Data Structures */
UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0),
KBD_POLL_WAIT };
REG sio_reg[] = {
{ HRDATA (DATA, sio_unit.buf, 8) },
{ HRDATA (STAT, sio_unit.u3, 8) },
{ NULL } };
MTAB sio_mod[] = {
{ UNIT_ANSI, 0, "TTY", "TTY", NULL }, /* keep bit 8 as is for output */
{ UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, /* set bit 8 to 0 before output */
{ UNIT_UPPER, 0, "ALL", "ALL", NULL }, /* do not change case of input characters */
{ UNIT_UPPER, UNIT_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */
{ UNIT_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */
{ UNIT_BS, UNIT_BS, "DEL", "DEL", NULL }, /* map backspace to delete */
{ 0 } };
DEVICE sio_dev = {
"SIO", &sio_unit, sio_reg, sio_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &sio_reset,
NULL, &sio_attach, &sio_detach };
UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0),
KBD_POLL_WAIT };
REG ptr_reg[] = {
{ HRDATA (DATA, ptr_unit.buf, 8) },
{ HRDATA (STAT, ptr_unit.u3, 8) },
{ DRDATA (POS, ptr_unit.pos, 31) },
{ NULL } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
NULL, NULL, NULL };
UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
KBD_POLL_WAIT };
REG ptp_reg[] = {
{ HRDATA (DATA, ptp_unit.buf, 8) },
{ HRDATA (STAT, ptp_unit.u3, 8) },
{ DRDATA (POS, ptp_unit.pos, 31) },
{ NULL } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL };
t_stat sio_attach (UNIT *uptr, char *cptr)
{
return tmxr_attach (&altairTMXR, uptr, cptr); /* attach mux */
}
/* Detach */
t_stat sio_detach (UNIT *uptr)
{
sio_unit.u3 = 0x02; /* Status */
sio_unit.buf = 0; /* Data */
return tmxr_detach (&altairTMXR, uptr);
}
/* Service routines to handle simulator functions */
/* service routine - actually gets char & places in buffer */
t_stat sio_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&sio_unit, sio_unit.wait); /* continue poll */
if (sio_unit.flags & UNIT_ATT) {
if (sim_poll_kbd () == SCPE_STOP) { /* listen for ^E */
return SCPE_STOP;
}
temp = tmxr_poll_conn(&altairTMXR, &sio_unit); /* poll connection */
if (temp >= 0) {
altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */
}
tmxr_poll_rx(&altairTMXR); /* poll input */
tmxr_poll_tx(&altairTMXR); /* poll output */
}
else {
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) {
return temp; /* no char or error? */
}
sio_unit.buf = temp & 0xff; /* Save char */
sio_unit.u3 |= 0x01; /* Set status */
}
return SCPE_OK;
}
t_stat ptr_svc (UNIT *uptr)
{
return SCPE_OK;
}
t_stat ptp_svc (UNIT *uptr)
{
return SCPE_OK;
}
/* Reset routine */
t_stat sio_reset (DEVICE *dptr)
{
if (sio_unit.flags & UNIT_ATT) {
if (altairTMXR.ldsc[0]->conn > 0) {
tmxr_reset_ln(altairTMXR.ldsc[0]);
}
sio_unit.u3 = 0; /* Status */
}
else {
sio_unit.u3 = 0x02; /* Status */
}
sio_unit.buf = 0; /* Data */
sim_activate (&sio_unit, sio_unit.wait); /* activate unit */
return SCPE_OK;
}
t_stat ptr_reset (DEVICE *dptr)
{
ptr_unit.buf = 0;
ptr_unit.u3 = 0;
ptr_unit.pos = 0;
if (ptr_unit.flags & UNIT_ATT) { /* attached? */
rewind(ptr_dev.units -> fileref);
}
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
ptp_unit.u3 = 0x02;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
/* I/O instruction handlers, called from the CPU module when an
IN or OUT instruction is issued.
Each function is passed an 'io' flag, where 0 means a read from
the port, and 1 means a write to the port. On input, the actual
input is passed as the return value, on output, 'data' is written
to the device.
*/
int32 sio0s(int32 io, int32 data)
{
if (io == 0) { /* IN */
if (sio_unit.flags & UNIT_ATT) {
sio_unit.u3 = (((tmxr_rqln(altairTMXR.ldsc[0]) > 0 ? 0x01 : 0) | /* read possible if character available */
(altairTMXR.ldsc[0]->conn == 0 ? 0 : 0x02))); /* write possible if connected */
}
return (sio_unit.u3);
}
else { /* OUT */
if (sio_unit.flags & UNIT_ATT) {
if (data == 0x03) { /* reset port! */
sio_unit.u3 = 0;
sio_unit.buf = 0;
}
}
else {
if (data == 0x03) { /* reset port! */
sio_unit.u3 = 0x02;
sio_unit.buf = 0;
}
}
return (0); /* ignored since OUT */
}
}
int32 sio0d(int32 io, int32 data)
{
if (io == 0) { /* IN */
if (sio_unit.flags & UNIT_ATT) {
sio_unit.buf = tmxr_getc_ln(altairTMXR.ldsc[0]) & 0xff;
}
sio_unit.u3 = sio_unit.u3 & 0xFE;
if (sio_unit.flags & UNIT_BS) {
if (sio_unit.buf == BACKSPACE_CHAR) {
sio_unit.buf = DELETE_CHAR;
}
}
else {
if (sio_unit.buf == DELETE_CHAR) {
sio_unit.buf = BACKSPACE_CHAR;
}
}
return ((sio_unit.flags & UNIT_UPPER) ? toupper(sio_unit.buf) : sio_unit.buf);
}
else { /* OUT */
if (sio_unit.flags & UNIT_ANSI) {
data &= 0x7f;
}
if (sio_unit.flags & UNIT_ATT) {
tmxr_putc_ln(altairTMXR.ldsc[0], data);
}
else {
sim_putchar(data);
}
return (0); /* ignored since OUT */
}
}
/* Port 2 controls the PTR/PTP devices */
int32 sio1s(int32 io, int32 data)
{
if (io == 0) {
/* reset I bit iff PTR unit not attached or no more data available. */
/* O bit is always set since write always possible. */
return ((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0) ? 0x02 : 0x03;
}
else { /* OUT */
if (data == 0x03) {
ptr_unit.u3 = 0;
ptr_unit.buf = 0;
ptr_unit.pos = 0;
ptp_unit.u3 = 0;
ptp_unit.buf = 0;
ptp_unit.pos = 0;
}
return (0); /* ignored since OUT */
}
}
int32 sio1d(int32 io, int32 data)
{
int32 temp;
if (io == 0) { /* IN */
if (((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0))
return (0); /* not attached or no more data available */
if ((temp = getc(ptr_dev.units -> fileref)) == EOF) { /* end of file? */
ptr_unit.u3 = 0x01;
return (CONTROLZ_CHAR); /* control Z denotes end of text file in CP/M */
}
ptr_unit.pos++;
return (temp & 0xFF);
}
else { /* OUT */
putc(data, ptp_dev.units -> fileref);
ptp_unit.pos++;
return (0); /* ignored since OUT */
}
}
int32 nulldev(int32 io, int32 data)
{
return (io == 0 ? 0xff : 0);
}
#define splimit 10
#define printTimeCmd 0
#define markTimeCmd 1
#define showTimeCmd 2
#define resetPtrCmd 3
#define attachCmd 4
#define detachCmd 5
#define resetCmd 6
#define cpmCommandLineLength 128
uint32 markTime[splimit];
int32 markTimeSP = 0;
char version[] = "SIMH001";
int32 versionPos = 0;
/* The CP/M commandline is used as the name of a file and PTR is attached to it */
void attachCPM() {
char cpmCommandLine[cpmCommandLineLength];
uint32 i, len = (M[0x80] & 0x7f) - 1; /* 0x80 contains length of commandline, discard first char */
for (i = 0; i < len; i++) {
cpmCommandLine[i] = (char)M[0x82+i]; /* the first char, typically ' ', is discarded */
}
cpmCommandLine[i] = 0; /* make C string */
sim_switches = SWMASK ('R');
attach_unit(&ptr_unit, cpmCommandLine);
}
/* port 0xfe is a device for communication SIMH <--> Altair machine */
int32 simh_dev(int32 io, int32 data) {
uint32 delta;
int32 result;
if (io == 0) { /* IN */
result = version[versionPos++];
if (result == 0) {
versionPos = 0;
}
return (result);
}
else { /* OUT */
switch(data) {
case printTimeCmd: /* print time */
if (rtc_avail) {
printf("Current time in milliseconds = %d.\n", sim_os_msec ());
if (sim_log) {
fprintf(sim_log, "Current time in milliseconds = %d.\n", sim_os_msec ());
}
}
break;
case markTimeCmd: /* mark time */
if (rtc_avail) {
if (markTimeSP < splimit) {
markTime[markTimeSP++] = sim_os_msec ();
}
else {
printf("Mark stack overflow.\n");
if (sim_log) {
fprintf(sim_log, "Mark stack overflow.\n");
}
}
}
break;
case showTimeCmd: /* show time difference */
if (rtc_avail) {
if (markTimeSP > 0) {
delta = sim_os_msec () - markTime[--markTimeSP];
printf("Delta to mark in milliseconds = %d.\n", delta);
if (sim_log) {
fprintf(sim_log, "Delta to mark in milliseconds = %d.\n", delta);
}
}
else {
printf("Missing mark.\n");
if (sim_log) {
fprintf(sim_log, "Missing mark.\n");
}
}
}
break;
case resetPtrCmd: /* reset ptr device */
ptr_reset(NULL);
break;
case attachCmd: /* attach ptr to the file with name at beginning of CP/M command line */
attachCPM();
break;
case detachCmd: /* detach ptr */
detach_unit(&ptr_unit);
break;
case resetCmd:
versionPos = 0;
break;
default:;
}
return 0; /* ignored, since OUT */
}
}

687
AltairZ80/altairZ80_sys.c Normal file
View file

@ -0,0 +1,687 @@
/* altairz80_sys.c: MITS Altair system interface
Written by Peter Schorn, 2001
Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited)
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
*/
#include <ctype.h>
#include "altairZ80_defs.h"
extern DEVICE cpu_dev;
extern DEVICE dsk_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern DEVICE sio_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern uint8 M[];
extern int32 saved_PC;
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag);
int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw);
int32 checkbase(char ch, char *numString);
int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result);
int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, int32 *at, int32 *hat);
int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]);
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw);
int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics);
/* SCP data structures
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words needed 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[] = "Altair 8800 (Z80)";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev, &ptp_dev, &dsk_dev, NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"Unknown I/O Instruction",
"HALT instruction",
"Breakpoint",
"Invalid Opcode" };
static char *Mnemonics8080[] = {
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
"NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */
"DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */
"DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */
"DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */
"DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */
"DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */
"DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */
"DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */
"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */
"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */
"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */
"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */
"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */
"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */
"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */
"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */
"ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */
"ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */
"SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */
"ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */
"XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */
"ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */
"CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */
"RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */
"RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */
"RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */
"RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */
"RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */
"RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */
"RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */
"RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */
};
static char *MnemonicsZ80[256] =
{
"NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA",
"EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA",
"DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA",
"JR @h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA",
"JR NZ,@h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA",
"JR Z,@h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL",
"JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF",
"JR C,@h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF",
"LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A",
"LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A",
"LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A",
"LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A",
"LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A",
"LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A",
"LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A",
"LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A",
"ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A",
"ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A",
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A",
"SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A",
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A",
"XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A",
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A",
"CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A",
"RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h",
"RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h",
"RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h",
"RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h",
"RET PO", "POP HL", "JP PO,#h", "EX HL,(SP)", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h",
"RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h",
"RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h",
"RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h"
};
static char *MnemonicsCB[256] =
{
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A",
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A",
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A",
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A",
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A",
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A",
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A",
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A",
"BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A",
"BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A",
"BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A",
"BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A",
"BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A",
"BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A",
"BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A",
"BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A",
"RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A",
"RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A",
"RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A",
"RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A",
"RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A",
"RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A",
"RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A",
"RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A",
"SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A",
"SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A",
"SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A",
"SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A",
"SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A",
"SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A",
"SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A",
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A"
};
static char *MnemonicsED[256] =
{
"DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h",
"DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh",
"DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h",
"DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh",
"DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h",
"DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh",
"DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h",
"DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh",
"IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A",
"IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A",
"IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I",
"IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R",
"IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD",
"IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD",
"IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h",
"IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh",
"DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h",
"DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh",
"DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h",
"DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh",
"LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h",
"LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh",
"LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h",
"LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh",
"DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h",
"DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh",
"DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h",
"DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh",
"DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h",
"DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh",
"DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h",
"DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh"
};
static char *MnemonicsXX[256] =
{
"NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA",
"EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA",
"DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA",
"JR @h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA",
"JR NZ,@h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%h", "DEC I%h", "LD I%h,*h", "DAA",
"JR Z,@h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%l", "DEC I%l", "LD I%l,*h", "CPL",
"JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF",
"JR C,@h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF",
"LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%h", "LD B,I%l", "LD B,(I%+^h)", "LD B,A",
"LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%h", "LD C,I%l", "LD C,(I%+^h)", "LD C,A",
"LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%h", "LD D,I%l", "LD D,(I%+^h)", "LD D,A",
"LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%h", "LD E,I%l", "LD E,(I%+^h)", "LD E,A",
"LD I%h,B", "LD I%h,C", "LD I%h,D", "LD I%h,E", "LD I%h,I%h", "LD I%h,I%l", "LD H,(I%+^h)", "LD I%h,A",
"LD I%l,B", "LD I%l,C", "LD I%l,D", "LD I%l,E", "LD I%l,I%h", "LD I%l,I%l", "LD L,(I%+^h)", "LD I%l,A",
"LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A",
"LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%h", "LD A,I%l", "LD A,(I%+^h)", "LD A,A",
"ADD B", "ADD C", "ADD D", "ADD E", "ADD I%h", "ADD I%l", "ADD (I%+^h)", "ADD A",
"ADC B", "ADC C", "ADC D", "ADC E", "ADC I%h", "ADC I%l", "ADC (I%+^h)", "ADC,A",
"SUB B", "SUB C", "SUB D", "SUB E", "SUB I%h", "SUB I%l", "SUB (I%+^h)", "SUB A",
"SBC B", "SBC C", "SBC D", "SBC E", "SBC I%h", "SBC I%l", "SBC (I%+^h)", "SBC A",
"AND B", "AND C", "AND D", "AND E", "AND I%h", "AND I%l", "AND (I%+^h)", "AND A",
"XOR B", "XOR C", "XOR D", "XOR E", "XOR I%h", "XOR I%l", "XOR (I%+^h)", "XOR A",
"OR B", "OR C", "OR D", "OR E", "OR I%h", "OR I%l", "OR (I%+^h)", "OR A",
"CP B", "CP C", "CP D", "CP E", "CP I%h", "CP I%l", "CP (I%+^h)", "CP A",
"RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h",
"RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h",
"RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h",
"RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h",
"RET PO", "POP I%", "JP PO,#h", "EX I%,(SP)", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h",
"RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h",
"RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h",
"RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h"
};
static char *MnemonicsXCB[256] =
{
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A",
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A",
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A",
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A",
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A",
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A",
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A",
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A",
"BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A",
"BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A",
"BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A",
"BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A",
"BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A",
"BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A",
"BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A",
"BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A",
"RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A",
"RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A",
"RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A",
"RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A",
"RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A",
"RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A",
"RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A",
"RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A",
"SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A",
"SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A",
"SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A",
"SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A",
"SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A",
"SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A",
"SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A",
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A"
};
/* Symbolic disassembler
Inputs:
*val = instructions to disassemble
useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used
Outputs:
*S = output text
DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997
You are not allowed to distribute this software
commercially.
*/
int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics)
{
char R[128], H[10], C= '\0', *T, *P;
uint8 J = 0, Offset;
uint16 B = 0;
if (useZ80Mnemonics) {
switch(val[B]) {
case 0xCB:
B++;
T = MnemonicsCB[val[B++]];
break;
case 0xED:
B++;
T = MnemonicsED[val[B++]];
break;
case 0xDD:
case 0xFD:
C = (val[B] == 0xDD) ? 'X' : 'Y';
B++;
if (val[B] == 0xCB) {
B++;
Offset = val[B++];
J = 1;
T = MnemonicsXCB[val[B++]];
}
else {
T = MnemonicsXX[val[B++]];
}
break;
default:
T = MnemonicsZ80[val[B++]];
}
}
else {
T = Mnemonics8080[val[B++]];
}
if (P = strchr(T, '^'))
{
strncpy(R, T, P - T);
R[P - T] = '\0';
sprintf(H, "%02X", val[B++]);
strcat(R, H);
strcat(R, P + 1);
}
else {
strcpy(R, T);
}
if (P = strchr(R, '%')) {
*P = C;
if (P = strchr(P + 1, '%')) *P = C;
}
if(P = strchr(R, '*')) {
strncpy(S, R, P - R);
S[P - R] = '\0';
sprintf(H, "%02X", val[B++]);
strcat(S, H);
strcat(S, P + 1);
}
else if (P = strchr(R, '@')) {
strncpy(S, R, P - R);
S[P - R] = '\0';
if(!J) {
Offset = val[B++];
}
strcat(S, Offset & 0x80 ? "-" : "+");
J = Offset & 0x80 ? 256 - Offset : Offset;
sprintf(H, "%02X", J);
strcat(S, H);
strcat(S, P + 1);
}
else if (P = strchr(R, '#')) {
strncpy(S, R, P - R);
S[P - R] = '\0';
sprintf(H, "%04X", val[B] + 256*val[B + 1]);
strcat(S, H);
strcat(S, P + 1);
B += 2;
}
else {
strcpy(S, R);
}
return(B);
}
/* Symbolic output
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
status = error code
*/
int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw)
{
char disasm[128];
int32 ch = val[0] & 0x7f;
if (sw & (SWMASK ('A') | SWMASK ('C'))) {
fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch);
return SCPE_OK;
}
if (!(sw & SWMASK ('M'))) {
return SCPE_ARG;
}
ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP);
fprintf(of, "%s", disasm);
return (1-ch); /* need to return additional bytes */
}
/* numString checks determines the base of the number (ch, *numString)
and returns FALSE if the number is bad */
int32 checkbase(char ch, char *numString) {
int32 decimal = (ch <= '9');
if (toupper(ch) == 'H') {
return FALSE;
}
while (isxdigit(ch = *numString++)) {
if (ch > '9') {
decimal = FALSE;
}
}
return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE);
}
int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result) {
int32 sign = 1, value = 0, base;
if (requireSign) {
if (ch == '+') {
ch = *(*numString)++;
}
else if (ch == '-') {
sign = -1;
ch = *(*numString)++;
}
else {
return FALSE;
}
}
if (!(base = checkbase(ch, *numString))) {
return FALSE;
}
while (isxdigit(ch)) {
value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10));
ch = *(*numString)++;
}
if (toupper(ch) != 'H') {
(*numString)--;
}
*result = value*sign;
return (minvalue <= value) && (value <= maxvalue);
}
int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star,
int32 *at, int32 *hat) {
char pat = *pattern++;
char inp = *input++;
while ((pat) && (inp)) {
switch(pat) {
case ',':
if (inp == ' ') {
inp = *input++;
continue;
}
case ' ':
if (inp != pat) {
return FALSE;
}
pat = *pattern++;
inp = *input++;
while (inp == ' ') {
inp = *input++;
}
continue;
break;
case '%':
inp = toupper(inp);
if ((inp == 'X') || (inp == 'Y')) {
*xy = inp;
}
else {
return FALSE;
}
break;
case '#':
if (numok(inp, &input, 0, 65535, FALSE, number)) {
pattern++; /* skip h */
}
else {
return FALSE;
}
break;
case '*':
if (numok(inp, &input, 0, 255, FALSE, star)) {
pattern++; /* skip h */
}
else {
return FALSE;
}
break;
case '@':
if (numok(inp, &input, -128, 65535, TRUE, at)) {
pattern++; /* skip h */
}
else {
return FALSE;
}
break;
case '^':
if (numok(inp, &input, 0, 255, FALSE, hat)) {
pattern++; /* skip h */
}
else {
return FALSE;
}
break;
default:
if (toupper(pat) != toupper(inp)) {
return FALSE;
}
}
pat = *pattern++;
inp = *input++;
}
while (inp == ' ') {
inp = *input++;
}
return (pat == 0) && (inp == 0);
}
inline int32 checkXY(char xy) {
if (xy == 'X') {
return 0xDD;
}
else if (xy == 'Y') {
return 0xFD;
}
else {
printf("X or Y expected.\n");
return FALSE;
}
}
int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) {
char xy;
int32 op, number, star, at, hat;
for (op = 0; op < 256; op++) {
number = star = at = -129;
if (match(Mnemonics[op], cptr, &xy, &number, &star, &at, &hat)) {
val[0] = op;
if (number >= 0) {
val[1] = (0xff) & number;
val[2] = (0xff) & (number >> 8);
return (-2); /* two additional bytes returned */
}
else if (star >= 0) {
val[1] = (0xff) & star;
return (-1); /* one additional byte returned */
}
else if (at > -129) {
if (at > 127) { /* assume absolute address is meant */
at -= addr + 2; /* translate to relative address */
}
if ((-128 <= at) && (at < 127)) {
val[1] = (int8)(at);
return (-1);
}
else {
return SCPE_ARG;
}
}
else {
return SCPE_OK;
}
}
}
if (Mnemonics == Mnemonics8080) {
return SCPE_ARG;
}
for (op = 0; op < 256; op++) {
if (match(MnemonicsCB[op], cptr, &xy, &number, &star, &at, &hat)) {
val[0] = 0xCB;
val[1] = op;
return (-1); /* one additional byte returned */
}
}
for (op = 0; op < 256; op++) {
number = -1;
if (match(MnemonicsED[op], cptr, &xy, &number, &star, &at, &hat)) {
val[0] = 0xED;
val[1] = op;
if (number >= 0) {
val[2] = (0xff) & number;
val[3] = (0xff) & (number >> 8);
return (-3); /* three additional bytes returned */
}
else {
return (-1); /* one additional byte returned */
}
}
}
for (op = 0; op < 256; op++) {
number = star = hat = -1;
xy = ' ';
if (match(MnemonicsXX[op], cptr, &xy, &number, &star, &at, &hat)) {
if (!(val[0] = checkXY(xy))) {
return SCPE_ARG;
}
val[1] = op;
if (number >= 0) {
val[2] = (0xff) & number;
val[3] = (0xff) & (number >> 8);
return (-3); /* three additional bytes returned */
}
else if ((star >= 0) && (hat >= 0)) {
val[2] = (0xff) & hat;
val[3] = (0xff) & star;
return (-3); /* three additional bytes returned */
}
else if (star >= 0) {
val[2] = (0xff) & star;
return (-2); /* two additional bytes returned */
}
else if (hat >= 0) {
val[2] = (0xff) & hat;
return (-2); /* two additional bytes returned */
}
else {
return (-1); /* one additional byte returned */
}
}
}
for (op = 0; op < 256; op++) {
at = -129;
xy = ' ';
if (match(MnemonicsXCB[op], cptr, &xy, &number, &star, &at, &hat)) {
if (!(val[0] = checkXY(xy))) {
return SCPE_ARG;
}
val[1] = 0xCB;
if (at > -129) {
val[2] = (int8) (at);
}
else {
printf("Offset expected.\n");
return SCPE_ARG;
}
val[3] = op;
return (-3); /* three additional bytes returned */
}
}
return SCPE_ARG;
}
/* 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
*/
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
{
while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & (SWMASK ('A') | SWMASK ('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) {
return SCPE_ARG; /* must have 1 char */
}
val[0] = (uint32) cptr[0];
return SCPE_OK;
}
return (cpu_unit.flags & UNIT_CHIP) ?
parse_X80(cptr, addr, val, MnemonicsZ80) : parse_X80(cptr, addr, val, Mnemonics8080);
}
/* This is the binary loader. The input file is considered to be
a string of literal bytes with no format special format. The
load starts at the current value of the PC.
*/
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag)
{
int32 i, addr = 0, cnt = 0;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
addr = saved_PC;
while ((i = getc (fileref)) != EOF) {
M[addr++] = i;
cnt++;
} /* end while */
printf ("%d Bytes loaded.\n", cnt);
return (SCPE_OK);
}

View file

@ -23,6 +23,11 @@
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.
cpu H316/H516 CPU
03-Nov-01 RMS Fixed NOHSA modifier
30-Nov-01 RMS Added extended SET/SHOW support
The register state for the Honeywell 316/516 CPU is:
AR<1:16> A register
@ -184,8 +189,6 @@
#include "h316_defs.h"
#define ILL_ADR_FLAG 0100000
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define m7 0001000 /* for generics */
@ -216,21 +219,20 @@ int32 dev_enable = 0; /* dev enable */
int32 ind_max = 8; /* iadr nest limit */
int32 stop_inst = 1; /* stop on ill inst */
int32 stop_dev = 2; /* stop on ill dev */
int32 ibkpt_addr = ILL_ADR_FLAG | X_AMASK; /* breakpoint addr */
int32 old_PC = 0; /* previous PC */
int32 dlog = 0; /* debug log */
int32 turnoff = 0;
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern FILE *sim_log;
extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
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_svc (UNIT *uptr);
t_stat cpu_set_noext (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
/* CPU data structures
@ -240,7 +242,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 value);
cpu_mod CPU modifiers list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + UNIT_EXT,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_EXT,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -268,7 +270,6 @@ REG cpu_reg[] = {
{ FLDATA (STOP_DEV, stop_dev, 1) },
{ DRDATA (INDMAX, ind_max, 8), REG_NZ + PV_LEFT },
{ ORDATA (OLDP, old_PC, 15), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 16) },
{ ORDATA (WRU, sim_int_char, 8) },
{ FLDATA (DLOG, dlog, 0) },
{ FLDATA (HEXT, cpu_unit.flags, UNIT_V_EXT), REG_HRO },
@ -278,7 +279,7 @@ REG cpu_reg[] = {
MTAB cpu_mod[] = {
{ UNIT_EXT, 0, "no extend", "NOEXTEND", &cpu_set_noext },
{ UNIT_EXT, UNIT_EXT, "extend", "EXTEND", NULL },
{ UNIT_HSA, 0, "no HSA", "HSA", NULL },
{ UNIT_HSA, 0, "no HSA", "NOHSA", NULL },
{ UNIT_HSA, UNIT_HSA, "HSA", "HSA", NULL },
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
@ -362,10 +363,8 @@ if ((dev_ready & (INT_PENDING | dev_enable)) > INT_PENDING) { /* int req? */
if (dlog && sim_log) fprintf (sim_log, "Interrupt\n");
MB = 0120000 | M_INT; } /* inst = JST* 63 */
else { if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save address */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
else { if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
Y = PC; /* set mem addr */
@ -986,7 +985,8 @@ dp = 0;
ext = pme = extoff_pending = 0;
dev_ready = dev_ready & ~INT_PENDING;
dev_enable = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -1012,35 +1012,26 @@ else M[addr] = val & DMASK;
return SCPE_OK;
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
/* Option processors */
t_stat cpu_set_noext (UNIT *uptr, int32 value)
t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (MEMSIZE > (NX_AMASK + 1)) return SCPE_ARG;
return SCPE_OK;
}
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0) ||
(((cpu_unit.flags & UNIT_EXT) == 0) && (value > (NX_AMASK + 1))))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0) ||
(((cpu_unit.flags & UNIT_EXT) == 0) && (val > (NX_AMASK + 1))))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}

303
H316/h316_doc.txt Normal file
View file

@ -0,0 +1,303 @@
To: Users
From: Bob Supnik
Subj: H316 Simulator Usage
Date: 1-Dec-2001
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 Honeywell 316/516 simulator.
1. Simulator Files
The H316 requires the following files:
sim/ sim_defs.h
scp.c
scp_tty.c
sim_rev.c
sim/h316/ h316_defs.h
h316_cpu.c
h316_lp.c
h316_stddev.c
h316_cpu.c
2. H316/H516 Features
The Honeywell 316/516 simulator is configured as follows:
device simulates
name(s)
CPU H316/H516 CPU with 16/32KW memory
PTR 316/516-50 paper tape reader
PTP 316/516-52 paper tape punch
TTY 316/516-33 console terminal
CLK 316/516-12 real time clock
LPT 316/516 line printer
The H316/H516 simulator implements several unique stop conditions:
- decode of an undefined instruction, and STOP_INST is et
- reference to an undefined I/O device, and STOP_DEV is set
- more than INDMAX indirect references are detected during
memory reference address decoding
The H316/H516 loader is not implemented.
2.1 CPU
CPU options include choice of instruction set and memory size.
SET CPU HSA high speed arithmetic instructions
SET CPU NOHSA no high speed arithmetic instructions
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
SET CPU 24K set memory size = 24K
SET CPU 32K set memory size = 32K
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 32K.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
P 15 program counter
A 16 A register
B 16 B register
X 16 index register
SC 16 shift count
C 1 carry flag
EXT 1 extend flag
PME 1 previous mode extend flag
EXT_OFF 1 extend off pending flag
DP 1 double precision flag
SS1..4 1 sense switches 1..4
ION 1 interrupts enabled
INODEF 1 interrupts not deferred
INTREQ 16 interrupt requests
DEVRDY 16 device ready flags (read only)
DEVENB 16 device interrupt enable flags (read only)
STOP_INST 1 stop on undefined instruction
STOP_DEV 1 stop on undefined device
INDMAX 1 indirect address limit
OLDP 15 PC prior to last JMP, JSB, or interrupt
WRU 8 interrupt character
2.2 Programmed I/O Devices
2.2.1 316/516-50 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 supports the BOOT command. BOOT PTR copies the
absolute binary loader into memory and starts it running.
The paper tape reader implements these registers:
name size comments
BUF 8 last data item processed
INTREQ 1 device interrupt request
READY 1 device ready
ENABLE 1 device interrupts enabled
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
end of file 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.2.2 316/516-52 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 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
INTREQ 1 device interrupt request
READY 1 device ready
ENABLE 1 device interrupts enabled
POWER 1 device powered up
POS 31 position in the input or output file
TIME 24 time from I/O initiation to interrupt
PWRTIME 24 time from I/O request to power up
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.2.3 316/516-33 Console Teletype (TTY)
The terminal reads from the console keyboard and writes to the
simulator console window. The terminal has one option, UC; when
set, the terminal automatically converts lower case input to upper
case. This is on by default.
The terminal these registers:
name size comments
BUF 8 last data item processed
MODE 1 read/write mode
INTREQ 1 device interrupt request
READY 1 device ready
ENABLE 1 device interrupts enabled
KPOS 31 number of characters input
KTIME 24 keyboard polling interval
TPOS 31 number of characters output
TTIME 24 time from I/O initiation to interrupt
2.2.4 316/516-12 Real Time Clock (CLK)
The real time clock (CLK) implements these registers:
name size comments
INTREQ 1 device interrupt request
READY 1 device ready
ENABLE 1 device interrupts enabled
TIME 24 clock interval
2.2.5 316/5116 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The line printer implements these registers:
name size comments
WDPOS 6 word position in current scan
DRPOS 6 drum position
CRPOS 1 carriage position
XFER 1 transfer ready flag
PRDN 1 print done flag
INTREQ 1 device interrupt request
ENABLE 1 device interrupt enable
SVCST 2 service state
SVCCH 2 service channel
BUF 8 buffer
POS 31 number of characters output
XTIME 24 delay between transfers
ETIME 24 delay at end of scan
PTIME 24 delay for shuttle/line advance
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 paper
OS I/O error x report error and stop
2.3 Symbolic Display and Input
The H316/H516 simulator implements symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as two character string
-m display instruction mnemonics
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c two character sixbit string
alphabetic instruction mnemonic
numeric octal number
Instruction input uses standard H316/H516 assembler syntax. There are six
instruction classes: memory reference, I/O, control, shift, skip, and
operate.
Memory reference instructions have the format
memref{*} {C/Z} address{,1}
where * signifies indirect, C a current sector reference, Z a sector zero
reference, and 1 indexed. The address is an octal number in the range 0 -
077777; if C or Z is specified, the address is a page offset in the range
0 - 0777. Normally, C is not needed; the simulator figures out from the
address what mode to use. However, when referencing memory outside the CPU
(eg, disks), there is no valid PC, and C must be used to specify current
sector addressing.
I/O instructions have the format
io pulse+device
The pulse+device is an octal number in the range 0 - 01777.
Control and operate instructions consist of a single opcode
opcode
Shift instructions have the format
shift n
where n is an octal number in the range 0-77.
Skip instructions have the format
sub-op sub-op sub-op...
The simulator checks that the combination of sub-opcodes is legal.

View file

@ -28,6 +28,8 @@
tty 316/516-33 teleprinter
clk/options 316/516-12 real time clocks/internal options
03-Nov-01 RMS Implemented upper case for console output
29-Nov-01 RMS Added read only unit support
07-Sep-01 RMS Moved function prototypes
*/
@ -66,7 +68,8 @@ t_stat clk_reset (DEVICE *dptr);
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
@ -125,7 +128,7 @@ DEVICE ptp_dev = {
UNIT tty_unit[] = {
{ UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT } };
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT } };
REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 8) },
@ -397,10 +400,13 @@ return SCPE_OK;
t_stat tto_svc (UNIT *uptr)
{
int32 temp;
int32 ch, temp;
SET_READY (INT_TTY); /* set done flag */
if ((temp = sim_putchar (tty_buf & 0177)) != SCPE_OK) return temp;
ch = tty_buf & 0177; /* get char */
if ((tty_unit[TTO].flags & UNIT_UC) && islower (ch)) /* force upper case? */
ch = toupper (ch);
if ((temp = sim_putchar (ch)) != SCPE_OK) return temp; /* output char */
tty_unit[TTO].pos = tty_unit[TTO].pos + 1;
return SCPE_OK;
}

View file

@ -23,6 +23,8 @@
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.
07-Dec-01 RMS Revised to use breakpoint package
03-Dec-01 RMS Added extended SET/SHOW support
10-Aug-01 RMS Removed register in declarations
26-Nov-00 RMS Fixed bug in dual device number routine
21-Nov-00 RMS Fixed bug in reset routine
@ -238,8 +240,6 @@
#include "hp2100_defs.h"
#define ILL_ADR_FLAG 0100000
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define UNIT_V_2100 (UNIT_V_UF + 1) /* 2100 vs 2116 */
@ -269,10 +269,10 @@ int32 maddr = 0; /* mem prot err addr */
int32 ind_max = 16; /* iadr nest limit */
int32 stop_inst = 1; /* stop on ill inst */
int32 stop_dev = 2; /* stop on ill dev */
int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */
int32 old_PC = 0; /* previous PC */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
int32 shift (int32 inval, int32 flag, int32 oper);
int32 calc_dma (void);
int32 calc_int (void);
@ -282,8 +282,7 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat dma0_reset (DEVICE *dptr);
t_stat dma1_reset (DEVICE *dptr);
t_stat cpu_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
/* CPU data structures
@ -293,7 +292,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 value);
cpu_mod CPU modifiers list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -317,7 +316,6 @@ REG cpu_reg[] = {
{ FLDATA (STOP_DEV, stop_dev, 1) },
{ DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
{ ORDATA (OLDP, old_PC, 15), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 16) },
{ ORDATA (WRU, sim_int_char, 8) },
{ FLDATA (T2100, cpu_unit.flags, UNIT_V_2100), REG_HRO },
{ FLDATA (T21MX, cpu_unit.flags, UNIT_V_21MX), REG_HRO },
@ -531,10 +529,8 @@ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */
intrq = 0; /* clear request */
clrCTL (PRO); } /* protection off */
else { if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save address */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
else { if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
err_PC = PC; /* save PC for error */
@ -1343,7 +1339,8 @@ clrFLG (PRO);
clrFBF (PRO);
mfence = 0;
maddr = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
t_stat dma0_reset (DEVICE *tptr)
@ -1391,45 +1388,29 @@ else M[addr] = val & DMASK;
return SCPE_OK;
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}
/* Set device number */
/* Set/show device number */
extern char *read_line (char *ptr, int size, FILE *stream);
extern t_value get_uint (char *cptr, int radix, t_value max, t_stat *status);
t_stat hp_setdev (UNIT *uptr, int32 ord)
t_stat hp_setdev (UNIT *uptr, int32 ord, char *cptr, void *desc)
{
char cbuf[CBUFSIZE], *cptr;
int32 i, olddev, newdev;
int32 i, newdev;
t_stat r;
olddev = infotab[ord].devno;
printf ("Device number: %-o ", olddev);
cptr = read_line (cbuf, CBUFSIZE, stdin);
if ((cptr == NULL) || (*cptr == 0)) return SCPE_OK;
if (cptr == NULL) return SCPE_ARG;
newdev = get_uint (cptr, 8, DEVMASK, &r);
if (r != SCPE_OK) return r;
if (newdev < VARDEV) return SCPE_ARG;
@ -1440,23 +1421,35 @@ infotab[ord].devno = newdev;
return SCPE_OK;
}
/* Set device number for data/control pair */
t_stat hp_setdev2 (UNIT *uptr, int32 ord)
t_stat hp_showdev (FILE *st, UNIT *uptr, int32 ord, void *desc)
{
int32 i, olddev;
fprintf (st, "devno=%o", infotab[ord].devno);
return SCPE_OK;
}
/* Set/show device number for data/control pair */
t_stat hp_setdev2 (UNIT *uptr, int32 ord, char *cptr, void *desc)
{
int32 i, olddev, newdev;
t_stat r;
olddev = infotab[ord].devno;
if ((r = hp_setdev (uptr, ord)) != SCPE_OK) return r;
if (infotab[ord].devno == DEVMASK) {
if ((r = hp_setdev (uptr, ord, cptr, NULL)) != SCPE_OK) return r;
newdev = infotab[ord].devno + 1;
if (newdev > DEVMASK) {
infotab[ord].devno = olddev;
return SCPE_ARG; }
for (i = 0; infotab[i].devno != 0; i++) {
if ((i != (ord + 1)) &&
((infotab[ord].devno + 1) == infotab[i].devno)) {
if ((i != (ord + 1)) && (newdev == infotab[i].devno)) {
infotab[ord].devno = olddev;
return SCPE_ARG; } }
infotab[ord + 1].devno = infotab[ord].devno + 1;
return SCPE_OK;
}
t_stat hp_showdev2 (FILE *st, UNIT *uptr, int32 ord, void *desc)
{
fprintf (st, "devno=%o/%o", infotab[ord].devno, infotab[ord + 1].devno);
return SCPE_OK;
}

View file

@ -23,6 +23,7 @@
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.
30-Nov-01 RMS Added extended SET/SHOW support
15-Oct-00 RMS Added dynamic device numbers
14-Apr-99 RMS Changed t_addr to unsigned
@ -178,5 +179,7 @@ struct hpdev {
/* Function prototypes */
t_bool hp_setdev (UNIT *uptr, int32 val);
t_bool hp_setdev2 (UNIT *uptr, int32 val);
t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat hp_setdev2 (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat hp_showdev2 (FILE *st, UNIT *uptr, int32 val, void *desc);

471
HP2100/hp2100_doc.txt Normal file
View file

@ -0,0 +1,471 @@
To: Users
From: Bob Supnik
Subj: HP2100 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 HP 2100 simulator.
1. Simulator Files
sim/ sim_defs.h
scp.c
scp_tty.c
sim_rev.c
sim/hp2100/ hp2100_defs.h
hp2100_cpu.c
hp2100_dp.c
hp2100_lp.c
hp2100_mt.c
hp2100_stddev.c
hp2100_sys.c
2. HP2100 Features
The HP2100 simulator is configured as follows:
device simulates
name(s)
CPU 2116, 2100, or 21MX CPU with 32KW memory
DMA0, DMA1 dual channel DMA controller
PTR,PTP 12597A paper tape reader/punch
TTY 12631C buffered teleprinter
LPT 12653A line printer
CLK 12539A/B/C time base generator
DP 12557A cartridge disk controller with four drives
MT 12559C magnetic tape controller with one drives
The HP2100 simulator implements several unique stop conditions:
- decode of an undefined instruction, and STOP_INST is et
- reference to an undefined I/O device, and STOP_DEV is set
- more than INDMAX indirect references are detected during
memory reference address decoding
The HP2100 loader supports standard absolute binary format. The DUMP
command is not implemented.
2.1 CPU
CPU options include choice of instruction set and memory size.
SET CPU 2116 2116 instructions
SET CPU 2100 2100 instructions
SET CPU 21MX 21MX instructions
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 16K set memory size = 16K
SET CPU 24K set memory size = 24K
SET CPU 32K set memory size = 32K
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 32K.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
P 15 program counter
A 16 A register
B 16 B register
X 16 X index register (21MX)
Y 16 Y index register (21MX)
S 16 switch/display register
E 1 extend flag
O 1 overflow flag
ION 1 interrupt enable flag
ION_DEFER 1 interrupt defer flag
IADDR 6 most recent interrupting device
MPCTL 1 memory protection enable (2100, 21MX)
MPFLG 1 memory protection flag (2100, 21MX)
MPFBF 1 memory protection flag buffer (2100, 21MX)
MFENCE 15 memory protection fence (2100, 21MX)
MADDR 16 memory protection error address (2100, 21MX)
STOP_INST 1 stop on undefined instruction
STOP_DEV 1 stop on undefined device
INDMAX 1 indirect address limit
OLDP 15 PC prior to last JMP, JSB, or interrupt
WRU 8 interrupt character
2.2 DMA Controllers
The HP2100 includes two DMA channel controllers (DMA0 and DMA1). Each
DMA channel has the following visible state:
name size comments
CMD 1 channel enabled
CTL 1 interrupt enabled
FLG 1 channel ready
FBF 1 channel ready buffer
CW1 1 command word 1
CW2 1 command word 2
CW3 1 command word 3
2.3 Variable Device Assignments
On the HP2100, I/O device take their device numbers from the backplane
slot they are plugged into. Thus, device number assignments vary
considerably from system to system, and software package to software
package. The HP2100 simulator supports dynamic device number assignment.
The current device device is shown with the command SHOW <dev> DEVNO:
sim> SHOW PTR DEV
device=10
The user can change the device number with the SET <dev> DEVNO=<num>
command:
sim> SET PTR DEV=30
sim> SHOW PTR DEV
device=30
The new device number must be in the range 010..077 (octal) and must
not be currently assigned to another device. For devices with two
device numbers, only the lower numbered device number can be changed;
the higher is automatically set to the lower + 1.
2.4 Programmed I/O Devices
2.4.1 12597A-002 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 supports the BOOT command. BOOT PTR copies the
absolute binary loader into memory and starts it running.
The paper tape reader implements these registers:
name size comments
BUF 8 last data item processed
CMD 1 reader enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
POS 31 position in the input file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
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 or paper
OS I/O error x report error and stop
2.4.2 12597A-005 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 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
CMD 1 punch enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
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.4.3 12631C Buffered Teleprinter (TTY)
The console teleprinter has three units: keyboard (unit 0), printer
(unit 1), and punch (unit 2). The keyboard reads from the console
keyboard; the printer writes to the simulator console window. The
punch writes to a disk file. The keyboard has one option, UC; when
set, it automatically converts lower case input to upper case. This
is on by default.
The terminal implements these registers:
name size comments
BUF 8 last data item processed
MODE 16 mode
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
KPOS 31 number of characters input
KTIME 24 keyboard polling interval
TPOS 31 number of characters printed
TTIME 24 time from I/O initiation to interrupt
PPOS 31 position in the punch output file
STOP_IOE 1 punch stop on I/O error
DEVNO 6 current device number (read only)
Error handling for the punch 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.4.4 12653A Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The line printer implements these registers:
name size comments
BUF 8 last data item processed
CMD 1 printer enable
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
POS 31 position in the output file
CTIME 24 time between characters
PTIME 24 time for a print operation
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.4.5 12539A/B/C Time Base Generator (CLK)
The time base generator (CLK) implements these registers:
name size comments
SEL 3 time base select
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
ERR 1 error flag
TIME[0:7] 31 clock intervals, select = 0..7
DEVNO 6 current device number (read only)
2.5 12557A Cartridge Disk (DP)
The 12557A cartridge disk has two separate devices, a data channel and
a device controller. The data channel includes a 128-word (one sector)
buffer for reads and writes. The device controller includes the four
disk drives. Disk drives can be REMOVEd or ADDed to the configuration.
The data channel implements these registers:
name size comments
IBUF 16 input buffer
OBUF 16 output buffer
BPTR 7 sector buffer pointer
CMD 1 channel enable
CTL 1 interrupt enable
FLG 1 channel ready
FBF 1 channel ready buffer
DEVNO 6 current device number (read only)
The device controller implements these registers:
name size comments
OBUF 16 output buffer
BUSY 3 busy (unit #, + 1, of active unit)
RARC 8 record address register cylinder
RARH 2 record address register head
RARS 4 record address register sector
CNT 5 check record count
CMD 1 controller enable
CTL 1 interrupt enable
FLG 1 controller ready
FBF 1 controller ready buffer
EOC 1 end of cylinder pending
CTIME 24 command delay time
STIME 24 seek delay time, per cylinder
XTIME 24 interword transfer time
STA[0:3] 16 drive status, drives 0-3
DEVNO 6 current device number (read only)
Error handling is as follows:
error processed as
not attached disk not ready
end of file assume rest of disk is zero
OS I/O error report error and stop
2.6 12559C Magnetic Tape (MT)
Magnetic tape options include the ability to make the unit write enabled
or write locked.
SET MT LOCKED set unit write locked
SET MT ENABLED set unit write enabled
The 12559C mag tape drive has two separate devices, a data channel and
a device controller. The data channel includes a maximum record sized
buffer for reads and writes. The device controller includes the tape
unit
The data channel implements these registers:
name size comments
FLG 1 channel ready
BPTR 16 buffer pointer (reads and writes)
BMAX 16 buffer size (writes)
DEVNO 6 current device number (read only)
The device controller implements these registers:
name size comments
FNC 8 current function
STA 9 tape status
BUF 8 buffer
BUSY 3 busy (unit #, + 1, of active unit)
CTL 1 interrupt enabled
FLG 1 controller ready
FBF 1 controller ready buffer
DTF 1 data transfer flop
FSVC 1 first service flop
POS 31 magtape position
CTIME 24 command delay time
XTIME 24 interword transfer delay time
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
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.7 Symbolic Display and Input
The HP2100 simulator implements symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as two character string
-m display instruction mnemonics
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c two character sixbit string
alphabetic instruction mnemonic
numeric octal number
Instruction input uses standard HP2100 assembler syntax. There are seven
instruction classes: memory reference, I/O, shift, alter skip, extended
shift, extended memory reference, extended two address reference.
Memory reference instructions have the format
memref {C/Z} address{,I}
where I signifies indirect, C a current page reference, and Z a zero page
reference. The address is an octal number in the range 0 - 077777; if C or
Z is specified, the address is a page offset in the range 0 - 01777. Normally,
C is not needed; the simulator figures out from the address what mode to use.
However, when referencing memory outside the CPU (eg, disks), there is no
valid PC, and C must be used to specify current page addressing.
IOT instructions have the format
io device{,C}
where C signifies that the device flag is to be cleared. The device is an
octal number in the range 0 - 77.
Shift and alter/skip instructions have the format
sub-op sub-op sub-op...
The simulator checks that the combination of sub-opcodes is legal.
Extended shift instructions have the format
extshift count
where count is an octal number in the range 1 - 020.
Extended memory reference instructions have the format
extmemref address{,I}
where I signifies indirect addressing. The address is an octal number in
the range 0 - 077777.
Extended two address instructions have the format
ext2addr addr1{,I},addr2{,I}
where I signifies indirect addressing. Both address 1 and address 2 are
octal numbers in the range 0 - 077777.

View file

@ -25,6 +25,8 @@
dp 12557A cartridge disk system
03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW
24-Nov-01 RMS Changed STA to be an array
07-Sep-01 RMS Moved function prototypes
29-Nov-00 RMS Made variable names unique
21-Nov-00 RMS Fixed flag, buffer power up state
@ -182,10 +184,7 @@ REG dpc_reg[] = {
{ DRDATA (CTIME, dpc_ctime, 24), PV_LEFT },
{ DRDATA (STIME, dpc_stime, 24), PV_LEFT },
{ DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT },
{ ORDATA (STA0, dpc_sta[0], 16) },
{ ORDATA (STA1, dpc_sta[1], 16) },
{ ORDATA (STA2, dpc_sta[2], 16) },
{ ORDATA (STA3, dpc_sta[3], 16) },
{ BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) },
{ GRDATA (UFLG0, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (UFLG1, dpc_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
@ -200,7 +199,8 @@ REG dpc_reg[] = {
MTAB dpc_mod[] = {
/* { UNIT_WLK, 0, "write enabled", "ENABLED", &dpc_vlock }, */
/* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dpc_vlock }, */
{ UNIT_DEVNO, inDPD, NULL, "DEVNO", &hp_setdev2 },
{ MTAB_XTD | MTAB_VDV, inDPD, "DEVNO", "DEVNO",
&hp_setdev2, &hp_showdev2, NULL },
{ 0 } };
DEVICE dpc_dev = {

View file

@ -25,6 +25,7 @@
lpt 12653A line printer
03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW
07-Sep-01 RMS Moved function prototypes
21-Nov-00 RMS Fixed flag, fbf power up state
Added command flop
@ -68,7 +69,8 @@ REG lpt_reg[] = {
{ NULL } };
MTAB lpt_mod[] = {
{ UNIT_DEVNO, inLPT, NULL, "DEVNO", &hp_setdev },
{ MTAB_XTD | MTAB_VDV, inLPT, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 0 } };
DEVICE lpt_dev = {

View file

@ -25,6 +25,7 @@
mt 12559A nine track magnetic tape
03-Dec-01 RMS Added read only unit, extended SET/SHOW support
07-Sep-01 RMS Moved function prototypes
30-Nov-00 RMS Made variable names unique
04-Oct-98 RMS V2.4 magtape format
@ -54,6 +55,7 @@
#define DB_V_SIZE 16 /* max data buf */
#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */
#define DBMASK (DBSIZE - 1)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Command - mtc_fnc */
@ -97,7 +99,7 @@ static const int32 mtc_cmd[] = {
t_stat mtc_svc (UNIT *uptr);
t_stat mtc_reset (DEVICE *dptr);
t_stat mtc_vlock (UNIT *uptr, int32 val);
t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat mtc_attach (UNIT *uptr, char *cptr);
t_stat mtc_detach (UNIT *uptr);
t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
@ -136,7 +138,7 @@ DEVICE mtd_dev = {
mtc_mod MTC modifier list
*/
UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE, 0) };
UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) };
REG mtc_reg[] = {
{ ORDATA (FNC, mtc_fnc, 8) },
@ -159,7 +161,8 @@ REG mtc_reg[] = {
MTAB mtc_mod[] = {
{ UNIT_WLK, 0, "write enabled", "ENABLED", &mtc_vlock },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mtc_vlock },
{ UNIT_DEVNO, inMTD, NULL, "DEVNO", &hp_setdev2 },
{ MTAB_XTD | MTAB_VDV, inMTD, "DEVNO", "DEVNO",
&hp_setdev2, &hp_showdev2, NULL },
{ 0 } };
DEVICE mtc_dev = {
@ -236,7 +239,7 @@ case ioOTX: /* output */
((mtc_unit.flags & UNIT_ATT) == 0) ||
((mtc_sta & STA_BOT) &&
((dat == FNC_BSR) || (dat == FNC_REW) || (dat == FNC_RWS))) ||
((mtc_unit.flags & UNIT_WLK) &&
((mtc_unit.flags & UNIT_WPRT) &&
((dat == FNC_WC) || (dat == FNC_GAP) || (dat == FNC_WFM))))
mtc_sta = mtc_sta | STA_REJ;
else { sim_activate (&mtc_unit, mtc_ctime); /* start tape */
@ -254,7 +257,7 @@ case ioMIX: /* merge */
if (mtc_unit.flags & UNIT_ATT) { /* construct status */
mtc_sta = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY);
if (sim_is_active (&mtc_unit)) mtc_sta = mtc_sta | STA_BUSY;
if (mtc_unit.flags & UNIT_WLK) mtc_sta = mtc_sta | STA_WLK; }
if (mtc_unit.flags & UNIT_WPRT) mtc_sta = mtc_sta | STA_WLK; }
else mtc_sta = STA_BUSY | STA_LOCAL;
dat = dat | mtc_sta;
break;
@ -419,7 +422,7 @@ infotab[inMTC].flg = infotab[inMTD].flg = 0; /* clear flg */
infotab[inMTC].fbf = infotab[inMTD].fbf = 0; /* clear fbf */
sim_cancel (&mtc_unit); /* cancel activity */
if (mtc_unit.flags & UNIT_ATT) mtc_sta = ((mtc_unit.pos)? 0: STA_BOT) |
((mtc_unit.flags & UNIT_WLK)? STA_WLK: 0);
((mtc_unit.flags & UNIT_WPRT)? STA_WLK: 0);
else mtc_sta = STA_LOCAL | STA_BUSY;
return SCPE_OK;
}
@ -432,7 +435,7 @@ t_stat r;
r = attach_unit (uptr, cptr); /* attach unit */
if (r != SCPE_OK) return r; /* update status */
mtc_sta = STA_BOT | ((uptr -> flags & UNIT_WLK)? STA_WLK: 0);
mtc_sta = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
return r;
}
@ -446,9 +449,9 @@ return detach_unit (uptr); /* detach unit */
/* Write lock/enable routine */
t_stat mtc_vlock (UNIT *uptr, int32 val)
t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr -> flags & UNIT_ATT) return SCPE_ARG;
if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG;
return SCPE_OK;
}

View file

@ -28,6 +28,9 @@
tty 12531C buffered teleprinter interface
clk 12539A/B/C time base generator
03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW
29-Nov-01 RMS Added read only unit support
24-Nov-01 RMS Changed TIME to an array
07-Sep-01 RMS Moved function prototypes
21-Nov-00 RMS Fixed flag, buffer power up state
Added status input for ptp, tty
@ -82,7 +85,8 @@ t_stat clk_reset (DEVICE *dptr);
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
@ -97,7 +101,8 @@ REG ptr_reg[] = {
{ NULL } };
MTAB ptr_mod[] = {
{ UNIT_DEVNO, inPTR, NULL, "DEVNO", &hp_setdev },
{ MTAB_XTD | MTAB_VDV, inPTR, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 0 } };
DEVICE ptr_dev = {
@ -130,7 +135,8 @@ REG ptp_reg[] = {
{ NULL } };
MTAB ptp_mod[] = {
{ UNIT_DEVNO, inPTP, NULL, "DEVNO", &hp_setdev },
{ MTAB_XTD | MTAB_VDV, inPTP, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 0 } };
DEVICE ptp_dev = {
@ -153,7 +159,7 @@ DEVICE ptp_dev = {
UNIT tty_unit[] = {
{ UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT },
{ UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT },
{ UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT } };
REG tty_reg[] = {
@ -176,7 +182,8 @@ REG tty_reg[] = {
MTAB tty_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_DEVNO, inTTY, NULL, "DEVNO", &hp_setdev },
{ MTAB_XTD | MTAB_VDV, inTTY, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 0 } };
DEVICE tty_dev = {
@ -203,19 +210,13 @@ REG clk_reg[] = {
{ FLDATA (FLG, infotab[inCLK].flg, 0) },
{ FLDATA (FBF, infotab[inCLK].fbf, 0) },
{ FLDATA (ERR, clk_error, CLK_V_ERROR) },
{ DRDATA (TIME0, clk_delay[0], 31), PV_LEFT },
{ DRDATA (TIME1, clk_delay[1], 31), PV_LEFT },
{ DRDATA (TIME2, clk_delay[2], 31), PV_LEFT },
{ DRDATA (TIME3, clk_delay[3], 31), PV_LEFT },
{ DRDATA (TIME4, clk_delay[4], 31), PV_LEFT },
{ DRDATA (TIME5, clk_delay[5], 31), PV_LEFT },
{ DRDATA (TIME6, clk_delay[6], 31), PV_LEFT },
{ DRDATA (TIME7, clk_delay[7], 31), PV_LEFT },
{ BRDATA (TIME, clk_delay, 8, 31, 8) },
{ ORDATA (DEVNO, infotab[inCLK].devno, 6), REG_RO },
{ NULL } };
MTAB clk_mod[] = {
{ UNIT_DEVNO, inCLK, NULL, "DEVNO", &hp_setdev },
{ MTAB_XTD | MTAB_VDV, inCLK, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 0 } };
DEVICE clk_dev = {
@ -447,6 +448,8 @@ t_stat tto_out (int32 ch)
t_stat ret = SCPE_OK;
if (tty_mode & TM_PRI) { /* printing? */
if ((tty_unit[TTI].flags & UNIT_UC) && islower (ch)) /* upper case? */
ch = toupper (ch);
ret = sim_putchar (ch & 0177); /* output char */
tty_unit[TTO].pos = tty_unit[TTO].pos + 1; }
if (tty_mode & TM_PUN) { /* punching? */

View file

@ -35,6 +35,7 @@
Cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files.
29-Nov-01 RMS Added read only unit support
13-Apr-01 RMS Revised for register arrays
*/
@ -60,7 +61,7 @@ t_stat cd_reset (DEVICE *dptr);
*/
UNIT cdr_unit = {
UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 100 };
UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), 100 };
REG cdr_reg[] = {
{ FLDATA (LAST, ind[IN_LST], 0) },

View file

@ -23,6 +23,7 @@
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.
30-Nov-01 RMS Added extended SET/SHOW support
10-Aug-01 RMS Removed register in declarations
07-Dec-00 RMS Fixed bugs found by Charles Owen
-- 4,7 char NOPs are legal
@ -105,8 +106,6 @@
#include "i1401_defs.h"
#define ILL_ADR_FLAG 100000 /* invalid addr flag */
#define save_ibkpt (cpu_unit.u3) /* saved bkpt addr */
#define MM(x) x = x - 1; \
if (x < 0) { \
x = BA + MAXMEMSIZE - 1; \
@ -135,14 +134,13 @@ int32 ind[64] = { 0 }; /* indicators */
int32 ssa = 1; /* sense switch A */
int32 prchk = 0; /* process check stop */
int32 iochk = 0; /* I/O check stop */
int32 ibkpt_addr = ILL_ADR_FLAG + MAXMEMSIZE; /* breakpoint addr */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
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_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
int32 store_addr_h (int32 addr);
int32 store_addr_t (int32 addr);
int32 store_addr_u (int32 addr);
@ -167,7 +165,7 @@ extern t_stat sim_activate (UNIT *uptr, int32 delay);
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BCD + STDOPT,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BCD + STDOPT,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -191,7 +189,6 @@ REG cpu_reg[] = {
{ FLDATA (IOCHK, iochk, 0) },
{ FLDATA (PRCHK, prchk, 0) },
{ DRDATA (OLDIS, oldIS, 14), REG_RO + PV_LEFT },
{ DRDATA (BREAK, ibkpt_addr, 17), PV_LEFT },
{ ORDATA (WRU, sim_int_char, 8) },
{ NULL } };
@ -420,10 +417,7 @@ saved_IS = IS; /* commit prev instr */
if (sim_interval <= 0) { /* check clock queue */
if (reason = sim_process_event ()) break; }
if (IS == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save ibkpt */
ibkpt_addr = ibkpt_addr + ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ && sim_brk_test (IS, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
@ -1061,15 +1055,7 @@ for (i = 0; i < 64; i++) ind[i] = 0;
ind[IN_UNC] = 1;
AS = 0; as_err = 1;
BS = 0; bs_err = 1;
return cpu_svc (&cpu_unit);
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr - ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
@ -1093,17 +1079,17 @@ return SCPE_OK;
/* Memory size change */
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value % 1000) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val % 1000) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
if (MEMSIZE > 4000) cpu_unit.flags = cpu_unit.flags | MA;
else cpu_unit.flags = cpu_unit.flags & ~MA;

428
I1401/i1401_doc.txt Normal file
View file

@ -0,0 +1,428 @@
To: Users
From: Bob Supnik
Subj: IBM 1401 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 IBM 1401 simulator.
1. Simulator Files
sim/ sim_defs.h
scp.c
scp_tty.c
sim_rev.c
sim/i1401/ i1401_defs.h
i1401_cpu.c
i1401_iq.c
i1401_lp.c
i1401_mt.c
i1401_sys.c
2. IBM 1401 Features
The IBM 1401 simulator is configured as follows:
device simulates
name(s)
CPU IBM 1401 CPU with 16K of memory
CDR,CDP IBM 1402 card reader/punch
LPT IBM 1403 line printer
INQ IBM 1407 inquiry terminal
MT IBM 729 7-track magnetic tape controller with six drives
The IBM 1401 simulator implements many unique stop conditions. On almost
any kind of error the simulator stops:
unimplemented opcode
reference to non-existent memory
reference to non-existent device
no word mark under opcode
invalid A address
invalid B address
invalid instruction length
invalid modifier character
invalid branch address
invalid magtape unit number
invalid magtape record length
write to locked magtape drive
skip to unpunched carriage control tape channel
card reader hopper empty
address register wrap-around
single character A field in MCE
single character B field in MCE
hanging $ in MCE with EPE enabled
I/O check with I/O stop switch set
The LOAD and DUMP commands are not implemented.
2.1 CPU
The CPU options include a number of special features and the size of main
memory. Note that the Modify Address special feature is always included
when memory size is greater than 4K.
SET CPU XSA enable advanced programming special feature
SET CPU NOXSA disable advanced programming
SET CPU HLE enable high/low/equal special feature
SET CPU NOHLE disable high/low/equal
SET CPU BBE enable branch on bit equal special feature
SET CPU NOBBE disable branch on bit equal
SET CPU MR enable move record special feature
SET CPU NOMR disable move record
SET CPU EPE enable extended print edit special feature
SET CPU NOEPE disable extended print edit
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initially, memory size is 16K, and all special
features are enabled.
Memory is implemented as 7 bit BCD characters, as follows:
6 5 4 3 2 1 0
word B bit A bit 8 4 2 1
mark <-- zone --> <-------- digit -------->
In BCD, the decimal digits 0-9 are (octal) values 012, 001, 002, 003, 004,
005, 006, 007, 010, 011, respectively. Signs are encoded in the zone bits,
with 00, 01, and 11 being positive, and 10 being negative.
CPU registers include the visible state of the processor. The 1401 has no
interrupt system.
name size comments
IS 14 instruction storage address register (PC)
AS 14 A storage address register
BS 14 B storage address register
ASERR 1 AS invalid flag
BSERR 1 BS invalid flag
SSA 1 sense switch A
SSB 1 sense switch B
SSC 1 sense switch C
SSD 1 sense switch D
SSE 1 sense switch E
SSF 1 sense switch F
SSG 1 sense switch G
EQU 1 equal compare indicator
UNEQ 1 unequal compare indicator
HIGH 1 high compare indicator
LOW 1 low compare indicator
OVF 1 overflow indicator
IOCHK 1 I/O check switch
PRCHK 1 process check switch
OLDIS 1 IS prior to last branch
WRU 8 interrupt character
2.2 1402 Card Reader/Punch (CDR, CDP, STKR)
The IBM 1402 card/reader punch is simulated as three independent devices:
the card reader (CDR), the card punch (CDP), and the reader and punch
stackers (STKR). STRK units 0, 1, 2, and 4 correspond to the reader
normal stacker, reader stacker 1, shared stacker 2/8, and punch stacker
4, respectively.
The card reader supports the BOOT command. BOOT CDR reads a card image
into locations 1-80, sets a word mark under location 1, clears storage,
and then transfers control to location 1.
The card reader reads data from disk files, while the punch and stackers
write data to disk files. Cards are simulated as ASCII text lines with
terminating newlines; column binary is not supported. For each unit,
the POS register specifies the number of the next data item to be read or
written. Thus, by changing POS, the user can backspace or advance these
devices.
The reader/punch registers are:
device name size comments
CDR LAST 1 last card indicator
ERR 1 error indicator
S1 1 stacker 1 select flag
S2 1 stacker 2 select flag
POS 31 position
TIME 24 delay window for stacker select
BUF[0:79] 8 reader buffer
CDP ERR 1 error indicator
S4 1 stacker 4 select flag
S8 1 stacker 8 select flag
STKR POS0 31 position, normal reader stack
POS1 31 position, reader stacker 1
POS2 31 position, shared stacker 2/8
POS4 31 position, punch stacker 4
Error handling is as follows:
device error processed as
reader end of file if SSA set, set LAST indicator
on next Read, report error and stop
reader,punch not attached report error and stop
OS I/O error print error message
if IOCHK set, report error and stop
otherwise, set ERR indicator
stacker not attached ignored
OS I/O error print error message
if IOCHK set, report error and stop
2.3 1403 Line Printer (LPT)
The IBM 1403 line printer (LPT) writes its data, converted to ASCII, to
a disk file. The line printer supports three different print character
sets or "chains":
SET LPT PCF full 64 character chain
SET LPT PCA 48 character business chain
SET LPT PCH 48 character FORTRAN chain
In addition, the line printer can be programmed with a carriage control
tape. The LOAD command loads a new carriage control tape:
LOAD <file> load carriage control tape file
The format of a carriage control tape consists of multiple lines. Each
line contains an optional repeat count, enclosed in parentheses, optionally
followed by a series of column numbers separated by commas. Column numbers
must be between 1 and 12; a column number of zero denotes top of form. The
following are all legal carriage control specifications:
<blank line> no punch
(5) 5 lines with no punches
1,5,7,8 columns 1, 5, 7, 8 punched
(10)2 10 lines with column 2 punched
1,0 column 1 punched; top of form
The default form is 66 lines long, with column 1 and the top of form mark
on line 1, and the rest blank.
The line printer registers are:
name size comments
LINES 8 number of newlines after next print
LFLAG 1 carriage control flag (1 = skip, 0 = space)
CCTP 8 carriage control tape pointer
CCTL 8 carriage control tape length (read only)
ERR 1 error indicator
POS 31 position
CCT[0:131] 32 carriage control tape array
Error handling is as follows:
error processed as
not attached report error and stop
OS I/O error print error message
if IOCHK set, report error and stop
otherwise, set ERR indicator
2.4 1407 Inquiry Terminal (INQ)
The IBM 1407 inquiry terminal (INQ) is a half-duplex console. It polls
the console keyboard periodically for inquiry requests. The inquiry
terminal registers are:
name size comments
INQC 7 inquiry request character (initially ESC)
INR 1 inquiry request indicator
INC 1 inquiry cleared indicator
TIME 24 polling interval
When the 1401 CPU requests input from the keyboard, the message [Enter]
is printed out, followed by a new line. The CPU hangs waiting for input
until either the return/enter key is pressed, or the inquiry request
character is typed in. The latter cancels the type-in and sets INC.
The inquiry terminal has no errors.
2.5 729 Magnetic Tape (MT)
The magnetic tape controller supports six drives, numbered 1 through 6.
Magnetic tape options include the ability to make units write enabled or
or write locked.
SET MTn LOCKED set unit n write locked
SET MTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration. The magnetic
tape simulator supports the BOOT command. BOOT MT reads the first
record off tape, starting at location 1, and then branches to it.
The magnetic tape controller implements these registers:
name size comments
END 1 end of file indicator
ERR 1 error indicator
PAR 1 parity error indicator
POS1..6 31 position, drives 1..6
Error handling is as follows:
error processed as
not attached report error and stop
end of file (read or space) end of physical tape
(write) ignored
OS I/O error print error message
if IOCHK set, report error and stop
otherwise, set ERR indicator
2.6 Symbolic Display and Input
The IBM 1401 simulator implements symbolic display and input. Display is
controlled by command line switches:
-c display as single character
(BCD for CPU and MT, ASCII for others)
-s display as wordmark terminated BCD string
(CPU only)
-m display instruction mnemonics
(CPU only)
In a CPU character display, word marks are denoted by ~.
Input parsing is controlled by the first character typed in or by command
line switches:
' or " or -c or -s characters (BCD for CPU and MT, ASCII
for others)
alphabetic instruction mnemonic
numeric octal number
Instruction input is free format, with spaces separating fields. There
are six instruction formats: 1, 2, 4, 5, 7, and 8 characters:
1 character opcode
2 character opcode 'modifier
4 character opcode address
5 character opcode address 'modifier
7 character opcode address address
8 character opcode address address 'modifier
Addresses are always decimal, except for special I/O addresses in the A
field, which may be specified as %xy, where x denotes the device and y
the unit number.
For the CPU, string input may encompass multiple characters. A word mark
is denoted by ~ and must precede the character to be marked. All other
devices can only accept single character input, without word marks.
2.7 Character Sets
The IBM 1401 used a 6b character code called BCD (binary coded decimal).
Some of the characters have no equivalent in ASCII and require different
representations:
BCD ASCII IBM 1401 print
code representation character chains
00 space
01 1
02 2
03 3
04 4
05 5
06 6
07 7
10 8
11 9
12 0
13 # = in H chain
14 @ ' in H chain
15 : blank in A, H chains
16 > blank in A, H chains
17 ( tape mark blank in A, H chains
20 ^ alternate blank blank in A, H chains
21 /
22 S
23 T
24 U
25 V
26 W
27 X
30 Y
31 Z
32 ' record mark
33 ,
34 % ( in H chain
35 = word mark blank in A, H chains
36 \ blank in A, H chains
37 + blank in A, H chains
40 -
41 J
42 K
43 L
44 M
45 N
46 O
47 P
50 Q
51 R
52 !
53 $
54 *
55 ] blank in A, H chains
56 ; blank in A, H chains
57 _ delta blank in A, H chains
60 &
61 A
62 B
63 C
64 D
65 E
66 F
67 G
70 H
71 I
72 ?
73 .
74 ) lozenge
75 [ blank in A, H chains
76 < blank in A, H chains
77 " group mark blank in A, H chains

View file

@ -23,6 +23,8 @@
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.
inq 1407 inquiry terminal
07-Sep-01 RMS Moved function prototypes
14-Apr-99 RMS Changed t_addr to unsigned
*/

View file

@ -23,7 +23,7 @@
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.
lpt 1403 line printer
lpt 1403 line printer
13-Apr-01 RMS Revised for register arrays
*/

View file

@ -1,4 +1,4 @@
/* IBM 1401 magnetic tape simulator
/* i1401_mt.c: IBM 1401 magnetic tape simulator
Copyright (c) 1993-2001, Robert M. Supnik
@ -23,6 +23,9 @@
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.
mt 7-track magtape
29-Nov-01 RMS Added read only unit support
18-Apr-01 RMS Changed to rewind tape before boot
07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt
CEO Added tape bootstrap
@ -50,6 +53,7 @@
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_W_UF 2 /* #save flags */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
extern uint8 M[]; /* memory */
extern int32 ind[64];
@ -70,12 +74,18 @@ UNIT *get_unit (int32 unit);
UNIT mt_unit[] = {
{ UDATA (NULL, UNIT_DIS, 0) }, /* doesn't exist */
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) } };
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
UNIT_ROABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
UNIT_ROABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
UNIT_ROABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
UNIT_ROABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
UNIT_ROABLE + UNIT_BCD, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
UNIT_ROABLE + UNIT_BCD, 0) } };
REG mt_reg[] = {
{ FLDATA (END, ind[IN_END], 0) },
@ -145,10 +155,10 @@ case BCD_B: /* backspace */
(2 * sizeof (t_mtrlnt));
break; /* end case */
case BCD_E: /* erase = nop */
if (uptr -> flags & UNIT_WLK) return STOP_MTL;
if (uptr -> flags & UNIT_WPRT) return STOP_MTL;
return SCPE_OK;
case BCD_M: /* write tapemark */
if (uptr -> flags & UNIT_WLK) return STOP_MTL;
if (uptr -> flags & UNIT_WPRT) return STOP_MTL;
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref);
err = ferror (uptr -> fileref);
@ -223,7 +233,7 @@ case BCD_R: /* read */
break;
case BCD_W:
if (uptr -> flags & UNIT_WLK) return STOP_MTL; /* locked? */
if (uptr -> flags & UNIT_WPRT) return STOP_MTL; /* locked? */
if (M[BS] == (BCD_GRPMRK + WM)) return STOP_MTZ; /* eor? */
ind[IN_TAP] = ind[IN_END] = 0; /* clear error */
for (tbc = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); ) {

View file

@ -2,9 +2,9 @@ Charles Owen's Eclipse Modules
1. Eclipse CPU simulator
The Eclipse CPU simulator can be used with the V2.5a Nova definitions and peripheral
modules to produce an Eclipse simulator that will run Eclipse mapped RDOS V7.5. The
compilation procedure is the same as for the Nova simulator, except:
The Eclipse CPU simulator can be used with the Nova definitions and peripheral
modules to produce an Eclipse simulator that will run Eclipse mapped RDOS V7.5.
The compilation procedure is the same as for the Nova simulator, except:
- the symbol ECLIPSE must be defined
- the module eclipse_cpu.c must be substituted for nova_cpu.c

View file

@ -28,6 +28,7 @@
cpu Eclipse central processor
30-Nov-01 RMS Added extended SET/SHOW support
01-Jun-01 RMS Added second terminal, plotter support
26-Apr-01 RMS Added device enable/disable support
@ -313,8 +314,6 @@
#include "nova_defs.h"
#define ILL_ADR_FLAG 0100000
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MICRO (UNIT_V_UF) /* Microeclipse? */
#define UNIT_MICRO (1 << UNIT_V_MICRO)
#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */
@ -336,7 +335,6 @@ int32 pimask = 0; /* priority int mask */
int32 pwr_low = 0; /* power fail flag */
int32 ind_max = 15; /* iadr nest limit */
int32 stop_dev = 0; /* stop on ill dev */
int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* ibreakpoint addr */
int32 old_PC = 0; /* previous PC */
int32 model = 130; /* Model of Eclipse */
int32 speed = 0; /* Delay for each instruction */
@ -417,15 +415,15 @@ int32 Tron = 0; /* For trace files */
FILE *Trace;
t_stat reason;
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
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_svc (UNIT *uptr);
t_stat cpu_boot (int32 unitno);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat Debug_Dump (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat Debug_Dump (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat map_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat map_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat map_reset (DEVICE *dptr);
@ -494,7 +492,7 @@ struct ndev dev_table[64] = {
cpu_mod CPU modifiers list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -517,7 +515,6 @@ REG cpu_reg[] = {
{ FLDATA (MICRO, cpu_unit.flags, UNIT_V_MICRO), REG_HRO },
{ DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
{ ORDATA (DEBUG, Debug_Flags, 16) },
{ ORDATA (BREAK, ibkpt_addr, 16) },
{ DRDATA (MODEL, model, 16) },
{ DRDATA (SPEED, speed, 16) },
{ ORDATA (WRU, sim_int_char, 8) },
@ -714,10 +711,7 @@ if (Inhibit != 0) { /* Handle 1-instruction inhibit sequence */
Inhibit = 0;
}
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save address */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break;
}
@ -3223,7 +3217,8 @@ int_req = int_req & ~INT_ION;
pimask = 0;
dev_disable = 0;
pwr_low = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -3244,26 +3239,17 @@ M[addr] = val & 0177777;
return SCPE_OK;
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}
@ -3366,7 +3352,7 @@ int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32
return 0;
}
int32 Debug_Dump(UNIT *uptr, int32 value)
int32 Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc)
{
char debmap[4], debion[4];
t_value simeval[20];

View file

@ -25,6 +25,8 @@
cpu Nova central processor
07-Dec-01 RMS Revised to use breakpoint package
30-Nov-01 RMS Added extended SET/SHOW support
10-Aug-01 RMS Removed register in declarations
17-Jul-01 RMS Moved function prototype
26-Apr-01 RMS Added device enable/disable support
@ -211,8 +213,6 @@
M[x] = (M[x] - 1) & 0177777; \
x = M[x] & AMASK
#define ILL_ADR_FLAG A_IND
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MDV (UNIT_V_UF) /* MDV present */
#define UNIT_MDV (1 << UNIT_V_MDV)
#define UNIT_V_STK (UNIT_V_UF+1) /* stack instr */
@ -241,15 +241,14 @@ int32 pimask = 0; /* priority int mask */
int32 pwr_low = 0; /* power fail flag */
int32 ind_max = 16; /* iadr nest limit */
int32 stop_dev = 0; /* stop on ill dev */
int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* ibreakpoint addr */
int32 old_PC = 0; /* previous PC */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
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_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_boot (int32 unitno);
extern int32 ptr (int32 pulse, int32 code, int32 AC);
extern int32 ptp (int32 pulse, int32 code, int32 AC);
@ -310,7 +309,7 @@ struct ndev dev_table[64] = {
cpu_mod CPU modifiers list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + UNIT_MDV,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_MDV,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -338,7 +337,6 @@ REG cpu_reg[] = {
{ FLDATA (IBYT, cpu_unit.flags, UNIT_V_BYT), REG_HRO },
{ DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
{ ORDATA (OLDPC, old_PC, 15), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 16) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (IOTENB, iot_enb, 32), REG_HRO },
{ NULL } };
@ -401,10 +399,7 @@ if (int_req > INT_PENDING) { /* interrupt? */
break; }
PC = MA; } /* end interrupt */
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save address */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
@ -828,7 +823,8 @@ int_req = int_req & ~(INT_ION | INT_STK);
pimask = 0;
dev_disable = 0;
pwr_low = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -849,26 +845,17 @@ M[addr] = val & DMASK;
return SCPE_OK;
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}

View file

@ -25,6 +25,8 @@
dkp moving head disk
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Changed FLG, CAPAC to arrays
26-Apr-01 RMS Added device enable/disable support
12-Dec-00 RMS Added Eclipse support from Charles Owen
15-Oct-00 RMS Editorial changes
@ -51,6 +53,7 @@
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define FUNC u3 /* function */
#define CYL u4 /* on cylinder */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Unit, surface, sector, count register
@ -282,7 +285,7 @@ t_stat dkp_reset (DEVICE *dptr);
t_stat dkp_boot (int32 unitno);
t_stat dkp_attach (UNIT *uptr, char *cptr);
t_stat dkp_go (void);
t_stat dkp_set_size (UNIT *uptr, int32 value);
t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
#if defined (ECLIPSE)
extern int32 MapAddr (int32 map, int32 addr);
#else
@ -299,13 +302,13 @@ extern int32 MapAddr (int32 map, int32 addr);
UNIT dkp_unit[] = {
{ UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
{ UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
{ UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) },
{ UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) } };
UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) } };
REG dkp_reg[] = {
{ ORDATA (FCCY, dkp_fccy, 16) },
@ -318,18 +321,10 @@ REG dkp_reg[] = {
{ FLDATA (DISABLE, dev_disable, INT_V_DKP) },
{ DRDATA (STIME, dkp_swait, 24), PV_LEFT },
{ DRDATA (RTIME, dkp_rwait, 24), PV_LEFT },
{ GRDATA (FLG0, dkp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, dkp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, dkp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, dkp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ DRDATA (CAPAC0, dkp_unit[0].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC1, dkp_unit[1].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC2, dkp_unit[2].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC3, dkp_unit[3].capac, 32), PV_LEFT + REG_HRO },
{ URDATA (FLG, dkp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
DKP_NUMDR, REG_HRO) },
{ URDATA (CAPAC, dkp_unit[0].capac, 10, 31, 0,
DKP_NUMDR, PV_LEFT | REG_HRO) },
{ FLDATA (*DEVENB, iot_enb, INT_V_DKP), REG_HRO },
{ NULL } };
@ -572,7 +567,7 @@ if (uptr -> FUNC == FCCY_SEEK) { /* seek? */
return SCPE_OK; }
if (((uptr -> flags & UNIT_ATT) == 0) || /* not attached? */
((uptr -> flags & UNIT_WLK) && (uptr -> FUNC == FCCY_WRITE)))
((uptr -> flags & UNIT_WPRT) && (uptr -> FUNC == FCCY_WRITE)))
dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */
else if ((uptr -> CYL >= drv_tab[dtype].cyl) || /* bad cylinder */
@ -673,10 +668,10 @@ return SCPE_OK;
/* Set size command validation routine */
t_stat dkp_set_size (UNIT *uptr, int32 value)
t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
uptr -> capac = drv_tab[GET_DTYPE (value)].size;
uptr -> capac = drv_tab[GET_DTYPE (val)].size;
return SCPE_OK;
}

565
NOVA/nova_doc.txt Normal file
View file

@ -0,0 +1,565 @@
To: Users
From: Bob Supnik
Subj: Nova 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 Nova simulator.
1. Simulator Files
sim/ sim_defs.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_rev.c
sim_sock.c
sim_tmxr.c
sim/nova/ nova_defs.h
nova_cpu.c
nova_clk.c
nova_dkp.c
nova_dsk.c
nova_lp.c
nova_mta.c
nova_plt.c
nova_sys.c
nova_tt.c
nova_tt1.c
2. Nova Features
The Nova simulator is configured as follows:
device simulates
name(s)
CPU Nova CPU with 32KW of memory
- hardware multiply/divide
PTR,PTP paper tape reader/punch
TTI,TTO console terminal
TTI1,TTO1 second terminal
LPT line printer
PLT plotter
CLK real-time clock
DK head-per-track disk controller
DP moving head disk controller with four drives
MT magnetic tape controller with eight drives
The TTI1/TTO1, PLT, DK, DP, and MT devices can be DISABLEd.
The Nova simulator implements these unique stop conditions:
- reference to undefined I/O device, and STOP_DEV is set
- more than INDMAX indirect addresses are detected during
an interrupt
- more than INDMAX indirect addresses are detected during
memory reference address decoding
The Nova loader supports standard binary format tapes. The DUMP command
is not implemented.
2.1 CPU
The only CPU options are the presence of the optional instructions
and the size of main memory.
SET CPU NOVA4 enable Nova4 instructions
SET CPU NOVA3 enable Nova3 instructions
SET CPU MDV enable multiply/divide
SET CPU NONE disable all optional instructions
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
SET CPU 20K set memory size = 20K
SET CPU 24K set memory size = 24K
SET CPU 28K set memory size = 28K
SET CPU 32K set memory size = 32K
(MDV = unsigned multiply/divide instructions)
(Nova 3 = unsigned multiply/divide, stack, trap instructions)
(Nova 4 = unsigned and signed multiply/divide, stack, byte, trap instructions)
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 32K.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
PC 15 program counter
AC0..AC3 16 accumulators 0..3
C 1 carry
SR 16 front panel switches
PI 16 priority interrupt mask
ION 1 interrupt enable
ION_DELAY 1 interrupt enable delay for ION
PWR 1 power fail interrupt
INT 15 interrupt pending flags
BUSY 15 device busy flags
DONE 15 device done flags
DISABLE 15 device interrupt disable flags
STOP_DEV 1 stop on undefined IOT
INDMAX 15 maximum number of nested indirects
OLDPC 15 PC prior to last JMP, JMS, or interrupt
WRU 8 interrupt character
2.2 Programmed I/O Devices
2.2.1 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
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
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 or paper
end of file 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.2.2 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 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
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 position in the 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 or paper
OS I/O error x report error and stop
2.2.3 Terminal Input (TTI)
The terminal input polls the console keyboard for input. Terminal
input options include the ability to set ANSI mode or limited Dasher
compatibility mode:
SET TTI ANSI normal mode
SET TTI DASHER Dasher mode
Setting either TTI or TTO changes both devices. In Dasher mode, carriage
return is changed to newline on input, and ^X is changed to backspace.
The terminal input implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 number of characters input
TIME 24 keyboard polling interval
2.2.4 Terminal Output (TTO)
The terminal output writes to the simulator console window. Terminal
output options include the the ability to set ANSI mode or limited
Dasher compatibility mode:
SET TTO ANSI normal mode
SET TTO DASHER Dasher mode
Setting either TTI or TTO changes both devices. In Dasher mode, carriage
return is changed to newline on input, and ^X is changed to backspace.
The terminal output implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 number of characters output
TIME 24 time from I/O initiation to interrupt
2.2.5 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The line printer implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 position in the 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 paper
OS I/O error x report error and stop
2.2.6 Real-Time Clock (CLK)
The real-time clock (CLK) implements these registers:
name size comments
SELECT 2 selected clock interval
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
TIME0 24 clock frequency, select = 0
TIME1 24 clock frequency, select = 1
TIME2 24 clock frequency, select = 2
TIME3 24 clock frequency, select = 3
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.7 Plotter (PTP)
The plotter (PLT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the plotter.
The plotter implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 position in the 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 or paper
OS I/O error x report error and stop
2.2.8 Second Terminal (TTI1, TTO1)
The second terminal consists of two independent devices, TTI1 and TTO1.
The additional terminal performs input and output through a Telnet session
connecting into a user-specified port. The ATTACH command specifies the
port to be used:
ATTACH TTI1 <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.
Once TTI1 is attached and the simulator is running, the terminal listens
for a connection on the specified port. It assumes that the incoming
connection is a Telnet connection. The connection remain opens until
disconnected by the Telnet client, or by a DETACH TTI1 command.
The second terminal has two options, recognized on both devices, for
setting limited Dasher-compatibility mode or ANSI mode:
SET TTI1 ANSI normal mode
SET TTI1 DASHER Dasher mode
SET TTO1 ANSI normal mode
SET TTO1 DASHER Dasher mode
Setting either TTI1 or TTO1 changes both devices. In Dasher mode, carriage
return is changed to newline on input, and ^X is changed to backspace.
The SHOW TTI1 LINESTATUS command displays the current connection to the
second terminal.
The second terminal input implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 number of characters input
TIME 24 keyboard polling interval
The second terminal output implements these registers:
name size comments
BUF 8 last data item processed
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
POS 31 number of characters output
TIME 24 time from I/O initiation to interrupt
2.3 Fixed Head Disk (DK)
The fixed head disk controller implements these registers:
name size comments
STAT 16 status
DA 16 disk address
MA 16 memory address
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 device disable flag
INT 1 interrupt pending flag
WLK 8 write lock switches
TIME 24 rotational delay, per sector
STOP_IOE 1 stop on I/O error
The fixed head disk controller supports the BOOT command.
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
Fixed head disk data files are buffered in memory; therefore, end of file
and OS I/O errors cannot occur.
2.4 Moving Head Disk (DP)
Moving head disk options include the ability to make units write enabled or
write locked, and to select the type of drive:
SET DPn LOCKED set unit n write locked
SET DPn ENABLED set unit n write enabled
SET DPn FLOPPY set unit n to floppy disk
SET DPn D31 set unit n to Diablo 31
SET DPn D44 set unit n to Diablo 44
SET DPn C111 set unit n to Century 111
SET DPn C114 set unit n to Century 114
SET DPn 6225 set unit n to 6225
SET DPn 6099 set unit n to 6099
SET DPn 6227 set unit n to 6227
SET DPn 6070 set unit n to 6070
SET DPn 6103 set unit n to 6103
SET DPn 4231 set unit n to 4231
Units can also be REMOVEd or ADDed to the configuration. The moving head
disk controller supports the BOOT command.
All drives have 256 16b words per sector. The other disk parameters are:
drive cylinders surfaces sectors size (MW) DG models
floppy 77 1 8 .158 6038
D31 203 2 12 1.247 4047, 4237, 4238
D44 408 4 12 5.014 4234, 6045
C111 203 10 6 3.118 4048
C114 203 20 12 12.472 4057, 2314
6225 20 2 245 2.508
6099 32 4 192 6.291
6227 20 6 245 7.526
6070 24 4 408 10.027
6103 32 8 192 12.583
4231 23 19 411 45.979
The moving head disk controller implements these registers:
name size comments
FCCY 16 flags, command, cylinder
USSC 16 unit, surface, sector, count
STAT 16 status
MA 16 memory address
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
STIME 24 seek time, per cylinder
RTIME 24 rotational delay
Error handling is as follows:
error processed as
not attached disk not ready
end of file assume rest of disk is zero
OS I/O error report error and stop
2.5 Magnetic Tape (MT)
Magnetic tape options include the ability to make units write enabled or
or write locked.
SET MTn LOCKED set unit n write locked
SET MTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration. The magnetic
tape controller supports the BOOT command.
The magnetic tape controller implements these registers:
name size comments
CU 16 command, unit
MA 16 memory address
WC 16 word count
STA1 16 status word 1
STA2 16 status word 2
EP 1 extended polling mode (not supported)
BUSY 1 device busy flag
DONE 1 device done flag
DISABLE 1 interrupt disable flag
INT 1 interrupt pending flag
STOP_IOE 1 stop on I/O error
CTIME 24 controller delay
RTIME 24 record delay
UST[0:7] 32 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.6 Symbolic Display and Input
The Nova simulator implements symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as two character ASCII string
-m display instruction mnemonics
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c two character ASCII string
alphabetic instruction mnemonic
numeric octal number
Instruction input uses standard Nova assembler syntax. There are three
instruction classes: memory reference, IOT, and operate.
Memory reference instructions have the format
memref {ac,}{@}address{,index}
LDA and STA require an initial register; ISZ, DSZ, JSR, and JMP do not.
The syntax for addresses and indices is as follows:
syntax mode displacement comments
0 <= n < 0400 0 n
{+/-}n >= 0400 1 {+/-}n - PC must be in range [-200, 177]
invalid on disk
.+/-n 1 {+/-}n must be in range [-200, 177]
{+/-}n,2 2 {+/-}n must be in range [-200, 177]
{+/-}n,3 3 {+/-}n must be in range [-200, 177]
IOT instructions have one of four formats
syntax example
iot HALT
iot reg INTA
iot device SKPDN
iot reg,device DOAS
Devices may be specified as mnemonics or as numbers in the range 0 - 077.
Operate instructions have the format
opcode{#} reg,reg{,skip}
In all Nova instructions, blanks may be substituted for commas as field
delimiters.

View file

@ -25,6 +25,8 @@
mta magnetic tape
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Changed POS, USTAT, FLG to an array
26-Apr-01 RMS Added device enable/disable support
18-Apr-01 RMS Changed to rewind tape before boot
10-Dec-00 RMS Added Eclipse support from Charles Owen
@ -54,12 +56,13 @@
#define MTA_NUMDR 8 /* #drives */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_W_UF 2 /* saved flags width */
#define UNIT_WLK 1 << UNIT_V_WLK
#define USTAT u3 /* unit status */
#define UNUM u4 /* unit number */
#define DTSIZE (1 << 14) /* max data xfer */
#define DTMASK (DTSIZE - 1)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Command/unit */
@ -149,7 +152,7 @@ t_stat mta_attach (UNIT *uptr, char *cptr);
t_stat mta_detach (UNIT *uptr);
int32 mta_updcsta (UNIT *uptr);
void mta_upddsta (UNIT *uptr, int32 newsta);
t_stat mta_vlock (UNIT *uptr, int32 val);
t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
#if defined (ECLIPSE)
extern int32 MapAddr (int32 map, int32 addr);
#else
@ -169,14 +172,14 @@ static const int ctype[32] = { /* c vs r timing */
*/
UNIT mta_unit[] = {
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } };
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } };
REG mta_reg[] = {
{ ORDATA (CU, mta_cu, 16) },
@ -191,38 +194,11 @@ REG mta_reg[] = {
{ FLDATA (INT, int_req, INT_V_MTA) },
{ DRDATA (CTIME, mta_cwait, 24), PV_LEFT },
{ DRDATA (RTIME, mta_rwait, 24), PV_LEFT },
{ ORDATA (UST0, mta_unit[0].USTAT, 32) },
{ ORDATA (UST1, mta_unit[1].USTAT, 32) },
{ ORDATA (UST2, mta_unit[2].USTAT, 32) },
{ ORDATA (UST3, mta_unit[3].USTAT, 32) },
{ ORDATA (UST4, mta_unit[4].USTAT, 32) },
{ ORDATA (UST5, mta_unit[5].USTAT, 32) },
{ ORDATA (UST6, mta_unit[6].USTAT, 32) },
{ ORDATA (UST7, mta_unit[7].USTAT, 32) },
{ DRDATA (POS0, mta_unit[0].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS1, mta_unit[1].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS2, mta_unit[2].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS3, mta_unit[3].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS4, mta_unit[4].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS5, mta_unit[5].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS6, mta_unit[6].pos, 31), REG_RO + PV_LEFT },
{ DRDATA (POS7, mta_unit[7].pos, 31), REG_RO + PV_LEFT },
{ GRDATA (FLG0, mta_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, mta_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, mta_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, mta_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, mta_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, mta_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, mta_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, mta_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) },
{ URDATA (POS, mta_unit[0].pos, 8, 31, 0,
MTA_NUMDR, REG_RO | PV_LEFT) },
{ URDATA (FLG, mta_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
MTA_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, iot_enb, INT_V_MTA), REG_HRO },
{ NULL } };
@ -341,7 +317,7 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */
mta_upddsta (uptr, 0); /* unit off line */
mta_sta = mta_sta | STA_ILL; } /* illegal operation */
else if ((uptr -> flags & UNIT_WLK) && /* write locked? */
else if ((uptr -> flags & UNIT_WPRT) && /* write locked? */
((c == CU_WRITE) || (c == CU_WREOF) || (c == CU_ERASE))) {
mta_upddsta (uptr, uptr -> USTAT | STA_WLK | STA_RDY);
mta_sta = mta_sta | STA_ILL; } /* illegal operation */
@ -526,7 +502,7 @@ for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */
uptr -> UNUM = u;
if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_RDY |
(uptr -> USTAT & STA_PEM) |
((uptr -> flags & UNIT_WLK)? STA_WLK: 0) |
((uptr -> flags & UNIT_WPRT)? STA_WLK: 0) |
((uptr -> pos)? 0: STA_BOT);
else uptr -> USTAT = 0; }
mta_updcsta (&mta_unit[0]); /* update status */
@ -542,7 +518,7 @@ t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
if (!sim_is_active (uptr)) mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM |
((uptr -> flags & UNIT_WLK)? STA_WLK: 0));
((uptr -> flags & UNIT_WPRT)? STA_WLK: 0));
return r;
}
@ -556,7 +532,7 @@ return detach_unit (uptr);
/* Write lock/unlock validate routine */
t_stat mta_vlock (UNIT *uptr, int32 val)
t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if ((uptr -> flags & UNIT_ATT) && val)
mta_upddsta (uptr, uptr -> USTAT | STA_WLK);

View file

@ -25,6 +25,8 @@
ptr paper tape reader
ptp paper tape punch
29-Nov-01 RMS Added read only unit support
*/
#include "nova_defs.h"
@ -44,7 +46,8 @@ t_stat ptp_reset (DEVICE *dptr);
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },

View file

@ -26,6 +26,7 @@
tti terminal input
tto terminal output
30-Nov-01 RMS Added extended SET/SHOW support
17-Sep-01 RMS Removed multiconsole support
07-Sep-01 RMS Moved function prototypes
31-May-01 RMS Added multiconsole support
@ -40,7 +41,7 @@ t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ttx_setmod (UNIT *uptr, int32 value);
t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr);
/* TTI data structures
@ -200,9 +201,9 @@ sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx_setmod (UNIT *uptr, int32 value)
t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr)
{
tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | value;
tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | value;
tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | val;
tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | val;
return SCPE_OK;
}

View file

@ -27,6 +27,7 @@
tti1 second terminal input
tto1 second terminal output
30-Nov-01 RMS Added extended SET/SHOW support
17-Sep-01 RMS Changed to use terminal multiplexor library
07-Sep-01 RMS Moved function prototypes
31-May-01 RMS Added multiconsole support
@ -49,10 +50,10 @@ t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr);
t_stat tto1_reset (DEVICE *dptr);
t_stat ttx1_setmod (UNIT *uptr, int32 value);
t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr);
t_stat tti1_attach (UNIT *uptr, char *cptr);
t_stat tti1_detach (UNIT *uptr);
t_stat tti1_status (UNIT *uptr, FILE *st);
t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc);
/* TTI1 data structures
@ -77,9 +78,11 @@ REG tti1_reg[] = {
{ NULL } };
MTAB ttx1_mod[] = {
{ UNIT_ATT, UNIT_ATT, "line status:", NULL, &tti1_status },
{ UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod },
{ UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod },
{ UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &tti1_status },
{ MTAB_XTD | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, "LINE", NULL,
NULL, &tti1_status, NULL },
{ 0 } };
DEVICE tti1_dev = {
@ -233,10 +236,10 @@ sim_cancel (&tto1_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx1_setmod (UNIT *uptr, int32 value)
t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr)
{
tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | value;
tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | value;
tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | val;
tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | val;
return SCPE_OK;
}
@ -266,7 +269,7 @@ return r;
/* Status routine */
t_stat tti1_status (UNIT *uptr, FILE *st)
t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc)
{
tmxr_fstatus (st, &tt1_ldsc, -1);
return SCPE_OK;

View file

@ -25,6 +25,8 @@
cpu PDP-1 central processor
07-Dec-01 RMS Revised to use breakpoint package
30-Nov-01 RMS Added extended SET/SHOW support
16-Dec-00 RMS Fixed bug in XCT address calculation
14-Apr-99 RMS Changed t_addr to unsigned
@ -212,8 +214,6 @@
#include "pdp1_defs.h"
#define ILL_ADR_FLAG (1 << ASIZE)
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MDV (UNIT_V_UF) /* mul/div */
#define UNIT_MDV (1 << UNIT_V_MDV)
#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */
@ -238,15 +238,14 @@ int32 stop_inst = 0; /* stop on rsrv inst */
int32 xct_max = 16; /* nested XCT limit */
int32 ind_max = 16; /* nested ind limit */
int32 old_PC = 0; /* old PC */
int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */
extern UNIT *sim_clock_queue;
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
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_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
extern int32 sim_int_char;
extern UNIT *sim_clock_queue;
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
extern int32 ptr (int32 inst, int32 dev, int32 IO);
extern int32 ptp (int32 inst, int32 dev, int32 IO);
extern int32 tti (int32 inst, int32 dev, int32 IO);
@ -297,7 +296,7 @@ int32 sc_map[512] = {
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
REG cpu_reg[] = {
{ ORDATA (PC, PC, ASIZE) },
@ -321,7 +320,6 @@ REG cpu_reg[] = {
{ FLDATA (MDV, cpu_unit.flags, UNIT_V_MDV), REG_HRO },
{ DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },
{ DRDATA (IND_MAX, ind_max, 8), PV_LEFT + REG_NZ },
{ ORDATA (BREAK, ibkpt_addr, ASIZE + 1) },
{ ORDATA (WRU, sim_int_char, 8) },
{ NULL } };
@ -379,10 +377,7 @@ if (sbs == (SB_ON | SB_RQ)) { /* interrupt? */
extm = 0; /* extend off */
OV = 0; } /* clear overflow */
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save ibkpt */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
@ -741,7 +736,8 @@ extm = extm_init;
ioh = ioc = 0;
OV = 0;
PF = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -762,28 +758,19 @@ M[addr] = val & 0777777;
return SCPE_OK;
}
/* Service breakpoint */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
/* Change memory size */
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}

409
PDP1/pdp1_doc.txt Normal file
View file

@ -0,0 +1,409 @@
To: Users
From: Bob Supnik
Subj: PDP-1 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-1 simulator.
1. Simulator Files
sim/ sim_defs.h
scp.c
scp_tty.c
sim_rev.c
sim/pdp1/ pdp1_defs.h
pdp1_cpu.c
pdp1_lp.c
pdp1_stddev.c
pdp1_sys.c
2. PDP-1 Features
The PDP-1 is configured as follows:
device simulates
name(s)
CPU PDP-1 CPU with up to 64KW of memory
PTR,PTP integral paper tape reader/punch
TTI,TTO Flexowriter typewriter input/output
LPT Type 62 line printer
The PDP-1 simulator implements the following unique stop conditions:
- an unimplemented instruction is decoded, and register
STOP_INST is set
- more than INDMAX indirect addresses are detected during
memory reference address decoding
- more than XCTMAX nested executes are detected during
instruction execution
- wait state entered, and no I/O operations outstanding
(ie, no interrupt can ever occur)
The PDP-1 loader supports RIM format tapes. The DUMP command is not
implemented.
2.1 CPU
The only CPU options are the presence of hardware multiply/divide and the
size of main memory.
SET CPU MDV enable multiply/divide
SET CPU NOMDV disable multiply/divide
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
SET CPU 20K set memory size = 20K
SET CPU 24K set memory size = 24K
SET CPU 28K set memory size = 28K
SET CPU 32K set memory size = 32K
SET CPU 48K set memory size = 48K
SET CPU 64K set memory size = 64K
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 64K.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
PC 16 program counter
AC 18 accumulator
IO 18 IO register
OV 1 overflow flag
PF 6 program flags<1:6>
SS 6 sense switches<1:6>
TW 18 test word (front panel switches)
EXTM 1 extend mode
IOSTA 18 IO status register
SBON 1 sequence break enable
SBRQ 1 sequence break request
SBIP 1 sequence break in progress
IOH 1 I/O halt in progress
IOC 1 I/O continue
OLDPC 16 PC prior to last transfer
STOP_INST 1 stop on undefined instruction
SBS_INIT 1 initial state of sequence break enable
EXTM_INIT 1 initial state of extend mode
WRU 8 interrupt character
2.2 Programmed I/O Devices
2.2.1 Paper Tape Reader (PTR)
The paper tape reader (PTR) reads data from or 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 supports the BOOT command. BOOT PTR copies the
RIM loader into memory and starts it running.
The paper tape reader implements these registers:
name size comments
BUF 8 last data item processed
DONE 1 device done flag
RPLS 1 return restart pulse flag
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.2.2 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 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
DONE 1 device done flag
RPLS 1 return restart pulse flag
POS 31 position in the 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.2.3 Terminal Input (TTI)
The terminal input (TTI) polls the console keyboard for input. It
implements these registers:
name size comments
BUF 8 last data item processed
DONE 1 device done flag
POS 31 number of characters input
TIME 24 keyboard polling interval
2.2.4 Terminal Output (TTO)
The terminal output (TTO) writes to the simulator console window.
It implements these registers:
name size comments
BUF 8 last data item processed
DONE 1 device done flag
RPLS 1 return restart pulse flag
POS 31 number of characters output
TIME 24 time from I/O initiation to interrupt
2.2.5 Type 62 Line Printer (LPT)
The paper line printer (LPT) writes data to a disk file. The POS
register specifies the number of the next data item to be written.
Thus, by changing POS, the user can backspace or advance the printer.
The line printer implements these registers:
name size comments
BUF 8 last data item processed
PNT 1 printing done flag
SPC 1 spacing done flag
RPLS 1 return restart pulse flag
BPTR 6 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.3 Symbolic Display and Input
The PDP-1 simulator implements symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as FIODEC character string
-m display instruction mnemonics
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c three character FIODEC string
alphabetic instruction mnemonic
numeric octal number
Instruction input uses modified PDP-1 assembler syntax. There are six
instruction classes: memory reference, shift, skip, operate, IOT, and
LAW.
Memory reference instructions have the format
memref {I} address
where I signifies indirect reference. The address is an octal number in
the range 0 - 0177777.
Shift instructions have the format
shift shift_count
The shift count is an octal number in the range 0-9.
Skip instructions consist of single mnemonics, eg, SZA, SZS4. Skip
instructions may be or'd together
skip skip skip...
The sense of a skip can be inverted by including the mnemonic I.
Operate instructions consist of single mnemonics, eg, CLA, CLI. Operate
instructions may be or'd together
opr opr opr...
IOT instructions consist of single mnemonics, eg, TYI, TYO. IOT
instructions may include an octal numeric modifier or the modifier I:
iot modifier
The simulator does not check the legality of skip, operate, or IOT
combinations.
Finally, the LAW instruction has the format
LAW {I} immediate
where immediate is in the range 0 to 07777.
2.4 Character Sets
The PDP-1's console was a Frieden Flexowriter; its character encoding
was known as FIODEC. The PDP-1's line printer used a modified Hollerith
character set. The following table provides equivalences between ASCII
characters and the PDP-1's I/O devices. In the console table, UC stands
for upper case.
PDP-1 PDP-1
ASCII console line printer
000 - 007 none none
bs 075 none
tab 036 none
012 - 014 none none
cr 077 none
016 - 037 none none
space 000 000
! {OR} UC+005 none
" UC+001 none
# {IMPLIES} UC+004 none
$ none none
% none none
& {AND} UC+006 none
' UC+002 none
( 057 057
) 055 055
* {TIMES} UC+073 072
+ UC+054 074
, 033 033
- 054 054
. 073 073
/ 021 021
0 020 020
1 001 001
2 002 002
3 003 003
4 004 004
5 005 005
6 006 006
7 007 007
8 010 010
9 011 011
: none none
; none none
< UC+007 034
= UC+033 053
> UC+010 034
? UC+021 037
@ {MID DOT} 040 {MID DOT} 040
A UC+061 061
B UC+062 062
C UC+063 063
D UC+064 064
E UC+065 065
F UC+066 066
G UC+067 067
H UC+070 070
I UC+071 071
J UC+041 041
K UC+042 042
L UC+043 043
M UC+044 044
N UC+045 045
O UC+046 046
P UC+047 047
Q UC+050 050
R UC+051 051
S UC+022 022
T UC+023 023
U UC+024 024
V UC+025 025
W UC+026 026
X UC+027 027
Y UC+030 030
Z UC+031 031
[ UC+057 none
\ {OVERLINE} 056 {OVERLINE} 056
] UC+055 none
^ {UP ARROW} UC+011 {UP ARROW} 035
_ UC+040 UC+040
` {RT ARROW} UC+020 036
a 061 none
b 062 none
c 063 none
d 064 none
e 065 none
f 066 none
g 067 none
h 070 none
i 071 none
j 041 none
k 042 none
l 043 none
m 044 none
n 045 none
o 046 none
p 047 none
q 050 none
r 051 none
s 022 none
t 023 none
u 024 none
v 025 none
w 026 none
x 027 none
y 030 none
z 031 none
{ none none
| UC+056 076
} none none
~ UC+003 013
del 075 none

View file

@ -28,6 +28,7 @@
tti keyboard
tto teleprinter
29-Nov-01 RMS Added read only unit support
07-Sep-01 RMS Moved function prototypes
10-Jun-01 RMS Fixed comment
30-Oct-00 RMS Standardized device naming
@ -103,7 +104,8 @@ int32 ascii_to_fiodec[128] = {
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 18) },

View file

@ -25,6 +25,9 @@
cpu KS10 central processor
25-Dec-01 RMS Cleaned up sim_inst declarations
07-Dec-01 RMS Revised to use new breakpoint package
21-Nov-01 RMS Implemented ITS 1-proceed hack
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
10-Aug-01 RMS Removed register in declarations
17-Jul-01 RMS Moved function prototype
@ -112,13 +115,19 @@
pdp10_defs.h add interrupt request definition
pdp10_ksio.c add I/O page linkages
pdp10_sys.c add pointer to data structures to sim_devices
A note on ITS 1-proceed. The simulator follows the implementation
on the KS10, keeping 1-proceed as a side flag (its_1pr) rather than
as flags<8>. This simplifies the flag saving instructions, which
don't have to clear flags<8> before saving it. Instead, the page
fail and interrupt code must restore flags<8> from its_1pr. Unlike
the KS10, the simulator will not lose the 1-proceed trap if the
1-proceeded instructions clears 1-proceed.
*/
#include "pdp10_defs.h"
#include <setjmp.h>
#define ILL_ADR_FLAG (1 << VASIZE)
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
@ -126,9 +135,12 @@ d10 *M = NULL; /* memory */
d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */
d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */
a10 epta, upta; /* proc tbl addr (dyn) */
d10 last_inst = 0; /* most recent inst */
a10 saved_PC = 0; /* scp: saved PC */
d10 pager_word = 0; /* pager: error word */
a10 pager_PC = 0; /* pager: saved PC */
int32 pager_flags = 0; /* pager: trap flags */
t_bool pager_pi = FALSE; /* pager: in pi seq */
t_bool pager_tc = FALSE; /* pager: trap cycle */
d10 ebr = 0; /* exec base reg */
d10 ubr = 0; /* user base reg */
d10 hsb = 0; /* halt status block */
@ -152,22 +164,60 @@ int32 apr_flg = 0; /* apr flags */
int32 apr_lvl = 0; /* apr level */
int32 qintr = 0; /* interrupt pending */
int32 flags = 0; /* flags */
int32 its_1pr = 0; /* ITS 1-proceed */
int32 stop_op0 = 0; /* stop on 0 */
d10 pager_word = 0; /* pager error word */
int32 rlog = 0; /* extend fixup log */
int32 ind_max = 32; /* nested ind limit */
int32 xct_max = 32; /* nested XCT limit */
int32 astop_cpu = 0; /* address stop */
a10 old_PC = 0; /* old PC */
a10 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */
jmp_buf save_env;
extern int32 sim_int_char;
extern int32 sim_interval;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern UNIT tim_unit;
/* Forward and external declarations */
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_svc (UNIT *uptr);
extern int32 sim_int_char;
extern int32 sim_interval;
d10 adjsp (d10 val, a10 ea);
void ibp (a10 ea, int32 pflgs);
d10 ldb (a10 ea, int32 pflgs);
void dpb (d10 val, a10 ea, int32 pflgs);
void adjbp (int32 ac, a10 ea, int32 pflgs);
d10 add (d10 val, d10 mb);
d10 sub (d10 val, d10 mb);
void dadd (int32 ac, d10 *rs);
void dsub (int32 ac, d10 *rs);
int32 jffo (d10 val);
d10 lsh (d10 val, a10 ea);
d10 rot (d10 val, a10 ea);
d10 ash (d10 val, a10 ea);
void lshc (int32 ac, a10 ea);
void rotc (int32 ac, a10 ea);
void ashc (int32 ac, a10 ea);
void circ (int32 ac, a10 ea);
void blt (int32 ac, a10 ea, int32 pflgs);
void bltu (int32 ac, a10 ea, int32 pflgs, int dir);
a10 calc_ea (d10 inst, int32 prv);
a10 calc_ioea (d10 inst, int32 prv);
d10 calc_jrstfea (d10 inst, int32 pflgs);
void pi_dismiss (void);
void set_newflags (d10 fl, t_bool jrst);
extern t_bool aprid (a10 ea, int32 prv);
t_bool wrpi (a10 ea, int32 prv);
t_bool rdpi (a10 ea, int32 prv);
t_bool czpi (a10 ea, int32 prv);
t_bool copi (a10 ea, int32 prv);
t_bool wrapr (a10 ea, int32 prv);
t_bool rdapr (a10 ea, int32 prv);
t_bool czapr (a10 ea, int32 prv);
t_bool coapr (a10 ea, int32 prv);
int32 pi_eval (void);
int32 test_int (void);
void set_ac_display (d10 *acbase);
extern d10 Read (a10 ea, int32 prv); /* read, read check */
extern d10 ReadM (a10 ea, int32 prv); /* read, write check */
@ -180,9 +230,69 @@ extern t_bool AccViol (a10 ea, int32 prv, int32 mode); /* access check */
extern void set_dyn_ptrs (void);
extern a10 conmap (a10 ea, int32 mode, int32 sw);
extern void fe_intr ();
int32 pi_eval (void);
int32 test_int (void);
void set_ac_display (d10 *acbase);
extern void dfad (int32 ac, d10 *rs, int32 inv);
extern void dfmp (int32 ac, d10 *rs);
extern void dfdv (int32 ac, d10 *rs);
extern void dmul (int32 ac, d10 *rs);
extern void ddiv (int32 ac, d10 *rs);
extern void fix (int32 ac, d10 mb, t_bool rnd);
extern d10 fad (d10 val, d10 mb, t_bool rnd, int32 inv);
extern d10 fmp (d10 val, d10 mb, t_bool rnd);
extern t_bool fdv (d10 val, d10 mb, d10 *rs, t_bool rnd);
extern d10 fsc (d10 val, a10 ea);
extern d10 fltr (d10 mb);
extern int xtend (int32 ac, a10 ea, int32 pflgs);
extern void xtcln (int32 rlog);
extern d10 map (a10 ea, int32 prv);
extern d10 imul (d10 val, d10 mb);
extern t_bool idiv (d10 val, d10 mb, d10 *rs);
extern void mul (d10 val, d10 mb, d10 *rs);
extern t_bool divi (int32 ac, d10 mb, d10 *rs);
extern t_bool io710 (int32 ac, a10 ea);
extern t_bool io711 (int32 ac, a10 ea);
extern d10 io712 (a10 ea);
extern void io713 (d10 val, a10 ea);
extern void io714 (d10 val, a10 ea);
extern void io715 (d10 val, a10 ea);
extern t_bool io720 (int32 ac, a10 ea);
extern t_bool io721 (int32 ac, a10 ea);
extern d10 io722 (a10 ea);
extern void io723 (d10 val, a10 ea);
extern void io724 (d10 val, a10 ea);
extern void io725 (d10 val, a10 ea);
extern t_bool clrcsh (a10 ea, int32 prv);
extern t_bool clrpt (a10 ea, int32 prv);
extern t_bool wrubr (a10 ea, int32 prv);
extern t_bool wrebr (a10 ea, int32 prv);
extern t_bool wrhsb (a10 ea, int32 prv);
extern t_bool wrspb (a10 ea, int32 prv);
extern t_bool wrcsb (a10 ea, int32 prv);
extern t_bool wrpur (a10 ea, int32 prv);
extern t_bool wrcstm (a10 ea, int32 prv);
extern t_bool ldbr1 (a10 ea, int32 prv);
extern t_bool ldbr2 (a10 ea, int32 prv);
extern t_bool ldbr3 (a10 ea, int32 prv);
extern t_bool ldbr4 (a10 ea, int32 prv);
extern t_bool rdubr (a10 ea, int32 prv);
extern t_bool rdebr (a10 ea, int32 prv);
extern t_bool rdhsb (a10 ea, int32 prv);
extern t_bool rdspb (a10 ea, int32 prv);
extern t_bool rdcsb (a10 ea, int32 prv);
extern t_bool rdpur (a10 ea, int32 prv);
extern t_bool rdcstm (a10 ea, int32 prv);
extern t_bool sdbr1 (a10 ea, int32 prv);
extern t_bool sdbr2 (a10 ea, int32 prv);
extern t_bool sdbr3 (a10 ea, int32 prv);
extern t_bool sdbr4 (a10 ea, int32 prv);
extern t_bool rdtim (a10 ea, int32 prv);
extern t_bool rdint (a10 ea, int32 prv);
extern t_bool wrtim (a10 ea, int32 prv);
extern t_bool wrint (a10 ea, int32 prv);
extern t_bool rdpcst (a10 ea, int32 prv);
extern t_bool wrpcst (a10 ea, int32 prv);
extern t_bool spm (a10 ea, int32 prv);
extern t_bool lpmr (a10 ea, int32 prv);
extern int32 pi_ub_vec (int32 lvl, int32 *uba);
/* CPU data structures
@ -192,7 +302,7 @@ void set_ac_display (d10 *acbase);
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX, MAXMEMSIZE) };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MAXMEMSIZE) };
REG cpu_reg[] = {
{ ORDATA (PC, saved_PC, VASIZE) },
@ -213,7 +323,6 @@ REG cpu_reg[] = {
{ ORDATA (AC15, acs[15], 36) },
{ ORDATA (AC16, acs[16], 36) },
{ ORDATA (AC17, acs[17], 36) },
{ ORDATA (IR, last_inst, 36), REG_RO },
{ ORDATA (PFW, pager_word, 36) },
{ ORDATA (EBR, ebr, EBR_N_EBR) },
{ FLDATA (PGON, ebr, EBR_V_PGON) },
@ -241,12 +350,12 @@ REG cpu_reg[] = {
{ ORDATA (APRFLG, apr_flg, 8) },
{ ORDATA (APRLVL, apr_lvl, 3) },
{ ORDATA (RLOG, rlog, 10) },
{ FLDATA (F1PR, its_1pr, 0) },
{ ORDATA (OLDPC, old_PC, VASIZE), REG_RO },
{ DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ },
{ DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ },
{ FLDATA (ITS, cpu_unit.flags, UNIT_V_ITS), REG_HRO },
{ FLDATA (T20V41, cpu_unit.flags, UNIT_V_T20V41), REG_HRO },
{ ORDATA (BREAK, ibkpt_addr, VASIZE + 1) },
{ ORDATA (WRU, sim_int_char, 8) },
{ FLDATA (STOP_ILL, stop_op0, 0) },
{ BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) },
@ -294,12 +403,32 @@ const d10 bytemask[64] = { 0,
ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES,
ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES };
/* JRST classes */
static t_bool (*io700d[16])() = {
&aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr,
NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi };
static t_bool (*io701d[16])() = {
NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
static t_bool (*io702d[16])() = {
&rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL,
&wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL };
#define io700i io700d
static t_bool (*io701i[16])() = {
&clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL,
NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL };
static t_bool (*io702i[16])() = {
&sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm,
&ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr };
/* JRST classes and validation table */
#define JRST_U 1 /* ok anywhere */
#define JRST_E 2 /* ok exec mode */
#define JRST_UIO 3 /* ok user I/O mode */
static t_stat jrst_tab[16] = {
JRST_U, JRST_U, JRST_U, 0, JRST_E, JRST_U, JRST_E, JRST_E,
JRST_UIO, 0, JRST_UIO, 0, JRST_E, JRST_U, 0, 0 };
/* Address operations */
@ -443,148 +572,19 @@ const d10 bytemask[64] = { 0,
t_stat sim_instr (void)
{
/* External and forward declarations */
extern void dfad (int32 ac, d10 *rs, int32 inv);
extern void dfmp (int32 ac, d10 *rs);
extern void dfdv (int32 ac, d10 *rs);
extern void dmul (int32 ac, d10 *rs);
extern void ddiv (int32 ac, d10 *rs);
extern void fix (int32 ac, d10 mb, t_bool rnd);
extern d10 fad (d10 val, d10 mb, t_bool rnd, int32 inv);
extern d10 fmp (d10 val, d10 mb, t_bool rnd);
extern t_bool fdv (d10 val, d10 mb, d10 *rs, t_bool rnd);
extern d10 fsc (d10 val, a10 ea);
extern d10 fltr (d10 mb);
extern int xtend (int32 ac, a10 ea, int32 pflgs);
extern void xtcln (int32 rlog);
extern d10 map (a10 ea, int32 prv);
extern d10 imul (d10 val, d10 mb);
extern t_bool idiv (d10 val, d10 mb, d10 *rs);
extern void mul (d10 val, d10 mb, d10 *rs);
extern t_bool divi (int32 ac, d10 mb, d10 *rs);
extern t_bool io710 (int32 ac, a10 ea);
extern t_bool io711 (int32 ac, a10 ea);
extern d10 io712 (a10 ea);
extern void io713 (d10 val, a10 ea);
extern void io714 (d10 val, a10 ea);
extern void io715 (d10 val, a10 ea);
extern t_bool io720 (int32 ac, a10 ea);
extern t_bool io721 (int32 ac, a10 ea);
extern d10 io722 (a10 ea);
extern void io723 (d10 val, a10 ea);
extern void io724 (d10 val, a10 ea);
extern void io725 (d10 val, a10 ea);
extern t_bool clrcsh (a10 ea, int32 prv);
extern t_bool clrpt (a10 ea, int32 prv);
extern t_bool wrubr (a10 ea, int32 prv);
extern t_bool wrebr (a10 ea, int32 prv);
extern t_bool wrhsb (a10 ea, int32 prv);
extern t_bool wrspb (a10 ea, int32 prv);
extern t_bool wrcsb (a10 ea, int32 prv);
extern t_bool wrpur (a10 ea, int32 prv);
extern t_bool wrcstm (a10 ea, int32 prv);
extern t_bool ldbr1 (a10 ea, int32 prv);
extern t_bool ldbr2 (a10 ea, int32 prv);
extern t_bool ldbr3 (a10 ea, int32 prv);
extern t_bool ldbr4 (a10 ea, int32 prv);
extern t_bool rdubr (a10 ea, int32 prv);
extern t_bool rdebr (a10 ea, int32 prv);
extern t_bool rdhsb (a10 ea, int32 prv);
extern t_bool rdspb (a10 ea, int32 prv);
extern t_bool rdcsb (a10 ea, int32 prv);
extern t_bool rdpur (a10 ea, int32 prv);
extern t_bool rdcstm (a10 ea, int32 prv);
extern t_bool sdbr1 (a10 ea, int32 prv);
extern t_bool sdbr2 (a10 ea, int32 prv);
extern t_bool sdbr3 (a10 ea, int32 prv);
extern t_bool sdbr4 (a10 ea, int32 prv);
extern t_bool rdtim (a10 ea, int32 prv);
extern t_bool rdint (a10 ea, int32 prv);
extern t_bool wrtim (a10 ea, int32 prv);
extern t_bool wrint (a10 ea, int32 prv);
extern t_bool rdpcst (a10 ea, int32 prv);
extern t_bool wrpcst (a10 ea, int32 prv);
extern t_bool spm (a10 ea, int32 prv);
extern t_bool lpmr (a10 ea, int32 prv);
extern int32 pi_ub_vec (int32 lvl, int32 *uba);
extern UNIT tim_unit;
d10 adjsp (d10 val, a10 ea);
void ibp (a10 ea, int32 pflgs);
d10 ldb (a10 ea, int32 pflgs);
void dpb (d10 val, a10 ea, int32 pflgs);
void adjbp (int32 ac, a10 ea, int32 pflgs);
d10 add (d10 val, d10 mb);
d10 sub (d10 val, d10 mb);
void dadd (int32 ac, d10 *rs);
void dsub (int32 ac, d10 *rs);
int32 jffo (d10 val);
d10 lsh (d10 val, a10 ea);
d10 rot (d10 val, a10 ea);
d10 ash (d10 val, a10 ea);
void lshc (int32 ac, a10 ea);
void rotc (int32 ac, a10 ea);
void ashc (int32 ac, a10 ea);
void circ (int32 ac, a10 ea);
void blt (int32 ac, a10 ea, int32 pflgs);
void bltu (int32 ac, a10 ea, int32 pflgs, int dir);
a10 calc_ea (d10 inst, int32 prv);
a10 calc_ioea (d10 inst, int32 prv);
d10 calc_jrstfea (d10 inst, int32 pflgs);
void pi_dismiss (void);
void set_newflags (d10 fl, t_bool jrst);
extern t_bool aprid (a10 ea, int32 prv);
t_bool wrpi (a10 ea, int32 prv);
t_bool rdpi (a10 ea, int32 prv);
t_bool czpi (a10 ea, int32 prv);
t_bool copi (a10 ea, int32 prv);
t_bool wrapr (a10 ea, int32 prv);
t_bool rdapr (a10 ea, int32 prv);
t_bool czapr (a10 ea, int32 prv);
t_bool coapr (a10 ea, int32 prv);
static t_bool (*io700d[16])() = {
&aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr,
NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi };
static t_bool (*io701d[16])() = {
NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
static t_bool (*io702d[16])() = {
&rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL,
&wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL };
#define io700i io700d
static t_bool (*io701i[16])() = {
&clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL,
NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL };
static t_bool (*io702i[16])() = {
&sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm,
&ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr };
static t_stat jrst_tab[16] = {
JRST_U, JRST_U, JRST_U, 0, JRST_E, JRST_U, JRST_E, JRST_E,
JRST_UIO, 0, JRST_UIO, 0, JRST_E, JRST_U, 0, 0 };
d10 inst;
a10 PC;
int32 pflgs;
int32 pager_flags = 0; /* pager: trap flags */
t_bool pager_pi = FALSE; /* pager: in pi seq */
int abortval = 0; /* abort value */
t_bool (*fptr)();
/* Restore register state */
pager_PC = PC = saved_PC & AMASK; /* load local PC */
set_dyn_ptrs (); /* set up local ptrs */
pflgs = 0; /* not trap or PXCT */
pager_tc = FALSE; /* not in trap cycle */
pager_pi = FALSE; /* not in pi sequence */
rlog = 0; /* not in extend */
pi_eval (); /* eval pi system */
astop_cpu = 0; /* no addr stop */
sim_rtc_init (tim_unit.wait); /* init calibration */
if (!ITS) its_1pr = 0; /* ~ITS, clr 1-proc */
/* Abort handling
@ -597,28 +597,32 @@ if ((abortval > 0) || pager_pi) { /* stop or pi err? */
if (pager_pi && (abortval == PAGE_FAIL))
abortval = STOP_PAGINT; /* stop for pi err */
saved_PC = pager_PC & AMASK; /* failing instr PC */
last_inst = inst; /* last instr decoded */
set_ac_display (ac_cur); /* set up AC display */
return abortval; } /* return to SCP */
/* Page fail - checked against KS10 ucode */
/* Page fail - checked against KS10 ucode
All state variables MUST be declared global for GCC optimization to work
*/
else if (abortval == PAGE_FAIL) { /* page fail */
d10 mb;
if (rlog) xtcln (rlog); /* clean up extend */
rlog = 0; /* clear log */
if (pflgs & TRAP_CYCLE) flags = pager_flags; /* trap? get flags */
if (!T20 || ITS) { /* TOPS-10 or ITS */
a10 ea;
if (ITS) ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3);
if (pager_tc) flags = pager_flags; /* trap? get flags */
if (T20) { /* TOPS-20 */
WriteP (upta + UPT_T20_PFL, pager_word);/* write page fail wd */
WriteP (upta + UPT_T20_OFL, XWD (flags, 0));
WriteP (upta + UPT_T20_OPC, pager_PC);
mb = ReadP (upta + UPT_T20_NPC); }
else { a10 ea; /* TOPS-10 or ITS */
if (ITS) { /* ITS? */
ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3);
if (its_1pr) flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; } /* clear 1-proc */
else ea = upta + UPT_T10_PAG;
WriteP (ea, pager_word); /* write page fail wd */
WriteP (ADDA (ea, 1), XWD (flags, pager_PC));
mb = ReadP (ADDA (ea, 2)); }
else { WriteP (upta + UPT_T20_PFL, pager_word);/* write page fail wd */
WriteP (upta + UPT_T20_OFL, XWD (flags, 0));
WriteP (upta + UPT_T20_OPC, pager_PC);
mb = ReadP (upta + UPT_T20_NPC); }
JUMP (mb); /* set new PC */
set_newflags (mb, FALSE); /* set new flags */
pi_eval (); } /* eval pi system */
@ -627,14 +631,15 @@ else PC = pager_PC; /* intr, restore PC */
/* Main instruction fetch/decode loop: check clock queue, intr, trap, bkpt */
for ( ;; ) { /* loop until ABORT */
int32 op, ac, i, st, xr, xct_cnt;
int32 op, ac, i, st, xr, xct_cnt, its_2pr, pflgs;
a10 ea;
d10 mb, indrct, rs[2];
d10 inst, mb, indrct, rs[2];
t_bool (*fptr)();
pager_PC = PC; /* update pager PC */
pflgs = 0; /* not in PXCT or trap */
pager_tc = FALSE; /* not in trap cycle */
pflgs = 0; /* not in PXCT */
xct_cnt = 0; /* count XCT's */
if (astop_cpu) ABORT (STOP_ASTOP); /* address stop? */
if (sim_interval <= 0) { /* check clock queue */
if (i = sim_process_event ()) ABORT (i); /* error? stop sim */
pi_eval (); } /* eval pi system */
@ -657,6 +662,9 @@ if (qintr) {
else inst = ReadP (epta + EPT_PIIT + (2 * qintr));
op = GET_OP (inst); /* get opcode */
ac = GET_AC (inst); /* get ac */
if (its_1pr && ITS) { /* 1-proc set? */
flags = flags | F_1PR; /* store 1-proc */
its_1pr = 0; } /* clear 1-proc */
if (op == OP_JSR) { /* JSR? */
ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */
WriteE (ea, FLPC); /* save flags+PC, exec */
@ -688,7 +696,7 @@ if (qintr) {
if (TSTF (F_T1 | F_T2) && PAGING) {
Read (pager_PC = PC, MM_CUR); /* test fetch */
pflgs = TRAP_CYCLE; /* in a trap sequence */
pager_tc = TRUE; /* in a trap sequence */
pager_flags = flags; /* save flags */
ea = (TSTF (F_USR)? upta + UPT_TRBASE: epta + EPT_TRBASE)
+ GET_TRAPS (flags);
@ -697,10 +705,8 @@ if (TSTF (F_T1 | F_T2) && PAGING) {
/* Test for instruction breakpoint */
else { if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save bkpt */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
else { if (sim_brk_summ &&
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
ABORT (STOP_IBKPT); } /* stop simulation */
/* Ready (at last) to get an instruction */
@ -709,6 +715,8 @@ else { if (PC == ibkpt_addr) { /* breakpoint? */
INCPC;
sim_interval = sim_interval - 1; }
its_2pr = its_1pr; /* save 1-proc flag */
/* Execute instruction. XCT and PXCT also return here. */
XCT:
@ -1240,7 +1248,8 @@ case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */
*/
default:
MUUO: if (T20) { /* TOPS20? */
MUUO: its_2pr = 0; /* clear trap */
if (T20) { /* TOPS20? */
int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18));
WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */
flags & ~(F_T2 | F_T1), tf)); /* traps clear */
@ -1252,7 +1261,7 @@ MUUO: if (T20) { /* TOPS20? */
flags & ~(F_T2 | F_T1), PC)); /* traps clear */
WriteP (upta + UPT_T10_CTX, UBRWORD); } /* store context */
ea = upta + (TSTF (F_USR)? UPT_UNPC: UPT_ENPC) +
(pflgs & TRAP_CYCLE? UPT_NPCT: 0); /* calculate vector */
(pager_tc? UPT_NPCT: 0); /* calculate vector */
mb = ReadP (ea); /* new flags, PC */
JUMP (mb); /* set new PC */
if (TSTF (F_USR)) mb = mb | XWD (F_UIO, 0); /* set PCU */
@ -1325,6 +1334,15 @@ case 0254: /* JRST */
JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */
break; } /* end case subop */
break; } /* end case op */
if (its_2pr) { /* 1-proc trap? */
its_1pr = its_2pr = 0; /* clear trap */
if (ITS) { /* better be ITS */
WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */
mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */
JUMP (mb); /* set PC */
set_newflags (mb, TRUE); } /* set new flags */
} /* end if 2-proc */
} /* end for */
/* Should never get here */
@ -1905,6 +1923,9 @@ int32 fl = (int32) LRZ (newf);
if (jrst && TSTF (F_USR)) { /* if in user now */
fl = fl | F_USR; /* can't clear user */
if (!TSTF (F_UIO)) fl = fl & ~F_UIO; } /* if !UIO, can't set */
if (ITS && (fl & F_1PR)) { /* ITS 1-proceed? */
its_1pr = 1; /* set flag */
fl = fl & ~F_1PR; } /* vanish bit */
flags = fl & F_MASK; /* set new flags */
set_dyn_ptrs (); /* set new ptrs */
return;
@ -2002,6 +2023,7 @@ return;
t_stat cpu_reset (DEVICE *dptr)
{
flags = 0; /* clear flags */
its_1pr = 0; /* clear 1-proceed */
ebr = ubr = 0; /* clear paging */
pi_enb = pi_act = pi_prq = 0; /* clear PI */
apr_enb = apr_flg = apr_lvl = 0; /* clear APR */
@ -2013,7 +2035,8 @@ set_ac_display (ac_cur);
pi_eval ();
if (M == NULL) M = calloc (MAXMEMSIZE, sizeof (d10));
if (M == NULL) return SCPE_MEM;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -2043,15 +2066,6 @@ else { if (sw & SWMASK ('V')) {
return SCPE_OK;
}
/* Service breakpoint */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
/* Set current AC pointers for SCP */
void set_ac_display (d10 *acbase)

View file

@ -379,11 +379,10 @@ typedef t_int64 d10; /* PDP-10 data (36b) */
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 (and the trap
in progress flag) are kept in a dynamic CPU variable.
various parts of an instruction. The PXCT flags are kept in a
dynamic CPU variable.
*/
#define TRAP_CYCLE 040 /* trap in progress */
#define EA_PXCT 010 /* eff addr calc */
#define OPND_PXCT 004 /* operand, bdst */
#define EABP_PXCT 002 /* bp eff addr calc */
@ -420,6 +419,8 @@ typedef t_int64 d10; /* PDP-10 data (36b) */
#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 */

526
PDP10/pdp10_doc.txt Normal file
View 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.

View file

@ -25,6 +25,7 @@
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
*/
@ -37,8 +38,8 @@ 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);
t_stat fe_ctrl_c (UNIT *uptr, int32 val);
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
@ -146,7 +147,7 @@ return SCPE_OK;
/* Stop operating system */
t_stat fe_stop_os (UNIT *uptr, int32 val)
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;
@ -154,7 +155,7 @@ return SCPE_OK;
/* Enter control-C for Windoze */
t_stat fe_ctrl_c (UNIT *uptr, int32 val)
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 */

View file

@ -24,6 +24,8 @@
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"
@ -152,7 +154,7 @@ 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 arg);
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);
@ -570,7 +572,7 @@ update_lpcs (CSA_MBZ);
return reason;
}
t_stat lp20_clear_vfu (UNIT *uptr, int32 arg)
t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int i;

View file

@ -25,6 +25,7 @@
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
@ -754,6 +755,7 @@ 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;
}

View file

@ -26,6 +26,7 @@
ptr paper tape reader
ptp paper tape punch
29-Nov-01 RMS Added read only unit support
07-Sep-01 RMS Revised disable mechanism
*/
@ -59,7 +60,8 @@ t_stat ptp_detach (UNIT *uptr);
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (CSR, ptr_csr, 16) },

View file

@ -25,6 +25,8 @@
rp RH/RP/RM moving head disks
30-Nov-01 RMS Added read only unit, extended SET/SHOW support support
24-Nov-01 RMS Changed RPER, RPDS, FNC, FLG to arrays
23-Oct-01 RMS Fixed bug in error interrupts
New IO page address constants
05-Oct-01 RMS Rewrote interrupt handling from schematics
@ -75,9 +77,10 @@
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_W_UF 6 /* user flags width */
#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */
#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */
#define UNIT_DUMMY (1 << UNIT_V_DUMMY)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Parameters in the unit descriptor */
@ -338,7 +341,7 @@ int reg_in_drive[32] = {
void update_rpcs (int32 flags, int32 drv);
void rp_go (int32 drv, int32 fnc);
t_stat rp_set_size (UNIT *uptr, int32 value);
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rp_svc (UNIT *uptr);
t_stat rp_reset (DEVICE *dptr);
t_stat rp_boot (int32 unitno);
@ -355,21 +358,21 @@ t_stat rp_detach (UNIT *uptr);
UNIT rp_unit[] = {
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) } };
UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) } };
REG rp_reg[] = {
{ ORDATA (RPCS1, rpcs1, 16) },
@ -377,6 +380,8 @@ REG rp_reg[] = {
{ ORDATA (RPBA, rpba, 16) },
{ ORDATA (RPDA, rpda, 16) },
{ ORDATA (RPCS2, rpcs2, 16) },
{ BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) },
{ BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) },
{ ORDATA (RPOF, rpof, 16) },
{ ORDATA (RPDC, rpdc, 16) },
{ ORDATA (RPER2, rper2, 16) },
@ -392,46 +397,11 @@ REG rp_reg[] = {
{ FLDATA (IE, rpcs1, CSR_V_IE) },
{ DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT },
{ DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT },
{ ORDATA (RPDS0, rpds[0], 16) },
{ ORDATA (RPDS1, rpds[1], 16) },
{ ORDATA (RPDS2, rpds[2], 16) },
{ ORDATA (RPDS3, rpds[3], 16) },
{ ORDATA (RPDS4, rpds[4], 16) },
{ ORDATA (RPDS5, rpds[5], 16) },
{ ORDATA (RPDS6, rpds[6], 16) },
{ ORDATA (RPDS7, rpds[7], 16) },
{ ORDATA (RPDE0, rper1[0], 16) },
{ ORDATA (RPDE1, rper1[1], 16) },
{ ORDATA (RPDE2, rper1[2], 16) },
{ ORDATA (RPDE3, rper1[3], 16) },
{ ORDATA (RPDE4, rper1[4], 16) },
{ ORDATA (RPDE5, rper1[5], 16) },
{ ORDATA (RPDE6, rper1[6], 16) },
{ ORDATA (RPDE7, rper1[7], 16) },
{ ORDATA (RPFN0, rp_unit[0].FUNC, 5), REG_HRO },
{ ORDATA (RPFN1, rp_unit[1].FUNC, 5), REG_HRO },
{ ORDATA (RPFN2, rp_unit[2].FUNC, 5), REG_HRO },
{ ORDATA (RPFN3, rp_unit[3].FUNC, 5), REG_HRO },
{ ORDATA (RPFN4, rp_unit[4].FUNC, 5), REG_HRO },
{ ORDATA (RPFN5, rp_unit[5].FUNC, 5), REG_HRO },
{ ORDATA (RPFN6, rp_unit[6].FUNC, 5), REG_HRO },
{ ORDATA (RPFN7, rp_unit[7].FUNC, 5), REG_HRO },
{ GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (FNC, rp_unit[0].FUNC, 8, 5, 0, RP_NUMDR, REG_HRO) },
{ URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
RP_NUMDR, REG_HRO) },
{ URDATA (CAPAC, rp_unit[0].capac, 10, 31, 0,
RP_NUMDR, PV_LEFT | REG_HRO) },
{ FLDATA (STOP_IOE, rp_stopioe, 0) },
{ NULL } };
@ -828,7 +798,7 @@ case FNC_SEEK: /* seek */
#define XBA_MBZ 0000003 /* addr<1:0> must be 0 */
case FNC_WRITE: /* write */
if (uptr -> flags & UNIT_WLK) { /* write locked? */
if (uptr -> flags & UNIT_WPRT) { /* write locked? */
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; }
@ -978,7 +948,7 @@ for (i = 0; i < RP_NUMDR; i++) {
sim_cancel (uptr);
uptr -> CYL = uptr -> FUNC = 0;
if (uptr -> flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) |
DS_DPR | DS_RDY | DS_MOL | ((uptr -> flags & UNIT_WLK)? DS_WRL: 0);
DS_DPR | DS_RDY | DS_MOL | ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0);
else if (uptr -> flags & UNIT_DIS) rpds[i] = 0;
else rpds[i] = DS_DPR;
rper1[i] = 0; }
@ -997,7 +967,7 @@ r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
drv = uptr - rp_dev.units; /* get drv number */
rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR |
((uptr -> flags & UNIT_WLK)? DS_WRL: 0);
((uptr -> flags & UNIT_WPRT)? DS_WRL: 0);
rper1[drv] = 0;
update_rpcs (CS1_SC, drv);
@ -1032,10 +1002,10 @@ return detach_unit (uptr);
/* Set size command validation routine */
t_stat rp_set_size (UNIT *uptr, int32 value)
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
uptr -> capac = drv_tab[GET_DTYPE (value)].size;
uptr -> capac = drv_tab[GET_DTYPE (val)].size;
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
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
@ -142,8 +143,8 @@ if (ttg <= 0) { /* timeout? */
if (ITS) { /* ITS? */
if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK;
if (TSTS (pcst)) { /* PC sampling? */
pcst = AOB (pcst); /* add 1,,1 */
WriteP ((a10) pcst & AMASK, pager_PC); }
WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */
pcst = AOB (pcst); } /* add 1,,1 */
} /* end ITS */
return SCPE_OK;
}

View file

@ -25,6 +25,8 @@
tu RH11/TM03/TU45 magtape
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Changed POS, FLG, UST to arrays
23-Oct-01 RMS Fixed bug in error interrupts
New IO page address constants
05-Oct-01 RMS Rewrote interrupt handling from schematics
@ -74,6 +76,7 @@
#define UDENS u4 /* unit density */
#define UD_UNK 0 /* unknown */
#define XBUFLNT (1 << 16) /* max data buf */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* MTCS1 - 172440 - control/status 1 */
@ -300,7 +303,7 @@ t_stat tu_detach (UNIT *uptr);
t_stat tu_boot (int32 unitno);
void tu_go (int32 drv);
void update_tucs (int32 flag, int32 drv);
t_stat tu_vlock (UNIT *uptr, int32 val);
t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
/* TU data structures
@ -311,14 +314,14 @@ t_stat tu_vlock (UNIT *uptr, int32 val);
*/
UNIT tu_unit[] = {
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } };
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } };
REG tu_reg[] = {
{ ORDATA (MTCS1, tucs1, 16) },
@ -338,38 +341,11 @@ REG tu_reg[] = {
{ FLDATA (IE, tucs1, CSR_V_IE) },
{ FLDATA (STOP_IOE, tu_stopioe, 0) },
{ DRDATA (TIME, tu_time, 24), PV_LEFT },
{ ORDATA (UST0, tu_unit[0].USTAT, 17) },
{ ORDATA (UST1, tu_unit[1].USTAT, 17) },
{ ORDATA (UST2, tu_unit[2].USTAT, 17) },
{ ORDATA (UST3, tu_unit[3].USTAT, 17) },
{ ORDATA (UST4, tu_unit[4].USTAT, 17) },
{ ORDATA (UST5, tu_unit[5].USTAT, 17) },
{ ORDATA (UST6, tu_unit[6].USTAT, 17) },
{ ORDATA (UST7, tu_unit[7].USTAT, 17) },
{ DRDATA (POS0, tu_unit[0].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS1, tu_unit[1].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS2, tu_unit[2].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS3, tu_unit[3].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS4, tu_unit[4].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS5, tu_unit[5].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS6, tu_unit[6].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS7, tu_unit[7].pos, 31), PV_LEFT + REG_RO },
{ GRDATA (FLG0, tu_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, tu_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, tu_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, tu_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, tu_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, tu_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, tu_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, tu_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (UST, tu_unit[0].USTAT, 8, 17, 0, TU_NUMDR, 0) },
{ URDATA (POS, tu_unit[0].pos, 8, 31, 0,
TU_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (FLG, tu_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
TU_NUMDR, REG_HRO) },
{ ORDATA (LOG, tu_log, 8), REG_HIDDEN },
{ NULL } };
@ -630,7 +606,7 @@ case FNC_WRITE: /* write */
break; }
case FNC_WREOF: /* write tape mark */
case FNC_ERASE: /* erase */
if (uptr -> flags & UNIT_WLK) { /* write locked? */
if (uptr -> flags & UNIT_WPRT) { /* write locked? */
tuer = tuer | ER_NXF;
break; }
case FNC_WCHKF: /* wchk = read */
@ -902,7 +878,7 @@ if (GET_FMTR (tucs2) == 0) { /* formatter present? */
if (tu_unit[drv].flags & UNIT_ATT) {
tufs = tufs | FS_MOL | tu_unit[drv].USTAT;
if (tu_unit[drv].UDENS == TC_1600) tufs = tufs | FS_PE;
if (tu_unit[drv].flags & UNIT_WLK) tufs = tufs | FS_WRL;
if (tu_unit[drv].flags & UNIT_WPRT) tufs = tufs | FS_WRL;
if ((tu_unit[drv].pos == 0) && !act) tufs = tufs | FS_BOT; }
if (tuer) tufs = tufs | FS_ERR; }
else tufs = 0;
@ -984,7 +960,7 @@ return detach_unit (uptr);
/* Write lock/enable routine */
t_stat tu_vlock (UNIT *uptr, int32 val)
t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (sim_is_active (uptr)) return SCPE_ARG;
return SCPE_OK;

View file

@ -25,6 +25,11 @@
cpu PDP-11 CPU (J-11 microprocessor)
25-Dec-01 RMS Cleaned up sim_inst declarations
11-Dec-01 RMS Moved interrupt debug code
07-Dec-01 RMS Revised to use new breakpoint package
08-Nov-01 RMS Moved I/O to external module
26-Oct-01 RMS Revised to use symbolic definitions for IO page
15-Oct-01 RMS Added debug logging
08-Oct-01 RMS Fixed bug in revised interrupt logic
07-Sep-01 RMS Revised device disable and interrupt mechanisms
@ -168,39 +173,41 @@
4. Adding I/O devices. This requires modifications to three modules:
pdp11_defs.h add interrupt request definitions
pdp11_cpu.c add I/O page linkages
pdp11_io.c add I/O page linkages
pdp11_sys.c add to sim_devices
*/
/* Definitions */
#include "pdp11_defs.h"
#include <setjmp.h>
#define calc_is(md) ((md) << VA_V_MODE)
#define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0))
#define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val))
#define GET_SIGN_W(v) ((v) >> 15)
#define GET_SIGN_B(v) ((v) >> 7)
#define GET_Z(v) ((v) == 0)
#define JMP_PC(x) old_PC = PC; PC = (x)
#define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777
#define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777
#define ILL_ADR_FLAG 0200000
#define save_ibkpt (cpu_unit.u3) /* will be SAVEd */
#define last_pa (cpu_unit.u4) /* and RESTOREd */
#define calc_is(md) ((md) << VA_V_MODE)
#define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0))
#define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val))
#define GET_SIGN_W(v) ((v) >> 15)
#define GET_SIGN_B(v) ((v) >> 7)
#define GET_Z(v) ((v) == 0)
#define JMP_PC(x) old_PC = PC; PC = (x)
#define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777
#define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777
#define last_pa (cpu_unit.u4) /* auto save/rest */
#define UNIT_V_18B (UNIT_V_UF) /* force 18b addr */
#define UNIT_V_UBM (UNIT_V_UF + 1) /* bus map present */
#define UNIT_V_RH11 (UNIT_V_UF + 2) /* RH11 Massbus */
#define UNIT_V_CIS (UNIT_V_UF + 3) /* CIS present */
#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy */
#define UNIT_18B (1u << UNIT_V_18B)
#define UNIT_V_CIS (UNIT_V_UF + 1) /* CIS present */
#define UNIT_UBM (1u << UNIT_V_UBM)
#define UNIT_RH11 (1u << UNIT_V_RH11)
#define UNIT_CIS (1u << UNIT_V_CIS)
#define UNIT_V_MSIZE (UNIT_V_UF + 2) /* dummy */
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
#define UNIT_MAP (UNIT_18B | UNIT_UBM | UNIT_RH11)
/* Global state */
extern FILE *sim_log;
uint16 *M = NULL; /* address of memory */
uint16 *M = NULL; /* memory */
int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */
int32 STACKFILE[4] = { 0 }; /* SP, four modes */
int32 saved_PC = 0; /* program counter */
@ -227,34 +234,36 @@ int32 MMR0 = 0; /* MMR0 - status */
int32 MMR1 = 0; /* MMR1 - R+/-R */
int32 MMR2 = 0; /* MMR2 - saved PC */
int32 MMR3 = 0; /* MMR3 - 22b status */
int32 ub_map[UBM_LNT_LW] = { 0 }; /* Unibus map array */
int32 cpu_bme = 0; /* bus map enable */
int32 cpu_18b = 0; /* 18b CPU config'd */
int32 cpu_ubm = 0; /* bus map config'd */
int32 cpu_rh11 = 0; /* RH11 config'd */
int32 isenable = 0, dsenable = 0; /* i, d space flags */
int32 CPUERR = 0; /* CPU error reg */
int32 MEMERR = 0; /* memory error reg */
int32 CCR = 0; /* cache control reg */
int32 HITMISS = 0; /* hit/miss reg */
int32 MAINT = (0 << 9) + (0 << 8) + (4 << 4); /* maint bit<9> = Q/U */
/* <8> = hwre FP */
/* <6:4> = sys type */
int32 MAINT = MAINT_Q | MAINT_NOFPA | MAINT_KDJ; /* maint reg */
int32 stop_trap = 1; /* stop on trap */
int32 stop_vecabort = 1; /* stop on vec abort */
int32 stop_spabort = 1; /* stop on SP abort */
int32 wait_enable = 0; /* wait state enable */
int32 pdp11_log = 0; /* logging */
int32 ibkpt_addr = ILL_ADR_FLAG | VAMASK; /* breakpoint addr */
int32 cpu_log = 0; /* logging */
int32 old_PC = 0; /* previous PC */
int32 dev_enb = (-1) & ~INT_TS; /* dev enables */
jmp_buf save_env; /* abort handler */
int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
/* Function declarations */
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_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
int32 GeteaB (int32 spec);
int32 GeteaW (int32 spec);
int32 relocR (int32 addr);
@ -267,103 +276,14 @@ void WriteW (int32 data, int32 addr);
void WriteB (int32 data, int32 addr);
void PWriteW (int32 data, int32 addr);
void PWriteB (int32 data, int32 addr);
t_stat iopageR (int32 *data, int32 addr, int32 access);
t_stat iopageW (int32 data, int32 addr, int32 access);
int32 calc_ints (int32 nipl, int32 trq);
t_stat CPU_rd (int32 *data, int32 addr, int32 access);
t_stat CPU_wr (int32 data, int32 addr, int32 access);
t_stat APR_rd (int32 *data, int32 addr, int32 access);
t_stat APR_wr (int32 data, int32 addr, int32 access);
t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access);
t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access);
t_stat MMR3_rd (int32 *data, int32 addr, int32 access);
t_stat MMR3_wr (int32 data, int32 addr, int32 access);
extern t_stat std_rd (int32 *data, int32 addr, int32 access);
extern t_stat std_wr (int32 data, int32 addr, int32 access);
extern t_stat lpt_rd (int32 *data, int32 addr, int32 access);
extern t_stat lpt_wr (int32 data, int32 addr, int32 access);
extern t_stat dz_rd (int32 *data, int32 addr, int32 access);
extern t_stat dz_wr (int32 data, int32 addr, int32 access);
extern t_stat rk_rd (int32 *data, int32 addr, int32 access);
extern t_stat rk_wr (int32 data, int32 addr, int32 access);
extern int32 rk_inta (void);
extern int32 rk_enb;
/* extern t_stat hk_rd (int32 *data, int32 addr, int32 access);
extern t_stat hk_wr (int32 data, int32 addr, int32 access);
extern int32 hk_inta (void);
extern int32 hk_enb; */
extern t_stat rl_rd (int32 *data, int32 addr, int32 access);
extern t_stat rl_wr (int32 data, int32 addr, int32 access);
extern int32 rl_enb;
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 int32 rp_enb;
extern t_stat rx_rd (int32 *data, int32 addr, int32 access);
extern t_stat rx_wr (int32 data, int32 addr, int32 access);
extern int32 rx_enb;
extern t_stat dt_rd (int32 *data, int32 addr, int32 access);
extern t_stat dt_wr (int32 data, int32 addr, int32 access);
extern int32 dt_enb;
extern t_stat tm_rd (int32 *data, int32 addr, int32 access);
extern t_stat tm_wr (int32 data, int32 addr, int32 access);
extern int32 tm_enb;
extern t_stat ts_rd (int32 *data, int32 addr, int32 access);
extern t_stat ts_wr (int32 data, int32 addr, int32 access);
extern int32 ts_enb;
/* Auxiliary data 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 */
extern t_stat iopageR (int32 *data, int32 addr, int32 access);
extern t_stat iopageW (int32 data, int32 addr, int32 access);
extern int32 calc_ints (int32 nipl, int32 trq);
extern int32 get_vector (int32 nipl);
struct iolink iotable[] = {
{ 017777740, 017777777, NULL, &CPU_rd, &CPU_wr },
{ 017777546, 017777567, NULL, &std_rd, &std_wr },
{ 017777514, 017777517, NULL, &lpt_rd, &lpt_wr },
{ 017760100, 017760107, NULL, &dz_rd, &dz_wr },
{ 017777400, 017777417, &rk_enb, &rk_rd, &rk_wr },
/* { 017777440, 017777477, &hk_enb, &hk_rd, &hk_wr }, */
{ 017774400, 017774411, &rl_enb, &rl_rd, &rl_wr },
{ 017776700, 017776753, &rp_enb, &rp_rd, &rp_wr },
{ 017777170, 017777173, &rx_enb, &rx_rd, &rx_wr },
{ 017777340, 017777351, &dt_enb, &dt_rd, &dt_wr },
{ 017772520, 017772533, &tm_enb, &tm_rd, &tm_wr },
{ 017772520, 017772523, &ts_enb, &ts_rd, &ts_wr },
{ 017777600, 017777677, NULL, &APR_rd, &APR_wr },
{ 017772200, 017772377, NULL, &APR_rd, &APR_wr },
{ 017777570, 017777577, NULL, &SR_MMR012_rd, &SR_MMR012_wr },
{ 017772516, 017772517, NULL, &MMR3_rd, &MMR3_wr },
{ 0, 0, NULL, NULL, NULL } };
int32 int_vec[IPL_HLVL][32] = { /* int req to vector */
{ 0 }, /* IPL 0 */
{ VEC_PIRQ }, /* IPL 1 */
{ VEC_PIRQ }, /* IPL 2 */
{ VEC_PIRQ }, /* IPL 3 */
{ VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, /* IPL 4 */
VEC_LPT, VEC_PIRQ },
{ VEC_RK, VEC_RL, VEC_RX, VEC_TM, /* IPL 5 */
VEC_RP, VEC_TS, VEC_HK, VEC_DZRX,
VEC_DZTX, VEC_PIRQ },
{ VEC_CLK, VEC_DTA, VEC_PIRQ }, /* IPL 6 */
{ VEC_PIRQ } }; /* IPL 7 */
int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */
{ NULL }, /* IPL 0 */
{ NULL }, /* IPL 1 */
{ NULL }, /* IPL 2 */
{ NULL }, /* IPL 3 */
{ NULL }, /* IPL 4 */
{ &rk_inta, NULL, NULL, NULL, /* IPL 5 */
&rp_inta, NULL, NULL, NULL },
{ NULL }, /* IPL 6 */
{ NULL } }; /* IPL 7 */
/* Trap data structures */
int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */
VEC_RED, VEC_ODD, VEC_MME, VEC_NXM,
@ -390,7 +310,7 @@ int32 trap_clear[TRAP_V_MAX] = { /* trap clears */
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, INIMEMSIZE) };
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INIMEMSIZE) };
REG cpu_reg[] = {
{ ORDATA (PC, saved_PC, 16) },
@ -434,7 +354,7 @@ REG cpu_reg[] = {
{ ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) },
{ FLDATA (STOP_VECA, stop_vecabort, 0) },
{ FLDATA (STOP_SPA, stop_spabort, 0) },
{ ORDATA (DBGLOG, pdp11_log, 16), REG_HIDDEN },
{ ORDATA (DBGLOG, cpu_log, 16), REG_HIDDEN },
{ ORDATA (FAC0H, FR[0].h, 32) },
{ ORDATA (FAC0L, FR[0].l, 32) },
{ ORDATA (FAC1H, FR[1].h, 32) },
@ -550,19 +470,23 @@ REG cpu_reg[] = {
{ GRDATA (UDPDR6, APRFILE[076], 8, 16, 0) },
{ GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) },
{ GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) },
{ BRDATA (UBMAP, ub_map, 8, 22, UBM_LNT_LW) },
{ FLDATA (18B_ADDR, cpu_unit.flags, UNIT_V_18B), REG_HRO },
{ FLDATA (UB_MAP, cpu_unit.flags, UNIT_V_UBM), REG_HRO },
{ FLDATA (RH11, cpu_unit.flags, UNIT_V_RH11), REG_HRO },
{ FLDATA (CIS, cpu_unit.flags, UNIT_V_CIS), REG_HRO },
{ ORDATA (OLDPC, old_PC, 16), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 17) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL} };
MTAB cpu_mod[] = {
{ UNIT_18B, UNIT_18B, "18b addressing", "18B", NULL },
{ UNIT_18B, 0, NULL, "22B", NULL },
{ UNIT_MAP, UNIT_18B, "18b addressing", "18B", NULL },
{ UNIT_MAP, UNIT_UBM, "22b Unibus + RH70", "URH70", NULL },
{ UNIT_MAP, UNIT_UBM + UNIT_RH11, "22b Unibus + RH11", "URH11", NULL },
{ UNIT_MAP, 0, "22b addressing", "22B", NULL },
{ UNIT_CIS, UNIT_CIS, "CIS", "CIS", NULL },
{ UNIT_CIS, 0, "No CIS", "NOCIS", NULL },
{ UNIT_CIS, 0, "no CIS", "NOCIS", NULL },
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size},
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size},
{ UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size},
@ -595,11 +519,8 @@ t_stat sim_instr (void)
extern int32 sim_interval;
extern UNIT *sim_clock_queue;
extern UNIT clk_unit;
int32 IR, srcspec, srcreg, dstspec, dstreg;
int32 src, src2, dst;
int32 i, j, t, sign, oldrs, trapnum;
int32 abortval;
volatile int32 trapea;
int abortval, i;
volatile int32 trapea; /* needed at longjmp */
t_stat reason;
void fp11 (int32 IR);
void cis11 (int32 IR);
@ -631,7 +552,11 @@ isenable = calc_is (cm);
dsenable = calc_ds (cm);
CPU_wr (PIRQ, 017777772, WRITE); /* rewrite PIRQ */
trap_req = calc_ints (ipl, trap_req);
cpu_bme = (MMR3 & MMR3_BME) && (cpu_unit.flags & UNIT_UBM);
cpu_18b = cpu_unit.flags & UNIT_18B; /* export cnf flgs */
cpu_ubm = cpu_unit.flags & UNIT_UBM;
cpu_rh11 = cpu_unit.flags & UNIT_RH11;
trap_req = calc_ints (ipl, trap_req); /* upd int req */
trapea = 0;
reason = 0;
sim_rtc_init (clk_unit.wait); /* init clock */
@ -668,41 +593,37 @@ if (abortval != 0) {
*/
while (reason == 0) {
if (sim_interval <= 0) { /* check clock queue */
reason = sim_process_event ();
trap_req = calc_ints (ipl, trap_req);
continue; }
int32 IR, srcspec, srcreg, dstspec, dstreg;
int32 src, src2, dst;
int32 i, t, sign, oldrs, trapnum;
if (sim_interval <= 0) { /* intv cnt expired? */
reason = sim_process_event (); /* process events */
trap_req = calc_ints (ipl, trap_req); /* recalc int req */
continue;
} /* end if sim_interval */
if (trap_req) { /* check traps, ints */
trapea = 0; /* assume srch fails */
if (t = trap_req & TRAP_ALL) { /* if a trap */
for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) {
if ((t >> trapnum) & 1) {
trapea = trap_vec[trapnum];
for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) {
if ((t >> trapnum) & 1) { /* trap set? */
trapea = trap_vec[trapnum]; /* get vec, clr */
trap_req = trap_req & ~trap_clear[trapnum];
if ((stop_trap >> trapnum) & 1)
reason = trapnum + 1;
break; } /* end if t & 1 */
} /* end for */
} /* end if */
else {
for (i = IPL_HLVL - 1; (trapea == 0) && (i > ipl); i--) {
t = int_req[i]; /* get level */
for (j = 0; t && (j < 32); j++) { /* srch level */
if ((t >> j) & 1) { /* irq found? */
int_req[i] = int_req[i] & ~(1u << j);
if (int_ack[i][j]) trapea = int_ack[i][j]();
else trapea = int_vec[i][j];
trapnum = TRAP_V_MAX;
if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log,
">>CPU, lvl=%d, flag=%d, vec=%o\n",
i, j, trapea);
break; } /* end if t & 1 */
} /* end for j */
} /* end for i */
} /* end else */
if ((stop_trap >> trapnum) & 1) /* stop on trap? */
reason = trapnum + 1;
break;
} /* end if t & 1 */
} /* end for */
} /* end if t */
else { trapea = get_vector (ipl); /* get int vector */
trapnum = TRAP_V_MAX; /* defang stk trap */
} /* end else t*/
if (trapea == 0) { /* nothing to do? */
trap_req = calc_ints (ipl, 0); /* recalculate */
continue; } /* back to fetch */
continue; /* back to fetch */
} /* end if trapea */
/* Process a trap or interrupt
@ -761,10 +682,7 @@ if (wait_state) { /* wait state? */
else reason = STOP_WAIT;
continue; }
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save bkpt */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
continue; }
@ -2090,56 +2008,6 @@ else { pa = va & 0177777; /* mmgt off */
return pa;
}
/* I/O page lookup and linkage routines
Inputs:
*data = pointer to data to read, if READ
data = data to store, if WRITE or WRITEB
pa = address
access = READ, WRITE, or WRITEB
Outputs:
status = SCPE_OK or SCPE_NXM
*/
t_stat iopageR (int32 *data, int32 pa, int32 access)
{
t_stat stat;
struct iolink *p;
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa <= p -> high) &&
((p -> enb == NULL) || *p -> enb)) {
stat = p -> read (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
return SCPE_NXM;
}
t_stat iopageW (int32 data, int32 pa, int32 access)
{
t_stat stat;
struct iolink *p;
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa <= p -> high) &&
((p -> enb == NULL) || *p -> enb)) {
stat = p -> write (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
return SCPE_NXM;
}
/* Calculate interrupt outstanding */
int32 calc_ints (int32 nipl, int32 trq)
{
int32 i;
for (i = IPL_HLVL - 1; i > nipl; i--) {
if (int_req[i]) return (trq | TRAP_INT); }
return (trq & ~TRAP_INT);
}
/* I/O page routines for CPU registers
Switch register and memory management registers
@ -2196,6 +2064,7 @@ if (pa & 1) return SCPE_OK;
MMR3 = data & MMR3_RW;
if (cpu_unit.flags & UNIT_18B)
MMR3 = MMR3 & ~(MMR3_BME + MMR3_M22E); /* for UNIX V6 */
cpu_bme = (MMR3 & MMR3_BME) && (cpu_unit.flags & UNIT_UBM);
dsenable = calc_ds (cm);
return SCPE_OK;
}
@ -2269,8 +2138,9 @@ case 2: /* MEMERR */
case 3: /* CCR */
*data = CCR;
return SCPE_OK;
case 4: /* MAint */
*data = MAINT;
case 4: /* MAINT */
if (cpu_ubm) *data = MAINT | MAINT_U;
else *data = MAINT | MAINT_Q;
return SCPE_OK;
case 5: /* Hit/miss */
*data = HITMISS;
@ -2378,14 +2248,19 @@ return SCPE_NXM; /* unimplemented */
t_stat cpu_reset (DEVICE *dptr)
{
int32 i;
PIRQ = MMR0 = MMR1 = MMR2 = MMR3 = 0;
cpu_bme = 0;
DR = CPUERR = MEMERR = CCR = HITMISS = 0;
PSW = 000340;
trap_req = 0;
wait_state = 0;
if (M == NULL) M = calloc (MEMSIZE >> 1, sizeof (unsigned int16));
if (M == NULL) return SCPE_MEM;
return cpu_svc (&cpu_unit);
for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0;
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -2423,34 +2298,25 @@ if (addr < MEMSIZE) {
if (addr < IOPAGEBASE) return SCPE_NXM;
return iopageW ((int32) val, addr, WRITEC);
}
/* Breakpoint service */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
/* Memory allocation */
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i, clim;
unsigned int16 *nM = NULL;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i = i + 2) mc = mc | M[i >> 1];
for (i = val; i < MEMSIZE; i = i + 2) mc = mc | M[i >> 1];
if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE))
return SCPE_OK;
nM = calloc (value >> 1, sizeof (unsigned int16));
nM = calloc (val >> 1, sizeof (unsigned int16));
if (nM == NULL) return SCPE_MEM;
clim = (((t_addr) value) < MEMSIZE)? value: MEMSIZE;
clim = (((t_addr) val) < MEMSIZE)? val: MEMSIZE;
for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1];
free (M);
M = nM;
MEMSIZE = value;
MEMSIZE = val;
return SCPE_OK; }

View file

@ -26,6 +26,9 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11
09-Nov-01 RMS Added bus map support
07-Nov-01 RMS Added RQDX3 support
26-Oct-01 RMS Added symbolic definitions for IO page
19-Oct-01 RMS Added DZ definitions
15-Oct-01 RMS Added logging capabilities
07-Sep-01 RMS Revised for multilevel interrupts
@ -46,6 +49,7 @@
#define INIMEMSIZE 001000000 /* 2**18 */
#define IOPAGEBASE 017760000 /* 2**22 - 2**13 */
#define MAXMEMSIZE 020000000 /* 2**22 */
#define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */
#define MEMSIZE (cpu_unit.capac)
#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE)
#define DMASK 0177777
@ -146,6 +150,16 @@
#define VA_V_MODE 17 /* offset to mode */
#define VA_DS (1u << VA_V_DS) /* data space flag */
/* Unibus map (if present) */
#define UBM_LNT_LW 32 /* size in LW */
#define UBM_V_PN 13 /* page number */
#define UBM_M_PN 037
#define UBM_V_OFF 0 /* offset */
#define UBM_M_OFF 017777
#define UBM_GETPN(x) (((x) >> UBM_V_PN) & UBM_M_PN)
#define UBM_GETOFF(x) ((x) & UBM_M_OFF)
/* CPUERR */
#define CPUE_RED 0004 /* red stack */
@ -156,6 +170,17 @@
#define CPUE_HALT 0200 /* HALT not kernel */
#define CPUE_IMP 0374 /* implemented bits */
/* Maintenance register */
#define MAINT_V_UQ 9 /* Q/U flag */
#define MAINT_Q (0 << MAINT_V_UQ) /* Qbus */
#define MAINT_U (1 << MAINT_V_UQ)
#define MAINT_V_FPA 8 /* FPA flag */
#define MAINT_NOFPA (0 << MAINT_V_FPA)
#define MAINT_FPA (1 << MAINT_V_FPA)
#define MAINT_V_TYP 4 /* system type */
#define MAINT_KDJ (4 << MAINT_V_TYP)
/* Floating point accumulators */
struct fpac {
@ -233,11 +258,12 @@ typedef struct fpac fpac_t;
/* Simulator stop codes; codes 1:TRAP_V_MAX correspond to traps 0:TRAPMAX-1 */
#define STOP_HALT TRAP_V_MAX + 1 /* HALT instruction */
#define STOP_IBKPT TRAP_V_MAX + 2 /* instruction bkpt */
#define STOP_WAIT TRAP_V_MAX + 3 /* wait, no events */
#define STOP_VECABORT TRAP_V_MAX + 4 /* abort vector read */
#define STOP_SPABORT TRAP_V_MAX + 5 /* abort trap push */
#define STOP_HALT (TRAP_V_MAX + 1) /* HALT instruction */
#define STOP_IBKPT (TRAP_V_MAX + 2) /* instruction bkpt */
#define STOP_WAIT (TRAP_V_MAX + 3) /* wait, no events */
#define STOP_VECABORT (TRAP_V_MAX + 4) /* abort vector read */
#define STOP_SPABORT (TRAP_V_MAX + 5) /* abort trap push */
#define STOP_RQ (TRAP_V_MAX + 6) /* RQDX3 panic */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
/* DZ11 parameters */
@ -245,6 +271,45 @@ typedef struct fpac fpac_t;
#define DZ_MUXES 1 /* # of muxes */
#define DZ_LINES 8 /* lines per mux */
/* I/O page layout */
#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */
#define IOLN_DZ (010 * DZ_MUXES)
#define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */
#define IOLN_UBM (UBM_LNT_LW * sizeof (int32))
#define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */
#define IOLN_RQ 004
#define IOBA_APR (IOPAGEBASE + 012200) /* APRs */
#define IOLN_APR 0200
#define IOBA_MMR3 (IOPAGEBASE + 012516) /* MMR3 */
#define IOLN_MMR3 002
#define IOBA_TM (IOPAGEBASE + 012520) /* TM11 */
#define IOLN_TM 014
#define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */
#define IOLN_TS 004
#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */
#define IOLN_RL 012
#define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */
#define IOLN_RP 054
#define IOBA_RX (IOPAGEBASE + 017170) /* RX11 */
#define IOLN_RX 004
#define IOBA_TC (IOPAGEBASE + 017340) /* TC11 */
#define IOLN_TC 012
#define IOBA_RK (IOPAGEBASE + 017400) /* RK11 */
#define IOLN_RK 020
#define IOBA_RK6 (IOPAGEBASE + 017440) /* RK611 */
#define IOLN_RK6 040
#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */
#define IOLN_LPT 004
#define IOBA_STD (IOPAGEBASE + 017546) /* KW11L, DL11, PC11 */
#define IOLN_STD 022
#define IOBA_SRMM (IOPAGEBASE + 017570) /* SR, MMR0-2 */
#define IOLN_SRMM 010
#define IOBA_APR1 (IOPAGEBASE + 017600) /* APRs */
#define IOLN_APR1 0100
#define IOBA_CPU (IOPAGEBASE + 017740) /* CPU reg */
#define IOLN_CPU 040
/* Interrupt assignments; within each level, priority is right to left */
#define IPL_HLVL 8 /* # int levels */
@ -262,9 +327,10 @@ typedef struct fpac fpac_t;
#define INT_V_RP 4
#define INT_V_TS 5
#define INT_V_HK 6
#define INT_V_DZRX 7
#define INT_V_DZTX 8
#define INT_V_PIR5 9
#define INT_V_RQ 7
#define INT_V_DZRX 8
#define INT_V_DZTX 9
#define INT_V_PIR5 10
#define INT_V_TTI 0 /* BR4 */
#define INT_V_TTO 1
@ -287,7 +353,8 @@ typedef struct fpac fpac_t;
#define INT_TM (1u << INT_V_TM)
#define INT_RP (1u << INT_V_RP)
#define INT_TS (1u << INT_V_TS)
#define INT_HK (1u << INT_V_HK)
#define INT_RK6 (1u << INT_V_HK)
#define INT_RQ (1u << INT_V_RQ)
#define INT_DZRX (1u << INT_V_DZRX)
#define INT_DZTX (1u << INT_V_DZTX)
#define INT_PIR5 (1u << INT_V_PIR5)
@ -309,7 +376,8 @@ typedef struct fpac fpac_t;
#define IPL_TM 5
#define IPL_RP 5
#define IPL_TS 5
#define IPL_HK 5
#define IPL_RK6 5
#define IPL_RQ 5
#define IPL_DZRX 5
#define IPL_DZTX 5
#define IPL_PTR 4
@ -326,16 +394,18 @@ typedef struct fpac fpac_t;
#define IPL_PIR2 2
#define IPL_PIR1 1
#define VEC_PIRQ 0240 /* interrupt vectors */
#define VEC_Q 0000 /* vector base */
#define VEC_PIRQ 0240
#define VEC_TTI 0060
#define VEC_TTO 0064
#define VEC_PTR 0070
#define VEC_PTP 0074
#define VEC_CLK 0100
#define VEC_LPT 0200
#define VEC_HK 0210
#define VEC_RK 0220
#define VEC_RQ 0154
#define VEC_RL 0160
#define VEC_LPT 0200
#define VEC_RK6 0210
#define VEC_RK 0220
#define VEC_DTA 0214
#define VEC_TM 0224
#define VEC_TS 0224
@ -347,15 +417,15 @@ typedef struct fpac fpac_t;
/* Interrupt macros */
#define IREQ(dv) int_req[IPL_##dv]
#define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv)
#define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv)
#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv)
#define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv)
/* CPU and FPU macros */
#define update_MM ((MMR0 & (MMR0_FREEZE + MMR0_MME)) == MMR0_MME)
#define setTRAP(name) trap_req = trap_req | (name)
#define setCPUERR(name) CPUERR = CPUERR | (name)
#define ABORT(val) longjmp (save_env, (val))
#define update_MM ((MMR0 & (MMR0_FREEZE + MMR0_MME)) == MMR0_MME)
#define setTRAP(name) trap_req = trap_req | (name)
#define setCPUERR(name) CPUERR = CPUERR | (name)
#define ABORT(val) longjmp (save_env, (val))
#define SP R[6]
#define PC R[7]
@ -364,9 +434,21 @@ typedef struct fpac fpac_t;
#define LOG_CPU_I 00000001
#define LOG_RP 00000010
#define LOG_TS 00000020
#define LOG_RQ 00000040
#define LOG_TC_MS 00000100
#define LOG_TC_RW 00000200
#define LOG_TC_RA 00000400
#define LOG_TC_BL 00001000
#define DBG_LOG(x) (sim_log && (pdp11_log & (x)))
#define DBG_LOG(x) (sim_log && (cpu_log & (x)))
/* Function prototypes */
#define QB 0 /* Q22 native */
#define UB 1 /* Unibus */
t_bool Map_Addr (t_addr qa, t_addr *ma);
int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub);
int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub);
int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub);
int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub);

868
PDP11/pdp11_doc.txt Normal file
View file

@ -0,0 +1,868 @@
To: Users
From: Bob Supnik
Subj: PDP-11 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-11 simulator.
1. Simulator Files
sim/ sim_defs.h
sim_sock.h
sim_tmxr.h
dec_dz.h
dec_mscp.h
dec_uqssp.h
scp.c
scp_tty.c
sim_rev.c
sim_sock.c
sim_tmxr.c
sim/pdp11/ pdp11_defs.h
pdp11_cpu.c
pdp11_dz.c
pdp11_fp.c
pdp11_io.c
pdp11_lp.c
pdp11_rk.c
pdp11_rl.c
pdp11_rp.c
pdp11_rq.c
pdp11_rx.c
pdp11_stddev.c
pdp11_sys.c
pdp11_tc.c
pdp11_tm.c
pdp11_ts.c
2. PDP-11 Features
The PDP-11 simulator is configured as follows:
device simulates
name(s)
CPU J-11 CPU with 256KB of memory
- FP11 floating point unit (FPA)
- CIS11 commercial instruction set (CIS, off by default)
PTR,PTP PC11 paper tape reader/punch
TTI,TTO DL11 console terminal
LPT LP11 line printer
CLK line frequency clock
DZ DZ11 8-line terminal multiplexor
RK RK11/RK05 cartridge disk controller with eight drives
RL RLV12/RL01(2) cartridge disk controller with four drives
RP RM02/03/05/80, RP04/05/06/07 Massbus style controller
with eight drives
RQ RQDX3 MSCP controller with four drives
RX RX11/RX01 floppy disk controller with two drives
TC TC11/TU56 DECtape controller with eight drives
TM TM11/TU10 magnetic tape controller with eight drives
TS TS11/TSV05 magnetic tape controller with one drive
The DZ, RK, RL, RP, RQ, RX, TC, TM, and TS devices can be DISABLEd. The
PDP-11 can support either a TM11 or a TS11, but not both, since they use
the same I/O addresses. The simulator defaults to the TM11. To change
the magtape,
ENABLE TM11 enable TM11 and disable TS11
ENABLE TS11 enable TS11 and disable TM11
The PDP-11 simulator implements several unique stop conditions:
- abort during exception vector fetch, and register STOP_VEC is set
- abort during exception stack push, and register STOP_SPA is set
- trap condition 'n' occurs, and register STOP_TRAP<n> is set
- wait state entered, and no I/O operations outstanding
(ie, no interrupt can ever occur)
The PDP-11 loader supports standard binary format tapes. The DUMP command
is not implemented.
2.1 CPU
The CPU options include CPU mapping configuration (18b Unibus, 22b Unibus
with RH70-style controllers, 22b Unibus with RH11 style controllers, and
22b Qbus), the CIS instruction set, and the size of main memory.
SET CPU 18B 18b addressing, no I/O map
SET CPU URH11 22b addresssing, Unibus I/O map,
18b mapped RH11 controller
SET CPU URH70 22b addressing, Unibus I/O map,
22b unmapped RH70 controller
SET CPU 22B 22b addressing, no I/O map (Qbus)
SET CPU NOCIS disable CIS instructions (default)
SET CPU CIS enable CIS instructions
SET CPU 16K set memory size = 16KB
SET CPU 32K set memory size = 32KB
SET CPU 48K set memory size = 48KB
SET CPU 64K set memory size = 64KB
SET CPU 96K set memory size = 96KB
SET CPU 128K set memory size = 128KB
SET CPU 192K set memory size = 192KB
SET CPU 256K set memory size = 256KB
SET CPU 384K set memory size = 384KB
SET CPU 512K set memory size = 512KB
SET CPU 768K set memory size = 768KB
SET CPU 1024K (or 1M) set memory size = 1024KB
SET CPU 2048K (or 2M) set memory size = 2048KB
SET CPU 3072K (or 3M) set memory size = 3072KB
SET CPU 4096K (or 4M) set memory size = 4096KB
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 256KB.
These switches are recognized when examining or depositing in CPU memory:
-v interpret address as virtual
-d if mem mgt enabled, force data space
-k if mem mgt enabled, force kernel mode
-s if mem mgt enabled, force supervisor mode
-u if mem mgt enabled, force user mode
-p if mem mgt enabled, force previous mode
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
name size comments
PC 16 program counter
R0..R5 16 R0..R5, first register set
R10..R15 16 R0..R5, second register set
KSP 16 kernel stack pointer
SSP 16 supervisor stack pointer
USP 16 user stack pointer
PSW 16 processor status word
CM 2 current mode, PSW<15:14>
PM 2 previous mode, PSW<13:12>
RS 2 register set, PSW<11>
IPL 3 interrupt priority level, PSW<7:5>
T 1 trace bit, PSW<4>
N 1 negative flag, PSW<3>
Z 1 zero flag, PSW<2>
V 1 overflow flag, PSW<1>
C 1 carry flag, PSW<0>
SR 16 front panel switches
DR 16 front panel display
MEMERR 16 memory error register
CCR 16 cache control register
MAINT 16 maintenance register
HITMISS 16 hit/miss register
CPUERR 16 CPU error register
PIRQ 16 programmed interrupt requests
FAC0H..FAC5H 32 FAC0..FAC5, high 32 bits
FAC0L..FAC5L 32 FAC0..FAC5, low 32 bits
FPS 16 floating point status
FEA 16 floating exception address
FEC 4 floating exception code
MMR0..3 16 memory management registers 0..3
{K/S/U}{I/D}{PAR/PDR}{0..7}
16 memory management registers
UBMAP[0:63] 16 Unibus map registers
INT 32 interrupt pending flags
TRAP 18 trap pending flags
WAIT 0 wait state flag
WAIT_ENABLE 0 wait state enable flag
STOP_TRAPS 18 stop on trap flags
STOP_VECA 1 stop on read abort in trap or interrupt
STOP_SPA 1 stop on stack push abort in trap or interrupt
OLDPC 16 PC prior to last JMP, JMS, or interrupt
WRU 8 interrupt character
2.2 Programmed I/O Devices
2.2.1 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.2.2 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 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.2.3 DL11 Terminal Input (TTI)
The terminal input (TTI) polls the console keyboard for input. It
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 number of characters input
TIME 24 keyboard polling interval
2.2.4 DL11 Terminal Output (TTO)
The terminal output (TTO) writes to the simulator console window. It
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 number of characters input
TIME 24 time from I/O initiation to interrupt
2.2.5 LP11 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The line printer 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 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 paper
OS I/O error x report error and stop
2.2.6 Line-Time Clock (CLK)
The clock (CLK) implements these registers:
name size comments
CSR 16 control/status register
INT 1 interrupt pending flag
DONE 1 device done flag (CSR<7>)
IE 1 interrupt enable flag (CSR<6>)
TIME 24 clock frequency
TPS 8 ticks per second (60 or 50)
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.7 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.3 RK11/RK05 Cartridge Disk (RK)
RK11 options include the ability to make units write enabled or write locked:
SET RKn LOCKED set unit n write locked
SET RKn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration. The RK11 supports
the BOOT command.
The RK11 implements these registers:
name size comments
RKCS 16 control/status
RKDA 16 disk address
RKBA 16 memory address
RKWC 16 word count
RKDS 16 drive status
RKER 16 error status
INTQ 9 interrupt queue
DRVN 3 number of last selected drive
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>)
INT 1 interrupt pending flag
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.4 RX11/RX01 Floppy Disk (RX)
RX11 options include the ability to make units write enabled or write locked:
SET RXn LOCKED set unit n write locked
SET RXn ENABLED set unit n write enabled
The RX11 supports the BOOT command.
The RX11 implements these registers:
name size comments
RXCS 12 status
RXDB 8 data buffer
RXES 8 error status
RXERR 8 error code
RXTA 8 current track
RXSA 8 current sector
STAPTR 3 controller state
BUFPTR 3 buffer pointer
INT 1 interrupt pending flag
ERR 1 error flag (CSR<15>)
TR 1 transfer ready flag (CSR<7>)
IE 1 interrupt enable flag (CSR<6>)
DONE 1 device done flag (CSR<5>)
CTIME 24 command completion time
STIME 24 seek time, per track
XTIME 24 transfer ready delay
STOP_IOE 1 stop on I/O error
SBUF[0:127] 8 sector buffer array
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
RX01 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.5 RL11(V12)/RL01,RL02 Cartridge Disk (RL)
RL11 options include the ability to set units write enabled or write locked,
to set the drive size to RL01, RL02, or autosize, and to write a DEC standard
044 compliant bad block table on the last track:
SET RLn LOCKED set unit n write locked
SET RLn ENABLED set unit n write enabled
SET RLn RL01 set size to RL01
SET RLn RL02 set size to RL02
SET RLn AUTOSIZE set size based on file size at attach
SET RLn BADBLOCK write bad block table on last track
The size options can be used only when a unit is not attached to a file. The
bad block option can be used only when a unit is attached to a file. Units
can also be REMOVEd or ADDed to the configuration. The RL11 supports the
BOOT command.
The RL11 implements these registers:
name size comments
RLCS 16 control/status
RLDA 16 disk address
RLBA 16 memory address
RLBAE 6 memory address extension (RLV12)
RLMP..RLMP2 16 multipurpose register queue
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>)
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.6 RM02/03/05/80, RP04/05/06/07 Disk Pack Drives (RP)
The RP controller implements a "Massbus style" 22b 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, and to write
a DEC standard 044 compliant bad block table on the last track:
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
SET RPn BADBLOCK write bad block table on last track
The type options can be used only when a unit is not attached to a file. The
bad block option can be used only when a unit is attached to a file. Units
can also be REMOVEd or ADDed to the configuration. The RP controller supports
the BOOT command.
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
RPBAE 6 bus address extension
RPCS3 16 control/status 3
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.7 RQDX3 MSCP Disk Controller (RQ)
The RQ controller simulates the RQDX3 MSCP disk controller. RQ options
include the ability to set units write enabled or write locked, and to
set the drive type to one of eleven disk types:
SET RQn LOCKED set unit n write locked
SET RQn ENABLED set unit n write enabled
SET RQn RX50 set type to RX50
SET RQn RX33 set type to RX33
SET RQn RD51 set type to RD51
SET RQn RD52 set type to RD52
SET RQn RD53 set type to RD53
SET RQn RD54 set type to RD54
SET RQn RD31 set type to RD31
SET RQn RA82 set type to RA82
SET RQn RA72 set type to RA72
SET RQn RA90 set type to RA90
SET RQn RA92 set type to RA92
The type options can be used only when a unit is not attached to a file.
Units can also be REMOVEd or ADDed to the configuration. The RQ controller
supports the BOOT command.
The RQ controller implements the following special SHOW commands:
SHOW RQ RINGS show command and response rings
SHOW RQ FREEQ show packet free queue
SHOW RQ RESPQ show packet response queue
SHOW RQ UNITQ show unit queues
SHOW RQ ALL show all ring and queue state
SHOW RQn UNITQ show unit queues for unit n
The RQ controller implements these registers:
name size comments
SA 16 status/address register
S1DAT 16 step 1 init host data
CQBA 22 command queue base address
CQLNT 8 command queue length
CQIDX 8 command queue index
RQBA 22 request queue base address
RQLNT 8 request queue length
RQIDX 8 request queue index
FREE 5 head of free packet list
RESP 5 head of response packet list
PBSY 5 number of busy packets
CFLGS 16 controller flags
CSTA 4 controller state
PERR 9 port error number
CRED 5 host credits
HAT 16 host available timer
HTMO 17 host timeout value
CPKT[0:3] 5 current packet, units 0-3
PKTQ[0:3] 5 packet queue, units 0-3
UFLG[0:3] 16 unit flags, units 0-3
INT 1 interrupt request
QTIME 24 response time for 'immediate' packets
XTIME 24 response time for data transfers
PKTS[33*32] 16 packet buffers, 33W each,
32 entries
Error handling is as follows:
error processed as
not attached disk not ready
end of file assume rest of disk is zero
OS I/O error report error and stop
2.8 TC11/TU56 DECtape (DT)
DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0.
DECtape options include the ability to make units write enabled or write
locked.
SET DTn LOCKED set unit n write locked
SET DTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration. The TC11 supports
the BOOT command.
The TC11 supports both PDP-8 format and PDP-9/11/15 format DECtape images.
ATTACH tries to determine the tape format from the DECtape image; the user
can force a particular format with switches:
-f foreign (PDP-8) format
-n native (PDP-9/11/15) format
The DECtape controller is a data-only simulator; the timing and mark
track, and block header and trailer, are not stored. Thus, the WRITE
TIMING AND MARK TRACK function is not supported; the READ ALL function
always returns the hardware standard block header and trailer; and the
WRITE ALL function dumps non-data words into the bit bucket.
The DECtape controller implements these registers:
name size comments
TCST 16 status register
TCCM 16 command register
TCWC 16 word count register
TCBA 16 bus address register
TCDT 16 data register
INT 1 interrupt pending flag
ERR 1 error flag
DONE 1 done flag
IE 1 interrupt enable flag
CTIME 31 time to complete transport stop
LTIME 31 time between lines
ACTIME 31 time to accelerate to full speed
DCTIME 31 time to decelerate to a full stop
SUBSTATE 2 read/write command substate
POS[0:7] 31 position, in lines, units 0-7
STATT[0-7] 31 unit state, units 0-7
It is critically important to maintain certain timing relationships
among the DECtape parameters, or the DECtape simulator will fail to
operate correctly.
- LTIME must be at least 6
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
2.9 TM11 Magnetic Tape (TM)
TM options include the ability to make units write enabled or write locked.
SET TMn LOCKED set unit n write locked
SET TMn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
The TM11 supports the BOOT command. The bootstrap supports both original
and DEC standard boot formats. Originally, a tape bootstrap read and
executed the first record on tape. To allow for ANSI labels, the DEC
standard bootstrap skipped the first record and read and executed the second.
The DEC standard is the default; to bootstrap an original format tape, use
the -o switch.
The magnetic tape controller implements these registers:
name size comments
MTS 16 status
MTC 16 command
MTCMA 16 memory address
MTBRC 16 byte/record count
INT 1 interrupt pending flag
ERR 1 error 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.10 TS11/TSV05 Magnetic Tape (TS)
The TS actually implements the TSV05, with 22-bit addressing, but will
work with TS11 drivers. TS options include the ability to make the unit
write enabled or write locked.
SET TS LOCKED set unit write locked
SET TS ENABLED set unit write enabled
The TS11 supports the BOOT command. The bootstrap supports only DEC
standard boot formats. To allow for ANSI labels, the DEC standard bootstrap
skipped the first record and read and executed the second.
The magnetic tape controller implements these registers:
name size comments
TSSR 16 status register
TSBA 16 bus address register
TSDBX 16 data buffer extension register
CHDR 16 command packet header
CADL 16 command packet low address or count
CADH 16 command packet high address
CLNT 16 command packet length
MHDR 16 message packet header
MRFC 16 message packet residual frame count
MXS0 16 message packet extended status 0
MXS1 16 message packet extended status 1
MXS2 16 message packet extended status 2
MXS3 16 message packet extended status 3
MXS4 16 message packet extended status 4
WADL 16 write char packet low address
WADH 16 write char packet high address
WLNT 16 write char packet length
WOPT 16 write char packet options
WXOPT 16 write char packet extended options
ATTN 1 attention message pending
BOOT 1 boot request pending
OWNC 1 if set, tape owns command buffer
OWNM 1 if set, tape owns message buffer
TIME 24 delay
POS 31 position
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 fatal tape error
2.11 Symbolic Display and Input
The PDP-11 simulator implements symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as two character ASCII string
-m display instruction mnemonics
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c two character ASCII string
alphabetic instruction mnemonic
numeric octal number
Instruction input uses standard PDP-11 assembler syntax. There are sixteen
instruction classes:
class operands examples comments
no operands none HALT, RESET
3b literal literal, 0 - 7 SPL
6b literal literal, 0 - 077 MARK
8b literal literal, 0 - 0377 EMT, TRAP
register register RTS
sop specifier SWAB, CLR, ASL
reg-sop register, specifier JSR, XOR, MUL
fop flt specifier ABSf, NEGf
ac-fop flt reg, flt specifier LDf, MULf
ac-sop flt reg, specifier LDEXP, STEXP
ac-moded sop flt reg, specifier LDCif, STCfi
dop specifier, specifier MOV, ADD, BIC
cond branch address BR, BCC, BNE
sob register, address SOB
cc clear cc clear instructions CLC, CLV, CLZ, CLN combinable
cc set cc set instructions SEC, SEV, SEZ, SEN combinable
For floating point opcodes, F and D variants, and I and L variants, may be
specified regardless of the state of FPS.
The syntax for specifiers is as follows:
syntax specifier displacement comments
Rn 0n -
Fn 0n - only in flt reg classes
(Rn) 1n -
@(Rn) 7n 0 equivalent to @0(Rn)
(Rn)+ 2n -
@(Rn)+ 3n -
-(Rn) 4n -
@-(Rn) 5n -
{+/-}d(Rn) 6n {+/-}d
@{+/-}d(Rn) 7n {+/-}d
#n 27 n
@#n 37 n
.+/-n 67 +/-n - 4
@.+/-n 77 +/-n - 4
{+/-}n 67 {+/-}n - PC - 4 if on disk, 37 and n
@{+/-}n 77 {+/-}n - PC - 4 if on disk, invalid

View file

@ -24,7 +24,19 @@
in this Software without prior written authorization from Robert M Supnik.
dz DZ11 terminal multiplexor
09-Nov-01 RMS Added VAX support
*/
#if defined (USE_INT64)
#define VM_VAX 1
#include "vax_defs.h"
#define DZ_RDX 16
#else
#define VM_PDP11 1
#include "pdp11_defs.h"
#define DZ_RDX 8
#endif
#include "dec_dz.h"

361
PDP11/pdp11_io.c Normal file
View file

@ -0,0 +1,361 @@
/* pdp11_io.c: PDP-11 I/O 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.
11-Dec-01 RMS Moved interrupt debug code
08-Nov-01 RMS Cloned from cpu sources
*/
#include "pdp11_defs.h"
extern uint16 *M;
extern int32 int_req[IPL_HLVL];
extern int32 ub_map[UBM_LNT_LW];
extern UNIT cpu_unit;
extern int32 cpu_bme, cpu_ubm;
extern int32 trap_req, ipl;
extern int32 cpu_log;
extern FILE *sim_log;
int32 calc_ints (int32 nipl, int32 trq);
extern t_stat CPU_rd (int32 *data, int32 addr, int32 access);
extern t_stat CPU_wr (int32 data, int32 addr, int32 access);
extern t_stat APR_rd (int32 *data, int32 addr, int32 access);
extern t_stat APR_wr (int32 data, int32 addr, int32 access);
extern t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access);
extern t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access);
extern t_stat MMR3_rd (int32 *data, int32 addr, int32 access);
extern t_stat MMR3_wr (int32 data, int32 addr, int32 access);
extern t_stat ubm_rd (int32 *data, int32 addr, int32 access);
extern t_stat ubm_wr (int32 data, int32 addr, int32 access);
extern t_stat std_rd (int32 *data, int32 addr, int32 access);
extern t_stat std_wr (int32 data, int32 addr, int32 access);
extern t_stat lpt_rd (int32 *data, int32 addr, int32 access);
extern t_stat lpt_wr (int32 data, int32 addr, int32 access);
extern t_stat dz_rd (int32 *data, int32 addr, int32 access);
extern t_stat dz_wr (int32 data, int32 addr, int32 access);
extern t_stat rk_rd (int32 *data, int32 addr, int32 access);
extern t_stat rk_wr (int32 data, int32 addr, int32 access);
extern int32 rk_inta (void);
extern int32 rk_enb;
/* extern t_stat rk6_rd (int32 *data, int32 addr, int32 access);
extern t_stat rk6_wr (int32 data, int32 addr, int32 access);
extern int32 rk6_inta (void);
extern int32 rk6_enb; */
extern t_stat rl_rd (int32 *data, int32 addr, int32 access);
extern t_stat rl_wr (int32 data, int32 addr, int32 access);
extern int32 rl_enb;
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 int32 rp_enb;
extern t_stat rq_rd (int32 *data, int32 addr, int32 access);
extern t_stat rq_wr (int32 data, int32 addr, int32 access);
extern int32 rq_inta (void);
extern int32 rq_enb;
extern t_stat rx_rd (int32 *data, int32 addr, int32 access);
extern t_stat rx_wr (int32 data, int32 addr, int32 access);
extern int32 rx_enb;
extern t_stat dt_rd (int32 *data, int32 addr, int32 access);
extern t_stat dt_wr (int32 data, int32 addr, int32 access);
extern int32 dt_enb;
extern t_stat tm_rd (int32 *data, int32 addr, int32 access);
extern t_stat tm_wr (int32 data, int32 addr, int32 access);
extern int32 tm_enb;
extern t_stat ts_rd (int32 *data, int32 addr, int32 access);
extern t_stat ts_wr (int32 data, int32 addr, int32 access);
extern int32 ts_enb;
/* I/O data 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 */
struct iolink iotable[] = {
{ IOBA_CPU, IOBA_CPU+IOLN_CPU, NULL, &CPU_rd, &CPU_wr },
{ IOBA_STD, IOBA_STD+IOLN_STD, NULL, &std_rd, &std_wr },
{ IOBA_LPT, IOBA_LPT+IOLN_LPT, NULL, &lpt_rd, &lpt_wr },
{ IOBA_DZ, IOBA_DZ +IOLN_DZ, NULL, &dz_rd, &dz_wr },
{ IOBA_RK, IOBA_RK +IOLN_RK, &rk_enb, &rk_rd, &rk_wr },
{ IOBA_RL, IOBA_RL +IOLN_RL, &rl_enb, &rl_rd, &rl_wr },
{ IOBA_RP, IOBA_RP +IOLN_RP, &rp_enb, &rp_rd, &rp_wr },
{ IOBA_RQ, IOBA_RQ +IOLN_RQ, &rq_enb, &rq_rd, &rq_wr },
{ IOBA_RX, IOBA_RX +IOLN_RX, &rx_enb, &rx_rd, &rx_wr },
{ IOBA_TC, IOBA_TC +IOLN_TC, &dt_enb, &dt_rd, &dt_wr },
{ IOBA_TM, IOBA_TM +IOLN_TM, &tm_enb, &tm_rd, &tm_wr },
{ IOBA_TS, IOBA_TS +IOLN_TS, &ts_enb, &ts_rd, &ts_wr },
/* { IOBA_RK6, IOBA_RK6+IOLN_RK6, &rk6_enb, &rk6_rd, &rk6_wr }, */
{ IOBA_APR, IOBA_APR+IOLN_APR, NULL, &APR_rd, &APR_wr },
{ IOBA_APR1, IOBA_APR1+IOLN_APR1, NULL, &APR_rd, &APR_wr },
{ IOBA_SRMM, IOBA_SRMM+IOLN_SRMM, NULL, &SR_MMR012_rd, &SR_MMR012_wr },
{ IOBA_MMR3, IOBA_MMR3+IOLN_MMR3, NULL, &MMR3_rd, &MMR3_wr },
{ IOBA_UBM, IOBA_UBM+IOLN_UBM, NULL, &ubm_rd, &ubm_wr },
{ 0, 0, NULL, NULL, NULL } };
int32 int_vec[IPL_HLVL][32] = { /* int req to vector */
{ 0 }, /* IPL 0 */
{ VEC_PIRQ }, /* IPL 1 */
{ VEC_PIRQ }, /* IPL 2 */
{ VEC_PIRQ }, /* IPL 3 */
{ VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, /* IPL 4 */
VEC_LPT, VEC_PIRQ },
{ VEC_RK, VEC_RL, VEC_RX, VEC_TM, /* IPL 5 */
VEC_RP, VEC_TS, VEC_RK6, VEC_RQ,
VEC_DZRX, VEC_DZTX, VEC_PIRQ },
{ VEC_CLK, VEC_DTA, VEC_PIRQ }, /* IPL 6 */
{ VEC_PIRQ } }; /* IPL 7 */
int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */
{ NULL }, /* IPL 0 */
{ NULL }, /* IPL 1 */
{ NULL }, /* IPL 2 */
{ NULL }, /* IPL 3 */
{ NULL }, /* IPL 4 */
{ &rk_inta, NULL, NULL, NULL, /* IPL 5 */
&rp_inta, NULL, NULL, &rq_inta },
{ NULL }, /* IPL 6 */
{ NULL } }; /* IPL 7 */
/* I/O page lookup and linkage routines
Inputs:
*data = pointer to data to read, if READ
data = data to store, if WRITE or WRITEB
pa = address
access = READ, WRITE, or WRITEB
Outputs:
status = SCPE_OK or SCPE_NXM
*/
t_stat iopageR (int32 *data, int32 pa, int32 access)
{
t_stat stat;
struct iolink *p;
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa < p -> high) &&
((p -> enb == NULL) || *p -> enb)) {
stat = p -> read (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
return SCPE_NXM;
}
t_stat iopageW (int32 data, int32 pa, int32 access)
{
t_stat stat;
struct iolink *p;
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa < p -> high) &&
((p -> enb == NULL) || *p -> enb)) {
stat = p -> write (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
return SCPE_NXM;
}
/* Calculate interrupt outstanding */
int32 calc_ints (int32 nipl, int32 trq)
{
int32 i;
for (i = IPL_HLVL - 1; i > nipl; i--) {
if (int_req[i]) return (trq | TRAP_INT); }
return (trq & ~TRAP_INT);
}
/* Find vector for highest priority interrupt */
int32 get_vector (int32 nipl)
{
int32 i, j, t, vec;
for (i = IPL_HLVL - 1; i > nipl; i--) { /* loop thru lvls */
t = int_req[i]; /* get level */
for (j = 0; t && (j < 32); j++) { /* srch level */
if ((t >> j) & 1) { /* irq found? */
int_req[i] = int_req[i] & ~(1u << j); /* clr irq */
if (int_ack[i][j]) vec = int_ack[i][j]();
else vec = int_vec[i][j];
if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log,
">>INT: lvl=%d, flag=%d, vec=%o\n", i, j, vec);
return vec; /* return vector */
} /* end if t */
} /* end for j */
} /* end for i */
return 0;
}
/* Read and write Unibus map registers
In any even/odd pair
even = low 16b, bit <0> clear
odd = high 6b
The Unibus map is stored as an array of longwords
*/
t_stat ubm_rd (int32 *data, int32 addr, int32 access)
{
if (cpu_ubm) {
int32 pg = (addr >> 2) & UBM_M_PN;
*data = (addr & 2)? ((ub_map[pg] >> 16) & 077):
(ub_map[pg] & 0177776);
return SCPE_OK; }
return SCPE_NXM;
}
t_stat ubm_wr (int32 data, int32 addr, int32 access)
{
if (cpu_ubm) {
int32 sc, pg = (addr >> 2) & UBM_M_PN;
if (access == WRITEB) {
sc = (addr & 3) << 3;
ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) |
((data & 0377) << sc); }
else { sc = (addr & 2) << 3;
ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) |
((data & 0177777) << sc); }
ub_map[pg] = ub_map[pg] & 017777776;
return SCPE_OK; }
return SCPE_NXM;
}
/* Mapped memory access routines for DMA devices */
/* Map I/O address to memory address */
t_bool Map_Addr (t_addr ba, t_addr *ma)
{
if (cpu_bme) { /* bus map on? */
int32 pg = UBM_GETPN (ba); /* map entry */
int32 off = UBM_GETOFF (ba); /* offset */
if (pg != UBM_M_PN) /* last page? */
*ma = (ub_map[pg] + off) & PAMASK; /* no, use map */
else *ma = (IOPAGEBASE + off) & PAMASK; } /* yes, use fixed */
else *ma = ba; /* else physical */
return TRUE;
}
/* I/O buffer routines, aligned access
Map_ReadB - fetch byte buffer from memory
Map_ReadW - fetch word buffer from memory
Map_WriteB - store byte buffer into memory
Map_WriteW - store word buffer into memory
*/
int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub)
{
t_addr alim, lim, ma;
lim = ba + bc;
if (ub && cpu_bme) { /* UB, map on? */
for ( ; ba < lim; ba++) { /* by bytes */
Map_Addr (ba, &ma); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
if (ma & 1) *buf++ = (M[ma >> 1] >> 8) & 0377; /* get byte */
else *buf++ = M[ma >> 1] & 0377; }
return 0; }
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba++) { /* by bytes */
if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */
else *buf++ = M[ba >> 1] & 0377; }
return (lim - alim); }
}
int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub)
{
t_addr alim, lim, ma;
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
if (ub && cpu_bme) { /* UB, map on? */
for (; ba < lim; ba = ba + 2) { /* by words */
Map_Addr (ba, &ma); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
*buf++ = M[ma >> 1]; }
return 0; }
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba = ba + 2) { /* by words */
*buf++ = M[ba >> 1]; }
return (lim - alim); }
}
int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub)
{
t_addr alim, lim, ma;
lim = ba + bc;
if (ub && cpu_bme) { /* UB, map on? */
for ( ; ba < lim; ba++) { /* by bytes */
Map_Addr (ba, &ma); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
if (ma & 1) M[ma >> 1] = (M[ma >> 1] & 0377) |
((uint16) *buf++ << 8);
else M[ma >> 1] = (M[ma >> 1] & ~0377) | *buf++; }
return 0; }
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba++) { /* by bytes */
if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) |
((uint16) *buf++ << 8);
else M[ba >> 1] = (M[ba >> 1] & ~0377) | *buf++; }
return (lim - alim); }
}
int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub)
{
t_addr alim, lim, ma;
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
if (ub && cpu_bme) { /* UB, map on? */
for (; ba < lim; ba = ba + 2) { /* by words */
Map_Addr (ba, &ma); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
M[ma >> 1] = *buf++; } /* store word */
return 0; }
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba = ba + 2) { /* by words */
M[ba >> 1] = *buf++; }
return (lim - alim); }
}

View file

@ -25,11 +25,21 @@
lpt LP11 line printer
09-Nov-01 RMS Added VAX support
07-Sep-01 RMS Revised interrupt mechanism
30-Oct-00 RMS Standardized register naming
*/
#if defined (USE_INT64)
#define VM_VAX 1
#include "vax_defs.h"
#define LPT_DRDX 16
#else
#define VM_PDP11 1
#include "pdp11_defs.h"
#define LPT_DRDX 8
#endif
#define LPTCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* implemented */
#define LPTCSR_RW (CSR_IE) /* read/write */
@ -53,8 +63,8 @@ UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ ORDATA (CSR, lpt_csr, 16) },
{ GRDATA (BUF, lpt_unit.buf, LPT_DRDX, 8, 0) },
{ GRDATA (CSR, lpt_csr, LPT_DRDX, 16, 0) },
{ FLDATA (INT, IREQ (LPT), INT_V_LPT) },
{ FLDATA (ERR, lpt_csr, CSR_V_ERR) },
{ FLDATA (DONE, lpt_csr, CSR_V_DONE) },
@ -66,7 +76,7 @@ REG lpt_reg[] = {
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 8,
1, 10, 31, 1, LPT_DRDX, 8,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, &lpt_detach };

View file

@ -25,6 +25,9 @@
rk RK11/RK05 cartridge disk
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Converted FLG to array
09-Nov-01 RMS Added bus map support
07-Sep-01 RMS Revised device disable and interrupt mechanisms
26-Apr-01 RMS Added device enable/disable support
25-Mar-01 RMS Fixed block fill calculation
@ -62,9 +65,9 @@
#define RK_NUMDR 8 /* drives/controller */
#define RK_M_NUMDR 07
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */
#define RK_MAXMEM ((int32) (MEMSIZE / sizeof (int16))) /* words/memory */
#define RK_CTLI 1 /* controller int */
#define RK_SCPI(x) (2u << (x)) /* drive int */
#define RK_MAXFR (1 << 16) /* max transfer */
/* Flags in the unit flags word */
@ -73,6 +76,7 @@
#define UNIT_W_UF 3 /* user flags width */
#define UNIT_HWLK (1u << UNIT_V_HWLK)
#define UNIT_SWLK (1u << UNIT_V_SWLK)
#define UNIT_WPRT (UNIT_HWLK|UNIT_SWLK|UNIT_RO) /* write prot */
/* Parameters in the unit descriptor */
@ -163,7 +167,7 @@
extern uint16 *M; /* memory */
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
uint16 *rkxb = NULL; /* xfer buffer */
int32 rkcs = 0; /* control/status */
int32 rkds = 0; /* drive status */
int32 rkba = 0; /* memory address */
@ -192,14 +196,22 @@ t_stat rk_boot (int32 unitno);
*/
UNIT rk_unit[] = {
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) } };
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) } };
REG rk_reg[] = {
{ ORDATA (RKCS, rkcs, 16) },
@ -216,32 +228,15 @@ REG rk_reg[] = {
{ FLDATA (IE, rkcs, CSR_V_IE) },
{ DRDATA (STIME, rk_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rk_rwait, 24), PV_LEFT },
{ GRDATA (FLG0, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, rk_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, rk_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, rk_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, rk_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, rk_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, rk_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, rk_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (FLG, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
RK_NUMDR, REG_HRO) },
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
{ FLDATA (*DEVENB, rk_enb, 0), REG_HRO },
{ NULL } };
MTAB rk_mod[] = {
{ (UNIT_HWLK+UNIT_SWLK), 0, "write enabled", "ENABLED", NULL },
{ (UNIT_HWLK+UNIT_SWLK), UNIT_HWLK, "write locked", "LOCKED", NULL },
{ (UNIT_HWLK+UNIT_SWLK), UNIT_SWLK, "write locked", NULL, NULL },
{ (UNIT_HWLK+UNIT_SWLK), (UNIT_HWLK+UNIT_SWLK), "write locked",
NULL, NULL },
{ UNIT_HWLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
{ 0 } };
DEVICE rk_dev = {
@ -275,7 +270,7 @@ case 0: /* RKDS: read only */
uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */
if (uptr -> flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */
if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS; /* idle? */
if (uptr -> flags & (UNIT_HWLK + UNIT_SWLK)) rkds = rkds | RKDS_WLK;
if (uptr -> flags & UNIT_WPRT) rkds = rkds | RKDS_WLK;
if (GET_SECT (rkda) == (rkds & RKDS_SC)) rkds = rkds | RKDS_ON_SC;
*data = rkds;
return SCPE_OK;
@ -373,7 +368,7 @@ if (((uptr -> flags & UNIT_ATT) == 0) || sim_is_active (uptr)) {
if (rkcs & (RKCS_INH + RKCS_FMT)) { /* format? */
rk_set_done (RKER_PGE);
return; }
if ((func == RKCS_WRITE) && (uptr -> flags & (UNIT_HWLK + UNIT_SWLK))) {
if ((func == RKCS_WRITE) && (uptr -> flags & UNIT_WPRT)) {
rk_set_done (RKER_WLK); /* write and locked? */
return; }
if (func == RKCS_WLK) { /* write lock? */
@ -413,9 +408,10 @@ return;
t_stat rk_svc (UNIT *uptr)
{
int32 comp, drv, err, awc, twc, wc;
int32 pa, da, remc, track, sect;
static uint16 fill[RK_NUMWD] = { 0 };
int32 i, drv, err, awc, wc, t;
int32 da, track, sect;
t_addr ma;
uint16 comp;
drv = uptr - rk_dev.units; /* get drv number */
if (uptr -> FUNC == RKCS_SEEK) { /* seek */
@ -424,54 +420,56 @@ if (uptr -> FUNC == RKCS_SEEK) { /* seek */
rkintq = rkintq | RK_SCPI (drv); /* queue request */
if (rkcs & CSR_DONE) SET_INT (RK); }
else { rkintq = 0; /* clear queue */
CLR_INT (RK); } /* clear interrupt */
CLR_INT (RK); } /* clear interrupt */
return SCPE_OK; }
if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */
rk_set_done (RKER_DRE);
return IORETURN (rk_stopioe, SCPE_UNATT); }
pa = (((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba) >> 1;
ma = ((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba; /* get mem addr */
da = GET_DA (rkda) * RK_NUMWD; /* get disk addr */
twc = 0200000 - rkwc; /* get true wc */
if ((pa + twc) > RK_MAXMEM) { /* mem overrun? */
rker = rker | RKER_NXM;
wc = (RK_MAXMEM - pa); }
else wc = twc;
if (wc < 0) { /* abort transfer? */
rk_set_done (0);
return SCPE_OK; }
if ((da + twc) > RK_SIZE) { /* disk overrun? */
rker = rker | RKER_OVR;
if (wc > (RK_SIZE - da)) wc = RK_SIZE - da; }
wc = 0200000 - rkwc; /* get wd cnt */
err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET);
if ((uptr -> FUNC == RKCS_READ) && (err == 0)) { /* read? */
awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref);
for ( ; awc < wc; awc++) M[pa + awc] = 0;
err = ferror (uptr -> fileref); }
i = fxread (rkxb, sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */
if (t = Map_WriteW (ma, wc << 1, rkxb, UB)) { /* store buf */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */
} /* end read */
if ((uptr -> FUNC == RKCS_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
if ((err == 0) && (remc = (wc & (RK_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), RK_NUMWD - remc, uptr -> fileref);
err = ferror (uptr -> fileref); } }
if (t = Map_ReadW (ma, wc << 1, rkxb, UB)) { /* get buf */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */
if (wc) { /* any xfer? */
awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */
for (i = wc; i < awc; i++) rkxb[i] = 0; /* end of blk */
fxwrite (rkxb, sizeof (int16), awc, uptr -> fileref);
err = ferror (uptr -> fileref); }
} /* end write */
if ((uptr -> FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */
twc = wc; /* xfer length */
for (wc = 0; (err == 0) && (wc < twc); wc++) {
awc = fxread (&comp, sizeof (int16), 1, uptr -> fileref);
if (awc == 0) comp = 0;
if (comp != M[pa + wc]) {
rker = rker | RKER_WCE;
i = fxread (rkxb, sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */
awc = wc; /* save wc */
for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */
if (Map_ReadW (ma + (wc << 1), 2, &comp, UB)) { /* mem wd */
rker = rker | RKER_NXM; /* NXM? set flg */
break; }
if (comp != rkxb[wc]) { /* match to disk? */
rker = rker | RKER_WCE; /* no, err */
if (rkcs & RKCS_SSE) break; } }
err = ferror (uptr -> fileref); }
} /* end wcheck */
rkwc = (rkwc + wc) & 0177777; /* final word count */
pa = (pa + wc) << 1; /* final byte addr */
rkba = pa & RKBA_IMP; /* lower 16b */
rkcs = (rkcs & ~RKCS_MEX) | ((pa >> (16 - RKCS_V_MEX)) & RKCS_MEX);
ma = ma + (wc << 1); /* final byte addr */
rkba = ma & RKBA_IMP; /* lower 16b */
rkcs = (rkcs & ~RKCS_MEX) | ((ma >> (16 - RKCS_V_MEX)) & RKCS_MEX);
da = da + wc + (RK_NUMWD - 1);
track = (da / RK_NUMWD) / RK_NUMSC;
sect = (da / RK_NUMWD) % RK_NUMSC;
@ -546,6 +544,8 @@ for (i = 0; i < RK_NUMDR; i++) {
sim_cancel (uptr);
uptr -> CYL = uptr -> FUNC = 0;
uptr -> flags = uptr -> flags & ~UNIT_SWLK; }
if (rkxb == NULL) rkxb = calloc (RK_MAXFR, sizeof (unsigned int16));
if (rkxb == NULL) return SCPE_MEM;
return SCPE_OK;
}

View file

@ -1,4 +1,4 @@
/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator
/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator
Copyright (c) 1993-2001, Robert M Supnik
@ -25,6 +25,11 @@
rl RL11(RLV12)/RL01/RL02 cartridge disk
30-Nov-01 MRS Added read only, extended SET/SHOW support
26-Nov-01 RMS Fixed per-drive error handling
24-Nov-01 RMS Converted FLG, CAPAC to arrays
19-Nov-01 RMS Fixed signed/unsigned mismatch in write check
09-Nov-01 RMS Added bus map, VAX support
07-Sep-01 RMS Revised device disable and interrupt mechanisms
20-Aug-01 RMS Added bad block option in attach
17-Jul-01 RMS Fixed warning from VC++ 6.0
@ -42,11 +47,31 @@
The most complicated part of the RL11 controller is the way it does
seeks. Seeking is relative to the current disk address; this requires
keeping accurate track of the current cylinder. The RL01 will not
keeping accurate track of the current cylinder. The RL11 will not
switch heads or cross cylinders during transfers.
The RL11 functions in three environments:
- PDP-11 Q22 systems - the I/O map is one for one, so it's safe to
go through the I/O map
- PDP-11 Unibus 22b systems - the RL11 behaves as an 18b Unibus
peripheral and must go through the I/O map
- VAX Q22 systems - the RL11 must go through the I/O map
*/
#if defined (USE_INT64) /* VAX version */
#include "vax_defs.h"
#define VM_VAX 1
#define RL_RDX 16
#define RL_18B FALSE /* always 22b */
#else /* PDP11 version */
#include "pdp11_defs.h"
#define VM_PDP11 1
#define RL_RDX 8
#define RL_18B (cpu_18b || cpu_ubm)
extern int32 cpu_18b, cpu_ubm;
#endif
/* Constants */
@ -55,46 +80,47 @@
#define RL_NUMSF 2 /* surfaces/cylinder */
#define RL_NUMCY 256 /* cylinders/drive */
#define RL_NUMDR 4 /* drives/controller */
#define RL_MAXFR (1 << 16) /* max transfer */
#define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD) /* words/drive */
#define RL02_SIZE (RL01_SIZE * 2) /* words/drive */
#define RL_MAXMEM ((int) (MEMSIZE / sizeof (int16))) /* words/memory */
/* Flags in the unit flags word */
#define UNIT_V_HWLK (UNIT_V_UF) /* hwre write lock */
#define UNIT_V_WLK (UNIT_V_UF) /* hwre write lock */
#define UNIT_V_RL02 (UNIT_V_UF+1) /* RL01 vs RL02 */
#define UNIT_V_AUTO (UNIT_V_UF+2) /* autosize enable */
#define UNIT_W_UF 4 /* saved flags width */
#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */
#define UNIT_DUMMY (1 << UNIT_V_DUMMY)
#define UNIT_HWLK (1u << UNIT_V_HWLK)
#define UNIT_WLK (1u << UNIT_V_WLK)
#define UNIT_RL02 (1u << UNIT_V_RL02)
#define UNIT_AUTO (1u << UNIT_V_AUTO)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protected */
/* Parameters in the unit descriptor */
#define TRK u3 /* current track */
#define STAT u4 /* status */
/* RLDS */
/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */
#define RLDS_LOAD 0 /* no cartridge */
#define RLDS_LOCK 5 /* lock on */
#define RLDS_BHO 0000010 /* brushes home */
#define RLDS_HDO 0000020 /* heads out */
#define RLDS_CVO 0000040 /* cover open */
#define RLDS_HD 0000100 /* head select */
#define RLDS_DSE 0000400 /* drive select err */
#define RLDS_BHO 0000010 /* brushes home NI */
#define RLDS_HDO 0000020 /* heads out NI */
#define RLDS_CVO 0000040 /* cover open NI */
#define RLDS_HD 0000100 /* head select ^ */
#define RLDS_RL02 0000200 /* RL02 */
#define RLDS_VCK 0001000 /* volume check */
#define RLDS_WGE 0002000 /* write gate err */
#define RLDS_SPE 0004000 /* spin err */
#define RLDS_STO 0010000 /* seek time out */
#define RLDS_WLK 0020000 /* write locked */
#define RLDS_HCE 0040000 /* head current err */
#define RLDS_WDE 0100000 /* write data err */
#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* attached status */
#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unattached status */
#define RLDS_DSE 0000400 /* drv sel err NI */
#define RLDS_VCK 0001000 /* vol check * */
#define RLDS_WGE 0002000 /* wr gate err * */
#define RLDS_SPE 0004000 /* spin err * */
#define RLDS_STO 0010000 /* seek time out NI */
#define RLDS_WLK 0020000 /* wr locked */
#define RLDS_HCE 0040000 /* hd curr err NI */
#define RLDS_WDE 0100000 /* wr data err NI */
#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */
#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */
#define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
RLDS_VCK+RLDS_DSE) /* errors bits */
@ -156,9 +182,8 @@
#define RLBAE_IMP 0000077 /* implemented */
extern uint16 *M; /* memory */
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
uint16 *rlxb = NULL; /* xfer buffer */
int32 rlcs = 0; /* control/status */
int32 rlba = 0; /* memory address */
int32 rlbae = 0; /* mem addr extension */
@ -173,8 +198,8 @@ t_stat rl_reset (DEVICE *dptr);
void rl_set_done (int32 error);
t_stat rl_boot (int32 unitno);
t_stat rl_attach (UNIT *uptr, char *cptr);
t_stat rl_set_size (UNIT *uptr, int32 value);
t_stat rl_set_bad (UNIT *uptr, int32 value);
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
/* RL11 data structures
@ -186,48 +211,40 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
*/
UNIT rl_unit[] = {
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO,
RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO,
RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO,
RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO,
RL01_SIZE) } };
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) } };
REG rl_reg[] = {
{ ORDATA (RLCS, rlcs, 16) },
{ ORDATA (RLDA, rlda, 16) },
{ ORDATA (RLBA, rlba, 16) },
{ ORDATA (RLBAE, rlbae, 6) },
{ ORDATA (RLMP, rlmp, 16) },
{ ORDATA (RLMP1, rlmp1, 16) },
{ ORDATA (RLMP2, rlmp2, 16) },
{ GRDATA (RLCS, rlcs, RL_RDX, 16, 0) },
{ GRDATA (RLDA, rlda, RL_RDX, 16, 0) },
{ GRDATA (RLBA, rlba, RL_RDX, 16, 0) },
{ GRDATA (RLBAE, rlbae, RL_RDX, 6, 0) },
{ GRDATA (RLMP, rlmp, RL_RDX, 16, 0) },
{ GRDATA (RLMP1, rlmp1, RL_RDX, 16, 0) },
{ GRDATA (RLMP2, rlmp2, RL_RDX, 16, 0) },
{ FLDATA (INT, IREQ (RL), INT_V_RL) },
{ FLDATA (ERR, rlcs, CSR_V_ERR) },
{ FLDATA (DONE, rlcs, CSR_V_DONE) },
{ FLDATA (IE, rlcs, CSR_V_IE) },
{ DRDATA (STIME, rl_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
{ GRDATA (FLG0, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, rl_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, rl_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, rl_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ DRDATA (CAPAC0, rl_unit[0].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC1, rl_unit[1].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC2, rl_unit[2].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC3, rl_unit[3].capac, 32), PV_LEFT + REG_HRO },
{ URDATA (FLG, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
RL_NUMDR, REG_HRO) },
{ URDATA (CAPAC, rl_unit[0].capac, 10, 31, 0,
RL_NUMDR, PV_LEFT + REG_HRO) },
{ FLDATA (STOP_IOE, rl_stopioe, 0) },
{ FLDATA (*DEVENB, rl_enb, 0), REG_HRO },
{ NULL } };
MTAB rl_mod[] = {
{ UNIT_HWLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
{ UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
{ (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
{ (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
@ -241,7 +258,7 @@ MTAB rl_mod[] = {
DEVICE rl_dev = {
"RL", rl_unit, rl_reg, rl_mod,
RL_NUMDR, 8, 24, 1, 8, 16,
RL_NUMDR, RL_RDX, 24, 1, RL_RDX, 16,
NULL, NULL, &rl_reset,
&rl_boot, &rl_attach, NULL };
@ -279,6 +296,7 @@ case 3: /* RLMP */
rlmp1 = rlmp2;
break;
case 4: /* RLBAE */
if (RL_18B) return SCPE_NXM; /* not in RL11 */
*data = rlbae & RLBAE_IMP;
break; } /* end switch */
return SCPE_OK;
@ -348,6 +366,7 @@ case 3: /* RLMP */
rlmp = rlmp1 = rlmp2 = data;
break;
case 4: /* RLBAE */
if (RL_18B) return SCPE_NXM; /* not in RL11 */
if (PA & 1) return SCPE_OK;
rlbae = data & RLBAE_IMP;
rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
@ -366,27 +385,29 @@ return SCPE_OK;
t_stat rl_svc (UNIT *uptr)
{
int32 comp, err, awc, wc, maxwc;
int32 func, pa, da, remc;
static uint16 fill[RL_NUMWD] = { 0 };
int32 err, wc, maxwc, t;
int32 i, func, da, awc;
t_addr ma;
uint16 comp;
func = GET_FUNC (rlcs); /* get function */
if (func == RLCS_GSTA) { /* get status */
if (rlda & RLDA_GS_CLR) uptr -> STAT = uptr -> STAT & ~RLDS_ERR;
rlmp = uptr -> STAT | (uptr -> TRK & RLDS_HD) |
((uptr -> flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
if (rlda & RLDA_GS_CLR) rlmp = rlmp & ~RLDS_ERR;
if (uptr -> flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02;
if (uptr -> flags & UNIT_HWLK) rlmp = rlmp | RLDS_WLK;
uptr -> STAT = rlmp2 = rlmp1 = rlmp;
if (uptr -> flags & UNIT_WPRT) rlmp = rlmp | RLDS_WLK;
rlmp2 = rlmp1 = rlmp;
rl_set_done (0); /* done */
return SCPE_OK; }
if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */
rlcs = rlcs & ~RLCS_DRDY; /* clear drive ready */
uptr -> STAT = uptr -> STAT | RLDS_SPE; /* spin error */
rl_set_done (RLCS_ERR | RLCS_INCMP); /* flag error */
return IORETURN (rl_stopioe, SCPE_UNATT); }
if ((func == RLCS_WRITE) && (uptr -> flags & UNIT_HWLK)) {
if ((func == RLCS_WRITE) && (uptr -> flags & UNIT_WPRT)) {
uptr -> STAT = uptr -> STAT | RLDS_WGE; /* write and locked */
rl_set_done (RLCS_ERR | RLCS_DRE);
return SCPE_OK; }
@ -397,7 +418,7 @@ if (func == RLCS_SEEK) { /* seek? */
if (func == RLCS_RHDR) { /* read header? */
rlmp = (uptr -> TRK & RLDA_TRACK) | GET_SECT (rlda);
rlmp1 = 0;
rlmp1 = rlmp2 = 0;
rl_set_done (0); /* done */
return SCPE_OK; }
@ -406,45 +427,53 @@ if (((func != RLCS_RNOHDR) && ((uptr -> TRK & RLDA_CYL) != (rlda & RLDA_CYL)))
rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */
return SCPE_OK; }
pa = ((rlbae << 16) | rlba) >> 1; /* form phys addr */
ma = (rlbae << 16) | rlba; /* get mem addr */
da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */
wc = 0200000 - rlmp; /* get true wc */
maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */
if (wc > maxwc) wc = maxwc; /* track overrun? */
if ((pa + wc) > RL_MAXMEM) { /* mem overrun? */
rlcs = rlcs | RLCS_ERR | RLCS_NXM;
wc = (RL_MAXMEM - pa); }
if (wc < 0) { /* abort transfer? */
rl_set_done (RLCS_INCMP);
return SCPE_OK; }
err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET);
if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */
awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref);
for ( ; awc < wc; awc++) M[pa + awc] = 0;
err = ferror (uptr -> fileref); }
i = fxread (rlxb, sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */
if (t = Map_WriteW (ma, wc << 1, rlxb, UB)) { /* store buffer */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adjust wc */
} /* end read */
if ((func == RLCS_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
if ((err == 0) && (remc = (wc & (RL_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), RL_NUMWD - remc, uptr -> fileref);
err = ferror (uptr -> fileref); } }
if (t = Map_ReadW (ma, wc << 1, rlxb, UB)) { /* fetch buffer */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adj xfer lnt */
if (wc) { /* any xfer? */
awc = (wc + (RL_NUMWD - 1)) & ~(RL_NUMWD - 1); /* clr to */
for (i = wc; i < awc; i++) rlxb[i] = 0; /* end of blk */
fxwrite (rlxb, sizeof (int16), awc, uptr -> fileref);
err = ferror (uptr -> fileref); }
} /* end write */
if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */
remc = wc; /* xfer length */
for (wc = 0; (err == 0) && (wc < remc); wc++) {
awc = fxread (&comp, sizeof (int16), 1, uptr -> fileref);
if (awc == 0) comp = 0;
if (comp != M[pa + wc]) rlcs = rlcs | RLCS_ERR | RLCS_CRC; }
err = ferror (uptr -> fileref); }
i = fxread (rlxb, sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */
awc = wc; /* save wc */
for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */
if (Map_ReadW (ma + (wc << 1), 2, &comp, UB)) { /* mem wd */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
break; }
if (comp != rlxb[wc]) /* check to buf */
rlcs = rlcs | RLCS_ERR | RLCS_CRC;
} /* end for */
} /* end wcheck */
rlmp = (rlmp + wc) & 0177777; /* final word count */
if (rlmp != 0) rlcs = rlcs | RLCS_ERR | RLCS_INCMP; /* completed? */
pa = (pa + wc) << 1; /* final byte addr */
rlbae = (pa >> 16) & RLBAE_IMP; /* upper 6b */
rlba = pa & RLBA_IMP; /* lower 16b */
ma = ma + (wc << 1); /* final byte addr */
rlbae = (ma >> 16) & RLBAE_IMP; /* upper 6b */
rlba = ma & RLBA_IMP; /* lower 16b */
rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
rlda = rlda + ((wc + (RL_NUMWD - 1)) / RL_NUMWD);
rl_set_done (0);
@ -483,6 +512,8 @@ for (i = 0; i < RL_NUMDR; i++) {
uptr = rl_dev.units + i;
sim_cancel (uptr);
uptr -> STAT = 0; }
if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int16));
if (rlxb == NULL) return SCPE_MEM;
return SCPE_OK;
}
@ -496,9 +527,12 @@ t_stat r;
uptr -> capac = (uptr -> flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
r = attach_unit (uptr, cptr);
if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r;
uptr -> TRK = 0; /* cylinder 0 */
uptr -> STAT = RLDS_VCK; /* new volume */
if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK;
if ((p = ftell (uptr -> fileref)) == 0)
return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD);
if ((p = ftell (uptr -> fileref)) == 0) {
if (uptr -> flags & UNIT_RO) return SCPE_OK;
return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); }
if (p > (RL01_SIZE * sizeof (int16))) {
uptr -> flags = uptr -> flags | UNIT_RL02;
uptr -> capac = RL02_SIZE; }
@ -509,22 +543,24 @@ return SCPE_OK;
/* Set size routine */
t_stat rl_set_size (UNIT *uptr, int32 value)
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
uptr -> capac = (value & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
uptr -> capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
return SCPE_OK;
}
/* Set bad block routine */
t_stat rl_set_bad (UNIT *uptr, int32 value)
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
{
return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD);
}
/* Device bootstrap */
#if defined (VM_PDP11)
#define BOOT_START 02000 /* start */
#define BOOT_UNIT 02006 /* unit number */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32))
@ -574,9 +610,18 @@ t_stat rl_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
extern uint16 *M;
for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE;
saved_PC = BOOT_START;
return SCPE_OK;
}
#else
t_stat rl_boot (int32 unitno)
{
return SCPE_NOFNC;
}
#endif

View file

@ -25,6 +25,9 @@
rp RH/RP/RM moving head disks
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Changed RPDS, RPER, FLG, CAPAC, RPFN to arrays
09-Nov-01 RMS Added bus map, VAX support
23-Oct-01 RMS Fixed bug in error interrupts
15-Oct-01 RMS Added debug logging
05-Oct-01 RMS Rewrote interrupt handling from schematics
@ -66,14 +69,45 @@
level sensitive.
- The DONE interrupt, once set, is not disabled if IE is cleared,
but the SC interrupt is.
The RP/RM functions in four environments:
- PDP-11 Q22 systems - the I/O map is one for one, so it's safe to
go through the I/O map
- PDP-11 Unibus systems with native 22b controllers - see above
- PDP-11 Unibus 22b systems - the RP/RM behaves as an 18b Unibus
peripheral and must go through the I/O map
- VAX Q22 systems - the Rp/RM must go through the I/O map
To distinguish the two Unibus cases, the PDP-11 version of the RP/RM
provides an internal mode flag for RH11 vs RH70
*/
#if defined (USE_INT64) /* VAX version */
#include "vax_defs.h"
#define VM_VAX 1
#define RP_RDX 16
#define RP_WID 32
#define DMASK 0xFFFF
#define RH_18B FALSE /* always 22b */
#else /* PDP11 version */
#include "pdp11_defs.h"
#define VM_PDP11 1
#define RP_RDX 8
#define RP_WID 16 /* off by default */
#define RH_18B (cpu_18b || (cpu_ubm && cpu_rh11))
extern uint16 *M;
extern int32 cpu_18b, cpu_ubm, cpu_rh11;
extern int32 cpu_log;
extern FILE *sim_log;
#endif
#include <math.h>
#define RP_NUMDR 8 /* #drives */
#define RP_NUMWD 256 /* words/sector */
#define RP_MAXFR 65536 /* max transfer */
#define RP_MAXFR (1 << 16) /* max transfer */
#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) drv_tab[d].sect)))
@ -90,6 +124,7 @@
#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */
#define UNIT_DUMMY (1 << UNIT_V_DUMMY)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
/* Parameters in the unit descriptor */
@ -318,7 +353,7 @@ struct drvtyp {
int devtype; /* device type */
};
struct drvtyp drv_tab[] = {
static struct drvtyp drv_tab[] = {
{ RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV },
{ RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV },
{ RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV },
@ -327,11 +362,8 @@ struct drvtyp drv_tab[] = {
{ RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV },
{ 0 } };
extern uint16 *M; /* memory */
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
extern int32 pdp11_log;
extern FILE *sim_log;
uint16 *rpxb = NULL; /* xfer buffer */
int32 rpcs1 = 0; /* control/status 1 */
int32 rpwc = 0; /* word count */
int32 rpba = 0; /* bus address */
@ -360,8 +392,8 @@ int reg_in_drive[32] = {
void update_rpcs (int32 flags, int32 drv);
void rp_go (int32 drv, int32 fnc);
t_stat rp_set_size (UNIT *uptr, int32 value);
t_stat rp_set_bad (UNIT *uptr, int32 value);
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat rp_svc (UNIT *uptr);
t_stat rp_reset (DEVICE *dptr);
t_stat rp_boot (int32 unitno);
@ -379,38 +411,40 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
UNIT rp_unit[] = {
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) } };
UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) } };
REG rp_reg[] = {
{ ORDATA (RPCS1, rpcs1, 16) },
{ ORDATA (RPWC, rpwc, 16) },
{ ORDATA (RPBA, rpba, 16) },
{ ORDATA (RPDA, rpda, 16) },
{ ORDATA (RPCS2, rpcs2, 16) },
{ ORDATA (RPOF, rpof, 16) },
{ ORDATA (RPDC, rpdc, 16) },
{ ORDATA (RPER2, rper2, 16) },
{ ORDATA (RPER3, rper3, 16) },
{ ORDATA (RPEC1, rpec1, 16) },
{ ORDATA (RPEC2, rpec2, 16) },
{ ORDATA (RPMR, rpmr, 16) },
{ ORDATA (RPDB, rpdb, 16) },
{ ORDATA (RPBAE, rpbae, 6) },
{ ORDATA (RPCS3, rpcs3, 16) },
{ GRDATA (RPCS1, rpcs1, RP_RDX, 16, 0) },
{ GRDATA (RPWC, rpwc, RP_RDX, 16, 0) },
{ GRDATA (RPBA, rpba, RP_RDX, 16, 0) },
{ GRDATA (RPDA, rpda, RP_RDX, 16, 0) },
{ GRDATA (RPCS2, rpcs2, RP_RDX, 16, 0) },
{ BRDATA (RPDS, rpds, RP_RDX, 16, RP_NUMDR) },
{ BRDATA (RPER1, rper1, RP_RDX, 16, RP_NUMDR) },
{ GRDATA (RPOF, rpof, RP_RDX, 16, 0) },
{ GRDATA (RPDC, rpdc, RP_RDX, 16, 0) },
{ GRDATA (RPER2, rper2, RP_RDX, 16, 0) },
{ GRDATA (RPER3, rper3, RP_RDX, 16, 0) },
{ GRDATA (RPEC1, rpec1, RP_RDX, 16, 0) },
{ GRDATA (RPEC2, rpec2, RP_RDX, 16, 0) },
{ GRDATA (RPMR, rpmr, RP_RDX, 16, 0) },
{ GRDATA (RPDB, rpdb, RP_RDX, 16, 0) },
{ GRDATA (RPBAE, rpbae, RP_RDX, 6, 0) },
{ GRDATA (RPCS3, rpcs3, RP_RDX, 16, 0) },
{ FLDATA (IFF, rpiff, 0) },
{ FLDATA (INT, IREQ (RP), INT_V_RP) },
{ FLDATA (SC, rpcs1, CSR_V_ERR) },
@ -418,46 +452,12 @@ REG rp_reg[] = {
{ FLDATA (IE, rpcs1, CSR_V_IE) },
{ DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT },
{ DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT },
{ ORDATA (RPDS0, rpds[0], 16) },
{ ORDATA (RPDS1, rpds[1], 16) },
{ ORDATA (RPDS2, rpds[2], 16) },
{ ORDATA (RPDS3, rpds[3], 16) },
{ ORDATA (RPDS4, rpds[4], 16) },
{ ORDATA (RPDS5, rpds[5], 16) },
{ ORDATA (RPDS6, rpds[6], 16) },
{ ORDATA (RPDS7, rpds[7], 16) },
{ ORDATA (RPDE0, rper1[0], 16) },
{ ORDATA (RPDE1, rper1[1], 16) },
{ ORDATA (RPDE2, rper1[2], 16) },
{ ORDATA (RPDE3, rper1[3], 16) },
{ ORDATA (RPDE4, rper1[4], 16) },
{ ORDATA (RPDE5, rper1[5], 16) },
{ ORDATA (RPDE6, rper1[6], 16) },
{ ORDATA (RPDE7, rper1[7], 16) },
{ ORDATA (RPFN0, rp_unit[0].FUNC, 5), REG_HRO },
{ ORDATA (RPFN1, rp_unit[1].FUNC, 5), REG_HRO },
{ ORDATA (RPFN2, rp_unit[2].FUNC, 5), REG_HRO },
{ ORDATA (RPFN3, rp_unit[3].FUNC, 5), REG_HRO },
{ ORDATA (RPFN4, rp_unit[4].FUNC, 5), REG_HRO },
{ ORDATA (RPFN5, rp_unit[5].FUNC, 5), REG_HRO },
{ ORDATA (RPFN6, rp_unit[6].FUNC, 5), REG_HRO },
{ ORDATA (RPFN7, rp_unit[7].FUNC, 5), REG_HRO },
{ GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (FNC, rp_unit[0].FUNC, RP_RDX, 5, 0,
RP_NUMDR, REG_HRO) },
{ URDATA (FLG, rp_unit[0].flags, RP_RDX, UNIT_W_UF, UNIT_V_UF - 1,
RP_NUMDR, REG_HRO) },
{ URDATA (CAPAC, rp_unit[0].capac, 10, 31, 0,
RP_NUMDR, PV_LEFT | REG_HRO) },
{ FLDATA (STOP_IOE, rp_stopioe, 0) },
{ FLDATA (*DEVENB, rp_enb, 0), REG_HRO },
{ NULL } };
@ -508,7 +508,7 @@ MTAB rp_mod[] = {
DEVICE rp_dev = {
"RP", rp_unit, rp_reg, rp_mod,
RP_NUMDR, 8, 30, 1, 8, 16,
RP_NUMDR, RP_RDX, 30, 1, RP_RDX, RP_WID,
NULL, NULL, &rp_reset,
&rp_boot, &rp_attach, &rp_detach };
@ -592,9 +592,11 @@ case 023: /* RPEC2 */
*data = rpec2;
break;
case 024: /* RPBAE */
if (RH_18B) return SCPE_NXM; /* not in RH11 */
*data = rpbae = rpbae & ~AE_MBZ;
break;
case 025: /* RPCS3 */
if (RH_18B) return SCPE_NXM; /* not in RH11 */
*data = rpcs3 = (rpcs3 & ~(CS1_IE | CS3_MBZ)) | (rpcs1 & CS1_IE);
break;
default: /* all others */
@ -704,11 +706,13 @@ case 016: /* RPDC */
rpdc = data & ~DC_MBZ;
break;
case 024: /* RPBAE */
if (RH_18B) return SCPE_NXM; /* not in RH11 */
if ((access == WRITEB) && (PA & 1)) break;
rpbae = data & ~AE_MBZ;
rpcs1 = (rpcs1 & ~CS1_UAE) | ((rpbae << CS1_V_UAE) & CS1_UAE);
break;
case 025: /* RPCS3 */
if (RH_18B) return SCPE_NXM; /* not in RH11 */
if ((access == WRITEB) && (PA & 1)) break;
rpcs3 = data & ~CS3_MBZ;
rpcs1 = (rpcs1 & ~CS1_IE) | (rpcs3 & CS1_IE);
@ -838,9 +842,11 @@ return;
t_stat rp_svc (UNIT *uptr)
{
int32 i, dtype, drv, err;
int32 ba, wc, awc, twc, da, fc;
static uint16 dbuf[RP_MAXFR];
int32 i, t, dtype, drv, err;
int32 wc, awc, da;
t_addr ba;
uint16 comp;
int32 ub = RH_18B;
dtype = GET_DTYPE (uptr -> flags); /* get drive type */
drv = uptr - rp_dev.units; /* get drv number */
@ -866,7 +872,7 @@ case FNC_SEEK: /* seek */
break;
case FNC_WRITE: /* write */
if (uptr -> flags & UNIT_WLK) { /* write locked? */
if (uptr -> flags & UNIT_WPRT) { /* write locked? */
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; }
@ -878,44 +884,65 @@ case FNC_READH: /* read headers */
wc = 0200000 - rpwc; /* get true wc */
if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */
rper1[drv] = rper1[drv] | ER1_AOE;
if (wc > (drv_tab[dtype].size - da))
wc = drv_tab[dtype].size - da; }
rper1[drv] = rper1[drv] | ER1_AOE; /* set err */
wc = drv_tab[dtype].size - da; /* trim xfer */
if (da >= drv_tab[dtype].size) { /* none left? */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; } }
err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET);
if (uptr -> FUNC == FNC_WRITE) { /* write? */
for (twc = 0; twc < wc; twc++) {
if (!ADDR_IS_MEM (ba)) { /* nx memory? */
if (rpcs2 & CS2_UAI) { /* no addr inc? */
if (t = Map_ReadW (ba, 2, &comp, ub)) { /* get 1st wd */
wc = 0; /* NXM, no xfr */
rpcs2 = rpcs2 | CS2_NEM; } /* set nxm err */
for (i = 0; i < wc; i++) rpxb[i] = comp; }
else { /* normal */
if (t = Map_ReadW (ba, wc << 1, rpxb, ub)) { /* get buf */
wc = wc - (t >> 1); /* NXM, adj wc */
rpcs2 = rpcs2 | CS2_NEM; } /* set nxm err */
ba = ba + (wc << 1); } /* adv ba */
awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1);
for (i = wc; i < awc; i++) rpxb[i] = 0; /* fill buf */
if (wc && !err) { /* write buf */
fxwrite (rpxb, sizeof (uint16), wc, uptr -> fileref);
err = ferror (uptr -> fileref); }
} /* end if wr */
else if ((uptr -> FUNC == FNC_READ) || /* read? */
(uptr -> FUNC == FNC_READH)) {
i = fxread (rpxb, sizeof (uint16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; i < wc; i++) rpxb[i] = 0; /* fill buf */
if (rpcs2 & CS2_UAI) { /* no addr inc? */
if (t = Map_WriteW (ba, 2, &rpxb[wc - 1], ub)) {
wc = 0; /* NXM, no xfr */
rpcs2 = rpcs2 | CS2_NEM; } } /* set nxm err */
else { /* normal */
if (t = Map_WriteW (ba, wc << 1, rpxb, ub)) { /* put buf */
wc = wc - (t >> 1); /* NXM, adj wc */
rpcs2 = rpcs2 | CS2_NEM; } /* set nxm err */
ba = ba + (wc << 1); } /* adv ba */
} /* end if read */
else { /* wchk */
i = fxread (rpxb, sizeof (uint16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; i < wc; i++) rpxb[i] = 0; /* fill buf */
awc = wc;
for (wc = 0; wc < awc; wc++) { /* loop thru buf */
if (Map_ReadW (ba, 2, &comp, ub)) { /* read word */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
break; }
dbuf[twc] = M[ba >> 1]; /* write to disk */
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; }
if (fc = twc & (RP_NUMWD - 1)) { /* fill? */
fc = RP_NUMWD - fc;
for (i = 0; i < fc; i++) dbuf[twc + i] = 0; }
fxwrite (dbuf, sizeof (uint16), twc + fc, uptr -> fileref);
err = ferror (uptr -> fileref);
} /* end if */
else { /* read, wchk */
awc = fxread (dbuf, sizeof (uint16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; awc < wc; awc++) dbuf[awc] = 0;
for (twc = 0; twc < wc; twc++) {
if (!ADDR_IS_MEM (ba)) { /* nx memory? */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
break; }
if (uptr -> FUNC == FNC_READ) M[ba >> 1] = dbuf[twc];
else if (M[ba >> 1] != dbuf[twc]) {
if (comp != rpxb[wc]) { /* compare wd */
rpcs2 = rpcs2 | CS2_WCE; /* set error */
break; }
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; }
} /* end else */
} /* end else wchk */
rpwc = (rpwc + twc) & 0177777; /* final word count */
rpwc = (rpwc + wc) & 0177777; /* final word count */
rpba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */
rpbae = (ba >> 16) & ~AE_MBZ; /* upper 6b */
rpcs1 = (rpcs1 & ~ CS1_UAE) | ((rpbae << CS1_V_UAE) & CS1_UAE);
da = da + twc + (RP_NUMWD - 1);
da = da + wc + (RP_NUMWD - 1);
if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST;
da = da / RP_NUMWD;
rpda = da % drv_tab[dtype].sect;
@ -1002,10 +1029,12 @@ for (i = 0; i < RP_NUMDR; i++) {
sim_cancel (uptr);
uptr -> CYL = uptr -> FUNC = 0;
if (uptr -> flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) |
DS_DPR | DS_RDY | DS_MOL | ((uptr -> flags & UNIT_WLK)? DS_WRL: 0);
DS_DPR | DS_RDY | DS_MOL | ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0);
else if (uptr -> flags & UNIT_DIS) rpds[i] = 0;
else rpds[i] = DS_DPR;
rper1[i] = 0; }
if (rpxb == NULL) rpxb = calloc (RP_MAXFR, sizeof (unsigned int16));
if (rpxb == NULL) return SCPE_MEM;
return SCPE_OK;
}
@ -1021,14 +1050,16 @@ r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
drv = uptr - rp_dev.units; /* get drv number */
rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR |
((uptr -> flags & UNIT_WLK)? DS_WRL: 0);
((uptr -> flags & UNIT_WPRT)? DS_WRL: 0);
rper1[drv] = 0;
update_rpcs (CS1_SC, drv);
if ((uptr -> flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */
if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK;
if ((p = ftell (uptr -> fileref)) == 0)
return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD);
if ((p = ftell (uptr -> fileref)) == 0) {
if (uptr -> flags & UNIT_RO) return SCPE_OK;
return pdp11_bad_block (uptr,
drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD); }
for (i = 0; drv_tab[i].sect != 0; i++) {
if (p <= (drv_tab[i].size * (int) sizeof (int16))) {
uptr -> flags = (uptr -> flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
@ -1057,22 +1088,24 @@ return detach_unit (uptr);
/* Set size command validation routine */
t_stat rp_set_size (UNIT *uptr, int32 value)
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
uptr -> capac = drv_tab[GET_DTYPE (value)].size;
uptr -> capac = drv_tab[GET_DTYPE (val)].size;
return SCPE_OK;
}
/* Set bad block routine */
t_stat rp_set_bad (UNIT *uptr, int32 value)
t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
{
return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD);
}
/* Device bootstrap */
#if defined (VM_PDP11)
#define BOOT_START 02000 /* start */
#define BOOT_UNIT 02006 /* unit number */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32))
@ -1111,3 +1144,12 @@ M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT;
saved_PC = BOOT_START;
return SCPE_OK;
}
#else
t_stat rp_boot (int32 unitno)
{
return SCPE_NOFNC;
}
#endif

1849
PDP11/pdp11_rq.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,8 @@
rx RX11/RX01 floppy disk
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Converted FLG to array
07-Sep-01 RMS Revised device disable and interrupt mechanisms
17-Jul-01 RMS Fixed warning from VC++ 6.0
26-Apr-01 RMS Added device enable/disable support
@ -48,6 +50,7 @@
#define RX_M_NUMDR 01
#define UNIT_V_WLK (UNIT_V_UF) /* write locked */
#define UNIT_WLK (1u << UNIT_V_UF)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
#define IDLE 0 /* idle state */
#define RWDS 1 /* rw, sect next */
@ -139,8 +142,7 @@ REG rx_reg[] = {
{ DRDATA (CTIME, rx_cwait, 24), PV_LEFT },
{ DRDATA (STIME, rx_swait, 24), PV_LEFT },
{ DRDATA (XTIME, rx_xwait, 24), PV_LEFT },
{ FLDATA (FLG0, rx_unit[0].flags, UNIT_V_WLK), REG_HRO },
{ FLDATA (FLG1, rx_unit[1].flags, UNIT_V_WLK), REG_HRO },
{ URDATA (FLG, rx_unit[0].flags, 2, 1, UNIT_V_WLK, RX_NUMDR, REG_HRO) },
{ FLDATA (STOP_IOE, rx_stopioe, 0) },
{ BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) },
{ FLDATA (*DEVENB, rx_enb, 0), REG_HRO },
@ -316,7 +318,7 @@ case RWDT: /* wait for track */
if (func == RXCS_READ) { /* read? */
for (i = 0; i < RX_NUMBY; i++)
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); }
else { if (uptr -> flags & UNIT_WLK) { /* write and locked? */
else { if (uptr -> flags & UNIT_WPRT) { /* write and locked? */
rx_esr = rx_esr | RXES_WLK; /* flag error */
rx_done (rx_esr, 0100); /* done, error */
break; }

View file

@ -27,6 +27,8 @@
tti,tto DL11 terminal input/output
clk KW11L line frequency clock
29-Nov-01 RMS Added read only unit support
09-Nov-01 RMS Added RQDX3 support
07-Oct-01 RMS Upgraded clock to full KW11L for RSTS/E autoconfigure
07-Sep-01 RMS Moved function prototypes, revised interrupt mechanism
17-Jul-01 RMS Moved function prototype
@ -60,6 +62,7 @@ int32 tto_csr = 0; /* control/status */
int32 clk_csr = 0; /* control/status */
int32 clk_tps = 60; /* ticks/second */
int32 tmxr_poll = CLK_DELAY; /* term mux poll */
int32 tmr_poll = CLK_DELAY; /* timer poll */
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
@ -84,7 +87,8 @@ t_stat ptp_detach (UNIT *uptr);
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
@ -500,6 +504,7 @@ clk_csr = clk_csr | CSR_DONE; /* set done */
if (clk_csr & CSR_IE) SET_INT (CLK);
t = sim_rtc_calb (clk_tps); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t; /* set mux poll */
return SCPE_OK;
}
@ -509,6 +514,7 @@ t_stat clk_reset (DEVICE *dptr)
clk_csr = 0;
CLR_INT (CLK);
sim_activate (&clk_unit, clk_unit.wait); /* activate unit */
tmr_poll = clk_unit.wait; /* set timer poll */
tmxr_poll = clk_unit.wait; /* set mux poll */
return SCPE_OK;
}

View file

@ -23,6 +23,7 @@
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.
29-Nov-01 RMS Added read only unit support
17-Sep-01 RMS Removed multiconsole support
26-Aug-01 RMS Added DZ11
20-Aug-01 RMS Updated bad block inquiry
@ -48,10 +49,10 @@ extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE lpt_dev, clk_dev;
extern DEVICE dz_dev;
extern DEVICE rk_dev, rx_dev;
extern DEVICE rl_dev, rp_dev;
extern DEVICE dt_dev, tm_dev;
extern DEVICE ts_dev;
extern DEVICE rk_dev, rl_dev;
extern DEVICE rp_dev, rq_dev;
extern DEVICE rx_dev, dt_dev;
extern DEVICE tm_dev, ts_dev;
/* extern DEVICE hk_dev; */
extern UNIT cpu_unit;
extern REG cpu_reg[];
@ -80,8 +81,8 @@ DEVICE *sim_devices[] = {
&tti_dev, &tto_dev,
&lpt_dev, &clk_dev,
&dz_dev,
&rk_dev, /* &hk_dev, */
&rl_dev, &rp_dev,
&rk_dev, &rl_dev,
&rp_dev, &rq_dev,
&rx_dev, &dt_dev,
&tm_dev, &ts_dev,
NULL };
@ -107,7 +108,8 @@ const char *sim_stop_messages[] = {
"Breakpoint",
"Wait state",
"Trap vector fetch abort",
"Trap stack push abort" };
"Trap stack push abort",
"RQDX3 consistency error" };
/* Binary loader.
@ -210,6 +212,7 @@ int16 *buf;
if ((sec < 2) || (wds < 16)) return SCPE_ARG;
if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT;
if (uptr -> flags & UNIT_RO) return SCPE_RO;
if (!get_yn ("Create bad block table on last track? [N]", FALSE)) return SCPE_OK;
da = (uptr -> capac - (sec * wds)) * sizeof (int16);
if (fseek (uptr -> fileref, da, SEEK_SET)) return SCPE_IOERR;

View file

@ -25,6 +25,9 @@
tc TC11/TU56 DECtape
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Converted POS, STATT, LASTT to arrays
09-Nov-01 RMS Added bus map support
15-Sep-01 RMS Integrated debug logging
27-Sep-01 RMS Fixed interrupt after stop for RSTS/E
07-Sep-01 RMS Revised device disable and interrupt mechanisms
@ -86,6 +89,7 @@
#define UNIT_W_UF 3 /* saved flag width */
#define STATE u3 /* unit state */
#define LASTT u4 /* last time update */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* System independent DECtape constants */
@ -241,7 +245,7 @@ extern uint16 *M; /* memory */
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
extern int32 sim_switches;
extern int32 pdp11_log;
extern int32 cpu_log;
extern FILE *sim_log;
int32 tcst = 0; /* status */
int32 tccm = 0; /* command */
@ -311,46 +315,14 @@ REG dt_reg[] = {
{ DRDATA (DCTIME, dt_dctime, 31), REG_NZ },
{ ORDATA (SUBSTATE, dt_substate, 1) },
{ DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
{ DRDATA (POS0, dt_unit[0].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS1, dt_unit[1].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS2, dt_unit[2].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS3, dt_unit[3].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS4, dt_unit[4].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS5, dt_unit[5].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS6, dt_unit[6].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS7, dt_unit[7].pos, 31), PV_LEFT + REG_RO },
{ ORDATA (STATT0, dt_unit[0].STATE, 18), REG_RO },
{ ORDATA (STATT1, dt_unit[1].STATE, 18), REG_RO },
{ ORDATA (STATT2, dt_unit[2].STATE, 18), REG_RO },
{ ORDATA (STATT3, dt_unit[3].STATE, 18), REG_RO },
{ ORDATA (STATT4, dt_unit[4].STATE, 18), REG_RO },
{ ORDATA (STATT5, dt_unit[5].STATE, 18), REG_RO },
{ ORDATA (STATT6, dt_unit[6].STATE, 18), REG_RO },
{ ORDATA (STATT7, dt_unit[7].STATE, 18), REG_RO },
{ DRDATA (LASTT0, dt_unit[0].LASTT, 32), REG_HRO },
{ DRDATA (LASTT1, dt_unit[1].LASTT, 32), REG_HRO },
{ DRDATA (LASTT2, dt_unit[2].LASTT, 32), REG_HRO },
{ DRDATA (LASTT3, dt_unit[3].LASTT, 32), REG_HRO },
{ DRDATA (LASTT4, dt_unit[4].LASTT, 32), REG_HRO },
{ DRDATA (LASTT5, dt_unit[5].LASTT, 32), REG_HRO },
{ DRDATA (LASTT6, dt_unit[6].LASTT, 32), REG_HRO },
{ DRDATA (LASTT7, dt_unit[7].LASTT, 32), REG_HRO },
{ GRDATA (FLG0, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, dt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, dt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, dt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, dt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, dt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, dt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, dt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (POS, dt_unit[0].pos, 10, 31, 0,
DT_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (STATT, dt_unit[0].STATE, 8, 18, 0,
DT_NUMDR, REG_RO) },
{ URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
DT_NUMDR, REG_HRO) },
{ URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
DT_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dt_enb, 0), REG_HRO },
{ NULL } };
@ -437,8 +409,8 @@ case 001: /* TCCM */
if (uptr -> flags & UNIT_DIS) /* disabled? */
dt_seterr (uptr, STA_SEL); /* select err */
if ((fnc == FNC_WMRK) || /* write mark? */
((fnc == FNC_WALL) && (uptr -> flags & UNIT_WLK)) ||
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK)))
((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT)) ||
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT)))
dt_seterr (uptr, STA_ILO); /* illegal op */
if (!(tccm & CSR_ERR)) dt_newsa (tccm); }
else if ((tccm & CSR_ERR) == 0) { /* clear err? */
@ -712,7 +684,7 @@ int32 fnc = DTS_GETFNC (uptr -> STATE);
int32 *bptr = uptr -> filebuf;
int32 unum = uptr - dt_dev.units;
int32 blk, wrd, relpos, dat;
t_addr ma, ba;
t_addr ma, mma, ba;
/* Motion cases
@ -775,11 +747,12 @@ case FNC_READ: /* read */
tcwc = tcwc & DMASK; /* incr MA, WC */
tcba = tcba & DMASK;
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (ma >= MEMSIZE) { /* nx mem? */
if (!Map_Addr (ma, &mma) || /* map addr */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM);
break; }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
M[ma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */
M[mma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm);
@ -806,10 +779,11 @@ case FNC_WRIT: /* write */
wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */
if (dt_substate) tcdt = 0; /* wc ovf? fill */
else { ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (ma >= MEMSIZE) { /* nx mem? */
if (!Map_Addr (ma, &mma) || /* map addr */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM);
break; }
else tcdt = M[ma >> 1]; /* get word */
else tcdt = M[mma >> 1]; /* get word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm); }
@ -1117,7 +1091,7 @@ if (sim_is_active (uptr)) { /* active? cancel op */
tccm = tccm | CSR_ERR | CSR_DONE;
if (tccm & CSR_IE) SET_INT (DTA); }
uptr -> STATE = uptr -> pos = 0; }
if (uptr -> hwmark) { /* any data? */
if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { /* any data? */
printf ("TC: writing buffer to file\n");
rewind (uptr -> fileref); /* start of file */
if (uptr -> flags & UNIT_8FMT) { /* PDP8? */

View file

@ -25,6 +25,9 @@
tm TM11/TU10 magtape
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Converted UST, POS, FLG to arrays
09-Nov-01 RMS Added bus map support
18-Oct-01 RMS Added stub diagnostic register (found by Thord Nilson)
07-Sep-01 RMS Revised device disable and interrupt mechanisms
26-Apr-01 RMS Added device enable/disable support
@ -64,8 +67,8 @@
#define UNIT_W_UF 2 /* saved user flags */
#define USTAT u3 /* unit status */
#define UNUM u4 /* unit number */
#define DBSIZE (1 << 16) /* max data buf */
#define DBMASK (SBSIZE - 1)
#define TM_MAXFR (1 << 16) /* max transfer */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Command - tm_cmd */
@ -133,7 +136,7 @@
extern uint16 *M; /* memory */
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
uint8 *tmxb = NULL; /* xfer buffer */
int32 tm_sta = 0; /* status register */
int32 tm_cmd = 0; /* command register */
int32 tm_ca = 0; /* current address */
@ -152,7 +155,7 @@ t_stat tm_boot (int32 unitno);
void tm_go (UNIT *uptr);
int32 tm_updcsta (UNIT *uptr);
void tm_set_done (void);
t_stat tm_vlock (UNIT *uptr, int32 val);
t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
/* MT data structures
@ -185,38 +188,11 @@ REG tm_reg[] = {
{ FLDATA (IE, tm_cmd, CSR_V_IE) },
{ FLDATA (STOP_IOE, tm_stopioe, 0) },
{ DRDATA (TIME, tm_time, 24), PV_LEFT },
{ ORDATA (UST0, tm_unit[0].USTAT, 16) },
{ ORDATA (UST1, tm_unit[1].USTAT, 16) },
{ ORDATA (UST2, tm_unit[2].USTAT, 16) },
{ ORDATA (UST3, tm_unit[3].USTAT, 16) },
{ ORDATA (UST4, tm_unit[4].USTAT, 16) },
{ ORDATA (UST5, tm_unit[5].USTAT, 16) },
{ ORDATA (UST6, tm_unit[6].USTAT, 16) },
{ ORDATA (UST7, tm_unit[7].USTAT, 16) },
{ DRDATA (POS0, tm_unit[0].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS1, tm_unit[1].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS2, tm_unit[2].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS3, tm_unit[3].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS4, tm_unit[4].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS5, tm_unit[5].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS6, tm_unit[6].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS7, tm_unit[7].pos, 31), PV_LEFT + REG_RO },
{ GRDATA (FLG0, tm_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, tm_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, tm_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, tm_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, tm_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, tm_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, tm_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, tm_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (UST, tm_unit[0].USTAT, 8, 16, 0, TM_NUMDR, 0) },
{ URDATA (POS, tm_unit[0].pos, 10, 31, 0,
TM_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (FLG, tm_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
TM_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, tm_enb, 0), REG_HRO },
{ NULL } };
@ -326,7 +302,7 @@ f = GET_FNC (tm_cmd); /* get function */
if (((uptr -> flags & UNIT_ATT) == 0) || /* not attached? */
sim_is_active (uptr) || /* busy? */
(((f == MTC_WRITE) || (f == MTC_WREOF) || (f == MTC_WREXT)) &&
(uptr -> flags & UNIT_WLK))) { /* write locked? */
(uptr -> flags & UNIT_WPRT))) { /* write locked? */
tm_sta = tm_sta | STA_ILL; /* illegal */
tm_set_done (); /* set done */
return; }
@ -352,19 +328,17 @@ return;
t_stat tm_svc (UNIT *uptr)
{
int32 f, i, p, err;
int32 f, i, t, err;
t_addr xma;
t_stat rval;
t_mtrlnt tbc, cbc;
uint16 c;
static uint8 dbuf[DBSIZE];
static t_mtrlnt bceof = { 0 };
if (uptr -> USTAT & STA_REW) { /* rewind? */
uptr -> pos = 0; /* update position */
if (uptr -> flags & UNIT_ATT) /* still on line? */
uptr -> USTAT = STA_ONL | STA_BOT |
((uptr -> flags & UNIT_WLK)? STA_WLK: 0);
((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
else uptr -> USTAT = 0;
if (uptr -> UNUM == GET_UNIT (tm_cmd)) { /* selected? */
tm_set_done (); /* set done */
@ -380,7 +354,7 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
f = GET_FNC (tm_cmd); /* get command */
if (((f == MTC_WRITE) || (f == MTC_WREOF) || (f == MTC_WREXT)) &&
(uptr -> flags & UNIT_WLK)) { /* write and locked? */
(uptr -> flags & UNIT_WPRT)) { /* write and locked? */
tm_sta = tm_sta | STA_ILL; /* illegal operation */
tm_set_done (); /* set done */
tm_updcsta (uptr); /* update status */
@ -408,38 +382,31 @@ case MTC_READ: /* read */
tbc = MTRL (tbc); /* ignore error flag */
if (tbc > cbc) tm_sta = tm_sta | STA_RLE; /* wrong size? */
if (tbc < cbc) cbc = tbc; /* use smaller */
i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref);
for ( ; i < tbc; i++) dbuf[i] = 0; /* fill with 0's */
i = fxread (tmxb, sizeof (int8), cbc, uptr -> fileref);
err = ferror (uptr -> fileref);
for (i = 0; i < cbc; i++) { /* copy buffer */
if (xma >= MEMSIZE) { /* nx memory? */
tm_sta = tm_sta | STA_NXM;
break; }
p = xma >> 1; /* word address */
c = dbuf[i]; /* character */
if (i & 1) M[p] = (M[p] & 0377) | (c << 8);
else M[p] = (M[p] & 0177400) | c;
xma = (xma + 1) & 0777777;
tm_bc = (tm_bc + 1) & 0177777; }
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
for ( ; i < cbc; i++) tmxb[i] = 0; /* fill with 0's */
if (t = Map_WriteB (xma, cbc, tmxb, UB)) { /* copy buf to mem */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; } /* adj byte cnt */
xma = (xma + cbc) & 0777777; /* inc bus addr */
tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + /* upd position */
(2 * sizeof (t_mtrlnt));
break;
case MTC_WRITE: /* write */
case MTC_WREXT: /* write ext gap */
if (t = Map_ReadB (xma, cbc, tmxb, UB)) { /* copy mem to buf */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; /* adj byte cnt */
if (cbc == 0) break; } /* no xfr? done */
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
for (i = 0; i < cbc; i++) { /* copy buf to tape */
if (xma >= MEMSIZE) { /* nx memory? */
tm_sta = tm_sta | STA_NXM;
break; }
if (i & 1) dbuf[i] = (M[xma >> 1] >> 8) & 0377;
else dbuf[i] = M[xma >> 1] & 0377;
xma = (xma + 1) & 0777777;
tm_bc = (tm_bc + 1) & 0177777; }
fxwrite (dbuf, sizeof (int8), cbc, uptr -> fileref);
fxwrite (tmxb, sizeof (int8), cbc, uptr -> fileref);
fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
err = ferror (uptr -> fileref);
uptr -> pos = uptr -> pos + ((cbc + 1) & ~1) +
xma = (xma + cbc) & 0777777; /* inc bus addr */
tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */
uptr -> pos = uptr -> pos + ((cbc + 1) & ~1) + /* upd position */
(2 * sizeof (t_mtrlnt));
break;
case MTC_WREOF:
@ -546,8 +513,10 @@ for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */
sim_cancel (uptr); /* cancel activity */
if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_ONL |
((uptr -> pos)? 0: STA_BOT) |
((uptr -> flags & UNIT_WLK)? STA_WLK: 0);
((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
else uptr -> USTAT = 0; }
if (tmxb == NULL) tmxb = calloc (TM_MAXFR, sizeof (unsigned int8));
if (tmxb == NULL) return SCPE_MEM;
return SCPE_OK;
}
@ -559,7 +528,7 @@ t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
uptr -> USTAT = STA_ONL | STA_BOT | ((uptr -> flags & UNIT_WLK)? STA_WLK: 0);
uptr -> USTAT = STA_ONL | STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
if (uptr -> UNUM == GET_UNIT (tm_cmd)) tm_updcsta (uptr);
return r;
}
@ -575,9 +544,11 @@ return detach_unit (uptr);
/* Write lock/enable routine */
t_stat tm_vlock (UNIT *uptr, int32 val)
t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if ((uptr -> flags & UNIT_ATT) && val) uptr -> USTAT = uptr -> USTAT | STA_WLK;
if ((uptr -> flags & UNIT_ATT) &&
(val || (uptr -> flags & UNIT_RO)))
uptr -> USTAT = uptr -> USTAT | STA_WLK;
else uptr -> USTAT = uptr -> USTAT & ~STA_WLK;
if (uptr -> UNUM == GET_UNIT (tm_cmd)) tm_updcsta (uptr);
return SCPE_OK;

View file

@ -25,6 +25,8 @@
ts TS11/TSV05 magtape
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
09-Nov-01 RMS Added bus map, VAX support
15-Oct-01 RMS Integrated debug logging across simulator
27-Sep-01 RMS Implemented extended characteristics and status
Fixed bug in write characteristics status return
@ -47,14 +49,51 @@
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a single record length of 0.
End of tape is two consecutive end of file marks.
The TS11 functions in three environments:
- PDP-11 Q22 systems - the I/O map is one for one, so it's safe to
go through the I/O map
- PDP-11 Unibus 22b systems - the TS11 behaves as an 18b Unibus
peripheral and must go through the I/O map
- VAX Q22 systems - the TS11 must go through the I/O map
*/
#if defined (USE_INT64) /* VAX version */
#include "vax_defs.h"
#define VM_VAX 1
#define TS_RDX 16
#define TS_DF_ENB 1 /* on by default */
#define TS_18B FALSE /* always 22b */
#define ADDRTEST 0177700
#define DMASK 0xFFFF
extern int32 ReadB (t_addr pa);
extern void WriteB (t_addr pa, int32 val);
extern int32 ReadW (t_addr pa);
extern void WriteW (t_addr pa, int32 val);
#else /* PDP11 version */
#include "pdp11_defs.h"
#define VM_PDP11 1
#define TS_RDX 8
#define TS_DF_ENB 0 /* off by default */
#define TS_18B (cpu_18b || cpu_ubm)
#define ADDRTEST (TS_18B? 0177774: 0177700)
extern uint16 *M;
extern int32 cpu_18b, cpu_ubm;
#define ReadB(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377)
#define WriteB(p,v) M[(p) >> 1] = ((p) & 1)? \
((M[(p) >> 1] & 0377) | ((v) << 8)): \
((M[(p) >> 1] & ~0377) | (v))
#define ReadW(p) M[(p) >> 1]
#define WriteW(p,v) M[(p) >> 1] = (v)
#endif
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define DBSIZE (1 << 16) /* data buffer */
#define TS_MAXFR (1 << 16) /* max xfer */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* TSBA/TSDB - 17772520: base address/data buffer register
read: most recent memory address
@ -212,16 +251,11 @@
#define WCHX_HDS 0000040 /* high density */
#define MAX(a,b) (((a) >= (b))? (a): (b))
#define READ_BYTE(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377)
#define WRITE_BYTE(d,p) M[(p) >> 1] = (p & 1)? \
((M[(p) >> 1] & 0377) | ((d) << 8)): \
((M[(p) >> 1] & ~0377) | (d))
extern uint16 *M; /* memory */
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
extern FILE *sim_log;
extern int32 pdp11_log;
uint8 *tsxb = NULL; /* xfer buffer */
int32 tssr = 0; /* status register */
int32 tsba = 0; /* mem addr */
int32 tsdbx = 0; /* data buf ext */
@ -233,8 +267,7 @@ int32 ts_ownm = 0; /* tape owns msg */
int32 ts_qatn = 0; /* queued attn */
int32 ts_bcmd = 0; /* boot cmd */
int32 ts_time = 10; /* record latency */
int32 ts_enb = 0; /* device enable */
static uint8 dbuf[DBSIZE];
int32 ts_enb = TS_DF_ENB; /* device enable */
t_stat ts_svc (UNIT *uptr);
t_stat ts_reset (DEVICE *dptr);
@ -257,25 +290,25 @@ void ts_endcmd (int32 ssf, int32 xs0f, int32 msg);
UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) };
REG ts_reg[] = {
{ ORDATA (TSSR, tssr, 16) },
{ ORDATA (TSBA, tsba, 22) },
{ ORDATA (TSDBX, tsdbx, 8) },
{ ORDATA (CHDR, cmdhdr, 16) },
{ ORDATA (CADL, cmdadl, 16) },
{ ORDATA (CADH, cmdadh, 16) },
{ ORDATA (CLNT, cmdlnt, 16) },
{ ORDATA (MHDR, msghdr, 16) },
{ ORDATA (MRFC, msgrfc, 16) },
{ ORDATA (MXS0, msgxs0, 16) },
{ ORDATA (MXS1, msgxs1, 16) },
{ ORDATA (MXS2, msgxs2, 16) },
{ ORDATA (MXS3, msgxs3, 16) },
{ ORDATA (MSX4, msgxs4, 16) },
{ ORDATA (WADL, wchadl, 16) },
{ ORDATA (WADH, wchadh, 16) },
{ ORDATA (WLNT, wchlnt, 16) },
{ ORDATA (WOPT, wchopt, 16) },
{ ORDATA (WXOPT, wchxopt, 16) },
{ GRDATA (TSSR, tssr, TS_RDX, 16, 0) },
{ GRDATA (TSBA, tsba, TS_RDX, 22, 0) },
{ GRDATA (TSDBX, tsdbx, TS_RDX, 8, 0) },
{ GRDATA (CHDR, cmdhdr, TS_RDX, 16, 0) },
{ GRDATA (CADL, cmdadl, TS_RDX, 16, 0) },
{ GRDATA (CADH, cmdadh, TS_RDX, 16, 0) },
{ GRDATA (CLNT, cmdlnt, TS_RDX, 16, 0) },
{ GRDATA (MHDR, msghdr, TS_RDX, 16, 0) },
{ GRDATA (MRFC, msgrfc, TS_RDX, 16, 0) },
{ GRDATA (MXS0, msgxs0, TS_RDX, 16, 0) },
{ GRDATA (MXS1, msgxs1, TS_RDX, 16, 0) },
{ GRDATA (MXS2, msgxs2, TS_RDX, 16, 0) },
{ GRDATA (MXS3, msgxs3, TS_RDX, 16, 0) },
{ GRDATA (MSX4, msgxs4, TS_RDX, 16, 0) },
{ GRDATA (WADL, wchadl, TS_RDX, 16, 0) },
{ GRDATA (WADH, wchadh, TS_RDX, 16, 0) },
{ GRDATA (WLNT, wchlnt, TS_RDX, 16, 0) },
{ GRDATA (WOPT, wchopt, TS_RDX, 16, 0) },
{ GRDATA (WXOPT, wchxopt, TS_RDX, 16, 0) },
{ FLDATA (INT, IREQ (TS), INT_V_TS) },
{ FLDATA (ATTN, ts_qatn, 0) },
{ FLDATA (BOOT, ts_bcmd, 0) },
@ -294,7 +327,7 @@ MTAB ts_mod[] = {
DEVICE ts_dev = {
"TS", &ts_unit, ts_reg, ts_mod,
1, 10, 31, 1, 8, 8,
1, 10, 31, 1, TS_RDX, 8,
NULL, NULL, &ts_reset,
&ts_boot, &ts_attach, &ts_detach };
@ -319,6 +352,7 @@ return SCPE_OK;
t_stat ts_wr (int32 data, int32 PA, int32 access)
{
int32 i;
t_addr pa;
switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TSDB */
@ -333,7 +367,8 @@ case 0: /* TSDB */
msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */
CLR_INT (TS); /* clr int req */
for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */
if (ADDR_IS_MEM (tsba)) tscmdp[i] = M[(tsba >> 1)];
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
tscmdp[i] = ReadW (pa);
else { ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);
return SCPE_OK; }
tsba = tsba + 2; } /* incr tsba */
@ -342,6 +377,7 @@ case 0: /* TSDB */
break;
case 1: /* TSSR */
if (PA & 1) { /* TSDBX */
if (TS_18B) return SCPE_OK; /* not in TS11 */
if (tssr & TSSR_SSR) { /* ready? */
tsdbx = data; /* save */
if (data & TSDBX_BOOT) {
@ -463,7 +499,7 @@ int32 ts_readf (UNIT *uptr, int32 fc)
{
int32 i, st;
t_mtrlnt tbc, wbc;
t_addr wa;
t_addr wa, pa;
msgrfc = fc;
if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */
@ -473,15 +509,16 @@ if (tbc == 0) { /* tape mark? */
if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl; /* buf addr */
tbc = MTRL (tbc); /* ignore err flag */
wbc = (tbc > DBSIZE)? DBSIZE: tbc; /* cap rec size */
wbc = (tbc > TS_MAXFR)? TS_MAXFR: tbc; /* cap rec size */
wbc = (wbc > fc)? fc: wbc; /* cap buf size */
i = fxread (dbuf, sizeof (uint8), wbc, uptr -> fileref); /* read record */
i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref); /* read record */
if (ferror (uptr -> fileref)) return XTC (XS0_EOT | XS0_RLS, TC2);
for ( ; i < wbc; i++) dbuf[i] = 0; /* fill with 0's */
for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt));
for (i = 0; i < wbc; i++) { /* copy buffer */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (ADDR_IS_MEM (wa)) WRITE_BYTE (dbuf[i], wa); /* nxm? */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */
WriteB (pa, tsxb[i]); /* no, store */
else { tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); }
tsba = tsba + 1;
@ -495,7 +532,7 @@ int32 ts_readr (UNIT *uptr, int32 fc)
{
int32 i, st;
t_mtrlnt tbc, wbc;
t_addr wa;
t_addr wa, pa;
msgrfc = fc;
if (uptr -> pos == 0) { /* BOT? */
@ -508,19 +545,20 @@ if (tbc == 0) { /* tape mark? */
if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */
tbc = MTRL (tbc); /* ignore err flag */
wbc = (tbc > DBSIZE)? DBSIZE: tbc; /* cap rec size */
wbc = (tbc > TS_MAXFR)? TS_MAXFR: tbc; /* cap rec size */
wbc = (wbc > fc)? fc: wbc; /* cap buf size */
fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) - wbc, SEEK_SET);
i = fxread (dbuf, sizeof (uint8), wbc, uptr -> fileref);
for ( ; i < wbc; i++) dbuf[i] = 0; /* fill with 0's */
i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref);
for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */
if (ferror (uptr -> fileref)) { /* error? */
msgxs3 = msgxs3 | XS3_OPI;
return XTC (XS0_RLS, TC6); }
uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt));
for (i = wbc; i > 0; i--) { /* copy buffer */
tsba = tsba - 1;
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba;
if (ADDR_IS_MEM (wa)) WRITE_BYTE (dbuf[i - 1], wa);
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */
WriteB (pa, tsxb[i - 1]); /* no, store */
else { tssr = ts_updtssr (tssr | TSSR_NXM);
return (XTC (XS0_RLS, TC4)); }
msgrfc = (msgrfc - 1) & DMASK; }
@ -532,20 +570,21 @@ return 0;
int32 ts_write (UNIT *uptr, int32 fc)
{
int32 i;
t_addr wa;
t_addr wa, pa;
msgrfc = fc;
if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl; /* buf addr */
for (i = 0; i < fc; i++) { /* copy mem to buf */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply opp */
if (ADDR_IS_MEM (wa)) dbuf[i] = READ_BYTE (wa); /* nxm? */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */
tsxb[i] = ReadB (pa); /* no, store */
else { tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; }
tsba = tsba + 1; }
fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* position */
fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref);
fxwrite (dbuf, sizeof (uint8), fc, uptr -> fileref);
fxwrite (tsxb, sizeof (uint8), fc, uptr -> fileref);
fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref);
uptr -> pos = uptr -> pos + ((fc + 1) & ~1) + (2 * sizeof (t_mtrlnt));
msgrfc = 0;
@ -571,6 +610,8 @@ return XTC (XS0_TMK, TC0);
t_stat ts_svc (UNIT *uptr)
{
int32 i, fnc, mod, st0, st1;
t_addr pa;
static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */
0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */
5, 3, 5, 1, 0, 0, 0, 1, /* 10 - 17 */
@ -619,7 +660,7 @@ if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!att)? */
ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; }
if ((fnc_flg[fnc] & FLG_WR) && /* write? */
(uptr -> flags & UNIT_WLK)) { /* write lck? */
(uptr -> flags & UNIT_WPRT)) { /* write lck? */
ts_endcmd (TC3, XS0_WLE | XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; }
if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */
@ -627,7 +668,7 @@ if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */
(uptr -> pos == 0)) { /* BOT? */
ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; }
if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & 0177700)) { /* buf addr > 22b? */
if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */
ts_endcmd (TC3, XS0_ILA, MSG_ACK | MSG_MILL | MSG_CFAIL);
return SCPE_OK; }
@ -640,12 +681,13 @@ case FNC_GSTA: /* get status */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */
return SCPE_OK;
case FNC_WCHR: /* write char */
if ((cmdadh & 0177700) || (cmdadl & 1) || (cmdlnt < 6)) {
if ((cmdadh & ADDRTEST) || (cmdadl & 1) || (cmdlnt < 6)) {
ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0);
break; }
tsba = (cmdadh << 16) | cmdadl;
for (i = 0; (i < WCH_PLNT) && (i < (cmdlnt / 2)); i++) {
if (ADDR_IS_MEM (tsba)) tswchp[i] = M[tsba >> 1];
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
tswchp[i] = ReadW (pa);
else { ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0);
return SCPE_OK; }
tsba = tsba + 2; }
@ -745,9 +787,6 @@ case FNC_POS:
break; }
ts_cmpendcmd (st0, 0);
break; }
if (DBG_LOG (LOG_TS))
fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%o, sta = %o, tc=%o, pos=%d\n",
fnc, mod, cmdadl, cmdlnt, msgxs0, (tssr & TSSR_TC) >> 1, ts_unit.pos);
return SCPE_OK;
}
@ -766,7 +805,7 @@ int32 ts_updxs0 (int32 t)
t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET;
if (ts_unit.flags & UNIT_ATT) {
t = t | XS0_ONL;
if (ts_unit.flags & UNIT_WLK) t = t | XS0_WLK;
if (ts_unit.flags & UNIT_WPRT) t = t | XS0_WLK;
if (ts_unit.pos == 0) t = (t | XS0_BOT) & ~XS0_EOT; }
else t = t & ~XS0_EOT;
if (cmdhdr & CMD_IE) t = t | XS0_IE;
@ -792,6 +831,7 @@ return;
void ts_endcmd (int32 tc, int32 xs0, int32 msg)
{
int32 i;
t_addr pa;
msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */
if (wchxopt & WCHX_HDS) msgxs4 = msgxs4 | XS4_HDS; /* update XS4 */
@ -800,7 +840,8 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */
msglnt = wchlnt - 4; /* exclude hdr, bc */
tsba = (wchadh << 16) | wchadl;
for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++) {
if (ADDR_IS_MEM (tsba)) M[tsba >> 1] = tsmsgp[i];
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
WriteW (pa, tsmsgp[i]);
else { tssr = tssr | TSSR_NXM;
tc = (tc & ~TSSR_TC) | TC4;
break; }
@ -816,9 +857,11 @@ return;
t_stat ts_reset (DEVICE *dptr)
{
int32 i;
#if defined (VM_PDP11)
extern int32 tm_enb;
if (ts_enb) tm_enb = 0; /* TM or TS */
#endif
ts_unit.pos = 0;
tsba = tsdbx = 0;
ts_ownc = ts_ownm = 0;
@ -830,6 +873,8 @@ for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0;
for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0;
msgxs0 = ts_updxs0 (XS0_VCK);
CLR_INT (TS);
if (tsxb == NULL) tsxb = calloc (TS_MAXFR, sizeof (unsigned int8));
if (tsxb == NULL) return SCPE_MEM;
return SCPE_OK;
}
@ -871,6 +916,7 @@ return r;
/* Boot */
#if defined (VM_PDP11)
#define BOOT_START 01000
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32))
@ -923,3 +969,10 @@ for (i = 0; i < BOOT_LEN; i++)
saved_PC = BOOT_START;
return SCPE_OK;
}
#else
t_stat ts_boot (int32 unitno)
{
return SCPE_NOFNC;
}
#endif

View file

@ -25,6 +25,8 @@
cpu PDP-4/7/9/15 central processor
30-Nov-01 RMS Added extended SET/SHOW support
25-Nov-01 RMS Revised interrupt structure
19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy)
17-Sep-01 RMS Fixed typo in conditional
10-Aug-01 RMS Removed register from declarations
@ -224,9 +226,9 @@
nested XCT's
I/O error in I/O simulator
2. Interrupts. Interrupt requests are maintained in the int_req
register. If interrupts are on and not deferred, and at least
one interrupt request is set, a program interrupt occurs.
2. Interrupts. Interrupt requests are maintained in the int_hwre
array. int_hwre[0:3] corresponds to API levels 0-3; int_hwre[4]
holds PI requests.
3. Arithmetic. The 18b PDP's implements both 1's and 2's complement
arithmetic for signed numbers. In 1's complement arithmetic, a
@ -244,8 +246,6 @@
#include "pdp18b_defs.h"
#define ILL_ADR_FLAG (1 << ADDRSIZE)
#define save_ibkpt (cpu_unit.u3)
#define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */
#define UNIT_NOEAE (1 << UNIT_V_NOEAE)
#define UNIT_V_NOAPI (UNIT_V_UF+1) /* API absent */
@ -271,7 +271,8 @@ int32 saved_PC = 0; /* PC */
int32 iors = 0; /* IORS */
int32 ion = 0; /* int on */
int32 ion_defer = 0; /* int defer */
int32 int_req = 0; /* int requests */
int32 int_pend = 0; /* int pending */
int32 int_hwre[API_HLVL+1] = { 0 }; /* int requests */
int32 api_enb = 0; /* API enable */
int32 api_req = 0; /* API requests */
int32 api_act = 0; /* API active */
@ -297,16 +298,16 @@ int32 LR = 0; /* limit register */
int32 stop_inst = 0; /* stop on rsrv inst */
int32 xct_max = 16; /* nested XCT limit */
int32 old_PC = 0; /* old PC */
int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */
int32 dev_enb = -1; /* device enables */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
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_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
int32 upd_iors (void);
int32 api_eval (void);
int32 api_eval (int32 *pend);
static const int32 api_ffo[256] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
@ -326,11 +327,11 @@ static const int32 api_ffo[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static const int32 api_vec[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, ACH_TTO1, ACH_TTI1, ACH_CLK, 0, 0, 0, 0,
0, ACH_LPT, ACH_LPT, ACH_PTR, 0, 0, 0, ACH_RP,
ACH_RF, ACH_DRM, ACH_MTA, ACH_DTA, 0, 0, ACH_PWRFL, 0 };
static const int32 api_vec[API_HLVL][32] = {
{ ACH_PWRFL }, /* API 0 */
{ ACH_DTA, ACH_MTA, ACH_DRM, ACH_RF, ACH_RP }, /* API 1 */
{ ACH_PTR, ACH_LPT, ACH_LPT }, /* API 2 */
{ ACH_CLK, ACH_TTI1, ACH_TTO1 } }; /* API 3 */
/* CPU data structures
@ -340,7 +341,7 @@ static const int32 api_vec[32] = {
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + EAE_DFLT + API_DFLT,
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + EAE_DFLT + API_DFLT,
MAXMEMSIZE) };
REG cpu_reg[] = {
@ -354,13 +355,14 @@ REG cpu_reg[] = {
#endif
{ ORDATA (SR, SR, 18) },
{ ORDATA (IORS, iors, 18), REG_RO },
{ ORDATA (INT, int_req, 32), REG_RO },
{ BRDATA (INT, int_hwre, 8, 32, API_HLVL+1), REG_RO },
{ FLDATA (ION, ion, 0) },
{ ORDATA (ION_DELAY, ion_defer, 2) },
#if defined (PDP7)
{ FLDATA (TRAPM, usmd, 0) },
{ FLDATA (TRAPP, trap_pending, 0) },
{ FLDATA (EXTM, memm, 0) },
{ FLDATA (EXTM_INIT, memm_init, 0) },
{ FLDATA (EMIRP, emir_pending, 0) },
#endif
#if defined (PDP9)
@ -377,7 +379,7 @@ REG cpu_reg[] = {
{ FLDATA (EXTM_INIT, memm_init, 0) },
{ FLDATA (EMIRP, emir_pending, 0) },
{ FLDATA (RESTP, rest_pending, 0) },
{ FLDATA (PWRFL, int_req, INT_V_PWRFL) },
{ FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) },
#endif
#if defined (PDP15)
{ FLDATA (APIENB, api_enb, 0) },
@ -386,22 +388,21 @@ REG cpu_reg[] = {
{ ORDATA (XR, XR, 18) },
{ ORDATA (LR, LR, 18) },
{ ORDATA (BR, BR, ADDRSIZE) },
{ FLDATA (USMD, usmd, 0) },
{ FLDATA (USMDBUF, usmdbuf, 0) },
{ FLDATA (NEXM, nexm, 0) },
{ FLDATA (PRVN, prvn, 0) },
{ FLDATA (TRAPP, trap_pending, 0) },
{ FLDATA (USMD, usmd, 0) },
{ FLDATA (USMDBUF, usmdbuf, 0) },
{ FLDATA (BANKM, memm, 0) },
{ FLDATA (BANKM_INIT, memm_init, 0) },
{ FLDATA (RESP, rest_pending, 0) },
{ FLDATA (PWRFL, int_req, INT_V_PWRFL) },
{ FLDATA (RESTP, rest_pending, 0) },
{ FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) },
#endif
{ ORDATA (OLDPC, old_PC, ADDRSIZE), REG_RO },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO },
{ FLDATA (NOAPI, cpu_unit.flags, UNIT_V_NOAPI), REG_HRO },
{ DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },
{ ORDATA (BREAK, ibkpt_addr, ADDRSIZE + 1) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL } };
@ -608,7 +609,7 @@ MQ = saved_MQ & 0777777;
reason = 0;
sim_rtc_init (clk_unit.wait); /* init calibration */
if (cpu_unit.flags & UNIT_NOAPI) api_enb = api_req = api_act = 0;
api_int = api_eval (); /* eval API */
api_int = api_eval (&int_pend); /* eval API */
api_cycle = 0; /* not API cycle */
/* Main instruction fetch/decode loop: check trap and interrupt */
@ -619,7 +620,7 @@ int32 link_init, fill;
if (sim_interval <= 0) { /* check clock queue */
if (reason = sim_process_event ()) break;
api_int = api_eval (); } /* eval API */
api_int = api_eval (&int_pend); } /* eval API */
/* Protection traps work like interrupts, with these quirks:
@ -653,18 +654,18 @@ if (trap_pending) { /* trap pending? */
if (api_int && !ion_defer) { /* API intr? */
int32 i, lvl = api_int - 1; /* get req level */
api_act = api_act | (0200 >> lvl); /* set level active */
if (lvl >= 4) { /* software req? */
MA = ACH_SWRE + lvl - 4; /* vec = 40:43 */
if (lvl >= API_HLVL) { /* software req? */
MA = ACH_SWRE + lvl - API_HLVL; /* vec = 40:43 */
api_req = api_req & ~(0200 >> lvl); } /* remove request */
else { MA = 0; /* assume fails */
for (i = 31; i >= 0; i--) { /* loop hi to lo */
if ((int_req >> i) & 1) { /* int req set? */
MA = api_vec[i]; /* get vector */
break; } } } /* and stop */
for (i = 0; i < 32; i++) { /* loop hi to lo */
if ((int_hwre[lvl] >> i) & 1) { /* int req set? */
MA = api_vec[lvl][i]; /* get vector */
break; } } } /* and stop */
if (MA == 0) { /* bad channel? */
reason = STOP_API; /* API error */
break; }
api_int = api_eval (); /* no API int */
api_int = api_eval (&int_pend); /* no API int */
api_cycle = 1; /* in API cycle */
emir_pending = rest_pending = 0; /* emir, restore off */
xct_count = 0;
@ -672,9 +673,9 @@ if (api_int && !ion_defer) { /* API intr? */
/* Standard program interrupt */
if (!(api_enb && api_act) && ion && !ion_defer && int_req) {
if (!(api_enb && api_act) && ion && !ion_defer && int_pend) {
#else
if (ion && !ion_defer && int_req) { /* interrupt? */
if (ion && !ion_defer && int_pend) { /* interrupt? */
#endif
old_PC = PC; /* save old PC */
M[0] = JMS_WORD (usmd); /* save state */
@ -688,10 +689,7 @@ if (ion && !ion_defer && int_req) { /* interrupt? */
/* Breakpoint */
if (PC == ibkpt_addr) { /* breakpoint? */
save_ibkpt = ibkpt_addr; /* save ibkpt */
ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */
sim_activate (&cpu_unit, 1); /* sched re-enable */
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break; }
@ -862,7 +860,7 @@ case 001: case 000: /* CAL */
usmd = 0; /* clear user mode */
if ((cpu_unit.flags & UNIT_NOAPI) == 0) { /* if API, act lvl 4 */
api_act = api_act | 010;
api_int = api_eval (); }
api_int = api_eval (&int_pend); }
#endif
if (IR & 0020000) { INDIRECT; } /* indirect? */
CHECK_ADDR_W (MA);
@ -1345,7 +1343,7 @@ case 034: /* IOT */
else if (pulse == 044) nexm = 0;
break;
case 032: /* power fail */
if ((pulse == 001) && (int_req & INT_PWRFL))
if ((pulse == 001) && (TST_INT (PWRFL)))
PC = INCR_ADDR (PC);
break;
case 033: /* CPU control */
@ -1477,7 +1475,7 @@ case 034: /* IOT */
LAC = LAC | (iot_data & 0777777);
if (iot_data & IOT_SKP) PC = INCR_ADDR (PC);
if (iot_data >= IOT_REASON) reason = iot_data >> IOT_V_REASON;
api_int = api_eval (); /* eval API */
api_int = api_eval (&int_pend); /* eval API */
break; /* end case IOT */
} /* end switch opcode */
if (api_cycle) { /* API cycle? */
@ -1497,16 +1495,17 @@ return reason;
/* Evaluate API */
int32 api_eval (void)
int32 api_eval (int32 *pend)
{
int32 i, hi;
static const uint32 api_mask[4] = {
API_L0, API_L1, API_L2, API_L3 };
for (i = *pend = 0; i < API_HLVL+1; i++) { /* any intr? */
if (int_hwre[i]) *pend = 1; }
if (api_enb == 0) return 0; /* off? no req */
api_req = api_req & ~0360; /* clr req<0:3> */
for (i = 0; i < 4; i++) {
if (int_req & api_mask[i]) api_req = api_req | (0200 >> i); }
for (i = 0; i < API_HLVL; i++) { /* loop thru levels */
if (int_hwre[i]) /* req on level? */
api_req = api_req | (0200 >> i); } /* set api req */
hi = api_ffo[api_req & 0377]; /* find hi req */
if (hi < api_ffo[api_act & 0377]) return (hi + 1);
return 0;
@ -1554,14 +1553,15 @@ t_stat cpu_reset (DEVICE *dptr)
SC = 0;
eae_ac_sign = 0;
ion = ion_defer = 0;
int_req = int_req & ~INT_PWRFL;
CLR_INT (PWRFL);
api_enb = api_req = api_act = 0;
BR = 0;
usmd = usmdbuf = 0;
memm = memm_init;
nexm = prvn = trap_pending = 0;
emir_pending = rest_pending = 0;
return cpu_svc (&cpu_unit);
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
@ -1582,28 +1582,19 @@ M[addr] = val & 0777777;
return SCPE_OK;
}
/* Service breakpoint */
t_stat cpu_svc (UNIT *uptr)
{
if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt;
save_ibkpt = -1;
return SCPE_OK;
}
/* Change memory size */
t_stat cpu_set_size (UNIT *uptr, int32 value)
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
t_addr i;
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0))
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = value; i < MEMSIZE; i++) mc = mc | M[i];
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = value;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}

View file

@ -23,6 +23,7 @@
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.
25-Nov-01 RMS Revised interrupt structure
27-May-01 RMS Added second Teletype support
21-Jan-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
@ -187,65 +188,101 @@
35 LT15 TTI 3 PDP-15 only
36 -
37 -
Interrupt system, priority is left to right.
<30:28> = priority 0
<27:20> = priority 1
<19:12> = priority 2
<11:8> = priority 3
<7:0> = PI only
*/
#define API_L0 0xF0000000
#define API_L1 0x0FF00000
#define API_L2 0x000FF000
#define API_L3 0x00000F00
#define API_HLVL 4 /* hwre levels */
#define ACH_SWRE 040 /* swre int vec */
#define INT_V_PWRFL 30 /* powerfail */
#define INT_V_DTA 27 /* DECtape */
#define INT_V_MTA 26 /* magtape */
#define INT_V_DRM 25 /* drum */
#define INT_V_RF 24 /* fixed head disk */
#define INT_V_RP 23 /* disk pack */
#define INT_V_PTR 19 /* paper tape reader */
#define INT_V_LPT 18 /* line printer */
#define INT_V_LPTSPC 17 /* line printer spc */
#define INT_V_CLK 11 /* clock */
#define INT_V_TTI1 10 /* LT15 keyboard */
#define INT_V_TTO1 9 /* LT15 output */
#define INT_V_TTI 7 /* console keyboard */
#define INT_V_TTO 6 /* console output */
#define INT_V_PTP 5 /* paper tape punch */
/* API level 0 */
#define INT_V_PWRFL 0 /* powerfail */
#define INT_PWRFL (1 << INT_V_PWRFL)
#define API_PWRFL 0
#define ACH_PWRFL 052
/*API level 1 */
#define INT_V_DTA 0 /* DECtape */
#define INT_V_MTA 1 /* magtape */
#define INT_V_DRM 2 /* drum */
#define INT_V_RF 3 /* fixed head disk */
#define INT_V_RP 4 /* disk pack */
#define INT_DTA (1 << INT_V_DTA)
#define INT_MTA (1 << INT_V_MTA)
#define INT_DRM (1 << INT_V_DRM)
#define INT_RF (1 << INT_V_RF)
#define INT_RP (1 << INT_V_RP)
#define INT_PTR (1 << INT_V_PTR)
#define INT_LPT (1 << INT_V_LPT)
#define INT_LPTSPC (1 << INT_V_LPTSPC)
#define INT_CLK (1 << INT_V_CLK)
#define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTO1 (1 << INT_V_TTO1)
#define INT_TTI (1 << INT_V_TTI)
#define INT_TTO (1 << INT_V_TTO)
#define INT_PTP (1 << INT_V_PTP)
#define ACH_SWRE 040 /* API channels */
#define ACH_PWRFL 052
#define API_DTA 1
#define API_MTA 1
#define API_DRM 1
#define API_RF 1
#define API_RP 1
#define ACH_DTA 044
#define ACH_MTA 045
#define ACH_DRM 046
#define ACH_RF 063
#define ACH_RP 064
/* API level 2 */
#define INT_V_PTR 0 /* paper tape reader */
#define INT_V_LPT 1 /* line printer */
#define INT_V_LPTSPC 2 /* line printer spc */
#define INT_PTR (1 << INT_V_PTR)
#define INT_LPT (1 << INT_V_LPT)
#define INT_LPTSPC (1 << INT_V_LPTSPC)
#define API_PTR 2
#define API_LPT 2
#define API_LPTSPC 2
#define ACH_PTR 050
#define ACH_LPT 056
/* API level 3 */
#define INT_V_CLK 0 /* clock */
#define INT_V_TTI1 1 /* LT15 keyboard */
#define INT_V_TTO1 2 /* LT15 output */
#define INT_CLK (1 << INT_V_CLK)
#define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTO1 (1 << INT_V_TTO1)
#define API_CLK 3
#define API_TTI1 3
#define API_TTO1 3
#define ACH_CLK 051
#define ACH_TTI1 075
#define ACH_TTO1 074
/* PI level */
#define INT_V_TTI 0 /* console keyboard */
#define INT_V_TTO 1 /* console output */
#define INT_V_PTP 2 /* paper tape punch */
#define INT_TTI (1 << INT_V_TTI)
#define INT_TTO (1 << INT_V_TTO)
#define INT_PTP (1 << INT_V_PTP)
#define API_TTI 4 /* PI level */
#define API_TTO 4
#define API_PTP 4
/* Interrupt macros */
#define SET_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] | INT_##dv
#define CLR_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] & ~INT_##dv
#define TST_INT(dv) (int_hwre[API_##dv] & INT_##dv)
/* I/O status flags for the IORS instruction

782
PDP18B/pdp18b_doc.txt Normal file
View file

@ -0,0 +1,782 @@
To: Users
From: Bob Supnik
Subj: 18b PDP 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-4, PDP-7, PDP-9, and PDP-15 simulators.
1. Simulator Files
To compile a particular model in the 18b family, you must include the appropriate
switch in the compilation command line:
PDP-4/ PDP4
PDP-7/ PDP7
PDP-9/ PDP9
PDP-15/ PDP15
If no model is specified, the default is the PDP-9.
sim/ sim_defs.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_rev.c
sim_sock.c
sim_tmxr.c
sim/pdp18b/ pdp18b_defs.h
pdp18b_cpu.c
pdp18b_drm.c
pdp18b_dt.c
pdp18b_lp.c
pdp18b_mt.c
pdp18b_rf.c
pdp18b_rp.c
pdp18b_stddev.c
pdp18b_sys.c
pdp18b_tt1.c
2. 18b PDP Features
The other four 18b PDP's (PDP-4, PDP-7, PDP-9, PDP-15) are very similar
and are configured as follows:
system device simulates
name(s)
PDP-4 CPU PDP-4 CPU with 8KW of memory
PTR,PTP integral paper tape/Type 75 punch
TTI,TTO KSR28 console terminal (Baudot code)
LPT Type 62 line printer (Hollerith code)
CLK integral real-time clock
PDP-7 CPU PDP-7 CPU with 32KW of memory
- Type 177 extended arithmetic element (EAE)
- Type 148 memory extension
PTR,PTP Type 444 paper tape reader/Type 75 punch
TTI,TTO KSR 33 console terminal
LPT Type 647 line printer
CLK integral real-time clock
DRM Type 24 serial drum
PDP-9 CPU PDP-9 CPU with 32KW of memory
- KE09A extended arithmetic element (EAE)
- KF09A automatic priority interrupt (API)
- KG09B memory extension
- KP09A power detection
- KX09A memory protection
PTR,PTP PC09A paper tape reader/punch
TTI,TTO KSR 33 console terminal
TTI1,TTO1 LT09A second console terminal
LPT Type 647E line printer
CLK integral real-time clock
RF RF09/RS09 fixed-head disk
DT TC02/TU55 DECtape
MT TC59/TU10 magnetic tape
PDP-15 CPU PDP-15 CPU with 32KW of memory
- KE15 extended arithmetic element (EAE)
- KA15 automatic priority interrupt (API)
- KF15 power detection
- KM15 memory protection
PTR,PTP PC15 paper tape reader/punch
TTI,TTO KSR 35 console terminal
TTI1,TTO1 LT15 second console terminal
LPT LP15 line printer
CLK integral real-time clock
RP RP15/RP02 disk pack
RF RF15/RS09 fixed-head disk
DT TC15/TU56 DECtape
MT TC59/TU10 magnetic tape
The DRM, RF, RP, DT, and MT devices can be DISABLEd.
The 18b PDP simulators implement several unique stop conditions:
- an unimplemented instruction is decoded, and register
STOP_INST is set
- more than XCTMAX nested executes are detected during
instruction execution
The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9
and PDP-15 support both RIM and BIN format tapes. If the file extension
is .RIM, or the -r switch is specified with LOAD, the file is assumed to
be RIM format; if the file extension is not .RIM, or if the -b switch is
specified, the file is assumed to be BIN format.
2.1 CPU
The CPU options are the presence of the EAE, the presense of the API (for
the PDP-9 and PDP-15), and the size of main memory.
SET CPU EAE enable EAE
SET CPU NOEAE disable EAE
SET CPU API enable API
SET CPU NOAPI disable API
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
SET CPU 20K set memory size = 20K
SET CPU 24K set memory size = 24K
SET CPU 28K set memory size = 28K
SET CPU 32K set memory size = 32K
SET CPU 48K set memory size = 48K
SET CPU 64K set memory size = 64K
SET CPU 80K set memory size = 80K
SET CPU 96K set memory size = 96K
SET CPU 112K set memory size = 112K
SET CPU 128K set memory size = 128K
Memory sizes greater than 8K are only available on the PDP-7, PDP-9, and
PDP-15; memory sizes greater than 32KW are only available on the PDP-15.
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 8K for the PDP-4, 32K
for the PDP-7 and PDP-9, and 128K for the PDP-15.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
system name size comments
all PC addr program counter
all AC 18 accumulator
all L 1 link
7,9,15 MQ 18 multiplier-quotient
7,9,15 SC 6 shift counter
7,9,15 EAE_AC_SIGN 1 EAE AC sign
all SR 18 front panel switches
all INT[0:4] 32 interrupt requests,
0:3 = API levels 0-3
4 = PI level
all IORS 18 IORS register
all ION 1 interrupt enable
all ION_DELAY 2 interrupt enable delay
9,15 APIENB 1 API enable
9,15 APIREQ 8 API requesting levels
9,15 APIACT 8 API active levels
9,15 BR addr memory protection bounds
15 XR 18 index register
15 LR 18 limit register
15 BR 17 memory protection bounds
9,15 USMD 1 user mode
9,15 USMDBUF 1 user mode buffer
9,15 NEXM 1 non-existent memory violation
9,15 PRVN 1 privilege violation
7,9 EXTM 1 extend mode
7,9 EXTM_INIT 1 extend mode value after reset
15 BANKM 1 bank mode
15 BANKM_INIT 1 bank mode value after reset
7 TRAPM 1 trap mode
7,9,15 TRAPP 1 trap pending
7,9 EMIRP 1 EMIR instruction pending
9,15 RESTP 1 DBR or RES instruction pending
9,15 PWRFL 1 power fail flag
all OLDPC addr PC prior to last transfer
all STOP_INST 1 stop on undefined instruction
all WRU 8 interrupt character
"addr" signifies the address width of the system (13b for the PDP-4, 15b for
the PDP-7 and PDP-9, 17b for the PDP-15).
2.2 Programmed I/O Devices
2.2.1 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.
On the PDP-4 and PDP-7, the paper tape reader supports the BOOT command.
BOOT PTR copies the RIM loader into memory and starts it running, while
BOOT -F PTR copies the funny format binary loader into memory and starts
it running.
The paper tape reader implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag (PDP-9, PDP-15 only)
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.2.2 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 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
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag (PDP-9, PDP-15 only)
POS 31 position in the 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 or paper
OS I/O error x report error and stop
2.2.3 Terminal Input (TTI)
The terminal input (TTI) polls the console keyboard for input. The
input side has one option, UC; when set, it automatically converts lower
case input to upper case.
The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default,
as half duplex. For backward compatibility, on the PDP-9 and PDP-15
the first terminal input has a second option, FDX; when set, it operates
the terminal input in full-duplex mode. The second terminal is always
full duplex.
The terminal input implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of characters input
TIME 24 keyboard polling interval
2.2.4 Terminal Output (TTO)
The terminal output (TTO) writes to the simulator console window. The
terminal output has one option, UC; when set, it suppresses lower case
output (so that ALTMODE is not echoed as }).
The terminal output implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of chararacters output
TIME 24 time from I/O initiation to interrupt
2.2.5 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The PDP-4 used a Type 62 printer controller, with these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
SPC 1 spacing done flag
BPTR 6 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
The PDP-7 and PDP-7 used a Type 647 printer controller, with these
registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
ENABLE 1 interrupt enable (PDP-9 only)
ERR 1 error flag
BPTR 7 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
The PDP-15 used an LP15 printer controller, with these registers:
name size comments
STA 18 status register
MA 18 DMA memory address
INT 1 interrupt pending flag
ENABLE 1 interrupt enable
LCNT 8 line counter
BPTR 7 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:131] 8 line buffer
For all three models, error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.2.6 Real-Time Clock (CLK)
The real-time clock (CLK) implements these registers:
name size comments
INT 1 interrupt pending flag
DONE 1 device done flag
ENABLE 1 clock enable
TIME 24 clock frequency
TPS 8 ticks per second (60 or 50)
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.7 Second Terminal (TTI1, TTO1)
The second terminal consists of two independent devices, TTI1 and TTO1.
The second terminal performs input and output through a Telnet session
connected to a user-specified port. The ATTACH command specifies the
port to be used:
ATTACH TTI1 <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.
Once TTI1 is attached and the simulator is running, the terminal listens
for a connection on the specified port. It assumes that the incoming
connection is a Telnet connection. The connection remain opens until
disconnected by the Telnet client, or by a DETACH TTI1 command.
The second terminal input has one option, UC; when set, it automatically
converts lower case input to upper case. The second terminal output also
has one option, UC; when set, it suppresses lower case output (so that
ALTMODE is not echoed as }).
The SHOW TTI1 LINESTATUS command displays the current connection to the
second terminal.
The second terminal input implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of characters input
TIME 24 keyboard polling interval
The second terminal output implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of chararacters output
TIME 24 time from I/O initiation to interrupt
2.3 RP15/RP02 Disk Pack (RP)
RP15 options include the ability to make units write enabled or write locked:
SET RPn LOCKED set unit n write locked
SET RPn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
The RP15 implements these registers:
name size comments
STA 18 status A
STB 18 status B
DA 18 disk address
MA 18 current memory address
WC 18 word count
INT 1 interrupt pending flag
BUSY 1 control busy flag
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.4 Type 24 Serial Drum (DRM)
The serial drum (DRM) implements these registers:
name size comments
DA 9 drum address (sector number)
MA 15 current memory address
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag
WLK 32 write lock switches
TIME 24 rotational latency, per word
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
Drum data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.5 RF09/RF15/RS09 Fixed Head Disk (RF)
The RF09/RF15 implements these registers:
name size comments
STA 18 status
DA 21 current disk address
MA 18 memory address (in memory)
WC 18 word count (in memory)
BUF 18 data buffer (diagnostic only)
INT 1 interrupt pending flag
WLK[0:7] 16 write lock switches for disks 0-7
TIME 24 rotational delay, per word
BURST 1 burst flag
STOP_IOE 1 stop on I/O error
The RF09/RF15 is a three-cycle data break device. If BURST = 0, word
transfers are scheduled individually; if BURST = 1, the entire transfer
occurs in a single data break.
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
RF15/RF09 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.6 TC02/TU55 and TC15/TU56 DECtape (DT)
DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0.
DECtape options include the ability to make units write enabled or write
locked.
SET DTn LOCKED set unit n write locked
SET DTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
The TC02/TC15 supports both PDP-8 format and PDP-9/11/15 format DECtape
images. ATTACH tries to determine the tape format from the DECtape image;
the user can force a particular format with switches:
-f foreign (PDP-8) format
-n native (PDP-9/11/15) format
The DECtape controller is a data-only simulator; the timing and mark
track, and block header and trailer, are not stored. Thus, the WRITE
TIMING AND MARK TRACK function is not supported; the READ ALL function
always returns the hardware standard block header and trailer; and the
WRITE ALL function dumps non-data words into the bit bucket.
The DECtape controller implements these registers:
name size comments
DTSA 12 status register A
DTSB 12 status register B
INT 1 interrupt pending flag
ENB 1 interrupt enable flag
DTF 1 DECtape flag
ERF 1 error flag
CA 18 current address (memory location 30)
WC 18 word count (memory location 31)
LTIME 31 time between lines
ACTIME 31 time to accelerate to full speed
DCTIME 31 time to decelerate to a full stop
SUBSTATE 2 read/write command substate
POS[0:7] 31 position, in lines, units 0-7
STATT[0:7] 31 unit state, units 0-7
It is critically important to maintain certain timing relationships
among the DECtape parameters, or the DECtape simulator will fail to
operate correctly.
- LTIME must be at least 6
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
2.7 TC59/TU10 Magnetic Tape (MT)
Magnetic tape options include the ability to make units write enabled or
or write locked.
SET MTn LOCKED set unit n write locked
SET MTn 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
CMD 18 command
STA 18 main status
MA 18 memory address (in memory)
WC 18 word count (in memory)
INT 1 interrupt pending flag
STOP_IOE 1 stop on I/O error
TIME 24 record delay
UST[0:7] 24 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.8 Symbolic Display and Input
The 18b PDP simulators implement symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as (sixbit) character string
-m display instruction mnemonics
The PDP-15 also recognizes an additional switch:
-p display as packed ASCII (five 7b ASCII
characters in two 18b words)
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c three character sixbit string
alphabetic instruction mnemonic
numeric octal number
The PDP-15 also recognizes an additional input mode:
# or -p five character packed ASCII string in
two 18b words
Instruction input uses standard 18b PDP assembler syntax. There are six
instruction classes: memory reference, EAE, index (PDP-15 only), IOT,
operate, and LAW.
Memory reference instructions have the format
memref {I/@} address{,X}
where I (PDP-4, PDP-7, PDP-9) /@ (PDP-15) signifies indirect reference,
and X signifies indexing (PDP-15 in page mode only). The address is an
octal number in the range 0 - 017777 (PDP-4, PDP-7, PDP-9, and PDP-15 in
bank mode) or 0 - 07777 (PDP-15 in page mode).
IOT instructions consist of single mnemonics, eg, KRB, TLS. IOT instructions
may be or'd together
iot iot iot...
IOT's may also include the number 10, signifying clear the accumulator
iot 10
The simulator does not check the legality of IOT combinations. IOT's for
which there is no opcode may be specified as IOT n, where n is an octal
number in the range 0 - 07777.
EAE instructions have the format
eae {+/- shift count}
EAE instructions may be or'd together
eae eae eae...
The simulator does not check the legality of EAE combinations. EAE's for
which there is no opcode may be specified as EAE n, where n is an octal
number in the range 0 - 037777.
Index instructions (PDP-15 only) have the format
index {immediate}
The immediate, if allowed, must be in the range of -0400 to +0377.
Operate instructions have the format
opr opr opr...
The simulator does not check the legality of the proposed combination. The
operands for MUY and DVI must be deposited explicitly.
Finally, the LAW instruction has the format
LAW immediate
where immediate is in the range of 0 to 017777.
2.9 Character Sets
The PDP-4's console was an ASR-28 Teletype; its character encoding was
Baudot. The PDP-4's line printer used a modified Hollerith character
set. The PDP-7's and PDP-9's consoles were KSR-33 Teletypes; their
character sets were basically ASCII. The PDP-7's and PDP-9's line
printers used sixbit encoding (ASCII codes 040 - 0137 masked to six
bits). The PDP-15's I/O devices were all ASCII. The following table
provides equivalences between ASCII characters and the PDP-4's I/O devices.
In the console table, FG stands for figures (upper case).
PDP-4 PDP-4
ASCII console line printer
000 - 006 none none
bell FG+024 none
010 - 011 none none
lf 010 none
013 - 014 none none
cr 002 none
016 - 037 none none
space 004 000
! FG+026 none
" FG+021 none
# FG+005 none
$ FG+062 none
% none none
& FG+013 none
' FG+032 none
( FG+036 057
) FG+011 055
* none 072
+ none 074
, FG+006 033
- FG+030 054
. FG+007 073
/ FG+027 021
0 FG+015 020
1 FG+035 001
2 FG+031 002
3 FG+020 003
4 FG+012 004
5 FG+001 005
6 FG+025 006
7 FG+034 007
8 FG+014 010
9 FG+003 011
: FG+016 none
; FG+017 none
< none 034
= none 053
> none 034
? FG+023 037
@ none {MID DOT} 040
A 030 061
B 023 062
C 016 063
D 022 064
E 020 065
F 026 066
G 013 067
H 005 070
I 014 071
J 032 041
K 036 042
L 011 043
M 007 044
N 006 045
O 003 046
P 015 047
Q 035 050
R 012 051
S 024 022
T 001 023
U 034 024
V 017 025
W 031 026
X 027 027
Y 025 030
Z 021 031
[ none none
\ none {OVERLINE} 056
] none none
^ none {UP ARROW} 035
_ none UC+040
0140 - 0177 none none

View file

@ -26,6 +26,7 @@
drm (PDP-7) Type 24 serial drum
(PDP-9) RM09 serial drum
25-Nov-01 RMS Revised interrupt structure
10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware
26-Apr-01 RMS Added device enable/disable support
14-Apr-99 RMS Changed t_addr to unsigned
@ -54,7 +55,7 @@
((double) DRM_NUMWDT)))
extern int32 M[];
extern int32 int_req, dev_enb;
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
int32 drm_da = 0; /* track address */
int32 drm_ma = 0; /* memory address */
@ -80,8 +81,8 @@ UNIT drm_unit =
REG drm_reg[] = {
{ ORDATA (DA, drm_da, 9) },
{ ORDATA (MA, drm_ma, 15) },
{ FLDATA (INT, int_req, INT_V_DRM) },
{ FLDATA (DONE, int_req, INT_V_DRM) },
{ FLDATA (INT, int_hwre[API_DRM], INT_V_DRM) },
{ FLDATA (DONE, int_hwre[API_DRM], INT_V_DRM) },
{ FLDATA (ERR, drm_err, 0) },
{ ORDATA (WLK, drm_wlk, 32) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
@ -110,9 +111,9 @@ int32 drm61 (int32 pulse, int32 AC)
int32 t;
if (pulse & 001) { /* DRSF */
if (int_req & INT_DRM) AC = AC | IOT_SKP; }
if (TST_INT (DRM)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* DRCF */
int_req = int_req & ~INT_DRM; /* clear done */
CLR_INT (DRM); /* clear done */
drm_err = 0; } /* clear error */
if (pulse & 004) { /* DRSS */
drm_da = AC & DRM_SMASK; /* load sector # */
@ -129,7 +130,7 @@ int32 t;
if (pulse & 001) { /* DRSN */
if (drm_err == 0) AC = AC | IOT_SKP; }
if (pulse & 004) { /* DRCS */
int_req = int_req & ~INT_DRM; /* clear done */
CLR_INT (DRM); /* clear done */
drm_err = 0; /* clear error */
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t < 0) t = t + DRM_NUMWDT; /* wrap around? */
@ -149,7 +150,7 @@ t_addr da;
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */
int_req = int_req | INT_DRM; /* set done */
SET_INT (DRM); /* set done */
return IORETURN (drm_stopioe, SCPE_UNATT); }
da = drm_da * DRM_NUMWDS; /* compute dev addr */
@ -163,7 +164,7 @@ for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
uptr -> hwmark = da + 1; } }
drm_ma = (drm_ma + 1) & ADDRMASK; } /* incr mem addr */
drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
int_req = int_req | INT_DRM; /* set done */
SET_INT (DRM); /* set done */
return SCPE_OK;
}
@ -172,7 +173,7 @@ return SCPE_OK;
t_stat drm_reset (DEVICE *dptr)
{
drm_ma = drm_ma = drm_err = 0;
int_req = int_req & ~INT_DRM;
CLR_INT (DRM); /* clear done */
sim_cancel (&drm_unit);
return SCPE_OK;
}
@ -181,7 +182,7 @@ return SCPE_OK;
int32 drm_iors (void)
{
return ((int_req & INT_DRM)? IOS_DRM: 0);
return (TST_INT (DRM)? IOS_DRM: 0);
}
/* Bootstrap routine */

View file

@ -26,6 +26,9 @@
dt (PDP-9) TC02/TU55 DECtape
(PDP-15) TC15/TU56 DECtape
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
Changed POS, STATT, LASTT, FLG to arrays
29-Aug-01 RMS Added casts to PDP-8 unpack routine
17-Jul-01 RMS Moved function prototype
11-May-01 RMS Fixed bug in reset
@ -83,6 +86,7 @@
#define LASTT u4 /* last time update */
#define DT_WC 030 /* word count */
#define DT_CA 031 /* current addr */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* System independent DECtape constants */
@ -227,12 +231,12 @@
#define LOG_BL 010 /* block # lblk */
#define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \
int_req = int_req | INT_DTA; \
else int_req = int_req & ~INT_DTA;
SET_INT (DTA); \
else CLR_INT (DTA);
#define ABS(x) (((x) < 0)? (-(x)): (x))
extern int32 M[];
extern int32 int_req, dev_enb;
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
extern int32 sim_switches;
int32 dtsa = 0; /* status A */
@ -267,19 +271,27 @@ extern int32 sim_is_running;
*/
UNIT dt_unit[] = {
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) } };
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) } };
REG dt_reg[] = {
{ GRDATA (DTSA, dtsa, 8, 12, 6) },
{ GRDATA (DTSB, dtsb, 8, 12, 6) },
{ FLDATA (INT, int_req, INT_V_DTA) },
{ FLDATA (INT, int_hwre[API_DTA], INT_V_DTA) },
{ FLDATA (ENB, dtsa, DTA_V_ENB) },
{ FLDATA (DTF, dtsb, DTB_V_DTF) },
{ FLDATA (ERF, dtsb, DTB_V_ERF) },
@ -291,46 +303,14 @@ REG dt_reg[] = {
{ ORDATA (SUBSTATE, dt_substate, 2) },
{ ORDATA (LOG, dt_log, 4), REG_HIDDEN },
{ DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
{ DRDATA (POS0, dt_unit[0].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS1, dt_unit[1].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS2, dt_unit[2].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS3, dt_unit[3].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS4, dt_unit[4].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS5, dt_unit[5].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS6, dt_unit[6].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS7, dt_unit[7].pos, 31), PV_LEFT + REG_RO },
{ ORDATA (STATE0, dt_unit[0].STATE, 18), REG_RO },
{ ORDATA (STATE1, dt_unit[1].STATE, 18), REG_RO },
{ ORDATA (STATE2, dt_unit[2].STATE, 18), REG_RO },
{ ORDATA (STATE3, dt_unit[3].STATE, 18), REG_RO },
{ ORDATA (STATE4, dt_unit[4].STATE, 18), REG_RO },
{ ORDATA (STATE5, dt_unit[5].STATE, 18), REG_RO },
{ ORDATA (STATE6, dt_unit[6].STATE, 18), REG_RO },
{ ORDATA (STATE7, dt_unit[7].STATE, 18), REG_RO },
{ DRDATA (LASTT0, dt_unit[0].LASTT, 32), REG_HRO },
{ DRDATA (LASTT1, dt_unit[1].LASTT, 32), REG_HRO },
{ DRDATA (LASTT2, dt_unit[2].LASTT, 32), REG_HRO },
{ DRDATA (LASTT3, dt_unit[3].LASTT, 32), REG_HRO },
{ DRDATA (LASTT4, dt_unit[4].LASTT, 32), REG_HRO },
{ DRDATA (LASTT5, dt_unit[5].LASTT, 32), REG_HRO },
{ DRDATA (LASTT6, dt_unit[6].LASTT, 32), REG_HRO },
{ DRDATA (LASTT7, dt_unit[7].LASTT, 32), REG_HRO },
{ GRDATA (FLG0, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, dt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, dt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, dt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, dt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, dt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, dt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, dt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (POS, dt_unit[0].pos, 10, 31, 0,
DT_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (STATT, dt_unit[0].STATE, 8, 18, 0,
DT_NUMDR, REG_RO) },
{ URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
DT_NUMDR, REG_HRO) },
{ URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
DT_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, INT_V_DTA), REG_HRO },
{ NULL } };
@ -366,8 +346,8 @@ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */
fnc = DTA_GETFNC (dtsa); /* get fnc */
if (((uptr -> flags) & UNIT_DIS) || /* disabled? */
(fnc >= FNC_WMRK) || /* write mark? */
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK)) ||
((fnc == FNC_WALL) && (uptr -> flags & UNIT_WLK)))
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT)) ||
((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT)))
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); /* new func */
DT_UPDINT;
@ -1046,7 +1026,7 @@ if (sim_is_active (uptr)) {
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
DT_UPDINT; }
uptr -> STATE = uptr -> pos = 0; }
if (uptr -> hwmark) { /* any data? */
if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { /* any data? */
printf ("DT: writing buffer to file\n");
rewind (uptr -> fileref); /* start of file */
if (uptr -> flags & UNIT_8FMT) { /* PDP8? */

View file

@ -27,6 +27,7 @@
(PDP-7,9) Type 647 line printer
(PDP-15) LP15 line printer
25-Nov-01 RMS Revised interrupt structure
19-Sep-01 RMS Fixed bug in 647
13-Feb-01 RMS Revised for register arrays
15-Feb-01 RMS Fixed 3 cycle data break sequence
@ -42,7 +43,7 @@
#define BPTR_MAX 40 /* pointer max */
#define LPT_BSIZE 120 /* line size */
#define BPTR_MASK 077 /* buf ptr max */
extern int32 int_req;
extern int32 int_hwre[API_HLVL+1];
int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
char lpt_buf[LPT_BSIZE + 1] = { 0 };
@ -61,9 +62,9 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ FLDATA (DONE, int_req, INT_V_LPT) },
{ FLDATA (SPC, int_req, INT_V_LPTSPC) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) },
{ DRDATA (BPTR, bptr, 6) },
{ ORDATA (STATE, lpt_iot, 6), REG_HRO },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
@ -90,8 +91,8 @@ static const char lpt_trans[64] = {
'o','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(',
'_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' };
if (pulse == 001) return (int_req & INT_LPT)? IOT_SKP + AC: AC; /* LPSF */
if (pulse == 002) int_req = int_req & ~INT_LPT; /* LPCF */
if (pulse == 001) return (TST_INT (LPT))? IOT_SKP + AC: AC; /* LPSF */
if (pulse == 002) CLR_INT (LPT); /* LPCF */
else if (pulse == 042) { /* LPLD */
if (bptr < BPTR_MAX) { /* limit test ptr */
i = bptr * 3; /* cvt to chr ptr */
@ -100,17 +101,17 @@ else if (pulse == 042) { /* LPLD */
lpt_buf[i++] = lpt_trans[AC & 077]; }
bptr = (bptr + 1) & BPTR_MASK; }
else if (pulse == 006) { /* LPSE */
int_req = int_req & ~INT_LPT; /* clear flag */
CLR_INT (LPT); /* clear flag */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
return AC;
}
int32 lpt66 (int32 pulse, int32 AC)
{
if (pulse == 001) return (int_req & INT_LPTSPC)? IOT_SKP + AC: AC; /* LSSF */
if (pulse & 002) int_req = int_req & ~INT_LPTSPC; /* LSCF */
if (pulse == 001) return (TST_INT (LPTSPC))? IOT_SKP + AC: AC; /* LSSF */
if (pulse & 002) CLR_INT (LPTSPC); /* LSCF */
if (pulse & 004) { /* LSPR */
int_req = int_req & ~INT_LPTSPC; /* clear flag */
CLR_INT (LPTSPC); /* clear flag */
lpt_iot = 020 | (AC & 07); /* space, no print */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
return AC;
@ -137,7 +138,7 @@ static const char *lpt_cc[] = {
"\f" };
if (lpt_iot & 020) { /* space? */
int_req = int_req | INT_LPTSPC; /* set flag */
SET_INT (LPTSPC); /* set flag */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
fputs (lpt_cc[lpt_iot & 07], lpt_unit.fileref); /* print cctl */
@ -146,7 +147,7 @@ if (lpt_iot & 020) { /* space? */
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
lpt_iot = 0; } /* clear state */
else { int_req = int_req | INT_LPT; /* print */
else { SET_INT (LPT); /* print */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
if (lpt_iot & 010) fputc ('\r', lpt_unit.fileref);
@ -168,7 +169,8 @@ t_stat lpt_reset (DEVICE *dptr)
{
int32 i;
int_req = int_req & ~(INT_LPT + INT_LPTSPC); /* clear flag, space */
CLR_INT (LPT); /* clear intrs */
CLR_INT (LPTSPC);
sim_cancel (&lpt_unit); /* deactivate unit */
bptr = 0; /* clear buffer ptr */
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
@ -180,14 +182,14 @@ return SCPE_OK;
int32 lpt_iors (void)
{
return ((int_req & INT_LPT)? IOS_LPT: 0) |
((int_req & INT_LPTSPC)? IOS_LPT1: 0);
return (TST_INT (LPT)? IOS_LPT: 0) |
(TST_INT (LPTSPC)? IOS_LPT1: 0);
}
#elif defined (TYPE647)
#define LPT_BSIZE 120 /* line size */
extern int32 int_req;
extern int32 int_hwre[API_HLVL+1];
int32 lpt_done = 0, lpt_ie = 1, lpt_err = 0;
int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
char lpt_buf[LPT_BSIZE] = { 0 };
@ -209,7 +211,7 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (DONE, lpt_done, 0) },
#if defined (PDP9)
{ FLDATA (ENABLE, lpt_ie, 0) },
@ -238,16 +240,16 @@ int32 i;
if (pulse == 001) return (lpt_done? IOT_SKP + AC: AC); /* LPSF */
if (pulse & 002) { /* pulse 02 */
lpt_done = 0; /* clear done */
int_req = int_req & ~INT_LPT; } /* clear int req */
CLR_INT (LPT); } /* clear int req */
if (pulse == 002) { /* LPCB */
for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0;
bptr = 0; /* reset buf ptr */
lpt_done = 1; /* set done */
if (lpt_ie) int_req = int_req | INT_LPT; } /* set int */
if (lpt_ie) SET_INT (LPT); } /* set int */
#if defined (PDP9)
if (pulse == 004) { /* LPDI */
lpt_ie = 0; /* clear int enable */
int_req = int_req & ~INT_LPT; } /* clear int req */
CLR_INT (LPT); } /* clear int req */
#endif
if ((pulse == 046) && (bptr < LPT_BSIZE)) { /* LPB3 */
lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 12) & 077);
@ -260,7 +262,7 @@ if ((pulse == 046) || (pulse == 026) || (pulse == 066)) {
lpt_buf[bptr] = lpt_buf[bptr] | (AC & 077);
bptr = bptr + 1; }
lpt_done = 1; /* set done */
if (lpt_ie) int_req = int_req | INT_LPT; } /* set int */
if (lpt_ie) SET_INT (LPT); } /* set int */
return AC;
}
@ -269,14 +271,14 @@ int32 lpt66 (int32 pulse, int32 AC)
if (pulse == 001) return (lpt_err? IOT_SKP + AC: AC); /* LPSE */
if (pulse & 002) { /* LPCF */
lpt_done = 0; /* clear done, int */
int_req = int_req & ~INT_LPT; }
CLR_INT (LPT); }
if (((pulse & 060) < 060) && (pulse & 004)) { /* LPLS, LPPB, LPPS */
lpt_iot = (pulse & 060) | (AC & 07); /* save parameters */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
#if defined (PDP9)
if (pulse == 064) { /* LPEI */
lpt_ie = 1; /* set int enable */
if (lpt_done) int_req = int_req | INT_LPT; }
if (lpt_done) SET_INT (LPT); }
#endif
return AC;
}
@ -303,7 +305,7 @@ static const char *lpt_cc[] = {
"\f" };
lpt_done = 1;
if (lpt_ie) int_req = int_req | INT_LPT; /* set flag */
if (lpt_ie) SET_INT (LPT); /* set flag */
if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
lpt_err = 1; /* set error */
return IORETURN (lpt_stopioe, SCPE_UNATT); }
@ -338,7 +340,7 @@ int32 i;
lpt_done = 0; /* clear done */
lpt_err = (lpt_unit.flags & UNIT_ATT)? 0: 1; /* compute error */
lpt_ie = 1; /* set enable */
int_req = int_req & ~INT_LPT; /* clear int */
CLR_INT (LPT); /* clear int */
sim_cancel (&lpt_unit); /* deactivate unit */
bptr = 0; /* clear buffer ptr */
lpt_iot = 0; /* clear state */
@ -391,7 +393,7 @@ return detach_unit (uptr);
#define STA_CLR 0003777 /* always clear */
extern int32 M[];
extern int32 int_req;
extern int32 int_hwre[API_HLVL+1];
int32 lpt_sta = 0, lpt_ie = 1, lpt_stopioe = 0;
int32 mode = 0, lcnt = 0, bptr = 0;
char lpt_buf[LPT_BSIZE] = { 0 };
@ -413,7 +415,7 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ ORDATA (STA, lpt_sta, 18) },
{ ORDATA (CA, M[LPT_CA], 18) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (ENABLE, lpt_ie, 0) },
{ DRDATA (LCNT, lcnt, 9) },
{ DRDATA (BPTR, bptr, 8) },
@ -523,8 +525,8 @@ int32 lpt_updsta (int32 new)
lpt_sta = (lpt_sta | new) & ~(STA_CLR | STA_ERR | STA_BUSY);
if (lpt_sta & STA_EFLGS) lpt_sta = lpt_sta | STA_ERR; /* update errors */
if (sim_is_active (&lpt_unit)) lpt_sta = lpt_sta | STA_BUSY;
if (lpt_ie && (lpt_sta & STA_DON)) int_req = int_req | INT_LPT;
else int_req = int_req & ~INT_LPT; /* update int */
if (lpt_ie && (lpt_sta & STA_DON)) SET_INT (LPT);
else CLR_INT (LPT); /* update int */
return lpt_sta;
}

View file

@ -26,6 +26,9 @@
mt (PDP-9) TC59 magtape
(PDP-15) TC59D magtape
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
Changed UST, POS, FLG to arrays
26-Apr-01 RMS Added device enable/disable support
15-Feb-01 RMS Fixed 3-cycle data break sequence
04-Oct-98 RMS V2.4 magtape format
@ -59,6 +62,7 @@
#define DBMASK (DBSIZE - 1)
#define MT_WC 032 /* word count */
#define MT_CA 033 /* current addr */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Command/unit - mt_cu */
@ -109,7 +113,7 @@
/* error flags */
extern int32 M[];
extern int32 int_req, dev_enb;
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
int32 mt_cu = 0; /* command/unit */
int32 mt_sta = 0; /* status register */
@ -131,55 +135,28 @@ UNIT *mt_busy (void);
*/
UNIT mt_unit[] = {
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } };
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } };
REG mt_reg[] = {
{ ORDATA (STA, mt_sta, 18) },
{ ORDATA (CMD, mt_cu, 18) },
{ ORDATA (WC, M[MT_WC], 18) },
{ ORDATA (CA, M[MT_CA], 18) },
{ FLDATA (INT, int_req, INT_V_MTA) },
{ FLDATA (INT, int_hwre[API_MTA], INT_V_MTA) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ DRDATA (TIME, mt_time, 24), PV_LEFT },
{ ORDATA (UST0, mt_unit[0].USTAT, 18) },
{ ORDATA (UST1, mt_unit[1].USTAT, 18) },
{ ORDATA (UST2, mt_unit[2].USTAT, 18) },
{ ORDATA (UST3, mt_unit[3].USTAT, 18) },
{ ORDATA (UST4, mt_unit[4].USTAT, 18) },
{ ORDATA (UST5, mt_unit[5].USTAT, 18) },
{ ORDATA (UST6, mt_unit[6].USTAT, 18) },
{ ORDATA (UST7, mt_unit[7].USTAT, 18) },
{ DRDATA (POS0, mt_unit[0].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS1, mt_unit[1].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS2, mt_unit[2].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS3, mt_unit[3].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS4, mt_unit[4].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS5, mt_unit[5].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS6, mt_unit[6].pos, 31), PV_LEFT + REG_RO },
{ DRDATA (POS7, mt_unit[7].pos, 31), PV_LEFT + REG_RO },
{ GRDATA (FLG0, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, mt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, mt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, mt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, mt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, mt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, mt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, mt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, 31, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
MT_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, INT_V_MTA), REG_HRO },
{ NULL } };
@ -220,7 +197,7 @@ if (pulse == 004) { /* MTGO */
f = GET_CMD (mt_cu); /* get function */
if (mt_busy () || (sim_is_active (uptr)) ||
(((f == FN_SPACER) || (f == FN_REWIND)) & (uptr -> pos == 0)) ||
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WLK))
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT))
|| ((uptr -> flags & UNIT_ATT) == 0) || (f == FN_NOP))
mt_sta = mt_sta | STA_ILL; /* illegal op flag */
else { if (f == FN_REWIND) uptr -> USTAT = STA_REW; /* rewind? */
@ -259,7 +236,7 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
return IORETURN (mt_stopioe, SCPE_UNATT); }
if ((f == FN_WRITE) || (f == FN_WREOF)) { /* write? */
if (uptr -> flags & UNIT_WLK) { /* write locked? */
if (uptr -> flags & UNIT_WPRT) { /* write locked? */
mt_updcsta (uptr, STA_ILL); /* illegal operation */
return SCPE_OK; }
mt_cu = mt_cu & ~CU_ERASE; } /* clear erase flag */
@ -404,8 +381,8 @@ mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) |
(uptr -> USTAT & STA_DYN) | new;
if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR; /* error flag */
if ((mt_sta & (STA_ERR | STA_DON)) && ((mt_cu & CU_IE) == 0))
int_req = int_req | INT_MTA;
else int_req = int_req & ~INT_MTA; /* int request */
SET_INT (MTA);
else CLR_INT (MTA); /* int request */
return mt_sta;
}

View file

@ -26,6 +26,8 @@
rf (PDP-9) RF09/RF09
(PDP-15) RF15/RS09
25-Nov-01 RMS Revised interrupt structure
24-Nov-01 RMS Changed WLK to array
26-Apr-01 RMS Added device enable/disable support
15-Feb-01 RMS Fixed 3 cycle data break sequencing
30-Nov-99 RMS Added non-zero requirement to rf_time
@ -85,7 +87,7 @@
#define RF_BUSY (sim_is_active (&rf_unit))
extern int32 M[];
extern int32 int_req, dev_enb;
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
@ -115,15 +117,8 @@ REG rf_reg[] = {
{ ORDATA (WC, M[RF_WC], 18) },
{ ORDATA (CA, M[RF_CA], 18) },
{ ORDATA (BUF, rf_dbuf, 18) },
{ FLDATA (INT, int_req, INT_V_RF) },
{ ORDATA (WLK0, rf_wlk[0], 16) },
{ ORDATA (WLK1, rf_wlk[1], 16) },
{ ORDATA (WLK2, rf_wlk[2], 16) },
{ ORDATA (WLK3, rf_wlk[3], 16) },
{ ORDATA (WLK4, rf_wlk[4], 16) },
{ ORDATA (WLK5, rf_wlk[5], 16) },
{ ORDATA (WLK6, rf_wlk[6], 16) },
{ ORDATA (WLK7, rf_wlk[7], 16) },
{ FLDATA (INT, int_hwre[API_RF], INT_V_RF) },
{ BRDATA (WLK, rf_wlk, 8, 16, RF_NUMDK) },
{ DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
@ -244,8 +239,8 @@ int32 rf_updsta (int32 new)
rf_sta = (rf_sta | new) & ~(RFS_ERR | RFS_CLR);
if (rf_sta & RFS_EFLGS) rf_sta = rf_sta | RFS_ERR;
if ((rf_sta & (RFS_ERR | RFS_DON)) && (rf_sta & RFS_IE))
int_req = int_req | INT_RF;
else int_req = int_req & ~INT_RF;
SET_INT (RF);
else CLR_INT (RF);
return rf_sta;
}

View file

@ -25,6 +25,9 @@
rp RP15/RP02 disk pack
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
Changed FLG to array
26-Apr-01 RMS Added device enable/disable support
14-Apr-99 RMS Changed t_addr to unsigned
29-Jun-96 RMS Added unit enable/disable support
@ -43,9 +46,10 @@
/* Unit specific flags */
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_W_UF 2 /* user flags width */
#define UNIT_HWLK (1u << UNIT_V_HWLK)
#define UNIT_WLK (1u << UNIT_V_WLK)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Parameters in the unit descriptor */
@ -124,7 +128,7 @@
#define MAX(x,y) (((x) > (y))? (x): (y))
extern int32 M[];
extern int32 int_req, dev_enb, nexm;
extern int32 int_hwre[API_HLVL+1], dev_enb, nexm;
extern UNIT cpu_unit;
int32 rp_sta = 0; /* status A */
int32 rp_stb = 0; /* status B */
@ -165,33 +169,19 @@ REG rp_reg[] = {
{ ORDATA (DA, rp_da, 18) },
{ ORDATA (MA, rp_ma, 18) },
{ ORDATA (WC, rp_wc, 18) },
{ FLDATA (INT, int_req, INT_V_RP) },
{ FLDATA (INT, int_hwre[API_RP], INT_V_RP) },
{ FLDATA (BUSY, rp_busy, 0) },
{ FLDATA (STOP_IOE, rp_stopioe, 0) },
{ DRDATA (STIME, rp_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rp_rwait, 24), PV_LEFT },
{ GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
RP_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO },
{ NULL } };
MTAB rp_mod[] = {
{ UNIT_HWLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
{ UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ 0 } };
DEVICE rp_dev = {
@ -315,6 +305,10 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */
rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */
return IORETURN (rp_stopioe, SCPE_UNATT); }
if ((f == FN_WRITE) && (uptr -> flags & UNIT_WPRT)) { /* write locked? */
rp_updsta (STA_DON | STA_WPE, 0); /* error */
return SCPE_OK; }
if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0);
if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0);
if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0);
@ -381,7 +375,7 @@ UNIT *uptr;
uptr = rp_dev.units + GET_UNIT (rp_sta);
rp_sta = (rp_sta & ~(STA_DYN | STA_ERR)) | newa;
rp_stb = (rp_stb & ~STB_DYN) | newb;
if (uptr -> flags & UNIT_HWLK) rp_sta = rp_sta | STA_SUWP;
if (uptr -> flags & UNIT_WPRT) rp_sta = rp_sta | STA_SUWP;
if ((uptr -> flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR;
else if (sim_is_active (uptr)) {
f = (uptr -> FUNC) & STA_M_FUNC;
@ -390,8 +384,8 @@ else if (sim_is_active (uptr)) {
else if (uptr -> CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI;
if ((rp_sta & STA_EFLGS) || (rp_stb & STB_EFLGS)) rp_sta = rp_sta | STA_ERR;
if (((rp_sta & (STA_ERR | STA_DON)) && (rp_sta & STA_IED)) ||
((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) int_req = int_req | INT_RP;
else int_req = int_req & ~INT_RP;
((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) SET_INT (RP);
else CLR_INT (RP);
return;
}
@ -403,7 +397,7 @@ int32 i;
UNIT *uptr;
rp_sta = rp_stb = rp_da = rp_wc = rp_ma = rp_busy = 0;
int_req = int_req & ~INT_RP;
CLR_INT (RP);
for (i = 0; i < RP_NUMDR; i++) {
uptr = rp_dev.units + i;
sim_cancel (uptr);

View file

@ -29,6 +29,8 @@
tto teleprinter
clk clock
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
17-Sep-01 RMS Removed multiconsole support
07-Sep-01 RMS Added terminal multiplexor support
17-Jul-01 RMS Moved function prototype
@ -47,7 +49,7 @@
#include <ctype.h>
extern int32 M[];
extern int32 int_req, saved_PC;
extern int32 int_hwre[API_HLVL+1], saved_PC;
extern UNIT cpu_unit;
int32 clk_state = 0;
int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0;
@ -83,8 +85,8 @@ t_stat ptr_boot (int32 unitno);
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (INT, int_req, INT_V_CLK) },
{ FLDATA (DONE, int_req, INT_V_CLK) },
{ FLDATA (INT, int_hwre[API_CLK], INT_V_CLK) },
{ FLDATA (DONE, int_hwre[API_CLK], INT_V_CLK) },
{ FLDATA (ENABLE, clk_state, 0) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
@ -104,12 +106,13 @@ DEVICE clk_dev = {
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 18) },
{ FLDATA (INT, int_req, INT_V_PTR) },
{ FLDATA (DONE, int_req, INT_V_PTR) },
{ FLDATA (INT, int_hwre[API_PTR], INT_V_PTR) },
{ FLDATA (DONE, int_hwre[API_PTR], INT_V_PTR) },
#if defined (IOS_PTRERR)
{ FLDATA (ERR, ptr_err, 0) },
#endif
@ -137,8 +140,8 @@ UNIT ptp_unit = {
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (INT, int_req, INT_V_PTP) },
{ FLDATA (DONE, int_req, INT_V_PTP) },
{ FLDATA (INT, int_hwre[API_PTP], INT_V_PTP) },
{ FLDATA (DONE, int_hwre[API_PTP], INT_V_PTP) },
#if defined (IOS_PTPERR)
{ FLDATA (ERR, ptp_err, 0) },
#endif
@ -205,8 +208,8 @@ UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX, 0), KBD_POLL_WAIT };
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, TTI_WIDTH) },
{ FLDATA (INT, int_req, INT_V_TTI) },
{ FLDATA (DONE, int_req, INT_V_TTI) },
{ FLDATA (INT, int_hwre[API_TTI], INT_V_TTI) },
{ FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) },
#if defined (KSR28)
{ ORDATA (TTI_STATE, tti_state, (TTI_WIDTH + 3)), REG_HRO },
#else
@ -264,8 +267,8 @@ UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
{ FLDATA (INT, int_req, INT_V_TTO) },
{ FLDATA (DONE, int_req, INT_V_TTO) },
{ FLDATA (INT, int_hwre[API_TTO], INT_V_TTO) },
{ FLDATA (DONE, int_hwre[API_TTO], INT_V_TTO) },
#if defined (KSR28)
{ FLDATA (TTO_STATE, tto_state, 0), REG_HRO },
#endif
@ -291,10 +294,10 @@ DEVICE tto_dev = {
int32 clk (int32 pulse, int32 AC)
{
if (pulse & 001) { /* CLSF */
if (int_req & INT_CLK) AC = AC | IOT_SKP; }
if (TST_INT (CLK)) AC = AC | IOT_SKP; }
if (pulse & 004) { /* CLON/CLOF */
if (pulse & 040) { /* CLON */
int_req = int_req & ~INT_CLK; /* clear flag */
CLR_INT (CLK); /* clear flag */
clk_state = 1; /* clock on */
if (!sim_is_active (&clk_unit)) /* already on? */
sim_activate (&clk_unit, /* start, calibr */
@ -311,7 +314,7 @@ int32 t;
if (clk_state) { /* clock on? */
M[7] = (M[7] + 1) & 0777777; /* incr counter */
if (M[7] == 0) int_req = int_req | INT_CLK; /* ovrflo? set flag */
if (M[7] == 0) SET_INT (CLK); /* ovrflo? set flag */
t = sim_rtc_calb (clk_tps); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
tmxr_poll = t; } /* set mux poll */
@ -322,7 +325,7 @@ return SCPE_OK;
t_stat clk_reset (DEVICE *dptr)
{
int_req = int_req & ~INT_CLK; /* clear flag */
CLR_INT (CLK); /* clear flag */
clk_state = 0; /* clock off */
sim_cancel (&clk_unit); /* stop clock */
tmxr_poll = clk_unit.wait; /* set mux poll */
@ -333,18 +336,18 @@ return SCPE_OK;
int32 std_iors (void)
{
return ((int_req & INT_CLK)? IOS_CLK: 0) |
((int_req & INT_PTR)? IOS_PTR: 0) |
((int_req & INT_PTP)? IOS_PTP: 0) |
((int_req & INT_TTI)? IOS_TTI: 0) |
((int_req & INT_TTO)? IOS_TTO: 0) |
return ((TST_INT (CLK)? IOS_CLK: 0) |
(TST_INT (PTR)? IOS_PTR: 0) |
(TST_INT (PTP)? IOS_PTP: 0) |
(TST_INT (TTI)? IOS_TTI: 0) |
(TST_INT (TTO)? IOS_TTO: 0) |
#if defined (IOS_PTRERR)
(ptr_err? IOS_PTRERR: 0) |
#endif
#if defined (IOS_PTPERR)
(ptp_err? IOS_PTPERR: 0) |
#endif
(clk_state? IOS_CLKON: 0);
(clk_state? IOS_CLKON: 0));
}
/* Paper tape reader: IOT routine */
@ -352,13 +355,13 @@ return ((int_req & INT_CLK)? IOS_CLK: 0) |
int32 ptr (int32 pulse, int32 AC)
{
if (pulse & 001) { /* RSF */
if (int_req & INT_PTR) AC = AC | IOT_SKP; }
if (TST_INT (PTR)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* RRB, RCF */
int_req = int_req & ~INT_PTR; /* clear done */
CLR_INT (PTR); /* clear done */
AC = AC | ptr_unit.buf; } /* return buffer */
if (pulse & 004) { /* RSA, RSB */
ptr_state = (pulse & 040)? 18: 0; /* set mode */
int_req = int_req & ~INT_PTR; /* clear done */
CLR_INT (PTR); /* clear done */
ptr_unit.buf = 0; /* clear buffer */
sim_activate (&ptr_unit, ptr_unit.wait); }
return AC;
@ -372,13 +375,13 @@ int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
#if defined (IOS_PTRERR)
int_req = int_req | INT_PTR; /* if err, set int */
SET_INT (PTR); /* if err, set int */
ptr_err = 1;
#endif
return IORETURN (ptr_stopioe, SCPE_UNATT); }
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
#if defined (IOS_PTRERR)
int_req = int_req | INT_PTR; /* if err, set done */
SET_INT (PTR); /* if err, set done */
ptr_err = 1;
#endif
if (feof (ptr_unit.fileref)) {
@ -391,7 +394,7 @@ if (ptr_state == 0) ptr_unit.buf = temp & 0377; /* alpha */
else if (temp & 0200) { /* binary */
ptr_state = ptr_state - 6;
ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); }
if (ptr_state == 0) int_req = int_req | INT_PTR; /* if done, set flag */
if (ptr_state == 0) SET_INT (PTR); /* if done, set flag */
else sim_activate (&ptr_unit, ptr_unit.wait); /* else restart */
ptr_unit.pos = ptr_unit.pos + 1;
return SCPE_OK;
@ -403,7 +406,7 @@ t_stat ptr_reset (DEVICE *dptr)
{
ptr_state = 0; /* clear state */
ptr_unit.buf = 0;
int_req = int_req & ~INT_PTR; /* clear flag */
CLR_INT (PTR); /* clear flag */
ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1;
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
@ -605,10 +608,10 @@ return SCPE_ARG;
int32 ptp (int32 pulse, int32 AC)
{
if (pulse & 001) { /* PSF */
if (int_req & INT_PTP) AC = AC | IOT_SKP; }
if (pulse & 002) int_req = int_req & ~INT_PTP; /* PCF */
if (TST_INT (PTP)) AC = AC | IOT_SKP; }
if (pulse & 002) CLR_INT (PTP); /* PCF */
if (pulse & 004) { /* PSA, PSB, PLS */
int_req = int_req & ~INT_PTP; /* clear flag */
CLR_INT (PTP); /* clear flag */
ptp_unit.buf = (pulse & 040)? /* load punch buf */
(AC & 077) | 0200: AC & 0377; /* bin or alpha */
sim_activate (&ptp_unit, ptp_unit.wait); } /* activate unit */
@ -619,7 +622,7 @@ return AC;
t_stat ptp_svc (UNIT *uptr)
{
int_req = int_req | INT_PTP; /* set done flag */
SET_INT (PTP); /* set done flag */
if ((ptp_unit.flags & UNIT_ATT) == 0) { /* not attached? */
ptp_err = 1; /* set error */
return IORETURN (ptp_stopioe, SCPE_UNATT); }
@ -637,7 +640,7 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
int_req = int_req & ~INT_PTP; /* clear flag */
CLR_INT (PTP); /* clear flag */
ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
@ -667,9 +670,9 @@ return detach_unit (uptr);
int32 tti (int32 pulse, int32 AC)
{
if (pulse & 001) { /* KSF */
if (int_req & INT_TTI) AC = AC | IOT_SKP; }
if (TST_INT (TTI)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* KRB */
int_req = int_req & ~INT_TTI; /* clear flag */
CLR_INT (TTI); /* clear flag */
AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */
return AC;
}
@ -705,7 +708,7 @@ if ((tti_unit.flags & UNIT_HDX) &&
tto_unit.pos = tto_unit.pos + 1; }
tti_unit.buf = temp | 0200; /* got char */
#endif
int_req = int_req | INT_TTI; /* set flag */
SET_INT (TTI); /* set flag */
tti_unit.pos = tti_unit.pos + 1;
return SCPE_OK;
}
@ -716,7 +719,7 @@ t_stat tti_reset (DEVICE *dptr)
{
tti_unit.buf = 0; /* clear buffer */
tti_state = 0; /* clear state */
int_req = int_req & ~INT_TTI; /* clear flag */
CLR_INT (TTI); /* clear flag */
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
return SCPE_OK;
}
@ -726,8 +729,8 @@ return SCPE_OK;
int32 tto (int32 pulse, int32 AC)
{
if (pulse & 001) { /* TSF */
if (int_req & INT_TTO) AC = AC | IOT_SKP; }
if (pulse & 002) int_req = int_req & ~INT_TTO; /* clear flag */
if (TST_INT (TTO)) AC = AC | IOT_SKP; }
if (pulse & 002) CLR_INT (TTO); /* clear flag */
if (pulse & 004) { /* load buffer */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
tto_unit.buf = AC & TTO_MASK; } /* load buffer */
@ -740,7 +743,7 @@ t_stat tto_svc (UNIT *uptr)
{
int32 out, temp;
int_req = int_req | INT_TTO; /* set flag */
SET_INT (TTO); /* set flag */
#if defined (KSR28) /* Baudot... */
if (tto_unit.buf == BAUDOT_FIGURES) { /* set figures? */
tto_state = TTO_FIGURES;
@ -766,7 +769,7 @@ t_stat tto_reset (DEVICE *dptr)
{
tto_unit.buf = 0; /* clear buffer */
tto_state = 0; /* clear state */
int_req = int_req & ~INT_TTO; /* clear flag */
CLR_INT (TTO); /* clear flag */
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}

Some files were not shown because too many files have changed in this diff Show more