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