Notes For V3.3

RESTRICTION: The HP DS disk is not debugged.  DO NOT enable this
feature for normal operations.
WARNING: Massive changes in the PDP-11 make all previous SAVEd
file obsolete.  Do not attempt to use a PDP-11 SAVE file from a
prior release with V3.3!

1. New Features in 3.3

1.1 SCP

- Added -p (powerup) qualifier to RESET
- Changed SET <unit> ONLINE/OFFLINE to SET <unit> ENABLED/DISABLED
- Moved SET DEBUG under SET CONSOLE hierarchy
- Added optional parameter value to SHOW command
- Added output file option to SHOW command

1.2 PDP-11

- Separated RH Massbus adapter from RP controller
- Added TU tape support
- Added model emulation framework
- Added model details

1.3 VAX

- Separated out CVAX-specific features from core instruction simulator
- Implemented capability for CIS, octaword, compatibility mode instructions
- Added instruction display and parse for compatibility mode
- Changed SET CPU VIRTUAL=n to SHOW CPU VIRTUAL=n
- Added =n optional parameter to SHOW CPU HISTORY

1.4 Unibus/Qbus simulators (PDP-11, VAX, PDP-10)

- Simplified DMA API's
- Modified DMA peripherals to use simplified API's

1.5 HP2100 (all changes from Dave Bryan)

CPU	- moved MP into its own device; added MP option jumpers
	- modified DMA to allow disabling
	- modified SET CPU 2100/2116 to truncate memory > 32K
	- added -F switch to SET CPU to force memory truncation
	- modified WRU to be REG_HRO
	- added BRK and DEL to save console settings

DR	- provided protected tracks and "Writing Enabled" status bit
	- added "parity error" status return on writes for 12606
	- added track origin test for 12606
	- added SCP test for 12606
	- added "Sector Flag" status bit
	- added "Read Inhibit" status bit for 12606
	- added TRACKPROT modifier

LPS	- added SET OFFLINE/ONLINE, POWEROFF/POWERON
	- added fast/realistic timing
	- added debug printouts

LPT	- added SET OFFLINE/ONLINE, POWEROFF/POWERON

PTR	- added paper tape loop mode, DIAG/READER modifiers to PTR
	- added PV_LEFT to PTR TRLLIM register

CLK	- modified CLK to permit disable

1.6 IBM 1401, IBM 1620, Interdata 16b, SDS 940, PDP-10

- Added instruction history

1.7 H316, PDP-15, PDP-8

- Added =n optional value to SHOW CPU HISTORY

2. Bugs Fixed in 3.3

2.1 SCP

- Fixed comma-separated SET options (from Dave Bryan)
- Fixed duplicate HELP displays with user-specified commands

2.2 PDP-10

- Replicated RP register state per drive
- Fixed TU to set FCE on short record
- Fixed TU to return bit<15> in drive type
- Fixed TU format specification, 1:0 are don't cares
- Fixed TU handling of TMK status
- Fixed TU handling of DONE, ATA at end of operation
- Implemented TU write check

2.3 PDP-11

- Replicated RP register state per drive
- Fixed RQ, TQ to report correct controller type and stage 1 configuration
  flags on a Unibus system
- Fixed HK CS2<output_ready> flag

2.4 VAX

- Fixed parsing of indirect displacement modes in instruction input

2.5 HP2100 (all fixes from Dave Bryan)

CPU	- fixed S-register behavior on 2116
	- fixed LIx/MIx behavior for DMA on 2116 and 2100
	- fixed LIx/MIx behavior for empty I/O card slots

DP	- fixed enable/disable from either device
	- fixed ANY ERROR status for 12557A interface
	- fixed unattached drive status for 12557A interface
	- status cmd without prior STC DC now completes (12557A)
	- OTA/OTB CC on 13210A interface also does CLC CC
	- fixed RAR model
	- fixed seek check on 13210 if sector out of range

DQ	- fixed enable/disable from either device
	- shortened xtime from 5 to 3 (drive avg 156KW/second)
	- fixed not ready/any error status
	- fixed RAR model

DR	- fixed enable/disable from either device
	- fixed sector return in status word
	- fixed DMA last word write, incomplete sector fill value
	- fixed 12610 SFC operation
	- fixed current-sector determination

IPL	- fixed enable/disable from either device

LPS	- fixed status returns for error conditions
	- fixed handling of non-printing characters
	- fixed handling of characters after column 80
	- improved timing model accuracy for RTE

LPT	- fixed status returns for error conditions
	- fixed TOF handling so form remains on line 0

SYS	- fixed display of CCA/CCB/CCE instructions

2.5 PDP-15

FPP	- fixed URFST to mask low 9b of fraction
	- fixed exception PC setting
This commit is contained in:
Bob Supnik 2004-11-23 15:49:00 -08:00 committed by Mark Pizzolato
parent 2e00e1122f
commit b6393b36b4
131 changed files with 20920 additions and 4845 deletions

View file

@ -1,53 +0,0 @@
Notes For V3.2-3
RESTRICTION: The PDP-15 FPP is only partially debugged. Do NOT
enable this feature for normal operations.
RESTRICTION: The HP DS disk is not debugged. DO NOT enable this
feature for normal operations.
1. New Features in 3.2-3
1.1 SCP
- Added ECHO command (from Dave Bryan)
2. Bugs Fixed in 3.2-2
2.1 SCP
- Qualified RESTORE detach with SIM_SW_REST
- Fixed OS/2 issues in sim_console.c and sim_sock.h
2.2 HP2100 (all from Dave Bryan)
- Changed CPU error stops to report PC not PC + 1
- Fixed CLC to DR to stop operation in progress
- Functional and timing fixes to DP
> controller sets ATN for all commands except read status
> controller resumes polling for ATN interrupts after read status
> check status on unattached drive set busy and not ready
> check status tests wrong unit for write protect status
> drive on line sets ATN, will set FLG if polling
- Functional and timing fixes to MS
> fixed erroneous execution of rejected command
> fixed erroneous execution of select-only command
> fixed erroneous execution of clear command
> fixed odd byte handling for read
> fixed spurious odd byte status on 13183A EOF
> modified handling of end of medium
> added detailed timing, with fast and realistic modes
> added reel sizes to simulate end of tape
> added debug printouts
- Modified MT handling of end of medium
- Added tab to TTY control char set
2.3 VAX
- VAX RQ controllers start LUNs at 0 (from Andreas Cejna)
- Added compatibility mode definitions
- Fixed EMODD, EMODG to probe second longword of quadword destination

143
0readme_33.txt Normal file
View file

@ -0,0 +1,143 @@
Notes For V3.3
RESTRICTION: The HP DS disk is not debugged. DO NOT enable this
feature for normal operations.
WARNING: Massive changes in the PDP-11 make all previous SAVEd
file obsolete. Do not attempt to use a PDP-11 SAVE file from a
prior release with V3.3!
1. New Features in 3.3
1.1 SCP
- Added -p (powerup) qualifier to RESET
- Changed SET <unit> ONLINE/OFFLINE to SET <unit> ENABLED/DISABLED
- Moved SET DEBUG under SET CONSOLE hierarchy
- Added optional parameter value to SHOW command
- Added output file option to SHOW command
1.2 PDP-11
- Separated RH Massbus adapter from RP controller
- Added TU tape support
- Added model emulation framework
- Added model details
1.3 VAX
- Separated out CVAX-specific features from core instruction simulator
- Implemented capability for CIS, octaword, compatibility mode instructions
- Added instruction display and parse for compatibility mode
- Changed SET CPU VIRTUAL=n to SHOW CPU VIRTUAL=n
- Added =n optional parameter to SHOW CPU HISTORY
1.4 Unibus/Qbus simulators (PDP-11, VAX, PDP-10)
- Simplified DMA API's
- Modified DMA peripherals to use simplified API's
1.5 HP2100 (all changes from Dave Bryan)
CPU - moved MP into its own device; added MP option jumpers
- modified DMA to allow disabling
- modified SET CPU 2100/2116 to truncate memory > 32K
- added -F switch to SET CPU to force memory truncation
- modified WRU to be REG_HRO
- added BRK and DEL to save console settings
DR - provided protected tracks and "Writing Enabled" status bit
- added "parity error" status return on writes for 12606
- added track origin test for 12606
- added SCP test for 12606
- added "Sector Flag" status bit
- added "Read Inhibit" status bit for 12606
- added TRACKPROT modifier
LPS - added SET OFFLINE/ONLINE, POWEROFF/POWERON
- added fast/realistic timing
- added debug printouts
LPT - added SET OFFLINE/ONLINE, POWEROFF/POWERON
PTR - added paper tape loop mode, DIAG/READER modifiers to PTR
- added PV_LEFT to PTR TRLLIM register
CLK - modified CLK to permit disable
1.6 IBM 1401, IBM 1620, Interdata 16b, SDS 940, PDP-10
- Added instruction history
1.7 H316, PDP-15, PDP-8
- Added =n optional value to SHOW CPU HISTORY
2. Bugs Fixed in 3.3
2.1 SCP
- Fixed comma-separated SET options (from Dave Bryan)
- Fixed duplicate HELP displays with user-specified commands
2.2 PDP-10
- Replicated RP register state per drive
- Fixed TU to set FCE on short record
- Fixed TU to return bit<15> in drive type
- Fixed TU format specification, 1:0 are don't cares
- Fixed TU handling of TMK status
- Fixed TU handling of DONE, ATA at end of operation
- Implemented TU write check
2.3 PDP-11
- Replicated RP register state per drive
- Fixed RQ, TQ to report correct controller type and stage 1 configuration
flags on a Unibus system
- Fixed HK CS2<output_ready> flag
2.4 VAX
- Fixed parsing of indirect displacement modes in instruction input
2.5 HP2100 (all fixes from Dave Bryan)
CPU - fixed S-register behavior on 2116
- fixed LIx/MIx behavior for DMA on 2116 and 2100
- fixed LIx/MIx behavior for empty I/O card slots
DP - fixed enable/disable from either device
- fixed ANY ERROR status for 12557A interface
- fixed unattached drive status for 12557A interface
- status cmd without prior STC DC now completes (12557A)
- OTA/OTB CC on 13210A interface also does CLC CC
- fixed RAR model
- fixed seek check on 13210 if sector out of range
DQ - fixed enable/disable from either device
- shortened xtime from 5 to 3 (drive avg 156KW/second)
- fixed not ready/any error status
- fixed RAR model
DR - fixed enable/disable from either device
- fixed sector return in status word
- fixed DMA last word write, incomplete sector fill value
- fixed 12610 SFC operation
- fixed current-sector determination
IPL - fixed enable/disable from either device
LPS - fixed status returns for error conditions
- fixed handling of non-printing characters
- fixed handling of characters after column 80
- improved timing model accuracy for RTE
LPT - fixed status returns for error conditions
- fixed TOF handling so form remains on line 0
SYS - fixed display of CCA/CCB/CCE instructions
2.5 PDP-15
FPP - fixed URFST to mask low 9b of fraction
- fixed exception PC setting

View file

@ -173,7 +173,7 @@ return (SCPE_OK);
status = error code status = error code
*/ */
int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val, int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
UNIT *uptr, int32 sw) UNIT *uptr, int32 sw)
{ {
int32 cflag, c1, c2, inst, adr; int32 cflag, c1, c2, inst, adr;
@ -220,7 +220,7 @@ return -(oplen[inst] - 1);
status = error status status = error status
*/ */
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw) int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
{ {
int32 cflag, i = 0, j, r; int32 cflag, i = 0, j, r;
char gbuf[CBUFSIZE]; char gbuf[CBUFSIZE];
@ -229,11 +229,11 @@ cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++; /* absorb spaces */ while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (unsigned int) cptr[0]; val[0] = (uint32) cptr[0];
return SCPE_OK; } return SCPE_OK; }
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1]; val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1];
return SCPE_OK; } return SCPE_OK; }
/* An instruction: get opcode (all characters until null, comma, /* An instruction: get opcode (all characters until null, comma,

View file

@ -1,914 +0,0 @@
Altair 8800 Simulator with Z80 support
======================================
0. Revision History
- 26-Jan-2004, Peter Schorn (added support for t-state stepping)
- 25-Feb-2003, Peter Schorn (added support for real time simulation)
- 9-Oct-2002, Peter Schorn (added support for simulated hard disk)
- 28-Sep-2002, Peter Schorn (number of tracks per disk can be configured)
- 19-Sep-2002, Peter Schorn (added WARNROM feature)
- 31-Aug-2002, Peter Schorn (added extended ROM features suggested
by Scott LaBombard)
- 4-May-2002, Peter Schorn (added description of MP/M II sample software)
- 28-Apr-2002, Peter Schorn (added periodic timer interrupts and three
additional consoles)
- 15-Apr-2002, Peter Schorn (added memory breakpoint)
- 7-Apr-2002, Peter Schorn (added ROM / NOROM switch)
Original version of this document written by Charles E Owen
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
...... (in 4K steps)
SET CPU 64K All these set various CPU memory configurations.
SET CPU BANKED Enables the banked memory support. The simulated memory
has eight banks with address range 0..'common' (see registers below)
and a common area from 'common' to 0xfff which is common to all
banks. The currently active bank is determined by register 'bank'
(see below). You can only switch to banked memory if the memory
is set to 64K. The banked memory is used by CP/M 3.
SET CPU NONBANKED Disables banked memory support.
SET CPU ROM Enables the ROM from address 'ROMLOW' to 'ROMHIGH'
(see below under CPU Registers) and prevents write access
to these locations. This is the default setting.
SET CPU NOROM Disables the ROM.
SET CPU ALTAIRROM Enables the slightly modified but downwards compatible
Altair boot ROM at addresses 0FF00 to 0FFFF. This is the default.
SET CPU NOALTAIRROM Disables standard Altair ROM behavior.
SET CPU WARNROM Enables warning messages to be printed when the CPU
attempts to write into ROM or into non-existing memory. Also prints
a warning message if the CPU attempts to read from non-existing
memory.
SET CPU NOWARNROM Suppreses all warning message of "WARNROM". Note that
some software tries on purpose to write to ROM in order to detect
the available RAM.
The BOOT EPROM card starts at address 0FF00 if it has been enabled by
'SET CPU ALTAIRROM'. Jumping to this address will boot drive 0 of the
floppy controller (CPU must be set to ROM or equivalent code must be
present). 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 Comment
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 (on Z80 only)
BC1 16 The alternate BC register (on Z80 only)
DE1 16 The alternate DE register (on Z80 only)
HL1 16 The alternate HL register (on Z80 only)
IX 16 The IX index register (on Z80 only)
IY 16 The IY index register (on Z80 only)
IFF 8 Interrupt flag (on Z80 only)
INT 8 Interrupt register (on Z80 only)
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-]).
BANK 3 The currently active memory bank (if banked memory
is activated - see memory options above)
COMMON 16 The starting address of common memory. Originally set
to 0xc000 (note this setting must agree with the
value supplied to GENCPM for CP/M 3 system generation)
ROMLOW 16 The starting address of the ROM. Default is 0FF00.
ROMHIGH 16 The final address of the ROM. Default is 0FFFF.
CLOCK 32 The clock speed of the simulated CPU in kHz or 0 to run
at maximum speed. To set the clock speed for a typical
4 MHz Z80 CPU, use D CLOCK 4000. The CP/M utility SPEED
measures the clock speed of the simulated CPU.
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
SET SIO QUIET Do not print warning messages
SET SIO VERBOSE Print warning messages (useful for debugging)
The register SIOWL determines how often the same warning
is displayed. The default is 3.
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 SIMH pseudo device
The SIMH pseudo device facilitates the communication between the
simulated ALTAIR and the simulator environment. This device defines a
number of (most R/O) registers (see source code) which are primarily useful
for debugging purposes.
The SIMH pseudo device can be configured with
SET SIMH QUIET Do not print warning messages
SET SIMH VERBOSE Print warning messages (useful for debugging)
SET SIMH TIMERON Start periodic timer interrupts
SET SIMH TIMEROFF Stop the periodic timer interrupts
The following variables determine the behavior of the timer:
TIMD This is the delay between consecutive interrupts in milliseconds.
Use D TIMD 20 for a 50 Hz clock.
TIMH This is the address of the interrupt handler to call for a
timer interrupt.
2.4 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). You can change the
number of tracks per disk by setting the appropriate value in TRACKS[..].
For example "D TRACKS[0] 77" sets the number of tracks for disk 0 to the
original number of 77. The command "D TRACKS[0-7] 77" changes the highest
track number for all disks to 77.
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.
The DSK device can be configured with
SET DSK<n> QUIET Do not print warning messages for disk <n>
SET DSK<n> VERBOSE Print warning messages for disk <n>
(useful for debugging)
The register DSKWL determines how often the
same warning is displayed. The default is 3.
SET DSK<n> WRITEENABLED Allow write operations for disk <n>
SET DSK<n> LOCKED Disk <n> is locked, i.e. no write operations
will be allowed.
2.5 The simulated hard disk
In order to increase the available storage capacity, the simulator
features 8 simulated hard disks with a capacity of 8MB (HDSK0 to HDSK7).
Currently only CP/M supports two hard disks as devices I: and J:.
For debugging purposes one can set the trace flag by executing the
command "D HDTRACE 1". The default for "HDTRACE" is 0 (no trace).
The HDSK device can be configured with
SET HDSK<n> QUIET Do not print warning messages for hard disk <n>
SET HDSK<n> VERBOSE Print warning messages for hard disk <n>
(useful for debugging)
SET HDSK<n> WRITEENABLED Allow write operations for hard disk <n>
SET HDSK<n> LOCKED Hard disk <n> is locked, i.e. no
write operations will be allowed.
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 cpm2.dsk
sim> boot dsk
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, DO 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 "SYSCPM2.SUB". To run it, type "DO SYSCPM2".
In order to efficiently transfer files into the CP/M environment use the
included program R <filename.ext>. If you have a file named foo.ext in the
current directory (i.e. the directory where SIMH is), executing R FOO.EXT
under CP/M will transfer the file onto the CP/M disk. Transferring a file
from the CP/M environment to the SIMH environment is accomplished by
W <filename.ext> for text files or by W <filename.ext> B for binary files.
The simplest way for transferring multiple files is to create a ".SUB"
batch file which contains the necessary R resp. W commands.
If you need more storage space you can use a simulated hard disk on
drives I: and J:. To use do "attach HDSK0 hdi.dsk" and issue the
"XFORMAT I:" resp. "XFORMAT J:" command from CP/M do initialize the disk
to an empty state.
The disk "cpm2.dsk" contains the following files:
Name Ext Size Comment
ASM .COM 8K ; CP/M assembler
BDOS .MAC 68K ; Basic Disk Operating System assembler source code
BOOT .COM 1K ; transfer control to boot ROM
BOOT .MAC 2K ; source for BOOT.COM
BOOTGEN .COM 2K ; put a program on the boot sectors
CBIOSX .MAC 48K ; CP/M 2 BIOS source for Altair
CCP .MAC 26K ; Console Command Processor assembler source code
COPY .COM 2K ; copy disks
CPMBOOT .COM 12K ; CP/M operating system
CPU .COM 2K ; get and set the CPU type (8080 or Z80)
CPU .MAC 2K ; source for CPU.COM
CREF80 .COM 4K ; cross reference utility
DDT .COM 6K ; 8080 debugger
DDTZ .COM 10K ; Z80 debugger
DIF .COM 4K ; determine differences between two files
DO .COM 2K ; batch processing
DSKBOOT .MAC 8K ; source for boot ROM
DUMP .COM 2K ; hex dump a file
ED .COM 8K ; line editor
ELIZA .BAS 10K ; Eliza game in Basic
EX8080 .COM 12K ; exercise 8080 instruction set
EXZ80N .COM 12K ; exercise Z80 instruction set, No undefined status bits
EXZ80U .COM 12K ; exercise Z80 instruction set, Undefined status bits
EXZ80 .MAC 54K ; source for EX8080.COM, EXZ80N.COM, EXZ80U.COM
EX .SUB 2K ; benchmark execution of EX8080.COM, EXZ80N.COM, EXZ80U.COM
FORMAT .COM 2K ; format disks
GO .COM 0K ; start the currently loaded program at 100H
HDSKBOOT.MAC 6K ; boot code for hard disk
L80 .COM 12K ; Microsoft linker
LADDER .COM 40K ; game
LADDER .DAT 2K ; high score file for LADDER.COM
LIB80 .COM 6K ; library utility
LOAD .COM 2K ; load hex files
LS .COM 4K ; directory utility
LU .COM 20K ; library utility
M80 .COM 20K ; Microsoft macro assembler
MBASIC .COM 24K ; Microsoft Basic interpreter
MC .SUB 2K ; assemble and link an assembler program
MCC .SUB 2K ; read, assemble and link an assembler program
MCCL .SUB 2K ; assemble, link and produce listing
MEMCFG .LIB 2K ; defines the memory configuration
MOVER .MAC 2K ; moves operating system in place
OTHELLO .COM 12K ; Othello (Reversi) game
PIP .COM 8K ; Peripheral Interchange Program
PRELIM .COM 2K ; preliminary CPU tests
PRELIM .MAC 6K ; source code for PRELIM.COM
R .COM 4K ; read files from SIMH environment
RSETSIMH.COM 2K ; reset SIMH interface
RSETSIMH.MAC 2K ; assembler source for RSETSIMH.COM
SHOWSEC .COM 3K ; show sectors on a disk
SID .COM 8K ; debugger for 8080
SPEED .COM 2K ; utility to measure the clock speed of the simulated CPU
STAT .COM 6K ; provide information about currently logged disks
SURVEY .COM 2K ; system survey
SURVEY .MAC 16K ; assembler source for SURVEY.COM
SYSCOPY .COM 2K ; copy system tracks between disks
SYSCPM2 .SUB 2K ; create CP/M 2 on drive A:
TIMER .COM 2K ; perform various timer operations
TIMER .MAC 2K ; source code for TIMER.COM
UNCR .COM 8K ; un-crunch utility
UNERA .COM 2K ; un-erase a file
UNERA .MAC 16K ; source for UNERA.COM
USQ .COM 2K ; un-squeeze utility
W .COM 4K ; write files to SIMH environment
WM .COM 12K ; word master screen editor
WM .HLP 3K ; help file for WM.COM
WORM .COM 4K ; worm game for VT100 terminal
XFORMAT .COM 2K ; initialise a drive (floppy or hard disk)
XSUB .COM 2K ; support for DO.COM
ZAP .COM 10K ; SuperZap 5.2 disk editor configured for VT100
ZSID .COM 10K ; debugger for Z80
ZTRAN4 .COM 4K ; translate 8080 mnemonics into Z80 equivalents
3.2 CP/M Version 3 with banked memory
CP/M 3 is the successor to CP/M 2.2. A customised BIOS (BIOS3.MAC) is
included to facilitate modification if so desired. The defaults supplied in
GENCPM.DAT for system generation can be used. BOOTGEN.COM is used to place
the CP/M loader (LDR.COM) on the boot tracks of a disk.
Running CP/M 3 with banked memory:
sim> attach dsk cpm3.dsk
sim> reset cpu
sim> set cpu banked
sim> set cpu itrap
sim> boot dsk
Executing "DO SYSCPM3" will re-generate the banked version of CP/M 3. You
can boot CP/M 3 with or without a Z80 CPU. The Z80 CPU is needed for both
sysgens due to the use of BOOTGEN.COM which requires it.
The disk "cpm3.dsk" contains the following files:
ASM .COM 8K ; CP/M assembler
ASSIGN .SYS 2K
BDOS3 .SPR 10K
BIOS3 .MAC 28K ; CP/M 3 BIOS source for Altair SIMH
BIOS3 .SPR 4K
BNKBDOS3.SPR 14K
BNKBIOS3.SPR 4K
BOOT .COM 2K ; transfer control to boot ROM
BOOTGEN .COM 2K ; put a program on the boot sectors
CCP .COM 4K
COPYSYS .COM 2K
CPM3 .SYS 18K
CPMLDR .MAC 38K ; CP/M 3 loader assembler source
DATE .COM 4K ; date utility
DDT .COM 6K ; 8080 debugger
DDTZ .COM 10K ; Z80 debugger
DEFS .LIB 2K ; include file for BIOS3.MAC to create banked CP/M 3
DEVICE .COM 8K
DIF .COM 4K ; determine differences between two files
DIR .COM 16K ; directory utility
DO .COM 6K ; batch processing
DUMP .COM 2K
ED .COM 10K
ERASE .COM 4K
GENCOM .COM 16K
GENCPM .COM 22K
GENCPM .DAT 4K ; CP/M generation information for banked version
GENCPMNB.DAT 4K ; CP/M generation information for non-banked version
GET .COM 8K
HELP .COM 8K ; help utility
HELP .HLP 62K ; help files
HEXCOM .CPM 2K
HIST .UTL 2K
INITDIR .COM 32K
L80 .COM 12K ; Microsoft linker
LDR .COM 4K ; CP/M loader with optimised loader BIOS
LDRBIOS3.MAC 14K ; optimised (for space) loader BIOS
LIB .COM 8K ; Digital Research librarian
LINK .COM 16K ; Digital Research linker
LOAD .COM 2K
M80 .COM 20K ; Microsoft macro assembler
MC .SUB 2K ; assemble and link an assmbler program
MCC .SUB 2K ; read, assemble and link an assembler program
PATCH .COM 4K
PIP .COM 10K ; Peripheral Interchange Program
PROFILE .SUB 2K ; commands to be executed at start up
PUT .COM 8K
R .COM 4K ; read files from SIMH environment
RENAME .COM 4K
RESBDOS3.SPR 2K
RMAC .COM 14K ; Digital Research macro assembler
RSETSIMH.COM 2K ; reset SIMH interface
SAVE .COM 2K
SCB .MAC 2K
SET .COM 12K
SETDEF .COM 6K
SHOW .COM 10K
SHOWSEC .COM 4K ; show sectors on a disk
SID .COM 8K ; 8080 debugger
SYSCOPY .COM 2K ; copy system tracks between disks
SYSCPM3 .SUB 2K ; create banked CP/M 3 system
TRACE .UTL 2K
TSHOW .COM 2K ; show split time
TSTART .COM 2K ; create timer and start it
TSTOP .COM 2K ; show final time and stop timer
TYPE .COM 4K
UNERA .COM 2K ; un-erase a file
W .COM 4K ; write files to SIMH environment
XREF .COM 16K ; cross reference utility
ZSID .COM 10K ; Z80 debugger
3.3 MP/M II with banked memory
MP/M II is an acronym for MultiProgramming Monitor Control Program for
Microprocessors. It is a multiuser operating system for an eight bit
microcomputer. MP/M II supports multiprogramming at each terminal. This
version supports four terminals available via Telnet. To boot:
sim> attach dsk mpm.dsk
sim> set cpu itrap
sim> set cpu z80
sim> set cpu rom
sim> set cpu banked
sim> attach sio 23
sim> d common b000
sim> boot dsk
Now connect a Telnet session to the simulator and type "MPM" at the "A>"
prompt. Now you can connect up to three additional terminals via Telnet to
the Altair running MP/M II. To re-generate the system perform "DO SYSMPM"
in the CP/M environment (not possible under MP/M since XSUB is needed).
The disk "mpm.dsk" contains the following files:
Name Ext Size Comment
ABORT .PRL 2K ; abort a process
ABORT .RSP 2K
ASM .PRL 10K ; MP/M assembler
BNKBDOS .SPR 12K ; banked BDOS
BNKXDOS .SPR 2K ; banked XDOS
BNKXIOS .SPR 4K ; banked XIOS
BOOTGEN .COM 2K ; copy an executable to the boot section
CONSOLE .PRL 2K ; print console number
CPM .COM 2K ; return to CP/M
CPM .MAC 2K ; source for CPM.COM
DDT .COM 6K ; MP/M DDT
DDT2 .COM 6K ; CP/M DDT
DDTZ .COM 10K ; CP/M DDT with Z80 support
DIF .COM 4K ; difference between two files
DIR .PRL 2K ; directory command
DO .COM 2K ; CP/M submit
DSKRESET.PRL 2K ; disk reset command
DUMP .MAC 6K ; source for DUMP.PRL
DUMP .PRL 2K ; dump command
ED .PRL 10K ; MP/M line editor
ERA .PRL 2K ; erase command
ERAQ .PRL 4K ; erase comand (verbose)
GENHEX .COM 2K
GENMOD .COM 2K
GENSYS .COM 10K
L80 .COM 12K ; Microsoft linker
LDRBIOS .MAC 14K ; loader BIOS
LIB .COM 8K ; library utility
LINK .COM 16K ; linker
LOAD .COM 2K ; loader
M80 .COM 20K ; Microsoft macro assembler
MC .SUB 2K ; assemble and link an assmbler program
MCC .SUB 2K ; read, assemble and link an assembler program
MPM .COM 8K ; start MP/M II
MPM .SYS 26K ; MP/M system file
MPMD .LIB 2K ; define a banked system
MPMLDR .COM 6K ; MP/M loader without LDRBIOS
MPMSTAT .BRS 6K ; status of MP/M system
MPMSTAT .PRL 6K
MPMSTAT .RSP 2K
MPMXIOS .MAC 26K ; XIOS for MP/M
PIP .PRL 10K ; MP/M peripheral interchange program
PIP2 .COM 8K ; CP/M peripheral interchange program
PRINTER .PRL 2K
PRLCOM .PRL 4K
R .COM 4K ; read a file from the SIMH environment
RDT .PRL 8K ; debugger for page relocatable programs
REN .PRL 4K ; rename a file
RESBDOS .SPR 4K ; non-banked BDOS
RMAC .COM 14K ; Digital Research macro assembler
RSETSIMH.COM 2K ; reset SIMH interface
SCHED .BRS 2K ; schedule a job
SCHED .PRL 4K
SCHED .RSP 2K
SDIR .PRL 18K ; fancy directory command
SET .PRL 8K ; set parameters
SHOW .PRL 8K ; show status of disks
SPOOL .BRS 4K ; spool utility
SPOOL .PRL 4K
SPOOL .RSP 2K
STAT .COM 6K ; CP/M stat command
STAT .PRL 10K ; MP/M stat command
STOPSPLR.PRL 2K ; stop spooler
SUBMIT .PRL 6K ; MP/M submit
SYSCOPY .COM 2K ; copy system tracks
SYSMPM .SUB 2K ; do a system generation
SYSTEM .DAT 2K ; default values for system generation
TMP .SPR 2K
TOD .PRL 4K ; time of day
TSHOW .COM 2K ; show split time
TSTART .COM 2K ; create timer and start it
TSTOP .COM 2K ; show final time and stop timer
TYPE .PRL 2K ; type a file on the screen
USER .PRL 2K ; set user area
W .COM 4K ; write a file to SIMH environment
XDOS .SPR 10K ; XDOS
XREF .COM 16K ; cross reference utility
XSUB .COM 2K ; for CP/M DO
3.4 CP/M application software
There is also a small collection of sample application software
containing the following items:
- SPL: a Small Programming Language with a suite of sample programs
- PROLOGZ: a Prolog interpreter written in SPL with sources
- PASCFORM: a Pascal pretty printer written in Pascal
- Pascal MT+: Pascal language system needed to compile PASCFORM
The sample software comes on "app.dsk" and to use it do
sim> attach dsk1 app.dsk
before booting CP/M.
The disk "app.dsk" contains the following files:
Name Ext Size Comment
BOOTGEN .COM 2K
BOOTGEN .SPL 6K ; SPL source for BOOTGEN.COM
C .SUB 2K ; batch file for compiling an SPL source file
CALC .PRO 4K ; Prolog demo program: Calculator
CC .SUB 2K ; compile an SPL source which is on the underlying
file system
DECLARAT. 12K ; common include file, SPL source
DIF .COM 4K
DIF .SPL 10K ; SPL source for DIF.COM
EDIT .SPL 10K ; screen editor for PROLOGZ, SPL source
FAMILY .PRO 4K ; Prolog demo program: Family relations
INTEGER .PRO 2K ; Prolog demo program: Integer arithmetic
KNAKE .PRO 2K ; Prolog demo program: Logic puzzle
LINKMT .COM 12K ; Pascal MT+ 5.5 linker
MAIN .SPL 14K ; main module for PROLOGZ, SPL source
MOVE .MAC 4K ; helper functions for PROLOGZ in assembler
MTERRS .TXT 6K ; Pascal MT+ error messages
MTPLUS .000 14K ; Pascal MT+ 5.5 compiler file
MTPLUS .001 12K ; Pascal MT+ 5.5 compiler file
MTPLUS .002 8K ; Pascal MT+ 5.5 compiler file
MTPLUS .003 8K ; Pascal MT+ 5.5 compiler file
MTPLUS .004 18K ; Pascal MT+ 5.5 compiler file
MTPLUS .005 8K ; Pascal MT+ 5.5 compiler file
MTPLUS .006 6K ; Pascal MT+ 5.5 compiler file
MTPLUS .COM 36K ; Pascal MT+ 5.5 compiler
PASCFORM.COM 36K ; Pascal formatter
PASCFORM.PAS 54K ; Pascal formatter source code
PASCFORM.SUB 2K ; create Pascal formatter
PASLIB .ERL 24K ; Pascal MT+ 5.5 run time library
PINST .COM 4K ; terminal installation program for PROLOGZ
PINST .SPL 16K ; terminal installation program for PROLOGZ,
SPL source
PROLOGZ .COM 18K ; PROLOGZ interpreter and screen editor
PROLOGZ .SPL 2K ; PROLOGZ main program, SPL source
PROLOGZ .TXT 40K ; PROLOGZ documentation in German
PROVE .SPL 16K ; backtrack theorem prover for PROLOGZ, SPL source
PZCLEAN .SUB 2K ; PROLOGZ: remove all created ".rel" and ".lst" files
PZLINK .SUB 2K ; PROLOGZ: create PINST, PROLOGZ and personalise the
serial number
PZMAKE .SUB 2K ; PROLOGZ: compiles the sources (you can ignore
any compiler errors)
QUEEN .PRO 2K ; Prolog demo program: N-queens problem
READ .COM 4K
READ .SPL 10K ; SPL source for R.COM
SHOWSEC .COM 4K
SHOWSEC .SPL 6K ; SPL source for SHOWSEC.COM
SPEED .COM 2K ; utility to measure the clock speed of the simulated CPU
SPEED .SPL 2K ; SPL source for SPEED.COM, requires SWLIB.MAC
SPL .COM 38K ; the SPL compiler itself
SPL .TXT 56K ; SPL language and compiler documentation in German
SPLERROR.DAT 12K ; error messages of the compiler (in German)
SPLIB .REL 6K ; SPL runtime library
STDIO . 2K ; include file for SPL programs
SWLIB .MAC 2K ; assembler utility routines needed by SPEED.SPL
SYSCOPY .COM 2K
SYSCOPY .SPL 6K ; SPL source for SYSCOPY.COM
TERMBDOS.SPL 2K ; terminal interface to CP/M for PROLOGZ, SPL source
UTIL .SPL 18K ; utility functions for PROLOGZ, SPL source
WRITE .COM 4K
WRITE .SPL 8K ; SPL source for W.COM
XFORMAT .COM 2K
XFORMAT .SPL 6K ; SPL source for XFORMAT.COM
3.5 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] (0 here = 1 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.6 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> d tracks[0-7] 77 ;set to Altair settings
sim> set cpu altairrom
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.7 Altair Basic 3.2 (4k)
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 0 ;load it at 0
sim> go 0 ;and start it
MEMORY SIZE? [return]
TERMINAL WIDTH? [return]
WANT SIN? [Y]
61911 BYTES FREE
BASIC VERSION 3.2
[4K VERSION]
OK
3.8 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 0 ;load it at 0
sim> go 0 ;and start it
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
3.9 Altair Basic 4.0
Execute the following commands to run Altair Extended Basic:
sim> set sio upper ;Extended Basic does not like lower case letters as input
sim> set sio ansi ;Extended Basic produces 8-bit output, strip to seven bits
sim> d sr 8 ;good setting for the Switch Register
sim> load exbas.bin 0 ;load it at 0
sim> go 0 ;and start it
16384 Bytes loaded at 0.
MEMORY SIZE? [return]
WANT SIN-COS-TAN-ATN? [Y]
50606 BYTES FREE
ALTAIR BASIC REV. 4.0
[EXTENDED VERSION]
COPYRIGHT 1977 BY MITS INC.
OK
3.10 Altair Disk Extended Basic Version 300-5-C
This version of Basic was provided by Scott LaBombard. To execute use the
following commands:
sim> d tracks[0-7] 77 ;set to Altair settings
sim> at dsk extbas5.dsk
sim> g 0
MEMORY SIZE? [return]
LINEPRINTER? [C]
HIGHEST DISK NUMBER? [0]
HOW MANY FILES? [3]
HOW MANY RANDOM FILES? [3]
42082 BYTES FREE
ALTAIR DISK EXTENDED BASIC
VERSION 300-5-C [01NOV78]
COPYRIGHT 1978 BY MITS INC.
OK
4. Special simulator features
4.1 Memory access breakpoints
In addition to the regular SIMH features such as PC queue, breakpoints
etc., this simulator supports memory access breakpoints. A memory access
breakpoint is triggered when a pre-defined memory location is accessed
(read, write or update). To set a memory location breakpoint enter
sim> break -m <location>
Execution will stop whenever an operation accesses <location>. Note that
a memory access breakpoint is not triggered by fetching code from memory
(this is the job of regular breakpoints). This feature has been implemented
by using the typing facility of the SIMH breakpoints.
4.2 T-state stepping
The SIMH step command supports the "-t" modifier to allow steppping for
a predefined number of t-states. For example
sim> step -t 1000
will cause the simulated CPU to execute 1000 t-states (note that the shortest
instruction will have 4 t-states). On the other hand, the command
sim> step 1000
will cause the simulated CPU to execute 1000 instructions.
5. 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.
- Added banked memory support.
- PC queue implemented.
- 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). In
addition one can enable and disable the ROM which is useful in special cases
(e.g. when testing a new version of the ROM).
- 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 WRITE program can be used to transfer files from the CP/M environment to
the regular environment (binary or ASCII transfer).
- 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.
- Added CP/M 3 banked version as sample software
- Changed from octal to hex
- Made the DSK and SIO device more robust (previously malicious code could
crash the simulator)
- Added memory access break points
- Added periodic timer interrupts (useful for MP/M)
- Added additional consoles (useful for MP/M)
- Added MP/M II banked version as sample software

View file

@ -90,17 +90,36 @@ static uint16 IFF;
#define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp))) #define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp)))
/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */ /* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */
/*
#define checkCPU8080 \ #define checkCPU8080 \
if (((cpu_unit.flags & UNIT_CHIP) == 0) && (cpu_unit.flags & UNIT_OPSTOP)) {\ if (((cpu_unit.flags & UNIT_CHIP) == 0) && (cpu_unit.flags & UNIT_OPSTOP)) {\
reason = STOP_OPCODE; \ reason = STOP_OPCODE; \
goto end_decode; \ goto end_decode; \
} }
*/
/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed
In case a Z80 instruction is executed on an 8080 the following two cases exist:
1) Trapping is enabled: execution stops
2) Trapping is not enabled: decoding continues with the next byte
*/
#define checkCPU8080 \
if ((cpu_unit.flags & UNIT_CHIP) == 0) { \
if (cpu_unit.flags & UNIT_OPSTOP) { \
reason = STOP_OPCODE; \
goto end_decode; \
} \
else { \
sim_brk_pend = FALSE; \
continue; \
} \
}
/* checkCPUZ80 must be invoked whenever a non Z80 instruction is executed */ /* checkCPUZ80 must be invoked whenever a non Z80 instruction is executed */
#define checkCPUZ80 \ #define checkCPUZ80 \
if (cpu_unit.flags & UNIT_OPSTOP) { \ if (cpu_unit.flags & UNIT_OPSTOP) { \
reason = STOP_OPCODE; \ reason = STOP_OPCODE; \
goto end_decode; \ goto end_decode; \
} }
#define POP(x) { \ #define POP(x) { \

View file

@ -64,6 +64,8 @@
#define UNIT_BS (1 << UNIT_V_BS) #define UNIT_BS (1 << UNIT_V_BS)
#define UNIT_V_SIO_VERBOSE (UNIT_V_UF + 3) /* verbose mode, i.e. show error messages */ #define UNIT_V_SIO_VERBOSE (UNIT_V_UF + 3) /* verbose mode, i.e. show error messages */
#define UNIT_SIO_VERBOSE (1 << UNIT_V_SIO_VERBOSE) #define UNIT_SIO_VERBOSE (1 << UNIT_V_SIO_VERBOSE)
#define UNIT_V_MAP (UNIT_V_UF + 4) /* mapping mode on */
#define UNIT_MAP (1 << UNIT_V_MAP)
#define UNIT_V_SIMH_VERBOSE (UNIT_V_UF + 0) /* verbose mode for SIMH pseudo device */ #define UNIT_V_SIMH_VERBOSE (UNIT_V_UF + 0) /* verbose mode for SIMH pseudo device */
#define UNIT_SIMH_VERBOSE (1 << UNIT_V_SIMH_VERBOSE) #define UNIT_SIMH_VERBOSE (1 << UNIT_V_SIMH_VERBOSE)
@ -187,7 +189,7 @@ static SIO_TERMINAL sio_terminals[Terminals] =
static TMLN TerminalLines[Terminals] = { {0} }; /* four terminals */ static TMLN TerminalLines[Terminals] = { {0} }; /* four terminals */
static TMXR altairTMXR = {Terminals, 0, 0, TerminalLines}; /* mux descriptor */ static TMXR altairTMXR = {Terminals, 0, 0, TerminalLines}; /* mux descriptor */
static UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; static UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE + UNIT_MAP, 0), KBD_POLL_WAIT };
static REG sio_reg[] = { static REG sio_reg[] = {
{ HRDATA (DATA0, sio_terminals[0].data, 8) }, { HRDATA (DATA0, sio_terminals[0].data, 8) },
@ -215,6 +217,8 @@ static MTAB sio_mod[] = {
{ UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */ { UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */
{ UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose }, { UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose },
/* verbose, display warning messages */ /* verbose, display warning messages */
{ UNIT_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */
{ UNIT_MAP, UNIT_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */
{ 0 } }; { 0 } };
DEVICE sio_dev = { DEVICE sio_dev = {
@ -491,17 +495,20 @@ int32 sio0d(const int32 port, const int32 io, const int32 data) {
sio_terminals[ti].data = tmxr_getc_ln(&TerminalLines[ti]) & 0xff; sio_terminals[ti].data = tmxr_getc_ln(&TerminalLines[ti]) & 0xff;
} }
sio_terminals[ti].status &= 0xfe; sio_terminals[ti].status &= 0xfe;
if (sio_unit.flags & UNIT_BS) { if (sio_unit.flags & UNIT_MAP) {
if (sio_terminals[ti].data == BACKSPACE_CHAR) { if (sio_unit.flags & UNIT_BS) {
sio_terminals[ti].data = DELETE_CHAR; if (sio_terminals[ti].data == BACKSPACE_CHAR) {
sio_terminals[ti].data = DELETE_CHAR;
}
}
else {
if (sio_terminals[ti].data == DELETE_CHAR) {
sio_terminals[ti].data = BACKSPACE_CHAR;
}
} }
} }
else { return ((sio_unit.flags & UNIT_UPPER) && (sio_unit.flags & UNIT_MAP)) ?
if (sio_terminals[ti].data == DELETE_CHAR) { toupper(sio_terminals[ti].data) : sio_terminals[ti].data;
sio_terminals[ti].data = BACKSPACE_CHAR;
}
}
return (sio_unit.flags & UNIT_UPPER) ? toupper(sio_terminals[ti].data) : sio_terminals[ti].data;
} }
else { /* OUT */ else { /* OUT */
int32 d = sio_unit.flags & UNIT_ANSI ? data & 0x7f : data; int32 d = sio_unit.flags & UNIT_ANSI ? data & 0x7f : data;

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Peter Schorn From: Peter Schorn
Subj: AltairZ80 Simulator Usage Subj: AltairZ80 Simulator Usage
Date: 15-Feb-2004 Date: 12-Apr-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -61,6 +61,7 @@ sim/AltairZ80/altairz80_defs.h
2. Revision History 2. Revision History
- 12-Apr-2004, Peter Schorn (added MAP/NOMAP capability to switch off key mapping)
- 26-Jan-2004, Peter Schorn (added support for t-state stepping) - 26-Jan-2004, Peter Schorn (added support for t-state stepping)
- 25-Feb-2003, Peter Schorn (added support for real time simulation) - 25-Feb-2003, Peter Schorn (added support for real time simulation)
- 9-Oct-2002, Peter Schorn (added support for simulated hard disk) - 9-Oct-2002, Peter Schorn (added support for simulated hard disk)
@ -132,7 +133,9 @@ the MITS Disk Basic and Altair DOS require about a minimum of 24K.
SET CPU ITRAP Causes the simulator to halt if an invalid opcode SET CPU ITRAP Causes the simulator to halt if an invalid opcode
is detected (depending on the chosen CPU). is detected (depending on the chosen CPU).
SET CPU NOITRAP Does not stop on an invalid Opcode. This is SET CPU NOITRAP Does not stop on an invalid Opcode. This is
how the real 8080 works. how the real 8080 works. Note that some software such as 4K Basic
apparently tries to execute nonexistent 8080 instructions. Therefore
it is advisable in this case to SET CPU NOITRAP.
SET CPU 4K SET CPU 4K
SET CPU 8K SET CPU 8K
@ -248,18 +251,29 @@ a simple stream of 8-bit bytes.
SET SIO TTY Bit 8 is set to zero on console output 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 ANSI Bit 8 is not touched on console output
SET SIO ALL Console input support lower- and upper case SET SIO ALL Console input remain unchanged
SET SIO UPPER Console input is transformed to upper case characters only SET SIO UPPER Console input is transformed to upper case characters only
(This feature is useful for most Altair software) (This feature is useful for most Altair software)
SET SIO MAP must also have been executed for this
option to take effect - otherwise no mapping occurs.
SET SIO BS Map the delete character to backspace SET SIO BS Map the delete character to backspace
SET SIO MAP must also have been executed for this
option to take effect - otherwise no mapping occurs.
SET SIO DEL Map the backspace character to delete SET SIO DEL Map the backspace character to delete
SET SIO MAP must also have been executed for this
option to take effect - otherwise no mapping occurs.
SET SIO QUIET Do not print warning messages SET SIO QUIET Do not print warning messages
SET SIO VERBOSE Print warning messages (useful for debugging) SET SIO VERBOSE Print warning messages (useful for debugging)
The register SIOWL determines how often the same warning The register SIOWL determines how often the same warning
is displayed. The default is 3. is displayed. The default is 3.
SET SIO MAP Enable mapping of characters
(see also SET SIO ALL/UPPER/BS/DEL)
SET SIO NOMAP Disable mapping of characters
(see also SET SIO ALL/UPPER/BS/DEL)
You can also attach the SIO to a port: You can also attach the SIO to a port:
ATTACH SIO 23 Console IO goes via a Telnet connection on port 23 ATTACH SIO 23 Console IO goes via a Telnet connection on port 23
@ -382,7 +396,7 @@ 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" 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 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 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. lines, E exits the editor. 20L20T will move down 20 lines, and type 20.
Very DECish. DDT is the debugger, DO is a batch-type command processor. A Very DECish. DDT is the debugger, DO is a batch-type command processor. A
sample batch file that will assemble and write out the bootable CP/M image sample batch file that will assemble and write out the bootable CP/M image
(on drive A) is "SYSCPM2.SUB". To run it, type "DO SYSCPM2". (on drive A) is "SYSCPM2.SUB". To run it, type "DO SYSCPM2".
@ -814,6 +828,7 @@ trick is to get the Switch Register right).
sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU 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 upper ;4k Basic does not like lower case letters as input
sim> set cpu noitrap ;4k Basic likes to execute non 8080 instructions - ignore
sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits 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> d sr 8 ;good setting for the Switch Register
sim> load 4kbas.bin 0 ;load it at 0 sim> load 4kbas.bin 0 ;load it at 0

View file

@ -25,6 +25,7 @@
cpu H316/H516 CPU cpu H316/H516 CPU
06-Nov-04 RMS Added =n to SHOW HISTORY
04-Jan-04 RMS Removed unnecessary compare 04-Jan-04 RMS Removed unnecessary compare
31-Dec-03 RMS Fixed bug in cpu_set_hist 31-Dec-03 RMS Fixed bug in cpu_set_hist
24-Oct-03 RMS Added DMA/DMC support, instruction history 24-Oct-03 RMS Added DMA/DMC support, instruction history
@ -338,7 +339,7 @@ MTAB cpu_mod[] = {
&cpu_set_nchan, &cpu_show_nchan, NULL }, &cpu_set_nchan, &cpu_show_nchan, NULL },
{ UNIT_DMC, 0, "no DMC", "NODMC", NULL }, { UNIT_DMC, 0, "no DMC", "NODMC", NULL },
{ UNIT_DMC, UNIT_DMC, "DMC", "DMC", NULL }, { UNIT_DMC, UNIT_DMC, "DMC", "DMC", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY", { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist }, &cpu_set_hist, &cpu_show_hist },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DMA1", NULL, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DMA1", NULL,
NULL, &cpu_show_dma, NULL }, NULL, &cpu_show_dma, NULL },
@ -1369,8 +1370,10 @@ return SCPE_OK;
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{ {
int32 cr, k, di, op; int32 cr, k, di, op, lnt;
char *cptr = (char *) desc;
t_value sim_eval; t_value sim_eval;
t_stat r;
struct InstHistory *h; struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw); UNIT *uptr, int32 sw);
@ -1378,9 +1381,14 @@ static uint8 has_opnd[16] = {
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }; 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 };
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC C A B X ea IR\n\n"); fprintf (st, "PC C A B X ea IR\n\n");
di = hst_p; /* work forward */ for (k = 0; k < lnt; k++) { /* print specified */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */ h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */ if (h->pc & HIST_PC) { /* instruction? */
cr = (h->pc & HIST_C)? 1: 0; /* carry */ cr = (h->pc & HIST_C)? 1: 0; /* carry */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: H316 Simulator Usage Subj: H316 Simulator Usage
Date: 15-Feb-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -155,6 +155,17 @@ control registers for the interrupt system.
most recent PC change first most recent PC change first
WRU 8 interrupt character WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 Programmed I/O Devices 2.2 Programmed I/O Devices
2.2.1 316/516-50 Paper Tape Reader (PTR) 2.2.1 316/516-50 Paper Tape Reader (PTR)
@ -373,7 +384,7 @@ or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can be set ONLINE or OFFLINE, and WRITEENABLED or write LOCKED. Units can also be set ENABLED or DISABLED.
The magtape controller can be connected to the IO bus, a DMC channel, or The magtape controller can be connected to the IO bus, a DMC channel, or
a DMA channel: a DMA channel:
@ -428,7 +439,7 @@ disk packs; a 4651, supporting 2 surface disk packs; or a 4720, supporting
SET DP 4720 controller is 4720 SET DP 4720 controller is 4720
The default is 4651. All disk packs on the controller must be of the The default is 4651. All disk packs on the controller must be of the
same type. Units can be set ONLINE or OFFLINE, and WRITEENABLED or same type. Units can be set ENABLED or DISABLED, and WRITEENABLED or
write LOCKED. write LOCKED.
The disk pack controller can be connected to a DMC channel or a DMA The disk pack controller can be connected to a DMC channel or a DMA

View file

@ -23,6 +23,22 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
CPU 2116A/2100A/21MXE central processing unit
MP 12892B memory protect
DMA0,DMA1 12895A/12897B direct memory access/dual channel port controller
25-Sep-04 JDB Moved MP into its own device; added MP option jumpers
Modified DMA to allow disabling
Modified SET CPU 2100/2116 to truncate memory > 32K
Added -F switch to SET CPU to force memory truncation
Fixed S-register behavior on 2116
Fixed LIx/MIx behavior for DMA on 2116 and 2100
Fixed LIx/MIx behavior for empty I/O card slots
Modified WRU to be REG_HRO
Added BRK and DEL to save console settings
Fixed use of "unsigned int16" in cpu_reset
Modified memory size routine to return SCPE_INCOMP if
memory size truncation declined
20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan) 20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan)
Back up PC on instruction errors (from Dave Bryan) Back up PC on instruction errors (from Dave Bryan)
14-May-04 RMS Fixed bugs and added features from Dave Bryan 14-May-04 RMS Fixed bugs and added features from Dave Bryan
@ -68,6 +84,12 @@
21-Nov-00 RMS Fixed bug in reset routine 21-Nov-00 RMS Fixed bug in reset routine
15-Oct-00 RMS Added dynamic device number support 15-Oct-00 RMS Added dynamic device number support
References:
- 21MX M-Series Computer, HP 2108B and HP 2112B, Operating and Reference Manual
(02108-90037, Apr-1979)
- HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
(92851-90001, Mar-1981)
The register state for the HP 2116 CPU is: The register state for the HP 2116 CPU is:
AR<15:0> A register - addressable as location 0 AR<15:0> A register - addressable as location 0
@ -308,21 +330,27 @@
#define UNIT_V_21MX (UNIT_V_UF + 1) /* 21MX */ #define UNIT_V_21MX (UNIT_V_UF + 1) /* 21MX */
#define UNIT_V_EAU (UNIT_V_UF + 2) /* EAU */ #define UNIT_V_EAU (UNIT_V_UF + 2) /* EAU */
#define UNIT_V_FP (UNIT_V_UF + 3) /* FP */ #define UNIT_V_FP (UNIT_V_UF + 3) /* FP */
#define UNIT_V_MPR (UNIT_V_UF + 4) /* mem prot */ #define UNIT_V_DMS (UNIT_V_UF + 4) /* DMS */
#define UNIT_V_DMS (UNIT_V_UF + 5) /* DMS */ #define UNIT_V_IOP (UNIT_V_UF + 5) /* 2100 IOP */
#define UNIT_V_IOP (UNIT_V_UF + 6) /* 2100 IOP */ #define UNIT_V_IOPX (UNIT_V_UF + 6) /* 21MX IOP */
#define UNIT_V_IOPX (UNIT_V_UF + 7) /* 21MX IOP */ #define UNIT_V_MSIZE (UNIT_V_UF + 7) /* dummy mask */
#define UNIT_V_MSIZE (UNIT_V_UF + 8) /* dummy mask */ #define UNIT_2116 (0)
#define UNIT_2100 (1 << UNIT_V_2100) #define UNIT_2100 (1 << UNIT_V_2100)
#define UNIT_21MX (1 << UNIT_V_21MX) #define UNIT_21MX (1 << UNIT_V_21MX)
#define UNIT_EAU (1 << UNIT_V_EAU) #define UNIT_EAU (1 << UNIT_V_EAU)
#define UNIT_FP (1 << UNIT_V_FP) #define UNIT_FP (1 << UNIT_V_FP)
#define UNIT_MPR (1 << UNIT_V_MPR)
#define UNIT_DMS (1 << UNIT_V_DMS) #define UNIT_DMS (1 << UNIT_V_DMS)
#define UNIT_IOP (1 << UNIT_V_IOP) #define UNIT_IOP (1 << UNIT_V_IOP)
#define UNIT_IOPX (1 << UNIT_V_IOPX) #define UNIT_IOPX (1 << UNIT_V_IOPX)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 out */
#define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 out */
#define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 out */
#define UNIT_MP_JSB (1 << UNIT_V_MP_JSB)
#define UNIT_MP_INT (1 << UNIT_V_MP_INT)
#define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1)
#define MOD_2116 1 #define MOD_2116 1
#define MOD_2100 2 #define MOD_2100 2
#define MOD_21MX 4 #define MOD_21MX 4
@ -378,18 +406,23 @@ struct opt_table { /* options table */
int32 cpuf; }; int32 cpuf; };
static struct opt_table opt_val[] = { static struct opt_table opt_val[] = {
{ UNIT_EAU, MOD_2116 }, { UNIT_EAU, MOD_2116 },
{ UNIT_FP, MOD_2100 }, { UNIT_FP, MOD_2100 },
{ UNIT_MPR, MOD_2100 | MOD_21MX }, { UNIT_DMS, MOD_21MX },
{ UNIT_DMS, MOD_21MX }, { UNIT_IOP, MOD_2100 | MOD_21MX },
{ UNIT_IOP, MOD_2100 | MOD_21MX }, { UNIT_2116, MOD_2116 | MOD_2100 | MOD_21MX },
{ UNIT_2100, MOD_2116 | MOD_2100 | MOD_21MX },
{ UNIT_21MX, MOD_2116 | MOD_2100 | MOD_21MX },
{ 0, 0 } }; { 0, 0 } };
extern int32 sim_interval; extern int32 sim_interval;
extern int32 sim_int_char; extern int32 sim_int_char;
extern int32 sim_brk_char;
extern int32 sim_del_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern FILE *sim_log; extern FILE *sim_log;
extern DEVICE *sim_devices[]; extern DEVICE *sim_devices[];
extern int32 sim_switches;
extern char halt_msg[]; extern char halt_msg[];
t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); t_stat Ea (uint32 IR, uint32 *addr, uint32 irq);
@ -421,6 +454,7 @@ 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_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr); t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat cpu_boot (int32 unitno, DEVICE *dptr);
t_stat mp_reset (DEVICE *dptr);
t_stat dma0_reset (DEVICE *dptr); t_stat dma0_reset (DEVICE *dptr);
t_stat dma1_reset (DEVICE *dptr); t_stat dma1_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
@ -458,13 +492,6 @@ REG cpu_reg[] = {
{ FLDATA (ION, ion, 0) }, { FLDATA (ION, ion, 0) },
{ FLDATA (ION_DEFER, ion_defer, 0) }, { FLDATA (ION_DEFER, ion_defer, 0) },
{ ORDATA (CIR, intaddr, 6) }, { ORDATA (CIR, intaddr, 6) },
{ FLDATA (MPCTL, dev_ctl[PRO/32], INT_V (PRO)) },
{ FLDATA (MPFLG, dev_flg[PRO/32], INT_V (PRO)) },
{ FLDATA (MPFBF, dev_fbf[PRO/32], INT_V (PRO)) },
{ ORDATA (MPFR, mp_fence, 15) },
{ ORDATA (MPVR, mp_viol, 16) },
{ FLDATA (MPMEV, mp_mevff, 0) },
{ FLDATA (MPEVR, mp_evrff, 0) },
{ FLDATA (DMSENB, dms_enb, 0) }, { FLDATA (DMSENB, dms_enb, 0) },
{ FLDATA (DMSCUR, dms_ump, VA_N_PAG) }, { FLDATA (DMSCUR, dms_ump, VA_N_PAG) },
{ ORDATA (DMSSR, dms_sr, 16) }, { ORDATA (DMSSR, dms_sr, 16) },
@ -476,7 +503,9 @@ REG cpu_reg[] = {
{ DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT },
{ BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC },
{ ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (PCQP, pcq_p, 6), REG_HRO },
{ ORDATA (WRU, sim_int_char, 8) }, { ORDATA (WRU, sim_int_char, 8), REG_HRO },
{ ORDATA (BRK, sim_brk_char, 8), REG_HRO },
{ ORDATA (DEL, sim_del_char, 8), REG_HRO },
{ ORDATA (HCMD, dev_cmd[0], 32), REG_HRO }, { ORDATA (HCMD, dev_cmd[0], 32), REG_HRO },
{ ORDATA (LCMD, dev_cmd[1], 32), REG_HRO }, { ORDATA (LCMD, dev_cmd[1], 32), REG_HRO },
{ ORDATA (HCTL, dev_ctl[0], 32), REG_HRO }, { ORDATA (HCTL, dev_ctl[0], 32), REG_HRO },
@ -490,15 +519,18 @@ REG cpu_reg[] = {
{ NULL } }; { NULL } };
MTAB cpu_mod[] = { MTAB cpu_mod[] = {
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP+UNIT_IOPX, { UNIT_2116+UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_DMS+UNIT_IOP+UNIT_IOPX,
0, NULL, "2116", NULL }, UNIT_2116, NULL, "2116", &cpu_set_opt,
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP+UNIT_IOPX, NULL, (void *) UNIT_2116 },
UNIT_2100+UNIT_EAU, NULL, "2100", NULL }, { UNIT_2116+UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_DMS+UNIT_IOP+UNIT_IOPX,
{ UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP+UNIT_IOPX, UNIT_2100+UNIT_EAU, NULL, "2100", &cpu_set_opt,
UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS, NULL, "21MX", NULL }, NULL, (void *) UNIT_2100 },
{ UNIT_2100+UNIT_21MX, 0, "2116", NULL, NULL }, { UNIT_2116+UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_DMS+UNIT_IOP+UNIT_IOPX,
{ UNIT_2100+UNIT_21MX, UNIT_2100, "2100", NULL, NULL }, UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_DMS, NULL, "21MX", &cpu_set_opt,
{ UNIT_2100+UNIT_21MX, UNIT_21MX, "21MX", NULL, NULL }, NULL, (void *) UNIT_21MX },
{ UNIT_2116+UNIT_2100+UNIT_21MX, UNIT_2116, "2116", NULL, NULL },
{ UNIT_2116+UNIT_2100+UNIT_21MX, UNIT_2100, "2100", NULL, NULL },
{ UNIT_2116+UNIT_2100+UNIT_21MX, UNIT_21MX, "21MX", NULL, NULL },
{ UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt,
NULL, (void *) UNIT_EAU }, NULL, (void *) UNIT_EAU },
{ UNIT_EAU, 0, "no EAU", "NOEAU", &cpu_set_opt, { UNIT_EAU, 0, "no EAU", "NOEAU", &cpu_set_opt,
@ -507,10 +539,6 @@ MTAB cpu_mod[] = {
NULL, (void *) UNIT_FP }, NULL, (void *) UNIT_FP },
{ UNIT_FP, 0, "no FP", "NOFP", &cpu_set_opt, { UNIT_FP, 0, "no FP", "NOFP", &cpu_set_opt,
NULL, (void *) UNIT_FP }, NULL, (void *) UNIT_FP },
{ UNIT_MPR, UNIT_MPR, "MPR", "MPR", &cpu_set_opt,
NULL, (void *) UNIT_MPR },
{ UNIT_MPR, 0, "no MPR", "NOMPR", &cpu_set_opt,
NULL, (void *) UNIT_MPR },
{ UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt,
NULL, (void *) UNIT_DMS }, NULL, (void *) UNIT_DMS },
{ UNIT_DMS, 0, "no DMS", "NODMS", &cpu_set_opt, { UNIT_DMS, 0, "no DMS", "NODMS", &cpu_set_opt,
@ -538,6 +566,43 @@ DEVICE cpu_dev = {
&cpu_ex, &cpu_dep, &cpu_reset, &cpu_ex, &cpu_dep, &cpu_reset,
&cpu_boot, NULL, NULL }; &cpu_boot, NULL, NULL };
/* Memory protect data structures
mp_dev MP device descriptor
mp_unit MP unit descriptor
mp_reg MP register list
mp_mod MP modifiers list
*/
UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) };
REG mp_reg[] = {
{ FLDATA (CTL, dev_ctl[PRO/32], INT_V (PRO)) },
{ FLDATA (FLG, dev_flg[PRO/32], INT_V (PRO)) },
{ FLDATA (FBF, dev_fbf[PRO/32], INT_V (PRO)) },
{ ORDATA (FR, mp_fence, 15) },
{ ORDATA (VR, mp_viol, 16) },
{ FLDATA (MEV, mp_mevff, 0) },
{ FLDATA (EVR, mp_evrff, 0) },
{ NULL } };
MTAB mp_mod[] = {
{ UNIT_MP_JSB, UNIT_MP_JSB, "JSB (W5) in", "JSBIN", NULL },
{ UNIT_MP_JSB, 0, "JSB (W5) out", "JSBOUT", NULL },
{ UNIT_MP_INT, UNIT_MP_INT, "INT (W6) in", "INTIN", NULL },
{ UNIT_MP_INT, 0, "INT (W6) out", "INTOUT", NULL },
{ UNIT_MP_SEL1, UNIT_MP_SEL1, "SEL1 (W7) in", "SEL1IN", NULL },
{ UNIT_MP_SEL1, 0, "SEL1 (W7) out", "SEL1OUT", NULL },
{ 0 } };
DEVICE mp_dev = {
"MP", &mp_unit, mp_reg, mp_mod,
1, 8, 1, 1, 8, 16,
NULL, NULL, &mp_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DIS };
/* DMA controller data structures /* DMA controller data structures
dmax_dev DMAx device descriptor dmax_dev DMAx device descriptor
@ -560,7 +625,8 @@ DEVICE dma0_dev = {
"DMA0", &dma0_unit, dma0_reg, NULL, "DMA0", &dma0_unit, dma0_reg, NULL,
1, 8, 1, 1, 8, 16, 1, 8, 1, 1, 8, 16,
NULL, NULL, &dma0_reset, NULL, NULL, &dma0_reset,
NULL, NULL, NULL }; NULL, NULL, NULL,
NULL, DEV_DISABLE };
UNIT dma1_unit = { UDATA (NULL, 0, 0) }; UNIT dma1_unit = { UDATA (NULL, 0, 0) };
@ -578,7 +644,8 @@ DEVICE dma1_dev = {
"DMA1", &dma1_unit, dma1_reg, NULL, "DMA1", &dma1_unit, dma1_reg, NULL,
1, 8, 1, 1, 8, 16, 1, 8, 1, 1, 8, 16,
NULL, NULL, &dma1_reset, NULL, NULL, &dma1_reset,
NULL, NULL, NULL }; NULL, NULL, NULL,
NULL, DEV_DISABLE };
/* Extended instruction decode tables */ /* Extended instruction decode tables */
@ -715,6 +782,17 @@ reason = 0;
/* Restore I/O state */ /* Restore I/O state */
if (mp_dev.flags & DEV_DIS) dtab[PRO] = NULL;
else dtab[PRO] = &proio; /* set up MP dispatch */
if (dma0_dev.flags & DEV_DIS) dtab[DMA0] = dtab[DMALT0] = NULL;
else { /* set up DMA0 dispatch */
dtab[DMA0] = &dmpio;
dtab[DMALT0] = &dmsio; }
if (dma1_dev.flags & DEV_DIS) dtab[DMA1] = dtab[DMALT1] = NULL;
else { /* set up DMA1 dispatch */
dtab[DMA1] = &dmpio;
dtab[DMALT1] = &dmsio; }
for (i = VARDEV; i <= I_DEVMASK; i++) dtab[i] = NULL; /* clr disp table */ for (i = VARDEV; i <= I_DEVMASK; i++) dtab[i] = NULL; /* clr disp table */
dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */ dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */
dev_ctl[0] = dev_ctl[0] & M_FXDEV; dev_ctl[0] = dev_ctl[0] & M_FXDEV;
@ -846,6 +924,8 @@ case 0034:case 0035:case 0036:case 0037:
case 0230:case 0231:case 0232:case 0233: case 0230:case 0231:case 0232:case 0233:
case 0234:case 0235:case 0236:case 0237: case 0234:case 0235:case 0236:case 0237:
if (reason = Ea (IR, &MA, intrq)) break; /* JSB */ if (reason = Ea (IR, &MA, intrq)) break; /* JSB */
if ((mp_unit.flags & UNIT_MP_JSB) && CTL (PRO) && (MA < mp_fence))
ABORT (ABORT_PRO); /* MP if W7 (JSB) out */
WriteW (MA, PC); /* store PC */ WriteW (MA, PC); /* store PC */
PCQ_ENTRY; PCQ_ENTRY;
PC = (MA + 1) & VAMASK; /* jump */ PC = (MA + 1) & VAMASK; /* jump */
@ -1850,8 +1930,9 @@ uint32 i, MA;
MA = IR & (I_IA | I_DISP); /* ind + disp */ MA = IR & (I_IA | I_DISP); /* ind + disp */
if (IR & I_CP) MA = ((PC - 1) & I_PAGENO) | MA; /* current page? */ if (IR & I_CP) MA = ((PC - 1) & I_PAGENO) | MA; /* current page? */
for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */
if ((i >= 2) && irq && /* >3 levels, int req, */ if (irq && /* int req? */
(cpu_unit.flags & UNIT_MPR)) /* mprot installed? */ ((i >= 2) || (mp_unit.flags & UNIT_MP_INT)) && /* ind > 3 or W6 out? */
!(mp_unit.flags & DEV_DIS)) /* MP installed? */
return STOP_INDINT; /* break out */ return STOP_INDINT; /* break out */
MA = ReadW (MA & VAMASK); } MA = ReadW (MA & VAMASK); }
if (i >= ind_max) return STOP_IND; /* indirect loop? */ if (i >= ind_max) return STOP_IND; /* indirect loop? */
@ -1868,8 +1949,9 @@ uint32 i, MA;
MA = ReadW (PC); /* get next address */ MA = ReadW (PC); /* get next address */
PC = (PC + 1) & VAMASK; PC = (PC + 1) & VAMASK;
for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */
if ((i >= 2) && irq && /* >3 levels, int req, */ if (irq && /* int req? */
(cpu_unit.flags & UNIT_MPR)) /* mprot installed? */ ((i >= 2) || (mp_unit.flags & UNIT_MP_INT)) && /* ind > 3 or W6 out? */
!(mp_unit.flags & DEV_DIS)) /* MP installed? */
return STOP_INDINT; /* break out */ return STOP_INDINT; /* break out */
MA = ReadW (MA & VAMASK); } MA = ReadW (MA & VAMASK); }
if (i >= ind_max) return STOP_IND; /* indirect loop? */ if (i >= ind_max) return STOP_IND; /* indirect loop? */
@ -1922,7 +2004,8 @@ uint32 dev, sop, iodata, ab;
ab = (ir & I_AB)? 1: 0; /* get A/B select */ ab = (ir & I_AB)? 1: 0; /* get A/B select */
dev = ir & I_DEVMASK; /* get device */ dev = ir & I_DEVMASK; /* get device */
sop = I_GETIOOP (ir); /* get subopcode */ sop = I_GETIOOP (ir); /* get subopcode */
if (!iotrap && CTL (PRO) && ((sop == ioHLT) || (dev != OVF))) { /* protected? */ if (!iotrap && CTL (PRO) && /* protected? */
((sop == ioHLT) || ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) {
if (sop == ioLIX) ABREG[ab] = 0; /* A/B writes anyway */ if (sop == ioLIX) ABREG[ab] = 0; /* A/B writes anyway */
ABORT (ABORT_PRO); } ABORT (ABORT_PRO); }
iodata = devdisp (dev, sop, ir, ABREG[ab]); /* process I/O */ iodata = devdisp (dev, sop, ir, ABREG[ab]); /* process I/O */
@ -2248,6 +2331,8 @@ return dms_sr;
/* Device 0 (CPU) I/O routine /* Device 0 (CPU) I/O routine
NOTE: LIx/MIx reads floating I/O bus (0 on all machines).
From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" to both test From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" to both test
and turn off the interrupt system. This is confirmed in the "RTE-6/VM and turn off the interrupt system. This is confirmed in the "RTE-6/VM
Technical Specifications" manual (HP 92084-90015), section 2.3.1 "Process Technical Specifications" manual (HP 92084-90015), section 2.3.1 "Process
@ -2295,7 +2380,9 @@ if (IR & I_HC) ion = 0; /* HC option */
return dat; return dat;
} }
/* Device 1 (overflow) I/O routine */ /* Device 1 (overflow) I/O routine
NOTE: The S register is read-only on the 2115/2116. */
int32 ovfio (int32 inst, int32 IR, int32 dat) int32 ovfio (int32 inst, int32 IR, int32 dat)
{ {
@ -2316,7 +2403,7 @@ case ioLIX: /* load */
dat = SR; dat = SR;
break; break;
case ioOTX: /* output */ case ioOTX: /* output */
SR = dat; if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) SR = dat;
break; break;
default: default:
break; } break; }
@ -2348,8 +2435,6 @@ return dat;
int32 proio (int32 inst, int32 IR, int32 dat) int32 proio (int32 inst, int32 IR, int32 dat)
{ {
if ((cpu_unit.flags & UNIT_MPR) == 0) /* not installed? */
return nulio (inst, IR, dat); /* non-existent dev */
switch (inst) { /* case on opcode */ switch (inst) { /* case on opcode */
case ioSFC: /* skip flag clear */ case ioSFC: /* skip flag clear */
if (!mp_mevff) PC = (PC + 1) & VAMASK; /* skip if mem prot */ if (!mp_mevff) PC = (PC + 1) & VAMASK; /* skip if mem prot */
@ -2407,7 +2492,9 @@ default:
return dat; return dat;
} }
/* Devices 6,7 (primary DMA) I/O routine */ /* Devices 6,7 (primary DMA) I/O routine
NOTE: LIx/MIx reads floating S-bus (1 on 21MX, 0 on 2116/2100). */
int32 dmpio (int32 inst, int32 IR, int32 dat) int32 dmpio (int32 inst, int32 IR, int32 dat)
{ {
@ -2426,8 +2513,10 @@ case ioSFC: /* skip flag clear */
case ioSFS: /* skip flag set */ case ioSFS: /* skip flag set */
if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK; if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK;
break; break;
case ioMIX: case ioLIX: /* load, merge */ case ioLIX: /* load */
dat = DMASK; dat = 0;
case ioMIX: /* merge */
if (cpu_unit.flags & UNIT_21MX) dat = DMASK;
break; break;
case ioOTX: /* output */ case ioOTX: /* output */
dmac[ch].cw1 = dat; dmac[ch].cw1 = dat;
@ -2495,19 +2584,27 @@ else { if (inp) { /* last cycle, input? */
return; return;
} }
/* Unimplemented device routine */ /* Unimplemented device routine
NOTE: For SC < 10, LIx/MIx reads floating S-bus (-1 on 21MX, 0 on 2116/2100).
For SC >= 10, LIx/MIx reads floating I/O bus (0 on all machines). */
int32 nulio (int32 inst, int32 IR, int32 dat) int32 nulio (int32 inst, int32 IR, int32 dat)
{ {
int32 devd;
devd = IR & I_DEVMASK; /* get device no */
switch (inst) { /* case on opcode */ switch (inst) { /* case on opcode */
case ioSFC: /* skip flag clear */ case ioSFC: /* skip flag clear */
PC = (PC + 1) & VAMASK; PC = (PC + 1) & VAMASK;
return (stop_dev << IOT_V_REASON) | dat; break;
case ioSFS: /* skip flag set */ case ioLIX: /* load */
return (stop_dev << IOT_V_REASON) | dat; dat = 0;
case ioMIX: /* merge */
if ((devd < VARDEV) && (cpu_unit.flags & UNIT_21MX)) dat = DMASK;
break;
default: default:
break; } break; }
if (IR & I_HC) { clrFLG (IR & I_DEVMASK); } /* HC option */
return (stop_dev << IOT_V_REASON) | dat; return (stop_dev << IOT_V_REASON) | dat;
} }
@ -2522,30 +2619,35 @@ clrCMD (PWR);
clrCTL (PWR); clrCTL (PWR);
clrFLG (PWR); clrFLG (PWR);
clrFBF (PWR); clrFBF (PWR);
clrCMD (PRO);
clrCTL (PRO);
clrFLG (PRO);
clrFBF (PRO);
dev_srq[0] = dev_srq[0] & ~M_FXDEV; dev_srq[0] = dev_srq[0] & ~M_FXDEV;
mp_fence = 0; /* init mprot */
mp_viol = 0;
mp_mevff = 0;
mp_evrff = 1;
dms_enb = dms_ump = 0; /* init DMS */ dms_enb = dms_ump = 0; /* init DMS */
dms_sr = 0; dms_sr = 0;
dms_vr = 0; dms_vr = 0;
pcq_r = find_reg ("PCQ", NULL, dptr); pcq_r = find_reg ("PCQ", NULL, dptr);
sim_brk_types = ALL_BKPTS; sim_brk_types = ALL_BKPTS;
sim_brk_dflt = SWMASK ('E'); sim_brk_dflt = SWMASK ('E');
if (M == NULL) M = calloc (PASIZE, sizeof (unsigned int16)); if (M == NULL) M = calloc (PASIZE, sizeof (uint16));
if (M == NULL) return SCPE_MEM; if (M == NULL) return SCPE_MEM;
if (pcq_r) pcq_r->qptr = 0; if (pcq_r) pcq_r->qptr = 0;
else return SCPE_IERR; else return SCPE_IERR;
return SCPE_OK; return SCPE_OK;
} }
t_stat mp_reset (DEVICE *dptr)
{
clrCTL (PRO);
clrFLG (PRO);
clrFBF (PRO);
mp_fence = 0; /* init mprot */
mp_viol = 0;
mp_mevff = 0;
mp_evrff = 1;
return SCPE_OK;
}
t_stat dma0_reset (DEVICE *tptr) t_stat dma0_reset (DEVICE *tptr)
{ {
hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */
clrCMD (DMA0); clrCMD (DMA0);
clrCTL (DMA0); clrCTL (DMA0);
setFLG (DMA0); setFLG (DMA0);
@ -2556,6 +2658,7 @@ return SCPE_OK;
t_stat dma1_reset (DEVICE *tptr) t_stat dma1_reset (DEVICE *tptr)
{ {
hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */
clrCMD (DMA1); clrCMD (DMA1);
clrCTL (DMA1); clrCTL (DMA1);
setFLG (DMA1); setFLG (DMA1);
@ -2601,9 +2704,10 @@ uint32 i;
if ((val <= 0) || (val > PASIZE) || ((val & 07777) != 0) || if ((val <= 0) || (val > PASIZE) || ((val & 07777) != 0) ||
(!(uptr->flags & UNIT_21MX) && (val > 32768))) (!(uptr->flags & UNIT_21MX) && (val > 32768)))
return SCPE_ARG; return SCPE_ARG;
for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
return SCPE_OK; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_INCOMP; }
MEMSIZE = val; MEMSIZE = val;
for (i = MEMSIZE; i < PASIZE; i++) M[i] = 0; for (i = MEMSIZE; i < PASIZE; i++) M[i] = 0;
return SCPE_OK; return SCPE_OK;
@ -2679,7 +2783,11 @@ for (i = 0; cdptr = sim_devices[i]; i++) {
return FALSE; return FALSE;
} }
/* Configuration validation */ /* Configuration validation
Memory is trimmed to 32K if 2116 or 2100 is selected.
Memory protect is enabled if 2100 or 21MX or DMS is selected.
DMA is enabled if 2116 or 2100 or 21MX is selected. */
t_bool cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) t_bool cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc)
{ {
@ -2689,15 +2797,22 @@ int32 mod, i;
mod = MOD_2116; mod = MOD_2116;
if (uptr->flags & UNIT_2100) mod = MOD_2100; if (uptr->flags & UNIT_2100) mod = MOD_2100;
else if (uptr->flags & UNIT_21MX) mod = MOD_21MX; else if (uptr->flags & UNIT_21MX) mod = MOD_21MX;
for (i = 0; opt_val[i].optf != 0; i++) { for (i = 0; opt_val[i].cpuf != 0; i++) {
if ((opt == opt_val[i].optf) && (mod & opt_val[i].cpuf)) { if ((opt == opt_val[i].optf) && (mod & opt_val[i].cpuf)) {
if ((mod == MOD_2100) && (val == UNIT_FP)) if ((mod == MOD_2100) && (val == UNIT_FP))
uptr->flags = uptr->flags & ~UNIT_IOP; uptr->flags = uptr->flags & ~UNIT_IOP;
if ((opt == UNIT_IOP) && val) { if ((opt == UNIT_IOP) && val) {
if (mod == MOD_2100) uptr->flags = if (mod == MOD_2100)
(uptr->flags & ~UNIT_FP) | UNIT_IOP | UNIT_MPR; uptr->flags = (uptr->flags & ~UNIT_FP) | UNIT_IOP;
if (mod == MOD_21MX) uptr->flags |= UNIT_IOPX | UNIT_MPR; } if (mod == MOD_21MX) uptr->flags |= UNIT_IOPX; }
if (val == UNIT_DMS) uptr->flags |= UNIT_MPR; if (opt == UNIT_2116) mp_dev.flags = mp_dev.flags | DEV_DIS;
else if ((val == UNIT_DMS) || (opt == UNIT_2100) || (opt == UNIT_21MX))
mp_dev.flags = mp_dev.flags & ~DEV_DIS;
if ((opt == UNIT_2116) || (opt == UNIT_2100) || (opt == UNIT_21MX)) {
dma0_dev.flags = dma0_dev.flags & ~DEV_DIS;
dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; }
if (((opt == UNIT_2116) || (opt == UNIT_2100)) && (MEMSIZE > 32768))
return cpu_set_size (uptr, 32768, cptr, desc);
return SCPE_OK; } } return SCPE_OK; } }
return SCPE_NOFNC; return SCPE_NOFNC;
} }

View file

@ -35,7 +35,8 @@
14-Apr-99 RMS Changed t_addr to unsigned 14-Apr-99 RMS Changed t_addr to unsigned
The author gratefully acknowledges the help of Jeff Moffat in answering The author gratefully acknowledges the help of Jeff Moffat in answering
questions about the HP2100. questions about the HP2100; and of Dave Bryan in adding featurs and
correcting errors throughout the simulator.
*/ */
#include "sim_defs.h" /* simulator defns */ #include "sim_defs.h" /* simulator defns */
@ -195,12 +196,12 @@ struct DMA { /* DMA channel */
/* I/O devices - variable assignment defaults */ /* I/O devices - variable assignment defaults */
#define PTR 010 /* paper tape reader */ #define PTR 010 /* 12597A-002 paper tape reader */
#define TTY 011 /* console */ #define TTY 011 /* 12531C teleprinter */
#define PTP 012 /* paper tape punch */ #define PTP 012 /* 12597A-005 paper tape punch */
#define CLK 013 /* clock */ #define CLK 013 /* 12539C time-base generator */
#define LPS 014 /* 12653 line printer */ #define LPS 014 /* 12653A line printer */
#define LPT 015 /* 12845 line printer */ #define LPT 015 /* 12845A line printer */
#define MTD 020 /* 12559A data */ #define MTD 020 /* 12559A data */
#define MTC 021 /* 12559A control */ #define MTC 021 /* 12559A control */
#define DPD 022 /* 12557A data */ #define DPD 022 /* 12557A data */
@ -211,9 +212,9 @@ struct DMA { /* DMA channel */
#define DRC 027 /* 12610A control */ #define DRC 027 /* 12610A control */
#define MSD 030 /* 13181A data */ #define MSD 030 /* 13181A data */
#define MSC 031 /* 13181A control */ #define MSC 031 /* 13181A control */
#define IPLI 032 /* 12556B link in */ #define IPLI 032 /* 12566B link in */
#define IPLO 033 /* 12556B link out */ #define IPLO 033 /* 12566B link out */
#define DS 034 /* 13037 control */ #define DS 034 /* 13037A control */
#define MUXL 040 /* 12920A lower data */ #define MUXL 040 /* 12920A lower data */
#define MUXU 041 /* 12920A upper data */ #define MUXU 041 /* 12920A upper data */
#define MUXC 042 /* 12920A control */ #define MUXC 042 /* 12920A control */

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: HP2100 Simulator Usage Subj: HP2100 Simulator Usage
Date: 20-Aug-2004 Date: 26-Oct-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -77,25 +77,27 @@ name(s)
CPU 2116 CPU with 32KW memory CPU 2116 CPU with 32KW memory
2100 CPU with 32KW memory, FP or IOP instructions 2100 CPU with 32KW memory, FP or IOP instructions
21MX CPU with 1024KW memory, FP or DMS instructions 21MX CPU with 1024KW memory, FP, DMS, and/or IOP instructions
DMA0, DMA1 dual channel DMA controller MP 12892B memory protect
PTR,PTP 12597A paper tape reader/punch DMA0, DMA1 12895A/12897B direct memory access/dual channel port controller
TTY 12531C buffered terminal controller PTR 12597A duplex register interface with 2748 paper tape reader
LPS 12653A printer controller with 2767 printer PTP 12597A duplex register interface with 2895 paper tape punch
12566B microcircuit interface for diagnostics TTY 12531C buffered teleprinter interface with 2752 teleprinter
LPT 12845A printer controller with 2607 printer LPS 12653A printer controller with 2767 line printer
CLK 12539A/B/C time base generator 12566B microcircuit interface with loopback connector
MUXL,MUXU,MUXC 12920A terminal multiplexor LPT 12845B printer controller with 2607 line printer
CLK 12539C time base generator
MUX,MUXL,MUXM 12920A terminal multiplexor
DP 12557A disk controller with four 2871 drives DP 12557A disk controller with four 2871 drives
13210A disk controller with four 7900 drives 13210A disk controller with four 7900 drives
DQ 12565A disk controller with two 2883 drives DQ 12565A disk controller with two 2883 drives
DR 12606B fixed head disk controller with 2770/2771 disks DR 12606B fixed head disk controller with 2770/2771 disk
12610B drum controller with 2773/2774/2775 drums 12610B drum controller with 2773/2774/2775 drum
MT 12559C magnetic tape controller with one 3030 drive MT 12559C magnetic tape controller with one 3030 drive
MS 13181A magnetic tape controller with four 7970B drives MS 13181A magnetic tape controller with four 7970B drives
13183A magnetic tape controller with four 7970E drives 13183A magnetic tape controller with four 7970E drives
IPLI 12556B interprocessor link, input side IPLI 12566B interprocessor link, input side
IPLO 12556B interprocessor link, output side IPLO 12566B interprocessor link, output side
The HP2100 simulator implements several unique stop conditions: The HP2100 simulator implements several unique stop conditions:
@ -109,7 +111,12 @@ command is not implemented.
2.1 CPU 2.1 CPU
CPU options include choice of instruction set and memory size. CPU options include choice of instruction set and memory size. The
general command form is:
SET {-F} CPU <option>
Options that may be specified are:
SET CPU 2116 2116 CPU SET CPU 2116 2116 CPU
SET CPU 2100 2100 CPU SET CPU 2100 2100 CPU
@ -133,13 +140,21 @@ CPU options include choice of instruction set and memory size.
SET CPU 1024K set memory size = 1024K (21MX only) SET CPU 1024K set memory size = 1024K (21MX only)
On the 2100, EAU is standard, and the FP and IOP options are mutually On the 2100, EAU is standard, and the FP and IOP options are mutually
exclusive. On the 21MX, EAU and FP are standard. The 2100 and 21MX exclusive. On the 21MX, EAU and FP are standard. The 21MX optionally
include memory protection as standard; the 21MX optionally includes includes DMS (dynamic mapping system) and IOP instructions.
DMS (dynamic memory system).
If memory size is being reduced, and the memory being truncated contains Setting the CPU type to 2116, 2100, or 21MX establishes a consistent set
non-zero data, the simulator asks for confirmation. Data in the truncated of common options. Additional SET CPU commands may follow to fine-tune
portion of memory is lost. Initial memory size is 32K. the desired feature set.
The initial memory size is 32K. Memory sizes larger than 32K are
supported only on the 21MX. If the memory size is being reduced, either
by setting a smaller size or by changing the CPU model from 21MX to 2116
or 2100 when the current memory size is more than 32K, and the memory
being truncated contains non-zero data, the simulator asks for
confirmation before proceeding. The confirmation request may be
suppressed by using the "-F" switch. Data in the truncated portion of
memory is lost.
These switches are recognized when examining or depositing in CPU memory: These switches are recognized when examining or depositing in CPU memory:
@ -173,16 +188,9 @@ control registers for the interrupt system.
O all 1 overflow flag O all 1 overflow flag
ION all 1 interrupt enable flag ION all 1 interrupt enable flag
ION_DEFER all 1 interrupt defer flag ION_DEFER all 1 interrupt defer flag
CIR all 6 current interrupt register CIR all 6 central interrupt register
MPCTL 2100,21MX 1 memory protection enable
MPFLG 2100,21MX 1 memory protection flag
MPFBF 2100,21MX 1 memory protection flag buffer
MPFR 2100,21MX 15 memory protection fence
MPVR 2100,21MX 16 memory protection violation reg
MPEVR 2100,21MX 1 memory protection freeze flag
MPMEV 2100,21MX 1 memory protection DMS error flag
DMSENB 21MX 1 DMS enable DMSENB 21MX 1 DMS enable
DMSCUR 21MX 1 DMS current mode DMSCUR 21MX 1 DMS current map (1 = user map)
DMSSR 21MX 16 DMS status register DMSSR 21MX 16 DMS status register
DMSVR 21MX 16 DMS violation register DMSVR 21MX 16 DMS violation register
DMSMAP[128] 21MX 16 DMS maps DMSMAP[128] 21MX 16 DMS maps
@ -195,12 +203,11 @@ control registers for the interrupt system.
INDMAX all 16 indirect address limit INDMAX all 16 indirect address limit
PCQ[0:63] all 15 P of last JMP, JSB, or interrupt; PCQ[0:63] all 15 P of last JMP, JSB, or interrupt;
most recent P change first most recent P change first
WRU all 8 interrupt character
BOOT CPU implements the 21MX IBL facility. IBL is controlled by the switch BOOT CPU implements the 21MX IBL facility. IBL is controlled by the switch
register S. S<15:14> selects the device to boot: register S. S<15:14> selects the device to boot:
00 paper-tape reader (12992K ROM) 00 2748B paper-tape reader (12992K ROM)
01 7900A/2883 disk (12992A ROM) 01 7900A/2883 disk (12992A ROM)
10 7970B/E tape (12992D ROM) 10 7970B/E tape (12992D ROM)
11 undefined 11 undefined
@ -215,10 +222,51 @@ specifies the lower address. S<5:3> are passed to the bootstrap program.
S<2:0> specify options for the boot loader. IBL will not report an error if S<2:0> specify options for the boot loader. IBL will not report an error if
the device address in S<11:6> is incorrect. the device address in S<11:6> is incorrect.
2.2 DMA Controllers 2.2 Memory Protect
The HP2100 includes two DMA channel controllers (DMA0 and DMA1). Each Memory protect is standard equipment on the 2100 (although it may be
DMA channel has the following visible state: disabled by removing a jumper) and optional on the 2116 and 21MX. The
following registers are implemented:
name size comments
CTL 1 memory protection enable
FLG 1 protection violation flag
FBF 1 protection violation flag buffer
FR 15 fence register
VR 16 violation register
EVR 1 enable violation register flag
MEV 1 memory expansion (DMS) violation flag
The 21MX memory protect card (12892B) has three feature options that
are implemented by jumper settings. These are controlled by the
following commands:
SET MP JSBIN jumper W5 installed
SET MP JSBOUT jumper W5 removed
SET MP INTIN jumper W6 installed
SET MP INTOUT jumper W6 removed
SET MP SEL1IN jumper W7 installed
SET MP SEL1OUT jumper W7 removed
W5 determines whether JSB instructions referencing memory locations 0
and 1 are legal (installed) or illegal (removed). W6 controls whether
the first three levels of indirect addressing hold off (installed) or
permit (removed) pending interrupts. W7 determines whether I/O
instructions referencing select codes other than 1 are legal (installed)
or illegal (removed); note that I/O instructions referencing select code
1 are legal, and HLT instructions are illegal, regardless of the setting
of W7.
The default configuration is JSB (W5) installed, INT (W6) installed, and
SEL1 (W7) removed, providing compatibility with the 2116 and 2100 memory
protect cards.
2.3 DMA/DCPC Controllers
The direct memory access/dual channel port controller is an option for
all three CPUs. DMA/DCPC provides two channel controllers (DMA0 and
DMA1). Each DMA channel has the following visible state:
name size comments name size comments
@ -230,7 +278,7 @@ DMA channel has the following visible state:
CW2 16 command word 2 CW2 16 command word 2
CW3 16 command word 3 CW3 16 command word 3
2.3 Variable Device Assignments 2.4 Variable Device Assignments
On the HP2100, I/O device take their device numbers from the backplane On the HP2100, I/O device take their device numbers from the backplane
slot they are plugged into. Thus, device number assignments vary slot they are plugged into. Thus, device number assignments vary
@ -253,25 +301,47 @@ changed; the higher is automatically set to the lower + 1. If a
device number conflict occurs, the simulator will return an error device number conflict occurs, the simulator will return an error
when started. when started.
In addition, most devices can be enabled or disabled. To enable a 2.4.1 Device State
device, use the SET <dev> ENABLED command:
sim> SET DPC ENABLED All devices other than the CPU and TTY may be disabled or enabled.
Disabling a device simulates removing the associated interface from the
CPU card cage. To disable or enable a device, use:
To disable a device, use the SET <dev> DISABLED command: SET <dev> DISABLED disable device
SET <dev> ENABLED enable device
sim> SET DPC DISABLED
For devices with more than one device number, disabling or enabling any For devices with more than one device number, disabling or enabling any
device in the set disables all the devices. device in the set disables or enables all of the devices.
2.4 Programmed I/O Devices Devices consisting of multiple addressible units connected to a controller
typically allow the units to be individually enabled or disabled. Disabled
simulates disconnecting the associated unit from the controller. The
commands to set units enabled and disabled are:
2.4.1 12597A-002 Paper Tape Reader (PTR) SET <unit> DISABLED disable unit
SET <unit> ENABLED enable unit
The paper tape reader (PTR) reads data from a disk file. The POS Some devices and units allow simulation of power-down conditions. Power
register specifies the number of the next data item to be read. settings are controlled by these commands:
Thus, by changing POS, the user can backspace or advance the reader.
SET <dev> POWEROFF turn power off
SET <dev> POWERON turn power on
Peripherals that provide operator-selectable disconnection, typically via an
"offline" switch, provide these simulation equivalents:
SET <dev> OFFLINE set peripheral offline
SET <dev> ONLINE set peripheral online
2.5 Programmed I/O Devices
2.5.1 12597A-002 Duplex Register Interface (PTR) with 2748 Paper Tape Reader
The paper tape reader (PTR) reads data from a disk file. For diagnostic
purposes, a tape loop may be simulated with the commands:
SET PTR DIAG rewind tape at EOF
SET PTR READER supply tape trailer at EOF
The paper tape reader supports the BOOT command. BOOT PTR copies the The paper tape reader supports the BOOT command. BOOT PTR copies the
IBL into memory and starts it running. The switch register (S) is IBL into memory and starts it running. The switch register (S) is
@ -298,6 +368,13 @@ The paper tape reader implements these registers:
TIME 24 time from I/O initiation to interrupt TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error STOP_IOE 1 stop on I/O error
The TRLLIM register specifies the number of nulls to supply as paper
tape trailer when EOF is detected. If TRLLIM is set to zero or the
count is exhausted, the reader will hang.
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.
Error handling is as follows: Error handling is as follows:
error STOP_IOE processed as error STOP_IOE processed as
@ -306,11 +383,11 @@ Error handling is as follows:
0 out of tape 0 out of tape
end of file 1 report error and stop end of file 1 report error and stop
0 out of tape or paper 0 out of tape
OS I/O error x report error and stop OS I/O error x report error and stop
2.4.2 12597A-005 Paper Tape Punch (PTP) 2.5.2 12597A-005 Duplex Register Interface (PTP) with 2895 Paper Tape Punch
The paper tape punch (PTP) writes data to a disk file. The POS 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. register specifies the number of the next data item to be written.
@ -339,23 +416,22 @@ Error handling is as follows:
OS I/O error x report error and stop OS I/O error x report error and stop
2.4.3 12531C Buffered Terminal (TTY) 2.5.3 12531C Buffered Teleprinter Interface (TTY) with 2752 Teleprinter
The console terminal has three units: keyboard (unit 0), printer The console teleprinter has three units: keyboard (unit 0), printer
(unit 1), and punch (unit 2). The keyboard reads from the console (unit 1), and punch (unit 2). The keyboard reads from the console
keyboard; the printer writes to the simulator console window. The keyboard; the printer writes to the simulator console window. The punch
punch writes to a disk file. The keyboard and printer units (TTY0, writes to a disk file. The keyboard and printer units (TTY0, TTY1) can
TTY1) can be set to one of three modes: UC, 7B, or 8B. In UC mode, be set to one of three modes: UC, 7B, or 8B. In UC mode, lower case
lower case input and output characters are automatically converted to input and output characters are automatically converted to upper case.
upper case. In 7B mode, input and output characters are masked to 7 In 7B mode, input and output characters are masked to 7 bits. In 8B
bits. In 8B mode, characters are not modified. In UC and 7B mode, mode, characters are not modified. In UC and 7B mode, output of control
output of null characters is suppressed; in 8B mode, output of null characters other than BEL, BS, HT, LF, and CR is suppressed; in 8B mode,
characters is permitted. Changing the mode of either the keyboard output of all characters is permitted. Changing the mode of either the
or the printer changes both. The default mode is UC. keyboard or the printer changes both. The default mode is UC.
Some HP software systems expect the console terminal to transmit Some HP software systems expect the console to transmit line-feed
line-feed automatically following carriage-return. This feature is automatically following carriage-return. This feature is enabled with:
enabled with:
SET TTY AUTOLF SET TTY AUTOLF
@ -389,22 +465,43 @@ Error handling for the punch is as follows:
OS I/O error x report error and stop OS I/O error x report error and stop
2.4.4 12653A Printer Controller (LPS) with 2767 Printer 2.5.4 12653A Printer Controller (LPS) with 2767 Line Printer
12566B Microcircuit Interface 12566B Microcircuit Interface with Loopback Connector
The 12653A line printer uses the 12566B microcircuit interface as The 2767 line printer uses the 12653A line printer interface as
its controller. As a line printer, LPS writes data to a disk file. its controller. As a line printer, LPS writes data to a disk file.
The POS register specifies the number of the next data item to be The POS register specifies the number of the next data item to be
written. Thus, by changing POS, the user can backspace or advance written. Thus, by changing POS, the user can backspace or advance
the printer. the printer.
As a microcircuit interface, LPS provides the DMA test device for The line printer responds to SET LPS POWEROFF as if the power were removed
running the dual channel port controller and DMS diagnostics. Printer or the printer cable were disconnected and DETACH LPS as if the paper were
mode verus diagnostic mode is controlled by the commands: out. It also provides these additional state commands:
SET LPS OFFLINE simulate ONLINE button up
SET LPS ONLINE simulate ONLINE button down
SET LPS REALTIME use realistic timing for print operations
SET LPS FASTTIME use optimized timing for print operations
As a 12566B microcircuit interface, LPS provides the test device for
running several of the HP diagnostics. Printer mode verus diagnostic
mode is controlled by the commands:
SET LPS PRINTER configure as line printer SET LPS PRINTER configure as line printer
SET LPS DIAG configure for diagnostic tests SET LPS DIAG configure for diagnostic tests
In diagnostic mode, LPS simulates the installation of the HP 1251-0332
diagnostic test (loopback) connector onto the 12566B card.
LPS may be configured to send debugging information to the previously
enabled debug output device using these commands:
SET LPS DEBUG provide debug printouts
SET LPS NODEBUG inhibit debug printouts
Diagnostic information includes characters supplied to and status received
from the interface, as well as data transfer initiations and completions.
The 12653A is disabled by default. The 12653A is disabled by default.
The 12653A implements these registers: The 12653A implements these registers:
@ -413,14 +510,19 @@ The 12653A implements these registers:
BUF 16 output buffer BUF 16 output buffer
STA 16 input buffer or status STA 16 input buffer or status
POWER 2 printer power state
CMD 1 printer enable CMD 1 printer enable
CTL 1 device/interrupt enable CTL 1 device/interrupt enable
FLG 1 device ready FLG 1 device ready
FBF 1 device ready buffer FBF 1 device ready buffer
SRQ 1 device DMA service request SRQ 1 device DMA service request
CCNT 7 current character count
LCNT 7 current line count
POS 32 position in the output file POS 32 position in the output file
CTIME 24 time between characters CTIME 24 character transfer time
PTIME 24 time for a print operation PTIME 24 per-zone print operation time
STIME 24 per-line paper slew time
RTIME 24 power-on ready delay time
STOP_IOE 1 stop on I/O error STOP_IOE 1 stop on I/O error
In printer mode, error handling is as follows: In printer mode, error handling is as follows:
@ -428,19 +530,26 @@ In printer mode, error handling is as follows:
error STOP_IOE processed as error STOP_IOE processed as
not attached 1 report error and stop not attached 1 report error and stop
0 out of tape or paper 0 out of paper
OS I/O error x report error and stop OS I/O error x report error and stop
In diagnostic mode, there are no errors; data sent to the output In diagnostic mode, there are no errors; data sent to the output
buffer is looped back to the status register with a fixed delay of 1. buffer is looped back to the status register with a fixed delay of 1.
2.4.5 12845A Printer Controller (LPT) 2.5.5 12845B Printer Controller (LPT) with 2607 Line Printer
The line printer (LPT) writes data to a disk file. The POS register 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, specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer. by changing POS, the user can backspace or advance the printer.
The line printer responds to SET LPT POWEROFF as if the power were
removed or the printer cable were disconnected and DETACH LPT as if the
paper were out. It also provides these additional state commands:
SET LPT OFFLINE simulate PAPER button up
SET LPT ONLINE simulate PAPER button down
The line printer implements these registers: The line printer implements these registers:
name size comments name size comments
@ -462,13 +571,22 @@ Error handling is as follows:
error STOP_IOE processed as error STOP_IOE processed as
not attached 1 report error and stop not attached 1 report error and stop
0 out of tape or paper 0 out of paper
OS I/O error x report error and stop OS I/O error x report error and stop
2.4.6 12539A/B/C Time Base Generator (CLK) 2.5.6 12539C Time Base Generator (CLK)
The time base generator (CLK) implements these registers: The time base generator (CLK) may be set for diagnostic mode:
SET CLK DIAG configure for diagnostic mode
SET CLK CALIBRATED configure for timing mode
Diagnostic mode corresponds to setting jumper W2 to position "B". This
turns off autocalibration and divides the longest time intervals down by
1000.
The time base generator implements these registers:
name size comments name size comments
@ -485,7 +603,7 @@ The time base generator autocalibrates; the clock interval is adjusted
up or down so that the clock tracks actual elapsed time. Operation at up or down so that the clock tracks actual elapsed time. Operation at
the fastest rates (100 usec, 1 msec) is not recommended. the fastest rates (100 usec, 1 msec) is not recommended.
2.4.7 12920A Terminal Multiplexor (MUXL, MUXU, MUXC) 2.5.7 12920A Terminal Multiplexor (MUX, MUXL, MUXM)
The 12920A is a 16-line terminal multiplexor, with five additional The 12920A is a 16-line terminal multiplexor, with five additional
receive-only diagnostic lines. It consists of three devices: receive-only diagnostic lines. It consists of three devices:
@ -494,7 +612,7 @@ receive-only diagnostic lines. It consists of three devices:
to the upper data card) to the upper data card)
MUXL individual lines (corresponding more or MUXL individual lines (corresponding more or
less to the lower data card) less to the lower data card)
MUXC modem control and status logic (corresponding MUXM modem control and status logic (corresponding
to the control card) to the control card)
The MUX performs input and output through Telnet sessions connected to a The MUX performs input and output through Telnet sessions connected to a
@ -578,11 +696,11 @@ The modem control (MUXM) implements these registers:
The terminal multiplexor does not support save and restore. All open The terminal multiplexor does not support save and restore. All open
connections are lost when the simulator shuts down or MUXU is detached. connections are lost when the simulator shuts down or MUX is detached.
2.4.8 Interprocessor Link (IPLI, IPLO) 2.5.8 Interprocessor Link (IPLI, IPLO)
The interprocessor link is a pair of 12556B parallel interfaces that The interprocessor link is a pair of 12566B parallel interfaces that
are cross coupled to provide interprocessor communications to a second are cross coupled to provide interprocessor communications to a second
copy of the HP2100 simulator. The IPL is intended to support simulation copy of the HP2100 simulator. The IPL is intended to support simulation
of a two system HP TimeShared Basic configuration. The links are actually of a two system HP TimeShared Basic configuration. The links are actually
@ -636,8 +754,8 @@ Both IPLI and IPLO implement these registers:
TIME 24 polling interval for input TIME 24 polling interval for input
STOP_IOE 1 stop on I/O error STOP_IOE 1 stop on I/O error
2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives 2.6 12557A Disk Controller (DPC, DPD) with Four 2781 Drives
13210A Disk Controller (DPC, DPD) with 7900 Drives 13210A Disk Controller (DPC, DPD) with Four 7900 Drives
The 12557A/13210A disk controller can be configured as either a The 12557A/13210A disk controller can be configured as either a
12557A, supporting 2.5MB drives, or a 13210A, supporting 5MB drives, 12557A, supporting 2.5MB drives, or a 13210A, supporting 5MB drives,
@ -651,9 +769,9 @@ one type or the other. The 13210A (for 7900/7901 disks) is selected
by default. by default.
The simulated controller has two separate devices, a data channel and The simulated controller has two separate devices, a data channel and
a device controller. The data channel includes a 128-word (one sector) a command channel. The data channel includes a 128-word (one sector)
buffer for reads and writes. The device controller includes the four buffer for reads and writes. The command channel includes the four
disk drives. Disk drives can be set ONLINE or OFFLINE. disk drives. Disk drives can be set DISABLED or ENABLED.
The 12557A/13210A supports the BOOT command. BOOT DPC copies the IBL The 12557A/13210A supports the BOOT command. BOOT DPC copies the IBL
for 7900 class disks into memory and starts it running. BOOT -R DPC for 7900 class disks into memory and starts it running. BOOT -R DPC
@ -683,7 +801,7 @@ The data channel implements these registers:
XFER 1 transfer in progress flag XFER 1 transfer in progress flag
WVAL 1 write data valid flag WVAL 1 write data valid flag
The device controller implements these registers: The command channel implements these registers:
name size comments name size comments
@ -697,9 +815,10 @@ The device controller implements these registers:
SRQ 1 controller DMA service request SRQ 1 controller DMA service request
EOC 1 end of cylinder pending EOC 1 end of cylinder pending
POLL 1 attention polling enabled POLL 1 attention polling enabled
RARC[0:3] 8 record address register cylinder, drives 0-3 RARC 8 record address register (cylinder)
RARH[0:3] 2 record address register head, drives 0-3 RARH 2 record address register (head)
RARS[0:3] 4 record address register sector, drives 0-3 RARS 4 record address register (sector)
CYL[0:3] 8 current cylinder, drives 0-3
STA[0:3] 16 drive status, drives 0-3 STA[0:3] 16 drive status, drives 0-3
CTIME 24 data transfer command delay time CTIME 24 data transfer command delay time
DTIME 24 data channel command delay time DTIME 24 data channel command delay time
@ -716,12 +835,12 @@ Error handling is as follows:
OS I/O error report error and stop OS I/O error report error and stop
2.6 12565A Disk Controller (DQC, DQD) with 2883 Drives 2.7 12565A Disk Controller (DQC, DQD) with Two 2883 Drives
The 12565A disk controller has two separate devices, a data channel and The 12565A disk controller has two separate devices, a data channel and
a device controller. The data channel includes a 128-word (one sector) a command channel. The data channel includes a 128-word (one sector)
buffer for reads and writes. The device controller includes the two buffer for reads and writes. The command channel includes the two
disk drives. Disk drives can be set ONLINE or OFFLINE. disk drives. Disk drives can be set DISABLED or ENABLED.
The 12565A supports the BOOT command. BOOT DQC copies the IBL for 2883 The 12565A supports the BOOT command. BOOT DQC copies the IBL for 2883
class disks into memory and starts it running. The switch register (S) class disks into memory and starts it running. The switch register (S)
@ -748,22 +867,24 @@ The data channel implements these registers:
XFER 1 transfer in progress flag XFER 1 transfer in progress flag
WVAL 1 write data valid flag WVAL 1 write data valid flag
The device controller implements these registers: The command channel implements these registers:
name size comments name size comments
OBUF 16 output buffer OBUF 16 output buffer
BUSY 2 busy (unit #, + 1, of active unit) BUSY 2 busy (unit # + 1 of active unit)
CNT 9 check record count CNT 9 check record count
CMD 1 controller enable CMD 1 controller enable
CTL 1 interrupt enable CTL 1 interrupt enable
FLG 1 controller ready FLG 1 controller ready
FBF 1 controller ready buffer FBF 1 controller ready buffer
SRQ 1 controller DMA service request SRQ 1 controller DMA service request
RARC[0:1] 8 record address register cylinder, drives 0-1 RARC 8 record address register (cylinder)
RARH[0:1] 5 record address register head, drives 0-1 RARH 5 record address register (head)
RARS[0:1] 5 record address register sector, drives 0-1 RARS 5 record address register (sector)
STA[0:1] 16 drive status, drives 0-3 CYL[0:1] 8 current cylinder, drives 0-1
HED[0:1] 5 current head, drives 0-1
STA[0:1] 16 drive status, drives 0-1
CTIME 24 data transfer command delay time CTIME 24 data transfer command delay time
DTIME 24 data channel command delay time DTIME 24 data channel command delay time
STIME 24 seek delay time, per cylinder STIME 24 seek delay time, per cylinder
@ -779,23 +900,45 @@ Error handling is as follows:
OS I/O error report error and stop OS I/O error report error and stop
2.7 12606B Fixed Head Disk Controller (DRC, DRD) with 2770/2771 Disk 2.8 12606B Fixed Head Disk Controller (DRC, DRD) with 2770/2771 Disk
12610B Drum Controller (DRC, DRD) with 2773/2774/2775 Drum 12610B Drum Controller (DRC, DRD) with 2773/2774/2775 Drum
The 12606B/12610B fixed head disk/drum controller has two separate devices, The 12606B/12610B fixed head disk/drum controller has two separate devices,
a data channel and a device controller. The device controller includes the a data channel and a command channel.
actual drive. Ten different models are supported:
SET DRC 180K 12606B, 180K words The command channel includes the actual drive. Ten different models are
SET DRC 360K 12606B, 360K words supported:
SET DRC 720K 12606B, 720K words
SET DRC 384K 12610B, 84K words command interface and size model
SET DRC 512K 12610B, 512K words
SET DRC 640K 12610B, 640K words SET DRC 180K 12606B, 180K words 2770A
SET DRC 768K 12610B, 768K words SET DRC 360K 12606B, 360K words 2771A
SET DRC 896K 12610B, 896K words SET DRC 720K 12606B, 720K words 2771A-001
SET DRC 1024K 12610B, 1024K words SET DRC 384K 12610B, 384K words 2773A
SET DRC 1536K 12610B, 1536K words SET DRC 512K 12610B, 512K words 2773A-001
SET DRC 640K 12610B, 640K words 2773A-002
SET DRC 768K 12610B, 768K words 2774A
SET DRC 896K 12610B, 896K words 2774A-001
SET DRC 1024K 12610B, 1024K words 2774A-002
SET DRC 1536K 12610B, 1536K words 2775A
The command channel supports write-protected tracks. Track protection
is enabled with this command:
SET DRC PROTECTED
In addition, the number of protected tracks is specified by the command:
SET DRC TRACKPROT=count
The track protect count must be a power of two from 1 to 128 on the 12606
interface and from 1 to 512, or 768, on the 12610 interface. If the drive
has fewer tracks than the track protect count, then all tracks on the drive
are eligible for protection.
Track protection is disabled with this command:
SET DRC UNPROTECTED
The 12606B/12610B support the BOOT command. The BOOT command loads the The 12606B/12610B support the BOOT command. The BOOT command loads the
first sector from the disk or drum into locations 0-77 and then jumps to 77. first sector from the disk or drum into locations 0-77 and then jumps to 77.
@ -815,12 +958,13 @@ The data channel implements these registers:
SRQ 1 channel DMA service request SRQ 1 channel DMA service request
BPTR 6 sector buffer pointer BPTR 6 sector buffer pointer
The device controller implements these registers: The command channel implements these registers:
name size comments name size comments
CW 16 command word CW 16 command word
STA 16 status STA 16 status
RUN 1 run flip-flop
CMD 1 controller enable CMD 1 controller enable
CTL 1 interrupt enable CTL 1 interrupt enable
FLG 1 controller ready FLG 1 controller ready
@ -838,7 +982,7 @@ Error handling is as follows:
12606B/12610B data files are buffered in memory; therefore, end of file 12606B/12610B data files are buffered in memory; therefore, end of file
and OS I/O errors cannot occur. and OS I/O errors cannot occur.
2.8 12559C Magnetic Tape Controller (MTC, MTD) with 3030 Drive 2.9 12559C Magnetic Tape Controller (MTC, MTD) with One 3030 Drive
Magnetic tape options include the ability to make the unit write enabled Magnetic tape options include the ability to make the unit write enabled
or write locked. or write locked.
@ -847,8 +991,8 @@ or write locked.
SET MTC WRITEENABLED set unit write enabled SET MTC WRITEENABLED set unit write enabled
The 12559C mag tape drive has two separate devices, a data channel and The 12559C mag tape drive has two separate devices, a data channel and
a device controller. The data channel includes a maximum record sized a command channel. The data channel includes a maximum record sized
buffer for reads and writes. The device controller includes the tape buffer for reads and writes. The command channel includes the tape
unit. unit.
The BOOT command is not supported. The 12559C was HP's earliest tape The BOOT command is not supported. The 12559C was HP's earliest tape
@ -865,7 +1009,7 @@ The data channel implements these registers:
BPTR 16 buffer pointer (reads and writes) BPTR 16 buffer pointer (reads and writes)
BMAX 16 buffer size (writes) BMAX 16 buffer size (writes)
The device controller implements these registers: The command channel implements these registers:
name size comments name size comments
@ -893,8 +1037,8 @@ Error handling is as follows:
OS I/O error parity error; if STOP_IOE, stop OS I/O error parity error; if STOP_IOE, stop
2.9 13181A Magnetic Tape Controller (MSC, MSD) with 7970B Drives 2.10 13181A Magnetic Tape Controller (MSC, MSD) with Four 7970B Drives
18183A Magnetic Tape Controller (MSC, MSD) with 7970E Drives 18183A Magnetic Tape Controller (MSC, MSD) with Four 7970E Drives
Magnetic tape options include the ability to make the unit write enabled Magnetic tape options include the ability to make the unit write enabled
or write locked, and the ability to select the 13181A (800 bpi) controller or write locked, and the ability to select the 13181A (800 bpi) controller
@ -905,29 +1049,38 @@ or the 13183A (1600 bpi) controller.
SET MSC 13181A set controller to 13181A SET MSC 13181A set controller to 13181A
SET MSC 13183A set controller to 13183A SET MSC 13183A set controller to 13183A
SET MSC REALTIME set controller to actual timing SET MSC REALTIME set controller to actual timing
SET MSC FASTIME set controller to optimized timing (default) SET MSC FASTTIME set controller to optimized timing (default)
SET MSCn REEL=length set unit tape reel size SET MSCn REEL=length set unit tape reel size
0 = unlimited (default) 0 = unlimited (default)
600 = 600 feet 600 = 600 feet
1200 = 1200 feet 1200 = 1200 feet
2400 = 2400 feet 2400 = 2400 feet
MSC may be configured to send debugging information to the previously
enabled debug output device using these commands:
SET MSC DEBUG provide debug printouts
SET MSC NODEBUG inhibit debug printouts
Diagnostic information includes commands supplied to and status received
from the interface, as well as command initiations and completions.
The 13181A/13183A mag tape drive has two separate devices, a data channel The 13181A/13183A mag tape drive has two separate devices, a data channel
and a device controller. The data channel includes a maximum record and a command channel. The data channel includes a maximum record
sized buffer for reads and writes. The device controller includes the sized buffer for reads and writes. The command channel includes the
tape units. tape units.
The 13181A/13183A supports the BOOT command. BOOT MSC loads the IBL for The 13181A/13183A supports the BOOT command. BOOT MSC loads the IBL for
7970B/E magnetic tape drives into memory and starts it running. BOOT -S 7970B/E magnetic tape drives into memory and starts it running. BOOT -S
MSC causes the loader to space forward the number of files specified in MSC causes the loader to position to the file number specified in the A
the A register before starting to load data. The switch register (S) is register before starting to load data. The switch register (S) is set
set automatically to the value expected by the IBL loader: automatically to the value expected by the IBL loader:
<15:12> = 1000 <15:12> = 1000
<11:6> = data channel device code <11:6> = data channel device code
<5:3> = unchanged <5:3> = unchanged
<2:0> = 00 <2:0> = 00
<0> = 1 if space forward before loading <0> = 1 if position tape before loading
The data channel implements these registers: The data channel implements these registers:
@ -942,7 +1095,7 @@ The data channel implements these registers:
BPTR 17 buffer pointer (reads and writes) BPTR 17 buffer pointer (reads and writes)
BMAX 17 buffer size (writes) BMAX 17 buffer size (writes)
The device controller implements these registers: The command channel implements these registers:
name size comments name size comments
@ -973,7 +1126,7 @@ Error handling is as follows:
OS I/O error parity error; if STOP_IOE, stop OS I/O error parity error; if STOP_IOE, stop
2.10 Symbolic Display and Input 2.11 Symbolic Display and Input
The HP2100 simulator implements symbolic display and input. Display is The HP2100 simulator implements symbolic display and input. Display is
controlled by command line switches: controlled by command line switches:

View file

@ -26,6 +26,13 @@
dp 12557A 2871 disk subsystem dp 12557A 2871 disk subsystem
13210A 7900 disk subsystem 13210A 7900 disk subsystem
07-Oct-04 JDB Fixed enable/disable from either device
Fixed ANY ERROR status for 12557A interface
Fixed unattached drive status for 12557A interface
Status cmd without prior STC DC now completes (12557A)
OTA/OTB CC on 13210A interface also does CLC CC
Fixed RAR model
Fixed seek check on 13210 if sector out of range
20-Aug-04 JDB Fixes from Dave Bryan 20-Aug-04 JDB Fixes from Dave Bryan
- Check status on unattached drive set busy and not ready - Check status on unattached drive set busy and not ready
- Check status tests wrong unit for write protect status - Check status tests wrong unit for write protect status
@ -73,6 +80,34 @@
dpc_poll indicates whether seek completion polling can occur. It is cleared dpc_poll indicates whether seek completion polling can occur. It is cleared
by reset and CLC CC and set by issuance of a seek or completion of check status. by reset and CLC CC and set by issuance of a seek or completion of check status.
The controller's "Record Address Register" (RAR) contains the CHS address of
the last Seek or Address Record command executed. The RAR is shared among
all drives on the controller. In addition, each drive has an internal
position register that contains the last cylinder position transferred to the
drive during Seek command execution (data operations always start with the
RAR head and sector position).
In a real drive, the address field of the sector under the head is read and
compared to the RAR. When they match, the target sector is under the head
and is ready for reading or writing. If a match doesn't occur, an Address
Error is indicated. In the simulator, the address field is obtained from the
drive's current position register during a read, i.e., the "on-disc" address
field is assumed to match the current position.
References:
- 7900A Disc Drive Operating and Service Manual (07900-90002, Feb-1975)
- 13210A Disc Drive Interface Kit Operating and Service Manual
(13210-90003, Nov-1974)
- 12557A Cartridge Disc Interface Kit Operating and Service Manual
(12557-90001, Sep-1970)
The following implemented behaviors have been inferred from secondary sources
(diagnostics, operating system drivers, etc.), due to absent or contradictory
authoritative information; future correction may be needed:
1. Status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR) on the 12557A.
2. Omitting STC DC before Status Check does not set DC flag but does poll.
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -80,7 +115,7 @@
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_WLK (1 << UNIT_V_WLK)
#define FNC u3 /* saved function */ #define FNC u3 /* saved function */
#define CYL u4 /* cylinder */ #define DRV u4 /* drive number (DC) */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
#define DP_N_NUMWD 7 #define DP_N_NUMWD 7
@ -109,9 +144,9 @@
#define FNC_AR 013 /* address */ #define FNC_AR 013 /* address */
#define FNC_SEEK1 020 /* fake - seek1 */ #define FNC_SEEK1 020 /* fake - seek1 */
#define FNC_SEEK2 021 /* fake - seek2 */ #define FNC_SEEK2 021 /* fake - seek2 */
#define FNC_SEEK3 022 /* fake - seek3 */
#define FNC_CHK1 023 /* fake - check1 */ #define FNC_CHK1 023 /* fake - check1 */
#define FNC_AR1 024 /* fake - arec1 */ #define FNC_AR1 024 /* fake - arec1 */
#define FNC_STA1 025 /* fake - sta1 */
#define CW_V_DRV 0 /* drive */ #define CW_V_DRV 0 /* drive */
#define CW_M_DRV 03 #define CW_M_DRV 03
#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) #define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV)
@ -152,10 +187,17 @@
#define STA_BSY 0000004 /* seeking */ #define STA_BSY 0000004 /* seeking */
#define STA_DTE 0000002 /* data error */ #define STA_DTE 0000002 /* data error */
#define STA_ERR 0000001 /* any error (d) */ #define STA_ERR 0000001 /* any error (d) */
#define STA_ALLERR (STA_ATN + STA_1ST + STA_OVR + STA_RWU + STA_ACU + \
STA_SKI + STA_SKE + STA_NRDY + STA_EOC + STA_AER + \ #define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
STA_FLG + STA_BSY + STA_DTE) STA_SKI | STA_SKE | STA_NRDY | \
#define STA_MBZ13 (STA_ATN + STA_RWU + STA_SKI) /* zero in 13210 */ STA_EOC | STA_AER | STA_DTE) /* 12557A error set */
#define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \
STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \
STA_FLG | STA_BSY | STA_DTE) /* 13210A error set */
#define STA_ANYERR (dp_ctype ? STA_ERSET3 : STA_ERSET2)
#define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY)
#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */
extern uint16 *M; extern uint16 *M;
extern uint32 PC, SR; extern uint32 PC, SR;
@ -177,9 +219,10 @@ int32 dpc_obuf = 0; /* cch buffers */
int32 dpd_xfer = 0; /* xfer in prog */ int32 dpd_xfer = 0; /* xfer in prog */
int32 dpd_wval = 0; /* write data valid */ int32 dpd_wval = 0; /* write data valid */
int32 dp_ptr = 0; /* buffer ptr */ int32 dp_ptr = 0; /* buffer ptr */
uint8 dpc_rarc[DP_NUMDRV] = { 0 }; /* cylinder */ uint8 dpc_rarc = 0; /* RAR cylinder */
uint8 dpc_rarh[DP_NUMDRV] = { 0 }; /* head */ uint8 dpc_rarh = 0; /* RAR head */
uint8 dpc_rars[DP_NUMDRV] = { 0 }; /* sector */ uint8 dpc_rars = 0; /* RAR sector */
uint8 dpc_ucyl[DP_NUMDRV] = { 0 }; /* unit cylinder */
uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */
uint16 dpxb[DP_NUMWD]; /* sector buffer */ uint16 dpxb[DP_NUMWD]; /* sector buffer */
@ -216,6 +259,8 @@ UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) };
REG dpd_reg[] = { REG dpd_reg[] = {
{ ORDATA (IBUF, dpd_ibuf, 16) }, { ORDATA (IBUF, dpd_ibuf, 16) },
{ ORDATA (OBUF, dpd_obuf, 16) }, { ORDATA (OBUF, dpd_obuf, 16) },
{ BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) },
{ DRDATA (BPTR, dp_ptr, DP_N_NUMWD) },
{ FLDATA (CMD, dpd_dib.cmd, 0) }, { FLDATA (CMD, dpd_dib.cmd, 0) },
{ FLDATA (CTL, dpd_dib.ctl, 0) }, { FLDATA (CTL, dpd_dib.ctl, 0) },
{ FLDATA (FLG, dpd_dib.flg, 0) }, { FLDATA (FLG, dpd_dib.flg, 0) },
@ -223,8 +268,6 @@ REG dpd_reg[] = {
{ FLDATA (SRQ, dpd_dib.srq, 0) }, { FLDATA (SRQ, dpd_dib.srq, 0) },
{ FLDATA (XFER, dpd_xfer, 0) }, { FLDATA (XFER, dpd_xfer, 0) },
{ FLDATA (WVAL, dpd_wval, 0) }, { FLDATA (WVAL, dpd_wval, 0) },
{ BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) },
{ DRDATA (BPTR, dp_ptr, DP_N_NUMWD) },
{ ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO }, { ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO },
{ NULL } }; { NULL } };
@ -238,7 +281,7 @@ DEVICE dpd_dev = {
1, 10, DP_N_NUMWD, 1, 8, 16, 1, 10, DP_N_NUMWD, 1, 8, 16,
NULL, NULL, &dpc_reset, NULL, NULL, &dpc_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&dpd_dib, 0 }; &dpd_dib, DEV_DISABLE };
/* DPC data structures /* DPC data structures
@ -269,17 +312,16 @@ REG dpc_reg[] = {
{ FLDATA (SRQ, dpc_dib.srq, 0) }, { FLDATA (SRQ, dpc_dib.srq, 0) },
{ FLDATA (EOC, dpc_eoc, 0) }, { FLDATA (EOC, dpc_eoc, 0) },
{ FLDATA (POLL, dpc_poll, 0) }, { FLDATA (POLL, dpc_poll, 0) },
{ BRDATA (RARC, dpc_rarc, 8, 8, DP_NUMDRV) }, { DRDATA (RARC, dpc_rarc, 8), PV_RZRO },
{ BRDATA (RARH, dpc_rarh, 8, 2, DP_NUMDRV) }, { DRDATA (RARH, dpc_rarh, 2), PV_RZRO },
{ BRDATA (RARS, dpc_rars, 8, 4, DP_NUMDRV) }, { DRDATA (RARS, dpc_rars, 5), PV_RZRO },
{ BRDATA (CYL, dpc_ucyl, 10, 8, DP_NUMDRV), PV_RZRO },
{ BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) },
{ DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT },
{ DRDATA (DTIME, dpc_dtime, 24), PV_LEFT }, { DRDATA (DTIME, dpc_dtime, 24), PV_LEFT },
{ DRDATA (STIME, dpc_stime, 24), PV_LEFT }, { DRDATA (STIME, dpc_stime, 24), PV_LEFT },
{ DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, dpc_xtime, 24), REG_NZ | PV_LEFT },
{ FLDATA (CTYPE, dp_ctype, 0), REG_HRO }, { FLDATA (CTYPE, dp_ctype, 0), REG_HRO },
{ URDATA (UCYL, dpc_unit[0].CYL, 10, 8, 0,
DP_NUMDRV, PV_LEFT | REG_HRO) },
{ URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0, { URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0,
DP_NUMDRV, REG_HRO) }, DP_NUMDRV, REG_HRO) },
{ URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0, { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0,
@ -367,15 +409,16 @@ case ioSFC: /* skip flag clear */
case ioSFS: /* skip flag set */ case ioSFS: /* skip flag set */
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
break; break;
case ioOTX: /* output */
dpc_obuf = dat;
break;
case ioLIX: /* load */ case ioLIX: /* load */
dat = 0; dat = 0;
case ioMIX: /* merge */ case ioMIX: /* merge */
for (i = 0; i < DP_NUMDRV; i++) for (i = 0; i < DP_NUMDRV; i++)
if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i); if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i);
break; break;
case ioOTX: /* output */
dpc_obuf = dat;
if (!dp_ctype) break;
IR = IR | I_CTL; /* 13210 OTx causes CLC */
case ioCTL: /* control clear/set */ case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC? */ if (IR & I_CTL) { /* CLC? */
clrCTL (devc); /* clr cmd, ctl */ clrCTL (devc); /* clr cmd, ctl */
@ -419,7 +462,7 @@ return dat;
void dp_god (int32 fnc, int32 drv, int32 time) void dp_god (int32 fnc, int32 drv, int32 time)
{ {
dpd_unit.CYL = drv; /* save unit */ dpd_unit.DRV = drv; /* save unit */
dpd_unit.FNC = fnc; /* save function */ dpd_unit.FNC = fnc; /* save function */
sim_activate (&dpd_unit, time); sim_activate (&dpd_unit, time);
return; return;
@ -450,7 +493,7 @@ return;
This routine handles the data channel transfers. It also handles This routine handles the data channel transfers. It also handles
data transfers that are blocked by seek in progress. data transfers that are blocked by seek in progress.
uptr->CYL = target drive uptr->DRV = target drive
uptr->FNC = target function uptr->FNC = target function
Seek substates Seek substates
@ -468,62 +511,55 @@ t_stat dpd_svc (UNIT *uptr)
{ {
int32 i, drv, devc, devd, st; int32 i, drv, devc, devd, st;
drv = uptr->CYL; /* get drive no */ drv = uptr->DRV; /* get drive no */
devc = dpc_dib.devno; /* get cch devno */ devc = dpc_dib.devno; /* get cch devno */
devd = dpd_dib.devno; /* get dch devno */ devd = dpd_dib.devno; /* get dch devno */
switch (uptr->FNC) { /* case function */ switch (uptr->FNC) { /* case function */
case FNC_AR: /* arec, need cyl */
case FNC_SEEK: /* seek, need cyl */ case FNC_SEEK: /* seek, need cyl */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */ dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */
dpd_wval = 0; /* clr data valid */ dpd_wval = 0; /* clr data valid */
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */ clrCMD (devd); /* clr dch cmd */
uptr->FNC = FNC_SEEK1; } /* advance state */ if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1;
else uptr->FNC = FNC_SEEK1; } /* advance state */
sim_activate (uptr, dpc_xtime); /* no, wait more */ sim_activate (uptr, dpc_xtime); /* no, wait more */
break; break;
case FNC_AR1: /* arec, need hd/sec */
case FNC_SEEK1: /* seek, need hd/sec */ case FNC_SEEK1: /* seek, need hd/sec */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */ dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */
dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */ dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */
dpd_wval = 0; /* clr data valid */ dpd_wval = 0; /* clr data valid */
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */ clrCMD (devd); /* clr dch cmd */
if (uptr->FNC == FNC_AR1) {
setFSR (devc); /* set cch flg */
clrCMD (devc); /* clr cch cmd */
dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */
break; } /* done if Address Record */
if (sim_is_active (&dpc_unit[drv])) { /* if busy, */ if (sim_is_active (&dpc_unit[drv])) { /* if busy, */
dpc_sta[drv] = dpc_sta[drv] | STA_SKE; dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */
break; } /* error, ignore */ break; } /* allow prev seek to cmpl */
st = abs (dpc_rarc[drv] - dpc_unit[drv].CYL) * dpc_stime; if ((dpc_rarc >= DP_NUMCY) || /* invalid cyl? */
(dp_ctype && (dpc_rars >= DP_NUMSC3))) { /* invalid sector? (13210A) */
dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */
sim_activate (&dpc_unit[drv], 1); /* schedule drive no-wait */
dpc_unit[drv].FNC = FNC_SEEK3; /* do immed compl w/poll */
break; }
st = abs (dpc_rarc - dpc_ucyl[drv]) * dpc_stime;
if (st == 0) st = dpc_stime; /* min time */ if (st == 0) st = dpc_stime; /* min time */
dpc_ucyl[drv] = dpc_rarc; /* transfer RAR */
sim_activate (&dpc_unit[drv], st); /* schedule drive */ sim_activate (&dpc_unit[drv], st); /* schedule drive */
dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) & dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) &
~(STA_SKE | STA_SKI | STA_HUNT); ~(STA_SKE | STA_SKI | STA_HUNT);
dpc_unit[drv].CYL = dpc_rarc[drv]; /* on cylinder */
dpc_unit[drv].FNC = FNC_SEEK2; } /* set operation */ dpc_unit[drv].FNC = FNC_SEEK2; } /* set operation */
else sim_activate (uptr, dpc_xtime); /* no, wait more */ else sim_activate (uptr, dpc_xtime); /* no, wait more */
break; break;
case FNC_AR: /* arec, need cyl */
if (CMD (devd)) { /* dch active? */
dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */
dpd_wval = 0; /* clr data valid */
setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
uptr->FNC = FNC_AR1; } /* advance state */
sim_activate (uptr, dpc_xtime); /* no, wait more */
break;
case FNC_AR1: /* arec, need hd/sec */
if (CMD (devd)) { /* dch active? */
dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */
dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */
dpd_wval = 0; /* clr data valid */
setFSR (devc); /* set cch flg */
clrCMD (devc); /* clr cch cmd */
setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
dpc_sta[drv] = dpc_sta[drv] | STA_ATN; } /* set drv attn */
else sim_activate (uptr, dpc_xtime); /* no, wait more */
break;
case FNC_STA: /* read status */ case FNC_STA: /* read status */
if (CMD (devd) || dp_ctype) { /* dch act or 13210? */ if (CMD (devd) || dp_ctype) { /* dch act or 13210? */
if (dpc_unit[drv].flags & UNIT_ATT) { /* attached? */ if (dpc_unit[drv].flags & UNIT_ATT) { /* attached? */
@ -531,20 +567,16 @@ case FNC_STA: /* read status */
if (dp_ctype) dpd_ibuf = /* 13210? */ if (dp_ctype) dpd_ibuf = /* 13210? */
(dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) | (dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) |
(dpc_unit[drv].flags & UNIT_WPRT? STA_PROT: 0); } (dpc_unit[drv].flags & UNIT_WPRT? STA_PROT: 0); }
else dpd_ibuf = STA_NRDY|STA_BSY; /* not ready */ else dpd_ibuf = STA_UNLOADED; /* not ready */
if (dpd_ibuf & STA_ALLERR) /* errors? set flg */ if (dpd_ibuf & STA_ANYERR) /* errors? set flg */
dpd_ibuf = dpd_ibuf | STA_ERR; dpd_ibuf = dpd_ibuf | STA_ERR;
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */ clrCMD (devd); /* clr dch cmd */
clrCMD (devc); /* clr cch cmd */ clrCMD (devc); } /* clr cch cmd */
dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */
~(STA_ATN | STA_1ST | STA_OVR | ~(STA_ATN | STA_1ST | STA_OVR |
STA_RWU | STA_ACU | STA_EOC | STA_RWU | STA_ACU | STA_EOC |
STA_AER | STA_FLG | STA_DTE); STA_AER | STA_FLG | STA_DTE);
uptr->FNC = FNC_STA1; } /* advance state */
sim_activate (uptr, dpc_xtime); /* no, wait more */
break;
case FNC_STA1: /* read sta, poll */
dpc_poll = 1; /* enable polling */ dpc_poll = 1; /* enable polling */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
if (dpc_sta[i] & STA_ATN) { /* any ATN set? */ if (dpc_sta[i] & STA_ATN) { /* any ATN set? */
@ -556,8 +588,6 @@ case FNC_CHK: /* check, need cnt */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */
dpd_wval = 0; /* clr data valid */ dpd_wval = 0; /* clr data valid */
/* setFSR (devd); /* set dch flg */
/* clrCMD (devd); /* clr dch cmd */
dp_goc (FNC_CHK1, drv, dpc_xtime); } /* sched drv */ dp_goc (FNC_CHK1, drv, dpc_xtime); } /* sched drv */
else sim_activate (uptr, dpc_xtime); /* wait more */ else sim_activate (uptr, dpc_xtime); /* wait more */
break; break;
@ -603,11 +633,10 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
return SCPE_OK; } return SCPE_OK; }
switch (uptr->FNC) { /* case function */ switch (uptr->FNC) { /* case function */
case FNC_SEEK2: /* seek done */ case FNC_SEEK2: /* positioning done */
dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */
if (uptr->CYL >= DP_NUMCY) { /* invalid cyl? */
dpc_sta[drv] = dpc_sta[drv] | STA_SKE; case FNC_SEEK3: /* seek complete */
uptr->CYL = DP_NUMCY - 1; }
if (dpc_poll) { /* polling enabled? */ if (dpc_poll) { /* polling enabled? */
setFSR (devc); /* set cch flg */ setFSR (devc); /* set cch flg */
clrCMD (devc); } /* clear cmd */ clrCMD (devc); } /* clear cmd */
@ -620,20 +649,19 @@ case FNC_RD: /* read */
case FNC_CHK1: /* check */ case FNC_CHK1: /* check */
if (dp_ptr == 0) { /* new sector? */ if (dp_ptr == 0) { /* new sector? */
if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break; if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break;
if (uptr->CYL != dpc_rarc[drv]) /* wrong cyl? */ if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */ dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */
if (dpc_rars[drv] >= DP_NUMSC) { /* bad sector? */ if (dpc_rars >= DP_NUMSC) { /* bad sector? */
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */ dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */
break; } break; }
if (dpc_eoc) { /* end of cyl? */ if (dpc_eoc) { /* end of cyl? */
dpc_sta[drv] = dpc_sta[drv] | STA_EOC; dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
break; } break; }
da = GETDA (dpc_rarc[drv], dpc_rarh[drv], dpc_rars[drv]); da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */
dpc_rars[drv] = dpc_rars[drv] + 1; /* incr address */ dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */
if (dpc_rars[drv] >= DP_NUMSC) { /* end of surf? */ if (dpc_rars == 0) { /* wrap? */
dpc_rars[drv] = 0; /* wrap to */ dpc_rarh = dpc_rarh ^ 1; /* incr head */
dpc_rarh[drv] = dpc_rarh[drv] ^ 1; /* next head */ dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
dpc_eoc = ((dpc_rarh[drv] & 1) == 0); }/* calc eoc */
if (err = fseek (uptr->fileref, da * sizeof (int16), if (err = fseek (uptr->fileref, da * sizeof (int16),
SEEK_SET)) break; SEEK_SET)) break;
fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);
@ -657,9 +685,9 @@ case FNC_WD: /* write */
if (uptr->flags & UNIT_WPRT) { /* wr prot? */ if (uptr->flags & UNIT_WPRT) { /* wr prot? */
dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */ dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */
break; } /* done */ break; } /* done */
if ((uptr->CYL != dpc_rarc[drv]) || /* wrong cyl or */ if ((dpc_rarc != dpc_ucyl[drv]) || /* RAR cyl miscompare? */
(dpc_rars[drv] >= DP_NUMSC)) { /* bad sector? */ (dpc_rars >= DP_NUMSC)) { /* bad sector? */
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */ dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* address error */
break; } break; }
if (dpc_eoc) { /* end of cyl? */ if (dpc_eoc) { /* end of cyl? */
dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */
@ -667,12 +695,11 @@ case FNC_WD: /* write */
dpxb[dp_ptr++] = dpd_wval? dpd_obuf: 0; /* store word/fill */ dpxb[dp_ptr++] = dpd_wval? dpd_obuf: 0; /* store word/fill */
dpd_wval = 0; /* clr data valid */ dpd_wval = 0; /* clr data valid */
if (dp_ptr >= DP_NUMWD) { /* buffer full? */ if (dp_ptr >= DP_NUMWD) { /* buffer full? */
da = GETDA (dpc_rarc[drv], dpc_rarh[drv], dpc_rars[drv]); da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */
dpc_rars[drv] = dpc_rars[drv] + 1; /* incr address */ dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */
if (dpc_rars[drv] >= DP_NUMSC) { /* end of surf? */ if (dpc_rars == 0) { /* wrap? */
dpc_rars[drv] = 0; /* wrap to */ dpc_rarh = dpc_rarh ^ 1; /* incr head */
dpc_rarh[drv] = dpc_rarh[drv] ^ 1; /* next head */ dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
dpc_eoc = ((dpc_rarh[drv] & 1) == 0); }/* calc eoc */
if (err = fseek (uptr->fileref, da * sizeof (int16), if (err = fseek (uptr->fileref, da * sizeof (int16),
SEEK_SET)) break; SEEK_SET)) break;
fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);
@ -703,29 +730,30 @@ return SCPE_OK;
t_stat dpc_reset (DEVICE *dptr) t_stat dpc_reset (DEVICE *dptr)
{ {
int32 i; int32 drv;
hp_enbdis_pair (&dpc_dev, &dpd_dev); /* make pair cons */ hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &dpd_dev)? &dpc_dev: &dpd_dev);
dpd_ibuf = dpd_obuf = 0; /* clear buffers */ dpd_ibuf = dpd_obuf = 0; /* clear buffers */
dpc_busy = dpc_obuf = 0; dpc_busy = dpc_obuf = 0;
dpc_eoc = 0; dpc_eoc = 0;
dpc_poll = 0; dpc_poll = 0;
dpd_xfer = dpd_wval = 0; dpd_xfer = dpd_wval = 0;
dp_ptr = 0; dp_ptr = 0;
dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */
dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */ dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */
dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */ dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */
dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */ dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */
dpc_dib.flg = dpd_dib.flg = 1; /* set flg */ dpc_dib.flg = dpd_dib.flg = 1; /* set flg */
dpc_dib.srq = dpd_dib.flg = 1; /* srq follows flg */ dpc_dib.srq = dpd_dib.flg = 1; /* srq follows flg */
sim_cancel (&dpd_unit); /* cancel dch */ sim_cancel (&dpd_unit); /* cancel dch */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ for (drv = 0; drv < DP_NUMDRV; drv++) { /* loop thru drives */
sim_cancel (&dpc_unit[i]); /* cancel activity */ sim_cancel (&dpc_unit[drv]); /* cancel activity */
dpc_unit[i].FNC = 0; /* clear function */ dpc_unit[drv].FNC = 0; /* clear function */
dpc_unit[i].CYL = 0; dpc_ucyl[drv] = 0; /* clear drive pos */
dpc_rarc[i] = dpc_rarh[i] = dpc_rars[i] = 0; if (dpc_unit[drv].flags & UNIT_ATT)
if (dpc_unit[i].flags & UNIT_ATT) dpc_sta[drv] = dpc_sta[drv] & STA_1ST; /* first seek status */
dpc_sta[i] = dpc_sta[i] & STA_1ST; else dpc_sta[drv] = 0; } /* clear status */
else dpc_sta[i] = 0; }
return SCPE_OK; return SCPE_OK;
} }
@ -847,4 +875,3 @@ SR = (SR & IBL_OPT) | IBL_DP | (dev << IBL_V_DEV); /* set SR */
if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */ if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */
return SCPE_OK; return SCPE_OK;
} }

View file

@ -25,6 +25,10 @@
dq 12565A 2883 disk system dq 12565A 2883 disk system
07-Oct-04 JDB Fixed enable/disable from either device
Shortened xtime from 5 to 3 (drive avg 156KW/second)
Fixed not ready/any error status
Fixed RAR model
21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan) 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan)
26-Apr-04 RMS Fixed SFS x,C and SFC x,C 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
Fixed SR setting in IBL Fixed SR setting in IBL
@ -39,6 +43,29 @@
- 12565 does not set error on positioner busy - 12565 does not set error on positioner busy
- 12565 does not set positioner busy if already on cylinder - 12565 does not set positioner busy if already on cylinder
- 12565 does not need eoc logic, it will hit an invalid head number - 12565 does not need eoc logic, it will hit an invalid head number
The controller's "Record Address Register" (RAR) contains the CHS address of
the last Position or Load Address command executed. The RAR is shared among
all drives on the controller. In addition, each drive has an internal
position register that contains the last cylinder and head position
transferred to the drive during Position command execution (sector operations
always start with the RAR sector position).
In a real drive, the address field of the sector under the head is read and
compared to the RAR. When they match, the target sector is under the head
and is ready for reading or writing. If a match doesn't occur, an Address
Error is indicated. In the simulator, the address field is obtained from the
drive's current position register during a read, i.e., the "on-disc" address
field is assumed to match the current position.
Reference:
- 12565A Disc Interface Kit Operating and Service Manual (12565-90003, Aug-1973)
The following implemented behaviors have been inferred from secondary sources
(diagnostics, operating system drivers, etc.), due to absent or contradictory
authoritative information; future correction may be needed:
1. Read Address command starts at the sector number in the RAR.
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -46,7 +73,7 @@
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_WLK (1 << UNIT_V_WLK)
#define FNC u3 /* saved function */ #define FNC u3 /* saved function */
#define CYL u4 /* cylinder */ #define DRV u4 /* drive number (DC) */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
#define DQ_N_NUMWD 7 #define DQ_N_NUMWD 7
@ -107,7 +134,7 @@
#define STA_BSY 0000004 /* seeking */ #define STA_BSY 0000004 /* seeking */
#define STA_DTE 0000002 /* data error */ #define STA_DTE 0000002 /* data error */
#define STA_ERR 0000001 /* any error */ #define STA_ERR 0000001 /* any error */
#define STA_ALLERR (STA_NRDY + STA_EOC + STA_AER + STA_FLG + STA_DTE) #define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE)
extern uint16 *M; extern uint16 *M;
extern uint32 PC, SR; extern uint32 PC, SR;
@ -119,17 +146,19 @@ int32 dqc_busy = 0; /* cch xfer */
int32 dqc_cnt = 0; /* check count */ int32 dqc_cnt = 0; /* check count */
int32 dqc_stime = 100; /* seek time */ int32 dqc_stime = 100; /* seek time */
int32 dqc_ctime = 100; /* command time */ int32 dqc_ctime = 100; /* command time */
int32 dqc_xtime = 5; /* xfer time */ int32 dqc_xtime = 3; /* xfer time */
int32 dqc_dtime = 2; /* dch time */ int32 dqc_dtime = 2; /* dch time */
int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */
int32 dqc_obuf = 0; /* cch buffers */ int32 dqc_obuf = 0; /* cch buffers */
int32 dqd_xfer = 0; /* xfer in prog */ int32 dqd_xfer = 0; /* xfer in prog */
int32 dqd_wval = 0; /* write data valid */ int32 dqd_wval = 0; /* write data valid */
int32 dq_ptr = 0; /* buffer ptr */ int32 dq_ptr = 0; /* buffer ptr */
uint8 dqc_rarc[DQ_NUMDRV] = { 0 }; /* cylinder */ uint8 dqc_rarc = 0; /* RAR cylinder */
uint8 dqc_rarh[DQ_NUMDRV] = { 0 }; /* head */ uint8 dqc_rarh = 0; /* RAR head */
uint8 dqc_rars[DQ_NUMDRV] = { 0 }; /* sector */ uint8 dqc_rars = 0; /* RAR sector */
uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* status regs */ uint8 dqc_ucyl[DQ_NUMDRV] = { 0 }; /* unit cylinder */
uint8 dqc_uhed[DQ_NUMDRV] = { 0 }; /* unit head */
uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */
uint16 dqxb[DQ_NUMWD]; /* sector buffer */ uint16 dqxb[DQ_NUMWD]; /* sector buffer */
DEVICE dqd_dev, dqc_dev; DEVICE dqd_dev, dqc_dev;
@ -161,6 +190,8 @@ UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) };
REG dqd_reg[] = { REG dqd_reg[] = {
{ ORDATA (IBUF, dqd_ibuf, 16) }, { ORDATA (IBUF, dqd_ibuf, 16) },
{ ORDATA (OBUF, dqd_obuf, 16) }, { ORDATA (OBUF, dqd_obuf, 16) },
{ BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) },
{ DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) },
{ FLDATA (CMD, dqd_dib.cmd, 0) }, { FLDATA (CMD, dqd_dib.cmd, 0) },
{ FLDATA (CTL, dqd_dib.ctl, 0) }, { FLDATA (CTL, dqd_dib.ctl, 0) },
{ FLDATA (FLG, dqd_dib.flg, 0) }, { FLDATA (FLG, dqd_dib.flg, 0) },
@ -168,8 +199,6 @@ REG dqd_reg[] = {
{ FLDATA (SRQ, dqd_dib.srq, 0) }, { FLDATA (SRQ, dqd_dib.srq, 0) },
{ FLDATA (XFER, dqd_xfer, 0) }, { FLDATA (XFER, dqd_xfer, 0) },
{ FLDATA (WVAL, dqd_wval, 0) }, { FLDATA (WVAL, dqd_wval, 0) },
{ BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) },
{ DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) },
{ ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO }, { ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO },
{ NULL } }; { NULL } };
@ -183,7 +212,7 @@ DEVICE dqd_dev = {
1, 10, DQ_N_NUMWD, 1, 8, 16, 1, 10, DQ_N_NUMWD, 1, 8, 16,
NULL, NULL, &dqc_reset, NULL, NULL, &dqc_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&dqd_dib, 0 }; &dqd_dib, DEV_DISABLE };
/* DQC data structures /* DQC data structures
@ -208,16 +237,16 @@ REG dqc_reg[] = {
{ FLDATA (FLG, dqc_dib.flg, 0) }, { FLDATA (FLG, dqc_dib.flg, 0) },
{ FLDATA (FBF, dqc_dib.fbf, 0) }, { FLDATA (FBF, dqc_dib.fbf, 0) },
{ FLDATA (SRQ, dqc_dib.srq, 0) }, { FLDATA (SRQ, dqc_dib.srq, 0) },
{ BRDATA (RARC, dqc_rarc, 8, 8, DQ_NUMDRV) }, { DRDATA (RARC, dqc_rarc, 8), PV_RZRO },
{ BRDATA (RARH, dqc_rarh, 8, 5, DQ_NUMDRV) }, { DRDATA (RARH, dqc_rarh, 5), PV_RZRO },
{ BRDATA (RARS, dqc_rars, 8, 5, DQ_NUMDRV) }, { DRDATA (RARS, dqc_rars, 5), PV_RZRO },
{ BRDATA (CYL, dqc_ucyl, 10, 8, DQ_NUMDRV), PV_RZRO },
{ BRDATA (HED, dqc_uhed, 10, 5, DQ_NUMDRV), PV_RZRO },
{ BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) }, { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) },
{ DRDATA (CTIME, dqc_ctime, 24), PV_LEFT }, { DRDATA (CTIME, dqc_ctime, 24), PV_LEFT },
{ DRDATA (DTIME, dqc_dtime, 24), PV_LEFT }, { DRDATA (DTIME, dqc_dtime, 24), PV_LEFT },
{ DRDATA (STIME, dqc_stime, 24), PV_LEFT }, { DRDATA (STIME, dqc_stime, 24), PV_LEFT },
{ DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT },
{ URDATA (UCYL, dqc_unit[0].CYL, 10, 8, 0,
DQ_NUMDRV, PV_LEFT | REG_HRO) },
{ URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0,
DQ_NUMDRV, REG_HRO) }, DQ_NUMDRV, REG_HRO) },
{ ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO }, { ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO },
@ -273,7 +302,7 @@ case ioCTL: /* control clear/set */
setCTL (devd); /* set ctl, cmd */ setCTL (devd); /* set ctl, cmd */
setCMD (devd); setCMD (devd);
if (dqc_busy && !dqd_xfer) /* overrun? */ if (dqc_busy && !dqd_xfer) /* overrun? */
dqc_sta[dqc_busy - 1] |= STA_DTE | STA_ERR; } dqc_sta[dqc_busy - 1] |= STA_DTE; }
break; break;
default: default:
break; } break; }
@ -342,7 +371,7 @@ return dat;
void dq_god (int32 fnc, int32 drv, int32 time) void dq_god (int32 fnc, int32 drv, int32 time)
{ {
dqd_unit.CYL = drv; /* save unit */ dqd_unit.DRV = drv; /* save unit */
dqd_unit.FNC = fnc; /* save function */ dqd_unit.FNC = fnc; /* save function */
sim_activate (&dqd_unit, time); sim_activate (&dqd_unit, time);
return; return;
@ -371,7 +400,7 @@ return;
This routine handles the data channel transfers. It also handles This routine handles the data channel transfers. It also handles
data transfers that are blocked by seek in progress. data transfers that are blocked by seek in progress.
uptr->CYL = target drive uptr->DRV = target drive
uptr->FNC = target function uptr->FNC = target function
Seek substates Seek substates
@ -391,80 +420,69 @@ t_stat dqd_svc (UNIT *uptr)
{ {
int32 drv, devc, devd, st; int32 drv, devc, devd, st;
drv = uptr->CYL; /* get drive no */ drv = uptr->DRV; /* get drive no */
devc = dqc_dib.devno; /* get cch devno */ devc = dqc_dib.devno; /* get cch devno */
devd = dqd_dib.devno; /* get dch devno */ devd = dqd_dib.devno; /* get dch devno */
switch (uptr->FNC) { /* case function */ switch (uptr->FNC) { /* case function */
case FNC_LA: /* arec, need cyl */
case FNC_SEEK: /* seek, need cyl */ case FNC_SEEK: /* seek, need cyl */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */ dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */
dqd_wval = 0; /* clr data valid */ dqd_wval = 0; /* clr data valid */
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */ clrCMD (devd); /* clr dch cmd */
uptr->FNC = FNC_SEEK1; } /* advance state */ if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1;
else uptr->FNC = FNC_SEEK1; } /* advance state */
sim_activate (uptr, dqc_xtime); /* no, wait more */ sim_activate (uptr, dqc_xtime); /* no, wait more */
break; break;
case FNC_LA1: /* arec, need hd/sec */
case FNC_SEEK1: /* seek, need hd/sec */ case FNC_SEEK1: /* seek, need hd/sec */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */ dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */
dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */ dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */
dqd_wval = 0; /* clr data valid */ dqd_wval = 0; /* clr data valid */
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */ clrCMD (devd); /* clr dch cmd */
if (sim_is_active (&dqc_unit[drv])) break; /* if busy */ if (uptr->FNC == FNC_LA1) {
st = abs (dqc_rarc[drv] - dqc_unit[drv].CYL) * dqc_stime; setFSR (devc); /* set cch flg */
clrCMD (devc); /* clr cch cmd */
break; } /* done if Load Address */
if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */
st = abs (dqc_rarc - dqc_ucyl[drv]) * dqc_stime;
if (st == 0) st = dqc_xtime; /* if on cyl, min time */ if (st == 0) st = dqc_xtime; /* if on cyl, min time */
else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */
dqc_ucyl[drv] = dqc_rarc; /* transfer RAR */
dqc_uhed[drv] = dqc_rarh;
sim_activate (&dqc_unit[drv], st); /* schedule op */ sim_activate (&dqc_unit[drv], st); /* schedule op */
dqc_unit[drv].CYL = dqc_rarc[drv]; /* on cylinder */
dqc_unit[drv].FNC = FNC_SEEK2; } /* advance state */ dqc_unit[drv].FNC = FNC_SEEK2; } /* advance state */
else sim_activate (uptr, dqc_xtime); /* no, wait more */ else sim_activate (uptr, dqc_xtime); /* no, wait more */
break; break;
case FNC_RCL: /* recalibrate */ case FNC_RCL: /* recalibrate */
dqc_rarc[drv] = dqc_rarh[drv] = dqc_rars[drv] = 0; /* clear RAR */ dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */
if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */ if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */
st = dqc_unit[drv].CYL * dqc_stime; /* calc diff */ st = dqc_ucyl[drv] * dqc_stime; /* calc diff */
if (st == 0) st = dqc_xtime; /* if on cyl, min time */ if (st == 0) st = dqc_xtime; /* if on cyl, min time */
else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */
sim_activate (&dqc_unit[drv], st); /* schedule drive */ sim_activate (&dqc_unit[drv], st); /* schedule drive */
dqc_unit[drv].CYL = 0; /* on cylinder */ dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */
dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */ dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */
break; break;
case FNC_LA: /* arec, need cyl */
if (CMD (devd)) { /* dch active? */
dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */
dqd_wval = 0; /* clr data valid */
setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */
uptr->FNC = FNC_LA1; } /* advance state */
sim_activate (uptr, dqc_xtime); /* no, wait more */
break;
case FNC_LA1: /* arec, need hd/sec */
if (CMD (devd)) { /* dch active? */
dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */
dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */
dqd_wval = 0; /* clr data valid */
setFSR (devc); /* set cch flg */
clrCMD (devc); /* clr cch cmd */
setFSR (devd); /* set dch flg */
clrCMD (devd); } /* clr dch cmd */
else sim_activate (uptr, dqc_xtime); /* no, wait more */
break;
case FNC_STA: /* read status */ case FNC_STA: /* read status */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
if (dqc_unit[drv].flags & UNIT_ATT) /* attached? */ if (dqc_unit[drv].flags & UNIT_ATT) /* attached? */
dqd_ibuf = dqc_sta[drv] & ~STA_DID; dqd_ibuf = dqc_sta[drv] & ~STA_DID;
else dqd_ibuf = STA_NRDY|STA_BSY; else dqd_ibuf = STA_NRDY;
if (dqd_ibuf & STA_ANYERR) /* errors? set flg */
dqd_ibuf = dqd_ibuf | STA_ERR;
if (drv) dqd_ibuf = dqd_ibuf | STA_DID; if (drv) dqd_ibuf = dqd_ibuf | STA_DID;
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
clrCMD (devd); /* clr dch cmd */ clrCMD (devd); /* clr dch cmd */
clrCMD (devc); /* clr cch cmd */ clrCMD (devc); /* clr cch cmd */
dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */ dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */
~(STA_DTE | STA_FLG | STA_AER | STA_EOC | STA_ERR);
} }
else sim_activate (uptr, dqc_xtime); /* wait more */ else sim_activate (uptr, dqc_xtime); /* wait more */
break; break;
@ -473,8 +491,6 @@ case FNC_CHK: /* check, need cnt */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */
dqd_wval = 0; /* clr data valid */ dqd_wval = 0; /* clr data valid */
/* setFSR (devd); /* set dch flg */
/* clrCMD (devd); /* clr dch cmd */
dq_goc (FNC_CHK1, drv, dqc_ctime); } /* sched drv */ dq_goc (FNC_CHK1, drv, dqc_ctime); } /* sched drv */
else sim_activate (uptr, dqc_xtime); /* wait more */ else sim_activate (uptr, dqc_xtime); /* wait more */
break; break;
@ -522,9 +538,9 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
switch (uptr->FNC) { /* case function */ switch (uptr->FNC) { /* case function */
case FNC_SEEK2: /* seek done */ case FNC_SEEK2: /* seek done */
if (uptr->CYL >= DQ_NUMCY) { /* out of range? */ if (dqc_ucyl[drv] >= DQ_NUMCY) { /* out of range? */
dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR; dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR; /* seek check */
dqc_unit[drv].CYL = 0; } dqc_ucyl[drv] = 0; } /* seek to cyl 0 */
else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */ else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */
case FNC_SEEK3: case FNC_SEEK3:
if (dqc_busy || FLG (devc)) { /* ctrl busy? */ if (dqc_busy || FLG (devc)) { /* ctrl busy? */
@ -537,13 +553,11 @@ case FNC_SEEK3:
case FNC_RA: /* read addr */ case FNC_RA: /* read addr */
if (!CMD (devd)) break; /* dch clr? done */ if (!CMD (devd)) break; /* dch clr? done */
if (dq_ptr == 0) dqd_ibuf = uptr->CYL; /* 1st word? */ if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */
else if (dq_ptr == 1) { /* second word? */ else if (dq_ptr == 1) { /* second word? */
dqd_ibuf = (dqc_rarh[drv] << DA_V_HD) | dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */
(dqc_rars[drv] << DA_V_SC); (dqc_rars << DA_V_SC); /* and RAR sector */
dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */ dqc_rars = (dqc_rars + 1) % DQ_NUMSC; } /* incr sector */
if (dqc_rars[drv] >= DQ_NUMSC) /* end of surf? */
dqc_rars[drv] = 0; }
else break; else break;
dq_ptr = dq_ptr + 1; dq_ptr = dq_ptr + 1;
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
@ -556,18 +570,18 @@ case FNC_RD: /* read */
case FNC_CHK1: /* check */ case FNC_CHK1: /* check */
if (dq_ptr == 0) { /* new sector? */ if (dq_ptr == 0) { /* new sector? */
if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break; if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break;
if ((uptr->CYL != dqc_rarc[drv]) || /* wrong cyl or */ if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */
(dqc_rars[drv] >= DQ_NUMSC)) { /* bad sector? */ (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */
dqc_sta[drv] = dqc_sta[drv] | STA_AER | STA_ERR; (dqc_rars >= DQ_NUMSC)) { /* bad sector? */
dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */
break; } break; }
if (dqc_rarh[drv] >= DQ_NUMSF) { /* bad head? */ if (dqc_rarh >= DQ_NUMSF) { /* bad head? */
dqc_sta[drv] = dqc_sta[drv] | STA_EOC | STA_ERR; dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */
break; } break; }
da = GETDA (dqc_rarc[drv], dqc_rarh[drv], dqc_rars[drv]); da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */
dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */ dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */
if (dqc_rars[drv] >= DQ_NUMSC) { /* end of surf? */ if (dqc_rars == 0) /* wrap? incr head */
dqc_rars[drv] = 0; /* wrap to */ dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1;
dqc_rarh[drv] = dqc_rarh[drv] + 1; } /* next head */
if (err = fseek (uptr->fileref, da * sizeof (int16), if (err = fseek (uptr->fileref, da * sizeof (int16),
SEEK_SET)) break; SEEK_SET)) break;
fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref);
@ -588,24 +602,24 @@ case FNC_WA: /* write address */
case FNC_WD: /* write */ case FNC_WD: /* write */
if (dq_ptr == 0) { /* sector start? */ if (dq_ptr == 0) { /* sector start? */
if (!CMD (devd) && !dqd_wval) break; /* xfer done? */ if (!CMD (devd) && !dqd_wval) break; /* xfer done? */
if(uptr->flags & UNIT_WPRT) { /* write protect? */ if (uptr->flags & UNIT_WPRT) { /* write protect? */
dqc_sta[drv] = dqc_sta[drv] | STA_FLG | STA_ERR; dqc_sta[drv] = dqc_sta[drv] | STA_FLG;
break; } /* done */ break; } /* done */
if ((uptr->CYL != dqc_rarc[drv]) || /* wrong cyl or */ if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */
(dqc_rars[drv] >= DQ_NUMSC)) { /* bad sector? */ (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */
dqc_sta[drv] = dqc_sta[drv] | STA_AER | STA_ERR; (dqc_rars >= DQ_NUMSC)) { /* bad sector? */
dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */
break; } break; }
if (dqc_rarh[drv] >= DQ_NUMSF) { /* bad head? */ if (dqc_rarh >= DQ_NUMSF) { /* bad head? */
dqc_sta[drv] = dqc_sta[drv] | STA_EOC | STA_ERR; dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */
break; } } /* done */ break; } }
dqxb[dq_ptr++] = dqd_wval? dqd_obuf: 0; /* store word/fill */ dqxb[dq_ptr++] = dqd_wval? dqd_obuf: 0; /* store word/fill */
dqd_wval = 0; /* clr data valid */ dqd_wval = 0; /* clr data valid */
if (dq_ptr >= DQ_NUMWD) { /* buffer full? */ if (dq_ptr >= DQ_NUMWD) { /* buffer full? */
da = GETDA (dqc_rarc[drv], dqc_rarh[drv], dqc_rars[drv]); da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */
dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */ dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */
if (dqc_rars[drv] >= DQ_NUMSC) { /* end of surf? */ if (dqc_rars == 0) /* wrap? incr head */
dqc_rars[drv] = 0; /* wrap to */ dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1;
dqc_rarh[drv] = dqc_rarh[drv] + 1; } /* next head */
if (err = fseek (uptr->fileref, da * sizeof (int16), if (err = fseek (uptr->fileref, da * sizeof (int16),
SEEK_SET)) return TRUE; SEEK_SET)) return TRUE;
fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref);
@ -635,25 +649,26 @@ return SCPE_OK;
t_stat dqc_reset (DEVICE *dptr) t_stat dqc_reset (DEVICE *dptr)
{ {
int32 i; int32 drv;
hp_enbdis_pair (&dqc_dev, &dqd_dev); /* make pair cons */ hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &dqd_dev)? &dqc_dev: &dqd_dev);
dqd_ibuf = dqd_obuf = 0; /* clear buffers */ dqd_ibuf = dqd_obuf = 0; /* clear buffers */
dqc_busy = dqc_obuf = 0; dqc_busy = dqc_obuf = 0;
dqd_xfer = dqd_wval = 0; dqd_xfer = dqd_wval = 0;
dq_ptr = 0; dq_ptr = 0;
dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */
dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */ dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */
dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */ dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */
dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */ dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */
dqc_dib.flg = dqd_dib.flg = 1; /* set flg */ dqc_dib.flg = dqd_dib.flg = 1; /* set flg */
dqc_dib.srq = dqd_dib.srq = 1; /* srq follows flg */ dqc_dib.srq = dqd_dib.srq = 1; /* srq follows flg */
sim_cancel (&dqd_unit); /* cancel dch */ sim_cancel (&dqd_unit); /* cancel dch */
for (i = 0; i < DQ_NUMDRV; i++) { /* loop thru drives */ for (drv = 0; drv < DQ_NUMDRV; drv++) { /* loop thru drives */
sim_cancel (&dqc_unit[i]); /* cancel activity */ sim_cancel (&dqc_unit[drv]); /* cancel activity */
dqc_unit[i].FNC = 0; /* clear function */ dqc_unit[drv].FNC = 0; /* clear function */
dqc_unit[i].CYL = 0; dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */
dqc_rarc[i] = dqc_rarh[i] = dqc_rars[i] = 0; /* clear rar */ dqc_sta[drv] = 0; } /* clear status */
dqc_sta[i] = 0; }
return SCPE_OK; return SCPE_OK;
} }

View file

@ -23,9 +23,29 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
fhd 12606B 2770/2771 fixed head disk dr 12606B 2770/2771 fixed head disk
12610B 2773/2774/2775 drum 12610B 2773/2774/2775 drum
07-Oct-04 JDB Fixed enable/disable from either device
Fixed sector return in status word
Provided protected tracks and "Writing Enabled" status bit
Fixed DMA last word write, incomplete sector fill value
Added "parity error" status return on writes for 12606
Added track origin test for 12606
Added SCP test for 12606
Fixed 12610 SFC operation
Added "Sector Flag" status bit
Added "Read Inhibit" status bit for 12606
Fixed current-sector determination
Added PROTECTED, UNPROTECTED, TRACKPROT modifiers
26-Aug-04 RMS Fixed CLC to stop operation (from Dave Bryan)
26-Apr-04 RMS Fixed SFS x,C and SFC x,C
Revised boot rom to use IBL algorithm
Implemented DMA SRQ (follows FLG)
27-Jul-03 RMS Fixed drum sizes
Fixed variable capacity interaction with SAVE/RESTORE
10-Nov-02 RMS Added BOOT command
These head-per-track devices are buffered in memory, to minimize overhead. These head-per-track devices are buffered in memory, to minimize overhead.
The drum data channel does not have a command flip-flop. Its control The drum data channel does not have a command flip-flop. Its control
@ -35,13 +55,46 @@
The drum control channel does not have any of the traditional flip-flops. The drum control channel does not have any of the traditional flip-flops.
26-Aug-04 RMS Fixed CLC to stop operation (from Dave Bryan) The 12606 interface implements two diagnostic tests. An SFS CC instruction
26-Apr-04 RMS Fixed SFS x,C and SFC x,C will skip if the disk has passed the track origin (sector 0) since the last
Revised boot rom to use IBL algorithm CLF CC instruction, and an SFC CC instruction will skip if the Sector Clock
Implemented DMA SRQ (follows FLG) Phase (SCP) flip-flop is clear, indicating that the current sector is
27-Jul-03 RMS Fixed drum sizes accessible. The 12610 interface does not support these tests; the SKF signal
Fixed variable capacity interaction with SAVE/RESTORE is not driven, so neither SFC CC nor SFS CC will skip.
10-Nov-02 RMS Added BOOT command
The interface implements a track protect mechanism via a switch and a set of
on-card diodes. The switch sets the protected/unprotected status, and the
particular diodes installed indicate the range of tracks (a power of 2) that
are read-only in the protected mode.
Somewhat unusually, writing to a protected track completes normally, but the
data isn't actually written, as the write current is inhibited. There is no
"failure" status indication. Instead, a program must note the lack of
"Writing Enabled" status before the write is attempted.
Specifications (2770/2771):
- 90 sectors per logical track
- 45 sectors per revolution
- 64 words per sector
- 2880 words per revolution
- 3450 RPM = 17.4 ms/revolution
- data timing = 6.0 us/word, 375 us/sector
- inst timing = 4 inst/word, 11520 inst/revolution
Specifications 2773/2774/2775:
- 32 sectors per logical track
- 32 sectors per revolution
- 64 words per sector
- 2048 words per revolution
- 3450 RPM = 17.4 ms/revolution
- data timing = 8.5 us/word, 550 us/sector
- inst timing = 6 inst/word, 12288 inst/revolution
References:
- 12606B Disc Memory Interface Kit Operating and Service Manual
(12606-90012, Mar-1970)
- 12610B Drum Memory Interface Kit Operating and Service Manual
(12610-9001, Feb-1970)
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -54,8 +107,13 @@
#define DR_DNUMSC 32 /* drum sec/track */ #define DR_DNUMSC 32 /* drum sec/track */
#define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC) #define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)
#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */ #define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */
#define UNIT_V_SZ (UNIT_V_UF) /* disk vs drum */ #define DR_FTIME 4 /* fhd per-word time */
#define DR_DTIME 6 /* drum per-word time */
#define DR_OVRHEAD 5 /* overhead words at track start */
#define UNIT_V_PROT (UNIT_V_UF + 0) /* track protect */
#define UNIT_V_SZ (UNIT_V_UF + 1) /* disk vs drum */
#define UNIT_M_SZ 017 /* size */ #define UNIT_M_SZ 017 /* size */
#define UNIT_PROT (1 << UNIT_V_PROT)
#define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ) #define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ)
#define UNIT_DR (1 << UNIT_V_SZ) /* low order bit */ #define UNIT_DR (1 << UNIT_V_SZ) /* low order bit */
#define SZ_180K 000 /* disks */ #define SZ_180K 000 /* disks */
@ -95,21 +153,21 @@
(((x) & CW_M_DSEC) << CW_V_DSEC): \ (((x) & CW_M_DSEC) << CW_V_DSEC): \
(((x) & CW_M_FSEC) << CW_V_FSEC)) (((x) & CW_M_FSEC) << CW_V_FSEC))
/* Status register */ /* Status register, ^ = dynamic */
#define DRS_V_NS 8 /* next sector */ #define DRS_V_NS 8 /* ^next sector */
#define DRS_M_NS 0177 #define DRS_M_NS 0177
#define DRS_SEC 0100000 /* sector flag */ #define DRS_SEC 0100000 /* ^sector flag */
#define DRS_RDY 0000200 /* ready */ #define DRS_RDY 0000200 /* ^ready */
#define DRS_RIF 0000100 /* read inhibit */ #define DRS_RIF 0000100 /* ^read inhibit */
#define DRS_SAC 0000040 /* sector coincidence */ #define DRS_SAC 0000040 /* sector coincidence */
#define DRS_ABO 0000010 /* abort */ #define DRS_ABO 0000010 /* abort */
#define DRS_WEN 0000004 /* write enabled */ #define DRS_WEN 0000004 /* ^write enabled */
#define DRS_PER 0000002 /* parity error */ #define DRS_PER 0000002 /* parity error */
#define DRS_BSY 0000001 /* busy */ #define DRS_BSY 0000001 /* ^busy */
#define GET_CURSEC(x) ((int32) fmod (sim_gtime() / ((double) (x)), \ #define CALC_SCP(x) (((int32) fmod ((x) / (double) dr_time, \
((double) ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)))) (double) (DR_NUMWD))) >= (DR_NUMWD - 3))
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern uint16 *M; extern uint16 *M;
@ -118,11 +176,13 @@ extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
int32 drc_cw = 0; /* fnc, addr */ int32 drc_cw = 0; /* fnc, addr */
int32 drc_sta = 0; /* status */ int32 drc_sta = 0; /* status */
int32 drc_run = 0; /* run flip-flop */
int32 drd_ibuf = 0; /* input buffer */ int32 drd_ibuf = 0; /* input buffer */
int32 drd_obuf = 0; /* output buffer */ int32 drd_obuf = 0; /* output buffer */
int32 drd_ptr = 0; /* sector pointer */ int32 drd_ptr = 0; /* sector pointer */
int32 drc_pcount = 1; /* number of prot tracks */
int32 dr_stopioe = 1; /* stop on error */ int32 dr_stopioe = 1; /* stop on error */
int32 dr_time = 10; /* time per word */ int32 dr_time = DR_DTIME; /* time per word */
static int32 sz_tab[16] = { static int32 sz_tab[16] = {
184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288, 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288,
@ -136,6 +196,8 @@ t_stat drc_reset (DEVICE *dptr);
t_stat drc_attach (UNIT *uptr, char *cptr); t_stat drc_attach (UNIT *uptr, char *cptr);
t_stat drc_boot (int32 unitno, DEVICE *dptr); t_stat drc_boot (int32 unitno, DEVICE *dptr);
int32 dr_incda (int32 trk, int32 sec, int32 ptr); int32 dr_incda (int32 trk, int32 sec, int32 ptr);
int32 dr_seccntr (double simtime);
t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
/* DRD data structures /* DRD data structures
@ -152,7 +214,12 @@ DIB dr_dib[] = {
#define drd_dib dr_dib[0] #define drd_dib dr_dib[0]
#define drc_dib dr_dib[1] #define drc_dib dr_dib[1]
UNIT drd_unit = { UDATA (NULL, 0, 0) }; UNIT drd_unit[] = {
{ UDATA (NULL, 0, 0) },
{ UDATA (NULL, UNIT_DIS, 0) } };
#define TMR_ORG 0 /* origin timer */
#define TMR_INH 1 /* inhibit timer */
REG drd_reg[] = { REG drd_reg[] = {
{ ORDATA (IBUF, drd_ibuf, 16) }, { ORDATA (IBUF, drd_ibuf, 16) },
@ -172,9 +239,9 @@ MTAB drd_mod[] = {
{ 0 } }; { 0 } };
DEVICE drd_dev = { DEVICE drd_dev = {
"DRD", &drd_unit, drd_reg, drd_mod, "DRD", drd_unit, drd_reg, drd_mod,
1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
NULL, NULL, NULL, NULL, NULL, &drc_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&drd_dib, DEV_DISABLE }; &drd_dib, DEV_DISABLE };
@ -191,8 +258,10 @@ UNIT drc_unit =
UNIT_MUSTBUF+UNIT_DR+UNIT_BINK, DR_SIZE) }; UNIT_MUSTBUF+UNIT_DR+UNIT_BINK, DR_SIZE) };
REG drc_reg[] = { REG drc_reg[] = {
{ DRDATA (PCNT, drc_pcount, 10), REG_HIDDEN | PV_LEFT },
{ ORDATA (CW, drc_cw, 16) }, { ORDATA (CW, drc_cw, 16) },
{ ORDATA (STA, drc_sta, 16) }, { ORDATA (STA, drc_sta, 16) },
{ FLDATA (RUN, drc_run, 0) },
{ FLDATA (CMD, drc_dib.cmd, 0) }, { FLDATA (CMD, drc_dib.cmd, 0) },
{ FLDATA (CTL, drc_dib.ctl, 0) }, { FLDATA (CTL, drc_dib.ctl, 0) },
{ FLDATA (FLG, drc_dib.flg, 0) }, { FLDATA (FLG, drc_dib.flg, 0) },
@ -217,6 +286,10 @@ MTAB drc_mod[] = {
{ UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size }, { UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size },
{ UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size }, { UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size },
{ UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size }, { UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size },
{ UNIT_PROT, UNIT_PROT, "protected", "PROTECTED", NULL },
{ UNIT_PROT, 0, "unprotected", "UNPROTECTED", NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "tracks protected", "TRACKPROT",
&dr_set_prot, NULL, &drc_reg[0] },
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &drd_dev }, &hp_setdev, &hp_showdev, &drd_dev },
{ 0 } }; { 0 } };
@ -249,15 +322,15 @@ case ioCTL: /* control clear/set */
if (IR & I_AB) { /* CLC */ if (IR & I_AB) { /* CLC */
clrCMD (devd); /* clr "ctl" */ clrCMD (devd); /* clr "ctl" */
clrFSR (devd); /* clr flg */ clrFSR (devd); /* clr flg */
sim_cancel (&drc_unit); /* cancel curr op */ if (!drc_run) sim_cancel (&drc_unit); /* cancel curr op */
drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */ drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */
else if (!CMD (devd)) { /* STC, not set? */ else if (!CMD (devd)) { /* STC, not set? */
setCMD (devd); /* set "ctl" */ setCMD (devd); /* set "ctl" */
if (drc_cw & CW_WR) { setFSR (devd); } /* prime DMA */ if (drc_cw & CW_WR) { setFSR (devd); } /* prime DMA */
drc_sta = 0; /* clear errors */ drc_sta = 0; /* clr status */
drd_ptr = 0; /* clear sec ptr */ drd_ptr = 0; /* clear sec ptr */
sim_cancel (&drc_unit); /* cancel curr op */ sim_cancel (&drc_unit); /* cancel curr op */
t = CW_GETSEC (drc_cw) - GET_CURSEC (dr_time * DR_NUMWD); t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime());
if (t <= 0) t = t + DR_NUMSC; if (t <= 0) t = t + DR_NUMSC;
sim_activate (&drc_unit, t * DR_NUMWD * dr_time); } sim_activate (&drc_unit, t * DR_NUMWD * dr_time); }
break; break;
@ -269,23 +342,48 @@ return dat;
int32 drcio (int32 inst, int32 IR, int32 dat) int32 drcio (int32 inst, int32 IR, int32 dat)
{ {
int32 st; int32 sec;
switch (inst) { /* case on opcode */ switch (inst) { /* case on opcode */
case ioFLG: /* flag clear/set */
if ((IR & I_HC) && !(drc_unit.flags & UNIT_DR)) { /* CLF disk */
sec = dr_seccntr (sim_gtime ()); /* current sector */
sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */
sim_activate (&drd_unit[TMR_ORG],
(DR_FNUMSC - sec) * DR_NUMWD * dr_time); }
break;
case ioSFC: /* skip flag clear */ case ioSFC: /* skip flag clear */
PC = (PC + 1) & VAMASK; if (drc_unit.flags & UNIT_DR) break; /* 12610 never skips */
if (!(CALC_SCP (sim_gtime()))) /* nearing end of sector? */
PC = (PC + 1) & VAMASK; /* skip if SCP clear */
break;
case ioSFS: /* skip flag set */
if (drc_unit.flags & UNIT_DR) break; /* 12610 never skips */
if (!sim_is_active (&drd_unit[TMR_ORG])) /* passed origin? */
PC = (PC + 1) & VAMASK; /* skip if origin seen */
break; break;
case ioOTX: /* output */ case ioOTX: /* output */
drc_cw = dat; if (!(drc_unit.flags & UNIT_DR)) { /* disk? */
sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */
sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); }
drc_cw = dat; /* get control word */
break; break;
case ioLIX: /* load */ case ioLIX: /* load */
dat = 0; dat = 0;
case ioMIX: /* merge */ case ioMIX: /* merge */
if (drc_unit.flags & UNIT_ATT) /* attached? */ dat = dat | drc_sta; /* static bits */
st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta | if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */
(sim_is_active (&drc_unit)? DRS_BSY: 0); (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */
else st = drc_sta; dat = dat | DRS_WEN; /* set wrt enb status */
dat = dat | st; /* merge status */ if (drc_unit.flags & UNIT_ATT) { /* attached? */
dat = dat | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY;
if (sim_is_active (&drc_unit)) /* op in progress? */
dat = dat | DRS_BSY;
if (CALC_SCP (sim_gtime())) /* SCP ff set? */
dat = dat | DRS_SEC; /* set sector flag */
if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */
!(drc_cw & CW_WR))
dat = dat | DRS_RIF; } /* set read inh flag */
break; break;
default: default:
break; } break; }
@ -304,11 +402,12 @@ if ((uptr->flags & UNIT_ATT) == 0) {
drc_sta = DRS_ABO; drc_sta = DRS_ABO;
return IORETURN (dr_stopioe, SCPE_UNATT); } return IORETURN (dr_stopioe, SCPE_UNATT); }
drc_sta = drc_sta | DRS_SAC;
devd = drd_dib.devno; /* get dch devno */ devd = drd_dib.devno; /* get dch devno */
trk = CW_GETTRK (drc_cw); trk = CW_GETTRK (drc_cw);
sec = CW_GETSEC (drc_cw); sec = CW_GETSEC (drc_cw);
da = ((trk * DR_NUMSC) + sec) * DR_NUMWD; da = ((trk * DR_NUMSC) + sec) * DR_NUMWD;
drc_sta = drc_sta | DRS_SAC;
drc_run = 1; /* set run ff */
if (drc_cw & CW_WR) { /* write? */ if (drc_cw & CW_WR) { /* write? */
if ((da < uptr->capac) && (sec < DR_NUMSC)) { if ((da < uptr->capac) && (sec < DR_NUMSC)) {
@ -319,9 +418,13 @@ if (drc_cw & CW_WR) { /* write? */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
sim_activate (uptr, dr_time); } /* sched next word */ sim_activate (uptr, dr_time); } /* sched next word */
else if (drd_ptr) { /* done, need to fill? */ else { /* done */
for ( ; drd_ptr < DR_NUMWD; drd_ptr++) if (drd_ptr) /* need to fill? */
bptr[da + drd_ptr] = 0; } for ( ; drd_ptr < DR_NUMWD; drd_ptr++)
bptr[da + drd_ptr] = drd_obuf; /* fill with last word */
if (!(drc_unit.flags & UNIT_DR)) /* disk? */
drc_sta = drc_sta | DRS_PER; /* parity bit sets on write */
drc_run = 0; } /* clear run ff */
} /* end write */ } /* end write */
else { /* read */ else { /* read */
if (CMD (devd)) { /* dch active? */ if (CMD (devd)) { /* dch active? */
@ -330,6 +433,7 @@ else { /* read */
drd_ptr = dr_incda (trk, sec, drd_ptr); drd_ptr = dr_incda (trk, sec, drd_ptr);
setFSR (devd); /* set dch flg */ setFSR (devd); /* set dch flg */
sim_activate (uptr, dr_time); } /* sched next word */ sim_activate (uptr, dr_time); } /* sched next word */
else drc_run = 0; /* clear run ff */
} }
return SCPE_OK; return SCPE_OK;
} }
@ -351,11 +455,38 @@ if (ptr >= DR_NUMWD) { /* end sector? */
return ptr; return ptr;
} }
/* Read the sector counter
The hardware sector counter contains the number of the next sector that will
pass under the heads (so it is one ahead of the current sector). For the
duration of the last sector of the track, the sector counter contains 90 for
the 12606 and 0 for the 12610. The sector counter resets to 0 at track
origin and increments at the start of the first sector. Therefore, the
counter value ranges from 0-90 for the 12606 and 0-31 for the 12610. The 0
state is quite short in the 12606 and long in the 12610, relative to the
other sector counter states.
The simulated sector counter is calculated from the simulation time, based on
the time per word and the number of words per track.
*/
int32 dr_seccntr (double simtime)
{
int32 curword;
curword = (int32) fmod (simtime / (double) dr_time,
(double) (DR_NUMWD * DR_NUMSC + DR_OVRHEAD));
if (curword <= DR_OVRHEAD) return 0;
else return ((curword - DR_OVRHEAD) / DR_NUMWD +
((drc_unit.flags & UNIT_DR)? 0: 1));
}
/* Reset routine */ /* Reset routine */
t_stat drc_reset (DEVICE *dptr) t_stat drc_reset (DEVICE *dptr)
{ {
hp_enbdis_pair (&drc_dev, &drd_dev); /* make pair cons */ hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &drd_dev)? &drc_dev: &drd_dev);
drc_sta = drc_cw = drd_ptr = 0; drc_sta = drc_cw = drd_ptr = 0;
drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */ drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */
drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */ drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */
@ -363,6 +494,8 @@ drc_dib.fbf = drd_dib.fbf = 0; /* clear fbf */
drc_dib.flg = drd_dib.flg = 0; /* clear flg */ drc_dib.flg = drd_dib.flg = 0; /* clear flg */
drc_dib.srq = drd_dib.srq = 0; /* srq follows flg */ drc_dib.srq = drd_dib.srq = 0; /* srq follows flg */
sim_cancel (&drc_unit); sim_cancel (&drc_unit);
sim_cancel (&drd_unit[TMR_ORG]);
sim_cancel (&drd_unit[TMR_INH]);
return SCPE_OK; return SCPE_OK;
} }
@ -377,16 +510,53 @@ uptr->capac = sz;
return attach_unit (uptr, cptr); return attach_unit (uptr, cptr);
} }
/* Set protected track count */
t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 count;
t_stat status;
if (cptr == NULL) return SCPE_ARG;
count = (int32) get_uint (cptr, 10, 768, &status);
if (status != SCPE_OK) return status;
else switch (count) {
case 1:
case 2:
case 4:
case 8:
case 16:
case 32:
case 64:
case 128:
drc_pcount = count;
break;
case 256:
case 512:
case 768:
if (drc_unit.flags & UNIT_DR) drc_pcount = count;
else return SCPE_ARG;
break;
default:
return SCPE_ARG; }
return SCPE_OK;
}
/* Set size routine */ /* Set size routine */
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{ {
int32 sz; int32 sz;
int32 szindex;
if (val < 0) return SCPE_IERR; if (val < 0) return SCPE_IERR;
if ((sz = sz_tab[DR_GETSZ (val)]) == 0) return SCPE_IERR; if ((sz = sz_tab[szindex = DR_GETSZ (val)]) == 0) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT; if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = sz; uptr->capac = sz;
if (szindex & UNIT_DR) dr_time = DR_DTIME; /* drum */
else {
dr_time = DR_FTIME; /* disk */
if (drc_pcount > 128) drc_pcount = 128; } /* max prot track count */
return SCPE_OK; return SCPE_OK;
} }

View file

@ -162,8 +162,7 @@
#define CMF_UNDF 001 /* undefined */ #define CMF_UNDF 001 /* undefined */
#define CMF_CLREC 002 /* clear eoc flag */ #define CMF_CLREC 002 /* clear eoc flag */
#define CMF_CLRS 004 /* clear status */ #define CMF_CLRS 004 /* clear status */
#define CMF_UNIT 010 /* validate unit */ #define CMF_UIDLE 010 /* requires unit no */
#define CMF_UIDLE 020 /* unit must be idle */
/* Cylinder words - 16b */ /* Cylinder words - 16b */
@ -216,7 +215,7 @@
#define DS2_BS 0000001 /* *busy */ #define DS2_BS 0000001 /* *busy */
#define DS2_ALLERR (DS2_FLT|DS2_SC|DS2_NR|DS2_BS) #define DS2_ALLERR (DS2_FLT|DS2_SC|DS2_NR|DS2_BS)
/* Drive state */ /* Controller state */
#define DS_IDLE 0 /* idle */ #define DS_IDLE 0 /* idle */
#define DS_WAIT 1 /* command wait */ #define DS_WAIT 1 /* command wait */
@ -313,25 +312,25 @@ uint32 ds_ptr = 0; /* buffer ptr */
uint16 dsxb[DS_NUMWDF]; /* sector buffer */ uint16 dsxb[DS_NUMWDF]; /* sector buffer */
static const uint32 ds_opflags[32] = { /* flags for ops */ static const uint32 ds_opflags[32] = { /* flags for ops */
CMF_CLREC|CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* cold read */ CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* cold read */
CMF_CLREC|CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* recalibrate */ CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* recalibrate */
CMF_CLREC|CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* seek */ CMF_CLREC|CMF_CLRS|CMF_UIDLE, /* seek */
0, /* read status */ 0, /* read status */
CMF_CLRS, /* read sector */ CMF_CLRS, /* read sector */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read */ CMF_CLRS|CMF_UIDLE, /* read */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read full */ CMF_CLRS|CMF_UIDLE, /* read full */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* verify */ CMF_CLRS|CMF_UIDLE, /* verify */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* write */ CMF_CLRS|CMF_UIDLE, /* write */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* write full */ CMF_CLRS|CMF_UIDLE, /* write full */
CMF_CLRS, /* clear */ CMF_CLRS, /* clear */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* init */ CMF_CLRS|CMF_UIDLE, /* init */
CMF_CLREC|CMF_CLRS, /* addr record */ CMF_CLREC|CMF_CLRS, /* addr record */
0, /* read syndrome */ 0, /* read syndrome */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read offset */ CMF_CLRS|CMF_UIDLE, /* read offset */
CMF_CLRS, /* set file mask */ CMF_CLRS, /* set file mask */
CMF_UNDF|CMF_CLRS, /* undefined */ CMF_UNDF|CMF_CLRS, /* undefined */
CMF_UNDF|CMF_CLRS, /* undefined */ CMF_UNDF|CMF_CLRS, /* undefined */
CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read no verify */ CMF_CLRS|CMF_UIDLE, /* read no verify */
CMF_CLRS, /* write TIO */ CMF_CLRS, /* write TIO */
CMF_CLRS, /* read disk addr */ CMF_CLRS, /* read disk addr */
CMF_CLRS, /* end */ CMF_CLRS, /* end */
@ -359,6 +358,7 @@ t_stat ds_boot (int32 unitno, DEVICE *dptr);
t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
void ds_poll (void); void ds_poll (void);
void ds_docmd (uint32 cmd); void ds_docmd (uint32 cmd);
void ds_doatn (void);
uint32 ds_updds2 (UNIT *uptr, uint32 clear); uint32 ds_updds2 (UNIT *uptr, uint32 clear);
void ds_cmd_done (t_bool sf, uint32 sr1); void ds_cmd_done (t_bool sf, uint32 sr1);
void ds_wait_for_cpu (UNIT *uptr, uint32 newst); void ds_wait_for_cpu (UNIT *uptr, uint32 newst);
@ -553,20 +553,10 @@ return dat;
void ds_poll (void) void ds_poll (void)
{ {
uint32 i, dev; int32 dev = ds_dib.devno;
dev = ds_dib.devno; /* device num */ if ((ds_state != DS_BUSY) && ds_cmdp) ds_docmd (ds_cmd);/* cmd pending? */
if (ds_state == DS_BUSY) return; /* ctrl busy? */ if ((ds_state == DS_IDLE) && CTL (dev)) ds_doatn (); /* idle? chk atn */
if (ds_cmdp) ds_docmd (ds_cmd); /* cmd pending? */
if ((ds_state != DS_IDLE) || !CTL (dev)) return; /* waiting for cmd or */
for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */
ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */
if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */
ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */
setFLG (dev); /* request interrupt */
ds_sr1 = DS1_ATTN | ds_lastatn; /* set up status 1 */
ds_state = DS_WAIT; /* block attn intrs */
return; } }
return; return;
} }
@ -598,11 +588,6 @@ if (f & CMF_CLREC) ds_eoc = 0; /* clear end cyl */
if (f & CMF_UNDF) { /* illegal op? */ if (f & CMF_UNDF) { /* illegal op? */
ds_sched_ctrl_op (DSC_BADF, 0, CLR_BUSY); /* sched, not busy */ ds_sched_ctrl_op (DSC_BADF, 0, CLR_BUSY); /* sched, not busy */
return; } return; }
if (f & CMF_UNIT) { /* validate unit? */
if (f & CMF_CLRS) ds_sr1 = ds_u; /* init status */
if (ds_u >= DS_NUMDR) { /* invalid unit? */
ds_sched_ctrl_op (DSC_BADU, ds_u, CLR_BUSY);/* sched, not busy */
return; } }
switch (op) { switch (op) {
/* Drive commands */ /* Drive commands */
@ -622,6 +607,10 @@ case DSC_VFY: /* verify */
case DSC_WRITE: /* write */ case DSC_WRITE: /* write */
case DSC_WFULL: /* write full */ case DSC_WFULL: /* write full */
case DSC_INIT: /* init */ case DSC_INIT: /* init */
ds_sr1 = ds_u; /* init status */
if (ds_u >= DS_NUMDR) { /* invalid unit? */
ds_sched_ctrl_op (DSC_BADU, ds_u, CLR_BUSY);/* sched, not busy */
return; }
ds_unit[ds_u].FNC = op; /* save op */ ds_unit[ds_u].FNC = op; /* save op */
ds_unit[ds_u].STA &= ~DS2_ATN; /* clear ATTN */ ds_unit[ds_u].STA &= ~DS2_ATN; /* clear ATTN */
sim_activate (&ds_unit[ds_u], ds_ctime); /* schedule unit */ sim_activate (&ds_unit[ds_u], ds_ctime); /* schedule unit */
@ -667,6 +656,24 @@ case DSC_END: /* end */
break; } break; }
return; return;
} }
/* Check for attention */
void ds_doatn (void)
{
uint32 i, dev;
dev = ds_dib.devno; /* device num */
for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */
ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */
if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */
ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */
setFLG (dev); /* request interrupt */
ds_sr1 = DS1_ATTN | ds_lastatn; /* set up status 1 */
ds_state = DS_WAIT; /* block attn intrs */
return; } }
return;
}
/* Controller service /* Controller service
@ -822,8 +829,7 @@ case DSC_COLD: /* cold load read */
break; break;
case DSC_READ: /* read */ case DSC_READ: /* read */
case DSC_RNOVFY: /* read, no verify */ if (r = ds_start_rd (uptr, 0, 1)) /* new sector; error? */
if (r = ds_start_rd (uptr, 0, op != DSC_RNOVFY)) /* new sector; error? */
return r; return r;
break; break;
case DSC_READ | DSC_2ND: /* word transfer */ case DSC_READ | DSC_2ND: /* word transfer */
@ -833,6 +839,17 @@ case DSC_READ | DSC_3RD: /* end of sector */
ds_end_rw (uptr, DSC_READ); /* see if more to do */ ds_end_rw (uptr, DSC_READ); /* see if more to do */
break; break;
case DSC_RNOVFY: /* read, no verify */
if (r = ds_start_rd (uptr, 0, 0)) /* new sector; error? */
return r;
break;
case DSC_RNOVFY | DSC_2ND: /* word transfer */
ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */
break;
case DSC_RNOVFY | DSC_3RD: /* end of sector */
ds_end_rw (uptr, DSC_RNOVFY); /* see if more to do */
break;
case DSC_RFULL: /* read full */ case DSC_RFULL: /* read full */
dsxb[DS_FSYNC] = 0100376; /* fill in header */ dsxb[DS_FSYNC] = 0100376; /* fill in header */
dsxb[DS_FCYL] = uptr->CYL; dsxb[DS_FCYL] = uptr->CYL;
@ -864,15 +881,14 @@ case DSC_VFY | DSC_3RD: /* start sector */
break; break;
case DSC_VFY | DSC_4TH: /* end sector */ case DSC_VFY | DSC_4TH: /* end sector */
ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */ ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */
if (ds_vctr) ds_end_rw (uptr, DSC_VFY | DSC_3RD); /* more to do? */ if (ds_vctr) ds_end_rw (uptr, DSC_VFY|DSC_3RD); /* more to do? */
else ds_cmd_done (1, DS1_OK); /* no, set done */ else ds_cmd_done (1, DS1_OK); /* no, set done */
break; break;
/* Write variants */ /* Write variants */
case DSC_INIT: /* init */
case DSC_WRITE: /* write */ case DSC_WRITE: /* write */
ds_start_wr (uptr, op != DSC_INIT); /* new sector */ ds_start_wr (uptr, 1); /* new sector */
break; break;
case DSC_WRITE | DSC_2ND: case DSC_WRITE | DSC_2ND:
if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */ if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */
@ -882,12 +898,23 @@ case DSC_WRITE | DSC_3RD: /* end sector */
ds_end_rw (uptr, DSC_WRITE); /* see if more to do */ ds_end_rw (uptr, DSC_WRITE); /* see if more to do */
break; break;
case DSC_INIT: /* init */
ds_start_wr (uptr, 0); /* new sector */
break;
case DSC_INIT | DSC_2ND:
if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */
return r; /* error? */
break;
case DSC_INIT | DSC_3RD: /* end sector */
ds_end_rw (uptr, DSC_INIT); /* see if more to do */
break;
case DSC_WFULL: /* write full */ case DSC_WFULL: /* write full */
ds_start_wr (uptr, 0); /* new sector */ ds_start_wr (uptr, 0); /* new sector */
break; break;
case DSC_WFULL | DSC_2ND: case DSC_WFULL | DSC_2ND:
if (r = ds_cont_wr (uptr, DS_FDATA, DS_NUMWDF)) if (r = ds_cont_wr (uptr, DS_FDATA, DS_NUMWDF)) /* write word */
return r; return r; /* error */
break; break;
case DSC_WFULL | DSC_3RD: case DSC_WFULL | DSC_3RD:
ds_end_rw (uptr, DSC_WFULL); /* see if more to do */ ds_end_rw (uptr, DSC_WFULL); /* see if more to do */
@ -999,12 +1026,12 @@ uint32 dtyp = GET_DTYPE (uptr->flags);
uptr->FNC = newst; /* set new state */ uptr->FNC = newst; /* set new state */
if (cyl >= drv_tab[dtyp].cyl) { /* out of bounds? */ if (cyl >= drv_tab[dtyp].cyl) { /* out of bounds? */
uptr->CYL = t = drv_tab[dtyp].cyl; /* put off edge */ uptr->CYL = t = drv_tab[dtyp].cyl; /* put off edge */
uptr->STA = uptr->STA | DS2_SC; } /* set seek check */ uptr->STA = uptr->STA | DS2_SC; } /* set seek check */
else { /* seek in range */ else { /* seek in range */
t = abs (uptr->CYL - cyl); /* delta cylinders */ t = abs (uptr->CYL - cyl); /* delta cylinders */
uptr->CYL = cyl; /* put on cylinder */ uptr->CYL = cyl; /* put on cylinder */
uptr->STA = uptr->STA & ~DS2_SC; } /* clear seek check */ uptr->STA = uptr->STA & ~DS2_SC; } /* clear seek check */
sim_activate (uptr, ds_stime * (t + 1)); /* schedule */ sim_activate (uptr, ds_stime * (t + 1)); /* schedule */
return; return;
} }

View file

@ -23,8 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
ipli, iplo 12556B interprocessor link pair ipli, iplo 12566B interprocessor link pair
07-Oct-04 JDB Fixed enable/disable from either device
26-Apr-04 RMS Fixed SFS x,C and SFC x,C 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
Implemented DMA SRQ (follows FLG) Implemented DMA SRQ (follows FLG)
21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny) 21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny)
@ -163,7 +164,7 @@ int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat)
{ {
uint32 u, dev, odev; uint32 u, dev, odev;
int32 sta; int32 sta;
int8 msg[2]; char msg[2];
dev = IR & I_DEVMASK; /* get device no */ dev = IR & I_DEVMASK; /* get device no */
switch (inst) { /* case on opcode */ switch (inst) { /* case on opcode */
@ -222,7 +223,7 @@ return dat;
t_stat ipl_svc (UNIT *uptr) t_stat ipl_svc (UNIT *uptr)
{ {
int32 u, nb, dev; int32 u, nb, dev;
int8 msg[2]; char msg[2];
u = uptr - ipl_unit; /* get link number */ u = uptr - ipl_unit; /* get link number */
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */
@ -270,7 +271,8 @@ t_stat ipl_reset (DEVICE *dptr)
DIB *dibp = (DIB *) dptr->ctxt; DIB *dibp = (DIB *) dptr->ctxt;
UNIT *uptr = dptr->units; UNIT *uptr = dptr->units;
hp_enbdis_pair (&ipli_dev, &iplo_dev); /* make pair cons */ hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &ipli_dev)? &iplo_dev: &ipli_dev);
dibp->cmd = dibp->ctl = 0; /* clear cmd, ctl */ dibp->cmd = dibp->ctl = 0; /* clear cmd, ctl */
dibp->flg = dibp->fbf = dibp->srq = 1; /* set flg, fbf, srq */ dibp->flg = dibp->fbf = dibp->srq = 1; /* set flg, fbf, srq */
uptr->IBUF = uptr->OBUF = 0; /* clr buffers */ uptr->IBUF = uptr->OBUF = 0; /* clr buffers */

View file

@ -24,8 +24,15 @@
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
lps 12653A 2767 line printer lps 12653A 2767 line printer
(based on 12556B microcircuit interface) (based on 12566B microcircuit interface)
01-Oct-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON
Fixed status returns for error conditions
Fixed handling of non-printing characters
Fixed handling of characters after column 80
Improved timing model accuracy for RTE
Added fast/realistic timing
Added debug printouts
03-Jun-04 RMS Fixed timing (found by Dave Bryan) 03-Jun-04 RMS Fixed timing (found by Dave Bryan)
26-Apr-04 RMS Fixed SFS x,C and SFC x,C 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
Implemented DMA SRQ (follows FLG) Implemented DMA SRQ (follows FLG)
@ -37,26 +44,129 @@
21-Nov-00 RMS Fixed flag, fbf power up state 21-Nov-00 RMS Fixed flag, fbf power up state
Added command flop Added command flop
15-Oct-00 RMS Added variable device number support 15-Oct-00 RMS Added variable device number support
The 2767 impact printer has a rotating drum with 80 columns of 64 raised
characters. ASCII codes 32 through 95 (SPACE through "_") form the print
repertoire. The printer responds to the control characters FF, LF, and CR.
The 80 columns are divided into four zones of 20 characters each that are
addressed sequentially. Received characters are buffered in a 20-character
memory. When the 20th printable character is received, the current zone is
printed, and the memory is reset. In the absence of print command
characters, a zone print operation will commence after each group of 20
printable characters is transmitted to the printer.
The print command characters have these actions:
* CR -- print the characters in the current zone, reset to zone 1, and clear
the buffer memory.
* LF -- same as CR, plus advances the paper one line.
* FF -- same as CR, plus advances the paper to the top of the next form.
The 2767 provides two status bits via the interface:
bit 15 -- printer not ready
bit 0 -- printer busy
The expected status returns are:
100001 -- power off or cable disconnected
100001 -- initial power on, then changes to 000001 within sixty
seconds of initial power on
000001 -- power on, paper unloaded or printer offline or not idle
000000 -- power on, paper loaded and printer online and idle
These simulator commands provide the listed printer states:
SET LPS POWEROFF --> power off or cable disconnected
SET LPS POWERON --> power on
SET LPS OFFLINE --> printer offline
SET LPS ONLINE --> printer online
ATT LPS <file> --> paper loaded
DET LPS --> paper out
References:
- 2767A Line Printer Operating and Service Manual (02767-90002, Oct-1973)
- 12566B, 12566B-001, 12566B-002, 12566B-003 Microcircuit Interface Kits
Operating and Service Manual (12566-90015, Apr-1976)
The following implemented behaviors have been inferred from secondary sources
(diagnostics, operating system drivers, etc.), due to absent or contradictory
authoritative information; future correction may be needed:
1. Paper out sets BUSY instead of NOT READY.
2. Print operation in progress sets BUSY instead of NOT READY.
3. Characters not in the print repertoire are replaced with blanks.
4. The 81st and succeeding characters overprint the current line.
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
#define LPS_BUSY 0000001 /* busy */ #define LPS_ZONECNT 20 /* zone char count */
#define LPS_NRDY 0100000 /* not ready */ #define LPS_PAGECNT 80 /* page char count */
#define LPS_PAGELNT 60 /* page line length */
#define LPS_FORMLNT 66 /* form line length */
/* Printer power states */
#define LPS_ON 0 /* power is on */
#define LPS_OFF 1 /* power is off */
#define LPS_TURNING_ON 2 /* power is turning on */
#define LPS_BUSY 0000001 /* busy status */
#define LPS_NRDY 0100000 /* not ready status */
#define LPS_PWROFF LPS_BUSY | LPS_NRDY /* power-off status */
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
#define UNIT_V_POWEROFF (UNIT_V_UF + 1) /* unit powered off */
#define UNIT_V_OFFLINE (UNIT_V_UF + 2) /* unit offline */
#define UNIT_DIAG (1 << UNIT_V_DIAG) #define UNIT_DIAG (1 << UNIT_V_DIAG)
#define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
extern uint32 PC; extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
int32 lps_ctime = 4; /* char time */ extern FILE *sim_deb;
int32 lps_ptime = 10000; /* print time */
int32 lps_ccnt = 0; /* character count */
int32 lps_lcnt = 0; /* line count */
int32 lps_stopioe = 0; /* stop on error */ int32 lps_stopioe = 0; /* stop on error */
int32 lps_sta = 0; int32 lps_sta = 0; /* printer status */
int32 lps_timing = 1; /* timing type */
uint32 lps_power = LPS_ON; /* power state */
/* Hardware timing:
(based on 1580 instr/msec) instr msec calc msec
------------------------
- character transfer time : ctime = 2 2 us
- per-zone printing time : ptime = 55300 35 40
- per-line paper slew time : stime = 17380 11 13
- power-on ready delay time : rtime = 158000 100
NOTE: the printer acknowledges before the print motion has stopped to allow
for continuous slew, so the set times are a bit less than the calculated
operation time from the manual.
*/
int32 lps_ctime = 0; /* char xfer time */
int32 lps_ptime = 0; /* zone printing time */
int32 lps_stime = 0; /* paper slew time */
int32 lps_rtime = 0; /* power-on ready time */
typedef int32 TIMESET[4]; /* set of controller times */
int32 *const lps_timers[] = { &lps_ctime, &lps_ptime, &lps_stime, &lps_rtime };
const TIMESET lps_times[2] = { { 2, 55300, 17380, 158000 }, /* REALTIME */
{ 2, 1000, 1000, 1000 } }; /* FASTTIME */
DEVICE lps_dev; DEVICE lps_dev;
int32 lpsio (int32 inst, int32 IR, int32 dat); int32 lpsio (int32 inst, int32 IR, int32 dat);
t_stat lps_svc (UNIT *uptr); t_stat lps_svc (UNIT *uptr);
t_stat lps_reset (DEVICE *dptr); t_stat lps_reset (DEVICE *dptr);
t_stat lps_attach (UNIT *uptr, char *cptr);
t_stat lps_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc);
/* LPS data structures /* LPS data structures
@ -68,19 +178,25 @@ t_stat lps_reset (DEVICE *dptr);
DIB lps_dib = { LPS, 0, 0, 0, 0, 0, &lpsio }; DIB lps_dib = { LPS, 0, 0, 0, 0, 0, &lpsio };
UNIT lps_unit = { UNIT lps_unit = {
UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE, 0) }; UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE, 0) };
REG lps_reg[] = { REG lps_reg[] = {
{ ORDATA (BUF, lps_unit.buf, 16) }, { ORDATA (BUF, lps_unit.buf, 16) },
{ ORDATA (STA, lps_sta, 16) }, { ORDATA (STA, lps_sta, 16) },
{ ORDATA (POWER, lps_power, 2), REG_RO },
{ FLDATA (CMD, lps_dib.cmd, 0) }, { FLDATA (CMD, lps_dib.cmd, 0) },
{ FLDATA (CTL, lps_dib.ctl, 0) }, { FLDATA (CTL, lps_dib.ctl, 0) },
{ FLDATA (FLG, lps_dib.flg, 0) }, { FLDATA (FLG, lps_dib.flg, 0) },
{ FLDATA (FBF, lps_dib.fbf, 0) }, { FLDATA (FBF, lps_dib.fbf, 0) },
{ FLDATA (SRQ, lps_dib.srq, 0) }, { FLDATA (SRQ, lps_dib.srq, 0) },
{ DRDATA (CCNT, lps_ccnt, 7), PV_LEFT },
{ DRDATA (LCNT, lps_lcnt, 7), PV_LEFT },
{ DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (CTIME, lps_ctime, 31), PV_LEFT }, { DRDATA (CTIME, lps_ctime, 24), PV_LEFT },
{ DRDATA (PTIME, lps_ptime, 24), PV_LEFT }, { DRDATA (PTIME, lps_ptime, 24), PV_LEFT },
{ DRDATA (STIME, lps_stime, 24), PV_LEFT },
{ DRDATA (RTIME, lps_rtime, 24), PV_LEFT },
{ FLDATA (TIMING, lps_timing, 0), REG_HRO },
{ FLDATA (STOP_IOE, lps_stopioe, 0) }, { FLDATA (STOP_IOE, lps_stopioe, 0) },
{ ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO }, { ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO },
{ NULL } }; { NULL } };
@ -88,6 +204,16 @@ REG lps_reg[] = {
MTAB lps_mod[] = { MTAB lps_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
{ UNIT_DIAG, 0, "printer mode", "PRINTER", NULL }, { UNIT_DIAG, 0, "printer mode", "PRINTER", NULL },
{ UNIT_POWEROFF, UNIT_POWEROFF, "power off", "POWEROFF", NULL },
{ UNIT_POWEROFF, 0, "power on", "POWERON", NULL },
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },
{ UNIT_OFFLINE, 0, "online", "ONLINE", NULL },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME",
&lps_set_timing, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME",
&lps_set_timing, NULL, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL,
NULL, &lps_show_timing, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &lps_dev }, &hp_setdev, &hp_showdev, &lps_dev },
{ 0 } }; { 0 } };
@ -96,14 +222,14 @@ DEVICE lps_dev = {
"LPS", &lps_unit, lps_reg, lps_mod, "LPS", &lps_unit, lps_reg, lps_mod,
1, 10, 31, 1, 8, 8, 1, 10, 31, 1, 8, 8,
NULL, NULL, &lps_reset, NULL, NULL, &lps_reset,
NULL, NULL, NULL, NULL, &lps_attach, NULL,
&lps_dib, DEV_DISABLE | DEV_DIS }; &lps_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG };
/* Line printer IOT routine */ /* Line printer IOT routine */
int32 lpsio (int32 inst, int32 IR, int32 dat) int32 lpsio (int32 inst, int32 IR, int32 dat)
{ {
int32 dev; int32 dev, sched;
dev = IR & I_DEVMASK; /* get device no */ dev = IR & I_DEVMASK; /* get device no */
switch (inst) { /* case on opcode */ switch (inst) { /* case on opcode */
@ -117,18 +243,37 @@ case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
break; break;
case ioOTX: /* output */ case ioOTX: /* output */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS OTx: Character %06o output\n", dat);
lps_unit.buf = dat; lps_unit.buf = dat;
break; break;
case ioLIX: /* load */ case ioLIX: /* load */
dat = 0; /* default sta = 0 */ dat = 0; /* default sta = 0 */
case ioMIX: /* merge */ case ioMIX: /* merge */
if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */ if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */
lps_sta = 0; /* create status */ if (lps_power == LPS_ON) { /* power on? */
if ((lps_unit.flags & UNIT_ATT) == 0) if (lps_unit.flags & UNIT_POWEROFF) { /* power just turned off? */
lps_sta = lps_sta | LPS_BUSY | LPS_NRDY; lps_power = LPS_OFF; /* change state */
else if (sim_is_active (&lps_unit)) lps_sta = LPS_PWROFF;
lps_sta = lps_sta | LPS_BUSY; } if (DEBUG_PRS (lps_dev))
fputs (">>LPS LIx: Power state is OFF\n", sim_deb); }
else if (((lps_unit.flags & UNIT_ATT) == 0) ||
(lps_unit.flags & UNIT_OFFLINE) ||
sim_is_active (&lps_unit)) lps_sta = LPS_BUSY;
else lps_sta = 0; }
else if (lps_power == LPS_TURNING_ON) /* printer warming up? */
lps_sta = LPS_PWROFF;
else if (!(lps_unit.flags & UNIT_POWEROFF)) { /* power just turned on? */
lps_power = LPS_TURNING_ON; /* change state */
lps_unit.flags |= UNIT_OFFLINE; /* set offline */
sim_activate (&lps_unit, lps_rtime); /* schedule printer ready */
lps_sta = LPS_PWROFF;
if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS LIx: Power state is TURNING ON, scheduled time = %d\n",
lps_rtime ); } }
dat = dat | lps_sta; /* diag, rtn status */ dat = dat | lps_sta; /* diag, rtn status */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", dat);
break; break;
case ioCTL: /* control clear/set */ case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */ if (IR & I_CTL) { /* CLC */
@ -139,8 +284,36 @@ case ioCTL: /* control clear/set */
setCTL (dev); setCTL (dev);
if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */ if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */
sim_activate (&lps_unit, 1); /* loop back */ sim_activate (&lps_unit, 1); /* loop back */
else sim_activate (&lps_unit, /* real lpt, sched */ else { /* real lpt, sched */
(lps_unit.buf < 040)? lps_ptime: lps_ctime); } if (DEBUG_PRS (lps_dev)) fprintf (sim_deb,
">>LPS STC: Character %06o scheduled for line %d, column %d, ",
lps_unit.buf, lps_lcnt + 1, lps_ccnt + 1);
if ((lps_unit.buf != '\f') &&
(lps_unit.buf != '\n') &&
(lps_unit.buf != '\r')) { /* normal char */
if ((lps_unit.buf < ' ') || (lps_unit.buf > '_'))
sched = lps_ctime; /* non-printing char */
else { /* printing char */
lps_ccnt = lps_ccnt + 1; /* incr char counter */
if (lps_ccnt % LPS_ZONECNT == 0)/* end of zone? */
sched = lps_ptime; /* print zone */
else sched = lps_ctime; } } /* xfer char */
else { /* print cmd */
if (lps_ccnt % LPS_ZONECNT == 0) /* last zone printed? */
sched = lps_ctime; /* yes, so just char time */
else sched = lps_ptime; /* no, so print needed */
lps_ccnt = 0; /* reset char counter */
if (lps_unit.buf == '\n') { /* line advance */
lps_lcnt = (lps_lcnt + 1) % LPS_PAGELNT;
if (lps_lcnt > 0) sched = sched + lps_stime;
else sched = sched + /* allow for perf skip */
lps_stime * (LPS_FORMLNT - LPS_PAGELNT); }
else if (lps_unit.buf == '\f') { /* form advance */
sched = sched + lps_stime * (LPS_FORMLNT - lps_lcnt);
lps_lcnt = 0; } }
sim_activate (&lps_unit, sched);
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, "time = %d\n", sched); } }
break; break;
default: default:
break; } break; }
@ -151,21 +324,45 @@ return dat;
t_stat lps_svc (UNIT *uptr) t_stat lps_svc (UNIT *uptr)
{ {
int32 dev; int32 dev;
int32 c = lps_unit.buf & 0177; int32 c = uptr->buf & 0177;
if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */
lps_power = LPS_ON; /* change state */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS svc: Power state is ON\n", sim_deb);
return SCPE_OK; } /* done */
dev = lps_dib.devno; /* get dev no */ dev = lps_dib.devno; /* get dev no */
clrCMD (dev); /* clear cmd */ clrCMD (dev); /* clear cmd */
setFSR (dev); /* set flag, fbf */ setFSR (dev); /* set flag, fbf */
if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ if (uptr->flags & UNIT_DIAG) { /* diagnostic? */
lps_sta = lps_unit.buf; /* loop back */ lps_sta = uptr->buf; /* loop back */
return SCPE_OK; } /* done */ return SCPE_OK; } /* done */
if ((lps_unit.flags & UNIT_ATT) == 0) /* real lpt, att? */ if ((uptr->flags & UNIT_ATT) == 0) /* real lpt, att? */
return IORETURN (lps_stopioe, SCPE_UNATT); return IORETURN (lps_stopioe, SCPE_UNATT);
if (fputc (c, lps_unit.fileref) == EOF) { if (((c < ' ') || (c > '_')) && /* non-printing char? */
(c != '\f') && (c != '\n') && (c != '\r')) {
c = ' '; /* replace with blank */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS svc: Character %06o erased\n", c); }
if (lps_ccnt > LPS_PAGECNT) { /* 81st character? */
fputc ('\r', uptr->fileref); /* return to line start */
uptr->pos = uptr->pos + 1; /* update pos */
lps_ccnt = 1; /* reset char counter */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS svc: Line wraparound to column 1\n", sim_deb); }
fputc (c, uptr->fileref); /* "print" char */
uptr->pos = uptr->pos + 1; /* update pos */
if (DEBUG_PRS (lps_dev))
fprintf (sim_deb, ">>LPS svc: Character %06o printed\n", c);
if ((lps_lcnt == 0) && (c == '\n')) { /* LF did TOF? */
fputc ('\f', uptr->fileref); /* do perf skip */
uptr->pos = uptr->pos + 1; /* update pos */
if (DEBUG_PRS (lps_dev))
fputs (">>LPS svc: Perforation skip to TOF\n", sim_deb); }
if (ferror (uptr->fileref)) {
perror ("LPS I/O error"); perror ("LPS I/O error");
clearerr (lps_unit.fileref); clearerr (uptr->fileref);
return SCPE_IOERR; } return SCPE_IOERR; }
lps_unit.pos = lps_unit.pos + 1; /* update pos */
return SCPE_OK; return SCPE_OK;
} }
@ -176,6 +373,37 @@ t_stat lps_reset (DEVICE *dptr)
lps_dib.cmd = lps_dib.ctl = 0; /* clear cmd, ctl */ lps_dib.cmd = lps_dib.ctl = 0; /* clear cmd, ctl */
lps_dib.flg = lps_dib.fbf = lps_dib.srq = 1; /* set flg, fbf, srq */ lps_dib.flg = lps_dib.fbf = lps_dib.srq = 1; /* set flg, fbf, srq */
lps_sta = lps_unit.buf = 0; lps_sta = lps_unit.buf = 0;
lps_power = LPS_ON; /* power is on */
sim_cancel (&lps_unit); /* deactivate unit */ sim_cancel (&lps_unit); /* deactivate unit */
lps_set_timing (NULL, lps_timing, NULL, NULL); /* init timing set */
return SCPE_OK;
}
/* Attach routine */
t_stat lps_attach (UNIT *uptr, char *cptr)
{
lps_ccnt = lps_lcnt = 0; /* top of form */
return attach_unit (uptr, cptr);
}
/* Set printer timing */
t_stat lps_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i;
lps_timing = (val != 0); /* determine choice */
for (i = 0; i < (sizeof (lps_timers) / sizeof (lps_timers[0])); i++)
*lps_timers[i] = lps_times[lps_timing][i]; /* assign times */
return SCPE_OK;
}
/* Show printer timing */
t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc)
{
if (lps_timing) fputs ("fast timing", st);
else fputs ("realistic timing", st);
return SCPE_OK; return SCPE_OK;
} }

View file

@ -1,4 +1,4 @@
/* hp2100_lpt.c: HP 2100 12845A line printer simulator /* hp2100_lpt.c: HP 2100 12845B line printer simulator
Copyright (c) 1993-2004, Robert M. Supnik Copyright (c) 1993-2004, Robert M. Supnik
@ -23,13 +23,45 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
lpt 12845A line printer lpt 12845B 2607 line printer
29-Sep-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON
Fixed status returns for error conditions
Fixed TOF handling so form remains on line 0
03-Jun-04 RMS Fixed timing (found by Dave Bryan) 03-Jun-04 RMS Fixed timing (found by Dave Bryan)
26-Apr-04 RMS Fixed SFS x,C and SFC x,C 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
Implemented DMA SRQ (follows FLG) Implemented DMA SRQ (follows FLG)
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
24-Oct-02 RMS Cloned from 12653A 24-Oct-02 RMS Cloned from 12653A
The 2607 provides three status bits via the interface:
bit 15 -- printer ready (online)
bit 14 -- paper out
bit 0 -- printer idle
The expected status returns are:
140001 -- power off or cable disconnected
100001 -- power on, paper loaded, printer ready
100000 -- power on, paper loaded, printer busy
040000 -- power on, paper out (at bottom-of-form)
000000 -- power on, paper out (not at BOF) / print button up / platen open
Manual Note: "2-33. PAPER OUT SIGNAL. [...] The signal is asserted only
when the format tape in the line printer has reached the bottom of form."
These simulator commands provide the listed printer states:
SET LPT POWEROFF --> power off or cable disconnected
SET LPT POWERON --> power on
SET LPT OFFLINE --> print button up
SET LPT ONLINE --> print button down
ATT LPT <file> --> paper loaded
DET LPT --> paper out
Reference:
- 12845A Line Printer Operating and Service Manual (12845-90001, Aug-1972)
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -39,12 +71,18 @@
#define LPT_NBSY 0000001 /* not busy */ #define LPT_NBSY 0000001 /* not busy */
#define LPT_PAPO 0040000 /* paper out */ #define LPT_PAPO 0040000 /* paper out */
#define LPT_RDY 0100000 /* ready */ #define LPT_RDY 0100000 /* ready */
#define LPT_PWROFF LPT_RDY | LPT_PAPO | LPT_NBSY /* power-off status */
#define LPT_CTL 0100000 /* control output */ #define LPT_CTL 0100000 /* control output */
#define LPT_CHAN 0000100 /* skip to chan */ #define LPT_CHAN 0000100 /* skip to chan */
#define LPT_SKIPM 0000077 /* line count mask */ #define LPT_SKIPM 0000077 /* line count mask */
#define LPT_CHANM 0000007 /* channel mask */ #define LPT_CHANM 0000007 /* channel mask */
#define UNIT_V_POWEROFF (UNIT_V_UF + 0) /* unit powered off */
#define UNIT_V_OFFLINE (UNIT_V_UF + 1) /* unit offline */
#define UNIT_POWEROFF (1 << UNIT_V_POWEROFF)
#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE)
extern uint32 PC; extern uint32 PC;
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2];
@ -71,7 +109,7 @@ t_stat lpt_attach (UNIT *uptr, char *cptr);
DIB lpt_dib = { LPT, 0, 0, 0, 0, 0, &lptio }; DIB lpt_dib = { LPT, 0, 0, 0, 0, 0, &lptio };
UNIT lpt_unit = { UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0) }; UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE, 0) };
REG lpt_reg[] = { REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 7) }, { ORDATA (BUF, lpt_unit.buf, 7) },
@ -89,6 +127,10 @@ REG lpt_reg[] = {
{ NULL } }; { NULL } };
MTAB lpt_mod[] = { MTAB lpt_mod[] = {
{ UNIT_POWEROFF, UNIT_POWEROFF, "power off", "POWEROFF", NULL },
{ UNIT_POWEROFF, 0, "power on", "POWERON", NULL },
{ UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL },
{ UNIT_OFFLINE, 0, "online", "ONLINE", NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &lpt_dev }, &hp_setdev, &hp_showdev, &lpt_dev },
{ 0 } }; { 0 } };
@ -123,11 +165,15 @@ case ioOTX: /* output */
case ioLIX: /* load */ case ioLIX: /* load */
dat = 0; /* default sta = 0 */ dat = 0; /* default sta = 0 */
case ioMIX: /* merge */ case ioMIX: /* merge */
if (lpt_unit.flags & UNIT_ATT) { if (lpt_unit.flags & UNIT_POWEROFF) /* power off? */
dat = dat | LPT_RDY; dat = dat | LPT_PWROFF;
if (!sim_is_active (&lpt_unit)) else if (!(lpt_unit.flags & UNIT_OFFLINE)) /* online? */
dat = dat | LPT_NBSY; } if (lpt_unit.flags & UNIT_ATT) { /* paper loaded? */
else dat = dat | LPT_PAPO; dat = dat | LPT_RDY;
if (!sim_is_active (&lpt_unit)) /* printer busy? */
dat = dat | LPT_NBSY; }
else if (lpt_lcnt == LPT_PAGELNT - 1) /* paper out, at BOF? */
dat = dat | LPT_PAPO;
break; break;
case ioCTL: /* control clear/set */ case ioCTL: /* control clear/set */
if (IR & I_CTL) { /* CLC */ if (IR & I_CTL) { /* CLC */
@ -160,7 +206,7 @@ if (uptr->buf & LPT_CTL) { /* control word? */
if (chan == 0) { /* top of form? */ if (chan == 0) { /* top of form? */
fputc ('\f', uptr->fileref); /* ffeed */ fputc ('\f', uptr->fileref); /* ffeed */
lpt_lcnt = 0; /* reset line cnt */ lpt_lcnt = 0; /* reset line cnt */
skip = 1; } skip = 0; }
else if (chan == 1) skip = LPT_PAGELNT - lpt_lcnt - 1; else if (chan == 1) skip = LPT_PAGELNT - lpt_lcnt - 1;
else skip = lpt_cct[chan] - (lpt_lcnt % lpt_cct[chan]); else skip = lpt_cct[chan] - (lpt_lcnt % lpt_cct[chan]);
} }

View file

@ -26,6 +26,7 @@
ms 13181A 7970B 800bpi nine track magnetic tape ms 13181A 7970B 800bpi nine track magnetic tape
13183A 7970E 1600bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape
07-Oct-04 JDB Fixed enable/disable from either device
14-Aug-04 JDB Fixed many functional and timing problems (from Dave Bryan) 14-Aug-04 JDB Fixed many functional and timing problems (from Dave Bryan)
- fixed erroneous execution of rejected command - fixed erroneous execution of rejected command
- fixed erroneous execution of select-only command - fixed erroneous execution of select-only command
@ -63,6 +64,12 @@
If the byte count is odd, the record is padded with an extra byte If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0. of junk. File marks are represented by a byte count of 0.
References:
- 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
(13181-90901, Nov-1982)
- 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual
(13183-90901, Nov-1983)
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -233,7 +240,7 @@ DEVICE msd_dev = {
1, 10, DB_N_SIZE, 1, 8, 8, 1, 10, DB_N_SIZE, 1, 8, 8,
NULL, NULL, &msc_reset, NULL, NULL, &msc_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&msd_dib, 0 }; &msd_dib, DEV_DISABLE };
/* MSC data structures /* MSC data structures
@ -646,7 +653,8 @@ t_stat msc_reset (DEVICE *dptr)
int32 i; int32 i;
UNIT *uptr; UNIT *uptr;
hp_enbdis_pair (&msc_dev, &msd_dev); /* make pair cons */ hp_enbdis_pair (dptr, /* make pair cons */
(dptr == &msd_dev)? &msc_dev: &msd_dev);
msc_buf = msd_buf = 0; msc_buf = msd_buf = 0;
msc_sta = msc_usl = 0; msc_sta = msc_usl = 0;
msc_1st = 0; msc_1st = 0;

View file

@ -25,6 +25,7 @@
mt 12559A 3030 nine track magnetic tape mt 12559A 3030 nine track magnetic tape
07-Oct-04 JDB Allow enable/disable from either device
14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan) 14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan)
06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan) 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan)
26-Apr-04 RMS Fixed SFS x,C and SFC x,C 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
@ -111,6 +112,7 @@ DEVICE mtd_dev, mtc_dev;
int32 mtdio (int32 inst, int32 IR, int32 dat); int32 mtdio (int32 inst, int32 IR, int32 dat);
int32 mtcio (int32 inst, int32 IR, int32 dat); int32 mtcio (int32 inst, int32 IR, int32 dat);
t_stat mtc_svc (UNIT *uptr); t_stat mtc_svc (UNIT *uptr);
t_stat mtd_reset (DEVICE *dptr);
t_stat mtc_reset (DEVICE *dptr); t_stat mtc_reset (DEVICE *dptr);
t_stat mtc_attach (UNIT *uptr, char *cptr); t_stat mtc_attach (UNIT *uptr, char *cptr);
t_stat mtc_detach (UNIT *uptr); t_stat mtc_detach (UNIT *uptr);
@ -156,7 +158,7 @@ MTAB mtd_mod[] = {
DEVICE mtd_dev = { DEVICE mtd_dev = {
"MTD", &mtd_unit, mtd_reg, mtd_mod, "MTD", &mtd_unit, mtd_reg, mtd_mod,
1, 10, 16, 1, 8, 8, 1, 10, 16, 1, 8, 8,
NULL, NULL, &mtc_reset, NULL, NULL, &mtd_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&mtd_dib, DEV_DISABLE | DEV_DIS }; &mtd_dib, DEV_DISABLE | DEV_DIS };
@ -447,6 +449,12 @@ return SCPE_OK;
/* Reset routine */ /* Reset routine */
t_stat mtd_reset (DEVICE *dptr)
{
hp_enbdis_pair (&mtd_dev, &mtc_dev); /* make pair cons */
return mtc_reset (dptr); /* do common reset */
}
t_stat mtc_reset (DEVICE *dptr) t_stat mtc_reset (DEVICE *dptr)
{ {
hp_enbdis_pair (&mtc_dev, &mtd_dev); /* make pair cons */ hp_enbdis_pair (&mtc_dev, &mtd_dev); /* make pair cons */

View file

@ -25,6 +25,7 @@
mux,muxl,muxc 12920A terminal multiplexor mux,muxl,muxc 12920A terminal multiplexor
07-Oct-04 JDB Allow enable/disable from any device
26-Apr-04 RMS Fixed SFS x,C and SFC x,C 26-Apr-04 RMS Fixed SFS x,C and SFC x,C
Implemented DMA SRQ (follows FLG) Implemented DMA SRQ (follows FLG)
05-Jan-04 RMS Revised for tmxr library changes 05-Jan-04 RMS Revised for tmxr library changes
@ -41,6 +42,10 @@
The lower data card has no CMD flop; the control card has no CMD flop. The lower data card has no CMD flop; the control card has no CMD flop.
The upper data card has none of the usual flops. The upper data card has none of the usual flops.
Reference:
- 12920A Asynchronous Multiplexer Interface Kits Operating and Service
Manual (12920-90001, Oct-1972)
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -163,7 +168,7 @@ int32 muxuio (int32 inst, int32 IR, int32 dat);
int32 muxcio (int32 inst, int32 IR, int32 dat); int32 muxcio (int32 inst, int32 IR, int32 dat);
t_stat muxi_svc (UNIT *uptr); t_stat muxi_svc (UNIT *uptr);
t_stat muxo_svc (UNIT *uptr); t_stat muxo_svc (UNIT *uptr);
t_stat mux_reset (DEVICE *dptr); t_stat muxc_reset (DEVICE *dptr);
t_stat mux_attach (UNIT *uptr, char *cptr); t_stat mux_attach (UNIT *uptr, char *cptr);
t_stat mux_detach (UNIT *uptr); t_stat mux_detach (UNIT *uptr);
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
@ -235,7 +240,7 @@ MTAB muxu_mod[] = {
DEVICE muxu_dev = { DEVICE muxu_dev = {
"MUX", &muxu_unit, muxu_reg, muxu_mod, "MUX", &muxu_unit, muxu_reg, muxu_mod,
1, 10, 31, 1, 8, 8, 1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &mux_reset, &tmxr_ex, &tmxr_dep, &muxc_reset,
NULL, &mux_attach, &mux_detach, NULL, &mux_attach, &mux_detach,
&muxu_dib, DEV_NET | DEV_DISABLE }; &muxu_dib, DEV_NET | DEV_DISABLE };
@ -301,9 +306,9 @@ REG muxl_reg[] = {
DEVICE muxl_dev = { DEVICE muxl_dev = {
"MUXL", muxl_unit, muxl_reg, muxl_mod, "MUXL", muxl_unit, muxl_reg, muxl_mod,
MUX_LINES, 10, 31, 1, 8, 8, MUX_LINES, 10, 31, 1, 8, 8,
NULL, NULL, &mux_reset, NULL, NULL, &muxc_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&muxl_dib, 0 }; &muxl_dib, DEV_DISABLE };
/* MUXM data structures /* MUXM data structures
@ -338,9 +343,9 @@ MTAB muxc_mod[] = {
DEVICE muxc_dev = { DEVICE muxc_dev = {
"MUXM", &muxc_unit, muxc_reg, muxc_mod, "MUXM", &muxc_unit, muxc_reg, muxc_mod,
1, 10, 31, 1, 8, 8, 1, 10, 31, 1, 8, 8,
NULL, NULL, &mux_reset, NULL, NULL, &muxc_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&muxc_dib, 0 }; &muxc_dib, DEV_DISABLE };
/* IOT routines: data cards */ /* IOT routines: data cards */
@ -634,15 +639,18 @@ return;
/* Reset routine */ /* Reset routine */
t_stat mux_reset (DEVICE *dptr) t_stat muxc_reset (DEVICE *dptr)
{ {
int32 i, t; int32 i, t;
if (muxu_dev.flags & DEV_DIS) { /* enb/dis dev */ if (dptr == &muxc_dev) { /* make all consistent */
muxl_dev.flags = muxu_dev.flags | DEV_DIS; hp_enbdis_pair (dptr, &muxl_dev);
muxc_dev.flags = muxc_dev.flags | DEV_DIS; } hp_enbdis_pair (dptr, &muxu_dev); }
else { muxl_dev.flags = muxl_dev.flags & ~DEV_DIS; else if (dptr == &muxl_dev) {
muxc_dev.flags = muxc_dev.flags & ~DEV_DIS; } hp_enbdis_pair (dptr, &muxc_dev);
hp_enbdis_pair (dptr, &muxu_dev); }
else { hp_enbdis_pair (dptr, &muxc_dev);
hp_enbdis_pair (dptr, &muxl_dev); }
muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */ muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */
muxl_dib.flg = muxl_dib.fbf = muxl_dib.srq = 1; muxl_dib.flg = muxl_dib.fbf = muxl_dib.srq = 1;
muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */ muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */

View file

@ -13,9 +13,9 @@
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTI_CTLILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LII_CTLLE FOR ANY CLAIM, DAMAGES OR OTHER LII_CTLILITY, WHETHER 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 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. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@ -23,11 +23,14 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
ptr 12597A-002 paper tape reader ptr 12597A-002 paper tape reader interface
ptp 12597A-005 paper tape punch ptp 12597A-005 paper tape punch interface
tty 12531C buffered teleprinter interface tty 12531C buffered teleprinter interface
clk 12539C time base generator clk 12539C time base generator
13-Sep-04 JDB Added paper tape loop mode, DIAG/READER modifiers to PTR
Added PV_LEFT to PTR TRLLIM register
Modified CLK to permit disable
15-Aug-04 RMS Added tab to control char set (from Dave Bryan) 15-Aug-04 RMS Added tab to control char set (from Dave Bryan)
14-Jul-04 RMS Generalized handling of control char echoing 14-Jul-04 RMS Generalized handling of control char echoing
(from Dave Bryan) (from Dave Bryan)
@ -57,6 +60,10 @@
The reader and punch, like most HP devices, have a command flop. The The reader and punch, like most HP devices, have a command flop. The
teleprinter and clock do not. teleprinter and clock do not.
Reader diagnostic mode simulates a tape loop by rewinding the tape image file
upon EOF. Normal mode EOF action is to supply TRLLIM nulls and then either
return SCPE_IOERR or SCPE_OK without setting the device flag.
The clock autocalibrates. If the specified clock frequency is below The clock autocalibrates. If the specified clock frequency is below
10Hz, the clock service routine runs at 10Hz and counts down a repeat 10Hz, the clock service routine runs at 10Hz and counts down a repeat
counter before generating an interrupt. Autocalibration will not work counter before generating an interrupt. Autocalibration will not work
@ -66,6 +73,13 @@
This turns off autocalibration and divides the longest time intervals down This turns off autocalibration and divides the longest time intervals down
by 10**3. The clk_time values were chosen to allow the diagnostic to by 10**3. The clk_time values were chosen to allow the diagnostic to
pass its clock calibration test. pass its clock calibration test.
References:
- 2748B Tape Reader Operating and Service Manual (02748-90041, Oct-1977)
- 12597A 8-Bit Duplex Register Interface Kit Operating and Service Manual
(12597-9002, Sep-1974)
- 12539C Time Base Generator Interface Kit Operating and Service Manual
(12539-90008, Jan-1975)
*/ */
#include "hp2100_defs.h" #include "hp2100_defs.h"
@ -170,7 +184,7 @@ REG ptr_reg[] = {
{ FLDATA (FBF, ptr_dib.fbf, 0) }, { FLDATA (FBF, ptr_dib.fbf, 0) },
{ FLDATA (SRQ, ptr_dib.srq, 0) }, { FLDATA (SRQ, ptr_dib.srq, 0) },
{ DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO }, { DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO },
{ DRDATA (TRLLIM, ptr_trllim, 8) }, { DRDATA (TRLLIM, ptr_trllim, 8), PV_LEFT },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) }, { FLDATA (STOP_IOE, ptr_stopioe, 0) },
@ -178,6 +192,8 @@ REG ptr_reg[] = {
{ NULL } }; { NULL } };
MTAB ptr_mod[] = { MTAB ptr_mod[] = {
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
{ UNIT_DIAG, 0, "reader mode", "READER", NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &ptr_dev }, &hp_setdev, &hp_showdev, &ptr_dev },
{ 0 } }; { 0 } };
@ -327,7 +343,7 @@ DEVICE clk_dev = {
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset, NULL, NULL, &clk_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&clk_dib, 0 }; &clk_dib, DEV_DISABLE };
/* Paper tape reader: IOT routine */ /* Paper tape reader: IOT routine */
@ -377,15 +393,20 @@ dev = ptr_dib.devno; /* get device no */
clrCMD (dev); /* clear cmd */ clrCMD (dev); /* clear cmd */
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT); return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */
if (feof (ptr_unit.fileref)) { /* end of file? */ if (feof (ptr_unit.fileref)) { /* end of file? */
if (ptr_trlcnt >= ptr_trllim) { /* added all trailer? */ if ((ptr_unit.flags & UNIT_DIAG) && (ptr_unit.pos > 0)) {
if (ptr_stopioe) { /* stop on error? */ rewind (ptr_unit.fileref); /* rewind if loop mode */
printf ("PTR end of file\n"); ptr_unit.pos = 0; }
return SCPE_IOERR; } else {
else return SCPE_OK; } /* no, just hang */ if (ptr_trlcnt >= ptr_trllim) { /* added all trailer? */
ptr_trlcnt++; /* count trailer */ if (ptr_stopioe) { /* stop on error? */
temp = 0; } /* read a zero */ printf ("PTR end of file\n");
return SCPE_IOERR; }
else return SCPE_OK; } /* no, just hang */
ptr_trlcnt++; /* count trailer */
temp = 0; /* read a zero */
break; } }
else { /* no, real error */ else { /* no, real error */
perror ("PTR I/O error"); perror ("PTR I/O error");
clearerr (ptr_unit.fileref); clearerr (ptr_unit.fileref);

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
25-Sep-04 JDB Added memory protect device
Fixed display of CCA/CCB/CCE instructions
01-Jun-04 RMS Added latent 13037 support 01-Jun-04 RMS Added latent 13037 support
19-Apr-04 RMS Recognize SFS x,C and SFC x,C 19-Apr-04 RMS Recognize SFS x,C and SFC x,C
22-Mar-02 RMS Revised for dynamically allocated memory 22-Mar-02 RMS Revised for dynamically allocated memory
@ -43,6 +45,7 @@
extern DEVICE cpu_dev; extern DEVICE cpu_dev;
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern DEVICE mp_dev;
extern DEVICE dma0_dev, dma1_dev; extern DEVICE dma0_dev, dma1_dev;
extern DEVICE ptr_dev, ptp_dev; extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tty_dev, clk_dev; extern DEVICE tty_dev, clk_dev;
@ -78,6 +81,7 @@ int32 sim_emax = 3;
DEVICE *sim_devices[] = { DEVICE *sim_devices[] = {
&cpu_dev, &cpu_dev,
&mp_dev,
&dma0_dev, &dma0_dev,
&dma1_dev, &dma1_dev,
&ptr_dev, &ptr_dev,
@ -283,8 +287,8 @@ static const char *stab[] = {
static const int32 mtab[] = { static const int32 mtab[] = {
0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
0006400, 0007000, 0007400, 0006400, 0007000, 0007400, 0007400, 0007400, 0007400, 0007400, 0007400, 0007400,
0002040, 0002040, 0002100, 0002200, 0002300, 0002040, 0002040, 0002300, 0002300, 0002300,
0006020, 0006020, 0004010, 0004010, 0006020, 0006020, 0004010, 0004010,
0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,

View file

@ -35,6 +35,7 @@
Cards are represented as ASCII text streams terminated by newlines. Cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files. This allows cards to be created and edited as normal files.
14-Nov-04 WVS Added column binary support
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
30-May-02 RMS Widened POS to 32b 30-May-02 RMS Widened POS to 32b
30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder 30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder
@ -49,8 +50,9 @@ extern uint8 M[];
extern int32 ind[64], ssa, iochk; extern int32 ind[64], ssa, iochk;
extern char bcd_to_ascii[64]; extern char bcd_to_ascii[64];
extern char ascii_to_bcd[128]; extern char ascii_to_bcd[128];
extern int16 colbin[64];
int32 s1sel, s2sel, s4sel, s8sel; int32 s1sel, s2sel, s4sel, s8sel;
char rbuf[CBUFSIZE]; /* > CDR_WIDTH */ char rbuf[2 * CBUFSIZE]; /* > CDR_WIDTH */
t_stat cdr_svc (UNIT *uptr); t_stat cdr_svc (UNIT *uptr);
t_stat cdr_boot (int32 unitno, DEVICE *dptr); t_stat cdr_boot (int32 unitno, DEVICE *dptr);
t_stat cdr_attach (UNIT *uptr, char *cptr); t_stat cdr_attach (UNIT *uptr, char *cptr);
@ -135,21 +137,24 @@ DEVICE stack_dev = {
/* Card read routine /* Card read routine
Modifiers have been checked by the caller Modifiers have been checked by the caller
No modifiers are recognized (column binary is not implemented) C modifier is recognized (column binary is implemented)
*/ */
t_stat read_card (int32 ilnt, int32 mod) t_stat read_card (int32 ilnt, int32 mod)
{ {
int32 i; int32 i, j;
int16 c;
t_stat r; t_stat r;
if (sim_is_active (&cdr_unit)) { /* busy? */ if (sim_is_active (&cdr_unit)) { /* busy? */
sim_cancel (&cdr_unit); /* cancel */ sim_cancel (&cdr_unit); /* cancel */
if (r = cdr_svc (&cdr_unit)) return r; } /* process */ if (r = cdr_svc (&cdr_unit)) return r; /* process */
}
if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */ ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */
for (i = 0; i < CBUFSIZE; i++) rbuf[i] = 0; /* clear buffer */ for (i = 0; i < 2 * CBUFSIZE; i++) rbuf[i] = 0; /* clear extended buf */
fgets (rbuf, CBUFSIZE, cdr_unit.fileref); /* read card */ fgets (rbuf, (mod == BCD_C)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */
cdr_unit.fileref);
if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */ if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */
if (ferror (cdr_unit.fileref)) { /* error? */ if (ferror (cdr_unit.fileref)) { /* error? */
perror ("Card reader I/O error"); perror ("Card reader I/O error");
@ -162,9 +167,28 @@ if (ssa) { /* if last cd on */
getc (cdr_unit.fileref); /* see if more */ getc (cdr_unit.fileref); /* see if more */
if (feof (cdr_unit.fileref)) ind[IN_LST] = 1; /* eof? set flag */ if (feof (cdr_unit.fileref)) ind[IN_LST] = 1; /* eof? set flag */
fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); } fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); }
for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */ if (mod == BCD_C) { /* column binary */
rbuf[i] = ascii_to_bcd[rbuf[i]]; for (i = 0; i < 2 * CDR_WIDTH; i++) /* cvt to BCD */
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | rbuf[i]; } rbuf[i] = ascii_to_bcd[rbuf[i]];
for (i = 0; i < CDR_WIDTH; i++) {
M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | rbuf[i];
M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | rbuf[CDR_WIDTH + i];
c = (rbuf[i] << 6) | rbuf[CDR_WIDTH + i];
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | 077;
for (j = 0; j < 64; j++) { /* look for char */
if (c == colbin[j]) {
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | j;
break;
} /* end if */
} /* end for j */
} /* end for i */
} /* end if col bin */
else { /* normal read */
for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */
rbuf[i] = ascii_to_bcd[rbuf[i]];
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | rbuf[i];
}
}
M[CDR_BUF - 1] = 060; /* mem mark */ M[CDR_BUF - 1] = 060; /* mem mark */
sim_activate (&cdr_unit, cdr_unit.wait); /* activate */ sim_activate (&cdr_unit, cdr_unit.wait); /* activate */
return SCPE_OK; return SCPE_OK;
@ -199,13 +223,13 @@ return SCPE_OK;
/* Card punch routine /* Card punch routine
Modifiers have been checked by the caller Modifiers have been checked by the caller
No modifiers are recognized (column binary is not implemented) C modifier is recognized (column binary is implemented)
*/ */
t_stat punch_card (int32 ilnt, int32 mod) t_stat punch_card (int32 ilnt, int32 mod)
{ {
int32 i; int32 i;
static char pbuf[CDP_WIDTH + 1]; /* + null */ static char pbuf[(2 * CDP_WIDTH) + 1]; /* + null */
UNIT *uptr; UNIT *uptr;
if (s8sel) uptr = &stack_unit[2]; /* stack 8? */ if (s8sel) uptr = &stack_unit[2]; /* stack 8? */
@ -215,9 +239,22 @@ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */ ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */
M[CDP_BUF - 1] = 012; /* set prev loc */ M[CDP_BUF - 1] = 012; /* set prev loc */
for (i = 0; i < CDP_WIDTH; i++) pbuf[i] = bcd_to_ascii[M[CDP_BUF + i] & CHAR]; if (mod == BCD_C) { /* column binary */
for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) pbuf[i] = 0; for (i = 0; i < CDP_WIDTH; i++) {
pbuf[CDP_WIDTH] = 0; /* trailing null */ pbuf[i] = bcd_to_ascii[M[CD_CBUF1 + i] & CHAR];
pbuf[i + CDP_WIDTH] = bcd_to_ascii[M[CD_CBUF2 + i] & CHAR];
}
for (i = 2 * CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--)
pbuf[i] = 0;
pbuf[2 * CDP_WIDTH] = 0; /* trailing null */
}
else { /* normal */
for (i = 0; i < CDP_WIDTH; i++)
pbuf[i] = bcd_to_ascii[M[CDP_BUF + i] & CHAR];
for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--)
pbuf[i] = 0;
pbuf[CDP_WIDTH] = 0; /* trailing null */
}
fputs (pbuf, uptr->fileref); /* output card */ fputs (pbuf, uptr->fileref); /* output card */
fputc ('\n', uptr->fileref); /* plus new line */ fputc ('\n', uptr->fileref); /* plus new line */
if (ferror (uptr->fileref)) { /* error? */ if (ferror (uptr->fileref)) { /* error? */

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
14-Nov-04 WVS Added column binary support, debug support
06-Nov-04 RMS Added instruction history
12-Jul-03 RMS Moved ASCII/BCD tables to included file 12-Jul-03 RMS Moved ASCII/BCD tables to included file
Revised fetch to model hardware Revised fetch to model hardware
Removed length checking in fetch phase Removed length checking in fetch phase
@ -123,6 +125,13 @@
#define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_IS #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_IS
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
uint16 is;
uint16 ilnt;
uint8 inst[MAX_L]; };
/* These macros validate addresses. If an addresses error is detected, /* These macros validate addresses. If an addresses error is detected,
they return an error status to the caller. These macros should only they return an error status to the caller. These macros should only
be used in a routine that returns a t_stat value. be used in a routine that returns a t_stat value.
@ -162,13 +171,22 @@ int32 ind[64] = { 0 }; /* indicators */
int32 ssa = 1; /* sense switch A */ int32 ssa = 1; /* sense switch A */
int32 prchk = 0; /* process check stop */ int32 prchk = 0; /* process check stop */
int32 iochk = 0; /* I/O check stop */ int32 iochk = 0; /* I/O check stop */
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
extern int32 sim_int_char; extern int32 sim_int_char;
extern int32 sim_emax;
extern t_value *sim_eval;
extern FILE *sim_deb;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ 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_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_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr); t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
int32 store_addr_h (int32 addr); int32 store_addr_h (int32 addr);
int32 store_addr_t (int32 addr); int32 store_addr_t (int32 addr);
int32 store_addr_u (int32 addr); int32 store_addr_u (int32 addr);
@ -188,6 +206,7 @@ extern t_stat mt_io (int32 unit, int32 flag, int32 mod);
extern t_stat dp_io (int32 fnc, int32 flag, int32 mod); extern t_stat dp_io (int32 fnc, int32 flag, int32 mod);
extern t_stat mt_func (int32 unit, int32 mod); extern t_stat mt_func (int32 unit, int32 mod);
extern t_stat sim_activate (UNIT *uptr, int32 delay); extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw);
/* CPU data structures /* CPU data structures
@ -246,13 +265,16 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 8000, NULL, "8K", &cpu_set_size }, { UNIT_MSIZE, 8000, NULL, "8K", &cpu_set_size },
{ UNIT_MSIZE, 12000, NULL, "12K", &cpu_set_size }, { UNIT_MSIZE, 12000, NULL, "12K", &cpu_set_size },
{ UNIT_MSIZE, 16000, NULL, "16K", &cpu_set_size }, { UNIT_MSIZE, 16000, NULL, "16K", &cpu_set_size },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
DEVICE cpu_dev = { DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod, "CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 10, 14, 1, 8, 7, 1, 10, 14, 1, 8, 7,
&cpu_ex, &cpu_dep, &cpu_reset, &cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL }; NULL, NULL, NULL,
NULL, DEV_DEBUG };
/* Tables */ /* Tables */
@ -431,6 +453,8 @@ static const int32 cry_table[100] = {
/* Legal modifier tables */ /* Legal modifier tables */
static const int32 r_mod[] = { BCD_C, -1 };
static const int32 p_mod[] = { BCD_C, -1 };
static const int32 w_mod[] = { BCD_S, BCD_SQUARE, -1 }; static const int32 w_mod[] = { BCD_S, BCD_SQUARE, -1 };
static const int32 ss_mod[] = { 1, 2, 4, 8, -1 }; static const int32 ss_mod[] = { 1, 2, 4, 8, -1 };
static const int32 mtf_mod[] = { BCD_B, BCD_E, BCD_M, BCD_R, BCD_U, -1 }; static const int32 mtf_mod[] = { BCD_B, BCD_E, BCD_M, BCD_R, BCD_U, -1 };
@ -440,7 +464,7 @@ t_stat sim_instr (void)
extern int32 sim_interval; extern int32 sim_interval;
int32 IS, ilnt, flags; int32 IS, ilnt, flags;
int32 op, xa, t, wm, ioind, dev, unit; int32 op, xa, t, wm, ioind, dev, unit;
int32 a, b, i, asave, bsave; int32 a, b, i, k, asave, bsave;
int32 carry, lowprd, sign, ps; int32 carry, lowprd, sign, ps;
int32 quo, ahigh, qs; int32 quo, ahigh, qs;
int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal; int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal;
@ -568,12 +592,30 @@ while (((t = M[IS]) & WM) == 0) { /* I-8: repeats until WM */
PP (IS); } PP (IS); }
CHECK_LENGTH: CHECK_LENGTH:
if ((flags & BREQ) && ADDR_ERR (BS)) { /* valid B? */
reason = STOP_INVB;
break; }
if ((flags & AREQ) && ADDR_ERR (AS)) { /* valid A? */
reason = STOP_INVA;
break; }
ilnt = IS - saved_IS; /* get lnt */ ilnt = IS - saved_IS; /* get lnt */
//if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */ if (hst_lnt) { /* history enabled? */
// ((flags & HNOP) == 0)) reason = STOP_INVL; hst_p = (hst_p + 1); /* next entry */
if ((flags & BREQ) && ADDR_ERR (BS)) reason = STOP_INVB; /* valid A? */ if (hst_p >= hst_lnt) hst_p = 0;
if ((flags & AREQ) && ADDR_ERR (AS)) reason = STOP_INVA; /* valid B? */ hst[hst_p].is = saved_IS; /* save IS */
if (reason) break; /* error in fetch? */ hst[hst_p].ilnt = ilnt;
for (i = 0; (i < MAX_L) && (i < ilnt); i++)
hst[hst_p].inst[i] = M[saved_IS + i];
}
if (DEBUG_PRS (cpu_dev)) {
fprint_val (sim_deb, saved_IS, 10, 5, PV_RSPC);
fprintf (sim_deb, ": " );
for (i = 0; i < sim_emax; i++) sim_eval[i] = 0;
for (i = 0, k = saved_IS; i < sim_emax; i++, k++) {
if (cpu_ex (&sim_eval[i], k, &cpu_unit, 0) != SCPE_OK) break; }
fprint_sym (sim_deb, saved_IS, sim_eval, &cpu_unit, SWMASK('M'));
fprintf (sim_deb, "\n" );
}
switch (op) { /* case on opcode */ switch (op) { /* case on opcode */
/* Move/load character instructions A check B check /* Move/load character instructions A check B check
@ -858,7 +900,7 @@ case OP_C: /* compare */
*/ */
case OP_R: /* read */ case OP_R: /* read */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */ if (reason = iomod (ilnt, D, r_mod)) break; /* valid modifier? */
reason = read_card (ilnt, D); /* read card */ reason = read_card (ilnt, D); /* read card */
BS = CDR_BUF + CDR_WIDTH; BS = CDR_BUF + CDR_WIDTH;
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */ if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
@ -872,7 +914,7 @@ case OP_W: /* write */
break; break;
case OP_P: /* punch */ case OP_P: /* punch */
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */ if (reason = iomod (ilnt, D, p_mod)) break; /* valid modifier? */
reason = punch_card (ilnt, D); /* punch card */ reason = punch_card (ilnt, D); /* punch card */
BS = CDP_BUF + CDP_WIDTH; BS = CDP_BUF + CDP_WIDTH;
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */ if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
@ -1561,3 +1603,66 @@ if (MEMSIZE > 4000) cpu_unit.flags = cpu_unit.flags | MA;
else cpu_unit.flags = cpu_unit.flags & ~MA; else cpu_unit.flags = cpu_unit.flags & ~MA;
return SCPE_OK; return SCPE_OK;
} }
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].ilnt = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, k, di, lnt;
char *cptr = (char *) desc;
t_value sim_eval[MAX_L + 1];
t_stat r;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "IS IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->ilnt) { /* instruction? */
fprintf (st, "%05d ", h->is);
for (i = 0; i < h->ilnt; i++)
sim_eval[i] = h->inst[i];
sim_eval[h->ilnt] = WM;
if ((fprint_sym (st, h->is, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) {
fprintf (st, "(undefined)");
for (i = 0; i < h->ilnt; i++)
fprintf (st, "% 02o", h->inst[i]);
}
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -20,7 +20,8 @@
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 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 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 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. in this Software without prior written authorization from Robert M Supnik.
*/ */
@ -47,11 +48,24 @@ const char ascii_to_bcd[128] = {
/* BCD to ASCII conversion - also the "full" print chain */ /* BCD to ASCII conversion - also the "full" print chain */
char bcd_to_ascii[64] = { char bcd_to_ascii[64] = {
' ', '1', '2', '3', '4', '5', '6', '7', ' ', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '#', '@', ':', '>', '(', '8', '9', '0', '#', '@', ':', '>', '(',
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X', '^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '\'', ',', '%', '=', '\\', '+', 'Y', 'Z', '\'', ',', '%', '=', '\\', '+',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '!', '$', '*', ']', ';', '_', 'Q', 'R', '!', '$', '*', ']', ';', '_',
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '?', '.', ')', '[', '<', '"' }; 'H', 'I', '?', '.', ')', '[', '<', '"' };
/* Column binary codes for valid punch combinations
High-order six bits are rows 12-3, low-order six bits are rows 4-9 */
int16 colbin[64] = {
00000, 00400, 00200, 00100, 00040, 00020, 00010, 00004,
00002, 00001, 01000, 00102, 00042, 00022, 00012, 00006,
07777, 01400, 01200, 01100, 01040, 01020, 01010, 01004,
01002, 01001, 01202, 01102, 01042, 01022, 01012, 01006,
02000, 02400, 02200, 02100, 02040, 02020, 02010, 02004,
02002, 02001, 03000, 02102, 02042, 02022, 02012, 02006,
04000, 04400, 04200, 04100, 04040, 04020, 04010, 04004,
04002, 04001, 05000, 04102, 04042, 04022, 04012, 04006 };

View file

@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
14-Nov-04 RMS Added column binary support
27-Oct-04 RMS Added maximum instruction length
16-Mar-03 RMS Fixed mnemonic for MCS 16-Mar-03 RMS Fixed mnemonic for MCS
03-Jun-02 RMS Added 1311 support 03-Jun-02 RMS Added 1311 support
14-Apr-99 RMS Converted t_addr to unsigned 14-Apr-99 RMS Converted t_addr to unsigned
@ -76,6 +78,8 @@
#define CDR_WIDTH 80 /* card rdr width */ #define CDR_WIDTH 80 /* card rdr width */
#define CDP_BUF 101 /* card punch buffer */ #define CDP_BUF 101 /* card punch buffer */
#define CDP_WIDTH 80 /* card punch width */ #define CDP_WIDTH 80 /* card punch width */
#define CD_CBUF1 401 /* r/p col bin buf 12-3 */
#define CD_CBUF2 501 /* r/p col bin buf 4-9 */
#define LPT_BUF 201 /* line print buffer */ #define LPT_BUF 201 /* line print buffer */
#define LPT_WIDTH 132 /* line print width */ #define LPT_WIDTH 132 /* line print width */
#define CCT_LNT 132 /* car ctrl length */ #define CCT_LNT 132 /* car ctrl length */
@ -110,6 +114,7 @@
#define L5 0010 /* 5: op aaa d */ #define L5 0010 /* 5: op aaa d */
#define L7 0020 /* 7: op aaa bbb */ #define L7 0020 /* 7: op aaa bbb */
#define L8 0040 /* 8: op aaa bbb d */ #define L8 0040 /* 8: op aaa bbb d */
#define MAX_L 8 /* max length */
/* CPU options, stored in cpu_unit.flags */ /* CPU options, stored in cpu_unit.flags */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: IBM 1401 Simulator Usage Subj: IBM 1401 Simulator Usage
Date: 15-Feb-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -174,6 +174,17 @@ interrupt system.
most recent IS change first most recent IS change first
WRU 8 interrupt character WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 1402 Card Reader/Punch (CDR, CDP, STKR) 2.2 1402 Card Reader/Punch (CDR, CDP, STKR)
The IBM 1402 card/reader punch is simulated as three independent devices: The IBM 1402 card/reader punch is simulated as three independent devices:
@ -314,7 +325,7 @@ pack options include the ability to enable address writing (formatting).
SET DPn ADDROFF set unit n address enable off SET DPn ADDROFF set unit n address enable off
SET DPn ADDRON set unit n address enable on SET DPn ADDRON set unit n address enable on
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
Unlike most simulated disks, the 1311 includes explicit representation Unlike most simulated disks, the 1311 includes explicit representation
for sector addresses. This is to support non-standard formats, such as for sector addresses. This is to support non-standard formats, such as
@ -367,7 +378,7 @@ or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. The magnetic tape simulator Units can also be set ENABLED or DISABLED. The magnetic tape simulator
supports the BOOT command. BOOT MT reads the first record off tape, supports the BOOT command. BOOT MT reads the first record off tape,
starting at location 1, and then branches to it. starting at location 1, and then branches to it.

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
14-Nov-04 WVS Added data printout support
16-Mar-03 RMS Fixed mnemonic for MCS 16-Mar-03 RMS Fixed mnemonic for MCS
03-Jun-02 RMS Added 1311 support 03-Jun-02 RMS Added 1311 support
18-May-02 RMS Added -D feature from Van Snyder 18-May-02 RMS Added -D feature from Van Snyder
@ -157,7 +158,7 @@ return SCPE_OK;
const char *opcode[64] = { const char *opcode[64] = {
NULL, "R", "W", "WR", "P", "RP", "WP", "WRP", NULL, "R", "W", "WR", "P", "RP", "WP", "WRP",
"RF", "WF", NULL, "MA", "MUL", NULL, NULL, NULL, "SRF", "SPF", NULL, "MA", "MUL", NULL, NULL, NULL,
NULL, "CS", "S", NULL, "MTF", "BWZ", "BBE", NULL, NULL, "CS", "S", NULL, "MTF", "BWZ", "BBE", NULL,
"MZ", "MCS", NULL, "SWM", "DIV", NULL, NULL, NULL, "MZ", "MCS", NULL, "SWM", "DIV", NULL, NULL, NULL,
NULL, NULL, "SS", "LCA", "MCW", "NOP", NULL, "MCM", NULL, NULL, "SS", "LCA", "MCW", "NOP", NULL, "MCM",
@ -180,6 +181,21 @@ else fprintf (of, " %d", addr);
return; return;
} }
/* Print unknown opcode as data */
t_stat dcw (FILE *of, int32 op, t_value *val)
{
int32 i;
fprintf (of, "DCW @%c", bcd_to_ascii[op]); /* assume it's data */
for (i = 1; i < sim_emax; i++) {
if (val[i] & WM) break;
fprintf (of, "%c", bcd_to_ascii[val[i]]);
}
fprintf (of, "@");
return -(i - 1); /* return # chars */
}
/* Symbolic decode /* Symbolic decode
Inputs: Inputs:
@ -224,13 +240,14 @@ if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;
if ((val[0] & WM) == 0) return STOP_NOWM; /* WM under op? */ if ((val[0] & WM) == 0) return STOP_NOWM; /* WM under op? */
op = val[0]& CHAR; /* isolate op */ op = val[0]& CHAR; /* isolate op */
if (opcode[op] == NULL) return dcw (of, op, val); /* invalid op */
flags = op_table[op]; /* get flags */ flags = op_table[op]; /* get flags */
for (ilnt = 1; ilnt < sim_emax; ilnt++) if (val[ilnt] & WM) break; for (ilnt = 1; ilnt < sim_emax; ilnt++) if (val[ilnt] & WM) break;
if ((flags & (NOWM | HNOP)) && (ilnt > 7)) ilnt = 7; /* cs, swm, h, nop? */ if ((flags & (NOWM | HNOP)) && (ilnt > 7)) ilnt = 7; /* cs, swm, h, nop? */
else if ((op == OP_B) && (ilnt > 4) && (val[4] == BCD_BLANK)) ilnt = 4; else if ((op == OP_B) && (ilnt > 4) && (val[4] == BCD_BLANK)) ilnt = 4;
else if ((ilnt > 8) && (op != OP_NOP)) ilnt = 8; /* cap length */ else if ((ilnt > 8) && (op != OP_NOP)) ilnt = 8; /* cap length */
if (((flags & len_table[ilnt]) == 0) && /* valid lnt, */ if (((flags & len_table[ilnt]) == 0) && /* invalid lnt, */
((op != OP_NOP) == 0)) return STOP_INVL; /* nop? */ (op != OP_NOP)) return dcw (of, op, val); /* not nop? */
fprintf (of, "%s",opcode[op]); /* print opcode */ fprintf (of, "%s",opcode[op]); /* print opcode */
if (ilnt > 2) { /* A address? */ if (ilnt > 2) { /* A address? */
if (((flags & IO) || (op == OP_NOP)) && (val[1] == BCD_PERCNT)) if (((flags & IO) || (op == OP_NOP)) && (val[1] == BCD_PERCNT))

View file

@ -26,6 +26,7 @@
This CPU module incorporates code and comments from the 1620 simulator by This CPU module incorporates code and comments from the 1620 simulator by
Geoff Kuenning, with his permission. Geoff Kuenning, with his permission.
07-Nov-04 RMS Added instruction history
26-Mar-04 RMS Fixed warnings with -std=c99 26-Mar-04 RMS Fixed warnings with -std=c99
02-Nov-03 RMS Fixed bug in branch digit (found by Dave Babcock) 02-Nov-03 RMS Fixed bug in branch digit (found by Dave Babcock)
21-Aug-03 RMS Fixed bug in immediate index add (found by Michael Short) 21-Aug-03 RMS Fixed bug in immediate index add (found by Michael Short)
@ -98,6 +99,14 @@
#define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_PC #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_PC
#define HIST_PC 0x40000000
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
uint16 vld;
uint16 pc;
uint8 inst[INST_LEN]; };
uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */
uint32 saved_PC = 0; /* saved PC */ uint32 saved_PC = 0; /* saved PC */
uint32 IR2 = 1; /* inst reg 2 */ uint32 IR2 = 1; /* inst reg 2 */
@ -113,6 +122,9 @@ int32 ind_max = 16; /* iadr nest limit */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */ int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
uint8 ind[NUM_IND] = { 0 }; /* indicators */ uint8 ind[NUM_IND] = { 0 }; /* indicators */
extern int32 sim_int_char; extern int32 sim_int_char;
@ -129,6 +141,8 @@ t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
int32 get_2d (uint32 ad); int32 get_2d (uint32 ad);
t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *addr); t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *addr);
@ -228,6 +242,8 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 60000, NULL, "60K", &cpu_set_size }, { UNIT_MSIZE, 60000, NULL, "60K", &cpu_set_size },
{ UNIT_MSIZE, 0, NULL, "SAVE", &cpu_set_save }, { UNIT_MSIZE, 0, NULL, "SAVE", &cpu_set_save },
{ UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table }, { UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
DEVICE cpu_dev = { DEVICE cpu_dev = {
@ -484,6 +500,16 @@ if (flags & (IF_VQA | IF_4QA | IF_NQX)) { /* need Q? */
reason = reason + (STOP_INVQDG - STOP_INVPDG); reason = reason + (STOP_INVQDG - STOP_INVPDG);
break; } } break; } }
else if (flags & IF_IMM) QAR = qla; /* immediate? */ else if (flags & IF_IMM) QAR = qla; /* immediate? */
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].vld = 1;
hst[hst_p].pc = PC;
for (i = 0; i < INST_LEN; i++)
hst[hst_p].inst[i] = M[(PC + i) % MEMSIZE];
}
PC = PC + INST_LEN; /* advance PC */ PC = PC + INST_LEN; /* advance PC */
switch (op) { /* case on op */ switch (op) { /* case on op */
@ -1884,3 +1910,65 @@ if (((cpu_unit.flags & IF_MII) == 0) || val) { /* set add table */
M[ADD_TABLE + i] = std_add_table[i]; } M[ADD_TABLE + i] = std_add_table[i]; }
return SCPE_OK; return SCPE_OK;
} }
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].vld = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, k, di, lnt;
char *cptr = (char *) desc;
t_value sim_eval[INST_LEN];
t_stat r;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->vld) { /* instruction? */
fprintf (st, "%05d ", h->pc);
for (i = 0; i < INST_LEN; i++)
sim_eval[i] = h->inst[i];
if ((fprint_sym (st, h->pc, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) {
fprintf (st, "(undefined)");
for (i = 0; i < INST_LEN; i++)
fprintf (st, "% 02X", h->inst[i]);
}
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: IBM 1620 Simulator Usage Subj: IBM 1620 Simulator Usage
Date: 15-Feb-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -188,6 +188,17 @@ interrupt system.
most recent IR1 change first most recent IR1 change first
WRU 8 interrupt character WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 Console Typewriter (TTY) 2.2 Console Typewriter (TTY)
The console typewriter (TTY) is a half-duplex console. The typewriter The console typewriter (TTY) is a half-duplex console. The typewriter
@ -361,7 +372,7 @@ pack options include the ability to enable address writing (formatting).
SET DPn ADDROFF set unit n address enable off SET DPn ADDROFF set unit n address enable off
SET DPn ADDRON set unit n address enable on SET DPn ADDRON set unit n address enable on
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
Unlike most simulated disks, the 1311 includes explicit representation Unlike most simulated disks, the 1311 includes explicit representation
for sector addresses. This is to support non-standard formats, such as for sector addresses. This is to support non-standard formats, such as

View file

@ -219,8 +219,8 @@ return STOP_RWRAP;
t_stat tti_rnum (int8 *c) t_stat tti_rnum (int8 *c)
{ {
int8 flg = 0; int8 raw, flg = 0;
char *cp, raw; char *cp;
t_stat r; t_stat r;
*c = -1; /* no char yet */ *c = -1; /* no char yet */
@ -240,7 +240,7 @@ return SCPE_OK;
t_stat tti_ralp (int8 *c) t_stat tti_ralp (int8 *c)
{ {
char raw; int8 raw;
t_stat r; t_stat r;
*c = -1; /* no char yet */ *c = -1; /* no char yet */

View file

@ -75,7 +75,8 @@ BSC32_SBRS= \
$(INTDIR)/ibm1130_fmt.sbr \ $(INTDIR)/ibm1130_fmt.sbr \
$(INTDIR)/sim_console.sbr \ $(INTDIR)/sim_console.sbr \
$(INTDIR)/sim_fio.sbr \ $(INTDIR)/sim_fio.sbr \
$(INTDIR)/sim_timer.sbr $(INTDIR)/sim_timer.sbr \
$(INTDIR)/ibm1130_ptrp.sbr
$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<< $(BSC32) @<<
@ -105,7 +106,8 @@ LINK32_OBJS= \
$(INTDIR)/ibm1130_fmt.obj \ $(INTDIR)/ibm1130_fmt.obj \
$(INTDIR)/sim_console.obj \ $(INTDIR)/sim_console.obj \
$(INTDIR)/sim_fio.obj \ $(INTDIR)/sim_fio.obj \
$(INTDIR)/sim_timer.obj $(INTDIR)/sim_timer.obj \
$(INTDIR)/ibm1130_ptrp.obj
$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<< $(LINK32) @<<
@ -158,7 +160,8 @@ BSC32_SBRS= \
$(INTDIR)/ibm1130_fmt.sbr \ $(INTDIR)/ibm1130_fmt.sbr \
$(INTDIR)/sim_console.sbr \ $(INTDIR)/sim_console.sbr \
$(INTDIR)/sim_fio.sbr \ $(INTDIR)/sim_fio.sbr \
$(INTDIR)/sim_timer.sbr $(INTDIR)/sim_timer.sbr \
$(INTDIR)/ibm1130_ptrp.sbr
$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
$(BSC32) @<< $(BSC32) @<<
@ -189,7 +192,8 @@ LINK32_OBJS= \
$(INTDIR)/ibm1130_fmt.obj \ $(INTDIR)/ibm1130_fmt.obj \
$(INTDIR)/sim_console.obj \ $(INTDIR)/sim_console.obj \
$(INTDIR)/sim_fio.obj \ $(INTDIR)/sim_fio.obj \
$(INTDIR)/sim_timer.obj $(INTDIR)/sim_timer.obj \
$(INTDIR)/ibm1130_ptrp.obj
$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<< $(LINK32) @<<
@ -377,10 +381,10 @@ DEP_SIM_C=\
\pdp11\supnik\sim_console.h\ \pdp11\supnik\sim_console.h\
\pdp11\supnik\sim_timer.h\ \pdp11\supnik\sim_timer.h\
\pdp11\supnik\sim_fio.h\ \pdp11\supnik\sim_fio.h\
d:\progra~1\micros~1\include\winsock2.h\ D:\PROGRA~1\MICROS~1\INCLUDE\WinSock2.h\
\MSVC20\INCLUDE\sys\TYPES.H\ \MSVC20\INCLUDE\sys\TYPES.H\
d:\progra~1\micros~1\include\qos.h\ D:\PROGRA~1\MICROS~1\INCLUDE\Qos.h\
d:\winddk\2600\inc\wxp\guiddef.h D:\WINDDK\2600\inc\wxp\guiddef.h
$(INTDIR)/sim_console.obj : $(SOURCE) $(DEP_SIM_C) $(INTDIR) $(INTDIR)/sim_console.obj : $(SOURCE) $(DEP_SIM_C) $(INTDIR)
$(CPP) $(CPP_PROJ) $(SOURCE) $(CPP) $(CPP_PROJ) $(SOURCE)
@ -392,7 +396,7 @@ $(INTDIR)/sim_console.obj : $(SOURCE) $(DEP_SIM_C) $(INTDIR)
SOURCE=\pdp11\supnik\sim_fio.c SOURCE=\pdp11\supnik\sim_fio.c
DEP_SIM_F=\ DEP_SIM_F=\
..\sim_defs.h\ ..\sim_defs.h\
d:\progra~1\micros~1\include\BASETSD.H\ D:\PROGRA~1\MICROS~1\INCLUDE\BaseTsd.h\
\pdp11\supnik\scp.h\ \pdp11\supnik\scp.h\
\pdp11\supnik\sim_console.h\ \pdp11\supnik\sim_console.h\
\pdp11\supnik\sim_timer.h\ \pdp11\supnik\sim_timer.h\
@ -408,7 +412,7 @@ $(INTDIR)/sim_fio.obj : $(SOURCE) $(DEP_SIM_F) $(INTDIR)
SOURCE=\pdp11\supnik\sim_timer.c SOURCE=\pdp11\supnik\sim_timer.c
DEP_SIM_TI=\ DEP_SIM_TI=\
..\sim_defs.h\ ..\sim_defs.h\
d:\progra~1\micros~1\include\BASETSD.H\ D:\PROGRA~1\MICROS~1\INCLUDE\BaseTsd.h\
\pdp11\supnik\scp.h\ \pdp11\supnik\scp.h\
\pdp11\supnik\sim_console.h\ \pdp11\supnik\sim_console.h\
\pdp11\supnik\sim_timer.h\ \pdp11\supnik\sim_timer.h\
@ -417,6 +421,14 @@ DEP_SIM_TI=\
$(INTDIR)/sim_timer.obj : $(SOURCE) $(DEP_SIM_TI) $(INTDIR) $(INTDIR)/sim_timer.obj : $(SOURCE) $(DEP_SIM_TI) $(INTDIR)
$(CPP) $(CPP_PROJ) $(SOURCE) $(CPP) $(CPP_PROJ) $(SOURCE)
# End Source File
################################################################################
# Begin Source File
SOURCE=.\ibm1130_ptrp.c
$(INTDIR)/ibm1130_ptrp.obj : $(SOURCE) $(INTDIR)
# End Source File # End Source File
# End Group # End Group
# End Project # End Project

View file

@ -18,6 +18,8 @@
18-Mar-03 BLK Fixed bug in divide instruction; didn't work with negative values 18-Mar-03 BLK Fixed bug in divide instruction; didn't work with negative values
23-Jul-03 BLK Prevented tti polling in CGI mode 23-Jul-03 BLK Prevented tti polling in CGI mode
24-Nov-03 BLK Fixed carry bit error in subtract and subtract double, found by Bob Flanders 24-Nov-03 BLK Fixed carry bit error in subtract and subtract double, found by Bob Flanders
20-Oct-04 BLK Changed "(unsigned int32)" to "(uint32)" to accomodate improved definitions of simh types
Also commented out my echo command as it's now a standard simh command
The register state for the IBM 1130 CPU is: The register state for the IBM 1130 CPU is:
@ -127,6 +129,7 @@
#define UPDATE_BY_TIMER #define UPDATE_BY_TIMER
#define ENABLE_BACKTRACE #define ENABLE_BACKTRACE
#define CGI_SUPPORT #define CGI_SUPPORT
// #define USE_MY_ECHO_CMD /* simh now has echo command built in */
static void cgi_start(void); static void cgi_start(void);
static void cgi_stop(t_stat reason); static void cgi_stop(t_stat reason);
@ -888,7 +891,7 @@ t_stat sim_instr (void)
ACC = (dst >> 16) & 0xFFFF; ACC = (dst >> 16) & 0xFFFF;
EXT = dst & 0xFFFF; EXT = dst & 0xFFFF;
C = (unsigned int32) dst < (unsigned int32) src; C = (uint32) dst < (uint32) src;
if (! V) if (! V)
V = DWSIGN_BIT((~src ^ src2) & (src ^ dst)); V = DWSIGN_BIT((~src ^ src2) & (src ^ dst));
break; break;
@ -910,7 +913,7 @@ t_stat sim_instr (void)
ACC = (dst >> 16) & 0xFFFF; ACC = (dst >> 16) & 0xFFFF;
EXT = dst & 0xFFFF; EXT = dst & 0xFFFF;
C = (unsigned int32) src < (unsigned int32) src2; C = (uint32) src < (uint32) src2;
if (! V) if (! V)
V = DWSIGN_BIT((src ^ src2) & (src ^ dst)); V = DWSIGN_BIT((src ^ src2) & (src ^ dst));
break; break;
@ -1280,6 +1283,7 @@ t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int ar
return SCPE_OK; return SCPE_OK;
} }
#ifdef USE_MY_ECHO_CMD
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* echo_cmd - just echo the command line * echo_cmd - just echo the command line
* ------------------------------------------------------------------------ */ * ------------------------------------------------------------------------ */
@ -1289,6 +1293,7 @@ static t_stat echo_cmd (int flag, char *cptr)
printf("%s\n", cptr); printf("%s\n", cptr);
return SCPE_OK; return SCPE_OK;
} }
#endif
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* sim_init - initialize simulator upon startup of scp, before reset * sim_init - initialize simulator upon startup of scp, before reset
@ -1319,7 +1324,9 @@ void sim_init (void)
register_cmd("CGI", &cgi_cmd, 0, "cgi run simulator in CGI mode\n"); register_cmd("CGI", &cgi_cmd, 0, "cgi run simulator in CGI mode\n");
#endif #endif
#ifdef USE_MY_ECHO_CMD
register_cmd("ECHO", &echo_cmd, 0, "echo args... echo arguments passed to command\n"); register_cmd("ECHO", &echo_cmd, 0, "echo args... echo arguments passed to command\n");
#endif
} }
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------

View file

@ -18,6 +18,8 @@
* This is not a supported product, but I welcome bug reports and fixes. * This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org * Mail to simh@ibm1130.org
* Update 2004-06-05: Removed "feedcycle" from cr_reset. Reset should not touch the card reader.
* Update 2004-04-12: Changed ascii field of CPCODE to unsigned char, caught a couple * Update 2004-04-12: Changed ascii field of CPCODE to unsigned char, caught a couple
other potential problems with signed characters used as subscript indexes. other potential problems with signed characters used as subscript indexes.
@ -337,6 +339,7 @@ static t_stat cr_reset (DEVICE *dptr);
static t_stat cr_set_code (UNIT *uptr, int32 match, char *cptr, void *desc); static t_stat cr_set_code (UNIT *uptr, int32 match, char *cptr, void *desc);
static t_stat cr_attach (UNIT *uptr, char *cptr); static t_stat cr_attach (UNIT *uptr, char *cptr);
static int32 guess_cr_code (void); static int32 guess_cr_code (void);
static void feedcycle (t_bool load, t_bool punching);
static t_stat cp_reset (DEVICE *dptr); static t_stat cp_reset (DEVICE *dptr);
static t_stat cp_set_code (UNIT *uptr, int32 match, char *cptr, void *desc); static t_stat cp_set_code (UNIT *uptr, int32 match, char *cptr, void *desc);
@ -400,7 +403,7 @@ static int32 cp_count= 0;
#define COLUMN u4 /* column field in unit record */ #define COLUMN u4 /* column field in unit record */
UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE|UNIT_ROABLE, 0) }; UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE|UNIT_ROABLE|UNIT_CR_EMPTY, 0) };
UNIT cp_unit = { UDATA (NULL, UNIT_ATTABLE, 0) }; UNIT cp_unit = { UDATA (NULL, UNIT_ATTABLE, 0) };
MTAB cr_mod[] = { MTAB cr_mod[] = {
@ -916,7 +919,7 @@ t_stat load_cr_boot (int drvno, int switches)
t_stat cr_boot (int unitno, DEVICE *dptr) t_stat cr_boot (int unitno, DEVICE *dptr)
{ {
t_stat rval; t_stat rval;
uint16 buf[80]; // uint16 buf[80];
int i; int i;
if ((rval = reset_all(0)) != SCPE_OK) if ((rval = reset_all(0)) != SCPE_OK)
@ -933,13 +936,15 @@ t_stat cr_boot (int unitno, DEVICE *dptr)
if (cr_unit.fileref == NULL) /* this will happen if no file in deck file can be opened */ if (cr_unit.fileref == NULL) /* this will happen if no file in deck file can be opened */
return SCPE_IOERR; return SCPE_IOERR;
if (fxread(buf, sizeof(buf[0]), 80, cr_unit.fileref) != 80) feedcycle(TRUE, FALSE);
return SCPE_IOERR;
// if (fxread(buf, sizeof(buf[0]), 80, cr_unit.fileref) != 80)
// return SCPE_IOERR;
IAR = 0; /* Program Load sets IAR = 0 */ IAR = 0; /* Program Load sets IAR = 0 */
for (i = 0; i < 80; i++) /* shift 12 bits into 16 */ for (i = 0; i < 80; i++) /* shift 12 bits into 16 */
WriteW(i, (buf[i] & 0xF800) | ((buf[i] & 0x0400) ? 0x00C0 : 0x0000) | ((buf[i] & 0x03F0) >> 4)); WriteW(i, (readstation[i] & 0xF800) | ((readstation[i] & 0x0400) ? 0x00C0 : 0x0000) | ((readstation[i] & 0x03F0) >> 4));
return SCPE_OK; return SCPE_OK;
} }
@ -1422,19 +1427,19 @@ static t_stat cr_reset (DEVICE *dptr)
return SCPE_OK; return SCPE_OK;
} }
SETBIT(cr_unit.flags, UNIT_CR_EMPTY); /* assume hopper empty */ // SETBIT(cr_unit.flags, UNIT_CR_EMPTY); /* assume hopper empty */
//
if (cr_unit.flags & UNIT_ATT) { // if (cr_unit.flags & UNIT_ATT) {
// if (deckfile != NULL) { /* do NOT rewind the deck file */ // if (deckfile != NULL) { /* do NOT rewind the deck file */
// fseek(deckfile, 0, SEEK_SET); // fseek(deckfile, 0, SEEK_SET);
// nextdeck(); // nextdeck();
// } // }
// else // else
// checkdeck(); // checkdeck();
//
if (cr_unit.fileref != NULL) // if (cr_unit.fileref != NULL)
feedcycle(FALSE, FALSE); // feedcycle(FALSE, FALSE);
} // }
return SCPE_OK; return SCPE_OK;
} }

View file

@ -775,7 +775,7 @@ static void tracesector (int iswrite, int nwords, int addr, int sector)
} }
printf("* %04x: %3d /%04x %c %3d.%d ", printf("* %04x: %3d /%04x %c %3d.%d ",
prev_IAR, nwords, addr, iswrite ? '>' : '<', sector/8, sector%8); prev_IAR, nwords, addr, iswrite ? 'W' : 'R', sector/8, sector%8);
if (name == NULL) { // look up sector in SLET if (name == NULL) { // look up sector in SLET
for (i = 0; i < MAXSLET; i++) { for (i = 0; i < MAXSLET; i++) {

View file

@ -46,6 +46,11 @@
#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */ #define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */
#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR) #define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
// I think I had it wrong; Program Load actually does start the processor after
// reading in the card?
#define PROGRAM_LOAD_STARTS_CPU
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Function declarations * Function declarations
* ------------------------------------------------------------------------ */ * ------------------------------------------------------------------------ */
@ -1229,9 +1234,12 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case IDC_PROGRAM_LOAD: case IDC_PROGRAM_LOAD:
if (! running) { /* if card reader is attached to a file, do cold start read of one card */ if (! running) { /* if card reader is attached to a file, do cold start read of one card */
IAR = 0; /* reset IAR */ IAR = 0; /* reset IAR */
// stuff_cmd("boot cr"); #ifdef PROGRAM_LOAD_STARTS_CPU
stuff_cmd("boot cr");
#else
if (cr_boot(0, NULL) != SCPE_OK) /* load boot card */ if (cr_boot(0, NULL) != SCPE_OK) /* load boot card */
remark_cmd("IPL failed"); remark_cmd("IPL failed");
#endif
} }
break; break;

309
Ibm1130/ibm1130_ptrp.c Normal file
View file

@ -0,0 +1,309 @@
/* ibm1130_ptrp.c: IBM 1130 paper tape reader/punch emulation
Based on the SIMH simulator package written by Robert M Supnik
Brian Knittel
Revision History
2004.10.22 - Written.
* (C) Copyright 2004, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*/
#include "ibm1130_defs.h"
/***************************************************************************************
* 1134 Paper Tape Reader device PTR
* 1055 Paper Tape Punch device PTP (shares DSW with PTR)
***************************************************************************************/
#define PTR1134_DSW_READER_RESPONSE 0x4000
#define PTR1134_DSW_PUNCH_RESPONSE 0x1000
#define PTR1134_DSW_READER_BUSY 0x0800
#define PTR1134_DSW_READER_NOT_READY 0x0400
#define PTR1134_DSW_PUNCH_BUSY 0x0200
#define PTR1134_DSW_PUNCH_NOT_READY 0x0100
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
static t_stat ptr_svc (UNIT *uptr);
static t_stat ptr_reset (DEVICE *dptr);
static t_stat ptr_attach (UNIT *uptr, char *cptr);
static t_stat ptr_detach (UNIT *uptr);
static t_stat ptr_boot (int unitno, DEVICE *dptr);
static t_stat ptp_svc (UNIT *uptr);
static t_stat ptp_reset (DEVICE *dptr);
static t_stat ptp_attach (UNIT *uptr, char *cptr);
static t_stat ptp_detach (UNIT *uptr);
static int16 ptr_dsw = 0; /* device status word */
static int32 ptr_wait = 1000; /* character read wait */
static uint8 ptr_char = 0; /* last character read */
static int32 ptp_wait = 1000; /* character punch wait */
UNIT ptr_unit[1] = {
{ UDATA (&ptr_svc, UNIT_ATTABLE, 0) },
};
REG ptr_reg[] = {
{ HRDATA (DSW, ptr_dsw, 16) }, /* device status word */
{ DRDATA (WTIME, ptr_wait, 24), PV_LEFT }, /* character read wait */
{ DRDATA (LASTCHAR, ptr_char, 8), PV_LEFT }, /* last character read */
{ NULL } };
DEVICE ptr_dev = {
"PTR", ptr_unit, ptr_reg, NULL,
1, 16, 16, 1, 16, 16,
NULL, NULL, ptr_reset,
ptr_boot, ptr_attach, ptr_detach};
UNIT ptp_unit[1] = {
{ UDATA (&ptp_svc, UNIT_ATTABLE, 0) },
};
REG ptp_reg[] = {
{ HRDATA (DSW, ptr_dsw, 16) }, /* device status word (this is the same as the reader's!) */
{ DRDATA (WTIME, ptp_wait, 24), PV_LEFT }, /* character punch wait */
{ NULL } };
DEVICE ptp_dev = {
"PTP", ptp_unit, ptp_reg, NULL,
1, 16, 16, 1, 16, 16,
NULL, NULL, ptp_reset,
NULL, ptp_attach, ptp_detach};
/* xio_1134_papertape - XIO command interpreter for the 1134 paper tape reader and 1055 paper tape punch */
void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod)
{
char msg[80];
switch (iocc_func) {
case XIO_READ: /* read: return last character read */
M[iocc_addr & mem_mask] = (uint16) (ptr_char << 8);
break;
case XIO_WRITE: /* write: initiate punch operation */
if ((ptr_dsw & PTR1134_DSW_PUNCH_NOT_READY) == 0 && IS_ONLINE(ptp_unit)) {
putc((M[iocc_addr & mem_mask] >> 8) & 0xFF, ptp_unit->fileref);
ptp_unit->pos++;
}
sim_activate(ptp_unit, ptp_wait); /* schedule interrupt */
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY | PTR1134_DSW_PUNCH_BUSY);
break;
case XIO_SENSE_DEV: /* sense device status */
ACC = ptr_dsw;
if (iocc_mod & 0x01) { /* reset interrupts */
CLRBIT(ptr_dsw, PTR1134_DSW_READER_RESPONSE | PTR1134_DSW_PUNCH_RESPONSE);
CLRBIT(ILSW[4], ILSW_4_1134_TAPE);
}
break;
case XIO_CONTROL: /* control: initiate character read */
sim_activate(ptr_unit, ptr_wait); /* schedule interrupt */
SETBIT(ptr_dsw, PTR1134_DSW_READER_BUSY | PTR1134_DSW_READER_NOT_READY);
break;
default:
sprintf(msg, "Invalid 1134 reader/1055 punch XIO function %x", iocc_func);
xio_error(msg);
}
}
// ptr_svc - emulated timeout - 1134 read operation complete
static t_stat ptr_svc (UNIT *uptr)
{
CLRBIT(ptr_dsw, PTR1134_DSW_READER_BUSY); /* clear reader busy flag */
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* assume at end of file */
if (IS_ONLINE(uptr)) { /* fetch character from file */
ptr_char = getc(uptr->fileref);
uptr->pos++;
if (! feof(uptr->fileref)) /* there's more left */
CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);
}
SETBIT(ptr_dsw, PTR1134_DSW_READER_RESPONSE); /* indicate read complete */
SETBIT(ILSW[4], ILSW_4_1134_TAPE); /* initiate interrupt */
calc_ints();
return SCPE_OK;
}
// ptp_svc - emulated timeout -- 1055 punch operation complete
static t_stat ptp_svc (UNIT *uptr)
{
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_BUSY); /* clear punch busy flag */
if (IS_ONLINE(uptr)) /* update punch ready status */
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);
else
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_RESPONSE); /* indicate punch complete */
SETBIT(ILSW[4], ILSW_4_1134_TAPE); /* initiate interrupt */
calc_ints();
return SCPE_OK;
}
/* ptr_reset - reset emulated paper tape reader */
static t_stat ptr_reset (DEVICE *dptr)
{
sim_cancel(ptr_unit);
CLRBIT(ptr_dsw, PTR1134_DSW_READER_BUSY | PTR1134_DSW_READER_RESPONSE);
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);
if (IS_ONLINE(ptr_unit) && ! feof(ptr_unit->fileref))
CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);
if ((ptr_dsw & PTR1134_DSW_PUNCH_RESPONSE) == 0) { /* punch isn't interrupting either */
CLRBIT(ILSW[4], ILSW_4_1134_TAPE);
calc_ints();
}
return SCPE_OK;
}
/* ptp_reset - reset emulated paper tape punch */
static t_stat ptp_reset (DEVICE *dptr)
{
sim_cancel(ptp_unit);
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_BUSY | PTR1134_DSW_PUNCH_RESPONSE);
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);
if (IS_ONLINE(ptp_unit))
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);
if ((ptr_dsw & PTR1134_DSW_READER_RESPONSE) == 0) { /* reader isn't interrupting either */
CLRBIT(ILSW[4], ILSW_4_1134_TAPE);
calc_ints();
}
return SCPE_OK;
}
/* ptr_attach - attach file to simulated paper tape reader */
static t_stat ptr_attach (UNIT *uptr, char *cptr)
{
t_stat rval;
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* assume failure */
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) /* use standard attach */
return rval;
if ((ptr_dsw & PTR1134_DSW_READER_BUSY) == 0 && ! feof(uptr->fileref))
CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* we're in business */
return SCPE_OK;
}
/* ptr_attach - detach file from simulated paper tape reader */
static t_stat ptr_detach (UNIT *uptr)
{
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY);
return detach_unit(uptr);
}
/* ptr_attach - perform paper tape initial program load */
static t_stat ptr_boot (int unitno, DEVICE *dptr)
{
int ch, nch, val, addr;
t_bool leader = TRUE, start = FALSE;
t_stat rval;
addr = 0;
nch = 0;
val = 0;
for (;;) {
if ((ch = getc(ptr_unit->fileref)) == EOF) {
printf("EOF on paper tape without finding Channel 5 end-of-load mark\n");
break;
}
if (leader) {
if ((ch & 0x7F) == 0x7F) // ignore leading rubouts or "delete" characters
continue;
leader = FALSE; // after first nonrubout, any punch in channel 5 terminates load
}
// this is untested -- not sure of actual byte ordering
val = (val << 4) | (ch & 0x0F); // get next nybble
if (++nch == 4) { // if we now have four nybbles, store the word
M[addr & mem_mask] = (uint16) val;
addr++; // prepare for next word
nch = 0;
val = 0;
}
if (ch & 0x10) { // channel 5 punch terminates load
start = TRUE;
break;
}
}
if (! start) // if we didn't get a valid load, report EOF error
return SCPE_EOF;
if ((rval = reset_all(0)) != SCPE_OK) // force a reset
return rval;
IAR = 0; // start running at address 0
return SCPE_OK;
}
/* ptp_attach - attach file to simulated paper tape punch */
static t_stat ptp_attach (UNIT *uptr, char *cptr)
{
t_stat rval;
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); /* assume failure */
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) /* use standard attach */
return rval;
fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */
uptr->pos = ftell(uptr->fileref);
if ((ptr_dsw & PTR1134_DSW_PUNCH_BUSY) == 0)
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); /* we're in business */
return SCPE_OK;
}
/* ptp_detach - detach file from simulated paper tape punch */
static t_stat ptp_detach (UNIT *uptr)
{
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY);
return detach_unit(uptr);
}

View file

@ -6,6 +6,8 @@
Revision History: Revision History:
2004.10.22 - Removed stub for xio_1134_papertape as it's now a supported device
2003.11.23 - Fixed bug in new routine "quotefix" that made sim crash 2003.11.23 - Fixed bug in new routine "quotefix" that made sim crash
for all non-Windows builds :( for all non-Windows builds :(
@ -90,12 +92,11 @@
static void badio (char *dev) static void badio (char *dev)
{ {
// the real 1130 just ignores attempts to use uninstalled devices. They get tested // the real 1130 just ignores attempts to use uninstalled devices. They get tested
// at times, so it's best to be quiet about this // at times, so it's best to just be quiet about this
// printf("%s I/O is not yet supported", dev); // printf("%s I/O is not yet supported", dev);
// wait_state = WAIT_INVALID_OP;
} }
void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");} // void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");}
void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");} void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");}
void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");} void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");}
void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");} void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");}

View file

@ -27,7 +27,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev; extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev, prt_dev, log_dev; extern DEVICE tti_dev, tto_dev, prt_dev, log_dev;
extern DEVICE gdu_dev, console_dev; extern DEVICE gdu_dev, console_dev;
@ -59,6 +59,8 @@ DEVICE *sim_devices[] = {
&tti_dev, /* console keyboard, selectric printer */ &tti_dev, /* console keyboard, selectric printer */
&tto_dev, &tto_dev,
&prt_dev, /* 1132 printer */ &prt_dev, /* 1132 printer */
&ptr_dev, /* 1134 paper tape reader */
&ptp_dev, /* 1055 paper tape punch */
&console_dev, /* console display (windows GUI) */ &console_dev, /* console display (windows GUI) */
&gdu_dev, /* 2250 display */ &gdu_dev, /* 2250 display */
NULL NULL

View file

@ -59,7 +59,7 @@ ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \
${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \ ${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \
${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \ ${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \
${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c \ ${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c \
${ibm1130D}ibm1130_fmt.c ${ibm1130D}ibm1130_ptrp.c ${ibm1130D}ibm1130_fmt.c
ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \ ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \
ibm1130_defs.h ibm1130_prtwheel.h ibm1130_fmt.h \ ibm1130_defs.h ibm1130_prtwheel.h ibm1130_fmt.h \

View file

@ -9,10 +9,27 @@
* Mail to sim@ibm1130.org * Mail to sim@ibm1130.org
*/ */
#define VERSION "ASM1130 CROSS ASSEMBLER V1.14"
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
// ASM1130 - IBM 1130 Cross Assembler // ASM1130 - IBM 1130 Cross Assembler
// //
// Version // Version
// 1.14 - 2004Oct22 - Fixed problem with BSS complaining about negative
// sizes. This may be a fundamental problem with my using
// 32-bit expressions, but for now, it appears that just
// truncating the BSS size to 16 bits is sufficient to build DMS.
// 1.13 - 2004Jun05 - Fixed sign extension of constants in expressions. Statements
// like LD /FFFF were being assembled incorrectly.
// 1.12 - 2004Jun04 - Made WAIT instruction take a displacement value.
// Doesn't affect operation, but these are used as indicators
// in the IBM one-card diagnostic programs.
// Also -- should mention that the .IPL directive was
// removed some time ago. To create bootable cards,
// use -b flag to create binary output, and post-process the
// binary output with program "mkboot"
// 1.11 - 2004May22 - Added CMP, DCM, and DECS instructions for 1800,
// thanks to Kevin Everets.
// 1.10 - 2003Dec08 - Fixed opcode value for XCH instruction, thanks to // 1.10 - 2003Dec08 - Fixed opcode value for XCH instruction, thanks to
// Roger Simpson. // Roger Simpson.
// 1.09 - 2003Aug03 - Added fxwrite so asm will write little-endian files // 1.09 - 2003Aug03 - Added fxwrite so asm will write little-endian files
@ -91,28 +108,14 @@
// >>> Look for "bug here" though, for things to check out. // >>> Look for "bug here" though, for things to check out.
// //
// Notes: // Notes:
// We assume that the computer on which the assembler runs uses ANSI floating point.
// Also, the assembly of floating point values may be incorrect on non-Intel
// architectures, this needs to be investigated.
//
// org_advanced tells whether * in an expression refers to the address AFTER the // org_advanced tells whether * in an expression refers to the address AFTER the
// instruction (1 or 2 words, depending on length). This is the case for opcodes // instruction (1 or 2 words, depending on length). This is the case for opcodes
// but not all directives. // but not all directives.
// //
// Added special coldstart format directives:
//
// .IPL 1130,XXXXXXXX
// .IPL 1800,XXXXXXXX
//
// (these are not standard IBM)
//
// These directives cause the output file to be written in binary in either 1130 or
// 1800 IPL format. In 1130 format, the index bits are lost and the displacement
// is sign extended. In 1800 format, the data are punched 8 bits at a time into
// two columns per word. If an identifier is not given, data are punched into
// all 80 columns. If an identifier is given, data is punched in columns 0 through
// 72, and the identification XXXXXXXX is punched in columns 73 through 80. (If
// there are multiple output cards the last ident character is incremented). A
// warning is issued if 1130 assembly results in lost bits. These directives
// should be the first in the file as you don't want text and binary mixed in
// the same output file.
//
// Revision History // Revision History
// 16Apr02 1.03 Added sector break, relocation flag output // 16Apr02 1.03 Added sector break, relocation flag output
// 02Apr02 1.02 Fixed bug in BOSC: it CAN be a short instruction. // 02Apr02 1.02 Fixed bug in BOSC: it CAN be a short instruction.
@ -133,7 +136,8 @@
// DEFINITIONS // DEFINITIONS
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
// I have found some IBM source code where @ and ' seem interchangable. // I have found some IBM source code where @ and ' seem interchangable (likely due to the
// use of 026 keypunches).
// Comment out this define to make @ and ' different in symbol names, keep to make equivalent // Comment out this define to make @ and ' different in symbol names, keep to make equivalent
#if defined(VMS) #if defined(VMS)
@ -162,8 +166,6 @@
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
#define VERSION "ASM1130 CROSS ASSEMBLER V1.08"
#define ISTV 0x33 // magic number from DMS R2V12 monitorm symbol @ISTV #define ISTV 0x33 // magic number from DMS R2V12 monitorm symbol @ISTV
#define MAXLITERALS 300 #define MAXLITERALS 300
@ -233,7 +235,7 @@ typedef enum {OUTMODE_LOAD, OUTMODE_1130, OUTMODE_1800, OUTMODE_BINARY} OUTMODE;
// command line syntax // command line syntax
char *usestr = char *usestr =
"Usage: asm1130 [-bpsvwxy] [-o[file]] [-l[file]] [-rN.M] file...\n\n" "Usage: asm1130 [-bpsvwxy8] [-o[file]] [-l[file]] [-rN.M] file...\n\n"
"-b binary (relocatable format) output; default is simulator LOAD format\n" "-b binary (relocatable format) output; default is simulator LOAD format\n"
"-p count passes required; no assembly output is created with this flag" "-p count passes required; no assembly output is created with this flag"
"-s add symbol table to listing\n" "-s add symbol table to listing\n"
@ -244,10 +246,12 @@ char *usestr =
"-y preload system symbol table SYMBOLS.SYS\n" "-y preload system symbol table SYMBOLS.SYS\n"
"-o set output file; default is first input file + .out or .bin\n" "-o set output file; default is first input file + .out or .bin\n"
"-l create listing file; default is first input file + .lst\n" "-l create listing file; default is first input file + .lst\n"
"-r set dms version to VN RM for system SBRK cards"; "-r set dms version to VN RM for system SBRK cards\n"
"-8 enable IBM 1800 instructions"; // (alternately, rename or link executable to asm1800.exe)
BOOL verbose = FALSE; // verbose mode flag BOOL verbose = FALSE; // verbose mode flag
BOOL tabformat = FALSE; // TRUE if tabs were seen in the file BOOL tabformat = FALSE; // TRUE if tabs were seen in the file
BOOL enable_1800 = FALSE; // TRUE if 1800 mode is enabled by flag or executable name
int pass; // current assembler pass (1 or 2) int pass; // current assembler pass (1 or 2)
char curfn[256]; // current input file name char curfn[256]; // current input file name
char progname[8]; // base name of primary input file char progname[8]; // base name of primary input file
@ -349,6 +353,7 @@ int ascii_to_1403_table[128] =
// PROTOTYPES // PROTOTYPES
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
void init (int argc, char **argv);
void bail (char *msg); void bail (char *msg);
void flag (char *arg); void flag (char *arg);
void proc (char *fname); void proc (char *fname);
@ -387,6 +392,7 @@ void bincard_endcard (void);
void handle_sbrk (char *line); void handle_sbrk (char *line);
void bincard_typecard (void); void bincard_typecard (void);
void namecode (unsigned short *words, char *tok); void namecode (unsigned short *words, char *tok);
int signextend (int v);
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
// main routine // main routine
@ -396,9 +402,7 @@ int main (int argc, char **argv)
{ {
int i, sawfile = FALSE; int i, sawfile = FALSE;
for (i = 1; i < argc; i++) // process command line switches init(argc, argv); // initialize, process flags
if (*argv[i] == '-')
flag(argv[i]+1);
startpass(1); // first pass, process files startpass(1); // first pass, process files
@ -460,6 +464,21 @@ int main (int argc, char **argv)
return 0; // all done return 0; // all done
} }
// ---------------------------------------------------------------------------------
// init - initialize assembler, process command line flags
// ---------------------------------------------------------------------------------
void init (int argc, char **argv)
{
int i;
enable_1800 = strstr(argv[0], "1800") != NULL; // if "1800" appears in the executable name, enable 1800 extensions
for (i = 1; i < argc; i++) // process command line switches
if (*argv[i] == '-')
flag(argv[i]+1);
}
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
// flag - process one command line switch // flag - process one command line switch
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -512,6 +531,10 @@ void flag (char *arg)
outmode = OUTMODE_BINARY; outmode = OUTMODE_BINARY;
break; break;
case '8':
enable_1800 = TRUE;
break;
case 'r': case 'r':
if (sscanf(arg, "%d.%d", &major, &minor) != 2) if (sscanf(arg, "%d.%d", &major, &minor) != 2)
bail(usestr); bail(usestr);
@ -1194,6 +1217,7 @@ void coltok (char *c, char *tok, int ifrom, int ito, BOOL condense, char *save)
#define IS_ABS 0x0002 // always uses absolute addressing mode (implied X) #define IS_ABS 0x0002 // always uses absolute addressing mode (implied X)
#define NO_IDX 0x0004 // even with 1 or 2 modifier, this is not really indexed (for STX/LDX) #define NO_IDX 0x0004 // even with 1 or 2 modifier, this is not really indexed (for STX/LDX)
#define NO_ARGS 0x0008 // statement takes no arguments #define NO_ARGS 0x0008 // statement takes no arguments
#define IS_1800 0x0010 // 1800-only directive or instruction, flagged if 1800 mode is not enabled
#define TRAP 0x1000 // debug this instruction #define TRAP 0x1000 // debug this instruction
struct tag_op { // OPCODE TABLE struct tag_op { // OPCODE TABLE
@ -1230,6 +1254,7 @@ void x_bes (struct tag_op *op, char *label, char *mods, char *arg);
void x_bss (struct tag_op *op, char *label, char *mods, char *arg); void x_bss (struct tag_op *op, char *label, char *mods, char *arg);
void x_dc (struct tag_op *op, char *label, char *mods, char *arg); void x_dc (struct tag_op *op, char *label, char *mods, char *arg);
void x_dec (struct tag_op *op, char *label, char *mods, char *arg); void x_dec (struct tag_op *op, char *label, char *mods, char *arg);
void x_decs (struct tag_op *op, char *label, char *mods, char *arg);
void x_ebc (struct tag_op *op, char *label, char *mods, char *arg); void x_ebc (struct tag_op *op, char *label, char *mods, char *arg);
void x_end (struct tag_op *op, char *label, char *mods, char *arg); void x_end (struct tag_op *op, char *label, char *mods, char *arg);
void x_ent (struct tag_op *op, char *label, char *mods, char *arg); void x_ent (struct tag_op *op, char *label, char *mods, char *arg);
@ -1262,6 +1287,7 @@ struct tag_op ops[] = {
"BSS", 0, x_bss, E, NONE, 0, "BSS", 0, x_bss, E, NONE, 0,
"DC", 0, x_dc, NONE, NONE, 0, "DC", 0, x_dc, NONE, NONE, 0,
"DEC", 0, x_dec, E, E, IS_DBL, "DEC", 0, x_dec, E, E, IS_DBL,
"DECS", 0, x_decs, E, E, IS_DBL, // this is an IBM 1800 directive
"DMES", 0, x_dmes, ANY, NONE, 0, "DMES", 0, x_dmes, ANY, NONE, 0,
"DN", 0, x_dn, NONE, NONE, 0, "DN", 0, x_dn, NONE, NONE, 0,
"DSA", 0, x_dsa, NONE, NONE, 0, "DSA", 0, x_dsa, NONE, NONE, 0,
@ -1293,6 +1319,8 @@ struct tag_op ops[] = {
"AND", 0xE000, std_op, ALL, NONE, 0, "AND", 0xE000, std_op, ALL, NONE, 0,
"BSI", 0x4000, bsi_op, ALL, NONE, 0, "BSI", 0x4000, bsi_op, ALL, NONE, 0,
"CALL", 0x4000, x_call, ALL, L, 0, // alias for BSI L, or external call "CALL", 0x4000, x_call, ALL, L, 0, // alias for BSI L, or external call
"CMP", 0xB000, std_op, ALL, NONE, IS_1800, // this is an IBM 1800-only instruction
"DCM", 0xB800, std_op, ALL, NONE, IS_1800, // this is an IBM 1800-only instruction
"D" , 0xA800, std_op, ALL, NONE, 0, "D" , 0xA800, std_op, ALL, NONE, 0,
"EOR", 0xF000, std_op, ALL, NONE, 0, "EOR", 0xF000, std_op, ALL, NONE, 0,
"LD", 0xC000, std_op, ALL, NONE, 0, "LD", 0xC000, std_op, ALL, NONE, 0,
@ -1310,7 +1338,7 @@ struct tag_op ops[] = {
"STO", 0xD000, std_op, ALL, NONE, 0, "STO", 0xD000, std_op, ALL, NONE, 0,
"STS", 0x2800, std_op, ALL, NONE, 0, "STS", 0x2800, std_op, ALL, NONE, 0,
"STX", 0x6800, std_op, ALL, NONE, NO_IDX, "STX", 0x6800, std_op, ALL, NONE, NO_IDX,
"WAIT", 0x3000, std_op, NONE, NONE, NO_ARGS, "WAIT", 0x3000, std_op, NONE, NONE, IS_ABS,
"XCH", 0x18D0, std_op, NONE, NONE, 0, // same as RTE 16, 18C0 + 10 "XCH", 0x18D0, std_op, NONE, NONE, 0, // same as RTE 16, 18C0 + 10
"XIO", 0x0800, std_op, ALL, NONE, IS_DBL, "XIO", 0x0800, std_op, ALL, NONE, IS_DBL,
@ -1850,6 +1878,9 @@ void parse_line (char *line)
org_advanced = strchr(mods, 'L') ? 2 : 1; // by default, * means address + 1 or 2. Sometimes it doesn't org_advanced = strchr(mods, 'L') ? 2 : 1; // by default, * means address + 1 or 2. Sometimes it doesn't
(op->handler)(op, label, mods, arg); (op->handler)(op, label, mods, arg);
if ((op->flags & IS_1800) && ! enable_1800)
asm_warning("%s is IBM 1800-specific; use the -8 command line option", op->mnem);
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -2178,6 +2209,9 @@ void convert_double_to_extended (double d, unsigned short *wd)
wd[2] = (unsigned short) (mantissa & 0xFFFF); wd[2] = (unsigned short) (mantissa & 0xFFFF);
} }
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
void convert_double_to_standard (double d, unsigned short *wd) void convert_double_to_standard (double d, unsigned short *wd)
{ {
int neg, exp; int neg, exp;
@ -2222,6 +2256,9 @@ void convert_double_to_standard (double d, unsigned short *wd)
// printf(" D %04x%04x\n", wd[0], wd[1]); // printf(" D %04x%04x\n", wd[0], wd[1]);
} }
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
void convert_double_to_fixed (double d, unsigned short *wd, int bexp) void convert_double_to_fixed (double d, unsigned short *wd, int bexp)
{ {
int neg, exp, rshift; int neg, exp, rshift;
@ -2232,6 +2269,9 @@ void convert_double_to_fixed (double d, unsigned short *wd, int bexp)
wd[0] = wd[1] = 0; wd[0] = wd[1] = 0;
return; return;
} }
// note: we assume that this computer uses ANSI floating point
// 7 6 5 4 0 // 7 6 5 4 0
// d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM
@ -2269,6 +2309,9 @@ void convert_double_to_fixed (double d, unsigned short *wd, int bexp)
wd[1] = (unsigned short) (mantissa & 0xFFFF); wd[1] = (unsigned short) (mantissa & 0xFFFF);
} }
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
void getDconstant (char *tok, unsigned short *wd) void getDconstant (char *tok, unsigned short *wd)
{ {
unsigned long l; unsigned long l;
@ -2312,14 +2355,15 @@ void getDconstant (char *tok, unsigned short *wd)
convert_double_to_standard(d, wd); convert_double_to_standard(d, wd);
} }
// ---------------------------------------------------------------------------------
// If the input value is an integer with no decimal point and no B or E, // If the input value is an integer with no decimal point and no B or E,
// DEC generates a double INTEGER value. // DEC generates a double INTEGER value.
// IBM documentation ranges from ambiguous to wrong on this point, but // IBM documentation ranges from ambiguous to wrong on this point, but
// examination of the DMS microfiche supports this. // examination of the DMS microfiche supports this.
// ---------------------------------------------------------------------------------
void x_dec (struct tag_op *op, char *label, char *mods, char *arg) void x_dec (struct tag_op *op, char *label, char *mods, char *arg)
{ {
// char *tok;
unsigned short wd[2]; unsigned short wd[2];
org_advanced = 2; // assume * means address after this location, since it's +1 for dc? org_advanced = 2; // assume * means address after this location, since it's +1 for dc?
@ -2343,6 +2387,28 @@ void x_dec (struct tag_op *op, char *label, char *mods, char *arg)
// writew(wd[1], FALSE); // writew(wd[1], FALSE);
} }
// ---------------------------------------------------------------------------------
// DECS directive. Writes just the high word of a DEC value
// ---------------------------------------------------------------------------------
void x_decs (struct tag_op *op, char *label, char *mods, char *arg)
{
unsigned short wd[2];
org_advanced = 1; // assume * means address after this location
setw(0, org, FALSE); // display the origin
if (*label) // define label
set_symbol(label, org, TRUE, relocate);
getDconstant(arg, wd);
writew(wd[0], FALSE); // write hiword ONLY
}
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
void x_xflc (struct tag_op *op, char *label, char *mods, char *arg) void x_xflc (struct tag_op *op, char *label, char *mods, char *arg)
{ {
char *tok, *b; char *tok, *b;
@ -2843,28 +2909,29 @@ void x_bss (struct tag_op *op, char *label, char *mods, char *arg)
else if (getexpr(arg, FALSE, &expr) != S_DEFINED) else if (getexpr(arg, FALSE, &expr) != S_DEFINED)
return; return;
if (strchr(mods, 'E') != NULL) // force even address if (strchr(mods, 'E') != NULL) // force even address
org_even(); org_even();
if (expr.relative) if (expr.relative)
asm_error("BSS size must be an absolute value"); asm_error("BSS size must be an absolute value");
setw(0, org, FALSE); // display origin setw(0, org, FALSE); // display origin
if (*label) // define label if (*label) // define label
set_symbol(label, org, TRUE, relocate); set_symbol(label, org, TRUE, relocate);
if (expr.value < 0) expr.value &= 0xFFFF; // truncate to 16 bits
asm_warning("Negative BSS size");
if (expr.value & 0x8000)
asm_warning("Negative BSS size");
else if (expr.value > 0) { else if (expr.value > 0) {
if (outmode == OUTMODE_LOAD) { if (outmode == OUTMODE_LOAD) {
org += expr.value; // advance the origin by appropriate number of words org += expr.value; // advance the origin by appropriate number of words
if (pass == 2) // emit new load address in output file if (pass == 2) // emit new load address in output file
fprintf(fout, "@%04x%s" ENDLINE, org & 0xFFFF, relocate ? "R" : ""); fprintf(fout, "@%04x%s" ENDLINE, org & 0xFFFF, relocate ? "R" : "");
} }
else { else {
org += expr.value; // advance the origin by appropriate number of words org += expr.value; // advance the origin by appropriate number of words
if (pass == 2) if (pass == 2)
bincard_setorg(org); bincard_setorg(org);
} }
@ -3920,7 +3987,7 @@ void a1130_term (EXPR *ap)
c = GETNEXT; c = GETNEXT;
if (ctype[c] == DIGIT) { /* number */ if (ctype[c] == DIGIT) { /* number */
ap->value = c_number(c,10,-1); ap->value = signextend(c_number(c,10,-1));
ap->relative = ABSOLUTE; ap->relative = ABSOLUTE;
} }
else if (c == '+') { /* unary + */ else if (c == '+') { /* unary + */
@ -3931,7 +3998,7 @@ void a1130_term (EXPR *ap)
ap->value = - ap->value; ap->value = - ap->value;
} }
else if (c == '/') { /* / starts a hex constant */ else if (c == '/') { /* / starts a hex constant */
ap->value = c_number(c,16,-1); ap->value = signextend(c_number(c,16,-1));
ap->relative = ABSOLUTE; ap->relative = ABSOLUTE;
} }
else if (c == '*') { /* asterisk alone = org */ else if (c == '*') { /* asterisk alone = org */
@ -3970,6 +4037,20 @@ void a1130_term (EXPR *ap)
exprerr(8); exprerr(8);
} }
// ---------------------------------------------------------------------------------
// signextend - sign-extend a 16-bit constant value to whatever "int" is.
// ---------------------------------------------------------------------------------
int signextend (int v)
{
v &= 0xFFFF; // clip to 16 bits (this may not be necessary, but best to be safe?)
if (v & 0x8000) // if sign bit is set
v |= ~0xFFFF; // sign extend
return v;
}
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
// c_expr - evalate an expression // c_expr - evalate an expression
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -4168,15 +4249,15 @@ void c_term (EXPR *ap)
ap->value = c_esc(c); ap->value = c_esc(c);
} }
else if (ctype[c] == DIGIT) { /* number */ else if (ctype[c] == DIGIT) { /* number */
ap->value = c_number(c,10,-1); ap->value = signextend(c_number(c,10,-1));
} }
else if (c == '0') { /* 0 starts a hex or octal constant */ else if (c == '0') { /* 0 starts a hex or octal constant */
if ((c = GETNEXT) == 'x') { if ((c = GETNEXT) == 'x') {
c = GETNEXT; c = GETNEXT;
ap->value = c_number(c,16,-1); ap->value = signextend(c_number(c,16,-1));
} }
else { else {
ap->value = c_number(c,8,-1); ap->value = signextend(c_number(c,8,-1));
} }
} }
else if (c == '*') { /* asterisk alone = org */ else if (c == '*') { /* asterisk alone = org */
@ -4501,3 +4582,4 @@ int strcmpi (char *a, char *b)
} }
#endif #endif

View file

@ -30,9 +30,9 @@
// loads somefile.bin, writes object in 1130 IPL format to somefile.ipl // loads somefile.bin, writes object in 1130 IPL format to somefile.ipl
// Up to 80 columns will be written depending on what the object actually uses // Up to 80 columns will be written depending on what the object actually uses
// //
// mkboot somefile.bin somefile.ipl 1130 0 48 SOMEF // mkboot somefile.bin somefile.ipl 1130 /0 /47 SOMEF
// //
// loads somefile.bin. Writes 72 columns (hex 48), with ident columns 73-80 = SOMEF001 // loads somefile.bin. Writes 72 columns (hex 0 to hex 47), with ident columns 73-80 = SOMEF001
// //
// mkboot somefile.bin somefile.dat core 0 0 SOMEF001 // mkboot somefile.bin somefile.dat core 0 0 SOMEF001
// //

View file

@ -25,6 +25,7 @@
cpu Interdata 16b CPU cpu Interdata 16b CPU
07-Nov-04 RMS Added instruction history
22-Sep-03 RMS Added additional instruction decode types 22-Sep-03 RMS Added additional instruction decode types
07-Feb-03 RMS Fixed bug in SETM, SETMR (found by Mark Pizzolato) 07-Feb-03 RMS Fixed bug in SETM, SETMR (found by Mark Pizzolato)
@ -151,6 +152,17 @@
#define UNIT_816E (1 << UNIT_V_816E) #define UNIT_816E (1 << UNIT_V_816E)
#define UNIT_TYPE (UNIT_ID4 | UNIT_716 | UNIT_816 | UNIT_816E) #define UNIT_TYPE (UNIT_ID4 | UNIT_716 | UNIT_816 | UNIT_816E)
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
uint16 vld;
uint16 pc;
uint16 ir1;
uint16 ir2;
uint16 r1;
uint16 ea;
uint16 opnd; };
#define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | 0xFFFF8000)): \ #define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | 0xFFFF8000)): \
((int32) ((x) & 0x7FFF))) ((int32) ((x) & 0x7FFF)))
#define CC_GL_16(x) if ((x) & SIGN16) cc = CC_L; \ #define CC_GL_16(x) if ((x) & SIGN16) cc = CC_L; \
@ -190,7 +202,9 @@ REG *pcq_r = NULL; /* PC queue reg ptr */
uint32 dec_flgs = 0; /* decode flags */ uint32 dec_flgs = 0; /* decode flags */
uint32 fp_in_hwre = 0; /* ucode/hwre fp */ uint32 fp_in_hwre = 0; /* ucode/hwre fp */
uint32 pawidth = PAWIDTH16; /* phys addr mask */ uint32 pawidth = PAWIDTH16; /* phys addr mask */
uint32 cpu_log = 0; /* debug logging */ uint32 hst_p = 0; /* history pointer */
uint32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
struct BlockIO blk_io; /* block I/O status */ struct BlockIO blk_io; /* block I/O status */
uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL };
@ -216,6 +230,8 @@ t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
extern t_bool devtab_init (void); extern t_bool devtab_init (void);
extern void int_eval (void); extern void int_eval (void);
@ -478,7 +494,6 @@ REG cpu_reg[] = {
{ BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO+REG_CIRC }, { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO+REG_CIRC },
{ HRDATA (PCQP, pcq_p, 6), REG_HRO }, { HRDATA (PCQP, pcq_p, 6), REG_HRO },
{ HRDATA (WRU, sim_int_char, 8) }, { HRDATA (WRU, sim_int_char, 8) },
{ HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN },
{ HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO }, { HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO },
{ HRDATA (BLKIOC, blk_io.cur, 16), REG_HRO }, { HRDATA (BLKIOC, blk_io.cur, 16), REG_HRO },
{ HRDATA (BLKIOE, blk_io.end, 16), REG_HRO }, { HRDATA (BLKIOE, blk_io.end, 16), REG_HRO },
@ -500,6 +515,8 @@ MTAB cpu_mod[] = {
{ UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model }, { UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT", { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
&cpu_set_consint, NULL, NULL }, &cpu_set_consint, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
DEVICE cpu_dev = { DEVICE cpu_dev = {
@ -659,6 +676,17 @@ case OP_RXH: /* reg-mem halfword */
default: default:
return SCPE_IERR; } return SCPE_IERR; }
if (hst_lnt) { /* instruction history? */
hst[hst_p].vld = 1;
hst[hst_p].pc = oPC;
hst[hst_p].ir1 = ir1;
hst[hst_p].ir2 = ir2;
hst[hst_p].r1 = R[r1];
hst[hst_p].ea = ea;
hst[hst_p].opnd = opnd;
hst_p = hst_p + 1;
if (hst_p >= hst_lnt) hst_p = 0; }
PC = (PC + 2) & VAMASK; /* increment PC */ PC = (PC + 2) & VAMASK; /* increment PC */
switch (op) { /* case on opcode */ switch (op) { /* case on opcode */
@ -1736,3 +1764,66 @@ if ((uptr->flags & (UNIT_716 | UNIT_816 | UNIT_816E)) == 0)
if (PSW & PSW_AIO) SET_INT (v_DS); if (PSW & PSW_AIO) SET_INT (v_DS);
return SCPE_OK; return SCPE_OK;
} }
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].vld = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (uint32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
uint32 op, k, di, lnt;
char *cptr = (char *) desc;
t_value sim_eval[4];
t_stat r;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC r1 opnd ea IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(di++) % hst_lnt]; /* entry pointer */
if (h->vld) { /* instruction? */
fprintf (st, "%04X %04X %04X ", h->pc, h->r1, h->opnd);
sim_eval[0] = op = (h->ir1 >> 8) & 0xFF;
sim_eval[1] = h->ir1 & 0xFF;
sim_eval[2] = (h->ir2 >> 8) & 0xFF;
sim_eval[3] = h->ir2 & 0xFF;
if (OP_TYPE (op) >= OP_RX) fprintf (st, "%04X ", h->ea);
else fprintf (st, " ");
if ((fprint_sym (st, h->pc, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %04X", h->ir1);
fputc ('\n', st); /* end line */
} /* end if instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
cpu Interdata 32b CPU cpu Interdata 32b CPU
06-Nov-04 RMS Added =n to SHOW HISTORY
25-Jan-04 RMS Revised for device debug support 25-Jan-04 RMS Revised for device debug support
31-Dec-03 RMS Fixed bug in cpu_set_hist 31-Dec-03 RMS Fixed bug in cpu_set_hist
22-Sep-03 RMS Added additional instruction decode types 22-Sep-03 RMS Added additional instruction decode types
@ -561,7 +562,7 @@ MTAB cpu_mod[] = {
{ UNIT_TYPE, UNIT_DPFP | UNIT_832, "8/32", "832", NULL }, { UNIT_TYPE, UNIT_DPFP | UNIT_832, "8/32", "832", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT", { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT",
&cpu_set_consint, NULL, NULL }, &cpu_set_consint, NULL, NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY", { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist }, &cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
@ -2106,16 +2107,23 @@ return SCPE_OK;
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{ {
uint32 op, k, di; uint32 op, k, di, lnt;
char *cptr = (char *) desc;
t_value sim_eval[6]; t_value sim_eval[6];
t_stat r;
struct InstHistory *h; struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw); UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC r1 operand ea IR\n\n"); fprintf (st, "PC r1 operand ea IR\n\n");
di = hst_p; /* work forward */ for (k = 0; k < lnt; k++) { /* print specified */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(di++) % hst_lnt]; /* entry pointer */ h = &hst[(di++) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */ if (h->pc & HIST_PC) { /* instruction? */
fprintf (st, "%06X %08X %08X ", h->pc & VAMASK32, h->r1, h->opnd); fprintf (st, "%06X %08X %08X ", h->pc & VAMASK32, h->r1, h->opnd);

View file

@ -73,8 +73,8 @@
/* Double precision floating point registers */ /* Double precision floating point registers */
struct dpr { struct dpr {
unsigned int32 h; /* high 32b */ uint32 h; /* high 32b */
unsigned int32 l; /* low 32b */ uint32 l; /* low 32b */
}; };
typedef struct dpr dpr_t; typedef struct dpr dpr_t;

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: Interdata 16b/32b Simulator Usage Subj: Interdata 16b/32b Simulator Usage
Date: 15-Feb-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -205,6 +205,17 @@ control registers for the interrupt system.
most recent PC change first most recent PC change first
WRU 8 interrupt character WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 CPU (32b) 2.2 CPU (32b)
The CPU options include memory size and CPU type: The CPU options include memory size and CPU type:
@ -270,8 +281,9 @@ This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, display length = n SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries. The maximum length for the history is 65536 entries.
@ -547,7 +559,7 @@ write locked.
SET FDn LOCKED set unit n write locked SET FDn LOCKED set unit n write locked
SET FDn WRITEENABLED set unit n write enabled SET FDn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The floppy disk supports the BOOT command. BOOT FDn copies an autoload The floppy disk supports the BOOT command. BOOT FDn copies an autoload
sequence into memory and starts it running. sequence into memory and starts it running.
@ -658,7 +670,7 @@ write locked, and to select the type of drive:
SET DPn 2315 set unit n to 2315 (2.5MB) SET DPn 2315 set unit n to 2315 (2.5MB)
SET DPn 5440 set unit n to 5440 (10MB) SET DPn 5440 set unit n to 5440 (10MB)
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The cartridge disk supports the BOOT command. To boot OS16/32, the hex The cartridge disk supports the BOOT command. To boot OS16/32, the hex
form of the operating system file's extension must be placed in locations form of the operating system file's extension must be placed in locations
@ -729,7 +741,7 @@ write enabled or write locked, and to select the type of drive:
(300MB formatted) (300MB formatted)
Note that the disk bootstraps can ONLY boot the MSM80 and MSM300. Note that the disk bootstraps can ONLY boot the MSM80 and MSM300.
Units can be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The MSM/IDC controller supports the BOOT command. To boot OS16/32, the hex The MSM/IDC controller supports the BOOT command. To boot OS16/32, the hex
form of the operating system file's extension must be placed in locations form of the operating system file's extension must be placed in locations
@ -791,7 +803,7 @@ or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The magnetic tape supports the BOOT command. BOOT MTn copies an autoload The magnetic tape supports the BOOT command. BOOT MTn copies an autoload
sequence into memory and starts it running. sequence into memory and starts it running.

View file

@ -344,7 +344,7 @@
#define UNIT_UP (1 << UNIT_V_UP) #define UNIT_UP (1 << UNIT_V_UP)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
unsigned int16 M[MAXMEMSIZE] = { 0 }; /* memory */ uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
int32 AC[4] = { 0 }; /* accumulators */ int32 AC[4] = { 0 }; /* accumulators */
int32 C = 0; /* carry flag */ int32 C = 0; /* carry flag */
int32 saved_PC = 0; /* program counter */ int32 saved_PC = 0; /* program counter */
@ -375,13 +375,13 @@ struct ndev dev_table[64]; /* dispatch table */
int32 hnext = 0; /* # of current entry */ int32 hnext = 0; /* # of current entry */
int32 hwrap = 0; /* 1 if wrapped */ int32 hwrap = 0; /* 1 if wrapped */
int32 hmax = HISTMAX; /* Maximum entries b4 wrap */ int32 hmax = HISTMAX; /* Maximum entries b4 wrap */
unsigned int16 hpc[HISTMAX]; uint16 hpc[HISTMAX];
unsigned int16 hinst[HISTMAX]; uint16 hinst[HISTMAX];
unsigned int16 hinst2[HISTMAX]; uint16 hinst2[HISTMAX];
unsigned int16 hac0[HISTMAX]; uint16 hac0[HISTMAX];
unsigned int16 hac1[HISTMAX]; uint16 hac1[HISTMAX];
unsigned int16 hac2[HISTMAX]; uint16 hac2[HISTMAX];
unsigned int16 hac3[HISTMAX]; uint16 hac3[HISTMAX];
unsigned short hflags[HISTMAX]; unsigned short hflags[HISTMAX];
/* Flags: 0x01 - carry bit /* Flags: 0x01 - carry bit
@ -689,7 +689,7 @@ t_stat sim_instr (void)
{ {
extern int32 sim_interval; extern int32 sim_interval;
register int32 PC, IR, i, t, MA, j, k, tac; register int32 PC, IR, i, t, MA, j, k, tac;
register unsigned int32 mddata, uAC0, uAC1, uAC2, uAC3; register uint32 mddata, uAC0, uAC1, uAC2, uAC3;
int16 sAC0, sAC1, sAC2; int16 sAC0, sAC1, sAC2;
int32 sddata, mi1, mi2, fpnum32; int32 sddata, mi1, mi2, fpnum32;
t_int64 fpnum, expon; t_int64 fpnum, expon;
@ -1623,9 +1623,9 @@ if ((IR & 0100017) == 0100010) { /* This pattern for all */
/* Multiply / Divide */ /* Multiply / Divide */
if (IR == 0143710) { /* MUL: Unsigned Multiply */ if (IR == 0143710) { /* MUL: Unsigned Multiply */
uAC0 = (unsigned int32) AC[0]; uAC0 = (uint32) AC[0];
uAC1 = (unsigned int32) AC[1]; uAC1 = (uint32) AC[1];
uAC2 = (unsigned int32) AC[2]; uAC2 = (uint32) AC[2];
mddata = (uAC1 * uAC2) + uAC0; mddata = (uAC1 * uAC2) + uAC0;
AC[0] = (mddata >> 16) & 0177777; AC[0] = (mddata >> 16) & 0177777;
@ -1643,9 +1643,9 @@ if ((IR & 0100017) == 0100010) { /* This pattern for all */
continue; continue;
} }
if (IR == 0153710) { /* DIV: Unsigned Divide */ if (IR == 0153710) { /* DIV: Unsigned Divide */
uAC0 = (unsigned int32) AC[0]; uAC0 = (uint32) AC[0];
uAC1 = (unsigned int32) AC[1]; uAC1 = (uint32) AC[1];
uAC2 = (unsigned int32) AC[2]; uAC2 = (uint32) AC[2];
if (uAC0 >= uAC2) C = 0200000; if (uAC0 >= uAC2) C = 0200000;
else { C = 0; else { C = 0;
@ -5930,7 +5930,6 @@ int32 Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc)
char debmap[4], debion[4]; char debmap[4], debion[4];
t_value simeval[20]; t_value simeval[20];
int debcar; int debcar;
FILE *Dumpf;
int start, end, ctr; int start, end, ctr;
int count = 0; int count = 0;
@ -5939,7 +5938,6 @@ int32 Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc)
printf("in DEBUG with bit 0 being 1 to build history.\n"); printf("in DEBUG with bit 0 being 1 to build history.\n");
return SCPE_OK; return SCPE_OK;
} }
Dumpf = fopen("history.log", "w");
if (!hwrap) { if (!hwrap) {
start = 0; start = 0;
end = hnext; end = hnext;
@ -5957,7 +5955,7 @@ int32 Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc)
strcpy(debmap, " "); strcpy(debmap, " ");
debcar = 0; debcar = 0;
if (hflags[ctr] & 0x80) { if (hflags[ctr] & 0x80) {
fprintf(Dumpf, "--------- Interrupt %o (%o) to %6o ---------\n", fprintf(st, "--------- Interrupt %o (%o) to %6o ---------\n",
hinst[ctr], hac0[ctr], hac1[ctr]); hinst[ctr], hac0[ctr], hac1[ctr]);
} else { } else {
if (hflags[ctr] & 0x01) debcar = 1; if (hflags[ctr] & 0x01) debcar = 1;
@ -5966,20 +5964,18 @@ int32 Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc)
if (hflags[ctr] & 0x08) strcpy(debmap, "B"); if (hflags[ctr] & 0x08) strcpy(debmap, "B");
if (hflags[ctr] & 0x10) strcpy(debmap, "C"); if (hflags[ctr] & 0x10) strcpy(debmap, "C");
if (hflags[ctr] & 0x20) strcpy(debmap, "D"); if (hflags[ctr] & 0x20) strcpy(debmap, "D");
fprintf(Dumpf, "%s%s%06o acs: %06o %06o %06o %06o %01o ", fprintf(st, "%s%s%06o acs: %06o %06o %06o %06o %01o ",
debion, debmap, hpc[ctr], hac0[ctr], hac1[ctr], hac2[ctr], debion, debmap, hpc[ctr], hac0[ctr], hac1[ctr], hac2[ctr],
hac3[ctr], debcar); hac3[ctr], debcar);
simeval[0] = hinst[ctr]; simeval[0] = hinst[ctr];
simeval[1] = hinst2[ctr]; simeval[1] = hinst2[ctr];
fprint_sym (Dumpf, hpc[ctr], simeval, NULL, SWMASK('M')); fprint_sym (st, hpc[ctr], simeval, NULL, SWMASK('M'));
fprintf(Dumpf, "\n"); fprintf(st, "\n");
} }
ctr++; ctr++;
if (ctr > hmax) if (ctr > hmax)
ctr = 0; ctr = 0;
} }
fclose(Dumpf);
printf("\n%d records dumped to history.log\n", count);
return SCPE_OK; return SCPE_OK;
} }

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: Nova Simulator Usage Subj: Nova Simulator Usage
Date: 15-Mar-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -540,7 +540,7 @@ write locked, and to select the type of drive:
SET DPn 6103 set unit n to 6103 SET DPn 6103 set unit n to 6103
SET DPn 4231 set unit n to 4231 SET DPn 4231 set unit n to 4231
Units can also be set ONLINE or OFFLINE. The moving head disk controller Units can also be set ENABLED or DISABLED. The moving head disk controller
supports the BOOT command. supports the BOOT command.
All drives have 256 16b words per sector. The other disk parameters are: All drives have 256 16b words per sector. The other disk parameters are:
@ -594,7 +594,7 @@ or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. The magnetic tape controller Units can also be set ENABLED or DISABLED. The magnetic tape controller
supports the BOOT command. supports the BOOT command.
The magnetic tape controller implements these registers: The magnetic tape controller implements these registers:

View file

@ -25,6 +25,7 @@
cpu PDP-1 central processor cpu PDP-1 central processor
09-Nov-04 RMS Added instruction history
07-Sep-03 RMS Added additional explanation on I/O simulation 07-Sep-03 RMS Added additional explanation on I/O simulation
01-Sep-03 RMS Added address switches for hardware readin 01-Sep-03 RMS Added address switches for hardware readin
23-Jul-03 RMS Revised to detect I/O wait hang 23-Jul-03 RMS Revised to detect I/O wait hang
@ -229,6 +230,18 @@
#define UNIT_MDV (1 << UNIT_V_MDV) #define UNIT_MDV (1 << UNIT_V_MDV)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_PC 0x40000000
#define HIST_V_SHF 18
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
uint32 pc;
uint32 ir;
uint32 ovac;
uint32 pfio;
uint32 ea;
uint32 opnd; };
int32 M[MAXMEMSIZE] = { 0 }; /* memory */ int32 M[MAXMEMSIZE] = { 0 }; /* memory */
int32 AC = 0; /* AC */ int32 AC = 0; /* AC */
int32 IO = 0; /* IO */ int32 IO = 0; /* IO */
@ -252,6 +265,9 @@ int32 ind_max = 16; /* nested ind limit */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */ int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
extern UNIT *sim_clock_queue; extern UNIT *sim_clock_queue;
extern int32 sim_int_char; extern int32 sim_int_char;
@ -261,6 +277,8 @@ 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_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr); t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
extern int32 ptr (int32 inst, int32 dev, int32 dat); extern int32 ptr (int32 inst, int32 dev, int32 dat);
extern int32 ptp (int32 inst, int32 dev, int32 dat); extern int32 ptp (int32 inst, int32 dev, int32 dat);
@ -355,6 +373,8 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
{ UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size }, { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
DEVICE cpu_dev = { DEVICE cpu_dev = {
@ -408,6 +428,13 @@ IR = M[MA]; /* fetch instruction */
PC = INCR_ADDR (PC); /* increment PC */ PC = INCR_ADDR (PC); /* increment PC */
xct_count = 0; /* track nested XCT's */ xct_count = 0; /* track nested XCT's */
sim_interval = sim_interval - 1; sim_interval = sim_interval - 1;
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].pc = MA | HIST_PC; /* save PC, IR, LAC, MQ */
hst[hst_p].ir = IR;
hst[hst_p].ovac = (OV << HIST_V_SHF) | AC;
hst[hst_p].pfio = (PF << HIST_V_SHF) | IO; }
xct_instr: /* label for XCT */ xct_instr: /* label for XCT */
if ((IR == (OP_JMP+IA+1)) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) { if ((IR == (OP_JMP+IA+1)) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) {
@ -430,7 +457,13 @@ if ((op < 032) && (op != 007)) { /* mem ref instr */
if ((t & IA) == 0) break; } if ((t & IA) == 0) break; }
if (i >= ind_max) { /* indirect loop? */ if (i >= ind_max) { /* indirect loop? */
reason = STOP_IND; reason = STOP_IND;
break; } } } } break; } /* end if loop */
} /* end else !extm */
} /* end if indirect */
if (hst_p) { /* history enabled? */
hst[hst_p].ea = MA;
hst[hst_p].opnd = M[MA]; }
}
switch (op) { /* decode IR<0:4> */ switch (op) { /* decode IR<0:4> */
@ -852,3 +885,70 @@ MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK; return SCPE_OK;
} }
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 ov, pf, op, k, di, lnt;
char *cptr = (char *) desc;
t_stat r;
t_value sim_eval;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC OV AC IO PF EA IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
ov = (h->ovac >> HIST_V_SHF) & 1; /* overflow */
pf = (h->pfio >> HIST_V_SHF) & 077; /* prog flags */
op = ((h->ir >> 13) & 037); /* get opcode */
fprintf (st, "%06o %o %06o %06o %02o ",
h->pc & AMASK, ov, h->ovac & DMASK, h->pfio & DMASK, pf);
if ((op < 032) && (op != 007)) /* mem ref instr */
fprintf (st, "%06o ", h->ea);
else fprintf (st, " ");
sim_eval = h->ir;
if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %06o", h->ir);
else if ((op < 032) && (op != 007)) /* mem ref instr */
fprintf (st, " [%06o]", h->opnd);
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: PDP-1 Simulator Usage Subj: PDP-1 Simulator Usage
Date: 15-Feb-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -150,6 +150,17 @@ control registers for the interrupt system.
IND_MAX 8 maximum nested indirect addresses IND_MAX 8 maximum nested indirect addresses
WRU 8 interrupt character WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 Programmed I/O Devices 2.2 Programmed I/O Devices
2.2.1 Paper Tape Reader (PTR) 2.2.1 Paper Tape Reader (PTR)
@ -280,7 +291,7 @@ locked.
SET DTn WRITEENABLED set unit n write enabled SET DTn WRITEENABLED set unit n write enabled
SET DTn LOCKED set unit n write locked SET DTn LOCKED set unit n write locked
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The DECtape controller can be disabled and enabled with the SET DT DISABLED The DECtape controller can be disabled and enabled with the SET DT DISABLED
and SET DT ENABLED commands, respectively. and SET DT ENABLED commands, respectively.

View file

@ -25,6 +25,7 @@
cpu KS10 central processor cpu KS10 central processor
10-Nov-04 RMS Added instruction history
08-Oct-02 RMS Revised to build dib_tab dynamically 08-Oct-02 RMS Revised to build dib_tab dynamically
Added SHOW IOSPACE Added SHOW IOSPACE
30-Dec-01 RMS Added old PC queue 30-Dec-01 RMS Added old PC queue
@ -136,6 +137,15 @@
#define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */ #define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_PC 0x40000000
#define HIST_MIN 64
#define HIST_MAX 65536
struct InstHistory {
a10 pc;
a10 ea;
d10 ir;
d10 ac; };
d10 *M = NULL; /* memory */ d10 *M = NULL; /* memory */
d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */ d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */
d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */ d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */
@ -178,6 +188,9 @@ a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */ int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */
jmp_buf save_env; jmp_buf save_env;
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
extern int32 sim_int_char; extern int32 sim_int_char;
extern int32 sim_interval; extern int32 sim_interval;
@ -189,6 +202,8 @@ extern UNIT tim_unit;
t_stat cpu_ex (t_value *vptr, t_addr addr, 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_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr); t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
d10 adjsp (d10 val, a10 ea); d10 adjsp (d10 val, a10 ea);
void ibp (a10 ea, int32 pflgs); void ibp (a10 ea, int32 pflgs);
d10 ldb (a10 ea, int32 pflgs); d10 ldb (a10 ea, int32 pflgs);
@ -375,6 +390,8 @@ MTAB cpu_mod[] = {
{ UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL }, { UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
NULL, &show_iospace }, NULL, &show_iospace },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
DEVICE cpu_dev = { DEVICE cpu_dev = {
@ -742,7 +759,14 @@ for (indrct = inst, i = 0; i < ind_max; i++) { /* calc eff addr */
if (TST_IND (indrct)) indrct = Read (ea, MM_EA); if (TST_IND (indrct)) indrct = Read (ea, MM_EA);
else break; } else break; }
if (i >= ind_max) if (i >= ind_max)
ABORT (STOP_IND); /* too many ind? stop */ ABORT (STOP_IND); /* too many ind? stop */
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].pc = pager_PC | HIST_PC;
hst[hst_p].ea = ea;
hst[hst_p].ir = inst;
hst[hst_p].ac = AC(ac); }
switch (op) { /* case on opcode */ switch (op) { /* case on opcode */
/* UUO's (0000 - 0077) - checked against KS10 ucode */ /* UUO's (0000 - 0077) - checked against KS10 ucode */
@ -2100,3 +2124,63 @@ if (rptr == NULL) return;
for (i = 0; i < AC_NUM; i++, rptr++) rptr->loc = (void *) (acbase + i); for (i = 0; i < AC_NUM; i++, rptr++) rptr->loc = (void *) (acbase + i);
return; return;
} }
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 k, di, lnt;
char *cptr = (char *) desc;
t_stat r;
t_value sim_eval;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC AC EA IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
fprintf (st, "%06o ", h->pc & AMASK);
fprintf (st, "%012o ", h->ac);
fprintf (st, "%06o ", h->ea);
sim_eval = h->ir;
if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %012o", h->ir);
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -619,9 +619,6 @@ typedef struct pdp_dib DIB;
#define UNIBUS TRUE /* 18b only */ #define UNIBUS TRUE /* 18b only */
#define FST 0 /* Unibus 1 */
#define MAP 1 /* Unibus 3 */
#define DEV_RDX 8 /* default device radix */ #define DEV_RDX 8 /* default device radix */
/* I/O page layout */ /* I/O page layout */
@ -739,10 +736,11 @@ typedef struct pdp_dib DIB;
/* Function prototypes */ /* Function prototypes */
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf, t_bool ub); int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool ub); int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf);
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool ub); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool ub); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf);
t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc);

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: PDP-10 Simulator Usage Subj: PDP-10 Simulator Usage
Date: 15-Jun-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -174,6 +174,17 @@ control registers for the interrupt system.
WRU 8 interrupt character WRU 8 interrupt character
REG[0:127] 36 fast memory blocks REG[0:127] 36 fast memory blocks
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 Pager 2.2 Pager
The pager contains the page maps for executive and user mode. The The pager contains the page maps for executive and user mode. The
@ -417,7 +428,7 @@ to set the drive type to one of six disk types, or autosize:
The type options can be used only when a unit is not attached to a file. The type options can be used only when a unit is not attached to a file.
Note that TOPS-10 V7.03 supported only the RP06 and RM03; V7.04 added Note that TOPS-10 V7.03 supported only the RP06 and RM03; V7.04 added
support for the RP07. TOPS-20 V4.1 also supported only the RP06 and support for the RP07. TOPS-20 V4.1 also supported only the RP06 and
RM03. Units can be set ONLINE or OFFLINE. RM03. Units can be set ENABLED or DISABLED.
The RP controller implements these registers: The RP controller implements these registers:
@ -467,7 +478,7 @@ the ability to make units write enabled or locked.
SET TUn LOCKED set unit n write locked SET TUn LOCKED set unit n write locked
SET TUn WRITEENABLED set unit n write enabled SET TUn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The magnetic tape controller implements these registers: The magnetic tape controller implements these registers:

View file

@ -394,7 +394,7 @@ for (i = 0; dibp = dib_tab[i]; i++ ) {
UBNXM_FAIL (pa, mode); UBNXM_FAIL (pa, mode);
} }
/* Mapped read and write routines - used by word-oriented Unibus devices */ /* Mapped read and write routines - used by standard Unibus devices on Unibus 1 */
a10 Map_Addr10 (a10 ba, int32 ub) a10 Map_Addr10 (a10 ba, int32 ub)
{ {
@ -407,23 +407,23 @@ pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;
return pa10; return pa10;
} }
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf, t_bool ub) int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 lim; uint32 lim;
a10 pa10; a10 pa10;
lim = ba + bc; lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */ for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */ pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */ return (lim - ba); } /* return bc */
*buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377); *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
} }
return 0; return 0;
} }
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool ub) int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 lim; uint32 lim;
a10 pa10; a10 pa10;
@ -431,16 +431,16 @@ a10 pa10;
ba = ba & ~01; /* align start */ ba = ba & ~01; /* align start */
lim = ba + (bc & ~01); lim = ba + (bc & ~01);
for ( ; ba < lim; ba = ba + 2) { /* by words */ for ( ; ba < lim; ba = ba + 2) { /* by words */
pa10 = Map_Addr10 (ba, ub); /* map addr */ pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */ return (lim - ba); } /* return bc */
*buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777); *buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
} }
return 0; return 0;
} }
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool ub) int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 lim; uint32 lim;
a10 pa10; a10 pa10;
@ -448,16 +448,16 @@ static d10 mask = 0377;
lim = ba + bc; lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */ for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */ pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */ return (lim - ba); } /* return bc */
M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) | M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |
(((d10) *buf++) << ubashf[ba & 3]); } (((d10) *buf++) << ubashf[ba & 3]); }
return 0; return 0;
} }
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool ub) int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 lim; uint32 lim;
a10 pa10; a10 pa10;
@ -466,9 +466,9 @@ d10 val;
ba = ba & ~01; /* align start */ ba = ba & ~01; /* align start */
lim = ba + (bc & ~01); lim = ba + (bc & ~01);
for ( ; ba < lim; ba++) { /* by bytes */ for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, ub); /* map addr */ pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */ return (lim - ba); } /* return bc */
val = *buf++; /* get data */ val = *buf++; /* get data */
if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val; if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;

View file

@ -373,7 +373,7 @@ if ((fnc == FNC_PR) && (dvlnt == 0)) {
return SCPE_OK; } return SCPE_OK; }
for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) { for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
if (Map_ReadW (ba, 2, &wd10, MAP)) { /* get word, err? */ if (Map_ReadW (ba, 2, &wd10)) { /* get word, err? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */ lpcsb = lpcsb | CSB_MTE; /* set NXM error */
update_lpcs (CSA_ERR); /* set done */ update_lpcs (CSA_ERR); /* set done */
break; } break; }

View file

@ -25,6 +25,7 @@
rp RH/RP/RM moving head disks rp RH/RP/RM moving head disks
20-Sep-04 RMS Fixed bugs in replicated state, RP vs RM accuracy
04-Jan-04 RMS Changed sim_fsize calling sequence 04-Jan-04 RMS Changed sim_fsize calling sequence
23-Jul-03 RMS Fixed bug in read header stub 23-Jul-03 RMS Fixed bug in read header stub
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
@ -72,6 +73,8 @@
#define RP_MAXFR 32768 /* max transfer */ #define RP_MAXFR 32768 /* max transfer */
#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ #define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) drv_tab[d].sect))) ((double) drv_tab[d].sect)))
#define MBA_RP_CTRL 0 /* RP drive */
#define MBA_RM_CTRL 1 /* RM drive */
/* Flags in the unit flags word */ /* Flags in the unit flags word */
@ -255,6 +258,8 @@
In theory, each drive can be a different type. The size field in In theory, each drive can be a different type. The size field in
each unit selects the drive capacity for each drive and thus the each unit selects the drive capacity for each drive and thus the
drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE.
The RP07, despite its name, uses an RM-style controller.
*/ */
#define RM03_DTYPE 0 #define RM03_DTYPE 0
@ -300,20 +305,21 @@
#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD) #define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD)
struct drvtyp { struct drvtyp {
int sect; /* sectors */ int32 sect; /* sectors */
int surf; /* surfaces */ int32 surf; /* surfaces */
int cyl; /* cylinders */ int32 cyl; /* cylinders */
int size; /* #blocks */ int32 size; /* #blocks */
int devtype; /* device type */ int32 devtype; /* device type */
int32 ctrl; /* ctrl type */
}; };
struct drvtyp drv_tab[] = { struct drvtyp drv_tab[] = {
{ RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV }, { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, MBA_RM_CTRL },
{ RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV }, { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, MBA_RP_CTRL },
{ RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV }, { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, MBA_RM_CTRL },
{ RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV }, { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, MBA_RP_CTRL },
{ RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV }, { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, MBA_RM_CTRL },
{ RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV }, { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, MBA_RM_CTRL },
{ 0 } }; { 0 } };
extern d10 *M; /* memory */ extern d10 *M; /* memory */
@ -326,18 +332,20 @@ extern UNIT cpu_unit;
int32 rpcs1 = 0; /* control/status 1 */ int32 rpcs1 = 0; /* control/status 1 */
int32 rpwc = 0; /* word count */ int32 rpwc = 0; /* word count */
int32 rpba = 0; /* bus address */ int32 rpba = 0; /* bus address */
int32 rpda = 0; /* track/sector */
int32 rpcs2 = 0; /* control/status 2 */ int32 rpcs2 = 0; /* control/status 2 */
int32 rpds[RP_NUMDR] = { 0 }; /* drive status */
int32 rper1[RP_NUMDR] = { 0 }; /* error status 1 */
int32 rpdb = 0; /* data buffer */ int32 rpdb = 0; /* data buffer */
int32 rpmr = 0; /* maint register */ uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */
int32 rpof = 0; /* offset */ uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */
int32 rpdc = 0; /* cylinder */ uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */
int32 rper2 = 0; /* error status 2 */ uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */
int32 rper3 = 0; /* error status 3 */ uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */
int32 rpec1 = 0; /* ECC correction 1 */ uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */
int32 rpec2 = 0; /* ECC correction 2 */ uint16 rpof[RP_NUMDR] = { 0 }; /* offset */
uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */
uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */
uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */
uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */
uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */
int32 rpiff = 0; /* INTR flip/flop */ int32 rpiff = 0; /* INTR flip/flop */
int32 rp_stopioe = 1; /* stop on error */ int32 rp_stopioe = 1; /* stop on error */
int32 rp_swait = 10; /* seek time */ int32 rp_swait = 10; /* seek time */
@ -345,6 +353,7 @@ int32 rp_rwait = 10; /* rotate time */
static int32 reg_in_drive[32] = { static int32 reg_in_drive[32] = {
0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static char *rp_mapnam[MBA_RM_CTRL + 1] = { "RP", "RM" };
t_stat rp_rd (int32 *data, int32 PA, int32 access); t_stat rp_rd (int32 *data, int32 PA, int32 access);
t_stat rp_wr (int32 data, int32 PA, int32 access); t_stat rp_wr (int32 data, int32 PA, int32 access);
@ -354,6 +363,7 @@ t_stat rp_reset (DEVICE *dptr);
t_stat rp_boot (int32 unitno, DEVICE *dptr); t_stat rp_boot (int32 unitno, DEVICE *dptr);
t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_attach (UNIT *uptr, char *cptr);
t_stat rp_detach (UNIT *uptr); t_stat rp_detach (UNIT *uptr);
void set_rper (int32 flag, int32 drv);
void update_rpcs (int32 flags, int32 drv); void update_rpcs (int32 flags, int32 drv);
void rp_go (int32 drv, int32 fnc); void rp_go (int32 drv, int32 fnc);
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
@ -391,18 +401,20 @@ REG rp_reg[] = {
{ ORDATA (RPCS1, rpcs1, 16) }, { ORDATA (RPCS1, rpcs1, 16) },
{ ORDATA (RPWC, rpwc, 16) }, { ORDATA (RPWC, rpwc, 16) },
{ ORDATA (RPBA, rpba, 16) }, { ORDATA (RPBA, rpba, 16) },
{ ORDATA (RPDA, rpda, 16) },
{ ORDATA (RPCS2, rpcs2, 16) }, { ORDATA (RPCS2, rpcs2, 16) },
{ ORDATA (RPDB, rpdb, 16) },
{ BRDATA (RPDA, rpda, 8, 16, RP_NUMDR) },
{ BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) }, { BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) },
{ BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) }, { BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) },
{ ORDATA (RPOF, rpof, 16) }, { BRDATA (RPHR, rmhr, 8, 16, RP_NUMDR) },
{ ORDATA (RPDC, rpdc, 16) }, { BRDATA (RPOF, rpof, 8, 16, RP_NUMDR) },
{ ORDATA (RPER2, rper2, 16) }, { BRDATA (RPDC, rpdc, 8, 16, RP_NUMDR) },
{ ORDATA (RPER3, rper3, 16) }, { BRDATA (RPER2, rper2, 8, 16, RP_NUMDR) },
{ ORDATA (RPEC1, rpec1, 16) }, { BRDATA (RPER3, rper3, 8, 16, RP_NUMDR) },
{ ORDATA (RPEC2, rpec2, 16) }, { BRDATA (RPEC1, rpec1, 8, 16, RP_NUMDR) },
{ ORDATA (RPMR, rpmr, 16) }, { BRDATA (RPEC2, rpec2, 8, 16, RP_NUMDR) },
{ ORDATA (RPDB, rpdb, 16) }, { BRDATA (RMMR, rpmr, 8, 16, RP_NUMDR) },
{ BRDATA (RMMR2, rmmr2, 8, 16, RP_NUMDR) },
{ FLDATA (IFF, rpiff, 0) }, { FLDATA (IFF, rpiff, 0) },
{ FLDATA (INT, int_req, INT_V_RP) }, { FLDATA (INT, int_req, INT_V_RP) },
{ FLDATA (SC, rpcs1, CSR_V_ERR) }, { FLDATA (SC, rpcs1, CSR_V_ERR) },
@ -497,7 +509,7 @@ case 002: /* RPBA */
*data = rpba = rpba & ~BA_MBZ; *data = rpba = rpba & ~BA_MBZ;
break; break;
case 003: /* RPDA */ case 003: /* RPDA */
*data = rpda = rpda & ~DA_MBZ; *data = rpda[drv] = rpda[drv] & ~DA_MBZ;
break; break;
case 004: /* RPCS2 */ case 004: /* RPCS2 */
*data = rpcs2 = (rpcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR; *data = rpcs2 = (rpcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR;
@ -520,7 +532,7 @@ case 011: /* RPDB */
*data = rpdb; *data = rpdb;
break; break;
case 012: /* RPMR */ case 012: /* RPMR */
*data = rpmr; *data = rpmr[drv];
break; break;
case 013: /* RPDT */ case 013: /* RPDT */
*data = drv_tab[dtype].devtype; *data = drv_tab[dtype].devtype;
@ -529,28 +541,34 @@ case 014: /* RPSN */
*data = 020 | (drv + 1); *data = 020 | (drv + 1);
break; break;
case 015: /* RPOF */ case 015: /* RPOF */
*data = rpof = rpof & ~OF_MBZ; *data = rpof[drv] = rpof[drv] & ~OF_MBZ;
break; break;
case 016: /* RPDC */ case 016: /* RPDC */
*data = rpdc = rpdc & ~DC_MBZ; *data = rpdc[drv] = rpdc[drv] & ~DC_MBZ;
break; break;
case 017: /* RPCC, RMHR */ case 017: /* RPCC, RMHR */
*data = rp_unit[drv].CYL; if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is CC */
*data = rp_unit[drv].CYL;
else *data = rmhr[drv] ^ 0177777; /* RM is HR */
break; break;
case 020: /* RPER2, RMMR2 */ case 020: /* RPER2, RMMR2 */
*data = rper2; if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER2 */
*data = rper2[drv];
else *data = rmmr2[drv]; /* RM is MR2 */
break; break;
case 021: /* RPER3, RMER2 */ case 021: /* RPER3, RMER2 */
*data = rper3; if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER3 */
*data = rper3[drv];
else *data = rper2[drv]; /* RM is ER2 */
break; break;
case 022: /* RPEC1 */ case 022: /* RPEC1 */
*data = rpec1; *data = rpec1[drv];
break; break;
case 023: /* RPEC2 */ case 023: /* RPEC2 */
*data = rpec2; *data = rpec2[drv];
break; break;
default: /* all others */ default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILR; set_rper (ER1_ILR, drv);
update_rpcs (0, drv); update_rpcs (0, drv);
break; } break; }
return SCPE_OK; return SCPE_OK;
@ -558,11 +576,12 @@ return SCPE_OK;
t_stat rp_wr (int32 data, int32 PA, int32 access) t_stat rp_wr (int32 data, int32 PA, int32 access)
{ {
int32 cs1f, drv, i, j; int32 cs1f, drv, dtype, i, j;
UNIT *uptr; UNIT *uptr;
cs1f = 0; /* no int on cs1 upd */ cs1f = 0; /* no int on cs1 upd */
drv = GET_UNIT (rpcs2); /* get current unit */ drv = GET_UNIT (rpcs2); /* get current unit */
dtype = GET_DTYPE (rp_unit[drv].flags); /* get drive type */
uptr = rp_dev.units + drv; /* get unit */ uptr = rp_dev.units + drv; /* get unit */
j = (PA >> 1) & 037; /* get reg offset */ j = (PA >> 1) & 037; /* get reg offset */
if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */
@ -570,9 +589,10 @@ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */
update_rpcs (CS1_SC, drv); /* request intr */ update_rpcs (CS1_SC, drv); /* request intr */
return SCPE_OK; } return SCPE_OK; }
if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */ if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */
rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */ set_rper (ER1_RMR, drv); /* won't write */
update_rpcs (0, drv); update_rpcs (0, drv);
return SCPE_OK; } return SCPE_OK; }
rmhr[drv] = data;
switch (j) { /* decode PA<5:1> */ switch (j) { /* decode PA<5:1> */
case 000: /* RPCS1 */ case 000: /* RPCS1 */
@ -591,7 +611,7 @@ case 000: /* RPCS1 */
rpcs2 = rpcs2 | CS2_NED; /* set error flag */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */
cs1f = CS1_SC; } /* req interrupt */ cs1f = CS1_SC; } /* req interrupt */
else if (sim_is_active (uptr)) else if (sim_is_active (uptr))
rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */ set_rper (ER1_RMR, drv); /* won't write */
else if (data & CS1_GO) { /* start op */ else if (data & CS1_GO) { /* start op */
uptr->FUNC = GET_FNC (data); /* set func */ uptr->FUNC = GET_FNC (data); /* set func */
if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */ if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */
@ -610,9 +630,8 @@ case 002: /* RPBA */
rpba = data & ~BA_MBZ; rpba = data & ~BA_MBZ;
break; break;
case 003: /* RPDA */ case 003: /* RPDA */
if (access == WRITEB) data = (PA & 1)? if ((access == WRITEB) && (PA & 1)) data = data << 8;
(rpda & 0377) | (data << 8): (rpda & ~0377) | data; rpda[drv] = data & ~DA_MBZ;
rpda = data & ~DA_MBZ;
break; break;
case 004: /* RPCS2 */ case 004: /* RPCS2 */
if ((access == WRITEB) && (PA & 1)) data = data << 8; if ((access == WRITEB) && (PA & 1)) data = data << 8;
@ -626,8 +645,8 @@ case 004: /* RPCS2 */
drv = GET_UNIT (rpcs2); drv = GET_UNIT (rpcs2);
break; break;
case 006: /* RPER1 */ case 006: /* RPER1 */
if (access == WRITEB) break; if ((access == WRITEB) && (PA & 1)) data = data << 8;
rper1[drv] = rper1[drv] & data; rper1[drv] = data;
break; break;
case 007: /* RPAS */ case 007: /* RPAS */
if ((access == WRITEB) && (PA & 1)) break; if ((access == WRITEB) && (PA & 1)) break;
@ -640,32 +659,28 @@ case 011: /* RPDB */
rpdb = data; rpdb = data;
break; break;
case 012: /* RPMR */ case 012: /* RPMR */
if (access == WRITEB) data = (PA & 1)? if ((access == WRITEB) && (PA & 1)) data = data << 8;
(rpmr & 0377) | (data << 8): (rpmr & ~0377) | data; rpmr[drv] = data;
rpmr = data;
break; break;
case 015: /* RPOF */ case 015: /* RPOF */
if (access == WRITEB) data = (PA & 1)? rpof[drv] = data & ~OF_MBZ;
(rpof & 0377) | (data << 8): (rpof & ~0377) | data;
rpof = data & ~OF_MBZ;
break; break;
case 016: /* RPDC */ case 016: /* RPDC */
if (access == WRITEB) data = (PA & 1)? if ((access == WRITEB) && (PA & 1)) data = data << 8;
(rpdc & 0377) | (data << 8): (rpdc & ~0377) | data; rpdc[drv] = data & ~DC_MBZ;
rpdc = data & ~DC_MBZ;
break; break;
case 005: /* RPDS */ case 005: /* RPDS */
case 010: /* RPLA */ case 010: /* RPLA */
case 013: /* RPDT */ case 013: /* RPDT */
case 014: /* RPSN */ case 014: /* RPSN */
case 017: /* RPDC, RMHR */ case 017: /* RPCC, RMHR */
case 020: /* RPER2, RMMN2 */ case 020: /* RPER2, RMMR2 */
case 021: /* RPER3, RMER2 */ case 021: /* RPER3, RMER2 */
case 022: /* RPEC1 */ case 022: /* RPEC1 */
case 023: /* RPEC2 */ case 023: /* RPEC2 */
break; /* read only */ break; /* read only */
default: /* all others */ default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILR; set_rper (ER1_ILR, drv);
break; } /* end switch */ break; } /* end switch */
update_rpcs (cs1f, drv); /* update status */ update_rpcs (cs1f, drv); /* update status */
return SCPE_OK; return SCPE_OK;
@ -684,26 +699,25 @@ if (uptr->flags & UNIT_DIS) { /* nx unit? */
update_rpcs (CS1_SC, drv); /* request intr */ update_rpcs (CS1_SC, drv); /* request intr */
return; } return; }
if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */
rper1[drv] = rper1[drv] | ER1_ILF; /* not allowed */ set_rper (ER1_ILF, drv); /* set err, ATN */
rpds[drv] = rpds[drv] | DS_ATA; /* set attention */
update_rpcs (CS1_SC, drv); /* request intr */ update_rpcs (CS1_SC, drv); /* request intr */
return; } return; }
dtype = GET_DTYPE (uptr->flags); /* get drive type */ dtype = GET_DTYPE (uptr->flags); /* get drive type */
rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */ rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */
dc = rpdc; /* assume seek, sch */ dc = rpdc[drv]; /* assume seek, sch */
switch (fnc) { /* case on function */ switch (fnc) { /* case on function */
case FNC_DCLR: /* drive clear */ case FNC_DCLR: /* drive clear */
rpda = 0; /* clear disk addr */ rpda[drv] = 0; /* clear disk addr */
rper1[drv] = rper2 = rper3 = 0; /* clear errors */ rper1[drv] = rper2[drv] = rper3[drv] = 0; /* clear errors */
case FNC_NOP: /* no operation */ case FNC_NOP: /* no operation */
case FNC_RELEASE: /* port release */ case FNC_RELEASE: /* port release */
return; return;
case FNC_PRESET: /* read-in preset */ case FNC_PRESET: /* read-in preset */
rpdc = 0; /* clear disk addr */ rpdc[drv] = 0; /* clear disk addr */
rpda = 0; rpda[drv] = 0;
rpof = 0; /* clear offset */ rpof[drv] = 0; /* clear offset */
case FNC_PACK: /* pack acknowledge */ case FNC_PACK: /* pack acknowledge */
rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */ rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */
return; return;
@ -711,7 +725,7 @@ case FNC_PACK: /* pack acknowledge */
case FNC_OFFSET: /* offset mode */ case FNC_OFFSET: /* offset mode */
case FNC_RETURN: case FNC_RETURN:
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ set_rper (ER1_UNS, drv); /* unsafe */
break; } break; }
rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */
sim_activate (uptr, rp_swait); /* time operation */ sim_activate (uptr, rp_swait); /* time operation */
@ -723,12 +737,12 @@ case FNC_RECAL: /* recalibrate */
case FNC_SEEK: /* seek */ case FNC_SEEK: /* seek */
case FNC_SEARCH: /* search */ case FNC_SEARCH: /* search */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ set_rper (ER1_UNS, drv); /* unsafe */
break; } break; }
if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */
(GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */ (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */
rper1[drv] = rper1[drv] | ER1_IAE; set_rper (ER1_IAE, drv);
break; } break; }
rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */
t = abs (dc - uptr->CYL); /* cyl diff */ t = abs (dc - uptr->CYL); /* cyl diff */
@ -743,14 +757,14 @@ case FNC_WCHK: /* write check */
case FNC_READ: /* read */ case FNC_READ: /* read */
case FNC_READH: /* read headers */ case FNC_READH: /* read headers */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ set_rper (ER1_UNS, drv); /* unsafe */
break; } break; }
rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */
rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE); rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE);
if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */
(GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */ (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */
rper1[drv] = rper1[drv] | ER1_IAE; set_rper (ER1_IAE, drv);
break; } break; }
rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */
sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL))); sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL)));
@ -758,9 +772,8 @@ case FNC_READH: /* read headers */
return; return;
default: /* all others */ default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILF; /* not supported */ set_rper (ER1_ILF, drv); /* not supported */
break; } break; }
rpds[drv] = rpds[drv] | DS_ATA; /* error, set attn */
update_rpcs (CS1_SC, drv); /* req intr */ update_rpcs (CS1_SC, drv); /* req intr */
return; return;
} }
@ -815,7 +828,7 @@ case FNC_SEEK: /* seek */
case FNC_WRITE: /* write */ case FNC_WRITE: /* write */
if (uptr->flags & UNIT_WPRT) { /* write locked? */ if (uptr->flags & UNIT_WPRT) { /* write locked? */
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */ set_rper (ER1_WLE, drv); /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; } break; }
case FNC_WCHK: /* write check */ case FNC_WCHK: /* write check */
@ -823,9 +836,9 @@ case FNC_READ: /* read */
case FNC_READH: /* read headers */ case FNC_READH: /* read headers */
ba = GET_UAE (rpcs1) | rpba; /* get byte addr */ ba = GET_UAE (rpcs1) | rpba; /* get byte addr */
wc10 = (0200000 - rpwc) >> 1; /* get PDP-10 wc */ wc10 = (0200000 - rpwc) >> 1; /* get PDP-10 wc */
da = GET_DA (rpdc, rpda, dtype) * RP_NUMWD; /* get disk addr */ da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */
if ((da + wc10) > drv_tab[dtype].size) { /* disk overrun? */ if ((da + wc10) > drv_tab[dtype].size) { /* disk overrun? */
rper1[drv] = rper1[drv] | ER1_AOE; set_rper (ER1_AOE, drv);
if (wc10 > (drv_tab[dtype].size - da)) if (wc10 > (drv_tab[dtype].size - da))
wc10 = drv_tab[dtype].size - da; } wc10 = drv_tab[dtype].size - da; }
@ -884,13 +897,13 @@ case FNC_READH: /* read headers */
da = da + twc10 + (RP_NUMWD - 1); da = da + twc10 + (RP_NUMWD - 1);
if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST; if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST;
da = da / RP_NUMWD; da = da / RP_NUMWD;
rpda = da % drv_tab[dtype].sect; rpda[drv] = da % drv_tab[dtype].sect;
da = da / drv_tab[dtype].sect; da = da / drv_tab[dtype].sect;
rpda = rpda | ((da % drv_tab[dtype].surf) << DA_V_SF); rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF);
rpdc = da / drv_tab[dtype].surf; rpdc[drv] = da / drv_tab[dtype].surf;
if (err != 0) { /* error? */ if (err != 0) { /* error? */
rper1[drv] = rper1[drv] | ER1_PAR; /* set drive error */ set_rper (ER1_PAR, drv); /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
perror ("RP I/O error"); perror ("RP I/O error");
clearerr (uptr->fileref); clearerr (uptr->fileref);
@ -901,6 +914,16 @@ case FNC_WRITEH: /* write headers stub */
return SCPE_OK; return SCPE_OK;
} }
/* Set drive error */
void set_rper (int32 flag, int32 drv)
{
rper1[drv] = rper1[drv] | flag;
rpds[drv] = rpds[drv] | DS_ATA;
rpcs1 = rpcs1 | CS1_SC;
return;
}
/* Controller status update /* Controller status update
Check for done transition Check for done transition
@ -921,7 +944,8 @@ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0;
else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM;
if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL; if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL;
else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY);
if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA; if (rper1[drv] | rper2[drv] | rper3[drv])
rpds[drv] = rpds[drv] | DS_ERR;
else rpds[drv] = rpds[drv] & ~DS_ERR; else rpds[drv] = rpds[drv] & ~DS_ERR;
rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag;
@ -955,10 +979,7 @@ UNIT *uptr;
rpcs1 = CS1_DVA | CS1_DONE; rpcs1 = CS1_DVA | CS1_DONE;
rpcs2 = CS2_IR | CS2_OR; rpcs2 = CS2_IR | CS2_OR;
rpba = rpda = 0; rpba = rpwc = 0;
rpof = rpdc = 0;
rper2 = rper3 = 0;
rpec1 = rpec2 = 0;
rpiff = 0; /* clear CSTB INTR */ rpiff = 0; /* clear CSTB INTR */
int_req = int_req & ~INT_RP; /* clear intr req */ int_req = int_req & ~INT_RP; /* clear intr req */
for (i = 0; i < RP_NUMDR; i++) { for (i = 0; i < RP_NUMDR; i++) {
@ -969,7 +990,17 @@ for (i = 0; i < RP_NUMDR; i++) {
DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? 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 if (uptr->flags & UNIT_DIS) rpds[i] = 0;
else rpds[i] = DS_DPR; else rpds[i] = DS_DPR;
rper1[i] = 0; } rper1[i] = 0;
rper2[i] = 0;
rper3[i] = 0;
rpda[i] = 0;
rpdc[i] = 0;
rpmr[i] = 0;
rpof[i] = 0;
rpec1[i] = 0;
rpec2[i] = 0;
rmmr2[i] = 0;
rmhr[i] = 0; }
return SCPE_OK; return SCPE_OK;
} }
@ -1021,8 +1052,10 @@ return detach_unit (uptr);
t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{ {
int32 dtype = GET_DTYPE (val);
if (uptr->flags & UNIT_ATT) return SCPE_ALATT; if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
uptr->capac = drv_tab[GET_DTYPE (val)].size; uptr->capac = drv_tab[dtype].size;
return SCPE_OK; return SCPE_OK;
} }

View file

@ -25,6 +25,12 @@
tu RH11/TM03/TU45 magtape tu RH11/TM03/TU45 magtape
23-Oct-04 RMS Fixed setting done on non data transfers
01-Oct-04 RMS Modified to set FCE on read short record, eof
Implemented write check
TM03 uses only den<2> for validity test
TMK is cleared by new motion command, not DCLR
14-Sep-04 RMS Fixed RIP value
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
28-Mar-03 RMS Added multiformat support 28-Mar-03 RMS Added multiformat support
28-Feb-03 RMS Revised for magtape library 28-Feb-03 RMS Revised for magtape library
@ -85,13 +91,14 @@
#define USTAT u3 /* unit status */ #define USTAT u3 /* unit status */
#define UDENS u4 /* unit density */ #define UDENS u4 /* unit density */
#define UD_UNK 0 /* unknown */ #define UD_UNK 0 /* unknown */
#define MT_MAXFR (1 << 16) /* max data buf */ #define MT_MAXFR (1 << 16) /* max data buf */
/* MTCS1 - 172440 - control/status 1 */ /* MTCS1 - 172440 - control/status 1 */
#define CS1_GO CSR_GO /* go */ #define CS1_GO CSR_GO /* go */
#define CS1_V_FNC 1 /* function pos */ #define CS1_V_FNC 1 /* function pos */
#define CS1_M_FNC 037 /* function mask */ #define CS1_M_FNC 037 /* function mask */
#define CS1_N_FNC (CS1_M_FNC + 1)
#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) #define CS1_FNC (CS1_M_FNC << CS1_V_FNC)
#define FNC_NOP 000 /* no operation */ #define FNC_NOP 000 /* no operation */
#define FNC_UNLOAD 001 /* unload */ #define FNC_UNLOAD 001 /* unload */
@ -146,7 +153,7 @@
#define CS2_NEM 0004000 /* nx mem err */ #define CS2_NEM 0004000 /* nx mem err */
#define CS2_NEF 0010000 /* nx fmter err */ #define CS2_NEF 0010000 /* nx fmter err */
#define CS2_PE 0020000 /* parity err NI */ #define CS2_PE 0020000 /* parity err NI */
#define CS2_WCE 0040000 /* write chk err NI */ #define CS2_WCE 0040000 /* write chk err */
#define CS2_DLT 0100000 /* data late NI */ #define CS2_DLT 0100000 /* data late NI */
#define CS2_MBZ (CS2_CLR | CS2_WCE) #define CS2_MBZ (CS2_CLR | CS2_WCE)
#define CS2_RW (CS2_FMTR | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE) #define CS2_RW (CS2_FMTR | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE)
@ -214,6 +221,7 @@
/* MTDT - 172466 - drive type */ /* MTDT - 172466 - drive type */
#define DT_NSA 0100000 /* not sect addr */
#define DT_TAPE 0040000 /* tape */ #define DT_TAPE 0040000 /* tape */
#define DT_PRES 0002000 /* slave present */ #define DT_PRES 0002000 /* slave present */
#define DT_TM03 0000040 /* TM03 formatter */ #define DT_TM03 0000040 /* TM03 formatter */
@ -243,6 +251,7 @@
#define TC_ACC 0100000 /* accelerating NI */ #define TC_ACC 0100000 /* accelerating NI */
#define TC_RW 0013777 #define TC_RW 0013777
#define TC_MBZ 0004000 #define TC_MBZ 0004000
#define TC_RIP ((TC_800 << TC_V_DEN) || (TC_10C << TC_V_FMT))
#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN) #define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)
#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT) #define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)
#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT) #define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)
@ -280,6 +289,8 @@ extern int32 int_vec[32];
extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */ extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */
extern int32 ubcs[UBANUM]; extern int32 ubcs[UBANUM];
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern int32 sim_switches;
extern FILE *sim_deb;
int32 tucs1 = 0; /* control/status 1 */ int32 tucs1 = 0; /* control/status 1 */
int32 tuwc = 0; /* word count */ int32 tuwc = 0; /* word count */
@ -304,8 +315,11 @@ int32 reg_in_fmtr1[32] = { /* rmr if write + go */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int32 fmt_test[16] = { /* fmt bytes/10 wd */ int32 fmt_test[16] = { /* fmt bytes/10 wd */
5, 0, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 5, 0, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32 den_test[8] = { /* valid densities */ static char *tu_fname[CS1_N_FNC] = {
0, 0, 0, 1, 1, 0, 0, 0 }; "NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",
"RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",
"20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",
"WRITE", "31", "32", "33", "READF", "35", "36" "READR" };
static uint8 *xbuf = NULL; /* xfer buffer */ static uint8 *xbuf = NULL; /* xfer buffer */
t_stat tu_rd (int32 *data, int32 PA, int32 access); t_stat tu_rd (int32 *data, int32 PA, int32 access);
@ -317,6 +331,7 @@ t_stat tu_attach (UNIT *uptr, char *cptr);
t_stat tu_detach (UNIT *uptr); t_stat tu_detach (UNIT *uptr);
t_stat tu_boot (int32 unitno, DEVICE *dptr); t_stat tu_boot (int32 unitno, DEVICE *dptr);
void tu_go (int32 drv); void tu_go (int32 drv);
void set_tuer (int32 flag);
void update_tucs (int32 flag, int32 drv); void update_tucs (int32 flag, int32 drv);
t_stat tu_map_err (UNIT *uptr, t_stat st); t_stat tu_map_err (UNIT *uptr, t_stat st);
@ -381,7 +396,7 @@ DEVICE tu_dev = {
TU_NUMDR, 10, 31, 1, 8, 8, TU_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &tu_reset, NULL, NULL, &tu_reset,
&tu_boot, &tu_attach, &tu_detach, &tu_boot, &tu_attach, &tu_detach,
&tu_dib, DEV_UBUS }; &tu_dib, DEV_UBUS | DEV_DEBUG };
/* I/O dispatch routine, I/O addresses 17772440 - 17772472 */ /* I/O dispatch routine, I/O addresses 17772440 - 17772472 */
@ -435,8 +450,8 @@ case 012: /* MTMR */
*data = tumr; *data = tumr;
break; break;
case 013: /* MTDT */ case 013: /* MTDT */
*data = DT_TAPE | DT_TM03 | ((tu_unit[drv].flags & UNIT_DIS)? *data = DT_NSA | DT_TAPE | DT_TM03 |
DT_OFF: (DT_PRES | DT_TU45)); ((tu_unit[drv].flags & UNIT_DIS)? DT_OFF: (DT_PRES | DT_TU45));
break; break;
case 014: /* MTSN */ case 014: /* MTSN */
*data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1); *data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1);
@ -445,7 +460,7 @@ case 015: /* MTTC */
*data = tutc = tutc & ~TC_MBZ; *data = tutc = tutc & ~TC_MBZ;
break; break;
default: /* all others */ default: /* all others */
tuer = tuer | ER_ILR; set_tuer (ER_ILR);
update_tucs (0, drv); update_tucs (0, drv);
break; } break; }
return SCPE_OK; return SCPE_OK;
@ -464,7 +479,7 @@ if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */
update_tucs (CS1_SC, drv); /* request intr */ update_tucs (CS1_SC, drv); /* request intr */
return SCPE_OK; } return SCPE_OK; }
if (reg_in_fmtr1[j] && ((tucs1 & CS1_DONE) == 0)) { /* formatter busy? */ if (reg_in_fmtr1[j] && ((tucs1 & CS1_DONE) == 0)) { /* formatter busy? */
tuer = tuer | ER_RMR; /* won't write */ set_tuer (ER_RMR); /* won't write */
update_tucs (0, drv); update_tucs (0, drv);
return SCPE_OK; } return SCPE_OK; }
@ -485,7 +500,7 @@ case 000: /* MTCS1 */
tucs2 = tucs2 | CS2_NEF; /* set error flag */ tucs2 = tucs2 | CS2_NEF; /* set error flag */
cs1f = CS1_SC; } /* req interrupt */ cs1f = CS1_SC; } /* req interrupt */
else if (tucs1 & CS1_GO) { /* busy? */ else if (tucs1 & CS1_GO) { /* busy? */
if (tucs1 & CS1_DONE) tuer = tuer | ER_RMR; if (tucs1 & CS1_DONE) set_tuer (ER_RMR);
else tucs2 = tucs2 | CS2_PGE; } else tucs2 = tucs2 | CS2_PGE; }
else { else {
tucs1 = (tucs1 & ~CS1_DRV) | (data & CS1_DRV); tucs1 = (tucs1 & ~CS1_DRV) | (data & CS1_DRV);
@ -544,7 +559,7 @@ case 013: /* MTDT */
case 014: /* MTSN */ case 014: /* MTSN */
break; /* read only */ break; /* read only */
default: /* all others */ default: /* all others */
tuer = tuer | ER_ILR; set_tuer (ER_ILR);
break; } /* end switch */ break; } /* end switch */
update_tucs (cs1f, drv); /* update status */ update_tucs (cs1f, drv); /* update status */
return SCPE_OK; return SCPE_OK;
@ -560,10 +575,12 @@ UNIT *uptr;
fnc = GET_FNC (tucs1); /* get function */ fnc = GET_FNC (tucs1); /* get function */
den = GET_DEN (tutc); /* get density */ den = GET_DEN (tutc); /* get density */
uptr = tu_dev.units + drv; /* get unit */ uptr = tu_dev.units + drv; /* get unit */
if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
">>TU%d STRT: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos);
if ((fnc != FNC_FCLR) && /* not clear & err */ if ((fnc != FNC_FCLR) && /* not clear & err */
((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */ ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */
tuer = tuer | ER_ILF; /* set error flag */ set_tuer (ER_ILF); /* set err, ATN */
tufs = tufs | FS_ATA; /* exception */
tucs1 = tucs1 & ~CS1_GO; /* clear go */ tucs1 = tucs1 & ~CS1_GO; /* clear go */
update_tucs (CS1_SC, drv); /* request intr */ update_tucs (CS1_SC, drv); /* request intr */
return; } return; }
@ -574,45 +591,48 @@ switch (fnc) { /* case on function */
case FNC_FCLR: /* drive clear */ case FNC_FCLR: /* drive clear */
tuer = 0; /* clear errors */ tuer = 0; /* clear errors */
tutc = tutc & ~TC_FCS; /* clear fc status */ tutc = tutc & ~TC_FCS; /* clear fc status */
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_TMK | FS_ERR); tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
sim_cancel (uptr); /* reset drive */ sim_cancel (uptr); /* reset drive */
uptr->USTAT = 0; uptr->USTAT = 0;
case FNC_NOP: case FNC_NOP:
tucs1 = tucs1 & ~CS1_GO; /* no operation */ tucs1 = tucs1 & ~CS1_GO; /* no operation */
return; return;
case FNC_RIP: /* read-in preset */ case FNC_RIP: /* read-in preset */
tutc = TC_800; /* density = 800 */ tutc = TC_RIP; /* density = 800 */
sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
tu_unit[0].USTAT = 0; tu_unit[0].USTAT = 0;
tucs1 = tucs1 & ~CS1_GO; tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return; return;
case FNC_UNLOAD: /* unload */ case FNC_UNLOAD: /* unload */
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS; set_tuer (ER_UNS);
break; } break; }
detach_unit (uptr); detach_unit (uptr);
uptr->USTAT = FS_REW; uptr->USTAT = FS_REW;
sim_activate (uptr, tu_time); sim_activate (uptr, tu_time);
tucs1 = tucs1 & ~CS1_GO; tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return; return;
case FNC_REWIND: case FNC_REWIND:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS; set_tuer (ER_UNS);
break; } break; }
uptr->USTAT = FS_PIP | FS_REW; uptr->USTAT = FS_PIP | FS_REW;
sim_activate (uptr, tu_time); sim_activate (uptr, tu_time);
tucs1 = tucs1 & ~CS1_GO; tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return; return;
case FNC_SPACEF: case FNC_SPACEF:
space_test = FS_EOT; space_test = FS_EOT;
case FNC_SPACER: case FNC_SPACER:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS; set_tuer (ER_UNS);
break; } break; }
if ((tufs & space_test) || ((tutc & TC_FCS) == 0)) { if ((tufs & space_test) || ((tutc & TC_FCS) == 0)) {
tuer = tuer | ER_NXF; set_tuer (ER_NXF);
break; } break; }
uptr->USTAT = FS_PIP; uptr->USTAT = FS_PIP;
goto GO_XFER; goto GO_XFER;
@ -620,36 +640,30 @@ case FNC_SPACER:
case FNC_WCHKR: /* wchk = read */ case FNC_WCHKR: /* wchk = read */
case FNC_READR: /* read rev */ case FNC_READR: /* read rev */
if (tufs & FS_BOT) { /* beginning of tape? */ if (tufs & FS_BOT) { /* beginning of tape? */
tuer = tuer | ER_NXF; set_tuer (ER_NXF);
break; } break; }
goto DATA_XFER; goto DATA_XFER;
case FNC_WRITE: /* write */ case FNC_WRITE: /* write */
if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */ if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */
((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */ ((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */
tuer = tuer | ER_NXF; set_tuer (ER_NXF);
break; } break; }
case FNC_WREOF: /* write tape mark */ case FNC_WREOF: /* write tape mark */
case FNC_ERASE: /* erase */ case FNC_ERASE: /* erase */
if (sim_tape_wrp (uptr)) { /* write locked? */ if (sim_tape_wrp (uptr)) { /* write locked? */
tuer = tuer | ER_NXF; set_tuer (ER_NXF);
break; } break; }
case FNC_WCHKF: /* wchk = read */ case FNC_WCHKF: /* wchk = read */
case FNC_READF: /* read */ case FNC_READF: /* read */
DATA_XFER: DATA_XFER:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tuer = tuer | ER_UNS; set_tuer (ER_UNS);
break; } break; }
if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */ if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */
tuer = tuer | ER_FER; set_tuer (ER_FER);
break; }
if (den_test[den] == 0) { /* invalid density? */
tuer = tuer | ER_NXF;
break; } break; }
if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */ if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */
/* else if (uptr->UDENS != den) { /* density mismatch? */
/* tuer = tuer | ER_NXF;
/* break; } */
uptr->USTAT = 0; uptr->USTAT = 0;
tucs1 = tucs1 & ~CS1_DONE; /* clear done */ tucs1 = tucs1 & ~CS1_DONE; /* clear done */
GO_XFER: GO_XFER:
@ -660,10 +674,9 @@ GO_XFER:
return; return;
default: /* all others */ default: /* all others */
tuer = tuer | ER_ILF; /* not supported */ set_tuer (ER_ILF); /* not supported */
break; } /* end case function */ break; } /* end case function */
tucs1 = tucs1 & ~CS1_GO; /* clear go */ tucs1 = tucs1 & ~CS1_GO; /* clear go */
tufs = tufs | FS_ATA; /* set attn */
update_tucs (CS1_SC, drv); /* set intr */ update_tucs (CS1_SC, drv); /* set intr */
return; return;
} }
@ -677,7 +690,7 @@ return;
t_stat tu_svc (UNIT *uptr) t_stat tu_svc (UNIT *uptr)
{ {
int32 f, fmt, i, j, k, wc10, ba10; int32 fnc, fmt, i, j, k, wc10, ba10;
int32 ba, fc, wc, drv, mpa10, vpn; int32 ba, fc, wc, drv, mpa10, vpn;
d10 val, v[4]; d10 val, v[4];
t_mtrlnt tbc; t_mtrlnt tbc;
@ -691,7 +704,7 @@ if (uptr->USTAT & FS_REW) { /* rewind or unload? */
update_tucs (CS1_SC, drv); /* update status */ update_tucs (CS1_SC, drv); /* update status */
return SCPE_OK; } return SCPE_OK; }
f = GET_FNC (tucs1); /* get command */ fnc = GET_FNC (tucs1); /* get command */
fmt = GET_FMT (tutc); /* get format */ fmt = GET_FMT (tutc); /* get format */
ba = GET_UAE (tucs1) | tuba; /* get bus address */ ba = GET_UAE (tucs1) | tuba; /* get bus address */
wc = 0200000 - tuwc; /* get word count */ wc = 0200000 - tuwc; /* get word count */
@ -700,7 +713,7 @@ wc10 = wc >> 1; /* 10 word count */
ba10 = ba >> 2; /* 10 word addr */ ba10 = ba >> 2; /* 10 word addr */
uptr->USTAT = 0; /* clear status */ uptr->USTAT = 0; /* clear status */
switch (f) { /* case on function */ switch (fnc) { /* case on function */
/* Unit service - non-data transfer commands - set ATA when done */ /* Unit service - non-data transfer commands - set ATA when done */
@ -712,7 +725,7 @@ case FNC_SPACEF: /* space forward */
break; } break; }
} }
while (tufc != 0); while (tufc != 0);
if (tufc) tuer = tuer | ER_FCE; if (tufc) set_tuer (ER_FCE);
else tutc = tutc & ~TC_FCS; else tutc = tutc & ~TC_FCS;
tufs = tufs | FS_ATA; tufs = tufs | FS_ATA;
break; break;
@ -725,7 +738,7 @@ case FNC_SPACER: /* space reverse */
break; } break; }
} }
while (tufc != 0); while (tufc != 0);
if (tufc) tuer = tuer | ER_FCE; if (tufc) set_tuer (ER_FCE);
else tutc = tutc & ~TC_FCS; else tutc = tutc & ~TC_FCS;
tufs = tufs | FS_ATA; tufs = tufs | FS_ATA;
break; break;
@ -770,11 +783,15 @@ case FNC_WCHKF: /* wcheck = read */
for (k = 0; k < 4; k++) v[k] = xbuf[j++]; for (k = 0; k < 4; k++) v[k] = xbuf[j++];
val = (v[0] << 28) | (v[1] << 20) | (v[2] << 12) | (v[3] << 4); val = (v[0] << 28) | (v[1] << 20) | (v[2] << 12) | (v[3] << 4);
if (fmt == TC_10C) val = val | ((d10) xbuf[j++] & 017); if (fmt == TC_10C) val = val | ((d10) xbuf[j++] & 017);
if (f == FNC_READF) M[mpa10] = val; if (fnc == FNC_READF) M[mpa10] = val; /* read? store */
else if (M[mpa10] != val) { /* wchk, mismatch? */
tucs2 = tucs2 | CS2_WCE; /* flag, stop */
break; }
mpa10 = mpa10 + 1; } /* end for */ mpa10 = mpa10 + 1; } /* end for */
tufc = tbc & 0177777; tufc = tbc & 0177777;
tuwc = (tuwc + (i << 1)) & 0177777; tuwc = (tuwc + (i << 1)) & 0177777;
ba = ba + (i << 2); ba = ba + (i << 2);
if (tuwc) set_tuer (ER_FCE); /* short record? */
break; break;
case FNC_WRITE: /* write */ case FNC_WRITE: /* write */
@ -813,20 +830,38 @@ case FNC_WCHKR: /* wcheck = read */
val = ((fmt == TC_10C)? (((d10) xbuf [--j]) & 017): 0); val = ((fmt == TC_10C)? (((d10) xbuf [--j]) & 017): 0);
for (k = 0; k < 4; i++) v[k] = xbuf[--j]; for (k = 0; k < 4; i++) v[k] = xbuf[--j];
val = val | (v[0] << 4) | (v[1] << 12) | (v[2] << 20) | (v[3] << 28); val = val | (v[0] << 4) | (v[1] << 12) | (v[2] << 20) | (v[3] << 28);
if (f == FNC_READR) M[mpa10] = val; if (fnc == FNC_READR) M[mpa10] = val; /* read? store */
else if (M[mpa10] != val) { /* wchk, mismatch? */
tucs2 = tucs2 | CS2_WCE; /* flag, stop */
break; }
mpa10 = mpa10 - 1; } /* end for */ mpa10 = mpa10 - 1; } /* end for */
tufc = tbc & 0177777; tufc = tbc & 0177777;
tuwc = (tuwc + (i << 1)) & 0177777; tuwc = (tuwc + (i << 1)) & 0177777;
ba = ba - (i << 2); ba = ba - (i << 2);
if (tuwc) set_tuer (ER_FCE); /* short record? */
break; } /* end case */ break; } /* end case */
tucs1 = (tucs1 & ~CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE); tucs1 = (tucs1 & ~CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE);
tuba = ba & 0177777; /* update mem addr */ tuba = ba & 0177777; /* update mem addr */
tucs1 = tucs1 & ~CS1_GO; /* clear go */ tucs1 = tucs1 & ~CS1_GO; /* clear go */
update_tucs (CS1_DONE, drv); if (fnc >= FNC_XFER) update_tucs (CS1_DONE, drv); /* data xfer? */
else update_tucs (CS1_SC, drv); /* no, set attn */
if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
">>TU%d DONE: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos);
return SCPE_OK; return SCPE_OK;
} }
/* Formatter error */
void set_tuer (int32 flag)
{
tuer = tuer | flag;
tufs = tufs | FS_ATA;
tucs1 = tucs1 | CS1_SC;
return;
}
/* Controller status update /* Controller status update
Check for done transition Check for done transition
@ -877,29 +912,30 @@ t_stat tu_map_err (UNIT *uptr, t_stat st)
switch (st) { switch (st) {
case MTSE_FMT: /* illegal fmt */ case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* not attached */ case MTSE_UNATT: /* not attached */
tuer = tuer | ER_NXF; /* can't execute */ set_tuer (ER_NXF); /* can't execute */
case MTSE_OK: /* no error */ case MTSE_OK: /* no error */
return SCPE_IERR; return SCPE_IERR;
case MTSE_TMK: /* end of file */ case MTSE_TMK: /* end of file */
tufs = tufs | FS_TMK; tufs = tufs | FS_TMK;
set_tuer (ER_FCE); /* also sets FCE */
break; break;
case MTSE_IOERR: /* IO error */ case MTSE_IOERR: /* IO error */
tuer = tuer | ER_VPE; /* flag error */ set_tuer (ER_VPE); /* flag error */
if (tu_stopioe) return SCPE_IOERR; if (tu_stopioe) return SCPE_IOERR;
break; break;
case MTSE_INVRL: /* invalid rec lnt */ case MTSE_INVRL: /* invalid rec lnt */
tuer = tuer | ER_VPE; /* flag error */ set_tuer (ER_VPE); /* flag error */
return SCPE_MTRLNT; return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */ case MTSE_RECE: /* record in error */
tuer = tuer | ER_CRC; /* set crc err */ set_tuer (ER_CRC); /* set crc err */
break; break;
case MTSE_EOM: /* end of medium */ case MTSE_EOM: /* end of medium */
tuer = tuer | ER_OPI; /* incomplete */ set_tuer (ER_OPI); /* incomplete */
break; break;
case MTSE_BOT: /* reverse into BOT */ case MTSE_BOT: /* reverse into BOT */
break; break;
case MTSE_WRP: /* write protect */ case MTSE_WRP: /* write protect */
tuer = tuer | ER_NXF; /* can't execute */ set_tuer (ER_NXF); /* can't execute */
break; } break; }
return SCPE_OK; return SCPE_OK;
} }
@ -913,9 +949,13 @@ UNIT *uptr;
tucs1 = CS1_DVA | CS1_DONE; tucs1 = CS1_DVA | CS1_DONE;
tucs2 = CS2_IR | CS2_OR; tucs2 = CS2_IR | CS2_OR;
tuba = tufc = 0; tuba = 0;
tutc = tuer = 0; tuwc = 0;
tufc = 0;
tuer = 0;
tufs = FS_FPR | FS_RDY; tufs = FS_FPR | FS_RDY;
if (sim_switches & SWMASK ('P')) tutc = 0; /* powerup? clr TC */
else tutc = tutc & ~TC_FCS; /* no, clr <fcs> */
tuiff = 0; /* clear CSTB INTR */ tuiff = 0; /* clear CSTB INTR */
int_req = int_req & ~INT_TU; /* clear interrupt */ int_req = int_req & ~INT_TU; /* clear interrupt */
for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */

View file

@ -25,6 +25,7 @@
This module simulates the PDP-11 commercial instruction set (CIS). This module simulates the PDP-11 commercial instruction set (CIS).
16-Sep-04 RMS Fixed bug in CMPP/N of negative strings
17-Oct-02 RMS Fixed compiler warning (found by Hans Pufal) 17-Oct-02 RMS Fixed compiler warning (found by Hans Pufal)
08-Oct-02 RMS Fixed macro definitions 08-Oct-02 RMS Fixed macro definitions
@ -154,8 +155,8 @@
#define MAXDVAL 429496730 /* 2^32 / 10 */ #define MAXDVAL 429496730 /* 2^32 / 10 */
struct dstr { struct dstr {
unsigned int32 sign; uint32 sign;
unsigned int32 val[DSTRLNT]; }; uint32 val[DSTRLNT]; };
typedef struct dstr DSTR; typedef struct dstr DSTR;
@ -175,8 +176,8 @@ void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst);
int32 CmpDstr (DSTR *src1, DSTR *src2); int32 CmpDstr (DSTR *src1, DSTR *src2);
int32 TestDstr (DSTR *dsrc); int32 TestDstr (DSTR *dsrc);
int32 LntDstr (DSTR *dsrc, int32 nz); int32 LntDstr (DSTR *dsrc, int32 nz);
unsigned int32 NibbleLshift (DSTR *dsrc, int32 sc, unsigned int32 cin); uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin);
unsigned int32 NibbleRshift (DSTR *dsrc, int32 sc, unsigned int32 cin); uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin);
int32 WordLshift (DSTR *dsrc, int32 sc); int32 WordLshift (DSTR *dsrc, int32 sc);
void WordRshift (DSTR *dsrc, int32 sc); void WordRshift (DSTR *dsrc, int32 sc);
void CreateTable (DSTR *dsrc, DSTR mtable[10]); void CreateTable (DSTR *dsrc, DSTR mtable[10]);
@ -738,8 +739,9 @@ case 052: case 072: case 0152: case 0172:
if (src1.sign != src2.sign) N = src1.sign; if (src1.sign != src2.sign) N = src1.sign;
else { else {
t = CmpDstr (&src1, &src2); /* compare strings */ t = CmpDstr (&src1, &src2); /* compare strings */
if (t < 0) N = 1; if (t < 0) N = (src1.sign? 0: 1);
else if (t == 0) Z = 1; } else if (t > 0) N = (src1.sign? 1: 0);
else Z = 1; }
if ((op & INLINE) == 0) /* if reg, clr reg */ if ((op & INLINE) == 0) /* if reg, clr reg */
R[0] = R[1] = R[2] = R[3] = 0; R[0] = R[1] = R[2] = R[3] = 0;
return; return;
@ -1073,7 +1075,7 @@ return;
int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy) int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy)
{ {
int32 i; int32 i;
unsigned int32 sm1, sm2, tm1, tm2, tm3, tm4; uint32 sm1, sm2, tm1, tm2, tm3, tm4;
for (i = 0; i < DSTRLNT; i++) { /* loop low to high */ for (i = 0; i < DSTRLNT; i++) { /* loop low to high */
tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */ tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */
@ -1226,7 +1228,7 @@ return c;
cin = carry in cin = carry in
*/ */
unsigned int32 NibbleRshift (DSTR *dsrc, int32 sc, unsigned int32 cin) uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin)
{ {
int32 i, s, rs, nc; int32 i, s, rs, nc;
@ -1249,7 +1251,7 @@ return 0;
cin = carry in cin = carry in
*/ */
unsigned int32 NibbleLshift (DSTR *dsrc, int32 sc, unsigned int32 cin) uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin)
{ {
int32 i, s, rs, nc; int32 i, s, rs, nc;

File diff suppressed because it is too large Load diff

977
PDP11/pdp11_cpumod.c Normal file
View file

@ -0,0 +1,977 @@
/* pdp11_cpumod.c: PDP-11 CPU model-specific features
Copyright (c) 2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
system PDP-11 model-specific registers
This module includes CPU- and system-specific registers, such as the Unibus
map and control registers on 22b Unibus systems, the board registers for the
F11- and J11-based systems, and the system registers for the PDP-11/44,
PDP-11/45, PDP-11/60, and PDP-11/70. Most registers are implemented at
a minimum level: just enough to satisfy the machine identification code
in the various operating systems.
*/
#include "pdp11_defs.h"
#include "pdp11_cpumod.h"
#include <time.h>
/* Byte write macros for system registers */
#define ODD_IGN(cur) \
if ((access == WRITEB) && (pa & 1)) return SCPE_OK
#define ODD_WO(cur) \
if ((access == WRITEB) && (pa & 1)) cur = cur << 8
#define ODD_MRG(prv,cur) \
if (access == WRITEB) cur = \
((pa & 1)? (((prv) & 0377) | ((cur) & 0177400)) : \
(((prv) & 0177400) | ((cur) & 0377)))
int32 SR = 0; /* switch register */
int32 DR = 0; /* display register */
int32 MBRK = 0; /* 11/70 microbreak */
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; /* maint reg */
int32 JCSR = 0; /* J11 control */
int32 JPCR = 0; /* J11 page ctrl */
int32 JASR = 0; /* J11 addtl status */
int32 UDCR = 0; /* UBA diag ctrl */
int32 UDDR = 0; /* UBA diag data */
int32 UCSR = 0; /* UBA control */
int32 uba_last = 0; /* UBA last mapped */
int32 ub_map[UBM_LNT_LW] = { 0 }; /* UBA map array */
int32 toy_state = 0;
uint8 toy_data[TOY_LNT] = { 0 };
static int32 clk_tps_map[4] = { 60, 60, 50, 800 };
extern uint16 *M;
extern int32 R[8];
extern DEVICE cpu_dev, *sim_devices[];
extern UNIT cpu_unit;
extern FILE *sim_log;
extern int32 STKLIM, PIRQ;
extern int32 cpu_model, cpu_type, cpu_opt;
extern int32 clk_fie, clk_fnxm, clk_tps, clk_default;
t_stat CPU24_rd (int32 *data, int32 addr, int32 access);
t_stat CPU24_wr (int32 data, int32 addr, int32 access);
t_stat CPU44_rd (int32 *data, int32 addr, int32 access);
t_stat CPU44_wr (int32 data, int32 addr, int32 access);
t_stat CPU45_rd (int32 *data, int32 addr, int32 access);
t_stat CPU45_wr (int32 data, int32 addr, int32 access);
t_stat CPU60_rd (int32 *data, int32 addr, int32 access);
t_stat CPU60_wr (int32 data, int32 addr, int32 access);
t_stat CPU70_rd (int32 *data, int32 addr, int32 access);
t_stat CPU70_wr (int32 data, int32 addr, int32 access);
t_stat CPUJ_rd (int32 *data, int32 addr, int32 access);
t_stat CPUJ_wr (int32 data, int32 addr, int32 access);
t_stat REG_rd (int32 *data, int32 addr, int32 access);
t_stat REG_wr (int32 data, int32 addr, int32 access);
t_stat SR_rd (int32 *data, int32 addr, int32 access);
t_stat DR_wr (int32 data, int32 addr, int32 access);
t_stat CTLFB_rd (int32 *data, int32 addr, int32 access);
t_stat CTLFB_wr (int32 data, int32 addr, int32 access);
t_stat CTLJB_rd (int32 *data, int32 addr, int32 access);
t_stat CTLJB_wr (int32 data, int32 addr, int32 access);
t_stat CTLJD_rd (int32 *data, int32 addr, int32 access);
t_stat CTLJD_wr (int32 data, int32 addr, int32 access);
t_stat CTLJE_rd (int32 *data, int32 addr, int32 access);
t_stat CTLJE_wr (int32 data, int32 addr, int32 access);
t_stat UBA24_rd (int32 *data, int32 addr, int32 access);
t_stat UBA24_wr (int32 data, int32 addr, int32 access);
t_stat UBAJ_rd (int32 *data, int32 addr, int32 access);
t_stat UBAJ_wr (int32 data, int32 addr, int32 access);
t_stat sys_reset (DEVICE *dptr);
int32 toy_read (void);
void toy_write (int32 bit);
uint8 toy_set (int32 val);
extern t_stat PSW_rd (int32 *data, int32 addr, int32 access);
extern t_stat PSW_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 MMR012_rd (int32 *data, int32 addr, int32 access);
extern t_stat 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 void put_PIRQ (int32 val);
/* Fixed I/O address table entries */
DIB psw_dib = { IOBA_PSW, IOLN_PSW, &PSW_rd, &PSW_wr, 0 };
DIB cpuj_dib = { IOBA_CPU, IOLN_CPU, &CPUJ_rd, &CPUJ_wr, 0 };
DIB cpu24_dib = { IOBA_CPU, IOLN_CPU, &CPU24_rd, &CPU24_wr, 0 };
DIB cpu44_dib = { IOBA_CPU, IOLN_CPU, &CPU44_rd, &CPU44_wr, 0 };
DIB cpu45_dib = { IOBA_CPU, IOLN_CPU, &CPU45_rd, &CPU45_wr, 0 };
DIB cpu60_dib = { IOBA_CPU, IOLN_CPU, &CPU60_rd, &CPU60_wr, 0 };
DIB cpu70_dib = { IOBA_CPU, IOLN_CPU, &CPU70_rd, &CPU70_wr, 0 };
DIB reg_dib = { IOBA_GPR, IOLN_GPR, &REG_rd, &REG_wr, 0 };
DIB ctlfb_dib = { IOBA_CTL, IOLN_CTL, &CTLFB_rd, &CTLFB_wr };
DIB ctljb_dib = { IOBA_CTL, IOLN_CTL, &CTLJB_rd, &CTLJB_wr };
DIB ctljd_dib = { IOBA_CTL, IOLN_CTL, &CTLJD_rd, &CTLJD_wr };
DIB ctlje_dib = { IOBA_CTL, IOLN_CTL, &CTLJE_rd, &CTLJE_wr };
DIB uba24_dib = { IOBA_UCTL, IOLN_UCTL, &UBA24_rd, &UBA24_wr };
DIB ubaj_dib = {IOBA_UCTL, IOLN_UCTL, &UBAJ_rd, &UBAJ_wr };
DIB supv_dib = { IOBA_SUP, IOLN_SUP, &APR_rd, &APR_wr, 0 };
DIB kipdr_dib = { IOBA_KIPDR, IOLN_KIPDR, &APR_rd, &APR_wr, 0 };
DIB kdpdr_dib = { IOBA_KDPDR, IOLN_KDPDR, &APR_rd, &APR_wr, 0 };
DIB kipar_dib = { IOBA_KIPAR, IOLN_KIPAR, &APR_rd, &APR_wr, 0 };
DIB kdpar_dib = { IOBA_KDPAR, IOLN_KDPAR, &APR_rd, &APR_wr, 0 };
DIB uipdr_dib = { IOBA_UIPDR, IOLN_UIPDR, &APR_rd, &APR_wr, 0 };
DIB udpdr_dib = { IOBA_UDPDR, IOLN_UDPDR, &APR_rd, &APR_wr, 0 };
DIB uipar_dib = { IOBA_UIPAR, IOLN_UIPAR, &APR_rd, &APR_wr, 0 };
DIB udpar_dib = { IOBA_UDPAR, IOLN_UDPAR, &APR_rd, &APR_wr, 0 };
DIB sr_dib = { IOBA_SR, IOLN_SR, &SR_rd, NULL, 0 };
DIB dr_dib = { IOBA_SR, IOLN_SR, NULL, &DR_wr, 0 };
DIB mmr012_dib = { IOBA_MMR012, IOLN_MMR012, &MMR012_rd, &MMR012_wr, 0 };
DIB mmr3_dib = { IOBA_MMR3, IOLN_MMR3, &MMR3_rd, &MMR3_wr, 0 };
DIB ubm_dib = { IOBA_UBM, IOLN_UBM, &ubm_rd, &ubm_wr, 0 };
CPUTAB cpu_tab[MOD_MAX] = {
{ "11/03", SOP_1103, OPT_1103, MEMSIZE64K, PSW_1103,
0, 0, 0, 0, 0 },
{ "11/04", SOP_1104, OPT_1104, MEMSIZE64K, PSW_1104,
0, 0, 0, 0, 0 },
{ "11/05", SOP_1105, OPT_1105, MEMSIZE64K, PSW_1105,
0, 0, 0, 0, 0 },
{ "11/20", SOP_1120, OPT_1120, MEMSIZE64K, PSW_1120,
0, 0, 0, 0, 0 },
{ "11/23", SOP_1123, OPT_1123, MAXMEMSIZE, PSW_F,
MFPT_F, PAR_F, PDR_F, MM0_F, MM3_F },
{ "11/23+", SOP_1123P, OPT_1123P, MAXMEMSIZE, PSW_F,
MFPT_F, PAR_F, PDR_F, MM0_F, MM3_F },
{ "11/24", SOP_1124, OPT_1124, MAXMEMSIZE, PSW_F,
MFPT_F, PAR_F, PDR_F, MM0_F, MM3_F },
{ "11/34", SOP_1134, OPT_1134, UNIMEMSIZE, PSW_1134,
0, PAR_1134, PDR_1134, MM0_1134, 0 },
{ "11/40", SOP_1140, OPT_1140, UNIMEMSIZE, PSW_1140,
0, PAR_1140, PDR_1140, MM0_1140, 0 },
{ "11/44", SOP_1144, OPT_1144, MAXMEMSIZE, PSW_1144,
MFPT_44, PAR_1144, PDR_1144, MM0_1144, MM3_1144 },
{ "11/45", SOP_1145, OPT_1145, UNIMEMSIZE, PSW_1145,
0, PAR_1145, PDR_1145, MM0_1145, MM3_1145 },
{ "11/60", SOP_1160, OPT_1160, UNIMEMSIZE, PSW_1160,
0, PAR_1160, PDR_1160, MM0_1160, 0 },
{ "11/70", SOP_1170, OPT_1170, MAXMEMSIZE, PSW_1170,
0, PAR_1170, PDR_1170, MM0_1170, MM3_1170 },
{ "11/73", SOP_1173, OPT_1173, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J },
{ "11/53", SOP_1153, OPT_1153, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J },
{ "11/73B", SOP_1173B, OPT_1173B, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J },
{ "11/83", SOP_1183, OPT_1183, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J },
{ "11/84", SOP_1184, OPT_1184, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J },
{ "11/93", SOP_1193, OPT_1193, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J },
{ "11/94", SOP_1194, OPT_1194, MAXMEMSIZE, PSW_J,
MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J } };
CNFTAB cnf_tab[] = {
{ HAS_PSW, 0, &psw_dib }, /* PSW */
{ CPUT_J, 0, &cpuj_dib }, /* CPU control */
{ CPUT_24, 0, &cpu24_dib },
{ CPUT_44, 0, &cpu44_dib },
{ CPUT_45, 0, &cpu45_dib },
{ CPUT_60, 0, &cpu60_dib },
{ CPUT_70, 0, &cpu70_dib },
{ HAS_IOSR, 0, &reg_dib },
{ CPUT_23P, 0, &ctlfb_dib }, /* board ctls */
{ CPUT_JB, 0, &ctljb_dib },
{ CPUT_53, 0, &ctljd_dib },
{ CPUT_JE, 0, &ctlje_dib },
{ CPUT_24, 0, &uba24_dib }, /* UBA */
{ CPUT_JU, 0, &ubaj_dib },
{ 0, OPT_MMU, &kipdr_dib }, /* MMU */
{ 0, OPT_MMU, &kipar_dib },
{ 0, OPT_MMU, &uipdr_dib },
{ 0, OPT_MMU, &uipar_dib },
{ 0, OPT_MMU, &mmr012_dib }, /* MMR0-2 */
{ HAS_MMR3, 0, &mmr3_dib }, /* MMR3 */
{ 0, OPT_UBM, &ubm_dib }, /* Unibus map */
{ HAS_SID, 0, &kdpdr_dib }, /* supv, I/D */
{ HAS_SID, 0, &kdpar_dib },
{ HAS_SID, 0, &supv_dib },
{ HAS_SID, 0, &udpdr_dib },
{ HAS_SID, 0, &udpar_dib },
{ HAS_SR, 0, &sr_dib }, /* SR */
{ HAS_DR, 0, &dr_dib }, /* DR */
{ 0, 0, NULL } };
static const char *opt_name[] = {
"Unibus", "Qbus", "EIS", "NOEIS", "FIS", "NOFIS",
"FPP", "NOFPP", "CIS", "NOCIS", "MMU", "NOMMU",
"RH11", "RH70", "PARITY", "NOPARITY", "Unibus map", "No map", NULL };
/* SYSTEM data structures
sys_dev SYSTEM device descriptor
sys_unit SYSTEM unit descriptor
sys_reg SYSTEM register list
*/
UNIT sys_unit = { UDATA (NULL, 0, 0) };
REG sys_reg[] = {
{ ORDATA (SR, SR, 16) },
{ ORDATA (DR, DR, 16) },
{ ORDATA (MEMERR, MEMERR, 16) },
{ ORDATA (CCR, CCR, 16) },
{ ORDATA (MAINT, MAINT, 16) },
{ ORDATA (HITMISS, HITMISS, 16) },
{ ORDATA (CPUERR, CPUERR, 16) },
{ ORDATA (MBRK, MBRK, 16) },
{ ORDATA (JCSR, JCSR, 16) },
{ ORDATA (JPCR, JPCR, 16) },
{ ORDATA (JASR, JASR, 16) },
{ ORDATA (UDCR, UDCR, 16) },
{ ORDATA (UDDR, UDDR, 16) },
{ ORDATA (UCSR, UCSR, 16) },
{ ORDATA (ULAST, uba_last, 23) },
{ BRDATA (UBMAP, ub_map, 8, 22, UBM_LNT_LW) },
{ DRDATA (TOY_STATE, toy_state, 6), REG_HRO },
{ BRDATA (TOY_DATA, toy_data, 8, 8, TOY_LNT), REG_HRO },
{ NULL} };
DEVICE sys_dev = {
"SYSTEM", &sys_unit, sys_reg, NULL,
1, 0, 0, 0, 0, 0,
NULL, NULL, &sys_reset,
NULL, NULL, NULL,
NULL, 0, 0,
NULL, NULL, NULL };
/* Switch and display registers - many */
t_stat SR_rd (int32 *data, int32 pa, int32 access)
{
*data = SR;
return SCPE_OK;
}
t_stat DR_wr (int32 data, int32 pa, int32 access)
{
DR = data;
return SCPE_OK;
}
/* GPR's - 11/04, 11/05 */
t_stat REG_rd (int32 *data, int32 pa, int32 access)
{
*data = R[pa & 07];
return SCPE_OK;
}
t_stat REG_wr (int32 data, int32 pa, int32 access)
{
int32 reg = pa & 07;
if (access == WRITE) R[reg] = data;
else if (pa & 1) R[reg] = (R[reg] & 0377) | (data << 8);
else R[reg] = (R[reg] & ~0377) | data;
return SCPE_OK;
}
/* CPU control registers - 11/24 */
t_stat CPU24_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 013: /* CPUERR */
*data = 0;
return SCPE_OK; } /* end switch PA */
*data = 0;
return SCPE_NXM; /* unimplemented */
}
t_stat CPU24_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 013: /* CPUERR */
return SCPE_OK; } /* end switch pa */
return SCPE_NXM; /* unimplemented */
}
/* CPU control registers - 11/44 */
t_stat CPU44_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
*data = MEMERR;
return SCPE_OK;
case 3: /* CCR */
*data = CCR & CCR44_RD;
return SCPE_OK;
case 4: /* MAINT */
*data = MAINT & CMR44_RD;
return SCPE_OK;
case 5: /* Hit/miss */
*data = HITMISS;
return SCPE_OK;
case 6: /* CDR */
*data = 0;
return SCPE_OK;
case 013: /* CPUERR */
if (CPUERR & CPUE_YEL) /* 11/44 stack err */
CPUERR = (CPUERR & ~CPUE_YEL) | CPUE_RED; /* in <2> not <3> */
if (CPUERR & (CPUE_ODD|CPUE_NXM|CPUE_TMO)) /* additional flag */
CPUERR = CPUERR | CPUE44_BUSE;
*data = CPUERR & CPUE_IMP;
return SCPE_OK;
case 015: /* PIRQ */
*data = PIRQ;
return SCPE_OK; } /* end switch PA */
*data = 0;
return SCPE_NXM; /* unimplemented */
}
t_stat CPU44_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
MEMERR = 0;
return SCPE_OK;
case 3: /* CCR */
ODD_MRG (CCR, data);
CCR = data & CCR44_WR;
return SCPE_OK;
case 4: /* MAINT */
ODD_MRG (MAINT, data);
MAINT = data & CMR44_WR;
return SCPE_OK;
case 5: /* Hit/miss */
return SCPE_OK;
case 013: /* CPUERR */
CPUERR = 0;
return SCPE_OK;
case 015: /* PIRQ */
ODD_WO (data);
put_PIRQ (data);
return SCPE_OK; }
return SCPE_NXM; /* unimplemented */
}
/* CPU control registers - 11/45 */
t_stat CPU45_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 014: /* MBRK */
*data = MBRK;
return SCPE_OK;
case 015: /* PIRQ */
*data = PIRQ;
return SCPE_OK;
case 016: /* STKLIM */
*data = STKLIM & STKLIM_RW;
return SCPE_OK; } /* end switch PA */
*data = 0;
return SCPE_NXM; /* unimplemented */
}
t_stat CPU45_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 015: /* PIRQ */
ODD_WO (data);
put_PIRQ (data);
return SCPE_OK;
case 016: /* STKLIM */
ODD_WO (data);
STKLIM = data & STKLIM_RW;
return SCPE_OK; } /* end switch pa */
return SCPE_NXM; /* unimplemented */
}
/* CPU control registers - 11/60 */
t_stat CPU60_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
*data = MEMERR;
return SCPE_OK;
case 3: /* CCR */
*data = CCR;
return SCPE_OK;
case 5: /* Hit/miss */
*data = HITMISS;
return SCPE_OK;
case 016: /* STKLIM */
*data = STKLIM & STKLIM_RW;
return SCPE_OK; } /* end switch PA */
*data = 0;
return SCPE_NXM; /* unimplemented */
}
t_stat CPU60_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
MEMERR = 0;
return SCPE_OK;
case 3: /* CCR */
ODD_MRG (CCR, data);
CCR = data;
return SCPE_OK;
case 5: /* Hit/miss */
return SCPE_OK;
case 016: /* STKLIM */
ODD_WO (data);
STKLIM = data & STKLIM_RW;
return SCPE_OK; } /* end switch pa */
return SCPE_NXM; /* unimplemented */
}
/* CPU control registers - 11/70 */
t_stat CPU70_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 0: case 1: case 011: /* LO,HI ERR, HI SIZE */
*data = 0;
return SCPE_OK;
case 2: /* MEMERR */
*data = MEMERR;
return SCPE_OK;
case 3: /* CCR */
*data = CCR;
return SCPE_OK;
case 4: /* MAINT */
*data = 0;
return SCPE_OK;
case 5: /* Hit/miss */
*data = HITMISS;
return SCPE_OK;
case 010: /* lower size */
*data = (MEMSIZE >> 6) - 1;
return SCPE_OK;
case 012: /* system ID */
*data = 0x1234;
return SCPE_OK;
case 013: /* CPUERR */
*data = CPUERR & CPUE_IMP;
return SCPE_OK;
case 014: /* MBRK */
*data = MBRK;
return SCPE_OK;
case 015: /* PIRQ */
*data = PIRQ;
return SCPE_OK;
case 016: /* STKLIM */
*data = STKLIM & STKLIM_RW;
return SCPE_OK; } /* end switch PA */
*data = 0;
return SCPE_NXM; /* unimplemented */
}
t_stat CPU70_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
ODD_WO (data);
MEMERR = MEMERR & ~data;
return SCPE_OK;
case 3: /* CCR */
ODD_MRG (CCR, data);
CCR = data;
return SCPE_OK;
case 4: /* MAINT */
return SCPE_OK;
case 5: /* Hit/miss */
return SCPE_OK;
case 013: /* CPUERR */
CPUERR = 0;
return SCPE_OK;
case 015: /* PIRQ */
ODD_WO (data);
put_PIRQ (data);
return SCPE_OK;
case 016: /* STKLIM */
ODD_WO (data);
STKLIM = data & STKLIM_RW;
return SCPE_OK; } /* end switch pa */
return SCPE_NXM; /* unimplemented */
}
/* CPU control registers - J11 */
t_stat CPUJ_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
*data = MEMERR;
return SCPE_OK;
case 3: /* CCR */
*data = CCR;
return SCPE_OK;
case 4: /* MAINT */
*data = MAINT | MAINT_NOFPA | MAINT_BPOK | (UNIBUS? MAINT_U: MAINT_Q);
if (CPUT (CPUT_53)) *data |= MAINT_KDJD | MAINT_POROM;
if (CPUT (CPUT_73)) *data |= MAINT_KDJA | MAINT_POODT;
if (CPUT (CPUT_73B|CPUT_83|CPUT_84)) *data |= MAINT_KDJB | MAINT_POROM;
if (CPUT (CPUT_93|CPUT_94)) *data |= MAINT_KDJE | MAINT_POROM;
return SCPE_OK;
case 5: /* Hit/miss */
if (CPUT (CPUT_73B)) *data = 0; /* must be 0 for 73B */
else *data = HITMISS | 010; /* must be nz for 11/8X */
return SCPE_OK;
case 013: /* CPUERR */
*data = CPUERR & CPUE_IMP;
return SCPE_OK;
case 015: /* PIRQ */
*data = PIRQ;
return SCPE_OK; } /* end switch PA */
*data = 0;
return SCPE_NXM; /* unimplemented */
}
t_stat CPUJ_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 2: /* MEMERR */
MEMERR = 0;
return SCPE_OK;
case 3: /* CCR */
ODD_MRG (CCR, data);
CCR = data;
return SCPE_OK;
case 4: /* MAINT */
return SCPE_OK;
case 5: /* Hit/miss */
return SCPE_OK;
case 013: /* CPUERR */
CPUERR = 0;
return SCPE_OK;
case 015: /* PIRQ */
ODD_WO (data);
put_PIRQ (data);
return SCPE_OK; } /* end switch pa */
return SCPE_NXM; /* unimplemented */
}
/* Board control registers - KDF11B */
t_stat CTLFB_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* PCR */
*data = JPCR & PCRFB_RW;
return SCPE_OK;
case 1: /* MAINT */
*data = MAINT;
return SCPE_OK;
case 2: /* CDR */
*data = SR & CDRFB_RD;
return SCPE_OK; }
*data = 0;
return SCPE_NXM;
}
t_stat CTLFB_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* PCR */
ODD_MRG (JPCR, data);
JPCR = data & PCRFB_RW;
return SCPE_OK;
case 1: /* MAINT */
ODD_MRG (MAINT, data);
MAINT = data;
return SCPE_OK;
case 2: /* CDR */
ODD_WO (data);
DR = data & CDRFB_WR;
return SCPE_OK; }
return SCPE_NXM;
}
/* Board control registers - KDJ11B */
t_stat CTLJB_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* CSR */
*data = JCSR & CSRJB_RD;
return SCPE_OK;
case 1: /* PCR */
*data = JPCR & PCRJB_RW;
return SCPE_OK;
case 2: /* CDR */
*data = SR & CDRJB_RD;
return SCPE_OK; }
*data = 0;
return SCPE_NXM;
}
t_stat CTLJB_wr (int32 data, int32 pa, int32 access)
{
int32 t;
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* CSR */
ODD_MRG (JCSR, data);
JCSR = (JCSR & ~CSRJB_WR) | (data & CSRJB_WR);
if (JCSR & CSRJ_LTCI) clk_fie = 1; /* force LTC int enb? */
else clk_fie = 0;
if (JCSR & CSRJ_LTCD) clk_fnxm = 1; /* force LTC reg nxm? */
else clk_fnxm = 0;
t = CSRJ_LTCSEL (JCSR); /* get freq sel */
if (t) clk_tps = clk_tps_map[t];
else clk_tps = clk_default;
return SCPE_OK;
case 1: /* PCR */
ODD_MRG (JPCR, data);
JPCR = data & PCRJB_RW;
return SCPE_OK;
case 2: /* CDR */
ODD_WO (data);
DR = data & CDRJB_WR;
return SCPE_OK; }
return SCPE_NXM;
}
/* Board control registers - KDJ11D */
t_stat CTLJD_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* CSR */
*data = JCSR & CSRJD_RD;
return SCPE_OK; }
*data = 0;
return SCPE_NXM;
}
t_stat CTLJD_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* CSR */
ODD_MRG (JCSR, data);
JCSR = (JCSR & ~CSRJD_WR) | (data & CSRJD_WR);
return SCPE_OK; }
return SCPE_NXM;
}
/* Board control registers - KDJ11E */
t_stat CTLJE_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* CSR */
*data = JCSR & CSRJE_RD;
return SCPE_OK;
case 1: /* PCR */
*data = JPCR & PCRJE_RW;
return SCPE_OK;
case 2: /* CDR */
*data = SR & CDRJE_RD;
return SCPE_OK;
case 3: /* ASR */
JASR = (JASR & ~ASRJE_TOY) | (toy_read () << ASRJE_V_TOY);
*data = JASR & ASRJE_RW;
return SCPE_OK; }
*data = 0;
return SCPE_NXM;
}
t_stat CTLJE_wr (int32 data, int32 pa, int32 access)
{
int32 t;
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* CSR */
ODD_MRG (JCSR, data);
JCSR = (JCSR & ~CSRJE_WR) | (data & CSRJE_WR);
if (JCSR & CSRJ_LTCI) clk_fie = 1; /* force LTC int enb? */
else clk_fie = 0;
if (JCSR & CSRJ_LTCD) clk_fnxm = 1; /* force LTC reg nxm? */
else clk_fnxm = 0;
t = CSRJ_LTCSEL (JCSR); /* get freq sel */
if (t) clk_tps = clk_tps_map[t];
else clk_tps = clk_default;
return SCPE_OK;
case 1: /* PCR */
ODD_MRG (JPCR, data);
JPCR = data & PCRJE_RW;
return SCPE_OK;
case 2: /* CDR */
ODD_WO (data);
DR = data & CDRJE_WR;
return SCPE_OK;
case 3: /* ASR */
ODD_MRG (JASR, data);
JASR = data & ASRJE_RW;
toy_write (ASRJE_TOYBIT (JASR));
return SCPE_OK; }
return SCPE_NXM;
}
/* Unibus adapter registers - KT24 */
t_stat UBA24_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 2: /* LMAL */
*data = uba_last & LMAL_RD;
return SCPE_OK;
case 3: /* LMAH */
*data = uba_last & LMAH_RD;
return SCPE_OK; }
*data = 0;
return SCPE_NXM;
}
t_stat UBA24_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 3: /* ASR */
ODD_IGN (data);
uba_last = (uba_last & ~LMAH_WR) | ((data & LMAH_WR) << 16);
return SCPE_OK; }
return SCPE_NXM;
}
/* Unibus registers - KTJ11B */
t_stat UBAJ_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* DCR */
*data = UDCR & DCRKTJ_RD;
return SCPE_OK;
case 1: /* DDR */
*data = UDDR & DDRKTJ_RW;
return SCPE_OK;
case 2: /* CSR */
*data = UCSR & MCRKTJ_RD;
return SCPE_OK; }
*data = 0;
return SCPE_NXM;
}
t_stat UBAJ_wr (int32 data, int32 pa, int32 access)
{
switch ((pa >> 1) & 03) { /* decode pa<2:1> */
case 0: /* DCR */
ODD_MRG (UDCR, data);
UDCR = (UDCR & ~DCRKTJ_WR) | (data & DCRKTJ_WR);
return SCPE_OK;
case 1: /* DDR */
ODD_MRG (UDDR, data);
UDDR = data & DDRKTJ_RW;;
return SCPE_OK;
case 2: /* CSR */
ODD_MRG (UCSR, data);
UCSR = (UCSR & ~MCRKTJ_WR) | (data & MCRKTJ_WR);
return SCPE_OK; }
return SCPE_NXM;
}
/* KDJ11E TOY routines */
int32 toy_read (void)
{
time_t curr;
struct tm *ctm;
int32 bit;
if (toy_state == 0) {
curr = time (NULL); /* get curr time */
if (curr == (time_t) -1) return 0; /* error? */
ctm = localtime (&curr); /* decompose */
if (ctm == NULL) return 0; /* error? */
toy_data[TOY_HSEC] = 0x50;
toy_data[TOY_SEC] = toy_set (ctm->tm_sec);
toy_data[TOY_MIN] = toy_set (ctm->tm_min);
toy_data[TOY_HR] = toy_set (ctm->tm_hour);
toy_data[TOY_DOW] = toy_set (ctm->tm_wday);
toy_data[TOY_DOM] = toy_set (ctm->tm_mday);
toy_data[TOY_MON] = toy_set (ctm->tm_mon + 1);
toy_data[TOY_YR] = toy_set (ctm->tm_year % 100); }
bit = toy_data[toy_state >> 3] >> (toy_state & 07);
toy_state = (toy_state + 1) % (TOY_LNT * 8);
return (bit & 1);
}
void toy_write (int32 bit)
{
toy_state = 0;
return;
}
uint8 toy_set (int32 val)
{
uint32 d1, d2;
d1 = val / 10;
d2 = val % 10;
return (uint8) ((d1 << 4) | d2);
}
/* Build I/O space entries for CPU */
t_stat cpu_build_dib (void)
{
int32 i;
t_stat r;
for (i = 0; cnf_tab[i].dib != NULL; i++) { /* loop thru config tab */
if (((cnf_tab[i].cpum == 0) || (cpu_type & cnf_tab[i].cpum)) &&
((cnf_tab[i].optm == 0) || (cpu_opt & cnf_tab[i].optm))) {
if (r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)) /* add to dispatch tab */
return r;
}
}
return SCPE_OK;
}
/* Set/show CPU model */
t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (cptr != NULL) return SCPE_ARG;
if (val >= MOD_MAX) return SCPE_IERR;
if (val == (int32) cpu_model) return SCPE_OK;
if (MEMSIZE > cpu_tab[val].maxm)
cpu_set_size (uptr, cpu_tab[val].maxm, NULL, NULL);
if (MEMSIZE > cpu_tab[val].maxm) return SCPE_INCOMP;
cpu_model = val;
cpu_type = 1u << cpu_model;
cpu_opt = cpu_tab[cpu_model].std;
cpu_set_bus (cpu_opt);
reset_all (0); /* reset world */
return SCPE_OK;
}
t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc)
{
uint32 i, std;
fprintf (st, "%s", cpu_tab[cpu_model].name);
std = cpu_tab[cpu_model].opt;
for (i = 0; std && opt_name[i]; i = i++) {
if ((std >> i) & 1) fprintf (st, ", %s",
((cpu_opt >> i) & 1)? opt_name[2 * i]: opt_name[(2 * i) + 1]);
}
return SCPE_OK;
}
/* Set/clear CPU option */
t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (cptr) return SCPE_ARG;
if ((val & cpu_tab[cpu_model].opt) == 0) return SCPE_ARG;
cpu_opt = cpu_opt | val;
return SCPE_OK;
}
t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (cptr) return SCPE_ARG;
if ((val & cpu_tab[cpu_model].opt) == 0) return SCPE_ARG;
cpu_opt = cpu_opt & ~val;
return SCPE_OK;
}
/* Memory allocation */
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc = 0;
uint32 i, clim;
uint16 *nM;
if ((val <= 0) || (val > (int32) cpu_tab[cpu_model].maxm) ||
((val & 07777) != 0)) return SCPE_ARG;
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 (val >> 1, sizeof (uint16));
if (nM == NULL) return SCPE_MEM;
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 = val;
cpu_set_bus (cpu_opt);
return SCPE_OK;
}
/* Bus configuration, disable Unibus or Qbus devices */
t_stat cpu_set_bus (int32 opt)
{
DEVICE *dptr;
uint32 i, mask;
if (opt & BUS_U) mask = DEV_UBUS; /* Unibus variant? */
else if (MEMSIZE <= UNIMEMSIZE) /* 18b Qbus devices? */
mask = DEV_QBUS | DEV_Q18;
else mask = DEV_QBUS; /* must be 22b */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
if ((dptr->flags & DEV_DISABLE) && /* disable-able? */
!(dptr->flags & DEV_DIS) && /* enabled? */
((dptr->flags & mask) == 0)) { /* not allowed? */
printf ("Disabling %s\n", sim_dname (dptr));
if (sim_log) fprintf (sim_log, "Disabling %s\n", sim_dname (dptr));
dptr->flags = dptr->flags | DEV_DIS; } }
return SCPE_OK;
}
/* System reset */
t_stat sys_reset (DEVICE *dptr)
{
int32 i;
CCR = 0;
HITMISS = 0;
CPUERR = 0;
MEMERR = 0;
if (!CPUT (CPUT_J)) MAINT = 0;
MBRK = 0;
JCSR = 0;
JPCR = 0;
JASR = 0;
UDCR = 0;
UDDR = 0;
UCSR = 0;
uba_last = 0;
DR = 0;
toy_state = 0;
for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0;
for (i = 0; i < TOY_LNT; i++) toy_data[i] = 0;
return SCPE_OK;
}

280
PDP11/pdp11_cpumod.h Normal file
View file

@ -0,0 +1,280 @@
/* pdp11_cpumod.h: PDP-11 CPU model definitions
Copyright (c) 2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#ifndef _PDP11_CPUMOD_H_
#define _PDP11_CPUMOD_H_ 1
#define SOP_1103 (BUS_Q)
#define OPT_1103 (OPT_EIS|OPT_FIS)
#define PSW_1103 0000377
#define SOP_1104 (BUS_U)
#define OPT_1104 0
#define PSW_1104 0000377
#define SOP_1105 (BUS_U)
#define OPT_1105 0
#define PSW_1105 0000377
#define SOP_1120 (BUS_U)
#define OPT_1120 0
#define PSW_1120 0000377
#define SOP_1123 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1123 (OPT_FPP|OPT_CIS)
#define PSW_F 0170777
#define PAR_F 0177777
#define PDR_F 0077516
#define MM0_F 0160157
#define MM3_F 0000060
#define SOP_1123P (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1123P (OPT_FPP|OPT_CIS)
#define SOP_1124 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM)
#define OPT_1124 (OPT_FPP|OPT_CIS)
#define SOP_1134 (BUS_U|OPT_EIS|OPT_MMU)
#define OPT_1134 (OPT_FPP)
#define PSW_1134 0170377
#define PAR_1134 0007777
#define PDR_1134 0077516
#define MM0_1134 0160557
#define SOP_1140 (BUS_U|OPT_EIS|OPT_MMU)
#define OPT_1140 (OPT_FIS)
#define PSW_1140 0170377
#define PAR_1140 0007777
#define PDR_1140 0077516
#define MM0_1140 0160557
#define SOP_1144 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM)
#define OPT_1144 (OPT_FPP|OPT_CIS)
#define PSW_1144 0170777
#define PAR_1144 0177777
#define PDR_1144 0177516
#define MM0_1144 0160557
#define MM3_1144 0000077
#define SOP_1145 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_RH11)
#define OPT_1145 (OPT_FPP)
#define PSW_1145 0174377
#define PAR_1145 0007777
#define PDR_1145 0077717
#define MM0_1145 0171777
#define MM3_1145 0000007
#define SOP_1160 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1160 0
#define PSW_1160 0170377
#define PAR_1160 0007777
#define PDR_1160 0077516
#define MM0_1160 0160557
#define SOP_1170 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM)
#define OPT_1170 (OPT_FPP|OPT_RH11)
#define PSW_1170 0174377
#define PAR_1170 0177777
#define PDR_1170 0077717
#define MM0_1170 0171777
#define MM3_1170 0000067
#define SOP_1173 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1173 (OPT_CIS)
#define PSW_J 0174777
#define PAR_J 0177777
#define PDR_J 0177516
#define MM0_J 0160177
#define MM3_J 0000077
#define SOP_1153 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1153 (OPT_CIS)
#define SOP_1173B (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1173B (OPT_CIS)
#define SOP_1183 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1183 (OPT_CIS)
#define SOP_1184 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM|OPT_RH11)
#define OPT_1184 (OPT_CIS)
#define SOP_1193 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU)
#define OPT_1193 (OPT_CIS)
#define SOP_1194 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM|OPT_RH11)
#define OPT_1194 (OPT_CIS)
#define MOD_MAX 20
/* MFPT codes */
#define MFPT_44 1
#define MFPT_F 3
#define MFPT_T 4
#define MFPT_J 5
/* KDF11B specific register */
#define PCRFB_RW 0037477 /* page ctrl reg */
#define CDRFB_RD 0000377 /* config reg */
#define CDRFB_WR 0000017
/* KT24 Unibus map specific registers */
#define LMAL_RD 0177777 /* last mapped low */
#define LMAH_RD 0000177 /* last mapped high */
#define LMAH_WR 0000100
/* 11/44 specific registers */
#define CCR44_RD 0033315 /* cache control */
#define CCR44_WR 0003315
#define CMR44_RD 0177437 /* cache maint */
#define CMR44_WR 0000037
#define CPUE44_BUSE 0004000
/* J11 specific registers */
/* 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_KDJA (1 << MAINT_V_TYP) /* KDJ11A */
#define MAINT_KDJB (2 << MAINT_V_TYP) /* KDJ11B */
#define MAINT_KDJD (4 << MAINT_V_TYP) /* KDJ11D */
#define MAINT_KDJE (5 << MAINT_V_TYP) /* KDJ11E */
#define MAINT_V_HTRAP 3 /* trap 4 on HALT */
#define MAINT_HTRAP (1 << MAINT_V_HTRAP)
#define MAINT_V_POM 1 /* power on option */
#define MAINT_POODT (0 << MAINT_V_POM) /* power up ODT */
#define MAINT_POROM (2 << MAINT_V_POM) /* power up ROM */
#define MAINT_V_BPOK 0 /* power OK */
#define MAINT_BPOK (1 << MAINT_V_BPOK)
/* KDJ11B control */
#define CSRJB_RD 0177767
#define CSRJB_WR 0037767
#define CSRJ_LTCI 0020000 /* force LTC int */
#define CSRJ_LTCD 0010000 /* disable LTC reg */
#define CSRJ_V_LTCSEL 10
#define CSRJ_M_LTCSEL 03
#define CSRJ_LTCSEL(x) (((x) >> CSRJ_V_LTCSEL) & CSRJ_M_LTCSEL)
#define CSRJ_HBREAK 0001000 /* halt on break */
#define PCRJB_RW 0077176 /* page ctrl reg */
#define CDRJB_RD 0000377 /* config register */
#define CDRJB_WR 0000377
/* KDJ11D control */
#define CSRJD_RD 0157777 /* native register */
#define CSRJD_WR 0000377
#define CSRJD_15M 0040000 /* 1.5M mem on board */
/* KDJ11E control */
#define CSRJE_RD 0137360 /* control reg */
#define CSRJE_WR 0037370
#define PCRJE_RW 0177376 /* page ctrl reg */
#define CDRJE_RD 0000377 /* config register */
#define CDRJE_WR 0000077
#define ASRJE_RW 0030462 /* additional status */
#define ASRJE_V_TOY 8
#define ASRJE_TOY (1u << ASRJE_V_TOY) /* TOY serial bit */
#define ASRJE_TOYBIT(x) (((x) >> ASRJE_V_TOY) & 1)
/* KDJ11E TOY clock */
#define TOY_HSEC 0
#define TOY_SEC 1
#define TOY_MIN 2
#define TOY_HR 3
#define TOY_DOW 4
#define TOY_DOM 5
#define TOY_MON 6
#define TOY_YR 7
#define TOY_LNT 8
/* KTJ11B Unibus map */
#define DCRKTJ_RD 0100616 /* diag control */
#define DCRKTJ_WR 0000416
#define DDRKTJ_RW 0177777 /* diag data */
#define MCRKTJ_RD 0000377 /* control register */
#define MCRKTJ_WR 0000177
/* Data tables */
struct cpu_table {
char *name; /* model name */
uint32 std; /* standard flags */
uint32 opt; /* set/clear flags */
uint32 maxm; /* max memory */
uint32 psw; /* PSW mask */
uint32 mfpt; /* MFPT code */
uint32 par; /* PAR mask */
uint32 pdr; /* PDR mask */
uint32 mm0; /* MMR0 mask */
uint32 mm3; /* MMR3 mask */
};
typedef struct cpu_table CPUTAB;
struct conf_table {
uint32 cpum;
uint32 optm;
DIB *dib;
};
typedef struct conf_table CNFTAB;
/* Prototypes */
t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_bus (int32 opt);
#endif

View file

@ -26,6 +26,10 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry, The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11 and John Wilson in resolving questions about the PDP-11
30-Sep-04 RMS Added Massbus support
Removed Map_Addr prototype
Removed map argument from Unibus routines
Added framework for model selection
28-May-04 RMS Added DHQ support 28-May-04 RMS Added DHQ support
25-Jan-04 RMS Removed local debug logging support 25-Jan-04 RMS Removed local debug logging support
22-Dec-03 RMS Added second DEUNA/DELUA support 22-Dec-03 RMS Added second DEUNA/DELUA support
@ -68,9 +72,11 @@
/* Architectural constants */ /* Architectural constants */
#define STKLIM 0400 /* stack limit */ #define STKL_R 0340 /* stack limit */
#define STKL_Y 0400
#define VASIZE 0200000 /* 2**16 */ #define VASIZE 0200000 /* 2**16 */
#define VAMASK (VASIZE - 1) /* 2**16 - 1 */ #define VAMASK (VASIZE - 1) /* 2**16 - 1 */
#define MEMSIZE64K 0200000 /* 2**16 */
#define INIMEMSIZE 001000000 /* 2**18 */ #define INIMEMSIZE 001000000 /* 2**18 */
#define UNIMEMSIZE 001000000 /* 2**18 */ #define UNIMEMSIZE 001000000 /* 2**18 */
#define UNIMASK (UNIMEMSIZE - 1) /* 2**18 - 1 */ #define UNIMASK (UNIMEMSIZE - 1) /* 2**18 - 1 */
@ -83,6 +89,149 @@
#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE) #define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE)
#define DMASK 0177777 #define DMASK 0177777
/* CPU models */
#define MOD_1103 0
#define MOD_1104 1
#define MOD_1105 2
#define MOD_1120 3
#define MOD_1123 4
#define MOD_1123P 5
#define MOD_1124 6
#define MOD_1134 7
#define MOD_1140 8
#define MOD_1144 9
#define MOD_1145 10
#define MOD_1160 11
#define MOD_1170 12
#define MOD_1173 13
#define MOD_1153 14
#define MOD_1173B 15
#define MOD_1183 16
#define MOD_1184 17
#define MOD_1193 18
#define MOD_1194 19
#define MOD_T 20
#define CPUT_03 (1u << MOD_1103) /* LSI-11 */
#define CPUT_04 (1u << MOD_1104) /* 11/04 */
#define CPUT_05 (1u << MOD_1105) /* 11/05 */
#define CPUT_20 (1u << MOD_1120) /* 11/20 */
#define CPUT_23 (1u << MOD_1123) /* 11/23 */
#define CPUT_23P (1u << MOD_1123P) /* 11/23+ */
#define CPUT_24 (1u << MOD_1124) /* 11/24 */
#define CPUT_34 (1u << MOD_1134) /* 11/34 */
#define CPUT_40 (1u << MOD_1140) /* 11/40 */
#define CPUT_44 (1u << MOD_1144) /* 11/44 */
#define CPUT_45 (1u << MOD_1145) /* 11/45 */
#define CPUT_60 (1u << MOD_1160) /* 11/60 */
#define CPUT_70 (1u << MOD_1170) /* 11/70 */
#define CPUT_73 (1u << MOD_1173) /* 11/73 */
#define CPUT_53 (1u << MOD_1153) /* 11/53 */
#define CPUT_73B (1u << MOD_1173B) /* 11/73B */
#define CPUT_83 (1u << MOD_1183) /* 11/83 */
#define CPUT_84 (1u << MOD_1184) /* 11/84 */
#define CPUT_93 (1u << MOD_1193) /* 11/93 */
#define CPUT_94 (1u << MOD_1194) /* 11/94 */
#define CPUT_T (1u << MOD_T) /* T-11 */
#define CPUT_F (CPUT_23|CPUT_23P|CPUT_24) /* all F11's */
#define CPUT_J (CPUT_53|CPUT_73|CPUT_73B| \
CPUT_83|CPUT_84|CPUT_93|CPUT_94)
#define CPUT_JB (CPUT_73B|CPUT_83|CPUT_84) /* KDJ11B */
#define CPUT_JE (CPUT_93|CPUT_94) /* KDJ11E */
#define CPUT_JU (CPUT_84|CPUT_94) /* KTJ11B UBA */
#define CPUT_ALL 0xFFFFFFFF
/* CPU options */
#define BUS_U (1u << 0) /* Unibus */
#define BUS_Q (0) /* Qbus */
#define OPT_EIS (1u << 1) /* EIS */
#define OPT_FIS (1u << 2) /* FIS */
#define OPT_FPP (1u << 3) /* FPP */
#define OPT_CIS (1u << 4) /* CIS */
#define OPT_MMU (1u << 5) /* MMU */
#define OPT_RH11 (1u << 6) /* RH11 */
#define OPT_PAR (1u << 7) /* parity */
#define OPT_UBM (1u << 8) /* UBM */
#define CPUT(x) ((cpu_type & (x)) != 0)
#define CPUO(x) ((cpu_opt & (x)) != 0)
#define UNIBUS (cpu_opt & BUS_U)
/* Feature sets
SDSD source addr, source fetch, dest addr, dest fetch
SR switch register
DR display register
RTT RTT instruction
SXS SXT, XOR, SOB instructions
MARK MARK instruction
SPL SPL instruction
MXPY MTPI, MTPD, MFPI, MFPD instructions
MXPS MTPS, MFPS instructions
MFPT MFPT instruction
CSM CSM instruction
TSWLK TSTSET, WRLCK instructions
PSW PSW register
EXPT explicit PSW writes can alter T-bit
IOSR general registers readable from programs in IO space
2REG dual register set
MMR3 MMR3 register
MMTR mem mgt traps
STKLR STKLIM register
STKLF fixed stack limit
SID supervisor mode, I/D spaces
ODD odd address trap
HALT4 halt in kernel mode traps to 4
JREG4 JMP/JSR R traps to 4
STKA stop on stack abort
LTCR LTC CSR
LTCM LTC CSR<7>
*/
#define IS_SDSD (CPUT_20|CPUT_F|CPUT_40|CPUT_60|CPUT_J|CPUT_T)
#define HAS_SR (CPUT_04|CPUT_05|CPUT_20|CPUT_34|CPUT_40| \
CPUT_44|CPUT_45|CPUT_60|CPUT_70)
#define HAS_DR (CPUT_04|CPUT_05|CPUT_20|CPUT_24|CPUT_34| \
CPUT_40|CPUT_45|CPUT_60|CPUT_70)
#define HAS_RTT (CPUT_03|CPUT_04|CPUT_F|CPUT_34|CPUT_40| \
CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J|CPUT_T)
#define HAS_SXS (CPUT_03|CPUT_F|CPUT_34|CPUT_40|CPUT_44| \
CPUT_45|CPUT_60|CPUT_70|CPUT_J|CPUT_T)
#define HAS_MARK (CPUT_03|CPUT_F|CPUT_34|CPUT_40|CPUT_44| \
CPUT_45|CPUT_60|CPUT_70|CPUT_J)
#define HAS_SPL (CPUT_44|CPUT_45|CPUT_70|CPUT_J)
#define HAS_MXPY (CPUT_F|CPUT_34|CPUT_40|CPUT_44|CPUT_45| \
CPUT_60|CPUT_70|CPUT_J)
#define HAS_MXPS (CPUT_03|CPUT_F|CPUT_34|CPUT_J|CPUT_T)
#define HAS_MFPT (CPUT_F|CPUT_44|CPUT_J|CPUT_T)
#define HAS_CSM (CPUT_44|CPUT_J)
#define HAS_TSWLK (CPUT_J)
#define HAS_PSW (CPUT_04|CPUT_05|CPUT_20|CPUT_F|CPUT_34|CPUT_40| \
CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J)
#define HAS_EXPT (CPUT_04|CPUT_05|CPUT_20)
#define HAS_IOSR (CPUT_04|CPUT_05)
#define HAS_2REG (CPUT_45|CPUT_70|CPUT_J)
#define HAS_MMR3 (CPUT_F|CPUT_44|CPUT_45|CPUT_70|CPUT_J)
#define HAS_MMTR (CPUT_45|CPUT_70)
#define HAS_STKLR (CPUT_45|CPUT_60|CPUT_70)
#define HAS_STKLF (CPUT_04|CPUT_05|CPUT_20|CPUT_F|CPUT_34| \
CPUT_40|CPUT_44|CPUT_J)
#define HAS_SID (CPUT_44|CPUT_45|CPUT_70|CPUT_J)
#define HAS_ODD (CPUT_04|CPUT_05|CPUT_20|CPUT_34|CPUT_40| \
CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J)
#define HAS_HALT4 (CPUT_44|CPUT_45|CPUT_70|CPUT_J)
#define HAS_JREG4 (CPUT_03|CPUT_04|CPUT_05|CPUT_20|CPUT_F| \
CPUT_34|CPUT_40|CPUT_60|CPUT_T)
#define STOP_STKA (CPUT_03|CPUT_04|CPUT_05|CPUT_20|CPUT_34|CPUT_44)
#define HAS_LTCR (CPUT_04|CPUT_05|CPUT_20|CPUT_23P|CPUT_24| \
CPUT_34|CPUT_40|CPUT_44|CPUT_45|CPUT_60| \
CPUT_70|CPUT_J)
#define HAS_LTCM (CPUT_04|CPUT_05|CPUT_20|CPUT_24|CPUT_34| \
CPUT_40|CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J)
/* Protection modes */ /* Protection modes */
#define MD_KER 0 #define MD_KER 0
@ -106,10 +255,13 @@
#define PSW_V_N 3 #define PSW_V_N 3
#define PSW_V_TBIT 4 /* trace trap */ #define PSW_V_TBIT 4 /* trace trap */
#define PSW_V_IPL 5 /* int priority */ #define PSW_V_IPL 5 /* int priority */
#define PSW_V_FPD 8 /* first part done */
#define PSW_V_RS 11 /* register set */ #define PSW_V_RS 11 /* register set */
#define PSW_V_PM 12 /* previous mode */ #define PSW_V_PM 12 /* previous mode */
#define PSW_V_CM 14 /* current mode */ #define PSW_V_CM 14 /* current mode */
#define PSW_RW 0174357 /* read/write bits */ #define PSW_CC 017
#define PSW_TBIT (1 << PSW_V_TBIT)
#define PSW_PM (3 << PSW_V_PM)
/* FPS */ /* FPS */
@ -139,18 +291,25 @@
#define PIRQ_IMP 0177356 /* implemented bits */ #define PIRQ_IMP 0177356 /* implemented bits */
#define PIRQ_RW 0177000 /* read/write bits */ #define PIRQ_RW 0177000 /* read/write bits */
/* STKLIM */
#define STKLIM_RW 0177400
/* MMR0 */ /* MMR0 */
#define MMR0_MME 0000001 /* mem mgt enable */ #define MMR0_MME 0000001 /* mem mgt enable */
#define MMR0_V_PAGE 1 /* offset to pageno */ #define MMR0_V_PAGE 1 /* offset to pageno */
#define MMR0_M_PAGE 077 /* mask for pageno */ #define MMR0_M_PAGE 077 /* mask for pageno */
#define MMR0_PAGE (MMR0_M_PAGE << MMR0_V_PAGE) #define MMR0_PAGE (MMR0_M_PAGE << MMR0_V_PAGE)
#define MMR0_IC 0000200 /* instr complete */
#define MMR0_MAINT 0000400 /* maintenance */
#define MMR0_TENB 0001000 /* trap enable */
#define MMR0_TRAP 0010000 /* mem mgt trap */
#define MMR0_RO 0020000 /* read only error */ #define MMR0_RO 0020000 /* read only error */
#define MMR0_PL 0040000 /* page lnt error */ #define MMR0_PL 0040000 /* page lnt error */
#define MMR0_NR 0100000 /* no access error */ #define MMR0_NR 0100000 /* no access error */
#define MMR0_FREEZE 0160000 /* if set, no update */ #define MMR0_FREEZE 0160000 /* if set, no update */
#define MMR0_IMP 0160177 /* implemented bits */ #define MMR0_WR 0171401 /* writeable bits */
#define MMR0_RW 0160001 /* read/write bits */
/* MMR3 */ /* MMR3 */
@ -160,18 +319,23 @@
#define MMR3_CSM 010 /* CSM enable */ #define MMR3_CSM 010 /* CSM enable */
#define MMR3_M22E 020 /* 22b mem mgt enbl */ #define MMR3_M22E 020 /* 22b mem mgt enbl */
#define MMR3_BME 040 /* DMA bus map enbl */ #define MMR3_BME 040 /* DMA bus map enbl */
#define MMR3_IMP 077 /* implemented bits */
#define MMR3_RW 077 /* read/write bits */ /* PAR */
#define PAR_18B 0007777 /* 18b addressing */
#define PAR_22B 0177777 /* 22b addressing */
/* PDR */ /* PDR */
#define PDR_PRD 0000002 /* page readable */ #define PDR_ACF 0000007 /* access control */
#define PDR_PWR 0000004 /* page writeable */ #define PDR_ACS 0000006 /* 2b access control */
#define PDR_ED 0000010 /* expansion dir */ #define PDR_ED 0000010 /* expansion dir */
#define PDR_W 0000100 /* written flag */ #define PDR_W 0000100 /* written flag */
#define PDR_A 0000200 /* access flag */
#define PDR_PLF 0077400 /* page lnt field */ #define PDR_PLF 0077400 /* page lnt field */
#define PDR_IMP 0177516 /* implemented bits */ #define PDR_NOC 0100000 /* don't cache */
#define PDR_RW 0177416 /* read/write bits */
#define PDR_PRD 0000003 /* page readable if 2 */
/* Virtual address */ /* Virtual address */
@ -189,6 +353,7 @@
#define UBM_M_PN 037 #define UBM_M_PN 037
#define UBM_V_OFF 0 /* offset */ #define UBM_V_OFF 0 /* offset */
#define UBM_M_OFF 017777 #define UBM_M_OFF 017777
#define UBM_PAGSIZE (UBM_M_OFF + 1) /* page size */
#define UBM_GETPN(x) (((x) >> UBM_V_PN) & UBM_M_PN) #define UBM_GETPN(x) (((x) >> UBM_V_PN) & UBM_M_PN)
#define UBM_GETOFF(x) ((x) & UBM_M_OFF) #define UBM_GETOFF(x) ((x) & UBM_M_OFF)
@ -202,26 +367,11 @@
#define CPUE_HALT 0200 /* HALT not kernel */ #define CPUE_HALT 0200 /* HALT not kernel */
#define CPUE_IMP 0374 /* implemented bits */ #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 (1 << MAINT_V_TYP) /* KDJ11A */
#define MAINT_V_HTRAP 3 /* trap 4 on HALT */
#define MAINT_HTRAP (1 << MAINT_V_HTRAP)
#define MAINT_V_BPOK 0 /* power OK */
#define MAINT_BPOK (1 << MAINT_V_BPOK)
/* Floating point accumulators */ /* Floating point accumulators */
struct fpac { struct fpac {
unsigned int32 l; /* low 32b */ uint32 l; /* low 32b */
unsigned int32 h; /* high 32b */ uint32 h; /* high 32b */
}; };
typedef struct fpac fpac_t; typedef struct fpac fpac_t;
@ -322,15 +472,13 @@ typedef struct fpac fpac_t;
#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ #define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */
#define DEV_V_Q18 (DEV_V_UF + 2) /* Qbus with <= 256KB */ #define DEV_V_Q18 (DEV_V_UF + 2) /* Qbus with <= 256KB */
#define DEV_V_FLTA (DEV_V_UF + 3) /* flt addr */ #define DEV_V_FLTA (DEV_V_UF + 3) /* flt addr */
#define DEV_V_MBUS (DEV_V_UF + 4) /* Massbus */
#define DEV_V_FFUF (DEV_V_UF + 5) /* first free flag */
#define DEV_UBUS (1u << DEV_V_UBUS) #define DEV_UBUS (1u << DEV_V_UBUS)
#define DEV_QBUS (1u << DEV_V_QBUS) #define DEV_QBUS (1u << DEV_V_QBUS)
#define DEV_Q18 (1u << DEV_V_Q18) #define DEV_Q18 (1u << DEV_V_Q18)
#define DEV_FLTA (1u << DEV_V_FLTA) #define DEV_FLTA (1u << DEV_V_FLTA)
#define DEV_MBUS (1u << DEV_V_MBUS)
#define UNIBUS (cpu_18b || cpu_ubm) /* T if 18b */
#define MAP 1 /* mapped */
#define NOMAP 0 /* not mapped */
#define DEV_RDX 8 /* default device radix */ #define DEV_RDX 8 /* default device radix */
@ -369,8 +517,18 @@ typedef struct pdp_dib DIB;
#define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) #define IOLN_UBM (UBM_LNT_LW * sizeof (int32))
#define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */
#define IOLN_RQ 004 #define IOLN_RQ 004
#define IOBA_APR (IOPAGEBASE + 012200) /* APRs */ #define IOBA_SUP (IOPAGEBASE + 012200) /* supervisor APR's */
#define IOLN_APR 0200 #define IOLN_SUP 0100
#define IOBA_KIPDR (IOPAGEBASE + 012300) /* kernel APR's */
#define IOLN_KIPDR 020
#define IOBA_KDPDR (IOPAGEBASE + 012320)
#define IOLN_KDPDR 020
#define IOBA_KIPAR (IOPAGEBASE + 012340)
#define IOLN_KIPAR 020
#define IOBA_KDPAR (IOPAGEBASE + 012360)
#define IOLN_KDPAR 020
#define IOBA_TU (IOPAGEBASE + 012440) /* TU */
#define IOLN_TU 040
#define IOBA_MMR3 (IOPAGEBASE + 012516) /* MMR3 */ #define IOBA_MMR3 (IOPAGEBASE + 012516) /* MMR3 */
#define IOLN_MMR3 002 #define IOLN_MMR3 002
#define IOBA_TM (IOPAGEBASE + 012520) /* TM11 */ #define IOBA_TM (IOPAGEBASE + 012520) /* TM11 */
@ -403,6 +561,8 @@ typedef struct pdp_dib DIB;
#define IOLN_HK 040 #define IOLN_HK 040
#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ #define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */
#define IOLN_LPT 004 #define IOLN_LPT 004
#define IOBA_CTL (IOPAGEBASE + 017520) /* board ctrl */
#define IOLN_CTL 010
#define IOBA_CLK (IOPAGEBASE + 017546) /* KW11L */ #define IOBA_CLK (IOPAGEBASE + 017546) /* KW11L */
#define IOLN_CLK 002 #define IOLN_CLK 002
#define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */ #define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */
@ -413,12 +573,26 @@ typedef struct pdp_dib DIB;
#define IOLN_TTI 004 #define IOLN_TTI 004
#define IOBA_TTO (IOPAGEBASE + 017564) /* DL11 xmt */ #define IOBA_TTO (IOPAGEBASE + 017564) /* DL11 xmt */
#define IOLN_TTO 004 #define IOLN_TTO 004
#define IOBA_SRMM (IOPAGEBASE + 017570) /* SR, MMR0-2 */ #define IOBA_SR (IOPAGEBASE + 017570) /* SR */
#define IOLN_SRMM 010 #define IOLN_SR 002
#define IOBA_APR1 (IOPAGEBASE + 017600) /* APRs */ #define IOBA_MMR012 (IOPAGEBASE + 017572) /* MMR0-2 */
#define IOLN_APR1 0100 #define IOLN_MMR012 006
#define IOBA_UIPDR (IOPAGEBASE + 017600) /* user APR's */
#define IOLN_UIPDR 020
#define IOBA_UDPDR (IOPAGEBASE + 017620)
#define IOLN_UDPDR 020
#define IOBA_UIPAR (IOPAGEBASE + 017640)
#define IOLN_UIPAR 020
#define IOBA_UDPAR (IOPAGEBASE + 017660)
#define IOLN_UDPAR 020
#define IOBA_GPR (IOPAGEBASE + 017700) /* GPR's */
#define IOLN_GPR 010
#define IOBA_UCTL (IOPAGEBASE + 017730) /* UBA ctrl */
#define IOLN_UCTL 010
#define IOBA_CPU (IOPAGEBASE + 017740) /* CPU reg */ #define IOBA_CPU (IOPAGEBASE + 017740) /* CPU reg */
#define IOLN_CPU 040 #define IOLN_CPU 036
#define IOBA_PSW (IOPAGEBASE + 017776) /* PSW */
#define IOLN_PSW 002
/* Interrupt assignments; within each level, priority is right to left */ /* Interrupt assignments; within each level, priority is right to left */
@ -445,7 +619,8 @@ typedef struct pdp_dib DIB;
#define INT_V_RY 11 #define INT_V_RY 11
#define INT_V_XQ 12 #define INT_V_XQ 12
#define INT_V_XU 13 #define INT_V_XU 13
#define INT_V_PIR5 14 #define INT_V_TU 14
#define INT_V_PIR5 15
#define INT_V_TTI 0 /* BR4 */ #define INT_V_TTI 0 /* BR4 */
#define INT_V_TTO 1 #define INT_V_TTO 1
@ -479,6 +654,7 @@ typedef struct pdp_dib DIB;
#define INT_RY (1u << INT_V_RY) #define INT_RY (1u << INT_V_RY)
#define INT_XQ (1u << INT_V_XQ) #define INT_XQ (1u << INT_V_XQ)
#define INT_XU (1u << INT_V_XU) #define INT_XU (1u << INT_V_XU)
#define INT_TU (1u << INT_V_TU)
#define INT_PIR5 (1u << INT_V_PIR5) #define INT_PIR5 (1u << INT_V_PIR5)
#define INT_PTR (1u << INT_V_PTR) #define INT_PTR (1u << INT_V_PTR)
#define INT_PTP (1u << INT_V_PTP) #define INT_PTP (1u << INT_V_PTP)
@ -509,6 +685,7 @@ typedef struct pdp_dib DIB;
#define IPL_RY 5 #define IPL_RY 5
#define IPL_XQ 5 #define IPL_XQ 5
#define IPL_XU 5 #define IPL_XU 5
#define IPL_TU 5
#define IPL_PTR 4 #define IPL_PTR 4
#define IPL_PTP 4 #define IPL_PTP 4
#define IPL_TTI 4 #define IPL_TTI 4
@ -545,6 +722,7 @@ typedef struct pdp_dib DIB;
#define VEC_DTA 0214 #define VEC_DTA 0214
#define VEC_TM 0224 #define VEC_TM 0224
#define VEC_TS 0224 #define VEC_TS 0224
#define VEC_TU 0224
#define VEC_RP 0254 #define VEC_RP 0254
#define VEC_TQ 0260 #define VEC_TQ 0260
#define VEC_RX 0264 #define VEC_RX 0264
@ -571,6 +749,16 @@ typedef struct pdp_dib DIB;
#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##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) #define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv)
/* Massbus definitions */
#define MBA_NUM 2 /* number of MBA's */
#define MBA_RP 0 /* MBA for RP */
#define MBA_TU 1 /* MBA for TU */
#define MBA_RMASK 037 /* max 32 reg */
#define MBE_NXD 1 /* nx drive */
#define MBE_NXR 2 /* nx reg */
#define MBE_GOE 3 /* err on GO */
/* CPU and FPU macros */ /* CPU and FPU macros */
#define update_MM ((MMR0 & MMR0_FREEZE) == 0) #define update_MM ((MMR0 & MMR0_FREEZE) == 0)
@ -582,16 +770,27 @@ typedef struct pdp_dib DIB;
/* Function prototypes */ /* Function prototypes */
t_bool Map_Addr (uint32 qa, uint32 *ma); int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf, t_bool map); int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf);
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool map); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf);
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool map); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf);
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool map);
t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat auto_config (uint32 rank, uint32 num); t_stat auto_config (uint32 rank, uint32 num);
t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp);
int32 mba_rdbufW (uint32 mbus, int32 bc, uint16 *buf);
int32 mba_wrbufW (uint32 mbus, int32 bc, uint16 *buf);
int32 mba_chbufW (uint32 mbus, int32 bc, uint16 *buf);
int32 mba_get_bc (uint32 mbus);
int32 mba_get_csr (uint32 mbus);
void mba_upd_ata (uint32 mbus, uint32 val);
void mba_set_exc (uint32 mbus);
void mba_set_don (uint32 mbus);
t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc);
#endif #endif

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: PDP-11 Simulator Usage Subj: PDP-11 Simulator Usage
Date: 15-Jun-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -59,12 +59,14 @@ sim/ scp.h
sim_timer.c sim_timer.c
sim_tmxr.c sim_tmxr.c
sim/pdp11/ pdp11_defs.h sim/pdp11/ pdp11_cpumod.h
pdp11_defs.h
pdp11_mscp.h pdp11_mscp.h
pdp11_uqssp.h pdp11_uqssp.h
pdp11_xq.h pdp11_xq.h
pdp11_xq_bootrom.h pdp11_xq_bootrom.h
pdp11_cpu.c pdp11_cpu.c
pdp11_cpumod.c
pdp11_dz.c pdp11_dz.c
pdp11_fp.c pdp11_fp.c
pdp11_hk.c pdp11_hk.c
@ -72,18 +74,20 @@ sim/pdp11/ pdp11_defs.h
pdp11_lp.c pdp11_lp.c
pdp11_pclk.c pdp11_pclk.c
pdp11_pt.c pdp11_pt.c
pdp11_rh.c
pdp11_rk.c pdp11_rk.c
pdp11_rl.c pdp11_rl.c
pdp11_rp.c pdp11_rp.c
pdp11_rq.c pdp11_rq.c
pdp11_tq.c
pdp11_rx.c pdp11_rx.c
pdp11_ry.c pdp11_ry.c
pdp11_stddev.c pdp11_stddev.c
pdp11_sys.c pdp11_sys.c
pdp11_tc.c pdp11_tc.c
pdp11_tm.c pdp11_tm.c
pdp11_tq.c
pdp11_ts.c pdp11_ts.c
pdp11_tu.c
pdp11_vh.c pdp11_vh.c
pdp11_xq.c pdp11_xq.c
pdp11_xu.c pdp11_xu.c
@ -95,31 +99,32 @@ The PDP-11 simulator is configured as follows:
device simulates device simulates
name(s) name(s)
CPU J-11 CPU with 256KB of memory CPU PDP-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 PTR,PTP PC11 paper tape reader/punch
TTI,TTO DL11 console terminal TTI,TTO DL11 console terminal
LPT LP11 line printer LPT LP11 line printer
CLK line frequency clock CLK line frequency clock
PCLK KW11P programmable clock PCLK KW11P programmable clock
DZ DZ11 8-line terminal multiplexor (up to 4) DZ DZ11 8-line terminal multiplexor (up to 4)
VH DHQ11 8-line terminal multiplexor (up to 4) VH DHU11/DHQ11 8-line terminal multiplexor (up to 4)
RK RK11/RK05 cartridge disk controller with eight drives RK RK11/RK05 cartridge disk controller with eight drives
HK RK611/RK06(7) cartridge disk controller with eight drives HK RK611/RK06(7) cartridge disk controller with eight drives
RL RLV12/RL01(2) cartridge disk controller with four drives RL RLV12/RL01(2) cartridge disk controller with four drives
RP RM02/03/05/80, RP04/05/06/07 Massbus style controller RH RH11/RH70 Massbus adapter (up to 2)
RP RM02/03/05/80, RP04/05/06/07 Massbus disks
with eight drives with eight drives
RQ RQDX3 MSCP controller with four drives RQ RQDX3/UDA50 MSCP controller with four drives
RQB second RQDX3 MSCP controller with four drives RQB second RQDX3/UDA50 MSCP controller with four drives
RQC third RQDX3 MSCP controller with four drives RQC third RQDX3/UDA50 MSCP controller with four drives
RQD fourth RQDX3 MSCP controller with four drives RQD fourth RQDX3/UDA50 MSCP controller with four drives
RX RX11/RX01 floppy disk controller with two drives RX RX11/RX01 floppy disk controller with two drives
RY RX211/RX01 floppy disk controller with two drives RY RX211/RX01 floppy disk controller with two drives
TC TC11/TU56 DECtape controller with eight drives TC TC11/TU56 DECtape controller with eight drives
TM TM11/TU10 magnetic tape controller with eight drives TM TM11/TU10 magnetic tape controller with eight drives
TS TS11/TSV05 magnetic tape controller with one drive TS TS11/TSV05 magnetic tape controller with one drive
TQ TQK50 TMSCP magnetic tape controller with four drives TQ TQK50/TU81 TMSCP magnetic tape controller with four drives
TU TM02/TM03 magnetic tape formatter with eight
TE16/TU45/TU77 drives
XQ DELQA/DEQNA Qbus Ethernet controller XQ DELQA/DEQNA Qbus Ethernet controller
XQB second DELQA/DEQNA Qbus Ethernet controller XQB second DELQA/DEQNA Qbus Ethernet controller
XU DEUNA/DELUA Unibus Ethernet controller XU DEUNA/DELUA Unibus Ethernet controller
@ -140,19 +145,44 @@ The PDP-11 simulator implements several unique stop conditions:
The PDP-11 loader supports standard binary format tapes. The DUMP command The PDP-11 loader supports standard binary format tapes. The DUMP command
is not implemented. is not implemented.
2.1 CPU 2.1 CPU and System
The CPU options include CPU mapping configuration (18b Unibus, 22b Unibus 2.1.1 CPU
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 U18 Unibus, no I/O map, 18b addressing The CPU options include CPU type, CPU instruction set options for the
SET CPU URH11 Unibus, I/O map with 22b addressing, specified type, and the size of main memory.
18b mapped RH11 controller
SET CPU URH70 Unibus, I/O map with 22b addressing, SET CPU 11/03 set CPU type to 11/03
22b unmapped RH70 controller SET CPU 11/04 set CPU type to 11/04
SET CPU Q22 Qbus, no I/O map, 22b addressing SET CPU 11/05 set CPU type to 11/05
SET CPU NOCIS disable CIS instructions (default) SET CPU 11/20 set CPU type to 11/20
SET CPU 11/23 set CPU type to 11/23
SET CPU 11/23+ set CPU type to 11/23+
SET CPU 11/24 set CPU type to 11/24
SET CPU 11/34 set CPU type to 11/34
SET CPU 11/40 set CPU type to 11/40
SET CPU 11/44 set CPU type to 11/44
SET CPU 11/45 set CPU type to 11/45
SET CPU 11/53 set CPU type to 11/53
SET CPU 11/60 set CPU type to 11/60
SET CPU 11/70 set CPU type to 11/70
SET CPU 11/73 set CPU type to 11/73
SET CPU 11/73B set CPU type to 11/73B
SET CPU 11/83 set CPU type to 11/83
SET CPU 11/84 set CPU type to 11/84
set CPU 11/93 set CPU type to 11/93
set CPU 11/94 set CPU type to 11/94
SET CPU U18 deprecated; same as 11/45
SET CPU URH11 deprecated; same as 11/84
SET CPU URH70 deprecated; same as 11/70
SET CPU Q22 deprecated; same as 11/73
SET CPU NOEIS disable EIS instructions
SET CPU EIS enable EIS instructions
SET CPU NOFIS disable FIS instructions
SET CPU FIS enable FIS instructions
SET CPU NOFPP disable FPP instructions
SET CPU FPP enable FPP instructions
SET CPU NOCIS disable CIS instructions
SET CPU CIS enable CIS instructions SET CPU CIS enable CIS instructions
SET CPU 16K set memory size = 16KB SET CPU 16K set memory size = 16KB
SET CPU 32K set memory size = 32KB SET CPU 32K set memory size = 32KB
@ -170,9 +200,37 @@ with RH70-style controllers, 22b Unibus with RH11 style controllers, and
SET CPU 3072K (or 3M) set memory size = 3072KB SET CPU 3072K (or 3M) set memory size = 3072KB
SET CPU 4096K (or 4M) set memory size = 4096KB SET CPU 4096K (or 4M) set memory size = 4096KB
The CPU implements a show command to display the I/O address space map: The CPU types and their capabilities are shown in the following table:
SHOW CPU IOSPACE show I/O space address map type bus memory MMU? Umap? EIS? FIS? FPP? CIS?
11/03 Q 64K no no std opt no no
11/04 U 64K no no no no no no
11/05 U 64K no no no no no no
11/20 U 64K no no no no no no
11/23 Q 4M std no std no opt opt
11/23+ Q 4M std no std no opt opt
11/24 U 4M std std std no opt opt
11/34 U 256K std no std no opt no
11/40 U 256K std no std opt no no
11/44 U 4M std std std no opt opt
11/45 U 256K std no std no opt no
11/53 Q 4M std no std no std opt
11/60 U 256K std no std no std no
11/70 U 4M std std std no opt no
11/73 Q 4M std no std no std opt
11/73B Q 4M std no std no std opt
11/83 Q 4M std no std no std opt
11/84 U 4M std std std no std opt
11/93 Q 4M std no std no std opt
11/94 U 4M std std std no std opt
If a capability is standard, it cannot be disabled; if a capability is
not included, it cannot be enabled.
The CPU implements a show command to display the I/O address assignments:
SHOW CPU IOSPACE show I/O space address assignments
If memory size is being reduced, and the memory being truncated contains If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated non-zero data, the simulator asks for confirmation. Data in the truncated
@ -181,31 +239,6 @@ is being increased to more than 256KB, or the bus structue is being changed,
the simulator asks whether it should disable peripherals that can't run the simulator asks whether it should disable peripherals that can't run
in the current bus structure. in the current bus structure.
DMA peripherals function differently, depending on whether the CPU is
configured for 18B, URH11, URH70, or 22B addressing and I/O:
peripheral 18B URH11 URH70 22B
RK 18b 18b 18b won't work, disabled
HK 18b 18b 18b SC02/C 22b, works
only with Ultrix-11
RL 18b 18b 18b 22b RLV12
RP 18b 18b 22b 22b third party
RQ 18b 18b 18b 22b RQDX3
RY 18b 18b 18b won't work, disabled
TC 18b 18b 18b won't work, disabled
TM 18b 18b 18b won't work, disabled
TS 18b 18b 18b 22b TSV05
TQ 18b 18b 18b 22b TQK50
XQ 18b won't work, 22b DELQA
disabled
XU 18b 18b 18b won't work, disabled
Non-DMA peripherals work the same in all configurations. Unibus-only
peripherals should be disabled in a Qbus (22B) configuration with more
than 256KB of memory, and Qbus-only peripherals should be disabled in
a Unibus (URH11 or URH70) configuration with more than 256KB of memory.
These switches are recognized when examining or depositing in CPU memory: These switches are recognized when examining or depositing in CPU memory:
-v interpret address as virtual -v interpret address as virtual
@ -215,8 +248,8 @@ These switches are recognized when examining or depositing in CPU memory:
-u if mem mgt enabled, force user mode -u if mem mgt enabled, force user mode
-p if mem mgt enabled, force previous mode -p if mem mgt enabled, force previous mode
CPU registers include the visible state of the processor as well as the CPU registers include the architectural state of the PDP-11 processor
control registers for the interrupt system. as well as the control registers for the interrupt system.
name size comments name size comments
@ -238,14 +271,8 @@ control registers for the interrupt system.
Z 1 zero flag, PSW<2> Z 1 zero flag, PSW<2>
V 1 overflow flag, PSW<1> V 1 overflow flag, PSW<1>
C 1 carry flag, PSW<0> 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 PIRQ 16 programmed interrupt requests
STKLIM 16 stack limit
FAC0H..FAC5H 32 FAC0..FAC5, high 32 bits FAC0H..FAC5H 32 FAC0..FAC5, high 32 bits
FAC0L..FAC5L 32 FAC0..FAC5, low 32 bits FAC0L..FAC5L 32 FAC0..FAC5, low 32 bits
FPS 16 floating point status FPS 16 floating point status
@ -254,9 +281,8 @@ control registers for the interrupt system.
MMR0..3 16 memory management registers 0..3 MMR0..3 16 memory management registers 0..3
{K/S/U}{I/D}{PAR/PDR}{0..7} {K/S/U}{I/D}{PAR/PDR}{0..7}
16 memory management registers 16 memory management registers
UBMAP[0:63] 16 Unibus map registers IREQ[0:7] 32 interrupt pending flags, IPL 0-7
INT 32 interrupt pending flags TRAPS 18 trap pending flags
TRAP 18 trap pending flags
WAIT 0 wait state flag WAIT 0 wait state flag
WAIT_ENABLE 0 wait state enable flag WAIT_ENABLE 0 wait state enable flag
STOP_TRAPS 18 stop on trap flags STOP_TRAPS 18 stop on trap flags
@ -266,7 +292,87 @@ control registers for the interrupt system.
most recent PC change first most recent PC change first
WRU 8 interrupt character WRU 8 interrupt character
2.2 I/O Device Addressing 2.1.2 System Registers (SYSTEM)
The SYSTEM device implements registers that vary from system to system:
name models size comments
SR 11/04, 11/05, 11/20, 16 switch register or
11/23+, 11/34, 11/40, configuration register
11/44, 11/45, 11/60,
11/70, 11/73B, 11/83,
11/84, 11/93, 11/94
DR 11/04, 11/05, 11/20, 16 display register or
1123+, 11/24, 11/34, board LEDs
11/70, 11/73B, 11/83,
11/84, 11/93, 11/94
MEMERR 11/44, 11/60, 11/70, 16 memory error register
11/53, 11/73, 11/73B,
11/83, 11/84, 11/93,
11/94
CCR 11/44, 11/60, 11/70, 16 cache control register
11/53, 11/73, 11/73B,
11/83, 11/84, 11/93,
11/94
MAINT 11/23+, 11/44, 11/70, 16 maintenance register
11/53, 11/73, 11/73B,
11/83, 11/84, 11/93,
11/94
HITMISS 11/44, 11/60, 11/70, 16 hit/miss register
11/53, 11/73, 11/73B,
11/83, 11/84, 11/93,
11/94
CPUERR 11/24, 11/44, 11/70, 16 CPU error register
11/53, 11/73, 11/73B,
11/83, 11/84, 11/93,
11/94
MBRK 11/45, 11/70 16 microbreak register
JCSR 11/53, 11/73B, 11/83, 16 board control/status
11/84, 11/93, 11/94
JPCR 11/23+, 11/53, 11/73B, 16 page control register
11/83, 11/84, 11/93,
11/94
JASR 11/93, 11/94 16 additional status
UDCR 11/84, 11/94 16 Unibus map diag control
UDDR 11/84, 11/94 16 Unibus map diag data
UCSR 11/84, 11/94 16 Unibus map control/status
ULAST 11/24 23 last Unibus map result
2.2 I/O Devices
2.2.1 Unibus and Qbus DMA Devices
DMA peripherals function differently, depending on whether the CPU is
configured for Unibus or Qbus, and whether the Unibus system supports
22b direct memory access (11/70 with RH70 controllers):
peripheral 11/70 all Qbus
+RH70 other
Unibus
RK 18b 18b disabled
HK 18b 18b disabled
RL 18b 18b 22b RLV12
RP 22b 18b 22b third party
RQ 18b 18b 22b RQDX3
RY 18b 18b disabled
TC 18b 18b disabled
TM 18b 18b disabled
TS 18b 18b 22b TSV05
TQ 18b 18b 22b TQK50
TU 22b 18b 22b third party
VH 18b 18b 22b DHQ11
XQ disabled 22b DELQA
XU 18b 18b disabled
Non-DMA peripherals work the same in all configurations. Unibus-only
peripherals are disabled in a Qbusconfiguration, and Qbus-only
peripherals are disabled in a Unibus configuration. In addition,
Qbus DMA peripherals with only 18b addressing capability are
disabled in a Qbus configuration with more than 256KB memory.
2.2.2 I/O Device Addressing
PDP-11 I/O space is not large enough to allow all possible devices to be PDP-11 I/O space is not large enough to allow all possible devices to be
configured simultaneously at fixed addresses. Instead, many devices have configured simultaneously at fixed addresses. Instead, many devices have
@ -274,6 +380,7 @@ floating addresses; that is, the assigned device address depends on the
presense of other devices in the configuration: presense of other devices in the configuration:
DZ11 all instances have floating addresses DZ11 all instances have floating addresses
DHU11/DHQ11 all instances have floating addresses
RL11 first instance has fixed address, rest floating RL11 first instance has fixed address, rest floating
RX11/RX211 first instance has fixed address, rest floating RX11/RX211 first instance has fixed address, rest floating
DEUNA/DELUA first instance has fixed address, rest floating DEUNA/DELUA first instance has fixed address, rest floating
@ -550,8 +657,8 @@ locked, single or double density, or autosized:
SET RYn DOUBLE set unit n double density (default) SET RYn DOUBLE set unit n double density (default)
SET RYn AUTOSIZE set unit n autosized SET RYn AUTOSIZE set unit n autosized
The RX211 supports the BOOT command. The RX211 will not function The RX211 supports the BOOT command. The RX211 is disabled in a
properly in a Qbus (22B) system with more than 256KB of memory. Qbus (Q22) system with more than 256KB of memory.
The RX211 implements these registers: The RX211 implements these registers:
@ -597,9 +704,9 @@ locked:
SET RKn LOCKED set unit n write locked SET RKn LOCKED set unit n write locked
SET RKn WRITEENABLED set unit n write enabled SET RKn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. The RK11 supports the BOOT Units can also be set ENABLED or DISABLED. The RK11 supports the BOOT
command. The RK11 will not function properly in a Qbus (22B) system command. The RK11 is disabled in a Qbus (Q22) system with more than
with more than 256KB of memory. 256KB of memory.
The RK11 implements these registers: The RK11 implements these registers:
@ -648,11 +755,8 @@ a DEC standard 044 compliant bad block table on the last track:
The size options can be used only when a unit is not attached to a file. 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. The bad block option can be used only when a unit is attached to a file.
Units can be set ONLINE or OFFLINE. The RK611 supports the BOOT command. Units can be set ENABLED or DISABLED. The RK611 supports the BOOT command.
The RK611 will not function properly in a Qbus (22B) system with more The RK611 is disabled in a Qbus (Q22) system with more than 256KB of memory.
than 256KB of memory using standard DEC software. The simulator implements
a third-party extension of addressing capability to 22b; this is only
supported by Ultrix-11.
The RK611 implements these registers: The RK611 implements these registers:
@ -704,10 +808,9 @@ a DEC standard 044 compliant bad block table on the last track:
The size options can be used only when a unit is not attached to a file. 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. The bad block option can be used only when a unit is attached to a file.
Units can be set ONLINE or OFFLINE. The RL11 supports the BOOT command. Units can be set ENABLED or DISABLED. The RL11 supports the BOOT command.
In an 18B or Unibus system, the RL behaves like an RL11 with 18b In a Unibus system, the RL behaves like an RL11 with 18b addressing; in
addressing; in a Qbus (22B) system, the RL behaves like the RLV12 with a Qbus (Q22) system, the RL behaves like the RLV12 with 22b addressing.
22b addressing.
The RL11 implements these registers: The RL11 implements these registers:
@ -737,14 +840,34 @@ Error handling is as follows:
OS I/O error x report error and stop OS I/O error x report error and stop
2.6 RM02/03/05/80, RP04/05/06/07 Disk Pack Drives (RP) 2.6 Massbus Subsystems
The RP controller implements a "Massbus style" 22b direct interface 2.6.1 RH70/RH11 Massbus Adapters (RHA, RHB)
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.
The RH70/RH11 Massbus adapters interface Massbus peripherals to the
memory bus or Unibus of the CPU. The simulator provides two Massbus
adapters. The first, RHA, is configured for the RP family of disk
drives. The second, RHB, is configured for the TU family of tape
controllers. By default, RHA is enabled and RHB is disabled.
Each RH adapter implements these registers:
CS1 16 control/status register 1
WC 16 word count
BA 16 bus address
CS2 16 control/status register 2
DB 16 data buffer
BAE 6 bus address extension
CS3 16 control/status register 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>)
2.6.2 RM02/03/05/80, RP04/05/06/07 Disk Pack Drives (RP)
The RP controller implements the Massbus family of large disk drives.
RP options include the ability to set units write enabled or write 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, 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 and to write a DEC standard 044 compliant bad block table on the last
@ -763,37 +886,29 @@ track:
The type options can be used only when a unit is not attached to a file. 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. The bad block option can be used only when a unit is attached to a file.
Units can be set ONLINE or OFFLINE. The RP controller supports the Units can be set ENABLED or DISABLED. The RP controller supports the
BOOT command. In a Unibus system, the RP can implement either 18b BOOT command. In a Unibus system, the RP can implement either 18b
(RH11) addressing or 22b (RH70) addressing. In a Qbus (22B) system, (URH11) addressing or 22b (URH70) addressing. In a Qbus (Q22) system,
the RP always implements 22b addressing. the RP always implements 22b addressing.
The RP controller implements these registers: The RP controller implements the registers listed below. Registers
suffixed with [0:7] are replicated per drive.
name size comments name size comments
RPCS1 16 control/status 1 CS1[0:7] 16 current operation
RPWC 16 word count DA[0:7] 16 desired surface, sector
RPBA 16 bus address DS[0:7] 16 drive status
RPDA 16 desired surface, sector ER1[0:7] 16 drive errors
RPCS2 16 control/status 2 OF[0:7] 16 offset
RPDS[0:7] 16 drive status, drives 0-7 DC[0:7] 16 desired cylinder
RPER1[0:7] 16 drive errors, drives 0-7 ER2[0:7] 16 error status 2
RPOF 16 offset ER3[0:7] 16 error status 3
RPDC 16 desired cylinder EC1[0:7] 16 ECC syndrome 1
RPER2 16 error status 2 EC2[0:7] 16 ECC syndrome 2
RPER3 16 error status 3 MR[0:7] 16 maintenance register
RPEC1 16 ECC syndrome 1 MR2[0:7] 16 maintenance register 2 (RM only)
RPEC2 16 ECC syndrome 2 HR[0:7] 16 holding register (RM only)
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 STIME 24 seek time, per cylinder
RTIME 24 rotational delay RTIME 24 rotational delay
STOP_IOE 1 stop on I/O error STOP_IOE 1 stop on I/O error
@ -809,7 +924,49 @@ Error handling is as follows:
OS I/O error x report error and stop OS I/O error x report error and stop
2.7 RQDX3 MSCP Disk Controllers (RQ, RQB, RQC, RQD) 2.6.3 TM02/TM03/TE16/TU45/TU77 Magtapes (TU)
The TU controller implementes the Massbus family of 800/1600bpi tape
drives. TU options include the ability to select the formatter type
(TM02 or TM03), to set the drive type to one of three drives (TE16,
TU45, or TU77), and to set the drives write enabled or write locked.
SET TU TM02 set controller type to TM02
SET TU TM03 set controller type to TM03
set TUn TE16 set drive type to TE16
SET TUn TU45 set drive type to TU45
SET TUn TU77 set drive type to TU77
Units can be set ENABLED or DISABLED. The TU controller supports the
BOOT command. In a Unibus system, the TU can implement either 18b
(URH11) addressing or 22b (URH70) addressing. In a Qbus (Q22) system,
the TU always implements 22b addressing.
The TU controller implements the following registers:
name size comments
CS1 6 current operation
FC 16 frame count
FS 16 formatter status
ER 16 formatter errors
CC 16 check character
MR 16 maintenance register
TC 16 tape control register
TIME 24 operation execution time
STOP_IOE 1 stop of I/O error
Error handling is as follows:
error processed as
not attached tape not ready; if STOP_IOE, stop
end of file bad tape
OS I/O error parity error; if STOP_IOE, stop
2.7 RQDX3/UDA50 MSCP Disk Controllers (RQ, RQB, RQC, RQD)
The simulator implements four MSCP disk controllers, RQ, RQB, RQC, RQD. The simulator implements four MSCP disk controllers, RQ, RQB, RQC, RQD.
Initially, RQB, RQC, and RQD are disabled. Each RQ controller simulates Initially, RQB, RQC, and RQD are disabled. Each RQ controller simulates
@ -831,16 +988,18 @@ of many disk types:
SET RQn RA90 set type to RA90 SET RQn RA90 set type to RA90
SET RQn RA92 set type to RA92 SET RQn RA92 set type to RA92
SET RQn RRD40 set type to RRD40 (CD ROM) SET RQn RRD40 set type to RRD40 (CD ROM)
SET RQn RAUSER{=n} set type to RA81 with n LBNs SET RQn RAUSER{=n} set type to RA81 with n MB's
SET -L RQn RAUSER{=n} set type to RA81 with n LBN's
The type options can be used only when a unit is not attached to a file. The type options can be used only when a unit is not attached to a file.
RAUSER is a "user specified" disk; the user can specify the size of the RAUSER is a "user specified" disk; the user can specify the size of the
disk in logical block numbers (LBN's, 512 bytes each). The minimum size disk in either MB (1000000 bytes) or logical block numbers (LBN's, 512
is 50MB; the maximum size is 2GB. bytes each). The minimum size is 5MB; the maximum size is 2GB.
Units can also be set ONLINE or OFFLINE. Each RQ controller supports the Units can also be set ENABLED or DISABLED. Each RQ controller supports the
BOOT command. In a Unibus system, an RQ supports 18b addressing. In BOOT command. In a Unibus system, an RQ supports 18b addressing and
a Qbus (22B) system, an RQ supports 22b addressing. identifies itself as a UDA50. In a Qbus (Q22) system, an RQ supports 22b
addressing and identifies itself as an RQDX3.
Each RQ controller implements the following special SHOW commands: Each RQ controller implements the following special SHOW commands:
@ -907,9 +1066,8 @@ locked.
SET DTn LOCKED set unit n write locked SET DTn LOCKED set unit n write locked
SET DTn WRITEENABLED set unit n write enabled SET DTn WRITEENABLED set unit n write enabled
Units can be set ONLINE or OFFLINE. The TC11 supports the BOOT command. Units can be set ENABLED or DISABLED. The TC11 supports the BOOT command.
The TC11 will not function properly in a 22B (Qbus) system with more The TC11 is automatically disabled in a Qbus system.
than 256KB of memory.
The TC11 supports supports PDP-8 format, PDP-11 format, and 18b format The TC11 supports supports PDP-8 format, PDP-11 format, and 18b format
DECtape images. ATTACH tries to determine the tape format from the DECtape DECtape images. ATTACH tries to determine the tape format from the DECtape
@ -965,7 +1123,7 @@ locked.
SET TMn LOCKED set unit n write locked SET TMn LOCKED set unit n write locked
SET TMn WRITEENABLED set unit n write enabled SET TMn WRITEENABLED set unit n write enabled
Units can be set ONLINE or OFFLINE. Units can be set ENABLED or DISABLED.
The TM11 supports the BOOT command. The bootstrap supports both original The TM11 supports the BOOT command. The bootstrap supports both original
and DEC standard boot formats. Originally, a tape bootstrap read and and DEC standard boot formats. Originally, a tape bootstrap read and
@ -974,8 +1132,8 @@ standard bootstrap skipped the first record and read and executed the
second. The DEC standard is the default; to bootstrap an original format second. The DEC standard is the default; to bootstrap an original format
tape, use the -o switch. tape, use the -o switch.
The TM11 will not function properly in a Qbus (22B) system with more The TM11 is automatically disabled in a Qbus (Q22) system with more than
than 256KB of memory 256KB of memory.
The TM controller implements these registers: The TM controller implements these registers:
@ -1017,7 +1175,7 @@ The TS11 supports the BOOT command. The bootstrap supports only DEC
standard boot formats. To allow for ANSI labels, the DEC standard standard boot formats. To allow for ANSI labels, the DEC standard
bootstrap skipped the first record and read and executed the second. bootstrap skipped the first record and read and executed the second.
In a Unibus system, the TS behaves like the TS11 and implements 18b In a Unibus system, the TS behaves like the TS11 and implements 18b
addresses. In a Qbus (22B) system, the TS behaves like the TSV05 addresses. In a Qbus (Q22) system, the TS behaves like the TSV05
and implements 22b addresses. and implements 22b addresses.
The TS controller implements these registers: The TS controller implements these registers:
@ -1077,7 +1235,7 @@ specify the controller type and tape length:
User-specified capacity must be between 50 and 2000 MB. User-specified capacity must be between 50 and 2000 MB.
The TQ controller supports the BOOT command. In a Unibus system, the The TQ controller supports the BOOT command. In a Unibus system, the
TQ supports 18b addressing. In a Qbus (22B) system, the TQ supports TQ supports 18b addressing. In a Qbus (Q22) system, the TQ supports
22b addressing. 22b addressing.
The TQ controller implements the following special SHOW commands: The TQ controller implements the following special SHOW commands:

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
04-Oct-04 RMS Added FIS instructions
19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict
08-Oct-02 RMS Fixed macro definitions 08-Oct-02 RMS Fixed macro definitions
05-Jun-98 RMS Fixed implementation specific shift bugs 05-Jun-98 RMS Fixed implementation specific shift bugs
@ -194,10 +195,13 @@
#define GET_SIGN_W(ir) GET_BIT((ir), 15) #define GET_SIGN_W(ir) GET_BIT((ir), 15)
extern jmp_buf save_env; extern jmp_buf save_env;
extern int32 cpu_type;
extern int32 FEC, FEA, FPS; extern int32 FEC, FEA, FPS;
extern int32 CPUERR, trap_req; extern int32 CPUERR, trap_req;
extern int32 N, Z, V, C; extern int32 N, Z, V, C;
extern int32 R[8]; extern int32 R[8];
extern int32 STKLIM;
extern int32 cm, isenable, dsenable, MMR0, MMR1;
extern fpac_t FR[6]; extern fpac_t FR[6];
fpac_t zero_fac = { 0, 0 }; fpac_t zero_fac = { 0, 0 };
@ -219,7 +223,7 @@ int32 backup_PC;
int32 fpnotrap (int32 code); int32 fpnotrap (int32 code);
int32 GeteaFP (int32 spec, int32 len); int32 GeteaFP (int32 spec, int32 len);
unsigned int32 ReadI (int32 addr, int32 spec, int32 len); uint32 ReadI (int32 addr, int32 spec, int32 len);
void ReadFP (fpac_t *fac, int32 addr, int32 spec, int32 len); void ReadFP (fpac_t *fac, int32 addr, int32 spec, int32 len);
void WriteI (int32 data, int32 addr, int32 spec, int32 len); void WriteI (int32 data, int32 addr, int32 spec, int32 len);
void WriteFP (fpac_t *data, int32 addr, int32 spec, int32 len); void WriteFP (fpac_t *data, int32 addr, int32 spec, int32 len);
@ -235,6 +239,7 @@ int32 round_and_pack (fpac_t *fac, int32 exp, fpac_t *frac, int r);
extern int32 GeteaW (int32 spec); extern int32 GeteaW (int32 spec);
extern int32 ReadW (int32 addr); extern int32 ReadW (int32 addr);
extern void WriteW (int32 data, int32 addr); extern void WriteW (int32 data, int32 addr);
extern void set_stack_trap (int32 adr);
/* Set up for instruction decode and execution */ /* Set up for instruction decode and execution */
@ -244,7 +249,7 @@ int32 dst, ea, ac, dstspec;
int32 i, qdouble, lenf, leni; int32 i, qdouble, lenf, leni;
int32 newV, exp, sign; int32 newV, exp, sign;
fpac_t fac, fsrc, modfrac; fpac_t fac, fsrc, modfrac;
static const unsigned int32 i_limit[2][2] = static const uint32 i_limit[2][2] =
{ { 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 } }; { { 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 } };
backup_PC = PC; /* save PC for FEA */ backup_PC = PC; /* save PC for FEA */
@ -471,6 +476,9 @@ case 6: /* SUBf */
case 011: /* DIVf */ case 011: /* DIVf */
ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf); ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
F_LOAD (qdouble, FR[ac], fac); F_LOAD (qdouble, FR[ac], fac);
if (GET_EXP (fsrc.h) == 0) { /* divide by zero? */
fpnotrap (FEC_DZRO);
ABORT (TRAP_INT); }
newV = divfp11 (&fac, &fsrc); newV = divfp11 (&fac, &fsrc);
F_STORE (qdouble, fac, FR[ac]); F_STORE (qdouble, fac, FR[ac]);
FPS = setfcc (FPS, fac.h, newV); FPS = setfcc (FPS, fac.h, newV);
@ -494,7 +502,6 @@ return;
int32 GeteaFP (int32 spec, int32 len) int32 GeteaFP (int32 spec, int32 len)
{ {
int32 adr, reg, ds; int32 adr, reg, ds;
extern int32 cm, isenable, dsenable, MMR0, MMR1;
reg = spec & 07; /* reg number */ reg = spec & 07; /* reg number */
ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */ ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */
@ -517,16 +524,14 @@ case 3: /* @(R)+ */
case 4: /* -(R) */ case 4: /* -(R) */
adr = R[reg] = (R[reg] - len) & 0177777; adr = R[reg] = (R[reg] - len) & 0177777;
if (update_MM) MMR1 = (((-len) & 037) << 3) | reg; if (update_MM) MMR1 = (((-len) & 037) << 3) | reg;
if ((adr < STKLIM) && (reg == 6) && (cm == MD_KER)) { if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
setTRAP (TRAP_YEL); set_stack_trap (adr);
setCPUERR (CPUE_YEL); }
return (adr | ds); return (adr | ds);
case 5: /* @-(R) */ case 5: /* @-(R) */
adr = R[reg] = (R[reg] - 2) & 0177777; adr = R[reg] = (R[reg] - 2) & 0177777;
if (update_MM) MMR1 = 0360 | reg; if (update_MM) MMR1 = 0360 | reg;
if ((adr < STKLIM) && (reg == 6) && (cm == MD_KER)) { if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y)))
setTRAP (TRAP_YEL); set_stack_trap (adr);
setCPUERR (CPUE_YEL); }
adr = ReadW (adr | ds); adr = ReadW (adr | ds);
return (adr | dsenable); return (adr | dsenable);
case 6: /* d(r) */ case 6: /* d(r) */
@ -551,7 +556,7 @@ return 0;
data = data read from memory or I/O space data = data read from memory or I/O space
*/ */
unsigned int32 ReadI (int32 VA, int32 spec, int32 len) uint32 ReadI (int32 VA, int32 spec, int32 len)
{ {
if ((len == WORD) || (spec == 027)) return (ReadW (VA) << 16); if ((len == WORD) || (spec == 027)) return (ReadW (VA) << 16);
return ((ReadW (VA) << 16) | ReadW ((VA & ~0177777) | ((VA + 2) & 0177777))); return ((ReadW (VA) << 16) | ReadW ((VA & ~0177777) | ((VA + 2) & 0177777)));
@ -633,6 +638,66 @@ WriteW ((fptr->l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777));
return; return;
} }
/* FIS instructions */
t_stat fis11 (int32 IR)
{
int32 reg, exta;
fpac_t fac, fsrc;
reg = IR & 07; /* isolate reg */
if (reg == 7) exta = isenable; /* choose I,D */
else exta = dsenable;
if (IR & 000740) { /* defined? */
if (CPUT (CPUT_03)) ReadW (exta | R[reg]); /* 11/03 reads word */
ABORT (TRAP_ILL); }
FEC = 0; /* no errors */
FPS = FPS_IU|FPS_IV; /* trap ovf,unf */
fsrc.h = (ReadW (exta | R[reg]) << FP_V_F0) |
(ReadW (exta | ((R[reg] + 2) & 0177777)) << FP_V_F1);
fsrc.l = 0;
fac.h = (ReadW (exta | ((R[reg] + 4) & 0177777)) << FP_V_F0) |
(ReadW (exta | ((R[reg] + 6) & 0177777)) << FP_V_F1);
fac.l = 0;
if (GET_SIGN (fsrc.h) && (GET_EXP (fsrc.h) == 0)) /* clean 0's */
fsrc.h = fsrc.l = 0;
if (GET_SIGN (fac.h) && (GET_EXP (fac.l) == 0))
fac.h = fac.l = 0;
N = Z = V = C = 0; /* clear cc's */
switch ((IR >> 3) & 3) { /* case IR<5:3> */
case 0: /* FAD */
addfp11 (&fac, &fsrc);
break;
case 1: /* FSUB */
if (fsrc.h != 0) fsrc.h = fsrc.h ^ FP_SIGN; /* invert sign */
addfp11 (&fac, &fsrc);
break;
case 2: /* FMUL */
mulfp11 (&fac, &fsrc);
break;
case 3: /* FDIV */
if (fsrc.h == 0) { /* div by 0? */
V = N = C = 1; /* set cc's */
setTRAP (TRAP_FPE); /* set trap */
return SCPE_OK; }
else divfp11 (&fac, &fsrc);
break; }
if (FEC == 0) { /* no err? */
WriteW ((fac.h >> FP_V_F0) & 0177777, exta | ((R[reg] + 4) & 0177777));
WriteW ((fac.h >> FP_V_F1) & 0177777, exta | ((R[reg] + 6) & 0177777));
R[reg] = (R[reg] + 4) & 0177777; /* pop stack */
N = (GET_SIGN (fac.h) != 0); /* set N,Z */
Z = (fac.h == 0); }
else if (FEC == FEC_OVFLO) V = 1; /* ovf? trap set */
else if (FEC == FEC_UNFLO) V = N = 1; /* unf? trap set */
else return SCPE_IERR; /* what??? */
return SCPE_OK;
}
/* Floating point add /* Floating point add
Inputs: Inputs:
@ -864,6 +929,8 @@ return;
fsrcp = pointer to divisor fsrcp = pointer to divisor
Outputs: Outputs:
ovflo = overflow indicator ovflo = overflow indicator
Source operand must be checked for zero by caller!
*/ */
int32 divfp11 (fpac_t *facp, fpac_t *fsrcp) int32 divfp11 (fpac_t *facp, fpac_t *fsrcp)
@ -872,9 +939,6 @@ int32 facexp, fsrcexp, i, count, qd;
fpac_t facfrac, fsrcfrac, quo; fpac_t facfrac, fsrcfrac, quo;
fsrcexp = GET_EXP (fsrcp->h); /* get divisor exp */ fsrcexp = GET_EXP (fsrcp->h); /* get divisor exp */
if (fsrcexp == 0) { /* divide by zero? */
fpnotrap (FEC_DZRO);
ABORT (TRAP_INT); }
facexp = GET_EXP (facp->h); /* get dividend exp */ facexp = GET_EXP (facp->h); /* get dividend exp */
if (facexp == 0) { /* test for zero */ if (facexp == 0) { /* test for zero */
*facp = zero_fac; /* result zero */ *facp = zero_fac; /* result zero */

View file

@ -25,6 +25,8 @@
hk RK611/RK06/RK07 disk hk RK611/RK06/RK07 disk
03-Oct-04 RMS Revised Unibus interface
RMS Fixed state of output ready for M+
26-Mar-04 RMS Fixed warnings with -std=c99 26-Mar-04 RMS Fixed warnings with -std=c99
25-Jan-04 RMS Revised for device debug support 25-Jan-04 RMS Revised for device debug support
04-Jan-04 RMS Changed sim_fsize calling sequence 04-Jan-04 RMS Changed sim_fsize calling sequence
@ -43,11 +45,16 @@
This module includes ideas from a previous implementation by Fred Van Kempen. This module includes ideas from a previous implementation by Fred Van Kempen.
*/ */
#include "pdp11_defs.h" #if defined (VM_PDP10) /* PDP10 version */
#error "RK611 is not supported on the PDP-10!"
#define HK_RDX 8 #elif defined (VM_VAX) /* VAX version */
#define HK_WID 16 #include "vax_defs.h"
extern int32 cpu_18b, cpu_ubm;
#else /* PDP-11 version */
#include "pdp11_defs.h"
extern int32 cpu_opt;
#endif
extern uint16 *M; extern uint16 *M;
@ -379,37 +386,37 @@ UNIT hk_unit[] = {
UNIT_ROABLE+UNIT_RK06, RK06_SIZE) } }; UNIT_ROABLE+UNIT_RK06, RK06_SIZE) } };
REG hk_reg[] = { REG hk_reg[] = {
{ GRDATA (HKCS1, hkcs1, HK_RDX, 16, 0) }, { GRDATA (HKCS1, hkcs1, DEV_RDX, 16, 0) },
{ GRDATA (HKWC, hkwc, HK_RDX, 16, 0) }, { GRDATA (HKWC, hkwc, DEV_RDX, 16, 0) },
{ GRDATA (HKBA, hkba, HK_RDX, 16, 0) }, { GRDATA (HKBA, hkba, DEV_RDX, 16, 0) },
{ GRDATA (HKDA, hkda, HK_RDX, 16, 0) }, { GRDATA (HKDA, hkda, DEV_RDX, 16, 0) },
{ GRDATA (HKCS2, hkcs2, HK_RDX, 16, 0) }, { GRDATA (HKCS2, hkcs2, DEV_RDX, 16, 0) },
{ BRDATA (HKDS, hkds, HK_RDX, 16, HK_NUMDR) }, { BRDATA (HKDS, hkds, DEV_RDX, 16, HK_NUMDR) },
{ BRDATA (HKER, hker, HK_RDX, 16, HK_NUMDR) }, { BRDATA (HKER, hker, DEV_RDX, 16, HK_NUMDR) },
{ BRDATA (HKDB, hkdb, HK_RDX, 16, 3) }, { BRDATA (HKDB, hkdb, DEV_RDX, 16, 3) },
{ GRDATA (HKDC, hkdc, HK_RDX, 16, 0) }, { GRDATA (HKDC, hkdc, DEV_RDX, 16, 0) },
{ GRDATA (HKOF, hkof, HK_RDX, 8, 0) }, { GRDATA (HKOF, hkof, DEV_RDX, 8, 0) },
{ GRDATA (HKMR, hkmr, HK_RDX, 16, 0) }, { GRDATA (HKMR, hkmr, DEV_RDX, 16, 0) },
{ GRDATA (HKMR2, hkmr2, HK_RDX, 16, 0), REG_RO }, { GRDATA (HKMR2, hkmr2, DEV_RDX, 16, 0), REG_RO },
{ GRDATA (HKMR3, hkmr3, HK_RDX, 16, 0), REG_RO }, { GRDATA (HKMR3, hkmr3, DEV_RDX, 16, 0), REG_RO },
{ GRDATA (HKSPR, hkspr, HK_RDX, 16, 0) }, { GRDATA (HKSPR, hkspr, DEV_RDX, 16, 0) },
{ FLDATA (INT, IREQ (HK), INT_V_HK) }, { FLDATA (INT, IREQ (HK), INT_V_HK) },
{ FLDATA (ERR, hkcs1, CSR_V_ERR) }, { FLDATA (ERR, hkcs1, CSR_V_ERR) },
{ FLDATA (DONE, hkcs1, CSR_V_DONE) }, { FLDATA (DONE, hkcs1, CSR_V_DONE) },
{ FLDATA (IE, hkcs1, CSR_V_IE) }, { FLDATA (IE, hkcs1, CSR_V_IE) },
{ DRDATA (STIME, hk_swait, 24), REG_NZ + PV_LEFT }, { DRDATA (STIME, hk_swait, 24), REG_NZ + PV_LEFT },
{ DRDATA (RTIME, hk_rwait, 24), REG_NZ + PV_LEFT }, { DRDATA (RTIME, hk_rwait, 24), REG_NZ + PV_LEFT },
{ URDATA (FNC, hk_unit[0].FNC, HK_RDX, 5, 0, { URDATA (FNC, hk_unit[0].FNC, DEV_RDX, 5, 0,
HK_NUMDR, REG_HRO) }, HK_NUMDR, REG_HRO) },
{ URDATA (CYL, hk_unit[0].CYL, HK_RDX, 10, 0, { URDATA (CYL, hk_unit[0].CYL, DEV_RDX, 10, 0,
HK_NUMDR, REG_HRO) }, HK_NUMDR, REG_HRO) },
{ BRDATA (OFFSET, hk_off, HK_RDX, 16, HK_NUMDR), REG_HRO }, { BRDATA (OFFSET, hk_off, DEV_RDX, 16, HK_NUMDR), REG_HRO },
{ BRDATA (CYLDIF, hk_dif, HK_RDX, 16, HK_NUMDR), REG_HRO }, { BRDATA (CYLDIF, hk_dif, DEV_RDX, 16, HK_NUMDR), REG_HRO },
{ URDATA (CAPAC, hk_unit[0].capac, 10, T_ADDR_W, 0, { URDATA (CAPAC, hk_unit[0].capac, 10, T_ADDR_W, 0,
HK_NUMDR, PV_LEFT | REG_HRO) }, HK_NUMDR, PV_LEFT | REG_HRO) },
{ FLDATA (STOP_IOE, hk_stopioe, 0) }, { FLDATA (STOP_IOE, hk_stopioe, 0) },
{ GRDATA (DEVADDR, hk_dib.ba, HK_RDX, 32, 0), REG_HRO }, { GRDATA (DEVADDR, hk_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, hk_dib.vec, HK_RDX, 16, 0), REG_HRO }, { GRDATA (DEVVEC, hk_dib.vec, DEV_RDX, 16, 0), REG_HRO },
{ NULL } }; { NULL } };
MTAB hk_mod[] = { MTAB hk_mod[] = {
@ -438,7 +445,7 @@ MTAB hk_mod[] = {
DEVICE hk_dev = { DEVICE hk_dev = {
"HK", hk_unit, hk_reg, hk_mod, "HK", hk_unit, hk_reg, hk_mod,
HK_NUMDR, HK_RDX, 24, 1, HK_RDX, HK_WID, HK_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16,
NULL, NULL, &hk_reset, NULL, NULL, &hk_reset,
&hk_boot, &hk_attach, &hk_detach, &hk_boot, &hk_attach, &hk_detach,
&hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG }; &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG };
@ -472,7 +479,7 @@ case 003: /* HKDA */
*data = hkda = hkda & ~DA_MBZ; *data = hkda = hkda & ~DA_MBZ;
break; break;
case 004: /* HKCS2 */ case 004: /* HKCS2 */
*data = hkcs2 = (hkcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR; *data = hkcs2 = (hkcs2 & ~CS2_MBZ) | CS2_IR;
break; break;
case 005: /* HKDS */ case 005: /* HKDS */
*data = hkds[drv]; *data = hkds[drv];
@ -532,7 +539,7 @@ switch (j) { /* decode PA<4:1> */
case 000: /* HKCS1 */ case 000: /* HKCS1 */
if (data & CS1_CCLR) { /* controller reset? */ if (data & CS1_CCLR) { /* controller reset? */
hkcs1 = CS1_DONE; /* CS1 = done */ hkcs1 = CS1_DONE; /* CS1 = done */
hkcs2 = CS2_IR | CS2_OR; /* CS2 = ready */ hkcs2 = CS2_IR; /* CS2 = ready */
hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */ hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */
hkda = hkdc = 0; hkda = hkdc = 0;
hkba = hkwc = 0; hkba = hkwc = 0;
@ -564,7 +571,7 @@ case 003: /* HKDA */
break; break;
case 004: /* HKCS2 */ case 004: /* HKCS2 */
if (data & CS2_CLR) hk_reset (&hk_dev); /* init? */ if (data & CS2_CLR) hk_reset (&hk_dev); /* init? */
else hkcs2 = (hkcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; else hkcs2 = (hkcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR;
drv = GET_UNIT (hkcs2); drv = GET_UNIT (hkcs2);
break; break;
case 007: /* HKAS */ case 007: /* HKAS */
@ -780,12 +787,12 @@ case FNC_READ: /* read */
err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);
if (uptr->FNC == FNC_WRITE) { /* write? */ if (uptr->FNC == FNC_WRITE) { /* write? */
if (hkcs2 & CS2_UAI) { /* no addr inc? */ if (hkcs2 & CS2_UAI) { /* no addr inc? */
if (t = Map_ReadW (ba, 2, &comp, MAP)) { /* get 1st wd */ if (t = Map_ReadW (ba, 2, &comp)) { /* get 1st wd */
wc = 0; /* NXM, no xfr */ wc = 0; /* NXM, no xfr */
hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */ hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */
for (i = 0; i < wc; i++) hkxb[i] = comp; } for (i = 0; i < wc; i++) hkxb[i] = comp; }
else { /* normal */ else { /* normal */
if (t = Map_ReadW (ba, wc << 1, hkxb, MAP)) { /* get buf */ if (t = Map_ReadW (ba, wc << 1, hkxb)) { /* get buf */
wc = wc - (t >> 1); /* NXM, adj wc */ wc = wc - (t >> 1); /* NXM, adj wc */
hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */ hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */
ba = ba + (wc << 1); } /* adv ba */ ba = ba + (wc << 1); } /* adv ba */
@ -800,11 +807,11 @@ case FNC_READ: /* read */
err = ferror (uptr->fileref); err = ferror (uptr->fileref);
for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */ for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */
if (hkcs2 & CS2_UAI) { /* no addr inc? */ if (hkcs2 & CS2_UAI) { /* no addr inc? */
if (t = Map_WriteW (ba, 2, &hkxb[wc - 1], MAP)) { if (t = Map_WriteW (ba, 2, &hkxb[wc - 1])) {
wc = 0; /* NXM, no xfr */ wc = 0; /* NXM, no xfr */
hkcs2 = hkcs2 | CS2_NEM; } } /* set nxm err */ hkcs2 = hkcs2 | CS2_NEM; } } /* set nxm err */
else { /* normal */ else { /* normal */
if (t = Map_WriteW (ba, wc << 1, hkxb, MAP)) { /* put buf */ if (t = Map_WriteW (ba, wc << 1, hkxb)) { /* put buf */
wc = wc - (t >> 1); /* NXM, adj wc */ wc = wc - (t >> 1); /* NXM, adj wc */
hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */ hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */
ba = ba + (wc << 1); } /* adv ba */ ba = ba + (wc << 1); } /* adv ba */
@ -815,7 +822,7 @@ case FNC_READ: /* read */
for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */ for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */
awc = wc; awc = wc;
for (wc = 0; wc < awc; wc++) { /* loop thru buf */ for (wc = 0; wc < awc; wc++) { /* loop thru buf */
if (Map_ReadW (ba, 2, &comp, MAP)) { /* read word */ if (Map_ReadW (ba, 2, &comp)) { /* read word */
hkcs2 = hkcs2 | CS2_NEM; /* set error */ hkcs2 = hkcs2 | CS2_NEM; /* set error */
break; } break; }
if (comp != hkxb[wc]) { /* compare wd */ if (comp != hkxb[wc]) { /* compare wd */
@ -999,7 +1006,7 @@ int32 i;
UNIT *uptr; UNIT *uptr;
hkcs1 = CS1_DONE; /* set done */ hkcs1 = CS1_DONE; /* set done */
hkcs2 = CS2_IR | CS2_OR; /* clear state */ hkcs2 = CS2_IR; /* clear state */
hkmr = hkmr2 = hkmr3 = 0; hkmr = hkmr2 = hkmr3 = 0;
hkda = hkdc = 0; hkda = hkdc = 0;
hkba = hkwc = 0; hkba = hkwc = 0;
@ -1014,7 +1021,7 @@ for (i = 0; i < HK_NUMDR; i++) { /* stop operations */
hk_dif[i] = 0; hk_dif[i] = 0;
hk_off[i] = 0; hk_off[i] = 0;
hker[i] = 0; } /* clear errors */ hker[i] = 0; } /* clear errors */
if (hkxb == NULL) hkxb = calloc (HK_MAXFR, sizeof (unsigned int16)); if (hkxb == NULL) hkxb = calloc (HK_MAXFR, sizeof (uint16));
if (hkxb == NULL) return SCPE_MEM; if (hkxb == NULL) return SCPE_MEM;
return SCPE_OK; return SCPE_OK;
} }
@ -1082,6 +1089,8 @@ t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD);
} }
#if defined (VM_PDP11)
/* Device bootstrap - does not clear CSR when done */ /* Device bootstrap - does not clear CSR when done */
#define BOOT_START 02000 /* start */ #define BOOT_START 02000 /* start */
@ -1134,3 +1143,12 @@ M[BOOT_CSR >> 1] = hk_dib.ba & DMASK;
saved_PC = BOOT_ENTRY; saved_PC = BOOT_ENTRY;
return SCPE_OK; return SCPE_OK;
} }
#else
t_stat hk_boot (int32 unitno, DEVICE *dptr)
{
return SCPE_NOFNC;
}
#endif

View file

@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
30-Sep-04 RMS Revised Unibus interface
28-May-04 RMS Revised I/O dispatching (from John Dundas) 28-May-04 RMS Revised I/O dispatching (from John Dundas)
25-Jan-04 RMS Removed local debug logging support 25-Jan-04 RMS Removed local debug logging support
21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls
@ -43,18 +44,20 @@
extern uint16 *M; extern uint16 *M;
extern int32 int_req[IPL_HLVL]; extern int32 int_req[IPL_HLVL];
extern int32 ub_map[UBM_LNT_LW]; extern int32 ub_map[UBM_LNT_LW];
extern int32 cpu_bme, cpu_18b, cpu_ubm; extern int32 cpu_opt, cpu_bme;
extern int32 trap_req, ipl; extern int32 trap_req, ipl;
extern int32 cpu_log; extern int32 cpu_log;
extern int32 autcon_enb; extern int32 autcon_enb;
extern int32 uba_last;
extern FILE *sim_log; extern FILE *sim_log;
extern DEVICE *sim_devices[], cpu_dev; extern DEVICE *sim_devices[], cpu_dev;
extern UNIT cpu_unit; extern UNIT cpu_unit;
int32 calc_ints (int32 nipl, int32 trq); int32 calc_ints (int32 nipl, int32 trq);
extern DIB cpu0_dib, cpu1_dib, cpu2_dib; extern t_stat cpu_build_dib (void);
extern DIB cpu3_dib, cpu4_dib, ubm_dib; extern void init_mbus_tab (void);
extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp);
/* I/O data structures */ /* I/O data structures */
@ -66,14 +69,6 @@ int32 int_vec[IPL_HLVL][32]; /* int req to vector */
int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */ int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */
static DIB *std_dib[] = { /* standard DIBs */
&cpu0_dib,
&cpu1_dib,
&cpu2_dib,
&cpu3_dib,
&cpu4_dib,
NULL };
static const int32 pirq_bit[7] = { static const int32 pirq_bit[7] = {
INT_V_PIR1, INT_V_PIR2, INT_V_PIR3, INT_V_PIR4, INT_V_PIR1, INT_V_PIR2, INT_V_PIR3, INT_V_PIR4,
INT_V_PIR5, INT_V_PIR6, INT_V_PIR7 }; INT_V_PIR5, INT_V_PIR6, INT_V_PIR7 };
@ -152,52 +147,48 @@ return 0;
even = low 16b, bit <0> clear even = low 16b, bit <0> clear
odd = high 6b odd = high 6b
The Unibus map is stored as an array of longwords The Unibus map is stored as an array of longwords.
These routines are only reachable if a Unibus map is configured.
*/ */
t_stat ubm_rd (int32 *data, int32 addr, int32 access) t_stat ubm_rd (int32 *data, int32 addr, int32 access)
{ {
if (cpu_ubm) { int32 pg = (addr >> 2) & UBM_M_PN;
int32 pg = (addr >> 2) & UBM_M_PN;
*data = (addr & 2)? ((ub_map[pg] >> 16) & 077): *data = (addr & 2)? ((ub_map[pg] >> 16) & 077):
(ub_map[pg] & 0177776); (ub_map[pg] & 0177776);
return SCPE_OK; } return SCPE_OK;
return SCPE_NXM;
} }
t_stat ubm_wr (int32 data, int32 addr, int32 access) t_stat ubm_wr (int32 data, int32 addr, int32 access)
{ {
if (cpu_ubm) { int32 sc, pg = (addr >> 2) & UBM_M_PN;
int32 sc, pg = (addr >> 2) & UBM_M_PN; if (access == WRITEB) {
if (access == WRITEB) { sc = (addr & 3) << 3;
sc = (addr & 3) << 3; ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) |
ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) | ((data & 0377) << sc); }
((data & 0377) << sc); } else { sc = (addr & 2) << 3;
else { ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) |
sc = (addr & 2) << 3; ((data & 0177777) << sc); }
ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) | ub_map[pg] = ub_map[pg] & 017777776;
((data & 0177777) << sc); } return SCPE_OK;
ub_map[pg] = ub_map[pg] & 017777776;
return SCPE_OK; }
return SCPE_NXM;
} }
/* Mapped memory access routines for DMA devices */ /* Mapped memory access routines for DMA devices */
#define BUSMASK(m) ((cpu_18b || (cpu_ubm && (m)))? UNIMASK: PAMASK) #define BUSMASK ((UNIBUS)? UNIMASK: PAMASK)
/* Map I/O address to memory address */ /* Map I/O address to memory address - caller checks cpu_bme */
t_bool Map_Addr (uint32 ba, uint32 *ma) uint32 Map_Addr (uint32 ba)
{ {
if (cpu_bme) { /* bus map on? */ int32 pg = UBM_GETPN (ba); /* map entry */
int32 pg = UBM_GETPN (ba); /* map entry */ int32 off = UBM_GETOFF (ba); /* offset */
int32 off = UBM_GETOFF (ba); /* offset */
if (pg != UBM_M_PN) /* last page? */ if (pg != UBM_M_PN) /* last page? */
*ma = (ub_map[pg] + off) & PAMASK; /* no, use map */ uba_last = (ub_map[pg] + off) & PAMASK; /* no, use map */
else *ma = (IOPAGEBASE + off) & PAMASK; } /* yes, use fixed */ else uba_last = (IOPAGEBASE + off) & PAMASK; /* yes, use fixed */
else *ma = ba; /* else physical */ return uba_last;
return TRUE;
} }
/* I/O buffer routines, aligned access /* I/O buffer routines, aligned access
@ -206,96 +197,108 @@ return TRUE;
Map_ReadW - fetch word buffer from memory Map_ReadW - fetch word buffer from memory
Map_WriteB - store byte buffer into memory Map_WriteB - store byte buffer into memory
Map_WriteW - store word buffer into memory Map_WriteW - store word buffer into memory
These routines are used only for Unibus and Qbus devices.
Massbus devices have their own IO routines. As a result,
the historic 'map' parameter is no longer needed.
- In a U18 configuration, the map is always disabled.
Device addresses are trimmed to 18b.
- In a U22 configuration, the map is always configured
(although it may be disabled). Device addresses are
trimmed to 18b.
- In a Qbus configuration, the map is always disabled.
Device addresses are trimmed to 22b.
*/ */
int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf, t_bool map) int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
ba = ba & BUSMASK (map); /* trim address */ ba = ba & BUSMASK; /* trim address */
lim = ba + bc; lim = ba + bc;
if (map && cpu_bme) { /* map req & on? */ if (cpu_bme) { /* map enabled? */
for ( ; ba < lim; ba++) { /* by bytes */ for ( ; ba < lim; ba++) { /* by bytes */
Map_Addr (ba, &ma); /* map addr */ ma = Map_Addr (ba); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
if (ma & 1) *buf++ = (M[ma >> 1] >> 8) & 0377; /* get byte */ if (ma & 1) *buf++ = (M[ma >> 1] >> 8) & 0377; /* get byte */
else *buf++ = M[ma >> 1] & 0377; } else *buf++ = M[ma >> 1] & 0377; }
return 0; } return 0; }
else { /* physical */ else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */ else return bc; /* no, err */
for ( ; ba < alim; ba++) { /* by bytes */ for ( ; ba < alim; ba++) { /* by bytes */
if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */ if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */
else *buf++ = M[ba >> 1] & 0377; } else *buf++ = M[ba >> 1] & 0377; }
return (lim - alim); } return (lim - alim); }
} }
int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf, t_bool map) int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
ba = (ba & BUSMASK (map)) & ~01; /* trim, align addr */ ba = (ba & BUSMASK) & ~01; /* trim, align addr */
lim = ba + (bc & ~01); lim = ba + (bc & ~01);
if (map && cpu_bme) { /* map req & on? */ if (cpu_bme) { /* map enabled? */
for (; ba < lim; ba = ba + 2) { /* by words */ for (; ba < lim; ba = ba + 2) { /* by words */
Map_Addr (ba, &ma); /* map addr */ ma = Map_Addr (ba); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
*buf++ = M[ma >> 1]; } *buf++ = M[ma >> 1]; }
return 0; } return 0; }
else { /* physical */ else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */ else return bc; /* no, err */
for ( ; ba < alim; ba = ba + 2) { /* by words */ for ( ; ba < alim; ba = ba + 2) { /* by words */
*buf++ = M[ba >> 1]; } *buf++ = M[ba >> 1]; }
return (lim - alim); } return (lim - alim); }
} }
int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf, t_bool map) int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
ba = ba & BUSMASK (map); /* trim address */ ba = ba & BUSMASK; /* trim address */
lim = ba + bc; lim = ba + bc;
if (map && cpu_bme) { /* map req & on? */ if (cpu_bme) { /* map enabled? */
for ( ; ba < lim; ba++) { /* by bytes */ for ( ; ba < lim; ba++) { /* by bytes */
Map_Addr (ba, &ma); /* map addr */ ma = Map_Addr (ba); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
if (ma & 1) M[ma >> 1] = (M[ma >> 1] & 0377) | if (ma & 1) M[ma >> 1] = (M[ma >> 1] & 0377) |
((uint16) *buf++ << 8); ((uint16) *buf++ << 8);
else M[ma >> 1] = (M[ma >> 1] & ~0377) | *buf++; } else M[ma >> 1] = (M[ma >> 1] & ~0377) | *buf++; }
return 0; } return 0; }
else { /* physical */ else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */ else return bc; /* no, err */
for ( ; ba < alim; ba++) { /* by bytes */ for ( ; ba < alim; ba++) { /* by bytes */
if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) | if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) |
((uint16) *buf++ << 8); ((uint16) *buf++ << 8);
else M[ba >> 1] = (M[ba >> 1] & ~0377) | *buf++; } else M[ba >> 1] = (M[ba >> 1] & ~0377) | *buf++; }
return (lim - alim); } return (lim - alim); }
} }
int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf, t_bool map) int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf)
{ {
uint32 alim, lim, ma; uint32 alim, lim, ma;
ba = (ba & BUSMASK (map)) & ~01; /* trim, align addr */ ba = (ba & BUSMASK) & ~01; /* trim, align addr */
lim = ba + (bc & ~01); lim = ba + (bc & ~01);
if (map && cpu_bme) { /* map req & on? */ if (cpu_bme) { /* map enabled? */
for (; ba < lim; ba = ba + 2) { /* by words */ for (; ba < lim; ba = ba + 2) { /* by words */
Map_Addr (ba, &ma); /* map addr */ ma = Map_Addr (ba); /* map addr */
if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */
M[ma >> 1] = *buf++; } /* store word */ M[ma >> 1] = *buf++; } /* store word */
return 0; } return 0; }
else { /* physical */ else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else return bc; /* no, err */ else return bc; /* no, err */
for ( ; ba < alim; ba = ba + 2) { /* by words */ for ( ; ba < alim; ba = ba + 2) { /* by words */
M[ba >> 1] = *buf++; } M[ba >> 1] = *buf++; }
return (lim - alim); } return (lim - alim); }
} }
/* Enable/disable autoconfiguration */ /* Enable/disable autoconfiguration */
@ -311,8 +314,7 @@ return auto_config (0, 0);
t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc) t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc)
{ {
fprintf (st, "autoconfiguration "); fprintf (st, "autoconfiguration %s", (autcon_enb? "on": "off"));
fprintf (st, autcon_enb? "enabled": "disabled");
return SCPE_OK; return SCPE_OK;
} }
@ -421,36 +423,26 @@ else { fprintf (st, "vector=%o", vec);
return SCPE_OK; return SCPE_OK;
} }
/* Build dispatch tables */ /* Init Unibus tables */
t_stat build_dsp_tab (DEVICE *dptr, DIB *dibp) void init_ubus_tab (void)
{ {
uint32 i, idx; int32 i, j;
if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */ for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */
for (i = 0; i < dibp->lnt; i = i + 2) { /* create entries */ for (j = 0; j < 32; j++) {
idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */ int_vec[i][j] = 0;
if ((iodispR[idx] && dibp->rd && /* conflict? */ int_ack[i][j] = NULL; } }
(iodispR[idx] != dibp->rd)) || for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */
(iodispW[idx] && dibp->wr && iodispR[i] = NULL;
(iodispW[idx] != dibp->wr))) { iodispW[i] = NULL;
printf ("Device %s address conflict at %08o\n", iodibp[i] = NULL; }
sim_dname (dptr), dibp->ba); return;
if (sim_log) fprintf (sim_log,
"Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
return SCPE_STOP;
}
if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */
if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */
iodibp[idx] = dibp; /* remember DIB */
}
return SCPE_OK;
} }
/* Build interrupt tables */ /* Build Unibus tables */
t_stat build_int_vec (DEVICE *dptr, DIB *dibp) t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp)
{ {
int32 i, idx, vec, ilvl, ibit; int32 i, idx, vec, ilvl, ibit;
@ -475,45 +467,53 @@ for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */
if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i]; if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i];
else if (vec) int_vec[ilvl][ibit] = vec; else if (vec) int_vec[ilvl][ibit] = vec;
} }
for (i = 0; i < (int32) dibp->lnt; i = i + 2) { /* create entries */
idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */
if ((iodispR[idx] && dibp->rd && /* conflict? */
(iodispR[idx] != dibp->rd)) ||
(iodispW[idx] && dibp->wr &&
(iodispW[idx] != dibp->wr))) {
printf ("Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
if (sim_log) fprintf (sim_log,
"Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
return SCPE_STOP;
}
if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */
if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */
iodibp[idx] = dibp; /* remember DIB */
}
return SCPE_OK; return SCPE_OK;
} }
/* Build tables from device list */ /* Build tables from device list */
t_stat build_dib_tab (int32 ubm) t_stat build_dib_tab (void)
{ {
int32 i, j; int32 i;
DEVICE *dptr; DEVICE *dptr;
DIB *dibp; DIB *dibp;
t_stat r; t_stat r;
for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */ init_ubus_tab (); /* init Unibus tables */
for (j = 0; j < 32; j++) { init_mbus_tab (); /* init Massbus tables */
int_vec[i][j] = 0;
int_ack[i][j] = NULL; } }
for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */
iodispR[i] = NULL;
iodispW[i] = NULL;
iodibp[i] = NULL; }
for (i = 0; i < 7; i++) /* seed PIRQ intr */ for (i = 0; i < 7; i++) /* seed PIRQ intr */
int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ; int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ;
if (r = cpu_build_dib ()) return r; /* build CPU entries */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */ dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
if (r = build_int_vec (dptr, dibp)) /* add to intr tab */ if (dptr->flags & DEV_MBUS) { /* Massbus? */
return r; if (r = build_mbus_tab (dptr, dibp)) /* add to Mbus tab */
if (r = build_dsp_tab (dptr, dibp)) /* add to dispatch tab */ return r;
return r; }
else { /* no, Unibus */
if (r = build_ubus_tab (dptr, dibp)) /* add to Unibus tab */
return r;
}
} /* end if enabled */ } /* end if enabled */
} /* end for */ } /* end for */
for (i = 0; std_dib[i] != NULL; i++) { /* loop thru std */
if (r = build_dsp_tab (&cpu_dev, std_dib[i])) /* add to dispatch tab */
return r;
}
if (ubm) { /* Unibus map? */
if (r = build_dsp_tab (&cpu_dev, &ubm_dib)) /* add to dispatch tab */
return r;
}
return SCPE_OK; return SCPE_OK;
} }
@ -525,7 +525,7 @@ uint32 i, j;
DEVICE *dptr; DEVICE *dptr;
DIB *dibp; DIB *dibp;
if (build_dib_tab (cpu_ubm)) return SCPE_OK; /* build IO page */ if (build_dib_tab ()) return SCPE_OK; /* build IO page */
for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */
if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */
dibp = iodibp[i]; /* DIB for block */ dibp = iodibp[i]; /* DIB for block */

View file

@ -41,13 +41,9 @@
#elif defined (VM_VAX) /* VAX version */ #elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h" #include "vax_defs.h"
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
#else /* PDP-11 version */ #else /* PDP-11 version */
#include "pdp11_defs.h" #include "pdp11_defs.h"
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
#endif #endif
#define LPTCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* implemented */ #define LPTCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* implemented */

779
PDP11/pdp11_rh.c Normal file
View file

@ -0,0 +1,779 @@
/* pdp11_rh.c: PDP-11 Massbus adapter simulator
Copyright (c) 2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rha, rhb RH11/RH70 Massbus adapter
WARNING: The interupt logic of the RH11/RH70 is unusual and must be
simulated with great precision. The RH11 has an internal interrupt
request flop, CSTB INTR, which is controlled as follows:
- Writing IE and DONE simultaneously sets CSTB INTR
- Controller clear, INIT, and interrupt acknowledge clear CSTB INTR
(and also clear IE)
- A transition of DONE from 0 to 1 sets CSTB INTR from IE
The output of CSTB INTR is OR'd with the AND of RPCS1<SC,DONE,IE> to
create the interrupt request signal. Thus,
- The DONE interrupt is edge sensitive, but the SC interrupt is
level sensitive.
- The DONE interrupt, once set, is not disabled if IE is cleared,
but the SC interrupt is.
*/
#if defined (VM_PDP10) /* PDP10 version */
#error "PDP-10 uses pdp10_rp.c and pdp10_tu.c!"
#elif defined (VM_VAX) /* VAX version */
#error "VAX uses vax780_mba.c!"
#else /* PDP-11 version */
#include "pdp11_defs.h"
#endif
/* CS1 - base + 000 - control/status 1 */
#define CS1_OF 0
#define CS1_GO CSR_GO /* go */
#define CS1_V_FNC 1 /* function pos */
#define CS1_M_FNC 037 /* function mask */
#define CS1_FNC (CS1_M_FNC << CS1_V_FNC)
#define FNC_XFER 024 /* >=? data xfr */
#define CS1_IE CSR_IE /* int enable */
#define CS1_DONE CSR_DONE /* ready */
#define CS1_V_UAE 8 /* Unibus addr ext */
#define CS1_M_UAE 03
#define CS1_UAE (CS1_M_UAE << CS1_V_UAE)
#define CS1_DVA 0004000 /* drive avail NI */
#define CS1_MCPE 0020000 /* Mbus par err NI */
#define CS1_TRE 0040000 /* transfer err */
#define CS1_SC 0100000 /* special cond */
#define CS1_MBZ 0012000
#define CS1_DRV (CS1_FNC | CS1_GO)
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
/* WC - base + 002 - word count */
#define WC_OF 1
/* BA - base + 004 - base address */
#define BA_OF 2
#define BA_MBZ 0000001 /* must be zero */
/* CS2 - base + 010 - control/status 2 */
#define CS2_OF 3
#define CS2_V_UNIT 0 /* unit pos */
#define CS2_M_UNIT 07 /* unit mask */
#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT)
#define CS2_UAI 0000010 /* addr inhibit */
#define CS2_PAT 0000020 /* parity test NI */
#define CS2_CLR 0000040 /* controller clear */
#define CS2_IR 0000100 /* input ready */
#define CS2_OR 0000200 /* output ready */
#define CS2_MDPE 0000400 /* Mbus par err NI */
#define CS2_MXF 0001000 /* missed xfer NI */
#define CS2_PGE 0002000 /* program err */
#define CS2_NEM 0004000 /* nx mem err */
#define CS2_NED 0010000 /* nx drive err */
#define CS2_PE 0020000 /* parity err NI */
#define CS2_WCE 0040000 /* write check err */
#define CS2_DLT 0100000 /* data late NI */
#define CS2_MBZ (CS2_CLR)
#define CS2_RW (CS2_UNIT | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE)
#define CS2_ERR (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \
CS2_NED | CS2_PE | CS2_WCE | CS2_DLT )
#define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT)
/* DB - base + 022 - data buffer */
#define DB_OF 4
/* BAE - base + 050/34 - bus address extension */
#define BAE_OF 5
#define AE_M_MAE 0 /* addr ext pos */
#define AE_V_MAE 077 /* addr ext mask */
#define AE_MBZ 0177700
/* CS3 - base + 052/36 - control/status 3 */
#define CS3_OF 6
#define CS3_APE 0100000 /* addr perr - NI */
#define CS3_DPO 0040000 /* data perr odd - NI */
#define CS3_DPE 0020000 /* data perr even - NI */
#define CS3_WCO 0010000 /* wchk err odd */
#define CS3_WCE 0004000 /* wchk err even */
#define CS3_DBL 0002000 /* dbl word xfer - NI */
#define CS3_IPCK 0000017 /* wrong par - NI */
#define CS3_ERR (CS3_APE|CS3_DPO|CS3_DPE|CS3_WCO|CS3_WCE)
#define CS3_MBZ 0001660
#define CS3_RW (CS1_IE | CS3_IPCK)
#define MBA_OFSMASK 077 /* max 32 reg */
#define INT 0000 /* int reg flag */
#define EXT 0100 /* ext reg flag */
/* Declarations */
#define RH11 (cpu_opt & OPT_RH11)
struct mbctx {
uint32 cs1; /* ctrl/status 1 */
uint32 wc; /* word count */
uint32 ba; /* bus addr */
uint32 cs2; /* ctrl/status 2 */
uint32 db; /* data buffer */
uint32 bae; /* addr ext */
uint32 cs3; /* ctrl/status 3 */
uint32 iff; /* int flip flop */
};
typedef struct mbctx MBACTX;
MBACTX massbus[MBA_NUM];
extern int32 cpu_opt, cpu_bme;
extern uint16 *M;
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
extern UNIT cpu_unit;
extern FILE *sim_deb;
extern FILE *sim_log;
extern int32 sim_switches;
t_stat mba_reset (DEVICE *dptr);
t_stat mba_rd (int32 *val, int32 pa, int32 access);
t_stat mba_wr (int32 val, int32 pa, int32 access);
t_stat mba_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat mba_show_type (FILE *st, UNIT *uptr, int32 val, void *desc);
int32 mba0_inta (void);
int32 mba1_inta (void);
void mba_set_int (uint32 mb);
void mba_clr_int (uint32 mb);
void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb);
void mba_set_cs2 (uint32 flg, uint32 mb);
uint32 mba_map_pa (int32 pa, int32 *ofs);
DEVICE mba0_dev, mba1_dev;
extern uint32 Map_Addr (uint32 ba);
/* Maps */
static MBACTX *ctxmap[MBA_NUM] = { &massbus[0], &massbus[1] };
static DEVICE *devmap[MBA_NUM] = { &mba0_dev, &mba1_dev };
/* Massbus register dispatches */
static t_stat (*mbregR[MBA_NUM])(int32 *dat, int32 ad, int32 md);
static t_stat (*mbregW[MBA_NUM])(int32 dat, int32 ad, int32 md);
static int32 (*mbabort[MBA_NUM])(void);
/* Unibus to register offset map */
static int32 mba_mapofs[(MBA_OFSMASK + 1) >> 1] =
{ INT|0, INT|1, INT|2, EXT|5, INT|3, EXT|1, EXT|2, EXT|4,
EXT|7, INT|4, EXT|3, EXT|6, EXT|8, EXT|9, EXT|10, EXT|11,
EXT|12, EXT|13, EXT|14, EXT|15, EXT|16, EXT|17, EXT|18, EXT|19,
EXT|20, EXT|21, EXT|22, EXT|23, EXT|24, EXT|25, EXT|26, EXT|27 };
/* Massbus adapter data structures
mbax_dev RHx device descriptor
mbax_unit RHx units
mbax_reg RHx register list
*/
DIB mba0_dib = { IOBA_RP, IOLN_RP, &mba_rd, &mba_wr,
1, IVCL (RP), VEC_RP, { &mba0_inta } };
UNIT mba0_unit = { UDATA (NULL, 0, 0) };
REG mba0_reg[] = {
{ ORDATA (CS1, massbus[0].cs1, 16) },
{ ORDATA (WC, massbus[0].wc, 16) },
{ ORDATA (BA, massbus[0].ba, 16) },
{ ORDATA (CS2, massbus[0].cs2, 16) },
{ ORDATA (DB, massbus[0].db, 16) },
{ ORDATA (BAE, massbus[0].bae, 6) },
{ ORDATA (CS3, massbus[0].cs3, 16) },
{ FLDATA (IFF, massbus[0].iff, 0) },
{ FLDATA (INT, IREQ (RP), INT_V_RP) },
{ FLDATA (SC, massbus[0].cs1, CSR_V_ERR) },
{ FLDATA (DONE, massbus[0].cs1, CSR_V_DONE) },
{ FLDATA (IE, massbus[0].cs1, CSR_V_IE) },
{ ORDATA (DEVADDR, mba0_dib.ba, 32), REG_HRO },
{ ORDATA (DEVVEC, mba0_dib.vec, 16), REG_HRO },
{ NULL } };
MTAB mba0_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0100, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ 0 } };
DEVICE mba0_dev = {
"RHA", &mba0_unit, mba0_reg, mba0_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &mba_reset,
NULL, NULL, NULL,
&mba0_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS };
DIB mba1_dib = { IOBA_TU, IOLN_TU, &mba_rd, &mba_wr,
1, IVCL (TU), VEC_TU, { &mba1_inta } };
UNIT mba1_unit = { UDATA (NULL, 0, 0) };
REG mba1_reg[] = {
{ ORDATA (CS1, massbus[1].cs1, 16) },
{ ORDATA (WC, massbus[1].wc, 16) },
{ ORDATA (BA, massbus[1].ba, 16) },
{ ORDATA (CS2, massbus[1].cs2, 16) },
{ ORDATA (DB, massbus[1].db, 16) },
{ ORDATA (BAE, massbus[1].bae, 6) },
{ ORDATA (CS3, massbus[1].cs3, 16) },
{ FLDATA (IFF, massbus[1].iff, 0) },
{ FLDATA (INT, IREQ (TU), INT_V_TU) },
{ FLDATA (SC, massbus[1].cs1, CSR_V_ERR) },
{ FLDATA (DONE, massbus[1].cs1, CSR_V_DONE) },
{ FLDATA (IE, massbus[1].cs1, CSR_V_IE) },
{ ORDATA (DEVADDR, mba1_dib.ba, 32), REG_HRO },
{ ORDATA (DEVVEC, mba1_dib.vec, 16), REG_HRO },
{ NULL } };
MTAB mba1_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ 0 } };
DEVICE mba1_dev = {
"RHB", &mba1_unit, mba1_reg, mba1_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &mba_reset,
NULL, NULL, NULL,
&mba1_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS };
/* Read Massbus adapter register */
t_stat mba_rd (int32 *val, int32 pa, int32 mode)
{
int32 ofs, dat, mb, drv;
t_stat r;
MBACTX *mbp;
mb = mba_map_pa (pa, &ofs); /* get mb number */
if ((mb < 0) || (ofs < 0)) return SCPE_NXM; /* valid? */
mbp = ctxmap[mb]; /* get context */
drv = GET_UNIT (mbp->cs2); /* get drive */
mba_upd_cs1 (0, 0, mb); /* update CS1 */
if (ofs & EXT) { /* external? */
if (!mbregR[mb]) return SCPE_NXM; /* device there? */
r = mbregR[mb] (val, ofs & ~EXT, drv); /* call device */
if (r == MBE_NXD) mba_set_cs2 (CS2_NED, mb); /* nx drive? */
else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
return SCPE_OK;
}
switch (ofs) { /* case on reg */
case CS1_OF: /* CS1 */
if (!mbregR[mb]) return SCPE_NXM; /* nx device? */
r = mbregR[mb] (&dat, ofs, drv); /* get dev cs1 */
if (r == MBE_NXD) mba_set_cs2 (CS2_NED, mb); /* nx drive? */
*val = mbp->cs1 | dat;
break;
case WC_OF: /* WC */
*val = mbp->wc;
break;
case BA_OF: /* BA */
*val = mbp->ba & ~BA_MBZ;
break;
case CS2_OF: /* CS2 */
*val = mbp->cs2 = (mbp->cs2 & ~CS2_MBZ) | CS2_IR | CS2_OR;
break;
case DB_OF: /* DB */
*val = mbp->db;
break;
case BAE_OF: /* BAE */
*val = mbp->bae = mbp->bae & ~AE_MBZ;
break;
case CS3_OF: /* CS3 */
*val = mbp->cs3 = (mbp->cs3 & ~(CS1_IE | CS3_MBZ)) | (mbp->cs1 & CS1_IE);
break;
default: /* huh? */
return SCPE_NXM;
}
return SCPE_OK;
}
t_stat mba_wr (int32 val, int32 pa, int32 access)
{
int32 ofs, cs1f, drv, mb;
t_stat r;
t_bool cs1dt;
MBACTX *mbp;
mb = mba_map_pa (pa, &ofs); /* get mb number */
if ((mb < 0) || (ofs < 0)) return SCPE_NXM; /* valid? */
mbp = ctxmap[mb]; /* get context */
drv = GET_UNIT (mbp->cs2); /* get drive */
if (ofs & EXT) { /* external? */
if (!mbregW[mb]) return SCPE_NXM; /* device there? */
if ((access == WRITEB) && (pa & 1)) /* byte writes */
val = val << 8; /* don't work */
r = mbregW[mb] (val, ofs & ~EXT, drv); /* write dev reg */
if (r == MBE_NXD) mba_set_cs2 (CS2_NED, mb); /* nx drive? */
else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
mba_upd_cs1 (0, 0, mb); /* update status */
return SCPE_OK;
}
cs1f = 0; /* no int on cs1 upd */
switch (ofs) { /* case on reg */
case CS1_OF: /* CS1 */
if (!mbregW[mb]) return SCPE_NXM; /* device exist? */
if ((access == WRITEB) && (pa & 1)) val = val << 8;
if (val & CS1_TRE) { /* error clear? */
mbp->cs1 = mbp->cs1 & ~CS1_TRE; /* clr CS1<TRE> */
mbp->cs2 = mbp->cs2 & ~CS2_ERR; /* clr CS2<15:8> */
mbp->cs3 = mbp->cs3 & ~CS3_ERR; /* clr CS3<15:11> */
}
if ((access == WRITE) || (pa & 1)) { /* hi byte write? */
if (mbp->cs1 & CS1_DONE) /* done set? */
mbp->cs1 = (mbp->cs1 & ~CS1_UAE) | (val & CS1_UAE); }
if ((access == WRITE) || !(pa & 1)) { /* lo byte write? */
if ((val & CS1_DONE) && (val & CS1_IE)) /* to DONE+IE? */
mbp->iff = 1; /* set CSTB INTR */
mbp->cs1 = (mbp->cs1 & ~CS1_IE) | (val & CS1_IE);
cs1dt = (val & CS1_GO) && (GET_FNC (val) >= FNC_XFER);
if (cs1dt && ((mbp->cs1 & CS1_DONE) == 0)) /* dt, done clr? */
mba_set_cs2 (CS2_PGE, mb); /* prgm error */
else {
r = mbregW[mb] (val & 077, ofs, drv); /* write dev CS1 */
if (r == MBE_NXD) mba_set_cs2 (CS2_NED, mb); /* nx drive? */
else if (r == MBE_NXR) return SCPE_NXM; /* nx reg? */
else if (cs1dt && (r == SCPE_OK)) { /* xfer, no err? */
mbp->cs1 &= ~(CS1_TRE | CS1_MCPE | CS1_DONE);
mbp->cs2 &= ~CS2_ERR; /* clear errors */
mbp->cs3 &= ~(CS3_ERR | CS3_DBL);
}
}
}
mbp->cs3 = (mbp->cs3 & ~CS1_IE) | /* update CS3 */
(mbp->cs1 & CS1_IE);
mbp->bae = (mbp->bae & ~CS1_M_UAE) | /* update BAE */
((mbp->cs1 >> CS1_V_UAE) & CS1_M_UAE);
break;
case WC_OF: /* WC */
if (access == WRITEB) val = (pa & 1)?
(mbp->wc & 0377) | (val << 8): (mbp->wc & ~0377) | val;
mbp->wc = val;
break;
case BA_OF: /* BA */
if (access == WRITEB) val = (pa & 1)?
(mbp->ba & 0377) | (val << 8): (mbp->ba & ~0377) | val;
mbp->ba = val & ~BA_MBZ;
break;
case CS2_OF: /* CS2 */
if ((access == WRITEB) && (pa & 1)) val = val << 8;
if (val & CS2_CLR) mba_reset (devmap[mb]); /* init? */
else {
if ((val & ~mbp->cs2) & (CS2_PE | CS2_MXF))
cs1f = CS1_SC; /* diagn intr */
if (access == WRITEB) val = (mbp->cs2 & /* merge val */
((pa & 1)? 0377: 0177400)) | val;
mbp->cs2 = (mbp->cs2 & ~CS2_RW) |
(val & CS2_RW) | CS2_IR | CS2_OR; }
break;
case DB_OF: /* DB */
if (access == WRITEB) val = (pa & 1)?
(mbp->db & 0377) | (val << 8): (mbp->db & ~0377) | val;
mbp->db = val;
break;
case BAE_OF: /* BAE */
if ((access == WRITEB) && (pa & 1)) break;
mbp->bae = val & ~AE_MBZ;
mbp->cs1 = (mbp->cs1 & ~CS1_UAE) | /* update CS1 */
((mbp->bae << CS1_V_UAE) & CS1_UAE);
break;
case CS3_OF: /* CS3 */
if ((access == WRITEB) && (pa & 1)) break;
mbp->cs3 = (mbp->cs3 & ~CS3_RW) | (val & CS3_RW);
mbp->cs1 = (mbp->cs1 & ~CS1_IE) | /* update CS1 */
(mbp->cs3 & CS1_IE);
break;
default:
return SCPE_NXM;
}
mba_upd_cs1 (cs1f, 0, mb); /* update status */
return SCPE_OK;
}
/* Massbus I/O routines
mb_rdbufW - fetch word buffer from memory
mb_wrbufW - store word buffer into memory
mb_chbufW - compare word buffer with memory
Returns number of bytes successfully transferred/checked
*/
int32 mba_rdbufW (uint32 mb, int32 bc, uint16 *buf)
{
MBACTX *mbp;
int32 i, j, ba, mbc, pbc;
uint32 pa;
bc = bc & ~1; /* bc even */
if (mb >= MBA_NUM) return 0; /* valid MBA? */
mbp = ctxmap[mb]; /* get context */
ba = (mbp->bae << 16) | mbp->ba; /* get busaddr */
mbc = (0200000 - mbp->wc) << 1; /* MB byte count */
if (bc > mbc) bc = mbc; /* use smaller */
for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
if (RH11 && cpu_bme) pa = Map_Addr (ba); /* map addr */
else pa = ba;
if (!ADDR_IS_MEM (pa)) { /* NXM? */
mba_set_cs2 (CS2_NEM, mb); /* set error */
break; }
pbc = UBM_PAGSIZE - UBM_GETOFF (pa); /* left in page */
if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
for (j = 0; j < pbc; j = j + 2) { /* loop by words */
*buf++ = M[pa >> 1]; /* fetch word */
if (!(mbp->cs2 & CS2_UAI)) { /* if not inhb */
ba = ba + 2; /* incr ba, pa */
pa = pa + 2;
}
}
}
mbp->wc = (mbp->wc + (bc >> 1)) & DMASK; /* update wc */
mbp->ba = ba & DMASK; /* update ba */
mbp->bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */
mbp->cs1 = (mbp->cs1 & ~ CS1_UAE) | /* update CS1 */
((mbp->bae << CS1_V_UAE) & CS1_UAE);
return i;
}
int32 mba_wrbufW (uint32 mb, int32 bc, uint16 *buf)
{
MBACTX *mbp;
int32 i, j, ba, mbc, pbc;
uint32 pa;
bc = bc & ~1; /* bc even */
if (mb >= MBA_NUM) return 0; /* valid MBA? */
mbp = ctxmap[mb]; /* get context */
ba = (mbp->bae << 16) | mbp->ba; /* get busaddr */
mbc = (0200000 - mbp->wc) << 1; /* MB byte count */
if (bc > mbc) bc = mbc; /* use smaller */
for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
if (RH11 && cpu_bme) pa = Map_Addr (ba); /* map addr */
else pa = ba;
if (!ADDR_IS_MEM (pa)) { /* NXM? */
mba_set_cs2 (CS2_NEM, mb); /* set error */
break; }
pbc = UBM_PAGSIZE - UBM_GETOFF (pa); /* left in page */
if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
for (j = 0; j < pbc; j = j + 2) { /* loop by words */
M[pa >> 1] = *buf++; /* put word */
if (!(mbp->cs2 & CS2_UAI)) { /* if not inhb */
ba = ba + 2; /* incr ba, pa */
pa = pa + 2;
}
}
}
mbp->wc = (mbp->wc + (bc >> 1)) & DMASK; /* update wc */
mbp->ba = ba & DMASK; /* update ba */
mbp->bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */
mbp->cs1 = (mbp->cs1 & ~ CS1_UAE) | /* update CS1 */
((mbp->bae << CS1_V_UAE) & CS1_UAE);
return i;
}
int32 mba_chbufW (uint32 mb, int32 bc, uint16 *buf)
{
MBACTX *mbp;
int32 i, j, ba, mbc, pbc;
uint32 pa;
bc = bc & ~1; /* bc even */
if (mb >= MBA_NUM) return 0; /* valid MBA? */
mbp = ctxmap[mb]; /* get context */
ba = (mbp->bae << 16) | mbp->ba; /* get busaddr */
mbc = (0200000 - mbp->wc) << 1; /* MB byte count */
if (bc > mbc) bc = mbc; /* use smaller */
for (i = 0; i < bc; i = i + pbc) { /* loop by pages */
if (RH11 && cpu_bme) pa = Map_Addr (ba); /* map addr */
else pa = ba;
if (!ADDR_IS_MEM (pa)) { /* NXM? */
mba_set_cs2 (CS2_NEM, mb); /* set error */
break; }
pbc = UBM_PAGSIZE - UBM_GETOFF (pa); /* left in page */
if (pbc > (bc - i)) pbc = bc - i; /* limit to rem xfr */
for (j = 0; j < pbc; j = j + 2) { /* loop by words */
mbp->db = *buf++; /* get dev word */
if (M[pa >> 1] != mbp->db) { /* miscompare? */
mba_set_cs2 (CS2_WCE, mb); /* set error */
mbp->cs3 = mbp->cs3 | /* set even/odd */
((pa & 1)? CS3_WCO: CS3_WCE);
break; }
if (!(mbp->cs2 & CS2_UAI)) { /* if not inhb */
ba = ba + 2; /* incr ba, pa */
pa = pa + 2;
}
}
}
mbp->wc = (mbp->wc + (bc >> 1)) & DMASK; /* update wc */
mbp->ba = ba & DMASK; /* update ba */
mbp->bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */
mbp->cs1 = (mbp->cs1 & ~ CS1_UAE) | /* update CS1 */
((mbp->bae << CS1_V_UAE) & CS1_UAE);
return i;
}
/* Device access, status, and interrupt routines */
void mba_set_don (uint32 mb)
{
mba_upd_cs1 (CS1_DONE, 0, mb);
return;
}
void mba_upd_ata (uint32 mb, uint32 val)
{
if (val) mba_upd_cs1 (CS1_SC, 0, mb);
else mba_upd_cs1 (0, CS1_SC, mb);
return;
}
void mba_set_exc (uint32 mb)
{
mba_upd_cs1 (CS1_TRE | CS1_DONE, 0, mb);
return;
}
int32 mba_get_bc (uint32 mb)
{
MBACTX *mbp;
if (mb >= MBA_NUM) return 0;
mbp = ctxmap[mb];
return ((0200000 - mbp->wc) << 1);
}
int32 mba_get_csr (uint32 mb)
{
DEVICE *dptr;
DIB *dibp;
if (mb >= MBA_NUM) return 0;
dptr = devmap[mb];
dibp = (DIB *) dptr->ctxt;
return dibp->ba;
}
void mba_set_int (uint32 mb)
{
DEVICE *dptr;
DIB *dibp;
if (mb >= MBA_NUM) return;
dptr = devmap[mb];
dibp = (DIB *) dptr->ctxt;
int_req[dibp->vloc >> 5] |= (1 << (dibp->vloc & 037));
return;
}
void mba_clr_int (uint32 mb)
{
DEVICE *dptr;
DIB *dibp;
if (mb >= MBA_NUM) return;
dptr = devmap[mb];
dibp = (DIB *) dptr->ctxt;
int_req[dibp->vloc >> 5] &= ~(1 << (dibp->vloc & 037));
return;
}
void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb)
{
MBACTX *mbp;
if (mb >= MBA_NUM) return;
mbp = ctxmap[mb];
if ((set & ~mbp->cs1) & CS1_DONE) /* DONE 0 to 1? */
mbp->iff = (mbp->cs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */
mbp->cs1 = (mbp->cs1 & ~(clr | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | set;
if (mbp->cs2 & CS2_ERR) mbp->cs1 = mbp->cs1 | CS1_TRE | CS1_SC;
else if (mbp->cs1 & CS1_TRE) mbp->cs1 = mbp->cs1 | CS1_SC;
if (mbp->iff || ((mbp->cs1 & CS1_SC) && (mbp->cs1 & CS1_DONE) && (mbp->cs1 & CS1_IE)))
mba_set_int (mb);
else mba_clr_int (mb);
return;
}
void mba_set_cs2 (uint32 flag, uint32 mb)
{
MBACTX *mbp;
if (mb >= MBA_NUM) return;
mbp = ctxmap[mb];
mbp->cs2 = mbp->cs2 | flag;
mba_upd_cs1 (0, 0, mb);
return;
}
/* Interrupt acknowledge */
int32 mba0_inta (void)
{
massbus[0].cs1 &= ~CS1_IE; /* clear int enable */
massbus[0].cs3 &= ~CS1_IE; /* in both registers */
massbus[0].iff = 0; /* clear CSTB INTR */
return mba0_dib.vec; /* acknowledge */
}
int32 mba1_inta (void)
{
massbus[1].cs1 &= ~CS1_IE; /* clear int enable */
massbus[1].cs3 &= ~CS1_IE; /* in both registers */
massbus[1].iff = 0; /* clear CSTB INTR */
return mba1_dib.vec; /* acknowledge */
}
/* Map physical address to Massbus number, offset */
uint32 mba_map_pa (int32 pa, int32 *ofs)
{
int32 i, uo, ba, lnt;
DEVICE *dptr;
DIB *dibp;
for (i = 0; i < MBA_NUM; i++) { /* loop thru ctrls */
dptr = devmap[i]; /* get device */
dibp = (DIB *) dptr->ctxt; /* get DIB */
ba = dibp->ba;
lnt = dibp->lnt;
if ((pa >= ba) && /* in range? */
(pa < (ba + lnt))) {
if (pa < (ba + (lnt - 4))) { /* not last two? */
uo = ((pa - ba) & MBA_OFSMASK) >> 1; /* get Unibus offset */
*ofs = mba_mapofs[uo]; /* map thru PROM */
return i; /* return ctrl idx */
}
else if (RH11) return -1; /* RH11? done */
else { /* RH70 */
uo = (pa - (ba + (lnt - 4))) >> 1; /* offset relative */
*ofs = BAE_OF + uo; /* to BAE */
return i;
}
}
}
return -1;
}
/* Reset Massbus adapter */
t_stat mba_reset (DEVICE *dptr)
{
int32 mb;
MBACTX *mbp;
for (mb = 0; mb < MBA_NUM; mb++) {
mbp = ctxmap[mb];
if (dptr == devmap[mb]) break;
}
if (mb >= MBA_NUM) return SCPE_NOFNC;
mbp->cs1 = CS1_DONE;
mbp->wc = 0;
mbp->ba = 0;
mbp->cs2 = 0;
mbp->db = 0;
mbp->bae= 0;
mbp->cs3 = 0;
mbp->iff = 0;
mba_clr_int (mb);
if (mbabort[mb]) mbabort[mb] ();
return SCPE_OK;
}
/* Show Massbus adapter number */
t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc)
{
DEVICE *dptr = find_dev_from_unit (uptr);
DIB *dibp;
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
fprintf (st, "Massbus adapter %d", dibp->ba);
return SCPE_OK;
}
/* Init Mbus tables */
void init_mbus_tab (void)
{
uint32 i;
for (i = 0; i < MBA_NUM; i++) {
mbregR[i] = NULL;
mbregW[i] = NULL;
mbabort[i] = NULL;
}
return;
}
/* Build dispatch tables */
t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp)
{
uint32 idx;
if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */
idx = dibp->ba; /* Mbus # */
if (idx >= MBA_NUM) return SCPE_STOP;
if ((mbregR[idx] && dibp->rd && /* conflict? */
(mbregR[idx] != dibp->rd)) ||
(mbregW[idx] && dibp->wr &&
(mbregW[idx] != dibp->wr)) ||
(mbabort[idx] && dibp->ack[0] &&
(mbabort[idx] != dibp->ack[0]))) {
printf ("Massbus %s assignment conflict at %d\n",
sim_dname (dptr), dibp->ba);
if (sim_log) fprintf (sim_log,
"Massbus %s assignment conflict at %d\n",
sim_dname (dptr), dibp->ba);
return SCPE_STOP;
}
if (dibp->rd) mbregR[idx] = dibp->rd; /* set rd dispatch */
if (dibp->wr) mbregW[idx] = dibp->wr; /* set wr dispatch */
if (dibp->ack[0]) mbabort[idx] = dibp->ack[0]; /* set abort dispatch */
return SCPE_OK;
}

View file

@ -25,6 +25,7 @@
rk RK11/RKV11/RK05 cartridge disk rk RK11/RKV11/RK05 cartridge disk
30-Sep-04 RMS Revised Unibus interface
24-Jan-04 RMS Added increment inhibit, overrun detection, formatting 24-Jan-04 RMS Added increment inhibit, overrun detection, formatting
29-Dec-03 RMS Added RKV11 support 29-Dec-03 RMS Added RKV11 support
29-Sep-02 RMS Added variable address support to bootstrap 29-Sep-02 RMS Added variable address support to bootstrap
@ -484,12 +485,12 @@ if (wc && (err == 0)) { /* seek ok? */
for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */
} }
if (rkcs & RKCS_INH) { /* incr inhibit? */ if (rkcs & RKCS_INH) { /* incr inhibit? */
if (t = Map_WriteW (ma, 2, &rkxb[wc - 1], MAP)) { /* store last */ if (t = Map_WriteW (ma, 2, &rkxb[wc - 1])) { /* store last */
rker = rker | RKER_NXM; /* NXM? set flag */ rker = rker | RKER_NXM; /* NXM? set flag */
wc = 0; } /* no transfer */ wc = 0; } /* no transfer */
} }
else { /* normal store */ else { /* normal store */
if (t = Map_WriteW (ma, wc << 1, rkxb, MAP)) { /* store buf */ if (t = Map_WriteW (ma, wc << 1, rkxb)) { /* store buf */
rker = rker | RKER_NXM; /* NXM? set flag */ rker = rker | RKER_NXM; /* NXM? set flag */
wc = wc - t; } /* adj wd cnt */ wc = wc - t; } /* adj wd cnt */
} }
@ -497,13 +498,13 @@ if (wc && (err == 0)) { /* seek ok? */
case RKCS_WRITE: /* write */ case RKCS_WRITE: /* write */
if (rkcs & RKCS_INH) { /* incr inhibit? */ if (rkcs & RKCS_INH) { /* incr inhibit? */
if (t = Map_ReadW (ma, 2, &comp, MAP)) { /* get 1st word */ if (t = Map_ReadW (ma, 2, &comp)) { /* get 1st word */
rker = rker | RKER_NXM; /* NXM? set flag */ rker = rker | RKER_NXM; /* NXM? set flag */
wc = 0; } /* no transfer */ wc = 0; } /* no transfer */
for (i = 0; i < wc; i++) rkxb[i] = comp; /* all words same */ for (i = 0; i < wc; i++) rkxb[i] = comp; /* all words same */
} }
else { /* normal fetch */ else { /* normal fetch */
if (t = Map_ReadW (ma, wc << 1, rkxb, MAP)) { /* get buf */ if (t = Map_ReadW (ma, wc << 1, rkxb)) { /* get buf */
rker = rker | RKER_NXM; /* NXM? set flg */ rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */ wc = wc - t; } /* adj wd cnt */
} }
@ -523,7 +524,7 @@ if (wc && (err == 0)) { /* seek ok? */
for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */
awc = wc; /* save wc */ awc = wc; /* save wc */
for (wc = 0, cma = ma; wc < awc; wc++) { /* loop thru buf */ for (wc = 0, cma = ma; wc < awc; wc++) { /* loop thru buf */
if (Map_ReadW (cma, 2, &comp, MAP)) { /* mem wd */ if (Map_ReadW (cma, 2, &comp)) { /* mem wd */
rker = rker | RKER_NXM; /* NXM? set flg */ rker = rker | RKER_NXM; /* NXM? set flg */
break; } break; }
if (comp != rkxb[wc]) { /* match to disk? */ if (comp != rkxb[wc]) { /* match to disk? */
@ -618,7 +619,7 @@ for (i = 0; i < RK_NUMDR; i++) {
sim_cancel (uptr); sim_cancel (uptr);
uptr->CYL = uptr->FUNC = 0; uptr->CYL = uptr->FUNC = 0;
uptr->flags = uptr->flags & ~UNIT_SWLK; } uptr->flags = uptr->flags & ~UNIT_SWLK; }
if (rkxb == NULL) rkxb = calloc (RK_MAXFR, sizeof (unsigned int16)); if (rkxb == NULL) rkxb = calloc (RK_MAXFR, sizeof (uint16));
if (rkxb == NULL) return SCPE_MEM; if (rkxb == NULL) return SCPE_MEM;
return SCPE_OK; return SCPE_OK;
} }

View file

@ -25,6 +25,7 @@
rl RL11(RLV12)/RL01/RL02 cartridge disk rl RL11(RLV12)/RL01/RL02 cartridge disk
30-Sep-04 RMS Revised Unibus interface
04-Jan-04 RMS Changed sim_fsize calling sequence 04-Jan-04 RMS Changed sim_fsize calling sequence
19-May-03 RMS Revised for new conditional compilation scheme 19-May-03 RMS Revised for new conditional compilation scheme
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
@ -73,14 +74,10 @@
#elif defined (VM_VAX) /* VAX version */ #elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h" #include "vax_defs.h"
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
#else /* PDP-11 version */ #else /* PDP-11 version */
#include "pdp11_defs.h" #include "pdp11_defs.h"
extern int32 int_req[IPL_HLVL]; extern int32 cpu_opt;
extern int32 int_vec[IPL_HLVL][32];
extern int32 cpu_18b, cpu_ubm;
#endif #endif
/* Constants */ /* Constants */
@ -191,7 +188,6 @@ extern int32 cpu_18b, cpu_ubm;
#define RLBAE_IMP 0000077 /* implemented */ #define RLBAE_IMP 0000077 /* implemented */
extern uint16 *M;
extern int32 int_req[IPL_HLVL]; extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32]; extern int32 int_vec[IPL_HLVL][32];
@ -462,13 +458,13 @@ if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */
i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); i = fxread (rlxb, sizeof (int16), wc, uptr->fileref);
err = ferror (uptr->fileref); err = ferror (uptr->fileref);
for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */ for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */
if (t = Map_WriteW (ma, wc << 1, rlxb, MAP)) { /* store buffer */ if (t = Map_WriteW (ma, wc << 1, rlxb)) { /* store buffer */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adjust wc */ wc = wc - t; } /* adjust wc */
} /* end read */ } /* end read */
if ((func == RLCS_WRITE) && (err == 0)) { /* write? */ if ((func == RLCS_WRITE) && (err == 0)) { /* write? */
if (t = Map_ReadW (ma, wc << 1, rlxb, MAP)) { /* fetch buffer */ if (t = Map_ReadW (ma, wc << 1, rlxb)) { /* fetch buffer */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adj xfer lnt */ wc = wc - t; } /* adj xfer lnt */
if (wc) { /* any xfer? */ if (wc) { /* any xfer? */
@ -484,7 +480,7 @@ if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */
for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */ for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */
awc = wc; /* save wc */ awc = wc; /* save wc */
for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */ for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */
if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */ if (Map_ReadW (ma + (wc << 1), 2, &comp)) { /* mem wd */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
break; } break; }
if (comp != rlxb[wc]) /* check to buf */ if (comp != rlxb[wc]) /* check to buf */
@ -535,7 +531,7 @@ for (i = 0; i < RL_NUMDR; i++) {
uptr = rl_dev.units + i; uptr = rl_dev.units + i;
sim_cancel (uptr); sim_cancel (uptr);
uptr->STAT = 0; } uptr->STAT = 0; }
if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int16)); if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (uint16));
if (rlxb == NULL) return SCPE_MEM; if (rlxb == NULL) return SCPE_MEM;
return SCPE_OK; return SCPE_OK;
} }
@ -635,6 +631,7 @@ static const uint16 boot_rom[] = {
t_stat rl_boot (int32 unitno, DEVICE *dptr) t_stat rl_boot (int32 unitno, DEVICE *dptr)
{ {
int32 i; int32 i;
extern uint16 *M;
extern int32 saved_PC; extern int32 saved_PC;
for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
@ -650,4 +647,6 @@ t_stat rl_boot (int32 unitno, DEVICE *dptr)
{ {
return SCPE_NOFNC; return SCPE_NOFNC;
} }
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,11 @@
rq RQDX3 disk controller rq RQDX3 disk controller
31-Oct-04 RMS Added -L switch (LBNs) to RAUSER size specification
01-Oct-04 RMS Revised Unibus interface
Changed to identify as UDA50 in Unibus configurations
Changed width to be 16b in all configurations
Changed default timing for VAX
24-Jul-04 RMS VAX controllers luns start with 0 (from Andreas Cejna) 24-Jul-04 RMS VAX controllers luns start with 0 (from Andreas Cejna)
05-Feb-04 RMS Revised for file I/O library 05-Feb-04 RMS Revised for file I/O library
25-Jan-04 RMS Revised for device debug support 25-Jan-04 RMS Revised for device debug support
@ -64,18 +69,18 @@
#elif defined (VM_VAX) /* VAX version */ #elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h" #include "vax_defs.h"
#define RQ_AINC 4 #define RQ_QTIME 100
#define RQ_WID 32 #define RQ_XTIME 200
extern int32 int_req[IPL_HLVL]; #define OLDPC fault_PC
extern int32 int_vec[IPL_HLVL][32]; extern int32 fault_PC;
#else /* PDP-11 version */ #else /* PDP-11 version */
#include "pdp11_defs.h" #include "pdp11_defs.h"
#define RQ_AINC 2 #define RQ_QTIME 200
#define RQ_WID 16 #define RQ_XTIME 500
extern int32 cpu_18b, cpu_ubm; #define OLDPC MMR2
extern int32 int_req[IPL_HLVL]; extern int32 MMR2;
extern int32 int_vec[IPL_HLVL][32]; extern int32 cpu_opt;
#endif #endif
#if !defined (RQ_NUMCT) #if !defined (RQ_NUMCT)
@ -98,8 +103,12 @@ extern int32 int_vec[IPL_HLVL][32];
#define RQ_SH_UN 010 /* show unit q's */ #define RQ_SH_UN 010 /* show unit q's */
#define RQ_CLASS 1 /* RQ class */ #define RQ_CLASS 1 /* RQ class */
#define RQ_UQPM 19 /* UQ port model */ #define RQU_UQPM 6 /* UB port model */
#define RQ_MODEL 19 /* MSCP ctrl model */ #define RQQ_UQPM 19 /* QB port model */
#define RQ_UQPM (UNIBUS? RQU_UQPM: RQQ_UQPM)
#define RQU_MODEL 6 /* UB MSCP ctrl model */
#define RQQ_MODEL 19 /* QB MSCP ctrl model */
#define RQ_MODEL (UNIBUS? RQU_MODEL: RQQ_MODEL)
#define RQ_HVER 1 /* hardware version */ #define RQ_HVER 1 /* hardware version */
#define RQ_SVER 3 /* software version */ #define RQ_SVER 3 /* software version */
#define RQ_DHTMO 60 /* def host timeout */ #define RQ_DHTMO 60 /* def host timeout */
@ -169,7 +178,7 @@ struct rqpkt {
#define PUTP32(p,w,x) cp->pak[p].d[w] = (x) & 0xFFFF; \ #define PUTP32(p,w,x) cp->pak[p].d[w] = (x) & 0xFFFF; \
cp->pak[p].d[(w)+1] = ((x) >> 16) & 0xFFFF cp->pak[p].d[(w)+1] = ((x) >> 16) & 0xFFFF
/* Disk formats. An RQDX3 consists of the following regions: /* Disk formats. An RQDX3 disk consists of the following regions:
XBNs Extended blocks - contain information about disk format, XBNs Extended blocks - contain information about disk format,
also holds track being reformatted during bad block repl. also holds track being reformatted during bad block repl.
@ -417,23 +426,23 @@ struct rqpkt {
#define RA92_FLGS RQDF_SDI #define RA92_FLGS RQDF_SDI
#define RA8U_DTYPE 12 /* user defined */ #define RA8U_DTYPE 12 /* user defined */
#define RA8U_SECT 57 /* +1 spare/track */ #define RA8U_SECT 57 /* from RA82 */
#define RA8U_SURF 15 #define RA8U_SURF 15
#define RA8U_CYL 1435 /* 0-1422 user */ #define RA8U_CYL 1435 /* from RA82 */
#define RA8U_TPG RA8U_SURF #define RA8U_TPG RA8U_SURF
#define RA8U_GPC 1 #define RA8U_GPC 1
#define RA8U_XBN 3420 /* cyl 1427-1430 */ #define RA8U_XBN 0
#define RA8U_DBN 3420 /* cyl 1431-1434 */ #define RA8U_DBN 0
#define RA8U_LBN 1216665 /* 57*15*1423 */ #define RA8U_LBN 1216665 /* from RA82 */
#define RA8U_RCTS 400 /* cyl 1423-1426 */ #define RA8U_RCTS 400
#define RA8U_RCTC 8 #define RA8U_RCTC 8
#define RA8U_RBN 21345 /* 1 *15*1423 */ #define RA8U_RBN 21345
#define RA8U_MOD 11 /* RA82 */ #define RA8U_MOD 11 /* RA82 */
#define RA8U_MED 0x25641052 /* RA82 */ #define RA8U_MED 0x25641052 /* RA82 */
#define RA8U_FLGS RQDF_SDI #define RA8U_FLGS RQDF_SDI
#define RA8U_MINC 5 /* min cap MB */ #define RA8U_MINC 10000 /* min cap LBNs */
#define RA8U_MAXC 2000 /* max cap MB */ #define RA8U_MAXC 4000000 /* max cap LBNs */
#define RA8U_EMAXC 1000000 /* ext max cap */ #define RA8U_EMAXC 2000000000 /* ext max cap */
struct drvtyp { struct drvtyp {
int32 sect; /* sectors */ int32 sect; /* sectors */
@ -474,12 +483,13 @@ extern int32 tmr_poll, clk_tps;
extern UNIT cpu_unit; extern UNIT cpu_unit;
extern FILE *sim_deb; extern FILE *sim_deb;
extern uint32 sim_taddr_64; extern uint32 sim_taddr_64;
extern int32 sim_switches;
uint16 *rqxb = NULL; /* xfer buffer */ uint16 *rqxb = NULL; /* xfer buffer */
int32 rq_itime = 200; /* init time, except */ int32 rq_itime = 200; /* init time, except */
int32 rq_itime4 = 10; /* stage 4 */ int32 rq_itime4 = 10; /* stage 4 */
int32 rq_qtime = 200; /* queue time */ int32 rq_qtime = RQ_QTIME; /* queue time */
int32 rq_xtime = 500; /* transfer time */ int32 rq_xtime = RQ_XTIME; /* transfer time */
struct mscp_con { struct mscp_con {
uint32 cnum; /* ctrl number */ uint32 cnum; /* ctrl number */
@ -687,7 +697,7 @@ MTAB rq_mod[] = {
DEVICE rq_dev = { DEVICE rq_dev = {
"RQ", rq_unit, rq_reg, rq_mod, "RQ", rq_unit, rq_reg, rq_mod,
RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, RQ_NUMDR + 2, DEV_RDX, 31, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG };
@ -751,7 +761,7 @@ REG rqb_reg[] = {
DEVICE rqb_dev = { DEVICE rqb_dev = {
"RQB", rqb_unit, rqb_reg, rq_mod, "RQB", rqb_unit, rqb_reg, rq_mod,
RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, RQ_NUMDR + 2, DEV_RDX, 31, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG };
@ -815,7 +825,7 @@ REG rqc_reg[] = {
DEVICE rqc_dev = { DEVICE rqc_dev = {
"RQC", rqc_unit, rqc_reg, rq_mod, "RQC", rqc_unit, rqc_reg, rq_mod,
RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, RQ_NUMDR + 2, DEV_RDX, 31, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG };
@ -879,7 +889,7 @@ REG rqd_reg[] = {
DEVICE rqd_dev = { DEVICE rqd_dev = {
"RQD", rqd_unit, rqd_reg, rq_mod, "RQD", rqd_unit, rqd_reg, rq_mod,
RQ_NUMDR + 2, DEV_RDX, 31, RQ_AINC, DEV_RDX, RQ_WID, RQ_NUMDR + 2, DEV_RDX, 31, 2, DEV_RDX, 16,
NULL, NULL, &rq_reset, NULL, NULL, &rq_reset,
&rq_boot, &rq_attach, &rq_detach, &rq_boot, &rq_attach, &rq_detach,
&rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG }; &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG };
@ -908,6 +918,8 @@ case 0: /* IP */
*data = 0; /* reads zero */ *data = 0; /* reads zero */
if (cp->csta == CST_S3_PPB) rq_step4 (cp); /* waiting for poll? */ if (cp->csta == CST_S3_PPB) rq_step4 (cp); /* waiting for poll? */
else if (cp->csta == CST_UP) { /* if up */ else if (cp->csta == CST_UP) { /* if up */
if (DEBUG_PRD (dptr)) fprintf (sim_deb,
">>RQ%c: poll started, PC=%X\n", 'A' + cp->cnum, OLDPC);
cp->pip = 1; /* poll host */ cp->pip = 1; /* poll host */
sim_activate (dptr->units + RQ_QUEUE, rq_qtime); } sim_activate (dptr->units + RQ_QUEUE, rq_qtime); }
break; break;
@ -977,7 +989,7 @@ else base = cp->comm + SA_COMM_CI;
lnt = cp->comm + cp->cq.lnt + cp->rq.lnt - base; /* comm lnt */ lnt = cp->comm + cp->cq.lnt + cp->rq.lnt - base; /* comm lnt */
if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */ if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */
for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */ for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */
if (Map_WriteW (base, lnt, zero, MAP)) /* zero comm area */ if (Map_WriteW (base, lnt, zero)) /* zero comm area */
return rq_fatal (cp, PE_QWE); /* error? */ return rq_fatal (cp, PE_QWE); /* error? */
cp->sa = SA_S4 | (RQ_UQPM << SA_S4C_V_MOD) | /* send step 4 */ cp->sa = SA_S4 | (RQ_UQPM << SA_S4C_V_MOD) | /* send step 4 */
(RQ_SVER << SA_S4C_V_VER); (RQ_SVER << SA_S4C_V_VER);
@ -1427,8 +1439,7 @@ int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd)
uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
uint32 lbn = GETP32 (pkt, RW_LBNL); /* get lbn */ uint32 lbn = GETP32 (pkt, RW_LBNL); /* get lbn */
uint32 bc = GETP32 (pkt, RW_BCL); /* get byte cnt */ uint32 bc = GETP32 (pkt, RW_BCL); /* get byte cnt */
uint32 maxlbn = uptr->capac / RQ_NUMBY; /* get max lbn */ uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */
/* uint32 maxlbn = drv_tab[dtyp].lbn; /* get max lbn */
if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */
return (ST_OFL | SB_OFL_NV); /* offl no vol */ return (ST_OFL | SB_OFL_NV); /* offl no vol */
@ -1497,7 +1508,7 @@ if (cmd == OP_ERS) { /* erase? */
err = ferror (uptr->fileref); } /* end if erase */ err = ferror (uptr->fileref); } /* end if erase */
else if (cmd == OP_WR) { /* write? */ else if (cmd == OP_WR) { /* write? */
t = Map_ReadW (ba, tbc, rqxb, MAP); /* fetch buffer */ t = Map_ReadW (ba, tbc, rqxb); /* fetch buffer */
if (abc = tbc - t) { /* any xfer? */ if (abc = tbc - t) { /* any xfer? */
wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1;
for (i = (abc >> 1); i < wwc; i++) rqxb[i] = 0; for (i = (abc >> 1); i < wwc; i++) rqxb[i] = 0;
@ -1517,7 +1528,7 @@ else { err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */
for ( ; i < (tbc >> 1); i++) rqxb[i] = 0; /* fill */ for ( ; i < (tbc >> 1); i++) rqxb[i] = 0; /* fill */
err = ferror (uptr->fileref); } err = ferror (uptr->fileref); }
if ((cmd == OP_RD) && !err) { /* read? */ if ((cmd == OP_RD) && !err) { /* read? */
if (t = Map_WriteW (ba, tbc, rqxb, MAP)) { /* store, nxm? */ if (t = Map_WriteW (ba, tbc, rqxb)) { /* store, nxm? */
PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */
PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */
if (rq_hbe (cp, uptr)) /* post err log */ if (rq_hbe (cp, uptr)) /* post err log */
@ -1527,7 +1538,7 @@ else { err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */
else if ((cmd == OP_CMP) && !err) { /* compare? */ else if ((cmd == OP_CMP) && !err) { /* compare? */
uint8 dby, mby; uint8 dby, mby;
for (i = 0; i < tbc; i++) { /* loop */ for (i = 0; i < tbc; i++) { /* loop */
if (Map_ReadB (ba + i, 1, &mby, MAP)) { /* fetch, nxm? */ if (Map_ReadB (ba + i, 1, &mby)) { /* fetch, nxm? */
PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */
PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */ PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */
if (rq_hbe (cp, uptr)) /* post err log */ if (rq_hbe (cp, uptr)) /* post err log */
@ -1762,7 +1773,7 @@ if ((desc & UQ_DESC_OWN) == 0) { /* none */
if (!rq_deqf (cp, pkt)) return ERR; /* get cmd pkt */ if (!rq_deqf (cp, pkt)) return ERR; /* get cmd pkt */
cp->hat = 0; /* dsbl hst timer */ cp->hat = 0; /* dsbl hst timer */
addr = desc & UQ_ADDR; /* get Q22 addr */ addr = desc & UQ_ADDR; /* get Q22 addr */
if (Map_ReadW (addr + UQ_HDR_OFF, RQ_PKT_SIZE, cp->pak[*pkt].d, MAP)) if (Map_ReadW (addr + UQ_HDR_OFF, RQ_PKT_SIZE, cp->pak[*pkt].d))
return rq_fatal (cp, PE_PRE); /* read pkt */ return rq_fatal (cp, PE_PRE); /* read pkt */
return rq_putdesc (cp, &cp->cq, desc); /* release desc */ return rq_putdesc (cp, &cp->cq, desc); /* release desc */
} }
@ -1794,7 +1805,7 @@ if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */
cr = (cp->credits >= 14)? 14: cp->credits; /* max 14 credits */ cr = (cp->credits >= 14)? 14: cp->credits; /* max 14 credits */
cp->credits = cp->credits - cr; /* decr credits */ cp->credits = cp->credits - cr; /* decr credits */
cp->pak[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); } cp->pak[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); }
if (Map_WriteW (addr + UQ_HDR_OFF, lnt, cp->pak[pkt].d, MAP)) if (Map_WriteW (addr + UQ_HDR_OFF, lnt, cp->pak[pkt].d))
return rq_fatal (cp, PE_PWE); /* write pkt */ return rq_fatal (cp, PE_PWE); /* write pkt */
rq_enqh (cp, &cp->freq, pkt); /* pkt is free */ rq_enqh (cp, &cp->freq, pkt); /* pkt is free */
cp->pbsy = cp->pbsy - 1; /* decr busy cnt */ cp->pbsy = cp->pbsy - 1; /* decr busy cnt */
@ -1809,7 +1820,7 @@ t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc)
uint32 addr = ring->ba + ring->idx; uint32 addr = ring->ba + ring->idx;
uint16 d[2]; uint16 d[2];
if (Map_ReadW (addr, 4, d, MAP)) /* fetch desc */ if (Map_ReadW (addr, 4, d)) /* fetch desc */
return rq_fatal (cp, PE_QRE); /* err? dead */ return rq_fatal (cp, PE_QRE); /* err? dead */
*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
return OK; return OK;
@ -1829,13 +1840,13 @@ uint16 d[2];
d[0] = newd & 0xFFFF; /* 32b to 16b */ d[0] = newd & 0xFFFF; /* 32b to 16b */
d[1] = (newd >> 16) & 0xFFFF; d[1] = (newd >> 16) & 0xFFFF;
if (Map_WriteW (addr, 4, d, MAP)) /* store desc */ if (Map_WriteW (addr, 4, d)) /* store desc */
return rq_fatal (cp, PE_QWE); /* err? dead */ return rq_fatal (cp, PE_QWE); /* err? dead */
if (desc & UQ_DESC_F) { /* was F set? */ if (desc & UQ_DESC_F) { /* was F set? */
if (ring->lnt <= 4) rq_ring_int (cp, ring); /* lnt = 1? intr */ if (ring->lnt <= 4) rq_ring_int (cp, ring); /* lnt = 1? intr */
else { /* prv desc */ else { /* prv desc */
prva = ring->ba + ((ring->idx - 4) & (ring->lnt - 1)); prva = ring->ba + ((ring->idx - 4) & (ring->lnt - 1));
if (Map_ReadW (prva, 4, d, MAP)) /* read prv */ if (Map_ReadW (prva, 4, d)) /* read prv */
return rq_fatal (cp, PE_QRE); return rq_fatal (cp, PE_QRE);
prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16);
if (prvd & UQ_DESC_OWN) rq_ring_int (cp, ring); } } if (prvd & UQ_DESC_OWN) rq_ring_int (cp, ring); } }
@ -1873,7 +1884,7 @@ return;
void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all) void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all)
{ {
uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */
uint32 maxlbn = uptr->capac / RQ_NUMBY; /* get max lbn */ uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */
cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */ cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */
cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr);
@ -1922,7 +1933,7 @@ void rq_ring_int (MSC *cp, struct uq_ring *ring)
uint32 iadr = cp->comm + ring->ioff; /* addr intr wd */ uint32 iadr = cp->comm + ring->ioff; /* addr intr wd */
uint16 flag = 1; uint16 flag = 1;
Map_WriteW (iadr, 2, &flag, MAP); /* write flag */ Map_WriteW (iadr, 2, &flag); /* write flag */
if (cp->s1dat & SA_S1H_VEC) rq_setint (cp); /* if enb, intr */ if (cp->s1dat & SA_S1H_VEC) rq_setint (cp); /* if enb, intr */
return; return;
} }
@ -2021,9 +2032,10 @@ if ((val < 0) || (val > RA8U_DTYPE) || ((val != RA8U_DTYPE) && cptr))
return SCPE_ARG; return SCPE_ARG;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT; if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
if (cptr) { if (cptr) {
cap = (int32) get_uint (cptr, 10, max, &r); cap = (uint32) get_uint (cptr, 10, 0xFFFFFFFF, &r);
if ((r != SCPE_OK) || (cap < RA8U_MINC)) return SCPE_ARG; if ((sim_switches & SWMASK ('L')) == 0) cap = cap * 1954;
drv_tab[val].lbn = cap * 1954; } if ((r != SCPE_OK) || (cap < RA8U_MINC) || (cap >= max)) return SCPE_ARG;
drv_tab[val].lbn = cap; }
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE); uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE);
uptr->capac = ((t_addr) drv_tab[val].lbn) * RQ_NUMBY; uptr->capac = ((t_addr) drv_tab[val].lbn) * RQ_NUMBY;
return SCPE_OK; return SCPE_OK;
@ -2089,7 +2101,8 @@ cp->csta = CST_S1; /* init stage 1 */
cp->s1dat = 0; /* no S1 data */ cp->s1dat = 0; /* no S1 data */
dibp->vec = 0; /* no vector */ dibp->vec = 0; /* no vector */
cp->comm = 0; /* no comm region */ cp->comm = 0; /* no comm region */
cp->sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ if (UNIBUS) cp->sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; /* Unibus? */
else cp->sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */
cp->cflgs = CF_RPL; /* ctrl flgs off */ cp->cflgs = CF_RPL; /* ctrl flgs off */
cp->htmo = RQ_DHTMO; /* default timeout */ cp->htmo = RQ_DHTMO; /* default timeout */
cp->hat = cp->htmo; /* default timer */ cp->hat = cp->htmo; /* default timer */
@ -2112,7 +2125,7 @@ for (i = 0; i < (RQ_NUMDR + 2); i++) { /* init units */
uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP);
uptr->uf = 0; /* clr unit flags */ uptr->uf = 0; /* clr unit flags */
uptr->cpkt = uptr->pktq = 0; } /* clr pkt q's */ uptr->cpkt = uptr->pktq = 0; } /* clr pkt q's */
if (rqxb == NULL) rqxb = calloc (RQ_MAXFR >> 1, sizeof (unsigned int16)); if (rqxb == NULL) rqxb = calloc (RQ_MAXFR >> 1, sizeof (uint16));
if (rqxb == NULL) return SCPE_MEM; if (rqxb == NULL) return SCPE_MEM;
return auto_config (0, 0); /* run autoconfig */ return auto_config (0, 0); /* run autoconfig */
} }
@ -2230,7 +2243,7 @@ fprintf (st, "ring, base = %x, index = %d, length = %d\n",
rp->ba, rp->idx >> 2, rp->lnt >> 2); rp->ba, rp->idx >> 2, rp->lnt >> 2);
#endif #endif
for (i = 0; i < (rp->lnt >> 2); i++) { for (i = 0; i < (rp->lnt >> 2); i++) {
if (Map_ReadW (rp->ba + (i << 2), 4, d, MAP)) { if (Map_ReadW (rp->ba + (i << 2), 4, d)) {
fprintf (st, " %3d: non-existent memory\n", i); fprintf (st, " %3d: non-existent memory\n", i);
break; } break; }
desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);

View file

@ -25,6 +25,7 @@
ry RX211/RXV21/RX02 floppy disk ry RX211/RXV21/RX02 floppy disk
30-Sep-04 RMS Revised Unibus interface
21-Mar-04 RMS Added VAX support 21-Mar-04 RMS Added VAX support
29-Dec-03 RMS Added RXV21 support 29-Dec-03 RMS Added RXV21 support
19-May-03 RMS Revised for new conditional compilation scheme 19-May-03 RMS Revised for new conditional compilation scheme
@ -372,8 +373,8 @@ case FEXFR: /* transfer */
break; } break; }
if (func == RYCS_FILL) { /* fill? read */ if (func == RYCS_FILL) { /* fill? read */
for (i = 0; i < RY_NUMBY; i++) rx2xb[i] = 0; for (i = 0; i < RY_NUMBY; i++) rx2xb[i] = 0;
t = Map_ReadB (ba, ry_wc << 1, rx2xb, MAP); } t = Map_ReadB (ba, ry_wc << 1, rx2xb); }
else t = Map_WriteB (ba, ry_wc << 1, rx2xb, MAP); else t = Map_WriteB (ba, ry_wc << 1, rx2xb);
ry_wc = t >> 1; /* adjust wc */ ry_wc = t >> 1; /* adjust wc */
ry_done (t? RYES_NXM: 0, 0); /* done */ ry_done (t? RYES_NXM: 0, 0); /* done */
break; break;
@ -428,7 +429,7 @@ case SDCNF: /* confirm set density */
break; break;
case SDXFR: /* erase disk */ case SDXFR: /* erase disk */
for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0; for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0;
uptr->hwmark = uptr->capac; uptr->hwmark = (uint32) uptr->capac;
if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN; if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN;
else uptr->flags = uptr->flags & ~UNIT_DEN; else uptr->flags = uptr->flags & ~UNIT_DEN;
ry_done (0, 0); ry_done (0, 0);
@ -452,7 +453,7 @@ case ESXFR:
((ry_unit[0].flags & UNIT_DEN)? 0020: 0) | ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) |
((ry_csr & RYCS_DEN)? 0001: 0); ((ry_csr & RYCS_DEN)? 0001: 0);
estat[7] = uptr->TRACK; estat[7] = uptr->TRACK;
t = Map_WriteB (ba, 8, estat, MAP); /* DMA to memory */ t = Map_WriteB (ba, 8, estat); /* DMA to memory */
ry_done (t? RYES_NXM: 0, 0); /* done */ ry_done (t? RYES_NXM: 0, 0); /* done */
break; break;

View file

@ -24,8 +24,9 @@
in this Software without prior written authorization from Robert M Supnik. in this Software without prior written authorization from Robert M Supnik.
tti,tto DL11 terminal input/output tti,tto DL11 terminal input/output
clk KW11L line frequency clock clk KW11L (and other) line frequency clock
11-Oct-04 RMS Added clock model dependencies
28-May-04 RMS Removed SET TTI CTRL-C 28-May-04 RMS Removed SET TTI CTRL-C
29-Dec-03 RMS Added console backpressure support 29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
@ -65,11 +66,15 @@
extern int32 int_req[IPL_HLVL]; extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32]; extern int32 int_vec[IPL_HLVL][32];
extern int32 cpu_type;
int32 tti_csr = 0; /* control/status */ int32 tti_csr = 0; /* control/status */
int32 tto_csr = 0; /* control/status */ int32 tto_csr = 0; /* control/status */
int32 clk_csr = 0; /* control/status */ int32 clk_csr = 0; /* control/status */
int32 clk_tps = 60; /* ticks/second */ int32 clk_tps = 60; /* ticks/second */
int32 clk_default = 60; /* default ticks/second */
int32 clk_fie = 0; /* force IE = 1 */
int32 clk_fnxm = 0; /* force NXM on reg */
int32 tmxr_poll = CLK_DELAY; /* term mux poll */ int32 tmxr_poll = CLK_DELAY; /* term mux poll */
int32 tmr_poll = CLK_DELAY; /* timer poll */ int32 tmr_poll = CLK_DELAY; /* timer poll */
@ -85,6 +90,7 @@ t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat clk_rd (int32 *data, int32 PA, int32 access); t_stat clk_rd (int32 *data, int32 PA, int32 access);
t_stat clk_wr (int32 data, int32 PA, int32 access); t_stat clk_wr (int32 data, int32 PA, int32 access);
t_stat clk_svc (UNIT *uptr); t_stat clk_svc (UNIT *uptr);
int32 clk_inta (void);
t_stat clk_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr);
t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
@ -175,7 +181,7 @@ DEVICE tto_dev = {
*/ */
DIB clk_dib = { IOBA_CLK, IOLN_CLK, &clk_rd, &clk_wr, DIB clk_dib = { IOBA_CLK, IOLN_CLK, &clk_rd, &clk_wr,
1, IVCL (CLK), VEC_CLK, { NULL } }; 1, IVCL (CLK), VEC_CLK, { &clk_inta } };
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 8000 }; UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 8000 };
@ -185,7 +191,10 @@ REG clk_reg[] = {
{ FLDATA (DONE, clk_csr, CSR_V_DONE) }, { FLDATA (DONE, clk_csr, CSR_V_DONE) },
{ FLDATA (IE, clk_csr, CSR_V_IE) }, { FLDATA (IE, clk_csr, CSR_V_IE) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO }, { DRDATA (TPS, clk_tps, 16), PV_LEFT + REG_HRO },
{ DRDATA (DEFTPS, clk_default, 16), PV_LEFT + REG_HRO },
{ FLDATA (FIE, clk_fie, 0), REG_HIDDEN },
{ FLDATA (FNXM, clk_fnxm, 0), REG_HIDDEN },
{ NULL } }; { NULL } };
MTAB clk_mod[] = { MTAB clk_mod[] = {
@ -334,20 +343,32 @@ tto_unit.flags = (tto_unit.flags & ~UNIT_8B) | val;
return SCPE_OK; return SCPE_OK;
} }
/* The line time clock has a few twists and turns through the history of 11's
LSI-11 no CSR
LSI-11/23 (KDF11A) no CSR
PDP-11/23+ (KDF11B) no monitor bit
PDP-11/24 (KDF11U) monitor bit clears on IAK
*/
/* Clock I/O address routines */ /* Clock I/O address routines */
t_stat clk_rd (int32 *data, int32 PA, int32 access) t_stat clk_rd (int32 *data, int32 PA, int32 access)
{ {
*data = clk_csr & CLKCSR_IMP; if (clk_fnxm) return SCPE_NXM; /* not there??? */
if (CPUT (HAS_LTCM)) *data = clk_csr & CLKCSR_IMP; /* monitor bit? */
else *data = clk_csr & (CLKCSR_IMP & ~CSR_DONE); /* no, just IE */
return SCPE_OK; return SCPE_OK;
} }
t_stat clk_wr (int32 data, int32 PA, int32 access) t_stat clk_wr (int32 data, int32 PA, int32 access)
{ {
if (clk_fnxm) return SCPE_NXM; /* not there??? */
if (PA & 1) return SCPE_OK; if (PA & 1) return SCPE_OK;
clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW);
if ((data & CSR_DONE) == 0) clk_csr = clk_csr & ~CSR_DONE; if (CPUT (HAS_LTCM) && ((data & CSR_DONE) == 0)) /* monitor bit? */
if (((clk_csr & CSR_IE) == 0) || /* unless IE+DONE */ clk_csr = clk_csr & ~CSR_DONE; /* clr if zero */
if ((((clk_csr & CSR_IE) == 0) && !clk_fie) || /* unless IE+DONE */
((clk_csr & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */ ((clk_csr & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */
return SCPE_OK; return SCPE_OK;
} }
@ -359,7 +380,7 @@ t_stat clk_svc (UNIT *uptr)
int32 t; int32 t;
clk_csr = clk_csr | CSR_DONE; /* set done */ clk_csr = clk_csr | CSR_DONE; /* set done */
if (clk_csr & CSR_IE) SET_INT (CLK); if ((clk_csr & CSR_IE) || clk_fie) SET_INT (CLK);
t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */ sim_activate (&clk_unit, t); /* reactivate unit */
tmr_poll = t; /* set timer poll */ tmr_poll = t; /* set timer poll */
@ -367,10 +388,21 @@ tmxr_poll = t; /* set mux poll */
return SCPE_OK; return SCPE_OK;
} }
/* Clock interrupt acknowledge */
int32 clk_inta (void)
{
if (CPUT (CPUT_24)) clk_csr = clk_csr & ~CSR_DONE;
return clk_dib.vec;
}
/* Clock reset */ /* Clock reset */
t_stat clk_reset (DEVICE *dptr) t_stat clk_reset (DEVICE *dptr)
{ {
if (CPUT (HAS_LTCR)) clk_fie = clk_fnxm = 0; /* reg there? */
else clk_fie = clk_fnxm = 1; /* no, BEVENT */
clk_tps = clk_default; /* set default tps */
clk_csr = CSR_DONE; /* set done */ clk_csr = CSR_DONE; /* set done */
CLR_INT (CLK); CLR_INT (CLK);
sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ sim_activate (&clk_unit, clk_unit.wait); /* activate unit */
@ -385,7 +417,7 @@ t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
{ {
if (cptr) return SCPE_ARG; if (cptr) return SCPE_ARG;
if ((val != 50) && (val != 60)) return SCPE_IERR; if ((val != 50) && (val != 60)) return SCPE_IERR;
clk_tps = val; clk_tps = clk_default = val;
return SCPE_OK; return SCPE_OK;
} }
@ -393,6 +425,6 @@ return SCPE_OK;
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc) t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
{ {
fprintf (st, (clk_tps == 50)? "50Hz": "60Hz"); fprintf (st, "%dHz", clk_tps);
return SCPE_OK; return SCPE_OK;
} }

View file

@ -51,7 +51,7 @@
#include "pdp11_defs.h" #include "pdp11_defs.h"
#include <ctype.h> #include <ctype.h>
extern DEVICE cpu_dev; extern DEVICE cpu_dev, sys_dev;
extern DEVICE ptr_dev, ptp_dev; extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev; extern DEVICE tti_dev, tto_dev;
extern DEVICE lpt_dev; extern DEVICE lpt_dev;
@ -61,7 +61,8 @@ extern DEVICE vh_dev;
extern DEVICE rk_dev, rl_dev; extern DEVICE rk_dev, rl_dev;
extern DEVICE hk_dev; extern DEVICE hk_dev;
extern DEVICE rx_dev, ry_dev; extern DEVICE rx_dev, ry_dev;
extern DEVICE rp_dev; extern DEVICE mba0_dev, mba1_dev;
extern DEVICE rp_dev, tu_dev;
extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
extern DEVICE dt_dev; extern DEVICE dt_dev;
extern DEVICE tm_dev, ts_dev; extern DEVICE tm_dev, ts_dev;
@ -91,6 +92,9 @@ int32 sim_emax = 4;
DEVICE *sim_devices[] = { DEVICE *sim_devices[] = {
&cpu_dev, &cpu_dev,
&sys_dev,
&mba0_dev,
&mba1_dev,
&ptr_dev, &ptr_dev,
&ptp_dev, &ptp_dev,
&tti_dev, &tti_dev,
@ -114,6 +118,7 @@ DEVICE *sim_devices[] = {
&tm_dev, &tm_dev,
&ts_dev, &ts_dev,
&tq_dev, &tq_dev,
&tu_dev,
&xq_dev, &xq_dev,
&xqb_dev, &xqb_dev,
&xu_dev, &xu_dev,
@ -335,7 +340,7 @@ static const char *opcode[] = {
"MOV","CMP","BIT","BIC", "MOV","CMP","BIT","BIC",
"BIS","ADD", "BIS","ADD",
"MUL","DIV","ASH","ASHC", "MUL","DIV","ASH","ASHC",
"XOR", "XOR",
"FADD","FSUB","FMUL","FDIV", "FADD","FSUB","FMUL","FDIV",
"L2DR", "L2DR",
"MOVC","MOVRC","MOVTC", "MOVC","MOVRC","MOVTC",

View file

@ -25,6 +25,7 @@
tc TC11/TU56 DECtape tc TC11/TU56 DECtape
30-Sep-04 RMS Revised Unibus interface
25-Jan-04 RMS Revised for device debug support 25-Jan-04 RMS Revised for device debug support
09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR
29-Dec-03 RMS Changed initial status to disabled (in Qbus system) 29-Dec-03 RMS Changed initial status to disabled (in Qbus system)
@ -737,7 +738,8 @@ int32 dir = mot & DTS_DIR;
int32 fnc = DTS_GETFNC (uptr->STATE); int32 fnc = DTS_GETFNC (uptr->STATE);
int32 *fbuf = uptr->filebuf; int32 *fbuf = uptr->filebuf;
int32 blk, wrd, relpos, dat; int32 blk, wrd, relpos, dat;
uint32 ba, ma, mma; uint32 ba, ma;
uint16 wbuf;
/* Motion cases /* Motion cases
@ -799,15 +801,12 @@ case DTS_OFR: /* off reel */
case FNC_READ: /* read */ case FNC_READ: /* read */
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
if (!dt_substate) { /* !wc ovf? */ if (!dt_substate) { /* !wc ovf? */
tcwc = tcwc & DMASK; /* incr MA, WC */
tcba = tcba & DMASK;
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */ ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (!Map_Addr (ma, &mma) || /* map addr */ ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
!ADDR_IS_MEM (mma)) { /* nx mem? */ tcdt = wbuf = fbuf[ba] & DMASK; /* read word */
if (Map_WriteW (ma, 2, &wbuf)) { /* store, nxm? */
dt_seterr (uptr, STA_NXM); dt_seterr (uptr, STA_NXM);
break; } break; }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
M[mma >> 1] = tcdt = fbuf[ba] & DMASK; /* read word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */ tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK; tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm); if (tcba <= 1) tccm = CSR_INCMEX (tccm);
@ -835,11 +834,10 @@ case FNC_WRIT: /* write */
if (dt_substate) tcdt = 0; /* wc ovf? fill */ if (dt_substate) tcdt = 0; /* wc ovf? fill */
else { else {
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */ ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (!Map_Addr (ma, &mma) || /* map addr */ if (Map_ReadW (ma, 2, &wbuf)) { /* fetch word */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM); dt_seterr (uptr, STA_NXM);
break; } break; }
else tcdt = M[mma >> 1]; /* get word */ tcdt = wbuf; /* get word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */ tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK; tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm); } if (tcba <= 1) tccm = CSR_INCMEX (tccm); }

View file

@ -25,6 +25,7 @@
tm TM11/TU10 magtape tm TM11/TU10 magtape
30-Sep-04 RMS Revised Unibus interface
25-Jan-04 RMS Revised for device debug support 25-Jan-04 RMS Revised for device debug support
29-Dec-03 RMS Added 18b Qbus support 29-Dec-03 RMS Added 18b Qbus support
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
@ -398,7 +399,7 @@ case MTC_READ: /* read */
break; } break; }
if (tbc > cbc) tm_sta = tm_sta | STA_RLE; /* wrong size? */ if (tbc > cbc) tm_sta = tm_sta | STA_RLE; /* wrong size? */
if (tbc < cbc) cbc = tbc; /* use smaller */ if (tbc < cbc) cbc = tbc; /* use smaller */
if (t = Map_WriteB (xma, cbc, tmxb, MAP)) { /* copy buf to mem */ if (t = Map_WriteB (xma, cbc, tmxb)) { /* copy buf to mem */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; } /* adj byte cnt */ cbc = cbc - t; } /* adj byte cnt */
xma = (xma + cbc) & 0777777; /* inc bus addr */ xma = (xma + cbc) & 0777777; /* inc bus addr */
@ -407,7 +408,7 @@ case MTC_READ: /* read */
case MTC_WRITE: /* write */ case MTC_WRITE: /* write */
case MTC_WREXT: /* write ext gap */ case MTC_WREXT: /* write ext gap */
if (t = Map_ReadB (xma, cbc, tmxb, MAP)) { /* copy mem to buf */ if (t = Map_ReadB (xma, cbc, tmxb)) { /* copy mem to buf */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; /* adj byte cnt */ cbc = cbc - t; /* adj byte cnt */
if (cbc == 0) break; } /* no xfr? done */ if (cbc == 0) break; } /* no xfr? done */
@ -530,7 +531,7 @@ for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */
(sim_tape_bot (uptr)? STA_BOT: 0) | (sim_tape_bot (uptr)? STA_BOT: 0) |
(sim_tape_wrp (uptr)? STA_WLK: 0); (sim_tape_wrp (uptr)? STA_WLK: 0);
else uptr->USTAT = 0; } else uptr->USTAT = 0; }
if (tmxb == NULL) tmxb = calloc (MT_MAXFR, sizeof (unsigned int8)); if (tmxb == NULL) tmxb = calloc (MT_MAXFR, sizeof (uint8));
if (tmxb == NULL) return SCPE_MEM; if (tmxb == NULL) return SCPE_MEM;
return SCPE_OK; return SCPE_OK;
} }

View file

@ -25,6 +25,7 @@
tq TQK50 tape controller tq TQK50 tape controller
30-Sep-04 RMS Revised Unibus interface
12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley) 12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley)
18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath) 18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath)
26-Mar-04 RMS Fixed warnings with -std=c99 26-Mar-04 RMS Fixed warnings with -std=c99
@ -45,14 +46,16 @@
#elif defined (VM_VAX) /* VAX version */ #elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h" #include "vax_defs.h"
extern int32 int_req[IPL_HLVL]; #if (UNIBUS)
extern int32 int_vec[IPL_HLVL][32]; #define INIT_TYPE TQU_TYPE
#else
#define INIT_TYPE TQ5_TYPE
#endif
#else /* PDP-11 version */ #else /* PDP-11 version */
#include "pdp11_defs.h" #include "pdp11_defs.h"
extern int32 int_req[IPL_HLVL]; #define INIT_TYPE TQ5_TYPE
extern int32 int_vec[IPL_HLVL][32]; extern int32 cpu_opt;
extern int32 cpu_18b, cpu_ubm;
#endif #endif
#include "pdp11_uqssp.h" #include "pdp11_uqssp.h"
@ -236,7 +239,7 @@ int32 tq_itime = 200; /* init time, except */
int32 tq_itime4 = 10; /* stage 4 */ int32 tq_itime4 = 10; /* stage 4 */
int32 tq_qtime = 200; /* queue time */ int32 tq_qtime = 200; /* queue time */
int32 tq_xtime = 500; /* transfer time */ int32 tq_xtime = 500; /* transfer time */
int32 tq_typ = TQ5_TYPE; /* device type */ int32 tq_typ = INIT_TYPE; /* device type */
/* Command table - legal modifiers (low 16b) and flags (high 16b) */ /* Command table - legal modifiers (low 16b) and flags (high 16b) */
@ -506,7 +509,7 @@ else base = tq_comm + SA_COMM_CI;
lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base; /* comm lnt */ lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base; /* comm lnt */
if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */ if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */
for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */ for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */
if (Map_WriteW (base, lnt, zero, MAP)) /* zero comm area */ if (Map_WriteW (base, lnt, zero)) /* zero comm area */
return tq_fatal (PE_QWE); /* error? */ return tq_fatal (PE_QWE); /* error? */
tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */ tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */
((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER); ((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER);
@ -1062,7 +1065,7 @@ case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */
wbc = bc; } /* set working bc */ wbc = bc; } /* set working bc */
else wbc = tbc; else wbc = tbc;
if (cmd == OP_RD) { /* read? */ if (cmd == OP_RD) { /* read? */
if (t = Map_WriteB (ba, wbc, tqxb, MAP)) { /* store, nxm? */ if (t = Map_WriteB (ba, wbc, tqxb)) { /* store, nxm? */
PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */ PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */
if (tq_hbe (uptr, ba + wbc - t)) /* post err log */ if (tq_hbe (uptr, ba + wbc - t)) /* post err log */
tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc);
@ -1078,7 +1081,7 @@ case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */
else { else {
mba = ba + i; mba = ba + i;
dby = tqxb[i]; } dby = tqxb[i]; }
if (Map_ReadB (mba, 1, &mby, MAP)) { /* fetch, nxm? */ if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */
PUTP32 (pkt, RW_BCL, i); /* adj bc */ PUTP32 (pkt, RW_BCL, i); /* adj bc */
if (tq_hbe (uptr, mba)) /* post err log */ if (tq_hbe (uptr, mba)) /* post err log */
tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc);
@ -1094,7 +1097,7 @@ case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */
break; break;
case OP_WR: /* write */ case OP_WR: /* write */
if (t = Map_ReadB (ba, bc, tqxb, MAP)) { /* fetch buf, nxm? */ if (t = Map_ReadB (ba, bc, tqxb)) { /* fetch buf, nxm? */
PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */ PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */
if (tq_hbe (uptr, ba + bc - t)) /* post err log */ if (tq_hbe (uptr, ba + bc - t)) /* post err log */
tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc);
@ -1481,7 +1484,7 @@ if ((desc & UQ_DESC_OWN) == 0) { /* none */
if (!tq_deqf (pkt)) return ERR; /* get cmd pkt */ if (!tq_deqf (pkt)) return ERR; /* get cmd pkt */
tq_hat = 0; /* dsbl hst timer */ tq_hat = 0; /* dsbl hst timer */
addr = desc & UQ_ADDR; /* get Q22 addr */ addr = desc & UQ_ADDR; /* get Q22 addr */
if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d, MAP)) if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d))
return tq_fatal (PE_PRE); /* read pkt */ return tq_fatal (PE_PRE); /* read pkt */
return tq_putdesc (&tq_cq, desc); /* release desc */ return tq_putdesc (&tq_cq, desc); /* release desc */
} }
@ -1516,7 +1519,7 @@ if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */
cr = (tq_credits >= 14)? 14: tq_credits; /* max 14 credits */ cr = (tq_credits >= 14)? 14: tq_credits; /* max 14 credits */
tq_credits = tq_credits - cr; /* decr credits */ tq_credits = tq_credits - cr; /* decr credits */
tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); } tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); }
if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d, MAP)) if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d))
return tq_fatal (PE_PWE); /* write pkt */ return tq_fatal (PE_PWE); /* write pkt */
tq_enqh (&tq_freq, pkt); /* pkt is free */ tq_enqh (&tq_freq, pkt); /* pkt is free */
tq_pbsy = tq_pbsy - 1; /* decr busy cnt */ tq_pbsy = tq_pbsy - 1; /* decr busy cnt */
@ -1531,7 +1534,7 @@ t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc)
uint32 addr = ring->ba + ring->idx; uint32 addr = ring->ba + ring->idx;
uint16 d[2]; uint16 d[2];
if (Map_ReadW (addr, 4, d, MAP)) /* fetch desc */ if (Map_ReadW (addr, 4, d)) /* fetch desc */
return tq_fatal (PE_QRE); /* err? dead */ return tq_fatal (PE_QRE); /* err? dead */
*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);
return OK; return OK;
@ -1551,13 +1554,13 @@ uint16 d[2];
d[0] = newd & 0xFFFF; /* 32b to 16b */ d[0] = newd & 0xFFFF; /* 32b to 16b */
d[1] = (newd >> 16) & 0xFFFF; d[1] = (newd >> 16) & 0xFFFF;
if (Map_WriteW (addr, 4, d, MAP)) /* store desc */ if (Map_WriteW (addr, 4, d)) /* store desc */
return tq_fatal (PE_QWE); /* err? dead */ return tq_fatal (PE_QWE); /* err? dead */
if (desc & UQ_DESC_F) { /* was F set? */ if (desc & UQ_DESC_F) { /* was F set? */
if (ring->lnt <= 4) tq_ring_int (ring); /* lnt = 1? intr */ if (ring->lnt <= 4) tq_ring_int (ring); /* lnt = 1? intr */
else { prva = ring->ba + /* prv desc */ else { prva = ring->ba + /* prv desc */
((ring->idx - 4) & (ring->lnt - 1)); ((ring->idx - 4) & (ring->lnt - 1));
if (Map_ReadW (prva, 4, d, MAP)) /* read prv */ if (Map_ReadW (prva, 4, d)) /* read prv */
return tq_fatal (PE_QRE); return tq_fatal (PE_QRE);
prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16);
if (prvd & UQ_DESC_OWN) tq_ring_int (ring); } } if (prvd & UQ_DESC_OWN) tq_ring_int (ring); } }
@ -1652,7 +1655,7 @@ void tq_ring_int (struct uq_ring *ring)
uint32 iadr = tq_comm + ring->ioff; /* addr intr wd */ uint32 iadr = tq_comm + ring->ioff; /* addr intr wd */
uint16 flag = 1; uint16 flag = 1;
Map_WriteW (iadr, 2, &flag, MAP); /* write flag */ Map_WriteW (iadr, 2, &flag); /* write flag */
if (tq_dib.vec) SET_INT (TQ); /* if enb, intr */ if (tq_dib.vec) SET_INT (TQ); /* if enb, intr */
return; return;
} }
@ -1712,7 +1715,8 @@ UNIT *uptr;
tq_csta = CST_S1; /* init stage 1 */ tq_csta = CST_S1; /* init stage 1 */
tq_s1dat = 0; /* no S1 data */ tq_s1dat = 0; /* no S1 data */
tq_dib.vec = 0; /* no vector */ tq_dib.vec = 0; /* no vector */
tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ if (UNIBUS) tq_sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; /* Unibus? */
else tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */
tq_cflgs = CF_RPL; /* ctrl flgs off */ tq_cflgs = CF_RPL; /* ctrl flgs off */
tq_htmo = TQ_DHTMO; /* default timeout */ tq_htmo = TQ_DHTMO; /* default timeout */
tq_hat = tq_htmo; /* default timer */ tq_hat = tq_htmo; /* default timer */
@ -1870,6 +1874,7 @@ t_stat tq_boot (int32 unitno, DEVICE *dptr)
{ {
return SCPE_NOFNC; return SCPE_NOFNC;
} }
#endif #endif
/* Special show commands */ /* Special show commands */
@ -1887,7 +1892,7 @@ fprintf (st, "ring, base = %x, index = %d, length = %d\n",
rp->ba, rp->idx >> 2, rp->lnt >> 2); rp->ba, rp->idx >> 2, rp->lnt >> 2);
#endif #endif
for (i = 0; i < (rp->lnt >> 2); i++) { for (i = 0; i < (rp->lnt >> 2); i++) {
if (Map_ReadW (rp->ba + (i << 2), 4, d, MAP)) { if (Map_ReadW (rp->ba + (i << 2), 4, d)) {
fprintf (st, " %3d: non-existent memory\n", i); fprintf (st, " %3d: non-existent memory\n", i);
break; } break; }
desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); desc = ((uint32) d[0]) | (((uint32) d[1]) << 16);

View file

@ -25,6 +25,7 @@
ts TS11/TSV05 magtape ts TS11/TSV05 magtape
30-Sep-04 RMS Revised Unibus interface
25-Jan-04 RMS Revised for device debug support 25-Jan-04 RMS Revised for device debug support
19-May-03 RMS Revised for new conditional compilation scheme 19-May-03 RMS Revised for new conditional compilation scheme
25-Apr-03 RMS Revised for extended file support 25-Apr-03 RMS Revised for extended file support
@ -82,30 +83,16 @@
#elif defined (VM_VAX) /* VAX version */ #elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h" #include "vax_defs.h"
#define TS_DIS 0 /* on by default */ #define TS_DIS 0 /* on by default */
#define ADDRTEST 0177700
#define DMASK 0xFFFF #define DMASK 0xFFFF
extern int32 ReadB (uint32 pa);
extern void WriteB (uint32 pa, int32 val);
extern int32 ReadW (uint32 pa);
extern void WriteW (uint32 pa, int32 val);
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
#else /* PDP-11 version */ #else /* PDP-11 version */
#include "pdp11_defs.h" #include "pdp11_defs.h"
#define TS_DIS DEV_DIS /* off by default */ #define TS_DIS DEV_DIS /* off by default */
#define ADDRTEST (UNIBUS? 0177774: 0177700) extern int32 cpu_opt;
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 #endif
#include "sim_tape.h" #include "sim_tape.h"
#define ADDRTEST (UNIBUS? 0177774: 0177700)
/* TSBA/TSDB - 17772520: base address/data buffer register /* TSBA/TSDB - 17772520: base address/data buffer register
@ -268,6 +255,7 @@ extern int32 cpu_18b, cpu_ubm;
#define WCHX_HDS 0000040 /* high density */ #define WCHX_HDS 0000040 /* high density */
#define MAX(a,b) (((a) >= (b))? (a): (b)) #define MAX(a,b) (((a) >= (b))? (a): (b))
#define MAX_PLNT 8 /* max pkt length */
extern int32 int_req[IPL_HLVL]; extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32]; extern int32 int_vec[IPL_HLVL][32];
@ -286,6 +274,7 @@ int32 ts_ownm = 0; /* tape owns msg */
int32 ts_qatn = 0; /* queued attn */ int32 ts_qatn = 0; /* queued attn */
int32 ts_bcmd = 0; /* boot cmd */ int32 ts_bcmd = 0; /* boot cmd */
int32 ts_time = 10; /* record latency */ int32 ts_time = 10; /* record latency */
static uint16 cpy_buf[MAX_PLNT]; /* copy buffer */
DEVICE ts_dev; DEVICE ts_dev;
t_stat ts_rd (int32 *data, int32 PA, int32 access); t_stat ts_rd (int32 *data, int32 PA, int32 access);
@ -383,8 +372,7 @@ return SCPE_OK;
t_stat ts_wr (int32 data, int32 PA, int32 access) t_stat ts_wr (int32 data, int32 PA, int32 access)
{ {
int32 i; int32 i, t;
uint32 pa;
switch ((PA >> 1) & 01) { /* decode PA<1> */ switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TSDB */ case 0: /* TSDB */
@ -398,13 +386,13 @@ case 0: /* TSDB */
msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLCLR); /* clr, upd xs0 */ msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLCLR); /* clr, upd xs0 */
msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */ msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */
CLR_INT (TS); /* clr int req */ CLR_INT (TS); /* clr int req */
for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */ t = Map_ReadW (tsba, CMD_PLNT << 1, cpy_buf); /* read cmd pkt */
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa)) tsba = tsba + ((CMD_PLNT << 1) - t); /* incr tsba */
tscmdp[i] = ReadW (pa); if (t) { /* nxm? */
else { ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);
ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); return SCPE_OK; }
return SCPE_OK; } for (i = 0; i < CMD_PLNT; i++) /* copy packet */
tsba = tsba + 2; } /* incr tsba */ tscmdp[i] = cpy_buf[i];
ts_ownc = ts_ownm = 1; /* tape owns all */ ts_ownc = ts_ownm = 1; /* tape owns all */
sim_activate (&ts_unit, ts_time); /* activate */ sim_activate (&ts_unit, ts_time); /* activate */
break; break;
@ -536,8 +524,8 @@ return 0;
int32 ts_readf (UNIT *uptr, uint32 fc) int32 ts_readf (UNIT *uptr, uint32 fc)
{ {
t_stat st; t_stat st;
t_mtrlnt i, tbc, wbc; t_mtrlnt i, t, tbc, wbc;
uint32 wa, pa; int32 wa;
msgrfc = fc; msgrfc = fc;
st = sim_tape_rdrecf (uptr, tsxb, &tbc, MT_MAXFR); /* read rec fwd */ st = sim_tape_rdrecf (uptr, tsxb, &tbc, MT_MAXFR); /* read rec fwd */
@ -546,15 +534,22 @@ if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl; /* buf addr */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */
wbc = (tbc > fc)? fc: tbc; /* cap buf size */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
for (i = 0; i < wbc; i++) { /* copy buffer */ if (cmdhdr & CMD_SWP) { /* swapped? */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ for (i = 0; i < wbc; i++) { /* copy buffer */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ wa = tsba ^ 1; /* apply OPP */
WriteB (pa, tsxb[i]); /* no, store */ if (Map_WriteB (tsba, 1, &tsxb[i])) { /* store byte, nxm? */
else { tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); }
tsba = tsba + 1;
msgrfc = (msgrfc - 1) & DMASK; }
}
else { t = Map_WriteB (tsba, wbc, tsxb); /* store record */
tsba = tsba + (wbc - t); /* update tsba */
if (t) { /* nxm? */
tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */ tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); } return (XTC (XS0_RLS, TC4)); }
tsba = tsba + 1; msgrfc = (msgrfc - (wbc - t)) & DMASK; /* update fc */
msgrfc = (msgrfc - 1) & DMASK; } }
if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */ if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */
if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */ if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */
return 0; return 0;
@ -564,7 +559,7 @@ int32 ts_readr (UNIT *uptr, uint32 fc)
{ {
t_stat st; t_stat st;
t_mtrlnt i, tbc, wbc; t_mtrlnt i, tbc, wbc;
uint32 wa, pa; int32 wa;
msgrfc = fc; msgrfc = fc;
st = sim_tape_rdrecr (uptr, tsxb, &tbc, MT_MAXFR); /* read rec rev */ st = sim_tape_rdrecr (uptr, tsxb, &tbc, MT_MAXFR); /* read rec rev */
@ -576,9 +571,7 @@ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
for (i = wbc; i > 0; i--) { /* copy buffer */ for (i = wbc; i > 0; i--) { /* copy buffer */
tsba = tsba - 1; tsba = tsba - 1;
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ if (Map_WriteB (wa, 1, &tsxb[i - 1])) { /* store byte, nxm? */
WriteB (pa, tsxb[i - 1]); /* no, store */
else {
tssr = ts_updtssr (tssr | TSSR_NXM); tssr = ts_updtssr (tssr | TSSR_NXM);
return (XTC (XS0_RLS, TC4)); } return (XTC (XS0_RLS, TC4)); }
msgrfc = (msgrfc - 1) & DMASK; } msgrfc = (msgrfc - 1) & DMASK; }
@ -589,21 +582,27 @@ return 0;
int32 ts_write (UNIT *uptr, int32 fc) int32 ts_write (UNIT *uptr, int32 fc)
{ {
int32 i; int32 i, t;
uint32 wa, pa; uint32 wa;
t_stat st; t_stat st;
msgrfc = fc; msgrfc = fc;
if (fc == 0) fc = 0200000; /* byte count */ if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl; /* buf addr */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */
for (i = 0; i < fc; i++) { /* copy mem to buf */ if (cmdhdr & CMD_SWP) { /* swapped? */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ for (i = 0; i < fc; i++) { /* copy mem to buf */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ wa = tsba ^ 1; /* apply OPP */
tsxb[i] = ReadB (pa); /* no, store */ if (Map_ReadB (wa, 1, &tsxb[i])) { /* fetch byte, nxm? */
else {
tssr = ts_updtssr (tssr | TSSR_NXM); tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; } return TC5; }
tsba = tsba + 1; } tsba = tsba + 1; }
}
else { t = Map_ReadB (tsba, fc, tsxb); /* fetch record */
tsba = tsba + (fc - t); /* update tsba */
if (t) { /* nxm? */
tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; }
}
if (st = sim_tape_wrrecf (uptr, tsxb, fc)) /* write rec, err? */ if (st = sim_tape_wrrecf (uptr, tsxb, fc)) /* write rec, err? */
return ts_map_status (st); /* return status */ return ts_map_status (st); /* return status */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
@ -625,8 +624,7 @@ return XTC (XS0_TMK, TC0);
t_stat ts_svc (UNIT *uptr) t_stat ts_svc (UNIT *uptr)
{ {
int32 i, fnc, mod, st0, st1; int32 i, t, bc, fnc, mod, st0, st1;
uint32 pa;
static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */ static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */
0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */ 0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */
@ -638,6 +636,11 @@ static const int32 fnc_flg[CMD_N_FNC] = {
FLG_MO, FLG_MO+FLG_WR, FLG_MO, 0, 0, 0, 0, 0, FLG_MO, FLG_MO+FLG_WR, FLG_MO, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */
0, 0, 0, 0, 0, 0, 0, 0 }; /* 30 - 37 */ 0, 0, 0, 0, 0, 0, 0, 0 }; /* 30 - 37 */
static const char *fnc_name[CMD_N_FNC] = {
"0", "READ", "2", "3", "WCHR", "WRITE", "WSSM", "7",
"POS", "FMT", "CTL", "INIT", "14", "15", "16", "GSTA",
"20", "21", "22", "23", "24", "25", "26", "27",
"30", "31", "32", "33", "34", "35", "36", "37" };
if (ts_bcmd) { /* boot? */ if (ts_bcmd) { /* boot? */
ts_bcmd = 0; /* clear flag */ ts_bcmd = 0; /* clear flag */
@ -659,8 +662,8 @@ if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */
fnc = GET_FNC (cmdhdr); /* get fnc+mode */ fnc = GET_FNC (cmdhdr); /* get fnc+mode */
mod = GET_MOD (cmdhdr); mod = GET_MOD (cmdhdr);
if (DEBUG_PRS (ts_dev)) if (DEBUG_PRS (ts_dev))
fprintf (sim_deb, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, pos=%d\n", fprintf (sim_deb, ">>TS: cmd=%s, mod=%o, buf=%o, lnt=%d, pos=%d\n",
fnc, mod, cmdadl, cmdlnt, ts_unit.pos); fnc_name[fnc], mod, cmdadl, cmdlnt, ts_unit.pos);
if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */ if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */
ts_endcmd (TC3, 0, 0); /* error */ ts_endcmd (TC3, 0, 0); /* error */
return SCPE_OK; } return SCPE_OK; }
@ -705,13 +708,14 @@ case FNC_WCHR: /* write char */
ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0); ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0);
break; } break; }
tsba = (cmdadh << 16) | cmdadl; tsba = (cmdadh << 16) | cmdadl;
for (i = 0; (i < WCH_PLNT) && (i < (cmdlnt / 2)); i++) { bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1;
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa)) t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */
tswchp[i] = ReadW (pa); tsba = tsba + (bc - t); /* inc tsba */
else { if (t) { /* nxm? */
ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0);
return SCPE_OK; } return SCPE_OK; }
tsba = tsba + 2; } for (i = 0; i < (bc / 2); i++) /* copy packet */
tswchp[i] = cpy_buf[i];
if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) || if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) ||
(wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0); (wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0);
else { else {
@ -859,8 +863,7 @@ return;
void ts_endcmd (int32 tc, int32 xs0, int32 msg) void ts_endcmd (int32 tc, int32 xs0, int32 msg)
{ {
int32 i; int32 i, t;
uint32 pa;
msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */ msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */
if (wchxopt & WCHX_HDS) msgxs4 = msgxs4 | XS4_HDS; /* update XS4 */ if (wchxopt & WCHX_HDS) msgxs4 = msgxs4 | XS4_HDS; /* update XS4 */
@ -868,14 +871,14 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */
msghdr = msg; msghdr = msg;
msglnt = wchlnt - 4; /* exclude hdr, bc */ msglnt = wchlnt - 4; /* exclude hdr, bc */
tsba = (wchadh << 16) | wchadl; tsba = (wchadh << 16) | wchadl;
for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++) { for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++)
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa)) cpy_buf[i] = (uint16) tsmsgp[i]; /* copy buffer */
WriteW (pa, tsmsgp[i]); t = Map_WriteW (tsba, i << 1, cpy_buf); /* write to mem */
else { tsba = tsba + ((i << 1) - t); /* incr tsba */
tssr = tssr | TSSR_NXM; if (t) { /* nxm? */
tc = (tc & ~TSSR_TC) | TC4; tssr = tssr | TSSR_NXM;
break; } tc = (tc & ~TSSR_TC) | TC4; }
tsba = tsba + 2; } } }
tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0)); tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0));
if (cmdhdr & CMD_IE) SET_INT (TS); if (cmdhdr & CMD_IE) SET_INT (TS);
ts_ownm = 0; ts_ownc = 0; ts_ownm = 0; ts_ownc = 0;
@ -902,7 +905,7 @@ for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0;
for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0; for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0;
msgxs0 = ts_updxs0 (XS0_VCK); msgxs0 = ts_updxs0 (XS0_VCK);
CLR_INT (TS); CLR_INT (TS);
if (tsxb == NULL) tsxb = calloc (MT_MAXFR, sizeof (unsigned int8)); if (tsxb == NULL) tsxb = calloc (MT_MAXFR, sizeof (uint8));
if (tsxb == NULL) return SCPE_MEM; if (tsxb == NULL) return SCPE_MEM;
return SCPE_OK; return SCPE_OK;
} }
@ -993,6 +996,7 @@ t_stat ts_boot (int32 unitno, DEVICE *dptr)
{ {
int32 i; int32 i;
extern int32 saved_PC; extern int32 saved_PC;
extern uint16 *M;
sim_tape_rewind (&ts_unit); sim_tape_rewind (&ts_unit);
for (i = 0; i < BOOT_LEN; i++) for (i = 0; i < BOOT_LEN; i++)
@ -1001,7 +1005,8 @@ M[BOOT_CSR0 >> 1] = ts_dib.ba & DMASK;
M[BOOT_CSR1 >> 1] = (ts_dib.ba & DMASK) + 02; M[BOOT_CSR1 >> 1] = (ts_dib.ba & DMASK) + 02;
saved_PC = BOOT_START; saved_PC = BOOT_START;
return SCPE_OK; return SCPE_OK;
} }
#else #else
t_stat ts_boot (int32 unitno, DEVICE *dptr) t_stat ts_boot (int32 unitno, DEVICE *dptr)

912
PDP11/pdp11_tu.c Normal file
View file

@ -0,0 +1,912 @@
/* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller
Copyright (c) 1993-2004, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
tu TM02/TM03 magtape
10-Sep-04 RMS Cloned from pdp10_tu.c
Magnetic tapes are represented as a series of variable 8b records
of the form:
32b record length in bytes - exact number, sign = error
byte 0
byte 1
:
byte n-2
byte n-1
32b record length in bytes - exact number, sign = error
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.
*/
#if defined (VM_PDP10)
#error "PDP-10 uses pdp10_tu.c!"
#elif defined (VM_PDP11)
#include "pdp11_defs.h"
#define DEV_DIS_INIT DEV_DIS
#elif defined (VM_VAX)
#include "vax_defs.h"
#define DEV_DIS_INIT 0
#if (!UNIBUS)
#error "Qbus not supported!"
#endif
#endif
#include "sim_tape.h"
#define TU_NUMFM 1 /* #formatters */
#define TU_NUMDR 8 /* #drives */
#define USTAT u3 /* unit status */
#define UDENS u4 /* unit density */
#define UD_UNK 0 /* unknown */
#define MT_MAXFR (1 << 16) /* max data buf */
#define DEV_V_TM03 (DEV_V_FFUF + 0) /* TM02/TM03 */
#define DEV_TM03 (1 << DEV_V_TM03)
#define UNIT_V_TYPE (MTUF_V_UF + 0)
#define UNIT_M_TYPE 03
#define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE)
#define UNIT_TE16 (0 << UNIT_V_TYPE)
#define UNIT_TU45 (1 << UNIT_V_TYPE)
#define UNIT_TU77 (2 << UNIT_V_TYPE)
#define GET_TYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE)
/* CS1 - offset 0 */
#define CS1_OF 0
#define CS1_GO CSR_GO /* go */
#define CS1_V_FNC 1 /* function pos */
#define CS1_M_FNC 037 /* function mask */
#define CS1_N_FNC (CS1_M_FNC + 1)
#define FNC_NOP 000 /* no operation */
#define FNC_UNLOAD 001 /* unload */
#define FNC_REWIND 003 /* rewind */
#define FNC_FCLR 004 /* formatter clear */
#define FNC_RIP 010 /* read in preset */
#define FNC_ERASE 012 /* erase tape */
#define FNC_WREOF 013 /* write tape mark */
#define FNC_SPACEF 014 /* space forward */
#define FNC_SPACER 015 /* space reverse */
#define FNC_XFER 024 /* >=? data xfr */
#define FNC_WCHKF 024 /* write check */
#define FNC_WCHKR 027 /* write check rev */
#define FNC_WRITE 030 /* write */
#define FNC_READF 034 /* read forward */
#define FNC_READR 037 /* read reverse */
#define CS1_RW 077
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
/* TUFS - formatter status - offset 1
+ indicates kept in drive status
^ indicates calculated on the fly
*/
#define FS_OF 1
#define FS_SAT 0000001 /* slave attention */
#define FS_BOT 0000002 /* ^beginning of tape */
#define FS_TMK 0000004 /* end of file */
#define FS_ID 0000010 /* ID burst detected */
#define FS_SLOW 0000020 /* slowing down NI */
#define FS_PE 0000040 /* ^PE status */
#define FS_SSC 0000100 /* slave stat change */
#define FS_RDY 0000200 /* ^formatter ready */
#define FS_FPR 0000400 /* formatter present */
#define FS_EOT 0002000 /* +end of tape */
#define FS_WRL 0004000 /* ^write locked */
#define FS_MOL 0010000 /* ^medium online */
#define FS_PIP 0020000 /* +pos in progress */
#define FS_ERR 0040000 /* ^error */
#define FS_ATA 0100000 /* attention active */
#define FS_REW 0200000 /* +rewinding */
#define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \
FS_RDY | FS_PE | FS_BOT)
/* TUER - error register - offset 2 */
#define ER_OF 2
#define ER_ILF 0000001 /* illegal func */
#define ER_ILR 0000002 /* illegal register */
#define ER_RMR 0000004 /* reg mod refused */
#define ER_MCP 0000010 /* Mbus cpar err NI */
#define ER_FER 0000020 /* format sel err */
#define ER_MDP 0000040 /* Mbus dpar err NI */
#define ER_VPE 0000100 /* vert parity err */
#define ER_CRC 0000200 /* CRC err NI */
#define ER_NSG 0000400 /* non std gap err NI */
#define ER_FCE 0001000 /* frame count err */
#define ER_ITM 0002000 /* inv tape mark NI */
#define ER_NXF 0004000 /* wlock or fnc err */
#define ER_DTE 0010000 /* time err NI */
#define ER_OPI 0020000 /* op incomplete */
#define ER_UNS 0040000 /* drive unsafe */
#define ER_DCK 0100000 /* data check NI */
/* TUMR - maintenance register - offset 03 */
#define MR_OF 3
#define MR_RW 0177637 /* read/write */
/* TUAS - attention summary - offset 4 */
#define AS_OF 4
#define AS_U0 0000001 /* unit 0 flag */
/* TUFC - offset 5 */
#define FC_OF 5
/* TUDT - drive type - offset 6 */
#define DT_OF 6
#define DT_NSA 0100000 /* not sect addr */
#define DT_TAPE 0040000 /* tape */
#define DT_PRES 0002000 /* slave present */
#define DT_TM03 0000040 /* TM03 formatter */
#define DT_OFF 0000010 /* drive off */
#define DT_TU16 0000011 /* TE16 */
#define DT_TU45 0000012 /* TU45 */
#define DT_TU77 0000014 /* TU77 */
/* TUCC - check character, read only - offset 7 */
#define CC_OF 7
#define CC_MBZ 0177000 /* must be zero */
/* TUSN - serial number - offset 8 */
#define SN_OF 8
/* TUTC - tape control register - offset 9 */
#define TC_OF 9
#define TC_V_UNIT 0 /* unit select */
#define TC_M_UNIT 07
#define TC_V_EVN 0000010 /* even parity */
#define TC_V_FMT 4 /* format select */
#define TC_M_FMT 017
#define TC_STD 014 /* standard */
#define TC_CDUMP 015 /* core dump */
#define TC_V_DEN 8 /* density select */
#define TC_M_DEN 07
#define TC_800 3 /* 800 bpi */
#define TC_1600 4 /* 1600 bpi */
#define TC_AER 0010000 /* abort on error */
#define TC_SAC 0020000 /* slave addr change */
#define TC_FCS 0040000 /* frame count status */
#define TC_ACC 0100000 /* accelerating NI */
#define TC_RW 0013777
#define TC_MBZ 0004000
#define TC_RIP ((TC_800 << TC_V_DEN) | (TC_STD << TC_V_FMT))
#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN)
#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT)
#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT)
int32 tucs1 = 0; /* control/status 1 */
int32 tufc = 0; /* frame count */
int32 tufs = 0; /* formatter status */
int32 tuer = 0; /* error status */
int32 tucc = 0; /* check character */
int32 tumr = 0; /* maint register */
int32 tutc = 0; /* tape control */
int32 tu_time = 10; /* record latency */
int32 tu_stopioe = 1; /* stop on error */
static uint8 *xbuf = NULL; /* xfer buffer */
static uint16 *wbuf = NULL;
static int32 den_test[8] = { /* valid densities */
1, 1, 1, 1, 1, 0, 0, 0 }; /* 0-3 = 800, 4 = 1600 */
static int32 fmt_test[16] = { /* fmt valid */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 };
static int32 dt_map[3] = { DT_TU16, DT_TU45, DT_TU77 };
static char *tu_fname[CS1_N_FNC] = {
"NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7",
"RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17",
"20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR",
"WRITE", "31", "32", "33", "READF", "35", "36" "READR" };
extern int32 sim_switches;
extern FILE *sim_deb;
t_stat tu_mbrd (int32 *data, int32 PA, int32 fmtr);
t_stat tu_mbwr (int32 data, int32 PA, int32 fmtr);
t_stat tu_svc (UNIT *uptr);
t_stat tu_reset (DEVICE *dptr);
t_stat tu_attach (UNIT *uptr, char *cptr);
t_stat tu_detach (UNIT *uptr);
t_stat tu_boot (int32 unitno, DEVICE *dptr);
t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat tu_go (int32 drv);
int32 tu_abort (void);
void tu_set_er (int32 flg);
void tu_clr_as (int32 mask);
void tu_update_fs (int32 flg, int32 drv);
t_stat tu_map_err (int32 drv, t_stat st);
/* TU data structures
tu_dev TU device descriptor
tu_unit TU unit list
tu_reg TU register list
tu_mod TU modifier list
*/
DIB tu_dib = { MBA_TU, 0, &tu_mbrd, &tu_mbwr,0, 0, 0, { &tu_abort } };
UNIT tu_unit[] = {
{ 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[] = {
{ GRDATA (CS1, tucs1, DEV_RDX, 6, 0) },
{ GRDATA (FC, tufc, DEV_RDX, 16, 0) },
{ GRDATA (FS, tufs, DEV_RDX, 16, 0) },
{ GRDATA (ER, tuer, DEV_RDX, 16, 0) },
{ GRDATA (CC, tucc, DEV_RDX, 16, 0) },
{ GRDATA (MR, tumr, DEV_RDX, 16, 0) },
{ GRDATA (TC, tutc, DEV_RDX, 16, 0) },
{ FLDATA (STOP_IOE, tu_stopioe, 0) },
{ DRDATA (TIME, tu_time, 24), PV_LEFT },
{ URDATA (UST, tu_unit[0].USTAT, DEV_RDX, 17, 0, TU_NUMDR, 0) },
{ URDATA (POS, tu_unit[0].pos, 10, T_ADDR_W, 0,
TU_NUMDR, PV_LEFT | REG_RO) },
{ NULL } };
MTAB tu_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "MASSBUS", "MASSBUS", NULL, &mba_show_num },
{ MTAB_XTD|MTAB_VDV, 0, "FORMATTER", "TM02",
&tu_set_fmtr, &tu_show_fmtr },
{ MTAB_XTD|MTAB_VDV, 1, NULL, "TM03",
&tu_set_fmtr, NULL },
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
{ UNIT_TYPE, UNIT_TE16, "TE16", "TE16", NULL },
{ UNIT_TYPE, UNIT_TU45, "TU45", "TU45", NULL },
{ UNIT_TYPE, UNIT_TU77, "TU77", "TU77", NULL },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ 0 } };
DEVICE tu_dev = {
"TU", tu_unit, tu_reg, tu_mod,
TU_NUMDR, 10, 31, 1, DEV_RDX, 8,
NULL, NULL, &tu_reset,
&tu_boot, &tu_attach, &tu_detach,
&tu_dib, DEV_MBUS | DEV_UBUS | DEV_QBUS | DEV_DEBUG | DEV_DISABLE | DEV_DIS_INIT };
/* Massbus register read */
t_stat tu_mbrd (int32 *data, int32 ofs, int32 fmtr)
{
int32 drv;
if (fmtr != 0) { /* only one fmtr */
*data = 0;
return MBE_NXD;
}
drv = GET_DRV (tutc); /* get current unit */
tu_update_fs (0, drv); /* update status */
switch (ofs) { /* decode offset */
case CS1_OF: /* MTCS1 */
*data = tucs1 & CS1_RW;
break;
case FC_OF: /* MTFC */
*data = tufc;
break;
case FS_OF: /* MTFS */
*data = tufs & 0177777; /* mask off rewind */
break;
case ER_OF: /* MTER */
*data = tuer;
break;
case AS_OF: /* MTAS */
*data = (tufs & FS_ATA)? AS_U0: 0;
break;
case CC_OF: /* MTCC */
*data = tucc = tucc & ~CC_MBZ;
break;
case MR_OF: /* MTMR */
*data = tumr;
break;
case DT_OF: /* MTDT */
*data = DT_NSA | DT_TAPE | /* fmtr flags */
((tu_dev.flags & DEV_TM03)? DT_TM03: 0);
if (tu_unit[drv].flags & UNIT_DIS) *data |= DT_OFF;
else *data |= DT_PRES | dt_map[GET_TYPE (tu_unit[drv].flags)];
break;
case SN_OF: /* MTSN */
*data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1);
break;
case TC_OF: /* MTTC */
*data = tutc = tutc & ~TC_MBZ;
break;
default: /* all others */
return MBE_NXR; }
return SCPE_OK;
}
/* Massbus register write */
t_stat tu_mbwr (int32 data, int32 ofs, int32 fmtr)
{
int32 drv;
if (fmtr != 0) return MBE_NXD; /* only one fmtr */
drv = GET_DRV (tutc); /* get current unit */
switch (ofs) { /* decode PA<4:1> */
case CS1_OF: /* MTCS1 */
if (tucs1 & CS1_GO) tu_set_er (ER_RMR);
else {
tucs1 = data & CS1_RW;
if (tucs1 & CS1_GO) return tu_go (drv);
}
break;
case FC_OF: /* MTFC */
if (tucs1 & CS1_GO) tu_set_er (ER_RMR);
else {
tufc = data;
tutc = tutc | TC_FCS; /* set fc flag */
}
break;
case AS_OF: /* MTAS */
tu_clr_as (data);
break;
case MR_OF: /* MTMR */
tumr = (tumr & ~MR_RW) | (data & MR_RW);
break;
case TC_OF: /* MTTC */
if (tucs1 & CS1_GO) tu_set_er (ER_RMR);
else {
tutc = (tutc & ~TC_RW) | (data & TC_RW) | TC_SAC;
drv = GET_DRV (tutc); }
break;
case FS_OF: /* MTFS */
case ER_OF: /* MTER */
case CC_OF: /* MTCC */
case DT_OF: /* MTDT */
case SN_OF: /* MTSN */
if (tucs1 & CS1_GO) tu_set_er (ER_RMR);
break; /* read only */
default: /* all others */
return MBE_NXR; } /* end switch */
tu_update_fs (0, drv);
return SCPE_OK;
}
/* New magtape command */
t_stat tu_go (int32 drv)
{
int32 fnc, den, space_test = FS_BOT;
UNIT *uptr;
fnc = GET_FNC (tucs1); /* get function */
den = GET_DEN (tutc); /* get density */
uptr = tu_dev.units + drv; /* get unit */
if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
drv, tu_fname[fnc], tufc, tufs, tuer, uptr->pos);
if ((fnc != FNC_FCLR) && /* not clear & err */
((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */
tu_set_er (ER_ILF); /* set err */
tucs1 = tucs1 & ~CS1_GO; /* clear go */
tu_update_fs (FS_ATA, drv); /* set attn */
return MBE_GOE; }
tu_clr_as (AS_U0); /* clear ATA */
tutc = tutc & ~TC_SAC; /* clear addr change */
switch (fnc) { /* case on function */
case FNC_FCLR: /* drive clear */
tuer = 0; /* clear errors */
tutc = tutc & ~TC_FCS; /* clear fc status */
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
sim_cancel (uptr); /* reset drive */
uptr->USTAT = 0;
case FNC_NOP:
tucs1 = tucs1 & ~CS1_GO; /* no operation */
return SCPE_OK;
case FNC_RIP: /* read-in preset */
tutc = TC_RIP; /* set tutc */
sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
tu_unit[0].USTAT = 0;
tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return SCPE_OK;
case FNC_UNLOAD: /* unload */
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tu_set_er (ER_UNS);
break; }
detach_unit (uptr);
uptr->USTAT = FS_REW;
sim_activate (uptr, tu_time);
tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return SCPE_OK;
case FNC_REWIND:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tu_set_er (ER_UNS);
break; }
uptr->USTAT = FS_PIP | FS_REW;
sim_activate (uptr, tu_time);
tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK;
return SCPE_OK;
case FNC_SPACEF:
space_test = FS_EOT;
case FNC_SPACER:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tu_set_er (ER_UNS);
break; }
if ((tufs & space_test) || ((tutc & TC_FCS) == 0)) {
tu_set_er (ER_NXF);
break; }
uptr->USTAT = FS_PIP;
goto GO_XFER;
case FNC_WCHKR: /* wchk = read */
case FNC_READR: /* read rev */
if (tufs & FS_BOT) { /* beginning of tape? */
tu_set_er (ER_NXF);
break; }
goto DATA_XFER;
case FNC_WRITE: /* write */
if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */
((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */
tu_set_er (ER_NXF);
break; }
case FNC_WREOF: /* write tape mark */
case FNC_ERASE: /* erase */
if (sim_tape_wrp (uptr)) { /* write locked? */
tu_set_er (ER_NXF);
break; }
case FNC_WCHKF: /* wchk = read */
case FNC_READF: /* read */
DATA_XFER:
if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */
tu_set_er (ER_UNS);
break; }
if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */
tu_set_er (ER_FER);
break; }
if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */
uptr->USTAT = 0;
GO_XFER:
tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */
sim_activate (uptr, tu_time);
return SCPE_OK;
default: /* all others */
tu_set_er (ER_ILF); /* not supported */
break; } /* end case function */
tucs1 = tucs1 & ~CS1_GO; /* clear go */
tu_update_fs (FS_ATA, drv); /* set attn */
return MBE_GOE;
}
/* Abort transfer */
t_stat tu_abort (void)
{
return tu_reset (&tu_dev);
}
/* Unit service
Complete movement or data transfer command
Unit must exist - can't remove an active unit
Unit must be attached - detach cancels in progress operations
*/
t_stat tu_svc (UNIT *uptr)
{
int32 fnc, fmt, j, xbc;
int32 fc, drv;
t_mtrlnt i, tbc;
t_stat st, r = SCPE_OK;
drv = uptr - tu_dev.units; /* get drive # */
if (uptr->USTAT & FS_REW) { /* rewind or unload? */
sim_tape_rewind (uptr); /* rewind tape */
uptr->USTAT = 0; /* clear status */
tu_update_fs (FS_ATA | FS_SSC, drv);
return SCPE_OK; }
fnc = GET_FNC (tucs1); /* get command */
fmt = GET_FMT (tutc); /* get format */
fc = 0200000 - tufc; /* get frame count */
uptr->USTAT = 0; /* clear status */
if ((uptr->flags & UNIT_ATT) == 0) {
tu_set_er (ER_UNS); /* set formatter error */
if (fnc >= FNC_XFER) mba_set_don (tu_dib.ba);
tu_update_fs (FS_ATA, drv);
return (tu_stopioe? SCPE_UNATT: SCPE_OK);
}
switch (fnc) { /* case on function */
/* Non-data transfer commands - set ATA when done */
case FNC_SPACEF: /* space forward */
do {
tufc = (tufc + 1) & 0177777; /* incr fc */
if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
r = tu_map_err (drv, st); /* map error */
break; }
}
while (tufc != 0);
if (tufc) tu_set_er (ER_FCE);
else tutc = tutc & ~TC_FCS;
break;
case FNC_SPACER: /* space reverse */
do {
tufc = (tufc + 1) & 0177777; /* incr wc */
if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
r = tu_map_err (drv, st); /* map error */
break; }
}
while (tufc != 0);
if (tufc) tu_set_er (ER_FCE);
else tutc = tutc & ~TC_FCS;
break;
case FNC_WREOF: /* write end of file */
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = tu_map_err (drv, st); /* map error */
break;
case FNC_ERASE:
if (sim_tape_wrp (uptr)) /* write protected? */
r = tu_map_err (drv, MTSE_WRP); /* map error */
break;
/* Unit service - data transfer commands */
case FNC_READF: /* read */
case FNC_WCHKF: /* wcheck = read */
tufc = 0; /* clear frame count */
if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr))
tufs = tufs | FS_ID; /* PE BOT? ID burst */
if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */
r = tu_map_err (drv, st); /* map error */
break; } /* done */
for (i = tbc; i < tbc + 4; i++) xbuf[i] = 0; /* pad with 0's */
if (fmt == TC_CDUMP) { /* core dump? */
for (i = j = 0; i < tbc; i = i + 4) {
wbuf[j++] = ((uint16) xbuf[i] & 0xF) |
(((uint16) (xbuf[i + 1] & 0xF)) << 4) |
(((uint16) (xbuf[i + 2] & 0xF)) << 8) |
(((uint16) (xbuf[i + 3] & 0xf)) << 12);
}
xbc = (tbc + 1) >> 1;
}
else { /* standard */
for (i = j = 0; i < tbc; i = i + 2) {
wbuf[j++] = ((uint16) xbuf[i]) |
(((uint16) xbuf[i + 1]) << 8);
}
xbc = tbc;
}
if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */
tu_set_er (ER_FCE); /* set FCE, ATN */
if (fnc == FNC_WCHKF) mba_chbufW (tu_dib.ba, xbc, wbuf);
else mba_wrbufW (tu_dib.ba, xbc, wbuf);
tufc = tbc & 0177777;
break;
case FNC_WRITE: /* write */
xbc = mba_rdbufW (tu_dib.ba, fc, wbuf); /* read buffer */
if (xbc == 0) break; /* anything?? */
if (fmt == TC_CDUMP) { /* core dump? */
for (i = j = 0; j < xbc; j = j + 1) {
xbuf[i++] = wbuf[j] & 0xF;
xbuf[i++] = (wbuf[j] >> 4) & 0xF;
xbuf[i++] = (wbuf[j] >> 8) & 0xF;
xbuf[i++] = (wbuf[j] >> 12) & 0xF;
}
tbc = (xbc + 1) >> 1;
}
else { /* standard */
for (i = j = 0; j < xbc; j = j + 1) {
xbuf[i++] = wbuf[j] & 0377;
xbuf[i++] = (wbuf[j] >> 8) & 0377; }
tbc = xbc;
}
if (st = sim_tape_wrrecf (uptr, xbuf, tbc)) /* write rec, err? */
r = tu_map_err (drv, st); /* map error */
else {
tufc = (tufc + tbc) & 0177777;
if (tufc == 0) tutc = tutc & ~TC_FCS;
}
break;
case FNC_READR: /* read reverse */
case FNC_WCHKR: /* wcheck = read */
tufc = 0; /* clear frame count */
if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */
r = tu_map_err (drv, st); /* map error */
break; } /* done */
for (i = 0; i < 4; i++) xbuf[i] = 0; /* pad with 0's */
if (fmt == TC_CDUMP) { /* core dump? */
for (i = tbc + 3, j = 0; i > 3; i = i - 4) {
wbuf[j++] = ((uint16) xbuf[i] & 0xF) |
(((uint16) (xbuf[i - 1] & 0xF)) << 4) |
(((uint16) (xbuf[i - 2] & 0xF)) << 8) |
(((uint16) (xbuf[i - 3] & 0xf)) << 12);
}
xbc = (tbc + 1) >> 1;
}
else { /* standard */
for (i = tbc + 3, j = 0; i > 3; i = i - 2) {
wbuf[j++] = ((uint16) xbuf[i]) |
(((uint16) xbuf[i - 1]) << 8);
}
xbc = tbc;
}
if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */
tu_set_er (ER_FCE); /* set FCE, ATN */
if (fnc == FNC_WCHKR) mba_chbufW (tu_dib.ba, xbc, wbuf);
else mba_wrbufW (tu_dib.ba, xbc, wbuf);
tufc = tbc & 0177777;
break;
} /* end case */
tucs1 = tucs1 & ~CS1_GO; /* clear go */
if (fnc >= FNC_XFER) { /* data xfer? */
mba_set_don (tu_dib.ba); /* set done */
tu_update_fs (0, drv); } /* update fs */
else tu_update_fs (FS_ATA, drv); /* no, set attn */
if (DEBUG_PRS (tu_dev)) fprintf (sim_deb,
">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=%d\n",
drv, tu_fname[fnc], tufc, tufs, tuer, uptr->pos);
return SCPE_OK;
}
/* Set formatter error */
void tu_set_er (int32 flg)
{
tuer = tuer | flg;
tufs = tufs | FS_ATA;
mba_upd_ata (tu_dib.ba, 1);
return;
}
/* Clear attention */
void tu_clr_as (int32 mask)
{
if (mask & AS_U0) tufs = tufs & ~FS_ATA;
mba_upd_ata (tu_dib.ba, tufs & FS_ATA);
return;
}
/* Formatter update status */
void tu_update_fs (int32 flg, int32 drv)
{
int32 act = sim_is_active (&tu_unit[drv]);
tufs = (tufs & ~FS_DYN) | FS_FPR | flg;
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 (sim_tape_wrp (&tu_unit[drv])) tufs = tufs | FS_WRL;
if (sim_tape_bot (&tu_unit[drv]) && !act) tufs = tufs | FS_BOT; }
if (tuer) tufs = tufs | FS_ERR;
if (tufs && !act) tufs = tufs | FS_RDY;
if (flg & FS_ATA) mba_upd_ata (tu_dib.ba, 1);
return;
}
/* Map tape error status */
t_stat tu_map_err (int32 drv, t_stat st)
{
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* not attached */
tu_set_er (ER_NXF); /* can't execute */
break;
case MTSE_TMK: /* end of file */
tufs = tufs | FS_TMK;
tu_set_er (ER_FCE); /* also sets FCE */
break;
case MTSE_IOERR: /* IO error */
tu_set_er (ER_VPE); /* flag error */
mba_set_exc (tu_dib.ba); /* set exception */
return (tu_stopioe? SCPE_IOERR: SCPE_OK);
case MTSE_INVRL: /* invalid rec lnt */
tu_set_er (ER_VPE); /* flag error */
return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */
tu_set_er (ER_CRC); /* set crc err */
break;
case MTSE_EOM: /* end of medium */
tu_set_er (ER_OPI); /* incomplete */
break;
case MTSE_BOT: /* reverse into BOT */
return SCPE_OK;
case MTSE_WRP: /* write protect */
tu_set_er (ER_NXF); /* can't execute */
break;
default: /* unknown error */
return SCPE_IERR; }
return SCPE_OK;
}
/* Reset routine */
t_stat tu_reset (DEVICE *dptr)
{
int32 u;
UNIT *uptr;
tucs1 = 0;
tufc = 0;
tuer = 0;
tufs = FS_FPR | FS_RDY;
if (sim_switches & SWMASK ('P')) tutc = 0; /* powerup? clr TC */
else tutc = tutc & ~TC_FCS; /* no, clr <fcs> */
for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */
uptr = tu_dev.units + u;
sim_tape_reset (uptr); /* clear pos flag */
sim_cancel (uptr); /* cancel activity */
uptr->USTAT = 0; }
if (xbuf == NULL) xbuf = calloc (MT_MAXFR + 4, sizeof (uint8));
if (xbuf == NULL) return SCPE_MEM;
if (wbuf == NULL) wbuf = calloc ((MT_MAXFR + 4) >> 1, sizeof (uint16));
if (wbuf == NULL) return SCPE_MEM;
return SCPE_OK;
}
/* Attach routine */
t_stat tu_attach (UNIT *uptr, char *cptr)
{
int32 drv = uptr - tu_dev.units, flg;
t_stat r;
r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK) return r;
uptr->USTAT = 0; /* clear unit status */
uptr->UDENS = UD_UNK; /* unknown density */
flg = FS_ATA | FS_SSC; /* set attention */
if (GET_DRV (tutc) == drv) flg = flg | FS_SAT; /* sel drv? set SAT */
tu_update_fs (flg, drv); /* update status */
return r;
}
/* Detach routine */
t_stat tu_detach (UNIT* uptr)
{
int32 drv = uptr - tu_dev.units;
uptr->USTAT = 0; /* clear status flags */
tu_update_fs (FS_ATA | FS_SSC, drv); /* update status */
return sim_tape_detach (uptr);
}
/* Set/show formatter type */
t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr = find_dev_from_unit (uptr);
if (cptr != NULL) return SCPE_ARG;
if (dptr == NULL) return SCPE_IERR;
if (val) dptr->flags = dptr->flags | DEV_TM03;
else dptr->flags = dptr->flags & ~DEV_TM03;
return SCPE_OK;
}
t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc)
{
DEVICE *dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
fprintf (st, "TM0%d", (dptr->flags & DEV_TM03? 3: 2));
return SCPE_OK;
}
/* Device bootstrap */
#if defined (PDP11)
#elif defined (VM_PDP11)
#define BOOT_START 016000 /* start */
#define BOOT_ENTRY (BOOT_START + 002) /* entry */
#define BOOT_UNIT (BOOT_START + 010) /* unit number */
#define BOOT_CSR (BOOT_START + 014) /* CSR */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16))
static const uint16 boot_rom[] = {
0046515, /* "MM" */
0012706, BOOT_START, /* mov #boot_start, sp */
0012700, 0000000, /* mov #unit, r0 */
0012701, 0172440, /* mov #TUCS1, r1 */
0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */
0012711, 0000021, /* mov #RIP+GO, (r1) ; rip */
0010004, /* mov r0, r4 */
0052704, 0002300, /* bis #2300, r4 ; set den */
0010461, 0000032, /* mov r4, 32(r1) ; set unit */
0012761, 0177777, 0000006, /* mov #-1, 6(r1) ; set fc */
0012711, 0000031, /* mov #SPCF+GO, (r1) ; skip rec */
0105761, 0000012, /* tstb 12 (r1) ; fmtr rdy? */
0100375, /* bpl .-4 */
0012761, 0177000, 0000002, /* mov #-1000, 2(r1) ; set wc */
0005061, 0000004, /* clr 4(r1) ; clr ba */
0005061, 0000006, /* clr 6(r1) ; clr fc */
0012711, 0000071, /* mov #READ+GO, (r1) ; read */
0105711, /* tstb (r1) ; wait */
0100376, /* bpl .-2 */
0005002, /* clr R2 */
0005003, /* clr R3 */
0012704, BOOT_START+020, /* mov #start+020, r4 */
0005005, /* clr R5 */
0105011, /* clrb (r1) */
0005007 /* clr PC */
};
t_stat tu_boot (int32 unitno, DEVICE *dptr)
{
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 & (TU_NUMDR - 1);
M[BOOT_CSR >> 1] = mba_get_csr (tu_dib.ba) & DMASK;
saved_PC = BOOT_ENTRY;
return SCPE_OK;
}
#else
t_stat tu_boot (int32 unitno, DEVICE *dptr)
{
return SCPE_NOFNC;
}
#endif

View file

@ -69,6 +69,7 @@ extern int32 int_vec[IPL_HLVL][32];
#include "pdp11_defs.h" #include "pdp11_defs.h"
extern int32 int_req[IPL_HLVL]; extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32]; extern int32 int_vec[IPL_HLVL][32];
extern int32 cpu_opt;
#endif #endif
#include "sim_sock.h" #include "sim_sock.h"
@ -1054,8 +1055,8 @@ static void doDMA ( int32 vh,
pa |= (lp->tbuf2 & TB2_M_TBUFFAD) << 16; pa |= (lp->tbuf2 & TB2_M_TBUFFAD) << 16;
status = chan << CSR_V_TX_LINE; status = chan << CSR_V_TX_LINE;
while (lp->tbuffct) { while (lp->tbuffct) {
char buf; uint8 buf;
if (Map_ReadB (pa, 1, &buf, MAP)) { if (Map_ReadB (pa, 1, &buf)) {
status |= CSR_TX_DMA_ERR; status |= CSR_TX_DMA_ERR;
lp->tbuffct = 0; lp->tbuffct = 0;
break; break;
@ -1233,10 +1234,6 @@ static t_stat vh_clear ( int32 vh,
static t_stat vh_reset ( DEVICE *dptr ) static t_stat vh_reset ( DEVICE *dptr )
{ {
int32 i; int32 i;
#if defined (VM_PDP11)
/* import from pdp11_cpu.c: */
extern int32 cpu_18b, cpu_ubm;
#endif
for (i = 0; i < (VH_MUXES * VH_LINES); i++) for (i = 0; i < (VH_MUXES * VH_LINES); i++)
vh_parm[i].tmln = &vh_ldsc[i]; vh_parm[i].tmln = &vh_ldsc[i];

View file

@ -669,11 +669,11 @@ void xq_write_callback (CTLR* xq, int status)
xq->var->stats.xmit += 1; xq->var->stats.xmit += 1;
/* update write status words */ /* update write status words */
if (status == 0) { /* success */ if (status == 0) { /* success */
wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_success, NOMAP); wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_success);
} else { /* failure */ } else { /* failure */
sim_debug(DBG_WRN, xq->dev, "Packet Write Error!\n"); sim_debug(DBG_WRN, xq->dev, "Packet Write Error!\n");
xq->var->stats.fail += 1; xq->var->stats.fail += 1;
wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_failure, NOMAP); wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_failure);
} }
if (wstatus) { if (wstatus) {
xq_nxm_error(xq); xq_nxm_error(xq);
@ -760,8 +760,8 @@ t_stat xq_process_rbdl(CTLR* xq)
/* get receive bdl from memory */ /* get receive bdl from memory */
xq->var->rbdl_buf[0] = 0xFFFF; xq->var->rbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1], NOMAP); rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
if (rstatus || wstatus) return xq_nxm_error(xq); if (rstatus || wstatus) return xq_nxm_error(xq);
/* invalid buffer? */ /* invalid buffer? */
@ -780,7 +780,7 @@ t_stat xq_process_rbdl(CTLR* xq)
if (!xq->var->ReadQ.count) break; if (!xq->var->ReadQ.count) break;
/* get status words */ /* get status words */
rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (rstatus) return xq_nxm_error(xq); if (rstatus) return xq_nxm_error(xq);
/* get host memory address */ /* get host memory address */
@ -828,7 +828,7 @@ t_stat xq_process_rbdl(CTLR* xq)
item->packet.used += rbl; item->packet.used += rbl;
/* send data to host */ /* send data to host */
wstatus = Map_WriteB(address, rbl, rbuf, NOMAP); wstatus = Map_WriteB(address, rbl, rbuf);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* set receive size into RBL - RBL<10:8> maps into Status1<10:8>, /* set receive size into RBL - RBL<10:8> maps into Status1<10:8>,
@ -860,7 +860,7 @@ t_stat xq_process_rbdl(CTLR* xq)
} }
/* update read status words*/ /* update read status words*/
wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* remove packet from queue */ /* remove packet from queue */
@ -901,7 +901,7 @@ t_stat xq_process_mop(CTLR* xq)
case 0: /* MOP Termination */ case 0: /* MOP Termination */
break; break;
case 1: /* MOP Read Ethernet Address */ case 1: /* MOP Read Ethernet Address */
wstatus = Map_WriteB(address, sizeof(ETH_MAC), (uint8*) &xq->var->setup.macs[0], NOMAP); wstatus = Map_WriteB(address, sizeof(ETH_MAC), (uint8*) &xq->var->setup.macs[0]);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
break; break;
case 2: /* MOP Reset System ID */ case 2: /* MOP Reset System ID */
@ -1062,9 +1062,9 @@ t_stat xq_process_xbdl(CTLR* xq)
while (1) { while (1) {
/* Get transmit bdl from memory */ /* Get transmit bdl from memory */
rstatus = Map_ReadW (xq->var->xbdl_ba, 12, &xq->var->xbdl_buf[0], NOMAP); rstatus = Map_ReadW (xq->var->xbdl_ba, 12, &xq->var->xbdl_buf[0]);
xq->var->xbdl_buf[0] = 0xFFFF; xq->var->xbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq->var->xbdl_ba, 2, &xq->var->xbdl_buf[0], NOMAP); wstatus = Map_WriteW(xq->var->xbdl_ba, 2, &xq->var->xbdl_buf[0]);
if (rstatus || wstatus) return xq_nxm_error(xq); if (rstatus || wstatus) return xq_nxm_error(xq);
/* invalid buffer? */ /* invalid buffer? */
@ -1093,7 +1093,7 @@ t_stat xq_process_xbdl(CTLR* xq)
/* add to transmit buffer, making sure it's not too big */ /* add to transmit buffer, making sure it's not too big */
if ((xq->var->write_buffer.len + b_length) > sizeof(xq->var->write_buffer.msg)) if ((xq->var->write_buffer.len + b_length) > sizeof(xq->var->write_buffer.msg))
b_length = sizeof(xq->var->write_buffer.msg) - xq->var->write_buffer.len; b_length = sizeof(xq->var->write_buffer.msg) - xq->var->write_buffer.len;
rstatus = Map_ReadB(address, b_length, &xq->var->write_buffer.msg[xq->var->write_buffer.len], NOMAP); rstatus = Map_ReadB(address, b_length, &xq->var->write_buffer.msg[xq->var->write_buffer.len]);
if (rstatus) return xq_nxm_error(xq); if (rstatus) return xq_nxm_error(xq);
xq->var->write_buffer.len += b_length; xq->var->write_buffer.len += b_length;
@ -1112,7 +1112,7 @@ t_stat xq_process_xbdl(CTLR* xq)
} }
/* update write status */ /* update write status */
wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) write_success, NOMAP); wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) write_success);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* clear write buffer */ /* clear write buffer */
@ -1145,7 +1145,7 @@ t_stat xq_process_xbdl(CTLR* xq)
sim_debug(DBG_WRN, xq->dev, "XBDL processing implicit chain buffer segment\n"); sim_debug(DBG_WRN, xq->dev, "XBDL processing implicit chain buffer segment\n");
/* update bdl status words */ /* update bdl status words */
wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) implicit_chain_status, NOMAP); wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) implicit_chain_status);
if(wstatus) return xq_nxm_error(xq); if(wstatus) return xq_nxm_error(xq);
} }
@ -1175,8 +1175,8 @@ t_stat xq_dispatch_rbdl(CTLR* xq)
/* get first receive buffer */ /* get first receive buffer */
xq->var->rbdl_buf[0] = 0xFFFF; xq->var->rbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1], NOMAP); rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
if (rstatus || wstatus) return xq_nxm_error(xq); if (rstatus || wstatus) return xq_nxm_error(xq);
/* is buffer valid? */ /* is buffer valid? */
@ -1460,8 +1460,8 @@ t_stat xq_process_bootrom (CTLR* xq)
/* get receive bdl from memory */ /* get receive bdl from memory */
xq->var->rbdl_buf[0] = 0xFFFF; xq->var->rbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1], NOMAP); rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
if (rstatus || wstatus) return xq_nxm_error(xq); if (rstatus || wstatus) return xq_nxm_error(xq);
/* invalid buffer? */ /* invalid buffer? */
@ -1471,7 +1471,7 @@ t_stat xq_process_bootrom (CTLR* xq)
} }
/* get status words */ /* get status words */
rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (rstatus) return xq_nxm_error(xq); if (rstatus) return xq_nxm_error(xq);
/* get host memory address */ /* get host memory address */
@ -1487,7 +1487,7 @@ t_stat xq_process_bootrom (CTLR* xq)
assert(b_length >= sizeof(xq_bootrom)/2); assert(b_length >= sizeof(xq_bootrom)/2);
/* send data to host */ /* send data to host */
wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, bootrom, NOMAP); wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, bootrom);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* update read status words */ /* update read status words */
@ -1495,7 +1495,7 @@ t_stat xq_process_bootrom (CTLR* xq)
xq->var->rbdl_buf[5] = 0; xq->var->rbdl_buf[5] = 0;
/* update read status words*/ /* update read status words*/
wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* set to next bdl (implicit chain) */ /* set to next bdl (implicit chain) */
@ -1505,8 +1505,8 @@ t_stat xq_process_bootrom (CTLR* xq)
/* get receive bdl from memory */ /* get receive bdl from memory */
xq->var->rbdl_buf[0] = 0xFFFF; xq->var->rbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1], NOMAP); rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
if (rstatus || wstatus) return xq_nxm_error(xq); if (rstatus || wstatus) return xq_nxm_error(xq);
/* invalid buffer? */ /* invalid buffer? */
@ -1516,7 +1516,7 @@ t_stat xq_process_bootrom (CTLR* xq)
} }
/* get status words */ /* get status words */
rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (rstatus) return xq_nxm_error(xq); if (rstatus) return xq_nxm_error(xq);
/* get host memory address */ /* get host memory address */
@ -1532,7 +1532,7 @@ t_stat xq_process_bootrom (CTLR* xq)
assert(b_length >= sizeof(xq_bootrom)/2); assert(b_length >= sizeof(xq_bootrom)/2);
/* send data to host */ /* send data to host */
wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, &bootrom[2048], NOMAP); wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, &bootrom[2048]);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* update read status words */ /* update read status words */
@ -1540,7 +1540,7 @@ t_stat xq_process_bootrom (CTLR* xq)
xq->var->rbdl_buf[5] = 0; xq->var->rbdl_buf[5] = 0;
/* update read status words*/ /* update read status words*/
wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* set to next bdl (implicit chain) */ /* set to next bdl (implicit chain) */
@ -1553,8 +1553,8 @@ t_stat xq_process_bootrom (CTLR* xq)
/* get receive bdl from memory */ /* get receive bdl from memory */
xq->var->rbdl_buf[0] = 0xFFFF; xq->var->rbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]);
rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1], NOMAP); rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]);
if (rstatus || wstatus) return xq_nxm_error(xq); if (rstatus || wstatus) return xq_nxm_error(xq);
/* invalid buffer? */ /* invalid buffer? */
@ -1564,7 +1564,7 @@ t_stat xq_process_bootrom (CTLR* xq)
} }
/* get status words */ /* get status words */
rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (rstatus) return xq_nxm_error(xq); if (rstatus) return xq_nxm_error(xq);
/* update read status words */ /* update read status words */
@ -1572,7 +1572,7 @@ t_stat xq_process_bootrom (CTLR* xq)
xq->var->rbdl_buf[5] = 0; xq->var->rbdl_buf[5] = 0;
/* update read status words*/ /* update read status words*/
wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4], NOMAP); wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]);
if (wstatus) return xq_nxm_error(xq); if (wstatus) return xq_nxm_error(xq);
/* set to next bdl (implicit chain) */ /* set to next bdl (implicit chain) */

View file

@ -605,7 +605,7 @@ int32 xu_command(CTLR* xu)
}; };
/* Grab the PCB from the host. */ /* Grab the PCB from the host. */
rstatus = Map_ReadW(xu->var->pcbb, 8, xu->var->pcb, MAP); rstatus = Map_ReadW(xu->var->pcbb, 8, xu->var->pcb);
if (rstatus != SCPE_OK) if (rstatus != SCPE_OK)
return PCSR0_PCEI + 1; return PCSR0_PCEI + 1;
@ -621,19 +621,19 @@ int32 xu_command(CTLR* xu)
break; break;
case FC_RDPA: /* read default physical address */ case FC_RDPA: /* read default physical address */
wstatus = Map_WriteW(xu->var->pcbb + 2, 6, (uint16*)xu->var->mac, MAP); wstatus = Map_WriteW(xu->var->pcbb + 2, 6, (uint16*)xu->var->mac);
if (wstatus != SCPE_OK) if (wstatus != SCPE_OK)
return PCSR0_PCEI + 1; return PCSR0_PCEI + 1;
break; break;
case FC_RPA: /* read current physical address */ case FC_RPA: /* read current physical address */
wstatus = Map_WriteW(xu->var->pcbb + 2, 6, (uint16*)&xu->var->setup.macs[0], MAP); wstatus = Map_WriteW(xu->var->pcbb + 2, 6, (uint16*)&xu->var->setup.macs[0]);
if (wstatus != SCPE_OK) if (wstatus != SCPE_OK)
return PCSR0_PCEI + 1; return PCSR0_PCEI + 1;
break; break;
case FC_WPA: /* write current physical address */ case FC_WPA: /* write current physical address */
rstatus = Map_ReadW(xu->var->pcbb + 2, 6, (uint16*)&xu->var->setup.macs[0], MAP); rstatus = Map_ReadW(xu->var->pcbb + 2, 6, (uint16*)&xu->var->setup.macs[0]);
if (xu->var->pcb[1] & 1) return PCSR0_PCEI; if (xu->var->pcb[1] & 1) return PCSR0_PCEI;
break; break;
@ -641,7 +641,7 @@ int32 xu_command(CTLR* xu)
mtlen = (xu->var->pcb[2] & 0xFF00) >> 8; mtlen = (xu->var->pcb[2] & 0xFF00) >> 8;
if (mtlen > 10) return PCSR0_PCEI; if (mtlen > 10) return PCSR0_PCEI;
udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16); udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16);
rstatus = Map_ReadW(udbb, mtlen * 6, (uint16*) &xu->var->setup.macs[1], MAP); rstatus = Map_ReadW(udbb, mtlen * 6, (uint16*) &xu->var->setup.macs[1]);
if (rstatus == SCPE_OK) { if (rstatus == SCPE_OK) {
xu->var->setup.mac_count = mtlen + 1; xu->var->setup.mac_count = mtlen + 1;
status = eth_filter (xu->var->etherface, xu->var->setup.mac_count, status = eth_filter (xu->var->etherface, xu->var->setup.mac_count,
@ -664,7 +664,7 @@ int32 xu_command(CTLR* xu)
/* Write UDB to host memory. */ /* Write UDB to host memory. */
udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
wstatus = Map_WriteW(udbb, 12, xu->var->pcb, MAP); wstatus = Map_WriteW(udbb, 12, xu->var->pcb);
if (wstatus != SCPE_OK) if (wstatus != SCPE_OK)
return PCSR0_PCEI+1; return PCSR0_PCEI+1;
break; break;
@ -677,7 +677,7 @@ int32 xu_command(CTLR* xu)
/* Read UDB into local memory. */ /* Read UDB into local memory. */
udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
rstatus = Map_ReadW(udbb, 12, xu->var->udb, MAP); rstatus = Map_ReadW(udbb, 12, xu->var->udb);
if (rstatus != SCPE_OK) if (rstatus != SCPE_OK)
return PCSR0_PCEI+1; return PCSR0_PCEI+1;
@ -740,7 +740,7 @@ int32 xu_command(CTLR* xu)
/* transfer udb to host */ /* transfer udb to host */
udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16);
wstatus = Map_WriteW(udbb, 68, xu->var->udb, MAP); wstatus = Map_WriteW(udbb, 68, xu->var->udb);
if (wstatus != SCPE_OK) { if (wstatus != SCPE_OK) {
xu->var->pcsr0 |= PCSR0_PCEI; xu->var->pcsr0 |= PCSR0_PCEI;
} }
@ -752,7 +752,7 @@ int32 xu_command(CTLR* xu)
case FC_RMODE: /* read mode register */ case FC_RMODE: /* read mode register */
value = xu->var->mode; value = xu->var->mode;
wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value, MAP); wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value);
if (wstatus != SCPE_OK) if (wstatus != SCPE_OK)
return PCSR0_PCEI + 1; return PCSR0_PCEI + 1;
break; break;
@ -775,11 +775,11 @@ int32 xu_command(CTLR* xu)
case FC_RSTAT: /* read extended status */ case FC_RSTAT: /* read extended status */
case FC_RCSTAT: /* read and clear extended status */ case FC_RCSTAT: /* read and clear extended status */
value = xu->var->stat; value = xu->var->stat;
wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value, MAP); wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value);
value = 10; value = 10;
wstatus2 = Map_WriteW(xu->var->pcbb+4, 2, &value, MAP); wstatus2 = Map_WriteW(xu->var->pcbb+4, 2, &value);
value = 32; value = 32;
wstatus3 = Map_WriteW(xu->var->pcbb+6, 2, &value, MAP); wstatus3 = Map_WriteW(xu->var->pcbb+6, 2, &value);
if ((wstatus != SCPE_OK) || (wstatus2 != SCPE_OK) || (wstatus3 != SCPE_OK)) if ((wstatus != SCPE_OK) || (wstatus2 != SCPE_OK) || (wstatus3 != SCPE_OK))
return PCSR0_PCEI + 1; return PCSR0_PCEI + 1;
@ -824,7 +824,7 @@ void xu_process_receive(CTLR* xu)
/* get next receive buffer */ /* get next receive buffer */
ba = xu->var->rdrb + (xu->var->relen * 2) * xu->var->rxnext; ba = xu->var->rdrb + (xu->var->relen * 2) * xu->var->rxnext;
rstatus = Map_ReadW (ba, 8, xu->var->rxhdr, MAP); rstatus = Map_ReadW (ba, 8, xu->var->rxhdr);
if (rstatus) { if (rstatus) {
/* tell host bus read failed */ /* tell host bus read failed */
xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG;
@ -882,7 +882,7 @@ void xu_process_receive(CTLR* xu)
wlen = slen; wlen = slen;
/* transfer chained packet to host buffer */ /* transfer chained packet to host buffer */
wstatus = Map_WriteB (segb, wlen, &item->packet.msg[off], MAP); wstatus = Map_WriteB (segb, wlen, &item->packet.msg[off]);
if (wstatus) { if (wstatus) {
/* error during write */ /* error during write */
xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG;
@ -938,7 +938,7 @@ void xu_process_receive(CTLR* xu)
xu->var->rxhdr[2] &= ~RXR_OWN; /* clear ownership flag */ xu->var->rxhdr[2] &= ~RXR_OWN; /* clear ownership flag */
/* update the ring entry in host memory. */ /* update the ring entry in host memory. */
wstatus = Map_WriteW (ba, 8, xu->var->rxhdr, MAP); wstatus = Map_WriteW (ba, 8, xu->var->rxhdr);
if (wstatus) { if (wstatus) {
/* tell host bus write failed */ /* tell host bus write failed */
xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG;
@ -978,7 +978,7 @@ void xu_process_transmit(CTLR* xu)
/* get next transmit buffer */ /* get next transmit buffer */
ba = xu->var->tdrb + (xu->var->telen * 2) * xu->var->txnext; ba = xu->var->tdrb + (xu->var->telen * 2) * xu->var->txnext;
rstatus = Map_ReadW (ba, 8, xu->var->txhdr, MAP); rstatus = Map_ReadW (ba, 8, xu->var->txhdr);
if (rstatus) { if (rstatus) {
/* tell host bus read failed */ /* tell host bus read failed */
xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG; xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG;
@ -1007,7 +1007,7 @@ void xu_process_transmit(CTLR* xu)
giant = 1; giant = 1;
} }
if (wlen > 0) { if (wlen > 0) {
rstatus = Map_ReadB(segb, wlen, &xu->var->write_buffer.msg[off], MAP); rstatus = Map_ReadB(segb, wlen, &xu->var->write_buffer.msg[off]);
if (rstatus) { if (rstatus) {
/* tell host bus read failed */ /* tell host bus read failed */
xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG; xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG;
@ -1078,7 +1078,7 @@ void xu_process_transmit(CTLR* xu)
xu->var->txhdr[2] &= ~TXR_OWN; xu->var->txhdr[2] &= ~TXR_OWN;
/* update transmit buffer */ /* update transmit buffer */
wstatus = Map_WriteW (ba, 8, xu->var->txhdr, MAP); wstatus = Map_WriteW (ba, 8, xu->var->txhdr);
if (wstatus) { if (wstatus) {
/* tell host bus write failed */ /* tell host bus write failed */
xu->var->pcsr0 |= PCSR0_PCEI; xu->var->pcsr0 |= PCSR0_PCEI;

View file

@ -50,9 +50,13 @@ extern int32 int_req;
extern int32 int_vec[32]; extern int32 int_vec[32];
#elif defined (VM_VAX) /* VAX version */ #elif defined (VM_VAX) /* VAX version */
#error "DEUNA/DELUA not supported on VAX!" #include "vax_defs.h"
#define XU_RDX 8
#define XU_WID 16
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
#else /* PDP-11 version */ #else /* PDP-11 version */
#include "pdp11_defs.h" #include "pdp11_defs.h"
#define XU_RDX 8 #define XU_RDX 8
#define XU_WID 16 #define XU_WID 16

View file

@ -25,6 +25,7 @@
cpu PDP-4/7/9/15 central processor cpu PDP-4/7/9/15 central processor
06-Nov-04 RMS Added =n to SHOW HISTORY
26-Mar-04 RMS Fixed warning from -std=c99 26-Mar-04 RMS Fixed warning from -std=c99
14-Jan-04 RMS Fixed g_mode in XVM implementation 14-Jan-04 RMS Fixed g_mode in XVM implementation
PDP-15 index, autoincrement generate 18b addresses PDP-15 index, autoincrement generate 18b addresses
@ -543,7 +544,7 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 114688, NULL, "112K", &cpu_set_size }, { UNIT_MSIZE, 114688, NULL, "112K", &cpu_set_size },
{ UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size },
#endif #endif
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY", { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist }, &cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
@ -1966,16 +1967,23 @@ return SCPE_OK;
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{ {
int32 l, j, k, di; int32 l, j, k, di, lnt;
char *cptr = (char *) desc;
t_value sim_eval[2]; t_value sim_eval[2];
t_stat r;
struct InstHistory *h; struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw); UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC L AC MQ IR\n\n"); fprintf (st, "PC L AC MQ IR\n\n");
di = hst_p; /* work forward */ for (k = 0; k < lnt; k++) { /* print specified */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(di++) % hst_lnt]; /* entry pointer */ h = &hst[(di++) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */ if (h->pc & HIST_PC) { /* instruction? */
l = (h->lac >> 18) & 1; /* link */ l = (h->lac >> 18) & 1; /* link */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: 18b PDP Simulator Usage Subj: 18b PDP Simulator Usage
Date: 15-Jun-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -280,8 +280,9 @@ This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, display length = n SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries. The maximum length for the history is 65536 entries.
@ -596,7 +597,7 @@ RP15 options include the ability to make units write enabled or write locked:
SET RPn LOCKED set unit n write locked SET RPn LOCKED set unit n write locked
SET RPn WRITEENABLED set unit n write enabled SET RPn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The RP15 implements these registers: The RP15 implements these registers:
@ -745,7 +746,7 @@ locked.
SET DTn WRITEENABLED set unit n write enabled SET DTn WRITEENABLED set unit n write enabled
SET DTn LOCKED set unit n write locked SET DTn LOCKED set unit n write locked
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The Type 550, TC02, and TC15 support PDP-8 format, PDP-11 format, and The Type 550, TC02, and TC15 support PDP-8 format, PDP-11 format, and
18b format DECtape images. ATTACH tries to determine the tape format 18b format DECtape images. ATTACH tries to determine the tape format
@ -800,7 +801,7 @@ or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The magnetic tape controller implements these registers: The magnetic tape controller implements these registers:

View file

@ -25,6 +25,8 @@
fpp PDP-15 floating point processor fpp PDP-15 floating point processor
31-Oct-04 RMS Fixed URFST to mask low 9b of fraction
Fixed exception PC setting
10-Apr-04 RMS JEA is 15b not 18b 10-Apr-04 RMS JEA is 15b not 18b
The FP15 instruction format is: The FP15 instruction format is:
@ -205,7 +207,7 @@ DEVICE fpp_dev = {
1, 8, 1, 1, 8, 18, 1, 8, 1, 1, 8, 18,
NULL, NULL, &fp15_reset, NULL, NULL, &fp15_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DIS }; NULL, DEV_DISABLE };
/* Instruction decode for FP15 /* Instruction decode for FP15
@ -390,11 +392,11 @@ t_stat sta;
fguard = 0; /* clear guard */ fguard = 0; /* clear guard */
if (ir & FI_FP) { /* fp? */ if (ir & FI_FP) { /* fp? */
if (sta = fp15_norm (ir, a, NULL, 0)) return sta; /* normalize */ if (sta = fp15_norm (ir, a, NULL, 0)) return sta; /* normalize */
wd[1] = (a->sign << 17) | a->hi; /* hi frac */
if (ir & FI_DP) { /* dp? */ if (ir & FI_DP) { /* dp? */
numwd = 3; /* 3 words */
wd[0] = a->exp & DMASK; /* exponent */ wd[0] = a->exp & DMASK; /* exponent */
wd[2] = a->lo; } /* low frac */ wd[1] = (a->sign << 17) | a->hi; /* hi frac */
wd[2] = a->lo; /* low frac */
numwd = 3; } /* 3 words */
else { /* single */ else { /* single */
if (!(ir & FI_NORND) && (a->lo & UFP_FL_SRND)) { /* round? */ if (!(ir & FI_NORND) && (a->lo & UFP_FL_SRND)) { /* round? */
a->lo = (a->lo + UFP_FL_SRND) & UFP_FL_SMASK; a->lo = (a->lo + UFP_FL_SRND) & UFP_FL_SMASK;
@ -404,24 +406,25 @@ if (ir & FI_FP) { /* fp? */
a->exp = a->exp + 1; } } a->exp = a->exp + 1; } }
if (a->exp > 0377) return FP_OVF; /* sp ovf? */ if (a->exp > 0377) return FP_OVF; /* sp ovf? */
if (a->exp < -0400) return FP_UNF; /* sp unf? */ if (a->exp < -0400) return FP_UNF; /* sp unf? */
numwd = 2; /* 2 words */ wd[0] = (a->exp & 0777) | (a->lo & UFP_FL_SMASK); /* low frac'exp */
wd[0] = (a->exp & 0777) | a->lo; } /* low frac'exp */ wd[1] = (a->sign << 17) | a->hi; /* hi frac */
numwd = 2; } /* 2 words */
} }
else { fmb.lo = (-a->lo) & UFP_FL_MASK; /* 2's complement */ else { fmb.lo = (-a->lo) & UFP_FL_MASK; /* 2's complement */
fmb.hi = (~a->hi + (fmb.lo == 0)) & UFP_FH_MASK;/* to FMB */ fmb.hi = (~a->hi + (fmb.lo == 0)) & UFP_FH_MASK;/* to FMB */
if (ir & FI_DP) { /* dp? */ if (ir & FI_DP) { /* dp? */
numwd = 2; /* 2 words */
if (a->sign) { /* negative? */ if (a->sign) { /* negative? */
wd[0] = fmb.hi | SIGN; /* store FMB */ wd[0] = fmb.hi | SIGN; /* store FMB */
wd[1] = fmb.lo; } wd[1] = fmb.lo; }
else { /* pos, store FMA */ else { /* pos, store FMA */
wd[0] = a->hi; wd[0] = a->hi;
wd[1] = a->lo; } } wd[1] = a->lo; }
numwd = 2; } /* 2 words */
else { /* single */ else { /* single */
if (a->hi || (a->lo & SIGN)) return FP_OVF; /* check int ovf */ if (a->hi || (a->lo & SIGN)) return FP_OVF; /* check int ovf */
numwd = 1; /* 1 word */
if (a->sign) wd[0] = fmb.lo; /* neg? store FMB */ if (a->sign) wd[0] = fmb.lo; /* neg? store FMB */
else wd[0] = a->lo; } /* pos, store FMA */ else wd[0] = a->lo; /* pos, store FMA */
numwd = 1; } /* 1 word */
} }
for (i = 0; i < numwd; i++) { /* store words */ for (i = 0; i < numwd; i++) { /* store words */
if (Write (addr, wd[i], WR)) return FP_MM; if (Write (addr, wd[i], WR)) return FP_MM;
@ -483,7 +486,7 @@ while (((a->hi & UFP_FH_NORM) == 0) && /* normalize divd */
dp_lsh_1 (a, NULL); /* lsh divd, divr */ dp_lsh_1 (a, NULL); /* lsh divd, divr */
dp_lsh_1 (b, NULL); } /* can't carry out */ dp_lsh_1 (b, NULL); } /* can't carry out */
if (!(a->hi & UFP_FH_NORM) && (b->hi & UFP_FH_NORM)) { /* divr norm, divd not? */ if (!(a->hi & UFP_FH_NORM) && (b->hi & UFP_FH_NORM)) { /* divr norm, divd not? */
a->hi = a->lo = 0; /* result is 0 */ dp_swap (a, &fmq); /* quo = 0 (fmq), rem = a */
return FP_OK; } return FP_OK; }
while ((b->hi & UFP_FH_NORM) == 0) { /* normalize divr */ while ((b->hi & UFP_FH_NORM) == 0) { /* normalize divr */
dp_lsh_1 (b, NULL); /* can't carry out */ dp_lsh_1 (b, NULL); /* can't carry out */
@ -562,7 +565,7 @@ if (a->hi | a->lo) { /* divd non-zero? */
for (i = 0; (fmq.hi & UFP_FH_NORM) == 0; i++) { /* until quo */ for (i = 0; (fmq.hi & UFP_FH_NORM) == 0; i++) { /* until quo */
dp_lsh_1 (&fmq, NULL); /* left shift quo */ dp_lsh_1 (&fmq, NULL); /* left shift quo */
if (dp_cmp (a, b) >= 0) { /* sub work? */ if (dp_cmp (a, b) >= 0) { /* sub work? */
dp_sub (a, b); /* a -= b */ dp_sub (a, b); /* a = a - b */
if (i == 0) a->exp = a->exp + 1; if (i == 0) a->exp = a->exp + 1;
fmq.lo = fmq.lo | 1; } /* set quo bit */ fmq.lo = fmq.lo | 1; } /* set quo bit */
dp_lsh_1 (a, NULL); } /* left shift divd */ dp_lsh_1 (a, NULL); } /* left shift divd */
@ -768,7 +771,7 @@ PCQ_ENTRY; /* record branch */
PC = Incr_addr (PC); /* PC+1 for "JMS" */ PC = Incr_addr (PC); /* PC+1 for "JMS" */
mb = Jms_word (usmd); /* form JMS word */ mb = Jms_word (usmd); /* form JMS word */
if (Write (ma, mb, WR)) return SCPE_OK; /* store */ if (Write (ma, mb, WR)) return SCPE_OK; /* store */
PC = (jea + 1) & IAMASK; /* new PC */ PC = (ma + 1) & IAMASK; /* new PC */
return SCPE_OK; return SCPE_OK;
} }

View file

@ -25,6 +25,7 @@
cpu central processor cpu central processor
06-Nov-04 RMS Added =n to SHOW HISTORY
31-Dec-03 RMS Fixed bug in set_cpu_hist 31-Dec-03 RMS Fixed bug in set_cpu_hist
13-Oct-03 RMS Added instruction history 13-Oct-03 RMS Added instruction history
Added TSC8-75 support (from Bernhard Baehr) Added TSC8-75 support (from Bernhard Baehr)
@ -298,7 +299,7 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
{ UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", "HISTORY", { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist }, &cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
@ -1326,16 +1327,23 @@ return SCPE_OK;
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{ {
int32 l, k, di; int32 l, k, di, lnt;
char *cptr = (char *) desc;
t_stat r;
t_value sim_eval; t_value sim_eval;
struct InstHistory *h; struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw); UNIT *uptr, int32 sw);
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */ if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC L AC MQ ea IR\n\n"); fprintf (st, "PC L AC MQ ea IR\n\n");
di = hst_p; /* work forward */ for (k = 0; k < lnt; k++) { /* print specified */
for (k = 0; k < hst_lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */ h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */ if (h->pc & HIST_PC) { /* instruction? */
l = (h->lac >> 12) & 1; /* link */ l = (h->lac >> 12) & 1; /* link */

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: PDP-8 Simulator Usage Subj: PDP-8 Simulator Usage
Date: 15-Jun-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -198,8 +198,9 @@ This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, display length = n SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries. The maximum length for the history is 65536 entries.
@ -442,7 +443,7 @@ locked.
SET DTn LOCKED set unit n write locked SET DTn LOCKED set unit n write locked
SET DTn WRITEENABLED set unit n write enabled SET DTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. The TD8E supports the BOOT command. Units can also be set ENABLED or DISABLED. The TD8E supports the BOOT command.
The TD8E supports supports PDP-8 format, PDP-11 format, and 18b format The TD8E supports supports PDP-8 format, PDP-11 format, and 18b format
DECtape images. ATTACH tries to determine the tape format from the DECtape DECtape images. ATTACH tries to determine the tape format from the DECtape
@ -487,7 +488,7 @@ RK8E options include the ability to make units write enabled or write locked:
SET RKn LOCKED set unit n write locked SET RKn LOCKED set unit n write locked
SET RKn WRITEENABLED set unit n write enabled SET RKn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. The RK8E supports the BOOT command. Units can also be set ENABLED or DISABLED. The RK8E supports the BOOT command.
The RK8E implements these registers: The RK8E implements these registers:
@ -719,7 +720,7 @@ locked.
SET DTn LOCKED set unit n write locked SET DTn LOCKED set unit n write locked
SET DTn WRITEENABLED set unit n write enabled SET DTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. The TC08 supports the BOOT command. Units can also be set ENABLED or DISABLED. The TC08 supports the BOOT command.
The TC08 supports supports PDP-8 format, PDP-11 format, and 18b format The TC08 supports supports PDP-8 format, PDP-11 format, and 18b format
DECtape images. ATTACH tries to determine the tape format from the DECtape DECtape images. ATTACH tries to determine the tape format from the DECtape
@ -771,7 +772,7 @@ or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The magnetic tape controller implements these registers: The magnetic tape controller implements these registers:

View file

@ -507,7 +507,7 @@ for (i = 0; i < RL_NUMDR; i++) {
uptr = rl_dev.units + i; uptr = rl_dev.units + i;
sim_cancel (uptr); sim_cancel (uptr);
uptr->STAT = 0; } uptr->STAT = 0; }
if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int8)); if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (uint8));
if (rlxb == NULL) return SCPE_MEM; if (rlxb == NULL) return SCPE_MEM;
return SCPE_OK; return SCPE_OK;
} }

View file

@ -396,7 +396,7 @@ extern int32 dsk1 (int32 op, int32 m, int32 n, int32 data);
extern int32 dsk2 (int32 op, int32 m, int32 n, int32 data); extern int32 dsk2 (int32 op, int32 m, int32 n, int32 data);
extern int32 cpu (int32 op, int32 m, int32 n, int32 data); extern int32 cpu (int32 op, int32 m, int32 n, int32 data);
extern t_stat sim_activate (UNIT *uptr, int32 delay); extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val, extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
UNIT *uptr, int32 sw); UNIT *uptr, int32 sw);
int32 nulldev (int32 opcode, int32 m, int32 n, int32 data); int32 nulldev (int32 opcode, int32 m, int32 n, int32 data);
int add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); int add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2);

View file

@ -44,7 +44,7 @@ extern int32 saved_PC, IAR[];
extern char ebcdic_to_ascii[256]; extern char ebcdic_to_ascii[256];
char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype); char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype);
int32 printf_sym (FILE *of, char *strg, int32 addr, unsigned int32 *val, int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val,
UNIT *uptr, int32 sw); UNIT *uptr, int32 sw);
/* SCP data structures /* SCP data structures
@ -246,7 +246,7 @@ return (SCPE_OK);
status = error code status = error code
*/ */
int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val, int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
UNIT *uptr, int32 sw) UNIT *uptr, int32 sw)
{ {
int32 r; int32 r;
@ -261,7 +261,7 @@ int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val,
return (r); return (r);
} }
int32 printf_sym (FILE *of, char *strg, int32 addr, unsigned int32 *val, int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val,
UNIT *uptr, int32 sw) UNIT *uptr, int32 sw)
{ {
int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr; int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr;
@ -496,7 +496,7 @@ return -(oplen - 1);
status = error status status = error status
*/ */
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw) int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
{ {
int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr; int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr;
char gbuf[CBUFSIZE]; char gbuf[CBUFSIZE];

View file

@ -23,6 +23,12 @@
be used in advertising or otherwise to promote the sale, use or other dealings 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. in this Software without prior written authorization from Robert M Supnik.
cpu central processor
rtc real time clock
07-Nov-04 RMS Added instruction history
01-Mar-03 RMS Added SET/SHOW RTC FREQ support
The system state for the SDS 940 is: The system state for the SDS 940 is:
A<0:23> A register A<0:23> A register
@ -38,11 +44,6 @@
EM2<0:2> memory extension, block 2 EM2<0:2> memory extension, block 2
EM3<0:2> memory extension, block 3 EM3<0:2> memory extension, block 3
bpt breakpoint switches bpt breakpoint switches
cpu central processor
rtc real time clock
01-Mar-03 RMS Added SET/SHOW RTC FREQ support
*/ */
/* The SDS 940 has three instruction format -- memory reference, register change, /* The SDS 940 has three instruction format -- memory reference, register change,
@ -137,6 +138,21 @@
#define UNIT_V_MSIZE (UNIT_V_GENIE + 1) /* dummy mask */ #define UNIT_V_MSIZE (UNIT_V_GENIE + 1) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_XCT 1 /* instruction */
#define HIST_INT 2 /* interrupt cycle */
#define HIST_TRP 3 /* trap cycle */
#define HIST_MIN 64
#define HIST_MAX 65536
#define HIST_NOEA 0x40000000
struct InstHistory {
uint32 typ;
uint32 pc;
uint32 ir;
uint32 a;
uint32 b;
uint32 x;
uint32 ea; };
uint32 M[MAXMEMSIZE] = { 0 }; /* memory */ uint32 M[MAXMEMSIZE] = { 0 }; /* memory */
uint32 A, B, X; /* registers */ uint32 A, B, X; /* registers */
uint32 P; /* program counter */ uint32 P; /* program counter */
@ -169,6 +185,9 @@ int32 stop_inviop = 1; /* stop inv io op */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */ int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
struct InstHistory *hst = NULL; /* instruction history */
int32 rtc_pie = 0; /* rtc pulse ie */ int32 rtc_pie = 0; /* rtc pulse ie */
int32 rtc_tps = 60; /* rtc ticks/sec */ int32 rtc_tps = 60; /* rtc ticks/sec */
@ -181,6 +200,8 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr); t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat Ea (uint32 wd, uint32 *va); t_stat Ea (uint32 wd, uint32 *va);
t_stat EaSh (uint32 wd, uint32 *va); t_stat EaSh (uint32 wd, uint32 *va);
t_stat Read (uint32 va, uint32 *dat); t_stat Read (uint32 va, uint32 *dat);
@ -195,6 +216,7 @@ void Div48 (uint32 dvdh, uint32 dvdl, uint32 dvr);
void RotR48 (uint32 sc); void RotR48 (uint32 sc);
void ShfR48 (uint32 sc, uint32 sgn); void ShfR48 (uint32 sc, uint32 sgn);
t_stat one_inst (uint32 inst, uint32 pc, uint32 mode); t_stat one_inst (uint32 inst, uint32 pc, uint32 mode);
void inst_hist (uint32 inst, uint32 pc, uint32 typ);
t_stat rtc_inst (uint32 inst); t_stat rtc_inst (uint32 inst);
t_stat rtc_svc (UNIT *uptr); t_stat rtc_svc (UNIT *uptr);
t_stat rtc_reset (DEVICE *dptr); t_stat rtc_reset (DEVICE *dptr);
@ -262,6 +284,8 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
{ UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size }, { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 } }; { 0 } };
DEVICE cpu_dev = { DEVICE cpu_dev = {
@ -371,6 +395,7 @@ if (ion && !ion_defer && int_reqhi) { /* int request? */
tinst = ReadP (pa); /* get inst */ tinst = ReadP (pa); /* get inst */
save_mode = usr_mode; /* save mode */ save_mode = usr_mode; /* save mode */
usr_mode = 0; /* switch to mon */ usr_mode = 0; /* switch to mon */
if (hst_lnt) inst_hist (tinst, P, HIST_INT); /* record inst */
if (pa != VEC_RTCP) { /* normal intr? */ if (pa != VEC_RTCP) { /* normal intr? */
tr = one_inst (tinst, P, save_mode); /* exec intr inst */ tr = one_inst (tinst, P, save_mode); /* exec intr inst */
if (tr) { /* stop code? */ if (tr) { /* stop code? */
@ -396,6 +421,7 @@ else { /* normal instr */
P = (P + 1) & VA_MASK; /* incr PC */ P = (P + 1) & VA_MASK; /* incr PC */
if (reason == SCPE_OK) { /* fetch ok? */ if (reason == SCPE_OK) { /* fetch ok? */
ion_defer = 0; /* clear ion */ ion_defer = 0; /* clear ion */
if (hst_lnt) inst_hist (inst, save_P, HIST_XCT);
reason = one_inst (inst, save_P, usr_mode); /* exec inst */ reason = one_inst (inst, save_P, usr_mode); /* exec inst */
if (reason > 0) { /* stop code? */ if (reason > 0) { /* stop code? */
if (reason != STOP_HALT) P = save_P; if (reason != STOP_HALT) P = save_P;
@ -411,6 +437,7 @@ else { /* normal instr */
save_mode = usr_mode; /* save mode */ save_mode = usr_mode; /* save mode */
usr_mode = 0; /* switch to mon */ usr_mode = 0; /* switch to mon */
mon_usr_trap = 0; mon_usr_trap = 0;
if (hst_lnt) inst_hist (tinst, save_P, HIST_TRP);
tr = one_inst (tinst, save_P, save_mode); /* trap inst */ tr = one_inst (tinst, save_P, save_mode); /* trap inst */
if (tr) { /* stop code? */ if (tr) { /* stop code? */
usr_mode = save_mode; /* restore mode */ usr_mode = save_mode; /* restore mode */
@ -838,7 +865,9 @@ t_stat r;
for (i = 0; i < ind_lim; i++) { /* count indirects */ for (i = 0; i < ind_lim; i++) { /* count indirects */
if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK); if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK);
*addr = va; *addr = va;
if ((wd & I_IND) == 0) return SCPE_OK; /* indirect? */ if ((wd & I_IND) == 0) { /* end of ind chain? */
if (hst_lnt) hst[hst_p].ea = *addr; /* record */
return SCPE_OK; }
if (r = Read (va, &wd)) return r; /* read ind; fails? */ if (r = Read (va, &wd)) return r; /* read ind; fails? */
va = (va & VA_USR) | (wd & XVA_MASK); va = (va & VA_USR) | (wd & XVA_MASK);
} }
@ -859,6 +888,7 @@ for (i = 0; i < ind_lim; i++) { /* count indirects */
if (wd & I_IDX) *addr = (va & (VA_MASK & ~I_SHFMSK)) | if (wd & I_IDX) *addr = (va & (VA_MASK & ~I_SHFMSK)) |
((va + X) & I_SHFMSK); /* 9b indexing */ ((va + X) & I_SHFMSK); /* 9b indexing */
else *addr = va & VA_MASK; else *addr = va & VA_MASK;
if (hst_lnt) hst[hst_p].ea = *addr; /* record */
return SCPE_OK; } return SCPE_OK; }
if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK); if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK);
if (r = Read (va, &wd)) return r; /* read ind; fails? */ if (r = Read (va, &wd)) return r; /* read ind; fails? */
@ -1280,3 +1310,82 @@ t_stat rtc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz"); fprintf (st, (rtc_tps == 50)? "50Hz": "60Hz");
return SCPE_OK; return SCPE_OK;
} }
/* Record history */
void inst_hist (uint32 ir, uint32 pc, uint32 tp)
{
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].typ = tp | (OV << 4);
hst[hst_p].pc = pc;
hst[hst_p].ir = ir;
hst[hst_p].a = A;
hst[hst_p].b = B;
hst[hst_p].x = X;
hst[hst_p].ea = HIST_NOEA;
return;
}
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].typ = 0;
hst_p = 0;
return SCPE_OK; }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL; }
if (lnt) {
hst = calloc (sizeof (struct InstHistory), lnt);
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt; }
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 ov, k, di, lnt;
char *cptr = (char *) desc;
t_stat r;
t_value sim_eval;
struct InstHistory *h;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
UNIT *uptr, int32 sw);
static char *cyc[] = { " ", " ", "INT", "TRP" };
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; }
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "CYC PC OV A B X EA IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->typ) { /* instruction? */
ov = (h->typ >> 4) & 1; /* overflow */
fprintf (st, "%s %05o %o %08o %08o %08o ", cyc[h->typ & 3],
h->pc, ov, h->a, h->b, h->x);
if (h->ea & HIST_NOEA) fprintf (st, " ");
else fprintf (st, "%05o ", h->ea);
sim_eval = h->ir;
if ((fprint_sym (st, h->pc, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %08o", h->ir);
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}

View file

@ -1,7 +1,7 @@
To: Users To: Users
From: Bob Supnik From: Bob Supnik
Subj: SDS 940 Simulator Usage Subj: SDS 940 Simulator Usage
Date: 15-Feb-2004 Date: 15-Nov-2004
COPYRIGHT NOTICE COPYRIGHT NOTICE
@ -142,6 +142,17 @@ control registers for the interrupt system.
most recent P change first most recent P change first
WRU 8 interrupt character WRU 8 interrupt character
The CPU can maintain a history of the most recently executed instructions.
This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:
SET CPU HISTORY clear history buffer
SET CPU HISTORY=0 disable history
SET CPU HISTORY=n enable history, length = n
SHOW CPU HISTORY print CPU history
SHOW CPU HISTORY=n print first n entries of CPU history
The maximum length for the history is 65536 entries.
2.2 Channels (CHAN) 2.2 Channels (CHAN)
The SDS 940 has up to eight I/O channels, designated W, Y, C, D, E, F, G, The SDS 940 has up to eight I/O channels, designated W, Y, C, D, E, F, G,
@ -481,7 +492,7 @@ MT options include the ability to make units write enabled or write locked.
SET MTn LOCKED set unit n write locked SET MTn LOCKED set unit n write locked
SET MTn WRITEENABLED set unit n write enabled SET MTn WRITEENABLED set unit n write enabled
Units can also be set ONLINE or OFFLINE. Units can also be set ENABLED or DISABLED.
The magnetic tape implements these registers: The magnetic tape implements these registers:

405
VAX/vax780_defs.h Normal file
View file

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

1077
VAX/vax780_doc.txt Normal file

File diff suppressed because it is too large Load diff

699
VAX/vax780_mba.c Normal file
View file

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

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