1
0
mirror of https://github.com/open-simh/simh.git synced 2026-05-01 14:06:14 +00:00

Notes For V2.9-11

1. New Features

1.1 GRI-909

- This is a new simulator for the GRI-909.
- It has been hand-tested; so far, no software has been discovered.

1.2 VAX

- SET CPU CONHALT will cause a HALT instruction to return to the
  boot ROM console rather than to SIMH.  SET CPU SIMHALT restores
  the default behavior.
- BRB/W self at IPL 1F stops the simulator.  This is the default
  behavior of VMS at exit.

1.3 PDP-18b

- ATTACH -A PTR/PTP attaches the reader and punch in ASCII mode.
  In ASCII mode, the reader automatically sets the high order bit
  of incoming alphabetic data, and the punch clears the high order
  bit of outgoing data.

1.4 SCP

- DO -V echoes commands from the file as they are executed.
- Under Windows, execution priority is set BELOW_NORMAL when the
  simulator is running.

2. Release Notes

2.1 Bugs Fixed

- PDP-11 CPU: fixed updating of MMR0 on a memory management error.
- VAX FPA: changed function names to avoid conflict with C math library.
- 1401 MT: read end of record generates group mark without word mark.
- 1401 DP: fixed address generation and checking.
- SCP: an EXIT within a DO command will cause the simulator to exit.

3. In Progress

- Interdata 16b/32b: coded, not tested.
- SDS 940: coded, not tested.
- IBM 1620: coded, not tested.

If you would like to help with the debugging of the untested simulators,
they can be made available by special request.
This commit is contained in:
Bob Supnik
2002-07-14 15:20:00 -07:00
committed by Mark Pizzolato
parent 701f0fe028
commit df6475181c
179 changed files with 36441 additions and 4464 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* hp2100_defs.h: HP 2100 simulator definitions
Copyright (c) 1993-2001, Robert M. Supnik
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"),
@@ -23,6 +23,9 @@
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.
08-Feb-02 RMS Added DMS definitions
01-Feb-02 RMS Added terminal multiplexor support
16-Jan-02 RMS Added additional device support
30-Nov-01 RMS Added extended SET/SHOW support
15-Oct-00 RMS Added dynamic device numbers
14-Apr-99 RMS Changed t_addr to unsigned
@@ -41,17 +44,25 @@
#define STOP_IBKPT 4 /* breakpoint */
#define STOP_IND 5 /* indirect loop */
#define ABORT_DMS 1 /* DMS abort */
#define ABORT_FENCE -1 /* fence abort */
/* Memory */
#define MAXMEMSIZE 32768 /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define AMASK (MAXMEMSIZE - 1) /* address mask */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
#define VA_N_SIZE 15 /* virtual addr size */
#define VASIZE (1 << VA_N_SIZE)
#define VAMASK (VASIZE - 1) /* virt addr mask */
#define PA_N_SIZE 20 /* phys addr size */
#define PASIZE (1 << PA_N_SIZE)
#define PAMASK (PASIZE - 1) /* phys addr mask */
/* Architectural constants */
#define SIGN 0100000 /* sign */
#define DMASK 0177777 /* data mask */
#define SIGN32 020000000000 /* 32b sign */
#define SIGN 0100000 /* 16b sign */
#define DMASK 0177777 /* 16b data mask */
#define AR M[0] /* A = location 0 */
#define BR M[1] /* B = location 1 */
#define ABREG M /* register array */
@@ -87,6 +98,67 @@ struct DMA { /* DMA channel */
int32 cw3; /* word count */
};
/* Memory management */
#define VA_N_OFF 10 /* offset width */
#define VA_M_OFF ((1 << VA_N_OFF) - 1) /* offset mask */
#define VA_GETOFF(x) ((x) & VA_M_OFF)
#define VA_N_PAG (VA_N_SIZE - VA_N_OFF) /* page width */
#define VA_V_PAG (VA_N_OFF)
#define VA_M_PAG ((1 << VA_N_PAG) - 1)
#define VA_GETPAG(x) (((x) >> VA_V_PAG) & VA_M_PAG)
/* Maps */
#define MAP_NUM 4 /* num maps */
#define MAP_LNT (1 << VA_N_PAG) /* map length */
#define MAP_MASK ((MAP_NUM * MAP_LNT) - 1)
#define SMAP 0 /* system map */
#define UMAP (SMAP + MAP_LNT) /* user map */
#define PAMAP (UMAP + MAP_LNT) /* port A map */
#define PBMAP (PAMAP + MAP_LNT) /* port B map */
/* Map entries are left shifted by VA_N_OFF, flags in lower 2b */
#define PA_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */
#define PA_V_PAG (VA_N_OFF)
#define PA_M_PAG ((1 << PA_N_PAG) - 1)
#define MAPM_V_RPR 15 /* in mem: read prot */
#define MAPM_V_WPR 14 /* write prot */
#define MAPA_V_RPR 1 /* in array: */
#define MAPA_V_WPR 0
#define PA_GETPAG(x) ((x) & (PA_M_PAG << VA_V_PAG))
#define RD (1 << MAPA_V_RPR)
#define WR (1 << MAPA_V_WPR)
/* Map status register */
#define MST_ENBI 0100000 /* mem enb @ int */
#define MST_UMPI 0040000 /* usr map @ int */
#define MST_ENB 0020000 /* mem enb */
#define MST_UMP 0010000 /* usr map */
#define MST_PRO 0004000 /* protection */
#define MST_FLT 0002000 /* fence comp */
#define MST_FENCE 0001777 /* base page fence */
/* Map violation register */
#define MVI_V_RPR 15
#define MVI_V_WPR 14
#define MVI_RPR (1 << MVI_V_RPR) /* rd viol */
#define MVI_WPR (1 << MVI_V_WPR) /* wr viol */
#define MVI_BPG 0020000 /* base page viol */
#define MVI_PRV 0010000 /* priv viol */
#define MVI_MEB 0000200 /* me bus enb @ viol */
#define MVI_MEM 0000100 /* mem enb @ viol */
#define MVI_UMP 0000040 /* usr map @ viol */
#define MVI_PAG 0000037 /* pag sel */
/* Timers */
#define TMR_CLK 0 /* clock */
#define TMR_MUX 1 /* multiplexor */
/* I/O sub-opcodes */
#define ioHLT 0 /* halt */
@@ -121,17 +193,25 @@ struct DMA { /* DMA channel */
#define PTP 012 /* paper tape punch */
#define CLK 013 /* clock */
#define LPT 014 /* line printer */
#define MTD 020 /* mag tape data */
#define MTC 021 /* mag tape control */
#define DPD 022 /* disk pack data */
#define DPC 023 /* disk pack control */
#define DPBD 024 /* second disk pack data */
#define DPBC 025 /* second disk pack control */
#define MTD 020 /* 12559A data */
#define MTC 021 /* 12559A control */
#define DPD 022 /* 12557A data */
#define DPC 023 /* 12557A control */
#define DQD 024 /* 12565A data */
#define DQC 025 /* 12565A control */
#define DRD 026 /* 12610A data */
#define DRC 027 /* 12610A control */
#define MSD 030 /* 13181A data */
#define MSC 031 /* 13181A control */
#define MUXL 040 /* 12920A lower data */
#define MUXU 041 /* 12920A upper data */
#define MUXC 042 /* 12920A control */
/* Dynamic device information table */
struct hpdev {
struct hp_dib {
int32 devno; /* device number */
int32 enb; /* enabled */
int32 cmd; /* saved command */
int32 ctl; /* saved control */
int32 flg; /* saved flag */
@@ -139,21 +219,7 @@ struct hpdev {
int32 (*iot)(); /* I/O routine */
};
/* Offsets in device information table */
#define inPTR 0 /* infotab ordinals */
#define inPTP 1
#define inTTY 2
#define inCLK 3
#define inLPT 4
#define inMTD 5
#define inMTC 6
#define inDPD 7
#define inDPC 8
#define inDPBD 9
#define inDPBC 10
#define UNIT_DEVNO (1 << UNIT_V_UF) /* dummy flag */
typedef struct hp_dib DIB;
/* I/O macros */
@@ -181,5 +247,5 @@ struct hpdev {
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 hp_setdev2 (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat hp_showdev2 (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);

View File

@@ -1,14 +1,14 @@
To: Users
From: Bob Supnik
Subj: HP2100 Simulator Usage
Date: 1-Dec-01
Date: 15-Jun-2002
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2001, written by Robert M Supnik
Copyright (c) 1993-2001, Robert M Supnik
Original code published in 1993-2002, written by Robert M Supnik
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"),
@@ -43,9 +43,14 @@ sim/ sim_defs.h
sim/hp2100/ hp2100_defs.h
hp2100_cpu.c
hp2100_fp.c
hp2100_dp.c
hp2100_dq.c
hp2100_dr.c
hp2100_lp.c
hp2100_mt.c
hp2100_ms.c
hp2100_mux.c
hp2100_stddev.c
hp2100_sys.c
@@ -62,8 +67,12 @@ PTR,PTP 12597A paper tape reader/punch
TTY 12631C buffered teleprinter
LPT 12653A line printer
CLK 12539A/B/C time base generator
DP 12557A cartridge disk controller with four drives
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
The HP2100 simulator implements several unique stop conditions:
@@ -116,7 +125,8 @@ control registers for the interrupt system.
STOP_INST 1 stop on undefined instruction
STOP_DEV 1 stop on undefined device
INDMAX 1 indirect address limit
OLDP 15 PC prior to last JMP, JSB, or interrupt
PCQ[0:63] 15 PC of last JMP, JSB, or interrupt;
most recent PC change first
WRU 8 interrupt character
2.2 DMA Controllers
@@ -140,22 +150,34 @@ On the HP2100, I/O device take their device numbers from the backplane
slot they are plugged into. Thus, device number assignments vary
considerably from system to system, and software package to software
package. The HP2100 simulator supports dynamic device number assignment.
The current device device is shown with the command SHOW <dev> DEVNO:
To show the current device number, use the SHOW <dev> DEVNO command:
sim> SHOW PTR DEV
device=10
The user can change the device number with the SET <dev> DEVNO=<num>
command:
To change the device number, use the SET <dev> DEVNO=<num> command:
sim> SET PTR DEV=30
sim> SHOW PTR DEV
device=30
The new device number must be in the range 010..077 (octal) and must
not be currently assigned to another device. For devices with two
device numbers, only the lower numbered device number can be changed;
the higher is automatically set to the lower + 1.
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.
In addition, most devices can be enabled or disabled. To enable a
device, use the SET <dev> ENABLED command:
sim> SET DP ENABLED
To disable a device, use the SET <dev> DISABLED command:
sim> SET DP DISABLED
For devices with two device numbers, disabling or enabling one device
in the pair disables or enables the other.
2.4 Programmed I/O Devices
@@ -177,10 +199,9 @@ The paper tape reader implements these registers:
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
POS 31 position in the input file
POS 32 position in the input file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
Error handling is as follows:
@@ -209,10 +230,9 @@ The paper tape punch implements these registers:
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
POS 31 position in the output file
POS 32 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
Error handling is as follows:
@@ -241,13 +261,12 @@ The terminal implements these registers:
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
KPOS 31 number of characters input
KPOS 32 number of characters input
KTIME 24 keyboard polling interval
TPOS 31 number of characters printed
TPOS 32 number of characters printed
TTIME 24 time from I/O initiation to interrupt
PPOS 31 position in the punch output file
PPOS 32 position in the punch output file
STOP_IOE 1 punch stop on I/O error
DEVNO 6 current device number (read only)
Error handling for the punch is as follows:
@@ -273,11 +292,10 @@ The line printer implements these registers:
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
POS 31 position in the output file
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
DEVNO 6 current device number (read only)
Error handling is as follows:
@@ -302,12 +320,106 @@ 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.5 12557A Cartridge Disk (DP)
2.4.6 12920A Terminal Multiplexor (MUXL, MUXU, MUXC)
The 12557A cartridge disk has two separate devices, a data channel and
The 12920A is a 16-line terminal multiplexor, with five additional
receive-only diagnostic lines. It consists of three devices:
MUX scanning logic (corresponding more or less
to the upper data card)
MUXL individual lines (corresponding more or
less to the lower data card)
MUXC modem control and status logic (corresponding
to the control card)
The MUX performs input and output through Telnet sessions connected to a
user-specified port. The ATTACH command to the scanning logic specifies
the port to be used:
ATTACH MUX <port> set up listening port
where port is a decimal number between 1 and 65535 that is not being used
for other TCP/IP activities.
Each line (each unit of MUXL) 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.
The modem controls model a simplified Bell 103A dataset with just four
lines: data terminal ready and request to send from the computer to the
data set, and carrier detect and data set ready from the data set to
the computer. There is no ring detection. If data terminal ready is
set when a Telnet connection starts up, then carrier detect and data
set ready are also set. The connection is established whether data
terminal ready is set or not.
Once MUX is attached and the simulator is running, the multiplexor listens
for connections on the specified port. It assumes that the incoming
connections are Telnet connections. The connections remain open until
disconnected either by the Telnet client, a SET MUXL DISCONNECT command,
or a DETACH MUX command.
The SHOW MUX CONNECTIONS command displays the current connections to the
extra terminals. The SHOW MUX STATISTICS command displays statistics for
active connections. The SET MUX DISCONNECT=linenumber disconnects the
specified line.
The scanner (MUX) implements these registers:
name size comments
IBUF 16 input buffer, holds line status
OBUF 16 output buffer, holds channel select
The lines (MUXL) implements these registers:
name size comments
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
STA[0:20] 16 line status, lines 0-20
RPAR[0:20] 16 receive parameters, lines 0-20
XPAR[0:15] 16 transmit parameters, lines 0-15
RBUF[0:20] 8 receive buffer, lines 0-20
XBUF[0:15] 8 transmit buffer, lines 0-15
RCHP[0:20] 1 receive character present, lines 0-20
XDON[0:15] 1 transmit done, lines 0-15
TIME[0:15] 24 transmit time, lines 0-15
The modem control (MUXM) implements these registers:
name size comments
CTL 1 device/interrupt enable
FLG 1 device ready
FBF 1 device ready buffer
SCAN 1 scan enabled
CHAN 4 current line
DSO[0:15] 6 C2,C1,ES2,ES1,SS2,SS1, lines 0-15
DSI[0:15] 2 S2,S1, lines 0-15
The terminal multiplexor does not support save and restore. All open
connections are lost when the simulator shuts down or MUXU is detached.
2.5 12557A/13210A Disk Controller (DP)
The 12557A/13210A disk controller can be configured as either a
12557A, supporting 2.5MB drives, or a 13210A, supporting 5MB drives,
with the commands:
SET DP 12557A 2.5MB drives
SET DP 13210A 5.0MB drives
Drive types cannot be intermixed; the controller is configured for
one type or the other.
The 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 REMOVEd or ADDed to the configuration.
disk drives. Disk drives can be set ONLINE or OFFLINE.
The data channel implements these registers:
@@ -315,12 +427,12 @@ The data channel implements these registers:
IBUF 16 input buffer
OBUF 16 output buffer
DBUF[0:127] 16 sector buffer
BPTR 7 sector buffer pointer
CMD 1 channel enable
CTL 1 interrupt enable
FLG 1 channel ready
FBF 1 channel ready buffer
DEVNO 6 current device number (read only)
The device controller implements these registers:
@@ -341,7 +453,6 @@ The device controller implements these registers:
STIME 24 seek delay time, per cylinder
XTIME 24 interword transfer time
STA[0:3] 16 drive status, drives 0-3
DEVNO 6 current device number (read only)
Error handling is as follows:
@@ -353,27 +464,125 @@ Error handling is as follows:
OS I/O error report error and stop
2.6 12559C Magnetic Tape (MT)
2.6 12565A Disk Controller (DP)
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 data channel implements these registers:
name size comments
IBUF 16 input buffer
OBUF 16 output buffer
DBUF[0:127] 16 sector buffer
BPTR 7 sector buffer pointer
CMD 1 channel enable
CTL 1 interrupt enable
FLG 1 channel ready
FBF 1 channel ready buffer
The device controller implements these registers:
name size comments
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
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
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:
error processed as
not attached disk not ready
end of file assume rest of disk is zero
OS I/O error report error and stop
2.7 12606A/12610A Fixed Head Disk/Drum Controller (DR)
The 12606A/12610A 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
The data channel implements these registers:
name size comments
IBUF 16 input buffer
OBUF 16 output buffer
CMD 1 channel enable
CTL 1 interrupt enable
FLG 1 channel ready
FBF 1 channel ready buffer
BPTR 6 sector buffer pointer
The device controller implements these registers:
name size comments
CW 16 command word
STA 16 status
CMD 1 controller enable
CTL 1 interrupt enable
FLG 1 controller ready
FBF 1 controller ready buffer
TIME 24 interword transfer time
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error processed as
not attached disk not ready
2.8 12559C Magnetic Tape (MT)
Magnetic tape options include the ability to make the unit write enabled
or write locked.
SET MT LOCKED set unit write locked
SET MT ENABLED set unit write enabled
SET MT 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
unit.
The data channel implements these registers:
name size comments
FLG 1 channel ready
DBUF[0:65535] 8 transfer buffer
BPTR 16 buffer pointer (reads and writes)
BMAX 16 buffer size (writes)
DEVNO 6 current device number (read only)
The device controller implements these registers:
@@ -382,17 +591,15 @@ The device controller implements these registers:
FNC 8 current function
STA 9 tape status
BUF 8 buffer
BUSY 3 busy (unit #, + 1, of active unit)
CTL 1 interrupt enabled
FLG 1 controller ready
FBF 1 controller ready buffer
DTF 1 data transfer flop
FSVC 1 first service flop
POS 31 magtape position
POS 32 magtape position
CTIME 24 command delay time
XTIME 24 interword transfer delay time
STOP_IOE 1 stop on I/O error
DEVNO 6 current device number (read only)
Error handling is as follows:
@@ -405,7 +612,59 @@ Error handling is as follows:
OS I/O error report error and stop
2.7 Symbolic Display and Input
2.9 13181A Magnetic Tape (MS)
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
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 data channel implements these registers:
name size comments
BUF 16 data buffer
CTL 1 interrupt enabled
FLG 1 channel ready
FBF 1 channel ready buffer
DBUF[0:65535] 8 transfer buffer
BPTR 17 buffer pointer (reads and writes)
BMAX 17 buffer size (writes)
The device controller implements these registers:
name size comments
STA 12 tape status
BUF 16 buffer
USEL 2 currently selected unit
FSVC 1 first service flop
CTL 1 interrupt enabled
FLG 1 controller ready
FBF 1 controller ready buffer
POS[0:3] 32 magtape position
CTIME 24 command delay time
XTIME 24 interword transfer delay time
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error processed as
not attached tape not ready
end of file (read or space) end of physical tape
(write) ignored
OS I/O error report error and stop
2.10 Symbolic Display and Input
The HP2100 simulator implements symbolic display and input. Display is
controlled by command line switches:

View File

@@ -1,6 +1,6 @@
/* hp2100_dp.c: HP 2100 disk pack simulator
/* hp2100_dp.c: HP 2100 12557A/13210A disk pack simulator
Copyright (c) 1993-2001, Robert M. Supnik
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"),
@@ -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 cartridge disk system
dp 12557A/13210A disk pack subsystem
15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith)
10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith)
03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW
24-Nov-01 RMS Changed STA to be an array
07-Sep-01 RMS Moved function prototypes
@@ -40,12 +42,15 @@
#define FNC u3 /* saved function */
#define CYL u4 /* cylinder */
#define DP_W_NUMWD 7
#define DP_NUMWD (1 << DP_W_NUMWD) /* words/sector */
#define DP_NUMSC 12 /* sectors/track */
#define DP_NUMTR 203 /* tracks/surface */
#define DP_NUMSF 4 /* surfaces/track */
#define DP_SIZE (DP_NUMSF * DP_NUMTR * DP_NUMSC * DP_NUMWD)
#define DP_N_NUMWD 7
#define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */
#define DP_NUMSC2 12 /* sectors/srf 12557 */
#define DP_NUMSC3 24 /* sectors/srf 13210 */
#define DP_NUMSC (dp_ctype? DP_NUMSC3: DP_NUMSC2)
#define DP_NUMSF 4 /* surfaces/cylinder */
#define DP_NUMCY 203 /* cylinders/disk */
#define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD)
#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD)
#define DP_NUMDRV 4 /* # drives */
/* Command word */
@@ -78,8 +83,13 @@
#define DA_M_HD 03
#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD)
#define DA_V_SC 0 /* sector */
#define DA_M_SC 017
#define DA_M_SC2 017
#define DA_M_SC3 037
#define DA_M_SC (dp_ctype? DA_M_SC3: DA_M_SC2)
#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)
#define DA_CKMASK2 037 /* check mask */
#define DA_CKMASK3 077
#define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2)
/* Status */
@@ -88,8 +98,8 @@
#define STA_OVR 0020000 /* overrun */
#define STA_RWU 0010000 /* rw unsafe */
#define STA_ACU 0004000 /* access unsafe */
#define STA_HUNT 0002000 /* hunting */
#define STA_SKI 0001000 /* incomplete */
#define STA_HUNT 0002000 /* hunting NI */
#define STA_SKI 0001000 /* incomplete NI */
#define STA_SKE 0000400 /* seek error */
/* 0000200 /* unused */
#define STA_NRDY 0000100 /* not ready */
@@ -102,11 +112,11 @@
#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)
#define STA_MBZ13 (STA_ATN + STA_RWU + STA_SKI) /* zero in 13210 */
extern uint16 M[];
extern struct hpdev infotab[];
extern int32 PC;
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 */
int32 dpc_cnt = 0; /* check count */
int32 dpc_eoc = 0; /* end of cyl */
@@ -118,16 +128,18 @@ int32 dpc_rarc = 0, dpc_rarh = 0, dpc_rars = 0; /* record addr */
int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */
int32 dpc_obuf = 0; /* cch buffers */
int32 dp_ptr = 0; /* buffer ptr */
uint16 dp_buf[DP_NUMWD]; /* sector buffer */
uint16 dpxb[DP_NUMWD]; /* sector buffer */
int32 dpdio (int32 inst, int32 IR, int32 dat);
int32 dpcio (int32 inst, int32 IR, int32 dat);
t_stat dpc_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);
t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev);
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
/* DPD data structures
@@ -136,23 +148,37 @@ void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev);
dpd_reg DPD register list
*/
UNIT dpd_unit = { UDATA (NULL, UNIT_FIX, DP_NUMWD) };
DIB dp_dib[] = {
{ DPD, 1, 0, 0, 0, 0, &dpdio },
{ DPC, 1, 0, 0, 0, 0, &dpcio } };
#define dpd_dib dp_dib[0]
#define dpc_dib dp_dib[1]
UNIT dpd_unit = { UDATA (NULL, 0, 0) };
REG dpd_reg[] = {
{ ORDATA (IBUF, dpd_ibuf, 16) },
{ ORDATA (OBUF, dpd_obuf, 16) },
{ FLDATA (CMD, infotab[inDPD].cmd, 0) },
{ FLDATA (CTL, infotab[inDPD].ctl, 0) },
{ FLDATA (FLG, infotab[inDPD].flg, 0) },
{ FLDATA (FBF, infotab[inDPD].fbf, 0) },
{ DRDATA (BPTR, dp_ptr, DP_W_NUMWD) },
{ ORDATA (DEVNO, infotab[inDPD].devno, 6), REG_RO },
{ FLDATA (CMD, dpd_dib.cmd, 0) },
{ FLDATA (CTL, dpd_dib.ctl, 0) },
{ FLDATA (FLG, dpd_dib.flg, 0) },
{ FLDATA (FBF, dpd_dib.fbf, 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 },
{ 0 } };
DEVICE dpd_dev = {
"DPD", &dpd_unit, dpd_reg, NULL,
1, 10, DP_W_NUMWD, 1, 8, 16,
&dpd_ex, &dpd_dep, &dpc_reset,
"DPD", &dpd_unit, dpd_reg, dpd_mod,
1, 10, DP_N_NUMWD, 1, 8, 16,
NULL, NULL, &dpc_reset,
NULL, NULL, NULL };
/* DPC data structures
@@ -164,10 +190,10 @@ DEVICE dpd_dev = {
*/
UNIT dpc_unit[] = {
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) },
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) },
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) },
{ UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE) } };
{ 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) } };
REG dpc_reg[] = {
{ ORDATA (OBUF, dpc_obuf, 16) },
@@ -176,31 +202,39 @@ REG dpc_reg[] = {
{ ORDATA (RARH, dpc_rarh, 2) },
{ ORDATA (RARS, dpc_rars, 4) },
{ ORDATA (CNT, dpc_cnt, 5) },
{ FLDATA (CMD, infotab[inDPC].cmd, 0) },
{ FLDATA (CTL, infotab[inDPC].ctl, 0) },
{ FLDATA (FLG, infotab[inDPC].flg, 0) },
{ FLDATA (FBF, infotab[inDPC].fbf, 0) },
{ 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) },
{ DRDATA (CTIME, dpc_ctime, 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) },
{ GRDATA (UFLG0, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (UFLG1, dpc_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (UFLG2, dpc_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ GRDATA (UFLG3, dpc_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
REG_HRO },
{ ORDATA (DEVNO, infotab[inDPC].devno, 6), REG_RO },
{ FLDATA (CTYPE, dp_ctype, 0), 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 }, */
{ MTAB_XTD | MTAB_VDV, inDPD, "DEVNO", "DEVNO",
&hp_setdev2, &hp_showdev2, 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 },
{ 0 } };
DEVICE dpc_dev = {
@@ -221,10 +255,10 @@ 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) & AMASK;
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (devd) != 0) PC = (PC + 1) & AMASK;
if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
dpd_obuf = dat;
@@ -258,10 +292,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (devc) == 0) PC = (PC + 1) & AMASK;
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (devc) != 0) PC = (PC + 1) & AMASK;
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
dpc_obuf = dat;
@@ -296,12 +330,8 @@ case ioCTL: /* control clear/set */
dp_go (fnc, drv, dpc_xtime, devc);
break;
case FNC_REF: case FNC_RD: case FNC_WD: /* ref, read, write */
dp_go (fnc, drv, dpc_ctime, devc);
break;
case FNC_INIT: /* init */
dpc_sta[drv] = dpc_sta[drv] | STA_FLG;
setFLG (devc); /* set cch flg */
clrCMD (devc); /* clr cch cmd */
dp_go (fnc, drv, dpc_ctime, devc);
break;
} /* end case */
} /* end else */
@@ -341,8 +371,8 @@ int32 i, da, drv, devc, devd, err, st, maxsc;
err = 0; /* assume no err */
drv = uptr - dpc_dev.units; /* get drive no */
devc = infotab[inDPC].devno; /* get cch devno */
devd = infotab[inDPD].devno; /* get dch devno */
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 */
@@ -370,9 +400,11 @@ case FNC_SEEK1: /* seek, need hd/sec */
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_NUMTR) { /* error? */
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;
@@ -397,10 +429,11 @@ case FNC_AR1: /* arec, need hd/sec */
case FNC_STA: /* read status */
if (CMD (devd)) { /* dch active? */
dpd_ibuf = dpc_sta[drv] | ((dpc_sta[drv] & STA_ALLERR)? STA_ERR: 0);
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 */
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 */
@@ -409,7 +442,7 @@ case FNC_STA: /* read status */
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++) dp_buf[i] = 0;
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? */
@@ -417,13 +450,13 @@ case FNC_REF: /* refine sector */
dpc_rarh = dpc_rarh ^ 1; } /* next surf */
if (err = fseek (uptr -> fileref, da * sizeof (int16),
SEEK_SET)) break;
fxwrite (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref);
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 & 037; /* get count */
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 */
@@ -461,23 +494,24 @@ case FNC_RD: /* read */
dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
if (err = fseek (uptr -> fileref, da * sizeof (int16),
SEEK_SET)) break;
fxread (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref);
fxread (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break; }
dpd_ibuf = dp_buf[dp_ptr++]; /* get word */
dpd_ibuf = dpxb[dp_ptr++]; /* get word */
if (dp_ptr >= DP_NUMWD) dp_ptr = 0; /* wrap if last */
setFLG (devd); /* set dch flg */
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 */
break; } /* done */
if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR;
dp_buf[dp_ptr++] = dpd_obuf; /* store word */
dpxb[dp_ptr++] = dpd_obuf; /* store word */
if (!CMD (devd)) { /* dch clr? done */
for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dp_buf[dp_ptr] = 0; }
for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dpxb[dp_ptr] = 0; }
if (dp_ptr >= DP_NUMWD) { /* buffer full? */
if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) {
dpc_sta[drv] = dpc_sta[drv] | STA_AER;
@@ -490,7 +524,7 @@ case FNC_WD: /* write */
dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */
if (err = fseek (uptr -> fileref, da * sizeof (int16),
SEEK_SET)) return TRUE;
fwrite (dp_buf, sizeof (int16), DP_NUMWD, uptr -> fileref);
fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref);
if (err = ferror (uptr -> fileref)) break;
dp_ptr = 0; }
if (CMD (devd)) { /* dch active? */
@@ -538,10 +572,10 @@ dpc_busy = dpc_obuf = 0;
dpc_eoc = 0;
dp_ptr = 0;
dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear rar */
infotab[inDPC].cmd = infotab[inDPD].cmd = 0; /* clear cmd */
infotab[inDPC].ctl = infotab[inDPD].ctl = 0; /* clear ctl */
infotab[inDPC].fbf = infotab[inDPD].fbf = 1; /* set fbf */
infotab[inDPC].flg = infotab[inDPD].flg = 1; /* set flg */
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 */
for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */
sim_cancel (&dpc_unit[i]); /* cancel activity */
dpc_unit[i].FNC = 0; /* clear function */
@@ -586,20 +620,28 @@ if (uptr -> flags & UNIT_ATT) return SCPE_ARG;
return SCPE_OK;
}
/* Buffer examine */
/* Set controller type */
t_stat dpd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (addr >= DP_NUMWD) return SCPE_NXM;
if (vptr != NULL) *vptr = dp_buf[addr] & DMASK;
int32 i;
if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
for (i = 0; i < DP_NUMDRV; i++) {
if (dpc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; }
for (i = 0; i < DP_NUMDRV; i++)
dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2);
dp_ctype = val;
return SCPE_OK;
}
/* Buffer deposit */
/* Show controller type */
t_stat dpd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
{
if (addr >= DP_NUMWD) return SCPE_NXM;
dp_buf[addr] = val & DMASK;
if (dp_ctype) fprintf (st, "13210A");
else fprintf (st, "12557A");
return SCPE_OK;
}

583
HP2100/hp2100_dq.c Normal file
View File

@@ -0,0 +1,583 @@
/* 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
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.
dq 12565A 2883/2884 disk system
09-Jan-02 WOM Copied dp driver and mods for 2883
*/
#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 DQ_N_NUMWD 7
#define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */
#define DQ_NUMSC 23 /* sectors/track */
#define DQ_NUMSF 20 /* tracks/cylinder */
#define DQ_NUMCY 203 /* cylinders/disk */
#define DQ_SIZE (DQ_NUMSF * DQ_NUMCY * DQ_NUMSC * DQ_NUMWD)
#define DQ_NUMDRV 2 /* # drives */
/* Command word */
#define CW_V_FNC 12 /* function */
#define CW_M_FNC 017
#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC)
/* 000 /* unused */
#define FNC_STA 001 /* status check */
#define FNC_RCL 002 /* recalibrate */
#define FNC_SEEK 003 /* seek */
#define FNC_RD 004 /* read */
#define FNC_WD 005 /* write */
#define FNC_RA 006 /* read address */
#define FNC_WA 007 /* write address */
#define FNC_CHK 010 /* check */
#define FNC_LA 013 /* load address */
#define FNC_AS 014 /* address skip */
#define FNC_SEEK1 020 /* fake - seek1 */
#define FNC_SEEK2 021 /* fake - seek2 */
#define FNC_CHK1 022 /* fake - check1 */
#define FNC_LA1 023 /* fake - arec1 */
#define FNC_RCL1 024 /* fake - recal1 */
#define CW_V_DRV 0 /* drive */
#define CW_M_DRV 01
#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV)
/* Disk address words */
#define DA_V_CYL 0 /* cylinder */
#define DA_M_CYL 0377
#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL)
#define DA_V_HD 8 /* head */
#define DA_M_HD 037
#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD)
#define DA_V_SC 0 /* sector */
#define DA_M_SC 037
#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC)
#define DA_CKMASK 0777 /* check mask */
/* Status */
#define STA_DID 0000200 /* drive ID */
#define STA_NRDY 0000100 /* not ready */
#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)
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
int32 dqc_busy = 0; /* cch busy */
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_xtime = 5; /* xfer time */
int32 dqc_rarc = 0, dqc_rarh = 0, dqc_rars = 0; /* record addr */
int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */
int32 dqc_obuf = 0; /* cch buffers */
int32 dq_ptr = 0; /* buffer ptr */
uint16 dqxb[DQ_NUMWD]; /* sector buffer */
int32 dqdio (int32 inst, int32 IR, int32 dat);
int32 dqcio (int32 inst, int32 IR, int32 dat);
t_stat dqc_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);
/* DQD data structures
dqd_dev DQD device descriptor
dqd_unit DQD unit list
dqd_reg DQD register list
*/
DIB dq_dib[] = {
{ DQD, 1, 0, 0, 0, 0, &dqdio },
{ DQC, 1, 0, 0, 0, 0, &dqcio } };
#define dqd_dib dq_dib[0]
#define dqc_dib dq_dib[1]
UNIT dqd_unit = { UDATA (NULL, 0, 0) };
REG dqd_reg[] = {
{ ORDATA (IBUF, dqd_ibuf, 16) },
{ ORDATA (OBUF, dqd_obuf, 16) },
{ FLDATA (CMD, dqd_dib.cmd, 0) },
{ FLDATA (CTL, dqd_dib.ctl, 0) },
{ FLDATA (FLG, dqd_dib.flg, 0) },
{ FLDATA (FBF, dqd_dib.fbf, 0) },
{ 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 },
{ 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 };
/* DQC data structures
dqc_dev DQC device descriptor
dqc_unit DQC unit list
dqc_reg DQC register list
dqc_mod DQC modifier list
*/
UNIT dqc_unit[] = {
{ UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) },
{ UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 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) },
{ 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) },
{ DRDATA (CTIME, dqc_ctime, 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) },
{ 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 },
{ MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &dqd_dib },
{ 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 };
/* IOT routines */
int32 dqdio (int32 inst, int32 IR, int32 dat)
{
int32 devd;
devd = IR & 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 */
dqd_obuf = dat;
break;
case ioMIX: /* merge */
dat = dat | dqd_ibuf;
break;
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 */
break;
default:
break; }
if (IR & HC) { clrFLG (devd); } /* H/C option */
return dat;
}
int32 dqcio (int32 inst, int32 IR, int32 dat)
{
int32 devc, fnc, drv;
devc = IR & DEVMASK; /* get device no */
switch (inst) { /* case on opcode */
case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
dqc_obuf = dat;
break;
case ioLIX: /* load */
dat = 0;
case ioMIX: /* merge */
break; /* no data */
case ioCTL: /* control clear/set */
if (IR & 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 */
} /* end else */
break;
default:
break; }
if (IR & HC) { clrFLG (devc); } /* H/C option */
return dat;
}
/* Unit service
Unit must be attached; detach cancels operation.
Seek substates
seek - transfer cylinder
seek1 - transfer head/surface
seek2 - done
Load address
la - transfer cylinder
la1 - transfer head/surface, finish operation
Status check - transfer status, finish operation
Check data
chk - transfer sector count
chk1 - finish operation
Read
Write
*/
#define GETDA(x,y,z) \
(((((x) * DQ_NUMSF) + (y)) * DQ_NUMSC) + (z)) * DQ_NUMWD
t_stat dqc_svc (UNIT *uptr)
{
int32 i, da, drv, devc, devd, err, st, maxsc;
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 */
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 */
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 */
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 */
setFLG (devd); /* set dch flg */
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 */
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 (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 */
setFLG (devc); /* set cch flg */
clrCMD (devc); /* clr cch cmd */
dqc_busy = 0; /* ctlr is free */
if (err != 0) { /* error? */
perror ("DQ I/O error");
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;
dqd_ibuf = dqd_obuf = 0; /* clear buffers */
dqc_busy = dqc_obuf = 0;
dqc_eoc = 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 */
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; }
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;
return SCPE_OK;
}

356
HP2100/hp2100_dr.c Normal file
View File

@@ -0,0 +1,356 @@
/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator
Copyright (c) 1993-2000, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
fhd 12606B fixed head disk
12619B 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 control channel does not have any of the traditional flip-flops.
*/
#include "hp2100_defs.h"
#include <math.h>
/* Constants */
#define DR_NUMWD 64 /* words/sector */
#define DR_FNUMSC 90 /* fhd sec/track */
#define DR_DNUMSC 32 /* drum sec/track */
#define DR_NUMSC ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)
#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */
#define UNIT_V_DR (UNIT_V_UF) /* disk vs drum */
#define UNIT_DR (1 << UNIT_V_DR)
/* Command word */
#define CW_WR 0100000 /* write vs read */
#define CW_V_FTRK 7
#define CW_M_FTRK 0177
#define CW_V_DTRK 5
#define CW_M_DTRK 01777
#define MAX_TRK (((drc_unit.flags & UNIT_DR)? CW_M_DTRK: CW_M_FTRK) + 1)
#define CW_GETTRK(x) ((drc_unit.flags & UNIT_DR)? \
(((x) >> CW_V_DTRK) & CW_M_DTRK): \
(((x) >> CW_V_FTRK) & CW_M_FTRK))
#define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DR)? \
(((x) & CW_M_DTRK) << CW_V_DTRK): \
(((x) & CW_M_FTRK) << CW_V_FTRK))
#define CW_V_FSEC 0
#define CW_M_FSEC 0177
#define CW_V_DSEC 0
#define CW_M_DSEC 037
#define CW_GETSEC(x) ((drc_unit.flags & UNIT_DR)? \
(((x) >> CW_V_DSEC) & CW_M_DSEC): \
(((x) >> CW_V_FSEC) & CW_M_FSEC))
#define CW_PUTSEC(x) ((drc_unit.flags & UNIT_DR)? \
(((x) & CW_M_DSEC) << CW_V_DSEC): \
(((x) & CW_M_FSEC) << CW_V_FSEC))
/* Status register */
#define DRS_V_NS 8 /* next sector */
#define DRS_M_NS 0177
#define DRS_SEC 0100000 /* sector flag */
#define DRS_RDY 0000200 /* ready */
#define DRS_RIF 0000100 /* read inhibit */
#define DRS_SAC 0000040 /* sector coincidence */
#define DRS_ABO 0000010 /* abort */
#define DRS_WEN 0000004 /* write enabled */
#define DRS_PER 0000002 /* parity error */
#define DRS_BSY 0000001 /* busy */
#define GET_CURSEC(x) ((int32) fmod (sim_gtime() / ((double) (x)), \
((double) ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC))))
extern UNIT cpu_unit;
extern 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 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);
int32 dr_incda (int32 trk, int32 sec, int32 ptr);
t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
/* DRD data structures
drd_dev device descriptor
drd_unit unit descriptor
drd_reg register list
*/
DIB dr_dib[] = {
{ DRD, 1, 0, 0, 0, 0, &drdio },
{ DRC, 1, 0, 0, 0, 0, &drcio } };
#define drd_dib dr_dib[0]
#define drc_dib dr_dib[1]
UNIT drd_unit = { UDATA (NULL, 0, 0) };
REG drd_reg[] = {
{ ORDATA (IBUF, drd_ibuf, 16) },
{ ORDATA (OBUF, drd_obuf, 16) },
{ FLDATA (CMD, drd_dib.cmd, 0) },
{ FLDATA (CTL, drd_dib.ctl, 0) },
{ FLDATA (FLG, drd_dib.flg, 0) },
{ FLDATA (FBF, drd_dib.fbf, 0) },
{ ORDATA (BPTR, drd_ptr, 6) },
{ ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO },
{ 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 },
{ 0 } };
DEVICE drd_dev = {
"DRD", &drd_unit, drd_reg, drd_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, NULL,
NULL, NULL, NULL };
/* DRC data structures
drc_dev device descriptor
drc_unit unit descriptor
drc_mod unit modifiers
drc_reg register list
*/
UNIT drc_unit =
{ UDATA (&drc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+
UNIT_MUSTBUF+UNIT_DR+UNIT_BINK, DR_SIZE) };
REG drc_reg[] = {
{ ORDATA (CW, drc_cw, 16) },
{ ORDATA (STA, drc_sta, 16) },
{ FLDATA (CMD, drc_dib.cmd, 0) },
{ FLDATA (CTL, drc_dib.ctl, 0) },
{ FLDATA (FLG, drc_dib.flg, 0) },
{ FLDATA (FBF, drc_dib.fbf, 0) },
{ DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, dr_stopioe, 0) },
{ ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO },
{ FLDATA (*DEVENB, drc_dib.enb, 0), REG_HRO },
{ NULL } };
MTAB drc_mod[] = {
{ UNIT_DR, 0, "disk", NULL, NULL },
{ UNIT_DR, UNIT_DR, "drum", NULL, NULL },
{ UNIT_DR, 184320, NULL, "180K", &dr_set_size },
{ UNIT_DR, 368640, NULL, "360K", &dr_set_size },
{ UNIT_DR, 737280, NULL, "720K", &dr_set_size },
{ UNIT_DR, 368640+1, NULL, "384K", &dr_set_size },
{ UNIT_DR, 524280+1, NULL, "512K", &dr_set_size },
{ UNIT_DR, 655360+1, NULL, "640K", &dr_set_size },
{ UNIT_DR, 786432+1, NULL, "768K", &dr_set_size },
{ 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 },
{ 0 } };
DEVICE drc_dev = {
"DRC", &drc_unit, drc_reg, drc_mod,
1, 8, 21, 1, 8, 16,
NULL, NULL, &drc_reset,
NULL, NULL, NULL };
/* IOT routines */
int32 drdio (int32 inst, int32 IR, int32 dat)
{
int32 devd, t;
devd = IR & 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;
case ioMIX: /* merge */
dat = dat | drd_ibuf;
break;
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 */
else if (!CMD (devd)) { /* STC, not set? */
setCMD (devd); /* set "ctl" */
if (drc_cw & CW_WR) setFLG (devd); /* prime DMA */
drc_sta = 0; /* clear errors */
drd_ptr = 0; /* clear sec ptr */
sim_cancel (&drc_unit); /* cancel curr op */
t = CW_GETSEC (drc_cw) - GET_CURSEC (dr_time * DR_NUMWD);
if (t <= 0) t = t + DR_NUMSC;
sim_activate (&drc_unit, t * DR_NUMWD * dr_time); }
break;
default:
break; }
if (IR & HC) { clrFLG (devd); } /* H/C option */
return dat;
}
int32 drcio (int32 inst, int32 IR, int32 dat)
{
int32 devc, st;
devc = IR & DEVMASK; /* get device no */
switch (inst) { /* case on opcode */
case ioSFC: /* skip flag clear */
PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
drc_cw = dat;
break;
case ioLIX: /* load */
dat = 0;
case ioMIX: /* merge */
if (drc_unit.flags & UNIT_ATT)
st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta |
(sim_is_active (&drc_unit)? DRS_BSY: 0);
else st = drc_sta;
break;
default:
break; }
return dat;
}
/* Unit service */
t_stat drc_svc (UNIT *uptr)
{
int32 devc, devd, trk, sec;
uint32 da;
if ((uptr -> flags & UNIT_ATT) == 0) {
drc_sta = DRS_ABO;
return IORETURN (dr_stopioe, SCPE_UNATT); }
drc_sta = drc_sta | DRS_SAC;
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; }
drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */
if (CMD (devd)) { /* dch active? */
setFLG (devd); /* set dch flg */
sim_activate (uptr, dr_time); } /* sched next word */
else if (drd_ptr) { /* done, need to fill? */
for ( ; drd_ptr < DR_NUMWD; drd_ptr++)
*(((uint16 *) uptr -> filebuf) + da + drd_ptr) = 0; }
} /* end write */
else { /* read */
if (CMD (devd)) { /* dch active? */
if ((da >= uptr -> capac) || (sec >= DR_NUMSC)) drd_ibuf = 0;
else drd_ibuf = *(((uint16 *) uptr -> filebuf) + da + drd_ptr);
drd_ptr = dr_incda (trk, sec, drd_ptr);
setFLG (devd); /* set dch flg */
sim_activate (uptr, dr_time); } /* sched next word */
}
return SCPE_OK;
}
/* Increment current disk address */
int32 dr_incda (int32 trk, int32 sec, int32 ptr)
{
ptr = ptr + 1; /* inc pointer */
if (ptr >= DR_NUMWD) { /* end sector? */
ptr = 0; /* new sector */
sec = sec + 1; /* adv sector */
if (sec >= DR_NUMSC) { /* end track? */
sec = 0; /* new track */
trk = trk + 1; /* adv track */
if (trk >= MAX_TRK) trk = 0; } /* wraps at max */
drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec);
}
return ptr;
}
/* Reset routine */
t_stat drc_reset (DEVICE *dptr)
{
drc_sta = drc_cw = drd_ptr = 0;
drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */
drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */
drc_dib.fbf = drd_dib.fbf = 0; /* clear fbf */
drc_dib.flg = drd_dib.flg = 0; /* clear flg */
sim_cancel (&drc_unit);
return SCPE_OK;
}
/* 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;
return SCPE_OK;
}

296
HP2100/hp2100_fp.c Normal file
View File

@@ -0,0 +1,296 @@
/* hp2100_fp.c: HP 2100 floating point instructions
Copyright (c) 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.
The HP2100 uses a unique binary floating point format:
15 14 0
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|S | fraction high | : A
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| fraction low | exponent |XS| : A + 1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
15 8 7 1 0
where S = 0 for plus fraction, 1 for minus fraction
fraction = s.bbbbb..., 24 binary digits
exponent = 2**+/-n
XS = 0 for plus exponent, 1 for minus exponent
Numbers can be normalized or unnormalized but are always normalized
when loaded.
Unpacked floating point numbers are stored in structure ufp
sign = fraction sign, 0 = +, 1 = -
exp = exponent, 2's complement
h'l = fraction, 2's comp, with 1 high guard bit
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)
*/
#include "hp2100_defs.h"
struct ufp { /* unpacked fp */
int32 sign; /* sign */
int32 exp; /* exp */
uint32 h; /* frac */
uint32 l; };
#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_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_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 FPAB ((((uint32) AR) << 16) | ((uint32) BR))
#define HFMASK 0x7FFFFFFF /* hi frac mask */
#define LFMASK 0xFFFFFFFF /* lo frac mask */
/* 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_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
extern uint16 *M;
void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs);
void NormFP (struct ufp *fop);
int32 StoreFP (struct ufp *fop, t_bool rnd);
/* Floating to integer conversion */
int32 f_fix (void)
{
struct ufp res;
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 */
return 0;
}
/* Integer to floating conversion */
void f_flt (void)
{
struct ufp res = { 0, 15, 0, 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;
}
/* Floating point add/subtract */
int32 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 */
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 */
}
/* Floating point multiply */
int32 f_mul (uint32 opnd)
{
struct ufp fop1, fop2;
struct ufp res = { 0, 0, 0, 0 };
int32 i;
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 */
}
/* Floating point divide */
int32 f_div (uint32 opnd)
{
struct ufp fop1, fop2;
struct ufp quo = { 0, 0, 0, 0 };
int32 i;
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 */
}
/* Utility routines */
/* Unpack operand */
void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs)
{
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;
}
/* 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 */
return;
}
/* Round fp number, store, generate overflow */
int32 StoreFP (struct ufp *fop, t_bool rnd)
{
int32 hi, ov;
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 */
AR = (hi >> 16) & DMASK;
BR = hi & DMASK;
return ov;
}

View File

@@ -1,6 +1,6 @@
/* hp2100_lp.c: HP 2100 line printer simulator
/* hp2100_lp.c: HP 2100 12653A line printer simulator
Copyright (c) 1993-2001, Robert M. Supnik
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"),
@@ -25,6 +25,7 @@
lpt 12653A 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
@@ -41,9 +42,10 @@ 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_stopioe = 0; /* stop on error */
int32 lptio (int32 inst, int32 IR, int32 dat);
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
extern struct hpdev infotab[];
/* LPT data structures
@@ -52,25 +54,32 @@ extern struct hpdev infotab[];
lpt_reg LPT register list
*/
DIB lpt_dib = { LPT, 1, 0, 0, 0, 0, &lptio };
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 7) },
{ FLDATA (CMD, infotab[inLPT].cmd, 0) },
{ FLDATA (CTL, infotab[inLPT].ctl, 0) },
{ FLDATA (FLG, infotab[inLPT].flg, 0) },
{ FLDATA (FBF, infotab[inLPT].fbf, 0) },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ FLDATA (CMD, lpt_dib.cmd, 0) },
{ FLDATA (CTL, lpt_dib.ctl, 0) },
{ FLDATA (FLG, lpt_dib.flg, 0) },
{ FLDATA (FBF, lpt_dib.fbf, 0) },
{ DRDATA (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, infotab[inLPT].devno, 6), REG_RO },
{ ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO },
{ FLDATA (*DEVENB, lpt_dib.enb, 0), REG_HRO },
{ NULL } };
MTAB lpt_mod[] = {
{ MTAB_XTD | MTAB_VDV, inLPT, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 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 },
{ 0 } };
DEVICE lpt_dev = {
@@ -91,10 +100,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & AMASK;
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & AMASK;
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
lpt_unit.buf = dat & 0177;
@@ -124,7 +133,7 @@ t_stat lpt_svc (UNIT *uptr)
{
int32 dev;
dev = infotab[inLPT].devno; /* get dev no */
dev = lpt_dib.devno; /* get dev no */
clrCMD (dev); /* clear cmd */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
@@ -137,12 +146,12 @@ lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */
return SCPE_OK;
}
/* Reset routine - called from SCP, flags in infotab */
/* Reset routine - called from SCP, flags in DIB */
t_stat lpt_reset (DEVICE *dptr)
{
infotab[inLPT].cmd = infotab[inLPT].ctl = 0; /* clear cmd, ctl */
infotab[inLPT].flg = infotab[inLPT].fbf = 1; /* set flg, fbf */
lpt_dib.cmd = lpt_dib.ctl = 0; /* clear cmd, ctl */
lpt_dib.flg = lpt_dib.fbf = 1; /* set flg, fbf */
lpt_unit.buf = 0;
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;

509
HP2100/hp2100_ms.c Normal file
View File

@@ -0,0 +1,509 @@
/* hp2100_ms.c: HP 2100 13181A magnetic tape 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.
ms 13181A nine track magnetic tape
30-May-02 RMS Widened POS to 32b
22-Apr-02 RMS Added maximum record length test
Magnetic tapes are represented as a series of variable records
of the form:
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32b byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
Unusually among HP peripherals, the 12559 does not have a command flop,
and its flag and flag buffer power up as clear rather than set.
*/
#include "hp2100_defs.h"
#define MS_NUMDR 4 /* number of drives */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define DB_N_SIZE 16 /* max data buf */
#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */
#define DBMASK (DBSIZE - 1)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
#define FNC u3 /* function */
#define UST u4 /* unit status */
/* 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_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 */
/* 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)
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
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_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 */
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_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
t_bool ms_forwsp (UNIT *uptr, int32 *err);
t_bool ms_backsp (UNIT *uptr, int32 *err);
/* MSD data structures
msd_dev MSD device descriptor
msd_unit MSD unit list
msd_reg MSD register list
*/
DIB ms_dib[] = {
{ MSD, 1, 0, 0, 0, 0, &msdio },
{ MSC, 1, 0, 0, 0, 0, &mscio } };
#define msd_dib ms_dib[0]
#define msc_dib ms_dib[1]
UNIT msd_unit = { UDATA (NULL, 0, 0) };
REG msd_reg[] = {
{ ORDATA (BUF, msd_buf, 16) },
{ FLDATA (CMD, msd_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, msd_dib.ctl, 0) },
{ FLDATA (FLG, msd_dib.flg, 0) },
{ FLDATA (FBF, msd_dib.fbf, 0) },
{ BRDATA (DBUF, msxb, 8, 8, DBSIZE) },
{ DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
{ DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
{ ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO },
{ 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 },
{ 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 };
/* MSC data structures
msc_dev MSC device descriptor
msc_unit MSC unit list
msc_reg MSC register list
msc_mod MSC modifier list
*/
UNIT msc_unit[] = {
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
{ UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } };
REG msc_reg[] = {
{ ORDATA (STA, msc_sta, 12) },
{ ORDATA (BUF, msc_buf, 16) },
{ ORDATA (USEL, msc_usl, 2) },
{ FLDATA (FSVC, msc_1st, 0) },
{ FLDATA (CMD, msc_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, msc_dib.ctl, 0) },
{ FLDATA (FLG, msc_dib.flg, 0) },
{ FLDATA (FBF, msc_dib.fbf, 0) },
{ URDATA (POS, msc_unit[0].pos, 8, 32, 0, MS_NUMDR, PV_LEFT) },
{ URDATA (FNC, msc_unit[0].FNC, 8, 12, 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 (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) },
{ 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, 1, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &msd_dib },
{ 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 };
/* IOT routines */
int32 msdio (int32 inst, int32 IR, int32 dat)
{
int32 devd;
devd = IR & 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 */
msd_buf = dat; /* store data */
break;
case ioMIX: /* merge */
dat = dat | msd_buf;
break;
case ioLIX: /* load */
dat = msd_buf;
break;
case ioCTL: /* control clear/set */
if (IR & AB) { /* CLC */
clrCTL (devd); /* clr ctl, cmd */
clrCMD (devd); }
else { setCTL (devd); /* STC */
setCMD (devd); } /* set ctl, cmd */
break;
default:
break; }
if (IR & HC) { clrFLG (devd); } /* H/C option */
return dat;
}
int32 mscio (int32 inst, int32 IR, int32 dat)
{
int32 i, devc, devd;
UNIT *uptr = msc_dev.units + msc_usl;
static const uint8 map_sel[16] = {
0, 0, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3 };
devc = IR & DEVMASK; /* get device no */
devd = devc - 1;
switch (inst) { /* case on opcode */
case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
msc_buf = dat = 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; }
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;
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;
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); }
break;
default:
break; }
if (IR & HC) { clrFLG (devc); } /* H/C option */
return dat;
}
/* Unit service
If rewind done, reposition to start of tape, set status
else, do operation, set done, interrupt
Can't be write locked, can only write lock detached unit
*/
t_stat msc_svc (UNIT *uptr)
{
int32 devc, devd, err, i;
static t_mtrlnt bceof = { 0 };
if ((uptr -> flags & UNIT_ATT) == 0) { /* offline? */
msc_sta = STA_LOCAL | STA_BUSY | STA_REJ;
return IORETURN (msc_stopioe, SCPE_UNATT); }
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; }
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 */
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 */
break;
case FNC_BSR: /* space reverse */
ms_backsp (uptr, &err);
break;
/* Unit service, continued */
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); }
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;
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 (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)); }
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); }
return SCPE_OK;
}
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));
return TRUE;
}
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));
return TRUE;
}
/* Reset routine */
t_stat msc_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;
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 */
for (i = 0; i < MS_NUMDR; i++) {
uptr = msc_dev.units + i;
sim_cancel (uptr);
uptr -> UST = 0; }
return SCPE_OK;
}
/* 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;
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* hp2100_mt.c: HP 2100 magnetic tape simulator
/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator
Copyright (c) 1993-2001, Robert M. Supnik
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"),
@@ -25,6 +25,9 @@
mt 12559A nine track magnetic tape
30-May-02 RMS Widened POS to 32b
22-Apr-02 RMS Added maximum record length test
20-Jan-02 RMS Fixed bug on last character write
03-Dec-01 RMS Added read only unit, extended SET/SHOW support
07-Sep-01 RMS Moved function prototypes
30-Nov-00 RMS Made variable names unique
@@ -81,8 +84,6 @@
#define STA_PAR 0002 /* parity error */
#define STA_BUSY 0001 /* busy */
extern uint16 M[];
extern struct hpdev infotab[];
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
int32 mtc_fnc = 0; /* function */
@@ -92,18 +93,18 @@ int32 mtc_1st = 0; /* first svc flop */
int32 mtc_ctime = 1000; /* command wait */
int32 mtc_xtime = 10; /* data xfer time */
int32 mtc_stopioe = 1; /* stop on error */
uint8 mt_buf[DBSIZE] = { 0 }; /* data buffer */
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 };
int32 mtdio (int32 inst, int32 IR, int32 dat);
int32 mtcio (int32 inst, int32 IR, int32 dat);
t_stat mtc_svc (UNIT *uptr);
t_stat mtc_reset (DEVICE *dptr);
t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat mtc_attach (UNIT *uptr, char *cptr);
t_stat mtc_detach (UNIT *uptr);
t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
/* MTD data structures
@@ -112,22 +113,36 @@ t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
mtd_reg MTD register list
*/
UNIT mtd_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, DBSIZE) };
DIB mt_dib[] = {
{ MTD, 1, 0, 0, 0, 0, &mtdio },
{ MTC, 1, 0, 0, 0, 0, &mtcio } };
#define mtd_dib mt_dib[0]
#define mtc_dib mt_dib[1]
UNIT mtd_unit = { UDATA (NULL, 0, 0) };
REG mtd_reg[] = {
{ FLDATA (CMD, infotab[inMTD].cmd, 0), REG_HRO },
{ FLDATA (CTL, infotab[inMTD].ctl, 0), REG_HRO },
{ FLDATA (FLG, infotab[inMTD].flg, 0) },
{ FLDATA (FBF, infotab[inMTD].fbf, 0), REG_HRO },
{ FLDATA (CMD, mtd_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, mtd_dib.ctl, 0), REG_HRO },
{ FLDATA (FLG, mtd_dib.flg, 0) },
{ FLDATA (FBF, mtd_dib.fbf, 0), REG_HRO },
{ BRDATA (DBUF, mtxb, 8, 8, DBSIZE) },
{ DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) },
{ DRDATA (BMAX, mt_max, DB_V_SIZE + 1) },
{ ORDATA (DEVNO, infotab[inMTD].devno, 6), REG_RO },
{ 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 },
{ 0 } };
DEVICE mtd_dev = {
"MTD", &mtd_unit, mtd_reg, NULL,
"MTD", &mtd_unit, mtd_reg, mtd_mod,
1, 10, 16, 1, 8, 8,
&mtd_ex, &mtd_dep, &mtc_reset,
NULL, NULL, &mtc_reset,
NULL, NULL, NULL };
/* MTC data structures
@@ -144,25 +159,30 @@ REG mtc_reg[] = {
{ ORDATA (FNC, mtc_fnc, 8) },
{ ORDATA (STA, mtc_sta, 9) },
{ ORDATA (BUF, mtc_unit.buf, 8) },
{ FLDATA (CMD, infotab[inMTC].cmd, 0), REG_HRO },
{ FLDATA (CTL, infotab[inMTC].ctl, 0) },
{ FLDATA (FLG, infotab[inMTC].flg, 0) },
{ FLDATA (FBF, infotab[inMTC].fbf, 0) },
{ FLDATA (CMD, mtc_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, mtc_dib.ctl, 0) },
{ FLDATA (FLG, mtc_dib.flg, 0) },
{ FLDATA (FBF, mtc_dib.fbf, 0) },
{ FLDATA (DTF, mtc_dtf, 0) },
{ FLDATA (FSVC, mtc_1st, 0) },
{ DRDATA (POS, mtc_unit.pos, 31), PV_LEFT },
{ DRDATA (POS, mtc_unit.pos, 32), PV_LEFT },
{ DRDATA (CTIME, mtc_ctime, 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 (CDEVNO, infotab[inMTC].devno, 6), REG_RO },
{ 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", "ENABLED", &mtc_vlock },
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mtc_vlock },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mtc_vlock },
{ MTAB_XTD | MTAB_VDV, inMTD, "DEVNO", "DEVNO",
&hp_setdev2, &hp_showdev2, NULL },
{ 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 },
{ 0 } };
DEVICE mtc_dev = {
@@ -183,10 +203,10 @@ 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) & AMASK;
if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (devd) != 0) PC = (PC + 1) & AMASK;
if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
mtc_unit.buf = dat & 0377; /* store data */
@@ -217,10 +237,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (devc); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (devc) == 0) PC = (PC + 1) & AMASK;
if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (devc) != 0) PC = (PC + 1) & AMASK;
if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
dat = dat & 0377;
@@ -287,15 +307,14 @@ 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 = infotab[inMTC].devno; /* get device nos */
devd = infotab[inMTD].devno;
devc = mtc_dib.devno; /* get device nos */
devd = mtd_dib.devno;
err = 0; /* assume no errors */
switch (mtc_fnc & 0377) { /* case on function */
case FNC_REW: /* rewind */
mtc_unit.pos = 0; /* BOT */
setFLG (devc); /* set cch flg */
mtc_sta = (mtc_sta | STA_BOT) & ~STA_BUSY; /* update status */
mtc_sta = mtc_sta | STA_BOT; /* update status */
break;
case FNC_RWS: /* rewind and offline */
mtc_unit.pos = 0; /* BOT */
@@ -308,15 +327,11 @@ case FNC_WFM: /* write file mark */
mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); /* update tape pos */
mtc_sta = mtc_sta | STA_EOF; /* set EOF status */
case FNC_GAP: /* erase gap */
setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* update status */
break;
/* Unit service, continued */
case FNC_FSR: /* space forward */
setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* update status */
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? */
@@ -328,8 +343,6 @@ case FNC_FSR: /* space forward */
(2 * sizeof (t_mtrlnt)); /* update position */
break;
case FNC_BSR: /* space reverse */
setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* update status */
if (mtc_unit.pos == 0) { /* at BOT? */
mtc_sta = mtc_sta | STA_BOT; /* update status */
break; }
@@ -365,45 +378,44 @@ case FNC_RC: /* read */
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) || (mt_max < 12)) {
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 (mt_buf, sizeof (int8), mt_max, mtc_unit.fileref);
for ( ; i < mt_max; i++) mt_buf[i] = 0; /* fill with 0's */
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); }
if (mt_ptr < mt_max) { /* more chars? */
if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM;
mtc_unit.buf = mt_buf[mt_ptr++]; /* fetch next */
mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */
setFLG (devd); /* set dch flg */
sim_activate (uptr, mtc_xtime); } /* re-activate */
else { setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; } /* update status */
sim_activate (uptr, mtc_xtime); /* re-activate */
return SCPE_OK; }
break;
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; }
if (mtc_dtf) { /* xfer flop set? */
if (!mtc_1st) { /* not first? */
if (mt_ptr < DBSIZE) /* room in buffer? */
mt_buf[mt_ptr++] = mtc_unit.buf;
else mtc_sta = mtc_sta | STA_PAR; }
mtc_1st = 0; /* clr 1st flop */
setFLG (devd); /* set dch flag */
sim_activate (uptr, mtc_xtime); /* re-activate */
break; }
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 (mt_buf, sizeof (int8), mt_ptr, 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)); }
setFLG (devc); /* set cch flg */
mtc_sta = mtc_sta & ~STA_BUSY; /* update status */
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);
@@ -416,10 +428,10 @@ return SCPE_OK;
t_stat mtc_reset (DEVICE *dptr)
{
mtc_fnc = 0;
infotab[inMTC].cmd = infotab[inMTD].cmd = 0; /* clear cmd */
infotab[inMTC].ctl = infotab[inMTD].ctl = 0; /* clear ctl */
infotab[inMTC].flg = infotab[inMTD].flg = 0; /* clear flg */
infotab[inMTC].fbf = infotab[inMTD].fbf = 0; /* clear fbf */
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 */
if (mtc_unit.flags & UNIT_ATT) mtc_sta = ((mtc_unit.pos)? 0: STA_BOT) |
((mtc_unit.flags & UNIT_WPRT)? STA_WLK: 0);
@@ -454,21 +466,3 @@ t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG;
return SCPE_OK;
}
/* Buffer examine */
t_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= DBSIZE) return SCPE_NXM;
if (vptr != NULL) *vptr = mt_buf[addr] & 0377;
return SCPE_OK;
}
/* Buffer deposit */
t_stat mtd_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= DBSIZE) return SCPE_NXM;
mt_buf[addr] = val & 0377;
return SCPE_OK;
}

715
HP2100/hp2100_mux.c Normal file
View File

@@ -0,0 +1,715 @@
/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator
Copyright (c) 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.
mux,muxl,muxc 12920A terminal multiplexor
The 12920A consists of three separate devices
mux scanner (upper data card)
muxl lines (lower data card)
muxm modem control (control card)
The lower data card has no CMD flop; the control card has no CMD flop.
The upper data card has none of the usual flops.
*/
#include "hp2100_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
#define MUX_LINES 16 /* user lines */
#define MUX_ILINES 5 /* diag rcv only */
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_V_MDM (UNIT_V_UF + 1) /* modem control */
#define UNIT_UC (1 << UNIT_V_UC)
#define UNIT_MDM (1 << UNIT_V_MDM)
#define MUXU_INIT_POLL 8000
#define MUXL_WAIT 500
/* Channel number (OTA upper, LIA lower or upper) */
#define MUX_V_CHAN 10 /* channel num */
#define MUX_M_CHAN 037
#define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN)
/* OTA, lower = parameters or data */
#define OTL_P 0100000 /* parameter */
#define OTL_TX 0040000 /* transmit */
#define OTL_ENB 0020000 /* enable */
#define OTL_TPAR 0010000 /* xmt parity */
#define OTL_ECHO 0010000 /* rcv echo */
#define OTL_DIAG 0004000 /* diagnose */
#define OTL_SYNC 0004000 /* sync */
#define OTL_V_LNT 8 /* char length */
#define OTL_M_LNT 07
#define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT)
#define OTL_V_BAUD 0 /* baud rate */
#define OTL_M_BAUD 0377
#define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD)
#define OTL_CHAR 01777 /* char mask */
/* LIA, lower = received data */
#define LIL_PAR 0100000 /* parity */
#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN)
#define LIL_CHAR 01777 /* character */
/* LIA, upper = status */
#define LIU_SEEK 0100000 /* seeking NI */
#define LIU_DG 0000010 /* diagnose */
#define LIU_BRK 0000004 /* break NI */
#define LIU_LOST 0000002 /* char lost */
#define LIU_TR 0000001 /* trans/rcv */
/* OTA, control */
#define OTC_SCAN 0100000 /* scan */
#define OTC_UPD 0040000 /* update */
#define OTC_V_CHAN 10 /* channel */
#define OTC_M_CHAN 017
#define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN)
#define OTC_EC2 0000200 /* enable Cn upd */
#define OTC_EC1 0000100
#define OTC_C2 0000040 /* Cn flops */
#define OTC_C1 0000020
#define OTC_ES2 0000010 /* enb comparison */
#define OTC_ES1 0000004
#define OTC_V_ES 2
#define OTC_SS2 0000002 /* SSn flops */
#define OTC_SS1 0000001
#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1)
#define RTS OCT_C2 /* C2 = rts */
#define DTR OTC_C1 /* C1 = dtr */
/* LIA, control */
#define LIC_MBO 0140000 /* always set */
#define LIC_V_CHAN 10 /* channel */
#define LIC_M_CHAN 017
#define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN)
#define LIC_I2 0001000 /* change flags */
#define LIC_I1 0000400
#define LIC_S2 0000002 /* Sn flops */
#define LIC_S1 0000001
#define LIC_V_I 8 /* S1 to I1 */
#define CDET LIC_S2 /* S2 = cdet */
#define DSR LIC_S1 /* S1 = dsr */
#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \
((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \
<< LIC_V_I)
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
uint16 mux_sta[MUX_LINES]; /* line status */
uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */
uint16 mux_xpar[MUX_LINES]; /* xmt param */
uint8 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */
uint8 mux_xbuf[MUX_LINES]; /* xmt buf */
uint8 mux_rchp[MUX_LINES + MUX_ILINES]; /* rcv chr pend */
uint8 mux_xdon[MUX_LINES]; /* xmt done */
uint8 muxc_ota[MUX_LINES]; /* ctrl: Cn,ESn,SSn */
uint8 muxc_lia[MUX_LINES]; /* ctrl: Sn */
uint32 mux_tps = 100; /* polls/second */
uint32 muxl_ibuf = 0; /* low in: rcv data */
uint32 muxl_obuf = 0; /* low out: param */
uint32 muxu_ibuf = 0; /* upr in: status */
uint32 muxu_obuf = 0; /* upr out: chan */
uint32 muxc_chan = 0; /* ctrl chan */
uint32 muxc_scan = 0; /* ctrl scan */
TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */
TMXR mux_desc = { MUX_LINES, 0, NULL }; /* mux descriptor */
int32 muxlio (int32 inst, int32 IR, int32 dat);
int32 muxuio (int32 inst, int32 IR, int32 dat);
int32 muxcio (int32 inst, int32 IR, int32 dat);
t_stat muxi_svc (UNIT *uptr);
t_stat muxo_svc (UNIT *uptr);
t_stat mux_reset (DEVICE *dptr);
t_stat mux_attach (UNIT *uptr, char *cptr);
t_stat mux_detach (UNIT *uptr);
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc);
void mux_data_int (void);
void mux_ctrl_int (void);
void mux_diag (int32 c);
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 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-257 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */
0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-367 */
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; /* 360-377 */
#define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0)
DIB mux_dib[] = {
{ MUXL, 1, 0, 0, 0, 0, &muxlio },
{ MUXU, 1, 0, 0, 0, 0, &muxuio } };
#define muxl_dib mux_dib[0]
#define muxu_dib mux_dib[1]
/* MUX data structures
muxu_dev MUX device descriptor
muxu_unit MUX unit descriptor
muxu_reg MUX register list
muxu_mod MUX modifiers list
*/
UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), MUXU_INIT_POLL };
REG muxu_reg[] = {
{ ORDATA (IBUF, muxu_ibuf, 16) },
{ ORDATA (OBUF, muxu_obuf, 16) },
{ FLDATA (CMD, muxu_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, muxu_dib.ctl, 0), REG_HRO },
{ FLDATA (FLG, muxu_dib.flg, 0), REG_HRO },
{ FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO },
{ ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO },
{ 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 },
{ 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 };
/* MUXL data structures
muxl_dev MUXL device descriptor
muxl_unit MUXL unit descriptor
muxl_reg MUXL register list
muxl_mod MUXL modifiers list
*/
UNIT muxl_unit[] = {
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT },
{ UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT } };
MTAB muxl_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", 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 },
{ 0 } };
REG muxl_reg[] = {
{ FLDATA (CMD, muxl_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, muxl_dib.ctl, 0) },
{ FLDATA (FLG, muxl_dib.flg, 0) },
{ FLDATA (FBF, muxl_dib.fbf, 0) },
{ BRDATA (STA, mux_sta, 8, 16, MUX_LINES) },
{ BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) },
{ BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) },
{ BRDATA (RBUF, mux_rbuf, 8, 8, MUX_LINES + MUX_ILINES) },
{ BRDATA (XBUF, mux_xbuf, 8, 8, MUX_LINES) },
{ BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) },
{ BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) },
{ URDATA (TIME, muxl_unit[0].wait, 10, 24, 0,
MUX_LINES, REG_NZ + PV_LEFT) },
{ 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 };
/* MUXM data structures
muxc_dev MUXM device descriptor
muxc_unit MUXM unit descriptor
muxc_reg MUXM register list
muxc_mod MUXM modifiers list
*/
DIB muxc_dib = { MUXC, 1, 0, 0, 0, 0, &muxcio };
UNIT muxc_unit = { UDATA (NULL, 0, 0) };
REG muxc_reg[] = {
{ FLDATA (CMD, muxc_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, muxc_dib.ctl, 0) },
{ FLDATA (FLG, muxc_dib.flg, 0) },
{ FLDATA (FBF, muxc_dib.fbf, 0) },
{ FLDATA (SCAN, muxc_scan, 0) },
{ ORDATA (CHAN, muxc_chan, 4) },
{ BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) },
{ BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) },
{ ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO },
{ 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 },
{ 0 } };
DEVICE muxc_dev = {
"MUXM", &muxc_unit, muxc_reg, muxc_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &mux_reset,
NULL, NULL, NULL };
/* IOT routines: data cards */
int32 muxlio (int32 inst, int32 IR, int32 dat)
{
int32 dev, ln;
dev = IR & DEVMASK; /* get device no */
switch (inst) { /* case on opcode */
case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
muxl_obuf = dat; /* store data */
break;
case ioMIX: /* merge */
dat = dat | muxl_ibuf;
break;
case ioLIX: /* load */
dat = muxl_ibuf;
break;
case ioCTL: /* control clear/set */
if (IR & AB) { clrCTL (dev); } /* CLC */
else { /* STC */
setCTL (dev); /* set ctl */
ln = MUX_CHAN (muxu_obuf); /* get chan # */
if (muxl_obuf & OTL_P) { /* parameter set? */
if (muxl_obuf & OTL_TX) { /* transmit? */
if (ln < MUX_LINES) /* to valid line? */
mux_xpar[ln] = muxl_obuf; }
else if (ln < (MUX_LINES + MUX_ILINES)) /* rcv, valid line? */
mux_rpar[ln] = muxl_obuf; }
else if ((muxl_obuf & OTL_TX) && /* xmit data? */
(ln < MUX_LINES)) { /* to valid line? */
if (sim_is_active (&muxl_unit[ln])) /* still working? */
mux_sta[ln] = mux_sta[ln] | LIU_LOST;
else sim_activate (&muxl_unit[ln], muxl_unit[ln].wait);
mux_xbuf[ln] = muxl_obuf & OTL_CHAR; } /* load buffer */
} /* end STC */
break;
default:
break; }
if (IR & HC) { /* H/C option */
clrFLG (dev); /* clear flag */
mux_data_int (); } /* look for new int */
return dat;
}
int32 muxuio (int32 inst, int32 IR, int32 dat)
{
switch (inst) { /* case on opcode */
case ioOTX: /* output */
muxu_obuf = dat; /* store data */
break;
case ioMIX: /* merge */
dat = dat | muxu_ibuf;
break;
case ioLIX: /* load */
dat = muxu_ibuf;
break;
default:
break; }
return dat;
}
/* IOT routine: control card */
int32 muxcio (int32 inst, int32 IR, int32 dat)
{
int32 dev, ln, t, old;
dev = IR & DEVMASK; /* get device no */
switch (inst) { /* case on opcode */
case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioOTX: /* output */
if (dat & OTC_SCAN) muxc_scan = 1; /* set scan flag */
else muxc_scan = 0;
if (dat & OTC_UPD) { /* update? */
ln = OTC_CHAN (dat); /* get channel */
old = muxc_ota[ln]; /* save prior val */
muxc_ota[ln] = (muxc_ota[ln] & ~OTC_RW) | /* save ESn,SSn */
(dat & OTC_RW);
if (dat & OTC_EC2) muxc_ota[ln] = /* if EC2, upd C2 */
(muxc_ota[ln] & ~OTC_C2) | (dat & OTC_C2);
if (dat & OTC_EC1) muxc_ota[ln] = /* if EC1, upd C1 */
(muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1);
if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
(old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */
tmxr_msg (mux_ldsc[ln].conn, "\r\nLine hangup\r\n");
tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */
muxc_lia[ln] = 0; } /* dataset off */
} /* end update */
break;
case ioLIX: /* load */
dat = 0;
case ioMIX: /* merge */
t = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */
LIC_TSTI (muxc_chan) | /* I2, I1 */
(muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */
(muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */
dat = dat | t; /* return status */
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */
break;
case ioCTL: /* ctrl clear/set */
if (IR & AB) { clrCTL (dev); } /* CLC */
else { setCTL (dev); } /* STC */
break;
default:
break; }
if (IR & HC) { /* H/C option */
clrFLG (dev); /* clear flag */
mux_ctrl_int (); } /* look for new int */
return dat;
}
/* Unit service - receive side
Poll for new connections
Poll all active lines for input
*/
t_stat muxi_svc (UNIT *uptr)
{
int32 ln, c, t;
if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
t = sim_rtcn_calb (mux_tps, TMR_MUX); /* calibrate */
sim_activate (uptr, t); /* continue poll */
ln = tmxr_poll_conn (&mux_desc, uptr); /* look for connect */
if (ln >= 0) { /* got one? */
if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */
(muxc_ota[ln] & DTR)) /* DTR? */
muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */
muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */
mux_ldsc[ln].rcve = 1; } /* rcv enabled */
tmxr_poll_rx (&mux_desc); /* poll for input */
for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */
if (mux_ldsc[ln].conn) { /* connected? */
if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */
if (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 (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */
if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */
return SCPE_OK;
}
/* Unit service - transmit side */
t_stat muxo_svc (UNIT *uptr)
{
int32 c, ln = uptr - muxl_unit; /* line # */
if (mux_ldsc[ln].conn) { /* connected? */
if (mux_ldsc[ln].xmte) { /* xmt enabled? */
if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */
TMLN *lp = &mux_ldsc[ln]; /* get line */
c = mux_xbuf[ln] & 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 (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for int */
return SCPE_OK;
}
/* Look for data interrupt */
void mux_data_int (void)
{
int32 i;
for (i = 0; i < MUX_LINES; i++) { /* rcv lines */
if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */
muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */
RCV_PAR (mux_rbuf[i]);
muxu_ibuf = PUT_CCH (i) | mux_sta[i]; /* hi buf = stat */
mux_rchp[i] = 0; /* clr char, stat */
mux_sta[i] = 0;
setFLG (muxl_dib.devno); /* interrupt */
return; } }
for (i = 0; i < MUX_LINES; i++) { /* xmt lines */
if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */
muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */
mux_xdon[i] = 0; /* clr done, stat */
mux_sta[i] = 0;
setFLG (muxl_dib.devno); /* interrupt */
return; } }
for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */
if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */
muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */
RCV_PAR (mux_rbuf[i]);
muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */
mux_rchp[i] = 0; /* clr char, stat */
mux_sta[i] = 0;
setFLG (muxl_dib.devno);
return; } }
return;
}
/* Look for control interrupt */
void mux_ctrl_int (void)
{
int32 i;
if (muxc_scan == 0) return;
for (i = 0; i < MUX_LINES; i++) {
muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */
if (LIC_TSTI (muxc_chan)) { /* status change? */
setFLG (muxc_dib.devno); /* set flag */
break; } }
return;
}
/* Set diagnostic lines for given character */
void mux_diag (int32 c)
{
int32 i;
for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) {
if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST;
mux_rchp[i] = 1;
mux_rbuf[i] = c; }
return;
}
/* Reset an individual line */
void mux_reset_ln (int32 i)
{
mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */
mux_rpar[i] = mux_xpar[i] = 0;
mux_rchp[i] = mux_xdon[i] = 0;
mux_sta[i] = 0;
muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */
if (mux_ldsc[i].conn) /* connected? */
muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */
(muxl_unit[i].flags & UNIT_MDM? CDET: 0);
sim_cancel (&muxl_unit[i]);
return;
}
/* Reset routine */
t_stat mux_reset (DEVICE *dptr)
{
int32 i, t;
muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */
muxl_dib.flg = muxl_dib.fbf = 1;
muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */
muxu_dib.flg = muxu_dib.fbf = 0; /* implemented */
muxc_dib.cmd = muxc_dib.ctl = 0; /* init ctrl */
muxc_dib.flg = muxc_dib.fbf = 1;
muxc_chan = muxc_scan = 0; /* init modem scan */
if (muxu_unit.flags & UNIT_ATT) { /* master att? */
if (!sim_is_active (&muxu_unit)) {
t = sim_rtcn_init (muxu_unit.wait, TMR_MUX);
sim_activate (&muxu_unit, t); } } /* activate */
else sim_cancel (&muxu_unit); /* else stop */
for (i = 0; i < MUX_LINES; i++) {
mux_desc.ldsc[i] = &mux_ldsc[i];
mux_reset_ln (i); }
return SCPE_OK;
}
/* Attach master unit */
t_stat mux_attach (UNIT *uptr, char *cptr)
{
t_stat r;
int32 t;
r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
t = sim_rtcn_init (muxu_unit.wait, TMR_MUX);
sim_activate (uptr, t); /* start poll */
return SCPE_OK;
}
/* Detach master unit */
t_stat mux_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&mux_desc, uptr); /* detach */
for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */
return SCPE_OK;
}
/* Show summary processor */
t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0);
if (t == 1) fprintf (st, "1 connection");
else fprintf (st, "%d connections", t);
return SCPE_OK;
}
/* SHOW CONN/STAT processor */
t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i;
for (i = 0; (i < MUX_LINES) && (mux_ldsc[i].conn == 0); i++) ;
if (i < MUX_LINES) {
for (i = 0; i < MUX_LINES; i++) {
if (mux_ldsc[i].conn)
if (val) tmxr_fconns (st, &mux_ldsc[i], i);
else tmxr_fstats (st, &mux_ldsc[i], i); } }
else fprintf (st, "all disconnected\n");
return SCPE_OK;
}
/* 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);
}

View File

@@ -1,6 +1,6 @@
/* hp2100_stddev.c: HP2100 standard devices
/* hp2100_stddev.c: HP2100 standard devices simulator
Copyright (c) 1993-2001, Robert M. Supnik
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"),
@@ -28,6 +28,8 @@
tty 12531C buffered teleprinter interface
clk 12539A/B/C time base generator
30-May-02 RMS Widened POS to 32b
22-Mar-02 RMS Revised for dynamically allocated memory
03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW
29-Nov-01 RMS Added read only unit support
24-Nov-01 RMS Changed TIME to an array
@@ -53,11 +55,10 @@
#define CLK_V_ERROR 4 /* clock overrun */
#define CLK_ERROR (1 << CLK_V_ERROR)
extern uint16 M[];
extern uint16 *M;
extern int32 PC;
extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
extern UNIT cpu_unit;
extern struct hpdev infotab[];
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
int32 ttp_stopioe = 0;
int32 tty_buf = 0, tty_mode = 0; /* tty buffer, mode */
@@ -65,14 +66,19 @@ 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 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);
int32 ptpio (int32 inst, int32 IR, int32 dat);
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr);
int32 ttyio (int32 inst, int32 IR, int32 dat);
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tty_reset (DEVICE *dptr);
int32 clkio (int32 inst, int32 IR, int32 dat);
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
@@ -84,25 +90,32 @@ t_stat clk_reset (DEVICE *dptr);
ptr_reg PTR register list
*/
DIB ptr_dib = { PTR, 1, 0, 0, 0, 0, &ptrio };
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (CMD, infotab[inPTR].cmd, 0) },
{ FLDATA (CTL, infotab[inPTR].ctl, 0) },
{ FLDATA (FLG, infotab[inPTR].flg, 0) },
{ FLDATA (FBF, infotab[inPTR].fbf, 0) },
{ DRDATA (POS, ptr_unit.pos, 31), PV_LEFT },
{ FLDATA (CMD, ptr_dib.cmd, 0) },
{ FLDATA (CTL, ptr_dib.ctl, 0) },
{ FLDATA (FLG, ptr_dib.flg, 0) },
{ FLDATA (FBF, ptr_dib.fbf, 0) },
{ DRDATA (POS, ptr_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ ORDATA (DEVNO, infotab[inPTR].devno, 6), REG_RO },
{ ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO },
{ FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO },
{ NULL } };
MTAB ptr_mod[] = {
{ MTAB_XTD | MTAB_VDV, inPTR, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 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 },
{ 0 } };
DEVICE ptr_dev = {
@@ -119,24 +132,31 @@ DEVICE ptr_dev = {
ptp_reg PTP register list
*/
DIB ptp_dib = { PTP, 1, 0, 0, 0, 0, &ptpio };
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (CMD, infotab[inPTP].cmd, 0) },
{ FLDATA (CTL, infotab[inPTP].ctl, 0) },
{ FLDATA (FLG, infotab[inPTP].flg, 0) },
{ FLDATA (FBF, infotab[inPTP].fbf, 0) },
{ DRDATA (POS, ptp_unit.pos, 31), PV_LEFT },
{ FLDATA (CMD, ptp_dib.cmd, 0) },
{ FLDATA (CTL, ptp_dib.ctl, 0) },
{ FLDATA (FLG, ptp_dib.flg, 0) },
{ FLDATA (FBF, ptp_dib.fbf, 0) },
{ DRDATA (POS, ptp_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ ORDATA (DEVNO, infotab[inPTP].devno, 6), REG_RO },
{ ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO },
{ FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO },
{ NULL } };
MTAB ptp_mod[] = {
{ MTAB_XTD | MTAB_VDV, inPTP, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ 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 },
{ 0 } };
DEVICE ptp_dev = {
@@ -157,6 +177,8 @@ DEVICE ptp_dev = {
#define TTO 1
#define TTP 2
DIB tty_dib = { TTY, 1, 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 },
@@ -165,25 +187,25 @@ UNIT tty_unit[] = {
REG tty_reg[] = {
{ ORDATA (BUF, tty_buf, 8) },
{ ORDATA (MODE, tty_mode, 16) },
{ FLDATA (CMD, infotab[inTTY].cmd, 0), REG_HRO },
{ FLDATA (CTL, infotab[inTTY].ctl, 0) },
{ FLDATA (FLG, infotab[inTTY].flg, 0) },
{ FLDATA (FBF, infotab[inTTY].fbf, 0) },
{ DRDATA (KPOS, tty_unit[TTI].pos, 31), PV_LEFT },
{ FLDATA (CMD, tty_dib.cmd, 0), REG_HRO },
{ FLDATA (CTL, tty_dib.ctl, 0) },
{ FLDATA (FLG, tty_dib.flg, 0) },
{ FLDATA (FBF, tty_dib.fbf, 0) },
{ DRDATA (KPOS, tty_unit[TTI].pos, 32), PV_LEFT },
{ DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPOS, tty_unit[TTO].pos, 31), PV_LEFT },
{ DRDATA (TPOS, tty_unit[TTO].pos, 32), PV_LEFT },
{ DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (PPOS, tty_unit[TTP].pos, 31), PV_LEFT },
{ DRDATA (PPOS, tty_unit[TTP].pos, 32), PV_LEFT },
{ FLDATA (STOP_IOE, ttp_stopioe, 0) },
{ ORDATA (DEVNO, infotab[inTTY].devno, 6), REG_RO },
{ 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 },
{ MTAB_XTD | MTAB_VDV, inTTY, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &tty_dib },
{ 0 } };
DEVICE tty_dev = {
@@ -200,23 +222,25 @@ DEVICE tty_dev = {
clk_reg CLK register list
*/
DIB clk_dib = { CLK, 1, 0, 0, 0, 0, &clkio };
UNIT clk_unit = {
UDATA (&clk_svc, 0, 0) };
REG clk_reg[] = {
{ ORDATA (SEL, clk_select, 3) },
{ FLDATA (CMD, infotab[inCLK].cmd, 0), REG_HRO },
{ FLDATA (CTL, infotab[inCLK].ctl, 0) },
{ FLDATA (FLG, infotab[inCLK].flg, 0) },
{ FLDATA (FBF, infotab[inCLK].fbf, 0) },
{ 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) },
{ ORDATA (DEVNO, infotab[inCLK].devno, 6), REG_RO },
{ ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO },
{ NULL } };
MTAB clk_mod[] = {
{ MTAB_XTD | MTAB_VDV, inCLK, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO",
&hp_setdev, &hp_showdev, &clk_dib },
{ 0 } };
DEVICE clk_dev = {
@@ -237,10 +261,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & AMASK;
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & AMASK;
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioMIX: /* merge */
dat = dat | ptr_unit.buf;
@@ -268,7 +292,7 @@ t_stat ptr_svc (UNIT *uptr)
{
int32 dev, temp;
dev = infotab[inPTR].devno; /* get device no */
dev = ptr_dib.devno; /* get device no */
clrCMD (dev); /* clear cmd */
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
@@ -285,12 +309,12 @@ ptr_unit.pos = ftell (ptr_unit.fileref);
return SCPE_OK;
}
/* Reset routine - called from SCP, flags in infotab */
/* Reset routine - called from SCP, flags in DIB's */
t_stat ptr_reset (DEVICE *dptr)
{
infotab[inPTR].cmd = infotab[inPTR].ctl = 0; /* clear cmd, ctl */
infotab[inPTR].flg = infotab[inPTR].fbf = 1; /* set flg, fbf */
ptr_dib.cmd = ptr_dib.ctl = 0; /* clear cmd, ctl */
ptr_dib.flg = ptr_dib.fbf = 1; /* set flg, fbf */
ptr_unit.buf = 0;
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
@@ -323,7 +347,7 @@ t_stat ptr_boot (int32 unit)
{
int32 i, dev;
dev = infotab[inPTR].devno; /* get device no */
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 */
@@ -343,10 +367,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & AMASK;
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & AMASK;
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioLIX: /* load */
dat = 0;
@@ -377,7 +401,7 @@ t_stat ptp_svc (UNIT *uptr)
{
int32 dev;
dev = infotab[inPTP].devno; /* get device no */
dev = ptp_dib.devno; /* get device no */
clrCMD (dev); /* clear cmd */
setFLG (dev); /* set flag */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
@@ -394,8 +418,8 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
infotab[inPTP].cmd = infotab[inPTP].ctl = 0; /* clear cmd, ctl */
infotab[inPTP].flg = infotab[inPTP].fbf = 1; /* set flg, fbf */
ptp_dib.cmd = ptp_dib.ctl = 0; /* clear cmd, ctl */
ptp_dib.flg = ptp_dib.fbf = 1; /* set flg, fbf */
ptp_unit.buf = 0;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
@@ -413,10 +437,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & AMASK;
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & AMASK;
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioLIX: /* load */
dat = 0;
@@ -448,6 +472,7 @@ t_stat tto_out (int32 ch)
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 */
@@ -467,7 +492,7 @@ t_stat tti_svc (UNIT *uptr)
{
int32 temp, dev;
dev = infotab[inTTY].devno; /* get device no */
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;
@@ -485,7 +510,7 @@ t_stat tto_svc (UNIT *uptr)
{
int32 ch, dev;
dev = infotab[inTTY].devno; /* get device no */
dev = tty_dib.devno; /* get device no */
setFLG (dev); /* set done flag */
ch = tty_buf;
tty_buf = 0377; /* defang buf */
@@ -496,8 +521,8 @@ return tto_out (ch); /* print and/or punch */
t_stat tty_reset (DEVICE *dptr)
{
infotab[inTTY].cmd = infotab[inTTY].ctl = 0; /* clear cmd, ctl */
infotab[inTTY].flg = infotab[inTTY].fbf = 1; /* set flg, fbf */
tty_dib.cmd = tty_dib.ctl = 0; /* clear cmd, ctl */
tty_dib.flg = tty_dib.fbf = 1; /* set flg, fbf */
tty_mode = 0;
tty_buf = 0;
sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */
@@ -517,10 +542,10 @@ case ioFLG: /* flag clear/set */
if ((IR & HC) == 0) { setFLG (dev); } /* STF */
break;
case ioSFC: /* skip flag clear */
if (FLG (dev) == 0) PC = (PC + 1) & AMASK;
if (FLG (dev) == 0) PC = (PC + 1) & VAMASK;
return dat;
case ioSFS: /* skip flag set */
if (FLG (dev) != 0) PC = (PC + 1) & AMASK;
if (FLG (dev) != 0) PC = (PC + 1) & VAMASK;
return dat;
case ioMIX: /* merge */
dat = dat | clk_error;
@@ -551,7 +576,7 @@ t_stat clk_svc (UNIT *uptr)
{
int32 dev;
dev = infotab[inCLK].devno; /* get device no */
dev = clk_dib.devno; /* get device no */
if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? */
setFLG (dev); /* set device flag */
return SCPE_OK;
@@ -561,8 +586,8 @@ return SCPE_OK;
t_stat clk_reset (DEVICE *dptr)
{
infotab[inCLK].cmd = infotab[inCLK].ctl = 0; /* clear cmd, ctl */
infotab[inCLK].flg = infotab[inCLK].fbf = 1; /* set flg, fbf */
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 */
sim_cancel (&clk_unit); /* deactivate unit */

View File

@@ -1,6 +1,6 @@
/* hp2100_sys.c: HP 2100 simulator interface
Copyright (c) 1993-2001, Robert M. Supnik
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"),
@@ -23,6 +23,11 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Mar-02 RMS Revised for dynamically allocated memory
14-Feb-02 RMS Added DMS instructions
04-Feb-02 RMS Fixed bugs in alter/skip display and parsing
01-Feb-02 RMS Added terminal multiplexor support
16-Jan-02 RMS Added additional device support
17-Sep-01 RMS Removed multiconsole support
27-May-01 RMS Added multiconsole support
14-Mar-01 RMS Revised load/dump interface (again)
@@ -40,9 +45,13 @@ extern DEVICE dma0_dev, dma1_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tty_dev, clk_dev, lpt_dev;
extern DEVICE mtd_dev, mtc_dev;
extern DEVICE msd_dev, msc_dev;
extern DEVICE dpd_dev, dpc_dev;
extern DEVICE dqd_dev, dqc_dev;
extern DEVICE drd_dev, drc_dev;
extern DEVICE muxl_dev, muxu_dev, muxc_dev;
extern REG cpu_reg[];
extern uint16 M[];
extern uint16 *M;
/* SCP data structures and interface routines
@@ -65,8 +74,12 @@ DEVICE *sim_devices[] = { &cpu_dev,
&ptr_dev, &ptp_dev,
&tty_dev,
&clk_dev, &lpt_dev,
&mtd_dev, &mtc_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,
NULL };
const char *sim_stop_messages[] = {
@@ -129,24 +142,24 @@ return SCPE_OK;
#define I_V_FL 16 /* flag start */
#define I_M_FL 017 /* flag mask */
#define I_V_NPN 0 /* no operand */
#define I_V_NPNC 1 /* no operand + C */
#define I_V_NPC 1 /* no operand + C */
#define I_V_MRF 2 /* mem ref */
#define I_V_ASH 3 /* alter/skip, shift */
#define I_V_ESHF 4 /* extended shift */
#define I_V_EMRF 5 /* extended mem ref */
#define I_V_IOT1 6 /* I/O + HC */
#define I_V_IOT2 7 /* I/O only */
#define I_V_EG1Z 010 /* ext grp, 1 op + 0 */
#define I_V_ESH 4 /* extended shift */
#define I_V_EMR 5 /* extended mem ref */
#define I_V_IO1 6 /* I/O + HC */
#define I_V_IO2 7 /* I/O only */
#define I_V_EGZ 010 /* ext grp, 1 op + 0 */
#define I_V_EG2 011 /* ext grp, 2 op */
#define I_NPN (I_V_NPN << I_V_FL)
#define I_NPNC (I_V_NPNC << I_V_FL)
#define I_NPC (I_V_NPC << I_V_FL)
#define I_MRF (I_V_MRF << I_V_FL)
#define I_ASH (I_V_ASH << I_V_FL)
#define I_ESHF (I_V_ESHF << I_V_FL)
#define I_EMRF (I_V_EMRF << I_V_FL)
#define I_IOT1 (I_V_IOT1 << I_V_FL)
#define I_IOT2 (I_V_IOT2 << I_V_FL)
#define I_EG1Z (I_V_EG1Z << I_V_FL)
#define I_ESH (I_V_ESH << I_V_FL)
#define I_EMR (I_V_EMR << I_V_FL)
#define I_IO1 (I_V_IO1 << I_V_FL)
#define I_IO2 (I_V_IO2 << I_V_FL)
#define I_EGZ (I_V_EGZ << I_V_FL)
#define I_EG2 (I_V_EG2 << I_V_FL)
static const int32 masks[] = {
@@ -169,6 +182,18 @@ static const char *opcode[] = {
"SFC", "SFS", "MIA", "MIB",
"LIA", "LIB", "OTA", "OTB",
"STC", "CLC",
"SYA", "USA", "PAA", "PBA",
"XMA",
"XLA", "XSA", "XCA", "LFA",
"RSA", "RVA",
"MBI", "MBF",
"MBW", "MWI", "MWF", "MWW",
"SYB", "USB", "PAB", "PBB",
"SSM", "JRS",
"XMM", "XMS", "XMB",
"XLB", "XSB", "XCB", "LFB",
"RSB", "RVB", "DJP", "DJS",
"SJP", "SJS", "UJP", "UJS",
"SAX", "SBX", "CAX", "CBX",
"LAX", "LBX", "STX",
"CXA", "CXB", "LDX",
@@ -189,28 +214,40 @@ 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_ESHF, 0100040+I_ESHF, 0100100+I_ESHF,
0101020+I_ESHF, 0101040+I_ESHF, 0101100+I_ESHF,
0100200+I_EMRF, 0100400+I_EMRF, 0104200+I_EMRF, 0104400+I_EMRF,
0105000+I_EMRF, 0105020+I_EMRF, 0105040+I_EMRF, 0105060+I_EMRF,
0100020+I_ESH, 0100040+I_ESH, 0100100+I_ESH,
0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH,
0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR,
0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR,
0105100+I_NPN, 0105120+I_NPN,
0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPNC, 0102301+I_NPNC,
0102000+I_IOT1, 0102100+I_IOT2, 0103100+I_IOT2,
0102200+I_IOT2, 0102300+I_IOT2, 0102400+I_IOT1, 0106400+I_IOT1,
0102500+I_IOT1, 0106500+I_IOT1, 0102600+I_IOT1, 0106600+I_IOT1,
0102700+I_IOT1, 0106700+I_IOT1,
0101740+I_EMRF, 0105740+I_EMRF, 0101741+I_NPN, 0105741+I_NPN,
0101742+I_EMRF, 0105742+I_EMRF, 0105743+I_EMRF,
0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMRF,
0105746+I_EMRF, 0101747+I_NPN, 0105747+I_NPN,
0101750+I_EMRF, 0105750+I_EMRF, 0101751+I_NPN, 0105751+I_NPN,
0101752+I_EMRF, 0105752+I_EMRF, 0105753+I_EMRF,
0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMRF,
0105756+I_EMRF, 0101757+I_NPN, 0105757+I_NPN,
0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMRF, 0105763+I_NPN,
0105764+I_NPN, 0105765+I_EG1Z, 0105766+I_EG1Z, 0105767+I_NPN,
0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMRF, 0105773+I_EG2,
0105774+I_EG2, 0105775+I_EG2, 0105776+I_EG1Z, 0105777+I_EG1Z,
0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC,
0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2,
0102200+I_IO2, 0102300+I_IO2, 0102400+I_IO1, 0106400+I_IO1,
0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1,
0102700+I_IO1, 0106700+I_IO1,
0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN,
0101722+I_NPN,
0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN,
0101730+I_NPN, 0101731+I_NPN,
0105702+I_NPN, 0105703+I_NPN,
0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN,
0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN,
0105714+I_EMR, 0105715+I_EG2,
0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN,
0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN,
0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR,
0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR,
0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN,
0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR,
0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR,
0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN,
0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN,
0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR,
0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR,
0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN,
0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN,
0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN,
0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2,
0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ,
0000000+I_ASH, /* decode only */
-1 };
@@ -230,8 +267,8 @@ static const char *stab[] = {
static const int32 mtab[] = {
0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700,
0007400, 0007400, 0007400, 0007400, 0007400, 0007400,
0002040, 0002040, 0002300, 0002300, 0002300,
0006400, 0007000, 0007400, 0006400, 0007000, 0007400,
0002040, 0002040, 0002100, 0002200, 0002300,
0006020, 0006020, 0004010, 0004010,
0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027,
@@ -288,15 +325,15 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
switch (j) { /* case on class */
case I_V_NPN: /* no operands */
fprintf (of, "%s", opcode[i]); /* opcode */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_NPNC: /* no operands + C */
case I_V_NPC: /* no operands + C */
fprintf (of, "%s", opcode[i]);
if (inst & HC) fprintf (of, " C");
break;
case I_V_MRF: /* mem ref */
disp = inst & DISP; /* displacement */
fprintf (of, "%s ", opcode[i]); /* opcode */
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); }
@@ -306,36 +343,37 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
case I_V_ASH: /* shift, alter-skip */
cm = FALSE;
for (i = 0; mtab[i] != 0; i++) {
if ((inst & mtab[i]) == vtab[i]) {
if (cm) fprintf (of, ",");
cm = TRUE;
fprintf (of, "%s", stab[i]); } }
if (!cm) return SCPE_ARG; /* nothing decoded? */
if ((inst & mtab[i]) == vtab[i]) {
inst = inst & ~(vtab[i] & 01777);
if (cm) fprintf (of, ",");
cm = TRUE;
fprintf (of, "%s", stab[i]); } }
if (!cm) return SCPE_ARG; /* nothing decoded? */
break;
case I_V_ESHF: /* extended shift */
case I_V_ESH: /* extended shift */
disp = inst & 017; /* shift count */
if (disp == 0) disp = 16;
fprintf (of, "%s %d", opcode[i], disp);
break;
case I_V_EMRF: /* extended mem ref */
fprintf (of, "%s %-o", opcode[i], val[1] & AMASK);
case I_V_EMR: /* extended mem ref */
fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
if (val[1] & IA) fprintf (of, ",I");
return -1; /* extra word */
case I_V_IOT1: /* IOT with H/C */
case I_V_IO1: /* IOT with H/C */
fprintf (of, "%s %-o", opcode[i], inst & DEVMASK);
if (inst & HC) fprintf (of, ",C");
break;
case I_V_IOT2: /* IOT */
case I_V_IO2: /* IOT */
fprintf (of, "%s %-o", opcode[i], inst & DEVMASK);
break;
case I_V_EG1Z: /* ext grp 1 op + 0 */
fprintf (of, "%s %-o", opcode[i], val[1] & AMASK);
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");
return -2; /* extra words */
case I_V_EG2: /* ext grp 2 op */
fprintf (of, "%s %-o", opcode[i], val[1] & AMASK);
fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK);
if (val[1] & IA) fprintf (of, ",I");
fprintf (of, " %-o", val[2] & AMASK);
fprintf (of, " %-o", val[2] & VAMASK);
if (val[2] & IA) fprintf (of, ",I");
return -2; } /* extra words */
return SCPE_OK; } /* end if */
@@ -359,7 +397,7 @@ t_stat r;
char gbuf[CBUFSIZE];
cptr = get_glyph (cptr, gbuf, ','); /* get next field */
d = get_uint (gbuf, 8, AMASK, &r); /* construe as addr */
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 */
@@ -410,7 +448,7 @@ if (opcode[i]) { /* found opcode? */
switch (j) { /* case on class */
case I_V_NPN: /* no operand */
break;
case I_V_NPNC: /* no operand + C */
case I_V_NPC: /* no operand + C */
if (*cptr != 0) {
cptr = get_glyph (cptr, gbuf, 0);
if (strcmp (gbuf, "C")) return SCPE_ARG;
@@ -424,24 +462,24 @@ if (opcode[i]) { /* found opcode? */
else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */
cptr = get_glyph (cptr, gbuf, ','); }
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
if ((d & AMASK) <= DISP) val[0] = val[0] | d;
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;
else return SCPE_ARG;
break;
case I_V_ESHF: /* extended shift */
case I_V_ESH: /* extended shift */
cptr = get_glyph (cptr, gbuf, 0);
d = get_uint (gbuf, 10, 16, &r);
if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG;
val[0] = val[0] | (d & 017);
break;
case I_V_EMRF: /* extended mem ref */
case I_V_EMR: /* extended mem ref */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
val[1] = d;
ret = -1;
break;
case I_V_IOT1: /* IOT + optional C */
case I_V_IO1: /* IOT + optional C */
cptr = get_glyph (cptr, gbuf, ','); /* get device */
d = get_uint (gbuf, 8, DEVMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
@@ -451,13 +489,13 @@ if (opcode[i]) { /* found opcode? */
if (strcmp (gbuf, "C")) return SCPE_ARG;
val[0] = val[0] | HC; }
break;
case I_V_IOT2: /* IOT */
case I_V_IO2: /* IOT */
cptr = get_glyph (cptr, gbuf, 0); /* get device */
d = get_uint (gbuf, 8, DEVMASK, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | d;
break;
case I_V_EG1Z: /* ext grp 1 op + 0 */
case I_V_EGZ: /* ext grp 1 op + 0 */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
if ((d = get_addr (gbuf)) < 0) return SCPE_ARG;
val[1] = d;
@@ -523,7 +561,7 @@ for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0;
val[0] = val[0] | vtab[i]; } /* fill value */
if (clef) { /* CLE seen? */
if (val[0] & ASKP) { /* alter-skip? */
if (val[0] & 0300) return SCPE_ARG; /* already filled in? */
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;