1
0
mirror of https://github.com/simh/simh.git synced 2026-01-26 04:01:38 +00:00

Notes For V2.8

1. New Features

1.1 Directory and documentation

- Only common files (SCP and libraries) are in the top level
  directory.  Individual simulator files are in their individual
  directories.
- simh_doc.txt has been split up.  simh_doc.txt now documents
  only SCP.  The individual simulators are documented in separate
  text files in their own directories.
- mingw_build.bat is a batch file for the MINGW/gcc environment
  that will build all the simulators, assuming the root directory
  structure is at c:\sim.
- Makefile is a UNIX make file for the gcc environment that will
  build all the simulators, assuming the root directory is at
  c:\sim.

1.2 SCP

- DO <file name> executes the SCP commands in the specified file.
- Replicated registers in unit structures can now be declared as
  arrays for examine, modify, save, and restore.  Most replicated
  unit registers (for example, mag tape position registers) have
  been changed to arrays.
- The ADD/REMOVE commands have been replaced by SET unit ONLINE
  and SET unit OFFLINE, respectively.
- Register names that are unique within an entire simulator do
  not have to be prefaced with the device name.
- The ATTACH command can attach files read only, either under
  user option (-r), or because the attached file is ready only.
- The SET/SHOW capabilities have been extended.  New forms include:

	SET <dev> param{=value}{ param ...}
	SET <unit> param{=value}{ param ...}
	SHOW <dev> {param param ...}
	SHOW <unit> {param param ...}

- Multiple breakpoints have been implemented.  Breakpoints are
  set/cleared/displayed by:

	BREAK addr_list{[count]}
	NOBREAK addr_list
	SHOW BREAK addr_list

1.3 PDP-11 simulator

- Unibus map implemented, with 22b RP controller (URH70) or 18b
  RP controller (URH11) (in debug).
- All DMA peripherals rewritten to use map.
- Many peripherals modified for source sharing with VAX.
- RQDX3 implemented.
- Bugs fixed in RK11 and RL11 write check.

1.4 PDP-10 simulator

- ITS 1-proceed implemented.
- Bugs fixed in ITS PC sampling and LPMR

1.5 18b PDP simulator

- Interrupts split out to multiple levels to allow easier
  expansion.

1.5 IBM System 3 Simulator

- Written by Charles (Dutch) Owen.

1.6 VAX Simulator (in debug)

- Simulates MicroVAX 3800 (KA655) with 16MB-64MB memory, RQDX3,
  RLV12, TSV11, DZV11, LPV11, PCV11.
- CDROM capability has been added to the RQDX3, to allow testing
  with VMS hobbyist images.

1.7 SDS 940 Simulator (not tested)

- Simulates SDS 940, 16K-64K memory, fixed and moving head
  disk, magtape, line printer, console.

1.8 Altair Z80

- Revised from Charles (Dutch) Owen's original by Peter Schorn.
- MITS 8080 with full Z80 simulation.
- 4K and 8K BASIC packages, Prolog package.

1.9 Interdata

The I4 simulator has been withdrawn for major rework.  Look for
a complete 16b/32b Interdata simulator sometime next year.

2. Release Notes

2.1 SCP

SCP now allows replicated registers in unit structures to be
modelled as arrays.  All replicated register declarations have
been replaced by register array declarations.  As a result,
save files from prior revisions will generate errors after
restoring main memory.

2.2 PDP-11

The Unibus map code is in debug.  The map was implemented primarily
to allow source sharing with the VAX, which requires a DMA map.
DMA devices work correctly with the Unibus map disabled.

The RQDX3 simulator has run a complete RSTS/E SYSGEN, with multiple
drives, and booted the completed system from scratch.

2.3 VAX

The VAX simulator will run the boot code up to the >>> prompt.  It
can successfully process a SHOW DEVICE command.  It runs the HCORE
instruction diagnostic.  It can boot the hobbyist CD through SYSBOOT
and through the date/time dialog and restore the hobbyist CD, using
standalone backup.  On the boot of the restored disk, it gets to the
date/time dialog, and then crashes.

2.4 SDS 940

The SDS 940 is untested, awaiting real code.

2.5 GCC Optimization

At -O2 and above, GCC does not correctly compile the simulators which
use setjmp-longjmp (PDP-11, PDP-10, VAX).  A working hypothesis is
that optimized state maintained in registers is being used in the
setjmp processing routine.  On the PDP-11 and PDP-10, all of this
state has been either made global, or volatile, to encourage GCC to
keep the state up to date in memory.  The VAX is still vulnerable.

3. Work list

3.1 SCP

- Better ENABLE/DISABLE.

3.2 PDP-11 RQDX3

Software mapped mode, RCT read simulation, VMS debug.
This commit is contained in:
Bob Supnik
2001-12-26 09:38:00 -08:00
committed by Mark Pizzolato
parent 654937fc88
commit 701f0fe028
145 changed files with 23190 additions and 9807 deletions

1600
PDP18B/pdp18b_cpu.c Normal file

File diff suppressed because it is too large Load Diff

338
PDP18B/pdp18b_defs.h Normal file
View File

@@ -0,0 +1,338 @@
/* pdp18b_defs.h: 18b PDP simulator definitions
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
25-Nov-01 RMS Revised interrupt structure
27-May-01 RMS Added second Teletype support
21-Jan-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
02-Jan-96 RMS Added fixed head and moving head disks
31-Dec-95 RMS Added memory management
19-Mar-95 RMS Added dynamic memory size
The author gratefully acknowledges the help of Craig St. Clair and
Deb Tevonian in locating archival material about the 18b PDP's, and of
Al Kossow and Max Burnet in making documentation and software available.
*/
#include "sim_defs.h" /* simulator defns */
/* Models: only one should be defined
model memory CPU options I/O options
PDP4 8K ??Type 18 EAE Type 65 KSR-28 Teletype (Baudot)
integral paper tape reader
Type 75 paper tape punch
integral real time clock
Type 62 line printer (Hollerith)
PDP7 32K Type 177 EAE Type 649 KSR-33 Teletype
Type 148 mem extension Type 444 paper tape reader
Type 75 paper tape punch
integral real time clock
Type 647B line printer (sixbit)
Type 24 serial drum
PDP9 32K KE09A EAE KSR-33 Teletype
KF09A auto pri intr PC09A paper tape reader and punch
KG09B mem extension integral real time clock
KP09A power detection Type 647D/E line printer (sixbit)
KX09A mem protection RF09/RS09 fixed head disk
TC59 magnetic tape
TC02/TU55 DECtape
LT09A second Teletype
PDP15 128K KE15 EAE KSR-35 Teletype
KA15 auto pri intr PC15 paper tape reader and punch
KF15 power detection KW15 real time clock
KM15 mem protection LP15 line printer
??KT15 mem relocation RP15 disk pack
RF15/RF09 fixed head disk
TC59D magnetic tape
TC15/TU56 DECtape
LT15 second Teletype
??Indicates not implemented. The PDP-4 manual refers to both an EAE
??and a memory extension control; there is no documentation on either.
*/
#if !defined (PDP4) && !defined (PDP7) && !defined (PDP9) && !defined (PDP15)
#define PDP9 0 /* default to PDP-9 */
#endif
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_XCT 4 /* nested XCT's */
#define STOP_API 5 /* invalid API int */
/* Peripheral configuration */
#if defined (PDP4)
#define ADDRSIZE 13
#define KSR28 0 /* Baudot terminal */
#define TYPE62 0 /* Hollerith printer */
#elif defined (PDP7)
#define ADDRSIZE 15
#define TYPE647 0 /* sixbit printer */
#define DRM 0 /* drum */
#elif defined (PDP9)
#define ADDRSIZE 15
#define TYPE647 0 /* sixbit printer */
#define RF 0 /* fixed head disk */
#define MTA 0 /* magtape */
#define DTA 0 /* DECtape */
#define TTY1 0 /* second Teletype */
#define BRMASK 0076000 /* bounds mask */
#elif defined (PDP15)
#define ADDRSIZE 17
#define LP15 0 /* ASCII printer */
#define RF 0 /* fixed head disk */
#define RP 0 /* disk pack */
#define MTA 0 /* magtape */
#define DTA 0 /* DECtape */
#define TTY1 0 /* second Teletype */
#define BRMASK 0377400 /* bounds mask */
#endif
/* Memory */
#define ADDRMASK ((1 << ADDRSIZE) - 1) /* address mask */
#define IAMASK 077777 /* ind address mask */
#define BLKMASK (ADDRMASK & (~IAMASK)) /* block mask */
#define MAXMEMSIZE (1 << ADDRSIZE) /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
/* Architectural constants */
#define DMASK 0777777 /* data mask */
#define LINK (DMASK + 1) /* link */
#define LACMASK (LINK | DMASK) /* link + data */
#define SIGN 0400000 /* sign bit */
#define OP_JMS 0100000 /* JMS */
#define OP_JMP 0600000 /* JMP */
#define OP_HLT 0740040 /* HLT */
/* IOT subroutine return codes */
#define IOT_V_SKP 18 /* skip */
#define IOT_V_REASON 19 /* reason */
#define IOT_SKP (1 << IOT_V_SKP)
#define IOT_REASON (1 << IOT_V_REASON)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* Interrupt system
The interrupt system can be modelled on either the flag driven system
of the PDP-4 and PDP-7 or the API driven system of the PDP-9 and PDP-15.
If flag based, API is hard to implement; if API based, IORS requires
extra code for implementation. I've chosen an API based model.
API channel Device API priority Notes
00 software 4 4
01 software 5 5
02 software 6 6
03 software 7 7
04 TC02/TC15 1
05 TC59D 1
06 drum 1 PDP-9 only
07 disk 1 PDP-9 only
10 paper tape reader 2
11 real time clock 3
12 power fail 0
13 memory parity 0
14 display 2
15 card reader 2
16 line printer 2
17 A/D converter 0
20 interprocessor buffer 3
21 360 link 3 PDP-9 only
22 data phone 2 PDP-15 only
23 RF09/RF15 1
24 RP15 1 PDP-15 only
25 plotter 1 PDP-15 only
26 -
27 -
30 -
31 -
32 -
33 -
34 LT15 TTO 3 PDP-15 only
35 LT15 TTI 3 PDP-15 only
36 -
37 -
*/
#define API_HLVL 4 /* hwre levels */
#define ACH_SWRE 040 /* swre int vec */
/* API level 0 */
#define INT_V_PWRFL 0 /* powerfail */
#define INT_PWRFL (1 << INT_V_PWRFL)
#define API_PWRFL 0
#define ACH_PWRFL 052
/*API level 1 */
#define INT_V_DTA 0 /* DECtape */
#define INT_V_MTA 1 /* magtape */
#define INT_V_DRM 2 /* drum */
#define INT_V_RF 3 /* fixed head disk */
#define INT_V_RP 4 /* disk pack */
#define INT_DTA (1 << INT_V_DTA)
#define INT_MTA (1 << INT_V_MTA)
#define INT_DRM (1 << INT_V_DRM)
#define INT_RF (1 << INT_V_RF)
#define INT_RP (1 << INT_V_RP)
#define API_DTA 1
#define API_MTA 1
#define API_DRM 1
#define API_RF 1
#define API_RP 1
#define ACH_DTA 044
#define ACH_MTA 045
#define ACH_DRM 046
#define ACH_RF 063
#define ACH_RP 064
/* API level 2 */
#define INT_V_PTR 0 /* paper tape reader */
#define INT_V_LPT 1 /* line printer */
#define INT_V_LPTSPC 2 /* line printer spc */
#define INT_PTR (1 << INT_V_PTR)
#define INT_LPT (1 << INT_V_LPT)
#define INT_LPTSPC (1 << INT_V_LPTSPC)
#define API_PTR 2
#define API_LPT 2
#define API_LPTSPC 2
#define ACH_PTR 050
#define ACH_LPT 056
/* API level 3 */
#define INT_V_CLK 0 /* clock */
#define INT_V_TTI1 1 /* LT15 keyboard */
#define INT_V_TTO1 2 /* LT15 output */
#define INT_CLK (1 << INT_V_CLK)
#define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTO1 (1 << INT_V_TTO1)
#define API_CLK 3
#define API_TTI1 3
#define API_TTO1 3
#define ACH_CLK 051
#define ACH_TTI1 075
#define ACH_TTO1 074
/* PI level */
#define INT_V_TTI 0 /* console keyboard */
#define INT_V_TTO 1 /* console output */
#define INT_V_PTP 2 /* paper tape punch */
#define INT_TTI (1 << INT_V_TTI)
#define INT_TTO (1 << INT_V_TTO)
#define INT_PTP (1 << INT_V_PTP)
#define API_TTI 4 /* PI level */
#define API_TTO 4
#define API_PTP 4
/* Interrupt macros */
#define SET_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] | INT_##dv
#define CLR_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] & ~INT_##dv
#define TST_INT(dv) (int_hwre[API_##dv] & INT_##dv)
/* I/O status flags for the IORS instruction
bit PDP-4 PDP-7 PDP-9 PDP-15
0 intr on intr on intr on intr on
1 tape rdr flag* tape rdr flag* tape rdr flag* tape rdr flag*
2 tape pun flag* tape pun flag* tape pun flag* tape pun flag*
3 keyboard flag* keyboard flag* keyboard flag* keyboard flag*
4 type out flag* type out flag* type out flag* type out flag*
5 display flag* display flag* light pen flag* light pen flag*
6 clk ovflo flag* clk ovflo flag* clk ovflo flag* clk ovflo flag*
7 clk enable flag clk enable flag clk enable flag clk enable flag
8 mag tape flag* mag tape flag* tape rdr empty* tape rdr empty*
9 card rdr col* * tape pun empty tape pun empty
10 card rdr ~busy DECtape flag* DECtape flag*
11 card rdr error magtape flag* magtape flag*
12 card rdr EOF disk pack flag*
13 card pun row* DECdisk flag* DECdisk flag*
14 card pun error lpt flag*
15 lpt flag* lpt flag* lpt flag*
16 lpt space flag* lpt error flag lpt error flag
17 drum flag* drum flag*
*/
#define IOS_ION 0400000 /* interrupts on */
#define IOS_PTR 0200000 /* tape reader */
#define IOS_PTP 0100000 /* tape punch */
#define IOS_TTI 0040000 /* keyboard */
#define IOS_TTO 0020000 /* terminal */
#define IOS_LPEN 0010000 /* light pen */
#define IOS_CLK 0004000 /* clock */
#define IOS_CLKON 0002000 /* clock enable */
#define IOS_DTA 0000200 /* DECtape */
#define IOS_RP 0000040 /* disk pack */
#define IOS_RF 0000020 /* fixed head disk */
#define IOS_DRM 0000001 /* drum */
#if defined (PDP4) || defined (PDP7)
#define IOS_MTA 0001000 /* magtape */
#define IOS_LPT 0000004 /* line printer */
#define IOS_LPT1 0000002 /* line printer stat */
#elif defined (PDP9)
#define IOS_PTRERR 0001000 /* reader empty */
#define IOS_PTPERR 0000400 /* punch empty */
#define IOS_MTA 0000100 /* magtape */
#define IOS_LPT 0000004 /* line printer */
#define IOS_LPT1 0000002 /* line printer stat */
#elif defined (PDP15)
#define IOS_PTRERR 0001000 /* reader empty */
#define IOS_PTPERR 0000400 /* punch empty */
#define IOS_MTA 0000100 /* magtape */
#define IOS_LPT 0000010 /* line printer */
#endif

782
PDP18B/pdp18b_doc.txt Normal file
View File

@@ -0,0 +1,782 @@
To: Users
From: Bob Supnik
Subj: 18b PDP Simulator Usage
Date: 1-Dec-01
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
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This memorandum documents the PDP-4, PDP-7, PDP-9, and PDP-15 simulators.
1. Simulator Files
To compile a particular model in the 18b family, you must include the appropriate
switch in the compilation command line:
PDP-4/ PDP4
PDP-7/ PDP7
PDP-9/ PDP9
PDP-15/ PDP15
If no model is specified, the default is the PDP-9.
sim/ sim_defs.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_rev.c
sim_sock.c
sim_tmxr.c
sim/pdp18b/ pdp18b_defs.h
pdp18b_cpu.c
pdp18b_drm.c
pdp18b_dt.c
pdp18b_lp.c
pdp18b_mt.c
pdp18b_rf.c
pdp18b_rp.c
pdp18b_stddev.c
pdp18b_sys.c
pdp18b_tt1.c
2. 18b PDP Features
The other four 18b PDP's (PDP-4, PDP-7, PDP-9, PDP-15) are very similar
and are configured as follows:
system device simulates
name(s)
PDP-4 CPU PDP-4 CPU with 8KW of memory
PTR,PTP integral paper tape/Type 75 punch
TTI,TTO KSR28 console terminal (Baudot code)
LPT Type 62 line printer (Hollerith code)
CLK integral real-time clock
PDP-7 CPU PDP-7 CPU with 32KW of memory
- Type 177 extended arithmetic element (EAE)
- Type 148 memory extension
PTR,PTP Type 444 paper tape reader/Type 75 punch
TTI,TTO KSR 33 console terminal
LPT Type 647 line printer
CLK integral real-time clock
DRM Type 24 serial drum
PDP-9 CPU PDP-9 CPU with 32KW of memory
- KE09A extended arithmetic element (EAE)
- KF09A automatic priority interrupt (API)
- KG09B memory extension
- KP09A power detection
- KX09A memory protection
PTR,PTP PC09A paper tape reader/punch
TTI,TTO KSR 33 console terminal
TTI1,TTO1 LT09A second console terminal
LPT Type 647E line printer
CLK integral real-time clock
RF RF09/RS09 fixed-head disk
DT TC02/TU55 DECtape
MT TC59/TU10 magnetic tape
PDP-15 CPU PDP-15 CPU with 32KW of memory
- KE15 extended arithmetic element (EAE)
- KA15 automatic priority interrupt (API)
- KF15 power detection
- KM15 memory protection
PTR,PTP PC15 paper tape reader/punch
TTI,TTO KSR 35 console terminal
TTI1,TTO1 LT15 second console terminal
LPT LP15 line printer
CLK integral real-time clock
RP RP15/RP02 disk pack
RF RF15/RS09 fixed-head disk
DT TC15/TU56 DECtape
MT TC59/TU10 magnetic tape
The DRM, RF, RP, DT, and MT devices can be DISABLEd.
The 18b PDP simulators implement several unique stop conditions:
- an unimplemented instruction is decoded, and register
STOP_INST is set
- more than XCTMAX nested executes are detected during
instruction execution
The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9
and PDP-15 support both RIM and BIN format tapes. If the file extension
is .RIM, or the -r switch is specified with LOAD, the file is assumed to
be RIM format; if the file extension is not .RIM, or if the -b switch is
specified, the file is assumed to be BIN format.
2.1 CPU
The CPU options are the presence of the EAE, the presense of the API (for
the PDP-9 and PDP-15), and the size of main memory.
SET CPU EAE enable EAE
SET CPU NOEAE disable EAE
SET CPU API enable API
SET CPU NOAPI disable API
SET CPU 4K set memory size = 4K
SET CPU 8K set memory size = 8K
SET CPU 12K set memory size = 12K
SET CPU 16K set memory size = 16K
SET CPU 20K set memory size = 20K
SET CPU 24K set memory size = 24K
SET CPU 28K set memory size = 28K
SET CPU 32K set memory size = 32K
SET CPU 48K set memory size = 48K
SET CPU 64K set memory size = 64K
SET CPU 80K set memory size = 80K
SET CPU 96K set memory size = 96K
SET CPU 112K set memory size = 112K
SET CPU 128K set memory size = 128K
Memory sizes greater than 8K are only available on the PDP-7, PDP-9, and
PDP-15; memory sizes greater than 32KW are only available on the PDP-15.
If memory size is being reduced, and the memory being truncated contains
non-zero data, the simulator asks for confirmation. Data in the truncated
portion of memory is lost. Initial memory size is 8K for the PDP-4, 32K
for the PDP-7 and PDP-9, and 128K for the PDP-15.
CPU registers include the visible state of the processor as well as the
control registers for the interrupt system.
system name size comments
all PC addr program counter
all AC 18 accumulator
all L 1 link
7,9,15 MQ 18 multiplier-quotient
7,9,15 SC 6 shift counter
7,9,15 EAE_AC_SIGN 1 EAE AC sign
all SR 18 front panel switches
all INT[0:4] 32 interrupt requests,
0:3 = API levels 0-3
4 = PI level
all IORS 18 IORS register
all ION 1 interrupt enable
all ION_DELAY 2 interrupt enable delay
9,15 APIENB 1 API enable
9,15 APIREQ 8 API requesting levels
9,15 APIACT 8 API active levels
9,15 BR addr memory protection bounds
15 XR 18 index register
15 LR 18 limit register
15 BR 17 memory protection bounds
9,15 USMD 1 user mode
9,15 USMDBUF 1 user mode buffer
9,15 NEXM 1 non-existent memory violation
9,15 PRVN 1 privilege violation
7,9 EXTM 1 extend mode
7,9 EXTM_INIT 1 extend mode value after reset
15 BANKM 1 bank mode
15 BANKM_INIT 1 bank mode value after reset
7 TRAPM 1 trap mode
7,9,15 TRAPP 1 trap pending
7,9 EMIRP 1 EMIR instruction pending
9,15 RESTP 1 DBR or RES instruction pending
9,15 PWRFL 1 power fail flag
all OLDPC addr PC prior to last transfer
all STOP_INST 1 stop on undefined instruction
all WRU 8 interrupt character
"addr" signifies the address width of the system (13b for the PDP-4, 15b for
the PDP-7 and PDP-9, 17b for the PDP-15).
2.2 Programmed I/O Devices
2.2.1 Paper Tape Reader (PTR)
The paper tape reader (PTR) reads data from a disk file. The POS
register specifies the number of the next data item to be read. Thus,
by changing POS, the user can backspace or advance the reader.
On the PDP-4 and PDP-7, the paper tape reader supports the BOOT command.
BOOT PTR copies the RIM loader into memory and starts it running, while
BOOT -F PTR copies the funny format binary loader into memory and starts
it running.
The paper tape reader implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag (PDP-9, PDP-15 only)
POS 31 position in the input file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape
end of file 1 report error and stop
0 out of tape
OS I/O error x report error and stop
2.2.2 Paper Tape Punch (PTP)
The paper tape punch (PTP) writes data to a disk file. The POS
register specifies the number of the next data item to be written.
Thus, by changing POS, the user can backspace or advance the punch.
The paper tape punch implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag (PDP-9, PDP-15 only)
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.2.3 Terminal Input (TTI)
The terminal input (TTI) polls the console keyboard for input. The
input side has one option, UC; when set, it automatically converts lower
case input to upper case.
The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default,
as half duplex. For backward compatibility, on the PDP-9 and PDP-15
the first terminal input has a second option, FDX; when set, it operates
the terminal input in full-duplex mode. The second terminal is always
full duplex.
The terminal input implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of characters input
TIME 24 keyboard polling interval
2.2.4 Terminal Output (TTO)
The terminal output (TTO) writes to the simulator console window. The
terminal output has one option, UC; when set, it suppresses lower case
output (so that ALTMODE is not echoed as }).
The terminal output implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of chararacters output
TIME 24 time from I/O initiation to interrupt
2.2.5 Line Printer (LPT)
The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The PDP-4 used a Type 62 printer controller, with these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
SPC 1 spacing done flag
BPTR 6 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
The PDP-7 and PDP-7 used a Type 647 printer controller, with these
registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
ENABLE 1 interrupt enable (PDP-9 only)
ERR 1 error flag
BPTR 7 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
The PDP-15 used an LP15 printer controller, with these registers:
name size comments
STA 18 status register
MA 18 DMA memory address
INT 1 interrupt pending flag
ENABLE 1 interrupt enable
LCNT 8 line counter
BPTR 7 print buffer pointer
POS 31 position in the output file
TIME 24 time from I/O initiation to interrupt
STOP_IOE 1 stop on I/O error
LBUF[0:131] 8 line buffer
For all three models, error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 out of tape or paper
OS I/O error x report error and stop
2.2.6 Real-Time Clock (CLK)
The real-time clock (CLK) implements these registers:
name size comments
INT 1 interrupt pending flag
DONE 1 device done flag
ENABLE 1 clock enable
TIME 24 clock frequency
TPS 8 ticks per second (60 or 50)
The real-time clock autocalibrates; the clock interval is adjusted up or
down so that the clock tracks actual elapsed time.
2.2.7 Second Terminal (TTI1, TTO1)
The second terminal consists of two independent devices, TTI1 and TTO1.
The second terminal performs input and output through a Telnet session
connected to a user-specified port. The ATTACH command specifies the
port to be used:
ATTACH TTI1 <port>(cr) -- set up listening port
where port is a decimal number between 1 and 65535 that is not being used
for other TCP/IP activities.
Once TTI1 is attached and the simulator is running, the terminal listens
for a connection on the specified port. It assumes that the incoming
connection is a Telnet connection. The connection remain opens until
disconnected by the Telnet client, or by a DETACH TTI1 command.
The second terminal input has one option, UC; when set, it automatically
converts lower case input to upper case. The second terminal output also
has one option, UC; when set, it suppresses lower case output (so that
ALTMODE is not echoed as }).
The SHOW TTI1 LINESTATUS command displays the current connection to the
second terminal.
The second terminal input implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of characters input
TIME 24 keyboard polling interval
The second terminal output implements these registers:
name size comments
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
POS 31 number of chararacters output
TIME 24 time from I/O initiation to interrupt
2.3 RP15/RP02 Disk Pack (RP)
RP15 options include the ability to make units write enabled or write locked:
SET RPn LOCKED set unit n write locked
SET RPn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
The RP15 implements these registers:
name size comments
STA 18 status A
STB 18 status B
DA 18 disk address
MA 18 current memory address
WC 18 word count
INT 1 interrupt pending flag
BUSY 1 control busy flag
STIME 24 seek time, per cylinder
RTIME 24 rotational delay
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
end of file x assume rest of disk is zero
OS I/O error x report error and stop
2.4 Type 24 Serial Drum (DRM)
The serial drum (DRM) implements these registers:
name size comments
DA 9 drum address (sector number)
MA 15 current memory address
INT 1 interrupt pending flag
DONE 1 device done flag
ERR 1 error flag
WLK 32 write lock switches
TIME 24 rotational latency, per word
STOP_IOE 1 stop on I/O error
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
Drum data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.5 RF09/RF15/RS09 Fixed Head Disk (RF)
The RF09/RF15 implements these registers:
name size comments
STA 18 status
DA 21 current disk address
MA 18 memory address (in memory)
WC 18 word count (in memory)
BUF 18 data buffer (diagnostic only)
INT 1 interrupt pending flag
WLK[0:7] 16 write lock switches for disks 0-7
TIME 24 rotational delay, per word
BURST 1 burst flag
STOP_IOE 1 stop on I/O error
The RF09/RF15 is a three-cycle data break device. If BURST = 0, word
transfers are scheduled individually; if BURST = 1, the entire transfer
occurs in a single data break.
Error handling is as follows:
error STOP_IOE processed as
not attached 1 report error and stop
0 disk not ready
RF15/RF09 data files are buffered in memory; therefore, end of file and OS
I/O errors cannot occur.
2.6 TC02/TU55 and TC15/TU56 DECtape (DT)
DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0.
DECtape options include the ability to make units write enabled or write
locked.
SET DTn LOCKED set unit n write locked
SET DTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
The TC02/TC15 supports both PDP-8 format and PDP-9/11/15 format DECtape
images. ATTACH tries to determine the tape format from the DECtape image;
the user can force a particular format with switches:
-f foreign (PDP-8) format
-n native (PDP-9/11/15) format
The DECtape controller is a data-only simulator; the timing and mark
track, and block header and trailer, are not stored. Thus, the WRITE
TIMING AND MARK TRACK function is not supported; the READ ALL function
always returns the hardware standard block header and trailer; and the
WRITE ALL function dumps non-data words into the bit bucket.
The DECtape controller implements these registers:
name size comments
DTSA 12 status register A
DTSB 12 status register B
INT 1 interrupt pending flag
ENB 1 interrupt enable flag
DTF 1 DECtape flag
ERF 1 error flag
CA 18 current address (memory location 30)
WC 18 word count (memory location 31)
LTIME 31 time between lines
ACTIME 31 time to accelerate to full speed
DCTIME 31 time to decelerate to a full stop
SUBSTATE 2 read/write command substate
POS[0:7] 31 position, in lines, units 0-7
STATT[0:7] 31 unit state, units 0-7
It is critically important to maintain certain timing relationships
among the DECtape parameters, or the DECtape simulator will fail to
operate correctly.
- LTIME must be at least 6
- ACTIME must be less than DCTIME, and both need to be at
least 100 times LTIME
2.7 TC59/TU10 Magnetic Tape (MT)
Magnetic tape options include the ability to make units write enabled or
or write locked.
SET MTn LOCKED set unit n write locked
SET MTn ENABLED set unit n write enabled
Units can also be REMOVEd or ADDed to the configuration.
The magnetic tape controller implements these registers:
name size comments
CMD 18 command
STA 18 main status
MA 18 memory address (in memory)
WC 18 word count (in memory)
INT 1 interrupt pending flag
STOP_IOE 1 stop on I/O error
TIME 24 record delay
UST[0:7] 24 unit status, units 0-7
POS[0:7] 31 position, units 0-7
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.8 Symbolic Display and Input
The 18b PDP simulators implement symbolic display and input. Display is
controlled by command line switches:
-a display as ASCII character
-c display as (sixbit) character string
-m display instruction mnemonics
The PDP-15 also recognizes an additional switch:
-p display as packed ASCII (five 7b ASCII
characters in two 18b words)
Input parsing is controlled by the first character typed in or by command
line switches:
' or -a ASCII character
" or -c three character sixbit string
alphabetic instruction mnemonic
numeric octal number
The PDP-15 also recognizes an additional input mode:
# or -p five character packed ASCII string in
two 18b words
Instruction input uses standard 18b PDP assembler syntax. There are six
instruction classes: memory reference, EAE, index (PDP-15 only), IOT,
operate, and LAW.
Memory reference instructions have the format
memref {I/@} address{,X}
where I (PDP-4, PDP-7, PDP-9) /@ (PDP-15) signifies indirect reference,
and X signifies indexing (PDP-15 in page mode only). The address is an
octal number in the range 0 - 017777 (PDP-4, PDP-7, PDP-9, and PDP-15 in
bank mode) or 0 - 07777 (PDP-15 in page mode).
IOT instructions consist of single mnemonics, eg, KRB, TLS. IOT instructions
may be or'd together
iot iot iot...
IOT's may also include the number 10, signifying clear the accumulator
iot 10
The simulator does not check the legality of IOT combinations. IOT's for
which there is no opcode may be specified as IOT n, where n is an octal
number in the range 0 - 07777.
EAE instructions have the format
eae {+/- shift count}
EAE instructions may be or'd together
eae eae eae...
The simulator does not check the legality of EAE combinations. EAE's for
which there is no opcode may be specified as EAE n, where n is an octal
number in the range 0 - 037777.
Index instructions (PDP-15 only) have the format
index {immediate}
The immediate, if allowed, must be in the range of -0400 to +0377.
Operate instructions have the format
opr opr opr...
The simulator does not check the legality of the proposed combination. The
operands for MUY and DVI must be deposited explicitly.
Finally, the LAW instruction has the format
LAW immediate
where immediate is in the range of 0 to 017777.
2.9 Character Sets
The PDP-4's console was an ASR-28 Teletype; its character encoding was
Baudot. The PDP-4's line printer used a modified Hollerith character
set. The PDP-7's and PDP-9's consoles were KSR-33 Teletypes; their
character sets were basically ASCII. The PDP-7's and PDP-9's line
printers used sixbit encoding (ASCII codes 040 - 0137 masked to six
bits). The PDP-15's I/O devices were all ASCII. The following table
provides equivalences between ASCII characters and the PDP-4's I/O devices.
In the console table, FG stands for figures (upper case).
PDP-4 PDP-4
ASCII console line printer
000 - 006 none none
bell FG+024 none
010 - 011 none none
lf 010 none
013 - 014 none none
cr 002 none
016 - 037 none none
space 004 000
! FG+026 none
" FG+021 none
# FG+005 none
$ FG+062 none
% none none
& FG+013 none
' FG+032 none
( FG+036 057
) FG+011 055
* none 072
+ none 074
, FG+006 033
- FG+030 054
. FG+007 073
/ FG+027 021
0 FG+015 020
1 FG+035 001
2 FG+031 002
3 FG+020 003
4 FG+012 004
5 FG+001 005
6 FG+025 006
7 FG+034 007
8 FG+014 010
9 FG+003 011
: FG+016 none
; FG+017 none
< none 034
= none 053
> none 034
? FG+023 037
@ none {MID DOT} 040
A 030 061
B 023 062
C 016 063
D 022 064
E 020 065
F 026 066
G 013 067
H 005 070
I 014 071
J 032 041
K 036 042
L 011 043
M 007 044
N 006 045
O 003 046
P 015 047
Q 035 050
R 012 051
S 024 022
T 001 023
U 034 024
V 017 025
W 031 026
X 027 027
Y 025 030
Z 021 031
[ none none
\ none {OVERLINE} 056
] none none
^ none {UP ARROW} 035
_ none UC+040
0140 - 0177 none none

210
PDP18B/pdp18b_drm.c Normal file
View File

@@ -0,0 +1,210 @@
/* pdp18b_drm.c: drum/fixed head disk simulator
Copyright (c) 1993-2001, 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.
drm (PDP-7) Type 24 serial drum
(PDP-9) RM09 serial drum
25-Nov-01 RMS Revised interrupt structure
10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware
26-Apr-01 RMS Added device enable/disable support
14-Apr-99 RMS Changed t_addr to unsigned
*/
#include "pdp18b_defs.h"
#include <math.h>
/* Constants */
#define DRM_NUMWDS 256 /* words/sector */
#define DRM_NUMSC 2 /* sectors/track */
#define DRM_NUMTR 256 /* tracks/drum */
#define DRM_NUMDK 1 /* drum/controller */
#define DRM_NUMWDT (DRM_NUMWDS * DRM_NUMSC) /* words/track */
#define DRM_SIZE (DRM_NUMDK * DRM_NUMTR * DRM_NUMWDT) /* words/drum */
#define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define DRM_READ 000 /* read */
#define DRM_WRITE 040 /* write */
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DRM_NUMWDT)))
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
int32 drm_da = 0; /* track address */
int32 drm_ma = 0; /* memory address */
int32 drm_err = 0; /* error flag */
int32 drm_wlk = 0; /* write lock */
int32 drm_time = 10; /* inter-word time */
int32 drm_stopioe = 1; /* stop on error */
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
t_stat drm_boot (int32 unitno);
/* DRM data structures
drm_dev DRM device descriptor
drm_unit DRM unit descriptor
drm_reg DRM register list
*/
UNIT drm_unit =
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
DRM_SIZE) };
REG drm_reg[] = {
{ ORDATA (DA, drm_da, 9) },
{ ORDATA (MA, drm_ma, 15) },
{ FLDATA (INT, int_hwre[API_DRM], INT_V_DRM) },
{ FLDATA (DONE, int_hwre[API_DRM], INT_V_DRM) },
{ FLDATA (ERR, drm_err, 0) },
{ ORDATA (WLK, drm_wlk, 32) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_DRM), REG_HRO },
{ NULL } };
DEVICE drm_dev = {
"DRM", &drm_unit, drm_reg, NULL,
1, 8, 20, 1, 8, 18,
NULL, NULL, &drm_reset,
&drm_boot, NULL, NULL };
/* IOT routines */
int32 drm60 (int32 pulse, int32 AC)
{
if ((pulse & 027) == 06) { /* DRLR, DRLW */
drm_ma = AC & ADDRMASK; /* load mem addr */
drm_unit.FUNC = pulse & 040; } /* save function */
return AC;
}
int32 drm61 (int32 pulse, int32 AC)
{
int32 t;
if (pulse & 001) { /* DRSF */
if (TST_INT (DRM)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* DRCF */
CLR_INT (DRM); /* clear done */
drm_err = 0; } /* clear error */
if (pulse & 004) { /* DRSS */
drm_da = AC & DRM_SMASK; /* load sector # */
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t < 0) t = t + DRM_NUMWDT; /* wrap around? */
sim_activate (&drm_unit, t * drm_time); } /* schedule op */
return AC;
}
int32 drm62 (int32 pulse, int32 AC)
{
int32 t;
if (pulse & 001) { /* DRSN */
if (drm_err == 0) AC = AC | IOT_SKP; }
if (pulse & 004) { /* DRCS */
CLR_INT (DRM); /* clear done */
drm_err = 0; /* clear error */
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
if (t < 0) t = t + DRM_NUMWDT; /* wrap around? */
sim_activate (&drm_unit, t * drm_time); } /* schedule op */
return AC;
}
/* Unit service
This code assumes the entire drum is buffered.
*/
t_stat drm_svc (UNIT *uptr)
{
int32 i;
t_addr da;
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */
SET_INT (DRM); /* set done */
return IORETURN (drm_stopioe, SCPE_UNATT); }
da = drm_da * DRM_NUMWDS; /* compute dev addr */
for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
if (uptr -> FUNC == DRM_READ) {
if (MEM_ADDR_OK (drm_ma)) /* read, check nxm */
M[drm_ma] = *(((int32 *) uptr -> filebuf) + da); }
else { if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1;
else { *(((int32 *) uptr -> filebuf) + da) = M[drm_ma];
if (da >= uptr -> hwmark)
uptr -> hwmark = da + 1; } }
drm_ma = (drm_ma + 1) & ADDRMASK; } /* incr mem addr */
drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
SET_INT (DRM); /* set done */
return SCPE_OK;
}
/* Reset routine */
t_stat drm_reset (DEVICE *dptr)
{
drm_ma = drm_ma = drm_err = 0;
CLR_INT (DRM); /* clear done */
sim_cancel (&drm_unit);
return SCPE_OK;
}
/* IORS routine */
int32 drm_iors (void)
{
return (TST_INT (DRM)? IOS_DRM: 0);
}
/* Bootstrap routine */
#define BOOT_START 02000
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
0750000, /* CLA ; dev, mem addr */
0706006, /* DRLR ; load ma */
0706106, /* DRSS ; load da, start */
0706101, /* DRSF ; wait for done */
0602003, /* JMP .-1
0600000 /* JMP 0 ; enter boot */
};
t_stat drm_boot (int32 unitno)
{
int32 i;
extern int32 saved_PC;
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
return SCPE_OK;
}

1053
PDP18B/pdp18b_dt.c Normal file

File diff suppressed because it is too large Load Diff

552
PDP18B/pdp18b_lp.c Normal file
View File

@@ -0,0 +1,552 @@
/* pdp18b_lp.c: 18b PDP's line printer simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
lpt (PDP-4) Type 62 line printer
(PDP-7,9) Type 647 line printer
(PDP-15) LP15 line printer
25-Nov-01 RMS Revised interrupt structure
19-Sep-01 RMS Fixed bug in 647
13-Feb-01 RMS Revised for register arrays
15-Feb-01 RMS Fixed 3 cycle data break sequence
30-Oct-00 RMS Standardized register naming
20-Aug-98 RMS Fixed compilation problem in BeOS
03-Jan-97 RMS Fixed bug in Type 62 state handling
*/
#include "pdp18b_defs.h"
#if defined (TYPE62)
#define BPTR_MAX 40 /* pointer max */
#define LPT_BSIZE 120 /* line size */
#define BPTR_MASK 077 /* buf ptr max */
extern int32 int_hwre[API_HLVL+1];
int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
char lpt_buf[LPT_BSIZE + 1] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
/* Type 62 LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) },
{ DRDATA (BPTR, bptr, 6) },
{ ORDATA (STATE, lpt_iot, 6), REG_HRO },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL };
/* Type 62 line printer: IOT routines */
int32 lpt65 (int32 pulse, int32 AC)
{
int32 i;
static const char lpt_trans[64] = {
' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<',
'0','/','S','T','U','V','W','X','Y','Z','"',',','>','^','-','?',
'o','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(',
'_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' };
if (pulse == 001) return (TST_INT (LPT))? IOT_SKP + AC: AC; /* LPSF */
if (pulse == 002) CLR_INT (LPT); /* LPCF */
else if (pulse == 042) { /* LPLD */
if (bptr < BPTR_MAX) { /* limit test ptr */
i = bptr * 3; /* cvt to chr ptr */
lpt_buf[i++] = lpt_trans[(AC >> 12) & 077];
lpt_buf[i++] = lpt_trans[(AC >> 6) & 077];
lpt_buf[i++] = lpt_trans[AC & 077]; }
bptr = (bptr + 1) & BPTR_MASK; }
else if (pulse == 006) { /* LPSE */
CLR_INT (LPT); /* clear flag */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
return AC;
}
int32 lpt66 (int32 pulse, int32 AC)
{
if (pulse == 001) return (TST_INT (LPTSPC))? IOT_SKP + AC: AC; /* LSSF */
if (pulse & 002) CLR_INT (LPTSPC); /* LSCF */
if (pulse & 004) { /* LSPR */
CLR_INT (LPTSPC); /* clear flag */
lpt_iot = 020 | (AC & 07); /* space, no print */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
return AC;
}
/* Unit service, printer is in one of three states
lpt_iot = 0 write buffer to file, set state to
lpt_iot = 10 write cr, then write buffer to file
lpt_iot = 2x space command x, then set state to 0
*/
t_stat lpt_svc (UNIT *uptr)
{
int32 i;
static const char *lpt_cc[] = {
"\n",
"\n\n",
"\n\n\n",
"\n\n\n\n\n\n",
"\n\n\n\n\n\n\n\n\n\n\n",
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\f" };
if (lpt_iot & 020) { /* space? */
SET_INT (LPTSPC); /* set flag */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
fputs (lpt_cc[lpt_iot & 07], lpt_unit.fileref); /* print cctl */
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
lpt_iot = 0; } /* clear state */
else { SET_INT (LPT); /* print */
if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (lpt_stopioe, SCPE_UNATT);
if (lpt_iot & 010) fputc ('\r', lpt_unit.fileref);
fputs (lpt_buf, lpt_unit.fileref); /* print buffer */
if (ferror (lpt_unit.fileref)) { /* test error */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
bptr = 0;
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
lpt_iot = 010; } /* set state */
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
return SCPE_OK;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
int32 i;
CLR_INT (LPT); /* clear intrs */
CLR_INT (LPTSPC);
sim_cancel (&lpt_unit); /* deactivate unit */
bptr = 0; /* clear buffer ptr */
for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
lpt_iot = 0; /* clear state */
return SCPE_OK;
}
/* IORS routine */
int32 lpt_iors (void)
{
return (TST_INT (LPT)? IOS_LPT: 0) |
(TST_INT (LPTSPC)? IOS_LPT1: 0);
}
#elif defined (TYPE647)
#define LPT_BSIZE 120 /* line size */
extern int32 int_hwre[API_HLVL+1];
int32 lpt_done = 0, lpt_ie = 1, lpt_err = 0;
int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
char lpt_buf[LPT_BSIZE] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_detach (UNIT *uptr);
/* Type 647 LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (DONE, lpt_done, 0) },
#if defined (PDP9)
{ FLDATA (ENABLE, lpt_ie, 0) },
#endif
{ FLDATA (ERR, lpt_err, 0) },
{ DRDATA (BPTR, bptr, 7) },
{ ORDATA (SCMD, lpt_iot, 6), REG_HRO },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, &lpt_detach };
/* Type 647 line printer: IOT routines */
int32 lpt65 (int32 pulse, int32 AC)
{
int32 i;
if (pulse == 001) return (lpt_done? IOT_SKP + AC: AC); /* LPSF */
if (pulse & 002) { /* pulse 02 */
lpt_done = 0; /* clear done */
CLR_INT (LPT); } /* clear int req */
if (pulse == 002) { /* LPCB */
for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0;
bptr = 0; /* reset buf ptr */
lpt_done = 1; /* set done */
if (lpt_ie) SET_INT (LPT); } /* set int */
#if defined (PDP9)
if (pulse == 004) { /* LPDI */
lpt_ie = 0; /* clear int enable */
CLR_INT (LPT); } /* clear int req */
#endif
if ((pulse == 046) && (bptr < LPT_BSIZE)) { /* LPB3 */
lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 12) & 077);
bptr = bptr + 1; }
if (((pulse == 046) || (pulse == 026)) && (bptr < LPT_BSIZE)) {
lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 6) & 077);
bptr = bptr + 1; }
if ((pulse == 046) || (pulse == 026) || (pulse == 066)) {
if (bptr < LPT_BSIZE) {
lpt_buf[bptr] = lpt_buf[bptr] | (AC & 077);
bptr = bptr + 1; }
lpt_done = 1; /* set done */
if (lpt_ie) SET_INT (LPT); } /* set int */
return AC;
}
int32 lpt66 (int32 pulse, int32 AC)
{
if (pulse == 001) return (lpt_err? IOT_SKP + AC: AC); /* LPSE */
if (pulse & 002) { /* LPCF */
lpt_done = 0; /* clear done, int */
CLR_INT (LPT); }
if (((pulse & 060) < 060) && (pulse & 004)) { /* LPLS, LPPB, LPPS */
lpt_iot = (pulse & 060) | (AC & 07); /* save parameters */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
#if defined (PDP9)
if (pulse == 064) { /* LPEI */
lpt_ie = 1; /* set int enable */
if (lpt_done) SET_INT (LPT); }
#endif
return AC;
}
/* Unit service. lpt_iot specifies the action to be taken
lpt_iot = 0x print only
lpt_iot = 2x space only, x is spacing command
lpt_iot = 4x print then space, x is spacing command
*/
t_stat lpt_svc (UNIT *uptr)
{
int32 i;
char pbuf[LPT_BSIZE + 1];
static const char *lpt_cc[] = {
"\n",
"\n\n",
"\n\n\n",
"\n\n\n\n\n\n",
"\n\n\n\n\n\n\n\n\n\n\n",
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\f" };
lpt_done = 1;
if (lpt_ie) SET_INT (LPT); /* set flag */
if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
lpt_err = 1; /* set error */
return IORETURN (lpt_stopioe, SCPE_UNATT); }
if ((lpt_iot & 020) == 0) { /* print? */
for (i = 0; i < bptr; i++) /* translate buffer */
pbuf[i] = lpt_buf[i] | ((lpt_buf[i] >= 040)? 0: 0100);
if ((lpt_iot & 060) == 0) pbuf[bptr++] = '\r';
for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
fwrite (pbuf, 1, bptr, lpt_unit.fileref); /* print buffer */
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
bptr = 0;
return SCPE_IOERR; }
bptr = 0; } /* clear buffer ptr */
if (lpt_iot & 060) { /* space? */
fputs (lpt_cc[lpt_iot & 07], lpt_unit.fileref); /* write cctl */
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; } }
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
return SCPE_OK;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
int32 i;
lpt_done = 0; /* clear done */
lpt_err = (lpt_unit.flags & UNIT_ATT)? 0: 1; /* compute error */
lpt_ie = 1; /* set enable */
CLR_INT (LPT); /* clear int */
sim_cancel (&lpt_unit); /* deactivate unit */
bptr = 0; /* clear buffer ptr */
lpt_iot = 0; /* clear state */
for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */
return SCPE_OK;
}
/* IORS routine */
int32 lpt_iors (void)
{
return (lpt_done? IOS_LPT: 0) | (lpt_err? IOS_LPT1: 0);
}
/* Attach routine */
t_stat lpt_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
lpt_err = (lpt_unit.flags & UNIT_ATT)? 0: 1; /* compute error */
return reason;
}
/* Detach routine */
t_stat lpt_detach (UNIT *uptr)
{
lpt_err = 1;
return detach_unit (uptr);
}
#elif defined (LP15)
#define LPT_BSIZE 132 /* line size */
#define LPT_WC 034 /* word count */
#define LPT_CA 035 /* current addr */
/* Status register */
#define STA_ERR 0400000 /* error */
#define STA_ALM 0200000 /* alarm */
#define STA_OVF 0100000 /* line overflow */
#define STA_IHT 0040000 /* illegal HT */
#define STA_BUSY 0020000 /* busy */
#define STA_DON 0010000 /* done */
#define STA_ILK 0004000 /* interlock */
#define STA_EFLGS (STA_ALM | STA_OVF | STA_IHT | STA_ILK)
#define STA_CLR 0003777 /* always clear */
extern int32 M[];
extern int32 int_hwre[API_HLVL+1];
int32 lpt_sta = 0, lpt_ie = 1, lpt_stopioe = 0;
int32 mode = 0, lcnt = 0, bptr = 0;
char lpt_buf[LPT_BSIZE] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
int32 lpt_updsta (int32 new);
/* LP15 LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (STA, lpt_sta, 18) },
{ ORDATA (CA, M[LPT_CA], 18) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
{ FLDATA (ENABLE, lpt_ie, 0) },
{ DRDATA (LCNT, lcnt, 9) },
{ DRDATA (BPTR, bptr, 8) },
{ FLDATA (MODE, mode, 0) },
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL };
/* LP15 line printer: IOT routines */
int32 lpt65 (int32 pulse, int32 AC)
{
int32 header;
if (pulse == 001) /* LPSF */
return (lpt_sta & (STA_ERR | STA_DON))? IOT_SKP + AC: AC;
if ((pulse == 021) || (pulse == 041)) { /* LPP1, LPPM */
header = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777;
mode = header & 1; /* mode */
if (pulse == 041) lcnt = 1; /* line count */
else lcnt = (header >> 9) & 0377;
if (lcnt == 0) lcnt = 256;
bptr = 0; /* reset buf ptr */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
if (pulse == 061) lpt_ie = 0; /* LPDI */
if (pulse == 042) return lpt_updsta (0); /* LPOS, LPRS */
if (pulse == 044) lpt_ie = 1; /* LPEI */
lpt_updsta (0); /* update status */
return AC;
}
int32 lpt66 (int32 pulse, int32 AC)
{
if (pulse == 021) lpt_sta = lpt_sta & ~STA_DON; /* LPCD */
if (pulse == 041) lpt_sta = lpt_sta = 0; /* LPCF */
lpt_updsta (0); /* update status */
return AC;
}
/* Unit service */
t_stat lpt_svc (UNIT *uptr)
{
int32 i, ccnt, more, w0, w1;
char c[5];
static const char *ctrl[040] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, "\n", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\f", "\r", NULL, NULL,
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\n\n", "\n\n\n", "\n",
"\n\n\n\n\n\n\n\n\n\n", NULL, NULL, NULL,
NULL, NULL, NULL, "\r", NULL, NULL, NULL, NULL };
if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */
lpt_updsta (STA_DON | STA_ALM); /* set done, err */
return IORETURN (lpt_stopioe, SCPE_UNATT); }
for (more = 1; more != 0; ) { /* loop until ctrl */
w0 = M[(M[LPT_CA] + 1) & ADDRMASK]; /* get first word */
w1 = M[(M[LPT_CA] + 2) & ADDRMASK]; /* get second word */
M[LPT_CA] = (M[LPT_CA] + 2) & 0777777; /* advance mem addr */
if (mode) { /* unpacked? */
c[0] = w0 & 0177;
c[1] = w1 & 0177;
ccnt = 2; }
else { c[0] = (w0 >> 11) & 0177; /* packed */
c[1] = (w0 >> 4) & 0177;
c[2] = (((w0 << 3) | (w1 >> 15))) & 0177;
c[3] = (w1 >> 8) & 0177;
c[4] = (w1 >> 1) & 0177;
ccnt = 5; }
for (i = 0; i < ccnt; i++) { /* loop through */
if ((c[i] <= 037) && ctrl[c[i]]) { /* control char? */
fwrite (lpt_buf, 1, bptr, lpt_unit.fileref);
fputs (ctrl[c[i]], lpt_unit.fileref);
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
bptr = 0;
lpt_updsta (STA_DON | STA_ALM);
return SCPE_IOERR; }
lpt_unit.pos = ftell (lpt_unit.fileref);
bptr = more = 0; }
else { if (bptr < LPT_BSIZE) lpt_buf[bptr++] = c[i];
else lpt_sta = lpt_sta | STA_OVF; } } }
lcnt = lcnt - 1; /* decr line count */
if (lcnt) sim_activate (&lpt_unit, lpt_unit.wait); /* more to do? */
else lpt_updsta (STA_DON); /* no, set done */
return SCPE_OK;
}
/* Update status */
int32 lpt_updsta (int32 new)
{
lpt_sta = (lpt_sta | new) & ~(STA_CLR | STA_ERR | STA_BUSY);
if (lpt_sta & STA_EFLGS) lpt_sta = lpt_sta | STA_ERR; /* update errors */
if (sim_is_active (&lpt_unit)) lpt_sta = lpt_sta | STA_BUSY;
if (lpt_ie && (lpt_sta & STA_DON)) SET_INT (LPT);
else CLR_INT (LPT); /* update int */
return lpt_sta;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
mode = lcnt = bptr = 0; /* clear controls */
sim_cancel (&lpt_unit); /* deactivate unit */
lpt_sta = 0; /* clear status */
lpt_ie = 1; /* enable interrupts */
lpt_updsta (0); /* update status */
return SCPE_OK;
}
/* IORS routine */
int32 lpt_iors (void)
{
return ((lpt_sta & STA_DON)? IOS_LPT: 0);
}
#endif

448
PDP18B/pdp18b_mt.c Normal file
View File

@@ -0,0 +1,448 @@
/* pdp18b_mt.c: 18b PDP magnetic tape simulator
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mt (PDP-9) TC59 magtape
(PDP-15) TC59D magtape
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
Changed UST, POS, FLG to arrays
26-Apr-01 RMS Added device enable/disable support
15-Feb-01 RMS Fixed 3-cycle data break sequence
04-Oct-98 RMS V2.4 magtape format
22-Jan-97 RMS V2.3 magtape format
29-Jun-96 RMS Added unit enable/disable support
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
32 byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
*/
#include "pdp18b_defs.h"
#define MT_NUMDR 8 /* #drives */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK 1 << UNIT_V_WLK
#define UNIT_W_UF 2 /* saved flag width */
#define USTAT u3 /* unit status */
#define UNUM u4 /* unit number */
#define DBSIZE (1 << 12) /* max data record */
#define DBMASK (DBSIZE - 1)
#define MT_WC 032 /* word count */
#define MT_CA 033 /* current addr */
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Command/unit - mt_cu */
#define CU_V_UNIT 15 /* unit */
#define CU_M_UNIT 07
#define CU_PARITY 0040000 /* parity select */
#define CU_DUMP 0020000 /* dump mode */
#define CU_ERASE 0010000 /* ext rec gap */
#define CU_V_CMD 9 /* command */
#define CU_M_CMD 07
#define FN_NOP 00
#define FN_REWIND 01
#define FN_READ 02
#define FN_CMPARE 03
#define FN_WRITE 04
#define FN_WREOF 05
#define FN_SPACEF 06
#define FN_SPACER 07
#define CU_IE 0000400 /* interrupt enable */
#define CU_V_TYPE 6 /* drive type */
#define CU_M_TYPE 03
#define TY_9TK 3
#define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
#define GET_CMD(x) (((x) >> CU_V_CMD) & CU_M_CMD)
#define GET_TYPE(x) (((x) >> CU_V_TYPE) & CU_M_TYPE)
#define PACKED(x) (((x) & CU_DUMP) || (GET_TYPE (x) != TY_9TK))
/* Status - stored in mt_sta or (*) uptr -> USTAT */
#define STA_ERR 0400000 /* error */
#define STA_REW 0200000 /* *rewinding */
#define STA_BOT 0100000 /* *start of tape */
#define STA_ILL 0040000 /* illegal cmd */
#define STA_PAR 0020000 /* parity error */
#define STA_EOF 0010000 /* *end of file */
#define STA_EOT 0004000 /* *end of tape */
#define STA_CPE 0002000 /* compare error */
#define STA_RLE 0001000 /* rec lnt error */
#define STA_DLT 0000400 /* data late */
#define STA_BAD 0000200 /* bad tape */
#define STA_DON 0000100 /* done */
#define STA_CLR 0000077 /* always clear */
#define STA_DYN (STA_REW | STA_BOT | STA_EOF | STA_EOT)
/* kept in USTAT */
#define STA_EFLGS (STA_BOT | STA_ILL | STA_PAR | STA_EOF | \
STA_EOT | STA_CPE | STA_RLE | STA_DLT | STA_BAD)
/* error flags */
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
int32 mt_cu = 0; /* command/unit */
int32 mt_sta = 0; /* status register */
int32 mt_time = 10; /* record latency */
int32 mt_stopioe = 1; /* stop on error */
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_detach (UNIT *uptr);
int32 mt_updcsta (UNIT *uptr, int32 val);
UNIT *mt_busy (void);
/* MT data structures
mt_dev MT device descriptor
mt_unit MT unit list
mt_reg MT register list
mt_mod MT modifier list
*/
UNIT mt_unit[] = {
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } };
REG mt_reg[] = {
{ ORDATA (STA, mt_sta, 18) },
{ ORDATA (CMD, mt_cu, 18) },
{ ORDATA (WC, M[MT_WC], 18) },
{ ORDATA (CA, M[MT_CA], 18) },
{ FLDATA (INT, int_hwre[API_MTA], INT_V_MTA) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ DRDATA (TIME, mt_time, 24), PV_LEFT },
{ URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, 31, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
MT_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, INT_V_MTA), REG_HRO },
{ NULL } };
MTAB mt_mod[] = {
{ UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ 0 } };
DEVICE mt_dev = {
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &mt_detach };
/* IOT routine */
int32 mt (int32 pulse, int32 AC)
{
int32 f;
UNIT *uptr;
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
mt_updcsta (uptr, 0); /* update status */
if (pulse == 001) /* MTTR */
return (!sim_is_active (uptr))? IOT_SKP + AC: AC;
if (pulse == 021) /* MTCR */
return (!mt_busy ())? IOT_SKP + AC: AC;
if (pulse == 041) /* MTSF */
return (mt_sta & (STA_ERR | STA_DON))? IOT_SKP + AC: AC;
if (pulse == 002) return (mt_cu & 0777700); /* MTRC */
if (pulse == 042) return mt_sta; /* MTRS */
if ((pulse & 062) == 022) { /* MTAF, MTLC */
if (!mt_busy ()) mt_cu = mt_sta = 0; /* if not busy, clr */
mt_sta = mt_sta & ~(STA_ERR | STA_DON); } /* clear flags */
if ((pulse & 064) == 024) /* MTCM, MTLC */
mt_cu = (mt_cu & 0770700) | (AC & 0777700); /* load status */
if (pulse == 004) { /* MTGO */
f = GET_CMD (mt_cu); /* get function */
if (mt_busy () || (sim_is_active (uptr)) ||
(((f == FN_SPACER) || (f == FN_REWIND)) & (uptr -> pos == 0)) ||
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT))
|| ((uptr -> flags & UNIT_ATT) == 0) || (f == FN_NOP))
mt_sta = mt_sta | STA_ILL; /* illegal op flag */
else { if (f == FN_REWIND) uptr -> USTAT = STA_REW; /* rewind? */
else mt_sta = uptr -> USTAT = 0; /* no, clear status */
sim_activate (uptr, mt_time); } } /* start io */
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return AC;
}
/* Unit service
If rewind done, reposition to start of tape, set status
else, do operation, set done, interrupt
*/
t_stat mt_svc (UNIT *uptr)
{
int32 c, c1, c2, c3, f, i, p, u, err;
int32 wc, xma;
t_stat rval;
t_mtrlnt tbc, cbc;
static uint8 dbuf[(3 * DBSIZE)];
static t_mtrlnt bceof = { 0 };
u = uptr -> UNUM; /* get unit number */
if (uptr -> USTAT & STA_REW) { /* rewind? */
uptr -> pos = 0; /* update position */
if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
else uptr -> USTAT = 0;
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr, STA_DON);
return SCPE_OK; }
f = GET_CMD (mt_cu); /* get command */
if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
mt_updcsta (uptr, STA_ILL); /* illegal operation */
return IORETURN (mt_stopioe, SCPE_UNATT); }
if ((f == FN_WRITE) || (f == FN_WREOF)) { /* write? */
if (uptr -> flags & UNIT_WPRT) { /* write locked? */
mt_updcsta (uptr, STA_ILL); /* illegal operation */
return SCPE_OK; }
mt_cu = mt_cu & ~CU_ERASE; } /* clear erase flag */
err = 0;
rval = SCPE_OK;
switch (f) { /* case on function */
/* Unit service, continued */
case FN_READ: /* read */
case FN_CMPARE: /* read/compare */
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
(feof (uptr -> fileref))) {
uptr -> USTAT = STA_EOT;
mt_updcsta (uptr, STA_RLE);
break; }
if (tbc == 0) { /* tape mark? */
uptr -> USTAT = STA_EOF;
mt_updcsta (uptr, STA_RLE);
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
break; }
tbc = MTRL (tbc); /* ignore error flag */
wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */
cbc = PACKED (mt_cu)? wc * 3: wc * 2; /* expected bc */
if (tbc != cbc) mt_sta = mt_sta | STA_RLE; /* wrong size? */
if (tbc < cbc) { /* record small? */
cbc = tbc; /* use smaller */
wc = PACKED (mt_cu)? ((tbc + 2) / 3): ((tbc + 1) / 2); }
i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref);
for ( ; i < cbc; i++) dbuf[i] = 0; /* fill with 0's */
err = ferror (uptr -> fileref);
for (i = p = 0; i < wc; i++) { /* copy buffer */
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
xma = M[MT_CA] & ADDRMASK;
if (PACKED (mt_cu)) { /* packed? */
c1 = dbuf[p++] & 077;
c2 = dbuf[p++] & 077;
c3 = dbuf[p++] & 077;
c = (c1 << 12) | (c2 << 6) | c3; }
else { c1 = dbuf[p++];
c2 = dbuf[p++];
c = (c1 << 8) | c2; }
if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
else if ((f == FN_CMPARE) && (c != (M[xma] &
(PACKED (mt_cu)? 0777777: 0177777)))) {
mt_updcsta (uptr, STA_CPE);
break; } }
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt));
break;
case FN_WRITE: /* write */
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */
tbc = PACKED (mt_cu)? wc * 3: wc * 2;
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
xma = M[MT_CA] & ADDRMASK;
if (PACKED (mt_cu)) { /* packed? */
dbuf[p++] = (M[xma] >> 12) & 077;
dbuf[p++] = (M[xma] >> 6) & 077;
dbuf[p++] = M[xma] & 077; }
else { dbuf[p++] = (M[xma] >> 8) & 0377;
dbuf[p++] = M[xma] & 0377; } }
fxwrite (dbuf, sizeof (char), (tbc + 1) & ~1, uptr -> fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
err = ferror (uptr -> fileref);
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt));
break;
/* Unit service, continued */
case FN_WREOF:
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);
uptr -> USTAT = STA_EOF;
break;
case FN_SPACEF: /* space forward */
do { fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read bc */
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
feof (uptr -> fileref)) {
uptr -> USTAT = STA_EOT;
break; }
if (tbc == 0) { /* zero bc? */
uptr -> USTAT = STA_EOF;
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
break; }
uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
break;
case FN_SPACER: /* space reverse */
if (uptr -> pos == 0) { /* at BOT? */
uptr -> USTAT = STA_BOT;
break; }
do { fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt),
SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
tbc = MTRL (tbc); /* ignore error flag */
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
feof (uptr -> fileref)) {
uptr -> USTAT = STA_BOT;
uptr -> pos = 0;
break; }
if (tbc == 0) { /* end of file? */
uptr -> USTAT = STA_EOF;
uptr -> pos = uptr -> pos - sizeof (t_mtrlnt);
break; }
uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt));
if (uptr -> pos == 0) { /* at BOT? */
uptr -> USTAT = STA_BOT;
break; } }
while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
break; } /* end case */
/* Unit service, continued */
if (err != 0) { /* I/O error */
mt_updcsta (uptr, STA_PAR); /* flag error */
perror ("MT I/O error");
rval = SCPE_IOERR;
clearerr (uptr -> fileref); }
mt_updcsta (uptr, STA_DON); /* set done */
return IORETURN (mt_stopioe, rval);
}
/* Update controller status */
int32 mt_updcsta (UNIT *uptr, int32 new)
{
mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) |
(uptr -> USTAT & STA_DYN) | new;
if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR; /* error flag */
if ((mt_sta & (STA_ERR | STA_DON)) && ((mt_cu & CU_IE) == 0))
SET_INT (MTA);
else CLR_INT (MTA); /* int request */
return mt_sta;
}
/* Test if controller busy */
UNIT *mt_busy (void)
{
int32 u;
UNIT *uptr;
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
uptr = mt_dev.units + u;
if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0))
return uptr; }
return NULL;
}
/* Reset routine */
t_stat mt_reset (DEVICE *dptr)
{
int32 u;
UNIT *uptr;
mt_cu = mt_sta = 0;
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
uptr = mt_dev.units + u;
uptr -> UNUM = u; /* init drive number */
sim_cancel (uptr); /* cancel activity */
if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
else uptr -> USTAT = 0; }
mt_updcsta (&mt_unit[0], 0); /* update status */
return SCPE_OK;
}
/* IORS routine */
int32 mt_iors (void)
{
return (mt_sta & (STA_ERR | STA_DON))? IOS_MTA: 0;
}
/* Attach routine */
t_stat mt_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
uptr -> USTAT = STA_BOT;
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return r;
}
/* Detach routine */
t_stat mt_detach (UNIT* uptr)
{
if (!sim_is_active (uptr)) uptr -> USTAT = 0;
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return detach_unit (uptr);
}

262
PDP18B/pdp18b_rf.c Normal file
View File

@@ -0,0 +1,262 @@
/* pdp18b_rf.c: fixed head disk simulator
Copyright (c) 1993-2001, 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.
rf (PDP-9) RF09/RF09
(PDP-15) RF15/RS09
25-Nov-01 RMS Revised interrupt structure
24-Nov-01 RMS Changed WLK to array
26-Apr-01 RMS Added device enable/disable support
15-Feb-01 RMS Fixed 3 cycle data break sequencing
30-Nov-99 RMS Added non-zero requirement to rf_time
14-Apr-99 RMS Changed t_addr to unsigned
The RFxx is a head-per-track disk. It uses the multicycle data break
facility. To minimize overhead, the entire RFxx is buffered in memory.
Two timing parameters are provided:
rf_time Interword timing. Must be non-zero.
rf_burst Burst mode. If 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst.
*/
#include "pdp18b_defs.h"
#include <math.h>
/* Constants */
#define RF_NUMWD 2048 /* words/track */
#define RF_NUMTR 128 /* tracks/disk */
#define RF_NUMDK 8 /* disks/controller */
#define RF_SIZE (RF_NUMDK * RF_NUMTR * RF_NUMWD) /* words/drive */
#define RF_WMASK (RF_NUMWD - 1) /* word mask */
#define RF_WC 036 /* word count */
#define RF_CA 037 /* current addr */
/* Function/status register */
#define RFS_ERR 0400000 /* error */
#define RFS_HDW 0200000 /* hardware error */
#define RFS_APE 0100000 /* addr parity error */
#define RFS_MXF 0040000 /* missed transfer */
#define RFS_WCE 0020000 /* write check error */
#define RFS_DPE 0010000 /* data parity error */
#define RFS_WLO 0004000 /* write lock error */
#define RFS_NED 0002000 /* non-existent disk */
#define RFS_DCH 0001000 /* data chan timing */
#define RFS_PGE 0000400 /* programming error */
#define RFS_DON 0000200 /* transfer complete */
#define RFS_V_FNC 1 /* function */
#define RFS_M_FNC 03
#define RFS_FNC (RFS_M_FNC << RFS_V_FNC)
#define FN_NOP 0
#define FN_READ 1
#define FN_WRITE 2
#define FN_WCHK 3
#define RFS_IE 0000001 /* interrupt enable */
#define RFS_CLR 0000170 /* always clear */
#define RFS_EFLGS (RFS_HDW | RFS_APE | RFS_MXF | RFS_WCE | \
RFS_DPE | RFS_WLO | RFS_NED ) /* error flags */
#define GET_FNC(x) (((x) >> RFS_V_FNC) & RFS_M_FNC)
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) RF_NUMWD)))
#define RF_BUSY (sim_is_active (&rf_unit))
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
int32 rf_dbuf = 0; /* data buffer */
int32 rf_wlk[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* write lock */
int32 rf_time = 10; /* inter-word time */
int32 rf_burst = 1; /* burst mode flag */
int32 rf_stopioe = 1; /* stop on error */
t_stat rf_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr);
int32 rf_updsta (int32 new);
/* RF data structures
rf_dev RF device descriptor
rf_unit RF unit descriptor
rf_reg RF register list
*/
UNIT rf_unit =
{ UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
RF_SIZE) };
REG rf_reg[] = {
{ ORDATA (STA, rf_sta, 18) },
{ ORDATA (DA, rf_da, 21) },
{ ORDATA (WC, M[RF_WC], 18) },
{ ORDATA (CA, M[RF_CA], 18) },
{ ORDATA (BUF, rf_dbuf, 18) },
{ FLDATA (INT, int_hwre[API_RF], INT_V_RF) },
{ BRDATA (WLK, rf_wlk, 8, 16, RF_NUMDK) },
{ DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO },
{ NULL } };
DEVICE rf_dev = {
"RF", &rf_unit, rf_reg, NULL,
1, 8, 21, 1, 8, 18,
NULL, NULL, &rf_reset,
NULL, NULL, NULL };
/* IOT routines */
int32 rf70 (int32 pulse, int32 AC)
{
int32 t;
if (pulse == 001) /* DSSF */
return (rf_sta & (RFS_ERR | RFS_DON))? IOT_SKP + AC: AC;
if (pulse == 021) rf_reset (&rf_dev); /* DSCC */
if ((pulse & 061) == 041) { /* DSCF */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else rf_sta = rf_sta & ~(RFS_FNC | RFS_IE); } /* clear func */
if (pulse == 002) { /* DRBR */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
return AC | rf_dbuf; }
if (pulse == 022) { /* DRAL */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
return rf_da & 0777777; }
if (pulse == 062) { /* DRAH */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
return (rf_da >> 18) | ((rf_sta & RFS_NED)? 010: 0); }
if ((pulse & 062) == 042) { /* DSFX */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else rf_sta = rf_sta ^ (AC & (RFS_FNC | RFS_IE)); } /* xor func */
if (pulse == 004) { /* DLBR */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else rf_dbuf = AC; }
if (pulse == 024) { /* DLAL */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else rf_da = (rf_da & ~0777777) | AC; }
if (pulse == 064) { /* DLAH */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else rf_da = (rf_da & 0777777) | ((AC & 07) << 18); }
if ((pulse & 064) == 044) { /* DSCN */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else if (GET_FNC (rf_sta) != FN_NOP) {
t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new */
if (t < 0) t = t + RF_NUMWD; /* wrap around? */
sim_activate (&rf_unit, t * rf_time); } } /* schedule op */
rf_updsta (0); /* update status */
return AC;
}
int32 rf72 (int32 pulse, int32 AC)
{
if (pulse == 002) return AC | GET_POS (rf_time) | /* DLOK */
(sim_is_active (&rf_unit)? 0400000: 0);
if (pulse == 042) { /* DSCD */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
else rf_sta = 0;
rf_updsta (0); }
if (pulse == 062) { /* DSRS */
if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
return rf_updsta (0); }
return AC;
}
/* Unit service
This code assumes the entire disk is buffered.
*/
t_stat rf_svc (UNIT *uptr)
{
int32 f, pa, d, t;
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
rf_updsta (RFS_NED | RFS_DON); /* set nxd, done */
return IORETURN (rf_stopioe, SCPE_UNATT); }
f = GET_FNC (rf_sta); /* get function */
do { M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */
pa = M[RF_CA] = (M[RF_CA] + 1) & ADDRMASK; /* incr mem addr */
if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */
M[pa] = *(((int32 *) uptr -> filebuf) + rf_da);
if ((f == FN_WCHK) && /* write check? */
(M[pa] != *(((int32 *) uptr -> filebuf) + rf_da))) {
rf_updsta (RFS_WCE); /* flag error */
break; }
if (f == FN_WRITE) { /* write? */
d = (rf_da >> 18) & 07; /* disk */
t = (rf_da >> 14) & 017; /* track groups */
if ((rf_wlk[d] >> t) & 1) { /* write locked? */
rf_updsta (RFS_WLO);
break; }
else { *(((int32 *) uptr -> filebuf) + rf_da) = M[pa];
if (((t_addr) rf_da) >= uptr -> hwmark)
uptr -> hwmark = rf_da + 1; } }
rf_da = rf_da + 1; /* incr disk addr */
if (rf_da > RF_SIZE) { /* disk overflow? */
rf_da = 0;
rf_updsta (RFS_NED); /* nx disk error */
break; } }
while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
sim_activate (&rf_unit, rf_time); /* sched next */
else rf_updsta (RFS_DON);
return SCPE_OK;
}
/* Update status */
int32 rf_updsta (int32 new)
{
rf_sta = (rf_sta | new) & ~(RFS_ERR | RFS_CLR);
if (rf_sta & RFS_EFLGS) rf_sta = rf_sta | RFS_ERR;
if ((rf_sta & (RFS_ERR | RFS_DON)) && (rf_sta & RFS_IE))
SET_INT (RF);
else CLR_INT (RF);
return rf_sta;
}
/* Reset routine */
t_stat rf_reset (DEVICE *dptr)
{
rf_sta = rf_da = rf_dbuf = 0;
rf_updsta (0);
sim_cancel (&rf_unit);
return SCPE_OK;
}
/* IORS routine */
int32 rf_iors (void)
{
return ((rf_sta & (RFS_ERR | RFS_DON))? IOS_RF: 0);
}

435
PDP18B/pdp18b_rp.c Normal file
View File

@@ -0,0 +1,435 @@
/* pdp18b_rp.c: RP15/RP02 disk pack simulator
Copyright (c) 1993-2001, 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.
rp RP15/RP02 disk pack
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
Changed FLG to array
26-Apr-01 RMS Added device enable/disable support
14-Apr-99 RMS Changed t_addr to unsigned
29-Jun-96 RMS Added unit enable/disable support
*/
#include "pdp18b_defs.h"
/* Constants */
#define RP_NUMWD 256 /* words/sector */
#define RP_NUMSC 10 /* sectors/surface */
#define RP_NUMSF 20 /* surfaces/cylinder */
#define RP_NUMCY 203 /* cylinders/drive */
#define RP_NUMDR 8 /* drives/controller */
#define RP_SIZE (RP_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD) /* words/drive */
/* Unit specific flags */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_W_UF 2 /* user flags width */
#define UNIT_WLK (1u << UNIT_V_WLK)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Parameters in the unit descriptor */
#define CYL u3 /* current cylinder */
#define FUNC u4 /* function */
/* Status register A */
#define STA_V_UNIT 15 /* unit select */
#define STA_M_UNIT 07
#define STA_V_FUNC 12 /* function */
#define STA_M_FUNC 07
#define FN_IDLE 0
#define FN_READ 1
#define FN_WRITE 2
#define FN_RECAL 3
#define FN_SEEK 4
#define FN_RDALL 5
#define FN_WRALL 6
#define FN_WRCHK 7
#define FN_2ND 010 /* second state flag */
#define STA_IED 0004000 /* int enable done */
#define STA_IEA 0002000 /* int enable attn */
#define STA_GO 0001000 /* go */
#define STA_WPE 0000400 /* write lock error */
#define STA_NXC 0000200 /* nx cyl error */
#define STA_NXF 0000100 /* nx surface error */
#define STA_NXS 0000040 /* nx sector error */
#define STA_HNF 0000020 /* hdr not found */
#define STA_SUWP 0000010 /* sel unit wrt lock */
#define STA_SUSI 0000004 /* sel unit seek inc */
#define STA_DON 0000002 /* done */
#define STA_ERR 0000001 /* error */
#define STA_RW 0777000 /* read/write */
#define STA_EFLGS (STA_WPE | STA_NXC | STA_NXF | STA_NXS | \
STA_HNF | STA_SUSI) /* error flags */
#define STA_DYN (STA_SUWP | STA_SUSI) /* per unit status */
#define GET_UNIT(x) (((x) >> STA_V_UNIT) & STA_M_UNIT)
#define GET_FUNC(x) (((x) >> STA_V_FUNC) & STA_M_FUNC)
/* Status register B */
#define STB_V_ATT0 17 /* unit 0 attention */
#define STB_ATTN 0776000 /* attention flags */
#define STB_SUFU 0001000 /* sel unit unsafe */
#define STB_PGE 0000400 /* programming error */
#define STB_EOP 0000200 /* end of pack */
#define STB_TME 0000100 /* timing error */
#define STB_FME 0000040 /* format error */
#define STB_WCE 0000020 /* write check error */
#define STB_WPE 0000010 /* word parity error */
#define STB_LON 0000004 /* long parity error */
#define STB_SUSU 0000002 /* sel unit seeking */
#define STB_SUNR 0000001 /* sel unit not rdy */
#define STB_EFLGS (STB_SUFU | STB_PGE | STB_EOP | STB_TME | STB_FME | \
STB_WCE | STB_WPE | STB_LON ) /* error flags */
#define STB_DYN (STB_SUFU | STB_SUSU | STB_SUNR) /* per unit */
/* Disk address */
#define DA_V_SECT 0 /* sector */
#define DA_M_SECT 017
#define DA_V_SURF 5
#define DA_M_SURF 037
#define DA_V_CYL 10 /* cylinder */
#define DA_M_CYL 0377
#define GET_SECT(x) (((x) >> DA_V_SECT) & DA_M_SECT)
#define GET_SURF(x) (((x) >> DA_V_SURF) & DA_M_SURF)
#define GET_CYL(x) (((x) >> DA_V_CYL) & DA_M_CYL)
#define GET_DA(x) ((((GET_CYL (x) * RP_NUMSF) + GET_SURF (x)) * \
RP_NUMSC) + GET_SECT (x))
#define RP_MIN 2
#define MAX(x,y) (((x) > (y))? (x): (y))
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb, nexm;
extern UNIT cpu_unit;
int32 rp_sta = 0; /* status A */
int32 rp_stb = 0; /* status B */
int32 rp_ma = 0; /* memory address */
int32 rp_da = 0; /* disk address */
int32 rp_wc = 0; /* word count */
int32 rp_busy = 0; /* busy */
int32 rp_stopioe = 1; /* stop on error */
int32 rp_swait = 10; /* seek time */
int32 rp_rwait = 10; /* rotate time */
t_stat rp_svc (UNIT *uptr);
void rp_updsta (int32 newa, int32 newb);
t_stat rp_reset (DEVICE *dptr);
t_stat rp_attach (UNIT *uptr, char *cptr);
t_stat rp_detach (UNIT *uptr);
/* RP15 data structures
rp_dev RP device descriptor
rp_unit RP unit list
rp_reg RP register list
rp_mod RP modifier list
*/
UNIT rp_unit[] = {
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) } };
REG rp_reg[] = {
{ ORDATA (STA, rp_sta, 18) },
{ ORDATA (STB, rp_stb, 18) },
{ ORDATA (DA, rp_da, 18) },
{ ORDATA (MA, rp_ma, 18) },
{ ORDATA (WC, rp_wc, 18) },
{ FLDATA (INT, int_hwre[API_RP], INT_V_RP) },
{ FLDATA (BUSY, rp_busy, 0) },
{ FLDATA (STOP_IOE, rp_stopioe, 0) },
{ DRDATA (STIME, rp_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rp_rwait, 24), PV_LEFT },
{ URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
RP_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO },
{ NULL } };
MTAB rp_mod[] = {
{ UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ 0 } };
DEVICE rp_dev = {
"RP", rp_unit, rp_reg, rp_mod,
RP_NUMDR, 8, 24, 1, 8, 18,
NULL, NULL, &rp_reset,
NULL, &rp_attach, &rp_detach };
/* IOT routines */
int32 rp63 (int32 pulse, int32 AC)
{
rp_updsta (0, 0);
if (pulse == 001) /* DPSF */
return ((rp_sta & (STA_DON | STA_ERR)) || (rp_stb & STB_ATTN))?
IOT_SKP + AC: AC;
if (pulse == 021) /* DPSA */
return (rp_stb & STB_ATTN)? IOT_SKP + AC: AC;
if (pulse == 041) /* DPSJ */
return (rp_sta & STA_DON)? IOT_SKP + AC: AC;
if (pulse == 061) /* DPSE */
return (rp_sta & STA_ERR)? IOT_SKP + AC: AC;
if (pulse == 002) return rp_sta; /* DPOSA */
if (pulse == 022) return rp_stb; /* DPOSB */
if (((pulse & 007) == 004) && rp_busy) { /* busy? */
rp_updsta (0, STB_PGE);
return AC; }
if (pulse == 004) { /* DPLA */
rp_da = AC;
if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0);
if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0);
if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0); }
if (pulse == 024) { /* DPCS */
rp_sta = rp_sta & ~(STA_HNF | STA_DON);
rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE |
STB_TME | STB_PGE | STB_EOP);
rp_updsta (0, 0); }
if (pulse == 044) rp_ma = AC; /* DPCA */
if (pulse == 064) rp_wc = AC; /* DPWC */
return AC;
}
/* IOT 64 */
int32 rp64 (int32 pulse, int32 AC)
{
int32 u, f, c;
UNIT *uptr;
if (pulse == 021) return IOT_SKP + AC; /* DPSN */
if (pulse == 002) return rp_unit[GET_UNIT (rp_sta)].CYL; /* DPOU */
if (pulse == 022) return rp_da; /* DPOA */
if (pulse == 042) return rp_ma; /* DPOC */
if (pulse == 062) return rp_wc; /* DPOW */
if ((pulse & 007) != 004) return AC;
if (rp_busy) { /* busy? */
rp_updsta (0, STB_PGE);
return AC; }
if (pulse == 004) rp_sta = rp_sta & ~STA_RW; /* DPCF */
if (pulse == 024) rp_sta = rp_sta & (AC | ~STA_RW); /* DPLZ */
if (pulse == 044) rp_sta = rp_sta | (AC & STA_RW); /* DPLO */
if (pulse == 064) rp_sta = (rp_sta & ~STA_RW) | (AC & STA_RW); /* DPLF */
if (rp_sta & STA_GO) {
u = GET_UNIT (rp_sta); /* get unit num */
uptr = rp_dev.units + u; /* select unit */
if (sim_is_active (uptr)) return AC; /* can't if busy */
f = uptr -> FUNC = GET_FUNC (rp_sta); /* get function */
rp_busy = 1; /* set ctrl busy */
rp_sta = rp_sta & ~(STA_HNF | STA_DON); /* clear flags */
rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE |
STB_TME | STB_PGE | STB_EOP | (1 << (STB_V_ATT0 - u)));
if (((uptr -> flags & UNIT_ATT) == 0) || (f == FN_IDLE) ||
(f == FN_SEEK) || (f == FN_RECAL))
sim_activate (uptr, RP_MIN); /* short delay */
else { c = GET_CYL (rp_da);
c = abs (c - uptr -> CYL) * rp_swait; /* seek time */
sim_activate (uptr, MAX (RP_MIN, c + rp_rwait)); } }
rp_updsta (0, 0);
return AC;
}
/* Unit service
If function = idle, clear busy
If seek or recal initial state, clear attention line, compute seek time,
put on cylinder, set second state
If unit not attached, give error
If seek or recal second state, set attention line, compute errors
Else complete data transfer command
The unit control block contains the function and cylinder for
the current command.
*/
static int32 fill[RP_NUMWD] = { 0 };
t_stat rp_svc (UNIT *uptr)
{
int32 f, u, comp, cyl, sect, surf;
int32 err, pa, da, wc, awc, i;
u = uptr - rp_dev.units; /* get drv number */
f = uptr -> FUNC; /* get function */
if (f == FN_IDLE) { /* idle? */
rp_busy = 0; /* clear busy */
return SCPE_OK; }
if ((f == FN_SEEK) || (f == FN_RECAL)) { /* seek or recal? */
rp_busy = 0; /* not busy */
cyl = (f == FN_SEEK)? GET_CYL (rp_da): 0; /* get cylinder */
sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr -> CYL) * rp_swait));
uptr -> CYL = cyl; /* on cylinder */
uptr -> FUNC = FN_SEEK | FN_2ND; /* set second state */
rp_updsta (0, 0); /* update status */
return SCPE_OK; }
if (f == (FN_SEEK | FN_2ND)) { /* seek done? */
rp_updsta (0, rp_stb | (1 << (STB_V_ATT0 - u))); /* set attention */
return SCPE_OK; }
if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */
rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */
return IORETURN (rp_stopioe, SCPE_UNATT); }
if ((f == FN_WRITE) && (uptr -> flags & UNIT_WPRT)) { /* write locked? */
rp_updsta (STA_DON | STA_WPE, 0); /* error */
return SCPE_OK; }
if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0);
if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0);
if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0);
if (rp_sta & (STA_NXS | STA_NXF | STA_NXC)) { /* or bad disk addr? */
rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */
return SCPE_OK; }
pa = rp_ma & ADDRMASK; /* get mem addr */
da = GET_DA (rp_da) * RP_NUMWD; /* get disk addr */
wc = 01000000 - rp_wc; /* get true wc */
if (((t_addr) (pa + wc)) > MEMSIZE) { /* memory overrun? */
nexm = 1; /* set nexm flag */
wc = MEMSIZE - pa; } /* limit xfer */
if ((da + wc) > RP_SIZE) { /* disk overrun? */
rp_updsta (0, STB_EOP); /* error */
wc = RP_SIZE - da; } /* limit xfer */
err = fseek (uptr -> fileref, da * sizeof (int), SEEK_SET);
if ((f == FN_READ) && (err == 0)) { /* read? */
awc = fxread (&M[pa], sizeof (int32), wc, uptr -> fileref);
for ( ; awc < wc; awc++) M[pa + awc] = 0;
err = ferror (uptr -> fileref); }
if ((f == FN_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int32), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
if ((err == 0) && (i = (wc & (RP_NUMWD - 1)))) {
fxwrite (fill, sizeof (int), i, uptr -> fileref);
err = ferror (uptr -> fileref); } }
if ((f == FN_WRCHK) && (err == 0)) { /* write check? */
for (i = 0; (err == 0) && (i < wc); i++) {
awc = fxread (&comp, sizeof (int32), 1, uptr -> fileref);
if (awc == 0) comp = 0;
if (comp != M[pa + i]) rp_updsta (0, STB_WCE); }
err = ferror (uptr -> fileref); }
rp_wc = (rp_wc + wc) & 0777777; /* final word count */
rp_ma = (rp_ma + wc) & 0777777; /* final mem addr */
da = (da + wc + (RP_NUMWD - 1)) / RP_NUMWD; /* final sector num */
cyl = da / (RP_NUMSC * RP_NUMSF); /* get cyl */
if (cyl >= RP_NUMCY) cyl = RP_NUMCY - 1;
surf = (da % (RP_NUMSC * RP_NUMSF)) / RP_NUMSC; /* get surface */
sect = (da % (RP_NUMSC * RP_NUMSF)) % RP_NUMSC; /* get sector */
rp_da = (cyl << DA_V_CYL) | (surf << DA_V_SURF) | (sect << DA_V_SECT);
rp_busy = 0; /* clear busy */
rp_updsta (STA_DON, 0); /* set done */
if (err != 0) { /* error? */
perror ("RP I/O error");
clearerr (uptr -> fileref);
return IORETURN (rp_stopioe, SCPE_IOERR); }
return SCPE_OK;
}
/* Update status */
void rp_updsta (int32 newa, int32 newb)
{
int32 f;
UNIT *uptr;
uptr = rp_dev.units + GET_UNIT (rp_sta);
rp_sta = (rp_sta & ~(STA_DYN | STA_ERR)) | newa;
rp_stb = (rp_stb & ~STB_DYN) | newb;
if (uptr -> flags & UNIT_WPRT) rp_sta = rp_sta | STA_SUWP;
if ((uptr -> flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR;
else if (sim_is_active (uptr)) {
f = (uptr -> FUNC) & STA_M_FUNC;
if ((f == FN_SEEK) || (f == FN_RECAL))
rp_stb = rp_stb | STB_SUSU | STB_SUNR; }
else if (uptr -> CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI;
if ((rp_sta & STA_EFLGS) || (rp_stb & STB_EFLGS)) rp_sta = rp_sta | STA_ERR;
if (((rp_sta & (STA_ERR | STA_DON)) && (rp_sta & STA_IED)) ||
((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) SET_INT (RP);
else CLR_INT (RP);
return;
}
/* Reset routine */
t_stat rp_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;
rp_sta = rp_stb = rp_da = rp_wc = rp_ma = rp_busy = 0;
CLR_INT (RP);
for (i = 0; i < RP_NUMDR; i++) {
uptr = rp_dev.units + i;
sim_cancel (uptr);
uptr -> CYL = uptr -> FUNC = 0; }
return SCPE_OK;
}
/* IORS routine */
int32 rp_iors (void)
{
return ((rp_sta & (STA_ERR | STA_DON)) || (rp_stb & STB_ATTN))? IOS_RP: 0;
}
/* Attach unit */
t_stat rp_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
rp_updsta (0, 0);
return reason;
}
/* Detach unit */
t_stat rp_detach (UNIT *uptr)
{
t_stat reason;
reason = detach_unit (uptr);
rp_updsta (0, 0);
return reason;
}

775
PDP18B/pdp18b_stddev.c Normal file
View File

@@ -0,0 +1,775 @@
/* pdp18b_stddev.c: 18b PDP's standard devices
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ptr paper tape reader
ptp paper tape punch
tti keyboard
tto teleprinter
clk clock
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
17-Sep-01 RMS Removed multiconsole support
07-Sep-01 RMS Added terminal multiplexor support
17-Jul-01 RMS Moved function prototype
10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware
27-May-01 RMS Added multiconsole support
10-Mar-01 RMS Added funny format loader support
05-Mar-01 RMS Added clock calibration support
22-Dec-00 RMS Added PDP-9/15 half duplex support
30-Nov-00 RMS Fixed PDP-4/7 bootstrap loader for 4K systems
30-Oct-00 RMS Standardized register naming
06-Jan-97 RMS Fixed PDP-4 console input
16-Dec-96 RMS Fixed bug in binary ptr service
*/
#include "pdp18b_defs.h"
#include <ctype.h>
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], saved_PC;
extern UNIT cpu_unit;
int32 clk_state = 0;
int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0;
int32 ptp_err = 0, ptp_stopioe = 0;
int32 tti_state = 0;
int32 tto_state = 0;
int32 clk_tps = 60; /* ticks/second */
int32 tmxr_poll = 16000; /* term mux poll */
t_stat clk_svc (UNIT *uptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat ptr_attach (UNIT *uptr, char *cptr);
t_stat ptp_attach (UNIT *uptr, char *cptr);
t_stat ptr_detach (UNIT *uptr);
t_stat ptp_detach (UNIT *uptr);
t_stat ptr_boot (int32 unitno);
/* CLK data structures
clk_dev CLK device descriptor
clk_unit CLK unit
clk_reg CLK register list
*/
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (INT, int_hwre[API_CLK], INT_V_CLK) },
{ FLDATA (DONE, int_hwre[API_CLK], INT_V_CLK) },
{ FLDATA (ENABLE, clk_state, 0) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
{ NULL } };
DEVICE clk_dev = {
"CLK", &clk_unit, clk_reg, NULL,
1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset,
NULL, NULL, NULL };
/* PTR data structures
ptr_dev PTR device descriptor
ptr_unit PTR unit
ptr_reg PTR register list
*/
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 18) },
{ FLDATA (INT, int_hwre[API_PTR], INT_V_PTR) },
{ FLDATA (DONE, int_hwre[API_PTR], INT_V_PTR) },
#if defined (IOS_PTRERR)
{ FLDATA (ERR, ptr_err, 0) },
#endif
{ ORDATA (STATE, ptr_state, 5), REG_HRO },
{ DRDATA (POS, ptr_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ NULL } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, &ptr_attach, &ptr_detach };
/* PTP data structures
ptp_dev PTP device descriptor
ptp_unit PTP unit
ptp_reg PTP register list
*/
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_PTP], INT_V_PTP) },
{ FLDATA (DONE, int_hwre[API_PTP], INT_V_PTP) },
#if defined (IOS_PTPERR)
{ FLDATA (ERR, ptp_err, 0) },
#endif
{ DRDATA (POS, ptp_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ NULL } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, &ptp_attach, &ptp_detach };
/* TTI data structures
tti_dev TTI device descriptor
tti_unit TTI unit
tti_reg TTI register list
tti_trans ASCII to Baudot table
*/
#if defined (KSR28)
#define TTI_WIDTH 5
#define TTI_FIGURES (1 << TTI_WIDTH)
#define TTI_2ND (1 << (TTI_WIDTH + 1))
#define TTI_BOTH (1 << (TTI_WIDTH + 2))
#define BAUDOT_LETTERS 033
#define BAUDOT_FIGURES 037
static const int32 tti_trans[128] = {
000,000,000,000,000,000,000,064, /* bell */
000,000,0210,000,000,0202,000,000, /* lf, cr */
000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,
0204,066,061,045,062,000,053,072, /* space - ' */
076,051,000,000,046,070,047,067, /* ( - / */
055,075,071,060,052,041,065,074, /* 0 - 7 */
054,043,056,057,000,000,000,063, /* 8 - ? */
000,030,023,016,022,020,026,013, /* @ - G */
005,014,032,036,011,007,006,003, /* H - O */
015,035,012,024,001,034,017,031, /* P - W */
027,025,021,000,000,000,000,000, /* X - _ */
000,030,023,016,022,020,026,013, /* ` - g */
005,014,032,036,011,007,006,003, /* h - o */
015,035,012,024,001,034,017,031, /* p - w */
027,025,021,000,000,000,000,000 }; /* x - DEL */
#else
#define TTI_WIDTH 8
#endif
#define TTI_MASK ((1 << TTI_WIDTH) - 1)
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
#define UNIT_V_HDX (UNIT_V_UF + 1) /* half duplex */
#define UNIT_HDX (1 << UNIT_V_HDX)
#if defined (PDP4) || defined (PDP7)
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT };
#else
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX, 0), KBD_POLL_WAIT };
#endif
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, TTI_WIDTH) },
{ FLDATA (INT, int_hwre[API_TTI], INT_V_TTI) },
{ FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) },
#if defined (KSR28)
{ ORDATA (TTI_STATE, tti_state, (TTI_WIDTH + 3)), REG_HRO },
#else
{ FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO },
{ FLDATA (HDX, tti_unit.flags, UNIT_V_HDX), REG_HRO },
#endif
{ DRDATA (POS, tti_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL } };
MTAB tti_mod[] = {
#if !defined (KSR28)
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_HDX, 0, "full duplex", "FDX", NULL },
{ UNIT_HDX, UNIT_HDX, "half duplex", "HDX", NULL },
#endif
{ 0 } };
DEVICE tti_dev = {
"TTI", &tti_unit, tti_reg, tti_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti_reset,
NULL, NULL, NULL };
/* TTO data structures
tto_dev TTO device descriptor
tto_unit TTO unit
tto_reg TTO register list
tto_trans Baudot to ASCII table
*/
#if defined (KSR28)
#define TTO_WIDTH 5
#define TTO_FIGURES (1 << TTO_WIDTH)
static const char tto_trans[64] = {
0 ,'T',015,'O',' ','H','N','M',
012,'L','R','G','I','P','C','V',
'E','Z','D','B','S','Y','F','X',
'A','W','J', 0 ,'U','Q','K', 0,
0 ,'5','\r','9',' ','#',',','.',
012,')','4','&','8','0',':',';',
'3','"','$','?','\a','6','!','/',
'-','2','\'',0 ,'7','1','(', 0 };
#else
#define TTO_WIDTH 8
#endif
#define TTO_MASK ((1 << TTO_WIDTH) - 1)
UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
{ FLDATA (INT, int_hwre[API_TTO], INT_V_TTO) },
{ FLDATA (DONE, int_hwre[API_TTO], INT_V_TTO) },
#if defined (KSR28)
{ FLDATA (TTO_STATE, tto_state, 0), REG_HRO },
#endif
{ DRDATA (POS, tto_unit.pos, 31), PV_LEFT },
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
{ NULL } };
MTAB tto_mod[] = {
#if !defined (KSR28)
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
#endif
{ 0 } };
DEVICE tto_dev = {
"TTO", &tto_unit, tto_reg, tto_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto_reset,
NULL, NULL, NULL };
/* Clock: IOT routine */
int32 clk (int32 pulse, int32 AC)
{
if (pulse & 001) { /* CLSF */
if (TST_INT (CLK)) AC = AC | IOT_SKP; }
if (pulse & 004) { /* CLON/CLOF */
if (pulse & 040) { /* CLON */
CLR_INT (CLK); /* clear flag */
clk_state = 1; /* clock on */
if (!sim_is_active (&clk_unit)) /* already on? */
sim_activate (&clk_unit, /* start, calibr */
sim_rtc_init (clk_unit.wait)); }
else clk_reset (&clk_dev); } /* CLOF */
return AC;
}
/* Unit service */
t_stat clk_svc (UNIT *uptr)
{
int32 t;
if (clk_state) { /* clock on? */
M[7] = (M[7] + 1) & 0777777; /* incr counter */
if (M[7] == 0) SET_INT (CLK); /* ovrflo? set flag */
t = sim_rtc_calb (clk_tps); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
tmxr_poll = t; } /* set mux poll */
return SCPE_OK;
}
/* Reset routine */
t_stat clk_reset (DEVICE *dptr)
{
CLR_INT (CLK); /* clear flag */
clk_state = 0; /* clock off */
sim_cancel (&clk_unit); /* stop clock */
tmxr_poll = clk_unit.wait; /* set mux poll */
return SCPE_OK;
}
/* IORS service for all standard devices */
int32 std_iors (void)
{
return ((TST_INT (CLK)? IOS_CLK: 0) |
(TST_INT (PTR)? IOS_PTR: 0) |
(TST_INT (PTP)? IOS_PTP: 0) |
(TST_INT (TTI)? IOS_TTI: 0) |
(TST_INT (TTO)? IOS_TTO: 0) |
#if defined (IOS_PTRERR)
(ptr_err? IOS_PTRERR: 0) |
#endif
#if defined (IOS_PTPERR)
(ptp_err? IOS_PTPERR: 0) |
#endif
(clk_state? IOS_CLKON: 0));
}
/* Paper tape reader: IOT routine */
int32 ptr (int32 pulse, int32 AC)
{
if (pulse & 001) { /* RSF */
if (TST_INT (PTR)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* RRB, RCF */
CLR_INT (PTR); /* clear done */
AC = AC | ptr_unit.buf; } /* return buffer */
if (pulse & 004) { /* RSA, RSB */
ptr_state = (pulse & 040)? 18: 0; /* set mode */
CLR_INT (PTR); /* clear done */
ptr_unit.buf = 0; /* clear buffer */
sim_activate (&ptr_unit, ptr_unit.wait); }
return AC;
}
/* Unit service */
t_stat ptr_svc (UNIT *uptr)
{
int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */
#if defined (IOS_PTRERR)
SET_INT (PTR); /* if err, set int */
ptr_err = 1;
#endif
return IORETURN (ptr_stopioe, SCPE_UNATT); }
if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */
#if defined (IOS_PTRERR)
SET_INT (PTR); /* if err, set done */
ptr_err = 1;
#endif
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
if (ptr_state == 0) ptr_unit.buf = temp & 0377; /* alpha */
else if (temp & 0200) { /* binary */
ptr_state = ptr_state - 6;
ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); }
if (ptr_state == 0) SET_INT (PTR); /* if done, set flag */
else sim_activate (&ptr_unit, ptr_unit.wait); /* else restart */
ptr_unit.pos = ptr_unit.pos + 1;
return SCPE_OK;
}
/* Reset routine */
t_stat ptr_reset (DEVICE *dptr)
{
ptr_state = 0; /* clear state */
ptr_unit.buf = 0;
CLR_INT (PTR); /* clear flag */
ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1;
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
/* Attach routine */
t_stat ptr_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1;
return reason;
}
/* Detach routine */
t_stat ptr_detach (UNIT *uptr)
{
ptr_err = 1;
return detach_unit (uptr);
}
#if defined (PDP4) || defined (PDP7)
/* Bootstrap routine, PDP-4 and PDP-7
In a 4K system, the boostrap resides at 7762-7776.
In an 8K or greater system, the bootstrap resides at 17762-17776.
Because the program is so small, simple masking can be
used to remove addr<5> for a 4K system.
*/
#define BOOT_START 017577
#define BOOT_FPC 017577
#define BOOT_RPC 017770
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
static const int32 boot_rom[] = {
0700144, /* rsb */
0117762, /* ff, jsb r1b */
0057666, /* dac done 1 */
0117762, /* jms r1b */
0057667, /* dac done 2 */
0117762, /* jms r1b */
0040007, /* dac conend */
0057731, /* dac conbeg */
0440007, /* isz conend */
0117762, /* blk, jms r1b */
0057673, /* dac cai */
0741100, /* spa */
0617665, /* jmp done */
0117762, /* jms r1b */
0057777, /* dac tem1 */
0317673, /* add cai */
0057775, /* dac cks */
0117713, /* jms r1a */
0140010, /* dzm word */
0457777, /* cont, isz tem1 */
0617632, /* jmp cont1 */
0217775, /* lac cks */
0740001, /* cma */
0740200, /* sza */
0740040, /* hlt */
0700144, /* rsb */
0617610, /* jmp blk */
0117713, /* cont1, jms r1a */
0057762, /* dac tem2 */
0117713, /* jms r1a */
0742010, /* rtl */
0742010, /* rtl */
0742010, /* rtl */
0742010, /* rtl */
0317762, /* add tem2 */
0057762, /* dac tem2 */
0117713, /* jms r1a */
0742020, /* rtr */
0317726, /* add cdsp */
0057713, /* dac r1a */
0517701, /* and ccma */
0740020, /* rar */
0317762, /* add tem2 */
0437713, /* xct i r1a */
0617622, /* jmp cont */
0617672, /* dsptch, jmp code0 */
0617670, /* jmp code1 */
0617700, /* jmp code2 */
0617706, /* jmp code3 */
0417711, /* xct code4 */
0617732, /* jmp const */
0740000, /* nop */
0740000, /* nop */
0740000, /* nop */
0200007, /* done, lac conend */
0740040, /* xx */
0740040, /* xx */
0517727, /* code1, and imsk */
0337762, /* add i tem2 */
0300010, /* code0, add word */
0740040, /* cai, xx */
0750001, /* clc */
0357673, /* tad cai */
0057673, /* dac cai */
0617621, /* jmp cont-1 */
0711101, /* code2, spa cla */
0740001, /* ccma, cma */
0277762, /* xor i tem2 */
0300010, /* add word */
0040010, /* code2a, dac word */
0617622, /* jmp cont */
0057711, /* code3, dac code4 */
0217673, /* lac cai */
0357701, /* tad ccma */
0740040, /* code4, xx */
0617622, /* jmp cont */
0000000, /* r1a, 0 */
0700101, /* rsf */
0617714, /* jmp .-1 */
0700112, /* rrb */
0700104, /* rsa */
0057730, /* dac tem */
0317775, /* add cks */
0057775, /* dac cks */
0217730, /* lac tem */
0744000, /* cll */
0637713, /* jmp i r1a */
0017654, /* cdsp, dsptch */
0760000, /* imsk, 760000 */
0000000, /* tem, 0 */
0000000, /* conbeg, 0 */
0300010, /* const, add word */
0060007, /* dac i conend */
0217731, /* lac conbeg */
0040010, /* dac index */
0220007, /* lac i conend */
0560010, /* con1, sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0560010, /* sad i index */
0617752, /* jmp find */
0617737, /* jmp con1 */
0200010, /* find, lac index */
0540007, /* sad conend */
0440007, /* isz conend */
0617704, /* jmp code2a */
0000000,
0000000,
0000000,
0000000,
0000000, /* r1b, 0 */
0700101, /* rsf */
0617763, /* jmp .-1 */
0700112, /* rrb */
0700144, /* rsb */
0637762, /* jmp i r1b */
0700144, /* go, rsb */
0117762, /* g, jms r1b */
0057775, /* dac cks */
0417775, /* xct cks */
0117762, /* jms r1b */
0000000, /* cks, 0 */
0617771 /* jmp g */
};
t_stat ptr_boot (int32 unitno)
{
int32 i, mask, wd;
extern int32 sim_switches;
if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
else mask = 0777777;
for (i = 0; i < BOOT_LEN; i++) {
wd = boot_rom[i];
if ((wd >= 0040000) && (wd < 0640000)) wd = wd & mask;
M[(BOOT_START & mask) + i] = wd; }
saved_PC = ((sim_switches & SWMASK ('F'))? BOOT_FPC: BOOT_RPC) & mask;
return SCPE_OK;
}
#else
/* PDP-9 and PDP-15 have built-in hardware RIM loaders */
t_stat ptr_boot (int32 unitno)
{
return SCPE_ARG;
}
#endif
/* Paper tape punch: IOT routine */
int32 ptp (int32 pulse, int32 AC)
{
if (pulse & 001) { /* PSF */
if (TST_INT (PTP)) AC = AC | IOT_SKP; }
if (pulse & 002) CLR_INT (PTP); /* PCF */
if (pulse & 004) { /* PSA, PSB, PLS */
CLR_INT (PTP); /* clear flag */
ptp_unit.buf = (pulse & 040)? /* load punch buf */
(AC & 077) | 0200: AC & 0377; /* bin or alpha */
sim_activate (&ptp_unit, ptp_unit.wait); } /* activate unit */
return AC;
}
/* Unit service */
t_stat ptp_svc (UNIT *uptr)
{
SET_INT (PTP); /* set done flag */
if ((ptp_unit.flags & UNIT_ATT) == 0) { /* not attached? */
ptp_err = 1; /* set error */
return IORETURN (ptp_stopioe, SCPE_UNATT); }
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */
ptp_err = 1; /* set error */
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
return SCPE_IOERR; }
ptp_unit.pos = ptp_unit.pos + 1;
return SCPE_OK;
}
/* Reset routine */
t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
CLR_INT (PTP); /* clear flag */
ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1;
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
/* Attach routine */
t_stat ptp_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr);
ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1;
return reason;
}
/* Detach routine */
t_stat ptp_detach (UNIT *uptr)
{
ptp_err = 1;
return detach_unit (uptr);
}
/* Terminal input: IOT routine */
int32 tti (int32 pulse, int32 AC)
{
if (pulse & 001) { /* KSF */
if (TST_INT (TTI)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* KRB */
CLR_INT (TTI); /* clear flag */
AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */
return AC;
}
/* Unit service */
t_stat tti_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
#if defined (KSR28) /* Baudot... */
if (tti_state & TTI_2ND) { /* char waiting? */
tti_unit.buf = tti_state & TTI_MASK; /* return char */
tti_state = tti_state & ~TTI_2ND; } /* not waiting */
else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;
temp = tti_trans[temp & 0177]; /* translate char */
if (temp == 0) return SCPE_OK; /* untranslatable? */
if (((temp & TTI_FIGURES) == (tti_state & TTI_FIGURES)) ||
(temp & TTI_BOTH)) tti_unit.buf = temp & TTI_MASK;
else { tti_unit.buf = (temp & TTI_FIGURES)?
BAUDOT_FIGURES: BAUDOT_LETTERS;
tti_state = temp | TTI_2ND; } } /* set 2nd waiting */
#else /* ASCII... */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
temp = temp & 0177;
if ((tti_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp);
if ((tti_unit.flags & UNIT_HDX) &&
(!(tto_unit.flags & UNIT_UC) ||
((temp >= 007) && (temp <= 0137)))) {
sim_putchar (temp);
tto_unit.pos = tto_unit.pos + 1; }
tti_unit.buf = temp | 0200; /* got char */
#endif
SET_INT (TTI); /* set flag */
tti_unit.pos = tti_unit.pos + 1;
return SCPE_OK;
}
/* Reset routine */
t_stat tti_reset (DEVICE *dptr)
{
tti_unit.buf = 0; /* clear buffer */
tti_state = 0; /* clear state */
CLR_INT (TTI); /* clear flag */
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
return SCPE_OK;
}
/* Terminal output: IOT routine */
int32 tto (int32 pulse, int32 AC)
{
if (pulse & 001) { /* TSF */
if (TST_INT (TTO)) AC = AC | IOT_SKP; }
if (pulse & 002) CLR_INT (TTO); /* clear flag */
if (pulse & 004) { /* load buffer */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
tto_unit.buf = AC & TTO_MASK; } /* load buffer */
return AC;
}
/* Unit service */
t_stat tto_svc (UNIT *uptr)
{
int32 out, temp;
SET_INT (TTO); /* set flag */
#if defined (KSR28) /* Baudot... */
if (tto_unit.buf == BAUDOT_FIGURES) { /* set figures? */
tto_state = TTO_FIGURES;
return SCPE_OK; }
if (tto_unit.buf == BAUDOT_LETTERS) { /* set letters? */
tto_state = 0;
return SCPE_OK; }
out = tto_trans[tto_unit.buf + tto_state]; /* translate */
#else
out = tto_unit.buf & 0177; /* ASCII... */
#endif
if (!(tto_unit.flags & UNIT_UC) ||
((out >= 007) && (out <= 0137))) {
temp = sim_putchar (out);
if (temp != SCPE_OK) return temp;
tto_unit.pos = tto_unit.pos + 1; }
return SCPE_OK;
}
/* Reset routine */
t_stat tto_reset (DEVICE *dptr)
{
tto_unit.buf = 0; /* clear buffer */
tto_state = 0; /* clear state */
CLR_INT (TTO); /* clear flag */
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}

858
PDP18B/pdp18b_sys.c Normal file
View File

@@ -0,0 +1,858 @@
/* pdp18b_sys.c: 18b PDP's simulator interface
Copyright (c) 1993-2001, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
17-Sep-01 RMS Removed multiconsole support
27-May-01 RMS Added second Teletype support
18-May-01 RMS Added PDP-9,-15 API IOT's
12-May-01 RMS Fixed bug in RIM loaders
14-Mar-01 RMS Added extension detection of RIM format tapes
21-Jan-01 RMS Added DECtape support
30-Nov-00 RMS Added PDP-9,-15 RIM/BIN loader format
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
20-Oct-97 RMS Fixed endian dependence in RIM loader
(found by Michael Somos)
*/
#include "pdp18b_defs.h"
#include <ctype.h>
extern DEVICE cpu_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev;
extern UNIT tti_unit, tto_unit;
extern DEVICE clk_dev;
extern DEVICE lpt_dev;
#if defined (DRM)
extern DEVICE drm_dev;
#endif
#if defined (RF)
extern DEVICE rf_dev;
#endif
#if defined (RP)
extern DEVICE rp_dev;
#endif
#if defined (MTA)
extern DEVICE mt_dev;
#endif
#if defined (DTA)
extern DEVICE dt_dev;
#endif
#if defined (TTY1)
extern DEVICE tti1_dev, tto1_dev;
extern UNIT tti1_unit, tto1_unit;
#endif
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern int32 M[];
extern int32 memm;
extern int32 saved_PC;
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
#if defined (PDP4)
char sim_name[] = "PDP-4";
#elif defined (PDP7)
char sim_name[] = "PDP-7";
#elif defined (PDP9)
char sim_name[] = "PDP-9";
#elif defined (PDP15)
char sim_name[] = "PDP-15";
#endif
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 3;
DEVICE *sim_devices[] = { &cpu_dev,
&ptr_dev, &ptp_dev,
&tti_dev, &tto_dev,
&clk_dev, &lpt_dev,
#if defined (DRM)
&drm_dev,
#endif
#if defined (RF)
&rf_dev,
#endif
#if defined (RP)
&rp_dev,
#endif
#if defined (DTA)
&dt_dev,
#endif
#if defined (MTA)
&mt_dev,
#endif
#if defined (TTY1)
&tti1_dev, &tto1_dev,
#endif
NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"Undefined instruction",
"HALT instruction",
"Breakpoint",
"Nested XCT's",
"Invalid API interrupt" };
/* Binary loader */
int32 getword (FILE *fileref, int32 *hi)
{
int32 word, bits, st, ch;
word = st = bits = 0;
do { if ((ch = getc (fileref)) == EOF) return -1;
if (ch & 0200) {
word = (word << 6) | (ch & 077);
bits = (bits << 1) | ((ch >> 6) & 1);
st++; } }
while (st < 3);
if (hi != NULL) *hi = bits;
return word;
}
#if defined (PDP4) || defined (PDP7)
/* PDP-4/PDP-7: RIM format only
Tape format
dac addr
data
:
dac addr
data
jmp addr or hlt
*/
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 origin, val;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
for (;;) {
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if ((val & 0760000) == 0040000) { /* DAC? */
origin = val & 017777;
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
else if ((val & 0760000) == OP_JMP) { /* JMP? */
saved_PC = ((origin - 1) & 060000) | (val & 017777);
return SCPE_OK; }
else if (val == OP_HLT) return SCPE_OK; /* HLT? */
else return SCPE_FMT; } /* error */
return SCPE_FMT; /* error */
}
#else
/* PDP-9/PDP-15: RIM format and BIN format
RIM format (read in address specified externally)
data
:
data
word to execute (bit 1 of last character set)
BIN format (starts after RIM bootstrap)
block/ origin (>= 0)
count
checksum
data
:
data
block/
:
endblock/ origin (< 0)
*/
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
extern int32 sim_switches;
int32 i, bits, origin, count, cksum, val;
t_stat r;
char gbuf[CBUFSIZE];
extern t_bool match_ext (char *fnm, char *ext);
/* RIM loader */
if ((sim_switches & SWMASK ('R')) || /* RIM format? */
(match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) {
if (*cptr != 0) { /* more input? */
cptr = get_glyph (cptr, gbuf, 0); /* get origin */
origin = get_uint (gbuf, 8, ADDRMASK, &r);
if (r != SCPE_OK) return r;
if (*cptr != 0) return SCPE_ARG; } /* no more */
else origin = 0200; /* default 200 */
for (;;) { /* word loop */
if ((val = getword (fileref, &bits)) < 0) return SCPE_FMT;
if (bits & 1) { /* end of tape? */
if ((val & 0760000) == OP_JMP) saved_PC =
((origin - 1) & 060000) | (val & 017777);
else if (val != OP_HLT) return SCPE_FMT;
break; }
else if (MEM_ADDR_OK (origin)) M[origin++] = val; }
return SCPE_OK; }
/* Binary loader */
if (*cptr != 0) return SCPE_ARG; /* no arguments */
do { val = getc (fileref); } /* find end RIM */
while (((val & 0100) == 0) && (val != EOF));
if (val == EOF) rewind (fileref); /* no RIM? rewind */
for (;;) { /* block loop */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (val & SIGN) {
if (val != DMASK) saved_PC = val & 077777;
return SCPE_OK; }
cksum = origin = val; /* save origin */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val; /* add to cksum */
count = (-val) & DMASK; /* save count */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val; /* add to cksum */
for (i = 0; i < count; i++) {
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
if ((cksum & DMASK) != 0) return SCPE_CSUM; }
return SCPE_FMT;
}
#endif
/* Symbol tables */
#define I_V_FL 18 /* inst class */
#define I_M_FL 017 /* class mask */
#define I_V_DC 22 /* default count */
#define I_V_NPN 0 /* no operand */
#define I_V_NPI 1 /* no operand IOT */
#define I_V_IOT 2 /* IOT */
#define I_V_MRF 3 /* memory reference */
#define I_V_OPR 4 /* OPR */
#define I_V_LAW 5 /* LAW */
#define I_V_XR 6 /* index */
#define I_V_XR9 7 /* index literal */
#define I_V_EST 8 /* EAE setup */
#define I_V_ESH 9 /* EAE shift */
#define I_V_EMD 10 /* EAE mul-div */
#define I_NPN (I_V_NPN << I_V_FL) /* no operand */
#define I_NPI (I_V_NPI << I_V_FL) /* no operand IOT */
#define I_IOT (I_V_IOT << I_V_FL) /* IOT */
#define I_MRF (I_V_MRF << I_V_FL) /* memory reference */
#define I_OPR (I_V_OPR << I_V_FL) /* OPR */
#define I_LAW (I_V_LAW << I_V_FL) /* LAW */
#define I_XR (I_V_XR << I_V_FL) /* index */
#define I_XR9 (I_V_XR9 << I_V_FL) /* index literal */
#define I_EST (I_V_EST << I_V_FL) /* EAE setup */
#define I_ESH (I_V_ESH << I_V_FL) /* EAE shift */
#define I_EMD (I_V_EMD << I_V_FL) /* EAE mul-div */
#define MD(x) ((I_EMD) + ((x) << I_V_DC))
static const int32 masks[] = {
0777777, 0777767, 0740000, 0760000,
0763730, 0760000, 0777000, 0777000,
0740700, 0760700, 0777700 };
static const char *opcode[] = {
"CAL", "DAC", "JMS", "DZM", /* mem refs */
"LAC", "XOR", "ADD", "TAD",
"XCT", "ISZ", "AND", "SAD",
"JMP",
#if defined (PDP9) || defined (PDP15) /* mem ref ind */
"CAL*", "DAC*", "JMS*", "DZM*", /* normal */
"LAC*", "XOR*", "ADD*", "TAD*",
"XCT*", "ISZ*", "AND*", "SAD*",
"JMP*",
#else
"CAL I", "DAC I", "JMS I", "DZM I", /* decode only */
"LAC I", "XOR I", "ADD I", "TAD I",
"XCT I", "ISZ I", "AND I", "SAD I",
"JMP I",
#endif
"LAW", /* LAW */
"LACQ", "LACS", "ABS", "GSM", "LMQ", /* EAE */
"MUL", "MULS", "DIV", "DIVS",
"IDIV", "IDIVS", "FRDIV", "FRDIVS",
"NORM", "NORMS",
"MUY", "LLK MUY", "DVI", "LLK DVI",
"NMI", "NMIS", "LRS", "LRSS",
"LLS", "LLSS", "ALS", "ALSS",
"EAE-setup", "EAE", /* setup, general */
"CLSF", "IOF", "ION", "CLOF", "CLON", /* standard IO devs */
"RSF", "RRB", "RCF", "RSA", "RSB",
"PSF", "PCF", "PSA", "PSB", "PLS",
"KSF", "KRB", "KCF", "IORS", "IOOS",
"TSF", "TCF", "TPC", "TLS",
#if defined (TYPE62) /* PDP-4 LPT */
"LPSF", "LPCF", "LPLD", "LPSE",
"LSSF", "LSCF", "LSPR",
#elif defined (TYPE647) /* PDP-7, PDP-9 LPT */
"LPSF", "LPCB", "LPCD", "LPCD", "LPCD",
"LPL2", "LPLD", "LPL1",
"LPEF", "LPCF", "LPCF", "LPCF", "LPCF",
"LPPB", "LPLS", "LPPS",
#elif defined (LP15)
"LPSF", "LPPM", "LPP1", "LPDI",
"LPRS", "LPOS", "LPEI", "LPCD", "LPCF",
#endif
#if defined (DRM) /* drum */
"DRLR", "DRLW", "DRSS", "DRCS",
"DRSF", "DRSN", "DRCF",
"DRLCRD", "DRLCWR", "DRLBLK", "DRCONT",
"DRSF", "DRSOK", "DRCF",
#endif
#if defined (RF) /* RF09 */
"DSSF", "DSCC", "DSCF",
"DRBR", "DRAL", "DSFX", "DRAH",
"DLBR", "DLAL", "DSCN", "DLAH",
"DLOK", "DSCD", "DSRS",
"DGHS", "DGSS",
#endif
#if defined (RP)
"DPSF", "DPSA", "DPSJ", "DPSE",
"DPRSA", "DPOSA", "DPRSB", "DPOSB",
"DPRM", "DPOM",
"DPLA", "DPCS", "DPCA", "DPWC",
"DPLM", "DPEM", "DPSN",
"DPRU", "DPOU", "DPRA", "DPOA",
"DPRC", "DPOC", "DPRW", "DPOW",
"DPCF", "DPLZ", "DPCN", "DPLO", "DPLF",
#endif
#if defined (MTA) /* TC59 */
"MTTR", "MTCR", "MTSF", "MTRC", "MTAF",
"MTRS", "MTGO", "MTCM", "MTLC",
#endif
#if defined (DTA) /* TC02/TC15 */
"DTCA", "DTRA", "DTXA", "DTLA",
"DTEF", "DTRB", "DTDF",
#endif
#if defined (TTY1)
"KSF1", "KRB1",
"TSF1", "TCF1", "TLS1", "TCF1!TLS1",
#endif
#if defined (PDP7)
"ITON", "TTS", "SKP7", "CAF",
"SEM", "EEM", "EMIR", "LEM",
#endif
#if defined (PDP9)
"SKP7", "SEM", "EEM", "LEM",
"LPDI", "LPEI",
#endif
#if defined (PDP15)
"SPCO", "SKP15", "RES",
"SBA", "DBA", "EBA",
"AAS", "PAX", "PAL", "AAC",
"PXA", "AXS", "PXL", "PLA",
"PLX", "CLAC","CLX", "CLLR", "AXR",
#endif
#if defined (PDP9) || defined (PDP15)
"MPSK", "MPSNE", "MPCV", "MPEU",
"MPLD", "MPCNE", "PFSF",
"TTS", "CAF", "DBK", "DBR",
"SPI", "RPL", "ISA",
#endif
"IOT", /* general */
"NOP", "STL", "RCL", "RCR",
"CLC", "LAS", "GLK",
"OPR", "SMA", "SZA", "SZA SMA",
"SNL", "SNL SMA", "SNL SZA", "SNL SZA SMA",
"SKP", "SPA", "SNA", "SNA SPA",
"SZL", "SZL SPA", "SZL SNA", "SZL SZA SPA",
"RAL", "SMA RAL", "SZA RAL", "SZA SMA RAL",
"SNL RAL", "SNL SMA RAL", "SNL SZA RAL", "SNL SZA SMA RAL",
"SKP RAL", "SPA RAL", "SNA RAL", "SNA SPA RAL",
"SZL RAL", "SZL SPA RAL", "SZL SNA RAL", "SZL SZA SPA RAL",
"RAR", "SMA RAR", "SZA RAR", "SZA SMA RAR",
"SNL RAR", "SNL SMA RAR", "SNL SZA RAR", "SNL SZA SMA RAR",
"SKP RAR", "SPA RAR", "SNA RAR", "SNA SPA RAR",
"SZL RAR", "SZL SPA RAR", "SZL SNA RAR", "SZL SZA SPA RAR",
#if defined (PDP15)
"IAC", "SMA IAC", "SZA IAC", "SZA SMA IAC",
"SNL IAC", "SNL SMA IAC", "SNL SZA IAC", "SNL SZA SMA IAC",
"SKP IAC", "SPA IAC", "SNA IAC", "SNA SPA IAC",
"SZL IAC", "SZL SPA IAC", "SZL SNA IAC", "SZL SZA SPA IAC",
#else
"RAL RAR", "SMA RAL RAR", "SZA RAL RAR", "SZA SMA RAL RAR",
"SNL RAL RAR", "SNL SMA RAL RAR", "SNL SZA RAL RAR", "SNL SZA SMA RAL RAR",
"SKP RAL RAR", "SPA RAL RAR", "SNA RAL RAR", "SNA SPA RAL RAR",
"SZL RAL RAR", "SZL SPA RAL RAR", "SZL SNA RAL RAR", "SZL SZA SPA RAL RAR",
#endif
"RTWO", "SMA RTWO", "SZA RTWO", "SZA SMA RTWO",
"SNL RTWO", "SNL SMA RTWO", "SNL SZA RTWO", "SNL SZA SMA RTWO",
"SKP RTWO", "SPA RTWO", "SNA RTWO", "SNA SPA RTWO",
"SZL RTWO", "SZL SPA RTWO", "SZL SNA RTWO", "SZL SZA SPA RTWO",
"RTL", "SMA RTL", "SZA RTL", "SZA SMA RTL",
"SNL RTL", "SNL SMA RTL", "SNL SZA RTL", "SNL SZA SMA RTL",
"SKP RTL", "SPA RTL", "SNA RTL", "SNA SPA RTL",
"SZL RTL", "SZL SPA RTL", "SZL SNA RTL", "SZL SZA SPA RTL",
"RTR", "SMA RTR", "SZA RTR", "SZA SMA RTR",
"SNL RTR", "SNL SMA RTR", "SNL SZA RTR", "SNL SZA SMA RTR",
"SKP RTR", "SPA RTR", "SNA RTR", "SNA SPA RTR",
"SZL RTR", "SZL SPA RTR", "SZL SNA RTR", "SZL SZA SPA RTR",
#if defined (PDP15)
"BSW", "SMA BSW", "SZA BSW", "SZA SMA BSW",
"SNL BSW", "SNL SMA BSW", "SNL SZA BSW", "SNL SZA SMA BSW",
"SKP BSW", "SPA BSW", "SNA BSW", "SNA SPA BSW",
"SZL BSW", "SZL SPA BSW", "SZL SNA BSW", "SZL SZA SPA BSW",
#else
"RTL RTR", "SMA RTL RTR", "SZA RTL RTR", "SZA SMA RTL RTR",
"SNL RTL RTR", "SNL SMA RTL RTR", "SNL SZA RTL RTR", "SNL SZA SMA RTL RTR",
"SKP RTL RTR", "SPA RTL RTR", "SNA RTL RTR", "SNA SPA RTL RTR",
"SZL RTL RTR", "SZL SPA RTL RTR", "SZL SNA RTL RTR", "SZL SZA SPA RTL RTR",
#endif
"LLK", "CLQ", "LSN", "OACQ", "ECLA", /* encode only masks */
"CMQ", "OMQ", "OSC",
"CLA", "CLL", "CML", "CMA",
"OAS", "HLT",
NULL };
static const int32 opc_val[] = {
0000000+I_MRF, 0040000+I_MRF, 0100000+I_MRF, 0140000+I_MRF,
0200000+I_MRF, 0240000+I_MRF, 0300000+I_MRF, 0340000+I_MRF,
0400000+I_MRF, 0440000+I_MRF, 0500000+I_MRF, 0540000+I_MRF,
0600000+I_MRF,
0020000+I_MRF, 0060000+I_MRF, 0120000+I_MRF, 0160000+I_MRF,
0220000+I_MRF, 0260000+I_MRF, 0320000+I_MRF, 0360000+I_MRF,
0420000+I_MRF, 0460000+I_MRF, 0520000+I_MRF, 0560000+I_MRF,
0620000+I_MRF,
0760000+I_LAW,
0641002+I_NPN, 0641001+I_NPN, 0644000+I_NPN, 0664000+I_NPN, 0652000+I_NPN,
0653100+MD(022), 0657100+MD(022), 0640300+MD(023), 0644300+MD(023),
0653300+MD(023), 0657300+MD(023), 0650300+MD(023), 0654300+MD(023),
0640400+MD(044), 0660400+MD(044),
0640100+I_ESH, 0660100+I_ESH, 0640300+I_ESH, 0660300+I_ESH,
0640400+I_ESH, 0660400+I_ESH, 0640500+I_ESH, 0660500+I_ESH,
0640600+I_ESH, 0660600+I_ESH, 0640700+I_ESH, 0660700+I_ESH,
0640000+I_EST, 0640000+I_IOT,
0700001+I_NPI, 0700002+I_NPI, 0700042+I_NPI, 0700004+I_NPI, 0700044+I_NPI,
0700101+I_NPI, 0700112+I_NPN, 0700102+I_NPI, 0700104+I_NPI, 0700144+I_NPI,
0700201+I_NPI, 0700202+I_NPI, 0700204+I_NPI, 0700244+I_NPI, 0700206+I_NPI,
0700301+I_NPI, 0700312+I_NPN, 0700302+I_NPI, 0700314+I_NPN, 0700304+I_NPI,
0700401+I_NPI, 0700402+I_NPI, 0700404+I_NPI, 0700406+I_NPI,
#if defined (TYPE62)
0706501+I_NPI, 0706502+I_NPI, 0706542+I_NPI, 0706506+I_NPI,
0706601+I_NPI, 0706602+I_NPI, 0706606+I_NPI,
#elif defined (TYPE647)
0706501+I_NPI, 0706502+I_NPI, 0706522+I_NPI, 0706542+I_NPI, 0706562+I_NPI,
0706526+I_NPI, 0706546+I_NPI, 0706566+I_NPI,
0706601+I_NPI, 0706602+I_NPI, 0706622+I_NPI, 0706642+I_NPI, 0706662+I_NPI,
0706606+I_NPI, 0706626+I_NPI, 0706646+I_NPI,
#elif defined (LP15)
0706501+I_NPI, 0706521+I_NPI, 0706541+I_NPI, 0706561+I_NPI,
0706552+I_NPN, 0706542+I_NPI, 0706544+I_NPI, 0706621+I_NPI, 0706641+I_NPI,
#endif
#if defined (DRM)
0706006+I_NPI, 0706046+I_NPI, 0706106+I_NPI, 0706204+I_NPI,
0706101+I_NPI, 0706201+I_NPI, 0706102+I_NPI,
0706006+I_NPI, 0706046+I_NPI, 0706106+I_NPI, 0706204+I_NPI,
0706101+I_NPI, 0706201+I_NPI, 0706102+I_NPI,
#endif
#if defined (RF)
0707001+I_NPI, 0707021+I_NPI, 0707041+I_NPI,
0707002+I_NPI, 0707022+I_NPI, 0707042+I_NPI, 0707062+I_NPI,
0707004+I_NPI, 0707024+I_NPI, 0707044+I_NPI, 0707064+I_NPI,
0707202+I_NPI, 0707242+I_NPI, 0707262+I_NPI,
0707204+I_NPI, 0707224+I_NPI,
#endif
#if defined (RP)
0706301+I_NPI, 0706321+I_NPI, 0706341+I_NPI, 0706361+I_NPI,
0706312+I_NPN, 0706302+I_NPI, 0706332+I_NPN, 0706322+I_NPI,
0706342+I_NPN, 0706352+I_NPI,
0706304+I_NPI, 0706324+I_NPI, 0706344+I_NPI, 0706364+I_NPI,
0706411+I_NPN, 0706401+I_NPI, 0706421+I_NPI,
0706412+I_NPN, 0706402+I_NPI, 0706432+I_NPN, 0706422+I_NPI,
0706452+I_NPN, 0706442+I_NPI, 0706472+I_NPN, 0706462+I_NPI,
0706404+I_NPI, 0706424+I_NPI, 0706454+I_NPN, 0706444+I_NPI, 0706464+I_NPI,
#endif
#if defined (MTA)
0707301+I_NPI, 0707321+I_NPI, 0707341+I_NPI, 0707312+I_NPN, 0707322+I_NPI,
0707352+I_NPN, 0707304+I_NPI, 0707324+I_NPI, 0707326+I_NPI,
#endif
#if defined (DTA)
0707541+I_NPI, 0707552+I_NPN, 0707544+I_NPI, 0707545+I_NPI,
0707561+I_NPI, 0707572+I_NPN, 0707601+I_NPI,
#endif
#if defined (TTY1)
0704101+I_NPI, 0704112+I_NPN,
0704001+I_NPI, 0704002+I_NPI, 0704004+I_NPI, 0704006+I_NPI,
#endif
#if defined (PDP7)
0703201+I_NPI, 0703301+I_NPI, 0703341+I_NPI, 0703302+I_NPI,
0707701+I_NPI, 0707702+I_NPI, 0707742+I_NPI, 0707704+I_NPI,
#endif
#if defined (PDP9)
0703341+I_NPI, 0707701+I_NPI, 0707702+I_NPI, 0707704+I_NPI,
0706504+I_NPI, 0706604+I_NPI,
#endif
#if defined (PDP15)
0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI,
0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI,
0720000+I_XR9, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9,
0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR,
0731000+I_XR, 0734000+I_XR, 0735000+I_XR, 0736000+I_XR, 0737000+I_XR9,
#endif
#if defined (PDP9) || defined (PDP15)
0701701+I_NPI, 0701741+I_NPI, 0701702+I_NPI, 0701742+I_NPI,
0701704+I_NPI, 0701744+I_NPI, 0703201+I_NPI,
0703301+I_NPI, 0703302+I_NPI, 0703304+I_NPI, 0703344+I_NPI,
0705501+I_NPI, 0705512+I_NPN, 0705504+I_NPI,
#endif
0700000+I_IOT,
0740000+I_NPN, 0744002+I_NPN, 0744010+I_NPN, 0744020+I_NPN,
0750001+I_NPN, 0750004+I_NPN, 0750010+I_NPN,
0740000+I_OPR, 0740100+I_OPR, 0740200+I_OPR, 0740300+I_OPR,
0740400+I_OPR, 0740500+I_OPR, 0740600+I_OPR, 0740700+I_OPR,
0741000+I_OPR, 0741100+I_OPR, 0741200+I_OPR, 0741300+I_OPR,
0741400+I_OPR, 0741500+I_OPR, 0741600+I_OPR, 0741700+I_OPR,
0740010+I_OPR, 0740110+I_OPR, 0740210+I_OPR, 0740310+I_OPR,
0740410+I_OPR, 0740510+I_OPR, 0740610+I_OPR, 0740710+I_OPR,
0741010+I_OPR, 0741110+I_OPR, 0741210+I_OPR, 0741310+I_OPR,
0741410+I_OPR, 0741510+I_OPR, 0741610+I_OPR, 0741710+I_OPR,
0740020+I_OPR, 0740120+I_OPR, 0740220+I_OPR, 0740320+I_OPR,
0740420+I_OPR, 0740520+I_OPR, 0740620+I_OPR, 0740720+I_OPR,
0741020+I_OPR, 0741120+I_OPR, 0741220+I_OPR, 0741320+I_OPR,
0741420+I_OPR, 0741520+I_OPR, 0741620+I_OPR, 0741720+I_OPR,
0740030+I_OPR, 0740130+I_OPR, 0740230+I_OPR, 0740330+I_OPR,
0740430+I_OPR, 0740530+I_OPR, 0740630+I_OPR, 0740730+I_OPR,
0741030+I_OPR, 0741130+I_OPR, 0741230+I_OPR, 0741330+I_OPR,
0741430+I_OPR, 0741530+I_OPR, 0741630+I_OPR, 0741730+I_OPR,
0742000+I_OPR, 0742100+I_OPR, 0742200+I_OPR, 0742300+I_OPR,
0742400+I_OPR, 0742500+I_OPR, 0742600+I_OPR, 0742700+I_OPR,
0743000+I_OPR, 0743100+I_OPR, 0743200+I_OPR, 0743300+I_OPR,
0743400+I_OPR, 0743500+I_OPR, 0743600+I_OPR, 0743700+I_OPR,
0742010+I_OPR, 0742110+I_OPR, 0742210+I_OPR, 0742310+I_OPR,
0742410+I_OPR, 0742510+I_OPR, 0742610+I_OPR, 0742710+I_OPR,
0743010+I_OPR, 0743110+I_OPR, 0743210+I_OPR, 0743310+I_OPR,
0743410+I_OPR, 0743510+I_OPR, 0743610+I_OPR, 0743710+I_OPR,
0742020+I_OPR, 0742120+I_OPR, 0742220+I_OPR, 0742320+I_OPR,
0742420+I_OPR, 0742520+I_OPR, 0742620+I_OPR, 0742720+I_OPR,
0743020+I_OPR, 0743120+I_OPR, 0743220+I_OPR, 0743320+I_OPR,
0743420+I_OPR, 0743520+I_OPR, 0743620+I_OPR, 0743720+I_OPR,
0742030+I_OPR, 0742130+I_OPR, 0742230+I_OPR, 0742330+I_OPR,
0742430+I_OPR, 0742530+I_OPR, 0742630+I_OPR, 0742730+I_OPR,
0743030+I_OPR, 0743130+I_OPR, 0743230+I_OPR, 0743330+I_OPR,
0743430+I_OPR, 0743530+I_OPR, 0743630+I_OPR, 0743730+I_OPR,
0660000+I_EST, 0650000+I_EST, 0644000+I_EST, 0642000+I_EST, 0641000+I_EST,
0640004+I_EST, 0640002+I_EST, 0640001+I_EST,
0750000+I_OPR, 0744000+I_OPR, 0740002+I_OPR, 0740001+I_OPR,
0740004+I_OPR, 0740040+I_OPR,
-1 };
/* Operate or EAE decode
Inputs:
*of = output stream
inst = mask bits
class = instruction class code
sp = space needed?
Outputs:
status = space needed?
*/
int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp)
{
int32 i, j;
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1; } }
return sp;
}
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
*/
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
#define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100)
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 cflag, i, j, k, sp, inst, disp, ma;
inst = val[0];
i = val[1];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
fprintf (of, FMTASC (inst & 0177));
return SCPE_OK; }
if (sw & SWMASK ('C')) { /* character? */
fprintf (of, "%c", SIXTOASC ((inst >> 12) & 077));
fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));
fprintf (of, "%c", SIXTOASC (inst & 077));
return SCPE_OK; }
#if defined (PDP15)
if (sw & SWMASK ('P')) { /* packed ASCII? */
fprintf (of, "%c", FMTASC ((inst >> 11) & 0177));
fprintf (of, "%c", FMTASC ((inst >> 4) & 0177));
fprintf (of, "%c", FMTASC (((inst << 3) | (i >> 15)) & 0177));
fprintf (of, "%c", FMTASC ((i >> 8) & 0177));
fprintf (of, "%c", FMTASC ((i >> 1) & 0177));
return -1; }
#endif
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
/* Instruction decode */
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */
switch (j) { /* case on class */
case I_V_NPN: /* no operands */
case I_V_XR: /* index no opers */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_NPI: /* IOT no operand */
fprintf (of, "%s", opcode[i]); /* opcode */
if (inst & 010) fprintf (of, " +10");
break;
case I_V_IOT: /* IOT or EAE */
fprintf (of, "%s %-o", opcode[i], inst & 037777);
break;
case I_V_MRF: /* mem ref */
#if defined (PDP15)
if (memm) {
disp = inst & 017777;
ma = (addr & 0760000) | disp; }
else { disp = inst & 007777;
ma = (addr & 0770000) | disp; }
fprintf (of, "%s %-o", opcode[i],
(cflag? ma & ADDRMASK: disp));
if (!memm && (inst & 0010000)) fprintf (of, ",X");
#else
disp = inst & 017777;
ma = (addr & 0760000) | disp;
fprintf (of, "%s %-o", opcode[i],
(cflag? ma & ADDRMASK: disp));
#endif
break;
case I_V_OPR: /* operate */
if (sp = (inst & 03730)) fprintf (of, "%s", opcode[i]);
fprint_opr (of, inst & 014047, I_V_OPR, sp);
break;
case I_V_LAW: /* LAW */
fprintf (of, "%s %-o", opcode[i], inst & 017777);
break;
case I_V_XR9: /* index with lit */
disp = inst & 0777;
if (disp & 0400) fprintf (of, "%s -%-o", opcode[i], 01000 - disp);
else fprintf (of, "%s %-o", opcode[i], disp);
break;
case I_V_EST: /* EAE setup */
fprint_opr (of, inst & 037007, I_V_EST, 0);
break;
case I_V_ESH: /* EAE shift */
sp = fprint_opr (of, inst & 017000, I_V_EST, 0);
fprintf (of, (sp? " %s %-o": "%s %-o"), opcode[i], inst & 077);
break;
case I_V_EMD: /* EAE mul-div */
disp = inst & 077; /* get actual val */
k = (opc_val[i] >> I_V_DC) & 077; /* get default val */
if (disp == k) fprintf (of, "%s", opcode[i]);
else if (disp < k) fprintf (of, "%s -%-o", opcode[i], k - disp);
else fprintf (of, "%s +%-o", opcode[i], disp - k);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
return SCPE_ARG;
}
/* Get 18b signed number
Inputs:
*cptr = pointer to input string
*sign = pointer to sign
*status = pointer to error status
Outputs:
val = output value
*/
t_value get_sint (char *cptr, int32 *sign, t_stat *status)
{
*sign = 0;
if (*cptr == '+') {
*sign = 1;
cptr++; }
else if (*cptr == '-') {
*sign = -1;
cptr++; }
return get_uint (cptr, 8, 0777777, status);
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 cflag, d, i, j, k, sign, dmask, epcmask;
t_stat r;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++;
for (i = 1; (i < 5) && (cptr[i] != 0); i++)
if (cptr[i] == 0) for (j = i + 1; j <= 5; j++) cptr[j] = 0;
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cptr[0] | 0200;
return SCPE_OK; }
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (((t_value) cptr[0] & 077) << 12) |
(((t_value) cptr[1] & 077) << 6) |
((t_value) cptr[2] & 077);
return SCPE_OK; }
#if defined (PDP15)
if ((sw & SWMASK ('P')) || ((*cptr == '#') && cptr++)) { /* packed string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (((t_value) cptr[0] & 0177) << 11) |
(((t_value) cptr[1] & 0177) << 4) |
(((t_value) cptr[2] & 0170) >> 3);
val[1] = (((t_value) cptr[2] & 0007) << 15) |
(((t_value) cptr[3] & 0177) << 8) |
(((t_value) cptr[4] & 0177) << 1);
return -1; }
#endif
/* Symbolic input, continued */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
val[0] = opc_val[i] & DMASK; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
switch (j) { /* case on class */
case I_V_XR: /* index */
break;
case I_V_XR9: /* index literal */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
d = get_sint (gbuf, &sign, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (((sign >= 0) && (d > 0377)) || ((sign < 0) && (d > 0400)))
return SCPE_ARG;
val[0] = val[0] | ((sign >= 0)? d: (01000 - d));
break;
case I_V_LAW: /* law */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
d = get_uint (gbuf, 8, 017777, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | d;
break;
case I_V_MRF: /* mem ref */
#if defined (PDP15)
if (memm) dmask = 017777;
else dmask = 07777;
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
#else
dmask = 017777;
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
#endif
#if defined (PDP4) || defined (PDP7)
if (strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | 020000;
cptr = get_glyph (cptr, gbuf, 0); }
#endif
epcmask = ADDRMASK & ~dmask; /* get ePC */
d = get_uint (gbuf, 8, ADDRMASK, &r); /* get addr */
if (r != SCPE_OK) return SCPE_ARG;
if (d <= dmask) val[0] = val[0] | d; /* fit in 12/13b? */
else if (cflag && (((addr ^ d) & epcmask) == 0))
val[0] = val[0] | (d & dmask); /* hi bits = ePC? */
else return SCPE_ARG;
#if defined (PDP15)
if (!memm) {
cptr = get_glyph (cptr, gbuf, 0);
if (gbuf[0] != 0) {
if (strcmp (gbuf, "X") != 0) return SCPE_ARG;
val[0] = val[0] | 010000; } }
#endif
break;
case I_V_EMD: /* or'able */
val[0] = val[0] | ((opc_val[i] >> I_V_DC) & 077); /* default shift */
case I_V_EST: case I_V_ESH:
case I_V_NPN: case I_V_NPI: case I_V_IOT: case I_V_OPR:
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] != NULL) {
k = opc_val[i] & DMASK;
if (((k ^ val[0]) & 0740000) != 0) return SCPE_ARG;
val[0] = val[0] | k; }
else { d = get_sint (gbuf, & sign, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (sign > 0) val[0] = val[0] + d;
else if (sign < 0) val[0] = val[0] - d;
else val[0] = val[0] | d; } }
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;
}

244
PDP18B/pdp18b_tt1.c Normal file
View File

@@ -0,0 +1,244 @@
/* pdp18b_tt1.c: 18b PDP's second Teletype
Copyright (c) 1993-2001, 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.
tti1 keyboard
tto1 teleprinter
30-Nov-01 RMS Added extended SET/SHOW support
25-Nov-01 RMS Revised interrupt structure
19-Sep-01 RMS Fixed typo
17-Sep-01 RMS Changed to use terminal multiplexor library
07-Sep-01 RMS Moved function prototypes
10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware
*/
#include "pdp18b_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
extern int32 int_hwre[API_HLVL+1];
extern int32 tmxr_poll; /* calibrated poll */
TMLN tt1_ldsc = { 0 }; /* line descriptors */
TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */
t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr);
t_stat tto1_reset (DEVICE *dptr);
t_stat tti1_attach (UNIT *uptr, char *cptr);
t_stat tti1_detach (UNIT *uptr);
t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc);
/* TTI1 data structures
tti1_dev TTI1 device descriptor
tti1_unit TTI1 unit
tto1_mod TTI1 modifier list
tti1_reg TTI1 register list
*/
UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT };
REG tti1_reg[] = {
{ ORDATA (BUF, tti1_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_TTI1], INT_V_TTI1) },
{ FLDATA (DONE, int_hwre[API_TTI1], INT_V_TTI1) },
{ FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO },
{ DRDATA (POS, tt1_ldsc.rxcnt, 31), PV_LEFT },
{ DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL } };
MTAB tti1_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &tti1_status },
{ MTAB_XTD | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, "LINE", NULL,
NULL, &tti1_status, NULL },
{ 0 } };
DEVICE tti1_dev = {
"TTI1", &tti1_unit, tti1_reg, tti1_mod,
1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &tti1_reset,
NULL, &tti1_attach, &tti1_detach };
/* TTO1 data structures
tto1_dev TTO1 device descriptor
tto1_unit TTO1 unit
tto1_mod TTO1 modifier list
tto1_reg TTO1 register list
*/
UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_UC, 0), SERIAL_OUT_WAIT };
REG tto1_reg[] = {
{ ORDATA (BUF, tto1_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_TTO1], INT_V_TTO1) },
{ FLDATA (DONE, int_hwre[API_TTO1], INT_V_TTO1) },
{ DRDATA (POS, tt1_ldsc.txcnt, 31), PV_LEFT },
{ DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT },
{ NULL } };
MTAB tto1_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ 0 } };
DEVICE tto1_dev = {
"TTO1", &tto1_unit, tto1_reg, tto1_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto1_reset,
NULL, NULL, NULL };
/* Terminal input: IOT routine */
int32 tti1 (int32 pulse, int32 AC)
{
if (pulse & 001) { /* KSF1 */
if (TST_INT (TTI1)) AC = AC | IOT_SKP; }
if (pulse & 002) { /* KRB1 */
CLR_INT (TTI1); /* clear flag */
AC= AC | tti1_unit.buf; } /* return buffer */
return AC;
}
/* Unit service */
t_stat tti1_svc (UNIT *uptr)
{
int32 temp, newln;
if (tt1_ldsc.conn) { /* connected? */
tmxr_poll_rx (&tt_desc); /* poll for input */
if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */
temp = temp & 0177;
if ((uptr -> flags & UNIT_UC) &&
islower (temp)) temp = toupper (temp);
uptr -> buf = temp | 0200; /* got char */
SET_INT (TTI1); } /* set flag */
sim_activate (uptr, uptr -> wait); } /* continue poll */
if (uptr -> flags & UNIT_ATT) { /* attached? */
newln = tmxr_poll_conn (&tt_desc, uptr); /* poll connect */
if (newln >= 0) { /* got one? */
sim_activate (&tti1_unit, tti1_unit.wait);
tt1_ldsc.rcve = 1; } /* rcv enabled */
sim_activate (uptr, tmxr_poll); } /* sched poll */
return SCPE_OK;
}
/* Reset routine */
t_stat tti1_reset (DEVICE *dptr)
{
tti1_unit.buf = 0; /* clear buffer */
CLR_INT (TTI1); /* clear flag */
if (tt1_ldsc.conn) { /* if conn, */
sim_activate (&tti1_unit, tti1_unit.wait); /* activate, */
tt1_ldsc.rcve = 1; } /* enable */
else if (tti1_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&tti1_unit, tmxr_poll); /* activate */
else sim_cancel (&tti1_unit); /* else stop */
return SCPE_OK;
}
/* Terminal output: IOT routine */
int32 tto1 (int32 pulse, int32 AC)
{
if (pulse & 001) { /* TSF */
if (TST_INT (TTO1)) AC = AC | IOT_SKP; }
if (pulse & 002) CLR_INT (TTO1); /* clear flag */
if (pulse & 004) { /* load buffer */
sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */
tto1_unit.buf = AC & 0377; } /* load buffer */
return AC;
}
/* Unit service */
t_stat tto1_svc (UNIT *uptr)
{
int32 out;
SET_INT (TTO1); /* set flag */
out = tto1_unit.buf & 0177;
if (tt1_ldsc.conn) { /* connected? */
if (tt1_ldsc.xmte) { /* tx enabled? */
if (!(tto1_unit.flags & UNIT_UC) ||
((out >= 007) && (out <= 0137)))
tmxr_putc_ln (&tt1_ldsc, out); /* output char */
tmxr_poll_tx (&tt_desc); } /* poll xmt */
else { tmxr_poll_tx (&tt_desc); /* poll xmt */
sim_activate (&tto1_unit, tmxr_poll); /* wait */
return SCPE_OK; } }
return SCPE_OK;
}
/* Reset routine */
t_stat tto1_reset (DEVICE *dptr)
{
tto1_unit.buf = 0; /* clear buffer */
CLR_INT (TTO1); /* clear flag */
sim_cancel (&tto1_unit); /* deactivate unit */
return SCPE_OK;
}
/* Attach routine */
t_stat tti1_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = tmxr_attach (&tt_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
sim_activate (uptr, tmxr_poll); /* start poll */
return SCPE_OK;
}
/* Detach routine */
t_stat tti1_detach (UNIT *uptr)
{
t_stat r;
r = tmxr_detach (&tt_desc, uptr); /* detach */
tt1_ldsc.rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */
return r;
}
/* Status routine */
t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc)
{
tmxr_fstatus (st, &tt1_ldsc, -1);
return SCPE_OK;
}