mirror of
https://github.com/open-simh/simh.git
synced 2026-05-03 14:49:02 +00:00
Notes For V3.8
The makefile now works for Linux and most Unix's. However, for Solaris and MacOS, you must first export the OSTYPE environment variable: > export OSTYPE > make Otherwise, you will get build errors. 1. New Features 1.1 3.8-0 1.1.1 SCP and Libraries - BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and show (respectively) a breakpoint at the current PC. 1.1.2 GRI - Added support for the GRI-99 processor. 1.1.3 HP2100 - Added support for the BACI terminal interface. - Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions. 1.1.4 Nova - Added support for 64KW memory (implemented in third-party CPU's). 1.1.5 PDP-11 - Added support for DC11, RC11, KE11A, KG11A. - Added modem control support for DL11. - Added ASCII character support for all 8b devices. 1.2 3.8-1 1.2.1 SCP and libraries - Added capability to set line connection order for terminal multiplexers. 1.2.2 HP2100 - Added support for 12620A/12936A privileged interrupt fence. - Added support for 12792C eight-channel asynchronous multiplexer. 1.3 3.8-2 1.3.1 1401 - Added "no rewind" option to magtape boot. 1.3.2 PDP-11 - Added RD32 support to RQ - Added debug support to RL 1.3.3 PDP-8 - Added FPP support (many thanks to Rick Murphy for debugging the code) 2. Bugs Fixed Please see the revision history on http://simh.trailing-edge.com or in the source module sim_rev.h.
This commit is contained in:
committed by
Mark Pizzolato
parent
9c4779c061
commit
35eac703c3
BIN
swtp/6800boot.dsk
Normal file
BIN
swtp/6800boot.dsk
Normal file
Binary file not shown.
BIN
swtp/6800work.dsk
Normal file
BIN
swtp/6800work.dsk
Normal file
Binary file not shown.
100
swtp/swtp.txt
Normal file
100
swtp/swtp.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
SWTP 6800 Emulator
|
||||
=====================
|
||||
|
||||
1. Background.
|
||||
|
||||
The Southwest Technical Products (SWTP) SWTP 6800 was announced 1n the 1976 SWTP Catalog, which boasted you could buy and build this powerful computer kit for only $395. The kit consisted at that time of only the parts to build a case, power supply, mother board, CPU card, serial card with RS-232 or 20 ma loop interface, and memory card with 2048 *bytes* of static memory.
|
||||
|
||||
2. Hardware
|
||||
|
||||
We are simulating a fairly "loaded" SWTP 6800 from about 1978, with the following configuration:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU SWTP MP-A with Motorola 6080 CPU board, 62KB of RAM, 2K of EPROM with start boot ROM.
|
||||
SIO SWTP MP-S Dual Serial Interface Board. Port 1 is assumed to be connected to a serial "glass TTY" that is your terminal running the Simulator.
|
||||
PTR Second serial port of SIO is assumed to be connected to the paper tap reader/punch.
|
||||
PTP Second serial port of SIO is assumed to be connected to the paper tap reader/punch.
|
||||
DSK SWTP DC-4 Floppy Disk controller with up to four drives.
|
||||
|
||||
2.1 The CPU Card (MP-A)
|
||||
|
||||
We allow you to select memory sizes, but be aware that some sample software requires the full 32K (i.e. FLEX). We emulate the SWTP SWTBUG boot rom.
|
||||
|
||||
SET CPU ITRAP Causes the simulator to halt if an invalid 8080 Opcode is detected.
|
||||
SET CPU NOITRAP Does not stop on an invalid Opcode. This is how the real 6800 operates.
|
||||
SET CPU MTRAP Causes the simulator to halt if an invalid address is accessed.
|
||||
SET CPU NOMTRAP Does not stop on invalid address access. This is how a real 6800 operates.
|
||||
SET CPU 4K
|
||||
SET CPU 8K
|
||||
SET CPU 12K
|
||||
SET CPU 16K
|
||||
......
|
||||
SET CPU 32K All these set various CPU memory configurations.
|
||||
The 2K EPROM at the high end of memory is always present and will always boot.
|
||||
SET CPU MA000 Enable 8 K bytes of memory at $A000-$BFFF. Otherwise, only 128 bytes re available at $A000.
|
||||
SET CPU NOMA000 Enable only 128 bytes of memory at $A000.
|
||||
|
||||
The SWTBUG EPROM maps to both addresses $E000-E3FF and $FC00-FFFF.
|
||||
|
||||
The real 6800, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator is a lot nicer, it will halt but send you back to the simulator command line.
|
||||
|
||||
CPU Registers include the following:
|
||||
|
||||
name size comments
|
||||
|
||||
PC 16 Program Counter
|
||||
A 8 Accumulator A
|
||||
B 8 Accumulator B
|
||||
IX 16 Index Register
|
||||
C 1 Carry flag
|
||||
Z 1 Zero Flag
|
||||
H 1 Half-Carry flag
|
||||
I 1 Interrupt flag
|
||||
N 1 Negative flag
|
||||
V 1 Overflao Flag
|
||||
|
||||
|
||||
2.2 The Serial I/O Card (MP-S)
|
||||
|
||||
This simple programmed I/O device provides 2 serial ports to the outside world, which could be hardware jumpered to support RS-232 plugs or a TTY current loop interface. The standard I/O addresses assigned by SWTP was $8004-8005 for the first port, and $8006-8007 for the second. We follow this standard in the Simulator.
|
||||
|
||||
The simulator directs I/O to/from the first port to the screen. The second port reads from an attachable "tape reader" file on input, and writes to an attachable "punch file" on output. These files are considered a simple stream of 8-bit bytes.
|
||||
|
||||
2.3 The Floppy Disk controller (DC4)
|
||||
|
||||
The SWTP DC4 is a simple programmed I/O interface to the SWTP MF-68 5-inch dual floppy drive, which was basically a pair of Shugart SA-400s with a power supply and buffer board builtin. The controller supports neither interrupts nor DMA, so floppy access required the sustained attention of the CPU. The standard I/O addresses were $8018-801B, and we follow the standard. Details on controlling this hardware are in the swtp_dsk.c source file.
|
||||
|
||||
|
||||
3. Sample Software
|
||||
|
||||
Running an SWTP 6800 in 1978 you would be running the FLEX Version 2.0 Operating System from Technical Systems Consultants, Inc.
|
||||
|
||||
3.1 CP/M Version 2.2
|
||||
|
||||
This version is a port of the standard FLEX Version 2.0 to the SWTP 6800.
|
||||
|
||||
To boot FLEX:
|
||||
|
||||
sim> set cpu hex
|
||||
sim> set cpu itrap
|
||||
sim> set cpu mtrap
|
||||
sim> att dsk 6800boot.dsk
|
||||
sim> att dsk1 6800work.dsk
|
||||
sim> set cpu MA000
|
||||
sim> set dsk1 rw
|
||||
sim> go
|
||||
|
||||
$D ; Capital D causes SWTBUG to boot Flex
|
||||
FLEX 2.0
|
||||
|
||||
DATE (MM,DD,YY)? 03,09,99 ; Must enter a date from last century!
|
||||
|
||||
+++ ;Flex prompt!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
9
swtp/swtp6800
Normal file
9
swtp/swtp6800
Normal file
@@ -0,0 +1,9 @@
|
||||
reset
|
||||
set cpu hex
|
||||
set cpu itrap
|
||||
set cpu mtrap
|
||||
att dsk 6800boot.dsk
|
||||
att dsk1 6800work.dsk
|
||||
set cpu MA000
|
||||
set dsk1 rw
|
||||
g
|
||||
2293
swtp/swtp_cpu.c
Normal file
2293
swtp/swtp_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
46
swtp/swtp_defs.h
Normal file
46
swtp/swtp_defs.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* swtp_defs.h: SWTP 6800 simulator definitions
|
||||
|
||||
Copyright (c) 2005, 2007, William Beech
|
||||
|
||||
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
|
||||
WILLIAM A BEECH 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 William A Beech shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from William A Beech.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
|
||||
|
||||
*/
|
||||
|
||||
#include "../sim_defs.h" // simulator defs
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 65536 // max memory size
|
||||
#define MEMSIZE (cpu_unit.capac)// actual memory size
|
||||
#define ADDRMASK (MAXMEMSIZE - 1)// address mask
|
||||
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_RSRV 1 // must be 1
|
||||
#define STOP_HALT 2 // HALT-really WAI
|
||||
#define STOP_IBKPT 3 // breakpoint
|
||||
#define STOP_OPCODE 4 // invalid opcode
|
||||
#define STOP_MEMORY 5 // invalid memory address
|
||||
|
||||
506
swtp/swtp_dsk.c
Normal file
506
swtp/swtp_dsk.c
Normal file
@@ -0,0 +1,506 @@
|
||||
/* swtp_dc4_dsk.c: SWTP DC-4 DISK Simulator
|
||||
|
||||
Copyright (c) 2005, William A. Beech
|
||||
|
||||
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 William A. Beech shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from William A. Beech.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
|
||||
|
||||
|
||||
The DC-4 is a 5-inch floppy controller which can control up
|
||||
to 4 daisy-chained 5-inch floppy drives. The controller is based on
|
||||
the Western Digital 1797 Floppy Disk Controller (FDC) chip. This
|
||||
file only emulates the minimum DC-4 functionality to interface with
|
||||
the virtual disk file.
|
||||
|
||||
The floppy controller is interfaced to the CPU by use of 5 memory
|
||||
addreses. These are device numbers 5 and 6 (0x8014-0x801B).
|
||||
|
||||
Address Mode Function
|
||||
------- ---- --------
|
||||
|
||||
0x8014 Read Returns FDC interrupt status
|
||||
0x8014 Write Selects the drive/head/motor control
|
||||
0x8018 Read Returns status of FDC
|
||||
0x8018 Write FDC command register
|
||||
0x8019 Read Returns FDC track register
|
||||
0x8019 Write Set FDC track register
|
||||
0x801A Read Returns FDC sector register
|
||||
0x801A Write Set FDC sector register
|
||||
0x801B Read Read data
|
||||
0x801B Write Write data
|
||||
|
||||
Drive Select Read (0x8014):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| I | D | X | X | X | X | X | X |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
I = Set indicates an interrupt request from the FDC pending.
|
||||
D = DRQ pending - same as bit 1 of FDC status register.
|
||||
|
||||
Drive Select Write (0x8014):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| M | S | X | X | X | X | Device|
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
M = If this bit is 1, the one-shot is triggered/retriggered to
|
||||
start/keep the motors on.
|
||||
S = Side select. If set, side one is selected otherwise side zero
|
||||
is selected.
|
||||
X = not used
|
||||
Device = value 0 thru 3, selects drive 0-3 to be controlled.
|
||||
|
||||
Drive Status Read (0x8018):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| R | P | H | S | C | L | D | B |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
B - When 1, the controller is busy.
|
||||
D - When 1, index mark detected (type I) or data request - read data
|
||||
ready/write data empty (type II or III).
|
||||
H - When 1, track 0 (type I) or lost data (type II or III).
|
||||
C - When 1, crc error detected.
|
||||
S - When 1, seek (type I) or RNF (type II or III) error.
|
||||
H - When 1, head is currently loaded (type I) or record type/
|
||||
write fault (type II or III).
|
||||
P - When 1, indicates that diskette is write-protected.
|
||||
R - When 1, drive is not ready.
|
||||
|
||||
Drive Control Write (0x8018) for type I commands:
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 0 | S2| S1| S0| H | V | R1| R0|
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
R0/R1 - Selects the step rate.
|
||||
V - When 1, verify on destination track.
|
||||
H - When 1, loads head to drive surface.
|
||||
S0/S1/S2 = 000 - home.
|
||||
001 - seek track in data register.
|
||||
010 - step without updating track register.
|
||||
011 - step and update track register.
|
||||
100 - step in without updating track register.
|
||||
101 - step in and update track register.
|
||||
110 - step out without updating track register.
|
||||
111 - step out and update track register.
|
||||
|
||||
Drive Control Write (0x8018) for type II commands:
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 1 | 0 | T | M | S | E | B | A |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
A - Zero for read, 1 on write deleted data mark else data mark.
|
||||
B - When 1, shifts sector length field definitions one place.
|
||||
E - When, delay operation 15 ms, 0 no delay.
|
||||
S - When 1, select side 1, 0 select side 0.
|
||||
M - When 1, multiple records, 0 for single record.
|
||||
T - When 1, write command, 0 for read.
|
||||
|
||||
Drive Control Write (0x8018) for type III commands:
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 1 | 1 | T0| T1| 0 | E | 0 | 0 |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
E - When, delay operation 15 ms, 0 no delay.
|
||||
T0/T1 - 00 - read address command.
|
||||
10 - read track command.
|
||||
11 - write track command.
|
||||
|
||||
Tracks are numbered from 0 up to one minus the last track in the 1797!
|
||||
|
||||
Track Register Read (0x8019):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| Track Number |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Reads the current 8-bit value from the track position.
|
||||
|
||||
Track Register Write (0x8019):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| Track Number |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Writes the 8-bit value to the track register.
|
||||
|
||||
Sectors are numbers from 1 up to the last sector in the 1797!
|
||||
|
||||
Sector Register Read (0x801A):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| Sector Number |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Reads the current 8-bit value from the sector position.
|
||||
|
||||
Sector Register Write (0x801A):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| Sector Number |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Writes the 8-bit value to the sector register.
|
||||
|
||||
Data Register Read (0x801B):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| Data |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Reads the current 8-bit value from the data register.
|
||||
|
||||
Data Register Write (0x801B):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| Data |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Writes the 8-bit value to the data register.
|
||||
|
||||
A FLEX disk is defined as follows:
|
||||
|
||||
Track Sector Use
|
||||
0 1 Boot sector
|
||||
0 2 Boot sector (cont)
|
||||
0 3 Unused
|
||||
0 4 System Identity Record (explained below)
|
||||
0 5 Unused
|
||||
0 6-last Directory - 10 entries/sector (explained below)
|
||||
1 1 First available data sector
|
||||
last-1 last Last available data sector
|
||||
|
||||
System Identity Record
|
||||
|
||||
Byte Use
|
||||
0x10 Volume ID (8 bytes)
|
||||
0x18 ???
|
||||
0x19 ???
|
||||
0x1A ???
|
||||
0x1B Volume number (2 bytes)
|
||||
0x1D First free sector (2 bytes)
|
||||
0x1F Last track minus one (byte)
|
||||
0x20 Last sector (byte)
|
||||
0x21 Total sectors on disk (2 bytes)
|
||||
0x23 Month (byte
|
||||
0x24 Day (byte)
|
||||
0x25 Year (byte)
|
||||
0x26 Last track minus one (byte)
|
||||
0x27 Last sector (byte)
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "swtp_defs.h"
|
||||
|
||||
#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */
|
||||
#define UNIT_ENABLE (1 << UNIT_V_ENABLE)
|
||||
|
||||
/* emulate a SS FLEX disk with 72 sectors and 80 tracks */
|
||||
|
||||
#define NUM_DISK 4 /* standard 1797 maximum */
|
||||
#define SECT_SIZE 256 /* standard FLEX sector */
|
||||
#define NUM_SECT 72 /* sectors/track */
|
||||
#define TRAK_SIZE (SECT_SIZE * NUM_SECT)
|
||||
#define HEADS 1 /* handle as SS with twice the sectors */
|
||||
#define NUM_CYL 80 /* maximum tracks */
|
||||
#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE)
|
||||
|
||||
/* 1797 status bits */
|
||||
|
||||
#define BUSY 0x01
|
||||
#define DRQ 0x02
|
||||
#define WRPROT 0x40
|
||||
#define NOTRDY 0x80
|
||||
|
||||
/* debug prints */
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
|
||||
/* prototypes */
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr);
|
||||
t_stat dsk_reset (DEVICE *dptr);
|
||||
int32 fdcdrv(int32 io, int32 data);
|
||||
int32 fdccmd(int32 io, int32 data);
|
||||
int32 fdctrk(int32 io, int32 data);
|
||||
int32 fdcsec(int32 io, int32 data);
|
||||
int32 fdcdata(int32 io, int32 data);
|
||||
|
||||
/* Global data on status */
|
||||
|
||||
int32 cur_dsk = NUM_DISK; /* Currently selected drive */
|
||||
int32 cur_trk[NUM_DISK] = {0, 0, 0, 0};
|
||||
int32 cur_sec[NUM_DISK] = {0, 0, 0, 0};
|
||||
int32 cur_byt[NUM_DISK] = {0, 0, 0, 0};
|
||||
int32 cur_flg[NUM_DISK] = {NOTRDY, NOTRDY, NOTRDY, NOTRDY};
|
||||
|
||||
/* Variables */
|
||||
|
||||
uint8 dskbuf[SECT_SIZE]; /* Data Buffer */
|
||||
UNIT *dptr = NULL; /* fileref to write dirty buffer to */
|
||||
int32 fdcbyte;
|
||||
int32 intrq = 0; /* interrupt request flag */
|
||||
|
||||
/* DC-4 Simh Device Data Structures */
|
||||
|
||||
UNIT dsk_unit[] = {
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } };
|
||||
|
||||
REG dsk_reg[] = {
|
||||
{ HRDATA (DISK, cur_dsk, 4) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dsk_mod[] = {
|
||||
{ UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL },
|
||||
{ UNIT_ENABLE, 0, "RO", "RO", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dsk_dev = {
|
||||
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||
NUM_DISK, 16, 16, 1, 16, 8,
|
||||
NULL, NULL, &dsk_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* service routines to handle simlulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dsk_reset (DEVICE *dptr)
|
||||
{
|
||||
cur_dsk = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
memory read or write to the proper addresses 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.
|
||||
*/
|
||||
|
||||
/* DC-4 drive select register routine - this register is not part of the 1797
|
||||
*/
|
||||
|
||||
int32 fdcdrv(int32 io, int32 data)
|
||||
{
|
||||
/* **** probably need to grab the parameters from the SIR and set the limits */
|
||||
if (io) { /* write to DC-4 drive register */
|
||||
cur_dsk = data & 0x03; /* only 2 drive select bits */
|
||||
#if DEBUG > 0
|
||||
printf("Drive set to %d\n\r", cur_dsk);
|
||||
#endif
|
||||
if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0)
|
||||
cur_flg[cur_dsk] |= WRPROT; /* set WPROT */
|
||||
return 0;
|
||||
} else { /* read from DC-4 drive register */
|
||||
#if DEBUG > 0
|
||||
printf("Drive read as %02X\n\r", intrq);
|
||||
#endif
|
||||
return intrq;
|
||||
}
|
||||
}
|
||||
|
||||
/* WD 1797 FDC command register routine */
|
||||
|
||||
int32 fdccmd(int32 io, int32 data)
|
||||
{
|
||||
static int32 val = 0, val1 = NOTRDY, i;
|
||||
static long pos;
|
||||
UNIT *uptr;
|
||||
|
||||
if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */
|
||||
cur_flg[cur_dsk] |= NOTRDY; /* set not ready flag */
|
||||
printf("Drive %d is not attached\n\r", cur_dsk);
|
||||
return 0;
|
||||
} else {
|
||||
cur_flg[cur_dsk] &= ~NOTRDY; /* clear not ready flag */
|
||||
}
|
||||
uptr = dsk_dev.units + cur_dsk; /* get virtual drive address */
|
||||
if (io) { /* write command to fdc */
|
||||
switch(data) {
|
||||
case 0x8C: /* read command */
|
||||
case 0x9C:
|
||||
#if DEBUG > 0
|
||||
printf("Read of disk %d, track %d, sector %d\n\r",
|
||||
cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]);
|
||||
#endif
|
||||
pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */
|
||||
pos += SECT_SIZE * (cur_sec[cur_dsk] - 1);
|
||||
#if DEBUG > 0
|
||||
printf("Read pos = %ld ($%04X)\n\r", pos, pos);
|
||||
#endif
|
||||
sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */
|
||||
sim_fread(dskbuf, 256, 1, uptr -> fileref); /* read in buffer */
|
||||
cur_flg[cur_dsk] |= BUSY | DRQ; /* set DRQ & BUSY */
|
||||
i = cur_byt[cur_dsk] = 0; /* clear counter */
|
||||
break;
|
||||
case 0xAC: /* write command */
|
||||
#if DEBUG > 0
|
||||
printf("Write of disk %d, track %d, sector %d\n\r",
|
||||
cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]);
|
||||
#endif
|
||||
if (cur_flg[cur_dsk] & WRPROT) {
|
||||
printf("Drive %d is write-protected\n\r", cur_dsk);
|
||||
} else {
|
||||
pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */
|
||||
pos += SECT_SIZE * (cur_sec[cur_dsk] - 1);
|
||||
#if DEBUG > 1
|
||||
printf("Write pos = %ld ($%04X)\n\r", pos, pos);
|
||||
#endif
|
||||
sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */
|
||||
dptr = uptr; /* save pointer for actual write */
|
||||
cur_flg[cur_dsk] |= BUSY | DRQ;/* set DRQ & BUSY */
|
||||
i = cur_byt[cur_dsk] = 0; /* clear counter */
|
||||
}
|
||||
break;
|
||||
case 0x18: /* seek command */
|
||||
case 0x1B:
|
||||
cur_trk[cur_dsk] = fdcbyte; /* set track */
|
||||
cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */
|
||||
#if DEBUG > 0
|
||||
printf("Seek of disk %d, track %d\n\r", cur_dsk, fdcbyte);
|
||||
#endif
|
||||
break;
|
||||
case 0x0B: /* restore command */
|
||||
cur_trk[cur_dsk] = 0; /* home the drive */
|
||||
cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */
|
||||
#if DEBUG > 0
|
||||
printf("Drive %d homed\n\r", cur_dsk);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
printf("Unknown FDC command %02H\n\r", data);
|
||||
}
|
||||
} else { /* read status from fdc */
|
||||
val = cur_flg[cur_dsk]; /* set return value */
|
||||
if (val1 == 0 && val == 0x03) /* delay BUSY going high */
|
||||
val = 0x02; /* set DRQ first */
|
||||
if (val != val1) { /* now allow BUSY after on read */
|
||||
val1 = val;
|
||||
#if DEBUG > 0
|
||||
printf("Drive %d status=%02X\n\r", cur_dsk, cur_flg[cur_dsk]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* WD 1797 FDC track register routine */
|
||||
|
||||
int32 fdctrk(int32 io, int32 data)
|
||||
{
|
||||
if (io) {
|
||||
cur_trk[cur_dsk] = data & 0xFF;
|
||||
#if DEBUG > 1
|
||||
printf("Drive %d track set to %d\n\r", cur_dsk, data);
|
||||
#endif
|
||||
} else
|
||||
;
|
||||
#if DEBUG > 1
|
||||
printf("Drive %d track read as %d\n\r", cur_dsk, cur_trk[cur_dsk]);
|
||||
#endif
|
||||
return cur_trk[cur_dsk];
|
||||
}
|
||||
|
||||
/* WD 1797 FDC sector register routine */
|
||||
|
||||
int32 fdcsec(int32 io, int32 data)
|
||||
{
|
||||
if (io) {
|
||||
cur_sec[cur_dsk] = data & 0xFF;
|
||||
if (cur_sec[cur_dsk] == 0) /* fix for swtp boot! */
|
||||
cur_sec[cur_dsk] = 1;
|
||||
#if DEBUG > 1
|
||||
printf("Drive %d sector set to %d\n\r", cur_dsk, data);
|
||||
#endif
|
||||
} else
|
||||
;
|
||||
#if DEBUG > 1
|
||||
printf("Drive %d sector read as %d\n\r", cur_dsk, cur_sec[cur_dsk]);
|
||||
#endif
|
||||
return cur_sec[cur_dsk];
|
||||
}
|
||||
|
||||
/* WD 1797 FDC data register routine */
|
||||
|
||||
int32 fdcdata(int32 io, int32 data)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (io) { /* write byte to fdc */
|
||||
fdcbyte = data; /* save for seek */
|
||||
if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes to buffer */
|
||||
#if DEBUG > 3
|
||||
printf("Writing byte %d of %02X\n\r", cur_byt[cur_dsk], data);
|
||||
#endif
|
||||
cur_byt[cur_dsk]++; /* step counter */
|
||||
dskbuf[i] = data; /* byte into buffer */
|
||||
if (cur_byt[cur_dsk] == SECT_SIZE) {
|
||||
cur_flg[cur_dsk] &= ~(BUSY | DRQ);
|
||||
if (dptr) { /* if initiated by FDC write command */
|
||||
sim_fwrite(dskbuf, 256, 1, dptr -> fileref); /* write it */
|
||||
dptr = NULL;
|
||||
}
|
||||
#if DEBUG > 0
|
||||
printf("Sector write complete\n\r");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else { /* read byte from fdc */
|
||||
if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes from buffer */
|
||||
#if DEBUG > 1
|
||||
printf("Reading byte %d\n\r", cur_byt[cur_dsk]);
|
||||
#endif
|
||||
cur_byt[cur_dsk]++; /* step counter */
|
||||
if (cur_byt[cur_dsk] == SECT_SIZE) { /* done? */
|
||||
cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */
|
||||
#if DEBUG > 0
|
||||
printf("Sector read complete\n\r");
|
||||
#endif
|
||||
}
|
||||
return (dskbuf[i] & 0xFF);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
312
swtp/swtp_sio.c
Normal file
312
swtp/swtp_sio.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/* swtp_sio: SWTP serial I/O card
|
||||
|
||||
Copyright (c) 2005, William Beech
|
||||
|
||||
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
|
||||
Willaim Beech 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 William A. Beech shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from William A. Beech.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
|
||||
|
||||
These functions support a simulated SWTP MP-S interface card.
|
||||
The card had two physical I/O ports which could be connected
|
||||
to any serial I/O device that would connect to a current loop
|
||||
or RS232 interface. Available baud rates were jumper selectable
|
||||
for each port from 110 to 9600. The ports appear at all 4 addresses.
|
||||
This fact is used by SWTBUG to determine the presence of the MP-S vice
|
||||
MP-C serial card.
|
||||
|
||||
All I/O is via either programmed I/O or interrupt controlled I/O.
|
||||
It has a status port and a data port. A write to the status port
|
||||
can select some options for the device (0x03 will reset the port).
|
||||
A read of the status port gets the port status:
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| I | P | O | F |CTS|DCD|TXE|RXF|
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
RXF - A 1 in this bit position means a character has been received
|
||||
on the data port and is ready to be read.
|
||||
TXE - A 1 in this bit means the port is ready to receive a character
|
||||
on the data port and transmit it out over the serial line.
|
||||
|
||||
A read to the data port gets the buffered character, a write
|
||||
to the data port writes the character to the device.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "swtp_defs.h"
|
||||
|
||||
#define UNIT_V_ANSI (UNIT_V_UF + 0) // ANSI mode
|
||||
#define UNIT_ANSI (1 << UNIT_V_ANSI)
|
||||
|
||||
t_stat sio_svc (UNIT *uptr);
|
||||
t_stat sio_reset (DEVICE *dptr);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
|
||||
int32 ptr_stopioe = 0, ptp_stopioe = 0; // stop on error
|
||||
|
||||
// MP-S Standard I/O Data Structures
|
||||
|
||||
UNIT sio_unit = { UDATA (&sio_svc, 0, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG sio_reg[] = {
|
||||
{ ORDATA (DATA, sio_unit.buf, 8) },
|
||||
{ ORDATA (STAT, sio_unit.u3, 8) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB sio_mod[] = {
|
||||
{ UNIT_ANSI, 0, "TTY", "TTY", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE sio_dev = {
|
||||
"MP-S", &sio_unit, sio_reg, sio_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &sio_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, NULL, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, NULL, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Service routines to handle simulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
int32 ptp_rdr(int32 io, int32 data);
|
||||
|
||||
int32 ptp_flag = 0, ptr_flag = 0;
|
||||
|
||||
/* console input service routine */
|
||||
|
||||
int32 sio_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&sio_unit, sio_unit.wait); // continue poll
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
|
||||
return temp; // no char or error?
|
||||
sio_unit.buf = temp & 0xFF; // Save char
|
||||
sio_unit.u3 |= 0x01; // Set RXF flag
|
||||
|
||||
/* Do any special character handling here */
|
||||
|
||||
sio_unit.pos++; // step character count
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* paper tape reader input service routine */
|
||||
|
||||
int32 ptr_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* paper tape punch output service routine */
|
||||
|
||||
int32 ptp_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset console */
|
||||
|
||||
int32 sio_reset (DEVICE *dptr)
|
||||
{
|
||||
sio_unit.buf = 0; // Data buffer
|
||||
sio_unit.u3 = 0x02; // Status buffer
|
||||
sim_activate (&sio_unit, sio_unit.wait); // activate unit
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset paper tape reader */
|
||||
|
||||
int32 ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
ptr_unit.buf = 0;
|
||||
ptr_unit.u3 = 0x02;
|
||||
sim_cancel (&ptr_unit); // deactivate unit
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset paper tape punch */
|
||||
|
||||
int32 ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
ptp_unit.buf = 0;
|
||||
ptp_unit.u3 = 0x02;
|
||||
sim_cancel (&ptp_unit); // deactivate unit
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when a
|
||||
read or write occur to addresses 0x8000-0x801F.
|
||||
|
||||
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.
|
||||
|
||||
This code emulates a SWTP MP-S Serial Card with a Model 33 Teletype
|
||||
attached. The Model 33 uses DC1-DC4 codes to enable or disable the
|
||||
paper tape reader and punch. Those devices are defined in this module,
|
||||
and the code built to emulate those functions if the PTP and/or PTR
|
||||
are attached in the simulator.
|
||||
*/
|
||||
|
||||
/* Port 1 (0x8004-0x8007) controls the Model 33 Teletype */
|
||||
|
||||
int32 ptr_flg1 = 0;
|
||||
int32 odata, status;
|
||||
|
||||
|
||||
int32 sio0s(int32 io, int32 data)
|
||||
{
|
||||
UNIT *uptr;
|
||||
|
||||
if (io == 0) { // control register read
|
||||
if (ptr_flag) { // reader enabled?
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) // attached?
|
||||
ptr_unit.u3 &= 0xFE; // no, clear RXF flag
|
||||
else {
|
||||
uptr = ptr_dev.units;// not EOF?
|
||||
if (feof(uptr -> fileref))
|
||||
ptr_unit.u3 &= 0xFE;
|
||||
else
|
||||
ptr_unit.u3 |= 0x01;
|
||||
}
|
||||
return (status = ptr_unit.u3); // no - done
|
||||
} else {
|
||||
return (status = sio_unit.u3); // return console status
|
||||
}
|
||||
} else { // control register write
|
||||
if (data == 0x03) { // reset port!
|
||||
sio_unit.u3 = 0x02; // reset console
|
||||
sio_unit.buf = 0;
|
||||
sio_unit.pos = 0;
|
||||
ptr_unit.u3 = 0x02; // reset reader
|
||||
ptr_unit.buf = 0;
|
||||
ptr_unit.pos = 0;
|
||||
ptp_unit.u3 = 0x02; // reset punch
|
||||
ptp_unit.buf = 0;
|
||||
ptp_unit.pos = 0;
|
||||
}
|
||||
return (status = 0); // invalid io
|
||||
}
|
||||
}
|
||||
|
||||
int32 sio0d(int32 io, int32 data)
|
||||
{
|
||||
UNIT *uptr;
|
||||
|
||||
if (io == 0) { // data register read
|
||||
if (ptr_flag) { // RDR enabled?
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) // attached?
|
||||
return 0; // no, done
|
||||
// printf("ptr_unit.u3=%02X\n", ptr_unit.u3);
|
||||
if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data?
|
||||
// printf("Returning old %02X\n", odata); // no, return previous byte
|
||||
return (odata & 0xFF);
|
||||
}
|
||||
uptr = ptr_dev.units; // get data byte
|
||||
if ((odata = getc(uptr -> fileref)) == EOF) { // end of file?
|
||||
// printf("Got EOF\n");
|
||||
ptr_unit.u3 &= 0xFE; // clear RXF flag
|
||||
return (odata = 0); // no data
|
||||
}
|
||||
// printf("Returning new %02X\n", odata);
|
||||
ptr_unit.pos++; // step character count
|
||||
ptr_unit.u3 &= 0xFE; // clear RXF flag
|
||||
return (odata & 0xFF); // return character
|
||||
} else {
|
||||
sio_unit.u3 &= 0xFE; // clear RXF flag
|
||||
return (odata = sio_unit.buf); // return next char
|
||||
}
|
||||
} else { // data register write
|
||||
if (isprint(data) || data == '\r' || data == '\n') { // printable?
|
||||
sim_putchar(data); // print character on console
|
||||
if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached?
|
||||
uptr = ptp_dev.units; // punch character to file
|
||||
putc(data, uptr -> fileref);
|
||||
ptp_unit.pos++; // step character counter
|
||||
}
|
||||
} else { // DC1-DC4 control Reader/Punch
|
||||
switch (data) {
|
||||
case 0x11: // RDR on
|
||||
ptr_flag = 1;
|
||||
ptr_flg1 = 0;
|
||||
ptr_unit.u3 |= 0x01;
|
||||
// printf("Reader on\r\n");
|
||||
break;
|
||||
case 0x12: // PTP on
|
||||
ptp_flag = 1;
|
||||
ptp_unit.u3 |= 0x02;
|
||||
// printf("Punch on\r\n");
|
||||
break;
|
||||
case 0x13: // RDR off
|
||||
ptr_flag = 0;
|
||||
// printf("Reader off-%d bytes read\r\n", ptr_unit.pos);
|
||||
break;
|
||||
case 0x14: // PTP off
|
||||
ptp_flag = 0;
|
||||
// printf("Punch off-%d bytes written\r\n", ptp_unit.pos);
|
||||
break;
|
||||
default: // ignore all other characters
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (odata = 0);
|
||||
}
|
||||
|
||||
/* because each port appears at 2 addresses and this fact is used
|
||||
to determine if it is a MP-C or MP-S repeatedly in the SWTBUG
|
||||
monitor, this code assures that reads of the high ports return
|
||||
the same data as was read the last time on the low ports.
|
||||
*/
|
||||
|
||||
int32 sio1s(int32 io, int32 data)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
int32 sio1d(int32 io, int32 data)
|
||||
{
|
||||
return odata;
|
||||
}
|
||||
|
||||
425
swtp/swtp_sys.c
Normal file
425
swtp/swtp_sys.c
Normal file
@@ -0,0 +1,425 @@
|
||||
/* swtp_sys.c: SWTP 6800 system interface
|
||||
|
||||
Copyright (c) 2005, William Beech
|
||||
|
||||
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
|
||||
WILLIAM A BEECH 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 William A. Beech shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from William A. Beech.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "swtp_defs.h"
|
||||
|
||||
/* externals */
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE dsk_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern DEVICE sio_dev;
|
||||
extern DEVICE ptr_dev;
|
||||
extern DEVICE ptp_dev;
|
||||
extern DEVICE lpt_dev;
|
||||
extern unsigned char M[];
|
||||
extern int32 saved_PC;
|
||||
extern int32 sim_switches;
|
||||
//extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr);
|
||||
|
||||
/* prototypes */
|
||||
|
||||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag);
|
||||
int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
|
||||
UNIT *uptr, int32 sw);
|
||||
t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr);
|
||||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw);
|
||||
void sim_special_init (void);
|
||||
|
||||
/* links into scp */
|
||||
|
||||
void (*sim_vm_init)(void) = &sim_special_init;
|
||||
|
||||
/* SCP data structures
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words needed for examine
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "SWTP 6800";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 16;
|
||||
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unknown I/O Instruction",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Invalid Opcode",
|
||||
"Invalid Memory" };
|
||||
|
||||
static const char *opcode[] = {
|
||||
"???", "NOP", "???", "???", //0x00
|
||||
"???", "???", "TAP", "TPA",
|
||||
"INX", "DEX", "CLV", "SEV",
|
||||
"CLC", "SEC", "CLI", "SEI",
|
||||
"SBA", "CBA", "???", "???", //0x10
|
||||
"???", "???", "TAB", "TBA",
|
||||
"???", "DAA", "???", "ABA",
|
||||
"???", "???", "???", "???",
|
||||
"BRA", "???", "BHI", "BLS", //0x20
|
||||
"BCC", "BCS", "BNE", "BEQ",
|
||||
"BVC", "BVS", "BPL", "BMI",
|
||||
"BGE", "BLT", "BGT", "BLE",
|
||||
"TSX", "INS", "PULA", "PULB", //0x30
|
||||
"DES", "TXS", "PSHA", "PSHB",
|
||||
"???", "RTS", "???", "RTI",
|
||||
"???", "???", "WAI", "SWI",
|
||||
"NEGA", "???", "???", "COMA", //0x40
|
||||
"LSRA", "???", "RORA", "ASRA",
|
||||
"ASLA", "ROLA", "DECA", "???",
|
||||
"INCA", "TSTA", "???", "CLRA",
|
||||
"NEGB", "???", "???", "COMB", //0x50
|
||||
"LSRB", "???", "RORB", "ASRB",
|
||||
"ASLB", "ROLB", "DECB", "???",
|
||||
"INCB", "TSTB", "???", "CLRB",
|
||||
"NEG", "???", "???", "COM", //0x60
|
||||
"LSR", "???", "ROR", "ASR",
|
||||
"ASL", "ROL", "DEC", "???",
|
||||
"INC", "TST", "JMP", "CLR",
|
||||
"NEG", "???", "???", "COM", //0x70
|
||||
"LSR", "???", "ROR", "ASR",
|
||||
"ASL", "ROL", "DEC", "???",
|
||||
"INC", "TST", "JMP", "CLR",
|
||||
"SUBA", "CMPA", "SBCA", "???", //0x80
|
||||
"ANDA", "BITA", "LDAA", "???",
|
||||
"EORA", "ADCA", "ORAA", "ADDA",
|
||||
"CPX", "BSR", "LDS", "???",
|
||||
"SUBA", "CMPA", "SBCA", "???", //0x90
|
||||
"ANDA", "BITA", "LDAA", "STAA",
|
||||
"EORA", "ADCA", "ORAA", "ADDA",
|
||||
"CPX", "???", "LDS", "STS",
|
||||
"SUBA", "CMPA", "SBCA", "???", //0xA0
|
||||
"ANDA", "BITA", "LDAA", "STAA",
|
||||
"EORA", "ADCA", "ORAA", "ADDA",
|
||||
"CPX X", "JSR X", "LDS X", "STS X",
|
||||
"SUBA", "CMPA", "SBCA", "???", //0xB0
|
||||
"ANDA", "BITA", "LDAA", "STAA",
|
||||
"EORA", "ADCA", "ORAA", "ADDA",
|
||||
"CPX", "JSR", "LDS", "STS",
|
||||
"SUBB", "CMPB", "SBCB", "???", //0xC0
|
||||
"ANDB", "BITB", "LDAB", "???",
|
||||
"EORB", "ADCB", "ORAB", "ADDB",
|
||||
"???", "???", "LDX", "???",
|
||||
"SUBB", "CMPB", "SBCB", "???", //0xD0
|
||||
"ANDB", "BITB", "LDAB", "STAB",
|
||||
"EORB", "ADCB", "ORAB", "ADDB",
|
||||
"???", "???", "LDX", "STX",
|
||||
"SUBB", "CMPB", "SBCB", "???", //0xE0
|
||||
"ANDB", "BITB", "LDAB", "STAB",
|
||||
"EORB", "ADCB", "ORAB", "ADDB",
|
||||
"???", "???", "LDX", "STX",
|
||||
"SUBB", "CMPB", "SBCB", "???", //0xF0
|
||||
"ANDB", "BITB", "LDAB", "STAB",
|
||||
"EORB", "ADCB", "ORAB", "ADDB",
|
||||
"???", "???", "LDX", "STX",
|
||||
};
|
||||
|
||||
int32 oplen[256] = {
|
||||
0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00
|
||||
1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0,
|
||||
2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,
|
||||
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40
|
||||
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,
|
||||
2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2,
|
||||
3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3,
|
||||
2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80
|
||||
2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2,
|
||||
2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,
|
||||
2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0
|
||||
2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,
|
||||
2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,
|
||||
3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 };
|
||||
|
||||
/* This is the dumper/loader. This command uses the -h to signify a
|
||||
hex dump/load vice a binary one. If no address is given to load, it
|
||||
takes the address from the hex record or the current PC for binary.
|
||||
*/
|
||||
|
||||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt,
|
||||
cksum1, cksum, bytes[250];
|
||||
char buffer[256];
|
||||
|
||||
sscanf(cptr," %x-%x", &start, &end);
|
||||
if (flag) { // dump
|
||||
if (start == 0x10000) // no address parameter
|
||||
return SCPE_2FARG;
|
||||
if (sim_switches & 0x80) { // hex dump
|
||||
addr = start;
|
||||
while (addr <= end) { // more records to write
|
||||
if ((addr + 16) <= end) // how many bytes this record
|
||||
bytecnt = 16 + 3;
|
||||
else
|
||||
bytecnt = end - addr + 4;
|
||||
cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum
|
||||
fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header
|
||||
for (i=0; i<bytecnt-3; i++, addr++, cnt++) { // data
|
||||
fprintf(fileref, "%02X", M[addr]);
|
||||
cksum -= M[addr];
|
||||
}
|
||||
fprintf(fileref, "%02X\r\n", cksum & 0xff); // eor
|
||||
}
|
||||
fprintf(fileref, "S9\r\n"); // eof
|
||||
} else { // binary dump
|
||||
for (addr = start; addr <= end; addr++, cnt++) {
|
||||
putc(M[addr], fileref);
|
||||
}
|
||||
}
|
||||
printf ("%d Bytes dumped starting at %04X\n", cnt, start);
|
||||
} else { // load
|
||||
if (sim_switches & 0x80) { // hex load
|
||||
while ((fgets(buffer, 255, fileref)) != NULL) {
|
||||
if (buffer[0] != 'S')
|
||||
printf("Not a Motorola hex format file\n");
|
||||
else {
|
||||
if (buffer[0] == '0') // name record
|
||||
printf("Name record found and ignored\n");
|
||||
else if (buffer[1] == '1') { // another record
|
||||
sscanf(buffer+2,"%2x%4x", &bytecnt, &addr);
|
||||
if (start == 0x10000)
|
||||
start = addr;
|
||||
for (i=0; i < bytecnt-3; i++)
|
||||
sscanf(buffer+8+(2*i), "%2x", &bytes[i]);
|
||||
sscanf(buffer+8+(2*i), "%2x", &cksum1);
|
||||
cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum
|
||||
for (i=0; i < bytecnt-3; i++)
|
||||
cksum -= bytes[i];
|
||||
cksum &= 0xFF;
|
||||
if (cksum != cksum1)
|
||||
printf("Checksum error\n");
|
||||
else {
|
||||
for (i=0; i < bytecnt-3; i++) {
|
||||
M[addr++] = bytes[i];
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
} else if (buffer[1] == '9') // end of file
|
||||
printf("End of file\n");
|
||||
}
|
||||
}
|
||||
} else { // binary load
|
||||
if (start == 0x10000) // no starting address
|
||||
addr = saved_PC;
|
||||
else
|
||||
addr = start;
|
||||
start = addr;
|
||||
while ((i = getc (fileref)) != EOF) {
|
||||
M[addr] = i;
|
||||
addr++;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
printf ("%d Bytes loaded starting at %04X\n", cnt, start);
|
||||
}
|
||||
return (SCPE_OK);
|
||||
}
|
||||
|
||||
/* Symbolic output
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to values
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error code
|
||||
*/
|
||||
|
||||
int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 i, inst, inst1;
|
||||
|
||||
if (sw & SWMASK ('D')) { // dump memory
|
||||
for (i=0; i<16; i++)
|
||||
fprintf(of, "%02X ", val[i]);
|
||||
fprintf(of, " ");
|
||||
for (i=0; i<16; i++)
|
||||
if (isprint(val[i]))
|
||||
fprintf(of, "%c", val[i]);
|
||||
else
|
||||
fprintf(of, ".");
|
||||
return -15;
|
||||
} else if (sw & SWMASK ('M')) { // dump instruction mnemonic
|
||||
inst = val[0];
|
||||
if (!oplen[inst]) { // invalid opcode
|
||||
fprintf(of, "%02X", inst);
|
||||
return 0;
|
||||
}
|
||||
inst1 = inst & 0xF0;
|
||||
fprintf (of, "%s", opcode[inst]); // mnemonic
|
||||
if (strlen(opcode[inst]) == 3)
|
||||
fprintf(of, " ");
|
||||
if (inst1 == 0x20 || inst == 0x8D) { // rel operand
|
||||
inst1 = val[1];
|
||||
if (val[1] & 0x80)
|
||||
inst1 |= 0xFF00;
|
||||
fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK);
|
||||
} else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand
|
||||
if ((inst & 0x0F) < 0x0C)
|
||||
fprintf(of, " #$%02X", val[1]);
|
||||
else
|
||||
fprintf(of, " #$%02X%02X", val[1], val[2]);
|
||||
} else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand
|
||||
fprintf(of, " %d,X", val[1]);
|
||||
else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand
|
||||
fprintf(of, " $%02X%02X", val[1], val[2]);
|
||||
return (-(oplen[inst] - 1));
|
||||
} else
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* address output routine */
|
||||
|
||||
t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr)
|
||||
{
|
||||
fprintf(of, "%04X", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
|
||||
{
|
||||
int32 cflag, i = 0, j, r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0)
|
||||
return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (uint32) cptr[0];
|
||||
return SCPE_OK;
|
||||
}
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
|
||||
if (cptr[0] == 0)
|
||||
return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* An instruction: get opcode (all characters until null, comma,
|
||||
or numeric (including spaces).
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
if (*cptr == ',' || *cptr == '\0' ||
|
||||
isdigit(*cptr))
|
||||
break;
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Allow for RST which has numeric as part of opcode */
|
||||
|
||||
if (toupper(gbuf[0]) == 'R' &&
|
||||
toupper(gbuf[1]) == 'S' &&
|
||||
toupper(gbuf[2]) == 'T') {
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Allow for 'MOV' which is only opcode that has comma in it. */
|
||||
|
||||
if (toupper(gbuf[0]) == 'M' &&
|
||||
toupper(gbuf[1]) == 'O' &&
|
||||
toupper(gbuf[2]) == 'V') {
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* kill trailing spaces if any */
|
||||
gbuf[i] = '\0';
|
||||
for (j = i - 1; gbuf[j] == ' '; j--) {
|
||||
gbuf[j] = '\0';
|
||||
}
|
||||
|
||||
/* find opcode in table */
|
||||
for (j = 0; j < 256; j++) {
|
||||
if (strcmp(gbuf, opcode[j]) == 0)
|
||||
break;
|
||||
}
|
||||
if (j > 255) /* not found */
|
||||
return SCPE_ARG;
|
||||
|
||||
val[0] = j; /* store opcode */
|
||||
if (oplen[j] < 2) /* if 1-byter we are done */
|
||||
return SCPE_OK;
|
||||
if (*cptr == ',') cptr++;
|
||||
cptr = get_glyph(cptr, gbuf, 0); /* get address */
|
||||
sscanf(gbuf, "%o", &r);
|
||||
if (oplen[j] == 2) {
|
||||
val[1] = r & 0xFF;
|
||||
return (-1);
|
||||
}
|
||||
val[1] = r & 0xFF;
|
||||
val[2] = (r >> 8) & 0xFF;
|
||||
return (-2);
|
||||
}
|
||||
|
||||
/* initialize optional interfaces */
|
||||
|
||||
void sim_special_init (void)
|
||||
{
|
||||
// *sim_vm_fprint_addr = &fprint_addr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user