mirror of
https://github.com/open-simh/simh.git
synced 2026-05-03 06:39:03 +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
375
AltairZ80/altairZ80.txt
Normal file
375
AltairZ80/altairZ80.txt
Normal file
@@ -0,0 +1,375 @@
|
||||
Altair 8800 Simulator
|
||||
=====================
|
||||
|
||||
1. Background.
|
||||
|
||||
The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800
|
||||
was announced on the January 1975 cover of Popular Electronics, which
|
||||
boasted you could buy and build this powerful computer kit for only $397.
|
||||
The kit consisted at that time of only the parts to build a case, power
|
||||
supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of
|
||||
memory. Still, thousands were ordered within the first few months after the
|
||||
announcement, starting the personal computer revolution as we know it today.
|
||||
|
||||
Many laugh at the small size of the that first kit, noting there
|
||||
were no peripherals and the 256 byte memory size. But the computer was an
|
||||
open system, and by 1977 MITS and many other small startups had added many
|
||||
expansion cards to make the Altair quite a respectable little computer. The
|
||||
"Altair Bus" that made this possible was soon called the S-100 Bus, later
|
||||
adopted as an industry standard, and eventually became the IEE-696 Bus.
|
||||
|
||||
2. Hardware
|
||||
|
||||
We are simulating a fairly "loaded" Altair 8800 from about 1977,
|
||||
with the following configuration:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU Altair 8800 with Intel 8080 CPU board, 62KB
|
||||
of RAM, 2K of EPROM with start boot ROM.
|
||||
SIO MITS 88-2SIO Dual Serial Interface Board. Port 1
|
||||
is assumed to be connected to a serial "glass
|
||||
TTY" that is your terminal running the Simulator.
|
||||
PTR Paper Tape Reader attached to port 2 of the 2SIO board.
|
||||
PTP Paper Tape Punch attached to port 2 of the
|
||||
2SIO board. This also doubles as a printer port.
|
||||
DSK MITS 88-DISK Floppy Disk controller with up
|
||||
to eight drives.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
We have 2 CPU options that were not present on the original
|
||||
machine but are useful in the simulator. We also allow you to select
|
||||
memory sizes, but be aware that some sample software requires the full
|
||||
64K (i.e. CP/M) and the MITS Disk Basic and Altair DOS require about
|
||||
a minimum of 24K.
|
||||
|
||||
SET CPU 8080 Simulates the 8080 CPU (normal)
|
||||
SET CPU Z80 Simulates the Z80 CPU. Note that some software (e.g. most
|
||||
original Altair software such as 4K Basic) requires an 8080 CPU and
|
||||
will not or not properly run on a Z80. This is mainly due to the use
|
||||
of the parity flag on the 8080 which has not always the same
|
||||
semantics on the Z80.
|
||||
SET CPU ITRAP Causes the simulator to halt if an invalid opcode
|
||||
is detected (depending on the chosen CPU).
|
||||
SET CPU NOITRAP Does not stop on an invalid Opcode. This is
|
||||
how the real 8080 works.
|
||||
SET CPU 4K
|
||||
SET CPU 8K
|
||||
SET CPU 12K
|
||||
SET CPU 16K
|
||||
......
|
||||
SET CPU 64K All these set various CPU memory configurations.
|
||||
The 2K EPROM at the high end of memory is always
|
||||
present and will always boot.
|
||||
|
||||
The BOOT EPROM card starts at address FF00. Jumping to this address
|
||||
will always boot drive 0 of the floppy controller. If no valid bootable
|
||||
software is present there the machine crashes. This is historically
|
||||
accurate behavior.
|
||||
|
||||
The real 8080, on receiving a HLT (Halt) instruction, freezes the processor
|
||||
and only an interrupt or CPU hardware reset will restore it. The simulator
|
||||
is alot nicer, it will halt but send you back to the simulator command line.
|
||||
|
||||
CPU Registers include the following:
|
||||
|
||||
name size comments
|
||||
|
||||
PC 16 The Program Counter
|
||||
AF 16 The accumulator and the flag register
|
||||
F = S Z - AC - P/V N C
|
||||
S = Sign flag.
|
||||
Z = Zero Flag.
|
||||
AC = Auxillary Carry flag.
|
||||
P/V = Parity flag on 8080
|
||||
Parity / Overflow flag on Z80
|
||||
- = not used (undefined)
|
||||
N = Internal sign flag
|
||||
C = Carry flag.
|
||||
BC 16 The BC register pair. Register B is the high 8 bits,
|
||||
C is the lower 8 bits
|
||||
DE 16 The DE register pair. Register D is the high 8 bits,
|
||||
E is the lower 8 bits.
|
||||
HL 16 The HL register pair. Register H is the high 8 bits,
|
||||
L is the lower 8 bits.
|
||||
AF1 16 The alternate AF register (only on Z80)
|
||||
BC1 16 The alternate BC register (only on Z80)
|
||||
DE1 16 The alternate DE register (only on Z80)
|
||||
HL1 16 The alternate HL register (only on Z80)
|
||||
IX 16 The IX index register (only on Z80)
|
||||
IY 16 The IY index register (only on Z80)
|
||||
IFF 8 Interrupt flag (only on Z80, no effect)
|
||||
INT 8 Interrupt register (only on Z80, no effect)
|
||||
|
||||
SR 16 The front panel switches (use D SR 8 for 4k Basic).
|
||||
WRU 8 The interrupt character. This starts as 5
|
||||
(ctrl-E) but some Altair software uses this
|
||||
keystroke so best to change this to something
|
||||
exotic such as 035 (which is Ctl-]).
|
||||
|
||||
|
||||
2.2 The Serial I/O Card (2SIO)
|
||||
|
||||
This simple programmed I/O device provides 2 serial ports to the
|
||||
outside world, which could be hardware jumpered to support RS-232 plugs or a
|
||||
TTY current loop interface. The standard I/O addresses assigned by MITS
|
||||
was 10-11 (hex) for the first port, and 12-13 (hex) for the second.
|
||||
We follow this standard in the Simulator.
|
||||
|
||||
The simulator directs I/O to/from the first port to the screen. The
|
||||
second port reads from an attachable "tape reader" file on input, and writes
|
||||
to an attachable "punch file" on output. These files are considered a
|
||||
simple stream of 8-bit bytes.
|
||||
|
||||
The SIO can be configured in SIMH with the following commands:
|
||||
|
||||
SET SIO TTY Bit 8 is set to zero on console output
|
||||
SET SIO ANSI Bit 8 is not touched on console output
|
||||
|
||||
SET SIO ALL Console input support lower- and upper case
|
||||
SET SIO UPPER Console input is transformed to upper case characters only
|
||||
(This feature is useful for most Altair software)
|
||||
|
||||
SET SIO BS Map the delete character to backspace
|
||||
SET SIO DEL Map the backspace character to delete
|
||||
|
||||
You can also attach the SIO to a port:
|
||||
|
||||
ATTACH SIO 23 Console IO goes via a Telnet connection on port 23
|
||||
DETACH SIO Console IO goes via the regular SIMH console
|
||||
|
||||
2.3 The 88-DISK controller.
|
||||
|
||||
The MITS 88-DISK is a simple programmed I/O interface to the MITS
|
||||
8-inch floppy drive, which was basically a Pertec FD-400 with a power
|
||||
supply and buffer board builtin. The controller supports neither interrupts
|
||||
nor DMA, so floppy access required the sustained attention of the CPU.
|
||||
The standard I/O addresses were 8, 9, and 0A (hex), and we follow the
|
||||
standard. Details on controlling this hardware are in the altair_dsk.c
|
||||
source file.
|
||||
|
||||
The only difference is that the simulated disks may be larger than the
|
||||
original ones: The original disk had 77 tracks while the simulated disks
|
||||
support up to 254 tracks (only relevant for CP/M).
|
||||
|
||||
For debugging purposes you can set the trace level of some disk I/O
|
||||
functions. To do so the following bits in TRACE (a register of the disk)
|
||||
have been defined with the following meaning:
|
||||
|
||||
1 Trace all IN and OUT instructions on the disk ports 8 and 9
|
||||
2 Trace all read and writes to full sectors on the disk
|
||||
4 Print a message whenever an unnecessary step-in or step out of the
|
||||
disk head occurs (often an indication of an infinite loop)
|
||||
8 Print a message whenever the disk head appears to be waiting for a
|
||||
sector which does not show up (often an indication of an infinite
|
||||
loop)
|
||||
|
||||
For example the command "D TRACE 10" will trace options 2+8 from above.
|
||||
|
||||
|
||||
3. Sample Software
|
||||
|
||||
Running an Altair in 1977 you would be running either MITS Disk
|
||||
Extended BASIC, or the brand new and sexy CP/M Operating System from Digital
|
||||
Research. Or possibly, you ordered Altair DOS back when it was promised in
|
||||
1975, and are still waiting for it to be delivered in early 1977.
|
||||
|
||||
We have samples of all three for you to check out. We can't go into
|
||||
the details of how they work, but we'll give you a few hints.
|
||||
|
||||
|
||||
3.1 CP/M Version 2.2
|
||||
|
||||
This version is my own port of the standard CP/M to the Altair.
|
||||
There were some "official" versions but I don't have them. None were
|
||||
endorsed or sold by MITS to my knowledge, however.
|
||||
To boot CP/M:
|
||||
|
||||
sim> attach dsk altcpm.dsk
|
||||
sim> go ff00
|
||||
62K CP/M VERSION 2.2 (ALTAIR 8800)
|
||||
A>DIR
|
||||
|
||||
CP/M feels like DOS, sort of. DIR will work. I have included all
|
||||
the standard CP/M utilities, plus a few common public-domain ones. I also
|
||||
include the sources to the customized BIOS and some other small programs.
|
||||
TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better
|
||||
DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to
|
||||
binary format (.COM). ED is a simple editor, #A command will bring the
|
||||
source file to the buffer, T command will "type" lines, L will move lines,
|
||||
E exits the editor. 20L20T will move down 20 lines, and type 20. Very
|
||||
DECish. DDT is the debugger, SUBMIT is a batch-type command processor.
|
||||
A sample batch file that will assemble and write out the bootable CP/M
|
||||
image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN".
|
||||
|
||||
In order to efficiently transfer files into the CP/M environment use the
|
||||
included program READ <filename.ext>. If you have a file named foo.ext in
|
||||
the current directory (i.e. the directory where SIMH is), executing
|
||||
READ FOO.EXT under CP/M will transfer the file onto the CP/M disk. READ will
|
||||
only run with Z80 CPU so remember to "SET CPU Z80".
|
||||
|
||||
The disk "altcpm.dsk" contains the following files:
|
||||
Name Ext Size Comment
|
||||
ABOOT62 ASM 1K Moves CP/M image from MOVCPM location to real location
|
||||
in memory
|
||||
ASM COM 8K Standard CP/M assembler
|
||||
CALC PRO 3K Prolog sample file "Calculator"
|
||||
CBIOS ASM 8K BIOS for the Altair (used for sysgen)
|
||||
COPY COM 1K ALTAIR diskette backup program
|
||||
CPM62 COM 9K CP/M binary (used for sysgen)
|
||||
DDT COM 5K Dynamic Debugging Tool (Standard CP/M)
|
||||
DDTZ COM 10K Dynamic Debugging Tool for Z80
|
||||
DUMP ASM 5K Assembler source for DUMP utility
|
||||
DUMP COM 1K Dumps the contents of a file in hex (Standard CP/M)
|
||||
ED COM 7K Line oriented editor (Standard CP/M)
|
||||
FAMILY PRO 2K Prolog sample file "Family relations"
|
||||
FORMAT COM 2K Formats a disk
|
||||
INTEGER PRO 1K Prolog sample file "Integer arithmetic"
|
||||
KNAKE PRO 2K Prolog sample file "Logic puzzle"
|
||||
LOAD COM 2K Loads a hex file and produces an executable
|
||||
(Standard CP/M)
|
||||
LS COM 3K Directory utility
|
||||
MOVCPM COM 12K Regenerates the CP/M system for a particular
|
||||
memory size (Standard CP/M)
|
||||
PINST COM 4K Terminal installer for PROLOGZ.COM
|
||||
PIP COM 8K Peripheral Interchange Program for copying files
|
||||
(Standard CP/M)
|
||||
PROLOGZ COM 17K Prolog development environment
|
||||
PROLOGZ TXT 40K PROLOGZ documentation in German
|
||||
PTD ASM 2K Writes Altair-format memory image to disk
|
||||
(used for sysgen)
|
||||
QUEEN PRO 2K Prolog sample file "N Queens problem"
|
||||
READ COM 2K Reads a file from the SIMH filesystem to CP/M
|
||||
README TXT 3K This file
|
||||
STAT COM 6K Provides information about drives, disks and
|
||||
files (Standard CP/M)
|
||||
SUBMIT COM 2K Submits a file of commands for batch processing
|
||||
(Standard CP/M)
|
||||
SURVEY COM 2K Provides information about memory and IO ports
|
||||
SYSCOPY COM 2K Copies the reserved tracks between disks
|
||||
SYSGEN SUB 2K Submit file for generating the CP/M system
|
||||
XSUB COM 2K Addition to SUBMIT such that all input is read
|
||||
from the submit file (Standard CP/M)
|
||||
|
||||
3.2 MITS Disk Extended BASIC Version 4.1
|
||||
|
||||
This was the commonly used software for serious users of the Altair
|
||||
computer. It is a powerful (but slow) BASIC with some extended commands to
|
||||
allow it to access and manage the disk. There was no operating system it
|
||||
ran under. To boot:
|
||||
|
||||
sim> set cpu 8080 ;Z80 will not work
|
||||
sim> attach dsk mbasic.dsk
|
||||
sim> set sio upper
|
||||
sim> go ff00
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
LINEPRINTER? C [return]
|
||||
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
|
||||
NUMBER OF FILES? 3 [return]
|
||||
NUMBER OF RANDOM FILES? 2 [return]
|
||||
|
||||
44041 BYTES FREE
|
||||
ALTAIR BASIC REV. 4.1
|
||||
[DISK EXTENDED VERSION]
|
||||
COPYRIGHT 1977 BY MITS INC.
|
||||
OK
|
||||
MOUNT 0
|
||||
OK
|
||||
FILES
|
||||
|
||||
|
||||
3.3 Altair DOS Version 1.0
|
||||
|
||||
This was long promised but not delivered until it was almost
|
||||
irrelevant. A short attempted tour will reveal it to be a dog, far inferior
|
||||
to CP/M. To boot:
|
||||
|
||||
sim> attach dsk altdos.dsk
|
||||
sim> set sio upper
|
||||
sim> go ff00
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
INTERRUPTS? N [return]
|
||||
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
|
||||
HOW MANY DISK FILES? 3 [return]
|
||||
HOW MANY RANDOM FILES? 2 [return]
|
||||
|
||||
056449 BYTES AVAILABLE
|
||||
DOS MONITOR VER 1.0
|
||||
COPYRIGHT 1977 BY MITS INC
|
||||
.MNT 0
|
||||
|
||||
.DIR 0
|
||||
|
||||
3.4 Altair 4k Basic
|
||||
In order to run the famous 4k Basic, use the following commands (the trick
|
||||
is to get the Switch Register right).
|
||||
|
||||
sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU
|
||||
sim> set sio upper ;4k Basic does not like lower case letters as input
|
||||
sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits
|
||||
sim> d sr 8 ;good setting for the Switch Register
|
||||
sim> load 4kbas.bin ;load it
|
||||
sim> go ;and go
|
||||
MEMORY SIZE? [return]
|
||||
TERMINAL WIDTH? [return]
|
||||
WANT SIN? [Y]
|
||||
|
||||
61911 BYTES FREE
|
||||
|
||||
BASIC VERSION 3.2
|
||||
[4K VERSION]
|
||||
|
||||
OK
|
||||
|
||||
3.5 Altair 8k Basic
|
||||
Running 8k Basic follows the procedure for 4k Basic.
|
||||
|
||||
sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU
|
||||
sim> set sio upper ;8k Basic does not like lower case letters as input
|
||||
sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits
|
||||
sim> d sr 8 ;good setting for the Switch Register
|
||||
sim> load 8kbas.bin ;load it
|
||||
sim> go ;and go
|
||||
MEMORY SIZE? [A]
|
||||
|
||||
WRITTEN FOR ROYALTIES BY MICRO-SOFT
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
TERMINAL WIDTH? [return]
|
||||
WANT SIN-COS-TAN-ATN? [Y]
|
||||
|
||||
58756 BYTES FREE
|
||||
ALTAIR BASIC REV. 4.0
|
||||
[EIGHT-K VERSION]
|
||||
COPYRIGHT 1976 BY MITS INC.
|
||||
OK
|
||||
|
||||
4. Brief summary of all major changes to the original Altair simulator
|
||||
- Full support for Z80. CP/M software requiring a Z80 CPU now runs
|
||||
properly. DDTZ and PROLOGZ are included for demonstration purposes.
|
||||
- Full assembler and dis-assembler support for Z80 and 8080 mnemonics.
|
||||
Depending on the current setting of the CPU, the appropriate mnemonics
|
||||
are used.
|
||||
- The BOOT ROM was changed to fully load the software from disk. The
|
||||
original code basically loaded a copy of itself from the disk and
|
||||
executed it.
|
||||
- ROM and memory size settings are now fully honored. This means that you
|
||||
cannot write into the ROM or outside the defined RAM (e.g. when the RAM size
|
||||
was truncated with the SET CPU commands). This feature allows programs which
|
||||
check for the size of available RAM to run properly (e.g. 4k Basic).
|
||||
- The console can also be used via Telnet. This is useful when a terminal is
|
||||
needed which supports cursor control such as a VT100. PROLOGZ for example
|
||||
has a built-in screen editor which works under Telnet.
|
||||
- Simplified file exchange for CP/M. Using the READ program under CP/M one
|
||||
can easily import files into CP/M from the regular file system. Note that PIP
|
||||
does not work properly on non-text files on PTR.
|
||||
- The last character read from PTR is always Control-Z (the EOF character for
|
||||
CP/M). This makes sure that PIP (Peripheral Interchange Program on CP/M) will
|
||||
terminate properly.
|
||||
- Fixed a bug in the BIOS warm boot routine which caused CP/M to crash.
|
||||
- Modified the BIOS for CP/M to support 8 disks.
|
||||
- Changed from octal to hex which is more concise.
|
||||
3372
AltairZ80/altairZ80_cpu.c
Normal file
3372
AltairZ80/altairZ80_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
30
AltairZ80/altairZ80_defs.h
Normal file
30
AltairZ80/altairZ80_defs.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* altairZ80_defs.h: MITS Altair simulator definitions
|
||||
Written by Peter Schorn, 2001
|
||||
Based on work by Charles E Owen ((c) 1997, Commercial use prohibited)
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator definitions */
|
||||
|
||||
/* Memory */
|
||||
#define MAXMEMSIZE 65536 /* max memory size */
|
||||
#define KB 1024 /* kilo byte */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
|
||||
#define bootrom_size 256 /* size of boot rom */
|
||||
#define bootrom_origin 0xFF00 /* start address of boot rom */
|
||||
|
||||
#define BACKSPACE_CHAR 0x08 /* backspace character */
|
||||
#define DELETE_CHAR 0x7f /* delete character */
|
||||
#define CONTROLZ_CHAR 26 /* control Z character */
|
||||
|
||||
/* Simulator stop codes */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_OPCODE 4
|
||||
|
||||
#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */
|
||||
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
|
||||
#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */
|
||||
#define UNIT_CHIP (1 << UNIT_V_CHIP)
|
||||
#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */
|
||||
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
||||
408
AltairZ80/altairZ80_dsk.c
Normal file
408
AltairZ80/altairZ80_dsk.c
Normal file
@@ -0,0 +1,408 @@
|
||||
/* altairZ80_dsk.c: MITS Altair 88-DISK Simulator
|
||||
Written by Charles E Owen ((c) 1997, Commercial use prohibited)
|
||||
Minor modifications by Peter Schorn, 2001
|
||||
|
||||
The 88_DISK is a 8-inch floppy controller which can control up
|
||||
to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives.
|
||||
Each diskette has physically 77 tracks of 32 137-byte sectors
|
||||
each.
|
||||
|
||||
The controller is interfaced to the CPU by use of 3 I/O addreses,
|
||||
standardly, these are device numbers 10, 11, and 12 (octal).
|
||||
|
||||
Address Mode Function
|
||||
------- ---- --------
|
||||
|
||||
10 Out Selects and enables Controller and Drive
|
||||
10 In Indicates status of Drive and Controller
|
||||
11 Out Controls Disk Function
|
||||
11 In Indicates current sector position of disk
|
||||
12 Out Write data
|
||||
12 In Read data
|
||||
|
||||
Drive Select Out (Device 10 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| C | X | X | X | Device |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
C = If this bit is 1, the disk controller selected by 'device' is
|
||||
cleared. If the bit is zero, 'device' is selected as the
|
||||
device being controlled by subsequent I/O operations.
|
||||
X = not used
|
||||
Device = value zero thru 15, selects drive to be controlled.
|
||||
|
||||
Drive Status In (Device 10 IN):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| R | Z | I | X | X | H | M | W |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
W - When 0, write circuit ready to write another byte.
|
||||
M - When 0, head movement is allowed
|
||||
H - When 0, indicates head is loaded for read/write
|
||||
X - not used (will be 0)
|
||||
I - When 0, indicates interrupts enabled (not used this simulator)
|
||||
Z - When 0, indicates head is on track 0
|
||||
R - When 0, indicates that read circuit has new byte to read
|
||||
|
||||
Drive Control (Device 11 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| W | C | D | E | U | H | O | I |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
I - When 1, steps head IN one track
|
||||
O - When 1, steps head OUT one track
|
||||
H - When 1, loads head to drive surface
|
||||
U - When 1, unloads head
|
||||
E - Enables interrupts (ignored this simulator)
|
||||
D - Disables interrupts (ignored this simulator)
|
||||
C - When 1 lowers head current (ignored this simulator)
|
||||
W - When 1, starts Write Enable sequence: W bit on device 10
|
||||
(see above) will go 1 and data will be read from port 12
|
||||
until 137 bytes have been read by the controller from
|
||||
that port. The W bit will go off then, and the sector data
|
||||
will be written to disk. Before you do this, you must have
|
||||
stepped the track to the desired number, and waited until
|
||||
the right sector number is presented on device 11 IN, then
|
||||
set this bit.
|
||||
|
||||
Sector Position (Device 11 IN):
|
||||
|
||||
As the sectors pass by the read head, they are counted and the
|
||||
number of the current one is available in this register.
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X | X | Sector Number | T |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
X = Not used
|
||||
Sector number = binary of the sector number currently under the
|
||||
head, 0-31.
|
||||
T = Sector True, is a 1 when the sector is positioned to read or
|
||||
write.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "altairZ80_defs.h"
|
||||
|
||||
#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */
|
||||
#define UNIT_ENABLE (1 << UNIT_V_ENABLE)
|
||||
#define DSK_SECTSIZE 137 /* size of sector */
|
||||
#define DSK_SECT 32 /* sectors per track */
|
||||
#define TRACKS 254 /* number of tracks,
|
||||
original Altair has 77 tracks only */
|
||||
#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT)
|
||||
#define DSK_SIZE (DSK_TRACSIZE * TRACKS)
|
||||
#define TRACE_IN_OUT 1
|
||||
#define TRACE_READ_WRITE 2
|
||||
#define TRACE_SECTOR_STUCK 4
|
||||
#define TRACE_TRACK_STUCK 8
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr);
|
||||
t_stat dsk_reset (DEVICE *dptr);
|
||||
void writebuf();
|
||||
|
||||
extern int32 PCX;
|
||||
extern FILE *sim_log;
|
||||
|
||||
/* Global data on status */
|
||||
|
||||
int32 cur_disk = 8; /* Currently selected drive */
|
||||
int32 cur_track[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff};
|
||||
int32 cur_sect[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff};
|
||||
int32 cur_byte[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff};
|
||||
int32 cur_flags[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int32 trace_flag = 0;
|
||||
int32 in9_count = 0;
|
||||
int32 in9_message = FALSE;
|
||||
|
||||
char dskbuf[DSK_SECTSIZE]; /* Data Buffer */
|
||||
int32 dirty = 0; /* 1 when buffer has unwritten data in it */
|
||||
UNIT *dptr; /* fileref to write dirty buffer to */
|
||||
|
||||
/* 88DSK Standard I/O Data Structures */
|
||||
|
||||
UNIT dsk_unit[] = {
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, DSK_SIZE) } };
|
||||
|
||||
REG dsk_reg[] = {
|
||||
{ DRDATA (DISK, cur_disk, 4) },
|
||||
{ ORDATA (TRACE, trace_flag, 8) },
|
||||
{ DRDATA (IN9, in9_count, 4), REG_RO },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE dsk_dev = {
|
||||
"DSK", dsk_unit, dsk_reg, NULL,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &dsk_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Service routines to handle simlulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dsk_reset (DEVICE *dptr)
|
||||
{
|
||||
cur_disk = 0;
|
||||
trace_flag = 0;
|
||||
in9_count = 0;
|
||||
in9_message = FALSE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
IN or OUT instruction is issued.
|
||||
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
*/
|
||||
|
||||
/* Disk Controller Status/Select */
|
||||
|
||||
/* IMPORTANT: The status flags read by port 8 IN instruction are
|
||||
INVERTED, that is, 0 is true and 1 is false. To handle this, the
|
||||
simulator keeps it's own status flags as 0=false, 1=true; and
|
||||
returns the COMPLEMENT of the status flags when read. This makes
|
||||
setting/testing of the flag bits more logical, yet meets the
|
||||
simulation requirement that they are reversed in hardware.
|
||||
*/
|
||||
|
||||
int32 dsk10(int32 io, int32 data)
|
||||
{
|
||||
in9_count = 0;
|
||||
if (io == 0) { /* IN: return flags */
|
||||
return ((~cur_flags[cur_disk]) & 0xFF); /* Return the COMPLEMENT! */
|
||||
}
|
||||
|
||||
/* OUT: Controller set/reset/enable/disable */
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
printf("\n[%x] OUT 08: %x", PCX, data);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] OUT 08: %x", PCX, data);
|
||||
}
|
||||
}
|
||||
cur_disk = data & 0x0F;
|
||||
if ((((dsk_dev.units + cur_disk) -> flags) & UNIT_ATT) == 0) { /* nothing attached? */
|
||||
cur_disk = 8;
|
||||
}
|
||||
else {
|
||||
cur_sect[cur_disk] = 0xff; /* reset internal counters */
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
cur_flags[cur_disk] = data & 0x80 ? 0 /* Disable drive */ :
|
||||
(cur_track[cur_disk] == 0 ? 0x5A /* Enable: head move true, track 0 if there */ :
|
||||
0x1A); /* Enable: head move true */
|
||||
}
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
|
||||
/* Disk Drive Status/Functions */
|
||||
|
||||
int32 dsk11(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) { /* Read sector position */
|
||||
in9_count++;
|
||||
if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2*DSK_SECT) && (!in9_message)) {
|
||||
in9_message = TRUE;
|
||||
printf("\n[%x] Looping on sector find %d.\n", PCX, cur_disk);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] Looping on sector find %d.\n", PCX, cur_disk);
|
||||
}
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
printf("\n[%x] IN 09", PCX);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] IN 09", PCX);
|
||||
}
|
||||
}
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
if (cur_flags[cur_disk] & 0x04) { /* head loaded? */
|
||||
cur_sect[cur_disk]++;
|
||||
if (cur_sect[cur_disk] >= DSK_SECT)
|
||||
cur_sect[cur_disk] = 0;
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
return (((cur_sect[cur_disk] << 1) & 0x3E) /* return 'sector true' bit = 0 (true) */
|
||||
| 0xC0); /* set on 'unused' bits */
|
||||
} else {
|
||||
return (0); /* head not loaded - return 0 */
|
||||
}
|
||||
}
|
||||
|
||||
in9_count = 0;
|
||||
/* Drive functions */
|
||||
|
||||
if (cur_disk > 7)
|
||||
return (0); /* no drive selected - can do nothing */
|
||||
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
printf("\n[%x] OUT 09: %x", PCX, data);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] OUT 09: %x", PCX, data);
|
||||
}
|
||||
}
|
||||
if (data & 0x01) { /* Step head in */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (cur_track[cur_disk] == (TRACKS-1)) {
|
||||
printf("\n[%x] Unnecessary step in for disk %d", PCX, cur_disk);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] Unnecessary step in for disk %d", PCX, cur_disk);
|
||||
}
|
||||
}
|
||||
}
|
||||
cur_track[cur_disk]++;
|
||||
if (cur_track[cur_disk] > (TRACKS-1) )
|
||||
cur_track[cur_disk] = (TRACKS-1);
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
cur_sect[cur_disk] = 0xff;
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
}
|
||||
|
||||
if (data & 0x02) { /* Step head out */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (cur_track[cur_disk] == 0) {
|
||||
printf("\n[%x] Unnecessary step out for disk %d", PCX, cur_disk);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] Unnecessary step out for disk %d", PCX, cur_disk);
|
||||
}
|
||||
}
|
||||
}
|
||||
cur_track[cur_disk]--;
|
||||
if (cur_track[cur_disk] < 0) {
|
||||
cur_track[cur_disk] = 0;
|
||||
cur_flags[cur_disk] |= 0x40; /* track 0 if there */
|
||||
}
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
cur_sect[cur_disk] = 0xff;
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
}
|
||||
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
|
||||
if (data & 0x04) { /* Head load */
|
||||
cur_flags[cur_disk] |= 0x04; /* turn on head loaded bit */
|
||||
cur_flags[cur_disk] |= 0x80; /* turn on 'read data available */
|
||||
}
|
||||
|
||||
if (data & 0x08) { /* Head Unload */
|
||||
cur_flags[cur_disk] &= 0xFB; /* off on 'head loaded' */
|
||||
cur_flags[cur_disk] &= 0x7F; /* off on 'read data avail */
|
||||
cur_sect[cur_disk] = 0xff;
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
}
|
||||
|
||||
/* Interrupts & head current are ignored */
|
||||
|
||||
if (data & 0x80) { /* write sequence start */
|
||||
cur_byte[cur_disk] = 0;
|
||||
cur_flags[cur_disk] |= 0x01; /* enter new write data on */
|
||||
}
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
|
||||
/* Disk Data In/Out*/
|
||||
|
||||
inline int32 dskseek(UNIT *xptr) {
|
||||
return fseek(xptr -> fileref, DSK_TRACSIZE * cur_track[cur_disk] +
|
||||
DSK_SECTSIZE * cur_sect[cur_disk], SEEK_SET);
|
||||
}
|
||||
|
||||
int32 dsk12(int32 io, int32 data)
|
||||
{
|
||||
static int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
in9_count = 0;
|
||||
uptr = dsk_dev.units + cur_disk;
|
||||
if (io == 0) {
|
||||
if (cur_byte[cur_disk] >= DSK_SECTSIZE) {
|
||||
/* physically read the sector */
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
printf("\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk], cur_sect[cur_disk]);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk],
|
||||
cur_sect[cur_disk]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < DSK_SECTSIZE; i++) {
|
||||
dskbuf[i] = 0;
|
||||
}
|
||||
dskseek(uptr);
|
||||
fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
||||
cur_byte[cur_disk] = 0;
|
||||
}
|
||||
return (dskbuf[cur_byte[cur_disk]++] & 0xFF);
|
||||
}
|
||||
else {
|
||||
if (cur_byte[cur_disk] >= DSK_SECTSIZE) {
|
||||
writebuf();
|
||||
}
|
||||
else {
|
||||
dirty = 1;
|
||||
dptr = uptr;
|
||||
dskbuf[cur_byte[cur_disk]++] = data & 0xFF;
|
||||
}
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
void writebuf()
|
||||
{
|
||||
int32 i, rtn;
|
||||
|
||||
i = cur_byte[cur_disk]; /* null-fill rest of sector if any */
|
||||
while (i < DSK_SECTSIZE) {
|
||||
dskbuf[i++] = 0;
|
||||
}
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
printf("\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk,
|
||||
cur_track[cur_disk], cur_sect[cur_disk]);
|
||||
if (sim_log) {
|
||||
fprintf (sim_log, "\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk,
|
||||
cur_track[cur_disk], cur_sect[cur_disk]);
|
||||
}
|
||||
}
|
||||
if (dskseek(dptr)) {
|
||||
printf("\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk,
|
||||
cur_track[cur_disk], cur_sect[cur_disk]);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk,
|
||||
cur_track[cur_disk], cur_sect[cur_disk]);
|
||||
}
|
||||
}
|
||||
rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, dptr -> fileref);
|
||||
if (rtn != 1) {
|
||||
printf("\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk],
|
||||
cur_sect[cur_disk], rtn);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk],
|
||||
cur_sect[cur_disk], rtn);
|
||||
}
|
||||
}
|
||||
cur_flags[cur_disk] &= 0xFE; /* ENWD off */
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
dirty = 0;
|
||||
}
|
||||
434
AltairZ80/altairZ80_sio.c
Normal file
434
AltairZ80/altairZ80_sio.c
Normal file
@@ -0,0 +1,434 @@
|
||||
/* altairZ80_sio: MITS Altair serial I/O card
|
||||
Written by Peter Schorn, 2001
|
||||
Based on work by Charles E Owen ((c) 1997, Commercial use prohibited)
|
||||
|
||||
These functions support a simulated MITS 2SIO interface card.
|
||||
The card had two physical I/O ports which could be connected
|
||||
to any serial I/O device that would connect to a current loop,
|
||||
RS232, or TTY interface. Available baud rates were jumper
|
||||
selectable for each port from 110 to 9600.
|
||||
|
||||
All I/O is via programmed I/O. Each each has a status port
|
||||
and a data port. A write to the status port can select
|
||||
some options for the device (0x03 will reset the port).
|
||||
A read of the status port gets the port status:
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X X X X X X O I |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
I - A 1 in this bit position means a character has been received
|
||||
on the data port and is ready to be read.
|
||||
O - A 1 in this bit means the port is ready to receive a character
|
||||
on the data port and transmit it out over the serial line.
|
||||
|
||||
A read to the data port gets the buffered character, a write
|
||||
to the data port writes the character to the device.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "altairZ80_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include "sim_tmxr.h"
|
||||
|
||||
#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */
|
||||
#define UNIT_ANSI (1 << UNIT_V_ANSI)
|
||||
#define UNIT_V_UPPER (UNIT_V_UF + 1) /* uppper case mode */
|
||||
#define UNIT_UPPER (1 << UNIT_V_UPPER)
|
||||
#define UNIT_V_BS (UNIT_V_UF + 2) /* map delete to backspace */
|
||||
#define UNIT_BS (1 << UNIT_V_BS)
|
||||
#define Terminals 1 /* lines per mux */
|
||||
|
||||
TMLN TerminalLines[Terminals] = { { 0 } }; /* we only need one line */
|
||||
TMXR altairTMXR = {Terminals, 0, &TerminalLines[0] }; /* mux descriptor */
|
||||
|
||||
t_stat sio_svc (UNIT *uptr);
|
||||
t_stat sio_reset (DEVICE *dptr);
|
||||
t_stat sio_attach (UNIT *uptr, char *cptr);
|
||||
t_stat sio_detach (UNIT *uptr);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
int32 nulldev(int32 io, int32 data);
|
||||
int32 simh_dev(int32 io, int32 data);
|
||||
int32 sio0d(int32 io, int32 data);
|
||||
int32 sio0s(int32 io, int32 data);
|
||||
int32 sio1d(int32 io, int32 data);
|
||||
int32 sio1s(int32 io, int32 data);
|
||||
void attachCPM();
|
||||
|
||||
extern t_stat sim_activate (UNIT *uptr, int32 interval);
|
||||
extern t_stat sim_cancel (UNIT *uptr);
|
||||
extern t_stat sim_poll_kbd (void);
|
||||
extern t_stat sim_putchar (int32 out);
|
||||
extern t_stat attach_unit (UNIT *uptr, char *cptr);
|
||||
extern t_bool rtc_avail;
|
||||
extern FILE *sim_log;
|
||||
extern int32 sim_switches;
|
||||
extern uint32 sim_os_msec (void);
|
||||
extern uint8 M[MAXMEMSIZE];
|
||||
|
||||
/* 2SIO Standard I/O Data Structures */
|
||||
|
||||
UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG sio_reg[] = {
|
||||
{ HRDATA (DATA, sio_unit.buf, 8) },
|
||||
{ HRDATA (STAT, sio_unit.u3, 8) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB sio_mod[] = {
|
||||
{ UNIT_ANSI, 0, "TTY", "TTY", NULL }, /* keep bit 8 as is for output */
|
||||
{ UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, /* set bit 8 to 0 before output */
|
||||
{ UNIT_UPPER, 0, "ALL", "ALL", NULL }, /* do not change case of input characters */
|
||||
{ UNIT_UPPER, UNIT_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */
|
||||
{ UNIT_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */
|
||||
{ UNIT_BS, UNIT_BS, "DEL", "DEL", NULL }, /* map backspace to delete */
|
||||
{ 0 } };
|
||||
|
||||
DEVICE sio_dev = {
|
||||
"SIO", &sio_unit, sio_reg, sio_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &sio_reset,
|
||||
NULL, &sio_attach, &sio_detach };
|
||||
|
||||
UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG ptr_reg[] = {
|
||||
{ HRDATA (DATA, ptr_unit.buf, 8) },
|
||||
{ HRDATA (STAT, ptr_unit.u3, 8) },
|
||||
{ DRDATA (POS, ptr_unit.pos, 31) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ HRDATA (DATA, ptp_unit.buf, 8) },
|
||||
{ HRDATA (STAT, ptp_unit.u3, 8) },
|
||||
{ DRDATA (POS, ptp_unit.pos, 31) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
t_stat sio_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
return tmxr_attach (&altairTMXR, uptr, cptr); /* attach mux */
|
||||
}
|
||||
|
||||
/* Detach */
|
||||
|
||||
t_stat sio_detach (UNIT *uptr)
|
||||
{
|
||||
sio_unit.u3 = 0x02; /* Status */
|
||||
sio_unit.buf = 0; /* Data */
|
||||
return tmxr_detach (&altairTMXR, uptr);
|
||||
}
|
||||
|
||||
/* Service routines to handle simulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
t_stat sio_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&sio_unit, sio_unit.wait); /* continue poll */
|
||||
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
if (sim_poll_kbd () == SCPE_STOP) { /* listen for ^E */
|
||||
return SCPE_STOP;
|
||||
}
|
||||
temp = tmxr_poll_conn(&altairTMXR, &sio_unit); /* poll connection */
|
||||
if (temp >= 0) {
|
||||
altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */
|
||||
}
|
||||
tmxr_poll_rx(&altairTMXR); /* poll input */
|
||||
tmxr_poll_tx(&altairTMXR); /* poll output */
|
||||
}
|
||||
else {
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) {
|
||||
return temp; /* no char or error? */
|
||||
}
|
||||
sio_unit.buf = temp & 0xff; /* Save char */
|
||||
sio_unit.u3 |= 0x01; /* Set status */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ptp_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat sio_reset (DEVICE *dptr)
|
||||
{
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
if (altairTMXR.ldsc[0]->conn > 0) {
|
||||
tmxr_reset_ln(altairTMXR.ldsc[0]);
|
||||
}
|
||||
sio_unit.u3 = 0; /* Status */
|
||||
}
|
||||
else {
|
||||
sio_unit.u3 = 0x02; /* Status */
|
||||
}
|
||||
sio_unit.buf = 0; /* Data */
|
||||
sim_activate (&sio_unit, sio_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
ptr_unit.buf = 0;
|
||||
ptr_unit.u3 = 0;
|
||||
ptr_unit.pos = 0;
|
||||
if (ptr_unit.flags & UNIT_ATT) { /* attached? */
|
||||
rewind(ptr_dev.units -> fileref);
|
||||
}
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
ptp_unit.buf = 0;
|
||||
ptp_unit.u3 = 0x02;
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
IN or OUT instruction is issued.
|
||||
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
*/
|
||||
|
||||
int32 sio0s(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) { /* IN */
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
sio_unit.u3 = (((tmxr_rqln(altairTMXR.ldsc[0]) > 0 ? 0x01 : 0) | /* read possible if character available */
|
||||
(altairTMXR.ldsc[0]->conn == 0 ? 0 : 0x02))); /* write possible if connected */
|
||||
}
|
||||
return (sio_unit.u3);
|
||||
}
|
||||
else { /* OUT */
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
if (data == 0x03) { /* reset port! */
|
||||
sio_unit.u3 = 0;
|
||||
sio_unit.buf = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (data == 0x03) { /* reset port! */
|
||||
sio_unit.u3 = 0x02;
|
||||
sio_unit.buf = 0;
|
||||
}
|
||||
}
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
int32 sio0d(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) { /* IN */
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
sio_unit.buf = tmxr_getc_ln(altairTMXR.ldsc[0]) & 0xff;
|
||||
}
|
||||
sio_unit.u3 = sio_unit.u3 & 0xFE;
|
||||
if (sio_unit.flags & UNIT_BS) {
|
||||
if (sio_unit.buf == BACKSPACE_CHAR) {
|
||||
sio_unit.buf = DELETE_CHAR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sio_unit.buf == DELETE_CHAR) {
|
||||
sio_unit.buf = BACKSPACE_CHAR;
|
||||
}
|
||||
}
|
||||
return ((sio_unit.flags & UNIT_UPPER) ? toupper(sio_unit.buf) : sio_unit.buf);
|
||||
}
|
||||
else { /* OUT */
|
||||
if (sio_unit.flags & UNIT_ANSI) {
|
||||
data &= 0x7f;
|
||||
}
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
tmxr_putc_ln(altairTMXR.ldsc[0], data);
|
||||
}
|
||||
else {
|
||||
sim_putchar(data);
|
||||
}
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
/* Port 2 controls the PTR/PTP devices */
|
||||
|
||||
int32 sio1s(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) {
|
||||
/* reset I bit iff PTR unit not attached or no more data available. */
|
||||
/* O bit is always set since write always possible. */
|
||||
return ((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0) ? 0x02 : 0x03;
|
||||
}
|
||||
else { /* OUT */
|
||||
if (data == 0x03) {
|
||||
ptr_unit.u3 = 0;
|
||||
ptr_unit.buf = 0;
|
||||
ptr_unit.pos = 0;
|
||||
ptp_unit.u3 = 0;
|
||||
ptp_unit.buf = 0;
|
||||
ptp_unit.pos = 0;
|
||||
}
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
int32 sio1d(int32 io, int32 data)
|
||||
{
|
||||
int32 temp;
|
||||
if (io == 0) { /* IN */
|
||||
if (((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0))
|
||||
return (0); /* not attached or no more data available */
|
||||
if ((temp = getc(ptr_dev.units -> fileref)) == EOF) { /* end of file? */
|
||||
ptr_unit.u3 = 0x01;
|
||||
return (CONTROLZ_CHAR); /* control Z denotes end of text file in CP/M */
|
||||
}
|
||||
ptr_unit.pos++;
|
||||
return (temp & 0xFF);
|
||||
}
|
||||
else { /* OUT */
|
||||
putc(data, ptp_dev.units -> fileref);
|
||||
ptp_unit.pos++;
|
||||
return (0); /* ignored since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
int32 nulldev(int32 io, int32 data)
|
||||
{
|
||||
return (io == 0 ? 0xff : 0);
|
||||
}
|
||||
|
||||
#define splimit 10
|
||||
#define printTimeCmd 0
|
||||
#define markTimeCmd 1
|
||||
#define showTimeCmd 2
|
||||
#define resetPtrCmd 3
|
||||
#define attachCmd 4
|
||||
#define detachCmd 5
|
||||
#define resetCmd 6
|
||||
#define cpmCommandLineLength 128
|
||||
uint32 markTime[splimit];
|
||||
int32 markTimeSP = 0;
|
||||
char version[] = "SIMH001";
|
||||
int32 versionPos = 0;
|
||||
|
||||
/* The CP/M commandline is used as the name of a file and PTR is attached to it */
|
||||
void attachCPM() {
|
||||
char cpmCommandLine[cpmCommandLineLength];
|
||||
uint32 i, len = (M[0x80] & 0x7f) - 1; /* 0x80 contains length of commandline, discard first char */
|
||||
for (i = 0; i < len; i++) {
|
||||
cpmCommandLine[i] = (char)M[0x82+i]; /* the first char, typically ' ', is discarded */
|
||||
}
|
||||
cpmCommandLine[i] = 0; /* make C string */
|
||||
sim_switches = SWMASK ('R');
|
||||
attach_unit(&ptr_unit, cpmCommandLine);
|
||||
}
|
||||
|
||||
/* port 0xfe is a device for communication SIMH <--> Altair machine */
|
||||
int32 simh_dev(int32 io, int32 data) {
|
||||
uint32 delta;
|
||||
int32 result;
|
||||
if (io == 0) { /* IN */
|
||||
result = version[versionPos++];
|
||||
if (result == 0) {
|
||||
versionPos = 0;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
else { /* OUT */
|
||||
switch(data) {
|
||||
case printTimeCmd: /* print time */
|
||||
if (rtc_avail) {
|
||||
printf("Current time in milliseconds = %d.\n", sim_os_msec ());
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "Current time in milliseconds = %d.\n", sim_os_msec ());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case markTimeCmd: /* mark time */
|
||||
if (rtc_avail) {
|
||||
if (markTimeSP < splimit) {
|
||||
markTime[markTimeSP++] = sim_os_msec ();
|
||||
}
|
||||
else {
|
||||
printf("Mark stack overflow.\n");
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "Mark stack overflow.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case showTimeCmd: /* show time difference */
|
||||
if (rtc_avail) {
|
||||
if (markTimeSP > 0) {
|
||||
delta = sim_os_msec () - markTime[--markTimeSP];
|
||||
printf("Delta to mark in milliseconds = %d.\n", delta);
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "Delta to mark in milliseconds = %d.\n", delta);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Missing mark.\n");
|
||||
if (sim_log) {
|
||||
fprintf(sim_log, "Missing mark.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case resetPtrCmd: /* reset ptr device */
|
||||
ptr_reset(NULL);
|
||||
break;
|
||||
case attachCmd: /* attach ptr to the file with name at beginning of CP/M command line */
|
||||
attachCPM();
|
||||
break;
|
||||
case detachCmd: /* detach ptr */
|
||||
detach_unit(&ptr_unit);
|
||||
break;
|
||||
case resetCmd:
|
||||
versionPos = 0;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
return 0; /* ignored, since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
687
AltairZ80/altairZ80_sys.c
Normal file
687
AltairZ80/altairZ80_sys.c
Normal file
@@ -0,0 +1,687 @@
|
||||
/* altairz80_sys.c: MITS Altair system interface
|
||||
Written by Peter Schorn, 2001
|
||||
Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited)
|
||||
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "altairZ80_defs.h"
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE dsk_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern DEVICE sio_dev;
|
||||
extern DEVICE ptr_dev;
|
||||
extern DEVICE ptp_dev;
|
||||
extern uint8 M[];
|
||||
extern int32 saved_PC;
|
||||
|
||||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag);
|
||||
int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw);
|
||||
int32 checkbase(char ch, char *numString);
|
||||
int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result);
|
||||
int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, int32 *at, int32 *hat);
|
||||
int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]);
|
||||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw);
|
||||
int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics);
|
||||
|
||||
/* SCP data structures
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words needed for examine
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "Altair 8800 (Z80)";
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
int32 sim_emax = 4;
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev, &ptp_dev, &dsk_dev, NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unknown I/O Instruction",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Invalid Opcode" };
|
||||
|
||||
static char *Mnemonics8080[] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */
|
||||
"DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */
|
||||
"DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */
|
||||
"DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */
|
||||
"DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */
|
||||
"DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */
|
||||
"DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */
|
||||
"DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */
|
||||
"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */
|
||||
"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */
|
||||
"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */
|
||||
"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */
|
||||
"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */
|
||||
"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */
|
||||
"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */
|
||||
"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */
|
||||
"ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */
|
||||
"ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */
|
||||
"SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */
|
||||
"ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */
|
||||
"XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */
|
||||
"ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */
|
||||
"CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */
|
||||
"RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */
|
||||
"RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */
|
||||
"RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */
|
||||
"RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */
|
||||
"RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */
|
||||
"RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */
|
||||
"RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */
|
||||
"RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */
|
||||
};
|
||||
|
||||
static char *MnemonicsZ80[256] =
|
||||
{
|
||||
"NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA",
|
||||
"EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA",
|
||||
"DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA",
|
||||
"JR @h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA",
|
||||
"JR NZ,@h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA",
|
||||
"JR Z,@h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL",
|
||||
"JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF",
|
||||
"JR C,@h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF",
|
||||
"LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A",
|
||||
"LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A",
|
||||
"LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A",
|
||||
"LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A",
|
||||
"LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A",
|
||||
"LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A",
|
||||
"LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A",
|
||||
"LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A",
|
||||
"ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A",
|
||||
"ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A",
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A",
|
||||
"SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A",
|
||||
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A",
|
||||
"XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A",
|
||||
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A",
|
||||
"CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A",
|
||||
"RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h",
|
||||
"RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h",
|
||||
"RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h",
|
||||
"RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h",
|
||||
"RET PO", "POP HL", "JP PO,#h", "EX HL,(SP)", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h",
|
||||
"RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h",
|
||||
"RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h",
|
||||
"RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h"
|
||||
};
|
||||
|
||||
static char *MnemonicsCB[256] =
|
||||
{
|
||||
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A",
|
||||
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A",
|
||||
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A",
|
||||
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A",
|
||||
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A",
|
||||
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A",
|
||||
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A",
|
||||
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A",
|
||||
"BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A",
|
||||
"BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A",
|
||||
"BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A",
|
||||
"BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A",
|
||||
"BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A",
|
||||
"BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A",
|
||||
"BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A",
|
||||
"BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A",
|
||||
"RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A",
|
||||
"RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A",
|
||||
"RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A",
|
||||
"RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A",
|
||||
"RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A",
|
||||
"RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A",
|
||||
"RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A",
|
||||
"RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A",
|
||||
"SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A",
|
||||
"SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A",
|
||||
"SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A",
|
||||
"SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A",
|
||||
"SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A",
|
||||
"SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A",
|
||||
"SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A",
|
||||
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A"
|
||||
};
|
||||
|
||||
static char *MnemonicsED[256] =
|
||||
{
|
||||
"DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h",
|
||||
"DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh",
|
||||
"DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h",
|
||||
"DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh",
|
||||
"DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h",
|
||||
"DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh",
|
||||
"DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h",
|
||||
"DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh",
|
||||
"IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A",
|
||||
"IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A",
|
||||
"IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I",
|
||||
"IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R",
|
||||
"IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD",
|
||||
"IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD",
|
||||
"IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h",
|
||||
"IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh",
|
||||
"DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h",
|
||||
"DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh",
|
||||
"DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h",
|
||||
"DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh",
|
||||
"LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h",
|
||||
"LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh",
|
||||
"LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h",
|
||||
"LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh",
|
||||
"DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h",
|
||||
"DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh",
|
||||
"DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h",
|
||||
"DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh",
|
||||
"DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h",
|
||||
"DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh",
|
||||
"DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h",
|
||||
"DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh"
|
||||
};
|
||||
|
||||
static char *MnemonicsXX[256] =
|
||||
{
|
||||
"NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA",
|
||||
"EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA",
|
||||
"DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA",
|
||||
"JR @h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA",
|
||||
"JR NZ,@h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%h", "DEC I%h", "LD I%h,*h", "DAA",
|
||||
"JR Z,@h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%l", "DEC I%l", "LD I%l,*h", "CPL",
|
||||
"JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF",
|
||||
"JR C,@h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF",
|
||||
"LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%h", "LD B,I%l", "LD B,(I%+^h)", "LD B,A",
|
||||
"LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%h", "LD C,I%l", "LD C,(I%+^h)", "LD C,A",
|
||||
"LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%h", "LD D,I%l", "LD D,(I%+^h)", "LD D,A",
|
||||
"LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%h", "LD E,I%l", "LD E,(I%+^h)", "LD E,A",
|
||||
"LD I%h,B", "LD I%h,C", "LD I%h,D", "LD I%h,E", "LD I%h,I%h", "LD I%h,I%l", "LD H,(I%+^h)", "LD I%h,A",
|
||||
"LD I%l,B", "LD I%l,C", "LD I%l,D", "LD I%l,E", "LD I%l,I%h", "LD I%l,I%l", "LD L,(I%+^h)", "LD I%l,A",
|
||||
"LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A",
|
||||
"LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%h", "LD A,I%l", "LD A,(I%+^h)", "LD A,A",
|
||||
"ADD B", "ADD C", "ADD D", "ADD E", "ADD I%h", "ADD I%l", "ADD (I%+^h)", "ADD A",
|
||||
"ADC B", "ADC C", "ADC D", "ADC E", "ADC I%h", "ADC I%l", "ADC (I%+^h)", "ADC,A",
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", "SUB I%h", "SUB I%l", "SUB (I%+^h)", "SUB A",
|
||||
"SBC B", "SBC C", "SBC D", "SBC E", "SBC I%h", "SBC I%l", "SBC (I%+^h)", "SBC A",
|
||||
"AND B", "AND C", "AND D", "AND E", "AND I%h", "AND I%l", "AND (I%+^h)", "AND A",
|
||||
"XOR B", "XOR C", "XOR D", "XOR E", "XOR I%h", "XOR I%l", "XOR (I%+^h)", "XOR A",
|
||||
"OR B", "OR C", "OR D", "OR E", "OR I%h", "OR I%l", "OR (I%+^h)", "OR A",
|
||||
"CP B", "CP C", "CP D", "CP E", "CP I%h", "CP I%l", "CP (I%+^h)", "CP A",
|
||||
"RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h",
|
||||
"RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h",
|
||||
"RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h",
|
||||
"RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h",
|
||||
"RET PO", "POP I%", "JP PO,#h", "EX I%,(SP)", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h",
|
||||
"RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h",
|
||||
"RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h",
|
||||
"RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h"
|
||||
};
|
||||
|
||||
static char *MnemonicsXCB[256] =
|
||||
{
|
||||
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A",
|
||||
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A",
|
||||
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A",
|
||||
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A",
|
||||
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A",
|
||||
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A",
|
||||
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A",
|
||||
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A",
|
||||
"BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A",
|
||||
"BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A",
|
||||
"BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A",
|
||||
"BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A",
|
||||
"BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A",
|
||||
"BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A",
|
||||
"BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A",
|
||||
"BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A",
|
||||
"RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A",
|
||||
"RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A",
|
||||
"RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A",
|
||||
"RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A",
|
||||
"RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A",
|
||||
"RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A",
|
||||
"RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A",
|
||||
"RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A",
|
||||
"SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A",
|
||||
"SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A",
|
||||
"SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A",
|
||||
"SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A",
|
||||
"SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A",
|
||||
"SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A",
|
||||
"SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A",
|
||||
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A"
|
||||
};
|
||||
|
||||
/* Symbolic disassembler
|
||||
|
||||
Inputs:
|
||||
*val = instructions to disassemble
|
||||
useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used
|
||||
Outputs:
|
||||
*S = output text
|
||||
|
||||
DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997
|
||||
You are not allowed to distribute this software
|
||||
commercially.
|
||||
|
||||
*/
|
||||
|
||||
int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics)
|
||||
{
|
||||
char R[128], H[10], C= '\0', *T, *P;
|
||||
uint8 J = 0, Offset;
|
||||
uint16 B = 0;
|
||||
|
||||
if (useZ80Mnemonics) {
|
||||
switch(val[B]) {
|
||||
case 0xCB:
|
||||
B++;
|
||||
T = MnemonicsCB[val[B++]];
|
||||
break;
|
||||
case 0xED:
|
||||
B++;
|
||||
T = MnemonicsED[val[B++]];
|
||||
break;
|
||||
case 0xDD:
|
||||
case 0xFD:
|
||||
C = (val[B] == 0xDD) ? 'X' : 'Y';
|
||||
B++;
|
||||
if (val[B] == 0xCB) {
|
||||
B++;
|
||||
Offset = val[B++];
|
||||
J = 1;
|
||||
T = MnemonicsXCB[val[B++]];
|
||||
}
|
||||
else {
|
||||
T = MnemonicsXX[val[B++]];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
T = MnemonicsZ80[val[B++]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
T = Mnemonics8080[val[B++]];
|
||||
}
|
||||
|
||||
if (P = strchr(T, '^'))
|
||||
{
|
||||
strncpy(R, T, P - T);
|
||||
R[P - T] = '\0';
|
||||
sprintf(H, "%02X", val[B++]);
|
||||
strcat(R, H);
|
||||
strcat(R, P + 1);
|
||||
}
|
||||
else {
|
||||
strcpy(R, T);
|
||||
}
|
||||
if (P = strchr(R, '%')) {
|
||||
*P = C;
|
||||
if (P = strchr(P + 1, '%')) *P = C;
|
||||
}
|
||||
|
||||
if(P = strchr(R, '*')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
sprintf(H, "%02X", val[B++]);
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
}
|
||||
else if (P = strchr(R, '@')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
if(!J) {
|
||||
Offset = val[B++];
|
||||
}
|
||||
strcat(S, Offset & 0x80 ? "-" : "+");
|
||||
J = Offset & 0x80 ? 256 - Offset : Offset;
|
||||
sprintf(H, "%02X", J);
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
}
|
||||
else if (P = strchr(R, '#')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
sprintf(H, "%04X", val[B] + 256*val[B + 1]);
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
B += 2;
|
||||
}
|
||||
else {
|
||||
strcpy(S, R);
|
||||
}
|
||||
return(B);
|
||||
}
|
||||
|
||||
/* Symbolic output
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to values
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error code
|
||||
*/
|
||||
|
||||
int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw)
|
||||
{
|
||||
char disasm[128];
|
||||
int32 ch = val[0] & 0x7f;
|
||||
if (sw & (SWMASK ('A') | SWMASK ('C'))) {
|
||||
fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch);
|
||||
return SCPE_OK;
|
||||
}
|
||||
if (!(sw & SWMASK ('M'))) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP);
|
||||
fprintf(of, "%s", disasm);
|
||||
return (1-ch); /* need to return additional bytes */
|
||||
}
|
||||
|
||||
/* numString checks determines the base of the number (ch, *numString)
|
||||
and returns FALSE if the number is bad */
|
||||
int32 checkbase(char ch, char *numString) {
|
||||
int32 decimal = (ch <= '9');
|
||||
if (toupper(ch) == 'H') {
|
||||
return FALSE;
|
||||
}
|
||||
while (isxdigit(ch = *numString++)) {
|
||||
if (ch > '9') {
|
||||
decimal = FALSE;
|
||||
}
|
||||
}
|
||||
return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE);
|
||||
}
|
||||
|
||||
int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result) {
|
||||
int32 sign = 1, value = 0, base;
|
||||
if (requireSign) {
|
||||
if (ch == '+') {
|
||||
ch = *(*numString)++;
|
||||
}
|
||||
else if (ch == '-') {
|
||||
sign = -1;
|
||||
ch = *(*numString)++;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (!(base = checkbase(ch, *numString))) {
|
||||
return FALSE;
|
||||
}
|
||||
while (isxdigit(ch)) {
|
||||
value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10));
|
||||
ch = *(*numString)++;
|
||||
}
|
||||
if (toupper(ch) != 'H') {
|
||||
(*numString)--;
|
||||
}
|
||||
*result = value*sign;
|
||||
return (minvalue <= value) && (value <= maxvalue);
|
||||
}
|
||||
|
||||
int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star,
|
||||
int32 *at, int32 *hat) {
|
||||
char pat = *pattern++;
|
||||
char inp = *input++;
|
||||
while ((pat) && (inp)) {
|
||||
switch(pat) {
|
||||
case ',':
|
||||
if (inp == ' ') {
|
||||
inp = *input++;
|
||||
continue;
|
||||
}
|
||||
case ' ':
|
||||
if (inp != pat) {
|
||||
return FALSE;
|
||||
}
|
||||
pat = *pattern++;
|
||||
inp = *input++;
|
||||
while (inp == ' ') {
|
||||
inp = *input++;
|
||||
}
|
||||
continue;
|
||||
break;
|
||||
case '%':
|
||||
inp = toupper(inp);
|
||||
if ((inp == 'X') || (inp == 'Y')) {
|
||||
*xy = inp;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
if (numok(inp, &input, 0, 65535, FALSE, number)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (numok(inp, &input, 0, 255, FALSE, star)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (numok(inp, &input, -128, 65535, TRUE, at)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '^':
|
||||
if (numok(inp, &input, 0, 255, FALSE, hat)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (toupper(pat) != toupper(inp)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
pat = *pattern++;
|
||||
inp = *input++;
|
||||
}
|
||||
while (inp == ' ') {
|
||||
inp = *input++;
|
||||
}
|
||||
return (pat == 0) && (inp == 0);
|
||||
}
|
||||
|
||||
inline int32 checkXY(char xy) {
|
||||
if (xy == 'X') {
|
||||
return 0xDD;
|
||||
}
|
||||
else if (xy == 'Y') {
|
||||
return 0xFD;
|
||||
}
|
||||
else {
|
||||
printf("X or Y expected.\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) {
|
||||
char xy;
|
||||
int32 op, number, star, at, hat;
|
||||
for (op = 0; op < 256; op++) {
|
||||
number = star = at = -129;
|
||||
if (match(Mnemonics[op], cptr, &xy, &number, &star, &at, &hat)) {
|
||||
val[0] = op;
|
||||
if (number >= 0) {
|
||||
val[1] = (0xff) & number;
|
||||
val[2] = (0xff) & (number >> 8);
|
||||
return (-2); /* two additional bytes returned */
|
||||
}
|
||||
else if (star >= 0) {
|
||||
val[1] = (0xff) & star;
|
||||
return (-1); /* one additional byte returned */
|
||||
}
|
||||
else if (at > -129) {
|
||||
if (at > 127) { /* assume absolute address is meant */
|
||||
at -= addr + 2; /* translate to relative address */
|
||||
}
|
||||
if ((-128 <= at) && (at < 127)) {
|
||||
val[1] = (int8)(at);
|
||||
return (-1);
|
||||
}
|
||||
else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Mnemonics == Mnemonics8080) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
if (match(MnemonicsCB[op], cptr, &xy, &number, &star, &at, &hat)) {
|
||||
val[0] = 0xCB;
|
||||
val[1] = op;
|
||||
return (-1); /* one additional byte returned */
|
||||
}
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
number = -1;
|
||||
if (match(MnemonicsED[op], cptr, &xy, &number, &star, &at, &hat)) {
|
||||
val[0] = 0xED;
|
||||
val[1] = op;
|
||||
if (number >= 0) {
|
||||
val[2] = (0xff) & number;
|
||||
val[3] = (0xff) & (number >> 8);
|
||||
return (-3); /* three additional bytes returned */
|
||||
}
|
||||
else {
|
||||
return (-1); /* one additional byte returned */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
number = star = hat = -1;
|
||||
xy = ' ';
|
||||
if (match(MnemonicsXX[op], cptr, &xy, &number, &star, &at, &hat)) {
|
||||
if (!(val[0] = checkXY(xy))) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
val[1] = op;
|
||||
if (number >= 0) {
|
||||
val[2] = (0xff) & number;
|
||||
val[3] = (0xff) & (number >> 8);
|
||||
return (-3); /* three additional bytes returned */
|
||||
}
|
||||
else if ((star >= 0) && (hat >= 0)) {
|
||||
val[2] = (0xff) & hat;
|
||||
val[3] = (0xff) & star;
|
||||
return (-3); /* three additional bytes returned */
|
||||
}
|
||||
else if (star >= 0) {
|
||||
val[2] = (0xff) & star;
|
||||
return (-2); /* two additional bytes returned */
|
||||
}
|
||||
else if (hat >= 0) {
|
||||
val[2] = (0xff) & hat;
|
||||
return (-2); /* two additional bytes returned */
|
||||
}
|
||||
else {
|
||||
return (-1); /* one additional byte returned */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
at = -129;
|
||||
xy = ' ';
|
||||
if (match(MnemonicsXCB[op], cptr, &xy, &number, &star, &at, &hat)) {
|
||||
if (!(val[0] = checkXY(xy))) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
val[1] = 0xCB;
|
||||
if (at > -129) {
|
||||
val[2] = (int8) (at);
|
||||
}
|
||||
else {
|
||||
printf("Offset expected.\n");
|
||||
return SCPE_ARG;
|
||||
}
|
||||
val[3] = op;
|
||||
return (-3); /* three additional bytes returned */
|
||||
}
|
||||
}
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
|
||||
{
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & (SWMASK ('A') | SWMASK ('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) {
|
||||
return SCPE_ARG; /* must have 1 char */
|
||||
}
|
||||
val[0] = (uint32) cptr[0];
|
||||
return SCPE_OK;
|
||||
}
|
||||
return (cpu_unit.flags & UNIT_CHIP) ?
|
||||
parse_X80(cptr, addr, val, MnemonicsZ80) : parse_X80(cptr, addr, val, Mnemonics8080);
|
||||
}
|
||||
|
||||
|
||||
/* This is the binary loader. The input file is considered to be
|
||||
a string of literal bytes with no format special format. The
|
||||
load starts at the current value of the PC.
|
||||
*/
|
||||
|
||||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag)
|
||||
{
|
||||
int32 i, addr = 0, cnt = 0;
|
||||
|
||||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||||
addr = saved_PC;
|
||||
while ((i = getc (fileref)) != EOF) {
|
||||
M[addr++] = i;
|
||||
cnt++;
|
||||
} /* end while */
|
||||
printf ("%d Bytes loaded.\n", cnt);
|
||||
return (SCPE_OK);
|
||||
}
|
||||
Reference in New Issue
Block a user