mirror of
https://github.com/open-simh/simh.git
synced 2026-05-02 22:33:04 +00:00
Notes For V2.10-0
WARNING: V2.10 has reorganized and renamed some of the definition files for the PDP-10, PDP-11, and VAX. Be sure to delete all previous source files before you unpack the Zip archive, or unpack it into a new directory structure. WARNING: V2.10 has a new, more comprehensive save file format. Restoring save files from previous releases will cause 'invalid register' errors and loss of CPU option flags, device enable/ disable flags, unit online/offline flags, and unit writelock flags. WARNING: If you are using Visual Studio .NET through the IDE, be sure to turn off the /Wp64 flag in the project settings, or dozens of spurious errors will be generated. WARNING: Compiling Ethernet support under Windows requires extra steps; see the Ethernet readme file. Ethernet support is currently available only for Windows, Linux, NetBSD, and OpenBSD. 1. New Features 1.1 SCP and Libraries - The VT emulation package has been replaced by the capability to remote the console to a Telnet session. Telnet clients typically have more complete and robust VT100 emulation. - Simulated devices may now have statically allocated buffers, in addition to dynamically allocated buffers or disk-based data stores. - The DO command now takes substitutable arguments (max 9). In command files, %n represents substitutable argument n. - The initial command line is now interpreted as the command name and substitutable arguments for a DO command. This is backward compatible to prior versions. - The initial command line parses switches. -Q is interpreted as quiet mode; informational messages are suppressed. - The HELP command now takes an optional argument. HELP <cmd> types help on the specified command. - Hooks have been added for implementing GUI-based consoles, as well as simulator-specific command extensions. A few internal data structures and definitions have changed. - Two new routines (tmxr_open_master, tmxr_close_master) have been added to sim_tmxr.c. The calling sequence for sim_accept_conn has been changed in sim_sock.c. - The calling sequence for the VM boot routine has been modified to add an additional parameter. - SAVE now saves, and GET now restores, controller and unit flags. - Library sim_ether.c has been added for Ethernet support. 1.2 VAX - Non-volatile RAM (NVR) can behave either like a memory or like a disk-based peripheral. If unattached, it behaves like memory and is saved and restored by SAVE and RESTORE, respectively. If attached, its contents are loaded from disk by ATTACH and written back to disk at DETACH and EXIT. - SHOW <device> VECTOR displays the device's interrupt vector. A few devices allow the vector to be changed with SET <device> VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The TK50 (TMSCP tape) has been added. - The DEQNA/DELQA (Qbus Ethernet controllers) have been added. - Autoconfiguration support has been added. - The paper tape reader has been removed from vax_stddev.c and now references a common implementation file, dec_pt.h. - Examine and deposit switches now work on all devices, not just the CPU. - Device address conflicts are not detected until simulation starts. 1.3 PDP-11 - SHOW <device> VECTOR displays the device's interrupt vector. Most devices allow the vector to be changed with SET <device> VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk), RX211 (double density floppy), and KW11P programmable clock have been added. - The DEQNA/DELQA (Qbus Ethernet controllers) have been added. - Autoconfiguration support has been added. - The paper tape reader has been removed from pdp11_stddev.c and now references a common implementation file, dec_pt.h. - Device bootstraps now use the actual CSR specified by the SET ADDRESS command, rather than just the default CSR. Note that PDP-11 operating systems may NOT support booting with non-standard addresses. - Specifying more than 256KB of memory, or changing the bus configuration, causes all peripherals that are not compatible with the current bus configuration to be disabled. - Device address conflicts are not detected until simulation starts. 1.4 PDP-10 - SHOW <device> VECTOR displays the device's interrupt vector. A few devices allow the vector to be changed with SET <device> VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The RX211 (double density floppy) has been added; it is off by default. - The paper tape now references a common implementation file, dec_pt.h. - Device address conflicts are not detected until simulation starts. 1.5 PDP-1 - DECtape (then known as MicroTape) support has been added. - The line printer and DECtape can be disabled and enabled. 1.6 PDP-8 - The RX28 (double density floppy) has been added as an option to the existing RX8E controller. - SHOW <device> DEVNO displays the device's device number. Most devices allow the device number to be changed with SET <device> DEVNO=nnn. - Device number conflicts are not detected until simulation starts. 1.7 IBM 1620 - The IBM 1620 simulator has been released. 1.8 AltairZ80 - A hard drive has been added for increased storage. - Several bugs have been fixed. 1.9 HP 2100 - The 12845A has been added and made the default line printer (LPT). The 12653A has been renamed LPS and is off by default. It also supports the diagnostic functions needed to run the DCPC and DMS diagnostics. - The 12557A/13210A disk defaults to the 13210A (7900/7901). - The 12559A magtape is off by default. - New CPU options (EAU/NOEAU) enable/disable the extended arithmetic instructions for the 2116. These instructions are standard on the 2100 and 21MX. - New CPU options (MPR/NOMPR) enable/disable memory protect for the 2100 and 21MX. - New CPU options (DMS/NODMS) enable/disable the dynamic mapping instructions for the 21MX. - The 12539 timebase generator autocalibrates. 1.10 Simulated Magtapes - Simulated magtapes recognize end of file and the marker 0xFFFFFFFF as end of medium. Only the TMSCP tape simulator can generate an end of medium marker. - The error handling in simulated magtapes was overhauled to be consistent through all simulators. 1.11 Simulated DECtapes - Added support for RT11 image file format (256 x 16b) to DECtapes. 2. Release Notes 2.1 Bugs Fixed - TS11/TSV05 was not simulating the XS0_MOT bit, causing failures under VMS. In addition, two of the CTL options were coded interchanged. - IBM 1401 tape was not setting a word mark under group mark for load mode reads. This caused the diagnostics to crash. - SCP bugs in ssh_break and set_logon were fixed (found by Dave Hittner). - Numerous bugs in the HP 2100 extended arithmetic, floating point, 21MX, DMS, and IOP instructions were fixed. Bugs were also fixed in the memory protect and DMS functions. The moving head disks (DP, DQ) were revised to simulate the hardware more accurately. Missing functions in DQ (address skip, read address) were added. 2.2 HP 2100 Debugging - The HP 2100 CPU nows runs all of the CPU diagnostics. - The peripherals run most of the peripheral diagnostics. There is still a problem in overlapped seek operation on the disks. See the file hp2100_diag.txt for details. 3. In Progress These simulators are not finished and are available in a separate Zip archive distribution. - Interdata 16b/32b: coded, partially tested. See the file id_diag.txt for details. - SDS 940: coded, partially tested.
This commit is contained in:
committed by
Mark Pizzolato
parent
df6475181c
commit
2c2dd5ea33
2491
HP2100/hp2100_cpu.c
2491
HP2100/hp2100_cpu.c
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
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.
|
||||
|
||||
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
|
||||
@@ -43,9 +44,9 @@
|
||||
#define STOP_HALT 3 /* HALT */
|
||||
#define STOP_IBKPT 4 /* breakpoint */
|
||||
#define STOP_IND 5 /* indirect loop */
|
||||
#define STOP_INDINT 6 /* indirect intr */
|
||||
|
||||
#define ABORT_DMS 1 /* DMS abort */
|
||||
#define ABORT_FENCE -1 /* fence abort */
|
||||
#define ABORT_PRO 1 /* protection abort */
|
||||
|
||||
/* Memory */
|
||||
|
||||
@@ -66,25 +67,27 @@
|
||||
#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 IA 0100000 /* indirect address */
|
||||
#define MROP 0070000 /* opcode */
|
||||
#define AB 0004000 /* A/B select */
|
||||
#define CP 0002000 /* current page */
|
||||
#define DISP 0001777 /* page displacement */
|
||||
#define PAGENO 0076000 /* page number */
|
||||
#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 NMROP 0102000 /* non-mrf opcode */
|
||||
#define SHFT 0000000 /* shift */
|
||||
#define ASKP 0002000 /* alter/skip */
|
||||
#define XTND 0100000 /* extend */
|
||||
#define IOT 0102000 /* I/O */
|
||||
#define HC 0001000 /* hold/clear */
|
||||
#define DEVMASK 0000077 /* device mask */
|
||||
#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 */
|
||||
|
||||
@@ -192,7 +195,8 @@ struct DMA { /* DMA channel */
|
||||
#define TTY 011 /* console */
|
||||
#define PTP 012 /* paper tape punch */
|
||||
#define CLK 013 /* clock */
|
||||
#define LPT 014 /* line printer */
|
||||
#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 */
|
||||
@@ -207,11 +211,22 @@ struct DMA { /* DMA channel */
|
||||
#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 enb; /* enabled */
|
||||
int32 cmd; /* saved command */
|
||||
int32 ctl; /* saved control */
|
||||
int32 flg; /* saved flag */
|
||||
@@ -247,5 +262,4 @@ typedef struct hp_dib DIB;
|
||||
|
||||
t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_stat set_enb (UNIT *uptr, int32 num, char *cptr, void *desc);
|
||||
t_stat set_dis (UNIT *uptr, int32 num, char *cptr, void *desc);
|
||||
void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp);
|
||||
|
||||
148
HP2100/hp2100_diag.txt
Normal file
148
HP2100/hp2100_diag.txt
Normal file
@@ -0,0 +1,148 @@
|
||||
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 group passed 13206 manual no
|
||||
|
||||
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
|
||||
- set MSC CTIME to 180000
|
||||
- do not change MSC XTIME
|
||||
- attach scratch tapes to units 0,1
|
||||
- set s = 2000 (suppress CRC/LRC)
|
||||
- run with test select a = 37737, 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,7 +1,7 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: HP2100 Simulator Usage
|
||||
Date: 15-Jun-2002
|
||||
Date: 15-Nov-2002
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
@@ -37,9 +37,13 @@ This memorandum documents the HP 2100 simulator.
|
||||
1. Simulator Files
|
||||
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_rev.c
|
||||
sim_sock.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/hp2100/ hp2100_defs.h
|
||||
hp2100_cpu.c
|
||||
@@ -47,7 +51,8 @@ sim/hp2100/ hp2100_defs.h
|
||||
hp2100_dp.c
|
||||
hp2100_dq.c
|
||||
hp2100_dr.c
|
||||
hp2100_lp.c
|
||||
hp2100_lps.c
|
||||
hp2100_lpt.c
|
||||
hp2100_mt.c
|
||||
hp2100_ms.c
|
||||
hp2100_mux.c
|
||||
@@ -61,18 +66,25 @@ The HP2100 simulator is configured as follows:
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU 2116, 2100, or 21MX CPU with 32KW memory
|
||||
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 teleprinter
|
||||
LPT 12653A line printer
|
||||
TTY 12631C buffered terminal controller
|
||||
LPS 12653A printer controller with 2767 printer
|
||||
12566B microcircuit interface for diagnostics
|
||||
LPT 12845A printer controller
|
||||
CLK 12539A/B/C time base generator
|
||||
MUXL,MUXU,MUXC 12920A terminal multiplexor
|
||||
DP 12557A/13210A disk controller with four drives
|
||||
DQ 12565A disk controller with two drives
|
||||
DR 12606A/12610A fixed head disk/drum controller
|
||||
MT 12559C magnetic tape controller with one drives
|
||||
MS 13181A magnetic tape controller with four drives
|
||||
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
|
||||
|
||||
The HP2100 simulator implements several unique stop conditions:
|
||||
|
||||
@@ -88,46 +100,78 @@ command is not implemented.
|
||||
|
||||
CPU options include choice of instruction set and memory size.
|
||||
|
||||
SET CPU 2116 2116 instructions
|
||||
SET CPU 2100 2100 instructions
|
||||
SET CPU 21MX 21MX instructions
|
||||
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 only)
|
||||
SET CPU NOIOP no IOP instructions (2100 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 24K set memory size = 24K
|
||||
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 size comments
|
||||
name models size comments
|
||||
|
||||
P 15 program counter
|
||||
A 16 A register
|
||||
B 16 B register
|
||||
X 16 X index register (21MX)
|
||||
Y 16 Y index register (21MX)
|
||||
S 16 switch/display register
|
||||
E 1 extend flag
|
||||
O 1 overflow flag
|
||||
ION 1 interrupt enable flag
|
||||
ION_DEFER 1 interrupt defer flag
|
||||
IADDR 6 most recent interrupting device
|
||||
MPCTL 1 memory protection enable (2100, 21MX)
|
||||
MPFLG 1 memory protection flag (2100, 21MX)
|
||||
MPFBF 1 memory protection flag buffer (2100, 21MX)
|
||||
MFENCE 15 memory protection fence (2100, 21MX)
|
||||
MADDR 16 memory protection error address (2100, 21MX)
|
||||
STOP_INST 1 stop on undefined instruction
|
||||
STOP_DEV 1 stop on undefined device
|
||||
INDMAX 1 indirect address limit
|
||||
PCQ[0:63] 15 PC of last JMP, JSB, or interrupt;
|
||||
most recent PC change first
|
||||
WRU 8 interrupt character
|
||||
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
|
||||
|
||||
@@ -140,9 +184,9 @@ DMA channel has the following visible state:
|
||||
CTL 1 interrupt enabled
|
||||
FLG 1 channel ready
|
||||
FBF 1 channel ready buffer
|
||||
CW1 1 command word 1
|
||||
CW2 1 command word 2
|
||||
CW3 1 command word 3
|
||||
CW1 16 command word 1
|
||||
CW2 16 command word 2
|
||||
CW3 16 command word 3
|
||||
|
||||
2.3 Variable Device Assignments
|
||||
|
||||
@@ -165,7 +209,7 @@ 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
|
||||
message when started.
|
||||
when started.
|
||||
|
||||
In addition, most devices can be enabled or disabled. To enable a
|
||||
device, use the SET <dev> ENABLED command:
|
||||
@@ -176,8 +220,8 @@ To disable a device, use the SET <dev> DISABLED command:
|
||||
|
||||
sim> SET DP DISABLED
|
||||
|
||||
For devices with two device numbers, disabling or enabling one device
|
||||
in the pair disables or enables the other.
|
||||
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
|
||||
|
||||
@@ -243,16 +287,19 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.3 12631C Buffered Teleprinter (TTY)
|
||||
2.4.3 12631C Buffered Terminal (TTY)
|
||||
|
||||
The console teleprinter has three units: keyboard (unit 0), printer
|
||||
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 has one option, UC; when
|
||||
set, it automatically converts lower case input to upper case. This
|
||||
is on by default.
|
||||
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 terminal implements these registers:
|
||||
The console teleprinter implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
@@ -277,7 +324,52 @@ Error handling for the punch is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.4 12653A Line Printer (LPT)
|
||||
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,
|
||||
@@ -292,6 +384,7 @@ The line printer implements these registers:
|
||||
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
|
||||
@@ -306,13 +399,14 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4.5 12539A/B/C Time Base Generator (CLK)
|
||||
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
|
||||
@@ -320,7 +414,11 @@ The time base generator (CLK) implements these registers:
|
||||
TIME[0:7] 31 clock intervals, select = 0..7
|
||||
DEVNO 6 current device number (read only)
|
||||
|
||||
2.4.6 12920A Terminal Multiplexor (MUXL, MUXU, MUXC)
|
||||
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:
|
||||
@@ -341,10 +439,13 @@ the port to be used:
|
||||
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) supports two options. UC, when set, causes
|
||||
lower case input characters to be automatically converted to upper case.
|
||||
DATASET, when set, enables modem control. By default, UC is on, and
|
||||
DATASET is off.
|
||||
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
|
||||
@@ -404,7 +505,8 @@ The modem control (MUXM) implements these registers:
|
||||
The terminal multiplexor does not support save and restore. All open
|
||||
connections are lost when the simulator shuts down or MUXU is detached.
|
||||
|
||||
2.5 12557A/13210A Disk Controller (DP)
|
||||
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,
|
||||
@@ -414,13 +516,25 @@ with the commands:
|
||||
SET DP 13210A 5.0MB drives
|
||||
|
||||
Drive types cannot be intermixed; the controller is configured for
|
||||
one type or the other.
|
||||
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
|
||||
@@ -433,6 +547,8 @@ The data channel implements these registers:
|
||||
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:
|
||||
|
||||
@@ -440,19 +556,20 @@ The device controller implements these registers:
|
||||
|
||||
OBUF 16 output buffer
|
||||
BUSY 3 busy (unit #, + 1, of active unit)
|
||||
RARC 8 record address register cylinder
|
||||
RARH 2 record address register head
|
||||
RARS 4 record address register sector
|
||||
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
|
||||
CTIME 24 command delay time
|
||||
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
|
||||
STA[0:3] 16 drive status, drives 0-3
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
@@ -464,13 +581,22 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error report error and stop
|
||||
|
||||
2.6 12565A Disk Controller (DP)
|
||||
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
|
||||
@@ -483,6 +609,8 @@ The data channel implements these registers:
|
||||
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:
|
||||
|
||||
@@ -490,19 +618,19 @@ The device controller implements these registers:
|
||||
|
||||
OBUF 16 output buffer
|
||||
BUSY 2 busy (unit #, + 1, of active unit)
|
||||
RARC 8 record address register cylinder
|
||||
RARH 5 record address register head
|
||||
RARS 5 record address register sector
|
||||
CNT 5 check record count
|
||||
CNT 9 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
|
||||
CTIME 24 command delay time
|
||||
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
|
||||
STA[0:3] 16 drive status, drives 0-3
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
@@ -514,22 +642,28 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error report error and stop
|
||||
|
||||
2.7 12606A/12610A Fixed Head Disk/Drum Controller (DR)
|
||||
2.7 12606B Fixed Head Disk Controller (DRC, DRD) with 2770/2771 Disk
|
||||
12610B Drum Controller (DRC, DRD) with 2773/2774/2775 Drum
|
||||
|
||||
The 12606A/12610A fixed head disk/drum controller has two separate devices,
|
||||
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 DR 180K 12606A, 180K words
|
||||
SET DR 360K 12606A, 360K words
|
||||
SET DR 720K 12606A, 720K words
|
||||
SET DR 384K 12610A, 384K words
|
||||
SET DR 512K 12610A, 512K words
|
||||
SET DR 640K 12610A, 640K words
|
||||
SET DR 768K 12610A, 768K words
|
||||
SET DR 896K 12610A, 896K words
|
||||
SET DR 1024K 12610A, 1024K words
|
||||
SET DR 1536K 12610A, 1536K words
|
||||
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:
|
||||
|
||||
@@ -562,19 +696,26 @@ Error handling is as follows:
|
||||
|
||||
not attached disk not ready
|
||||
|
||||
2.8 12559C Magnetic Tape (MT)
|
||||
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 MT LOCKED set unit write locked
|
||||
SET MT WRITEENABLED set unit write enabled
|
||||
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
|
||||
@@ -605,25 +746,40 @@ Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached tape not ready
|
||||
not attached tape not ready; if STOP_IOE, stop
|
||||
|
||||
end of file (read or space) end of physical tape
|
||||
(write) ignored
|
||||
end of file parity error
|
||||
|
||||
OS I/O error report error and stop
|
||||
OS I/O error parity error; if STOP_IOE, stop
|
||||
|
||||
2.9 13181A Magnetic Tape (MS)
|
||||
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.
|
||||
or write locked, and the ability to select the 13181A (800 bpi) controller
|
||||
or the 13183A (1600 bpi) controller.
|
||||
|
||||
SET MT LOCKED set unit write locked
|
||||
SET MT WRITEENABLED set unit write enabled
|
||||
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 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 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:
|
||||
|
||||
@@ -657,12 +813,11 @@ Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached tape not ready
|
||||
not attached tape not ready; if STOP_IOE, stop
|
||||
|
||||
end of file (read or space) end of physical tape
|
||||
(write) ignored
|
||||
end of file parity error
|
||||
|
||||
OS I/O error report error and stop
|
||||
OS I/O error parity error; if STOP_IOE, stop
|
||||
|
||||
2.10 Symbolic Display and Input
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* hp2100_dp.c: HP 2100 12557A/13210A disk pack simulator
|
||||
/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator
|
||||
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
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/13210A disk pack subsystem
|
||||
dp 12557A 2871 disk subsystem
|
||||
13210A 7900 disk subsystem
|
||||
|
||||
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
|
||||
@@ -38,9 +40,9 @@
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_W_UF 2 /* # flags */
|
||||
#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 */
|
||||
@@ -68,8 +70,9 @@
|
||||
#define FNC_AR 013 /* address */
|
||||
#define FNC_SEEK1 020 /* fake - seek1 */
|
||||
#define FNC_SEEK2 021 /* fake - seek2 */
|
||||
#define FNC_CHK1 022 /* fake - check1 */
|
||||
#define FNC_AR1 023 /* fake - arec1 */
|
||||
#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)
|
||||
@@ -91,53 +94,66 @@
|
||||
#define DA_CKMASK3 077
|
||||
#define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2)
|
||||
|
||||
/* Status */
|
||||
/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */
|
||||
|
||||
#define STA_ATN 0100000 /* attention */
|
||||
#define STA_1ST 0040000 /* first seek */
|
||||
#define STA_ATN 0100000 /* attention (u) */
|
||||
#define STA_1ST 0040000 /* first status */
|
||||
#define STA_OVR 0020000 /* overrun */
|
||||
#define STA_RWU 0010000 /* rw unsafe */
|
||||
#define STA_ACU 0004000 /* access unsafe */
|
||||
#define STA_HUNT 0002000 /* hunting NI */
|
||||
#define STA_SKI 0001000 /* incomplete NI */
|
||||
#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 */
|
||||
#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_ERR 0000001 /* any error (d) */
|
||||
#define STA_ALLERR (STA_ATN + STA_1ST + STA_OVR + STA_RWU + STA_ACU + \
|
||||
STA_HUNT + STA_SKI + STA_SKE + STA_NRDY + STA_EOC + \
|
||||
STA_FLG + STA_DTE)
|
||||
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 int32 PC;
|
||||
extern uint16 *M;
|
||||
extern int32 PC, SR;
|
||||
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
int32 dp_ctype = 0; /* ctrl type */
|
||||
int32 dpc_busy = 0; /* cch busy */
|
||||
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_sta[DP_NUMDRV] = { 0 }; /* status regs */
|
||||
int32 dpc_stime = 10; /* seek time */
|
||||
int32 dpc_ctime = 10; /* command time */
|
||||
int32 dpc_stime = 100; /* seek time */
|
||||
int32 dpc_ctime = 100; /* command time */
|
||||
int32 dpc_xtime = 5; /* xfer time */
|
||||
int32 dpc_rarc = 0, dpc_rarh = 0, dpc_rars = 0; /* record addr */
|
||||
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_detach (UNIT *uptr);
|
||||
void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev);
|
||||
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);
|
||||
|
||||
@@ -149,13 +165,13 @@ t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
*/
|
||||
|
||||
DIB dp_dib[] = {
|
||||
{ DPD, 1, 0, 0, 0, 0, &dpdio },
|
||||
{ DPC, 1, 0, 0, 0, 0, &dpcio } };
|
||||
{ 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 (NULL, 0, 0) };
|
||||
UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) };
|
||||
|
||||
REG dpd_reg[] = {
|
||||
{ ORDATA (IBUF, dpd_ibuf, 16) },
|
||||
@@ -164,22 +180,24 @@ REG dpd_reg[] = {
|
||||
{ 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 },
|
||||
{ FLDATA (*DEVENB, dpd_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dpd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dpd_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&dpd_dib, 0 };
|
||||
|
||||
/* DPC data structures
|
||||
|
||||
@@ -190,58 +208,61 @@ DEVICE dpd_dev = {
|
||||
*/
|
||||
|
||||
UNIT dpc_unit[] = {
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) },
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) },
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) },
|
||||
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) } };
|
||||
{ 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 (RARC, dpc_rarc, 8) },
|
||||
{ ORDATA (RARH, dpc_rarh, 2) },
|
||||
{ ORDATA (RARS, dpc_rars, 4) },
|
||||
{ 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 },
|
||||
{ BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) },
|
||||
{ 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, 31, 0,
|
||||
DP_NUMDRV, PV_LEFT | REG_HRO) },
|
||||
{ URDATA (UFLG, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
|
||||
DP_NUMDRV, REG_HRO) },
|
||||
{ ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, dpc_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dpc_mod[] = {
|
||||
/* { UNIT_WLK, 0, "write enabled", "ENABLED", &dpc_vlock }, */
|
||||
/* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dpc_vlock }, */
|
||||
{ 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, NULL, "ENABLED",
|
||||
&set_enb, NULL, &dpd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED",
|
||||
&set_dis, NULL, &dpd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dpd_dib },
|
||||
&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,
|
||||
NULL, &dpc_attach, &dpc_detach };
|
||||
&dpc_boot, &dpc_attach, NULL,
|
||||
&dpc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
@@ -249,10 +270,10 @@ int32 dpdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & DEVMASK; /* get device no */
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devd); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -262,6 +283,7 @@ case ioSFS: /* skip flag set */
|
||||
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;
|
||||
@@ -270,15 +292,19 @@ case ioLIX: /* load */
|
||||
dat = dpd_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC */
|
||||
clrCTL (devd); /* clr ctl, cmd */
|
||||
clrCMD (devd); }
|
||||
else { setCTL (devd); /* STC */
|
||||
setCMD (devd); } /* set ctl, cmd */
|
||||
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 & HC) { clrFLG (devd); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -286,10 +312,10 @@ int32 dpcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 i, devc, fnc, drv;
|
||||
|
||||
devc = IR & DEVMASK; /* get device no */
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -304,59 +330,187 @@ 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);
|
||||
if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i);
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC? */
|
||||
clrCMD (devc); /* clr cmd, ctl */
|
||||
clrCTL (devc); /* cancel non-seek */
|
||||
if (dpc_busy) sim_cancel (&dpc_unit[dpc_busy - 1]);
|
||||
dpc_busy = 0; } /* clr busy */
|
||||
else if (!CTL (devc)) { /* set and now clr? */
|
||||
setCMD (devc); /* set cmd, ctl */
|
||||
setCTL (devc);
|
||||
drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */
|
||||
fnc = CW_GETFNC (dpc_obuf); /* from cmd word */
|
||||
switch (fnc) { /* case on fnc */
|
||||
case FNC_SEEK: /* seek */
|
||||
dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) &
|
||||
~(STA_SKE | STA_SKI | STA_HUNT | STA_1ST);
|
||||
dp_go (fnc, drv, dpc_xtime, devc);
|
||||
break;
|
||||
case FNC_STA: case FNC_AR: /* rd sta, addr rec */
|
||||
dp_go (fnc, drv, dpc_xtime, 0);
|
||||
break;
|
||||
case FNC_CHK: /* check */
|
||||
dp_go (fnc, drv, dpc_xtime, devc);
|
||||
break;
|
||||
case FNC_REF: case FNC_RD: case FNC_WD: /* ref, read, write */
|
||||
case FNC_INIT: /* init */
|
||||
dp_go (fnc, drv, dpc_ctime, devc);
|
||||
break;
|
||||
} /* end case */
|
||||
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 if (!CTL (devc)) { /* set and was clr? */
|
||||
setCTL (devc); /* set ctl */
|
||||
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_SEEK: case FNC_CHK: /* seek, check */
|
||||
case FNC_STA: case FNC_AR: /* rd sta, 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 & HC) { clrFLG (devc); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
/* Start data channel operation */
|
||||
|
||||
Unit must be attached; detach cancels 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
|
||||
seek2 - done
|
||||
Address record
|
||||
ar - transfer cylinder
|
||||
ar1 - transfer head/surface, finish operation
|
||||
Status check - transfer status, finish operation
|
||||
Refine sector - erase sector, 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)) { /* dch active? */
|
||||
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 */
|
||||
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
|
||||
@@ -367,221 +521,144 @@ return dat;
|
||||
|
||||
t_stat dpc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, da, drv, devc, devd, err, st, maxsc;
|
||||
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 */
|
||||
switch (uptr -> FNC) { /* case function */
|
||||
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_SEEK: /* seek, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarc = DA_GETCYL (dpd_obuf); /* take cyl word */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr -> FNC = FNC_SEEK1; } /* advance state */
|
||||
sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_SEEK1: /* seek, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarh = DA_GETHD (dpd_obuf); /* get head */
|
||||
dpc_rars = DA_GETSC (dpd_obuf); /* get sector */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
st = abs (dpc_rarc - uptr -> CYL) * dpc_stime; /* calc diff */
|
||||
if (st == 0) st = dpc_xtime; /* min time */
|
||||
sim_activate (uptr, st); /* schedule op */
|
||||
uptr -> CYL = dpc_rarc; /* on cylinder */
|
||||
dpc_busy = 0; /* ctrl is free */
|
||||
uptr -> FNC = FNC_SEEK2; } /* advance state */
|
||||
else sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_SEEK2: /* seek done */
|
||||
if (dpc_busy) sim_activate (uptr, dpc_xtime); /* ctrl busy? wait */
|
||||
else { 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 = 0; }
|
||||
if (dpc_rars >= DP_NUMSC) /* invalid sec? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_SKE;
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); } /* clr cch cmd */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_AR: /* arec, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarc = DA_GETCYL (dpd_obuf); /* take cyl word */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr -> FNC = FNC_AR1; } /* advance state */
|
||||
sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_AR1: /* arec, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_rarh = DA_GETHD (dpd_obuf); /* get head */
|
||||
dpc_rars = DA_GETSC (dpd_obuf); /* get sector */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); } /* clr dch cmd */
|
||||
else { sim_activate (uptr, dpc_xtime); /* no, wait more */
|
||||
return SCPE_OK; }
|
||||
break; /* done */
|
||||
|
||||
case FNC_STA: /* read status */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpd_ibuf = dpc_sta[drv] & ~(dp_ctype? STA_MBZ13: 0);
|
||||
if (dpc_sta[drv] & STA_ALLERR) dpd_ibuf = dpd_ibuf | STA_ERR;
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */
|
||||
~(STA_ATN | STA_DTE | STA_FLG | STA_AER | STA_EOC);
|
||||
dpc_busy = 0; } /* ctlr is free */
|
||||
else sim_activate (uptr, dpc_xtime); /* wait more */
|
||||
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 */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_REF: /* refine sector */
|
||||
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC))
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
|
||||
else { for (i = 0; i < DP_NUMWD; i++) dpxb[i] = 0;
|
||||
da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */
|
||||
dpc_rars = dpc_rars + 1; /* incr sector */
|
||||
if (dpc_rars >= DP_NUMSC) { /* end of trk? */
|
||||
dpc_rars = 0; /* wrap to */
|
||||
dpc_rarh = dpc_rarh ^ 1; } /* next surf */
|
||||
if (err = fseek (uptr -> fileref, da * sizeof (int16),
|
||||
SEEK_SET)) break;
|
||||
fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref); }
|
||||
break;
|
||||
|
||||
case FNC_CHK: /* check, need cnt */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dpc_ctime); /* schedule op */
|
||||
uptr -> FNC = FNC_CHK1; } /* advance state */
|
||||
else sim_activate (uptr, dpc_xtime); /* wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_CHK1:
|
||||
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC))
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
|
||||
else { maxsc = ((2 - (dpc_rarh & 1)) * DP_NUMSC) - dpc_rars;
|
||||
if (dpc_cnt > maxsc) { /* too many sec? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
|
||||
dpc_rarh = dpc_rarh & ~1; /* rar = 0/2, 0 */
|
||||
dpc_rars = 0; }
|
||||
else { i = dpc_rars + dpc_cnt; /* final sector */
|
||||
dpc_rars = i % DP_NUMSC; /* reposition */
|
||||
dpc_rarh = dpc_rarh ^ ((i / DP_NUMSC) & 1); } }
|
||||
break; /* done */
|
||||
break; /* just a NOP */
|
||||
|
||||
case FNC_RD: /* read */
|
||||
if (!CMD (devd)) break; /* dch clr? done */
|
||||
if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR;
|
||||
case FNC_CHK1: /* check */
|
||||
if (dp_ptr == 0) { /* new sector? */
|
||||
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) {
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
|
||||
break; }
|
||||
if (dpc_eoc) { /* end of cyl? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_EOC;
|
||||
break; }
|
||||
da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */
|
||||
dpc_rars = dpc_rars + 1; /* incr address */
|
||||
if (dpc_rars >= DP_NUMSC) { /* end of trk? */
|
||||
dpc_rars = 0; /* wrap to */
|
||||
dpc_rarh = dpc_rarh ^ 1; /* next cyl */
|
||||
dpc_eoc = ((dpc_rarh & 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; }
|
||||
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) dp_ptr = 0; /* wrap if last */
|
||||
setFLG (devd); /* set dch flg */
|
||||
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 (dpc_eoc) { /* end of cyl? */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */
|
||||
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 (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR;
|
||||
dpxb[dp_ptr++] = dpd_obuf; /* store word */
|
||||
if (!CMD (devd)) { /* dch clr? done */
|
||||
for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dpxb[dp_ptr] = 0; }
|
||||
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? */
|
||||
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) {
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
|
||||
break; }
|
||||
da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */
|
||||
dpc_rars = dpc_rars + 1; /* incr address */
|
||||
if (dpc_rars >= DP_NUMSC) { /* end of trk? */
|
||||
dpc_rars = 0; /* wrap to */
|
||||
dpc_rarh = dpc_rarh ^ 1; /* next cyl */
|
||||
dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
|
||||
if (err = fseek (uptr -> fileref, da * sizeof (int16),
|
||||
SEEK_SET)) return TRUE;
|
||||
fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref);
|
||||
if (err = ferror (uptr -> fileref)) break;
|
||||
dp_ptr = 0; }
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dpc_xtime); /* sched next word */
|
||||
return SCPE_OK; }
|
||||
break; } /* end case fnc */
|
||||
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;
|
||||
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* request attn */
|
||||
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);
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Start disk operation */
|
||||
|
||||
void dp_go (int32 fnc, int32 drv, int32 time, int32 dev)
|
||||
{
|
||||
if (dev && ((dpc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */
|
||||
dpc_sta[drv] = STA_NRDY; /* not attached */
|
||||
setFLG (dev); /* set cch flag */
|
||||
clrCMD (dev); } /* clr cch cmd */
|
||||
else { dpc_busy = drv + 1; /* set busy */
|
||||
dp_ptr = 0; /* init buf ptr */
|
||||
dpc_eoc = 0; /* clear end cyl */
|
||||
dpc_unit[drv].FNC = fnc; /* save function */
|
||||
sim_activate (&dpc_unit[drv], time); } /* activate unit */
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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_rarc = dpc_rarh = dpc_rars = 0; /* clear rar */
|
||||
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_sta[i] = (dpc_sta[i] & STA_1ST) |
|
||||
((dpc_unit[i].flags & UNIT_ATT)? 0: STA_NRDY); }
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -595,31 +672,10 @@ 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) & ~STA_NRDY; /* update status */
|
||||
dpc_sta[drv] = dpc_sta[drv] | STA_1ST; /* update status */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat dpc_detach (UNIT* uptr)
|
||||
{
|
||||
int32 drv;
|
||||
|
||||
drv = uptr - dpc_dev.units; /* get drive no */
|
||||
dpc_sta[drv] = (dpc_sta[drv] | STA_NRDY) & ~STA_1ST; /* update status */
|
||||
if (drv == (dpc_busy + 1)) dpc_busy = 0; /* update busy */
|
||||
sim_cancel (uptr); /* cancel op */
|
||||
return detach_unit (uptr); /* detach unit */
|
||||
}
|
||||
|
||||
/* Write lock/enable routine */
|
||||
|
||||
t_stat dpc_vlock (UNIT *uptr, int32 val)
|
||||
{
|
||||
if (uptr -> flags & UNIT_ATT) return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set controller type */
|
||||
|
||||
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
@@ -644,4 +700,89 @@ else fprintf (st, "12557A");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 7900/7901 bootstrap routine (HP 12992F ROM) */
|
||||
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
#define CHANGE_ADDR (1 << 23)
|
||||
|
||||
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 */
|
||||
CHANGE_ADDR }; /* -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_ADDR) /* memory limit? */
|
||||
M[PC + i] = (-PC) & DMASK;
|
||||
else if (dboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (dboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = dboot[i]; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* hp2100_dq.c: HP 2100 12565A disk simulator
|
||||
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
Modified from hp2100_dp.c by Bill McDermith; used by permission
|
||||
Copyright (c) 1993-2002, Bill McDermith
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -20,22 +19,29 @@
|
||||
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
|
||||
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 Robert M Supnik.
|
||||
in this Software without prior written authorization from the author.
|
||||
|
||||
dq 12565A 2883/2884 disk system
|
||||
dq 12565A 2883 disk system
|
||||
|
||||
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 UNIT_W_UF 2 /* # flags */
|
||||
#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 */
|
||||
@@ -64,9 +70,9 @@
|
||||
|
||||
#define FNC_SEEK1 020 /* fake - seek1 */
|
||||
#define FNC_SEEK2 021 /* fake - seek2 */
|
||||
#define FNC_CHK1 022 /* fake - check1 */
|
||||
#define FNC_LA1 023 /* fake - arec1 */
|
||||
#define FNC_RCL1 024 /* fake - recal1 */
|
||||
#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
|
||||
@@ -85,42 +91,50 @@
|
||||
#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)
|
||||
#define DA_CKMASK 0777 /* check mask */
|
||||
|
||||
/* Status */
|
||||
/* Status in dqc_sta[drv] - (d) = dynamic */
|
||||
|
||||
#define STA_DID 0000200 /* drive ID */
|
||||
#define STA_NRDY 0000100 /* not ready */
|
||||
#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_DID + STA_NRDY + STA_EOC + \
|
||||
STA_FLG + STA_DTE)
|
||||
#define STA_ALLERR (STA_NRDY + STA_EOC + STA_AER + STA_FLG + STA_DTE)
|
||||
|
||||
extern int32 PC;
|
||||
extern uint16 *M;
|
||||
extern int32 PC, SR;
|
||||
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
int32 dqc_busy = 0; /* cch busy */
|
||||
extern int32 sim_switches;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 dqc_busy = 0; /* cch xfer */
|
||||
int32 dqc_cnt = 0; /* check count */
|
||||
int32 dqc_eoc = 0; /* end of cyl */
|
||||
int32 dqc_sta[DQ_NUMDRV] = { 0 }; /* status regs */
|
||||
int32 dqc_stime = 10; /* seek time */
|
||||
int32 dqc_ctime = 10; /* command time */
|
||||
int32 dqc_stime = 100; /* seek time */
|
||||
int32 dqc_ctime = 100; /* command time */
|
||||
int32 dqc_xtime = 5; /* xfer time */
|
||||
int32 dqc_rarc = 0, dqc_rarh = 0, dqc_rars = 0; /* record addr */
|
||||
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_vlock (UNIT *uptr, int32 val);
|
||||
t_stat dqc_attach (UNIT *uptr, char *cptr);
|
||||
t_stat dqc_detach (UNIT *uptr);
|
||||
void dq_go (int32 fnc, int32 drv, int32 time, int32 attdev);
|
||||
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
|
||||
|
||||
@@ -130,13 +144,13 @@ void dq_go (int32 fnc, int32 drv, int32 time, int32 attdev);
|
||||
*/
|
||||
|
||||
DIB dq_dib[] = {
|
||||
{ DQD, 1, 0, 0, 0, 0, &dqdio },
|
||||
{ DQC, 1, 0, 0, 0, 0, &dqcio } };
|
||||
{ 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 (NULL, 0, 0) };
|
||||
UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) };
|
||||
|
||||
REG dqd_reg[] = {
|
||||
{ ORDATA (IBUF, dqd_ibuf, 16) },
|
||||
@@ -145,22 +159,24 @@ REG dqd_reg[] = {
|
||||
{ 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 },
|
||||
{ FLDATA (*DEVENB, dqd_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dqd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &dqd_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&dqd_dib, 0 };
|
||||
|
||||
/* DQC data structures
|
||||
|
||||
@@ -171,47 +187,47 @@ DEVICE dqd_dev = {
|
||||
*/
|
||||
|
||||
UNIT dqc_unit[] = {
|
||||
{ UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) },
|
||||
{ UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) } };
|
||||
{ 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 (RARC, dqc_rarc, 8) },
|
||||
{ ORDATA (RARH, dqc_rarh, 5) },
|
||||
{ ORDATA (RARS, dqc_rars, 5) },
|
||||
{ ORDATA (CNT, dqc_cnt, 5) },
|
||||
{ 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) },
|
||||
{ FLDATA (EOC, dqc_eoc, 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 },
|
||||
{ BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) },
|
||||
{ URDATA (UFLG, dqc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
|
||||
DQ_NUMDRV, REG_HRO) },
|
||||
{ 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 },
|
||||
{ FLDATA (*DEVENB, dqc_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dqc_mod[] = {
|
||||
/* { UNIT_WLK, 0, "write enabled", "ENABLED", &dqc_vlock }, */
|
||||
/* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dqc_vlock }, */
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED",
|
||||
&set_enb, NULL, &dqd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED",
|
||||
&set_dis, NULL, &dqd_dib },
|
||||
{ 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_dib },
|
||||
&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,
|
||||
NULL, &dqc_attach, &dqc_detach };
|
||||
&dqc_boot, NULL, NULL,
|
||||
&dqc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
@@ -219,10 +235,10 @@ int32 dqdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & DEVMASK; /* get device no */
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devd); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -232,6 +248,7 @@ case ioSFS: /* skip flag set */
|
||||
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;
|
||||
@@ -240,15 +257,19 @@ case ioLIX: /* load */
|
||||
dat = dqd_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC */
|
||||
clrCTL (devd); /* clr ctl, cmd */
|
||||
clrCMD (devd); }
|
||||
else { setCTL (devd); /* STC */
|
||||
setCMD (devd); } /* set ctl, cmd */
|
||||
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 & HC) { clrFLG (devd); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -256,10 +277,10 @@ int32 dqcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devc, fnc, drv;
|
||||
|
||||
devc = IR & DEVMASK; /* get device no */
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -275,56 +296,197 @@ case ioLIX: /* load */
|
||||
case ioMIX: /* merge */
|
||||
break; /* no data */
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC? */
|
||||
clrCMD (devc); /* clr cmd, ctl */
|
||||
clrCTL (devc); /* cancel non-seek */
|
||||
if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]);
|
||||
dqc_busy = 0; } /* clr busy */
|
||||
else if (!CTL (devc)) { /* set and now clr? */
|
||||
setCMD (devc); /* set cmd, ctl */
|
||||
setCTL (devc);
|
||||
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 */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_BSY;
|
||||
dq_go (fnc, drv, dqc_xtime, devc);
|
||||
break;
|
||||
case FNC_STA: case FNC_LA: /* rd sta, load addr */
|
||||
dq_go (fnc, drv, dqc_xtime, 0);
|
||||
break;
|
||||
case FNC_CHK: /* check */
|
||||
dq_go (fnc, drv, dqc_xtime, devc);
|
||||
break;
|
||||
case FNC_RD: case FNC_WD: case FNC_WA: /* read, write, wr addr */
|
||||
dq_go (fnc, drv, dqc_ctime, devc);
|
||||
break;
|
||||
} /* end case */
|
||||
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 if (!CTL (devc)) { /* set and was clr? */
|
||||
setCMD (devc); /* set cmd, ctl */
|
||||
setCTL (devc);
|
||||
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 else */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & HC) { clrFLG (devc); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
/* Start data channel operation */
|
||||
|
||||
Unit must be attached; detach cancels 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
|
||||
seek2 - done
|
||||
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
|
||||
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 */
|
||||
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) \
|
||||
@@ -332,252 +494,225 @@ return dat;
|
||||
|
||||
t_stat dqc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, da, drv, devc, devd, err, st, maxsc;
|
||||
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 */
|
||||
switch (uptr -> FNC) { /* case function */
|
||||
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_SEEK: /* seek, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarc = DA_GETCYL (dqd_obuf); /* take cyl word */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr -> FNC = FNC_SEEK1; } /* advance state */
|
||||
sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_SEEK1: /* seek, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarh = DA_GETHD (dqd_obuf); /* get head */
|
||||
dqc_rars = DA_GETSC (dqd_obuf); /* get sector */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
st = abs (dqc_rarc - uptr -> CYL) * dqc_stime; /* calc diff */
|
||||
if (st == 0) st = dqc_xtime; /* min time */
|
||||
sim_activate (uptr, st); /* schedule op */
|
||||
uptr -> CYL = dqc_rarc; /* on cylinder */
|
||||
dqc_busy = 0; /* ctrl is free */
|
||||
uptr -> FNC = FNC_SEEK2; } /* advance state */
|
||||
else sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_SEEK2: /* seek done */
|
||||
if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */
|
||||
else { dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY;
|
||||
if (uptr -> CYL >= DQ_NUMCY) { /* invalid cyl? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER;
|
||||
uptr -> CYL = 0; }
|
||||
if (dqc_rars >= DQ_NUMSC) /* invalid sec? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER;
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); } /* clr cch cmd */
|
||||
return SCPE_OK;
|
||||
case FNC_RCL: /* recalibrate */
|
||||
if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */
|
||||
else { st = uptr -> CYL * dqc_stime; /* calc diff */
|
||||
if (st == 0) st = dqc_xtime; /* min time */
|
||||
sim_activate (uptr, st); /* schedule op */
|
||||
uptr -> CYL = 0; /* on cylinder */
|
||||
dqc_busy = 0; /* ctrl is free */
|
||||
uptr -> FNC = FNC_RCL1; } /* advance state */
|
||||
return SCPE_OK;
|
||||
case FNC_RCL1: /* recal done */
|
||||
if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */
|
||||
else { dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY;
|
||||
setFLG (devc); /* set cch flg */
|
||||
clrCMD (devc); } /* clr cch cmd */
|
||||
return SCPE_OK;
|
||||
|
||||
case FNC_LA: /* arec, need cyl */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarc = DA_GETCYL (dqd_obuf); /* take cyl word */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
uptr -> FNC = FNC_LA1; } /* advance state */
|
||||
sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_LA1: /* arec, need hd/sec */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_rarh = DA_GETHD (dqd_obuf); /* get head */
|
||||
dqc_rars = DA_GETSC (dqd_obuf); /* get sector */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); } /* clr dch cmd */
|
||||
else { sim_activate (uptr, dqc_xtime); /* no, wait more */
|
||||
return SCPE_OK; }
|
||||
break; /* done */
|
||||
|
||||
case FNC_STA: /* read status */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqd_ibuf = dqc_sta[drv] | ((dqc_sta[drv] & STA_ALLERR)? STA_ERR: 0);
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */
|
||||
~(STA_DTE | STA_FLG | STA_AER | STA_EOC);
|
||||
dqc_busy = 0; } /* ctlr is free */
|
||||
else sim_activate (uptr, dqc_xtime); /* wait more */
|
||||
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_CHK: /* check, need cnt */
|
||||
if (CMD (devd)) { /* dch active? */
|
||||
dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dqc_ctime); /* schedule op */
|
||||
uptr -> FNC = FNC_CHK1; } /* advance state */
|
||||
else sim_activate (uptr, dqc_xtime); /* wait more */
|
||||
return SCPE_OK;
|
||||
case FNC_CHK1:
|
||||
if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC))
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER;
|
||||
else { maxsc = ((2 - (dqc_rarh & 1)) * DQ_NUMSC) - dqc_rars;
|
||||
if (dqc_cnt > maxsc) { /* too many sec? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_EOC;
|
||||
dqc_rarh = dqc_rarh & ~1; /* rar = 0/2, 0 */
|
||||
dqc_rars = 0; }
|
||||
else { i = dqc_rars + dqc_cnt; /* final sector */
|
||||
dqc_rars = i % DQ_NUMSC; /* reposition */
|
||||
dqc_rarh = dqc_rarh ^ ((i / DQ_NUMSC) & 1); } }
|
||||
break; /* done */
|
||||
|
||||
case FNC_RD: /* read */
|
||||
case FNC_RA: /* read addr */
|
||||
if (!CMD (devd)) break; /* dch clr? done */
|
||||
if (FLG (devd)) dqc_sta[drv] = dqc_sta[drv] | STA_DTE;
|
||||
if (dq_ptr == 0) { /* new sector? */
|
||||
if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) {
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER;
|
||||
break; }
|
||||
if (dqc_eoc) { /* end of cyl? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_EOC;
|
||||
break; }
|
||||
da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* get addr */
|
||||
dqc_rars = dqc_rars + 1; /* incr address */
|
||||
if (dqc_rars >= DQ_NUMSC) { /* end of trk? */
|
||||
dqc_rars = 0; /* wrap to */
|
||||
dqc_rarh = dqc_rarh ^ 1; /* next cyl */
|
||||
dqc_eoc = ((dqc_rarh & 1) == 0); } /* calc eoc */
|
||||
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) dq_ptr = 0; /* wrap if last */
|
||||
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 (dqc_eoc) { /* end of cyl? */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* set status */
|
||||
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 (FLG (devd)) dqc_sta[drv] = dqc_sta[drv] | STA_DTE;
|
||||
dqxb[dq_ptr++] = dqd_obuf; /* store word */
|
||||
if (!CMD (devd)) { /* dch clr? done */
|
||||
for ( ; dq_ptr < DQ_NUMWD; dq_ptr++) dqxb[dq_ptr] = 0; }
|
||||
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? */
|
||||
if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) {
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_AER;
|
||||
break; }
|
||||
da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* get addr */
|
||||
dqc_rars = dqc_rars + 1; /* incr address */
|
||||
if (dqc_rars >= DQ_NUMSC) { /* end of trk? */
|
||||
dqc_rars = 0; /* wrap to */
|
||||
dqc_rarh = dqc_rarh ^ 1; /* next cyl */
|
||||
dqc_eoc = ((dqc_rarh & 1) == 0); } /* calc eoc */
|
||||
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)) { /* dch active? */
|
||||
setFLG (devd); /* set dch flg */
|
||||
clrCMD (devd); /* clr dch cmd */
|
||||
sim_activate (uptr, dqc_xtime); /* sched next word */
|
||||
return SCPE_OK; }
|
||||
break; } /* end case fnc */
|
||||
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);
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Start disk operation */
|
||||
|
||||
void dq_go (int32 fnc, int32 drv, int32 time, int32 dev)
|
||||
{
|
||||
if (dev && ((dqc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */
|
||||
dqc_sta[drv] = STA_NRDY; /* not attached */
|
||||
setFLG (dev); /* set cch flag */
|
||||
clrCMD (dev); } /* clr cch cmd */
|
||||
else { dqc_busy = drv + 1; /* set busy */
|
||||
dq_ptr = 0; /* init buf ptr */
|
||||
dqc_eoc = 0; /* clear end cyl */
|
||||
dqc_unit[drv].FNC = fnc; /* save function */
|
||||
sim_activate (&dqc_unit[drv], time); } /* activate unit */
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
dqc_eoc = 0;
|
||||
dqd_xfer = dqd_wval = 0;
|
||||
dq_ptr = 0;
|
||||
dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear rar */
|
||||
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_sta[i] = (dqc_unit[i].flags & UNIT_ATT)? 0: STA_NRDY; }
|
||||
dqc_rarc[i] = dqc_rarh[i] = dqc_rars[i] = 0; /* clear rar */
|
||||
dqc_sta[i] = 0; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat dqc_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
int32 drv;
|
||||
t_stat r;
|
||||
|
||||
drv = uptr - dqc_dev.units; /* get drive no */
|
||||
r = attach_unit (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r;
|
||||
dqc_sta[drv] = dqc_sta[drv] & ~STA_NRDY; /* update status */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat dqc_detach (UNIT* uptr)
|
||||
{
|
||||
int32 drv;
|
||||
|
||||
drv = uptr - dqc_dev.units; /* get drive no */
|
||||
dqc_sta[drv] = dqc_sta[drv] | STA_NRDY; /* update status */
|
||||
if (drv == (dqc_busy + 1)) dqc_busy = 0; /* update busy */
|
||||
sim_cancel (uptr); /* cancel op */
|
||||
return detach_unit (uptr); /* detach unit */
|
||||
}
|
||||
|
||||
/* Write lock/enable routine */
|
||||
|
||||
t_stat dqc_vlock (UNIT *uptr, int32 val)
|
||||
{
|
||||
if (uptr -> flags & UNIT_ATT) return SCPE_ARG;
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 2883/2884 bootstrap routine (subset HP 12992A ROM) */
|
||||
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
#define CHANGE_ADDR (1 << 23)
|
||||
|
||||
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 */
|
||||
CHANGE_ADDR }; /* -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_ADDR) /* memory limit? */
|
||||
M[PC + i] = (-PC) & DMASK;
|
||||
else if (dboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (dboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = dboot[i]; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -23,16 +23,19 @@
|
||||
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 fixed head disk
|
||||
12619B drum
|
||||
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. Further, its
|
||||
control flip-flop is not wired into the interrupt chain. Accordingly,
|
||||
the simulator uses command rather than control for the data channel.
|
||||
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.
|
||||
|
||||
10-Nov-02 RMS Added BOOT command
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
@@ -51,9 +54,9 @@
|
||||
/* Command word */
|
||||
|
||||
#define CW_WR 0100000 /* write vs read */
|
||||
#define CW_V_FTRK 7
|
||||
#define CW_V_FTRK 7 /* fhd track */
|
||||
#define CW_M_FTRK 0177
|
||||
#define CW_V_DTRK 5
|
||||
#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)? \
|
||||
@@ -62,9 +65,9 @@
|
||||
#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
|
||||
#define CW_V_FSEC 0 /* fhd sector */
|
||||
#define CW_M_FSEC 0177
|
||||
#define CW_V_DSEC 0
|
||||
#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): \
|
||||
@@ -90,20 +93,24 @@
|
||||
((double) ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC))))
|
||||
|
||||
extern UNIT cpu_unit;
|
||||
extern uint16 *M;
|
||||
extern int32 PC;
|
||||
extern int32 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 = 5; /* time per word*/
|
||||
int32 dr_time = 10; /* time per word */
|
||||
|
||||
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_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);
|
||||
|
||||
@@ -115,8 +122,8 @@ t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
*/
|
||||
|
||||
DIB dr_dib[] = {
|
||||
{ DRD, 1, 0, 0, 0, 0, &drdio },
|
||||
{ DRC, 1, 0, 0, 0, 0, &drcio } };
|
||||
{ DRD, 0, 0, 0, 0, &drdio },
|
||||
{ DRC, 0, 0, 0, 0, &drcio } };
|
||||
|
||||
#define drd_dib dr_dib[0]
|
||||
#define drc_dib dr_dib[1]
|
||||
@@ -132,19 +139,19 @@ REG drd_reg[] = {
|
||||
{ FLDATA (FBF, drd_dib.fbf, 0) },
|
||||
{ ORDATA (BPTR, drd_ptr, 6) },
|
||||
{ ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, drd_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB drd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &drd_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&drd_dib, DEV_DISABLE };
|
||||
|
||||
/* DRC data structures
|
||||
|
||||
@@ -168,7 +175,6 @@ REG drc_reg[] = {
|
||||
{ DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, dr_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, drc_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB drc_mod[] = {
|
||||
@@ -184,19 +190,16 @@ MTAB drc_mod[] = {
|
||||
{ UNIT_DR, 917504+1, NULL, "896K", &dr_set_size },
|
||||
{ UNIT_DR, 1048576+1, NULL, "1024K", &dr_set_size },
|
||||
{ UNIT_DR, 1572864+1, NULL, "1536K", &dr_set_size },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED",
|
||||
&set_enb, NULL, &drd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED",
|
||||
&set_dis, NULL, &drd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &drd_dib },
|
||||
&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,
|
||||
NULL, NULL, NULL };
|
||||
&drc_boot, NULL, NULL,
|
||||
&drc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
@@ -204,17 +207,8 @@ int32 drdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd, t;
|
||||
|
||||
devd = IR & DEVMASK; /* get device no */
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & 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 */
|
||||
drd_obuf = dat;
|
||||
break;
|
||||
@@ -225,31 +219,30 @@ case ioLIX: /* load */
|
||||
dat = drd_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC */
|
||||
clrCMD (devd); /* clr "ctl" */
|
||||
clrFLG (devd); /* clr flg */
|
||||
drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */
|
||||
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); }
|
||||
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 & HC) { clrFLG (devd); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
int32 drcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devc, st;
|
||||
int32 st;
|
||||
|
||||
devc = IR & DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioSFC: /* skip flag clear */
|
||||
PC = (PC + 1) & VAMASK;
|
||||
@@ -260,10 +253,11 @@ case ioOTX: /* output */
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
if (drc_unit.flags & UNIT_ATT)
|
||||
st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta |
|
||||
(sim_is_active (&drc_unit)? DRS_BSY: 0);
|
||||
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; }
|
||||
@@ -274,40 +268,39 @@ return dat;
|
||||
|
||||
t_stat drc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 devc, devd, trk, sec;
|
||||
int32 devd, trk, sec;
|
||||
uint32 da;
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) {
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
drc_sta = DRS_ABO;
|
||||
return IORETURN (dr_stopioe, SCPE_UNATT); }
|
||||
|
||||
drc_sta = drc_sta | DRS_SAC;
|
||||
devc = drc_dib.devno; /* get cch devno */
|
||||
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 (((t_addr) (da + drd_ptr)) >= uptr -> hwmark)
|
||||
uptr -> hwmark = da + drd_ptr + 1; }
|
||||
if ((da < uptr->capac) && (sec < DR_NUMSC)) {
|
||||
*(((uint16 *) uptr->filebuf) + da + drd_ptr) = drd_obuf;
|
||||
if (((t_addr) (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 */
|
||||
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; }
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
@@ -321,9 +314,9 @@ 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 */
|
||||
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;
|
||||
@@ -333,6 +326,7 @@ return ptr;
|
||||
|
||||
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 */
|
||||
@@ -344,13 +338,52 @@ return SCPE_OK;
|
||||
|
||||
/* Set size routine */
|
||||
|
||||
/* Set size command validation routine */
|
||||
|
||||
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
|
||||
if (val & 1) uptr -> flags = uptr -> flags | UNIT_DR;
|
||||
else uptr -> flags = uptr -> flags & ~UNIT_DR;
|
||||
uptr -> capac = val & ~1;
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
if (val & 1) uptr->flags = uptr->flags | UNIT_DR;
|
||||
else uptr->flags = uptr->flags & ~UNIT_DR;
|
||||
uptr->capac = val & ~1;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
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.
|
||||
|
||||
21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms
|
||||
|
||||
The HP2100 uses a unique binary floating point format:
|
||||
|
||||
15 14 0
|
||||
@@ -43,253 +45,266 @@
|
||||
|
||||
Unpacked floating point numbers are stored in structure ufp
|
||||
|
||||
sign = fraction sign, 0 = +, 1 = -
|
||||
exp = exponent, 2's complement
|
||||
h'l = fraction, 2's comp, with 1 high guard bit
|
||||
h'l = fraction, 2's comp, left justified
|
||||
|
||||
Questions:
|
||||
1. Are fraction and exponent magnitude or 2's complement? 2's complement
|
||||
2. Do operations round? yes, with IEEE like standards (sticky bits)
|
||||
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 sign; /* sign */
|
||||
int32 exp; /* exp */
|
||||
uint32 h; /* frac */
|
||||
uint32 l; };
|
||||
uint32 fr; }; /* frac */
|
||||
|
||||
#define FP_V_SIGN 31 /* sign */
|
||||
#define FP_M_SIGN 01
|
||||
#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN)
|
||||
#define FP_V_FRH 8 /* fraction */
|
||||
#define FP_M_FRH 077777777
|
||||
#define FP_FRH (FP_M_FRH << FP_V_FRH)
|
||||
#define FP_V_FR 8 /* fraction */
|
||||
#define FP_M_FR 077777777
|
||||
#define FP_V_EXP 1 /* exponent */
|
||||
#define FP_M_EXP 0177
|
||||
#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP)
|
||||
#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 UFP_GUARD 1 /* 1 extra left */
|
||||
#define UFP_V_SIGN (FP_V_SIGN - UFP_GUARD) /* sign */
|
||||
#define UFP_SIGN (1 << UFP_V_SIGN)
|
||||
#define UFP_CRY (1 << (UFP_V_SIGN + 1)) /* carry */
|
||||
#define UFP_NORM (1 << (UFP_V_SIGN - 1)) /* normalized */
|
||||
#define UFP_V_LOW (FP_V_FRH - UFP_GUARD) /* low bit */
|
||||
#define UFP_LOW (1 << UFP_V_LOW)
|
||||
#define UFP_RND (1 << (UFP_V_LOW - 1)) /* round */
|
||||
#define UFP_STKY (UFP_RND - 1) /* sticky bits */
|
||||
#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 HFMASK 0x7FFFFFFF /* hi frac mask */
|
||||
#define LFMASK 0xFFFFFFFF /* lo frac mask */
|
||||
#define DMASK32 0xFFFFFFFF
|
||||
|
||||
/* Fraction shift; 0 < shift < 32 */
|
||||
|
||||
#define FR_ARSH(v,s) v.l = ((v.l >> (s)) | \
|
||||
(v.h << (32 - (s)))) & LFMASK; \
|
||||
v.h = ((v.h >> (s)) | ((v.h & UFP_SIGN)? \
|
||||
(LFMASK << (32 - (s))): 0)) & HFMASK
|
||||
#define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \
|
||||
(DMASK32 << (32 - (s))): 0)) & DMASK32
|
||||
|
||||
#define FR_LRSH(v,s) v.l = ((v.l >> (s)) | \
|
||||
(v.h << (32 - (s)))) & LFMASK; \
|
||||
v.h = (v.h >> (s)) & HFMASK
|
||||
|
||||
#define FR_NEG(v) v.l = (~v.l + 1) & LFMASK; \
|
||||
v.h = (~v.h + (v.l == 0)) & HFMASK
|
||||
|
||||
#define FR_NEGH(v) v = (~v + 1) & HFMASK
|
||||
#define FR_NEG(v) ((~(v) + 1) & DMASK32)
|
||||
|
||||
extern uint16 *M;
|
||||
void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs);
|
||||
uint32 UnpackFP (struct ufp *fop, uint32 opnd);
|
||||
void NegFP (struct ufp *fop);
|
||||
void NormFP (struct ufp *fop);
|
||||
int32 StoreFP (struct ufp *fop, t_bool rnd);
|
||||
uint32 StoreFP (struct ufp *fop);
|
||||
|
||||
/* Floating to integer conversion */
|
||||
|
||||
int32 f_fix (void)
|
||||
uint32 f_fix (void)
|
||||
{
|
||||
struct ufp res;
|
||||
struct ufp fop;
|
||||
uint32 res = 0;
|
||||
|
||||
UnpackFP (&res, FPAB, 0); /* unpack A-B, norm */
|
||||
if ((res.h == 0) || (res.exp <= 0)) { /* result zero? */
|
||||
AR = 0;
|
||||
return 0; }
|
||||
if (res.exp > 15) {
|
||||
AR = 077777;
|
||||
return 1; }
|
||||
FR_ARSH (res, (30 - res.exp)); /* right align frac */
|
||||
if (res.sign && res.l) res.h = res.h + 1; /* round? */
|
||||
AR = res.h & DMASK; /* store result */
|
||||
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 */
|
||||
|
||||
void f_flt (void)
|
||||
uint32 f_flt (void)
|
||||
{
|
||||
struct ufp res = { 0, 15, 0, 0 }; /* +, 2**15 */
|
||||
struct ufp res = { 15, 0 }; /* +, 2**15 */
|
||||
|
||||
res.h = ((uint32) AR) << 15; /* left justify */
|
||||
if (res.h & UFP_SIGN) res.sign = 1; /* set sign */
|
||||
NormFP (&res); /* normalize */
|
||||
StoreFP (&res, 0); /* store result */
|
||||
return;
|
||||
res.fr = ((uint32) AR) << 16; /* left justify */
|
||||
StoreFP (&res); /* store result */
|
||||
return 0; /* clr overflow */
|
||||
}
|
||||
|
||||
/* Floating point add/subtract */
|
||||
|
||||
int32 f_as (uint32 opnd, t_bool sub)
|
||||
uint32 f_as (uint32 opnd, t_bool sub)
|
||||
{
|
||||
struct ufp fop1, fop2, t;
|
||||
int32 ediff;
|
||||
|
||||
UnpackFP (&fop1, FPAB, 0); /* unpack A-B, norm */
|
||||
UnpackFP (&fop2, opnd, 0); /* get op, norm */
|
||||
UnpackFP (&fop1, FPAB); /* unpack A-B */
|
||||
UnpackFP (&fop2, opnd); /* get op */
|
||||
if (sub) { /* subtract? */
|
||||
fop2.sign = fop2.sign ^ 1; /* negate sign */
|
||||
fop2.h = FR_NEGH (fop2.h); /* negate frac */
|
||||
if (fop2.h & UFP_SIGN) { /* -1/2? */
|
||||
fop2.h = UFP_NORM; /* special case */
|
||||
fop2.exp = fop2.exp + 1; } }
|
||||
if (fop1.h == 0) fop1 = fop2; /* op1 = 0? res = op2 */
|
||||
else if (fop2.h != 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) { FR_ARSH (fop2, ediff); } /* denorm, signed */
|
||||
fop1.h = fop1.h + fop2.h; /* add fractions */
|
||||
if (fop1.sign ^ fop2.sign) { /* eff subtract */
|
||||
if (fop1.h & UFP_SIGN) fop1.sign = 1; /* result neg? */
|
||||
else fop1.sign = 0;
|
||||
NormFP (&fop1); } /* normalize result */
|
||||
else if (fop1.h & (fop1.sign? UFP_CRY: UFP_SIGN)) { /* add, cry out? */
|
||||
fop1.h = fop1.h >> 1; /* renormalize */
|
||||
fop1.exp = fop1.exp + 1; } /* incr exp */
|
||||
} /* end if ediff */
|
||||
} /* end if fop2 */
|
||||
return StoreFP (&fop1, 1); /* store result */
|
||||
fop2.fr = FR_NEG (fop2.fr); /* negate frac */
|
||||
if (fop2.fr == 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 */
|
||||
/* Floating point multiply - passes diagnostic */
|
||||
|
||||
int32 f_mul (uint32 opnd)
|
||||
uint32 f_mul (uint32 opnd)
|
||||
{
|
||||
struct ufp fop1, fop2;
|
||||
struct ufp res = { 0, 0, 0, 0 };
|
||||
int32 i;
|
||||
struct ufp res = { 0, 0 };
|
||||
int32 shi1, shi2, t1, t2, t3, t4, t5;
|
||||
|
||||
UnpackFP (&fop1, FPAB, 1); /* unpack |A-B|, norm */
|
||||
UnpackFP (&fop2, opnd, 1); /* unpack |op|, norm */
|
||||
if (fop1.h && fop2.h) { /* if both != 0 */
|
||||
res.sign = fop1.sign ^ fop2.sign; /* sign = diff */
|
||||
res.exp = fop1.exp + fop2.exp; /* exp = sum */
|
||||
for (i = 0; i < 24; i++) { /* 24 iterations */
|
||||
if (fop2.h & UFP_LOW) /* mplr bit set? */
|
||||
res.h = res.h + fop1.h; /* add mpcn to res */
|
||||
fop2.h = fop2.h >> 1; /* shift mplr */
|
||||
FR_LRSH (res, 1); } /* shift res */
|
||||
if (res.sign) FR_NEG (res); /* correct sign */
|
||||
NormFP (&res); /* normalize */
|
||||
}
|
||||
return StoreFP (&res, 1); /* store */
|
||||
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 */
|
||||
/* Floating point divide - reverse engineered from diagnostic */
|
||||
|
||||
int32 f_div (uint32 opnd)
|
||||
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, 0, 0 };
|
||||
int32 i;
|
||||
struct ufp quo = { 0, 0 };
|
||||
uint32 ba, q0, q1, q2, dvrh;
|
||||
|
||||
UnpackFP (&fop1, FPAB, 1); /* unpack |A-B|, norm */
|
||||
UnpackFP (&fop2, opnd, 1); /* unpack |op|, norm */
|
||||
if (fop2.h == 0) return 1; /* div by zero? */
|
||||
if (fop1.h) { /* dvd != 0? */
|
||||
quo.sign = fop1.sign ^ fop2.sign; /* sign = diff */
|
||||
quo.exp = fop1.exp - fop2.exp; /* exp = diff */
|
||||
if (fop1.h < fop2.h) { /* will sub work? */
|
||||
fop1.h = fop1.h << 1; /* ensure success */
|
||||
quo.exp = quo.exp - 1; }
|
||||
for (i = 0; i < 24; i++) { /* 24 digits */
|
||||
quo.h = quo.h << 1; /* shift quotient */
|
||||
if (fop1.h >= fop2.h) { /* subtract work? */
|
||||
fop1.h = fop1.h - fop2.h; /* decrement */
|
||||
quo.h = quo.h + UFP_RND; } /* add quo bit */
|
||||
fop1.h = fop1.h << 1; } /* shift divd */
|
||||
} /* end if fop1.h */
|
||||
if (quo.sign) quo.h = FR_NEGH (quo.h); /* correct sign */
|
||||
NormFP (&quo); /* negate */
|
||||
return StoreFP (&quo, 1); /* store result */
|
||||
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 */
|
||||
|
||||
void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs)
|
||||
uint32 UnpackFP (struct ufp *fop, uint32 opnd)
|
||||
{
|
||||
fop -> h = (opnd & FP_FRH) >> UFP_GUARD; /* get frac, guard */
|
||||
if (fop -> h) { /* non-zero? */
|
||||
fop -> sign = FP_GETSIGN (opnd); /* get sign */
|
||||
fop -> exp = FP_GETEXP (opnd); /* get exp */
|
||||
if (FP_GETEXPS (opnd)) /* get exp sign */
|
||||
fop -> exp = fop -> exp | ~FP_M_EXP; /* if -, sext */
|
||||
if (abs && fop -> sign) { /* want abs val? */
|
||||
fop -> h = FR_NEGH (fop -> h); /* negate frac*/
|
||||
if (fop -> h == UFP_SIGN) { /* -1/2? */
|
||||
fop -> h = fop -> h >> 1; /* special case */
|
||||
fop -> exp = fop -> exp + 1; } }
|
||||
NormFP (fop); } /* normalize */
|
||||
else fop -> sign = fop -> exp = 0; /* clean zero */
|
||||
fop -> l = 0;
|
||||
return;
|
||||
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 -> h | fop -> l) { /* any fraction? */
|
||||
uint32 test = (fop -> h >> 1) & UFP_NORM;
|
||||
while ((fop -> h & UFP_NORM) == test) { /* until norm */
|
||||
fop -> exp = fop -> exp - 1;
|
||||
fop -> h = (fop -> h << 1) | (fop -> l >> 31);
|
||||
fop -> l = fop -> l << 1; } }
|
||||
else fop -> sign = fop -> exp = 0; /* clean 0 */
|
||||
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 */
|
||||
|
||||
int32 StoreFP (struct ufp *fop, t_bool rnd)
|
||||
uint32 StoreFP (struct ufp *fop)
|
||||
{
|
||||
int32 hi, ov;
|
||||
uint32 sign, svfr, hi, ov = 0;
|
||||
|
||||
if (rnd && (fop -> h & UFP_RND) &&
|
||||
((fop -> sign == 0) || (fop -> h & UFP_STKY) || fop -> l)) {
|
||||
fop -> h = fop -> h + UFP_RND; /* round */
|
||||
if (fop -> h & ((fop -> sign)? UFP_CRY: UFP_SIGN)) {
|
||||
fop -> h = fop -> h >> 1;
|
||||
fop -> exp = fop -> exp + 1; } }
|
||||
if (fop -> h == 0) hi = ov = 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 -> h << UFP_GUARD) & FP_FRH) | /* merge frac */
|
||||
((fop -> exp & FP_M_EXP) << FP_V_EXP); /* and exp */
|
||||
if (fop -> exp < 0) hi = hi | (1 << FP_V_EXPS); } /* add exp sign */
|
||||
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;
|
||||
|
||||
174
HP2100/hp2100_lps.c
Normal file
174
HP2100/hp2100_lps.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/* hp2100_lps.c: HP 2100 12653A line printer simulator
|
||||
|
||||
Copyright (c) 1993-2002, 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)
|
||||
|
||||
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 int32 PC;
|
||||
extern int32 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, 32), 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, "DIAG", "DIAG", NULL },
|
||||
{ UNIT_DIAG, 0, "PRINTER", "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 { setCMD (dev); /* STC */
|
||||
setCTL (dev); /* set ctl, cmd */
|
||||
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 = ftell (lps_unit.fileref); /* 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,4 +1,4 @@
|
||||
/* hp2100_lp.c: HP 2100 12653A line printer simulator
|
||||
/* hp2100_lpt.c: HP 2100 12845A line printer simulator
|
||||
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
@@ -23,29 +23,37 @@
|
||||
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 12653A line printer
|
||||
lpt 12845A line printer
|
||||
|
||||
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
|
||||
24-Oct-02 RMS Cloned from 12653A
|
||||
*/
|
||||
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
#define LPT_BUSY 0000001 /* busy */
|
||||
#define LPT_NRDY 0100000 /* not ready */
|
||||
#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 int32 PC;
|
||||
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
int32 lpt_ctime = 10; /* char time */
|
||||
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
|
||||
|
||||
@@ -54,7 +62,7 @@ t_stat lpt_reset (DEVICE *dptr);
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
DIB lpt_dib = { LPT, 1, 0, 0, 0, 0, &lptio };
|
||||
DIB lpt_dib = { LPT, 0, 0, 0, 0, &lptio };
|
||||
|
||||
UNIT lpt_unit = {
|
||||
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
@@ -65,28 +73,25 @@ REG lpt_reg[] = {
|
||||
{ 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, 32), 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 },
|
||||
{ FLDATA (*DEVENB, lpt_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB lpt_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED",
|
||||
&set_enb, NULL, &lpt_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED",
|
||||
&set_dis, NULL, &lpt_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &lpt_dib },
|
||||
&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, NULL, NULL };
|
||||
NULL, &lpt_attach, NULL,
|
||||
&lpt_dib, DEV_DISABLE };
|
||||
|
||||
/* Line printer IOT routine */
|
||||
|
||||
@@ -94,10 +99,10 @@ int32 lptio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -106,43 +111,64 @@ case ioSFS: /* skip flag set */
|
||||
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
lpt_unit.buf = dat & 0177;
|
||||
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) == 0) dat = dat | LPT_BUSY | LPT_NRDY;
|
||||
else if (sim_is_active (&lpt_unit)) dat = dat | LPT_BUSY;
|
||||
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 & AB) { /* CLC */
|
||||
if (IR & I_CTL) { /* CLC */
|
||||
clrCMD (dev); /* clear ctl, cmd */
|
||||
clrCTL (dev); }
|
||||
else { setCMD (dev); /* STC */
|
||||
setCTL (dev); /* set ctl, cmd */
|
||||
sim_activate (&lpt_unit, /* schedule op */
|
||||
(lpt_unit.buf < 040)? lpt_unit.wait: lpt_ctime); }
|
||||
(lpt_unit.buf & LPT_CTL)? lpt_unit.wait: lpt_ctime); }
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & HC) { clrFLG (dev); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
t_stat lpt_svc (UNIT *uptr)
|
||||
{
|
||||
int32 dev;
|
||||
int32 i, skip, chan, dev;
|
||||
|
||||
dev = lpt_dib.devno; /* get dev no */
|
||||
clrCMD (dev); /* clear cmd */
|
||||
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (lpt_stopioe, SCPE_UNATT);
|
||||
setFLG (dev); /* set flag, fbf */
|
||||
if (putc (lpt_unit.buf & 0177, lpt_unit.fileref) == EOF) {
|
||||
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 (lpt_unit.fileref);
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */
|
||||
lpt_unit.pos = ftell (uptr->fileref); /* update pos */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -156,3 +182,11 @@ 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,4 +1,4 @@
|
||||
/* hp2100_ms.c: HP 2100 13181A magnetic tape simulator
|
||||
/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator
|
||||
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
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 nine track magnetic tape
|
||||
ms 13181A 7970B 800bpi nine track magnetic tape
|
||||
13183A 7970E 1600bpi nine track magnetic tape
|
||||
|
||||
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
|
||||
|
||||
@@ -50,7 +54,9 @@
|
||||
|
||||
#define MS_NUMDR 4 /* number of drives */
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_PNU (1 << UNIT_V_PNU)
|
||||
#define DB_N_SIZE 16 /* max data buf */
|
||||
#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
|
||||
#define DBMASK (DBSIZE - 1)
|
||||
@@ -60,66 +66,87 @@
|
||||
|
||||
/* Command - msc_fnc */
|
||||
|
||||
#define FNC_CLR 0110 /* clear */
|
||||
#define FNC_GAP 0015 /* write gap */
|
||||
#define FNC_GFM 0215 /* gap+file mark */
|
||||
#define FNC_RC 0023 /* read */
|
||||
#define FNC_WC 0031 /* write */
|
||||
#define FNC_FSR 0003 /* forward space */
|
||||
#define FNC_BSR 0041 /* backward space */
|
||||
#define FNC_FSF 0203 /* forward file */
|
||||
#define FNC_BSF 0241 /* backward file */
|
||||
#define FNC_REW 0101 /* rewind */
|
||||
#define FNC_RWS 0105 /* rewind and offline */
|
||||
#define FNC_WFM 0211 /* write file mark */
|
||||
#define FNC_CHS 0400 /* change select */
|
||||
#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 0001 /* motion */
|
||||
#define FNF_OFL 0004
|
||||
#define FNF_WRT 0010 /* write */
|
||||
#define FNF_REV 0040 /* reverse */
|
||||
#define FNF_RWD 0100 /* rewind */
|
||||
#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_ODD 04000 /* odd bytes */
|
||||
#define STA_REW 02000 /* rewinding (u) */
|
||||
#define STA_TBSY 01000 /* transport busy (d) */
|
||||
#define STA_BUSY 00400 /* ctrl busy */
|
||||
#define STA_EOF 00200 /* end of file */
|
||||
#define STA_BOT 00100 /* beg of tape (d) */
|
||||
#define STA_EOT 00040 /* end of tape (u) */
|
||||
#define STA_TIM 00020 /* timing error */
|
||||
#define STA_REJ 00010 /* programming error */
|
||||
#define STA_WLK 00004 /* write locked (d) */
|
||||
#define STA_PAR 00002 /* parity error */
|
||||
#define STA_LOCAL 00001 /* local (d) */
|
||||
#define STA_STATIC (STA_ODD|STA_BUSY|STA_EOF|STA_TIM|STA_REJ|STA_PAR)
|
||||
#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 int32 PC;
|
||||
extern uint16 *M;
|
||||
extern int32 PC, SR;
|
||||
extern int32 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_xtime = 10; /* data xfer time */
|
||||
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 msc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_bool ms_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
|
||||
t_bool ms_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
|
||||
t_bool ms_forwsp (UNIT *uptr, int32 *err);
|
||||
t_bool ms_backsp (UNIT *uptr, int32 *err);
|
||||
|
||||
int32 ms_wrtrec (UNIT *uptr, t_mtrlnt lnt);
|
||||
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
|
||||
@@ -128,8 +155,8 @@ t_bool ms_backsp (UNIT *uptr, int32 *err);
|
||||
*/
|
||||
|
||||
DIB ms_dib[] = {
|
||||
{ MSD, 1, 0, 0, 0, 0, &msdio },
|
||||
{ MSC, 1, 0, 0, 0, 0, &mscio } };
|
||||
{ MSD, 0, 0, 0, 0, &msdio },
|
||||
{ MSC, 0, 0, 0, 0, &mscio } };
|
||||
|
||||
#define msd_dib ms_dib[0]
|
||||
#define msc_dib ms_dib[1]
|
||||
@@ -146,19 +173,19 @@ REG msd_reg[] = {
|
||||
{ DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
|
||||
{ DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
|
||||
{ ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, msd_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB msd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &msd_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&msd_dib, 0 };
|
||||
|
||||
/* MSC data structures
|
||||
|
||||
@@ -183,33 +210,37 @@ REG msc_reg[] = {
|
||||
{ FLDATA (CTL, msc_dib.ctl, 0) },
|
||||
{ FLDATA (FLG, msc_dib.flg, 0) },
|
||||
{ FLDATA (FBF, msc_dib.fbf, 0) },
|
||||
{ URDATA (POS, msc_unit[0].pos, 8, 32, 0, MS_NUMDR, PV_LEFT) },
|
||||
{ URDATA (FNC, msc_unit[0].FNC, 8, 12, 0, MS_NUMDR, REG_HRO) },
|
||||
{ URDATA (POS, msc_unit[0].pos, 10, 32, 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) },
|
||||
{ URDATA (WLK, msc_unit[0].flags, 8, 1, UNIT_V_WLK, MS_NUMDR, REG_HRO) },
|
||||
{ FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
|
||||
{ ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, msc_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB msc_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", &msc_vlock },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &msc_vlock },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED",
|
||||
&set_enb, NULL, &msd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED",
|
||||
&set_dis, NULL, &msd_dib },
|
||||
{ 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_dib },
|
||||
&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,
|
||||
NULL, NULL, NULL };
|
||||
&msc_boot, &msc_attach, &msc_detach,
|
||||
&msc_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
@@ -217,10 +248,10 @@ int32 msdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & DEVMASK; /* get device no */
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devd); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -238,15 +269,16 @@ case ioLIX: /* load */
|
||||
dat = msd_buf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC */
|
||||
clrCTL (devd); /* clr ctl, cmd */
|
||||
clrCMD (devd); }
|
||||
else { setCTL (devd); /* STC */
|
||||
setCMD (devd); } /* set ctl, cmd */
|
||||
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 & HC) { clrFLG (devd); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -258,11 +290,11 @@ static const uint8 map_sel[16] = {
|
||||
0, 0, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
|
||||
devc = IR & DEVMASK; /* get device no */
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
devd = devc - 1;
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -271,57 +303,61 @@ case ioSFS: /* skip flag set */
|
||||
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
msc_buf = dat = dat & 07777;
|
||||
if (dat == FNC_CLR) { /* clear? */
|
||||
for (i = 0; i < MS_NUMDR; i++) {
|
||||
if ((msc_unit[i].UST & STA_REW) == 0)
|
||||
sim_cancel (&msc_unit[i]); }
|
||||
clrCTL (devc); /* init device */
|
||||
clrFLG (devc);
|
||||
clrCTL (devd);
|
||||
clrFLG (devd);
|
||||
msc_sta = msd_buf = msc_buf = msc_1st = 0;
|
||||
break; }
|
||||
if (msc_sta & STA_BUSY) {
|
||||
msc_sta = msc_sta | STA_REJ;
|
||||
break; }
|
||||
if (dat & FNC_CHS) {
|
||||
msc_usl = map_sel[FNC_GETSEL (dat)];
|
||||
uptr = msc_dev.units + msc_usl; }
|
||||
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 -> pos == 0)) ||
|
||||
((dat & FNF_WRT) && (uptr -> flags & UNIT_WPRT)))
|
||||
msc_sta = msc_sta | STA_REJ;
|
||||
((dat & FNF_REV) && (uptr->UST & STA_BOT)) ||
|
||||
((dat & FNF_WRT) && (uptr->flags & UNIT_WPRT)))
|
||||
msc_sta = msc_sta | STA_REJ; /* reject? */
|
||||
break;
|
||||
case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
msc_sta = (msc_sta & STA_STATIC) | uptr -> UST;
|
||||
if (uptr -> flags & UNIT_ATT) {
|
||||
msc_sta = msc_sta & ~(STA_LOCAL | STA_WLK | STA_TBSY);
|
||||
if (sim_is_active (uptr))
|
||||
msc_sta = msc_sta | STA_TBSY;
|
||||
if (uptr -> flags & UNIT_WPRT)
|
||||
msc_sta = msc_sta | STA_WLK; }
|
||||
else msc_sta = msc_sta | STA_TBSY | STA_LOCAL;
|
||||
dat = dat | msc_sta;
|
||||
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 (uptr->flags & UNIT_WPRT) /* 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 & AB) { clrCTL (devc); } /* CLC */
|
||||
else if (!CTL (devc)) { /* STC, not busy? */
|
||||
uptr -> FNC = msc_buf; /* save function */
|
||||
if (uptr -> FNC & FNF_RWD) {
|
||||
uptr -> UST = STA_REW;
|
||||
sim_activate (uptr, msc_xtime); }
|
||||
else { uptr -> UST = 0; /* clr unit status */
|
||||
sim_activate (uptr, msc_ctime); }
|
||||
msc_sta = STA_BUSY;
|
||||
msc_1st = 1;
|
||||
setCTL (devc); }
|
||||
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))
|
||||
ms_wrtrec (uptr, ms_ptr | MTR_ERF);
|
||||
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 & HC) { clrFLG (devc); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -335,128 +371,182 @@ return dat;
|
||||
|
||||
t_stat msc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 devc, devd, err, i;
|
||||
static t_mtrlnt bceof = { 0 };
|
||||
int32 devc, devd, err, pnu;
|
||||
static t_mtrlnt i, bceof = { MTR_TMK };
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) { /* offline? */
|
||||
msc_sta = STA_LOCAL | STA_BUSY | STA_REJ;
|
||||
return IORETURN (msc_stopioe, SCPE_UNATT); }
|
||||
err = 0; /* assume no errors */
|
||||
devc = msc_dib.devno; /* get device nos */
|
||||
devd = msd_dib.devno;
|
||||
|
||||
if (uptr -> UST & STA_REW) { /* rewinding? */
|
||||
if (msc_sta & STA_BUSY) { /* controller busy? */
|
||||
sim_activate (uptr, msc_ctime); /* do real rewind */
|
||||
setFLG (devc); /* set cch flg */
|
||||
msc_sta = msc_sta & ~STA_BUSY; } /* update status */
|
||||
else { uptr -> pos = 0; /* rewind done */
|
||||
uptr -> UST = 0; /* offline? */
|
||||
if (uptr -> FNC & FNF_OFL) detach_unit (uptr); }
|
||||
return SCPE_OK; }
|
||||
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); }
|
||||
|
||||
pnu = MT_TST_PNU (uptr); /* get pos not upd */
|
||||
MT_CLR_PNU (uptr); /* and clear */
|
||||
|
||||
switch (uptr->FNC) { /* case on function */
|
||||
case FNC_REW: /* rewind */
|
||||
case FNC_RWS: /* rewind offline */
|
||||
if (uptr->UST & STA_REW) { /* rewind in prog? */
|
||||
uptr->pos = 0; /* 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" */
|
||||
|
||||
err = 0; /* assume no errors */
|
||||
switch (uptr -> FNC & 07777) { /* case on function */
|
||||
case FNC_GFM: /* gap file mark */
|
||||
case FNC_WFM: /* write file mark */
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
|
||||
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update tape pos */
|
||||
msc_sta = msc_sta | STA_EOF; /* set EOF status */
|
||||
fseek (uptr->fileref, uptr->pos, SEEK_SET);
|
||||
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref);
|
||||
msc_sta = STA_EOF; /* set EOF status */
|
||||
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr);
|
||||
else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update tape pos */
|
||||
break;
|
||||
|
||||
case FNC_GAP: /* erase gap */
|
||||
break;
|
||||
|
||||
case FNC_FSF:
|
||||
while (ms_forwsp (uptr, &err)) ; /* spc until EOF/EOT */
|
||||
break;
|
||||
|
||||
case FNC_FSR: /* space forward */
|
||||
ms_forwsp (uptr, &err);
|
||||
break;
|
||||
|
||||
case FNC_BSF:
|
||||
while (ms_backsp (uptr, &err)) ; /* spc until EOF/EOT */
|
||||
while (ms_backsp (uptr, &err)) ; /* spc until EOF/BOT */
|
||||
break;
|
||||
|
||||
case FNC_BSR: /* space reverse */
|
||||
ms_backsp (uptr, &err);
|
||||
if (!pnu) { /* position ok? */
|
||||
ms_backsp (uptr, &err); /* backspace */
|
||||
if (msc_sta & STA_ODD) msc_sta = msc_sta | STA_PAR; }
|
||||
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 */
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
|
||||
fxread (&ms_max, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
if ((err = ferror (uptr -> fileref)) ||
|
||||
feof (uptr -> fileref)) { /* error or eof? */
|
||||
uptr -> UST = STA_EOT;
|
||||
break; }
|
||||
if (ms_max == 0) { /* tape mark? */
|
||||
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
|
||||
msc_sta = msc_sta | STA_EOF;
|
||||
break; }
|
||||
ms_max = MTRL (ms_max); /* ignore errors */
|
||||
uptr -> pos = uptr -> pos + ((ms_max + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); /* update position */
|
||||
if (ms_max > DBSIZE) return SCPE_MTRLNT;/* record too long? */
|
||||
i = fxread (msxb, sizeof (int8), ms_max, uptr -> fileref);
|
||||
for ( ; i < ms_max; i++) msxb[i] = 0; /* fill with 0's */
|
||||
err = ferror (uptr -> fileref); }
|
||||
msc_1st = ms_ptr = 0; /* clr 1st flop */
|
||||
if (ms_rdlntf (uptr, &ms_max, &err)) { /* read rec lnt */
|
||||
if (!err) { /* tmk or eom? */
|
||||
sim_activate (uptr, msc_gtime); /* sched IRG */
|
||||
uptr->FNC = 0; /* NOP func */
|
||||
return SCPE_OK; }
|
||||
break; } /* err, done */
|
||||
if (ms_max > DBSIZE) return SCPE_MTRLNT; /* record too long? */
|
||||
i = fxread (msxb, sizeof (int8), ms_max, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) { /* error? */
|
||||
msc_sta = msc_sta | STA_PAR; /* set flag */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
break; }
|
||||
for ( ; i < ms_max; i++) msxb[i] = 0; /* fill with 0's */
|
||||
uptr->pos = uptr->pos + ((ms_max + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); } /* update position */
|
||||
if (ms_ptr < ms_max) { /* more chars? */
|
||||
if (FLG (devd)) msc_sta = msc_sta | STA_TIM;
|
||||
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; }
|
||||
if (ms_max & 1) msc_sta = msc_sta | STA_ODD;
|
||||
break;
|
||||
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;
|
||||
else { if (ms_ptr < DBSIZE) { /* room in buffer? */
|
||||
msxb[ms_ptr] = msd_buf >> 8;
|
||||
msxb[ms_ptr + 1] = msd_buf & 0377;
|
||||
ms_ptr = ms_ptr + 2; }
|
||||
else msc_sta = msc_sta | STA_PAR; }
|
||||
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) { /* write buffer */
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
|
||||
fxwrite (&ms_ptr, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
fxwrite (msxb, sizeof (int8), ms_ptr, uptr -> fileref);
|
||||
fxwrite (&ms_ptr, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
uptr -> pos = uptr -> pos + ((ms_ptr + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); }
|
||||
setFLG (devd); /* set dch flag */
|
||||
sim_activate (uptr, msc_xtime); /* re-activate */
|
||||
return SCPE_OK; }
|
||||
if (ms_ptr) { /* any data? write */
|
||||
if (err = ms_wrtrec (uptr, ms_ptr)) break; }
|
||||
sim_activate (uptr, msc_gtime); /* sched IRG */
|
||||
uptr->FNC = 0; /* NOP func */
|
||||
return SCPE_OK;
|
||||
|
||||
default: /* unknown */
|
||||
break; }
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
setFLG (devc); /* set cch flg */
|
||||
msc_sta = msc_sta & ~STA_BUSY; /* update status */
|
||||
if (err != 0) { /* I/O error */
|
||||
perror ("MT I/O error");
|
||||
clearerr (uptr -> fileref);
|
||||
IORETURN (msc_stopioe, SCPE_IOERR); }
|
||||
clearerr (uptr->fileref);
|
||||
if (msc_stopioe) return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Tape motion routines */
|
||||
|
||||
t_bool ms_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
|
||||
{
|
||||
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */
|
||||
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */
|
||||
if ((*err = ferror (uptr->fileref)) || /* error or eom? */
|
||||
feof (uptr->fileref) || (*tbc == MTR_EOM)) {
|
||||
msc_sta = msc_sta | STA_PAR; /* error */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_TMK) { /* tape mark? */
|
||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt);
|
||||
msc_sta = msc_sta | STA_EOF | STA_ODD; /* eof (also sets odd) */
|
||||
return TRUE; }
|
||||
if (MTRF (*tbc)) msc_sta = msc_sta | STA_PAR; /* error in rec? */
|
||||
*tbc = MTRL (*tbc); /* clear err flag */
|
||||
if (*tbc & 1) msc_sta = msc_sta | STA_ODD;
|
||||
else msc_sta = msc_sta & ~STA_ODD;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool ms_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
|
||||
{
|
||||
if (uptr->pos < sizeof (t_mtrlnt)) { /* at bot? */
|
||||
uptr->UST = STA_BOT; /* set status */
|
||||
return TRUE; } /* error */
|
||||
fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
|
||||
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */
|
||||
if ((*err = ferror (uptr->fileref)) || /* error or eof? */
|
||||
feof (uptr->fileref)) {
|
||||
msc_sta = msc_sta | STA_PAR; /* error */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_EOM) { /* eom? */
|
||||
msc_sta = msc_sta | STA_PAR; /* error */
|
||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_TMK) { /* tape mark? */
|
||||
msc_sta = msc_sta | STA_EOF; /* eof */
|
||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */
|
||||
return TRUE; }
|
||||
if (MTRF (*tbc)) msc_sta = msc_sta | STA_PAR; /* error in rec? */
|
||||
*tbc = MTRL (*tbc); /* clear err flag */
|
||||
if (*tbc & 1) msc_sta = msc_sta | STA_ODD;
|
||||
else msc_sta = msc_sta & ~STA_ODD;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool ms_forwsp (UNIT *uptr, int32 *err)
|
||||
{
|
||||
t_mtrlnt tbc;
|
||||
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* position */
|
||||
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* get bc */
|
||||
if ((*err = ferror (uptr -> fileref)) || feof (uptr -> fileref)) {
|
||||
uptr -> UST = STA_EOT;
|
||||
return FALSE; }
|
||||
if (tbc == 0) { /* zero bc? */
|
||||
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
|
||||
msc_sta = msc_sta | STA_EOF; /* eof */
|
||||
return FALSE; }
|
||||
uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + (2 * sizeof (t_mtrlnt));
|
||||
if (ms_rdlntf (uptr, &tbc, err)) return FALSE; /* read rec lnt, err? */
|
||||
uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* incr tape position */
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -464,20 +554,26 @@ t_bool ms_backsp (UNIT *uptr, int32 *err)
|
||||
{
|
||||
t_mtrlnt tbc;
|
||||
|
||||
if (uptr -> pos == 0) return FALSE; /* at bot? */
|
||||
fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), SEEK_SET);
|
||||
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* get bc */
|
||||
if ((*err = ferror (uptr -> fileref)) || feof (uptr -> fileref)) {
|
||||
uptr -> UST = STA_EOT;
|
||||
uptr -> pos = 0;
|
||||
return FALSE; }
|
||||
if (tbc == 0) { /* zero bc? */
|
||||
uptr -> pos = uptr -> pos - sizeof (t_mtrlnt);
|
||||
msc_sta = msc_sta | STA_EOF; /* eof */
|
||||
return FALSE; }
|
||||
uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - (2 * sizeof (t_mtrlnt));
|
||||
if (ms_rdlntr (uptr, &tbc, err)) return FALSE; /* read rec lnt, err? */
|
||||
uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - /* decr tape position */
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int32 ms_wrtrec (UNIT *uptr, t_mtrlnt lnt)
|
||||
{
|
||||
int32 elnt = MTRL ((lnt + 1) & ~1); /* even lnt, no err */
|
||||
|
||||
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* seek to record */
|
||||
fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */
|
||||
fxwrite (msxb, sizeof (int8), elnt, uptr->fileref); /* write data */
|
||||
fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr); /* pos not updated */
|
||||
return 1; }
|
||||
else uptr->pos = uptr->pos + elnt + (2 * sizeof (t_mtrlnt)); /* no, upd pos */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
@@ -486,24 +582,156 @@ 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 = 0; /* clear flg */
|
||||
msc_dib.fbf = msd_dib.fbf = 0; /* clear fbf */
|
||||
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;
|
||||
MT_CLR_PNU (uptr);
|
||||
sim_cancel (uptr);
|
||||
uptr -> UST = 0; }
|
||||
uptr->UST = 0; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat msc_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = attach_unit (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r; /* update status */
|
||||
MT_CLR_PNU (uptr);
|
||||
uptr->UST = STA_BOT;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Detach routine */
|
||||
|
||||
t_stat msc_detach (UNIT* uptr)
|
||||
{
|
||||
uptr->UST = 0; /* update status */
|
||||
MT_CLR_PNU (uptr);
|
||||
return detach_unit (uptr); /* detach unit */
|
||||
}
|
||||
|
||||
/* Write lock/enable routine */
|
||||
|
||||
t_stat msc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG;
|
||||
if (val && (uptr->flags & UNIT_ATT)) return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
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 nine track magnetic tape
|
||||
mt 12559A 3030 nine track magnetic tape
|
||||
|
||||
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
|
||||
@@ -54,7 +56,9 @@
|
||||
#include "hp2100_defs.h"
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_PNU (1 << UNIT_V_PNU)
|
||||
#define DB_V_SIZE 16 /* max data buf */
|
||||
#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */
|
||||
#define DBMASK (DBSIZE - 1)
|
||||
@@ -72,17 +76,17 @@
|
||||
#define FNC_RWS 0101 /* rewind and offline */
|
||||
#define FNC_WFM 0035 /* write file mark */
|
||||
|
||||
/* Status - stored in mtc_sta */
|
||||
/* Status - stored in mtc_sta, (d) = dynamic */
|
||||
|
||||
#define STA_LOCAL 0400 /* local */
|
||||
#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 */
|
||||
#define STA_WLK 0004 /* write locked (d) */
|
||||
#define STA_PAR 0002 /* parity error */
|
||||
#define STA_BUSY 0001 /* busy */
|
||||
#define STA_BUSY 0001 /* busy (d) */
|
||||
|
||||
extern int32 PC;
|
||||
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
|
||||
@@ -91,13 +95,15 @@ 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_xtime = 10; /* data xfer time */
|
||||
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);
|
||||
@@ -105,6 +111,9 @@ t_stat mtc_reset (DEVICE *dptr);
|
||||
t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat mtc_attach (UNIT *uptr, char *cptr);
|
||||
t_stat mtc_detach (UNIT *uptr);
|
||||
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
|
||||
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
|
||||
int32 mt_wrtrec (UNIT *uptr, t_mtrlnt lnt);
|
||||
|
||||
/* MTD data structures
|
||||
|
||||
@@ -114,8 +123,8 @@ t_stat mtc_detach (UNIT *uptr);
|
||||
*/
|
||||
|
||||
DIB mt_dib[] = {
|
||||
{ MTD, 1, 0, 0, 0, 0, &mtdio },
|
||||
{ MTC, 1, 0, 0, 0, 0, &mtcio } };
|
||||
{ MTD, 0, 0, 0, 0, &mtdio },
|
||||
{ MTC, 0, 0, 0, 0, &mtcio } };
|
||||
|
||||
#define mtd_dib mt_dib[0]
|
||||
#define mtc_dib mt_dib[1]
|
||||
@@ -131,19 +140,19 @@ REG mtd_reg[] = {
|
||||
{ DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },
|
||||
{ DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },
|
||||
{ ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, mtd_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB mtd_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &mtd_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&mtd_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* MTC data structures
|
||||
|
||||
@@ -167,29 +176,25 @@ REG mtc_reg[] = {
|
||||
{ FLDATA (FSVC, mtc_1st, 0) },
|
||||
{ DRDATA (POS, mtc_unit.pos, 32), 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) },
|
||||
{ FLDATA (WLK, mtc_unit.flags, UNIT_V_WLK), REG_HRO },
|
||||
{ ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, mtc_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB mtc_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mtc_vlock },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mtc_vlock },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED",
|
||||
&set_enb, NULL, &mtd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED",
|
||||
&set_dis, NULL, &mtd_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &mtd_dib },
|
||||
&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 };
|
||||
NULL, &mtc_attach, &mtc_detach,
|
||||
&mtc_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
@@ -197,10 +202,10 @@ int32 mtdio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 devd;
|
||||
|
||||
devd = IR & DEVMASK; /* get device no */
|
||||
devd = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devd); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -218,11 +223,11 @@ case ioLIX: /* load */
|
||||
dat = mtc_unit.buf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) mtc_dtf = 0; /* CLC: clr xfer flop */
|
||||
if (IR & I_CTL) mtc_dtf = 0; /* CLC: clr xfer flop */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & HC) { clrFLG (devd); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devd); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -230,11 +235,11 @@ int32 mtcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 i, devc, devd, valid;
|
||||
|
||||
devc = IR & DEVMASK; /* get device no */
|
||||
devc = IR & I_DEVMASK; /* get device no */
|
||||
devd = devc - 1;
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -244,50 +249,53 @@ case ioSFS: /* skip flag set */
|
||||
return dat;
|
||||
case ioOTX: /* output */
|
||||
dat = dat & 0377;
|
||||
mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */
|
||||
if (dat == FNC_CLR) { /* clear? */
|
||||
if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) &&
|
||||
sim_is_active (&mtc_unit)) break;
|
||||
mtc_reset (&mtc_dev); /* if not rewind, */
|
||||
clrCTL (devc); /* init device */
|
||||
clrFLG (devc);
|
||||
clrCTL (devd);
|
||||
clrFLG (devd);
|
||||
break; }
|
||||
if (sim_is_active (&mtc_unit) && /* write in prog? */
|
||||
(mtc_fnc == FNC_WC) && (mt_ptr > 0)) /* yes, bad rec */
|
||||
mt_wrtrec (&mtc_unit, mt_ptr | MTR_ERF);
|
||||
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 (dat == mtc_cmd[i]) valid = 1;
|
||||
if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */
|
||||
((mtc_unit.flags & UNIT_ATT) == 0) ||
|
||||
((mtc_sta & STA_BOT) &&
|
||||
((dat == FNC_BSR) || (dat == FNC_REW) || (dat == FNC_RWS))) ||
|
||||
((mtc_unit.flags & UNIT_WPRT) &&
|
||||
((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 */
|
||||
((mtc_sta & STA_BOT) && (dat == FNC_BSR)) ||
|
||||
((mtc_unit.flags & UNIT_WPRT) &&
|
||||
((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 */
|
||||
mtc_sta = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY);
|
||||
if (sim_is_active (&mtc_unit)) mtc_sta = mtc_sta | STA_BUSY;
|
||||
if (mtc_unit.flags & UNIT_WPRT) mtc_sta = mtc_sta | STA_WLK; }
|
||||
else mtc_sta = STA_BUSY | STA_LOCAL;
|
||||
dat = dat | mtc_sta;
|
||||
if (sim_is_active (&mtc_unit)) dat = dat | STA_BUSY;
|
||||
if (mtc_unit.flags & UNIT_WPRT) dat = dat | STA_WLK; }
|
||||
else dat = dat | STA_BUSY | STA_LOCAL;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { clrCTL (devc); } /* CLC */
|
||||
if (IR & I_CTL) { clrCTL (devc); } /* CLC */
|
||||
else { setCTL (devc); } /* STC */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & HC) { clrFLG (devc); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (devc); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -301,138 +309,188 @@ return dat;
|
||||
|
||||
t_stat mtc_svc (UNIT *uptr)
|
||||
{
|
||||
int32 devc, devd, err, i;
|
||||
static t_mtrlnt bceof = { 0 };
|
||||
|
||||
if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */
|
||||
mtc_sta = STA_LOCAL | STA_BUSY | STA_REJ;
|
||||
return IORETURN (mtc_stopioe, SCPE_UNATT); }
|
||||
devc = mtc_dib.devno; /* get device nos */
|
||||
devd = mtd_dib.devno;
|
||||
int32 devc, devd, err, pnu;
|
||||
static t_mtrlnt i, bceof = { MTR_TMK };
|
||||
|
||||
err = 0; /* assume no errors */
|
||||
switch (mtc_fnc & 0377) { /* case on function */
|
||||
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); }
|
||||
|
||||
pnu = MT_TST_PNU (uptr); /* get pos not upd */
|
||||
MT_CLR_PNU (uptr); /* and clear */
|
||||
switch (mtc_fnc) { /* case on function */
|
||||
|
||||
case FNC_REW: /* rewind */
|
||||
mtc_unit.pos = 0; /* BOT */
|
||||
mtc_sta = mtc_sta | STA_BOT; /* update status */
|
||||
mtc_sta = STA_BOT; /* update status */
|
||||
break;
|
||||
|
||||
case FNC_RWS: /* rewind and offline */
|
||||
mtc_unit.pos = 0; /* BOT */
|
||||
mtc_sta = STA_LOCAL | STA_BUSY; /* set status */
|
||||
mtc_unit.pos = 0; /* clear position */
|
||||
return detach_unit (uptr); /* don't set cch flg */
|
||||
|
||||
case FNC_WFM: /* write file mark */
|
||||
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
|
||||
fxwrite (&bceof, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
|
||||
err = ferror (mtc_unit.fileref);
|
||||
mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); /* update tape pos */
|
||||
mtc_sta = mtc_sta | STA_EOF; /* set EOF status */
|
||||
mtc_sta = STA_EOF; /* set EOF status */
|
||||
if (err = ferror (mtc_unit.fileref)) MT_SET_PNU (uptr);
|
||||
else mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); /* update tape pos */
|
||||
break;
|
||||
|
||||
case FNC_GAP: /* erase gap */
|
||||
break;
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
case FNC_FSR: /* space forward */
|
||||
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
|
||||
fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
|
||||
if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */
|
||||
feof (mtc_unit.fileref)) mtc_sta = mtc_sta | STA_EOT;
|
||||
else if (mt_max == 0) { /* zero bc? */
|
||||
mtc_sta = mtc_sta | STA_EOF; /* EOF */
|
||||
mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); }
|
||||
else mtc_unit.pos = mtc_unit.pos + ((MTRL (mt_max) + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); /* update position */
|
||||
break;
|
||||
case FNC_BSR: /* space reverse */
|
||||
if (mtc_unit.pos == 0) { /* at BOT? */
|
||||
mtc_sta = mtc_sta | STA_BOT; /* update status */
|
||||
break; }
|
||||
fseek (mtc_unit.fileref, mtc_unit.pos - sizeof (t_mtrlnt), SEEK_SET);
|
||||
fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
|
||||
if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */
|
||||
feof (mtc_unit.fileref)) mtc_unit.pos = 0;
|
||||
else if (mt_max == 0) { /* zero bc? */
|
||||
mtc_sta = mtc_sta | STA_EOF; /* EOF */
|
||||
mtc_unit.pos = mtc_unit.pos - sizeof (t_mtrlnt); }
|
||||
else mtc_unit.pos = mtc_unit.pos - ((MTRL (mt_max) + 1) & ~1) -
|
||||
if (mt_rdlntf (uptr, &mt_max, &err)) break; /* read rec lnt, err? */
|
||||
mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); /* update position */
|
||||
if (mtc_unit.pos == 0) mtc_sta = mtc_sta | STA_BOT;
|
||||
break;
|
||||
|
||||
case FNC_BSR: /* space reverse */
|
||||
if (pnu) break; /* pnu? do nothing */
|
||||
if (mt_rdlntr (uptr, &mt_max, &err)) break; /* read rec lnt, err? */
|
||||
mtc_unit.pos = mtc_unit.pos - ((mt_max + 1) & ~1) -
|
||||
(2 * sizeof (t_mtrlnt)); /* update position */
|
||||
break;
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
case FNC_RC: /* read */
|
||||
if (mtc_1st) { /* first svc? */
|
||||
mtc_1st = 0; /* clr 1st flop */
|
||||
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
|
||||
fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
|
||||
if ((err = ferror (mtc_unit.fileref)) ||
|
||||
feof (mtc_unit.fileref)) { /* error or eof? */
|
||||
setFLG (devc); /* set cch flg */
|
||||
mtc_sta = (mtc_sta | STA_EOT) & ~STA_BUSY;
|
||||
break; }
|
||||
if (mt_max == 0) { /* tape mark? */
|
||||
mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt);
|
||||
setFLG (devc); /* set cch flg */
|
||||
mtc_sta = (mtc_sta | STA_EOF) & ~STA_BUSY;
|
||||
break; }
|
||||
mt_max = MTRL (mt_max); /* ignore errors */
|
||||
mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); /* update position */
|
||||
if (mt_max > DBSIZE) return SCPE_MTRLNT;/* record too long? */
|
||||
if (mt_max < 12) { /* record too short? */
|
||||
setFLG (devc); /* set cch flg */
|
||||
mtc_sta = (mtc_sta | STA_PAR) & ~STA_BUSY;
|
||||
break; }
|
||||
i = fxread (mtxb, sizeof (int8), mt_max, mtc_unit.fileref);
|
||||
for ( ; i < mt_max; i++) mtxb[i] = 0; /* fill with 0's */
|
||||
err = ferror (mtc_unit.fileref); }
|
||||
mtc_1st = 0; /* clr 1st flop */
|
||||
if (mt_rdlntf (uptr, &mt_max, &err)) { /* read rec lnt */
|
||||
if (!err) { /* tmk or eom? */
|
||||
sim_activate (uptr, mtc_gtime); /* sched IRG */
|
||||
mtc_fnc = 0; /* NOP func */
|
||||
return SCPE_OK; }
|
||||
break; } /* error, done */
|
||||
if (mt_max > DBSIZE) return SCPE_MTRLNT; /* record too long? */
|
||||
if (mt_max < 12) { /* record too short? */
|
||||
mtc_sta = mtc_sta | STA_PAR; /* set flag */
|
||||
break; }
|
||||
i = fxread (mtxb, sizeof (int8), mt_max, mtc_unit.fileref);
|
||||
for ( ; i < mt_max; i++) mtxb[i] = 0; /* fill with 0's */
|
||||
if (err = ferror (mtc_unit.fileref)) { /* error? */
|
||||
mtc_sta = mtc_sta | STA_PAR; /* set flag */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
break; }
|
||||
mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); } /* update position */
|
||||
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; }
|
||||
break;
|
||||
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;
|
||||
else mtc_sta = mtc_sta | STA_PAR; }
|
||||
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; }
|
||||
setFLG (devd); /* set dch flag */
|
||||
sim_activate (uptr, mtc_xtime); /* re-activate */
|
||||
return SCPE_OK; }
|
||||
if (mt_ptr) { /* write buffer */
|
||||
fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET);
|
||||
fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
|
||||
fxwrite (mtxb, sizeof (int8), mt_ptr, mtc_unit.fileref);
|
||||
fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref);
|
||||
err = ferror (mtc_unit.fileref);
|
||||
mtc_unit.pos = mtc_unit.pos + ((mt_ptr + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); }
|
||||
if (err = mt_wrtrec (uptr, mt_ptr)) break; }
|
||||
sim_activate (uptr, mtc_gtime); /* schedule gap */
|
||||
mtc_fnc = 0; /* nop */
|
||||
return SCPE_OK;
|
||||
|
||||
default: /* unknown */
|
||||
break; }
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
setFLG (devc); /* set cch flg */
|
||||
mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */
|
||||
if (err != 0) { /* I/O error */
|
||||
perror ("MT I/O error");
|
||||
clearerr (mtc_unit.fileref);
|
||||
IORETURN (mtc_stopioe, SCPE_IOERR); }
|
||||
if (mtc_stopioe) return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Tape motion routines */
|
||||
|
||||
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
|
||||
{
|
||||
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */
|
||||
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */
|
||||
if ((*err = ferror (uptr->fileref)) || /* error or eom? */
|
||||
feof (uptr->fileref) || (*tbc == MTR_EOM)) {
|
||||
mtc_sta = mtc_sta | STA_PAR; /* error */
|
||||
MT_SET_PNU (uptr); /* pos not upd */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_TMK) { /* tape mark? */
|
||||
mtc_sta = mtc_sta | STA_EOF; /* eof */
|
||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */
|
||||
return TRUE; }
|
||||
if (MTRF (*tbc)) mtc_sta = mtc_sta | STA_PAR; /* error in rec? */
|
||||
*tbc = MTRL (*tbc); /* clear err flag */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
|
||||
{
|
||||
if (uptr->pos < sizeof (t_mtrlnt)) { /* no data to read? */
|
||||
mtc_sta = mtc_sta | STA_BOT; /* update status */
|
||||
return TRUE; }
|
||||
fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
|
||||
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */
|
||||
if ((*err = ferror (uptr->fileref)) || /* error or eof? */
|
||||
feof (uptr->fileref)) {
|
||||
mtc_sta = mtc_sta | STA_PAR; /* error */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_EOM) { /* eom? */
|
||||
mtc_sta = mtc_sta | STA_PAR; /* error */
|
||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_TMK) { /* tape mark? */
|
||||
mtc_sta = mtc_sta | STA_EOF; /* eof */
|
||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */
|
||||
return TRUE; }
|
||||
if (MTRF (*tbc)) mtc_sta = mtc_sta | STA_PAR; /* error in rec? */
|
||||
*tbc = MTRL (*tbc); /* clear err flag */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int32 mt_wrtrec (UNIT *uptr, t_mtrlnt lnt)
|
||||
{
|
||||
int32 elnt = MTRL ((lnt + 1) & ~1); /* even lnt, no err */
|
||||
|
||||
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* seek to record */
|
||||
fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */
|
||||
fxwrite (mtxb, sizeof (int8), elnt, uptr->fileref); /* write data */
|
||||
fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */
|
||||
if (ferror (uptr->fileref)) { /* error? */
|
||||
MT_SET_PNU (uptr); /* pos not updated */
|
||||
return 1; }
|
||||
else uptr->pos = uptr->pos + elnt + (2 * sizeof (t_mtrlnt)); /* no, upd pos */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
mtc_unit.flags = mtc_unit.flags & ~UNIT_PNU; /* clear pos flag */
|
||||
if (mtc_unit.flags & UNIT_ATT) mtc_sta = ((mtc_unit.pos)? 0: STA_BOT) |
|
||||
((mtc_unit.flags & UNIT_WPRT)? STA_WLK: 0);
|
||||
else mtc_sta = STA_LOCAL | STA_BUSY;
|
||||
@@ -447,7 +505,8 @@ t_stat r;
|
||||
|
||||
r = attach_unit (uptr, cptr); /* attach unit */
|
||||
if (r != SCPE_OK) return r; /* update status */
|
||||
mtc_sta = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
|
||||
MT_CLR_PNU (uptr);
|
||||
mtc_sta = STA_BOT;
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -455,7 +514,8 @@ return r;
|
||||
|
||||
t_stat mtc_detach (UNIT* uptr)
|
||||
{
|
||||
mtc_sta = STA_LOCAL | STA_BUSY; /* update status */
|
||||
mtc_sta = 0; /* update status */
|
||||
MT_CLR_PNU (uptr);
|
||||
return detach_unit (uptr); /* detach unit */
|
||||
}
|
||||
|
||||
@@ -463,6 +523,6 @@ return detach_unit (uptr); /* detach unit */
|
||||
|
||||
t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG;
|
||||
if (val && (uptr->flags & UNIT_ATT)) return SCPE_ARG;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
mux,muxl,muxc 12920A terminal multiplexor
|
||||
|
||||
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)
|
||||
@@ -42,8 +45,10 @@
|
||||
|
||||
#define MUX_LINES 16 /* user lines */
|
||||
#define MUX_ILINES 5 /* diag rcv only */
|
||||
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
|
||||
#define UNIT_V_MDM (UNIT_V_UF + 1) /* modem control */
|
||||
#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
|
||||
@@ -145,8 +150,9 @@ 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, NULL }; /* mux descriptor */
|
||||
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);
|
||||
@@ -160,8 +166,6 @@ 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);
|
||||
t_stat mux_enb (UNIT *uptr, int32 num, char *cptr, void *desc);
|
||||
t_stat mux_dis (UNIT *uptr, int32 num, char *cptr, void *desc);
|
||||
|
||||
static uint8 odd_par[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */
|
||||
@@ -183,9 +187,9 @@ static uint8 odd_par[256] = {
|
||||
|
||||
#define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0)
|
||||
|
||||
DIB mux_dib[] = {
|
||||
{ MUXL, 1, 0, 0, 0, 0, &muxlio },
|
||||
{ MUXU, 1, 0, 0, 0, 0, &muxuio } };
|
||||
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]
|
||||
@@ -208,30 +212,26 @@ REG muxu_reg[] = {
|
||||
{ FLDATA (FLG, muxu_dib.flg, 0), REG_HRO },
|
||||
{ FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO },
|
||||
{ ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, muxu_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB muxu_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
|
||||
&tmxr_dscln, NULL, &mux_desc },
|
||||
{ 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, 0, NULL, "ENABLED",
|
||||
&mux_enb, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED",
|
||||
&mux_dis, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &mux_dib },
|
||||
&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 };
|
||||
NULL, &mux_attach, &mux_detach,
|
||||
&muxu_dib, DEV_DISABLE };
|
||||
|
||||
/* MUXL data structures
|
||||
|
||||
@@ -261,16 +261,13 @@ UNIT muxl_unit[] = {
|
||||
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT } };
|
||||
|
||||
MTAB muxl_mod[] = {
|
||||
{ UNIT_UC, 0, "lower case", "LC", NULL },
|
||||
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
|
||||
{ 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, 0, NULL, "ENABLED",
|
||||
&mux_enb, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED",
|
||||
&mux_dis, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &mux_dib },
|
||||
&hp_setdev, &hp_showdev, &muxl_dev },
|
||||
{ 0 } };
|
||||
|
||||
REG muxl_reg[] = {
|
||||
@@ -287,17 +284,15 @@ REG muxl_reg[] = {
|
||||
{ BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) },
|
||||
{ URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
|
||||
MUX_LINES, REG_NZ + PV_LEFT) },
|
||||
{ URDATA (FLGS, muxl_unit[0].flags, 8, 2, UNIT_V_UF,
|
||||
MUX_LINES, REG_HRO) },
|
||||
{ ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, muxl_dib.enb, 0), 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 };
|
||||
NULL, NULL, NULL,
|
||||
&muxl_dib, 0 };
|
||||
|
||||
/* MUXM data structures
|
||||
|
||||
@@ -307,7 +302,7 @@ DEVICE muxl_dev = {
|
||||
muxc_mod MUXM modifiers list
|
||||
*/
|
||||
|
||||
DIB muxc_dib = { MUXC, 1, 0, 0, 0, 0, &muxcio };
|
||||
DIB muxc_dib = { MUXC, 0, 0, 0, 0, &muxcio };
|
||||
|
||||
UNIT muxc_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
@@ -321,23 +316,19 @@ REG muxc_reg[] = {
|
||||
{ BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) },
|
||||
{ BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) },
|
||||
{ ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, muxc_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB muxc_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED",
|
||||
&mux_enb, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED",
|
||||
&mux_dis, NULL, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &muxc_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&muxc_dib, 0 };
|
||||
|
||||
/* IOT routines: data cards */
|
||||
|
||||
@@ -345,10 +336,10 @@ int32 muxlio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev, ln;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -366,7 +357,7 @@ case ioLIX: /* load */
|
||||
dat = muxl_ibuf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { clrCTL (dev); } /* CLC */
|
||||
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
|
||||
else { /* STC */
|
||||
setCTL (dev); /* set ctl */
|
||||
ln = MUX_CHAN (muxu_obuf); /* get chan # */
|
||||
@@ -386,7 +377,7 @@ case ioCTL: /* control clear/set */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & HC) { /* H/C option */
|
||||
if (IR & I_HC) { /* H/C option */
|
||||
clrFLG (dev); /* clear flag */
|
||||
mux_data_int (); } /* look for new int */
|
||||
return dat;
|
||||
@@ -415,10 +406,10 @@ int32 muxcio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev, ln, t, old;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -456,12 +447,12 @@ case ioMIX: /* merge */
|
||||
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
|
||||
break;
|
||||
case ioCTL: /* ctrl clear/set */
|
||||
if (IR & AB) { clrCTL (dev); } /* CLC */
|
||||
if (IR & I_CTL) { clrCTL (dev); } /* CLC */
|
||||
else { setCTL (dev); } /* STC */
|
||||
break;
|
||||
default:
|
||||
break; }
|
||||
if (IR & HC) { /* H/C option */
|
||||
if (IR & I_HC) { /* H/C option */
|
||||
clrFLG (dev); /* clear flag */
|
||||
mux_ctrl_int (); } /* look for new int */
|
||||
return dat;
|
||||
@@ -477,31 +468,33 @@ t_stat muxi_svc (UNIT *uptr)
|
||||
{
|
||||
int32 ln, c, t;
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
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, uptr); /* look for connect */
|
||||
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 */
|
||||
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 (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST;
|
||||
if ((muxl_unit[ln].flags & UNIT_UC) && /* cvt to UC? */
|
||||
islower (c & 0177)) c = toupper (c);
|
||||
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 */
|
||||
if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */
|
||||
mux_rbuf[ln] = c; /* save char */
|
||||
mux_rchp[ln] = 1; } } /* char pending */
|
||||
else muxc_lia[ln] = 0; } /* disconnected */ /* end for */
|
||||
if (mux_ldsc[ln].conn) { /* connected? */
|
||||
if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */
|
||||
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 */
|
||||
if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */
|
||||
mux_rbuf[ln] = c; /* save char */
|
||||
mux_rchp[ln] = 1; } } /* char pending */
|
||||
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;
|
||||
@@ -514,21 +507,23 @@ 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] & 0177; /* get char */
|
||||
if ((muxl_unit[ln].flags & UNIT_UC) && islower (c))
|
||||
c = toupper (c); /* cvt to UC? */
|
||||
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 (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;
|
||||
}
|
||||
@@ -542,7 +537,7 @@ 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]);
|
||||
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;
|
||||
@@ -558,7 +553,7 @@ for (i = 0; i < MUX_LINES; i++) { /* xmt lines */
|
||||
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]);
|
||||
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;
|
||||
@@ -577,8 +572,8 @@ 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; } }
|
||||
setFLG (muxc_dib.devno); /* set flag */
|
||||
break; } }
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -617,6 +612,11 @@ 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 */
|
||||
@@ -626,8 +626,8 @@ 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 */
|
||||
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];
|
||||
@@ -659,7 +659,7 @@ 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 SCPE_OK;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Show summary processor */
|
||||
@@ -682,34 +682,11 @@ 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); } }
|
||||
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;
|
||||
}
|
||||
|
||||
/* Enable device */
|
||||
|
||||
t_stat mux_enb (UNIT *uptr, int32 num, char *cptr, void *desc)
|
||||
{
|
||||
if (cptr != NULL) return SCPE_ARG;
|
||||
muxl_dib.enb = 1;
|
||||
muxu_dib.enb = 1;
|
||||
muxc_dib.enb = 1;
|
||||
return mux_reset (&muxl_dev);
|
||||
}
|
||||
|
||||
/* Disable device */
|
||||
|
||||
t_stat mux_dis (UNIT *uptr, int32 num, char *cptr, void *desc)
|
||||
{
|
||||
if (cptr != NULL) return SCPE_ARG;
|
||||
if (muxu_unit.flags & UNIT_ATT) return SCPE_NOFNC;
|
||||
muxl_dib.enb = 0;
|
||||
muxu_dib.enb = 0;
|
||||
muxc_dib.enb = 0;
|
||||
return mux_reset (&muxl_dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
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,
|
||||
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 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
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.
|
||||
|
||||
@@ -26,8 +26,13 @@
|
||||
ptr 12597A-002 paper tape reader
|
||||
ptp 12597A-005 paper tape punch
|
||||
tty 12531C buffered teleprinter interface
|
||||
clk 12539A/B/C time base generator
|
||||
clk 12539C time base generator
|
||||
|
||||
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
|
||||
@@ -40,37 +45,60 @@
|
||||
|
||||
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 int32 PC;
|
||||
extern int32 PC, SR;
|
||||
extern int32 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_delay[8] = /* clock intervals */
|
||||
{ 50, 500, 5000, 50000, 500000, 5000000, 50000000, 50000000 };
|
||||
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);
|
||||
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);
|
||||
@@ -78,9 +106,11 @@ 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
|
||||
|
||||
@@ -90,7 +120,7 @@ t_stat clk_reset (DEVICE *dptr);
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
DIB ptr_dib = { PTR, 1, 0, 0, 0, 0, &ptrio };
|
||||
DIB ptr_dib = { PTR, 0, 0, 0, 0, &ptrio };
|
||||
|
||||
UNIT ptr_unit = {
|
||||
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
|
||||
@@ -106,23 +136,19 @@ REG ptr_reg[] = {
|
||||
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ptr_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED",
|
||||
&set_enb, NULL, &ptr_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED",
|
||||
&set_dis, NULL, &ptr_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &ptr_dib },
|
||||
&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_boot, NULL, NULL,
|
||||
&ptr_dib, DEV_DISABLE };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
@@ -132,7 +158,7 @@ DEVICE ptr_dev = {
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
DIB ptp_dib = { PTP, 1, 0, 0, 0, 0, &ptpio };
|
||||
DIB ptp_dib = { PTP, 0, 0, 0, 0, &ptpio };
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
@@ -147,23 +173,19 @@ REG ptp_reg[] = {
|
||||
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ptp_mod[] = {
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED",
|
||||
&set_enb, NULL, &ptp_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED",
|
||||
&set_dis, NULL, &ptp_dib },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &ptp_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&ptp_dib, DEV_DISABLE };
|
||||
|
||||
/* TTY data structures
|
||||
|
||||
@@ -177,12 +199,12 @@ DEVICE ptp_dev = {
|
||||
#define TTO 1
|
||||
#define TTP 2
|
||||
|
||||
DIB tty_dib = { TTY, 1, 0, 0, 0, 0, &ttyio };
|
||||
DIB tty_dib = { TTY, 0, 0, 0, 0, &ttyio };
|
||||
|
||||
UNIT tty_unit[] = {
|
||||
{ UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT },
|
||||
{ UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT },
|
||||
{ UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_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) },
|
||||
@@ -198,21 +220,22 @@ REG tty_reg[] = {
|
||||
{ DRDATA (PPOS, tty_unit[TTP].pos, 32), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, ttp_stopioe, 0) },
|
||||
{ ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO },
|
||||
{ FLDATA (UC, tty_unit[TTI].flags, UNIT_V_UC), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tty_mod[] = {
|
||||
{ UNIT_UC, 0, "lower case", "LC", NULL },
|
||||
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
|
||||
{ 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_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&tty_dib, 0 };
|
||||
|
||||
/* CLK data structures
|
||||
|
||||
@@ -222,32 +245,36 @@ DEVICE tty_dev = {
|
||||
clk_reg CLK register list
|
||||
*/
|
||||
|
||||
DIB clk_dib = { CLK, 1, 0, 0, 0, 0, &clkio };
|
||||
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_delay, 8, 31, 8) },
|
||||
{ BRDATA (TIME, clk_time, 10, 24, 8) },
|
||||
{ ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB clk_mod[] = {
|
||||
{ UNIT_DIAG, UNIT_DIAG, "DIAG", "DIAG", NULL },
|
||||
{ UNIT_DIAG, 0, "CALIBRATED", "CALIBRATED", NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&hp_setdev, &hp_showdev, &clk_dib },
|
||||
&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 };
|
||||
NULL, NULL, NULL,
|
||||
&clk_dib, 0 };
|
||||
|
||||
/* Paper tape reader: IOT routine */
|
||||
|
||||
@@ -255,10 +282,10 @@ int32 ptrio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -273,16 +300,17 @@ case ioLIX: /* load */
|
||||
dat = ptr_unit.buf;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC */
|
||||
clrCMD (dev); /* clear cmd, ctl */
|
||||
clrCTL (dev); }
|
||||
else { setCMD (dev); /* STC */
|
||||
setCTL (dev); /* set cmd, ctl */
|
||||
sim_activate (&ptr_unit, ptr_unit.wait); }
|
||||
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 & HC) { clrFLG (dev); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -298,8 +326,8 @@ 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; }
|
||||
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; }
|
||||
@@ -320,38 +348,76 @@ sim_cancel (&ptr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Paper tape reader bootstrap routine */
|
||||
/* Paper tape reader bootstrap routine (HP 12992K ROM) */
|
||||
|
||||
#define CHANGE_DEV (1 << 24)
|
||||
#define PBOOT_MASK 077
|
||||
#define PBOOT_SIZE (sizeof (pboot) / sizeof (int32))
|
||||
#define CHANGE_ADDR (1 << 23)
|
||||
|
||||
static const int32 pboot[] = {
|
||||
0107700, 0063770, 0106501, 0004010,
|
||||
0002400, 0006020, 0063771, 0073736,
|
||||
0006401, 0067773, 0006006, 0027717,
|
||||
0107700, 0102077, 0027700, 0017762,
|
||||
0002003, 0027712, 0003104, 0073774,
|
||||
0017762, 0017753, 0070001, 0073775,
|
||||
0063775, 0043772, 0002040, 0027751,
|
||||
0017753, 0044000, 0000000, 0002101,
|
||||
0102000, 0037775, 0037774, 0027730,
|
||||
0017753, 0054000, 0027711, 0102011,
|
||||
0027700, 0102055, 0027700, 0000000,
|
||||
0017762, 0001727, 0073776, 0017762,
|
||||
0033776, 0127753, 0000000, 0103700+CHANGE_DEV,
|
||||
0102300+CHANGE_DEV, 0027764, 0102500+CHANGE_DEV, 0127762,
|
||||
0173775, 0153775, 0170100, 0177765 };
|
||||
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 */
|
||||
CHANGE_ADDR }; /*MAXAD -ST ; max addr */
|
||||
|
||||
t_stat ptr_boot (int32 unit)
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i, dev;
|
||||
|
||||
dev = ptr_dib.devno; /* get device no */
|
||||
PC = (MEMSIZE - 1) & ~PBOOT_MASK; /* start at mem top */
|
||||
for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */
|
||||
M[PC + i] = (pboot[i] & CHANGE_DEV)? /* insert ptr dev no */
|
||||
((pboot[i] | dev) & DMASK): pboot[i];
|
||||
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_ADDR) /* memory limit? */
|
||||
M[PC + i] = (-PC) & DMASK;
|
||||
else if (pboot[i] & CHANGE_DEV) /* IO instr? */
|
||||
M[PC + i] = (pboot[i] + dev) & DMASK;
|
||||
else M[PC + i] = pboot[i]; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -361,10 +427,10 @@ int32 ptpio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -376,22 +442,23 @@ case ioLIX: /* load */
|
||||
dat = 0;
|
||||
case ioMIX: /* merge */
|
||||
if ((ptp_unit.flags & UNIT_ATT) == 0)
|
||||
dat = dat | PTP_LOW; /* out of tape? */
|
||||
dat = dat | PTP_LOW; /* out of tape? */
|
||||
break;
|
||||
case ioOTX: /* output */
|
||||
ptp_unit.buf = dat;
|
||||
break;
|
||||
case ioCTL: /* control clear/set */
|
||||
if (IR & AB) { /* CLC */
|
||||
clrCMD (dev); /* clear cmd, ctl */
|
||||
clrCTL (dev); }
|
||||
else { setCMD (dev); /* STC */
|
||||
setCTL (dev); /* set cmd, ctl */
|
||||
sim_activate (&ptp_unit, ptp_unit.wait); }
|
||||
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 & HC) { clrFLG (dev); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -431,10 +498,10 @@ int32 ttyio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -447,74 +514,77 @@ case ioLIX: /* load */
|
||||
case ioMIX: /* merge */
|
||||
dat = dat | tty_buf;
|
||||
if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO]))
|
||||
dat = dat | TP_BUSY;
|
||||
dat = dat | TP_BUSY;
|
||||
break;
|
||||
case ioOTX: /* output */
|
||||
if (dat & TM_MODE) tty_mode = dat;
|
||||
else tty_buf = dat & 0377;
|
||||
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 & AB) { clrCTL (dev); } /* CLC */
|
||||
else { setCTL (dev); /* STC */
|
||||
if (!(tty_mode & TM_KBD)) /* output? */
|
||||
sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); }
|
||||
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 & HC) { clrFLG (dev); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Unit service routines */
|
||||
|
||||
t_stat tto_out (int32 ch)
|
||||
t_stat tto_out (int32 c)
|
||||
{
|
||||
t_stat ret = SCPE_OK;
|
||||
|
||||
if (tty_mode & TM_PRI) { /* printing? */
|
||||
ch = ch & 0177;
|
||||
if ((tty_unit[TTI].flags & UNIT_UC) && islower (ch)) /* upper case? */
|
||||
ch = toupper (ch);
|
||||
ret = sim_putchar (ch & 0177); /* output char */
|
||||
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 (ch, tty_unit[TTP].fileref) == EOF) { /* output char */
|
||||
perror ("TTP I/O error");
|
||||
clearerr (tty_unit[TTP].fileref);
|
||||
return SCPE_IOERR; }
|
||||
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 temp, dev;
|
||||
int32 c, dev;
|
||||
|
||||
dev = tty_dib.devno; /* get device no */
|
||||
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
|
||||
temp = temp & 0177;
|
||||
if ((tty_unit[TTI].flags & UNIT_UC) && islower (temp)) /* force upper case? */
|
||||
temp = toupper (temp);
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
|
||||
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 = temp; /* put char in buf */
|
||||
tty_buf = c; /* put char in buf */
|
||||
tty_unit[TTI].pos = tty_unit[TTI].pos + 1;
|
||||
setFLG (dev); /* set flag */
|
||||
return tto_out (temp); } /* echo or punch? */
|
||||
return tto_out (c); } /* echo or punch? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_svc (UNIT *uptr)
|
||||
{
|
||||
int32 ch, dev;
|
||||
int32 c, dev;
|
||||
|
||||
dev = tty_dib.devno; /* get device no */
|
||||
setFLG (dev); /* set done flag */
|
||||
ch = tty_buf;
|
||||
c = tty_buf;
|
||||
tty_buf = 0377; /* defang buf */
|
||||
return tto_out (ch); /* print and/or punch */
|
||||
return tto_out (c); /* print and/or punch */
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
@@ -523,12 +593,22 @@ 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 = 0;
|
||||
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 */
|
||||
|
||||
@@ -536,10 +616,10 @@ int32 clkio (int32 inst, int32 IR, int32 dat)
|
||||
{
|
||||
int32 dev;
|
||||
|
||||
dev = IR & DEVMASK; /* get device no */
|
||||
dev = IR & I_DEVMASK; /* get device no */
|
||||
switch (inst) { /* case on opcode */
|
||||
case ioFLG: /* flag clear/set */
|
||||
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
|
||||
if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */
|
||||
break;
|
||||
case ioSFC: /* skip flag clear */
|
||||
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
|
||||
@@ -554,19 +634,25 @@ case ioLIX: /* load */
|
||||
dat = clk_error;
|
||||
break;
|
||||
case ioOTX: /* output */
|
||||
clk_select = dat & 07;
|
||||
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 & AB) { /* CLC */
|
||||
clrCTL (dev); /* turn off clock */
|
||||
sim_cancel (&clk_unit); } /* deactivate unit */
|
||||
else { setCTL (dev); /* turn on clock */
|
||||
clk_error = 0; /* clear error */
|
||||
sim_activate (&clk_unit, clk_delay[clk_select]); }
|
||||
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 & HC) { clrFLG (dev); } /* H/C option */
|
||||
if (IR & I_HC) { clrFLG (dev); } /* H/C option */
|
||||
return dat;
|
||||
}
|
||||
|
||||
@@ -574,11 +660,20 @@ return dat;
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
int32 dev;
|
||||
int32 tim, dev;
|
||||
|
||||
dev = clk_dib.devno; /* get device no */
|
||||
if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? */
|
||||
setFLG (dev); /* set device flag */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -590,6 +685,18 @@ 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];
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ 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, lpt_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;
|
||||
@@ -69,17 +70,22 @@ REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 3;
|
||||
|
||||
DEVICE *sim_devices[] = { &cpu_dev,
|
||||
&dma0_dev, &dma1_dev,
|
||||
&ptr_dev, &ptp_dev,
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&dma0_dev,
|
||||
&dma1_dev,
|
||||
&ptr_dev,
|
||||
&ptp_dev,
|
||||
&tty_dev,
|
||||
&clk_dev, &lpt_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,
|
||||
&muxu_dev, &muxl_dev, &muxc_dev,
|
||||
&muxl_dev, &muxu_dev, &muxc_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
@@ -88,7 +94,8 @@ const char *sim_stop_messages[] = {
|
||||
"Non-existent I/O device",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Indirect address loop" };
|
||||
"Indirect address loop",
|
||||
"Indirect address interrupt (should not happen!)" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
@@ -121,17 +128,17 @@ 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 ((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 (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;
|
||||
@@ -172,8 +179,8 @@ static const char *opcode[] = {
|
||||
"XOR", "JMP", "IOR", "ISZ",
|
||||
"ADA", "ADB" ,"CPA", "CPB",
|
||||
"LDA", "LDB", "STA", "STB",
|
||||
"ASL", "LSL", "RRL",
|
||||
"ASR", "LSR", "RRR",
|
||||
"DIAG", "ASL", "LSL", "TIMER",
|
||||
"RRL", "ASR", "LSR", "RRR",
|
||||
"MPY", "DIV", "DLD", "DST",
|
||||
"FAD", "FSB", "FMP", "FDV",
|
||||
"FIX", "FLT",
|
||||
@@ -214,8 +221,8 @@ static const int32 opc_val[] = {
|
||||
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,
|
||||
0100020+I_ESH, 0100040+I_ESH, 0100100+I_ESH,
|
||||
0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH,
|
||||
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,
|
||||
@@ -329,16 +336,16 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
break;
|
||||
case I_V_NPC: /* no operands + C */
|
||||
fprintf (of, "%s", opcode[i]);
|
||||
if (inst & HC) fprintf (of, " C");
|
||||
if (inst & I_HC) fprintf (of, " C");
|
||||
break;
|
||||
case I_V_MRF: /* mem ref */
|
||||
disp = inst & DISP; /* displacement */
|
||||
disp = inst & I_DISP; /* displacement */
|
||||
fprintf (of, "%s ", opcode[i]); /* opcode */
|
||||
if (inst & CP) { /* current page? */
|
||||
if (cflag) fprintf (of, "%-o", (addr & PAGENO) | disp);
|
||||
else fprintf (of, "C %-o", disp); }
|
||||
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 & IA) fprintf (of, ",I");
|
||||
if (inst & I_IA) fprintf (of, ",I");
|
||||
break;
|
||||
case I_V_ASH: /* shift, alter-skip */
|
||||
cm = FALSE;
|
||||
@@ -357,24 +364,24 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
break;
|
||||
case I_V_EMR: /* extended mem ref */
|
||||
fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
|
||||
if (val[1] & IA) fprintf (of, ",I");
|
||||
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 & DEVMASK);
|
||||
if (inst & HC) fprintf (of, ",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 & DEVMASK);
|
||||
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] & IA) fprintf (of, ",I");
|
||||
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] & IA) fprintf (of, ",I");
|
||||
if (val[1] & I_IA) fprintf (of, ",I");
|
||||
fprintf (of, " %-o", val[2] & VAMASK);
|
||||
if (val[2] & IA) fprintf (of, ",I");
|
||||
if (val[2] & I_IA) fprintf (of, ",I");
|
||||
return -2; } /* extra words */
|
||||
return SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
@@ -401,8 +408,9 @@ 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 (strcmp (gbuf, "I")) return -1;
|
||||
d = d | IA; }
|
||||
if (*cptr != 0) return -1; /* should be done */
|
||||
if (strcmp (gbuf, "I")) return -1; /* I? */
|
||||
d = d | I_IA; }
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -450,21 +458,21 @@ if (opcode[i]) { /* found opcode? */
|
||||
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] | HC; }
|
||||
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] | CP;
|
||||
cptr = get_glyph (cptr, gbuf, 0); }
|
||||
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, ','); }
|
||||
cptr = get_glyph (cptr, gbuf, ','); }
|
||||
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
|
||||
if ((d & VAMASK) <= DISP) val[0] = val[0] | d;
|
||||
else if (cflag && !k && (((addr ^ d) & PAGENO) == 0))
|
||||
val[0] = val[0] | (d & (IA | DISP)) | CP;
|
||||
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 */
|
||||
@@ -481,17 +489,17 @@ if (opcode[i]) { /* found opcode? */
|
||||
break;
|
||||
case I_V_IO1: /* IOT + optional C */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get device */
|
||||
d = get_uint (gbuf, 8, DEVMASK, &r);
|
||||
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] | HC; }
|
||||
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, DEVMASK, &r);
|
||||
d = get_uint (gbuf, 8, I_DEVMASK, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
val[0] = val[0] | d;
|
||||
break;
|
||||
@@ -548,21 +556,22 @@ 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; }
|
||||
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 ((strcmp (gbuf, stab[i]) == 0) &&
|
||||
((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; }
|
||||
if (stab[i] == NULL) return SCPE_ARG;
|
||||
if (tbits & mtab[i] & (AB | ASKP) & (vtab[i] ^ val[0])) return SCPE_ARG;
|
||||
if (tbits & mtab[i] & ~(AB | ASKP)) 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] & ASKP) { /* alter-skip? */
|
||||
if (tbits & 0100) return SCPE_ARG; /* already filled in? */
|
||||
else val[0] = val[0] | 0100; }
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user