mirror of
https://github.com/open-simh/simh.git
synced 2026-04-25 20:01:33 +00:00
Notes For V3.5-0
The source set has been extensively overhauled. For correct viewing, set Visual C++ or Emacs to have tab stops every 4 characters. 1. New Features in 3.4-1 1.1 All Ethernet devices - Added Windows user-defined adapter names (from Timothe Litt) 1.2 Interdata, SDS, HP, PDP-8, PDP-18b terminal multiplexors - Added support for SET <unit>n DISCONNECT 1.3 VAX - Added latent QDSS support - Revised autoconfigure to handle QDSS 1.4 PDP-11 - Revised autoconfigure to handle more casees 2. Bugs Fixed in 3.4-1 2.1 SCP and libraries - Trim trailing spaces on all input (for example, attach file names) - Fixed sim_sock spurious SIGPIPE error in Unix/Linux - Fixed sim_tape misallocation of TPC map array for 64b simulators 2.2 1401 - Fixed bug, CPU reset was clearing SSB through SSG 2.3 PDP-11 - Fixed bug in VH vector display routine - Fixed XU runt packet processing (found by Tim Chapman) 2.4 Interdata - Fixed bug in SHOW PAS CONN/STATS - Fixed potential integer overflow exception in divide 2.5 SDS - Fixed bug in SHOW MUX CONN/STATS 2.6 HP - Fixed bug in SHOW MUX CONN/STATS 2.7 PDP-8 - Fixed bug in SHOW TTIX CONN/STATS - Fixed bug in SET/SHOW TTOXn LOG 2.8 PDP-18b - Fixed bug in SHOW TTIX CONN/STATS - Fixed bug in SET/SHOW TTOXn LOG 2.9 Nova, Eclipse - Fixed potential integer overflow exception in divide
This commit is contained in:
committed by
Mark Pizzolato
parent
ec60bbf329
commit
b7c1eae41f
File diff suppressed because it is too large
Load Diff
@@ -1,80 +1,80 @@
|
||||
/* altairz80_defs.h: MITS Altair simulator definitions
|
||||
/* altairz80_defs.h: MITS Altair simulator definitions
|
||||
|
||||
Copyright (c) 2002-2005, Peter Schorn
|
||||
Copyright (c) 2002-2005, 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:
|
||||
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 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
|
||||
PETER SCHORN 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.
|
||||
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
|
||||
PETER SCHORN 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.
|
||||
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
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator definitions */
|
||||
#include "sim_defs.h" /* simulator definitions */
|
||||
|
||||
#define MAXMEMSIZE 65536 /* maximum 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 address of ROM */
|
||||
#define defaultROMHigh 0xffff /* default for highest address of ROM */
|
||||
#define MAXMEMSIZE 65536 /* maximum 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 address of ROM */
|
||||
#define defaultROMHigh 0xffff /* default for highest address of 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 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 UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */
|
||||
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
|
||||
#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */
|
||||
#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 UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */
|
||||
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
|
||||
#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */
|
||||
#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()
|
||||
#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". */
|
||||
/* The default is to use "inline". */
|
||||
#if defined(NO_INLINE)
|
||||
#define INLINE
|
||||
#else
|
||||
|
||||
@@ -1,130 +1,130 @@
|
||||
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
|
||||
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
|
||||
|
||||
Copyright (c) 2002-2005, Peter Schorn
|
||||
Copyright (c) 2002-2005, 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:
|
||||
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 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
|
||||
PETER SCHORN 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.
|
||||
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
|
||||
PETER SCHORN 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.
|
||||
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
|
||||
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.
|
||||
Each diskette has physically 77 tracks of 32 137-byte sectors
|
||||
each.
|
||||
The 88_DISK is a 8-inch floppy controller which can control up
|
||||
to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives.
|
||||
Each diskette has physically 77 tracks of 32 137-byte sectors
|
||||
each.
|
||||
|
||||
The controller is interfaced to the CPU by use of 3 I/O addresses,
|
||||
standardly, these are device numbers 10, 11, and 12 (octal).
|
||||
The controller is interfaced to the CPU by use of 3 I/O addresses,
|
||||
standardly, these are device numbers 10, 11, and 12 (octal).
|
||||
|
||||
Address Mode Function
|
||||
------- ---- --------
|
||||
Address Mode Function
|
||||
------- ---- --------
|
||||
|
||||
10 Out Selects and enables Controller and Drive
|
||||
10 In Indicates status of Drive and Controller
|
||||
11 Out Controls Disk Function
|
||||
11 In Indicates current sector position of disk
|
||||
12 Out Write data
|
||||
12 In Read data
|
||||
10 Out Selects and enables Controller and Drive
|
||||
10 In Indicates status of Drive and Controller
|
||||
11 Out Controls Disk Function
|
||||
11 In Indicates current sector position of disk
|
||||
12 Out Write data
|
||||
12 In Read data
|
||||
|
||||
Drive Select Out (Device 10 OUT):
|
||||
Drive Select Out (Device 10 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| C | X | X | X | Device |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| C | X | X | X | Device |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
C = If this bit is 1, the disk controller selected by 'device' is
|
||||
cleared. If the bit is zero, 'device' is selected as the
|
||||
device being controlled by subsequent I/O operations.
|
||||
X = not used
|
||||
Device = value zero thru 15, selects drive to be controlled.
|
||||
C = If this bit is 1, the disk controller selected by 'device' is
|
||||
cleared. If the bit is zero, 'device' is selected as the
|
||||
device being controlled by subsequent I/O operations.
|
||||
X = not used
|
||||
Device = value zero thru 15, selects drive to be controlled.
|
||||
|
||||
Drive Status In (Device 10 IN):
|
||||
Drive Status In (Device 10 IN):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| R | Z | I | X | X | H | M | W |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| R | Z | I | X | X | H | M | W |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
W - When 0, write circuit ready to write another byte.
|
||||
M - When 0, head movement is allowed
|
||||
H - When 0, indicates head is loaded for read/write
|
||||
X - not used (will be 0)
|
||||
I - When 0, indicates interrupts enabled (not used by this simulator)
|
||||
Z - When 0, indicates head is on track 0
|
||||
R - When 0, indicates that read circuit has new byte to read
|
||||
W - When 0, write circuit ready to write another byte.
|
||||
M - When 0, head movement is allowed
|
||||
H - When 0, indicates head is loaded for read/write
|
||||
X - not used (will be 0)
|
||||
I - When 0, indicates interrupts enabled (not used by this simulator)
|
||||
Z - When 0, indicates head is on track 0
|
||||
R - When 0, indicates that read circuit has new byte to read
|
||||
|
||||
Drive Control (Device 11 OUT):
|
||||
Drive Control (Device 11 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| W | C | D | E | U | H | O | I |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| W | C | D | E | U | H | O | I |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
I - When 1, steps head IN one track
|
||||
O - When 1, steps head OUT one track
|
||||
H - When 1, loads head to drive surface
|
||||
U - When 1, unloads head
|
||||
E - Enables interrupts (ignored by this simulator)
|
||||
D - Disables interrupts (ignored by this simulator)
|
||||
C - When 1 lowers head current (ignored by this simulator)
|
||||
W - When 1, starts Write Enable sequence: W bit on device 10
|
||||
(see above) will go 1 and data will be read from port 12
|
||||
until 137 bytes have been read by the controller from
|
||||
that port. The W bit will go off then, and the sector data
|
||||
will be written to disk. Before you do this, you must have
|
||||
stepped the track to the desired number, and waited until
|
||||
the right sector number is presented on device 11 IN, then
|
||||
set this bit.
|
||||
I - When 1, steps head IN one track
|
||||
O - When 1, steps head OUT one track
|
||||
H - When 1, loads head to drive surface
|
||||
U - When 1, unloads head
|
||||
E - Enables interrupts (ignored by this simulator)
|
||||
D - Disables interrupts (ignored by this simulator)
|
||||
C - When 1 lowers head current (ignored by this simulator)
|
||||
W - When 1, starts Write Enable sequence: W bit on device 10
|
||||
(see above) will go 1 and data will be read from port 12
|
||||
until 137 bytes have been read by the controller from
|
||||
that port. The W bit will go off then, and the sector data
|
||||
will be written to disk. Before you do this, you must have
|
||||
stepped the track to the desired number, and waited until
|
||||
the right sector number is presented on device 11 IN, then
|
||||
set this bit.
|
||||
|
||||
Sector Position (Device 11 IN):
|
||||
Sector Position (Device 11 IN):
|
||||
|
||||
As the sectors pass by the read head, they are counted and the
|
||||
number of the current one is available in this register.
|
||||
As the sectors pass by the read head, they are counted and the
|
||||
number of the current one is available in this register.
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X | X | Sector Number | T |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X | X | Sector Number | T |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
X = Not used
|
||||
Sector number = binary of the sector number currently under the
|
||||
head, 0-31.
|
||||
T = Sector True, is a 1 when the sector is positioned to read or
|
||||
write.
|
||||
X = Not used
|
||||
Sector number = binary of the sector number currently under the
|
||||
head, 0-31.
|
||||
T = Sector True, is a 1 when the sector is positioned to read or
|
||||
write.
|
||||
|
||||
*/
|
||||
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
#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 MAX_TRACKS 254 /* number of tracks,
|
||||
original Altair has 77 tracks only */
|
||||
#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT)
|
||||
#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_MASK (NUM_OF_DSK - 1)
|
||||
#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 MAX_TRACKS 254 /* number of tracks,
|
||||
original Altair has 77 tracks only */
|
||||
#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT)
|
||||
#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_MASK (NUM_OF_DSK - 1)
|
||||
|
||||
int32 dsk10(const int32 port, const int32 io, const int32 data);
|
||||
int32 dsk11(const int32 port, const int32 io, const int32 data);
|
||||
@@ -149,140 +149,144 @@ extern UNIT cpu_unit;
|
||||
|
||||
/* global data on status */
|
||||
|
||||
static int32 current_disk = NUM_OF_DSK; /* currently selected drive (values are 0 .. NUM_OF_DSK)
|
||||
current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */
|
||||
static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
||||
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS };
|
||||
static int32 trace_flag = 0;
|
||||
static int32 in9_count = 0;
|
||||
static int32 in9_message = FALSE;
|
||||
static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */
|
||||
static int32 warnLevelDSK = 3;
|
||||
static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 warnDSK10 = 0;
|
||||
static int32 warnDSK11 = 0;
|
||||
static int32 warnDSK12 = 0;
|
||||
static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */
|
||||
static int32 current_disk = NUM_OF_DSK; /* currently selected drive (values are 0 .. NUM_OF_DSK)
|
||||
current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */
|
||||
static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
||||
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS };
|
||||
static int32 trace_flag = 0;
|
||||
static int32 in9_count = 0;
|
||||
static int32 in9_message = FALSE;
|
||||
static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */
|
||||
static int32 warnLevelDSK = 3;
|
||||
static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static int32 warnDSK10 = 0;
|
||||
static int32 warnDSK11 = 0;
|
||||
static int32 warnDSK12 = 0;
|
||||
static 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, /* 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 */
|
||||
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 */
|
||||
|
||||
static UNIT dsk_unit[] = {
|
||||
{ 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) } };
|
||||
{ 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) }
|
||||
};
|
||||
|
||||
static REG dsk_reg[] = {
|
||||
{ DRDATA (DISK, current_disk, 4) },
|
||||
{ BRDATA (CURTRACK, current_track, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (CURSECTOR, current_sector, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (CURBYTE, current_byte, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (CURFLAG, current_flag, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC },
|
||||
{ ORDATA (TRACE, trace_flag, 8) },
|
||||
{ DRDATA (IN9COUNT, in9_count, 4), REG_RO },
|
||||
{ DRDATA (IN9MESSAGE, in9_message, 4), REG_RO },
|
||||
{ DRDATA (DIRTY, dirty, 4), REG_RO },
|
||||
{ DRDATA (DSKWL, warnLevelDSK, 32) },
|
||||
{ BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ DRDATA (WARNDSK10, warnDSK10, 4), REG_RO },
|
||||
{ DRDATA (WARNDSK11, warnDSK11, 4), REG_RO },
|
||||
{ DRDATA (WARNDSK12, warnDSK12, 4), REG_RO },
|
||||
{ BRDATA (DISKBUFFER, dskbuf, 10, 8, DSK_SECTSIZE), REG_CIRC + REG_RO },
|
||||
{ NULL } };
|
||||
{ DRDATA (DISK, current_disk, 4) },
|
||||
{ BRDATA (CURTRACK, current_track, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (CURSECTOR, current_sector, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (CURBYTE, current_byte, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (CURFLAG, current_flag, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC },
|
||||
{ ORDATA (TRACE, trace_flag, 8) },
|
||||
{ DRDATA (IN9COUNT, in9_count, 4), REG_RO },
|
||||
{ DRDATA (IN9MESSAGE, in9_message, 4), REG_RO },
|
||||
{ DRDATA (DIRTY, dirty, 4), REG_RO },
|
||||
{ DRDATA (DSKWL, warnLevelDSK, 32) },
|
||||
{ BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
||||
{ DRDATA (WARNDSK10, warnDSK10, 4), REG_RO },
|
||||
{ DRDATA (WARNDSK11, warnDSK11, 4), REG_RO },
|
||||
{ DRDATA (WARNDSK12, warnDSK12, 4), REG_RO },
|
||||
{ BRDATA (DISKBUFFER, dskbuf, 10, 8, DSK_SECTSIZE), REG_CIRC + REG_RO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static MTAB dsk_mod[] = {
|
||||
{ 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 } };
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
DEVICE dsk_dev = {
|
||||
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &dsk_reset,
|
||||
&dsk_boot, NULL, NULL,
|
||||
NULL, 0, 0,
|
||||
NULL, NULL, NULL };
|
||||
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &dsk_reset,
|
||||
&dsk_boot, NULL, NULL,
|
||||
NULL, 0, 0,
|
||||
NULL, NULL, NULL
|
||||
};
|
||||
|
||||
static void resetDSKWarningFlags(void) {
|
||||
int32 i;
|
||||
for (i = 0; i < NUM_OF_DSK; i++) {
|
||||
warnLock[i] = 0;
|
||||
warnAttached[i] = 0;
|
||||
}
|
||||
warnDSK10 = 0;
|
||||
warnDSK11 = 0;
|
||||
warnDSK12 = 0;
|
||||
int32 i;
|
||||
for (i = 0; i < NUM_OF_DSK; i++) {
|
||||
warnLock[i] = 0;
|
||||
warnAttached[i] = 0;
|
||||
}
|
||||
warnDSK10 = 0;
|
||||
warnDSK11 = 0;
|
||||
warnDSK12 = 0;
|
||||
}
|
||||
|
||||
static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
resetDSKWarningFlags();
|
||||
return SCPE_OK;
|
||||
resetDSKWarningFlags();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* returns TRUE iff there exists a disk with VERBOSE */
|
||||
static int32 hasVerbose(void) {
|
||||
int32 i;
|
||||
for (i = 0; i < NUM_OF_DSK; i++) {
|
||||
if (((dsk_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
int32 i;
|
||||
for (i = 0; i < NUM_OF_DSK; i++) {
|
||||
if (((dsk_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char* selectInOut(const int32 io) {
|
||||
return io == 0 ? "IN" : "OUT";
|
||||
return io == 0 ? "IN" : "OUT";
|
||||
}
|
||||
|
||||
/* service routines to handle simulator functions */
|
||||
@@ -290,281 +294,280 @@ static char* selectInOut(const int32 io) {
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
static t_stat dsk_svc(UNIT *uptr) {
|
||||
return SCPE_OK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* reset routine */
|
||||
|
||||
static t_stat dsk_reset(DEVICE *dptr) {
|
||||
resetDSKWarningFlags();
|
||||
current_disk = NUM_OF_DSK;
|
||||
trace_flag = 0;
|
||||
in9_count = 0;
|
||||
in9_message = FALSE;
|
||||
return SCPE_OK;
|
||||
resetDSKWarningFlags();
|
||||
current_disk = NUM_OF_DSK;
|
||||
trace_flag = 0;
|
||||
in9_count = 0;
|
||||
in9_message = FALSE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* The boot routine modifies the boot ROM in such a way that subsequently
|
||||
the specified disk is used for boot purposes.
|
||||
/* The boot routine modifies the boot ROM in such a way that subsequently
|
||||
the specified disk is used for boot purposes.
|
||||
*/
|
||||
static 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;
|
||||
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
|
||||
IN or OUT instruction is issued.
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
IN or OUT instruction is issued.
|
||||
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
*/
|
||||
|
||||
/* Disk Controller Status/Select */
|
||||
|
||||
/* IMPORTANT: The status flags read by port 8 IN instruction are
|
||||
INVERTED, that is, 0 is true and 1 is false. To handle this, the
|
||||
simulator keeps it's own status flags as 0=false, 1=true; and
|
||||
returns the COMPLEMENT of the status flags when read. This makes
|
||||
setting/testing of the flag bits more logical, yet meets the
|
||||
simulation requirement that they are reversed in hardware.
|
||||
/* IMPORTANT: The status flags read by port 8 IN instruction are
|
||||
INVERTED, that is, 0 is true and 1 is false. To handle this, the
|
||||
simulator keeps it's own status flags as 0=false, 1=true; and
|
||||
returns the COMPLEMENT of the status flags when read. This makes
|
||||
setting/testing of the flag bits more logical, yet meets the
|
||||
simulation requirement that they are reversed in hardware.
|
||||
*/
|
||||
|
||||
int32 dsk10(const int32 port, const int32 io, const int32 data) {
|
||||
int32 current_disk_flags;
|
||||
in9_count = 0;
|
||||
if (io == 0) { /* IN: return flags */
|
||||
if (current_disk >= NUM_OF_DSK) {
|
||||
if (hasVerbose() && (warnDSK10 < warnLevelDSK)) {
|
||||
warnDSK10++;
|
||||
/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored.");
|
||||
}
|
||||
return 0xff; /* no drive selected - can do nothing */
|
||||
}
|
||||
return (~current_flag[current_disk]) & 0xff; /* return the COMPLEMENT! */
|
||||
}
|
||||
int32 current_disk_flags;
|
||||
in9_count = 0;
|
||||
if (io == 0) { /* IN: return flags */
|
||||
if (current_disk >= NUM_OF_DSK) {
|
||||
if (hasVerbose() && (warnDSK10 < warnLevelDSK)) {
|
||||
warnDSK10++;
|
||||
/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored.");
|
||||
}
|
||||
return 0xff; /* no drive selected - can do nothing */
|
||||
}
|
||||
return (~current_flag[current_disk]) & 0xff; /* return the COMPLEMENT! */
|
||||
}
|
||||
|
||||
/* OUT: Controller set/reset/enable/disable */
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message2("OUT 0x08: %x", data);
|
||||
}
|
||||
current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */
|
||||
current_disk_flags = (dsk_dev.units + current_disk) -> flags;
|
||||
if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */
|
||||
if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) {
|
||||
warnAttached[current_disk]++;
|
||||
/* OUT: Controller set/reset/enable/disable */
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message2("OUT 0x08: %x", data);
|
||||
}
|
||||
current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */
|
||||
current_disk_flags = (dsk_dev.units + current_disk) -> flags;
|
||||
if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */
|
||||
if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) {
|
||||
warnAttached[current_disk]++;
|
||||
/*02*/message2("Attempt to select unattached DSK%d - ignored.", current_disk);
|
||||
}
|
||||
current_disk = NUM_OF_DSK;
|
||||
}
|
||||
else {
|
||||
current_sector[current_disk] = 0xff; /* reset internal counters */
|
||||
current_byte[current_disk] = 0xff;
|
||||
current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ :
|
||||
(current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ :
|
||||
0x1a);/* enable: head move true */
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
}
|
||||
current_disk = NUM_OF_DSK;
|
||||
}
|
||||
else {
|
||||
current_sector[current_disk] = 0xff; /* reset internal counters */
|
||||
current_byte[current_disk] = 0xff;
|
||||
current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ :
|
||||
(current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ :
|
||||
0x1a); /* enable: head move true */
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
}
|
||||
|
||||
/* Disk Drive Status/Functions */
|
||||
|
||||
int32 dsk11(const int32 port, const int32 io, const int32 data) {
|
||||
if (current_disk >= NUM_OF_DSK) {
|
||||
if (hasVerbose() && (warnDSK11 < warnLevelDSK)) {
|
||||
warnDSK11++;
|
||||
/*03*/message2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io));
|
||||
}
|
||||
return 0; /* no drive selected - can do nothing */
|
||||
}
|
||||
if (current_disk >= NUM_OF_DSK) {
|
||||
if (hasVerbose() && (warnDSK11 < warnLevelDSK)) {
|
||||
warnDSK11++;
|
||||
/*03*/ message2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io));
|
||||
}
|
||||
return 0; /* no drive selected - can do nothing */
|
||||
}
|
||||
|
||||
/* now current_disk < NUM_OF_DSK */
|
||||
if (io == 0) { /* read sector position */
|
||||
in9_count++;
|
||||
if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) {
|
||||
in9_message = TRUE;
|
||||
message2("Looping on sector find %d.", current_disk);
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message1("IN 0x09");
|
||||
}
|
||||
if (dirty) {/* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (current_flag[current_disk] & 0x04) { /* head loaded? */
|
||||
current_sector[current_disk]++;
|
||||
if (current_sector[current_disk] >= DSK_SECT) {
|
||||
current_sector[current_disk] = 0;
|
||||
}
|
||||
current_byte[current_disk] = 0xff;
|
||||
return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */
|
||||
| 0xc0); /* set on 'unused' bits */
|
||||
} else {
|
||||
return 0; /* head not loaded - return 0 */
|
||||
}
|
||||
}
|
||||
/* now current_disk < NUM_OF_DSK */
|
||||
if (io == 0) { /* read sector position */
|
||||
in9_count++;
|
||||
if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) {
|
||||
in9_message = TRUE;
|
||||
message2("Looping on sector find %d.", current_disk);
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message1("IN 0x09");
|
||||
}
|
||||
if (dirty) {/* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (current_flag[current_disk] & 0x04) { /* head loaded? */
|
||||
current_sector[current_disk]++;
|
||||
if (current_sector[current_disk] >= DSK_SECT) {
|
||||
current_sector[current_disk] = 0;
|
||||
}
|
||||
current_byte[current_disk] = 0xff;
|
||||
return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */
|
||||
| 0xc0); /* set on 'unused' bits */
|
||||
} else {
|
||||
return 0; /* head not loaded - return 0 */
|
||||
}
|
||||
}
|
||||
|
||||
in9_count = 0;
|
||||
/* drive functions */
|
||||
in9_count = 0;
|
||||
/* drive functions */
|
||||
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message2("OUT 0x09: %x", data);
|
||||
}
|
||||
if (data & 0x01) { /* step head in */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (current_track[current_disk] == (tracks[current_disk] - 1)) {
|
||||
message2("Unnecessary step in for disk %d", current_disk);
|
||||
}
|
||||
}
|
||||
current_track[current_disk]++;
|
||||
if (current_track[current_disk] > (tracks[current_disk] - 1)) {
|
||||
current_track[current_disk] = (tracks[current_disk] - 1);
|
||||
}
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
current_sector[current_disk] = 0xff;
|
||||
current_byte[current_disk] = 0xff;
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message2("OUT 0x09: %x", data);
|
||||
}
|
||||
if (data & 0x01) { /* step head in */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (current_track[current_disk] == (tracks[current_disk] - 1)) {
|
||||
message2("Unnecessary step in for disk %d", current_disk);
|
||||
}
|
||||
}
|
||||
current_track[current_disk]++;
|
||||
if (current_track[current_disk] > (tracks[current_disk] - 1)) {
|
||||
current_track[current_disk] = (tracks[current_disk] - 1);
|
||||
}
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
current_sector[current_disk] = 0xff;
|
||||
current_byte[current_disk] = 0xff;
|
||||
}
|
||||
|
||||
if (data & 0x02) { /* step head out */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (current_track[current_disk] == 0) {
|
||||
message2("Unnecessary step out for disk %d", current_disk);
|
||||
}
|
||||
}
|
||||
current_track[current_disk]--;
|
||||
if (current_track[current_disk] < 0) {
|
||||
current_track[current_disk] = 0;
|
||||
current_flag[current_disk] |= 0x40; /* track 0 if there */
|
||||
}
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
current_sector[current_disk] = 0xff;
|
||||
current_byte[current_disk] = 0xff;
|
||||
}
|
||||
if (data & 0x02) { /* step head out */
|
||||
if (trace_flag & TRACE_TRACK_STUCK) {
|
||||
if (current_track[current_disk] == 0) {
|
||||
message2("Unnecessary step out for disk %d", current_disk);
|
||||
}
|
||||
}
|
||||
current_track[current_disk]--;
|
||||
if (current_track[current_disk] < 0) {
|
||||
current_track[current_disk] = 0;
|
||||
current_flag[current_disk] |= 0x40; /* track 0 if there */
|
||||
}
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
current_sector[current_disk] = 0xff;
|
||||
current_byte[current_disk] = 0xff;
|
||||
}
|
||||
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
if (dirty) { /* implies that current_disk < NUM_OF_DSK */
|
||||
writebuf();
|
||||
}
|
||||
|
||||
if (data & 0x04) { /* head load */
|
||||
current_flag[current_disk] |= 0x04; /* turn on head loaded bit */
|
||||
current_flag[current_disk] |= 0x80; /* turn on 'read data available' */
|
||||
}
|
||||
if (data & 0x04) { /* head load */
|
||||
current_flag[current_disk] |= 0x04; /* turn on head loaded bit */
|
||||
current_flag[current_disk] |= 0x80; /* turn on 'read data available' */
|
||||
}
|
||||
|
||||
if (data & 0x08) { /* head unload */
|
||||
current_flag[current_disk] &= 0xfb; /* turn off 'head loaded' bit */
|
||||
current_flag[current_disk] &= 0x7f; /* turn off 'read data available' */
|
||||
current_sector[current_disk] = 0xff;
|
||||
current_byte[current_disk] = 0xff;
|
||||
}
|
||||
if (data & 0x08) { /* head unload */
|
||||
current_flag[current_disk] &= 0xfb; /* turn off 'head loaded' bit */
|
||||
current_flag[current_disk] &= 0x7f; /* turn off 'read data available' */
|
||||
current_sector[current_disk] = 0xff;
|
||||
current_byte[current_disk] = 0xff;
|
||||
}
|
||||
|
||||
/* interrupts & head current are ignored */
|
||||
/* interrupts & head current are ignored */
|
||||
|
||||
if (data & 0x80) { /* write sequence start */
|
||||
current_byte[current_disk] = 0;
|
||||
current_flag[current_disk] |= 0x01; /* enter new write data on */
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
if (data & 0x80) { /* write sequence start */
|
||||
current_byte[current_disk] = 0;
|
||||
current_flag[current_disk] |= 0x01; /* enter new write data on */
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
}
|
||||
|
||||
/* Disk Data In/Out */
|
||||
|
||||
static INLINE int32 dskseek(const UNIT *xptr) {
|
||||
return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] +
|
||||
DSK_SECTSIZE * current_sector[current_disk], SEEK_SET);
|
||||
return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] +
|
||||
DSK_SECTSIZE * current_sector[current_disk], SEEK_SET);
|
||||
}
|
||||
|
||||
int32 dsk12(const int32 port, const int32 io, const int32 data) {
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
if (current_disk >= NUM_OF_DSK) {
|
||||
if (hasVerbose() && (warnDSK12 < warnLevelDSK)) {
|
||||
warnDSK12++;
|
||||
/*04*/message2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (current_disk >= NUM_OF_DSK) {
|
||||
if (hasVerbose() && (warnDSK12 < warnLevelDSK)) {
|
||||
warnDSK12++;
|
||||
/*04*/ message2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* now current_disk < NUM_OF_DSK */
|
||||
in9_count = 0;
|
||||
uptr = dsk_dev.units + current_disk;
|
||||
if (io == 0) {
|
||||
if (current_byte[current_disk] >= DSK_SECTSIZE) {
|
||||
/* physically read the sector */
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
message4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
for (i = 0; i < DSK_SECTSIZE; i++) {
|
||||
dskbuf[i] = 0;
|
||||
}
|
||||
dskseek(uptr);
|
||||
fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
||||
current_byte[current_disk] = 0;
|
||||
}
|
||||
return dskbuf[current_byte[current_disk]++] & 0xff;
|
||||
}
|
||||
else {
|
||||
if (current_byte[current_disk] >= DSK_SECTSIZE) {
|
||||
writebuf(); /* from above we have that current_disk < NUM_OF_DSK */
|
||||
}
|
||||
else {
|
||||
dirty = TRUE; /* this guarantees for the next call to writebuf that current_disk < NUM_OF_DSK */
|
||||
dskbuf[current_byte[current_disk]++] = data & 0xff;
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
}
|
||||
/* now current_disk < NUM_OF_DSK */
|
||||
in9_count = 0;
|
||||
uptr = dsk_dev.units + current_disk;
|
||||
if (io == 0) {
|
||||
if (current_byte[current_disk] >= DSK_SECTSIZE) {
|
||||
/* physically read the sector */
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
message4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
for (i = 0; i < DSK_SECTSIZE; i++) {
|
||||
dskbuf[i] = 0;
|
||||
}
|
||||
dskseek(uptr);
|
||||
fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
||||
current_byte[current_disk] = 0;
|
||||
}
|
||||
return dskbuf[current_byte[current_disk]++] & 0xff;
|
||||
}
|
||||
else {
|
||||
if (current_byte[current_disk] >= DSK_SECTSIZE) {
|
||||
writebuf(); /* from above we have that current_disk < NUM_OF_DSK */
|
||||
}
|
||||
else {
|
||||
dirty = TRUE; /* this guarantees for the next call to writebuf that current_disk < NUM_OF_DSK */
|
||||
dskbuf[current_byte[current_disk]++] = data & 0xff;
|
||||
}
|
||||
return 0; /* ignored since OUT */
|
||||
}
|
||||
}
|
||||
|
||||
/* precondition: current_disk < NUM_OF_DSK */
|
||||
static void writebuf(void) {
|
||||
int32 i, rtn;
|
||||
UNIT *uptr;
|
||||
i = current_byte[current_disk]; /* null-fill rest of sector if any */
|
||||
while (i < DSK_SECTSIZE) {
|
||||
dskbuf[i++] = 0;
|
||||
}
|
||||
uptr = dsk_dev.units + current_disk;
|
||||
if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
message4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
if (dskseek(uptr)) {
|
||||
message4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
||||
if (rtn != 1) {
|
||||
message4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn);
|
||||
}
|
||||
}
|
||||
else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) {
|
||||
/* write locked - print warning message if required */
|
||||
warnLock[current_disk]++;
|
||||
/*05*/
|
||||
message2("Attempt to write to locked DSK%d - ignored.", current_disk);
|
||||
}
|
||||
current_flag[current_disk] &= 0xfe; /* ENWD off */
|
||||
current_byte[current_disk] = 0xff;
|
||||
dirty = FALSE;
|
||||
int32 i, rtn;
|
||||
UNIT *uptr;
|
||||
i = current_byte[current_disk]; /* null-fill rest of sector if any */
|
||||
while (i < DSK_SECTSIZE) {
|
||||
dskbuf[i++] = 0;
|
||||
}
|
||||
uptr = dsk_dev.units + current_disk;
|
||||
if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */
|
||||
if (trace_flag & TRACE_READ_WRITE) {
|
||||
message4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
if (dskseek(uptr)) {
|
||||
message4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
||||
if (rtn != 1) {
|
||||
message4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn);
|
||||
}
|
||||
}
|
||||
else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) {
|
||||
/* write locked - print warning message if required */
|
||||
warnLock[current_disk]++;
|
||||
/*05*/ message2("Attempt to write to locked DSK%d - ignored.", current_disk);
|
||||
}
|
||||
current_flag[current_disk] &= 0xfe; /* ENWD off */
|
||||
current_byte[current_disk] = 0xff;
|
||||
dirty = FALSE;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,49 +1,49 @@
|
||||
/* altairz80_hdsk.c: simulated hard disk device to increase capacity
|
||||
/* altairz80_hdsk.c: simulated hard disk device to increase capacity
|
||||
|
||||
Copyright (c) 2002-2005, Peter Schorn
|
||||
Copyright (c) 2002-2005, 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:
|
||||
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 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
|
||||
PETER SCHORN 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.
|
||||
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
|
||||
PETER SCHORN 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.
|
||||
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 "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
|
||||
#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;
|
||||
@@ -70,8 +70,8 @@ static int32 doSeek(void);
|
||||
static int32 doRead(void);
|
||||
static int32 doWrite(void);
|
||||
|
||||
static int32 hdskLastCommand = hdsk_none;
|
||||
static int32 hdskCommandPosition = 0;
|
||||
static int32 hdskLastCommand = hdsk_none;
|
||||
static int32 hdskCommandPosition = 0;
|
||||
static int32 selectedDisk;
|
||||
static int32 selectedSector;
|
||||
static int32 selectedTrack;
|
||||
@@ -79,310 +79,324 @@ static int32 selectedDMA;
|
||||
static int32 hdskTrace;
|
||||
|
||||
static 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) } };
|
||||
{ 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) }
|
||||
};
|
||||
|
||||
static 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 } };
|
||||
{ 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 }
|
||||
};
|
||||
|
||||
static 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 } };
|
||||
{ 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, 0,
|
||||
NULL, NULL, NULL };
|
||||
"HDSK", hdsk_unit, hdsk_reg, hdsk_mod,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, NULL,
|
||||
&hdsk_boot, NULL, NULL,
|
||||
NULL, 0, 0,
|
||||
NULL, NULL, NULL
|
||||
};
|
||||
|
||||
static t_stat hdsk_svc(UNIT *uptr) {
|
||||
return SCPE_OK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static const 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 */
|
||||
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 */
|
||||
};
|
||||
|
||||
static 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++) {
|
||||
PutBYTEBasic(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;
|
||||
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++) {
|
||||
PutBYTEBasic(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 */
|
||||
static 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;
|
||||
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.
|
||||
/* 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
|
||||
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 */
|
||||
static int32 checkParameters(void) {
|
||||
int32 currentFlag;
|
||||
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
|
||||
if (hdsk_hasVerbose()) {
|
||||
message2("HDSK%d does not exist, will use HDSK0 instead.", 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.", 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.",
|
||||
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.",
|
||||
selectedDisk, selectedTrack, HDS_MAX_TRACKS);
|
||||
}
|
||||
selectedTrack = 0;
|
||||
}
|
||||
selectedDMA &= ADDRMASK;
|
||||
if (hdskTrace) {
|
||||
message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x",
|
||||
(hdskLastCommand == hdsk_read) ? "Read" : "Write",
|
||||
selectedDisk, selectedSector, selectedTrack, selectedDMA);
|
||||
}
|
||||
return TRUE;
|
||||
int32 currentFlag;
|
||||
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
|
||||
if (hdsk_hasVerbose()) {
|
||||
message2("HDSK%d does not exist, will use HDSK0 instead.", 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.", 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.",
|
||||
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.",
|
||||
selectedDisk, selectedTrack, HDS_MAX_TRACKS);
|
||||
}
|
||||
selectedTrack = 0;
|
||||
}
|
||||
selectedDMA &= ADDRMASK;
|
||||
if (hdskTrace) {
|
||||
message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x",
|
||||
(hdskLastCommand == hdsk_read) ? "Read" : "Write",
|
||||
selectedDisk, selectedSector, selectedTrack, selectedDMA);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static 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.",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
else {
|
||||
return CPM_OK;
|
||||
}
|
||||
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.",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
else {
|
||||
return CPM_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 doRead(void) {
|
||||
int32 i;
|
||||
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */
|
||||
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.",
|
||||
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 i;
|
||||
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */
|
||||
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.",
|
||||
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;
|
||||
}
|
||||
|
||||
static int32 doWrite(void) {
|
||||
int32 i;
|
||||
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */
|
||||
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.",
|
||||
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.",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
return CPM_OK;
|
||||
int32 i;
|
||||
uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */
|
||||
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.",
|
||||
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.",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
static int32 hdsk_in(const int32 port) {
|
||||
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()) {
|
||||
message4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).",
|
||||
port, hdskLastCommand, hdskCommandPosition);
|
||||
}
|
||||
return CPM_OK;
|
||||
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()) {
|
||||
message4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).",
|
||||
port, hdskLastCommand, hdskCommandPosition);
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
static int32 hdsk_out(const 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 */
|
||||
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(const int32 port, const int32 io, const int32 data) {
|
||||
return io == 0 ? hdsk_in(port) : hdsk_out(data);
|
||||
return io == 0 ? hdsk_in(port) : hdsk_out(data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user