simh v2.6

This commit is contained in:
Bob Supnik 2001-11-06 20:50:00 -08:00 committed by Mark Pizzolato
parent 062d217c67
commit 4d6dfa4bdb
107 changed files with 22745 additions and 1067 deletions

35
0readme26.txt Normal file
View file

@ -0,0 +1,35 @@
Release notes for simh V2.6
1. Register arrays
The simulator has supported register arrays for some time, but their contents
were always hidden, and register arrays had names like *BUF. Register arrays
can now be examined and modified, and the names have changed to normal form.
As a result, SAVE FILES FROM PRIOR RELEASES WILL NOT RESTORE PROPERLY, because
the previous array names won't be found. These errors will occur AFTER main
memory has been restored, so memory contents can be salvaged; but most device
state will be lost.
2. USE_INT64 instead of _INT64
As a #define, _INT64 conflicts with some compiler implementations. Therefore,
the enable switch for 64b has been changed to USE_INT64, e.g.,
% cc -o pdp10 -DUSE_INT64 pdp10_*.c,scp*.c -lm
3. int64 definition defaults to long long
If 64b is specified, the default compiler declaration for int64 is 'long long',
with exceptions for Win32 (_int64) and Digital UNIX (long).
4. Real-time clock calibration
Many of the simulators now calibrate their real-time clocks to match wall
time. This allows simulated operating systems to track wall time.
5. Calling sequence change
The calling sequence for sim_load has been changed to include the file name.
This allows simulator loaders to use different formats depending on the
extension of the load file.

211
altair.txt Normal file
View file

@ -0,0 +1,211 @@
Altair 8800 Simulator
=====================
1. Background.
The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800
was announced on the January 1975 cover of Popular Electronics, which
boasted you could buy and build this powerful computer kit for only $397.
The kit consisted at that time of only the parts to build a case, power
supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of
memory. Still, thousands were ordered within the first few months after the
announcement, starting the personal computer revolution as we know it today.
Many laugh at the small size of the that first kit, noting there
were no peripherals and the 256 byte memory size. But the computer was an
open system, and by 1977 MITS and many other small startups had added many
expansion cards to make the Altair quite a respectable little computer. The
"Altair Bus" that made this possible was soon called the S-100 Bus, later
adopted as an industry standard, and eventually became the IEE-696 Bus.
2. Hardware
We are simulating a fairly "loaded" Altair 8800 from about 1977,
with the following configuration:
device simulates
name(s)
CPU Altair 8800 with Intel 8080 CPU board, 62KB
of RAM, 2K of EPROM with start boot ROM.
2SIO 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 later Z80 CPU [At the present time
this is not fully implemented and is not to be
trusted with real Z80 software]
SET CPU ITRAP Causes the simulator to halt if an invalid 8080
Opcode is detected.
SET CPU NOITRAP Does not stop on an invalid Opcode. This is
how the real 8080 works.
SET CPU 4K
SET CPU 8K
SET CPU 12K
SET CPU 16K
......
SET CPU 64K All these set various CPU memory configurations.
The 2K EPROM at the high end of memory is always
present and will always boot.
The BOOT EPROM card starts at address 177400. Jumping to this address
will always boot drive 0 of the floppy controller. If no valid bootable
software is present there the machine crashes. This is historically
accurate behavior.
The real 8080, on receiving a HLT (Halt) instruction, freezes the processor
and only an interrupt or CPU hardware reset will restore it. The simulator
is alot nicer, it will halt but send you back to the simulator command line.
CPU Registers include the following:
name size comments
PC 16 The Program Counter
A 8 The accumulator
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. D is the top 8 bits, E is
the bottom.
HL 16 The HL register pair. H is top, L is bottom.
C 1 Carry flag.
Z 1 Zero Flag.
AC 1 Auxillary Carry flag.
P 1 Parity flag.
S 1 Sign flag.
SR 16 The front panel switches.
BREAK 16 Breakpoint address (377777 to disable).
WRU 8 The interrupt character. This starts as 005
(ctrl-E) but some Altair software uses this
keystroke so best to change this to something
exotic such as 035 (which is Ctl-]).
2.2 The Serial I/O Card (2SIO)
This simple programmed I/O device provides 2 serial ports to the
outside world, which could be hardware jumpered to support RS-232 plugs or a
TTY current loop interface. The standard I/O addresses assigned by MITS
was 20-21 (octal) for the first port, and 22-23 (octal) 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.
2.3 The 88-DISK controller.
The MITS 88-DISK is a simple programmed I/O interface to the MITS
8-inch floppy drive, which was basically a Pertec FD-400 with a power
supply and buffer board builtin. The controller supports neither interrupts
nor DMA, so floppy access required the sustained attention of the CPU.
The standard I/O addresses were 10, 11, and 12 (octal), and we follow the
standard. Details on controlling this hardware are in the altair_dsk.c
source file.
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 dsk0 altcpm.dsk
sim> go 177400
62K CP/M VERSION 2.2 (ALTAIR 8800)
A>DIR
CP/M feels like DOS, sort of. DIR will work. I have included all
the standard CP/M utilities, plus a few common public-domain ones. I also
include the sources to the customized BIOS and some other small programs.
TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better
DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to
binary format (.COM). ED is a simple editor, #A command will bring the
source file to the buffer, T command will "type" lines, L will move lines,
E exits the editor. 20L20T will move down 20 lines, and type 20. Very
DECish. DDT is the debugger, SUBMIT is a batch-type command processor.
A sample batch file that will assemble and write out the bootable CP/M
image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN".
3.2 MITS Disk Extended BASIC Version 4.1
This was the commonly used software for serious users of the Altair
computer. It is a powerful (but slow) BASIC with some extended commands to
allow it to access and manage the disk. There was no operating system it
ran under. To boot:
sim> attach dsk0 mbasic.dsk
sim> go 177400
MEMORY SIZE? [return]
LINEPRINTER? C [return]
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
NUMBER OF FILES? 3 [return]
NUMBER OF RANDOM FILES? 2 [return]
44297 BYTES FREE
ALTAIR BASIC REV. 4.1
[DISK EXTENDED VERSION]
COPYRIGHT 1977 BY MITS INC.
OK
mount 0
OK
files
3.3 Altair DOS Version 1.0
This was long promised but not delivered until it was almost
irrelevant. A short attempted tour will reveal it to be a dog, far inferior
to CP/M. To boot:
sim> attach dsk0 altdos.dsk
sim> go 177400
MEMORY SIZE? 64 [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]
056769 BYTES AVAILABLE
DOS MONITOR VER 1.0
COPYRIGHT 1977 BY MITS INC
.mnt 0
.dir 0

1179
altair_cpu.c Normal file

File diff suppressed because it is too large Load diff

24
altair_defs.h Normal file
View file

@ -0,0 +1,24 @@
/* altair_defs.h: MITS Altair simulator definitions
Copyright (c) 1997,
Charles E Owen
Commercial use prohibited
*/
#include "sim_defs.h" /* simulator defns */
/* Memory */
#define MAXMEMSIZE 65536 /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define MEM_ADDR_OK(x) (x < MEMSIZE)
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_OPCODE 4

345
altair_dsk.c Normal file
View file

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

238
altair_sio.c Normal file
View file

@ -0,0 +1,238 @@
/* altair_sio: MITS Altair serial I/O card
These functions support a simulated MITS 2SIO interface card.
The card had two physical I/O ports which could be connected
to any serial I/O device that would connect to a current loop,
RS232, or TTY interface. Available baud rates were jumper
selectable for each port from 110 to 9600.
All I/O is via programmed I/O. Each each has a status port
and a data port. A write to the status port can select
some options for the device (0x03 will reset the port).
A read of the status port gets the port status:
+---+---+---+---+---+---+---+---+
| X X X X X X O I |
+---+---+---+---+---+---+---+---+
I - A 1 in this bit position means a character has been received
on the data port and is ready to be read.
O - A 1 in this bit means the port is ready to receive a character
on the data port and transmit it out over the serial line.
A read to the data port gets the buffered character, a write
to the data port writes the character to the device.
*/
#include <stdio.h>
#include "altair_defs.h"
#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */
#define UNIT_ANSI (1 << UNIT_V_ANSI)
t_stat sio_svc (UNIT *uptr);
t_stat sio_reset (DEVICE *dptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr);
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
extern t_stat sim_activate (UNIT *uptr, int32 interval);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
/* 2SIO Standard I/O Data Structures */
UNIT sio_unit = { UDATA (&sio_svc, 0, 0),
KBD_POLL_WAIT };
REG sio_reg[] = {
{ ORDATA (DATA, sio_unit.buf, 8) },
{ ORDATA (STAT, sio_unit.u3, 8) },
{ NULL } };
MTAB sio_mod[] = {
{ UNIT_ANSI, 0, "TTY", "TTY", NULL },
{ UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL },
{ 0 } };
DEVICE sio_dev = {
"2SIO", &sio_unit, sio_reg, sio_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &sio_reset,
NULL, NULL, NULL };
UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
KBD_POLL_WAIT };
REG ptr_reg[] = {
{ ORDATA (DATA, ptr_unit.buf, 8) },
{ ORDATA (STAT, ptr_unit.u3, 8) },
{ ORDATA (POS, ptr_unit.pos, 31) },
{ NULL } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
NULL, NULL, NULL };
UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
KBD_POLL_WAIT };
REG ptp_reg[] = {
{ ORDATA (DATA, ptp_unit.buf, 8) },
{ ORDATA (STAT, ptp_unit.u3, 8) },
{ ORDATA (POS, ptp_unit.pos, 31) },
{ NULL } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL };
/* Service routines to handle simulator functions */
/* service routine - actually gets char & places in buffer */
int32 sio_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&sio_unit, sio_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
return temp; /* no char or error? */
sio_unit.buf = temp & 0377; /* Save char */
sio_unit.u3 |= 0x01; /* Set status */
/* Do any special character handling here */
sio_unit.pos++;
return SCPE_OK;
}
int32 ptr_svc (UNIT *uptr)
{
return SCPE_OK;
}
int32 ptp_svc (UNIT *uptr)
{
return SCPE_OK;
}
/* Reset routine */
int32 sio_reset (DEVICE *dptr)
{
sio_unit.buf = 0; /* Data */
sio_unit.u3 = 0x02; /* Status */
sim_activate (&sio_unit, sio_unit.wait); /* activate unit */
return SCPE_OK;
}
int32 ptr_reset (DEVICE *dptr)
{
ptr_unit.buf = 0;
ptr_unit.u3 = 0x02;
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
int32 ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
ptp_unit.u3 = 0x02;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
/* I/O instruction handlers, called from the CPU module when an
IN or OUT instruction is issued.
Each function is passed an 'io' flag, where 0 means a read from
the port, and 1 means a write to the port. On input, the actual
input is passed as the return value, on output, 'data' is written
to the device.
*/
int32 sio0s(int32 io, int32 data)
{
if (io == 0) {
return (sio_unit.u3);
} else {
if (data == 0x03) { /* reset port! */
sio_unit.u3 = 0x02;
sio_unit.buf = 0;
sio_unit.pos = 0;
}
return (0);
}
}
int32 sio0d(int32 io, int32 data)
{
if (io == 0) {
sio_unit.u3 = sio_unit.u3 & 0xFE;
return (sio_unit.buf);
} else {
sim_putchar(data);
}
}
/* Port 2 controls the PTR/PTP devices */
int32 sio1s(int32 io, int32 data)
{
if (io == 0) {
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return 0x02;
if (ptr_unit.u3 != 0) /* No more data? */
return 0x02;
return (0x03); /* ready to read/write */
} else {
if (data == 0x03) {
ptr_unit.u3 = 0;
ptr_unit.buf = 0;
ptr_unit.pos = 0;
ptp_unit.u3 = 0;
ptp_unit.buf = 0;
ptp_unit.pos = 0;
}
return (0);
}
}
int32 sio1d(int32 io, int32 data)
{
int32 temp;
UNIT *uptr;
if (io == 0) {
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return 0;
if (ptr_unit.u3 != 0)
return 0;
uptr = ptr_dev.units;
if ((temp = getc(uptr -> fileref)) == EOF) { /* end of file? */
ptr_unit.u3 = 0x01;
return 0;
}
ptr_unit.pos++;
return (temp & 0xFF);
} else {
uptr = ptp_dev.units;
putc(data, uptr -> fileref);
ptp_unit.pos++;
}
}

288
altair_sys.c Normal file
View file

@ -0,0 +1,288 @@
/* altair_sys.c: MITS Altair system interface
(C) Copyright 1997 by Charles E. Owen
Commercial use prohibited
*/
#include <ctype.h>
#include "altair_defs.h"
extern DEVICE cpu_dev;
extern DEVICE dsk_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern DEVICE sio_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE lpt_dev;
extern unsigned char M[];
extern int32 saved_PC;
extern char *get_glyph (char *cptr, char *gbuf, char term);
extern unsigned int32 get_uint (char *cptr, int32 radix, unsigned int32 max,
int32 *status);
/* SCP data structures
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words needed for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "Altair 8800";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev,
&ptp_dev, &dsk_dev, NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"Unknown I/O Instruction",
"HALT instruction",
"Breakpoint",
"Invalid Opcode" };
static const char *opcode[] = {
"NOP", "LXI B", "STAX B", "INX B", /* 000-003 */
"INR B", "DCR B", "MVI B", "RLC", /* 004-007 */
"???", "DAD B", "LDAX B", "DCX B", /* 010-013 */
"INR C", "DCR C", "MVI C", "RRC", /* 014-017 */
"???", "LXI D", "STAX D", "INX D", /* 020-023 */
"INR D", "DCR D", "MVI D", "RAL", /* 024-027 */
"???", "DAD D", "LDAX D", "DCX D", /* 030-033 */
"INR E", "DCR E", "MVI E", "RAR", /* 034-037 */
"???", "LXI H", "SHLD", "INX H", /* 040-043 */
"INR H", "DCR H", "MVI H", "DAA", /* 044-047 */
"???", "DAD H", "LHLD", "DCX H", /* 050-053 */
"INR L", "DCR L", "MVI L", "CMA", /* 054-057 */
"???", "LXI SP", "STA", "INX SP", /* 060-063 */
"INR M", "DCR M", "MVI M", "STC", /* 064-067 */
"???", "DAD SP", "LDA", "DCX SP", /* 070-073 */
"INR A", "DCR A", "MVI A", "CMC", /* 074-077 */
"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", /* 100-103 */
"MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 104-107 */
"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", /* 110-113 */
"MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 114-117 */
"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", /* 120-123 */
"MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 124-127 */
"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", /* 130-133 */
"MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 134-137 */
"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", /* 140-143 */
"MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 144-147 */
"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", /* 150-153 */
"MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 154-157 */
"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", /* 160-163 */
"MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 164-167 */
"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", /* 170-173 */
"MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 174-177 */
"ADD B", "ADD C", "ADD D", "ADD E", /* 200-203 */
"ADD H", "ADD L", "ADD M", "ADD A", /* 204-207 */
"ADC B", "ADC C", "ADC D", "ADC E", /* 210-213 */
"ADC H", "ADC L", "ADC M", "ADC A", /* 214-217 */
"SUB B", "SUB C", "SUB D", "SUB E", /* 220-223 */
"SUB H", "SUB L", "SUB M", "SUB A", /* 224-227 */
"SBB B", "SBB C", "SBB D", "SBB E", /* 230-233 */
"SBB H", "SBB L", "SBB M", "SBB A", /* 234-237 */
"ANA B", "ANA C", "ANA D", "ANA E", /* 240-243 */
"ANA H", "ANA L", "ANA M", "ANA A", /* 244-247 */
"XRA B", "XRA C", "XRA D", "XRA E", /* 250-253 */
"XRA H", "XRA L", "XRA M", "XRA A", /* 254-257 */
"ORA B", "ORA C", "ORA D", "ORA E", /* 260-263 */
"ORA H", "ORA L", "ORA M", "ORA A", /* 264-267 */
"CMP B", "CMP C", "CMP D", "CMP E", /* 270-273 */
"CMP H", "CMP L", "CMP M", "CMP A", /* 274-277 */
"RNZ", "POP B", "JNZ", "JMP", /* 300-303 */
"CNZ", "PUSH B", "ADI", "RST 0", /* 304-307 */
"RZ", "RET", "JZ", "???", /* 310-313 */
"CZ", "CALL", "ACI", "RST 1", /* 314-317 */
"RNC", "POP D", "JNC", "OUT", /* 320-323 */
"CNC", "PUSH D", "SUI", "RST 2", /* 324-327 */
"RC", "???", "JC", "IN", /* 330-333 */
"CC", "???", "SBI", "RST 3", /* 334-337 */
"RPO", "POP H", "JPO", "XTHL", /* 340-343 */
"CPO", "PUSH H", "ANI", "RST 4", /* 344-347 */
"RPE", "PCHL", "JPE", "XCHG", /* 350-353 */
"CPE", "???", "XRI", "RST 5", /* 354-357 */
"RP", "POP PSW", "JP", "DI", /* 360-363 */
"CP", "PUSH PSW", "ORI", "RST 6", /* 364-367 */
"RM", "SPHL", "JM", "EI", /* 370-373 */
"CM", "???", "CPI", "RST 7", /* 374-377 */
};
int32 oplen[256] = {
1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,
0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1,0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,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,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,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,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,1,
1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1,1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1,
1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1,1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 };
/* This is the binary loader. The input file is considered to be
a string of literal bytes with no format special format. The
load starts at the current value of the PC.
*/
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 i, addr = 0, cnt = 0;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
addr = saved_PC;
while ((i = getc (fileref)) != EOF) {
M[addr] = i;
addr++;
cnt++;
} /* end while */
printf ("%d Bytes loaded.\n", cnt);
return (SCPE_OK);
}
/* Symbolic output
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
status = error code
*/
int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val,
UNIT *uptr, int32 sw)
{
int32 cflag, c1, c2, inst, adr;
cflag = (uptr == NULL) || (uptr == &cpu_unit);
c1 = (val[0] >> 8) & 0177;
c2 = val[0] & 0177;
if (sw & SWMASK ('A')) {
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
return SCPE_OK; }
if (sw & SWMASK ('C')) {
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
return SCPE_OK; }
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
inst = val[0];
fprintf (of, "%s", opcode[inst]);
if (oplen[inst] == 2) {
if (strchr(opcode[inst], ' ') != NULL)
fprintf (of, ",");
else fprintf (of, " ");
fprintf (of, "%o", val[1]);
}
if (oplen[inst] == 3) {
adr = val[1] & 0xFF;
adr |= (val[2] << 8) & 0xff00;
if (strchr(opcode[inst], ' ') != NULL)
fprintf (of, ",");
else fprintf (of, " ");
fprintf (of, "%o", adr);
}
return -(oplen[inst] - 1);
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw)
{
int32 cflag, i = 0, j, r;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (unsigned int) cptr[0];
return SCPE_OK; }
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1];
return SCPE_OK; }
/* An instruction: get opcode (all characters until null, comma,
or numeric (including spaces).
*/
while (1) {
if (*cptr == ',' || *cptr == '\0' ||
isdigit(*cptr))
break;
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* Allow for RST which has numeric as part of opcode */
if (toupper(gbuf[0]) == 'R' &&
toupper(gbuf[1]) == 'S' &&
toupper(gbuf[2]) == 'T') {
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* Allow for 'MOV' which is only opcode that has comma in it. */
if (toupper(gbuf[0]) == 'M' &&
toupper(gbuf[1]) == 'O' &&
toupper(gbuf[2]) == 'V') {
gbuf[i] = toupper(*cptr);
cptr++;
i++;
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* kill trailing spaces if any */
gbuf[i] = '\0';
for (j = i - 1; gbuf[j] == ' '; j--) {
gbuf[j] = '\0';
}
/* find opcode in table */
for (j = 0; j < 256; j++) {
if (strcmp(gbuf, opcode[j]) == 0)
break;
}
if (j > 255) /* not found */
return SCPE_ARG;
val[0] = j; /* store opcode */
if (oplen[j] < 2) /* if 1-byter we are done */
return SCPE_OK;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0); /* get address */
sscanf(gbuf, "%o", &r);
if (oplen[j] == 2) {
val[1] = r & 0xFF;
return (-1);
}
val[1] = r & 0xFF;
val[2] = (r >> 8) & 0xFF;
return (-2);
}

24
eclipse.txt Normal file
View file

@ -0,0 +1,24 @@
Charles Owen's Eclipse Modules
1. Eclipse CPU simulator
The Eclipse CPU simulator can be used with the V2.5a Nova definitions and peripheral
modules to produce an Eclipse simulator that will run Eclipse mapped RDOS V7.5. The
compilation procedure is the same as for the Nova simulator, except:
- the symbol ECLIPSE must be defined
- the module eclipse_cpu.c must be substituted for nova_cpu.c
- the output should be named eclipse rather than nova
For example, to compile under UNIX, move nova_cpu.c out of the source directory
and then give this command:
% cc -DECLIPSE eclipse_cpu.c nova_*.c -o eclipse
2. Alternate terminal emulator
The module eclipse_tt.c can be used with either an Eclipse or Nova CPU simulator
in place of nova_tt.c. It provides a full emulation of the cursor controls on
the Dasher video terminal but requires that the underlying operating system
interpret VT100 cursor controls. Thus, it works under VMS or UNIX but not under
Windows or OS/2.

3421
eclipse_cpu.c Normal file

File diff suppressed because it is too large Load diff

382
eclipse_tt.c Normal file
View file

@ -0,0 +1,382 @@
/* eclipse_tt.c: Eclipse console terminal simulator
Copyright (c) 1993-1997,
Robert M Supnik, Digital Equipment Corporation
Commercial use prohibited
tti terminal input
tto terminal output
*/
#include "nova_defs.h"
#define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */
#define UNIT_DASHER (1 << UNIT_V_DASHER)
extern int32 int_req, dev_busy, dev_done, dev_disable;
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ttx_setmod (UNIT *uptr, int32 value);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
/* TTI data structures
tti_dev TTI device descriptor
tti_unit TTI unit descriptor
tti_reg TTI register list
ttx_mod TTI/TTO modifiers list
*/
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, 8) },
{ FLDATA (BUSY, dev_busy, INT_V_TTI) },
{ FLDATA (DONE, dev_done, INT_V_TTI) },
{ FLDATA (DISABLE, dev_disable, INT_V_TTI) },
{ FLDATA (INT, int_req, INT_V_TTI) },
{ DRDATA (POS, tti_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (MODE, tti_unit.flags, UNIT_V_DASHER), REG_HRO },
{ NULL } };
MTAB ttx_mod[] = {
{ UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod },
{ UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod },
{ 0 } };
DEVICE tti_dev = {
"TTI", &tti_unit, tti_reg, ttx_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti_reset,
NULL, NULL, NULL };
/* TTO data structures
tto_dev TTO device descriptor
tto_unit TTO unit descriptor
tto_reg TTO register list
*/
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, 8) },
{ FLDATA (BUSY, dev_busy, INT_V_TTO) },
{ FLDATA (DONE, dev_done, INT_V_TTO) },
{ FLDATA (DISABLE, dev_disable, INT_V_TTO) },
{ FLDATA (INT, int_req, INT_V_TTO) },
{ DRDATA (POS, tto_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
{ FLDATA (MODE, tto_unit.flags, UNIT_V_DASHER), REG_HRO },
{ NULL } };
DEVICE tto_dev = {
"TTO", &tto_unit, tto_reg, ttx_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto_reset,
NULL, NULL, NULL };
/* Terminal input: IOT routine */
int32 tti (int32 pulse, int32 code, int32 AC)
{
int32 iodata;
iodata = (code == ioDIA)? tti_unit.buf & 0377: 0;
switch (pulse) { /* decode IR<8:9> */
case iopS: /* start */
dev_busy = dev_busy | INT_TTI; /* set busy */
dev_done = dev_done & ~INT_TTI; /* clear done, int */
int_req = int_req & ~INT_TTI;
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_TTI; /* clear busy */
dev_done = dev_done & ~INT_TTI; /* clear done, int */
int_req = int_req & ~INT_TTI;
break; } /* end switch */
return iodata;
}
/* Unit service */
t_stat tti_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
tti_unit.buf = temp & 0177;
/* --- BEGIN MODIFIED CODE --- */
if (tti_unit.flags & UNIT_DASHER) /* translate input */
translate_in();
/* --- END MODIFIED CODE --- */
dev_busy = dev_busy & ~INT_TTI; /* clear busy */
dev_done = dev_done | INT_TTI; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
tti_unit.pos = tti_unit.pos + 1;
return SCPE_OK;
}
/* -------------------- BEGIN INSERTION -----------------------*/
int curpos = 0; /* used by translate_out() */
int row = 0, col = 0; /* ditto - for cursor positioning */
int spec200 = 0; /* signals next char is 'special' */
/* Translation: Vt100 input to D200 keycodes. */
int32 translate_in()
{
char rev = 0;
if (tti_unit.buf == '\r')
rev = '\n';
if (tti_unit.buf == '\n')
rev = '\r';
if (rev)
tti_unit.buf = rev;
}
/* -------------------- END INSERTION -----------------------*/
/* Reset routine */
t_stat tti_reset (DEVICE *dptr)
{
tti_unit.buf = 0;
dev_busy = dev_busy & ~INT_TTI; /* clear busy */
dev_done = dev_done & ~INT_TTI; /* clear done, int */
int_req = int_req & ~INT_TTI;
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
return SCPE_OK;
}
/* Terminal output: IOT routine */
int32 tto (int32 pulse, int32 code, int32 AC)
{
if (code == ioDOA) tto_unit.buf = AC & 0377;
switch (pulse) { /* decode IR<8:9> */
case iopS: /* start */
dev_busy = dev_busy | INT_TTO; /* set busy */
dev_done = dev_done & ~INT_TTO; /* clear done, int */
int_req = int_req & ~INT_TTO;
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_TTO; /* clear busy */
dev_done = dev_done & ~INT_TTO; /* clear done, int */
int_req = int_req & ~INT_TTO;
sim_cancel (&tto_unit); /* deactivate unit */
break; } /* end switch */
return 0;
}
/* Unit service */
t_stat tto_svc (UNIT *uptr)
{
int32 c, temp;
dev_busy = dev_busy & ~INT_TTO; /* clear busy */
dev_done = dev_done | INT_TTO; /* set done */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
c = tto_unit.buf & 0177;
/* --- BEGIN MODIFIED CODE --- */
if (tto_unit.flags & UNIT_DASHER) {
if ((temp = translate_out(c)) != SCPE_OK) return temp;
} else {
if ((temp = sim_putchar (c)) != SCPE_OK) return temp;
tto_unit.pos = tto_unit.pos + 1;
}
/* --- END MODIFIED CODE --- */
return SCPE_OK;
}
/* -------------------- BEGIN INSERTION -----------------------*/
/* Translation routine - D200 screen controls to VT-100 controls. */
int32 translate_out(int32 c)
{
int32 temp;
char outstr[32];
if (spec200 == 1) { /* Special terminal control seq */
spec200 = 0;
switch (c) {
case 'C': /* read model ID */
return SCPE_OK;
case 'E': /* Reverse video off */
return SCPE_OK;
case 'D': /* Reverse video on */
return SCPE_OK;
default:
return SCPE_OK;
}
}
if (curpos == 1) { /* 2nd char of cursor position */
col = c & 0x7f;
curpos++;
return (SCPE_OK);
}
if (curpos == 2) { /* 3rd char of cursor position */
row = c & 0x7f;
curpos = 0;
sprintf(outstr, "\033[%d;%dH", row+1, col+1);
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
}
switch (c) { /* Single-char command or data */
case 003: /* Blink enable */
break;
case 004: /* Blink disable */
break;
case 005: /* Read cursor address */
break;
case 010: /* Cursor home */
sprintf(outstr, "\033[1;1H");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
row = col = 0;
return (SCPE_OK);
case 012: /* Newline */
if ((temp = sim_putchar('\r')) != SCPE_OK) return temp;
tto_unit.pos += 1;
if ((temp = sim_putchar(c)) != SCPE_OK) return temp;
tto_unit.pos += 1;
col = 1;
row++;
if (row > 24) row = 1;
return (SCPE_OK);
case 013: /* Erase EOL */
sprintf(outstr, "\033[K");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
case 014: /* Erase screen */
sprintf(outstr, "\033[1;1H\033[2J");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
row = col = 0;
return (SCPE_OK);
case 015: /* CR */
if ((temp = sim_putchar(c)) != SCPE_OK) return temp;
tto_unit.pos += 1;
col = 1;
return (SCPE_OK);
case 016: /* Blink On */
sprintf(outstr, "\033[5m");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
case 017: /* Blink off */
sprintf(outstr, "\033[25m");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
case 020: /* Write cursor address */
curpos = 1;
return SCPE_OK;
case 024: /* underscore on */
sprintf(outstr, "\033[4m");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
case 025: /* underscore off */
sprintf(outstr, "\033[24m");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
break;
case 027: /* cursor up */
sprintf(outstr, "\033[A");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
row--;
if (row < 1) row = 24;
return (SCPE_OK);
case 030: /* cursor right */
sprintf(outstr, "\033[C");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
col++;
if (col > 80) {
col = 1;
row++;
if (row > 24) row = 1;
}
return (SCPE_OK);
case 031: /* Cursor left */
sprintf(outstr, "\033[D");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
tto_unit.pos += 1;
col--;
if (col < 1) {
col = 80;
row--;
if (row < 1) row = 24;
}
return (SCPE_OK);
case 032: /* Cursor down */
sprintf(outstr, "\033[B");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
row++;
if (row > 24) row = 1;
return (SCPE_OK);
case 034: /* Dim on */
sprintf(outstr, "\033[22m");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
case 035: /* Dim off */
sprintf(outstr, "\033[1m");
if ((temp = putseq(outstr)) != SCPE_OK) return temp;
return (SCPE_OK);
case 036: /* Special sequence */
spec200 = 1;
return SCPE_OK;
default: /* ..A character of data */
if ((temp = sim_putchar(c)) != SCPE_OK) return temp;
tto_unit.pos += 1;
col++;
if (col > 80) {
col = 1;
row++;
if (row > 24) row = 24;
}
return (SCPE_OK);
}
return SCPE_OK;
}
int32 putseq(char *seq)
{
int i, len, temp;
len = strlen(seq);
for (i = 0; i < len; i++) {
if ((temp = sim_putchar(seq[i])) != SCPE_OK)
return temp;
tto_unit.pos += 1;
}
return SCPE_OK;
}
/* -------------------- END INSERTION -----------------------*/
/* Reset routine */
t_stat tto_reset (DEVICE *dptr)
{
tto_unit.buf = 0;
dev_busy = dev_busy & ~INT_TTO; /* clear busy */
dev_done = dev_done & ~INT_TTO; /* clear done, int */
int_req = int_req & ~INT_TTO;
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ttx_setmod (UNIT *uptr, int32 value)
{
tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | value;
tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | value;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* hp2100_cpu.c: HP 2100 CPU simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -246,7 +246,7 @@
#define UNIT_V_21MX (UNIT_V_UF + 2) /* 21MX vs 2100 */
#define UNIT_21MX (1 << UNIT_V_21MX)
unsigned int16 M[MAXMEMSIZE] = { 0 }; /* memory */
uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
int32 saved_AR = 0; /* A register */
int32 saved_BR = 0; /* B register */
int32 PC = 0; /* P register */

View file

@ -1,6 +1,6 @@
/* hp2100_defs.h: HP 2100 simulator definitions
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* hp2100_dp.c: HP 2100 disk pack simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -100,7 +100,7 @@
STA_HUNT + STA_SKI + STA_SKE + STA_NRDY + STA_EOC + \
STA_FLG + STA_DTE)
extern unsigned int16 M[];
extern uint16 M[];
extern struct hpdev infotab[];
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
@ -115,7 +115,7 @@ int32 dpc_rarc = 0, dpc_rarh = 0, dpc_rars = 0; /* record addr */
int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */
int32 dpc_obuf = 0; /* cch buffers */
int32 dp_ptr = 0; /* buffer ptr */
unsigned int16 dp_buf[DP_NUMWD]; /* sector buffer */
uint16 dp_buf[DP_NUMWD]; /* sector buffer */
t_stat dpc_svc (UNIT *uptr);
t_stat dpc_reset (DEVICE *dptr);
@ -541,7 +541,7 @@ dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear rar */
infotab[inDPC].cmd = infotab[inDPD].cmd = 0; /* clear cmd */
infotab[inDPC].ctl = infotab[inDPD].ctl = 0; /* clear ctl */
infotab[inDPC].fbf = infotab[inDPD].fbf = 1; /* set fbf */
infotab[inDPC].flg = infotab[inDPD].flg = 1; /* set fbf */
infotab[inDPC].flg = infotab[inDPD].flg = 1; /* set flg */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
sim_cancel (&dpc_unit[i]); /* cancel activity */
dpc_unit[i].FNC = 0; /* clear function */
@ -602,4 +602,4 @@ t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
if (addr >= DP_NUMWD) return SCPE_NXM;
dp_buf[addr] = val & DMASK;
return SCPE_OK;
}
}

View file

@ -1,6 +1,6 @@
/* hp2100_lp.c: HP 2100 line printer simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* hp2100_mt.c: HP 2100 magnetic tape simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -78,7 +78,7 @@
#define STA_PAR 0002 /* parity error */
#define STA_BUSY 0001 /* busy */
extern unsigned int16 M[];
extern uint16 M[];
extern struct hpdev infotab[];
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
@ -89,7 +89,7 @@ int32 mtc_1st = 0; /* first svc flop */
int32 mtc_ctime = 1000; /* command wait */
int32 mtc_xtime = 10; /* data xfer time */
int32 mtc_stopioe = 1; /* stop on error */
unsigned int8 mt_buf[DBSIZE] = { 0 }; /* data buffer */
uint8 mt_buf[DBSIZE] = { 0 }; /* data buffer */
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
static const int32 mtc_cmd[] = {
FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM };
@ -468,4 +468,4 @@ t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
if (addr >= DBSIZE) return SCPE_NXM;
mt_buf[addr] = val & 0377;
return SCPE_OK;
}
}

View file

@ -1,6 +1,6 @@
/* hp2100_stddev.c: HP2100 standard devices
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -49,7 +49,7 @@
#define CLK_V_ERROR 4 /* clock overrun */
#define CLK_ERROR (1 << CLK_V_ERROR)
extern unsigned int16 M[];
extern uint16 M[];
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern UNIT cpu_unit;

View file

@ -1,6 +1,6 @@
/* hp2100_sys.c: HP 2100 simulator interface
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
14-Mar-01 RMS Revised load/dump interface (again)
30-Oct-00 RMS Added examine to file support
15-Oct-00 RMS Added dynamic device number support
27-Oct-98 RMS V2.4 load interface
@ -39,7 +40,7 @@ extern DEVICE tty_dev, clk_dev, lpt_dev;
extern DEVICE mtd_dev, mtc_dev;
extern DEVICE dpd_dev, dpc_dev;
extern REG cpu_reg[];
extern unsigned int16 M[];
extern uint16 M[];
/* SCP data structures and interface routines
@ -98,7 +99,7 @@ if ((c2 = fgetc (fileref)) == EOF) return -1;
return ((c1 & 0377) << 8) | (c2 & 0377);
}
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 origin, csum, zerocnt, count, word, i;

View file

@ -1,6 +1,6 @@
/* i1401_cd.c: IBM 1402 card reader/punch
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -34,12 +34,14 @@
Cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files.
13-Apr-01 RMS Revised for register arrays
*/
#include "i1401_defs.h"
#include <ctype.h>
extern unsigned char M[];
extern uint8 M[];
extern int32 ind[64], ssa, iochk;
extern char bcd_to_ascii[64];
extern char ascii_to_bcd[128];
@ -49,9 +51,6 @@ t_stat cdr_svc (UNIT *uptr);
t_stat cdr_boot (int32 unitno);
t_stat cdr_attach (UNIT *uptr, char *cptr);
t_stat cd_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
/* Card reader data structures
@ -70,7 +69,7 @@ REG cdr_reg[] = {
{ FLDATA (S2, s2sel, 0) },
{ DRDATA (POS, cdr_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },
{ BRDATA (*BUF, rbuf, 8, 8, CDR_WIDTH), REG_HRO },
{ BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },
{ NULL } };
DEVICE cdr_dev = {

View file

@ -1,6 +1,6 @@
/* i1401_cpu.c: IBM 1401 CPU simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -124,7 +124,7 @@
oldIS = saved_IS; \
IS = AS;
unsigned char M[MAXMEMSIZE] = { 0 }; /* main memory */
uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */
int32 saved_IS = 0; /* saved IS */
int32 AS = 0; /* AS */
int32 BS = 0; /* BS */

View file

@ -1,6 +1,6 @@
/* i1401_defs.h: IBM 1401 simulator definitions
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* i1401_iq.c: IBM 1407 inquiry terminal
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -30,7 +30,7 @@
#include <ctype.h>
extern volatile int32 stop_cpu;
extern unsigned char M[];
extern uint8 M[];
extern int32 BS, iochk, ind[64];
extern char ascii_to_bcd[128], bcd_to_ascii[64];
extern UNIT cpu_unit;
@ -38,7 +38,6 @@ int32 inq_char = 033; /* request inq */
t_stat inq_svc (UNIT *uptr);
t_stat inq_reset (DEVICE *dptr);
void puts_tty (char *cptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
@ -117,7 +116,6 @@ case BCD_W: /* output */
return SCPE_OK;
default:
return STOP_INVM; } /* invalid mod */
return SCPE_OK;
}
/* Unit service - polls for WRU or inquiry request */

View file

@ -1,6 +1,6 @@
/* i1401_lp.c: IBM 1403 line printer simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -22,11 +22,15 @@
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.
lpt 1403 line printer
13-Apr-01 RMS Revised for register arrays
*/
#include "i1401_defs.h"
extern unsigned char M[];
extern uint8 M[];
extern char bcd_to_ascii[64];
extern int32 iochk, ind[64];
int32 cct[CCT_LNT] = { 03 };
@ -80,7 +84,7 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ FLDATA (ERR, ind[IN_LPT], 0) },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ BRDATA (*CCT, cct, 8, 32, CCT_LNT), REG_HRO },
{ BRDATA (CCT, cct, 8, 32, CCT_LNT) },
{ DRDATA (LINES, lines, 8), PV_LEFT },
{ DRDATA (CCTP, cctptr, 8), PV_LEFT },
{ DRDATA (CCTL, cctlnt, 8), REG_RO + PV_LEFT },

View file

@ -1,6 +1,6 @@
/* IBM 1401 magnetic tape simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
18-Apr-01 RMS Changed to rewind tape before boot
07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt
CEO Added tape bootstrap
14-Apr-99 RMS Changed t_addr to unsigned
@ -50,7 +51,7 @@
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_W_UF 2 /* #save flags */
extern unsigned char M[]; /* memory */
extern uint8 M[]; /* memory */
extern int32 ind[64];
extern int32 BS, iochk;
extern UNIT cpu_unit;
@ -58,8 +59,6 @@ unsigned int8 dbuf[MAXMEMSIZE * 2]; /* tape buffer */
t_stat mt_reset (DEVICE *dptr);
t_stat mt_boot (int32 unitno);
UNIT *get_unit (int32 unit);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* MT data structures
@ -286,6 +285,7 @@ t_stat mt_boot (int32 unitno)
int32 i;
extern int32 saved_IS;
mt_unit[unitno].pos = 0;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
M[BOOT_START + 3] = unitno & 07;
saved_IS = BOOT_START;

View file

@ -1,6 +1,6 @@
/* i1401_sys.c: IBM 1401 simulator interface
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
14-Mar-01 RMS Revised load/dump interface (again)
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
*/
@ -36,7 +37,7 @@ extern DEVICE cdr_dev, cdp_dev, stack_dev;
extern DEVICE mt_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern unsigned char M[];
extern uint8 M[];
extern char bcd_to_ascii[64], ascii_to_bcd[128];
extern char *get_glyph (char *cptr, char *gbuf, char term);
extern int32 store_addr_h (int32 addr);
@ -97,7 +98,7 @@ const char *sim_stop_messages[] = {
number of entries
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
t_stat r;

View file

@ -1,6 +1,6 @@
/* id4_cpu.c: Interdata 4 CPU simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -121,9 +121,9 @@
PC = ReadW ((n) + 2); \
CC = PSW & CC_MASK
unsigned int16 M[MAXMEMSIZE >> 1] = { 0 }; /* memory */
uint16 M[MAXMEMSIZE >> 1] = { 0 }; /* memory */
int32 R[16] = { 0 }; /* general registers */
unsigned int32 F[8] = { 0 }; /* fp registers */
uint32 F[8] = { 0 }; /* fp registers */
int32 PSW = 0; /* processor status word */
int32 saved_PC = 0; /* program counter */
int32 SR = 0; /* switch register */

View file

@ -1,6 +1,6 @@
/* id4_defs.h: Interdata 4 simulator definitions
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* id4_fp.c: Interdata 4 floating point instructions
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -69,16 +69,21 @@ struct ufp { /* unpacked fp */
#define FP_ROUND 0x80000000
#define FP_DMASK 0xFFFFFFFF
#define FP_SHFR(v,s) if ((s) < 32) { \
/* Variable and constant shifts; for constants, 0 < k < 32 */
#define FP_SHFR_V(v,s) if ((s) < 32) { \
v.frl = ((v.frl >> (s)) | \
(v.frh << (32 - (s)))) & FP_DMASK; \
v.frh = (v.frh >> (s)) & FP_DMASK; } \
else { v.frl = v.frh >> ((s) - 32); \
v.frh = 0; }
v.frh = 0; }
#define FP_SHFR_K(v,s) v.frl = ((v.frl >> (s)) | \
(v.frh << (32 - (s)))) & FP_DMASK; \
v.frh = (v.frh >> (s)) & FP_DMASK
extern int32 R[16];
extern unsigned int32 F[8];
extern unsigned int16 M[];
extern uint32 F[8];
extern uint16 M[];
void ReadFP2 (struct ufp *fop, int32 op, int32 r2, int32 ea);
void UnpackFP (struct ufp *fop, unsigned int32 val);
void NormFP (struct ufp *fop);
@ -130,7 +135,7 @@ else if (fop2.frh != 0) { /* if op2 = 0, no add */
fop1 = t; }
if (ediff = fop1.exp - fop2.exp) { /* exp differ? */
if (ediff > 14) fop2.frh = 0; /* limit shift */
else { FP_SHFR (fop2, ediff * 4); } }
else { FP_SHFR_V (fop2, ediff * 4); } }
if (fop1.sign ^ fop2.sign) { /* eff subtract */
fop1.frl = 0 - fop2.frl; /* sub fractions */
fop1.frh = fop1.frh - fop2.frh - (fop1.frl != 0);
@ -138,7 +143,7 @@ else if (fop2.frh != 0) { /* if op2 = 0, no add */
else { fop1.frl = fop2.frl; /* add fractions */
fop1.frh = fop1.frh + fop2.frh;
if (fop1.frh & FP_CARRY) { /* carry out? */
FP_SHFR (fop1, 4); /* renormalize */
FP_SHFR_K (fop1, 4); /* renormalize */
fop1.exp = fop1.exp + 1; } } /* incr exp */
} /* end if fop2 */
return StoreFP (&fop1, r1); /* store result */
@ -269,4 +274,4 @@ F[r1 >> 1] = ((fop -> sign & FP_M_SIGN) << FP_V_SIGN) | /* pack result */
if (fop -> sign) return CC_L; /* generate cc's */
if (F[r1 >> 1]) return CC_G;
return 0;
}
}

View file

@ -1,6 +1,6 @@
/* id4_stddev.c: Interdata 4 standard devices
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -33,7 +33,7 @@
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
extern unsigned int16 M[];
extern uint16 M[];
extern int32 int_req[INTSZ], int_enb[INTSZ];
int32 pt_run = 0, pt_slew = 0; /* ptr modes */
int pt_rw = 0, pt_busy = 0; /* pt state */

View file

@ -1,6 +1,6 @@
/* id4_sys.c: Interdata 4 simulator interface
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
14-Mar-01 RMS Revised load/dump interface (again)
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
*/
@ -34,7 +35,7 @@ extern DEVICE cpu_dev;
extern DEVICE pt_dev, tt_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern unsigned int16 *M;
extern uint16 *M;
extern int32 saved_PC;
/* SCP data structures and interface routines
@ -69,7 +70,7 @@ const char *sim_stop_messages[] = {
To be specified
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
return SCPE_FMT; /* unexpected eof */
}

View file

@ -1,81 +0,0 @@
/* This program converts a pre V2.3 simulated magtape to a V2.3 magtape
Copyright (c) 1993-1999, 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.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, k, wc, fc, rc;
unsigned char bc[4] = { 0 };
unsigned char buf[FLPSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fc = 1; rc = 0;
for (;;) {
k = fread (bc, sizeof (char), 2, ifile);
if (k == 0) break;
wc = ((unsigned int) bc[1] << 8) | (unsigned int) bc[0];
wc = (wc + 1) & ~1;
fwrite (bc, sizeof (char), 4, ofile);
if (wc) {
k = fread (buf, sizeof (char), wc, ifile);
for ( ; k < wc; k++) buf[k] =0;
fwrite (buf, sizeof (char), wc, ofile);
fwrite (bc, sizeof (char), 4, ofile);
rc++; }
else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc);
else printf ("End of tape\n");
fc++;
rc = 0; }
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

View file

@ -1,6 +1,6 @@
/* nova_clk.c: NOVA real-time clock simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,18 +23,22 @@
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.
24-Sep-97 RMS Fixed bug in unit service (found by Charles Owen)
clk real-time clock
05-Mar-01 RMS Added clock calibration
24-Sep-97 RMS Fixed bug in unit service (found by Charles Owen)
*/
#include "nova_defs.h"
extern int32 int_req, dev_busy, dev_done, dev_disable;
int32 clk_sel = 0; /* selected freq */
int32 clk_alt_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */
int32 clk_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */
int32 clk_tps[4] = { 60, 10, 100, 1000 }; /* ticks per sec */
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
extern int32 sim_rtc_init (int32 time);
extern int32 sim_rtc_calb (int32 tps);
/* CLK data structures
@ -43,7 +47,7 @@ t_stat clk_reset (DEVICE *dptr);
clk_reg CLK register list
*/
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
UNIT clk_unit = { UDATA (&clk_svc, 0, 0) };
REG clk_reg[] = {
{ ORDATA (SELECT, clk_sel, 2) },
@ -51,10 +55,10 @@ REG clk_reg[] = {
{ FLDATA (DONE, dev_done, INT_V_CLK) },
{ FLDATA (DISABLE, dev_disable, INT_V_CLK) },
{ FLDATA (INT, int_req, INT_V_CLK) },
{ DRDATA (TIME0, clk_alt_time[0], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME1, clk_alt_time[1], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME2, clk_alt_time[2], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME3, clk_alt_time[3], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME0, clk_time[0], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME1, clk_time[1], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME2, clk_time[2], 24), REG_NZ + PV_LEFT },
{ DRDATA (TIME3, clk_time[3], 24), REG_NZ + PV_LEFT },
{ NULL } };
DEVICE clk_dev = {
@ -67,13 +71,17 @@ DEVICE clk_dev = {
int32 clk (int32 pulse, int32 code, int32 AC)
{
if (code == ioDOA) clk_sel = AC & 3;
if (code == ioDOA) { /* DOA */
clk_sel = AC & 3; /* save select */
sim_rtc_init (clk_time[clk_sel]); } /* init calibr */
switch (pulse) { /* decode IR<8:9> */
case iopS: /* start */
dev_busy = dev_busy | INT_CLK; /* set busy */
dev_done = dev_done & ~INT_CLK; /* clear done, int */
int_req = int_req & ~INT_CLK;
sim_activate (&clk_unit, clk_alt_time[clk_sel]); /* activate unit */
if (!sim_is_active (&clk_unit)) /* not running? */
sim_activate (&clk_unit, /* activate */
sim_rtc_init (clk_time[clk_sel])); /* init calibr */
break;
case iopC: /* clear */
dev_busy = dev_busy & ~INT_CLK; /* clear busy */
@ -91,7 +99,8 @@ t_stat clk_svc (UNIT *uptr)
dev_done = dev_done | INT_CLK; /* set done */
dev_busy = dev_busy & ~INT_CLK; /* clear busy */
int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
sim_activate (&clk_unit, clk_alt_time[clk_sel]); /* reactivate unit */
sim_activate (&clk_unit, /* reactivate unit */
sim_rtc_calb (clk_tps[clk_sel])); /* calibrate delay */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* nova_cpu.c: NOVA CPU simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,10 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu Nova central processor
26-Apr-01 RMS Added device enable/disable support
05-Mar-01 RMS Added clock calibration
22-Dec-00 RMS Added Bruce Ray's second terminal
15-Dec-00 RMS Added Charles Owen's CPU bootstrap
08-Dec-00 RMS Changes from Bruce Ray
@ -219,7 +223,7 @@
#define UNIT_V_MSIZE (UNIT_V_UF+3) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
unsigned int16 M[MAXMEMSIZE] = { 0 }; /* memory */
uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
int32 AC[4] = { 0 }; /* accumulators */
int32 C = 0; /* carry flag */
int32 saved_PC = 0; /* program counter */
@ -229,6 +233,7 @@ int32 SR = 0; /* switch register */
int32 dev_done = 0; /* device done flags */
int32 dev_busy = 0; /* device busy flags */
int32 dev_disable = 0; /* int disable flags */
int32 iot_enb = -1; /* IOT enables */
int32 int_req = 0; /* interrupt requests */
int32 pimask = 0; /* priority int mask */
int32 pwr_low = 0; /* power fail flag */
@ -333,6 +338,7 @@ REG cpu_reg[] = {
{ ORDATA (OLDPC, old_PC, 15), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 16) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (IOTENB, iot_enb, 32), REG_HRO },
{ NULL } };
MTAB cpu_mod[] = {
@ -362,6 +368,8 @@ extern int32 sim_interval;
register int32 PC, IR, i;
register t_stat reason;
void mask_out (int32 mask);
extern int32 clk_sel, clk_time[4];
extern int32 sim_rtc_init (int32 time);
/* Restore register state */
@ -369,6 +377,7 @@ PC = saved_PC & AMASK; /* load local PC */
C = C & CBIT;
mask_out (pimask); /* reset int system */
reason = 0;
sim_rtc_init (clk_time[clk_sel]); /* init calibration */
/* Main instruction fetch/decode loop */
@ -774,10 +783,12 @@ else { /* IOT */
int_req = int_req & ~INT_ION;
break; } /* end switch pulse */
} /* end CPU control */
else { /* normal device */
else if ((dev_table[device].mask == 0) ||
(dev_table[device].mask & iot_enb)) { /* normal device */
iodata = dev_table[device].routine (pulse, code, AC[dstAC]);
reason = iodata >> IOT_V_REASON;
if (code & 1) AC[dstAC] = iodata & 0177777; }
else reason = stop_dev;
} /* end if IOT */
} /* end while */

View file

@ -1,6 +1,6 @@
/* nova_defs.h: NOVA/Eclipse simulator definitions
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -171,9 +171,9 @@
*/
struct ndev {
int mask; /* done/busy mask */
int pi; /* assigned pi bit */
int (*routine)(); /* dispatch routine */
int32 mask; /* done/busy mask */
int32 pi; /* assigned pi bit */
int32 (*routine)(); /* dispatch routine */
};
/* Device flags (simulator representation)

View file

@ -1,6 +1,6 @@
/* nova_dkp.c: NOVA moving head disk simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,13 +25,14 @@
dkp moving head disk
26-Apr-01 RMS Added device enable/disable support
12-Dec-00 RMS Added Eclipse support from Charles Owen
15-Oct-00 RMS Editorial changes
14-Apr-99 RMS Changed t_addr to unsigned
15-Sep-97 RMS Fixed bug in DIB/DOB for new disks
15-Sep-97 RMS Fixed bug in cylinder extraction (found by Charles Owen)
10-Sep-97 RMS Fixed bug in error reporting (found by Charles Owen)
25-Nov-96 RMS Defaults to autosize
25-Nov-96 RMS Defaulted to autosize
29-Jun-96 RMS Added unit disable support
*/
@ -267,16 +268,15 @@ struct drvtyp drv_tab[] = {
{ SECT_4231, SURF_4231, CYL_4231, SIZE_4231, NFMT_4231 },
{ 0 } };
extern unsigned int16 M[];
extern uint16 M[];
extern UNIT cpu_unit;
extern int32 int_req, dev_busy, dev_done, dev_disable;
extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb;
int32 dkp_ma = 0; /* memory address */
int32 dkp_ussc = 0; /* unit/sf/sc/cnt */
int32 dkp_fccy = 0; /* flags/cylinder */
int32 dkp_sta = 0; /* status register */
int32 dkp_swait = 100; /* seek latency */
int32 dkp_rwait = 100; /* rotate latency */
static unsigned int16 tbuf[DKP_NUMWD]; /* transfer buffer */
t_stat dkp_svc (UNIT *uptr);
t_stat dkp_reset (DEVICE *dptr);
t_stat dkp_boot (int32 unitno);
@ -330,6 +330,7 @@ REG dkp_reg[] = {
{ DRDATA (CAPAC1, dkp_unit[1].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC2, dkp_unit[2].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC3, dkp_unit[3].capac, 32), PV_LEFT + REG_HRO },
{ FLDATA (*DEVENB, iot_enb, INT_V_DKP), REG_HRO },
{ NULL } };
MTAB dkp_mod[] = {
@ -556,6 +557,7 @@ int32 sc, sa, xcsa, awc, bda;
int32 sx, dx, pa;
int32 dtype, u, err, newsect, newsurf;
t_stat rval;
static uint16 tbuf[DKP_NUMWD]; /* transfer buffer */
rval = SCPE_OK;
dtype = GET_DTYPE (uptr -> flags); /* get drive type */
@ -594,22 +596,22 @@ else { sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */
if (uptr -> FUNC == FCCY_READ) { /* read? */
for (sx = 0; sx < sc; sx++) { /* loop thru sectors */
awc = fxread (&tbuf, sizeof(uint16), DKP_NUMWD, uptr -> fileref);
awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr -> fileref);
for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0;
if (err = ferror (uptr -> fileref)) break;
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */
if (err = ferror (uptr -> fileref)) break;
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */
pa = MapAddr (0, dkp_ma);
if (MEM_ADDR_OK (pa)) M[pa] = tbuf[dx];
dkp_ma = (dkp_ma + 1) & AMASK; } } }
if (uptr -> FUNC == FCCY_WRITE) { /* write? */
for (sx = 0; sx < sc; sx++) { /* loop thru sectors */
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */
for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */
pa = MapAddr (0, dkp_ma);
tbuf[dx] = M[pa];
dkp_ma = (dkp_ma + 1) & AMASK; }
fxwrite (&tbuf, sizeof(int16), DKP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break; } }
fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break; } }
if (err != 0) {
perror ("DKP I/O error");

View file

@ -1,6 +1,6 @@
/* nova_dsk.c: 4019 fixed head disk simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
dsk fixed head disk
26-Apr-01 RMS Added device enable/disable support
10-Dec-00 RMS Added Eclipse support
15-Oct-00 RMS Editorial changes
14-Apr-99 RMS Changed t_addr to unsigned
@ -74,9 +75,9 @@ static const int32 sector_map[] = {
#define GET_SECTOR(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DSK_NUMSC)))
extern unsigned int16 M[];
extern uint16 M[];
extern UNIT cpu_unit;
extern int32 int_req, dev_busy, dev_done, dev_disable;
extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb;
int32 dsk_stat = 0; /* status register */
int32 dsk_da = 0; /* disk address */
int32 dsk_ma = 0; /* memory address */
@ -114,6 +115,7 @@ REG dsk_reg[] = {
{ ORDATA (WLK, dsk_wlk, 8) },
{ DRDATA (TIME, dsk_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, dsk_stopioe, 0) },
{ FLDATA (*DEVENB, iot_enb, INT_V_DSK), REG_HRO },
{ NULL } };
DEVICE dsk_dev = {

View file

@ -1,6 +1,6 @@
/* nova_lp.c: NOVA line printer simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* nova_mta.c: NOVA magnetic tape simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,12 +25,14 @@
mta magnetic tape
26-Apr-01 RMS Added device enable/disable support
18-Apr-01 RMS Changed to rewind tape before boot
10-Dec-00 RMS Added Eclipse support from Charles Owen
15-Oct-00 RMS Editorial changes
11-Nov-98 CEO Removed clear of mta_ma on iopC
04-Oct-98 RMS V2.4 magtape format
18-Jan-97 RMS V2.3 magtape format
29-Jun-96 RMS Added unit disable support
29-Jun-96 RMS Added unit enable/disable support
Magnetic tapes are represented as a series of variable records
of the form:
@ -130,9 +132,9 @@
#define STA_MON (STA_REW | STA_BOT | STA_WLK | STA_RDY | \
STA_PEM) /* set status chg */
extern unsigned int16 M[];
extern uint16 M[];
extern UNIT cpu_unit;
extern int32 int_req, dev_busy, dev_done, dev_disable;
extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb;
int32 mta_ma = 0; /* memory address */
int32 mta_wc = 0; /* word count */
int32 mta_cu = 0; /* command/unit */
@ -221,6 +223,7 @@ REG mta_reg[] = {
REG_HRO },
{ GRDATA (FLG7, mta_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (*DEVENB, iot_enb, INT_V_MTA), REG_HRO },
{ NULL } };
MTAB mta_mod[] = {
@ -318,8 +321,8 @@ t_stat mta_svc (UNIT *uptr)
int32 c, i, p, u, pa, err;
t_stat rval;
t_mtrlnt cbc, tbc, wc;
unsigned int16 c1, c2;
unsigned int8 dbuf[2 * DTSIZE];
uint16 c1, c2;
static uint8 dbuf[2 * DTSIZE];
static t_mtrlnt bceof = { 0 };
rval = SCPE_OK;
@ -593,6 +596,7 @@ t_stat mta_boot (int32 unitno)
int32 i;
extern int32 saved_PC;
mta_unit[unitno].pos = 0;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
M[BOOT_UNIT] = (unitno & CU_M_UNIT) << CU_V_UNIT;
saved_PC = BOOT_START;

View file

@ -1,6 +1,6 @@
/* nova_plt.c: NOVA plotter simulator
Copyright (c) 2000, Robert M. Supnik
Copyright (c) 2000-2001, Robert M. Supnik
Written by Bruce Ray and used with his gracious permission.
Permission is hereby granted, free of charge, to any person obtaining a
@ -23,11 +23,15 @@
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.
plt plotter
26-Apr-01 RMS Added device enable/disable support
*/
#include "nova_defs.h"
extern int32 int_req, dev_busy, dev_done, dev_disable;
extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb;
int32 plt_stopioe = 0; /* stop on error */
t_stat plt_svc (UNIT *uptr);
t_stat plt_reset (DEVICE *dptr);
@ -51,6 +55,7 @@ REG plt_reg[] = {
{ DRDATA (POS, plt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, plt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, plt_stopioe, 0) },
{ FLDATA (*DEVENB, iot_enb, INT_V_PLT), REG_HRO },
{ NULL } };
DEVICE plt_dev = {

View file

@ -1,6 +1,6 @@
/* nova_pt.c: NOVA paper tape read/punch simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* nova_sys.c: NOVA simulator interface
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
14-Mar-01 RMS Revised load/dump interface (again)
22-Dec-00 RMS Added second terminal support
10-Dec-00 RMS Added Eclipse support
08-Dec-00 BKR Added plotter support
@ -49,7 +50,7 @@ extern DEVICE clk_dev, lpt_dev;
extern DEVICE dkp_dev, dsk_dev;
extern DEVICE mta_dev;
extern REG cpu_reg[];
extern unsigned int16 M[];
extern uint16 M[];
extern int32 saved_PC;
/* SCP data structures
@ -119,7 +120,7 @@ const char *sim_stop_messages[] = {
If the word count is >1, the block is an error block.
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 data, csum, count, state, i;
t_addr origin;

View file

@ -1,6 +1,6 @@
/* nova_tt.c: NOVA console terminal simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -1,6 +1,6 @@
/* nova_tt1.c: NOVA second terminal simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Written by Bruce Ray and used with his gracious permission.
Permission is hereby granted, free of charge, to any person obtaining a
@ -26,6 +26,8 @@
tti1 second terminal input
tto1 second terminal output
26-Apr-01 RMS Added device enable/disable support
*/
#include "nova_defs.h"
@ -33,7 +35,7 @@
#define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */
#define UNIT_DASHER (1 << UNIT_V_DASHER)
extern int32 int_req, dev_busy, dev_done, dev_disable;
extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb;
int32 tti1_stopioe = 0, tto1_stopioe = 0; /* stop on error */
t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
@ -63,6 +65,7 @@ REG tti1_reg[] = {
{ DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, tti1_stopioe, 0) },
{ FLDATA (MODE, tti1_unit.flags, UNIT_V_DASHER), REG_HRO },
{ FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO },
{ NULL } };
MTAB ttx1_mod[] = {
@ -95,6 +98,7 @@ REG tto1_reg[] = {
{ DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, tto1_stopioe, 0) },
{ FLDATA (MODE, tto1_unit.flags, UNIT_V_DASHER), REG_HRO },
{ FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO },
{ NULL } };
DEVICE tto1_dev = {

2063
pdp10_cpu.c Normal file

File diff suppressed because it is too large Load diff

626
pdp10_defs.h Normal file
View file

@ -0,0 +1,626 @@
/* pdp10_defs.h: PDP-10 simulator definitions
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "sim_defs.h" /* simulator defns */
/* Digital Equipment Corporation's 36b family had six implementations:
name mips comments
PDP-6 0.25 Original 36b implementation, 1964
KA10 0.38 First PDP-10, flip chips, 1967
KI10 0.72 First paging system, flip chip + MSI, 1969
KL10 1.8 First ECL system, ECL 10K, 1972
KL10X 1.8 Expanded addressing, ECL 10K, 1975
KS10 0.3 Last 36b system, 2901 based, 1979
In addition, it ran four major (incompatible) operating systems:
name company comments
TOPS-10 DEC Original timesharing system
ITS MIT "Incompatible Timesharing System"
TENEX BBN ARPA-sponsored, became
TOPS-20 DEC Commercial version of TENEX
All of the implementations differ from one another, in instruction set,
I/O structure, and memory management. Further, each of the operating
systems customized the microcode of the paging systems (KI10, KL10, KS10)
for additional instructions and specialized memory management. As a
result, there is no "reference implementation" for the 36b family that
will run all programs and all operating systems. The conditionalization
and generality needed to support the full matrix of models and operating
systems, and to support 36b hardware on 32b data types, is beyond the
scope of this project.
Instead, this simulator emulates one model -- the KS10. It has the best
documentation and allows reuse of some of the Unibus peripheral emulators
written for the PDP-11 simulator. Further, the simulator requires that
the underlying compiler support 64b integer data types, allowing 36b data
to be maintained in a single data item. Lastly, the simulator implements
the maximum memory size, so that NXM's never happen.
*/
/* Data types */
typedef int32 a10; /* PDP-10 addr (30b) */
typedef int64 d10; /* PDP-10 data (36b) */
/* Abort codes, used to sort out longjmp's back to the main loop
Codes > 0 are simulator stop codes
Codes < 0 are internal aborts
Code = 0 stops execution for an interrupt check
*/
#define STOP_HALT 1 /* halted */
#define STOP_IBKPT 2 /* breakpoint */
#define STOP_ILLEG 3 /* illegal instr */
#define STOP_ILLINT 4 /* illegal intr inst */
#define STOP_PAGINT 5 /* page fail in intr */
#define STOP_ZERINT 6 /* zero vec in intr */
#define STOP_NXMPHY 7 /* nxm on phys ref */
#define STOP_IND 8 /* indirection loop */
#define STOP_XCT 9 /* XCT loop */
#define STOP_ILLIOC 10 /* invalid UBA num */
#define STOP_MTRLNT 11 /* invalid mt rec lnt */
#define STOP_ASTOP 12 /* address stop */
#define STOP_UNKNOWN 13 /* unknown stop */
#define PAGE_FAIL -1 /* page fail */
#define INTERRUPT -2 /* interrupt */
#define ABORT(x) longjmp (save_env, (x)) /* abort */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
/* Return codes from eXTEND */
#define XT_MUUO 0 /* invalid operation */
#define XT_SKIP 1 /* skip return */
#define XT_NOSK 2 /* no skip return */
/* Operating system flags, kept in cpu_unit.flags */
#define UNIT_V_ITS (UNIT_V_UF) /* ITS */
#define UNIT_ITS (1 << UNIT_V_ITS)
#define ITS (cpu_unit.flags & UNIT_ITS)
/* Architectural constants */
#define PASIZE 20 /* phys addr width */
#define MAXMEMSIZE (1 << PASIZE) /* maximum memory */
#define PAMASK ((1 << PASIZE) - 1)
#define MEMSIZE MAXMEMSIZE /* fixed, KISS */
#define MEM_ADDR_NXM(x) ((x) >= MEMSIZE)
#define VASIZE 18 /* virtual addr width */
#define AMASK ((1 << VASIZE) - 1) /* virtual addr mask */
#define LMASK 0777777000000 /* left mask */
#define LSIGN 0400000000000 /* left sign */
#define RMASK 0000000777777 /* right mask */
#define RSIGN 0000000400000 /* right sign */
#define DMASK 0777777777777 /* data mask */
#define SIGN 0400000000000 /* sign */
#define MMASK 0377777777777 /* magnitude mask */
#define ONES 0777777777777
#define MAXPOS 0377777777777
#define MAXNEG 0400000000000
/* Instruction format */
#define INST_V_OP 27 /* opcode */
#define INST_M_OP 0777
#define INST_V_DEV 26
#define INST_M_DEV 0177 /* device */
#define INST_V_AC 23 /* AC */
#define INST_M_AC 017
#define INST_V_IND 22 /* indirect */
#define INST_IND (1 << INST_V_IND)
#define INST_V_XR 18 /* index */
#define INST_M_XR 017
#define OP_JRST 0254 /* JRST */
#define AC_XPCW 07 /* XPCW */
#define OP_JSR 0264 /* JSR */
#define GET_OP(x) ((int32) (((x) >> INST_V_OP) & INST_M_OP))
#define GET_DEV(x) ((int32) (((x) >> INST_V_DEV) & INST_M_DEV))
#define GET_AC(x) ((int32) (((x) >> INST_V_AC) & INST_M_AC))
#define TST_IND(x) ((x) & INST_IND)
#define GET_XR(x) ((int32) (((x) >> INST_V_XR) & INST_M_XR))
#define GET_ADDR(x) ((a10) ((x) & AMASK))
/* Byte pointer format */
#define BP_V_P 30 /* position */
#define BP_M_P 077
#define BP_P 0770000000000
#define BP_V_S 24 /* size */
#define BP_M_S 077
#define BP_S 0007700000000
#define GET_P(x) ((int32) (((x) >> BP_V_P) & BP_M_P))
#define GET_S(x) ((int32) (((x) >> BP_V_S) & BP_M_S))
#define PUT_P(b,x) (((b) & ~BP_P) | ((((int64) (x)) & BP_M_P) << BP_V_P))
/* Flags (stored in their own halfword) */
#define F_V_AOV 17 /* arithmetic ovflo */
#define F_V_C0 16 /* carry 0 */
#define F_V_C1 15 /* carry 1 */
#define F_V_FOV 14 /* floating ovflo */
#define F_V_FPD 13 /* first part done */
#define F_V_USR 12 /* user mode */
#define F_V_UIO 11 /* user I/O mode */
#define F_V_PUB 10 /* public mode */
#define F_V_AFI 9 /* addr fail inhibit */
#define F_V_T2 8 /* trap 2 */
#define F_V_T1 7 /* trap 1 */
#define F_V_FXU 6 /* floating exp unflo */
#define F_V_DCK 5 /* divide check */
#define F_AOV (1 << F_V_AOV)
#define F_C0 (1 << F_V_C0)
#define F_C1 (1 << F_V_C1)
#define F_FOV (1 << F_V_FOV)
#define F_FPD (1 << F_V_FPD)
#define F_USR (1 << F_V_USR)
#define F_UIO (1 << F_V_UIO)
#define F_PUB (1 << F_V_PUB)
#define F_AFI (1 << F_V_AFI)
#define F_T2 (1 << F_V_T2)
#define F_T1 (1 << F_V_T1)
#define F_TR (F_T1 | F_T2)
#define F_FXU (1 << F_V_FXU)
#define F_DCK (1 << F_V_DCK)
#define F_1PR (F_AFI) /* ITS: 1-proceed */
#define F_MASK 0777740 /* all flags */
#define SETF(x) flags = flags | (x)
#define CLRF(x) flags = flags & ~(x)
#define TSTF(x) (flags & (x))
#define GET_TRAPS(x) (((x) & (F_T2 | F_T1)) >> F_V_T1)
/* Priority interrupt system */
#define PI_CPRQ 020000 /* drop prog req */
#define PI_INIT 010000 /* clear pi system */
#define PI_SPRQ 004000 /* set prog req */
#define PI_SENB 002000 /* set enables */
#define PI_CENB 001000 /* clear enables */
#define PI_CON 000400 /* turn off pi system */
#define PI_SON 000200 /* turn on pi system */
#define PI_M_LVL 000177 /* level mask */
#define PI_V_PRQ 18 /* in CONI */
#define PI_V_ACT 8
#define PI_V_ON 7
#define PI_V_ENB 0
/* Arithmetic processor flags */
#define APR_SENB 0100000 /* set enable */
#define APR_CENB 0040000 /* clear enable */
#define APR_CFLG 0020000 /* clear flag */
#define APR_SFLG 0010000 /* set flag */
#define APR_IRQ 0000010 /* int request */
#define APR_M_LVL 0000007 /* pi level */
#define APR_V_FLG 4 /* system flags */
#define APR_M_FLG 0377
#define APRF_ITC (002000 >> APR_V_FLG) /* int console flag */
#define APRF_NXM (000400 >> APR_V_FLG) /* nxm flag */
#define APRF_TIM (000040 >> APR_V_FLG) /* timer request */
#define APRF_CON (000020 >> APR_V_FLG) /* console int */
#define APR_GETF(x) (((x) >> APR_V_FLG) & APR_M_FLG)
/* Virtual address, DEC paging */
#define PAG_V_OFF 0 /* offset - must be 0 */
#define PAG_N_OFF 9 /* page offset width */
#define PAG_SIZE 01000 /* page offset size */
#define PAG_M_OFF 0777 /* mask for offset */
#define PAG_V_PN PAG_N_OFF /* page number */
#define PAG_N_PPN (PASIZE - PAG_N_OFF) /* phys pageno width */
#define PAG_M_PPN 03777 /* phys pageno mask */
#define PAG_PPN 03777000
#define PAG_N_VPN (VASIZE - PAG_N_OFF) /* virt pageno width */
#define PAG_M_VPN 0777 /* virt pageno mask */
#define PAG_VPN 0777000
#define PAG_GETOFF(x) ((x) & PAG_M_OFF)
#define PAG_GETVPN(x) (((x) >> PAG_V_PN) & PAG_M_VPN)
#define PAG_XPTEPA(p,x) (((p) + PAG_GETOFF (x)) & PAMASK)
#define PAG_PTEPA(p,x) (((((int32) (p)) & PTE_PPMASK) << PAG_V_PN) + PAG_GETOFF (x))
/* Page table entry, TOPS-10 paging */
#define PTE_T10_A 0400000 /* T10: access */
#define PTE_T10_P 0200000 /* T10: public */
#define PTE_T10_W 0100000 /* T10: writeable */
#define PTE_T10_S 0040000 /* T10: software */
#define PTE_T10_C 0020000 /* T10: cacheable */
#define PTE_PPMASK PAG_M_PPN
/* Page table entry, TOPS-20 paging */
#define PTE_T20_V_TYP 33 /* T20: pointer type */
#define PTE_T20_M_TYP 07
#define T20_NOA 0 /* no access */
#define T20_IMM 1 /* immediate */
#define T20_SHR 2 /* shared */
#define T20_IND 3 /* indirect */
#define PTE_T20_W 0020000000000 /* T20: writeable */
#define PTE_T20_C 0004000000000 /* T20: cacheable */
#define PTE_T20_STM 0000077000000 /* T20: storage medium */
#define PTE_T20_V_PMI 18 /* page map index */
#define PTE_T20_M_PMI 0777
#define T20_GETTYP(x) ((int32) (((x) >> PTE_T20_V_TYP) & PTE_T20_M_TYP))
#define T20_GETPMI(x) ((int32) (((x) >> PTE_T20_V_PMI) & PTE_T20_M_PMI))
/* CST entry, TOPS-20 paging */
#define CST_AGE 0770000000000 /* age field */
#define CST_M 0000000000001 /* modified */
/* Page fail word, DEC paging */
#define PF_USER 0400000000000 /* user mode */
#define PF_HARD 0200000000000 /* nx I/O reg */
#define PF_NXM 0370000000000 /* nx memory */
#define PF_T10_A 0100000000000 /* T10: pte A bit */
#define PF_T10_W 0040000000000 /* T10: pte W bit */
#define PF_T10_S 0020000000000 /* T10: pte S bit */
#define PF_T20_DN 0100000000000 /* T20: eval done */
#define PF_T20_M 0040000000000 /* T20: modified */
#define PF_T20_W 0020000000000 /* T20: writeable */
#define PF_WRITE 0010000000000 /* write reference */
#define PF_PUB 0004000000000 /* pte public bit */
#define PF_C 0002000000000 /* pte C bit */
#define PF_VIRT 0001000000000 /* pfl: virt ref */
#define PF_NXMP 0001000000000 /* nxm: phys ref */
#define PF_IO 0000200000000 /* I/O reference */
#define PF_BYTE 0000020000000 /* I/O byte ref */
/* Virtual address, ITS paging */
#define ITS_V_OFF 0 /* offset - must be 0 */
#define ITS_N_OFF 10 /* page offset width */
#define ITS_SIZE 02000 /* page offset size */
#define ITS_M_OFF 01777 /* mask for offset */
#define ITS_V_PN ITS_N_OFF /* page number */
#define ITS_N_PPN (PASIZE- ITS_N_OFF) /* phys pageno width */
#define ITS_M_PPN 01777 /* phys pageno mask */
#define ITS_PPN 03776000
#define ITS_N_VPN (VASIZE - ITS_N_OFF) /* virt pageno width */
#define ITS_M_VPN 0377 /* virt pageno mask */
#define ITS_VPN 0776000
#define ITS_GETVPN(x) (((x) >> ITS_V_PN) & ITS_M_VPN)
/* Page table entry, ITS paging */
#define PTE_ITS_V_ACC 16 /* access field */
#define PTE_ITS_M_ACC 03
#define ITS_ACC_NO 0 /* no access */
#define ITS_ACC_RO 1 /* read only */
#define ITS_ACC_RWF 2 /* read-write first */
#define ITS_ACC_RW 3 /* read write */
#define PTE_ITS_AGE 0020000 /* age */
#define PTE_ITS_C 0010000 /* cacheable */
#define PTE_ITS_PPMASK ITS_M_PPN
#define ITS_GETACC(x) (((x) >> PTE_ITS_V_ACC) & PTE_ITS_M_ACC)
/* Page fail word, ITS paging */
#define PF_ITS_WRITE 0010000000000 /* write reference */
#define PF_ITS_V_ACC 28 /* access from PTE */
/* Page table fill operations */
#define PTF_RD 0 /* read check */
#define PTF_WR 1 /* write check */
#define PTF_MAP 2 /* map instruction */
#define PTF_CON 4 /* console access */
/* User base register */
#define UBR_SETACB 0400000000000 /* set AC blocks */
#define UBR_SETUBR 0100000000000 /* set UBR */
#define UBR_V_CURAC 27 /* current AC block */
#define UBR_V_PRVAC 24 /* previous AC block */
#define UBR_M_AC 07
#define UBR_ACBMASK 0007700000000
#define UBR_V_UBR 0 /* user base register */
#define UBR_N_UBR 11
#define UBR_M_UBR 03777
#define UBR_UBRMASK 0000000003777
#define UBR_GETCURAC(x) ((int32) (((x) >> UBR_V_CURAC) & UBR_M_AC))
#define UBR_GETPRVAC(x) ((int32) (((x) >> UBR_V_PRVAC) & UBR_M_AC))
#define UBR_GETUBR(x) ((int32) (((x) >> UBR_V_UBR) & PAG_M_PPN))
#define UBRWORD (ubr | UBR_SETACB | UBR_SETUBR)
/* Executive base register */
#define EBR_V_T20P 14 /* TOPS20 paging */
#define EBR_T20P (1u << EBR_V_T20P)
#define EBR_V_PGON 13 /* enable paging */
#define EBR_PGON (1u << EBR_V_PGON)
#define EBR_V_EBR 0 /* exec base register */
#define EBR_N_EBR 11
#define EBR_M_EBR 03777
#define EBR_MASK (EBR_T20P | EBR_PGON | (EBR_M_EBR << EBR_V_EBR))
#define EBR_GETEBR(x) ((int32) (((x) >> EBR_V_EBR) & PAG_M_PPN))
#define PAGING (ebr & EBR_PGON)
#define T20 (ebr & EBR_T20P)
/* AC and mapping contexts
There are only two real contexts for selecting the AC block and
the memory map: current and previous. However, PXCT allows the
choice of current versus previous to be made selectively for
various parts of an instruction. The PXCT flags (and the trap
in progress flag) are kept in a dynamic CPU variable.
*/
#define TRAP_CYCLE 040 /* trap in progress */
#define EA_PXCT 010 /* eff addr calc */
#define OPND_PXCT 004 /* operand, bdst */
#define EABP_PXCT 002 /* bp eff addr calc */
#define BSTK_PXCT 001 /* stk, bp op, bsrc */
#define XSRC_PXCT 002 /* extend source */
#define XDST_PXCT 001 /* extend destination */
#define MM_CUR 000 /* current context */
#define MM_EA (pflgs & EA_PXCT)
#define MM_OPND (pflgs & OPND_PXCT)
#define MM_EABP (pflgs & EABP_PXCT)
#define MM_BSTK (pflgs & BSTK_PXCT)
/* Accumulator access. The AC blocks are kept in array acs[AC_NBLK * AC_NUM].
Two pointers are provided to the bases of the current and previous blocks.
Macro AC selects the current AC block; macro XR selects current or previous,
depending on whether the selected bit in the "pxct in progress" flag is set.
*/
#define AC_NUM 16 /* # AC's/block */
#define AC_NBLK 8 /* # AC blocks */
#define AC(r) (ac_cur[r]) /* AC select current */
#define XR(r,prv) ((prv)? ac_prv[r]: ac_cur[r]) /* AC select context */
#define ADDAC(x,i) (((x) + (i)) & INST_M_AC)
#define P1 ADDAC (ac, 1)
/* User process table entries */
#define UPT_T10_UMAP 0000 /* T10: user map */
#define UPT_T10_X340 0400 /* T10: exec 340-377 */
#define UPT_TRBASE 0420 /* trap base */
#define UPT_MUUO 0424 /* MUUO block */
#define UPT_MUPC 0425 /* caller's PC */
#define UPT_T10_CTX 0426 /* T10: context */
#define UPT_T20_UEA 0426 /* T20: address */
#define UPT_T20_CTX 0427 /* T20: context */
#define UPT_ENPC 0430 /* MUUO new PC, exec */
#define UPT_UNPC 0434 /* MUUO new PC, user */
#define UPT_NPCT 1 /* PC offset if trap */
#define UPT_T10_PAG 0500 /* T10: page fail blk */
#define UPT_T20_PFL 0500 /* T20: page fail wd */
#define UPT_T20_OFL 0501 /* T20: flags */
#define UPT_T20_OPC 0502 /* T20: old PC */
#define UPT_T20_NPC 0503 /* T20: new PC */
#define UPT_T20_SCTN 0540 /* T20: section 0 ptr */
/* Exec process table entries */
#define EPT_PIIT 0040 /* PI interrupt table */
#define EPT_UBIT 0100 /* Unibus intr table */
#define EPT_T10_X400 0200 /* T10: exec 400-777 */
#define EPT_TRBASE 0420 /* trap base */
#define EPT_ITS_PAG 0440 /* ITS: page fail blk */
#define EPT_T20_SCTN 0540 /* T20: section 0 ptr */
#define EPT_T10_X000 0600 /* T10: exec 0 - 337 */
/* Microcode constants */
#define UC_INHCST 0400000000000 /* inhibit CST update */
#define UC_UBABLT 0040000000000 /* BLTBU and BLTUB */
#define UC_KIPAGE 0020000000000 /* "KI" paging */
#define UC_KLPAGE 0010000000000 /* "KL" paging */
#define UC_VERDEC (0130 << 18) /* ucode version */
#define UC_VERITS (262u << 18)
#define UC_SERDEC 4097 /* serial number */
#define UC_SERITS 1729
#define UC_AIDDEC (UC_INHCST | UC_UBABLT | UC_KIPAGE | UC_KLPAGE | \
UC_VERDEC | UC_SERDEC)
#define UC_AIDITS (UC_KIPAGE | UC_VERITS | UC_SERITS)
#define UC_HSBDEC 0376000 /* DEC initial HSB */
#define UC_HSBITS 0000500 /* ITS initial HSB */
/* Front end communications region */
#define FE_SWITCH 030 /* halt switch */
#define FE_KEEPA 031 /* keep alive */
#define FE_CTYIN 032 /* console in */
#define FE_CTYOUT 033 /* console out */
#define FE_KLININ 034 /* KLINIK in */
#define FE_KLINOUT 035 /* KLINIK out */
#define FE_RHBASE 036 /* boot: RH11 addr */
#define FE_UNIT 037 /* boot: unit num */
#define FE_MTFMT 040 /* boot: magtape params */
#define FE_CVALID 0400 /* char valid flag */
/* Halfword operations */
#define ADDL(x,y) (((x) + ((y) << 18)) & LMASK)
#define ADDR(x,y) (((x) + (y)) & RMASK)
#define INCL(x) ADDL (x, 1)
#define INCR(x) ADDR (x, 1)
#define AOB(x) (INCL (x) | INCR(x))
#define SUBL(x,y) (((x) - ((y) << 18)) & LMASK)
#define SUBR(x,y) (((x) - (y)) & RMASK)
#define DECL(x) SUBL (x, 1)
#define DECR(x) SUBR (x, 1)
#define SOB(x) (DECL (x) | DECR(x))
#define LLZ(x) ((x) & LMASK)
#define RLZ(x) (((x) << 18) & LMASK)
#define RRZ(x) ((x) & RMASK)
#define LRZ(x) (((x) >> 18) & RMASK)
#define LIT8(x) (((x) & RSIGN)? \
(((x) & 0377)? (-(x) & 0377): 0400): ((x) & 0377))
/* Fullword operations */
#define INC(x) (((x) + 1) & DMASK)
#define DEC(x) (((x) - 1) & DMASK)
#define SWP(x) ((((x) << 18) & LMASK) | (((x) >> 18) & RMASK))
#define XWD(x,y) (((((d10) (x)) << 18) & LMASK) | (((d10) (y)) & RMASK))
#define SETS(x) ((x) | SIGN)
#define CLRS(x) ((x) & ~SIGN)
#define TSTS(x) ((x) & SIGN)
#define NEG(x) (-(x) & DMASK)
#define ABS(x) (TSTS (x)? NEG(x): (x))
#define SXT(x) (TSTS (x)? (x) | ~DMASK: (x))
/* Doubleword operations (on 2-word arrays) */
#define DMOVN(rs) rs[1] = (-rs[1]) & MMASK; \
rs[0] = (~rs[0] + (rs[1] == 0)) & DMASK
#define MKDNEG(rs) rs[1] = SETS (-rs[1]) & DMASK; \
rs[0] = (~rs[0] + (rs[1] == MAXNEG)) & DMASK
#define DCMPGE(a,b) ((a[0] > b[0]) || ((a[0] == b[0]) && (a[1] >= b[1])))
/* Address operations */
#define ADDA(x,i) (((x) + (i)) & AMASK)
#define INCA(x) ADDA (x, 1)
/* Unibus adapter control/status register */
#define UBCS_TMO 0400000 /* timeout */
#define UBCS_BMD 0200000 /* bad mem data NI */
#define UBCS_PAR 0100000 /* parity error NI */
#define UBCS_NXD 0040000 /* nx device */
#define UBCS_HI 0004000 /* irq on BR7 or BR6 */
#define UBCS_LO 0002000 /* irq on BR5 or BR4 */
#define UBCS_PWR 0001000 /* power low NI */
#define UBCS_DXF 0000200 /* disable xfer NI*/
#define UBCS_INI 0000100 /* Unibus init */
#define UBCS_RDZ 0030500 /* read as zero */
#define UBCS_RDW 0000277 /* read/write bits */
#define UBCS_V_LHI 3 /* hi pri irq level */
#define UBCS_V_LLO 0 /* lo pri irq level */
#define UBCS_M_PRI 07
#define UBCS_GET_HI(x) (((x) >> UBCS_V_LHI) & UBCS_M_PRI)
#define UBCS_GET_LO(x) (((x) >> UBCS_V_LLO) & UBCS_M_PRI)
/* Unibus adapter page map */
#define UBANUM 2 /* # of Unibus adapters */
#define UMAP_ASIZE 6 /* address size */
#define UMAP_MEMSIZE (1 << UMAP_ASIZE) /* length */
#define UMAP_AMASK (UMAP_MEMSIZE - 1)
#define UMAP_V_RRV 30 /* read reverse */
#define UMAP_V_DSB 29 /* 16b on NPR read */
#define UMAP_V_FST 28 /* fast transfer */
#define UMAP_V_VLD 27 /* valid flag */
#define UMAP_RRV (1 << UMAP_V_RRV)
#define UMAP_DSB (1 << UMAP_V_DSB)
#define UMAP_FST (1 << UMAP_V_FST)
#define UMAP_VLD (1 << UMAP_V_VLD)
#define UMAP_V_FLWR 14 /* flags as written */
#define UMAP_V_FLRD 27 /* flags as stored */
#define UMAP_M_FL 017
#define UMAP_V_PNWR 0 /* page num, write */
#define UMAP_V_PNRD 9 /* page num, read */
#define UMAP_M_PN 03777
#define UMAP_MASK ((UMAP_M_FL << UMAP_V_FLRD) | (UMAP_M_PN << UMAP_V_PNRD))
#define UMAP_POSFL(x) (((x) & (UMAP_M_FL << UMAP_V_FLWR)) \
<< (UMAP_V_FLRD - UMAP_V_FLWR))
#define UMAP_POSPN(x) (((x) & (UMAP_M_PN << UMAP_V_PNWR)) \
<< (UMAP_V_PNRD - UMAP_V_PNWR))
/* Unibus I/O constants */
#define READ 0 /* PDP11 compatible */
/* #define READC 1 /* console read */
#define WRITE 2
/* #define WRITEC 3 /* console write */
#define WRITEB 4
#define IO_V_UBA 18 /* UBA in I/O addr */
#define IO_N_UBA 16 /* max num of UBA's */
#define IO_M_UBA (IO_N_UBA - 1)
#define IO_UBA1 (1 << IO_V_UBA)
#define IO_UBA3 (3 << IO_V_UBA)
#define GET_IOUBA(x) (((x) >> IO_V_UBA) & IO_M_UBA)
/* I/O page layout */
#define IO_DZBASE 0760010 /* DZ11 base */
#define IO_TCUBASE 0760770 /* TCU150 base */
#define IO_UBMAP 0763000 /* Unibus map base */
#define IO_UBCS 0763100 /* Unibus c/s reg */
#define IO_UBMNT 0763101 /* Unibus maint reg */
#define IO_TMBASE 0772440 /* RH11/tape base */
#define IO_RHBASE 0776700 /* RH11/disk base */
#define IO_LPBASE 0775400 /* LP20 base */
#define IO_PTBASE 0777550 /* PC11 base */
/* Common Unibus CSR flags */
#define CSR_V_GO 0 /* go */
#define CSR_V_IE 6 /* interrupt enable */
#define CSR_V_DONE 7 /* done */
#define CSR_V_BUSY 11 /* busy */
#define CSR_V_ERR 15 /* error */
#define CSR_GO (1u << CSR_V_GO)
#define CSR_IE (1u << CSR_V_IE)
#define CSR_DONE (1u << CSR_V_DONE)
#define CSR_BUSY (1u << CSR_V_BUSY)
#define CSR_ERR (1u << CSR_V_ERR)
/* I/O system definitions, lifted from the PDP-11 simulator
Interrupt assignments, priority is right to left
<7:0> = BR7
<15:8> = BR6
<23:16> = BR5
<30:24> = BR4
*/
#define INT_V_RP 8 /* RH11/RP,RM drives */
#define INT_V_TU 9 /* RH11/TM03/TU45 */
#define INT_V_DZ 16 /* DZ11 */
#define INT_V_PTR 24 /* PC11 */
#define INT_V_PTP 25
#define INT_V_LP20 26 /* LPT20 */
#define INT_RP (1u << INT_V_RP)
#define INT_TU (1u << INT_V_TU)
#define INT_DZ (1u << INT_V_DZ)
#define INT_PTR (1u << INT_V_PTR)
#define INT_PTP (1u << INT_V_PTP)
#define INT_LP20 (1u << INT_V_LP20)
#define INT_UB1 INT_RP /* on Unibus 1 */
#define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */
#define INT_IPL7 0x000000FF /* int level masks */
#define INT_IPL6 0x0000FF00
#define INT_IPL5 0x00FF0000
#define INT_IPL4 0x3F000000
#define VEC_PTR 0070 /* interrupt vectors */
#define VEC_PTP 0074
#define VEC_TU 0224
#define VEC_RP 0254
#define VEC_DZ 0340
#define VEC_LP20 0754

162
pdp10_fe.c Normal file
View file

@ -0,0 +1,162 @@
/* pdp10_fe.c: PDP-10 front end (console terminal) simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
fe KS10 console front end
*/
#include "pdp10_defs.h"
#define UNIT_DUMMY (1 << UNIT_V_UF)
extern d10 *M;
extern int32 apr_flg;
t_stat fei_svc (UNIT *uptr);
t_stat feo_svc (UNIT *uptr);
t_stat fe_reset (DEVICE *dptr);
t_stat fe_stop_os (UNIT *uptr, int32 val);
t_stat fe_ctrl_c (UNIT *uptr, int32 val);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
/* FE data structures
fe_dev FE device descriptor
fe_unit FE unit descriptor
fe_reg FE register list
*/
#define fei_unit fe_unit[0]
#define feo_unit fe_unit[1]
UNIT fe_unit[] = {
{ UDATA (&fei_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT } };
REG fe_reg[] = {
{ ORDATA (IBUF, fei_unit.buf, 8) },
{ DRDATA (ICOUNT, fei_unit.pos, 31), REG_RO + PV_LEFT },
{ DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT },
{ ORDATA (OBUF, feo_unit.buf, 8) },
{ DRDATA (OCOUNT, feo_unit.pos, 31), REG_RO + PV_LEFT },
{ DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL } };
MTAB fe_mod[] = {
{ UNIT_DUMMY, 0, NULL, "STOP", &fe_stop_os },
{ UNIT_DUMMY, 0, NULL, "CTRL-C", &fe_ctrl_c },
{ 0 } };
DEVICE fe_dev = {
"FE", fe_unit, fe_reg, fe_mod,
2, 10, 31, 1, 8, 8,
NULL, NULL, &fe_reset,
NULL, NULL, NULL };
/* Front end processor (console terminal)
Communications between the KS10 and its front end is based on an in-memory
status block and two interrupt lines: interrupt-to-control (APR_ITC) and
interrupt-from-console (APR_CON). When the KS10 wants to print a character
on the terminal,
1. It places a character, plus the valid flag, in FE_CTYOUT.
2. It interrupts the front end processor.
3. The front end processor types the character and then zeroes FE_CTYOUT.
4. The front end procesor interrupts the KS10.
When the front end wants to send an input character to the KS10,
1. It places a character, plus the valid flag, in FE_CTYIN.
2. It interrupts the KS10.
3. It waits for the KS10 to take the character and clear the valid flag.
4. It can then send more input (the KS10 may signal this by interrupting
the front end).
Note that the protocol has both ambiguity (interrupt to the KS10 may mean
character printed, or input character available, or both) and lack of
symmetry (the KS10 does not inform the front end that it has taken an
input character).
*/
void fe_intr (void)
{
if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */
feo_unit.buf = (int32) M[FE_CTYOUT] & 0177; /* pick it up */
sim_putchar (feo_unit.buf); /* type it */
feo_unit.pos = feo_unit.pos + 1;
sim_activate (&feo_unit, feo_unit.time); } /* sched completion */
else if ((M[FE_CTYIN] & FE_CVALID) == 0) { /* input char taken? */
sim_cancel (&fei_unit); /* sched immediate */
sim_activate (&fei_unit, 0); }; /* keyboard poll */
return;
}
t_stat feo_svc (UNIT *uptr)
{
M[FE_CTYOUT] = 0; /* clear char */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;
}
t_stat fei_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&fei_unit, fei_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
fei_unit.buf = temp & 0177;
fei_unit.pos = fei_unit.pos + 1;
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;
}
/* Reset */
t_stat fe_reset (DEVICE *dptr)
{
fei_unit.buf = feo_unit.buf = 0;
M[FE_CTYIN] = M[FE_CTYOUT] = 0;
apr_flg = apr_flg & ~(APRF_ITC | APRF_CON);
sim_activate (&fei_unit, fei_unit.wait); /* start input poll */
return SCPE_OK;
}
/* Stop operating system */
t_stat fe_stop_os (UNIT *uptr, int32 val)
{
M[FE_SWITCH] = IO_RHBASE; /* tell OS to stop */
return SCPE_OK;
}
/* Enter control-C for Windoze */
t_stat fe_ctrl_c (UNIT *uptr, int32 val)
{
fei_unit.buf = 003; /* control-C */
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;
}

546
pdp10_ksio.c Normal file
View file

@ -0,0 +1,546 @@
/* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
uba Unibus adapters
12-May-01 RMS Fixed typo
The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While
nominally four adapters are supported, in practice only 1 and 3
are implemented. The disks are placed on adapter 1, the rest of
the I/O devices on adapter 3.
In theory, we should maintain completely separate Unibuses, with
distinct PI systems. In practice, this simulator has so few devices
that we can get away with a single PI system, masking for which
devices are on adapter 1, and which on adapter 3. The Unibus
implementation is modeled on the Qbus in the PDP-11 simulator and
is described there.
The I/O subsystem is programmed by I/O instructions which create
Unibus operations (read, read pause, write, write byte). DMA is
the responsibility of the I/O device simulators, which also implement
Unibus to physical memory mapping.
The priority interrupt subsystem (and other privileged functions)
is programmed by I/O instructions with internal devices codes
(opcodes 700-702). These are dispatched here, although many are
handled in the memory management unit or elsewhere.
The ITS instructions are significantly different from the TOPS-10/20
instructions. They do not use the extended address calculation but
instead provide instruction variants (Q for Unibus adapter 1, I for
Unibus adapter 3) which insert the Unibus adapter number into the
effective address.
*/
#include "pdp10_defs.h"
#include <setjmp.h>
#define eaRB (ea & ~1)
#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)
#define UBNXM_FAIL(pa,op) \
n = iocmap[GET_IOUBA (pa)]; \
if (n >= 0) ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \
pager_word = PF_HARD | PF_VIRT | PF_IO | \
((op == WRITEB)? PF_BYTE: 0) | \
(TSTF (F_USR)? PF_USER: 0) | (pa); \
ABORT (PAGE_FAIL)
/* Unibus adapter data */
int32 ubcs[UBANUM] = { 0 }; /* status registers */
int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */
int32 int_req = 0; /* interrupt requests */
int32 dev_enb = -1 & ~(INT_PTR | INT_PTP); /* device enables */
/* Map IO controller numbers to Unibus adapters: -1 = non-existent */
static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */
-1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
static const int32 ubabr76[UBANUM] = {
INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6) };
static const int32 ubabr54[UBANUM] = {
INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4) };
extern d10 *ac_cur;
extern d10 pager_word;
extern int32 flags, pi_l2bit[8];
extern UNIT cpu_unit;
extern jmp_buf save_env;
extern d10 Read (a10 ea);
extern void pi_eval ();
extern t_stat dz_rd (int32 *data, int32 addr, int32 access);
extern t_stat dz_wr (int32 data, int32 addr, int32 access);
extern t_stat pt_rd (int32 *data, int32 addr, int32 access);
extern t_stat pt_wr (int32 data, int32 addr, int32 access);
extern t_stat lp20_rd (int32 *data, int32 addr, int32 access);
extern t_stat lp20_wr (int32 data, int32 addr, int32 access);
extern int32 lp20_inta (void);
extern t_stat rp_rd (int32 *data, int32 addr, int32 access);
extern t_stat rp_wr (int32 data, int32 addr, int32 access);
extern int32 rp_inta (void);
extern t_stat tu_rd (int32 *data, int32 addr, int32 access);
extern t_stat tu_wr (int32 data, int32 addr, int32 access);
extern int32 tu_inta (void);
extern t_stat tcu_rd (int32 *data, int32 addr, int32 access);
t_stat ubmap_rd (int32 *data, int32 addr, int32 access);
t_stat ubmap_wr (int32 data, int32 addr, int32 access);
t_stat ubs_rd (int32 *data, int32 addr, int32 access);
t_stat ubs_wr (int32 data, int32 addr, int32 access);
t_stat rd_zro (int32 *data, int32 addr, int32 access);
t_stat wr_nop (int32 data, int32 addr, int32 access);
t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat uba_reset (DEVICE *dptr);
d10 ReadIO (a10 ea);
void WriteIO (a10 ea, d10 val, int32 mode);
/* Unibus adapter data structures
uba_dev UBA device descriptor
uba_unit UBA units
uba_reg UBA register list
*/
UNIT uba_unit[] = {
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) } };
REG uba_reg[] = {
{ ORDATA (INTREQ, int_req, 32), REG_RO },
{ ORDATA (UB1CS, ubcs[0], 18) },
{ ORDATA (UB3CS, ubcs[1], 18) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL } };
DEVICE uba_dev = {
"UBA", uba_unit, uba_reg, NULL,
UBANUM, 8, UMAP_ASIZE, 1, 8, 32,
&uba_ex, &uba_dep, &uba_reset,
NULL, NULL, NULL };
/* PDP-11 I/O structures */
struct iolink { /* I/O page linkage */
int32 low; /* low I/O addr */
int32 high; /* high I/O addr */
int32 enb; /* enable mask */
t_stat (*read)(); /* read routine */
t_stat (*write)(); }; /* write routine */
/* Table of I/O devices and corresponding read/write routines
The expected Unibus adapter number is included as the high 2 bits */
struct iolink iotable[] = {
{ IO_UBA1+IO_RHBASE, IO_UBA1+IO_RHBASE+047, 0,
&rp_rd, &rp_wr }, /* disk */
{ IO_UBA3+IO_TMBASE, IO_UBA3+IO_TMBASE+033, 0,
&tu_rd, &tu_wr }, /* mag tape */
/* { IO_UBA3+IO_DZBASE, IO_UBA3+IO_DZBASE+07, INT_DZ,
&dz_rd, &dz_wr }, /* terminal mux */
{ IO_UBA3+IO_LPBASE, IO_UBA3+IO_LPBASE+017, 0,
&lp20_rd, &lp20_wr }, /* line printer */
{ IO_UBA3+IO_PTBASE, IO_UBA3+IO_PTBASE+07, INT_PTR,
&pt_rd, &pt_wr }, /* paper tape */
{ IO_UBA1+IO_UBMAP, IO_UBA1+IO_UBMAP+077, 0,
&ubmap_rd, &ubmap_wr }, /* Unibus 1 map */
{ IO_UBA3+IO_UBMAP, IO_UBA3+IO_UBMAP+077, 0,
&ubmap_rd, &ubmap_wr }, /* Unibus 3 map */
{ IO_UBA1+IO_UBCS, IO_UBA1+IO_UBCS, 0,
&ubs_rd, &ubs_wr }, /* Unibus 1 c/s */
{ IO_UBA3+IO_UBCS, IO_UBA3+IO_UBCS, 0,
&ubs_rd, &ubs_wr }, /* Unibus 3 c/s */
{ IO_UBA1+IO_UBMNT, IO_UBA1+IO_UBMNT, 0,
&rd_zro, &wr_nop }, /* Unibus 1 maint */
{ IO_UBA3+IO_UBMNT, IO_UBA3+IO_UBMNT, 0,
&rd_zro, &wr_nop }, /* Unibus 3 maint */
{ IO_UBA3+IO_TCUBASE, IO_UBA3+IO_TCUBASE+05, 0,
&tcu_rd, &wr_nop }, /* TCU150 */
{ 00100000, 00100000, 0, &rd_zro, &wr_nop }, /* Mem sys stat */
{ 0, 0, 0, NULL, NULL } };
/* Interrupt request to interrupt action map */
int32 (*int_ack[32])() = { /* int ack routines */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&rp_inta, &tu_inta, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, &lp20_inta, NULL, NULL, NULL, NULL, NULL };
/* Interrupt request to vector map */
int32 int_vec[32] = { /* int req to vector */
0, 0, 0, 0, 0, 0, 0, 0,
VEC_RP, VEC_TU, 0, 0, 0, 0, 0, 0,
VEC_DZ, 0, 0, 0, 0, 0, 0, 0,
VEC_PTR, VEC_PTP, VEC_LP20, 0, 0, 0, 0, 0 };
/* IO 710 (DEC) TIOE - test I/O word, skip if zero
(ITS) IORDI - read word from Unibus 3
returns TRUE if skip, FALSE otherwise
*/
t_bool io710 (int32 ac, a10 ea)
{
d10 val;
if (ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
else { /* TIOE */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) == 0) return TRUE; }
return FALSE;
}
/* IO 711 (DEC) TION - test I/O word, skip if non-zero
(ITS) IORDQ - read word from Unibus 1
returns TRUE if skip, FALSE otherwise
*/
t_bool io711 (int32 ac, a10 ea)
{
d10 val;
if (ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
else { /* TION */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) != 0) return TRUE; }
return FALSE;
}
/* IO 712 (DEC) RDIO - read I/O word, addr in ea
(ITS) IORD - read I/O word, addr in M[ea]
*/
d10 io712 (a10 ea)
{
return ReadIO (ea); /* RDIO, IORD */
}
/* IO 713 (DEC) WRIO - write I/O word, addr in ea
(ITS) IOWR - write I/O word, addr in M[ea]
*/
void io713 (d10 val, a10 ea)
{
WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */
return;
}
/* IO 714 (DEC) BSIO - set bit in I/O address
(ITS) IOWRI - write word to Unibus 3
*/
void io714 (d10 val, a10 ea)
{
d10 temp;
val = val & 0177777;
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
else {
temp = ReadIO (ea); /* BSIO */
temp = temp | val;
WriteIO (ea, temp, WRITE); }
return;
}
/* IO 715 (DEC) BCIO - clear bit in I/O address
(ITS) IOWRQ - write word to Unibus 1
*/
void io715 (d10 val, a10 ea)
{
d10 temp;
val = val & 0177777;
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
else {
temp = ReadIO (ea); /* BCIO */
temp = temp & ~val;
WriteIO (ea, temp, WRITE); }
return;
}
/* IO 720 (DEC) TIOEB - test I/O byte, skip if zero
(ITS) IORDBI - read byte from Unibus 3
returns TRUE if skip, FALSE otherwise
*/
t_bool io720 (int32 ac, a10 ea)
{
d10 val;
if (ITS) { /* IORDBI */
val = ReadIO (IO_UBA3 | eaRB);
AC(ac) = GETBYTE (ea, val); }
else { /* TIOEB */
val = ReadIO (eaRB);
val = GETBYTE (ea, val);
if ((AC(ac) & val) == 0) return TRUE; }
return FALSE;
}
/* IO 721 (DEC) TIONB - test I/O word, skip if non-zero
(ITS) IORDBQ - read word from Unibus 1
returns TRUE if skip, FALSE otherwise
*/
t_bool io721 (int32 ac, a10 ea)
{
d10 val;
if (ITS) { /* IORDBQ */
val = ReadIO (IO_UBA1 | eaRB);
AC(ac) = GETBYTE (ea, val); }
else { /* TIONB */
val = ReadIO (eaRB);
val = GETBYTE (ea, val);
if ((AC(ac) & val) != 0) return TRUE; }
return FALSE;
}
/* IO 722 (DEC) RDIOB - read I/O byte, addr in ea
(ITS) IORDB - read I/O byte, addr in M[ea]
*/
d10 io722 (a10 ea)
{
d10 val;
val = ReadIO (eaRB); /* RDIOB, IORDB */
return GETBYTE (ea, val);
}
/* IO 723 (DEC) WRIOB - write I/O byte, addr in ea
(ITS) IOWRB - write I/O byte, addr in M[ea]
*/
void io723 (d10 val, a10 ea)
{
WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */
return;
}
/* IO 724 (DEC) BSIOB - set bit in I/O byte address
(ITS) IOWRBI - write byte to Unibus 3
*/
void io724 (d10 val, a10 ea)
{
d10 temp;
val = val & 0377;
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
else {
temp = ReadIO (eaRB); /* BSIOB */
temp = GETBYTE (ea, temp);
temp = temp | val;
WriteIO (ea, temp, WRITEB); }
return;
}
/* IO 725 (DEC) BCIOB - clear bit in I/O byte address
(ITS) IOWRBQ - write byte to Unibus 1
*/
void io725 (d10 val, a10 ea)
{
d10 temp;
val = val & 0377;
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
else {
temp = ReadIO (eaRB); /* BCIOB */
temp = GETBYTE (ea, temp);
temp = temp & ~val;
WriteIO (ea, temp, WRITEB); }
return;
}
/* Read and write I/O devices.
These routines are the linkage between the 64b world of the main
simulator and the 32b world of the device simulators.
*/
d10 ReadIO (a10 ea)
{
int32 n, pa, val;
struct iolink *p;
pa = (int32) ea; /* cvt addr to 32b */
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa <= p -> high) &&
((p -> enb == 0) || (dev_enb & p -> enb))) {
p -> read (&val, pa, READ);
pi_eval ();
return ((d10) val); } }
UBNXM_FAIL (pa, READ);
}
void WriteIO (a10 ea, d10 val, int32 mode)
{
int32 n, pa;
struct iolink *p;
pa = (int32) ea; /* cvt addr to 32b */
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa <= p -> high) &&
((p -> enb == 0) || (dev_enb & p -> enb))) {
p -> write ((int32) val, pa, mode);
pi_eval ();
return; } }
UBNXM_FAIL (pa, mode);
}
/* Evaluate Unibus priority interrupts */
int32 pi_ub_eval ()
{
int32 i, lvl;
for (i = lvl = 0; i < UBANUM; i++) {
if (int_req & ubabr76[i])
lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
if (int_req & ubabr54[i])
lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])]; }
return lvl;
}
/* Return Unibus device vector
Takes as input the request level calculated by pi_eval
If there is an interrupting Unibus device at that level, return its vector,
otherwise, returns 0
*/
int32 pi_ub_vec (int32 rlvl, int32 *uba)
{
int32 i, masked_irq;
for (i = masked_irq = 0; i < UBANUM; i++) {
if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */
(masked_irq = int_req & ubabr76[i])) break;
if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */
(masked_irq = int_req & ubabr54[i])) break; }
*uba = (i << 1) + 1; /* store uba # */
for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */
if ((masked_irq >> i) & 1) {
int_req = int_req & ~(1u << i); /* clear req */
if (int_ack[i]) return int_ack[i]();
return int_vec[i]; } } /* return vector */
return 0;
}
/* Unibus adapter map routines */
t_stat ubmap_rd (int32 *val, int32 pa, int32 mode)
{
int32 n = iocmap[GET_IOUBA (pa)];
if (n < 0) ABORT (STOP_ILLIOC);
*val = ubmap[n][pa & UMAP_AMASK];
return SCPE_OK;
}
t_stat ubmap_wr (int32 val, int32 pa, int32 mode)
{
int32 n = iocmap[GET_IOUBA (pa)];
if (n < 0) ABORT (STOP_ILLIOC);
ubmap[n][pa & UMAP_AMASK] = UMAP_POSFL (val) | UMAP_POSPN (val);
return SCPE_OK;
}
/* Unibus adapter control/status routines */
t_stat ubs_rd (int32 *val, int32 pa, int32 mode)
{
int32 n = iocmap[GET_IOUBA (pa)];
if (n < 0) ABORT (STOP_ILLIOC);
if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
*val = ubcs[n] = ubcs[n] & ~UBCS_RDZ;
return SCPE_OK;
}
t_stat ubs_wr (int32 val, int32 pa, int32 mode)
{
int32 n = iocmap[GET_IOUBA (pa)];
if (n < 0) ABORT (STOP_ILLIOC);
if (val & UBCS_INI) {
reset_all (5); /* start after UBA */
ubcs[n] = val & UBCS_DXF; }
else ubcs[n] = val & UBCS_RDW;
if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
return SCPE_OK;
}
/* Unibus adapter read zero/write ignore routines */
t_stat rd_zro (int32 *val, int32 pa, int32 mode)
{
*val = 0;
return SCPE_OK;
}
t_stat wr_nop (int32 val, int32 pa, int32 mode)
{
return SCPE_OK;
}
t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
int32 uba = uptr - uba_unit;
if (addr >= UMAP_MEMSIZE) return SCPE_NXM;
*vptr = ubmap[uba][addr];
return SCPE_OK;
}
t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
int32 uba = uptr - uba_unit;
if (addr >= UMAP_MEMSIZE) return SCPE_NXM;
ubmap[uba][addr] = (int32) val & UMAP_MASK;
return SCPE_OK;
}
t_stat uba_reset (DEVICE *dptr)
{
int32 i, uba;
int_req = 0;
for (uba = 0; uba < UBANUM; uba++) {
ubcs[uba] = 0;
for (i = 0; i < UMAP_MEMSIZE; i++) ubmap[uba][i] = 0; }
pi_eval ();
return SCPE_OK;
}

582
pdp10_lp20.c Normal file
View file

@ -0,0 +1,582 @@
/* pdp10_lp20.c: PDP-10 LP20 line printer simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
lp20 line printer
*/
#include "pdp10_defs.h"
#define UNIT_DUMMY (1 << UNIT_V_UF)
#define LP_WIDTH 132 /* printer width */
/* DAVFU RAM */
#define DV_SIZE 143 /* DAVFU size */
#define DV_DMASK 077 /* data mask per byte */
#define DV_TOF 0 /* top of form channel */
#define DV_MAX 11 /* max channel number */
/* Translation RAM */
#define TX_SIZE 256 /* translation RAM */
#define TX_AMASK (TX_SIZE - 1)
#define TX_DMASK 07777
#define TX_V_FL 8 /* flags */
#define TX_M_FL 017
/* define TX_INTR 04000 /* interrupt */
#define TX_DELH 02000 /* delimiter */
/* define TX_XLAT 01000 /* translate */
/* define TX_DVFU 00400 /* DAVFU */
#define TX_SLEW 00020 /* chan vs slew */
#define TX_VMASK 00017 /* spacing mask */
#define TX_CHR 0 /* states: pr char */
#define TX_RAM 1 /* pr translation */
#define TX_DVU 2 /* DAVFU action */
#define TX_INT 3 /* interrupt */
#define TX_GETFL(x) (((x) >> TX_V_FL) & TX_M_FL)
/* LPCSRA (765400) */
#define CSA_GO 0000001 /* go */
#define CSA_PAR 0000002 /* parity enable NI */
#define CSA_V_FNC 2 /* function */
#define CSA_M_FNC 03
#define FNC_PR 0 /* print */
#define FNC_TST 1 /* test */
#define FNC_DVU 2 /* load DAVFU */
#define FNC_RAM 3 /* load translation RAM */
#define FNC_INTERNAL 1 /* internal function */
#define CSA_FNC (CSA_M_FNC << CSA_V_FNC)
#define CSA_V_UAE 4 /* Unibus addr extension */
#define CSA_UAE (03 << CSA_V_UAE)
#define CSA_IE 0000100 /* interrupt enable */
#define CSA_DONE 0000200 /* done */
#define CSA_INIT 0000400 /* init */
#define CSA_ECLR 0001000 /* clear errors */
#define CSA_DELH 0002000 /* delimiter hold */
#define CSA_ONL 0004000 /* online */
#define CSA_DVON 0010000 /* DAVFU online */
#define CSA_UNDF 0020000 /* undefined char */
#define CSA_PZRO 0040000 /* page counter zero */
#define CSA_ERR 0100000 /* error */
#define CSA_RW (CSA_DELH | CSA_IE | CSA_UAE | CSA_FNC | CSA_PAR | CSA_GO)
#define CSA_MBZ (CSA_ECLR | CSA_INIT)
#define CSA_GETUAE(x) (((x) & CSA_UAE) << (16 - CSA_V_UAE))
#define CSA_GETFNC(x) (((x) >> CSA_V_FNC) & CSA_M_FNC)
/* LPCSRB (765402) */
#define CSB_GOE 0000001 /* go error */
#define CSB_DTE 0000002 /* DEM timing error NI */
#define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */
#define CSB_RPE 0000010 /* RAM parity error NI */
#define CSB_MPE 0000020 /* MEM parity error NI */
#define CSB_LPE 0000040 /* LPT parity error NI */
#define CSB_DVOF 0000100 /* DAVFU not ready */
#define CSB_OFFL 0000200 /* offline */
#define CSB_TEST 0003400 /* test mode */
#define CSB_OVFU 0004000 /* optical VFU NI */
#define CSB_PBIT 0010000 /* data parity bit NI */
#define CSB_NRDY 0020000 /* printer error NI */
#define CSB_LA180 0040000 /* LA180 printer NI */
#define CSB_VLD 0100000 /* valid data NI */
#define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE)
#define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL)
#define CSB_RW CSB_TEST
#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\
CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD)
/* LPBA (765404) */
#define XBA_MBZ 0400000 /* addr<17> must be 0 */
/* LPBC (765506) */
#define BC_MASK 0007777 /* <15:12> MBZ */
/* LPPAGC (765510) */
#define PAGC_MASK 0007777 /* <15:12> MBZ */
/* LPRDAT (765512) */
#define RDAT_MASK 0007777 /* <15:12> MBZ */
/* LPCOLC/LPCBUF (765514) */
/* LPCSUM/LPPDAT (765516) */
extern d10 *M; /* main memory */
extern int32 int_req;
extern int32 ubcs[UBANUM]; /* UBA csr */
extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* UBA map */
int32 lpcsa = 0; /* control/status A */
int32 lpcsb = 0; /* control/status B */
int32 lpba = 0; /* bus address */
int32 lpbc = 0; /* byte count */
int32 lppagc = 0; /* page count */
int32 lprdat = 0; /* RAM data */
int32 lpcbuf = 0; /* character buffer */
int32 lpcolc = 0; /* column count */
int32 lppdat = 0; /* printer data */
int32 lpcsum = 0; /* checksum */
int32 dvptr = 0; /* davfu pointer */
int32 dvlnt = 0; /* davfu length */
int32 lp20_irq = 0; /* int request */
int32 lp20_stopioe = 0; /* stop on error */
int16 txram[TX_SIZE] = { 0 }; /* translation RAM */
int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */
t_stat lp20_svc (UNIT *uptr);
t_stat lp20_reset (DEVICE *dptr);
t_stat lp20_attach (UNIT *uptr, char *ptr);
t_stat lp20_detach (UNIT *uptr);
t_stat lp20_clear_vfu (UNIT *uptr, int32 arg);
t_bool lp20_print (int32 c);
t_bool lp20_adv (int32 c, t_bool advdvu);
t_bool lp20_davfu (int32 c);
void update_lpcs (int32 flg);
/* LP data structures
lp20_dev LPT device descriptor
lp20_unit LPT unit descriptor
lp20_reg LPT register list
*/
UNIT lp20_unit = {
UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lp20_reg[] = {
{ ORDATA (LPCSA, lpcsa, 16) },
{ ORDATA (LPCSB, lpcsb, 16) },
{ ORDATA (LPBA, lpba, 16) },
{ ORDATA (LPBC, lpbc, 12) },
{ ORDATA (LPPAGC, lppagc, 12) },
{ ORDATA (LPRDAT, lprdat, 12) },
{ ORDATA (LPCBUF, lpcbuf, 8) },
{ ORDATA (LPCOLC, lpcolc, 8) },
{ ORDATA (LPPDAT, lppdat, 8) },
{ ORDATA (LPCSUM, lpcsum, 8) },
{ ORDATA (DVPTR, dvptr, 7) },
{ ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ },
{ FLDATA (INT, int_req, INT_V_LP20) },
{ FLDATA (IRQ, lp20_irq, 0) },
{ FLDATA (ERR, lpcsa, CSR_V_ERR) },
{ FLDATA (DONE, lpcsa, CSR_V_DONE) },
{ FLDATA (IE, lpcsa, CSR_V_IE) },
{ DRDATA (POS, lp20_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lp20_stopioe, 0) },
{ BRDATA (TXRAM, txram, 8, 12, TX_SIZE) },
{ BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) },
{ NULL } };
MTAB lp20_mod[] = {
{ UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu },
{ 0 } };
DEVICE lp20_dev = {
"LP20", &lp20_unit, lp20_reg, lp20_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lp20_reset,
NULL, &lp20_attach, &lp20_detach };
/* Line printer routines
lp20_rd I/O page read
lp20_wr I/O page write
lp20_svc process event (printer ready)
lp20_reset process reset
lp20_attach process attach
lp20_detach process detach
*/
t_stat lp20_rd (int32 *data, int32 pa, int32 access)
{
update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
*data = lpcsa = lpcsa & ~CSA_MBZ;
break;
case 01: /* LPCSB */
*data = lpcsb = lpcsb & ~CSB_MBZ;
break;
case 02: /* LPBA */
*data = lpba;
break;
case 03: /* LPBC */
*data = lpbc = lpbc & BC_MASK;
break;
case 04: /* LPPAGC */
*data = lppagc = lppagc & PAGC_MASK;
break;
case 05: /* LPRDAT */
*data = lprdat = lprdat & RDAT_MASK;
break;
case 06: /* LPCOLC/LPCBUF */
*data = (lpcolc << 8) | lpcbuf;
break;
case 07: /* LPCSUM/LPPDAT */
*data = (lpcsum << 8) | lppdat;
break; } /* end case PA */
return SCPE_OK;
}
t_stat lp20_wr (int32 data, int32 pa, int32 access)
{
update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
if (access == WRITEB) data = (pa & 1)?
(lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;
if (data & CSA_ECLR) { /* error clear? */
lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */
lpcsb = lpcsb & ~CSB_ECLR; /* clear err */
sim_cancel (&lp20_unit); } /* cancel I/O */
if (data & CSA_INIT) lp20_reset (&lp20_dev); /* init? */
if (data & CSA_GO) { /* go set? */
if ((lpcsa & CSA_GO) == 0) { /* not set before? */
if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;
lpcsum = 0; /* clear checksum */
sim_activate (&lp20_unit, lp20_unit.time); } }
else sim_cancel (&lp20_unit); /* go clr, stop DMA */
lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);
break;
case 01: /* LPCSB */
break; /* ignore writes to TEST */
case 02: /* LPBA */
if (access == WRITEB) data = (pa & 1)?
(lpba & 0377) | (data << 8): (lpba & ~0377) | data;
lpba = data;
break;
case 03: /* LPBC */
if (access == WRITEB) data = (pa & 1)?
(lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;
lpbc = data & BC_MASK;
lpcsa = lpcsa & ~CSA_DONE;
break;
case 04: /* LPPAGC */
if (access == WRITEB) data = (pa & 1)?
(lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;
lppagc = data & PAGC_MASK;
break;
case 05: /* LPRDAT */
if (access == WRITEB) data = (pa & 1)?
(lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;
lprdat = data & RDAT_MASK;
txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */
break;
case 06: /* LPCOLC/LPCBUF */
if ((access == WRITEB) && (pa & 1)) /* odd byte */
lpcolc = data & 0377;
else { lpcbuf = data & 0377; /* even byte, word */
if (access == WRITE) lpcolc = (data >> 8) & 0377; }
break;
case 07: /* LPCSUM/LPPDAT */
break; } /* read only */
update_lpcs (0);
return SCPE_OK;
}
/* Line printer service
The translation RAM case table is derived from the LP20 spec and
verified against the LP20 RAM simulator in TOPS10 7.04 LPTSPL.
The equations are:
flags := inter, delim, xlate, paper, delim_hold (from CSRA)
actions : = print_input, print_xlate, davfu_action, interrupt
if (inter) {
if (!xlate || delim || delim_hold) interrupt;
else if (paper) davfu_action;
else print_xlate; }
else if (paper) {
if (xlate || delim || delim_hold) davfu_action;
else print_input; }
else {
if (xlate || delim || delim_hold) print_xlate;
else print_input; }
*/
t_stat lp20_svc (UNIT *uptr)
{
int32 fnc, i, tbc, vpn, temp, txst, wd10;
int32 dvld = -2; /* must be even */
int32 err = 0;
t_bool cont;
a10 ba, pa10;
static const uint32 txcase[32] = {
TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
TX_RAM, TX_RAM, TX_DVU, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
TX_INT, TX_INT, TX_INT, TX_INT, TX_RAM, TX_INT, TX_DVU, TX_INT,
TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT };
lpcsa = lpcsa & ~CSA_GO;
ba = CSA_GETUAE (lpcsa) | lpba;
fnc = CSA_GETFNC (lpcsa);
tbc = 010000 - lpbc;
if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) {
update_lpcs (CSA_ERR);
IORETURN (lp20_stopioe, SCPE_UNATT); }
if ((fnc == FNC_PR) && (dvlnt == 0)) {
update_lpcs (CSA_ERR);
return SCPE_OK; }
for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */
if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) ||
((ubmap[1][vpn] & UMAP_VLD) == 0)) { /* invalid map? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
update_lpcs (CSA_ERR); /* set done */
break; }
pa10 = (ubmap[1][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;
if (MEM_ADDR_NXM (pa10)) { /* nxm? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
update_lpcs (CSA_ERR); /* set done */
break; }
wd10 = (int32) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */
lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */
switch (fnc) { /* switch on function */
/* Translation RAM load */
case FNC_RAM: /* RAM load */
txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;
break;
/* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by
a start (354 to 356) and stop (357) byte pair. If the number of bytes
loaded is odd, or no bytes are loaded, the DAVFU is invalid.
*/
case FNC_DVU: /* DVU load */
if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */
dvld = dvlnt = 0; /* reset lnt */
else if (lpcbuf == 0357) { /* stop DVU load? */
dvptr = 0; /* reset ptr */
if (dvld & 1) dvlnt = 0; } /* if odd, invalid */
else if (dvld == 0) { /* even state? */
temp = lpcbuf & DV_DMASK;
dvld = 1; }
else if (dvld == 1) { /* odd state? */
if (dvlnt < DV_SIZE) davfu[dvlnt++] =
temp | ((lpcbuf & DV_DMASK) << 6);
dvld = 0; }
break;
/* Print characters */
case FNC_PR: /* print */
lprdat = txram[lpcbuf]; /* get RAM char */
txst = (TX_GETFL (lprdat) << 1) | /* get state */
((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */
if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;
else lpcsa = lpcsa & ~CSA_DELH;
lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */
switch (txcase[txst]) { /* case on state */
case TX_CHR: /* take char */
cont = lp20_print (lpcbuf);
break;
case TX_RAM: /* take translation */
cont = lp20_print (lprdat);
break;
case TX_DVU: /* DAVFU action */
if (lprdat & TX_SLEW)
cont = lp20_adv (lprdat & TX_VMASK, TRUE);
else cont = lp20_davfu (lprdat & TX_VMASK);
break;
case TX_INT: /* interrupt */
lpcsa = lpcsa | CSA_UNDF; /* set flag */
cont = FALSE; /* force stop */
break; } /* end case char state */
break;
case FNC_TST: /* test */
break; } /* end case function */
} /* end for */
lpba = ba & 0177777;
lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE);
lpbc = (lpbc + i) & BC_MASK;
if (lpbc) update_lpcs (CSA_MBZ); /* intr, but not done */
else update_lpcs (CSA_DONE); /* intr and done */
if ((fnc == FNC_PR) && ferror (lp20_unit.fileref)) {
perror ("LP I/O error");
clearerr (uptr -> fileref);
return SCPE_IOERR; }
return SCPE_OK;
}
/* Print routines
lp20_print print a character
lp20_adv advance n lines
lp20_davfu advance to channel on VFU
Return TRUE to continue printing, FALSE to stop
*/
t_bool lp20_print (int32 c)
{
t_bool r = TRUE;
int32 i, rpt = 1;
lppdat = c & 0177; /* mask char to 7b */
if (lppdat == 000) return TRUE; /* NUL? no op */
if (lppdat == 012) return lp20_adv (1, TRUE); /* LF? adv carriage */
if (lppdat == 014) return lp20_davfu (DV_TOF); /* FF? top of form */
if (lppdat == 015) lpcolc = 0; /* CR? reset col cntr */
else if (lppdat == 011) { /* TAB? simulate */
lppdat = ' '; /* with spaces */
if (lpcolc >= 128) {
r = lp20_adv (1, TRUE); /* eol? adv carriage */
rpt = 8; } /* adv to col 9 */
else rpt = 8 - (lpcolc & 07); } /* else adv 1 to 8 */
else { if (lppdat < 040) lppdat = ' '; /* cvt non-prnt to spc */
if (lpcolc >= LP_WIDTH) /* line full? */
r = lp20_adv (1, TRUE); } /* adv carriage */
for (i = 0; i < rpt; i++) putc (lppdat, lp20_unit.fileref);
lp20_unit.pos = lp20_unit.pos + rpt;
lpcolc = lpcolc + rpt;
return r;
}
t_bool lp20_adv (int32 cnt, t_bool dvuadv)
{
int32 i;
if (cnt == 0) return TRUE;
lpcolc = 0; /* reset col cntr */
for (i = 0; i < cnt; i++) putc ('\n', lp20_unit.fileref);
lp20_unit.pos = lp20_unit.pos + cnt; /* print 'n' newlines */
if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */
if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
return TRUE;
}
t_bool lp20_davfu (int32 cnt)
{
int i;
if (cnt > DV_MAX) cnt = 7; /* inval chan? */
for (i = 0; i < dvlnt; i++) { /* search DAVFU */
dvptr = dvptr + 1; /* adv DAVFU ptr */
if (dvptr >= dvlnt) dvptr = 0; /* wrap at end */
if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */
if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */
if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */
putc ('\f', lp20_unit.fileref); /* print form feed */
lp20_unit.pos = lp20_unit.pos + 1;
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
} /* end for */
dvlnt = 0; /* DAVFU error */
return FALSE;
}
/* Update LPCSA, optionally request interrupt */
void update_lpcs (int32 flg)
{
if (flg) lp20_irq = 1; /* set int req */
lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL | CSA_DVON);
lpcsb = (lpcsb | CSB_OFFL | CSB_DVOF) & ~CSB_MBZ;
if (lp20_unit.flags & UNIT_ATT) {
lpcsa = lpcsa | CSA_ONL;
lpcsb = lpcsb & ~CSB_OFFL; }
else lpcsa = lpcsa & ~CSA_DONE;
if (dvlnt) {
lpcsa = lpcsa | CSA_DVON;
lpcsb = lpcsb & ~CSB_DVOF; }
if (lpcsb & CSB_ERR) lpcsa = lpcsa | CSA_ERR;
if ((lpcsa & CSA_IE) && lp20_irq) int_req = int_req | INT_LP20;
else int_req = int_req & ~INT_LP20;
return;
}
/* Acknowledge interrupt (clear internal request) */
int32 lp20_inta (void)
{
lp20_irq = 0; /* clear int req */
return VEC_LP20;
}
t_stat lp20_reset (DEVICE *dptr)
{
lpcsa = CSA_DONE;
lpcsb = 0;
lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */
lprdat = lppdat = lpcbuf = lpcsum = 0;
lp20_irq = 0; /* clear int req */
dvptr = 0; /* reset davfu ptr */
sim_cancel (&lp20_unit); /* deactivate unit */
update_lpcs (0); /* update status */
return SCPE_OK;
}
t_stat lp20_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr); /* attach file */
if (lpcsa & CSA_ONL) return reason; /* just file chg? */
if (sim_is_active (&lp20_unit)) update_lpcs (0); /* busy? no int */
else update_lpcs (CSA_MBZ); /* interrupt */
return reason;
}
t_stat lp20_detach (UNIT *uptr)
{
t_stat reason;
reason = detach_unit (uptr);
sim_cancel (&lp20_unit);
lpcsa = lpcsa & ~CSA_GO;
update_lpcs (CSA_MBZ);
return reason;
}
t_stat lp20_clear_vfu (UNIT *uptr, int32 arg)
{
int i;
if (!get_yn ("Clear DAVFU? [N]", FALSE)) return SCPE_OK;
for (i = 0; i < DV_SIZE; i++) davfu[i] = 0;
dvlnt = dvptr = 0;
update_lpcs (0);
return SCPE_OK;
}

681
pdp10_mdfp.c Normal file
View file

@ -0,0 +1,681 @@
/* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Instructions handled in this module:
imul integer multiply
idiv integer divide
mul multiply
div divide
dmul double precision multiply
ddiv double precision divide
fad(r) floating add (and round)
fsb(r) floating subtract (and round)
fmp(r) floating multiply (and round)
fdv(r) floating divide and round
fsc floating scale
fix(r) floating to fixed (and round)
fltr fixed to floating and round
dfad double precision floating add/subtract
dfmp double precision floating multiply
dfdv double precision floating divide
The PDP-10 stores double (quad) precision integers in sequential
AC's or memory locations. Integers are stored in 2's complement
form. Only the sign of the high order word matters; the signs
in low order words are ignored on input and set to the sign of
the result on output. Quad precision integers exist only in the
AC's as the result of a DMUL or the dividend of a DDIV.
0 00000000011111111112222222222333333
0 12345678901234567890123456789012345
+-+-----------------------------------+
|S| high order integer | AC(n), A
+-+-----------------------------------+
|S| low order integer | AC(n + 1), A + 1
+-+-----------------------------------+
|S| low order integer | AC(n + 2)
+-+-----------------------------------+
|S| low order integer | AC(n + 3)
+-+-----------------------------------+
The PDP-10 supports two floating point formats: single and double
precision. In both, the exponent is 8 bits, stored in excess
128 notation. The fraction is expected to be normalized. A
single precision floating point number has 27 bits of fraction;
a double precision number has 62 bits of fraction (the sign
bit of the second word is ignored and is set to zero).
In a negative floating point number, the exponent is stored in
one's complement form, the fraction in two's complement form.
0 00000000 011111111112222222222333333
0 12345678 901234567890123456789012345
+-+--------+---------------------------+
|S|exponent| high order fraction | AC(n), A
+-+--------+---------------------------+
|0| low order fraction | AC(n + 1), A + 1
+-+------------------------------------+
Note that treatment of the sign is different for double precision
integers and double precision floating point. DMOVN (implemented
as an inline macro) follows floating point conventions.
The original PDP-10 CPU (KA10) used a different format for double
precision numbers and included certain instructions to make
software support easier. These instructions were phased out in
the KL10 and KS10 and are treated as MUUO's.
The KL10 added extended precision (11-bit exponent) floating point
format (so-called G floating). These instructions were not
implemented in the KS10 and are treated as MUUO's.
*/
#include "pdp10_defs.h"
#include <setjmp.h>
struct ufp { /* unpacked fp number */
int32 sign; /* sign */
int32 exp; /* exponent */
uint64 fhi; /* fraction high */
uint64 flo; }; /* for double prec */
typedef struct ufp UFP;
#define MSK32 0xFFFFFFFF
#define FIT27 (DMASK - 0x07FFFFFF)
#define FIT32 (DMASK - MSK32)
#define SFRC TRUE /* frac 2's comp */
#define AFRC FALSE /* frac abs value */
/* In packed floating point number */
#define FP_BIAS 0200 /* exponent bias */
#define FP_N_FHI 27 /* # of hi frac bits */
#define FP_V_FHI 0 /* must be zero */
#define FP_M_FHI 0000777777777
#define FP_N_EXP 8 /* # of exp bits */
#define FP_V_EXP (FP_V_FHI + FP_N_FHI)
#define FP_M_EXP 0377
#define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */
#define FP_N_FLO 35 /* # of lo frac bits */
#define FP_V_FLO 0 /* must be zero */
#define FP_M_FLO 0377777777777
#define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1))
#define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP))
#define GET_FPHI(x) ((x) & FP_M_FHI)
#define GET_FPLO(x) ((x) & FP_M_FLO)
/* In unpacked floating point number */
#define FP_N_GUARD 1 /* # of guard bits */
#define FP_V_UFLO FP_N_GUARD /* <35:1> */
#define FP_V_URNDD (FP_V_UFLO - 1) /* dp round bit */
#define FP_V_UFHI (FP_V_UFLO + FP_N_FLO) /* <62:36> */
#define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */
#define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */
#define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */
#define FP_UFHI 0x7FFFFFF000000000
#define FP_UFLO 0x0000000FFFFFFFFE
#define FP_UFRAC 0x7FFFFFFFFFFFFFFE
#define FP_URNDD 0x0000000000000001
#define FP_URNDS 0x0000000800000000
#define FP_UNORM 0x4000000000000000
#define FP_UCRY 0x8000000000000000
#define FP_ONES 0xFFFFFFFFFFFFFFFF
#define UNEG(x) ((~x) + 1)
#define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0)
extern d10 *ac_cur; /* current AC block */
extern int32 flags; /* flags */
void mul (d10 a, d10 b, d10 *rs);
void funpack (d10 h, d10 l, UFP *r, t_bool sgn);
void fnorm (UFP *r, int64 rnd);
d10 fpack (UFP *r, d10 *lo, t_bool fdvneg);
/* Integer multiply - checked against KS-10 ucode */
d10 imul (d10 a, d10 b)
{
d10 rs[2];
if ((a == SIGN) && (b == SIGN)) { /* KS10 hack */
SETF (F_AOV | F_T1); /* -2**35 squared */
return SIGN; }
mul (a, b, rs); /* mpy, dprec result */
if (rs[0] && (rs[0] != ONES)) { /* high not all sign? */
rs[1] = TSTS (a ^ b)? SETS (rs[1]): CLRS (rs[1]); /* set sign */
SETF (F_AOV | F_T1); } /* overflow */
return rs[1];
}
/* Integer divide, return quotient, remainder - checked against KS10 ucode
The KS10 does not recognize -2^35/-1 as an error. Instead, it produces
2^35 (that is, -2^35) as the incorrect result.
*/
t_bool idiv (d10 a, d10 b, d10 *rs)
{
d10 dvd = ABS (a); /* make ops positive */
d10 dvr = ABS (b);
if (dvr == 0) { /* divide by 0? */
SETF (F_DCK | F_AOV | F_T1); /* set flags, return */
return FALSE; }
rs[0] = dvd / dvr; /* get quotient */
rs[1] = dvd % dvr; /* get remainder */
if (TSTS (a ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
if (TSTS (a)) rs[1] = NEG (rs[1]); /* sign of remainder */
return TRUE;
}
/* Multiply, return double precision result - checked against KS10 ucode */
void mul (d10 s1, d10 s2, d10 *rs)
{
register uint64 a = ABS (s1);
register uint64 b = ABS (s2);
register uint64 t, u, r;
if ((a == 0) || (b == 0)) { /* operand = 0? */
rs[0] = rs[1] = 0; /* result 0 */
return; }
if ((a & FIT32) || (b & FIT32)) { /* fit in 64b? */
t = a >> 18; /* no, split in half */
a = a & RMASK; /* "dp" multiply */
u = b >> 18;
b = b & RMASK;
r = (a * b) + (((a * u) + (b * t)) << 18); /* low is only 35b */
rs[0] = ((t * u) << 1) + (r >> 35); /* so lsh hi 1 */
rs[1] = r & MMASK; }
else { r = a * b; /* fits, native mpy */
rs[0] = r >> 35; /* split at bit 35 */
rs[1] = r & MMASK; }
if (TSTS (s1 ^ s2)) { MKDNEG (rs); } /* result -? */
else if (TSTS (rs[0])) { /* result +, 2**70? */
SETF (F_AOV | F_T1); /* overflow */
rs[1] = SETS (rs[1]); } /* consistent - */
return;
}
/* Divide, return quotient and remainder - checked against KS10 ucode
Note that the initial divide check catches the case -2^70/-2^35;
thus, the quotient can have at most 35 bits.
*/
t_bool divi (int32 ac, d10 b, d10 *rs)
{
register int32 p1 = ADDAC (ac, 1);
register d10 dvr = ABS (b); /* make divr positive */
int64 t;
int32 i;
d10 dvd[2];
dvd[0] = AC(ac); /* divd high */
dvd[1] = CLRS (AC(p1)); /* divd lo, clr sgn */
if (TSTS (AC(ac))) { DMOVN (dvd); } /* make divd positive */
if (dvd[0] >= dvr) { /* divide fail? */
SETF (F_AOV | F_DCK | F_T1); /* set flags, return */
return FALSE; }
if (dvd[0] & FIT27) { /* fit in 63b? */
for (i = 0, rs[0] = 0; i < 35; i++) { /* 35 quotient bits */
dvd[0] = (dvd[0] << 1) | ((dvd[1] >> 34) & 1);
dvd[1] = (dvd[1] << 1) & MMASK; /* shift dividend */
rs[0] = rs[0] << 1; /* shift quotient */
if (dvd[0] >= dvr) { /* subtract work? */
dvd[0] = dvd[0] - dvr; /* quo bit is 1 */
rs[0] = rs[0] + 1; } }
rs[1] = dvd[0]; } /* store remainder */
else { t = (dvd[0] << 35) | dvd[1]; /* concatenate */
rs[0] = t / dvr; /* quotient */
rs[1] = t % dvr; } /* remainder */
if (TSTS (AC(ac) ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
if (TSTS (AC(ac))) rs[1] = NEG (rs[1]); /* sign of remainder */
return TRUE;
}
/* Double precision multiply. This is done the old fashioned way. Cross
product multiplies would be a lot faster but would require more code.
*/
void dmul (int32 ac, d10 *mpy)
{
int32 p1 = ADDAC (ac, 1);
int32 p2 = ADDAC (ac, 2);
int32 p3 = ADDAC (ac, 3);
int32 i;
d10 mpc[2], sign;
mpc[0] = AC(ac); /* mplcnd hi */
mpc[1] = CLRS (AC(p1)); /* mplcnd lo, clr sgn */
sign = mpc[0] ^ mpy[0]; /* sign of result */
if (TSTS (mpc[0])) { DMOVN (mpc); } /* get abs (mpcnd) */
if (TSTS (mpy[0])) { DMOVN (mpy); } /* get abs (mpyer) */
else mpy[1] = CLRS (mpy[1]); /* clear mpy lo sign */
AC(ac) = AC(p1) = AC(p2) = AC(p3) = 0; /* clear AC's */
if (((mpy[0] | mpy[1]) == 0) || ((mpc[0] | mpc[1]) == 0)) return;
for (i = 0; i < 71; i++) { /* 71 mpyer bits */
if (i) { /* shift res, mpy */
AC(p3) = (AC(p3) >> 1) | ((AC(p2) & 1) << 34);
AC(p2) = (AC(p2) >> 1) | ((AC(p1) & 1) << 34);
AC(p1) = (AC(p1) >> 1) | ((AC(ac) & 1) << 34);
AC(ac) = AC(ac) >> 1;
mpy[1] = (mpy[1] >> 1) | ((mpy[0] & 1) << 34);
mpy[0] = mpy[0] >> 1; }
if (mpy[1] & 1) { /* if mpy lo bit = 1 */
AC(p1) = AC(p1) + mpc[1];
AC(ac) = AC(ac) + mpc[0] + (TSTS (AC(p1) != 0));
AC(p1) = CLRS (AC(p1)); } }
if (TSTS (sign)) { /* result minus? */
AC(p3) = (-AC(p3)) & MMASK; /* quad negate */
AC(p2) = (~AC(p2) + (AC(p3) == 0)) & MMASK;
AC(p1) = (~AC(p1) + (AC(p2) == 0)) & MMASK;
AC(ac) = (~AC(ac) + (AC(p1) == 0)) & DMASK; }
else if (TSTS (AC(ac))) SETF (F_AOV | F_T1); /* wrong sign */
if (TSTS (AC(ac))) { /* if result - */
AC(p1) = SETS (AC(p1)); /* make signs consistent */
AC(p2) = SETS (AC(p2));
AC(p3) = SETS (AC(p3)); }
return;
}
/* Double precision divide - checked against KS10 ucode */
void ddiv (int32 ac, d10 *dvr)
{
int32 i, cryin;
d10 sign, qu[2], dvd[4];
dvd[0] = AC(ac); /* save dividend */
for (i = 1; i < 4; i++) dvd[i] = CLRS (AC(ADDAC (ac, i)));
sign = AC(ac) ^ dvr[0]; /* sign of result */
if (TSTS (AC(ac))) { /* get abs (dividend) */
for (i = 3, cryin = 1; i > 0; i--) { /* negate quad */
dvd[i] = (~dvd[i] + cryin) & MMASK; /* comp + carry in */
if (dvd[i]) cryin = 0; } /* next carry in */
dvd[0] = (~dvd[0] + cryin) & DMASK; }
if (TSTS (dvr[0])) { DMOVN (dvr); } /* get abs (divisor) */
else dvr[1] = CLRS (dvr[1]);
if (DCMPGE (dvd, dvr)) { /* will divide work? */
SETF (F_AOV | F_DCK | F_T1); /* no, set flags */
return; }
qu[0] = qu[1] = 0; /* clear quotient */
for (i = 0; i < 70; i++) { /* 70 quotient bits */
dvd[0] = ((dvd[0] << 1) | ((dvd[1] >> 34) & 1)) & DMASK;;
dvd[1] = ((dvd[1] << 1) | ((dvd[2] >> 34) & 1)) & MMASK;
dvd[2] = ((dvd[2] << 1) | ((dvd[3] >> 34) & 1)) & MMASK;
dvd[3] = (dvd[3] << 1) & MMASK; /* shift dividend */
qu[0] = (qu[0] << 1) | ((qu[1] >> 34) & 1); /* shift quotient */
qu[1] = (qu[1] << 1) & MMASK;
if (DCMPGE (dvd, dvr)) { /* subtract work? */
dvd[0] = dvd[0] - dvr[0] - (dvd[1] < dvr[1]);
dvd[1] = (dvd[1] - dvr[1]) & MMASK; /* do subtract */
qu[1] = qu[1] + 1; } } /* set quotient bit */
if (TSTS (sign) && (qu[0] | qu[1])) { MKDNEG (qu); }
if (TSTS (AC(ac)) && (dvd[0] | dvd[1])) { MKDNEG (dvd); }
AC(ac) = qu[0]; /* quotient */
AC(ADDAC(ac, 1)) = qu[1];
AC(ADDAC(ac, 2)) = dvd[0]; /* remainder */
AC(ADDAC(ac, 3)) = dvd[1];
return;
}
/* Single precision floating add - checked against KS10 ucode
The KS10 shifts the smaller operand regardless of the exponent diff.
This code will not shift more than 63 places; shifts beyond that
cannot change the value of the smaller operand.
If the signs of the operands are the same, the result sign is the
same as the source sign; the sign of the result fraction is actually
part of the data. If the signs of the operands are different, the
result sign is determined by the fraction sign.
*/
d10 fad (d10 op1, d10 op2, t_bool rnd, int32 inv)
{
register int32 ediff;
UFP a, b, t;
if (inv) op2 = NEG (op2); /* subtract? -b */
if (op1 == 0) funpack (op2, 0, &a, AFRC); /* a = 0? result is b */
else if (op2 == 0) funpack (op1, 0, &a, AFRC); /* b = 0? result is a */
else { funpack (op1, 0, &a, SFRC); /* unpack operands */
funpack (op2, 0, &b, SFRC); /* fracs are 2's comp */
ediff = a.exp - b.exp; /* get exp diff */
if (ediff < 0) { /* a < b? switch */
t = a;
a = b;
b = t;
ediff = -ediff; }
if (ediff > 63) ediff = 63; /* cap diff at 63 */
if (ediff) b.fhi = (int64) b.fhi >> ediff; /* shift b (signed) */
a.fhi = a.fhi + b.fhi; /* add fractions */
if (a.sign ^ b.sign) { /* add or subtract? */
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
a.fhi = UNEG (a.fhi); /* complement result */
a.sign = 1; } /* result is - */
else a.sign = 0; } /* result is + */
else { if (a.sign) a.fhi = UNEG (a.fhi); /* add, src -? comp */
if (a.fhi & FP_UCRY) { /* check for carry */
a.fhi = a.fhi >> 1; /* flo won't be used */
a.exp = a.exp + 1; } } }
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
return fpack (&a, NULL, FALSE);
}
/* Single precision floating multiply. Because the fractions are 27b,
a 64b multiply can be used for the fraction multiply. The 27b
fractions are positioned 0'frac'0000, resulting in 00'hifrac'0..0.
The extra 0 is accounted for by biasing the result exponent.
*/
#define FP_V_SPM (FP_V_UFHI - (32 - FP_N_FHI - 1))
d10 fmp (d10 op1, d10 op2, t_bool rnd)
{
UFP a, b;
funpack (op1, 0, &a, AFRC); /* unpack operands */
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
if ((a.fhi == 0) || (b.fhi == 0)) return 0; /* either 0? */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
a.fhi = (a.fhi >> FP_V_SPM) * (b.fhi >> FP_V_SPM); /* high 27b of result */
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
return fpack (&a, NULL, FALSE);
}
/* Single precision floating divide. Because the fractions are 27b, a
64b divide can be used for the fraction divide. Note that 28b-29b
of fraction are developed; the code will do one special normalize to
make sure that the 28th bit is not lost. Also note the special
treatment of negative quotients with non-zero remainders; this
implements the note on p2-23 of the Processor Reference Manual.
*/
t_bool fdv (d10 op1, d10 op2, d10 *rs, t_bool rnd)
{
UFP a, b;
uint64 savhi;
t_bool rem = FALSE;
funpack (op1, 0, &a, AFRC); /* unpack operands */
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
SETF (F_AOV | F_DCK | F_FOV | F_T1);
return FALSE; }
if (savhi = a.fhi) { /* dvd = 0? quo = 0 */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */
if (a.sign && (savhi != (a.fhi * (b.fhi >> (FP_N_FHI + 1)))))
rem = TRUE; /* KL/KS hack */
a.fhi = a.fhi << (FP_V_UNORM - FP_N_FHI - 1); /* put quo in place */
if ((a.fhi & FP_UNORM) == 0) { /* normalize 1b */
a.fhi = a.fhi << 1; /* before masking */
a.exp = a.exp - 1; }
a.fhi = a.fhi & (FP_UFHI | FP_URNDS); } /* mask quo to 28b */
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
*rs = fpack (&a, NULL, rem); /* pack result */
return TRUE;
}
/* Single precision floating scale. */
d10 fsc (d10 val, a10 ea)
{
int32 sc = LIT8 (ea);
UFP a;
if (val == 0) return 0;
funpack (val, 0, &a, AFRC); /* unpack operand */
if (ea & RSIGN) a.exp = a.exp - sc; /* adjust exponent */
else a.exp = a.exp + sc;
fnorm (&a, 0); /* renormalize */
return fpack (&a, NULL, FALSE); /* pack result */
}
/* Float integer operand and round */
d10 fltr (d10 mb)
{
UFP a;
d10 val = ABS (mb);
a.sign = GET_FPSIGN (mb); /* get sign */
a.exp = FP_BIAS + 36; /* initial exponent */
a.fhi = val << (FP_V_UNORM - 35); /* left justify op */
a.flo = 0;
fnorm (&a, FP_URNDS); /* normalize, round */
return fpack (&a, NULL, FALSE); /* pack result */
}
/* Fix and truncate/round floating operand */
void fix (int32 ac, d10 mb, t_bool rnd)
{
int32 sc;
uint64 so;
UFP a;
funpack (mb, 0, &a, AFRC); /* unpack operand */
if (a.exp > (FP_BIAS + FP_N_FHI + FP_N_EXP)) SETF (F_AOV | F_T1);
else if (a.exp < (FP_BIAS - 1)) AC(ac) = 0;
else { sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1;
AC(ac) = a.fhi >> sc;
if (rnd) {
so = a.fhi << (64 - sc);
if (so >= (0x8000000000000000 + a.sign)) AC(ac) = AC(ac) + 1; }
if (a.sign) AC(ac) = NEG (AC(ac)); }
return;
}
/* Double precision floating add/subtract
Since a.flo is 0, adding b.flo is just a copy - this is incorporated into
the denormalization step. If there's no denormalization, bflo is zero too.
*/
void dfad (int32 ac, d10 *rs, int32 inv)
{
int32 p1 = ADDAC (ac, 1);
register int32 ediff;
UFP a, b, t;
if (inv) { DMOVN (rs); } /* subtract? -b */
if ((AC(ac) | AC(p1)) == 0) funpack (rs[0], rs[1], &a, AFRC);
/* a == 0? sum = b */
else if ((rs[0] | rs[1]) == 0) funpack (AC(ac), AC(p1), &a, AFRC);
/* b == 0? sum = a */
else {
funpack (AC(ac), AC(p1), &a, SFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, SFRC);
ediff = a.exp - b.exp; /* get exp diff */
if (ediff < 0) { /* a < b? switch */
t = a;
a = b;
b = t;
ediff = -ediff; }
if (ediff > 127) ediff = 127; /* cap diff at 127 */
if (ediff > 63) { /* diff > 63? */
a.flo = (int64) b.fhi >> (ediff - 64); /* b hi to a lo */
b.fhi = b.sign? FP_ONES: 0; } /* hi = all sign */
else if (ediff) { /* diff <= 63 */
a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff));
b.fhi = (int64) b.fhi >> ediff; } /* shift b (signed) */
a.fhi = a.fhi + b.fhi; /* do add */
if (a.sign ^ b.sign) { /* add or subtract? */
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
DUNEG (a); /* complement result */
a.sign = 1; } /* result is - */
else a.sign = 0; } /* result is + */
else { if (a.sign) { DUNEG (a); }; /* add, src -? comp */
if (a.fhi & FP_UCRY) { /* check for carry */
a.fhi = a.fhi >> 1; /* flo won't be used */
a.exp = a.exp + 1; } } }
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
return;
}
/* Double precision floating multiply
The 62b fractions are multiplied, with cross products, to produce a
124b fraction with two leading and two trailing 0's. Because the
product has 2 leading 0's, instead of the normal 1, an extra
normalization step is needed. Accordingly, the exponent calculation
increments the result exponent, to compensate for normalization.
*/
void dfmp (int32 ac, d10 *rs)
{
int32 p1 = ADDAC (ac, 1);
uint64 xh, xl, yh, yl, mid;
UFP a, b;
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, AFRC);
if ((a.fhi == 0) || (b.fhi == 0)) { /* either 0? result 0 */
AC(ac) = AC(p1) = 0;
return; }
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
xh = a.fhi >> 32; /* split 62b fracs */
xl = a.fhi & MSK32; /* into 32b halves */
yh = b.fhi >> 32;
yl = b.fhi & MSK32;
a.fhi = xh * yh; /* hi xproduct */
a.flo = xl * yl; /* low xproduct */
mid = (xh * yl) + (yh * xl); /* fits in 64b */
a.flo = a.flo + (mid << 32); /* add mid lo to lo */
a.fhi = a.fhi + ((mid >> 32) & MSK32) + (a.flo < (mid << 32));
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
return;
}
/* Double precision floating divide
This algorithm develops a full 62 bits of quotient, plus one rounding
bit, in the low order 63b of a 64b number. To do this, we must assure
that the initial divide step generates a 1. If it would fail, shift
the dividend left and decrement the result exponent accordingly.
*/
void dfdv (int32 ac, d10 *rs)
{
int32 p1 = ADDAC (ac, 1);
int32 i;
uint64 qu = 0;
UFP a, b;
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, AFRC);
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
SETF (F_AOV | F_DCK | F_FOV | F_T1);
return; }
if (a.fhi) { /* dvd = 0? quo = 0 */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
if (a.fhi < b.fhi) { /* make sure initial */
a.fhi = a.fhi << 1; /* divide step will work */
a.exp = a.exp - 1; }
for (i = 0; i < 63; i++) { /* 63b of quotient */
qu = qu << 1; /* shift quotient */
if (a.fhi >= b.fhi) { /* will div work? */
a.fhi = a.fhi - b.fhi; /* sub, quo = 1 */
qu = qu + 1; }
a.fhi = a.fhi << 1; } /* shift dividend */
a.fhi = qu; }
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
return;
}
/* Unpack floating point operand */
void funpack (d10 h, d10 l, UFP *r, t_bool sgn)
{
d10 fphi, fplo;
r -> sign = GET_FPSIGN (h);
r -> exp = GET_FPEXP (h);
fphi = GET_FPHI (h);
fplo = GET_FPLO (l);
r -> fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO);
r -> flo = 0;
if (r -> sign) {
r -> exp = r -> exp ^ FP_M_EXP;
if (sgn) r -> fhi = r -> fhi | FP_UCRY; /* ext sign */
else { if (r -> fhi) r -> fhi = UNEG (r -> fhi) & FP_UFRAC;
else { r -> exp = r -> exp + 1;
r -> fhi = FP_UNORM; } } }
return;
}
/* Normalize and optionally round floating point operand */
void fnorm (UFP *a, int64 rnd)
{
int32 i;
static uint64 normmask[6] = {
0x6000000000000000, 0x7800000000000000, 0x7F80000000000000,
0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF };
static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 };
if ((a -> fhi | a -> flo) == 0) { /* if fraction = 0 */
a -> sign = a -> exp = 0; /* result is 0 */
return; }
while ((a -> fhi & FP_UNORM) == 0) { /* normalized? */
for (i = 0; i < 6; i++) {
if (a -> fhi & normmask[i]) break; }
a -> fhi = (a -> fhi << normtab[i]) | (a -> flo >> (64 - normtab[i]));
a -> flo = a -> flo << normtab[i];
a -> exp = a -> exp - normtab[i]; }
if (rnd) { /* rounding? */
a -> fhi = a -> fhi + rnd; /* add round const */
if (a -> fhi & FP_UCRY) { /* if carry out, */
a -> fhi = a -> fhi >> 1; /* renormalize */
a -> exp = a -> exp + 1; } }
return;
}
/* Pack floating point result */
d10 fpack (UFP *r, d10 *lo, t_bool fdvneg)
{
d10 val[2];
if (r -> exp < 0) SETF (F_AOV | F_FOV | F_FXU | F_T1);
else if (r -> exp > FP_M_EXP) SETF (F_AOV | F_FOV | F_T1);
val[0] = (((((d10) r -> exp) & FP_M_EXP) << FP_V_EXP) |
((r -> fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK;
if (lo) val[1] = ((r -> fhi & FP_UFLO) >> FP_V_UFLO) & MMASK;
else val[1] = 0;
if (r -> sign) { /* negate? */
if (fdvneg) { /* fdvr special? */
val[1] = ~val[1] & MMASK; /* 1's comp */
val[0] = ~val[0] & DMASK; }
else { DMOVN (val); } } /* 2's comp */
if (lo) *lo = val[1];
return val[0];
}

792
pdp10_pag.c Normal file
View file

@ -0,0 +1,792 @@
/* pdp10_pag.c: PDP-10 paging subsystem simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
pag KS10 pager
03-May-01 RMS Fixed bug in indirect page table pointer processing
29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR
The pager consists of a standard hardware part (the translation
tables) and an operating-system specific page table fill routine.
There are two translation tables, one for executive mode and one
for user mode. Each table consists of 512 page table entries,
one for each page in the 18b virtual address space. Each pte
contains (in the hardware) a valid bit, a writeable bit, an
address space bit (executive or user), and a cacheable bit, plus
the physical page number corresponding to the virtual page. In
the simulator, the pte is expanded for rapid processing of normal
reads and writes. An expanded pte contains a valid bit, a writeable
bit, and the physical page number shifted left by the page size.
Expanded pte meaning
0 invalid
>0 read only
<0 read write
There is a third, physical table, which is used in place of the
executive and user tables if paging is off. Its entries are always
valid and always writeable.
To translate a virtual to physical address, the simulator uses
the virtual page number to index into the appropriate page table.
If the page table entry (pte) is not valid, the page fill routine
is called to see if the entry is merely not filled or is truly
inaccessible. If the pte is valid but not writeable, and the
reference is a write reference, the page fill routine is also
called to see if the reference can be resolved.
The page fill routine is operating system dependent. Three styles
of paging are supported:
TOPS10 known in the KS10 microcode as KI10 paging,
used by earlier versions of TOPS10
TOPS20 known in the KS10 microcode as KL10 paging,
used by later versions of TOPS10, and TOPS20
ITS used only by ITS
TOPS10 vs TOPS20 is selected by a bit in the EBR; ITS paging is
"hardwired" (it required different microcode).
*/
#include "pdp10_defs.h"
#include <setjmp.h>
/* Page table (contains expanded pte's) */
#define PTBL_ASIZE PAG_N_VPN
#define PTBL_MEMSIZE (1 << PTBL_ASIZE) /* page table size */
#define PTBL_AMASK (PTBL_MEMSIZE - 1)
#define PTBL_M (1u << 31) /* must be sign bit */
#define PTBL_V (1u << 30)
#define PTBL_MASK (PAG_PPN | PTBL_M | PTBL_V)
/* NXM processing */
#define REF_V 0 /* ref is virt */
#define REF_P 1 /* ref is phys */
#define PF_OK 0 /* pfail ok */
#define PF_TR 1 /* pfail trap */
extern d10 *M;
extern d10 acs[AC_NBLK * AC_NUM];
extern d10 *ac_cur, *ac_prv, *last_pa;
extern a10 epta, upta;
extern int32 flags;
extern d10 pager_word;
extern int32 apr_flg;
extern d10 ebr, ubr, hsb;
extern d10 spt, cst, cstm, pur;
extern a10 dbr1, dbr2, dbr3, dbr4;
extern d10 pcst, quant;
extern t_bool paging;
extern UNIT cpu_unit;
extern jmp_buf save_env;
extern int32 test_int (void);
extern int32 pi_eval (void);
int32 eptbl[PTBL_MEMSIZE]; /* exec page table */
int32 uptbl[PTBL_MEMSIZE]; /* user page table */
int32 physptbl[PTBL_MEMSIZE]; /* phys page table */
int32 *ptbl_cur, *ptbl_prv;
int32 save_ea;
int32 ptbl_fill (a10 ea, int32 *ptbl, int32 mode);
t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat pag_reset (DEVICE *dptr);
void pag_nxm (a10 pa, int32 phys, int32 trap);
/* Pager data structures
pag_dev pager device descriptor
pag_unit pager units
pager_reg pager register list
*/
UNIT pag_unit[] = {
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) },
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) } };
REG pag_reg[] = {
{ ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO },
{ NULL } };
DEVICE pag_dev = {
"PAG", pag_unit, pag_reg, NULL,
2, 8, PTBL_ASIZE, 1, 8, 32,
&pag_ex, &pag_dep, &pag_reset,
NULL, NULL, NULL };
/* Memory read and write routines
Read - read current or previous, read checking
ReadM - read current or previous, write checking
ReadE - read exec
ReadP - read physical
Write - write current or previous
WriteE - write exec
WriteP - write physical
AccChk - test accessibility of virtual address
*/
d10 Read (a10 ea, int32 prv)
{
register int32 pa, vpn, xpte;
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte == 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_RD);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
}
d10 ReadM (a10 ea, int32 prv)
{
register int32 pa, vpn, xpte;
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
}
d10 ReadE (a10 ea)
{
register int32 pa, vpn, xpte;
if (ea < AC_NUM) return AC(ea); /* AC? use current */
if (!PAGING) return M[ea]; /* phys? no mapping */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
if (xpte == 0) xpte = ptbl_fill (ea, eptbl, PTF_RD);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
}
d10 ReadP (a10 ea)
{
if (ea < AC_NUM) return AC(ea); /* AC request */
if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
return M[ea]; /* return data */
}
void Write (a10 ea, d10 val, int32 prv)
{
register int32 pa, vpn, xpte;
if (ea < AC_NUM) { /* AC request */
if (prv) ac_prv[ea] = val; /* write AC */
else ac_cur[ea] = val; }
else { vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
else M[pa] = val; } /* write data */
return;
}
void WriteE (a10 ea, d10 val)
{
register int32 pa, vpn, xpte;
if (ea < AC_NUM) AC(ea) = val; /* AC? use current */
else if (!PAGING) M[ea] = val; /* phys? no mapping */
else { vpn = PAG_GETVPN (ea); /* get page num */
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
if (xpte >= 0) xpte = ptbl_fill (ea, eptbl, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
else M[pa] = val; } /* write data */
return;
}
void WriteP (a10 ea, d10 val)
{
if (ea < AC_NUM) AC(ea) = val; /* AC request */
else { if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
M[ea] = val; } /* memory */
return;
}
t_bool AccViol (a10 ea, int32 prv, int32 mode)
{
register int32 vpn, xpte;
if (ea < AC_NUM) return FALSE; /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP);
if (xpte) return FALSE; /* accessible */
return TRUE; /* not accessible */
}
void pag_nxm (a10 pa, int32 phys, int32 trap)
{
apr_flg = apr_flg | APRF_NXM; /* set APR flag */
pi_eval (); /* eval intr */
pager_word = PF_NXM | (phys? PF_NXMP: 0) |
(TSTF (F_USR)? PF_USER: 0) | ((d10) pa);
if (PAGING && trap) ABORT (PAGE_FAIL); /* trap? */
return;
}
/* Page table fill
This routine is called if the page table is invalid, or on a write
reference if the page table is read only. If the access is allowed
it stores the pte in the page table entry and returns an expanded
pte for use by the caller. Otherwise, it generates a page fail.
Notes:
- If called from the console, invalid references return a pte
of 0, and the page table entry is not filled.
- If called from MAP, invalid references return a pte of 0. The
page fail word is properly set up.
*/
#define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) return 0; \
ABORT (PAGE_FAIL)
#define READPT(x,y) if (MEM_ADDR_NXM (y)) { \
pag_nxm (y, REF_P, PF_OK); \
PAGE_FAIL_TRAP; } \
x = ReadP (y)
int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode)
{
/* ITS paging is based on conventional page tables. ITS divides each address
space into a 128K high and low section, and uses different descriptor base
pointers (dbr) for each. ITS pages are twice the size of DEC standard;
therefore, the fill routine fills two page table entries and returns the pte
that maps the correct ITS half page. This allows the DEC paging macros to
be used in the normal path read-write routines.
ITS has no MAP instruction, therefore, physical NXM traps are ok.
*/
if (ITS) { /* ITS paging */
int32 acc, decvpn, pte, vpn, ptead, xpte;
d10 ptewd;
vpn = ITS_GETVPN (ea); /* get ITS pagno */
if (tbl == uptbl)
ptead = ((ea & RSIGN)? dbr2: dbr1) + ((vpn >> 1) & 077);
else ptead = ((ea & RSIGN)? dbr4: dbr3) + ((vpn >> 1) & 077);
ptewd = ReadP (ptead); /* get PTE pair */
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
acc = ITS_GETACC (pte); /* get access */
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_ITS_WRITE: 0) | (acc << PF_ITS_V_ACC);
if ((acc != ITS_ACC_NO) && (!(mode & PTF_WR) || (acc == ITS_ACC_RW))) {
pte = pte & ~PTE_ITS_AGE; /* clear age */
if (vpn & 1) WriteP (ptead, (ptewd & LMASK) | pte);
else WriteP (ptead, (ptewd & RMASK) | (((d10) pte) << 18));
xpte = ((pte & PTE_ITS_PPMASK) << ITS_V_PN) | PTBL_V |
((acc == ITS_ACC_RW)? PTBL_M: 0);
decvpn = PAG_GETVPN (ea); /* get tlb idx */
if (!(mode & PTF_CON)) {
tbl[decvpn & ~1] = xpte; /* map lo ITS page */
tbl[decvpn | 1] = xpte + PAG_SIZE; } /* map hi */
return (xpte + ((decvpn & 1)? PAG_SIZE: 0)); }
PAGE_FAIL_TRAP;
} /* end ITS paging */
/* TOPS-10 paging - checked against KS10 microcode
TOPS-10 paging is also based on conventional page tables. The user page
tables are arranged contiguously at the beginning of the user process table;
however, the executive page tables are scattered through the executive and
user process tables.
*/
else if (!T20) { /* TOPS-10 paging */
int32 pte, vpn, ptead, xpte;
d10 ptewd;
vpn = PAG_GETVPN (ea); /* get virt page num */
if (tbl == uptbl) ptead = upta + UPT_T10_UMAP + (vpn >> 1);
else if (vpn < 0340) ptead = epta + EPT_T10_X000 + (vpn >> 1);
else if (vpn < 0400) ptead = upta + UPT_T10_X340 + ((vpn - 0340) >> 1);
else ptead = epta + EPT_T10_X400 + ((vpn - 0400) >> 1);
READPT (ptewd, ptead); /* get PTE pair */
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_WRITE: 0) |
((pte & PTE_T10_A)? PF_T10_A |
((pte & PTE_T10_S)? PF_T10_S: 0): 0);
if (mode & PTF_MAP) pager_word = pager_word | /* map? add to pf wd */
((pte & PTE_T10_W)? PF_T10_W: 0) | /* W, S, C bits */
((pte & PTE_T10_S)? PF_T10_S: 0) |
((pte & PTE_T10_C)? PF_C: 0);
if ((pte & PTE_T10_A) && (!(mode & PTF_WR) || (pte & PTE_T10_W))) {
xpte = ((pte & PTE_PPMASK) << PAG_V_PN) | /* calc exp pte */
PTBL_V | ((pte & PTE_T10_W)? PTBL_M: 0);
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
return xpte; }
PAGE_FAIL_TRAP;
} /* end TOPS10 paging */
/* TOPS-20 paging - checked against KS10 ucode.
TOPS-20 paging has three phases:
1. Starting at EPT/UPT + 540 + section number, chase section pointers to
get the pointer to the section page table. In the KS10, because there
is only one section, the microcode caches the result of this evaluation.
Also, the evaluation of indirect pointers is simplified, as the section
table index is ignored.
2. Starting with the page map pointer, chase page pointers to get the
pointer to the page. The KS10 allows the operating system to inhibit
updating of the CST (base address = 0).
3. Use the page pointer to get the CST entry. If a write reference to
a writeable page, set CST_M. If CST_M is set, set M in page table.
*/
else { /* TOPS-20 paging */
int32 pmi, vpn, xpte;
int32 flg, t;
t_bool stop;
a10 pa, csta;
d10 ptr, cste;
d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_WRITE: 0); /* set page fail word */
/* First phase - evaluate section pointers - returns a ptr to a page map
As a single section machine, the KS10 short circuits this part of the
process. In particular, the indirect pointer calculation assumes that
the section table index will be 0. It adds the full pointer (not just
the right half) to the SPT base. If the section index is > 0, the
result is a physical memory address > 256KW. Depending on the size of
memory, the SPT fetch may or may not generate a NXM page fail. The
KS10 then ignores the section table index in fetching the next pointer.
The KS10 KL10 memory management diagnostic (dskec.sav) tests for this
behavior with a section index of 3. However, this would be a legal
physical address in a system with 1MW. Accordingly, the simulator
special cases non-zero section indices (which can't work in any case)
to generate the right behavior for the diagnostic.
*/
vpn = PAG_GETVPN (ea); /* get virt page num */
pa = (tbl == uptbl)? upta + UPT_T20_SCTN: epta + EPT_T20_SCTN;
READPT (ptr, pa & PAMASK); /* get section 0 ptr */
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval section ptrs */
acc = acc & ptr; /* cascade acc bits */
switch (T20_GETTYP (ptr)) { /* case on ptr type */
case T20_NOA: /* no access */
default: /* undefined type */
PAGE_FAIL_TRAP; /* page fail */
case T20_IMM: /* immediate */
stop = TRUE; /* exit */
break;
case T20_SHR: /* shared */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
stop = TRUE; /* exit */
break;
case T20_IND: /* indirect */
if (flg && (t = test_int ())) ABORT (t);
pmi = T20_GETPMI (ptr); /* get sect tbl idx */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
if (pmi) { /* for dskec */
pag_nxm ((pmi << 18) | pa, REF_P, PF_OK);
PAGE_FAIL_TRAP; }
READPT (ptr, pa & PAMASK); /* get SPT entry */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; }
pa = PAG_PTEPA (ptr, pmi); /* index off page */
READPT (ptr, pa & PAMASK); /* get pointer */
break; /* continue in loop */
} /* end case */
} /* end for */
/* Second phase - found page map ptr, evaluate page pointers */
pa = PAG_PTEPA (ptr, vpn); /* get ptbl address */
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval page ptrs */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-res? */
if (cst) { /* cst really there? */
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
READPT (cste, csta); /* get CST entry */
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
cste = (cste & cstm) | pur; /* update entry */
WriteP (csta, cste); } /* rewrite */
READPT (ptr, pa & PAMASK); /* get pointer */
acc = acc & ptr; /* cascade acc bits */
switch (T20_GETTYP (ptr)) { /* case on ptr type */
case T20_NOA: /* no access */
default: /* undefined type */
PAGE_FAIL_TRAP; /* page fail */
case T20_IMM: /* immediate */
stop = TRUE; /* exit */
break;
case T20_SHR: /* shared */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
stop = TRUE; /* exit */
break;
case T20_IND: /* indirect */
if (flg && (t = test_int ())) ABORT (t);
pmi = T20_GETPMI (ptr); /* get section index */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
pa = PAG_PTEPA (ptr, pmi); /* index off page */
break; /* continue in loop */
} /* end case */
} /* end for */
/* Last phase - have final page pointer, check modifiability */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-resident? */
if (cst) { /* CST really there? */
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
READPT (cste, csta); /* get CST entry */
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
cste = (cste & cstm) | pur; } /* update entry */
else cste = 0; /* no, entry = 0 */
pager_word = pager_word | PF_T20_DN; /* set eval done */
xpte = ((int32) ((ptr & PTE_PPMASK) << PAG_V_PN)) | PTBL_V;
if (mode & PTF_WR) { /* write? */
if (acc & PTE_T20_W) { /* writable? */
xpte = xpte | PTBL_M; /* set PTE M */
cste = cste | CST_M; } /* set CST M */
else { PAGE_FAIL_TRAP; } } /* no, trap */
if (cst) WriteP (csta, cste); /* write CST entry */
if (mode & PTF_MAP) pager_word = pager_word | /* map? more in pf wd */
((xpte & PTBL_M)? PF_T20_M: 0) | /* M, W, C bits */
((acc & PTE_T20_W)? PF_T20_W: 0) |
((acc & PTE_T20_C)? PF_C: 0);
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
return xpte;
} /* end TOPS20 paging */
}
/* Set up pointers for AC, memory, and process table access */
void set_dyn_ptrs (void)
{
int32 t;
if (PAGING) {
ac_cur = &acs[UBR_GETCURAC (ubr) * AC_NUM];
ac_prv = &acs[UBR_GETPRVAC (ubr) * AC_NUM];
if (TSTF (F_USR)) ptbl_cur = ptbl_prv = &uptbl[0];
else { ptbl_cur = &eptbl[0];
ptbl_prv = TSTF (F_UIO)? &uptbl[0]: &eptbl[0]; } }
else { ac_cur = ac_prv = &acs[0];
ptbl_cur = ptbl_prv = &physptbl[0]; }
t = EBR_GETEBR (ebr);
epta = t << PAG_V_PN;
if (ITS) upta = (int32) ubr & PAMASK;
else { t = UBR_GETUBR (ubr);
upta = t << PAG_V_PN; }
return;
}
/* MAP instruction, TOPS-10 and TOPS-20 only
According to the KS-10 ucode, map with paging disabled sets
"accessible, writeable, software", regardless of whether
TOPS-10 or TOPS-20 paging is implemented
*/
d10 map (a10 ea, int32 prv)
{
int32 xpte;
d10 val = (TSTF (F_USR)? PF_USER: 0);
if (!PAGING) return (val | PF_T10_A | PF_T10_W | PF_T10_S | ea);
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_MAP); /* get exp pte */
if (xpte) val = (pager_word & ~PAMASK) | PAG_XPTEPA (xpte, ea);
else { if (pager_word & PF_HARD) val = pager_word; /* hard error */
else val = val | PF_VIRT | ea; } /* inaccessible */
return val;
}
/* Mapping routine for console */
a10 conmap (a10 ea, int32 mode, int32 sw)
{
int32 xpte, *tbl;
if (!PAGING) return ea;
set_dyn_ptrs (); /* in case changed */
if (sw & SWMASK ('E')) tbl = eptbl;
else if (sw & SWMASK ('U')) tbl = uptbl;
else tbl = ptbl_cur;
xpte = ptbl_fill (ea, tbl, mode);
if (xpte) return PAG_XPTEPA (xpte, ea);
else return MAXMEMSIZE;
}
/* Common pager instructions */
t_bool clrpt (a10 ea, int32 prv)
{
int32 vpn = PAG_GETVPN (ea); /* get page num */
if (ITS) { /* ITS? */
uptbl[vpn & ~1] = 0; /* clear double size */
uptbl[vpn | 1] = 0; /* entries in */
eptbl[vpn & ~1] = 0; /* both page tables */
eptbl[vpn | 1] = 0; }
else { uptbl[vpn] = 0; /* clear entries in */
eptbl[vpn] = 0; } /* both page tables */
return FALSE;
}
t_bool wrebr (a10 ea, int32 prv)
{
ebr = ea & EBR_MASK; /* store EBR */
pag_reset (&pag_dev); /* clear page tables */
set_dyn_ptrs (); /* set dynamic ptrs */
return FALSE;
}
t_bool rdebr (a10 ea, int32 prv)
{
Write (ea, (ebr & EBR_MASK), prv);
return FALSE;
}
t_bool wrubr (a10 ea, int32 prv)
{
d10 val = Read (ea, prv);
d10 ubr_mask = (ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */
if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */
else val = val & ~UBR_ACBMASK; /* no, keep old val */
if (val & UBR_SETUBR) { /* set UBR? */
ubr = ubr & ~ubr_mask;
pag_reset (&pag_dev); } /* yes, clr pg tbls */
else val = val & ~ubr_mask; /* no, keep old val */
ubr = (ubr | val) & (UBR_ACBMASK | ubr_mask);
set_dyn_ptrs ();
return FALSE;
}
t_bool rdubr (a10 ea, int32 prv)
{
ubr = ubr & (UBR_ACBMASK | (ITS? PAMASK: UBR_UBRMASK));
Write (ea, UBRWORD, prv);
return FALSE;
}
t_bool wrhsb (a10 ea, int32 prv)
{
hsb = Read (ea, prv) & PAMASK;
return FALSE;
}
t_bool rdhsb (a10 ea, int32 prv)
{
Write (ea, hsb, prv);
return FALSE;
}
/* TOPS20 pager instructions */
t_bool wrspb (a10 ea, int32 prv)
{
spt = Read (ea, prv);
return FALSE;
}
t_bool rdspb (a10 ea, int32 prv)
{
Write (ea, spt, prv);
return FALSE;
}
t_bool wrcsb (a10 ea, int32 prv)
{
cst = Read (ea, prv);
return FALSE;
}
t_bool rdcsb (a10 ea, int32 prv)
{
Write (ea, cst, prv);
return FALSE;
}
t_bool wrpur (a10 ea, int32 prv)
{
pur = Read (ea, prv);
return FALSE;
}
t_bool rdpur (a10 ea, int32 prv)
{
Write (ea, pur, prv);
return FALSE;
}
t_bool wrcstm (a10 ea, int32 prv)
{
cstm = Read (ea, prv);
return FALSE;
}
t_bool rdcstm (a10 ea, int32 prv)
{
Write (ea, cstm, prv);
return FALSE;
}
/* ITS pager instructions
The KS10 does not implement the JPC option.
*/
t_bool clrcsh (a10 ea, int32 prv)
{
return FALSE;
}
t_bool ldbr1 (a10 ea, int32 prv)
{
dbr1 = ea;
pag_reset (&pag_dev);
return FALSE;
}
t_bool sdbr1 (a10 ea, int32 prv)
{
Write (ea, dbr1, prv);
return FALSE;
}
t_bool ldbr2 (a10 ea, int32 prv)
{
dbr2 = ea;
pag_reset (&pag_dev);
return FALSE;
}
t_bool sdbr2 (a10 ea, int32 prv)
{
Write (ea, dbr2, prv);
return FALSE;
}
t_bool ldbr3 (a10 ea, int32 prv)
{
dbr3 = ea;
pag_reset (&pag_dev);
return FALSE;
}
t_bool sdbr3 (a10 ea, int32 prv)
{
Write (ea, dbr3, prv);
return FALSE;
}
t_bool ldbr4 (a10 ea, int32 prv)
{
dbr4 = ea;
pag_reset (&pag_dev);
return FALSE;
}
t_bool sdbr4 (a10 ea, int32 prv)
{
Write (ea, dbr4, prv);
return FALSE;
}
t_bool wrpcst (a10 ea, int32 prv)
{
pcst = Read (ea, prv);
return FALSE;
}
t_bool rdpcst (a10 ea, int32 prv)
{
Write (ea, pcst, prv);
return FALSE;
}
t_bool lpmr (a10 ea, int32 prv)
{
d10 val;
val = Read (ADDA (ea, 2), prv);
dbr1 = (a10) (Read (ea, prv) & AMASK);
dbr2 = (a10) (Read (ADDA (ea, 1), prv) & AMASK);
quant = val;
return FALSE;
}
t_bool spm (a10 ea, int32 prv)
{
ReadM (ADDA (ea, 2), prv);
Write (ea, dbr1, prv);
Write (ADDA (ea, 1), dbr2, prv);
Write (ADDA (ea, 2), quant, prv);
return FALSE;
}
t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
int32 tbln = uptr - pag_unit;
if (addr >= PTBL_MEMSIZE) return SCPE_NXM;
*vptr = tbln? uptbl[addr]: eptbl[addr];;
return SCPE_OK;
}
t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
int32 tbln = uptr - pag_unit;
if (addr >= PTBL_MEMSIZE) return SCPE_NXM;
if (tbln) uptbl[addr] = (int32) val & PTBL_MASK;
else eptbl[addr] = (int32) val & PTBL_MASK;
return SCPE_OK;
}
t_stat pag_reset (DEVICE *dptr)
{
int32 i;
for (i = 0; i < PTBL_MEMSIZE; i++) {
eptbl[i] = uptbl[i] = 0;
physptbl[i] = (i << PAG_V_PN) + PTBL_M + PTBL_V; }
return SCPE_OK;
}

279
pdp10_pt.c Normal file
View file

@ -0,0 +1,279 @@
/* pdp10_pt.c: PDP-10 Unibus paper tape reader/punch simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ptr paper tape reader
ptp paper tape punch
*/
#include "pdp10_defs.h"
#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */
#define PTRCSR_RW (CSR_IE)
#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */
#define PTPCSR_RW (CSR_IE)
extern int32 int_req, dev_enb;
int32 ptr_csr = 0; /* control/status */
int32 ptr_stopioe = 0; /* stop on error */
int32 ptp_csr = 0; /* control/status */
int32 ptp_stopioe = 0; /* stop on error */
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
t_stat ptr_attach (UNIT *uptr, char *ptr);
t_stat ptr_detach (UNIT *uptr);
t_stat ptp_attach (UNIT *uptr, char *ptr);
t_stat ptp_detach (UNIT *uptr);
/* PTR data structures
ptr_dev PTR device descriptor
ptr_unit PTR unit descriptor
ptr_reg PTR register list
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (CSR, ptr_csr, 16) },
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (INT, int_req, INT_V_PTR) },
{ FLDATA (ERR, ptr_csr, CSR_V_ERR) },
{ FLDATA (BUSY, ptr_csr, CSR_V_BUSY) },
{ FLDATA (DONE, ptr_csr, CSR_V_DONE) },
{ FLDATA (IE, ptr_csr, CSR_V_IE) },
{ DRDATA (POS, ptr_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_PTR), REG_HRO },
{ NULL } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
NULL, &ptr_attach, &ptr_detach };
/* PTP data structures
ptp_dev PTP device descriptor
ptp_unit PTP unit descriptor
ptp_reg PTP register list
*/
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ ORDATA (CSR, ptp_csr, 16) },
{ FLDATA (INT, int_req, INT_V_PTP) },
{ FLDATA (ERR, ptp_csr, CSR_V_ERR) },
{ FLDATA (DONE, ptp_csr, CSR_V_DONE) },
{ FLDATA (IE, ptp_csr, CSR_V_IE) },
{ DRDATA (POS, ptp_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_PTR), REG_HRO },
{ NULL } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, &ptp_attach, &ptp_detach };
/* Standard I/O dispatch routine, I/O addresses 17777550-17777557
17777550 ptr CSR
17777552 ptr buffer
17777554 ptp CSR
17777556 ptp buffer
Note: Word access routines filter out odd addresses. Thus,
an odd address implies an (odd) byte access.
*/
t_stat pt_rd (int32 *data, int32 PA, int32 access)
{
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 0: /* ptr csr */
*data = ptr_csr & PTRCSR_IMP;
return SCPE_OK;
case 1: /* ptr buf */
ptr_csr = ptr_csr & ~CSR_DONE;
int_req = int_req & ~INT_PTR;
*data = ptr_unit.buf & 0377;
return SCPE_OK;
case 2: /* ptp csr */
*data = ptp_csr & PTPCSR_IMP;
return SCPE_OK;
case 3: /* ptp buf */
*data = ptp_unit.buf;
return SCPE_OK; }
return SCPE_NXM; /* can't get here */
}
t_stat pt_wr (int32 data, int32 PA, int32 access)
{
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 0: /* ptr csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTR;
else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE)))
int_req = int_req | INT_PTR;
if (data & CSR_GO) {
ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY;
int_req = int_req & ~INT_PTR;
if (ptr_unit.flags & UNIT_ATT) /* data to read? */
sim_activate (&ptr_unit, ptr_unit.wait);
else sim_activate (&ptr_unit, 0); } /* error if not */
ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW);
return SCPE_OK;
case 1: /* ptr buf */
return SCPE_OK;
case 2: /* ptp csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTP;
else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE)))
int_req = int_req | INT_PTP;
ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW);
return SCPE_OK;
case 3: /* ptp buf */
if ((PA & 1) == 0) ptp_unit.buf = data & 0377;
ptp_csr = ptp_csr & ~CSR_DONE;
int_req = int_req & ~INT_PTP;
if (ptp_unit.flags & UNIT_ATT) /* file to write? */
sim_activate (&ptp_unit, ptp_unit.wait);
else sim_activate (&ptp_unit, 0); /* error if not */
return SCPE_OK; } /* end switch PA */
return SCPE_NXM; /* can't get here */
}
/* Paper tape reader routines
ptr_svc process event (character ready)
ptr_reset process reset
ptr_attach process attach
ptr_detach process detach
*/
t_stat ptr_svc (UNIT *uptr)
{
int32 temp;
ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY;
if (ptr_csr & CSR_IE) int_req = int_req | INT_PTR;
if ((ptr_unit.flags & UNIT_ATT) == 0)
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) {
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR;
ptr_unit.buf = temp & 0377;
ptr_unit.pos = ptr_unit.pos + 1;
return SCPE_OK;
}
t_stat ptr_reset (DEVICE *dptr)
{
ptr_unit.buf = 0;
ptr_csr = 0;
if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR;
int_req = int_req & ~INT_PTR;
sim_cancel (&ptr_unit);
return SCPE_OK;
}
t_stat ptr_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR;
else ptr_csr = ptr_csr & ~CSR_ERR;
return reason;
}
t_stat ptr_detach (UNIT *uptr)
{
ptr_csr = ptr_csr | CSR_ERR;
return detach_unit (uptr);
}
/* Paper tape punch routines
ptp_svc process event (character punched)
ptp_reset process reset
ptp_attach process attach
ptp_detach process detach
*/
t_stat ptp_svc (UNIT *uptr)
{
ptp_csr = ptp_csr | CSR_ERR | CSR_DONE;
if (ptp_csr & CSR_IE) int_req = int_req | INT_PTP;
if ((ptp_unit.flags & UNIT_ATT) == 0)
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) {
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
return SCPE_IOERR; }
ptp_csr = ptp_csr & ~CSR_ERR;
ptp_unit.pos = ptp_unit.pos + 1;
return SCPE_OK;
}
t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
ptp_csr = CSR_DONE;
if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR;
int_req = int_req & ~INT_PTP;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat ptp_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR;
else ptp_csr = ptp_csr & ~CSR_ERR;
return reason;
}
t_stat ptp_detach (UNIT *uptr)
{
ptp_csr = ptp_csr | CSR_ERR;
return detach_unit (uptr);
}

1093
pdp10_rp.c Normal file

File diff suppressed because it is too large Load diff

784
pdp10_sys.c Normal file
View file

@ -0,0 +1,784 @@
/* pdp10_sys.c: PDP-10 simulator interface
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
29-Apr-01 RMS Fixed format for RDPCST, WRPCST
Added CLRCSH for ITS
03-Apr-01 RMS Added support for loading EXE files
19-Mar-01 RMS Added support for loading SAV files
30-Oct-00 RMS Added support for examine to file
*/
#include "pdp10_defs.h"
#include <ctype.h>
extern DEVICE cpu_dev, pag_dev;
extern DEVICE tim_dev, fe_dev, uba_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE rp_dev, tu_dev;
/* extern DEVICE dz_dev; */
extern DEVICE lp20_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern d10 *M;
extern a10 saved_PC;
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "PDP-10";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&pag_dev, &tim_dev,
&fe_dev, &uba_dev,
&ptr_dev, &ptp_dev,
&lp20_dev, /* &dz_dev, */
&rp_dev, &tu_dev,
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Illegal instruction",
"Illegal interrupt instruction",
"Paging error in interrupt",
"Zero vector table",
"NXM on UPT/EPT reference",
"Nested indirect address limit exceeded",
"Nested XCT limit exceeded",
"Invalid I/O controller",
"Invalid magtape record length",
"Address stop",
"Panic stop" };
/* Binary loader, supports RIM10, SAV, EXE */
#define FMT_R 1 /* RIM10 */
#define FMT_S 2 /* SAV */
#define FMT_E 3 /* EXE */
#define EXE_DIR 01776 /* EXE directory */
#define EXE_VEC 01775 /* EXE entry vec */
#define EXE_PDV 01774 /* EXE ignored */
#define EXE_END 01777 /* EXE end
/* RIM10 loader
RIM10 format is a binary paper tape format (all data frames
are 200 or greater). It consists of blocks containing
-count,,origin-1
word
:
word
checksum (includes IOWD)
:
JRST start
*/
d10 getrimw (FILE *fileref)
{
int32 i, tmp;
d10 word;
word = 0;
for (i = 0; i < 6;) {
if ((tmp = getc (fileref)) == EOF) return -1;
if (tmp & 0200) {
word = (word << 6) | ((d10) tmp & 077);
i++; } }
return word;
}
t_stat load_rim (FILE *fileref)
{
d10 count, cksm, data;
a10 pa;
int32 op;
for ( ;; ) { /* loop until JRST */
count = cksm = getrimw (fileref); /* get header */
if (count < 0) return SCPE_FMT; /* read err? */
if (TSTS (count)) { /* hdr = IOWD? */
for ( ; TSTS (count); count = AOB (count)) {
data = getrimw (fileref); /* get data wd */
if (data < 0) return SCPE_FMT;
cksm = cksm + data; /* add to cksm */
pa = ((a10) count + 1) & AMASK; /* store */
M[pa] = data; } /* end for */
data = getrimw (fileref); /* get cksm */
if (data < 0) return SCPE_FMT;
if ((cksm + data) & DMASK) return SCPE_CSUM; /* test cksm */
} /* end if count */
else { op = GET_OP (count); /* not IOWD */
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
saved_PC = (a10) count & AMASK; /* set PC */
return SCPE_OK; } /* end else */
} /* end for */
return SCPE_FMT;
}
/* SAV file loader
SAV format is a disk file format (36b words). It consists of
blocks containing:
-count,,origin-1
word
:
word
:
JRST start
*/
t_stat load_sav (FILE *fileref)
{
d10 count, data;
a10 pa;
int32 wc, op;
for ( ;; ) { /* loop */
wc = fxread (&count, sizeof (d10), 1, fileref); /* read IOWD */
if (wc == 0) return SCPE_OK; /* done? */
if (TSTS (count)) { /* IOWD? */
for ( ; TSTS (count); count = AOB (count)) {
wc = fxread (&data, sizeof (d10), 1, fileref);
if (wc == 0) return SCPE_FMT;
pa = ((a10) count + 1) & AMASK; /* store data */
M[pa] = data; } /* end for */
} /* end if count*/
else { op = GET_OP (count); /* not IOWD */
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
saved_PC = (a10) count & AMASK; /* set PC */
return SCPE_OK; } /* end else */
} /* end for */
return SCPE_FMT;
}
/* EXE file loader
EXE format is a disk file format (36b words). It consists of
blocks containing:
block type,,total words = n
n - 1 data words
Block types are
EXE_DIR (1776) directory
EXE_VEC (1775) entry vector
EXE_PDV (1774) optional blocks
EXE_END (1777) end block
The directory blocks are the most important and contain doubleword
page loading information:
word0<0:8> = flags
<9:35> = page in file (0 if 0 page)
word1<0:8> = repeat count - 1
<9:35> = page in memory
*/
#define DIRSIZ (2 * PAG_SIZE)
t_stat load_exe (FILE *fileref)
{
d10 data, dirbuf[DIRSIZ], pagbuf[PAG_SIZE], entbuf[2];
int32 ndir, entvec, i, j, k, cont, bsz, bty, rpt, wc;
int32 fpage, mpage;
a10 ma;
ndir = entvec = 0; /* no dir, entvec */
cont = 1;
do { wc = fxread (&data, sizeof (d10), 1, fileref); /* read blk hdr */
if (wc == 0) return SCPE_FMT; /* error? */
bsz = (int32) ((data & RMASK) - 1); /* get count */
if (bsz <= 0) return SCPE_FMT; /* zero? */
bty = (int32) LRZ (data); /* get type */
switch (bty) { /* case type */
case EXE_DIR: /* directory */
if (ndir) return SCPE_FMT; /* got one */
ndir = fxread (dirbuf, sizeof (d10), bsz, fileref);
if (ndir < bsz) return SCPE_FMT; /* error */
break;
case EXE_PDV: /* ??? */
fseek (fileref, bsz * sizeof (d10), SEEK_CUR);
break;
case EXE_VEC: /* entry vec */
if (bsz != 2) return SCPE_FMT; /* must be 2 wds */
entvec = fxread (entbuf, sizeof (d10), bsz, fileref);
if (entvec < 2) return SCPE_FMT; /* error? */
cont = 0; /* stop */
break;
case EXE_END: /* end */
if (bsz != 0) return SCPE_FMT; /* must be hdr */
cont = 0; /* stop */
break;
default:
return SCPE_FMT; } /* end switch */
} /* end do */
while (cont);
for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */
fpage = (int32) (dirbuf[i] & RMASK); /* file page */
mpage = (int32) (dirbuf[i + 1] & RMASK); /* memory page */
rpt = (int32) ((dirbuf[i + 1] >> 27) + 1); /* repeat count */
for (j = 0; j < rpt; j++, mpage++) { /* loop thru rpts */
if (fpage) { /* file pages? */
fseek (fileref, (fpage << PAG_V_PN) * sizeof (d10), SEEK_SET);
wc = fxread (pagbuf, sizeof (d10), PAG_SIZE, fileref);
if (wc < PAG_SIZE) return SCPE_FMT;
fpage++; }
ma = mpage << PAG_V_PN; /* mem addr */
for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */
if (MEM_ADDR_NXM (ma)) return SCPE_NXM;
M[ma] = fpage? (pagbuf[k] & DMASK): 0;
} /* end copy */
} /* end rpt */
} /* end directory */
if (entvec && entbuf[1])
saved_PC = (int32) entbuf[1] & RMASK; /* start addr */
return SCPE_OK;
}
/* Master loader */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
d10 data;
int32 wc, fmt;
extern int32 sim_switches;
extern t_bool match_ext (char *fnam, char *ext);
fmt = 0; /* no fmt */
if (sim_switches & SWMASK ('R')) fmt = FMT_R; /* -r? */
else if (sim_switches & SWMASK ('S')) fmt = FMT_S; /* -s? */
else if (sim_switches & SWMASK ('E')) fmt = FMT_E; /* -e? */
else if (match_ext (fnam, "RIM")) fmt = FMT_R; /* .RIM? */
else if (match_ext (fnam, "SAV")) fmt = FMT_S; /* .SAV? */
else if (match_ext (fnam, "EXE")) fmt = FMT_E; /* .EXE? */
else { wc = fxread (&data, sizeof (d10), 1, fileref); /* read hdr */
if (wc == 0) return SCPE_FMT; /* error? */
if (LRZ (data) == EXE_DIR) fmt = FMT_E; /* EXE magic? */
else if (TSTS (data)) fmt = FMT_S; /* SAV magic? */
fseek (fileref, 0, SEEK_SET); } /* rewind */
switch (fmt) { /* case fmt */
case FMT_R: /* RIM */
return load_rim (fileref);
case FMT_S: /* SAV */
return load_sav (fileref);
case FMT_E: /* EXE */
return load_exe (fileref); }
printf ("Can't determine load file format\n");
return SCPE_FMT;
}
/* Symbol tables */
#define I_V_FL 39 /* inst class */
#define I_M_FL 03 /* class mask */
#define I_ITS 004000000000000 /* ITS flag */
#define I_AC 000000000000000 /* AC, address */
#define I_OP 010000000000000 /* address only */
#define I_IO 020000000000000 /* classic I/O */
#define I_V_AC 00
#define I_V_OP 01
#define I_V_IO 02
static const d10 masks[] = {
0777000000000, 0777740000000,
0700340000000, 0777777777777 };
static const char *opcode[] = {
"XCTR", "XCTI", /* ITS only */
"IORDI", "IORDQ", "IORD", "IOWR", "IOWRI", "IOWRQ",
"IORDBI", "IORDBQ", "IORDB", "IOWRB", "IOWRBI", "IOWRBQ",
"CLRCSH", "RDPCST", "WRPCST",
"SDBR1", "SDBR2", "SDBR3", "SDBR4", "SPM",
"LDBR1", "LDBR2", "LDBR3", "LDBR4", "LPMR",
"PORTAL", "JRSTF", "HALT", /* AC defines op */
"XJRSTF", "XJEN", "XPCW",
"JEN", "SFM", "XJRST", "IBP",
"JFOV", "JCRY1", "JCRY0", "JCRY", "JOV",
"APRID", "WRAPR", "RDAPR", "WRPI", "RDPI", "RDUBR", "CLRPT", "WRUBR",
"WREBR", "RDEBR",
"RDSPB", "RDCSB", "RDPUR", "RDCSTM", "RDTIM", "RDINT", "RDHSB",
"WRSPB", "WRCSB", "WRPUR", "WRCSTM", "WRTIM", "WRINT", "WRHSB",
"LUUO01", "LUUO02", "LUUO03", "LUUO04", "LUUO05", "LUUO06", "LUUO07",
"LUUO10", "LUUO11", "LUUO12", "LUUO13", "LUUO14", "LUUO15", "LUUO16", "LUUO17",
"LUUO20", "LUUO21", "LUUO22", "LUUO23", "LUUO24", "LUUO25", "LUUO26", "LUUO27",
"LUUO30", "LUUO31", "LUUO32", "LUUO33", "LUUO34", "LUUO35", "LUUO36", "LUUO37",
"MUUO40", "MUUO41", "MUUO42", "MUUO43", "MUUO44", "MUUO45", "MUUO46", "MUUO47",
"MUUO50", "MUUO51", "MUUO52", "MUUO53", "MUUO54", "MUUO55", "MUUO56", "MUUO57",
"MUUO60", "MUUO61", "MUUO62", "MUUO63", "MUUO64", "MUUO65", "MUUO66", "MUUO67",
"MUUO70", "MUUO71", "MUUO72", "MUUO73", "MUUO74", "MUUO75", "MUUO76", "MUUO77",
"UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ",
"DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV",
"DMOVE", "DMOVN", "FIX", "EXTEND", "DMOVEM", "DMOVNM", "FIXR", "FLTR",
"UFA", "DFN", "FSC", "ADJBP", "ILDB", "LDB", "IDPB", "DPB",
"FAD", "FADL", "FADM", "FADB", "FADR", "FADRL", "FADRM", "FADRB",
"FSB", "FSBL", "FSBM", "FSBB", "FSBR", "FSBRL", "FSBRM", "FSBRB",
"FMP", "FMPL", "FMPM", "FMPB", "FMPR", "FMPRL", "FMPRM", "FMPRB",
"FDV", "FDVL", "FDVM", "FDVB", "FDVR", "FDVRL", "FDVRM", "FDVRB",
"MOVE", "MOVEI", "MOVEM", "MOVES", "MOVS", "MOVSI", "MOVSM", "MOVSS",
"MOVN", "MOVNI", "MOVNM", "MOVNS", "MOVM", "MOVMI", "MOVMM", "MOVMS",
"IMUL", "IMULI", "IMULM", "IMULB", "MUL", "MULI", "MULM", "MULB",
"IDIV", "IDIVI", "IDIVM", "IDIVB", "DIV", "DIVI", "DIVM", "DIVB",
"ASH", "ROT", "LSH", "JFFO", "ASHC", "ROTC", "LSHC", "CIRC",
"EXCH", "BLT", "AOBJP", "AOBJN", "JRST", "JFCL", "XCT", "MAP",
"PUSHJ", "PUSH", "POP", "POPJ", "JSR", "JSP", "JSA", "JRA",
"ADD", "ADDI", "ADDM", "ADDB", "SUB", "SUBI", "SUBM", "SUBB",
"CAI", "CAIL", "CAIE", "CAILE", "CAIA", "CAIGE", "CAIN", "CAIG",
"CAM", "CAML", "CAME", "CAMLE", "CAMA", "CAMGE", "CAMN", "CAMG",
"JUMP", "JUMPL", "JUMPE", "JUMPLE", "JUMPA", "JUMPGE", "JUMPN", "JUMPG",
"SKIP", "SKIPL", "SKIPE", "SKIPLE", "SKIPA", "SKIPGE", "SKIPN", "SKIPG",
"AOJ", "AOJL", "AOJE", "AOJLE", "AOJA", "AOJGE", "AOJN", "AOJG",
"AOS", "AOSL", "AOSE", "AOSLE", "AOSA", "AOSGE", "AOSN", "AOSG",
"SOJ", "SOJL", "SOJE", "SOJLE", "SOJA", "SOJGE", "SOJN", "SOJG",
"SOS", "SOSL", "SOSE", "SOSLE", "SOSA", "SOSGE", "SOSN", "SOSG",
"SETZ", "SETZI", "SETZM", "SETZB", "AND", "ANDI", "ANDM", "ANDB",
"ANDCA", "ANDCAI", "ANDCAM", "ANDCAB", "SETM", "SETMI", "SETMM", "SETMB",
"ANDCM", "ANDCMI", "ANDCMM", "ANDCMB", "SETA", "SETAI", "SETAM", "SETAB",
"XOR", "XORI", "XORM", "XORB", "IOR", "IORI", "IORM", "IORB",
"ANDCB", "ANDCBI", "ANDCBM", "ANDCBB", "EQV", "EQVI", "EQVM", "EQVB",
"SETCA", "SETCAI", "SETCAM", "SETCAB", "ORCA", "ORCAI", "ORCAM", "ORCAB",
"SETCM", "SETCMI", "SETCMM", "SETCMB", "ORCM", "ORCMI", "ORCMM", "ORCMB",
"ORCB", "ORCBI", "ORCBM", "ORCBB", "SETO", "SETOI", "SETOM", "SETOB",
"HLL", "HLLI", "HLLM", "HLLS", "HRL", "HRLI", "HRLM", "HRLS",
"HLLZ", "HLLZI", "HLLZM", "HLLZS", "HRLZ", "HRLZI", "HRLZM", "HRLZS",
"HLLO", "HLLOI", "HLLOM", "HLLOS", "HRLO", "HRLOI", "HRLOM", "HRLOS",
"HLLE", "HLLEI", "HLLEM", "HLLES", "HRLE", "HRLEI", "HRLEM", "HRLES",
"HRR", "HRRI", "HRRM", "HRRS", "HLR", "HLRI", "HLRM", "HLRS",
"HRRZ", "HRRZI", "HRRZM", "HRRZS", "HLRZ", "HLRZI", "HLRZM", "HLRZS",
"HRRO", "HRROI", "HRROM", "HRROS", "HLRO", "HLROI", "HLROM", "HLROS",
"HRRE", "HRREI", "HRREM", "HRRES", "HLRE", "HLREI", "HLREM", "HLRES",
"TRN", "TLN", "TRNE", "TLNE", "TRNA", "TLNA", "TRNN", "TLNN",
"TDN", "TSN", "TDNE", "TSNE", "TDNA", "TSNA", "TDNN", "TSNN",
"TRZ", "TLZ", "TRZE", "TLZE", "TRZA", "TLZA", "TRZN", "TLZN",
"TDZ", "TSZ", "TDZE", "TSZE", "TDZA", "TSZA", "TDZN", "TSZN",
"TRC", "TLC", "TRCE", "TLCE", "TRCA", "TLCA", "TRCN", "TLCN",
"TDC", "TSC", "TDCE", "TSCE", "TDCA", "TSCA", "TDCN", "TSCN",
"TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON",
"TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON",
"UMOVE", "UMOVEM", /* KS10 I/O */
"TIOE", "TION", "RDIO", "WRIO",
"BSIO", "BCIO", "BLTBU", "BLTUB",
"TIOEB", "TIONB", "RDIOB", "WRIOB",
"BSIOB", "BCIOB",
"BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */
"CONO", "CONI", "CONSZ", "CONSO",
"CLEAR", "CLEARI", "CLEARM", "CLEARB",
"OR", "ORI", "ORM", "ORB", "XMOVEI", "XHLLI", /* alternate ops */
"CMPSL", "CMPSE", "CMPSLE", /* extended ops */
"EDIT", "CMPSGE", "CMPSN", "CMPSG",
"CVTDBO", "CVTDBT", "CVTBDO", "CVTBDT",
"MOVSO", "MOVST", "MOVSLJ", "MOVSRJ",
"XBLT", "GSNGL", "GDBLE", "GDFIX",
"GFIX", "GDFIXR", "GFIXR", "DGFLTR",
"GFLTR", "GFSC",
NULL };
static const d10 opc_val[] = {
0102000000000+I_AC+I_ITS, 0103000000000+I_AC+I_ITS,
0710000000000+I_AC+I_ITS, 0711000000000+I_AC+I_ITS, 0712000000000+I_AC+I_ITS,
0713000000000+I_AC+I_ITS, 0714000000000+I_AC+I_ITS, 0715000000000+I_AC+I_ITS,
0720000000000+I_AC+I_ITS, 0721000000000+I_AC+I_ITS, 0722000000000+I_AC+I_ITS,
0723000000000+I_AC+I_ITS, 0724000000000+I_AC+I_ITS, 0725000000000+I_AC+I_ITS,
0701000000000+I_OP+I_ITS, 0701440000000+I_OP+I_ITS, 0701540000000+I_OP+I_ITS,
0702000000000+I_OP+I_ITS, 0702040000000+I_OP+I_ITS,
0702100000000+I_OP+I_ITS, 0702140000000+I_OP+I_ITS, 0702340000000+I_OP+I_ITS,
0702400000000+I_OP+I_ITS, 0702440000000+I_OP+I_ITS,
0702500000000+I_OP+I_ITS, 0702540000000+I_OP+I_ITS, 0702740000000+I_OP+I_ITS,
0254040000000+I_OP, 0254100000000+I_OP,
0254200000000+I_OP, 0254240000000+I_OP, 0254300000000+I_OP, 0254340000000+I_OP,
0254500000000+I_OP, 0254600000000+I_OP, 0254640000000+I_OP, 0133000000000+I_OP,
0255040000000+I_OP, 0255100000000+I_OP, 0255200000000+I_OP, 0255300000000+I_OP,
0255400000000+I_OP,
0700000000000+I_OP, 0700200000000+I_OP, 0700240000000+I_OP, 0700600000000+I_OP,
0700640000000+I_OP, 0701040000000+I_OP, 0701100000000+I_OP, 0701140000000+I_OP,
0701200000000+I_OP, 0701240000000+I_OP,
0702000000000+I_OP, 0702040000000+I_OP, 0702100000000+I_OP, 0702140000000+I_OP,
0702200000000+I_OP, 0702240000000+I_OP, 0702300000000+I_OP,
0702400000000+I_OP, 0702440000000+I_OP, 0702500000000+I_OP, 0702540000000+I_OP,
0702600000000+I_OP, 0702640000000+I_OP, 0702700000000+I_OP,
0001000000000+I_AC, 0002000000000+I_AC, 0003000000000+I_AC,
0004000000000+I_AC, 0005000000000+I_AC, 0006000000000+I_AC, 0007000000000+I_AC,
0010000000000+I_AC, 0011000000000+I_AC, 0012000000000+I_AC, 0013000000000+I_AC,
0014000000000+I_AC, 0015000000000+I_AC, 0016000000000+I_AC, 0017000000000+I_AC,
0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC,
0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC,
0030000000000+I_AC, 0031000000000+I_AC, 0032000000000+I_AC, 0033000000000+I_AC,
0034000000000+I_AC, 0035000000000+I_AC, 0036000000000+I_AC, 0037000000000+I_AC,
0040000000000+I_AC, 0041000000000+I_AC, 0042000000000+I_AC, 0043000000000+I_AC,
0044000000000+I_AC, 0045000000000+I_AC, 0046000000000+I_AC, 0047000000000+I_AC,
0050000000000+I_AC, 0051000000000+I_AC, 0052000000000+I_AC, 0053000000000+I_AC,
0054000000000+I_AC, 0055000000000+I_AC, 0056000000000+I_AC, 0057000000000+I_AC,
0060000000000+I_AC, 0061000000000+I_AC, 0062000000000+I_AC, 0063000000000+I_AC,
0064000000000+I_AC, 0065000000000+I_AC, 0066000000000+I_AC, 0067000000000+I_AC,
0070000000000+I_AC, 0071000000000+I_AC, 0072000000000+I_AC, 0073000000000+I_AC,
0074000000000+I_AC, 0075000000000+I_AC, 0076000000000+I_AC, 0077000000000+I_AC,
0100000000000+I_AC, 0102000000000+I_AC, 0103000000000+I_AC,
0104000000000+I_AC, 0105000000000+I_AC, 0106000000000+I_AC, 0107000000000+I_AC,
0110000000000+I_AC, 0111000000000+I_AC, 0112000000000+I_AC, 0113000000000+I_AC,
0114000000000+I_AC, 0115000000000+I_AC, 0116000000000+I_AC, 0117000000000+I_AC,
0120000000000+I_AC, 0121000000000+I_AC, 0122000000000+I_AC, 0123000000000+I_AC,
0124000000000+I_AC, 0125000000000+I_AC, 0126000000000+I_AC, 0127000000000+I_AC,
0130000000000+I_AC, 0131000000000+I_AC, 0132000000000+I_AC, 0133000000000+I_AC,
0134000000000+I_AC, 0135000000000+I_AC, 0136000000000+I_AC, 0137000000000+I_AC,
0140000000000+I_AC, 0141000000000+I_AC, 0142000000000+I_AC, 0143000000000+I_AC,
0144000000000+I_AC, 0145000000000+I_AC, 0146000000000+I_AC, 0147000000000+I_AC,
0150000000000+I_AC, 0151000000000+I_AC, 0152000000000+I_AC, 0153000000000+I_AC,
0154000000000+I_AC, 0155000000000+I_AC, 0156000000000+I_AC, 0157000000000+I_AC,
0160000000000+I_AC, 0161000000000+I_AC, 0162000000000+I_AC, 0163000000000+I_AC,
0164000000000+I_AC, 0165000000000+I_AC, 0166000000000+I_AC, 0167000000000+I_AC,
0170000000000+I_AC, 0171000000000+I_AC, 0172000000000+I_AC, 0173000000000+I_AC,
0174000000000+I_AC, 0175000000000+I_AC, 0176000000000+I_AC, 0177000000000+I_AC,
0200000000000+I_AC, 0201000000000+I_AC, 0202000000000+I_AC, 0203000000000+I_AC,
0204000000000+I_AC, 0205000000000+I_AC, 0206000000000+I_AC, 0207000000000+I_AC,
0210000000000+I_AC, 0211000000000+I_AC, 0212000000000+I_AC, 0213000000000+I_AC,
0214000000000+I_AC, 0215000000000+I_AC, 0216000000000+I_AC, 0217000000000+I_AC,
0220000000000+I_AC, 0221000000000+I_AC, 0222000000000+I_AC, 0223000000000+I_AC,
0224000000000+I_AC, 0225000000000+I_AC, 0226000000000+I_AC, 0227000000000+I_AC,
0230000000000+I_AC, 0231000000000+I_AC, 0232000000000+I_AC, 0233000000000+I_AC,
0234000000000+I_AC, 0235000000000+I_AC, 0236000000000+I_AC, 0237000000000+I_AC,
0240000000000+I_AC, 0241000000000+I_AC, 0242000000000+I_AC, 0243000000000+I_AC,
0244000000000+I_AC, 0245000000000+I_AC, 0246000000000+I_AC, 0247000000000+I_AC+I_ITS,
0250000000000+I_AC, 0251000000000+I_AC, 0252000000000+I_AC, 0253000000000+I_AC,
0254000000000+I_AC, 0255000000000+I_AC, 0256000000000+I_AC, 0257000000000+I_AC,
0260000000000+I_AC, 0261000000000+I_AC, 0262000000000+I_AC, 0263000000000+I_AC,
0264000000000+I_AC, 0265000000000+I_AC, 0266000000000+I_AC, 0267000000000+I_AC,
0270000000000+I_AC, 0271000000000+I_AC, 0272000000000+I_AC, 0273000000000+I_AC,
0274000000000+I_AC, 0275000000000+I_AC, 0276000000000+I_AC, 0277000000000+I_AC,
0300000000000+I_AC, 0301000000000+I_AC, 0302000000000+I_AC, 0303000000000+I_AC,
0304000000000+I_AC, 0305000000000+I_AC, 0306000000000+I_AC, 0307000000000+I_AC,
0310000000000+I_AC, 0311000000000+I_AC, 0312000000000+I_AC, 0313000000000+I_AC,
0314000000000+I_AC, 0315000000000+I_AC, 0316000000000+I_AC, 0317000000000+I_AC,
0320000000000+I_AC, 0321000000000+I_AC, 0322000000000+I_AC, 0323000000000+I_AC,
0324000000000+I_AC, 0325000000000+I_AC, 0326000000000+I_AC, 0327000000000+I_AC,
0330000000000+I_AC, 0331000000000+I_AC, 0332000000000+I_AC, 0333000000000+I_AC,
0334000000000+I_AC, 0335000000000+I_AC, 0336000000000+I_AC, 0337000000000+I_AC,
0340000000000+I_AC, 0341000000000+I_AC, 0342000000000+I_AC, 0343000000000+I_AC,
0344000000000+I_AC, 0345000000000+I_AC, 0346000000000+I_AC, 0347000000000+I_AC,
0350000000000+I_AC, 0351000000000+I_AC, 0352000000000+I_AC, 0353000000000+I_AC,
0354000000000+I_AC, 0355000000000+I_AC, 0356000000000+I_AC, 0357000000000+I_AC,
0360000000000+I_AC, 0361000000000+I_AC, 0362000000000+I_AC, 0363000000000+I_AC,
0364000000000+I_AC, 0365000000000+I_AC, 0366000000000+I_AC, 0367000000000+I_AC,
0370000000000+I_AC, 0371000000000+I_AC, 0372000000000+I_AC, 0373000000000+I_AC,
0374000000000+I_AC, 0375000000000+I_AC, 0376000000000+I_AC, 0377000000000+I_AC,
0400000000000+I_AC, 0401000000000+I_AC, 0402000000000+I_AC, 0403000000000+I_AC,
0404000000000+I_AC, 0405000000000+I_AC, 0406000000000+I_AC, 0407000000000+I_AC,
0410000000000+I_AC, 0411000000000+I_AC, 0412000000000+I_AC, 0413000000000+I_AC,
0414000000000+I_AC, 0415000000000+I_AC, 0416000000000+I_AC, 0417000000000+I_AC,
0420000000000+I_AC, 0421000000000+I_AC, 0422000000000+I_AC, 0423000000000+I_AC,
0424000000000+I_AC, 0425000000000+I_AC, 0426000000000+I_AC, 0427000000000+I_AC,
0430000000000+I_AC, 0431000000000+I_AC, 0432000000000+I_AC, 0433000000000+I_AC,
0434000000000+I_AC, 0435000000000+I_AC, 0436000000000+I_AC, 0437000000000+I_AC,
0440000000000+I_AC, 0441000000000+I_AC, 0442000000000+I_AC, 0443000000000+I_AC,
0444000000000+I_AC, 0445000000000+I_AC, 0446000000000+I_AC, 0447000000000+I_AC,
0450000000000+I_AC, 0451000000000+I_AC, 0452000000000+I_AC, 0453000000000+I_AC,
0454000000000+I_AC, 0455000000000+I_AC, 0456000000000+I_AC, 0457000000000+I_AC,
0460000000000+I_AC, 0461000000000+I_AC, 0462000000000+I_AC, 0463000000000+I_AC,
0464000000000+I_AC, 0465000000000+I_AC, 0466000000000+I_AC, 0467000000000+I_AC,
0470000000000+I_AC, 0471000000000+I_AC, 0472000000000+I_AC, 0473000000000+I_AC,
0474000000000+I_AC, 0475000000000+I_AC, 0476000000000+I_AC, 0477000000000+I_AC,
0500000000000+I_AC, 0501000000000+I_AC, 0502000000000+I_AC, 0503000000000+I_AC,
0504000000000+I_AC, 0505000000000+I_AC, 0506000000000+I_AC, 0507000000000+I_AC,
0510000000000+I_AC, 0511000000000+I_AC, 0512000000000+I_AC, 0513000000000+I_AC,
0514000000000+I_AC, 0515000000000+I_AC, 0516000000000+I_AC, 0517000000000+I_AC,
0520000000000+I_AC, 0521000000000+I_AC, 0522000000000+I_AC, 0523000000000+I_AC,
0524000000000+I_AC, 0525000000000+I_AC, 0526000000000+I_AC, 0527000000000+I_AC,
0530000000000+I_AC, 0531000000000+I_AC, 0532000000000+I_AC, 0533000000000+I_AC,
0534000000000+I_AC, 0535000000000+I_AC, 0536000000000+I_AC, 0537000000000+I_AC,
0540000000000+I_AC, 0541000000000+I_AC, 0542000000000+I_AC, 0543000000000+I_AC,
0544000000000+I_AC, 0545000000000+I_AC, 0546000000000+I_AC, 0547000000000+I_AC,
0550000000000+I_AC, 0551000000000+I_AC, 0552000000000+I_AC, 0553000000000+I_AC,
0554000000000+I_AC, 0555000000000+I_AC, 0556000000000+I_AC, 0557000000000+I_AC,
0560000000000+I_AC, 0561000000000+I_AC, 0562000000000+I_AC, 0563000000000+I_AC,
0564000000000+I_AC, 0565000000000+I_AC, 0566000000000+I_AC, 0567000000000+I_AC,
0570000000000+I_AC, 0571000000000+I_AC, 0572000000000+I_AC, 0573000000000+I_AC,
0574000000000+I_AC, 0575000000000+I_AC, 0576000000000+I_AC, 0577000000000+I_AC,
0600000000000+I_AC, 0601000000000+I_AC, 0602000000000+I_AC, 0603000000000+I_AC,
0604000000000+I_AC, 0605000000000+I_AC, 0606000000000+I_AC, 0607000000000+I_AC,
0610000000000+I_AC, 0611000000000+I_AC, 0612000000000+I_AC, 0613000000000+I_AC,
0614000000000+I_AC, 0615000000000+I_AC, 0616000000000+I_AC, 0617000000000+I_AC,
0620000000000+I_AC, 0621000000000+I_AC, 0622000000000+I_AC, 0623000000000+I_AC,
0624000000000+I_AC, 0625000000000+I_AC, 0626000000000+I_AC, 0627000000000+I_AC,
0630000000000+I_AC, 0631000000000+I_AC, 0632000000000+I_AC, 0633000000000+I_AC,
0634000000000+I_AC, 0635000000000+I_AC, 0636000000000+I_AC, 0637000000000+I_AC,
0640000000000+I_AC, 0641000000000+I_AC, 0642000000000+I_AC, 0643000000000+I_AC,
0644000000000+I_AC, 0645000000000+I_AC, 0646000000000+I_AC, 0647000000000+I_AC,
0650000000000+I_AC, 0651000000000+I_AC, 0652000000000+I_AC, 0653000000000+I_AC,
0654000000000+I_AC, 0655000000000+I_AC, 0656000000000+I_AC, 0657000000000+I_AC,
0660000000000+I_AC, 0661000000000+I_AC, 0662000000000+I_AC, 0663000000000+I_AC,
0664000000000+I_AC, 0665000000000+I_AC, 0666000000000+I_AC, 0667000000000+I_AC,
0670000000000+I_AC, 0671000000000+I_AC, 0672000000000+I_AC, 0673000000000+I_AC,
0674000000000+I_AC, 0675000000000+I_AC, 0676000000000+I_AC, 0677000000000+I_AC,
0704000000000+I_AC, 0705000000000+I_AC,
0710000000000+I_AC, 0711000000000+I_AC, 0712000000000+I_AC, 0713000000000+I_AC,
0714000000000+I_AC, 0715000000000+I_AC, 0716000000000+I_AC, 0717000000000+I_AC,
0720000000000+I_AC, 0721000000000+I_AC, 0722000000000+I_AC, 0723000000000+I_AC,
0724000000000+I_AC, 0725000000000+I_AC,
0700000000000+I_IO, 0700040000000+I_IO, 0700100000000+I_IO, 0700140000000+I_IO,
0700200000000+I_IO, 0700240000000+I_IO, 0700300000000+I_IO, 0700340000000+I_IO,
0400000000000+I_AC, 0401000000000+I_AC, 0402000000000+I_AC, 0403000000000+I_AC,
0434000000000+I_AC, 0435000000000+I_AC, 0436000000000+I_AC, 0437000000000+I_AC,
0415000000000+I_AC, 0501000000000+I_AC,
0001000000000+I_AC, 0002000000000+I_AC, 0003000000000+I_AC,
0004000000000+I_AC, 0005000000000+I_AC, 0006000000000+I_AC, 0007000000000+I_AC,
0010000000000+I_AC, 0011000000000+I_AC, 0012000000000+I_AC, 0013000000000+I_AC,
0014000000000+I_AC, 0015000000000+I_AC, 0016000000000+I_AC, 0017000000000+I_AC,
0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC,
0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC,
0030000000000+I_AC, 0031000000000+I_AC,
-1 };
#define NUMDEV 6
static const char *devnam[NUMDEV] = {
"APR", "PI", "PAG", "CCA", "TIM", "MTR"};
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
*/
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
#define SIXTOASC(x) ((x) + 040)
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 i, j, c, cflag, ac, xr, y, dev;
d10 inst;
inst = val[0];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
fprintf (of, FMTASC ((int32) (inst & 0177)));
return SCPE_OK; }
if (sw & SWMASK ('C')) { /* character? */
for (i = 30; i >= 0; i = i - 6) {
c = (int32) ((inst >> i) & 077);
fprintf (of, "%c", SIXTOASC (c)); }
return SCPE_OK; }
if (sw & SWMASK ('P')) { /* packed? */
for (i = 29; i >= 0; i = i - 7) {
c = (int32) ((inst >> i) & 0177);
fprintf (of, FMTASC (c)); }
return SCPE_OK; }
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
/* Instruction decode */
ac = GET_AC (inst);
xr = GET_XR (inst);
y = GET_ADDR (inst);
dev = GET_DEV (inst);
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */
(((opc_val[i] & I_ITS) == 0) || ITS)) {
fprintf (of, "%s ", opcode[i]); /* opcode */
switch (j) { /* case on class */
case I_V_AC: /* AC + address */
fprintf (of, "%-o,", ac); /* print AC, fall thru */
case I_V_OP: /* address only */
if (inst & INST_IND) fprintf (of, "@");
if (xr) fprintf (of, "%-o(%-o)", y, xr);
else fprintf (of, "%-o", y);
break;
case I_V_IO: /* I/O */
if (dev < NUMDEV) fprintf (of, "%s,", devnam[dev]);
else fprintf (of, "%-o,", dev);
if (inst & INST_IND) fprintf (of, "@");
if (xr) fprintf (of, "%-o(%-o)", y, xr);
else fprintf (of, "%-o", y);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
}
/* Get operand, including indirect and index
Inputs:
*cptr = pointer to input string
*status = pointer to error status
Outputs:
val = output value
*/
t_value get_opnd (char *cptr, t_stat *status)
{
int32 sign = 0;
t_value val, xr = 0, ind = 0;
char *tptr;
*status = SCPE_ARG; /* assume fail */
if (*cptr == '@') {
ind = INST_IND;
cptr++; }
if (*cptr == '+') cptr++;
else if (*cptr == '-') {
sign = 1;
cptr++; }
val = strtotv (cptr, &tptr, 8);
if (val > 0777777) return 0;
if (sign) val = (~val + 1) & 0777777;
cptr = tptr;
if (*cptr == '(') {
cptr++;
xr = strtotv (cptr, &tptr, 8);
if ((cptr == tptr) || (*tptr != ')') ||
(xr > AC_NUM) || (xr == 0)) return 0;
cptr = ++tptr; }
if (*cptr == 0) *status = SCPE_OK;
return (ind | (xr << 18) | val);
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 cflag, i, j;
t_value ac, dev;
t_stat r;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++;
for (i = 0; i < 6; i++) {
if (cptr[i] == 0) {
for (j = i + 1; j <= 6; j++) cptr[j] = 0;
break; } }
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cptr[0];
return SCPE_OK; }
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 6; i++) {
val[0] = (val[0] << 6);
if (cptr[i]) val[0] = val[0] |
((t_value) ((cptr[i] + 040) & 077)); }
return SCPE_OK; }
if ((sw & SWMASK ('P')) || ((*cptr == '#') && cptr++)) { /* packed string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 5; i++) val[0] = (val[0] << 7) | ((t_value) cptr[i]);
val[0] = val[0] << 1;
return SCPE_OK; }
/* Symbolic input, continued */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
val[0] = opc_val[i] & DMASK; /* get value */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
switch (j) { /* case on class */
case I_V_AC: /* AC + operand */
if (strchr (cptr, ',')) { /* AC specified? */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if (gbuf[0]) { /* can be omitted */
ac = get_uint (gbuf, 8, AC_NUM - 1, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (ac << INST_V_AC); } }
case I_V_OP: /* operand */
cptr = get_glyph (cptr, gbuf, 0);
val[0] = val[0] | get_opnd (gbuf, &r);
if (r != SCPE_OK) return SCPE_ARG;
break;
case I_V_IO: /* I/O */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
for (dev = 0; (dev < NUMDEV) && (strcmp (devnam[dev], gbuf) != 0); dev++);
if (dev >= NUMDEV) {
dev = get_uint (gbuf, 8, INST_M_DEV, &r);
if (r != SCPE_OK) return SCPE_ARG; }
val[0] = val[0] | (dev << INST_V_DEV);
cptr = get_glyph (cptr, gbuf, 0);
val[0] = val[0] | get_opnd (gbuf, &r);
if (r != SCPE_OK) return SCPE_ARG;
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;
}

178
pdp10_tim.c Normal file
View file

@ -0,0 +1,178 @@
/* pdp10_tim.c: PDP-10 tim subsystem simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include "pdp10_defs.h"
#include <time.h>
#define TIM_N_HWRE 12 /* hwre bits */
#define TIM_HWRE 0000000010000 /* hwre incr */
#define TB_MASK 037777777777777777777; /* 71 - 12 bits */
#define TPS 1001 /* ticks per sec */
#define UNIT_V_Y2K (UNIT_V_UF) /* Y2K compliant OS */
#define UNIT_Y2K (1u << UNIT_V_Y2K)
extern int32 apr_flg, pi_act;
extern UNIT cpu_unit;
extern d10 pcst;
extern a10 pager_PC;
int64 timebase = 0; /* 71b timebase */
d10 ttg = 0; /* time to go */
d10 period = 0; /* period */
d10 quant = 0; /* ITS quantum */
int32 diagflg = 0; /* diagnostics? */
t_stat tim_svc (UNIT *uptr);
t_stat tim_reset (DEVICE *dptr);
extern d10 Read (a10 ea, int32 prv);
extern d10 ReadM (a10 ea, int32 prv);
extern void Write (a10 ea, d10 val, int32 prv);
extern void WriteP (a10 ea, d10 val);
extern int32 pi_eval (void);
extern sim_rtc_calb (int32 tps);
/* TIM data structures
tim_dev TIM device descriptor
tim_unit TIM unit descriptor
tim_reg TIM register list
*/
UNIT tim_unit = { UDATA (&tim_svc, 0, 0), 500 };
REG tim_reg[] = {
{ ORDATA (TIMEBASE, timebase, 71 - TIM_N_HWRE) },
{ ORDATA (TTG, ttg, 36) },
{ ORDATA (PERIOD, period, 36) },
{ ORDATA (QUANT, quant, 36) },
{ DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (DIAG, diagflg, 0) },
{ FLDATA (Y2K, tim_unit.flags, UNIT_V_Y2K), REG_HRO },
{ NULL } };
MTAB tim_mod[] = {
{ UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL },
{ UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL },
{ 0 } };
DEVICE tim_dev = {
"TIM", &tim_unit, tim_reg, tim_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &tim_reset,
NULL, NULL, NULL };
/* Timer instructions */
t_bool rdtim (a10 ea, int32 prv)
{
ReadM (INCA (ea), prv);
Write (ea, (timebase >> (35 - TIM_N_HWRE)) & DMASK, prv);
Write (INCA(ea), (timebase << TIM_N_HWRE) & MMASK, prv);
return FALSE;
}
t_bool wrtim (a10 ea, int32 prv)
{
timebase = (Read (ea, prv) << (35 - TIM_N_HWRE)) |
(CLRS (Read (INCA (ea), prv)) >> TIM_N_HWRE);
return FALSE;
}
t_bool rdint (a10 ea, int32 prv)
{
Write (ea, period, prv);
return FALSE;
}
t_bool wrint (a10 ea, int32 prv)
{
period = Read (ea, prv);
ttg = period;
return FALSE;
}
/* Timer routines
tim_svc process event (timer tick)
tim_reset process reset
*/
t_stat tim_svc (UNIT *uptr)
{
sim_activate (&tim_unit, /* reactivate unit */
(diagflg? tim_unit.wait: sim_rtc_calb (TPS)));
timebase = (timebase + 1) & TB_MASK; /* increment timebase */
ttg = ttg - TIM_HWRE; /* decrement timer */
if (ttg <= 0) { /* timeout? */
ttg = period; /* reload */
apr_flg = apr_flg | APRF_TIM; } /* request interrupt */
if (ITS) { /* ITS? */
if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK;
if (TSTS (pcst)) { /* PC sampling? */
pcst = AOB (pcst); /* add 1,,1 */
WriteP ((a10) pcst & AMASK, pager_PC); }
} /* end ITS */
return SCPE_OK;
}
t_stat tim_reset (DEVICE *dptr)
{
period = ttg = 0; /* clear timer */
apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */
sim_activate (&tim_unit, tim_unit.wait); /* activate unit */
return SCPE_OK;
}
/* Time of year clock */
t_stat tcu_rd (int32 *data, int32 PA, int32 access)
{
time_t curtim;
struct tm *tptr;
curtim = time (NULL); /* get time */
tptr = localtime (&curtim); /* decompose */
if (tptr == NULL) return SCPE_NXM; /* Y2K prob? */
if ((tptr -> tm_year > 99) && !(tim_unit.flags & UNIT_Y2K))
tptr -> tm_year = 99;
switch ((PA >> 1) & 03) { /* decode PA<3:1> */
case 0: /* year/month/day */
*data = (((tptr -> tm_year) & 0177) << 9) |
(((tptr -> tm_mon + 1) & 017) << 5) |
((tptr -> tm_mday) & 037);
return SCPE_OK;
case 1: /* hour/minute */
*data = (((tptr -> tm_hour) & 037) << 8) |
((tptr -> tm_min) & 077);
return SCPE_OK;
case 2: /* second */
*data = (tptr -> tm_sec) & 077;
return SCPE_OK;
case 3: /* status */
*data = CSR_DONE;
return SCPE_OK; }
return SCPE_NXM; /* can't get here */
}

1045
pdp10_tu.c Normal file

File diff suppressed because it is too large Load diff

638
pdp10_xtnd.c Normal file
View file

@ -0,0 +1,638 @@
/* pdp10_xtnd.c: PDP-10 extended instruction simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
12-May-01 RMS Fixed compiler warning in xlate
Instructions handled in this module:
MOVSLJ move string left justified
MOVSO move string offset
MOVST move string translated
MOVSRJ move string right justified
CMPSL compare string, skip on less
CMPSE compare string, skip on equal
CMPSLE compare string, skip on less or equal
CMPSGE compare string, skip on greater or equal
CMPSN compare string, skip on unequal
CMPSG compare string, skip on greater
CVTDBO convert decimal to binary offset
CVTDBT convert decimal to binary translated
CVTBDO convert binary to decimal offset
CVTBDT convert binary to decimal translated
EDIT edit
The PDP-10 extended instructions deal with non-binary data types,
particularly byte strings and decimal strings. (In the KL10, the
extended instructions include G floating support as well.) They
are very complicated microcoded subroutines that can potentially
run for a very long time. Accordingly, the instructions must test
for interrupts as well as page faults, and be prepared to restart
from either.
In general, the simulator attempts to keep the AC block up to date,
so that page fails and interrupts can be taken directly at any point.
If the AC block is not up to date, memory accessibility must be tested
before the actual read or write is done.
The extended instruction routine returns a status code as follows:
XT_NOSK no skip completion
XT_SKIP skip completion
XT_MUUO invalid extended instruction
*/
#include "pdp10_defs.h"
#include <setjmp.h>
#define MM_XSRC (pflgs & XSRC_PXCT)
#define MM_XDST (pflgs & XDST_PXCT)
#define MM_EA_XSRC ((pflgs & EA_PXCT) && MM_XSRC)
#define MM_EA_XDST ((pflgs & EA_PXCT) && MM_XDST)
#define XT_CMPSL 001 /* opcodes */
#define XT_CMPSE 002
#define XT_CMPSLE 003
#define XT_EDIT 004
#define XT_CMPSGE 005
#define XT_CMPSN 006
#define XT_CMPSG 007
#define XT_CVTDBO 010
#define XT_CVTDBT 011
#define XT_CVTBDO 012
#define XT_CVTBDT 013
#define XT_MOVSO 014
#define XT_MOVST 015
#define XT_MOVSLJ 016
#define XT_MOVSRJ 017
/* Translation control */
#define XT_LFLG 0400000000000 /* L flag */
#define XT_SFLG 0400000000000 /* S flag */
#define XT_NFLG 0200000000000 /* N flag */
#define XT_MFLG 0100000000000 /* M flag */
/* Translation table */
#define XT_V_CODE 15 /* translation op */
#define XT_M_CODE 07
#define XT_BYMASK 07777 /* byte mask */
#define XT_DGMASK 017 /* digit mask */
#define XT_GETCODE(x) ((int32) (((x) >> XT_V_CODE) & XT_M_CODE))
/* AC masks */
#define XLNTMASK 0000777777777 /* length */
#define XFLGMASK 0700000000000 /* flags */
#define XT_MBZ 0777000000000 /* must be zero */
#define XT_MBZE 0047777000000 /* must be zero, edit */
/* Register change log */
#define XT_N_RLOG 5 /* entry width */
#define XT_M_RLOG ((1 << XT_N_RLOG) - 1) /* entry mask */
#define XT_O_RLOG 1 /* entry offset */
#define XT_INSRLOG(x,v) v = ((v << XT_N_RLOG) | (((x) + XT_O_RLOG) & XT_M_RLOG))
#define XT_REMRLOG(x,v) x = (v & XT_M_RLOG) - XT_O_RLOG; \
v = v >> XT_N_RLOG
/* Edit */
#define ED_V_PBYN 30 /* pattern byte # */
#define ED_M_PBYN 03
#define ED_PBYNO 0040000000000 /* overflow bit */
#define ED_GETPBYN(x) ((int32) (((x) >> ED_V_PBYN) & ED_M_PBYN))
#define ED_V_POPC 6 /* pattern byte opcode */
#define ED_M_PAT 0777 /* pattern byte mask */
#define ED_M_NUM 0077 /* number for msg, etc */
#define ED_PBYTE(x,y) ((int32) (((x) >> (27 - (ED_GETPBYN (y) * 9))) & ED_M_PAT))
#define ED_STOP 0000 /* stop */
#define ED_SELECT 0001 /* select source */
#define ED_SIGST 0002 /* start significance */
#define ED_FLDSEP 0003 /* field separator */
#define ED_EXCHMD 0004 /* exchange mark, dst */
#define ED_MESSAG 0100 /* message */
#define ED_SKPM 0500 /* skip if M */
#define ED_SKPN 0600 /* skip if N */
#define ED_SKPA 0700 /* skip always */
extern d10 *ac_cur; /* current AC block */
extern d10 bytemask[64];
extern int32 flags;
extern int32 rlog;
extern jmp_buf save_env;
extern d10 Read (int32 ea, int32 prv);
extern void Write (int32 ea, d10 val, int32 prv);
extern a10 calc_ea (d10 inst, int32 prv);
extern int32 test_int (void);
d10 incbp (d10 bp);
d10 incloadbp (int32 ac, int32 pflgs);
void incstorebp (d10 val, int32 ac, int32 pflgs);
d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 pflgs);
void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs);
static const d10 pwrs10[23][2] = {
0, 0,
0, 1,
0, 10,
0, 100,
0, 1000,
0, 10000,
0, 100000,
0, 1000000,
0, 10000000,
0, 100000000,
0, 1000000000,
0, 10000000000,
2, 31280523264,
29, 3567587328,
291, 1316134912,
2910, 13161349120,
29103, 28534276096,
291038, 10464854016,
2910383, 1569325056,
29103830, 15693250560,
291038304, 19493552128,
2910383045, 23136829440,
29103830456, 25209864192 };
int xtend (int32 ac, int32 ea, int32 pflgs)
{
d10 b1, b2, ppi;
d10 xinst, xoff, digit, f1, f2, rs[2];
d10 xflgs = 0;
a10 e1, entad;
int32 p1 = ADDAC (ac, 1);
int32 p3 = ADDAC (ac, 3);
int32 p4 = ADDAC (ac, 4);
int32 flg, i, s2, t, pp, pat, xop, xac, ret;
xinst = Read (ea, MM_OPND); /* get extended instr */
xop = GET_OP (xinst); /* get opcode */
xac = GET_AC (xinst); /* get AC */
if (xac || (xop == 0) || (xop > XT_MOVSRJ)) return XT_MUUO;
rlog = 0; /* clear log */
switch (xop) { /* case on opcode */
/* String compares - checked against KS10 ucode
If both strings are zero length, they are considered equal.
Both source and destination lengths are MBZ checked.
AC = source1 length
AC + 1 = source1 byte pointer
AC + 3 = source2 length
AC + 4 = source2 byte pointer
*/
case XT_CMPSL: /* CMPSL */
case XT_CMPSE: /* CMPSE */
case XT_CMPSLE: /* CMPSLE */
case XT_CMPSGE: /* CMPSGE */
case XT_CMPSN: /* CMPSN */
case XT_CMPSG: /* CMPSG */
if ((AC(ac) | AC(p3)) & XT_MBZ) return XT_MUUO; /* check length MBZ */
f1 = Read (ADDA (ea, 1), MM_OPND) & bytemask[GET_S (AC(p1))];
f2 = Read (ADDA (ea, 2), MM_OPND) & bytemask[GET_S (AC(p4))];
b1 = b2 = 0;
for (flg = 0; (AC(ac) | AC(p3)) && (b1 == b2); flg++) {
if (flg && (t = test_int ())) ABORT (t);
rlog = 0; /* clear log */
if (AC(ac)) b1 = incloadbp (p1, pflgs); /* src1 */
else b1 = f1;
if (AC(p3)) b2 = incloadbp (p4, pflgs); /* src2 */
else b2 = f2;
if (AC(ac)) AC(ac) = (AC(ac) - 1) & XLNTMASK;
if (AC(p3)) AC(p3) = (AC(p3) - 1) & XLNTMASK; }
switch (xop) {
case XT_CMPSL: return (b1 < b2)? XT_SKIP: XT_NOSK;
case XT_CMPSE: return (b1 == b2)? XT_SKIP: XT_NOSK;
case XT_CMPSLE: return (b1 <= b2)? XT_SKIP: XT_NOSK;
case XT_CMPSGE: return (b1 >= b2)? XT_SKIP: XT_NOSK;
case XT_CMPSN: return (b1 != b2)? XT_SKIP: XT_NOSK;
case XT_CMPSG: return (b1 > b2)? XT_SKIP: XT_NOSK; }
return XT_MUUO;
/* Convert binary to decimal instructions - checked against KS10 ucode
There are no MBZ tests.
AC'AC + 1 = double precision integer source
AC + 3 = flags and destination length
AC + 4 = destination byte pointer
*/
case XT_CVTBDO: /* CVTBDO */
case XT_CVTBDT: /* CVTBDT */
e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */
if (xop == XT_CVTBDO) /* offset? */
xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */
rs[0] = AC(ac); /* get src opnd */
rs[1] = CLRS (AC(p1));
if (!TSTF (F_FPD)) { /* set up done yet? */
if (TSTS (AC(ac))) { DMOVN (rs); } /* get abs value */
for (i = 22; i > 1; i--) { /* find field width */
if (DCMPGE (rs, pwrs10[i])) break; }
if (i > (AC(p3) & XLNTMASK)) return XT_NOSK;
if ((i < (AC(p3) & XLNTMASK)) && (AC(p3) & XT_LFLG)) {
f1 = Read (ADDA (ea, 1), MM_OPND);
filldst (f1, p3, (AC(p3) & XLNTMASK) - i, pflgs); }
else AC(p3) = (AC(p3) & XFLGMASK) | i;
if (TSTS (AC(ac))) AC(p3) = AC(p3) | XT_MFLG;
if (AC(ac) | AC(p1)) AC(p3) = AC(p3) | XT_NFLG;
AC(ac) = rs[0]; /* update state */
AC(p1) = rs[1];
SETF (F_FPD); } /* mark set up done */
/* Now do actual binary to decimal conversion */
for (flg = 0; AC(p3) & XLNTMASK; flg++) {
if (flg && (t = test_int ())) ABORT (t);
rlog = 0; /* clear log */
i = (int32) AC(p3) & XLNTMASK; /* get length */
if (i > 22) i = 22; /* put in range */
for (digit = 0; (digit < 10) && DCMPGE (rs, pwrs10[i]); digit++) {
rs[0] = rs[0] - pwrs10[i][0] - (rs[1] < pwrs10[i][1]);
rs[1] = (rs[1] - pwrs10[i][1]) & MMASK; }
if (xop == XT_CVTBDO) digit = (digit + xoff) & DMASK;
else { f1 = Read (e1 + (int32) digit, MM_OPND);
if ((i == 1) && (AC(p3) & XT_LFLG)) f1 = f1 >> 18;
digit = f1 & RMASK; }
incstorebp (digit, p4, pflgs); /* store digit */
AC(ac) = rs[0]; /* mem access ok */
AC(p1) = rs[1]; /* update state */
AC(p3) = (AC(p3) & XFLGMASK) | ((AC(p3) - 1) & XLNTMASK); }
CLRF (F_FPD); /* clear FPD */
return XT_SKIP;
/* Convert decimal to binary instructions - checked against KS10 ucode
There are no MBZ tests.
AC = flags and source length
AC + 1 = source byte pointer
AC + 3'AC + 4 = double precision integer result
*/
case XT_CVTDBT: /* CVTDBT */
case XT_CVTDBO: /* CVTDBO */
e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */
if ((AC(ac) & XT_SFLG) == 0) AC(p3) = AC(p4) = 0; /* !S? clr res */
else AC(p4) = CLRS (AC(p4)); /* clear low sign */
if (xop == XT_CVTDBO) { /* offset? */
xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */
AC(ac) = AC(ac) | XT_SFLG; } /* set S flag */
xflgs = AC(ac) & XFLGMASK; /* get xlation flags */
for (flg = 0; AC(ac) & XLNTMASK; flg++) {
if (flg && (t = test_int ())) ABORT (t);
rlog = 0; /* clear log */
b1 = incloadbp (p1, pflgs); /* get byte */
if (xop == XT_CVTDBO) b1 = (b1 + xoff) & DMASK;
else { b1 = xlate (b1, e1, &xflgs, MM_OPND);
if (b1 < 0) { /* terminated? */
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4));
return XT_NOSK; }
if (xflgs & XT_SFLG) b1 = b1 & XT_DGMASK;
else b1 = 0; }
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
if ((b1 < 0) || (b1 > 9)) { /* bad digit? done */
if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4));
return XT_NOSK; }
AC(p4) = (AC(p4) * 10) + b1; /* base * 10 + digit */
AC(p3) = ((AC(p3) * 10) + (AC(p4) >> 35)) & DMASK;
AC(p4) = AC(p4) & MMASK; }
if (AC(ac) & XT_MFLG) {
AC(p4) = -AC(p4) & MMASK;
AC(p3) = (~AC(p3) + (AC(p4) == 0)) & DMASK; }
if (TSTS (AC(p3))) AC(p4) = SETS (AC(p4));
return XT_SKIP;
/* String move instructions - checked against KS10 ucode
Only the destination length is MBZ checked.
AC = flags (MOVST only) and source length
AC + 1 = source byte pointer
AC + 3 = destination length
AC + 4 = destination byte pointer
*/
case XT_MOVSO: /* MOVSO */
case XT_MOVST: /* MOVST */
case XT_MOVSRJ: /* MOVSRJ */
case XT_MOVSLJ: /* MOVSLJ */
if (AC(p3) & XT_MBZ) return XT_MUUO; /* test dst lnt MBZ */
f1 = Read (ADDA (ea, 1), MM_OPND); /* get fill */
switch (xop) { /* case on instr */
case XT_MOVSO: /* MOVSO */
AC(ac) = AC(ac) & XLNTMASK; /* trim src length */
xoff = calc_ea (xinst, MM_EA); /* get offset */
if (xoff & RSIGN) xoff = xoff | LMASK; /* sign extend 18b */
s2 = GET_S (AC(p4)); /* get dst byte size */
break;
case XT_MOVST: /* MOVST */
e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */
break;
case XT_MOVSRJ: /* MOVSRJ */
AC(ac) = AC(ac) & XLNTMASK; /* trim src length */
if (AC(p3) == 0) return (AC(ac)? XT_NOSK: XT_SKIP);
if (AC(ac) > AC(p3)) { /* adv src ptr */
for (flg = 0; AC(ac) > AC(p3); flg++) {
if (flg && (t = test_int ())) ABORT (t);
AC(p1) = incbp (AC(p1));
AC(ac) = (AC(ac) - 1) & XLNTMASK; } }
else if (AC(ac) < AC(p3))
filldst (f1, p3, AC(p3) - AC(ac), pflgs);
break;
case XT_MOVSLJ: /* MOVSLJ */
AC(ac) = AC(ac) & XLNTMASK; /* trim src length */
break; }
xflgs = AC(ac) & XFLGMASK; /* get xlation flags */
if (AC(p3) == 0) return (AC(ac)? XT_NOSK: XT_SKIP);
for (flg = 0; AC(p3) & XLNTMASK; flg++) {
if (flg && (t = test_int ())) ABORT (t);
rlog = 0; /* clear log */
if (AC(ac) & XLNTMASK) { /* any source? */
b1 = incloadbp (p1, pflgs); /* src byte */
if (xop == XT_MOVSO) { /* offset? */
b1 = (b1 + xoff) & DMASK; /* test fit */
if (b1 & ~bytemask[s2]) {
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
return XT_NOSK; } }
else if (xop == XT_MOVST) { /* translate? */
b1 = xlate (b1, e1, &xflgs, MM_OPND);
if (b1 < 0) { /* upd flags in AC */
AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK);
return XT_NOSK; }
if (xflgs & XT_SFLG) b1 = b1 & XT_BYMASK;
else b1 = -1; } }
else b1 = f1;
if (b1 >= 0) { /* valid byte? */
incstorebp (b1, p4, pflgs); /* store byte */
AC(p3) = (AC(p3) - 1) & XLNTMASK; } /* update state */
if (AC(ac) & XLNTMASK) AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); }
return (AC(ac) & XLNTMASK)? XT_NOSK: XT_SKIP;
/* Edit - checked against KS10 ucode
Only the flags/pattern pointer word is MBZ checked.
AC = flags, pattern pointer
AC + 1 = source byte pointer
AC + 3 = mark address
AC + 4 = destination byte pointer
*/
case XT_EDIT: /* EDIT */
if (AC(ac) & XT_MBZE) return XT_MUUO; /* check pattern MBZ */
xflgs = AC(ac) & XFLGMASK; /* get xlation flags */
e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */
for (ppi = 1, ret = -1, flg = 0; ret < 0; flg++, ppi = 1) {
if (flg && (t = test_int ())) ABORT (t);
rlog = 0; /* clear log */
pp = (int32) AC(ac) & AMASK; /* get pattern ptr */
b1 = Read (pp, MM_OPND); /* get pattern word */
pat = ED_PBYTE (b1, AC(ac)); /* get pattern byte */
switch ((pat < 0100)? pat: ((pat >> ED_V_POPC) + 0100)) {
case ED_STOP: /* stop */
ret = XT_SKIP; /* exit loop */
break;
case ED_SELECT: /* select source */
b1 = incloadbp (p1, pflgs); /* get src */
entad = (e1 + ((int32) b1 >> 1)) & AMASK;
f1 = ((Read (entad, MM_OPND) >> ((b1 & 1)? 0: 18)) & RMASK);
i = XT_GETCODE (f1);
if (i & 2) xflgs =
(i & 1)? xflgs | XT_MFLG: xflgs & ~XT_MFLG;
switch (i) {
case 00: case 02: case 03:
if (xflgs & XT_SFLG) f1 = f1 & XT_BYMASK;
else { f1 = Read (INCA (ea), MM_OPND);
if (f1 == 0) break; }
incstorebp (f1, p4, pflgs);
break;
case 01:
ret = XT_NOSK; /* exit loop */
break;
case 04: case 06: case 07:
xflgs = xflgs | XT_NFLG;
f1 = f1 & XT_BYMASK;
if ((xflgs & XT_SFLG) == 0) {
f2 = Read (ADDA (ea, 2), MM_OPND);
Write ((a10) AC(p3), AC(p4), MM_OPND);
if (f2) incstorebp (f2, p4, pflgs);
xflgs = xflgs | XT_SFLG; }
incstorebp (f1, p4, pflgs);
break;
case 05:
xflgs = xflgs | XT_NFLG;
ret = XT_NOSK; /* exit loop */
break; } /* end case xlate op */
break;
case ED_SIGST: /* start significance */
if ((xflgs & XT_SFLG) == 0) {
f2 = Read (ADDA (ea, 2), MM_OPND);
Write ((a10) AC(p3), AC(p4), MM_OPND);
if (f2) incstorebp (f2, p4, pflgs);
xflgs = xflgs | XT_SFLG; }
break;
case ED_FLDSEP: /* separate fields */
xflgs = 0;
break;
case ED_EXCHMD: /* exchange */
f2 = Read ((int32) (AC(p3) & AMASK), MM_OPND);
Write ((int32) (AC(p3) & AMASK), AC(p4), MM_OPND);
AC(p4) = f2;
break;
case (0100 + (ED_MESSAG >> ED_V_POPC)): /* message */
if (xflgs & XT_SFLG)
f1 = Read (ea + (pat & ED_M_NUM) + 1, MM_OPND);
else { f1 = Read (ea + 1, MM_OPND);
if (f1 == 0) break; }
incstorebp (f1, p4, pflgs);
break;
case (0100 + (ED_SKPM >> ED_V_POPC)): /* skip on M */
if (xflgs & XT_MFLG) ppi = (pat & ED_M_NUM) + 2;
break;
case (0100 + (ED_SKPN >> ED_V_POPC)): /* skip on N */
if (xflgs & XT_NFLG) ppi = (pat & ED_M_NUM) + 2;
break;
case (0100 + (ED_SKPA >> ED_V_POPC)): /* skip always */
ppi = (pat & ED_M_NUM) + 2;
break;
default: /* NOP or undefined */
break; } /* end case pttrn op */
AC(ac) = AC(ac) + ((ppi & ED_M_PBYN) << ED_V_PBYN);
AC(ac) = AC(ac) + (ppi >> 2) + ((AC(ac) & ED_PBYNO)? 1: 0);
AC(ac) = xflgs | (AC(ac) & ~(XT_MBZE | XFLGMASK)); }
return ret; } /* end case xop */
return XT_MUUO;
}
/* Supporting subroutines */
/* Increment byte pointer, register version */
d10 incbp (d10 bp)
{
int32 p, s;
p = GET_P (bp); /* get P and S */
s = GET_S (bp);
p = p - s; /* adv P */
if (p < 0) { /* end of word? */
bp = (bp & LMASK) | (INCR (bp)); /* increment addr */
p = (36 - s) & 077; } /* reset P */
bp = PUT_P (bp, p); /* store new P */
return bp;
}
/* Increment and load byte, extended version - uses register log */
d10 incloadbp (int32 ac, int32 pflgs)
{
a10 ba;
d10 bp, wd;
int32 p, s;
bp = AC(ac) = incbp (AC(ac)); /* increment bp */
XT_INSRLOG (ac, rlog); /* log change */
p = GET_P (bp); /* get P and S */
s = GET_S (bp);
ba = calc_ea (bp, MM_EA_XSRC); /* calc bp eff addr */
wd = Read (ba, MM_XSRC); /* read word */
wd = (wd >> p) & bytemask[s]; /* get byte */
return wd;
}
/* Increment and deposit byte, extended version - uses register log */
void incstorebp (d10 val, int32 ac, int32 pflgs)
{
a10 ba;
d10 bp, wd, mask;
int32 p, s;
bp = AC(ac) = incbp (AC(ac)); /* increment bp */
XT_INSRLOG (ac, rlog); /* log change */
p = GET_P (bp); /* get P and S */
s = GET_S (bp);
ba = calc_ea (bp, MM_EA_XDST); /* calc bp eff addr */
wd = Read (ba, MM_XDST); /* read, write test */
mask = bytemask[s] << p; /* shift mask, val */
val = val << p;
wd = (wd & ~mask) | (val & mask); /* insert byte */
Write (ba, wd & DMASK, MM_XDST);
return;
}
/* Translate byte
Arguments
by = byte to translate
tblad = virtual address of translation table
*xflgs = pointer to word containing translation flags
prv = previous mode flag for table lookup
Returns
xby = >= 0, translated byte
< 0, terminate translation
*/
d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 prv)
{
a10 ea;
int32 tcode;
d10 tblent;
ea = (tblad + ((int32) by >> 1)) & AMASK;
tblent = ((Read (ea, prv) >> ((by & 1)? 0: 18)) & RMASK);
tcode = XT_GETCODE (tblent); /* get xlate code */
switch (tcode) {
case 00:
return (*xflgs & XT_SFLG)? tblent: by;
case 01:
break;
case 02:
*xflgs = *xflgs & ~XT_MFLG;
return (*xflgs & XT_SFLG)? tblent: by;
case 03:
*xflgs = *xflgs | XT_MFLG;
return (*xflgs & XT_SFLG)? tblent: by;
case 04:
*xflgs = *xflgs | XT_SFLG | XT_NFLG;
return tblent;
case 05:
*xflgs = *xflgs | XT_NFLG;
break;
case 06:
*xflgs = (*xflgs | XT_SFLG | XT_NFLG) & ~XT_MFLG;
return tblent;
case 07:
*xflgs = *xflgs | XT_SFLG | XT_NFLG | XT_MFLG;
return tblent; } /* end case xlate code */
return -1;
}
/* Fill out the destination string
Arguments:
fill = fill
ac = 2 word AC block (length, byte pointer)
cnt = fill count
pflgs = PXCT flags
*/
void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs)
{
int32 i, t;
int32 p1 = ADDA (ac, 1);
for (i = 0; i < cnt; i++) {
if (i && (t = test_int ())) ABORT (t);
rlog = 0; /* clear log */
incstorebp (fill, p1, pflgs);
AC(ac) = (AC(ac) & XFLGMASK) | ((AC(ac) - 1) & XLNTMASK); }
rlog = 0;
return;
}
/* Clean up after page fault
Arguments:
logv = register change log
For each register in logv, decrement the register's contents as
though it were a byte pointer. Note that the KS10 does <not>
do a full decrement calculation but merely adds S to P.
*/
void xtcln (int32 logv)
{
int32 p, reg;
while (logv) {
XT_REMRLOG (reg, logv); /* get next reg */
if ((reg >= 0) && (reg < AC_NUM)) {
p = GET_P (AC(reg)) + GET_S (AC(reg)); /* get p + s */
AC(reg) = PUT_P (AC(reg), p); } /* p <- p + s */
}
return;
}

View file

@ -1,6 +1,6 @@
/* pdp11_cis.c: PDP-11 CIS optional instruction set simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -313,7 +313,7 @@ int32 c, i, j, k, t, op, rn, addr;
int32 fill, mask, match, limit, mvlnt, shift;
int32 spc, ldivd, ldivr;
int32 arg[6]; /* operands */
unsigned int32 nc, digit, result;
uint32 nc, digit, result;
static DSTR accum, src1, src2, dst;
static DSTR mptable[10];
static DSTR Dstr1 = { 0, 0x10, 0, 0, 0 };
@ -981,9 +981,10 @@ return TestDstr (src); /* clean -0 */
void WriteDstr (int32 *dscr, DSTR *dst, int32 flag)
{
int32 c, i, mask, limit, end, type, lnt;
static int32 masktab[8] = {
0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,
int32 c, i, limit, end, type, lnt;
uint32 mask;
static uint32 masktab[8] = {
0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000,
0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000 };
static int32 unsignedtab[8] = { 0, 1, 0, 0, 0, 0, 0, 1 };

View file

@ -1,6 +1,6 @@
/* pdp11_cpu.c: PDP-11 CPU simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,13 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu PDP-11 CPU (J-11 microprocessor)
23-Apr-01 RMS Added RK611 support
05-Apr-01 RMS Added TS11/TSV05 support
05-Mar-01 RMS Added clock calibration support
11-Feb-01 RMS Added DECtape support
25-Jan-01 RMS Fixed 4M memory definition (found by Eric Smith)
14-Apr-99 RMS Changed t_addr to unsigned
18-Aug-98 RMS Added CIS support
09-May-98 RMS Fixed bug in DIV overflow test
@ -179,14 +186,14 @@
#define last_pa (cpu_unit.u4) /* and RESTOREd */
#define UNIT_V_18B (UNIT_V_UF) /* force 18b addr */
#define UNIT_18B (1u << UNIT_V_18B)
#define UNIT_V_CIS (UNIT_V_UF + 1) /* CIS present */
#define UNIT_V_CIS (UNIT_V_UF + 1) /* CIS present */
#define UNIT_CIS (1u << UNIT_V_CIS)
#define UNIT_V_MSIZE (UNIT_V_UF + 2) /* dummy */
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
/* Global state */
unsigned int16 *M = NULL; /* address of memory */
uint16 *M = NULL; /* address of memory */
int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */
int32 STACKFILE[4] = { 0 }; /* SP, four modes */
int32 saved_PC = 0; /* program counter */
@ -195,8 +202,8 @@ int32 PSW = 0; /* PSW */
int32 cm = 0; /* current mode */
int32 pm = 0; /* previous mode */
int32 rs = 0; /* register set */
int32 ipl = 0; /* int pri level */
int32 tbit = 0; /* trace flag */
int32 ipl = 0; /* int pri level */
int32 tbit = 0; /* trace flag */
int32 N = 0, Z = 0, V = 0, C = 0; /* condition codes */
int32 wait_state = 0; /* wait state */
int32 trap_req = 0; /* trap requests */
@ -213,23 +220,24 @@ int32 MMR0 = 0; /* MMR0 - status */
int32 MMR1 = 0; /* MMR1 - R+/-R */
int32 MMR2 = 0; /* MMR2 - saved PC */
int32 MMR3 = 0; /* MMR3 - 22b status */
int32 isenable = 0, dsenable = 0; /* i, d space flags */
int32 CPUERR = 0; /* CPU error reg */
int32 MEMERR = 0; /* memory error reg */
int32 isenable = 0, dsenable = 0; /* i, d space flags */
int32 CPUERR = 0; /* CPU error reg */
int32 MEMERR = 0; /* memory error reg */
int32 CCR = 0; /* cache control reg */
int32 HITMISS = 0; /* hit/miss reg */
int32 MAINT = (0 << 9) + (0 << 8) + (4 << 4); /* maint bit<9> = Q/U */
/* <8> = hwre FP */
/* <6:4> = sys type */
int32 stop_trap = 1; /* stop on trap */
int32 stop_vecabort = 1; /* stop on vec abort */
int32 stop_vecabort = 1; /* stop on vec abort */
int32 stop_spabort = 1; /* stop on SP abort */
int32 wait_enable = 0; /* wait state enable */
int32 ibkpt_addr = ILL_ADR_FLAG | VAMASK; /* breakpoint addr */
int32 old_PC = 0; /* previous PC */
int32 ibkpt_addr = ILL_ADR_FLAG | VAMASK; /* breakpoint addr */
int32 old_PC = 0; /* previous PC */
int32 dev_enb = (-1) & ~INT_TS; /* dev enables */
jmp_buf save_env; /* abort handler */
int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */
int32 int_mask[8] = { INT_IPL0, INT_IPL1, INT_IPL2, /* interrupt masks */
uint32 int_mask[8] = { INT_IPL0, INT_IPL1, INT_IPL2, /* interrupt masks */
INT_IPL3, INT_IPL4, INT_IPL5, INT_IPL6, INT_IPL7 };
extern int32 sim_int_char;
@ -270,6 +278,9 @@ extern t_stat lpt_wr (int32 data, int32 addr, int32 access);
extern t_stat rk_rd (int32 *data, int32 addr, int32 access);
extern t_stat rk_wr (int32 data, int32 addr, int32 access);
extern int32 rk_inta (void);
/* extern t_stat hk_rd (int32 *data, int32 addr, int32 access);
extern t_stat hk_wr (int32 data, int32 addr, int32 access);
extern int32 hk_inta (void); */
extern t_stat rl_rd (int32 *data, int32 addr, int32 access);
extern t_stat rl_wr (int32 data, int32 addr, int32 access);
extern t_stat rp_rd (int32 *data, int32 addr, int32 access);
@ -277,38 +288,45 @@ extern t_stat rp_wr (int32 data, int32 addr, int32 access);
extern int32 rp_inta (void);
extern t_stat rx_rd (int32 *data, int32 addr, int32 access);
extern t_stat rx_wr (int32 data, int32 addr, int32 access);
extern t_stat dt_rd (int32 *data, int32 addr, int32 access);
extern t_stat dt_wr (int32 data, int32 addr, int32 access);
extern t_stat tm_rd (int32 *data, int32 addr, int32 access);
extern t_stat tm_wr (int32 data, int32 addr, int32 access);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat ts_rd (int32 *data, int32 addr, int32 access);
extern t_stat ts_wr (int32 data, int32 addr, int32 access);
/* Auxiliary data structures */
struct iolink { /* I/O page linkage */
int32 low; /* low I/O addr */
int32 high; /* high I/O addr */
int32 enb; /* enable mask */
t_stat (*read)(); /* read routine */
t_stat (*write)(); }; /* write routine */
struct iolink iotable[] = {
{ 017777740, 017777777, &CPU_rd, &CPU_wr },
{ 017777546, 017777567, &std_rd, &std_wr },
{ 017777514, 017777517, &lpt_rd, &lpt_wr },
{ 017777400, 017777417, &rk_rd, &rk_wr },
{ 017774400, 017774411, &rl_rd, &rl_wr },
{ 017776700, 017776753, &rp_rd, &rp_wr },
{ 017777170, 017777173, &rx_rd, &rx_wr },
{ 017772520, 017772533, &tm_rd, &tm_wr },
{ 017777600, 017777677, &APR_rd, &APR_wr },
{ 017772200, 017772377, &APR_rd, &APR_wr },
{ 017777570, 017777577, &SR_MMR012_rd, &SR_MMR012_wr },
{ 017772516, 017772517, &MMR3_rd, &MMR3_wr },
{ 0, 0, NULL } };
{ 017777740, 017777777, 0, &CPU_rd, &CPU_wr },
{ 017777546, 017777567, 0, &std_rd, &std_wr },
{ 017777514, 017777517, 0, &lpt_rd, &lpt_wr },
{ 017777400, 017777417, INT_RK, &rk_rd, &rk_wr },
/* { 017777440, 017777477, INT_HK, &hk_rd, &hk_wr }, */
{ 017774400, 017774411, INT_RL, &rl_rd, &rl_wr },
{ 017776700, 017776753, INT_RP, &rp_rd, &rp_wr },
{ 017777170, 017777173, INT_RX, &rx_rd, &rx_wr },
{ 017777340, 017777351, INT_DTA, &dt_rd, &dt_wr },
{ 017772520, 017772533, INT_TM, &tm_rd, &tm_wr },
{ 017772520, 017772523, INT_TS, &ts_rd, &ts_wr },
{ 017777600, 017777677, 0, &APR_rd, &APR_wr },
{ 017772200, 017772377, 0, &APR_rd, &APR_wr },
{ 017777570, 017777577, 0, &SR_MMR012_rd, &SR_MMR012_wr },
{ 017772516, 017772517, 0, &MMR3_rd, &MMR3_wr },
{ 0, 0, 0, NULL, NULL } };
int32 int_vec[32] = { /* int req to vector */
0, 0, 0, VEC_PIRQ, VEC_CLK, 0, 0, VEC_PIRQ,
VEC_RK, VEC_RL, VEC_RX, VEC_TM, VEC_RP, 0, 0, VEC_PIRQ,
VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, VEC_LPT, 0, 0, 0,
0, 0, 0, 0, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ };
0, 0, 0, VEC_PIRQ, VEC_CLK, VEC_DTA, 0, VEC_PIRQ,
VEC_RK, VEC_RL, VEC_RX, VEC_TM, VEC_RP, VEC_TS, VEC_HK, 0,
0, 0, 0, VEC_PIRQ, VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP,
VEC_LPT, 0, 0, 0, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ, VEC_PIRQ };
int32 (*int_ack[32])() = { /* int ack routines */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -322,7 +340,7 @@ int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */
VEC_IOT, VEC_EMT, VEC_TRAP, VEC_TRC,
VEC_YEL, VEC_PWRFL, VEC_FPE };
int32 trap_clear[TRAP_V_MAX] = { /* trap clears */
int32 trap_clear[TRAP_V_MAX] = { /* trap clears */
TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC,
TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC,
@ -505,6 +523,7 @@ REG cpu_reg[] = {
{ ORDATA (OLDPC, old_PC, 16), REG_RO },
{ ORDATA (BREAK, ibkpt_addr, 17) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL} };
MTAB cpu_mod[] = {
@ -530,7 +549,7 @@ MTAB cpu_mod[] = {
{ UNIT_MSIZE, 1048576, NULL, "1M", &cpu_set_size},
{ UNIT_MSIZE, 2097152, NULL, "2M", &cpu_set_size},
{ UNIT_MSIZE, 3145728, NULL, "3M", &cpu_set_size},
{ UNIT_MSIZE, 4194304, NULL, "4M", &cpu_set_size},
{ UNIT_MSIZE, 4186112, NULL, "4M", &cpu_set_size},
{ 0 } };
DEVICE cpu_dev = {
@ -543,6 +562,8 @@ t_stat sim_instr (void)
{
extern int32 sim_interval;
extern UNIT *sim_clock_queue;
extern UNIT clk_unit;
extern int32 sim_rtc_init (int32 time);
register int32 IR, srcspec, srcreg, dstspec, dstreg;
register int32 src, src2, dst;
register int32 i, t, sign, oldrs, trapnum;
@ -582,6 +603,7 @@ CPU_wr (PIRQ, 017777772, WRITE); /* rewrite PIRQ */
trap_req = calc_ints (ipl, int_req, trap_req);
trapea = 0;
reason = 0;
sim_rtc_init (clk_unit.wait); /* init clock */
/* Abort handling
@ -2043,7 +2065,8 @@ t_stat stat;
struct iolink *p;
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa <= p -> high)) {
if ((pa >= p -> low) && (pa <= p -> high) &&
((p -> enb == 0) || (dev_enb & p -> enb))) {
stat = p -> read (data, pa, access);
trap_req = calc_ints (ipl, int_req, trap_req);
return stat; } }
@ -2056,7 +2079,8 @@ t_stat stat;
struct iolink *p;
for (p = &iotable[0]; p -> low != 0; p++ ) {
if ((pa >= p -> low) && (pa <= p -> high)) {
if ((pa >= p -> low) && (pa <= p -> high) &&
((p -> enb == 0) || (dev_enb & p -> enb))) {
stat = p -> write (data, pa, access);
trap_req = calc_ints (ipl, int_req, trap_req);
return stat; } }

View file

@ -1,6 +1,6 @@
/* pdp11_defs.h: PDP-11 simulator definitions
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,10 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11
23-Apr-01 RMS Added RK611 support
05-Apr-01 RMS Added TS11/TSV05 support
10-Feb-01 RMS Added DECtape support
*/
#include "sim_defs.h" /* simulator defns */
@ -40,6 +44,7 @@
#define MAXMEMSIZE 020000000 /* 2**22 */
#define MEMSIZE (cpu_unit.capac)
#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE)
#define DMASK 0177777
/* Protection modes */
@ -235,8 +240,8 @@ typedef struct fpac fpac_t;
<3:0> = BR7, <3> = PIR7
<7:4> = BR6, <7> = PIR6
<15:8> = BR5, <15> = PIR5
<28:16> = BR4, <28> = PIR4
<19:8> = BR5, <15> = PIR5
<28:20> = BR4, <28> = PIR4
<29> = PIR3
<30> = PIR2
<31> = PIR1
@ -244,18 +249,21 @@ typedef struct fpac fpac_t;
#define INT_V_PIR7 3
#define INT_V_CLK 4
#define INT_V_DTA 5
#define INT_V_PIR6 7
#define INT_V_RK 8
#define INT_V_RL 9
#define INT_V_RX 10
#define INT_V_TM 11
#define INT_V_RP 12
#define INT_V_PIR5 15
#define INT_V_TTI 16
#define INT_V_TTO 17
#define INT_V_PTR 18
#define INT_V_PTP 19
#define INT_V_LPT 20
#define INT_V_TS 13
#define INT_V_HK 14
#define INT_V_PIR5 19
#define INT_V_TTI 20
#define INT_V_TTO 21
#define INT_V_PTR 22
#define INT_V_PTP 23
#define INT_V_LPT 24
#define INT_V_PIR4 28
#define INT_V_PIR3 29
#define INT_V_PIR2 30
@ -263,12 +271,15 @@ typedef struct fpac fpac_t;
#define INT_PIR7 (1u << INT_V_PIR7)
#define INT_CLK (1u << INT_V_CLK)
#define INT_DTA (1u << INT_V_DTA)
#define INT_PIR6 (1u << INT_V_PIR6)
#define INT_RK (1u << INT_V_RK)
#define INT_RL (1u << INT_V_RL)
#define INT_RX (1u << INT_V_RX)
#define INT_TM (1u << INT_V_TM)
#define INT_RP (1u << INT_V_RP)
#define INT_TS (1u << INT_V_TS)
#define INT_HK (1u << INT_V_HK)
#define INT_PIR5 (1u << INT_V_PIR5)
#define INT_PTR (1u << INT_V_PTR)
#define INT_PTP (1u << INT_V_PTP)
@ -283,7 +294,7 @@ typedef struct fpac fpac_t;
#define INT_IPL7 0x00000000 /* int level masks */
#define INT_IPL6 0x0000000F
#define INT_IPL5 0x000000FF
#define INT_IPL4 0x0000FFFF
#define INT_IPL4 0x000FFFFF
#define INT_IPL3 0x1FFFFFFF
#define INT_IPL2 0x3FFFFFFF
#define INT_IPL1 0x7FFFFFFF
@ -296,11 +307,14 @@ typedef struct fpac fpac_t;
#define VEC_PTP 0074
#define VEC_CLK 0100
#define VEC_LPT 0200
#define VEC_HK 0210
#define VEC_RK 0220
#define VEC_RL 0160
#define VEC_RX 0264
#define VEC_DTA 0214
#define VEC_TM 0224
#define VEC_TS 0224
#define VEC_RP 0254
#define VEC_RX 0264
/* CPU and FPU macros */

View file

@ -1,6 +1,6 @@
/* pdp11_fp.c: PDP-11 floating point simulator (32b version)
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -206,7 +206,7 @@ fpac_t fround_fac = { (1u << (FP_V_FROUND + 32)), 0 };
fpac_t fround_guard_fac = { 0, (1u << (FP_V_FROUND + FP_GUARD)) };
fpac_t dround_guard_fac = { (1u << (FP_V_DROUND + FP_GUARD)), 0 };
fpac_t fmask_fac = { 0xFFFFFFFF, (1u << (FP_V_HB + FP_GUARD + 1)) - 1 };
static const unsigned int32 and_mask[33] = { 0,
static const uint32 and_mask[33] = { 0,
0x1, 0x3, 0x7, 0xF,
0x1F, 0x3F, 0x7F, 0xFF,
0x1FF, 0x3FF, 0x7FF, 0xFFF,

View file

@ -1,6 +1,6 @@
/* pdp11_lp.c: PDP-11 line printer simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,7 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
lpt line printer
lpt LP11 line printer
30-Oct-00 RMS Standardized register naming
*/
@ -40,8 +40,6 @@ t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *ptr);
t_stat lpt_detach (UNIT *uptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* LPT data structures

View file

@ -1,6 +1,6 @@
/* RK11 cartridge disk simulator
/* pdp11_rk.c: RK11 cartridge disk simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rk RK11/RK05 cartridge disk
26-Apr-01 RMS Added device enable/disable support
25-Mar-01 RMS Fixed block fill calculation
15-Feb-01 RMS Corrected bootstrap string
29-Jun-96 RMS Added unit disable support.
The RK11 is an eight drive cartridge disk subsystem. An RK05 drive
@ -155,8 +160,8 @@
#define RK_MIN 10
#define MAX(x,y) (((x) > (y))? (x): (y))
extern int32 int_req;
extern unsigned int16 *M; /* memory */
extern uint16 *M; /* memory */
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 rkcs = 0; /* control/status */
int32 rkds = 0; /* drive status */
@ -175,11 +180,6 @@ void rk_go (void);
void rk_set_done (int32 error);
void rk_clr_done (void);
t_stat rk_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* RK11 data structures
@ -231,6 +231,7 @@ REG rk_reg[] = {
{ GRDATA (FLG7, rk_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RK), REG_HRO },
{ NULL } };
MTAB rk_mod[] = {
@ -408,11 +409,11 @@ return;
the current command.
*/
static unsigned int16 fill[RK_NUMWD] = { 0 };
t_stat rk_svc (UNIT *uptr)
{
int32 comp, drv, err, awc, twc, wc;
int32 pa, da, fillc, track, sect;
int32 pa, da, remc, track, sect;
static uint16 fill[RK_NUMWD] = { 0 };
drv = uptr - rk_dev.units; /* get drv number */
if (uptr -> FUNC == RKCS_SEEK) { /* seek */
@ -451,8 +452,8 @@ if ((uptr -> FUNC == RKCS_READ) && (err == 0)) { /* read? */
if ((uptr -> FUNC == RKCS_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
if ((err == 0) && (fillc = (wc & (RK_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), fillc, uptr -> fileref);
if ((err == 0) && (remc = (wc & (RK_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), RK_NUMWD - remc, uptr -> fileref);
err = ferror (uptr -> fileref); } }
if ((uptr -> FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */
@ -570,7 +571,7 @@ static const int32 boot_rom[] = {
0005002, /* CLR R2 */
0005003, /* CLR R3 */
0005004, /* CLR R4 */
0012705, 0062153, /* MOV #"DK, R5 */
0012705, 0045504, /* MOV #"DK, R5 */
0105711, /* TSTB (R1) */
0100376, /* BPL .-2 */
0105011, /* CLRB (R1) */

View file

@ -1,6 +1,6 @@
/* RL11 (RLV12) cartridge disk simulator
/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rl RL11(RLV12)/RL01/RL02 cartridge disk
26-Apr-01 RMS Added device enable/disable support
25-Mar-01 RMS Fixed block fill calculation
15-Feb-01 RMS Corrected bootstrap string
12-Nov-97 RMS Added bad block table command.
25-Nov-96 RMS Default units to autosize.
29-Jun-96 RMS Added unit disable support.
@ -148,8 +153,8 @@
#define RLBAE_IMP 0000077 /* implemented */
extern int32 int_req;
extern unsigned int16 *M; /* memory */
extern uint16 *M; /* memory */
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 rlcs = 0; /* control/status */
int32 rlba = 0; /* memory address */
@ -166,11 +171,6 @@ t_stat rl_boot (int32 unitno);
t_stat rl_attach (UNIT *uptr, char *cptr);
t_stat rl_set_size (UNIT *uptr, int32 value);
t_stat rl_set_bad (UNIT *uptr, int32 value);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
/* RL11 data structures
@ -218,6 +218,7 @@ REG rl_reg[] = {
{ DRDATA (CAPAC2, rl_unit[2].capac, 32), PV_LEFT + REG_HRO },
{ DRDATA (CAPAC3, rl_unit[3].capac, 32), PV_LEFT + REG_HRO },
{ FLDATA (STOP_IOE, rl_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RL), REG_HRO },
{ NULL } };
MTAB rl_mod[] = {
@ -306,7 +307,7 @@ case 0: /* RLCS */
switch (GET_FUNC (rlcs)) { /* case on RLCS<3:1> */
case RLCS_NOP: /* nop */
rl_set_done (0);
return SCPE_OK;
break;
case RLCS_SEEK: /* seek */
curr = GET_CYL (uptr -> TRK); /* current cylinder */
offs = GET_CYL (rlda); /* offset */
@ -320,10 +321,10 @@ case 0: /* RLCS */
uptr -> TRK = (newc << RLDA_V_CYL) | /* put on track */
((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0);
sim_activate (uptr, rl_swait * abs (newc - curr));
return SCPE_OK;
break;
default: /* data transfer */
sim_activate (uptr, rl_swait); /* activate unit */
return SCPE_OK; } /* end switch func */
break; } /* end switch func */
return SCPE_OK; /* end case RLCS */
case 1: /* RLBA */
@ -357,11 +358,11 @@ case 4: /* RLBAE */
the current command.
*/
static unsigned int16 fill[RL_NUMWD] = { 0 };
t_stat rl_svc (UNIT *uptr)
{
int32 comp, err, awc, wc, maxwc;
int32 func, pa, da, fillc;
int32 func, pa, da, remc;
static uint16 fill[RL_NUMWD] = { 0 };
func = GET_FUNC (rlcs); /* get function */
if (func == RLCS_GSTA) { /* get status */
@ -421,13 +422,13 @@ if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */
if ((func == RLCS_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
if ((err == 0) && (fillc = (wc & (RL_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), fillc, uptr -> fileref);
if ((err == 0) && (remc = (wc & (RL_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), RL_NUMWD - remc, uptr -> fileref);
err = ferror (uptr -> fileref); } }
if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */
fillc = wc; /* xfer length */
for (wc = 0; (err == 0) && (wc < fillc); wc++) {
remc = wc; /* xfer length */
for (wc = 0; (err == 0) && (wc < remc); wc++) {
awc = fxread (&comp, sizeof (int16), 1, uptr -> fileref);
if (awc == 0) comp = 0;
if (comp != M[pa + wc]) rlcs = rlcs | RLCS_ERR | RLCS_CRC; }
@ -558,7 +559,7 @@ static const int32 boot_rom[] = {
0005002, /* CLR R2 */
0005003, /* CLR R3 */
0005004, /* CLR R4 */
0012705, 0062154, /* MOV "DL, R5 */
0012705, 0046104, /* MOV "DL, R5 */
0005007 /* CLR PC */
};

View file

@ -1,6 +1,6 @@
/* pdp11_rp.c - RP04/05/06/07 RM02/03/05/80 "Massbus style" disk controller
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,14 @@
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.
rp RH/RP/RM moving head disks
14-May-01 RMS Added check for unattached drive
25-Apr-01 RMS Added device enable/disable support
21-Apr-01 RMS Implemented UAI function
02-Apr-01 RMS Fixed CS1.TRE error clear function, CS2.MXF/PE writes
25-Mar-01 RMS Corrected block fill calculation, IE write processing
15-Feb-01 RMS Corrected bootstrap string
14-Apr-99 RMS Changed t_addr to unsigned
05-Oct-98 RMS Fixed bug, failing to interrupt on go error
04-Oct-98 RMS Changed names to allow coexistence with RH/TU77
@ -50,6 +58,7 @@
#define RP_NUMDR 8 /* #drives */
#define RP_NUMWD 256 /* words/sector */
#define RP_MAXFR 65536 /* max transfer */
#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) drv_tab[d].sect)))
@ -126,7 +135,7 @@
#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 NI */
#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 */
@ -140,7 +149,7 @@
#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)
#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)
@ -300,8 +309,8 @@ struct drvtyp drv_tab[] = {
{ RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV },
{ 0 } };
extern int32 int_req;
extern unsigned int16 *M; /* memory */
extern uint16 *M; /* memory */
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 rpcs1 = 0; /* control/status 1 */
int32 rpwc = 0; /* word count */
@ -336,11 +345,6 @@ t_stat rp_reset (DEVICE *dptr);
t_stat rp_boot (int32 unitno);
t_stat rp_attach (UNIT *uptr, char *cptr);
t_stat rp_detach (UNIT *uptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
/* RP data structures
@ -424,6 +428,7 @@ REG rp_reg[] = {
{ GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (STOP_IOE, rp_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO },
{ NULL } };
MTAB rp_mod[] = {
@ -570,8 +575,9 @@ return SCPE_OK;
t_stat rp_wr (int32 data, int32 PA, int32 access)
{
int32 drv, i, j;
int32 cs1f, drv, i, j;
cs1f = 0; /* no int on cs1 upd */
drv = GET_UNIT (rpcs2); /* get current unit */
j = (PA >> 1) & 037; /* get reg offset */
if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */
@ -585,11 +591,14 @@ if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */
switch (j) { /* decode PA<5:1> */
case 000: /* RPCS1 */
if (access == WRITEB) data = (PA & 1)?
(rpcs1 & 0377) | (data << 8): (rpcs1 & ~0377) | data;
if ((data & CS1_IE) == 0) int_req = int_req & ~INT_RP;
else if ((((rpcs1 & CS1_IE) == 0) && (rpcs1 & CS1_DONE)) ||
(data & CS1_DONE)) int_req = int_req | INT_RP;
if ((access == WRITEB) && (PA & 1)) data = data << 8;
else { if ((data & CS1_IE) == 0) int_req = int_req & ~INT_RP;
else if (data & CS1_DONE) int_req = int_req | INT_RP; }
if (data & CS1_TRE) { /* error clear? */
rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1<TRE> */
rpcs2 = rpcs2 & ~CS2_ERR; } /* clr CS2<15:8> */
if (access == WRITEB) data = (rpcs1 & /* merge data */
((PA & 1)? 0377: 0177400)) | data;
rpcs1 = (rpcs1 & ~CS1_RW) | (data & CS1_RW);
rpbae = (rpbae & ~CS1_M_UAE) | ((rpcs1 >> CS1_V_UAE) & CS1_M_UAE);
rpcs3 = (rpcs3 & ~CS1_IE) | (rpcs1 & CS1_IE);
@ -613,10 +622,13 @@ case 003: /* RPDA */
rpda = data & ~DA_MBZ;
break;
case 004: /* RPCS2 */
if (access == WRITEB) data = (PA & 1)?
(rpcs2 & 0377) | (data << 8): (rpcs2 & ~0377) | data;
if (data & CS2_CLR) rp_reset (&rp_dev);
else rpcs2 = (rpcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR;
if ((access == WRITEB) && (PA & 1)) data = data << 8;
if (data & CS2_CLR) rp_reset (&rp_dev); /* init? */
else { if ((data & ~rpcs2) & (CS2_PE | CS2_MXF))
cs1f = CS1_SC; /* diagn intr */
if (access == WRITEB) data = (rpcs2 & /* merge data */
((PA & 1)? 0377: 0177400)) | data;
rpcs2 = (rpcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; }
drv = GET_UNIT (rpcs2);
break;
case 006: /* RPER1 */
@ -624,7 +636,7 @@ case 006: /* RPER1 */
rper1[drv] = rper1[drv] & data;
break;
case 007: /* RPAS */
if (PA & 1) break;
if ((access == WRITEB) && (PA & 1)) break;
for (i = 0; i < RP_NUMDR; i++)
if (data & (AS_U0 << i)) rpds[i] = rpds[i] & ~DS_ATA;
break;
@ -649,12 +661,12 @@ case 016: /* RPDC */
rpdc = data & ~DC_MBZ;
break;
case 024: /* RPBAE */
if (PA & 1) break;
if ((access == WRITEB) && (PA & 1)) break;
rpbae = data & ~AE_MBZ;
rpcs1 = (rpcs1 & ~CS1_UAE) | ((rpbae << CS1_V_UAE) & CS1_UAE);
break;
case 025: /* RPCS3 */
if (PA & 1) break;
if ((access == WRITEB) && (PA & 1)) break;
rpcs3 = data & ~CS3_MBZ;
if ((data & CS1_IE) == 0) int_req = int_req & ~INT_RP;
else if (((rpcs1 & CS1_IE) == 0) && (rpcs1 & CS1_DONE))
@ -674,7 +686,7 @@ case 023: /* RPEC2 */
default: /* all others */
rper1[drv] = rper1[drv] | ER1_ILR;
break; } /* end switch */
update_rpcs (0, drv); /* update status */
update_rpcs (cs1f, drv); /* update status */
return SCPE_OK;
}
@ -692,11 +704,16 @@ if (uptr -> flags & UNIT_DIS) { /* nx unit? */
rpcs2 = rpcs2 | CS2_NED; /* set error flag */
update_rpcs (CS1_SC, drv); /* request intr */
return; }
if (((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) || /* not clear & err? */
((rpds[drv] & DS_RDY) == 0)) { /* not ready? */
rpcs2 = rpcs2 | CS2_PGE; /* set error flag */
update_rpcs (CS1_SC, drv); /* request intr */
return; }
if (fnc != FNC_DCLR) { /* not clear? */
if ((rpds[drv] & DS_ERR) || /* error or */
((rpds[drv] & DS_RDY) == 0)) { /* not ready? */
rpcs2 = rpcs2 | CS2_PGE; /* set error flag */
update_rpcs (CS1_SC, drv); /* request intr */
return; }
if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
update_rpcs (CS1_SC, drv); /* request intr */
return; } }
dtype = GET_DTYPE (uptr -> flags); /* get drive type */
rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */
dc = rpdc; /* assume seek, sch */
@ -771,11 +788,11 @@ return;
Unit must be attached - detach cancels in progress operations
*/
static unsigned int16 fill[RP_NUMWD] = { 0 };
t_stat rp_svc (UNIT *uptr)
{
int32 dtype, drv, err;
int32 pa, wc, awc, twc, da, fillc;
int32 i, dtype, drv, err;
int32 ba, wc, awc, twc, da, fc;
static uint16 dbuf[RP_MAXFR];
dtype = GET_DTYPE (uptr -> flags); /* get drive type */
drv = uptr - rp_dev.units; /* get drv number */
@ -785,73 +802,71 @@ switch (uptr -> FUNC) { /* case on function */
case FNC_OFFSET: /* offset */
rpds[drv] = rpds[drv] | DS_OF | DS_ATA; /* set offset, attention */
update_rpcs (CS1_SC, drv);
return SCPE_OK;
break;
case FNC_RETURN: /* return to centerline */
rpds[drv] = (rpds[drv] & ~DS_OF) | DS_ATA; /* clear offset, set attn */
update_rpcs (CS1_SC, drv);
return SCPE_OK;
break;
case FNC_UNLOAD: /* unload */
rp_detach (uptr); /* detach unit */
return SCPE_OK;
break;
case FNC_RECAL: /* recalibrate */
case FNC_SEARCH: /* search */
case FNC_SEEK: /* seek */
rpds[drv] = rpds[drv] | DS_ATA; /* set attention */
update_rpcs (CS1_SC, drv);
return SCPE_OK;
break;
case FNC_WRITE: /* write */
if (uptr -> flags & UNIT_WLK) { /* write locked? */
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
return SCPE_OK; }
break; }
case FNC_WCHK: /* write check */
case FNC_READ: /* read */
pa = ((rpbae << 16) | rpba) >> 1; /* get mem addr */
ba = (rpbae << 16) | rpba; /* get byte addr */
da = GET_DA (rpdc, rpda, dtype) * RP_NUMWD; /* get disk addr */
twc = 0200000 - rpwc; /* get true wc */
if (((t_addr) (pa + twc)) > (MEMSIZE / 2)) { /* mem overrun? */
rpcs2 = rpcs2 | CS2_NEM;
wc = ((MEMSIZE / 2) - pa);
if (wc < 0) { /* abort transfer? */
update_rpcs (CS1_DONE, drv); /* set done */
return SCPE_OK; } }
else wc = twc;
if ((da + twc) > drv_tab[dtype].size) { /* disk overrun? */
wc = 0200000 - rpwc; /* get true wc */
if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */
rper1[drv] = rper1[drv] | ER1_AOE;
if (wc > (drv_tab[dtype].size - da))
wc = drv_tab[dtype].size - da; }
err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET);
if (uptr -> FUNC == FNC_WRITE) { /* write? */
for (twc = 0; twc < wc; twc++) {
if (!ADDR_IS_MEM (ba)) { /* nx memory? */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
break; }
dbuf[twc] = M[ba >> 1]; /* write to disk */
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; }
if (fc = twc & (RP_NUMWD - 1)) { /* fill? */
fc = RP_NUMWD - fc;
for (i = 0; i < fc; i++) dbuf[twc + i] = 0; }
fxwrite (dbuf, sizeof (uint16), twc + fc, uptr -> fileref);
err = ferror (uptr -> fileref);
} /* end if */
else { /* read, wchk */
awc = fread (dbuf, sizeof (uint16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
for ( ; awc < wc; awc++) dbuf[awc] = 0;
for (twc = 0; twc < wc; twc++) {
if (!ADDR_IS_MEM (ba)) { /* nx memory? */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
break; }
if (uptr -> FUNC == FNC_READ) M[ba >> 1] = dbuf[twc];
else if (M[ba >> 1] != dbuf[twc]) {
rpcs2 = rpcs2 | CS2_WCE; /* set error */
break; }
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; }
} /* end else */
if ((uptr -> FUNC == FNC_READ) && (err == 0)) { /* read? */
awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref);
for ( ; awc < wc; awc++) M[pa + awc] = 0;
err = ferror (uptr -> fileref); }
if ((uptr -> FUNC == FNC_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
if ((err == 0) && (fillc = (wc & (RP_NUMWD - 1)))) {
fxwrite (fill, sizeof (int16), fillc, uptr -> fileref);
err = ferror (uptr -> fileref); } }
if ((uptr -> FUNC == FNC_WCHK) && (err == 0)) { /* wcheck? */
twc = wc; /* xfer length */
for (wc = 0; (err == 0) && (wc < twc); wc++) {
awc = fxread (&rpdb, sizeof (int16), 1, uptr -> fileref);
if (awc == 0) rpdb = 0;
if (rpdb != M[pa + wc]) {
rpcs2 = rpcs2 | CS2_WCE;
break; } }
err = ferror (uptr -> fileref); }
rpwc = (rpwc + wc) & 0177777; /* final word count */
pa = (pa + wc) << 1; /* final byte addr */
rpba = (pa & 0177777) & ~BA_MBZ; /* lower 16b */
rpbae = (pa >> 16) & ~AE_MBZ; /* upper 6b */
rpwc = (rpwc + twc) & 0177777; /* final word count */
rpba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */
rpbae = (ba >> 16) & ~AE_MBZ; /* upper 6b */
rpcs1 = (rpcs1 & ~ CS1_UAE) | ((rpbae << CS1_V_UAE) & CS1_UAE);
da = da + wc + (RP_NUMWD - 1);
da = da + twc + (RP_NUMWD - 1);
if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST;
da = da / RP_NUMWD;
rpda = da % drv_tab[dtype].sect;
@ -866,7 +881,7 @@ case FNC_READ: /* read */
clearerr (uptr -> fileref);
return SCPE_IOERR; }
update_rpcs (CS1_DONE, drv); /* set done */
return SCPE_OK; } /* end case function */
break; } /* end case function */
return SCPE_OK;
}
@ -883,7 +898,7 @@ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0;
else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM;
if (rp_unit[drv].flags & UNIT_ATT) rpds[drv] = rpds[drv] | DS_MOL;
else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY);
if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR;
if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA;
else rpds[drv] = rpds[drv] & ~DS_ERR;
rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ)) | CS1_DVA | flag;
@ -1016,7 +1031,7 @@ static const int32 boot_rom[] = {
0005002, /* clr R2 */
0005003, /* clr R3 */
0005004, /* clr R4 */
0012705, 0042120, /* mov #"DP, r5 */
0012705, 0050104, /* mov #"DP, r5 */
0105711, /* tstb (R1) */
0100376, /* bpl .-2 */
0105011, /* clrb (R1) */

View file

@ -1,6 +1,6 @@
/* pdp11_rx.c: RX11/RX01 floppy disk simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,8 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rx RX11 disk controller
rx RX11/RX01 floppy disk
26-Apr-01 RMS Added device enable/disable support
13-Apr-01 RMS Revised for register arrays
15-Feb-01 RMS Corrected bootstrap string
14-Apr-99 RMS Changed t_addr to unsigned
An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.
@ -84,7 +87,7 @@
#define TRACK u3 /* current track */
#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY
extern int32 int_req;
extern int32 int_req, dev_enb;
int32 rx_csr = 0; /* control/status */
int32 rx_dbr = 0; /* data buffer */
int32 rx_esr = 0; /* error status */
@ -96,13 +99,11 @@ int32 rx_stopioe = 1; /* stop on error */
int32 rx_cwait = 100; /* command time */
int32 rx_swait = 10; /* seek, per track */
int32 rx_xwait = 1; /* tr set time */
unsigned int8 buf[RX_NUMBY] = { 0 }; /* sector buffer */
unsigned int8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */
int32 bptr = 0; /* buffer pointer */
t_stat rx_svc (UNIT *uptr);
t_stat rx_reset (DEVICE *dptr);
t_stat rx_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* RX11 data structures
@ -138,7 +139,8 @@ REG rx_reg[] = {
{ FLDATA (FLG0, rx_unit[0].flags, UNIT_V_WLK), REG_HRO },
{ FLDATA (FLG1, rx_unit[1].flags, UNIT_V_WLK), REG_HRO },
{ FLDATA (STOP_IOE, rx_stopioe, 0) },
{ BRDATA (**BUF, buf, 8, 8, RX_NUMBY), REG_HRO },
{ BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RX), REG_HRO },
{ NULL } };
MTAB rx_mod[] = {
@ -250,10 +252,10 @@ case 1: /* RXDB */
IDLE Should never get here, treat as unknown command
RWDS Just transferred sector, wait for track, set tr
RWDT Just transferred track, do read or write, finish command
FILL copy ir to buf[bptr], advance ptr
FILL copy ir to rx_buf[bptr], advance ptr
if bptr > max, finish command, else set tr
EMPTY if bptr > max, finish command, else
copy buf[bptr] to ir, advance ptr, set tr
copy rx_buf[bptr] to ir, advance ptr, set tr
CMD_COMPLETE copy requested data to ir, finish command
INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
@ -276,12 +278,12 @@ case IDLE: /* idle */
break;
case EMPTY: /* empty buffer */
if (bptr >= RX_NUMBY) rx_done (rx_esr, 0); /* done all? */
else { rx_dbr = buf[bptr]; /* get next */
else { rx_dbr = rx_buf[bptr]; /* get next */
bptr = bptr + 1;
rx_csr = rx_csr | RXCS_TR; } /* set xfer */
break;
case FILL: /* fill buffer */
buf[bptr] = rx_dbr; /* write next */
rx_buf[bptr] = rx_dbr; /* write next */
bptr = bptr + 1;
if (bptr < RX_NUMBY) rx_csr = rx_csr | RXCS_TR; /* if more, set xfer */
else rx_done (rx_esr, 0); /* else done */
@ -308,13 +310,13 @@ case RWDT: /* wait for track */
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
if (func == RXCS_READ) { /* read? */
for (i = 0; i < RX_NUMBY; i++)
buf[i] = *(((int8 *) uptr -> filebuf) + da + i); }
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); }
else { if (uptr -> flags & UNIT_WLK) { /* write and locked? */
rx_esr = rx_esr | RXES_WLK; /* flag error */
rx_done (rx_esr, 0100); /* done, error */
break; }
for (i = 0; i < RX_NUMBY; i++) /* write */
*(((int8 *) uptr -> filebuf) + da + i) = buf[i];
*(((int8 *) uptr -> filebuf) + da + i) = rx_buf[i];
da = da + RX_NUMBY;
if (da > uptr -> hwmark) uptr -> hwmark = da; }
rx_done (rx_esr, 0); /* done */
@ -332,7 +334,7 @@ case INIT_COMPLETE: /* init complete */
break; }
da = CALC_DA (1, 1); /* track 1, sector 1 */
for (i = 0; i < RX_NUMBY; i++) /* read sector */
buf[i] = *(((int8 *) uptr -> filebuf) + da + i);
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i);
rx_done (rx_esr | RXES_ID | RXES_DRDY, 0); /* set done */
if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;
break; } /* end case state */
@ -363,11 +365,12 @@ t_stat rx_reset (DEVICE *dptr)
{
rx_csr = rx_dbr = 0; /* clear regs */
rx_esr = rx_ecode = 0; /* clear error */
rx_state = INIT_COMPLETE; /* set state */
int_req = int_req & ~INT_RX; /* clear int req */
sim_cancel (&rx_unit[1]); /* cancel drive 1 */
sim_activate (&rx_unit[0], /* start drive 0 */
rx_swait * abs (1 - rx_unit[0].TRACK));
if (rx_unit[0].flags & UNIT_BUF) { /* attached? */
rx_state = INIT_COMPLETE; /* yes, sched init */
sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK)); }
else rx_done (rx_esr | RXES_ID, 0010); /* no, error */
return SCPE_OK;
}
@ -408,7 +411,7 @@ static const int32 boot_rom[] = {
0005002, /* CLR R2 */
0005003, /* CLR R3 */
0005004, /* CLR R4 */
0012705, 0062170, /* MOV #"DX, R5 */
0012705, 0054104, /* MOV #"DX, R5 */
0005007 /* CLR R7 */
};
@ -416,7 +419,7 @@ t_stat rx_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
extern unsigned short *M;
extern uint16 *M;
for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR;

View file

@ -1,6 +1,6 @@
/* pdp11_stddev.c: PDP-11 standard I/O devices simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,12 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ptr paper tape reader
ptp paper tape punch
tti terminal input
tto terminal output
clk line frequency clock
ptr,ptp PC11 paper tape reader/punch
tti,tto DL11 terminal input/output
clk KW11L line frequency clock
05-Mar-01 RMS Added clock calibration support
30-Oct-00 RMS Standardized register order
25-Jun-98 RMS Fixed bugs in paper tape error handling
*/
@ -54,6 +53,7 @@ int32 ptp_stopioe = 0; /* stop on error */
int32 tti_csr = 0; /* control/status */
int32 tto_csr = 0; /* control/status */
int32 clk_csr = 0; /* control/status */
int32 clk_tps = 60; /* ticks/second */
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat tti_svc (UNIT *uptr);
@ -68,10 +68,9 @@ t_stat ptr_attach (UNIT *uptr, char *ptr);
t_stat ptr_detach (UNIT *uptr);
t_stat ptp_attach (UNIT *uptr, char *ptr);
t_stat ptp_detach (UNIT *uptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
extern int32 sim_rtc_calb (int32 ticksper);
/* PTR data structures
@ -197,6 +196,7 @@ REG clk_reg[] = {
{ FLDATA (DONE, clk_csr, CSR_V_DONE) },
{ FLDATA (IE, clk_csr, CSR_V_IE) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
{ NULL } };
DEVICE clk_dev = {
@ -255,7 +255,7 @@ case 012: /* tto csr */
case 013: /* tto buf */
*data = tto_unit.buf;
return SCPE_OK; } /* end switch PA */
return SCPE_NXM; /* can't get here */
return SCPE_NXM;
}
t_stat std_wr (int32 data, int32 PA, int32 access)
@ -265,7 +265,6 @@ case 03: /* clk csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0) int_req = int_req & ~INT_CLK;
clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW);
sim_activate (&clk_unit, clk_unit.wait);
return SCPE_OK;
case 04: /* ptr csr */
if (PA & 1) return SCPE_OK;
@ -319,7 +318,7 @@ case 013: /* tto buf */
int_req = int_req & ~INT_TTO;
sim_activate (&tto_unit, tto_unit.wait);
return SCPE_OK; } /* end switch PA */
return SCPE_NXM; /* can't get here */
return SCPE_NXM;
}
/* Paper tape reader routines
@ -489,7 +488,7 @@ return SCPE_OK;
t_stat clk_svc (UNIT *uptr)
{
if (clk_csr & CSR_IE) int_req = int_req | INT_CLK;
sim_activate (&clk_unit, clk_unit.wait); /* reactivate unit */
sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate unit */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp11_sys.c: PDP-11 simulator interface
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
05-Apr-01 RMS Added support for TS11/TSV05
14-Mar-01 RMS Revised load/dump interface (again)
11-Feb-01 RMS Added DECtape support
30-Oct-00 RMS Added support for examine to file
14-Apr-99 RMS Changed t_addr to unsigned
09-Nov-98 RMS Fixed assignments of ROR/ROL (John Wilson).
@ -41,10 +44,12 @@ extern DEVICE tti_dev, tto_dev;
extern DEVICE lpt_dev, clk_dev;
extern DEVICE rk_dev, rx_dev;
extern DEVICE rl_dev, rp_dev;
extern DEVICE tm_dev;
extern DEVICE dt_dev, tm_dev;
extern DEVICE ts_dev;
/* extern DEVICE hk_dev; */
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern unsigned int16 *M;
extern uint16 *M;
extern int32 saved_PC;
/* SCP data structures and interface routines
@ -63,10 +68,16 @@ REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = { &cpu_dev,
&ptr_dev, &ptp_dev, &tti_dev, &tto_dev,
&lpt_dev, &clk_dev, &rk_dev, &rl_dev,
&rp_dev, &rx_dev, &tm_dev, NULL };
DEVICE *sim_devices[] = {
&cpu_dev,
&ptr_dev, &ptp_dev,
&tti_dev, &tto_dev,
&lpt_dev, &clk_dev,
&rk_dev, /* &hk_dev, */
&rl_dev, &rp_dev,
&rx_dev, &dt_dev,
&tm_dev, &ts_dev,
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
@ -112,7 +123,7 @@ const char *sim_stop_messages[] = {
the PC at which to start the program.
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 csum, count, state, i;
t_addr origin;

1138
pdp11_tc.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* PDP-11 magnetic tape simulator
/* pdp11_tm.c: PDP-11 magnetic tape simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
tm TM11/TU10 magtape
26-Apr-01 RMS Added device enable/disable support
18-Apr-01 RMS Changed to rewind tape before boot
14-Apr-99 RMS Changed t_addr to unsigned
04-Oct-98 RMS V2.4 magtape format
10-May-98 RMS Fixed bug with non-zero unit operation (from Steven Schultz)
@ -123,8 +125,8 @@
STA_DLT | STA_EOT | STA_RLE | STA_BAD | STA_NXM)
/* set error */
extern unsigned int16 *M; /* memory */
extern int32 int_req;
extern uint16 *M; /* memory */
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 tm_sta = 0; /* status register */
int32 tm_cmd = 0; /* command register */
@ -142,11 +144,6 @@ void tm_go (UNIT *uptr);
int32 tm_updcsta (UNIT *uptr);
void tm_set_done (void);
t_stat tm_vlock (UNIT *uptr, int32 val);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* MT data structures
@ -210,6 +207,7 @@ REG tm_reg[] = {
REG_HRO },
{ GRDATA (FLG7, tm_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (*DEVENB, dev_enb, INT_V_TM), REG_HRO },
{ NULL } };
MTAB tm_mod[] = {
@ -340,12 +338,12 @@ return;
t_stat tm_svc (UNIT *uptr)
{
int f, i, p, err;
int32 f, i, p, err;
t_addr xma;
t_stat rval;
t_mtrlnt tbc, cbc;
unsigned int16 c;
unsigned int8 dbuf[DBSIZE];
uint16 c;
static uint8 dbuf[DBSIZE];
static t_mtrlnt bceof = { 0 };
if (uptr -> USTAT & STA_REW) { /* rewind? */
@ -523,6 +521,7 @@ t_stat tm_reset (DEVICE *dptr)
int32 u;
UNIT *uptr;
if (dev_enb & INT_TM) dev_enb = dev_enb & ~INT_TS; /* TM or TS */
tm_cmd = MTC_DONE; /* set done */
tm_bc = tm_ca = tm_db = tm_sta = 0;
int_req = int_req & ~INT_TM; /* clear interrupt */
@ -635,6 +634,7 @@ int32 i;
extern int32 saved_PC;
extern int32 sim_switches;
tm_unit[unitno].pos = 0;
if (sim_switches & SWMASK ('O')) {
for (i = 0; i < BOOT1_LEN; i++)
M[(BOOT_START >> 1) + i] = boot1_rom[i]; }

901
pdp11_ts.c Normal file
View file

@ -0,0 +1,901 @@
/* pdp11_ts.c: TS11/TSV05 magnetic tape simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ts TS11/TSV05 magtape
Magnetic tapes are represented as a series of variable 8b records
of the form:
32b record length in bytes - exact number
byte 0
byte 1
:
byte n-2
byte n-1
32b record length in bytes - exact number
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.
*/
#include "pdp11_defs.h"
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define DBSIZE (1 << 16) /* data buffer */
/* TSBA/TSDB - 17772520: base address/data buffer register
read: most recent memory address
write word: initiate command
write byte: diagnostic use
*/
/* TSSR - 17772522: subsystem status register
TSDBX - 17772523: extended address register
read: return status
write word: initialize
write byte: if odd, set extended packet address register
*/
#define TSSR_SC 0100000 /* special condition */
#define TSSR_RMR 0010000 /* reg mod refused */
#define TSSR_NXM 0004000 /* nxm */
#define TSSR_NBA 0002000 /* need buf addr */
#define TSSR_V_EMA 8 /* mem addr<17:16> */
#define TSSR_EMA 0001400
#define TSSR_SSR 0000200 /* subsystem ready */
#define TSSR_OFL 0000100 /* offline */
#define TSSR_V_TC 1 /* term class */
#define TSSR_TC (07 << TSSR_V_TC)
#define TC0 (0 << TSSR_V_TC) /* ok */
#define TC1 (1 << TSSR_V_TC) /* attention */
#define TC2 (2 << TSSR_V_TC) /* status alert */
#define TC3 (3 << TSSR_V_TC) /* func reject */
#define TC4 (4 << TSSR_V_TC) /* retry, moved */
#define TC5 (5 << TSSR_V_TC) /* retry */
#define TC6 (6 << TSSR_V_TC) /* pos lost */
#define TC7 (7 << TSSR_V_TC) /* fatal err */
#define TSSR_MBZ 0060060
#define TSDBX_M_XA 017 /* ext addr */
#define TSDBX_BOOT 0000200 /* boot */
/* Command packet offsets */
#define CMD_PLNT 4 /* cmd pkt length */
#define cmdhdr tscmdp[0] /* header */
#define cmdadl tscmdp[1] /* address low */
#define cmdadh tscmdp[2] /* address high */
#define cmdlnt tscmdp[3] /* length */
/* Command packet header */
#define CMD_ACK 0100000 /* acknowledge */
#define CMD_CVC 0040000 /* clear vol chk */
#define CMD_OPP 0020000 /* opposite */
#define CMD_SWP 0010000 /* swap bytes */
#define CMD_V_MODE 8 /* mode */
#define CMD_M_MODE 017
#define CMD_IE 0000200 /* int enable */
#define CMD_V_FNC 0 /* function */
#define CMD_M_FNC 037 /* function */
#define CMD_N_FNC (CMD_M_FNC + 1)
#define FNC_READ 001 /* read */
#define FNC_WCHR 004 /* write char */
#define FNC_WRIT 005 /* write */
#define FNC_WSSM 006 /* write mem */
#define FNC_POS 010 /* position */
#define FNC_FMT 011 /* format */
#define FNC_CTL 012 /* control */
#define FNC_INIT 013 /* init */
#define FNC_GSTA 017 /* get status */
#define CMD_MBZ 0000140
#define GET_FNC(x) (((x) >> CMD_V_FNC) & CMD_M_FNC)
#define GET_MOD(x) (((x) >> CMD_V_MODE) & CMD_M_MODE)
/* Function test flags */
#define FLG_MO 001 /* motion */
#define FLG_WR 002 /* write */
#define FLG_AD 004 /* addr mem */
/* Message packet offsets */
#define MSG_PLNT 8 /* packet length */
#define msghdr tsmsgp[0] /* header */
#define msglnt tsmsgp[1] /* length */
#define msgrfc tsmsgp[2] /* residual frame */
#define msgxs0 tsmsgp[3] /* ext status 0 */
#define msgxs1 tsmsgp[4] /* ext status 1 */
#define msgxs2 tsmsgp[5] /* ext status 2 */
#define msgxs3 tsmsgp[6] /* ext status 3 */
#define msgxs4 tsmsgp[7] /* ext status 4 */
/* Message packet header */
#define MSG_ACK 0100000 /* acknowledge */
#define MSG_MATN 0000000 /* attention */
#define MSG_MILL 0000400 /* illegal */
#define MSG_MNEF 0001000 /* non exec fnc */
#define MSG_CEND 0000020 /* end */
#define MSG_CFAIL 0000021 /* fail */
#define MSG_CERR 0000022 /* error */
#define MSG_CATN 0000023 /* attention */
/* Extended status register 0 */
#define XS0_TMK 0100000 /* tape mark */
#define XS0_RLS 0040000 /* rec lnt short */
#define XS0_LET 0020000 /* log end tape */
#define XS0_RLL 0010000 /* rec lnt long */
#define XS0_WLE 0004000 /* write lock err */
#define XS0_NEF 0002000 /* non exec fnc */
#define XS0_ILC 0001000 /* illegal cmd */
#define XS0_ILA 0000400 /* illegal addr */
#define XS0_MOT 0000200 /* motion */
#define XS0_ONL 0000100 /* online */
#define XS0_IE 0000040 /* int enb */
#define XS0_VCK 0000020 /* volume check */
#define XS0_PET 0000010 /* 1600 bpi */
#define XS0_WLK 0000004 /* write lock */
#define XS0_BOT 0000002 /* BOT */
#define XS0_EOT 0000001 /* EOT */
#define XS0_ALLERR 0177600 /* all errors */
/* Extended status register 1 - none of these errors are ever set */
/* Extended status register 2 - none of these errors are ever set */
/* Extended status register 3 */
#define XS3_XTF 0000200 /* ext features */
#define XS3_OPI 0000100 /* op incomplete */
#define XS3_REV 0000040 /* reverse */
#define XS3_RIB 0000001 /* reverse to BOT */
/* Extended status register 4 - none of these errors are ever set */
/* Write characteristics packet offsets */
#define WCH_PLNT 4 /* packet length */
#define wchadl tswchp[0] /* address low */
#define wchadh tswchp[1] /* address high */
#define wchlnt tswchp[2] /* length */
#define wchopt tswchp[3] /* options */
/* Write characteristics options */
#define WCH_ESS 0000200 /* stop dbl tmk */
#define WCH_ENB 0000100 /* BOT = tmk */
#define WCH_EAI 0000040 /* enb attn int */
#define WCH_ERI 0000020 /* enb mrls int */
#define MAX(a,b) (((a) >= (b))? (a): (b))
#define READ_BYTE(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377)
#define WRITE_BYTE(d,p) M[(p) >> 1] = (p & 1)? \
((M[(p) >> 1] & 0377) | ((d) << 8)): \
((M[(p) >> 1] & ~0377) | (d))
extern uint16 *M; /* memory */
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 tssr = 0; /* status register */
int32 tsba = 0; /* mem addr */
int32 tsdbx = 0; /* data buf ext */
int32 tscmdp[CMD_PLNT] = { 0 }; /* command packet */
int32 tsmsgp[MSG_PLNT] = { 0 }; /* message packet */
int32 tswchp[WCH_PLNT] = { 0 }; /* wr char packet */
int32 ts_ownc = 0; /* tape owns cmd */
int32 ts_ownm = 0; /* tape owns msg */
int32 ts_qatn = 0; /* queued attn */
int32 ts_bcmd = 0; /* boot cmd */
int32 ts_time = 10; /* record latency */
int32 ts_log = 0;
static uint8 dbuf[DBSIZE];
t_stat ts_svc (UNIT *uptr);
t_stat ts_reset (DEVICE *dptr);
t_stat ts_attach (UNIT *uptr, char *cptr);
t_stat ts_detach (UNIT *uptr);
t_stat ts_boot (int32 unitno);
int32 ts_updtssr (int32 t);
int32 ts_updxs0 (int32 t);
void ts_cmpendcmd (int32 s0, int32 s1);
void ts_endcmd (int32 ssf, int32 xs0f, int32 msg);
/* TS data structures
ts_dev TS device descriptor
ts_unit TS unit list
ts_reg TS register list
ts_mod TS modifier list
*/
UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) };
REG ts_reg[] = {
{ ORDATA (TSSR, tssr, 16) },
{ ORDATA (TSBA, tsba, 22) },
{ ORDATA (TSDBX, tsdbx, 8) },
{ ORDATA (CHDR, cmdhdr, 16) },
{ ORDATA (CADL, cmdadl, 16) },
{ ORDATA (CADH, cmdadh, 16) },
{ ORDATA (CLNT, cmdlnt, 16) },
{ ORDATA (MHDR, msghdr, 16) },
{ ORDATA (MRFC, msgrfc, 16) },
{ ORDATA (MXS0, msgxs0, 16) },
{ ORDATA (MXS1, msgxs1, 16) },
{ ORDATA (MXS2, msgxs2, 16) },
{ ORDATA (MXS3, msgxs3, 16) },
{ ORDATA (MSX4, msgxs4, 16) },
{ ORDATA (WADL, wchadl, 16) },
{ ORDATA (WADH, wchadh, 16) },
{ ORDATA (WLNT, wchlnt, 16) },
{ ORDATA (WOPT, wchopt, 16) },
{ FLDATA (ATTN, ts_qatn, 0) },
{ FLDATA (BOOT, ts_bcmd, 0) },
{ FLDATA (OWNC, ts_ownc, 0) },
{ FLDATA (OWNM, ts_ownm, 0) },
{ DRDATA (TIME, ts_time, 24), PV_LEFT + REG_NZ },
{ DRDATA (POS, ts_unit.pos, 31), PV_LEFT + REG_RO },
{ FLDATA (WLK, ts_unit.flags, UNIT_V_WLK), REG_HRO },
{ FLDATA (LOG, ts_log, 0), REG_HIDDEN },
{ FLDATA (*DEVENB, dev_enb, INT_V_TS), REG_HRO },
{ NULL } };
MTAB ts_mod[] = {
{ UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ 0 } };
DEVICE ts_dev = {
"TS", &ts_unit, ts_reg, ts_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ts_reset,
&ts_boot, &ts_attach, &ts_detach };
/* I/O dispatch routine, I/O addresses 17772520 - 17772522
17772520 TSBA read/write
17772522 TSSR read/write
*/
t_stat ts_rd (int32 *data, int32 PA, int32 access)
{
switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TSBA */
*data = tsba & DMASK; /* low 16b of ba */
break;
case 1: /* TSSR */
*data = tssr = ts_updtssr (tssr); /* update tssr */
break; }
return SCPE_OK;
}
t_stat ts_wr (int32 data, int32 PA, int32 access)
{
int32 i;
switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TSDB */
if ((tssr & TSSR_SSR) == 0) { /* ready? */
tssr = tssr | TSSR_RMR; /* no, refuse */
break; }
tsba = ((tsdbx & TSDBX_M_XA) << 18) | /* form pkt addr */
((data & 03) << 16) | (data & 0177774);
tsdbx = 0; /* clr tsdbx */
tssr = ts_updtssr (tssr & TSSR_NBA); /* clr ssr, err */
msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLERR); /* clr err, upd xs0 */
msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */
int_req = int_req & ~INT_TS; /* clr int req */
for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */
if (ADDR_IS_MEM (tsba)) tscmdp[i] = M[(tsba >> 1)];
else { ts_endcmd (TSSR_NXM + TC3, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);
return SCPE_OK; }
tsba = tsba + 2; } /* incr tsba */
ts_ownc = ts_ownm = 1; /* tape owns all */
sim_activate (&ts_unit, ts_time); /* activate */
break;
case 1: /* TSSR */
if (PA & 1) { /* TSDBX */
if (tssr & TSSR_SSR) { /* ready? */
tsdbx = data; /* save */
if (data & TSDBX_BOOT) {
ts_bcmd = 1;
sim_activate (&ts_unit, ts_time); } }
else tssr = tssr | TSSR_RMR; } /* no, err */
else if (access == WRITE) ts_reset (&ts_dev); /* reset */
break; }
return SCPE_OK;
}
/* Tape motion routines */
#define XTC(x,t) (((unsigned) (x) << 16) | (t))
#define GET_X(x) (((x) >> 16) & 0177777)
#define GET_T(x) ((x) & 0177777)
int32 ts_rdlntf (UNIT *uptr, t_mtrlnt *tbc)
{
fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* set pos */
fxread (tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read rec lnt */
if (ferror (uptr -> fileref)) return (XTC (XS0_EOT | XS0_RLS, TC2));
if (feof (uptr -> fileref)) return (XTC (XS0_TMK | XS0_RLS, TC2));
return 0;
}
int32 ts_spacef (UNIT *uptr, int32 fc, t_bool upd)
{
int32 st;
t_mtrlnt tbc;
do { if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update pos */
if (tbc == 0) return (XTC (XS0_TMK | XS0_RLS, TC2));
uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + sizeof (t_mtrlnt);
fc = (fc - 1) & DMASK; /* decr wc */
if (upd) msgrfc = fc; }
while (fc != 0);
return 0;
}
int32 ts_skipf (UNIT *uptr, int32 fc)
{
int32 tc;
t_mtrlnt prvp;
t_bool tmkprv = FALSE;
msgrfc = fc;
if ((uptr -> pos == 0) && (wchopt & WCH_ENB)) tmkprv = TRUE;
do { prvp = uptr -> pos; /* save cur pos */
tc = ts_spacef (uptr, 0, FALSE); /* space fwd */
if (GET_X (tc) & XS0_TMK) { /* tape mark? */
msgrfc = (msgrfc - 1) & DMASK; /* decr count */
if (tmkprv && (wchopt & WCH_ESS) &&
(uptr -> pos - prvp == sizeof (t_mtrlnt)))
return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2));
tmkprv = TRUE; }
else { if (tc) return tc; /* other err? */
tmkprv = FALSE; } }
while (msgrfc != 0);
return 0;
}
int32 ts_rdlntr (UNIT *uptr, t_mtrlnt *tbc)
{
msgxs3 = msgxs3 | XS3_REV; /* set rev op */
fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), SEEK_SET);
fxread (tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
if (ferror (uptr -> fileref) || /* error or eof? */
feof (uptr -> fileref)) {
msgxs3 = msgxs3 | XS3_OPI; /* fatal err */
return (XTC (XS0_RLS, TC6)); }
return 0;
}
int32 ts_spacer (UNIT *uptr, int32 fc, t_bool upd)
{
int32 st;
t_mtrlnt tbc;
do { if (uptr -> pos == 0) break; /* BOT? */
if (st = ts_rdlntr (uptr, &tbc)) return st; /* read rec lnt */
uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); /* update pos */
if (tbc == 0) return (XTC (XS0_TMK | XS0_RLS, TC2));
uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - sizeof (t_mtrlnt);
fc = (fc - 1) & DMASK; /* decr wc */
if (upd) msgrfc = fc; }
while (fc != 0);
if (uptr -> pos == 0) {
msgxs3 = msgxs3 | XS3_RIB;
return (XTC (XS0_BOT | (fc? XS0_RLS: 0), TC2)); }
return 0;
}
int32 ts_skipr (UNIT *uptr, int32 fc)
{
int32 tc;
t_mtrlnt prvp;
t_bool tmkprv = FALSE;
msgrfc = fc;
do { tc = ts_spacer (uptr, 0, FALSE); /* space rev */
if (GET_X (tc) & XS0_TMK) { /* tape mark? */
msgrfc = (msgrfc - 1) & DMASK; /* decr wc */
if (tmkprv && (wchopt & WCH_ESS) &&
(prvp - uptr -> pos == sizeof (t_mtrlnt)))
return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2));
tmkprv = TRUE; }
else { if (tc) return tc; /* other err? */
tmkprv = FALSE; } }
while (msgrfc != 0);
return 0;
}
int32 ts_readf (UNIT *uptr, int32 fc)
{
int32 i, st;
t_mtrlnt tbc, wbc;
t_addr wa;
msgrfc = fc;
if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */
if (tbc == 0) { /* tape mark? */
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update pos */
return (XTC (XS0_TMK | XS0_RLS, TC2)); }
if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl; /* buf addr */
tbc = MTRL (tbc); /* ignore err flag */
wbc = (tbc > DBSIZE)? DBSIZE: tbc; /* cap rec size */
wbc = (wbc > fc)? fc: wbc; /* cap buf size */
i = fxread (dbuf, sizeof (uint8), wbc, uptr -> fileref); /* read record */
if (ferror (uptr -> fileref)) return XTC (XS0_EOT | XS0_RLS, TC2);
for ( ; i < wbc; i++) dbuf[i] = 0; /* fill with 0's */
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt));
for (i = 0; i < wbc; i++) { /* copy buffer */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (ADDR_IS_MEM (wa)) WRITE_BYTE (dbuf[i], wa); /* nxm? */
else { tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); }
tsba = tsba + 1;
msgrfc = (msgrfc - 1) & DMASK; }
if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */
if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */
return 0;
}
int32 ts_readr (UNIT *uptr, int32 fc)
{
int32 i, st;
t_mtrlnt tbc, wbc;
t_addr wa;
msgrfc = fc;
if (uptr -> pos == 0) { /* BOT? */
msgxs3 = msgxs3 | XS3_RIB; /* nothing to do */
return (XTC (XS0_BOT | XS0_RLS, TC2)); }
if (st = ts_rdlntr (uptr, &tbc)) return st; /* read rec lnt */
if (tbc == 0) { /* tape mark? */
uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); /* update pos */
return XTC (XS0_TMK | XS0_RLS, TC2); }
if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */
tbc = MTRL (tbc); /* ignore err flag */
wbc = (tbc > DBSIZE)? DBSIZE: tbc; /* cap rec size */
wbc = (wbc > fc)? fc: wbc; /* cap buf size */
fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) - wbc, SEEK_SET);
i = fxread (dbuf, sizeof (uint8), wbc, uptr -> fileref);
for ( ; i < wbc; i++) dbuf[i] = 0; /* fill with 0's */
if (ferror (uptr -> fileref)) { /* error? */
msgxs3 = msgxs3 | XS3_OPI;
return XTC (XS0_RLS, TC6); }
uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt));
for (i = wbc; i > 0; i--) { /* copy buffer */
tsba = tsba - 1;
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba;
if (ADDR_IS_MEM (wa)) WRITE_BYTE (dbuf[i - 1], wa);
else { tssr = ts_updtssr (tssr | TSSR_NXM);
return (XTC (XS0_RLS, TC4)); }
msgrfc = (msgrfc - 1) & DMASK; }
if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */
if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */
return 0;
}
int32 ts_write (UNIT *uptr, int32 fc)
{
int32 i;
t_addr wa;
msgrfc = fc;
if (fc == 0) fc = 0200000; /* byte count */
tsba = (cmdadh << 16) | cmdadl; /* buf addr */
for (i = 0; i < fc; i++) { /* copy mem to buf */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply opp */
if (ADDR_IS_MEM (wa)) dbuf[i] = READ_BYTE (wa); /* nxm? */
else { tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; }
tsba = tsba + 1; }
fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* position */
fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref);
fxwrite (dbuf, sizeof (uint8), fc, uptr -> fileref);
fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref);
uptr -> pos = uptr -> pos + ((fc + 1) & ~1) + (2 * sizeof (t_mtrlnt));
msgrfc = 0;
if (ferror (uptr -> fileref)) { /* error? */
msgxs3 = msgxs3 | XS3_OPI;
return TC6; }
return 0;
}
int32 ts_wtmk (UNIT *uptr)
{
t_mtrlnt bceof = 0;
fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* set pos */
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref);
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update position */
if (ferror (uptr -> fileref)) return TC6;
return XTC (XS0_TMK, TC0);
}
/* Unit service */
t_stat ts_svc (UNIT *uptr)
{
int32 i, fnc, mod, st0, st1;
static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */
0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */
5, 3, 5, 1, 0, 0, 0, 1, /* 10 - 17 */
0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */
0, 0, 0, 0, 0, 0, 0, 0 }; /* 30 - 37 */
static const int32 fnc_flg[CMD_N_FNC] = {
0, FLG_MO+FLG_AD, 0, 0, 0, FLG_MO+FLG_WR+FLG_AD, FLG_AD, 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 }; /* 30 - 37 */
if (ts_bcmd) { /* boot? */
ts_bcmd = 0; /* clear flag */
uptr -> pos = 0; /* rewind */
if (uptr -> flags & UNIT_ATT) { /* attached? */
cmdlnt = cmdadh = cmdadl = 0; /* defang rd */
ts_spacef (uptr, 1, FALSE); /* space fwd */
ts_readf (uptr, 512); /* read blk */
tssr = ts_updtssr (tssr | TSSR_SSR); }
else tssr = ts_updtssr (tssr | TSSR_SSR | TC3);
if (cmdhdr & CMD_IE) int_req = int_req | INT_TS;
return SCPE_OK; }
if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */
tssr = ts_updtssr (tssr | TSSR_SSR); /* set rdy, int */
if (cmdhdr & CMD_IE) int_req = int_req | INT_TS;
ts_ownc = ts_ownm = 0; /* CPU owns all */
return SCPE_OK; }
fnc = GET_FNC (cmdhdr); /* get fnc+mode */
mod = GET_MOD (cmdhdr);
if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */
ts_endcmd (TC3, 0, 0); /* error */
return SCPE_OK; }
if (ts_qatn && (wchopt & WCH_EAI)) { /* attn pending? */
ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn msg */
int_req = int_req | INT_TS; /* set interrupt */
ts_qatn = 0; /* not pending */
return SCPE_OK; }
if (cmdhdr & CMD_CVC) /* cvc? clr vck */
msgxs0 = msgxs0 & ~XS0_VCK;
if ((cmdhdr & CMD_MBZ) || (mod >= fnc_mod[fnc])) { /* test mbz */
ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL);
return SCPE_OK; }
if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!att)? */
((msgxs0 & XS0_VCK) || !(uptr -> flags & UNIT_ATT))) {
ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; }
if ((fnc_flg[fnc] & FLG_WR) && /* write? */
(uptr -> flags & UNIT_WLK)) { /* write lck? */
ts_endcmd (TC3, XS0_WLE | XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; }
if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */
((fnc == FNC_POS) && (mod & 1))) && /* space rev */
(uptr -> pos == 0)) { /* BOT? */
ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; }
if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & 0177700)) { /* buf addr > 22b? */
ts_endcmd (TC3, XS0_ILA, MSG_ACK | MSG_MILL | MSG_CFAIL);
return SCPE_OK; }
st0 = st1 = 0;
switch (fnc) { /* case on func */
case FNC_INIT: /* init */
uptr -> pos = 0; /* rewind */
case FNC_WSSM: /* write mem */
case FNC_GSTA: /* get status */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */
return SCPE_OK;
case FNC_WCHR: /* write char */
if ((cmdadh & 0177700) || (cmdadl & 1) || (cmdlnt < 6)) {
ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0);
break; }
tsba = (cmdadh << 16) | cmdadl;
for (i = 0; (i < WCH_PLNT) && (i < (cmdlnt / 2)); i++) {
if (ADDR_IS_MEM (cmdadl)) tswchp[i] = M[tsba >> 1];
else { ts_endcmd (TSSR_NBA | TSSR_NXM | TC3, 0, 0);
return SCPE_OK; }
tsba = tsba + 2; }
if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) ||
(wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0);
else { msgxs3 = msgxs3 | XS3_XTF | 1;
tssr = ts_updtssr (tssr & ~TSSR_NBA);
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); }
return SCPE_OK;
case FNC_CTL: /* control */
switch (mod) { /* case mode */
case 00: /* msg buf rls */
tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */
if (wchopt & WCH_ERI) int_req = int_req | INT_TS;
ts_ownc = 0; ts_ownm = 1; /* keep msg */
break;
case 01: /* clean */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */
break;
case 02: /* rewind and unload */
detach_unit (uptr); /* unload */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND);
break;
case 03: /* undefined */
ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL);
return SCPE_OK;
case 04: /* rewind */
ts_unit.pos = 0;
ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND);
break; }
break;
case FNC_READ: /* read */
switch (mod) { /* case mode */
case 00: /* fwd */
st0 = ts_readf (uptr, cmdlnt); /* read */
break;
case 01: /* back */
st0 = ts_readr (uptr, cmdlnt); /* read */
break;
case 02: /* reread fwd */
if (cmdhdr & CMD_OPP) { /* opposite? */
st0 = ts_readr (uptr, cmdlnt);
st1 = ts_spacef (uptr, 1, FALSE); }
else { st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_readf (uptr, cmdlnt); }
break;
case 03: /* reread back */
if (cmdhdr & CMD_OPP) { /* opposite */
st0 = ts_readf (uptr, cmdlnt);
st1 = ts_spacer (uptr, 1, FALSE); }
else { st0 = ts_spacef (uptr, 1, FALSE);
st1 = ts_readr (uptr, cmdlnt); }
break; }
ts_cmpendcmd (st0, st1);
break;
case FNC_WRIT: /* write */
switch (mod) { /* case mode */
case 00: /* write */
st0 = ts_write (uptr, cmdlnt);
break;
case 01: /* rewrite */
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_write (uptr, cmdlnt);
break; }
ts_cmpendcmd (st0, st1);
break;
case FNC_FMT: /* format */
switch (mod) { /* case mode */
case 00: /* write tmk */
st0 = ts_wtmk (uptr);
break;
case 01: /* erase */
break;
case 02: /* retry tmk */
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_wtmk (uptr);
break; }
ts_cmpendcmd (st0, st1);
break;
case FNC_POS:
switch (mod) { /* case mode */
case 00: /* space fwd */
st0 = ts_spacef (uptr, cmdadl, TRUE);
break;
case 01: /* space rev */
st0 = ts_spacer (uptr, cmdadl, TRUE);
break;
case 02: /* space ffwd */
st0 = ts_skipf (uptr, cmdadl);
break;
case 03: /* space frev */
st0 = ts_skipr (uptr, cmdadl);
break;
case 04: /* rewind */
ts_unit.pos = 0;
break; }
ts_cmpendcmd (st0, 0);
break; }
if (ts_log) printf ("Cmd=%o, mod=%o, buf=%o, lnt=%o, sta = %o, tc=%o, pos=%d\n",
fnc, mod, cmdadl, cmdlnt, msgxs0, (tssr & TSSR_TC) >> 1, ts_unit.pos);
return SCPE_OK;
}
/* Utility routines */
int32 ts_updtssr (int32 t)
{
t = (t & ~TSSR_EMA) | ((tsba >> (16 - TSSR_V_EMA)) & TSSR_EMA);
if (ts_unit.flags & UNIT_ATT) t = t & ~TSSR_OFL;
else t = t | TSSR_OFL;
return (t & ~TSSR_MBZ);
}
int32 ts_updxs0 (int32 t)
{
t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET;
if (ts_unit.flags & UNIT_ATT) {
t = t | XS0_ONL;
if (ts_unit.flags & UNIT_WLK) t = t | XS0_WLK;
if (ts_unit.pos == 0) t = (t | XS0_BOT) & ~XS0_EOT; }
else t = t & ~XS0_EOT;
if (cmdhdr & CMD_IE) t = t | XS0_IE;
return t;
}
void ts_cmpendcmd (int32 s0, int32 s1)
{
int32 xs0, ssr, tc;
static const int32 msg[8] = {
MSG_ACK | MSG_CEND, MSG_ACK | MSG_MATN | MSG_CATN,
MSG_ACK | MSG_CEND, MSG_ACK | MSG_CFAIL,
MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR,
MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR };
xs0 = GET_X (s0 | s1); /* or XS0 errs */
ssr = GET_T (s0 | s1) & ~TSSR_TC; /* or SSR errs */
tc = MAX (s0 & TSSR_TC, s1 & TSSR_TC); /* max term code */
ts_endcmd (ssr | tc, xs0, msg[tc]); /* end cmd */
return;
}
void ts_endcmd (int32 tc, int32 xs0, int32 msg)
{
int32 i;
msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */
if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */
msghdr = msg;
msglnt = wchlnt - 4; /* exclude hdr, bc */
tsba = (wchadh << 16) | wchadl;
for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++) {
if (ADDR_IS_MEM (tsba)) M[tsba >> 1] = tsmsgp[i];
else { tssr = tssr | TSSR_NXM;
tc = (tc & ~TSSR_TC) | TC4;
break; }
tsba = tsba + 2; } }
tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0));
if (cmdhdr & CMD_IE) int_req = int_req | INT_TS;
ts_ownm = 0; ts_ownc = 0;
return;
}
/* Device reset */
t_stat ts_reset (DEVICE *dptr)
{
int32 i;
if (dev_enb & INT_TS) dev_enb = dev_enb & ~INT_TM; /* TM or TS */
ts_unit.pos = 0;
tsba = tsdbx = 0;
ts_ownc = ts_ownm = 0;
ts_bcmd = 0;
ts_qatn = 0;
tssr = ts_updtssr (TSSR_NBA | TSSR_SSR);
for (i = 0; i < CMD_PLNT; i++) tscmdp[i] = 0;
for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0;
for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0;
msgxs0 = ts_updxs0 (XS0_VCK);
int_req = int_req & ~INT_TS;
return SCPE_OK;
}
/* Attach */
t_stat ts_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = attach_unit (uptr, cptr); /* attach unit */
if (r != SCPE_OK) return r; /* error? */
tssr = tssr & ~TSSR_OFL; /* clr offline */
if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) return r; /* attn msg? */
if (ts_ownm) { /* own msg buf? */
ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */
int_req = int_req | INT_TS; /* set interrupt */
ts_qatn = 0; } /* don't queue */
else ts_qatn = 1; /* else queue */
return r;
}
/* Detach routine */
t_stat ts_detach (UNIT* uptr)
{
t_stat r;
r = detach_unit (uptr); /* detach unit */
if (r != SCPE_OK) return r; /* error? */
tssr = tssr | TSSR_OFL; /* set offline */
if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) return r; /* attn msg? */
if (ts_ownm) { /* own msg buf? */
ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */
int_req = int_req | INT_TS; /* set interrupt */
ts_qatn = 0; } /* don't queue */
else ts_qatn = 1; /* else queue */
return r;
}
/* Boot */
#define BOOT_START 01000
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32))
static const int32 boot_rom[] = {
0012706, 0001000, /* mov #boot_start, sp */
0012700, 0172520, /* mov #tsba, r0 */
0012701, 0172522, /* mov #tssr, r1 */
0005011, /* clr (r1) ; init, rew */
0105711, /* tstb (r1) ; wait */
0100376, /* bpl .-2 */
0012710, 0001064, /* mov #pkt1, (r0) ; set char */
0105711, /* tstb (r1) ; wait */
0100376, /* bpl .-2 */
0012710, 0001104, /* mov #pkt2, (r0) ; read, skip */
0105711, /* tstb (r1) ; wait */
0100376, /* bpl .-2 */
0012710, 0001104, /* mov #pkt2, (r0) ; read */
0105711, /* tstb (r1) ; wait */
0100376, /* bpl .-2 */
0005711, /* tst (r1) ; err? */
0100421, /* bmi hlt */
0005000, /* clr r0 */
0012705, 0051515, /* mov #MS, r5 */
0005007, /* clr r7 */
0046523, /* pad */
0140004, /* pkt1: 140004, wcpk, 0, 8. */
0001074,
0000000,
0000010,
0001116, /* wcpk: msg, 0, 14., 0 */
0000000,
0000016,
0000000,
0140001, /* pkt2: 140001, 0, 0, 512. */
0000000,
0000000,
0001000,
0000000 /* hlt: halt */
};
t_stat ts_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
ts_unit.pos = 0;
for (i = 0; i < BOOT_LEN; i++)
M[(BOOT_START >> 1) + i] = boot_rom[i];
saved_PC = BOOT_START;
return SCPE_OK;
}

View file

@ -1 +0,0 @@
#define PDP15 0

View file

@ -1,6 +1,6 @@
/* pdp18b_cpu.c: 18b PDP CPU simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,10 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu PDP-4/7/9/15 central processor
26-Apr-01 RMS Added device enable/disable support
25-Jan-01 RMS Added DECtape support
18-Dec-00 RMS Added PDP-9,-15 memm init register
30-Nov-00 RMS Fixed numerous PDP-15 bugs
14-Apr-99 RMS Changed t_addr to unsigned
@ -276,6 +280,7 @@ int32 stop_inst = 0; /* stop on rsrv inst */
int32 xct_max = 16; /* nested XCT limit */
int32 old_PC = 0; /* old PC */
int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */
int32 dev_enb = -1; /* device enables */
extern int32 sim_int_char;
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);
@ -347,6 +352,7 @@ REG cpu_reg[] = {
{ DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },
{ ORDATA (BREAK, ibkpt_addr, ADDRSIZE + 1) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL } };
MTAB cpu_mod[] = {
@ -387,6 +393,8 @@ extern int32 sim_interval;
register int32 PC, LAC, MQ;
int32 iot_data, device, pulse;
t_stat reason;
extern UNIT clk_unit;
extern int32 sim_rtc_init (int32 time);
extern int32 tti (int32 pulse, int32 AC);
extern int32 tto (int32 pulse, int32 AC);
extern int32 ptr (int32 pulse, int32 AC);
@ -410,6 +418,10 @@ extern int32 rp64 (int32 pulse, int32 AC);
#if defined (MTA)
extern int32 mt (int32 pulse, int32 AC);
#endif
#if defined (DTA)
extern int32 dt75 (int32 pulse, int32 AC);
extern int32 dt76 (int32 pulse, int32 AC);
#endif
#define JMS_WORD(t) (((LAC & 01000000) >> 1) | ((memm & 1) << 16) | \
(((t) & 1) << 15) | ((PC) & 077777))
@ -433,6 +445,7 @@ PC = saved_PC & ADDRMASK; /* load local copies */
LAC = saved_LAC & 01777777;
MQ = saved_MQ & 0777777;
reason = 0;
sim_rtc_init (clk_unit.wait); /* init calibration */
/* Main instruction fetch/decode loop: check trap and interrupt */
@ -795,7 +808,7 @@ case 031: /* JMP, indir */
if (rest_pending) { /* restore pending? */
LAC = ((M[MA] << 1) & 01000000) | (LAC & 0777777);
memm = (M[MA] >> 16) & 1;
usmd = (M[MA] >> 15) & 1); }
usmd = (M[MA] >> 15) & 1; }
#endif
INDIRECT; /* complete indirect */
emir_pending = rest_pending = 0;
@ -1304,21 +1317,26 @@ case 034: /* IOT */
break;
#if defined (DRM)
case 060: /* drum */
iot_data = drm60 (pulse, iot_data);
if (dev_enb & INT_DRM) iot_data = drm60 (pulse, iot_data);
else reason = stop_inst;
break;
case 061:
iot_data = drm61 (pulse, iot_data);
if (dev_enb & INT_DRM) iot_data = drm61 (pulse, iot_data);
else reason = stop_inst;
break;
case 062:
iot_data = drm62 (pulse, iot_data);
if (dev_enb & INT_DRM) iot_data = drm62 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (RP)
case 063: /* RP15 */
iot_data = rp63 (pulse, iot_data);
if (dev_enb & INT_RP) iot_data = rp63 (pulse, iot_data);
else reason = stop_inst;
break;
case 064:
iot_data = rp64 (pulse, iot_data);
if (dev_enb & INT_RP) iot_data = rp64 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
case 065: /* LPT */
@ -1329,15 +1347,28 @@ case 034: /* IOT */
break;
#if defined (RF)
case 070: /* RF09 */
iot_data = rf70 (pulse, iot_data);
if (dev_enb & INT_RF) iot_data = rf70 (pulse, iot_data);
else reason = stop_inst;
break;
case 072:
iot_data = rf72 (pulse, iot_data);
if (dev_enb & INT_RF) iot_data = rf72 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (MTA)
case 073: /* TC59 */
iot_data = mt (pulse, iot_data);
if (dev_enb & INT_MTA) iot_data = mt (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (DTA)
case 075: /* TC02/TC15 */
if (dev_enb & INT_DTA) iot_data = dt75 (pulse, iot_data);
else reason = stop_inst;
break;
case 076:
if (dev_enb & INT_DTA) iot_data = dt76 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
default: /* unknown device */

View file

@ -1,6 +1,6 @@
/* pdp18b_defs.h: 18b PDP simulator definitions
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
21-Jan-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
02-Jan-96 RMS Added fixed head and moving head disks
31-Dec-95 RMS Added memory management
@ -39,7 +40,7 @@
model memory CPU options I/O options
PDP4 8K none Type 65 KSR-28 Teletype (Baudot)
PDP4 8K ??Type 18 EAE Type 65 KSR-28 Teletype (Baudot)
integral paper tape reader
Type 75 paper tape punch
integral real time clock
@ -58,6 +59,7 @@
KX09A mem protection Type 647D/E line printer (sixbit)
RF09/RS09 fixed head disk
TC59 magnetic tape
TC02/TU55 DECtape
PDP15 128K KE15 EAE KSR-35 Teletype
KF15 power detection PC15 paper tape reader and punch
@ -66,6 +68,7 @@
RP15 disk pack
RF15/RF09 fixed head disk
TC59D magnetic tape
TC15/TU56 DECtape
??Indicates not implemented. The PDP-4 manual refers to both an EAE
??and a memory extension control; there is no documentation on either.
@ -97,12 +100,14 @@
#define TYPE647 0 /* sixbit printer */
#define RF 0 /* fixed head disk */
#define MTA 0 /* magtape */
#define DTA 0 /* DECtape */
#elif defined (PDP15)
#define ADDRSIZE 17
#define LP15 0 /* ASCII printer */
#define RF 0 /* fixed head disk */
#define RP 0 /* disk pack */
#define MTA 0 /* magtape */
#define DTA 0 /* DECtape */
#endif
/* Memory */
@ -120,6 +125,8 @@
#define LINK (DMASK + 1) /* link */
#define LACMASK (LINK | DMASK) /* link + data */
#define SIGN 0400000 /* sign bit */
#define OP_JMP 0600000 /* JMP */
#define OP_HLT 0740040 /* HLT */
/* IOT subroutine return codes */

View file

@ -1,6 +1,6 @@
/* pdp18b_drm.c: drum/fixed head disk simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,6 +26,7 @@
drm (PDP-7) Type 24 serial drum
(PDP-9) RM09 serial drum
26-Apr-01 RMS Added device enable/disable support
14-Apr-99 RMS Changed t_addr to unsigned
*/
@ -52,7 +53,7 @@
((double) DRM_NUMWDT)))
extern int32 M[];
extern int32 int_req;
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 drm_da = 0; /* track address */
int32 drm_ma = 0; /* memory address */
@ -63,8 +64,6 @@ int32 drm_stopioe = 1; /* stop on error */
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
t_stat drm_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* DRM data structures
@ -86,6 +85,7 @@ REG drm_reg[] = {
{ ORDATA (WLK, drm_wlk, 32) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_DRM), REG_HRO },
{ NULL } };
DEVICE drm_dev = {

1072
pdp18b_dt.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* pdp18b_lp.c: 18b PDP's line printer simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,13 +23,15 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
lpt (PDP-4) Type 62 line printer
(PDP-7,9) Type 647 line printer
(PDP-15) LP15 line printer
13-Feb-01 RMS Revised for register arrays
15-Feb-01 RMS Fixed 3 cycle data break sequence
30-Oct-00 RMS Standardized register naming
20-Aug-98 RMS Fixed compilation problem in BeOS
03-Jan-97 RMS Fixed bug in Type 62 state handling
lpt Type 62 line printer for the PDP-4
Type 647 line printer for the PDP-7 and PDP-9
LP15 line printer for the PDP-15
*/
#include "pdp18b_defs.h"
@ -45,8 +47,6 @@ char lpt_buf[LPT_BSIZE + 1] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* Type 62 LPT data structures
@ -68,7 +68,7 @@ REG lpt_reg[] = {
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (**BUF, lpt_buf, 8, 8, LPT_BSIZE), REG_HRO },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {
@ -195,8 +195,6 @@ t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_detach (UNIT *uptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* Type 647 LPT data structures
@ -221,7 +219,7 @@ REG lpt_reg[] = {
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (**BUF, lpt_buf, 8, 8, LPT_BSIZE), REG_HRO },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {
@ -377,7 +375,7 @@ return detach_unit (uptr);
#define LPT_BSIZE 132 /* line size */
#define LPT_WC 034 /* word count */
#define LPT_MA 035 /* mem address */
#define LPT_CA 035 /* current addr */
/* Status register */
@ -400,9 +398,6 @@ char lpt_buf[LPT_BSIZE] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
int32 lpt_updsta (int32 new);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
/* LP15 LPT data structures
@ -416,7 +411,7 @@ UNIT lpt_unit = {
REG lpt_reg[] = {
{ ORDATA (STA, lpt_sta, 18) },
{ ORDATA (MA, M[LPT_MA], 18) },
{ ORDATA (CA, M[LPT_CA], 18) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ FLDATA (ENABLE, lpt_ie, 0) },
{ DRDATA (LCNT, lcnt, 9) },
@ -425,7 +420,7 @@ REG lpt_reg[] = {
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (**BUF, lpt_buf, 8, 8, LPT_BSIZE), REG_HRO },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {
@ -443,8 +438,8 @@ int32 header;
if (pulse == 001) /* LPSF */
return (lpt_sta & (STA_ERR | STA_DON))? IOT_SKP + AC: AC;
if ((pulse == 021) || (pulse == 041)) { /* LPP1, LPPM */
header = M[(M[LPT_MA] + 1) & ADDRMASK]; /* get first word */
M[LPT_MA] = (M[LPT_MA] + 2) & 0777777;
header = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777;
mode = header & 1; /* mode */
if (pulse == 041) lcnt = 1; /* line count */
else lcnt = (header >> 9) & 0377;
@ -486,9 +481,9 @@ if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT); }
for (more = 1; more != 0; ) { /* loop until ctrl */
w0 = M[(M[LPT_MA] + 1) & ADDRMASK]; /* get first word */
w1 = M[(M[LPT_MA] + 2) & ADDRMASK]; /* get second word */
M[LPT_MA] = (M[LPT_MA] + 2) & 0777777; /* advance mem addr */
w0 = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */
w1 = M[(M[LPT_CA] + 2) & ADDRMASK]; /* get second word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777; /* advance mem addr */
if (mode) { /* unpacked? */
c[0] = w0 & 0177;
c[1] = w1 & 0177;

View file

@ -1,6 +1,6 @@
/* 18b PDP magnetic tape simulator
/* pdp18b_mt.c: 18b PDP magnetic tape simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,12 +23,14 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mt TC59 magnetic tape for PDP-9
TC59D magnetic tape for PDP-15
mt (PDP-9) TC59 magtape
(PDP-15) TC59D magtape
26-Apr-01 RMS Added device enable/disable support
15-Feb-01 RMS Fixed 3-cycle data break sequence
04-Oct-98 RMS V2.4 magtape format
22-Jan-97 RMS V2.3 magtape format
29-Jun-96 RMS Added unit disable support
29-Jun-96 RMS Added unit enable/disable support
Magnetic tapes are represented as a series of variable records
of the form:
@ -55,8 +57,8 @@
#define UNUM u4 /* unit number */
#define DBSIZE (1 << 12) /* max data record */
#define DBMASK (DBSIZE - 1)
#define MT_WC 032 /* in core reg */
#define MT_MA 033
#define MT_WC 032 /* word count */
#define MT_CA 033 /* current addr */
/* Command/unit - mt_cu */
@ -107,7 +109,7 @@
/* error flags */
extern int32 M[];
extern int32 int_req;
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 mt_cu = 0; /* command/unit */
int32 mt_sta = 0; /* status register */
@ -119,11 +121,6 @@ t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_detach (UNIT *uptr);
int32 mt_updcsta (UNIT *uptr, int32 val);
UNIT *mt_busy (void);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* MT data structures
@ -146,8 +143,8 @@ UNIT mt_unit[] = {
REG mt_reg[] = {
{ ORDATA (STA, mt_sta, 18) },
{ ORDATA (CMD, mt_cu, 18) },
{ ORDATA (MA, M[MT_MA], 18) },
{ ORDATA (WC, M[MT_WC], 18) },
{ ORDATA (CA, M[MT_CA], 18) },
{ FLDATA (INT, int_req, INT_V_MTA) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ DRDATA (TIME, mt_time, 24), PV_LEFT },
@ -183,6 +180,7 @@ REG mt_reg[] = {
REG_HRO },
{ GRDATA (FLG7, mt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (*DEVENB, dev_enb, INT_V_MTA), REG_HRO },
{ NULL } };
MTAB mt_mod[] = {
@ -244,7 +242,7 @@ int32 c, c1, c2, c3, f, i, p, u, err;
int32 wc, xma;
t_stat rval;
t_mtrlnt tbc, cbc;
unsigned int8 dbuf[(3 * DBSIZE)];
static uint8 dbuf[(3 * DBSIZE)];
static t_mtrlnt bceof = { 0 };
u = uptr -> UNUM; /* get unit number */
@ -297,8 +295,9 @@ case FN_CMPARE: /* read/compare */
for ( ; i < cbc; i++) dbuf[i] = 0; /* fill with 0's */
err = ferror (uptr -> fileref);
for (i = p = 0; i < wc; i++) { /* copy buffer */
M[MT_MA] = (M[MT_MA] + 1) & 0777777;
xma = M[MT_MA] & ADDRMASK;
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
xma = M[MT_CA] & ADDRMASK;
if (PACKED (mt_cu)) { /* packed? */
c1 = dbuf[p++] & 077;
c2 = dbuf[p++] & 077;
@ -311,8 +310,7 @@ case FN_CMPARE: /* read/compare */
else if ((f == FN_CMPARE) && (c != (M[xma] &
(PACKED (mt_cu)? 0777777: 0177777)))) {
mt_updcsta (uptr, STA_CPE);
break; }
M[MT_WC] = (M[MT_WC] + 1) & 0777777; }
break; } }
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt));
break;
@ -321,16 +319,16 @@ case FN_WRITE: /* write */
wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */
tbc = PACKED (mt_cu)? wc * 3: wc * 2;
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
M[MT_MA] = (M[MT_MA] + 1) & 0777777;
xma = M[MT_MA] & ADDRMASK;
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
xma = M[MT_CA] & ADDRMASK;
if (PACKED (mt_cu)) { /* packed? */
dbuf[p++] = (M[xma] >> 12) & 077;
dbuf[p++] = (M[xma] >> 6) & 077;
dbuf[p++] = M[xma] & 077; }
else { dbuf[p++] = (M[xma] >> 8) & 0377;
dbuf[p++] = M[xma] & 0377; }
M[MT_WC] = (M[MT_WC] + 1) & 0777777; }
dbuf[p++] = M[xma] & 0377; } }
fxwrite (dbuf, sizeof (char), (tbc + 1) & ~1, uptr -> fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
err = ferror (uptr -> fileref);
@ -348,7 +346,6 @@ case FN_WREOF:
uptr -> USTAT = STA_EOF;
break;
case FN_SPACEF: /* space forward */
wc = 01000000 - M[MT_WC]; /* get word count */
do { fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read bc */
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
@ -364,7 +361,6 @@ case FN_SPACEF: /* space forward */
while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
break;
case FN_SPACER: /* space reverse */
wc = 01000000 - M[MT_WC]; /* get word count */
if (uptr -> pos == 0) { /* at BOT? */
uptr -> USTAT = STA_BOT;
break; }

View file

@ -1,6 +1,6 @@
/* pdp18b_rf.c: fixed head disk simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,9 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rf RF09/RF09 for PDP-9
RF15/RS09 for PDP-15
rf (PDP-9) RF09/RF09
(PDP-15) RF15/RS09
26-Apr-01 RMS Added device enable/disable support
15-Feb-01 RMS Fixed 3 cycle data break sequencing
30-Nov-99 RMS Added non-zero requirement to rf_time
14-Apr-99 RMS Changed t_addr to unsigned
@ -50,7 +52,7 @@
#define RF_SIZE (RF_NUMDK * RF_NUMTR * RF_NUMWD) /* words/drive */
#define RF_WMASK (RF_NUMWD - 1) /* word mask */
#define RF_WC 036 /* word count */
#define RF_MA 037 /* mem address */
#define RF_CA 037 /* current addr */
/* Function/status register */
@ -83,7 +85,7 @@
#define RF_BUSY (sim_is_active (&rf_unit))
extern int32 M[];
extern int32 int_req;
extern int32 int_req, dev_enb;
extern UNIT cpu_unit;
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
@ -95,9 +97,6 @@ int32 rf_stopioe = 1; /* stop on error */
t_stat rf_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr);
int32 rf_updsta (int32 new);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
/* RF data structures
@ -113,8 +112,8 @@ UNIT rf_unit =
REG rf_reg[] = {
{ ORDATA (STA, rf_sta, 18) },
{ ORDATA (DA, rf_da, 21) },
{ ORDATA (MA, M[RF_MA], 18) },
{ ORDATA (WC, M[RF_WC], 18) },
{ ORDATA (CA, M[RF_CA], 18) },
{ ORDATA (BUF, rf_dbuf, 18) },
{ FLDATA (INT, int_req, INT_V_RF) },
{ ORDATA (WLK0, rf_wlk[0], 16) },
@ -128,6 +127,7 @@ REG rf_reg[] = {
{ DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO },
{ NULL } };
DEVICE rf_dev = {
@ -207,7 +207,8 @@ if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
return IORETURN (rf_stopioe, SCPE_UNATT); }
f = GET_FNC (rf_sta); /* get function */
do { pa = M[RF_MA] = (M[RF_MA] + 1) & ADDRMASK; /* incr mem addr */
do { M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */
pa = M[RF_CA] = (M[RF_CA] + 1) & ADDRMASK; /* incr mem addr */
if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */
M[pa] = *(((int32 *) uptr -> filebuf) + rf_da);
if ((f == FN_WCHK) && /* write check? */
@ -227,8 +228,7 @@ do { pa = M[RF_MA] = (M[RF_MA] + 1) & ADDRMASK; /* incr mem addr */
if (rf_da > RF_SIZE) { /* disk overflow? */
rf_da = 0;
rf_updsta (RFS_NED); /* nx disk error */
break; }
M[RF_WC] = (M[RF_WC] + 1) & 0777777; } /* incr word count */
break; } }
while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */

View file

@ -1,6 +1,6 @@
/* RP15/RP02 disk pack simulator
/* pdp18b_rp.c: RP15/RP02 disk pack simulator
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,8 +25,9 @@
rp RP15/RP02 disk pack
26-Apr-01 RMS Added device enable/disable support
14-Apr-99 RMS Changed t_addr to unsigned
29-Jun-96 RMS Added unit disable support
29-Jun-96 RMS Added unit enable/disable support
*/
#include "pdp18b_defs.h"
@ -123,7 +124,7 @@
#define MAX(x,y) (((x) > (y))? (x): (y))
extern int32 M[];
extern int32 int_req, nexm;
extern int32 int_req, dev_enb, nexm;
extern UNIT cpu_unit;
int32 rp_sta = 0; /* status A */
int32 rp_stb = 0; /* status B */
@ -139,11 +140,6 @@ void rp_updsta (int32 newa, int32 newb);
t_stat rp_reset (DEVICE *dptr);
t_stat rp_attach (UNIT *uptr, char *cptr);
t_stat rp_detach (UNIT *uptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* RP15 data structures
@ -190,6 +186,7 @@ REG rp_reg[] = {
REG_HRO },
{ GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO },
{ NULL } };
MTAB rp_mod[] = {

View file

@ -1,6 +1,6 @@
/* pdp18b_stddev.c: 18b PDP's standard devices
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,30 +23,33 @@
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.
22-Dec-00 RMS Added PDP-9/15 half duplex support
30-Nov-00 RMS Fixed PDP-4/7 bootstrap loader for 4K systems
30-Oct-00 RMS Standardized register naming
06-Jan-97 RMS Fixed PDP-4 console input
16-Dec-96 RMS Fixed bug in binary ptr service
ptr paper tape reader
ptp paper tape punch
tti keyboard
tto teleprinter
clk clock
10-Mar-01 RMS Added funny format loader support
05-Mar-01 RMS Added clock calibration support
22-Dec-00 RMS Added PDP-9/15 half duplex support
30-Nov-00 RMS Fixed PDP-4/7 bootstrap loader for 4K systems
30-Oct-00 RMS Standardized register naming
06-Jan-97 RMS Fixed PDP-4 console input
16-Dec-96 RMS Fixed bug in binary ptr service
*/
#include "pdp18b_defs.h"
#include <ctype.h>
extern int32 int_req, saved_PC;
extern int32 M[];
extern int32 int_req, saved_PC;
extern UNIT cpu_unit;
int32 clk_state = 0;
int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0;
int32 ptp_err = 0, ptp_stopioe = 0;
int32 tti_state = 0;
int32 tto_state = 0;
int32 clk_tps = 60;
t_stat clk_svc (UNIT *uptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
@ -62,8 +65,8 @@ t_stat ptp_attach (UNIT *uptr, char *cptr);
t_stat ptr_detach (UNIT *uptr);
t_stat ptp_detach (UNIT *uptr);
t_stat ptr_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_rtc_init (int32 time);
extern int32 sim_rtc_calb (int32 tps);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
@ -74,13 +77,14 @@ extern t_stat sim_putchar (int32 out);
clk_reg CLK register list
*/
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 5000 };
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (INT, int_req, INT_V_CLK) },
{ FLDATA (DONE, int_req, INT_V_CLK) },
{ FLDATA (ENABLE, clk_state, 0) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
{ NULL } };
DEVICE clk_dev = {
@ -281,7 +285,9 @@ if (pulse == 004) clk_reset (&clk_dev); /* CLOF */
else if (pulse == 044) { /* CLON */
int_req = int_req & ~INT_CLK; /* clear flag */
clk_state = 1; /* clock on */
sim_activate (&clk_unit, clk_unit.wait); } /* start clock */
if (!sim_is_active (&clk_unit)) /* already on? */
sim_activate (&clk_unit, /* start */
sim_rtc_init (clk_unit.wait)); } /* init calibr */
return AC;
}
@ -292,7 +298,8 @@ t_stat clk_svc (UNIT *uptr)
if (clk_state) { /* clock on? */
M[7] = (M[7] + 1) & 0777777; /* incr counter */
if (M[7] == 0) int_req = int_req | INT_CLK; /* ovrflo? set flag */
sim_activate (&clk_unit, clk_unit.wait); } /* reactivate unit */
sim_activate (&clk_unit, /* reactivate unit */
sim_rtc_calb (clk_tps)); } /* calibr delay */
return SCPE_OK;
}
@ -414,35 +421,154 @@ return detach_unit (uptr);
used to remove addr<5> for a 4K system.
*/
#define BOOT_START 017762
#define BOOT_PC 017770
#define BOOT_START 017577
#define BOOT_FPC 017577
#define BOOT_RPC 017770
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
0000000, /* r, 0 */
0700101, /* rsf */
0617763, /* jmp .-1 */
0700112, /* rrb */
0700144, /* rsb */
0637762, /* jmp i r */
0700144, /* go, rsb */
0117762, /* g, jms r */
0057775, /* dac out */
0417775, /* xct out */
0117762, /* jms r */
0000000, /* out, 0 */
0617771 /* jmp g */
0117762, /* ff, jsb r1b */
0057666, /* dac done 1 */
0117762, /* jms r1b */
0057667, /* dac done 2 */
0117762, /* jms r1b */
0040007, /* dac conend */
0057731, /* dac conbeg */
0440007, /* isz conend */
0117762, /* blk, jms r1b */
0057673, /* dac cai */
0741100, /* spa */
0617665, /* jmp done */
0117762, /* jms r1b */
0057777, /* dac tem1 */
0317673, /* add cai */
0057775, /* dac cks */
0117713, /* jms r1a */
0140010, /* dzm word */
0457777, /* cont, isz tem1 */
0617632, /* jmp cont1 */
0217775, /* lac cks */
0740001, /* cma */
0740200, /* sza */
0740040, /* hlt */
0700144, /* rsb */
0617610, /* jmp blk */
0117713, /* cont1, jms r1a */
0057762, /* dac tem2 */
0117713, /* jms r1a */
0742010, /* rtl */
0742010, /* rtl */
0742010, /* rtl */
0742010, /* rtl */
0317762, /* add tem2 */
0057762, /* dac tem2 */
0117713, /* jms r1a */
0742020, /* rtr */
0317726, /* add cdsp */
0057713, /* dac r1a */
0517701, /* and ccma */
0740020, /* rar */
0317762, /* add tem2 */
0437713, /* xct i r1a */
0617622, /* jmp cont */
0617672, /* dsptch, jmp code0 */
0617670, /* jmp code1 */
0617700, /* jmp code2 */
0617706, /* jmp code3 */
0417711, /* xct code4 */
0617732, /* jmp const */
0740000, /* nop */
0740000, /* nop */
0740000, /* nop */
0200007, /* done, lac conend */
0740040, /* xx */
0740040, /* xx */
0517727, /* code1, and imsk */
0337762, /* add i tem2 */
0300010, /* code0, add word */
0740040, /* cai, xx */
0750001, /* clc */
0357673, /* tad cai */
0057673, /* dac cai */
0617621, /* jmp cont-1 */
0711101, /* code2, spa cla */
0740001, /* ccma, cma */
0277762, /* xor i tem2 */
0300010, /* add word */
0040010, /* code2a, dac word */
0617622, /* jmp cont */
0057711, /* code3, dac code4 */
0217673, /* lac cai */
0357701, /* tad ccma */
0740040, /* code4, xx */
0617622, /* jmp cont */
0000000, /* r1a, 0 */
0700101, /* rsf */
0617714, /* jmp .-1 */
0700112, /* rrb */
0700104, /* rsa */
0057730, /* dac tem */
0317775, /* add cks */
0057775, /* dac cks */
0217730, /* lac tem */
0744000, /* cll */
0637713, /* jmp i r1a */
0017654, /* cdsp, dsptch */
0760000, /* imsk, 760000 */
0000000, /* tem, 0 */
0000000, /* conbeg, 0 */
0300010, /* const, add word */
0060007, /* dac i conend */
0217731, /* lac conbeg */
0040010, /* dac index */
0220007, /* lac i conend */
0560010, /* con1, sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0617737, /* jmp con1 */
0200010, /* find, lac index */
0540007, /* sad conend */
0440007, /* isz conend */
0617704, /* jmp code2a */
0000000,
0000000,
0000000,
0000000,
0000000, /* r1b, 0 */
0700101, /* rsf */
0617763, /* jmp .-1 */
0700112, /* rrb */
0700144, /* rsb */
0637762, /* jmp i r1b */
0700144, /* go, rsb */
0117762, /* g, jms r1b */
0057775, /* dac cks */
0417775, /* xct cks */
0117762, /* jms r1b */
0000000, /* cks, 0 */
0617771 /* jmp g */
};
t_stat ptr_boot (int32 unitno)
{
int32 i, mask;
int32 i, mask, wd;
extern int32 sim_switches;
if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
else mask = 0777777;
for (i = 0; i < BOOT_LEN; i++)
M[(BOOT_START & mask) + i] = boot_rom[i] & mask;
saved_PC = BOOT_PC & mask;
for (i = 0; i < BOOT_LEN; i++) {
wd = boot_rom[i];
if ((wd >= 0040000) && (wd < 0640000)) wd = wd & mask;
M[(BOOT_START & mask) + i] = wd; }
saved_PC = ((sim_switches & SWMASK ('F'))? BOOT_FPC: BOOT_RPC) & mask;
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp18b_sys.c: 18b PDP's simulator interface
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
12-May-01 RMS Fixed bug in RIM loaders
14-Mar-01 RMS Added extension detection of RIM format tapes
21-Jan-01 RMS Added DECtape support
30-Nov-00 RMS Added PDP-9,-15 RIM/BIN loader format
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
@ -50,6 +53,9 @@ extern DEVICE rp_dev;
#if defined (MTA)
extern DEVICE mt_dev;
#endif
#if defined (DTA)
extern DEVICE dt_dev;
#endif
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern int32 M[];
@ -92,6 +98,9 @@ DEVICE *sim_devices[] = { &cpu_dev,
#if defined (RP)
&rp_dev,
#endif
#if defined (DTA)
&dt_dev,
#endif
#if defined (MTA)
&mt_dev,
#endif
@ -134,7 +143,7 @@ return word;
jmp addr or hlt
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 origin, val;
@ -145,10 +154,10 @@ for (;;) {
origin = val & 017777;
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0760000) == 0600000) { /* JMP? */
saved_PC = val & 017777;
else if ((val & 0760000) == OP_JMP) { /* JMP? */
saved_PC = ((origin - 1) & 060000) | (val & 017777);
return SCPE_OK; }
else if (val == 0740040) return SCPE_OK; /* HLT? */
else if (val == OP_HLT) return SCPE_OK; /* HLT? */
else return SCPE_FMT; } /* error */
return SCPE_FMT; /* error */
}
@ -175,16 +184,18 @@ return SCPE_FMT; /* error */
endblock/ origin (< 0)
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
extern int32 sim_switches;
int32 i, bits, origin, count, cksum, val;
t_stat r;
char gbuf[CBUFSIZE];
extern t_bool match_ext (char *fnm, char *ext);
/* RIM loader */
if (sim_switches & SWMASK ('R')) { /* RIM load? */
if ((sim_switches & SWMASK ('R')) || /* RIM format? */
(match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) {
if (*cptr != 0) { /* more input? */
cptr = get_glyph (cptr, gbuf, 0); /* get origin */
origin = get_uint (gbuf, 8, ADDRMASK, &r);
@ -192,11 +203,15 @@ if (sim_switches & SWMASK ('R')) { /* RIM load? */
if (*cptr != 0) return SCPE_ARG; } /* no more */
else origin = 0200; /* default 200 */
for (bits = 0; (bits & 1) == 0; ) { /* word loop */
for (;;) { /* word loop */
if ((val = getword (fileref, &bits)) < 0) return SCPE_FMT;
saved_PC = origin & ADDRMASK; /* save start */
if (MEM_ADDR_OK (origin)) M[origin++] = val; } /* store word */
return SCPE_OK; } /* found word
if (bits & 1) { /* end of tape? */
if ((val & 0760000) == OP_JMP) saved_PC =
((origin - 1) & 060000) | (val & 017777);
else if (val != OP_HLT) return SCPE_FMT;
break; }
else if (MEM_ADDR_OK (origin)) M[origin++] = val; }
return SCPE_OK; }
/* Binary loader */
@ -331,6 +346,10 @@ static const char *opcode[] = {
"MTTR", "MTCR", "MTSF", "MTRC", "MTAF",
"MTRS", "MTGO", "MTCM", "MTLC",
#endif
#if defined (DTA)
"DTCA", "DTRA", "DTXA", "DTLA",
"DTEF", "DTRB", "DTDF",
#endif
#if defined (PDP7)
"ITON", "TTS", "SKP7", "CAF",
"SEM", "EEM", "EMIR", "LEM",
@ -470,6 +489,10 @@ static const int32 opc_val[] = {
0707301+I_NPI, 0707321+I_NPI, 0707341+I_NPI, 0707312+I_NPN, 0707322+I_NPI,
0707352+I_NPN, 0707304+I_NPI, 0707324+I_NPI, 0707326+I_NPI,
#endif
#if defined (DTA)
0707541+I_NPI, 0707552+I_NPN, 0707544+I_NPI, 0707545+I_NPI,
0707561+I_NPI, 0707572+I_NPN, 0707601+I_NPI,
#endif
#if defined (PDP7)
0703201+I_NPI, 0703301+I_NPI, 0703341+I_NPI, 0703302+I_NPI,
0707701+I_NPI, 0707702+I_NPI, 0707742+I_NPI, 0707704+I_NPI,

View file

@ -1,6 +1,6 @@
/* pdp1_cpu.c: PDP-1 CPU simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,8 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu PDP-1 central processor
16-Dec-00 RMS Fixed bug in XCT address calculation
14-Apr-99 RMS Changed t_addr to unsigned
@ -46,11 +48,13 @@
SS<1:6> sense switches
TW<0:17> test word (switch register)
Unresolved questions:
Questions:
1. cks: is there a status flag for sequence break enabled?
2. cks: which bits are line printer print done and space done?
3. sbs: do sequence breaks accumulate when the break system is off?
cks: which bits are line printer print done and space done?
cks: is there a bit for sequence break enabled (yes, according
to the 1963 Handbook)
sbs: do sequence breaks accumulate while the system is disabled
(yes, according to the Maintenance Manual)
*/
/* The PDP-1 has six instruction formats: memory reference, skips,
@ -188,9 +192,10 @@
I/O error in I/O simulator
2. Interrupts. With a single channel sequence break system, the
PDP-1 had a single break request flop, b2, here sbs<SB_V_RQ>.
If sequence breaks are enabled, and one is not already in
progress, a sequence break occurs.
PDP-1 has a single break request (flop b2, here sbs<SB_V_RQ>).
If sequence breaks are enabled (flop sbm, here sbs<SB_V_ON>),
and one is not already in progress (flop b4, here sbs<SB_V_IP>),
a sequence break occurs.
3. Arithmetic. The PDP-1 is a 1's complement system. In 1's
complement arithmetic, a negative number is represented by the

View file

@ -1,6 +1,6 @@
/* pdp1_defs.h: 18b PDP simulator definitions
Copyright (c) 1993-1999, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -27,7 +27,7 @@
The PDP-1 was Digital's first computer. The system design evolved during
its life, and as a result, specifications are sketchy or contradictory.
This simulator is based on the 1963 maintenance manual.
This simulator is based on the 1962 maintenance manual.
This simulator implements the following options:
@ -61,7 +61,7 @@
#define EPCMASK (AMASK & ~DAMASK) /* extended addr */
#define IA 010000 /* indirect flag */
#define IO_WAIT 010000 /* I/O sync wait */
#define IO_CPLS 004000 /* cmopletion pulse */
#define IO_CPLS 004000 /* completion pulse */
#define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */
/* IOT subroutine return codes */

View file

@ -1,6 +1,6 @@
/* pdp1_lp.c: PDP-1 line printer simulator
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -24,6 +24,8 @@
in this Software without prior written authorization from Robert M Supnik.
lpt Type 62 line printer for the PDP-1
13-Apr-01 RMS Revised for register arrays
*/
#include "pdp1_defs.h"
@ -32,12 +34,9 @@
#define BPTR_MASK 077 /* buf ptr mask */
extern int32 ioc, sbs, iosta;
int32 lpt_rpls = 0, lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
unsigned char lpt_buf[LPT_BSIZE + 1] = { 0 };
char lpt_buf[LPT_BSIZE + 1] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* LPT data structures
@ -59,7 +58,7 @@ REG lpt_reg[] = {
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (**BUF, lpt_buf, 8, 8, LPT_BSIZE), REG_HRO },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {

View file

@ -1,6 +1,6 @@
/* pdp1_stddev.c: PDP-1 standard devices
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -54,8 +54,6 @@ t_stat ptp_reset (DEVICE *dptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);

View file

@ -1,6 +1,6 @@
/* pdp1_sys.c: PDP-1 simulator interface
Copyright (c) 1993-2000, Robert M. Supnik
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
14-Mar-01 RMS Revised load/dump interface (again)
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
20-Oct-97 RMS Fixed endian-dependence in RIM loader
@ -90,7 +91,7 @@ for (i = 0; i < 3;) {
return word;
}
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 origin, val;

1
pdp4.c
View file

@ -1 +0,0 @@
#define PDP4 0

1
pdp7.c
View file

@ -1 +0,0 @@
#define PDP7 0

View file

@ -1,6 +1,6 @@
/* pdp8_clk.c: PDP-8 real-time clock simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,18 +23,20 @@
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.
clk real-time clock
clk real time clock
05-Mar-01 RMS Added clock calibration support
Note: includes the IOT's for both the PDP-8/E and PDP-8/A clocks
*/
#include "pdp8_defs.h"
extern int32 int_req, dev_enable, dev_done, stop_inst;
extern int32 int_req, int_enable, dev_done, stop_inst;
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_rtc_calb (int32 tps);
int32 clk_tps = 60;
/* CLK data structures
@ -43,13 +45,14 @@ extern t_stat sim_cancel (UNIT *uptr);
clk_reg CLK register list
*/
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 5000 };
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (DONE, dev_done, INT_V_CLK) },
{ FLDATA (ENABLE, dev_enable, INT_V_CLK) },
{ FLDATA (ENABLE, int_enable, INT_V_CLK) },
{ FLDATA (INT, int_req, INT_V_CLK) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
{ NULL } };
DEVICE clk_dev = {
@ -68,11 +71,11 @@ int32 clk (int32 pulse, int32 AC)
{
switch (pulse) { /* decode IR<9:11> */
case 1: /* CLEI */
dev_enable = dev_enable | INT_CLK; /* enable clk ints */
int_enable = int_enable | INT_CLK; /* enable clk ints */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 2: /* CLDI */
dev_enable = dev_enable & ~INT_CLK; /* disable clk ints */
int_enable = int_enable & ~INT_CLK; /* disable clk ints */
int_req = int_req & ~INT_CLK; /* update interrupts */
return AC;
case 3: /* CLSC */
@ -82,8 +85,8 @@ case 3: /* CLSC */
return IOT_SKP + AC; }
return AC;
case 5: /* CLLE */
if (AC & 1) dev_enable = dev_enable | INT_CLK; /* test AC<11> */
else dev_enable = dev_enable & ~INT_CLK;
if (AC & 1) int_enable = int_enable | INT_CLK; /* test AC<11> */
else int_enable = int_enable & ~INT_CLK;
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 6: /* CLCL */
@ -102,7 +105,7 @@ t_stat clk_svc (UNIT *uptr)
{
dev_done = dev_done | INT_CLK; /* set done */
int_req = INT_UPDATE; /* update interrupts */
sim_activate (&clk_unit, clk_unit.wait); /* reactivate unit */
sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate unit */
return SCPE_OK;
}
@ -112,7 +115,7 @@ t_stat clk_reset (DEVICE *dptr)
{
dev_done = dev_done & ~INT_CLK; /* clear done, int */
int_req = int_req & ~INT_CLK;
dev_enable = dev_enable & ~INT_CLK; /* clear enable */
int_enable = int_enable & ~INT_CLK; /* clear enable */
sim_activate (&clk_unit, clk_unit.wait); /* activate unit */
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp8_cpu.c: PDP-8 CPU simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,12 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
cpu central processor
25-Apr-01 RMS Added device enable/disable support
18-Mar-01 RMS Added DF32 support
05-Mar-01 RMS Added clock calibration support
15-Feb-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
The register state for the PDP-8 is:
@ -143,7 +149,7 @@
2. Interrupts. Interrupts are maintained by three parallel variables:
dev_done device done flags
dev_enable device interrupt enable flags
int_enable interrupt enable flags
int_req interrupt requests
In addition, int_req contains the interrupt enable flag, the
@ -173,7 +179,7 @@
#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
unsigned int16 M[MAXMEMSIZE] = { 0 }; /* main memory */
uint16 M[MAXMEMSIZE] = { 0 }; /* main memory */
int32 saved_LAC = 0; /* saved L'AC */
int32 saved_MQ = 0; /* saved MQ */
int32 saved_PC = 0; /* saved IF'PC */
@ -187,9 +193,10 @@ int32 UB = 0; /* User mode Buffer */
int32 UF = 0; /* User mode Flag */
int32 OSR = 0; /* Switch Register */
int32 old_PC = 0; /* old PC */
int32 dev_enable = INT_INIT_ENABLE; /* dev intr enables */
int32 dev_done = 0; /* dev done flags */
int32 int_enable = INT_INIT_ENABLE; /* intr enables */
int32 int_req = 0; /* intr requests */
int32 dev_enb = -1 & ~INT_DF; /* device enables */
int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */
int32 stop_inst = 0; /* trap on ill inst */
extern int32 sim_int_char;
@ -199,7 +206,6 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_svc (UNIT *uptr);
t_stat cpu_set_size (UNIT *uptr, int32 value);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
/* CPU data structures
@ -233,12 +239,13 @@ REG cpu_reg[] = {
{ FLDATA (UF_INT, int_req, INT_V_UF) },
{ ORDATA (INT, int_req, INT_V_ION+1), REG_RO },
{ ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO },
{ ORDATA (ENABLE, dev_enable, INT_V_DIRECT), REG_RO },
{ ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO },
{ FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO },
{ ORDATA (OLDPC, old_PC, 15), REG_RO },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ ORDATA (BREAK, ibkpt_addr, 16) },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL } };
MTAB cpu_mod[] = {
@ -267,6 +274,8 @@ register int32 IR, MB, IF, DF, LAC, MQ;
register t_addr PC, MA;
int32 device, pulse, temp, iot_data;
t_stat reason;
extern UNIT clk_unit;
extern int32 sim_rtc_init (int32 time);
extern int32 tti (int32 pulse, int32 AC);
extern int32 tto (int32 pulse, int32 AC);
extern int32 ptr (int32 pulse, int32 AC);
@ -275,6 +284,9 @@ extern int32 clk (int32 pulse, int32 AC);
extern int32 lpt (int32 pulse, int32 AC);
extern int32 rk (int32 pulse, int32 AC);
extern int32 rx (int32 pulse, int32 AC);
extern int32 df60 (int32 pulse, int32 AC);
extern int32 df61 (int32 pulse, int32 AC);
extern int32 df62 (int32 pulse, int32 AC);
extern int32 rf60 (int32 pulse, int32 AC);
extern int32 rf61 (int32 pulse, int32 AC);
extern int32 rf62 (int32 pulse, int32 AC);
@ -282,6 +294,8 @@ extern int32 rf64 (int32 pulse, int32 AC);
extern int32 mt70 (int32 pulse, int32 AC);
extern int32 mt71 (int32 pulse, int32 AC);
extern int32 mt72 (int32 pulse, int32 AC);
extern int32 dt76 (int32 pulse, int32 AC);
extern int32 dt77 (int32 pulse, int32 AC);
/* Restore register state */
@ -292,6 +306,7 @@ LAC = saved_LAC & 017777;
MQ = saved_MQ & 07777;
int_req = INT_UPDATE;
reason = 0;
sim_rtc_init (clk_unit.wait); /* init calibration */
/* Main instruction fetch/decode loop */
@ -898,7 +913,7 @@ case 030:case 031:case 032:case 033: /* IOT */
emode = 0;
int_req = int_req & INT_NO_CIF_PENDING;
dev_done = 0;
dev_enable = INT_INIT_ENABLE;
int_enable = INT_INIT_ENABLE;
LAC = 0;
break; } /* end switch pulse */
continue; /* skip rest of IOT */
@ -993,35 +1008,54 @@ case 030:case 031:case 032:case 033: /* IOT */
case 013: /* CLK */
iot_data = clk (pulse, iot_data);
break;
case 060: /* RF08 */
iot_data = rf60 (pulse, iot_data);
case 060: /* DF32/RF08 */
if (dev_enb & INT_DF) iot_data = df60 (pulse, iot_data);
else if (dev_enb & INT_RF) iot_data = rf60 (pulse, iot_data);
else reason = stop_inst;
break;
case 061:
iot_data = rf61 (pulse, iot_data);
if (dev_enb & INT_DF) iot_data = df61 (pulse, iot_data);
else if (dev_enb & INT_RF) iot_data = rf61 (pulse, iot_data);
else reason = stop_inst;
break;
case 062:
iot_data = rf62 (pulse, iot_data);
if (dev_enb & INT_DF) iot_data = df62 (pulse, iot_data);
else if (dev_enb & INT_RF) iot_data = rf62 (pulse, iot_data);
else reason = stop_inst;
break;
case 064:
iot_data = rf64 (pulse, iot_data);
if (dev_enb & INT_RF) iot_data = rf64 (pulse, iot_data);
else reason = stop_inst;
break;
case 066: /* LPT */
iot_data = lpt (pulse, iot_data);
break;
case 070: /* TM8E */
iot_data = mt70 (pulse, iot_data);
if (dev_enb & INT_MT) iot_data = mt70 (pulse, iot_data);
else reason = stop_inst;
break;
case 071:
iot_data = mt71 (pulse, iot_data);
if (dev_enb & INT_MT) iot_data = mt71 (pulse, iot_data);
else reason = stop_inst;
break;
case 072:
iot_data = mt72 (pulse, iot_data);
if (dev_enb & INT_MT) iot_data = mt72 (pulse, iot_data);
else reason = stop_inst;
break;
case 074: /* RK8E */
iot_data = rk (pulse, iot_data);
if (dev_enb & INT_RK) iot_data = rk (pulse, iot_data);
else reason = stop_inst;
break;
case 075: /* RX8E */
iot_data = rx (pulse, iot_data);
if (dev_enb & INT_RX) iot_data = rx (pulse, iot_data);
break;
case 076: /* TC01/TC08 */
if (dev_enb & INT_DTA) iot_data = dt76 (pulse, iot_data);
else reason = stop_inst;
break;
case 077:
if (dev_enb & INT_DTA) iot_data = dt77 (pulse, iot_data);
else reason = stop_inst;
break; } /* end switch device */
LAC = (LAC & 010000) | (iot_data & 07777);
if (iot_data & IOT_SKP) PC = (PC + 1) & 07777;

View file

@ -1,6 +1,6 @@
/* pdp8_defs.h: PDP-8 simulator definitions
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,9 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
18-Mar-01 RMS Added DF32 support
15-Feb-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
19-Mar-95 RMS Added dynamic memory size.
02-May-94 RMS Added non-existent memory handling.
19-Mar-95 RMS Added dynamic memory size
02-May-94 RMS Added non-existent memory handling
The author gratefully acknowledges the help of Max Burnet, Richie Lary,
and Bill Haygood in resolving questions about the PDP-8
@ -84,10 +86,12 @@
#define INT_V_RX (INT_V_DIRECT+0) /* RX8E */
#define INT_V_RK (INT_V_DIRECT+1) /* RK8E */
#define INT_V_RF (INT_V_DIRECT+2) /* RF08 */
#define INT_V_MT (INT_V_DIRECT+3) /* TM8E */
#define INT_V_PWR (INT_V_DIRECT+4) /* power int */
#define INT_V_UF (INT_V_DIRECT+5) /* user int */
#define INT_V_OVHD (INT_V_DIRECT+6) /* overhead start */
#define INT_V_DF (INT_V_DIRECT+3) /* DF32 */
#define INT_V_MT (INT_V_DIRECT+4) /* TM8E */
#define INT_V_DTA (INT_V_DIRECT+5) /* TC08 */
#define INT_V_PWR (INT_V_DIRECT+6) /* power int */
#define INT_V_UF (INT_V_DIRECT+7) /* user int */
#define INT_V_OVHD (INT_V_DIRECT+8) /* overhead start */
#define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */
#define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */
#define INT_V_ION (INT_V_OVHD+2) /* interrupts on */
@ -101,7 +105,9 @@
#define INT_RX (1 << INT_V_RX)
#define INT_RK (1 << INT_V_RK)
#define INT_RF (1 << INT_V_RF)
#define INT_DF (1 << INT_V_DF)
#define INT_MT (1 << INT_V_MT)
#define INT_DTA (1 << INT_V_DTA)
#define INT_PWR (1 << INT_V_PWR)
#define INT_UF (1 << INT_V_UF)
#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING)
@ -111,4 +117,4 @@
#define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */
#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT)
#define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING)
#define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & dev_enable))
#define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable))

278
pdp8_df.c Normal file
View file

@ -0,0 +1,278 @@
/* pdp8_df.c: DF32 fixed head disk simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
df DF32 fixed head disk
25-Apr-01 RMS Added device enable/disable support
The DF32 is a head-per-track disk. It uses the three cycle data break
facility. To minimize overhead, the entire DF32 is buffered in memory.
Two timing parameters are provided:
df_time Interword timing, must be non-zero
df_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst
*/
#include "pdp8_defs.h"
#include <math.h>
/* Constants */
#define DF_NUMWD 2048 /* words/track */
#define DF_NUMTR 16 /* tracks/disk */
#define DF_NUMDK 4 /* disks/controller */
#define DF_SIZE (DF_NUMDK * DF_NUMTR * DF_NUMWD) /* words/drive */
#define DF_WC 07750 /* word count */
#define DF_MA 07751 /* mem address */
#define DF_WMASK (DF_NUMWD - 1) /* word mask */
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define DF_READ 2 /* read */
#define DF_WRITE 4 /* write */
/* Status register */
#define DFS_PCA 04000 /* photocell status */
#define DFS_DEX 03700 /* disk addr extension */
#define DFS_MEX 00070 /* mem addr extension */
#define DFS_DRL 00004 /* data late error */
#define DFS_WLS 00002 /* write lock error */
#define DFS_PER 00001 /* parity error */
#define DFS_ERR (DFS_DRL + DFS_WLS + DFS_PER)
#define DFS_V_DEX 6
#define DFS_V_MEX 3
#define GET_MEX(x) (((x) & DFS_MEX) << (12 - DFS_V_MEX))
#define GET_DEX(x) (((x) & DFS_DEX) << (12 - DFS_V_DEX))
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DF_NUMWD)))
#define UPDATE_PCELL if (GET_POS (df_time) < 6) df_sta = df_sta | DFS_PCA; \
else df_sta = df_sta & ~DFS_PCA
extern uint16 M[];
extern int32 int_req, dev_enb, stop_inst;
extern UNIT cpu_unit;
extern int32 rf_devenb;
int32 df_sta = 0; /* status register */
int32 df_da = 0; /* disk address */
int32 df_done = 0; /* done flag */
int32 df_wlk = 0; /* write lock */
int32 df_time = 10; /* inter-word time */
int32 df_burst = 1; /* burst mode flag */
int32 df_stopioe = 1; /* stop on error */
t_stat df_svc (UNIT *uptr);
t_stat pcell_svc (UNIT *uptr);
t_stat df_reset (DEVICE *dptr);
t_stat df_boot (int32 unitno);
/* DF32 data structures
df_dev RF device descriptor
df_unit RF unit descriptor
pcell_unit photocell timing unit (orphan)
df_reg RF register list
*/
UNIT df_unit =
{ UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
DF_SIZE) };
REG df_reg[] = {
{ ORDATA (STA, df_sta, 12) },
{ ORDATA (DA, df_da, 12) },
{ ORDATA (WC, M[DF_WC], 12) },
{ ORDATA (MA, M[DF_MA], 12) },
{ FLDATA (DONE, df_done, 0) },
{ FLDATA (INT, int_req, INT_V_DF) },
{ ORDATA (WLS, df_wlk, 8) },
{ DRDATA (TIME, df_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (BURST, df_burst, 0) },
{ FLDATA (STOP_IOE, df_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_DF), REG_HRO },
{ NULL } };
DEVICE df_dev = {
"DF", &df_unit, df_reg, NULL,
1, 8, 17, 1, 8, 12,
NULL, NULL, &df_reset,
&df_boot, NULL, NULL };
/* IOT routines */
int32 df60 (int32 pulse, int32 AC)
{
int32 t;
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DCMA */
df_da = 0; /* clear disk addr */
df_done = 0; /* clear done */
df_sta = df_sta & ~DFS_ERR; /* clear errors */
int_req = int_req & ~INT_DF; } /* clear int req */
if (pulse & 6) { /* DMAR, DMAW */
df_da = df_da | AC; /* disk addr |= AC */
df_unit.FUNC = pulse & ~1; /* save function */
t = (df_da & DF_WMASK) - GET_POS (df_time); /* delta to new loc */
if (t < 0) t = t + DF_NUMWD; /* wrap around? */
sim_activate (&df_unit, t * df_time); /* schedule op */
AC = 0; } /* clear AC */
return AC;
}
/* Based on the hardware implementation. DEAL and DEAC work as follows:
6615 pulse 1 = clear df_sta<dex,mex>
pulse 4 = df_sta = df_sta | AC<dex,mex>
AC = AC | old_df_sta
6616 pulse 2 = clear AC, skip if address confirmed
pulse 4 = df_sta = df_sta | AC<dex,mex> = 0 (nop)
AC = AC | old_df_sta
*/
int32 df61 (int32 pulse, int32 AC)
{
int32 old_df_sta = df_sta;
UPDATE_PCELL; /* update photocell */
if (pulse & 1) /* DCEA */
df_sta = df_sta & ~(DFS_DEX | DFS_MEX); /* clear dex, mex */
if (pulse & 2) /* DSAC */
AC = ((df_da & DF_WMASK) == GET_POS (df_time))? IOT_SKP: 0;
if (pulse & 4) {
df_sta = df_sta | (AC & (DFS_DEX | DFS_MEX)); /* DEAL */
AC = AC | old_df_sta; } /* DEAC */
return AC;
}
int32 df62 (int32 pulse, int32 AC)
{
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DFSE */
if ((df_sta & DFS_ERR) == 0) AC = AC | IOT_SKP; }
if (pulse & 2) { /* DFSC */
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
else if (df_done) AC = AC | IOT_SKP; }
if (pulse & 4) AC = AC | df_da; /* DMAC */
return AC;
}
/* Unit service
Note that for reads and writes, memory addresses wrap around in the
current field. This code assumes the entire disk is buffered.
*/
t_stat df_svc (UNIT *uptr)
{
int32 pa, t, mex;
t_addr da;
UPDATE_PCELL; /* update photocell */
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
df_done = 1;
int_req = int_req | INT_DF; /* update int req */
return IORETURN (df_stopioe, SCPE_UNATT); }
mex = GET_MEX (df_sta);
da = GET_DEX (df_sta) | df_da; /* form disk addr */
do { M[DF_WC] = (M[DF_WC] + 1) & 07777; /* incr word count */
M[DF_MA] = (M[DF_MA] + 1) & 07777; /* incr mem addr */
pa = mex | M[DF_MA]; /* add extension */
if (uptr -> FUNC == DF_READ) {
if (MEM_ADDR_OK (pa)) /* read, check nxm */
M[pa] = *(((int16 *) uptr -> filebuf) + da); }
else { t = (da >> 14) & 07;
if ((df_wlk >> t) & 1) df_sta = df_sta | DFS_WLS;
else { *(((int16 *) uptr -> filebuf) + da) = M[pa];
if (da >= uptr -> hwmark)
uptr -> hwmark = da + 1; } }
da = (da + 1) & 0377777; } /* incr disk addr */
while ((M[DF_WC] != 0) && (df_burst != 0)); /* brk if wc, no brst */
if (M[DF_WC] != 0) /* more to do? */
sim_activate (&df_unit, df_time); /* sched next */
else { if (uptr -> FUNC != DF_READ) da = (da - 1) & 0377777;
df_done = 1; /* done */
int_req = int_req | INT_DF; } /* update int req */
df_sta = (df_sta & ~DFS_DEX) | ((da >> (12 - DFS_V_DEX)) & DFS_DEX);
df_da = da & 07777; /* separate disk addr */
return SCPE_OK;
}
/* Reset routine */
t_stat df_reset (DEVICE *dptr)
{
if (dev_enb & INT_DF) dev_enb = dev_enb & ~INT_RF; /* either DF or RF */
df_sta = df_da = 0;
df_done = 1;
int_req = int_req & ~INT_DF; /* clear interrupt */
sim_cancel (&df_unit);
return SCPE_OK;
}
/* Bootstrap routine */
#define OS8_START 07750
#define OS8_LEN (sizeof (os8_rom) / sizeof (int32))
#define DM4_START 00200
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int32))
static const int32 os8_rom[] = {
07600, /* 7750, CLA CLL ; also word count */
06603, /* 7751, DMAR ; also address */
06622, /* 7752, DFSC ; done? */
05352, /* 7753, JMP .-1 ; no */
05752 /* 7754, JMP @.-2 ; enter boot */
};
static const int32 dm4_rom[] = {
00200, 07600, /* 0200, CLA CLL */
00201, 06603, /* 0201, DMAR ; read */
00202, 06622, /* 0202, DFSC ; done? */
00203, 05202, /* 0203, JMP .-1 ; no */
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
07750, 07576, /* 7750, 7576 ; word count */
07751, 07576 /* 7751, 7576 ; address */
};
t_stat df_boot (int32 unitno)
{
int32 i;
extern int32 sim_switches, saved_PC;
if (sim_switches & SWMASK ('D')) {
for (i = 0; i < DM4_LEN; i = i + 2)
M[dm4_rom[i]] = dm4_rom[i + 1];
saved_PC = DM4_START; }
else { for (i = 0; i < OS8_LEN; i++)
M[OS8_START + i] = os8_rom[i];
saved_PC = OS8_START; }
return SCPE_OK;
}

1150
pdp8_dt.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* pdp8_lp.c: PDP-8 line printer simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,20 +23,18 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
lpt line printer
lpt LP8E line printer
*/
#include "pdp8_defs.h"
extern int32 int_req, dev_done, dev_enable, stop_inst;
extern int32 int_req, int_enable, dev_done, stop_inst;
int32 lpt_err = 0; /* error flag */
int32 lpt_stopioe = 0; /* stop on error */
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_detach (UNIT *uptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* LPT data structures
@ -52,7 +50,7 @@ REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (ERR, lpt_err, 0) },
{ FLDATA (DONE, dev_done, INT_V_LPT) },
{ FLDATA (ENABLE, dev_enable, INT_V_LPT) },
{ FLDATA (ENABLE, int_enable, INT_V_LPT) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
@ -89,11 +87,11 @@ case 4: /* PSTB */
return AC; }
return (lpt_svc (&lpt_unit) << IOT_V_REASON) + AC;
case 5: /* PSIE */
dev_enable = dev_enable | INT_LPT; /* set enable */
int_enable = int_enable | INT_LPT; /* set enable */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 7: /* PCIE */
dev_enable = dev_enable & ~INT_LPT; /* clear enable */
int_enable = int_enable & ~INT_LPT; /* clear enable */
int_req = int_req & ~INT_LPT; /* clear int req */
return AC;
default:
@ -124,7 +122,7 @@ t_stat lpt_reset (DEVICE *dptr)
lpt_unit.buf = 0;
dev_done = dev_done & ~INT_LPT; /* clear done, int */
int_req = int_req & ~INT_LPT;
dev_enable = dev_enable | INT_LPT; /* set enable */
int_enable = int_enable | INT_LPT; /* set enable */
lpt_err = (lpt_unit.flags & UNIT_ATT) == 0;
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/* PDP-8 magnetic tape simulator
/* pdp8_mt.c: PDP-8 magnetic tape simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mt TM8E/TU10 magtape
25-Apr-01 RMS Added device enable/disable support
04-Oct-98 RMS V2.4 magtape format
22-Jan-97 RMS V2.3 magtape format
01-Jan-96 RMS Rewritten from TM8-E Maintenance Manual
@ -114,8 +117,8 @@
/* set error */
#define TUR(u) (!sim_is_active (u)) /* tape unit ready */
extern unsigned int16 M[];
extern int32 int_req, stop_inst;
extern uint16 M[];
extern int32 int_req, dev_enb, stop_inst;
extern UNIT cpu_unit;
int32 mt_cu = 0; /* command/unit */
int32 mt_fn = 0; /* function */
@ -135,11 +138,6 @@ int32 mt_ixma (int32 xma);
t_stat mt_vlock (UNIT *uptr, int32 val);
UNIT *mt_busy (void);
void mt_set_done (void);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* MT data structures
@ -203,6 +201,7 @@ REG mt_reg[] = {
REG_HRO },
{ GRDATA (FLG7, mt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (*DEVENB, dev_enb, INT_V_MT), REG_HRO },
{ NULL } };
MTAB mt_mod[] = {
@ -276,10 +275,8 @@ case 7: /* LDBR */
mt_db = AC; /* load buffer */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return 0;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
return AC;
return 0; } /* end switch */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
}
/* IOTs, continued */
@ -305,10 +302,8 @@ case 6: /* RFSR */
return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK))
& 07777); /* read function */
case 7: /* RDBR */
return mt_db; /* read data buffer */
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
return AC;
return mt_db; } /* read data buffer */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
}
int32 mt72 (int32 pulse, int32 AC)
@ -330,10 +325,8 @@ case 5: /* CLF */
else { mt_sta = 0; /* clear status */
mt_done = 0; /* clear done */
mt_updcsta (uptr); } /* update status */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
return AC;
return AC; } /* end switch */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
}
/* Unit service
@ -347,8 +340,8 @@ t_stat mt_svc (UNIT *uptr)
int32 f, i, p, u, err, wc, xma;
t_stat rval;
t_mtrlnt tbc, cbc;
unsigned int16 c, c1, c2;
unsigned int8 dbuf[(2 * DBSIZE)];
uint16 c, c1, c2;
uint8 dbuf[(2 * DBSIZE)];
static t_mtrlnt bceof = { 0 };
u = uptr -> UNUM; /* get unit number */

View file

@ -1,6 +1,6 @@
/* pdp8_pt.c: PDP-8 paper tape reader/punch simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,24 +23,20 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
30-Mar-98 RMS Added RIM loader as PTR bootstrap.
ptr,ptp PC8E paper tape reader/punch
ptr paper tape reader
ptp paper tape punch
30-Mar-98 RMS Added RIM loader as PTR bootstrap
*/
#include "pdp8_defs.h"
extern int32 int_req, dev_done, dev_enable, stop_inst;
extern unsigned int16 M[];
extern int32 int_req, int_enable, dev_done, stop_inst;
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* PTR data structures
@ -55,7 +51,7 @@ UNIT ptr_unit = {
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_PTR) },
{ FLDATA (ENABLE, dev_enable, INT_V_PTR) },
{ FLDATA (ENABLE, int_enable, INT_V_PTR) },
{ FLDATA (INT, int_req, INT_V_PTR) },
{ DRDATA (POS, ptr_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
@ -81,7 +77,7 @@ UNIT ptp_unit = {
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_PTP) },
{ FLDATA (ENABLE, dev_enable, INT_V_PTP) },
{ FLDATA (ENABLE, int_enable, INT_V_PTP) },
{ FLDATA (INT, int_req, INT_V_PTP) },
{ DRDATA (POS, ptp_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
@ -100,7 +96,7 @@ int32 ptr (int32 pulse, int32 AC)
{
switch (pulse) { /* decode IR<9:11> */
case 0: /* RPE */
dev_enable = dev_enable | (INT_PTR+INT_PTP); /* set enable */
int_enable = int_enable | (INT_PTR+INT_PTP); /* set enable */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 1: /* RSF */
@ -149,7 +145,7 @@ t_stat ptr_reset (DEVICE *dptr)
ptr_unit.buf = 0;
dev_done = dev_done & ~INT_PTR; /* clear done, int */
int_req = int_req & ~INT_PTR;
dev_enable = dev_enable | INT_PTR; /* set enable */
int_enable = int_enable | INT_PTR; /* set enable */
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
@ -160,7 +156,7 @@ int32 ptp (int32 pulse, int32 AC)
{
switch (pulse) { /* decode IR<9:11> */
case 0: /* PCE */
dev_enable = dev_enable & ~(INT_PTR+INT_PTP); /* clear enables */
int_enable = int_enable & ~(INT_PTR+INT_PTP); /* clear enables */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 1: /* PSF */
@ -203,7 +199,7 @@ t_stat ptp_reset (DEVICE *dptr)
ptp_unit.buf = 0;
dev_done = dev_done & ~INT_PTP; /* clear done, int */
int_req = int_req & ~INT_PTP;
dev_enable = dev_enable | INT_PTP; /* set enable */
int_enable = int_enable | INT_PTP; /* set enable */
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
@ -238,6 +234,7 @@ t_stat ptr_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
extern uint16 M[];
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;

View file

@ -1,6 +1,6 @@
/* pdp8_rf.c: RF08 fixed head disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rf RF08 fixed head disk
25-Apr-01 RMS Added device enable/disable support
19-Mar-01 RMS Added disk monitor bootstrap, fixed IOT decoding
15-Feb-01 RMS Fixed 3 cycle data break sequence
14-Apr-99 RMS Changed t_addr to unsigned
30-Mar-98 RMS Fixed bug in RF bootstrap.
@ -52,8 +57,8 @@
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define RF_READ 3 /* read */
#define RF_WRITE 5 /* write */
#define RF_READ 2 /* read */
#define RF_WRITE 4 /* write */
/* Status register */
@ -81,9 +86,10 @@
int_req = int_req | INT_RF; \
else int_req = int_req & ~INT_RF
extern int32 int_req, stop_inst;
extern unsigned int16 M[];
extern uint16 M[];
extern int32 int_req, dev_enb, stop_inst;
extern UNIT cpu_unit;
extern int32 df_devenb;
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
int32 rf_done = 0; /* done flag */
@ -95,8 +101,6 @@ t_stat rf_svc (UNIT *uptr);
t_stat pcell_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr);
t_stat rf_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* RF08 data structures
@ -115,14 +119,15 @@ UNIT pcell_unit = { UDATA (&pcell_svc, 0, 0) };
REG rf_reg[] = {
{ ORDATA (STA, rf_sta, 12) },
{ ORDATA (DA, rf_da, 20) },
{ ORDATA (MA, M[RF_MA], 12) },
{ ORDATA (WC, M[RF_WC], 12) },
{ ORDATA (MA, M[RF_MA], 12) },
{ FLDATA (DONE, rf_done, 0) },
{ FLDATA (INT, int_req, INT_V_RF) },
{ ORDATA (WLK, rf_wlk, 32) },
{ DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO },
{ NULL } };
DEVICE rf_dev = {
@ -138,22 +143,19 @@ int32 rf60 (int32 pulse, int32 AC)
int32 t;
UPDATE_PCELL; /* update photocell */
switch (pulse) { /* decode IR<9:11> */
case 1: /* DCMA */
if (pulse & 1) { /* DCMA */
rf_da = rf_da & ~07777; /* clear DAR<8:19> */
return AC;
case 3:case 5: /* DMAR, DMAW */
rf_da = (rf_da & ~07777) | AC; /* DAR<8:19> <- AC */
rf_done = 0; /* clear done */
rf_sta = rf_sta & ~RFS_ERR; /* clear errors */
RF_INT_UPDATE; /* update int req */
rf_unit.FUNC = pulse; /* save function */
RF_INT_UPDATE; } /* update int req */
if (pulse & 6) { /* DMAR, DMAW */
rf_da = rf_da | AC; /* DAR<8:19> |= AC */
rf_unit.FUNC = pulse & ~1; /* save function */
t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new loc */
if (t < 0) t = t + RF_NUMWD; /* wrap around? */
sim_activate (&rf_unit, t * rf_time); /* schedule op */
return 0; /* clear AC */
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
AC = 0; } /* clear AC */
return AC;
}
int32 rf61 (int32 pulse, int32 AC)
@ -176,9 +178,8 @@ case 5: /* DIML */
RF_INT_UPDATE; /* update int req */
return 0; /* clear AC */
case 6: /* DIMA */
return rf_sta; /* AC <- STA<0:11> */
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
return rf_sta; } /* AC <- STA<0:11> */
return AC;
}
/* IOT's, continued */
@ -186,17 +187,13 @@ default:
int32 rf62 (int32 pulse, int32 AC)
{
UPDATE_PCELL; /* update photocell */
switch (pulse) { /* decode IR<9:11> */
case 1: /* DFSE */
return (rf_sta & RFS_ERR)? IOT_SKP + AC: AC;
case 2: /* DFSC */
return (rf_done)? IOT_SKP + AC: AC;
case 3: /* DISK */
return (rf_done || (rf_sta & RFS_ERR))? IOT_SKP + AC: AC;
case 6: /* DMAC */
return rf_da & 07777; /* AC <- DAR<0:11> */
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
if (pulse & 1) { /* DFSE */
if (rf_sta & RFS_ERR) AC = AC | IOT_SKP; }
if (pulse & 2) { /* DFSC */
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
else if (rf_done) AC = AC | IOT_SKP; }
if (pulse & 4) AC = AC | (rf_da & 07777); /* DMAC */
return AC;
}
int32 rf64 (int32 pulse, int32 AC)
@ -233,7 +230,8 @@ if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
return IORETURN (rf_stopioe, SCPE_UNATT); }
mex = GET_MEX (rf_sta);
do { M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */
do { M[RF_WC] = (M[RF_WC] + 1) & 07777; /* incr word count */
M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */
pa = mex | M[RF_MA]; /* add extension */
if (uptr -> FUNC == RF_READ) {
if (MEM_ADDR_OK (pa)) /* read, check nxm */
@ -243,8 +241,7 @@ do { M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */
else { *(((int16 *) uptr -> filebuf) + rf_da) = M[pa];
if (((t_addr) rf_da) >= uptr -> hwmark)
uptr -> hwmark = rf_da + 1; } }
rf_da = (rf_da + 1) & 03777777; /* incr disk addr */
M[RF_WC] = (M[RF_WC] + 1) & 07777; } /* incr word count */
rf_da = (rf_da + 1) & 03777777; } /* incr disk addr */
while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
if (M[RF_WC] != 0) /* more to do? */
@ -269,6 +266,7 @@ return SCPE_OK;
t_stat rf_reset (DEVICE *dptr)
{
if (dev_enb & INT_RF) dev_enb = dev_enb & ~INT_DF; /* either DF or RF */
rf_sta = rf_da = 0;
rf_done = 1;
int_req = int_req & ~INT_RF; /* clear interrupt */
@ -279,10 +277,12 @@ return SCPE_OK;
/* Bootstrap routine */
#define BOOT_START 07750
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
#define OS8_START 07750
#define OS8_LEN (sizeof (os8_rom) / sizeof (int32))
#define DM4_START 00200
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int32))
static const int32 boot_rom[] = {
static const int32 os8_rom[] = {
07600, /* 7750, CLA CLL ; also word count */
06603, /* 7751, DMAR ; also address */
06622, /* 7752, DFSC ; done? */
@ -290,12 +290,27 @@ static const int32 boot_rom[] = {
05752 /* 7754, JMP @.-2 ; enter boot */
};
static const int32 dm4_rom[] = {
00200, 07600, /* 0200, CLA CLL */
00201, 06603, /* 0201, DMAR ; read */
00202, 06622, /* 0202, DFSC ; done? */
00203, 05202, /* 0203, JMP .-1 ; no */
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
07750, 07576, /* 7750, 7576 ; word count */
07751, 07576 /* 7751, 7576 ; address */
};
t_stat rf_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
extern int32 sim_switches, saved_PC;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
if (sim_switches & SWMASK ('D')) {
for (i = 0; i < DM4_LEN; i = i + 2)
M[dm4_rom[i]] = dm4_rom[i + 1];
saved_PC = DM4_START; }
else { for (i = 0; i < OS8_LEN; i++)
M[OS8_START + i] = os8_rom[i];
saved_PC = OS8_START; }
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp8_rk.c: RK8E cartridge disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,7 +23,10 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
29-Jun-96 RMS Added unit disable feature
rk RK8E/RK05 cartridge disk
25-Apr-01 RMS Added device enable/disable support
29-Jun-96 RMS Added unit enable/disable support
*/
#include "pdp8_defs.h"
@ -115,8 +118,8 @@
#define RK_MIN 10
#define MAX(x,y) (((x) > (y))? (x): (y))
extern int32 int_req, stop_inst;
extern unsigned int16 M[];
extern uint16 M[];
extern int32 int_req, dev_enb, stop_inst;
extern UNIT cpu_unit;
int32 rk_busy = 0; /* controller busy */
int32 rk_sta = 0; /* status register */
@ -129,11 +132,6 @@ t_stat rk_svc (UNIT *uptr);
t_stat rk_reset (DEVICE *dptr);
t_stat rk_boot (int32 unitno);
void rk_go (int32 function, int32 cylinder);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern int32 sim_is_active (UNIT *uptr);
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
/* RK-8E data structures
@ -167,6 +165,7 @@ REG rk_reg[] = {
{ GRDATA (FLG3, rk_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RK), REG_HRO },
{ NULL } };
MTAB rk_mod[] = {
@ -291,7 +290,7 @@ return;
Note that memory addresses wrap around in the current field.
*/
static unsigned int16 fill[RK_NUMWD/2] = { 0 };
static uint16 fill[RK_NUMWD/2] = { 0 };
t_stat rk_svc (UNIT *uptr)
{
int32 err, wc, wc1, awc, swc, pa, da;

View file

@ -1,6 +1,6 @@
/* pdp8_rx.c: RX8E/RX01 floppy disk simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,7 +23,12 @@
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.
rx RX8E disk controller
rx RX8E/RX01 floppy disk
26-Apr-01 RMS Added device enable/disable support
13-Apr-01 RMS Revised for register arrays
14-Apr-99 RMS Changed t_addr to unsigned
15-Aug-96 RMS Fixed bug in LCD
An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.
Tracks are numbered 0-76, sectors 1-26. The RX8E can store data in
@ -31,9 +36,6 @@
128 bytes per sector. In 12b mode, the reads or writes 64 12b words
per sector. The 12b words are bit packed into the first 96 bytes
of the sector; the last 32 bytes are zeroed on writes.
14-Apr-99 RMS Changed t_addr to unsigned
15-Aug-96 RMS Fixed bug in LCD
*/
#include "pdp8_defs.h"
@ -82,7 +84,7 @@
#define READ_RXDBR ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr)
#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY
extern int32 int_req, dev_done, dev_enable;
extern int32 int_req, int_enable, dev_done, dev_enb;
int32 rx_tr = 0; /* xfer ready flag */
int32 rx_err = 0; /* error flag */
int32 rx_csr = 0; /* control/status */
@ -96,13 +98,11 @@ int32 rx_cwait = 100; /* command time */
int32 rx_swait = 10; /* seek, per track */
int32 rx_xwait = 1; /* tr set time */
int32 rx_stopioe = 1; /* stop on error */
unsigned int8 buf[RX_NUMBY] = { 0 }; /* sector buffer */
uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */
int32 bufptr = 0; /* buffer pointer */
t_stat rx_svc (UNIT *uptr);
t_stat rx_reset (DEVICE *dptr);
t_stat rx_boot (int32 unitno);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
/* RX8E data structures
@ -130,7 +130,7 @@ REG rx_reg[] = {
{ FLDATA (TR, rx_tr, 0) },
{ FLDATA (ERR, rx_err, 0) },
{ FLDATA (DONE, dev_done, INT_V_RX) },
{ FLDATA (ENABLE, dev_enable, INT_V_RX) },
{ FLDATA (ENABLE, int_enable, INT_V_RX) },
{ FLDATA (INT, int_req, INT_V_RX) },
{ DRDATA (CTIME, rx_cwait, 24), PV_LEFT },
{ DRDATA (STIME, rx_swait, 24), PV_LEFT },
@ -138,7 +138,8 @@ REG rx_reg[] = {
{ FLDATA (FLG0, rx_unit[0].flags, UNIT_V_WLK), REG_HRO },
{ FLDATA (FLG1, rx_unit[1].flags, UNIT_V_WLK), REG_HRO },
{ FLDATA (STOP_IOE, rx_stopioe, 0) },
{ BRDATA (*BUF, buf, 8, 8, RX_NUMBY), REG_HRO },
{ BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RX), REG_HRO },
{ NULL } };
MTAB rx_mod[] = {
@ -226,8 +227,8 @@ case 5: /* SDN */
return IOT_SKP + AC; }
return AC;
case 6: /* INTR */
if (AC & 1) dev_enable = dev_enable | INT_RX;
else dev_enable = dev_enable & ~INT_RX;
if (AC & 1) int_enable = int_enable | INT_RX;
else int_enable = int_enable & ~INT_RX;
int_req = INT_UPDATE;
return AC;
case 7: /* INIT */
@ -240,10 +241,10 @@ case 7: /* INIT */
IDLE Should never get here, treat as unknown command
RWDS Just transferred sector, wait for track, set tr
RWDT Just transferred track, do read or write, finish command
FILL copy dbr to buf[bufptr], advance ptr
FILL copy dbr to rx_buf[bufptr], advance ptr
if bufptr > max, finish command, else set tr
EMPTY if bufptr > max, finish command, else
copy buf[bufptr] to dbr, advance ptr, set tr
copy rx_buf[bufptr] to dbr, advance ptr, set tr
CMD_COMPLETE copy requested data to dbr, finish command
INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
@ -270,34 +271,34 @@ case EMPTY: /* empty buffer */
if (bufptr >= RX_NUMBY) { /* done? */
rx_done (rx_esr, 0); /* set done */
break; } /* and exit */
rx_dbr = buf[bufptr]; } /* else get data */
rx_dbr = rx_buf[bufptr]; } /* else get data */
else { byptr = PTR12 (bufptr); /* 12b xfer */
if (bufptr >= RX_NUMWD) { /* done? */
rx_done (rx_esr, 0); /* set done */
break; } /* and exit */
rx_dbr = (bufptr & 1)? /* get data */
((buf[byptr] & 017) << 8) | buf[byptr + 1]:
(buf[byptr] << 4) | ((buf[byptr + 1] >> 4) & 017); }
((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]:
(rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017); }
bufptr = bufptr + 1;
rx_tr = 1;
break;
case FILL: /* fill buffer */
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
buf[bufptr] = rx_dbr; /* fill buffer */
rx_buf[bufptr] = rx_dbr; /* fill buffer */
bufptr = bufptr + 1;
if (bufptr < RX_NUMBY) rx_tr = 1; /* if more, set xfer */
else rx_done (rx_esr, 0); } /* else done */
else { byptr = PTR12 (bufptr); /* 12b xfer */
if (bufptr & 1) { /* odd or even? */
buf[byptr] = (buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
buf[byptr + 1] = rx_dbr & 0377; }
rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
rx_buf[byptr + 1] = rx_dbr & 0377; }
else {
buf[byptr] = (rx_dbr >> 4) & 0377;
buf[byptr + 1] = (rx_dbr & 017) << 4; }
rx_buf[byptr] = (rx_dbr >> 4) & 0377;
rx_buf[byptr + 1] = (rx_dbr & 017) << 4; }
bufptr = bufptr + 1;
if (bufptr < RX_NUMWD) rx_tr = 1; /* if more, set xfer */
else { for (i = PTR12 (RX_NUMWD); i < RX_NUMBY; i++)
buf[i] = 0; /* else fill sector */
rx_buf[i] = 0; /* else fill sector */
rx_done (rx_esr, 0); } } /* set done */
break;
case RWDS: /* wait for sector */
@ -320,13 +321,13 @@ case RWDT: /* wait for track */
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
if (func == RXCS_READ) { /* read? */
for (i = 0; i < RX_NUMBY; i++)
buf[i] = *(((int8 *) uptr -> filebuf) + da + i); }
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); }
else { if (uptr -> flags & UNIT_WLK) { /* write and locked? */
rx_esr = rx_esr | RXES_WLK; /* flag error */
rx_done (rx_esr, 0100); /* done, error */
break; }
for (i = 0; i < RX_NUMBY; i++) /* write */
*(((int8 *) uptr -> filebuf) + da + i) = buf[i];
*(((int8 *) uptr -> filebuf) + da + i) = rx_buf[i];
da = da + RX_NUMBY;
if (da > uptr -> hwmark) uptr -> hwmark = da; }
rx_done (rx_esr, 0); /* done */
@ -344,7 +345,7 @@ case INIT_COMPLETE: /* init complete */
break; }
da = CALC_DA (1, 1); /* track 1, sector 1 */
for (i = 0; i < RX_NUMBY; i++) /* read sector */
buf[i] = *(((int8 *) uptr -> filebuf) + da + i);
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i);
rx_done (rx_esr | RXES_ID | RXES_DRDY, 0); /* set done */
if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;
break; } /* end case state */
@ -377,11 +378,13 @@ rx_esr = rx_ecode = 0; /* clear error */
rx_tr = rx_err = 0; /* clear flags */
dev_done = dev_done & ~INT_RX; /* clear done, int */
int_req = int_req & ~INT_RX;
int_enable = int_enable & ~INT_RX;
rx_dbr = rx_csr = 0; /* 12b mode, drive 0 */
rx_state = INIT_COMPLETE; /* set state */
sim_cancel (&rx_unit[1]); /* cancel drive 1 */
sim_activate (&rx_unit[0], /* start drive 0 */
rx_swait * abs (1 - rx_unit[0].TRACK));
if (rx_unit[0].flags & UNIT_BUF) { /* attached? */
rx_state = INIT_COMPLETE; /* yes, sched init */
sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK)); }
else rx_done (rx_esr | RXES_ID, 0010); /* no, error */
return SCPE_OK;
}
@ -427,7 +430,7 @@ t_stat rx_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
extern unsigned int16 M[];
extern uint16 M[];
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
M[BOOT_INST] = unitno? 07024: 07004;

View file

@ -1,6 +1,6 @@
/* pdp8_sys.c: PDP-8 simulator interface
Copyright (c) 1993-2000, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,9 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
18-Mar-01 RMS Added DF32 support
14-Mar-01 RMS Added extension detection of RIM binary tapes
15-Feb-01 RMS Added DECtape support
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
10-Apr-98 RMS Added RIM loader support
@ -38,10 +41,10 @@ extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE clk_dev, lpt_dev;
extern DEVICE rk_dev, rx_dev;
extern DEVICE rf_dev;
extern DEVICE mt_dev;
extern DEVICE df_dev, rf_dev;
extern DEVICE dt_dev, mt_dev;
extern REG cpu_reg[];
extern unsigned int16 M[];
extern uint16 M[];
extern int32 sim_switches;
/* SCP data structures and interface routines
@ -60,11 +63,14 @@ REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = { &cpu_dev,
&ptr_dev, &ptp_dev, &tti_dev, &tto_dev,
DEVICE *sim_devices[] = {
&cpu_dev,
&ptr_dev, &ptp_dev,
&tti_dev, &tto_dev,
&clk_dev, &lpt_dev,
&rk_dev, &rx_dev, &rf_dev,
&mt_dev,
&rk_dev, &rx_dev,
&df_dev, &rf_dev,
&dt_dev, &mt_dev,
NULL };
const char *sim_stop_messages[] = {
@ -75,9 +81,9 @@ const char *sim_stop_messages[] = {
/* Binary loader
Two loader formats are supported: RIM loader (-r) and BIN loader.
Two loader formats are supported: RIM loader (-r) and BIN (-b) loader.
RIM loader format cosists of alternating pairs of addresses and 12-bit
RIM loader format consists of alternating pairs of addresses and 12-bit
words. It can only operate in field 0 and is not checksummed.
BIN loader format consists of a string of 12-bit words (made up from
@ -86,14 +92,16 @@ const char *sim_stop_messages[] = {
a character > 0200 indicates a change of field.
*/
t_stat sim_load (FILE *fileref, char *cptr, int flag)
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 rubout, word, low, high, csum, newf, state, i;
t_addr origin, field;
extern t_bool match_ext (char *fnam, char *ext);
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
rubout = state = field = newf = origin = csum = 0;
if (sim_switches & SWMASK ('R')) { /* RIM format? */
if ((sim_switches & SWMASK ('R')) || /* RIM format? */
(match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) {
while ((i = getc (fileref)) != EOF) {
switch (state) {
case 0: /* leader */
@ -190,6 +198,7 @@ static const char *opcode[] = {
"ADSK", "ADSE", "ADLE", "ADRS",
"DCMA", "DMAR", "DMAW",
"DCIM", "DSAC", "DIML", "DIMA",
"DCEA", "DEAL", "DEAC",
"DFSE", "DFSC", "DISK", "DMAC",
"DCXA", "DXAL", "DXAC",
"PSKF", "PCLF", "PSKE",
@ -241,6 +250,7 @@ static const int32 opc_val[] = {
06534+I_NPN, 06535+I_NPN, 06536+I_NPN, 06537+I_NPN,
06601+I_NPN, 06603+I_NPN, 06605+I_NPN,
06611+I_NPN, 06612+I_NPN, 06615+I_NPN, 06616+I_NPN,
06611+I_NPN, 06615+I_NPN, 06616+I_NPN,
06621+I_NPN, 06622+I_NPN, 06623+I_NPN, 06626+I_NPN,
06641+I_NPN, 06643+I_NPN, 06645+I_NPN,
06661+I_NPN, 06662+I_NPN, 06663+I_NPN,

View file

@ -1,6 +1,6 @@
/* pdp8_tt.c: PDP-8 console terminal simulator
Copyright (c) 1993-1999, Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,8 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
tti terminal input
tto terminal output
tti,tto KL8E terminal input/output
*/
#include "pdp8_defs.h"
@ -32,13 +31,11 @@
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
extern int32 int_req, dev_done, dev_enable, stop_inst;
extern int32 int_req, int_enable, dev_done, stop_inst;
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
extern t_stat sim_activate (UNIT *uptr, int32 delay);
extern t_stat sim_cancel (UNIT *uptr);
extern t_stat sim_poll_kbd (void);
extern t_stat sim_putchar (int32 out);
@ -55,7 +52,7 @@ UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT };
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_TTI) },
{ FLDATA (ENABLE, dev_enable, INT_V_TTI) },
{ FLDATA (ENABLE, int_enable, INT_V_TTI) },
{ FLDATA (INT, int_req, INT_V_TTI) },
{ DRDATA (POS, tti_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
@ -85,7 +82,7 @@ UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_TTO) },
{ FLDATA (ENABLE, dev_enable, INT_V_TTO) },
{ FLDATA (ENABLE, int_enable, INT_V_TTO) },
{ FLDATA (INT, int_req, INT_V_TTO) },
{ DRDATA (POS, tto_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
@ -115,8 +112,8 @@ case 2: /* KCC */
case 4: /* KRS */
return (AC | tti_unit.buf); /* return buffer */
case 5: /* KIE */
if (AC & 1) dev_enable = dev_enable | (INT_TTI+INT_TTO);
else dev_enable = dev_enable & ~(INT_TTI+INT_TTO);
if (AC & 1) int_enable = int_enable | (INT_TTI+INT_TTO);
else int_enable = int_enable & ~(INT_TTI+INT_TTO);
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 6: /* KRB */
@ -152,7 +149,7 @@ t_stat tti_reset (DEVICE *dptr)
tti_unit.buf = 0;
dev_done = dev_done & ~INT_TTI; /* clear done, int */
int_req = int_req & ~INT_TTI;
dev_enable = dev_enable | INT_TTI; /* set enable */
int_enable = int_enable | INT_TTI; /* set enable */
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
return SCPE_OK;
}
@ -205,7 +202,7 @@ t_stat tto_reset (DEVICE *dptr)
tto_unit.buf = 0;
dev_done = dev_done & ~INT_TTO; /* clear done, int */
int_req = int_req & ~INT_TTO;
dev_enable = dev_enable | INT_TTO; /* set enable */
int_enable = int_enable | INT_TTO; /* set enable */
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}

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