mirror of
https://github.com/simh/simh.git
synced 2026-04-27 20:38:04 +00:00
Notes For V2.10-0
WARNING: V2.10 has reorganized and renamed some of the definition files for the PDP-10, PDP-11, and VAX. Be sure to delete all previous source files before you unpack the Zip archive, or unpack it into a new directory structure. WARNING: V2.10 has a new, more comprehensive save file format. Restoring save files from previous releases will cause 'invalid register' errors and loss of CPU option flags, device enable/ disable flags, unit online/offline flags, and unit writelock flags. WARNING: If you are using Visual Studio .NET through the IDE, be sure to turn off the /Wp64 flag in the project settings, or dozens of spurious errors will be generated. WARNING: Compiling Ethernet support under Windows requires extra steps; see the Ethernet readme file. Ethernet support is currently available only for Windows, Linux, NetBSD, and OpenBSD. 1. New Features 1.1 SCP and Libraries - The VT emulation package has been replaced by the capability to remote the console to a Telnet session. Telnet clients typically have more complete and robust VT100 emulation. - Simulated devices may now have statically allocated buffers, in addition to dynamically allocated buffers or disk-based data stores. - The DO command now takes substitutable arguments (max 9). In command files, %n represents substitutable argument n. - The initial command line is now interpreted as the command name and substitutable arguments for a DO command. This is backward compatible to prior versions. - The initial command line parses switches. -Q is interpreted as quiet mode; informational messages are suppressed. - The HELP command now takes an optional argument. HELP <cmd> types help on the specified command. - Hooks have been added for implementing GUI-based consoles, as well as simulator-specific command extensions. A few internal data structures and definitions have changed. - Two new routines (tmxr_open_master, tmxr_close_master) have been added to sim_tmxr.c. The calling sequence for sim_accept_conn has been changed in sim_sock.c. - The calling sequence for the VM boot routine has been modified to add an additional parameter. - SAVE now saves, and GET now restores, controller and unit flags. - Library sim_ether.c has been added for Ethernet support. 1.2 VAX - Non-volatile RAM (NVR) can behave either like a memory or like a disk-based peripheral. If unattached, it behaves like memory and is saved and restored by SAVE and RESTORE, respectively. If attached, its contents are loaded from disk by ATTACH and written back to disk at DETACH and EXIT. - SHOW <device> VECTOR displays the device's interrupt vector. A few devices allow the vector to be changed with SET <device> VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The TK50 (TMSCP tape) has been added. - The DEQNA/DELQA (Qbus Ethernet controllers) have been added. - Autoconfiguration support has been added. - The paper tape reader has been removed from vax_stddev.c and now references a common implementation file, dec_pt.h. - Examine and deposit switches now work on all devices, not just the CPU. - Device address conflicts are not detected until simulation starts. 1.3 PDP-11 - SHOW <device> VECTOR displays the device's interrupt vector. Most devices allow the vector to be changed with SET <device> VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk), RX211 (double density floppy), and KW11P programmable clock have been added. - The DEQNA/DELQA (Qbus Ethernet controllers) have been added. - Autoconfiguration support has been added. - The paper tape reader has been removed from pdp11_stddev.c and now references a common implementation file, dec_pt.h. - Device bootstraps now use the actual CSR specified by the SET ADDRESS command, rather than just the default CSR. Note that PDP-11 operating systems may NOT support booting with non-standard addresses. - Specifying more than 256KB of memory, or changing the bus configuration, causes all peripherals that are not compatible with the current bus configuration to be disabled. - Device address conflicts are not detected until simulation starts. 1.4 PDP-10 - SHOW <device> VECTOR displays the device's interrupt vector. A few devices allow the vector to be changed with SET <device> VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The RX211 (double density floppy) has been added; it is off by default. - The paper tape now references a common implementation file, dec_pt.h. - Device address conflicts are not detected until simulation starts. 1.5 PDP-1 - DECtape (then known as MicroTape) support has been added. - The line printer and DECtape can be disabled and enabled. 1.6 PDP-8 - The RX28 (double density floppy) has been added as an option to the existing RX8E controller. - SHOW <device> DEVNO displays the device's device number. Most devices allow the device number to be changed with SET <device> DEVNO=nnn. - Device number conflicts are not detected until simulation starts. 1.7 IBM 1620 - The IBM 1620 simulator has been released. 1.8 AltairZ80 - A hard drive has been added for increased storage. - Several bugs have been fixed. 1.9 HP 2100 - The 12845A has been added and made the default line printer (LPT). The 12653A has been renamed LPS and is off by default. It also supports the diagnostic functions needed to run the DCPC and DMS diagnostics. - The 12557A/13210A disk defaults to the 13210A (7900/7901). - The 12559A magtape is off by default. - New CPU options (EAU/NOEAU) enable/disable the extended arithmetic instructions for the 2116. These instructions are standard on the 2100 and 21MX. - New CPU options (MPR/NOMPR) enable/disable memory protect for the 2100 and 21MX. - New CPU options (DMS/NODMS) enable/disable the dynamic mapping instructions for the 21MX. - The 12539 timebase generator autocalibrates. 1.10 Simulated Magtapes - Simulated magtapes recognize end of file and the marker 0xFFFFFFFF as end of medium. Only the TMSCP tape simulator can generate an end of medium marker. - The error handling in simulated magtapes was overhauled to be consistent through all simulators. 1.11 Simulated DECtapes - Added support for RT11 image file format (256 x 16b) to DECtapes. 2. Release Notes 2.1 Bugs Fixed - TS11/TSV05 was not simulating the XS0_MOT bit, causing failures under VMS. In addition, two of the CTL options were coded interchanged. - IBM 1401 tape was not setting a word mark under group mark for load mode reads. This caused the diagnostics to crash. - SCP bugs in ssh_break and set_logon were fixed (found by Dave Hittner). - Numerous bugs in the HP 2100 extended arithmetic, floating point, 21MX, DMS, and IOP instructions were fixed. Bugs were also fixed in the memory protect and DMS functions. The moving head disks (DP, DQ) were revised to simulate the hardware more accurately. Missing functions in DQ (address skip, read address) were added. 2.2 HP 2100 Debugging - The HP 2100 CPU nows runs all of the CPU diagnostics. - The peripherals run most of the peripheral diagnostics. There is still a problem in overlapped seek operation on the disks. See the file hp2100_diag.txt for details. 3. In Progress These simulators are not finished and are available in a separate Zip archive distribution. - Interdata 16b/32b: coded, partially tested. See the file id_diag.txt for details. - SDS 940: coded, partially tested.
This commit is contained in:
committed by
Mark Pizzolato
parent
df6475181c
commit
2c2dd5ea33
@@ -4,6 +4,10 @@ Altair 8800 Simulator with Z80 support
|
||||
0. Revision History
|
||||
|
||||
Original version of this document written by Charles E Owen
|
||||
- 9-Oct-2002, Peter Schorn (added support for simulated hard disk)
|
||||
- 28-Sep-2002, Peter Schorn (number of tracks per disk can be configured)
|
||||
- 19-Sep-2002, Peter Schorn (added WARNROM feature)
|
||||
- 31-Aug-2002, Peter Schorn (added extended ROM features suggested by Scott LaBombard)
|
||||
- 4-May-2002, Peter Schorn (added description of MP/M II sample software)
|
||||
- 28-Apr-2002, Peter Schorn (added periodic timer interrupts and three
|
||||
additional consoles)
|
||||
@@ -78,7 +82,7 @@ a minimum of 24K.
|
||||
present and will always boot.
|
||||
|
||||
SET CPU BANKED Enables the banked memory support. The simulated memory
|
||||
has four banks with address range 0..'common' (see registers below)
|
||||
has eight banks with address range 0..'common' (see registers below)
|
||||
and a common area from 'common' to 0xfff which is common to all
|
||||
banks. The currently active bank is determined by register 'bank'
|
||||
(see below). You can only switch to banked memory if the memory
|
||||
@@ -86,18 +90,31 @@ a minimum of 24K.
|
||||
|
||||
SET CPU NONBANKED Disables banked memory support.
|
||||
|
||||
SET CPU ROM Enables the boot EPROM at address 0FF00H and prevents
|
||||
write access to the locations from 0FF00H to 0FFFFH. This is the
|
||||
default setting.
|
||||
SET CPU ROM Enables the ROM from address 'ROMLOW' to 'ROMHIGH'
|
||||
(see below under CPU Registers) and prevents write access
|
||||
to these locations. This is the default setting.
|
||||
|
||||
SET CPU NOROM Disables the boot EPROM at address 0FF00H and enables
|
||||
write access to the locations from 0FF00H to 0FFFFH.
|
||||
SET CPU NOROM Disables the ROM.
|
||||
|
||||
The BOOT EPROM card starts at address 0FF00H. Jumping to this address
|
||||
will boot drive 0 of the floppy controller (CPU must be set to ROM or
|
||||
equivalent code must be present). If no valid bootable software is
|
||||
present there the machine crashes. This is historically accurate
|
||||
behavior.
|
||||
SET CPU ALTAIRROM Enables the slightly modified but downwards compatible
|
||||
Altair boot ROM at addresses 0FF00 to 0FFFF. This is the default.
|
||||
|
||||
SET CPU NOALTAIRROM Disables standard Altair ROM behavior.
|
||||
|
||||
SET CPU WARNROM Enables warning messages to be printed when the CPU
|
||||
attempts to write into ROM or into non-existing memory. Also prints
|
||||
a warning message if the CPU attempts to read from non-existing
|
||||
memory.
|
||||
|
||||
SET CPU NOWARNROM Suppreses all warning message of "WARNROM". Note that
|
||||
some software tries on purpose to write to ROM in order to detect
|
||||
the available RAM.
|
||||
|
||||
The BOOT EPROM card starts at address 0FF00 if it has been enabled by 'SET
|
||||
CPU ALTAIRROM'. Jumping to this address will boot drive 0 of the floppy
|
||||
controller (CPU must be set to ROM or equivalent code must be present). If
|
||||
no valid bootable software is present there the machine crashes. This is
|
||||
historically accurate behavior.
|
||||
|
||||
The real 8080, on receiving a HLT (Halt) instruction, freezes the processor
|
||||
and only an interrupt or CPU hardware reset will restore it. The simulator
|
||||
@@ -105,7 +122,7 @@ is alot nicer, it will halt but send you back to the simulator command line.
|
||||
|
||||
CPU Registers include the following:
|
||||
|
||||
name size comments
|
||||
Name Size Comment
|
||||
|
||||
PC 16 The Program Counter
|
||||
AF 16 The accumulator and the flag register
|
||||
@@ -144,6 +161,8 @@ CPU Registers include the following:
|
||||
COMMON 16 The starting address of common memory. Originally set
|
||||
to 0xc000 (note this setting must agree with the
|
||||
value supplied to GENCPM for CP/M 3 system generation)
|
||||
ROMLOW 16 The starting address of the ROM. Default is 0FF00.
|
||||
ROMHIGH 16 The final address of the ROM. Default is 0FFFF.
|
||||
|
||||
2.2 The Serial I/O Card (2SIO)
|
||||
|
||||
@@ -213,7 +232,11 @@ 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).
|
||||
support up to 254 tracks (only relevant for CP/M). You can change the
|
||||
number of tracks per disk by setting the appropriate value in TRACKS[..].
|
||||
For example "D TRACKS[0] 77" sets the number of tracks for disk 0 to
|
||||
the original number of 77. The command "D TRACKS[0-7] 77" changes the
|
||||
highest track number for all disks to 77.
|
||||
|
||||
For debugging purposes you can set the trace level of some disk I/O
|
||||
functions. To do so the following bits in TRACE (a register of the disk)
|
||||
@@ -242,6 +265,26 @@ For example the command "D TRACE 10" will trace options 2+8 from above.
|
||||
will be allowed.
|
||||
|
||||
|
||||
2.5 The simulated hard disk
|
||||
|
||||
In order to increase the available storage capacity, the simulator
|
||||
features 8 simulated hard disks with a capacity of 8MB (HDSK0 to HDSK7).
|
||||
Currently only CP/M supports two hard disks as devices I: and J:.
|
||||
|
||||
For debugging purposes one can set the trace flag by executing the
|
||||
command "D HDTRACE 1". The default for "HDTRACE" is 0 (no trace).
|
||||
|
||||
The HDSK device can be configured with
|
||||
|
||||
SET HDSK<n> QUIET Do not print warning messages for hard disk <n>
|
||||
SET HDSK<n> VERBOSE Print warning messages for hard disk <n>
|
||||
(useful for debugging)
|
||||
|
||||
SET HDSK<n> WRITEENABLED Allow write operations for hard disk <n>
|
||||
SET HDSK<n> LOCKED Hard disk <n> is locked, i.e. no
|
||||
write operations will be allowed.
|
||||
|
||||
|
||||
3. Sample Software
|
||||
|
||||
Running an Altair in 1977 you would be running either MITS Disk
|
||||
@@ -282,74 +325,78 @@ R FOO.EXT under CP/M will transfer the file onto the CP/M disk.
|
||||
Transferring a file from the CP/M environment to the SIMH environment is
|
||||
accomplished by W <filename.ext>.
|
||||
|
||||
If you need more storage space you can use a simulated hard disk on
|
||||
drives I: and J:. To use do "attach HDSK0 hdi.dsk" and issue the
|
||||
"XFORMAT I:" resp. "XFORMAT J:" command from CP/M do initialize the disk
|
||||
to an empty state.
|
||||
|
||||
The disk "cpm2.dsk" contains the following files:
|
||||
Name Ext Size Comment
|
||||
ASM .COM 8K ; CP/M assembler
|
||||
BDOS .MAC 66K ; Basic Disk Operating System assembler source code
|
||||
BDOS .MAC 68K ; Basic Disk Operating System assembler source code
|
||||
BOOT .COM 1K ; transfer control to boot ROM
|
||||
BOOT .MAC 2K ; source for BOOT.COM
|
||||
BOOTGEN .COM 2K ; put a program on the boot sectors
|
||||
CBIOSX .MAC 10K ; CP/M 2 BIOS source for Altair
|
||||
CBIOSX .MAC 48K ; CP/M 2 BIOS source for Altair
|
||||
CCP .MAC 26K ; Console Command Processor assembler source code
|
||||
COPY .COM 1K ; copy disks
|
||||
COPY .COM 2K ; copy disks
|
||||
CPMBOOT .COM 12K ; CP/M operating system
|
||||
CREF80 .COM 4K ; cross reference utility
|
||||
DDT .COM 5K ; 8080 debugger
|
||||
DDT .COM 6K ; 8080 debugger
|
||||
DDTZ .COM 10K ; Z80 debugger
|
||||
DIF .COM 3K ; determine differences between two files
|
||||
DIF .COM 4K ; determine differences between two files
|
||||
DO .COM 2K ; batch processing
|
||||
DSKBOOT .COM 1K ; code for boot ROM
|
||||
DSKBOOT .MAC 3K ; source for boot ROM
|
||||
DUMP .COM 1K ; hex dump a file
|
||||
ED .COM 7K ; line editor
|
||||
ELIZA .BAS 9K ; Elisa game in Basic
|
||||
EX8080 .COM 9K ; exercise 8080 instruction set
|
||||
EX8080 .MAC 47K ; source for EX8080.COM
|
||||
EX8080 .SUB 1K ; benchmark execution of EX8080.COM
|
||||
EXZ80 .COM 9K ; exercise Z80 instruction set
|
||||
EXZ80 .MAC 47K ; source for EXZ80.COM
|
||||
EXZ80 .SUB 1K ; benchmark execution of EXZ80.COM
|
||||
DSKBOOT .MAC 8K ; source for boot ROM
|
||||
DUMP .COM 2K ; hex dump a file
|
||||
ED .COM 8K ; line editor
|
||||
ELIZA .BAS 10K ; Elisa game in Basic
|
||||
EX8080 .COM 10K ; exercise 8080 instruction set
|
||||
EX8080 .MAC 48K ; source for EX8080.COM
|
||||
EX8080 .SUB 2K ; benchmark execution of EX8080.COM
|
||||
EXZ80 .COM 10K ; exercise Z80 instruction set
|
||||
EXZ80 .MAC 48K ; source for EXZ80.COM
|
||||
EXZ80 .SUB 2K ; benchmark execution of EXZ80.COM
|
||||
FORMAT .COM 2K ; format disks
|
||||
GO .COM 0K ; start the currently loaded program at 100H
|
||||
L80 .COM 11K ; Microsoft linker
|
||||
HDSKBOOT.MAC 6K ; boot code for hard disk
|
||||
L80 .COM 12K ; Microsoft linker
|
||||
LADDER .COM 40K ; game
|
||||
LADDER .DAT 1K ; high score file for LADDER.COM
|
||||
LADDER .DAT 2K ; high score file for LADDER.COM
|
||||
LIB80 .COM 6K ; library utility
|
||||
LOAD .COM 2K ; load hex files
|
||||
LS .COM 3K ; directory utility
|
||||
LS .COM 4K ; directory utility
|
||||
LU .COM 20K ; library utility
|
||||
M80 .COM 20K ; Microsoft macro assembler
|
||||
MBASIC .COM 24K ; Microsoft Basic interpreter
|
||||
MC .SUB 1K ; assemble and link an assmbler program
|
||||
MCC .SUB 1K ; read, assemble and link an assmbler program
|
||||
MC .SUB 2K ; assemble and link an assembler program
|
||||
MCC .SUB 2K ; read, assemble and link an assembler program
|
||||
MCCL .SUB 2K ; assemble, link and produce listing
|
||||
MEMCFG .LIB 2K ; defines the memory configuration
|
||||
MOVER .MAC 2K ; moves operating system in place
|
||||
OTHELLO .COM 12K ; Othello (Reversi) game
|
||||
PIP .COM 8K ; Peripheral Interchange Program
|
||||
R .COM 3K ; read files from SIMH environment
|
||||
RSETSIMH.COM 1K ; reset SIMH interface
|
||||
RSETSIMH.MAC 1K ; assembler source for RSETSIMH.COM
|
||||
R .COM 4K ; read files from SIMH environment
|
||||
RSETSIMH.COM 2K ; reset SIMH interface
|
||||
RSETSIMH.MAC 2K ; assembler source for RSETSIMH.COM
|
||||
SHOWSEC .COM 3K ; show sectors on a disk
|
||||
SID .COM 8K ; debugger for 8080
|
||||
STAT .COM 6K ; provide information about currently logged disks
|
||||
SURVEY .COM 2K ; system survey
|
||||
SURVEY .MAC 15K ; assembler source for SURVEY.COM
|
||||
SURVEY .MAC 16K ; assembler source for SURVEY.COM
|
||||
SYSCOPY .COM 2K ; copy system tracks between disks
|
||||
SYSCPM2 .SUB 1K ; create CP/M 2 on drive A:
|
||||
TSHOW .COM 1K ; show split time
|
||||
TSHOW .MAC 1K ; assembler source for TSHOW.COM
|
||||
TSTART .COM 1K ; create timer and start it
|
||||
TSTART .MAC 1K ; assembler source for TSTART.COM
|
||||
TSTOP .COM 1K ; show final time and stop timer
|
||||
TSTOP .MAC 1K ; assembler source for TSTOP.COM
|
||||
UNCR .COM 7K ; un-crunch utility
|
||||
SYSCPM2 .SUB 2K ; create CP/M 2 on drive A:
|
||||
TIMER .COM 2K ; perform various timer operations
|
||||
TIMER .MAC 2K ; source code for TIMER.COM
|
||||
UNCR .COM 8K ; un-crunch utility
|
||||
UNERA .COM 2K ; un-erase a file
|
||||
UNERA .MAC 16K ; source for UNERA.COM
|
||||
USQ .COM 2K ; un-squeeze utility
|
||||
W .COM 3K ; write files to SIMH environment
|
||||
WM .COM 11K ; word master screen editor
|
||||
W .COM 4K ; write files to SIMH environment
|
||||
WM .COM 12K ; word master screen editor
|
||||
WM .HLP 3K ; help file for WM.COM
|
||||
WORM .COM 4K ; worm game for VT100 terminal
|
||||
XSUB .COM 1K ; support for DO.COM
|
||||
XFORMAT .COM 2K ; initialise a drive (floppy or hard disk)
|
||||
XSUB .COM 2K ; support for DO.COM
|
||||
ZSID .COM 10K ; debugger for Z80
|
||||
ZTRAN4 .COM 4K ; translate 8080 mnemonics into Z80 equivalents
|
||||
|
||||
@@ -457,6 +504,7 @@ version supports four terminals available via Telnet. To boot:
|
||||
sim> set cpu rom
|
||||
sim> set cpu banked
|
||||
sim> attach sio 23
|
||||
sim> d common b000
|
||||
sim> boot dsk
|
||||
|
||||
Now connect a Telnet session to the simulator and type "MPM" at the "A>"
|
||||
@@ -622,6 +670,8 @@ TERMBDOS.SPL 2K ; terminal interface to CP/M for PROLOGZ, SPL source
|
||||
UTIL .SPL 18K ; utility functions for PROLOGZ, SPL source
|
||||
WRITE .COM 4K
|
||||
WRITE .SPL 8K ; SPL source for W.COM
|
||||
XFORMAT .COM 2K
|
||||
XFORMAT .SPL 6K ; SPL source for XFORMAT.COM
|
||||
|
||||
|
||||
3.6 MITS Disk Extended BASIC Version 4.1
|
||||
@@ -658,6 +708,8 @@ ran under. To boot:
|
||||
irrelevant. A short attempted tour will reveal it to be a dog, far inferior
|
||||
to CP/M. To boot:
|
||||
|
||||
sim> d tracks[0-7] 77 ;set to Altair settings
|
||||
sim> set cpu altairrom
|
||||
sim> attach dsk altdos.dsk
|
||||
sim> set sio upper
|
||||
sim> go ff00
|
||||
@@ -723,7 +775,7 @@ is to get the Switch Register right).
|
||||
|
||||
|
||||
3.10 Altair Basic 4.0
|
||||
Execute the following commands to run Altair Extended Basic.
|
||||
Execute the following commands to run Altair Extended Basic:
|
||||
|
||||
sim> set sio upper ;Extended Basic does not like lower case letters as input
|
||||
sim> set sio ansi ;Extended Basic produces 8-bit output, strip to seven bits
|
||||
@@ -742,6 +794,29 @@ is to get the Switch Register right).
|
||||
OK
|
||||
|
||||
|
||||
3.11 Altair Disk Extended Basic Version 300-5-C
|
||||
This version of Basic was provided by Scott LaBombard. To execute use the
|
||||
following commands:
|
||||
|
||||
sim> d tracks[0-7] 77 ;set to Altair settings
|
||||
sim> at dsk extbas5.dsk
|
||||
sim> g 0
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
LINEPRINTER? [C]
|
||||
HIGHEST DISK NUMBER? [0]
|
||||
HOW MANY FILES? [3]
|
||||
HOW MANY RANDOM FILES? [3]
|
||||
|
||||
42082 BYTES FREE
|
||||
|
||||
ALTAIR DISK EXTENDED BASIC
|
||||
VERSION 300-5-C [01NOV78]
|
||||
COPYRIGHT 1978 BY MITS INC.
|
||||
|
||||
OK
|
||||
|
||||
|
||||
4. Special simulator features
|
||||
In addition to the regular SIMH features such as PC queue, breakpoints
|
||||
etc., this simulator supports memory access breakpoints. A memory access
|
||||
|
||||
@@ -1,27 +1,46 @@
|
||||
/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80)
|
||||
Written by Peter Schorn, 2001-2002
|
||||
Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited)
|
||||
Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license)
|
||||
|
||||
Copyright (c) 2002, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Peter Schorn shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Peter Schorn.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "altairZ80_defs.h"
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
#define PCQ_SIZE 64 /* must be 2**n */
|
||||
#define PCQ_SIZE 64 /* must be 2**n */
|
||||
#define PCQ_MASK (PCQ_SIZE - 1)
|
||||
#define PCQ_ENTRY(PC) pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
|
||||
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define KB 1024 /* kilo byte */
|
||||
#define bootrom_origin 0xff00 /* start address of boot rom */
|
||||
|
||||
/* Simulator stop codes */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint (program counter) */
|
||||
#define STOP_MEM 4 /* breakpoint (memory access) */
|
||||
#define STOP_OPCODE 5 /* unknown 8080 or Z80 instruction */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint (program counter) */
|
||||
#define STOP_MEM 4 /* breakpoint (memory access) */
|
||||
#define STOP_OPCODE 5 /* unknown 8080 or Z80 instruction */
|
||||
|
||||
/*-------------------------------- definitions for memory space ------------------*/
|
||||
/*-------------------------------- definitions for memory space --------------------*/
|
||||
|
||||
uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */
|
||||
|
||||
@@ -55,12 +74,12 @@ uint16 IFF;
|
||||
#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0)
|
||||
|
||||
#define ldig(x) ((x) & 0xf)
|
||||
#define hdig(x) (((x)>>4)&0xf)
|
||||
#define lreg(x) ((x)&0xff)
|
||||
#define hreg(x) (((x)>>8)&0xff)
|
||||
#define hdig(x) (((x) >> 4) & 0xf)
|
||||
#define lreg(x) ((x) & 0xff)
|
||||
#define hreg(x) (((x) >> 8) & 0xff)
|
||||
|
||||
#define Setlreg(x, v) x = (((x)&0xff00) | ((v)&0xff))
|
||||
#define Sethreg(x, v) x = (((x)&0xff) | (((v)&0xff) << 8))
|
||||
#define Setlreg(x, v) x = (((x) & 0xff00) | ((v) & 0xff))
|
||||
#define Sethreg(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8))
|
||||
|
||||
/* SetPV and SetPV2 are used to provide correct parity flag semantics for the 8080 in cases
|
||||
where the Z80 uses the overflow flag
|
||||
@@ -70,7 +89,7 @@ uint16 IFF;
|
||||
|
||||
/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */
|
||||
#define checkCPU8080 \
|
||||
if ((cpu_unit.flags & UNIT_CHIP == 0) && (cpu_unit.flags & UNIT_OPSTOP)) { \
|
||||
if (((cpu_unit.flags & UNIT_CHIP) == 0) && (cpu_unit.flags & UNIT_OPSTOP)) { \
|
||||
reason = STOP_OPCODE; \
|
||||
goto end_decode; \
|
||||
}
|
||||
@@ -101,7 +120,7 @@ static const uint8 partab[256] = {
|
||||
4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4,
|
||||
};
|
||||
|
||||
#define parity(x) partab[(x)&0xff]
|
||||
#define parity(x) partab[(x) & 0xff]
|
||||
|
||||
#define POP(x) do { \
|
||||
register uint32 y = RAM_pp(SP); \
|
||||
@@ -132,11 +151,13 @@ static const uint8 partab[256] = {
|
||||
} \
|
||||
}
|
||||
|
||||
int32 saved_PC = 0; /* program counter */
|
||||
int32 SR = 0; /* switch register */
|
||||
int32 PCX; /* External view of PC */
|
||||
int32 bankSelect = 0; /* determines selected memory bank */
|
||||
uint32 common = 0xc000; /* addresses >= 'common' are in common memory */
|
||||
int32 saved_PC = 0; /* program counter */
|
||||
int32 SR = 0; /* switch register */
|
||||
int32 PCX; /* External view of PC */
|
||||
int32 bankSelect = 0; /* determines selected memory bank */
|
||||
uint32 common = 0xc000; /* addresses >= 'common' are in common memory */
|
||||
uint32 ROMLow = defaultROMLow; /* lowest address of ROM */
|
||||
uint32 ROMHigh = defaultROMHigh; /* highest address of ROM */
|
||||
|
||||
extern int32 sim_int_char;
|
||||
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
|
||||
@@ -148,10 +169,13 @@ extern int32 dsk10 (int32 port, int32 io, int32 data);
|
||||
extern int32 dsk11 (int32 port, int32 io, int32 data);
|
||||
extern int32 dsk12 (int32 port, int32 io, int32 data);
|
||||
extern int32 nulldev (int32 port, int32 io, int32 data);
|
||||
extern int32 hdsk_io (int32 port, int32 io, int32 data);
|
||||
extern int32 simh_dev (int32 port, int32 io, int32 data);
|
||||
extern int32 sr_dev (int32 port, int32 io, int32 data);
|
||||
extern int32 bootrom[bootrom_size];
|
||||
extern char memoryAccessMessage[];
|
||||
extern char messageBuffer[];
|
||||
extern void printMessage(void);
|
||||
|
||||
/* function prototypes */
|
||||
t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
@@ -160,22 +184,32 @@ t_stat cpu_reset(DEVICE *dptr);
|
||||
t_stat cpu_set_size(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc);
|
||||
t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc);
|
||||
t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc);
|
||||
t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc);
|
||||
uint32 in(uint32 Port);
|
||||
void out(uint32 Port, uint32 Value);
|
||||
uint8 GetBYTE(register uint32 Addr);
|
||||
void PutBYTE(register uint32 Addr, register uint32 Value);
|
||||
void PutBYTEForced(register uint32 Addr, register uint32 Value);
|
||||
int32 addressIsInROM(uint32 Addr);
|
||||
int32 addressExists(uint32 Addr);
|
||||
uint16 GetWORD(register uint32 a);
|
||||
void PutWORD(register uint32 a, register uint32 v);
|
||||
int32 sim_instr (void);
|
||||
void install_bootrom(void);
|
||||
void clear_memory(int32 starting);
|
||||
int32 sim_instr(void);
|
||||
int32 install_bootrom(void);
|
||||
void reset_memory(void);
|
||||
t_bool sim_brk_lookup (t_addr bloc, int32 btyp);
|
||||
void prepareMemoryAccessMessage(t_addr loc);
|
||||
void checkROMBoundaries(void);
|
||||
void warnUnsuccessfulWriteAttempt(uint32 Addr);
|
||||
uint8 warnUnsuccessfulReadAttempt(uint32 Addr);
|
||||
t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc);
|
||||
void protect(int32 l, int32 h);
|
||||
void resetCell(int32 address, int32 bank);
|
||||
|
||||
#ifndef NO_INLINE
|
||||
/* in case of using inline we need to ensure that the GetBYTE and PutBYTE
|
||||
are accessible externally */
|
||||
#ifndef NO_INLINE
|
||||
uint8 GetBYTEWrapper(register uint32 Addr);
|
||||
void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
#endif
|
||||
@@ -187,7 +221,7 @@ void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
cpu_mod CPU modifiers list
|
||||
*/
|
||||
|
||||
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM, MAXMEMSIZE) };
|
||||
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM + UNIT_ALTAIRROM, MAXMEMSIZE) };
|
||||
|
||||
int32 AF_S;
|
||||
int32 BC_S;
|
||||
@@ -226,37 +260,50 @@ REG cpu_reg[] = {
|
||||
{ HRDATA (SR, SR, 8) },
|
||||
{ HRDATA (BANK, bankSelect, MAXBANKSLOG2) },
|
||||
{ HRDATA (COMMON, common, 16) },
|
||||
{ HRDATA (ROMLOW, ROMLow, 16) },
|
||||
{ HRDATA (ROMHIGH, ROMHigh, 16) },
|
||||
{ HRDATA (CAPACITY, cpu_unit.capac, 17), REG_RO },
|
||||
{ BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC },
|
||||
{ DRDATA (PCQP, pcq_p, 6), REG_HRO },
|
||||
{ HRDATA (WRU, sim_int_char, 8) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB cpu_mod[] = {
|
||||
{ UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL },
|
||||
{ UNIT_CHIP, 0, "8080", "8080", NULL },
|
||||
{ UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL },
|
||||
{ UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL },
|
||||
{ UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked },
|
||||
{ UNIT_BANKED, 0, "NONBANKED", "NONBANKED", NULL },
|
||||
{ UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom },
|
||||
{ UNIT_ROM, 0, "NOROM", "NOROM", NULL },
|
||||
{ UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size },
|
||||
{ UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL },
|
||||
{ UNIT_CHIP, 0, "8080", "8080", NULL },
|
||||
{ UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL },
|
||||
{ UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL },
|
||||
{ UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked },
|
||||
{ UNIT_BANKED, 0, "NONBANKED", "NONBANKED", NULL },
|
||||
{ UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom },
|
||||
{ UNIT_ROM, 0, "NOROM", "NOROM", &cpu_set_norom },
|
||||
{ UNIT_ALTAIRROM, UNIT_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom },
|
||||
{ UNIT_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", NULL },
|
||||
{ UNIT_WARNROM, UNIT_WARNROM, "WARNROM", "WARNROM", &cpu_set_warnrom },
|
||||
{ UNIT_WARNROM, 0, "NOWARNROM", "NOWARNROM", NULL },
|
||||
{ UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 36 * KB, NULL, "36K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 40 * KB, NULL, "40K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 44 * KB, NULL, "44K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 52 * KB, NULL, "52K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 56 * KB, NULL, "56K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 60 * KB, NULL, "60K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE cpu_dev = {
|
||||
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
||||
1, 16, 16, 1, 16, 8,
|
||||
&cpu_ex, &cpu_dep, &cpu_reset,
|
||||
NULL, NULL, NULL };
|
||||
NULL, NULL, NULL, NULL, 0 };
|
||||
|
||||
/* data structure for IN/OUT instructions */
|
||||
struct idev {
|
||||
@@ -331,7 +378,7 @@ struct idev dev_table[256] = {
|
||||
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */
|
||||
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */
|
||||
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */
|
||||
{&nulldev}, {&nulldev}, {&simh_dev}, {&sr_dev} }; /* FC */
|
||||
{&nulldev}, {&hdsk_io}, {&simh_dev}, {&sr_dev} }; /* FC */
|
||||
|
||||
INLINE void out(uint32 Port, uint32 Value) {
|
||||
dev_table[Port].routine(Port, 1, Value);
|
||||
@@ -341,13 +388,52 @@ INLINE uint32 in(uint32 Port) {
|
||||
return dev_table[Port].routine(Port, 0, 0);
|
||||
}
|
||||
|
||||
void warnUnsuccessfulWriteAttempt(uint32 Addr) {
|
||||
if (cpu_unit.flags & UNIT_WARNROM) {
|
||||
if (addressIsInROM(Addr)) {
|
||||
message2("Attempt to write to ROM " AddressFormat ".\n", Addr);
|
||||
}
|
||||
else {
|
||||
message2("Attempt to write to non existing memory " AddressFormat ".\n", Addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 warnUnsuccessfulReadAttempt(uint32 Addr) {
|
||||
if (cpu_unit.flags & UNIT_WARNROM) {
|
||||
message2("Attempt to read from non existing memory " AddressFormat ".\n", Addr);
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* Determine whether Addr points to Read Only Memory */
|
||||
int32 addressIsInROM(uint32 Addr) {
|
||||
Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */
|
||||
return (cpu_unit.flags & UNIT_ROM) && ( /* must have ROM enabled */
|
||||
/* in banked case we have standard Altair ROM */
|
||||
((cpu_unit.flags & UNIT_BANKED) && (defaultROMLow <= Addr)) ||
|
||||
/* in non-banked case we check the bounds of the ROM */
|
||||
(((cpu_unit.flags & UNIT_BANKED) == 0) && (ROMLow <= Addr) && (Addr <= ROMHigh)));
|
||||
}
|
||||
|
||||
/* Determine whether Addr points to a valid memory address */
|
||||
int32 addressExists(uint32 Addr) {
|
||||
Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */
|
||||
return (cpu_unit.flags & UNIT_BANKED) || (Addr < MEMSIZE) ||
|
||||
((cpu_unit.flags & UNIT_BANKED) == 0) && (cpu_unit.flags & UNIT_ROM)
|
||||
&& (ROMLow <= Addr) && (Addr <= ROMHigh);
|
||||
}
|
||||
|
||||
INLINE uint8 GetBYTE(register uint32 Addr) {
|
||||
Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */
|
||||
if (cpu_unit.flags & UNIT_BANKED) {
|
||||
if (cpu_unit.flags & UNIT_BANKED) { /* banked memory case */
|
||||
/* if Addr below "common" take from selected bank, otherwise from bank 0 */
|
||||
return Addr < common ? M[Addr][bankSelect] : M[Addr][0];
|
||||
}
|
||||
else {
|
||||
return ((Addr < MEMSIZE) || (bootrom_origin <= Addr)) ? M[Addr][0] : 0xff;
|
||||
else { /* non-banked memory case */
|
||||
return ((Addr < MEMSIZE) ||
|
||||
(cpu_unit.flags & UNIT_ROM) && (ROMLow <= Addr) && (Addr <= ROMHigh)) ?
|
||||
M[Addr][0] : warnUnsuccessfulReadAttempt(Addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,26 +443,27 @@ INLINE void PutBYTE(register uint32 Addr, register uint32 Value) {
|
||||
if (Addr < common) {
|
||||
M[Addr][bankSelect] = Value;
|
||||
}
|
||||
else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) {
|
||||
else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) {
|
||||
M[Addr][0] = Value;
|
||||
}
|
||||
else {
|
||||
warnUnsuccessfulWriteAttempt(Addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) {
|
||||
if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) {
|
||||
M[Addr][0] = Value;
|
||||
}
|
||||
else {
|
||||
warnUnsuccessfulWriteAttempt(Addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PutBYTEForced(register uint32 Addr, register uint32 Value) {
|
||||
Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */
|
||||
if (cpu_unit.flags & UNIT_BANKED) {
|
||||
if (Addr < common) {
|
||||
M[Addr][bankSelect] = Value;
|
||||
}
|
||||
else {
|
||||
M[Addr][0] = Value;
|
||||
}
|
||||
if ((cpu_unit.flags & UNIT_BANKED) && (Addr < common)) {
|
||||
M[Addr][bankSelect] = Value;
|
||||
}
|
||||
else {
|
||||
M[Addr][0] = Value;
|
||||
@@ -389,25 +476,37 @@ INLINE void PutWORD(register uint32 Addr, register uint32 Value) {
|
||||
if (Addr < common) {
|
||||
M[Addr][bankSelect] = Value;
|
||||
}
|
||||
else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) {
|
||||
else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) {
|
||||
M[Addr][0] = Value;
|
||||
}
|
||||
else {
|
||||
warnUnsuccessfulWriteAttempt(Addr);
|
||||
}
|
||||
Addr = (Addr + 1) & ADDRMASK;
|
||||
if (Addr < common) {
|
||||
M[Addr][bankSelect] = Value >> 8;
|
||||
}
|
||||
else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) {
|
||||
else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) {
|
||||
M[Addr][0] = Value >> 8;
|
||||
}
|
||||
else {
|
||||
warnUnsuccessfulWriteAttempt(Addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) {
|
||||
if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) {
|
||||
M[Addr][0] = Value;
|
||||
}
|
||||
else {
|
||||
warnUnsuccessfulWriteAttempt(Addr);
|
||||
}
|
||||
Addr = (Addr + 1) & ADDRMASK;
|
||||
if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) {
|
||||
if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) {
|
||||
M[Addr][0] = Value >> 8;
|
||||
}
|
||||
else {
|
||||
warnUnsuccessfulWriteAttempt(Addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,11 +673,11 @@ int32 sim_instr (void) {
|
||||
PCX = PC;
|
||||
sim_interval--;
|
||||
|
||||
/* make sure that each instructions properly sets sim_brk_pend:
|
||||
1) Either directly to FALSE if no memory access takes place or
|
||||
2) through a call to a Check... routine
|
||||
*/
|
||||
switch(RAM_pp(PC)) {
|
||||
/* make sure that each instructions properly sets sim_brk_pend:
|
||||
1) Either directly to FALSE if no memory access takes place or
|
||||
2) through a call to a Check... routine
|
||||
*/
|
||||
switch(RAM_pp(PC)) {
|
||||
case 0x00: /* NOP */
|
||||
sim_brk_pend = FALSE;
|
||||
break;
|
||||
@@ -966,7 +1065,7 @@ int32 sim_instr (void) {
|
||||
break;
|
||||
case 0x37: /* SCF */
|
||||
sim_brk_pend = FALSE;
|
||||
AF = (AF&~0x3b)|((AF>>8)&0x28)|1;
|
||||
AF = (AF & ~0x3b) | ((AF>>8) & 0x28) | 1;
|
||||
break;
|
||||
case 0x38: /* JR C,dd */
|
||||
sim_brk_pend = FALSE;
|
||||
@@ -1023,7 +1122,8 @@ int32 sim_instr (void) {
|
||||
break;
|
||||
case 0x3f: /* CCF */
|
||||
sim_brk_pend = FALSE;
|
||||
AF = (AF&~0x3b)|((AF>>8)&0x28)|((AF&1)<<4)|(~AF&1);
|
||||
AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) |
|
||||
((AF & 1) << 4) | (~AF & 1);
|
||||
break;
|
||||
case 0x40: /* LD B,B */
|
||||
sim_brk_pend = FALSE;
|
||||
@@ -1982,7 +2082,7 @@ int32 sim_instr (void) {
|
||||
else {
|
||||
AF = (AF & ~0xfe) | 0x54;
|
||||
}
|
||||
if ((op&7) != 6) {
|
||||
if ((op & 7) != 6) {
|
||||
AF |= (acu & 0x28);
|
||||
}
|
||||
temp = acu;
|
||||
@@ -2689,7 +2789,7 @@ int32 sim_instr (void) {
|
||||
else {
|
||||
AF = (AF & ~0xfe) | 0x54;
|
||||
}
|
||||
if ((op&7) != 6) {
|
||||
if ((op & 7) != 6) {
|
||||
AF |= (acu & 0x28);
|
||||
}
|
||||
temp = acu;
|
||||
@@ -3142,7 +3242,7 @@ int32 sim_instr (void) {
|
||||
sum = acu - temp;
|
||||
cbits = acu ^ temp ^ sum;
|
||||
AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) |
|
||||
(((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) |
|
||||
(((sum - ((cbits & 16)>>4)) & 2) << 4) | (cbits & 16) |
|
||||
((sum - ((cbits >> 4) & 1)) & 8) |
|
||||
((--BC & ADDRMASK) != 0) << 2 | 2;
|
||||
if ((sum & 15) == 8 && (cbits & 16) != 0) {
|
||||
@@ -3177,7 +3277,7 @@ int32 sim_instr (void) {
|
||||
sum = acu - temp;
|
||||
cbits = acu ^ temp ^ sum;
|
||||
AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) |
|
||||
(((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) |
|
||||
(((sum - ((cbits & 16)>>4)) & 2) << 4) | (cbits & 16) |
|
||||
((sum - ((cbits >> 4) & 1)) & 8) |
|
||||
((--BC & ADDRMASK) != 0) << 2 | 2;
|
||||
if ((sum & 15) == 8 && (cbits & 16) != 0) {
|
||||
@@ -3220,7 +3320,7 @@ int32 sim_instr (void) {
|
||||
} while (op && sum != 0);
|
||||
cbits = acu ^ temp ^ sum;
|
||||
AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) |
|
||||
(((sum - ((cbits&16)>>4))&2) << 4) |
|
||||
(((sum - ((cbits & 16)>>4)) & 2) << 4) |
|
||||
(cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) |
|
||||
op << 2 | 2;
|
||||
if ((sum & 15) == 8 && (cbits & 16) != 0) {
|
||||
@@ -3268,7 +3368,7 @@ int32 sim_instr (void) {
|
||||
} while (op && sum != 0);
|
||||
cbits = acu ^ temp ^ sum;
|
||||
AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) |
|
||||
(((sum - ((cbits&16)>>4))&2) << 4) |
|
||||
(((sum - ((cbits & 16)>>4)) & 2) << 4) |
|
||||
(cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) |
|
||||
op << 2 | 2;
|
||||
if ((sum & 15) == 8 && (cbits & 16) != 0) {
|
||||
@@ -3327,7 +3427,6 @@ int32 sim_instr (void) {
|
||||
sim_brk_pend = FALSE;
|
||||
JPC(!TSTFLAG(S));
|
||||
break;
|
||||
|
||||
case 0xf3: /* DI */
|
||||
sim_brk_pend = FALSE;
|
||||
IFF = 0;
|
||||
@@ -3959,7 +4058,7 @@ int32 sim_instr (void) {
|
||||
else {
|
||||
AF = (AF & ~0xfe) | 0x54;
|
||||
}
|
||||
if ((op&7) != 6) {
|
||||
if ((op & 7) != 6) {
|
||||
AF |= (acu & 0x28);
|
||||
}
|
||||
temp = acu;
|
||||
@@ -4055,28 +4154,60 @@ int32 sim_instr (void) {
|
||||
return reason;
|
||||
}
|
||||
|
||||
void install_bootrom(void) {
|
||||
int32 i;
|
||||
int32 install_bootrom(void) {
|
||||
int32 i, cnt = 0;
|
||||
for (i = 0; i < bootrom_size; i++) {
|
||||
M[i + bootrom_origin][0] = bootrom[i] & 0xff;
|
||||
if (M[i + defaultROMLow][0] != (bootrom[i] & 0xff)) {
|
||||
cnt++;
|
||||
M[i + defaultROMLow][0] = bootrom[i] & 0xff;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int32 lowProtect;
|
||||
int32 highProtect;
|
||||
int32 isProtected = FALSE;
|
||||
|
||||
void protect(int32 l, int32 h) {
|
||||
isProtected = TRUE;
|
||||
lowProtect = l;
|
||||
highProtect = h;
|
||||
}
|
||||
|
||||
void resetCell(int32 address, int32 bank) {
|
||||
if (!(isProtected && (bank == 0) && (lowProtect <= address) && (address <= highProtect))) {
|
||||
M[address][bank] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_memory(int32 starting) {
|
||||
int32 i, j;
|
||||
void reset_memory(void) {
|
||||
uint32 i, j;
|
||||
checkROMBoundaries();
|
||||
if (cpu_unit.flags & UNIT_BANKED) {
|
||||
for (i = 0; i < MAXMEMSIZE; i++) {
|
||||
for (j = 0; j < MAXBANKS; j++) {
|
||||
M[i][j] = 0;
|
||||
resetCell(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = starting; i < MAXMEMSIZE; i++) {
|
||||
M[i][0] = 0;
|
||||
else if (cpu_unit.flags & UNIT_ROM) {
|
||||
for (i = 0; i < ROMLow; i++) {
|
||||
resetCell(i, 0);
|
||||
}
|
||||
for (i = ROMHigh+1; i < MAXMEMSIZE; i++) {
|
||||
resetCell(i, 0);
|
||||
}
|
||||
}
|
||||
install_bootrom();
|
||||
else {
|
||||
for (i = 0; i < MAXMEMSIZE; i++) {
|
||||
resetCell(i, 0);
|
||||
}
|
||||
}
|
||||
if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) {
|
||||
install_bootrom();
|
||||
}
|
||||
isProtected = FALSE;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
@@ -4091,8 +4222,7 @@ t_stat cpu_reset(DEVICE *dptr) {
|
||||
INT_S = IX_S = IY_S = SP_S = 0;
|
||||
IFF_S = 3;
|
||||
bankSelect = 0;
|
||||
saved_PC = 0;
|
||||
clear_memory(0);
|
||||
reset_memory();
|
||||
sim_brk_types = (SWMASK('E') | SWMASK('M'));
|
||||
sim_brk_dflt = SWMASK('E');
|
||||
for (i = 0; i < PCQ_SIZE; i++) {
|
||||
@@ -4111,62 +4241,109 @@ t_stat cpu_reset(DEVICE *dptr) {
|
||||
|
||||
/* Memory examine */
|
||||
t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) {
|
||||
if (cpu_unit.flags & UNIT_BANKED) {
|
||||
if (addr >= MAXMEMSIZE) {
|
||||
return SCPE_NXM;
|
||||
if (addressExists(addr)) {
|
||||
if (vptr != NULL) {
|
||||
*vptr = GetBYTE(addr) & 0xff;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
else {
|
||||
if ((addr >= MEMSIZE) && (addr < bootrom_origin)) {
|
||||
return SCPE_NXM;
|
||||
}
|
||||
return SCPE_NXM;
|
||||
}
|
||||
if (vptr != NULL) {
|
||||
*vptr = GetBYTE(addr) & 0xff;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Memory deposit */
|
||||
t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) {
|
||||
if (cpu_unit.flags & UNIT_BANKED) {
|
||||
if ((addr >= bootrom_origin) && (cpu_unit.flags & UNIT_ROM)) {
|
||||
return SCPE_NXM;
|
||||
}
|
||||
if (addressExists(addr) && (!addressIsInROM(addr))) {
|
||||
PutBYTE(addr, val & 0xff);
|
||||
return SCPE_OK;
|
||||
}
|
||||
else {
|
||||
if ((addr >= MEMSIZE) || ((addr >= bootrom_origin) && (cpu_unit.flags & UNIT_ROM))) {
|
||||
return SCPE_NXM;
|
||||
return SCPE_NXM;
|
||||
}
|
||||
}
|
||||
|
||||
void checkROMBoundaries(void) {
|
||||
uint32 temp;
|
||||
if (ROMLow > ROMHigh) {
|
||||
printf("ROMLOW [%04X] must be less than or equal to ROMHIGH [%04X]. Values exchanged.\n",
|
||||
ROMLow, ROMHigh);
|
||||
temp = ROMLow;
|
||||
ROMLow = ROMHigh;
|
||||
ROMHigh = temp;
|
||||
}
|
||||
if (cpu_unit.flags & UNIT_ALTAIRROM) {
|
||||
if (defaultROMLow < ROMLow) {
|
||||
printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, defaultROMLow);
|
||||
ROMLow = defaultROMLow;
|
||||
}
|
||||
if (ROMHigh < defaultROMHigh) {
|
||||
printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, defaultROMHigh);
|
||||
ROMHigh = defaultROMHigh;
|
||||
}
|
||||
}
|
||||
PutBYTE(addr, val & 0xff);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
checkROMBoundaries();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
if (cpu_unit.flags & UNIT_ALTAIRROM) {
|
||||
printf("\"SET CPU NOALTAIRROM\" also executed.\n");
|
||||
cpu_unit.flags &= ~UNIT_ALTAIRROM;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
install_bootrom();
|
||||
if (ROMLow != defaultROMLow) {
|
||||
printf("\"D ROMLOW %04X\" also executed.\n", defaultROMLow);
|
||||
ROMLow = defaultROMLow;
|
||||
}
|
||||
if (ROMHigh != defaultROMHigh) {
|
||||
printf("\"D ROMHIGH %04X\" also executed.\n", defaultROMHigh);
|
||||
ROMHigh = defaultROMHigh;
|
||||
}
|
||||
if (!(cpu_unit.flags & UNIT_ROM)) {
|
||||
printf("\"SET CPU ROM\" also executed.\n");
|
||||
cpu_unit.flags |= UNIT_ROM;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
if ((!(cpu_unit.flags & UNIT_ROM)) && (MEMSIZE == 64*KB)) {
|
||||
printf("CPU has currently 64 Kb available for writing.\n");
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
return MEMSIZE < MAXMEMSIZE ? SCPE_ARG : SCPE_OK;
|
||||
if (common > defaultROMLow) {
|
||||
printf("Warning: COMMON [%04X] must not be greater than %04X. Reset to %04X.\n",
|
||||
common, defaultROMLow, defaultROMLow);
|
||||
common = defaultROMLow;
|
||||
}
|
||||
if (MEMSIZE < MAXMEMSIZE) {
|
||||
printf("\"SET CPU 64K\" also executed.\n");
|
||||
MEMSIZE = MAXMEMSIZE;
|
||||
reset_memory();
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
int32 i, limit, mc = 0;
|
||||
|
||||
if ((cpu_unit.flags & UNIT_BANKED) ||
|
||||
(value <= 0) || (value > MAXMEMSIZE) || ((value & 0xfff) != 0)) {
|
||||
return SCPE_ARG;
|
||||
if ((cpu_unit.flags & UNIT_BANKED) && (value < MAXMEMSIZE)) {
|
||||
printf("\"SET CPU NONBANKED\" also executed.\n");
|
||||
cpu_unit.flags &= ~UNIT_BANKED;
|
||||
}
|
||||
limit = (bootrom_origin < MEMSIZE) ? bootrom_origin : MEMSIZE;
|
||||
for (i = value; i < limit; i++) {
|
||||
mc |= GetBYTE(i);
|
||||
}
|
||||
if (mc && (!get_yn("Really truncate memory [N]?", FALSE))) {
|
||||
return SCPE_OK;
|
||||
if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xfff) != 0)) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
MEMSIZE = value;
|
||||
clear_memory(value);
|
||||
reset_memory();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1,38 +1,83 @@
|
||||
/* altairZ80_defs.h: MITS Altair simulator definitions
|
||||
Written by Peter Schorn, 2001-2002
|
||||
Based on work by Charles E Owen ((c) 1997, Commercial use prohibited)
|
||||
|
||||
Copyright (c) 2002, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Peter Schorn shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Peter Schorn.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator definitions */
|
||||
#include "sim_defs.h" /* simulator definitions */
|
||||
|
||||
/* Memory */
|
||||
#define MAXMEMSIZE 65536 /* max memory size */
|
||||
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
|
||||
#define bootrom_size 256 /* size of boot rom */
|
||||
#define MAXBANKS 8 /* max number of memory banks */
|
||||
#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */
|
||||
#define BANKMASK (MAXBANKS-1) /* bank mask */
|
||||
#define MAXMEMSIZE 65536 /* max memory size */
|
||||
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
|
||||
#define bootrom_size 256 /* size of boot rom */
|
||||
#define MAXBANKS 8 /* max number of memory banks */
|
||||
#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */
|
||||
#define BANKMASK (MAXBANKS-1) /* bank mask */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define KB 1024 /* kilo byte */
|
||||
#define defaultROMLow 0xff00 /* default for lowest addres of ROM */
|
||||
#define defaultROMHigh 0xffff /* default for highest addres of ROM */
|
||||
|
||||
#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)
|
||||
#define UNIT_V_BANKED (UNIT_V_UF+3) /* Banked memory is used */
|
||||
#define UNIT_BANKED (1 << UNIT_V_BANKED)
|
||||
#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */
|
||||
#define UNIT_ROM (1 << UNIT_V_ROM)
|
||||
#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */
|
||||
#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */
|
||||
#define unitNoOffset1 0x37 /* LD A,<unitno> */
|
||||
#define unitNoOffset2 0xb4 /* LD a,80h | <unitno> */
|
||||
|
||||
#define PCformat "\n[%04xh] "
|
||||
#define message1(p1) sprintf(messageBuffer,PCformat p1,PCX); printMessage()
|
||||
#define message2(p1,p2) sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage()
|
||||
#define message3(p1,p2,p3) sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage()
|
||||
#define message4(p1,p2,p3,p4) sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage()
|
||||
#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* 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)
|
||||
#define UNIT_V_BANKED (UNIT_V_UF+3) /* Banked memory is used */
|
||||
#define UNIT_BANKED (1 << UNIT_V_BANKED)
|
||||
#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */
|
||||
#define UNIT_ROM (1 << UNIT_V_ROM)
|
||||
#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */
|
||||
#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM)
|
||||
#define UNIT_V_WARNROM (UNIT_V_UF+6) /* Warn if ROM is written to */
|
||||
#define UNIT_WARNROM (1 << UNIT_V_WARNROM)
|
||||
|
||||
#define AddressFormat "[%04xh]"
|
||||
#define PCformat "\n" AddressFormat " "
|
||||
#define message1(p1) \
|
||||
sprintf(messageBuffer,PCformat p1,PCX); printMessage()
|
||||
#define message2(p1,p2) \
|
||||
sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage()
|
||||
#define message3(p1,p2,p3) \
|
||||
sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage()
|
||||
#define message4(p1,p2,p3,p4) \
|
||||
sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage()
|
||||
#define message5(p1,p2,p3,p4,p5) \
|
||||
sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage()
|
||||
#define message6(p1,p2,p3,p4,p5,p6) \
|
||||
sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage()
|
||||
|
||||
/* The Default is to use "inline". In this case the wrapper functions for
|
||||
GetBYTE and PutBYTE need to be created. Otherwise they are not needed
|
||||
and the calls map to the original functions. */
|
||||
and the calls map to the original functions. */
|
||||
#ifdef NO_INLINE
|
||||
#define INLINE
|
||||
#define GetBYTEWrapper GetBYTE
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
/* altairZ80_dsk.c: MITS Altair 88-DISK Simulator
|
||||
Written by Charles E Owen ((c) 1997, Commercial use prohibited)
|
||||
Modifications to improve robustness by Peter Schorn, 2001-2002
|
||||
|
||||
Copyright (c) 2002, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Peter Schorn shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Peter Schorn.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
|
||||
The 88_DISK is a 8-inch floppy controller which can control up
|
||||
to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives.
|
||||
@@ -42,7 +65,7 @@
|
||||
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)
|
||||
I - When 0, indicates interrupts enabled (not used by this simulator)
|
||||
Z - When 0, indicates head is on track 0
|
||||
R - When 0, indicates that read circuit has new byte to read
|
||||
|
||||
@@ -86,30 +109,29 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "altairZ80_defs.h"
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_WLK (1 << UNIT_V_UF)
|
||||
#define UNIT_V_DSKWLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_DSKWLK (1 << UNIT_V_DSKWLK)
|
||||
#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||
#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE)
|
||||
#define DSK_SECTSIZE 137 /* size of sector */
|
||||
#define DSK_SECT 32 /* sectors per track */
|
||||
#define TRACKS 254 /* number of tracks,
|
||||
#define MAX_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 MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS)
|
||||
#define TRACE_IN_OUT 1
|
||||
#define TRACE_READ_WRITE 2
|
||||
#define TRACE_SECTOR_STUCK 4
|
||||
#define TRACE_TRACK_STUCK 8
|
||||
#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */
|
||||
#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1)
|
||||
|
||||
int32 dsk10(int32 port, int32 io, int32 data);
|
||||
int32 dsk11(int32 port, int32 io, int32 data);
|
||||
int32 dsk12(int32 port, int32 io, int32 data);
|
||||
int32 dskseek(UNIT *xptr);
|
||||
t_stat dsk_boot(int32 unitno);
|
||||
t_stat dsk_boot(int32 unitno, DEVICE *dptr);
|
||||
t_stat dsk_reset(DEVICE *dptr);
|
||||
t_stat dsk_svc(UNIT *uptr);
|
||||
void writebuf(void);
|
||||
@@ -124,101 +146,101 @@ extern FILE *sim_log;
|
||||
extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
extern void printMessage(void);
|
||||
extern char messageBuffer[];
|
||||
extern void install_bootrom(void);
|
||||
extern int32 install_bootrom(void);
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
/* Global data on status */
|
||||
|
||||
int32 cur_disk = NUM_OF_DSK; /* Currently selected drive (values are 0 .. NUM_OF_DSK)
|
||||
int32 cur_disk = NUM_OF_DSK; /* Currently selected drive (values are 0 .. NUM_OF_DSK)
|
||||
cur_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */
|
||||
int32 cur_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int32 cur_sect [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int32 cur_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int32 cur_flags [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
||||
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS };
|
||||
int32 trace_flag = 0;
|
||||
int32 in9_count = 0;
|
||||
int32 in9_message = FALSE;
|
||||
int32 dirty = 0; /* 1 when buffer has unwritten data in it */
|
||||
int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */
|
||||
int32 warnLevelDSK = 3;
|
||||
int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int32 warnAttached[NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int32 warnDSK10 = 0;
|
||||
int32 warnDSK11 = 0;
|
||||
int32 warnDSK12 = 0;
|
||||
int8 dskbuf[DSK_SECTSIZE]; /* Data Buffer */
|
||||
|
||||
#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */
|
||||
#define unitNoOffset1 0x37 /* LD A,<unitno> */
|
||||
#define unitNoOffset2 0xb4 /* LD a,80h | <unitno> */
|
||||
int8 dskbuf[DSK_SECTSIZE]; /* Data Buffer */
|
||||
|
||||
/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */
|
||||
int32 bootrom[bootrom_size] = {
|
||||
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* fe00-fe07 */
|
||||
0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* fe08-fe0f */
|
||||
0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* fe10-fe17 */
|
||||
0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* fe18-fe1f */
|
||||
0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* fe20-fe27 */
|
||||
0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* fe28-fe2f */
|
||||
0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* fe30-fe37 */
|
||||
0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* fe38-fe3f */
|
||||
0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* fe40-fe47 */
|
||||
0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* fe48-fe4f */
|
||||
0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* fe50-fe57 */
|
||||
0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* fe58-fe5f */
|
||||
0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* fe60-fe67 */
|
||||
0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* fe68-fe6f */
|
||||
0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* fe70-fe77 */
|
||||
0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* fe78-fe7f */
|
||||
0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* fe80-fe87 */
|
||||
0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* fe88-fe8f */
|
||||
0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* fe90-fe97 */
|
||||
0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* fe98-fe9f */
|
||||
0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* fea0-fea7 */
|
||||
0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* fea8-feaf */
|
||||
0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* feb0-feb7 */
|
||||
0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* feb8-febf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fec0-fec7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fec8-fecf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fed0-fed7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fed8-fedf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fee0-fee7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fee8-feef */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fef0-fef7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fef8-feff */
|
||||
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */
|
||||
0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* ff08-ff0f */
|
||||
0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* ff10-ff17 */
|
||||
0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* ff18-ff1f */
|
||||
0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* ff20-ff27 */
|
||||
0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* ff28-ff2f */
|
||||
0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* ff30-ff37 */
|
||||
0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* ff38-ff3f */
|
||||
0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* ff40-ff47 */
|
||||
0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* ff48-ff4f */
|
||||
0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* ff50-ff57 */
|
||||
0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* ff58-ff5f */
|
||||
0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* ff60-ff67 */
|
||||
0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* ff68-ff6f */
|
||||
0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* ff70-ff77 */
|
||||
0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* ff78-ff7f */
|
||||
0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* ff80-ff87 */
|
||||
0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* ff88-ff8f */
|
||||
0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* ff90-ff97 */
|
||||
0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* ff98-ff9f */
|
||||
0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* ffa0-ffa7 */
|
||||
0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* ffa8-ffaf */
|
||||
0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* ffb0-ffb7 */
|
||||
0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffb8-ffbf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc0-ffc7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc8-ffcf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd0-ffd7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd8-ffdf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe0-ffe7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe8-ffef */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff0-fff7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff8-ffff */
|
||||
};
|
||||
|
||||
/* 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) } };
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } };
|
||||
|
||||
REG dsk_reg[] = {
|
||||
{ DRDATA (DISK, cur_disk, 4) },
|
||||
{ DRDATA (DSKWL, warnLevelDSK, 32) },
|
||||
{ ORDATA (TRACE, trace_flag, 8) },
|
||||
{ DRDATA (IN9, in9_count, 4), REG_RO },
|
||||
{ DRDATA (DISK, cur_disk, 4) },
|
||||
{ DRDATA (DSKWL, warnLevelDSK, 32) },
|
||||
{ ORDATA (TRACE, trace_flag, 8) },
|
||||
{ BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC },
|
||||
{ DRDATA (IN9, in9_count, 4), REG_RO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dsk_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ UNIT_DSKWLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_DSKWLK, UNIT_DSKWLK, "write locked", "LOCKED", NULL },
|
||||
/* quiet, no warning messages */
|
||||
{ UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
||||
/* verbose, show warning messages */
|
||||
{ UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &dsk_set_verbose },
|
||||
{ 0 } };
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dsk_dev = {
|
||||
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &dsk_reset,
|
||||
&dsk_boot, NULL, NULL };
|
||||
&dsk_boot, NULL, NULL, NULL, 0 };
|
||||
|
||||
void resetDSKWarningFlags(void) {
|
||||
int32 i;
|
||||
@@ -251,7 +273,7 @@ char* selectInOut(int32 io) {
|
||||
return io == 0 ? "IN" : "OUT";
|
||||
}
|
||||
|
||||
/* Service routines to handle simlulator functions */
|
||||
/* Service routines to handle simulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
@@ -271,22 +293,25 @@ t_stat dsk_reset(DEVICE *dptr) {
|
||||
}
|
||||
|
||||
/* The boot routine modifies the boot ROM in such a way that subsequently
|
||||
the specified disk is used for boot purposes. The program counter will reach
|
||||
the boot ROM by executing NOP instructions starting from address 0 until
|
||||
it reaches 0xff00.
|
||||
the specified disk is used for boot purposes.
|
||||
*/
|
||||
t_stat dsk_boot(int32 unitno) {
|
||||
install_bootrom();
|
||||
/* check whether we are really modifying an LD A,<> instruction */
|
||||
if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) {
|
||||
bootrom[unitNoOffset1] = unitno & 0xff; /* LD A,<unitno> */
|
||||
bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
|
||||
return SCPE_OK;
|
||||
}
|
||||
else { /* Attempt to modify non LD A,<> instructions is refused. */
|
||||
printf("Incorrect boot ROM offsets detected.\n");
|
||||
return SCPE_IERR;
|
||||
t_stat dsk_boot(int32 unitno, DEVICE *dptr) {
|
||||
if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) {
|
||||
if (install_bootrom()) {
|
||||
printf("ALTAIR boot ROM installed.\n");
|
||||
}
|
||||
/* check whether we are really modifying an LD A,<> instruction */
|
||||
if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) {
|
||||
bootrom[unitNoOffset1] = unitno & 0xff; /* LD A,<unitno> */
|
||||
bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
|
||||
}
|
||||
else { /* Attempt to modify non LD A,<> instructions is refused. */
|
||||
printf("Incorrect boot ROM offsets detected.\n");
|
||||
return SCPE_IERR;
|
||||
}
|
||||
}
|
||||
saved_PC = defaultROMLow;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
@@ -323,7 +348,7 @@ int32 dsk10(int32 port, int32 io, int32 data) {
|
||||
}
|
||||
|
||||
/* OUT: Controller set/reset/enable/disable */
|
||||
if (dirty == 1) {/* implies that cur_disk < NUM_OF_DSK */
|
||||
if (dirty) {/* implies that cur_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
@@ -369,7 +394,7 @@ int32 dsk11(int32 port, int32 io, int32 data) {
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message1("IN 0x09\n");
|
||||
}
|
||||
if (dirty == 1) {/* implies that cur_disk < NUM_OF_DSK */
|
||||
if (dirty) {/* implies that cur_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (cur_flags[cur_disk] & 0x04) { /* head loaded? */
|
||||
@@ -393,15 +418,15 @@ int32 dsk11(int32 port, int32 io, int32 data) {
|
||||
}
|
||||
if (data & 0x01) { /* Step head in */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (cur_track[cur_disk] == (TRACKS - 1)) {
|
||||
if (cur_track[cur_disk] == (tracks[cur_disk] - 1)) {
|
||||
message2("Unnecessary step in for disk %d\n", cur_disk);
|
||||
}
|
||||
}
|
||||
cur_track[cur_disk]++;
|
||||
if (cur_track[cur_disk] > (TRACKS - 1)) {
|
||||
cur_track[cur_disk] = (TRACKS - 1);
|
||||
if (cur_track[cur_disk] > (tracks[cur_disk] - 1)) {
|
||||
cur_track[cur_disk] = (tracks[cur_disk] - 1);
|
||||
}
|
||||
if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */
|
||||
if (dirty) { /* implies that cur_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
cur_sect[cur_disk] = 0xff;
|
||||
@@ -419,14 +444,14 @@ int32 dsk11(int32 port, int32 io, int32 data) {
|
||||
cur_track[cur_disk] = 0;
|
||||
cur_flags[cur_disk] |= 0x40; /* track 0 if there */
|
||||
}
|
||||
if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */
|
||||
if (dirty) { /* implies that cur_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
cur_sect[cur_disk] = 0xff;
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
}
|
||||
|
||||
if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */
|
||||
if (dirty) { /* implies that cur_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
|
||||
@@ -493,7 +518,7 @@ int32 dsk12(int32 port, int32 io, int32 data) {
|
||||
writebuf(); /* from above we have that cur_disk < NUM_OF_DSK */
|
||||
}
|
||||
else {
|
||||
dirty = 1; /* this guarantees for the next call to writebuf that cur_disk < NUM_OF_DSK */
|
||||
dirty = TRUE; /* this guarantees for the next call to writebuf that cur_disk < NUM_OF_DSK */
|
||||
dskbuf[cur_byte[cur_disk]++] = data & 0xff;
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
@@ -509,7 +534,7 @@ void writebuf(void) {
|
||||
dskbuf[i++] = 0;
|
||||
}
|
||||
uptr = dsk_dev.units + cur_disk;
|
||||
if (((uptr -> flags) & UNIT_WLK) == 0) { /* write enabled */
|
||||
if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
message4("OUT 0x0a (WRITE) D%d T%d S%d\n", cur_disk, cur_track[cur_disk], cur_sect[cur_disk]);
|
||||
}
|
||||
@@ -529,5 +554,5 @@ void writebuf(void) {
|
||||
}
|
||||
cur_flags[cur_disk] &= 0xfe; /* ENWD off */
|
||||
cur_byte[cur_disk] = 0xff;
|
||||
dirty = 0;
|
||||
dirty = FALSE;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
/* altairZ80_sio: MITS Altair serial I/O card
|
||||
Written by Peter Schorn, 2001-2002
|
||||
Based on work by Charles E Owen ((c) 1997, Commercial use prohibited)
|
||||
|
||||
Copyright (c) 2002, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Peter Schorn shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Peter Schorn.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
|
||||
These functions support a simulated MITS 2SIO interface card.
|
||||
The card had two physical I/O ports which could be connected
|
||||
@@ -29,7 +52,7 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "altairZ80_defs.h"
|
||||
#include "altairz80_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include "sim_tmxr.h"
|
||||
#include <time.h>
|
||||
@@ -164,7 +187,7 @@ SIO_TERMINAL sio_terminals[Terminals] = { {0, 0, 0x10, 0x11, 0x02},
|
||||
{0, 0, 0x16, 0x17, 0x00},
|
||||
{0, 0, 0x18, 0x19, 0x00} };
|
||||
TMLN TerminalLines[Terminals] = { {0} }; /* four terminals */
|
||||
TMXR altairTMXR = {Terminals, 0, NULL }; /* mux descriptor */
|
||||
TMXR altairTMXR = {Terminals, 0, 0 }; /* mux descriptor */
|
||||
|
||||
UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT };
|
||||
|
||||
@@ -200,7 +223,7 @@ 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 };
|
||||
NULL, &sio_attach, &sio_detach, NULL, 0 };
|
||||
|
||||
UNIT ptr_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
@@ -215,7 +238,7 @@ DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
NULL, NULL, NULL };
|
||||
NULL, NULL, NULL, NULL, 0 };
|
||||
|
||||
UNIT ptp_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
@@ -230,7 +253,7 @@ DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL };
|
||||
NULL, NULL, NULL, NULL, 0 };
|
||||
|
||||
/* Synthetic device SIMH for communication
|
||||
between Altair and SIMH environment using port 0xfe */
|
||||
@@ -269,7 +292,7 @@ DEVICE simh_device = {
|
||||
"SIMH", &simh_unit, simh_reg, simh_mod,
|
||||
1, 10, 31, 1, 16, 4,
|
||||
NULL, NULL, &simh_dev_reset,
|
||||
NULL, NULL, NULL };
|
||||
NULL, NULL, NULL, NULL, 0 };
|
||||
|
||||
|
||||
void resetSIOWarningFlags(void) {
|
||||
@@ -317,10 +340,10 @@ t_stat sio_svc(UNIT *uptr) {
|
||||
sim_activate(&sio_unit, sio_unit.wait); /* continue poll */
|
||||
|
||||
if (sio_unit.flags & UNIT_ATT) {
|
||||
if (sim_poll_kbd() == SCPE_STOP) { /* listen for ^E */
|
||||
if (sim_poll_kbd() == SCPE_STOP) { /* listen for ^E */
|
||||
return SCPE_STOP;
|
||||
}
|
||||
temp = tmxr_poll_conn(&altairTMXR, &sio_unit); /* poll connection */
|
||||
temp = tmxr_poll_conn(&altairTMXR); /* poll connection */
|
||||
if (temp >= 0) {
|
||||
altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */
|
||||
}
|
||||
@@ -584,7 +607,7 @@ int32 fromBCD(int32 x) {
|
||||
the pseudo device is left in an unexpected state.
|
||||
|
||||
4) Commands requiring parameters and returning results do not exist currently.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define splimit 10
|
||||
@@ -747,8 +770,8 @@ int32 simh_in(void) {
|
||||
currentTime -> tm_year - 100 : currentTime -> tm_year);
|
||||
break;
|
||||
case 1: result = toBCD(currentTime -> tm_mon + 1); break;
|
||||
case 2: result = toBCD(currentTime -> tm_mday); break;
|
||||
case 3: result = toBCD(currentTime -> tm_hour); break;
|
||||
case 2: result = toBCD(currentTime -> tm_mday); break;
|
||||
case 3: result = toBCD(currentTime -> tm_hour); break;
|
||||
case 4: result = toBCD(currentTime -> tm_min); break;
|
||||
case 5: result = toBCD(currentTime -> tm_sec); break;
|
||||
default: result = 0;
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
/* altairz80_sys.c: MITS Altair system interface
|
||||
Written by Peter Schorn, 2001-2002
|
||||
Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited)
|
||||
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
|
||||
|
||||
Copyright (c) 2002, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Peter Schorn shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Peter Schorn.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "altairZ80_defs.h"
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE dsk_dev;
|
||||
extern DEVICE hdsk_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern DEVICE sio_dev;
|
||||
@@ -20,7 +44,12 @@ extern char *get_range(char *cptr, t_addr *lo, t_addr *hi, int rdx,
|
||||
t_addr max, char term);
|
||||
extern t_value get_uint(char *cptr, int radix, t_value max, t_stat *status);
|
||||
extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
extern void PutBYTEForced(register uint32 Addr, register uint32 Value);
|
||||
extern uint8 GetBYTEWrapper(register uint32 Addr);
|
||||
extern int32 addressIsInROM(uint32 Addr);
|
||||
extern int32 addressExists(uint32 Addr);
|
||||
extern uint32 ROMLow;
|
||||
extern uint32 ROMHigh;
|
||||
|
||||
int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag);
|
||||
int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw);
|
||||
@@ -45,7 +74,7 @@ int32 checkXY(char xy);
|
||||
char sim_name[] = "Altair 8800 (Z80)";
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
int32 sim_emax = 4;
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, NULL };
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL };
|
||||
|
||||
char memoryAccessMessage[80];
|
||||
const char *sim_stop_messages[] = {
|
||||
@@ -693,18 +722,18 @@ int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) {
|
||||
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);
|
||||
return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : 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.
|
||||
load starts at the current value of the PC. ROM/NOROM and
|
||||
ALTAIRROM/NOALTAIRROM settings are ignored.
|
||||
*/
|
||||
|
||||
int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) {
|
||||
int32 i, addr = 0, cnt = 0, org;
|
||||
int32 i, addr = 0, cnt = 0, org, cntROM = 0, cntNonExist = 0;
|
||||
t_addr j, lo, hi;
|
||||
char *result;
|
||||
t_stat status;
|
||||
@@ -718,7 +747,7 @@ int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) {
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
}
|
||||
printf("%d Bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi);
|
||||
printf("%d bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi);
|
||||
}
|
||||
else {
|
||||
if (*cptr == 0) {
|
||||
@@ -732,11 +761,24 @@ int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) {
|
||||
}
|
||||
org = addr;
|
||||
while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) {
|
||||
PutBYTEWrapper(addr, i);
|
||||
PutBYTEForced(addr, i);
|
||||
if (addressIsInROM(addr)) {
|
||||
cntROM++;
|
||||
}
|
||||
if (!addressExists(addr)) {
|
||||
cntNonExist++;
|
||||
}
|
||||
addr++;
|
||||
cnt++;
|
||||
} /* end while */
|
||||
printf("%d Bytes loaded at %x.\n", cnt, org);
|
||||
printf("%d bytes [%d page%s] loaded at %x.\n", cnt, (cnt + 255) >> 8,
|
||||
((cnt + 255) >> 8) == 1 ? "" : "s", org);
|
||||
if (cntROM) {
|
||||
printf("Warning: %d bytes written to ROM [%04X - %04X].\n", cntROM, ROMLow, ROMHigh);
|
||||
}
|
||||
if (cntNonExist) {
|
||||
printf("Warning: %d bytes written to non-existing memory (for this configuration).\n", cntNonExist);
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
384
AltairZ80/altairz80_hdsk.c
Normal file
384
AltairZ80/altairz80_hdsk.c
Normal file
@@ -0,0 +1,384 @@
|
||||
/* altairZ80_hdsk.c: simulated hard disk device to increase capacity
|
||||
|
||||
Copyright (c) 2002, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Peter Schorn shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Peter Schorn.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
#define UNIT_V_HDSKWLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK)
|
||||
#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||
#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE)
|
||||
#define HDSK_SECTOR_SIZE 128 /* size of sector */
|
||||
#define HDSK_SECTORS_PER_TRACK 32 /* sectors per track */
|
||||
#define HDS_MAX_TRACKS 2048 /* number of tracks */
|
||||
#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK)
|
||||
#define HDSK_CAPACITY (HDSK_TRACK_SIZE * HDS_MAX_TRACKS)
|
||||
#define HDSK_NUMBER 8 /* number of hard disks */
|
||||
#define CPM_OK 0 /* indicates to CP/M everything ok */
|
||||
#define CPM_ERROR 1 /* indicates to CP/M an error condition */
|
||||
#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */
|
||||
#define hdsk_none 0
|
||||
#define hdsk_reset 1
|
||||
#define hdsk_read 2
|
||||
#define hdsk_write 3
|
||||
#define hdsk_boot_address 0x5c00
|
||||
|
||||
extern char messageBuffer[];
|
||||
extern int32 PCX;
|
||||
extern UNIT cpu_unit;
|
||||
extern uint8 M[MAXMEMSIZE][MAXBANKS];
|
||||
extern int32 saved_PC;
|
||||
|
||||
extern int32 install_bootrom(void);
|
||||
extern void printMessage(void);
|
||||
extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
extern void protect(int32 l, int32 h);
|
||||
extern uint8 GetBYTEWrapper(register uint32 Addr);
|
||||
extern int32 bootrom[bootrom_size];
|
||||
|
||||
t_stat hdsk_svc(UNIT *uptr);
|
||||
t_stat hdsk_boot(int32 unitno, DEVICE *dptr);
|
||||
int32 hdsk_hasVerbose(void);
|
||||
int32 hdsk_io(int32 port, int32 io, int32 data);
|
||||
int32 hdsk_in(void);
|
||||
int32 hdsk_out(int32 data);
|
||||
int32 checkParameters(void);
|
||||
int32 doSeek(void);
|
||||
int32 doRead(void);
|
||||
int32 doWrite(void);
|
||||
|
||||
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* Data Buffer */
|
||||
int32 hdskLastCommand = hdsk_none;
|
||||
int32 hdskCommandPosition = 0;
|
||||
int32 selectedDisk;
|
||||
int32 selectedSector;
|
||||
int32 selectedTrack;
|
||||
int32 selectedDMA;
|
||||
int32 hdskTrace;
|
||||
|
||||
UNIT hdsk_unit[] = {
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||
{ UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } };
|
||||
|
||||
REG hdsk_reg[] = {
|
||||
{ DRDATA (HDCMD, hdskLastCommand, 32), REG_RO },
|
||||
{ DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO },
|
||||
{ DRDATA (HDDSK, selectedDisk, 32), REG_RO },
|
||||
{ DRDATA (HDSEC, selectedSector, 32), REG_RO },
|
||||
{ DRDATA (HDTRK, selectedTrack, 32), REG_RO },
|
||||
{ DRDATA (HDDMA, selectedDMA, 32), REG_RO },
|
||||
{ DRDATA (HDTRACE, hdskTrace, 8), },
|
||||
{ NULL } };
|
||||
|
||||
MTAB hdsk_mod[] = {
|
||||
{ UNIT_HDSKWLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_HDSKWLK, UNIT_HDSKWLK, "write locked", "LOCKED", NULL },
|
||||
/* quiet, no warning messages */
|
||||
{ UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
||||
/* verbose, show warning messages */
|
||||
{ UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE hdsk_dev = {
|
||||
"HDSK", hdsk_unit, hdsk_reg, hdsk_mod,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, NULL,
|
||||
&hdsk_boot, NULL, NULL, NULL, 0 };
|
||||
|
||||
t_stat hdsk_svc(UNIT *uptr) {
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int32 hdskBoot[bootrom_size] = {
|
||||
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */
|
||||
0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */
|
||||
0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */
|
||||
0x5c, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* 5c18-5c1f */
|
||||
0x06, 0x20, 0x3e, 0x01, 0xd3, 0xfd, 0x05, 0xc2, /* 5c20-5c27 */
|
||||
0x24, 0x5c, 0x11, 0x08, 0x00, 0x21, 0x00, 0x00, /* 5c28-5c2f */
|
||||
0x0e, 0xb8, 0x3e, 0x02, 0xd3, 0xfd, 0x3a, 0x37, /* 5c30-5c37 */
|
||||
0xff, 0xd6, 0x08, 0xd3, 0xfd, 0x7b, 0xd3, 0xfd, /* 5c38-5c3f */
|
||||
0x7a, 0xd3, 0xfd, 0xaf, 0xd3, 0xfd, 0x7d, 0xd3, /* 5c40-5c47 */
|
||||
0xfd, 0x7c, 0xd3, 0xfd, 0xdb, 0xfd, 0xb7, 0xca, /* 5c48-5c4f */
|
||||
0x53, 0x5c, 0x76, 0x79, 0x0e, 0x80, 0x09, 0x4f, /* 5c50-5c57 */
|
||||
0x0d, 0xc2, 0x60, 0x5c, 0xfb, 0xc3, 0x00, 0x00, /* 5c58-5c5f */
|
||||
0x1c, 0x1c, 0x7b, 0xfe, 0x20, 0xca, 0x73, 0x5c, /* 5c60-5c67 */
|
||||
0xfe, 0x21, 0xc2, 0x32, 0x5c, 0x1e, 0x00, 0x14, /* 5c68-5c6f */
|
||||
0xc3, 0x32, 0x5c, 0x1e, 0x01, 0xc3, 0x32, 0x5c, /* 5c70-5c77 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c78-5c7f */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c80-5c87 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c88-5c8f */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c90-5c97 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c98-5c9f */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca0-5ca7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca8-5caf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb0-5cb7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb8-5cbf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc0-5cc7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc8-5ccf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd0-5cd7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd8-5cdf */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce0-5ce7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce8-5cef */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf0-5cf7 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf8-5cff */
|
||||
};
|
||||
|
||||
t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
|
||||
int32 i;
|
||||
if (MEMSIZE < 24*KB) {
|
||||
printf("Need at least 24KB RAM to boot from hard disk.\n");
|
||||
return SCPE_ARG;
|
||||
}
|
||||
if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) {
|
||||
if (install_bootrom()) {
|
||||
printf("ALTAIR boot ROM installed.\n");
|
||||
}
|
||||
/* check whether we are really modifying an LD A,<> instruction */
|
||||
if (bootrom[unitNoOffset1 - 1] == LDAInstruction) {
|
||||
bootrom[unitNoOffset1] = (unitno+NUM_OF_DSK) & 0xff; /* LD A,<unitno> */
|
||||
}
|
||||
else { /* Attempt to modify non LD A,<> instructions is refused. */
|
||||
printf("Incorrect boot ROM offset detected.\n");
|
||||
return SCPE_IERR;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < bootrom_size; i++) {
|
||||
M[i + hdsk_boot_address][0] = hdskBoot[i] & 0xff;
|
||||
}
|
||||
saved_PC = hdsk_boot_address;
|
||||
protect(hdsk_boot_address, hdsk_boot_address + bootrom_size - 1);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* returns TRUE iff there exists a disk with VERBOSE */
|
||||
int32 hdsk_hasVerbose(void) {
|
||||
int32 i;
|
||||
for (i = 0; i < HDSK_NUMBER; i++) {
|
||||
if (((hdsk_dev.units + i) -> flags) & UNIT_HDSK_VERBOSE) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The hard disk port is 0xfd. It understands the following commands.
|
||||
|
||||
1. reset
|
||||
ld b,32
|
||||
ld a,hdsk_reset
|
||||
l out (0fdh),a
|
||||
dec b
|
||||
jp nz,l
|
||||
|
||||
2. read / write
|
||||
; parameter block
|
||||
cmd: db hdsk_read or hdsk_write
|
||||
hd: db 0 ; 0 .. 7, defines hard disk to be used
|
||||
sector: db 0 ; 0 .. 31, defines sector
|
||||
track: dw 0 ; 0 .. 2047, defines track
|
||||
dma: dw 0 ; defines where result is placed in memory
|
||||
|
||||
; routine to execute
|
||||
ld b,7 ; size of parameter block
|
||||
ld hl,cmd ; start address of parameter block
|
||||
l ld a,(hl) ; get byte of parameter block
|
||||
out (0fdh),a ; send it to port
|
||||
inc hl ; point to next byte
|
||||
dec b ; decrement counter
|
||||
jp nz,l ; again, if not done
|
||||
in a,(0fdh) ; get result code
|
||||
|
||||
*/
|
||||
|
||||
/* check the parameters and return TRUE iff parameters are correct or have been repaired */
|
||||
int32 checkParameters(void) {
|
||||
int32 currentFlag;
|
||||
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
|
||||
if (hdsk_hasVerbose()) {
|
||||
message2("HDSK%d does not exist, will use HDSK0 instead.\n", selectedDisk);
|
||||
}
|
||||
selectedDisk = 0;
|
||||
}
|
||||
currentFlag = (hdsk_dev.units + selectedDisk) -> flags;
|
||||
if ((currentFlag & UNIT_ATT) == 0) {
|
||||
if (currentFlag & UNIT_HDSK_VERBOSE) {
|
||||
message2("HDSK%d is not attached.\n", selectedDisk);
|
||||
}
|
||||
return FALSE; /* cannot read or write */
|
||||
}
|
||||
if ((selectedSector < 0) || (selectedSector >= HDSK_SECTORS_PER_TRACK)) {
|
||||
if (currentFlag & UNIT_HDSK_VERBOSE) {
|
||||
message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.\n",
|
||||
selectedDisk, selectedSector, HDSK_SECTORS_PER_TRACK);
|
||||
}
|
||||
selectedSector = 0;
|
||||
}
|
||||
if ((selectedTrack < 0) || (selectedTrack >= HDS_MAX_TRACKS)) {
|
||||
if (currentFlag & UNIT_HDSK_VERBOSE) {
|
||||
message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.\n",
|
||||
selectedDisk, selectedTrack, HDS_MAX_TRACKS);
|
||||
}
|
||||
selectedTrack = 0;
|
||||
}
|
||||
selectedDMA &= ADDRMASK;
|
||||
if (hdskTrace) {
|
||||
message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x\n",
|
||||
(hdskLastCommand == hdsk_read) ? "Read" : "Write",
|
||||
selectedDisk, selectedSector, selectedTrack, selectedDMA);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int32 doSeek(void) {
|
||||
UNIT *uptr = hdsk_dev.units + selectedDisk;
|
||||
if (fseek(uptr -> fileref,
|
||||
HDSK_TRACK_SIZE * selectedTrack + HDSK_SECTOR_SIZE * selectedSector, SEEK_SET)) {
|
||||
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
|
||||
message4("Could not access HDSK%d Sector=%02d Track=%04d.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
else {
|
||||
return CPM_OK;
|
||||
}
|
||||
}
|
||||
|
||||
int32 doRead(void) {
|
||||
int32 i;
|
||||
UNIT *uptr = hdsk_dev.units + selectedDisk;
|
||||
if (doSeek()) {
|
||||
return CPM_ERROR;
|
||||
}
|
||||
if (fread(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
|
||||
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
|
||||
hdskbuf[i] = CPM_EMPTY;
|
||||
}
|
||||
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
|
||||
message4("Could not read HDSK%d Sector=%02d Track=%04d.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_OK; /* allows the creation of empty hard disks */
|
||||
}
|
||||
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
|
||||
PutBYTEWrapper(selectedDMA + i, hdskbuf[i]);
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
int32 doWrite(void) {
|
||||
int32 i;
|
||||
UNIT *uptr = hdsk_dev.units + selectedDisk;
|
||||
if (((uptr -> flags) & UNIT_HDSKWLK) == 0) { /* write enabled */
|
||||
if (doSeek()) {
|
||||
return CPM_ERROR;
|
||||
}
|
||||
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
|
||||
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
|
||||
}
|
||||
if (fwrite(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
|
||||
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
|
||||
message4("Could not write HDSK%d Sector=%02d Track=%04d.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
|
||||
message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
int32 hdsk_in(void) {
|
||||
int32 result;
|
||||
if ((hdskCommandPosition == 6) && ((hdskLastCommand == hdsk_read) || (hdskLastCommand == hdsk_write))) {
|
||||
result = checkParameters() ? ((hdskLastCommand == hdsk_read) ? doRead() : doWrite()) : CPM_ERROR;
|
||||
hdskLastCommand = hdsk_none;
|
||||
hdskCommandPosition = 0;
|
||||
return result;
|
||||
}
|
||||
else if (hdsk_hasVerbose()) {
|
||||
message3("Illegal IN command detected (cmd=%d, pos=%d).\n", hdskLastCommand, hdskCommandPosition);
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
int32 hdsk_out(int32 data) {
|
||||
switch(hdskLastCommand) {
|
||||
case hdsk_read:
|
||||
case hdsk_write:
|
||||
switch(hdskCommandPosition) {
|
||||
case 0:
|
||||
selectedDisk = data;
|
||||
hdskCommandPosition++;
|
||||
break;
|
||||
case 1:
|
||||
selectedSector = data;
|
||||
hdskCommandPosition++;
|
||||
break;
|
||||
case 2:
|
||||
selectedTrack = data;
|
||||
hdskCommandPosition++;
|
||||
break;
|
||||
case 3:
|
||||
selectedTrack += (data << 8);
|
||||
hdskCommandPosition++;
|
||||
break;
|
||||
case 4:
|
||||
selectedDMA = data;
|
||||
hdskCommandPosition++;
|
||||
break;
|
||||
case 5:
|
||||
selectedDMA += (data << 8);
|
||||
hdskCommandPosition++;
|
||||
break;
|
||||
default:
|
||||
hdskLastCommand = hdsk_none;
|
||||
hdskCommandPosition = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hdskLastCommand = data;
|
||||
hdskCommandPosition = 0;
|
||||
}
|
||||
return 0; /* ignored, since OUT */
|
||||
}
|
||||
|
||||
int32 hdsk_io(int32 port, int32 io, int32 data) {
|
||||
return io == 0 ? hdsk_in() : hdsk_out(data);
|
||||
}
|
||||
Reference in New Issue
Block a user