mirror of
https://github.com/simh/simh.git
synced 2026-01-26 04:01:38 +00:00
Notes For V2.8
1. New Features
1.1 Directory and documentation
- Only common files (SCP and libraries) are in the top level
directory. Individual simulator files are in their individual
directories.
- simh_doc.txt has been split up. simh_doc.txt now documents
only SCP. The individual simulators are documented in separate
text files in their own directories.
- mingw_build.bat is a batch file for the MINGW/gcc environment
that will build all the simulators, assuming the root directory
structure is at c:\sim.
- Makefile is a UNIX make file for the gcc environment that will
build all the simulators, assuming the root directory is at
c:\sim.
1.2 SCP
- DO <file name> executes the SCP commands in the specified file.
- Replicated registers in unit structures can now be declared as
arrays for examine, modify, save, and restore. Most replicated
unit registers (for example, mag tape position registers) have
been changed to arrays.
- The ADD/REMOVE commands have been replaced by SET unit ONLINE
and SET unit OFFLINE, respectively.
- Register names that are unique within an entire simulator do
not have to be prefaced with the device name.
- The ATTACH command can attach files read only, either under
user option (-r), or because the attached file is ready only.
- The SET/SHOW capabilities have been extended. New forms include:
SET <dev> param{=value}{ param ...}
SET <unit> param{=value}{ param ...}
SHOW <dev> {param param ...}
SHOW <unit> {param param ...}
- Multiple breakpoints have been implemented. Breakpoints are
set/cleared/displayed by:
BREAK addr_list{[count]}
NOBREAK addr_list
SHOW BREAK addr_list
1.3 PDP-11 simulator
- Unibus map implemented, with 22b RP controller (URH70) or 18b
RP controller (URH11) (in debug).
- All DMA peripherals rewritten to use map.
- Many peripherals modified for source sharing with VAX.
- RQDX3 implemented.
- Bugs fixed in RK11 and RL11 write check.
1.4 PDP-10 simulator
- ITS 1-proceed implemented.
- Bugs fixed in ITS PC sampling and LPMR
1.5 18b PDP simulator
- Interrupts split out to multiple levels to allow easier
expansion.
1.5 IBM System 3 Simulator
- Written by Charles (Dutch) Owen.
1.6 VAX Simulator (in debug)
- Simulates MicroVAX 3800 (KA655) with 16MB-64MB memory, RQDX3,
RLV12, TSV11, DZV11, LPV11, PCV11.
- CDROM capability has been added to the RQDX3, to allow testing
with VMS hobbyist images.
1.7 SDS 940 Simulator (not tested)
- Simulates SDS 940, 16K-64K memory, fixed and moving head
disk, magtape, line printer, console.
1.8 Altair Z80
- Revised from Charles (Dutch) Owen's original by Peter Schorn.
- MITS 8080 with full Z80 simulation.
- 4K and 8K BASIC packages, Prolog package.
1.9 Interdata
The I4 simulator has been withdrawn for major rework. Look for
a complete 16b/32b Interdata simulator sometime next year.
2. Release Notes
2.1 SCP
SCP now allows replicated registers in unit structures to be
modelled as arrays. All replicated register declarations have
been replaced by register array declarations. As a result,
save files from prior revisions will generate errors after
restoring main memory.
2.2 PDP-11
The Unibus map code is in debug. The map was implemented primarily
to allow source sharing with the VAX, which requires a DMA map.
DMA devices work correctly with the Unibus map disabled.
The RQDX3 simulator has run a complete RSTS/E SYSGEN, with multiple
drives, and booted the completed system from scratch.
2.3 VAX
The VAX simulator will run the boot code up to the >>> prompt. It
can successfully process a SHOW DEVICE command. It runs the HCORE
instruction diagnostic. It can boot the hobbyist CD through SYSBOOT
and through the date/time dialog and restore the hobbyist CD, using
standalone backup. On the boot of the restored disk, it gets to the
date/time dialog, and then crashes.
2.4 SDS 940
The SDS 940 is untested, awaiting real code.
2.5 GCC Optimization
At -O2 and above, GCC does not correctly compile the simulators which
use setjmp-longjmp (PDP-11, PDP-10, VAX). A working hypothesis is
that optimized state maintained in registers is being used in the
setjmp processing routine. On the PDP-11 and PDP-10, all of this
state has been either made global, or volatile, to encourage GCC to
keep the state up to date in memory. The VAX is still vulnerable.
3. Work list
3.1 SCP
- Better ENABLE/DISABLE.
3.2 PDP-11 RQDX3
Software mapped mode, RCT read simulation, VMS debug.
This commit is contained in:
committed by
Mark Pizzolato
parent
654937fc88
commit
701f0fe028
211
ALTAIR/altair.txt
Normal file
211
ALTAIR/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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1164
ALTAIR/altair_cpu.c
Normal file
1164
ALTAIR/altair_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
24
ALTAIR/altair_defs.h
Normal file
24
ALTAIR/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/altair_dsk.c
Normal file
345
ALTAIR/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/altair_sio.c
Normal file
238
ALTAIR/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/altair_sys.c
Normal file
288
ALTAIR/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);
|
||||
}
|
||||
Reference in New Issue
Block a user