mirror of
https://github.com/simh/simh.git
synced 2026-03-30 11:04:59 +00:00
Separated Pcap-VMS from the rest of the simh source tree.
This is being done since the plan going forward (in the primary descrip.mms and the Visual Studio Projects) is to local pcap components (VMS and Windows) one level up from the simh directory. The PCAP-VMS components are presumed (by this procedure) to be located in a directory at the same level as the directory containing the simh source files. For example, if these exist here: []descrip.mms []scp.c etc. Then the following should exist: [-.PCAP-VMS]BUILD_ALL.COM [-.PCAP-VMS.PCAP-VCI] [-.PCAP-VMS.PCAPVCM] etc.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,3 +30,4 @@ _ReSharper*/
|
||||
*.o
|
||||
BIN/
|
||||
ipch/
|
||||
*.map
|
||||
|
||||
166
0readme_30.txt
166
0readme_30.txt
@@ -1,166 +0,0 @@
|
||||
Notes For V3.0-2
|
||||
|
||||
RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially
|
||||
debugged. Do NOT enable these features for normal operations.
|
||||
|
||||
1. New Features in 3.0-2
|
||||
|
||||
1.1 PDP-1
|
||||
|
||||
- The LOAD command takes an optional argument specifying the memory field
|
||||
to be loaded.
|
||||
- The PTR BOOT command takes its starting memory field from the TA (address
|
||||
switch) register.
|
||||
|
||||
2. Bugs Fixed in 3.0-2
|
||||
|
||||
2.1 SCP and libraries
|
||||
|
||||
- Fixed end of file problem in dep, idep.
|
||||
- Fixed handling of trailing spaces in dep, idep.
|
||||
|
||||
2.2 PDP-1
|
||||
|
||||
- Fixed system hang if continue after PTR error.
|
||||
- Fixed PTR to start/stop on successive rpa instructions.
|
||||
|
||||
2.3 PDP 18b family
|
||||
|
||||
- Fixed priorities in PDP-15 API (differs from PDP-9).
|
||||
- Fixed sign handling in PDP-15 EAE unsigned mul/div (differs from PDP-9).
|
||||
- Fixed bug in CAF, clears API subsystem.
|
||||
|
||||
2.4 1401
|
||||
|
||||
- Fixed tape read end-of-record handling based on real 1401.
|
||||
- Added diagnostic read (space forward).
|
||||
|
||||
2.5 1620
|
||||
|
||||
- Fixed bug in immediate index add (found by Michael Short).
|
||||
|
||||
3. New Features in 3.0 vs prior releases
|
||||
|
||||
3.1 SCP and Libraries
|
||||
|
||||
- Added ASSIGN/DEASSIGN (logical name) commands.
|
||||
- Changed RESTORE to unconditionally detach files.
|
||||
- Added E11 and TPC format support to magtape library.
|
||||
- Fixed bug in SHOW CONNECTIONS.
|
||||
- Added USE_ADDR64 support
|
||||
|
||||
3.2 All magtapes
|
||||
|
||||
- Magtapes support SIMH format, E11 format, and TPC format (read only).
|
||||
- SET <tape_unit> FORMAT=format sets the specified tape unit's format.
|
||||
- SHOW <tape_unit> FORMAT displays the specified tape unit's format.
|
||||
- Tape format can also be set as part of the ATTACH command, using
|
||||
the -F switch.
|
||||
|
||||
3.3 VAX
|
||||
|
||||
- VAX can be compiled without USE_INT64.
|
||||
- If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support
|
||||
files > 2GB.
|
||||
- VAX ROM has speed control (SET ROM DELAY/NODELAY).
|
||||
|
||||
3.4 PDP-1
|
||||
|
||||
- Added block loader format support to LOAD.
|
||||
- Changed BOOT PTR to allow loading of all of the first bank of memory.
|
||||
|
||||
3.5 PDP-18b Family
|
||||
|
||||
- Added PDP-4 EAE support.
|
||||
- Added PDP-15 FP15 support.
|
||||
- Added PDP-15 XVM support.
|
||||
- Added PDP-15 "re-entrancy ECO".
|
||||
- Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR.
|
||||
|
||||
4. Bugs Fixed in 3.0 vs prior releases
|
||||
|
||||
4.1 VAX
|
||||
|
||||
- Fixed CVTfi bug: integer overflow not set if exponent out of range
|
||||
- Fixed EMODx bugs:
|
||||
o First and second operands reversed
|
||||
o Separated fraction received wrong exponent
|
||||
o Overflow calculation on separated integer incorrect
|
||||
o Fraction not set to zero if exponent out of range
|
||||
- Fixed interval timer and ROM access to pass power-up self-test even on very
|
||||
fast host processors (fixes from Mark Pizzolato).
|
||||
- Fixed bug in user disk size (found by Chaskiel M Grundman).
|
||||
|
||||
4.2 1401
|
||||
|
||||
- Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS.
|
||||
- Fixed MCE bug, BS off by 1 if zero suppress.
|
||||
- Fixed chaining bug, D lost if return to SCP.
|
||||
- Fixed H branch, branch occurs after continue.
|
||||
- Added check for invalid 8 character MCW, LCA.
|
||||
- Fixed magtape load-mode end of record response.
|
||||
- Revised fetch to model hardware more closely.
|
||||
|
||||
4.3 Nova
|
||||
|
||||
- Fixed DSK variable size interaction with restore.
|
||||
- Fixed bug in DSK set size routine.
|
||||
|
||||
4.4 PDP-1
|
||||
|
||||
- Fixed DT variable size interaction with restore.
|
||||
- Updated CPU, line printer, standard devices to detect indefinite I/O wait.
|
||||
- Fixed incorrect logical, missing activate, break in drum simulator.
|
||||
- Fixed bugs in instruction decoding, overprinting for line printer.
|
||||
|
||||
4.5 PDP-11
|
||||
|
||||
- Fixed DT variable size interaction with restore.
|
||||
- Fixed bug in MMR1 update (found by Tim Stark).
|
||||
- Added XQ features and fixed bugs:
|
||||
o Corrected XQ interrupts on IE state transition (code by Tom Evans).
|
||||
o Added XQ interrupt clear on soft reset.
|
||||
o Removed XQ interrupt when setting XL or RL (multiple people).
|
||||
o Added SET/SHOW XQ STATS.
|
||||
o Added SHOW XQ FILTERS.
|
||||
o Added ability to split received packet into multiple buffers.
|
||||
o Added explicit runt and giant packet processing.
|
||||
- Fixed bug in user disk size (found by Chaskiel M Grundman).
|
||||
|
||||
4.6 PDP-18B
|
||||
|
||||
- Fixed DT, RF variable size interaction with restore.
|
||||
- Fixed MT bug in MTTR.
|
||||
- Fixed bug in PDP-4 line printer overprinting.
|
||||
- Fixed bug in PDP-15 memory protect/skip interaction.
|
||||
- Fixed bug in RF set size routine.
|
||||
- Increased PTP TIME for PDP-15 operating systems.
|
||||
|
||||
4.7 PDP-8
|
||||
|
||||
- Fixed DT, DF, RF, RX variable size interaction with restore.
|
||||
- Fixed MT bug in SKTR.
|
||||
- Fixed bug in DF, RF set size routine.
|
||||
|
||||
4.8 HP2100
|
||||
|
||||
- Fixed bug in DP (13210A controller only), DQ read status.
|
||||
- Fixed bug in DP, DQ seek complete.
|
||||
- Fixed DR drum sizes.
|
||||
- Fixed DR variable capacity interaction with SAVE/RESTORE.
|
||||
|
||||
4.9 GRI
|
||||
|
||||
- Fixed bug in SC queue pointer management.
|
||||
|
||||
4.10 PDP-10
|
||||
|
||||
- Fixed bug in RP read header.
|
||||
|
||||
4.11 Ibm1130
|
||||
|
||||
- Fixed bugs found by APL 1130.
|
||||
|
||||
4.12 Altairz80
|
||||
|
||||
- Fixed bug in real-time clock on Windows host.
|
||||
@@ -1,162 +0,0 @@
|
||||
This file contains information about the XQ/SIM_ETHER package.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The XQ emulator is a host-independant software emulation of Digital's
|
||||
DELQA (M7516) and DEQNA (M7504) Q-bus ethernet cards for the SIMH emulator.
|
||||
|
||||
The XQ emulator uses the Sim_Ether module to execute host-specific ethernet
|
||||
packet reads and writes, since all operating systems talk to real ethernet
|
||||
cards/controllers differently. The host-dependant Sim_Ether module currently
|
||||
supports Windows, Linux, NetBSD, and OpenBSD.
|
||||
|
||||
Currently, the Sim_Ether module sets the selected ethernet card into
|
||||
promiscuous mode to gather all packets, then filters out the packets that it
|
||||
doesn't want. In Windows, packets having the same source MAC address as the
|
||||
controller are ignored for WinPCAP compatibility (see Windows notes below).
|
||||
|
||||
If your ethernet card is plugged into a switch, the promiscuous mode setting
|
||||
should not cause much of a problem, since the switch will still filter out
|
||||
most of the undesirable traffic. You will only see "excessive" traffic if you
|
||||
are on a direct or hub(repeater) segment.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Windows notes:
|
||||
1. The Windows-specific code uses the WinPCAP 3.0 package from
|
||||
http://winpcap.polito.it. This package for windows simulates the libpcap
|
||||
package that is freely available for unix systems.
|
||||
2. You must *install* the WinPCAP runtime package.
|
||||
3. The first time the WinPCAP driver is used, it will be dynamically loaded,
|
||||
and the user must be an Administrator on the machine to do so. If you need
|
||||
to run as an unprivileged user, you must set the service to autostart. See
|
||||
the WinPCAP documentation for details on the static load workaround.
|
||||
4. WinPCAP loops packet writes back into the read queue. This causes problems
|
||||
since the XQ controller is not expecting to read it's own packet. A fix
|
||||
to the packet read filter was added to reject packets from the current MAC,
|
||||
but this defeats DECNET's duplicate node number detection scheme. A more
|
||||
correct fix for WinPCAP will be explored as time allows.
|
||||
|
||||
Building on Windows:
|
||||
1. Install WinPCAP 3.0.
|
||||
2. Put the required .h files (bittypes,devioctl,ip6_misc,packet32,pcap,
|
||||
pcap-stdinc).h from the WinPCAP 3.0 developer's kit in the compiler's path
|
||||
3. Put the required .lib files (packet,wpcap).lib from the WinPCAP 3.0
|
||||
developer's kit in the linker's path
|
||||
4. If you're using Borland C++, use COFF2OMF to convert the .lib files into
|
||||
a format that can be used by the compiler.
|
||||
5. Define USE_NETWORK if you want the network functionality.
|
||||
6. Build it!
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Linux, NetBSD, and OpenBSD notes:
|
||||
1. You must run SIMH(scp) as root so that the ethernet card can be set into
|
||||
promiscuous mode by the driver. Alternative methods for avoiding the
|
||||
'run as root' requirement will be welcomed.
|
||||
|
||||
Building on Linux, NetBSD, and OpenBSD:
|
||||
1. Get/install the libpcap package for your unix version. http://rpmfind.net
|
||||
might be a useful site for finding the linux variants.
|
||||
2. Use Make USE_NETWORK=1 if you want the network functionality.
|
||||
3. Build it!
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
VAX simulator support:
|
||||
|
||||
An OpenVMS VAX v7.2 system with DECNET Phase IV, MultiNet 4.4a, and LAT 5.3 has
|
||||
been successfully run. Other testers have reported success booting NetBSD also.
|
||||
|
||||
|
||||
PDP11 simulator support:
|
||||
|
||||
An RT-11 v5.3 system with a freeware TCP/IP stack has been successfully run.
|
||||
Other testers have reported that RSX with DECNET and the NetBSD operating
|
||||
systems also work. RSTS/E v10.1 has preliminary support - RSTS/E boots and
|
||||
enables the XH (XQ) device - DECNET and LAT software have not been tested.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Things planned for future releases:
|
||||
1. PDP-11 bootstrap/bootrom
|
||||
2. Full MOP implementation
|
||||
3. DESQA support (if someone can get me the user manuals)
|
||||
4. DETQA support [DELQA-Turbo] (I have the manual)
|
||||
5. DEUNA/DELUA support
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Things which I need help with:
|
||||
1. Porting Sim_Ether packet driver to other host platforms, especially VMS.
|
||||
2. Information about Remote MOP processing
|
||||
3. VAX/PDP-11 hardware diagnotics image files and docs, to test XQ thoroughly.
|
||||
4. Feedback on operation with other VAX/PDP-11 OS's.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Please send all patches, questions, feedback, clarifications, and help to:
|
||||
dhittner AT northropgrumman DOT com
|
||||
|
||||
Thanks, and Enjoy!!
|
||||
Dave
|
||||
|
||||
|
||||
===============================================================================
|
||||
Change Log
|
||||
===============================================================================
|
||||
|
||||
05-Jun-03 Release:
|
||||
1. Added SET/SHOW XQ STATS
|
||||
2. Added SHOW XQ FILTERS
|
||||
3. Added ability to split received packet into multiple buffers
|
||||
4. Added explicit runt & giant packet processing
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
30-May-03 Release:
|
||||
1. Corrected bug in xq_setmac introduced in v3.0 (multiple people)
|
||||
2. Made XQ receive buffer allocation dynamic to reduce scp executable size
|
||||
3. Optimized some structs, removed legacy variables (Mark Pizzolato)
|
||||
4. Changed #ifdef WIN32 to _WIN32 for consistancy
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
06-May-03 Release:
|
||||
1. Added second XQ controller
|
||||
2. Added SIMH v3.0 compatibility
|
||||
3. Removed SET ADDRESS functionality
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
10-Apr-03 Release:
|
||||
1. Added preliminary support for RSTS/E
|
||||
2. Added PDP-11 bootrom load via CSR flags
|
||||
3. Support for SPARC linux (thanks to Mark Pizzolato)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
11-Mar-03 Release:
|
||||
1. Added support for RT-11 TCP/IP
|
||||
2. Corrected interrupts (thanks to Tom Evans and Bob Supnik)
|
||||
3. Moved change log to the bottom of the readme file, cleaned up document
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
16-Jan-03 Release:
|
||||
1. Added VMScluster support (thanks to Mark Pizzolato)
|
||||
2. Verified VAX remote boot functionality (>>>B XQA0)
|
||||
3. Added major performance enhancements (thanks to Mark Pizzolato again)
|
||||
4. Changed _DEBUG tracers to XQ_DEBUG and ETH_DEBUG
|
||||
5. Added local packet processing
|
||||
6. Added system id broadcast
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
08-Nov-02 Release:
|
||||
1. Added USE_NETWORK conditional to Sim_Ether
|
||||
2. Fixed behaviour of SHOW XQ ETH if no devices exist
|
||||
3. Added OpenBSD support to Sim_Ether (courtesy of Federico Schwindt)
|
||||
4. Added ethX detection simplification (from Megan Gentry)
|
||||
|
||||
===============================================================================
|
||||
@@ -1,211 +0,0 @@
|
||||
Altair 8800 Simulator
|
||||
=====================
|
||||
|
||||
1. Background.
|
||||
|
||||
The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800
|
||||
was announced on the January 1975 cover of Popular Electronics, which
|
||||
boasted you could buy and build this powerful computer kit for only $397.
|
||||
The kit consisted at that time of only the parts to build a case, power
|
||||
supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of
|
||||
memory. Still, thousands were ordered within the first few months after the
|
||||
announcement, starting the personal computer revolution as we know it today.
|
||||
|
||||
Many laugh at the small size of the that first kit, noting there
|
||||
were no peripherals and the 256 byte memory size. But the computer was an
|
||||
open system, and by 1977 MITS and many other small startups had added many
|
||||
expansion cards to make the Altair quite a respectable little computer. The
|
||||
"Altair Bus" that made this possible was soon called the S-100 Bus, later
|
||||
adopted as an industry standard, and eventually became the IEE-696 Bus.
|
||||
|
||||
2. Hardware
|
||||
|
||||
We are simulating a fairly "loaded" Altair 8800 from about 1977,
|
||||
with the following configuration:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU Altair 8800 with Intel 8080 CPU board, 62KB
|
||||
of RAM, 2K of EPROM with start boot ROM.
|
||||
2SIO MITS 88-2SIO Dual Serial Interface Board. Port 1
|
||||
is assumed to be connected to a serial "glass
|
||||
TTY" that is your terminal running the Simulator.
|
||||
PTR Paper Tape Reader attached to port 2 of the
|
||||
2SIO board.
|
||||
PTP Paper Tape Punch attached to port 2 of the
|
||||
2SIO board. This also doubles as a printer
|
||||
port.
|
||||
DSK MITS 88-DISK Floppy Disk controller with up
|
||||
to eight drives.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
We have 2 CPU options that were not present on the original
|
||||
machine but are useful in the simulator. We also allow you to select
|
||||
memory sizes, but be aware that some sample software requires the full
|
||||
64K (i.e. CP/M) and the MITS Disk Basic and Altair DOS require about
|
||||
a minimum of 24K.
|
||||
|
||||
SET CPU 8080 Simulates the 8080 CPU (normal)
|
||||
SET CPU Z80 Simulates the later Z80 CPU [At the present time
|
||||
this is not fully implemented and is not to be
|
||||
trusted with real Z80 software]
|
||||
SET CPU ITRAP Causes the simulator to halt if an invalid 8080
|
||||
Opcode is detected.
|
||||
SET CPU NOITRAP Does not stop on an invalid Opcode. This is
|
||||
how the real 8080 works.
|
||||
SET CPU 4K
|
||||
SET CPU 8K
|
||||
SET CPU 12K
|
||||
SET CPU 16K
|
||||
......
|
||||
SET CPU 64K All these set various CPU memory configurations.
|
||||
The 2K EPROM at the high end of memory is always
|
||||
present and will always boot.
|
||||
|
||||
The BOOT EPROM card starts at address 177400. Jumping to this address
|
||||
will always boot drive 0 of the floppy controller. If no valid bootable
|
||||
software is present there the machine crashes. This is historically
|
||||
accurate behavior.
|
||||
|
||||
The real 8080, on receiving a HLT (Halt) instruction, freezes the processor
|
||||
and only an interrupt or CPU hardware reset will restore it. The simulator
|
||||
is alot nicer, it will halt but send you back to the simulator command line.
|
||||
|
||||
CPU Registers include the following:
|
||||
|
||||
name size comments
|
||||
|
||||
PC 16 The Program Counter
|
||||
A 8 The accumulator
|
||||
BC 16 The BC register pair. Register B is the high
|
||||
8 bits, C is the lower 8 bits
|
||||
DE 16 The DE register pair. D is the top 8 bits, E is
|
||||
the bottom.
|
||||
HL 16 The HL register pair. H is top, L is bottom.
|
||||
C 1 Carry flag.
|
||||
Z 1 Zero Flag.
|
||||
AC 1 Auxillary Carry flag.
|
||||
P 1 Parity flag.
|
||||
S 1 Sign flag.
|
||||
SR 16 The front panel switches.
|
||||
BREAK 16 Breakpoint address (377777 to disable).
|
||||
WRU 8 The interrupt character. This starts as 005
|
||||
(ctrl-E) but some Altair software uses this
|
||||
keystroke so best to change this to something
|
||||
exotic such as 035 (which is Ctl-]).
|
||||
|
||||
|
||||
2.2 The Serial I/O Card (2SIO)
|
||||
|
||||
This simple programmed I/O device provides 2 serial ports to the
|
||||
outside world, which could be hardware jumpered to support RS-232 plugs or a
|
||||
TTY current loop interface. The standard I/O addresses assigned by MITS
|
||||
was 20-21 (octal) for the first port, and 22-23 (octal) for the second.
|
||||
We follow this standard in the Simulator.
|
||||
|
||||
The simulator directs I/O to/from the first port to the screen. The
|
||||
second port reads from an attachable "tape reader" file on input, and writes
|
||||
to an attachable "punch file" on output. These files are considered a
|
||||
simple stream of 8-bit bytes.
|
||||
|
||||
2.3 The 88-DISK controller.
|
||||
|
||||
The MITS 88-DISK is a simple programmed I/O interface to the MITS
|
||||
8-inch floppy drive, which was basically a Pertec FD-400 with a power
|
||||
supply and buffer board builtin. The controller supports neither interrupts
|
||||
nor DMA, so floppy access required the sustained attention of the CPU.
|
||||
The standard I/O addresses were 10, 11, and 12 (octal), and we follow the
|
||||
standard. Details on controlling this hardware are in the altair_dsk.c
|
||||
source file.
|
||||
|
||||
|
||||
3. Sample Software
|
||||
|
||||
Running an Altair in 1977 you would be running either MITS Disk
|
||||
Extended BASIC, or the brand new and sexy CP/M Operating System from Digital
|
||||
Research. Or possibly, you ordered Altair DOS back when it was promised in
|
||||
1975, and are still waiting for it to be delivered in early 1977.
|
||||
|
||||
We have samples of all three for you to check out. We can't go into
|
||||
the details of how they work, but we'll give you a few hints.
|
||||
|
||||
|
||||
3.1 CP/M Version 2.2
|
||||
|
||||
This version is my own port of the standard CP/M to the Altair.
|
||||
There were some "official" versions but I don't have them. None were
|
||||
endorsed or sold by MITS to my knowledge, however.
|
||||
To boot CP/M:
|
||||
|
||||
sim> attach dsk0 altcpm.dsk
|
||||
sim> go 177400
|
||||
62K CP/M VERSION 2.2 (ALTAIR 8800)
|
||||
A>DIR
|
||||
|
||||
CP/M feels like DOS, sort of. DIR will work. I have included all
|
||||
the standard CP/M utilities, plus a few common public-domain ones. I also
|
||||
include the sources to the customized BIOS and some other small programs.
|
||||
TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better
|
||||
DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to
|
||||
binary format (.COM). ED is a simple editor, #A command will bring the
|
||||
source file to the buffer, T command will "type" lines, L will move lines,
|
||||
E exits the editor. 20L20T will move down 20 lines, and type 20. Very
|
||||
DECish. DDT is the debugger, SUBMIT is a batch-type command processor.
|
||||
A sample batch file that will assemble and write out the bootable CP/M
|
||||
image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN".
|
||||
|
||||
|
||||
3.2 MITS Disk Extended BASIC Version 4.1
|
||||
|
||||
This was the commonly used software for serious users of the Altair
|
||||
computer. It is a powerful (but slow) BASIC with some extended commands to
|
||||
allow it to access and manage the disk. There was no operating system it
|
||||
ran under. To boot:
|
||||
|
||||
sim> attach dsk0 mbasic.dsk
|
||||
sim> go 177400
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
LINEPRINTER? C [return]
|
||||
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
|
||||
NUMBER OF FILES? 3 [return]
|
||||
NUMBER OF RANDOM FILES? 2 [return]
|
||||
|
||||
44297 BYTES FREE
|
||||
ALTAIR BASIC REV. 4.1
|
||||
[DISK EXTENDED VERSION]
|
||||
COPYRIGHT 1977 BY MITS INC.
|
||||
OK
|
||||
mount 0
|
||||
OK
|
||||
files
|
||||
|
||||
|
||||
3.3 Altair DOS Version 1.0
|
||||
|
||||
This was long promised but not delivered until it was almost
|
||||
irrelevant. A short attempted tour will reveal it to be a dog, far inferior
|
||||
to CP/M. To boot:
|
||||
|
||||
sim> attach dsk0 altdos.dsk
|
||||
sim> go 177400
|
||||
|
||||
MEMORY SIZE? 64 [return]
|
||||
INTERRUPTS? N [return]
|
||||
HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system)
|
||||
HOW MANY DISK FILES? 3 [return]
|
||||
HOW MANY RANDOM FILES? 2 [return]
|
||||
|
||||
056769 BYTES AVAILABLE
|
||||
DOS MONITOR VER 1.0
|
||||
COPYRIGHT 1977 BY MITS INC
|
||||
.mnt 0
|
||||
|
||||
.dir 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1189
ALTAIR/altair_cpu.c
1189
ALTAIR/altair_cpu.c
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
/* altair_defs.h: MITS Altair simulator definitions
|
||||
|
||||
Copyright (c) 1997-2003, Charles E. Owen
|
||||
|
||||
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 Charles E. Owen shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Charles E. Owen.
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 65536 /* max memory size */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
|
||||
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_RSRV 1 /* must be 1 */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_OPCODE 4
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
/* altair_dsk.c: MITS Altair 88-DISK Simulator
|
||||
|
||||
Copyright (c) 1997-2003, Charles E. Owen
|
||||
|
||||
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 Charles E. Owen shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Charles E. Owen.
|
||||
|
||||
The 88_DISK is a 8-inch floppy controller which can control up
|
||||
to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives.
|
||||
Each diskette has physically 77 tracks of 32 137-byte sectors
|
||||
each.
|
||||
|
||||
The controller is interfaced to the CPU by use of 3 I/O addreses,
|
||||
standardly, these are device numbers 10, 11, and 12 (octal).
|
||||
|
||||
Address Mode Function
|
||||
------- ---- --------
|
||||
|
||||
10 Out Selects and enables Controller and Drive
|
||||
10 In Indicates status of Drive and Controller
|
||||
11 Out Controls Disk Function
|
||||
11 In Indicates current sector position of disk
|
||||
12 Out Write data
|
||||
12 In Read data
|
||||
|
||||
Drive Select Out (Device 10 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| C | X | X | X | Device |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
C = If this bit is 1, the disk controller selected by 'device' is
|
||||
cleared. If the bit is zero, 'device' is selected as the
|
||||
device being controlled by subsequent I/O operations.
|
||||
X = not used
|
||||
Device = value zero thru 15, selects drive to be controlled.
|
||||
|
||||
Drive Status In (Device 10 IN):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| R | Z | I | X | X | H | M | W |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
W - When 0, write circuit ready to write another byte.
|
||||
M - When 0, head movement is allowed
|
||||
H - When 0, indicates head is loaded for read/write
|
||||
X - not used (will be 0)
|
||||
I - When 0, indicates interrupts enabled (not used this simulator)
|
||||
Z - When 0, indicates head is on track 0
|
||||
R - When 0, indicates that read circuit has new byte to read
|
||||
|
||||
Drive Control (Device 11 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| W | C | D | E | U | H | O | I |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
I - When 1, steps head IN one track
|
||||
O - When 1, steps head OUT out track
|
||||
H - When 1, loads head to drive surface
|
||||
U - When 1, unloads head
|
||||
E - Enables interrupts (ignored this simulator)
|
||||
D - Disables interrupts (ignored this simulator)
|
||||
C - When 1 lowers head current (ignored this simulator)
|
||||
W - When 1, starts Write Enable sequence: W bit on device 10
|
||||
(see above) will go 1 and data will be read from port 12
|
||||
until 137 bytes have been read by the controller from
|
||||
that port. The W bit will go off then, and the sector data
|
||||
will be written to disk. Before you do this, you must have
|
||||
stepped the track to the desired number, and waited until
|
||||
the right sector number is presented on device 11 IN, then
|
||||
set this bit.
|
||||
|
||||
Sector Position (Device 11 IN):
|
||||
|
||||
As the sectors pass by the read head, they are counted and the
|
||||
number of the current one is available in this register.
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X | X | Sector Number | T |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
X = Not used
|
||||
Sector number = binary of the sector number currently under the
|
||||
head, 0-31.
|
||||
T = Sector True, is a 1 when the sector is positioned to read or
|
||||
write.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "altair_defs.h"
|
||||
|
||||
#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */
|
||||
#define UNIT_ENABLE (1 << UNIT_V_ENABLE)
|
||||
|
||||
#define DSK_SECTSIZE 137
|
||||
#define DSK_SECT 32
|
||||
#define DSK_TRACSIZE 4384
|
||||
#define DSK_SURF 1
|
||||
#define DSK_CYL 77
|
||||
#define DSK_SIZE (DSK_SECT * DSK_SURF * DSK_CYL * DSK_SECTSIZE)
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr);
|
||||
t_stat dsk_reset (DEVICE *dptr);
|
||||
void writebuf();
|
||||
|
||||
extern int32 PCX;
|
||||
|
||||
/* Global data on status */
|
||||
|
||||
int32 cur_disk = 8; /* Currently selected drive */
|
||||
int32 cur_track[9] = {0, 0, 0, 0, 0, 0, 0, 0, 377};
|
||||
int32 cur_sect[9] = {0, 0, 0, 0, 0, 0, 0, 0, 377};
|
||||
int32 cur_byte[9] = {0, 0, 0, 0, 0, 0, 0, 0, 377};
|
||||
int32 cur_flags[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
char dskbuf[137]; /* Data Buffer */
|
||||
int32 dirty = 0; /* 1 when buffer has unwritten data in it */
|
||||
UNIT *dptr; /* fileref to write dirty buffer to */
|
||||
|
||||
int32 dsk_rwait = 100; /* rotate latency */
|
||||
|
||||
|
||||
/* 88DSK Standard I/O Data Structures */
|
||||
|
||||
UNIT dsk_unit[] = {
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }
|
||||
};
|
||||
|
||||
REG dsk_reg[] = {
|
||||
{ ORDATA (DISK, cur_disk, 4) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE dsk_dev = {
|
||||
"DSK", dsk_unit, dsk_reg, NULL,
|
||||
8, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &dsk_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Service routines to handle simlulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dsk_reset (DEVICE *dptr)
|
||||
{
|
||||
cur_disk = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
IN or OUT instruction is issued.
|
||||
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
*/
|
||||
|
||||
/* Disk Controller Status/Select */
|
||||
|
||||
/* IMPORTANT: The status flags read by port 8 IN instruction are
|
||||
INVERTED, that is, 0 is true and 1 is false. To handle this, the
|
||||
simulator keeps it's own status flags as 0=false, 1=true; and
|
||||
returns the COMPLEMENT of the status flags when read. This makes
|
||||
setting/testing of the flag bits more logical, yet meets the
|
||||
simulation requirement that they are reversed in hardware.
|
||||
*/
|
||||
|
||||
int32 dsk10(int32 io, int32 data)
|
||||
{
|
||||
|
||||
if (io == 0) { /* IN: return flags */
|
||||
return ((~cur_flags[cur_disk]) & 0xFF); /* Return the COMPLEMENT! */
|
||||
}
|
||||
|
||||
/* OUT: Controller set/reset/enable/disable */
|
||||
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
|
||||
/*printf("\n[%o] OUT 10: %x", PCX, data);*/
|
||||
cur_disk = data & 0x0F;
|
||||
if (data & 0x80) {
|
||||
cur_flags[cur_disk] = 0; /* Disable drive */
|
||||
cur_sect[cur_disk = 0377];
|
||||
cur_byte[cur_disk = 0377];
|
||||
return (0);
|
||||
}
|
||||
cur_flags[cur_disk] = 0x1A; /* Enable: head move true */
|
||||
cur_sect[cur_disk] = 0377; /* reset internal counters */
|
||||
cur_byte[cur_disk] = 0377;
|
||||
if (cur_track[cur_disk] == 0)
|
||||
cur_flags[cur_disk] |= 0x40; /* track 0 if there */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Disk Drive Status/Functions */
|
||||
|
||||
int32 dsk11(int32 io, int32 data)
|
||||
{
|
||||
int32 stat;
|
||||
|
||||
if (io == 0) { /* Read sector position */
|
||||
/*printf("\n[%o] IN 11", PCX);*/
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
if (cur_flags[cur_disk] & 0x04) { /* head loaded? */
|
||||
cur_sect[cur_disk]++;
|
||||
if (cur_sect[cur_disk] > 31)
|
||||
cur_sect[cur_disk] = 0;
|
||||
cur_byte[cur_disk] = 0377;
|
||||
stat = cur_sect[cur_disk] << 1;
|
||||
stat &= 0x3E; /* return 'sector true' bit = 0 (true) */
|
||||
stat |= 0xC0; /* set on 'unused' bits */
|
||||
return (stat);
|
||||
} else {
|
||||
return (0); /* head not loaded - return 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/* Drive functions */
|
||||
|
||||
if (cur_disk > 7)
|
||||
return (0); /* no drive selected - can do nothin */
|
||||
|
||||
/*printf("\n[%o] OUT 11: %x", PCX, data);*/
|
||||
if (data & 0x01) { /* Step head in */
|
||||
cur_track[cur_disk]++;
|
||||
if (cur_track[cur_disk] > 76 )
|
||||
cur_track[cur_disk] = 76;
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
cur_sect[cur_disk] = 0377;
|
||||
cur_byte[cur_disk] = 0377;
|
||||
}
|
||||
|
||||
if (data & 0x02) { /* Step head out */
|
||||
cur_track[cur_disk]--;
|
||||
if (cur_track[cur_disk] < 0) {
|
||||
cur_track[cur_disk] = 0;
|
||||
cur_flags[cur_disk] |= 0x40; /* track 0 if there */
|
||||
}
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
cur_sect[cur_disk] = 0377;
|
||||
cur_byte[cur_disk] = 0377;
|
||||
}
|
||||
|
||||
if (dirty == 1)
|
||||
writebuf();
|
||||
|
||||
if (data & 0x04) { /* Head load */
|
||||
cur_flags[cur_disk] |= 0x04; /* turn on head loaded bit */
|
||||
cur_flags[cur_disk] |= 0x80; /* turn on 'read data available */
|
||||
}
|
||||
|
||||
if (data & 0x08) { /* Head Unload */
|
||||
cur_flags[cur_disk] &= 0xFB; /* off on 'head loaded' */
|
||||
cur_flags[cur_disk] &= 0x7F; /* off on 'read data avail */
|
||||
cur_sect[cur_disk] = 0377;
|
||||
cur_byte[cur_disk] = 0377;
|
||||
}
|
||||
|
||||
/* Interrupts & head current are ignored */
|
||||
|
||||
if (data & 0x80) { /* write sequence start */
|
||||
cur_byte[cur_disk] = 0;
|
||||
cur_flags[cur_disk] |= 0x01; /* enter new write data on */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disk Data In/Out*/
|
||||
|
||||
int32 dsk12(int32 io, int32 data)
|
||||
{
|
||||
static int32 rtn, i;
|
||||
static long pos;
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = dsk_dev.units + cur_disk;
|
||||
if (io == 0) {
|
||||
if ((i = cur_byte[cur_disk]) < 138) { /* just get from buffer */
|
||||
cur_byte[cur_disk]++;
|
||||
return (dskbuf[i] & 0xFF);
|
||||
}
|
||||
/* physically read the sector */
|
||||
/*printf("\n[%o] IN 12 (READ) T%d S%d", PCX, cur_track[cur_disk],
|
||||
cur_sect[cur_disk]);*/
|
||||
pos = DSK_TRACSIZE * cur_track[cur_disk];
|
||||
pos += DSK_SECTSIZE * cur_sect[cur_disk];
|
||||
rtn = fseek(uptr -> fileref, pos, 0);
|
||||
rtn = fread(dskbuf, 137, 1, uptr -> fileref);
|
||||
cur_byte[cur_disk] = 1;
|
||||
return (dskbuf[0] & 0xFF);
|
||||
} else {
|
||||
if (cur_byte[cur_disk] > 136) {
|
||||
i = cur_byte[cur_disk];
|
||||
dskbuf[i] = data & 0xFF;
|
||||
writebuf();
|
||||
return (0);
|
||||
}
|
||||
i = cur_byte[cur_disk];
|
||||
dirty = 1;
|
||||
dptr = uptr;
|
||||
dskbuf[i] = data & 0xFF;
|
||||
cur_byte[cur_disk]++;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
void writebuf()
|
||||
{
|
||||
long pos;
|
||||
int32 rtn, i;
|
||||
|
||||
i = cur_byte[cur_disk]; /* null-fill rest of sector if any */
|
||||
while (i < 138) {
|
||||
dskbuf[i] = 0;
|
||||
i++;
|
||||
}
|
||||
/*printf("\n[%o] OUT 12 (WRITE) T%d S%d", PCX, cur_track[cur_disk],
|
||||
cur_sect[cur_disk]); i = getch(); */
|
||||
pos = DSK_TRACSIZE * cur_track[cur_disk]; /* calc file pos */
|
||||
pos += DSK_SECTSIZE * cur_sect[cur_disk];
|
||||
rtn = fseek(dptr -> fileref, pos, 0);
|
||||
rtn = fwrite(dskbuf, 137, 1, dptr -> fileref);
|
||||
cur_flags[cur_disk] &= 0xFE; /* ENWD off */
|
||||
cur_byte[cur_disk] = 0377;
|
||||
dirty = 0;
|
||||
return;
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
/* altair_sio: MITS Altair serial I/O card
|
||||
|
||||
Copyright (c) 1997-2003, Charles E. Owen
|
||||
|
||||
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 Charles E. Owen shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Charles E. Owen.
|
||||
|
||||
These functions support a simulated MITS 2SIO interface card.
|
||||
The card had two physical I/O ports which could be connected
|
||||
to any serial I/O device that would connect to a current loop,
|
||||
RS232, or TTY interface. Available baud rates were jumper
|
||||
selectable for each port from 110 to 9600.
|
||||
|
||||
All I/O is via programmed I/O. Each each has a status port
|
||||
and a data port. A write to the status port can select
|
||||
some options for the device (0x03 will reset the port).
|
||||
A read of the status port gets the port status:
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X X X X X X O I |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
I - A 1 in this bit position means a character has been received
|
||||
on the data port and is ready to be read.
|
||||
O - A 1 in this bit means the port is ready to receive a character
|
||||
on the data port and transmit it out over the serial line.
|
||||
|
||||
A read to the data port gets the buffered character, a write
|
||||
to the data port writes the character to the device.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "altair_defs.h"
|
||||
|
||||
#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */
|
||||
#define UNIT_ANSI (1 << UNIT_V_ANSI)
|
||||
|
||||
t_stat sio_svc (UNIT *uptr);
|
||||
t_stat sio_reset (DEVICE *dptr);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
|
||||
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
|
||||
|
||||
/* 2SIO Standard I/O Data Structures */
|
||||
|
||||
UNIT sio_unit = { UDATA (&sio_svc, 0, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG sio_reg[] = {
|
||||
{ ORDATA (DATA, sio_unit.buf, 8) },
|
||||
{ ORDATA (STAT, sio_unit.u3, 8) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB sio_mod[] = {
|
||||
{ UNIT_ANSI, 0, "TTY", "TTY", NULL },
|
||||
{ UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE sio_dev = {
|
||||
"2SIO", &sio_unit, sio_reg, sio_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &sio_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG ptr_reg[] = {
|
||||
{ ORDATA (DATA, ptr_unit.buf, 8) },
|
||||
{ ORDATA (STAT, ptr_unit.u3, 8) },
|
||||
{ ORDATA (POS, ptr_unit.pos, T_ADDR_W) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
|
||||
KBD_POLL_WAIT };
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ ORDATA (DATA, ptp_unit.buf, 8) },
|
||||
{ ORDATA (STAT, ptp_unit.u3, 8) },
|
||||
{ ORDATA (POS, ptp_unit.pos, T_ADDR_W) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Service routines to handle simulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
int32 sio_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&sio_unit, sio_unit.wait); /* continue poll */
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
|
||||
return temp; /* no char or error? */
|
||||
sio_unit.buf = temp & 0377; /* Save char */
|
||||
sio_unit.u3 |= 0x01; /* Set status */
|
||||
|
||||
/* Do any special character handling here */
|
||||
|
||||
sio_unit.pos++;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
int32 ptr_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int32 ptp_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
int32 sio_reset (DEVICE *dptr)
|
||||
{
|
||||
sio_unit.buf = 0; /* Data */
|
||||
sio_unit.u3 = 0x02; /* Status */
|
||||
sim_activate (&sio_unit, sio_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
int32 ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
ptr_unit.buf = 0;
|
||||
ptr_unit.u3 = 0x02;
|
||||
sim_cancel (&ptr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int32 ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
ptp_unit.buf = 0;
|
||||
ptp_unit.u3 = 0x02;
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
IN or OUT instruction is issued.
|
||||
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
*/
|
||||
|
||||
int32 sio0s(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) {
|
||||
return (sio_unit.u3);
|
||||
} else {
|
||||
if (data == 0x03) { /* reset port! */
|
||||
sio_unit.u3 = 0x02;
|
||||
sio_unit.buf = 0;
|
||||
sio_unit.pos = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
int32 sio0d(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) {
|
||||
sio_unit.u3 = sio_unit.u3 & 0xFE;
|
||||
return (sio_unit.buf);
|
||||
} else {
|
||||
sim_putchar(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Port 2 controls the PTR/PTP devices */
|
||||
|
||||
int32 sio1s(int32 io, int32 data)
|
||||
{
|
||||
if (io == 0) {
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return 0x02;
|
||||
if (ptr_unit.u3 != 0) /* No more data? */
|
||||
return 0x02;
|
||||
return (0x03); /* ready to read/write */
|
||||
} else {
|
||||
if (data == 0x03) {
|
||||
ptr_unit.u3 = 0;
|
||||
ptr_unit.buf = 0;
|
||||
ptr_unit.pos = 0;
|
||||
ptp_unit.u3 = 0;
|
||||
ptp_unit.buf = 0;
|
||||
ptp_unit.pos = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
int32 sio1d(int32 io, int32 data)
|
||||
{
|
||||
int32 temp;
|
||||
UNIT *uptr;
|
||||
|
||||
if (io == 0) {
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return 0;
|
||||
if (ptr_unit.u3 != 0)
|
||||
return 0;
|
||||
uptr = ptr_dev.units;
|
||||
if ((temp = getc(uptr -> fileref)) == EOF) { /* end of file? */
|
||||
ptr_unit.u3 = 0x01;
|
||||
return 0;
|
||||
}
|
||||
ptr_unit.pos++;
|
||||
return (temp & 0xFF);
|
||||
} else {
|
||||
uptr = ptp_dev.units;
|
||||
putc(data, uptr -> fileref);
|
||||
ptp_unit.pos++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
/* altair_sys.c: MITS Altair system interface
|
||||
|
||||
Copyright (c) 1997-2003, Charles E. Owen
|
||||
|
||||
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 Charles E. Owen shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Charles E. Owen.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "altair_defs.h"
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE dsk_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern DEVICE sio_dev;
|
||||
extern DEVICE ptr_dev;
|
||||
extern DEVICE ptp_dev;
|
||||
extern DEVICE lpt_dev;
|
||||
extern unsigned char M[];
|
||||
extern int32 saved_PC;
|
||||
|
||||
/* SCP data structures
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words needed for examine
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "Altair 8800";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 4;
|
||||
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev,
|
||||
&ptp_dev, &dsk_dev, NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unknown I/O Instruction",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Invalid Opcode" };
|
||||
|
||||
static const char *opcode[] = {
|
||||
"NOP", "LXI B", "STAX B", "INX B", /* 000-003 */
|
||||
"INR B", "DCR B", "MVI B", "RLC", /* 004-007 */
|
||||
"???", "DAD B", "LDAX B", "DCX B", /* 010-013 */
|
||||
"INR C", "DCR C", "MVI C", "RRC", /* 014-017 */
|
||||
"???", "LXI D", "STAX D", "INX D", /* 020-023 */
|
||||
"INR D", "DCR D", "MVI D", "RAL", /* 024-027 */
|
||||
"???", "DAD D", "LDAX D", "DCX D", /* 030-033 */
|
||||
"INR E", "DCR E", "MVI E", "RAR", /* 034-037 */
|
||||
"???", "LXI H", "SHLD", "INX H", /* 040-043 */
|
||||
"INR H", "DCR H", "MVI H", "DAA", /* 044-047 */
|
||||
"???", "DAD H", "LHLD", "DCX H", /* 050-053 */
|
||||
"INR L", "DCR L", "MVI L", "CMA", /* 054-057 */
|
||||
"???", "LXI SP", "STA", "INX SP", /* 060-063 */
|
||||
"INR M", "DCR M", "MVI M", "STC", /* 064-067 */
|
||||
"???", "DAD SP", "LDA", "DCX SP", /* 070-073 */
|
||||
"INR A", "DCR A", "MVI A", "CMC", /* 074-077 */
|
||||
"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", /* 100-103 */
|
||||
"MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 104-107 */
|
||||
"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", /* 110-113 */
|
||||
"MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 114-117 */
|
||||
"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", /* 120-123 */
|
||||
"MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 124-127 */
|
||||
"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", /* 130-133 */
|
||||
"MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 134-137 */
|
||||
"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", /* 140-143 */
|
||||
"MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 144-147 */
|
||||
"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", /* 150-153 */
|
||||
"MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 154-157 */
|
||||
"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", /* 160-163 */
|
||||
"MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 164-167 */
|
||||
"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", /* 170-173 */
|
||||
"MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 174-177 */
|
||||
"ADD B", "ADD C", "ADD D", "ADD E", /* 200-203 */
|
||||
"ADD H", "ADD L", "ADD M", "ADD A", /* 204-207 */
|
||||
"ADC B", "ADC C", "ADC D", "ADC E", /* 210-213 */
|
||||
"ADC H", "ADC L", "ADC M", "ADC A", /* 214-217 */
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", /* 220-223 */
|
||||
"SUB H", "SUB L", "SUB M", "SUB A", /* 224-227 */
|
||||
"SBB B", "SBB C", "SBB D", "SBB E", /* 230-233 */
|
||||
"SBB H", "SBB L", "SBB M", "SBB A", /* 234-237 */
|
||||
"ANA B", "ANA C", "ANA D", "ANA E", /* 240-243 */
|
||||
"ANA H", "ANA L", "ANA M", "ANA A", /* 244-247 */
|
||||
"XRA B", "XRA C", "XRA D", "XRA E", /* 250-253 */
|
||||
"XRA H", "XRA L", "XRA M", "XRA A", /* 254-257 */
|
||||
"ORA B", "ORA C", "ORA D", "ORA E", /* 260-263 */
|
||||
"ORA H", "ORA L", "ORA M", "ORA A", /* 264-267 */
|
||||
"CMP B", "CMP C", "CMP D", "CMP E", /* 270-273 */
|
||||
"CMP H", "CMP L", "CMP M", "CMP A", /* 274-277 */
|
||||
"RNZ", "POP B", "JNZ", "JMP", /* 300-303 */
|
||||
"CNZ", "PUSH B", "ADI", "RST 0", /* 304-307 */
|
||||
"RZ", "RET", "JZ", "???", /* 310-313 */
|
||||
"CZ", "CALL", "ACI", "RST 1", /* 314-317 */
|
||||
"RNC", "POP D", "JNC", "OUT", /* 320-323 */
|
||||
"CNC", "PUSH D", "SUI", "RST 2", /* 324-327 */
|
||||
"RC", "???", "JC", "IN", /* 330-333 */
|
||||
"CC", "???", "SBI", "RST 3", /* 334-337 */
|
||||
"RPO", "POP H", "JPO", "XTHL", /* 340-343 */
|
||||
"CPO", "PUSH H", "ANI", "RST 4", /* 344-347 */
|
||||
"RPE", "PCHL", "JPE", "XCHG", /* 350-353 */
|
||||
"CPE", "???", "XRI", "RST 5", /* 354-357 */
|
||||
"RP", "POP PSW", "JP", "DI", /* 360-363 */
|
||||
"CP", "PUSH PSW", "ORI", "RST 6", /* 364-367 */
|
||||
"RM", "SPHL", "JM", "EI", /* 370-373 */
|
||||
"CM", "???", "CPI", "RST 7", /* 374-377 */
|
||||
};
|
||||
|
||||
int32 oplen[256] = {
|
||||
1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,
|
||||
0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1,0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1,1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1,
|
||||
1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1,1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 };
|
||||
|
||||
/* This is the binary loader. The input file is considered to be
|
||||
a string of literal bytes with no format special format. The
|
||||
load starts at the current value of the PC.
|
||||
*/
|
||||
|
||||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 i, addr = 0, cnt = 0;
|
||||
|
||||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||||
addr = saved_PC;
|
||||
while ((i = getc (fileref)) != EOF) {
|
||||
M[addr] = i;
|
||||
addr++;
|
||||
cnt++;
|
||||
} /* end while */
|
||||
printf ("%d Bytes loaded.\n", cnt);
|
||||
return (SCPE_OK);
|
||||
}
|
||||
|
||||
/* Symbolic output
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to values
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error code
|
||||
*/
|
||||
|
||||
int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 cflag, c1, c2, inst, adr;
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
c1 = (val[0] >> 8) & 0177;
|
||||
c2 = val[0] & 0177;
|
||||
if (sw & SWMASK ('A')) {
|
||||
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('C')) {
|
||||
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
|
||||
fprintf (of, (c2 < 040)? "<%03o>": "%c", c2);
|
||||
return SCPE_OK; }
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
inst = val[0];
|
||||
fprintf (of, "%s", opcode[inst]);
|
||||
if (oplen[inst] == 2) {
|
||||
if (strchr(opcode[inst], ' ') != NULL)
|
||||
fprintf (of, ",");
|
||||
else fprintf (of, " ");
|
||||
fprintf (of, "%o", val[1]);
|
||||
}
|
||||
if (oplen[inst] == 3) {
|
||||
adr = val[1] & 0xFF;
|
||||
adr |= (val[2] << 8) & 0xff00;
|
||||
if (strchr(opcode[inst], ' ') != NULL)
|
||||
fprintf (of, ",");
|
||||
else fprintf (of, " ");
|
||||
fprintf (of, "%o", adr);
|
||||
}
|
||||
return -(oplen[inst] - 1);
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw)
|
||||
{
|
||||
int32 cflag, i = 0, j, r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (unsigned int) cptr[0];
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1];
|
||||
return SCPE_OK; }
|
||||
|
||||
/* An instruction: get opcode (all characters until null, comma,
|
||||
or numeric (including spaces).
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
if (*cptr == ',' || *cptr == '\0' ||
|
||||
isdigit(*cptr))
|
||||
break;
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Allow for RST which has numeric as part of opcode */
|
||||
|
||||
if (toupper(gbuf[0]) == 'R' &&
|
||||
toupper(gbuf[1]) == 'S' &&
|
||||
toupper(gbuf[2]) == 'T') {
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Allow for 'MOV' which is only opcode that has comma in it. */
|
||||
|
||||
if (toupper(gbuf[0]) == 'M' &&
|
||||
toupper(gbuf[1]) == 'O' &&
|
||||
toupper(gbuf[2]) == 'V') {
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
gbuf[i] = toupper(*cptr);
|
||||
cptr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* kill trailing spaces if any */
|
||||
gbuf[i] = '\0';
|
||||
for (j = i - 1; gbuf[j] == ' '; j--) {
|
||||
gbuf[j] = '\0';
|
||||
}
|
||||
|
||||
/* find opcode in table */
|
||||
for (j = 0; j < 256; j++) {
|
||||
if (strcmp(gbuf, opcode[j]) == 0)
|
||||
break;
|
||||
}
|
||||
if (j > 255) /* not found */
|
||||
return SCPE_ARG;
|
||||
|
||||
val[0] = j; /* store opcode */
|
||||
if (oplen[j] < 2) /* if 1-byter we are done */
|
||||
return SCPE_OK;
|
||||
if (*cptr == ',') cptr++;
|
||||
cptr = get_glyph(cptr, gbuf, 0); /* get address */
|
||||
sscanf(gbuf, "%o", &r);
|
||||
if (oplen[j] == 2) {
|
||||
val[1] = r & 0xFF;
|
||||
return (-1);
|
||||
}
|
||||
val[1] = r & 0xFF;
|
||||
val[2] = (r >> 8) & 0xFF;
|
||||
return (-2);
|
||||
}
|
||||
@@ -1,895 +0,0 @@
|
||||
Altair 8800 Simulator with Z80 support
|
||||
======================================
|
||||
|
||||
0. Revision History
|
||||
|
||||
- 25-Feb-2003, Peter Schorn (added support for real time simulation)
|
||||
- 9-Oct-2002, Peter Schorn (added support for simulated hard disk)
|
||||
- 28-Sep-2002, Peter Schorn (number of tracks per disk can be configured)
|
||||
- 19-Sep-2002, Peter Schorn (added WARNROM feature)
|
||||
- 31-Aug-2002, Peter Schorn (added extended ROM features suggested
|
||||
by Scott LaBombard)
|
||||
- 4-May-2002, Peter Schorn (added description of MP/M II sample software)
|
||||
- 28-Apr-2002, Peter Schorn (added periodic timer interrupts and three
|
||||
additional consoles)
|
||||
- 15-Apr-2002, Peter Schorn (added memory breakpoint)
|
||||
- 7-Apr-2002, Peter Schorn (added ROM / NOROM switch)
|
||||
Original version of this document written by Charles E Owen
|
||||
|
||||
|
||||
1. Background.
|
||||
|
||||
The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800 was
|
||||
announced on the January 1975 cover of Popular Electronics, which boasted
|
||||
you could buy and build this powerful computer kit for only $397. The kit
|
||||
consisted at that time of only the parts to build a case, power supply,
|
||||
card cage (18 slots), CPU card, and memory card with 256 *bytes* of memory.
|
||||
Still, thousands were ordered within the first few months after the
|
||||
announcement, starting the personal computer revolution as we know it
|
||||
today.
|
||||
|
||||
Many laugh at the small size of the that first kit, noting there were no
|
||||
peripherals and the 256 byte memory size. But the computer was an open
|
||||
system, and by 1977 MITS and many other small startups had added many
|
||||
expansion cards to make the Altair quite a respectable little computer. The
|
||||
"Altair Bus" that made this possible was soon called the S-100 Bus, later
|
||||
adopted as an industry standard, and eventually became the IEE-696 Bus.
|
||||
|
||||
|
||||
2. Hardware
|
||||
|
||||
We are simulating a fairly "loaded" Altair 8800 from about 1977, with the
|
||||
following configuration:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU Altair 8800 with Intel 8080 CPU board, 62KB
|
||||
of RAM, 2K of EPROM with start boot ROM.
|
||||
SIO MITS 88-2SIO Dual Serial Interface Board. Port 1
|
||||
is assumed to be connected to a serial "glass
|
||||
TTY" that is your terminal running the Simulator.
|
||||
PTR Paper Tape Reader attached to port 2 of the 2SIO board.
|
||||
PTP Paper Tape Punch attached to port 2 of the
|
||||
2SIO board. This also doubles as a printer port.
|
||||
DSK MITS 88-DISK Floppy Disk controller with up
|
||||
to eight drives.
|
||||
|
||||
|
||||
2.1 CPU
|
||||
|
||||
We have 2 CPU options that were not present on the original machine but
|
||||
are useful in the simulator. We also allow you to select memory sizes, but
|
||||
be aware that some sample software requires the full 64K (i.e. CP/M) and
|
||||
the MITS Disk Basic and Altair DOS require about a minimum of 24K.
|
||||
|
||||
SET CPU 8080 Simulates the 8080 CPU (normal)
|
||||
SET CPU Z80 Simulates the Z80 CPU. Note that some software (e.g. most
|
||||
original Altair software such as 4K Basic) requires an 8080 CPU and
|
||||
will not or not properly run on a Z80. This is mainly due to the use
|
||||
of the parity flag on the 8080 which has not always the same
|
||||
semantics on the Z80.
|
||||
|
||||
SET CPU ITRAP Causes the simulator to halt if an invalid opcode
|
||||
is detected (depending on the chosen CPU).
|
||||
SET CPU NOITRAP Does not stop on an invalid Opcode. This is
|
||||
how the real 8080 works.
|
||||
|
||||
SET CPU 4K
|
||||
SET CPU 8K
|
||||
SET CPU 12K
|
||||
SET CPU 16K
|
||||
...... (in 4K steps)
|
||||
SET CPU 64K All these set various CPU memory configurations.
|
||||
|
||||
SET CPU BANKED Enables the banked memory support. The simulated memory
|
||||
has eight banks with address range 0..'common' (see registers below)
|
||||
and a common area from 'common' to 0xfff which is common to all
|
||||
banks. The currently active bank is determined by register 'bank'
|
||||
(see below). You can only switch to banked memory if the memory
|
||||
is set to 64K. The banked memory is used by CP/M 3.
|
||||
|
||||
SET CPU NONBANKED Disables banked memory support.
|
||||
|
||||
SET CPU ROM Enables the ROM from address 'ROMLOW' to 'ROMHIGH'
|
||||
(see below under CPU Registers) and prevents write access
|
||||
to these locations. This is the default setting.
|
||||
|
||||
SET CPU NOROM Disables the ROM.
|
||||
|
||||
SET CPU ALTAIRROM Enables the slightly modified but downwards compatible
|
||||
Altair boot ROM at addresses 0FF00 to 0FFFF. This is the default.
|
||||
|
||||
SET CPU NOALTAIRROM Disables standard Altair ROM behavior.
|
||||
|
||||
SET CPU WARNROM Enables warning messages to be printed when the CPU
|
||||
attempts to write into ROM or into non-existing memory. Also prints
|
||||
a warning message if the CPU attempts to read from non-existing
|
||||
memory.
|
||||
|
||||
SET CPU NOWARNROM Suppreses all warning message of "WARNROM". Note that
|
||||
some software tries on purpose to write to ROM in order to detect
|
||||
the available RAM.
|
||||
|
||||
The BOOT EPROM card starts at address 0FF00 if it has been enabled by
|
||||
'SET CPU ALTAIRROM'. Jumping to this address will boot drive 0 of the
|
||||
floppy controller (CPU must be set to ROM or equivalent code must be
|
||||
present). If no valid bootable software is present there the machine
|
||||
crashes. This is historically accurate behavior.
|
||||
|
||||
The real 8080, on receiving a HLT (Halt) instruction, freezes the
|
||||
processor and only an interrupt or CPU hardware reset will restore it. The
|
||||
simulator is alot nicer, it will halt but send you back to the simulator
|
||||
command line.
|
||||
|
||||
CPU Registers include the following:
|
||||
|
||||
Name Size Comment
|
||||
|
||||
PC 16 The Program Counter
|
||||
AF 16 The accumulator and the flag register
|
||||
F = S Z - AC - P/V N C
|
||||
S = Sign flag.
|
||||
Z = Zero Flag.
|
||||
AC = Auxillary Carry flag.
|
||||
P/V = Parity flag on 8080
|
||||
Parity / Overflow flag on Z80
|
||||
- = not used (undefined)
|
||||
N = Internal sign flag
|
||||
C = Carry flag.
|
||||
BC 16 The BC register pair.
|
||||
Register B is the high 8 bits, C is the lower 8 bits
|
||||
DE 16 The DE register pair.
|
||||
Register D is the high 8 bits, E is the lower 8 bits.
|
||||
HL 16 The HL register pair.
|
||||
Register H is the high 8 bits, L is the lower 8 bits.
|
||||
AF1 16 The alternate AF register (on Z80 only)
|
||||
BC1 16 The alternate BC register (on Z80 only)
|
||||
DE1 16 The alternate DE register (on Z80 only)
|
||||
HL1 16 The alternate HL register (on Z80 only)
|
||||
IX 16 The IX index register (on Z80 only)
|
||||
IY 16 The IY index register (on Z80 only)
|
||||
IFF 8 Interrupt flag (on Z80 only)
|
||||
INT 8 Interrupt register (on Z80 only)
|
||||
|
||||
SR 16 The front panel switches (use D SR 8 for 4k Basic).
|
||||
WRU 8 The interrupt character. This starts as 5
|
||||
(ctrl-E) but some Altair software uses this
|
||||
keystroke so best to change this to something
|
||||
exotic such as 035 (which is Ctl-]).
|
||||
|
||||
BANK 3 The currently active memory bank (if banked memory
|
||||
is activated - see memory options above)
|
||||
COMMON 16 The starting address of common memory. Originally set
|
||||
to 0xc000 (note this setting must agree with the
|
||||
value supplied to GENCPM for CP/M 3 system generation)
|
||||
ROMLOW 16 The starting address of the ROM. Default is 0FF00.
|
||||
ROMHIGH 16 The final address of the ROM. Default is 0FFFF.
|
||||
CLOCK 32 The clock speed of the simulated CPU in kHz or 0 to run
|
||||
at maximum speed. To set the clock speed for a typical
|
||||
4 MHz Z80 CPU, use D CLOCK 4000. The CP/M utility SPEED
|
||||
measures the clock speed of the simulated CPU.
|
||||
|
||||
|
||||
2.2 The Serial I/O Card (2SIO)
|
||||
|
||||
This simple programmed I/O device provides 2 serial ports to the outside
|
||||
world, which could be hardware jumpered to support RS-232 plugs or a TTY
|
||||
current loop interface. The standard I/O addresses assigned by MITS was
|
||||
10-11 (hex) for the first port, and 12-13 (hex) for the second. We follow
|
||||
this standard in the Simulator.
|
||||
|
||||
The simulator directs I/O to/from the first port to the screen. The
|
||||
second port reads from an attachable "tape reader" file on input, and
|
||||
writes to an attachable "punch file" on output. These files are considered
|
||||
a simple stream of 8-bit bytes.
|
||||
|
||||
The SIO can be configured in SIMH with the following commands:
|
||||
|
||||
SET SIO TTY Bit 8 is set to zero on console output
|
||||
SET SIO ANSI Bit 8 is not touched on console output
|
||||
|
||||
SET SIO ALL Console input support lower- and upper case
|
||||
SET SIO UPPER Console input is transformed to upper case characters only
|
||||
(This feature is useful for most Altair software)
|
||||
|
||||
SET SIO BS Map the delete character to backspace
|
||||
SET SIO DEL Map the backspace character to delete
|
||||
|
||||
SET SIO QUIET Do not print warning messages
|
||||
SET SIO VERBOSE Print warning messages (useful for debugging)
|
||||
The register SIOWL determines how often the same warning
|
||||
is displayed. The default is 3.
|
||||
|
||||
You can also attach the SIO to a port:
|
||||
|
||||
ATTACH SIO 23 Console IO goes via a Telnet connection on port 23
|
||||
DETACH SIO Console IO goes via the regular SIMH console
|
||||
|
||||
|
||||
2.3 The SIMH pseudo device
|
||||
|
||||
The SIMH pseudo device facilitates the communication between the
|
||||
simulated ALTAIR and the simulator environment. This device defines a
|
||||
number of (most R/O) registers (see source code) which are primarily useful
|
||||
for debugging purposes.
|
||||
|
||||
The SIMH pseudo device can be configured with
|
||||
|
||||
SET SIMH QUIET Do not print warning messages
|
||||
SET SIMH VERBOSE Print warning messages (useful for debugging)
|
||||
|
||||
SET SIMH TIMERON Start periodic timer interrupts
|
||||
SET SIMH TIMEROFF Stop the periodic timer interrupts
|
||||
|
||||
The following variables determine the behavior of the timer:
|
||||
|
||||
TIMD This is the delay between consecutive interrupts in milliseconds.
|
||||
Use D TIMD 20 for a 50 Hz clock.
|
||||
TIMH This is the address of the interrupt handler to call for a
|
||||
timer interrupt.
|
||||
|
||||
|
||||
2.4 The 88-DISK controller.
|
||||
|
||||
The MITS 88-DISK is a simple programmed I/O interface to the MITS 8-inch
|
||||
floppy drive, which was basically a Pertec FD-400 with a power supply and
|
||||
buffer board builtin. The controller supports neither interrupts nor DMA,
|
||||
so floppy access required the sustained attention of the CPU. The standard
|
||||
I/O addresses were 8, 9, and 0A (hex), and we follow the standard. Details
|
||||
on controlling this hardware are in the altair_dsk.c source file.
|
||||
|
||||
The only difference is that the simulated disks may be larger than the
|
||||
original ones: The original disk had 77 tracks while the simulated disks
|
||||
support up to 254 tracks (only relevant for CP/M). You can change the
|
||||
number of tracks per disk by setting the appropriate value in TRACKS[..].
|
||||
For example "D TRACKS[0] 77" sets the number of tracks for disk 0 to the
|
||||
original number of 77. The command "D TRACKS[0-7] 77" changes the highest
|
||||
track number for all disks to 77.
|
||||
|
||||
For debugging purposes you can set the trace level of some disk I/O
|
||||
functions. To do so the following bits in TRACE (a register of the disk)
|
||||
have been defined with the following meaning:
|
||||
|
||||
1 Trace all IN and OUT instructions on the disk ports 8 and 9
|
||||
2 Trace all read and writes to full sectors on the disk
|
||||
4 Print a message whenever an unnecessary step-in or step out of the
|
||||
disk head occurs (often an indication of an infinite loop)
|
||||
8 Print a message whenever the disk head appears to be waiting for a
|
||||
sector which does not show up (often an indication of an infinite
|
||||
loop)
|
||||
|
||||
For example the command "D TRACE 10" will trace options 2+8 from above.
|
||||
|
||||
The DSK device can be configured with
|
||||
|
||||
SET DSK<n> QUIET Do not print warning messages for disk <n>
|
||||
SET DSK<n> VERBOSE Print warning messages for disk <n>
|
||||
(useful for debugging)
|
||||
The register DSKWL determines how often the
|
||||
same warning is displayed. The default is 3.
|
||||
|
||||
SET DSK<n> WRITEENABLED Allow write operations for disk <n>
|
||||
SET DSK<n> LOCKED Disk <n> is locked, i.e. no write operations
|
||||
will be allowed.
|
||||
|
||||
|
||||
2.5 The simulated hard disk
|
||||
|
||||
In order to increase the available storage capacity, the simulator
|
||||
features 8 simulated hard disks with a capacity of 8MB (HDSK0 to HDSK7).
|
||||
Currently only CP/M supports two hard disks as devices I: and J:.
|
||||
|
||||
For debugging purposes one can set the trace flag by executing the
|
||||
command "D HDTRACE 1". The default for "HDTRACE" is 0 (no trace).
|
||||
|
||||
The HDSK device can be configured with
|
||||
|
||||
SET HDSK<n> QUIET Do not print warning messages for hard disk <n>
|
||||
SET HDSK<n> VERBOSE Print warning messages for hard disk <n>
|
||||
(useful for debugging)
|
||||
|
||||
SET HDSK<n> WRITEENABLED Allow write operations for hard disk <n>
|
||||
SET HDSK<n> LOCKED Hard disk <n> is locked, i.e. no
|
||||
write operations will be allowed.
|
||||
|
||||
|
||||
3. Sample Software
|
||||
|
||||
Running an Altair in 1977 you would be running either MITS Disk Extended
|
||||
BASIC, or the brand new and sexy CP/M Operating System from Digital
|
||||
Research. Or possibly, you ordered Altair DOS back when it was promised in
|
||||
1975, and are still waiting for it to be delivered in early 1977.
|
||||
|
||||
We have samples of all three for you to check out. We can't go into the
|
||||
details of how they work, but we'll give you a few hints.
|
||||
|
||||
|
||||
3.1 CP/M Version 2.2
|
||||
|
||||
This version is my own port of the standard CP/M to the Altair. There
|
||||
were some "official" versions but I don't have them. None were endorsed or
|
||||
sold by MITS to my knowledge, however.
|
||||
|
||||
To boot CP/M:
|
||||
|
||||
sim> attach dsk cpm2.dsk
|
||||
sim> boot dsk
|
||||
|
||||
CP/M feels like DOS, sort of. DIR will work. I have included all the
|
||||
standard CP/M utilities, plus a few common public-domain ones. I also
|
||||
include the sources to the customized BIOS and some other small programs.
|
||||
TYPE will print an ASCII file. DUMP will dump a binary one. LS is a
|
||||
better DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load"
|
||||
them to binary format (.COM). ED is a simple editor, #A command will bring
|
||||
the source file to the buffer, T command will "type" lines, L will move
|
||||
lines, E exits the editor. 20L20T will move down 20 lines, and type 20.
|
||||
Very DECish. DDT is the debugger, DO is a batch-type command processor. A
|
||||
sample batch file that will assemble and write out the bootable CP/M image
|
||||
(on drive A) is "SYSCPM2.SUB". To run it, type "DO SYSCPM2".
|
||||
|
||||
In order to efficiently transfer files into the CP/M environment use the
|
||||
included program R <filename.ext>. If you have a file named foo.ext in the
|
||||
current directory (i.e. the directory where SIMH is), executing R FOO.EXT
|
||||
under CP/M will transfer the file onto the CP/M disk. Transferring a file
|
||||
from the CP/M environment to the SIMH environment is accomplished by
|
||||
W <filename.ext> for text files or by W <filename.ext> B for binary files.
|
||||
The simplest way for transferring multiple files is to create a ".SUB"
|
||||
batch file which contains the necessary R resp. W commands.
|
||||
|
||||
If you need more storage space you can use a simulated hard disk on
|
||||
drives I: and J:. To use do "attach HDSK0 hdi.dsk" and issue the
|
||||
"XFORMAT I:" resp. "XFORMAT J:" command from CP/M do initialize the disk
|
||||
to an empty state.
|
||||
|
||||
The disk "cpm2.dsk" contains the following files:
|
||||
Name Ext Size Comment
|
||||
ASM .COM 8K ; CP/M assembler
|
||||
BDOS .MAC 68K ; Basic Disk Operating System assembler source code
|
||||
BOOT .COM 1K ; transfer control to boot ROM
|
||||
BOOT .MAC 2K ; source for BOOT.COM
|
||||
BOOTGEN .COM 2K ; put a program on the boot sectors
|
||||
CBIOSX .MAC 48K ; CP/M 2 BIOS source for Altair
|
||||
CCP .MAC 26K ; Console Command Processor assembler source code
|
||||
COPY .COM 2K ; copy disks
|
||||
CPMBOOT .COM 12K ; CP/M operating system
|
||||
CPU .COM 2K ; get and set the CPU type (8080 or Z80)
|
||||
CPU .MAC 2K ; source for CPU.COM
|
||||
CREF80 .COM 4K ; cross reference utility
|
||||
DDT .COM 6K ; 8080 debugger
|
||||
DDTZ .COM 10K ; Z80 debugger
|
||||
DIF .COM 4K ; determine differences between two files
|
||||
DO .COM 2K ; batch processing
|
||||
DSKBOOT .MAC 8K ; source for boot ROM
|
||||
DUMP .COM 2K ; hex dump a file
|
||||
ED .COM 8K ; line editor
|
||||
ELIZA .BAS 10K ; Eliza game in Basic
|
||||
EX8080 .COM 12K ; exercise 8080 instruction set
|
||||
EXZ80N .COM 12K ; exercise Z80 instruction set, No undefined status bits
|
||||
EXZ80U .COM 12K ; exercise Z80 instruction set, Undefined status bits
|
||||
EXZ80 .MAC 54K ; source for EX8080.COM, EXZ80N.COM, EXZ80U.COM
|
||||
EX .SUB 2K ; benchmark execution of EX8080.COM, EXZ80N.COM, EXZ80U.COM
|
||||
FORMAT .COM 2K ; format disks
|
||||
GO .COM 0K ; start the currently loaded program at 100H
|
||||
HDSKBOOT.MAC 6K ; boot code for hard disk
|
||||
L80 .COM 12K ; Microsoft linker
|
||||
LADDER .COM 40K ; game
|
||||
LADDER .DAT 2K ; high score file for LADDER.COM
|
||||
LIB80 .COM 6K ; library utility
|
||||
LOAD .COM 2K ; load hex files
|
||||
LS .COM 4K ; directory utility
|
||||
LU .COM 20K ; library utility
|
||||
M80 .COM 20K ; Microsoft macro assembler
|
||||
MBASIC .COM 24K ; Microsoft Basic interpreter
|
||||
MC .SUB 2K ; assemble and link an assembler program
|
||||
MCC .SUB 2K ; read, assemble and link an assembler program
|
||||
MCCL .SUB 2K ; assemble, link and produce listing
|
||||
MEMCFG .LIB 2K ; defines the memory configuration
|
||||
MOVER .MAC 2K ; moves operating system in place
|
||||
OTHELLO .COM 12K ; Othello (Reversi) game
|
||||
PIP .COM 8K ; Peripheral Interchange Program
|
||||
PRELIM .COM 2K ; preliminary CPU tests
|
||||
PRELIM .MAC 6K ; source code for PRELIM.COM
|
||||
R .COM 4K ; read files from SIMH environment
|
||||
RSETSIMH.COM 2K ; reset SIMH interface
|
||||
RSETSIMH.MAC 2K ; assembler source for RSETSIMH.COM
|
||||
SHOWSEC .COM 3K ; show sectors on a disk
|
||||
SID .COM 8K ; debugger for 8080
|
||||
SPEED .COM 2K ; utility to measure the clock speed of the simulated CPU
|
||||
STAT .COM 6K ; provide information about currently logged disks
|
||||
SURVEY .COM 2K ; system survey
|
||||
SURVEY .MAC 16K ; assembler source for SURVEY.COM
|
||||
SYSCOPY .COM 2K ; copy system tracks between disks
|
||||
SYSCPM2 .SUB 2K ; create CP/M 2 on drive A:
|
||||
TIMER .COM 2K ; perform various timer operations
|
||||
TIMER .MAC 2K ; source code for TIMER.COM
|
||||
UNCR .COM 8K ; un-crunch utility
|
||||
UNERA .COM 2K ; un-erase a file
|
||||
UNERA .MAC 16K ; source for UNERA.COM
|
||||
USQ .COM 2K ; un-squeeze utility
|
||||
W .COM 4K ; write files to SIMH environment
|
||||
WM .COM 12K ; word master screen editor
|
||||
WM .HLP 3K ; help file for WM.COM
|
||||
WORM .COM 4K ; worm game for VT100 terminal
|
||||
XFORMAT .COM 2K ; initialise a drive (floppy or hard disk)
|
||||
XSUB .COM 2K ; support for DO.COM
|
||||
ZAP .COM 10K ; SuperZap 5.2 disk editor configured for VT100
|
||||
ZSID .COM 10K ; debugger for Z80
|
||||
ZTRAN4 .COM 4K ; translate 8080 mnemonics into Z80 equivalents
|
||||
|
||||
|
||||
3.2 CP/M Version 3 with banked memory
|
||||
|
||||
CP/M 3 is the successor to CP/M 2.2. A customised BIOS (BIOS3.MAC) is
|
||||
included to facilitate modification if so desired. The defaults supplied in
|
||||
GENCPM.DAT for system generation can be used. BOOTGEN.COM is used to place
|
||||
the CP/M loader (LDR.COM) on the boot tracks of a disk.
|
||||
|
||||
Running CP/M 3 with banked memory:
|
||||
sim> attach dsk cpm3.dsk
|
||||
sim> reset cpu
|
||||
sim> set cpu banked
|
||||
sim> set cpu itrap
|
||||
sim> boot dsk
|
||||
|
||||
Executing "DO SYSCPM3" will re-generate the banked version of CP/M 3. You
|
||||
can boot CP/M 3 with or without a Z80 CPU. The Z80 CPU is needed for both
|
||||
sysgens due to the use of BOOTGEN.COM which requires it.
|
||||
|
||||
The disk "cpm3.dsk" contains the following files:
|
||||
ASM .COM 8K ; CP/M assembler
|
||||
ASSIGN .SYS 2K
|
||||
BDOS3 .SPR 10K
|
||||
BIOS3 .MAC 28K ; CP/M 3 BIOS source for Altair SIMH
|
||||
BIOS3 .SPR 4K
|
||||
BNKBDOS3.SPR 14K
|
||||
BNKBIOS3.SPR 4K
|
||||
BOOT .COM 2K ; transfer control to boot ROM
|
||||
BOOTGEN .COM 2K ; put a program on the boot sectors
|
||||
CCP .COM 4K
|
||||
COPYSYS .COM 2K
|
||||
CPM3 .SYS 18K
|
||||
CPMLDR .MAC 38K ; CP/M 3 loader assembler source
|
||||
DATE .COM 4K ; date utility
|
||||
DDT .COM 6K ; 8080 debugger
|
||||
DDTZ .COM 10K ; Z80 debugger
|
||||
DEFS .LIB 2K ; include file for BIOS3.MAC to create banked CP/M 3
|
||||
DEVICE .COM 8K
|
||||
DIF .COM 4K ; determine differences between two files
|
||||
DIR .COM 16K ; directory utility
|
||||
DO .COM 6K ; batch processing
|
||||
DUMP .COM 2K
|
||||
ED .COM 10K
|
||||
ERASE .COM 4K
|
||||
GENCOM .COM 16K
|
||||
GENCPM .COM 22K
|
||||
GENCPM .DAT 4K ; CP/M generation information for banked version
|
||||
GENCPMNB.DAT 4K ; CP/M generation information for non-banked version
|
||||
GET .COM 8K
|
||||
HELP .COM 8K ; help utility
|
||||
HELP .HLP 62K ; help files
|
||||
HEXCOM .CPM 2K
|
||||
HIST .UTL 2K
|
||||
INITDIR .COM 32K
|
||||
L80 .COM 12K ; Microsoft linker
|
||||
LDR .COM 4K ; CP/M loader with optimised loader BIOS
|
||||
LDRBIOS3.MAC 14K ; optimised (for space) loader BIOS
|
||||
LIB .COM 8K ; Digital Research librarian
|
||||
LINK .COM 16K ; Digital Research linker
|
||||
LOAD .COM 2K
|
||||
M80 .COM 20K ; Microsoft macro assembler
|
||||
MC .SUB 2K ; assemble and link an assmbler program
|
||||
MCC .SUB 2K ; read, assemble and link an assembler program
|
||||
PATCH .COM 4K
|
||||
PIP .COM 10K ; Peripheral Interchange Program
|
||||
PROFILE .SUB 2K ; commands to be executed at start up
|
||||
PUT .COM 8K
|
||||
R .COM 4K ; read files from SIMH environment
|
||||
RENAME .COM 4K
|
||||
RESBDOS3.SPR 2K
|
||||
RMAC .COM 14K ; Digital Research macro assembler
|
||||
RSETSIMH.COM 2K ; reset SIMH interface
|
||||
SAVE .COM 2K
|
||||
SCB .MAC 2K
|
||||
SET .COM 12K
|
||||
SETDEF .COM 6K
|
||||
SHOW .COM 10K
|
||||
SHOWSEC .COM 4K ; show sectors on a disk
|
||||
SID .COM 8K ; 8080 debugger
|
||||
SYSCOPY .COM 2K ; copy system tracks between disks
|
||||
SYSCPM3 .SUB 2K ; create banked CP/M 3 system
|
||||
TRACE .UTL 2K
|
||||
TSHOW .COM 2K ; show split time
|
||||
TSTART .COM 2K ; create timer and start it
|
||||
TSTOP .COM 2K ; show final time and stop timer
|
||||
TYPE .COM 4K
|
||||
UNERA .COM 2K ; un-erase a file
|
||||
W .COM 4K ; write files to SIMH environment
|
||||
XREF .COM 16K ; cross reference utility
|
||||
ZSID .COM 10K ; Z80 debugger
|
||||
|
||||
|
||||
3.3 MP/M II with banked memory
|
||||
|
||||
MP/M II is an acronym for MultiProgramming Monitor Control Program for
|
||||
Microprocessors. It is a multiuser operating system for an eight bit
|
||||
microcomputer. MP/M II supports multiprogramming at each terminal. This
|
||||
version supports four terminals available via Telnet. To boot:
|
||||
|
||||
sim> attach dsk mpm.dsk
|
||||
sim> set cpu itrap
|
||||
sim> set cpu z80
|
||||
sim> set cpu rom
|
||||
sim> set cpu banked
|
||||
sim> attach sio 23
|
||||
sim> d common b000
|
||||
sim> boot dsk
|
||||
|
||||
Now connect a Telnet session to the simulator and type "MPM" at the "A>"
|
||||
prompt. Now you can connect up to three additional terminals via Telnet to
|
||||
the Altair running MP/M II. To re-generate the system perform "DO SYSMPM"
|
||||
in the CP/M environment (not possible under MP/M since XSUB is needed).
|
||||
|
||||
The disk "mpm.dsk" contains the following files:
|
||||
Name Ext Size Comment
|
||||
ABORT .PRL 2K ; abort a process
|
||||
ABORT .RSP 2K
|
||||
ASM .PRL 10K ; MP/M assembler
|
||||
BNKBDOS .SPR 12K ; banked BDOS
|
||||
BNKXDOS .SPR 2K ; banked XDOS
|
||||
BNKXIOS .SPR 4K ; banked XIOS
|
||||
BOOTGEN .COM 2K ; copy an executable to the boot section
|
||||
CONSOLE .PRL 2K ; print console number
|
||||
CPM .COM 2K ; return to CP/M
|
||||
CPM .MAC 2K ; source for CPM.COM
|
||||
DDT .COM 6K ; MP/M DDT
|
||||
DDT2 .COM 6K ; CP/M DDT
|
||||
DDTZ .COM 10K ; CP/M DDT with Z80 support
|
||||
DIF .COM 4K ; difference between two files
|
||||
DIR .PRL 2K ; directory command
|
||||
DO .COM 2K ; CP/M submit
|
||||
DSKRESET.PRL 2K ; disk reset command
|
||||
DUMP .MAC 6K ; source for DUMP.PRL
|
||||
DUMP .PRL 2K ; dump command
|
||||
ED .PRL 10K ; MP/M line editor
|
||||
ERA .PRL 2K ; erase command
|
||||
ERAQ .PRL 4K ; erase comand (verbose)
|
||||
GENHEX .COM 2K
|
||||
GENMOD .COM 2K
|
||||
GENSYS .COM 10K
|
||||
L80 .COM 12K ; Microsoft linker
|
||||
LDRBIOS .MAC 14K ; loader BIOS
|
||||
LIB .COM 8K ; library utility
|
||||
LINK .COM 16K ; linker
|
||||
LOAD .COM 2K ; loader
|
||||
M80 .COM 20K ; Microsoft macro assembler
|
||||
MC .SUB 2K ; assemble and link an assmbler program
|
||||
MCC .SUB 2K ; read, assemble and link an assembler program
|
||||
MPM .COM 8K ; start MP/M II
|
||||
MPM .SYS 26K ; MP/M system file
|
||||
MPMD .LIB 2K ; define a banked system
|
||||
MPMLDR .COM 6K ; MP/M loader without LDRBIOS
|
||||
MPMSTAT .BRS 6K ; status of MP/M system
|
||||
MPMSTAT .PRL 6K
|
||||
MPMSTAT .RSP 2K
|
||||
MPMXIOS .MAC 26K ; XIOS for MP/M
|
||||
PIP .PRL 10K ; MP/M peripheral interchange program
|
||||
PIP2 .COM 8K ; CP/M peripheral interchange program
|
||||
PRINTER .PRL 2K
|
||||
PRLCOM .PRL 4K
|
||||
R .COM 4K ; read a file from the SIMH environment
|
||||
RDT .PRL 8K ; debugger for page relocatable programs
|
||||
REN .PRL 4K ; rename a file
|
||||
RESBDOS .SPR 4K ; non-banked BDOS
|
||||
RMAC .COM 14K ; Digital Research macro assembler
|
||||
RSETSIMH.COM 2K ; reset SIMH interface
|
||||
SCHED .BRS 2K ; schedule a job
|
||||
SCHED .PRL 4K
|
||||
SCHED .RSP 2K
|
||||
SDIR .PRL 18K ; fancy directory command
|
||||
SET .PRL 8K ; set parameters
|
||||
SHOW .PRL 8K ; show status of disks
|
||||
SPOOL .BRS 4K ; spool utility
|
||||
SPOOL .PRL 4K
|
||||
SPOOL .RSP 2K
|
||||
STAT .COM 6K ; CP/M stat command
|
||||
STAT .PRL 10K ; MP/M stat command
|
||||
STOPSPLR.PRL 2K ; stop spooler
|
||||
SUBMIT .PRL 6K ; MP/M submit
|
||||
SYSCOPY .COM 2K ; copy system tracks
|
||||
SYSMPM .SUB 2K ; do a system generation
|
||||
SYSTEM .DAT 2K ; default values for system generation
|
||||
TMP .SPR 2K
|
||||
TOD .PRL 4K ; time of day
|
||||
TSHOW .COM 2K ; show split time
|
||||
TSTART .COM 2K ; create timer and start it
|
||||
TSTOP .COM 2K ; show final time and stop timer
|
||||
TYPE .PRL 2K ; type a file on the screen
|
||||
USER .PRL 2K ; set user area
|
||||
W .COM 4K ; write a file to SIMH environment
|
||||
XDOS .SPR 10K ; XDOS
|
||||
XREF .COM 16K ; cross reference utility
|
||||
XSUB .COM 2K ; for CP/M DO
|
||||
|
||||
|
||||
3.4 CP/M application software
|
||||
|
||||
There is also a small collection of sample application software
|
||||
containing the following items:
|
||||
|
||||
- SPL: a Small Programming Language with a suite of sample programs
|
||||
- PROLOGZ: a Prolog interpreter written in SPL with sources
|
||||
- PASCFORM: a Pascal pretty printer written in Pascal
|
||||
- Pascal MT+: Pascal language system needed to compile PASCFORM
|
||||
|
||||
The sample software comes on "app.dsk" and to use it do
|
||||
|
||||
sim> attach dsk1 app.dsk
|
||||
|
||||
before booting CP/M.
|
||||
|
||||
The disk "app.dsk" contains the following files:
|
||||
Name Ext Size Comment
|
||||
BOOTGEN .COM 2K
|
||||
BOOTGEN .SPL 6K ; SPL source for BOOTGEN.COM
|
||||
C .SUB 2K ; batch file for compiling an SPL source file
|
||||
CALC .PRO 4K ; Prolog demo program: Calculator
|
||||
CC .SUB 2K ; compile an SPL source which is on the underlying
|
||||
file system
|
||||
DECLARAT. 12K ; common include file, SPL source
|
||||
DIF .COM 4K
|
||||
DIF .SPL 10K ; SPL source for DIF.COM
|
||||
EDIT .SPL 10K ; screen editor for PROLOGZ, SPL source
|
||||
FAMILY .PRO 4K ; Prolog demo program: Family relations
|
||||
INTEGER .PRO 2K ; Prolog demo program: Integer arithmetic
|
||||
KNAKE .PRO 2K ; Prolog demo program: Logic puzzle
|
||||
LINKMT .COM 12K ; Pascal MT+ 5.5 linker
|
||||
MAIN .SPL 14K ; main module for PROLOGZ, SPL source
|
||||
MOVE .MAC 4K ; helper functions for PROLOGZ in assembler
|
||||
MTERRS .TXT 6K ; Pascal MT+ error messages
|
||||
MTPLUS .000 14K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .001 12K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .002 8K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .003 8K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .004 18K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .005 8K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .006 6K ; Pascal MT+ 5.5 compiler file
|
||||
MTPLUS .COM 36K ; Pascal MT+ 5.5 compiler
|
||||
PASCFORM.COM 36K ; Pascal formatter
|
||||
PASCFORM.PAS 54K ; Pascal formatter source code
|
||||
PASCFORM.SUB 2K ; create Pascal formatter
|
||||
PASLIB .ERL 24K ; Pascal MT+ 5.5 run time library
|
||||
PINST .COM 4K ; terminal installation program for PROLOGZ
|
||||
PINST .SPL 16K ; terminal installation program for PROLOGZ,
|
||||
SPL source
|
||||
PROLOGZ .COM 18K ; PROLOGZ interpreter and screen editor
|
||||
PROLOGZ .SPL 2K ; PROLOGZ main program, SPL source
|
||||
PROLOGZ .TXT 40K ; PROLOGZ documentation in German
|
||||
PROVE .SPL 16K ; backtrack theorem prover for PROLOGZ, SPL source
|
||||
PZCLEAN .SUB 2K ; PROLOGZ: remove all created ".rel" and ".lst" files
|
||||
PZLINK .SUB 2K ; PROLOGZ: create PINST, PROLOGZ and personalise the
|
||||
serial number
|
||||
PZMAKE .SUB 2K ; PROLOGZ: compiles the sources (you can ignore
|
||||
any compiler errors)
|
||||
QUEEN .PRO 2K ; Prolog demo program: N-queens problem
|
||||
READ .COM 4K
|
||||
READ .SPL 10K ; SPL source for R.COM
|
||||
SHOWSEC .COM 4K
|
||||
SHOWSEC .SPL 6K ; SPL source for SHOWSEC.COM
|
||||
SPEED .COM 2K ; utility to measure the clock speed of the simulated CPU
|
||||
SPEED .SPL 2K ; SPL source for SPEED.COM, requires SWLIB.MAC
|
||||
SPL .COM 38K ; the SPL compiler itself
|
||||
SPL .TXT 56K ; SPL language and compiler documentation in German
|
||||
SPLERROR.DAT 12K ; error messages of the compiler (in German)
|
||||
SPLIB .REL 6K ; SPL runtime library
|
||||
STDIO . 2K ; include file for SPL programs
|
||||
SWLIB .MAC 2K ; assembler utility routines needed by SPEED.SPL
|
||||
SYSCOPY .COM 2K
|
||||
SYSCOPY .SPL 6K ; SPL source for SYSCOPY.COM
|
||||
TERMBDOS.SPL 2K ; terminal interface to CP/M for PROLOGZ, SPL source
|
||||
UTIL .SPL 18K ; utility functions for PROLOGZ, SPL source
|
||||
WRITE .COM 4K
|
||||
WRITE .SPL 8K ; SPL source for W.COM
|
||||
XFORMAT .COM 2K
|
||||
XFORMAT .SPL 6K ; SPL source for XFORMAT.COM
|
||||
|
||||
|
||||
3.5 MITS Disk Extended BASIC Version 4.1
|
||||
|
||||
This was the commonly used software for serious users of the Altair
|
||||
computer. It is a powerful (but slow) BASIC with some extended commands to
|
||||
allow it to access and manage the disk. There was no operating system it
|
||||
ran under. To boot:
|
||||
|
||||
sim> set cpu 8080 ;Z80 will not work
|
||||
sim> attach dsk mbasic.dsk
|
||||
sim> set sio upper
|
||||
sim> go ff00
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
LINEPRINTER? [C return]
|
||||
HIGHEST DISK NUMBER? [0 return] (0 here = 1 drive system)
|
||||
NUMBER OF FILES? [3 return]
|
||||
NUMBER OF RANDOM FILES? [2 return]
|
||||
|
||||
44041 BYTES FREE
|
||||
ALTAIR BASIC REV. 4.1
|
||||
[DISK EXTENDED VERSION]
|
||||
COPYRIGHT 1977 BY MITS INC.
|
||||
OK
|
||||
[MOUNT 0]
|
||||
OK
|
||||
[FILES]
|
||||
|
||||
|
||||
3.6 Altair DOS Version 1.0
|
||||
|
||||
This was long promised but not delivered until it was almost irrelevant.
|
||||
A short attempted tour will reveal it to be a dog, far inferior to CP/M. To
|
||||
boot:
|
||||
|
||||
sim> d tracks[0-7] 77 ;set to Altair settings
|
||||
sim> set cpu altairrom
|
||||
sim> attach dsk altdos.dsk
|
||||
sim> set sio upper
|
||||
sim> go ff00
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
INTERRUPTS? N [return]
|
||||
HIGHEST DISK NUMBER? [0 return] (3 here = 4 drive system)
|
||||
HOW MANY DISK FILES? [3 return]
|
||||
HOW MANY RANDOM FILES? [2 return]
|
||||
|
||||
056449 BYTES AVAILABLE
|
||||
DOS MONITOR VER 1.0
|
||||
COPYRIGHT 1977 BY MITS INC
|
||||
.[MNT 0]
|
||||
|
||||
.[DIR 0]
|
||||
|
||||
|
||||
3.7 Altair Basic 3.2 (4k)
|
||||
|
||||
In order to run the famous 4k Basic, use the following commands (the
|
||||
trick is to get the Switch Register right).
|
||||
|
||||
sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU
|
||||
sim> set sio upper ;4k Basic does not like lower case letters as input
|
||||
sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits
|
||||
sim> d sr 8 ;good setting for the Switch Register
|
||||
sim> load 4kbas.bin 0 ;load it at 0
|
||||
sim> go 0 ;and start it
|
||||
MEMORY SIZE? [return]
|
||||
TERMINAL WIDTH? [return]
|
||||
WANT SIN? [Y]
|
||||
|
||||
61911 BYTES FREE
|
||||
|
||||
BASIC VERSION 3.2
|
||||
[4K VERSION]
|
||||
|
||||
OK
|
||||
|
||||
|
||||
3.8 Altair 8k Basic
|
||||
Running 8k Basic follows the procedure for 4k Basic.
|
||||
|
||||
sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU
|
||||
sim> set sio upper ;8k Basic does not like lower case letters as input
|
||||
sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits
|
||||
sim> d sr 8 ;good setting for the Switch Register
|
||||
sim> load 8kbas.bin 0 ;load it at 0
|
||||
sim> go 0 ;and start it
|
||||
MEMORY SIZE? [A]
|
||||
|
||||
WRITTEN FOR ROYALTIES BY MICRO-SOFT
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
TERMINAL WIDTH? [return]
|
||||
WANT SIN-COS-TAN-ATN? [Y]
|
||||
|
||||
58756 BYTES FREE
|
||||
ALTAIR BASIC REV. 4.0
|
||||
[EIGHT-K VERSION]
|
||||
COPYRIGHT 1976 BY MITS INC.
|
||||
OK
|
||||
|
||||
|
||||
3.9 Altair Basic 4.0
|
||||
|
||||
Execute the following commands to run Altair Extended Basic:
|
||||
|
||||
sim> set sio upper ;Extended Basic does not like lower case letters as input
|
||||
sim> set sio ansi ;Extended Basic produces 8-bit output, strip to seven bits
|
||||
sim> d sr 8 ;good setting for the Switch Register
|
||||
sim> load exbas.bin 0 ;load it at 0
|
||||
sim> go 0 ;and start it
|
||||
16384 Bytes loaded at 0.
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
WANT SIN-COS-TAN-ATN? [Y]
|
||||
|
||||
50606 BYTES FREE
|
||||
ALTAIR BASIC REV. 4.0
|
||||
[EXTENDED VERSION]
|
||||
COPYRIGHT 1977 BY MITS INC.
|
||||
OK
|
||||
|
||||
|
||||
3.10 Altair Disk Extended Basic Version 300-5-C
|
||||
|
||||
This version of Basic was provided by Scott LaBombard. To execute use the
|
||||
following commands:
|
||||
|
||||
sim> d tracks[0-7] 77 ;set to Altair settings
|
||||
sim> at dsk extbas5.dsk
|
||||
sim> g 0
|
||||
|
||||
MEMORY SIZE? [return]
|
||||
LINEPRINTER? [C]
|
||||
HIGHEST DISK NUMBER? [0]
|
||||
HOW MANY FILES? [3]
|
||||
HOW MANY RANDOM FILES? [3]
|
||||
|
||||
42082 BYTES FREE
|
||||
|
||||
ALTAIR DISK EXTENDED BASIC
|
||||
VERSION 300-5-C [01NOV78]
|
||||
COPYRIGHT 1978 BY MITS INC.
|
||||
|
||||
OK
|
||||
|
||||
|
||||
4. Special simulator features
|
||||
|
||||
In addition to the regular SIMH features such as PC queue, breakpoints
|
||||
etc., this simulator supports memory access breakpoints. A memory access
|
||||
breakpoint is triggered when a pre-defined memory location is accessed
|
||||
(read, write or update). To set a memory location breakpoint enter
|
||||
|
||||
sim> break -m <location>
|
||||
|
||||
Execution will stop whenever an operation accesses <location>. Note that
|
||||
a memory access breakpoint is not triggered by fetching code from memory
|
||||
(this is the job of regular breakpoints). This feature has been implemented
|
||||
by using the typing facility of the SIMH breakpoints.
|
||||
|
||||
|
||||
5. Brief summary of all major changes to the original Altair simulator
|
||||
- Full support for Z80. CP/M software requiring a Z80 CPU now runs
|
||||
properly. DDTZ and PROLOGZ are included for demonstration purposes.
|
||||
- Added banked memory support.
|
||||
- PC queue implemented.
|
||||
- Full assembler and dis-assembler support for Z80 and 8080 mnemonics.
|
||||
Depending on the current setting of the CPU, the appropriate mnemonics
|
||||
are used.
|
||||
- The BOOT ROM was changed to fully load the software from disk. The
|
||||
original code basically loaded a copy of itself from the disk and
|
||||
executed it.
|
||||
- ROM and memory size settings are now fully honored. This means that you
|
||||
cannot write into the ROM or outside the defined RAM (e.g. when the RAM size
|
||||
was truncated with the SET CPU commands). This feature allows programs which
|
||||
check for the size of available RAM to run properly (e.g. 4k Basic). In
|
||||
addition one can enable and disable the ROM which is useful in special cases
|
||||
(e.g. when testing a new version of the ROM).
|
||||
- The console can also be used via Telnet. This is useful when a terminal is
|
||||
needed which supports cursor control such as a VT100. PROLOGZ for example
|
||||
has a built-in screen editor which works under Telnet.
|
||||
- Simplified file exchange for CP/M. Using the READ program under CP/M one
|
||||
can easily import files into CP/M from the regular file system. Note that PIP
|
||||
does not work properly on non-text files on PTR.
|
||||
- The WRITE program can be used to transfer files from the CP/M environment to
|
||||
the regular environment (binary or ASCII transfer).
|
||||
- The last character read from PTR is always Control-Z (the EOF character for
|
||||
CP/M). This makes sure that PIP (Peripheral Interchange Program on CP/M) will
|
||||
terminate properly.
|
||||
- Fixed a bug in the BIOS warm boot routine which caused CP/M to crash.
|
||||
- Modified the BIOS for CP/M to support 8 disks.
|
||||
- Added CP/M 3 banked version as sample software
|
||||
- Changed from octal to hex
|
||||
- Made the DSK and SIO device more robust (previously malicious code could
|
||||
crash the simulator)
|
||||
- Added memory access break points
|
||||
- Added periodic timer interrupts (useful for MP/M)
|
||||
- Added additional consoles (useful for MP/M)
|
||||
- Added MP/M II banked version as sample software
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +0,0 @@
|
||||
/* altairz80_defs.h: MITS Altair simulator definitions
|
||||
|
||||
Copyright (c) 2002-2003, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
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.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
*/
|
||||
|
||||
#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 addres of ROM */
|
||||
#define defaultROMHigh 0xffff /* default for highest addres 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 UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on nvalid 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()
|
||||
|
||||
/* The Default is to use "inline". In this case the wrapper functions for
|
||||
GetBYTE and PutBYTE need to be created. Otherwise they are not needed
|
||||
and the calls map to the original functions. */
|
||||
#ifdef NO_INLINE
|
||||
#define INLINE
|
||||
#define GetBYTEWrapper GetBYTE
|
||||
#define PutBYTEWrapper PutBYTE
|
||||
#else
|
||||
#if defined(__DECC) && defined(VMS)
|
||||
#define INLINE __inline
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,569 +0,0 @@
|
||||
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
|
||||
|
||||
Copyright (c) 2002-2003, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
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.
|
||||
|
||||
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 controller is interfaced to the CPU by use of 3 I/O addreses,
|
||||
standardly, these are device numbers 10, 11, and 12 (octal).
|
||||
|
||||
Address Mode Function
|
||||
------- ---- --------
|
||||
|
||||
10 Out Selects and enables Controller and Drive
|
||||
10 In Indicates status of Drive and Controller
|
||||
11 Out Controls Disk Function
|
||||
11 In Indicates current sector position of disk
|
||||
12 Out Write data
|
||||
12 In Read data
|
||||
|
||||
Drive Select Out (Device 10 OUT):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| C | X | X | X | Device |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
C = If this bit is 1, the disk controller selected by 'device' is
|
||||
cleared. If the bit is zero, 'device' is selected as the
|
||||
device being controlled by subsequent I/O operations.
|
||||
X = not used
|
||||
Device = value zero thru 15, selects drive to be controlled.
|
||||
|
||||
Drive Status In (Device 10 IN):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| R | Z | I | X | X | H | M | W |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
W - When 0, write circuit ready to write another byte.
|
||||
M - When 0, head movement is allowed
|
||||
H - When 0, indicates head is loaded for read/write
|
||||
X - not used (will be 0)
|
||||
I - When 0, indicates interrupts enabled (not used 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):
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 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.
|
||||
|
||||
Sector Position (Device 11 IN):
|
||||
|
||||
As the sectors pass by the read head, they are counted and the
|
||||
number of the current one is available in this register.
|
||||
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| X | X | Sector Number | T |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
X = Not used
|
||||
Sector number = binary of the sector number currently under the
|
||||
head, 0-31.
|
||||
T = Sector True, is a 1 when the sector is positioned to read or
|
||||
write.
|
||||
|
||||
*/
|
||||
|
||||
#include "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)
|
||||
|
||||
int32 dsk10(const int32 port, const int32 io, const int32 data);
|
||||
int32 dsk11(const int32 port, const int32 io, const int32 data);
|
||||
int32 dsk12(const int32 port, const int32 io, const int32 data);
|
||||
static int32 dskseek(const UNIT *xptr);
|
||||
static t_stat dsk_boot(int32 unitno, DEVICE *dptr);
|
||||
static t_stat dsk_reset(DEVICE *dptr);
|
||||
static t_stat dsk_svc(UNIT *uptr);
|
||||
static void writebuf(void);
|
||||
static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc);
|
||||
static void resetDSKWarningFlags(void);
|
||||
static int32 hasVerbose(void);
|
||||
static char* selectInOut(const int32 io);
|
||||
|
||||
extern int32 PCX;
|
||||
extern int32 saved_PC;
|
||||
extern FILE *sim_log;
|
||||
extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
extern void printMessage(void);
|
||||
extern char messageBuffer[];
|
||||
extern int32 install_bootrom(void);
|
||||
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 */
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
/* 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) } };
|
||||
|
||||
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 } };
|
||||
|
||||
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 } };
|
||||
|
||||
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, 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;
|
||||
}
|
||||
|
||||
static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||
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;
|
||||
}
|
||||
|
||||
static char* selectInOut(const int32 io) {
|
||||
return io == 0 ? "IN" : "OUT";
|
||||
}
|
||||
|
||||
/* service routines to handle simulator functions */
|
||||
|
||||
/* service routine - actually gets char & places in buffer */
|
||||
|
||||
static t_stat dsk_svc(UNIT *uptr) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* I/O instruction handlers, called from the CPU module when an
|
||||
IN or OUT instruction is issued.
|
||||
|
||||
Each function is passed an 'io' flag, where 0 means a read from
|
||||
the port, and 1 means a write to the port. On input, the actual
|
||||
input is passed as the return value, on output, 'data' is written
|
||||
to the device.
|
||||
*/
|
||||
|
||||
/* Disk Controller Status/Select */
|
||||
|
||||
/* IMPORTANT: The status flags read by port 8 IN instruction are
|
||||
INVERTED, that is, 0 is true and 1 is false. To handle this, the
|
||||
simulator keeps it's own status flags as 0=false, 1=true; and
|
||||
returns the COMPLEMENT of the status flags when read. This makes
|
||||
setting/testing of the flag bits more logical, yet meets the
|
||||
simulation requirement that they are reversed in hardware.
|
||||
*/
|
||||
|
||||
int32 dsk10(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.\n");
|
||||
}
|
||||
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\n", 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.\n", 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 */
|
||||
}
|
||||
|
||||
/* 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.\n", 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.\n", current_disk);
|
||||
}
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message1("IN 0x09\n");
|
||||
}
|
||||
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 */
|
||||
|
||||
if (trace_flag & TRACE_IN_OUT) {
|
||||
message2("OUT 0x09: %x\n", 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\n", 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\n", 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 (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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
int32 dsk12(const int32 port, const int32 io, const int32 data) {
|
||||
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.\n", 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\n", 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\n", current_disk, current_track[current_disk], current_sector[current_disk]);
|
||||
}
|
||||
if (dskseek(uptr)) {
|
||||
message4("fseek failed D%d T%d S%d\n", 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\n", 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.\n", 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
@@ -1,782 +0,0 @@
|
||||
/* altairz80_sys.c: MITS Altair system interface
|
||||
|
||||
Copyright (c) 2002-2003, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
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.
|
||||
|
||||
Based on work by Charles E Owen (c) 1997
|
||||
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE dsk_dev;
|
||||
extern DEVICE hdsk_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern DEVICE sio_dev;
|
||||
extern DEVICE simh_device;
|
||||
extern DEVICE ptr_dev;
|
||||
extern DEVICE ptp_dev;
|
||||
extern int32 saved_PC;
|
||||
extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
extern void PutBYTEForced(register uint32 Addr, register uint32 Value);
|
||||
extern uint8 GetBYTEWrapper(register uint32 Addr);
|
||||
extern int32 addressIsInROM(const uint32 Addr);
|
||||
extern int32 addressExists(const uint32 Addr);
|
||||
extern void printROMMessage(const uint32 cntROM);
|
||||
|
||||
int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag);
|
||||
int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw);
|
||||
static int32 checkbase(char ch, const char *numString);
|
||||
static int32 numok(char ch, const char **numString, const int32 minvalue,
|
||||
const int32 maxvalue, const int32 requireSign, int32 *result);
|
||||
static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, int32 *at,
|
||||
int32 *hat, int32 *dollar);
|
||||
static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]);
|
||||
int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw);
|
||||
static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr);
|
||||
static int32 checkXY(const char xy);
|
||||
|
||||
/* SCP data structures
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words needed for examine
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "Altair 8800 (Z80)";
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
int32 sim_emax = 4;
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL };
|
||||
|
||||
char memoryAccessMessage[80];
|
||||
const char *sim_stop_messages[] = {
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
memoryAccessMessage,
|
||||
"Invalid Opcode" };
|
||||
|
||||
static char *const Mnemonics8080[] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */
|
||||
"DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */
|
||||
"DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */
|
||||
"DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */
|
||||
"DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */
|
||||
"DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */
|
||||
"DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */
|
||||
"DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */
|
||||
"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */
|
||||
"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */
|
||||
"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */
|
||||
"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */
|
||||
"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */
|
||||
"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */
|
||||
"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */
|
||||
"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */
|
||||
"ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */
|
||||
"ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */
|
||||
"SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */
|
||||
"ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */
|
||||
"XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */
|
||||
"ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */
|
||||
"CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */
|
||||
"RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */
|
||||
"RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */
|
||||
"RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */
|
||||
"RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */
|
||||
"RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */
|
||||
"RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */
|
||||
"RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */
|
||||
"RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */
|
||||
};
|
||||
|
||||
static char *const MnemonicsZ80[256] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */
|
||||
"EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */
|
||||
"DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */
|
||||
"JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */
|
||||
"JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */
|
||||
"JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */
|
||||
"JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */
|
||||
"JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */
|
||||
"LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */
|
||||
"LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */
|
||||
"LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */
|
||||
"LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */
|
||||
"LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */
|
||||
"LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */
|
||||
"LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */
|
||||
"LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */
|
||||
"ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */
|
||||
"ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */
|
||||
"SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */
|
||||
"AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */
|
||||
"XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */
|
||||
"OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */
|
||||
"CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */
|
||||
"RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */
|
||||
"RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */
|
||||
"RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */
|
||||
"RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */
|
||||
"RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */
|
||||
"RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */
|
||||
"RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */
|
||||
"RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */
|
||||
};
|
||||
|
||||
static char *const MnemonicsCB[256] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */
|
||||
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */
|
||||
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */
|
||||
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */
|
||||
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */
|
||||
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */
|
||||
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */
|
||||
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */
|
||||
"BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */
|
||||
"BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */
|
||||
"BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */
|
||||
"BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */
|
||||
"BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */
|
||||
"BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */
|
||||
"BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */
|
||||
"BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */
|
||||
"RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */
|
||||
"RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */
|
||||
"RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */
|
||||
"RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */
|
||||
"RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */
|
||||
"RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */
|
||||
"RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */
|
||||
"RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */
|
||||
"SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */
|
||||
"SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */
|
||||
"SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */
|
||||
"SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */
|
||||
"SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */
|
||||
"SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */
|
||||
"SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */
|
||||
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */
|
||||
};
|
||||
|
||||
static char *const MnemonicsED[256] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */
|
||||
"DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */
|
||||
"DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */
|
||||
"DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */
|
||||
"DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */
|
||||
"DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */
|
||||
"DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */
|
||||
"DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */
|
||||
"IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */
|
||||
"IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */
|
||||
"IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */
|
||||
"IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */
|
||||
"IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */
|
||||
"IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */
|
||||
"IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */
|
||||
"IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */
|
||||
"DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */
|
||||
"DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */
|
||||
"DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */
|
||||
"DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */
|
||||
"LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */
|
||||
"LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */
|
||||
"LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */
|
||||
"LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */
|
||||
"DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */
|
||||
"DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */
|
||||
"DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */
|
||||
"DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */
|
||||
"DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */
|
||||
"DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */
|
||||
"DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */
|
||||
"DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */
|
||||
};
|
||||
|
||||
static char *const MnemonicsXX[256] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */
|
||||
"EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */
|
||||
"DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */
|
||||
"JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */
|
||||
"JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */
|
||||
"JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */
|
||||
"JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", /* 30-37 */
|
||||
"JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */
|
||||
"LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */
|
||||
"LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */
|
||||
"LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */
|
||||
"LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */
|
||||
"LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */
|
||||
"LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */
|
||||
"LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */
|
||||
"LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */
|
||||
"ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)", "ADD A,A", /* 80-87 */
|
||||
"ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)", "ADC A,A", /* 88-8f */
|
||||
"SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */
|
||||
"SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)", "SBC A,A", /* 98-9f */
|
||||
"AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */
|
||||
"XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */
|
||||
"OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */
|
||||
"CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */
|
||||
"RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */
|
||||
"RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */
|
||||
"RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */
|
||||
"RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */
|
||||
"RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */
|
||||
"RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */
|
||||
"RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */
|
||||
"RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */
|
||||
};
|
||||
|
||||
static char *const MnemonicsXCB[256] = {
|
||||
/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */
|
||||
"RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */
|
||||
"RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */
|
||||
"RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */
|
||||
"RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */
|
||||
"SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */
|
||||
"SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */
|
||||
"SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */
|
||||
"SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */
|
||||
"BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */
|
||||
"BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */
|
||||
"BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */
|
||||
"BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */
|
||||
"BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */
|
||||
"BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */
|
||||
"BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */
|
||||
"BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */
|
||||
"RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */
|
||||
"RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */
|
||||
"RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */
|
||||
"RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */
|
||||
"RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */
|
||||
"RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */
|
||||
"RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */
|
||||
"RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */
|
||||
"SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */
|
||||
"SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */
|
||||
"SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */
|
||||
"SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */
|
||||
"SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */
|
||||
"SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */
|
||||
"SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */
|
||||
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */
|
||||
};
|
||||
|
||||
/* symbolic disassembler
|
||||
|
||||
Inputs:
|
||||
*val = instructions to disassemble
|
||||
useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used
|
||||
addr = current PC
|
||||
Outputs:
|
||||
*S = output text
|
||||
|
||||
DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997
|
||||
You are not allowed to distribute this software
|
||||
commercially.
|
||||
|
||||
*/
|
||||
|
||||
static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) {
|
||||
char R[128], H[10], C = '\0', *T, *P;
|
||||
uint8 J = 0, Offset = 0;
|
||||
uint16 B = 0;
|
||||
|
||||
if (useZ80Mnemonics) {
|
||||
switch(val[B]) {
|
||||
case 0xcb:
|
||||
B++;
|
||||
T = MnemonicsCB[val[B++]];
|
||||
break;
|
||||
case 0xed:
|
||||
B++;
|
||||
T = MnemonicsED[val[B++]];
|
||||
break;
|
||||
case 0xdd:
|
||||
case 0xfd:
|
||||
C = (val[B++] == 0xdd) ? 'X' : 'Y';
|
||||
if (val[B] == 0xcb) {
|
||||
B++;
|
||||
Offset = val[B++];
|
||||
J = 1;
|
||||
T = MnemonicsXCB[val[B++]];
|
||||
}
|
||||
else {
|
||||
T = MnemonicsXX[val[B++]];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
T = MnemonicsZ80[val[B++]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
T = Mnemonics8080[val[B++]];
|
||||
}
|
||||
|
||||
if (P = strchr(T, '^')) {
|
||||
strncpy(R, T, P - T);
|
||||
R[P - T] = '\0';
|
||||
sprintf(H, "%02X", val[B++]);
|
||||
strcat(R, H);
|
||||
strcat(R, P + 1);
|
||||
}
|
||||
else {
|
||||
strcpy(R, T);
|
||||
}
|
||||
if (P = strchr(R, '%')) {
|
||||
*P = C;
|
||||
if (P = strchr(P + 1, '%')) {
|
||||
*P = C;
|
||||
}
|
||||
}
|
||||
|
||||
if(P = strchr(R, '*')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
sprintf(H, "%02X", val[B++]);
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
}
|
||||
else if (P = strchr(R, '@')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
if(!J) {
|
||||
Offset = val[B++];
|
||||
}
|
||||
strcat(S, Offset & 0x80 ? "-" : "+");
|
||||
J = Offset & 0x80 ? 256 - Offset : Offset;
|
||||
sprintf(H, "%02X", J);
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
}
|
||||
else if (P = strchr(R, '$')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
Offset = val[B++];
|
||||
sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset));
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
}
|
||||
else if (P = strchr(R, '#')) {
|
||||
strncpy(S, R, P - R);
|
||||
S[P - R] = '\0';
|
||||
sprintf(H, "%04X", val[B] + 256 * val[B + 1]);
|
||||
strcat(S, H);
|
||||
strcat(S, P + 1);
|
||||
B += 2;
|
||||
}
|
||||
else {
|
||||
strcpy(S, R);
|
||||
}
|
||||
return(B);
|
||||
}
|
||||
|
||||
/* symbolic output
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to values
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error code
|
||||
*/
|
||||
|
||||
int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) {
|
||||
char disasm[128];
|
||||
int32 ch = val[0] & 0x7f;
|
||||
if (sw & (SWMASK('A') | SWMASK('C'))) {
|
||||
fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch);
|
||||
return SCPE_OK;
|
||||
}
|
||||
if (!(sw & SWMASK('M'))) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr);
|
||||
fprintf(of, "%s", disasm);
|
||||
return 1 - ch; /* need to return additional bytes */
|
||||
}
|
||||
|
||||
/* numString checks determines the base of the number (ch, *numString)
|
||||
and returns FALSE if the number is bad */
|
||||
static int32 checkbase(char ch, const char *numString) {
|
||||
int32 decimal = (ch <= '9');
|
||||
if (toupper(ch) == 'H') {
|
||||
return FALSE;
|
||||
}
|
||||
while (isxdigit(ch = *numString++)) {
|
||||
if (ch > '9') {
|
||||
decimal = FALSE;
|
||||
}
|
||||
}
|
||||
return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE);
|
||||
}
|
||||
|
||||
static int32 numok(char ch, const char **numString, const int32 minvalue,
|
||||
const int32 maxvalue, const int32 requireSign, int32 *result) {
|
||||
int32 sign = 1, value = 0, base;
|
||||
if (requireSign) {
|
||||
if (ch == '+') {
|
||||
ch = *(*numString)++;
|
||||
}
|
||||
else if (ch == '-') {
|
||||
sign = -1;
|
||||
ch = *(*numString)++;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (!(base = checkbase(ch, *numString))) {
|
||||
return FALSE;
|
||||
}
|
||||
while (isxdigit(ch)) {
|
||||
value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10));
|
||||
ch = *(*numString)++;
|
||||
}
|
||||
if (toupper(ch) != 'H') {
|
||||
(*numString)--;
|
||||
}
|
||||
*result = value * sign;
|
||||
return (minvalue <= value) && (value <= maxvalue);
|
||||
}
|
||||
|
||||
static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star,
|
||||
int32 *at, int32 *hat, int32 *dollar) {
|
||||
char pat = *pattern++;
|
||||
char inp = *input++;
|
||||
while ((pat) && (inp)) {
|
||||
switch(pat) {
|
||||
case '_': /* patterns containting '_' should never match */
|
||||
return FALSE;
|
||||
case ',':
|
||||
if (inp == ' ') {
|
||||
inp = *input++;
|
||||
continue;
|
||||
} /* otherwise fall through */
|
||||
case ' ':
|
||||
if (inp != pat) {
|
||||
return FALSE;
|
||||
}
|
||||
pat = *pattern++;
|
||||
inp = *input++;
|
||||
while (inp == ' ') {
|
||||
inp = *input++;
|
||||
}
|
||||
continue;
|
||||
case '%':
|
||||
inp = toupper(inp);
|
||||
if ((inp == 'X') || (inp == 'Y')) {
|
||||
if (*xyFirst) { /* make sure that second '%' corresponds to first */
|
||||
if (*xyFirst == inp) {
|
||||
*xy = inp;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else { /* take note of first '%' for later */
|
||||
*xyFirst = inp;
|
||||
*xy = inp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
if (numok(inp, &input, 0, 65535, FALSE, number)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
if (numok(inp, &input, 0, 255, FALSE, star)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (numok(inp, &input, -128, 65535, TRUE, at)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '$':
|
||||
if (numok(inp, &input, 0, 65535, FALSE, dollar)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case '^':
|
||||
if (numok(inp, &input, 0, 255, FALSE, hat)) {
|
||||
pattern++; /* skip h */
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (toupper(pat) != toupper(inp)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
pat = *pattern++;
|
||||
inp = *input++;
|
||||
}
|
||||
while (inp == ' ') {
|
||||
inp = *input++;
|
||||
}
|
||||
return (pat == 0) && (inp == 0);
|
||||
}
|
||||
|
||||
static INLINE int32 checkXY(const char xy) {
|
||||
return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */
|
||||
}
|
||||
|
||||
static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) {
|
||||
char xyFirst = 0, xy;
|
||||
int32 op, number, star, at, hat, dollar;
|
||||
for (op = 0; op < 256; op++) {
|
||||
number = star = at = dollar = -129;
|
||||
if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) {
|
||||
val[0] = op;
|
||||
if (number >= 0) {
|
||||
val[1] = (0xff) & number;
|
||||
val[2] = (0xff) & (number >> 8);
|
||||
return -2; /* two additional bytes returned */
|
||||
}
|
||||
else if (star >= 0) {
|
||||
val[1] = (0xff) & star;
|
||||
return -1; /* one additional byte returned */
|
||||
}
|
||||
else if (at > -129) {
|
||||
if ((-128 <= at) && (at <= 127)) {
|
||||
val[1] = (int8)(at);
|
||||
return -1; /* one additional byte returned */
|
||||
}
|
||||
else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
}
|
||||
else if (dollar >= 0) {
|
||||
dollar -= addr + 2; /* relative translation */
|
||||
if ((-128 <= dollar) && (dollar <= 127)) {
|
||||
val[1] = (int8)(dollar);
|
||||
return -1; /* one additional byte returned */
|
||||
}
|
||||
else {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return SCPE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Mnemonics == Mnemonics8080) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
if (match(MnemonicsCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) {
|
||||
val[0] = 0xcb;
|
||||
val[1] = op;
|
||||
return -1; /* one additional byte returned */
|
||||
}
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
number = -1;
|
||||
if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) {
|
||||
val[0] = 0xed;
|
||||
val[1] = op;
|
||||
if (number >= 0) {
|
||||
val[2] = (0xff) & number;
|
||||
val[3] = (0xff) & (number >> 8);
|
||||
return -3; /* three additional bytes returned */
|
||||
}
|
||||
else {
|
||||
return -1; /* one additional byte returned */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
number = star = hat = -1;
|
||||
xy = 0;
|
||||
if (match(MnemonicsXX[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) {
|
||||
/* all matches must have contained a '%' character */
|
||||
if (!(val[0] = checkXY(xy))) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
val[1] = op;
|
||||
if (number >= 0) {
|
||||
val[2] = (0xff) & number;
|
||||
val[3] = (0xff) & (number >> 8);
|
||||
return -3; /* three additional bytes returned */
|
||||
}
|
||||
else if ((star >= 0) && (hat >= 0)) {
|
||||
val[2] = (0xff) & hat;
|
||||
val[3] = (0xff) & star;
|
||||
return -3; /* three additional bytes returned */
|
||||
}
|
||||
else if (star >= 0) {
|
||||
val[2] = (0xff) & star;
|
||||
return -2; /* two additional bytes returned */
|
||||
}
|
||||
else if (hat >= 0) {
|
||||
val[2] = (0xff) & hat;
|
||||
return -2; /* two additional bytes returned */
|
||||
}
|
||||
else {
|
||||
return -1; /* one additional byte returned */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (op = 0; op < 256; op++) {
|
||||
at = -129;
|
||||
xy = 0;
|
||||
if (match(MnemonicsXCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) {
|
||||
/* all matches must have contained a '%' character */
|
||||
if (!(val[0] = checkXY(xy))) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
val[1] = 0xcb;
|
||||
if (at > -129) {
|
||||
val[2] = (int8) (at);
|
||||
}
|
||||
else {
|
||||
printf("Offset expected.\n");
|
||||
return SCPE_ARG;
|
||||
}
|
||||
val[3] = op;
|
||||
return -3; /* three additional bytes returned */
|
||||
}
|
||||
}
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
|
||||
/* symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) {
|
||||
while (isspace(*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) {
|
||||
return SCPE_ARG; /* must have one char */
|
||||
}
|
||||
val[0] = (uint32) cptr[0];
|
||||
return SCPE_OK;
|
||||
}
|
||||
return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080);
|
||||
}
|
||||
|
||||
|
||||
/* This is the binary loader. The input file is considered to be
|
||||
a string of literal bytes with no format special format. The
|
||||
load starts at the current value of the PC. ROM/NOROM and
|
||||
ALTAIRROM/NOALTAIRROM settings are ignored.
|
||||
*/
|
||||
|
||||
int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) {
|
||||
int32 i, addr = 0, cnt = 0, org, cntROM = 0, cntNonExist = 0;
|
||||
t_addr j, lo, hi;
|
||||
char *result;
|
||||
t_stat status;
|
||||
if (flag) {
|
||||
result = get_range(cptr, &lo, &hi, 16, ADDRMASK, 0);
|
||||
if (result == NULL) {
|
||||
return SCPE_ARG;
|
||||
}
|
||||
for (j = lo; j <= hi; j++) {
|
||||
if (putc(GetBYTEWrapper(j), fileref) == EOF) {
|
||||
return SCPE_IOERR;
|
||||
}
|
||||
}
|
||||
printf("%d bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi);
|
||||
}
|
||||
else {
|
||||
if (*cptr == 0) {
|
||||
addr = saved_PC;
|
||||
}
|
||||
else {
|
||||
addr = get_uint(cptr, 16, ADDRMASK, &status);
|
||||
if (status != SCPE_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
org = addr;
|
||||
while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) {
|
||||
PutBYTEForced(addr, i);
|
||||
if (addressIsInROM(addr)) {
|
||||
cntROM++;
|
||||
}
|
||||
if (!addressExists(addr)) {
|
||||
cntNonExist++;
|
||||
}
|
||||
addr++;
|
||||
cnt++;
|
||||
} /* end while */
|
||||
printf("%d bytes [%d page%s] loaded at %x.\n", cnt, (cnt + 255) >> 8,
|
||||
((cnt + 255) >> 8) == 1 ? "" : "s", org);
|
||||
printROMMessage(cntROM);
|
||||
if (cntNonExist) {
|
||||
printf("Warning: %d bytes written to non-existing memory (for this configuration).\n", cntNonExist);
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,386 +0,0 @@
|
||||
/* altairz80_hdsk.c: simulated hard disk device to increase capacity
|
||||
|
||||
Copyright (c) 2002-2003, Peter Schorn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "altairz80_defs.h"
|
||||
|
||||
#define UNIT_V_HDSKWLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK)
|
||||
#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||
#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE)
|
||||
#define HDSK_SECTOR_SIZE 128 /* size of sector */
|
||||
#define HDSK_SECTORS_PER_TRACK 32 /* sectors per track */
|
||||
#define HDS_MAX_TRACKS 2048 /* number of tracks */
|
||||
#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK)
|
||||
#define HDSK_CAPACITY (HDSK_TRACK_SIZE * HDS_MAX_TRACKS)
|
||||
#define HDSK_NUMBER 8 /* number of hard disks */
|
||||
#define CPM_OK 0 /* indicates to CP/M everything ok */
|
||||
#define CPM_ERROR 1 /* indicates to CP/M an error condition */
|
||||
#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */
|
||||
#define hdsk_none 0
|
||||
#define hdsk_reset 1
|
||||
#define hdsk_read 2
|
||||
#define hdsk_write 3
|
||||
#define hdsk_boot_address 0x5c00
|
||||
|
||||
extern char messageBuffer[];
|
||||
extern int32 PCX;
|
||||
extern UNIT cpu_unit;
|
||||
extern uint8 M[MAXMEMSIZE][MAXBANKS];
|
||||
extern int32 saved_PC;
|
||||
|
||||
extern int32 install_bootrom(void);
|
||||
extern void printMessage(void);
|
||||
extern void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value);
|
||||
extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value);
|
||||
extern void protect(const int32 l, const int32 h);
|
||||
extern uint8 GetBYTEWrapper(register uint32 Addr);
|
||||
extern int32 bootrom[bootrom_size];
|
||||
|
||||
static t_stat hdsk_svc(UNIT *uptr);
|
||||
static t_stat hdsk_boot(int32 unitno, DEVICE *dptr);
|
||||
static int32 hdsk_hasVerbose(void);
|
||||
int32 hdsk_io(const int32 port, const int32 io, const int32 data);
|
||||
static int32 hdsk_in(const int32 port);
|
||||
static int32 hdsk_out(const int32 data);
|
||||
static int32 checkParameters(void);
|
||||
static int32 doSeek(void);
|
||||
static int32 doRead(void);
|
||||
static int32 doWrite(void);
|
||||
|
||||
static int32 hdskLastCommand = hdsk_none;
|
||||
static int32 hdskCommandPosition = 0;
|
||||
static int32 selectedDisk;
|
||||
static int32 selectedSector;
|
||||
static int32 selectedTrack;
|
||||
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) } };
|
||||
|
||||
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 } };
|
||||
|
||||
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 } };
|
||||
|
||||
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, NULL, NULL };
|
||||
|
||||
static t_stat hdsk_svc(UNIT *uptr) {
|
||||
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 */
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* The hard disk port is 0xfd. It understands the following commands.
|
||||
|
||||
1. reset
|
||||
ld b,32
|
||||
ld a,hdsk_reset
|
||||
l out (0fdh),a
|
||||
dec b
|
||||
jp nz,l
|
||||
|
||||
2. read / write
|
||||
; parameter block
|
||||
cmd: db hdsk_read or hdsk_write
|
||||
hd: db 0 ; 0 .. 7, defines hard disk to be used
|
||||
sector: db 0 ; 0 .. 31, defines sector
|
||||
track: dw 0 ; 0 .. 2047, defines track
|
||||
dma: dw 0 ; defines where result is placed in memory
|
||||
|
||||
; routine to execute
|
||||
ld b,7 ; size of parameter block
|
||||
ld hl,cmd ; start address of parameter block
|
||||
l ld a,(hl) ; get byte of parameter block
|
||||
out (0fdh),a ; send it to port
|
||||
inc hl ; point to next byte
|
||||
dec b ; decrement counter
|
||||
jp nz,l ; again, if not done
|
||||
in a,(0fdh) ; get result code
|
||||
|
||||
*/
|
||||
|
||||
/* check the parameters and return TRUE iff parameters are correct or have been repaired */
|
||||
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.\n", selectedDisk);
|
||||
}
|
||||
selectedDisk = 0;
|
||||
}
|
||||
currentFlag = (hdsk_dev.units + selectedDisk) -> flags;
|
||||
if ((currentFlag & UNIT_ATT) == 0) {
|
||||
if (currentFlag & UNIT_HDSK_VERBOSE) {
|
||||
message2("HDSK%d is not attached.\n", selectedDisk);
|
||||
}
|
||||
return FALSE; /* cannot read or write */
|
||||
}
|
||||
if ((selectedSector < 0) || (selectedSector >= HDSK_SECTORS_PER_TRACK)) {
|
||||
if (currentFlag & UNIT_HDSK_VERBOSE) {
|
||||
message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.\n",
|
||||
selectedDisk, selectedSector, HDSK_SECTORS_PER_TRACK);
|
||||
}
|
||||
selectedSector = 0;
|
||||
}
|
||||
if ((selectedTrack < 0) || (selectedTrack >= HDS_MAX_TRACKS)) {
|
||||
if (currentFlag & UNIT_HDSK_VERBOSE) {
|
||||
message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.\n",
|
||||
selectedDisk, selectedTrack, HDS_MAX_TRACKS);
|
||||
}
|
||||
selectedTrack = 0;
|
||||
}
|
||||
selectedDMA &= ADDRMASK;
|
||||
if (hdskTrace) {
|
||||
message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x\n",
|
||||
(hdskLastCommand == hdsk_read) ? "Read" : "Write",
|
||||
selectedDisk, selectedSector, selectedTrack, selectedDMA);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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.\n",
|
||||
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.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_OK; /* allows the creation of empty hard disks */
|
||||
}
|
||||
for (i = 0; i < HDSK_SECTOR_SIZE; i++) {
|
||||
PutBYTEWrapper(selectedDMA + i, hdskbuf[i]);
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
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.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((uptr -> flags) & UNIT_HDSK_VERBOSE) {
|
||||
message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.\n",
|
||||
selectedDisk, selectedSector, selectedTrack);
|
||||
}
|
||||
return CPM_ERROR;
|
||||
}
|
||||
return CPM_OK;
|
||||
}
|
||||
|
||||
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).\n",
|
||||
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 */
|
||||
}
|
||||
|
||||
int32 hdsk_io(const int32 port, const int32 io, const int32 data) {
|
||||
return io == 0 ? hdsk_in(port) : hdsk_out(data);
|
||||
}
|
||||
890
GRI/gri_cpu.c
890
GRI/gri_cpu.c
@@ -1,890 +0,0 @@
|
||||
/* gri_cpu.c: GRI-909 CPU simulator
|
||||
|
||||
Copyright (c) 2001-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
cpu GRI-909 CPU
|
||||
|
||||
14-Mar-03 RMS Fixed bug in SC queue tracking
|
||||
|
||||
The system state for the GRI-909 is:
|
||||
|
||||
AX<0:15> arithmetic input
|
||||
AY<0:15> arithmetic input
|
||||
BSW<0:15> byte swapper
|
||||
BPK<0:15> byte packer
|
||||
GR[0:5]<0:15> extended general registers
|
||||
MSR<0:15> machine status register
|
||||
TRP<0:15> trap register (subroutine return)
|
||||
SC<0:14> sequence counter
|
||||
|
||||
The GRI-909 has, nominally, just one instruction format: move.
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | op | destination | move
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
<6:9> operation
|
||||
|
||||
xx1x complement
|
||||
01xx add 1
|
||||
10xx rotate left 1
|
||||
11xx rotate right 1
|
||||
|
||||
In fact, certain of the source and destination operators have side
|
||||
effects, yielding four additional instruction formats: function out,
|
||||
skip on function, memory reference, and conditional jump.
|
||||
*/
|
||||
|
||||
/* The function out format is:
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| 0 0 0 0 1 0| pulse | destination | function out
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
The skip on function format is:
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | skip |rv| 0 0 0 0 1 0| skip function
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
The memory reference format is (src and/or dst = 006):
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | op | mode| destination | memory ref
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| address or immediate |
|
||||
+-----------------------------------------------+
|
||||
|
||||
<6:9> operation
|
||||
|
||||
xx0x direct, ea = M[SC+1]
|
||||
xx1x immediate, ea = SC+1
|
||||
xxx1 indirect, M[ea] = M[ea]+1, then ea = M[ea]
|
||||
01xx add 1
|
||||
10xx rotate left 1
|
||||
11xx rotate right 1
|
||||
|
||||
The conditional jump format is (src != 006):
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | cond|rv|df| 0 0 0 0 1 1| cond jump
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| jump address |
|
||||
+-----------------------------------------------+
|
||||
|
||||
<6:9> operation
|
||||
|
||||
xxx0 direct, ea = M[SC+1]
|
||||
xxx1 indirect, ea = M[SC+1], M[ea] = M[ea]+1,
|
||||
then ea = M[ea]
|
||||
xx1x reverse conditional sense
|
||||
x1xx jump if src == 0
|
||||
1xxx jump if src < 0
|
||||
*/
|
||||
|
||||
/* This routine is the instruction decode routine for the GRI-909.
|
||||
It is called from the simulator control program to execute
|
||||
instructions in simulated memory, starting at the simulated PC.
|
||||
It runs until 'reason' is set non-zero.
|
||||
|
||||
General notes:
|
||||
|
||||
1. Reasons to stop. The simulator can be stopped by:
|
||||
|
||||
HALT instruction
|
||||
breakpoint encountered
|
||||
unknown source or destination and STOP_OPR flag set
|
||||
I/O error in I/O simulator
|
||||
|
||||
2. Interrupts. The interrupt structure is kept in two parallel variables:
|
||||
|
||||
dev_done device done flags
|
||||
ISR interrupt status register (enables)
|
||||
|
||||
In addition, there is a master interrupt enable, and a one cycle
|
||||
interrupt defer, both kept in dev_done.
|
||||
|
||||
3. Non-existent memory. On the GRI-909, reads to non-existent memory
|
||||
return zero, and writes are ignored. In the simulator, the
|
||||
largest possible memory is instantiated and initialized to zero.
|
||||
Thus, only writes need be checked against actual memory size.
|
||||
|
||||
4. Adding I/O devices. These modules must be modified:
|
||||
|
||||
gri_defs.h add interrupt request definition
|
||||
gri_cpu.c add dev_tab table entry
|
||||
gri_sys.c add sim_devices table entry
|
||||
*/
|
||||
|
||||
#include "gri_defs.h"
|
||||
|
||||
#define SCQ_SIZE 64 /* must be 2**n */
|
||||
#define SCQ_MASK (SCQ_SIZE - 1)
|
||||
#define SCQ_ENTRY scq[scq_p = (scq_p - 1) & SCQ_MASK] = SC
|
||||
#define UNIT_V_NOEAO (UNIT_V_UF) /* EAO absent */
|
||||
#define UNIT_NOEAO (1 << UNIT_V_NOEAO)
|
||||
#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */
|
||||
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
||||
|
||||
uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
|
||||
uint32 SC; /* sequence cntr */
|
||||
uint32 AX, AY, AO; /* arithmetic unit */
|
||||
uint32 IR; /* instr reg */
|
||||
uint32 MA; /* memory addr */
|
||||
uint32 TRP; /* subr return */
|
||||
uint32 MSR; /* machine status */
|
||||
uint32 ISR; /* interrupt status */
|
||||
uint32 BSW, BPK; /* byte swap, pack */
|
||||
uint32 GR[6]; /* extended general regs */
|
||||
uint32 SWR; /* switch reg */
|
||||
uint32 DR; /* display register */
|
||||
uint32 thwh = 0; /* thumbwheel */
|
||||
uint32 dev_done = 0; /* device flags */
|
||||
uint32 bkp = 0; /* bkpt pending */
|
||||
uint32 stop_opr = 1; /* stop ill operator */
|
||||
int16 scq[SCQ_SIZE] = { 0 }; /* PC queue */
|
||||
int32 scq_p = 0; /* PC queue ptr */
|
||||
REG *scq_r = NULL; /* PC queue reg ptr */
|
||||
|
||||
extern int32 sim_interval;
|
||||
extern int32 sim_int_char;
|
||||
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
|
||||
|
||||
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_reset (DEVICE *dptr);
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat bus_op (uint32 src, uint32 op, uint32 dst);
|
||||
|
||||
/* Dispatch tables for source, dest, function out, skip on function */
|
||||
|
||||
uint32 no_rd (uint32 src);
|
||||
t_stat no_wr (uint32 dst, uint32 val);
|
||||
t_stat no_fo (uint32 op);
|
||||
uint32 no_sf (uint32 op);
|
||||
uint32 zero_rd (uint32 src);
|
||||
t_stat zero_wr (uint32 dst, uint32 val);
|
||||
t_stat zero_fo (uint32 op);
|
||||
uint32 zero_sf (uint32 op);
|
||||
uint32 ir_rd (uint32 op);
|
||||
t_stat ir_fo (uint32 op);
|
||||
uint32 trp_rd (uint32 src);
|
||||
uint32 isr_rd (uint32 src);
|
||||
t_stat isr_wr (uint32 dst, uint32 val);
|
||||
t_stat isr_fo (uint32 op);
|
||||
uint32 isr_sf (uint32 op);
|
||||
uint32 ma_rd (uint32 src);
|
||||
uint32 mem_rd (uint32 src);
|
||||
t_stat mem_wr (uint32 dst, uint32 val);
|
||||
uint32 sc_rd (uint32 src);
|
||||
t_stat sc_wr (uint32 dst, uint32 val);
|
||||
uint32 swr_rd (uint32 src);
|
||||
uint32 ax_rd (uint32 src);
|
||||
t_stat ax_wr (uint32 dst, uint32 val);
|
||||
uint32 ay_rd (uint32 src);
|
||||
t_stat ay_wr (uint32 dst, uint32 val);
|
||||
uint32 ao_rd (uint32 src);
|
||||
t_stat ao_fo (uint32 op);
|
||||
uint32 ao_sf (uint32 op);
|
||||
uint32 ao_update (void);
|
||||
t_stat eao_fo (uint32 op);
|
||||
uint32 msr_rd (uint32 src);
|
||||
t_stat msr_wr (uint32 dst, uint32 val);
|
||||
uint32 bsw_rd (uint32 src);
|
||||
t_stat bsw_wr (uint32 dst, uint32 val);
|
||||
uint32 bpk_rd (uint32 src);
|
||||
t_stat bpk_wr (uint32 dst, uint32 val);
|
||||
uint32 gr_rd (uint32 src);
|
||||
t_stat gr_wr (uint32 dst, uint32 val);
|
||||
|
||||
extern t_stat rtc_fo (uint32 op);
|
||||
extern uint32 rtc_sf (uint32 op);
|
||||
extern uint32 hsrp_rd (uint32 src);
|
||||
extern t_stat hsrp_wr (uint32 dst, uint32 val);
|
||||
extern t_stat hsrp_fo (uint32 op);
|
||||
extern uint32 hsrp_sf (uint32 op);
|
||||
extern uint32 tty_rd (uint32 src);
|
||||
extern t_stat tty_wr (uint32 dst, uint32 val);
|
||||
extern t_stat tty_fo (uint32 op);
|
||||
extern uint32 tty_sf (uint32 op);
|
||||
|
||||
struct gdev dev_tab[64] = {
|
||||
{ &zero_rd, &zero_wr, &zero_fo, &zero_sf }, /* 00: zero */
|
||||
{ &ir_rd, &zero_wr, &ir_fo, &zero_sf }, /* ir */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* fo/sf */
|
||||
{ &trp_rd, &no_wr, &zero_fo, &zero_sf }, /* trp */
|
||||
{ &isr_rd, &isr_wr, &isr_fo, &isr_sf }, /* isr */
|
||||
{ &ma_rd, &no_wr, &no_fo, &no_sf }, /* MA */
|
||||
{ &mem_rd, &mem_wr, &zero_fo, &zero_sf }, /* memory */
|
||||
{ &sc_rd, &sc_wr, &zero_fo, &zero_sf }, /* sc */
|
||||
{ &swr_rd, &no_wr, &no_fo, &no_sf }, /* swr */
|
||||
{ &ax_rd, &ax_wr, &zero_fo, &zero_sf }, /* ax */
|
||||
{ &ay_rd, &ay_wr, &zero_fo, &zero_sf }, /* ay */
|
||||
{ &ao_rd, &zero_wr, &ao_fo, &ao_sf }, /* ao */
|
||||
{ &zero_rd, &zero_wr, &eao_fo, &zero_sf }, /* eao */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &msr_rd, &msr_wr, &zero_fo, &zero_sf }, /* msr */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 20 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &bsw_rd, &bsw_wr, &no_fo, &no_sf }, /* bsw */
|
||||
{ &bpk_rd, &bpk_wr, &no_fo, &no_sf }, /* bpk */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* 30: gr1 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr2 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr3 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr4 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr5 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr6 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 40 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 50 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 60 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 70 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &zero_rd, &zero_wr, &rtc_fo, &rtc_sf }, /* rtc */
|
||||
{ &hsrp_rd, &hsrp_wr, &hsrp_fo, &hsrp_sf }, /* hsrp */
|
||||
{ &tty_rd, &tty_wr, &tty_fo, &tty_sf } }; /* tty */
|
||||
|
||||
static const int32 vec_map[16] = {
|
||||
VEC_TTO, VEC_TTI, VEC_HSP, VEC_HSR,
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, VEC_RTC,
|
||||
-1, -1, -1, -1 };
|
||||
|
||||
/* CPU data structures
|
||||
|
||||
cpu_dev CPU device descriptor
|
||||
cpu_unit CPU unit descriptor
|
||||
cpu_reg CPU register list
|
||||
cpu_mod CPU modifiers list
|
||||
*/
|
||||
|
||||
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
|
||||
|
||||
REG cpu_reg[] = {
|
||||
{ ORDATA (SC, SC, 15) },
|
||||
{ ORDATA (AX, AX, 16) },
|
||||
{ ORDATA (AY, AY, 16) },
|
||||
{ ORDATA (AO, AO, 16), REG_RO },
|
||||
{ ORDATA (TRP, TRP, 16) },
|
||||
{ ORDATA (MSR, MSR, 16) },
|
||||
{ ORDATA (ISR, ISR, 16) },
|
||||
{ ORDATA (BSW, BSW, 16) },
|
||||
{ ORDATA (BPK, BPK, 16) },
|
||||
{ ORDATA (GR1, GR[0], 16) },
|
||||
{ ORDATA (GR2, GR[1], 16) },
|
||||
{ ORDATA (GR3, GR[2], 16) },
|
||||
{ ORDATA (GR4, GR[3], 16) },
|
||||
{ ORDATA (GR5, GR[4], 16) },
|
||||
{ ORDATA (GR6, GR[5], 16) },
|
||||
{ FLDATA (BOV, MSR, MSR_V_BOV) },
|
||||
{ FLDATA (L, MSR, MSR_V_L) },
|
||||
{ GRDATA (FOA, MSR, 8, 2, MSR_V_FOA) },
|
||||
{ FLDATA (AOV, MSR, MSR_V_AOV) },
|
||||
{ ORDATA (IR, IR, 16), REG_RO },
|
||||
{ ORDATA (MA, MA, 16), REG_RO },
|
||||
{ ORDATA (SWR, SWR, 16) },
|
||||
{ ORDATA (DR, DR, 16) },
|
||||
{ ORDATA (THW, thwh, 6) },
|
||||
{ ORDATA (IREQ, dev_done, INT_V_NODEF) },
|
||||
{ FLDATA (ION, dev_done, INT_V_ON) },
|
||||
{ FLDATA (INODEF, dev_done, INT_V_NODEF) },
|
||||
{ FLDATA (BKP, bkp, 0) },
|
||||
{ BRDATA (SCQ, scq, 8, 15, SCQ_SIZE), REG_RO + REG_CIRC },
|
||||
{ ORDATA (SCQP, scq_p, 6), REG_HRO },
|
||||
{ FLDATA (STOP_OPR, stop_opr, 0) },
|
||||
{ ORDATA (WRU, sim_int_char, 8) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB cpu_mod[] = {
|
||||
{ UNIT_NOEAO, UNIT_NOEAO, "no EAO", "NOEAO", NULL },
|
||||
{ UNIT_NOEAO, 0, "EAO", "EAO", NULL },
|
||||
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE cpu_dev = {
|
||||
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
||||
1, 8, 15, 1, 8, 16,
|
||||
&cpu_ex, &cpu_dep, &cpu_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
t_stat sim_instr (void)
|
||||
{
|
||||
uint32 src, dst, op, t, jmp;
|
||||
t_stat reason;
|
||||
extern UNIT rtc_unit;
|
||||
|
||||
/* Restore register state */
|
||||
|
||||
SC = SC & AMASK; /* load local PC */
|
||||
reason = 0;
|
||||
AO = ao_update (); /* update AO */
|
||||
sim_rtc_init (rtc_unit.wait); /* init calibration */
|
||||
|
||||
/* Main instruction fetch/decode loop */
|
||||
|
||||
while (reason == 0) { /* loop until halted */
|
||||
|
||||
if (sim_interval <= 0) { /* check clock queue */
|
||||
if (reason = sim_process_event ()) break; }
|
||||
|
||||
if (bkp) { /* breakpoint? */
|
||||
bkp = 0; /* clear request */
|
||||
dev_done = dev_done & ~INT_ON; /* int off */
|
||||
M[VEC_BKP] = SC; /* save SC */
|
||||
SC = VEC_BKP + 1; } /* new SC */
|
||||
|
||||
else if ((dev_done & (INT_PENDING | ISR)) > (INT_PENDING)) { /* intr? */
|
||||
int32 i, vec;
|
||||
t = dev_done & ISR; /* find hi pri */
|
||||
for (i = 15; i >= 0; i--) {
|
||||
if ((t >> i) & 1) break; }
|
||||
if ((i < 0) || ((vec = vec_map[i]) < 0)) { /* undefined? */
|
||||
reason = STOP_ILLINT; /* stop */
|
||||
break; }
|
||||
dev_done = dev_done & ~INT_ON; /* int off */
|
||||
M[vec] = SC; /* save SC */
|
||||
SC = vec + 1; /* new SC */
|
||||
continue; }
|
||||
|
||||
if (sim_brk_summ && sim_brk_test (SC, SWMASK ('E'))) { /* breakpoint? */
|
||||
reason = STOP_IBKPT; /* stop simulation */
|
||||
break; }
|
||||
|
||||
MA = SC; /* set mem addr */
|
||||
IR = M[MA]; /* fetch instr */
|
||||
dev_done = dev_done | INT_NODEF; /* clr ion defer */
|
||||
sim_interval = sim_interval - 1;
|
||||
|
||||
/* Decode instruction types */
|
||||
|
||||
src = I_GETSRC (IR); /* src unit */
|
||||
dst = I_GETDST (IR); /* dst unit */
|
||||
op = I_GETOP (IR); /* bus op */
|
||||
|
||||
if (src == U_FSK) { /* func out? */
|
||||
reason = dev_tab[dst].FO (op); /* send function */
|
||||
SC = (SC + 1) & AMASK; } /* incr SC */
|
||||
|
||||
else if (dst == U_FSK) { /* skip func? */
|
||||
t = dev_tab[src].SF (op & ~1); /* issue SF */
|
||||
reason = t >> SF_V_REASON;
|
||||
if ((t ^ op) & 1) SC = SC + 2; /* skip? */
|
||||
SC = (SC + 1) & AMASK; } /* incr SC */
|
||||
|
||||
else if ((src != U_MEM) && (dst == U_TRP)) { /* cond jump */
|
||||
t = dev_tab[src].Src (src); /* get source */
|
||||
switch (op >> 1) { /* case on jump */
|
||||
case 00: /* never */
|
||||
jmp = 0;
|
||||
break;
|
||||
case 01: /* always */
|
||||
jmp = 1;
|
||||
break;
|
||||
case 02: /* src == 0 */
|
||||
jmp = (t == 0);
|
||||
break;
|
||||
case 03: /* src != 0 */
|
||||
jmp = (t != 0);
|
||||
break;
|
||||
case 04: /* src < 0 */
|
||||
jmp = (t >= SIGN);
|
||||
break;
|
||||
case 05: /* src >= 0 */
|
||||
jmp = (t < SIGN);
|
||||
break;
|
||||
case 06: /* src <= 0 */
|
||||
jmp = (t == 0) || (t & SIGN);
|
||||
break;
|
||||
case 07: /* src > 0 */
|
||||
jmp = (t != 0) && !(t & SIGN);
|
||||
break; }
|
||||
if (jmp) { /* jump taken? */
|
||||
SCQ_ENTRY; /* save SC */
|
||||
SC = (SC + 1) & AMASK; /* incr SC once */
|
||||
MA = M[SC]; /* get jump addr */
|
||||
if (op & TRP_DEF) { /* defer? */
|
||||
t = (M[MA] + 1) & DMASK; /* autoinc */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = t;
|
||||
MA = t & AMASK; } /* ind addr */
|
||||
TRP = SC; /* save SC */
|
||||
SC = MA; } /* load new SC */
|
||||
else SC = (SC + 2) & AMASK; } /* incr SC twice */
|
||||
|
||||
else if ((src != U_MEM) && (dst != U_MEM)) { /* reg-reg? */
|
||||
reason = bus_op (src, op, dst); /* xmt and modify */
|
||||
SC = (SC + 1) & AMASK; } /* incr SC */
|
||||
|
||||
/* Memory reference. The second SC increment occurs after the first
|
||||
execution cycle. For direct, defer, and immediate defer, this is
|
||||
after the first memory read and before the bus transfer; but for
|
||||
immediate, it is after the bus transfer.
|
||||
*/
|
||||
|
||||
else { SC = (SC + 1) & AMASK; /* incr SC */
|
||||
switch (op & MEM_MOD) { /* case on addr mode */
|
||||
case MEM_DIR: /* direct */
|
||||
MA = M[SC] & AMASK; /* get address */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
break;
|
||||
case MEM_DEF: /* defer */
|
||||
MA = M[SC] & AMASK; /* get ind addr */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
t = (M[MA] + 1) & DMASK; /* autoinc */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = t;
|
||||
MA = t & AMASK; /* ind addr */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
break;
|
||||
case MEM_IMM: /* immediate */
|
||||
MA = SC; /* eff addr */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
break;
|
||||
case MEM_IDF: /* immediate defer */
|
||||
MA = SC; /* get ind addr */
|
||||
t = (M[MA] + 1) & DMASK; /* autoinc */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = t;
|
||||
MA = t & AMASK; /* ind addr */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
break; } /* end switch */
|
||||
} /* end mem ref */
|
||||
} /* end while */
|
||||
|
||||
/* Simulation halted */
|
||||
|
||||
AO = ao_update (); /* update AO */
|
||||
scq_r->qptr = scq_p; /* update sc q ptr */
|
||||
return reason;
|
||||
}
|
||||
|
||||
/* Bus operations */
|
||||
|
||||
t_stat bus_op (uint32 src, uint32 op, uint32 dst)
|
||||
{
|
||||
uint32 t, old_t;
|
||||
|
||||
t = dev_tab[src].Src (src); /* get src */
|
||||
if (op & BUS_COM) t = t ^ DMASK; /* complement? */
|
||||
switch (op & BUS_FNC) { /* case op */
|
||||
case BUS_P1: /* plus 1 */
|
||||
t = t + 1; /* do add */
|
||||
if (t & CBIT) MSR = MSR | MSR_BOV; /* set cry out */
|
||||
else MSR = MSR & ~MSR_BOV;
|
||||
break;
|
||||
case BUS_L1: /* left 1 */
|
||||
t = (t << 1) | ((MSR & MSR_L)? 1: 0); /* rotate */
|
||||
if (t & CBIT) MSR = MSR | MSR_L; /* set link out */
|
||||
else MSR = MSR & ~MSR_L;
|
||||
break;
|
||||
case BUS_R1: /* right 1 */
|
||||
old_t = t;
|
||||
t = (t >> 1) | ((MSR & MSR_L)? SIGN: 0); /* rotate */
|
||||
if (old_t & 1) MSR = MSR | MSR_L; /* set link out */
|
||||
else MSR = MSR & ~MSR_L;
|
||||
break; } /* end case op */
|
||||
if (dst == thwh) DR = t & DMASK; /* display dst? */
|
||||
return dev_tab[dst].Dst (dst, t & DMASK); /* store dst */
|
||||
}
|
||||
|
||||
/* Non-existent device */
|
||||
|
||||
uint32 no_rd (uint32 src)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat no_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
return stop_opr;
|
||||
}
|
||||
|
||||
t_stat no_fo (uint32 fnc)
|
||||
{
|
||||
return stop_opr;
|
||||
}
|
||||
|
||||
uint32 no_sf (uint32 fnc)
|
||||
{
|
||||
return (stop_opr << SF_V_REASON);
|
||||
}
|
||||
|
||||
/* Zero device */
|
||||
|
||||
uint32 zero_rd (uint32 src)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat zero_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat zero_fo (uint32 op)
|
||||
{
|
||||
switch (op & 3) { /* FOM link */
|
||||
case 1: /* CLL */
|
||||
MSR = MSR & ~MSR_L;
|
||||
break;
|
||||
case 2: /* STL */
|
||||
MSR = MSR | MSR_L;
|
||||
break;
|
||||
case 3: /* CML */
|
||||
MSR = MSR ^ MSR_L;
|
||||
break; }
|
||||
if (op & 4) return STOP_HALT; /* HALT */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 zero_sf (uint32 op)
|
||||
{
|
||||
if ((op & 010) || /* power always ok */
|
||||
((op & 4) && (MSR & MSR_L)) || /* link set? */
|
||||
((op & 2) && (MSR & MSR_BOV))) return 1; /* BOV set? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Instruction register (01) */
|
||||
|
||||
uint32 ir_rd (uint32 src)
|
||||
{
|
||||
return IR;
|
||||
}
|
||||
|
||||
t_stat ir_fo (uint32 op)
|
||||
{
|
||||
if (op & 2) bkp = 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Trap register (03) */
|
||||
|
||||
uint32 trp_rd (uint32 src)
|
||||
{
|
||||
return TRP;
|
||||
}
|
||||
|
||||
/* Interrupt status register (04) */
|
||||
|
||||
uint32 isr_rd (uint32 src)
|
||||
{
|
||||
return ISR;
|
||||
}
|
||||
|
||||
t_stat isr_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
ISR = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat isr_fo (uint32 op)
|
||||
{
|
||||
if (op & ISR_ON) dev_done = (dev_done | INT_ON) & ~INT_NODEF;
|
||||
if (op & ISR_OFF) dev_done = dev_done & ~INT_ON;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 isr_sf (uint32 op)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Memory address (05) */
|
||||
|
||||
uint32 ma_rd (uint32 src)
|
||||
{
|
||||
return MA;
|
||||
}
|
||||
|
||||
/* Memory (06) */
|
||||
|
||||
uint32 mem_rd (uint32 src)
|
||||
{
|
||||
return M[MA];
|
||||
}
|
||||
|
||||
t_stat mem_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Sequence counter (07) */
|
||||
|
||||
uint32 sc_rd (uint32 src)
|
||||
{
|
||||
return SC;
|
||||
}
|
||||
|
||||
t_stat sc_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
SCQ_ENTRY;
|
||||
SC = dat & AMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Switch register (10) */
|
||||
|
||||
uint32 swr_rd (uint32 src)
|
||||
{
|
||||
return SWR;
|
||||
}
|
||||
|
||||
/* Machine status register (17) */
|
||||
|
||||
uint32 msr_rd (uint32 src)
|
||||
{
|
||||
return MSR;
|
||||
}
|
||||
|
||||
t_stat msr_wr (uint32 src, uint32 dat)
|
||||
{
|
||||
MSR = dat; /* new MSR */
|
||||
ao_update (); /* update AOV */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Arithmetic operators (11:14) */
|
||||
|
||||
uint32 ao_update (void)
|
||||
{
|
||||
int32 t;
|
||||
int32 af = MSR_GET_FOA (MSR);
|
||||
|
||||
switch (af) {
|
||||
case AO_ADD:
|
||||
t = (AX + AY) & DMASK; /* add */
|
||||
break;
|
||||
case AO_AND:
|
||||
t = AX & AY; /* and */
|
||||
break;
|
||||
case AO_XOR: /* xor */
|
||||
t = AX ^ AY;
|
||||
break;
|
||||
case AO_IOR:
|
||||
t = AX | AY; /* or */
|
||||
break; }
|
||||
if ((AX + AY) & CBIT) MSR = MSR | MSR_AOV; /* always calc AOV */
|
||||
else MSR = MSR & ~MSR_AOV;
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32 ax_rd (uint32 src)
|
||||
{
|
||||
return AX;
|
||||
}
|
||||
|
||||
t_stat ax_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
AX = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 ay_rd (uint32 src)
|
||||
{
|
||||
return AY;
|
||||
}
|
||||
|
||||
t_stat ay_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
AY = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 ao_rd (uint32 src)
|
||||
{
|
||||
AO = ao_update ();
|
||||
return AO;
|
||||
}
|
||||
|
||||
t_stat ao_fo (uint32 op)
|
||||
{
|
||||
uint32 t = OP_GET_FOA (op); /* get func */
|
||||
MSR = MSR_PUT_FOA (MSR, t); /* store in MSR */
|
||||
ao_update (); /* update AOV */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat eao_fo (uint32 op)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
if (cpu_unit.flags & UNIT_NOEAO) return stop_opr; /* EAO installed? */
|
||||
if (op == EAO_MUL) { /* mul? */
|
||||
t = AX * AY; /* AX * AY */
|
||||
AX = (t >> 16) & DMASK; /* to AX'GR1 */
|
||||
GR[0] = t & DMASK; }
|
||||
if (op == EAO_DIV) { /* div? */
|
||||
if (AY && (AX < AY)) {
|
||||
t = (AX << 16) | GR[0]; /* AX'GR1 / AY */
|
||||
GR[0] = t / AY; /* quo to GR1 */
|
||||
AX = t % AY; } /* rem to AX */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 ao_sf (uint32 op)
|
||||
{
|
||||
if (((op & 2) && (MSR & MSR_AOV)) || /* arith carry? */
|
||||
((op & 4) && (SIGN & /* arith overflow? */
|
||||
((AX ^ (AX + AY)) & (~AX ^ AY))))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Byte swapper (24) */
|
||||
|
||||
uint32 bsw_rd (uint32 src)
|
||||
{
|
||||
return BSW;
|
||||
}
|
||||
|
||||
t_stat bsw_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
BSW = ((val >> 8) & 0377) | ((val & 0377) << 8);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Byte packer (25) */
|
||||
|
||||
uint32 bpk_rd (uint32 src)
|
||||
{
|
||||
return BPK;
|
||||
}
|
||||
|
||||
t_stat bpk_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
BPK = ((BPK & 0377) << 8) | (val & 0377);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* General registers (30:35) */
|
||||
|
||||
uint32 gr_rd (uint32 src)
|
||||
{
|
||||
return GR[src - U_GR];
|
||||
}
|
||||
|
||||
t_stat gr_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
GR[dst - U_GR] = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat cpu_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
AX = AY = AO = 0;
|
||||
TRP = 0;
|
||||
ISR = 0;
|
||||
MSR = 0;
|
||||
MA = IR = 0;
|
||||
BSW = BPK = 0;
|
||||
for (i = 0; i < 6; i++) GR[i] = 0;
|
||||
dev_done = dev_done & ~INT_PENDING;
|
||||
scq_r = find_reg ("SCQ", NULL, dptr);
|
||||
if (scq_r) scq_r->qptr = 0;
|
||||
else return SCPE_IERR;
|
||||
sim_brk_types = sim_brk_dflt = SWMASK ('E');
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Memory examine */
|
||||
|
||||
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= MEMSIZE) return SCPE_NXM;
|
||||
if (vptr != NULL) *vptr = M[addr] & DMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Memory deposit */
|
||||
|
||||
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= MEMSIZE) return SCPE_NXM;
|
||||
M[addr] = val & DMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 mc = 0;
|
||||
uint32 i;
|
||||
|
||||
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
|
||||
return SCPE_ARG;
|
||||
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
|
||||
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
|
||||
return SCPE_OK;
|
||||
MEMSIZE = val;
|
||||
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
221
GRI/gri_defs.h
221
GRI/gri_defs.h
@@ -1,221 +0,0 @@
|
||||
/* gri_defs.h: GRI-909 simulator definitions
|
||||
|
||||
Copyright (c) 2001-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
19-Sep-02 RMS Fixed declarations in gdev structure
|
||||
|
||||
There are several discrepancies between the original GRI-909 Reference
|
||||
Manual of 1969 and the only surviving code sample, the MIT Crystal Growing
|
||||
System of 1972:
|
||||
|
||||
1. Ref Manual documents two GR's at codes 26-27; MITCS documents six GR's
|
||||
at 30-35.
|
||||
2. Ref Manual documents only unsigned overflow (carry) for arithmetic
|
||||
operator; MITCS uses both unsigned overflow (AOV) and signed overflow
|
||||
(SOV).
|
||||
3. Ref Manual documents a ROM-subroutine multiply operator and mentions
|
||||
but does not document a "fast multiply"; MITCS uses an extended
|
||||
arithmetic operator with multiply, divide, and shifts. The behavior
|
||||
of the extended arithmetic operator can only be inferred partially;
|
||||
the shifts are never used, and there is no indication of how divide
|
||||
overflow is handled.
|
||||
|
||||
The simulator follows the code in these instances.
|
||||
|
||||
Outstanding issues:
|
||||
|
||||
1. Is there any interaction between the byte swapper and the byte packer?
|
||||
2. Is SOV testable even if the FOA is not ADD?
|
||||
3. How does the EAO handle divide overflow?
|
||||
4. What are the other EAO functions beside multiply and divide?
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_DEV 1 /* must be 1 */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_ILLINT 4 /* illegal intr */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 32768 /* max memory size */
|
||||
#define AMASK 077777 /* logical addr mask */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
|
||||
|
||||
/* Architectural constants */
|
||||
|
||||
#define SIGN 0100000 /* sign */
|
||||
#define DMASK 0177777 /* data mask */
|
||||
#define CBIT (DMASK + 1) /* carry bit */
|
||||
|
||||
/* Instruction format */
|
||||
|
||||
#define I_M_SRC 077 /* source */
|
||||
#define I_V_SRC 10
|
||||
#define I_GETSRC(x) (((x) >> I_V_SRC) & I_M_SRC)
|
||||
#define I_M_OP 017 /* operator */
|
||||
#define I_V_OP 6
|
||||
#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP)
|
||||
#define I_M_DST 077 /* destination */
|
||||
#define I_V_DST 0
|
||||
#define I_GETDST(x) (((x) >> I_V_DST) & I_M_DST)
|
||||
#define SF_V_REASON 1 /* SF reason */
|
||||
|
||||
/* IO return */
|
||||
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
|
||||
|
||||
/* Operators */
|
||||
|
||||
#define U_ZERO 000 /* zero */
|
||||
#define U_IR 001 /* instruction reg */
|
||||
#define U_FSK 002 /* func out/skip */
|
||||
#define U_TRP 003 /* trap */
|
||||
#define U_ISR 004 /* intr status */
|
||||
#define U_MA 005 /* mem addr */
|
||||
#define U_MEM 006 /* mem data */
|
||||
#define U_SC 007 /* seq counter */
|
||||
#define U_SWR 010 /* switch register */
|
||||
#define U_AX 011 /* arith in 1 */
|
||||
#define U_AY 012 /* arith in 2 */
|
||||
#define U_AO 013 /* arith out */
|
||||
#define U_EAO 014 /* ext arith */
|
||||
#define U_MSR 017 /* machine status */
|
||||
#define U_BSW 024 /* byte swap */
|
||||
#define U_BPK 025 /* byte pack */
|
||||
/* #define U_GR 026 /* dual general regs */
|
||||
#define U_GR 030 /* hex general regs */
|
||||
#define U_RTC 075 /* clock */
|
||||
#define U_HS 076 /* paper tape */
|
||||
#define U_TTY 077 /* console */
|
||||
|
||||
struct gdev {
|
||||
uint32 (*Src)(uint32); /* source */
|
||||
t_stat (*Dst)(uint32, uint32); /* dest */
|
||||
t_stat (*FO)(uint32); /* func out */
|
||||
uint32 (*SF)(uint32); /* skip func */
|
||||
};
|
||||
|
||||
/* Trap (jump) */
|
||||
|
||||
#define TRP_DIR 00 /* direct */
|
||||
#define TRP_DEF 01 /* defer */
|
||||
|
||||
/* Interrupt status */
|
||||
|
||||
#define ISR_OFF 01 /* int off */
|
||||
#define ISR_ON 02 /* int on */
|
||||
|
||||
/* Bus modifiers */
|
||||
|
||||
#define BUS_COM 002 /* complement */
|
||||
#define BUS_FNC 014 /* function mask */
|
||||
#define BUS_P1 004 /* + 1 */
|
||||
#define BUS_L1 010 /* rotate left */
|
||||
#define BUS_R1 014 /* rotate right */
|
||||
|
||||
/* Memory address modes */
|
||||
|
||||
#define MEM_MOD 03
|
||||
#define MEM_DIR 00 /* direct */
|
||||
#define MEM_DEF 01 /* defer */
|
||||
#define MEM_IMM 02 /* immediate */
|
||||
#define MEM_IDF 03 /* immediate defer */
|
||||
|
||||
/* Arithmetic unit */
|
||||
|
||||
#define FO_V_FOA 8 /* arith func */
|
||||
#define FO_M_FOA 03
|
||||
#define OP_GET_FOA(x) (((x) >> (FO_V_FOA - I_V_OP)) & FO_M_FOA)
|
||||
#define AO_ADD 00 /* add */
|
||||
#define AO_AND 01 /* and */
|
||||
#define AO_XOR 02 /* xor */
|
||||
#define AO_IOR 03 /* or */
|
||||
#define EAO_MUL 01 /* multiply */
|
||||
#define EAO_DIV 02 /* divide */
|
||||
#define EAO_ASR 03 /* arith rshft */
|
||||
|
||||
/* Machine status */
|
||||
|
||||
#define MSR_V_BOV 15 /* bus carry */
|
||||
#define MSR_BOV (1u << MSR_V_BOV)
|
||||
#define MSR_V_L 14 /* bus link */
|
||||
#define MSR_L (1u << MSR_V_L) /* bus link */
|
||||
#define MSR_V_FOA 8 /* arith func */
|
||||
#define MSR_M_FOA 03
|
||||
#define MSR_V_AOV 0 /* arith carry */
|
||||
#define MSR_AOV (1u << MSR_V_AOV)
|
||||
#define MSR_GET_FOA(x) (((x) >> MSR_V_FOA) & MSR_M_FOA)
|
||||
#define MSR_PUT_FOA(x,n) (((x) & ~(MSR_M_FOA << MSR_V_FOA)) | \
|
||||
(((n) & MSR_M_FOA) << MSR_V_FOA))
|
||||
|
||||
/* Real time clock */
|
||||
|
||||
#define RTC_OFF 001 /* off */
|
||||
#define RTC_ON 002 /* clock on */
|
||||
#define RTC_OV 010 /* clock flag */
|
||||
#define RTC_CTR 0103 /* counter */
|
||||
|
||||
/* Terminal */
|
||||
|
||||
#define TTY_ORDY 002 /* output flag */
|
||||
#define TTY_IRDY 010 /* input flag */
|
||||
|
||||
/* Paper tape */
|
||||
|
||||
#define PT_STRT 001 /* start reader */
|
||||
#define PT_ORDY 002 /* output flag */
|
||||
#define PT_IRDY 010 /* input flag */
|
||||
|
||||
/* Interrupt masks (ISR) */
|
||||
|
||||
#define INT_V_TTO 0 /* console out */
|
||||
#define INT_V_TTI 1 /* console in */
|
||||
#define INT_V_HSP 2 /* paper tape punch */
|
||||
#define INT_V_HSR 3 /* paper tape reader */
|
||||
#define INT_V_RTC 11 /* clock */
|
||||
#define INT_V_NODEF 16 /* nodefer */
|
||||
#define INT_V_ON 17 /* enable */
|
||||
#define INT_TTO (1u << INT_V_TTO)
|
||||
#define INT_TTI (1u << INT_V_TTI)
|
||||
#define INT_HSP (1u << INT_V_HSP)
|
||||
#define INT_HSR (1u << INT_V_HSR)
|
||||
#define INT_RTC (1u << INT_V_RTC)
|
||||
#define INT_NODEF (1u << INT_V_NODEF)
|
||||
#define INT_ON (1u << INT_V_ON)
|
||||
#define INT_PENDING (INT_ON | INT_NODEF)
|
||||
|
||||
/* Vectors */
|
||||
|
||||
#define VEC_BKP 0000 /* breakpoint */
|
||||
#define VEC_TTO 0011 /* console out */
|
||||
#define VEC_TTI 0014 /* console in */
|
||||
#define VEC_HSP 0017 /* paper tape punch */
|
||||
#define VEC_HSR 0022 /* paper tape reader */
|
||||
#define VEC_RTC 0100 /* clock */
|
||||
321
GRI/gri_doc.txt
321
GRI/gri_doc.txt
@@ -1,321 +0,0 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: GRI-909 Simulator Usage
|
||||
Date: 20-Apr-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2003, written by Robert M Supnik
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This memorandum documents the GRI-909 simulator.
|
||||
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_sock.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/gri/ gri_defs.h
|
||||
gri_cpu.c
|
||||
gri_stddev.c
|
||||
gri_sys.c
|
||||
|
||||
2. GRI-909 Features
|
||||
|
||||
The GRI-909 is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU GRI-909 CPU with up to 32KW of memory
|
||||
HSR S42-004 high speed reader
|
||||
HSP S42-004 high speed punch
|
||||
TTI S42-001 Teletype input
|
||||
TTO S42-002 Teletype output
|
||||
RTC real-time clock
|
||||
|
||||
The GRI-909 simulator implements the following unique stop conditions:
|
||||
|
||||
- an unimplemented operator is referenced, and register
|
||||
STOP_OPR is set
|
||||
- an invalid interrupt request is made
|
||||
|
||||
The LOAD commands has an optional argument to specify the load address:
|
||||
|
||||
LOAD <filename> {<starting address>}
|
||||
|
||||
The LOAD command loads a paper-tape bootstrap format file at the specified
|
||||
address. If no address is specified, loading starts at location 200. The
|
||||
DUMP command is not supported.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
The only CPU options are the presence of the extended arithmetic operator
|
||||
and the size of main memory.
|
||||
|
||||
SET CPU EAO enable extended arithmetic operator
|
||||
SET CPU NOEAO disable extended arithmetic operator
|
||||
SET CPU 4K set memory size = 4K
|
||||
SET CPU 8K set memory size = 8K
|
||||
SET CPU 12K set memory size = 12K
|
||||
SET CPU 16K set memory size = 16K
|
||||
SET CPU 20K set memory size = 20K
|
||||
SET CPU 24K set memory size = 24K
|
||||
SET CPU 28K set memory size = 28K
|
||||
SET CPU 32K set memory size = 32K
|
||||
|
||||
If memory size is being reduced, and the memory being truncated contains
|
||||
non-zero data, the simulator asks for confirmation. Data in the truncated
|
||||
portion of memory is lost. Initial memory size is 32K.
|
||||
|
||||
CPU registers include the visible state of the processor as well as the
|
||||
control registers for the interrupt system.
|
||||
|
||||
name size comments
|
||||
|
||||
SC 15 sequence counter
|
||||
AX 16 arithmetic operator input register 1
|
||||
AY 16 arithmetic operator input register 2
|
||||
AO 16 arithmetic operator output register
|
||||
TRP 16 TRP register
|
||||
MSR 16 machine status register
|
||||
ISR 16 interrupt status register
|
||||
BSW 16 byte swapper buffer
|
||||
BPK 16 byte packer buffer
|
||||
GR1..GR6 16 general registers 1 to 6
|
||||
BOV 1 bus overflow (MSR<15>)
|
||||
L 1 link (MSR<14>)
|
||||
FOA 2 arithmetic operator function (MSR<9:8>)
|
||||
AOV 1 arithmetic overflow (MSR<0>)
|
||||
IR 16 instruction register (read only)
|
||||
MA 16 memory address register (read only)
|
||||
SWR 16 switch register
|
||||
DR 16 display register
|
||||
THW 6 thumbwheels (selects operator displayed in DR)
|
||||
IREQ 16 interrupt requests
|
||||
ION 1 interrupts enabled
|
||||
INODEF 1 interrupts not deferred
|
||||
BKP 1 breakpoint request
|
||||
SCQ[0:63] 15 SC prior to last jump or interrupt;
|
||||
most recent SC change first
|
||||
STOP_OPR 1 stop on undefined operator
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 Programmed I/O Devices
|
||||
|
||||
2.2.1 S42-004 High Speed Reader (HSR)
|
||||
|
||||
The paper tape reader (HSR) reads data from or a disk file. The POS
|
||||
register specifies the number of the next data item to be read.
|
||||
Thus, by changing POS, the user can backspace or advance the reader.
|
||||
|
||||
The paper tape reader implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
IRDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 position in the input file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
end of file 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.2 S42-006 High Speed Punch (HSP)
|
||||
|
||||
The paper tape punch (HSP) writes data to a disk file. The POS
|
||||
register specifies the number of the next data item to be written.
|
||||
Thus, by changing POS, the user can backspace or advance the punch.
|
||||
|
||||
The paper tape punch implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
ORDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 position in the output file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.3 S42-001 Teletype Input (TTI)
|
||||
|
||||
The Teletype interfaces (TTI, TTO) can be set to one of three modes:
|
||||
KSR, 7B, or 8B. In KSR mode, lower case input and output characters
|
||||
are automatically converted to upper case, and the high order bit is
|
||||
forced to one on input. In 7B mode, input and output characters are
|
||||
masked to 7 bits. In 8B mode, characters are not modified. Changing
|
||||
the mode of either interface changes both. The default mode is KSR.
|
||||
|
||||
The Teletype input (TTI) polls the console keyboard for input. It
|
||||
implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
IRDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 position in the output file
|
||||
TIME 24 keyboard polling interval
|
||||
|
||||
2.2.4 S42-002 Teletype Output (TTO)
|
||||
|
||||
The Teletype output (TTO) writes to the simulator console window. It
|
||||
implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
ORDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 number of characters output
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
|
||||
2.2.5 Real-Time Clock (RTC)
|
||||
|
||||
The real-time clock (CLK) implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
RDY 1 device ready flag
|
||||
IENB 1 interrupt enable flag
|
||||
TIME 24 clock interval
|
||||
|
||||
The real-time clock autocalibrates; the clock interval is adjusted up or
|
||||
down so that the clock tracks actual elapsed time.
|
||||
|
||||
2.3 Symbolic Display and Input
|
||||
|
||||
The GRI-909 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-a display as ASCII character
|
||||
-c display as packed ASCII characters
|
||||
-m display instruction mnemonics
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or -a ASCII character
|
||||
" or -c two packed ASCII characters
|
||||
alphabetic instruction mnemonic
|
||||
numeric octal number
|
||||
|
||||
Instruction input uses modified GRI-909 basic assembler syntax. There are
|
||||
thirteen different instruction formats. Operators, functions, and tests may
|
||||
be octal or symbolic; jump conditions and bus operators are always symbolic.
|
||||
|
||||
Function out, general
|
||||
Syntax: FO function,operator
|
||||
Function symbols: INP, IRDY, ORDY, STRT
|
||||
Example: FO ORDY,TTO
|
||||
|
||||
Function out, named
|
||||
Syntax: FO{M|I|A} function
|
||||
Function symbols: M: CLL, CML, STL, HLT; I: ICF, ICO;
|
||||
A: ADD, AND, XOR, OR
|
||||
Example: FOA XOR
|
||||
|
||||
Sense function, general
|
||||
Syntax: SF operator,{NOT} tests
|
||||
Test symbols: IRDY, ORDY
|
||||
Example: SF HSR,IRDY
|
||||
|
||||
Sense function, named
|
||||
Syntax: SF{M|A} {NOT} tests
|
||||
Test symbols: M: POK BOV LNK; A: SOV AOV
|
||||
Example: SFM NOT BOV
|
||||
|
||||
Register to register
|
||||
Syntax: RR{C} src,{bus op,}dst
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: RRC AX,P1,AY
|
||||
|
||||
Zero to register
|
||||
Syntax: ZR{C} {bus op,}dst
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: ZR P1,GR1
|
||||
|
||||
Register to self
|
||||
Syntax: RS{C} dst{,bus op}
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: RS AX,L1
|
||||
|
||||
Jump unconditional or named condition
|
||||
Syntax: J{U|O|N}{D} address
|
||||
Example: JUD 1400
|
||||
|
||||
Jump conditional
|
||||
Syntax: JC{D} src,cond,address
|
||||
Cond symbols: NEVER,ALWAYS,ETZ,NEZ,LTZ,GEZ,LEZ,GTZ
|
||||
Example: JC AX,LEZ,200
|
||||
|
||||
Register to memory
|
||||
syntax: RM{I|D|ID} src,{bus op,}address
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: RMD AX,P1,1315
|
||||
|
||||
Zero to memory
|
||||
Syntax: ZM{I|D|ID} {bus op,}address
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: ZM P1,5502
|
||||
|
||||
Memory to register
|
||||
Syntax: MR{I|D|ID} address,{bus op,}dst
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: MRI 1405,GR6
|
||||
|
||||
Memory to self:
|
||||
Syntax: MS{I|D|ID} address{,bus op}
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: MS 3333,P1
|
||||
394
GRI/gri_stddev.c
394
GRI/gri_stddev.c
@@ -1,394 +0,0 @@
|
||||
/* gri_stddev.c: GRI-909 standard devices
|
||||
|
||||
Copyright (c) 2001-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
tti S42-001 terminal input
|
||||
tto S42-002 terminal output
|
||||
hsr S42-004 high speed reader
|
||||
hsp S42-006 high speed punch
|
||||
rtc real time clock
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
22-Dec-02 RMS Added break support
|
||||
01-Nov-02 RMS Added 7b/8B support to terminal
|
||||
*/
|
||||
|
||||
#include "gri_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
|
||||
#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */
|
||||
#define UNIT_8B (1 << UNIT_V_8B)
|
||||
#define UNIT_KSR (1 << UNIT_V_KSR)
|
||||
|
||||
uint32 hsr_stopioe = 1, hsp_stopioe = 1;
|
||||
|
||||
extern uint16 M[];
|
||||
extern uint32 dev_done, ISR;
|
||||
|
||||
t_stat tti_svc (UNIT *uhsr);
|
||||
t_stat tto_svc (UNIT *uhsr);
|
||||
t_stat tti_reset (DEVICE *dhsr);
|
||||
t_stat tto_reset (DEVICE *dhsr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat hsr_svc (UNIT *uhsr);
|
||||
t_stat hsp_svc (UNIT *uhsr);
|
||||
t_stat hsr_reset (DEVICE *dhsr);
|
||||
t_stat hsp_reset (DEVICE *dhsr);
|
||||
t_stat rtc_svc (UNIT *uhsr);
|
||||
t_stat rtc_reset (DEVICE *dhsr);
|
||||
int32 rtc_tps = 1000;
|
||||
|
||||
/* TTI data structures
|
||||
|
||||
tti_dev TTI device descriptor
|
||||
tti_unit TTI unit descriptor
|
||||
tti_reg TTI register list
|
||||
tti_mod TTI modifiers list
|
||||
*/
|
||||
|
||||
UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG tti_reg[] = {
|
||||
{ ORDATA (BUF, tti_unit.buf, 8) },
|
||||
{ FLDATA (IRDY, dev_done, INT_V_TTI) },
|
||||
{ FLDATA (IENB, ISR, INT_V_TTI) },
|
||||
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (UC, tti_unit.flags, UNIT_V_KSR), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tti_mod[] = {
|
||||
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode },
|
||||
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode },
|
||||
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tti_dev = {
|
||||
"TTI", &tti_unit, tti_reg, tti_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tti_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* TTO data structures
|
||||
|
||||
tto_dev TTO device descriptor
|
||||
tto_unit TTO unit descriptor
|
||||
tto_reg TTO register list
|
||||
*/
|
||||
|
||||
UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG tto_reg[] = {
|
||||
{ ORDATA (BUF, tto_unit.buf, 8) },
|
||||
{ FLDATA (ORDY, dev_done, INT_V_TTO) },
|
||||
{ FLDATA (IENB, ISR, INT_V_TTO) },
|
||||
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tto_mod[] = {
|
||||
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode },
|
||||
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode },
|
||||
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tto_dev = {
|
||||
"TTO", &tto_unit, tto_reg, tto_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tto_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* HSR data structures
|
||||
|
||||
hsr_dev HSR device descriptor
|
||||
hsr_unit HSR unit descriptor
|
||||
hsr_reg HSR register list
|
||||
hsr_mod HSR modifiers list
|
||||
*/
|
||||
|
||||
UNIT hsr_unit = {
|
||||
UDATA (&hsr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT };
|
||||
|
||||
REG hsr_reg[] = {
|
||||
{ ORDATA (BUF, hsr_unit.buf, 8) },
|
||||
{ FLDATA (IRDY, dev_done, INT_V_HSR) },
|
||||
{ FLDATA (IENB, ISR, INT_V_HSR) },
|
||||
{ DRDATA (POS, hsr_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, hsr_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, hsr_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE hsr_dev = {
|
||||
"HSR", &hsr_unit, hsr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &hsr_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* HSP data structures
|
||||
|
||||
hsp_dev HSP device descriptor
|
||||
hsp_unit HSP unit descriptor
|
||||
hsp_reg HSP register list
|
||||
*/
|
||||
|
||||
UNIT hsp_unit = {
|
||||
UDATA (&hsp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG hsp_reg[] = {
|
||||
{ ORDATA (BUF, hsp_unit.buf, 8) },
|
||||
{ FLDATA (ORDY, dev_done, INT_V_HSP) },
|
||||
{ FLDATA (IENB, ISR, INT_V_HSP) },
|
||||
{ DRDATA (POS, hsp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, hsp_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, hsp_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE hsp_dev = {
|
||||
"HSP", &hsp_unit, hsp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &hsp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* RTC data structures
|
||||
|
||||
rtc_dev RTC device descriptor
|
||||
rtc_unit RTC unit descriptor
|
||||
rtc_reg RTC register list
|
||||
*/
|
||||
|
||||
UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), 16000 };
|
||||
|
||||
REG rtc_reg[] = {
|
||||
{ FLDATA (RDY, dev_done, INT_V_RTC) },
|
||||
{ FLDATA (IENB, ISR, INT_V_RTC) },
|
||||
{ DRDATA (TIME, rtc_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPS, rtc_tps, 8), REG_NZ + PV_LEFT + REG_HIDDEN },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE rtc_dev = {
|
||||
"RTC", &rtc_unit, rtc_reg, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &rtc_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Console terminal function processors */
|
||||
|
||||
int32 tty_rd (int32 src, int32 ea)
|
||||
{
|
||||
return tti_unit.buf; /* return data */
|
||||
}
|
||||
|
||||
t_stat tty_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
tto_unit.buf = val & 0377; /* save char */
|
||||
dev_done = dev_done & ~INT_TTO; /* clear ready */
|
||||
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tty_fo (uint32 op)
|
||||
{
|
||||
if (op & TTY_IRDY) dev_done = dev_done & ~INT_TTI;
|
||||
if (op & TTY_ORDY) dev_done = dev_done & ~INT_TTO;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 tty_sf (uint32 op)
|
||||
{
|
||||
if (((op & TTY_IRDY) && (dev_done & INT_TTI)) ||
|
||||
((op & TTY_ORDY) && (dev_done & INT_TTO))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Service routines */
|
||||
|
||||
t_stat tti_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c;
|
||||
|
||||
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
|
||||
if (c & SCPE_BREAK) tti_unit.buf = 0; /* break? */
|
||||
else if (tti_unit.flags & UNIT_KSR) { /* KSR? */
|
||||
c = c & 0177; /* force 7b */
|
||||
if (islower (c)) c = toupper (c); /* cvt to UC */
|
||||
tti_unit.buf = c | 0200; } /* add TTY bit */
|
||||
else tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177);
|
||||
dev_done = dev_done | INT_TTI; /* set ready */
|
||||
tti_unit.pos = tti_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c;
|
||||
t_stat r;
|
||||
|
||||
dev_done = dev_done | INT_TTO; /* set ready */
|
||||
if (tto_unit.flags & UNIT_KSR) { /* KSR? */
|
||||
c = tto_unit.buf & 0177; /* force 7b */
|
||||
if (islower (c)) c = toupper (c); } /* cvt to UC */
|
||||
else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
|
||||
if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output */
|
||||
tto_unit.pos = tto_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routines */
|
||||
|
||||
t_stat tti_reset (DEVICE *dptr)
|
||||
{
|
||||
tti_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done & ~INT_TTI; /* clear ready */
|
||||
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_reset (DEVICE *dptr)
|
||||
{
|
||||
tto_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done | INT_TTO; /* set ready */
|
||||
sim_cancel (&tto_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
tti_unit.flags = (tti_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val;
|
||||
tto_unit.flags = (tto_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* High speed paper tape function processors */
|
||||
|
||||
int32 hsrp_rd (int32 src, int32 ea)
|
||||
{
|
||||
return hsr_unit.buf; /* return data */
|
||||
}
|
||||
|
||||
t_stat hsrp_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
hsp_unit.buf = val & 0377; /* save char */
|
||||
dev_done = dev_done & ~INT_HSP; /* clear ready */
|
||||
sim_activate (&hsp_unit, hsp_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat hsrp_fo (uint32 op)
|
||||
{
|
||||
if (op & PT_IRDY) dev_done = dev_done & ~INT_HSR;
|
||||
if (op & PT_ORDY) dev_done = dev_done & ~INT_HSP;
|
||||
if (op & PT_STRT) sim_activate (&hsr_unit, hsr_unit.wait);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 hsrp_sf (uint32 op)
|
||||
{
|
||||
if (((op & PT_IRDY) && (dev_done & INT_HSR)) ||
|
||||
((op & PT_ORDY) && (dev_done & INT_HSP))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat hsr_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (hsr_stopioe, SCPE_UNATT);
|
||||
if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */
|
||||
if (feof (hsr_unit.fileref)) { /* err or eof? */
|
||||
if (hsr_stopioe) printf ("HSR end of file\n");
|
||||
else return SCPE_OK; }
|
||||
else perror ("HSR I/O error");
|
||||
clearerr (hsr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
dev_done = dev_done | INT_HSR; /* set ready */
|
||||
hsr_unit.buf = temp & 0377; /* save char */
|
||||
hsr_unit.pos = hsr_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat hsp_svc (UNIT *uptr)
|
||||
{
|
||||
dev_done = dev_done | INT_HSP; /* set ready */
|
||||
if ((hsp_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (hsp_stopioe, SCPE_UNATT);
|
||||
if (putc (hsp_unit.buf, hsp_unit.fileref) == EOF) { /* write char */
|
||||
perror ("HSP I/O error"); /* error? */
|
||||
clearerr (hsp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
hsp_unit.pos = hsp_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routines */
|
||||
|
||||
t_stat hsr_reset (DEVICE *dptr)
|
||||
{
|
||||
hsr_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done & ~INT_HSR; /* clear ready */
|
||||
sim_cancel (&hsr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat hsp_reset (DEVICE *dptr)
|
||||
{
|
||||
hsp_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done | INT_HSP; /* set ready */
|
||||
sim_cancel (&hsp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Clock function processors */
|
||||
|
||||
t_stat rtc_fo (int32 op)
|
||||
{
|
||||
if (op & RTC_OFF) sim_cancel (&rtc_unit); /* clock off? */
|
||||
if ((op & RTC_ON) && !sim_is_active (&rtc_unit)) /* clock on? */
|
||||
sim_activate (&rtc_unit, sim_rtc_init (rtc_unit.wait));
|
||||
if (op & RTC_OV) dev_done = dev_done & ~INT_RTC; /* clr ovflo? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int32 rtc_sf (int32 op)
|
||||
{
|
||||
if ((op & RTC_OV) && (dev_done & INT_RTC)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat rtc_svc (UNIT *uptr)
|
||||
{
|
||||
M[RTC_CTR] = (M[RTC_CTR] + 1) & DMASK; /* incr counter */
|
||||
if (M[RTC_CTR] == 0) dev_done = dev_done | INT_RTC; /* ovflo? set ready */
|
||||
sim_activate (&rtc_unit, sim_rtc_calb (rtc_tps)); /* reactivate */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat rtc_reset (DEVICE *dptr)
|
||||
{
|
||||
dev_done = dev_done & ~INT_RTC; /* clear ready */
|
||||
sim_cancel (&rtc_unit); /* stop clock */
|
||||
return SCPE_OK;
|
||||
}
|
||||
582
GRI/gri_sys.c
582
GRI/gri_sys.c
@@ -1,582 +0,0 @@
|
||||
/* gri_sys.c: GRI-909 simulator interface
|
||||
|
||||
Copyright (c) 2001-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
18-Oct-02 RMS Fixed bug in symbolic decode (found by Hans Pufal)
|
||||
*/
|
||||
|
||||
#include "gri_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern DEVICE tti_dev, tto_dev;
|
||||
extern DEVICE hsr_dev, hsp_dev;
|
||||
extern DEVICE rtc_dev;
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 M[];
|
||||
extern int32 sim_switches;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "GRI-909";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 2;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&tti_dev,
|
||||
&tto_dev,
|
||||
&hsr_dev,
|
||||
&hsp_dev,
|
||||
&rtc_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented unit",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Invalid interrupt request" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
Bootstrap loader format consists of blocks separated by zeroes. Each
|
||||
word in the block has three frames: a control frame (ignored) and two
|
||||
data frames. The user must specify the load address. Switch -c means
|
||||
continue and load all blocks until end of tape.
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 c;
|
||||
uint32 org;
|
||||
t_stat r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
if (*cptr != 0) { /* more input? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get origin */
|
||||
org = get_uint (gbuf, 8, AMASK, &r);
|
||||
if (r != SCPE_OK) return r;
|
||||
if (*cptr != 0) return SCPE_ARG; } /* no more */
|
||||
else org = 0200; /* default 200 */
|
||||
|
||||
for (;;) { /* until EOF */
|
||||
while ((c = getc (fileref)) == 0) ; /* skip starting 0's */
|
||||
if (c == EOF) break; /* EOF? done */
|
||||
for ( ; c != 0; ) { /* loop until ctl = 0 */
|
||||
/* ign ctrl frame */
|
||||
if ((c = getc (fileref)) == EOF) /* get high byte */
|
||||
return SCPE_FMT; /* EOF is error */
|
||||
if (!MEM_ADDR_OK (org)) return SCPE_NXM;
|
||||
M[org] = ((c & 0377) << 8); /* store high */
|
||||
if ((c = getc (fileref)) == EOF) /* get low byte */
|
||||
return SCPE_FMT; /* EOF is error */
|
||||
M[org] = M[org] | (c & 0377); /* store low */
|
||||
org = org + 1; /* incr origin */
|
||||
if ((c = getc (fileref)) == EOF) /* get ctrl frame */
|
||||
return SCPE_OK; /* EOF is ok */
|
||||
} /* end block for */
|
||||
if (!(sim_switches & SWMASK ('C'))) return SCPE_OK;
|
||||
} /* end tape for */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
|
||||
#define F_V_FL 16 /* class flag */
|
||||
#define F_M_FL 017
|
||||
#define F_V_FO 000 /* function out */
|
||||
#define F_V_FOI 001 /* FO, impl reg */
|
||||
#define F_V_SF 002 /* skip function */
|
||||
#define F_V_SFI 003 /* SF, impl reg */
|
||||
#define F_V_RR 004 /* reg reg */
|
||||
#define F_V_ZR 005 /* zero reg */
|
||||
#define F_V_RS 006 /* reg self */
|
||||
#define F_V_JC 010 /* jump cond */
|
||||
#define F_V_JU 011 /* jump uncond */
|
||||
#define F_V_RM 012 /* reg mem */
|
||||
#define F_V_ZM 013 /* zero mem */
|
||||
#define F_V_MR 014 /* mem reg */
|
||||
#define F_V_MS 015 /* mem self */
|
||||
#define F_2WD 010 /* 2 words */
|
||||
|
||||
#define F_FO (F_V_FO << F_V_FL)
|
||||
#define F_FOI (F_V_FOI << F_V_FL)
|
||||
#define F_SF (F_V_SF << F_V_FL)
|
||||
#define F_SFI (F_V_SFI << F_V_FL)
|
||||
#define F_RR (F_V_RR << F_V_FL)
|
||||
#define F_ZR (F_V_ZR << F_V_FL)
|
||||
#define F_RS (F_V_RS << F_V_FL)
|
||||
#define F_JC (F_V_JC << F_V_FL)
|
||||
#define F_JU (F_V_JU << F_V_FL)
|
||||
#define F_RM (F_V_RM << F_V_FL)
|
||||
#define F_ZM (F_V_ZM << F_V_FL)
|
||||
#define F_MR (F_V_MR << F_V_FL)
|
||||
#define F_MS (F_V_MS << F_V_FL)
|
||||
|
||||
struct fnc_op {
|
||||
uint32 inst; /* instr prot */
|
||||
uint32 imask; /* instr mask */
|
||||
uint32 oper; /* operator */
|
||||
uint32 omask; }; /* oper mask */
|
||||
|
||||
static const int32 masks[] = {
|
||||
0176000, 0176077, 0000077, 0176077,
|
||||
0000300, 0176300, 0000300, 0177777,
|
||||
0000077, 0177777, 0000377, 0176377,
|
||||
0176300, 0176377 };
|
||||
|
||||
/* Instruction mnemonics
|
||||
|
||||
Order is critical, as some instructions are more precise versions of
|
||||
others. For example, JU must precede JC, otherwise, JU will be decoded
|
||||
as JC 0,ETZ,dst. There are some ambiguities, eg, what is 02-xxxx-06?
|
||||
Priority is as follows:
|
||||
|
||||
FO (02-xxxx-rr)
|
||||
SF (rr-xxxx-02)
|
||||
MR (06-xxxx-rr)
|
||||
RM (rr-xxxx-06)
|
||||
JC (rr-xxxx-03)
|
||||
RR
|
||||
*/
|
||||
|
||||
static const char *opcode[] = {
|
||||
"FOM", "FOA", "FOI", "FO", /* FOx before FO */
|
||||
"SFM", "SFA", "SFI", "SF", /* SFx before SF */
|
||||
"ZM", "ZMD", "ZMI", "ZMID", /* ZM before RM */
|
||||
"MS", "MSD", "MSI", "MSID",
|
||||
"RM", "RMD", "RMI", "RMID",
|
||||
"MR", "MRD", "MRI", "MRID",
|
||||
"JO", "JOD", "JN", "JND", /* JU before JC */
|
||||
"JU", "JUD", "JC", "JCD",
|
||||
"ZR", "ZRC", "RR", "RRC", /* ZR before RR */
|
||||
"RS", "RSC",
|
||||
NULL };
|
||||
|
||||
static const uint32 opc_val[] = {
|
||||
0004000+F_FOI, 0004013+F_FOI, 0004004+F_FOI, 0004000+F_FO,
|
||||
0000002+F_SFI, 0026002+F_SFI, 0010002+F_SFI, 0000002+F_SF,
|
||||
0000006+F_ZM, 0000106+F_ZM, 0000206+F_ZM, 0000306+F_ZM,
|
||||
0014006+F_MS, 0014106+F_MS, 0014206+F_MS, 0014306+F_MS,
|
||||
0000006+F_RM, 0000106+F_RM, 0000206+F_RM, 0000306+F_RM,
|
||||
0014000+F_MR, 0014100+F_MR, 0014200+F_MR, 0014300+F_MR,
|
||||
0037003+F_JU, 0037103+F_JU, 0037203+F_JU, 0037303+F_JU,
|
||||
0000403+F_JU, 0000503+F_JU, 0000003+F_JC, 0000103+F_JC,
|
||||
0000000+F_ZR, 0000200+F_ZR, 0000000+F_RR, 0000200+F_RR,
|
||||
0000000+F_RS, 0000200+F_RS };
|
||||
|
||||
/* Unit mnemonics. All 64 units are decoded, most just to octal integers */
|
||||
|
||||
static const char *unsrc[64] = {
|
||||
"0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */
|
||||
"SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */
|
||||
"20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */
|
||||
"GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */
|
||||
"40", "41", "42", "43", "44", "45", "46", "47",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67",
|
||||
"70", "71", "72", "73", "74", "RTC", "HSR", "TTI" }; /* 70 - 77 */
|
||||
|
||||
static const char *undst[64] = {
|
||||
"0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */
|
||||
"SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */
|
||||
"20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */
|
||||
"GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */
|
||||
"40", "41", "42", "43", "44", "45", "46", "47",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67",
|
||||
"70", "71", "72", "73", "74", "RTC", "HSP", "TTO" }; /* 70 - 77 */
|
||||
|
||||
/* Operators */
|
||||
|
||||
static const char *opname[4] = {
|
||||
NULL, "P1", "L1", "R1" };
|
||||
|
||||
/* Conditions */
|
||||
|
||||
static const char *cdname[8] = {
|
||||
"NEVER", "ALWAYS", "ETZ", "NEZ", "LTZ", "GEZ", "LEZ", "GTZ" };
|
||||
|
||||
/* Function out/sense function */
|
||||
|
||||
static const char *fname[] = {
|
||||
"NOT", /* any SF */
|
||||
"POK", "LNK", "BOV", /* SFM */
|
||||
"SOV", "AOV", /* SFA */
|
||||
"IRDY", "ORDY", /* any SF */
|
||||
"CLL", "STL", "CML", "HLT", /* FOM */
|
||||
"ICF", "ICO", /* FOI */
|
||||
"ADD", "AND", "XOR", "OR", /* FOA */
|
||||
"INP", "IRDY", "ORDY", "STRT", /* any FO */
|
||||
NULL };
|
||||
|
||||
static const struct fnc_op fop[] = {
|
||||
{ 0000002, 0000077, 001, 001 }, /* NOT */
|
||||
{ 0000002, 0176077, 010, 010 }, /* POK */
|
||||
{ 0000002, 0176077, 004, 004 }, /* LNK */
|
||||
{ 0000002, 0176077, 002, 002 }, /* BOV */
|
||||
{ 0026002, 0176077, 004, 004 }, /* SOV */
|
||||
{ 0026002, 0176077, 002, 002 }, /* AOV */
|
||||
{ 0000002, 0000077, 010, 010 }, /* IRDY */
|
||||
{ 0000002, 0000077, 002, 002 }, /* ORDY */
|
||||
{ 0004000, 0176077, 001, 003 }, /* CLL */
|
||||
{ 0004000, 0176077, 002, 003 }, /* STL */
|
||||
{ 0004000, 0176077, 003, 003 }, /* CML */
|
||||
{ 0004000, 0176077, 004, 004 }, /* HLT */
|
||||
{ 0004004, 0176077, 001, 001 }, /* ICF */
|
||||
{ 0004004, 0176077, 002, 002 }, /* ICO */
|
||||
{ 0004013, 0176077, 000, 014 }, /* ADD */
|
||||
{ 0004013, 0176077, 004, 014 }, /* AND */
|
||||
{ 0004013, 0176077, 010, 014 }, /* XOR */
|
||||
{ 0004013, 0176077, 014, 014 }, /* OR */
|
||||
{ 0004000, 0176000, 011, 011 }, /* INP */
|
||||
{ 0004000, 0176000, 010, 010 }, /* IRDY */
|
||||
{ 0004000, 0176000, 002, 002 }, /* ORDY */
|
||||
{ 0004000, 0176000, 001, 001 } }; /* STRT */
|
||||
|
||||
/* Print opcode field for FO, SF */
|
||||
|
||||
void fprint_op (FILE *of, uint32 inst, uint32 op)
|
||||
{
|
||||
int32 i, nfirst;
|
||||
|
||||
for (i = nfirst = 0; fname[i] != NULL; i++) {
|
||||
if (((inst & fop[i].imask) == fop[i].inst) &&
|
||||
((op & fop[i].omask) == fop[i].oper)) {
|
||||
op = op & ~fop[i].omask;
|
||||
if (nfirst) fputc (' ', of);
|
||||
nfirst = 1;
|
||||
fprintf (of, "%s", fname[i]); }
|
||||
}
|
||||
if (op) fprintf (of, " %o", op);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to data
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = status code
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 i, j;
|
||||
uint32 inst, src, dst, op, bop;
|
||||
|
||||
inst = val[0];
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
if (inst > 0377) return SCPE_ARG;
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('C')) { /* characters? */
|
||||
fprintf (of, FMTASC ((inst >> 8) & 0177));
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
|
||||
/* Instruction decode */
|
||||
|
||||
inst = val[0];
|
||||
src = I_GETSRC (inst); /* get fields */
|
||||
op = I_GETOP (inst);
|
||||
dst = I_GETDST (inst);
|
||||
bop = op >> 2; /* bus op */
|
||||
for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */
|
||||
if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case F_V_FO: /* func out */
|
||||
fprintf (of, "%s ", opcode[i]);
|
||||
fprint_op (of, inst, op);
|
||||
fprintf (of, ",%s", undst[dst]);
|
||||
break;
|
||||
case F_V_FOI: /* func out impl */
|
||||
fprintf (of, "%s ", opcode[i]);
|
||||
fprint_op (of, inst, op);
|
||||
break;
|
||||
case F_V_SF: /* skip func */
|
||||
fprintf (of, "%s %s,", opcode[i], unsrc[src]);
|
||||
fprint_op (of, inst, op);
|
||||
break;
|
||||
case F_V_SFI: /* skip func impl */
|
||||
fprintf (of, "%s ", opcode[i]);
|
||||
fprint_op (of, inst, op);
|
||||
break;
|
||||
case F_V_RR: /* reg reg */
|
||||
if (strcmp (unsrc[src], undst[dst]) == 0) {
|
||||
if (bop) fprintf (of, "%s %s,%s", opcode[i + 2],
|
||||
unsrc[src], opname[bop]);
|
||||
else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]); }
|
||||
else {
|
||||
if (bop) fprintf (of, "%s %s,%s,%s", opcode[i],
|
||||
unsrc[src], opname[bop], undst[dst]);
|
||||
else fprintf (of, "%s %s,%s", opcode[i],
|
||||
unsrc[src], undst[dst]); }
|
||||
break;
|
||||
case F_V_ZR: /* zero reg */
|
||||
if (bop) fprintf (of, "%s %s,%s", opcode[i],
|
||||
opname[bop], undst[dst]);
|
||||
else fprintf (of, "%s %s", opcode[i], undst[dst]);
|
||||
break;
|
||||
case F_V_JC: /* jump cond */
|
||||
fprintf (of, "%s %s,%s,%o", opcode[i],
|
||||
unsrc[src], cdname[op >> 1], val[1]);
|
||||
break;
|
||||
case F_V_JU: /* jump uncond */
|
||||
fprintf (of, "%s %o", opcode[i], val[1]);
|
||||
break;
|
||||
case F_V_RM: /* reg mem */
|
||||
if (bop) fprintf (of, "%s %s,%s,%o", opcode[i],
|
||||
unsrc[src], opname[bop], val[1]);
|
||||
else fprintf (of, "%s %s,%o", opcode[i], unsrc[src], val[1]);
|
||||
break;
|
||||
case F_V_ZM: /* zero mem */
|
||||
if (bop) fprintf (of, "%s %s,%o", opcode[i],
|
||||
opname[bop], val[1]);
|
||||
else fprintf (of, "%s %o", opcode[i], val[1]);
|
||||
break;
|
||||
case F_V_MR: /* mem reg */
|
||||
if (bop) fprintf (of, "%s %o,%s,%s", opcode[i],
|
||||
val[1], opname[bop], undst[dst]);
|
||||
else fprintf (of, "%s %o,%s", opcode[i], val[1], undst[dst]);
|
||||
break;
|
||||
case F_V_MS: /* mem self */
|
||||
if (bop) fprintf (of, "%s %o,%s", opcode[i],
|
||||
val[1], opname[bop]);
|
||||
else fprintf (of, "%s %o", opcode[i], val[1]);
|
||||
break; } /* end case */
|
||||
return (j >= F_2WD)? -1: SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Field parse routines
|
||||
|
||||
get_fnc get function field
|
||||
get_ma get memory address
|
||||
get_sd get source or dest
|
||||
get_op get optional bus operator
|
||||
*/
|
||||
|
||||
char *get_fnc (char *cptr, t_value *val)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
int32 i;
|
||||
t_value d;
|
||||
t_stat r;
|
||||
uint32 inst = val[0];
|
||||
uint32 fncv = 0, fncm = 0;
|
||||
|
||||
while (*cptr) {
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
|
||||
d = get_uint (gbuf, 8, 017, &r); /* octal? */
|
||||
if (r == SCPE_OK) { /* ok? */
|
||||
if (d & fncm) return NULL; /* already filled? */
|
||||
fncv = fncv | d; /* save */
|
||||
fncm = fncm | d; } /* field filled */
|
||||
else { /* symbol? */
|
||||
for (i = 0; fname[i] != NULL; i++) { /* search table */
|
||||
if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */
|
||||
((inst & fop[i].imask) == fop[i].inst)) {
|
||||
if (fop[i].oper & fncm) return NULL;/* already filled? */
|
||||
fncm = fncm | fop[i].omask;
|
||||
fncv = fncv | fop[i].oper;
|
||||
break; } }
|
||||
if (fname[i] == NULL) return NULL; } /* end else */
|
||||
} /* end while */
|
||||
val[0] = val[0] | (fncv << I_V_OP); /* store fnc */
|
||||
return cptr;
|
||||
}
|
||||
|
||||
char *get_ma (char *cptr, t_value *val, char term)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
t_value d;
|
||||
t_stat r;
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, term); /* get glyph */
|
||||
d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */
|
||||
if (r != SCPE_OK) return NULL;
|
||||
val[1] = d; /* second wd */
|
||||
return cptr;
|
||||
}
|
||||
|
||||
char *get_sd (char *cptr, t_value *val, char term, t_bool src)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
int32 d;
|
||||
t_stat r;
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, term); /* get glyph */
|
||||
for (d = 0; d < 64; d++) { /* symbol match? */
|
||||
if ((strcmp (gbuf, unsrc[d]) == 0) ||
|
||||
(strcmp (gbuf, undst[d]) == 0)) break; }
|
||||
if (d >= 64) { /* no, [0,63]? */
|
||||
d = get_uint (gbuf, 8, 077, &r);
|
||||
if (r != SCPE_OK) return NULL; }
|
||||
val[0] = val[0] | (d << (src? I_V_SRC: I_V_DST)); /* or to inst */
|
||||
return cptr;
|
||||
}
|
||||
|
||||
char *get_op (char *cptr, t_value *val, char term)
|
||||
{
|
||||
char gbuf[CBUFSIZE], *tptr;
|
||||
int32 i;
|
||||
|
||||
tptr = get_glyph (cptr, gbuf, term); /* get glyph */
|
||||
for (i = 1; i < 4; i++) { /* symbol match? */
|
||||
if (strcmp (gbuf, opname[i]) == 0) {
|
||||
val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */
|
||||
return tptr; } }
|
||||
return cptr; /* original ptr */
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 i, j, k;
|
||||
char *tptr, gbuf[CBUFSIZE];
|
||||
|
||||
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] = (t_value) cptr[0] & 0177;
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (((t_value) cptr[0] & 0177) << 8) |
|
||||
((t_value) cptr[1] & 0177);
|
||||
return SCPE_OK; }
|
||||
|
||||
/* Instruction parse */
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i] == NULL) return SCPE_ARG;
|
||||
val[0] = opc_val[i] & DMASK; /* get value */
|
||||
j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case F_V_FO: /* func out */
|
||||
tptr = strchr (cptr, ','); /* find dst */
|
||||
if (!tptr) return SCPE_ARG; /* none? */
|
||||
*tptr = 0; /* split fields */
|
||||
cptr = get_fnc (cptr, val); /* fo # */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (tptr + 1, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_FOI: /* func out impl */
|
||||
cptr = get_fnc (cptr, val); /* fo # */
|
||||
break;
|
||||
case F_V_SF: /* skip func */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
case F_V_SFI: /* skip func impl */
|
||||
cptr = get_fnc (cptr, val); /* fo # */
|
||||
break;
|
||||
case F_V_RR: /* reg-reg */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (cptr, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_ZR: /* zero-reg */
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (cptr, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_RS: /* reg self */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
val[0] = val[0] | I_GETSRC (val[0]); /* duplicate */
|
||||
cptr = get_op (cptr, val, 0); /* op */
|
||||
break;
|
||||
case F_V_JC: /* jump cond */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* cond */
|
||||
for (k = 0; k < 8; k++) { /* symbol? */
|
||||
if (strcmp (gbuf, cdname[k]) == 0) break; }
|
||||
if (k >= 8) return SCPE_ARG;
|
||||
val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */
|
||||
case F_V_JU: /* jump uncond */
|
||||
cptr = get_ma (cptr, val, 0); /* addr */
|
||||
break;
|
||||
case F_V_RM: /* reg mem */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
case F_V_ZM: /* zero mem */
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_ma (cptr, val, 0); /* addr */
|
||||
break;
|
||||
case F_V_MR: /* mem reg */
|
||||
cptr = get_ma (cptr, val, ','); /* addr */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (cptr, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_MS: /* mem self */
|
||||
cptr = get_ma (cptr, val, ','); /* addr */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_op (cptr, val, 0); /* op */
|
||||
break; }
|
||||
if (!cptr || (*cptr != 0)) return SCPE_ARG; /* junk at end? */
|
||||
return (j >= F_2WD)? -1: SCPE_OK;
|
||||
}
|
||||
1088
H316/h316_cpu.c
1088
H316/h316_cpu.c
File diff suppressed because it is too large
Load Diff
144
H316/h316_defs.h
144
H316/h316_defs.h
@@ -1,144 +0,0 @@
|
||||
/* h316_defs.h: Honeywell 316/516 simulator definitions
|
||||
|
||||
Copyright (c) 1999-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_RSRV 1 /* must be 1 */
|
||||
#define STOP_IODV 2 /* must be 2 */
|
||||
#define STOP_HALT 3 /* HALT */
|
||||
#define STOP_IBKPT 4 /* breakpoint */
|
||||
#define STOP_IND 5 /* indirect loop */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 32768 /* max memory size */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define X_AMASK (MAXMEMSIZE - 1) /* ext address mask */
|
||||
#define NX_AMASK ((MAXMEMSIZE / 2) - 1) /* nx address mask */
|
||||
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
|
||||
|
||||
/* Architectural constants */
|
||||
|
||||
#define SIGN 0100000 /* sign */
|
||||
#define DMASK 0177777 /* data mask */
|
||||
#define MMASK (DMASK & ~SIGN) /* magnitude mask */
|
||||
#define XR M[0]
|
||||
#define M_CLK 061 /* clock location */
|
||||
#define M_RSTINT 062 /* restrict int */
|
||||
#define M_INT 063 /* int location */
|
||||
|
||||
/* CPU options */
|
||||
|
||||
#define UNIT_V_EXT (UNIT_V_UF + 1) /* extended mem */
|
||||
#define UNIT_V_HSA (UNIT_V_UF + 2) /* high speed arith */
|
||||
#define UNIT_EXT (1u << UNIT_V_EXT)
|
||||
#define UNIT_HSA (1u << UNIT_V_HSA)
|
||||
|
||||
/* Instruction format */
|
||||
|
||||
#define I_M_OP 077 /* opcode */
|
||||
#define I_V_OP 10
|
||||
#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP)
|
||||
#define I_M_FNC 017 /* function */
|
||||
#define I_V_FNC 6
|
||||
#define I_GETFNC(x) (((x) >> I_V_FNC) & I_M_FNC)
|
||||
#define IA 0100000 /* indirect address */
|
||||
#define IDX 0040000 /* indexed */
|
||||
#define SC 0001000 /* sector */
|
||||
#define DISP 0000777 /* page displacement */
|
||||
#define PAGENO 0077000 /* page number */
|
||||
#define INCLRA (010 << I_V_FNC) /* INA clear A */
|
||||
#define DEVMASK 0000077 /* device mask */
|
||||
#define SHFMASK 0000077 /* shift mask */
|
||||
|
||||
/* I/O opcodes */
|
||||
|
||||
#define ioOCP 0 /* output control */
|
||||
#define ioSKS 1 /* skip if set */
|
||||
#define ioINA 2 /* input to A */
|
||||
#define ioOTA 3 /* output from A */
|
||||
|
||||
/* I/O devices */
|
||||
|
||||
#define PTR 001 /* paper tape reader */
|
||||
#define PTP 002 /* paper tape punch */
|
||||
#define LPT 003 /* line printer */
|
||||
#define TTY 004 /* console */
|
||||
#define CDR 005 /* card reader */
|
||||
#define MT 010 /* mag tape data */
|
||||
#define KEYS 020 /* keys (CPU) */
|
||||
#define FHD 022 /* fixed head disk */
|
||||
#define DMA 024 /* DMA control */
|
||||
#define DP 025 /* moving head disk */
|
||||
#define OPT 034 /* SKS/OCP option */
|
||||
|
||||
/* Interrupt flags, definitions correspond to SMK bits */
|
||||
|
||||
#define INT_V_CLK 0 /* clock */
|
||||
#define INT_V_MPE 1 /* parity error */
|
||||
#define INT_V_LPT 2 /* line printer */
|
||||
#define INT_V_CDR 4 /* card reader */
|
||||
#define INT_V_TTY 5 /* teletype */
|
||||
#define INT_V_PTP 6 /* paper tape punch */
|
||||
#define INT_V_PTR 7 /* paper tape reader */
|
||||
#define INT_V_FHD 8 /* fixed head disk */
|
||||
#define INT_V_DP 12 /* moving head disk */
|
||||
#define INT_V_MT 15 /* mag tape */
|
||||
#define INT_V_NODEF 16 /* int not deferred */
|
||||
#define INT_V_ON 17 /* int on */
|
||||
|
||||
/* I/O macros */
|
||||
|
||||
#define IOT_V_REASON 17
|
||||
#define IOT_V_SKIP 16
|
||||
#define IOT_SKIP (1u << IOT_V_SKIP)
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
|
||||
#define IOBADFNC(x) (((stop_inst) << IOT_V_REASON) | (x))
|
||||
#define IOSKIP(x) (IOT_SKIP | (x))
|
||||
|
||||
#define INT_CLK (1u << INT_V_CLK)
|
||||
#define INT_MPE (1u << INT_V_MPE)
|
||||
#define INT_LPT (1u << INT_V_LPT)
|
||||
#define INT_CDR (1u << INT_V_CDR)
|
||||
#define INT_TTY (1u << INT_V_TTY)
|
||||
#define INT_PTP (1u << INT_V_PTP)
|
||||
#define INT_PTR (1u << INT_V_PTR)
|
||||
#define INT_FHD (1u << INT_V_FHD)
|
||||
#define INT_DP (1u << INT_V_DP)
|
||||
#define INT_MT (1u << INT_V_MT)
|
||||
#define INT_NODEF (1u << INT_V_NODEF)
|
||||
#define INT_ON (1u << INT_V_ON)
|
||||
#define INT_PENDING (INT_ON | INT_NODEF)
|
||||
|
||||
#define SET_READY(x) dev_ready = dev_ready | (x)
|
||||
#define CLR_READY(x) dev_ready = dev_ready & ~(x)
|
||||
#define TST_READY(x) ((dev_ready & (x)) != 0)
|
||||
#define CLR_ENABLE(x) dev_enable = dev_enable & ~(x)
|
||||
#define TST_INTREQ(x) ((dev_ready & dev_enable & (x)) != 0)
|
||||
@@ -1,320 +0,0 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: H316 Simulator Usage
|
||||
Date: 15-Jul-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2003, written by Robert M Supnik
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This memorandum documents the Honeywell 316/516 simulator.
|
||||
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
The H316 requires the following files:
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_sock.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/h316/ h316_defs.h
|
||||
h316_cpu.c
|
||||
h316_lp.c
|
||||
h316_stddev.c
|
||||
h316_sys.c
|
||||
|
||||
2. H316/H516 Features
|
||||
|
||||
The Honeywell 316/516 simulator is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU H316/H516 CPU with 16/32KW memory
|
||||
PTR 316/516-50 paper tape reader
|
||||
PTP 316/516-52 paper tape punch
|
||||
TTY 316/516-33 console terminal
|
||||
CLK 316/516-12 real time clock
|
||||
LPT 316/516 line printer
|
||||
|
||||
The H316/H516 simulator implements several unique stop conditions:
|
||||
|
||||
- decode of an undefined instruction, and STOP_INST is et
|
||||
- reference to an undefined I/O device, and STOP_DEV is set
|
||||
- more than INDMAX indirect references are detected during
|
||||
memory reference address decoding
|
||||
|
||||
The H316/H516 loader is not implemented.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
CPU options include choice of instruction set and memory size.
|
||||
|
||||
SET CPU HSA high speed arithmetic instructions
|
||||
SET CPU NOHSA no high speed arithmetic instructions
|
||||
SET CPU 4K set memory size = 4K
|
||||
SET CPU 8K set memory size = 8K
|
||||
SET CPU 12K set memory size = 12K
|
||||
SET CPU 16K set memory size = 16K
|
||||
SET CPU 24K set memory size = 24K
|
||||
SET CPU 32K set memory size = 32K
|
||||
|
||||
If memory size is being reduced, and the memory being truncated contains
|
||||
non-zero data, the simulator asks for confirmation. Data in the truncated
|
||||
portion of memory is lost. Initial memory size is 32K.
|
||||
|
||||
CPU registers include the visible state of the processor as well as the
|
||||
control registers for the interrupt system.
|
||||
|
||||
name size comments
|
||||
|
||||
P 15 program counter
|
||||
A 16 A register
|
||||
B 16 B register
|
||||
X 16 index register
|
||||
SC 16 shift count
|
||||
C 1 carry flag
|
||||
EXT 1 extend flag
|
||||
PME 1 previous mode extend flag
|
||||
EXT_OFF 1 extend off pending flag
|
||||
DP 1 double precision flag
|
||||
SS1..4 1 sense switches 1..4
|
||||
ION 1 interrupts enabled
|
||||
INODEF 1 interrupts not deferred
|
||||
INTREQ 16 interrupt requests
|
||||
DEVRDY 16 device ready flags (read only)
|
||||
DEVENB 16 device interrupt enable flags (read only)
|
||||
STOP_INST 1 stop on undefined instruction
|
||||
STOP_DEV 1 stop on undefined device
|
||||
INDMAX 1 indirect address limit
|
||||
PCQ[0:63] 15 PC prior to last JMP, JSB, or interrupt;
|
||||
most recent PC change first
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 Programmed I/O Devices
|
||||
|
||||
2.2.1 316/516-50 Paper Tape Reader (PTR)
|
||||
|
||||
The paper tape reader (PTR) reads data from a disk file. The POS
|
||||
register specifies the number of the next data item to be read.
|
||||
Thus, by changing POS, the user can backspace or advance the reader.
|
||||
|
||||
The paper tape reader supports the BOOT command. BOOT PTR copies the
|
||||
absolute binary loader into memory and starts it running.
|
||||
|
||||
The paper tape reader implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
INTREQ 1 device interrupt request
|
||||
READY 1 device ready
|
||||
ENABLE 1 device interrupts enabled
|
||||
POS 32 position in the input or output file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
end of file 1 report error and stop
|
||||
0 out of tape or paper
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.2 316/516-52 Paper Tape Punch (PTP)
|
||||
|
||||
The paper tape punch (PTP) writes data to a disk file. The POS
|
||||
register specifies the number of the next data item to be written.
|
||||
Thus, by changing POS, the user can backspace or advance the punch.
|
||||
|
||||
The paper tape punch implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
INTREQ 1 device interrupt request
|
||||
READY 1 device ready
|
||||
ENABLE 1 device interrupts enabled
|
||||
POWER 1 device powered up
|
||||
POS 32 position in the input or output file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
PWRTIME 24 time from I/O request to power up
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.3 316/516-33 Console Teletype (TTY)
|
||||
|
||||
The Teletype units (TTY0, TTY1) can be set to one of three modes:
|
||||
KSR, 7B, or 8B. In KSR mode, lower case input and output characters
|
||||
are automatically converted to upper case, and the high order bit is
|
||||
forced to one on input. In 7B mode, input and output characters are
|
||||
masked to 7 bits. In 8B mode, characters are not modified. Changing
|
||||
the mode of either unit changes both. The default mode is KSR.
|
||||
|
||||
The Teletype reads from the console keyboard and writes to the
|
||||
simulator console window. It implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
MODE 1 read/write mode
|
||||
INTREQ 1 device interrupt request
|
||||
READY 1 device ready
|
||||
ENABLE 1 device interrupts enabled
|
||||
KPOS 32 number of characters input
|
||||
KTIME 24 keyboard polling interval
|
||||
TPOS 32 number of characters output
|
||||
TTIME 24 time from I/O initiation to interrupt
|
||||
|
||||
2.2.4 316/516-12 Real Time Clock (CLK)
|
||||
|
||||
The real time clock (CLK) frequency can be adjusted as follows:
|
||||
|
||||
SET CLK 60HZ set frequency to 60Hz
|
||||
SET CLK 50HZ set frequency to 50Hz
|
||||
|
||||
The default is 60Hz.
|
||||
|
||||
The clock implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
INTREQ 1 device interrupt request
|
||||
READY 1 device ready
|
||||
ENABLE 1 device interrupts enabled
|
||||
TIME 24 clock interval
|
||||
|
||||
The real-time clock autocalibrates; the clock interval is adjusted up or
|
||||
down so that the clock tracks actual elapsed time.
|
||||
|
||||
2.2.5 316/516 Line Printer (LPT)
|
||||
|
||||
The line printer (LPT) writes data to a disk file. The POS register
|
||||
specifies the number of the next data item to be written. Thus,
|
||||
by changing POS, the user can backspace or advance the printer.
|
||||
|
||||
The line printer implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
WDPOS 6 word position in current scan
|
||||
DRPOS 6 drum position
|
||||
CRPOS 1 carriage position
|
||||
XFER 1 transfer ready flag
|
||||
PRDN 1 print done flag
|
||||
INTREQ 1 device interrupt request
|
||||
ENABLE 1 device interrupt enable
|
||||
SVCST 2 service state
|
||||
SVCCH 2 service channel
|
||||
BUF 8 buffer
|
||||
POS 32 number of characters output
|
||||
XTIME 24 delay between transfers
|
||||
ETIME 24 delay at end of scan
|
||||
PTIME 24 delay for shuttle/line advance
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of paper
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.3 Symbolic Display and Input
|
||||
|
||||
The H316/H516 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-a display as ASCII character
|
||||
-c display as two character string
|
||||
-m display instruction mnemonics
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or -a ASCII character
|
||||
" or -c two character sixbit string
|
||||
alphabetic instruction mnemonic
|
||||
numeric octal number
|
||||
|
||||
Instruction input uses standard H316/H516 assembler syntax. There are six
|
||||
instruction classes: memory reference, I/O, control, shift, skip, and
|
||||
operate.
|
||||
|
||||
Memory reference instructions have the format
|
||||
|
||||
memref{*} {C/Z} address{,1}
|
||||
|
||||
where * signifies indirect, C a current sector reference, Z a sector zero
|
||||
reference, and 1 indexed. The address is an octal number in the range 0 -
|
||||
077777; if C or Z is specified, the address is a page offset in the range
|
||||
0 - 0777. Normally, C is not needed; the simulator figures out from the
|
||||
address what mode to use. However, when referencing memory outside the CPU,
|
||||
there is no valid PC, and C must be used to specify current sector addressing.
|
||||
|
||||
I/O instructions have the format
|
||||
|
||||
io pulse+device
|
||||
|
||||
The pulse+device is an octal number in the range 0 - 01777.
|
||||
|
||||
Control and operate instructions consist of a single opcode
|
||||
|
||||
opcode
|
||||
|
||||
Shift instructions have the format
|
||||
|
||||
shift n
|
||||
|
||||
where n is an octal number in the range 0-77.
|
||||
|
||||
Skip instructions have the format
|
||||
|
||||
sub-op sub-op sub-op...
|
||||
|
||||
The simulator checks that the combination of sub-opcodes is legal.
|
||||
261
H316/h316_lp.c
261
H316/h316_lp.c
@@ -1,261 +0,0 @@
|
||||
/* h316_lp.c: Honeywell 316/516 line printer
|
||||
|
||||
Copyright (c) 1999-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
lpt line printer
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
|
||||
The Series 16 line printer is an unbuffered Analex shuttle printer.
|
||||
Because it was unbuffered, the CPU had to scan out an entire line's
|
||||
worth of characters (60 words) for every character on the print drum
|
||||
(64 characters). Because it was a shuttle printer, the entire
|
||||
process must be repeated first for the odd columns and then for the
|
||||
even columns. After scanning the odd columns, the printer carriage
|
||||
shuttled right by one column; after scanning the even columns, the
|
||||
carriage shuttled left. This halved the number of hammers required,
|
||||
reducing cost but increasing mechanical complexity.
|
||||
|
||||
The real printer is very timing dependent. If the CPU misses a
|
||||
scan, then the wrong characters are printed. If the printer protocol
|
||||
is violated, then results are unpredictable. The simulated printer
|
||||
is much more forgiving. Rather than simulating the fixed drum and
|
||||
hammer timing of the real printer, the simulator is driven by the
|
||||
program's OTA instructions. If the program misses a time slot, the
|
||||
simulator will still print the "correct" result. A timing based
|
||||
simulation would be very hard to do in the absense of accurate
|
||||
instruction timing.
|
||||
|
||||
Printer state is maintained in a set of position and state variables:
|
||||
|
||||
lpt_wdpos word count within a line scan (0-59)
|
||||
lpt_drpos drum position (0-63)
|
||||
lpt_crpos carriage position (0-1)
|
||||
lpt_svcst service state (shuttle, paper advance)
|
||||
lpt_svcch channel for paper advance (0 = no adv)
|
||||
lpt_xfer transfer ready flag
|
||||
lpt_prdn printing done flag
|
||||
*/
|
||||
|
||||
#include "h316_defs.h"
|
||||
|
||||
#define LPT_WIDTH 120 /* width */
|
||||
#define LPT_SCAN (LPT_WIDTH / 2) /* words/scan */
|
||||
#define LPT_DRUM 64 /* drum rows */
|
||||
#define LPT_SVCSH 01 /* shuttle */
|
||||
#define LPT_SVCPA 02 /* paper advance */
|
||||
|
||||
extern int32 dev_ready, dev_enable;
|
||||
extern int32 stop_inst;
|
||||
|
||||
int32 lpt_wdpos = 0; /* word position */
|
||||
int32 lpt_drpos = 0; /* drum position */
|
||||
int32 lpt_crpos = 0; /* carriage position */
|
||||
int32 lpt_svcst = 0; /* service state */
|
||||
int32 lpt_svcch = 0; /* service channel */
|
||||
int32 lpt_xfer = 0; /* transfer flag */
|
||||
int32 lpt_prdn = 1; /* printing done */
|
||||
char lpt_buf[LPT_WIDTH + 1] = { 0 }; /* line buffer */
|
||||
int32 lpt_xtime = 5; /* transfer time */
|
||||
int32 lpt_etime = 50; /* end of scan time */
|
||||
int32 lpt_ptime = 5000; /* paper adv time */
|
||||
int32 lpt_stopioe = 0; /* stop on error */
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr);
|
||||
t_stat lpt_reset (DEVICE *dptr);
|
||||
|
||||
/* LPT data structures
|
||||
|
||||
lpt_dev LPT device descriptor
|
||||
lpt_unit LPT unit descriptor
|
||||
lpt_mod LPT modifiers
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0) };
|
||||
|
||||
REG lpt_reg[] = {
|
||||
{ DRDATA (WDPOS, lpt_wdpos, 6) },
|
||||
{ DRDATA (DRPOS, lpt_drpos, 6) },
|
||||
{ FLDATA (CRPOS, lpt_crpos, 0) },
|
||||
{ FLDATA (XFER, lpt_xfer, 0) },
|
||||
{ FLDATA (PRDN, lpt_prdn, 0) },
|
||||
{ FLDATA (INTREQ, dev_ready, INT_V_LPT) },
|
||||
{ FLDATA (ENABLE, dev_enable, INT_V_LPT) },
|
||||
{ ORDATA (SVCST, lpt_svcst, 2) },
|
||||
{ ORDATA (SVCCH, lpt_svcch, 2) },
|
||||
{ BRDATA (BUF, lpt_buf, 8, 8, 120) },
|
||||
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (XTIME, lpt_xtime, 24), PV_LEFT },
|
||||
{ DRDATA (ETIME, lpt_etime, 24), PV_LEFT },
|
||||
{ DRDATA (PTIME, lpt_ptime, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE lpt_dev = {
|
||||
"LPT", &lpt_unit, lpt_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &lpt_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* IO routine */
|
||||
|
||||
int32 lptio (int32 inst, int32 fnc, int32 dat)
|
||||
{
|
||||
int32 chr;
|
||||
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOCP: /* OCP */
|
||||
switch (fnc) { /* case on fnc */
|
||||
case 000: case 002: case 004: /* paper adv */
|
||||
lpt_svcst = lpt_svcst | LPT_SVCPA; /* set state */
|
||||
lpt_svcch = fnc >> 1; /* save channel */
|
||||
sim_activate (&lpt_unit, lpt_ptime);
|
||||
CLR_READY (INT_LPT); /* clear int */
|
||||
break;
|
||||
case 007: /* init scan */
|
||||
lpt_prdn = 0; /* clear pr done */
|
||||
lpt_wdpos = 0; /* init scan pos */
|
||||
if (!sim_is_active (&lpt_unit)) lpt_xfer = 1;
|
||||
CLR_READY (INT_LPT); /* clear int */
|
||||
break;
|
||||
default:
|
||||
return IOBADFNC (dat); }
|
||||
break;
|
||||
|
||||
case ioSKS: /* SKS */
|
||||
switch (fnc) { /* case on fnc */
|
||||
case 000: /* if xfer rdy */
|
||||
if (lpt_xfer) return IOSKIP (dat);
|
||||
break;
|
||||
case 002: /* if !alarm */
|
||||
if (lpt_unit.flags & UNIT_ATT) return IOSKIP (dat);
|
||||
break;
|
||||
case 003: /* if odd col */
|
||||
if (lpt_crpos) return IOSKIP (dat);
|
||||
break;
|
||||
case 004: /* if !interrupt */
|
||||
if (!TST_INTREQ (INT_LPT)) return IOSKIP (dat);
|
||||
break;
|
||||
case 011: /* if line printed */
|
||||
if (lpt_prdn) return IOSKIP (dat);
|
||||
break;
|
||||
case 012: /* if !shuttling */
|
||||
if (!(lpt_svcst & LPT_SVCSH)) return IOSKIP (dat);
|
||||
break;
|
||||
case 013:
|
||||
if (lpt_prdn && !(lpt_svcst & LPT_SVCSH)) return IOSKIP (dat);
|
||||
break;
|
||||
case 014: /* if !advancing */
|
||||
if (!(lpt_svcst & LPT_SVCPA)) return IOSKIP (dat);
|
||||
break;
|
||||
case 015:
|
||||
if (lpt_prdn && !(lpt_svcst & LPT_SVCPA)) return IOSKIP (dat);
|
||||
break;
|
||||
case 016:
|
||||
if (!(lpt_svcst & (LPT_SVCSH | LPT_SVCPA))) return IOSKIP (dat);
|
||||
break;
|
||||
case 017:
|
||||
if (lpt_prdn && !(lpt_svcst & (LPT_SVCSH | LPT_SVCPA)))
|
||||
return IOSKIP (dat);
|
||||
break;
|
||||
default:
|
||||
return IOBADFNC (dat); }
|
||||
break;
|
||||
|
||||
case ioOTA: /* OTA */
|
||||
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
|
||||
if (lpt_xfer) { /* xfer ready? */
|
||||
lpt_xfer = 0; /* clear xfer */
|
||||
chr = (dat >> (lpt_crpos? 0: 8)) & 077; /* get 6b char */
|
||||
if (chr == lpt_drpos) { /* match drum pos? */
|
||||
if (chr < 040) chr = chr | 0100;
|
||||
lpt_buf[2 * lpt_wdpos + lpt_crpos] = chr; }
|
||||
lpt_wdpos++; /* adv scan pos */
|
||||
if (lpt_wdpos >= LPT_SCAN) { /* end of scan? */
|
||||
lpt_wdpos = 0; /* reset scan pos */
|
||||
lpt_drpos++; /* adv drum pos */
|
||||
if (lpt_drpos >= LPT_DRUM) { /* end of drum? */
|
||||
lpt_drpos = 0; /* reset drum pos */
|
||||
lpt_crpos = lpt_crpos ^ 1; /* shuttle */
|
||||
lpt_svcst = lpt_svcst | LPT_SVCSH;
|
||||
sim_activate (&lpt_unit, lpt_ptime);
|
||||
} /* end if shuttle */
|
||||
else sim_activate (&lpt_unit, lpt_etime);
|
||||
} /* end if endscan */
|
||||
else sim_activate (&lpt_unit, lpt_xtime);
|
||||
return IOSKIP (dat); } /* skip return */
|
||||
break; } /* end case op */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i;
|
||||
static const char *lpt_cc[] = {
|
||||
"\r",
|
||||
"\n",
|
||||
"\n\f",
|
||||
"\n" };
|
||||
|
||||
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (lpt_stopioe, SCPE_UNATT);
|
||||
lpt_xfer = 1;
|
||||
if (lpt_svcst & LPT_SVCSH) { /* shuttling */
|
||||
SET_READY (INT_LPT); /* interrupt */
|
||||
if (lpt_crpos == 0) lpt_prdn = 1; }
|
||||
if (lpt_svcst & LPT_SVCPA) { /* paper advance */
|
||||
SET_READY (INT_LPT); /* interrupt */
|
||||
for (i = LPT_WIDTH - 1; i >= 0; i++) {
|
||||
if (lpt_buf[i] != ' ') break; }
|
||||
lpt_buf[i + 1] = 0;
|
||||
fputs (lpt_buf, uptr->fileref); /* output buf */
|
||||
fputs (lpt_cc[lpt_svcch & 03], uptr->fileref); /* output eol */
|
||||
uptr->pos = ftell (uptr->fileref); /* update pos */
|
||||
for (i = 0; i < LPT_WIDTH; i++) lpt_buf[i] = ' '; /* clear buf */
|
||||
}
|
||||
lpt_svcst = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat lpt_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
lpt_wdpos = lpt_drpos = lpt_crpos = 0; /* clear positions */
|
||||
lpt_svcst = lpt_svcch = 0; /* idle state */
|
||||
lpt_xfer = 0; /* not rdy to xfer */
|
||||
lpt_prdn = 1; /* printing done */
|
||||
for (i = 0; i < LPT_WIDTH; i++) lpt_buf[i] = ' '; /* clear buffer */
|
||||
lpt_buf[LPT_WIDTH] = 0;
|
||||
CLR_READY (INT_LPT); /* clear int, enb */
|
||||
CLR_ENABLE (INT_LPT);
|
||||
sim_cancel (&lpt_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,539 +0,0 @@
|
||||
/* h316_stddev.c: Honeywell 316/516 standard devices
|
||||
|
||||
Copyright (c) 1999-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
ptr 316/516-50 paper tape reader
|
||||
ptp 316/516-52 paper tape punch
|
||||
tty 316/516-33 teleprinter
|
||||
clk/options 316/516-12 real time clocks/internal options
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
01-Mar-03 RMS Added SET/SHOW CLK FREQ support
|
||||
22-Dec-02 RMS Added break support
|
||||
01-Nov-02 RMS Added 7b/8b support to terminal
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
03-Nov-01 RMS Implemented upper case for console output
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
*/
|
||||
|
||||
#include "h316_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
|
||||
#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */
|
||||
#define UNIT_8B (1 << UNIT_V_8B)
|
||||
#define UNIT_KSR (1 << UNIT_V_KSR)
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 PC;
|
||||
extern int32 stop_inst;
|
||||
extern int32 C, dp, ext, extoff_pending, sc;
|
||||
extern int32 dev_ready, dev_enable;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
|
||||
int32 ptp_power = 0, ptp_ptime; /* punch power, time */
|
||||
int32 tty_mode = 0, tty_buf = 0; /* tty mode, buf */
|
||||
int32 clk_tps = 60; /* ticks per second */
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat tty_reset (DEVICE *dptr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
/* PTR data structures
|
||||
|
||||
ptr_dev PTR device descriptor
|
||||
ptr_unit PTR unit descriptor
|
||||
ptr_mod PTR modifiers
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
UNIT ptr_unit = {
|
||||
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
|
||||
SERIAL_IN_WAIT };
|
||||
|
||||
REG ptr_reg[] = {
|
||||
{ ORDATA (BUF, ptr_unit.buf, 8) },
|
||||
{ FLDATA (READY, dev_ready, INT_V_PTR) },
|
||||
{ FLDATA (ENABLE, dev_enable, INT_V_PTR) },
|
||||
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
&ptr_boot, NULL, NULL };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
ptp_dev PTP device descriptor
|
||||
ptp_unit PTP unit descriptor
|
||||
ptp_mod PTP modifiers
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ ORDATA (BUF, ptp_unit.buf, 8) },
|
||||
{ FLDATA (READY, dev_ready, INT_V_PTP) },
|
||||
{ FLDATA (ENABLE, dev_enable, INT_V_PTP) },
|
||||
{ FLDATA (POWER, ptp_power, 0) },
|
||||
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
|
||||
{ DRDATA (PWRTIME, ptp_ptime, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* TTY data structures
|
||||
|
||||
tty_dev TTY device descriptor
|
||||
tty_unit TTY unit descriptor
|
||||
tty_reg TTY register list
|
||||
tty_mod TTy modifiers list
|
||||
*/
|
||||
|
||||
#define TTI 0
|
||||
#define TTO 1
|
||||
|
||||
UNIT tty_unit[] = {
|
||||
{ UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT },
|
||||
{ UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT } };
|
||||
|
||||
REG tty_reg[] = {
|
||||
{ ORDATA (BUF, tty_buf, 8) },
|
||||
{ FLDATA (MODE, tty_mode, 0) },
|
||||
{ FLDATA (READY, dev_ready, INT_V_TTY) },
|
||||
{ FLDATA (ENABLE, dev_enable, INT_V_TTY) },
|
||||
{ DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tty_mod[] = {
|
||||
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode },
|
||||
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode },
|
||||
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tty_dev = {
|
||||
"TTY", tty_unit, tty_reg, tty_mod,
|
||||
2, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tty_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* CLK data structures
|
||||
|
||||
clk_dev CLK device descriptor
|
||||
clk_unit CLK unit descriptor
|
||||
clk_mod CLK modifiers
|
||||
clk_reg CLK register list
|
||||
*/
|
||||
|
||||
UNIT clk_unit = {
|
||||
UDATA (&clk_svc, 0, 0), 16000 };
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ FLDATA (READY, dev_ready, INT_V_CLK) },
|
||||
{ FLDATA (ENABLE, dev_enable, INT_V_CLK) },
|
||||
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB clk_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
|
||||
&clk_set_freq, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
|
||||
&clk_set_freq, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
|
||||
NULL, &clk_show_freq, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE clk_dev = {
|
||||
"CLK", &clk_unit, clk_reg, clk_mod,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &clk_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Paper tape reader: IO routine */
|
||||
|
||||
int32 ptrio (int32 inst, int32 fnc, int32 dat)
|
||||
{
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOCP: /* OCP */
|
||||
if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
|
||||
if (fnc) sim_cancel (&ptr_unit); /* fnc 1? stop */
|
||||
else sim_activate (&ptr_unit, ptr_unit.wait); /* fnc 0? start */
|
||||
break;
|
||||
case ioSKS: /* SKS */
|
||||
if (fnc & 013) return IOBADFNC (dat); /* only fnc 0,4 */
|
||||
if (((fnc == 0) && TST_READY (INT_PTR)) || /* fnc 0? skip rdy */
|
||||
((fnc == 4) && !TST_INTREQ (INT_PTR))) /* fnc 4? skip !int */
|
||||
return IOSKIP (dat);
|
||||
break;
|
||||
case ioINA: /* INA */
|
||||
if (fnc & 007) return IOBADFNC (dat); /* only fnc 0,10 */
|
||||
if (TST_READY (INT_PTR)) { /* ready? */
|
||||
CLR_READY (INT_PTR); /* clear ready */
|
||||
return IOSKIP (ptr_unit.buf | dat); } /* ret buf, skip */
|
||||
break; } /* end case op */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ptr_stopioe, SCPE_UNATT);
|
||||
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */
|
||||
if (feof (ptr_unit.fileref)) {
|
||||
if (ptr_stopioe) printf ("PTR end of file\n");
|
||||
else return SCPE_OK; }
|
||||
else perror ("PTR I/O error");
|
||||
clearerr (ptr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
SET_READY (INT_PTR); /* set ready flag */
|
||||
ptr_unit.buf = temp & 0377; /* get byte */
|
||||
ptr_unit.pos = ftell (ptr_unit.fileref); /* update pos */
|
||||
sim_activate (&ptr_unit, ptr_unit.wait); /* reactivate */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
CLR_READY (INT_PTR); /* clear ready, enb */
|
||||
CLR_ENABLE (INT_PTR);
|
||||
ptr_unit.buf = 0; /* clear buffer */
|
||||
sim_cancel (&ptr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape reader bootstrap routine */
|
||||
|
||||
#define PBOOT_START 1
|
||||
#define PBOOT_SIZE (sizeof (pboot) / sizeof (int32))
|
||||
|
||||
static const int32 pboot[] = {
|
||||
0010057, /* STA 57 */
|
||||
0030001, /* OCP 1 */
|
||||
0131001, /* READ, INA 1001 */
|
||||
0002003, /* JMP READ */
|
||||
0101040, /* SNZ */
|
||||
0002003, /* JMP READ */
|
||||
0010000, /* STA 0 */
|
||||
0131001, /* READ1, INA 1001 */
|
||||
0002010, /* JMP READ1 */
|
||||
0041470, /* LGL 8 */
|
||||
0130001, /* READ2, INA 1 */
|
||||
0002013, /* JMP READ2 */
|
||||
0110000, /* STA* 0 */
|
||||
0024000, /* IRS 0 */
|
||||
0100040 /* SZE */
|
||||
};
|
||||
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */
|
||||
M[PBOOT_START + i] = pboot[i];
|
||||
PC = PBOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape punch: IO routine */
|
||||
|
||||
int32 ptpio (int32 inst, int32 fnc, int32 dat)
|
||||
{
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOCP: /* OCP */
|
||||
if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
|
||||
if (fnc) { /* fnc 1? pwr off */
|
||||
CLR_READY (INT_PTP); /* not ready */
|
||||
ptp_power = 0; /* turn off power */
|
||||
sim_cancel (&ptp_unit); } /* stop punch */
|
||||
else if (ptp_power == 0) /* fnc 0? start */
|
||||
sim_activate (&ptp_unit, ptp_ptime);
|
||||
break;
|
||||
case ioSKS: /* SKS */
|
||||
if ((fnc & 012) || (fnc == 005)) /* only 0, 1, 4 */
|
||||
return IOBADFNC (dat);
|
||||
if (((fnc == 00) && TST_READY (INT_PTP)) || /* fnc 0? skip rdy */
|
||||
((fnc == 01) /* fnc 1? skip ptp on */
|
||||
&& (ptp_power || sim_is_active (&ptp_unit))) ||
|
||||
((fnc == 04) && !TST_INTREQ (INT_PTP))) /* fnc 4? skip !int */
|
||||
return IOSKIP (dat);
|
||||
break;
|
||||
case ioOTA: /* OTA */
|
||||
if (fnc) return IOBADFNC (dat); /* only fnc 0 */
|
||||
if (TST_READY (INT_PTP)) { /* if ptp ready */
|
||||
CLR_READY (INT_PTP); /* clear ready */
|
||||
ptp_unit.buf = dat & 0377; /* store byte */
|
||||
sim_activate (&ptp_unit, ptp_unit.wait);
|
||||
return IOSKIP (dat); } /* skip return */
|
||||
break; }
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ptp_svc (UNIT *uptr)
|
||||
{
|
||||
|
||||
SET_READY (INT_PTP); /* set flag */
|
||||
if (ptp_power == 0) { /* power on? */
|
||||
ptp_power = 1; /* ptp is ready */
|
||||
return SCPE_OK; }
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ptp_stopioe, SCPE_UNATT);
|
||||
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */
|
||||
perror ("PTP I/O error");
|
||||
clearerr (ptp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
ptp_unit.pos = ftell (ptp_unit.fileref); /* update pos */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
CLR_READY (INT_PTP); /* clear ready, enb */
|
||||
CLR_ENABLE (INT_PTP);
|
||||
ptp_power = 0; /* power off */
|
||||
ptp_unit.buf = 0; /* clear buffer */
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Terminal: IO routine */
|
||||
|
||||
int32 ttyio (int32 inst, int32 fnc, int32 dat)
|
||||
{
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOCP: /* OCP */
|
||||
if (fnc & 016) return IOBADFNC (dat); /* only fnc 0,1 */
|
||||
if (fnc && (tty_mode == 0)) { /* input to output? */
|
||||
if (!sim_is_active (&tty_unit[TTO])) /* set ready */
|
||||
SET_READY (INT_TTY);
|
||||
tty_mode = 1; } /* mode is output */
|
||||
else if ((fnc == 0) && tty_mode) { /* output to input? */
|
||||
CLR_READY (INT_TTY); /* clear ready */
|
||||
tty_mode = 0; } /* mode is input */
|
||||
break;
|
||||
case ioSKS: /* SKS */
|
||||
if (fnc & 012) return IOBADFNC (dat); /* fnc 0,1,4,5 */
|
||||
if (((fnc == 0) && TST_READY (INT_TTY)) || /* fnc 0? skip rdy */
|
||||
((fnc == 1) && /* fnc 1? skip !busy */
|
||||
tty_mode && !sim_is_active (&tty_unit[TTO])) ||
|
||||
((fnc == 4) && !TST_INTREQ (INT_TTY)) || /* fnc 4? skip !int */
|
||||
((fnc == 5) && /* fnc 5? skip !xoff */
|
||||
!tty_mode && ((tty_buf & 0177) == 023)))
|
||||
return IOSKIP (dat);
|
||||
break;
|
||||
case ioINA: /* INA */
|
||||
if (fnc & 005) return IOBADFNC (dat); /* only 0,2,10,12 */
|
||||
if (TST_READY (INT_TTY)) { /* ready? */
|
||||
if (tty_mode == 0) CLR_READY (INT_TTY); /* inp? clear rdy */
|
||||
return IOSKIP (dat |
|
||||
(tty_buf & ((fnc & 002)? 077: 0377))); }
|
||||
break;
|
||||
case ioOTA:
|
||||
if (fnc & 015) return IOBADFNC (dat); /* only 0,2 */
|
||||
if (TST_READY (INT_TTY)) { /* ready? */
|
||||
tty_buf = dat & 0377; /* store char */
|
||||
if (fnc & 002) { /* binary mode? */
|
||||
tty_buf = tty_buf | 0100; /* set ch 7 */
|
||||
if (tty_buf & 040) tty_buf = tty_buf & 0277; }
|
||||
if (tty_mode) {
|
||||
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait);
|
||||
CLR_READY (INT_TTY); }
|
||||
return IOSKIP (dat); }
|
||||
break; } /* end case op */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service routines */
|
||||
|
||||
t_stat tti_svc (UNIT *uptr)
|
||||
{
|
||||
int32 out, c;
|
||||
|
||||
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
|
||||
out = c & 0177; /* mask echo to 7b */
|
||||
if (c & SCPE_BREAK) c = 0; /* break? */
|
||||
else if (tty_unit[TTI].flags & UNIT_KSR) { /* KSR? */
|
||||
if (islower (out)) out = toupper (out); /* cvt to UC */
|
||||
c = out | 0200; } /* add TTY bit */
|
||||
else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177);
|
||||
if (tty_mode == 0) { /* input mode? */
|
||||
tty_buf = c; /* put char in buf */
|
||||
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
|
||||
SET_READY (INT_TTY); /* set flag */
|
||||
if (out) sim_putchar (out); } /* echo */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c;
|
||||
t_stat r;
|
||||
|
||||
SET_READY (INT_TTY); /* set done flag */
|
||||
if (tty_unit[TTO].flags & UNIT_KSR) { /* UC only? */
|
||||
c = tty_buf & 0177; /* mask to 7b */
|
||||
if (islower (c)) c = toupper (c); } /* cvt to UC */
|
||||
else c = tty_buf & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177);
|
||||
if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output char */
|
||||
tty_unit[TTO].pos = tty_unit[TTO].pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tty_reset (DEVICE *dptr)
|
||||
{
|
||||
CLR_READY (INT_TTY); /* clear ready, enb */
|
||||
CLR_ENABLE (INT_TTY);
|
||||
tty_mode = 0; /* mode = input */
|
||||
tty_buf = 0;
|
||||
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */
|
||||
sim_cancel (&tty_unit[TTO]); /* cancel output */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
tty_unit[TTI].flags = (tty_unit[TTI].flags & ~(UNIT_KSR | UNIT_8B)) | val;
|
||||
tty_unit[TTO].flags = (tty_unit[TTO].flags & ~(UNIT_KSR | UNIT_8B)) | val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Clock/options: IO routine */
|
||||
|
||||
int32 clkio (int32 inst, int32 fnc, int32 dat)
|
||||
{
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOCP: /* OCP */
|
||||
if (fnc & 015) return IOBADFNC (dat); /* only fnc 0,2 */
|
||||
CLR_READY (INT_CLK); /* reset ready */
|
||||
if (fnc) sim_cancel (&clk_unit); /* fnc = 2? stop */
|
||||
else { /* fnc = 0? */
|
||||
if (!sim_is_active (&clk_unit))
|
||||
sim_activate (&clk_unit, /* activate */
|
||||
sim_rtc_init (clk_unit.wait)); } /* init calibr */
|
||||
break;
|
||||
case ioSKS: /* SKS */
|
||||
if (fnc == 0) { /* clock skip !int */
|
||||
if (!TST_INTREQ (INT_CLK)) return IOSKIP (dat); }
|
||||
else if ((fnc & 007) == 002) { /* mem parity? */
|
||||
if (((fnc == 002) && !TST_READY (INT_MPE)) ||
|
||||
((fnc == 012) && TST_READY (INT_MPE)))
|
||||
return IOSKIP (dat); }
|
||||
else return IOBADFNC (dat); /* invalid fnc */
|
||||
break;
|
||||
case ioOTA: /* OTA */
|
||||
if (fnc == 000) dev_enable = dat; /* SMK */
|
||||
else if (fnc == 010) { /* OTK */
|
||||
C = (dat >> 15) & 1; /* set C */
|
||||
if (cpu_unit.flags & UNIT_HSA) /* HSA included? */
|
||||
dp = (dat >> 14) & 1; /* set dp */
|
||||
if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */
|
||||
if (dat & 020000) { /* ext set? */
|
||||
ext = 1; /* yes, set */
|
||||
extoff_pending = 0; }
|
||||
else extoff_pending = 1; } /* no, clr later */
|
||||
sc = dat & 037; } /* set sc */
|
||||
else return IOBADFNC (dat);
|
||||
break; }
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
|
||||
M[M_CLK] = M[M_CLK + 1] & DMASK; /* increment mem ctr */
|
||||
if (M[M_CLK] == 0) SET_READY (INT_CLK); /* = 0? set flag */
|
||||
sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
CLR_READY (INT_CLK); /* clear ready, enb */
|
||||
CLR_ENABLE (INT_CLK);
|
||||
sim_cancel (&clk_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set frequency */
|
||||
|
||||
t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (cptr) return SCPE_ARG;
|
||||
if ((val != 50) && (val != 60)) return SCPE_IERR;
|
||||
clk_tps = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show frequency */
|
||||
|
||||
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
|
||||
return SCPE_OK;
|
||||
}
|
||||
346
H316/h316_sys.c
346
H316/h316_sys.c
@@ -1,346 +0,0 @@
|
||||
/* h316_sys.c: Honeywell 316/516 simulator interface
|
||||
|
||||
Copyright (c) 1999-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
17-Sep-01 RMS Removed multiconsole support
|
||||
*/
|
||||
|
||||
#include "h316_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE tty_dev, lpt_dev;
|
||||
extern DEVICE clk_dev;
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 M[];
|
||||
extern int32 sim_switches;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "H316";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 1;
|
||||
|
||||
DEVICE *sim_devices[] = { &cpu_dev,
|
||||
&ptr_dev, &ptp_dev,
|
||||
&tty_dev, &lpt_dev,
|
||||
&clk_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented instruction",
|
||||
"Unimplemented I/O device",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Indirect address loop" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
Tbs.
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
return SCPE_FMT;
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
|
||||
#define I_V_FL 16 /* flag start */
|
||||
#define I_M_FL 07 /* flag mask */
|
||||
#define I_V_NPN 0 /* no operand */
|
||||
#define I_V_MRF 1 /* mem ref */
|
||||
#define I_V_MRX 2 /* mem ref, no idx */
|
||||
#define I_V_IOT 3 /* I/O */
|
||||
#define I_V_SHF 4 /* shift */
|
||||
#define I_V_SK0 5 /* skip 0 */
|
||||
#define I_V_SK1 6 /* skip 1 */
|
||||
#define I_NPN (I_V_NPN << I_V_FL)
|
||||
#define I_MRF (I_V_MRF << I_V_FL)
|
||||
#define I_MRX (I_V_MRX << I_V_FL)
|
||||
#define I_IOT (I_V_IOT << I_V_FL)
|
||||
#define I_SHF (I_V_SHF << I_V_FL)
|
||||
#define I_SK0 (I_V_SK0 << I_V_FL)
|
||||
#define I_SK1 (I_V_SK1 << I_V_FL)
|
||||
|
||||
static const int32 masks[] = {
|
||||
0177777, 0136000, 0176000, 0176000,
|
||||
0177700, 0177000, 0177000 };
|
||||
|
||||
static const char *opcode[] = {
|
||||
"HLT", "SGL", "DBL",
|
||||
"DXA", "EXA", "RMP",
|
||||
"SCA", "INK", "NRM",
|
||||
"IAB", "ENB", "INH", "ERM",
|
||||
"CHS", "CRA", "SSP",
|
||||
"RCB", "CSA", "CMA",
|
||||
"TCA", "SSM", "SCB",
|
||||
"CAR", "CAL", "ICL",
|
||||
"AOA", "ACA", "ICR", "ICA",
|
||||
"NOP", "SKP", "SSR", "SSS",
|
||||
"JMP", "JMP*",
|
||||
"LDA", "LDA*", "ANA", "ANA*",
|
||||
"STA", "STA*", "ERA", "ERA*",
|
||||
"ADD", "ADD*", "SUB", "SUB*",
|
||||
"JST", "JST*", "CAS", "CAS*",
|
||||
"IRS", "IRS*", "IMA", "IMA*",
|
||||
"MPY", "MPY*", "DIV", "DIV*",
|
||||
"STX", "STX*", "LDX", "LDX*",
|
||||
"LRL", "LRS", "LRR",
|
||||
"LGR", "ARS", "ARR",
|
||||
"LLL", "LLS", "LLR",
|
||||
"LGL", "ALS", "ALR",
|
||||
"OCP", "SKS", "INA", "OTA",
|
||||
"SMK",
|
||||
"SPL", "SPN", "SLZ", /* encode only */
|
||||
"SZE", "SR1", "SR2",
|
||||
"SR3", "SR4", "SRC",
|
||||
"SMI", "SPS", "SLN",
|
||||
"SNZ", "SS1", "SS2",
|
||||
"SS3", "SS4", "SSC",
|
||||
NULL, NULL, /* decode only */
|
||||
NULL };
|
||||
|
||||
static const int32 opc_val[] = {
|
||||
0000000+I_NPN, 0000005+I_NPN, 0000007+I_NPN,
|
||||
0000011+I_NPN, 0000013+I_NPN, 0000021+I_NPN,
|
||||
0000041+I_NPN, 0000043+I_NPN, 0000101+I_NPN,
|
||||
0000201+I_NPN, 0000401+I_NPN, 0001001+I_NPN, 0001401+I_NPN,
|
||||
0140024+I_NPN, 0140040+I_NPN, 0140100+I_NPN,
|
||||
0140200+I_NPN, 0140320+I_NPN, 0140401+I_NPN,
|
||||
0140407+I_NPN, 0140500+I_NPN, 0140600+I_NPN,
|
||||
0141044+I_NPN, 0141050+I_NPN, 0141140+I_NPN,
|
||||
0141206+I_NPN, 0141216+I_NPN, 0141240+I_NPN, 0141340+I_NPN,
|
||||
0101000+I_NPN, 0100000+I_NPN, 0100036+I_NPN, 0101036+I_NPN,
|
||||
0002000+I_MRF, 0102000+I_MRF,
|
||||
0004000+I_MRF, 0104000+I_MRF, 0006000+I_MRF, 0106000+I_MRF,
|
||||
0010000+I_MRF, 0110000+I_MRF, 0012000+I_MRF, 0112000+I_MRF,
|
||||
0014000+I_MRF, 0114000+I_MRF, 0016000+I_MRF, 0116000+I_MRF,
|
||||
0020000+I_MRF, 0120000+I_MRF, 0022000+I_MRF, 0122000+I_MRF,
|
||||
0024000+I_MRF, 0124000+I_MRF, 0026000+I_MRF, 0126000+I_MRF,
|
||||
0034000+I_MRF, 0134000+I_MRF, 0036000+I_MRF, 0136000+I_MRF,
|
||||
0032000+I_MRX, 0132000+I_MRX, 0072000+I_MRX, 0172000+I_MRX,
|
||||
0040000+I_SHF, 0040100+I_SHF, 0040200+I_SHF,
|
||||
0040400+I_SHF, 0040500+I_SHF, 0040600+I_SHF,
|
||||
0041000+I_SHF, 0041100+I_SHF, 0041200+I_SHF,
|
||||
0041400+I_SHF, 0041500+I_SHF, 0041600+I_SHF,
|
||||
0030000+I_IOT, 0070000+I_IOT, 0130000+I_IOT, 0170000+I_IOT,
|
||||
0170000+I_IOT,
|
||||
0100400+I_SK0, 0100200+I_SK0, 0100100+I_SK0, /* encode only */
|
||||
0100040+I_SK0, 0100020+I_SK0, 0100010+I_SK0,
|
||||
0100004+I_SK0, 0100002+I_SK0, 0100001+I_SK0,
|
||||
0101400+I_SK1, 0101200+I_SK1, 0101100+I_SK1,
|
||||
0101040+I_SK1, 0101020+I_SK1, 0101010+I_SK1,
|
||||
0101004+I_SK1, 0101002+I_SK1, 0101001+I_SK1,
|
||||
0100000+I_SK0, 0101000+I_SK1, /* decode only */
|
||||
-1 };
|
||||
|
||||
/* Operate decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
inst = mask bits
|
||||
class = instruction class code
|
||||
sp = space needed?
|
||||
Outputs:
|
||||
status = space needed
|
||||
*/
|
||||
|
||||
int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp)
|
||||
{
|
||||
int32 i, j;
|
||||
|
||||
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
|
||||
inst = inst & ~opc_val[i]; /* mask bit set? */
|
||||
fprintf (of, (sp? " %s": "%s"), opcode[i]);
|
||||
sp = 1; } }
|
||||
return sp;
|
||||
}
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to data
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = status code
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 cflag, i, j, inst, disp;
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
inst = val[0];
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
if (inst > 0377) return SCPE_ARG;
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('C')) { /* characters? */
|
||||
fprintf (of, FMTASC ((inst >> 8) & 0177));
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
|
||||
/* Instruction decode */
|
||||
|
||||
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case I_V_NPN: /* no operands */
|
||||
fprintf (of, "%s", opcode[i]); /* opcode */
|
||||
break;
|
||||
case I_V_MRF: case I_V_MRX: /* mem ref */
|
||||
disp = inst & DISP; /* displacement */
|
||||
fprintf (of, "%s ", opcode[i]); /* opcode */
|
||||
if (inst & SC) { /* current sector? */
|
||||
if (cflag) fprintf (of, "%-o", (addr & PAGENO) | disp);
|
||||
else fprintf (of, "C %-o", disp); }
|
||||
else fprintf (of, "%-o", disp); /* sector zero */
|
||||
if ((j == I_V_MRF) && (inst & IDX)) fprintf (of, ",1");
|
||||
break;
|
||||
case I_V_IOT: /* I/O */
|
||||
disp = inst & 01777; /* pulse+dev */
|
||||
fprintf (of, "%s %o", opcode[i], disp);
|
||||
break;
|
||||
case I_V_SHF: /* shift */
|
||||
disp = -inst & SHFMASK; /* shift count */
|
||||
fprintf (of, "%s %o", opcode[i], disp);
|
||||
break;
|
||||
case I_V_SK0: case I_V_SK1: /* skips */
|
||||
fprint_opr (of, inst & 0777, j, 0); /* print skips */
|
||||
break; } /* end case */
|
||||
return SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 cflag, d, i, j, k;
|
||||
t_stat 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] = (t_value) cptr[0] & 0177;
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (((t_value) cptr[0] & 0177) << 8) |
|
||||
((t_value) cptr[1] & 0177);
|
||||
return SCPE_OK; }
|
||||
|
||||
/* Instruction parse */
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i] == NULL) return SCPE_ARG;
|
||||
val[0] = opc_val[i] & DMASK; /* get value */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case I_V_NPN: /* no operand */
|
||||
break;
|
||||
case I_V_IOT: /* IOT */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get pulse+dev */
|
||||
d = get_uint (gbuf, 8, 01777, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | d;
|
||||
break;
|
||||
case I_V_SHF: /* shift */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get shift count */
|
||||
d = get_uint (gbuf, 8, SHFMASK, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | (-d & SHFMASK); /* store 2's comp */
|
||||
break;
|
||||
case I_V_MRF: case I_V_MRX: /* mem ref */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
|
||||
if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */
|
||||
val[0] = val[0] | SC;
|
||||
cptr = get_glyph (cptr, gbuf, 0); }
|
||||
else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */
|
||||
cptr = get_glyph (cptr, gbuf, ','); }
|
||||
d = get_uint (gbuf, 8, X_AMASK, &r); /* construe as addr */
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
if (d <= DISP) val[0] = val[0] | d; /* fits? */
|
||||
else if (cflag && !k && (((addr ^ d) & PAGENO) == 0))
|
||||
val[0] = val[0] | (d & DISP) | SC;
|
||||
else return SCPE_ARG;
|
||||
if ((j == I_V_MRX) || (*cptr == 0)) break; /* indexed? */
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
d = get_uint (gbuf, 8, 1, &r); /* get tag */
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
if (d) val[0] = val[0] | IDX; /* or in index */
|
||||
break;
|
||||
case I_V_SK0: case I_V_SK1: /* skips */
|
||||
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
|
||||
cptr = get_glyph (cptr, gbuf, 0)) {
|
||||
for (i = 0; (opcode[i] != NULL) &&
|
||||
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
k = opc_val[i] & DMASK;
|
||||
if ((opcode[i] == NULL) || (((k ^ val[0]) & 0177000) != 0))
|
||||
return SCPE_ARG;
|
||||
val[0] = val[0] | k; }
|
||||
break; } /* end case */
|
||||
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
2602
HP2100/hp2100_cpu.c
2602
HP2100/hp2100_cpu.c
File diff suppressed because it is too large
Load Diff
@@ -1,269 +0,0 @@
|
||||
/* hp2100_defs.h: HP 2100 simulator definitions
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
24-Oct-02 RMS Added indirect address interrupt
|
||||
08-Feb-02 RMS Added DMS definitions
|
||||
01-Feb-02 RMS Added terminal multiplexor support
|
||||
16-Jan-02 RMS Added additional device support
|
||||
30-Nov-01 RMS Added extended SET/SHOW support
|
||||
15-Oct-00 RMS Added dynamic device numbers
|
||||
14-Apr-99 RMS Changed t_addr to unsigned
|
||||
|
||||
The author gratefully acknowledges the help of Jeff Moffat in answering
|
||||
questions about the HP2100.
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_RSRV 1 /* must be 1 */
|
||||
#define STOP_IODV 2 /* must be 2 */
|
||||
#define STOP_HALT 3 /* HALT */
|
||||
#define STOP_IBKPT 4 /* breakpoint */
|
||||
#define STOP_IND 5 /* indirect loop */
|
||||
#define STOP_INDINT 6 /* indirect intr */
|
||||
#define STOP_NOCONN 7 /* no connection */
|
||||
|
||||
#define ABORT_PRO 1 /* protection abort */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
|
||||
#define VA_N_SIZE 15 /* virtual addr size */
|
||||
#define VASIZE (1 << VA_N_SIZE)
|
||||
#define VAMASK (VASIZE - 1) /* virt addr mask */
|
||||
#define PA_N_SIZE 20 /* phys addr size */
|
||||
#define PASIZE (1 << PA_N_SIZE)
|
||||
#define PAMASK (PASIZE - 1) /* phys addr mask */
|
||||
|
||||
/* Architectural constants */
|
||||
|
||||
#define SIGN32 020000000000 /* 32b sign */
|
||||
#define SIGN 0100000 /* 16b sign */
|
||||
#define DMASK 0177777 /* 16b data mask */
|
||||
#define AR M[0] /* A = location 0 */
|
||||
#define BR M[1] /* B = location 1 */
|
||||
#define ABREG M /* register array */
|
||||
#define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK)))
|
||||
|
||||
/* Memory reference instructions */
|
||||
|
||||
#define I_IA 0100000 /* indirect address */
|
||||
#define I_AB 0004000 /* A/B select */
|
||||
#define I_CP 0002000 /* current page */
|
||||
#define I_DISP 0001777 /* page displacement */
|
||||
#define I_PAGENO 0076000 /* page number */
|
||||
|
||||
/* Other instructions */
|
||||
|
||||
#define I_NMRMASK 0102000 /* non-mrf opcode */
|
||||
#define I_SRG 0000000 /* shift */
|
||||
#define I_ASKP 0002000 /* alter/skip */
|
||||
#define I_EXTD 0100000 /* extend */
|
||||
#define I_IO 0102000 /* I/O */
|
||||
#define I_CTL 0004000 /* CTL on/off */
|
||||
#define I_HC 0001000 /* hold/clear */
|
||||
#define I_DEVMASK 0000077 /* device mask */
|
||||
#define I_GETIOOP(x) (((x) >> 6) & 07) /* I/O sub op */
|
||||
|
||||
/* DMA channels */
|
||||
|
||||
#define DMA1_STC 0100000 /* DMA - issue STC */
|
||||
#define DMA1_CLC 0020000 /* DMA - issue CLC */
|
||||
#define DMA2_OI 0100000 /* DMA - output/input */
|
||||
|
||||
struct DMA { /* DMA channel */
|
||||
int32 cw1; /* device select */
|
||||
int32 cw2; /* direction, address */
|
||||
int32 cw3; /* word count */
|
||||
};
|
||||
|
||||
/* Memory management */
|
||||
|
||||
#define VA_N_OFF 10 /* offset width */
|
||||
#define VA_M_OFF ((1 << VA_N_OFF) - 1) /* offset mask */
|
||||
#define VA_GETOFF(x) ((x) & VA_M_OFF)
|
||||
#define VA_N_PAG (VA_N_SIZE - VA_N_OFF) /* page width */
|
||||
#define VA_V_PAG (VA_N_OFF)
|
||||
#define VA_M_PAG ((1 << VA_N_PAG) - 1)
|
||||
#define VA_GETPAG(x) (((x) >> VA_V_PAG) & VA_M_PAG)
|
||||
|
||||
/* Maps */
|
||||
|
||||
#define MAP_NUM 4 /* num maps */
|
||||
#define MAP_LNT (1 << VA_N_PAG) /* map length */
|
||||
#define MAP_MASK ((MAP_NUM * MAP_LNT) - 1)
|
||||
#define SMAP 0 /* system map */
|
||||
#define UMAP (SMAP + MAP_LNT) /* user map */
|
||||
#define PAMAP (UMAP + MAP_LNT) /* port A map */
|
||||
#define PBMAP (PAMAP + MAP_LNT) /* port B map */
|
||||
|
||||
/* Map entries are left shifted by VA_N_OFF, flags in lower 2b */
|
||||
|
||||
#define PA_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */
|
||||
#define PA_V_PAG (VA_N_OFF)
|
||||
#define PA_M_PAG ((1 << PA_N_PAG) - 1)
|
||||
#define MAPM_V_RPR 15 /* in mem: read prot */
|
||||
#define MAPM_V_WPR 14 /* write prot */
|
||||
#define MAPA_V_RPR 1 /* in array: */
|
||||
#define MAPA_V_WPR 0
|
||||
#define PA_GETPAG(x) ((x) & (PA_M_PAG << VA_V_PAG))
|
||||
#define RD (1 << MAPA_V_RPR)
|
||||
#define WR (1 << MAPA_V_WPR)
|
||||
|
||||
/* Map status register */
|
||||
|
||||
#define MST_ENBI 0100000 /* mem enb @ int */
|
||||
#define MST_UMPI 0040000 /* usr map @ int */
|
||||
#define MST_ENB 0020000 /* mem enb */
|
||||
#define MST_UMP 0010000 /* usr map */
|
||||
#define MST_PRO 0004000 /* protection */
|
||||
#define MST_FLT 0002000 /* fence comp */
|
||||
#define MST_FENCE 0001777 /* base page fence */
|
||||
|
||||
/* Map violation register */
|
||||
|
||||
#define MVI_V_RPR 15
|
||||
#define MVI_V_WPR 14
|
||||
#define MVI_RPR (1 << MVI_V_RPR) /* rd viol */
|
||||
#define MVI_WPR (1 << MVI_V_WPR) /* wr viol */
|
||||
#define MVI_BPG 0020000 /* base page viol */
|
||||
#define MVI_PRV 0010000 /* priv viol */
|
||||
#define MVI_MEB 0000200 /* me bus enb @ viol */
|
||||
#define MVI_MEM 0000100 /* mem enb @ viol */
|
||||
#define MVI_UMP 0000040 /* usr map @ viol */
|
||||
#define MVI_PAG 0000037 /* pag sel */
|
||||
|
||||
/* Timers */
|
||||
|
||||
#define TMR_CLK 0 /* clock */
|
||||
#define TMR_MUX 1 /* multiplexor */
|
||||
|
||||
/* I/O sub-opcodes */
|
||||
|
||||
#define ioHLT 0 /* halt */
|
||||
#define ioFLG 1 /* set/clear flag */
|
||||
#define ioSFC 2 /* skip on flag clear */
|
||||
#define ioSFS 3 /* skip on flag set */
|
||||
#define ioMIX 4 /* merge into A/B */
|
||||
#define ioLIX 5 /* load into A/B */
|
||||
#define ioOTX 6 /* output from A/B */
|
||||
#define ioCTL 7 /* set/clear control */
|
||||
|
||||
/* I/O devices - fixed assignments */
|
||||
|
||||
#define CPU 000 /* interrupt control */
|
||||
#define OVF 001 /* overflow */
|
||||
#define DMALT0 002 /* DMA 0 alternate */
|
||||
#define DMALT1 003 /* DMA 1 alternate */
|
||||
#define PWR 004 /* power fail */
|
||||
#define PRO 005 /* parity/mem protect */
|
||||
#define DMA0 006 /* DMA channel 0 */
|
||||
#define DMA1 007 /* DMA channel 1 */
|
||||
#define VARDEV (DMA1 + 1) /* start of var assign */
|
||||
#define M_NXDEV (INT_M (CPU) | INT_M (OVF) | \
|
||||
INT_M (DMALT0) | INT_M (DMALT1))
|
||||
#define M_FXDEV (M_NXDEV | INT_M (PWR) | INT_M (PRO) | \
|
||||
INT_M (DMA0) | INT_M (DMA1))
|
||||
|
||||
/* I/O devices - variable assignment defaults */
|
||||
|
||||
#define PTR 010 /* paper tape reader */
|
||||
#define TTY 011 /* console */
|
||||
#define PTP 012 /* paper tape punch */
|
||||
#define CLK 013 /* clock */
|
||||
#define LPS 014 /* 12653 line printer */
|
||||
#define LPT 015 /* 12845 line printer */
|
||||
#define MTD 020 /* 12559A data */
|
||||
#define MTC 021 /* 12559A control */
|
||||
#define DPD 022 /* 12557A data */
|
||||
#define DPC 023 /* 12557A control */
|
||||
#define DQD 024 /* 12565A data */
|
||||
#define DQC 025 /* 12565A control */
|
||||
#define DRD 026 /* 12610A data */
|
||||
#define DRC 027 /* 12610A control */
|
||||
#define MSD 030 /* 13181A data */
|
||||
#define MSC 031 /* 13181A control */
|
||||
#define IPLI 032 /* 12556B link in */
|
||||
#define IPLO 033 /* 12556B link out */
|
||||
#define MUXL 040 /* 12920A lower data */
|
||||
#define MUXU 041 /* 12920A upper data */
|
||||
#define MUXC 042 /* 12920A control */
|
||||
|
||||
/* IBL assignments */
|
||||
|
||||
#define IBL_PTR 0000000 /* PTR */
|
||||
#define IBL_DP 0040000 /* DP */
|
||||
#define IBL_DQ 0060000 /* DQ */
|
||||
#define IBL_MS 0100000 /* MS */
|
||||
#define IBL_TBD 0140000 /* tbd */
|
||||
#define IBL_V_DEV 6 /* dev in <11:6> */
|
||||
#define IBL_FIX 0000001 /* DP fixed */
|
||||
#define IBL_LNT 64 /* boot length */
|
||||
#define IBL_MASK (IBL_LNT - 1) /* boot length mask */
|
||||
|
||||
/* Dynamic device information table */
|
||||
|
||||
struct hp_dib {
|
||||
int32 devno; /* device number */
|
||||
int32 cmd; /* saved command */
|
||||
int32 ctl; /* saved control */
|
||||
int32 flg; /* saved flag */
|
||||
int32 fbf; /* saved flag buf */
|
||||
int32 (*iot)(); /* I/O routine */
|
||||
};
|
||||
|
||||
typedef struct hp_dib DIB;
|
||||
|
||||
/* I/O macros */
|
||||
|
||||
#define INT_V(x) ((x) & 037) /* device bit pos */
|
||||
#define INT_M(x) (1u << INT_V (x)) /* device bit mask */
|
||||
#define setCMD(D) dev_cmd[(D)/32] = dev_cmd[(D)/32] | INT_M ((D))
|
||||
#define clrCMD(D) dev_cmd[(D)/32] = dev_cmd[(D)/32] & ~INT_M (D)
|
||||
#define setCTL(D) dev_ctl[(D)/32] = dev_ctl[(D)/32] | INT_M ((D))
|
||||
#define clrCTL(D) dev_ctl[(D)/32] = dev_ctl[(D)/32] & ~INT_M (D)
|
||||
#define setFBF(D) dev_fbf[(D)/32] = dev_fbf[(D)/32] | INT_M (D)
|
||||
#define clrFBF(D) dev_fbf[(D)/32] = dev_fbf[(D)/32] & ~INT_M (D)
|
||||
#define setFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] | INT_M (D); \
|
||||
setFBF(D)
|
||||
#define clrFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] & ~INT_M (D); \
|
||||
clrFBF(D)
|
||||
#define CMD(D) ((dev_cmd[(D)/32] >> INT_V (D)) & 1)
|
||||
#define CTL(D) ((dev_ctl[(D)/32] >> INT_V (D)) & 1)
|
||||
#define FLG(D) ((dev_flg[(D)/32] >> INT_V (D)) & 1)
|
||||
#define FBF(D) ((dev_fbf[(D)/32] >> INT_V (D)) & 1)
|
||||
|
||||
#define IOT_V_REASON 16
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp);
|
||||
@@ -1,171 +0,0 @@
|
||||
HP2100 Diagnostics
|
||||
|
||||
CPU status writeup sources
|
||||
|
||||
24315 Memory reference group passed in 21MX CE no
|
||||
- LOAD diagnostic
|
||||
- RUN 100
|
||||
- HLT 77, PC = 3353
|
||||
|
||||
24316 Alter/skip group passed in 21MX CE no
|
||||
- LOAD diagnostic
|
||||
- RUN 100
|
||||
- HLT 77, PC = 633
|
||||
|
||||
24317 Shift/rotate group passed in 21MX CE no
|
||||
- LOAD diagnostic
|
||||
- RUN 100
|
||||
- HLT 77, PC = 1726
|
||||
|
||||
24296 Diagnostic configurator passed in 21MX CE no
|
||||
- LOAD configurator
|
||||
- SET CPU 21MX
|
||||
- ATTACH PTR binary image of
|
||||
diagnostic to be configured
|
||||
- D S XXYY, where XX = device number
|
||||
of PTR, YY = device number of TTY
|
||||
- RUN 2
|
||||
- HLT 77, PC = 77237 (for 32K mem)
|
||||
|
||||
24319 Extended arithmetic group passed in 21MX CE no
|
||||
- load diagnostic via configurator
|
||||
- D S 0
|
||||
- RUN 100
|
||||
- prints diagnostic name
|
||||
- prints END OF PASS 1 and halts
|
||||
|
||||
13206 IOP for 2100 passed 13206 manual no
|
||||
- load diagnostic via configurator
|
||||
- D S 0
|
||||
- SET CPU 2100
|
||||
- SET CPU IOP
|
||||
- RUN 2000
|
||||
- prints diagnostic name
|
||||
- prints section names, PASS 000001, and halts
|
||||
- note: will not pass interruptibility tests
|
||||
|
||||
13207 IOP for 21MX passed 13207 manual no
|
||||
- load diagnostic via configurator
|
||||
- D S 13
|
||||
- SET CPU 21MX
|
||||
- SET CPU IOP
|
||||
- RUN 100
|
||||
- HLT 74, PC = 2425
|
||||
- D S 0
|
||||
- CON
|
||||
- prints diagnostic name
|
||||
- prints section names, PASS 000001, and halts
|
||||
|
||||
24320 Floating point passed in 21MX CE no
|
||||
- load diagnostic via configurator
|
||||
- D S 0
|
||||
- RUN 100
|
||||
- prints diagnostic name
|
||||
- prints PASS 000001 and halts
|
||||
|
||||
12943-1 Extended instruction group, part 1 passed 12943 manual no
|
||||
- load diagnostic via configurator
|
||||
- D S 0
|
||||
- RUN 100
|
||||
- prints diagnostic name
|
||||
- prints PASS 000001 and halts
|
||||
|
||||
12943-2 Extended instruction group, part 2 passed 12943 manual no
|
||||
- load diagnostic via configurator
|
||||
- D S XX, where XX = device number
|
||||
of TTY
|
||||
- RUN 100
|
||||
- HLT 74, PC = 2406
|
||||
- D S 0
|
||||
- CONTINUE
|
||||
- prints diagnostic name
|
||||
- prints PASS 000001 and halts
|
||||
|
||||
24322 Dual channel port controller passed in 21MX CE no
|
||||
- load diagnostic via configurator
|
||||
- SET LPS ENA
|
||||
- SET LPS DIAG
|
||||
- D S XX, where XX = device number
|
||||
of LPS
|
||||
- RUN 100
|
||||
- HALT 74, PC = 1541
|
||||
- D S 0
|
||||
- CONTINUE
|
||||
- prints diagnostic name
|
||||
- prints H324 PRESS PRESET AND RUN
|
||||
- HLT 24, PC = 2312
|
||||
- RESET ALL
|
||||
- CONTINUE
|
||||
- prints PASS 000001 and halts
|
||||
|
||||
12892 Memory protect-parity error passed in 21MX CE no
|
||||
- load diagnostic via configurator
|
||||
- disable all I/O devices except
|
||||
PTR, TTY, clock
|
||||
- D S 1400XX, where XX = device number
|
||||
of PTR
|
||||
- RUN 100
|
||||
- HLT 74, PC = 2444
|
||||
- D S 1000 (test select mode)
|
||||
- CONTINUE
|
||||
- prints diagnostic name
|
||||
- HLT 75, PC = 2026
|
||||
- D S 0
|
||||
- D A 31777 (tests 10-11 can't be run)
|
||||
- Rings bell and prints
|
||||
H314 PRESS HALT,PRESET AND RUN WITHIN 30 SECONDS
|
||||
- WRU (CTRL+E) to interrupt simulation
|
||||
- RESET ALL
|
||||
- CONTINUE
|
||||
- prints PASS 000001 and halts
|
||||
|
||||
12929 Memory expansion unit (DMS) passed in 21MX CE no
|
||||
- load diagnostic via configurator
|
||||
- SET CPU 64K
|
||||
- SET LPS ENA
|
||||
- SET LPS DIAG
|
||||
- D S XX, where XX = device number
|
||||
of LPS
|
||||
- RUN 100
|
||||
- HLT 74, PC = 2435
|
||||
- D S 0
|
||||
- CONTINUE
|
||||
- Prints H115 PRESS HALT-PRESET-RUN IN LESS THAN 10 SECONDS
|
||||
- WRU (CTRL+E) to interrupt simulation
|
||||
- RESET ALL
|
||||
- CONTINUE
|
||||
- Prints H117 PRESET TEST COMPLETE
|
||||
- Prints PASS 000001 and halts
|
||||
- Test 23 won't run at >256K mem
|
||||
(real 21MX limited to 304K)
|
||||
|
||||
Peripherals
|
||||
|
||||
12531 TTY test passed in 21MX CE no
|
||||
- set TTY TTIME to 100
|
||||
- run with test select = 173
|
||||
- remaining tests can't be run
|
||||
12539 time base generator passed in 21MX CE no
|
||||
- runs with CLK in diag mode
|
||||
12597 reader/punch passed in 21MX CE no
|
||||
- set PTP TIME to 100
|
||||
- run with test select a=4017
|
||||
- remaining tests can't be run
|
||||
12984 2767 line printer passed in 21MX CE no
|
||||
- set LPS PTIME, CTIME to 100
|
||||
- run with test select a = 15
|
||||
- remaining tests can't be run
|
||||
12960 7900/7901 disk passed in 21MX CE no
|
||||
12965 2883/2884 disk passed 12965 manual no
|
||||
12559 3030 magtape not run no documentation
|
||||
13181 7970B magtape partial in 21MX CE no
|
||||
- initial s = 102030
|
||||
- set MSC CTIME to 180000
|
||||
- do not change MSC XTIME
|
||||
- attach scratch tapes to units 0,1
|
||||
- set s = 1201 (suppress CRC/LRC)
|
||||
- run with test select a = 37757, b = 7767
|
||||
- tests 4, 14, 15 are timing dependent
|
||||
- test 19 uses non-supported read rev
|
||||
13183 7970E magtape not run in 21MX CE no
|
||||
12920 multiplexor not run in 21MX CE no
|
||||
@@ -1,945 +0,0 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: HP2100 Simulator Usage
|
||||
Date: 15-Jul-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2002, written by Robert M Supnik
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This memorandum documents the HP 2100 simulator.
|
||||
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tape.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_sock.c
|
||||
sim_tape.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/hp2100/ hp2100_defs.h
|
||||
hp2100_cpu.c
|
||||
hp2100_fp.c
|
||||
hp2100_dp.c
|
||||
hp2100_dq.c
|
||||
hp2100_dr.c
|
||||
hp2100_ipl.c
|
||||
hp2100_lps.c
|
||||
hp2100_lpt.c
|
||||
hp2100_mt.c
|
||||
hp2100_ms.c
|
||||
hp2100_mux.c
|
||||
hp2100_stddev.c
|
||||
hp2100_sys.c
|
||||
|
||||
2. HP2100 Features
|
||||
|
||||
The HP2100 simulator is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU 2116 CPU with 32KW memory
|
||||
2100 CPU with 32KW memory, FP or IOP instructions
|
||||
21MX CPU with 1024KW memory, FP or DMS instructions
|
||||
DMA0, DMA1 dual channel DMA controller
|
||||
PTR,PTP 12597A paper tape reader/punch
|
||||
TTY 12631C buffered terminal controller
|
||||
LPS 12653A printer controller with 2767 printer
|
||||
12566B microcircuit interface for diagnostics
|
||||
LPT 12845A printer controller with 2607 printer
|
||||
CLK 12539A/B/C time base generator
|
||||
MUXL,MUXU,MUXC 12920A terminal multiplexor
|
||||
DP 12557A disk controller with four 2871 drives
|
||||
13210A disk controller with four 7900 drives
|
||||
DQ 12565A disk controller with two 2883 drives
|
||||
DR 12606B fixed head disk controller with 2770/2771 disks
|
||||
12610B drum controller with 2773/2774/2775 drums
|
||||
MT 12559C magnetic tape controller with one 3030 drive
|
||||
MS 13181A magnetic tape controller with four 7970B drives
|
||||
13183A magnetic tape controller with four 7970E drives
|
||||
IPLI 12556B interprocessor link, input side
|
||||
IPLO 12556B interprocessor link, output side
|
||||
|
||||
The HP2100 simulator implements several unique stop conditions:
|
||||
|
||||
- decode of an undefined instruction, and STOP_INST is et
|
||||
- reference to an undefined I/O device, and STOP_DEV is set
|
||||
- more than INDMAX indirect references are detected during
|
||||
memory reference address decoding
|
||||
|
||||
The HP2100 loader supports standard absolute binary format. The DUMP
|
||||
command is not implemented.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
CPU options include choice of instruction set and memory size.
|
||||
|
||||
SET CPU 2116 2116 CPU
|
||||
SET CPU 2100 2100 CPU
|
||||
SET CPU 21MX 21MX CPU
|
||||
SET CPU EAU EAU instructions (2116 only)
|
||||
SET CPU NOEAU no EAU instructions (2116 only)
|
||||
SET CPU FP FP instructions (2100 only)
|
||||
SET CPU NOFP no FP instructions (2100 only)
|
||||
SET CPU IOP IOP instructions (2100, 21MX only)
|
||||
SET CPU NOIOP no IOP instructions (2100, 21MX only)
|
||||
SET CPU DMS DMS instructions (21MX only)
|
||||
SET CPU NODMS no DMS instructions (21MX only)
|
||||
SET CPU 4K set memory size = 4K
|
||||
SET CPU 8K set memory size = 8K
|
||||
SET CPU 16K set memory size = 16K
|
||||
SET CPU 32K set memory size = 32K
|
||||
SET CPU 64K set memory size = 64K (21MX only)
|
||||
SET CPU 128K set memory size = 128K (21MX only)
|
||||
SET CPU 256K set memory size = 256K (21MX only)
|
||||
SET CPU 512K set memory size = 512K (21MX only)
|
||||
SET CPU 1024K set memory size = 1024K (21MX only)
|
||||
|
||||
On the 2100, EAU is standard, and the FP and IOP options are mutually
|
||||
exclusive. On the 21MX, EAU and FP are standard. The 2100 and 21MX
|
||||
include memory protection as standard; the 21MX optionally includes
|
||||
DMS (dynamic memory system).
|
||||
|
||||
If memory size is being reduced, and the memory being truncated contains
|
||||
non-zero data, the simulator asks for confirmation. Data in the truncated
|
||||
portion of memory is lost. Initial memory size is 32K.
|
||||
|
||||
These switches are recognized when examining or depositing in CPU memory:
|
||||
|
||||
-v if DMS enabled, interpret address as virtual
|
||||
-s if DMS enabled, force system map
|
||||
-u if DMS enabled, force user map
|
||||
-p if DMS enabled, force port A map
|
||||
-q if DMS enabled, force port B map
|
||||
|
||||
CPU registers include the visible state of the processor as well as the
|
||||
control registers for the interrupt system.
|
||||
|
||||
name models size comments
|
||||
|
||||
P all 15 program counter
|
||||
A all 16 A register
|
||||
B all 16 B register
|
||||
X 21MX 16 X index register
|
||||
Y 21MX 16 Y index register
|
||||
S all 16 switch/display register
|
||||
F 2100,21MX 15 memory protection fence
|
||||
E all 1 extend flag
|
||||
O all 1 overflow flag
|
||||
ION all 1 interrupt enable flag
|
||||
ION_DEFER all 1 interrupt defer flag
|
||||
IADDR all 6 most recent interrupting device
|
||||
MPCTL 2100,21MX 1 memory protection enable
|
||||
MPFLG 2100,21MX 1 memory protection flag
|
||||
MPFBF 2100,21MX 1 memory protection flag buffer
|
||||
MPVR 2100,21MX 16 memory protection violation reg
|
||||
MPEVR 2100,21MX 1 memory protection freeze flag
|
||||
MPMEV 2100,21MX 1 memory protection DMS error flag
|
||||
DMSENB 21MX 1 DMS enable
|
||||
DMSCUR 21MX 1 DMS current mode
|
||||
DMSSR 21MX 16 DMS status register
|
||||
DMSVR 21MX 16 DMS violation register
|
||||
DMSMAP[4][32] 21MX 20 DMS maps
|
||||
STOP_INST all 1 stop on undefined instruction
|
||||
STOP_DEV all 1 stop on undefined device
|
||||
INDMAX all 16 indirect address limit
|
||||
PCQ[0:63] all 15 P of last JMP, JSB, or interrupt;
|
||||
most recent P change first
|
||||
WRU all 8 interrupt character
|
||||
|
||||
2.2 DMA Controllers
|
||||
|
||||
The HP2100 includes two DMA channel controllers (DMA0 and DMA1). Each
|
||||
DMA channel has the following visible state:
|
||||
|
||||
name size comments
|
||||
|
||||
CMD 1 channel enabled
|
||||
CTL 1 interrupt enabled
|
||||
FLG 1 channel ready
|
||||
FBF 1 channel ready buffer
|
||||
CW1 16 command word 1
|
||||
CW2 16 command word 2
|
||||
CW3 16 command word 3
|
||||
|
||||
2.3 Variable Device Assignments
|
||||
|
||||
On the HP2100, I/O device take their device numbers from the backplane
|
||||
slot they are plugged into. Thus, device number assignments vary
|
||||
considerably from system to system, and software package to software
|
||||
package. The HP2100 simulator supports dynamic device number assignment.
|
||||
To show the current device number, use the SHOW <dev> DEVNO command:
|
||||
|
||||
sim> SHOW PTR DEV
|
||||
device=10
|
||||
|
||||
To change the device number, use the SET <dev> DEVNO=<num> command:
|
||||
|
||||
sim> SET PTR DEV=30
|
||||
sim> SHOW PTR DEV
|
||||
device=30
|
||||
|
||||
The new device number must be in the range 010..077 (octal). For devices
|
||||
with two device numbers, only the lower numbered device number can be
|
||||
changed; the higher is automatically set to the lower + 1. If a
|
||||
device number conflict occurs, the simulator will return an error
|
||||
when started.
|
||||
|
||||
In addition, most devices can be enabled or disabled. To enable a
|
||||
device, use the SET <dev> ENABLED command:
|
||||
|
||||
sim> SET DP ENABLED
|
||||
|
||||
To disable a device, use the SET <dev> DISABLED command:
|
||||
|
||||
sim> SET DP DISABLED
|
||||
|
||||
For devices with more than one device number, disabling or enabling any
|
||||
device in the set disables all the devices.
|
||||
|
||||
2.4 Programmed I/O Devices
|
||||
|
||||
2.4.1 12597A-002 Paper Tape Reader (PTR)
|
||||
|
||||
The paper tape reader (PTR) reads data from a disk file. The POS
|
||||
register specifies the number of the next data item to be read.
|
||||
Thus, by changing POS, the user can backspace or advance the reader.
|
||||
|
||||
The paper tape reader supports the BOOT command. BOOT PTR copies the
|
||||
absolute binary loader into memory and starts it running.
|
||||
|
||||
The paper tape reader implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
CMD 1 reader enable
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
POS 32 position in the input file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
end of file 1 report error and stop
|
||||
0 out of tape or paper
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.2 12597A-005 Paper Tape Punch (PTP)
|
||||
|
||||
The paper tape punch (PTP) writes data to a disk file. The POS
|
||||
register specifies the number of the next data item to be written.
|
||||
Thus, by changing POS, the user can backspace or advance the punch.
|
||||
|
||||
The paper tape punch implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
CMD 1 punch enable
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
POS 32 position in the output file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.3 12631C Buffered Terminal (TTY)
|
||||
|
||||
The console terminal has three units: keyboard (unit 0), printer
|
||||
(unit 1), and punch (unit 2). The keyboard reads from the console
|
||||
keyboard; the printer writes to the simulator console window. The
|
||||
punch writes to a disk file. The keyboard and printer units (TTY0,
|
||||
TTY1) can be set to one of three modes: UC, 7B, or 8B. In UC mode,
|
||||
lower case input and output characters are automatically converted to
|
||||
upper case. In 7B mode, input and output characters are masked to 7
|
||||
bits. In 8B mode, characters are not modified. Changing the mode
|
||||
of either unit changes both. The default mode is UC.
|
||||
|
||||
The console teleprinter implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
MODE 16 mode
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
KPOS 32 number of characters input
|
||||
KTIME 24 keyboard polling interval
|
||||
TPOS 32 number of characters printed
|
||||
TTIME 24 time from I/O initiation to interrupt
|
||||
PPOS 32 position in the punch output file
|
||||
STOP_IOE 1 punch stop on I/O error
|
||||
|
||||
Error handling for the punch is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.4 12653A Printer Controller (LPS) with 2767 Printer
|
||||
12566B Microcircuit Interface
|
||||
|
||||
The 12653A line printer uses the 12566B microcircuit interface as
|
||||
its controller. As a line printer, LPS writes data to a disk file.
|
||||
The POS register specifies the number of the next data item to be
|
||||
written. Thus, by changing POS, the user can backspace or advance
|
||||
the printer.
|
||||
|
||||
As a microcircuit interface, LPS provides the DMA test device for
|
||||
running the dual channel port controller and DMS diagnostics. Printer
|
||||
mode verus diagnostic mode is controlled by the commands:
|
||||
|
||||
SET LPS PRINTER configure as line printer
|
||||
SET LPS DIAG configure for diagnostic tests
|
||||
|
||||
The 12653A is disabled by default.
|
||||
|
||||
The 12653A implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 16 output buffer
|
||||
STA 16 input buffer or status
|
||||
CMD 1 printer enable
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
POS 32 position in the output file
|
||||
CTIME 24 time between characters
|
||||
PTIME 24 time for a print operation
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
In printer mode, error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape or paper
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
In diagnostic mode, there are no errors; data sent to the output
|
||||
buffer is looped back to the status register with a fixed delay of 1.
|
||||
|
||||
2.4.5 12845A Printer Controller (LPT)
|
||||
|
||||
The line printer (LPT) writes data to a disk file. The POS register
|
||||
specifies the number of the next data item to be written. Thus,
|
||||
by changing POS, the user can backspace or advance the printer.
|
||||
|
||||
The line printer implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
CMD 1 printer enable
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
LCNT 7 line count within page
|
||||
POS 32 position in the output file
|
||||
CTIME 24 time between characters
|
||||
PTIME 24 time for a print operation
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape or paper
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.6 12539A/B/C Time Base Generator (CLK)
|
||||
|
||||
The time base generator (CLK) implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
SEL 3 time base select
|
||||
CTR 14 repeat counter for < 1Hz operation
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
ERR 1 error flag
|
||||
TIME[0:7] 31 clock intervals, select = 0..7
|
||||
DEVNO 6 current device number (read only)
|
||||
|
||||
The time base generator autocalibrates; the clock interval is adjusted
|
||||
up or down so that the clock tracks actual elapsed time. Operation at
|
||||
the fastest rates (100 usec, 1 msec) is not recommended.
|
||||
|
||||
2.4.7 12920A Terminal Multiplexor (MUXL, MUXU, MUXC)
|
||||
|
||||
The 12920A is a 16-line terminal multiplexor, with five additional
|
||||
receive-only diagnostic lines. It consists of three devices:
|
||||
|
||||
MUX scanning logic (corresponding more or less
|
||||
to the upper data card)
|
||||
MUXL individual lines (corresponding more or
|
||||
less to the lower data card)
|
||||
MUXC modem control and status logic (corresponding
|
||||
to the control card)
|
||||
|
||||
The MUX performs input and output through Telnet sessions connected to a
|
||||
user-specified port. The ATTACH command to the scanning logic specifies
|
||||
the port to be used:
|
||||
|
||||
ATTACH MUX <port> set up listening port
|
||||
|
||||
where port is a decimal number between 1 and 65535 that is not being used
|
||||
for other TCP/IP activities.
|
||||
|
||||
Each line (each unit of MUXL) can be set to one of three modes: UC, 7B,
|
||||
or 8B. In UC mode, lower case input and output characters are converted
|
||||
automatically to upper case. In 7B mode, input and output characters
|
||||
are masked to 7 bits. In 8B mode, characters are not modified. The
|
||||
default mode is UC. In addition, each line supports the DATASET option.
|
||||
DATASET, when set, enables modem control. The default settings are UC
|
||||
mode and DATASET disabled.
|
||||
|
||||
The modem controls model a simplified Bell 103A dataset with just four
|
||||
lines: data terminal ready and request to send from the computer to the
|
||||
data set, and carrier detect and data set ready from the data set to
|
||||
the computer. There is no ring detection. If data terminal ready is
|
||||
set when a Telnet connection starts up, then carrier detect and data
|
||||
set ready are also set. The connection is established whether data
|
||||
terminal ready is set or not.
|
||||
|
||||
Once MUX is attached and the simulator is running, the multiplexor listens
|
||||
for connections on the specified port. It assumes that the incoming
|
||||
connections are Telnet connections. The connections remain open until
|
||||
disconnected either by the Telnet client, a SET MUXL DISCONNECT command,
|
||||
or a DETACH MUX command.
|
||||
|
||||
The SHOW MUX CONNECTIONS command displays the current connections to the
|
||||
extra terminals. The SHOW MUX STATISTICS command displays statistics for
|
||||
active connections. The SET MUX DISCONNECT=linenumber disconnects the
|
||||
specified line.
|
||||
|
||||
The scanner (MUX) implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
IBUF 16 input buffer, holds line status
|
||||
OBUF 16 output buffer, holds channel select
|
||||
|
||||
The lines (MUXL) implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
STA[0:20] 16 line status, lines 0-20
|
||||
RPAR[0:20] 16 receive parameters, lines 0-20
|
||||
XPAR[0:15] 16 transmit parameters, lines 0-15
|
||||
RBUF[0:20] 8 receive buffer, lines 0-20
|
||||
XBUF[0:15] 8 transmit buffer, lines 0-15
|
||||
RCHP[0:20] 1 receive character present, lines 0-20
|
||||
XDON[0:15] 1 transmit done, lines 0-15
|
||||
TIME[0:15] 24 transmit time, lines 0-15
|
||||
|
||||
The modem control (MUXM) implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
SCAN 1 scan enabled
|
||||
CHAN 4 current line
|
||||
DSO[0:15] 6 C2,C1,ES2,ES1,SS2,SS1, lines 0-15
|
||||
DSI[0:15] 2 S2,S1, lines 0-15
|
||||
|
||||
|
||||
The terminal multiplexor does not support save and restore. All open
|
||||
connections are lost when the simulator shuts down or MUXU is detached.
|
||||
|
||||
2.4.8 Interprocessor Link (IPLI, IPLO)
|
||||
|
||||
The interprocessor link is a pair of 12556B parallel interfaces that
|
||||
are cross coupled to provide interprocessor communications to a second
|
||||
copy of the HP2100 simulator. The IPL is intended to support simulation
|
||||
of a two system HP TimeShared Basic configuration. The links are actually
|
||||
bidirectional half-duplex; TimeShared Basic uses them unidirectionally.
|
||||
The IPL is disabled by default.
|
||||
|
||||
To operate, the IPL devices must be enabled and then connected to the IPL
|
||||
devices in another copy of the simulator. The IPLI device in the first
|
||||
simulator is connected to the IPLO device in the second, and vice versa.
|
||||
Connections are established with the ATTACH command. One copy of the
|
||||
simulator listens for connections on a specified port (ATTACH -L); the
|
||||
other establishes connections to an IP address and port (ATTACH -C).
|
||||
Either copy may perform either operation, but the operations must be
|
||||
done in matched pairs:
|
||||
|
||||
simulator #1 simulator #2
|
||||
|
||||
sim> set ipli ena sim> set ipli ena
|
||||
(also enables iplo) (also enables iplo)
|
||||
sim> att -lw ipli 4000
|
||||
Listening on port 4000
|
||||
Waiting for connection
|
||||
sim> att -c iplo 4000
|
||||
Connection established Connected to 127.0.0.1 port 4000
|
||||
sim> att -lw iplo 4000
|
||||
Listening on port 4001
|
||||
Waiting for connection
|
||||
sim> att -c ipli 4001
|
||||
Connection established Connected to 127.0.0.1 port 4000
|
||||
|
||||
Both forms of ATTACH take a modifier -W (wait); if specified, the command
|
||||
will wait up to 30 seconds for the connection process to complete. ATTACH
|
||||
-C can specify both an IP address and a port, in the form aa.bb.cc.dd:port;
|
||||
if the IP address is omitted, it defaults to 127.0.0.1 (local system).
|
||||
|
||||
Both IPLI and IPLO implement the BOOT command. BOOT loads the HP Access
|
||||
Basic Block Loader for the IOP into the top 64 words of memory and starts
|
||||
it running.
|
||||
|
||||
Both IPLI and IPLO implement these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 16 buffer
|
||||
HOLD 8 holding buffer
|
||||
CMD 1 device enable
|
||||
CTL 1 device/interrupt enable
|
||||
FLG 1 device ready
|
||||
FBF 1 device ready buffer
|
||||
TIME 24 polling interval for input
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives
|
||||
13210A Disk Controller (DPC, DPD) with 7900 Drives
|
||||
|
||||
The 12557A/13210A disk controller can be configured as either a
|
||||
12557A, supporting 2.5MB drives, or a 13210A, supporting 5MB drives,
|
||||
with the commands:
|
||||
|
||||
SET DP 12557A 2.5MB drives
|
||||
SET DP 13210A 5.0MB drives
|
||||
|
||||
Drive types cannot be intermixed; the controller is configured for
|
||||
one type or the other. The 13210A (for 7900/7901 disks) is selected
|
||||
by default.
|
||||
|
||||
The simulated controller has two separate devices, a data channel and
|
||||
a device controller. The data channel includes a 128-word (one sector)
|
||||
buffer for reads and writes. The device controller includes the four
|
||||
disk drives. Disk drives can be set ONLINE or OFFLINE.
|
||||
|
||||
The 12557A/13210A supports the BOOT command. BOOT DP loads the IBL
|
||||
for 7900 class disks into memory and starts it running. BOOT -F DP
|
||||
boots from the fixed platter (head 2). The switch register (S) is
|
||||
set automatically to the value expected by the IBL loader:
|
||||
|
||||
<15:14> = 01
|
||||
<13:12> = 00
|
||||
<11:6> = data channel device code
|
||||
<5:1> = 00000
|
||||
<0> = 1 if booting from the fixed platter
|
||||
|
||||
The data channel implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
IBUF 16 input buffer
|
||||
OBUF 16 output buffer
|
||||
DBUF[0:127] 16 sector buffer
|
||||
BPTR 7 sector buffer pointer
|
||||
CMD 1 channel enable
|
||||
CTL 1 interrupt enable
|
||||
FLG 1 channel ready
|
||||
FBF 1 channel ready buffer
|
||||
XFER 1 transfer in progress flag
|
||||
WVAL 1 write data valid flag
|
||||
|
||||
The device controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
OBUF 16 output buffer
|
||||
BUSY 3 busy (unit #, + 1, of active unit)
|
||||
CNT 5 check record count
|
||||
CMD 1 controller enable
|
||||
CTL 1 interrupt enable
|
||||
FLG 1 controller ready
|
||||
FBF 1 controller ready buffer
|
||||
EOC 1 end of cylinder pending
|
||||
RARC[0:3] 8 record address register cylinder, drives 0-3
|
||||
RARH[0:3] 2 record address register head, drives 0-3
|
||||
RARS[0:3] 4 record address register sector, drives 0-3
|
||||
STA[0:3] 16 drive status, drives 0-3
|
||||
CTIME 24 data transfer command delay time
|
||||
DTIME 24 data channel command delay time
|
||||
STIME 24 seek delay time, per cylinder
|
||||
XTIME 24 interword transfer time
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached disk not ready
|
||||
|
||||
end of file assume rest of disk is zero
|
||||
|
||||
OS I/O error report error and stop
|
||||
|
||||
2.6 12565A Disk Controller (DQC, DRC) with 2883 Drives
|
||||
|
||||
The 12565A disk controller has two separate devices, a data channel and
|
||||
a device controller. The data channel includes a 128-word (one sector)
|
||||
buffer for reads and writes. The device controller includes the two
|
||||
disk drives. Disk drives can be set ONLINE or OFFLINE.
|
||||
|
||||
The 12565A supports the BOOT command. BOOT DQ loads the IBL for 2883
|
||||
class disks into memory and starts it running. The switch register (S)
|
||||
is set automatically to the value expected by the IBL loader:
|
||||
|
||||
<15:14> = 01
|
||||
<13:12> = 10
|
||||
<11:6> = data channel device code
|
||||
<5:0> = 00000
|
||||
|
||||
The data channel implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
IBUF 16 input buffer
|
||||
OBUF 16 output buffer
|
||||
DBUF[0:127] 16 sector buffer
|
||||
BPTR 7 sector buffer pointer
|
||||
CMD 1 channel enable
|
||||
CTL 1 interrupt enable
|
||||
FLG 1 channel ready
|
||||
FBF 1 channel ready buffer
|
||||
XFER 1 transfer in progress flag
|
||||
WVAL 1 write data valid flag
|
||||
|
||||
The device controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
OBUF 16 output buffer
|
||||
BUSY 2 busy (unit #, + 1, of active unit)
|
||||
CNT 9 check record count
|
||||
CMD 1 controller enable
|
||||
CTL 1 interrupt enable
|
||||
FLG 1 controller ready
|
||||
FBF 1 controller ready buffer
|
||||
RARC[0:1] 8 record address register cylinder, drives 0-1
|
||||
RARH[0:1] 5 record address register head, drives 0-1
|
||||
RARS[0:1] 5 record address register sector, drives 0-1
|
||||
STA[0:1] 16 drive status, drives 0-3
|
||||
CTIME 24 data transfer command delay time
|
||||
DTIME 24 data channel command delay time
|
||||
STIME 24 seek delay time, per cylinder
|
||||
XTIME 24 interword transfer time
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached disk not ready
|
||||
|
||||
end of file assume rest of disk is zero
|
||||
|
||||
OS I/O error report error and stop
|
||||
|
||||
2.7 12606B Fixed Head Disk Controller (DRC, DRD) with 2770/2771 Disk
|
||||
12610B Drum Controller (DRC, DRD) with 2773/2774/2775 Drum
|
||||
|
||||
The 12606B/12610B fixed head disk/drum controller has two separate devices,
|
||||
a data channel and a device controller. The device controller includes the
|
||||
actual drive. Ten different models are supported:
|
||||
|
||||
SET DRC 180K 12606B, 180K words
|
||||
SET DRC 360K 12606B, 360K words
|
||||
SET DRC 720K 12606B, 720K words
|
||||
SET DRC 384K 12610B, 84K words
|
||||
SET DRC 512K 12610B, 512K words
|
||||
SET DRC 640K 12610B, 640K words
|
||||
SET DRC 768K 12610B, 768K words
|
||||
SET DRC 896K 12610B, 896K words
|
||||
SET DRC 1024K 12610B, 1024K words
|
||||
SET DRC 1536K 12610B, 1536K words
|
||||
|
||||
The 12606B/12610B support the BOOT command. The BOOT command loads the
|
||||
first sector from the disk or drum into locations 0-77 and then jumps to 77.
|
||||
This is very different from the IBL loader protocol used by the 12565A and
|
||||
the 12557A/13210A.
|
||||
|
||||
The data channel implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
IBUF 16 input buffer
|
||||
OBUF 16 output buffer
|
||||
CMD 1 channel enable
|
||||
CTL 1 interrupt enable
|
||||
FLG 1 channel ready
|
||||
FBF 1 channel ready buffer
|
||||
BPTR 6 sector buffer pointer
|
||||
|
||||
The device controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
CW 16 command word
|
||||
STA 16 status
|
||||
CMD 1 controller enable
|
||||
CTL 1 interrupt enable
|
||||
FLG 1 controller ready
|
||||
FBF 1 controller ready buffer
|
||||
TIME 24 interword transfer time
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached disk not ready
|
||||
|
||||
12606B/12610B data files are buffered in memory; therefore, end of file
|
||||
and OS I/O errors cannot occur.
|
||||
|
||||
2.8 12559C Magnetic Tape Controller (MTC, MTD) with 3030 Drive
|
||||
|
||||
Magnetic tape options include the ability to make the unit write enabled
|
||||
or write locked.
|
||||
|
||||
SET MTC LOCKED set unit write locked
|
||||
SET MTC WRITEENABLED set unit write enabled
|
||||
|
||||
The 12559C mag tape drive has two separate devices, a data channel and
|
||||
a device controller. The data channel includes a maximum record sized
|
||||
buffer for reads and writes. The device controller includes the tape
|
||||
unit.
|
||||
|
||||
The BOOT command is not supported. The 12559C was HP's earliest tape
|
||||
drive and is not supported by most of its operating systems. It is
|
||||
disabled by default.
|
||||
|
||||
The data channel implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
FLG 1 channel ready
|
||||
DBUF[0:65535] 8 transfer buffer
|
||||
BPTR 16 buffer pointer (reads and writes)
|
||||
BMAX 16 buffer size (writes)
|
||||
|
||||
The device controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
FNC 8 current function
|
||||
STA 9 tape status
|
||||
BUF 8 buffer
|
||||
CTL 1 interrupt enabled
|
||||
FLG 1 controller ready
|
||||
FBF 1 controller ready buffer
|
||||
DTF 1 data transfer flop
|
||||
FSVC 1 first service flop
|
||||
POS 32 magtape position
|
||||
CTIME 24 command delay time
|
||||
XTIME 24 interword transfer delay time
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached tape not ready; if STOP_IOE, stop
|
||||
|
||||
end of file parity error
|
||||
|
||||
OS I/O error parity error; if STOP_IOE, stop
|
||||
|
||||
2.9 13181A Magnetic Tape Controller (MSC, MSD) with 7970B Drives
|
||||
18183A Magnetic Tape Controller (MSC, MSD) with 7970E Drives
|
||||
|
||||
Magnetic tape options include the ability to make the unit write enabled
|
||||
or write locked, and the ability to select the 13181A (800 bpi) controller
|
||||
or the 13183A (1600 bpi) controller.
|
||||
|
||||
SET MTn LOCKED set unit n write locked
|
||||
SET MTn WRITEENABLED set unit n write enabled
|
||||
SET MT 13181A set controller to 13181A
|
||||
SET MT 13183A set controller to 13183A
|
||||
|
||||
The 13181A/13183A mag tape drive has two separate devices, a data channel
|
||||
and a device controller. The data channel includes a maximum record
|
||||
sized buffer for reads and writes. The device controller includes the
|
||||
tape units.
|
||||
|
||||
The 13181A/13183A supports the BOOT command. BOOT MS loads the IBL for
|
||||
7970B/E magnetic tape drives into memory and starts it running. BOOT -S
|
||||
MS causes the loader to space forward the number of files specified in
|
||||
the A register before starting to load data. The switch register (S) is
|
||||
set automatically to the value expected by the IBL loader:
|
||||
|
||||
<15:14> = 10
|
||||
<13:12> = 00
|
||||
<11:6> = data channel device code
|
||||
<5:1> = 00000
|
||||
<0> = 1 if space forward before loading
|
||||
|
||||
The data channel implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 16 data buffer
|
||||
CTL 1 interrupt enabled
|
||||
FLG 1 channel ready
|
||||
FBF 1 channel ready buffer
|
||||
DBUF[0:65535] 8 transfer buffer
|
||||
BPTR 17 buffer pointer (reads and writes)
|
||||
BMAX 17 buffer size (writes)
|
||||
|
||||
The device controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
STA 12 tape status
|
||||
BUF 16 buffer
|
||||
USEL 2 currently selected unit
|
||||
FSVC 1 first service flop
|
||||
CTL 1 interrupt enabled
|
||||
FLG 1 controller ready
|
||||
FBF 1 controller ready buffer
|
||||
POS[0:3] 32 magtape position
|
||||
CTIME 24 command delay time
|
||||
XTIME 24 interword transfer delay time
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached tape not ready; if STOP_IOE, stop
|
||||
|
||||
end of file parity error
|
||||
|
||||
OS I/O error parity error; if STOP_IOE, stop
|
||||
|
||||
2.10 Symbolic Display and Input
|
||||
|
||||
The HP2100 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-a display as ASCII character
|
||||
-c display as two character string
|
||||
-m display instruction mnemonics
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or -a ASCII character
|
||||
" or -c two character sixbit string
|
||||
alphabetic instruction mnemonic
|
||||
numeric octal number
|
||||
|
||||
Instruction input uses standard HP2100 assembler syntax. There are seven
|
||||
instruction classes: memory reference, I/O, shift, alter skip, extended
|
||||
shift, extended memory reference, extended two address reference.
|
||||
|
||||
Memory reference instructions have the format
|
||||
|
||||
memref {C/Z} address{,I}
|
||||
|
||||
where I signifies indirect, C a current page reference, and Z a zero page
|
||||
reference. The address is an octal number in the range 0 - 077777; if C or
|
||||
Z is specified, the address is a page offset in the range 0 - 01777. Normally,
|
||||
C is not needed; the simulator figures out from the address what mode to use.
|
||||
However, when referencing memory outside the CPU (eg, disks), there is no
|
||||
valid PC, and C must be used to specify current page addressing.
|
||||
|
||||
IOT instructions have the format
|
||||
|
||||
io device{,C}
|
||||
|
||||
where C signifies that the device flag is to be cleared. The device is an
|
||||
octal number in the range 0 - 77.
|
||||
|
||||
Shift and alter/skip instructions have the format
|
||||
|
||||
sub-op sub-op sub-op...
|
||||
|
||||
The simulator checks that the combination of sub-opcodes is legal.
|
||||
|
||||
Extended shift instructions have the format
|
||||
|
||||
extshift count
|
||||
|
||||
where count is an octal number in the range 1 - 020.
|
||||
|
||||
Extended memory reference instructions have the format
|
||||
|
||||
extmemref address{,I}
|
||||
|
||||
where I signifies indirect addressing. The address is an octal number in
|
||||
the range 0 - 077777.
|
||||
|
||||
Extended two address instructions have the format
|
||||
|
||||
ext2addr addr1{,I},addr2{,I}
|
||||
|
||||
where I signifies indirect addressing. Both address 1 and address 2 are
|
||||
octal numbers in the range 0 - 077777.
|
||||
@@ -1,796 +0,0 @@
|
||||
/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
dp 12557A 2871 disk subsystem
|
||||
13210A 7900 disk subsystem
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
Fixed bug(s) in boot (found by Terry Newton)
|
||||
10-Nov-02 RMS Added BOOT command, fixed numerous bugs
|
||||
15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith)
|
||||
10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith)
|
||||
03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW
|
||||
24-Nov-01 RMS Changed STA to be an array
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
29-Nov-00 RMS Made variable names unique
|
||||
21-Nov-00 RMS Fixed flag, buffer power up state
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define FNC u3 /* saved function */
|
||||
#define CYL u4 /* cylinder */
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
|
||||
|
||||
#define DP_N_NUMWD 7
|
||||
#define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */
|
||||
#define DP_NUMSC2 12 /* sectors/srf 12557 */
|
||||
#define DP_NUMSC3 24 /* sectors/srf 13210 */
|
||||
#define DP_NUMSC (dp_ctype? DP_NUMSC3: DP_NUMSC2)
|
||||
#define DP_NUMSF 4 /* surfaces/cylinder */
|
||||
#define DP_NUMCY 203 /* cylinders/disk */
|
||||
#define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD)
|
||||
#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD)
|
||||
#define DP_NUMDRV 4 /* # drives */
|
||||
|
||||
/* Command word */
|
||||
|
||||
#define CW_V_FNC 12 /* function */
|
||||
#define CW_M_FNC 017
|
||||
#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC)
|
||||
#define FNC_STA 000 /* status check */
|
||||
#define FNC_WD 001 /* write */
|
||||
#define FNC_RD 002 /* read */
|
||||
#define FNC_SEEK 003 /* seek */
|
||||
#define FNC_REF 005 /* refine */
|
||||
#define FNC_CHK 006 /* check */
|
||||
#define FNC_INIT 011 /* init */
|
||||
#define FNC_AR 013 /* address */
|
||||
#define FNC_SEEK1 020 /* fake - seek1 */
|
||||
#define FNC_SEEK2 021 /* fake - seek2 */
|
||||
#define FNC_SEEK3 022 /* fake - seek3 */
|
||||
#define FNC_CHK1 023 /* fake - check1 */
|
||||
#define FNC_AR1 024 /* fake - arec1 */
|
||||
#define CW_V_DRV 0 /* drive */
|
||||
#define CW_M_DRV 03
|
||||
#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV)
|
||||
|
||||
/* Disk address words */
|
||||
|
||||
#define DA_V_CYL 0 /* cylinder */
|
||||
#define DA_M_CYL 0377
|
||||
#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL)
|
||||
#define DA_V_HD 8 /* head */
|
||||
#define DA_M_HD 03
|
||||
#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD)
|
||||
#define DA_V_SC 0 /* sector */
|
||||
#define DA_M_SC2 017
|
||||
#define DA_M_SC3 037
|
||||
#define DA_M_SC (dp_ctype? DA_M_SC3: DA_M_SC2)
|
||||
#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)
|
||||
#define DA_CKMASK2 037 /* check mask */
|
||||
#define DA_CKMASK3 077
|
||||
#define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2)
|
||||
|
||||
/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */
|
||||
|
||||
#define STA_ATN 0100000 /* attention (u) */
|
||||
#define STA_1ST 0040000 /* first status */
|
||||
#define STA_OVR 0020000 /* overrun */
|
||||
#define STA_RWU 0010000 /* rw unsafe NI (u) */
|
||||
#define STA_ACU 0004000 /* access unsafe NI */
|
||||
#define STA_HUNT 0002000 /* hunting NI (12557) */
|
||||
#define STA_PROT 0002000 /* protected (13210) */
|
||||
#define STA_SKI 0001000 /* incomplete NI (u) */
|
||||
#define STA_SKE 0000400 /* seek error */
|
||||
/* 0000200 /* unused */
|
||||
#define STA_NRDY 0000100 /* not ready (d) */
|
||||
#define STA_EOC 0000040 /* end of cylinder */
|
||||
#define STA_AER 0000020 /* addr error */
|
||||
#define STA_FLG 0000010 /* flagged */
|
||||
#define STA_BSY 0000004 /* seeking */
|
||||
#define STA_DTE 0000002 /* data error */
|
||||
#define STA_ERR 0000001 /* any error (d) */
|
||||
#define STA_ALLERR (STA_ATN + STA_1ST + STA_OVR + STA_RWU + STA_ACU + \
|
||||
STA_SKI + STA_SKE + STA_NRDY + STA_EOC + STA_AER + \
|
||||
STA_FLG + STA_BSY + STA_DTE)
|
||||
#define STA_MBZ13 (STA_ATN + STA_RWU + STA_SKI) /* zero in 13210 */
|
||||
|
||||
extern uint16 *M;
|
||||
extern uint32 PC, SR;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
extern int32 sim_switches;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 dp_ctype = 1; /* ctrl type */
|
||||
int32 dpc_busy = 0; /* cch unit */
|
||||
int32 dpc_cnt = 0; /* check count */
|
||||
int32 dpc_eoc = 0; /* end of cyl */
|
||||
int32 dpc_stime = 100; /* seek time */
|
||||
int32 dpc_ctime = 100; /* command time */
|
||||
int32 dpc_xtime = 5; /* xfer time */
|
||||
int32 dpc_dtime = 2; /* dch time */
|
||||
int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */
|
||||
int32 dpc_obuf = 0; /* cch buffers */
|
||||
int32 dpd_xfer = 0; /* xfer in prog */
|
||||
int32 dpd_wval = 0; /* write data valid */
|
||||
int32 dp_ptr = 0; /* buffer ptr */
|
||||
uint8 dpc_rarc[DP_NUMDRV] = { 0 }; /* cylinder */
|
||||
uint8 dpc_rarh[DP_NUMDRV] = { 0 }; /* head */
|
||||
uint8 dpc_rars[DP_NUMDRV] = { 0 }; /* sector */
|
||||
uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */
|
||||
uint16 dpxb[DP_NUMWD]; /* sector buffer */
|
||||
|
||||
DEVICE dpd_dev, dpc_dev;
|
||||
int32 dpdio (int32 inst, int32 IR, int32 dat);
|
||||
int32 dpcio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat dpc_svc (UNIT *uptr);
|
||||
t_stat dpd_svc (UNIT *uptr);
|
||||
t_stat dpc_reset (DEVICE *dptr);
|
||||
t_stat dpc_vlock (UNIT *uptr, int32 val);
|
||||
t_stat dpc_attach (UNIT *uptr, char *cptr);
|
||||
t_stat dpc_boot (int32 unitno, DEVICE *dptr);
|
||||
void dp_god (int32 fnc, int32 drv, int32 time);
|
||||
void dp_goc (int32 fnc, int32 drv, int32 time);
|
||||
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
/* DPD data structures
|
||||
|
||||
dpd_dev DPD device descriptor
|
||||
dpd_unit DPD unit list
|
||||
dpd_reg DPD register list
|
||||
*/
|
||||
|
||||
DIB dp_dib[] = {
|
||||
{ DPD, 0, 0, 0, 0, &dpdio },
|
||||
{ DPC, 0, 0, 0, 0, &dpcio } };
|
||||
|
||||
#define dpd_dib dp_dib[0]
|
||||
#define dpc_dib dp_dib[1]
|
||||
|
||||
UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) };
|
||||
|
||||
REG dpd_reg[] = {
|
||||
{ ORDATA (IBUF, dpd_ibuf, 16) },
|
||||
{ ORDATA (OBUF, dpd_obuf, 16) },
|
||||
{ FLDATA (CMD, dpd_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, dpd_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, dpd_dib.flg, 0) },
|
||||
{ FLDATA (FBF, dpd_dib.fbf, 0) },
|
||||
{ FLDATA (XFER, dpd_xfer, 0) },
|
||||
{ FLDATA (WVAL, dpd_wval, 0) },
|
||||
{ BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) },
|
||||
{ DRDATA (BPTR, dp_ptr, DP_N_NUMWD) },
|
||||
{ ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dpd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dpd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dpd_dev = {
|
||||
"DPD", &dpd_unit, dpd_reg, dpd_mod,
|
||||
1, 10, DP_N_NUMWD, 1, 8, 16,
|
||||
NULL, NULL, &dpc_reset,
|
||||
NULL, NULL, NULL,
|
||||
&dpd_dib, 0 };
|
||||
|
||||
/* DPC data structures
|
||||
|
||||
dpc_dev DPC device descriptor
|
||||
dpc_unit DPC unit list
|
||||
dpc_reg DPC register list
|
||||
dpc_mod DPC modifier list
|
||||
*/
|
||||
|
||||
UNIT dpc_unit[] = {
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, DP_SIZE3) },
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, DP_SIZE3) },
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, DP_SIZE3) },
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, DP_SIZE3) } };
|
||||
|
||||
REG dpc_reg[] = {
|
||||
{ ORDATA (OBUF, dpc_obuf, 16) },
|
||||
{ ORDATA (BUSY, dpc_busy, 3), REG_RO },
|
||||
{ ORDATA (CNT, dpc_cnt, 5) },
|
||||
{ FLDATA (CMD, dpc_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, dpc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, dpc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, dpc_dib.fbf, 0) },
|
||||
{ FLDATA (EOC, dpc_eoc, 0) },
|
||||
{ BRDATA (RARC, dpc_rarc, 8, 8, DP_NUMDRV) },
|
||||
{ BRDATA (RARH, dpc_rarh, 8, 2, DP_NUMDRV) },
|
||||
{ BRDATA (RARS, dpc_rars, 8, 4, DP_NUMDRV) },
|
||||
{ BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) },
|
||||
{ DRDATA (CTIME, dpc_ctime, 24), PV_LEFT },
|
||||
{ DRDATA (DTIME, dpc_dtime, 24), PV_LEFT },
|
||||
{ DRDATA (STIME, dpc_stime, 24), PV_LEFT },
|
||||
{ DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (CTYPE, dp_ctype, 0), REG_HRO },
|
||||
{ URDATA (UCYL, dpc_unit[0].CYL, 10, 8, 0,
|
||||
DP_NUMDRV, PV_LEFT | REG_HRO) },
|
||||
{ URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0,
|
||||
DP_NUMDRV, REG_HRO) },
|
||||
{ URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0,
|
||||
DP_NUMDRV, PV_LEFT | REG_HRO) },
|
||||
{ ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dpc_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "13210A",
|
||||
&dp_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "12557A",
|
||||
&dp_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
|
||||
NULL, &dp_showtype, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dpd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dpc_dev = {
|
||||
"DPC", dpc_unit, dpc_reg, dpc_mod,
|
||||
DP_NUMDRV, 8, 24, 1, 8, 16,
|
||||
NULL, NULL, &dpc_reset,
|
||||
&dpc_boot, &dpc_attach, NULL,
|
||||
&dpc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 dpdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
dpd_obuf = dat;
|
||||
if (!dpc_busy || dpd_xfer) dpd_wval = 1; /* if !overrun, valid */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | dpd_ibuf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = dpd_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCTL (devd); /* clr ctl, cmd */
|
||||
clrCMD (devd);
|
||||
dpd_xfer = 0; } /* clr xfer */
|
||||
else { /* STC */
|
||||
if (!dp_ctype) setCTL (devd); /* 12557: set ctl */
|
||||
setCMD (devd); /* set cmd */
|
||||
if (dpc_busy && !dpd_xfer) /* overrun? */
|
||||
dpc_sta[dpc_busy - 1] |= STA_OVR; }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 dpcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 i, devc, fnc, drv;
|
||||
int32 devd = dpd_dib.devno;
|
||||
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
dpc_obuf = dat;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
for (i = 0; i < DP_NUMDRV; i++)
|
||||
if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i);
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC? */
|
||||
clrCTL (devc); /* clr cmd, ctl */
|
||||
clrCMD (devc); /* cancel non-seek */
|
||||
if (dpc_busy) sim_cancel (&dpc_unit[dpc_busy - 1]);
|
||||
sim_cancel (&dpd_unit); /* cancel dch */
|
||||
dpd_xfer = 0; /* clr dch xfer */
|
||||
dpc_busy = 0; } /* clr cch busy */
|
||||
else { /* STC */
|
||||
setCTL (devc); /* set ctl */
|
||||
if (!CMD (devc)) { /* is cmd clr? */
|
||||
setCMD (devc); /* set cmd */
|
||||
drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */
|
||||
fnc = CW_GETFNC (dpc_obuf); /* from cmd word */
|
||||
switch (fnc) { /* case on fnc */
|
||||
case FNC_STA: /* rd sta */
|
||||
if (dp_ctype) { clrFLG (devd); } /* 13210? clr dch flag */
|
||||
case FNC_SEEK: case FNC_CHK: /* seek, check */
|
||||
case FNC_AR: /* addr rec */
|
||||
dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */
|
||||
break;
|
||||
case FNC_RD: case FNC_WD: /* read, write */
|
||||
case FNC_REF: case FNC_INIT: /* refine, init */
|
||||
dp_goc (fnc, drv, dpc_ctime); /* sched drive */
|
||||
break; } /* end case */
|
||||
}
|
||||
} /* end else */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Start data channel operation */
|
||||
|
||||
void dp_god (int32 fnc, int32 drv, int32 time)
|
||||
{
|
||||
dpd_unit.CYL = drv; /* save unit */
|
||||
dpd_unit.FNC = fnc; /* save function */
|
||||
sim_activate (&dpd_unit, time);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start controller operation */
|
||||
|
||||
void dp_goc (int32 fnc, int32 drv, int32 time)
|
||||
{
|
||||
if (sim_is_active (&dpc_unit[drv])) { /* still seeking? */
|
||||
sim_cancel (&dpc_unit[drv]); /* stop seek */
|
||||
dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY; /* clear busy */
|
||||
time = time + dpc_stime; } /* take longer */
|
||||
dp_ptr = 0; /* init buf ptr */
|
||||
dpc_eoc = 0; /* clear end cyl */
|
||||
dpc_busy = drv + 1; /* set busy */
|
||||
dpd_xfer = 1; /* xfer in prog */
|
||||
dpc_unit[drv].FNC = fnc; /* save function */
|
||||
sim_activate (&dpc_unit[drv], time); /* activate unit */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Data channel unit service
|
||||
|
||||
This routine handles the data channel transfers. It also handles
|
||||
data transfers that are blocked by seek in progress.
|
||||
|
||||
uptr->CYL = target drive
|
||||
uptr->FNC = target function
|
||||
|
||||
Seek substates
|
||||
seek - transfer cylinder
|
||||
seek1 - transfer head/surface
|
||||
Address record
|
||||
ar - transfer cylinder
|
||||
ar1 - transfer head/surface, finish operation
|
||||
Status check - transfer status, finish operation
|
||||
Check data
|
||||
chk - transfer sector count
|
||||
*/
|
||||
|
||||
t_stat dpd_svc (UNIT *uptr)
|
||||
{
|
||||
int32 drv, devc, devd, st;
|
||||
|
||||
drv = uptr->CYL; /* get drive no */
|
||||
devc = dpc_dib.devno; /* get cch devno */
|
||||
devd = dpd_dib.devno; /* get dch devno */
|
||||
switch (uptr->FNC) { /* case function */
|
||||
|
||||
case FNC_SEEK: /* seek, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */
|
||||
dpd_wval = 0; /* clr data valid */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr->FNC = FNC_SEEK1; } /* advance state */
|
||||
sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
break;
|
||||
case FNC_SEEK1: /* seek, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */
|
||||
dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */
|
||||
dpd_wval = 0; /* clr data valid */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
if (sim_is_active (&dpc_unit[drv])) { /* if busy, */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_SKE;
|
||||
break; } /* error, ignore */
|
||||
st = abs (dpc_rarc[drv] - dpc_unit[drv].CYL) * dpc_stime;
|
||||
if (st == 0) st = dpc_stime; /* min time */
|
||||
sim_activate (&dpc_unit[drv], st); /* schedule drive */
|
||||
dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) &
|
||||
~(STA_SKE | STA_SKI | STA_HUNT);
|
||||
dpc_unit[drv].CYL = dpc_rarc[drv]; /* on cylinder */
|
||||
dpc_unit[drv].FNC = FNC_SEEK2; } /* set operation */
|
||||
else sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
break;
|
||||
|
||||
case FNC_AR: /* arec, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */
|
||||
dpd_wval = 0; /* clr data valid */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr->FNC = FNC_AR1; } /* advance state */
|
||||
sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
break;
|
||||
case FNC_AR1: /* arec, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */
|
||||
dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */
|
||||
dpd_wval = 0; /* clr data valid */
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); } /* clr dch cmd */
|
||||
else sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
break;
|
||||
|
||||
case FNC_STA: /* read status */
|
||||
if (CMD (devd) || dp_ctype) { /* dch act or 13210? */
|
||||
if (dpc_unit[drv].flags & UNIT_ATT) { /* attached? */
|
||||
dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */
|
||||
if (dp_ctype) dpd_ibuf = /* 13210? */
|
||||
(dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) |
|
||||
(uptr->flags & UNIT_WPRT? STA_PROT: 0); }
|
||||
else dpd_ibuf = STA_NRDY; /* not ready */
|
||||
if (dpd_ibuf & STA_ALLERR) /* errors? set flg */
|
||||
dpd_ibuf = dpd_ibuf | STA_ERR;
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */
|
||||
~(STA_ATN | STA_1ST | STA_OVR |
|
||||
STA_RWU | STA_ACU | STA_EOC |
|
||||
STA_AER | STA_FLG | STA_DTE); }
|
||||
else sim_activate (uptr, dpc_xtime); /* wait more */
|
||||
break;
|
||||
|
||||
case FNC_CHK: /* check, need cnt */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */
|
||||
dpd_wval = 0; /* clr data valid */
|
||||
/* setFLG (devd); /* set dch flg */
|
||||
/* clrCMD (devd); /* clr dch cmd */
|
||||
dp_goc (FNC_CHK1, drv, dpc_xtime); } /* sched drv */
|
||||
else sim_activate (uptr, dpc_xtime); /* wait more */
|
||||
break;
|
||||
|
||||
default:
|
||||
return SCPE_IERR; }
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Drive unit service
|
||||
|
||||
This routine handles the data transfers.
|
||||
|
||||
Seek substates
|
||||
seek2 - done
|
||||
Refine sector - erase sector, finish operation
|
||||
Check data
|
||||
chk1 - finish operation
|
||||
Read
|
||||
Write
|
||||
*/
|
||||
|
||||
#define GETDA(x,y,z) \
|
||||
(((((x) * DP_NUMSF) + (y)) * DP_NUMSC) + (z)) * DP_NUMWD
|
||||
|
||||
t_stat dpc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 da, drv, devc, devd, err;
|
||||
|
||||
err = 0; /* assume no err */
|
||||
drv = uptr - dpc_dev.units; /* get drive no */
|
||||
devc = dpc_dib.devno; /* get cch devno */
|
||||
devd = dpd_dib.devno; /* get dch devno */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
dpc_sta[drv] = 0; /* clr status */
|
||||
dpc_busy = 0; /* ctlr is free */
|
||||
dpd_xfer = dpd_wval = 0;
|
||||
return SCPE_OK; }
|
||||
switch (uptr->FNC) { /* case function */
|
||||
|
||||
case FNC_SEEK2: /* seek done */
|
||||
dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY;
|
||||
if (uptr->CYL >= DP_NUMCY) { /* invalid cyl? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_SKE;
|
||||
uptr->CYL = DP_NUMCY - 1; }
|
||||
case FNC_SEEK3: /* waiting for flag */
|
||||
if (dpc_busy || FLG (devc)) { /* ctrl busy? wait */
|
||||
uptr->FNC = FNC_SEEK3; /* next state */
|
||||
sim_activate (uptr, dpc_xtime); }
|
||||
else {
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); } /* clear cmd */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_REF: /* refine sector */
|
||||
break; /* just a NOP */
|
||||
|
||||
case FNC_RD: /* read */
|
||||
case FNC_CHK1: /* check */
|
||||
if (dp_ptr == 0) { /* new sector? */
|
||||
if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break;
|
||||
if (uptr->CYL != dpc_rarc[drv]) /* wrong cyl? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */
|
||||
if (dpc_rars[drv] >= DP_NUMSC) { /* bad sector? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */
|
||||
break; }
|
||||
if (dpc_eoc) { /* end of cyl? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
|
||||
break; }
|
||||
da = GETDA (dpc_rarc[drv], dpc_rarh[drv], dpc_rars[drv]);
|
||||
dpc_rars[drv] = dpc_rars[drv] + 1; /* incr address */
|
||||
if (dpc_rars[drv] >= DP_NUMSC) { /* end of surf? */
|
||||
dpc_rars[drv] = 0; /* wrap to */
|
||||
dpc_rarh[drv] = dpc_rarh[drv] ^ 1; /* next head */
|
||||
dpc_eoc = ((dpc_rarh[drv] & 1) == 0); }/* calc eoc */
|
||||
if (err = fseek (uptr->fileref, da * sizeof (int16),
|
||||
SEEK_SET)) break;
|
||||
fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) break; }
|
||||
dpd_ibuf = dpxb[dp_ptr++]; /* get word */
|
||||
if (dp_ptr >= DP_NUMWD) { /* end of sector? */
|
||||
if (uptr->FNC == FNC_CHK1) { /* check? */
|
||||
dpc_cnt = (dpc_cnt - 1) & DA_CKMASK; /* decr count */
|
||||
if (dpc_cnt == 0) break; } /* stop at zero */
|
||||
dp_ptr = 0; } /* wrap buf ptr */
|
||||
if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */
|
||||
setFLG (devd); } /* set flag */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dpc_xtime); /* sched next word */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_INIT: /* init */
|
||||
case FNC_WD: /* write */
|
||||
if (dp_ptr == 0) { /* start sector? */
|
||||
if (!CMD (devd) && !dpd_wval) break; /* xfer done? */
|
||||
if (uptr->flags & UNIT_WPRT) { /* wr prot? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */
|
||||
break; } /* done */
|
||||
if ((uptr->CYL != dpc_rarc[drv]) || /* wrong cyl or */
|
||||
(dpc_rars[drv] >= DP_NUMSC)) { /* bad sector? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */
|
||||
break; }
|
||||
if (dpc_eoc) { /* end of cyl? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */
|
||||
break; } } /* done */
|
||||
dpxb[dp_ptr++] = dpd_wval? dpd_obuf: 0; /* store word/fill */
|
||||
dpd_wval = 0; /* clr data valid */
|
||||
if (dp_ptr >= DP_NUMWD) { /* buffer full? */
|
||||
da = GETDA (dpc_rarc[drv], dpc_rarh[drv], dpc_rars[drv]);
|
||||
dpc_rars[drv] = dpc_rars[drv] + 1; /* incr address */
|
||||
if (dpc_rars[drv] >= DP_NUMSC) { /* end of surf? */
|
||||
dpc_rars[drv] = 0; /* wrap to */
|
||||
dpc_rarh[drv] = dpc_rarh[drv] ^ 1; /* next head */
|
||||
dpc_eoc = ((dpc_rarh[drv] & 1) == 0); }/* calc eoc */
|
||||
if (err = fseek (uptr->fileref, da * sizeof (int16),
|
||||
SEEK_SET)) break;
|
||||
fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) break; /* error? */
|
||||
dp_ptr = 0; } /* next sector */
|
||||
if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */
|
||||
setFLG (devd); } /* set flag */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dpc_xtime); /* sched next word */
|
||||
return SCPE_OK;
|
||||
|
||||
default:
|
||||
return SCPE_IERR; } /* end case fnc */
|
||||
|
||||
if (!dp_ctype) dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* 12559 sets ATN */
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
dpc_busy = 0; /* ctlr is free */
|
||||
dpd_xfer = dpd_wval = 0;
|
||||
if (err != 0) { /* error? */
|
||||
perror ("DP I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dpc_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
hp_enbdis_pair (&dpc_dev, &dpd_dev); /* make pair cons */
|
||||
dpd_ibuf = dpd_obuf = 0; /* clear buffers */
|
||||
dpc_busy = dpc_obuf = 0;
|
||||
dpc_eoc = 0;
|
||||
dpd_xfer = dpd_wval = 0;
|
||||
dp_ptr = 0;
|
||||
dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */
|
||||
dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */
|
||||
dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */
|
||||
dpc_dib.flg = dpd_dib.flg = 1; /* set flg */
|
||||
sim_cancel (&dpd_unit); /* cancel dch */
|
||||
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
|
||||
sim_cancel (&dpc_unit[i]); /* cancel activity */
|
||||
dpc_unit[i].FNC = 0; /* clear function */
|
||||
dpc_unit[i].CYL = 0;
|
||||
dpc_rarc[i] = dpc_rarh[i] = dpc_rars[i] = 0;
|
||||
if (dpc_unit[i].flags & UNIT_ATT)
|
||||
dpc_sta[i] = dpc_sta[i] & STA_1ST;
|
||||
else dpc_sta[i] = 0; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat dpc_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
int32 drv;
|
||||
t_stat r;
|
||||
|
||||
drv = uptr - dpc_dev.units; /* get drive no */
|
||||
r = attach_unit (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r;
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_1ST; /* update status */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Set controller type */
|
||||
|
||||
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
|
||||
for (i = 0; i < DP_NUMDRV; i++) {
|
||||
if (dpc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; }
|
||||
for (i = 0; i < DP_NUMDRV; i++)
|
||||
dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2);
|
||||
dp_ctype = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show controller type */
|
||||
|
||||
t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if (dp_ctype) fprintf (st, "13210A");
|
||||
else fprintf (st, "12557A");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 7900/7901 bootstrap routine (HP 12992F ROM) */
|
||||
|
||||
#define LDR_BASE 077
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
|
||||
static const int32 dboot[IBL_LNT] = {
|
||||
0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */
|
||||
0106701+CHANGE_DEV, /* CLC CC ; clr cch */
|
||||
0017757, /* JSB STAT ; get status */
|
||||
0067746, /*SK LDB SKCMD ; seek cmd */
|
||||
0106600+CHANGE_DEV, /* OTB DC ; cyl # */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; to dch */
|
||||
0106601+CHANGE_DEV, /* OTB CC ; seek cmd */
|
||||
0103701+CHANGE_DEV, /* STC CC,C ; to cch */
|
||||
0102300+CHANGE_DEV, /* SFS DC ; addr wd ok? */
|
||||
0027710, /* JMP *-1 ; no, wait */
|
||||
0006400, /* CLB */
|
||||
0102501, /* LIA 1 ; read switches */
|
||||
0002011, /* SLA,RSS ; <0> set? */
|
||||
0047747, /* ADB BIT9 ; head 2 = fixed */
|
||||
0106600+CHANGE_DEV, /* OTB DC ; head/sector */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; to dch */
|
||||
0102301+CHANGE_DEV, /* SFS CC ; seek done? */
|
||||
0027720, /* JMP *-1 ; no, wait */
|
||||
0017757, /* JSB STAT ; get status */
|
||||
0067776, /* LDB DMACW ; DMA control */
|
||||
0106606, /* OTB 6 */
|
||||
0067750, /* LDB ADDR1 ; memory addr */
|
||||
0106602, /* OTB 2 */
|
||||
0102702, /* STC 2 ; flip DMA ctrl */
|
||||
0067752, /* LDB CNT ; word count */
|
||||
0106602, /* OTB 2 */
|
||||
0063745, /* LDB RDCMD ; read cmd */
|
||||
0102601+CHANGE_DEV, /* OTA CC ; to cch */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; start dch */
|
||||
0103606, /* STC 6,C ; start DMA */
|
||||
0103701+CHANGE_DEV, /* STC CC,C ; start cch */
|
||||
0102301+CHANGE_DEV, /* SFS CC ; done? */
|
||||
0027737, /* JMP *-1 ; no, wait */
|
||||
0017757, /* JSB STAT ; get status */
|
||||
0027775, /* JMP XT ; done */
|
||||
0037766, /*FSMSK 037766 ; status mask */
|
||||
0004000, /*STMSK 004000 ; unsafe mask */
|
||||
0020000, /*RDCMD 020000 ; read cmd */
|
||||
0030000, /*SKCMD 030000 ; seek cmd */
|
||||
0001000, /*BIT9 001000 ; head 2 select */
|
||||
0102011, /*ADDR1 102011 */
|
||||
0102055, /*ADDR2 102055 */
|
||||
0164000, /*CNT -6144. */
|
||||
0, 0, 0, 0, /* unused */
|
||||
0000000, /*STAT 0 */
|
||||
0002400, /* CLA ; status request */
|
||||
0102601+CHANGE_DEV, /* OTC CC ; to cch */
|
||||
0103701+CHANGE_DEV, /* STC CC,C ; start cch */
|
||||
0102300+CHANGE_DEV, /* SFS DC ; done? */
|
||||
0027763, /* JMP *-1 */
|
||||
0102500+CHANGE_DEV, /* LIA DC ; get status */
|
||||
0013743, /* AND FSMSK ; mask 15,14,3,0 */
|
||||
0002003, /* SZA,RSS ; drive ready? */
|
||||
0127757, /* JMP STAT,I ; yes */
|
||||
0013744, /* AND STMSK ; fault? */
|
||||
0002002, /* SZA */
|
||||
0102030, /* HLT 30 ; yes */
|
||||
0027700, /* JMP ST ; no, retry */
|
||||
0117751, /*XT JSB ADDR2,I ; start program */
|
||||
0120000+CHANGE_DEV, /*DMACW 120000+DC */
|
||||
0000000 }; /* -ST */
|
||||
|
||||
t_stat dpc_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, dev;
|
||||
|
||||
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
|
||||
dev = dpd_dib.devno; /* get data chan dev */
|
||||
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
|
||||
SR = IBL_DP + (dev << IBL_V_DEV); /* set SR */
|
||||
if (sim_switches & SWMASK ('F')) SR = SR | IBL_FIX; /* boot from fixed? */
|
||||
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
|
||||
if (dboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (dboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = dboot[i]; }
|
||||
M[PC + LDR_BASE] = (~PC + 1) & DMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1,720 +0,0 @@
|
||||
/* hp2100_dq.c: HP 2100 12565A disk simulator
|
||||
|
||||
Copyright (c) 1993-2003, Bill McDermith
|
||||
|
||||
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 the author shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from the author.
|
||||
|
||||
dq 12565A 2883 disk system
|
||||
|
||||
25-Apr-03 RMS Fixed bug in status check
|
||||
10-Nov-02 RMS Added boot command, rebuilt like 12559/13210
|
||||
09-Jan-02 WOM Copied dp driver and mods for 2883
|
||||
|
||||
Differences between 12559/13210 and 12565 controllers
|
||||
- 12565 stops transfers on address miscompares; 12559/13210 only stops writes
|
||||
- 12565 does not set error on positioner busy
|
||||
- 12565 does not set positioner busy if already on cylinder
|
||||
- 12565 does not need eoc logic, it will hit an invalid head number
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define FNC u3 /* saved function */
|
||||
#define CYL u4 /* cylinder */
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */
|
||||
|
||||
#define DQ_N_NUMWD 7
|
||||
#define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */
|
||||
#define DQ_NUMSC 23 /* sectors/track */
|
||||
#define DQ_NUMSF 20 /* tracks/cylinder */
|
||||
#define DQ_NUMCY 203 /* cylinders/disk */
|
||||
#define DQ_SIZE (DQ_NUMSF * DQ_NUMCY * DQ_NUMSC * DQ_NUMWD)
|
||||
#define DQ_NUMDRV 2 /* # drives */
|
||||
|
||||
/* Command word */
|
||||
|
||||
#define CW_V_FNC 12 /* function */
|
||||
#define CW_M_FNC 017
|
||||
#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC)
|
||||
/* 000 /* unused */
|
||||
#define FNC_STA 001 /* status check */
|
||||
#define FNC_RCL 002 /* recalibrate */
|
||||
#define FNC_SEEK 003 /* seek */
|
||||
#define FNC_RD 004 /* read */
|
||||
#define FNC_WD 005 /* write */
|
||||
#define FNC_RA 006 /* read address */
|
||||
#define FNC_WA 007 /* write address */
|
||||
#define FNC_CHK 010 /* check */
|
||||
#define FNC_LA 013 /* load address */
|
||||
#define FNC_AS 014 /* address skip */
|
||||
|
||||
#define FNC_SEEK1 020 /* fake - seek1 */
|
||||
#define FNC_SEEK2 021 /* fake - seek2 */
|
||||
#define FNC_SEEK3 022 /* fake - seek3 */
|
||||
#define FNC_CHK1 023 /* fake - check1 */
|
||||
#define FNC_LA1 024 /* fake - ldaddr1 */
|
||||
|
||||
#define CW_V_DRV 0 /* drive */
|
||||
#define CW_M_DRV 01
|
||||
#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV)
|
||||
|
||||
/* Disk address words */
|
||||
|
||||
#define DA_V_CYL 0 /* cylinder */
|
||||
#define DA_M_CYL 0377
|
||||
#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL)
|
||||
#define DA_V_HD 8 /* head */
|
||||
#define DA_M_HD 037
|
||||
#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD)
|
||||
#define DA_V_SC 0 /* sector */
|
||||
#define DA_M_SC 037
|
||||
#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)
|
||||
#define DA_CKMASK 0777 /* check mask */
|
||||
|
||||
/* Status in dqc_sta[drv] - (d) = dynamic */
|
||||
|
||||
#define STA_DID 0000200 /* drive ID (d) */
|
||||
#define STA_NRDY 0000100 /* not ready (d) */
|
||||
#define STA_EOC 0000040 /* end of cylinder */
|
||||
#define STA_AER 0000020 /* addr error */
|
||||
#define STA_FLG 0000010 /* flagged */
|
||||
#define STA_BSY 0000004 /* seeking */
|
||||
#define STA_DTE 0000002 /* data error */
|
||||
#define STA_ERR 0000001 /* any error */
|
||||
#define STA_ALLERR (STA_NRDY + STA_EOC + STA_AER + STA_FLG + STA_DTE)
|
||||
|
||||
extern uint16 *M;
|
||||
extern uint32 PC, SR;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
extern int32 sim_switches;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 dqc_busy = 0; /* cch xfer */
|
||||
int32 dqc_cnt = 0; /* check count */
|
||||
int32 dqc_stime = 100; /* seek time */
|
||||
int32 dqc_ctime = 100; /* command time */
|
||||
int32 dqc_xtime = 5; /* xfer time */
|
||||
int32 dqc_dtime = 2; /* dch time */
|
||||
int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */
|
||||
int32 dqc_obuf = 0; /* cch buffers */
|
||||
int32 dqd_xfer = 0; /* xfer in prog */
|
||||
int32 dqd_wval = 0; /* write data valid */
|
||||
int32 dq_ptr = 0; /* buffer ptr */
|
||||
uint8 dqc_rarc[DQ_NUMDRV] = { 0 }; /* cylinder */
|
||||
uint8 dqc_rarh[DQ_NUMDRV] = { 0 }; /* head */
|
||||
uint8 dqc_rars[DQ_NUMDRV] = { 0 }; /* sector */
|
||||
uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* status regs */
|
||||
uint16 dqxb[DQ_NUMWD]; /* sector buffer */
|
||||
|
||||
DEVICE dqd_dev, dqc_dev;
|
||||
int32 dqdio (int32 inst, int32 IR, int32 dat);
|
||||
int32 dqcio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat dqc_svc (UNIT *uptr);
|
||||
t_stat dqd_svc (UNIT *uptr);
|
||||
t_stat dqc_reset (DEVICE *dptr);
|
||||
t_stat dqc_boot (int32 unitno, DEVICE *dptr);
|
||||
void dq_god (int32 fnc, int32 drv, int32 time);
|
||||
void dq_goc (int32 fnc, int32 drv, int32 time);
|
||||
|
||||
/* DQD data structures
|
||||
|
||||
dqd_dev DQD device descriptor
|
||||
dqd_unit DQD unit list
|
||||
dqd_reg DQD register list
|
||||
*/
|
||||
|
||||
DIB dq_dib[] = {
|
||||
{ DQD, 0, 0, 0, 0, &dqdio },
|
||||
{ DQC, 0, 0, 0, 0, &dqcio } };
|
||||
|
||||
#define dqd_dib dq_dib[0]
|
||||
#define dqc_dib dq_dib[1]
|
||||
|
||||
UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) };
|
||||
|
||||
REG dqd_reg[] = {
|
||||
{ ORDATA (IBUF, dqd_ibuf, 16) },
|
||||
{ ORDATA (OBUF, dqd_obuf, 16) },
|
||||
{ FLDATA (CMD, dqd_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, dqd_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, dqd_dib.flg, 0) },
|
||||
{ FLDATA (FBF, dqd_dib.fbf, 0) },
|
||||
{ FLDATA (XFER, dqd_xfer, 0) },
|
||||
{ FLDATA (WVAL, dqd_wval, 0) },
|
||||
{ BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) },
|
||||
{ DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) },
|
||||
{ ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dqd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dqd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dqd_dev = {
|
||||
"DQD", &dqd_unit, dqd_reg, dqd_mod,
|
||||
1, 10, DQ_N_NUMWD, 1, 8, 16,
|
||||
NULL, NULL, &dqc_reset,
|
||||
NULL, NULL, NULL,
|
||||
&dqd_dib, 0 };
|
||||
|
||||
/* DQC data structures
|
||||
|
||||
dqc_dev DQC device descriptor
|
||||
dqc_unit DQC unit list
|
||||
dqc_reg DQC register list
|
||||
dqc_mod DQC modifier list
|
||||
*/
|
||||
|
||||
UNIT dqc_unit[] = {
|
||||
{ UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, DQ_SIZE) },
|
||||
{ UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, DQ_SIZE) } };
|
||||
|
||||
REG dqc_reg[] = {
|
||||
{ ORDATA (OBUF, dqc_obuf, 16) },
|
||||
{ ORDATA (BUSY, dqc_busy, 2), REG_RO },
|
||||
{ ORDATA (CNT, dqc_cnt, 9) },
|
||||
{ FLDATA (CMD, dqc_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, dqc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, dqc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, dqc_dib.fbf, 0) },
|
||||
{ BRDATA (RARC, dqc_rarc, 8, 8, DQ_NUMDRV) },
|
||||
{ BRDATA (RARH, dqc_rarh, 8, 5, DQ_NUMDRV) },
|
||||
{ BRDATA (RARS, dqc_rars, 8, 5, DQ_NUMDRV) },
|
||||
{ BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) },
|
||||
{ DRDATA (CTIME, dqc_ctime, 24), PV_LEFT },
|
||||
{ DRDATA (DTIME, dqc_dtime, 24), PV_LEFT },
|
||||
{ DRDATA (STIME, dqc_stime, 24), PV_LEFT },
|
||||
{ DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT },
|
||||
{ URDATA (UCYL, dqc_unit[0].CYL, 10, 8, 0,
|
||||
DQ_NUMDRV, PV_LEFT | REG_HRO) },
|
||||
{ URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0,
|
||||
DQ_NUMDRV, REG_HRO) },
|
||||
{ ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dqc_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dqd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dqc_dev = {
|
||||
"DQC", dqc_unit, dqc_reg, dqc_mod,
|
||||
DQ_NUMDRV, 8, 24, 1, 8, 16,
|
||||
NULL, NULL, &dqc_reset,
|
||||
&dqc_boot, NULL, NULL,
|
||||
&dqc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 dqdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
dqd_obuf = dat;
|
||||
if (!dqc_busy || dqd_xfer) dqd_wval = 1; /* if !overrun, valid */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | dqd_ibuf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = dqd_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCTL (devd); /* clr ctl, cmd */
|
||||
clrCMD (devd);
|
||||
dqd_xfer = 0; } /* clr xfer */
|
||||
else { /* STC */
|
||||
setCTL (devd); /* set ctl, cmd */
|
||||
setCMD (devd);
|
||||
if (dqc_busy && !dqd_xfer) /* overrun? */
|
||||
dqc_sta[dqc_busy - 1] |= STA_DTE | STA_ERR; }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 dqcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devc, fnc, drv;
|
||||
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
dqc_obuf = dat;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
break; /* no data */
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC? */
|
||||
clrCMD (devc); /* clr cmd, ctl */
|
||||
clrCTL (devc); /* cancel non-seek */
|
||||
if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]);
|
||||
sim_cancel (&dqd_unit); /* cancel dch */
|
||||
dqd_xfer = 0; /* clr dch xfer */
|
||||
dqc_busy = 0; } /* clr busy */
|
||||
else { /* STC */
|
||||
setCTL (devc); /* set ctl */
|
||||
if (!CMD (devc)) { /* cmd clr? */
|
||||
setCMD (devc); /* set cmd, ctl */
|
||||
drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */
|
||||
fnc = CW_GETFNC (dqc_obuf); /* from cmd word */
|
||||
switch (fnc) { /* case on fnc */
|
||||
case FNC_SEEK: case FNC_RCL: /* seek, recal */
|
||||
case FNC_CHK: /* check */
|
||||
dqc_sta[drv] = 0; /* clear status */
|
||||
case FNC_STA: case FNC_LA: /* rd sta, load addr */
|
||||
dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */
|
||||
break;
|
||||
case FNC_RD: case FNC_WD: /* read, write */
|
||||
case FNC_RA: case FNC_WA: /* rd addr, wr addr */
|
||||
case FNC_AS: /* address skip */
|
||||
dq_goc (fnc, drv, dqc_ctime); /* sched drive */
|
||||
break; } /* end case */
|
||||
} /* end if !CMD */
|
||||
} /* end else */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Start data channel operation */
|
||||
|
||||
void dq_god (int32 fnc, int32 drv, int32 time)
|
||||
{
|
||||
dqd_unit.CYL = drv; /* save unit */
|
||||
dqd_unit.FNC = fnc; /* save function */
|
||||
sim_activate (&dqd_unit, time);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start controller operation */
|
||||
|
||||
void dq_goc (int32 fnc, int32 drv, int32 time)
|
||||
{
|
||||
if (sim_is_active (&dqc_unit[drv])) { /* still seeking? */
|
||||
sim_cancel (&dqc_unit[drv]); /* cancel */
|
||||
time = time + dqc_stime; } /* take longer */
|
||||
dqc_sta[drv] = 0; /* clear status */
|
||||
dq_ptr = 0; /* init buf ptr */
|
||||
dqc_busy = drv + 1; /* set busy */
|
||||
dqd_xfer = 1; /* xfer in prog */
|
||||
dqc_unit[drv].FNC = fnc; /* save function */
|
||||
sim_activate (&dqc_unit[drv], time); /* activate unit */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Data channel unit service
|
||||
|
||||
This routine handles the data channel transfers. It also handles
|
||||
data transfers that are blocked by seek in progress.
|
||||
|
||||
uptr->CYL = target drive
|
||||
uptr->FNC = target function
|
||||
|
||||
Seek substates
|
||||
seek - transfer cylinder
|
||||
seek1 - transfer head/surface, sched drive
|
||||
Recalibrate substates
|
||||
rcl - clear cyl/head/surface, sched drive
|
||||
Load address
|
||||
la - transfer cylinder
|
||||
la1 - transfer head/surface, finish operation
|
||||
Status check - transfer status, finish operation
|
||||
Check data
|
||||
chk - transfer sector count, sched drive
|
||||
*/
|
||||
|
||||
t_stat dqd_svc (UNIT *uptr)
|
||||
{
|
||||
int32 drv, devc, devd, st;
|
||||
|
||||
drv = uptr->CYL; /* get drive no */
|
||||
devc = dqc_dib.devno; /* get cch devno */
|
||||
devd = dqd_dib.devno; /* get dch devno */
|
||||
switch (uptr->FNC) { /* case function */
|
||||
|
||||
case FNC_SEEK: /* seek, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */
|
||||
dqd_wval = 0; /* clr data valid */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr->FNC = FNC_SEEK1; } /* advance state */
|
||||
sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
break;
|
||||
case FNC_SEEK1: /* seek, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */
|
||||
dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */
|
||||
dqd_wval = 0; /* clr data valid */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
if (sim_is_active (&dqc_unit[drv])) break; /* if busy */
|
||||
st = abs (dqc_rarc[drv] - dqc_unit[drv].CYL) * dqc_stime;
|
||||
if (st == 0) st = dqc_xtime; /* if on cyl, min time */
|
||||
else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */
|
||||
sim_activate (&dqc_unit[drv], st); /* schedule op */
|
||||
dqc_unit[drv].CYL = dqc_rarc[drv]; /* on cylinder */
|
||||
dqc_unit[drv].FNC = FNC_SEEK2; } /* advance state */
|
||||
else sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
break;
|
||||
|
||||
case FNC_RCL: /* recalibrate */
|
||||
dqc_rarc[drv] = dqc_rarh[drv] = dqc_rars[drv] = 0; /* clear RAR */
|
||||
if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */
|
||||
st = dqc_unit[drv].CYL * dqc_stime; /* calc diff */
|
||||
if (st == 0) st = dqc_xtime; /* if on cyl, min time */
|
||||
else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */
|
||||
sim_activate (&dqc_unit[drv], st); /* schedule drive */
|
||||
dqc_unit[drv].CYL = 0; /* on cylinder */
|
||||
dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */
|
||||
break;
|
||||
|
||||
case FNC_LA: /* arec, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */
|
||||
dqd_wval = 0; /* clr data valid */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr->FNC = FNC_LA1; } /* advance state */
|
||||
sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
break;
|
||||
case FNC_LA1: /* arec, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */
|
||||
dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */
|
||||
dqd_wval = 0; /* clr data valid */
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); } /* clr dch cmd */
|
||||
else sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
break;
|
||||
|
||||
case FNC_STA: /* read status */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
if (dqc_unit[drv].flags & UNIT_ATT) /* attached? */
|
||||
dqd_ibuf = dqc_sta[drv] & ~STA_DID;
|
||||
else dqd_ibuf = STA_NRDY;
|
||||
if (drv) dqd_ibuf = dqd_ibuf | STA_DID;
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */
|
||||
~(STA_DTE | STA_FLG | STA_AER | STA_EOC | STA_ERR);
|
||||
}
|
||||
else sim_activate (uptr, dqc_xtime); /* wait more */
|
||||
break;
|
||||
|
||||
case FNC_CHK: /* check, need cnt */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */
|
||||
dqd_wval = 0; /* clr data valid */
|
||||
/* setFLG (devd); /* set dch flg */
|
||||
/* clrCMD (devd); /* clr dch cmd */
|
||||
dq_goc (FNC_CHK1, drv, dqc_ctime); } /* sched drv */
|
||||
else sim_activate (uptr, dqc_xtime); /* wait more */
|
||||
break;
|
||||
|
||||
default:
|
||||
return SCPE_IERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Drive unit service
|
||||
|
||||
This routine handles the data transfers.
|
||||
|
||||
Seek substates
|
||||
seek2 - done
|
||||
Recalibrate substate
|
||||
rcl1 - done
|
||||
Check data substates
|
||||
chk1 - finish operation
|
||||
Read
|
||||
Read address
|
||||
Address skip (read without header check)
|
||||
Write
|
||||
Write address
|
||||
*/
|
||||
|
||||
#define GETDA(x,y,z) \
|
||||
(((((x) * DQ_NUMSF) + (y)) * DQ_NUMSC) + (z)) * DQ_NUMWD
|
||||
|
||||
t_stat dqc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 da, drv, devc, devd, err;
|
||||
|
||||
err = 0; /* assume no err */
|
||||
drv = uptr - dqc_dev.units; /* get drive no */
|
||||
devc = dqc_dib.devno; /* get cch devno */
|
||||
devd = dqd_dib.devno; /* get dch devno */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
dqc_sta[drv] = 0; /* clr status */
|
||||
dqc_busy = 0; /* ctlr is free */
|
||||
dqd_xfer = dqd_wval = 0;
|
||||
return SCPE_OK; }
|
||||
switch (uptr->FNC) { /* case function */
|
||||
|
||||
case FNC_SEEK2: /* seek done */
|
||||
if (uptr->CYL >= DQ_NUMCY) { /* out of range? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR;
|
||||
dqc_unit[drv].CYL = 0; }
|
||||
else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */
|
||||
case FNC_SEEK3:
|
||||
if (dqc_busy || FLG (devc)) { /* ctrl busy? */
|
||||
uptr->FNC = FNC_SEEK3; /* next state */
|
||||
sim_activate (uptr, dqc_xtime); } /* ctrl busy? wait */
|
||||
else {
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); } /* clr cch cmd */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_RA: /* read addr */
|
||||
if (!CMD (devd)) break; /* dch clr? done */
|
||||
if (dq_ptr == 0) dqd_ibuf = uptr->CYL; /* 1st word? */
|
||||
else if (dq_ptr == 1) { /* second word? */
|
||||
dqd_ibuf = (dqc_rarh[drv] << DA_V_HD) |
|
||||
(dqc_rars[drv] << DA_V_SC);
|
||||
dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */
|
||||
if (dqc_rars[drv] >= DQ_NUMSC) /* end of surf? */
|
||||
dqc_rars[drv] = 0; }
|
||||
else break;
|
||||
dq_ptr = dq_ptr + 1;
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dqc_xtime); /* sched next word */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_AS: /* address skip */
|
||||
case FNC_RD: /* read */
|
||||
case FNC_CHK1: /* check */
|
||||
if (dq_ptr == 0) { /* new sector? */
|
||||
if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break;
|
||||
if ((uptr->CYL != dqc_rarc[drv]) || /* wrong cyl or */
|
||||
(dqc_rars[drv] >= DQ_NUMSC)) { /* bad sector? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER | STA_ERR;
|
||||
break; }
|
||||
if (dqc_rarh[drv] >= DQ_NUMSF) { /* bad head? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_EOC | STA_ERR;
|
||||
break; }
|
||||
da = GETDA (dqc_rarc[drv], dqc_rarh[drv], dqc_rars[drv]);
|
||||
dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */
|
||||
if (dqc_rars[drv] >= DQ_NUMSC) { /* end of surf? */
|
||||
dqc_rars[drv] = 0; /* wrap to */
|
||||
dqc_rarh[drv] = dqc_rarh[drv] + 1; } /* next head */
|
||||
if (err = fseek (uptr->fileref, da * sizeof (int16),
|
||||
SEEK_SET)) break;
|
||||
fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) break; }
|
||||
dqd_ibuf = dqxb[dq_ptr++]; /* get word */
|
||||
if (dq_ptr >= DQ_NUMWD) { /* end of sector? */
|
||||
if (uptr->FNC == FNC_CHK1) { /* check? */
|
||||
dqc_cnt = (dqc_cnt - 1) & DA_CKMASK; /* decr count */
|
||||
if (dqc_cnt == 0) break; } /* if zero, done */
|
||||
dq_ptr = 0; } /* wrap buf ptr */
|
||||
if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */
|
||||
setFLG (devd); } /* set flag */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dqc_xtime); /* sched next word */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_WA: /* write address */
|
||||
case FNC_WD: /* write */
|
||||
if (dq_ptr == 0) { /* sector start? */
|
||||
if (!CMD (devd) && !dqd_wval) break; /* xfer done? */
|
||||
if(uptr->flags & UNIT_WPRT) { /* write protect? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_FLG | STA_ERR;
|
||||
break; } /* done */
|
||||
if ((uptr->CYL != dqc_rarc[drv]) || /* wrong cyl or */
|
||||
(dqc_rars[drv] >= DQ_NUMSC)) { /* bad sector? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER | STA_ERR;
|
||||
break; }
|
||||
if (dqc_rarh[drv] >= DQ_NUMSF) { /* bad head? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_EOC | STA_ERR;
|
||||
break; } } /* done */
|
||||
dqxb[dq_ptr++] = dqd_wval? dqd_obuf: 0; /* store word/fill */
|
||||
dqd_wval = 0; /* clr data valid */
|
||||
if (dq_ptr >= DQ_NUMWD) { /* buffer full? */
|
||||
da = GETDA (dqc_rarc[drv], dqc_rarh[drv], dqc_rars[drv]);
|
||||
dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */
|
||||
if (dqc_rars[drv] >= DQ_NUMSC) { /* end of surf? */
|
||||
dqc_rars[drv] = 0; /* wrap to */
|
||||
dqc_rarh[drv] = dqc_rarh[drv] + 1; } /* next head */
|
||||
if (err = fseek (uptr->fileref, da * sizeof (int16),
|
||||
SEEK_SET)) return TRUE;
|
||||
fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) break;
|
||||
dq_ptr = 0; }
|
||||
if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */
|
||||
setFLG (devd); } /* set flag */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dqc_xtime); /* sched next word */
|
||||
return SCPE_OK;
|
||||
|
||||
default:
|
||||
return SCPE_IERR; } /* end case fnc */
|
||||
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); /* clr cch cmd */
|
||||
dqc_busy = 0; /* ctlr is free */
|
||||
dqd_xfer = dqd_wval = 0;
|
||||
if (err != 0) { /* error? */
|
||||
perror ("DQ I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dqc_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
hp_enbdis_pair (&dqc_dev, &dqd_dev); /* make pair cons */
|
||||
dqd_ibuf = dqd_obuf = 0; /* clear buffers */
|
||||
dqc_busy = dqc_obuf = 0;
|
||||
dqd_xfer = dqd_wval = 0;
|
||||
dq_ptr = 0;
|
||||
dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */
|
||||
dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */
|
||||
dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */
|
||||
dqc_dib.flg = dqd_dib.flg = 1; /* set flg */
|
||||
sim_cancel (&dqd_unit); /* cancel dch */
|
||||
for (i = 0; i < DQ_NUMDRV; i++) { /* loop thru drives */
|
||||
sim_cancel (&dqc_unit[i]); /* cancel activity */
|
||||
dqc_unit[i].FNC = 0; /* clear function */
|
||||
dqc_unit[i].CYL = 0;
|
||||
dqc_rarc[i] = dqc_rarh[i] = dqc_rars[i] = 0; /* clear rar */
|
||||
dqc_sta[i] = 0; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write lock/enable routine */
|
||||
|
||||
t_stat dqc_vlock (UNIT *uptr, int32 val)
|
||||
{
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 2883/2884 bootstrap routine (subset HP 12992A ROM) */
|
||||
|
||||
#define LDR_BASE 077
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
|
||||
static const int32 dboot[IBL_LNT] = {
|
||||
0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */
|
||||
0106701+CHANGE_DEV, /* CLC CC ; clr cch */
|
||||
0067771, /* LDA SKCMD ; seek cmd */
|
||||
0106600+CHANGE_DEV, /* OTB DC ; cyl # */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; to dch */
|
||||
0106601+CHANGE_DEV, /* OTB CC ; seek cmd */
|
||||
0103701+CHANGE_DEV, /* STC CC,C ; to cch */
|
||||
0102300+CHANGE_DEV, /* SFS DC ; addr wd ok? */
|
||||
0027707, /* JMP *-1 ; no, wait */
|
||||
0006400, /* CLB */
|
||||
0106600+CHANGE_DEV, /* OTB DC ; head/sector */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; to dch */
|
||||
0102301+CHANGE_DEV, /* SFS CC ; seek done? */
|
||||
0027714, /* JMP *-1 ; no, wait */
|
||||
0063770, /* LDA RDCMD ; get read read */
|
||||
0067776, /* LDB DMACW ; DMA control */
|
||||
0106606, /* OTB 6 */
|
||||
0067772, /* LDB ADDR1 ; memory addr */
|
||||
0106602, /* OTB 2 */
|
||||
0102702, /* STC 2 ; flip DMA ctrl */
|
||||
0067774, /* LDB CNT ; word count */
|
||||
0106602, /* OTB 2 */
|
||||
0102601+CHANGE_DEV, /* OTA CC ; to cch */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; start dch */
|
||||
0103606, /* STC 6,C ; start DMA */
|
||||
0103701+CHANGE_DEV, /* STC CC,C ; start cch */
|
||||
0102301+CHANGE_DEV, /* SFS CC ; done? */
|
||||
0027732, /* JMP *-1 ; no, wait */
|
||||
0027775, /* JMP XT ; done */
|
||||
0, 0, 0, /* unused */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0020000, /*RDCMD 020000 ; read cmd */
|
||||
0030000, /*SKCMD 030000 ; seek cmd */
|
||||
0102011, /*ADDR1 102011 */
|
||||
0102055, /*ADDR2 102055 */
|
||||
0164000, /*CNT -6144. */
|
||||
0117773, /*XT JSB ADDR2,I ; start program */
|
||||
0120000+CHANGE_DEV, /*DMACW 120000+DC */
|
||||
0000000 }; /* -ST */
|
||||
|
||||
t_stat dqc_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, dev;
|
||||
|
||||
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
|
||||
dev = dqd_dib.devno; /* get data chan dev */
|
||||
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
|
||||
SR = IBL_DQ + (dev << IBL_V_DEV); /* set SR */
|
||||
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
|
||||
if (dboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (dboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = dboot[i]; }
|
||||
M[PC + LDR_BASE] = (~PC + 1) & DMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,422 +0,0 @@
|
||||
/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
fhd 12606B 2770/2771 fixed head disk
|
||||
12610B 2773/2774/2775 drum
|
||||
|
||||
These head-per-track devices are buffered in memory, to minimize overhead.
|
||||
|
||||
The drum data channel does not have a command flip-flop. Its control
|
||||
flip-flop is not wired into the interrupt chain; accordingly, the
|
||||
simulator uses command rather than control for the data channel. Its
|
||||
flag does not respond to SFS, SFC, or STF.
|
||||
|
||||
The drum control channel does not have any of the traditional flip-flops.
|
||||
|
||||
27-Jul-03 RMS Fixed drum sizes
|
||||
Fixed variable capacity interaction with SAVE/RESTORE
|
||||
10-Nov-02 RMS Added BOOT command
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include <math.h>
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define DR_NUMWD 64 /* words/sector */
|
||||
#define DR_FNUMSC 90 /* fhd sec/track */
|
||||
#define DR_DNUMSC 32 /* drum sec/track */
|
||||
#define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)
|
||||
#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */
|
||||
#define UNIT_V_SZ (UNIT_V_UF) /* disk vs drum */
|
||||
#define UNIT_M_SZ 017 /* size */
|
||||
#define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ)
|
||||
#define UNIT_DR (1 << UNIT_V_SZ) /* low order bit */
|
||||
#define SZ_180K 000 /* disks */
|
||||
#define SZ_360K 002
|
||||
#define SZ_720K 004
|
||||
#define SZ_1024K 001 /* drums: default size */
|
||||
#define SZ_1536K 003
|
||||
#define SZ_384K 005
|
||||
#define SZ_512K 007
|
||||
#define SZ_640K 011
|
||||
#define SZ_768K 013
|
||||
#define SZ_896K 015
|
||||
#define DR_GETSZ(x) (((x) >> UNIT_V_SZ) & UNIT_M_SZ)
|
||||
|
||||
/* Command word */
|
||||
|
||||
#define CW_WR 0100000 /* write vs read */
|
||||
#define CW_V_FTRK 7 /* fhd track */
|
||||
#define CW_M_FTRK 0177
|
||||
#define CW_V_DTRK 5 /* drum track */
|
||||
#define CW_M_DTRK 01777
|
||||
#define MAX_TRK (((drc_unit.flags & UNIT_DR)? CW_M_DTRK: CW_M_FTRK) + 1)
|
||||
#define CW_GETTRK(x) ((drc_unit.flags & UNIT_DR)? \
|
||||
(((x) >> CW_V_DTRK) & CW_M_DTRK): \
|
||||
(((x) >> CW_V_FTRK) & CW_M_FTRK))
|
||||
#define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DR)? \
|
||||
(((x) & CW_M_DTRK) << CW_V_DTRK): \
|
||||
(((x) & CW_M_FTRK) << CW_V_FTRK))
|
||||
#define CW_V_FSEC 0 /* fhd sector */
|
||||
#define CW_M_FSEC 0177
|
||||
#define CW_V_DSEC 0 /* drum sector */
|
||||
#define CW_M_DSEC 037
|
||||
#define CW_GETSEC(x) ((drc_unit.flags & UNIT_DR)? \
|
||||
(((x) >> CW_V_DSEC) & CW_M_DSEC): \
|
||||
(((x) >> CW_V_FSEC) & CW_M_FSEC))
|
||||
#define CW_PUTSEC(x) ((drc_unit.flags & UNIT_DR)? \
|
||||
(((x) & CW_M_DSEC) << CW_V_DSEC): \
|
||||
(((x) & CW_M_FSEC) << CW_V_FSEC))
|
||||
|
||||
/* Status register */
|
||||
|
||||
#define DRS_V_NS 8 /* next sector */
|
||||
#define DRS_M_NS 0177
|
||||
#define DRS_SEC 0100000 /* sector flag */
|
||||
#define DRS_RDY 0000200 /* ready */
|
||||
#define DRS_RIF 0000100 /* read inhibit */
|
||||
#define DRS_SAC 0000040 /* sector coincidence */
|
||||
#define DRS_ABO 0000010 /* abort */
|
||||
#define DRS_WEN 0000004 /* write enabled */
|
||||
#define DRS_PER 0000002 /* parity error */
|
||||
#define DRS_BSY 0000001 /* busy */
|
||||
|
||||
#define GET_CURSEC(x) ((int32) fmod (sim_gtime() / ((double) (x)), \
|
||||
((double) ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC))))
|
||||
|
||||
extern UNIT cpu_unit;
|
||||
extern uint16 *M;
|
||||
extern uint32 PC;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
|
||||
int32 drc_cw = 0; /* fnc, addr */
|
||||
int32 drc_sta = 0; /* status */
|
||||
int32 drd_ibuf = 0; /* input buffer */
|
||||
int32 drd_obuf = 0; /* output buffer */
|
||||
int32 drd_ptr = 0; /* sector pointer */
|
||||
int32 dr_stopioe = 1; /* stop on error */
|
||||
int32 dr_time = 10; /* time per word */
|
||||
|
||||
static int32 sz_tab[16] = {
|
||||
184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288,
|
||||
0, 655360, 0, 786432, 0, 917504, 0, 0 };
|
||||
|
||||
DEVICE drd_dev, drc_dev;
|
||||
int32 drdio (int32 inst, int32 IR, int32 dat);
|
||||
int32 drcio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat drc_svc (UNIT *uptr);
|
||||
t_stat drc_reset (DEVICE *dptr);
|
||||
t_stat drc_attach (UNIT *uptr, char *cptr);
|
||||
t_stat drc_boot (int32 unitno, DEVICE *dptr);
|
||||
int32 dr_incda (int32 trk, int32 sec, int32 ptr);
|
||||
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* DRD data structures
|
||||
|
||||
drd_dev device descriptor
|
||||
drd_unit unit descriptor
|
||||
drd_reg register list
|
||||
*/
|
||||
|
||||
DIB dr_dib[] = {
|
||||
{ DRD, 0, 0, 0, 0, &drdio },
|
||||
{ DRC, 0, 0, 0, 0, &drcio } };
|
||||
|
||||
#define drd_dib dr_dib[0]
|
||||
#define drc_dib dr_dib[1]
|
||||
|
||||
UNIT drd_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG drd_reg[] = {
|
||||
{ ORDATA (IBUF, drd_ibuf, 16) },
|
||||
{ ORDATA (OBUF, drd_obuf, 16) },
|
||||
{ FLDATA (CMD, drd_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, drd_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, drd_dib.flg, 0) },
|
||||
{ FLDATA (FBF, drd_dib.fbf, 0) },
|
||||
{ ORDATA (BPTR, drd_ptr, 6) },
|
||||
{ ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB drd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &drd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE drd_dev = {
|
||||
"DRD", &drd_unit, drd_reg, drd_mod,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
&drd_dib, DEV_DISABLE };
|
||||
|
||||
/* DRC data structures
|
||||
|
||||
drc_dev device descriptor
|
||||
drc_unit unit descriptor
|
||||
drc_mod unit modifiers
|
||||
drc_reg register list
|
||||
*/
|
||||
|
||||
UNIT drc_unit =
|
||||
{ UDATA (&drc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
|
||||
UNIT_MUSTBUF+UNIT_DR+UNIT_BINK, DR_SIZE) };
|
||||
|
||||
REG drc_reg[] = {
|
||||
{ ORDATA (CW, drc_cw, 16) },
|
||||
{ ORDATA (STA, drc_sta, 16) },
|
||||
{ FLDATA (CMD, drc_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, drc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, drc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, drc_dib.fbf, 0) },
|
||||
{ DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, dr_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO },
|
||||
{ DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB drc_mod[] = {
|
||||
{ UNIT_DR, 0, "disk", NULL, NULL },
|
||||
{ UNIT_DR, UNIT_DR, "drum", NULL, NULL },
|
||||
{ UNIT_SZ, (SZ_180K << UNIT_V_SZ), NULL, "180K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_360K << UNIT_V_SZ), NULL, "360K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_720K << UNIT_V_SZ), NULL, "720K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_384K << UNIT_V_SZ), NULL, "384K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_512K << UNIT_V_SZ), NULL, "512K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_640K << UNIT_V_SZ), NULL, "640K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_768K << UNIT_V_SZ), NULL, "768K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size },
|
||||
{ UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &drd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE drc_dev = {
|
||||
"DRC", &drc_unit, drc_reg, drc_mod,
|
||||
1, 8, 21, 1, 8, 16,
|
||||
NULL, NULL, &drc_reset,
|
||||
&drc_boot, &drc_attach, NULL,
|
||||
&drc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 drdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd, t;
|
||||
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOTX: /* output */
|
||||
drd_obuf = dat;
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | drd_ibuf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = drd_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_AB) { /* CLC */
|
||||
clrCMD (devd); /* clr "ctl" */
|
||||
clrFLG (devd); /* clr flg */
|
||||
drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */
|
||||
else if (!CMD (devd)) { /* STC, not set? */
|
||||
setCMD (devd); /* set "ctl" */
|
||||
if (drc_cw & CW_WR) { setFLG (devd); } /* prime DMA */
|
||||
drc_sta = 0; /* clear errors */
|
||||
drd_ptr = 0; /* clear sec ptr */
|
||||
sim_cancel (&drc_unit); /* cancel curr op */
|
||||
t = CW_GETSEC (drc_cw) - GET_CURSEC (dr_time * DR_NUMWD);
|
||||
if (t <= 0) t = t + DR_NUMSC;
|
||||
sim_activate (&drc_unit, t * DR_NUMWD * dr_time); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 drcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 st;
|
||||
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioSFC: /* skip flag clear */
|
||||
PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
drc_cw = dat;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
if (drc_unit.flags & UNIT_ATT) /* attached? */
|
||||
st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta |
|
||||
(sim_is_active (&drc_unit)? DRS_BSY: 0);
|
||||
else st = drc_sta;
|
||||
dat = dat | st; /* merge status */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat drc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 devd, trk, sec;
|
||||
uint32 da;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
drc_sta = DRS_ABO;
|
||||
return IORETURN (dr_stopioe, SCPE_UNATT); }
|
||||
|
||||
drc_sta = drc_sta | DRS_SAC;
|
||||
devd = drd_dib.devno; /* get dch devno */
|
||||
trk = CW_GETTRK (drc_cw);
|
||||
sec = CW_GETSEC (drc_cw);
|
||||
da = ((trk * DR_NUMSC) + sec) * DR_NUMWD;
|
||||
|
||||
if (drc_cw & CW_WR) { /* write? */
|
||||
if ((da < uptr->capac) && (sec < DR_NUMSC)) {
|
||||
*(((uint16 *) uptr->filebuf) + da + drd_ptr) = drd_obuf;
|
||||
if (((uint32) (da + drd_ptr)) >= uptr->hwmark)
|
||||
uptr->hwmark = da + drd_ptr + 1; }
|
||||
drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
setFLG (devd); /* set dch flg */
|
||||
sim_activate (uptr, dr_time); } /* sched next word */
|
||||
else if (drd_ptr) { /* done, need to fill? */
|
||||
for ( ; drd_ptr < DR_NUMWD; drd_ptr++)
|
||||
*(((uint16 *) uptr->filebuf) + da + drd_ptr) = 0; }
|
||||
} /* end write */
|
||||
else { /* read */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0;
|
||||
else drd_ibuf = *(((uint16 *) uptr->filebuf) + da + drd_ptr);
|
||||
drd_ptr = dr_incda (trk, sec, drd_ptr);
|
||||
setFLG (devd); /* set dch flg */
|
||||
sim_activate (uptr, dr_time); } /* sched next word */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Increment current disk address */
|
||||
|
||||
int32 dr_incda (int32 trk, int32 sec, int32 ptr)
|
||||
{
|
||||
ptr = ptr + 1; /* inc pointer */
|
||||
if (ptr >= DR_NUMWD) { /* end sector? */
|
||||
ptr = 0; /* new sector */
|
||||
sec = sec + 1; /* adv sector */
|
||||
if (sec >= DR_NUMSC) { /* end track? */
|
||||
sec = 0; /* new track */
|
||||
trk = trk + 1; /* adv track */
|
||||
if (trk >= MAX_TRK) trk = 0; } /* wraps at max */
|
||||
drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat drc_reset (DEVICE *dptr)
|
||||
{
|
||||
hp_enbdis_pair (&drc_dev, &drd_dev); /* make pair cons */
|
||||
drc_sta = drc_cw = drd_ptr = 0;
|
||||
drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */
|
||||
drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */
|
||||
drc_dib.fbf = drd_dib.fbf = 0; /* clear fbf */
|
||||
drc_dib.flg = drd_dib.flg = 0; /* clear flg */
|
||||
sim_cancel (&drc_unit);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat drc_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
int32 sz = sz_tab[DR_GETSZ (uptr->flags)];
|
||||
|
||||
if (sz == 0) return SCPE_IERR;
|
||||
uptr->capac = sz;
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
/* Set size routine */
|
||||
|
||||
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 sz;
|
||||
|
||||
if (val < 0) return SCPE_IERR;
|
||||
if ((sz = sz_tab[DR_GETSZ (val)]) == 0) return SCPE_IERR;
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
uptr->capac = sz;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */
|
||||
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
#define BOOT_BASE 056
|
||||
#define BOOT_START 060
|
||||
|
||||
static const int32 dboot[IBL_LNT - BOOT_BASE] = {
|
||||
0020000+CHANGE_DEV, /*DMA 20000+DC */
|
||||
0000000, /* 0 */
|
||||
0107700, /* CLC 0,C */
|
||||
0063756, /* LDA DMA ; DMA ctrl */
|
||||
0102606, /* OTA 6 */
|
||||
0002700, /* CLA,CCE */
|
||||
0102601+CHANGE_DEV, /* OTA CC ; trk = sec = 0 */
|
||||
0001500, /* ERA ; A = 100000 */
|
||||
0102602, /* OTA 2 ; DMA in, addr */
|
||||
0063777, /* LDA M64 */
|
||||
0102702, /* STC 2 */
|
||||
0102602, /* OTA 2 ; DMA wc = -64 */
|
||||
0103706, /* STC 6,C ; start DMA */
|
||||
0067776, /* LDB JSF ; get JMP . */
|
||||
0074077, /* STB 77 ; in base page */
|
||||
0102700+CHANGE_DEV, /* STC DC ; start disc */
|
||||
0024077, /*JSF JMP 77 ; go wait */
|
||||
0177700 }; /*M64 -100 */
|
||||
|
||||
t_stat drc_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, dev, ad;
|
||||
|
||||
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
|
||||
dev = drd_dib.devno; /* get data chan dev */
|
||||
ad = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
|
||||
for (i = 0; i < (IBL_LNT - BOOT_BASE); i++) { /* copy bootstrap */
|
||||
if (dboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[ad + BOOT_BASE + i] = (dboot[i] + dev) & DMASK;
|
||||
else M[ad + BOOT_BASE + i] = dboot[i]; }
|
||||
PC = ad + BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
/* hp2100_fp.c: HP 2100 floating point instructions
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
15-Jul-03 RMS Fixed signed/unsigned warning
|
||||
21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms
|
||||
|
||||
The HP2100 uses a unique binary floating point format:
|
||||
|
||||
15 14 0
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|S | fraction high | : A
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| fraction low | exponent |XS| : A + 1
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
15 8 7 1 0
|
||||
|
||||
where S = 0 for plus fraction, 1 for minus fraction
|
||||
fraction = s.bbbbb..., 24 binary digits
|
||||
exponent = 2**+/-n
|
||||
XS = 0 for plus exponent, 1 for minus exponent
|
||||
|
||||
Numbers can be normalized or unnormalized but are always normalized
|
||||
when loaded.
|
||||
|
||||
Unpacked floating point numbers are stored in structure ufp
|
||||
|
||||
exp = exponent, 2's complement
|
||||
h'l = fraction, 2's comp, left justified
|
||||
|
||||
This routine tries to reproduce the algorithms of the 2100/21MX
|
||||
microcode in order to achieve 'bug-for-bug' compatibility. In
|
||||
particular,
|
||||
|
||||
- The FIX code produces various results in B.
|
||||
- The fraction multiply code uses 16b x 16b multiplies to produce
|
||||
a 31b result. It always loses the low order bit of the product.
|
||||
- The fraction divide code is an approximation that may produce
|
||||
an error of 1 LSB.
|
||||
- Signs are tracked implicitly as part of the fraction. Unnormalized
|
||||
inputs may cause the packup code to produce the wrong sign.
|
||||
- "Unclean" zeros (zero fraction, non-zero exponent) are processed
|
||||
like normal operands.
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
struct ufp { /* unpacked fp */
|
||||
int32 exp; /* exp */
|
||||
uint32 fr; }; /* frac */
|
||||
|
||||
#define FP_V_SIGN 31 /* sign */
|
||||
#define FP_M_SIGN 01
|
||||
#define FP_V_FR 8 /* fraction */
|
||||
#define FP_M_FR 077777777
|
||||
#define FP_V_EXP 1 /* exponent */
|
||||
#define FP_M_EXP 0177
|
||||
#define FP_V_EXPS 0 /* exp sign */
|
||||
#define FP_M_EXPS 01
|
||||
#define FP_SIGN (FP_M_SIGN << FP_V_SIGN)
|
||||
#define FP_FR (FP_M_FR << FP_V_FR)
|
||||
#define FP_EXP (FP_M_EXP << FP_V_EXP)
|
||||
#define FP_EXPS (FP_M_EXPS << FP_V_EXPS)
|
||||
#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN)
|
||||
#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP)
|
||||
#define FP_GETEXPS(x) (((x) >> FP_V_EXPS) & FP_M_EXPS)
|
||||
|
||||
#define FP_NORM (1 << (FP_V_SIGN - 1)) /* normalized */
|
||||
#define FP_LOW (1 << FP_V_FR)
|
||||
#define FP_RNDP (1 << (FP_V_FR - 1)) /* round for plus */
|
||||
#define FP_RNDM (FP_RNDP - 1) /* round for minus */
|
||||
|
||||
#define FPAB ((((uint32) AR) << 16) | ((uint32) BR))
|
||||
|
||||
#define DMASK32 0xFFFFFFFF
|
||||
|
||||
/* Fraction shift; 0 < shift < 32 */
|
||||
|
||||
#define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \
|
||||
(DMASK32 << (32 - (s))): 0)) & DMASK32
|
||||
|
||||
#define FR_NEG(v) ((~(v) + 1) & DMASK32)
|
||||
|
||||
extern uint16 *M;
|
||||
uint32 UnpackFP (struct ufp *fop, uint32 opnd);
|
||||
void NegFP (struct ufp *fop);
|
||||
void NormFP (struct ufp *fop);
|
||||
uint32 StoreFP (struct ufp *fop);
|
||||
|
||||
/* Floating to integer conversion */
|
||||
|
||||
uint32 f_fix (void)
|
||||
{
|
||||
struct ufp fop;
|
||||
uint32 res = 0;
|
||||
|
||||
UnpackFP (&fop, FPAB); /* unpack op */
|
||||
if (fop.exp < 0) { /* exp < 0? */
|
||||
AR = 0; /* result = 0 */
|
||||
return 0; } /* B unchanged */
|
||||
if (fop.exp > 15) { /* exp > 15? */
|
||||
BR = AR; /* B has high bits */
|
||||
AR = 077777; /* result = 77777 */
|
||||
return 1; } /* overflow */
|
||||
if (fop.exp < 15) { /* if not aligned */
|
||||
res = FR_ARS (fop.fr, 15 - fop.exp); /* shift right */
|
||||
AR = (res >> 16) & DMASK; } /* AR gets result */
|
||||
BR = AR;
|
||||
if ((AR & SIGN) && ((fop.fr | res) & DMASK)) /* any low bits lost? */
|
||||
AR = (AR + 1) & DMASK; /* round up */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Integer to floating conversion */
|
||||
|
||||
uint32 f_flt (void)
|
||||
{
|
||||
struct ufp res = { 15, 0 }; /* +, 2**15 */
|
||||
|
||||
res.fr = ((uint32) AR) << 16; /* left justify */
|
||||
StoreFP (&res); /* store result */
|
||||
return 0; /* clr overflow */
|
||||
}
|
||||
|
||||
/* Floating point add/subtract */
|
||||
|
||||
uint32 f_as (uint32 opnd, t_bool sub)
|
||||
{
|
||||
struct ufp fop1, fop2, t;
|
||||
int32 ediff;
|
||||
|
||||
UnpackFP (&fop1, FPAB); /* unpack A-B */
|
||||
UnpackFP (&fop2, opnd); /* get op */
|
||||
if (sub) { /* subtract? */
|
||||
fop2.fr = FR_NEG (fop2.fr); /* negate frac */
|
||||
if (fop2.fr == ((uint32) FP_SIGN)) { /* -1/2? */
|
||||
fop2.fr = fop2.fr >> 1; /* special case */
|
||||
fop2.exp = fop2.exp + 1; } }
|
||||
if (fop1.fr == 0) fop1 = fop2; /* op1 = 0? res = op2 */
|
||||
else if (fop2.fr != 0) { /* op2 = 0? no add */
|
||||
if (fop1.exp < fop2.exp) { /* |op1| < |op2|? */
|
||||
t = fop2; /* swap operands */
|
||||
fop2 = fop1;
|
||||
fop1 = t; }
|
||||
ediff = fop1.exp - fop2.exp; /* get exp diff */
|
||||
if (ediff <= 24) {
|
||||
if (ediff) fop2.fr = FR_ARS (fop2.fr, ediff); /* denorm, signed */
|
||||
if ((fop1.fr ^ fop2.fr) & FP_SIGN) /* unlike signs? */
|
||||
fop1.fr = fop1.fr + fop2.fr; /* eff subtract */
|
||||
else { /* like signs */
|
||||
fop1.fr = fop1.fr + fop2.fr; /* eff add */
|
||||
if (fop2.fr & FP_SIGN) { /* both -? */
|
||||
if ((fop1.fr & FP_SIGN) == 0) { /* overflow? */
|
||||
fop1.fr = FP_SIGN | (fop1.fr >> 1); /* renormalize */
|
||||
fop1.exp = fop1.exp + 1; } } /* incr exp */
|
||||
else if (fop1.fr & FP_SIGN) { /* both +, cry out? */
|
||||
fop1.fr = fop1.fr >> 1; /* renormalize */
|
||||
fop1.exp = fop1.exp + 1; } /* incr exp */
|
||||
} /* end else like */
|
||||
} /* end if ediff */
|
||||
} /* end if fop2 */
|
||||
return StoreFP (&fop1); /* store result */
|
||||
}
|
||||
|
||||
/* Floating point multiply - passes diagnostic */
|
||||
|
||||
uint32 f_mul (uint32 opnd)
|
||||
{
|
||||
struct ufp fop1, fop2;
|
||||
struct ufp res = { 0, 0 };
|
||||
int32 shi1, shi2, t1, t2, t3, t4, t5;
|
||||
|
||||
UnpackFP (&fop1, FPAB); /* unpack A-B */
|
||||
UnpackFP (&fop2, opnd); /* unpack op */
|
||||
if (fop1.fr && fop2.fr) { /* if both != 0 */
|
||||
res.exp = fop1.exp + fop2.exp + 1; /* exp = sum */
|
||||
shi1 = SEXT (fop1.fr >> 16); /* mpy hi */
|
||||
shi2 = SEXT (fop2.fr >> 16); /* mpc hi */
|
||||
t1 = shi2 * ((int32) ((fop1.fr >> 1) & 077600));/* mpc hi * (mpy lo/2) */
|
||||
t2 = shi1 * ((int32) ((fop2.fr >> 1) & 077600));/* mpc lo * (mpy hi/2) */
|
||||
t3 = t1 + t2; /* cross product */
|
||||
t4 = (shi1 * shi2) & ~1; /* mpy hi * mpc hi */
|
||||
t5 = (SEXT (t3 >> 16)) << 1; /* add in cross */
|
||||
res.fr = (t4 + t5) & DMASK32; } /* bit<0> is lost */
|
||||
return StoreFP (&res); /* store */
|
||||
}
|
||||
|
||||
/* Floating point divide - reverse engineered from diagnostic */
|
||||
|
||||
uint32 divx (uint32 ba, uint32 dvr, uint32 *rem)
|
||||
{
|
||||
int32 sdvd = 0, sdvr = 0;
|
||||
uint32 q, r;
|
||||
|
||||
if (ba & FP_SIGN) sdvd = 1; /* 32b/16b signed dvd */
|
||||
if (dvr & SIGN) sdvr = 1; /* use old-fashioned */
|
||||
if (sdvd) ba = (~ba + 1) & DMASK32; /* unsigned divides, */
|
||||
if (sdvr) dvr = (~dvr + 1) & DMASK; /* as results may ovflo */
|
||||
q = ba / dvr;
|
||||
r = ba % dvr;
|
||||
if (sdvd ^ sdvr) q = (~q + 1) & DMASK;
|
||||
if (sdvd) r = (~r + 1) & DMASK;
|
||||
if (rem) *rem = r;
|
||||
return q;
|
||||
}
|
||||
|
||||
uint32 f_div (uint32 opnd)
|
||||
{
|
||||
struct ufp fop1, fop2;
|
||||
struct ufp quo = { 0, 0 };
|
||||
uint32 ba, q0, q1, q2, dvrh;
|
||||
|
||||
UnpackFP (&fop1, FPAB); /* unpack A-B */
|
||||
UnpackFP (&fop2, opnd); /* unpack op */
|
||||
dvrh = (fop2.fr >> 16) & DMASK; /* high divisor */
|
||||
if (dvrh == 0) { /* div by zero? */
|
||||
AR = 0077777; /* return most pos */
|
||||
BR = 0177776;
|
||||
return 1; }
|
||||
if (fop1.fr) { /* dvd != 0? */
|
||||
quo.exp = fop1.exp - fop2.exp + 1; /* exp = diff */
|
||||
ba = FR_ARS (fop1.fr, 2); /* prevent ovflo */
|
||||
q0 = divx (ba, dvrh, &ba); /* Q0 = dvd / dvrh */
|
||||
ba = (ba & ~1) << 16; /* remainder */
|
||||
ba = FR_ARS (ba, 1); /* prevent ovflo */
|
||||
q1 = divx (ba, dvrh, NULL); /* Q1 = rem / dvrh */
|
||||
ba = (fop2.fr & 0xFF00) << 13; /* dvrl / 8 */
|
||||
q2 = divx (ba, dvrh, NULL); /* dvrl / dvrh */
|
||||
ba = -(SEXT (q2)) * (SEXT (q0)); /* -Q0 * Q2 */
|
||||
ba = (ba >> 16) & 0xFFFF; /* save ms half */
|
||||
if (q1 & SIGN) quo.fr = quo.fr - 0x00010000; /* Q1 < 0? -1 */
|
||||
if (ba & SIGN) quo.fr = quo.fr - 0x00010000; /* -Q0*Q2 < 0? */
|
||||
quo.fr = quo.fr + ((ba << 2) & 0xFFFF) + q1; /* rest prod, add Q1 */
|
||||
quo.fr = quo.fr << 1; /* shift result */
|
||||
quo.fr = quo.fr + (q0 << 16); /* add Q0 */
|
||||
} /* end if fop1.h */
|
||||
return StoreFP (&quo); /* store result */
|
||||
}
|
||||
|
||||
/* Utility routines */
|
||||
|
||||
/* Unpack operand */
|
||||
|
||||
uint32 UnpackFP (struct ufp *fop, uint32 opnd)
|
||||
{
|
||||
fop->fr = opnd & FP_FR; /* get frac */
|
||||
fop->exp = FP_GETEXP (opnd); /* get exp */
|
||||
if (FP_GETEXPS (opnd)) fop->exp = fop->exp | ~FP_M_EXP; /* < 0? sext */
|
||||
return FP_GETSIGN (opnd); /* return sign */
|
||||
}
|
||||
|
||||
/* Normalize unpacked floating point number */
|
||||
|
||||
void NormFP (struct ufp *fop)
|
||||
{
|
||||
if (fop->fr) { /* any fraction? */
|
||||
uint32 test = (fop->fr >> 1) & FP_NORM;
|
||||
while ((fop->fr & FP_NORM) == test) { /* until norm */
|
||||
fop->exp = fop->exp - 1;
|
||||
fop->fr = (fop->fr << 1); } }
|
||||
else fop->exp = 0; /* clean 0 */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Round fp number, store, generate overflow */
|
||||
|
||||
uint32 StoreFP (struct ufp *fop)
|
||||
{
|
||||
uint32 sign, svfr, hi, ov = 0;
|
||||
|
||||
NormFP (fop); /* normalize */
|
||||
svfr = fop->fr; /* save fraction */
|
||||
sign = FP_GETSIGN (fop->fr); /* save sign */
|
||||
fop->fr = (fop->fr + (sign? FP_RNDM: FP_RNDP)) & FP_FR; /* round */
|
||||
if ((fop->fr ^ svfr) & FP_SIGN) { /* sign change? */
|
||||
fop->fr = (fop->fr >> 1) | (sign? FP_SIGN: 0); /* renormalize */
|
||||
fop->exp = fop->exp + 1; }
|
||||
if (fop->fr == 0) hi = 0; /* result 0? */
|
||||
else if (fop->exp < -(FP_M_EXP + 1)) { /* underflow? */
|
||||
hi = 0; /* store clean 0 */
|
||||
ov = 1; }
|
||||
else if (fop->exp > FP_M_EXP) { /* overflow? */
|
||||
hi = 0x7FFFFFFE; /* all 1's */
|
||||
ov = 1; }
|
||||
else hi = (fop->fr & FP_FR) | /* merge frac */
|
||||
((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */
|
||||
((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */
|
||||
AR = (hi >> 16) & DMASK;
|
||||
BR = hi & DMASK;
|
||||
return ov;
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
/* hp2100_ipl.c: HP 2000 interprocessor link simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
ipli, iplo 12556B interprocessor link pair
|
||||
|
||||
09-May-03 RMS Added network device flag
|
||||
31-Jan-03 RMS Links are full duplex (found by Mike Gemeny)
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include "sim_tmxr.h"
|
||||
|
||||
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
|
||||
#define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */
|
||||
#define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */
|
||||
#define UNIT_V_HOLD (UNIT_V_UF + 3) /* character holding */
|
||||
#define UNIT_DIAG (1 << UNIT_V_DIAG)
|
||||
#define UNIT_ACTV (1 << UNIT_V_ACTV)
|
||||
#define UNIT_ESTB (1 << UNIT_V_ESTB)
|
||||
#define UNIT_HOLD (1 << UNIT_V_HOLD)
|
||||
#define IBUF buf /* input buffer */
|
||||
#define OBUF wait /* output buffer */
|
||||
#define DSOCKET u3 /* data socket */
|
||||
#define LSOCKET u4 /* listening socket */
|
||||
|
||||
extern uint32 PC;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
extern FILE *sim_log;
|
||||
int32 ipl_ptime = 400; /* polling interval */
|
||||
int32 ipl_stopioe = 0; /* stop on error */
|
||||
int32 ipl_hold[2] = { 0 }; /* holding character */
|
||||
|
||||
DEVICE ipli_dev, iplo_dev;
|
||||
int32 ipliio (int32 inst, int32 IR, int32 dat);
|
||||
int32 iploio (int32 inst, int32 IR, int32 dat);
|
||||
int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat);
|
||||
t_stat ipl_svc (UNIT *uptr);
|
||||
t_stat ipl_reset (DEVICE *dptr);
|
||||
t_stat ipl_attach (UNIT *uptr, char *cptr);
|
||||
t_stat ipl_detach (UNIT *uptr);
|
||||
t_stat ipl_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_bool ipl_check_conn (UNIT *uptr);
|
||||
|
||||
/* IPLI data structures
|
||||
|
||||
ipli_dev IPLI device descriptor
|
||||
ipli_unit IPLI unit descriptor
|
||||
ipli_reg IPLI register list
|
||||
*/
|
||||
|
||||
DIB ipl_dib[] = {
|
||||
{ IPLI, 0, 0, 0, 0, &ipliio },
|
||||
{ IPLO, 0, 0, 0, 0, &iploio } };
|
||||
|
||||
#define ipli_dib ipl_dib[0]
|
||||
#define iplo_dib ipl_dib[1]
|
||||
|
||||
UNIT ipl_unit[] = {
|
||||
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) },
|
||||
{ UDATA (&ipl_svc, UNIT_ATTABLE, 0) } };
|
||||
|
||||
#define ipli_unit ipl_unit[0]
|
||||
#define iplo_unit ipl_unit[1]
|
||||
|
||||
REG ipli_reg[] = {
|
||||
{ ORDATA (IBUF, ipli_unit.IBUF, 16) },
|
||||
{ ORDATA (OBUF, ipli_unit.OBUF, 16) },
|
||||
{ FLDATA (CMD, ipli_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, ipli_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, ipli_dib.flg, 0) },
|
||||
{ FLDATA (FBF, ipli_dib.fbf, 0) },
|
||||
{ ORDATA (HOLD, ipl_hold[0], 8) },
|
||||
{ DRDATA (TIME, ipl_ptime, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ipl_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, ipli_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ipl_mod[] = {
|
||||
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag },
|
||||
{ UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT",
|
||||
&ipl_dscln, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &ipli_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE ipli_dev = {
|
||||
"IPLI", &ipli_unit, ipli_reg, ipl_mod,
|
||||
1, 10, 31, 1, 16, 16,
|
||||
&tmxr_ex, &tmxr_dep, &ipl_reset,
|
||||
&ipl_boot, &ipl_attach, &ipl_detach,
|
||||
&ipli_dib, DEV_NET | DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IPLO data structures
|
||||
|
||||
iplo_dev IPLO device descriptor
|
||||
iplo_unit IPLO unit descriptor
|
||||
iplo_reg IPLO register list
|
||||
*/
|
||||
|
||||
REG iplo_reg[] = {
|
||||
{ ORDATA (IBUF, iplo_unit.IBUF, 16) },
|
||||
{ ORDATA (OBUF, iplo_unit.OBUF, 16) },
|
||||
{ FLDATA (CMD, iplo_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, iplo_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, iplo_dib.flg, 0) },
|
||||
{ FLDATA (FBF, iplo_dib.fbf, 0) },
|
||||
{ ORDATA (HOLD, ipl_hold[1], 8) },
|
||||
{ DRDATA (TIME, ipl_ptime, 24), PV_LEFT },
|
||||
{ ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE iplo_dev = {
|
||||
"IPLO", &iplo_unit, iplo_reg, ipl_mod,
|
||||
1, 10, 31, 1, 16, 16,
|
||||
&tmxr_ex, &tmxr_dep, &ipl_reset,
|
||||
&ipl_boot, &ipl_attach, &ipl_detach,
|
||||
&iplo_dib, DEV_NET | DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* Interprocessor link I/O routines */
|
||||
|
||||
int32 ipliio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
return iplio (&ipli_unit, inst, IR, dat);
|
||||
}
|
||||
|
||||
int32 iploio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
return iplio (&iplo_unit, inst, IR, dat);
|
||||
}
|
||||
|
||||
int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
uint32 u, dev, odev;
|
||||
int32 sta;
|
||||
int8 msg[2];
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
uptr->OBUF = dat;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = uptr->IBUF; /* return val */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | uptr->IBUF; /* get return data */
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCMD (dev); /* clear ctl, cmd */
|
||||
clrCTL (dev); }
|
||||
else { /* STC */
|
||||
setCMD (dev); /* set ctl, cmd */
|
||||
setCTL (dev);
|
||||
if (uptr->flags & UNIT_ATT) { /* attached? */
|
||||
if ((uptr->flags & UNIT_ESTB) == 0) { /* established? */
|
||||
if (!ipl_check_conn (uptr)) /* not established? */
|
||||
return STOP_NOCONN; /* lose */
|
||||
uptr->flags = uptr->flags | UNIT_ESTB; }
|
||||
msg[0] = (uptr->OBUF >> 8) & 0377;
|
||||
msg[1] = uptr->OBUF & 0377;
|
||||
sta = sim_write_sock (uptr->DSOCKET, msg, 2);
|
||||
if (sta == SOCKET_ERROR) {
|
||||
printf ("IPL: socket write error\n");
|
||||
return SCPE_IOERR; }
|
||||
sim_os_sleep (0); }
|
||||
else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */
|
||||
u = (uptr - ipl_unit) ^ 1; /* find other device */
|
||||
ipl_unit[u].IBUF = uptr->OBUF; /* output to other */
|
||||
odev = ipl_dib[u].devno; /* other device no */
|
||||
setFLG (odev); } /* set other flag */
|
||||
else return SCPE_UNATT; } /* lose */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service - poll for input */
|
||||
|
||||
t_stat ipl_svc (UNIT *uptr)
|
||||
{
|
||||
int32 u, nb, dev;
|
||||
int8 msg[2];
|
||||
|
||||
u = uptr - ipl_unit; /* get link number */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */
|
||||
sim_activate (uptr, ipl_ptime); /* reactivate */
|
||||
if ((uptr->flags & UNIT_ESTB) == 0) { /* not established? */
|
||||
if (!ipl_check_conn (uptr)) return SCPE_OK; /* check for conn */
|
||||
uptr->flags = uptr->flags | UNIT_ESTB; }
|
||||
nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2));
|
||||
if (nb < 0) { /* connection closed? */
|
||||
printf ("IPL: socket read error\n");
|
||||
return SCPE_IOERR; }
|
||||
if (nb == 0) return SCPE_OK; /* no data? */
|
||||
if (uptr->flags & UNIT_HOLD) { /* holdover byte? */
|
||||
uptr->IBUF = (ipl_hold[u] << 8) | (((int32) msg[0]) & 0377);
|
||||
uptr->flags = uptr->flags & ~UNIT_HOLD; }
|
||||
else if (nb == 1) {
|
||||
ipl_hold[u] = ((int32) msg[0]) & 0377;
|
||||
uptr->flags = uptr->flags | UNIT_HOLD; }
|
||||
else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) |
|
||||
(((int32) msg[1]) & 0377);
|
||||
dev = ipl_dib[u].devno; /* get device number */
|
||||
clrCMD (dev); /* clr cmd, set flag */
|
||||
setFLG (dev);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_bool ipl_check_conn (UNIT *uptr)
|
||||
{
|
||||
SOCKET sock;
|
||||
|
||||
if (uptr->flags & UNIT_ESTB) return TRUE; /* established? */
|
||||
if (uptr->flags & UNIT_ACTV) { /* active connect? */
|
||||
if (sim_check_conn (uptr->DSOCKET, 0) <= 0) return FALSE; }
|
||||
else { sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */
|
||||
if (sock == INVALID_SOCKET) return FALSE; /* got a live one? */
|
||||
uptr->DSOCKET = sock; } /* save data socket */
|
||||
uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ipl_reset (DEVICE *dptr)
|
||||
{
|
||||
DIB *dibp = (DIB *) dptr->ctxt;
|
||||
UNIT *uptr = dptr->units;
|
||||
|
||||
hp_enbdis_pair (&ipli_dev, &iplo_dev); /* make pair cons */
|
||||
dibp->cmd = dibp->ctl = 0; /* clear cmd, ctl */
|
||||
dibp->flg = dibp->fbf = 1; /* set flg, fbf */
|
||||
uptr->IBUF = uptr->OBUF = 0; /* clr buffers */
|
||||
if (uptr->flags & UNIT_ATT) sim_activate (uptr, ipl_ptime);
|
||||
else sim_cancel (uptr); /* deactivate unit */
|
||||
uptr->flags = uptr->flags & ~UNIT_HOLD;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine
|
||||
|
||||
attach -l - listen for connection on port
|
||||
attach -c - connect to ip address and port
|
||||
*/
|
||||
|
||||
t_stat ipl_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
extern int32 sim_switches;
|
||||
SOCKET newsock;
|
||||
uint32 i, t, ipa, ipp, oldf;
|
||||
char *tptr;
|
||||
t_stat r;
|
||||
|
||||
r = get_ipaddr (cptr, &ipa, &ipp);
|
||||
if ((r != SCPE_OK) || (ipp == 0)) return SCPE_ARG;
|
||||
oldf = uptr->flags;
|
||||
if (oldf & UNIT_ATT) ipl_detach (uptr);
|
||||
if ((sim_switches & SWMASK ('C')) ||
|
||||
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
|
||||
if (ipa == 0) ipa = 0x7F000001;
|
||||
newsock = sim_connect_sock (ipa, ipp);
|
||||
if (newsock == INVALID_SOCKET) return SCPE_IOERR;
|
||||
printf ("Connecting to IP address %d.%d.%d.%d, port %d\n",
|
||||
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
|
||||
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
|
||||
if (sim_log) fprintf (sim_log,
|
||||
"Connecting to IP address %d.%d.%d.%d, port %d\n",
|
||||
(ipa >> 24) & 0xff, (ipa >> 16) & 0xff,
|
||||
(ipa >> 8) & 0xff, ipa & 0xff, ipp);
|
||||
uptr->flags = uptr->flags | UNIT_ACTV;
|
||||
uptr->LSOCKET = 0;
|
||||
uptr->DSOCKET = newsock; }
|
||||
else { if (ipa != 0) return SCPE_ARG;
|
||||
newsock = sim_master_sock (ipp);
|
||||
if (newsock == INVALID_SOCKET) return SCPE_IOERR;
|
||||
printf ("Listening on port %d\n", ipp);
|
||||
if (sim_log) fprintf (sim_log, "Listening on port %d\n", ipp);
|
||||
uptr->flags = uptr->flags & ~UNIT_ACTV;
|
||||
uptr->LSOCKET = newsock;
|
||||
uptr->DSOCKET = 0; }
|
||||
uptr->IBUF = uptr->OBUF = 0;
|
||||
uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD);
|
||||
tptr = malloc (strlen (cptr) + 1); /* get string buf */
|
||||
if (tptr == NULL) { /* no memory? */
|
||||
ipl_detach (uptr); /* close sockets */
|
||||
return SCPE_MEM; }
|
||||
strcpy (tptr, cptr); /* copy ipaddr:port */
|
||||
uptr->filename = tptr; /* save */
|
||||
sim_activate (uptr, ipl_ptime); /* activate poll */
|
||||
if (sim_switches & SWMASK ('W')) { /* wait? */
|
||||
for (i = 0; i < 30; i++) { /* check for 30 sec */
|
||||
if (t = ipl_check_conn (uptr)) break; /* established? */
|
||||
if ((i % 10) == 0) /* status every 10 sec */
|
||||
printf ("Waiting for connnection\n");
|
||||
sim_os_sleep (1); } /* sleep 1 sec */
|
||||
if (t) printf ("Connection established\n"); }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat ipl_detach (UNIT *uptr)
|
||||
{
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
if (uptr->flags & UNIT_ACTV) sim_close_sock (uptr->DSOCKET, 1);
|
||||
else { if (uptr->flags & UNIT_ESTB) /* if established, */
|
||||
sim_close_sock (uptr->DSOCKET, 0); /* close data socket */
|
||||
sim_close_sock (uptr->LSOCKET, 1); } /* closen listen socket */
|
||||
free (uptr->filename); /* free string */
|
||||
uptr->filename = NULL;
|
||||
uptr->LSOCKET = 0;
|
||||
uptr->DSOCKET = 0;
|
||||
uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_ACTV | UNIT_ESTB);
|
||||
sim_cancel (uptr); /* don't poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Disconnect routine */
|
||||
|
||||
t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (cptr) return SCPE_ARG;
|
||||
if (((uptr->flags & UNIT_ATT) == 0) || (uptr->flags & UNIT_ACTV) ||
|
||||
((uptr->flags & UNIT_ESTB) == 0)) return SCPE_NOFNC;
|
||||
sim_close_sock (uptr->DSOCKET, 0);
|
||||
uptr->DSOCKET = 0;
|
||||
uptr->flags = uptr->flags & ~UNIT_ESTB;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Diagnostic/normal mode routine */
|
||||
|
||||
t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (val) {
|
||||
ipli_unit.flags = ipli_unit.flags | UNIT_DIAG;
|
||||
iplo_unit.flags = iplo_unit.flags | UNIT_DIAG; }
|
||||
else { ipli_unit.flags = ipli_unit.flags & ~UNIT_DIAG;
|
||||
iplo_unit.flags = iplo_unit.flags & ~UNIT_DIAG; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Interprocessor link bootstrap routine (HP Access Manual) */
|
||||
|
||||
#define LDR_BASE 073
|
||||
#define IPL_PNTR 074
|
||||
#define PTR_PNTR 075
|
||||
#define IPL_DEVA 076
|
||||
#define PTR_DEVA 077
|
||||
|
||||
static const int32 pboot[IBL_LNT] = {
|
||||
0163774, /*BBL LDA ICK,I ; IPL sel code */
|
||||
0027751, /* JMP CFG ; go configure */
|
||||
0107700, /*ST CLC 0,C ; intr off */
|
||||
0002702, /* CLA,CCE,SZA ; skip in */
|
||||
0063772, /*CN LDA M26 ; feed frame */
|
||||
0002307, /*EOC CCE,INA,SZA,RSS ; end of file? */
|
||||
0027760, /* JMP EOT ; yes */
|
||||
0017736, /* JSB READ ; get #char */
|
||||
0007307, /* CMB,CCE,INB,SZB,RSS ; 2's comp; null? */
|
||||
0027705, /* JMP EOC ; read next */
|
||||
0077770, /* STB WC ; word in rec */
|
||||
0017736, /* JSB READ ; get feed frame */
|
||||
0017736, /* JSB READ ; get address */
|
||||
0074000, /* STB 0 ; init csum */
|
||||
0077771, /* STB AD ; save addr */
|
||||
0067771, /*CK LDB AD ; check addr */
|
||||
0047773, /* ADB MAXAD ; below loader */
|
||||
0002040, /* SEZ ; E =0 => OK */
|
||||
0102055, /* HLT 55 */
|
||||
0017736, /* JSB READ ; get word */
|
||||
0040001, /* ADA 1 ; cont checksum */
|
||||
0177771, /* STB AD,I ; store word */
|
||||
0037771, /* ISZ AD */
|
||||
0000040, /* CLE ; force wd read */
|
||||
0037770, /* ISZ WC ; block done? */
|
||||
0027717, /* JMP CK ; no */
|
||||
0017736, /* JSB READ ; get checksum */
|
||||
0054000, /* CPB 0 ; ok? */
|
||||
0027704, /* JMP CN ; next block */
|
||||
0102011, /* HLT 11 ; bad csum */
|
||||
0000000, /*RD 0 */
|
||||
0006600, /* CLB,CME ; E reg byte ptr */
|
||||
0103700, /*IO1 STC RDR,C ; start reader */
|
||||
0102300, /*IO2 SFS RDR ; wait */
|
||||
0027741, /* JMP *-1 */
|
||||
0106400, /*IO3 MIB RDR ; get byte */
|
||||
0002041, /* SEZ,RSS ; E set? */
|
||||
0127736, /* JMP RD,I ; no, done */
|
||||
0005767, /* BLF,CLE,BLF ; shift byte */
|
||||
0027740, /* JMP IO1 ; again */
|
||||
0163775, /* LDA PTR,I ; get ptr code */
|
||||
0043765, /*CFG ADA SFS ; config IO */
|
||||
0073741, /* STA IO2 */
|
||||
0043766, /* ADA STC */
|
||||
0073740, /* STA IO1 */
|
||||
0043767, /* ADA MIB */
|
||||
0073743, /* STA IO3 */
|
||||
0027702, /* JMP ST */
|
||||
0063777, /*EOT LDA PSC ; put select codes */
|
||||
0067776, /* LDB ISC ; where xloader wants */
|
||||
0102077, /* HLT 77 */
|
||||
0027702, /* JMP ST */
|
||||
0000000, /* NOP */
|
||||
0102300, /*SFS SFS 0 */
|
||||
0001400, /*STC 1400 */
|
||||
0002500, /*MIB 2500 */
|
||||
0000000, /*WC 0 */
|
||||
0000000, /*AD 0 */
|
||||
0177746, /*M26 -26 */
|
||||
0000000, /*MAX -BBL */
|
||||
0007776, /*ICK ISC */
|
||||
0007777, /*PTR IPT */
|
||||
0000000, /*ISC 0 */
|
||||
0000000 /*IPT 0 */
|
||||
};
|
||||
|
||||
t_stat ipl_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, devi, devp;
|
||||
extern DIB ptr_dib;
|
||||
extern UNIT cpu_unit;
|
||||
extern uint32 SR;
|
||||
extern uint16 *M;
|
||||
|
||||
devi = ipli_dib.devno; /* get device no */
|
||||
devp = ptr_dib.devno;
|
||||
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
|
||||
SR = (devi << IBL_V_DEV) | devp; /* set SR */
|
||||
for (i = 0; i < IBL_LNT; i++) M[PC + i] = pboot[i]; /* copy bootstrap */
|
||||
M[PC + LDR_BASE] = (~PC + 1) & DMASK; /* fix ups */
|
||||
M[PC + IPL_PNTR] = M[PC + IPL_PNTR] | PC;
|
||||
M[PC + PTR_PNTR] = M[PC + PTR_PNTR] | PC;
|
||||
M[PC + IPL_DEVA] = devi;
|
||||
M[PC + PTR_DEVA] = devp;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/* hp2100_lps.c: HP 2100 12653A line printer simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
lps 12653A 2767 line printer
|
||||
(based on 12556B microcircuit interface)
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
24-Oct-02 RMS Added microcircuit test features
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
21-Nov-00 RMS Fixed flag, fbf power up state
|
||||
Added command flop
|
||||
15-Oct-00 RMS Added variable device number support
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
#define LPS_BUSY 0000001 /* busy */
|
||||
#define LPS_NRDY 0100000 /* not ready */
|
||||
#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */
|
||||
#define UNIT_DIAG (1 << UNIT_V_DIAG)
|
||||
|
||||
extern uint32 PC;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
int32 lps_ctime = 1000; /* char time */
|
||||
int32 lps_stopioe = 0; /* stop on error */
|
||||
int32 lps_sta = 0;
|
||||
|
||||
DEVICE lps_dev;
|
||||
int32 lpsio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat lps_svc (UNIT *uptr);
|
||||
t_stat lps_reset (DEVICE *dptr);
|
||||
|
||||
/* LPS data structures
|
||||
|
||||
lps_dev LPS device descriptor
|
||||
lps_unit LPS unit descriptor
|
||||
lps_reg LPS register list
|
||||
*/
|
||||
|
||||
DIB lps_dib = { LPS, 0, 0, 0, 0, &lpsio };
|
||||
|
||||
UNIT lps_unit = {
|
||||
UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG lps_reg[] = {
|
||||
{ ORDATA (BUF, lps_unit.buf, 16) },
|
||||
{ ORDATA (STA, lps_sta, 16) },
|
||||
{ FLDATA (CMD, lps_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, lps_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, lps_dib.flg, 0) },
|
||||
{ FLDATA (FBF, lps_dib.fbf, 0) },
|
||||
{ DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (CTIME, lps_ctime, 31), PV_LEFT },
|
||||
{ DRDATA (PTIME, lps_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, lps_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB lps_mod[] = {
|
||||
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
|
||||
{ UNIT_DIAG, 0, "printer mode", "PRINTER", NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &lps_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE lps_dev = {
|
||||
"LPS", &lps_unit, lps_reg, lps_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &lps_reset,
|
||||
NULL, NULL, NULL,
|
||||
&lps_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* Line printer IOT routine */
|
||||
|
||||
int32 lpsio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
lps_unit.buf = dat;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0; /* default sta = 0 */
|
||||
case ioMIX: /* merge */
|
||||
if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */
|
||||
lps_sta = 0; /* create status */
|
||||
if ((lps_unit.flags & UNIT_ATT) == 0)
|
||||
lps_sta = lps_sta | LPS_BUSY | LPS_NRDY;
|
||||
else if (sim_is_active (&lps_unit))
|
||||
lps_sta = lps_sta | LPS_BUSY; }
|
||||
dat = dat | lps_sta; /* diag, rtn status */
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCMD (dev); /* clear ctl, cmd */
|
||||
clrCTL (dev); }
|
||||
else { /* STC */
|
||||
setCMD (dev); /* set ctl, cmd */
|
||||
setCTL (dev);
|
||||
if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */
|
||||
sim_activate (&lps_unit, 1); /* loop back */
|
||||
else sim_activate (&lps_unit, /* real lpt, sched */
|
||||
(lps_unit.buf < 040)? lps_unit.wait: lps_ctime); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
t_stat lps_svc (UNIT *uptr)
|
||||
{
|
||||
int32 dev;
|
||||
int32 c = lps_unit.buf & 0177;
|
||||
|
||||
dev = lps_dib.devno; /* get dev no */
|
||||
clrCMD (dev); /* clear cmd */
|
||||
setFLG (dev); /* set flag, fbf */
|
||||
if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */
|
||||
lps_sta = lps_unit.buf; /* loop back */
|
||||
return SCPE_OK; } /* done */
|
||||
if ((lps_unit.flags & UNIT_ATT) == 0) /* real lpt, att? */
|
||||
return IORETURN (lps_stopioe, SCPE_UNATT);
|
||||
if (fputc (c, lps_unit.fileref) == EOF) {
|
||||
perror ("LPS I/O error");
|
||||
clearerr (lps_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
lps_unit.pos = lps_unit.pos + 1; /* update pos */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine - called from SCP, flags in DIB */
|
||||
|
||||
t_stat lps_reset (DEVICE *dptr)
|
||||
{
|
||||
lps_dib.cmd = lps_dib.ctl = 0; /* clear cmd, ctl */
|
||||
lps_dib.flg = lps_dib.fbf = 1; /* set flg, fbf */
|
||||
lps_sta = lps_unit.buf = 0;
|
||||
sim_cancel (&lps_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
/* hp2100_lpt.c: HP 2100 12845A line printer simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
lpt 12845A line printer
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
24-Oct-02 RMS Cloned from 12653A
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
#define LPT_PAGELNT 60 /* page length */
|
||||
|
||||
#define LPT_NBSY 0000001 /* not busy */
|
||||
#define LPT_PAPO 0040000 /* paper out */
|
||||
#define LPT_RDY 0100000 /* ready */
|
||||
|
||||
#define LPT_CTL 0100000 /* control output */
|
||||
#define LPT_CHAN 0000100 /* skip to chan */
|
||||
#define LPT_SKIPM 0000077 /* line count mask */
|
||||
#define LPT_CHANM 0000007 /* channel mask */
|
||||
|
||||
extern uint32 PC;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
int32 lpt_ctime = 1000; /* char time */
|
||||
int32 lpt_stopioe = 0; /* stop on error */
|
||||
int32 lpt_lcnt = 0; /* line count */
|
||||
static int32 lpt_cct[8] = {
|
||||
1, 1, 1, 2, 3, LPT_PAGELNT/2, LPT_PAGELNT/4, LPT_PAGELNT/6 };
|
||||
|
||||
DEVICE lpt_dev;
|
||||
int32 lptio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat lpt_svc (UNIT *uptr);
|
||||
t_stat lpt_reset (DEVICE *dptr);
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr);
|
||||
|
||||
/* LPT data structures
|
||||
|
||||
lpt_dev LPT device descriptor
|
||||
lpt_unit LPT unit descriptor
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
DIB lpt_dib = { LPT, 0, 0, 0, 0, &lptio };
|
||||
|
||||
UNIT lpt_unit = {
|
||||
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG lpt_reg[] = {
|
||||
{ ORDATA (BUF, lpt_unit.buf, 7) },
|
||||
{ FLDATA (CMD, lpt_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, lpt_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, lpt_dib.flg, 0) },
|
||||
{ FLDATA (FBF, lpt_dib.fbf, 0) },
|
||||
{ DRDATA (LCNT, lpt_lcnt, 7) },
|
||||
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (CTIME, lpt_ctime, 31), PV_LEFT },
|
||||
{ DRDATA (PTIME, lpt_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB lpt_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &lpt_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE lpt_dev = {
|
||||
"LPT", &lpt_unit, lpt_reg, lpt_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &lpt_reset,
|
||||
NULL, &lpt_attach, NULL,
|
||||
&lpt_dib, DEV_DISABLE };
|
||||
|
||||
/* Line printer IOT routine */
|
||||
|
||||
int32 lptio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
lpt_unit.buf = dat & (LPT_CTL | 0177);
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0; /* default sta = 0 */
|
||||
case ioMIX: /* merge */
|
||||
if (lpt_unit.flags & UNIT_ATT) {
|
||||
dat = dat | LPT_RDY;
|
||||
if (!sim_is_active (&lpt_unit))
|
||||
dat = dat | LPT_NBSY; }
|
||||
else dat = dat | LPT_PAPO;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCMD (dev); /* clear ctl, cmd */
|
||||
clrCTL (dev); }
|
||||
else { /* STC */
|
||||
setCMD (dev); /* set ctl, cmd */
|
||||
setCTL (dev);
|
||||
sim_activate (&lpt_unit, /* schedule op */
|
||||
(lpt_unit.buf & LPT_CTL)? lpt_unit.wait: lpt_ctime); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, skip, chan, dev;
|
||||
|
||||
dev = lpt_dib.devno; /* get dev no */
|
||||
clrCMD (dev); /* clear cmd */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (lpt_stopioe, SCPE_UNATT);
|
||||
setFLG (dev); /* set flag, fbf */
|
||||
if (uptr->buf & LPT_CTL) { /* control word? */
|
||||
if (uptr->buf & LPT_CHAN) {
|
||||
chan = uptr->buf & LPT_CHANM;
|
||||
if (chan == 0) { /* top of form? */
|
||||
fputc ('\f', uptr->fileref); /* ffeed */
|
||||
lpt_lcnt = 0; /* reset line cnt */
|
||||
skip = 1; }
|
||||
else if (chan == 1) skip = LPT_PAGELNT - lpt_lcnt - 1;
|
||||
else skip = lpt_cct[chan] - (lpt_lcnt % lpt_cct[chan]);
|
||||
}
|
||||
else {
|
||||
skip = uptr->buf & LPT_SKIPM;
|
||||
if (skip == 0) fputc ('\r', uptr->fileref);
|
||||
}
|
||||
for (i = 0; i < skip; i++) fputc ('\n', uptr->fileref);
|
||||
lpt_lcnt = (lpt_lcnt + skip) % LPT_PAGELNT;
|
||||
}
|
||||
else fputc (uptr->buf & 0177, uptr->fileref); /* no, just add char */
|
||||
if (ferror (uptr->fileref)) {
|
||||
perror ("LPT I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
lpt_unit.pos = ftell (uptr->fileref); /* update pos */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine - called from SCP, flags in DIB */
|
||||
|
||||
t_stat lpt_reset (DEVICE *dptr)
|
||||
{
|
||||
lpt_dib.cmd = lpt_dib.ctl = 0; /* clear cmd, ctl */
|
||||
lpt_dib.flg = lpt_dib.fbf = 1; /* set flg, fbf */
|
||||
lpt_unit.buf = 0;
|
||||
sim_cancel (&lpt_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
lpt_lcnt = 0; /* top of form */
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
@@ -1,672 +0,0 @@
|
||||
/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
ms 13181A 7970B 800bpi nine track magnetic tape
|
||||
13183A 7970E 1600bpi nine track magnetic tape
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
28-Mar-03 RMS Added multiformat support
|
||||
28-Feb-03 RMS Revised for magtape library
|
||||
18-Oct-02 RMS Added BOOT command, added 13183A support
|
||||
30-Sep-02 RMS Revamped error handling
|
||||
29-Aug-02 RMS Added end of medium support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
22-Apr-02 RMS Added maximum record length test
|
||||
|
||||
Magnetic tapes are represented as a series of variable records
|
||||
of the form:
|
||||
|
||||
32b byte count
|
||||
byte 0
|
||||
byte 1
|
||||
:
|
||||
byte n-2
|
||||
byte n-1
|
||||
32b byte count
|
||||
|
||||
If the byte count is odd, the record is padded with an extra byte
|
||||
of junk. File marks are represented by a byte count of 0.
|
||||
|
||||
Unusually among HP peripherals, the 12559 does not have a command flop,
|
||||
and its flag and flag buffer power up as clear rather than set.
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
#define MS_NUMDR 4 /* number of drives */
|
||||
#define DB_N_SIZE 16 /* max data buf */
|
||||
#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
|
||||
#define FNC u3 /* function */
|
||||
#define UST u4 /* unit status */
|
||||
|
||||
/* Command - msc_fnc */
|
||||
|
||||
#define FNC_CLR 00110 /* clear */
|
||||
#define FNC_GAP 00015 /* write gap */
|
||||
#define FNC_GFM 00215 /* gap+file mark */
|
||||
#define FNC_RC 00023 /* read */
|
||||
#define FNC_WC 00031 /* write */
|
||||
#define FNC_FSR 00003 /* forward space */
|
||||
#define FNC_BSR 00041 /* backward space */
|
||||
#define FNC_FSF 00203 /* forward file */
|
||||
#define FNC_BSF 00241 /* backward file */
|
||||
#define FNC_REW 00101 /* rewind */
|
||||
#define FNC_RWS 00105 /* rewind and offline */
|
||||
#define FNC_WFM 00211 /* write file mark */
|
||||
#define FNC_RFF 00223 /* "read file fwd" */
|
||||
#define FNC_V_SEL 9 /* select */
|
||||
#define FNC_M_SEL 017
|
||||
#define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL)
|
||||
|
||||
#define FNF_MOT 00001 /* motion */
|
||||
#define FNF_OFL 00004
|
||||
#define FNF_WRT 00010 /* write */
|
||||
#define FNF_REV 00040 /* reverse */
|
||||
#define FNF_RWD 00100 /* rewind */
|
||||
#define FNF_CHS 00400 /* change select */
|
||||
|
||||
/* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */
|
||||
|
||||
#define STA_PE 0100000 /* 1600 bpi (d) */
|
||||
#define STA_V_SEL 13 /* unit sel (d) */
|
||||
#define STA_M_SEL 03
|
||||
#define STA_SEL (STA_M_SEL << STA_V_SEL)
|
||||
#define STA_ODD 0004000 /* odd bytes */
|
||||
#define STA_REW 0002000 /* rewinding (u) */
|
||||
#define STA_TBSY 0001000 /* transport busy (d) */
|
||||
#define STA_BUSY 0000400 /* ctrl busy */
|
||||
#define STA_EOF 0000200 /* end of file */
|
||||
#define STA_BOT 0000100 /* beg of tape (u) */
|
||||
#define STA_EOT 0000040 /* end of tape (u) */
|
||||
#define STA_TIM 0000020 /* timing error */
|
||||
#define STA_REJ 0000010 /* programming error */
|
||||
#define STA_WLK 0000004 /* write locked (d) */
|
||||
#define STA_PAR 0000002 /* parity error */
|
||||
#define STA_LOCAL 0000001 /* local (d) */
|
||||
#define STA_DYN (STA_PE|STA_SEL|STA_TBSY|STA_WLK|STA_LOCAL)
|
||||
|
||||
extern uint16 *M;
|
||||
extern uint32 PC, SR;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
extern int32 sim_switches;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 ms_ctype = 0; /* ctrl type */
|
||||
int32 msc_sta = 0; /* status */
|
||||
int32 msc_buf = 0; /* buffer */
|
||||
int32 msc_usl = 0; /* unit select */
|
||||
int32 msc_1st = 0;
|
||||
int32 msc_ctime = 1000; /* command wait */
|
||||
int32 msc_gtime = 1000; /* gap stop time */
|
||||
int32 msc_rtime = 1000; /* rewind wait */
|
||||
int32 msc_xtime = 15; /* data xfer time */
|
||||
int32 msc_stopioe = 1; /* stop on error */
|
||||
int32 msd_buf = 0; /* data buffer */
|
||||
uint8 msxb[DBSIZE] = { 0 }; /* data buffer */
|
||||
t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */
|
||||
|
||||
DEVICE msd_dev, msc_dev;
|
||||
int32 msdio (int32 inst, int32 IR, int32 dat);
|
||||
int32 mscio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat msc_svc (UNIT *uptr);
|
||||
t_stat msc_reset (DEVICE *dptr);
|
||||
t_stat msc_attach (UNIT *uptr, char *cptr);
|
||||
t_stat msc_detach (UNIT *uptr);
|
||||
t_stat msc_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat ms_map_err (UNIT *uptr, t_stat st);
|
||||
t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
/* MSD data structures
|
||||
|
||||
msd_dev MSD device descriptor
|
||||
msd_unit MSD unit list
|
||||
msd_reg MSD register list
|
||||
*/
|
||||
|
||||
DIB ms_dib[] = {
|
||||
{ MSD, 0, 0, 0, 0, &msdio },
|
||||
{ MSC, 0, 0, 0, 0, &mscio } };
|
||||
|
||||
#define msd_dib ms_dib[0]
|
||||
#define msc_dib ms_dib[1]
|
||||
|
||||
UNIT msd_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG msd_reg[] = {
|
||||
{ ORDATA (BUF, msd_buf, 16) },
|
||||
{ FLDATA (CMD, msd_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, msd_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, msd_dib.flg, 0) },
|
||||
{ FLDATA (FBF, msd_dib.fbf, 0) },
|
||||
{ BRDATA (DBUF, msxb, 8, 8, DBSIZE) },
|
||||
{ DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
|
||||
{ DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
|
||||
{ ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB msd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &msd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE msd_dev = {
|
||||
"MSD", &msd_unit, msd_reg, msd_mod,
|
||||
1, 10, DB_N_SIZE, 1, 8, 8,
|
||||
NULL, NULL, &msc_reset,
|
||||
NULL, NULL, NULL,
|
||||
&msd_dib, 0 };
|
||||
|
||||
/* MSC data structures
|
||||
|
||||
msc_dev MSC device descriptor
|
||||
msc_unit MSC unit list
|
||||
msc_reg MSC register list
|
||||
msc_mod MSC modifier list
|
||||
*/
|
||||
|
||||
UNIT msc_unit[] = {
|
||||
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
|
||||
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
|
||||
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
|
||||
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } };
|
||||
|
||||
REG msc_reg[] = {
|
||||
{ ORDATA (STA, msc_sta, 12) },
|
||||
{ ORDATA (BUF, msc_buf, 16) },
|
||||
{ ORDATA (USEL, msc_usl, 2) },
|
||||
{ FLDATA (FSVC, msc_1st, 0) },
|
||||
{ FLDATA (CMD, msc_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, msc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, msc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, msc_dib.fbf, 0) },
|
||||
{ URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) },
|
||||
{ URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) },
|
||||
{ URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) },
|
||||
{ DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, msc_stopioe, 0) },
|
||||
{ FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
|
||||
{ ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB msc_mod[] = {
|
||||
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "13181A",
|
||||
&ms_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "13183A",
|
||||
&ms_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
|
||||
NULL, &ms_showtype, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &msd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE msc_dev = {
|
||||
"MSC", msc_unit, msc_reg, msc_mod,
|
||||
MS_NUMDR, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &msc_reset,
|
||||
&msc_boot, &msc_attach, &msc_detach,
|
||||
&msc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 msdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
msd_buf = dat; /* store data */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | msd_buf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = msd_buf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCTL (devd); /* clr ctl, cmd */
|
||||
clrCMD (devd); }
|
||||
else { /* STC */
|
||||
setCTL (devd); /* set ctl, cmd */
|
||||
setCMD (devd); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 mscio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 i, devc, devd;
|
||||
t_stat st;
|
||||
UNIT *uptr = msc_dev.units + msc_usl;
|
||||
static const uint8 map_sel[16] = {
|
||||
0, 0, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
devd = devc - 1;
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
msc_buf = dat;
|
||||
msc_sta = msc_sta & ~STA_REJ; /* clear reject */
|
||||
if ((dat & 0377) == FNC_CLR) break; /* clear always ok */
|
||||
if (msc_sta & STA_BUSY) { /* busy? reject */
|
||||
msc_sta = msc_sta | STA_REJ; /* dont chg select */
|
||||
break; }
|
||||
if (dat & FNF_CHS) { /* select change */
|
||||
msc_usl = map_sel[FNC_GETSEL (dat)]; /* is immediate */
|
||||
uptr = msc_dev.units + msc_usl; }
|
||||
if (((dat & FNF_MOT) && sim_is_active (uptr)) ||
|
||||
((dat & FNF_REV) && (uptr->UST & STA_BOT)) ||
|
||||
((dat & FNF_WRT) && sim_tape_wrp (uptr)))
|
||||
msc_sta = msc_sta | STA_REJ; /* reject? */
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | ((msc_sta | uptr->UST) & ~STA_DYN);
|
||||
if (uptr->flags & UNIT_ATT) { /* online? */
|
||||
if (sim_is_active (uptr)) /* busy */
|
||||
dat = dat | STA_TBSY;
|
||||
if (sim_tape_wrp (uptr)) /* write prot? */
|
||||
dat = dat | STA_WLK; }
|
||||
else dat = dat | STA_TBSY | STA_LOCAL;
|
||||
if (ms_ctype) dat = dat | STA_PE | /* 13183A? */
|
||||
(msc_usl << STA_V_SEL);
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { clrCTL (devc); } /* CLC */
|
||||
else { /* STC */
|
||||
if ((msc_buf & 0377) == FNC_CLR) { /* clear? */
|
||||
for (i = 0; i < MS_NUMDR; i++) { /* loop thru units */
|
||||
if (sim_is_active (&msc_unit[i]) && /* write in prog? */
|
||||
(msc_unit[i].FNC == FNC_WC) && (ms_ptr > 0)) {
|
||||
if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF))
|
||||
ms_map_err (uptr, st); }
|
||||
if ((msc_unit[i].UST & STA_REW) == 0)
|
||||
sim_cancel (&msc_unit[i]); } /* stop if now rew */
|
||||
clrCTL (devc); /* init device */
|
||||
setFLG (devc);
|
||||
clrCTL (devd);
|
||||
setFLG (devd);
|
||||
msc_sta = msd_buf = msc_buf = msc_1st = 0;
|
||||
return SCPE_OK; }
|
||||
uptr->FNC = msc_buf & 0377; /* save function */
|
||||
if (uptr->FNC & FNF_RWD) /* rewind? */
|
||||
sim_activate (uptr, msc_rtime); /* fast response */
|
||||
else sim_activate (uptr, msc_ctime); /* schedule op */
|
||||
uptr->UST = 0; /* clear status */
|
||||
msc_sta = STA_BUSY; /* ctrl is busy */
|
||||
msc_1st = 1;
|
||||
setCTL (devc); } /* go */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
|
||||
If rewind done, reposition to start of tape, set status
|
||||
else, do operation, set done, interrupt
|
||||
|
||||
Can't be write locked, can only write lock detached unit
|
||||
*/
|
||||
|
||||
t_stat msc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 devc, devd;
|
||||
t_mtrlnt tbc;
|
||||
t_stat st, r = SCPE_OK;
|
||||
|
||||
devc = msc_dib.devno; /* get device nos */
|
||||
devd = msd_dib.devno;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */
|
||||
msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */
|
||||
setFLG (devc); /* set cch flg */
|
||||
return IORETURN (msc_stopioe, SCPE_UNATT); }
|
||||
|
||||
switch (uptr->FNC) { /* case on function */
|
||||
case FNC_REW: /* rewind */
|
||||
case FNC_RWS: /* rewind offline */
|
||||
if (uptr->UST & STA_REW) { /* rewind in prog? */
|
||||
sim_tape_rewind (uptr); /* done */
|
||||
uptr->UST = STA_BOT; /* set BOT status */
|
||||
if (uptr->FNC & FNF_OFL) detach_unit (uptr);
|
||||
return SCPE_OK; }
|
||||
uptr->UST = STA_REW; /* set rewinding */
|
||||
sim_activate (uptr, msc_ctime); /* sched completion */
|
||||
break; /* "done" */
|
||||
|
||||
case FNC_GFM: /* gap file mark */
|
||||
case FNC_WFM: /* write file mark */
|
||||
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
|
||||
r = ms_map_err (uptr, st); /* map error */
|
||||
msc_sta = STA_EOF; /* set EOF status */
|
||||
break;
|
||||
|
||||
case FNC_GAP: /* erase gap */
|
||||
break;
|
||||
|
||||
case FNC_FSR: /* space forward */
|
||||
if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */
|
||||
r = ms_map_err (uptr, st); /* map error */
|
||||
if (tbc & 1) msc_sta = msc_sta | STA_ODD;
|
||||
else msc_sta = msc_sta & ~STA_ODD;
|
||||
break;
|
||||
|
||||
case FNC_BSR:
|
||||
if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */
|
||||
r = ms_map_err (uptr, st); /* map error */
|
||||
if (tbc & 1) msc_sta = msc_sta | STA_ODD;
|
||||
else msc_sta = msc_sta & ~STA_ODD;
|
||||
break;
|
||||
|
||||
case FNC_FSF:
|
||||
while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
|
||||
if (st == MTSE_TMK) /* stopped by tmk? */
|
||||
msc_sta = msc_sta | STA_EOF | STA_ODD; /* normal status */
|
||||
else r = ms_map_err (uptr, st); /* map error */
|
||||
break;
|
||||
|
||||
case FNC_BSF:
|
||||
while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
|
||||
if (st == MTSE_TMK) /* stopped by tmk? */
|
||||
msc_sta = msc_sta | STA_EOF | STA_ODD; /* normal status */
|
||||
else r = ms_map_err (uptr, st); /* map error */
|
||||
break;
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
case FNC_RFF: /* diagnostic read */
|
||||
case FNC_RC: /* read */
|
||||
if (msc_1st) { /* first svc? */
|
||||
msc_1st = ms_ptr = 0; /* clr 1st flop */
|
||||
st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */
|
||||
if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */
|
||||
else if (st != MTSE_OK) { /* other error? */
|
||||
r = ms_map_err (uptr, st); /* map error */
|
||||
if (r == SCPE_OK) { /* recoverable? */
|
||||
sim_activate (uptr, msc_gtime); /* sched IRG */
|
||||
uptr->FNC = 0; /* NOP func */
|
||||
return SCPE_OK; }
|
||||
break; } /* err, done */
|
||||
}
|
||||
if (ms_ptr < ms_max) { /* more chars? */
|
||||
if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR;
|
||||
msd_buf = ((uint16) msxb[ms_ptr] << 8) | msxb[ms_ptr + 1];
|
||||
ms_ptr = ms_ptr + 2;
|
||||
setFLG (devd); /* set dch flg */
|
||||
sim_activate (uptr, msc_xtime); /* re-activate */
|
||||
return SCPE_OK; }
|
||||
sim_activate (uptr, msc_gtime); /* sched IRG */
|
||||
if (uptr->FNC == FNC_RFF) msc_1st = 1; /* diagnostic? */
|
||||
else uptr->FNC = 0; /* NOP func */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_WC: /* write */
|
||||
if (msc_1st) msc_1st = ms_ptr = 0; /* no xfer on first */
|
||||
else { /* not 1st, next char */
|
||||
if (ms_ptr < DBSIZE) { /* room in buffer? */
|
||||
msxb[ms_ptr] = msd_buf >> 8; /* store 2 char */
|
||||
msxb[ms_ptr + 1] = msd_buf & 0377;
|
||||
ms_ptr = ms_ptr + 2;
|
||||
uptr->UST = 0; }
|
||||
else msc_sta = msc_sta | STA_PAR; }
|
||||
if (CTL (devd)) { /* xfer flop set? */
|
||||
setFLG (devd); /* set dch flag */
|
||||
sim_activate (uptr, msc_xtime); /* re-activate */
|
||||
return SCPE_OK; }
|
||||
if (ms_ptr) { /* any data? write */
|
||||
if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) { /* write, err? */
|
||||
r = ms_map_err (uptr, st); /* map error */
|
||||
break; } }
|
||||
sim_activate (uptr, msc_gtime); /* sched IRG */
|
||||
uptr->FNC = 0; /* NOP func */
|
||||
return SCPE_OK;
|
||||
|
||||
default: /* unknown */
|
||||
break; }
|
||||
|
||||
setFLG (devc); /* set cch flg */
|
||||
msc_sta = msc_sta & ~STA_BUSY; /* update status */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Map tape error status */
|
||||
|
||||
t_stat ms_map_err (UNIT *uptr, t_stat st)
|
||||
{
|
||||
switch (st) {
|
||||
case MTSE_FMT: /* illegal fmt */
|
||||
case MTSE_UNATT: /* unattached */
|
||||
msc_sta = msc_sta | STA_REJ; /* reject */
|
||||
case MTSE_OK: /* no error */
|
||||
return SCPE_IERR; /* never get here! */
|
||||
case MTSE_TMK: /* end of file */
|
||||
msc_sta = msc_sta | STA_EOF | STA_ODD; /* eof (also sets odd) */
|
||||
break;
|
||||
case MTSE_INVRL: /* invalid rec lnt */
|
||||
msc_sta = msc_sta | STA_PAR;
|
||||
return SCPE_MTRLNT;
|
||||
case MTSE_IOERR: /* IO error */
|
||||
msc_sta = msc_sta | STA_PAR; /* error */
|
||||
if (msc_stopioe) return SCPE_IOERR;
|
||||
break;
|
||||
case MTSE_RECE: /* record in error */
|
||||
case MTSE_EOM: /* end of medium */
|
||||
msc_sta = msc_sta | STA_PAR; /* error */
|
||||
break;
|
||||
case MTSE_BOT: /* reverse into BOT */
|
||||
uptr->UST = STA_BOT; /* set status */
|
||||
break;
|
||||
case MTSE_WRP: /* write protect */
|
||||
msc_sta = msc_sta | STA_REJ; /* reject */
|
||||
break; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat msc_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
hp_enbdis_pair (&msc_dev, &msd_dev); /* make pair cons */
|
||||
msc_buf = msd_buf = 0;
|
||||
msc_sta = msc_usl = 0;
|
||||
msc_1st = 0;
|
||||
msc_dib.cmd = msd_dib.cmd = 0; /* clear cmd */
|
||||
msc_dib.ctl = msd_dib.ctl = 0; /* clear ctl */
|
||||
msc_dib.flg = msd_dib.flg = 1; /* set flg */
|
||||
msc_dib.fbf = msd_dib.fbf = 1; /* set fbf */
|
||||
for (i = 0; i < MS_NUMDR; i++) {
|
||||
uptr = msc_dev.units + i;
|
||||
sim_tape_reset (uptr);
|
||||
sim_cancel (uptr);
|
||||
uptr->UST = 0; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat msc_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = sim_tape_attach (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r; /* update status */
|
||||
uptr->UST = STA_BOT;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat msc_detach (UNIT* uptr)
|
||||
{
|
||||
uptr->UST = 0; /* update status */
|
||||
return sim_tape_detach (uptr); /* detach unit */
|
||||
}
|
||||
|
||||
/* Set controller type */
|
||||
|
||||
t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
|
||||
for (i = 0; i < MS_NUMDR; i++) {
|
||||
if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; }
|
||||
ms_ctype = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show controller type */
|
||||
|
||||
t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if (ms_ctype) fprintf (st, "13183A");
|
||||
else fprintf (st, "13181A");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 7970B/7970E bootstrap routine (HP 12992D ROM) */
|
||||
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
|
||||
static const int32 mboot[IBL_LNT] = {
|
||||
0106501, /*ST LIB 1 ; read sw */
|
||||
0006011, /* SLB,RSS ; bit 0 set? */
|
||||
0027714, /* JMP RD ; no read */
|
||||
0003004, /* CMA,INA ; A is ctr */
|
||||
0073775, /* STA WC ; save */
|
||||
0067772, /* LDA SL0RW ; sel 0, rew */
|
||||
0017762, /*FF JSB CMD ; do cmd */
|
||||
0102301+CHANGE_DEV, /* SFS CC ; done? */
|
||||
0027707, /* JMP *-1 ; wait */
|
||||
0067774, /* LDB FFC ; get file fwd */
|
||||
0037775, /* ISZ WC ; done files? */
|
||||
0027706, /* JMP FF ; no */
|
||||
0067773, /*RD LDB RDCMD ; read cmd */
|
||||
0017762, /* JSB CMD ; do cmd */
|
||||
0103700+CHANGE_DEV, /* STC DC,C ; start dch */
|
||||
0102201+CHANGE_DEV, /* SFC CC ; read done? */
|
||||
0027752, /* JMP STAT ; no, get stat */
|
||||
0102300+CHANGE_DEV, /* SFS DC ; any data? */
|
||||
0027717, /* JMP *-3 ; wait */
|
||||
0107500+CHANGE_DEV, /* LIB DC,C ; get rec cnt */
|
||||
0005727, /* BLF,BLF ; move to lower */
|
||||
0007000, /* CMB ; make neg */
|
||||
0077775, /* STA WC ; save */
|
||||
0102201+CHANGE_DEV, /* SFC CC ; read done? */
|
||||
0027752, /* JMP STAT ; no, get stat */
|
||||
0102300+CHANGE_DEV, /* SFS DC ; any data? */
|
||||
0027727, /* JMP *-3 ; wait */
|
||||
0107500+CHANGE_DEV, /* LIB DC,C ; get load addr */
|
||||
0074000, /* STB 0 ; start csum */
|
||||
0077762, /* STA CMD ; save address */
|
||||
0027742, /* JMP *+4 */
|
||||
0177762, /*NW STB CMD,I ; store data */
|
||||
0040001, /* ADA 1 ; add to csum */
|
||||
0037762, /* ISZ CMD ; adv addr ptr */
|
||||
0102300+CHANGE_DEV, /* SFS DC ; any data? */
|
||||
0027742, /* JMP *-1 ; wait */
|
||||
0107500+CHANGE_DEV, /* LIB DC,C ; get word */
|
||||
0037775, /* ISZ WC ; done? */
|
||||
0027737, /* JMP NW ; no */
|
||||
0054000, /* CPB 0 ; csum ok? */
|
||||
0027717, /* JMP RD+3 ; yes, cont */
|
||||
0102011, /* HLT 11 ; no, halt */
|
||||
0102501+CHANGE_DEV, /*ST LIA CC ; get status */
|
||||
0001727, /* ALF,ALF ; get eof bit */
|
||||
0002020, /* SSA ; set? */
|
||||
0102077, /* HLT 77 ; done */
|
||||
0001727, /* ALF,ALF ; put status back */
|
||||
0001310, /* RAR,SLA ; read ok? */
|
||||
0102000, /* HLT 0 ; no */
|
||||
0027714, /* JMP RD ; read next */
|
||||
0000000, /*CMD 0 */
|
||||
0106601+CHANGE_DEV, /* OTB CC ; output cmd */
|
||||
0102501+CHANGE_DEV, /* LIA CC ; check for reject */
|
||||
0001323, /* RAR,RAR */
|
||||
0001310, /* RAR,SLA */
|
||||
0027763, /* JMP CMD+1 ; try again */
|
||||
0103701+CHANGE_DEV, /* STC CC,C ; start command */
|
||||
0127762, /* JMP CMD,I ; exit */
|
||||
0001501, /*SL0RW 001501 ; select 0, rewind */
|
||||
0001423, /*RDCMD 001423 ; read record */
|
||||
0000203, /*FFC 000203 ; space forward file */
|
||||
0000000, /*WC 000000 */
|
||||
0000000,
|
||||
0000000 };
|
||||
|
||||
t_stat msc_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, dev;
|
||||
|
||||
if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */
|
||||
dev = msd_dib.devno; /* get data chan dev */
|
||||
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
|
||||
SR = IBL_MS + (dev << IBL_V_DEV); /* set SR */
|
||||
if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1; /* skip? */
|
||||
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
|
||||
if (mboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (mboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = mboot[i]; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,478 +0,0 @@
|
||||
/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
mt 12559A 3030 nine track magnetic tape
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
28-Mar-03 RMS Added multiformat support
|
||||
28-Feb-03 RMS Revised for magtape library
|
||||
30-Sep-02 RMS Revamped error handling
|
||||
28-Aug-02 RMS Added end of medium support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
22-Apr-02 RMS Added maximum record length test
|
||||
20-Jan-02 RMS Fixed bug on last character write
|
||||
03-Dec-01 RMS Added read only unit, extended SET/SHOW support
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
30-Nov-00 RMS Made variable names unique
|
||||
04-Oct-98 RMS V2.4 magtape format
|
||||
|
||||
Magnetic tapes are represented as a series of variable records
|
||||
of the form:
|
||||
|
||||
32b byte count
|
||||
byte 0
|
||||
byte 1
|
||||
:
|
||||
byte n-2
|
||||
byte n-1
|
||||
32b byte count
|
||||
|
||||
If the byte count is odd, the record is padded with an extra byte
|
||||
of junk. File marks are represented by a byte count of 0.
|
||||
|
||||
Unusually among HP peripherals, the 12559 does not have a command flop,
|
||||
and its flag and flag buffer power up as clear rather than set.
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
#define DB_V_SIZE 16 /* max data buf */
|
||||
#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */
|
||||
|
||||
/* Command - mtc_fnc */
|
||||
|
||||
#define FNC_CLR 0300 /* clear */
|
||||
#define FNC_WC 0031 /* write */
|
||||
#define FNC_RC 0023 /* read */
|
||||
#define FNC_GAP 0011 /* write gap */
|
||||
#define FNC_FSR 0003 /* forward space */
|
||||
#define FNC_BSR 0041 /* backward space */
|
||||
#define FNC_REW 0201 /* rewind */
|
||||
#define FNC_RWS 0101 /* rewind and offline */
|
||||
#define FNC_WFM 0035 /* write file mark */
|
||||
|
||||
/* Status - stored in mtc_sta, (d) = dynamic */
|
||||
|
||||
#define STA_LOCAL 0400 /* local (d) */
|
||||
#define STA_EOF 0200 /* end of file */
|
||||
#define STA_BOT 0100 /* beginning of tape */
|
||||
#define STA_EOT 0040 /* end of tape */
|
||||
#define STA_TIM 0020 /* timing error */
|
||||
#define STA_REJ 0010 /* programming error */
|
||||
#define STA_WLK 0004 /* write locked (d) */
|
||||
#define STA_PAR 0002 /* parity error */
|
||||
#define STA_BUSY 0001 /* busy (d) */
|
||||
|
||||
extern uint32 PC;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
int32 mtc_fnc = 0; /* function */
|
||||
int32 mtc_sta = 0; /* status register */
|
||||
int32 mtc_dtf = 0; /* data xfer flop */
|
||||
int32 mtc_1st = 0; /* first svc flop */
|
||||
int32 mtc_ctime = 1000; /* command wait */
|
||||
int32 mtc_gtime = 1000; /* gap stop time */
|
||||
int32 mtc_xtime = 15; /* data xfer time */
|
||||
int32 mtc_stopioe = 1; /* stop on error */
|
||||
uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */
|
||||
t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */
|
||||
static const int32 mtc_cmd[] = {
|
||||
FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM };
|
||||
|
||||
DEVICE mtd_dev, mtc_dev;
|
||||
int32 mtdio (int32 inst, int32 IR, int32 dat);
|
||||
int32 mtcio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat mtc_svc (UNIT *uptr);
|
||||
t_stat mtc_reset (DEVICE *dptr);
|
||||
t_stat mtc_attach (UNIT *uptr, char *cptr);
|
||||
t_stat mtc_detach (UNIT *uptr);
|
||||
t_stat mt_map_err (UNIT *uptr, t_stat st);
|
||||
|
||||
/* MTD data structures
|
||||
|
||||
mtd_dev MTD device descriptor
|
||||
mtd_unit MTD unit list
|
||||
mtd_reg MTD register list
|
||||
*/
|
||||
|
||||
DIB mt_dib[] = {
|
||||
{ MTD, 0, 0, 0, 0, &mtdio },
|
||||
{ MTC, 0, 0, 0, 0, &mtcio } };
|
||||
|
||||
#define mtd_dib mt_dib[0]
|
||||
#define mtc_dib mt_dib[1]
|
||||
|
||||
UNIT mtd_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG mtd_reg[] = {
|
||||
{ FLDATA (CMD, mtd_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, mtd_dib.ctl, 0), REG_HRO },
|
||||
{ FLDATA (FLG, mtd_dib.flg, 0) },
|
||||
{ FLDATA (FBF, mtd_dib.fbf, 0), REG_HRO },
|
||||
{ BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },
|
||||
{ DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },
|
||||
{ DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },
|
||||
{ ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB mtd_mod[] = {
|
||||
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &mtd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE mtd_dev = {
|
||||
"MTD", &mtd_unit, mtd_reg, mtd_mod,
|
||||
1, 10, 16, 1, 8, 8,
|
||||
NULL, NULL, &mtc_reset,
|
||||
NULL, NULL, NULL,
|
||||
&mtd_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* MTC data structures
|
||||
|
||||
mtc_dev MTC device descriptor
|
||||
mtc_unit MTC unit list
|
||||
mtc_reg MTC register list
|
||||
mtc_mod MTC modifier list
|
||||
*/
|
||||
|
||||
UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) };
|
||||
|
||||
REG mtc_reg[] = {
|
||||
{ ORDATA (FNC, mtc_fnc, 8) },
|
||||
{ ORDATA (STA, mtc_sta, 9) },
|
||||
{ ORDATA (BUF, mtc_unit.buf, 8) },
|
||||
{ FLDATA (CMD, mtc_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, mtc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, mtc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, mtc_dib.fbf, 0) },
|
||||
{ FLDATA (DTF, mtc_dtf, 0) },
|
||||
{ FLDATA (FSVC, mtc_1st, 0) },
|
||||
{ DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, mtc_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB mtc_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &mtd_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE mtc_dev = {
|
||||
"MTC", &mtc_unit, mtc_reg, mtc_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &mtc_reset,
|
||||
NULL, &mtc_attach, &mtc_detach,
|
||||
&mtc_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 mtdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
mtc_unit.buf = dat & 0377; /* store data */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | mtc_unit.buf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = mtc_unit.buf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) mtc_dtf = 0; /* CLC: clr xfer flop */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 mtcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 i, devc, devd, valid;
|
||||
t_stat st;
|
||||
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
devd = devc - 1;
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
dat = dat & 0377;
|
||||
mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */
|
||||
if (dat == FNC_CLR) { /* clear? */
|
||||
if (sim_is_active (&mtc_unit) && /* write in prog? */
|
||||
(mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */
|
||||
if (st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF))
|
||||
mt_map_err (&mtc_unit, st); }
|
||||
if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) &&
|
||||
sim_is_active (&mtc_unit)) sim_cancel (&mtc_unit);
|
||||
mtc_1st = mtc_dtf = 0;
|
||||
mtc_sta = mtc_sta & STA_BOT;
|
||||
clrCTL (devc); /* init device */
|
||||
clrFLG (devc);
|
||||
clrCTL (devd);
|
||||
clrFLG (devd);
|
||||
return SCPE_OK; }
|
||||
for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */
|
||||
if (dat == mtc_cmd[i]) valid = 1;
|
||||
if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */
|
||||
((mtc_sta & STA_BOT) && (dat == FNC_BSR)) ||
|
||||
(sim_tape_wrp (&mtc_unit) &&
|
||||
((dat == FNC_WC) || (dat == FNC_GAP) || (dat == FNC_WFM))))
|
||||
mtc_sta = mtc_sta | STA_REJ;
|
||||
else {
|
||||
sim_activate (&mtc_unit, mtc_ctime); /* start tape */
|
||||
mtc_fnc = dat; /* save function */
|
||||
mtc_sta = STA_BUSY; /* unit busy */
|
||||
mt_ptr = 0; /* init buffer ptr */
|
||||
clrFLG (devc); /* clear flags */
|
||||
clrFLG (devd);
|
||||
mtc_1st = 1; /* set 1st flop */
|
||||
mtc_dtf = 1; } /* set xfer flop */
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | (mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY));
|
||||
if (mtc_unit.flags & UNIT_ATT) { /* construct status */
|
||||
if (sim_is_active (&mtc_unit)) dat = dat | STA_BUSY;
|
||||
if (sim_tape_wrp (&mtc_unit)) dat = dat | STA_WLK; }
|
||||
else dat = dat | STA_BUSY | STA_LOCAL;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { clrCTL (devc); } /* CLC */
|
||||
else { setCTL (devc); } /* STC */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
|
||||
If rewind done, reposition to start of tape, set status
|
||||
else, do operation, set done, interrupt
|
||||
|
||||
Can't be write locked, can only write lock detached unit
|
||||
*/
|
||||
|
||||
t_stat mtc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 devc, devd;
|
||||
t_mtrlnt tbc;
|
||||
t_stat st, r = SCPE_OK;
|
||||
|
||||
devc = mtc_dib.devno; /* get device nos */
|
||||
devd = mtd_dib.devno;
|
||||
if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */
|
||||
mtc_sta = STA_LOCAL | STA_REJ; /* rejected */
|
||||
setFLG (devc); /* set cch flg */
|
||||
return IORETURN (mtc_stopioe, SCPE_UNATT); }
|
||||
|
||||
switch (mtc_fnc) { /* case on function */
|
||||
|
||||
case FNC_REW: /* rewind */
|
||||
sim_tape_rewind (uptr); /* BOT */
|
||||
mtc_sta = STA_BOT; /* update status */
|
||||
break;
|
||||
|
||||
case FNC_RWS: /* rewind and offline */
|
||||
sim_tape_rewind (uptr); /* clear position */
|
||||
return sim_tape_detach (uptr); /* don't set cch flg */
|
||||
|
||||
case FNC_WFM: /* write file mark */
|
||||
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
mtc_sta = STA_EOF; /* set EOF status */
|
||||
break;
|
||||
|
||||
case FNC_GAP: /* erase gap */
|
||||
break;
|
||||
|
||||
case FNC_FSR: /* space forward */
|
||||
if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
break;
|
||||
|
||||
case FNC_BSR: /* space reverse */
|
||||
if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
break;
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
case FNC_RC: /* read */
|
||||
if (mtc_1st) { /* first svc? */
|
||||
mtc_1st = mt_ptr = 0; /* clr 1st flop */
|
||||
st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */
|
||||
if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */
|
||||
else if (st != MTSE_OK) { /* other error? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
if (r == SCPE_OK) { /* recoverable? */
|
||||
sim_activate (uptr, mtc_gtime); /* sched IRG */
|
||||
mtc_fnc = 0; /* NOP func */
|
||||
return SCPE_OK; }
|
||||
break; } /* non-recov, done */
|
||||
if (mt_max < 12) { /* record too short? */
|
||||
mtc_sta = mtc_sta | STA_PAR; /* set flag */
|
||||
break; }
|
||||
}
|
||||
if (mt_ptr < mt_max) { /* more chars? */
|
||||
if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM;
|
||||
mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */
|
||||
setFLG (devd); /* set dch flg */
|
||||
sim_activate (uptr, mtc_xtime); /* re-activate */
|
||||
return SCPE_OK; }
|
||||
sim_activate (uptr, mtc_gtime); /* schedule gap */
|
||||
mtc_fnc = 0; /* nop */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_WC: /* write */
|
||||
if (mtc_1st) mtc_1st = 0; /* no xfr on first */
|
||||
else {
|
||||
if (mt_ptr < DBSIZE) { /* room in buffer? */
|
||||
mtxb[mt_ptr++] = mtc_unit.buf;
|
||||
mtc_sta = mtc_sta & ~STA_BOT; } /* clear BOT */
|
||||
else mtc_sta = mtc_sta | STA_PAR; }
|
||||
if (mtc_dtf) { /* xfer flop set? */
|
||||
setFLG (devd); /* set dch flag */
|
||||
sim_activate (uptr, mtc_xtime); /* re-activate */
|
||||
return SCPE_OK; }
|
||||
if (mt_ptr) { /* write buffer */
|
||||
if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) { /* write, err? */
|
||||
r = mt_map_err (uptr, st); /* map error */
|
||||
break; } } /* done */
|
||||
sim_activate (uptr, mtc_gtime); /* schedule gap */
|
||||
mtc_fnc = 0; /* nop */
|
||||
return SCPE_OK;
|
||||
|
||||
default: /* unknown */
|
||||
break; }
|
||||
|
||||
setFLG (devc); /* set cch flg */
|
||||
mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Map tape error status */
|
||||
|
||||
t_stat mt_map_err (UNIT *uptr, t_stat st)
|
||||
{
|
||||
switch (st) {
|
||||
case MTSE_FMT: /* illegal fmt */
|
||||
case MTSE_UNATT: /* unattached */
|
||||
mtc_sta = mtc_sta | STA_REJ; /* reject */
|
||||
case MTSE_OK: /* no error */
|
||||
return SCPE_IERR; /* never get here! */
|
||||
case MTSE_TMK: /* end of file */
|
||||
mtc_sta = mtc_sta | STA_EOF; /* eof */
|
||||
break;
|
||||
case MTSE_IOERR: /* IO error */
|
||||
mtc_sta = mtc_sta | STA_PAR; /* error */
|
||||
if (mtc_stopioe) return SCPE_IOERR;
|
||||
break;
|
||||
case MTSE_INVRL: /* invalid rec lnt */
|
||||
mtc_sta = mtc_sta | STA_PAR;
|
||||
return SCPE_MTRLNT;
|
||||
case MTSE_RECE: /* record in error */
|
||||
case MTSE_EOM: /* end of medium */
|
||||
mtc_sta = mtc_sta | STA_PAR; /* error */
|
||||
break;
|
||||
case MTSE_BOT: /* reverse into BOT */
|
||||
mtc_sta = mtc_sta | STA_BOT; /* set status */
|
||||
break;
|
||||
case MTSE_WRP: /* write protect */
|
||||
mtc_sta = mtc_sta | STA_REJ; /* reject */
|
||||
break; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat mtc_reset (DEVICE *dptr)
|
||||
{
|
||||
hp_enbdis_pair (&mtc_dev, &mtd_dev); /* make pair cons */
|
||||
mtc_fnc = 0;
|
||||
mtc_1st = mtc_dtf = 0;
|
||||
mtc_dib.cmd = mtd_dib.cmd = 0; /* clear cmd */
|
||||
mtc_dib.ctl = mtd_dib.ctl = 0; /* clear ctl */
|
||||
mtc_dib.flg = mtd_dib.flg = 0; /* clear flg */
|
||||
mtc_dib.fbf = mtd_dib.fbf = 0; /* clear fbf */
|
||||
sim_cancel (&mtc_unit); /* cancel activity */
|
||||
sim_tape_reset (&mtc_unit);
|
||||
if (mtc_unit.flags & UNIT_ATT) mtc_sta =
|
||||
(sim_tape_bot (&mtc_unit)? STA_BOT: 0) |
|
||||
(sim_tape_wrp (&mtc_unit)? STA_WLK: 0);
|
||||
else mtc_sta = STA_LOCAL | STA_BUSY;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat mtc_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = sim_tape_attach (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r; /* update status */
|
||||
mtc_sta = STA_BOT;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat mtc_detach (UNIT* uptr)
|
||||
{
|
||||
mtc_sta = 0; /* update status */
|
||||
return sim_tape_detach (uptr); /* detach unit */
|
||||
}
|
||||
@@ -1,704 +0,0 @@
|
||||
/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
mux,muxl,muxc 12920A terminal multiplexor
|
||||
|
||||
09-May-03 RMS Added network device flag
|
||||
01-Nov-02 RMS Added 7B/8B support
|
||||
22-Aug-02 RMS Updated for changes to sim_tmxr
|
||||
|
||||
The 12920A consists of three separate devices
|
||||
|
||||
mux scanner (upper data card)
|
||||
muxl lines (lower data card)
|
||||
muxm modem control (control card)
|
||||
|
||||
The lower data card has no CMD flop; the control card has no CMD flop.
|
||||
The upper data card has none of the usual flops.
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include "sim_sock.h"
|
||||
#include "sim_tmxr.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define MUX_LINES 16 /* user lines */
|
||||
#define MUX_ILINES 5 /* diag rcv only */
|
||||
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
|
||||
#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */
|
||||
#define UNIT_V_MDM (UNIT_V_UF + 2) /* modem control */
|
||||
#define UNIT_8B (1 << UNIT_V_8B)
|
||||
#define UNIT_UC (1 << UNIT_V_UC)
|
||||
#define UNIT_MDM (1 << UNIT_V_MDM)
|
||||
#define MUXU_INIT_POLL 8000
|
||||
#define MUXL_WAIT 500
|
||||
|
||||
/* Channel number (OTA upper, LIA lower or upper) */
|
||||
|
||||
#define MUX_V_CHAN 10 /* channel num */
|
||||
#define MUX_M_CHAN 037
|
||||
#define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN)
|
||||
|
||||
/* OTA, lower = parameters or data */
|
||||
|
||||
#define OTL_P 0100000 /* parameter */
|
||||
#define OTL_TX 0040000 /* transmit */
|
||||
#define OTL_ENB 0020000 /* enable */
|
||||
#define OTL_TPAR 0010000 /* xmt parity */
|
||||
#define OTL_ECHO 0010000 /* rcv echo */
|
||||
#define OTL_DIAG 0004000 /* diagnose */
|
||||
#define OTL_SYNC 0004000 /* sync */
|
||||
#define OTL_V_LNT 8 /* char length */
|
||||
#define OTL_M_LNT 07
|
||||
#define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT)
|
||||
#define OTL_V_BAUD 0 /* baud rate */
|
||||
#define OTL_M_BAUD 0377
|
||||
#define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD)
|
||||
#define OTL_CHAR 01777 /* char mask */
|
||||
|
||||
/* LIA, lower = received data */
|
||||
|
||||
#define LIL_PAR 0100000 /* parity */
|
||||
#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN)
|
||||
#define LIL_CHAR 01777 /* character */
|
||||
|
||||
/* LIA, upper = status */
|
||||
|
||||
#define LIU_SEEK 0100000 /* seeking NI */
|
||||
#define LIU_DG 0000010 /* diagnose */
|
||||
#define LIU_BRK 0000004 /* break */
|
||||
#define LIU_LOST 0000002 /* char lost */
|
||||
#define LIU_TR 0000001 /* trans/rcv */
|
||||
|
||||
/* OTA, control */
|
||||
|
||||
#define OTC_SCAN 0100000 /* scan */
|
||||
#define OTC_UPD 0040000 /* update */
|
||||
#define OTC_V_CHAN 10 /* channel */
|
||||
#define OTC_M_CHAN 017
|
||||
#define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN)
|
||||
#define OTC_EC2 0000200 /* enable Cn upd */
|
||||
#define OTC_EC1 0000100
|
||||
#define OTC_C2 0000040 /* Cn flops */
|
||||
#define OTC_C1 0000020
|
||||
#define OTC_ES2 0000010 /* enb comparison */
|
||||
#define OTC_ES1 0000004
|
||||
#define OTC_V_ES 2
|
||||
#define OTC_SS2 0000002 /* SSn flops */
|
||||
#define OTC_SS1 0000001
|
||||
#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1)
|
||||
#define RTS OCT_C2 /* C2 = rts */
|
||||
#define DTR OTC_C1 /* C1 = dtr */
|
||||
|
||||
/* LIA, control */
|
||||
|
||||
#define LIC_MBO 0140000 /* always set */
|
||||
#define LIC_V_CHAN 10 /* channel */
|
||||
#define LIC_M_CHAN 017
|
||||
#define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN)
|
||||
#define LIC_I2 0001000 /* change flags */
|
||||
#define LIC_I1 0000400
|
||||
#define LIC_S2 0000002 /* Sn flops */
|
||||
#define LIC_S1 0000001
|
||||
#define LIC_V_I 8 /* S1 to I1 */
|
||||
#define CDET LIC_S2 /* S2 = cdet */
|
||||
#define DSR LIC_S1 /* S1 = dsr */
|
||||
|
||||
#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \
|
||||
((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \
|
||||
<< LIC_V_I)
|
||||
|
||||
extern uint32 PC;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
|
||||
uint16 mux_sta[MUX_LINES]; /* line status */
|
||||
uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */
|
||||
uint16 mux_xpar[MUX_LINES]; /* xmt param */
|
||||
uint8 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */
|
||||
uint8 mux_xbuf[MUX_LINES]; /* xmt buf */
|
||||
uint8 mux_rchp[MUX_LINES + MUX_ILINES]; /* rcv chr pend */
|
||||
uint8 mux_xdon[MUX_LINES]; /* xmt done */
|
||||
uint8 muxc_ota[MUX_LINES]; /* ctrl: Cn,ESn,SSn */
|
||||
uint8 muxc_lia[MUX_LINES]; /* ctrl: Sn */
|
||||
uint32 mux_tps = 100; /* polls/second */
|
||||
uint32 muxl_ibuf = 0; /* low in: rcv data */
|
||||
uint32 muxl_obuf = 0; /* low out: param */
|
||||
uint32 muxu_ibuf = 0; /* upr in: status */
|
||||
uint32 muxu_obuf = 0; /* upr out: chan */
|
||||
uint32 muxc_chan = 0; /* ctrl chan */
|
||||
uint32 muxc_scan = 0; /* ctrl scan */
|
||||
|
||||
TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */
|
||||
TMXR mux_desc = { MUX_LINES, 0, 0, NULL }; /* mux descriptor */
|
||||
|
||||
DEVICE muxl_dev, muxu_dev, muxc_dev;
|
||||
int32 muxlio (int32 inst, int32 IR, int32 dat);
|
||||
int32 muxuio (int32 inst, int32 IR, int32 dat);
|
||||
int32 muxcio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat muxi_svc (UNIT *uptr);
|
||||
t_stat muxo_svc (UNIT *uptr);
|
||||
t_stat mux_reset (DEVICE *dptr);
|
||||
t_stat mux_attach (UNIT *uptr, char *cptr);
|
||||
t_stat mux_detach (UNIT *uptr);
|
||||
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
void mux_data_int (void);
|
||||
void mux_ctrl_int (void);
|
||||
void mux_diag (int32 c);
|
||||
|
||||
static uint8 odd_par[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-257 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-367 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; /* 360-377 */
|
||||
|
||||
#define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0)
|
||||
|
||||
DIB mux_dib[] = {
|
||||
{ MUXL, 0, 0, 0, 0, &muxlio },
|
||||
{ MUXU, 0, 0, 0, 0, &muxuio } };
|
||||
|
||||
#define muxl_dib mux_dib[0]
|
||||
#define muxu_dib mux_dib[1]
|
||||
|
||||
/* MUX data structures
|
||||
|
||||
muxu_dev MUX device descriptor
|
||||
muxu_unit MUX unit descriptor
|
||||
muxu_reg MUX register list
|
||||
muxu_mod MUX modifiers list
|
||||
*/
|
||||
|
||||
UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), MUXU_INIT_POLL };
|
||||
|
||||
REG muxu_reg[] = {
|
||||
{ ORDATA (IBUF, muxu_ibuf, 16) },
|
||||
{ ORDATA (OBUF, muxu_obuf, 16) },
|
||||
{ FLDATA (CMD, muxu_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, muxu_dib.ctl, 0), REG_HRO },
|
||||
{ FLDATA (FLG, muxu_dib.flg, 0), REG_HRO },
|
||||
{ FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO },
|
||||
{ ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB muxu_mod[] = {
|
||||
{ UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &mux_summ },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||
NULL, &mux_show, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
|
||||
NULL, &mux_show, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &muxl_dev },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
|
||||
&tmxr_dscln, NULL, &mux_desc },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE muxu_dev = {
|
||||
"MUX", &muxu_unit, muxu_reg, muxu_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
&tmxr_ex, &tmxr_dep, &mux_reset,
|
||||
NULL, &mux_attach, &mux_detach,
|
||||
&muxu_dib, DEV_NET | DEV_DISABLE };
|
||||
|
||||
/* MUXL data structures
|
||||
|
||||
muxl_dev MUXL device descriptor
|
||||
muxl_unit MUXL unit descriptor
|
||||
muxl_reg MUXL register list
|
||||
muxl_mod MUXL modifiers list
|
||||
*/
|
||||
|
||||
UNIT muxl_unit[] = {
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT } };
|
||||
|
||||
MTAB muxl_mod[] = {
|
||||
{ UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", NULL },
|
||||
{ UNIT_UC+UNIT_8B, 0 , "7b", "7B", NULL },
|
||||
{ UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", NULL },
|
||||
{ UNIT_MDM, 0, "no dataset", "NODATASET", NULL },
|
||||
{ UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &muxl_dev },
|
||||
{ 0 } };
|
||||
|
||||
REG muxl_reg[] = {
|
||||
{ FLDATA (CMD, muxl_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, muxl_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, muxl_dib.flg, 0) },
|
||||
{ FLDATA (FBF, muxl_dib.fbf, 0) },
|
||||
{ BRDATA (STA, mux_sta, 8, 16, MUX_LINES) },
|
||||
{ BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) },
|
||||
{ BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) },
|
||||
{ BRDATA (RBUF, mux_rbuf, 8, 8, MUX_LINES + MUX_ILINES) },
|
||||
{ BRDATA (XBUF, mux_xbuf, 8, 8, MUX_LINES) },
|
||||
{ BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) },
|
||||
{ BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) },
|
||||
{ URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
|
||||
MUX_LINES, REG_NZ + PV_LEFT) },
|
||||
{ ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE muxl_dev = {
|
||||
"MUXL", muxl_unit, muxl_reg, muxl_mod,
|
||||
MUX_LINES, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &mux_reset,
|
||||
NULL, NULL, NULL,
|
||||
&muxl_dib, 0 };
|
||||
|
||||
/* MUXM data structures
|
||||
|
||||
muxc_dev MUXM device descriptor
|
||||
muxc_unit MUXM unit descriptor
|
||||
muxc_reg MUXM register list
|
||||
muxc_mod MUXM modifiers list
|
||||
*/
|
||||
|
||||
DIB muxc_dib = { MUXC, 0, 0, 0, 0, &muxcio };
|
||||
|
||||
UNIT muxc_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG muxc_reg[] = {
|
||||
{ FLDATA (CMD, muxc_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, muxc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, muxc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, muxc_dib.fbf, 0) },
|
||||
{ FLDATA (SCAN, muxc_scan, 0) },
|
||||
{ ORDATA (CHAN, muxc_chan, 4) },
|
||||
{ BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) },
|
||||
{ BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) },
|
||||
{ ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB muxc_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &muxc_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE muxc_dev = {
|
||||
"MUXM", &muxc_unit, muxc_reg, muxc_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &mux_reset,
|
||||
NULL, NULL, NULL,
|
||||
&muxc_dib, 0 };
|
||||
|
||||
/* IOT routines: data cards */
|
||||
|
||||
int32 muxlio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev, ln;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
muxl_obuf = dat; /* store data */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | muxl_ibuf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = muxl_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
|
||||
else { /* STC */
|
||||
setCTL (dev); /* set ctl */
|
||||
ln = MUX_CHAN (muxu_obuf); /* get chan # */
|
||||
if (muxl_obuf & OTL_P) { /* parameter set? */
|
||||
if (muxl_obuf & OTL_TX) { /* transmit? */
|
||||
if (ln < MUX_LINES) /* to valid line? */
|
||||
mux_xpar[ln] = muxl_obuf; }
|
||||
else if (ln < (MUX_LINES + MUX_ILINES)) /* rcv, valid line? */
|
||||
mux_rpar[ln] = muxl_obuf; }
|
||||
else if ((muxl_obuf & OTL_TX) && /* xmit data? */
|
||||
(ln < MUX_LINES)) { /* to valid line? */
|
||||
if (sim_is_active (&muxl_unit[ln])) /* still working? */
|
||||
mux_sta[ln] = mux_sta[ln] | LIU_LOST;
|
||||
else sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
|
||||
mux_xbuf[ln] = muxl_obuf & OTL_CHAR; } /* load buffer */
|
||||
} /* end STC */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { /* H/C option */
|
||||
clrFLG (dev); /* clear flag */
|
||||
mux_data_int (); } /* look for new int */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 muxuio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioOTX: /* output */
|
||||
muxu_obuf = dat; /* store data */
|
||||
break;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | muxu_ibuf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = muxu_ibuf;
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* IOT routine: control card */
|
||||
|
||||
int32 muxcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev, ln, t, old;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
if (dat & OTC_SCAN) muxc_scan = 1; /* set scan flag */
|
||||
else muxc_scan = 0;
|
||||
if (dat & OTC_UPD) { /* update? */
|
||||
ln = OTC_CHAN (dat); /* get channel */
|
||||
old = muxc_ota[ln]; /* save prior val */
|
||||
muxc_ota[ln] = (muxc_ota[ln] & ~OTC_RW) | /* save ESn,SSn */
|
||||
(dat & OTC_RW);
|
||||
if (dat & OTC_EC2) muxc_ota[ln] = /* if EC2, upd C2 */
|
||||
(muxc_ota[ln] & ~OTC_C2) | (dat & OTC_C2);
|
||||
if (dat & OTC_EC1) muxc_ota[ln] = /* if EC1, upd C1 */
|
||||
(muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1);
|
||||
if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
|
||||
(old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */
|
||||
tmxr_msg (mux_ldsc[ln].conn, "\r\nLine hangup\r\n");
|
||||
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
|
||||
muxc_lia[ln] = 0; } /* dataset off */
|
||||
} /* end update */
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
t = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */
|
||||
LIC_TSTI (muxc_chan) | /* I2, I1 */
|
||||
(muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */
|
||||
(muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */
|
||||
dat = dat | t; /* return status */
|
||||
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
|
||||
break;
|
||||
case ioCTL: /* ctrl clear/set */
|
||||
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
|
||||
else { setCTL (dev); } /* STC */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { /* H/C option */
|
||||
clrFLG (dev); /* clear flag */
|
||||
mux_ctrl_int (); } /* look for new int */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service - receive side
|
||||
|
||||
Poll for new connections
|
||||
Poll all active lines for input
|
||||
*/
|
||||
|
||||
t_stat muxi_svc (UNIT *uptr)
|
||||
{
|
||||
int32 ln, c, t;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
t = sim_rtcn_calb (mux_tps, TMR_MUX); /* calibrate */
|
||||
sim_activate (uptr, t); /* continue poll */
|
||||
ln = tmxr_poll_conn (&mux_desc); /* look for connect */
|
||||
if (ln >= 0) { /* got one? */
|
||||
if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
|
||||
(muxc_ota[ln] & DTR)) /* DTR? */
|
||||
muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */
|
||||
muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */
|
||||
mux_ldsc[ln].rcve = 1; } /* rcv enabled */
|
||||
tmxr_poll_rx (&mux_desc); /* poll for input */
|
||||
for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */
|
||||
if (mux_ldsc[ln].conn) { /* connected? */
|
||||
if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */
|
||||
if (c & SCPE_BREAK) { /* break? */
|
||||
mux_sta[ln] = mux_sta[ln] | LIU_BRK;
|
||||
mux_rbuf[ln] = 0; } /* no char */
|
||||
else { /* normal */
|
||||
if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST;
|
||||
if (muxl_unit[ln].flags & UNIT_UC) { /* cvt to UC? */
|
||||
c = c & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = c & ((muxl_unit[ln].flags & UNIT_8B)? 0377: 0177);
|
||||
if (mux_rpar[ln] & OTL_ECHO) { /* echo? */
|
||||
TMLN *lp = &mux_ldsc[ln]; /* get line */
|
||||
tmxr_putc_ln (lp, c); /* output char */
|
||||
tmxr_poll_tx (&mux_desc); } /* poll xmt */
|
||||
mux_rbuf[ln] = c; /* save char */
|
||||
mux_rchp[ln] = 1; } /* char pending */
|
||||
if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */
|
||||
} /* end if char */
|
||||
} /* end if connected */
|
||||
else muxc_lia[ln] = 0; /* disconnected */
|
||||
} /* end for */
|
||||
if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */
|
||||
if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Unit service - transmit side */
|
||||
|
||||
t_stat muxo_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c, ln = uptr - muxl_unit; /* line # */
|
||||
|
||||
if (mux_ldsc[ln].conn) { /* connected? */
|
||||
if (mux_ldsc[ln].xmte) { /* xmt enabled? */
|
||||
if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */
|
||||
TMLN *lp = &mux_ldsc[ln]; /* get line */
|
||||
c = mux_xbuf[ln]; /* get char */
|
||||
if (muxl_unit[ln].flags & UNIT_UC) { /* cvt to UC? */
|
||||
c = c & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = c & ((muxl_unit[ln].flags & UNIT_8B)? 0377: 0177);
|
||||
if (mux_xpar[ln] & OTL_DIAG) /* xmt diag? */
|
||||
mux_diag (mux_xbuf[ln]); /* before munge */
|
||||
mux_xdon[ln] = 1; /* set done */
|
||||
tmxr_putc_ln (lp, c); /* output char */
|
||||
tmxr_poll_tx (&mux_desc); } } /* poll xmt */
|
||||
else { /* buf full */
|
||||
tmxr_poll_tx (&mux_desc); /* poll xmt */
|
||||
sim_activate (uptr, muxl_unit[ln].wait); /* wait */
|
||||
return SCPE_OK; } }
|
||||
if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for int */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Look for data interrupt */
|
||||
|
||||
void mux_data_int (void)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < MUX_LINES; i++) { /* rcv lines */
|
||||
if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */
|
||||
muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */
|
||||
RCV_PAR (mux_rbuf[i]);
|
||||
muxu_ibuf = PUT_CCH (i) | mux_sta[i]; /* hi buf = stat */
|
||||
mux_rchp[i] = 0; /* clr char, stat */
|
||||
mux_sta[i] = 0;
|
||||
setFLG (muxl_dib.devno); /* interrupt */
|
||||
return; } }
|
||||
for (i = 0; i < MUX_LINES; i++) { /* xmt lines */
|
||||
if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */
|
||||
muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */
|
||||
mux_xdon[i] = 0; /* clr done, stat */
|
||||
mux_sta[i] = 0;
|
||||
setFLG (muxl_dib.devno); /* interrupt */
|
||||
return; } }
|
||||
for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */
|
||||
if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */
|
||||
muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */
|
||||
RCV_PAR (mux_rbuf[i]);
|
||||
muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */
|
||||
mux_rchp[i] = 0; /* clr char, stat */
|
||||
mux_sta[i] = 0;
|
||||
setFLG (muxl_dib.devno);
|
||||
return; } }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Look for control interrupt */
|
||||
|
||||
void mux_ctrl_int (void)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (muxc_scan == 0) return;
|
||||
for (i = 0; i < MUX_LINES; i++) {
|
||||
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */
|
||||
if (LIC_TSTI (muxc_chan)) { /* status change? */
|
||||
setFLG (muxc_dib.devno); /* set flag */
|
||||
break; } }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set diagnostic lines for given character */
|
||||
|
||||
void mux_diag (int32 c)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) {
|
||||
if (c & SCPE_BREAK) { /* break? */
|
||||
mux_sta[i] = mux_sta[i] | LIU_BRK;
|
||||
mux_rbuf[i] = 0; } /* no char */
|
||||
else {
|
||||
if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST;
|
||||
mux_rchp[i] = 1;
|
||||
mux_rbuf[i] = c; } }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset an individual line */
|
||||
|
||||
void mux_reset_ln (int32 i)
|
||||
{
|
||||
mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */
|
||||
mux_rpar[i] = mux_xpar[i] = 0;
|
||||
mux_rchp[i] = mux_xdon[i] = 0;
|
||||
mux_sta[i] = 0;
|
||||
muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */
|
||||
if (mux_ldsc[i].conn) /* connected? */
|
||||
muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */
|
||||
(muxl_unit[i].flags & UNIT_MDM? CDET: 0);
|
||||
sim_cancel (&muxl_unit[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat mux_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i, t;
|
||||
|
||||
if (muxu_dev.flags & DEV_DIS) { /* enb/dis dev */
|
||||
muxl_dev.flags = muxu_dev.flags | DEV_DIS;
|
||||
muxc_dev.flags = muxc_dev.flags | DEV_DIS; }
|
||||
else { muxl_dev.flags = muxl_dev.flags & ~DEV_DIS;
|
||||
muxc_dev.flags = muxc_dev.flags & ~DEV_DIS; }
|
||||
muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */
|
||||
muxl_dib.flg = muxl_dib.fbf = 1;
|
||||
muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */
|
||||
muxu_dib.flg = muxu_dib.fbf = 0; /* implemented */
|
||||
muxc_dib.cmd = muxc_dib.ctl = 0; /* init ctrl */
|
||||
muxc_dib.flg = muxc_dib.fbf = 1;
|
||||
muxc_chan = muxc_scan = 0; /* init modem scan */
|
||||
if (muxu_unit.flags & UNIT_ATT) { /* master att? */
|
||||
if (!sim_is_active (&muxu_unit)) {
|
||||
t = sim_rtcn_init (muxu_unit.wait, TMR_MUX);
|
||||
sim_activate (&muxu_unit, t); } } /* activate */
|
||||
else sim_cancel (&muxu_unit); /* else stop */
|
||||
for (i = 0; i < MUX_LINES; i++) {
|
||||
mux_desc.ldsc[i] = &mux_ldsc[i];
|
||||
mux_reset_ln (i); }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach master unit */
|
||||
|
||||
t_stat mux_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
int32 t;
|
||||
|
||||
r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
|
||||
if (r != SCPE_OK) return r; /* error */
|
||||
t = sim_rtcn_init (muxu_unit.wait, TMR_MUX);
|
||||
sim_activate (uptr, t); /* start poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach master unit */
|
||||
|
||||
t_stat mux_detach (UNIT *uptr)
|
||||
{
|
||||
int32 i;
|
||||
t_stat r;
|
||||
|
||||
r = tmxr_detach (&mux_desc, uptr); /* detach */
|
||||
for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */
|
||||
sim_cancel (uptr); /* stop poll */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Show summary processor */
|
||||
|
||||
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
int32 i, t;
|
||||
|
||||
for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0);
|
||||
if (t == 1) fprintf (st, "1 connection");
|
||||
else fprintf (st, "%d connections", t);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* SHOW CONN/STAT processor */
|
||||
|
||||
t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; (i < MUX_LINES) && (mux_ldsc[i].conn == 0); i++) ;
|
||||
if (i < MUX_LINES) {
|
||||
for (i = 0; i < MUX_LINES; i++) {
|
||||
if (mux_ldsc[i].conn) {
|
||||
if (val) tmxr_fconns (st, &mux_ldsc[i], i);
|
||||
else tmxr_fstats (st, &mux_ldsc[i], i); } } }
|
||||
else fprintf (st, "all disconnected\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1,704 +0,0 @@
|
||||
/* hp2100_stddev.c: HP2100 standard devices simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 MERCHANTI_CTLILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LII_CTLLE FOR ANY CLAIM, DAMAGES OR OTHER LII_CTLILITY, 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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
ptr 12597A-002 paper tape reader
|
||||
ptp 12597A-005 paper tape punch
|
||||
tty 12531C buffered teleprinter interface
|
||||
clk 12539C time base generator
|
||||
|
||||
25-Apr-03 RMS Added extended file support
|
||||
22-Dec-02 RMS Added break support
|
||||
01-Nov-02 RMS Revised BOOT command for IBL ROMs
|
||||
Fixed bug in TTY reset, TTY starts in input mode
|
||||
Fixed bug in TTY mode OTA, stores data as well
|
||||
Fixed clock to add calibration, proper start/stop
|
||||
Added UC option to TTY output
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
22-Mar-02 RMS Revised for dynamically allocated memory
|
||||
03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
24-Nov-01 RMS Changed TIME to an array
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
21-Nov-00 RMS Fixed flag, buffer power up state
|
||||
Added status input for ptp, tty
|
||||
15-Oct-00 RMS Added dynamic device number support
|
||||
|
||||
The reader and punch, like most HP devices, have a command flop. The
|
||||
teleprinter and clock do not.
|
||||
|
||||
The clock autocalibrates. If the specified clock frequency is below
|
||||
10Hz, the clock service routine runs at 10Hz and counts down a repeat
|
||||
counter before generating an interrupt. Autocalibration will not work
|
||||
if the clock is running at 1Hz or less.
|
||||
|
||||
Clock diagnostic mode corresponds to inserting jumper W2 on the 12539C.
|
||||
This turns off autocalibration and divides the longest time intervals down
|
||||
by 10**3. The clk_time values were chosen to allow the diagnostic to
|
||||
pass its clock calibration test.
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include <ctype.h>
|
||||
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
|
||||
#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */
|
||||
#define UNIT_V_DIAG (UNIT_V_UF + 2) /* diag mode */
|
||||
#define UNIT_8B (1 << UNIT_V_8B)
|
||||
#define UNIT_UC (1 << UNIT_V_UC)
|
||||
#define UNIT_DIAG (1 << UNIT_V_DIAG)
|
||||
|
||||
#define PTP_LOW 0000040 /* low tape */
|
||||
#define TM_MODE 0100000 /* mode change */
|
||||
#define TM_KBD 0040000 /* enable keyboard */
|
||||
#define TM_PRI 0020000 /* enable printer */
|
||||
#define TM_PUN 0010000 /* enable punch */
|
||||
#define TP_BUSY 0100000 /* busy */
|
||||
|
||||
#define CLK_V_ERROR 4 /* clock overrun */
|
||||
#define CLK_ERROR (1 << CLK_V_ERROR)
|
||||
|
||||
extern uint16 *M;
|
||||
extern uint32 PC, SR;
|
||||
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
|
||||
int32 ttp_stopioe = 0;
|
||||
int32 tty_buf = 0, tty_mode = 0; /* tty buffer, mode */
|
||||
int32 clk_select = 0; /* clock time select */
|
||||
int32 clk_error = 0; /* clock error */
|
||||
int32 clk_ctr = 0; /* clock counter */
|
||||
int32 clk_time[8] = /* clock intervals */
|
||||
{ 155, 1550, 15500, 155000, 155000, 155000, 155000, 155000 };
|
||||
int32 clk_tps[8] = /* clock tps */
|
||||
{ 10000, 1000, 100, 10, 10, 10, 10, 10 };
|
||||
int32 clk_rpt[8] = /* number of repeats */
|
||||
{ 1, 1, 1, 1, 10, 100, 1000, 10000 };
|
||||
|
||||
DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev;
|
||||
int32 ptrio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
|
||||
int32 ptpio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
int32 ttyio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat tty_reset (DEVICE *dptr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
int32 clkio (int32 inst, int32 IR, int32 dat);
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
int32 clk_delay (int32 flg);
|
||||
|
||||
/* PTR data structures
|
||||
|
||||
ptr_dev PTR device descriptor
|
||||
ptr_unit PTR unit descriptor
|
||||
ptr_mod PTR modifiers
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
DIB ptr_dib = { PTR, 0, 0, 0, 0, &ptrio };
|
||||
|
||||
UNIT ptr_unit = {
|
||||
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
|
||||
SERIAL_IN_WAIT };
|
||||
|
||||
REG ptr_reg[] = {
|
||||
{ ORDATA (BUF, ptr_unit.buf, 8) },
|
||||
{ FLDATA (CMD, ptr_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, ptr_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, ptr_dib.flg, 0) },
|
||||
{ FLDATA (FBF, ptr_dib.fbf, 0) },
|
||||
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ptr_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &ptr_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, ptr_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
&ptr_boot, NULL, NULL,
|
||||
&ptr_dib, DEV_DISABLE };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
ptp_dev PTP device descriptor
|
||||
ptp_unit PTP unit descriptor
|
||||
ptp_mod PTP modifiers
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
DIB ptp_dib = { PTP, 0, 0, 0, 0, &ptpio };
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ ORDATA (BUF, ptp_unit.buf, 8) },
|
||||
{ FLDATA (CMD, ptp_dib.cmd, 0) },
|
||||
{ FLDATA (CTL, ptp_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, ptp_dib.flg, 0) },
|
||||
{ FLDATA (FBF, ptp_dib.fbf, 0) },
|
||||
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ptp_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &ptp_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, ptp_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL,
|
||||
&ptp_dib, DEV_DISABLE };
|
||||
|
||||
/* TTY data structures
|
||||
|
||||
tty_dev TTY device descriptor
|
||||
tty_unit TTY unit descriptor
|
||||
tty_reg TTY register list
|
||||
tty_mod TTy modifiers list
|
||||
*/
|
||||
|
||||
#define TTI 0
|
||||
#define TTO 1
|
||||
#define TTP 2
|
||||
|
||||
DIB tty_dib = { TTY, 0, 0, 0, 0, &ttyio };
|
||||
|
||||
UNIT tty_unit[] = {
|
||||
{ UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT },
|
||||
{ UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
|
||||
{ UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_8B, 0), SERIAL_OUT_WAIT } };
|
||||
|
||||
REG tty_reg[] = {
|
||||
{ ORDATA (BUF, tty_buf, 8) },
|
||||
{ ORDATA (MODE, tty_mode, 16) },
|
||||
{ FLDATA (CMD, tty_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, tty_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, tty_dib.flg, 0) },
|
||||
{ FLDATA (FBF, tty_dib.fbf, 0) },
|
||||
{ DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ttp_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tty_mod[] = {
|
||||
{ UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", &tty_set_mode },
|
||||
{ UNIT_UC+UNIT_8B, 0 , "7b", "7B", &tty_set_mode },
|
||||
{ UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", &tty_set_mode },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &tty_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tty_dev = {
|
||||
"TTY", tty_unit, tty_reg, tty_mod,
|
||||
3, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tty_reset,
|
||||
NULL, NULL, NULL,
|
||||
&tty_dib, 0 };
|
||||
|
||||
/* CLK data structures
|
||||
|
||||
clk_dev CLK device descriptor
|
||||
clk_unit CLK unit descriptor
|
||||
clk_mod CLK modifiers
|
||||
clk_reg CLK register list
|
||||
*/
|
||||
|
||||
DIB clk_dib = { CLK, 0, 0, 0, 0, &clkio };
|
||||
|
||||
UNIT clk_unit = {
|
||||
UDATA (&clk_svc, 0, 0) };
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ ORDATA (SEL, clk_select, 3) },
|
||||
{ DRDATA (CTR, clk_ctr, 14) },
|
||||
{ FLDATA (CMD, clk_dib.cmd, 0), REG_HRO },
|
||||
{ FLDATA (CTL, clk_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, clk_dib.flg, 0) },
|
||||
{ FLDATA (FBF, clk_dib.fbf, 0) },
|
||||
{ FLDATA (ERR, clk_error, CLK_V_ERROR) },
|
||||
{ BRDATA (TIME, clk_time, 10, 24, 8) },
|
||||
{ ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB clk_mod[] = {
|
||||
{ UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },
|
||||
{ UNIT_DIAG, 0, "calibrated", "CALIBRATED", NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &clk_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE clk_dev = {
|
||||
"CLK", &clk_unit, clk_reg, clk_mod,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &clk_reset,
|
||||
NULL, NULL, NULL,
|
||||
&clk_dib, 0 };
|
||||
|
||||
/* Paper tape reader: IOT routine */
|
||||
|
||||
int32 ptrio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | ptr_unit.buf;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = ptr_unit.buf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCMD (dev); /* clear cmd, ctl */
|
||||
clrCTL (dev); }
|
||||
else { /* STC */
|
||||
setCMD (dev); /* set cmd, ctl */
|
||||
setCTL (dev);
|
||||
sim_activate (&ptr_unit, ptr_unit.wait); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ptr_svc (UNIT *uptr)
|
||||
{
|
||||
int32 dev, temp;
|
||||
|
||||
dev = ptr_dib.devno; /* get device no */
|
||||
clrCMD (dev); /* clear cmd */
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ptr_stopioe, SCPE_UNATT);
|
||||
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */
|
||||
if (feof (ptr_unit.fileref)) {
|
||||
if (ptr_stopioe) printf ("PTR end of file\n");
|
||||
else return SCPE_OK; }
|
||||
else perror ("PTR I/O error");
|
||||
clearerr (ptr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
setFLG (dev); /* set flag */
|
||||
ptr_unit.buf = temp & 0377; /* put byte in buf */
|
||||
ptr_unit.pos = ftell (ptr_unit.fileref);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine - called from SCP, flags in DIB's */
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
ptr_dib.cmd = ptr_dib.ctl = 0; /* clear cmd, ctl */
|
||||
ptr_dib.flg = ptr_dib.fbf = 1; /* set flg, fbf */
|
||||
ptr_unit.buf = 0;
|
||||
sim_cancel (&ptr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape reader bootstrap routine (HP 12992K ROM) */
|
||||
|
||||
#define LDR_BASE 077
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
|
||||
static const int32 pboot[IBL_LNT] = {
|
||||
0107700, /*ST CLC 0,C ; intr off */
|
||||
0002401, /* CLA,RSS ; skip in */
|
||||
0063756, /*CN LDA M11 ; feed frame */
|
||||
0006700, /* CLB,CCE ; set E to rd byte */
|
||||
0017742, /* JSB READ ; get #char */
|
||||
0007306, /* CMB,CCE,INB,SZB ; 2's comp */
|
||||
0027713, /* JMP *+5 ; non-zero byte */
|
||||
0002006, /* INA,SZA ; feed frame ctr */
|
||||
0027703, /* JMP *-3 */
|
||||
0102077, /* HLT 77B ; stop */
|
||||
0027700, /* JMP ST ; next */
|
||||
0077754, /* STA WC ; word in rec */
|
||||
0017742, /* JSB READ ; get feed frame */
|
||||
0017742, /* JSB READ ; get address */
|
||||
0074000, /* STB 0 ; init csum */
|
||||
0077755, /* STB AD ; save addr */
|
||||
0067755, /*CK LDB AD ; check addr */
|
||||
0047777, /* ADB MAXAD ; below loader */
|
||||
0002040, /* SEZ ; E =0 => OK */
|
||||
0027740, /* JMP H55 */
|
||||
0017742, /* JSB READ ; get word */
|
||||
0040001, /* ADA 1 ; cont checksum */
|
||||
0177755, /* STA AD,I ; store word */
|
||||
0037755, /* ISZ AD */
|
||||
0000040, /* CLE ; force wd read */
|
||||
0037754, /* ISZ WC ; block done? */
|
||||
0027720, /* JMP CK ; no */
|
||||
0017742, /* JSB READ ; get checksum */
|
||||
0054000, /* CPB 0 ; ok? */
|
||||
0027702, /* JMP CN ; next block */
|
||||
0102011, /* HLT 11 ; bad csum */
|
||||
0027700, /* JMP ST ; next */
|
||||
0102055, /*H55 HALT 55 ; bad address */
|
||||
0027700, /* JMP ST ; next */
|
||||
0000000, /*RD 0 */
|
||||
0006600, /* CLB,CME ; E reg byte ptr */
|
||||
0103700+CHANGE_DEV, /* STC RDR,C ; start reader */
|
||||
0102300+CHANGE_DEV, /* SFS RDR ; wait */
|
||||
0027745, /* JMP *-1 */
|
||||
0106400+CHANGE_DEV, /* MIB RDR ; get byte */
|
||||
0002041, /* SEZ,RSS ; E set? */
|
||||
0127742, /* JMP RD,I ; no, done */
|
||||
0005767, /* BLF,CLE,BLF ; shift byte */
|
||||
0027744, /* JMP RD+2 ; again */
|
||||
0000000, /*WC 000000 ; word count */
|
||||
0000000, /*AD 000000 ; address */
|
||||
0177765, /*M11 -11 ; feed count */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* unused */
|
||||
0, 0, 0, 0, 0, 0, 0, /* unused */
|
||||
0000000 }; /*MAXAD -ST ; max addr */
|
||||
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, dev;
|
||||
|
||||
dev = ptr_dib.devno; /* get device no */
|
||||
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */
|
||||
SR = IBL_PTR + (dev << IBL_V_DEV); /* set SR */
|
||||
for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */
|
||||
if (pboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (pboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = pboot[i]; }
|
||||
M[PC + LDR_BASE] = (~PC + 1) & DMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape punch: IOT routine */
|
||||
|
||||
int32 ptpio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0)
|
||||
dat = dat | PTP_LOW; /* out of tape? */
|
||||
break;
|
||||
case ioOTX: /* output */
|
||||
ptp_unit.buf = dat;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCMD (dev); /* clear cmd, ctl */
|
||||
clrCTL (dev); }
|
||||
else { /* STC */
|
||||
setCMD (dev); /* set cmd, ctl */
|
||||
setCTL (dev);
|
||||
sim_activate (&ptp_unit, ptp_unit.wait); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat ptp_svc (UNIT *uptr)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = ptp_dib.devno; /* get device no */
|
||||
clrCMD (dev); /* clear cmd */
|
||||
setFLG (dev); /* set flag */
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ptp_stopioe, SCPE_UNATT);
|
||||
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */
|
||||
perror ("PTP I/O error");
|
||||
clearerr (ptp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
ptp_unit.pos = ftell (ptp_unit.fileref); /* update position */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
ptp_dib.cmd = ptp_dib.ctl = 0; /* clear cmd, ctl */
|
||||
ptp_dib.flg = ptp_dib.fbf = 1; /* set flg, fbf */
|
||||
ptp_unit.buf = 0;
|
||||
sim_cancel (&ptp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Terminal: IOT routine */
|
||||
|
||||
int32 ttyio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | tty_buf;
|
||||
if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO]))
|
||||
dat = dat | TP_BUSY;
|
||||
break;
|
||||
case ioOTX: /* output */
|
||||
if (dat & TM_MODE) tty_mode = dat & (TM_KBD|TM_PRI|TM_PUN);
|
||||
tty_buf = dat & 0377;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
|
||||
else { /* STC */
|
||||
setCTL (dev);
|
||||
if (!(tty_mode & TM_KBD)) /* output? */
|
||||
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service routines */
|
||||
|
||||
t_stat tto_out (int32 c)
|
||||
{
|
||||
t_stat ret = SCPE_OK;
|
||||
|
||||
if (tty_mode & TM_PRI) { /* printing? */
|
||||
if (tty_unit[TTO].flags & UNIT_UC) { /* UC only? */
|
||||
c = c & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = c & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177);
|
||||
ret = sim_putchar (c); /* output char */
|
||||
tty_unit[TTO].pos = tty_unit[TTO].pos + 1; }
|
||||
if (tty_mode & TM_PUN) { /* punching? */
|
||||
if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (ttp_stopioe, SCPE_UNATT);
|
||||
if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */
|
||||
perror ("TTP I/O error");
|
||||
clearerr (tty_unit[TTP].fileref);
|
||||
return SCPE_IOERR; }
|
||||
tty_unit[TTP].pos = ftell (tty_unit[TTP].fileref); }
|
||||
return ret;
|
||||
}
|
||||
|
||||
t_stat tti_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c, dev;
|
||||
|
||||
dev = tty_dib.devno; /* get device no */
|
||||
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
|
||||
if (c & SCPE_BREAK) c = 0; /* break? */
|
||||
else if (tty_unit[TTI].flags & UNIT_UC) { /* UC only? */
|
||||
c = c & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177);
|
||||
if (tty_mode & TM_KBD) { /* keyboard enabled? */
|
||||
tty_buf = c; /* put char in buf */
|
||||
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
|
||||
setFLG (dev); /* set flag */
|
||||
if (c) return tto_out (c); } /* echo or punch? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c, dev;
|
||||
|
||||
dev = tty_dib.devno; /* get device no */
|
||||
setFLG (dev); /* set done flag */
|
||||
c = tty_buf;
|
||||
tty_buf = 0377; /* defang buf */
|
||||
return tto_out (c); /* print and/or punch */
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tty_reset (DEVICE *dptr)
|
||||
{
|
||||
tty_dib.cmd = tty_dib.ctl = 0; /* clear cmd, ctl */
|
||||
tty_dib.flg = tty_dib.fbf = 1; /* set flg, fbf */
|
||||
tty_mode = TM_KBD; /* enable input */
|
||||
tty_buf = 0;
|
||||
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */
|
||||
sim_cancel (&tty_unit[TTO]); /* cancel output */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 u = uptr - tty_dev.units;
|
||||
|
||||
if (u > 1) return SCPE_NOFNC;
|
||||
tty_unit[TTI].flags = (tty_unit[TTI].flags & ~(UNIT_UC | UNIT_8B)) | val;
|
||||
tty_unit[TTO].flags = (tty_unit[TTO].flags & ~(UNIT_UC | UNIT_8B)) | val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Clock: IOT routine */
|
||||
|
||||
int32 clkio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | clk_error;
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = clk_error;
|
||||
break;
|
||||
case ioOTX: /* output */
|
||||
clk_select = dat & 07; /* save select */
|
||||
sim_cancel (&clk_unit); /* stop the clock */
|
||||
clrCTL (dev); /* clear control */
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCTL (dev); /* turn off clock */
|
||||
sim_cancel (&clk_unit); } /* deactivate unit */
|
||||
else { /* STC */
|
||||
setCTL (dev); /* set CTL */
|
||||
if (!sim_is_active (&clk_unit)) { /* clock running? */
|
||||
sim_activate (&clk_unit,
|
||||
sim_rtc_init (clk_delay (0))); /* no, start clock */
|
||||
clk_ctr = clk_delay (1); } /* set repeat ctr */
|
||||
clk_error = 0; } /* clear error */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service */
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
int32 tim, dev;
|
||||
|
||||
dev = clk_dib.devno; /* get device no */
|
||||
if (!CTL (dev)) return SCPE_OK; /* CTL off? done */
|
||||
if (clk_unit.flags & UNIT_DIAG) /* diag mode? */
|
||||
tim = clk_delay (0); /* get fixed delay */
|
||||
else tim = sim_rtc_calb (clk_tps[clk_select]); /* calibrate delay */
|
||||
sim_activate (uptr, tim); /* reactivate */
|
||||
clk_ctr = clk_ctr - 1; /* decrement counter */
|
||||
if (clk_ctr <= 0) { /* end of interval? */
|
||||
tim = FLG (dev);
|
||||
if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? error */
|
||||
else { setFLG (dev); } /* else set flag */
|
||||
clk_ctr = clk_delay (1); } /* reset counter */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
clk_dib.cmd = clk_dib.ctl = 0; /* clear cmd, ctl */
|
||||
clk_dib.flg = clk_dib.fbf = 1; /* set flg, fbf */
|
||||
clk_error = 0; /* clear error */
|
||||
clk_select = 0; /* clear select */
|
||||
clk_ctr = 0; /* clear counter */
|
||||
sim_cancel (&clk_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Clock delay routine */
|
||||
|
||||
int32 clk_delay (int32 flg)
|
||||
{
|
||||
int32 sel = clk_select;
|
||||
|
||||
if ((clk_unit.flags & UNIT_DIAG) && (sel >= 4)) sel = sel - 3;
|
||||
if (flg) return clk_rpt[sel];
|
||||
else return clk_time[sel];
|
||||
}
|
||||
@@ -1,580 +0,0 @@
|
||||
/* hp2100_sys.c: HP 2100 simulator interface
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
22-Mar-02 RMS Revised for dynamically allocated memory
|
||||
14-Feb-02 RMS Added DMS instructions
|
||||
04-Feb-02 RMS Fixed bugs in alter/skip display and parsing
|
||||
01-Feb-02 RMS Added terminal multiplexor support
|
||||
16-Jan-02 RMS Added additional device support
|
||||
17-Sep-01 RMS Removed multiconsole support
|
||||
27-May-01 RMS Added multiconsole support
|
||||
14-Mar-01 RMS Revised load/dump interface (again)
|
||||
30-Oct-00 RMS Added examine to file support
|
||||
15-Oct-00 RMS Added dynamic device number support
|
||||
27-Oct-98 RMS V2.4 load interface
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern DEVICE dma0_dev, dma1_dev;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE tty_dev, clk_dev;
|
||||
extern DEVICE lps_dev, lpt_dev;
|
||||
extern DEVICE mtd_dev, mtc_dev;
|
||||
extern DEVICE msd_dev, msc_dev;
|
||||
extern DEVICE dpd_dev, dpc_dev;
|
||||
extern DEVICE dqd_dev, dqc_dev;
|
||||
extern DEVICE drd_dev, drc_dev;
|
||||
extern DEVICE muxl_dev, muxu_dev, muxc_dev;
|
||||
extern DEVICE ipli_dev, iplo_dev;
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 *M;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "HP 2100";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 3;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&dma0_dev,
|
||||
&dma1_dev,
|
||||
&ptr_dev,
|
||||
&ptp_dev,
|
||||
&tty_dev,
|
||||
&clk_dev,
|
||||
&lps_dev,
|
||||
&lpt_dev,
|
||||
&dpd_dev, &dpc_dev,
|
||||
&dqd_dev, &dqc_dev,
|
||||
&drd_dev, &drc_dev,
|
||||
&mtd_dev, &mtc_dev,
|
||||
&msd_dev, &msc_dev,
|
||||
&muxl_dev, &muxu_dev, &muxc_dev,
|
||||
&ipli_dev, &iplo_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented instruction",
|
||||
"Non-existent I/O device",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Indirect address loop",
|
||||
"Indirect address interrupt (should not happen!)",
|
||||
"No connection on interprocessor link" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
The binary loader consists of blocks preceded and trailed by zero frames.
|
||||
A block consists of 16b words (punched big endian), as follows:
|
||||
|
||||
count'xxx
|
||||
origin
|
||||
word 0
|
||||
:
|
||||
word count-1
|
||||
checksum
|
||||
|
||||
The checksum includes the origin but not the count.
|
||||
*/
|
||||
|
||||
int32 fgetw (FILE *fileref)
|
||||
{
|
||||
int c1, c2;
|
||||
|
||||
if ((c1 = fgetc (fileref)) == EOF) return -1;
|
||||
if ((c2 = fgetc (fileref)) == EOF) return -1;
|
||||
return ((c1 & 0377) << 8) | (c2 & 0377);
|
||||
}
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 origin, csum, zerocnt, count, word, i;
|
||||
|
||||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||||
for (zerocnt = 1;; zerocnt = -10) { /* block loop */
|
||||
for (;; zerocnt++) { /* skip 0's */
|
||||
if ((count = fgetc (fileref)) == EOF) return SCPE_OK;
|
||||
else if (count) break;
|
||||
else if (zerocnt == 0) return SCPE_OK; }
|
||||
if (fgetc (fileref) == EOF) return SCPE_FMT;
|
||||
if ((origin = fgetw (fileref)) < 0) return SCPE_FMT;
|
||||
csum = origin; /* seed checksum */
|
||||
for (i = 0; i < count; i++) { /* get data words */
|
||||
if ((word = fgetw (fileref)) < 0) return SCPE_FMT;
|
||||
if (MEM_ADDR_OK (origin)) M[origin] = word;
|
||||
origin = origin + 1;
|
||||
csum = csum + word; }
|
||||
if ((word = fgetw (fileref)) < 0) return SCPE_FMT;
|
||||
if ((word ^ csum) & DMASK) return SCPE_CSUM; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
|
||||
#define I_V_FL 16 /* flag start */
|
||||
#define I_M_FL 017 /* flag mask */
|
||||
#define I_V_NPN 0 /* no operand */
|
||||
#define I_V_NPC 1 /* no operand + C */
|
||||
#define I_V_MRF 2 /* mem ref */
|
||||
#define I_V_ASH 3 /* alter/skip, shift */
|
||||
#define I_V_ESH 4 /* extended shift */
|
||||
#define I_V_EMR 5 /* extended mem ref */
|
||||
#define I_V_IO1 6 /* I/O + HC */
|
||||
#define I_V_IO2 7 /* I/O only */
|
||||
#define I_V_EGZ 010 /* ext grp, 1 op + 0 */
|
||||
#define I_V_EG2 011 /* ext grp, 2 op */
|
||||
#define I_NPN (I_V_NPN << I_V_FL)
|
||||
#define I_NPC (I_V_NPC << I_V_FL)
|
||||
#define I_MRF (I_V_MRF << I_V_FL)
|
||||
#define I_ASH (I_V_ASH << I_V_FL)
|
||||
#define I_ESH (I_V_ESH << I_V_FL)
|
||||
#define I_EMR (I_V_EMR << I_V_FL)
|
||||
#define I_IO1 (I_V_IO1 << I_V_FL)
|
||||
#define I_IO2 (I_V_IO2 << I_V_FL)
|
||||
#define I_EGZ (I_V_EGZ << I_V_FL)
|
||||
#define I_EG2 (I_V_EG2 << I_V_FL)
|
||||
|
||||
static const int32 masks[] = {
|
||||
0177777, 0176777, 0074000, 0170000,
|
||||
0177760, 0177777, 0176700, 0177700,
|
||||
0177777, 0177777 };
|
||||
|
||||
static const char *opcode[] = {
|
||||
"NOP", "NOP", "AND", "JSB",
|
||||
"XOR", "JMP", "IOR", "ISZ",
|
||||
"ADA", "ADB" ,"CPA", "CPB",
|
||||
"LDA", "LDB", "STA", "STB",
|
||||
"DIAG", "ASL", "LSL", "TIMER",
|
||||
"RRL", "ASR", "LSR", "RRR",
|
||||
"MPY", "DIV", "DLD", "DST",
|
||||
"FAD", "FSB", "FMP", "FDV",
|
||||
"FIX", "FLT",
|
||||
"STO", "CLO", "SOC", "SOS",
|
||||
"HLT", "STF", "CLF",
|
||||
"SFC", "SFS", "MIA", "MIB",
|
||||
"LIA", "LIB", "OTA", "OTB",
|
||||
"STC", "CLC",
|
||||
"SYA", "USA", "PAA", "PBA",
|
||||
"XMA",
|
||||
"XLA", "XSA", "XCA", "LFA",
|
||||
"RSA", "RVA",
|
||||
"MBI", "MBF",
|
||||
"MBW", "MWI", "MWF", "MWW",
|
||||
"SYB", "USB", "PAB", "PBB",
|
||||
"SSM", "JRS",
|
||||
"XMM", "XMS", "XMB",
|
||||
"XLB", "XSB", "XCB", "LFB",
|
||||
"RSB", "RVB", "DJP", "DJS",
|
||||
"SJP", "SJS", "UJP", "UJS",
|
||||
"SAX", "SBX", "CAX", "CBX",
|
||||
"LAX", "LBX", "STX",
|
||||
"CXA", "CXB", "LDX",
|
||||
"ADX", "XAX", "XBX",
|
||||
"SAY", "SBY", "CAY", "CBY",
|
||||
"LAY", "LBY", "STY",
|
||||
"CYA", "CYB", "LDY",
|
||||
"ADY", "XAY", "XBY",
|
||||
"ISX", "DSX", "JLY", "LBT",
|
||||
"SBT", "MBT", "CBT", "SBT",
|
||||
"ISY", "DSY", "JPY", "SBS",
|
||||
"CBS", "TBS", "CMW", "MVW",
|
||||
NULL, /* decode only */
|
||||
NULL };
|
||||
|
||||
static const int32 opc_val[] = {
|
||||
0000000+I_NPN, 0002000+I_NPN, 0010000+I_MRF, 0014000+I_MRF,
|
||||
0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF,
|
||||
0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF,
|
||||
0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF,
|
||||
0100000+I_NPN, 0100020+I_ESH, 0100040+I_ESH, 0100060+I_NPN,
|
||||
0100100+I_ESH, 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH,
|
||||
0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR,
|
||||
0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR,
|
||||
0105100+I_NPN, 0105120+I_NPN,
|
||||
0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC,
|
||||
0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2,
|
||||
0102200+I_IO2, 0102300+I_IO2, 0102400+I_IO1, 0106400+I_IO1,
|
||||
0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1,
|
||||
0102700+I_IO1, 0106700+I_IO1,
|
||||
0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN,
|
||||
0101722+I_NPN,
|
||||
0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN,
|
||||
0101730+I_NPN, 0101731+I_NPN,
|
||||
0105702+I_NPN, 0105703+I_NPN,
|
||||
0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN,
|
||||
0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN,
|
||||
0105714+I_EMR, 0105715+I_EG2,
|
||||
0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN,
|
||||
0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN,
|
||||
0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR,
|
||||
0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR,
|
||||
0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN,
|
||||
0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR,
|
||||
0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR,
|
||||
0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN,
|
||||
0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN,
|
||||
0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR,
|
||||
0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR,
|
||||
0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN,
|
||||
0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN,
|
||||
0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN,
|
||||
0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2,
|
||||
0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ,
|
||||
0000000+I_ASH, /* decode only */
|
||||
-1 };
|
||||
|
||||
/* Decode tables for shift and alter/skip groups */
|
||||
|
||||
static const char *stab[] = {
|
||||
"ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF",
|
||||
"BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF",
|
||||
"CLA", "CMA", "CCA", "CLB", "CMB", "CCB",
|
||||
"SEZ", "CLE", "CLE", "CME", "CCE",
|
||||
"SSA", "SSB", "SLA", "SLB",
|
||||
"ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF",
|
||||
"BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF",
|
||||
"INA", "INB", "SZA", "SZB", "RSS",
|
||||
NULL };
|
||||
|
||||
static const int32 mtab[] = {
|
||||
0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
|
||||
0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
|
||||
0006400, 0007000, 0007400, 0006400, 0007000, 0007400,
|
||||
0002040, 0002040, 0002100, 0002200, 0002300,
|
||||
0006020, 0006020, 0004010, 0004010,
|
||||
0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
|
||||
0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
|
||||
0006004, 0006004, 0006002, 0006002, 0002001,
|
||||
0 };
|
||||
|
||||
static const int32 vtab[] = {
|
||||
0001000, 0001100, 0001200, 0001300, 0001400, 0001500, 0001600, 0001700,
|
||||
0005000, 0005100, 0005200, 0005300, 0005400, 0005500, 0005600, 0005700,
|
||||
0002400, 0003000, 0003400, 0006400, 0007000, 0007400,
|
||||
0002040, 0000040, 0002100, 0002200, 0002300,
|
||||
0002020, 0006020, 0000010, 0004010,
|
||||
0000020, 0000021, 0000022, 0000023, 0000024, 0000025, 0000026, 0000027,
|
||||
0004020, 0004021, 0004022, 0004023, 0004024, 0004025, 0004026, 0004027,
|
||||
0002004, 0006004, 0002002, 0006002, 0002001,
|
||||
-1 };
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to data
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = status code
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 cflag, cm, i, j, inst, disp;
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
inst = val[0];
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
if (inst > 0377) return SCPE_ARG;
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('C')) { /* characters? */
|
||||
fprintf (of, FMTASC ((inst >> 8) & 0177));
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
|
||||
/* Instruction decode */
|
||||
|
||||
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case I_V_NPN: /* no operands */
|
||||
fprintf (of, "%s", opcode[i]); /* opcode */
|
||||
break;
|
||||
case I_V_NPC: /* no operands + C */
|
||||
fprintf (of, "%s", opcode[i]);
|
||||
if (inst & I_HC) fprintf (of, " C");
|
||||
break;
|
||||
case I_V_MRF: /* mem ref */
|
||||
disp = inst & I_DISP; /* displacement */
|
||||
fprintf (of, "%s ", opcode[i]); /* opcode */
|
||||
if (inst & I_CP) { /* current page? */
|
||||
if (cflag) fprintf (of, "%-o", (addr & I_PAGENO) | disp);
|
||||
else fprintf (of, "C %-o", disp); }
|
||||
else fprintf (of, "%-o", disp); /* page zero */
|
||||
if (inst & I_IA) fprintf (of, ",I");
|
||||
break;
|
||||
case I_V_ASH: /* shift, alter-skip */
|
||||
cm = FALSE;
|
||||
for (i = 0; mtab[i] != 0; i++) {
|
||||
if ((inst & mtab[i]) == vtab[i]) {
|
||||
inst = inst & ~(vtab[i] & 01777);
|
||||
if (cm) fprintf (of, ",");
|
||||
cm = TRUE;
|
||||
fprintf (of, "%s", stab[i]); } }
|
||||
if (!cm) return SCPE_ARG; /* nothing decoded? */
|
||||
break;
|
||||
case I_V_ESH: /* extended shift */
|
||||
disp = inst & 017; /* shift count */
|
||||
if (disp == 0) disp = 16;
|
||||
fprintf (of, "%s %d", opcode[i], disp);
|
||||
break;
|
||||
case I_V_EMR: /* extended mem ref */
|
||||
fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
|
||||
if (val[1] & I_IA) fprintf (of, ",I");
|
||||
return -1; /* extra word */
|
||||
case I_V_IO1: /* IOT with H/C */
|
||||
fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK);
|
||||
if (inst & I_HC) fprintf (of, ",C");
|
||||
break;
|
||||
case I_V_IO2: /* IOT */
|
||||
fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK);
|
||||
break;
|
||||
case I_V_EGZ: /* ext grp 1 op + 0 */
|
||||
fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
|
||||
if (val[1] & I_IA) fprintf (of, ",I");
|
||||
return -2; /* extra words */
|
||||
case I_V_EG2: /* ext grp 2 op */
|
||||
fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
|
||||
if (val[1] & I_IA) fprintf (of, ",I");
|
||||
fprintf (of, " %-o", val[2] & VAMASK);
|
||||
if (val[2] & I_IA) fprintf (of, ",I");
|
||||
return -2; } /* extra words */
|
||||
return SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Get address with indirection
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
Outputs:
|
||||
val = address
|
||||
-1 if error
|
||||
*/
|
||||
|
||||
int32 get_addr (char *cptr)
|
||||
{
|
||||
int32 d;
|
||||
t_stat r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
|
||||
d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */
|
||||
if (r != SCPE_OK) return -1;
|
||||
if (*cptr != 0) { /* more? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */
|
||||
if (*cptr != 0) return -1; /* should be done */
|
||||
if (strcmp (gbuf, "I")) return -1; /* I? */
|
||||
d = d | I_IA; }
|
||||
return d;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*iptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *iptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 cflag, d, i, j, k, clef, tbits;
|
||||
t_stat r, ret;
|
||||
char *cptr, gbuf[CBUFSIZE];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
while (isspace (*iptr)) iptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('A')) || ((*iptr == '\'') && iptr++)) { /* ASCII char? */
|
||||
if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (t_value) iptr[0] & 0177;
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('C')) || ((*iptr == '"') && iptr++)) { /* char string? */
|
||||
if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (((t_value) iptr[0] & 0177) << 8) |
|
||||
((t_value) iptr[1] & 0177);
|
||||
return SCPE_OK; }
|
||||
|
||||
/* Instruction parse */
|
||||
|
||||
ret = SCPE_OK;
|
||||
cptr = get_glyph (iptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i]) { /* found opcode? */
|
||||
val[0] = opc_val[i] & DMASK; /* get value */
|
||||
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case I_V_NPN: /* no operand */
|
||||
break;
|
||||
case I_V_NPC: /* no operand + C */
|
||||
if (*cptr != 0) {
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
if (strcmp (gbuf, "C")) return SCPE_ARG;
|
||||
val[0] = val[0] | I_HC; }
|
||||
break;
|
||||
case I_V_MRF: /* mem ref */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
|
||||
if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */
|
||||
val[0] = val[0] | I_CP;
|
||||
cptr = get_glyph (cptr, gbuf, 0); }
|
||||
else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */
|
||||
cptr = get_glyph (cptr, gbuf, ','); }
|
||||
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
|
||||
if ((d & VAMASK) <= I_DISP) val[0] = val[0] | d;
|
||||
else if (cflag && !k && (((addr ^ d) & I_PAGENO) == 0))
|
||||
val[0] = val[0] | (d & (I_IA | I_DISP)) | I_CP;
|
||||
else return SCPE_ARG;
|
||||
break;
|
||||
case I_V_ESH: /* extended shift */
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
d = get_uint (gbuf, 10, 16, &r);
|
||||
if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG;
|
||||
val[0] = val[0] | (d & 017);
|
||||
break;
|
||||
case I_V_EMR: /* extended mem ref */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
|
||||
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
|
||||
val[1] = d;
|
||||
ret = -1;
|
||||
break;
|
||||
case I_V_IO1: /* IOT + optional C */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get device */
|
||||
d = get_uint (gbuf, 8, I_DEVMASK, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | d;
|
||||
if (*cptr != 0) {
|
||||
cptr = get_glyph (cptr, gbuf, 0);
|
||||
if (strcmp (gbuf, "C")) return SCPE_ARG;
|
||||
val[0] = val[0] | I_HC; }
|
||||
break;
|
||||
case I_V_IO2: /* IOT */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get device */
|
||||
d = get_uint (gbuf, 8, I_DEVMASK, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | d;
|
||||
break;
|
||||
case I_V_EGZ: /* ext grp 1 op + 0 */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
|
||||
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
|
||||
val[1] = d;
|
||||
val[2] = 0;
|
||||
ret = -2;
|
||||
break;
|
||||
case I_V_EG2: /* ext grp 2 op */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
|
||||
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
|
||||
if ((k = get_addr (gbuf)) < 0) return SCPE_ARG;
|
||||
val[1] = d;
|
||||
val[2] = k;
|
||||
ret = -2;
|
||||
break; } /* end case */
|
||||
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
|
||||
return ret;
|
||||
} /* end if opcode */
|
||||
|
||||
/* Shift or alter-skip
|
||||
|
||||
Each opcode is matched by a mask, specifiying the bits affected, and
|
||||
the value, specifying the value. As opcodes are processed, the mask
|
||||
values are used to specify which fields have already been filled in.
|
||||
|
||||
The mask has two subfields, the type bits (A/B and A/S), and the field
|
||||
bits. The type bits, once specified by any instruction, must be
|
||||
consistent in all other instructions. The mask bits assure that no
|
||||
field is filled in twice.
|
||||
|
||||
Two special cases:
|
||||
|
||||
1. The dual shift field in shift requires checking how much of the
|
||||
target word has been filled in before assigning the shift value.
|
||||
To implement this, shifts are listed twice is the decode table.
|
||||
If the current subopcode is a shift in the first part of the table
|
||||
(entries 0..15), and CLE has been seen or the first shift field is
|
||||
filled in, the code forces a mismatch. The glyph will match in
|
||||
the second part of the table.
|
||||
|
||||
2. CLE processing must be deferred until the instruction can be
|
||||
classified as shift or alter-skip, since it has two different
|
||||
bit values in the two classes. To implement this, CLE seen is
|
||||
recorded as a flag and processed after all other subopcodes.
|
||||
*/
|
||||
|
||||
clef = FALSE;
|
||||
tbits = 0;
|
||||
val[0] = 0;
|
||||
for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0;
|
||||
cptr = get_glyph (cptr, gbuf, ',')) { /* loop thru glyphs */
|
||||
if (strcmp (gbuf, "CLE") == 0) { /* CLE? */
|
||||
if (clef) return SCPE_ARG; /* already seen? */
|
||||
clef = TRUE; /* set flag */
|
||||
continue; }
|
||||
for (i = 0; stab[i] != NULL; i++) { /* find subopcode */
|
||||
if ((strcmp (gbuf, stab[i]) == 0) &&
|
||||
((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; }
|
||||
if (stab[i] == NULL) return SCPE_ARG;
|
||||
if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0]))
|
||||
return SCPE_ARG;
|
||||
if (tbits & mtab[i] & ~(I_AB | I_ASKP)) return SCPE_ARG;
|
||||
tbits = tbits | mtab[i]; /* fill type+mask */
|
||||
val[0] = val[0] | vtab[i]; } /* fill value */
|
||||
if (clef) { /* CLE seen? */
|
||||
if (val[0] & I_ASKP) { /* alter-skip? */
|
||||
if (tbits & 0100) return SCPE_ARG; /* already filled in? */
|
||||
else val[0] = val[0] | 0100; }
|
||||
else val[0] = val[0] | 040; } /* fill in shift */
|
||||
return ret;
|
||||
}
|
||||
282
I1401/i1401_cd.c
282
I1401/i1401_cd.c
@@ -1,282 +0,0 @@
|
||||
/* i1401_cd.c: IBM 1402 card reader/punch
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
cdr card reader
|
||||
cdp card punch
|
||||
stack stackers (5 units)
|
||||
0 normal
|
||||
1 1
|
||||
2 2/8
|
||||
3 unused
|
||||
4 4
|
||||
|
||||
Cards are represented as ASCII text streams terminated by newlines.
|
||||
This allows cards to be created and edited as normal files.
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
13-Apr-01 RMS Revised for register arrays
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern uint8 M[];
|
||||
extern int32 ind[64], ssa, iochk;
|
||||
extern char bcd_to_ascii[64];
|
||||
extern char ascii_to_bcd[128];
|
||||
int32 s1sel, s2sel, s4sel, s8sel;
|
||||
char rbuf[CBUFSIZE]; /* > CDR_WIDTH */
|
||||
t_stat cdr_svc (UNIT *uptr);
|
||||
t_stat cdr_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat cdr_attach (UNIT *uptr, char *cptr);
|
||||
t_stat cd_reset (DEVICE *dptr);
|
||||
|
||||
/* Card reader data structures
|
||||
|
||||
cdr_dev CDR descriptor
|
||||
cdr_unit CDR unit descriptor
|
||||
cdr_reg CDR register list
|
||||
*/
|
||||
|
||||
UNIT cdr_unit = {
|
||||
UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), 100 };
|
||||
|
||||
REG cdr_reg[] = {
|
||||
{ FLDATA (LAST, ind[IN_LST], 0) },
|
||||
{ FLDATA (ERR, ind[IN_READ], 0) },
|
||||
{ FLDATA (S1, s1sel, 0) },
|
||||
{ FLDATA (S2, s2sel, 0) },
|
||||
{ DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },
|
||||
{ BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE cdr_dev = {
|
||||
"CDR", &cdr_unit, cdr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &cd_reset,
|
||||
&cdr_boot, &cdr_attach, NULL };
|
||||
|
||||
/* CDP data structures
|
||||
|
||||
cdp_dev CDP device descriptor
|
||||
cdp_unit CDP unit descriptor
|
||||
cdp_reg CDP register list
|
||||
*/
|
||||
|
||||
UNIT cdp_unit = {
|
||||
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
|
||||
|
||||
REG cdp_reg[] = {
|
||||
{ FLDATA (ERR, ind[IN_PNCH], 0) },
|
||||
{ FLDATA (S4, s4sel, 0) },
|
||||
{ FLDATA (S8, s8sel, 0) },
|
||||
{ DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE cdp_dev = {
|
||||
"CDP", &cdp_unit, cdp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &cd_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Stacker data structures
|
||||
|
||||
stack_dev STACK device descriptor
|
||||
stack_unit STACK unit descriptors
|
||||
stack_reg STACK register list
|
||||
*/
|
||||
|
||||
UNIT stack_unit[] = {
|
||||
{ UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) },
|
||||
{ UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) },
|
||||
{ UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) },
|
||||
{ UDATA (NULL, UNIT_DIS, 0) }, /* unused */
|
||||
{ UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } };
|
||||
|
||||
REG stack_reg[] = {
|
||||
{ DRDATA (POS0, stack_unit[0].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (POS1, stack_unit[1].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (POS28, stack_unit[2].pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (POS4, stack_unit[4].pos, T_ADDR_W), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE stack_dev = {
|
||||
"STKR", stack_unit, stack_reg, NULL,
|
||||
5, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &cd_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Card read routine
|
||||
|
||||
Modifiers have been checked by the caller
|
||||
No modifiers are recognized (column binary is not implemented)
|
||||
*/
|
||||
|
||||
t_stat read_card (int32 ilnt, int32 mod)
|
||||
{
|
||||
int32 i;
|
||||
t_stat r;
|
||||
|
||||
if (sim_is_active (&cdr_unit)) { /* busy? */
|
||||
sim_cancel (&cdr_unit); /* cancel */
|
||||
if (r = cdr_svc (&cdr_unit)) return r; } /* process */
|
||||
if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
|
||||
ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */
|
||||
for (i = 0; i < CBUFSIZE; i++) rbuf[i] = 0; /* clear buffer */
|
||||
fgets (rbuf, CBUFSIZE, cdr_unit.fileref); /* read card */
|
||||
if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */
|
||||
if (ferror (cdr_unit.fileref)) { /* error? */
|
||||
perror ("Card reader I/O error");
|
||||
clearerr (cdr_unit.fileref);
|
||||
if (iochk) return SCPE_IOERR;
|
||||
ind[IN_READ] = 1;
|
||||
return SCPE_OK; }
|
||||
cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */
|
||||
if (ssa) { /* if last cd on */
|
||||
getc (cdr_unit.fileref); /* see if more */
|
||||
if (feof (cdr_unit.fileref)) ind[IN_LST] = 1; /* eof? set flag */
|
||||
fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); }
|
||||
for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */
|
||||
rbuf[i] = ascii_to_bcd[rbuf[i]];
|
||||
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | rbuf[i]; }
|
||||
M[CDR_BUF - 1] = 060; /* mem mark */
|
||||
sim_activate (&cdr_unit, cdr_unit.wait); /* activate */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Card reader service. If a stacker select is active, copy to the
|
||||
selected stacker. Otherwise, copy to the normal stacker. If the
|
||||
unit is unattached, simply exit.
|
||||
*/
|
||||
|
||||
t_stat cdr_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (s1sel) uptr = &stack_unit[1]; /* stacker 1? */
|
||||
else if (s2sel) uptr = &stack_unit[2]; /* stacker 2? */
|
||||
else uptr = &stack_unit[0]; /* then default */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
for (i = 0; i < CDR_WIDTH; i++) rbuf[i] = bcd_to_ascii[rbuf[i]];
|
||||
for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0;
|
||||
rbuf[CDR_WIDTH] = 0; /* null at end */
|
||||
fputs (rbuf, uptr->fileref); /* write card */
|
||||
fputc ('\n', uptr->fileref); /* plus new line */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
perror ("Card stacker I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
if (iochk) return SCPE_IOERR; }
|
||||
uptr->pos = ftell (uptr->fileref); /* update position */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Card punch routine
|
||||
|
||||
Modifiers have been checked by the caller
|
||||
No modifiers are recognized (column binary is not implemented)
|
||||
*/
|
||||
|
||||
t_stat punch_card (int32 ilnt, int32 mod)
|
||||
{
|
||||
int32 i;
|
||||
static char pbuf[CDP_WIDTH + 1]; /* + null */
|
||||
UNIT *uptr;
|
||||
|
||||
if (s8sel) uptr = &stack_unit[2]; /* stack 8? */
|
||||
else if (s4sel) uptr = &stack_unit[4]; /* stack 4? */
|
||||
else uptr = &cdp_unit; /* normal output */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
|
||||
ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */
|
||||
|
||||
M[CDP_BUF - 1] = 012; /* set prev loc */
|
||||
for (i = 0; i < CDP_WIDTH; i++) pbuf[i] = bcd_to_ascii[M[CDP_BUF + i] & CHAR];
|
||||
for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) pbuf[i] = 0;
|
||||
pbuf[CDP_WIDTH] = 0; /* trailing null */
|
||||
fputs (pbuf, uptr->fileref); /* output card */
|
||||
fputc ('\n', uptr->fileref); /* plus new line */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
perror ("Card punch I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
if (iochk) return SCPE_IOERR;
|
||||
ind[IN_PNCH] = 1; }
|
||||
uptr->pos = ftell (uptr->fileref); /* update position */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Select stack routine
|
||||
|
||||
Modifiers have been checked by the caller
|
||||
Modifiers are 1, 2, 4, 8 for the respective stack
|
||||
*/
|
||||
|
||||
t_stat select_stack (int32 ilnt, int32 mod)
|
||||
{
|
||||
if (mod == 1) s1sel = 1;
|
||||
else if (mod == 2) s2sel = 1;
|
||||
else if (mod == 4) s4sel = 1;
|
||||
else if (mod == 8) s8sel = 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Card reader/punch reset */
|
||||
|
||||
t_stat cd_reset (DEVICE *dptr)
|
||||
{
|
||||
ind[IN_LST] = ind[IN_READ] = ind[IN_PNCH] = 0; /* clear indicators */
|
||||
s1sel = s2sel = s4sel = s8sel = 0; /* clear stacker sel */
|
||||
sim_cancel (&cdr_unit); /* clear reader event */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Card reader attach */
|
||||
|
||||
t_stat cdr_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
ind[IN_LST] = ind[IN_READ] = 0; /* clear last card */
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 0
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char))
|
||||
|
||||
static const unsigned char boot_rom[] = {
|
||||
OP_R + WM, OP_NOP + WM }; /* R, NOP */
|
||||
|
||||
t_stat cdr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_IS;
|
||||
|
||||
for (i = 0; i < CDR_WIDTH; i++) M[CDR_BUF + i] = 0; /* clear buffer */
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_IS = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
1563
I1401/i1401_cpu.c
1563
I1401/i1401_cpu.c
File diff suppressed because it is too large
Load Diff
@@ -1,57 +0,0 @@
|
||||
/* i1401_dat.h: IBM 1401 character conversion tables
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
*/
|
||||
|
||||
/* ASCII to BCD conversion */
|
||||
|
||||
const char ascii_to_bcd[128] = {
|
||||
000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */
|
||||
000, 000, 000, 000, 000, 000, 000, 000,
|
||||
000, 000, 000, 000, 000, 000, 000, 000,
|
||||
000, 000, 000, 000, 000, 000, 000, 000,
|
||||
000, 052, 077, 013, 053, 034, 060, 032, /* 040 - 077 */
|
||||
017, 074, 054, 037, 033, 040, 073, 021,
|
||||
012, 001, 002, 003, 004, 005, 006, 007,
|
||||
010, 011, 015, 056, 076, 035, 016, 072,
|
||||
014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */
|
||||
070, 071, 041, 042, 043, 044, 045, 046,
|
||||
047, 050, 051, 022, 023, 024, 025, 026,
|
||||
027, 030, 031, 075, 036, 055, 020, 057,
|
||||
000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */
|
||||
070, 071, 041, 042, 043, 044, 045, 046,
|
||||
047, 050, 051, 022, 023, 024, 025, 026,
|
||||
027, 030, 031, 000, 000, 000, 000, 000 };
|
||||
|
||||
/* BCD to ASCII conversion - also the "full" print chain */
|
||||
|
||||
char bcd_to_ascii[64] = {
|
||||
' ', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '0', '#', '@', ':', '>', '(',
|
||||
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', '\'', ',', '%', '=', '\\', '+',
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', '!', '$', '*', ']', ';', '_',
|
||||
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', '?', '.', ')', '[', '<', '"' };
|
||||
@@ -1,278 +0,0 @@
|
||||
/* i1401_defs.h: IBM 1401 simulator definitions
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
16-Mar-03 RMS Fixed mnemonic for MCS
|
||||
03-Jun-02 RMS Added 1311 support
|
||||
14-Apr-99 RMS Converted t_addr to unsigned
|
||||
|
||||
This simulator is based on the 1401 simulator written by Len Fehskens
|
||||
with assistance from Sarah Lee Harris and Bob Supnik. This one's for
|
||||
you, Len. I am grateful to Paul Pierce and Charles Owen for their help
|
||||
in answering questions, gathering source material, and debugging.
|
||||
*/
|
||||
|
||||
#include "sim_defs.h"
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_NXI 1 /* unimpl instr */
|
||||
#define STOP_NXM 2 /* non-exist mem */
|
||||
#define STOP_NXD 3 /* non-exist dev */
|
||||
#define STOP_NOWM 4 /* no WM under op */
|
||||
#define STOP_INVA 5 /* invalid A addr */
|
||||
#define STOP_INVB 6 /* invalid B addr */
|
||||
#define STOP_INVL 7 /* invalid length */
|
||||
#define STOP_INVM 8 /* invalid modifier */
|
||||
#define STOP_INVBR 9 /* invalid branch */
|
||||
#define STOP_IBKPT 10 /* breakpoint */
|
||||
#define STOP_HALT 11 /* halt */
|
||||
#define STOP_INVMTU 12 /* invalid MT unit */
|
||||
#define STOP_MTZ 13 /* MT zero lnt rec */
|
||||
#define STOP_MTL 14 /* MT write lock */
|
||||
#define STOP_CCT 15 /* inv CCT channel */
|
||||
#define STOP_NOCD 16 /* no cards left */
|
||||
#define STOP_WRAP 17 /* AS, BS mem wrap */
|
||||
#define STOP_MCE1 18 /* MCE short A field */
|
||||
#define STOP_MCE2 19 /* MCE short B field */
|
||||
#define STOP_MCE3 20 /* MCE hanging $ */
|
||||
#define STOP_IOC 21 /* I/O check */
|
||||
#define STOP_INVDSC 22 /* invalid disk sector */
|
||||
#define STOP_INVDCN 23 /* invalid disk count */
|
||||
#define STOP_INVDSK 24 /* invalid disk unit */
|
||||
#define STOP_INVDFN 25 /* invalid disk func */
|
||||
#define STOP_INVDLN 26 /* invalid disk reclen */
|
||||
#define STOP_WRADIS 27 /* write address dis */
|
||||
#define STOP_WRCHKE 28 /* write check error */
|
||||
#define STOP_INVDAD 39 /* invalid disk addr */
|
||||
#define STOP_INVDCY 30 /* invalid direct seek */
|
||||
|
||||
/* Memory and devices */
|
||||
|
||||
#define MAXMEMSIZE 16000 /* max memory */
|
||||
#define MEMSIZE (cpu_unit.capac) /* current memory */
|
||||
#define CDR_BUF 1 /* card rdr buffer */
|
||||
#define CDR_WIDTH 80 /* card rdr width */
|
||||
#define CDP_BUF 101 /* card punch buffer */
|
||||
#define CDP_WIDTH 80 /* card punch width */
|
||||
#define LPT_BUF 201 /* line print buffer */
|
||||
#define LPT_WIDTH 132 /* line print width */
|
||||
#define CCT_LNT 132 /* car ctrl length */
|
||||
#define INQ_WIDTH 80 /* inq term width */
|
||||
#define ADDR_ERR(x) (((uint32) (x)) >= MEMSIZE)
|
||||
|
||||
/* Binary address format
|
||||
|
||||
<14:0> address, with index added in
|
||||
<23:16> index register memory address
|
||||
<25:24> address error bits
|
||||
*/
|
||||
|
||||
#define ADDRMASK 037777 /* addr mask */
|
||||
#define INDEXMASK 077777 /* addr + index mask */
|
||||
#define V_INDEX 16
|
||||
#define M_INDEX 0177
|
||||
#define V_ADDRERR 24
|
||||
#define BA (1 << V_ADDRERR) /* bad addr digit */
|
||||
#define X1 (87 << V_INDEX) /* index reg 1 */
|
||||
#define X2 (92 << V_INDEX) /* index reg 2 */
|
||||
#define X3 (97 << V_INDEX) /* index reg 3 */
|
||||
|
||||
/* CPU instruction control flags. The flag definitions must be harmonized
|
||||
with the UNIT flag definitions used by the simulator. */
|
||||
|
||||
/* Lengths */
|
||||
|
||||
#define L1 0001 /* 1: op */
|
||||
#define L2 0002 /* 2: op d */
|
||||
#define L4 0004 /* 4: op aaa */
|
||||
#define L5 0010 /* 5: op aaa d */
|
||||
#define L7 0020 /* 7: op aaa bbb */
|
||||
#define L8 0040 /* 8: op aaa bbb d */
|
||||
|
||||
/* CPU options, stored in cpu_unit.flags */
|
||||
|
||||
#define MDV (1 << (UNIT_V_UF + 0)) /* multiply/divide */
|
||||
#define MR (1 << (UNIT_V_UF + 1)) /* move record */
|
||||
#define XSA (1 << (UNIT_V_UF + 2)) /* index, store addr */
|
||||
#define EPE (1 << (UNIT_V_UF + 3)) /* expanded edit */
|
||||
#define MA (1 << (UNIT_V_UF + 4)) /* modify address */
|
||||
#define BBE (1 << (UNIT_V_UF + 5)) /* br bit equal */
|
||||
#define HLE (1 << (UNIT_V_UF + 6)) /* high/low/equal */
|
||||
#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* fake flag */
|
||||
#define ALLOPT (MDV + MR + XSA + EPE + MA + BBE + HLE)
|
||||
#define STDOPT (MDV + MR + XSA + EPE + MA + BBE + HLE)
|
||||
|
||||
/* Fetch control */
|
||||
|
||||
#define AREQ (1 << (UNIT_V_UF + 8)) /* validate A */
|
||||
#define BREQ (1 << (UNIT_V_UF + 9)) /* validate B */
|
||||
#define MLS (1 << (UNIT_V_UF + 10)) /* move load store */
|
||||
#define NOWM (1 << (UNIT_V_UF + 11)) /* no WM at end */
|
||||
#define HNOP (1 << (UNIT_V_UF + 12)) /* halt or nop */
|
||||
#define IO (1 << (UNIT_V_UF + 13)) /* IO */
|
||||
#define UNIT_BCD (1 << (UNIT_V_UF + 14)) /* BCD strings */
|
||||
|
||||
#if (UNIT_V_UF < 6) || ((UNIT_V_UF + 14) > 31)
|
||||
Definition error: flags overlap
|
||||
#endif
|
||||
|
||||
/* BCD memory character format */
|
||||
|
||||
#define WM 0100 /* word mark */
|
||||
#define ZONE 0060 /* zone */
|
||||
#define BBIT 0040 /* 1 in valid sign */
|
||||
#define ABIT 0020 /* sign (1 = +) */
|
||||
#define DIGIT 0017 /* digit */
|
||||
#define CHAR 0077 /* character */
|
||||
|
||||
#define V_WM 6
|
||||
#define V_ZONE 4
|
||||
#define V_DIGIT 0
|
||||
|
||||
/* Interesting BCD characters */
|
||||
|
||||
#define BCD_BLANK 000
|
||||
#define BCD_ONE 001
|
||||
#define BCD_TWO 002
|
||||
#define BCD_THREE 003
|
||||
#define BCD_FOUR 004
|
||||
#define BCD_FIVE 005
|
||||
#define BCD_SIX 006
|
||||
#define BCD_SEVEN 007
|
||||
#define BCD_EIGHT 010
|
||||
#define BCD_NINE 011
|
||||
#define BCD_ZERO 012
|
||||
#define BCD_ALT 020
|
||||
#define BCD_S 022
|
||||
#define BCD_U 024
|
||||
#define BCD_W 026
|
||||
#define BCD_RECMRK 032
|
||||
#define BCD_COMMA 033
|
||||
#define BCD_PERCNT 034
|
||||
#define BCD_WM 035
|
||||
#define BCD_BS 036
|
||||
#define BCD_TS 037
|
||||
#define BCD_MINUS 040
|
||||
#define BCD_M 044
|
||||
#define BCD_R 051
|
||||
#define BCD_DOLLAR 053
|
||||
#define BCD_ASTER 054
|
||||
#define BCD_AMPER 060
|
||||
#define BCD_A 061
|
||||
#define BCD_B 062
|
||||
#define BCD_C 063
|
||||
#define BCD_E 065
|
||||
#define BCD_DECIMAL 073
|
||||
#define BCD_SQUARE 074
|
||||
#define BCD_GRPMRK 077
|
||||
|
||||
/* Opcodes */
|
||||
|
||||
#define OP_R 001 /* read */
|
||||
#define OP_W 002 /* write */
|
||||
#define OP_WR 003 /* write and read */
|
||||
#define OP_P 004 /* punch */
|
||||
#define OP_RP 005 /* read and punch */
|
||||
#define OP_WP 006 /* write and punch */
|
||||
#define OP_WRP 007 /* write read punch */
|
||||
#define OP_RF 010 /* reader feed */
|
||||
#define OP_PF 011 /* punch feed */
|
||||
#define OP_MA 013 /* modify address */
|
||||
#define OP_MUL 014 /* multiply */
|
||||
#define OP_CS 021 /* clear storage */
|
||||
#define OP_S 022 /* subtract */
|
||||
#define OP_MTF 024 /* magtape function */
|
||||
#define OP_BWZ 025 /* branch wm or zone */
|
||||
#define OP_BBE 026 /* branch bit equal */
|
||||
#define OP_MZ 030 /* move zone */
|
||||
#define OP_MCS 031 /* move suppr zeroes */
|
||||
#define OP_SWM 033 /* set word mark */
|
||||
#define OP_DIV 034 /* divide */
|
||||
#define OP_SS 042 /* select stacker */
|
||||
#define OP_LCA 043 /* load characters */
|
||||
#define OP_MCW 044 /* move characters */
|
||||
#define OP_NOP 045 /* no op */
|
||||
#define OP_MCM 047 /* move to rec/grp mk */
|
||||
#define OP_SAR 050 /* store A register */
|
||||
#define OP_ZS 052 /* zero and subtract */
|
||||
#define OP_A 061 /* add */
|
||||
#define OP_B 062 /* branch */
|
||||
#define OP_C 063 /* compare */
|
||||
#define OP_MN 064 /* move numeric */
|
||||
#define OP_MCE 065 /* move char and edit */
|
||||
#define OP_CC 066 /* carriage control */
|
||||
#define OP_SBR 070 /* store B register */
|
||||
#define OP_ZA 072 /* zero and add */
|
||||
#define OP_H 073 /* halt */
|
||||
#define OP_CWM 074 /* clear word mark */
|
||||
|
||||
/* I/O addresses */
|
||||
|
||||
#define IO_INQ 023 /* inquiry terminal */
|
||||
#define IO_MT 024 /* magtape */
|
||||
#define IO_MTB 062 /* binary magtape */
|
||||
#define IO_DP 066 /* 1311 diskpack */
|
||||
|
||||
/* I/O modes */
|
||||
|
||||
#define MD_NORM 0 /* normal (move) */
|
||||
#define MD_WM 1 /* word mark (load) */
|
||||
#define MD_BIN 2 /* binary */
|
||||
|
||||
/* Indicator characters */
|
||||
|
||||
#define IN_UNC 000 /* unconditional */
|
||||
#define IN_CC9 011 /* carr ctrl chan 9 */
|
||||
#define IN_CC12 014 /* carr ctrl chan 12 */
|
||||
#define IN_UNQ 021 /* unequal */
|
||||
#define IN_EQU 022 /* equal */
|
||||
#define IN_LOW 023 /* low */
|
||||
#define IN_HGH 024 /* high */
|
||||
#define IN_DPW 025 /* parity/compare check */
|
||||
#define IN_LNG 026 /* wrong lnt record */
|
||||
#define IN_UNA 027 /* unequal addr cmp */
|
||||
#define IN_DSK 030 /* disk error */
|
||||
#define IN_OVF 031 /* overflow */
|
||||
#define IN_LPT 032 /* printer error */
|
||||
#define IN_PRO 034 /* process check */
|
||||
#define IN_DBY 036 /* disk busy */
|
||||
#define IN_END 042 /* end indicator */
|
||||
#define IN_TAP 043 /* tape error */
|
||||
#define IN_ACC 045 /* access error */
|
||||
#define IN_BSY 047 /* printer busy */
|
||||
#define IN_INR 050 /* inquiry request */
|
||||
#define IN_PCB 051 /* printer carr busy */
|
||||
#define IN_PNCH 052 /* punch error */
|
||||
#define IN_INC 054 /* inquiry clear */
|
||||
#define IN_LST 061 /* last card */
|
||||
#define IN_SSB 062 /* sense switch B */
|
||||
#define IN_SSC 063 /* sense switch C */
|
||||
#define IN_SSD 064 /* sense switch D */
|
||||
#define IN_SSE 065 /* sense switch E */
|
||||
#define IN_SSF 066 /* sense switch F */
|
||||
#define IN_SSG 067 /* sense switch G */
|
||||
#define IN_READ 072 /* reader error */
|
||||
|
||||
#define CRETIOE(f,c) return ((f)? (c): SCPE_OK)
|
||||
@@ -1,503 +0,0 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: IBM 1401 Simulator Usage
|
||||
Date: 15-Jul-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2003, written by Robert M Supnik
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This memorandum documents the IBM 1401 simulator.
|
||||
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tape.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_sock.c
|
||||
sim_tape.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/i1401/ i1401_defs.h
|
||||
i1401_dat.h
|
||||
i1401_cpu.c
|
||||
i1401_cd.c
|
||||
i1401_iq.c
|
||||
i1401_lp.c
|
||||
i1401_dp.c
|
||||
i1401_mt.c
|
||||
i1401_sys.c
|
||||
|
||||
2. IBM 1401 Features
|
||||
|
||||
The IBM 1401 simulator is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU IBM 1401 CPU with 16K of memory
|
||||
CDR,CDP IBM 1402 card reader/punch
|
||||
LPT IBM 1403 line printer
|
||||
INQ IBM 1407 inquiry terminal
|
||||
DP IBM 1311 disk pack with five drives
|
||||
MT IBM 729 7-track magnetic tape controller with six drives
|
||||
|
||||
The IBM 1401 simulator implements many unique stop conditions. On almost
|
||||
any kind of error the simulator stops:
|
||||
|
||||
unimplemented opcode
|
||||
reference to non-existent memory
|
||||
reference to non-existent device
|
||||
no word mark under opcode
|
||||
invalid A address
|
||||
invalid B address
|
||||
invalid instruction length
|
||||
invalid modifier character
|
||||
invalid branch address
|
||||
invalid magtape unit number
|
||||
invalid magtape record length
|
||||
write to locked magtape drive
|
||||
skip to unpunched carriage control tape channel
|
||||
card reader hopper empty
|
||||
address register wrap-around
|
||||
single character A field in MCE
|
||||
single character B field in MCE
|
||||
hanging $ in MCE with EPE enabled
|
||||
I/O check with I/O stop switch set
|
||||
invalid disk drive
|
||||
invalid disk sector address
|
||||
invalid disk sector count
|
||||
invalid disk address compare
|
||||
|
||||
The LOAD command is used to load a line printer carriage-control tape.
|
||||
The DUMP command is not implemented.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
The CPU options include a number of special features and the size of main
|
||||
memory. Note that the Modify Address special feature is always included
|
||||
when memory size is greater than 4K.
|
||||
|
||||
SET CPU XSA enable advanced programming special feature
|
||||
SET CPU NOXSA disable advanced programming
|
||||
SET CPU HLE enable high/low/equal special feature
|
||||
SET CPU NOHLE disable high/low/equal
|
||||
SET CPU BBE enable branch on bit equal special feature
|
||||
SET CPU NOBBE disable branch on bit equal
|
||||
SET CPU MR enable move record special feature
|
||||
SET CPU NOMR disable move record
|
||||
SET CPU EPE enable extended print edit special feature
|
||||
SET CPU NOEPE disable extended print edit
|
||||
SET CPU MDV enable multiply/divide special feature
|
||||
SET CPU NOMDV disable multiply/divide
|
||||
SET CPU 4K set memory size = 4K
|
||||
SET CPU 8K set memory size = 8K
|
||||
SET CPU 12K set memory size = 12K
|
||||
SET CPU 16K set memory size = 16K
|
||||
|
||||
If memory size is being reduced, and the memory being truncated contains
|
||||
non-zero data, the simulator asks for confirmation. Data in the truncated
|
||||
portion of memory is lost. Initially, memory size is 16K, and all special
|
||||
features are enabled.
|
||||
|
||||
Memory is implemented as 7 bit BCD characters, as follows:
|
||||
|
||||
6 5 4 3 2 1 0
|
||||
|
||||
word B bit A bit 8 4 2 1
|
||||
mark <-- zone --> <-------- digit -------->
|
||||
|
||||
In BCD, the decimal digits 0-9 are (octal) values 012, 001, 002, 003, 004,
|
||||
005, 006, 007, 010, 011, respectively. Signs are encoded in the zone bits,
|
||||
with 00, 01, and 11 being positive, and 10 being negative.
|
||||
|
||||
CPU registers include the visible state of the processor. The 1401 has no
|
||||
interrupt system.
|
||||
|
||||
name size comments
|
||||
|
||||
IS 14 instruction storage address register (PC)
|
||||
AS 14 A storage address register
|
||||
BS 14 B storage address register
|
||||
ASERR 1 AS invalid flag
|
||||
BSERR 1 BS invalid flag
|
||||
SSA 1 sense switch A
|
||||
SSB 1 sense switch B
|
||||
SSC 1 sense switch C
|
||||
SSD 1 sense switch D
|
||||
SSE 1 sense switch E
|
||||
SSF 1 sense switch F
|
||||
SSG 1 sense switch G
|
||||
EQU 1 equal compare indicator
|
||||
UNEQ 1 unequal compare indicator
|
||||
HIGH 1 high compare indicator
|
||||
LOW 1 low compare indicator
|
||||
OVF 1 overflow indicator
|
||||
IOCHK 1 I/O check switch
|
||||
PRCHK 1 process check switch
|
||||
ISQ[0:63] 14 IS prior to last branch;
|
||||
most recent IS change first
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 1402 Card Reader/Punch (CDR, CDP, STKR)
|
||||
|
||||
The IBM 1402 card/reader punch is simulated as three independent devices:
|
||||
the card reader (CDR), the card punch (CDP), and the reader and punch
|
||||
stackers (STKR). STRK units 0, 1, 2, and 4 correspond to the reader
|
||||
normal stacker, reader stacker 1, shared stacker 2/8, and punch stacker
|
||||
4, respectively.
|
||||
|
||||
The card reader supports the BOOT command. BOOT CDR reads a card image
|
||||
into locations 1-80, sets a word mark under location 1, clears storage,
|
||||
and then transfers control to location 1.
|
||||
|
||||
The card reader reads data from disk files, while the punch and stackers
|
||||
write data to disk files. Cards are simulated as ASCII text lines with
|
||||
terminating newlines; column binary is not supported. For each unit,
|
||||
the POS register specifies the number of the next data item to be read or
|
||||
written. Thus, by changing POS, the user can backspace or advance these
|
||||
devices.
|
||||
|
||||
The card reader registers are:
|
||||
|
||||
name size comments
|
||||
|
||||
LAST 1 last card indicator
|
||||
ERR 1 error indicator
|
||||
S1 1 stacker 1 select flag
|
||||
S2 1 stacker 2 select flag
|
||||
POS 32 position
|
||||
TIME 24 delay window for stacker select
|
||||
BUF[0:79] 8 reader buffer
|
||||
|
||||
The card punch registers are:
|
||||
|
||||
ERR 1 error indicator
|
||||
S4 1 stacker 4 select flag
|
||||
S8 1 stacker 8 select flag
|
||||
|
||||
The stacker registers are:
|
||||
|
||||
POS0 32 position, normal reader stack
|
||||
POS1 32 position, reader stacker 1
|
||||
POS2 32 position, shared stacker 2/8
|
||||
POS4 32 position, punch stacker 4
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
device error processed as
|
||||
|
||||
reader end of file if SSA set, set LAST indicator
|
||||
on next Read, report error and stop
|
||||
|
||||
reader,punch not attached report error and stop
|
||||
OS I/O error print error message
|
||||
if IOCHK set, report error and stop
|
||||
otherwise, set ERR indicator
|
||||
|
||||
stacker not attached ignored
|
||||
OS I/O error print error message
|
||||
if IOCHK set, report error and stop
|
||||
|
||||
2.3 1403 Line Printer (LPT)
|
||||
|
||||
The IBM 1403 line printer (LPT) writes its data, converted to ASCII, to
|
||||
a disk file. The line printer supports three different print character
|
||||
sets or "chains":
|
||||
|
||||
SET LPT PCF full 64 character chain
|
||||
SET LPT PCA 48 character business chain
|
||||
SET LPT PCH 48 character FORTRAN chain
|
||||
|
||||
In addition, the line printer can be programmed with a carriage control
|
||||
tape. The LOAD command loads a new carriage control tape:
|
||||
|
||||
LOAD <file> load carriage control tape file
|
||||
|
||||
The format of a carriage control tape consists of multiple lines. Each
|
||||
line contains an optional repeat count, enclosed in parentheses, optionally
|
||||
followed by a series of column numbers separated by commas. Column numbers
|
||||
must be between 1 and 12; a column number of zero denotes top of form. The
|
||||
following are all legal carriage control specifications:
|
||||
|
||||
<blank line> no punch
|
||||
(5) 5 lines with no punches
|
||||
1,5,7,8 columns 1, 5, 7, 8 punched
|
||||
(10)2 10 lines with column 2 punched
|
||||
1,0 column 1 punched; top of form
|
||||
|
||||
The default form is 66 lines long, with column 1 and the top of form mark
|
||||
on line 1, and the rest blank.
|
||||
|
||||
The line printer registers are:
|
||||
|
||||
name size comments
|
||||
|
||||
LINES 8 number of newlines after next print
|
||||
LFLAG 1 carriage control flag (1 = skip, 0 = space)
|
||||
CCTP 8 carriage control tape pointer
|
||||
CCTL 8 carriage control tape length (read only)
|
||||
ERR 1 error indicator
|
||||
POS 32 position
|
||||
CCT[0:131] 32 carriage control tape array
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached report error and stop
|
||||
|
||||
OS I/O error print error message
|
||||
if IOCHK set, report error and stop
|
||||
otherwise, set ERR indicator
|
||||
|
||||
2.4 1407 Inquiry Terminal (INQ)
|
||||
|
||||
The IBM 1407 inquiry terminal (INQ) is a half-duplex console. It polls
|
||||
the console keyboard periodically for inquiry requests. The inquiry
|
||||
terminal registers are:
|
||||
|
||||
name size comments
|
||||
|
||||
INQC 7 inquiry request character (initially ESC)
|
||||
INR 1 inquiry request indicator
|
||||
INC 1 inquiry cleared indicator
|
||||
TIME 24 polling interval
|
||||
|
||||
When the 1401 CPU requests input from the keyboard, the message [Enter]
|
||||
is printed out, followed by a new line. The CPU hangs waiting for input
|
||||
until either the return/enter key is pressed, or the inquiry request
|
||||
character is typed in. The latter cancels the type-in and sets INC.
|
||||
|
||||
The inquiry terminal has no errors.
|
||||
|
||||
2.5 1311 Disk Pack (DP)
|
||||
|
||||
The disk pack controller supports 5 drives, numbered 0 through 4. Disk
|
||||
pack options include the ability to enable address writing (formatting).
|
||||
|
||||
SET DPn ADDROFF set unit n address enable off
|
||||
SET DPn ADDRON set unit n address enable on
|
||||
|
||||
Units can also be set ONLINE or OFFLINE.
|
||||
|
||||
Unlike most simulated disks, the 1311 includes explicit representation
|
||||
for sector addresses. This is to support non-standard formats, such as
|
||||
the inclusion of the drive number in the sector address. As a result,
|
||||
1311 sectors are 106 characters long: 6 address characters and 100
|
||||
data characters. If the 1311 has not been formatted, the addresses
|
||||
are blanks and are synthesized, if needed, based on the sector number.
|
||||
|
||||
The 1311 also supports two modes of operation: move mode and load mode.
|
||||
In move mode, word marks are ignored on writes and left untouched on reads,
|
||||
and sectors hold 100 characters. In load mode, word marks are included
|
||||
on writes and stored on reads, and sectors hold 90 characters. No attempt
|
||||
is made to deal with sectors written in load mode and read in move mode,
|
||||
or vice versa; on a real 1401, this causes a fatal parity error.
|
||||
|
||||
The disk pack controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
ACC 1 access error indicator
|
||||
PWC 1 parity or write check error indicator
|
||||
WLR 1 wrong length record error indicator
|
||||
UNA 1 unequal address compare error indicator
|
||||
DSK 1 any disk error indicator
|
||||
BSY 1 disk access busy indicator
|
||||
LASTF 3 most recent function
|
||||
TIME 24 seek time
|
||||
|
||||
The 1311 has a primative overlapped seek capability. If TIME is set
|
||||
non-zero, the 1311 will report itself busy for the specified amount
|
||||
of time following a seek. This allows programs to utilize the seek
|
||||
time for processing.
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached set DSK indicator
|
||||
if IOCHK set, report error and stop
|
||||
|
||||
1311 data files are buffered in memory; therefore, end of file and OS
|
||||
I/O errors cannot occur.
|
||||
|
||||
2.6 729 Magnetic Tape (MT)
|
||||
|
||||
The magnetic tape controller supports six drives, numbered 1 through 6.
|
||||
Magnetic tape options include the ability to make units write enabled or
|
||||
or write locked.
|
||||
|
||||
SET MTn LOCKED set unit n write locked
|
||||
SET MTn WRITEENABLED set unit n write enabled
|
||||
|
||||
Units can also be set ONLINE or OFFLINE. The magnetic tape simulator
|
||||
supports the BOOT command. BOOT MT reads the first record off tape,
|
||||
starting at location 1, and then branches to it.
|
||||
|
||||
The magnetic tape controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
END 1 end of file indicator
|
||||
ERR 1 error indicator
|
||||
PAR 1 parity error indicator
|
||||
POS1..6 32 position, drives 1..6
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached report error and stop
|
||||
|
||||
end of file set error indicator
|
||||
|
||||
OS I/O error print error message
|
||||
set error indicator
|
||||
if IOCHK set, report error and stop
|
||||
|
||||
2.7 Symbolic Display and Input
|
||||
|
||||
The IBM 1401 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-c display as single character
|
||||
(BCD for CPU and MT, ASCII for others)
|
||||
-s display as wordmark terminated BCD string
|
||||
(CPU only)
|
||||
-m display instruction mnemonics
|
||||
(CPU only)
|
||||
-d display 50 characters per line, with word
|
||||
marks denoted by "1" on the line below
|
||||
|
||||
In a CPU character display, word marks are denoted by ~.
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or " or -c or -s characters (BCD for CPU and MT, ASCII
|
||||
for others)
|
||||
alphabetic instruction mnemonic
|
||||
numeric octal number
|
||||
|
||||
Instruction input is free format, with spaces separating fields. There
|
||||
are six instruction formats: 1, 2, 4, 5, 7, and 8 characters:
|
||||
|
||||
1 character opcode
|
||||
2 character opcode 'modifier
|
||||
4 character opcode address
|
||||
5 character opcode address 'modifier
|
||||
7 character opcode address address
|
||||
8 character opcode address address 'modifier
|
||||
|
||||
Addresses are always decimal, except for special I/O addresses in the A
|
||||
field, which may be specified as %xy, where x denotes the device and y
|
||||
the unit number.
|
||||
|
||||
For the CPU, string input may encompass multiple characters. A word mark
|
||||
is denoted by ~ and must precede the character to be marked. All other
|
||||
devices can only accept single character input, without word marks.
|
||||
|
||||
2.7 Character Sets
|
||||
|
||||
The IBM 1401 uses a 6b character code called BCD (binary coded decimal).
|
||||
Some of the characters have no equivalent in ASCII and require different
|
||||
representations:
|
||||
|
||||
BCD ASCII IBM 1401 print
|
||||
code representation character chains
|
||||
|
||||
00 space
|
||||
01 1
|
||||
02 2
|
||||
03 3
|
||||
04 4
|
||||
05 5
|
||||
06 6
|
||||
07 7
|
||||
10 8
|
||||
11 9
|
||||
12 0
|
||||
13 # = in H chain
|
||||
14 @ ' in H chain
|
||||
15 : blank in A, H chains
|
||||
16 > blank in A, H chains
|
||||
17 ( tape mark blank in A, H chains
|
||||
20 ^ alternate blank blank in A, H chains
|
||||
21 /
|
||||
22 S
|
||||
23 T
|
||||
24 U
|
||||
25 V
|
||||
26 W
|
||||
27 X
|
||||
30 Y
|
||||
31 Z
|
||||
32 ' record mark
|
||||
33 ,
|
||||
34 % ( in H chain
|
||||
35 = word mark blank in A, H chains
|
||||
36 \ blank in A, H chains
|
||||
37 + blank in A, H chains
|
||||
40 -
|
||||
41 J
|
||||
42 K
|
||||
43 L
|
||||
44 M
|
||||
45 N
|
||||
46 O
|
||||
47 P
|
||||
50 Q
|
||||
51 R
|
||||
52 !
|
||||
53 $
|
||||
54 *
|
||||
55 ] blank in A, H chains
|
||||
56 ; blank in A, H chains
|
||||
57 _ delta blank in A, H chains
|
||||
60 &
|
||||
61 A
|
||||
62 B
|
||||
63 C
|
||||
64 D
|
||||
65 E
|
||||
66 F
|
||||
67 G
|
||||
70 H
|
||||
71 I
|
||||
72 ?
|
||||
73 .
|
||||
74 ) lozenge
|
||||
75 [ blank in A, H chains
|
||||
76 < blank in A, H chains
|
||||
77 " group mark blank in A, H chains
|
||||
555
I1401/i1401_dp.c
555
I1401/i1401_dp.c
@@ -1,555 +0,0 @@
|
||||
/* i1401_dp.c: IBM 1311 disk simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
dp 1311 disk pack
|
||||
|
||||
18-Oct-02 RMS Fixed bug in address comparison logic
|
||||
19-Sep-02 RMS Minor edit for consistency with 1620
|
||||
15-Jun-02 RMS Reworked address comparison logic
|
||||
|
||||
The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.
|
||||
Each sector contains 106 characters of information:
|
||||
|
||||
6c sector address
|
||||
100c sector data
|
||||
|
||||
By default, a sector's address field will be '000000', which is illegal.
|
||||
This is interpreted to mean the implied sector number that would be in
|
||||
place if the disk pack had been formatted with sequential sector numbers.
|
||||
|
||||
The sector data can be 100 characters without word marks, or 90 characters
|
||||
with word marks. Load mode transfers 90 characters per sector with
|
||||
word marks, move mode transfers 100 characters per sector without word
|
||||
marks. No attempt is made to catch incompatible writes (eg, load mode
|
||||
write followed by move mode read).
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
|
||||
#define DP_NUMDR 5 /* #drives */
|
||||
#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */
|
||||
#define UNIT_WAE (1 << UNIT_V_WAE)
|
||||
|
||||
/* Disk format */
|
||||
|
||||
#define DP_ADDR 6 /* address */
|
||||
#define DP_DATA 100 /* data */
|
||||
#define DP_NUMCH (DP_ADDR + DP_DATA)
|
||||
|
||||
#define DP_NUMSC 20 /* #sectors */
|
||||
#define DP_NUMSF 10 /* #surfaces */
|
||||
#define DP_NUMCY 100 /* #cylinders */
|
||||
#define DP_TOTSC (DP_NUMCY*DP_NUMSF*DP_NUMSC)
|
||||
#define DP_SIZE (DP_TOTSC*DP_NUMCH)
|
||||
|
||||
/* Disk control field */
|
||||
|
||||
#define DCF_DRV 0 /* drive select */
|
||||
#define DCF_SEC 1 /* sector addr */
|
||||
#define DCF_SEC_LEN 6
|
||||
#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */
|
||||
#define DCF_CNT_LEN 3
|
||||
#define DCF_LEN (DCF_CNT + DCF_CNT_LEN)
|
||||
#define DCF_DIR 1 /* direct seek */
|
||||
#define DCF_DIR_LEN 4
|
||||
#define DCF_DIR_FL (DCF_DIR + DCF_DIR_LEN) /* direct seek flag */
|
||||
#define DCF_DSEEK 0xB
|
||||
|
||||
/* Functions */
|
||||
|
||||
#define FNC_SEEK 0 /* seek */
|
||||
#define FNC_CHECK 3 /* check */
|
||||
#define FNC_READ 1 /* read sectors */
|
||||
#define FNC_RSCO 5 /* read sec cnt overlay */
|
||||
#define FNC_RTRK 6 /* read track */
|
||||
#define FNC_WOFF 10 /* offset for write */
|
||||
#define FNC_WRITE 11 /* write sectors */
|
||||
#define FNC_WRSCO 15 /* write sec cnt overlay */
|
||||
#define FNC_WRTRK 16 /* write track */
|
||||
|
||||
#define CYL u3 /* current cylinder */
|
||||
|
||||
extern uint8 M[]; /* memory */
|
||||
extern int32 ind[64];
|
||||
extern int32 AS, BS, iochk;
|
||||
extern int32 bcd_to_bin[16];
|
||||
extern int32 bin_to_bcd[16];
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 dp_lastf = 0; /* prior function */
|
||||
int32 dp_time = 0; /* seek time */
|
||||
|
||||
t_stat dp_reset (DEVICE *dptr);
|
||||
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 wchk);
|
||||
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 wchk);
|
||||
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg);
|
||||
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg);
|
||||
int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf);
|
||||
t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf);
|
||||
t_bool dp_zeroad (uint8 *ap);
|
||||
t_bool dp_cmp_ad (uint8 *ap, int32 dcf);
|
||||
int32 dp_trkop (int32 drv, int32 sec);
|
||||
int32 dp_cvt_bcd (int32 ad, int32 len);
|
||||
void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg);
|
||||
int32 dp_get_cnt (int32 dcf);
|
||||
void dp_fill (UNIT *uptr, uint32 da, int32 cnt);
|
||||
|
||||
/* DP data structures
|
||||
|
||||
dp_dev DSK device descriptor
|
||||
dp_unit DSK unit list
|
||||
dp_reg DSK register list
|
||||
dp_mod DSK modifier list
|
||||
*/
|
||||
|
||||
UNIT dp_unit[] = {
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } };
|
||||
|
||||
REG dp_reg[] = {
|
||||
{ FLDATA (ACC, ind[IN_ACC], 0) },
|
||||
{ FLDATA (PWC, ind[IN_DPW], 0) },
|
||||
{ FLDATA (WLR, ind[IN_LNG], 0) },
|
||||
{ FLDATA (UNA, ind[IN_UNA], 0) },
|
||||
{ FLDATA (ERR, ind[IN_DSK], 0) },
|
||||
{ FLDATA (BSY, ind[IN_DBY], 0) },
|
||||
{ DRDATA (LASTF, dp_lastf, 3) },
|
||||
{ DRDATA (TIME, dp_time, 24), PV_LEFT },
|
||||
{ URDATA (CYL, dp_unit[0].CYL, 10, 8, 0,
|
||||
DP_NUMDR, PV_LEFT + REG_RO) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dp_mod[] = {
|
||||
{ UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL },
|
||||
{ UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dp_dev = {
|
||||
"DP", dp_unit, dp_reg, dp_mod,
|
||||
DP_NUMDR, 10, 21, 1, 8, 7,
|
||||
NULL, NULL, &dp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Disk IO routine
|
||||
|
||||
Inputs:
|
||||
fnc = function character
|
||||
flg = load vs move mode
|
||||
mod = modifier character
|
||||
Outputs:
|
||||
status = status
|
||||
*/
|
||||
|
||||
t_stat dp_io (int32 fnc, int32 flg, int32 mod)
|
||||
{
|
||||
int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff;
|
||||
UNIT *uptr;
|
||||
t_stat r;
|
||||
|
||||
dcf = BS; /* save DCF addr */
|
||||
qwc = 0; /* not wcheck */
|
||||
ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */
|
||||
ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0;
|
||||
if (sim_is_active (&dp_unit[0])) { /* ctlr busy? */
|
||||
ind[IN_DBY] = ind[IN_DSK] = 1; /* set indicators */
|
||||
return SCPE_OK; } /* done */
|
||||
|
||||
AS = dcf + 6; /* AS for most ops */
|
||||
BS = dcf + DCF_CNT - 1; /* minimum DCF */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */
|
||||
if (M[dcf] & BBIT) drv = M[dcf + DCF_SEC + 1] & 0xE; /* impl sel? cyl 8-4-2 */
|
||||
else drv = M[dcf] & DIGIT; /* get drive sel */
|
||||
if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */
|
||||
return STOP_INVDSK;
|
||||
drv = bcd_to_bin[drv] >> 1; /* convert */
|
||||
uptr = dp_dev.units + drv; /* get unit ptr */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */
|
||||
CRETIOE (iochk, SCPE_UNATT); }
|
||||
|
||||
if ((fnc == FNC_SEEK) && /* seek and */
|
||||
(M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */
|
||||
diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */
|
||||
if (diff < 0) return STOP_INVDSC; /* error? */
|
||||
diff = diff >> 1; /* diff is *2 */
|
||||
if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT)
|
||||
diff = -diff; /* get sign */
|
||||
uptr->CYL = uptr->CYL + diff; /* bound seek */
|
||||
if (uptr->CYL < 0) uptr->CYL = 0;
|
||||
else if (uptr->CYL >= DP_NUMCY) { /* too big? */
|
||||
uptr->CYL = 0; /* system hangs */
|
||||
return STOP_INVDCY; }
|
||||
sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */
|
||||
return SCPE_OK; } /* done! */
|
||||
|
||||
sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */
|
||||
if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */
|
||||
return STOP_INVDSC;
|
||||
if (fnc == FNC_SEEK) { /* seek? */
|
||||
uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */
|
||||
DP_NUMCY;
|
||||
sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */
|
||||
return SCPE_OK; } /* done! */
|
||||
|
||||
BS = dcf + DCF_LEN; /* full DCF */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */
|
||||
cnt = dp_get_cnt (dcf); /* get count */
|
||||
if (cnt < 0) return STOP_INVDCN; /* bad count? */
|
||||
|
||||
if (fnc >= FNC_WOFF) return STOP_INVDFN; /* invalid func */
|
||||
if (mod == BCD_W) { /* write? */
|
||||
if (fnc == FNC_CHECK) { /* write check? */
|
||||
qwc = 1; /* special read */
|
||||
fnc = dp_lastf; } /* use last func */
|
||||
else {
|
||||
dp_lastf = fnc; /* save func */
|
||||
fnc = fnc + FNC_WOFF; } } /* change to write */
|
||||
else if (mod == BCD_R) dp_lastf = fnc; /* read? save func */
|
||||
else return STOP_INVM; /* other? error */
|
||||
|
||||
switch (fnc) { /* case on function */
|
||||
case FNC_RSCO: /* read sec cnt ov */
|
||||
BS = dcf + DCF_CNT; /* set count back */
|
||||
/* fall thru */
|
||||
case FNC_READ: /* read */
|
||||
psec = dp_fndsec (uptr, sec, dcf); /* find sector */
|
||||
if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */
|
||||
if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read sector */
|
||||
break;
|
||||
cnt = dp_get_cnt (dcf); /* get new count */
|
||||
if (cnt < 0) return STOP_INVDCN; /* bad count? */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
sec++; psec++; /* next sector */
|
||||
dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */
|
||||
if (r = dp_nexsec (uptr, psec, dcf)) break; /* find next */
|
||||
}
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_RTRK: /* read track */
|
||||
AS = dcf + 9; /* special AS */
|
||||
psec = dp_trkop (drv, sec); /* start of track */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */
|
||||
if (r = dp_rdadr (uptr, psec, flg, qwc)) /* read addr */
|
||||
break; /* error? */
|
||||
if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read data */
|
||||
break; /* error? */
|
||||
cnt = dp_get_cnt (dcf); /* get new count */
|
||||
if (cnt < 0) return STOP_INVDCN; /* bad count? */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_WRSCO: /* write sec cnt ov */
|
||||
BS = dcf + DCF_CNT; /* set count back */
|
||||
/* fall through */
|
||||
case FNC_WRITE: /* read */
|
||||
psec = dp_fndsec (uptr, sec, dcf); /* find sector */
|
||||
if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* rewr cnt */
|
||||
if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
sec++; psec++; /* next sector */
|
||||
dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */
|
||||
if (r = dp_nexsec (uptr, psec, dcf)) break; /* find next */
|
||||
}
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_WRTRK: /* write track */
|
||||
if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */
|
||||
return STOP_WRADIS;
|
||||
AS = dcf + 9; /* special AS */
|
||||
psec = dp_trkop (drv, sec); /* start of track */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */
|
||||
if (r = dp_wradr (uptr, psec, flg)) break; /* write addr */
|
||||
if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
|
||||
break; /* done, clean up */
|
||||
|
||||
default: /* unknown */
|
||||
return STOP_INVDFN; }
|
||||
|
||||
if (r == SCPE_OK) { /* normal so far? */
|
||||
BS++; /* advance BS */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; /* address error? */
|
||||
if (M[BS - 1] != (WM + BCD_GRPMRK)) { /* GM + WM at end? */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */
|
||||
r = STOP_INVDLN; } }
|
||||
CRETIOE (iochk || !ind[IN_DSK], r); /* return status */
|
||||
}
|
||||
|
||||
/* Read or compare address with memory */
|
||||
|
||||
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 qwc)
|
||||
{
|
||||
int32 i;
|
||||
uint8 ac;
|
||||
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
t_bool zad = dp_zeroad (ap); /* zero address */
|
||||
static const int32 dec_tab[DP_ADDR] = /* powers of 10 */
|
||||
{ 100000, 10000, 1000, 100, 10, 1} ;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++) { /* copy address */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (zad) { /* addr zero? */
|
||||
ac = sec / dec_tab[i]; /* get addr digit */
|
||||
sec = sec % dec_tab[i]; /* get remainder */
|
||||
ac = bcd_to_bin[ac]; } /* cvt to BCD */
|
||||
else ac = *ap; /* addr char */
|
||||
if (qwc) { /* wr chk? skip if zad */
|
||||
if (!zad && (flg? (M[BS] != ac): /* L? cmp with WM */
|
||||
((M[BS] & CHAR) != (ac & CHAR)))) { /* M? cmp w/o WM */
|
||||
ind[IN_DPW] = ind[IN_DSK] = 1;
|
||||
return STOP_WRCHKE; } }
|
||||
else if (flg) M[BS] = ac & CHAR; /* load mode */
|
||||
else M[BS] = (M[BS] & WM) | (ac & CHAR); /* move mode */
|
||||
ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Read or compare data with memory */
|
||||
|
||||
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 qwc)
|
||||
{
|
||||
int32 i, lim;
|
||||
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */
|
||||
|
||||
lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */
|
||||
for (i = 0; i < lim; i++) { /* copy data */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (qwc) { /* write check? */
|
||||
if (flg? (M[BS] != *ap): /* load mode cmp */
|
||||
((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */
|
||||
ind[IN_DPW] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_WRCHKE; } }
|
||||
else if (flg) M[BS] = *ap & (WM | CHAR); /* load mode */
|
||||
else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* word mode */
|
||||
ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write address to disk */
|
||||
|
||||
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg)
|
||||
{
|
||||
int32 i;
|
||||
uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++) { /* copy address */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (flg) *ap = M[BS] & (WM | CHAR); /* L? copy WM */
|
||||
else *ap = M[BS] & CHAR; /* M? strip WM */
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
da++; ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write data to disk */
|
||||
|
||||
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg)
|
||||
{
|
||||
int32 i, lim;
|
||||
uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
|
||||
lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */
|
||||
for (i = 0; i < lim; i++) { /* copy data */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
dp_fill (uptr, da, DP_DATA - i); /* fill, set err */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (flg) *ap = M[BS] & (WM | CHAR); /* load, copy WM */
|
||||
else *ap = M[BS] & CHAR; /* move, strip WM */
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
da++; ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Find sector */
|
||||
|
||||
int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf)
|
||||
{
|
||||
int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
|
||||
int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;
|
||||
int32 da = psec * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
int32 i;
|
||||
|
||||
if (dp_zeroad (ap)) return psec; /* addr zero? ok */
|
||||
if (dp_cmp_ad (ap, dcf)) return psec; /* addr comp? ok */
|
||||
psec = psec - (psec % DP_NUMSC); /* sector 0 */
|
||||
for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */
|
||||
da = psec * DP_NUMCH; /* char number */
|
||||
ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */
|
||||
if (dp_zeroad (ap)) continue; /* no implicit match */
|
||||
if (dp_cmp_ad (ap, dcf)) return psec; } /* match? */
|
||||
ind[IN_UNA] = ind[IN_DSK] = 1; /* no match */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find next sector - must be sequential, cannot cross cylinder boundary */
|
||||
|
||||
t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf)
|
||||
{
|
||||
int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
|
||||
int32 da = psec * DP_NUMCH; /* word number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
|
||||
if (ctrk) { /* not trk zero? */
|
||||
if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */
|
||||
if (dp_cmp_ad (ap, dcf)) return SCPE_OK; } /* addr comp? ok */
|
||||
ind[IN_UNA] = ind[IN_DSK] = 1; /* no, error */
|
||||
return STOP_INVDAD;
|
||||
}
|
||||
|
||||
/* Test for zero address */
|
||||
|
||||
t_bool dp_zeroad (uint8 *ap)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
|
||||
if (*ap & CHAR) return FALSE; } /* nonzero? lose */
|
||||
return TRUE; /* all zeroes */
|
||||
}
|
||||
|
||||
/* Compare disk address to memory sector address - always omit word marks */
|
||||
|
||||
t_bool dp_cmp_ad (uint8 *ap, int32 dcf)
|
||||
{
|
||||
int32 i;
|
||||
uint8 c;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
|
||||
c = M[dcf + DCF_SEC + i]; /* sector addr char */
|
||||
if ((c & CHAR) != (*ap & CHAR)) /* cmp w/o WM */
|
||||
return FALSE; }
|
||||
return TRUE; /* compare ok */
|
||||
}
|
||||
|
||||
/* Track operation setup */
|
||||
|
||||
int32 dp_trkop (int32 drv, int32 sec)
|
||||
{
|
||||
int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;
|
||||
|
||||
return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) +
|
||||
(ctrk * DP_NUMSC));
|
||||
}
|
||||
|
||||
/* Convert DCF BCD field to binary */
|
||||
|
||||
int32 dp_cvt_bcd (int32 ad, int32 len)
|
||||
{
|
||||
uint8 c;
|
||||
int32 r;
|
||||
|
||||
for (r = 0; len > 0; len--) { /* loop thru char */
|
||||
c = M[ad] & DIGIT; /* get digit */
|
||||
if ((c == 0) || (c > BCD_ZERO)) return -1; /* invalid? */
|
||||
r = (r * 10) + bcd_to_bin[c]; /* cvt to bin */
|
||||
ad++; } /* next digit */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert binary to DCF BCD field */
|
||||
|
||||
void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg)
|
||||
{
|
||||
int32 r;
|
||||
|
||||
for ( ; len > 0; len--) { /* loop thru char */
|
||||
r = val % 10; /* get digit */
|
||||
if (flg) M[ad + len - 1] = bin_to_bcd[r]; /* load mode? */
|
||||
else M[ad + len - 1] = (M[ad + len - 1] & WM) | bin_to_bcd[r];
|
||||
val = val / 10; }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get and validate count */
|
||||
|
||||
int32 dp_get_cnt (int32 dcf)
|
||||
{
|
||||
int32 cnt = dp_cvt_bcd (dcf + DCF_CNT, DCF_CNT_LEN); /* get new count */
|
||||
if (cnt < 0) return -1; /* bad count? */
|
||||
if (cnt == 0) return 1000; /* 0 => 1000 */
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* Fill sector buffer with blanks */
|
||||
|
||||
void dp_fill (UNIT *uptr, uint32 da, int32 cnt)
|
||||
{
|
||||
while (cnt-- > 0) { /* fill with blanks */
|
||||
*(((uint8 *) uptr->filebuf) + da) = BCD_BLANK;
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
da++; }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dp_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */
|
||||
dp_lastf = 0; /* clear state */
|
||||
ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */
|
||||
ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0;
|
||||
sim_cancel (&dp_unit[0]); /* cancel timer */
|
||||
return SCPE_OK;
|
||||
}
|
||||
155
I1401/i1401_iq.c
155
I1401/i1401_iq.c
@@ -1,155 +0,0 @@
|
||||
/* i1401_iq.c: IBM 1407 inquiry terminal
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
inq 1407 inquiry terminal
|
||||
|
||||
22-Dec-02 RMS Added break support
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
14-Apr-99 RMS Changed t_addr to unsigned
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern volatile int32 stop_cpu;
|
||||
extern uint8 M[];
|
||||
extern int32 BS, iochk, ind[64];
|
||||
extern char ascii_to_bcd[128], bcd_to_ascii[64];
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 inq_char = 033; /* request inq */
|
||||
t_stat inq_svc (UNIT *uptr);
|
||||
t_stat inq_reset (DEVICE *dptr);
|
||||
|
||||
void puts_tty (char *cptr);
|
||||
|
||||
/* INQ data structures
|
||||
|
||||
inq_dev INQ device descriptor
|
||||
inq_unit INQ unit descriptor
|
||||
inq_reg INQ register list
|
||||
*/
|
||||
|
||||
UNIT inq_unit = { UDATA (&inq_svc, 0, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG inq_reg[] = {
|
||||
{ ORDATA (INQC, inq_char, 7) },
|
||||
{ FLDATA (INR, ind[IN_INR], 0) },
|
||||
{ FLDATA (INC, ind[IN_INC], 0) },
|
||||
{ DRDATA (TIME, inq_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE inq_dev = {
|
||||
"INQ", &inq_unit, inq_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &inq_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Terminal I/O
|
||||
|
||||
Modifiers have not been checked; legal modifiers are R and W
|
||||
*/
|
||||
|
||||
t_stat inq_io (int32 flag, int32 mod)
|
||||
{
|
||||
int32 i, t, wm_seen = 0;
|
||||
|
||||
ind[IN_INC] = 0; /* clear inq clear */
|
||||
switch (mod) { /* case on mod */
|
||||
case BCD_R: /* input */
|
||||
/* if (ind[IN_INR] == 0) return SCPE_OK; /* return if no req */
|
||||
ind[IN_INR] = 0; /* clear req */
|
||||
puts_tty ("[Enter]\r\n"); /* prompt */
|
||||
for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */
|
||||
while (((t = sim_poll_kbd ()) == SCPE_OK) ||
|
||||
(t & SCPE_BREAK)) {
|
||||
if (stop_cpu) return SCPE_STOP; } /* interrupt? */
|
||||
if (t < SCPE_KFLAG) return t; /* if not char, err */
|
||||
t = t & 0177;
|
||||
if ((t == '\r') || (t == '\n')) break;
|
||||
if (t == inq_char) { /* cancel? */
|
||||
ind[IN_INC] = 1; /* set indicator */
|
||||
puts_tty ("\r\n[Canceled]\r\n");
|
||||
return SCPE_OK; }
|
||||
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
|
||||
sim_putchar (t); /* echo */
|
||||
if (flag == MD_WM) { /* word mark mode? */
|
||||
if ((t == '~') && (wm_seen == 0)) wm_seen = WM;
|
||||
else {
|
||||
M[BS] = wm_seen | ascii_to_bcd[t];
|
||||
wm_seen = 0; } }
|
||||
else M[BS] = (M[BS] & WM) | ascii_to_bcd[t];
|
||||
if (!wm_seen) BS++;
|
||||
if (ADDR_ERR (BS)) {
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_NXM; } }
|
||||
puts_tty ("\r\n");
|
||||
M[BS++] = BCD_GRPMRK + WM;
|
||||
return SCPE_OK;
|
||||
case BCD_W: /* output */
|
||||
for (i = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); i++) {
|
||||
if ((flag == MD_WM) && (t & WM)) {
|
||||
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
|
||||
sim_putchar ('~'); }
|
||||
if (i && ((i % INQ_WIDTH) == 0)) puts_tty ("\r\n");
|
||||
sim_putchar (bcd_to_ascii[t & CHAR]);
|
||||
if (ADDR_ERR (BS)) {
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_NXM; } }
|
||||
puts_tty ("\r\n");
|
||||
return SCPE_OK;
|
||||
default:
|
||||
return STOP_INVM; } /* invalid mod */
|
||||
}
|
||||
|
||||
/* Unit service - polls for WRU or inquiry request */
|
||||
|
||||
t_stat inq_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&inq_unit, inq_unit.wait); /* continue poll */
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
|
||||
if ((temp & 0177) == inq_char) ind[IN_INR] = 1; /* set indicator */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Output multiple characters */
|
||||
|
||||
void puts_tty (char *cptr)
|
||||
{
|
||||
if (cptr == NULL) return;
|
||||
while (*cptr != 0) sim_putchar (*cptr++);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat inq_reset (DEVICE *dptr)
|
||||
{
|
||||
ind[IN_INR] = ind[IN_INC] = 0; /* clear indicators */
|
||||
sim_activate (&inq_unit, inq_unit.wait); /* activate poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
233
I1401/i1401_lp.c
233
I1401/i1401_lp.c
@@ -1,233 +0,0 @@
|
||||
/* i1401_lp.c: IBM 1403 line printer simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
lpt 1403 line printer
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
13-Apr-01 RMS Revised for register arrays
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
|
||||
extern uint8 M[];
|
||||
extern char bcd_to_ascii[64];
|
||||
extern int32 iochk, ind[64];
|
||||
|
||||
int32 cct[CCT_LNT] = { 03 };
|
||||
int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0;
|
||||
|
||||
t_stat lpt_reset (DEVICE *dptr);
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr);
|
||||
t_stat space (int32 lines, int32 lflag);
|
||||
|
||||
char bcd_to_pca[64] = {
|
||||
' ', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '0', '#', '@', ' ', ' ', ' ',
|
||||
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', ' ', ',', '%', ' ', ' ', ' ',
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', '-', '$', '*', ' ', ' ', ' ',
|
||||
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', '&', '.', ')', ' ', ' ', ' ' };
|
||||
char bcd_to_pch[64] = {
|
||||
' ', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '0', '=', '\'', ' ', ' ', ' ',
|
||||
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', ' ', ',', '(', ' ', ' ', ' ',
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', '-', '$', '*', ' ', ' ', ' ',
|
||||
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', '&', '.', ')', ' ', ' ', ' ' };
|
||||
char *pch_table[4] = {
|
||||
bcd_to_ascii, bcd_to_pca, bcd_to_pch, bcd_to_ascii };
|
||||
|
||||
#define UNIT_V_PCHAIN (UNIT_V_UF + 0)
|
||||
#define UNIT_M_PCHAIN 03
|
||||
#define M_PCF 00 /* full */
|
||||
#define M_PCA 01 /* business */
|
||||
#define M_PCH 02 /* Fortran */
|
||||
#define UNIT_PCHAIN (UNIT_M_PCHAIN << UNIT_V_PCHAIN)
|
||||
#define PCF (M_PCF << UNIT_V_PCHAIN)
|
||||
#define PCA (M_PCA << UNIT_V_PCHAIN)
|
||||
#define PCH (M_PCH << UNIT_V_PCHAIN)
|
||||
#define GET_PCHAIN(x) (((x) >> UNIT_V_PCHAIN) & UNIT_M_PCHAIN)
|
||||
#define CHP(ch,val) ((val) & (1 << (ch)))
|
||||
|
||||
/* LPT data structures
|
||||
|
||||
lpt_dev LPT device descriptor
|
||||
lpt_unit LPT unit descriptor
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
UNIT lpt_unit = {
|
||||
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
|
||||
|
||||
REG lpt_reg[] = {
|
||||
{ FLDATA (ERR, ind[IN_LPT], 0) },
|
||||
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ BRDATA (CCT, cct, 8, 32, CCT_LNT) },
|
||||
{ DRDATA (LINES, lines, 8), PV_LEFT },
|
||||
{ DRDATA (CCTP, cctptr, 8), PV_LEFT },
|
||||
{ DRDATA (CCTL, cctlnt, 8), REG_RO + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
MTAB lpt_mod[] = {
|
||||
{ UNIT_PCHAIN, PCF, "F chain", "PCF", NULL },
|
||||
{ UNIT_PCHAIN, PCA, "A chain", "PCA", NULL },
|
||||
{ UNIT_PCHAIN, PCH, "H chain", "PCH", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE lpt_dev = {
|
||||
"LPT", &lpt_unit, lpt_reg, lpt_mod,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &lpt_reset,
|
||||
NULL, &lpt_attach, NULL };
|
||||
|
||||
/* Print routine
|
||||
|
||||
Modifiers have been checked by the caller
|
||||
SQUARE = word mark mode
|
||||
S = suppress automatic newline
|
||||
*/
|
||||
|
||||
t_stat write_line (int32 ilnt, int32 mod)
|
||||
{
|
||||
int32 i, t, wm, sup;
|
||||
char *pch;
|
||||
static char lbuf[LPT_WIDTH + 1]; /* + null */
|
||||
|
||||
if ((lpt_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
|
||||
wm = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_SQUARE);
|
||||
sup = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_S);
|
||||
ind[IN_LPT] = 0; /* clear error */
|
||||
pch = pch_table[GET_PCHAIN (lpt_unit.flags)]; /* get print chain */
|
||||
for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */
|
||||
t = M[LPT_BUF + i];
|
||||
if (wm) lbuf[i] = (t & WM)? '1': ' '; /* wmarks -> 1 or sp */
|
||||
else lbuf[i] = pch[t & CHAR]; } /* normal */
|
||||
M[LPT_BUF + 1] = 0; /* trailing null */
|
||||
for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) lbuf[i] = 0;
|
||||
fputs (lbuf, lpt_unit.fileref); /* write line */
|
||||
if (lines) space (lines, lflag); /* cc action? do it */
|
||||
else if (sup == 0) space (1, FALSE); /* default? 1 line */
|
||||
else { fputc ('\r', lpt_unit.fileref); /* sup -> overprint */
|
||||
lpt_unit.pos = ftell (lpt_unit.fileref); } /* update position */
|
||||
lines = lflag = 0; /* clear cc action */
|
||||
if (ferror (lpt_unit.fileref)) { /* error? */
|
||||
perror ("Line printer I/O error");
|
||||
clearerr (lpt_unit.fileref);
|
||||
if (iochk) return SCPE_IOERR;
|
||||
ind[IN_LPT] = 1; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Carriage control routine
|
||||
|
||||
The modifier has not been checked, its format is
|
||||
<5:4> = 00, skip to channel now
|
||||
= 01, space lines after
|
||||
= 10, space lines now
|
||||
= 11, skip to channel after
|
||||
<3:0> = number of lines or channel number
|
||||
*/
|
||||
|
||||
t_stat carriage_control (int32 mod)
|
||||
{
|
||||
int32 i, action;
|
||||
|
||||
action = (mod & ZONE) >> V_ZONE; /* get mod type */
|
||||
mod = mod & DIGIT; /* isolate value */
|
||||
switch (action) {
|
||||
case 0: /* to channel now */
|
||||
if ((mod == 0) || (mod > 12) || CHP (mod, cct[cctptr])) return SCPE_OK;
|
||||
for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */
|
||||
if (CHP (mod, cct[(cctptr + i) % cctlnt]))
|
||||
return space (i, TRUE); }
|
||||
return STOP_CCT; /* runaway channel */
|
||||
case 1: /* space after */
|
||||
if (mod <= 3) {
|
||||
lines = mod; /* save # lines */
|
||||
lflag = FALSE; /* flag spacing */
|
||||
ind[IN_CC9] = ind[IN_CC12] = 0; }
|
||||
return SCPE_OK;
|
||||
case 2: /* space now */
|
||||
if (mod <= 3) return space (mod, FALSE);
|
||||
return SCPE_OK;
|
||||
case 3: /* to channel after */
|
||||
if ((mod == 0) || (mod > 12)) return SCPE_OK; /* check channel */
|
||||
ind[IN_CC9] = ind[IN_CC12] = 0;
|
||||
for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */
|
||||
if (CHP (mod, cct[(cctptr + i) % cctlnt])) {
|
||||
lines = i; /* save # lines */
|
||||
lflag = TRUE; /* flag skipping */
|
||||
return SCPE_OK; } }
|
||||
return STOP_CCT; } /* runaway channel */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Space routine - space or skip n lines
|
||||
|
||||
Inputs:
|
||||
count = number of lines to space or skip
|
||||
sflag = skip (TRUE) or space (FALSE)
|
||||
*/
|
||||
|
||||
t_stat space (int32 count, int32 sflag)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if ((lpt_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */
|
||||
if (sflag && CHP (0, cct[cctptr])) /* skip, top of form? */
|
||||
fputs ("\n\f", lpt_unit.fileref); /* nl, ff */
|
||||
else { for (i = 0; i < count; i++)
|
||||
fputc ('\n', lpt_unit.fileref); }
|
||||
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
|
||||
ind[IN_CC9] = CHP (9, cct[cctptr]) != 0; /* set indicators */
|
||||
ind[IN_CC12] = CHP (12, cct[cctptr]) != 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat lpt_reset (DEVICE *dptr)
|
||||
{
|
||||
cctptr = 0; /* clear cct ptr */
|
||||
lines = lflag = 0; /* no cc action */
|
||||
ind[IN_LPT] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
cctptr = 0; /* clear cct ptr */
|
||||
lines = 0; /* no cc action */
|
||||
ind[IN_LPT] = 0;
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
329
I1401/i1401_mt.c
329
I1401/i1401_mt.c
@@ -1,329 +0,0 @@
|
||||
/* i1401_mt.c: IBM 1401 magnetic tape simulator
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
mt 7-track magtape
|
||||
|
||||
16-Aug-03 RMS End-of-record on load read works like move read
|
||||
(verified on real 1401)
|
||||
Added diagnostic read (space forward)
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
28-Mar-03 RMS Added multiformat support
|
||||
15-Mar-03 RMS Fixed end-of-record on load read yet again
|
||||
28-Feb-03 RMS Modified for magtape library
|
||||
31-Oct-02 RMS Added error record handling
|
||||
10-Oct-02 RMS Fixed end-of-record on load read writes WM plus GM
|
||||
30-Sep-02 RMS Revamped error handling
|
||||
28-Aug-02 RMS Added end of medium support
|
||||
12-Jun-02 RMS End-of-record on move read preserves old WM under GM
|
||||
(found by Van Snyder)
|
||||
03-Jun-02 RMS Modified for 1311 support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
22-Apr-02 RMS Added protection against bad record lengths
|
||||
30-Jan-02 RMS New zero footprint tape bootstrap from Van Snyder
|
||||
20-Jan-02 RMS Changed write enabled modifier
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
18-Apr-01 RMS Changed to rewind tape before boot
|
||||
07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt
|
||||
CEO Added tape bootstrap
|
||||
14-Apr-99 RMS Changed t_addr to unsigned
|
||||
04-Oct-98 RMS V2.4 magtape format
|
||||
|
||||
Magnetic tapes are represented as a series of variable 16b records
|
||||
of the form:
|
||||
|
||||
32b byte count
|
||||
byte 0
|
||||
byte 1
|
||||
:
|
||||
byte n-2
|
||||
byte n-1
|
||||
32b byte count
|
||||
|
||||
If the byte count is odd, the record is padded with an extra byte
|
||||
of junk. File marks are represented by a byte count of 0.
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
#include "sim_tape.h"
|
||||
|
||||
#define MT_NUMDR 7 /* #drives */
|
||||
#define MT_MAXFR (MAXMEMSIZE * 2) /* max transfer */
|
||||
|
||||
extern uint8 M[]; /* memory */
|
||||
extern int32 ind[64];
|
||||
extern int32 BS, iochk;
|
||||
extern UNIT cpu_unit;
|
||||
uint8 dbuf[MT_MAXFR]; /* tape buffer */
|
||||
t_stat mt_reset (DEVICE *dptr);
|
||||
t_stat mt_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat mt_map_status (t_stat st);
|
||||
UNIT *get_unit (int32 unit);
|
||||
|
||||
/* MT data structures
|
||||
|
||||
mt_dev MT device descriptor
|
||||
mt_unit MT unit list
|
||||
mt_reg MT register list
|
||||
mt_mod MT modifier list
|
||||
*/
|
||||
|
||||
UNIT mt_unit[] = {
|
||||
{ UDATA (NULL, UNIT_DIS, 0) }, /* doesn't exist */
|
||||
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_ROABLE + UNIT_BCD, 0) },
|
||||
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_ROABLE + UNIT_BCD, 0) },
|
||||
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_ROABLE + UNIT_BCD, 0) },
|
||||
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_ROABLE + UNIT_BCD, 0) },
|
||||
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_ROABLE + UNIT_BCD, 0) },
|
||||
{ UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_ROABLE + UNIT_BCD, 0) } };
|
||||
|
||||
REG mt_reg[] = {
|
||||
{ FLDATA (END, ind[IN_END], 0) },
|
||||
{ FLDATA (ERR, ind[IN_TAP], 0) },
|
||||
{ DRDATA (POS1, mt_unit[1].pos, T_ADDR_W), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS2, mt_unit[2].pos, T_ADDR_W), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS3, mt_unit[3].pos, T_ADDR_W), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS4, mt_unit[4].pos, T_ADDR_W), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS5, mt_unit[5].pos, T_ADDR_W), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS6, mt_unit[6].pos, T_ADDR_W), PV_LEFT + REG_RO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB mt_mod[] = {
|
||||
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE mt_dev = {
|
||||
"MT", mt_unit, mt_reg, mt_mod,
|
||||
MT_NUMDR, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &mt_reset,
|
||||
&mt_boot, &sim_tape_attach, &sim_tape_detach };
|
||||
|
||||
/* Function routine
|
||||
|
||||
Inputs:
|
||||
unit = unit character
|
||||
mod = modifier character
|
||||
Outputs:
|
||||
status = status
|
||||
*/
|
||||
|
||||
t_stat mt_func (int32 unit, int32 mod)
|
||||
{
|
||||
t_mtrlnt tbc;
|
||||
UNIT *uptr;
|
||||
t_stat st;
|
||||
|
||||
if ((uptr = get_unit (unit)) == NULL) return STOP_INVMTU; /* valid unit? */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
|
||||
switch (mod) { /* case on modifier */
|
||||
|
||||
case BCD_A: /* diagnostic read */
|
||||
ind[IN_END] = 0; /* clear end of file */
|
||||
st = sim_tape_sprecf (uptr, &tbc); /* space fwd */
|
||||
break;
|
||||
|
||||
case BCD_B: /* backspace */
|
||||
ind[IN_END] = 0; /* clear end of file */
|
||||
st = sim_tape_sprecr (uptr, &tbc); /* space rev */
|
||||
break; /* end case */
|
||||
|
||||
case BCD_E: /* erase = nop */
|
||||
if (sim_tape_wrp (uptr)) return STOP_MTL;
|
||||
return SCPE_OK;
|
||||
|
||||
case BCD_M: /* write tapemark */
|
||||
st = sim_tape_wrtmk (uptr); /* write tmk */
|
||||
break;
|
||||
|
||||
case BCD_R: /* rewind */
|
||||
sim_tape_rewind (uptr); /* update position */
|
||||
return SCPE_OK;
|
||||
|
||||
case BCD_U: /* unload */
|
||||
sim_tape_rewind (uptr); /* update position */
|
||||
return detach_unit (uptr); /* detach */
|
||||
|
||||
default:
|
||||
return STOP_INVM; }
|
||||
|
||||
return mt_map_status (st);
|
||||
}
|
||||
|
||||
/* Read and write routines
|
||||
|
||||
Inputs:
|
||||
unit = unit character
|
||||
flag = normal, word mark, or binary mode
|
||||
mod = modifier character
|
||||
Outputs:
|
||||
status = status
|
||||
|
||||
Fine point: after a read, the system writes a group mark just
|
||||
beyond the end of the record. However, first it checks for a
|
||||
GM + WM; if present, the GM + WM is not changed. Otherwise,
|
||||
an MCW read sets a GM, preserving the current WM; while an LCA
|
||||
read sets a GM and clears the WM.
|
||||
*/
|
||||
|
||||
t_stat mt_io (int32 unit, int32 flag, int32 mod)
|
||||
{
|
||||
int32 t, wm_seen;
|
||||
t_mtrlnt i, tbc;
|
||||
t_stat st;
|
||||
UNIT *uptr;
|
||||
|
||||
if ((uptr = get_unit (unit)) == NULL) return STOP_INVMTU; /* valid unit? */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
|
||||
|
||||
switch (mod) {
|
||||
case BCD_R: /* read */
|
||||
ind[IN_TAP] = ind[IN_END] = 0; /* clear error */
|
||||
wm_seen = 0; /* no word mk seen */
|
||||
st = sim_tape_rdrecf (uptr, dbuf, &tbc, MT_MAXFR); /* read rec */
|
||||
if (st == MTSE_RECE) ind[IN_TAP] = 1; /* rec in error? */
|
||||
else if (st != MTSE_OK) break; /* stop on error */
|
||||
for (i = 0; i < tbc; i++) { /* loop thru buf */
|
||||
if (M[BS] == (BCD_GRPMRK + WM)) { /* GWM in memory? */
|
||||
BS++; /* incr BS */
|
||||
if (ADDR_ERR (BS)) { /* test for wrap */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; }
|
||||
return SCPE_OK; } /* done */
|
||||
t = dbuf[i]; /* get char */
|
||||
if ((flag != MD_BIN) && (t == BCD_ALT)) t = BCD_BLANK;
|
||||
if (flag == MD_WM) { /* word mk mode? */
|
||||
if ((t == BCD_WM) && (wm_seen == 0)) wm_seen = WM;
|
||||
else {
|
||||
M[BS] = wm_seen | (t & CHAR);
|
||||
wm_seen = 0; } }
|
||||
else M[BS] = (M[BS] & WM) | (t & CHAR);
|
||||
if (!wm_seen) BS++;
|
||||
if (ADDR_ERR (BS)) { /* check next BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; } }
|
||||
/* if (M[BS] != (BCD_GRPMRK + WM)) { /* not GM+WM at end? */
|
||||
/* if (flag == MD_WM) M[BS] = BCD_GRPMRK; /* LCA: clear WM */
|
||||
/* else M[BS] = (M[BS] & WM) | BCD_GRPMRK; } /* MCW: save WM */
|
||||
M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* write GM, save WM */
|
||||
BS++; /* adv BS */
|
||||
if (ADDR_ERR (BS)) { /* check final BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; }
|
||||
break;
|
||||
|
||||
case BCD_W:
|
||||
if (uptr->flags & MTUF_WRP) return STOP_MTL; /* locked? */
|
||||
if (M[BS] == (BCD_GRPMRK + WM)) return STOP_MTZ; /* eor? */
|
||||
ind[IN_TAP] = ind[IN_END] = 0; /* clear error */
|
||||
for (tbc = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); ) {
|
||||
if ((t & WM) && (flag == MD_WM)) dbuf[tbc++] = BCD_WM;
|
||||
if (((t & CHAR) == BCD_BLANK) && (flag != MD_BIN))
|
||||
dbuf[tbc++] = BCD_ALT;
|
||||
else dbuf[tbc++] = t & CHAR;
|
||||
if (ADDR_ERR (BS)) { /* check next BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; } }
|
||||
st = sim_tape_wrrecf (uptr, dbuf, tbc); /* write record */
|
||||
if (ADDR_ERR (BS)) { /* check final BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; }
|
||||
break;
|
||||
default:
|
||||
return STOP_INVM; }
|
||||
|
||||
return mt_map_status (st);
|
||||
}
|
||||
|
||||
/* Get unit pointer from unit number */
|
||||
|
||||
UNIT *get_unit (int32 unit)
|
||||
{
|
||||
if ((unit <= 0) || (unit >= MT_NUMDR)) return NULL;
|
||||
return mt_dev.units + unit;
|
||||
}
|
||||
|
||||
/* Map tape status */
|
||||
|
||||
t_stat mt_map_status (t_stat st)
|
||||
{
|
||||
switch (st) {
|
||||
case MTSE_OK: /* no error */
|
||||
case MTSE_BOT: /* reverse into BOT */
|
||||
break;
|
||||
case MTSE_FMT: /* illegal fmt */
|
||||
return SCPE_IERR;
|
||||
case MTSE_UNATT: /* not attached */
|
||||
return SCPE_UNATT;
|
||||
case MTSE_INVRL: /* invalid rec lnt */
|
||||
return SCPE_MTRLNT;
|
||||
case MTSE_TMK: /* end of file */
|
||||
ind[IN_END] = 1; /* set end mark */
|
||||
break;
|
||||
case MTSE_IOERR: /* IO error */
|
||||
ind[IN_TAP] = 1; /* set error */
|
||||
if (iochk) return SCPE_IOERR;
|
||||
break;
|
||||
case MTSE_RECE: /* record in error */
|
||||
case MTSE_EOM: /* end of medium */
|
||||
ind[IN_TAP] = 1; /* set error */
|
||||
break;
|
||||
case MTSE_WRP: /* write protect */
|
||||
return STOP_MTL; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat mt_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
for (i = 0; i < MT_NUMDR; i++) { /* clear pos flag */
|
||||
if (uptr = get_unit (i)) MT_CLR_PNU (uptr); }
|
||||
ind[IN_END] = ind[IN_TAP] = 0; /* clear indicators */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
t_stat mt_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
extern int32 saved_IS;
|
||||
|
||||
sim_tape_rewind (&mt_unit[unitno]); /* force rewind */
|
||||
BS = 1; /* set BS = 001 */
|
||||
mt_io (unitno, MD_WM, BCD_R); /* LDA %U1 001 R */
|
||||
saved_IS = 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
/* i1401_sys.c: IBM 1401 simulator interface
|
||||
|
||||
Copyright (c) 1993-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
16-Mar-03 RMS Fixed mnemonic for MCS
|
||||
03-Jun-02 RMS Added 1311 support
|
||||
18-May-02 RMS Added -D feature from Van Snyder
|
||||
26-Jan-02 RMS Fixed H, NOP with no trailing wm (found by Van Snyder)
|
||||
17-Sep-01 RMS Removed multiconsole support
|
||||
13-Jul-01 RMS Fixed bug in symbolic output (found by Peter Schorn)
|
||||
27-May-01 RMS Added multiconsole support
|
||||
14-Mar-01 RMS Revised load/dump interface (again)
|
||||
30-Oct-00 RMS Added support for examine to file
|
||||
27-Oct-98 RMS V2.4 load interface
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define LINE_LNT 80
|
||||
extern DEVICE cpu_dev, inq_dev, lpt_dev;
|
||||
extern DEVICE cdr_dev, cdp_dev, stack_dev;
|
||||
extern DEVICE dp_dev, mt_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern uint8 M[];
|
||||
extern char bcd_to_ascii[64], ascii_to_bcd[128];
|
||||
extern char *get_glyph (char *cptr, char *gbuf, char term);
|
||||
extern int32 store_addr_h (int32 addr);
|
||||
extern int32 store_addr_t (int32 addr);
|
||||
extern int32 store_addr_u (int32 addr);
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "IBM 1401";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = LINE_LNT;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&inq_dev,
|
||||
&cdr_dev,
|
||||
&cdp_dev,
|
||||
&stack_dev,
|
||||
&lpt_dev,
|
||||
&mt_dev,
|
||||
&dp_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented instruction",
|
||||
"Non-existent memory",
|
||||
"Non-existent device",
|
||||
"No WM at instruction start",
|
||||
"Invalid A address",
|
||||
"Invalid B address",
|
||||
"Invalid instruction length",
|
||||
"Invalid modifer",
|
||||
"Invalid branch address",
|
||||
"Breakpoint",
|
||||
"HALT instruction",
|
||||
"Invalid MT unit number",
|
||||
"Invalid MT record length",
|
||||
"Write to locked MT unit",
|
||||
"Skip to unpunched CCT channel",
|
||||
"Card reader empty",
|
||||
"Address register wrap",
|
||||
"MCE data field too short",
|
||||
"MCE control field too short",
|
||||
"MCE EPE hanging $",
|
||||
"I/O check",
|
||||
"Invalid disk sector address",
|
||||
"Invalid disk sector count",
|
||||
"Invalid disk unit",
|
||||
"Invalid disk function",
|
||||
"Invalid disk record length",
|
||||
"Write track while disabled",
|
||||
"Write check error",
|
||||
"Disk address miscompare",
|
||||
"Direct seek cylinder exceeds maximum"
|
||||
};
|
||||
|
||||
/* Binary loader -- load carriage control tape
|
||||
|
||||
A carriage control tape consists of entries of the form
|
||||
|
||||
(repeat count) column number,column number,column number,...
|
||||
|
||||
The CCT entries are stored in cct[0:lnt-1], cctlnt contains the
|
||||
number of entries
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
|
||||
t_stat r;
|
||||
extern int32 cctlnt, cctptr, cct[CCT_LNT];
|
||||
char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
|
||||
|
||||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||||
ptr = 0;
|
||||
for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
|
||||
mask = 0;
|
||||
if (*cptr == '(') { /* repeat count? */
|
||||
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
|
||||
rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
|
||||
if (r != SCPE_OK) return SCPE_FMT; }
|
||||
else rpt = 1;
|
||||
while (*cptr != 0) { /* get col no's */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
|
||||
col = get_uint (gbuf, 10, 12, &r); /* column number */
|
||||
if (r != SCPE_OK) return SCPE_FMT;
|
||||
mask = mask | (1 << col); } /* set bit */
|
||||
for ( ; rpt > 0; rpt--) { /* store vals */
|
||||
if (ptr >= CCT_LNT) return SCPE_FMT;
|
||||
cctbuf[ptr++] = mask; } }
|
||||
if (ptr == 0) return SCPE_FMT;
|
||||
cctlnt = ptr;
|
||||
cctptr = 0;
|
||||
for (rpt = 0; rpt < cctlnt; rpt++) cct[rpt] = cctbuf[rpt];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbol table */
|
||||
|
||||
const char *opcode[64] = {
|
||||
NULL, "R", "W", "WR", "P", "RP", "WP", "WRP",
|
||||
"RF", "WF", NULL, "MA", "MUL", NULL, NULL, NULL,
|
||||
NULL, "CS", "S", NULL, "MTF", "BWZ", "BBE", NULL,
|
||||
"MZ", "MCS", NULL, "SWM", "DIV", NULL, NULL, NULL,
|
||||
NULL, NULL, "SS", "LCA", "MCW", "NOP", NULL, "MCM",
|
||||
"SAR", NULL, "ZS", NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, "A", "B", "C", "MN", "MCE", "CC", NULL,
|
||||
"SBR", NULL, "ZA", "H", "CWM", NULL, NULL, NULL };
|
||||
|
||||
/* Print an address from three characters */
|
||||
|
||||
void fprint_addr (FILE *of, t_value *dig)
|
||||
{
|
||||
int32 addr, xa;
|
||||
extern int32 hun_table[64], ten_table[64], one_table[64];
|
||||
|
||||
addr = hun_table[dig[0]] + ten_table[dig[1]] + one_table[dig[2]];
|
||||
xa = (addr >> V_INDEX) & M_INDEX;
|
||||
if (xa) fprintf (of, " %d,%d", addr & ADDRMASK, ((xa - (X1 >> V_INDEX)) / 5) + 1);
|
||||
else if (addr >= MAXMEMSIZE) fprintf (of, " %d*", addr & ADDRMASK);
|
||||
else fprintf (of, " %d", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current address
|
||||
*val = values to decode
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = if >= 0, error code
|
||||
if < 0, number of extra words retired
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 op, flags, ilnt, i, t;
|
||||
extern int32 op_table[64], len_table[9];
|
||||
|
||||
if (sw & SWMASK ('C')) { /* character? */
|
||||
t = val[0];
|
||||
if (uptr->flags & UNIT_BCD)
|
||||
fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]);
|
||||
else fprintf (of, FMTASC (t & 0177));
|
||||
return SCPE_OK; }
|
||||
if ((uptr != NULL) && (uptr != &cpu_unit)) return SCPE_ARG; /* CPU? */
|
||||
if (sw & SWMASK ('D')) { /* dump? */
|
||||
for (i = 0; i < 50; i++) fprintf (of, "%c", bcd_to_ascii[val[i]&CHAR]) ;
|
||||
fprintf (of, "\n\t");
|
||||
for (i = 0; i < 50; i++) fprintf (of, (val[i]&WM)? "1": " ") ;
|
||||
return -(i - 1); }
|
||||
if (sw & SWMASK ('S')) { /* string? */
|
||||
i = 0;
|
||||
do {
|
||||
t = val[i++];
|
||||
fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]); }
|
||||
while ((i < LINE_LNT) && ((val[i] & WM) == 0));
|
||||
return -(i - 1); }
|
||||
if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;
|
||||
|
||||
if ((val[0] & WM) == 0) return STOP_NOWM; /* WM under op? */
|
||||
op = val[0]& CHAR; /* isolate op */
|
||||
flags = op_table[op]; /* get flags */
|
||||
for (ilnt = 1; ilnt < sim_emax; ilnt++) if (val[ilnt] & WM) break;
|
||||
if ((flags & (NOWM | HNOP)) && (ilnt > 7)) ilnt = 7; /* cs, swm, h, nop? */
|
||||
else if ((op == OP_B) && (ilnt > 4) && (val[4] == BCD_BLANK)) ilnt = 4;
|
||||
else if ((ilnt > 8) && (op != OP_NOP)) ilnt = 8; /* cap length */
|
||||
if (((flags & len_table[ilnt]) == 0) && /* valid lnt, */
|
||||
((op != OP_NOP) == 0)) return STOP_INVL; /* nop? */
|
||||
fprintf (of, "%s",opcode[op]); /* print opcode */
|
||||
if (ilnt > 2) { /* A address? */
|
||||
if (((flags & IO) || (op == OP_NOP)) && (val[1] == BCD_PERCNT))
|
||||
fprintf (of, " %%%c%c", bcd_to_ascii[val[2]], bcd_to_ascii[val[3]]);
|
||||
else fprint_addr (of, &val[1]); }
|
||||
if (ilnt > 5) fprint_addr (of, &val[4]); /* B address? */
|
||||
if ((ilnt == 2) || (ilnt == 5) || (ilnt == 8)) /* d character? */
|
||||
fprintf (of, " '%c", bcd_to_ascii[val[ilnt - 1]]);
|
||||
return -(ilnt - 1); /* return # chars */
|
||||
}
|
||||
|
||||
/* get_addr - get address + index pair */
|
||||
|
||||
t_stat get_addr (char *cptr, t_value *val)
|
||||
{
|
||||
int32 addr, index;
|
||||
t_stat r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get address */
|
||||
addr = get_uint (gbuf, 10, MAXMEMSIZE, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
if (*cptr != 0) { /* more? */
|
||||
cptr = get_glyph (cptr, gbuf, ' ');
|
||||
index = get_uint (gbuf, 10, 3, &r);
|
||||
if ((r != SCPE_OK) || (index == 0)) return SCPE_ARG; }
|
||||
else index = 0;
|
||||
if (*cptr != 0) return SCPE_ARG;
|
||||
val[0] = store_addr_h (addr);
|
||||
val[1] = store_addr_t (addr) | (index << V_ZONE);
|
||||
val[2] = store_addr_u (addr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* get_io - get I/O address */
|
||||
|
||||
t_stat get_io (char *cptr, t_value *val)
|
||||
{
|
||||
if ((cptr[0] != '%') || (cptr[3] != 0) || !isalnum (cptr[1]) ||
|
||||
!isalnum (cptr[2])) return SCPE_ARG;
|
||||
val[0] = BCD_PERCNT;
|
||||
val[1] = ascii_to_bcd[cptr[1]];
|
||||
val[2] = ascii_to_bcd[cptr[2]];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = > 0 error code
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 i, op, ilnt, t, cflag, wm_seen;
|
||||
extern int32 op_table[64], len_table[9];
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('C')) || (sw & SWMASK ('S')) || (*cptr == '~') ||
|
||||
((*cptr == '\'') && cptr++) || ((*cptr == '"') && cptr++)) {
|
||||
wm_seen = 0;
|
||||
for (i = 0; (i < sim_emax) && (*cptr != 0); ) {
|
||||
t = *cptr++; /* get character */
|
||||
if (cflag && (wm_seen == 0) && (t == '~')) wm_seen = WM;
|
||||
else if (uptr->flags & UNIT_BCD) {
|
||||
if (t < 040) return SCPE_ARG;
|
||||
val[i++] = ascii_to_bcd[t] | wm_seen;
|
||||
wm_seen = 0; }
|
||||
else val[i++] = t; }
|
||||
if ((i == 0) || wm_seen) return SCPE_ARG;
|
||||
return -(i-1); }
|
||||
|
||||
if (cflag == 0) return SCPE_ARG; /* CPU only */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (op = 0; op < 64; op++) /* look it up */
|
||||
if (opcode[op] && strcmp (gbuf, opcode[op]) == 0) break;
|
||||
if (op >= 64) return SCPE_ARG; /* successful? */
|
||||
val[0] = op | WM; /* store opcode */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */
|
||||
if (((op_table[op] && IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) ||
|
||||
(get_addr (gbuf, &val[1]) == SCPE_OK)) {
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */
|
||||
if (get_addr (gbuf, &val[4]) == SCPE_OK) {
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get d */
|
||||
ilnt = 7; } /* a and b addresses */
|
||||
else ilnt = 4; } /* a address */
|
||||
else ilnt = 1; /* no addresses */
|
||||
if ((gbuf[0] == '\'') || (gbuf[0] == '"')) { /* d character? */
|
||||
t = gbuf[1];
|
||||
if ((gbuf[2] != 0) || (*cptr != 0) || (t < 040))
|
||||
return SCPE_ARG; /* end and legal? */
|
||||
val[ilnt] = ascii_to_bcd[t]; /* save D char */
|
||||
ilnt = ilnt + 1; }
|
||||
else if (gbuf[0] != 0) return SCPE_ARG; /* not done? */
|
||||
if ((op_table[op] & len_table[ilnt]) == 0) return STOP_INVL;
|
||||
return -(ilnt - 1);
|
||||
}
|
||||
405
I1620/i1620_cd.c
405
I1620/i1620_cd.c
@@ -1,405 +0,0 @@
|
||||
/* i1620_cd.c: IBM 1622 card reader/punch
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
cdr 1622 card reader
|
||||
cdp 1622 card punch
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
|
||||
Cards are represented as ASCII text streams terminated by newlines.
|
||||
This allows cards to be created and edited as normal files.
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
|
||||
#define CD_LEN 80
|
||||
|
||||
extern uint8 M[MAXMEMSIZE];
|
||||
extern uint8 ind[NUM_IND];
|
||||
extern UNIT cpu_unit;
|
||||
extern int32 io_stop;
|
||||
|
||||
char cdr_buf[CD_LEN + 2];
|
||||
char cdp_buf[CD_LEN + 2];
|
||||
|
||||
t_stat cdr_reset (DEVICE *dptr);
|
||||
t_stat cdr_attach (UNIT *uptr, char *cptr);
|
||||
t_stat cdr_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat cdr_read (void);
|
||||
t_stat cdp_reset (DEVICE *dptr);
|
||||
t_stat cdp_write (uint32 len);
|
||||
t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump);
|
||||
|
||||
/* Card reader data structures
|
||||
|
||||
cdr_dev CDR descriptor
|
||||
cdr_unit CDR unit descriptor
|
||||
cdr_reg CDR register list
|
||||
*/
|
||||
|
||||
UNIT cdr_unit = {
|
||||
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) };
|
||||
|
||||
REG cdr_reg[] = {
|
||||
{ FLDATA (LAST, ind[IN_LAST], 0) },
|
||||
{ DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE cdr_dev = {
|
||||
"CDR", &cdr_unit, cdr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &cdr_reset,
|
||||
&cdr_boot, &cdr_attach, NULL };
|
||||
|
||||
/* CDP data structures
|
||||
|
||||
cdp_dev CDP device descriptor
|
||||
cdp_unit CDP unit descriptor
|
||||
cdp_reg CDP register list
|
||||
*/
|
||||
|
||||
UNIT cdp_unit = {
|
||||
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
|
||||
|
||||
REG cdp_reg[] = {
|
||||
{ DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE cdp_dev = {
|
||||
"CDP", &cdp_unit, cdp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &cdp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Data tables. The card reader presents unusual problems.
|
||||
- Unique codes needed for 11-2-8 (uses !) and 12-7-8 (uses ") .
|
||||
- Can punch both 11 (-) and 11-0 (uses ]).
|
||||
On input, the nul and nl generated by C are converted to
|
||||
spaces; tabs and line feeds are also converted to spaces.
|
||||
|
||||
/* Card reader (ASCII) to numeric (one digit) */
|
||||
|
||||
const char cdr_to_num[128] = {
|
||||
0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */
|
||||
-1, 0x00, 0x00, -1, -1, 0x00, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x00, 0x1A, 0x1F, 0x00, 0x1B, 0x0A, 0x0F, 0x0A, /* !"#$%&' */
|
||||
0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x1B, 0x01, /* ()*+,-./ */
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */
|
||||
0x08, 0x09, 0x00, 0x1E, 0x1E, 0x0B, 0x0E, 0x1A, /* 89:;<=>? */
|
||||
0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */
|
||||
0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */
|
||||
0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */
|
||||
0x07, 0x08, 0x09, 0x00, 0x0E, 0x10, 0x0F, 0x1F, /* XYZ[\]^_ */
|
||||
-1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* abcdefg */
|
||||
0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */
|
||||
0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */
|
||||
0x07, 0x08, 0x09, -1, -1, -1, -1, -1 }; /* xyz */
|
||||
|
||||
/* Numeric (flag + digit) to card punch (ASCII) */
|
||||
|
||||
const char num_to_cdp[32] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* 0 */
|
||||
'8', '9', '\'', ',', ' ', '&', ' ', '&',
|
||||
']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */
|
||||
'Q', 'R', '!', '$', -1, -1, -1, '"' };
|
||||
|
||||
/* Card reader (ASCII) to alphameric (two digits)
|
||||
|
||||
11-2-8 (!) reads as 5A
|
||||
11-7-8 (_) reads as 5F
|
||||
12-2-8 (?) reads inconsistently (here 02)
|
||||
12-6-8 (<) reads inconsistently (here 5E)
|
||||
12-7-8 (") reads as 5F
|
||||
*/
|
||||
|
||||
const char cdr_to_alp[128] = {
|
||||
0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */
|
||||
-1, 0x00, 0x00, -1, -1, 0x00, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x00, 0x5A, 0x5F, 0x60, 0x13, 0x0A, 0x0F, 0x0A, /* !"#$%&' */
|
||||
0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */
|
||||
0x78, 0x79, 0x70, 0x5E, 0x5E, 0x33, 0x0E, 0x02, /* 89:;<=>? */
|
||||
0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
|
||||
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */
|
||||
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */
|
||||
0x67, 0x68, 0x69, 0x40, 0x0E, 0x50, 0x0F, 0x5F, /* XYZ[\]^_ */
|
||||
-1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */
|
||||
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */
|
||||
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */
|
||||
0x67, 0x68, 0x69, -1, -1, -1, -1, -1 }; /* xyz */
|
||||
|
||||
/* Alphameric (two digits) to card punch (ASCII). Oddities:
|
||||
|
||||
02 -> 12-2-8 (?), symmetric
|
||||
07 -> 12-7-8 ("), reads as 5F
|
||||
12 -> 11-2-8 (!), reads as 5A
|
||||
15 -> 11,0 (]), reads as 50
|
||||
22 -> 0-2-8 ('), reads as 0A
|
||||
32 -> 2-8 (%), reads as 0A
|
||||
5B -> 11-3-8 (=), reads as 13
|
||||
6A -> 0-2-8 ('), reads as 0A
|
||||
6B -> 0-3-8 (,), reads as 23
|
||||
AA -> 0-2-8 ('), reads as 0A
|
||||
|
||||
There is no way to punch 0-5-8 (#), 0-6-8 (\),
|
||||
11-5-8 (]), 11-6-8 (;), 11-7-8 (_),
|
||||
12-5-8 ([), or 12-6-8 (<)
|
||||
*/
|
||||
|
||||
const char alp_to_cdp[256] = {
|
||||
' ', -1, '?', '.', ')', -1, -1, '"', /* 00 */
|
||||
-1, -1, '\'', -1, -1, -1, -1, '&',
|
||||
'+', -1, '!', '$', '*', ']', -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
'-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, '%', '=', '@', ':', ' ', -1, /* 30 */
|
||||
-1, -1, '\'', -1, -1, -1, -1, '&',
|
||||
-1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
|
||||
'H', 'I', -1, -1, -1, -1, -1, -1,
|
||||
'_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
|
||||
'Q', 'R', '?', '=', -1, -1, -1, '"',
|
||||
-1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
|
||||
'Y', 'Z', '\'', ',', -1, -1, -1, -1,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
|
||||
'8', '9', -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
|
||||
-1, -1, '\'', -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
/* Card reader IO routine
|
||||
|
||||
- Hard errors stop the operation and halt the system.
|
||||
- Invalid characters place a blank in memory and set RDCHK.
|
||||
If IO stop is set, the system halts at the end of the operation.
|
||||
*/
|
||||
|
||||
t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
int32 i;
|
||||
int8 cdc;
|
||||
t_stat r, inv = SCPE_OK;
|
||||
|
||||
switch (op) { /* case on op */
|
||||
case OP_RN: /* read numeric */
|
||||
r = cdr_read (); /* fill reader buf */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
for (i = 0; i < CD_LEN; i++) { /* transfer to mem */
|
||||
cdc = cdr_to_num[cdr_buf[i]]; /* translate */
|
||||
if (cdc < 0) { /* invalid? */
|
||||
ind[IN_RDCHK] = 1; /* set read check */
|
||||
inv = STOP_INVCHR; /* set return status */
|
||||
cdc = 0; }
|
||||
M[pa] = cdc; /* store digit */
|
||||
PP (pa); } /* incr mem addr */
|
||||
break;
|
||||
case OP_RA: /* read alphameric */
|
||||
r = cdr_read (); /* fill reader buf */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
for (i = 0; i < CD_LEN; i++) { /* transfer to mem */
|
||||
cdc = cdr_to_alp[cdr_buf[i]]; /* translate */
|
||||
if (cdc < 0) { /* invalid? */
|
||||
ind[IN_RDCHK] = 1; /* set read check */
|
||||
inv = STOP_INVCHR; /* set return status */
|
||||
cdc = 0; };
|
||||
M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */
|
||||
M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT);
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
CRETIOE (io_stop, inv);
|
||||
}
|
||||
|
||||
/* Fill card reader buffer - all errors are hard errors */
|
||||
|
||||
t_stat cdr_read (void)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
ind[IN_LAST] = 0; /* clear last card */
|
||||
if ((cdr_unit.flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_RDCHK] = 1; /* no, error */
|
||||
return SCPE_UNATT; }
|
||||
|
||||
for (i = 0; i < CD_LEN + 1; i++) cdr_buf[i] = ' '; /* clear buffer */
|
||||
fgets (cdr_buf, CD_LEN, cdr_unit.fileref); /* read card */
|
||||
if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */
|
||||
if (ferror (cdr_unit.fileref)) { /* error? */
|
||||
ind[IN_RDCHK] = 1; /* set read check */
|
||||
perror ("CDR I/O error");
|
||||
clearerr (cdr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */
|
||||
getc (cdr_unit.fileref); /* see if more */
|
||||
if (feof (cdr_unit.fileref)) ind[IN_LAST] = 1; /* eof? set last */
|
||||
fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); /* "backspace" */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Card reader attach */
|
||||
|
||||
t_stat cdr_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
ind[IN_LAST] = 0; /* clear last card */
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
|
||||
/* Card reader reset */
|
||||
|
||||
t_stat cdr_reset (DEVICE *dptr)
|
||||
{
|
||||
ind[IN_LAST] = 0; /* clear last card */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
const static uint8 boot_rom[] = {
|
||||
3, 6, 1, 9, 9, 0, 1, 0, 0, 5, 0, 0, /* RNCD 19901 */
|
||||
2, 5, 0, 0, 0, 8, 0, 1, 9, 9, 1, 0x10, /* TD 80,-19910 */
|
||||
3, 1, 1, 9, 9, 0, 0x15, 1, 9, 9, 2, 0, /* TR -19905,19920 */
|
||||
2, 5, 1, 9, 9, 1, 0x10, 0, 0, 0, 8, 0, /* TD -19910,80 */
|
||||
4, 9, 1, 9, 9, 1, 0x15, 0, 0, 0, 0, 0 }; /* BR -19915 */
|
||||
|
||||
#define BOOT_START 0
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
|
||||
|
||||
t_stat cdr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if ((cpu_unit.flags & IF_IA) == 0) return SCPE_NOFNC; /* must have IA */
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Card punch IO routine
|
||||
|
||||
- Hard errors stop the operation and halt the system.
|
||||
- Invalid characters stop the operation and set WRCHK.
|
||||
If IO stop is set, the system halts.
|
||||
*/
|
||||
|
||||
t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
int32 i;
|
||||
int8 cdc;
|
||||
uint8 z, d;
|
||||
|
||||
switch (op) { /* decode op */
|
||||
case OP_DN:
|
||||
return cdp_num (pa, 20000 - (pa % 20000), TRUE); /* dump numeric */
|
||||
case OP_WN:
|
||||
return cdp_num (pa, CD_LEN, FALSE); /* write numeric */
|
||||
case OP_WA:
|
||||
for (i = 0; i < CD_LEN; i++) { /* one card */
|
||||
d = M[pa] & DIGIT; /* get digit pair */
|
||||
z = M[pa - 1] & DIGIT;
|
||||
cdc = alp_to_cdp[(z << 4) | d]; /* translate */
|
||||
if (cdc < 0) { /* bad char? */
|
||||
ind[IN_WRCHK] = 1; /* set write check */
|
||||
CRETIOE (io_stop, STOP_INVCHR); }
|
||||
cdp_buf[i] = cdc; /* store in buf */
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
return cdp_write (CD_LEN); /* punch buffer */
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Punch card numeric */
|
||||
|
||||
t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump)
|
||||
{
|
||||
int32 i, ncd, len;
|
||||
uint8 d;
|
||||
int8 cdc;
|
||||
t_stat r;
|
||||
|
||||
ncd = ndig / CD_LEN; /* number of cards */
|
||||
while (ncd-- >= 0) { /* until done */
|
||||
len = (ncd >= 0)? CD_LEN: (ndig % CD_LEN); /* card length */
|
||||
if (len == 0) break;
|
||||
for (i = 0; i < len; i++) { /* one card */
|
||||
d = M[pa] & (FLAG | DIGIT); /* get char */
|
||||
if (dump && (d == FLAG)) cdc = '-'; /* dump? F+0 is diff */
|
||||
else cdc = num_to_cdp[d]; /* translate */
|
||||
if (cdc < 0) { /* bad char? */
|
||||
ind[IN_WRCHK] = 1; /* set write check */
|
||||
CRETIOE (io_stop, STOP_INVCHR); } /* stop */
|
||||
cdp_buf[i] = cdc; /* store in buf */
|
||||
PP (pa); } /* incr mem addr */
|
||||
r = cdp_write (len); /* punch card */
|
||||
if (r != SCPE_OK) return r; } /* error? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write punch card buffer - all errors are hard errors */
|
||||
|
||||
t_stat cdp_write (uint32 len)
|
||||
{
|
||||
if ((cdp_unit.flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_WRCHK] = 1; /* no, error */
|
||||
return SCPE_UNATT; }
|
||||
|
||||
while ((len > 0) && (cdp_buf[len - 1] == ' ')) --len; /* trim spaces */
|
||||
cdp_buf[len] = '\n'; /* newline, null */
|
||||
cdp_buf[len + 1] = 0;
|
||||
|
||||
if (fputs (cdp_buf, cdp_unit.fileref) == EOF) { /* write card */
|
||||
ind[IN_WRCHK] = 1; /* error? */
|
||||
perror ("CDP I/O error");
|
||||
clearerr (cdp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset card punch */
|
||||
|
||||
t_stat cdp_reset (DEVICE *dptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
1884
I1620/i1620_cpu.c
1884
I1620/i1620_cpu.c
File diff suppressed because it is too large
Load Diff
@@ -1,221 +0,0 @@
|
||||
/* i1620_defs.h: IBM 1620 simulator definitions
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This simulator is based on the 1620 simulator written by Geoff Kuenning.
|
||||
I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate
|
||||
Archives for their help in gathering documentation about the IBM 1620.
|
||||
|
||||
18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal)
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_HALT 1 /* HALT */
|
||||
#define STOP_IBKPT 2 /* breakpoint */
|
||||
#define STOP_INVINS 3 /* invalid instruction */
|
||||
#define STOP_INVDIG 4 /* invalid digit */
|
||||
#define STOP_INVCHR 5 /* invalid char */
|
||||
#define STOP_INVIND 6 /* invalid indicator */
|
||||
#define STOP_INVPDG 7 /* invalid P addr digit */
|
||||
#define STOP_INVPAD 8 /* invalid P addr */
|
||||
#define STOP_INVPIA 9 /* invalid P indir addr */
|
||||
#define STOP_INVQDG 10 /* invalid Q addr digits */
|
||||
#define STOP_INVQAD 11 /* invalid Q addr */
|
||||
#define STOP_INVQIA 12 /* invalid Q indir addr */
|
||||
#define STOP_INVIO 13 /* invalid IO address */
|
||||
#define STOP_INVRTN 14 /* invalid return */
|
||||
#define STOP_INVFNC 15 /* invalid function */
|
||||
#define STOP_INVIAD 16 /* invalid instr addr */
|
||||
#define STOP_INVSEL 17 /* invalid select */
|
||||
#define STOP_INVIDX 18 /* invalid index instr */
|
||||
#define STOP_INVEAD 19 /* invalid even addr */
|
||||
#define STOP_INVDCF 20 /* invalid DCF addr */
|
||||
#define STOP_INVDRV 21 /* invalid disk drive */
|
||||
#define STOP_INVDSC 22 /* invalid disk sector */
|
||||
#define STOP_INVDCN 23 /* invalid disk count */
|
||||
#define STOP_INVDBA 24 /* invalid disk buf addr */
|
||||
#define STOP_DACERR 25 /* disk addr comp err */
|
||||
#define STOP_DWCERR 26 /* disk wr check err */
|
||||
#define STOP_CYOERR 27 /* cylinder ovflo err */
|
||||
#define STOP_WRLERR 28 /* wrong rec lnt err */
|
||||
#define STOP_CCT 29 /* runaway CCT */
|
||||
#define STOP_FWRAP 30 /* field wrap */
|
||||
#define STOP_RWRAP 31 /* record wrap */
|
||||
#define STOP_NOCD 32 /* no card in reader */
|
||||
#define STOP_OVERFL 33 /* overflow */
|
||||
#define STOP_EXPCHK 34 /* exponent error */
|
||||
#define STOP_WRADIS 35 /* write addr disabled */
|
||||
#define STOP_FPLNT 36 /* invalid fp length */
|
||||
#define STOP_FPUNL 37 /* fp lengths unequal */
|
||||
#define STOP_FPMF 38 /* no flag on exp */
|
||||
#define STOP_FPDVZ 39 /* divide by zero */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 60000 /* max mem size */
|
||||
#define MEMSIZE (cpu_unit.capac) /* act memory size */
|
||||
|
||||
/* Processor parameters */
|
||||
|
||||
#define INST_LEN 12 /* inst length */
|
||||
#define ADDR_LEN 5 /* addr length */
|
||||
#define MUL_TABLE 100 /* multiply table */
|
||||
#define MUL_TABLE_LEN 200
|
||||
#define ADD_TABLE 300 /* add table */
|
||||
#define ADD_TABLE_LEN 100
|
||||
#define IDX_A 300 /* index A base */
|
||||
#define IDX_B 340 /* index B base */
|
||||
#define PROD_AREA 80 /* product area */
|
||||
#define PROD_AREA_LEN 20 /* product area */
|
||||
#define PROD_AREA_END (PROD_AREA + PROD_AREA_LEN)
|
||||
|
||||
/* Branch indicator codes */
|
||||
|
||||
#define NUM_IND 100 /* number of indicators */
|
||||
|
||||
#define IN_SW1 1 /* sense switch 1 */
|
||||
#define IN_SW2 2 /* sense switch 2 */
|
||||
#define IN_SW3 3 /* sense switch 3 */
|
||||
#define IN_SW4 4 /* sense switch 4 */
|
||||
#define IN_RDCHK 6 /* read check (I/O error) */
|
||||
#define IN_WRCHK 7 /* write check (I/O error) */
|
||||
#define IN_LAST 9 /* last card was just read */
|
||||
#define IN_HP 11 /* high or positive result */
|
||||
#define IN_EZ 12 /* equal or zero result */
|
||||
#define IN_HPEZ 13 /* high/positive or equal/zero */
|
||||
#define IN_OVF 14 /* overflow */
|
||||
#define IN_EXPCHK 15 /* floating exponent check */
|
||||
#define IN_MBREVEN 16 /* even parity check */
|
||||
#define IN_MBRODD 17 /* odd parity check */
|
||||
#define IN_ANYCHK 19 /* any of read, write, even/odd */
|
||||
#define IN_PRCHK 25 /* printer check */
|
||||
#define IN_IXN 30 /* IX neither */
|
||||
#define IN_IXA 31 /* IX A band */
|
||||
#define IN_IXB 32 /* IX B band */
|
||||
#define IN_PRCH9 33 /* printer chan 9 */
|
||||
#define IN_PRCH12 34 /* printer chan 12 */
|
||||
#define IN_PRBSY 35 /* printer busy */
|
||||
#define IN_DACH 36 /* disk addr/data check */
|
||||
#define IN_DWLR 37 /* disk rec length */
|
||||
#define IN_DCYO 38 /* disk cyl overflow */
|
||||
#define IN_DERR 39 /* disk any error */
|
||||
|
||||
/* I/O channel codes */
|
||||
|
||||
#define NUM_IO 100 /* number of IO chan */
|
||||
|
||||
#define IO_TTY 1 /* console typewriter */
|
||||
#define IO_PTP 2 /* paper-tape punch */
|
||||
#define IO_PTR 3 /* paper-tape reader */
|
||||
#define IO_CDP 4 /* card punch */
|
||||
#define IO_CDR 5 /* card reader */
|
||||
#define IO_DSK 7 /* disk */
|
||||
#define IO_LPT 9 /* line printer */
|
||||
#define IO_BTP 32 /* binary ptp */
|
||||
#define IO_BTR 33 /* binary ptr */
|
||||
|
||||
#define LPT_WIDTH 120 /* line print width */
|
||||
#define CCT_LNT 132 /* car ctrl length */
|
||||
|
||||
#define CRETIOE(f,c) return ((f)? (c): SCPE_OK)
|
||||
|
||||
/* Memory representation: flag + BCD digit per byte */
|
||||
|
||||
#define FLAG 0x10
|
||||
#define DIGIT 0x0F
|
||||
#define REC_MARK 0xA
|
||||
#define NUM_BLANK 0xC
|
||||
#define GRP_MARK 0xF
|
||||
#define BAD_DIGIT(x) ((x) > 9)
|
||||
|
||||
/* Instruction format */
|
||||
|
||||
#define I_OP 0 /* opcode */
|
||||
#define I_P 2 /* P start */
|
||||
#define I_PL 6 /* P end */
|
||||
#define I_Q 7 /* Q start */
|
||||
#define I_QL 11 /* Q end */
|
||||
#define I_IO 8 /* IO select */
|
||||
#define I_BR 8 /* indicator select */
|
||||
#define I_CTL 10 /* control select */
|
||||
#define I_SEL 11 /* BS select */
|
||||
|
||||
#define ADDR_A(x,a) ((((x) + (a)) >= MEMSIZE)? ((x) + (a) - MEMSIZE): ((x) + (a)))
|
||||
#define ADDR_S(x,a) (((x) < (a))? ((x) - (a) + MEMSIZE): ((x) - (a)))
|
||||
#define PP(x) x = ADDR_A(x,1)
|
||||
#define MM(x) x = ADDR_S(x,1)
|
||||
|
||||
/* CPU options, stored in cpu_unit.flags */
|
||||
/* Decoding flags must be part of the same definition set */
|
||||
|
||||
#define UNIT_SCP ((1 << UNIT_V_UF) - 1) /* mask of SCP flags */
|
||||
#define IF_MII (1 << (UNIT_V_UF + 0)) /* model 2 */
|
||||
#define IF_DIV (1 << (UNIT_V_UF + 1)) /* automatic divide */
|
||||
#define IF_IA (1 << (UNIT_V_UF + 2)) /* indirect addressing */
|
||||
#define IF_EDT (1 << (UNIT_V_UF + 3)) /* edit */
|
||||
#define IF_FP (1 << (UNIT_V_UF + 4)) /* floating point */
|
||||
#define IF_BIN (1 << (UNIT_V_UF + 5)) /* binary */
|
||||
#define IF_IDX (1 << (UNIT_V_UF + 6)) /* indexing */
|
||||
#define IF_VPA (1 << (UNIT_V_UF + 7)) /* valid P addr */
|
||||
#define IF_VQA (1 << (UNIT_V_UF + 8)) /* valid Q addr */
|
||||
#define IF_4QA (1 << (UNIT_V_UF + 9)) /* 4 char Q addr */
|
||||
#define IF_NQX (1 << (UNIT_V_UF + 10)) /* no Q indexing */
|
||||
#define IF_IMM (1 << (UNIT_V_UF + 11)) /* immediate */
|
||||
#define UNIT_BCD (1 << (UNIT_V_UF + 12)) /* BCD coded */
|
||||
#define UNIT_MSIZE (1 << (UNIT_V_UF + 13)) /* fake flag */
|
||||
#define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX)
|
||||
#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP)
|
||||
#define MI_STD (IF_DIV + IF_IA + IF_EDT)
|
||||
#define MII_OPT (ALLOPT)
|
||||
#define MII_STD (IF_DIV + IF_IA + IF_EDT + IF_BIN + IF_IDX)
|
||||
|
||||
/* Add status codes */
|
||||
|
||||
#define ADD_NOCRY 0 /* no carry out */
|
||||
#define ADD_CARRY 1 /* carry out */
|
||||
#define ADD_SIGNC 2 /* sign change */
|
||||
|
||||
/* Opcodes */
|
||||
|
||||
enum opcodes {
|
||||
OP_FADD = 1, OP_FSUB, OP_FMUL, /* 00 - 09 */
|
||||
OP_FSL = 5, OP_TFL, OP_BTFL, OP_FSR, OP_FDIV,
|
||||
OP_BTAM = 10, OP_AM, OP_SM, OP_MM, OP_CM, /* 10 - 19 */
|
||||
OP_TDM, OP_TFM, OP_BTM, OP_LDM, OP_DM,
|
||||
OP_BTA = 20, OP_A, OP_S, OP_M, OP_C, /* 20 - 29 */
|
||||
OP_TD, OP_TF, OP_BT, OP_LD, OP_D,
|
||||
OP_TRNM = 30, OP_TR, OP_SF, OP_CF, OP_K, /* 30 - 39 */
|
||||
OP_DN, OP_RN, OP_RA, OP_WN, OP_WA,
|
||||
OP_NOP = 41, OP_BB, OP_BD, OP_BNF, /* 40 - 49 */
|
||||
OP_BNR, OP_BI, OP_BNI, OP_H, OP_B,
|
||||
OP_BNG = 55,
|
||||
OP_BS = 60, OP_BX, OP_BXM, OP_BCX, OP_BCXM, /* 60 - 69 */
|
||||
OP_BLX, OP_BLXM, OP_BSX,
|
||||
OP_MA = 70, OP_MF, OP_TNS, OP_TNF, /* 70 - 79 */
|
||||
/* 80 - 89 */
|
||||
OP_BBT = 90, OP_BMK, OP_ORF, OP_ANDF, OP_CPLF, /* 90 - 99 */
|
||||
OP_EORF, OP_OTD, OP_DTO };
|
||||
@@ -1,518 +0,0 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: IBM 1620 Simulator Usage
|
||||
Date: 15-Apr-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2003, written by Robert M Supnik
|
||||
Copyright (c) 1993-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This memorandum documents the IBM 1620 simulator. This simulator is based on
|
||||
Geoff Kuenning's 1620 simulator, which is used by permission.
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_sock.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/i1620/ i1620_defs.h
|
||||
i1620_cpu.c
|
||||
i1620_fp.c
|
||||
i1620_tty.c
|
||||
i1620_pt.c
|
||||
i1620_cd.c
|
||||
i1620_lp.c
|
||||
i1620_dp.c
|
||||
i1620_sys.c
|
||||
|
||||
2. IBM 1620 Features
|
||||
|
||||
The IBM 1620 simulator is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU IBM 1620 Model 1 or Model 2 CPU with 20K to 60K of memory
|
||||
Model 1 options: indirect addressing, automatic divide,
|
||||
edit instructions, floating point
|
||||
Model 2 options: indexing, binary capability, floating point
|
||||
TTY IBM console terminal
|
||||
PTR IBM 1621 paper tape reader
|
||||
PTP IBM 1624 paper tape punch
|
||||
CDR,CDP IBM 1622 card reader/punch
|
||||
LPT IBM 1443 line printer
|
||||
DP IBM 1311 disk pack with four drives
|
||||
|
||||
The IBM 1620 simulator implements many unique stop conditions. On almost
|
||||
any kind of error the simulator stops:
|
||||
|
||||
unimplemented opcode
|
||||
reference to non-existent device
|
||||
invalid digit
|
||||
invalid alphameric character
|
||||
invalid P address digit
|
||||
invalid Q address digit
|
||||
indirect address limit exceeded
|
||||
invalid odd address
|
||||
invalid even address
|
||||
invalid function
|
||||
invalid indicator
|
||||
invalid return address register
|
||||
skip to unpunched carriage control tape channel
|
||||
card reader hopper empty
|
||||
overflow with arithmetic stop switch set
|
||||
I/O error with I/O stop switch set
|
||||
invalid disk drive
|
||||
invalid disk sector address
|
||||
invalid disk sector count
|
||||
invalid disk buffer address
|
||||
disk address compare error
|
||||
disk cylinder overflow error
|
||||
disk write check error
|
||||
field exceeds memory
|
||||
record exceeds memory
|
||||
floating point mantissa exceeds maximum length
|
||||
floating point mantissas not the same length
|
||||
floating point exponent check with arithmetic stop switch set
|
||||
floating point exponent missing high flag
|
||||
|
||||
The LOAD command is used to load a line printer carriage-control tape.
|
||||
The DUMP command is not implemented.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
The CPU options include the CPU model (Model 1 or Model 2), a number of
|
||||
special features, and the size of main memory.
|
||||
|
||||
SET CPU IA enable indirect addressing
|
||||
SET CPU NOIA disable indirect addressing
|
||||
SET CPU EDT enable extra editing instructions
|
||||
SET CPU NOEDT disable extra editing instructions
|
||||
SET CPU DIV enable divide instructions
|
||||
SET CPU NODIV disable divide instructions
|
||||
SET CPU IDX enable indexing
|
||||
SET CPU NOIDX disable indexing
|
||||
SET CPU BIN enable binary instructions
|
||||
SET CPU NOBIN disable binary instructions
|
||||
SET CPU FP enable floating point instructions
|
||||
SET CPU NOFP disable floating point instructions
|
||||
SET CPU MOD1 set Model 1
|
||||
SET CPU MOD2 set Model 2
|
||||
SET CPU 20K set memory size = 20K
|
||||
SET CPU 40K set memory size = 40K
|
||||
SET CPU 60K set memory size = 60K
|
||||
|
||||
Model 1 options include IA, EDT, DIV, and FP; the first three are on by
|
||||
default. Model 2 options include IDX, BIN, and FP; IA, EDT, and DIV are
|
||||
standard on the Model 2.
|
||||
|
||||
If memory size is being reduced, and the memory being truncated contains
|
||||
non-zero data, the simulator asks for confirmation. Data in the truncated
|
||||
portion of memory is lost. Initially, the CPU is a Model 1, memory size is
|
||||
20K, and indirect addressing, editing instructions, and divide are enabled.
|
||||
|
||||
Memory is implemented as 5 bit BCD digits, as follows:
|
||||
|
||||
4 3 2 1 0
|
||||
|
||||
flag 8 4 2 1
|
||||
<-------- digit -------->
|
||||
|
||||
In BCD, the decimal digits 0-9 are (hex) values 0x0, 0x1, 0x2, 0x3, 0x4,
|
||||
0x5, 0x6, 0x7, 0x8, 0x9, respectively. 0xA is record mark, 0xC non-
|
||||
punching blank, and 0xF group mark, respectively.
|
||||
|
||||
CPU registers include the visible state of the processor. The 1620 has no
|
||||
interrupt system.
|
||||
|
||||
name size comments
|
||||
|
||||
IR1 16 instruction storage address register (PC)
|
||||
IR2 16 return register
|
||||
PR1 16 processor register 1
|
||||
PAR 16 P address register (OR2)
|
||||
QAR 16 Q address register (OR1)
|
||||
SS1 1 sense switch 1
|
||||
SS2 1 sense switch 2
|
||||
SS3 1 sense switch 3
|
||||
SS4 1 sense switch 4
|
||||
HP 1 high/positive indicator
|
||||
EZ 1 equal/zero indicator
|
||||
ARCHK 1 arithmetic check (overflow) indicator
|
||||
EXPCHK 1 exponent check indicator
|
||||
RDCHK 1 read check indicator
|
||||
WRCHK 1 write check indicator
|
||||
ARSTOP 1 arithmetic check stop switch
|
||||
IOSTOP 1 I/O check stop switch
|
||||
IND[0:99] 1 indicator array
|
||||
IAE 1 indirect address enable (Model 2 only)
|
||||
IDXE 1 indexing enable (Model 2 only)
|
||||
IDXB 1 indexing band select (Model 2 only)
|
||||
IR1Q[0:63] 16 IR1 prior to last branch;
|
||||
most recent IR1 change first
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 Console Typewriter (TTY)
|
||||
|
||||
The console typewriter (TTY) is a half-duplex console. The typewriter
|
||||
registers are:
|
||||
|
||||
name size comments
|
||||
|
||||
COL 7 current column
|
||||
TIME 24 polling interval
|
||||
|
||||
When the 1620 CPU requests input from the keyboard, a reverse apostrophe
|
||||
(`) is printed. The CPU hangs waiting for input until the return/enter
|
||||
key is pressed. The typewriter has no errors.
|
||||
|
||||
2.3 1621 Paper Tape Reader (PTR)
|
||||
|
||||
The paper tape reader (PTR) reads data from a disk file. The POS register
|
||||
specifies the number of the next data item to be read. Thus, by changing
|
||||
POS, the user can backspace or advance the reader.
|
||||
|
||||
The paper tape reader supports the BOOT command. BOOT PTR starts the
|
||||
standard paper tape boot sequence at location 0.
|
||||
|
||||
The paper tape reader implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
POS 32 position in the input file
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error IOCHK processed as
|
||||
|
||||
not attached x set RDCHK indicator, report error, stop
|
||||
|
||||
end of file x set RDCHK indicator, report error, stop
|
||||
|
||||
OS I/O error x set RDCHK indicator, report error, stop
|
||||
|
||||
parity error 1 set RDCHK indicator, report error, stop
|
||||
0 set RDCHK indicator
|
||||
|
||||
2.4 1624 Paper Tape Punch (PTP)
|
||||
|
||||
The paper tape punch (PTP) writes data to a disk file. The POS register
|
||||
specifies the number of the next data item to be written. Thus, by
|
||||
changing POS, the user can backspace or advance the punch.
|
||||
|
||||
The paper tape punch implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
POS 32 position in the output file
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error IOCHK processed as
|
||||
|
||||
not attached x set WRCHK indicator, report error, stop
|
||||
|
||||
OS I/O error x set WRCHK indicator, report error, stop
|
||||
|
||||
invalid char 1 set WRCHK indicator, report error, stop
|
||||
0 set WRCHK indicator
|
||||
|
||||
2.5 1622 Card Reader/Punch (CDR, CDP)
|
||||
|
||||
The IBM 1402 card/reader punch is simulated as two independent devices:
|
||||
the card reader (CDR) and the card punch (CDP).
|
||||
|
||||
The card reader supports the BOOT command. BOOT CDR starts the standard
|
||||
card boot sequence at location 0.
|
||||
|
||||
The card reader reads data from a disk file, while the punch writes data
|
||||
to a disk file. Cards are simulated as ASCII text lines with terminating
|
||||
newlines. For each unit, the POS register specifies the number of the
|
||||
next data item to be read or written. Thus, by changing POS, the user
|
||||
can backspace or advance these devices.
|
||||
|
||||
The card reader registers are:
|
||||
|
||||
name size comments
|
||||
|
||||
LAST 1 last card indicator
|
||||
POS 32 position
|
||||
|
||||
The card punch registes are:
|
||||
|
||||
name size comments
|
||||
|
||||
POS 32 position
|
||||
|
||||
Card reader error handling is as follows:
|
||||
|
||||
error IOCHK processed as
|
||||
|
||||
end of file x set RDCHK indicator, report error, stop
|
||||
|
||||
not attached x set RDCHK indicator, report error, stop
|
||||
|
||||
OS I/O error x set RDCHK indicator, report error, stop
|
||||
|
||||
invalid char 1 set RDCHK indicator, report error, stop
|
||||
0 set RDCHK indicator
|
||||
|
||||
Card punch error handling is as follows:
|
||||
|
||||
error IOCHK processed as
|
||||
|
||||
not attached x set WRCHK indicator, report error, stop
|
||||
|
||||
OS I/O error x set WRCHK indicator, report error, stop
|
||||
|
||||
invalid char 1 set WRCHK indicator, report error, stop
|
||||
0 set WRCHK indicator
|
||||
|
||||
2.6 1443 Line Printer (LPT)
|
||||
|
||||
The IBM 1443 line printer (LPT) writes its data, converted to ASCII, to
|
||||
a disk file. The line printer can be programmed with a carriage control
|
||||
tape. The LOAD command loads a new carriage control tape:
|
||||
|
||||
LOAD <file> load carriage control tape file
|
||||
|
||||
The format of a carriage control tape consists of multiple lines. Each
|
||||
line contains an optional repeat count, enclosed in parentheses, optionally
|
||||
followed by a series of column numbers separated by commas. Column numbers
|
||||
must be between 1 and 12; a column number of zero denotes top of form. The
|
||||
following are all legal carriage control specifications:
|
||||
|
||||
<blank line> no punch
|
||||
(5) 5 lines with no punches
|
||||
1,5,7,8 columns 1, 5, 7, 8 punched
|
||||
(10)2 10 lines with column 2 punched
|
||||
1,0 column 1 punched; top of form
|
||||
|
||||
The default form is 66 lines long, with column 1 and the top of form mark
|
||||
on line 1, and the rest blank.
|
||||
|
||||
The line printer registers are:
|
||||
|
||||
name size comments
|
||||
|
||||
LBUF[0:119] 7 line buffer
|
||||
BPTR 7 buffer pointer
|
||||
PCTL 8 saved print control directive
|
||||
PRCHK 1 print check indicator
|
||||
PRCH9 1 channel 9 indicator
|
||||
PRCH12 1 channel 12 indicator
|
||||
POS 32 position
|
||||
CCT[0:131] 32 carriage control tape array
|
||||
CCTP 8 carriage control tape pointer
|
||||
CCTL 8 carriage control tape length (read only)
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error IOCHK processed as
|
||||
|
||||
not attached x set PRCHK, WRCHK indicators, report error, stop
|
||||
|
||||
OS I/O error x set PRCHK, WRCHK indicators, report error, stop
|
||||
|
||||
invalid char 1 set PRCHK, WRCHK indicator, report error, stop
|
||||
0 set PRCHK, WRCHK indicator
|
||||
|
||||
2.7 1311 Disk Pack (DP)
|
||||
|
||||
The disk pack controller supports 4 drives, numbered 0 through 3. Disk
|
||||
pack options include the ability to enable address writing (formatting).
|
||||
|
||||
SET DPn ADDROFF set unit n address enable off
|
||||
SET DPn ADDRON set unit n address enable on
|
||||
|
||||
Units can also be set ONLINE or OFFLINE.
|
||||
|
||||
Unlike most simulated disks, the 1311 includes explicit representation
|
||||
for sector addresses. This is to support non-standard formats, such as
|
||||
the inclusion of the drive number in the sector address. As a result,
|
||||
1311 sectors are 105 digits long: 5 address digits and 100 data digits.
|
||||
If the 1311 has not been formatted, the addresses are zeroes and are
|
||||
synthesized, if needed, based on the sector number.
|
||||
|
||||
The disk pack controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
ADCHK 1 address check (compare error) indicator
|
||||
WLRC 1 wrong length record check indicator
|
||||
CYLO 1 cylinder overflow check indicator
|
||||
ERR 1 disk error indicator
|
||||
DPSTOP 1 disk check stop
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error DPCHK processed as
|
||||
|
||||
not attached x set ERR indicator, report error, stop
|
||||
|
||||
1311 data files are buffered in memory; therefore, end of file and OS
|
||||
I/O errors cannot occur.
|
||||
|
||||
2.8 Symbolic Display and Input
|
||||
|
||||
The IBM 1620 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-c display as single character (alphameric
|
||||
for CPU and DP, ASCII for others)
|
||||
-s display as flag terminated numeric string
|
||||
(CPU and DP only)
|
||||
-m display instruction mnemonics
|
||||
(CPU and DP only)
|
||||
-d display 50 characters per line, with word
|
||||
marks denoted by "_" on the line above
|
||||
|
||||
In a CPU string display, word marks are denoted by ~.
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or -c character (alphameric for CPU and DP, ASCII
|
||||
for others)
|
||||
" or -s numeric string (CPU and DP only)
|
||||
alphabetic instruction mnemonic (CPU and DP only)
|
||||
numeric octal number
|
||||
|
||||
Instruction input is free format and consists of an opcode and up to
|
||||
three operands:
|
||||
|
||||
op {+/-}ppppp{(idx)},{+-}qqqqq{(idx)},flags
|
||||
|
||||
The p address and, if present, the q address, are always decimal. A
|
||||
plus sign is ignored; a minus sign denotes indirect addressing (or a
|
||||
negative immediate operand). If indexing is enabled, addresses may
|
||||
be indexed; index registers are decimal numbers between 1 and 7. The
|
||||
flags field is used to set extra flags on the instruction. It consists
|
||||
of digit numbers in ascending order, with no separators. For example,
|
||||
|
||||
AM -12345(5),67890,110
|
||||
|
||||
translates into
|
||||
_ _ ___ _
|
||||
111234567890
|
||||
|
||||
The flag over digits 3 and 5 specify the P index register; the flag
|
||||
over digit 6 specifies the P indirect address; the flag over digit 7
|
||||
marks the end of the immediate Q operand; and the flags over digits
|
||||
1 and 10 are specified by the third field.
|
||||
|
||||
2.9 Character Sets
|
||||
|
||||
The IBM 1620 uses single digits to represent numbers, and pairs of
|
||||
digits to represent characters (alphameric coding). Only a small
|
||||
number of the 256 possible alphameric codings have legitimate values.
|
||||
Further, the translation between alphameric and devices varied from
|
||||
device to device. The simulator implements a code called 1620 ASCII,
|
||||
which allows all 64 possible card codes to be represented by upper
|
||||
case ASCII characters. In addition, lower case alphabetic characters
|
||||
are accepted on input as equivalent to upper case.
|
||||
|
||||
Card code PT code RA RN LPT WA ASCII representation
|
||||
|
||||
<blank> C 0 0 blank blank
|
||||
12 XOC 10 0 + +
|
||||
11 X 20 F+0 - -
|
||||
0 O 70 0 0 0
|
||||
1 1 71 1 1 1
|
||||
2 2 72 2 2 2
|
||||
3 C21 73 3 3 3
|
||||
4 4 74 4 4 4
|
||||
5 C41 75 5 5 5
|
||||
6 C42 76 6 6 6
|
||||
7 421 77 7 7 7
|
||||
8 8 78 8 8 8
|
||||
9 C81 79 9 9 9
|
||||
12 + 1 XO1 41 1 A A
|
||||
12 + 2 XO2 42 2 B B
|
||||
12 + 3 XOC21 43 3 C C
|
||||
12 + 4 XO4 44 4 D D
|
||||
12 + 5 XOC41 45 5 E E
|
||||
12 + 6 XOC42 46 6 F F
|
||||
12 + 7 XO421 47 7 G G
|
||||
12 + 8 XO8 48 8 H H
|
||||
12 + 9 XOC81 49 9 I I
|
||||
11 + 1 XC1 51 F+1 J J
|
||||
11 + 2 XC2 52 F+2 K K
|
||||
11 + 3 X21 53 F+3 L L
|
||||
11 + 4 XC4 54 F+4 M M
|
||||
11 + 5 X41 55 F+5 N N
|
||||
11 + 6 X42 56 F+6 O O
|
||||
11 + 7 XC421 57 F+7 P P
|
||||
11 + 8 XC8 58 F+8 Q Q
|
||||
11 + 9 X81 59 F+9 R R
|
||||
0 + 1 OC1 21 1 / /
|
||||
0 + 2 OC2 62 2 S S
|
||||
0 + 3 O21 63 3 T T
|
||||
0 + 4 OC4 64 4 U U
|
||||
0 + 5 O41 65 5 V V
|
||||
0 + 6 O42 66 6 W W
|
||||
0 + 7 OC421 67 7 X X
|
||||
0 + 8 OC8 68 8 Y Y
|
||||
0 + 9 O81 69 9 Z Z
|
||||
2 + 8 C82 ? 0A A na %
|
||||
3 + 8 821 33 B = =
|
||||
4 + 8 C84 34 C @ @
|
||||
5 + 8 841 70 0 0 :
|
||||
6 + 8 842 ? 0E E na >
|
||||
7 + 8 C8421 ? 0F F na ^
|
||||
12 + 2 + 8 XOC82 ? 5A ? F+A na ?
|
||||
12 + 3 + 8 XO821 3 ? F+B . .
|
||||
12 + 4 + 8 XOC84 4 C ) )
|
||||
12 + 5 + 8 XO841 40 0 na [
|
||||
12 + 6 + 8 XO842 ? 5E ? F+E na <
|
||||
12 + 7 + 8 XOC8421 5F F+F na "
|
||||
11 + 2 + 8 X82 5A F+A na !
|
||||
11 + 3 + 8 XC821 13 F+B $ $
|
||||
11 + 4 + 8 X84 14 F+C * *
|
||||
11 + 5 + 8 XC841 50 F+0 - ]
|
||||
11 + 6 + 8 XC842 ? 5E ? F+E na ;
|
||||
11 + 7 + 8 X8421 5F F+F na _
|
||||
0 + 2 + 8 O82 0A A na '
|
||||
0 + 3 + 8 OC821 23 B , ,
|
||||
0 + 4 + 8 O84 24 C ( (
|
||||
0 + 5 + 8 OC841 60 0 na #
|
||||
0 + 6 + 8 OC842 0E E na \
|
||||
0 + 7 + 8 O8421 0F F na &
|
||||
|
||||
2 ?
|
||||
12 !
|
||||
22 '
|
||||
32 0
|
||||
35 :
|
||||
36 blank
|
||||
11 + 0 50 - ]
|
||||
463
I1620/i1620_dp.c
463
I1620/i1620_dp.c
@@ -1,463 +0,0 @@
|
||||
/* i1620_dp.c: IBM 1311 disk simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
dp 1311 disk pack
|
||||
|
||||
The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.
|
||||
Each sector contains 105 characters of information:
|
||||
|
||||
5c sector address
|
||||
100c sector data
|
||||
|
||||
By default, a sector's address field will be '00000', which is interpreted
|
||||
to mean the implied sector number that would be in place if the disk pack
|
||||
had been formatted with sequential sector numbers.
|
||||
|
||||
18-Oct-02 RMS Fixed bug in error testing (found by Hans Pufal)
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
|
||||
#define DP_NUMDR 4 /* #drives */
|
||||
#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */
|
||||
#define UNIT_WAE (1 << UNIT_V_WAE)
|
||||
|
||||
/* Disk format */
|
||||
|
||||
#define DP_ADDR 5 /* address */
|
||||
#define DP_DATA 100 /* data */
|
||||
#define DP_NUMCH (DP_ADDR + DP_DATA)
|
||||
|
||||
#define DP_NUMSC 20 /* #sectors */
|
||||
#define DP_NUMSF 10 /* #surfaces */
|
||||
#define DP_NUMCY 100 /* #cylinders */
|
||||
#define DP_TOTSC (DP_NUMCY * DP_NUMSF * DP_NUMSC)
|
||||
#define DP_SIZE (DP_TOTSC * DP_NUMCH)
|
||||
|
||||
/* Disk control field */
|
||||
|
||||
#define DCF_DRV 0 /* drive select */
|
||||
#define DCF_SEC 1 /* sector addr */
|
||||
#define DCF_SEC_LEN 5
|
||||
#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */
|
||||
#define DCF_CNT_LEN 3
|
||||
#define DCF_ADR (DCF_CNT + DCF_CNT_LEN) /* buffer address */
|
||||
#define DCF_ADR_LEN 5
|
||||
#define DCF_LEN (DCF_ADR + DCF_ADR_LEN)
|
||||
|
||||
/* Functions */
|
||||
|
||||
#define FNC_SEEK 1 /* seek */
|
||||
#define FNC_SEC 0 /* sectors */
|
||||
#define FNC_WCH 1 /* write check */
|
||||
#define FNC_NRL 2 /* no rec lnt chk */
|
||||
#define FNC_TRK 4 /* tracks */
|
||||
#define FNC_WRI 8 /* write offset */
|
||||
|
||||
#define CYL u3 /* current cylinder */
|
||||
|
||||
extern uint8 M[MAXMEMSIZE]; /* memory */
|
||||
extern uint8 ind[NUM_IND];
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 dp_stop = 1; /* disk err stop */
|
||||
uint32 dp_ba = 0; /* buffer addr */
|
||||
|
||||
t_stat dp_reset (DEVICE *dptr);
|
||||
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);
|
||||
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc);
|
||||
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr);
|
||||
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr);
|
||||
int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd);
|
||||
t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd);
|
||||
t_bool dp_zeroad (uint8 *ap);
|
||||
int32 dp_cvt_ad (uint8 *ap);
|
||||
int32 dp_trkop (int32 drv, int32 sec);
|
||||
int32 dp_cvt_bcd (uint32 ad, int32 len);
|
||||
void dp_fill (UNIT *uptr, uint32 da, int32 cnt);
|
||||
t_stat dp_tstgm (uint32 c, int32 qnr);
|
||||
|
||||
/* DP data structures
|
||||
|
||||
dp_dev DP device descriptor
|
||||
dp_unit DP unit list
|
||||
dp_reg DP register list
|
||||
dp_mod DP modifier list
|
||||
*/
|
||||
|
||||
UNIT dp_unit[] = {
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } };
|
||||
|
||||
REG dp_reg[] = {
|
||||
{ FLDATA (ADCHK, ind[IN_DACH], 0) },
|
||||
{ FLDATA (WLRC, ind[IN_DWLR], 0) },
|
||||
{ FLDATA (CYLO, ind[IN_DCYO], 0) },
|
||||
{ FLDATA (ERR, ind[IN_DERR], 0) },
|
||||
{ FLDATA (DPSTOP, dp_stop, 0) },
|
||||
{ URDATA (CYL, dp_unit[0].CYL, 10, 8, 0,
|
||||
DP_NUMDR, PV_LEFT + REG_RO) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dp_mod[] = {
|
||||
{ UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL },
|
||||
{ UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dp_dev = {
|
||||
"DP", dp_unit, dp_reg, dp_mod,
|
||||
DP_NUMDR, 10, 21, 1, 16, 5,
|
||||
NULL, NULL, &dp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Disk IO routine */
|
||||
|
||||
t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
int32 drv, sa, sec, psec, cnt, qwc, qnr, t;
|
||||
UNIT *uptr;
|
||||
t_stat r;
|
||||
|
||||
if (pa & 1) return STOP_INVDCF; /* dcf must be even */
|
||||
ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */
|
||||
ind[IN_DERR] = ind[IN_DCYO] = 0;
|
||||
sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */
|
||||
if (((dp_unit[0].flags & UNIT_DIS) == 0) && /* only drive 0? */
|
||||
(dp_unit[1].flags & UNIT_DIS) &&
|
||||
(dp_unit[2].flags & UNIT_DIS) &&
|
||||
(dp_unit[3].flags & UNIT_DIS)) drv = 0; /* ignore drv select */
|
||||
else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */
|
||||
if (drv >= DP_NUMDR) return STOP_INVDRV; /* invalid? */
|
||||
uptr = dp_dev.units + drv; /* get unit ptr */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_DERR] = 1; /* no, error */
|
||||
CRETIOE (dp_stop, SCPE_UNATT); }
|
||||
|
||||
sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */
|
||||
if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */
|
||||
return STOP_INVDSC;
|
||||
if (op == OP_K) { /* seek? */
|
||||
if (f1 != FNC_SEEK) return STOP_INVFNC; /* really? */
|
||||
uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */
|
||||
DP_NUMCY;
|
||||
return SCPE_OK; } /* done! */
|
||||
|
||||
cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */
|
||||
t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */
|
||||
if ((t < 0) || (t & 1)) return STOP_INVDBA; /* bad address? */
|
||||
dp_ba = t; /* save addr */
|
||||
|
||||
if (f1 >= FNC_WRI) return STOP_INVFNC; /* invalid func? */
|
||||
if (op == OP_RN) qwc = f1 & FNC_WCH; /* read? set wch */
|
||||
else if (op == OP_WN) { /* write? */
|
||||
if (op & FNC_WCH) return STOP_INVFNC; /* cant check */
|
||||
f1 = f1 + FNC_WRI; } /* offset fnc */
|
||||
else return STOP_INVFNC; /* not R or W */
|
||||
qnr = f1 & FNC_NRL; /* no rec check? */
|
||||
|
||||
switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */
|
||||
case FNC_SEC: /* read sectors */
|
||||
if (cnt <= 0) return STOP_INVDCN; /* bad count? */
|
||||
psec = dp_fndsec (uptr, sec, TRUE); /* find sector */
|
||||
if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */
|
||||
do { /* loop on count */
|
||||
if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read sector */
|
||||
break;
|
||||
sec++; psec++; } /* next sector */
|
||||
while ((--cnt > 0) &&
|
||||
((r = dp_nexsec (uptr, sec, psec, TRUE)) == SCPE_OK));
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_TRK: /* read track */
|
||||
psec = dp_trkop (drv, sec); /* start of track */
|
||||
for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */
|
||||
if (r = dp_rdadr (uptr, psec, qnr, qwc)) /* read addr */
|
||||
break; /* error? */
|
||||
if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read data */
|
||||
break; /* error? */
|
||||
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_SEC + FNC_WRI: /* write */
|
||||
if (cnt <= 0) return STOP_INVDCN; /* bad count? */
|
||||
psec = dp_fndsec (uptr, sec, FALSE); /* find sector */
|
||||
if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */
|
||||
do { /* loop on count */
|
||||
if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */
|
||||
if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */
|
||||
sec++; psec++; } /* next sector */
|
||||
while ((--cnt > 0) &&
|
||||
((r = dp_nexsec (uptr, sec, psec, FALSE)) == SCPE_OK));
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_TRK + FNC_WRI: /* write track */
|
||||
if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */
|
||||
return STOP_WRADIS;
|
||||
psec = dp_trkop (drv, sec); /* start of track */
|
||||
for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */
|
||||
if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */
|
||||
if (r = dp_wradr (uptr, psec, qnr)) break; /* write addr */
|
||||
if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */
|
||||
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
|
||||
break; /* done, clean up */
|
||||
|
||||
default: /* unknown */
|
||||
return STOP_INVFNC; }
|
||||
|
||||
if ((r == SCPE_OK) && !qnr) { /* eor check? */
|
||||
if ((M[dp_ba] & DIGIT) != GRP_MARK) { /* GM at end? */
|
||||
ind[IN_DWLR] = ind[IN_DERR] = 1; /* no, error */
|
||||
r = STOP_WRLERR; } }
|
||||
if ((r != SCPE_OK) && /* error? */
|
||||
(dp_stop || !ind[IN_DERR])) return r; /* iochk or stop? */
|
||||
return SCPE_OK; /* continue */
|
||||
}
|
||||
|
||||
/* Read or compare address with memory */
|
||||
|
||||
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)
|
||||
{
|
||||
int32 i;
|
||||
uint8 ad;
|
||||
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
t_bool zad = dp_zeroad (ap); /* zero address */
|
||||
static const int32 dec_tab[DP_ADDR] = /* powers of 10 */
|
||||
{ 10000, 1000, 100, 10, 1} ;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++) { /* copy/check addr */
|
||||
if (zad) { /* addr zero? */
|
||||
ad = sec / dec_tab[i]; /* get addr digit */
|
||||
sec = sec % dec_tab[i]; } /* get remainder */
|
||||
else ad = *ap; /* addr digit */
|
||||
if (qwc) { /* write check? */
|
||||
if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */
|
||||
return STOP_WRLERR; /* yes, error */
|
||||
if (!zad && (M[dp_ba] != ad)) { /* digits equal? */
|
||||
ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */
|
||||
return STOP_DWCERR; } }
|
||||
else M[dp_ba] = ad & (FLAG | DIGIT); /* store digit */
|
||||
if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */
|
||||
ap++; PP (dp_ba); } /* adv ptrs */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Read or compare data with memory */
|
||||
|
||||
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc)
|
||||
{
|
||||
int32 i;
|
||||
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */
|
||||
|
||||
for (i = 0; i < DP_DATA; i++) { /* copy data */
|
||||
if (qwc) { /* write check? */
|
||||
if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */
|
||||
return STOP_WRLERR; /* yes, error */
|
||||
if (M[dp_ba] != *ap) { /* dig+flags equal? */
|
||||
ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */
|
||||
return STOP_DWCERR; } }
|
||||
else M[dp_ba] = *ap & (FLAG | DIGIT); /* flag + digit */
|
||||
if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */
|
||||
ap++; PP (dp_ba); } /* adv ptrs */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write address to disk */
|
||||
|
||||
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr)
|
||||
{
|
||||
int32 i;
|
||||
uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++) { /* copy address */
|
||||
*ap = M[dp_ba] & (FLAG | DIGIT); /* flag + digit */
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */
|
||||
dp_fill (uptr, da + 1, DP_NUMCH - i - 1); /* fill addr+data */
|
||||
return STOP_WRLERR; } /* error */
|
||||
da++; ap++; PP (dp_ba); /* adv ptrs */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write data to disk */
|
||||
|
||||
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr)
|
||||
{
|
||||
int32 i;
|
||||
uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
|
||||
for (i = 0; i < DP_DATA; i++) { /* copy data */
|
||||
*ap = M[dp_ba] & (FLAG | DIGIT); /* get character */
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */
|
||||
dp_fill (uptr, da + 1, DP_DATA - i - 1); /* fill data */
|
||||
return STOP_WRLERR; } /* error */
|
||||
da++; ap++; PP (dp_ba); /* adv ptrs */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Find sector */
|
||||
|
||||
int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd)
|
||||
{
|
||||
int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
|
||||
int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;
|
||||
int32 da = psec * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
int32 dskad, i;
|
||||
|
||||
if (dp_zeroad (ap)) return psec; /* addr zero? ok */
|
||||
dskad = dp_cvt_ad (ap); /* cvt addr */
|
||||
if (dskad == sec) { /* match? */
|
||||
if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */
|
||||
ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */
|
||||
return -1; }
|
||||
psec = psec - (psec % DP_NUMSC); /* sector 0 */
|
||||
for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */
|
||||
da = psec * DP_NUMCH; /* char number */
|
||||
ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */
|
||||
if (dp_zeroad (ap)) continue; /* no implicit match */
|
||||
dskad = dp_cvt_ad (ap); /* cvt addr */
|
||||
if (dskad == sec) { /* match? */
|
||||
if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */
|
||||
ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */
|
||||
return -1; } }
|
||||
ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find next sector - must be sequential, cannot cross cylinder boundary */
|
||||
|
||||
t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd)
|
||||
{
|
||||
int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
|
||||
int32 da = psec * DP_NUMCH; /* word number */
|
||||
uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */
|
||||
int32 dskad;
|
||||
|
||||
if (ctrk) { /* not trk zero? */
|
||||
if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */
|
||||
dskad = dp_cvt_ad (ap); /* cvt addr */
|
||||
if ((dskad == sec) && /* match? */
|
||||
(rd || ((*ap & FLAG) == 0))) return SCPE_OK; /* read or !wprot? */
|
||||
ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */
|
||||
return STOP_DACERR; }
|
||||
ind[IN_DCYO] = ind[IN_DERR] = 1; /* cyl overflow */
|
||||
return STOP_CYOERR;
|
||||
}
|
||||
|
||||
/* Test for zero address */
|
||||
|
||||
t_bool dp_zeroad (uint8 *ap)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
|
||||
if (*ap & DIGIT) return FALSE; } /* nonzero? lose */
|
||||
return TRUE; /* all zeroes */
|
||||
}
|
||||
|
||||
/* Test for group mark when enabled */
|
||||
|
||||
t_stat dp_tstgm (uint32 c, int32 qnr)
|
||||
{
|
||||
if (!qnr && ((c & DIGIT) == GRP_MARK)) { /* premature GM? */
|
||||
ind[IN_DWLR] = ind[IN_DERR] = 1; /* error */
|
||||
return STOP_WRLERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Convert disk address to binary - invalid char force bad address */
|
||||
|
||||
int32 dp_cvt_ad (uint8 *ap)
|
||||
{
|
||||
int32 i, r;
|
||||
uint8 c;
|
||||
|
||||
for (i = r = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
|
||||
c = *ap & DIGIT; /* get digit */
|
||||
if (BAD_DIGIT (c)) return -1; /* bad digit? */
|
||||
r = (r * 10) + c; } /* bcd to binary */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Track operation setup */
|
||||
|
||||
int32 dp_trkop (int32 drv, int32 sec)
|
||||
{
|
||||
int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;
|
||||
|
||||
return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) +
|
||||
(ctrk * DP_NUMSC));
|
||||
}
|
||||
|
||||
/* Convert DCF BCD field to binary */
|
||||
|
||||
int32 dp_cvt_bcd (uint32 ad, int32 len)
|
||||
{
|
||||
uint8 c;
|
||||
int32 r;
|
||||
|
||||
for (r = 0; len > 0; len--) { /* loop thru char */
|
||||
c = M[ad] & DIGIT; /* get digit */
|
||||
if (BAD_DIGIT (c)) return -1; /* invalid? */
|
||||
r = (r * 10) + c; /* cvt to bin */
|
||||
PP (ad); } /* next digit */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Fill sector buffer with zero */
|
||||
|
||||
void dp_fill (UNIT *uptr, uint32 da, int32 cnt)
|
||||
{
|
||||
while (cnt-- > 0) { /* fill with zeroes*/
|
||||
*(((uint8 *) uptr->filebuf) + da) = 0;
|
||||
if (da >= uptr->hwmark) uptr->hwmark = da + 1;
|
||||
da++; }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dp_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */
|
||||
ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */
|
||||
ind[IN_DERR] = ind[IN_DCYO] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
388
I1620/i1620_fp.c
388
I1620/i1620_fp.c
@@ -1,388 +0,0 @@
|
||||
/* i1620_fp.c: IBM 1620 floating point simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
The IBM 1620 uses a variable length floating point format, with a fixed
|
||||
two digit decimal exponent and a variable length decimal mantissa:
|
||||
|
||||
_ S_S
|
||||
M.......MEE
|
||||
|
||||
where S represents flag bits if the mantissa or exponent are negative.
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
|
||||
#define FP_LMAX 100 /* max fp mant lnt */
|
||||
#define FP_EMAX 99 /* max fp exponent */
|
||||
|
||||
/* Unpacked floating point operand */
|
||||
|
||||
struct fp_opnd {
|
||||
int32 sign; /* 0 => +, 1 => - */
|
||||
int32 exp; /* binary exponent */
|
||||
uint32 lnt; /* mantissa length */
|
||||
uint32 addr; /* mantissa addr */
|
||||
uint32 zero; /* 0 => nz, 1 => zero */
|
||||
};
|
||||
|
||||
typedef struct fp_opnd FPA;
|
||||
|
||||
extern uint8 M[MAXMEMSIZE]; /* main memory */
|
||||
extern uint8 ind[NUM_IND]; /* indicators */
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro);
|
||||
t_stat fp_zero (FPA *fp);
|
||||
|
||||
extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp);
|
||||
extern t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, int32 *sta);
|
||||
extern t_stat mul_field (uint32 d, uint32 s);
|
||||
extern t_stat xmt_divd (uint32 d, uint32 s);
|
||||
extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez);
|
||||
|
||||
/* Unpack and validate a floating point argument */
|
||||
|
||||
t_stat fp_unpack (uint32 ad, FPA *fp)
|
||||
{
|
||||
uint8 d0, d1, esign;
|
||||
|
||||
esign = M[ad] & FLAG; /* get exp sign */
|
||||
d0 = M[ad] & DIGIT; /* get exp lo digit */
|
||||
MM (ad);
|
||||
if ((M[ad] & FLAG) == 0) return STOP_FPMF; /* no flag on hi exp? */
|
||||
d1 = M[ad] & DIGIT; /* get exp hi digit */
|
||||
MM (ad);
|
||||
fp->addr = ad; /* save mant addr */
|
||||
if (BAD_DIGIT (d1) || BAD_DIGIT (d0)) return STOP_INVDIG; /* exp bad dig? */
|
||||
fp->exp = ((d1 * 10) + d0) * (esign? -1: 1); /* convert exponent */
|
||||
fp->sign = (M[ad] & FLAG)? 1: 0; /* get mantissa sign */
|
||||
return fp_scan_mant (fp->addr, &(fp->lnt), &(fp->zero));
|
||||
}
|
||||
|
||||
/* Unpack and validate source and destination arguments */
|
||||
|
||||
t_stat fp_unpack_two (uint32 dad, uint32 sad, FPA *dfp, FPA *sfp)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
if ((r = fp_unpack (dad, dfp)) != SCPE_OK) return r; /* unpack dst */
|
||||
if ((r = fp_unpack (sad, sfp)) != SCPE_OK) return r; /* unpack src */
|
||||
if (sfp->lnt != dfp->lnt) return STOP_FPUNL; /* lnts must be equal */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Pack floating point result */
|
||||
|
||||
t_stat fp_pack (FPA *fp)
|
||||
{
|
||||
int32 e;
|
||||
uint32 i, mad;
|
||||
|
||||
e = (fp->exp >= 0)? fp->exp: -fp->exp; /* get |exp| */
|
||||
if (e > FP_EMAX) { /* too big? */
|
||||
ind[IN_EXPCHK] = 1; /* set indicator */
|
||||
if (fp->exp < 0) return fp_zero (fp); /* underflow? */
|
||||
mad = fp->addr;
|
||||
for (i = 0; i < fp->lnt; i++) { /* mant = 99...99 */
|
||||
M[mad] = (M[mad] & FLAG) | 9;
|
||||
MM (mad); }
|
||||
e = FP_EMAX; } /* cap at max */
|
||||
M[ADDR_A (fp->addr, 1)] = (e / 10) | FLAG; /* high exp digit */
|
||||
M[ADDR_A (fp->addr, 2)] = (e % 10) | /* low exp digit */
|
||||
((fp->exp < 0)? FLAG: 0);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Shift mantissa right n positions */
|
||||
|
||||
void fp_rsh (FPA *fp, uint32 n)
|
||||
{
|
||||
uint32 i, sad, dad;
|
||||
|
||||
if (n == 0) return; /* zero? done */
|
||||
sad = ADDR_S (fp->addr, n); /* src = addr - n */
|
||||
dad = fp->addr; /* dst = n */
|
||||
for (i = 0; i < fp->lnt; i++) { /* move digits */
|
||||
if (i >= (fp->lnt - n)) M[dad] = M[dad] & FLAG;
|
||||
else M[dad] = (M[dad] & FLAG) | (M[sad] & DIGIT);
|
||||
MM (dad);
|
||||
MM (sad); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Shift mantissa left 1 position */
|
||||
|
||||
void fp_lsh_1 (FPA *fp)
|
||||
{
|
||||
uint32 i, mad, nxt;
|
||||
|
||||
mad = ADDR_S (fp->addr, fp->lnt - 1); /* hi order digit */
|
||||
for (i = 0; i < (fp->lnt - 1); i++) { /* move lnt-1 digits */
|
||||
nxt = ADDR_A (mad, 1);
|
||||
M[mad] = (M[mad] & FLAG) | (M[nxt] & DIGIT);
|
||||
mad = nxt; }
|
||||
M[mad] = M[mad] & FLAG; /* clear last digit */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear floating point number */
|
||||
|
||||
t_stat fp_zero (FPA *fp)
|
||||
{
|
||||
uint32 i, mad = fp->addr;
|
||||
|
||||
for (i = 0; i < fp->lnt; i++) { /* clear mantissa */
|
||||
M[mad] = (i? M[mad] & FLAG: 0); /* clear sign bit */
|
||||
MM (mad); }
|
||||
M[ADDR_A (fp->addr, 1)] = FLAG + 9; /* exp = -99 */
|
||||
M[ADDR_A (fp->addr, 2)] = FLAG + 9; /* exp = -99 */
|
||||
ind[IN_EZ] = 1; /* result = 0 */
|
||||
ind[IN_HP] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Scan floating point mantissa for length and (optionally) zero */
|
||||
|
||||
t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro)
|
||||
{
|
||||
uint8 d, l, z;
|
||||
|
||||
z = 1; /* assume zero */
|
||||
for (l = 1; l <= FP_LMAX; l++) { /* scan to get length */
|
||||
d = M[ad] & DIGIT; /* get mant digit */
|
||||
if (d) z = 0; /* non-zero? */
|
||||
if ((l != 1) && (M[ad] & FLAG)) { /* flag past first dig? */
|
||||
*lnt = l; /* set returns */
|
||||
if (zro) *zro = z;
|
||||
return SCPE_OK; }
|
||||
MM (ad); }
|
||||
return STOP_FPLNT; /* too long */
|
||||
}
|
||||
|
||||
/* Copy floating point mantissa */
|
||||
|
||||
void fp_copy_mant (uint32 d, uint32 s, uint32 l)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
if (ind[IN_HP]) M[d] = M[d] & ~FLAG; /* clr/set sign */
|
||||
else M[d] = M[d] | FLAG;
|
||||
for (i = 0; i < l; i++) { /* copy src */
|
||||
M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* preserve flags */
|
||||
MM (d);
|
||||
MM (s); }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compare floating point mantissa */
|
||||
|
||||
int32 fp_comp_mant (uint32 d, uint32 s, uint32 l)
|
||||
{
|
||||
uint8 i, dd, sd;
|
||||
|
||||
d = ADDR_S (d, l - 1); /* start of mantissa */
|
||||
s = ADDR_S (s, l - 1);
|
||||
for (i = 0; i < l; i++) { /* compare dst:src */
|
||||
dd = M[d] & DIGIT; /* get dst digit */
|
||||
sd = M[s] & DIGIT; /* get src digit */
|
||||
if (dd > sd) return 1; /* >? done */
|
||||
if (dd < sd) return -1; /* <? done */
|
||||
PP (d); /* =? continue */
|
||||
PP (s); }
|
||||
return 0; /* done, equal */
|
||||
}
|
||||
|
||||
/* Floating point add */
|
||||
|
||||
t_stat fp_add (uint32 d, uint32 s, t_bool sub)
|
||||
{
|
||||
FPA sfp, dfp;
|
||||
uint32 i, sad, hi;
|
||||
int32 dif, sta;
|
||||
uint8 sav_src[FP_LMAX];
|
||||
t_stat r;
|
||||
|
||||
r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
dif = dfp.exp - sfp.exp; /* exp difference */
|
||||
|
||||
if (sfp.zero || (dif >= ((int32) dfp.lnt))) { /* src = 0, or too small? */
|
||||
if (dfp.zero) return fp_zero (&dfp); /* res = dst, zero? */
|
||||
ind[IN_EZ] = 0; /* res nz, set EZ, HP */
|
||||
ind[IN_HP] = (dfp.sign == 0);
|
||||
return SCPE_OK; }
|
||||
if (dfp.zero || (dif <= -((int32) dfp.lnt))) { /* dst = 0, or too small? */
|
||||
if (sfp.zero) return fp_zero (&dfp); /* res = src, zero? */
|
||||
r = xmt_field (d, s, 3); /* copy src to dst */
|
||||
ind[IN_EZ] = 0; /* res nz, set EZ, HP */
|
||||
ind[IN_HP] = (dfp.sign == 0);
|
||||
return r; }
|
||||
|
||||
if (dif > 0) { /* dst exp > src exp? */
|
||||
sad = sfp.addr; /* save src in save area */
|
||||
for (i = 0; i < sfp.lnt; i++) {
|
||||
sav_src[i] = M[sad];
|
||||
MM (sad); }
|
||||
fp_rsh (&sfp, dif); } /* denormalize src */
|
||||
else if (dif < 0) { /* dst exp < src exp? */
|
||||
dfp.exp = sfp.exp; /* res exp = src exp */
|
||||
fp_rsh (&dfp, -dif); } /* denormalize dst */
|
||||
r = add_field (dfp.addr, sfp.addr, sub, TRUE, &sta); /* add mant, set EZ, HP */
|
||||
if (dif > 0) { /* src denormalized? */
|
||||
sad = sfp.addr; /* restore src from */
|
||||
for (i = 0; i < sfp.lnt; i++) { /* save area */
|
||||
M[sad] = sav_src[i];
|
||||
MM (sad); } }
|
||||
if (r != SCPE_OK) return r; /* add error? */
|
||||
|
||||
hi = ADDR_S (dfp.addr, dfp.lnt - 1); /* addr of hi digit */
|
||||
if (sta == ADD_CARRY) { /* carry out? */
|
||||
fp_rsh (&dfp, 1); /* shift mantissa */
|
||||
M[hi] = FLAG + 1; /* high order 1 */
|
||||
dfp.exp = dfp.exp + 1;
|
||||
ind[IN_EZ] = 0; /* not zero */
|
||||
ind[IN_HP] = (dfp.sign == 0); } /* set HP */
|
||||
else if (ind[IN_EZ]) return fp_zero (&dfp); /* result zero? */
|
||||
else { while ((M[hi] & DIGIT) == 0) { /* until normalized */
|
||||
fp_lsh_1 (&dfp); /* left shift */
|
||||
dfp.exp = dfp.exp - 1; } } /* decr exponent */
|
||||
|
||||
return fp_pack (&dfp); /* pack and exit */
|
||||
}
|
||||
|
||||
/* Floating point multiply */
|
||||
|
||||
t_stat fp_mul (uint32 d, uint32 s)
|
||||
{
|
||||
FPA sfp, dfp;
|
||||
uint32 pad;
|
||||
t_stat r;
|
||||
|
||||
r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (sfp.zero || dfp.zero) return fp_zero (&dfp); /* either zero? */
|
||||
|
||||
r = mul_field (dfp.addr, sfp.addr); /* mul, set EZ, HP */
|
||||
if (r != SCPE_OK) return r;
|
||||
if (M[ADDR_S (PROD_AREA_END, 2 * dfp.lnt)] & DIGIT) { /* hi prod dig set? */
|
||||
pad = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* no normalization */
|
||||
dfp.exp = dfp.exp + sfp.exp; } /* res exp = sum */
|
||||
else { pad = ADDR_S (PROD_AREA_END, dfp.lnt); /* 'normalize' 1 */
|
||||
dfp.exp = dfp.exp + sfp.exp - 1; } /* res exp = sum - 1 */
|
||||
fp_copy_mant (dfp.addr, pad, dfp.lnt); /* copy prod to mant */
|
||||
|
||||
return fp_pack (&dfp); /* pack and exit */
|
||||
}
|
||||
|
||||
/* Floating point divide */
|
||||
|
||||
t_stat fp_div (uint32 d, uint32 s)
|
||||
{
|
||||
FPA sfp, dfp;
|
||||
uint32 i, pad, a100ml, a99ml;
|
||||
int32 ez;
|
||||
t_stat r;
|
||||
|
||||
r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (sfp.zero) { /* divide by zero? */
|
||||
ind[IN_OVF] = 1; /* dead jim */
|
||||
return SCPE_OK; }
|
||||
if (dfp.zero) return fp_zero (&dfp); /* divide into zero? */
|
||||
|
||||
for (i = 0; i < PROD_AREA_LEN; i++) /* clear prod area */
|
||||
M[PROD_AREA + i] = 0;
|
||||
a100ml = ADDR_S (PROD_AREA_END, dfp.lnt); /* 100 - lnt */
|
||||
a99ml = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* 99 - lnt */
|
||||
if (fp_comp_mant (dfp.addr, sfp.addr, dfp.lnt) >= 0) { /* |Mdst| >= |Msrc|? */
|
||||
pad = a100ml;
|
||||
dfp.exp = dfp.exp - sfp.exp + 1; } /* res exp = diff + 1 */
|
||||
else { pad = a99ml;
|
||||
dfp.exp = dfp.exp - sfp.exp; } /* res exp = diff */
|
||||
r = xmt_divd (pad, dfp.addr); /* xmt dividend */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
r = div_field (a100ml, sfp.addr, &ez); /* divide fractions */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (ez) return fp_zero (&dfp); /* result zero? */
|
||||
|
||||
ind[IN_HP] = ((dfp.sign ^ sfp.sign) == 0); /* set res sign */
|
||||
ind[IN_EZ] = 0; /* not zero */
|
||||
fp_copy_mant (dfp.addr, a99ml, dfp.lnt); /* copy result */
|
||||
|
||||
return fp_pack (&dfp);
|
||||
}
|
||||
|
||||
/* Floating shift right */
|
||||
|
||||
t_stat fp_fsr (uint32 d, uint32 s)
|
||||
{
|
||||
uint32 cnt;
|
||||
uint8 t;
|
||||
|
||||
if (d == s) return SCPE_OK; /* no move? */
|
||||
|
||||
cnt = 0;
|
||||
M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* move 1st wo flag */
|
||||
do { MM (d); /* decr ptrs */
|
||||
MM (s);
|
||||
t = M[d] = M[s] & (FLAG | DIGIT); /* copy others */
|
||||
if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */
|
||||
while ((t & FLAG) == 0); /* until src flag */
|
||||
|
||||
cnt = 0;
|
||||
do { MM (d); /* decr pointer */
|
||||
t = M[d]; /* save old val */
|
||||
M[d] = 0; /* zero field */
|
||||
if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */
|
||||
while ((t & FLAG) == 0); /* until dst flag */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Floating shift left - note that dst is addr of high order digit */
|
||||
|
||||
t_stat fp_fsl (uint32 d, uint32 s)
|
||||
{
|
||||
uint32 i, lnt;
|
||||
uint8 sign;
|
||||
t_stat r;
|
||||
|
||||
if (d == s) return SCPE_OK;
|
||||
sign = M[s] & FLAG; /* get src sign */
|
||||
r = fp_scan_mant (s, &lnt, NULL); /* get src length */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
s = ADDR_S (s, lnt - 1); /* hi order src */
|
||||
M[d] = M[s] & (FLAG | DIGIT); /* move 1st w flag */
|
||||
M[s] = M[s] & ~FLAG; /* clr flag from src */
|
||||
for (i = 1; i < lnt; i++) { /* move src to dst */
|
||||
PP (d); /* incr ptrs */
|
||||
PP (s);
|
||||
M[d] = M[s] & DIGIT; } /* move just digit */
|
||||
PP (d); /* incr pointer */
|
||||
while ((M[d] & FLAG) == 0) { /* until flag */
|
||||
M[d] = 0; /* clear field */
|
||||
PP (d); }
|
||||
if (sign) M[d] = FLAG; /* -? zero under sign */
|
||||
return SCPE_OK;
|
||||
}
|
||||
316
I1620/i1620_lp.c
316
I1620/i1620_lp.c
@@ -1,316 +0,0 @@
|
||||
/* i1620_lp.c: IBM 1443 line printer simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
lpt 1443 line printer
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
|
||||
#define LPT_BSIZE 197 /* buffer size */
|
||||
|
||||
#define K_IMM 0x10 /* control now */
|
||||
#define K_LIN 0x20 /* spc lines */
|
||||
#define K_CH10 0x40 /* chan 10 */
|
||||
#define K_LCNT 0x03 /* line count */
|
||||
#define K_CHAN 0x0F /* channel */
|
||||
|
||||
extern uint8 M[MAXMEMSIZE];
|
||||
extern uint8 ind[NUM_IND];
|
||||
extern UNIT cpu_unit;
|
||||
extern uint32 io_stop;
|
||||
|
||||
uint32 cct[CCT_LNT] = { 03 }; /* car ctrl tape */
|
||||
int32 cct_lnt = 66, cct_ptr = 0; /* cct len, ptr */
|
||||
int32 lpt_bptr = 0; /* lpt buf ptr */
|
||||
char lpt_buf[LPT_BSIZE + 1]; /* lpt buf */
|
||||
int32 lpt_savctrl = 0; /* saved spc ctrl */
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr);
|
||||
t_stat lpt_reset (DEVICE *dptr);
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr);
|
||||
void lpt_buf_init (void);
|
||||
t_stat lpt_num (uint32 pa, uint32 len, uint32 f1);
|
||||
t_stat lpt_print (void);
|
||||
t_stat lpt_space (int32 lines, int32 lflag);
|
||||
|
||||
#define CHP(ch,val) ((val) & (1 << (ch)))
|
||||
|
||||
/* LPT data structures
|
||||
|
||||
lpt_dev LPT device descriptor
|
||||
lpt_unit LPT unit descriptor
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
UNIT lpt_unit = {
|
||||
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 50) };
|
||||
|
||||
REG lpt_reg[] = {
|
||||
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE + 1) },
|
||||
{ DRDATA (BPTR, lpt_bptr, 8) },
|
||||
{ HRDATA (PCTL, lpt_savctrl, 8) },
|
||||
{ FLDATA (PRCHK, ind[IN_PRCHK], 0) },
|
||||
{ FLDATA (PRCH9, ind[IN_PRCH9], 0) },
|
||||
{ FLDATA (PRCH12, ind[IN_PRCH12], 0) },
|
||||
{ FLDATA (PRBSY, ind[IN_PRBSY], 0) },
|
||||
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ BRDATA (CCT, cct, 8, 32, CCT_LNT) },
|
||||
{ DRDATA (CCTP, cct_ptr, 8), PV_LEFT },
|
||||
{ DRDATA (CCTL, cct_lnt, 8), REG_RO + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE lpt_dev = {
|
||||
"LPT", &lpt_unit, lpt_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &lpt_reset,
|
||||
NULL, &lpt_attach, NULL };
|
||||
|
||||
/* Data tables */
|
||||
|
||||
/* Numeric (flag plus digit) to lineprinter (ASCII) */
|
||||
|
||||
const char num_to_lpt[32] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '\'', ' ', '@', ':', ' ', 'G',
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'W', ' ', '*', ' ', -1, 'X' };
|
||||
|
||||
/* Alphameric (digit pair) to lineprinter (ASCII) */
|
||||
|
||||
const char alp_to_lpt[256] = {
|
||||
' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
'+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
'-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, '0', '=', '@', ':', -1, -1, /* 30 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
|
||||
'H', 'I', -1, -1, -1, -1, -1, -1,
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
|
||||
'Q', 'R', -1, -1, -1, -1, -1, -1,
|
||||
-1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
|
||||
'Y', 'Z', -1, -1, -1, -1, -1, -1,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
|
||||
'8', '9', -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
/* Line printer IO routine
|
||||
|
||||
- Hard errors halt the system.
|
||||
- Invalid characters print a blank, set the WRCHK and PRCHK
|
||||
flags, and halt the system if IO stop is set.
|
||||
*/
|
||||
|
||||
t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
int8 lpc;
|
||||
uint8 z, d;
|
||||
t_stat r, inv = SCPE_OK;
|
||||
|
||||
sim_cancel (&lpt_unit); /* "stall" until */
|
||||
ind[IN_PRBSY] = 0; /* printer free */
|
||||
|
||||
switch (op) { /* decode op */
|
||||
case OP_K: /* control */
|
||||
lpt_savctrl = (f0 << 4) | f1; /* form ctrl */
|
||||
if (lpt_savctrl & K_IMM) return lpt_print (); /* immediate? */
|
||||
break;
|
||||
case OP_DN:
|
||||
return lpt_num (pa, 20000 - (pa % 20000), f1); /* dump numeric */
|
||||
case OP_WN:
|
||||
return lpt_num (pa, 0, f1); /* write numeric */
|
||||
case OP_WA:
|
||||
for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */
|
||||
d = M[pa] & DIGIT; /* get digit */
|
||||
z = M[pa - 1] & DIGIT; /* get zone */
|
||||
if ((d & REC_MARK) == REC_MARK) break; /* 8-2 char? */
|
||||
lpc = alp_to_lpt[(z << 4) | d]; /* translate pair */
|
||||
if (lpc < 0) { /* bad char? */
|
||||
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
|
||||
inv = STOP_INVCHR; } /* set return status */
|
||||
lpt_buf[lpt_bptr] = lpc & 0x7F; /* fill buffer */
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
if ((f1 & 1) == 0) { ; /* print now? */
|
||||
r = lpt_print (); /* print line */
|
||||
if (r != SCPE_OK) return r; }
|
||||
CRETIOE (io_stop, inv);
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Print numeric */
|
||||
|
||||
t_stat lpt_num (uint32 pa, uint32 len, uint32 f1)
|
||||
{
|
||||
uint32 end;
|
||||
uint8 d;
|
||||
int8 lpc;
|
||||
t_stat r, inv = SCPE_OK;
|
||||
|
||||
end = pa + len;
|
||||
for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */
|
||||
d = M[pa]; /* get digit */
|
||||
if (len? (pa >= end): /* end reached? */
|
||||
((d & REC_MARK) == REC_MARK)) break;
|
||||
lpc = num_to_lpt[d]; /* translate */
|
||||
if (lpc < 0) { /* bad char? */
|
||||
ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */
|
||||
inv = STOP_INVCHR; } /* set return status */
|
||||
lpt_buf[lpt_bptr++] = lpc & 0x7F; /* fill buffer */
|
||||
PP (pa); } /* incr mem addr */
|
||||
if ((f1 & 1) == 0) { /* print now? */
|
||||
r = lpt_print (); /* print line */
|
||||
if (r != SCPE_OK) return r; }
|
||||
CRETIOE (io_stop, inv);
|
||||
}
|
||||
|
||||
/* Print and space */
|
||||
|
||||
t_stat lpt_print (void)
|
||||
{
|
||||
int32 i, chan, ctrl = lpt_savctrl;
|
||||
|
||||
if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
|
||||
return SCPE_UNATT; }
|
||||
|
||||
ind[IN_PRBSY] = 1; /* print busy */
|
||||
sim_activate (&lpt_unit, lpt_unit.time); /* start timer */
|
||||
|
||||
for (i = LPT_WIDTH; i <= LPT_BSIZE; i++) /* clear unprintable */
|
||||
lpt_buf[i] = ' ';
|
||||
while ((lpt_bptr > 0) && (lpt_buf[lpt_bptr - 1] == ' '))
|
||||
lpt_buf[--lpt_bptr] = 0; /* trim buffer */
|
||||
if (lpt_bptr) { /* any line? */
|
||||
fputs (lpt_buf, lpt_unit.fileref); /* print */
|
||||
lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */
|
||||
lpt_buf_init (); /* reinit buf */
|
||||
if (ferror (lpt_unit.fileref)) { /* error? */
|
||||
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
|
||||
perror ("LPT I/O error");
|
||||
clearerr (lpt_unit.fileref);
|
||||
return SCPE_IOERR; } }
|
||||
|
||||
lpt_savctrl = 0x61; /* reset ctrl */
|
||||
if ((ctrl & K_LIN) == ((ctrl & K_IMM)? 0: K_LIN)) /* space lines? */
|
||||
return lpt_space (ctrl & K_LCNT, FALSE);
|
||||
chan = lpt_savctrl & K_CHAN; /* basic chan */
|
||||
if (lpt_savctrl & K_CH10) { /* chan 10-12? */
|
||||
if (chan == 0) chan = 10;
|
||||
else if (chan == 3) chan = 11;
|
||||
else if (chan == 4) chan = 12;
|
||||
else chan = 0; }
|
||||
if ((chan == 0) || (chan > 12)) return STOP_INVFNC;
|
||||
for (i = 1; i < cct_lnt + 1; i++) { /* sweep thru cct */
|
||||
if (CHP (chan, cct[(cct_ptr + i) % cct_lnt]))
|
||||
return lpt_space (i, TRUE); }
|
||||
return STOP_CCT; /* runaway channel */
|
||||
}
|
||||
|
||||
/* Space routine - space or skip n lines
|
||||
|
||||
Inputs:
|
||||
count = number of lines to space or skip
|
||||
sflag = skip (TRUE) or space (FALSE)
|
||||
*/
|
||||
|
||||
t_stat lpt_space (int32 count, int32 sflag)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
cct_ptr = (cct_ptr + count) % cct_lnt; /* adv cct, mod lnt */
|
||||
if (sflag && CHP (0, cct[cct_ptr])) /* skip, top of form? */
|
||||
fputs ("\n\f", lpt_unit.fileref); /* nl, ff */
|
||||
else { for (i = 0; i < count; i++) /* count lines */
|
||||
fputc ('\n', lpt_unit.fileref); }
|
||||
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
|
||||
ind[IN_PRCH9] = CHP (9, cct[cct_ptr]) != 0; /* set indicators */
|
||||
ind[IN_PRCH12] = CHP (12, cct[cct_ptr]) != 0;
|
||||
if (ferror (lpt_unit.fileref)) { /* error? */
|
||||
ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */
|
||||
perror ("LPT I/O error");
|
||||
clearerr (lpt_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Unit service - clear printer busy */
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr)
|
||||
{
|
||||
ind[IN_PRBSY] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Initialize lpt buffer */
|
||||
|
||||
void lpt_buf_init (void)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
lpt_bptr = 0;
|
||||
for (i = 0; i < LPT_WIDTH + 1; i++) lpt_buf[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat lpt_reset (DEVICE *dptr)
|
||||
{
|
||||
lpt_buf_init (); /* clear buffer */
|
||||
cct_ptr = 0; /* clear cct ptr */
|
||||
lpt_savctrl = 0x61; /* clear cct action */
|
||||
ind[IN_PRCHK] = ind[IN_PRBSY] = 0; /* clear indicators */
|
||||
ind[IN_PRCH9] = ind[IN_PRCH12] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
lpt_reset (&lpt_dev);
|
||||
return attach_unit (uptr, cptr);
|
||||
}
|
||||
436
I1620/i1620_pt.c
436
I1620/i1620_pt.c
@@ -1,436 +0,0 @@
|
||||
/* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator
|
||||
|
||||
Copyright (c) 2002-2003, Robert M Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
ptr 1621 paper tape reader
|
||||
ptp 1624 paper tape punch
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
|
||||
#define PT_EL 0x80 /* end record */
|
||||
#define PT_X 0x40 /* X */
|
||||
#define PT_O 0x20 /* O */
|
||||
#define PT_C 0x10 /* C */
|
||||
#define PT_FD 0x7F /* deleted */
|
||||
|
||||
extern uint8 M[MAXMEMSIZE];
|
||||
extern uint8 ind[NUM_IND];
|
||||
extern UNIT cpu_unit;
|
||||
extern uint32 io_stop;
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat ptr_read (uint8 *c, t_bool ignfeed);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
t_stat ptp_write (uint32 c);
|
||||
t_stat ptp_num (uint32 pa, uint32 len);
|
||||
|
||||
/* PTR data structures
|
||||
|
||||
ptr_dev PTR device descriptor
|
||||
ptr_unit PTR unit descriptor
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
UNIT ptr_unit = {
|
||||
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) };
|
||||
|
||||
REG ptr_reg[] = {
|
||||
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptr_dev = {
|
||||
"PTR", &ptr_unit, ptr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptr_reset,
|
||||
&ptr_boot, NULL, NULL };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
ptp_dev PTP device descriptor
|
||||
ptp_unit PTP unit descriptor
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
|
||||
|
||||
REG ptp_reg[] = {
|
||||
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE ptp_dev = {
|
||||
"PTP", &ptp_unit, ptp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ptp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Data tables */
|
||||
|
||||
/* Paper tape reader odd parity chart: 1 = bad, 0 = ok */
|
||||
|
||||
const int8 bad_par[128] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 00 */
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 10 */
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 20 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 30 */
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 40 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 50 */
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 60 */
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; /* 70 */
|
||||
|
||||
/* Paper tape read (7b) to numeric (one digit) */
|
||||
|
||||
const int8 ptr_to_num[128] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* - */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* C */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* O */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* OC */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* X */
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* XC */
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XO */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XOC */
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F };
|
||||
|
||||
/* Paper tape read (7b) to alphameric (two digits)
|
||||
Codes XO82, 82, XO842, 842 do not have consistent translations
|
||||
*/
|
||||
|
||||
const int8 ptr_to_alp[128] = {
|
||||
0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */
|
||||
0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
|
||||
0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */
|
||||
0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F,
|
||||
0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */
|
||||
0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
|
||||
0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */
|
||||
0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F,
|
||||
0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */
|
||||
0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
|
||||
0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */
|
||||
0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F,
|
||||
0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */
|
||||
0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F,
|
||||
0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */
|
||||
0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F };
|
||||
|
||||
/* Numeric (flag + digit) to paper tape punch */
|
||||
|
||||
const int8 num_to_ptp[32] = {
|
||||
0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */
|
||||
0x08, 0x19, 0x2A, 0x3B, 0x1C, 0x0D, 0x3E, 0x3F,
|
||||
0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */
|
||||
0x58, 0x49, 0x4A, 0x5B, 0x4C, 0x5D, 0x5E, 0x4F };
|
||||
|
||||
/* Alphameric (two digits) to paper tape punch */
|
||||
|
||||
const int8 alp_to_ptp[256] = {
|
||||
0x10, -1, 0x7A, 0x6B, 0x7C, -1, -1, 0x7F, /* 00 */
|
||||
-1, -1, 0x2A, -1, -1, -1, -1, 0x1F,
|
||||
0x70, -1, 0x4A, 0x5B, 0x4C, -1, -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x40, 0x31, 0x2A, 0x3B, 0x2C, -1, -1, -1, /* 20 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 0x1A, 0x0B, 0x1C, 0x0D, 0x0E, -1, /* 30 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */
|
||||
0x68, 0x79, -1, -1, -1, -1, -1, -1,
|
||||
0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */
|
||||
0x58, 0x49, 0x4A, -1, -1, -1, -1, 0x4F,
|
||||
-1, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */
|
||||
0x38, 0x29, -1, -1, -1, -1, -1, -1,
|
||||
0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */
|
||||
0x08, 0x19, 0x7A, -1, -1, -1, -1, 0x7F,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
/* Paper tape reader IO routine
|
||||
|
||||
- Hard errors halt the operation and the system.
|
||||
- Parity errors place an invalid character in memory and set
|
||||
RDCHK, but the read continues until end of record. If IO
|
||||
stop is set, the system then halts.
|
||||
*/
|
||||
|
||||
t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
uint32 i;
|
||||
int8 mc;
|
||||
uint8 ptc;
|
||||
t_stat r, inv = SCPE_OK;
|
||||
|
||||
switch (op) { /* case on op */
|
||||
case OP_RN: /* read numeric */
|
||||
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
|
||||
r = ptr_read (&ptc, TRUE); /* read frame */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (ptc & PT_EL) { /* end record? */
|
||||
M[pa] = REC_MARK; /* store rec mark */
|
||||
CRETIOE (io_stop, inv); } /* done */
|
||||
if (bad_par[ptc]) { /* bad parity? */
|
||||
ind[IN_RDCHK] = 1; /* set read check */
|
||||
inv = STOP_INVCHR; /* set return status */
|
||||
M[pa] = 0; } /* store zero */
|
||||
else M[pa] = ptr_to_num[ptc]; /* translate, store */
|
||||
PP (pa); } /* incr mem addr */
|
||||
break;
|
||||
case OP_RA: /* read alphameric */
|
||||
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
|
||||
r = ptr_read (&ptc, TRUE); /* read frame */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (ptc & PT_EL) { /* end record? */
|
||||
M[pa] = REC_MARK; /* store rec mark */
|
||||
M[pa - 1] = 0;
|
||||
CRETIOE (io_stop, inv); } /* done */
|
||||
mc = ptr_to_alp[ptc]; /* translate */
|
||||
if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */
|
||||
ind[IN_RDCHK] = 1; /* set read check */
|
||||
inv = STOP_INVCHR; /* set return status */
|
||||
mc = 0; } /* store blank */
|
||||
M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */
|
||||
M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT);
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Binary paper tape reader IO routine - see above for error handling */
|
||||
|
||||
t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 ptc;
|
||||
t_stat r, inv = SCPE_OK;
|
||||
|
||||
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
|
||||
switch (op) { /* case on op */
|
||||
case OP_RA: /* read alphameric */
|
||||
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
|
||||
r = ptr_read (&ptc, FALSE); /* read frame */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (ptc & PT_EL) { /* end record? */
|
||||
M[pa] = REC_MARK; /* store rec mark */
|
||||
M[pa - 1] = 0;
|
||||
CRETIOE (io_stop, inv); } /* done */
|
||||
if (bad_par[ptc]) { /* bad parity? */
|
||||
ind[IN_RDCHK] = 1; /* set read check */
|
||||
inv = STOP_INVCHR; } /* set return status */
|
||||
M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */
|
||||
M[pa - 1] = (M[pa - 1] & FLAG) |
|
||||
(((ptc >> 5) & 06) | ((ptc >> 3) & 1));
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Read ptr frame - all errors are 'hard' errors and halt the system */
|
||||
|
||||
t_stat ptr_read (uint8 *c, t_bool ignfeed)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_RDCHK] = 1; /* no, error */
|
||||
return SCPE_UNATT; }
|
||||
|
||||
do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */
|
||||
ind[IN_RDCHK] = 1; /* err, rd chk */
|
||||
if (feof (ptr_unit.fileref))
|
||||
printf ("PTR end of file\n");
|
||||
else perror ("PTR I/O error");
|
||||
clearerr (ptr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
*c = temp & 0377; /* save char */
|
||||
ptr_unit.pos = ptr_unit.pos + 1; } /* incr file addr */
|
||||
while (ignfeed && (*c == PT_FD)); /* until not feed */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptr_reset (DEVICE *dptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
const static uint8 boot_rom[] = {
|
||||
4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */
|
||||
3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */
|
||||
2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */
|
||||
3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT loc1 */
|
||||
2, 6, 0, 0, 0, 6, 6, 0, 0, 0, 3, 5, /* TF 66,35 */
|
||||
1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TDM loc2,loc3 */
|
||||
4, 9, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 }; /* BR 12 */
|
||||
|
||||
#define BOOT_START 0
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8))
|
||||
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape punch IO routine
|
||||
|
||||
- Hard errors halt the operation and the system.
|
||||
- Parity errors stop the operation and set WRCHK.
|
||||
If IO stop is set, the system then halts.
|
||||
*/
|
||||
|
||||
t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
uint32 i;
|
||||
int8 ptc;
|
||||
uint8 z, d;
|
||||
t_stat r;
|
||||
|
||||
switch (op) { /* decode op */
|
||||
case OP_DN:
|
||||
return ptp_num (pa, 20000 - (pa % 20000)); /* dump numeric */
|
||||
case OP_WN:
|
||||
return ptp_num (pa, 0); /* punch numeric */
|
||||
case OP_WA:
|
||||
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
|
||||
d = M[pa] & DIGIT; /* get digit */
|
||||
z = M[pa - 1] & DIGIT; /* get zone */
|
||||
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
|
||||
return ptp_write (PT_EL); /* end record */
|
||||
ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */
|
||||
if (ptc < 0) { /* bad char? */
|
||||
ind[IN_WRCHK] = 1; /* write check */
|
||||
CRETIOE (io_stop, STOP_INVCHR); }
|
||||
r = ptp_write (ptc); /* write char */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Binary paper tape punch IO routine - see above for error handling */
|
||||
|
||||
t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
uint32 i;
|
||||
uint8 ptc, z, d;
|
||||
t_stat r;
|
||||
|
||||
if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO;
|
||||
switch (op) { /* decode op */
|
||||
case OP_WA:
|
||||
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
|
||||
d = M[pa] & DIGIT; /* get digit */
|
||||
z = M[pa - 1] & DIGIT; /* get zone */
|
||||
if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */
|
||||
return ptp_write (PT_EL); /* end record */
|
||||
ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07);
|
||||
if (bad_par[ptc]) ptc = ptc | PT_C; /* set parity */
|
||||
r = ptp_write (ptc); /* write char */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Punch tape numeric - cannot generate parity errors */
|
||||
|
||||
t_stat ptp_num (uint32 pa, uint32 len)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 d;
|
||||
uint32 i, end;
|
||||
|
||||
end = pa + len;
|
||||
for (i = 0; i < MEMSIZE; i++) { /* stop runaway */
|
||||
d = M[pa] & (FLAG | DIGIT); /* get char */
|
||||
if (len? (pa >= end): /* dump: end reached? */
|
||||
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
|
||||
return ptp_write (PT_EL); /* end record */
|
||||
r = ptp_write (num_to_ptp[d]); /* write */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
PP (pa); } /* incr mem addr */
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Write ptp frame - all errors are hard errors */
|
||||
|
||||
t_stat ptp_write (uint32 c)
|
||||
{
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_WRCHK] = 1; /* no, error */
|
||||
return SCPE_UNATT; }
|
||||
|
||||
if (putc (c, ptp_unit.fileref) == EOF) { /* write char */
|
||||
ind[IN_WRCHK] = 1; /* error? */
|
||||
perror ("PTP I/O error");
|
||||
clearerr (ptp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
ptp_unit.pos = ptp_unit.pos + 1; /* count char */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat ptp_reset (DEVICE *dptr)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,491 +0,0 @@
|
||||
/* i1620_sys.c: IBM 1620 simulator interface
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define LINE_LNT 50
|
||||
|
||||
extern DEVICE cpu_dev, tty_dev;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE lpt_dev;
|
||||
extern DEVICE cdr_dev, cdp_dev;
|
||||
extern DEVICE dp_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern uint8 M[MAXMEMSIZE];
|
||||
extern char cdr_to_alp[128], alp_to_cdp[256];
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "IBM 1620";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = LINE_LNT;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&tty_dev,
|
||||
&ptr_dev,
|
||||
&ptp_dev,
|
||||
&cdr_dev,
|
||||
&cdp_dev,
|
||||
&lpt_dev,
|
||||
&dp_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Invalid instruction",
|
||||
"Invalid digit",
|
||||
"Invalid character",
|
||||
"Invalid indicator",
|
||||
"Invalid digit in P address",
|
||||
"Invalid P address",
|
||||
"P address exceeds indirect address limit",
|
||||
"Invalid digit in Q address",
|
||||
"Invalid Q address",
|
||||
"Q address exceeds indirect address limit",
|
||||
"Invalid IO device",
|
||||
"Invalid return register",
|
||||
"Invalid IO function",
|
||||
"Instruction address must be even",
|
||||
"Invalid select code",
|
||||
"Index instruction with no band selected",
|
||||
"P address must be odd",
|
||||
"DCF address must be even",
|
||||
"Invalid disk drive",
|
||||
"Invalid disk sector address",
|
||||
"Invalid disk sector count",
|
||||
"Invalid disk buffer address",
|
||||
"Disk address compare error",
|
||||
"Disk write check error",
|
||||
"Disk cylinder overflow error",
|
||||
"Disk wrong length record error",
|
||||
"Invalid CCT",
|
||||
"Field exceeds memory",
|
||||
"Record exceeds memory",
|
||||
"No card in reader",
|
||||
"Overflow check",
|
||||
"Exponent check",
|
||||
"Write address function disabled",
|
||||
"Floating point mantissa too long",
|
||||
"Floating point mantissa lengths unequal",
|
||||
"Floating point exponent flag missing",
|
||||
"Floating point divide by zero" };
|
||||
|
||||
/* Binary loader -- load carriage control tape
|
||||
|
||||
A carriage control tape consists of entries of the form
|
||||
|
||||
(repeat count) column number,column number,column number,...
|
||||
|
||||
The CCT entries are stored in cct[0:lnt-1], cctlnt contains the
|
||||
number of entries
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 col, rpt, ptr, mask, cctbuf[CCT_LNT];
|
||||
t_stat r;
|
||||
extern int32 cct_lnt, cct_ptr, cct[CCT_LNT];
|
||||
char cbuf[CBUFSIZE], gbuf[CBUFSIZE];
|
||||
|
||||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||||
ptr = 0;
|
||||
for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */
|
||||
mask = 0;
|
||||
if (*cptr == '(') { /* repeat count? */
|
||||
cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */
|
||||
rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */
|
||||
if (r != SCPE_OK) return SCPE_FMT; }
|
||||
else rpt = 1;
|
||||
while (*cptr != 0) { /* get col no's */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
|
||||
col = get_uint (gbuf, 10, 12, &r); /* column number */
|
||||
if (r != SCPE_OK) return SCPE_FMT;
|
||||
mask = mask | (1 << col); } /* set bit */
|
||||
for ( ; rpt > 0; rpt--) { /* store vals */
|
||||
if (ptr >= CCT_LNT) return SCPE_FMT;
|
||||
cctbuf[ptr++] = mask; } }
|
||||
if (ptr == 0) return SCPE_FMT;
|
||||
cct_lnt = ptr;
|
||||
cct_ptr = 0;
|
||||
for (rpt = 0; rpt < cct_lnt; rpt++) cct[rpt] = cctbuf[rpt];
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbol table */
|
||||
|
||||
struct opc {
|
||||
char *str; /* mnemonic */
|
||||
uint32 opv; /* opcode & flags */
|
||||
uint32 qv; /* q field */
|
||||
};
|
||||
|
||||
#define I_V_FL 16 /* flags */
|
||||
#define I_M_QX 0x01 /* Q indexable */
|
||||
#define I_M_QM 0x02 /* Q immediate */
|
||||
#define I_M_QNP 0x00 /* Q no print */
|
||||
#define I_M_QCP 0x04 /* Q cond print */
|
||||
#define I_M_QP 0x08 /* Q print */
|
||||
#define I_M_PCP 0x00 /* P cond print */
|
||||
#define I_M_PP 0x10 /* P print */
|
||||
#define I_GETQF(x) (((x) >> I_V_FL) & 0x03)
|
||||
#define I_GETQP(x) (((x) >> I_V_FL) & 0x0C)
|
||||
#define I_GETPP(x) (((x) >> I_V_FL) & 0x10)
|
||||
|
||||
#define I_2 ((I_M_PP | I_M_QP | I_M_QX) << I_V_FL)
|
||||
#define I_2M ((I_M_PP | I_M_QP | I_M_QM) << I_V_FL)
|
||||
#define I_2X ((I_M_PP | I_M_QP | I_M_QX | I_M_QM) << I_V_FL)
|
||||
#define I_2S ((I_M_PP | I_M_QP) << I_V_FL)
|
||||
#define I_1 ((I_M_PP | I_M_QCP) << I_V_FL)
|
||||
#define I_1E ((I_M_PP | I_M_QNP) << I_V_FL)
|
||||
#define I_0 ((I_M_PCP | I_M_QCP) << I_V_FL)
|
||||
#define I_0E ((I_M_PCP | I_M_QNP) << I_V_FL)
|
||||
|
||||
struct opc opcode[] = {
|
||||
{ "RNTY", 36+I_1E, 100 }, { "RATY", 37+I_1E, 100 },
|
||||
{ "WNTY", 38+I_1E, 100 }, { "WATY", 39+I_1E, 100 },
|
||||
{ "DNTY", 35+I_1E, 100 }, { "SPTY", 34+I_0E, 101 },
|
||||
{ "RCTY", 34+I_0E, 102 }, { "BKTY", 34+I_0E, 103 },
|
||||
{ "IXTY", 34+I_0E, 104 }, { "TBTY", 34+I_0E, 108 },
|
||||
{ "RNPT", 36+I_1E, 300 }, { "RAPT", 37+I_1E, 300 },
|
||||
{ "WNPT", 38+I_1E, 200 }, { "WAPT", 39+I_1E, 200 },
|
||||
{ "DNPT", 35+I_1E, 200 },
|
||||
{ "RNCD", 36+I_1E, 500 }, { "RACD", 37+I_1E, 500 },
|
||||
{ "WNCD", 38+I_1E, 400 }, { "WACD", 39+I_1E, 400 },
|
||||
{ "DNCD", 35+I_1E, 400 },
|
||||
{ "PRN", 38+I_1E, 900 }, { "PRNS", 38+I_1E, 901 },
|
||||
{ "PRA", 39+I_1E, 900 }, { "PRAS", 39+I_1E, 901 },
|
||||
{ "PRD", 35+I_1E, 900 }, { "PRDS", 35+I_1E, 901 },
|
||||
{ "SK", 34+I_1E, 701 },
|
||||
{ "RDGN", 36+I_1E, 700 }, { "CDGN", 36+I_1E, 701 },
|
||||
{ "RDN", 36+I_1E, 702 }, { "CDN", 36+I_1E, 703 },
|
||||
{ "RTGN", 36+I_1E, 704 }, { "CTGN", 36+I_1E, 705 },
|
||||
{ "RTN", 36+I_1E, 706 }, { "CTN", 36+I_1E, 707 },
|
||||
{ "WDGN", 38+I_1E, 700 }, { "WDN", 38+I_1E, 702 },
|
||||
{ "WTGN", 38+I_1E, 704 }, { "WTN", 38+I_1E, 706 },
|
||||
{ "RBPT", 37+I_1E, 3300 }, { "WBPT", 39+I_1E, 3200 },
|
||||
{ "BC1", 46+I_1E, 100 }, { "BNC1", 47+I_1E, 100 },
|
||||
{ "BC2", 46+I_1E, 200 }, { "BNC2", 47+I_1E, 200 },
|
||||
{ "BC3", 46+I_1E, 300 }, { "BNC3", 47+I_1E, 300 },
|
||||
{ "BC4", 46+I_1E, 400 }, { "BNC4", 47+I_1E, 400 },
|
||||
{ "BLC", 46+I_1E, 900 }, { "BNLC", 47+I_1E, 900 },
|
||||
{ "BH", 46+I_1E, 1100 }, { "BNH", 47+I_1E, 1100 },
|
||||
{ "BP", 46+I_1E, 1100 }, { "BNP", 47+I_1E, 1100 },
|
||||
{ "BE", 46+I_1E, 1200 }, { "BNE", 47+I_1E, 1200 },
|
||||
{ "BZ", 46+I_1E, 1200 }, { "BNZ", 47+I_1E, 1200 },
|
||||
{ "BNL", 46+I_1E, 1300 }, { "BL", 47+I_1E, 1300 },
|
||||
{ "BNN", 46+I_1E, 1300 }, { "BN", 47+I_1E, 1300 },
|
||||
{ "BV", 46+I_1E, 1400 }, { "BNV", 47+I_1E, 1400 },
|
||||
{ "BXV", 46+I_1E, 1500 }, { "BNXV", 47+I_1E, 1500 },
|
||||
{ "BA", 46+I_1E, 1900 }, { "BNA", 47+I_1E, 1900 },
|
||||
{ "BNBS", 46+I_1E, 3000 }, { "BEBS", 47+I_1E, 3000 },
|
||||
{ "BBAS", 46+I_1E, 3100 }, { "BANS", 47+I_1E, 3100 },
|
||||
{ "BBBS", 46+I_1E, 3200 }, { "BBNS", 47+I_1E, 3200 },
|
||||
{ "BCH9", 46+I_1E, 3300 },
|
||||
{ "BCOV", 46+I_1E, 3400 },
|
||||
{ "BSNX", 60+I_1E, 0 }, { "BSBA", 60+I_1E, 1 },
|
||||
{ "BSBB", 60+I_1E, 2 },
|
||||
{ "BSNI", 60+I_1E, 8 }, { "BSIA", 60+I_1E, 9 },
|
||||
|
||||
{ "FADD", 1+I_2, 0 }, { "FSUB", 2+I_2, 0 },
|
||||
{ "FMUL", 3+I_2, 0 }, { "FSL", 5+I_2, 0 },
|
||||
{ "TFL", 6+I_2, 0 }, { "BTFL", 7+I_2, 0 },
|
||||
{ "FSR", 8+I_2, 0 }, { "FDIV", 9+I_2, 0 },
|
||||
{ "BTAM", 10+I_2M, 0 }, { "AM", 11+I_2M, 0 },
|
||||
{ "SM", 12+I_2M, 0 }, { "MM", 13+I_2M, 0 },
|
||||
{ "CM", 14+I_2M, 0 }, { "TDM", 15+I_2S, 0 },
|
||||
{ "TFM", 16+I_2M, 0 }, { "BTM", 17+I_2M, 0 },
|
||||
{ "LDM", 18+I_2M, 0 }, { "DM", 19+I_2M, 0 },
|
||||
{ "BTA", 20+I_2, 0 }, { "A", 21+I_2, 0 },
|
||||
{ "S", 22+I_2, 0 }, { "M", 23+I_2, 0 },
|
||||
{ "C", 24+I_2, 0 }, { "TD", 25+I_2, 0 },
|
||||
{ "TF", 26+I_2, 0 }, { "BT", 27+I_2, 0 },
|
||||
{ "LD", 28+I_2, 0 }, { "D", 29+I_2, 0 },
|
||||
{ "TRNM", 30+I_2, 0 }, { "TR", 31+I_2, 0 },
|
||||
{ "SF", 32+I_1, 0 }, { "CF", 33+I_1, 0 },
|
||||
{ "K", 34+I_2S, 0 }, { "DN", 35+I_2S, 0 },
|
||||
{ "RN", 36+I_2S, 0 }, { "RA", 37+I_2S, 0 },
|
||||
{ "WN", 38+I_2S, 0 }, { "WA", 39+I_2S, 0 },
|
||||
{ "NOP", 41+I_0, 0 }, { "BB", 42+I_0, 0 },
|
||||
{ "BD", 43+I_2, 0 }, { "BNF", 44+I_2, 0 },
|
||||
{ "BNR", 45+I_2, 0 }, { "BI", 46+I_2S, 0 },
|
||||
{ "BNI", 47+I_2S, 0 }, { "H", 48+I_0, 0 },
|
||||
{ "B", 49+I_1, 0 }, { "BNG", 55+I_2, 0 },
|
||||
{ "BS", 60+I_2S, 0 }, { "BX", 61+I_2, 0 },
|
||||
{ "BXM", 62+I_2X, 0 }, { "BCX", 63+I_2, 0 },
|
||||
{ "BCXM", 64+I_2X, 0 }, { "BLX", 65+I_2, 0 },
|
||||
{ "BLXM", 66+I_2X, 0 }, { "BSX", 67+I_2, 0 },
|
||||
{ "MA", 70+I_2, 0 }, { "MF", 71+I_2, 0 },
|
||||
{ "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 },
|
||||
{ "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 },
|
||||
{ "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 },
|
||||
{ "CPFL", 94+I_2, 0 }, { "EORF", 95+I_2, 0 },
|
||||
{ "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 },
|
||||
{ NULL, 0, 0 } };
|
||||
|
||||
/* Print an address from five characters */
|
||||
|
||||
void fprint_addr (FILE *of, int32 spc, t_value *dig, t_bool flg)
|
||||
{
|
||||
int32 i, idx;
|
||||
|
||||
fputc (spc, of); /* spacer */
|
||||
if (dig[ADDR_LEN - 1] & FLAG) { /* signed? */
|
||||
fputc ('-', of); /* print minus */
|
||||
dig[ADDR_LEN - 1] = dig[ADDR_LEN - 1] & ~FLAG; }
|
||||
for (i = 0; i < ADDR_LEN; i++) /* print digits */
|
||||
fprintf (of, "%X", dig[i] & DIGIT);
|
||||
if ((cpu_unit.flags & IF_IDX) && flg) { /* indexing? */
|
||||
for (i = idx = 0; i < ADDR_LEN - 2; i++) { /* get index reg */
|
||||
if (dig[ADDR_LEN - 2 - i] & FLAG)
|
||||
idx = idx | (1 << i);
|
||||
dig[ADDR_LEN - 2 - i] = dig[ADDR_LEN - 2 - i] & ~FLAG; }
|
||||
if (idx) fprintf (of, "(%d)", idx); } /* print */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current address
|
||||
*val = values to decode
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = if >= 0, error code
|
||||
if < 0, number of extra words retired
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 pmp, qmp, i, c, d, any;
|
||||
uint32 op, qv, opfl;
|
||||
|
||||
if (uptr == NULL) uptr = &cpu_unit;
|
||||
if (sw & SWMASK ('C')) { /* character? */
|
||||
if (uptr->flags & UNIT_BCD) {
|
||||
if (addr & 1) return SCPE_ARG; /* must be even */
|
||||
c = ((val[0] & DIGIT) << 4) | (val[1] & DIGIT);
|
||||
if (alp_to_cdp[c] > 0)
|
||||
fprintf (of, "%c", alp_to_cdp[c]);
|
||||
else fprintf (of, "<%02x>", c);
|
||||
return -1; }
|
||||
else fprintf (of, FMTASC (val[0] & 0177));
|
||||
return SCPE_OK; }
|
||||
if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */
|
||||
if (sw & SWMASK ('D')) { /* dump? */
|
||||
for (i = d = 0; i < LINE_LNT; i++) d = d | val[i];
|
||||
if (d & FLAG) { /* any flags? */
|
||||
for (i = 0; i < LINE_LNT; i++) /* print flags */
|
||||
fprintf (of, (val[i] & FLAG)? "_": " ");
|
||||
fprintf (of, "\n\t"); }
|
||||
for (i = 0; i < LINE_LNT; i++) /* print digits */
|
||||
fprintf (of, "%X", val[i] & DIGIT) ;
|
||||
return -(i - 1); }
|
||||
if (sw & SWMASK ('S')) { /* string? */
|
||||
if (addr & 1) return SCPE_ARG; /* must be even */
|
||||
for (i = 0; i < LINE_LNT; i = i + 2) {
|
||||
c = ((val[i] & DIGIT) << 4) | (val[i + 1] & DIGIT);
|
||||
if (alp_to_cdp[c] < 0) break;
|
||||
fprintf (of, "%c", alp_to_cdp[c]); }
|
||||
if (i == 0) {
|
||||
fprintf (of, "<%02X>", c);
|
||||
return -1; }
|
||||
return -(i - 1); }
|
||||
if ((sw & SWMASK ('M')) == 0) return SCPE_ARG;
|
||||
|
||||
if (addr & 1) return SCPE_ARG; /* must be even */
|
||||
op = ((val[0] & DIGIT) * 10) + (val[1] & DIGIT); /* get opcode */
|
||||
for (i = qv = pmp = qmp = 0; i < ADDR_LEN; i++) { /* test addr */
|
||||
if (val[I_P + i]) pmp = 1;
|
||||
if (val[I_Q + i]) qmp = 1;
|
||||
qv = (qv * 10) + (val[I_Q + i] & DIGIT); }
|
||||
if ((val[0] | val[1]) & FLAG) pmp = qmp = 1; /* flags force */
|
||||
for (i = 0; opcode[i].str != NULL; i++) { /* find opcode */
|
||||
opfl = opcode[i].opv & 0xFF0000;
|
||||
if ((op == (opcode[i].opv & 0xFF)) &&
|
||||
((qv == opcode[i].qv) ||
|
||||
((opfl != I_1E) && (opfl != I_0E)))) break; }
|
||||
if (opcode[i].str == NULL) return SCPE_ARG;
|
||||
if (I_GETQP (opfl) == I_M_QNP) qmp = 0; /* Q no print? */
|
||||
|
||||
fprintf (of, opcode[i].str); /* print opcode */
|
||||
if (I_GETPP (opfl) == I_M_PP) /* P required? */
|
||||
fprint_addr (of, ' ', &val[I_P], I_M_QX);
|
||||
else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */
|
||||
fprint_addr (of, ' ', &val[I_P], 0);
|
||||
if (I_GETQP (opfl) == I_M_QP) { /* Q required? */
|
||||
fprint_addr (of, ',', &val[I_Q], I_GETQF (opfl));
|
||||
if (I_GETQF (opfl) & I_M_QM) /* immediate? */
|
||||
val[I_Q] = val[I_Q] & ~FLAG; } /* clr hi Q flag */
|
||||
else if ((I_GETQP (opfl) == I_M_QCP) && (pmp || qmp)) /* Q opt & needed? */
|
||||
fprint_addr (of, ',', &val[I_Q], 0);
|
||||
for (i = any = 0; i < INST_LEN; i++) { /* print rem flags */
|
||||
if (val[i] & FLAG) {
|
||||
if (!any) fputc (',', of);
|
||||
any = 1;
|
||||
fprintf (of, "%d", i); } }
|
||||
return -(INST_LEN - 1);
|
||||
}
|
||||
|
||||
/* parse_addr - get sign + address + index */
|
||||
|
||||
t_stat parse_addr (char *cptr, t_value *val, int32 flg)
|
||||
{
|
||||
int32 i, sign = 0, addr, index;
|
||||
static int32 idx_tst[ADDR_LEN] = { 0, 4, 2, 1, 0 };
|
||||
char *tptr;
|
||||
|
||||
if (*cptr == '+') cptr++; /* +? skip */
|
||||
else if (*cptr == '-') { /* -? skip, flag */
|
||||
sign = 1;
|
||||
cptr++; }
|
||||
errno = 0; /* get address */
|
||||
addr = strtoul (cptr, &tptr, 16);
|
||||
if (errno || (cptr == tptr) || (addr > 0xFFFFF)) /* err or too big? */
|
||||
return SCPE_ARG;
|
||||
if ((cpu_unit.flags & IF_IDX) && (flg & I_M_QX) && /* index allowed? */
|
||||
(*tptr == '(')) { /* index specified */
|
||||
errno = 0;
|
||||
index = strtoul (cptr = tptr + 1, &tptr, 10); /* get index */
|
||||
if (errno || (cptr == tptr) || (index > 7)) /* err or too big? */
|
||||
return SCPE_ARG;
|
||||
if (*tptr++ != ')') return SCPE_ARG; }
|
||||
else index = 0;
|
||||
if (*tptr != 0) return SCPE_ARG; /* all done? */
|
||||
for (i = ADDR_LEN - 1; i >= 0; i--) { /* cvt addr to dig */
|
||||
val[i] = (addr & 0xF) | ((index & idx_tst[i])? FLAG: 0);
|
||||
addr = addr >> 4; }
|
||||
if (sign) val[ADDR_LEN - 1] = val[ADDR_LEN - 1] | FLAG; /* set sign */
|
||||
if (flg & I_M_QM) val[0] = val[0] | FLAG; /* set immediate */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = > 0 error code
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 i, qv, opfl, last;
|
||||
char t, la, *fptr, gbuf[CBUFSIZE];
|
||||
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */
|
||||
if ((t = *cptr & 0x7F) == 0) return SCPE_ARG; /* get char */
|
||||
if (uptr->flags & UNIT_BCD) { /* BCD? */
|
||||
if (addr & 1) return SCPE_ARG;
|
||||
t = cdr_to_alp[t]; /* convert */
|
||||
if (t < 0) return SCPE_ARG; /* invalid? */
|
||||
val[0] = (t >> 4) & DIGIT; /* store */
|
||||
val[1] = t & DIGIT;
|
||||
return -1; }
|
||||
else val[0] = t; /* store ASCII */
|
||||
return SCPE_OK; }
|
||||
|
||||
if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */
|
||||
if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* string? */
|
||||
if (addr & 1) return SCPE_ARG; /* must be even */
|
||||
for (i = 0; (i < sim_emax) && (*cptr != 0); i = i + 2) {
|
||||
t = *cptr++ & 0x7F; /* get character */
|
||||
t = cdr_to_alp[t]; /* convert */
|
||||
if (t < 0) return SCPE_ARG; /* invalid? */
|
||||
val[i] = (t >> 4) & DIGIT; /* store */
|
||||
val[i + 1] = t & DIGIT; }
|
||||
if (i == 0) return SCPE_ARG; /* final check */
|
||||
return -(i - 1); }
|
||||
|
||||
if (addr & 1) return SCPE_ARG; /* even addr? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; opcode[i].str != NULL; i++) { /* look it up */
|
||||
if (strcmp (gbuf, opcode[i].str) == 0) break; }
|
||||
if (opcode[i].str == NULL) return SCPE_ARG; /* successful? */
|
||||
opfl = opcode[i].opv & 0xFF0000; /* get flags */
|
||||
val[0] = (opcode[i].opv & 0xFF) / 10; /* store opcode */
|
||||
val[1] = (opcode[i].opv & 0xFF) % 10;
|
||||
qv = opcode[i].qv;
|
||||
for (i = ADDR_LEN - 1; i >= 0; i--) { /* set P,Q fields */
|
||||
val[I_P + i] = 0;
|
||||
val[I_Q + i] = qv % 10;
|
||||
qv = qv /10; }
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get P field */
|
||||
if (gbuf[0]) { /* any? */
|
||||
if (parse_addr (gbuf, &val[I_P], (I_GETPP (opfl)?
|
||||
I_M_QX: 0))) return SCPE_ARG; }
|
||||
else if (I_GETPP (opfl) == I_M_PP) return SCPE_ARG;
|
||||
|
||||
if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get Q field */
|
||||
if (gbuf[0]) { /* any? */
|
||||
if (parse_addr (gbuf, &val[I_Q], I_GETQF (opfl)))
|
||||
return SCPE_ARG; }
|
||||
else if (I_GETQP (opfl) == I_M_QP) return SCPE_ARG; }
|
||||
|
||||
cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */
|
||||
last = -1; /* none yet */
|
||||
while (t = *fptr++) { /* loop through */
|
||||
if ((t < '0') || (t > '9')) return SCPE_ARG; /* must be digit */
|
||||
t = t - '0'; /* convert */
|
||||
if (t == 1) { /* ambiguous? */
|
||||
la = *fptr++; /* get next */
|
||||
if (la == '0') t = 10; /* 10? */
|
||||
else if ((la == '1') && (*fptr == 0)) t = 11; /* 11 & end field? */
|
||||
else --fptr; } /* dont lookahead */
|
||||
if (t <= last) return SCPE_ARG; /* in order? */
|
||||
val[t] = val[t] | FLAG; /* set flag */
|
||||
last = t; } /* continue */
|
||||
|
||||
if (*cptr != 0) return SCPE_ARG;
|
||||
return -(INST_LEN - 1);
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
/* i1620_tty.c: IBM 1620 typewriter
|
||||
|
||||
Copyright (c) 2002-2003, Robert M. Supnik
|
||||
|
||||
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 Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
tty console typewriter
|
||||
|
||||
22-Dec-02 RMS Added break test
|
||||
*/
|
||||
|
||||
#include "i1620_defs.h"
|
||||
|
||||
#define TTO_COLMAX 80
|
||||
|
||||
int32 tto_col = 0;
|
||||
|
||||
extern uint8 M[MAXMEMSIZE];
|
||||
extern uint8 ind[NUM_IND];
|
||||
extern UNIT cpu_unit;
|
||||
extern uint32 io_stop;
|
||||
|
||||
void tti_unlock (void);
|
||||
t_stat tti_rnum (int8 *c);
|
||||
t_stat tti_ralp (int8 *c);
|
||||
t_stat tti_read (int8 *c);
|
||||
t_stat tto_num (uint32 pa, uint32 len);
|
||||
t_stat tto_write (uint32 c);
|
||||
t_stat tty_svc (UNIT *uptr);
|
||||
t_stat tty_reset (DEVICE *dptr);
|
||||
|
||||
/* TTY data structures
|
||||
|
||||
tty_dev TTY device descriptor
|
||||
tty_unit TTY unit descriptor
|
||||
tty_reg TTY register list
|
||||
*/
|
||||
|
||||
UNIT tty_unit = { UDATA (&tty_svc, 0, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG tty_reg[] = {
|
||||
{ DRDATA (COL, tto_col, 7) },
|
||||
{ DRDATA (TIME, tty_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE tty_dev = {
|
||||
"TTY", &tty_unit, tty_reg, NULL,
|
||||
1, 10, 31, 1, 8, 7,
|
||||
NULL, NULL, &tty_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Data tables */
|
||||
|
||||
/* Keyboard to numeric */
|
||||
|
||||
const char *tti_to_num = "0123456789'=@:;\"";
|
||||
|
||||
/* Keyboard to alphameric (digit pair) - translates LC to UC */
|
||||
|
||||
const int8 tti_to_alp[128] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 00 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x00, 0x02, 0x0F, -1, 0x13, -1, -1, -1, /* !"#$%&' */
|
||||
0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */
|
||||
0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89:;<=>? */
|
||||
0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
|
||||
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */
|
||||
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */
|
||||
0x67, 0x68, 0x69, -1, -1, -1, -1, -1, /* XYZ[\]^_ */
|
||||
-1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */
|
||||
0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */
|
||||
0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */
|
||||
0x67, 0x68, 0x69, -1, -1, -1, -1, -1 }; /* xyz */
|
||||
|
||||
/* Numeric (digit) to typewriter */
|
||||
|
||||
const char num_to_tto[16] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '\'', '=', '@', ':', ';', '"' };
|
||||
|
||||
/* Alphameric (digit pair) to typewriter */
|
||||
|
||||
const char alp_to_tto[256] = {
|
||||
' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
'+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
'-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, '0', '=', '@', ':', -1, -1, /* 30 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */
|
||||
'H', 'I', -1, -1, -1, -1, -1, -1,
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */
|
||||
'Q', 'R', -1, -1, -1, -1, -1, -1,
|
||||
-1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */
|
||||
'Y', 'Z', -1, -1, -1, -1, -1, -1,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', /* 70 */
|
||||
'8', '9', -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 80 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 90 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* A0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* B0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* C0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* D0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* E0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* F0 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1 };
|
||||
|
||||
/* Terminal IO
|
||||
|
||||
- On input, parity errors cannot occur.
|
||||
- On input, release-start does NOT cause a record mark to be stored.
|
||||
- On output, invalid characters type an invalid character and set WRCHK.
|
||||
If IO stop is set, the system halts at the end of the operation.
|
||||
*/
|
||||
|
||||
t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1)
|
||||
{
|
||||
t_addr i;
|
||||
uint8 d;
|
||||
int8 ttc;
|
||||
t_stat r, inv = SCPE_OK;
|
||||
|
||||
switch (op) { /* case on op */
|
||||
case OP_K: /* control */
|
||||
switch (f1) { /* case on control */
|
||||
case 1: /* space */
|
||||
tto_write (' ');
|
||||
break;
|
||||
case 2: /* return */
|
||||
tto_write ('\r');
|
||||
break;
|
||||
case 3: /* backspace */
|
||||
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
|
||||
tto_write ('\b');
|
||||
break;
|
||||
case 4: /* index */
|
||||
if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC;
|
||||
tto_write ('\n');
|
||||
break;
|
||||
case 8: /* tab */
|
||||
tto_write ('\t');
|
||||
break;
|
||||
default:
|
||||
return STOP_INVFNC; }
|
||||
return SCPE_OK;
|
||||
case OP_RN: /* read numeric */
|
||||
tti_unlock (); /* unlock keyboard */
|
||||
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
|
||||
r = tti_rnum (&ttc); /* read char */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (ttc == 0x7F) return SCPE_OK; /* end record? */
|
||||
M[pa] = ttc & (FLAG | DIGIT); /* store char */
|
||||
PP (pa); } /* incr mem addr */
|
||||
break;
|
||||
case OP_RA: /* read alphameric */
|
||||
tti_unlock ();
|
||||
for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */
|
||||
r = tti_ralp (&ttc); /* read char */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (ttc == 0x7F) return SCPE_OK; /* end record? */
|
||||
M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */
|
||||
M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT);
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
case OP_DN:
|
||||
return tto_num (pa, 20000 - (pa % 20000)); /* dump numeric */
|
||||
case OP_WN:
|
||||
return tto_num (pa, 0); /* type numeric */
|
||||
case OP_WA:
|
||||
for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */
|
||||
d = M[pa] & DIGIT; /* get digit */
|
||||
if ((d & 0xA) == REC_MARK) /* 8-2 char? */
|
||||
CRETIOE (io_stop, inv); /* end record */
|
||||
d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */
|
||||
ttc = alp_to_tto[d]; /* translate */
|
||||
if (ttc < 0) { /* bad char? */
|
||||
ind[IN_WRCHK] = 1; /* set write check */
|
||||
inv = STOP_INVCHR; } /* set return status */
|
||||
tto_write (ttc & 0x7F); /* write */
|
||||
pa = ADDR_A (pa, 2); } /* incr mem addr */
|
||||
break;
|
||||
default: /* invalid function */
|
||||
return STOP_INVFNC; }
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Read numerically - cannot generate parity errors */
|
||||
|
||||
t_stat tti_rnum (int8 *c)
|
||||
{
|
||||
int8 flg = 0;
|
||||
char *cp, raw;
|
||||
t_stat r;
|
||||
|
||||
*c = -1; /* no char yet */
|
||||
do { r = tti_read (&raw); /* get char */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (raw == '\r') *c = 0x7F; /* return? mark */
|
||||
else if (raw == '~') flg = FLAG; /* flag? mark */
|
||||
else if (cp = strchr (tti_to_num, raw)) /* legal? */
|
||||
*c = ((int8) (cp - tti_to_num)) | flg; /* assemble char */
|
||||
else raw = 007; /* beep! */
|
||||
tto_write (raw); } /* echo */
|
||||
while (*c == -1);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Read alphamerically - cannot generate parity errors */
|
||||
|
||||
t_stat tti_ralp (int8 *c)
|
||||
{
|
||||
char raw;
|
||||
t_stat r;
|
||||
|
||||
*c = -1; /* no char yet */
|
||||
do { r = tti_read (&raw); /* get char */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
if (raw == '\r') *c = 0x7F; /* return? mark */
|
||||
else if (tti_to_alp[raw] >= 0) /* legal char? */
|
||||
*c = tti_to_alp[raw]; /* xlate */
|
||||
else raw = 007; /* beep! */
|
||||
tto_write (raw); } /* echo */
|
||||
while (*c == -1);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Read from keyboard */
|
||||
|
||||
t_stat tti_read (int8 *c)
|
||||
{
|
||||
int32 t;
|
||||
|
||||
do { t = sim_poll_kbd (); } /* get character */
|
||||
while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */
|
||||
if (t < SCPE_KFLAG) return t; /* error? */
|
||||
*c = t & 0177; /* store character */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write numerically - cannot generate parity errors */
|
||||
|
||||
t_stat tto_num (uint32 pa, uint32 len)
|
||||
{
|
||||
t_stat r;
|
||||
uint8 d;
|
||||
uint32 i, end;
|
||||
|
||||
end = pa + len;
|
||||
for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */
|
||||
d = M[pa]; /* get char */
|
||||
if (len? (pa >= end): /* dump: end reached? */
|
||||
((d & REC_MARK) == REC_MARK)) /* write: rec mark? */
|
||||
return SCPE_OK; /* end operation */
|
||||
if (d & FLAG) tto_write ('~'); /* flag? */
|
||||
r = tto_write (num_to_tto[d & DIGIT]); /* write */
|
||||
if (r != SCPE_OK) return r; /* error? */
|
||||
PP (pa); } /* incr mem addr */
|
||||
return STOP_RWRAP;
|
||||
}
|
||||
|
||||
/* Write, maintaining position */
|
||||
|
||||
t_stat tto_write (uint32 c)
|
||||
{
|
||||
int32 rpt;
|
||||
|
||||
if (c == '\t') { /* tab? */
|
||||
rpt = 8 - (tto_col % 8); /* distance to next */
|
||||
tto_col = tto_col + rpt; /* tab over */
|
||||
while (rpt-- > 0) sim_putchar (' '); /* use spaces */
|
||||
return SCPE_OK; }
|
||||
if (c == '\r') { /* return? */
|
||||
sim_putchar ('\r'); /* crlf */
|
||||
sim_putchar ('\n');
|
||||
tto_col = 0; /* clear colcnt */
|
||||
return SCPE_OK; }
|
||||
if ((c == '\n') || (c == 007)) { /* non-spacing? */
|
||||
sim_putchar (c);
|
||||
return SCPE_OK; }
|
||||
if (c == '\b') tto_col = tto_col? tto_col - 1: 0; /* backspace? */
|
||||
else tto_col++; /* normal */
|
||||
if (tto_col > TTO_COLMAX) { /* line wrap? */
|
||||
sim_putchar ('\r');
|
||||
sim_putchar ('\n');
|
||||
tto_col = 0; }
|
||||
sim_putchar (c);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Unit service - polls for WRU */
|
||||
|
||||
t_stat tty_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&tty_unit, tty_unit.wait); /* continue poll */
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat tty_reset (DEVICE *dptr)
|
||||
{
|
||||
sim_activate (&tty_unit, tty_unit.wait); /* activate poll */
|
||||
tto_col = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* TTI unlock - signals that we are ready for keyboard input */
|
||||
|
||||
void tti_unlock (void)
|
||||
{
|
||||
tto_write ('`');
|
||||
return;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 867 KiB |
BIN
Ibm1130/HAND.CUR
BIN
Ibm1130/HAND.CUR
Binary file not shown.
|
Before Width: | Height: | Size: 326 B |
@@ -1,171 +0,0 @@
|
||||
0x01, "DUP - COMMON SUBROUTINES",
|
||||
0x02, "DUP - CTRL RECORD PROCESSOR",
|
||||
0x03, "DUP - STORE PHASE",
|
||||
0x04, "DUP - *FILES, *LOCAL, *NOCAL PHASE",
|
||||
0x05, "DUP - DUMP PHASE",
|
||||
0x06, "DUP - DUMP LET/FLET PHASE",
|
||||
0x07, "DUP - DELETE PHASE",
|
||||
0x08, "DUP - DEFINE PHASE",
|
||||
0x09, "DUP - EXIT PHASE",
|
||||
0x0A, "DUP - CARD I/O INTERFACE",
|
||||
0x0B, "DUP - KEYBOARD INPUT INTERFACE",
|
||||
0x0C, "DUP - PAPER TAPE I/O INTERFACE",
|
||||
0x0D, "DUP - SAVED UPCOR PHASE",
|
||||
0x0E, "DUP - PRINCIPAL I/O DUMMY PHASE",
|
||||
0x0F, "DUP - PRINCIPAL I/O (W/O KB) DUMMY PHASE",
|
||||
0x10, "DUP - PAPER TAPE I/O DUMMY PHASE",
|
||||
0x11, "DUP - MOVE DCI PROGRAMS TO UA OR FXA",
|
||||
0x12, "DUP - EXIT TO MODIF DUMMY PHASE",
|
||||
|
||||
0x1F, "FOR - INPUT PHASE",
|
||||
0x20, "FOR - CLASSIFIERPHASE",
|
||||
0x21, "FOR - CHECK ORDER/ST NO PHASE",
|
||||
0x22, "FOR - COMMON SUBR OR FUNCTION PHASE",
|
||||
0x23, "FOR - DIMENSION/REAL/INTEGER PHASE",
|
||||
0x24, "FOR - REAL CONSTANT PHASE",
|
||||
0x25, "FOR - DEFINE FILE, CALL LINK/EXIT PHASE",
|
||||
0x26, "FOR - VARIABLE, STMT FUNC PHASE",
|
||||
0x27, "FOR - DATA STATEMENT PHASE",
|
||||
0x28, "FOR - FORMAT STATEMENT PHASE",
|
||||
0x29, "FOR - SUBTRACT DECOMPOSITION PHASE",
|
||||
0x2A, "FOR - ASCAN I PHASE",
|
||||
0x2B, "FOR - ASCAN II PHASE",
|
||||
0x2C, "FOR - DO/CONTINUE/ETC PHASE",
|
||||
0x2D, "FOR - SUBSCRIPT OPTIMIZATION PHASE",
|
||||
0x2E, "FOR - SCAN PHASE",
|
||||
0x2F, "FOR - EXPANDER I PHASE",
|
||||
0x30, "FOR - EXPANDER II PHASE",
|
||||
0x31, "FOR - DATA ALLOCATION PHASE",
|
||||
0x32, "FOR - COMPILATION ERROR PHASE",
|
||||
0x33, "FOR - STATEMENT ALLOCATION PHASE",
|
||||
0x34, "FOR - LIST STATEMENT PHASE",
|
||||
0x35, "FOR - LIST SYMBOL TABLE PHASE",
|
||||
0x36, "FOR - LIST CONSTANTS PHASE",
|
||||
0x37, "FOR - OUTPUT I PHASE",
|
||||
0x38, "FOR - OUTPUT II PHASE",
|
||||
0x39, "FOR - RECOVERY/EXIT PHASE",
|
||||
|
||||
0X51, "COBOL 51",
|
||||
0X52, "COBOL 52",
|
||||
0X53, "COBOL 53",
|
||||
0X54, "COBOL 54",
|
||||
0X55, "COBOL 55",
|
||||
0X56, "COBOL 56",
|
||||
0X57, "COBOL 57",
|
||||
0X58, "COBOL 58",
|
||||
0X59, "COBOL 59",
|
||||
0X5A, "COBOL 5A",
|
||||
0X5B, "COBOL 5B",
|
||||
0X5C, "COBOL 5C",
|
||||
|
||||
0X6E, "SUP PHASE 1 - MONITOR CONTROL RECORD ANALYZER",
|
||||
0x6F, "SUP PHASE 2 - JOB PROCESSING",
|
||||
0x70, "SUP PHASE 3 - DELETE TEMPORARY LET",
|
||||
0x71, "SUP PHASE 4 - XEQ PROCESSING",
|
||||
0x72, "SUP PHASE 5 - SUPV CONTROL REC PROCESSING",
|
||||
0X73, "SYSTEM DUMP-CORE-TO-PRINTER",
|
||||
0X74, "AUXILIARY SUPERVISOR",
|
||||
0X78, "CORE LOAD BUILDER, PHASE 1",
|
||||
0x79, "CORE LOAD BUILDER, PHASE 2",
|
||||
0x7A, "CORE LOAD BUILDER, PHASE 3",
|
||||
0x7B, "CORE LOAD BUILDER, PHASE 4",
|
||||
0x7C, "CORE LOAD BUILDER, PHASE 5",
|
||||
0x7D, "CORE LOAD BUILDER, PHASE 6",
|
||||
0x7E, "CORE LOAD BUILDER, PHASE 7",
|
||||
0x7F, "CORE LOAD BUILDER, PHASE 8",
|
||||
0x80, "CORE LOAD BUILDER, PHASE 9",
|
||||
0x81, "CORE LOAD BUILDER, PHASE 10",
|
||||
0x82, "CORE LOAD BUILDER, PHASE 11",
|
||||
0x83, "CORE LOAD BUILDER, PHASE 12",
|
||||
0x84, "CORE LOAD BUILDER, PHASE 13",
|
||||
|
||||
0X8C, "SYS 1403 READER",
|
||||
0x8D, "SYS 1132 PRINTER",
|
||||
0x8E, "SYS CONSOLE PRINTER",
|
||||
0x8F, "SYS 2501/1442 READER",
|
||||
0x90, "SYS 1442/1442 READER",
|
||||
0x91, "SYS 1134/1055 PAPER TAPE IO",
|
||||
0x92, "SYS KEYBOARD",
|
||||
0x93, "SYS 2501/1442 CONVERSION",
|
||||
0x94, "SYS 1134/1055 CONVERSION",
|
||||
0x95, "SYS KEYBOARD CONVERSION",
|
||||
0x96, "DISKZ",
|
||||
0x97, "SYS DISK1",
|
||||
0x98, "SYS DISKN",
|
||||
|
||||
0xA0, "CIL CORE IMAGE LOADER - PHASE 1",
|
||||
0xA1, "CIL CORE IMAGE LOADER - PHASE 2",
|
||||
|
||||
0XB0, "RPG B0",
|
||||
0XB1, "RPG B1",
|
||||
0XB2, "RPG B2",
|
||||
0XB3, "RPG B3",
|
||||
0XB4, "RPG B4",
|
||||
0XB5, "RPG B5",
|
||||
0XB6, "RPG B6",
|
||||
0XB7, "RPG B7",
|
||||
0XB8, "RPG B8",
|
||||
0XB9, "RPG B9",
|
||||
0XBA, "RPG BA",
|
||||
0XBB, "RPG BB",
|
||||
0XBC, "RPG BC",
|
||||
0XBD, "RPG BD",
|
||||
0XBE, "RPG BE",
|
||||
0XBF, "RPG BF",
|
||||
0XC0, "RPG C0",
|
||||
0XC1, "RPG C1",
|
||||
0XC2, "RPG C2",
|
||||
0XC3, "RPG C3",
|
||||
0XC4, "RPG C4",
|
||||
0XC5, "RPG C5",
|
||||
0XC6, "RPG C6",
|
||||
0XC7, "RPG C7",
|
||||
0XC8, "RPG C8",
|
||||
0XC9, "RPG C9",
|
||||
0XCA, "RPG CA",
|
||||
0XCB, "RPG CB",
|
||||
0XCC, "RPG CC",
|
||||
|
||||
0XCD, "DUP PART 2 - CTRL",
|
||||
0XCE, "DUP PART 2 - MACRO UPDATE",
|
||||
|
||||
0XCF, "ASM INITIALIZATION PHASE",
|
||||
0xD0, "ASM CARD CONVERSION PHASE",
|
||||
0xD1, "ASM DSF OUTPUT PHASE",
|
||||
0xD2, "ASM INTERMEDIATE INPUT PHASE",
|
||||
0xD3, "ASM END STATEMENT PHASE",
|
||||
0xD4, "ASM ASSEMBLY ERROR PHASE",
|
||||
0xD5, "ASM CONTROL CARDS I",
|
||||
0xD6, "ASM CONTROL CARDS 2",
|
||||
0xD7, "ASM DUMMY SYST SYMBOL TBL",
|
||||
0xD8, "ASM SYMBOL TABLE OPTIONS PHASE",
|
||||
0xD9, "ASM EXIT PHASE",
|
||||
0xDA, "ASM PROG HEADER MNEMONICS PH",
|
||||
0xDB, "ASM FILE STATEMENT PHASE",
|
||||
0xDC, "ASM COMMON SUBROUTINES,ASCOM",
|
||||
0xE4, "ASM INTERMEDIATE I/O",
|
||||
0xE5, "ASM SYMBOL TABLE OVERFLOW",
|
||||
0xDD, "ASM PROG CONTROL MNEMONICS PH",
|
||||
0xDE, "ASM IMPERATIVE STATEMENTS PH",
|
||||
0xDF, "ASM DECML,XFLC PROCESSING PH",
|
||||
0xE0, "ASM DECIMAL CONVERSION PH",
|
||||
0xE1, "ASM PROG LINKAGE PHASE",
|
||||
0xE2, "ASM DMES PROCESSING PHASE",
|
||||
0xE3, "ASM PUNCH CONVERSION PHASE",
|
||||
0xE6, "ASM GRAPHIC ORDER PHASE",
|
||||
0xE8, "ASM CONTROL CARDS III",
|
||||
0xE9, "ASM MACRO PH 1 - SPECIAL OP AND PREPROCESSI",
|
||||
0xEA, "MACRO PHASE 1A - SPECIAL PSEUDO OPS",
|
||||
0xEB, "MACRO PHASE 1B - CONDITIONAL ASM PSEUDO OPS",
|
||||
0xEC, "ASM MACRO PHASE 2 - MACRO DEFINITION",
|
||||
0xED, "MACRO PHASE 2A - MACRO DEFINITION",
|
||||
0xEE, "MACRO PHASE 2B - MACRO DEFINITION",
|
||||
0xEF, "MACRO PHASE 3 - MACRO EXPANSION",
|
||||
0xF0, "MACRO PHASE 3A - MACRO EXPANSION",
|
||||
0xF1, "MACRO PHASE 3B - MACRO EXPANSION",
|
||||
0xE7, "ASM DIVISION OPERATOR",
|
||||
0xF2, "ASM CROSS-REFERENCE PART I",
|
||||
0xF3, "ASM CROSS-REFERENCE PART 2A",
|
||||
0xF4, "ASM CROSS-REFERENCE PART 2B",
|
||||
0xF5, "ASM CROSS-REFERENCE PART 2C",
|
||||
0xF6, "ASM CROSS-REFERENCE PART III",
|
||||
@@ -1,129 +0,0 @@
|
||||
// DMS R2V12 SLET without RPG, for debugging only
|
||||
|
||||
0x0001, 0x7c50, 0x032f, 0x0008,
|
||||
0x0002, 0x11de, 0x05a2, 0x000b,
|
||||
0x0003, 0x21de, 0x05a2, 0x0010,
|
||||
0x0004, 0x01de, 0x03c0, 0x0015,
|
||||
0x0005, 0x41de, 0x0550, 0x0018,
|
||||
0x0006, 0x01de, 0x03c0, 0x001d,
|
||||
0x0007, 0x01de, 0x05a2, 0x0020,
|
||||
0x0008, 0x01de, 0x05a2, 0x0025,
|
||||
0x0009, 0x01de, 0x0500, 0x002a,
|
||||
0x000a, 0x7a06, 0x00db, 0x002e,
|
||||
0x000b, 0x7a06, 0x0035, 0x002f,
|
||||
0x000c, 0x7a06, 0x00d8, 0x0030,
|
||||
0x000d, 0x7782, 0x087c, 0x0031,
|
||||
0x000e, 0x7a06, 0x0248, 0x0038,
|
||||
0x000f, 0x7a06, 0x0248, 0x003a,
|
||||
0x0010, 0x7a06, 0x0248, 0x003c,
|
||||
0x0011, 0x01de, 0x0280, 0x003e,
|
||||
0x0012, 0x0e6e, 0x0140, 0x0040,
|
||||
0x001f, 0x760c, 0x09f1, 0x0041,
|
||||
0x0020, 0x7a34, 0x0500, 0x0049,
|
||||
0x0021, 0x7a34, 0x0280, 0x004d,
|
||||
0x0022, 0x7a34, 0x03c0, 0x004f,
|
||||
0x0023, 0x7a34, 0x0500, 0x0052,
|
||||
0x0024, 0x7a34, 0x03c0, 0x0056,
|
||||
0x0025, 0x7a34, 0x0280, 0x0059,
|
||||
0x0026, 0x7a34, 0x0500, 0x005b,
|
||||
0x0027, 0x7a34, 0x03f0, 0x005f,
|
||||
0x0028, 0x7a34, 0x03c0, 0x0063,
|
||||
0x0029, 0x7a34, 0x03c0, 0x0066,
|
||||
0x002a, 0x7a34, 0x03c0, 0x0069,
|
||||
0x002b, 0x7a34, 0x03c0, 0x006c,
|
||||
0x002c, 0x7a34, 0x0500, 0x006f,
|
||||
0x002d, 0x7a34, 0x0500, 0x0073,
|
||||
0x002e, 0x7a34, 0x0500, 0x0077,
|
||||
0x002f, 0x7a34, 0x0500, 0x007b,
|
||||
0x0030, 0x7a34, 0x0500, 0x007f,
|
||||
0x0031, 0x7a34, 0x0404, 0x0083,
|
||||
0x0032, 0x7a34, 0x03c0, 0x0087,
|
||||
0x0033, 0x7a34, 0x03c0, 0x008a,
|
||||
0x0034, 0x7a34, 0x0280, 0x008d,
|
||||
0x0035, 0x7a34, 0x03c0, 0x008f,
|
||||
0x0036, 0x7a34, 0x03c0, 0x0092,
|
||||
0x0037, 0x7a34, 0x0500, 0x0095,
|
||||
0x0038, 0x7b96, 0x03c0, 0x0099,
|
||||
0x0039, 0x766e, 0x013e, 0x009c,
|
||||
0x006e, 0x04fe, 0x02fe, 0x009d,
|
||||
0x006f, 0x07fe, 0x052b, 0x00a0,
|
||||
0x0070, 0x07fe, 0x0280, 0x00a5,
|
||||
0x0071, 0x07fe, 0x0280, 0x00a7,
|
||||
0x0072, 0x07fe, 0x03ea, 0x00a9,
|
||||
0x0073, 0x0506, 0x04f8, 0x00ad,
|
||||
0x0074, 0x0400, 0x0189, 0x00b1,
|
||||
0x0078, 0x01e0, 0x0782, 0x00b3,
|
||||
0x0079, 0x05bc, 0x04dd, 0x00ba,
|
||||
0x007a, 0x08b6, 0x01e8, 0x00be,
|
||||
0x007b, 0x08b6, 0x01e8, 0x00c0,
|
||||
0x007c, 0x08b6, 0x01e8, 0x00c2,
|
||||
0x007d, 0x08b6, 0x01e8, 0x00c4,
|
||||
0x007e, 0x0aa0, 0x0140, 0x00c6,
|
||||
0x007f, 0x0aa0, 0x0140, 0x00c7,
|
||||
0x0080, 0x0aa0, 0x0140, 0x00c8,
|
||||
0x0081, 0x0aa0, 0x0140, 0x00c9,
|
||||
0x0082, 0x0be2, 0x0140, 0x00ca,
|
||||
0x0083, 0x08b6, 0x01e8, 0x00cb,
|
||||
0x0084, 0x0aa0, 0x0140, 0x00cd,
|
||||
0x008c, 0x0000, 0x0134, 0x80ceU,
|
||||
0x008d, 0x0000, 0x0113, 0x00cf,
|
||||
0x008e, 0x0000, 0x011f, 0x00d0,
|
||||
0x008f, 0x0000, 0x009c, 0x80d1U,
|
||||
0x0090, 0x0000, 0x00ab, 0x00d2,
|
||||
0x0091, 0x0000, 0x016c, 0x80d3U,
|
||||
0x0092, 0x0000, 0x0174, 0x00d5,
|
||||
0x0093, 0x0000, 0x00b9, 0x00d7,
|
||||
0x0094, 0x0000, 0x0003, 0x80d8U,
|
||||
0x0095, 0x0000, 0x0003, 0x00d9,
|
||||
0x0096, 0x00f0, 0x00ec, 0x00da,
|
||||
0x0097, 0x00f0, 0x01a2, 0x00db,
|
||||
0x0098, 0x00f0, 0x02b0, 0x00dd,
|
||||
0x0099, 0x0000, 0x0113, 0x00cf,
|
||||
0x009a, 0x0000, 0x00ab, 0x00d2,
|
||||
0x009b, 0x0000, 0x00ab, 0x00d2,
|
||||
0x009c, 0x0000, 0x00b9, 0x00d7,
|
||||
0x009d, 0x0000, 0x00b9, 0x00d7,
|
||||
0x00a0, 0x0000, 0x016c, 0x00e0,
|
||||
0x00a1, 0x0000, 0x01c0, 0x00e2,
|
||||
0x00cd, 0x11de, 0x0280, 0x00e4,
|
||||
0x00ce, 0x01de, 0x11df, 0x00e6,
|
||||
0x00cf, 0x01e0, 0x026b, 0x00f5,
|
||||
0x00d0, 0x01e8, 0x00bb, 0x00f7,
|
||||
0x00d1, 0x01e8, 0x005f, 0x00f8,
|
||||
0x00d2, 0x01e8, 0x005f, 0x00f9,
|
||||
0x00d3, 0x0280, 0x01d5, 0x00fa,
|
||||
0x00d4, 0x0ad0, 0x0145, 0x00fc,
|
||||
0x00d5, 0x0280, 0x01d6, 0x00fe,
|
||||
0x00d6, 0x0280, 0x0113, 0x0100,
|
||||
0x00d7, 0x0000, 0x0130, 0x0101,
|
||||
0x00d8, 0x07a8, 0x0254, 0x0102,
|
||||
0x00d9, 0x0280, 0x01d7, 0x0104,
|
||||
0x00da, 0x0280, 0x01a0, 0x0106,
|
||||
0x00db, 0x0282, 0x00a3, 0x0108,
|
||||
0x00dc, 0x0458, 0x05a7, 0x0109,
|
||||
0x00dd, 0x0280, 0x01d5, 0x010e,
|
||||
0x00de, 0x0280, 0x01d6, 0x0110,
|
||||
0x00df, 0x0280, 0x017c, 0x0112,
|
||||
0x00e0, 0x0282, 0x0127, 0x0114,
|
||||
0x00e1, 0x0280, 0x0196, 0x0115,
|
||||
0x00e2, 0x0280, 0x01d8, 0x0117,
|
||||
0x00e3, 0x0280, 0x0099, 0x0119,
|
||||
0x00e4, 0x098a, 0x005f, 0x011a,
|
||||
0x00e5, 0x098a, 0x0062, 0x011b,
|
||||
0x00e6, 0x0eca, 0x03c1, 0x011c,
|
||||
0x00e7, 0x0280, 0x00b8, 0x0120,
|
||||
0x00e8, 0x0280, 0x017f, 0x0121,
|
||||
0x00e9, 0x0280, 0x01d6, 0x0123,
|
||||
0x00ea, 0x0280, 0x01d9, 0x0125,
|
||||
0x00eb, 0x0280, 0x01d9, 0x0127,
|
||||
0x00ec, 0x0280, 0x01ca, 0x0129,
|
||||
0x00ed, 0x0280, 0x01c2, 0x012b,
|
||||
0x00ee, 0x05dc, 0x0158, 0x012d,
|
||||
0x00ef, 0x07ac, 0x0051, 0x012f,
|
||||
0x00f0, 0x0280, 0x01af, 0x0130,
|
||||
0x00f1, 0x12f4, 0x027f, 0x0132,
|
||||
0x00f2, 0x0280, 0x01c7, 0x0134,
|
||||
0x00f3, 0x07a8, 0x0052, 0x0136,
|
||||
0x00f4, 0x0924, 0x005b, 0x0137,
|
||||
0x00f5, 0x0886, 0x003d, 0x0138,
|
||||
0x00f6, 0x0eca, 0x03b2, 0x0139,
|
||||
@@ -1,372 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "ibm1130.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/ibm1130.exe $(OUTDIR)/ibm1130.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /YX /O2 /I "c:\pdp11\supnik" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /YX /O2 /I "c:\pdp11\supnik" /D "NDEBUG" /D "WIN32" /D\
|
||||
"_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR$(INTDIR)/ /Fp$(OUTDIR)/"ibm1130.pch"\
|
||||
/Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
RSC_PROJ=/l 0x409 /fo$(INTDIR)/"ibm1130.res" /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"ibm1130.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/ibm1130_cpu.sbr \
|
||||
$(INTDIR)/ibm1130_sys.sbr \
|
||||
$(INTDIR)/ibm1130_cr.sbr \
|
||||
$(INTDIR)/ibm1130_stddev.sbr \
|
||||
$(INTDIR)/ibm1130_disk.sbr \
|
||||
$(INTDIR)/ibm1130_gdu.sbr \
|
||||
$(INTDIR)/ibm1130_gui.sbr \
|
||||
$(INTDIR)/ibm1130_prt.sbr \
|
||||
$(INTDIR)/scp.sbr \
|
||||
$(INTDIR)/scp_tty.sbr \
|
||||
$(INTDIR)/sim_tmxr.sbr \
|
||||
$(INTDIR)/sim_sock.sbr \
|
||||
$(INTDIR)/ibm1130_fmt.sbr
|
||||
|
||||
$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\
|
||||
wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\
|
||||
/PDB:$(OUTDIR)/"ibm1130.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/ibm1130_cpu.obj \
|
||||
$(INTDIR)/ibm1130_sys.obj \
|
||||
$(INTDIR)/ibm1130_cr.obj \
|
||||
$(INTDIR)/ibm1130_stddev.obj \
|
||||
$(INTDIR)/ibm1130.res \
|
||||
$(INTDIR)/ibm1130_disk.obj \
|
||||
$(INTDIR)/ibm1130_gdu.obj \
|
||||
$(INTDIR)/ibm1130_gui.obj \
|
||||
$(INTDIR)/ibm1130_prt.obj \
|
||||
$(INTDIR)/scp.obj \
|
||||
$(INTDIR)/scp_tty.obj \
|
||||
$(INTDIR)/sim_tmxr.obj \
|
||||
$(INTDIR)/sim_sock.obj \
|
||||
$(INTDIR)/ibm1130_fmt.obj
|
||||
|
||||
$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/ibm1130.exe $(OUTDIR)/ibm1130.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /I "c:\pdp11\supnik" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /I "c:\pdp11\supnik" /D "_DEBUG" /D\
|
||||
"WIN32" /D "_CONSOLE" /D "GUI_SUPPORT" /U "VMS" /FR$(INTDIR)/\
|
||||
/Fp$(OUTDIR)/"ibm1130.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"ibm1130.pdb" /c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
RSC_PROJ=/l 0x409 /fo$(INTDIR)/"ibm1130.res" /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"ibm1130.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/ibm1130_cpu.sbr \
|
||||
$(INTDIR)/ibm1130_sys.sbr \
|
||||
$(INTDIR)/ibm1130_cr.sbr \
|
||||
$(INTDIR)/ibm1130_stddev.sbr \
|
||||
$(INTDIR)/ibm1130_disk.sbr \
|
||||
$(INTDIR)/ibm1130_gdu.sbr \
|
||||
$(INTDIR)/ibm1130_gui.sbr \
|
||||
$(INTDIR)/ibm1130_prt.sbr \
|
||||
$(INTDIR)/scp.sbr \
|
||||
$(INTDIR)/scp_tty.sbr \
|
||||
$(INTDIR)/sim_tmxr.sbr \
|
||||
$(INTDIR)/sim_sock.sbr \
|
||||
$(INTDIR)/ibm1130_fmt.sbr
|
||||
|
||||
$(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\
|
||||
wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\
|
||||
/PDB:$(OUTDIR)/"ibm1130.pdb" /DEBUG /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/ibm1130_cpu.obj \
|
||||
$(INTDIR)/ibm1130_sys.obj \
|
||||
$(INTDIR)/ibm1130_cr.obj \
|
||||
$(INTDIR)/ibm1130_stddev.obj \
|
||||
$(INTDIR)/ibm1130.res \
|
||||
$(INTDIR)/ibm1130_disk.obj \
|
||||
$(INTDIR)/ibm1130_gdu.obj \
|
||||
$(INTDIR)/ibm1130_gui.obj \
|
||||
$(INTDIR)/ibm1130_prt.obj \
|
||||
$(INTDIR)/scp.obj \
|
||||
$(INTDIR)/scp_tty.obj \
|
||||
$(INTDIR)/sim_tmxr.obj \
|
||||
$(INTDIR)/sim_sock.obj \
|
||||
$(INTDIR)/ibm1130_fmt.obj
|
||||
|
||||
$(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_cpu.c
|
||||
DEP_IBM11=\
|
||||
.\ibm1130_defs.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_cpu.obj : $(SOURCE) $(DEP_IBM11) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_sys.c
|
||||
DEP_IBM113=\
|
||||
.\ibm1130_defs.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_sys.obj : $(SOURCE) $(DEP_IBM113) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_cr.c
|
||||
DEP_IBM1130=\
|
||||
.\ibm1130_defs.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_cr.obj : $(SOURCE) $(DEP_IBM1130) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_stddev.c
|
||||
DEP_IBM1130_=\
|
||||
.\ibm1130_defs.h\
|
||||
.\ibm1130_conout.h\
|
||||
.\ibm1130_conin.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_stddev.obj : $(SOURCE) $(DEP_IBM1130_) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130.rc
|
||||
DEP_IBM1130_R=\
|
||||
.\1130consoleblank.bmp\
|
||||
.\hand.cur
|
||||
|
||||
$(INTDIR)/ibm1130.res : $(SOURCE) $(DEP_IBM1130_R) $(INTDIR)
|
||||
$(RSC) $(RSC_PROJ) $(SOURCE)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_disk.c
|
||||
DEP_IBM1130_D=\
|
||||
.\ibm1130_defs.h\
|
||||
.\dmsr2v12phases.h\
|
||||
.\dmsr2v12slet.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_disk.obj : $(SOURCE) $(DEP_IBM1130_D) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_gdu.c
|
||||
DEP_IBM1130_G=\
|
||||
.\ibm1130_defs.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_gdu.obj : $(SOURCE) $(DEP_IBM1130_G) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_gui.c
|
||||
DEP_IBM1130_GU=\
|
||||
.\ibm1130_defs.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_gui.obj : $(SOURCE) $(DEP_IBM1130_GU) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_prt.c
|
||||
DEP_IBM1130_P=\
|
||||
.\ibm1130_defs.h\
|
||||
.\ibm1130_prtwheel.h\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/ibm1130_prt.obj : $(SOURCE) $(DEP_IBM1130_P) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\pdp11\supnik\scp.c
|
||||
DEP_SCP_C=\
|
||||
..\sim_defs.h\
|
||||
\pdp11\supnik\sim_rev.h\
|
||||
\pdp11\supnik\sim_sock.h\
|
||||
\pdp11\supnik\sim_tmxr.h\
|
||||
\MSVC20\INCLUDE\sys\TYPES.H
|
||||
|
||||
$(INTDIR)/scp.obj : $(SOURCE) $(DEP_SCP_C) $(INTDIR)
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\scp_tty.c
|
||||
DEP_SCP_T=\
|
||||
..\sim_defs.h
|
||||
|
||||
$(INTDIR)/scp_tty.obj : $(SOURCE) $(DEP_SCP_T) $(INTDIR)
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\pdp11\supnik\sim_tmxr.c
|
||||
DEP_SIM_T=\
|
||||
..\sim_defs.h\
|
||||
\pdp11\supnik\sim_sock.h\
|
||||
\pdp11\supnik\sim_tmxr.h\
|
||||
\MSVC20\INCLUDE\sys\TYPES.H
|
||||
|
||||
$(INTDIR)/sim_tmxr.obj : $(SOURCE) $(DEP_SIM_T) $(INTDIR)
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=\pdp11\supnik\sim_sock.c
|
||||
DEP_SIM_S=\
|
||||
..\sim_defs.h\
|
||||
\pdp11\supnik\sim_sock.h\
|
||||
\MSVC20\INCLUDE\sys\TYPES.H
|
||||
|
||||
$(INTDIR)/sim_sock.obj : $(SOURCE) $(DEP_SIM_S) $(INTDIR)
|
||||
$(CPP) $(CPP_PROJ) $(SOURCE)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ibm1130_fmt.c
|
||||
|
||||
$(INTDIR)/ibm1130_fmt.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
@@ -1,61 +0,0 @@
|
||||
//Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "ibm1130res.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include <windows.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"ibm1130res.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include <windows.h>\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bitmap
|
||||
//
|
||||
|
||||
IDB_CONSOLE BITMAP DISCARDABLE "1130consoleblank.bmp"
|
||||
|
||||
IDC_HAND CURSOR DISCARDABLE "HAND.CUR"
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
// 03 ctrl-C => Program stop (not handled here)
|
||||
// 05 ctrl-E => Simulator stop (not handled here)
|
||||
// 08 ctrl-H => Backspace
|
||||
// 0D ctrl-M (Enter) => EOF
|
||||
// 11 ctrl-Q => Interrupt request (not handled here)
|
||||
// 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard)
|
||||
// 15 ctrl-U => Erase Field
|
||||
// 7E ~ => "not"
|
||||
// FF Del => Backspace again
|
||||
|
||||
static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key flags) */
|
||||
{
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */
|
||||
/* 00 */ 0, 0, 0, 0, 0, 0, 0, 0,0x0004, 0, 0, 0, 0,0x0008, 0, 0,
|
||||
/* 10 */ 0, 0,0x8820, 0, 0,0x0002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 20 */ 0x0001,0x4820,0x0060,0x0420,0x4420,0x2220,0x8000,0x0120,0x8120,0x4120,0x4220,0x80a0,0x2420,0x4000,0x8420,0x3000,
|
||||
/* 30 */ 0x2000,0x1000,0x0800,0x0400,0x0200,0x0100,0x0080,0x0040,0x0020,0x0010,0x0820,0x40a0,0x8220,0x00a0,0x20a0,0x2060,
|
||||
/* 40 */ 0x0220,0x9000,0x8800,0x8400,0x8200,0x8100,0x8080,0x8040,0x8020,0x8010,0x5000,0x4800,0x4400,0x4200,0x4100,0x4080,
|
||||
/* 50 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010, 0, 0, 0, 0,0x2120,
|
||||
/* 60 */ 0,0x9000,0x8800,0x8400,0x8200,0x8100,0x8080,0x8040,0x8020,0x8010,0x5000,0x4800,0x4400,0x4200,0x4100,0x4080,
|
||||
/* 70 */ 0x4040,0x4020,0x4010,0x2800,0x2400,0x2200,0x2100,0x2080,0x2040,0x2020,0x2010, 0,0xB060, 0, 0,0x0004,
|
||||
/* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0x0004,
|
||||
};
|
||||
@@ -1,58 +0,0 @@
|
||||
/* IBM1130 CONSOLE OUTPUT TO ASCII CONVERSION TABLE
|
||||
*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
#define _0_ '\0'
|
||||
|
||||
#define CENT_ '\xA2' /* cent and not: standard DOS mapping */
|
||||
#define NOT_ '\xAC'
|
||||
#define IGNR_ '\xFF'
|
||||
#define CRLF_ '\r'
|
||||
|
||||
#define COUT_IS_CTRL 0x01 /* conout characters with bit 1 set are controls: */
|
||||
|
||||
#define COUT_CTRL_BLACK 0x04 /* none or one of these bits */
|
||||
#define COUT_CTRL_RED 0x08
|
||||
|
||||
#define COUT_CTRL_LINEFEED 0x02 /* plus none or one of these bits */
|
||||
#define COUT_CTRL_BACKSPACE 0x10
|
||||
#define COUT_CTRL_SPACE 0x20
|
||||
#define COUT_CTRL_TAB 0x40
|
||||
#define COUT_CTRL_RETURN 0x80
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4245) /* enable int->char demotion warning caused by characters with high-bit set */
|
||||
#endif
|
||||
|
||||
static unsigned char conout_to_ascii[] = /* console output code to ASCII */
|
||||
{
|
||||
/* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */
|
||||
/* 00 */ '.', IGNR_,CENT_, '\n', '@', IGNR_,'%', _0_, _0_, IGNR_,_0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* 10 */ 'F', '\b', 'f', _0_, 'G', _0_, 'g', _0_, 'B', _0_, 'b', _0_, 'C', _0_, 'c', _0_,
|
||||
/* 20 */ 'I', ' ', 'i', _0_, 'H', _0_, 'h', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* 30 */ 'D', _0_, 'd', _0_, 'E', _0_, 'e', _0_, _0_, _0_, _0_, _0_, 'A', _0_, 'a', _0_,
|
||||
/* 40 */ '$', '\t', '!', _0_, '&', _0_, '>', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* 50 */ 'O', _0_, 'o', _0_, 'P', _0_, 'o', _0_, 'K', _0_, 'k', _0_, 'L', _0_, 'l', _0_,
|
||||
/* 60 */ 'R', _0_, 'r', _0_, 'Q', _0_, 'q', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* 70 */ 'M', _0_, 'm', _0_, 'N', _0_, 'n', _0_, _0_, _0_, _0_, _0_, 'J', _0_, 'j', _0_,
|
||||
/* 80 */ ',', CRLF_, ':', _0_, '-', _0_, '?', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* 90 */ 'W', _0_, 'w', _0_, 'X', _0_, 'x', _0_, 'S', _0_, 's', _0_, 'T', _0_, 't', _0_,
|
||||
/* A0 */ 'Z', _0_, 'z', _0_, 'Y', _0_, 'y', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* B0 */ 'U', _0_, 'u', _0_, 'V', _0_, 'v', _0_, _0_, _0_, _0_, _0_, '/', _0_, '_', _0_,
|
||||
/* C0 */ '#', _0_, '=', _0_, '0', _0_, '|', _0_, _0_, _0_, _0_, _0_, 'J', _0_, 'j', _0_,
|
||||
/* D0 */ '6', _0_, ';', _0_, '7', _0_, '*', _0_, '2', _0_, '+', _0_, '3', _0_, '<', _0_,
|
||||
/* E0 */ '9', _0_, '"', _0_, '8', _0_, '\'', _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_, _0_,
|
||||
/* F0 */ '4', _0_, NOT_, _0_, '5', _0_, ')', _0_, _0_, _0_, _0_, _0_, '1', _0_, '(', _0_,
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(default:4245) /* enable int->char demotion warning */
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
2079
Ibm1130/ibm1130_cr.c
2079
Ibm1130/ibm1130_cr.c
File diff suppressed because it is too large
Load Diff
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
/* ibm1130_defs.h: IBM-1130 simulator definitions
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* main SIMH defns (include path should include .., or make a copy) */
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(VMS)
|
||||
# include <unistd.h> /* to pick up 'unlink' */
|
||||
#endif
|
||||
|
||||
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
|
||||
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
|
||||
|
||||
#ifndef WIN32
|
||||
int strnicmp (char *a, char *b, int n);
|
||||
int strcmpi (char *a, char *b);
|
||||
#endif
|
||||
|
||||
// #define GUI_SUPPORT // uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Architectural constants */
|
||||
|
||||
#define MAXMEMSIZE (32768) /* 32Kwords */
|
||||
#define INIMEMSIZE (16384) /* 16Kwords */
|
||||
#define MEMSIZE (cpu_unit.capac)
|
||||
|
||||
#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */
|
||||
|
||||
#define ILL_ADR_FLAG 0x40000000 /* an impossible 1130 address */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Global state */
|
||||
|
||||
extern int cgi; // TRUE if we are running as a CGI program
|
||||
extern int sim_gui;
|
||||
|
||||
extern uint16 M[]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */
|
||||
extern uint16 ILSW[]; /* interrupt level status words */
|
||||
extern int32 IAR; /* instruction address register */
|
||||
extern int32 prev_IAR; /* instruction address register at start of current instruction */
|
||||
extern int32 SAR, SBR; /* storage address/buffer registers */
|
||||
extern int32 OP, TAG, CCC; /* instruction decoded pieces */
|
||||
extern int32 CES; /* console entry switches */
|
||||
extern int32 ACC, EXT; /* accumulator and extension */
|
||||
extern int32 RUNMODE; /* processor run/step mode */
|
||||
extern int32 ipl; /* current interrupt level (-1 = not handling irq) */
|
||||
extern int32 iplpending; /* interrupted IPL's */
|
||||
extern int32 tbit; /* trace flag (causes level 5 IRQ after each instr) */
|
||||
extern int32 V, C; /* condition codes */
|
||||
extern int32 wait_state; /* wait state (waiting for an IRQ) */
|
||||
extern int32 wait_lamp; /* alternate indicator to light the wait lamp on the GUI */
|
||||
extern int32 int_req; /* sum of interrupt request levels active */
|
||||
extern int32 int_lamps; /* accumulated version of int_req - gives lamp persistence */
|
||||
extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */
|
||||
extern int32 mem_mask;
|
||||
extern int32 cpu_dsw; /* CPU device status word */
|
||||
extern int32 sim_int_char; /* interrupt character */
|
||||
extern t_bool running;
|
||||
extern t_bool power;
|
||||
extern t_bool cgi; /* TRUE if we are running as a CGI program */
|
||||
extern t_stat reason; /* CPU execution loop control */
|
||||
|
||||
#define WAIT_OP 1 /* wait state causes: wait instruction, invalid instruction*/
|
||||
#define WAIT_INVALID_OP 2
|
||||
|
||||
#define MODE_SS 3 /* RUNMODE values. SS and SMC are not implemented in this simulator */
|
||||
#define MODE_SMC 2
|
||||
#define MODE_INT_RUN 1
|
||||
#define MODE_RUN 0
|
||||
#define MODE_SI -1
|
||||
#define MODE_DISP -2
|
||||
#define MODE_LOAD -3
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* debugging */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#define ENABLE_DEBUG_PRINT
|
||||
#define ENABLE_DEBUG_TO_LOG
|
||||
|
||||
#ifdef ENABLE_DEBUG_PRINT
|
||||
# define DEBUG_PRINT debug_print
|
||||
#else
|
||||
# ifdef ENABLE_DEBUG_TO_LOG
|
||||
# define DEBUG_PRINT trace_io
|
||||
# else
|
||||
# define DEBUG_PRINT if (0) debug_print
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void debug_print(char *fmt, ...);
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* memory IO routines */
|
||||
|
||||
int32 ReadW (int32 a);
|
||||
void WriteW (int32 a, int32 d);
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* handy macros */
|
||||
|
||||
#define CLRBIT(v,b) ((v) &= ~(b))
|
||||
#define SETBIT(v,b) ((v) |= (b))
|
||||
#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b)))
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_WAIT 1 /* wait, no events */
|
||||
#define STOP_INVALID_INSTR 2 /* bad instruction */
|
||||
#define STOP_IBKPT 3 /* simulator breakpoint */
|
||||
#define STOP_INCOMPLETE 4 /* simulator coding not complete here */
|
||||
#define STOP_POWER_OFF 5 /* no power */
|
||||
#define STOP_DECK_BREAK 6 /* !BREAK in deck file */
|
||||
#define STOP_PHASE_BREAK 7 /* phase load break */
|
||||
#define STOP_CRASH 8 /* program has crashed badly */
|
||||
#define STOP_TIMED_OUT 9 /* simulation time limit exceeded */
|
||||
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
|
||||
|
||||
#define INT_REQ_0 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */
|
||||
#define INT_REQ_1 0x02
|
||||
#define INT_REQ_2 0x04
|
||||
#define INT_REQ_3 0x08
|
||||
#define INT_REQ_4 0x10
|
||||
#define INT_REQ_5 0x20
|
||||
|
||||
#define XIO_UNUSED 0x00 /* XIO commands */
|
||||
#define XIO_WRITE 0x01
|
||||
#define XIO_READ 0x02
|
||||
#define XIO_SENSE_IRQ 0x03
|
||||
#define XIO_CONTROL 0x04
|
||||
#define XIO_INITW 0x05
|
||||
#define XIO_INITR 0x06
|
||||
#define XIO_SENSE_DEV 0x07
|
||||
|
||||
#define XIO_FAILED 0x20 /* fake function to record error */
|
||||
|
||||
/* ILSW bits - set by appropriate device whenever an interrupt is outstanding */
|
||||
|
||||
#define ILSW_0_1442_CARD 0x8000 /* ILSW 0 is not really defined on the 1130 */
|
||||
|
||||
#define ILSW_1_1132_PRINTER 0x8000 // had these backwards!
|
||||
#define ILSW_1_SCA 0x4000
|
||||
|
||||
#define ILSW_2_1131_DISK 0x8000
|
||||
|
||||
#define ILSW_2_2310_DRV_1 0x4000
|
||||
#define ILSW_2_2310_DRV_2 0x2000
|
||||
#define ILSW_2_2310_DRV_3 0x1000
|
||||
#define ILSW_2_2310_DRV_4 0x0800 /* can have 2310 or 2311 */
|
||||
|
||||
#define ILSW_2_2311_DRV_1_DISK_1 0x4000
|
||||
#define ILSW_2_2311_DRV_1_DISK_2 0x2000
|
||||
#define ILSW_2_2311_DRV_1_DISK_3 0x1000
|
||||
#define ILSW_2_2311_DRV_1_DISK_4 0x0800
|
||||
|
||||
#define ILSW_2_2311_DRV_1_DISK_5 0x0400
|
||||
#define ILSW_2_2311_DRV_2_DISK_1 0x0200
|
||||
#define ILSW_2_2311_DRV_2_DISK_2 0x0100
|
||||
#define ILSW_2_2311_DRV_2_DISK_3 0x0080
|
||||
#define ILSW_2_2311_DRV_2_DISK_4 0x0040
|
||||
#define ILSW_2_2311_DRV_2_DISK_5 0x0020
|
||||
|
||||
#define ILSW_2_SAC_BIT_11 0x0010
|
||||
#define ILSW_2_SAC_BIT_12 0x0008
|
||||
#define ILSW_2_SAC_BIT_13 0x0004
|
||||
#define ILSW_2_SAC_BIT_14 0x0002
|
||||
#define ILSW_2_SAC_BIT_15 0x0001
|
||||
|
||||
#define ILSW_3_1627_PLOTTER 0x8000
|
||||
#define ILSW_3_SAC_BIT_01 0x4000
|
||||
#define ILSW_3_SAC_BIT_02 0x2000
|
||||
#define ILSW_3_SAC_BIT_03 0x1000
|
||||
#define ILSW_3_2250_DISPLAY 0x0800
|
||||
#define ILSW_3_SYSTEM7 0x0800
|
||||
#define ILSW_3_SAC_BIT_05 0x0400
|
||||
#define ILSW_3_SAC_BIT_06 0x0200
|
||||
#define ILSW_3_SAC_BIT_07 0x0100
|
||||
#define ILSW_3_SAC_BIT_08 0x0080
|
||||
#define ILSW_3_SAC_BIT_09 0x0040
|
||||
#define ILSW_3_SAC_BIT_10 0x0020
|
||||
#define ILSW_3_SAC_BIT_11 0x0010
|
||||
#define ILSW_3_SAC_BIT_12 0x0008
|
||||
#define ILSW_3_SAC_BIT_13 0x0004
|
||||
#define ILSW_3_SAC_BIT_14 0x0002
|
||||
#define ILSW_3_SAC_BIT_15 0x0001
|
||||
|
||||
#define ILSW_4_1134_TAPE 0x8000
|
||||
#define ILSW_4_1055_TAPE 0x8000
|
||||
#define ILSW_4_CONSOLE 0x4000
|
||||
#define ILSW_4_1442_CARD 0x2000
|
||||
#define ILSW_4_2501_CARD 0x1000
|
||||
#define ILSW_4_1403_PRINTER 0x0800
|
||||
#define ILSW_4_1231_MARK 0x0400
|
||||
#define ILSW_4_SAC_BIT_06 0x0200
|
||||
#define ILSW_4_SAC_BIT_07 0x0100
|
||||
#define ILSW_4_SAC_BIT_08 0x0080
|
||||
#define ILSW_4_SAC_BIT_09 0x0040
|
||||
#define ILSW_4_SAC_BIT_10 0x0020
|
||||
#define ILSW_4_SAC_BIT_11 0x0010
|
||||
#define ILSW_4_SAC_BIT_12 0x0008
|
||||
#define ILSW_4_SAC_BIT_13 0x0004
|
||||
#define ILSW_4_SAC_BIT_14 0x0002
|
||||
#define ILSW_4_SAC_BIT_15 0x0001
|
||||
|
||||
#define ILSW_5_INT_RUN 0x8000
|
||||
#define ILSW_5_PROGRAM_STOP 0x8000
|
||||
#define ILSW_5_SAC_BIT_01 0x4000
|
||||
#define ILSW_5_SAC_BIT_02 0x2000
|
||||
#define ILSW_5_SAC_BIT_03 0x1000
|
||||
#define ILSW_5_SAC_BIT_04 0x0800
|
||||
#define ILSW_5_SAC_BIT_05 0x0400
|
||||
#define ILSW_5_SAC_BIT_06 0x0200
|
||||
#define ILSW_5_SAC_BIT_07 0x0100
|
||||
#define ILSW_5_SAC_BIT_08 0x0080
|
||||
#define ILSW_5_SAC_BIT_09 0x0040
|
||||
#define ILSW_5_SAC_BIT_10 0x0020
|
||||
#define ILSW_5_SAC_BIT_11 0x0010
|
||||
#define ILSW_5_SAC_BIT_12 0x0008
|
||||
#define ILSW_5_SAC_BIT_13 0x0004
|
||||
#define ILSW_5_SAC_BIT_14 0x0002
|
||||
#define ILSW_5_SAC_BIT_15 0x0001
|
||||
|
||||
//* CPU DSW bits
|
||||
|
||||
#define CPU_DSW_PROGRAM_STOP 0x8000
|
||||
#define CPU_DSW_INT_RUN 0x4000
|
||||
|
||||
/* prototypes: xio handlers */
|
||||
|
||||
void xio_1131_console (int32 addr, int32 func, int32 modify); // console keyboard and printer
|
||||
void xio_1142_card (int32 addr, int32 func, int32 modify); // standard card reader/punch
|
||||
void xio_1134_papertape (int32 addr, int32 func, int32 modify); // paper tape reader/punch
|
||||
void xio_disk (int32 addr, int32 func, int32 modify, int drv); // internal CPU disk
|
||||
void xio_1627_plotter (int32 addr, int32 func, int32 modify); // XY plotter
|
||||
void xio_1132_printer (int32 addr, int32 func, int32 modify); // standard line printer
|
||||
void xio_1131_switches (int32 addr, int32 func, int32 modify); // console buttons & switches
|
||||
void xio_1231_optical (int32 addr, int32 func, int32 modify); // optical mark page reader
|
||||
void xio_2501_card (int32 addr, int32 func, int32 modify); // alternate high-speed card reader
|
||||
void xio_1131_synch (int32 addr, int32 func, int32 modify); // synchronous communications adapter
|
||||
void xio_system7 (int32 addr, int32 func, int32 modify); // system/7 interprocessor IO link
|
||||
void xio_1403_printer (int32 addr, int32 func, int32 modify); // alternate high-speed printer
|
||||
void xio_2250_display (int32 addr, int32 func, int32 modify); // vector display processor
|
||||
void xio_error (char *msg);
|
||||
|
||||
void bail (char *msg);
|
||||
t_stat load_cr_boot (int drv, int switches);
|
||||
t_stat cr_boot (int unitno, DEVICE *dptr);
|
||||
void calc_ints (void); /* recalculate interrupt bitmask */
|
||||
void trace_io (char *fmt, ...); /* debugging printout */
|
||||
void scp_panic (char *msg); /* bail out of simulator */
|
||||
char *upcase(char *str);
|
||||
void break_simulation (t_stat reason); /* let a device halt the simulation */
|
||||
char hollerith_to_ascii (uint16 hol); /* for debugging use only */
|
||||
t_bool gdu_active (void);
|
||||
void remark_cmd (char *remark);
|
||||
void stuff_cmd (char *cmd);
|
||||
void update_gui (t_bool force);
|
||||
void sim_init (void);
|
||||
t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help);
|
||||
|
||||
/* GUI interface routines */
|
||||
t_bool keyboard_is_busy (void);
|
||||
void forms_check (int set); /* device notification to console lamp display */
|
||||
void print_check (int set);
|
||||
void keyboard_selected (int select);
|
||||
void disk_ready (int ready);
|
||||
void disk_unlocked (int unlocked);
|
||||
void gui_run(int running);
|
||||
char *read_cmdline (char *ptr, int size, FILE *stream);
|
||||
|
||||
#ifdef GUI_SUPPORT
|
||||
# define GUI_BEGIN_CRITICAL_SECTION begin_critical_section();
|
||||
# define GUI_END_CRITICAL_SECTION end_critical_section();
|
||||
void begin_critical_section (void);
|
||||
void end_critical_section (void);
|
||||
#else
|
||||
# define GUI_BEGIN_CRITICAL_SECTION
|
||||
# define GUI_END_CRITICAL_SECTION
|
||||
#endif
|
||||
@@ -1,875 +0,0 @@
|
||||
/* ibm1130_disk.c: IBM 1130 disk IO simulator
|
||||
|
||||
NOTE - there is a problem with this code. The Device Status Word (DSW) is
|
||||
computed from current conditions when requested by an XIO load status
|
||||
command; the value of DSW available to the simulator's examine & save
|
||||
commands may NOT be accurate. This should probably be fixed.
|
||||
|
||||
Based on the SIMH package written by Robert M Supnik
|
||||
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* Revision History
|
||||
* 15-jun-03 moved actual read on XIO read to end of time interval,
|
||||
* as the APL boot card required 2 instructions to run between the
|
||||
* time read was initiated and the time the data was read (a jump and a wait)
|
||||
*
|
||||
* 01-sep-02 corrected treatment of -m and -r flags in dsk_attach
|
||||
* in cgi mode, so that file is opened readonly but emulated
|
||||
* disk is writable.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to simh@ibm1130.org
|
||||
*/
|
||||
|
||||
#include "ibm1130_defs.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define TRACE_DMS_IO // define to enable debug of DMS phase IO
|
||||
|
||||
#ifdef TRACE_DMS_IO
|
||||
extern int32 sim_switches;
|
||||
extern int32 sim_quiet;
|
||||
static int trace_dms = 0;
|
||||
static void tracesector (int iswrite, int nwords, int addr, int sector);
|
||||
static t_stat where_cmd (int flag, char *ptr);
|
||||
static t_stat phdebug_cmd (int flag, char *ptr);
|
||||
static t_stat fdump_cmd (int flags, char *cptr);
|
||||
static void enable_dms_tracing (int newsetting);
|
||||
#endif
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define DSK_NUMWD 321 /* words/sector */
|
||||
#define DSK_NUMSC 4 /* sectors/surface */
|
||||
#define DSK_NUMSF 2 /* surfaces/cylinder */
|
||||
#define DSK_NUMCY 203 /* cylinders/drive */
|
||||
#define DSK_NUMTR (DSK_NUMCY * DSK_NUMSF) /* tracks/drive */
|
||||
#define DSK_NUMDR 5 /* drives/controller */
|
||||
#define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */
|
||||
|
||||
#define UNIT_V_RONLY (UNIT_V_UF + 0) /* hwre write lock */
|
||||
#define UNIT_V_OPERR (UNIT_V_UF + 1) /* operation error flag */
|
||||
#define UNIT_V_HARDERR (UNIT_V_UF + 2) /* hard error flag (reset on power down) */
|
||||
#define UNIT_RONLY (1u << UNIT_V_RONLY)
|
||||
#define UNIT_OPERR (1u << UNIT_V_OPERR)
|
||||
#define UNIT_HARDERR (1u << UNIT_V_HARDERR)
|
||||
|
||||
#define MEM_MAPPED(uptr) (uptr->flags & UNIT_BUF) /* disk buffered in memory */
|
||||
|
||||
#define IO_NONE 0 /* last operation, used to ensure fseek between read and write */
|
||||
#define IO_READ 1
|
||||
#define IO_WRITE 2
|
||||
|
||||
#define DSK_DSW_DATA_ERROR 0x8000 /* device status word bits */
|
||||
#define DSK_DSW_OP_COMPLETE 0x4000
|
||||
#define DSK_DSW_NOT_READY 0x2000
|
||||
#define DSK_DSW_DISK_BUSY 0x1000
|
||||
#define DSK_DSW_CARRIAGE_HOME 0x0800
|
||||
#define DSK_DSW_SECTOR_MASK 0x0003
|
||||
|
||||
/* device status words */
|
||||
static int16 dsk_dsw[DSK_NUMDR] = {DSK_DSW_NOT_READY, DSK_DSW_NOT_READY, DSK_DSW_NOT_READY, DSK_DSW_NOT_READY, DSK_DSW_NOT_READY};
|
||||
static int16 dsk_sec[DSK_NUMDR] = {0}; /* next-sector-up */
|
||||
static char dsk_lastio[DSK_NUMDR]; /* last stdio operation: IO_READ or IO_WRITE */
|
||||
int32 dsk_swait = 50; /* seek time -- see how short a delay we can get away with */
|
||||
int32 dsk_rwait = 50; /* rotate time */
|
||||
static t_bool raw_disk_debug = FALSE;
|
||||
|
||||
static t_stat dsk_svc (UNIT *uptr);
|
||||
static t_stat dsk_reset (DEVICE *dptr);
|
||||
static t_stat dsk_attach (UNIT *uptr, char *cptr);
|
||||
static t_stat dsk_detach (UNIT *uptr);
|
||||
static t_stat dsk_boot (int unitno, DEVICE *dptr);
|
||||
|
||||
static void diskfail (UNIT *uptr, int errflag);
|
||||
|
||||
/* DSK data structures
|
||||
|
||||
dsk_dev disk device descriptor
|
||||
dsk_unit unit descriptor
|
||||
dsk_reg register list
|
||||
*/
|
||||
|
||||
UNIT dsk_unit[] = {
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
|
||||
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }
|
||||
};
|
||||
|
||||
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
|
||||
|
||||
/* Parameters in the unit descriptor */
|
||||
|
||||
#define CYL u3 /* current cylinder */
|
||||
#define FUNC u4 /* current function */
|
||||
|
||||
REG dsk_reg[] = {
|
||||
{ HRDATA (DSKDSW0, dsk_dsw[0], 16) },
|
||||
{ HRDATA (DSKDSW1, dsk_dsw[1], 16) },
|
||||
{ HRDATA (DSKDSW2, dsk_dsw[2], 16) },
|
||||
{ HRDATA (DSKDSW3, dsk_dsw[3], 16) },
|
||||
{ HRDATA (DSKDSW4, dsk_dsw[4], 16) },
|
||||
{ DRDATA (STIME, dsk_swait, 24), PV_LEFT },
|
||||
{ DRDATA (RTIME, dsk_rwait, 24), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dsk_mod[] = {
|
||||
{ UNIT_RONLY, 0, "write enabled", "ENABLED", NULL },
|
||||
{ UNIT_RONLY, UNIT_RONLY, "write locked", "LOCKED", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dsk_dev = {
|
||||
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||
DSK_NUMDR, 16, 16, 1, 16, 16,
|
||||
NULL, NULL, &dsk_reset,
|
||||
dsk_boot, dsk_attach, dsk_detach};
|
||||
|
||||
static int32 dsk_ilswbit[DSK_NUMDR] = { /* interrupt level status word bits for the drives */
|
||||
ILSW_2_1131_DISK,
|
||||
ILSW_2_2310_DRV_1,
|
||||
ILSW_2_2310_DRV_2,
|
||||
ILSW_2_2310_DRV_3,
|
||||
ILSW_2_2310_DRV_4,
|
||||
};
|
||||
|
||||
static int32 dsk_ilswlevel[DSK_NUMDR] =
|
||||
{
|
||||
2, /* interrupt levels for the drives */
|
||||
2, 2, 2, 2
|
||||
};
|
||||
|
||||
typedef enum {DSK_FUNC_IDLE, DSK_FUNC_READ, DSK_FUNC_VERIFY, DSK_FUNC_WRITE, DSK_FUNC_SEEK, DSK_FUNC_FAILED} DSK_FUNC;
|
||||
|
||||
static struct tag_dsk_action { /* stores data needed for pending IO activity */
|
||||
int32 io_address;
|
||||
uint32 io_filepos;
|
||||
int io_nwords;
|
||||
int io_sector;
|
||||
} dsk_action[DSK_NUMDR];
|
||||
|
||||
/* xio_disk - XIO command interpreter for the disk drives */
|
||||
/*
|
||||
* device status word:
|
||||
*
|
||||
* 0 data error, occurs when:
|
||||
* 1. A modulo 4 error is detected during a read, read-check, or write operation.
|
||||
* 2. The disk storage is in a read or write mode at the leading edge of a sector pulse.
|
||||
* 3. A seek-incomplete signal is received from the 2311.
|
||||
* 4. A write select error has occurred in the disk storage drive.
|
||||
* 5. The power unsafe latch is set in the attachment.
|
||||
* Conditions 1, 2, and 3 are turned off by a sense device command with modifier bit 15
|
||||
* set to 1. Conditions 4 and 5 are turned off by powering the drive off and back on.
|
||||
* 1 operation complete
|
||||
* 2 not ready, occurs when disk not ready or busy or disabled or off-line or
|
||||
* power unsafe latch set. Also included in the disk not ready is the write select error,
|
||||
* which can be a result of power unsafe or write select.
|
||||
* 3 disk busy
|
||||
* 4 carriage home (on cyl 0)
|
||||
* 15-16: number of next sector spinning into position.
|
||||
*/
|
||||
|
||||
extern void void_backtrace (int afrom, int ato);
|
||||
|
||||
void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
|
||||
{
|
||||
int i, rev, nsteps, newcyl, sec, nwords;
|
||||
uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development
|
||||
char msg[80];
|
||||
UNIT *uptr = dsk_unit+drv;
|
||||
int16 buf[DSK_NUMWD];
|
||||
|
||||
if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { // hmmm, invalid drive */
|
||||
if (func != XIO_SENSE_DEV) { // tried to use it, too
|
||||
// just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads
|
||||
// sprintf(msg, "Op %x on invalid drive number %d", func, drv);
|
||||
// xio_error(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLRBIT(uptr->flags, UNIT_OPERR); /* clear pending error flag from previous op, if any */
|
||||
|
||||
switch (func) {
|
||||
case XIO_INITR:
|
||||
if (! IS_ONLINE(uptr)) { /* disk is offline */
|
||||
diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */
|
||||
break;
|
||||
}
|
||||
|
||||
sim_cancel(uptr); /* cancel any pending ops */
|
||||
dsk_dsw[drv] |= DSK_DSW_DISK_BUSY; /* and mark the disk as busy */
|
||||
|
||||
nwords = M[iocc_addr++ & mem_mask]; /* get word count w/o upsetting SAR/SBR */
|
||||
|
||||
if (nwords == 0) /* this is bad -- on real 1130, this locks up disk controller ! */
|
||||
break;
|
||||
|
||||
if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */
|
||||
SETBIT(uptr->flags, UNIT_OPERR); /* set data error DSW bit when op complete */
|
||||
nwords = DSK_NUMWD; /* limit xfer to proper sector size */
|
||||
}
|
||||
|
||||
sec = modify & 0x07; /* get sector on cylinder */
|
||||
|
||||
if ((modify & 0x0080) == 0) { /* it's a real read if it's not a read check */
|
||||
// ah. We have a problem. The APL boot card counts on there being time for at least one
|
||||
// more instruction to execute between the XIO read and the time the data starts loading
|
||||
// into core. So, we have to defer the actual read operation a bit. Might as well wait
|
||||
// until it's time to issue the operation complete interrupt. This means saving the
|
||||
// IO information, then performing the actual read in dsk_svc.
|
||||
|
||||
newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD;
|
||||
|
||||
dsk_action[drv].io_address = iocc_addr;
|
||||
dsk_action[drv].io_nwords = nwords;
|
||||
dsk_action[drv].io_sector = sec;
|
||||
dsk_action[drv].io_filepos = newpos;
|
||||
|
||||
uptr->FUNC = DSK_FUNC_READ;
|
||||
}
|
||||
else {
|
||||
trace_io("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec);
|
||||
|
||||
if (raw_disk_debug)
|
||||
printf("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec);
|
||||
|
||||
uptr->FUNC = DSK_FUNC_VERIFY;
|
||||
}
|
||||
|
||||
sim_activate(uptr, dsk_rwait);
|
||||
break;
|
||||
|
||||
case XIO_INITW:
|
||||
if (! IS_ONLINE(uptr)) { /* disk is offline */
|
||||
diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */
|
||||
break;
|
||||
}
|
||||
|
||||
if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error */
|
||||
diskfail(uptr, UNIT_HARDERR);
|
||||
break;
|
||||
}
|
||||
|
||||
sim_cancel(uptr); /* cancel any pending ops */
|
||||
dsk_dsw[drv] |= DSK_DSW_DISK_BUSY; /* and mark drive as busy */
|
||||
|
||||
nwords = M[iocc_addr++ & mem_mask]; /* get word count w/o upsetting SAR/SBR */
|
||||
|
||||
if (nwords == 0) /* this is bad -- locks up disk controller ! */
|
||||
break;
|
||||
|
||||
if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */
|
||||
SETBIT(uptr->flags, UNIT_OPERR); /* set data error DSW bit when op complete */
|
||||
nwords = DSK_NUMWD; /* limit xfer to proper sector size */
|
||||
}
|
||||
|
||||
sec = modify & 0x07; /* get sector on cylinder */
|
||||
newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD;
|
||||
|
||||
trace_io("* DSK%d wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)", drv, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos);
|
||||
|
||||
if (raw_disk_debug)
|
||||
printf("* DSK%d XIO @ %04x wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)\n", drv, prev_IAR, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos);
|
||||
|
||||
#ifdef TRACE_DMS_IO
|
||||
if (trace_dms)
|
||||
tracesector(1, nwords, iocc_addr & mem_mask, uptr->CYL*8 + sec);
|
||||
#endif
|
||||
for (i = 0; i < nwords; i++)
|
||||
buf[i] = M[iocc_addr++ & mem_mask];
|
||||
|
||||
for (; i < DSK_NUMWD; i++) /* rest of sector gets zeroed */
|
||||
buf[i] = 0;
|
||||
|
||||
i = uptr->CYL*8 + sec;
|
||||
if (buf[0] != i)
|
||||
printf("*DSK writing bad sector#\n");
|
||||
|
||||
if (MEM_MAPPED(uptr)) {
|
||||
memcpy((char *) uptr->filebuf + newpos, buf, 2*DSK_NUMWD);
|
||||
uptr->hwmark = newpos + 2*DSK_NUMWD;
|
||||
}
|
||||
else {
|
||||
if (uptr->pos != newpos || dsk_lastio[drv] != IO_WRITE) {
|
||||
fseek(uptr->fileref, newpos, SEEK_SET);
|
||||
dsk_lastio[drv] = IO_WRITE;
|
||||
}
|
||||
|
||||
fxwrite(buf, 2, DSK_NUMWD, uptr->fileref);
|
||||
uptr->pos = newpos + 2*DSK_NUMWD;
|
||||
}
|
||||
|
||||
uptr->FUNC = DSK_FUNC_WRITE;
|
||||
sim_activate(uptr, dsk_rwait);
|
||||
break;
|
||||
|
||||
case XIO_CONTROL: /* step fwd/rev */
|
||||
if (! IS_ONLINE(uptr)) {
|
||||
diskfail(uptr, UNIT_HARDERR);
|
||||
break;
|
||||
}
|
||||
|
||||
sim_cancel(uptr);
|
||||
|
||||
rev = modify & 4;
|
||||
nsteps = iocc_addr & 0x00FF;
|
||||
if (nsteps == 0) /* 0 steps does not cause op complete interrupt */
|
||||
break;
|
||||
|
||||
newcyl = uptr->CYL + (rev ? (-nsteps) : nsteps);
|
||||
if (newcyl < 0)
|
||||
newcyl = 0;
|
||||
else if (newcyl >= DSK_NUMCY)
|
||||
newcyl = DSK_NUMCY-1;
|
||||
|
||||
uptr->FUNC = DSK_FUNC_SEEK;
|
||||
uptr->CYL = newcyl;
|
||||
sim_activate(uptr, dsk_swait); /* schedule interrupt */
|
||||
|
||||
dsk_dsw[drv] |= DSK_DSW_DISK_BUSY;
|
||||
trace_io("* DSK%d at cyl %d", drv, newcyl);
|
||||
break;
|
||||
|
||||
case XIO_SENSE_DEV:
|
||||
CLRBIT(dsk_dsw[drv], DSK_DSW_CARRIAGE_HOME|DSK_DSW_NOT_READY);
|
||||
|
||||
if ((uptr->flags & UNIT_HARDERR) || (dsk_dsw[drv] & DSK_DSW_DISK_BUSY) || ! IS_ONLINE(uptr))
|
||||
SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY);
|
||||
else if (uptr->CYL <= 0) {
|
||||
SETBIT(dsk_dsw[drv], DSK_DSW_CARRIAGE_HOME);
|
||||
uptr->CYL = 0;
|
||||
}
|
||||
|
||||
dsk_sec[drv] = (dsk_sec[drv] + 1) % 4; /* advance the "next sector" count every time */
|
||||
ACC = dsk_dsw[drv] | dsk_sec[drv];
|
||||
|
||||
if (modify & 0x01) { /* reset interrupts */
|
||||
CLRBIT(dsk_dsw[drv], DSK_DSW_OP_COMPLETE|DSK_DSW_DATA_ERROR);
|
||||
CLRBIT(ILSW[dsk_ilswlevel[drv]], dsk_ilswbit[drv]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(msg, "Invalid disk XIO function %x", func);
|
||||
xio_error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* diskfail - schedule an operation complete that sets the error bit */
|
||||
|
||||
static void diskfail (UNIT *uptr, int errflag)
|
||||
{
|
||||
sim_cancel(uptr); /* cancel any pending ops */
|
||||
SETBIT(uptr->flags, errflag); /* set the error flag */
|
||||
uptr->FUNC = DSK_FUNC_FAILED; /* tell svc routine why it failed */
|
||||
sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */
|
||||
}
|
||||
|
||||
t_stat dsk_svc (UNIT *uptr)
|
||||
{
|
||||
int drv = uptr - dsk_unit, i, nwords, sec;
|
||||
int16 buf[DSK_NUMWD];
|
||||
uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development
|
||||
int32 iocc_addr;
|
||||
|
||||
if (uptr->FUNC == DSK_FUNC_IDLE) /* service function called with no activity? not good, but ignore */
|
||||
return SCPE_OK;
|
||||
|
||||
CLRBIT(dsk_dsw[drv], DSK_DSW_DISK_BUSY); /* activate operation complete interrupt */
|
||||
SETBIT(dsk_dsw[drv], DSK_DSW_OP_COMPLETE);
|
||||
|
||||
if (uptr->flags & (UNIT_OPERR|UNIT_HARDERR)) { /* word count error or data error */
|
||||
SETBIT(dsk_dsw[drv], DSK_DSW_DATA_ERROR);
|
||||
CLRBIT(uptr->flags, UNIT_OPERR); /* soft error is one time occurrence; don't clear hard error */
|
||||
}
|
||||
/* schedule interrupt */
|
||||
SETBIT(ILSW[dsk_ilswlevel[drv]], dsk_ilswbit[drv]);
|
||||
|
||||
switch (uptr->FUNC) { /* take care of business */
|
||||
case DSK_FUNC_IDLE:
|
||||
case DSK_FUNC_VERIFY:
|
||||
case DSK_FUNC_WRITE:
|
||||
case DSK_FUNC_SEEK:
|
||||
case DSK_FUNC_FAILED:
|
||||
break;
|
||||
|
||||
case DSK_FUNC_READ: /* actually read the data into core */
|
||||
iocc_addr = dsk_action[drv].io_address; /* recover saved parameters */
|
||||
nwords = dsk_action[drv].io_nwords;
|
||||
newpos = dsk_action[drv].io_filepos;
|
||||
sec = dsk_action[drv].io_sector;
|
||||
|
||||
if (MEM_MAPPED(uptr)) {
|
||||
memcpy(buf, (char *) uptr->filebuf + newpos, 2*DSK_NUMWD);
|
||||
}
|
||||
else {
|
||||
if (uptr->pos != newpos || dsk_lastio[drv] != IO_READ) {
|
||||
fseek(uptr->fileref, newpos, SEEK_SET);
|
||||
dsk_lastio[drv] = IO_READ;
|
||||
uptr->pos = newpos;
|
||||
}
|
||||
fxread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read
|
||||
uptr->pos = newpos + 2*DSK_NUMWD;
|
||||
}
|
||||
|
||||
void_backtrace(iocc_addr, iocc_addr + nwords - 1); // mark prev instruction as altered
|
||||
|
||||
trace_io("* DSK%d read %d words from %d.%d (%x, %x) to M[%04x-%04x]", drv, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask,
|
||||
(iocc_addr + nwords - 1) & mem_mask);
|
||||
|
||||
// // this will help debug the monitor by letting me watch phase loading
|
||||
if (raw_disk_debug)
|
||||
printf("* DSK%d XIO @ %04x read %d words from %d.%d (%x, %x) to M[%04x-%04x]\n", drv, prev_IAR, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask,
|
||||
(iocc_addr + nwords - 1) & mem_mask);
|
||||
|
||||
i = uptr->CYL*8 + sec;
|
||||
if (buf[0] != i)
|
||||
printf("*DSK read bad sector #\n");
|
||||
|
||||
for (i = 0; i < nwords; i++)
|
||||
M[(iocc_addr+i) & mem_mask] = buf[i];
|
||||
|
||||
#ifdef TRACE_DMS_IO
|
||||
if (trace_dms)
|
||||
tracesector(0, nwords, iocc_addr & mem_mask, uptr->CYL*8 + sec);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unexpected FUNC %x in dsk_svc(%d)\n", uptr->FUNC, drv);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
uptr->FUNC = DSK_FUNC_IDLE; // we're done with this operation
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat dsk_reset (DEVICE *dptr)
|
||||
{
|
||||
int drv;
|
||||
UNIT *uptr;
|
||||
|
||||
#ifdef TRACE_DMS_IO
|
||||
// add the WHERE command. It finds the phase that was loaded at given address and indicates
|
||||
// the offset in the phase
|
||||
register_cmd("WHERE", &where_cmd, 0, "w{here} address find phase and offset of an address\n");
|
||||
register_cmd("PHDEBUG", &phdebug_cmd, 0, "ph{debug} off|phlo phhi break on phase load\n");
|
||||
register_cmd("FDUMP", &fdump_cmd, 0, NULL);
|
||||
#endif
|
||||
|
||||
for (drv = 0, uptr = dsk_dev.units; drv < DSK_NUMDR; drv++, uptr++) {
|
||||
sim_cancel(uptr);
|
||||
|
||||
CLRBIT(ILSW[2], dsk_ilswbit[drv]);
|
||||
CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR);
|
||||
|
||||
uptr->CYL = 0;
|
||||
uptr->FUNC = DSK_FUNC_IDLE;
|
||||
dsk_dsw[drv] = (uptr->flags & UNIT_ATT) ? DSK_DSW_CARRIAGE_HOME : 0;
|
||||
}
|
||||
|
||||
calc_ints();
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat dsk_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
int drv = uptr - dsk_unit;
|
||||
t_stat rval;
|
||||
|
||||
sim_cancel(uptr); // cancel current IO
|
||||
dsk_lastio[drv] = IO_NONE;
|
||||
|
||||
if (uptr->flags & UNIT_ATT) // dismount current disk
|
||||
if ((rval = dsk_detach(uptr)) != SCPE_OK)
|
||||
return rval;
|
||||
|
||||
uptr->CYL = 0; // reset the device
|
||||
uptr->FUNC = DSK_FUNC_IDLE;
|
||||
dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME;
|
||||
|
||||
CLRBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_BUFABLE|UNIT_BUF|UNIT_RONLY|UNIT_OPERR|UNIT_HARDERR);
|
||||
CLRBIT(ILSW[2], dsk_ilswbit[drv]);
|
||||
calc_ints();
|
||||
|
||||
if (sim_switches & SWMASK('M')) // if memory mode (e.g. for CGI), buffer the file
|
||||
SETBIT(uptr->flags, UNIT_BUFABLE);
|
||||
|
||||
if (sim_switches & SWMASK('R')) // read lock mode
|
||||
SETBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_RONLY);
|
||||
|
||||
if (cgi && (sim_switches & SWMASK('M'))) { // if cgi and memory mode,
|
||||
sim_switches |= SWMASK('R'); // have attach_unit open file in readonly mode
|
||||
SETBIT(uptr->flags, UNIT_ROABLE|UNIT_MUSTBUF); // but don't set the UNIT_RONLY flag so DMS can write to the buffered image
|
||||
}
|
||||
|
||||
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) { // mount new disk
|
||||
SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY);
|
||||
return rval;
|
||||
}
|
||||
|
||||
if (drv == 0) {
|
||||
disk_ready(TRUE);
|
||||
disk_unlocked(FALSE);
|
||||
}
|
||||
|
||||
enable_dms_tracing(sim_switches & SWMASK('D'));
|
||||
raw_disk_debug = sim_switches & SWMASK('G');
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat dsk_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat rval;
|
||||
int drv = uptr - dsk_unit;
|
||||
|
||||
sim_cancel(uptr);
|
||||
|
||||
if ((rval = detach_unit (uptr)) != SCPE_OK)
|
||||
return rval;
|
||||
|
||||
CLRBIT(ILSW[2], dsk_ilswbit[drv]);
|
||||
CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR);
|
||||
calc_ints();
|
||||
|
||||
uptr->CYL = 0;
|
||||
uptr->FUNC = DSK_FUNC_IDLE;
|
||||
dsk_dsw[drv] = DSK_DSW_NOT_READY;
|
||||
|
||||
if (drv == 0) {
|
||||
disk_unlocked(TRUE);
|
||||
disk_ready(FALSE);
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
// boot routine - if they type BOOT DSK, load the standard boot card.
|
||||
|
||||
static t_stat dsk_boot (int unitno, DEVICE *dptr)
|
||||
{
|
||||
t_stat rval;
|
||||
|
||||
if ((rval = reset_all(0)) != SCPE_OK)
|
||||
return rval;
|
||||
|
||||
return load_cr_boot(unitno, sim_switches);
|
||||
}
|
||||
|
||||
#ifdef TRACE_DMS_IO
|
||||
|
||||
static struct {
|
||||
int phid;
|
||||
char *name;
|
||||
} phase[] = {
|
||||
# include "dmsr2v12phases.h"
|
||||
0xFFFF, ""
|
||||
};
|
||||
|
||||
#pragma pack(2)
|
||||
#define MAXSLET ((3*320)/4)
|
||||
struct tag_slet {
|
||||
int16 phid;
|
||||
int16 addr;
|
||||
int16 nwords;
|
||||
int16 sector;
|
||||
} slet[MAXSLET] = {
|
||||
# include "dmsr2v12slet.h" // without RPG, use this info until overwritten by actual data from disk
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define MAXMSEG 100
|
||||
struct tag_mseg {
|
||||
char *name;
|
||||
int addr, offset, len, phid;
|
||||
} mseg[MAXMSEG];
|
||||
int nseg = 0;
|
||||
|
||||
static void enable_dms_tracing (int newsetting)
|
||||
{
|
||||
nseg = 0; // clear the segment map
|
||||
|
||||
if ((newsetting && trace_dms) || ! (newsetting || trace_dms))
|
||||
return;
|
||||
|
||||
trace_dms = newsetting;
|
||||
if (! sim_quiet)
|
||||
printf("DMS disk tracing is now %sabled\n", trace_dms ? "en" : "dis");
|
||||
}
|
||||
|
||||
char * saywhere (int addr)
|
||||
{
|
||||
int i;
|
||||
static char buf[150];
|
||||
|
||||
for (i = 0; i < nseg; i++) {
|
||||
if (addr >= mseg[i].addr && addr < (mseg[i].addr+mseg[i].len)) {
|
||||
sprintf(buf, "/%04x = /%04x + /%x in ", addr, mseg[i].addr - mseg[i].offset, addr-mseg[i].addr + mseg[i].offset);
|
||||
if (mseg[i].phid > 0)
|
||||
sprintf(buf+strlen(buf), "phase %02x (%s)", mseg[i].phid, mseg[i].name);
|
||||
else
|
||||
sprintf(buf+strlen(buf), "%s", mseg[i].name);
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int phdebug_lo = -1, phdebug_hi = -1;
|
||||
|
||||
static t_stat phdebug_cmd (int flag, char *ptr)
|
||||
{
|
||||
int val1, val2;
|
||||
|
||||
if (strcmpi(ptr, "off") == 0)
|
||||
phdebug_lo = phdebug_hi = -1;
|
||||
else {
|
||||
switch(sscanf(ptr, "%x%x", &val1, &val2)) {
|
||||
case 1:
|
||||
phdebug_lo = phdebug_hi = val1;
|
||||
enable_dms_tracing(TRUE);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
phdebug_lo = val1;
|
||||
phdebug_hi = val2;
|
||||
enable_dms_tracing(TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Usage: phdebug off | phdebug phfrom [phto]\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat where_cmd (int flag, char *ptr)
|
||||
{
|
||||
int addr;
|
||||
char *where;
|
||||
|
||||
if (! trace_dms) {
|
||||
printf("Tracing is disabled. To enable, attach disk with -d switch\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (sscanf(ptr, "%x", &addr) != 1)
|
||||
return SCPE_ARG;
|
||||
|
||||
if ((where = saywhere(addr)) == NULL)
|
||||
printf("/%04x not found\n", addr);
|
||||
else
|
||||
printf("%s\n", where);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
// savesector - save info on a sector just read. THIS IS NOT YET TESTED
|
||||
|
||||
static void addseg (int i)
|
||||
{
|
||||
if (! trace_dms)
|
||||
return;
|
||||
|
||||
if (nseg >= MAXMSEG) {
|
||||
printf("(Memory map full, disabling tracing)\n");
|
||||
trace_dms = 0;
|
||||
nseg = -1;
|
||||
return;
|
||||
}
|
||||
memcpy(mseg+i+1, mseg+i, (nseg-i)*sizeof(mseg[0]));
|
||||
nseg++;
|
||||
}
|
||||
|
||||
static void delseg (int i)
|
||||
{
|
||||
if (! trace_dms)
|
||||
return;
|
||||
|
||||
if (nseg > 0) {
|
||||
nseg--;
|
||||
memcpy(mseg+i, mseg+i+1, (nseg-i)*sizeof(mseg[0]));
|
||||
}
|
||||
}
|
||||
|
||||
static void savesector (int addr, int offset, int len, int phid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (! trace_dms)
|
||||
return;
|
||||
|
||||
addr++; // first word is sector address, so account for that
|
||||
len--;
|
||||
|
||||
for (i = 0; i < nseg; i++) {
|
||||
if (addr >= (mseg[i].addr+mseg[i].len)) // entirely after this entry
|
||||
continue;
|
||||
|
||||
if (mseg[i].addr < addr) { // old one starts before this. split it
|
||||
addseg(i);
|
||||
mseg[i].len = addr-mseg[i].addr;
|
||||
i++;
|
||||
mseg[i].addr = addr;
|
||||
mseg[i].len -= mseg[i-1].len;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
addseg(i); // add new segment. Old one ends up after this
|
||||
|
||||
if (i >= MAXMSEG)
|
||||
return;
|
||||
|
||||
mseg[i].addr = addr;
|
||||
mseg[i].offset = offset;
|
||||
mseg[i].phid = phid;
|
||||
mseg[i].len = len;
|
||||
mseg[i].name = name;
|
||||
|
||||
i++; // delete any segments completely covered
|
||||
|
||||
while (i < nseg && (mseg[i].addr+mseg[i].len) <= (addr+len))
|
||||
delseg(i);
|
||||
|
||||
if (i < nseg && mseg[i].addr < (addr+len)) { // old one extends past this. Retain the end
|
||||
mseg[i].len = (mseg[i].addr+mseg[i].len) - (addr+len);
|
||||
mseg[i].addr = addr+len;
|
||||
}
|
||||
}
|
||||
|
||||
static void tracesector (int iswrite, int nwords, int addr, int sector)
|
||||
{
|
||||
int i, phid = 0, sletind = -1, offset = 0;
|
||||
char *name = NULL;
|
||||
|
||||
if (nwords < 3 || ! trace_dms)
|
||||
return;
|
||||
|
||||
switch (sector) { // explicitly known sector name
|
||||
case 0: name = "ID/COLD START"; break;
|
||||
case 1: name = "DCOM"; break;
|
||||
case 2: name = "RESIDENT IMAGE"; break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5: name = "SLET"; // save just-read or written SLET info
|
||||
memmove(&slet[(320/4)*(sector-3)], &M[addr+1], nwords*2);
|
||||
break;
|
||||
case 6: name = "RELOAD TABLE"; break;
|
||||
case 7: name = "PAGE HEADER"; break;
|
||||
}
|
||||
|
||||
printf("* %04x: %3d /%04x %c %3d.%d ",
|
||||
prev_IAR, nwords, addr, iswrite ? '>' : '<', sector/8, sector%8);
|
||||
|
||||
if (name == NULL) { // look up sector in SLET
|
||||
for (i = 0; i < MAXSLET; i++) {
|
||||
if (slet[i].phid == 0) // not found
|
||||
goto done;
|
||||
else if (slet[i].sector > sector) {
|
||||
if (--i >= 0) {
|
||||
if (sector >= slet[i].sector && sector <= (slet[i].sector + slet[i].nwords/320)) {
|
||||
phid = slet[i].phid;
|
||||
offset = (sector-slet[i].sector)*320;
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
if (slet[i].sector == sector) {
|
||||
phid = slet[i].phid; // we found the starting sector
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= MAXSLET) // was not found
|
||||
goto done;
|
||||
|
||||
name = "?";
|
||||
for (i = sizeof(phase)/sizeof(phase[0]); --i >= 0; ) {
|
||||
if (phase[i].phid == phid) { // look up name
|
||||
name = phase[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("%02x %s", phid, name);
|
||||
}
|
||||
else
|
||||
printf("%s", name);
|
||||
|
||||
done:
|
||||
putchar('\n');
|
||||
|
||||
if (phid >= phdebug_lo && phid <= phdebug_hi && offset == 0)
|
||||
break_simulation(STOP_PHASE_BREAK); // break on read of first sector of indicated phases
|
||||
|
||||
if (name != NULL && *name != '?' && ! iswrite)
|
||||
savesector(addr, offset, nwords, phid, name);
|
||||
}
|
||||
|
||||
static t_stat fdump_cmd (int flags, char *cptr)
|
||||
{
|
||||
int addr = 0x7a24; // address of next statement;
|
||||
int sofst = 0x7a26, symaddr;
|
||||
int cword, nwords, stype, has_stnum, strel = 1, laststno = 0;
|
||||
|
||||
addr = M[addr & mem_mask] & mem_mask; // get address of first statement
|
||||
sofst = M[sofst & mem_mask] & mem_mask; // get address of symbol table
|
||||
|
||||
for (;;) {
|
||||
cword = M[addr];
|
||||
nwords = (cword >> 2) & 0x01FF;
|
||||
stype = (cword >> 1) & 0x7C00;
|
||||
has_stnum = (cword & 1);
|
||||
|
||||
if (has_stnum) {
|
||||
laststno++;
|
||||
strel = 0;
|
||||
}
|
||||
|
||||
printf("/%04x [%4d +%3d] %3d - %04x", addr, laststno, strel, nwords, stype);
|
||||
|
||||
if (has_stnum) {
|
||||
addr++;
|
||||
nwords--;
|
||||
symaddr = sofst - (M[addr] & 0x7FF)*3 + 3;
|
||||
printf(" [%04x %04x %04x]", M[symaddr], M[symaddr+1], M[symaddr+2]);
|
||||
}
|
||||
|
||||
if (stype == 0x5000) { // error record
|
||||
printf(" (err %d)", M[addr+1]);
|
||||
}
|
||||
|
||||
if (stype == 0x0800)
|
||||
break;
|
||||
|
||||
addr += nwords;
|
||||
putchar('\n');
|
||||
|
||||
if (nwords == 0) {
|
||||
printf("0 words?\n");
|
||||
break;
|
||||
}
|
||||
strel++;
|
||||
}
|
||||
|
||||
printf("\nEnd found at /%04x, EOFS = /%04x\n", addr, M[0x7a25 & mem_mask]);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
#endif // TRACE_DMS_IO
|
||||
@@ -1,303 +0,0 @@
|
||||
// ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source
|
||||
// Bob Flanders
|
||||
// -------------------------------------------------------------------------------------------
|
||||
//
|
||||
// These routines are used by ibm1130_cr.c when the user has indicated
|
||||
// that the input text is formatted with tabs. Input lines are edited
|
||||
// into the appropriate column format. Three edit modes are recognized:
|
||||
//
|
||||
// Assembler mode:
|
||||
// Input lines of the form
|
||||
//
|
||||
// [label]<whitespace>[opcode]<tab>[tag][L]<tab>[argument]
|
||||
//
|
||||
// are rearranged so that the input fields are placed in the appropriate columns
|
||||
//
|
||||
// The label must start on the first character of the line. If there is no label,
|
||||
// the first character(s) before the opcode must be whitespace. Following the opcode, there
|
||||
// MUST be a tab character, followed by the format and tag. Following the format and tag
|
||||
// may be exactly one whitespace character, and then starts the argument.
|
||||
//
|
||||
// Input lines with * in column 1 and blank lines are turned into Assembler comments,
|
||||
// with the * in the Opcode field.
|
||||
//
|
||||
// Assembler directive lines at the beginning of the deck must be preceded by
|
||||
// ! to indicate that they are not comments. For example,
|
||||
//
|
||||
// !*LIST
|
||||
// * This is a comment
|
||||
//
|
||||
// Fortran mode:
|
||||
// Input lines of the form
|
||||
//
|
||||
// [label]<tab>statement
|
||||
//
|
||||
// or
|
||||
//
|
||||
// [label]<tab>Xcontinuation
|
||||
//
|
||||
// where X is a non alphabetic contination character are rearranged in the
|
||||
// appropriate manner:
|
||||
//
|
||||
// 1 2
|
||||
// 12345678901234567890...
|
||||
// ------------------------
|
||||
// label statement
|
||||
// labelXcontinuation
|
||||
//
|
||||
// However, you must take care that you don't end up with statement text after column 72.
|
||||
//
|
||||
// Input lines with * or C in column 1 are left alone (comments and directives)
|
||||
//
|
||||
// (The ! escape is not used before Fortran directives as before Assembler directives)
|
||||
//
|
||||
// Tab mode:
|
||||
// Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide,
|
||||
// as is standard for vi, notepad, etc.
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <ctype.h>
|
||||
#include "ibm1130_fmt.h"
|
||||
|
||||
#define MAXLINE 81 // maximum output line size
|
||||
#define WORKSZ 256 // size for tab work area
|
||||
#define TAGOFFSET 12 // offset for tag field
|
||||
#define FMTOFFSET 11 // offset for format field
|
||||
|
||||
#define MIN(a,b) ((a < b) ? a : b)
|
||||
#define AMSG " with Assembler Reformat"
|
||||
#define FMSG " with FORTRAN Reformat"
|
||||
#define AFORMAT "%20.20s%-60.60s"," "
|
||||
#define ACOMMENTFMT "%20.20s%-60.60s"," "
|
||||
#define ABLANKLINE "%20.20s*"," "
|
||||
#define FFORMAT "%-5.5s %-74.74s"
|
||||
#define FCONTFMT "%-5.5s%-75.75s"
|
||||
|
||||
char gszLabel[6]; // work area for label
|
||||
char gszArg[MAXLINE]; // .. argument
|
||||
char gszOutput[MAXLINE]; // .. output
|
||||
short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};// tab stops for assembler
|
||||
|
||||
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};// tab stops for just plain tabs
|
||||
|
||||
// ///////////////
|
||||
// helper routines
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// ExpandTabs: Expand tabs to spaces
|
||||
|
||||
char* ExpandTabs(char* p_szInbuf, // expand tabs .. input buffer
|
||||
char* p_szOutbuf, // .. output buffer
|
||||
short* p_aiTabs) // .. array of tab stops (1 based) -- 0 end of array
|
||||
{
|
||||
short iI, // input position
|
||||
iO, // output position
|
||||
iT; // next tab stop
|
||||
|
||||
char cX; // character to test
|
||||
|
||||
iI = 0; // init input position
|
||||
iO = 0; // init output position
|
||||
iT = 0; // init tab stop
|
||||
|
||||
while (cX = *(p_szInbuf + iI)) // while there are characters
|
||||
{
|
||||
if (cX == '\t') // q. tab character?
|
||||
{ // a. yes ..
|
||||
while ((p_aiTabs[iT] <= iO + 1) // search for next valid stop ..
|
||||
&& (p_aiTabs[iT] != 0)) // .. or end of table
|
||||
iT++; // .. go to next tab
|
||||
|
||||
if (p_aiTabs[iT] != 0) // q. end of tab array?
|
||||
{ // a. no ..
|
||||
while (iO < (p_aiTabs[iT] - 1)) // fill to tab with blanks
|
||||
*(p_szOutbuf + iO++) = ' '; // .. put in a blank
|
||||
|
||||
}
|
||||
else // Otherwise ...
|
||||
*(p_szOutbuf + iO++) = ' '; // .. Translate to blank
|
||||
}
|
||||
else // Otherwise .. not tab
|
||||
*(p_szOutbuf + iO++) = cX; // .. save the input char
|
||||
|
||||
iI++; // next input character
|
||||
}
|
||||
|
||||
*(p_szOutbuf + iO) = 0; // end the string..
|
||||
return p_szOutbuf; // .. return output area addr
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
// extract next token, modify pointer
|
||||
|
||||
char* GetToken(char* p_szOut, // output location
|
||||
int p_iLen, // max output length
|
||||
char**p_pszToken) // pointer to input token
|
||||
{
|
||||
int iI; // work integer
|
||||
char* pszX; // work pointer
|
||||
|
||||
pszX = *p_pszToken; // get pointer to token
|
||||
|
||||
for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) // while not whitespace & not end
|
||||
iI++; // .. count token length
|
||||
|
||||
memset(p_szOut, 0, p_iLen); // zero out output area
|
||||
|
||||
if (iI > 0) // q. any chars?
|
||||
strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); // a. yes.. copy max of p_iLen-1
|
||||
|
||||
*p_pszToken += iI; // point beyond token
|
||||
return p_szOut; // .. return token pointer
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// EditToAsm - convert tab-formatted text line to 1130 Assembler format
|
||||
|
||||
char *EditToAsm (char* p_pszEdit) // convert line to 1130 assembler
|
||||
{
|
||||
char pszLine[MAXLINE]; // source line
|
||||
char pszWork[WORKSZ]; // work buffer
|
||||
char acTFWrk[2]; // tag/format work area
|
||||
size_t iI; // work integer
|
||||
|
||||
if (p_pszEdit == NULL) // q. null request?
|
||||
return AMSG; // a. yes .. return display message
|
||||
|
||||
if (*p_pszEdit == '!') // leave lines starting with ! alone
|
||||
return EditToWhitespace(p_pszEdit+1);
|
||||
|
||||
if (*p_pszEdit == '*') // q. comment line?
|
||||
{ // a. yes..
|
||||
strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); // .. convert any tabs
|
||||
sprintf(gszOutput, ACOMMENTFMT, pszWork); // .. put the comment out there in the opcode column
|
||||
return gszOutput; // .. and return it
|
||||
}
|
||||
|
||||
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
|
||||
|
||||
ExpandTabs(pszLine, pszWork, gaiAsmTabs); // expand the tabs
|
||||
strncpy(pszLine, pszWork, MAXLINE-1); // copy the line back
|
||||
|
||||
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace
|
||||
{
|
||||
if (*(pszLine + iI) <= ' ') // q. space or less?
|
||||
*(pszLine + iI) = 0; // a. yes .. remove it
|
||||
else // otherwise
|
||||
break; // .. done. Leave loop.
|
||||
}
|
||||
|
||||
if (strlen(pszLine) == 0) // q. blank line?
|
||||
{ // a. yes .. Assembler abhors these so
|
||||
sprintf(gszOutput, ABLANKLINE); // format as comment statement
|
||||
return gszOutput; // .. and return it
|
||||
}
|
||||
|
||||
|
||||
// TODO: Add code to process a strip switch
|
||||
// comment?
|
||||
|
||||
if (strlen(pszLine) > (TAGOFFSET + 1)) // q. line long enough?
|
||||
{ // a. yes.. reorder tag/format
|
||||
memcpy(acTFWrk, pszLine + FMTOFFSET, 2); // get tag/format
|
||||
memset((pszLine + FMTOFFSET), ' ', 2); // .. blank 'em out
|
||||
|
||||
for (iI = 0; iI < 2; iI ++)
|
||||
if (isalpha(acTFWrk[iI])) // q. alpha char?
|
||||
*(pszLine + FMTOFFSET) = acTFWrk[iI]; // a. yes .. make it format
|
||||
else if (isdigit(acTFWrk[iI])) // q. digit?
|
||||
*(pszLine + TAGOFFSET) = acTFWrk[iI]; // a. yes .. make it the tag
|
||||
}
|
||||
|
||||
sprintf(gszOutput, AFORMAT, pszLine); // format the line
|
||||
|
||||
return gszOutput; // return formatted line
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// EditToFortran - convert tab-formatted input text line to FORTRAN format
|
||||
// (a la DEC Fortran)
|
||||
|
||||
char *EditToFortran(char* p_pszEdit) // convert line to 1130 assembler
|
||||
{
|
||||
char pszLine[MAXLINE]; // source line
|
||||
char* pszWork; // work pointer
|
||||
size_t iI; // work integer
|
||||
char bContinue; // true if continue
|
||||
|
||||
if (p_pszEdit == NULL) // q. null request?
|
||||
return FMSG; // a. yes .. return display message
|
||||
|
||||
if (strchr(p_pszEdit, '\t') == NULL) // q. no tab in the line?
|
||||
return p_pszEdit; // a. nope, return line as is, assume it's formatted correctly
|
||||
|
||||
if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') // q. comment or directive or blank line?
|
||||
{ // a. yes.. don't restructure
|
||||
return EditToWhitespace(p_pszEdit);
|
||||
}
|
||||
|
||||
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
|
||||
|
||||
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace
|
||||
{
|
||||
if (*(pszLine + iI) <= ' ') // q. space or less?
|
||||
*(pszLine + iI) = 0; // a. yes .. remove it
|
||||
else // otherwise
|
||||
break; // .. done. Leave loop.
|
||||
}
|
||||
|
||||
// TODO: Add code to process a strip switch
|
||||
// comment?
|
||||
|
||||
pszWork = (char*) pszLine; // set pointer to line
|
||||
GetToken(gszLabel, 6, &pszWork); // get the line, if any.
|
||||
|
||||
pszWork++; // skip tab/whitespace
|
||||
|
||||
// continuation...
|
||||
bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) // if first char non-zero digit
|
||||
|| (!isspace(*pszWork) && !isalpha(*pszWork))); // .. or non-alpha non-blank
|
||||
|
||||
memset(gszArg, 0, MAXLINE); // .. and arguments
|
||||
|
||||
strncpy(gszArg, pszWork, 75); // copy rest to argument
|
||||
|
||||
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, // format the line
|
||||
gszLabel, // .. statement #
|
||||
gszArg); // .. code
|
||||
|
||||
return gszOutput; // return formatted line
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// EditToWhitespace - expand tabs at 8 space intervals.
|
||||
|
||||
char* EditToWhitespace(char *p_pszEdit)
|
||||
{
|
||||
int iI; /* work integer */
|
||||
char pszLine[MAXLINE]; // source line
|
||||
char pszWork[WORKSZ]; // work buffer
|
||||
|
||||
if (p_pszEdit == NULL) // q. null request?
|
||||
return AMSG; // a. yes .. return display message
|
||||
|
||||
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
|
||||
|
||||
ExpandTabs(pszLine, pszWork, gaiPlainTabs); // expand the tabs
|
||||
strncpy(gszOutput, pszWork, MAXLINE-1); // copy the line back
|
||||
|
||||
for (iI = strlen(gszOutput); iI--;) // look at each character
|
||||
{
|
||||
if (*(gszOutput + iI) <= ' ') // q. space or less?
|
||||
*(gszOutput + iI) = 0; // a. yes .. remove it
|
||||
else // otherwise
|
||||
break; // .. done. Leave loop.
|
||||
}
|
||||
|
||||
|
||||
return gszOutput; /* ... return buffer */
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2003, Bob Flander.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to bob@jftr.com
|
||||
*/
|
||||
|
||||
/* ibm1130_asm.h: definition of routines in ibm1130_asm.c
|
||||
*/
|
||||
|
||||
char* EditToAsm(char*); // convert edit format to 1130 assembler format
|
||||
char* EditToFortran(char*); // convert edit format to Fortran format
|
||||
char* EditToWhitespace(char*); // clean white space, tabstops every 8 positions
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,773 +0,0 @@
|
||||
/* ibm1130_prt.c: IBM 1130 line printer emulation
|
||||
|
||||
Based on the SIMH simulator package written by Robert M Supnik
|
||||
|
||||
Brian Knittel
|
||||
Revision History
|
||||
2002.09.13 - Added 1403 support. New file, taken from part of ibm1130_stddev.c
|
||||
|
||||
Note: The 1403 is much faster, even in emulation, because it takes much
|
||||
less CPU power to run it. DMS doesn't use the WAIT command when waiting for
|
||||
printer operations to complete, so it ends up burning LOTS of cpu cycles.
|
||||
The 1403 printer doesn't require as many. HOWEVER: DMS must be loaded for the 1403,
|
||||
and Fortran IOCS control cards must specify it.
|
||||
|
||||
The 1132 is still the default printer.
|
||||
|
||||
As written, we can't have two printers.
|
||||
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to simh@ibm1130.org
|
||||
*/
|
||||
|
||||
#include "ibm1130_defs.h"
|
||||
|
||||
/***************************************************************************************
|
||||
* 1132 PRINTER
|
||||
***************************************************************************************/
|
||||
|
||||
#define PRT1132_DSW_READ_EMITTER_RESPONSE 0x8000
|
||||
#define PRT1132_DSW_SKIP_RESPONSE 0x4000
|
||||
#define PRT1132_DSW_SPACE_RESPONSE 0x2000
|
||||
#define PRT1132_DSW_CARRIAGE_BUSY 0x1000
|
||||
#define PRT1132_DSW_PRINT_SCAN_CHECK 0x0800
|
||||
#define PRT1132_DSW_NOT_READY 0x0400
|
||||
#define PRT1132_DSW_PRINTER_BUSY 0x0200
|
||||
|
||||
#define PRT1132_DSW_CHANNEL_MASK 0x00FF /* 1132 printer DSW bits */
|
||||
#define PRT1132_DSW_CHANNEL_1 0x0080
|
||||
#define PRT1132_DSW_CHANNEL_2 0x0040
|
||||
#define PRT1132_DSW_CHANNEL_3 0x0020
|
||||
#define PRT1132_DSW_CHANNEL_4 0x0010
|
||||
#define PRT1132_DSW_CHANNEL_5 0x0008
|
||||
#define PRT1132_DSW_CHANNEL_6 0x0004
|
||||
#define PRT1132_DSW_CHANNEL_9 0x0002
|
||||
#define PRT1132_DSW_CHANNEL_12 0x0001
|
||||
|
||||
#define PRT1403_DSW_PARITY_CHECK 0x8000 /* 1403 printer DSW bits */
|
||||
#define PRT1403_DSW_TRANSFER_COMPLETE 0x4000
|
||||
#define PRT1403_DSW_PRINT_COMPLETE 0x2000
|
||||
#define PRT1403_DSW_CARRIAGE_COMPLETE 0x1000
|
||||
#define PRT1403_DSW_RING_CHECK 0x0400
|
||||
#define PRT1403_DSW_SYNC_CHECK 0x0200
|
||||
#define PRT1403_DSW_CH9 0x0010
|
||||
#define PRT1403_DSW_CH12 0x0008
|
||||
#define PRT1403_DSW_CARRIAGE_BUSY 0x0004
|
||||
#define PRT1403_DSW_PRINTER_BUSY 0x0002
|
||||
#define PRT1403_DSW_NOT_READY 0x0001
|
||||
|
||||
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
|
||||
|
||||
static t_stat prt1132_svc(UNIT *uptr);
|
||||
static t_stat prt1403_svc(UNIT *uptr);
|
||||
static t_stat prt_svc (UNIT *uptr);
|
||||
static t_stat prt_reset (DEVICE *dptr);
|
||||
static t_stat prt_attach (UNIT *uptr, char *cptr);
|
||||
static t_stat prt_detach (UNIT *uptr);
|
||||
|
||||
static int16 PRT_DSW = 0; /* device status word */
|
||||
static int32 prt_swait = 500; /* line skip wait */
|
||||
static int32 prt_cwait = 1250; /* character rotation wait */
|
||||
static int32 prt_fwait = 100; /* fast wait, for 1403 operations */
|
||||
static int32 prt_twait = 50; /* transfer wait, for 1403 operations */
|
||||
#define SKIPTARGET (uptr->u4) /* target for skip operation */
|
||||
|
||||
#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */
|
||||
#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */
|
||||
#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */
|
||||
#define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */
|
||||
#define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */
|
||||
#define UNIT_V_TRANSFERRING (UNIT_V_UF + 5) /* unit is transferring print buffer (1403 only) */
|
||||
#define UNIT_V_1403 (UNIT_V_UF + 6) /* printer model is 1403 rather than 1132 */
|
||||
#define UNIT_V_PARITYCHECK (UNIT_V_UF + 7) /* error flags for 1403 */
|
||||
#define UNIT_V_RINGCHECK (UNIT_V_UF + 8)
|
||||
#define UNIT_V_SYNCCHECK (UNIT_V_UF + 9)
|
||||
|
||||
#define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK)
|
||||
#define UNIT_DATACHECK (1u << UNIT_V_DATACHECK)
|
||||
#define UNIT_SKIPPING (1u << UNIT_V_SKIPPING)
|
||||
#define UNIT_SPACING (1u << UNIT_V_SPACING)
|
||||
#define UNIT_PRINTING (1u << UNIT_V_PRINTING)
|
||||
#define UNIT_TRANSFERRING (1u << UNIT_V_TRANSFERRING)
|
||||
#define UNIT_1403 (1u << UNIT_V_1403)
|
||||
#define UNIT_PARITYCHECK (1u << UNIT_V_PARITYCHECK)
|
||||
#define UNIT_RINGCHECK (1u << UNIT_V_RINGCHECK)
|
||||
#define UNIT_SYNCCHECK (1u << UNIT_V_SYNCCHECK)
|
||||
|
||||
UNIT prt_unit[] = {
|
||||
{ UDATA (&prt_svc, UNIT_ATTABLE, 0) },
|
||||
};
|
||||
|
||||
#define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */
|
||||
#define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */
|
||||
|
||||
/* Parameter in the unit descriptor (1132 printer) */
|
||||
|
||||
#define CMD_NONE 0
|
||||
#define CMD_SPACE 1
|
||||
#define CMD_SKIP 2
|
||||
#define CMD_PRINT 3
|
||||
|
||||
REG prt_reg[] = {
|
||||
{ HRDATA (PRTDSW, PRT_DSW, 16) }, /* device status word */
|
||||
{ DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */
|
||||
{ DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */
|
||||
{ DRDATA (CTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */
|
||||
{ DRDATA (CTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */
|
||||
{ NULL } };
|
||||
|
||||
MTAB prt_mod[] = {
|
||||
{ UNIT_1403, 0, "1132", "1132", NULL }, /* model option */
|
||||
{ UNIT_1403, UNIT_1403, "1403", "1403", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE prt_dev = {
|
||||
"PRT", prt_unit, prt_reg, prt_mod,
|
||||
1, 16, 16, 1, 16, 16,
|
||||
NULL, NULL, &prt_reset,
|
||||
NULL, prt_attach, prt_detach};
|
||||
|
||||
#define PRT_COLUMNS 120
|
||||
#define PRT_ROWLEN 120
|
||||
#define MAX_OVPRINT 20
|
||||
|
||||
static char prtbuf[PRT_ROWLEN*MAX_OVPRINT];
|
||||
static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp;
|
||||
static int prt_nchar, prt_row; /* current printwheel position, current page row */
|
||||
static int prt_nnl; /* number of queued newlines */
|
||||
|
||||
#define CC_CHANNEL_1 0x0800 /* carriage control tape punch values */
|
||||
#define CC_CHANNEL_2 0x0400
|
||||
#define CC_CHANNEL_3 0x0200
|
||||
#define CC_CHANNEL_4 0x0100
|
||||
#define CC_CHANNEL_5 0x0080
|
||||
#define CC_CHANNEL_6 0x0040 /* 7, 8, 10 and 11 are not used on 1132 printer */
|
||||
#define CC_CHANNEL_7 0x0020
|
||||
#define CC_CHANNEL_8 0x0010
|
||||
#define CC_CHANNEL_9 0x0008
|
||||
#define CC_CHANNEL_10 0x0004
|
||||
#define CC_CHANNEL_11 0x0002
|
||||
#define CC_CHANNEL_12 0x0001
|
||||
|
||||
#define CC_1403_BITS 0x0FFF /* all bits for 1403, most for 1132 */
|
||||
#define CC_1132_BITS (CC_1403_BITS & ~(CC_CHANNEL_7|CC_CHANNEL_8|CC_CHANNEL_10|CC_CHANNEL_11))
|
||||
|
||||
#define PRT_PAGELENGTH 66
|
||||
|
||||
static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */
|
||||
|
||||
static struct tag_ccpunches { /* list of rows and punches on tape */
|
||||
int row, channels;
|
||||
}
|
||||
ccpunches[] = {
|
||||
2, CC_CHANNEL_1, // channel 1 = top of form
|
||||
62, CC_CHANNEL_12 // channel 12 = bottom of form
|
||||
},
|
||||
cccgi[] = {
|
||||
2, CC_CHANNEL_1 // channel 1 = top of form; no bottom of form
|
||||
};
|
||||
|
||||
#include "ibm1130_prtwheel.h"
|
||||
|
||||
// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read
|
||||
|
||||
static int cc_format_1132 (int bits)
|
||||
{
|
||||
return ((bits & (CC_CHANNEL_1|CC_CHANNEL_2|CC_CHANNEL_3|CC_CHANNEL_4|CC_CHANNEL_5|CC_CHANNEL_6)) >> 4) |
|
||||
((bits & CC_CHANNEL_9) >> 3) |
|
||||
(bits & CC_CHANNEL_12);
|
||||
}
|
||||
|
||||
#define cc_format_1403(bits) (bits)
|
||||
|
||||
// reset_prt_line - clear the print line following paper advancement
|
||||
|
||||
static void reset_prt_line (void)
|
||||
{
|
||||
memset(nprint, 0, sizeof(nprint));
|
||||
memset(ncol, 0, sizeof(ncol));
|
||||
maxnp = 0;
|
||||
}
|
||||
|
||||
// save_1132_prt_line - fire hammers for character 'ch'
|
||||
|
||||
static t_bool save_1132_prt_line (int ch)
|
||||
{
|
||||
int i, r, addr = 32;
|
||||
int32 mask = 0, wd = 0;
|
||||
|
||||
for (i = 0; i < PRT_COLUMNS; i++) {
|
||||
if (mask == 0) { // fetch next word from memory
|
||||
mask = 0x8000;
|
||||
wd = M[addr++];
|
||||
}
|
||||
|
||||
if (wd & mask) { // hammer is to fire in this column
|
||||
if ((r = nprint[i]) < MAX_OVPRINT) {
|
||||
if (ncol[r] <= i) { // we haven't moved this far yet
|
||||
if (ncol[r] == 0) // first char in this row?
|
||||
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
|
||||
ncol[r] = i+1; // remember new row length
|
||||
}
|
||||
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
|
||||
|
||||
nprint[i]++; // remember max overprintings for this column
|
||||
maxnp = MAX(maxnp, nprint[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mask >>= 1; // prepare to examine next bit
|
||||
}
|
||||
|
||||
return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set
|
||||
}
|
||||
|
||||
// write_line - write collected line to output file. No need to trim spaces as the hammers
|
||||
// are never fired for them, so ncol[r] is the last printed position on each line.
|
||||
|
||||
static void newpage (FILE *fd)
|
||||
{
|
||||
if (cgi)
|
||||
fputs("<HR>\n", fd);
|
||||
else
|
||||
putc('\f', fd); // formfeed
|
||||
}
|
||||
|
||||
static void flush_prt_line (FILE *fd, int spacemode)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (! (spacemode || maxnp)) // nothing to do
|
||||
return;
|
||||
|
||||
prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line
|
||||
|
||||
if (spacemode && ! maxnp) { // spacing only
|
||||
if (prt_row == 0 && prt_nnl) {
|
||||
#ifdef WIN32
|
||||
if (! cgi)
|
||||
putc('\r', fd); // DOS/Windows: end with cr/lf
|
||||
#endif
|
||||
putc('\n', fd); // otherwise end with lf
|
||||
if (spacemode & UNIT_SKIPPING) // add formfeed if we crossed page boundary while skipping
|
||||
newpage(fd);
|
||||
prt_nnl = 0;
|
||||
}
|
||||
else
|
||||
prt_nnl++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (prt_nnl) { // there are queued newlines
|
||||
// if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels
|
||||
// if (prt_row == 0 && prt_nnl) { // we spaced to top of form
|
||||
//#ifdef WIN32
|
||||
// if (! cgi)
|
||||
// putc('\r', fd); // DOS/Windows: end with cr/lf
|
||||
//#endif
|
||||
// putc('\n', fd); // otherwise end with lf
|
||||
// newpage(fd);
|
||||
// prt_nnl = 0;
|
||||
// }
|
||||
// else {
|
||||
while (prt_nnl > 0) { // spit out queued newlines
|
||||
#ifdef WIN32
|
||||
if (! cgi)
|
||||
putc('\r', fd); // DOS/Windows: end with cr/lf
|
||||
#endif
|
||||
putc('\n', fd); // otherwise end with lf
|
||||
prt_nnl--;
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
for (r = 0; r < maxnp; r++) {
|
||||
if (r > 0)
|
||||
putc('\r', fd); // carriage return between overprinted lines
|
||||
fxwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd);
|
||||
}
|
||||
|
||||
reset_prt_line();
|
||||
|
||||
prt_nnl++; // queue a newline
|
||||
}
|
||||
|
||||
// 1132 printer commands
|
||||
|
||||
#define PRT_CMD_START_PRINTER 0x0080
|
||||
#define PRT_CMD_STOP_PRINTER 0x0040
|
||||
#define PRT_CMD_START_CARRIAGE 0x0004
|
||||
#define PRT_CMD_STOP_CARRIAGE 0x0002
|
||||
#define PRT_CMD_SPACE 0x0001
|
||||
|
||||
#define PRT_CMD_MASK 0x00C7
|
||||
|
||||
extern char * saywhere (int addr);
|
||||
|
||||
static void mytrace (int start, char *what)
|
||||
{
|
||||
char *where;
|
||||
|
||||
if ((where = saywhere(prev_IAR)) == NULL) where = "?";
|
||||
trace_io("%s %s at %04x: %s\n", start ? "start" : "stop", what, prev_IAR, where);
|
||||
}
|
||||
|
||||
/* xio_1132_printer - XIO command interpreter for the 1132 printer */
|
||||
|
||||
void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)
|
||||
{
|
||||
char msg[80];
|
||||
UNIT *uptr = &prt_unit[0];
|
||||
|
||||
switch (func) {
|
||||
case XIO_READ:
|
||||
M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8;
|
||||
|
||||
if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */
|
||||
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132;
|
||||
break;
|
||||
|
||||
case XIO_SENSE_DEV:
|
||||
ACC = PRT_DSW;
|
||||
if (modify & 0x01) { /* reset interrupts */
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE | PRT1132_DSW_SKIP_RESPONSE | PRT1132_DSW_SPACE_RESPONSE);
|
||||
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
||||
}
|
||||
break;
|
||||
|
||||
case XIO_CONTROL:
|
||||
if (modify & PRT_CMD_START_PRINTER) {
|
||||
SETBIT(uptr->flags, UNIT_PRINTING);
|
||||
// mytrace(1, "printing");
|
||||
}
|
||||
|
||||
if (modify & PRT_CMD_STOP_PRINTER) {
|
||||
CLRBIT(uptr->flags, UNIT_PRINTING);
|
||||
// mytrace(0, "printing");
|
||||
}
|
||||
|
||||
if (modify & PRT_CMD_START_CARRIAGE) {
|
||||
SETBIT(uptr->flags, UNIT_SKIPPING);
|
||||
// mytrace(1, "skipping");
|
||||
}
|
||||
|
||||
if (modify & PRT_CMD_STOP_CARRIAGE) {
|
||||
CLRBIT(uptr->flags, UNIT_SKIPPING);
|
||||
// mytrace(0, "skipping");
|
||||
}
|
||||
|
||||
if (modify & PRT_CMD_SPACE) {
|
||||
SETBIT(uptr->flags, UNIT_SPACING);
|
||||
// mytrace(1, "space");
|
||||
}
|
||||
|
||||
sim_cancel(uptr);
|
||||
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { // busy bits = doing something
|
||||
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
||||
sim_activate(uptr, prt_cwait);
|
||||
}
|
||||
else
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
||||
|
||||
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING))
|
||||
SETBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);
|
||||
else
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY);
|
||||
|
||||
if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) {
|
||||
sprintf(msg, "1132 printer skip and space at same time?");
|
||||
xio_error(msg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(msg, "Invalid 1132 printer XIO function %x", func);
|
||||
xio_error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
#define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING|UNIT_TRANSFERRING); (u)->flags |= a;}
|
||||
|
||||
static t_stat prt_svc (UNIT *uptr)
|
||||
{
|
||||
return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr);
|
||||
}
|
||||
|
||||
// prt1132_svc - emulated timeout for 1132 operation
|
||||
|
||||
static t_stat prt1132_svc (UNIT *uptr)
|
||||
{
|
||||
if (PRT_DSW & PRT1132_DSW_NOT_READY) { // cancel operation if printer went offline
|
||||
SETBIT(uptr->flags, UNIT_FORMCHECK);
|
||||
SET_ACTION(uptr, 0);
|
||||
forms_check(TRUE); // and turn on forms check lamp
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (uptr->flags & UNIT_SPACING) {
|
||||
flush_prt_line(uptr->fileref, UNIT_SPACING);
|
||||
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);
|
||||
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);
|
||||
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
||||
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
|
||||
calc_ints();
|
||||
}
|
||||
|
||||
if (uptr->flags & UNIT_SKIPPING) {
|
||||
do {
|
||||
flush_prt_line(uptr->fileref, UNIT_SKIPPING);
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);
|
||||
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));
|
||||
} while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch
|
||||
|
||||
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE);
|
||||
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
||||
calc_ints();
|
||||
}
|
||||
|
||||
if (uptr->flags & UNIT_PRINTING) {
|
||||
if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line
|
||||
SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time
|
||||
SET_ACTION(uptr, 0);
|
||||
print_check(TRUE); // and turn on forms check lamp
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; // advance print drum
|
||||
|
||||
SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer
|
||||
SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130)
|
||||
calc_ints();
|
||||
}
|
||||
|
||||
if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something
|
||||
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
||||
sim_activate(uptr, prt_cwait);
|
||||
}
|
||||
else
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void save_1403_prt_line (int32 addr)
|
||||
{
|
||||
int i, j, r, ch, even = TRUE;
|
||||
unsigned char ebcdic;
|
||||
int32 wd;
|
||||
|
||||
for (i = 0; i < PRT_COLUMNS; i++) {
|
||||
if (even) { // fetch next word from memory
|
||||
wd = M[addr++];
|
||||
ebcdic = (unsigned char) ((wd >> 8) & 0x7F);
|
||||
even = FALSE;
|
||||
}
|
||||
else {
|
||||
ebcdic = (unsigned char) (wd & 0x7F); // use low byte of previously fetched word
|
||||
even = TRUE;
|
||||
}
|
||||
|
||||
ch = ' '; // translate ebcdic to ascii. Don't bother checking for parity errors
|
||||
for (j = 0; j < WHEELCHARS_1403; j++) {
|
||||
if (codewheel1403[j].ebcdic == ebcdic) {
|
||||
ch = codewheel1403[j].ascii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch > ' ') {
|
||||
if ((r = nprint[i]) < MAX_OVPRINT) {
|
||||
if (ncol[r] <= i) { // we haven't moved this far yet
|
||||
if (ncol[r] == 0) // first char in this row?
|
||||
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
|
||||
ncol[r] = i+1; // remember new row length
|
||||
}
|
||||
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
|
||||
|
||||
nprint[i]++; // remember max overprintings for this column
|
||||
maxnp = MAX(maxnp, nprint[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify)
|
||||
{
|
||||
UNIT *uptr = &prt_unit[0];
|
||||
|
||||
switch (func) {
|
||||
case XIO_INITW: /* print a line */
|
||||
save_1403_prt_line(iocc_addr); /* put formatted line into our print buffer */
|
||||
|
||||
SETBIT(uptr->flags, UNIT_TRANSFERRING); /* schedule transfer complete interrupt */
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);
|
||||
sim_activate(uptr, prt_twait);
|
||||
break;
|
||||
|
||||
case XIO_CONTROL: /* initiate single space */
|
||||
if (uptr->flags & UNIT_SKIPPING) {
|
||||
xio_error("1403 printer skip and space at same time?");
|
||||
}
|
||||
else {
|
||||
SETBIT(uptr->flags, UNIT_SPACING);
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
||||
sim_activate(uptr, prt_fwait);
|
||||
}
|
||||
break;
|
||||
|
||||
case XIO_WRITE: /* initiate skip */
|
||||
if (uptr->flags & UNIT_SPACING) {
|
||||
xio_error("1403 printer skip and space at same time?");
|
||||
}
|
||||
else {
|
||||
SETBIT(uptr->flags, UNIT_SKIPPING);
|
||||
SKIPTARGET = ReadW(iocc_addr) & CC_1403_BITS; /* get CC bits that we're to match */
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
||||
sim_activate(uptr, prt_fwait);
|
||||
}
|
||||
break;
|
||||
|
||||
case XIO_SENSE_DEV: /* get device status word */
|
||||
ACC = PRT_DSW;
|
||||
if (modify & 0x01) { /* reset interrupts */
|
||||
CLRBIT(PRT_DSW, PRT1403_DSW_PARITY_CHECK | PRT1403_DSW_TRANSFER_COMPLETE |
|
||||
PRT1403_DSW_PRINT_COMPLETE | PRT1403_DSW_CARRIAGE_COMPLETE |
|
||||
PRT1403_DSW_RING_CHECK | PRT1403_DSW_SYNC_CHECK);
|
||||
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static t_stat prt1403_svc(UNIT *uptr)
|
||||
{
|
||||
if (PRT_DSW & PRT1403_DSW_NOT_READY) { // cancel operation if printer went offline
|
||||
SET_ACTION(uptr, 0);
|
||||
forms_check(TRUE); // and turn on forms check lamp
|
||||
}
|
||||
else if (uptr->flags & UNIT_TRANSFERRING) { // end of transfer
|
||||
CLRBIT(uptr->flags, UNIT_TRANSFERRING);
|
||||
SETBIT(uptr->flags, UNIT_PRINTING); // schedule "print complete"
|
||||
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); // issue transfer complete interrupt
|
||||
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
}
|
||||
else if (uptr->flags & UNIT_PRINTING) {
|
||||
CLRBIT(uptr->flags, UNIT_PRINTING);
|
||||
CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);
|
||||
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE);
|
||||
SETBIT(ILSW[4], ILSW_4_1403_PRINTER); // issue print complete interrupt
|
||||
}
|
||||
else if (uptr->flags & UNIT_SKIPPING) {
|
||||
do { // find line with exact match of tape punches
|
||||
flush_prt_line(uptr->fileref, UNIT_SKIPPING);
|
||||
} while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch
|
||||
|
||||
CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this
|
||||
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
||||
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
|
||||
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
}
|
||||
else if (uptr->flags & UNIT_SPACING) {
|
||||
flush_prt_line(uptr->fileref, UNIT_SPACING);
|
||||
|
||||
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
|
||||
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
|
||||
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
|
||||
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
}
|
||||
|
||||
if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING))
|
||||
sim_activate(uptr, prt_fwait);
|
||||
|
||||
CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); // set the two CC bits in the DSW
|
||||
if (cctape[prt_row] & CC_CHANNEL_9)
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
|
||||
if (cctape[prt_row] & CC_CHANNEL_12)
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
|
||||
|
||||
calc_ints();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* delete_cmd - SCP command to delete a file */
|
||||
|
||||
static t_stat delete_cmd (int flag, char *cptr)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
int status;
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
|
||||
if (*gbuf == 0) return SCPE_2FARG;
|
||||
if (*cptr != 0) return SCPE_2MARG; /* now eol? */
|
||||
|
||||
status = unlink(gbuf); /* delete the file */
|
||||
|
||||
if (status != 0 && errno != ENOENT) /* print message if failed and file exists */
|
||||
perror(gbuf);
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* prt_reset - reset emulated printer */
|
||||
|
||||
static t_stat prt_reset (DEVICE *dptr)
|
||||
{
|
||||
UNIT *uptr = &prt_unit[0];
|
||||
int i;
|
||||
|
||||
// add a DELETE filename command so we can be sure to have clean listings
|
||||
register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n");
|
||||
|
||||
sim_cancel(uptr);
|
||||
|
||||
memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image
|
||||
|
||||
if (cgi)
|
||||
for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++)
|
||||
cctape[cccgi[i].row-1] |= cccgi[i].channels;
|
||||
else
|
||||
for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)
|
||||
cctape[ccpunches[i].row-1] |= ccpunches[i].channels;
|
||||
|
||||
prt_nchar = 0;
|
||||
prt_row = 0;
|
||||
prt_nnl = 0;
|
||||
|
||||
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK|UNIT_PRINTING|UNIT_SPACING|UNIT_SKIPPING|
|
||||
UNIT_TRANSFERRING|UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);
|
||||
|
||||
if (IS_1132(uptr)) {
|
||||
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
||||
PRT_DSW = cc_format_1132(cctape[prt_row]);
|
||||
if (! IS_ONLINE(uptr))
|
||||
SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
||||
}
|
||||
else {
|
||||
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
PRT_DSW = 0;
|
||||
if (cctape[prt_row] & CC_CHANNEL_9)
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
|
||||
if (cctape[prt_row] & CC_CHANNEL_12)
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
|
||||
if (! IS_ONLINE(uptr))
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);
|
||||
}
|
||||
|
||||
SET_ACTION(uptr, 0);
|
||||
calc_ints();
|
||||
reset_prt_line();
|
||||
|
||||
forms_check(FALSE);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat prt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat rval;
|
||||
/* assume failure */
|
||||
SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY);
|
||||
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
if ((rval = prt_detach(uptr)) != SCPE_OK) {
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
|
||||
sim_cancel(uptr);
|
||||
|
||||
if (strcmp(cptr, "-") == 0) { /* connect printer to stdout */
|
||||
if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */
|
||||
uptr->filename = calloc(CBUFSIZE, sizeof(char));
|
||||
strcpy(uptr->filename, "(stdout)");
|
||||
uptr->fileref = stdout;
|
||||
SETBIT(uptr->flags, UNIT_ATT);
|
||||
uptr->pos = 0;
|
||||
}
|
||||
else if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) {
|
||||
return rval;
|
||||
}
|
||||
|
||||
fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */
|
||||
|
||||
if (IS_1132(uptr)) {
|
||||
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
||||
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
||||
}
|
||||
else {
|
||||
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
CLRBIT(uptr->flags, UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK);
|
||||
}
|
||||
|
||||
SET_ACTION(uptr, 0);
|
||||
calc_ints();
|
||||
|
||||
prt_nchar = 0;
|
||||
prt_nnl = 0;
|
||||
prt_row = 0;
|
||||
reset_prt_line();
|
||||
|
||||
if (IS_1132(uptr)) {
|
||||
PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]);
|
||||
|
||||
if (IS_ONLINE(uptr))
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
||||
}
|
||||
else {
|
||||
CLRBIT(PRT_DSW, PRT1403_DSW_CH9 | PRT1403_DSW_CH12);
|
||||
if (cctape[prt_row] & CC_CHANNEL_9)
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
|
||||
if (cctape[prt_row] & CC_CHANNEL_12)
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
|
||||
|
||||
if (IS_ONLINE(uptr))
|
||||
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
||||
}
|
||||
|
||||
forms_check(FALSE);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat prt_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat rval;
|
||||
|
||||
flush_prt_line(uptr->fileref, TRUE);
|
||||
|
||||
if (uptr->fileref == stdout) {
|
||||
CLRBIT(uptr->flags, UNIT_ATT);
|
||||
free(uptr->filename);
|
||||
uptr->filename = NULL;
|
||||
}
|
||||
else if ((rval = detach_unit(uptr)) != SCPE_OK)
|
||||
return rval;
|
||||
|
||||
sim_cancel(uptr);
|
||||
|
||||
if (IS_1132(uptr)) {
|
||||
CLRBIT(ILSW[1], ILSW_1_1132_PRINTER);
|
||||
CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK);
|
||||
SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
|
||||
}
|
||||
else {
|
||||
CLRBIT(ILSW[4], ILSW_4_1403_PRINTER);
|
||||
SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY);
|
||||
}
|
||||
SET_ACTION(uptr, 0);
|
||||
|
||||
calc_ints();
|
||||
|
||||
forms_check(FALSE);
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
struct tag_codewheel {
|
||||
unsigned char ascii;
|
||||
unsigned char ebcdic;
|
||||
};
|
||||
|
||||
static struct tag_codewheel codewheel1132[] =
|
||||
{ /* characters and EBCDIC codes in printwheel order */
|
||||
'A', 0xC1,
|
||||
'B', 0xC2,
|
||||
'C', 0xC3,
|
||||
'D', 0xC4,
|
||||
'F', 0xC6,
|
||||
'H', 0xC8,
|
||||
'I', 0xC9,
|
||||
'S', 0xE2,
|
||||
'T', 0xE3,
|
||||
'U', 0xE4,
|
||||
'V', 0xE5,
|
||||
'1', 0xF1,
|
||||
'2', 0xF2,
|
||||
'3', 0xF3,
|
||||
'4', 0xF4,
|
||||
'5', 0xF5,
|
||||
'6', 0xF6,
|
||||
'7', 0xF7,
|
||||
'8', 0xF8,
|
||||
'9', 0xF9,
|
||||
'0', 0xF0,
|
||||
'=', 0x7E,
|
||||
'$', 0x5B,
|
||||
'.', 0x4B,
|
||||
'\'', 0x7D,
|
||||
',', 0x6B,
|
||||
')', 0x5D,
|
||||
'-', 0x60,
|
||||
'(', 0x4D,
|
||||
'+', 0x4E,
|
||||
'/', 0x61,
|
||||
'*', 0x5C,
|
||||
'&', 0x50,
|
||||
'J', 0xD1,
|
||||
'K', 0xD2,
|
||||
'L', 0xD3,
|
||||
'M', 0xD4,
|
||||
'N', 0xD5,
|
||||
'O', 0xD6,
|
||||
'P', 0xD7,
|
||||
'Q', 0xD8,
|
||||
'R', 0xD9,
|
||||
'E', 0xC5,
|
||||
'G', 0xC7,
|
||||
'W', 0xE6,
|
||||
'X', 0xE7,
|
||||
'Y', 0xE8,
|
||||
'Z', 0xE9,
|
||||
};
|
||||
|
||||
#define WHEELCHARS_1132 (sizeof(codewheel1132)/sizeof(codewheel1132[0]))
|
||||
|
||||
static struct tag_codewheel codewheel1403[] =
|
||||
{
|
||||
'A', 0x64,
|
||||
'B', 0x25,
|
||||
'C', 0x26,
|
||||
'D', 0x67,
|
||||
'E', 0x68,
|
||||
'F', 0x29,
|
||||
'G', 0x2A,
|
||||
'H', 0x6B,
|
||||
'I', 0x2C,
|
||||
'J', 0x58,
|
||||
'K', 0x19,
|
||||
'L', 0x1A,
|
||||
'M', 0x5B,
|
||||
'N', 0x1C,
|
||||
'O', 0x5D,
|
||||
'P', 0x5E,
|
||||
'Q', 0x1F,
|
||||
'R', 0x20,
|
||||
'S', 0x0D,
|
||||
'T', 0x0E,
|
||||
'U', 0x4F,
|
||||
'V', 0x10,
|
||||
'W', 0x51,
|
||||
'X', 0x52,
|
||||
'Y', 0x13,
|
||||
'Z', 0x54,
|
||||
'0', 0x49,
|
||||
'1', 0x40,
|
||||
'2', 0x01,
|
||||
'3', 0x02,
|
||||
'4', 0x43,
|
||||
'5', 0x04,
|
||||
'6', 0x45,
|
||||
'7', 0x46,
|
||||
'8', 0x07,
|
||||
'9', 0x08,
|
||||
' ', 0x7F,
|
||||
'.', 0x6E,
|
||||
'(', 0x57,
|
||||
'+', 0x6D,
|
||||
'&', 0x15,
|
||||
'$', 0x62,
|
||||
'*', 0x23,
|
||||
')', 0x2F,
|
||||
'-', 0x61,
|
||||
'/', 0x4C,
|
||||
',', 0x16,
|
||||
'\'', 0x0B,
|
||||
'=', 0x4A,
|
||||
};
|
||||
|
||||
#define WHEELCHARS_1403 (sizeof(codewheel1403)/sizeof(codewheel1403[0]))
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,495 +0,0 @@
|
||||
/* ibm1130_sys.c: IBM 1130 simulator interface
|
||||
|
||||
Based on PDP-11 simulator written by Robert M Supnik
|
||||
|
||||
Revision History
|
||||
0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator
|
||||
0.25 2002Apr18 - Fixed some card reader problems. It starts the reader
|
||||
properly if you attach a deck while it's waiting to a read.
|
||||
0.24 2002Mar27 - Fixed BOSC bug; BOSC works in short instructions too
|
||||
0.23 2002Feb26 - Added @decklist feature for ATTACH CR.
|
||||
0.22 2002Feb26 - Replaced "strupr" with "upcase" for compatibility.
|
||||
0.21 2002Feb25 - Some compiler compatibiity changes, couple of compiler-detected
|
||||
bugs
|
||||
0.01 2001Jul31 - Derived from pdp11_sys.c, which carries this disclaimer:
|
||||
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to simh@ibm1130.org
|
||||
*/
|
||||
|
||||
#include "ibm1130_defs.h"
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev;
|
||||
extern DEVICE tti_dev, tto_dev, prt_dev, log_dev;
|
||||
extern DEVICE gdu_dev, console_dev;
|
||||
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern int32 saved_PC;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax number of words 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[] = "IBM 1130";
|
||||
char sim_version[] = "V0.30";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 4;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev, /* the cpu */
|
||||
&dsk_dev, /* disk drive(s) */
|
||||
&cr_dev, /* card reader/punch */
|
||||
&cp_dev,
|
||||
&tti_dev, /* console keyboard, selectric printer */
|
||||
&tto_dev,
|
||||
&prt_dev, /* 1132 printer */
|
||||
&console_dev, /* console display (windows GUI) */
|
||||
&gdu_dev, /* 2250 display */
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Wait",
|
||||
"Invalid command",
|
||||
"Simulator breakpoint",
|
||||
"Use of incomplete simulator function",
|
||||
"Power off",
|
||||
"!BREAK in card deck file",
|
||||
"Phase load break",
|
||||
"Program has run amok",
|
||||
"Run time limit exceeded"
|
||||
};
|
||||
|
||||
/* Loader. IPL is normally performed by card reader (boot command). This function
|
||||
* loads hex data from a file for testing purposes. The format is:
|
||||
*
|
||||
* blank lines or lines starting with ; / or # are ignored as comments
|
||||
*
|
||||
* @XXXX set load addresss to hex value XXXX
|
||||
* XXXX store hex word value XXXX at current load address and increment address
|
||||
* ...
|
||||
* =XXXX set IAR to hex value XXXX
|
||||
* ZXXXX zero XXXX words and increment load address
|
||||
* SXXXX set console entry switches to XXXX. This lets a program specify the
|
||||
* default value for the toggle switches.
|
||||
*
|
||||
* Multiple @ and data sections may be entered. If more than one = or S value is specified
|
||||
* the last one wins.
|
||||
*
|
||||
* Note: the load address @XXXX and data values XXXX can be followed by the letter
|
||||
* R to indicate that the values are relocatable addresses. This is ignored in this loader,
|
||||
* but the asm1130 cross assembler may put them there.
|
||||
*/
|
||||
|
||||
t_stat my_load (FILE *fileref, char *cptr, char *fnam)
|
||||
{
|
||||
char line[150], *c;
|
||||
int iaddr = -1, runaddr = -1, val, nwords;
|
||||
|
||||
while (fgets(line, sizeof(line), fileref) != NULL) {
|
||||
for (c = line; *c && *c <= ' '; c++) // find first nonblank
|
||||
;
|
||||
|
||||
if (*c == '\0' || *c == '#' || *c == '/' || *c == ';')
|
||||
continue; // empty line or comment
|
||||
|
||||
if (*c == '@') { // set load address
|
||||
if (sscanf(c+1, "%x", &iaddr) != 1)
|
||||
return SCPE_FMT;
|
||||
}
|
||||
else if (*c == '=') {
|
||||
if (sscanf(c+1, "%x", &runaddr) != 1)
|
||||
return SCPE_FMT;
|
||||
}
|
||||
else if (*c == 's' || *c == 'S') {
|
||||
if (sscanf(c+1, "%x", &val) != 1)
|
||||
return SCPE_FMT;
|
||||
|
||||
CES = val & 0xFFFF; // preload console entry switches
|
||||
}
|
||||
else if (*c == 'z' || *c == 'Z') {
|
||||
if (sscanf(c+1, "%x", &nwords) != 1)
|
||||
return SCPE_FMT;
|
||||
|
||||
if (iaddr == -1)
|
||||
return SCPE_FMT;
|
||||
|
||||
while (--nwords >= 0) {
|
||||
WriteW(iaddr, 0);
|
||||
iaddr++;
|
||||
}
|
||||
}
|
||||
else if (strchr("0123456789abcdefABCDEF", *c) != NULL) {
|
||||
if (sscanf(c, "%x", &val) != 1)
|
||||
return SCPE_FMT;
|
||||
|
||||
if (iaddr == -1)
|
||||
return SCPE_FMT;
|
||||
|
||||
WriteW(iaddr, val); // store data
|
||||
iaddr++;
|
||||
}
|
||||
else
|
||||
return SCPE_FMT; // unexpected data
|
||||
}
|
||||
|
||||
if (runaddr != -1)
|
||||
IAR = runaddr;
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat my_save (FILE *fileref, char *cptr, char *fnam)
|
||||
{
|
||||
int iaddr, nzeroes = 0, nwords = (int) (MEMSIZE/2), val;
|
||||
|
||||
fprintf(fileref, "=%04x\r\n", IAR);
|
||||
fprintf(fileref, "@0000\r\n");
|
||||
for (iaddr = 0; iaddr < nwords; iaddr++) {
|
||||
val = ReadW(iaddr);
|
||||
if (val == 0) // queue up zeroes
|
||||
nzeroes++;
|
||||
else {
|
||||
if (nzeroes >= 4) { // spit out a Z directive
|
||||
fprintf(fileref, "Z%04x\r\n", nzeroes);
|
||||
nzeroes = 0;
|
||||
}
|
||||
else { // write queued zeroes literally
|
||||
while (nzeroes > 0) {
|
||||
fprintf(fileref, " 0000\r\n");
|
||||
nzeroes--;
|
||||
}
|
||||
}
|
||||
fprintf(fileref, " %04x\r\n", val);
|
||||
}
|
||||
}
|
||||
if (nzeroes >= 4) { // emit any queued zeroes
|
||||
fprintf(fileref, "Z%04x\r\n", nzeroes);
|
||||
nzeroes = 0;
|
||||
}
|
||||
else {
|
||||
while (nzeroes > 0) {
|
||||
fprintf(fileref, " 0000\r\n");
|
||||
nzeroes--;
|
||||
}
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
if (flag)
|
||||
return my_save(fileref, cptr, fnam);
|
||||
else
|
||||
return my_load(fileref, cptr, fnam);
|
||||
}
|
||||
|
||||
/* Specifier decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
spec = specifier
|
||||
nval = next word
|
||||
flag = TRUE if decoding for CPU
|
||||
iflag = TRUE if decoding integer instruction
|
||||
Outputs:
|
||||
count = -number of extra words retired
|
||||
*/
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = values to decode
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = if >= 0, error code
|
||||
if < 0, number of extra words retired
|
||||
*/
|
||||
|
||||
static char *opcode[] = {
|
||||
"?00 ", "XIO ", "SLA ", "SRA ",
|
||||
"LDS ", "STS ", "WAIT", "?07 ",
|
||||
"BSI ", "BSC ", "?0A ", "?0B ",
|
||||
"LDX ", "STX ", "MDX ", "?0F ",
|
||||
"A ", "AD ", "S ", "SD ",
|
||||
"M ", "D ", "?16 ", "?17 ",
|
||||
"LD ", "LDD ", "STO ", "STD ",
|
||||
"AND ", "OR ", "EOR ", "?1F ",
|
||||
};
|
||||
|
||||
static char relative[] = { // true if short mode displacements are IAR relative
|
||||
FALSE, TRUE, FALSE, FALSE,
|
||||
FALSE, TRUE, FALSE, FALSE,
|
||||
TRUE, FALSE, FALSE, FALSE,
|
||||
TRUE, TRUE, TRUE, FALSE,
|
||||
TRUE, TRUE, TRUE, TRUE,
|
||||
TRUE, TRUE, FALSE, FALSE,
|
||||
TRUE, TRUE, TRUE, TRUE,
|
||||
TRUE, TRUE, TRUE, FALSE
|
||||
};
|
||||
|
||||
static char *lsopcode[] = {"SLA ", "SLCA ", "SLT ", "SLC "};
|
||||
static char *rsopcode[] = {"SRA ", "?188 ", "SRT ", "RTE "};
|
||||
static char tagc[] = " 123";
|
||||
|
||||
static int ascii_to_ebcdic_table[128] =
|
||||
{
|
||||
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
|
||||
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
|
||||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
|
||||
|
||||
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
|
||||
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,
|
||||
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
|
||||
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
|
||||
};
|
||||
|
||||
static int ebcdic_to_ascii (int ch)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 32; j < 128; j++)
|
||||
if (ascii_to_ebcdic_table[j] == ch)
|
||||
return j;
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 cflag, ch, OP, F, TAG, INDIR, DSPLC, IR, eaddr;
|
||||
char *mnem, tst[12];
|
||||
|
||||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||||
|
||||
// if (sw & SWMASK ('A')) { /* ASCII? not useful */
|
||||
// fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
|
||||
// return SCPE_OK;
|
||||
// }
|
||||
|
||||
if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */
|
||||
sw |= SWMASK('E');
|
||||
|
||||
if (sw & SWMASK ('E')) { /* EBCDIC! */
|
||||
ch = ebcdic_to_ascii((val[0] >> 8) & 0xFF); /* take high byte first */
|
||||
fprintf (of, (ch < ' ')? "<%03o>": "%c", ch);
|
||||
ch = ebcdic_to_ascii(val[0] & 0xFF);
|
||||
fprintf (of, (ch < ' ')? "<%03o>": "%c", ch);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (sw & SWMASK ('H')) { /* HOLLERITH! now THIS is useful! */
|
||||
ch = hollerith_to_ascii((int16) val[0]);
|
||||
fprintf (of, (ch < ' ')? "<%03o>": "%c", ch);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
if (! (sw & SWMASK ('M')))
|
||||
return SCPE_ARG;
|
||||
|
||||
IR = val[0];
|
||||
OP = (IR >> 11) & 0x1F; /* opcode */
|
||||
F = IR & 0x0400; /* format bit: 1 = long instr */
|
||||
TAG = IR & 0x0300; /* tag bits: index reg select */
|
||||
if (TAG)
|
||||
TAG >>= 8;
|
||||
|
||||
if (F) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */
|
||||
INDIR = IR & 0x0080; /* indirect bit */
|
||||
DSPLC = IR & 0x007F; /* displacement or modifier */
|
||||
if (DSPLC & 0x0040)
|
||||
DSPLC |= ~ 0x7F; /* sign extend */
|
||||
|
||||
eaddr = val[1]; /* get reference address */
|
||||
}
|
||||
else { /* short instruction, use displacement */
|
||||
INDIR = 0; /* never indirect */
|
||||
DSPLC = IR & 0x00FF; /* get displacement */
|
||||
if (DSPLC & 0x0080)
|
||||
DSPLC |= ~ 0xFF;
|
||||
|
||||
eaddr = DSPLC;
|
||||
if (relative[OP] && ! TAG)
|
||||
eaddr += addr+1; /* turn displacement into address */
|
||||
}
|
||||
|
||||
mnem = opcode[OP]; /* get mnemonic */
|
||||
if (OP == 0x02) { /* left shifts are special */
|
||||
mnem = lsopcode[(DSPLC >> 6) & 0x0003];
|
||||
DSPLC &= 0x003F;
|
||||
eaddr = DSPLC;
|
||||
}
|
||||
else if (OP == 0x03) { /* right shifts too */
|
||||
mnem = rsopcode[(DSPLC >> 6) & 0x0003];
|
||||
DSPLC &= 0x003F;
|
||||
eaddr = DSPLC;
|
||||
}
|
||||
else if ((OP == 0x08 && F)|| OP == 0x09) { // BSI L and BSC any
|
||||
if (OP == 0x09 && (IR & 0x40))
|
||||
mnem = "BOSC";
|
||||
|
||||
tst[0] = '\0';
|
||||
if (DSPLC & 0x20) strcat(tst, "Z");
|
||||
if (DSPLC & 0x10) strcat(tst, "-");
|
||||
if (DSPLC & 0x08) strcat(tst, "+");
|
||||
if (DSPLC & 0x04) strcat(tst, "E");
|
||||
if (DSPLC & 0x02) strcat(tst, "C");
|
||||
if (DSPLC & 0x01) strcat(tst, "O");
|
||||
|
||||
if (F) {
|
||||
fprintf(of, "%04x %s %c%c %s,%04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst, eaddr & 0xFFFF);
|
||||
return -1;
|
||||
}
|
||||
fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst);
|
||||
return SCPE_OK;
|
||||
}
|
||||
else if (OP == 0x0e && TAG == 0) { // MDX with no tag => MDM or jump
|
||||
if (F) {
|
||||
fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC);
|
||||
return -1;
|
||||
}
|
||||
mnem = "JMP ";
|
||||
}
|
||||
|
||||
fprintf(of, "%04x %s %c%c %04x ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], eaddr & 0xFFFF);
|
||||
return F ? -1 : SCPE_OK; /* inform how many words we read */
|
||||
}
|
||||
|
||||
int32 get_reg (char *cptr, const char *strings[], char mchar)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Number or memory address
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
*dptr = pointer to output displacement
|
||||
*pflag = pointer to accumulating flags
|
||||
Outputs:
|
||||
cptr = pointer to next character in input string
|
||||
NULL if parsing error
|
||||
|
||||
Flags: 0 (no result), A_NUM (number), A_REL (relative)
|
||||
*/
|
||||
|
||||
char *get_addr (char *cptr, int32 *dptr, int32 *pflag)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Specifier decode
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
n1 = 0 if no extra word used
|
||||
-1 if extra word used in prior decode
|
||||
*sptr = pointer to output specifier
|
||||
*dptr = pointer to output displacement
|
||||
cflag = true if parsing for the CPU
|
||||
iflag = true if integer specifier
|
||||
Outputs:
|
||||
status = = -1 extra word decoded
|
||||
= 0 ok
|
||||
= +1 error
|
||||
*/
|
||||
|
||||
t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr,
|
||||
int32 cflag, int32 iflag)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = > 0 error code
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
int strnicmp (char *a, char *b, int n)
|
||||
{
|
||||
int ca, cb;
|
||||
|
||||
for (;;) {
|
||||
if (--n < 0) // still equal after n characters? quit now
|
||||
return 0;
|
||||
|
||||
if ((ca = *a) == 0) // get character, stop on null terminator
|
||||
return *b ? -1 : 0;
|
||||
|
||||
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
|
||||
ca -= 32;
|
||||
|
||||
cb = *b;
|
||||
if (cb >= 'a' && cb <= 'z')
|
||||
cb -= 32;
|
||||
|
||||
if ((ca -= cb) != 0) // if different, return comparison
|
||||
return ca;
|
||||
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
||||
int strcmpi (char *a, char *b)
|
||||
{
|
||||
int ca, cb;
|
||||
|
||||
for (;;) {
|
||||
if ((ca = *a) == 0) // get character, stop on null terminator
|
||||
return *b ? -1 : 0;
|
||||
|
||||
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
|
||||
ca -= 32;
|
||||
|
||||
cb = *b;
|
||||
if (cb >= 'a' && cb <= 'z')
|
||||
cb -= 32;
|
||||
|
||||
if ((ca -= cb) != 0) // if different, return comparison
|
||||
return ca;
|
||||
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ibm1130.rc
|
||||
//
|
||||
|
||||
#define IDB_CONSOLE 101
|
||||
#define IDC_HAND 102
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
# (This makefile is for operating systems other than Windows,
|
||||
# or compilers other than Microsoft's. For MS builds, use the
|
||||
# .mak files found in this directory and the utils directory).
|
||||
#
|
||||
# If you are building the emulator and utilities as part of
|
||||
# the SIMH package, please:
|
||||
#
|
||||
# Be sure that you there are NO copies of scp.c, scp_tty.c,
|
||||
# sim_sock.c, sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and
|
||||
# sim_tmxr.h in the ibm1130 subdirectory. Delete them if there
|
||||
# are.
|
||||
#
|
||||
# Do not use this makefile with "make all" or "make ibm1130".
|
||||
# Use the SIMH build files instead.
|
||||
#
|
||||
# If and when you download updates for this simulator from
|
||||
# www.ibm1130.org, get ibm1130code.zip and ibm1130software.zip
|
||||
# separately.
|
||||
#
|
||||
# If you have downloaded the emulator independently of SIMH (e.g, from
|
||||
# www.ibm1130.org), please:
|
||||
#
|
||||
# Be sure that you DO have copies of scp.c, scp_tty.c, sim_sock.c,
|
||||
# sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and sim_tmxr.h
|
||||
# in this folder.
|
||||
#
|
||||
# Use this file to make the emulator.
|
||||
#
|
||||
# If and when you download updates for this simulator from
|
||||
# www.ibm1130.org, get ibm1130.zip. When you expand it,
|
||||
# also expand ibm1130sofware.zip, which is inside.
|
||||
#
|
||||
# In either case, if you want to build DMS or work with assembly
|
||||
# language programs outside of DMS, you'll want to make the utilities
|
||||
# by cd'ing to the utils directory and running make there.
|
||||
|
||||
# CC Command
|
||||
#
|
||||
# Note: -O2 is sometimes broken in GCC when setjump/longjump is being
|
||||
# used. Try -O2 only with released simulators.
|
||||
#
|
||||
CC = gcc -O0 -lm -I .
|
||||
#CC = gcc -O2 -g -lm -I .
|
||||
|
||||
|
||||
#
|
||||
# Common Libraries
|
||||
#
|
||||
BIN =
|
||||
SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c
|
||||
SIM_INC = sim_defs.h sim_rev.h sim_sock.h sim_tmxr.h
|
||||
|
||||
#
|
||||
# Emulator source files and compile time options
|
||||
#
|
||||
|
||||
ibm1130D = ./
|
||||
ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \
|
||||
${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \
|
||||
${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \
|
||||
${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c \
|
||||
${ibm1130D}ibm1130_fmt.c
|
||||
|
||||
ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \
|
||||
ibm1130_defs.h ibm1130_prtwheel.h ibm1130_fmt.h \
|
||||
dmsr2v12phases.h dmsr2v12slet.h
|
||||
|
||||
#
|
||||
# Build the emulator
|
||||
#
|
||||
|
||||
${BIN}ibm1130 : ${ibm1130} ${SIM} ${ibm1130_INC} ${SIM_INC}
|
||||
${CC} ${ibm1130} ${SIM} -o $@
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
Here's the 1130 simulator as it stands now.
|
||||
|
||||
Status: 22Jul2003
|
||||
|
||||
* Added support for APL\1130 output translations
|
||||
and some bug fixes uncovered by APL.
|
||||
|
||||
Status: 13Sep2002
|
||||
|
||||
* Added support for 1403 printer. It's MUCH faster
|
||||
even in emulation. Not important for general use,
|
||||
but it will help the CGI version a lot.
|
||||
|
||||
Status: 16Aug2002
|
||||
|
||||
* Disk Monitor System R2V12 is available including the
|
||||
Macro Assembler, Fortran Compiler and System Library.
|
||||
|
||||
* There was a bug in the multiply instruction. This has
|
||||
been fixed, and now the single precision trig functions
|
||||
work correctly.
|
||||
|
||||
* The card punch does not yet work correctly.
|
||||
|
||||
* The card reader, punch and disk don't compute their device
|
||||
status word until an XIO requests it; this is probably bad
|
||||
as the "examine" command will show the wrong value. Doesn't
|
||||
affect functioning of emulated software, though.
|
||||
|
||||
* Documentation is a work in progress, see ibm1130.doc
|
||||
in ibm1130software.zip. We hope to have it finished in
|
||||
October. This is a Word document. Will distribute as a
|
||||
PDF when it's finished.
|
||||
|
||||
* Thanks to Oscar E Wyss (www.cosecans.ch) for
|
||||
the DMS V12 source code listings and one card
|
||||
programs, to Douglas W. Jones for the DMS V10, 11 and
|
||||
12 microfiche (which will end up scanned on IBM1130.org).
|
||||
|
||||
* Thanks to Robert Alan Byer for adding the 1130
|
||||
to the simh makefiles & testing the builds on several
|
||||
platforms.
|
||||
|
||||
* For updated information about the 1130 and for
|
||||
future 1130 OS and application software developments,
|
||||
check www.ibm1130.org periodically. Sign up for the
|
||||
mailing list to get updates as they occur!
|
||||
|
||||
* Cross-assembler has been updated to handle card image input
|
||||
correctly. The DMS sources seems to mix up @ and '
|
||||
as a leading symbol in labels, I have to find out why
|
||||
this is.
|
||||
|
||||
BUILD NOTES: if you download this simulator directly from
|
||||
IBM1130.org, the makefile, source, and binaries are all in
|
||||
the main directory. If you use the version from Bob Supnik's
|
||||
SIMH distribution, the makefile is in the main simh
|
||||
directory, and the SCP files used are Bob's. For a
|
||||
Windows build, use the .mak file in the IBM1130 directory,
|
||||
as this incorporates the GUI.
|
||||
|
||||
Make the utilities in the utils directory if you want
|
||||
to actually build and load DMS from scratch. Move the
|
||||
executables to a common directory in your search path
|
||||
|
||||
Brian Knittel
|
||||
brian@ibm1130.org
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
Some sample things to run:
|
||||
(it's best to hit CHECK RESET or type "reset" between program runs!)
|
||||
|
||||
* Run a Fortran Program
|
||||
ibm1130
|
||||
do job roots
|
||||
do job csort
|
||||
|
||||
* List the monitor system disk's contents
|
||||
ibm1130
|
||||
do job list
|
||||
|
||||
* Look into the files "job", "roots.job" and "csort.job" and "list.job"
|
||||
to see the actual input files
|
||||
|
||||
* When the jobs have run (stop at 2A with 1000 in the
|
||||
accumulator), detach the printer (det prt) and look at
|
||||
the output file: for.lst or asm.lst. The supplied "job"
|
||||
script displays the print output automatically on Windows
|
||||
builds.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
Contents:
|
||||
|
||||
There are several programs:
|
||||
|
||||
ibm1130 the simulator
|
||||
asm1130 cross assembler
|
||||
bindump dumps contents of relocatable format object decks (xxx.bin)
|
||||
checkdisk validates DMS disk format
|
||||
diskview dumps contents of DMS disk directory
|
||||
mkboot creates IPL and Core Image Format Decks from .bin
|
||||
viewdeck displays contents of Hollerith-format binary decks
|
||||
|
||||
Files in the software (sw) directory:
|
||||
|
||||
actual 1130 software:
|
||||
dms.dsk disk image file containing Disk Monitor System
|
||||
zdcip.asm disk cartridge initialization program
|
||||
zcrdumpc.asm a cold-start-mode one card memory dump program
|
||||
dmsboot.asm source code for the DMS cold start loader
|
||||
|
||||
contributed software:
|
||||
onecard/* one-card programs from Oscar Wyss
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
Status of the simulator:
|
||||
|
||||
* There is a reasonably fun console GUI available for Windows builds,
|
||||
as well as support for the 2250 graphical display.
|
||||
|
||||
* The card reader emulator now supports deck files with literal cards and
|
||||
breakpoints. The command "attach cr @filename" tells the simulator to
|
||||
read data from the files named in the specified file. Input lines are of
|
||||
the following form:
|
||||
|
||||
filename a -- input file to be read as ascii text
|
||||
filename b -- input file to be read as binary card images
|
||||
!xyz... -- literal text xyz..., treated as a card
|
||||
!break -- halts the simulator
|
||||
#comment -- remarks
|
||||
|
||||
* The do command may have arguments after the filename. These may be
|
||||
interpolated in the script and in card reader deck files with %1, %2, etc
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
sample usage
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
ibm1130
|
||||
starts SIMH-based simulator.
|
||||
Optional command line arguments: -q quiet mode, -g no GUI
|
||||
|
||||
Enhancements:
|
||||
|
||||
* Windows builds display a console window
|
||||
|
||||
* CPU activity log
|
||||
|
||||
the command "attach cpu file.log" will make the simulator
|
||||
write a detailed log of CPU and IO activity, good for
|
||||
debugging. Turn off with "detach cpu".
|
||||
|
||||
* DO command [arg1 arg2...]
|
||||
reads file 'filename' for SIMH commands. Lets you write
|
||||
simh command files to be run from the prompt rather
|
||||
than just the command line. In the do command file, %1 will
|
||||
be replaced by the first command line argument, etc. This
|
||||
applies to the script run from the ibm1130 command line too.
|
||||
|
||||
* DELETE filename
|
||||
deletes the named file
|
||||
|
||||
* VIEW filename
|
||||
displays the named file with "notepad." (Windows only).
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
asm1130 -l program.asm
|
||||
|
||||
compiles source file, creates simulator load
|
||||
file (program.out) and listing file (program.lst)
|
||||
|
||||
The cross assembler wants files either in strict column
|
||||
layout matching the IBM spec, or, if tabs are present in the
|
||||
source file,
|
||||
|
||||
label<tab>opcode<tab>flags<tab>operand
|
||||
|
||||
The output file is in the format used by the 1130 simulator's
|
||||
load command.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Note: the DMS disk is built with the Windows batch file "mkdms.bat".
|
||||
|
||||
Subnote: DMS cannot be built with the 1130's native assembler.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
check www.ibm1130.org for updates...
|
||||
@@ -1,48 +0,0 @@
|
||||
Version: 10 July 2003
|
||||
|
||||
History (partial):
|
||||
|
||||
2003-07-10 Fixed disk and console terminal bugs uncovered by
|
||||
APL\1130. Added APL keyboard and output font support
|
||||
to enable use of APL\1130. APL will be released soon.
|
||||
|
||||
2003-03-18 Fixed bug in asm1130 that produced an error message
|
||||
with a (legal) offset of +127 in MDX instructions.
|
||||
|
||||
Fixed sign bug in 1130 emulator divide instruction.
|
||||
|
||||
Interim 1130 distribution:
|
||||
--------------------------------------------
|
||||
|
||||
folders:
|
||||
. sources
|
||||
winrel windows executables
|
||||
windebug windows executables
|
||||
utils accessory programs
|
||||
utils\winrel windows executables
|
||||
utils\windebug windows executables
|
||||
sw working directory for DMS build & execution
|
||||
sw\dmsR2V12 Disk Monitor System sources
|
||||
|
||||
programs:
|
||||
asm1130 cross assembler
|
||||
bindump object deck dump tool, also used to sort decks by phase id
|
||||
checkdisk DMS disk image check and dump
|
||||
diskview work in progress, interpreted disk image dump
|
||||
ibm1130 emulator
|
||||
mkboot object deck to IPL and core image converter
|
||||
viewdeck binary to hollerith deck viewer if needed to view phase ID cards and ident fields
|
||||
|
||||
batch file:
|
||||
mkdms.bat builds DMS objects and binary cards. Need a shell script version of this.
|
||||
|
||||
IBM1130 simulator DO command scripts:
|
||||
format format a disk image named DMS.DSK
|
||||
loaddms format and install DMS onto the formatted DMS.DSK
|
||||
for run a Fortran program
|
||||
list list the disk contents
|
||||
asm assemble a program
|
||||
|
||||
ancillary files:
|
||||
loaddms.deck list of files stacked into the card reader for loaddms
|
||||
*.deck other sample deck files
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,161 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "asm1130.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/asm1130.sbr
|
||||
|
||||
$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
|
||||
/INCREMENTAL:no /PDB:$(OUTDIR)/"asm1130.pdb" /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"asm1130.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/asm1130.obj
|
||||
|
||||
$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/\
|
||||
/Fd$(OUTDIR)/"asm1130.pdb" /c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/asm1130.sbr
|
||||
|
||||
$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
|
||||
/INCREMENTAL:yes /PDB:$(OUTDIR)/"asm1130.pdb" /DEBUG /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"asm1130.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/asm1130.obj
|
||||
|
||||
$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\asm1130.c
|
||||
|
||||
$(INTDIR)/asm1130.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
@@ -1,752 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// BINDUMP - dumps card deck files in assembler object format
|
||||
//
|
||||
// Usage:
|
||||
/// bindump deckfile lists object header info & sector break cards
|
||||
// bindump -v deckfile lists object data records as well
|
||||
// bindump -p deckfile for system program, lists phase IDs in the deck
|
||||
// bindump -s deckfile >outfile for system program, sorts the phases & writes to stdout
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define BOOL int
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC;
|
||||
|
||||
BOOL verbose = FALSE;
|
||||
BOOL phid = FALSE;
|
||||
BOOL sort = FALSE;
|
||||
unsigned short card[80], buf[54], cardtype;
|
||||
|
||||
// bindump - dump a binary (card format) deck to verify sbrks, etc
|
||||
|
||||
void bail (char *msg);
|
||||
void dump (char *fname);
|
||||
void dump_data (char *fname);
|
||||
void dump_phids (char *fname);
|
||||
char *getname (unsigned short *ptr);
|
||||
char *getseq (void);
|
||||
int hollerith_to_ascii (unsigned short h);
|
||||
void process (char *fname);
|
||||
void show_raw (char *name);
|
||||
void show_data (void);
|
||||
void show_core (void);
|
||||
void show_endc (void);
|
||||
void show_81 (void);
|
||||
void show_main (void);
|
||||
void show_sub (void);
|
||||
void show_ils (void);
|
||||
void show_iss (void);
|
||||
void show_end (void);
|
||||
void sort_phases (char *fname);
|
||||
void trim (char *s);
|
||||
void unpack (unsigned short *card, unsigned short *buf);
|
||||
void verify_checksum(unsigned short *buf);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
char *arg;
|
||||
static char usestr[] = "Usage: bindump [-psv] filename...";
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
arg = argv[i];
|
||||
if (*arg == '-') {
|
||||
arg++;
|
||||
while (*arg) {
|
||||
switch (*arg++) {
|
||||
case 'v':
|
||||
verbose = TRUE;
|
||||
break;
|
||||
case 'p':
|
||||
phid = TRUE; // print only phase ID's
|
||||
break;
|
||||
case 's':
|
||||
sort = TRUE; // sort deck by phases, writing to stdout
|
||||
break;
|
||||
default:
|
||||
bail(usestr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
arg = argv[i];
|
||||
if (*arg != '-')
|
||||
process(arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process (char *nm)
|
||||
{
|
||||
#ifdef WIN32
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hFind;
|
||||
char *c, buf[256];
|
||||
|
||||
if (strchr(nm, '*') == NULL && strchr(nm, '?') == NULL)
|
||||
dump(nm);
|
||||
|
||||
else if ((hFind = FindFirstFile(nm, &fd)) == INVALID_HANDLE_VALUE)
|
||||
fprintf(stderr, "No files matching '%s'\n", nm);
|
||||
|
||||
else {
|
||||
if ((c = strrchr(nm, '\\')) == NULL)
|
||||
c = strrchr(nm, ':');
|
||||
|
||||
do {
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
continue;
|
||||
|
||||
if (c == NULL)
|
||||
dump(fd.cFileName);
|
||||
else {
|
||||
strcpy(buf, nm);
|
||||
strcpy(buf + (c-nm+1), fd.cFileName);
|
||||
dump(buf);
|
||||
}
|
||||
|
||||
} while (FindNextFile(hFind, &fd));
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
#else
|
||||
dump(nm); // on unices, sh globs for us
|
||||
#endif
|
||||
}
|
||||
|
||||
void dump (char *fname)
|
||||
{
|
||||
if (sort)
|
||||
sort_phases(fname);
|
||||
else if (phid)
|
||||
dump_phids(fname);
|
||||
else
|
||||
dump_data(fname);
|
||||
}
|
||||
|
||||
struct tag_card {
|
||||
int phid, seq;
|
||||
unsigned short card[80];
|
||||
};
|
||||
|
||||
int cardcomp (const void *a, const void *b)
|
||||
{
|
||||
short diff;
|
||||
|
||||
diff = ((struct tag_card *) a)->phid - ((struct tag_card *) b)->phid;
|
||||
|
||||
return diff ? diff : (((struct tag_card *) a)->seq - ((struct tag_card *) b)->seq);
|
||||
}
|
||||
|
||||
void sort_phases (char *fname)
|
||||
{
|
||||
int i, ncards, cardtype, len, seq = 0, phid;
|
||||
struct tag_card *deck;
|
||||
FILE *fd;
|
||||
BOOL saw_sbrk = TRUE;
|
||||
|
||||
if ((fd = fopen(fname, "rb")) == NULL) {
|
||||
perror(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(fd, 0, SEEK_END);
|
||||
len = ftell(fd); // get length of file
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (len <= 0 || (len % 160) != 0) {
|
||||
fprintf(stderr, "%s is not a binard deck image\n");
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
ncards = len / 160;
|
||||
|
||||
if ((deck = (struct tag_card *) malloc(ncards*sizeof(struct tag_card))) == NULL) {
|
||||
fprintf(stderr, "%s: can't sort, insufficient memory\n");
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
phid = 0;
|
||||
for (i = 0; i < ncards; i++) {
|
||||
if (fread(deck[i].card, sizeof(card[0]), 80, fd) != 80) {
|
||||
free(deck);
|
||||
fprintf(stderr, "%s: error reading deck\n");
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
unpack(deck[i].card, buf);
|
||||
deck[i].seq = seq++;
|
||||
deck[i].phid = phid;
|
||||
|
||||
verify_checksum(buf);
|
||||
|
||||
cardtype = (buf[2] >> 8) & 0xFF;
|
||||
|
||||
if (cardtype == 1 || cardtype == 2) { // start of deck is same as sector break
|
||||
saw_sbrk = TRUE;
|
||||
}
|
||||
else if (cardtype == 0) {
|
||||
fprintf(stderr, "%s is a core image deck\n");
|
||||
free(deck);
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
else if (cardtype == 0x0A && saw_sbrk) {
|
||||
phid = (int) (signed short) buf[10];
|
||||
if (phid < 0)
|
||||
phid = -phid;
|
||||
|
||||
deck[i].phid = phid; // this belongs to the new phase
|
||||
deck[i-1].phid = phid; // as does previous card
|
||||
saw_sbrk = FALSE;
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
qsort(deck, ncards, sizeof(struct tag_card), cardcomp); // sort the deck
|
||||
|
||||
#ifdef WIN32
|
||||
_setmode(_fileno(stdout), _O_BINARY); // set standard output to binary mode
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ncards; i++) // write to stdout
|
||||
fwrite(deck[i].card, sizeof(card[0]), 80, stdout);
|
||||
|
||||
free(deck);
|
||||
}
|
||||
|
||||
void dump_phids (char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
BOOL first = TRUE;
|
||||
BOOL saw_sbrk = TRUE, neg;
|
||||
short id;
|
||||
|
||||
if ((fp = fopen(fname, "rb")) == NULL) {
|
||||
perror(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\n%s:\n", fname);
|
||||
|
||||
while (fread(card, sizeof(card[0]), 80, fp) > 0) {
|
||||
unpack(card, buf);
|
||||
verify_checksum(buf);
|
||||
|
||||
cardtype = (buf[2] >> 8) & 0xFF;
|
||||
|
||||
if (cardtype == 1 && ! first) { // sector break
|
||||
saw_sbrk = TRUE;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
switch (cardtype) {
|
||||
case 0x00:
|
||||
printf(" This is a core image deck\n");
|
||||
goto done;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
case 0x0F:
|
||||
break;
|
||||
|
||||
case 0x0A:
|
||||
if (saw_sbrk) {
|
||||
id = buf[10];
|
||||
if (id < 0)
|
||||
id = -id, neg = TRUE;
|
||||
else
|
||||
neg = FALSE;
|
||||
printf(" : %3d / %02x%s\n", id, id, neg ? " (neg)" : "");
|
||||
saw_sbrk = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
show_raw("??? ");
|
||||
}
|
||||
}
|
||||
done:
|
||||
first = FALSE;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void dump_data (char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
BOOL first = TRUE;
|
||||
char str[80];
|
||||
int i;
|
||||
|
||||
if ((fp = fopen(fname, "rb")) == NULL) {
|
||||
perror(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\n%s:\n", fname);
|
||||
|
||||
while (fread(card, sizeof(card[0]), 80, fp) > 0) {
|
||||
unpack(card, buf);
|
||||
verify_checksum(buf);
|
||||
|
||||
cardtype = (buf[2] >> 8) & 0xFF;
|
||||
|
||||
if (cardtype == 1 && ! first) { // sector break
|
||||
for (i = 4; i < 72; i++)
|
||||
str[i] = hollerith_to_ascii(card[i]);
|
||||
|
||||
str[i] = '\0';
|
||||
trim(str+4);
|
||||
printf("*SBRK %s\n", str+4);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
switch (cardtype) {
|
||||
case 0x00:
|
||||
if (first)
|
||||
show_raw("CORE");
|
||||
if (verbose)
|
||||
show_core();
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
show_raw("ABS ");
|
||||
show_main();
|
||||
break;
|
||||
case 0x02:
|
||||
show_raw("REL ");
|
||||
show_main();
|
||||
break;
|
||||
case 0x03:
|
||||
show_raw("LIB ");
|
||||
show_sub();
|
||||
break;
|
||||
case 0x04:
|
||||
show_raw("SUB ");
|
||||
show_sub();
|
||||
break;
|
||||
case 0x05:
|
||||
show_raw("ISSL");
|
||||
show_iss();
|
||||
break;
|
||||
case 0x06:
|
||||
show_raw("ISSC");
|
||||
show_iss();
|
||||
break;
|
||||
case 0x07:
|
||||
show_raw("ILS ");
|
||||
show_ils();
|
||||
break;
|
||||
case 0x0F:
|
||||
show_raw("END ");
|
||||
show_end();
|
||||
break;
|
||||
case 0x80:
|
||||
show_raw("ENDC");
|
||||
show_endc();
|
||||
break;
|
||||
case 0x81:
|
||||
show_raw("81 ");
|
||||
show_81();
|
||||
break;
|
||||
case 0x0A:
|
||||
if (verbose)
|
||||
show_data();
|
||||
break;
|
||||
default:
|
||||
show_raw("??? ");
|
||||
}
|
||||
}
|
||||
|
||||
first = FALSE;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void show_data (void)
|
||||
{
|
||||
int i, n, jrel, rflag, nout, ch, reloc;
|
||||
BOOL first = TRUE;
|
||||
|
||||
n = buf[2] & 0x00FF;
|
||||
|
||||
printf("%04x: ", buf[0]);
|
||||
|
||||
jrel = 3;
|
||||
nout = 0;
|
||||
rflag = buf[jrel++];
|
||||
for (i = 0; i < n; i++) {
|
||||
if (nout >= 8) {
|
||||
rflag = buf[jrel++];
|
||||
if (first) {
|
||||
printf(" %s", getseq());
|
||||
first = FALSE;
|
||||
}
|
||||
printf("\n ");
|
||||
nout = 0;
|
||||
}
|
||||
reloc = (rflag >> 14) & 0x03;
|
||||
ch = (reloc == R_ABSOLUTE) ? ' ' :
|
||||
(reloc == R_RELATIVE) ? 'R' :
|
||||
(reloc == R_LIBF) ? 'L' : '@';
|
||||
|
||||
printf("%04x%c ", buf[9+i], ch);
|
||||
rflag <<= 2;
|
||||
nout++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_core (void)
|
||||
{
|
||||
int i, n, nout;
|
||||
BOOL first = TRUE;
|
||||
|
||||
n = buf[2] & 0x00FF;
|
||||
|
||||
printf("%04x: ", buf[0]);
|
||||
|
||||
nout = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (nout >= 8) {
|
||||
if (first) {
|
||||
printf(" %s", getseq());
|
||||
first = FALSE;
|
||||
}
|
||||
printf("\n ");
|
||||
nout = 0;
|
||||
}
|
||||
printf("%04x ", buf[9+i]);
|
||||
nout++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void info (int i, char *nm, char type)
|
||||
{
|
||||
if (nm)
|
||||
printf("%s ", nm);
|
||||
|
||||
switch (type) {
|
||||
case 'd':
|
||||
printf("%d ", buf[i]);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
printf("%04x ", buf[i]);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf("%02x ", buf[i] & 0xFF);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
printf("%s ", getname(buf+i));
|
||||
break;
|
||||
|
||||
default:
|
||||
bail("BAD TYPE");
|
||||
}
|
||||
}
|
||||
|
||||
void show_main (void)
|
||||
{
|
||||
printf(" ");
|
||||
info(2, "prec", 'b');
|
||||
info(4, "common", 'd');
|
||||
info(6, "work", 'd');
|
||||
info(8, "files", 'd');
|
||||
info(9, "name", 'n');
|
||||
info(11, "pta", 'x');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_sub (void)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
printf(" ");
|
||||
info( 2, "prec", 'b');
|
||||
|
||||
n = buf[5] / 3;
|
||||
for (i = 0; i < n; i++) {
|
||||
info( 9+3*i, "ent", 'n');
|
||||
info(11+3*i, NULL, 'x');
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_iss (void)
|
||||
{
|
||||
printf(" ");
|
||||
info(12, "level", 'd');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_ils (void)
|
||||
{
|
||||
printf(" ");
|
||||
info( 2, "prec", 'b');
|
||||
info( 5, "nint6", 'd');
|
||||
info( 9, "ent", 'n');
|
||||
info(11, NULL, 'x');
|
||||
info(14, "nint", 'd');
|
||||
info(15, "il1", 'd');
|
||||
info(16, "il2", 'd');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_end (void)
|
||||
{
|
||||
printf(" ");
|
||||
info(0, "size", 'd');
|
||||
info(3, "pta", 'x');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_endc(void)
|
||||
{
|
||||
printf(" ");
|
||||
info(52, "IX3", 'x');
|
||||
info(53, "pta", 'x');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void show_81(void)
|
||||
{
|
||||
}
|
||||
|
||||
void show_raw (char *name)
|
||||
{
|
||||
int i;
|
||||
printf("*%s", name);
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
printf(" %04x", buf[i]);
|
||||
|
||||
printf(" %s\n", getseq());
|
||||
}
|
||||
|
||||
char * getseq (void)
|
||||
{
|
||||
static char seq[10];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
seq[i] = hollerith_to_ascii(card[72+i]);
|
||||
|
||||
seq[i] = '\0';
|
||||
return seq;
|
||||
}
|
||||
|
||||
|
||||
void bail (char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void unpack (unsigned short *icard, unsigned short *obuf)
|
||||
{
|
||||
int i, j;
|
||||
unsigned short wd1, wd2, wd3, wd4;
|
||||
|
||||
for (i = j = 0; i < 54; i += 3, j += 4) {
|
||||
wd1 = icard[j];
|
||||
wd2 = icard[j+1];
|
||||
wd3 = icard[j+2];
|
||||
wd4 = icard[j+3];
|
||||
|
||||
obuf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F);
|
||||
obuf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF);
|
||||
obuf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF);
|
||||
}
|
||||
}
|
||||
|
||||
void verify_checksum (unsigned short *obuf)
|
||||
{
|
||||
// unsigned short sum;
|
||||
|
||||
if (obuf[1] == 0) // no checksum
|
||||
return;
|
||||
|
||||
// if (sum != card[1])
|
||||
// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned short hollerith;
|
||||
char ascii;
|
||||
} CPCODE;
|
||||
|
||||
static CPCODE cardcode_029[] =
|
||||
{
|
||||
0x0000, ' ',
|
||||
0x8000, '&', // + in 026 Fortran
|
||||
0x4000, '-',
|
||||
0x2000, '0',
|
||||
0x1000, '1',
|
||||
0x0800, '2',
|
||||
0x0400, '3',
|
||||
0x0200, '4',
|
||||
0x0100, '5',
|
||||
0x0080, '6',
|
||||
0x0040, '7',
|
||||
0x0020, '8',
|
||||
0x0010, '9',
|
||||
0x9000, 'A',
|
||||
0x8800, 'B',
|
||||
0x8400, 'C',
|
||||
0x8200, 'D',
|
||||
0x8100, 'E',
|
||||
0x8080, 'F',
|
||||
0x8040, 'G',
|
||||
0x8020, 'H',
|
||||
0x8010, 'I',
|
||||
0x5000, 'J',
|
||||
0x4800, 'K',
|
||||
0x4400, 'L',
|
||||
0x4200, 'M',
|
||||
0x4100, 'N',
|
||||
0x4080, 'O',
|
||||
0x4040, 'P',
|
||||
0x4020, 'Q',
|
||||
0x4010, 'R',
|
||||
0x3000, '/',
|
||||
0x2800, 'S',
|
||||
0x2400, 'T',
|
||||
0x2200, 'U',
|
||||
0x2100, 'V',
|
||||
0x2080, 'W',
|
||||
0x2040, 'X',
|
||||
0x2020, 'Y',
|
||||
0x2010, 'Z',
|
||||
0x0820, ':',
|
||||
0x0420, '#', // = in 026 Fortran
|
||||
0x0220, '@', // ' in 026 Fortran
|
||||
0x0120, '\'',
|
||||
0x00A0, '=',
|
||||
0x0060, '"',
|
||||
0x8820, 'c', // cent
|
||||
0x8420, '.',
|
||||
0x8220, '<', // ) in 026 Fortran
|
||||
0x8120, '(',
|
||||
0x80A0, '+',
|
||||
0x8060, '|',
|
||||
0x4820, '!',
|
||||
0x4420, '$',
|
||||
0x4220, '*',
|
||||
0x4120, ')',
|
||||
0x40A0, ';',
|
||||
0x4060, 'n', // not
|
||||
0x2820, 'x', // what?
|
||||
0x2420, ',',
|
||||
0x2220, '%', // ( in 026 Fortran
|
||||
0x2120, '_',
|
||||
0x20A0, '>',
|
||||
0x2060, '>',
|
||||
};
|
||||
|
||||
int hollerith_to_ascii (unsigned short h)
|
||||
{
|
||||
int i;
|
||||
|
||||
h &= 0xFFF0;
|
||||
|
||||
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)
|
||||
if (cardcode_029[i].hollerith == h)
|
||||
return cardcode_029[i].ascii;
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// trim - remove trailing whitespace from string s
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
void trim (char *s)
|
||||
{
|
||||
char *nb;
|
||||
|
||||
for (nb = s-1; *s; s++)
|
||||
if (*s > ' ')
|
||||
nb = s;
|
||||
|
||||
nb[1] = '\0';
|
||||
}
|
||||
|
||||
int ascii_to_ebcdic_table[128] =
|
||||
{
|
||||
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
|
||||
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
|
||||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
|
||||
|
||||
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
|
||||
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,
|
||||
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
|
||||
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
|
||||
};
|
||||
|
||||
char *getname (unsigned short *ptr)
|
||||
{
|
||||
static char str[6];
|
||||
int i, j, ch;
|
||||
long v;
|
||||
|
||||
v = (ptr[0] << 16L) | ptr[1];
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
ch = ((v >> 24) & 0x3F) | 0xC0; // recover those lost two bits
|
||||
v <<= 6;
|
||||
|
||||
str[i] = ' ';
|
||||
|
||||
for (j = 0; j < (sizeof(ascii_to_ebcdic_table)/sizeof(ascii_to_ebcdic_table[0])); j++) {
|
||||
if (ascii_to_ebcdic_table[j] == ch) {
|
||||
str[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str[5] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "bindump.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/bindump.sbr
|
||||
|
||||
$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
||||
/NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"bindump.pdb"\
|
||||
/MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/bindump.obj
|
||||
|
||||
$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/\
|
||||
/Fd$(OUTDIR)/"bindump.pdb" /c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/bindump.sbr
|
||||
|
||||
$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
||||
/NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"bindump.pdb" /DEBUG\
|
||||
/MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/bindump.obj
|
||||
|
||||
$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\bindump.c
|
||||
|
||||
$(INTDIR)/bindump.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
// checkdisk - validates and optionally dumps an IBM1130 DMS2 disk image file
|
||||
//
|
||||
// Usage:
|
||||
// checkdisk [-f] [-d cyl.sec|abssec] [-n count] filename
|
||||
//
|
||||
// Examples:
|
||||
// checkdisk file.dsk
|
||||
// report any misnumbered sectors in file.dsk
|
||||
//
|
||||
// checkdisk -f file.dsk
|
||||
// report and fix any misnumbered sectors
|
||||
//
|
||||
// checkdisk -d 198.0 file.dsk
|
||||
// dump cylinder 198 sector 0
|
||||
//
|
||||
// checkdisk -d 0 file.dsk
|
||||
// dump absolute sector 0
|
||||
//
|
||||
// checkdisk -d 198.0 -n 4 file.dsk
|
||||
// dump 4 sectors starting at m.n
|
||||
// -----------------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util_io.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
long filelength (int fno);
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
# define BOOL int
|
||||
# define TRUE 1
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
#define DSK_NUMWD 321 /* words/sector */
|
||||
#define DSK_NUMSC 4 /* sectors/surface */
|
||||
#define DSK_NUMSF 2 /* surfaces/cylinder */
|
||||
#define DSK_NUMCY 203 /* cylinders/drive */
|
||||
#define DSK_NUMDR 5 /* drives/controller */
|
||||
#define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */
|
||||
|
||||
char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile";
|
||||
char *baddisk = "Cannot fix this";
|
||||
|
||||
void bail (char *msg);
|
||||
char *lowcase (char *str);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
FILE *fp;
|
||||
char *fname = NULL, *arg, *argval;
|
||||
int i, j, cyl, sec, pos, asec, retry, nbad = 0, nfixed = 0, nline;
|
||||
BOOL fixit = FALSE, dump = FALSE;
|
||||
int dsec, nsec = 1;
|
||||
unsigned short wd, buf[DSK_NUMWD];
|
||||
|
||||
util_io_init();
|
||||
|
||||
for (i = 1; i < argc;) {
|
||||
arg = argv[i++];
|
||||
if (*arg == '-') {
|
||||
arg++;
|
||||
lowcase(arg);
|
||||
while (*arg) {
|
||||
switch (*arg++) {
|
||||
case 'f':
|
||||
fixit = TRUE;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dump = TRUE;
|
||||
|
||||
if (i >= argc)
|
||||
bail(usestr);
|
||||
|
||||
argval = argv[i++];
|
||||
if (strchr(argval, '.') != NULL) {
|
||||
if (sscanf(argval, "%d.%d", &cyl, &sec) != 2)
|
||||
bail(usestr);
|
||||
|
||||
dsec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec;
|
||||
}
|
||||
else if (sscanf(argval, "%d", &dsec) != 1)
|
||||
bail(usestr);
|
||||
|
||||
if (dsec < 0 || dsec >= (DSK_NUMCY*DSK_NUMSF*DSK_NUMSC))
|
||||
bail("No such sector");
|
||||
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (i >= argc)
|
||||
bail(usestr);
|
||||
|
||||
argval = argv[i++];
|
||||
if (sscanf(argval, "%d", &nsec) != 1)
|
||||
bail(usestr);
|
||||
|
||||
if (nsec <= 0)
|
||||
bail(usestr);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
bail(usestr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fname == NULL)
|
||||
fname = arg;
|
||||
else
|
||||
bail(usestr);
|
||||
}
|
||||
|
||||
if (fname == NULL)
|
||||
bail(usestr);
|
||||
|
||||
if ((fp = fopen(fname, "rb+")) == NULL) {
|
||||
perror(fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (filelength(fileno(fp)) != 2*DSK_SIZE) {
|
||||
fprintf(stderr, "File is wrong length, expected %d\n", DSK_SIZE);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
for (cyl = 0; cyl < DSK_NUMCY; cyl++) {
|
||||
for (sec = 0; sec < (DSK_NUMSF*DSK_NUMSC); sec++) {
|
||||
retry = 1;
|
||||
again:
|
||||
asec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec;
|
||||
pos = asec*2*DSK_NUMWD;
|
||||
|
||||
if (fseek(fp, pos, SEEK_SET) != 0) {
|
||||
fprintf(stderr, "Error seeking to pos %x\n", pos);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
if (fxread(&wd, sizeof(wd), 1, fp) != 1) {
|
||||
fprintf(stderr, "Error reading word at abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
if (wd != asec) {
|
||||
fprintf(stderr, "Bad sector #%x at abs sec %x, cyl %x, sec %x at offset %x\n", wd, asec, cyl, sec, pos);
|
||||
nbad++;
|
||||
|
||||
if (fixit) {
|
||||
if (fseek(fp, pos, SEEK_SET) != 0) {
|
||||
fprintf(stderr, "Error seeking to pos %x\n", pos);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
if (fxwrite(&asec, sizeof(wd), 1, fp) != 1) {
|
||||
fprintf(stderr, "Error writing sector # to abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
if (retry) {
|
||||
retry = 0;
|
||||
nfixed++;
|
||||
goto again;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Failed after retry\n");
|
||||
bail(baddisk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nbad)
|
||||
printf("%d bad sector mark%s %s\n", nbad, (nbad == 1) ? "" : "s", fixit ? "fixed" : "found");
|
||||
else if (! dump)
|
||||
printf("All sector marks OK\n");
|
||||
|
||||
if (! dump)
|
||||
return 0;
|
||||
|
||||
pos = dsec*2*DSK_NUMWD;
|
||||
if (fseek(fp, pos, SEEK_SET) != 0) {
|
||||
fprintf(stderr, "Error seeking to pos %x\n", pos);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
for (i = 0; i < nsec; i++) {
|
||||
cyl = dsec / (DSK_NUMSF*DSK_NUMSC);
|
||||
sec = dsec - cyl*(DSK_NUMSF*DSK_NUMSC);
|
||||
|
||||
if (fxread(&buf, sizeof(buf[0]), DSK_NUMWD, fp) != DSK_NUMWD) {
|
||||
fprintf(stderr, "Error reading abs sec %x, cyl %x, sec %x at offset %x\n", dsec, cyl, sec, pos);
|
||||
bail(baddisk);
|
||||
}
|
||||
|
||||
printf("\nSector %d.%d - %d - /%04x label %04x\n", cyl, sec, dsec, dsec, buf[0]);
|
||||
for (nline = 0, j = 1; j < DSK_NUMWD; j++) {
|
||||
printf("%04x", buf[j]);
|
||||
if (++nline == 16) {
|
||||
putchar('\n');
|
||||
nline = 0;
|
||||
}
|
||||
else
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
dsec++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bail (char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* lowcase - force a string to lower case (ASCII)
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
char *lowcase (char *str)
|
||||
{
|
||||
char *s;
|
||||
|
||||
for (s = str; *s; s++) {
|
||||
if (*s >= 'A' && *s <= 'Z')
|
||||
*s += 32;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
long filelength (int fno)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (fstat(fno, &sb) != 0)
|
||||
return 0;
|
||||
|
||||
return (long) sb.st_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "checkdisk.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "Win32 Release"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/checkdisk.sbr \
|
||||
$(INTDIR)/util_io.sbr
|
||||
|
||||
$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\
|
||||
/SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"checkdisk.pdb" /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"checkdisk.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/checkdisk.obj \
|
||||
$(INTDIR)/util_io.obj
|
||||
|
||||
$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/\
|
||||
/Fd$(OUTDIR)/"checkdisk.pdb" /c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/checkdisk.sbr \
|
||||
$(INTDIR)/util_io.sbr
|
||||
|
||||
$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\
|
||||
/SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"checkdisk.pdb" /DEBUG\
|
||||
/MACHINE:I386 /OUT:$(OUTDIR)/"checkdisk.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/checkdisk.obj \
|
||||
$(INTDIR)/util_io.obj
|
||||
|
||||
$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\checkdisk.c
|
||||
DEP_CHECK=\
|
||||
.\util_io.h\
|
||||
\MSVC20\INCLUDE\sys\types.h\
|
||||
\MSVC20\INCLUDE\sys\stat.h
|
||||
|
||||
$(INTDIR)/checkdisk.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util_io.c
|
||||
|
||||
$(INTDIR)/util_io.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
@@ -1,614 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
// DISKVIEW - lists contents of an 1130 system disk image file. Not finished yet.
|
||||
// needs LET/SLET listing routine.
|
||||
//
|
||||
// usage:
|
||||
// diskview -v diskfile
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "util_io.h"
|
||||
|
||||
#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b)))
|
||||
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
|
||||
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
|
||||
|
||||
#ifndef TRUE
|
||||
# define TRUE 1
|
||||
# define FALSE 0
|
||||
# define BOOL int
|
||||
#endif
|
||||
|
||||
#define NOT_DEF 0x0658 // defective cylinder table entry means no defect
|
||||
|
||||
#define DSK_NUMWD 321 /* words/sector */
|
||||
#define DSK_NUMCY 203 /* cylinders/drive */
|
||||
#define DSK_SECCYL 8 /* sectors per cylinder */
|
||||
#define SECLEN 320 /* data words per sector */
|
||||
#define SLETLEN ((3*SECLEN)/4) /* length of slet in records */
|
||||
|
||||
typedef unsigned short WORD;
|
||||
|
||||
FILE *fp;
|
||||
WORD buf[DSK_NUMWD];
|
||||
WORD dcom[DSK_NUMWD];
|
||||
|
||||
#pragma pack(2)
|
||||
struct tag_slet {
|
||||
WORD phid;
|
||||
WORD addr;
|
||||
WORD nwords;
|
||||
WORD sector;
|
||||
} slet[SLETLEN];
|
||||
|
||||
#pragma pack()
|
||||
|
||||
WORD dcyl[3];
|
||||
BOOL verbose = FALSE;
|
||||
|
||||
void checksectors (void);
|
||||
void dump_id (void);
|
||||
void dump_dcom (void);
|
||||
void dump_resmon (void);
|
||||
void dump_slet (void);
|
||||
void dump_hdng (void);
|
||||
void dump_scra (void);
|
||||
void dump_let (void);
|
||||
void dump_flet (void);
|
||||
void dump_cib (void);
|
||||
void getsector (int sec, WORD *sbuf);
|
||||
void getdcyl (void);
|
||||
char *lowcase (char *str);
|
||||
|
||||
void bail(char *fmt, ...);
|
||||
char *trim (char *s);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
char *fname = NULL, *arg;
|
||||
static char usestr[] = "Usage: diskview [-v] filename";
|
||||
int i;
|
||||
|
||||
util_io_init();
|
||||
|
||||
for (i = 1; i < argc;) {
|
||||
arg = argv[i++];
|
||||
if (*arg == '-') {
|
||||
arg++;
|
||||
lowcase(arg);
|
||||
while (*arg) {
|
||||
switch (*arg++) {
|
||||
case 'v':
|
||||
verbose = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
bail(usestr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fname == NULL)
|
||||
fname = arg;
|
||||
else
|
||||
bail(usestr);
|
||||
}
|
||||
|
||||
if (fname == NULL)
|
||||
bail(usestr);
|
||||
|
||||
if ((fp = fopen(fname, "rb")) == NULL) {
|
||||
perror(fname);
|
||||
return 2;
|
||||
}
|
||||
|
||||
printf("%s:\n", fname);
|
||||
|
||||
checksectors();
|
||||
getdcyl();
|
||||
|
||||
dump_id(); // ID & coldstart
|
||||
dump_dcom(); // DCOM
|
||||
dump_resmon(); // resident image
|
||||
dump_slet(); // SLET
|
||||
dump_hdng(); // heading sector
|
||||
dump_scra();
|
||||
dump_flet();
|
||||
dump_cib();
|
||||
dump_let();
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// checksectors - verify that all sectors are properly numbered
|
||||
|
||||
void checksectors ()
|
||||
{
|
||||
WORD sec = 0;
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
for (sec = 0; sec < DSK_NUMCY*DSK_SECCYL; sec++) {
|
||||
if (fxread(buf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD)
|
||||
bail("File read error or not a disk image file");
|
||||
|
||||
if (buf[0] != sec)
|
||||
bail("Sector /%x is misnumbered, run checkdisk [-f]", sec);
|
||||
}
|
||||
}
|
||||
|
||||
// get defective cylinder list
|
||||
|
||||
void getdcyl (void)
|
||||
{
|
||||
fseek(fp, sizeof(WORD), SEEK_SET); // skip sector count
|
||||
if (fxread(dcyl, sizeof(WORD), 3, fp) != 3)
|
||||
bail("Unable to read defective cylinder table");
|
||||
}
|
||||
|
||||
// getsector - read specified absolute sector
|
||||
|
||||
void getsector (int sec, WORD *sbuf)
|
||||
{
|
||||
int i, cyl, ssec;
|
||||
|
||||
sec &= 0x7FF; // mask of drive bits, if any
|
||||
|
||||
cyl = sec / DSK_SECCYL; // get cylinder
|
||||
ssec = sec & ~(DSK_SECCYL-1); // mask to get starting sector of cylinder
|
||||
for (i = 0; i < 3; i++) { // map through defective cylinder table
|
||||
if (dcyl[i] == ssec) {
|
||||
sec &= (DSK_SECCYL-1); // mask to get base sector
|
||||
cyl = DSK_NUMCY-3+i; // replacements are last three on disk
|
||||
sec += cyl*DSK_SECCYL; // add new cylinder offset
|
||||
break;
|
||||
}
|
||||
}
|
||||
// read the sector
|
||||
if (fseek(fp, (sec*DSK_NUMWD+1)*sizeof(WORD), SEEK_SET) != 0)
|
||||
bail("File seek failed");
|
||||
|
||||
if (fxread(sbuf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD)
|
||||
bail("File read error or not a disk image file");
|
||||
}
|
||||
|
||||
void dump (int nwords)
|
||||
{
|
||||
int i, nline = 0;
|
||||
|
||||
for (i = 0; i < nwords; i++) {
|
||||
if (nline == 16) {
|
||||
putchar('\n');
|
||||
nline = 0;
|
||||
}
|
||||
|
||||
printf("%04x", buf[i]);
|
||||
nline++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void showmajor (char *label)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("\n--- %s ", label);
|
||||
|
||||
for (i = strlen(label); i < 40; i++)
|
||||
putchar('-');
|
||||
|
||||
putchar('\n');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void name (char *label)
|
||||
{
|
||||
printf("%-32.32s ", label);
|
||||
}
|
||||
|
||||
void pbf (char *label, WORD *buf, int nwords)
|
||||
{
|
||||
int i, nout;
|
||||
|
||||
name(label);
|
||||
|
||||
for (i = nout = 0; i < nwords; i++, nout++) {
|
||||
if (nout == 8) {
|
||||
putchar('\n');
|
||||
name("");
|
||||
nout = 0;
|
||||
}
|
||||
printf(" %04x", buf[i]);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void prt (char *label, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
name(label);
|
||||
|
||||
putchar(' ');
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void dump_id (void)
|
||||
{
|
||||
showmajor("Sector 0 - ID & coldstart");
|
||||
getsector(0, buf);
|
||||
|
||||
pbf("DCYL def cyl table", buf+ 0, 3);
|
||||
pbf("CIDN cart id", buf+ 3, 1);
|
||||
pbf(" copy code", buf+ 4, 1);
|
||||
pbf("DTYP disk type", buf+ 7, 1);
|
||||
pbf(" diskz copy", buf+ 30, 8);
|
||||
pbf(" cold start pgm",buf+270, 8);
|
||||
}
|
||||
|
||||
// EQUIVALENCES FOR DCOM PARAMETERS
|
||||
#define NAME 4 // NAME OF PROGRAM/CORE LOAD
|
||||
#define DBCT 6 // BLOCK CT OF PROGRAM/CORE LOAD
|
||||
#define FCNT 7 // FILES SWITCH
|
||||
#define SYSC 8 // SYSTEM/NON-SYSTEM CARTRIDGE INDR
|
||||
#define JBSW 9 // JOBT SWITCH
|
||||
#define CBSW 10 // CLB-RETURN SWITCH
|
||||
#define LCNT 11 // NO. OF LOCALS
|
||||
#define MPSW 12 // CORE MAP SWITCH
|
||||
#define MDF1 13 // NO. DUP CTRL RECORDS (MODIF)
|
||||
#define MDF2 14 // ADDR OF MODIF BUFFER
|
||||
#define NCNT 15 // NO. OF NOCALS
|
||||
#define ENTY 16 // RLTV ENTRY ADDR OF PROGRAM
|
||||
#define RP67 17 // 1442-5 SWITCH
|
||||
#define TODR 18 // OBJECT WORK STORAGE DRIVE CODE
|
||||
#define FHOL 20 // ADDR LARGEST HOLE IN FIXED AREA
|
||||
#define FSZE 21 // BLK CNT LARGEST HOLE IN FXA
|
||||
#define UHOL 22 // ADDR LAST HOLE IN USER AREA 2-10
|
||||
#define USZE 23 // BLK CNT LAST HOLE IN UA 2-10
|
||||
#define DCSW 24 // DUP CALL SWITCH
|
||||
#define PIOD 25 // PRINCIPAL I/O DEVICE INDICATOR
|
||||
#define PPTR 26 // PRINCIPAL PRINT DEVICE INDICATOR
|
||||
#define CIAD 27 // RLTV ADDR IN @STRT OF CIL ADDR
|
||||
#define ACIN 28 // AVAILABLE CARTRIDGE INDICATOR
|
||||
#define GRPH 29 // 2250 INDICATOR 2G2
|
||||
#define GCNT 30 // NO. G2250 RECORDS 2G2
|
||||
#define LOSW 31 // LOCAL-CALLS-LOCAL SWITCH 2-2
|
||||
#define X3SW 32 // SPECIAL ILS SWITCH 2-2
|
||||
#define ECNT 33 // NO. OF *EQUAT RCDS 2-4
|
||||
#define ANDU 35 // 1+BLK ADDR END OF UA (ADJUSTED)
|
||||
#define BNDU 40 // 1+BLK ADDR END OF UA (BASE)
|
||||
#define FPAD 45 // FILE PROTECT ADDR
|
||||
#define PCID 50 // CARTRIDGE ID, PHYSICAL DRIVE
|
||||
#define CIDN 55 // CARTRIDGE ID, LOGICAL DRIVE
|
||||
#define CIBA 60 // SCTR ADDR OF CIB
|
||||
#define SCRA 65 // SCTR ADDR OF SCRA
|
||||
#define FMAT 70 // FORMAT OF PROG IN WORKING STG
|
||||
#define FLET 75 // SCTR ADDR 1ST SCTR OF FLET
|
||||
#define ULET 80 // SCTR ADDR 1ST SCTR OF LET
|
||||
#define WSCT 85 // BLK CNT OF PROG IN WORKING STG
|
||||
#define CSHN 90 // NO. SCTRS IN CUSHION AREA
|
||||
|
||||
struct tag_dcominfo {
|
||||
char *nm;
|
||||
int offset;
|
||||
char *descr;
|
||||
} dcominfo[] = {
|
||||
"NAME", 4, "NAME OF PROGRAM/CORE LOAD",
|
||||
"DBCT", 6, "BLOCK CT OF PROGRAM/CORE LOAD",
|
||||
"FCNT", 7, "FILES SWITCH",
|
||||
"SYSC", 8, "SYSTEM/NON-SYSTEM CARTRIDGE INDR",
|
||||
"JBSW", 9, "JOBT SWITCH",
|
||||
"CBSW", 10, "CLB-RETURN SWITCH",
|
||||
"LCNT", 11, "NO. OF LOCALS",
|
||||
"MPSW", 12, "CORE MAP SWITCH",
|
||||
"MDF1", 13, "NO. DUP CTRL RECORDS (MODIF)",
|
||||
"MDF2", 14, "ADDR OF MODIF BUFFER",
|
||||
"NCNT", 15, "NO. OF NOCALS",
|
||||
"ENTY", 16, "RLTV ENTRY ADDR OF PROGRAM",
|
||||
"RP67", 17, "1442-5 SWITCH",
|
||||
"TODR", 18, "OBJECT WORK STORAGE DRIVE CODE",
|
||||
"FHOL", 20, "ADDR LARGEST HOLE IN FIXED AREA",
|
||||
"FSZE", 21, "BLK CNT LARGEST HOLE IN FXA",
|
||||
"UHOL", 22, "ADDR LAST HOLE IN USER AREA",
|
||||
"USZE", 23, "BLK CNT LAST HOLE IN UA",
|
||||
"DCSW", 24, "DUP CALL SWITCH",
|
||||
"PIOD", 25, "PRINCIPAL I/O DEVICE INDICATOR",
|
||||
"PPTR", 26, "PRINCIPAL PRINT DEVICE INDICATOR",
|
||||
"CIAD", 27, "RLTV ADDR IN @STRT OF CIL ADDR",
|
||||
"ACIN", 28, "AVAILABLE CARTRIDGE INDICATOR",
|
||||
"GRPH", 29, "2250 INDICATOR",
|
||||
"GCNT", 30, "NO. G2250 RECORDS",
|
||||
"LOSW", 31, "LOCAL-CALLS-LOCAL SWITCH",
|
||||
"X3SW", 32, "SPECIAL ILS SWITCH",
|
||||
"ECNT", 33, "NO. OF *EQUAT RCDS",
|
||||
"ANDU", 35, "1+BLK ADDR END OF UA (ADJUSTED)",
|
||||
"BNDU", 40, "1+BLK ADDR END OF UA (BASE)",
|
||||
"FPAD", 45, "FILE PROTECT ADDR",
|
||||
"PCID", 50, "CARTRIDGE ID, PHYSICAL DRIVE",
|
||||
"CIDN", 55, "CARTRIDGE ID, LOGICAL DRIVE",
|
||||
"CIBA", 60, "SCTR ADDR OF CIB",
|
||||
"SCRA", 65, "SCTR ADDR OF SCRA",
|
||||
"FMAT", 70, "FORMAT OF PROG IN WORKING STG",
|
||||
"FLET", 75, "SCTR ADDR 1ST SCTR OF FLET",
|
||||
"ULET", 80, "SCTR ADDR 1ST SCTR OF LET",
|
||||
"WSCT", 85, "BLK CNT OF PROG IN WORKING STG",
|
||||
"CSHN", 90, "NO. SCTRS IN CUSHION AREA",
|
||||
NULL
|
||||
};
|
||||
|
||||
void dump_dcom (void)
|
||||
{
|
||||
struct tag_dcominfo *d;
|
||||
char txt[50];
|
||||
|
||||
showmajor("Sector 1 - DCOM");
|
||||
getsector(1, dcom);
|
||||
|
||||
for (d = dcominfo; d->nm != NULL; d++) {
|
||||
sprintf(txt, "%-4.4s %s", d->nm, d->descr);
|
||||
pbf(txt, dcom+d->offset, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_resmon (void)
|
||||
{
|
||||
showmajor("Sector 2 - Resident Image");
|
||||
getsector(2, buf);
|
||||
dump(verbose ? SECLEN : 32);
|
||||
}
|
||||
|
||||
struct {
|
||||
int pfrom, pto;
|
||||
int printed;
|
||||
char *name;
|
||||
} sletinfo[] = {
|
||||
0x01, 0x12, FALSE, "DUP",
|
||||
0x1F, 0x39, FALSE, "Fortran",
|
||||
0x51, 0x5C, FALSE, "Cobol",
|
||||
0x6E, 0x74, FALSE, "Supervisor",
|
||||
0x78, 0x84, FALSE, "Core Load Builder",
|
||||
0x8C, 0x8C, FALSE, "Sys 1403 prt",
|
||||
0x8D, 0x8D, FALSE, "Sys 1132 prt",
|
||||
0x8E, 0x8E, FALSE, "Sys console prt",
|
||||
0x8F, 0x8F, FALSE, "Sys 2501 rdr",
|
||||
0x90, 0x90, FALSE, "Sys 1442 rdr/pun",
|
||||
0x91, 0x91, FALSE, "Sys 1134 paper tape",
|
||||
0x92, 0x92, FALSE, "Sys kbd",
|
||||
0x93, 0x93, FALSE, "Sys 2501/1442 conv",
|
||||
0x94, 0x94, FALSE, "Sys 1134 conv",
|
||||
0x95, 0x95, FALSE, "Sys kbd conv",
|
||||
0x96, 0x96, FALSE, "Sys diskz",
|
||||
0x97, 0x97, FALSE, "Sys disk1",
|
||||
0x98, 0x98, FALSE, "Sys diskn",
|
||||
0x99, 0x99, FALSE, "(primary print)",
|
||||
0x9A, 0x9A, FALSE, "(primary input)",
|
||||
0x9B, 0x9B, FALSE, "(primary input excl kbd)",
|
||||
0x9C, 0x9C, FALSE, "(primary sys conv)",
|
||||
0x9D, 0x9D, FALSE, "(primary conv excl kbd)",
|
||||
0xA0, 0xA1, FALSE, "Core Image Loader",
|
||||
0xB0, 0xCC, FALSE, "RPG",
|
||||
0xCD, 0xCE, FALSE, "Dup Part 2",
|
||||
0xCF, 0xF6, FALSE, "Macro Assembler",
|
||||
0
|
||||
};
|
||||
|
||||
void dump_slet (void)
|
||||
{
|
||||
int i, j, iphase, nsecs, sec, max_sec = 0;
|
||||
char sstr[16], *smark;
|
||||
|
||||
showmajor("Sectors 3-5 - SLET");
|
||||
for (i = 0; i < 3; i++) {
|
||||
getsector(3+i, buf);
|
||||
memmove(((WORD *) slet)+SECLEN*i, buf, SECLEN*sizeof(WORD));
|
||||
}
|
||||
|
||||
printf("# PHID Addr Len Sector Secs\n");
|
||||
printf("------------------------------------------\n");
|
||||
for (i = 0; i < SLETLEN; i++) {
|
||||
if (slet[i].phid == 0)
|
||||
break;
|
||||
|
||||
sec = slet[i].sector;
|
||||
iphase = (int) (signed short) slet[i].phid;
|
||||
nsecs = (slet[i].nwords + SECLEN-1)/SECLEN;
|
||||
|
||||
if (sec & 0xF800) {
|
||||
smark = "*";
|
||||
sec &= 0x7FF;
|
||||
}
|
||||
else
|
||||
smark = " ";
|
||||
|
||||
for (j = 0; sletinfo[j].pfrom != 0; j++)
|
||||
if (sletinfo[j].pfrom <= iphase && sletinfo[j].pto >= iphase)
|
||||
break;
|
||||
|
||||
sprintf(sstr, "(%d.%d)", sec / DSK_SECCYL, slet[i].sector % DSK_SECCYL);
|
||||
|
||||
printf("%3d %04x %4d %04x %04x %04x %s %-7s %3x",
|
||||
i, slet[i].phid, iphase, slet[i].addr, slet[i].nwords, slet[i].sector, smark, sstr, nsecs);
|
||||
|
||||
if (iphase < 0)
|
||||
iphase = -iphase;
|
||||
|
||||
if (sletinfo[j].pfrom == 0)
|
||||
printf(" ???");
|
||||
else if (! sletinfo[j].printed) {
|
||||
printf(" %s", sletinfo[j].name);
|
||||
sletinfo[j].printed = TRUE;
|
||||
}
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (sec == (slet[j].sector & 0x7FF)) {
|
||||
printf(" (same as %04x)", slet[j].phid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
max_sec = MAX(max_sec, sec+nsecs-1); // find last sector used
|
||||
|
||||
putchar('\n');
|
||||
|
||||
if (i >= 15 && ! verbose) {
|
||||
printf("...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ascii_to_ebcdic_table[128] =
|
||||
{
|
||||
0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
|
||||
0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
|
||||
0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
|
||||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
|
||||
|
||||
0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
|
||||
0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d,
|
||||
0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
|
||||
0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
|
||||
};
|
||||
|
||||
int ebcdic_to_ascii (int ch)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 32; j < 128; j++)
|
||||
if (ascii_to_ebcdic_table[j] == ch)
|
||||
return j;
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
#define HDR_LEN 120
|
||||
|
||||
void dump_hdng(void)
|
||||
{
|
||||
int i;
|
||||
char str[HDR_LEN+1], *p = str;
|
||||
|
||||
showmajor("Sector 7 - Heading");
|
||||
getsector(7, buf);
|
||||
|
||||
for (i = 0; i < (HDR_LEN/2); i++) {
|
||||
*p++ = ebcdic_to_ascii((buf[i] >> 8) & 0xFF);
|
||||
*p++ = ebcdic_to_ascii( buf[i] & 0xFF);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
trim(str);
|
||||
printf("%s\n", str);
|
||||
}
|
||||
|
||||
BOOL mget (int offset, char *name)
|
||||
{
|
||||
char title[80];
|
||||
|
||||
if (dcom[offset] == 0)
|
||||
return FALSE;
|
||||
|
||||
getsector(dcom[offset], buf);
|
||||
sprintf(title, "Sector %x - %s", dcom[offset], name);
|
||||
showmajor(title);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void dump_scra (void)
|
||||
{
|
||||
if (! mget(SCRA, "SCRA"))
|
||||
return;
|
||||
|
||||
dump(verbose ? SECLEN : 32);
|
||||
}
|
||||
|
||||
void dump_let (void)
|
||||
{
|
||||
if (! mget(ULET, "LET"))
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_flet (void)
|
||||
{
|
||||
if (! mget(FLET, "FLET"))
|
||||
return;
|
||||
}
|
||||
|
||||
void dump_cib (void)
|
||||
{
|
||||
if (! mget(CIBA, "CIB"))
|
||||
return;
|
||||
|
||||
dump(verbose ? SECLEN : 32);
|
||||
}
|
||||
|
||||
#define LFHD 5 // WORD COUNT OF LET/FLET HEADER PMN09970
|
||||
#define LFEN 3 // NO OF WDS PER LET/FLET ENTRY PMN09980
|
||||
#define SCTN 0 // RLTY ADDR OF LET/FLET SCTR NO. PMN09990
|
||||
#define UAFX 1 // RLTV ADDR OF SCTR ADDR OF UA/FXA PMN10000
|
||||
#define WDSA 3 // RLTV ADDR OF WDS AVAIL IN SCTR PMN10010
|
||||
#define NEXT 4 // RLTV ADDR OF ADDR NEXT SCTR PMN10020
|
||||
#define LFNM 0 // RLTV ADDR OF LET/FLET ENTRY NAME PMN10030
|
||||
#define BLCT 2 // RLTV ADDR OF LET/FLET ENTRY DBCT PMN10040
|
||||
|
||||
void bail (char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
fprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
putchar('\n');
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// trim - remove trailing whitespace from string s
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
char *trim (char *s)
|
||||
{
|
||||
char *os = s, *nb;
|
||||
|
||||
for (nb = s-1; *s; s++)
|
||||
if (*s > ' ')
|
||||
nb = s;
|
||||
|
||||
nb[1] = '\0';
|
||||
return os;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* lowcase - force a string to lowercase (ASCII)
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
char *lowcase (char *str)
|
||||
{
|
||||
char *s;
|
||||
|
||||
for (s = str; *s; s++) {
|
||||
if (*s >= 'A' && *s <= 'Z')
|
||||
*s += 32;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "diskview.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/diskview.sbr \
|
||||
$(INTDIR)/util_io.sbr
|
||||
|
||||
$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
|
||||
/INCREMENTAL:no /PDB:$(OUTDIR)/"diskview.pdb" /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"diskview.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/diskview.obj \
|
||||
$(INTDIR)/util_io.obj
|
||||
|
||||
$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/\
|
||||
/Fd$(OUTDIR)/"diskview.pdb" /c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/diskview.sbr \
|
||||
$(INTDIR)/util_io.sbr
|
||||
|
||||
$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
|
||||
/INCREMENTAL:yes /PDB:$(OUTDIR)/"diskview.pdb" /DEBUG /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"diskview.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/diskview.obj \
|
||||
$(INTDIR)/util_io.obj
|
||||
|
||||
$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\diskview.c
|
||||
|
||||
$(INTDIR)/diskview.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util_io.c
|
||||
DEP_UTIL_=\
|
||||
.\util_io.h
|
||||
|
||||
$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
@@ -1,705 +0,0 @@
|
||||
/*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// MKBOOT - reads card loader format cards and produces an absolute core image that
|
||||
// can then be dumped out in 1130 IPL, 1800 IPL or Core Image loader formats.
|
||||
//
|
||||
// Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]"
|
||||
//
|
||||
// Arguments:
|
||||
// binfile - name of assembler output file (card loader format, absolute output)
|
||||
// outfile - name of output file to create
|
||||
// mode - output mode, default is 1130 IPL format
|
||||
// loaddr - low address to dump. Default is lowest address loaded from binfile
|
||||
// hiaddr - high address to dump. Defult is highest address loaded from binfile
|
||||
// ident - ident string to write in last 8 columns. Omit when when writing an
|
||||
// 1130 IPL card that requires all 80 columns of data.
|
||||
//
|
||||
// Examples:
|
||||
// mkboot somefile.bin somefile.ipl 1130
|
||||
//
|
||||
// loads somefile.bin, writes object in 1130 IPL format to somefile.ipl
|
||||
// Up to 80 columns will be written depending on what the object actually uses
|
||||
//
|
||||
// mkboot somefile.bin somefile.ipl 1130 0 48 SOMEF
|
||||
//
|
||||
// loads somefile.bin. Writes 72 columns (hex 48), with ident columns 73-80 = SOMEF001
|
||||
//
|
||||
// mkboot somefile.bin somefile.dat core 0 0 SOMEF001
|
||||
//
|
||||
// loads somefile.bin and writes a core image format deck with ident SOMEF001, SOMEF002, etc
|
||||
//
|
||||
// For other examples of usage, see MKDMS.BAT
|
||||
//
|
||||
// 1.00 - 2002Apr18 - first release. Tested only under Win32. The core image
|
||||
// loader format is almost certainly wrong. Cannot handle
|
||||
// relocatable input decks, but it works well enough to
|
||||
// load DSYSLDR1 which is what we are after here.
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define BOOL int
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
int strnicmp (char *a, char *b, int n);
|
||||
int strcmpi (char *a, char *b);
|
||||
#endif
|
||||
|
||||
#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b)))
|
||||
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
|
||||
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
|
||||
|
||||
#define MAXADDR 4096
|
||||
|
||||
typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC;
|
||||
|
||||
typedef enum {B_1130, B_1800, B_CORE} BOOTMODE;
|
||||
|
||||
BOOL verbose = FALSE;
|
||||
char *infile = NULL, *outfile = NULL;
|
||||
BOOTMODE mode = B_1130;
|
||||
int addr_from = 0, addr_to = 79;
|
||||
int outcols = 0; // columns written in using card output
|
||||
int maxiplcols = 80;
|
||||
char cardid[9]; // characters used for IPL card ID
|
||||
int pta = 0;
|
||||
int load_low = 0x7FFFFFF;
|
||||
int load_high = 0;
|
||||
unsigned short mem[MAXADDR]; // small core!
|
||||
|
||||
// mkboot - load a binary object deck into core and dump requested bytes as a boot card
|
||||
|
||||
void bail (char *msg);
|
||||
void verify_checksum(unsigned short *card);
|
||||
char *upcase (char *str);
|
||||
void unpack (unsigned short *card, unsigned short *buf);
|
||||
void dump (char *fname);
|
||||
void loaddata (char *fname);
|
||||
void write_1130 (void);
|
||||
void write_1800 (void);
|
||||
void write_core (void);
|
||||
void flushcard(void);
|
||||
int ascii_to_hollerith (int ch);
|
||||
void corecard_init (void);
|
||||
void corecard_writecard (char *sbrk_text);
|
||||
void corecard_writedata (void);
|
||||
void corecard_flush (void);
|
||||
void corecard_setorg (int neworg);
|
||||
void corecard_writew (int word, RELOC relative);
|
||||
void corecard_endcard (void);
|
||||
|
||||
char *fname = NULL;
|
||||
FILE *fout;
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
char *arg;
|
||||
static char usestr[] = "Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]";
|
||||
int i, ano = 0, ok;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
arg = argv[i];
|
||||
if (*arg == '-') {
|
||||
arg++;
|
||||
while (*arg) {
|
||||
switch (*arg++) {
|
||||
case 'v':
|
||||
verbose = TRUE;
|
||||
break;
|
||||
default:
|
||||
bail(usestr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (ano++) {
|
||||
case 0:
|
||||
infile = arg;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
outfile = arg;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (strcmp(arg, "1130") == 0) mode = B_1130;
|
||||
else if (strcmp(arg, "1800") == 0) mode = B_1800;
|
||||
else if (strcmpi(arg, "core") == 0) mode = B_CORE;
|
||||
else bail(usestr);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_from);
|
||||
else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_from);
|
||||
else ok = sscanf(arg, "%d", &addr_from);
|
||||
if (ok != 1) bail(usestr);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_to);
|
||||
else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_to);
|
||||
else ok = sscanf(arg, "%d", &addr_to);
|
||||
if (ok != 1) bail(usestr);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
strncpy(cardid, arg, 9);
|
||||
cardid[8] = '\0';
|
||||
upcase(cardid);
|
||||
break;
|
||||
|
||||
default:
|
||||
bail(usestr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*cardid == '\0')
|
||||
maxiplcols = (mode == B_1130) ? 80 : 72;
|
||||
else {
|
||||
while (strlen(cardid) < 8)
|
||||
strcat(cardid, "0");
|
||||
maxiplcols = 72;
|
||||
}
|
||||
|
||||
loaddata(infile);
|
||||
|
||||
if (mode == B_1800)
|
||||
write_1800();
|
||||
else if (mode == B_CORE)
|
||||
write_core();
|
||||
else
|
||||
write_1130();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_1130 (void)
|
||||
{
|
||||
int addr;
|
||||
unsigned short word;
|
||||
|
||||
if ((fout = fopen(outfile, "wb")) == NULL) {
|
||||
perror(outfile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (addr = addr_from; addr <= addr_to; addr++) {
|
||||
if (outcols >= maxiplcols)
|
||||
flushcard();
|
||||
|
||||
word = mem[addr];
|
||||
|
||||
// if F or L bits are set, or if high 2 bits of displacement are unequal, it's bad
|
||||
if ((word & 0x0700) || ! (((word & 0x00C0) == 0) || ((word & 0x00C0) == 0x00C0)))
|
||||
printf("Warning: word %04x @ %04x may not IPL properly\n", word & 0xFFFF, addr);
|
||||
|
||||
word = ((word & 0xF800) >> 4) | (word & 0x7F); // convert to 1130 IPL format
|
||||
|
||||
putc((word & 0x000F) << 4, fout); // write the 12 bits in little-endian binary AABBCC00 as CC00 AABB
|
||||
putc((word & 0x0FF0) >> 4, fout);
|
||||
outcols++;
|
||||
}
|
||||
flushcard();
|
||||
fclose(fout);
|
||||
}
|
||||
|
||||
void write_1800 (void)
|
||||
{
|
||||
int addr;
|
||||
unsigned short word;
|
||||
|
||||
if ((fout = fopen(outfile, "wb")) == NULL) {
|
||||
perror(outfile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (addr = addr_from; addr <= addr_to; addr++) {
|
||||
word = mem[addr];
|
||||
|
||||
if (outcols >= maxiplcols)
|
||||
flushcard();
|
||||
|
||||
putc(0, fout);
|
||||
putc(word & 0xFF, fout); // write the low 8 bits in little-endian binary
|
||||
outcols++;
|
||||
|
||||
putc(0, fout);
|
||||
putc((word >> 8) & 0xFF, fout); // write the high 8 bits in little-endian binary
|
||||
outcols++;
|
||||
}
|
||||
flushcard();
|
||||
fclose(fout);
|
||||
}
|
||||
|
||||
void write_core (void)
|
||||
{
|
||||
int addr;
|
||||
|
||||
if ((fout = fopen(outfile, "wb")) == NULL) {
|
||||
perror(outfile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
addr_from = load_low;
|
||||
addr_to = load_high;
|
||||
|
||||
maxiplcols = 72;
|
||||
corecard_init();
|
||||
corecard_setorg(addr_from);
|
||||
|
||||
for (addr = addr_from; addr <= addr_to; addr++) {
|
||||
corecard_writew(mem[addr], 0);
|
||||
}
|
||||
|
||||
corecard_flush();
|
||||
corecard_endcard();
|
||||
fclose(fout);
|
||||
}
|
||||
|
||||
void flushcard (void)
|
||||
{
|
||||
int i, hol, ndig;
|
||||
char fmt[20], newdig[20];
|
||||
|
||||
if (outcols <= 0)
|
||||
return; // nothing to flush
|
||||
|
||||
while (outcols < maxiplcols) { // pad to required number of columns with blanks (no punches)
|
||||
putc(0, fout);
|
||||
putc(0, fout);
|
||||
outcols++;
|
||||
}
|
||||
|
||||
if (*cardid) { // add label
|
||||
for (i = 0; i < 8; i++) { // write label as specified
|
||||
hol = ascii_to_hollerith(cardid[i] & 0x7F);
|
||||
putc(hol & 0xFF, fout);
|
||||
putc((hol >> 8) & 0xFF, fout);
|
||||
}
|
||||
|
||||
ndig = 0; // count trailing digits in the label
|
||||
for (i = 8; --i >= 0; ndig++)
|
||||
if (! isdigit(cardid[i]))
|
||||
break;
|
||||
|
||||
i++; // index of first digit in trailing sequence
|
||||
|
||||
if (ndig > 0) { // if any, increment them
|
||||
sprintf(fmt, "%%0%dd", ndig); // make, e.g. %03d
|
||||
sprintf(newdig, fmt, atoi(cardid+i)+1);
|
||||
newdig[ndig] = '\0'; // clip if necessary
|
||||
strcpy(cardid+i, newdig); // replace for next card's sequence number
|
||||
}
|
||||
}
|
||||
|
||||
outcols = 0;
|
||||
}
|
||||
|
||||
void show_data (unsigned short *buf)
|
||||
{
|
||||
int i, n, jrel, rflag, nout, ch, reloc;
|
||||
|
||||
n = buf[2] & 0x00FF;
|
||||
|
||||
printf("%04x: ", buf[0]);
|
||||
|
||||
jrel = 3;
|
||||
nout = 0;
|
||||
rflag = buf[jrel++];
|
||||
for (i = 0; i < n; i++) {
|
||||
if (nout >= 8) {
|
||||
rflag = buf[jrel++];
|
||||
putchar('\n');
|
||||
printf(" ");
|
||||
nout = 0;
|
||||
}
|
||||
reloc = (rflag >> 14) & 0x03;
|
||||
ch = (reloc == R_ABSOLUTE) ? ' ' :
|
||||
(reloc == R_RELATIVE) ? 'R' :
|
||||
(reloc == R_LIBF) ? 'L' : '@';
|
||||
|
||||
printf("%04x%c ", buf[9+i], ch);
|
||||
rflag <<= 2;
|
||||
nout++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void loadcard (unsigned short *buf)
|
||||
{
|
||||
int addr, n, i;
|
||||
|
||||
addr = buf[0];
|
||||
n = buf[2] & 0x00FF;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (addr >= MAXADDR)
|
||||
bail("Program doesn't fit into 4K");
|
||||
mem[addr] = buf[9+i];
|
||||
|
||||
load_low = MIN(addr, load_low);
|
||||
load_high = MAX(addr, load_high);
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
void loaddata (char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
BOOL first = TRUE;
|
||||
unsigned short card[80], buf[54], cardtype;
|
||||
|
||||
if ((fp = fopen(fname, "rb")) == NULL) {
|
||||
perror(fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("\n%s:\n", fname);
|
||||
|
||||
while (fread(card, sizeof(card[0]), 80, fp) > 0) {
|
||||
unpack(card, buf);
|
||||
verify_checksum(card);
|
||||
|
||||
cardtype = (buf[2] >> 8) & 0xFF;
|
||||
|
||||
if (cardtype == 1 && ! first) { // sector break
|
||||
if (verbose)
|
||||
printf("*SBRK\n");
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
switch (cardtype) {
|
||||
case 0x01:
|
||||
if (verbose)
|
||||
printf("*ABS\n");
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
bail("Data must be in absolute format");
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
pta = buf[3]; // save program transfer address
|
||||
if (verbose)
|
||||
printf("*END\n");
|
||||
break;
|
||||
|
||||
case 0x0A:
|
||||
if (verbose)
|
||||
show_data(buf);
|
||||
loadcard(buf);
|
||||
break;
|
||||
default:
|
||||
bail("Unexpected card type");
|
||||
}
|
||||
}
|
||||
first = FALSE;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void bail (char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void unpack (unsigned short *card, unsigned short *buf)
|
||||
{
|
||||
int i, j;
|
||||
unsigned short wd1, wd2, wd3, wd4;
|
||||
|
||||
for (i = j = 0; i < 54; i += 3, j += 4) {
|
||||
wd1 = card[j];
|
||||
wd2 = card[j+1];
|
||||
wd3 = card[j+2];
|
||||
wd4 = card[j+3];
|
||||
|
||||
buf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F);
|
||||
buf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF);
|
||||
buf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF);
|
||||
}
|
||||
}
|
||||
|
||||
void verify_checksum (unsigned short *card)
|
||||
{
|
||||
// unsigned short sum;
|
||||
|
||||
if (card[1] == 0) // no checksum
|
||||
return;
|
||||
|
||||
// if (sum != card[1])
|
||||
// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int hollerith;
|
||||
char ascii;
|
||||
} CPCODE;
|
||||
|
||||
static CPCODE cardcode_029[] =
|
||||
{
|
||||
0x0000, ' ',
|
||||
0x8000, '&', // + in 026 Fortran
|
||||
0x4000, '-',
|
||||
0x2000, '0',
|
||||
0x1000, '1',
|
||||
0x0800, '2',
|
||||
0x0400, '3',
|
||||
0x0200, '4',
|
||||
0x0100, '5',
|
||||
0x0080, '6',
|
||||
0x0040, '7',
|
||||
0x0020, '8',
|
||||
0x0010, '9',
|
||||
0x9000, 'A',
|
||||
0x8800, 'B',
|
||||
0x8400, 'C',
|
||||
0x8200, 'D',
|
||||
0x8100, 'E',
|
||||
0x8080, 'F',
|
||||
0x8040, 'G',
|
||||
0x8020, 'H',
|
||||
0x8010, 'I',
|
||||
0x5000, 'J',
|
||||
0x4800, 'K',
|
||||
0x4400, 'L',
|
||||
0x4200, 'M',
|
||||
0x4100, 'N',
|
||||
0x4080, 'O',
|
||||
0x4040, 'P',
|
||||
0x4020, 'Q',
|
||||
0x4010, 'R',
|
||||
0x3000, '/',
|
||||
0x2800, 'S',
|
||||
0x2400, 'T',
|
||||
0x2200, 'U',
|
||||
0x2100, 'V',
|
||||
0x2080, 'W',
|
||||
0x2040, 'X',
|
||||
0x2020, 'Y',
|
||||
0x2010, 'Z',
|
||||
0x0820, ':',
|
||||
0x0420, '#', // = in 026 Fortran
|
||||
0x0220, '@', // ' in 026 Fortran
|
||||
0x0120, '\'',
|
||||
0x00A0, '=',
|
||||
0x0060, '"',
|
||||
0x8820, 'c', // cent
|
||||
0x8420, '.',
|
||||
0x8220, '<', // ) in 026 Fortran
|
||||
0x8120, '(',
|
||||
0x80A0, '+',
|
||||
0x8060, '|',
|
||||
0x4820, '!',
|
||||
0x4420, '$',
|
||||
0x4220, '*',
|
||||
0x4120, ')',
|
||||
0x40A0, ';',
|
||||
0x4060, 'n', // not
|
||||
0x2820, 'x', // what?
|
||||
0x2420, ',',
|
||||
0x2220, '%', // ( in 026 Fortran
|
||||
0x2120, '_',
|
||||
0x20A0, '>',
|
||||
0x2060, '>',
|
||||
};
|
||||
|
||||
int ascii_to_hollerith (int ch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)
|
||||
if (cardcode_029[i].ascii == ch)
|
||||
return cardcode_029[i].hollerith;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// corecard - routines to write IBM 1130 Card object format
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
unsigned short corecard[54]; // the 54 data words that can fit on a binary format card
|
||||
int corecard_n = 0; // number of object words stored in corecard (0-45)
|
||||
int corecard_seq = 1; // card output sequence number
|
||||
int corecard_org = 0; // origin of current card-full
|
||||
int corecard_maxaddr = 0;
|
||||
BOOL corecard_first = TRUE; // TRUE when we're to write the program type card
|
||||
|
||||
// corecard_init - prepare a new object data output card
|
||||
|
||||
void corecard_init (void)
|
||||
{
|
||||
memset(corecard, 0, sizeof(corecard)); // clear card data
|
||||
corecard_n = 0; // no data
|
||||
corecard[0] = corecard_org; // store load address
|
||||
corecard_maxaddr = MAX(corecard_maxaddr, corecard_org-1); // save highest address written-to (this may be a BSS)
|
||||
}
|
||||
|
||||
// binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card
|
||||
|
||||
void corecard_writecard (char *sbrk_text)
|
||||
{
|
||||
unsigned short binout[80];
|
||||
int i, j;
|
||||
|
||||
for (i = j = 0; i < 54; i += 3, j += 4) {
|
||||
binout[j ] = ( corecard[i] & 0xFFF0);
|
||||
binout[j+1] = ((corecard[i] << 12) & 0xF000) | ((corecard[i+1] >> 4) & 0x0FF0);
|
||||
binout[j+2] = ((corecard[i+1] << 8) & 0xFF00) | ((corecard[i+2] >> 8) & 0x00F0);
|
||||
binout[j+3] = ((corecard[i+2] << 4) & 0xFFF0);
|
||||
}
|
||||
|
||||
for (i = 0; i < 72; i++) {
|
||||
putc(binout[i] & 0xFF, fout);
|
||||
putc((binout[i] >> 8) & 0xFF, fout);
|
||||
}
|
||||
|
||||
outcols = 72; // add the ident
|
||||
flushcard();
|
||||
}
|
||||
|
||||
// binard_writedata - emit an object data card
|
||||
|
||||
void corecard_writedata (void)
|
||||
{
|
||||
corecard[1] = 0; // checksum
|
||||
corecard[2] = 0x0000 | corecard_n; // data card type + word count
|
||||
corecard_writecard(FALSE); // emit the card
|
||||
}
|
||||
|
||||
// corecard_flush - flush any pending binary data
|
||||
|
||||
void corecard_flush (void)
|
||||
{
|
||||
if (corecard_n > 0)
|
||||
corecard_writedata();
|
||||
|
||||
corecard_init();
|
||||
}
|
||||
|
||||
// corecard_setorg - set the origin
|
||||
|
||||
void corecard_setorg (int neworg)
|
||||
{
|
||||
corecard_org = neworg; // set origin for next card
|
||||
corecard_flush(); // flush any current data & store origin
|
||||
}
|
||||
|
||||
// corecard_writew - write a word to the current output card.
|
||||
|
||||
void corecard_writew (int word, RELOC relative)
|
||||
{
|
||||
if (corecard_n >= 50) // flush full card buffer (must be even)
|
||||
corecard_flush();
|
||||
|
||||
corecard[3+corecard_n++] = word;
|
||||
corecard_org++;
|
||||
}
|
||||
|
||||
// corecard_endcard - write end of program card
|
||||
|
||||
void corecard_endcard (void)
|
||||
{
|
||||
corecard_flush();
|
||||
|
||||
corecard[0] = 0; // effective length: add 1 to max origin, then 1 more to round up
|
||||
corecard[1] = 0;
|
||||
corecard[2] = 0x8000; // they look for negative bit but all else must be zero
|
||||
corecard[52] = 0xabcd; // index register 3 value, this is for fun
|
||||
corecard[53] = pta; // hmmm
|
||||
|
||||
corecard_writecard(NULL);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* upcase - force a string to uppercase (ASCII)
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
char *upcase (char *str)
|
||||
{
|
||||
char *s;
|
||||
|
||||
for (s = str; *s; s++) {
|
||||
if (*s >= 'a' && *s <= 'z')
|
||||
*s -= 32;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
int strnicmp (char *a, char *b, int n)
|
||||
{
|
||||
int ca, cb;
|
||||
|
||||
for (;;) {
|
||||
if (--n < 0) // still equal after n characters? quit now
|
||||
return 0;
|
||||
|
||||
if ((ca = *a) == 0) // get character, stop on null terminator
|
||||
return *b ? -1 : 0;
|
||||
|
||||
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
|
||||
ca -= 32;
|
||||
|
||||
cb = *b;
|
||||
if (cb >= 'a' && cb <= 'z')
|
||||
cb -= 32;
|
||||
|
||||
if ((ca -= cb) != 0) // if different, return comparison
|
||||
return ca;
|
||||
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
||||
int strcmpi (char *a, char *b)
|
||||
{
|
||||
int ca, cb;
|
||||
|
||||
for (;;) {
|
||||
if ((ca = *a) == 0) // get character, stop on null terminator
|
||||
return *b ? -1 : 0;
|
||||
|
||||
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
|
||||
ca -= 32;
|
||||
|
||||
cb = *b;
|
||||
if (cb >= 'a' && cb <= 'z')
|
||||
cb -= 32;
|
||||
|
||||
if ((ca -= cb) != 0) // if different, return comparison
|
||||
return ca;
|
||||
|
||||
a++, b++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,161 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "mkboot.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
# PROP Target_Last_Scanned "Win32 Debug"
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/mkboot.sbr
|
||||
|
||||
$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
|
||||
/INCREMENTAL:no /PDB:$(OUTDIR)/"mkboot.pdb" /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"mkboot.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/mkboot.obj
|
||||
|
||||
$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"mkboot.pdb"\
|
||||
/c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/mkboot.sbr
|
||||
|
||||
$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\
|
||||
/INCREMENTAL:yes /PDB:$(OUTDIR)/"mkboot.pdb" /DEBUG /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"mkboot.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/mkboot.obj
|
||||
|
||||
$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mkboot.c
|
||||
|
||||
$(INTDIR)/mkboot.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
@@ -1,242 +0,0 @@
|
||||
/* Simple program to display a binary card-image file in ASCII.
|
||||
* We assume the deck was written with one card per 16-bit word, left-justified,
|
||||
* and written in PC little-endian order
|
||||
*
|
||||
* (C) Copyright 2002, Brian Knittel.
|
||||
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
|
||||
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
|
||||
* usual yada-yada. Please keep this notice and the copyright in any distributions
|
||||
* or modifications.
|
||||
*
|
||||
* This is not a supported product, but I welcome bug reports and fixes.
|
||||
* Mail to sim@ibm1130.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
typedef int BOOL;
|
||||
|
||||
int hollerith_to_ascii (unsigned short h);
|
||||
void bail (char *msg);
|
||||
void format_coldstart (unsigned short *buf);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
FILE *fd;
|
||||
char *fname = NULL, line[82], *arg;
|
||||
BOOL coldstart = FALSE;
|
||||
unsigned short buf[80];
|
||||
int i, lastnb;
|
||||
static char usestr[] =
|
||||
"Usage: viewdeck [-c] deckfile\n"
|
||||
"\n"
|
||||
"-c: convert cold start card to 16-bit format as a C array initializer\n";
|
||||
|
||||
for (i = 1; i < argc; i++) { // process command line arguments
|
||||
arg = argv[i];
|
||||
|
||||
if (*arg == '-') {
|
||||
arg++;
|
||||
while (*arg) {
|
||||
switch (*arg++) {
|
||||
case 'c':
|
||||
coldstart = TRUE;
|
||||
break;
|
||||
default:
|
||||
bail(usestr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fname == NULL) // first non-switch arg is file name
|
||||
fname = arg;
|
||||
else
|
||||
bail(usestr); // there can be only one name
|
||||
}
|
||||
|
||||
if (fname == NULL) // there must be a name
|
||||
bail(usestr);
|
||||
|
||||
if ((fd = fopen(fname, "rb")) == NULL) {
|
||||
perror(fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (fread(buf, sizeof(short), 80, fd) == 80) {
|
||||
if (coldstart) {
|
||||
format_coldstart(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
lastnb = -1;
|
||||
for (i = 0; i < 80; i++) {
|
||||
line[i] = hollerith_to_ascii(buf[i]);
|
||||
if (line[i] > ' ')
|
||||
lastnb = i;
|
||||
}
|
||||
line[++lastnb] = '\n';
|
||||
line[++lastnb] = '\0';
|
||||
fputs(line, stdout);
|
||||
}
|
||||
|
||||
if (coldstart) {
|
||||
if (fread(buf, sizeof(short), 1, fd) == 1)
|
||||
bail("Coldstart deck has more than one card");
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void format_coldstart (unsigned short *buf)
|
||||
{
|
||||
int i, nout = 0;
|
||||
unsigned short word;
|
||||
|
||||
for (i = 0; i < 80; i++) {
|
||||
word = buf[i]; // expand 12-bit card data to 16-bit instruction
|
||||
word = (word & 0xF800) | ((word & 0x0400) ? 0x00C0 : 0x0000) | ((word & 0x03F0) >> 4);
|
||||
|
||||
if (nout >= 8) {
|
||||
fputs(",\n", stdout);
|
||||
nout = 0;
|
||||
}
|
||||
else if (i > 0)
|
||||
fputs(", ", stdout);
|
||||
|
||||
printf("0x%04x", word);
|
||||
nout++;
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned short hollerith;
|
||||
char ascii;
|
||||
} CPCODE;
|
||||
|
||||
static CPCODE cardcode_029[] =
|
||||
{
|
||||
0x0000, ' ',
|
||||
0x8000, '&', // + in 026 Fortran
|
||||
0x4000, '-',
|
||||
0x2000, '0',
|
||||
0x1000, '1',
|
||||
0x0800, '2',
|
||||
0x0400, '3',
|
||||
0x0200, '4',
|
||||
0x0100, '5',
|
||||
0x0080, '6',
|
||||
0x0040, '7',
|
||||
0x0020, '8',
|
||||
0x0010, '9',
|
||||
0x9000, 'A',
|
||||
0x8800, 'B',
|
||||
0x8400, 'C',
|
||||
0x8200, 'D',
|
||||
0x8100, 'E',
|
||||
0x8080, 'F',
|
||||
0x8040, 'G',
|
||||
0x8020, 'H',
|
||||
0x8010, 'I',
|
||||
0x5000, 'J',
|
||||
0x4800, 'K',
|
||||
0x4400, 'L',
|
||||
0x4200, 'M',
|
||||
0x4100, 'N',
|
||||
0x4080, 'O',
|
||||
0x4040, 'P',
|
||||
0x4020, 'Q',
|
||||
0x4010, 'R',
|
||||
0x3000, '/',
|
||||
0x2800, 'S',
|
||||
0x2400, 'T',
|
||||
0x2200, 'U',
|
||||
0x2100, 'V',
|
||||
0x2080, 'W',
|
||||
0x2040, 'X',
|
||||
0x2020, 'Y',
|
||||
0x2010, 'Z',
|
||||
0x0820, ':',
|
||||
0x0420, '#', // = in 026 Fortran
|
||||
0x0220, '@', // ' in 026 Fortran
|
||||
0x0120, '\'',
|
||||
0x00A0, '=',
|
||||
0x0060, '"',
|
||||
0x8820, '\xA2', // cent, in MS-DOS encoding
|
||||
0x8420, '.',
|
||||
0x8220, '<', // ) in 026 Fortran
|
||||
0x8120, '(',
|
||||
0x80A0, '+',
|
||||
0x8060, '|',
|
||||
0x4820, '!',
|
||||
0x4420, '$',
|
||||
0x4220, '*',
|
||||
0x4120, ')',
|
||||
0x40A0, ';',
|
||||
0x4060, '\xAC', // not, in MS-DOS encoding
|
||||
0x2420, ',',
|
||||
0x2220, '%', // ( in 026 Fortran
|
||||
0x2120, '_',
|
||||
0x20A0, '>',
|
||||
0xB000, 'a',
|
||||
0xA800, 'b',
|
||||
0xA400, 'c',
|
||||
0xA200, 'd',
|
||||
0xA100, 'e',
|
||||
0xA080, 'f',
|
||||
0xA040, 'g',
|
||||
0xA020, 'h',
|
||||
0xA010, 'i',
|
||||
0xD000, 'j',
|
||||
0xC800, 'k',
|
||||
0xC400, 'l',
|
||||
0xC200, 'm',
|
||||
0xC100, 'n',
|
||||
0xC080, 'o',
|
||||
0xC040, 'p',
|
||||
0xC020, 'q',
|
||||
0xC010, 'r',
|
||||
0x6800, 's',
|
||||
0x6400, 't',
|
||||
0x6200, 'u',
|
||||
0x6100, 'v',
|
||||
0x6080, 'w',
|
||||
0x6040, 'x',
|
||||
0x6020, 'y',
|
||||
0x6010, 'z', // these odd punch codes are used by APL:
|
||||
0x1010, '\001', // no corresponding ASCII using ^A
|
||||
0x0810, '\002', // SYN using ^B
|
||||
0x0410, '\003', // no corresponding ASCII using ^C
|
||||
0x0210, '\004', // PUNCH ON using ^D
|
||||
0x0110, '\005', // READER STOP using ^E
|
||||
0x0090, '\006', // UPPER CASE using ^F
|
||||
0x0050, '\013', // EOT using ^K
|
||||
0x0030, '\016', // no corresponding ASCII using ^N
|
||||
0x1030, '\017', // no corresponding ASCII using ^O
|
||||
0x0830, '\020', // no corresponding ASCII using ^P
|
||||
};
|
||||
|
||||
int hollerith_to_ascii (unsigned short h)
|
||||
{
|
||||
int i;
|
||||
|
||||
h &= 0xFFF0;
|
||||
|
||||
for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)
|
||||
if (cardcode_029[i].hollerith == h)
|
||||
return cardcode_029[i].ascii;
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
void bail (char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
!IF "$(CFG)" == ""
|
||||
CFG=Win32 Debug
|
||||
!MESSAGE No configuration specified. Defaulting to Win32 Debug.
|
||||
!ENDIF
|
||||
|
||||
!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
|
||||
!MESSAGE Invalid configuration "$(CFG)" specified.
|
||||
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "viewdeck.mak" CFG="Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
!ERROR An invalid configuration is specified.
|
||||
!ENDIF
|
||||
|
||||
################################################################################
|
||||
# Begin Project
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "WinRel"
|
||||
# PROP BASE Intermediate_Dir "WinRel"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "WinRel"
|
||||
# PROP Intermediate_Dir "WinRel"
|
||||
OUTDIR=.\WinRel
|
||||
INTDIR=.\WinRel
|
||||
|
||||
ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/ /c
|
||||
CPP_OBJS=.\WinRel/
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/viewdeck.sbr
|
||||
|
||||
$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
||||
advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\
|
||||
/PDB:$(OUTDIR)/"viewdeck.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"viewdeck.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/viewdeck.obj
|
||||
|
||||
$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ELSEIF "$(CFG)" == "Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "WinDebug"
|
||||
# PROP BASE Intermediate_Dir "WinDebug"
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "WinDebug"
|
||||
# PROP Intermediate_Dir "WinDebug"
|
||||
OUTDIR=.\WinDebug
|
||||
INTDIR=.\WinDebug
|
||||
|
||||
ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc
|
||||
|
||||
$(OUTDIR) :
|
||||
if not exist $(OUTDIR)/nul mkdir $(OUTDIR)
|
||||
|
||||
# ADD BASE CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
# ADD CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
|
||||
CPP_PROJ=/nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
|
||||
/FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/\
|
||||
/Fd$(OUTDIR)/"viewdeck.pdb" /c
|
||||
CPP_OBJS=.\WinDebug/
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc"
|
||||
BSC32_SBRS= \
|
||||
$(INTDIR)/viewdeck.sbr
|
||||
|
||||
$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS)
|
||||
$(BSC32) @<<
|
||||
$(BSC32_FLAGS) $(BSC32_SBRS)
|
||||
<<
|
||||
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
|
||||
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
||||
advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\
|
||||
/PDB:$(OUTDIR)/"viewdeck.pdb" /DEBUG /MACHINE:I386\
|
||||
/OUT:$(OUTDIR)/"viewdeck.exe"
|
||||
DEF_FILE=
|
||||
LINK32_OBJS= \
|
||||
$(INTDIR)/viewdeck.obj
|
||||
|
||||
$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS)
|
||||
$(LINK32) @<<
|
||||
$(LINK32_FLAGS) $(LINK32_OBJS)
|
||||
<<
|
||||
|
||||
!ENDIF
|
||||
|
||||
.c{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cpp{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
.cxx{$(CPP_OBJS)}.obj:
|
||||
$(CPP) $(CPP_PROJ) $<
|
||||
|
||||
################################################################################
|
||||
# Begin Group "Source Files"
|
||||
|
||||
################################################################################
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\viewdeck.c
|
||||
|
||||
$(INTDIR)/viewdeck.obj : $(SOURCE) $(INTDIR)
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Project
|
||||
################################################################################
|
||||
1720
Interdata/id16_cpu.c
1720
Interdata/id16_cpu.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user