1
0
mirror of https://github.com/open-simh/simh.git synced 2026-01-11 23:53:30 +00:00

S3: Restore original S3 code to branch

This commit is contained in:
Bob Supnik 2022-05-16 03:01:45 -07:00 committed by Mark Pizzolato
parent adf023bf86
commit d29c6f43e3
10 changed files with 6291 additions and 0 deletions

950
S3/haltguide.txt Normal file
View File

@ -0,0 +1,950 @@
IBM System/3 Model 8/10 SCP
**********
Halt Guide
**********
This following list is my own reformatting and rewording of the
official IBM Halt Guide for the Model 8/10 SCP.
The halts are those displayed on the message display unit. The
list is in alphabetical order for easy reference.
When the system halts, the two 7-segment displays will display the
halt as listed here, and the system console (or printer if the log
device is the printer) will print the "SCP Message" below. To
respond to the halt, deposit one of the valid response numbers
(0 thru 3) into the SR, and then use the C command to continue.
Unless otherwise stated, a response of 0 means to continue and accept
the error, 1 means to retry the operation or re-read the statement in
error, 2 means to cancel the job and retain added records (if any) and
3 means to end the job and discard any added records in files.
This is a listing of those halts likely to be encountered using SCP on
the simuator, it is not the complete list of all possible halts.
Halt SCP Message Description
---- ----------- -----------
00 Invalid response to another halt. Deposit a valid
value (0 thru 3) in SR.
0A A 5448 Disk Unit not ready.
0C 5448 Disk Equipment Check
0E Permanent disk error during logging.
0F ID0FXX 23 Invalid cylinder number on disk operation.
XX = Disk Drive.
0H ID0HXX 23 Invalid sector number on disk operation
XX = Disk Drive.
0Y IK0Y0X 123 3741 Error. X: 1=not ready 2=wrong mode
3=parity error 5=record length error
0 ID0 XX 23 Disk Data Check
XX = Disk Drive.
0- ID0-XX Invalid disk operation code: Start cancels job.
XX = Disk Drive.
10 3 No input file allocate, user error.
11 0 23 Square root of a negative field
12 0 23 Divide Overflow
13 0 23 Divide by zero
14 0 23 Varible index zero of out of range
15 0 23 Sequenced table is out of sequence
16 0 23 (RPG) OBject tables expected. /* Read.
17 0 23 (RPG) Object table exceeds specified length
18 0 23 (RPG) Terminal errors in source program.
19 0 3 (RPG) Warning errors in source program. 0=continue.
1A 3 (RPG) Out of core memory
1C 23 Unidentified halt has been issued. Probable system
error.
1E 0 3 (RPG) Demand file at end of file.
1F 23 (RPG) End of file or end of extent. If during RPG
compilation, expand $SOURCE or $WORK.
1H 0 23 Duplicate keys found during build of indexed file.
0=skip this record and continue.
1J 0 23 Out of sequence keys during build of indexed file.
0=skip this record and continue.
1L 0 23 Key changed during record update. User error.
0=continue, do not update record.
1P 01 Forms in printer need positioning.
1U 123 No record found on direct or indexed file.
1Y 0 23 (RPG) Invalid numeric data to DSPLY statement.
1 0 3 Object program ready to punch tables.
20 1 3 Disk Sort: Invalid header and no // SOURCE
21 01 3 Disk Sort: Name on // SOURCE not found
22 0 2 Disk Sort: Warning errors found.
23 3 Disk Sort: Unrecoverable error.
25 3 Disk Sort: Terminal errors in sort statements.
27 0 Disk Sort: In debug mode, finished pass.
2C 0 3 Disk Sort: No Input Records selected.
2E 3 Disk Sort: Workfile too small.
2F 23 Disk Sort: Output file too small.
2L DT2LY2 3 Tape Record too large to process.
DT2LY7 3 No FILE statement for tape file open.
DT2LY9 3 No enough storage for tape operation
DT2LTC 3 Invalid tape header length
DT2LYF 123 Incorrect block length read from tape
2P Permanent tape error.
2U 12 Tape unit is write protected.
2Y 3 Invalid device specification in object.
2- 0 3 First statement was not a Tape Sort header.
30 EG30 3 Space not available on R1 or F1.
UB30A1 0 3 Active files exist on output disk
UB30AF 0 3 Active files exist on 5448 disk
UB30H1 0 3 Wrong capacity or uninitialized pack
UB30NS 3 No 5448 disk for $PCOPY
UB30TP 0 3 Pack change required.
UC30AF 3 Active or system files on target
UC30BD 3 Volume label cannot be read
UC30SP 3 Not enough space for work file
UP30AF 3 Active or system files on target
31 UI31AF 0 3 Active or system files on target
0=proceed to next unit to initialize
UI30WP 01 3 Wrong pack, name does not match.
32 UB32Bx 01 3 5444 pack is not a $PCOPY backup pack.
UB32NP 01 3 Unit specified is not a $PCOPY pack.
UC32BD 3 FROM pack is a TO pack from an interrupted
COPYPACK run.
UC32BP 3 Output pack is a $PCOPY output pack.
Must be initialized or reset by a RESET
statement to be used.
UC32DS 3 Packs FROM and TO are different sizes.
33 UI33PU 0 3 Pack defective, cannot be initialized.
34 Ux34 1 3 Keyword in a utility control statement is invalid.
35 UC35xx 1 3 Error in $COPY or $KCOPY control statement.
36 UI36CE 0 3 CE track defective on unit F1.
37 UC37xx 0 3 Pack change required. xx: FP=mount on R1,
IP=pack on COPYIN, OP=pack on COPYO.
38 UA38XX 0 3 Wrong pack mounted.
UB38DA 01 3 Dates do not match.
UB38DM 01 3 2nd 5444 pack not from same backup set as 1st.
UB38IP 01 3 PACKIN keyword pack not same as pack mounted.
UB38OP 01 3 PACKO keyword not same as pack mounted.
3A UC3Axx 3 Key out of sequence (DP), invalid high key (HK),
out of space to copy file (XE), or disk I/O error.
3C UC3CCS 3 COPYFILE out of core.
UC3CNF 3 Module not found, name is logged as R XXXXXX.
3E UC3EOX 0 3 COPYFILE output not as big as size of input.
3F UC3Fxx 1 3 Error in COPYFILE statement.
3J UC3Fxx 3 Invalid specification for Copy/Dump.
3P UC3Pxx 1 3 Error in COPYPACK, RESET, or LABELS statement.
3Y UI3YIS 0 3 Requested secondary init when primary required.
3 UI3 xx 1 3 Error in VOL statement.
40 DD40 3 File has been referenced as an output or add file
and the file is already allocated.
4A DD4A 3 File had already been opened and is re-opened.
4C DD4C 3 Multivolumne file spec error.
4E DD4E 3 FILE indicates a multivolule file being built,
but program compiled for single volume.
4F DD4F 3 Print buffers not aligned in program.
4H DD4H 0 3 Unordered load specified for ISAM. Ordered load
must be specified on RPG file specs.
4J DD4J 3 All file specs have been checked and there were
errors.
4L DD4L 3 Referenced file already allocated.
4P DD4P 3 Prgram/FILE statement mismatch.
4U DD4U 3 File referenced as update, already allocated.
4Y DD4Y 3 File has an incorrect device specification.
4 DD4 3 No FILE specification for referenced file.
4' DD4' 3 Attempting reference to a file in 2 levels, one or
both using RETAIN-S.
50 UA50ID 2 Bad track which can't be reassigned.
51 UR51 12 Can't use Alternate Track program in procedure.
52 ML52 12 EOJ for Card List program.
53 IU53 1 3 Number of VOL statements does not agree with number
of units on UIN statement.
54 EO54 3 End-of-file.
55 UF55xx 1 3 Error in SCRATCH or REMOVE statement.
56 UA56TS 0 3 ASSIGN track is over disk capacity.
UA56XX 0 3 Unit specified is uninitialized.
57 UF57WP 01 3 File delete program. Wrong pack is mounted.
0: Mount correct pack and continue. 1:
correct statement and retry.
5A UA5Axx 012 Alternate track assignment error.
5C MR5Cxx 1 3 Invalid reformat specs.
5F UF5Fxx 1 3 Error in DISPLAY statement.
5H UA5HEU 0123 Primary track is still defective.
5L UF5LAF 0 3 PRogram try to delete files that are being used by
another program.
UF5LNF 0 3 File not found.
UF5LTM 23 Too many files specified. Max is 40.
5U UI5Uxx 1 3 Error in UIN statement.
5Y UR5Yxx 1 3 Error in REBUILD statment.
5 UA5 xx 1 3 Error in ALT statement.
5- 3 Tape Sort error occurred.
5' UF5'N1 0 3 Pack cannot be used. Not inited.
UF5'NU 0 3 Pack was used as TO pack on a COPYPACK job
that required early termination. Can only
be used for another COPYPACK job.
60 LM60SY 0 3 Cannot remove or change library size on pack
from which $MAINT was loaded.
61 LM61EP 0 3 Trying to copy a system to a library that is
1) not empty, 2) not allocated with large enough
SWA, or 3) not allocated with enough space.
LM61NS 0 3 System does not exist on FROM pack.
62 LM62CS 01 3 Check Sum error.
LM62DR Can't determine if REMOVE is data or control.
LM62EF FROM, TO, or AFTER statement does not exist or
is out of sequence.
LM62ND NO data records following INSERT or REPLACE.
LM62SQ Records are out of sequence.
LM62TP Incorrect type record.
63 LM63DE 0 3 Directory entry error. Name can't be found or
attributes don't match, or attempt to remove
dir entry with MODIFY.
64 LM64DS 0 3 Syntax error in ALLOCATE.
65 LM65UN 0 3 Pack not properly initialized.
66 LA66xx 3 Error with LOAD * function.
67 EL67NL 0 3 Library does not exist.
68 EL68DF 0 3 No room in library or directory.
69 XX69HE 3 Disk I/O Error while using library.
6A LM6Axx 1 3 $MAINT has detected a syntax error on a control
statement. xx gives a hint of what might be wrong.
AL: SOURCE or OBJECT missing or invalid
AZ: SYSTEM missing or invalid
D2: FROM, TO, or WORK is R2 or F2, not available
DK: Duplicate keyword
DS: Invalid DIRSIZE
FL: Invalid or missing FILE keyword
FM: Invalid or missing FROM keyword
IK: Invalid keyword
IN: Invalid INCR keyword
IS: first 3 columns must be // blank
IV: Invalid statement identifier
LB: Invalid LIBRARY keyword
LS: Invalid LIST keyword
NK: No keywords
NM: Invalid NAME keyword
NU: Invalid NEWNAME keyword
OM: Invalid OMIT keyword
RL: Invalid RECL keyword
RS: Invalid RESER keyword
RT: Invalid RETAIN keyword
SF: INvalid SEQFLD keyword
SQ: Invalid FROM, TO, or AFTER in MODIFY mode
XC: Invalid record.
XD: Duplicate keyword
XF: $$SYFG could not be found.
XL: LIBRARY keyword missing
XM: NAME keyword missing
XN: NAME parameter is invalid
XP: Library does not exist on this pack
XS: Syntax error
XT: Invalid library type
XV: INvalid operation
6C LM6CSP 0 3 Not enough space on pack.
LM6CSW 0 3 Space not available for work file.
6E LM6EOF 0 3 Overflow in seq field during RESER.
LM6EDP 0 3 Entry with same name already exists in library.
6H EL6HDT 0 3 Trying to replace perm with temp entry.
LM6HDP 0 3 NEWNAME is already in library.
6J LM6JCC 0 3 Control statements are missing.
6L UA6L 3 Log device is required for this program.
6Y LM6YNN 1 3 No NEWNAME when copying to same library.
6 LM6 BC 3 Invalid character in source record.
LM6 CM 0 3 Invalid object deck.
LM6 ND 0 3 No data between COPY and CEND.
6- LM6-BC 01 Entry containing a blank card being placed in
library. 0: accept, 1: skip and read next card.
6' LM6'CE 1 3 // CEND expected but not found. 1: Retry,
provide CEND. NOTE: For option 3, if a module
was being replaced, it may have been deleted but
new module not loaded.
70 CR70 3 Too many overrides for procedure. Max is 25.
71 CR71 0 3 OCL Syntax Error.
73 CR73 0 // PARTITION given in invalid location.
74 CR74 3 /& between LOAD and RUN or CALL and RUN.
75 CR75 23 Extraneous statement.
76 CR76 0 3 // Missing from OCL statement.
77 CR77 23 Invalid OCL statement identifier.
78 CR78 0 3 Unknown OCL keyword.
79 CR79 23 Continuation expected but not received.
7A CR7A 3 A second LOAD or CALL found before run, or a
CALL in procedure overrides.
7C CR7C 0 3 // COMPILE found between jobs.
7E CR7E 0 3 // DATE found between jobs. 0: Ignore and continue.
7F CR7F 0 3 // FILE found between jobs. Must go between
// LOAD or // CALL and // RUN statements.
7H CR7H 0 3 // SWITCH found between jobs.
7J CR7J 23 // READER found between LOAD or CALL and RUN.
7L CI7Lxx 23 Error when reading a tape file.
7P New print chain expected. Load it and press START.
7U CR7U 3 RUN statement not preceeded by LOAD or CALL.
7Y CI7Yxx 23 Error outputing a tape file.
7 CR7 3 Too many utility control statements, max is 25.
7- CR7- 0 // PARTITION was read but system does not support
Dual Programming.
7' Error during tape processing.
80 CR80 0 // DATE card has not been entered.
81 CR81 23 Error in LOAD statement.
83 CR83 23 Error in LOAD * statement.
84 CR84 23 Error in CALL statement
85 CR85 23 Second SWITCH statement found.
86 CR86 23 Invalid paramter in switch statement.
88 CR88 1 3 Procedure not found.
89 CR89 01 // DATE has already been given.
0 - accept the new date as the date.
1 - leave the old date as the current date.
8A CR8A01 0 Invalid date specified.
CR8A02 0 DATE parameter missing.
8C CR8C 23 Second DATE found.
8E CR8E01 23 Date specified incorrectly.
8F CR8Fxx 23 Invalid BSCA statement.
8H CR8H 3 More than 9 levels of procedures have been called.
8J CR8J 0 Invalid // READER parameter.
8L CR8L 0 Desired system input device being used by other
program.
8P CR8P 0 Output device not defined.
8U CU8UIP 23 Invalid HIKEY in FILE statement: non-numeric.
CR8UKL Parameter length mismatch.
CR8ULO Key greater than 29.
CR8UPL HIKEY-P greater than 15.
CR8USQ HIKEY parameters not in sequence.
8Y CR8Y 0 Not logging can be done. Log turned off by
other program level.
8- CR8- 0 3 Logging requested but cannot be done.
90 CR90 0 // PAUSE statement read. Check printer or console
for instructions and continue. PAUSE was outside
LOAD and RUN.
91 CR90 0 // PAUSE statement read. Check printer or console
for instructions and continue. PAUSE was inside
LOAD and RUN.
92 CR92 23 COMPILE already recieved for this job.
93 CR93 23 Error in COMPILE statement.
94 CR94 23 Error in COMPILE statement.
95 CR95 23 Error in COMPILE statement.
96 CR96 0 23 System error. An OCL error was found, but the system
cannot resolve the error.
97 CR97 0 Error in LOG statement.
98 CR98 23 Error in LOG statement.
99 CR99 0 23 Error in LOG statement.
9A CR9A 23 Indicated action on last OCL statement read will
be ignored due to previous errors detected.
9C CR9Cxx 123 Incorrect tape volume online.
9E CR9E 0 Logging device being used by other program level.
9F CR9F 0 23 Logging device in use by other program.
9H CR9H 23 Log device in use.
9J CR9J 0 Error in FORMS statement.
9L CR9L 0 23 Error in FORMS statement.
9P CR9P 23 Error in FORMS statement.
9U CR9U 0 3 Other program has gotten a // IMAGE or other
program level is using the printer.
9Y CR9Y 0 23 Logging device not sysgenned or CCP has it.
9 CR9 0 23 Same as 9Y.
9- CR9- 0 3 Other program level received a // FORMS or
other level using the printer.
9' CR9' 0 Same as 9Y.
A0 CRa0xx 23 Syntax error in FILE statement.
A1 CRA1xx 23 Keyword error in FILE statement.
A2 CRA2xx 23 Parameter error on FILE statement.
xx gives parameter:
01 NAME, 02 UNIT, 03 PACK, 04 LABEL,
05 RETAIN, 06 DATE, 07 RECORDS, 08 TRACKS,
09 LOCATION, AS ASCII, BL BLKL, CV CONVERT,
DF DEFER, DN DENSITY, EN END, PT PARITY,
RC RECL, RF RECFM, RL REEL, SP SPLIT,
TN TRANSLATE.
A3 CRA3xx 23 Missing Parameter on FILE statement, xx =
NN: NAME, NP: PACK, NU: UNIT, OP: no
parameters.
A4 CRA4xx 23 Invalid parameter combination in FILE statement:
AS: ASCII-YES and RECFM-D/DB on 7-track tape
AV: ASCII-YES and RECFB-V/VB
AY: RECFM-D/DB without ASCII-YES
CT: CONVERT-ON and TRANSLATE
DI: UNIT says tape but disk parameters given
DN: DENSITY-800 not supported.
FS: RECFM is fexed and block or rec len less than 18
IL: Incorrected RECL or BLKL for RECFM
IP: SPLIT or LOCATION used with RECORDS / TRACKS.
IR: LABEL, DATE or RETAIN wirh REEL-NL or REEL-NS
NS: Not all units are 7-track
PC: CONVERT-ON and PARITY-EVEN
RC: CONVERT-ON not given with RECFM-V/VB for 7-track
SD: DENSITY-1600 invalid for 7-track
SL: LOCATION missing or invalid for SPLIT.
SM: SPLIT invalid for multivolume files.
ST: 7-track paras with 9-track unit
SU: SPlit can't be used with 5444
TL: TRACKS/LOCATION invalid with unit
TP: UNIT is disk but tape paras given
TR: TRACKS and RECORDS both given
A6 CRA6xx 23 Error in FILE statement for multivolumne files.
A7 CRA7xx 23 Error in IMAGE statement.
A8 CRA8xx 0 Error in IMAGE statements o disk.
A9 CRA9xx 0 23 Same as A8.
AA CRAAxx 23 Same as A8.
AC CRAC 0 Invalid hex character in chain image.
AE CRAE 0 23 Same as AC.
AF CRAF 23 Same as AC.
AH CRAH 0 Error in IMAGE statement.
AJ CRAJ 0 23 Same as AH
AL CRALxx 0 Error in PARTITION statement.
AP CRMN 0 3 Either reocvery option has has been selected during
a job, or OCL errors have occurred for this job.
0: Continue iwth next job, or no data cards in
reader for this job, otherwise, 3 to cancel.
AU CRAUxx 23 Error in PARTITION statement.
A CRA 23 Total number of volumes for a FILE statement
exceeds 40 (!).
A- CRA-xx 0 23 Error in PARTITION statement.
A' CRA' 3 No space remaining is System work area. Too many
FILE statements are in this job.
C1-C9 IFC1 123 1442 Check, various causes.
CL UDCLxx 1 3 5445 Data Interchange Utility error
E7 DKE7 0 3 Incorrect record length for attached 3741
E8 UTE8xx 1 3 Error in Tape Init VOL statement.
E9 UTE9xy 0 3 Error during Tape Init Processing.
F8 DDF8 3 RPG--LIne counter specs omitted and skip past
page size for printer.
F9 CIF9xy 23 Tape drive not available, x = drive #.
FA CIFA 3 Program requesting Data Recorder, unsupported.
FC CIFC 3 Program requesting CRT, unsupported.
FE DDFE 0 3 Program requesting line line on printer that
exceeds sysgen value.
FF RPQ routine error. Press start to continue.
FH CIFH 123 BSCA line not supported.
FJ CIFJ01 123 1442 not supported but requested
CIFJ02 123 3741 not supported but requested
FL CIFL 123 Printer/keyboard not supported or unavailable.
FP CIFP 123 Printer not supported or allocated to other level
FU CIFU 123 MFCU not supported or allocated to other level
FY CIFY 23 Device is not supported or in use.
F CIF 23 Conflict with a resource being used by other level.
H0-H9 0 23 RPG Programmed halt indicator is on.
HA CIHA 3 Out of space on $SOURCE during compile.
HC CIHC 3 Program given on LOAD statement not found.
HE Hardware error. Simulator has messed up.
HF CIHF 0 3 // COMPILE read but not required.
HJ CIHJ01 1 3 Program not found on removable unit, 1:
mount new unit and retry.
CIHJ02 3 Program not found, but removable unit in use.
HL CIHL 3 Inquiry request made but program is wrong type.
HP CIHP 3 Insufficient main storage for program.
LMHP 3 $MAINT function out of storage. NOTE: After the
cancel, IPL from the system pack or the pack will
be unusable.
HU CIHUxx 3 Source program not found on disk. IF a 1 option
is present, you can mount a new removeable pack.
HY CCHYNN 0 A checkpoint is received and accepted.
H CCH NN 0 23 A restart has been requested.
H' CIH' 3 An uninitialized pack has been referenced.
J0-J9 123 Record with specified match field out of sequence.
This is an RPG error, the 2nd digit indicates which
RPG file statement the error applies to in the
source program. 0=greater than statement 9,
otherwise indicates the file statement number.
JA CIJA 3 Trying to laod a program that requires or allows
inquiry while another inquiry program is running
in the other level.
JC CIJCxx 3 Program cannot be run for this reason (xx):
01: Must be dedicated and other level active
02: Program in other level must be dedicated
03: $$RSTR cannot run in level 2
04: CHeckpointed program not allowed in level 2
05: Program can't run while checkpoint active
JE CIJE 0 3 Level 1 partition too small.
JF CIJF 3 Attempt to start inquiry program but keyboard
in use.
JH CIJF 3 Attempt to start program which allows interrupts in
level 2.
JJ CIJJ 3 No object library on pack requested for load.
JL CIJL 3 Not enough storage for program. DPF only.
JP System input device in use by other level.
JU 0123 Cancel request made from interrupt key. 0: ignore
1: continue, request ignored
JY CIJYRD 0 2 Inquiry request made and accepted.
J- 3 Attempt to run a CCP program, but CCP not running.
J' 01 3 Inquiry request is completed, interrupted program
can now resume.
L0-L9 123 RPG. Unidentified record, 2nd digit gives file
statement number in source program 1-9, 0 means
greater than 9. Can also occur if record is out
of sequence.
LA CILA 23 Too little storage for number of files in program.
LC CILC 23 Too little storage for requested allocation.
LE CILE 23 No FILE or an incorrect FILE for a file requested
by current program.
LH CILH 23 No space given for an output file on FILE statement.
LJ CILJ 23 Attempt to output to existing permanent file.
LL CILL 0 23 Attempt to output over an existing temporary file.
LP CILP 23 File already exists.
LU CILU 123 Pack name requested but wrong pack mounted. 1:
retry after mounting correct pack.
LY CILYxx 23 Attempt to allocate space that isn't available.
xx=02 means space not available in split cylinder
area.
L LML CP 01 3 $MAINT detected attempt to modify a program on
a pack with an active checkpoint.
L- CIL- 3 Attempt to add a split cylinder to a split cyl
file while other level is fiddling with a split
cylinder file.
L' CIl' 23 Trying to allocate a split cylinder file before
allocating the first split cylinder file in a group.
P1-P8 Printer hardware errors, should not occur in sim.
PC IPPC 0 23 Unprintable character.
PH CIPH 23 LOCATION plus TRACKS goes past end of pack.
PJ CIPJxx 1 A Pack is to be remounted, pack name printed before
half code, xx= unit.
PU CIPU 3 Duplicate file names in the FILE statements.
PY CIPY01 3 ISAM file requires at least 2 tracks.
CIPY02 3 ISAM file can't be split cylinder.
P' CIP'xx 23 Too many scratch or work files.
U0-U9 0123 RPG. Unidentified record in file, 2nd digit of
halt is file statement in RPG source, 0= greater
than 9.
UA CIUA 3 Attempt to create a multivolume file in
invalid.
UC CIUC 3 The printed actived file cannot be found in the
list of scratch files.
UE CIUExx 1 3 PACK parameter does not match pack name on unit.
xx = Unit referenced.
1 = Mount another pack and continue.
UF CIUF 3 Disk file referenced by name and date not found.
UH CIUH 3 Attempt to create multivolume file failed,
because name alreayd exists.
UJ CIUJ 3 A LOCATION was specified for an existing disk file
and the file exists but not at that location.
UL CIUL 3 File on // FILE statement not found, and no size
in TRACKS or RECORDS was given.
UP CIUP 3 Permanent file referenced with RETAIN-S
UU CIUU 3 Disk Pack not available.
UY CIUY 3 File is a System/3 BASIC file which must be unique.
U CIU 3 Existing file: TRACKS/RECORDS or LOCATION mismatch.
U- General CCP halt. Press start to see subhalt.
Refer to CCP manual for more info.
U' CIU' 23 VTOC is full, or more than 2 multivolume files per
pack, or more than 2 ISAM files using HIKEY
parameter.
YH CRYH 0 3 Cards are being punched, but card read from
reader was not blank. This means you are trying to
punch with a file attached to the CDR device.
Unattach the file and take the zero option.
0 (blank 0) FILE WRITE switch in off position.
1 (blank 1) Permanent DIsk I/O Error
2 RC 211 3 COBOL. Out of room on $WORK.
RC 212 3 Out of room on $SOURCE.
RC 213 3 Out of room on $WORKX.
RC 214 3 Subprogram name table greater than 20.
RC 219 0 3 C or E level diagnostics during compile.
RC 2A1 23 Subscript invalid
RC 2A2 23 Negative exponent or 0 degrees in program
RC 2F1 23 MFCU File not open or opened improperly
RC 2F2 23 1442 File not open or opened improperly
RC 2F3 23 1403/5203 File not open or opened improperly
RC 2F4 23 5444 Disk File not open or opened improperly
RC 2F5 23 5444 File not open or opened improperly
RC 2F7 23 5444 File not open or opened improperly
RC 2F8 23 Tape File not open or opened improperly
RC 2H1 23 OPEN attempted after CLOSE WITH LOCK
RC 2H2 23 Error during ACCEPT
RC 2H3 23 $$STOP not found
RC 2H4 23 CHeckpoint could not be taken.
RC 2H5 23 $$STIC not found for ACCEPT
RC 2H6 23 Parameter mismatch CALL and USING
RC 2H7 23 ACCEPT after /& read
RC 2H8 23 OPEN for a file already OPEN
RC 2 0 3 Too little core for compile
RC 2 1 3 PROCEDURE or DATA division not found.
RC 2 3 3 Program has more than 65535 statements (!)
RC 2 4 3 Source name on COMPILE statement not found
3 R 3XX 0 3 COBOL Stop literal. XX is user-specified.
0 continues program 3 cancels.
4 VF 4NF 3 Program not found. Program library and
not printed before halt message.
6 RF 6XX 0 23 FORTRAN stop statement.
7 RF 701 23 Source member on COMPILE not found
RF 702 23 Object program too large for core.
8 CS 8 1 3 System input device allocated to other level.
9 CS 9 1 3 System input device has an error. This usually
means the card hopper is empty (i.e. EOF on the
file attached to the reader but SCP wants more
input).
A DC A 123 Number of characters entered from keyboard
incorrect.
C DD C 0 23 Unprintable character for printer/keyboard.
E DC E 123 Hardware error, PKB
F DC F 0 23 End of forms, PKB
L DD L 0 3 Records with duplicate keys have been loaded
into ISAM file. Each dup key is logged followed
by blank P halt. 0: continue. Index will
contain duplicate keys. 3: cancel, file is
not usable, reload it.
P DD P 0 3 Duplicate key encountered. The key is printed
on the log. 0: continue, halt will recur for
any other duplicates, then blank L appears.
U DD U 3 Disk I/O error while sorting ISAM index.
Y DD Y 3 System error during file termination.
-0 DD-0XX 3 ISAM multivolume file being used and high key
not found for current columme, or does not agree
with HIKEY spec. XX=unit number.
-1 DD-1XX 123 Halt -P occurred and option 0 taken. But, the
pack mounted is not a part of volume set.
-2 DD-2XX 123 Multivolume load sequence error.
-3 DD-3XX 123 Multivolume load sequence error.
-4 DD-4XX 0123 Warning that one or more volumes are about to be
bypassed.
-5 DD-5XX 123 Multivolume file not found. 1: mount correct pack.
-6 DD-6XX 0 23 Warning. ENd of volume and HIKEY not found.
-7 DD-7XX 1 3 -A halt and option 1 taken. But the pack referenced
does not match pack name.
-8 DD-8XX 3 Multivolume file referenced but file isn't
multivolume.
-9 DD-9XX 3 Add to a multivolumen file, but last pack not
mounted.
-A DD-AXX 1 3 Add to existing multivolume filebut no room.
-C DD-CXX 3 Multivolume file error. Probably out of sequence
volume mounts.
-E DD-EXX 123 Next volume cannot be processed, because the
location is not available or space is not available
or there are scratch files on the pack.
-F DD-Fxx 123 Finished a volume, next cannot be processed, mount
the correct pack or cancel.
-H DD-Hxx 3 HIKEY length does not match file.
-J DD-Jxx 01 3 First volume referenced is not volumme 1. 0:
continue with this volume, 1: mount another pack.
-L DD-Lxx 3 Output to multivolume, but file isn't multivolume
or referenced volume isn't first one of set.
-P DD-PXX 0123 Mount next volume. XX=unit number. 0: continue
bypassing volumes, 1: mount next volume.
-U DD-UXX 1 3 Halt -J just occurred and 0 or 1 taken. But the
pack name is incorrect or the file isn't found.
- DD- 123 Multivolume key error. Key too low or high for
volume.
-' DD-' 123 Sequential add to multivolume file, but HIKEY
record missing on previous volume.
'0 GM'0DE 3 SYSGEN. I/O Error on reader.
GM'0EX 3 SYSGEN. End of extent on MACOUT or $SOURCE.
GM'0IC 1 3 SYSGEN. Option dependent on a preceding option, the
preceding one was omitted or invalid.
GM'0ID 1 3 SYSGEN invalid delimiter.
GM'0IK 1 3 SYSGEN invalid keyword.
GM'0IR 1 3 SYSGEN invalid option.
GM'0IS 1 3 SYSGEN sequence error.
GM'0NF 1 3 SYSGEN entry in cols 8-12 not found.
GM'0NS 3 SYSGEN Requested source program not found.
GM'0EM 1 3 SYSGEN. END statement not found.
GM'0NP 3 SYSGEN. Module $SGXP2, $SGXP3, $SGXP4, $SGXP5, or
$SGXP6 missing for sysgen, or $MPXP2, $MPXP3 or
$MPXP4 missing for macro processor.
'1 GG'1 3 System Generation Errors.
'2 0 3 Error during macro processor run.
'3 3 Invalid 5445 disk label record.
'4 GG'4EX 3 Out of room on Sysgen, or disk error.
----------------------- End of haltguide.txt ---------------------------

78
S3/readme_s3.txt Normal file
View File

@ -0,0 +1,78 @@
Welcome to the IBM System/3 Model 10 SIMH simulator.
---------------------------------------------------
To compile under linux:
cc s3*.c scp*.c sim_rev.c -o s3
This code can be compiled and run as a console application using
Microsoft Visual C++.
To IPL the provided SCP distribution disk:
./s3
sim> at r1 m10scp.dsk
sim> at f1 f1f1f1.dsk
sim> at lpt print.txt
sim> d sr 5471
sim> boot r1
// DATE 06/14/01
// NOHALT
// LOAD $MAINT,R1
// RUN
// COPY FROM-R1,LIBRARY-ALL,NAME-DIR,TO-PRINT
// END
(A printout of the libraries and directories on the SCP DTR
disk will be in the file print.txt)
The text file "system3.txt" gives details on the simulators
implementation of System/3 hardware.
A write up on the use of the SCP and the OCL job control language is
in the text file "userguide.txt". This includes examples of using the
utility programs, and a tutorial guiding you thru a sysgen.
A nearly complete listing of all possible SCP halts is in the
document "haltguide.txt".
IMPORTANT NOTES:
1) How to correct typing errors when using the System/3 console:
If you make an error, press ESC, which will cancel the current
line being typed and print a quote in position 1. Then you
can use CTRL/R to retype characters up until the error, then
type correctly. Or simply retype the line. BACKSPACE DOES NOT
WORK with the SCP.
2) While the simulator allows disk images to be independently
attached to any disk unit, on the real hardware R1 and F1 were on
a single spindle, and R2 and F2 likewise. It is not possible using
SCP to attach R1 without attaching a disk image to F1 also, because
SCP will always look at F1 even when IPLed off R1.
The OS distributed with the simulator is version 16 of the Model
10 SCP. This is sysgenned with support only for R1 and F1. If you
do a sysgen to support R2 amd F2 also, you must have images attached
to all 4 disks when you IPL, because SCP looks at all drives when
it starts up, and you will get an "Unattached Unit" error if you
fail to have one attached.
3) The 1442 card reader had in reality one card input hopper
and two stackers. This means the same path is used for reading and
punching cards. When punching cards, SCP does a read operation
and inspects the card read for blanks, and if it is not blank,
issues a YH halt. SCP will not punch data onto non-blank cards.
This feature causes problems in the simulator, and as a result
if you punch cards from SCP, YOU MUST not have any file attached
to the CDR device. Leaving this device unattached presents an
infinite supply of blank cards to SCP for punching.
-- End of README_S3.txt --

448
S3/s3_cd.c Normal file
View File

@ -0,0 +1,448 @@
/* s3_cd.c: IBM 1442 card reader/punch
Copyright (c) 2001-2012, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Charles E. Owen shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Charles E. Owen.
cdr card reader
cdp card punch
cdp2 card punch stacker 2
19-Mar-12 RMS Fixed declaration of conversion tables (Mark Pizzolato)
25-Apr-03 RMS Revised for extended file support
08-Oct-02 RMS Added impossible function catcher
Normally, cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files. Set the EBCDIC
flag on the card unit allows cards to be read or punched in EBCDIC format,
suitable for binary data.
*/
#include "s3_defs.h"
#include <ctype.h>
extern uint8 M[];
extern unsigned char ebcdic_to_ascii[];
extern unsigned char ascii_to_ebcdic[];
int32 s1sel, s2sel;
char rbuf[CBUFSIZE]; /* > CDR_WIDTH */
t_stat cdr_svc (UNIT *uptr);
t_stat cdr_boot (int32 unitno, DEVICE *dptr);
t_stat cdr_attach (UNIT *uptr, char *cptr);
t_stat cd_reset (DEVICE *dptr);
t_stat read_card (int32 ilnt, int32 mod);
t_stat punch_card (int32 ilnt, int32 mod);
int32 DAR; /* Data address register */
int32 LCR; /* Length Count Register */
int32 lastcard = 0; /* Last card switch */
int32 carderr = 0; /* Error switch */
int32 pcherror = 0; /* Punch error */
int32 notready = 0; /* Not ready error */
int32 cdr_ebcdic = 0; /* EBCDIC mode on reader */
int32 cdp_ebcdic = 0; /* EBCDIC mode on punch */
extern int32 GetMem(int32 addr);
extern int32 PutMem(int32 addr, int32 data);
/* Card reader data structures
cdr_dev CDR descriptor
cdr_unit CDR unit descriptor
cdr_reg CDR register list
*/
UNIT cdr_unit = { UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 100 };
REG cdr_reg[] = {
{ FLDATA (LAST, lastcard, 0) },
{ FLDATA (ERR, carderr, 0) },
{ FLDATA (NOTRDY, notready, 0) },
{ HRDATA (DAR, DAR, 16) },
{ HRDATA (LCR, LCR, 16) },
{ FLDATA (EBCDIC, cdr_ebcdic, 0) },
{ FLDATA (S2, s2sel, 0) },
{ DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },
{ BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },
{ NULL }
};
DEVICE cdr_dev = {
"CDR", &cdr_unit, cdr_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cd_reset,
&cdr_boot, &cdr_attach, NULL
};
/* CDP data structures
cdp_dev CDP device descriptor
cdp_unit CDP unit descriptor
cdp_reg CDP register list
*/
UNIT cdp_unit = { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
REG cdp_reg[] = {
{ FLDATA (ERR, pcherror, 0) },
{ FLDATA (EBCDIC, cdp_ebcdic, 0) },
{ FLDATA (S2, s2sel, 0) },
{ FLDATA (NOTRDY, notready, 0) },
{ HRDATA (DAR, DAR, 16) },
{ HRDATA (LCR, LCR, 16) },
{ DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },
{ NULL }
};
DEVICE cdp_dev = {
"CDP", &cdp_unit, cdp_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cd_reset,
NULL, NULL, NULL
};
/* Stacker data structures
stack_dev STACK device descriptor
stack_unit STACK unit descriptors
stack_reg STACK register list
*/
UNIT stack_unit[] = {
{ UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }
};
REG stack_reg[] = {
{ DRDATA (POS0, stack_unit[0].pos, 32), PV_LEFT },
{ NULL }
};
DEVICE stack_dev = {
"CDP2", stack_unit, stack_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cd_reset,
NULL, NULL, NULL
};
/* -------------------------------------------------------------------- */
/* 1442: master routine */
int32 crd (int32 op, int32 m, int32 n, int32 data)
{
int32 iodata;
switch (op) {
case 0: /* SIO 1442 */
/* if (n == 1)
return STOP_IBKPT; */
switch (data) { /* Select stacker */
case 0x00:
break;
case 0x01:
s2sel = 1;
break;
default:
break;
}
switch (n) {
case 0x00: /* Feed */
iodata = SCPE_OK;
break;
case 0x01: /* Read only */
if (cdr_ebcdic)
iodata = read_card(0, 1);
else
iodata = read_card(0, 0);
break;
case 0x02: /* Punch and feed */
iodata = punch_card(0, 0);
break;
case 0x03: /* Read Col Binary */
iodata = read_card(0, 1);
break;
case 0x04: /* Punch no feed */
iodata = punch_card(0, 1);
break;
default:
return STOP_INVDEV;
}
return iodata;
case 1: /* LIO 1442 */
switch (n) {
case 0x00: /* Load LCR */
LCR = data & 0xffff;
break;
case 0x04:
DAR = data & 0xffff;
break;
default:
return STOP_INVDEV;
}
return SCPE_OK;
case 2: /* TIO 1442 */
iodata = 0;
switch (n) {
case 0x00: /* Error */
if (carderr || pcherror || notready)
iodata = 1;
if ((cdr_unit.flags & UNIT_ATT) == 0)
iodata = 1; /* attached? */
break;
case 0x02: /* Busy */
if (sim_is_active (&cdr_unit))
iodata = 1;
break;
default:
return (STOP_INVDEV << 16);
}
return ((SCPE_OK << 16) | iodata);
case 3: /* SNS 1442 */
iodata = 0;
switch (n) {
case 0x01:
break;
case 0x02:
break;
case 0x03:
if (carderr)
iodata |= 0x80;
if (lastcard)
iodata |= 0x40;
if (pcherror)
iodata |= 0x20;
if ((cdr_unit.flags & UNIT_ATT) == 0)
iodata |= 0x08;
if (notready)
iodata |= 0x08;
break;
case 0x04:
iodata = DAR;
break;
default:
return (STOP_INVDEV << 16);
}
iodata |= ((SCPE_OK << 16) & 0xffff0000);
return (iodata);
case 4: /* APL 1442 */
iodata = 0;
switch (n) {
case 0x00: /* Error */
if (carderr || pcherror || notready)
iodata = 1;
if ((cdr_unit.flags & UNIT_ATT) == 0)
iodata = 1; /* attached? */
break;
case 0x02: /* Busy */
if (sim_is_active (&cdr_unit))
iodata = 1;
break;
default:
return (STOP_INVDEV << 16);
}
return ((SCPE_OK << 16) | iodata);
default:
break;
}
sim_printf (">>CRD non-existent function %d\n", op);
return SCPE_OK;
}
/* Card read routine
mod 0 = ASCII read
mod 1 = EBCDIC read
*/
t_stat read_card (int32 ilnt, int32 mod)
{
int32 i;
t_stat r;
if (sim_is_active (&cdr_unit)) { /* busy? */
sim_cancel (&cdr_unit); /* cancel */
if (r = cdr_svc (&cdr_unit)) return r; /* process */
}
if (((cdp_unit.flags & UNIT_ATT) != 0 ||
(stack_unit[0].flags & UNIT_ATT) != 0) && /* Punch is attached and */
(cdr_unit.flags & UNIT_ATT) == 0) { /* reader is not --- */
for (i = 0; i < 80; i++) { /* Assume blank cards in hopper */
PutMem(DAR, 0x40);
DAR++;
}
sim_activate (&cdr_unit, cdr_unit.wait); /* activate */
return SCPE_OK;
}
if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */
lastcard = carderr = notready = s1sel = s2sel = 0; /* default stacker */
for (i = 0; i < CBUFSIZE; i++) rbuf[i] = 0x20; /* clear buffer */
if (mod) {
for (i = 0; i < 80; i++) {
rbuf[i] = fgetc(cdr_unit.fileref); /* Read EBCDIC */
}
} else {
fgets (rbuf, CBUFSIZE, cdr_unit.fileref); /* read Ascii */
}
if (feof (cdr_unit.fileref)) { /* eof? */
notready = 1;
return STOP_NOCD;
}
if (ferror (cdr_unit.fileref)) { /* error? */
perror ("Card reader I/O error");
clearerr (cdr_unit.fileref);
carderr = 1;
return SCPE_OK; }
cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */
i = getc (cdr_unit.fileref); /* see if more */
if (feof (cdr_unit.fileref)) lastcard = 1; /* eof? set flag */
fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET);
for (i = 0; i < 80; i++) {
if (mod == 0) { /* If ASCII mode... */
if (rbuf[i] == '\n' || /* remove ASCII CR/LF */
rbuf[i] == '\r' ||
rbuf[i] == 0x00)
rbuf[i] = ' ';
rbuf[i] = ascii_to_ebcdic[rbuf[i]]; /* convert to EBCDIC */
}
PutMem(DAR, rbuf[i]); /* Copy to main memory */
DAR++;
}
sim_activate (&cdr_unit, cdr_unit.wait); /* activate */
return SCPE_OK;
}
/* Card reader service. If a stacker select is active, copy to the
selected stacker. Otherwise, copy to the normal stacker. If the
unit is unattached, simply exit.
*/
t_stat cdr_svc (UNIT *uptr)
{
int32 i;
if (s2sel) uptr = &stack_unit[0]; /* stacker 1? */
else uptr = &stack_unit[0]; /* then default */
if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
for (i = 0; (size_t)i < CDR_WIDTH; i++) rbuf[i] = ebcdic_to_ascii[rbuf[i]];
for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0;
rbuf[CDR_WIDTH] = 0; /* null at end */
fputs (rbuf, uptr -> fileref); /* write card */
fputc ('\n', uptr -> fileref); /* plus new line */
if (ferror (uptr -> fileref)) { /* error? */
perror ("Card stacker I/O error");
clearerr (uptr -> fileref);
}
uptr -> pos = ftell (uptr -> fileref); /* update position */
return SCPE_OK;
}
/* Card punch routine
mod: not used
*/
t_stat punch_card (int32 ilnt, int32 mod)
{
int32 i, colcount;
static char pbuf[CDP_WIDTH + 1]; /* + null */
UNIT *uptr;
if (s2sel) uptr = &stack_unit[0]; /* stack 2? */
else uptr = &cdp_unit; /* normal output */
if ((uptr -> flags & UNIT_ATT) == 0) { /* Attached? */
notready = 1;
return SCPE_OK;
}
pcherror = s1sel = notready = 0; /* clear flags */
colcount = 128 - LCR;
for (i = 0; i < colcount; i++) { /* Fetch data */
if (cdp_ebcdic)
pbuf[i] = GetMem(DAR) & 0xff;
else
pbuf[i] = ebcdic_to_ascii[GetMem(DAR)];
DAR++;
}
for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) pbuf[i] = 0;
pbuf[CDP_WIDTH] = 0; /* trailing null */
if (!cdp_ebcdic) {
fputs (pbuf, uptr -> fileref); /* output card */
fputc ('\n', uptr -> fileref); /* plus new line */
} else {
for (i = 0; i < 80; i++) {
fputc(pbuf[i], uptr -> fileref);
}
}
if (ferror (uptr -> fileref)) { /* error? */
perror ("Card punch I/O error");
clearerr (uptr -> fileref);
pcherror = 1;
}
uptr -> pos = ftell (uptr -> fileref); /* update position */
return SCPE_OK;
}
/* Select stack routine
Modifiers have been checked by the caller
Modifiers are 1, 2, for the respective stack
*/
t_stat select_stack (int32 ilnt, int32 mod)
{
if (mod == 1) s1sel = 1;
else if (mod == 2) s2sel = 1;
return SCPE_OK;
}
/* Card reader/punch reset */
t_stat cd_reset (DEVICE *dptr)
{
lastcard = carderr = notready = pcherror = 0; /* clear indicators */
s1sel = s2sel = 0; /* clear stacker sel */
sim_cancel (&cdr_unit); /* clear reader event */
return SCPE_OK;
}
/* Card reader attach */
t_stat cdr_attach (UNIT *uptr, char *cptr)
{
carderr = lastcard = notready = 0; /* clear last card */
return attach_unit (uptr, cptr);
}
/* Bootstrap routine */
t_stat cdr_boot (int32 unitno, DEVICE *dptr)
{
cdr_ebcdic = 1;
DAR = 0;
LCR = 80;
read_card(0, 1);
return SCPE_OK;
}

1830
S3/s3_cpu.c Normal file

File diff suppressed because it is too large Load Diff

94
S3/s3_defs.h Normal file
View File

@ -0,0 +1,94 @@
/* s3_defs.h: IBM System/3 simulator definitions
Copyright (c) 2001-2005, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Charles E. Owen shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Charles E. Owen.
*/
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_INVOP 4 /* program check - invalid op */
#define STOP_INVQ 5 /* Prog check - invalid Q */
#define STOP_INVADDR 6 /* Prog check - invalid addr */
#define STOP_INVDEV 7 /* Prog check - invalid dev cmd */
#define STOP_NOCD 8 /* ATTN card reader */
#define RESET_INTERRUPT 77 /* special return from SIO */
/* Memory */
#define MAXMEMSIZE 65536 /* max memory size */
#define AMASK (MAXMEMSIZE - 1) /* logical addr mask */
#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MAX_DECIMAL_DIGITS 31 /* max size of a decimal number */
#define CDR_WIDTH 80 /* Max card size */
#define CDP_WIDTH 80 /* Punch width */
#define LPT_WIDTH 132
#define CCT_LNT 132
#define DSK_SECTSIZE 256 /* Sector length */
#define DSK_CYLSIZE 256*48 /* Cylinder length */
/* I/O structure
The I/O structure is tied together by dev_table, indexed by
the device number. Each entry in dev_table consists of
level Interrupt level for device (0-7)
priority Priority for device (1-8)
routine IOT action routine
*/
struct ndev {
int32 level; /* interrupt level */
int32 pri; /* Device priority */
int32 (*routine)(int32, int32, int32, int32); /* dispatch routine */
};
/* Structure to define operation codes */
struct opdef {
char op[6]; /* Mnemonic for op */
int32 opmask; /* Bits set on in opcode */
int32 q; /* Qbyte */
int32 form; /* Forms are:
0 - 1-byte hex operand
1 - 1-byte register addr, A-Addr
2 - A-addr,B-addr,Qbyte
3 - A-addr,Qbyte
4 - da,m,n
5 - da,m,n,cc
6 - da,m,n,A-addr
7 - 1-address implict Q
8 - 2-address implict Q */
int32 group; /* Group Code:
0 - Command Format (0xFx)
1 - 1-address A (0x<C,D,E>x)
2 - 2-address (0x<0,1,2,4,5,6,8,9,A>x)
3 - 1-address B (0x<3,7,B>x) */
};

792
S3/s3_disk.c Normal file
View File

@ -0,0 +1,792 @@
/* s3_disk.c: IBM 5444 Disk Drives
Copyright (c) 2001-2005, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Charles E. Owen shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Charles E. Owen.
r1 Removeable disk 1
f1 Fixed disk 1
r2 Removeable disk 2
f2 Fixed disk 2
25-Apr-03 RMS Revised for extended file support
08-Oct-02 RMS Added impossible function catcher
*/
#include "s3_defs.h"
#include <ctype.h>
extern uint8 M[];
extern int32 IAR[], level;
extern FILE *trace;
extern int32 debug_reg;
char dbuf[DSK_SECTSIZE]; /* Disk buffer */
int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data);
int32 read_sector(UNIT *uptr, char *dbuf, int32 sect);
int32 write_sector(UNIT *uptr, char *dbuf, int32 sect);
t_stat r1_svc (UNIT *uptr);
t_stat r1_boot (int32 unitno, DEVICE *dptr);
t_stat r1_attach (UNIT *uptr, char *cptr);
t_stat r1_reset (DEVICE *dptr);
t_stat f1_svc (UNIT *uptr);
t_stat f1_boot (int32 unitno, DEVICE *dptr);
t_stat f1_attach (UNIT *uptr, char *cptr);
t_stat f1_reset (DEVICE *dptr);
t_stat r2_svc (UNIT *uptr);
t_stat r2_boot (int32 unitno, DEVICE *dptr);
t_stat r2_attach (UNIT *uptr, char *cptr);
t_stat r2_reset (DEVICE *dptr);
t_stat f2_svc (UNIT *uptr);
t_stat f2_boot (int32 unitno, DEVICE *dptr);
t_stat f2_attach (UNIT *uptr, char *cptr);
t_stat f2_reset (DEVICE *dptr);
extern int32 GetMem(int32 addr);
extern int32 PutMem(int32 addr, int32 data);
char opstr[5][5] = { "SIO", "LIO", "TIO", "SNS", "APL" };
int32 DDAR[2]; /* Data address register */
int32 DCAR[2]; /* Disk Control Address Register */
int32 diskerr[2] = { 0, 0 }; /* Error status */
int32 notrdy[2] = { 0, 0 }; /* Not ready error */
int32 seekbusy[2] = { 0, 0 }; /* Drive busy flags */
int32 seekhead[2] = { 0, 0 }; /* Disk head 0,1 */
int32 found[2] = { 0, 0 }; /* Scan found bit */
int32 RIDsect[2] = { 0, 0 }; /* for Read ID */
/* Disk data structures
xy_dev CDR descriptor
xy_unit CDR unit descriptor
xy_reg CDR register list
x = F or R
y = 1 or 2
*/
UNIT r1_unit = { UDATA (&r1_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
REG r1_reg[] = {
{ FLDATA (NOTRDY, notrdy[0], 0) },
{ FLDATA (SEEK, seekbusy[0], 0) },
{ HRDATA (DAR, DDAR[0], 16) },
{ HRDATA (CAR, DCAR[0], 16) },
{ HRDATA (ERR, diskerr[0], 16) },
{ DRDATA (CYL, r1_unit.u3, 8) },
{ DRDATA (HEAD, seekhead[0], 8) },
{ DRDATA (POS, r1_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, r1_unit.wait, 24), PV_LEFT },
{ BRDATA (BUF, dbuf, 8, 8, 256) },
{ NULL }
};
DEVICE r1_dev = {
"R1", &r1_unit, r1_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &r1_reset,
&r1_boot, &r1_attach, NULL
};
UNIT f1_unit = { UDATA (&f1_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
REG f1_reg[] = {
{ FLDATA (NOTRDY, notrdy[0], 0) },
{ FLDATA (SEEK, seekbusy[0], 0) },
{ HRDATA (DAR, DDAR[0], 16) },
{ HRDATA (CAR, DCAR[0], 16) },
{ HRDATA (ERR, diskerr[0], 16) },
{ DRDATA (CYL, f1_unit.u3, 8) },
{ DRDATA (HEAD, seekhead[0], 8) },
{ DRDATA (POS, f1_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, f1_unit.wait, 24), PV_LEFT },
{ BRDATA (BUF, dbuf, 8, 8, 256) },
{ NULL }
};
DEVICE f1_dev = {
"F1", &f1_unit, f1_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &f1_reset,
&f1_boot, &f1_attach, NULL
};
UNIT r2_unit = { UDATA (&r2_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
REG r2_reg[] = {
{ FLDATA (NOTRDY, notrdy[1], 0) },
{ FLDATA (SEEK, seekbusy[1], 0) },
{ HRDATA (DAR, DDAR[1], 16) },
{ HRDATA (CAR, DCAR[1], 16) },
{ HRDATA (ERR, diskerr[1], 16) },
{ DRDATA (CYL, r2_unit.u3, 8) },
{ DRDATA (HEAD, seekhead[1], 8) },
{ DRDATA (POS, r2_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, r2_unit.wait, 24), PV_LEFT },
{ BRDATA (BUF, dbuf, 8, 8, 256) },
{ NULL }
};
DEVICE r2_dev = {
"R2", &r2_unit, r2_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &r2_reset,
&r2_boot, &r2_attach, NULL
};
UNIT f2_unit = { UDATA (&f2_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
REG f2_reg[] = {
{ FLDATA (NOTRDY, notrdy[1], 0) },
{ FLDATA (SEEK, seekbusy[1], 0) },
{ HRDATA (DAR, DDAR[1], 16) },
{ HRDATA (CAR, DCAR[1], 16) },
{ HRDATA (ERR, diskerr[1], 16) },
{ DRDATA (CYL, f2_unit.u3, 8) },
{ DRDATA (HEAD, seekhead[1], 8) },
{ DRDATA (POS, f2_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, f2_unit.wait, 24), PV_LEFT },
{ BRDATA (BUF, dbuf, 8, 8, 256) },
{ NULL }
};
DEVICE f2_dev = {
"F2", &f2_unit, f2_reg, NULL,
1, 10, 31, 1, 8, 7,
NULL, NULL, &f2_reset,
&f2_boot, &f2_attach, NULL
};
/* -------------------------------------------------------------------- */
/* 5444: master routines */
int32 dsk1 (int32 op, int32 m, int32 n, int32 data)
{
int32 r;
r = dsk(0, op, m, n, data);
return (r);
}
int32 dsk2 (int32 op, int32 m, int32 n, int32 data)
{
int32 r;
r = dsk(1, op, m, n, data);
return (r);
}
/* 5444: operational routine */
int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data)
{
int32 iodata, i, j, u, sect, nsects, addr, r, c, res;
int32 F, C, S, N, usave;
UNIT *uptr;
u = m;
if (disk == 1) u += 2;
F = GetMem(DCAR[disk]+0); /* Flag bits */
C = GetMem(DCAR[disk]+1); /* Cylinder */
S = GetMem(DCAR[disk]+2); /* Sector */
N = GetMem(DCAR[disk]+3); /* Number of sectors */
switch (u) {
case 0:
uptr = r1_dev.units;
break;
case 1:
uptr = f1_dev.units;
break;
case 2:
uptr = r2_dev.units;
break;
case 3:
uptr = f2_dev.units;
break;
default:
break;
}
if (debug_reg & 0x02)
fprintf(trace, "==> %04X %s %01X,%d,%04X DAR=%04X CAR=%04X C=%02X, S=%02X, N=%02X\n",
IAR[level],
opstr[op],
m, n, data,
DDAR[disk],
DCAR[disk],
C, S, N);
switch (op) {
/* SIO 5444 */
case 0:
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
diskerr[disk] = 0; /* SIO resets errors */
found[disk] = 0; /* ... and found bit */
iodata = 0;
switch (n) {
case 0x00: /* Seek */
if (S & 0x80)
seekhead[disk] = 1;
else
seekhead[disk] = 0;
if (S & 1) {
uptr -> u3 += N;
} else {
uptr -> u3 -= N;
}
if (uptr -> u3 < 0)
uptr -> u3 = 0;
if (uptr -> u3 > 203) {
uptr -> u3 = 0;
diskerr[disk] |= 0x0100;
if (debug_reg & 0x02)
fprintf(trace, "==> Seek Past End of Disk\n");
}
/*sim_activate(uptr, uptr -> wait);*/
sim_activate(uptr, 1);
/* Seek arms are the same for both disks on a drive:
update the other arm */
usave = uptr -> u3;
if (u == 0) uptr = f1_dev.units;
if (u == 1) uptr = r1_dev.units;
if (u == 2) uptr = f2_dev.units;
if (u == 3) uptr = r2_dev.units;
uptr -> u3 = usave;
seekbusy[disk] = 1;
iodata = SCPE_OK;
break;
case 0x01: /* Read */
switch (data) {
case 0: /* Read data */
sect = (S >> 2) & 0x3F;
nsects = N + 1;
addr = DDAR[disk];
for (i = 0; i < nsects; i++) {
r = read_sector(uptr, dbuf, sect);
if (r != 1 || uptr->u3 != C) {
diskerr[disk] |= 0x0800;
break;
}
for (j = 0; j < DSK_SECTSIZE; j++) {
PutMem(addr, dbuf[j]);
addr++;
}
if (sect == 55) { /* HJS MODS */
S = sect;
N = nsects - i - 2;
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
DDAR[disk] = addr & 0xFFFF; /* HJS mod */
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
sim_activate(uptr, 1);
iodata = SCPE_OK;
break;
}
sect++;
S = sect - 1;
N = nsects - i - 2;
if (sect == 24)
sect = 32;
}
DDAR[disk] = addr & 0xFFFF; /* HJS mod */
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
/*sim_activate(uptr, uptr -> wait);*/
sim_activate(uptr, 1);
iodata = SCPE_OK;
break;
case 1: /* Read ID */
if (uptr -> u3 > 0 && uptr -> u3 < 4)
PutMem(DCAR[disk], 1);
else
PutMem(DCAR[disk], 0);
PutMem(DCAR[disk]+1, uptr -> u3);
PutMem(DCAR[disk]+2, RIDsect[disk]);
RIDsect[disk]++;
if (RIDsect[disk] > 23)
RIDsect[disk] = 32;
if (RIDsect[disk] > 55)
RIDsect[disk] = 0;
break;
case 2: /* Read Diagnostic */
iodata = STOP_INVDEV;
break;
case 3: /* Verify */
sect = (S >> 2) & 0x3F;
nsects = N + 1;
addr = DDAR[disk];
for (i = 0; i < nsects; i++) {
r = read_sector(uptr, dbuf, sect);
if (r != 1 || uptr->u3 != C) {
diskerr[disk] |= 0x0800;
break;
}
if (sect == 55) { /* HJS MODS */
S = sect;
N = nsects - i - 2;
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
DDAR[disk] = addr & 0xFFFF;
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
sim_activate(uptr, 1);
iodata = SCPE_OK;
break;
}
sect++;
S = sect - 1;
N = nsects - i - 2;
if (sect == 24)
sect = 32;
}
DDAR[disk] = addr & 0xFFFF;
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
/*sim_activate(uptr, uptr -> wait);*/
sim_activate(uptr, 1);
break;
default:
return STOP_INVDEV;
}
break;
case 0x02: /* Write */
switch (data) {
case 0: /* Write Data */
sect = (S >> 2) & 0x3F;
nsects = N + 1;
addr = DDAR[disk];
for (i = 0; i < nsects; i++) {
for (j = 0; j < DSK_SECTSIZE; j++) {
dbuf[j] = GetMem(addr);
addr++;
}
r = write_sector(uptr, dbuf, sect);
if (r != 1 || uptr->u3 != C) {
diskerr[disk] |= 0x0400;
break;
}
if (sect == 55) { /* HJS MODS */
S = sect;
N = nsects - i - 2;
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
DDAR[disk] = addr & 0xFFFF;
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
sim_activate(uptr, 1);
iodata = SCPE_OK;
break;
}
sect++;
S = sect - 1;
N = nsects - i - 2;
if (sect == 24)
sect = 32;
}
DDAR[disk] = addr & 0xFFFF; /* HJS mod */
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
/*sim_activate(uptr, uptr -> wait);*/
sim_activate(uptr, 1);
break;
case 1: /* Write identifier */
if (seekhead[disk] == 0)
S = 0;
else
S = 0x80;
N = 23;
sect = (S >> 2) & 0x3F;
nsects = N + 1;
addr = DDAR[disk];
for (i = 0; i < nsects; i++) {
for (j = 0; j < DSK_SECTSIZE; j++) {
dbuf[j] = GetMem(addr);
}
r = write_sector(uptr, dbuf, sect);
if (r != 1) {
diskerr[disk] |= 0x0400;
break;
}
if (sect == 55) {
S = sect;
N = nsects - i - 2;
if (N > 0) diskerr[disk] |= 0x0020;
DDAR[disk] = addr & 0xFFFF;
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
sim_activate(uptr, 1);
iodata = SCPE_OK;
break;
}
sect++;
S = sect - 1;
N = nsects - i - 2;
if (sect == 24)
sect = 32;
}
DDAR[disk] = addr & 0xFFFF;
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
/*sim_activate(uptr, uptr -> wait);*/
sim_activate(uptr, 1);
break;
default:
return STOP_INVDEV;
}
break;
case 0x03: /* Scan */
sect = (S >> 2) & 0x3F;
nsects = N + 1;
addr = DDAR[disk];
for (i = 0; i < nsects; i++) {
r = read_sector(uptr, dbuf, sect);
if (r != 1 || uptr->u3 != C) {
diskerr[disk] |= 0x0800;
break;
}
res = 0;
for (j = 0; j < DSK_SECTSIZE; j++) {
c = GetMem(addr);
if (j != 0xff) {
if (dbuf[i] < c)
res = 1;
if (dbuf[i] > c)
res = 3;
}
addr++;
}
if (res == 0)
found[disk] = 1;
if (res == data)
break;
if (sect == 55) { /* HJS MODS */
S = sect;
N = nsects - i - 2;
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
DDAR[disk] = addr & 0xFFFF;
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
sim_activate(uptr, 1);
iodata = SCPE_OK;
break;
}
sect++;
S = sect - 1;
N = nsects - i - 2;
if (sect == 24)
sect = 32;
}
PutMem(DCAR[disk]+2, S << 2);
PutMem(DCAR[disk]+3, N);
/*sim_activate(uptr, uptr -> wait);*/
sim_activate(uptr, 1);
break;
default:
return STOP_INVDEV;
}
return iodata;
/* LIO 5444 */
case 1:
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
switch (n) {
case 0x04: /* Data Addr */
DDAR[disk] = data;
break;
case 0x06: /* Control Addr */
DCAR[disk] = data;
break;
default:
return STOP_INVDEV;
}
return SCPE_OK;
/* TIO 5444 */
case 2:
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT << 16;
iodata = 0;
switch (n) {
case 0x00: /* Error */
if (diskerr[disk] || notrdy[disk])
iodata = 1;
if ((uptr -> flags & UNIT_ATT) == 0)
iodata = 1;
break;
case 0x02: /* Busy */
if (sim_is_active (uptr))
iodata = 1;
break;
case 0x04:
if (found[disk])
iodata = 1;
break;
default:
return (STOP_INVDEV << 16);
}
return ((SCPE_OK << 16) | iodata);
/* SNS 5444 */
case 3:
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT << 16;
iodata = 0;
switch (n) {
case 0x01:
break;
case 0x02:
iodata = diskerr[disk];
if (notrdy[disk])
iodata |= 0x4000;
if ((uptr -> flags & UNIT_ATT) == 0)
iodata |= 0x4000;
if (seekbusy[disk])
iodata |= 0x0010;
if (uptr -> u3 == 0)
iodata |= 0x0040;
break;
case 0x03:
iodata = 0;
break;
case 0x04:
iodata = DDAR[disk];
break;
case 0x06:
iodata = DCAR[disk];
break;
default:
return (STOP_INVDEV << 16);
}
iodata |= ((SCPE_OK << 16) & 0xffff0000);
return (iodata);
/* APL 5444 */
case 4:
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT << 16;
iodata = 0;
switch (n) {
case 0x00: /* Error */
if (diskerr[disk] || notrdy[disk])
iodata = 1;
if ((uptr -> flags & UNIT_ATT) == 0)
iodata = 1;
break;
case 0x02: /* Busy */
if (sim_is_active (uptr))
iodata = 1;
break;
default:
return (STOP_INVDEV << 16);
}
return ((SCPE_OK << 16) | iodata);
default:
break;
}
sim_printf (">>DSK%d non-existent function %d\n", disk, op);
return SCPE_OK;
}
/* Disk unit service. If a stacker select is active, copy to the
selected stacker. Otherwise, copy to the normal stacker. If the
unit is unattached, simply exit.
*/
t_stat r1_svc (UNIT *uptr)
{
seekbusy[0] = 0;
return SCPE_OK;
}
t_stat f1_svc (UNIT *uptr)
{
seekbusy[0] = 0;
return SCPE_OK;
}
t_stat r2_svc (UNIT *uptr)
{
seekbusy[1] = 0;
return SCPE_OK;
}
t_stat f2_svc (UNIT *uptr)
{
seekbusy[1] = 0;
return SCPE_OK;
}
/* Disk reset */
t_stat r1_reset (DEVICE *dptr)
{
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear indicators */
found[0] = 0;
sim_cancel (&r1_unit); /* clear event */
r1_unit.u3 = 0; /* cylinder 0 */
return SCPE_OK;
}
t_stat f1_reset (DEVICE *dptr)
{
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear indicators */
found[0] = 0;
sim_cancel (&f1_unit); /* clear event */
f1_unit.u3 = 0; /* cylinder 0 */
return SCPE_OK;
}
t_stat r2_reset (DEVICE *dptr)
{
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear indicators */
found[1] = 0;
sim_cancel (&r2_unit); /* clear event */
r2_unit.u3 = 0; /* cylinder 0 */
return SCPE_OK;
}
t_stat f2_reset (DEVICE *dptr)
{
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear indicators */
found[1] = 0;
sim_cancel (&f2_unit); /* clear event */
f2_unit.u3 = 0; /* cylinder 0 */
return SCPE_OK;
}
/* Disk unit attach */
t_stat r1_attach (UNIT *uptr, char *cptr)
{
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear status */
found[0] = 0;
uptr -> u3 = 0; /* cylinder 0 */
return attach_unit (uptr, cptr);
}
t_stat f1_attach (UNIT *uptr, char *cptr)
{
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear status */
found[0] = 0;
uptr -> u3 = 0; /* cylinder 0 */
return attach_unit (uptr, cptr);
}
t_stat r2_attach (UNIT *uptr, char *cptr)
{
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear status */
found[1] = 0;
uptr -> u3 = 0; /* cylinder 0 */
return attach_unit (uptr, cptr);
}
t_stat f2_attach (UNIT *uptr, char *cptr)
{
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear status */
found[1] = 0;
uptr -> u3 = 0; /* cylinder 0 */
return attach_unit (uptr, cptr);
}
/* Bootstrap routine */
t_stat r1_boot (int32 unitno, DEVICE *dptr)
{
int i;
r1_unit.u3 = 0;
read_sector(r1_dev.units, dbuf, 0);
for (i = 0; i < 256; i++) {
M[i] = dbuf[i];
}
return SCPE_OK;
}
t_stat f1_boot (int32 unitno, DEVICE *dptr)
{
int i;
f1_unit.u3 = 0;
read_sector(f1_dev.units, dbuf, 0);
for (i = 0; i < 256; i++) {
M[i] = dbuf[i];
}
return SCPE_OK;
}
t_stat r2_boot (int32 unitno, DEVICE *dptr)
{
int i;
r2_unit.u3 = 0;
read_sector(r2_dev.units, dbuf, 0);
for (i = 0; i < 256; i++) {
M[i] = dbuf[i];
}
return SCPE_OK;
}
t_stat f2_boot (int32 unitno, DEVICE *dptr)
{
int i;
f2_unit.u3 = 0;
read_sector(f2_dev.units, dbuf, 0);
for (i = 0; i < 256; i++) {
M[i] = dbuf[i];
}
return SCPE_OK;
}
/* Raw Disk Data In/Out */
int32 read_sector(UNIT *uptr, char *dbuf, int32 sect)
{
static int32 rtn, realsect;
static long pos;
/* calculate real sector no */
if (sect > 23)
realsect = sect - 8;
else
realsect = sect;
/* physically read the sector */
pos = DSK_CYLSIZE * uptr -> u3;
pos += DSK_SECTSIZE * realsect;
rtn = fseek(uptr -> fileref, pos, 0);
rtn = fread(dbuf, DSK_SECTSIZE, 1, uptr -> fileref);
return (rtn);
}
int32 write_sector(UNIT *uptr, char *dbuf, int32 sect)
{
static int32 rtn, realsect;
static long pos;
/* calculate real sector no */
if (sect > 23)
realsect = sect - 8;
else
realsect = sect;
if (uptr -> u3 == 0 && realsect == 32)
rtn = 0;
/* physically write the sector */
pos = DSK_CYLSIZE * uptr -> u3;
pos += DSK_SECTSIZE * realsect;
rtn = fseek(uptr -> fileref, pos, 0);
rtn = fwrite(dbuf, DSK_SECTSIZE, 1, uptr -> fileref);
return (rtn);
}

364
S3/s3_lp.c Normal file
View File

@ -0,0 +1,364 @@
/* s3_lp.c: IBM 1403 line printer simulator
Copyright (c) 2001-2012, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Charles E. Owen shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Charles E. Owen.
lpt 1403 line printer
19-Mar-12 RMS Fixed declaration of conversion tables (Mark Pizzolato)
25-Apr-03 RMS Revised for extended file support
08-Oct-02 RMS Added impossible function catcher
*/
#include "s3_defs.h"
extern uint8 M[];
extern char bcd_to_ascii[64];
extern int32 iochk, ind[64];
int32 cct[CCT_LNT] = { 03 };
int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0;
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat write_line (int32 ilnt, int32 mod);
t_stat space (int32 lines, int32 lflag);
t_stat carriage_control (int32 action, int32 mod);
extern unsigned char ebcdic_to_ascii[];
#define UNIT_V_PCHAIN (UNIT_V_UF + 0)
#define UNIT_M_PCHAIN 03
#define M_UCS 00 /* Universal */
#define M_PCF 00 /* full */
#define M_PCA 01 /* business */
#define M_PCH 02 /* Fortran */
#define UNIT_PCHAIN (UNIT_M_PCHAIN << UNIT_V_PCHAIN)
#define UCS (M_UCS << UNIT_V_PCHAIN)
#define PCF (M_PCF << UNIT_V_PCHAIN)
#define PCA (M_PCA << UNIT_V_PCHAIN)
#define PCH (M_PCH << UNIT_V_PCHAIN)
#define GET_PCHAIN(x) (((x) >> UNIT_V_PCHAIN) & UNIT_M_PCHAIN)
#define CHP(ch,val) ((val) & (1 << (ch)))
int32 LPDAR; /* Data Address */
int32 LPFLR; /* Forms Length */
int32 LPIAR; /* Image address */
int32 linectr; /* current line # */
int32 lpterror = 0;
int32 CC9 = 0;
int32 CC12 = 0;
/* LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit descriptor
lpt_reg LPT register list
*/
UNIT lpt_unit = { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) };
REG lpt_reg[] = {
{ FLDATA (ERR, lpterror, 0) },
{ HRDATA (LPDAR, LPDAR, 16) },
{ HRDATA (LPFLR, LPFLR, 8) },
{ HRDATA (LPIAR, LPIAR, 16) },
{ DRDATA (LINECT, linectr, 8) },
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT },
{ BRDATA (CCT, cct, 8, 32, CCT_LNT) },
{ DRDATA (LINES, lines, 8), PV_LEFT },
{ DRDATA (CCTP, cctptr, 8), PV_LEFT },
{ DRDATA (CCTL, cctlnt, 8), REG_RO + PV_LEFT },
{ GRDATA (CHAIN, lpt_unit.flags, 10, 2, UNIT_V_PCHAIN), REG_HRO },
{ NULL }
};
MTAB lpt_mod[] = {
{ UNIT_PCHAIN, UCS, "UCS", "UCS", NULL },
{ UNIT_PCHAIN, PCA, "A chain", "PCA", NULL },
{ UNIT_PCHAIN, PCH, "H chain", "PCH", NULL },
{ 0 }
};
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 7,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL
};
/* -------------------------------------------------------------------- */
/* Printer: master routine */
int32 lpt (int32 op, int32 m, int32 n, int32 data)
{
int32 iodata;
switch (op) {
case 0: /* SIO 1403 */
iodata = 0;
// printf("\0");
switch (n) {
case 0x00: /* Spacing only */
if (data > 0 && data < 4)
iodata = carriage_control(2, data);
break;
case 0x02: /* Print & space */
iodata = write_line(0, 0);
if (data > 3) data = 0;
if (iodata == SCPE_OK)
iodata = carriage_control(2, data);
break;
case 0x04: /* Skip only */
iodata = carriage_control(4, data);
break;
case 0x06: /* Print and skip */
iodata = write_line(0, 0);
if (iodata == SCPE_OK)
iodata = carriage_control(4, data);
break;
default:
return STOP_INVDEV;
}
return iodata;
case 1: /* LIO 1403 */
switch (n) {
case 0x00: /* LPFLR */
LPFLR = (data >> 8) & 0xff;
break;
case 0x04:
LPIAR = data & 0xffff;
break;
case 0x06:
LPDAR = data & 0xffff;
break;
default:
return STOP_INVDEV;
}
return SCPE_OK;
case 2: /* TIO 1403 */
iodata = 0;
switch (n) {
case 0x00: /* Not ready/check */
if (lpterror)
iodata = 1;
if ((lpt_unit.flags & UNIT_ATT) == 0)
iodata = 1;
break;
case 0x02: /* Buffer Busy */
iodata = 0;
break;
case 0x04: /* Carriage Busy */
iodata = 0;
break;
case 0x06: /* Printer busy */
iodata = 0;
break;
default:
return (STOP_INVDEV << 16);
}
return ((SCPE_OK << 16) | iodata);
case 3: /* SNS 1403 */
switch (n) {
case 0x00: /* Line count */
iodata = (linectr << 8);
break;
case 0x02: /* Timing data */
iodata = 0;
break;
case 0x03: /* Check data */
iodata = 0;
break;
case 0x04: /* LPIAR */
iodata = LPIAR;
break;
case 0x06: /* LPDAR */
iodata = LPDAR;
break;
default:
return (STOP_INVDEV << 16);
}
return ((SCPE_OK << 16) | iodata);
case 4: /* APL 1403 */
iodata = 0;
return ((SCPE_OK << 16) | iodata);
default:
break;
}
sim_printf (">>LPT non-existent function %d\n", op);
return SCPE_OK;
}
/* Print routine
Modifiers have been checked by the caller
S = suppress automatic newline
*/
t_stat write_line (int32 ilnt, int32 mod)
{
int32 i, t, lc;
static char lbuf[LPT_WIDTH + 1]; /* + null */
if ((lpt_unit.flags & UNIT_ATT) == 0)
return SCPE_UNATT;
lpterror = 0;
lc = LPDAR; /* clear error */
for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */
t = M[lc];
lbuf[i] = ebcdic_to_ascii[t & 0xff];
M[lc] = 0x40; /* HJS MOD */
lc++;
}
for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) lbuf[i] = 0;
fputs (lbuf, lpt_unit.fileref); /* write line */
if (lines) space (lines, lflag); /* cc action? do it */
else if (mod == 0) space (1, FALSE); /* default? 1 line */
else {
fputc ('\r', lpt_unit.fileref); /* sup -> overprint */
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
}
lines = lflag = 0; /* clear cc action */
if (ferror (lpt_unit.fileref)) { /* error? */
perror ("Line printer I/O error");
clearerr (lpt_unit.fileref);
lpterror = 1;
}
return SCPE_OK;
}
/* Carriage control routine
Parameters:
action = 00, skip to channel now
= 01, space lines after
= 02, space lines now
= 03, skip to channel after
= 04, skip to line number
mod = number of lines or channel number or line number
*/
t_stat carriage_control (int32 action, int32 mod)
{
int32 i;
if ((lpt_unit.flags & UNIT_ATT) == 0)
return SCPE_UNATT;
switch (action) {
case 0: /* to channel now */
if ((mod == 0) || (mod > 12) || CHP (mod, cct[cctptr])) return SCPE_OK;
for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */
if (CHP (mod, cct[(cctptr + i) % cctlnt]))
return space (i, TRUE);
}
return STOP_INVDEV; /* runaway channel */
case 1: /* space after */
if (mod <= 3) {
lines = mod; /* save # lines */
lflag = FALSE; /* flag spacing */
CC9 = CC12 = 0;
}
return SCPE_OK;
case 2: /* space now */
if (mod <= 3) return space (mod, FALSE);
return SCPE_OK;
case 3: /* to channel after */
if ((mod == 0) || (mod > 12)) return SCPE_OK; /* check channel */
CC9 = CC12 = 0;
for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */
if (CHP (mod, cct[(cctptr + i) % cctlnt])) {
lines = i; /* save # lines */
lflag = TRUE; /* flag skipping */
return SCPE_OK;
}
}
return STOP_INVDEV;
case 4: /* To line # */
if (mod < 2) {
fputs ("\n\f", lpt_unit.fileref); /* nl, ff */
linectr = 1;
} else {
if (mod <= linectr) {
fputs ("\n\f", lpt_unit.fileref);
linectr = 1;
}
while (1) {
if (linectr == mod)
break;
space(1, 0);
}
}
return SCPE_OK;
}
return SCPE_OK;
}
/* Space routine - space or skip n lines
Inputs:
count = number of lines to space or skip
sflag = skip (TRUE) or space (FALSE)
*/
t_stat space (int32 count, int32 sflag)
{
int32 i;
if ((lpt_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT;
cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */
if (sflag && CHP (0, cct[cctptr])) { /* skip, top of form? */
fputs ("\n\f", lpt_unit.fileref); /* nl, ff */
linectr = 1;
} else {
for (i = 0; i < count; i++) fputc ('\n', lpt_unit.fileref);
}
lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */
CC9 = CHP (9, cct[cctptr]) != 0; /* set indicators */
CC12 = CHP (12, cct[cctptr]) != 0;
linectr += count;
if (linectr > LPFLR)
linectr -= LPFLR;
return SCPE_OK;
}
/* Reset routine */
t_stat lpt_reset (DEVICE *dptr)
{
cctptr = 0; /* clear cct ptr */
lines = linectr = lflag = 0; /* no cc action */
lpterror = 0;
return SCPE_OK;
}
/* Attach routine */
t_stat lpt_attach (UNIT *uptr, char *cptr)
{
cctptr = 0; /* clear cct ptr */
lines = 0; /* no cc action */
lpterror = 0;
linectr = 0;
return attach_unit (uptr, cptr);
}

313
S3/s3_pkb.c Normal file
View File

@ -0,0 +1,313 @@
/* s3_pkb.c: System/3 5471 console terminal simulator
Copyright (c) 2001-2005, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Charles E. Owen shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Charles E. Owen.
pkb 5471 printer/keyboard
25-Apr-03 RMS Revised for extended file support
08-Oct-02 RMS Added impossible function catcher
*/
#include "s3_defs.h"
#include <ctype.h>
extern int32 int_req, dev_busy, dev_done, dev_disable;
t_stat pkb_svc (UNIT *uptr);
t_stat pkb_reset (DEVICE *dptr);
extern int32 IAR[], level;
extern int32 debug_reg;
/* 5471 data structures
pkb_dev TTI device descriptor
pkb_unit TTI unit descriptor
pkb_reg TTI register list
pkb_mod TTI/TTO modifiers list
*/
/* Flag bits : (kept in pkb_unit.u3) */
#define PRT_INTREQ 0x800 /* Printer interrupt pending */
#define KBD_INTREQ 0x400 /* Request key interrupt pending */
#define KBD_INTEND 0x200 /* End or cancel key interrupt pending */
#define KBD_INTKEY 0x100 /* Return or other key interrupt pending */
#define KBD_REQLIGHT 0x20 /* Request Pending Indicator (light on/off) */
#define KBD_PROLIGHT 0x10 /* Proceed indicator (light on/off) */
#define KBD_REQINT 0x04 /* Req key interrupts enabled */
#define KBD_KEYINT 0x02 /* Other key interrupts enabled */
#define PRT_PRTINT 0x01 /* Printer interrupts enabled */
/* Keys mapped to 5471 functions */
int32 key_req = 0x01; /* Request key: ^A */
int32 key_rtn = 0x12; /* Return key: ^R */
int32 key_can = 0x1B; /* Cancel key: ESC */
int32 key_end = 0x0d; /* End key - CR */
UNIT pkb_unit = { UDATA (&pkb_svc, 0, 0), KBD_POLL_WAIT };
REG pkb_reg[] = {
{ HRDATA (FLAG, pkb_unit.u3, 16) },
{ HRDATA (IBUF, pkb_unit.buf, 8) },
{ HRDATA (OBUF, pkb_unit.u4, 8) },
{ HRDATA (REQKEY, key_req, 8) },
{ HRDATA (RTNKEY, key_rtn, 8) },
{ HRDATA (CANKEY, key_can, 8) },
{ HRDATA (ENDKEY, key_end, 8) },
{ DRDATA (POS, pkb_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, pkb_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL }
};
MTAB pkb_mod[] = {
{ 0 }
};
DEVICE pkb_dev = {
"PKB", &pkb_unit, pkb_reg, pkb_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &pkb_reset,
NULL, NULL, NULL
};
/*-------------------------------------------------------------------*/
/* EBCDIC to ASCII translate table */
/*-------------------------------------------------------------------*/
unsigned char ebcdic_to_ascii[] = {
"\x00\x01\x02\x03\xA6\x09\xA7\x7F\xA9\xB0\xB1\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\xB2\xB4\x08\xB7\x18\x19\x1A\xB8\xBA\x1D\xBB\x1F"
"\xBD\xC0\x1C\xC1\xC2\x0A\x17\x1B\xC3\xC4\xC5\xC6\xC7\x05\x06\x07"
"\xC8\xC9\x16\xCB\xCC\x1E\xCD\x04\xCE\xD0\xD1\xD2\x14\x15\xD3\xFC"
"\x20\xD4\x83\x84\x85\xA0\xD5\x86\x87\xA4\xD6\x2E\x3C\x28\x2B\xD7"
"\x26\x82\x88\x89\x8A\xA1\x8C\x8B\x8D\xD8\x21\x24\x2A\x29\x3B\x5E"
"\x2D\x2F\xD9\x8E\xDB\xDC\xDD\x8F\x80\xA5\x7C\x2C\x25\x5F\x3E\x3F"
"\xDE\x90\xDF\xE0\xE2\xE3\xE4\xE5\xE6\x60\x3A\x23\x40\x27\x3D\x22"
"\xE7\x61\x62\x63\x64\x65\x66\x67\x68\x69\xAE\xAF\xE8\xE9\xEA\xEC"
"\xF0\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\xF1\xF2\x91\xF3\x92\xF4"
"\xF5\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xAD\xA8\xF6\x5B\xF7\xF8"
"\x9B\x9C\x9D\x9E\x9F\xB5\xB6\xAC\xAB\xB9\xAA\xB3\xBC\x5D\xBE\xBF"
"\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xCA\x93\x94\x95\xA2\xCF"
"\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xDA\x96\x81\x97\xA3\x98"
"\x5C\xE1\x53\x54\x55\x56\x57\x58\x59\x5A\xFD\xEB\x99\xED\xEE\xEF"
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xFE\xFB\x9A\xF9\xFA\xFF"
};
/*-------------------------------------------------------------------*/
/* ASCII to EBCDIC translate table */
/*-------------------------------------------------------------------*/
unsigned char ascii_to_ebcdic[] = {
"\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x1A\x27\x22\x1D\x35\x1F"
"\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61"
"\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F"
"\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6"
"\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D"
"\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96"
"\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x6A\xD0\xA1\x07"
"\x68\xDC\x51\x42\x43\x44\x47\x48\x52\x53\x54\x57\x56\x58\x63\x67"
"\x71\x9C\x9E\xCB\xCC\xCD\xDB\xDD\xDF\xEC\xFC\xB0\xB1\xB2\xB3\xB4"
"\x45\x55\xCE\xDE\x49\x69\x04\x06\xAB\x08\xBA\xB8\xB7\xAA\x8A\x8B"
"\x09\x0A\x14\xBB\x15\xB5\xB6\x17\x1B\xB9\x1C\x1E\xBC\x20\xBE\xBF"
"\x21\x23\x24\x28\x29\x2A\x2B\x2C\x30\x31\xCA\x33\x34\x36\x38\xCF"
"\x39\x3A\x3B\x3E\x41\x46\x4A\x4F\x59\x62\xDA\x64\x65\x66\x70\x72"
"\x73\xE1\x74\x75\x76\x77\x78\x80\x8C\x8D\x8E\xEB\x8F\xED\xEE\xEF"
"\x90\x9A\x9B\x9D\x9F\xA0\xAC\xAE\xAF\xFD\xFE\xFB\x3F\xEA\xFA\xFF"
};
/* -------------------------------------------------------------------- */
/* Console Input: master routine */
int32 pkb (int32 op, int32 m, int32 n, int32 data)
{
int32 iodata= 0, ec, ac;
switch (op) {
case 0: /* SIO 5471 */
if (n != 0)
return STOP_INVDEV;
/*printf("%04X SIO %d,%d,%02X\n\r", IAR[level]-4, m, n, data);*/
if (m == 0) { /* Keyboard */
pkb_unit.u3 &= 0xFC1;
pkb_unit.u3 |= data;
if (data & 0x01) {
pkb_unit.u3 &= ~KBD_INTREQ;
pkb_unit.u3 &= ~KBD_INTKEY;
pkb_unit.u3 &= ~KBD_INTEND;
return RESET_INTERRUPT;
}
} else { /* Printer */
if (data & 0x80) { /* start print bit */
if (debug_reg & 0x80)
return STOP_IBKPT;
ec = pkb_unit.u4 & 0xff;
ac = ebcdic_to_ascii[ec];
sim_putchar(ac);
pkb_unit.u3 |= PRT_INTREQ;
}
if (data & 0x40) { /* Carr. Return */
sim_putchar('\n');
sim_putchar('\r');
pkb_unit.u3 |= PRT_INTREQ;
}
pkb_unit.u3 &= 0xFFe;
if (data & 0x04) /* Print interrupt flag */
pkb_unit.u3 |= PRT_PRTINT;
if (data & 0x01) { /* Reset Interrupt */
if (level < 8) {
if (!(data & 0x80))
pkb_unit.u3 &= ~PRT_INTREQ;
return RESET_INTERRUPT;
}
}
}
return SCPE_OK;
case 1: /* LIO 5471 */
if (n != 0)
return STOP_INVDEV;
if (m != 1)
return STOP_INVDEV;
pkb_unit.u4 = (data >> 8) & 0xff;
return SCPE_OK;
break;
case 2: /* TIO 5471 */
return STOP_INVDEV;
case 3: /* SNS 5471 */
if (n != 1 && n != 3)
return (STOP_INVDEV << 16);
if (m == 0) { /* Keyboard data */
if (n == 1) { /* Sense bytes 0 & 1 */
iodata = (pkb_unit.buf << 8) & 0xff00;
if (pkb_unit.u3 & KBD_INTREQ)
iodata |= 0x80;
if (pkb_unit.u3 & KBD_INTEND)
iodata |= 0x40;
if (pkb_unit.u3 & KBD_INTKEY)
iodata |= 0x08;
if (pkb_unit.buf == 0x12) /* Return key */
iodata |= 0x04;
if (pkb_unit.buf == 0x03) /* Cancel key */
iodata |= 0x20;
if (pkb_unit.buf == 0x0d) /* End key */
iodata |= 0x10;
iodata |= ((SCPE_OK << 16) & 0xffff0000);
} else { /* Sense bytes 2 & 3 */
iodata = 0; /* Manual says CE use only */
}
} else { /* Printer Data */
if (n == 1) { /* Sense bytes 0 & 1 */
iodata = 0;
if (pkb_unit.u3 & PRT_INTREQ)
iodata |= 0x80;
} else {
iodata = 0; /* CE use only */
}
}
iodata |= ((SCPE_OK << 16) & 0xffff0000);
return (iodata);
case 4: /* APL 5471 */
return STOP_INVDEV;
default:
break;
}
sim_printf (">>PKB non-existent function %d\n", op);
return SCPE_OK;
}
/* Unit service */
t_stat pkb_svc (UNIT *uptr)
{
int32 temp, ac, ec;
sim_activate (&pkb_unit, pkb_unit.wait); /* continue poll */
if (pkb_unit.u3 & PRT_INTREQ) { /* Printer Interrupt */
int_req |= 2;
return SCPE_OK;
}
/* Keyboard : handle input */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
ac = temp & 0x7f; /* placed type ASCII char in ac */
if (pkb_unit.u3 & KBD_REQINT) {
if (ac == key_req) { /* Request Key */
pkb_unit.u3 |= KBD_INTREQ;
int_req |= 2;
return SCPE_OK;
}
}
if (islower(ac))
ac = toupper(ac);
ec = ascii_to_ebcdic[ac]; /* Translate */
pkb_unit.buf = ec; /* put in buf */
pkb_unit.pos = pkb_unit.pos + 1;
if (ac == key_end) { /* End key */
if (pkb_unit.u3 & KBD_KEYINT) {
pkb_unit.u3 |= KBD_INTEND;
pkb_unit.buf = 0x0d;
int_req |= 2;
}
return SCPE_OK;
}
if (ac == key_can) { /* Cancel key */
if (pkb_unit.u3 & KBD_KEYINT) {
pkb_unit.u3 |= KBD_INTEND;
pkb_unit.buf = 0x03;
int_req |= 2;
}
return SCPE_OK;
}
if (ac == key_rtn) { /* Return key */
if (pkb_unit.u3 & KBD_KEYINT) {
pkb_unit.u3 |= KBD_INTKEY;
pkb_unit.buf = 0x12;
int_req |= 2;
}
return SCPE_OK;
}
if (pkb_unit.u3 & KBD_KEYINT) { /* Key interupts enabled ? */
int_req |= 2; /* Device 1 Interrupt! */
pkb_unit.u3 |= KBD_INTKEY; /* Set pending flag */
}
return SCPE_OK;
}
/* Reset routine */
t_stat pkb_reset (DEVICE *dptr)
{
pkb_unit.buf = 0;
int_req = int_req & ~0x02; /* reset interrupt */
sim_activate (&pkb_unit, pkb_unit.wait); /* activate unit */
return SCPE_OK;
}
t_stat pkb_setmod (UNIT *uptr, int32 value)
{
return SCPE_OK;
}

950
S3/s3_sys.c Normal file
View File

@ -0,0 +1,950 @@
/* s3_sys.c: IBM System/3 system interface
Copyright (c) 2001-2020, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Charles E. Owen shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Charles E. Owen.
06-Jun-20 RMS Fixed declaration of bldaddr (Mark Pizzolato)
19-Mar-12 RMS Fixed declaration of conversion tables (Mark Pizzolato)
*/
#include <ctype.h>
#include "s3_defs.h"
extern DEVICE cpu_dev;
extern DEVICE pkb_dev;
extern DEVICE cdr_dev;
extern DEVICE cdp_dev;
extern DEVICE stack_dev;
extern DEVICE lpt_dev;
extern DEVICE r1_dev;
extern DEVICE f1_dev;
extern DEVICE r2_dev;
extern DEVICE f2_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern unsigned char M[];
extern int32 saved_PC, IAR[];
extern unsigned char ebcdic_to_ascii[];
char *parse_addr(char *cptr, char *gbuf, t_addr *addr, int32 *addrtype);
int32 printf_sym (FILE *of, char *strg, t_addr addr, uint32 *val,
UNIT *uptr, int32 sw);
/* SCP data structures
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words needed for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "System/3";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 6;
DEVICE *sim_devices[] = {
&cpu_dev,
&pkb_dev,
&cdr_dev,
&cdp_dev,
&stack_dev,
&lpt_dev,
&r1_dev,
&f1_dev,
&r2_dev,
&f2_dev,
NULL
};
const char *sim_stop_messages[] = {
"Unknown error",
"Unknown I/O Instruction",
"HALT instruction",
"Breakpoint",
"Invalid Opcode",
"Invalid Qbyte",
"Invalid Address",
"Invalid Device Command",
"ATTN Card Reader"
};
/* This is the opcode master defintion table. Each possible opcode mnemonic
is defined here, with enough information to translate to and from
symbolic to binary machine code.
First field is the opcode's mnemonic
Second field is the hex of the right nybble of the binary opcode
Third field is the Q code for those with implicit Q codes
Fourth field is the symbolic format of the operands:
0 - (Q-byte),(R-byte)
1 - (Q-byte),(Address)
2 - (Address),(Address),(Qbyte)
3 - (Address),(Qbyte)
4 - (device),(modifier),(function) -- these 3 make up qbyte
5 - (device),(modifier),(function),(control)
6 - (device),(modifier),(function),(Address)
7 - (displacement) -- Q byte is implicit in opcode
8 - (address) -- Qbyte is implicit in opcode
9 - (Address),(Address) -- Qbyte is implicit in opcode
Fifth Field is the group number:
0 - Command Group (left op nybble is F)
1 - One Address Operations A (Left Nybble C, D, or E)
2 - Two Address Operations (Left Nybble 0,1,2,4,5,6,8,9, or A)
3 - One Address Operations B (left Nybble 3, 7, or B)
There is duplication in this table -- IBM defines different opcodes
that resolve to the same binary machine instruction -- e.g. JE and
JZ. On input this is no problem, on output, define the one you
want to appear first, the second will never appear on output.
*/
int32 nopcode = 75;
struct opdef opcode[75] = {
{"HPL", 0x00,0,0,0}, /** Halt Program Level */
{"A", 0x06,0,1,3}, /** Add to Register: A R,AADD */
{"ST", 0x04,0,1,3}, /** Store Register */
{"L", 0x05,0,1,3}, /** Load Register */
{"LA", 0x02,0,1,1}, /** Load Address */
{"ZAZ", 0x04,0,2,2}, /** Zero and Add Zoned */
{"AZ", 0x06,0,2,2}, /** Add Zoned Decimal */
{"SZ", 0x07,0,2,2}, /** Subtract Zoned Decimal */
{"ALC", 0x0E,0,2,2}, /** Add Logical: ALC BADD,AADD,LEN */
{"SLC", 0x0F,0,2,2}, /** Sub Logical: SLC BADD,AADD,LEN */
{"MVC", 0x0C,0,2,2}, /** Move Chars MVX BADD,AADD,LEN */
{"ED", 0x0A,0,2,2}, /** Edit: ED BADD,AADD,LEN */
{"ITC", 0x0B,0,2,2}, /** Insert Chars: ITC BADD,AADD,LEN */
{"CLC", 0x0D,0,2,2}, /** Compare Logical: CLC BADD,AADD,LEN */
{"MVI", 0x0C,0,3,3}, /** Move Immediate */
{"SBN", 0x0A,0,3,3}, /** Set Bits On */
{"SBF", 0x0B,0,3,3}, /** Set Bits Off */
{"CLI", 0x0D,0,3,3}, /** Compare Immediate */
{"TBN", 0x08,0,3,3}, /** Test Bits On */
{"TBF", 0x09,0,3,3}, /** Test Bits Off */
{"APL", 0x01,0,4,0}, /** Advance Program Level */
{"SIO", 0x03,0,5,0}, /** Start I/O */
{"SNS", 0x00,0,6,3}, /** Sense I/O */
{"LIO", 0x01,0,6,3}, /** Load I/O */
{"TIO", 0x01,0,6,1}, /** Test I/O */
{"J", 0x02,0,7,0}, /** Jump Unconditional */
{"J", 0x02,0x87,7,0}, /* Alternate J */
{"JH", 0x02,132,7,0}, /* Jump if High */
{"JL", 0x02,130,7,0}, /* Jump if Low */
{"JE", 0x02,129,7,0}, /* Jump if Equal */
{"JNH", 0x02,4,7,0}, /** Jump if Not High */
{"JNL", 0x02,2,7,0}, /** Jump if Not Low */
{"JNE", 0x02,1,7,0}, /** Jump if Not Equal */
{"JOZ", 0x02,136,7,0}, /* Jump if Overflow Zoned */
{"JOL", 0x02,160,7,0}, /* Jump if Overflow Logical */
{"JNOZ", 0x02,8,7,0}, /** Jump if No Overflow Zoned */
{"JNOL", 0x02,32,7,0}, /* Jump if No Overflow Logical */
{"JT", 0x02,16,7,0}, /* Jump if True */
{"JF", 0x02,144,7,0}, /* Jump if False */
{"JP", 0x02,132,7,0}, /* Jump if Plus */
{"JM", 0x02,130,7,0}, /* Jump if Minus */
{"JZ", 0x02,129,7,0}, /* Jump if Zero */
{"JNP", 0x02,4,7,0}, /** Jump if Not Plus */
{"JNM", 0x02,2,7,0}, /** Jump if Not Minus */
{"JNZ", 0x02,1,7,0}, /** Jump if Not Zero */
{"NOPJ", 0x02,0x80,7,0}, /* Never Jump - NOP */
{"B", 0x00,0x00,8,1}, /* Branch Unconditional */
{"B", 0x00,0x87,8,1}, /* Alternate B */
{"BH", 0x00,0x84,8,1}, /* Branch if High */
{"BL", 0x00,0x82,8,1}, /* Branch if Low */
{"BE", 0x00,0x81,8,1}, /* Branch if Equal */
{"BNH", 0x00,0x04,8,1}, /* Branch if Not High */
{"BNL", 0x00,0x02,8,1}, /* Branch if Not Low */
{"BNE", 0x00,0x01,8,1}, /* Branch if Not Equal */
{"BOZ", 0x00,0x88,8,1}, /* Branch if Overflow Zoned */
{"BOL", 0x00,0xA0,8,1}, /* Branch if Overflow Logical */
{"BNOZ", 0x00,0x08,8,1}, /* Branch if No Overflow Zoned */
{"BNOL", 0x00,0x20,8,1}, /* Branch if No Overflow Logical */
{"BT", 0x00,0x10,8,1}, /* Branch if True */
{"BF", 0x00,0x90,8,1}, /* Branch if False */
{"BP", 0x00,0x84,8,1}, /* Branch if Plus */
{"BM", 0x00,0x82,8,1}, /* Branch if Minus */
{"BZ", 0x00,0x81,8,1}, /* Branch if Zero */
{"BNP", 0x00,0x04,8,1}, /* Branch if Not Plus */
{"BNM", 0x00,0x02,8,1}, /* Branch if Not Minus */
{"BNZ", 0x00,0x01,8,1}, /* Branch if Not Zero */
{"NOPB", 0x00,0x80,8,1}, /* Never Branch - NOP */
{"MZZ", 0x08,0,9,2}, /** Move Zone to Zone */
{"MNZ", 0x08,1,9,2}, /** Move Numeric to Zone */
{"MZN", 0x08,2,9,2}, /** Move Zone to Numeric */
{"MNN", 0x08,3,9,2}, /** Move Numeric to Numeric */
{"MVX", 0x08,0,2,2}, /** Move Hex: MVX BADD,AADD,CODE */
{"JC", 0x02,0,3,0}, /** Jump on Specified Condition bits */
{"BC", 0x00,0,3,1}, /** Branch on Specified Condition */
{"***", 0x00,0,0,0}
};
int32 regcode[15] = { 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
0x80, 0xC0, 0xA0, 0x90, 0x88, 0x84, 0x82, 0x81
};
char regname[15][8] = { "(P2IAR)",
"(P1IAR)",
"(IAR)",
"(ARR)",
"(PSR)",
"(XR2)",
"(XR1)",
"(IAR0)",
"(IAR1)",
"(IAR2)",
"(IAR3)",
"(IAR4)",
"(IAR5)",
"(IAR6)",
"(IAR7)"
};
/* This is the binary loader. The input file is considered to be
a string of literal bytes with no special format. The
load starts at the current value of the P1IAR.
*/
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 i, addr = 0, cnt = 0;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
addr = IAR[8];
while ((i = getc (fileref)) != EOF) {
M[addr] = i & 0xff;
addr++;
cnt++;
} /* end while */
printf ("%d Bytes loaded.\n", cnt);
return (SCPE_OK);
}
/* Symbolic output
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
status = error code
*/
t_stat fprint_sym (FILE *of, t_addr addr, uint32 *val,
UNIT *uptr, int32 sw)
{
int32 r;
char strg[256];
strcpy(strg, "");
r = printf_sym(of, strg, addr, val, uptr, sw);
if (sw & SWMASK ('A'))
strcpy(strg, "");
else
fprintf(of, "%s", strg);
return (r);
}
t_stat printf_sym (FILE *of, char *strg, t_addr addr, uint32 *val,
UNIT *uptr, int32 sw)
{
int32 c1, c2, group, len1, len2, inst, aaddr, baddr;
int32 oplen, groupno, i, j, vpos, qbyte, da, m, n;
char bld[128], bldaddr[160], boperand[32], aoperand[32];
int32 blk[16], blt[16];
int32 blkadd;
c1 = val[0] & 0xff;
if (sw & SWMASK ('A')) {
for (i = 0; i < 16; i++) {
blkadd = addr + (i*16);
for (j = 0; j < 16; j++) {
blk[j] = M[blkadd+j] & 0xff;
c2 = ebcdic_to_ascii[blk[j]];
if (c2 < 040 || c2 > 0177 || blk[j] == 07) {
blt[j] = '.';
} else {
blt[j] = c2;
}
}
if (i == 0) {
fprintf(of, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ",
blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7],
blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15],
blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7],
blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]);
} else {
fprintf(of, "%X\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ",
blkadd, blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7],
blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15],
blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7],
blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]);
}
}
return SCPE_OK; }
if (sw & SWMASK ('C')) {
c2 = ebcdic_to_ascii[c1];
if (c2 < 040 || c2 > 0177) {
sprintf(strg, "<%02X>", c1 & 0xff);
} else {
sprintf (strg, "%c", c2 & 0xff);
}
return SCPE_OK; }
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
inst = val[0] & 0x0f;
len1 = (val[0] >> 6) & 3;
len2 = (val[0] >> 4) & 3;
group = (val[0] >> 4) & 0x0f;
qbyte = val[1];
/* Get total length of instruction */
if (group == 0x0f) {
oplen = 3;
} else {
oplen = 2;
if (len1 == 0) oplen += 2;
if (len1 == 1 || len1 == 2) oplen++;
if (len2 == 0) oplen += 2;
if (len2 == 1 || len2 == 2) oplen++;
}
/* Find which group it belongs to */
switch (group) {
case 0x0f:
groupno = 0;
break;
case 0x0c:
case 0x0d:
case 0x0e:
groupno = 1;
break;
case 0x03:
case 0x07:
case 0x0b:
groupno = 3;
break;
default:
groupno = 2;
break;
}
/* find the table entry */
for (i = 0; i < nopcode; i++) {
if (opcode[i].form < 7) { /* Explicit Q */
if (opcode[i].group == groupno &&
opcode[i].opmask == inst) break;
} else { /* Implicit Q */
if (opcode[i].group == groupno &&
opcode[i].opmask == inst &&
opcode[i].q == qbyte) break;
}
}
/* print the opcode */
if (i >= nopcode) {
sprintf(strg, "%02X", val[0]);
oplen = 1;
} else {
sprintf(bld, "%s ", opcode[i].op);
/* Extract the addresses into aaddr and baddr */
strcpy(aoperand, "ERROR");
strcpy(boperand, "ERROR");
vpos = 2;
aaddr = baddr = 0;
switch (len1) {
case 0:
baddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff);
sprintf(boperand, "%04X", baddr);
vpos = 4;
break;
case 1:
baddr = val[vpos] & 255;
sprintf(boperand, "(%02X,XR1)", baddr);
vpos = 3;
break;
case 2:
baddr = val[vpos] & 255;
sprintf(boperand, "(%02X,XR2)", baddr);
vpos = 3;
break;
default:
baddr = 0;
break;
}
switch (len2) {
case 0:
aaddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff);
if (group == 0x0C || group == 0x0D || group == 0x0E)
sprintf(boperand, "%04X", aaddr);
else
sprintf(aoperand, "%04X", aaddr);
break;
case 1:
aaddr = val[vpos] & 255;
if (group == 0x0C || group == 0x0D || group == 0x0E)
sprintf(boperand, "(%02X,XR1)", aaddr);
else
sprintf(aoperand, "(%02X,XR1)", aaddr);
break;
case 2:
aaddr = val[vpos] & 255;
if (group == 0x0C || group == 0x0D || group == 0x0E)
sprintf(boperand, "(%02X,XR2)", aaddr);
else
sprintf(aoperand, "(%02X,XR2)", aaddr);
break;
default:
aaddr = 0;
break;
}
/* Display the operands in the correct format */
da = (qbyte >> 4) & 0x0f;
m = (qbyte >> 3) & 0x01;
n = (qbyte) & 0x07;
switch (opcode[i].form) {
case 0:
sprintf(bldaddr, "%02X,%02X", qbyte, val[2]);
break;
case 1:
if (inst == 2 || inst == 4 || inst == 5 || inst == 6) {
for (i = 0; i < 16; i++) {
if (regcode[i] == qbyte)
break;
}
if (i < 16) {
sprintf(bldaddr, "%s,%s", regname[i], boperand);
} else {
sprintf(bldaddr, "%02X,%s", qbyte, boperand);
}
} else {
sprintf(bldaddr, "%02X,%s", qbyte, boperand);
}
break;
case 2:
if (inst > 9 || inst == 4 || inst == 6 || inst == 7)
qbyte++; /* special +1 for length display */
sprintf(bldaddr, "%s,%s,%d", boperand, aoperand, qbyte);
break;
case 3:
if (strcmp(opcode[i].op, "JC") == 0) {
sprintf(bldaddr, "%04X,%02X", addr+oplen+val[2], qbyte);
} else {
sprintf(bldaddr, "%s,%02X", boperand, qbyte);
}
break;
case 4:
sprintf(bldaddr, "%d,%d,%d", da, m, n);
break;
case 5:
sprintf(bldaddr, "%d,%d,%d,%02X", da, m, n, val[2]);
break;
case 6:
sprintf(bldaddr, "%d,%d,%d,%s", da, m, n, boperand);
break;
case 7:
sprintf(bldaddr, "%04X", addr+oplen+val[2]);
break;
case 8:
sprintf(bldaddr, "%s", boperand);
break;
default:
sprintf(bldaddr, "%s,%s", boperand, aoperand);
break;
}
sprintf(strg, "%s%s", bld, bldaddr);
}
return -(oplen - 1);
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (unsigned int) cptr[0];
return SCPE_OK;
}
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1];
return SCPE_OK;
}
/* An instruction: get opcode (all characters until null, comma, left paren,
or numeric (including spaces).
*/
while (1) {
if (*cptr == ',' || *cptr == '\0' || *cptr == '(' ||
isdigit(*cptr))
break;
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* kill trailing spaces if any */
gbuf[i] = '\0';
for (j = i - 1; gbuf[j] == ' '; j--) {
gbuf[j] = '\0';
}
/* find opcode in table */
for (j = 0; j < nopcode; j++) {
if (strcmp(gbuf, opcode[j].op) == 0)
break;
}
if (j >= nopcode) /* not found */
return SCPE_ARG;
oplen = 2; /* start with op & q */
val[0] = opcode[j].opmask; /* store opcode right nybble */
switch (opcode[j].form) { /* Get operands based on operand format */
case 0: /* Single Byte Operand */
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ','); /* Get Q Byte */
sscanf(gbuf, "%x", &r);
val[1] = r;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0); /* Get R Byte */
sscanf(gbuf, "%x", &r);
val[2] = r;
oplen = 3;
val[0] = 0xf0 | opcode[j].opmask;
break;
case 1:
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
if (opcode[j].opmask == 2 ||
opcode[j].opmask == 4 ||
opcode[j].opmask == 5 ||
opcode[j].opmask == 6) {
if (isdigit(gbuf[0])) {
sscanf(gbuf, "%x", &r);
} else {
for (i = 0; i < 16; i++) {
if (strcmp(gbuf, regname[i]) == 0)
break;
}
if (i < 16) {
r = regcode[i];
} else {
return SCPE_ARG;
}
}
} else {
sscanf(gbuf, "%x", &r);
}
if (r > 255) return SCPE_ARG;
val[1] = r;
if (*cptr == ',') cptr++;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[2] = (addr >> 8) & 0x00ff;
val[3] = addr & 0xff;
oplen = 4;
if (opcode[j].group == 1)
val[0] = 0xC0 | opcode[j].opmask;
else
val[0] = 0x30 | opcode[j].opmask;
break;
case 1:
val[2] = addr & 0xff;
oplen = 3;
if (opcode[j].group == 1)
val[0] = 0xD0 | opcode[j].opmask;
else
val[0] = 0x70 | opcode[j].opmask;
break;
case 2:
val[2] = addr & 0xff;
oplen = 3;
if (opcode[j].group == 1)
val[0] = 0xE0 | opcode[j].opmask;
else
val[0] = 0xB0 | opcode[j].opmask;
break;
default:
return SCPE_ARG;
break;
}
break;
case 2:
oplen = 2;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[2] = (addr >> 8) & 0xff;
val[3] = addr & 0xff;
oplen += 2;
vptr = 4;
val[0] = 0x00 | opcode[j].opmask;
break;
case 1:
val[2] = addr & 0xff;
oplen += 1;
vptr = 3;
val[0] = 0x40 | opcode[j].opmask;
break;
case 2:
val[2] = addr & 0xff;
oplen += 1;
vptr = 3;
val[0] = 0x80 | opcode[j].opmask;
break;
default:
return SCPE_ARG;
break;
}
if (*cptr == ',') cptr++;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[vptr] = (addr >> 8) & 0xff;
val[vptr+1] = addr & 0xff;
oplen += 2;
break;
case 1:
val[vptr] = addr & 0xff;
oplen += 1;
val[0] = 0x10 | val[0];
break;
case 2:
val[vptr] = addr & 0xff;
oplen += 1;
val[0] = 0x20 | val[0];
break;
default:
return SCPE_ARG;
break;
}
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0);
sscanf(gbuf, "%d", &r);
if (opcode[j].opmask > 9 ||
opcode[j].opmask == 4 ||
opcode[j].opmask == 6 ||
opcode[j].opmask == 7) r--; /* special: length -1 */
val[1] = r;
if (*cptr == ',') cptr++;
break;
case 3:
saveaddr = addr;
if (*cptr == ',') cptr++;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
if (opcode[j].group == 0) { /* Group 0 form 3 is JC with explicit Q */
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0);
sscanf(gbuf, "%x", &r);
if ((addr - (saveaddr+3)) > 255 || (addr - (saveaddr+3)) < 1)
return SCPE_ARG;
val[2] = addr - (saveaddr+3);
val[1] = r;
val[0] = 0xf0 | opcode[j].opmask;
oplen = 3;
} else {
val[2] = (addr >> 8) & 0x00ff;
val[3] = addr & 0xff;
oplen = 4;
if (opcode[j].group == 1)
val[0] = 0xC0 | opcode[j].opmask;
else
val[0] = 0x30 | opcode[j].opmask;
}
break;
case 1:
val[2] = addr & 0xff;
oplen = 3;
if (opcode[j].group == 1)
val[0] = 0xD0 | opcode[j].opmask;
else
val[0] = 0x70 | opcode[j].opmask;
break;
case 2:
val[2] = addr & 0xff;
oplen = 3;
if (opcode[j].group == 1)
val[0] = 0xE0 | opcode[j].opmask;
else
val[0] = 0xB0 | opcode[j].opmask;
break;
default:
return SCPE_ARG;
break;
}
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0);
sscanf(gbuf, "%x", &r);
if (r > 255) return SCPE_ARG;
val[1] = r;
break;
case 4:
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 15) return SCPE_ARG;
val[1] = (r << 4) & 0xf0;
val[0] = 0xf0 | opcode[j].opmask;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 1) return SCPE_ARG;
val[1] |= (r << 3) & 0x08;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0);
sscanf(gbuf, "%d", &r);
if (r > 7) return SCPE_ARG;
val[1] |= r & 0x07;
val[2] = 0;
oplen = 3;
break;
case 5:
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 15) return SCPE_ARG;
val[1] = (r << 4) & 0xf0;
val[0] = 0xf0 | opcode[j].opmask;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 1) return SCPE_ARG;
val[1] |= (r << 3) & 0x08;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 7) return SCPE_ARG;
val[1] |= r & 0x07;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0);
sscanf(gbuf, "%x", &r);
if (r > 255) return SCPE_ARG;
val[2] = r;
oplen = 3;
break;
case 6:
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 15) return SCPE_ARG;
val[1] = (r << 4) & 0xf0;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 1) return SCPE_ARG;
val[1] |= (r << 3) & 0x08;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
sscanf(gbuf, "%d", &r);
if (r > 7) return SCPE_ARG;
val[1] |= r & 0x07;
if (*cptr == ',') cptr++;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[2] = (addr >> 8) & 0x00ff;
val[3] = addr & 0xff;
oplen = 4;
if (opcode[j].group == 1)
val[0] = 0xC0 | opcode[j].opmask;
else
val[0] = 0x30 | opcode[j].opmask;
break;
case 1:
val[2] = addr & 0xff;
oplen = 3;
if (opcode[j].group == 1)
val[0] = 0xD0 | opcode[j].opmask;
else
val[0] = 0x70 | opcode[j].opmask;
break;
case 2:
val[2] = addr & 0xff;
oplen = 3;
if (opcode[j].group == 1)
val[0] = 0xE0 | opcode[j].opmask;
else
val[0] = 0xB0 | opcode[j].opmask;
break;
default:
return SCPE_ARG;
break;
}
break;
case 7:
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0);
sscanf(gbuf, "%x", &r);
if ((r - (addr+3)) > 255 || (r - (addr+3)) < 1) return SCPE_ARG;
val[2] = r - (addr+3);
val[1] = opcode[j].q;
val[0] = 0xf0 | opcode[j].opmask;
oplen = 3;
break;
case 8:
if (*cptr == ',') cptr++;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[2] = (addr >> 8) & 0x00ff;
val[3] = addr & 0xff;
oplen = 4;
val[0] = 0xC0 | opcode[j].opmask;
break;
case 1:
val[2] = addr & 0xff;
oplen = 3;
val[0] = 0xD0 | opcode[j].opmask;
break;
case 2:
val[2] = addr & 0xff;
oplen = 3;
val[0] = 0xE0 | opcode[j].opmask;
break;
default:
return SCPE_ARG;
break;
}
val[1] = opcode[j].q;
break;
case 9:
oplen = 2;
val[0] = 0;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[2] = (addr >> 8) & 0xff;
val[3] = addr & 0xff;
oplen += 2;
vptr = 4;
val[0] = 0x00 | opcode[j].opmask;
break;
case 1:
val[2] = addr & 0xff;
oplen += 1;
vptr = 3;
val[0] = 0x40 | opcode[j].opmask;
break;
case 2:
val[2] = addr & 0xff;
oplen += 1;
vptr = 3;
val[0] = 0x80 | opcode[j].opmask;
break;
default:
return SCPE_ARG;
break;
}
if (*cptr == ',') cptr++;
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
switch(addtyp) {
case 0:
val[vptr] = (addr >> 8) & 0xff;
val[vptr+1] = addr & 0xff;
oplen += 2;
break;
case 1:
val[vptr] = addr & 0xff;
oplen += 1;
val[0] = 0x10 | val[0];
break;
case 2:
val[vptr] = addr & 0xff;
oplen += 1;
val[0] = 0x20 | val[0];
break;
default:
return SCPE_ARG;
break;
}
val[1] = opcode[j].q;
break;
default:
break;
}
return (-(oplen-1));
}
char *parse_addr(char *cptr, char *gbuf, t_addr *addr, int32 *addrtype)
{
int32 nybble = 0;
char temp[32];
cptr = get_glyph(cptr, gbuf, ',');
if (gbuf[0] == '(') { /* XR relative */
strcpy(temp, gbuf+1);
sscanf(temp, "%x", addr);
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, ',');
nybble = -1;
if (strcmp(gbuf, "XR1)") == 0)
nybble = 1;
if (strcmp(gbuf, "XR2)") == 0)
nybble = 2;
} else { /* Direct */
sscanf(gbuf, "%x", addr);
nybble = 0;
}
*addrtype = nybble;
return cptr;
}

472
S3/system3.txt Normal file
View File

@ -0,0 +1,472 @@
The IBM System/3 simulator is configured as follows:
CPU 5410 (Model 10) CPU with 64KB of memory.
PKB 5471 Printer/Keyboard console.
CDR 1442 Card Reader
CDP 1442 Card Punch
CDP2 1442 2nd stacker
LPT 1403 Line Printer
R1 5444 Top Drive (removeable)
F1 5444 Top Drive (fixed)
R2 5444 Bottom Drive (removeable)
F2 5444 Bottom Drive (fixed
The only CPU options are to set Model 15 mode (not implemented), DPF
(Dual Programming Facility, not implemented), and the memory size 8K, 16K,
32K, 48K, or 64K.
CPU registers are the standard System/3 set:
name size Description
IAR-P1 16 Instruction Address Register for Program Level 1
ARR-P2 16 Address Recall Register for Program Level 1
IAR-P2 16 IAR for Program Level 2 (not implemented)
ARR-P2 16 ARR for Program Level 2 (not implemented)
AAR 16 A-Address Register
BAR 16 B-Address Register
PSR 16 Program Status Register
XR1 16 Index Register 1
XR2 16 Index Register 2
IAR<0:7> 16 IAR for interrupt level 0 thru 7
ARR<0:7> 16 ARR for interrupt level 0 thru 7
Plus these simulator registers:
IAR 16 Value of last IAR used.
LEVEL 8 Current operating level (8=P1, 9=P2,
0 thru 7 = Interrupt level)
SR 16 Front Panel switches
INT 16 Interrupt Request Flags
WRU 8 Simulator Interrupt Character
BREAK 17 Breakpoint Address
DEBUG 16 Debugging bits:
0x01: Write all instructions executed to
file trace.log.
0x02: Write details of all Disk I/O
requests to trace.log.
0x80: Breakpoint on first character
written to 5471 printer.
1 5471 Printer/Keyboard
This is the operator console. It has the following registers:
FLAG 5471 Flag Bytes
IBUF: Input character from keyboard
OBUF: Output character to printer
POS: Number of characters printed
TIME: Delay for device operation
REQKEY: ASCII value of key mapped to 5471 REQUEST key
RTNKEY: ASCII value of key mapped to 5471 RETURN key
ENDKEY: ASCII value of key mapped to 5471 END key
CANKEY: ASCII value of key mapped to 5471 CANCEL key
2 1442 Card Reader. This reader reads 80-column cards; the input
is usually an ASCII file which is translated to EBCDIC when read,
but optionally can be a binary file in EBCDIC format (such as an
object program).
LAST Last card switch
ERR Card Reader Error
NOTRDY 1442 reader not ready (not attached or past EOF)
DAR Data Address Register (shared with punch)
LCR Length Count Register (shared with punch)
EBCDIC EBCDIC mode flag: if 1, input is 80-col EBCDIC binary.
(IPL from 1442 automatically sets this to 1).
S2 Stacker 2 is selected when this is 1
POS Number of cards read
TIME Device Delay
The real hardware 1442 had only 1 hopper for cards, whether
these were used for blank cards for punching, or cards to be
read. Cards could be read without a feed cycle, then
punched. When punching cards, the SCP does a read of a card,
makes sure it is blank, and then punches it. To simulate
this without requiring that a stack of blank lines be attached
to the card reader device, a special feature of the simulator
is this: if no file is attached to the cdr device, but a file
is attached to the cdp or the cdp2 devices, any read from the
reader will return a blank card -- i.e. when punching, an
unattached cdr device is assumed to be loaded with an unlimited
supply of blank cards.
3 1442 Card Punch. Normally cards are written to the attached
disk file as ASCII with newline/cr delimiters. But an optional
flag allows writing as 80-column binary EBCDIC.
ERR Card Punch Error
EBCDIC When this is 1, output will be 80-col EBCDIC.
S2 When this is 1, output is placed in stacker 2
NOTRDY 1442 punch not ready (not attached)
DAR Data Address Register (shared with reader)
LCR Length Count Register (shared with reader)
POS Number of cards punched
TIME Device Delay
4 1442 Stacker 2. When cards are to be punched in stacker 2,
attach a disk file to this device (cdp2) to hold that output.
Note: When SCP punches cards, the default is to punch in
stacker 2.
POS0 Number of cards punched.
5 1403 Printer. This is a 132-column output device, emulating
the famous IBM 1403, models 2, 6, and N1. Output is always
translated to ASCII with newline/CR delimiters. Page advance
is output as a form feed.
ERR 1403 error flags
LPDAR Data Address Register
LPFLR Forms Length Register
LPIAR Image Address Register
LINECT Current Line on form
POS Number of lines printed
6 5444 Disk Drives (R1, R2, F1, F2)
The 5444 came as a set of two drives, each with two disks. The
top disk in a drive was removable, the bottom fixed. The first
drive consists of disks R1 and F1, the second drive R2 and F2.
Each disk holds 2,467,600 bytes of user data, plus 3 alternate
tracks and a CE track. Flagging of alternate tracks is not
supported in this version of the simulator.
NOTRDY Drive not ready (not attached)
SEEK Drive is busy with a seek operation
DAR Data Address Register
CAR Control Address Register
ERR Error Flags (16 bits)
CYL Current Cylinder (0 thru 203)
HEAD Current head (0 or 1)
POS Current position in attached disk file
TIME Device Delay
7 Symbolic Display and Input
The System/3 Simulator supports symbolic display and input.
Display is controlled by command line switches:
(none) display as hex EBCDIC
-c display bytes as characters
-m display instruction mnemonics.
-a display a 256-byte block of memory in both hex and ASCII.
The symbolic format contains the same elements as the machine
language operation, but not always in the same order. The
operation code frequently specifies both the opcode and the Q byte,
and the top nybble of the opcode is determined by the format of the
addresses.
Addresses take two forms: the direct address in hex, or a relative
address specified thusly: (byte,XRx) where 'byte' is a 1-byte
offset, and XRx is either XR1 or XR2 for the two index registers.
Use these formats when 'address' is indicated below:
When 'reg' is mentioned, a mnemonic may be used for the register,
thusly:
IAR Instruction Address Register for the current program level
ARR Address Recall Register for the current program level
P1IAR IAR for Program Level 1
P2IAR IAR for Program Level 2
PSR Program Status Register
XR1 Index Register 1
XR2 Index Register 2
IARx IAR for the interrupt level x (x = 0 thru 7)
All other operands mentioned below are single-byte hex, except for
the length (len) operand of the two-address instructions, which is a
decimal length in the range 1-256.
In operations where there is a source and a destination, the
destination is always operand 1, the source is operand 2.
No-address formats:
------------------
HPL hex,hex Halt Program Level, the operands are the
Q and R bytes.
One-address formats:
-------------------
A reg,address Add to register
CLI address,byte Compare Logical Immediate
MVI address,byte Move Immediate
TBF address,mask Test Bits Off
TBN address,mask Test Bits On
SBF address,mask Set Bits Off
SBN address,mask Set Bits On
ST reg,address Store Register
L reg,address Load Register
LA reg,address Load Address (reg can only be XR1 or XR2)
JC address,cond Jump on Condition
BC address,cond Branch on Condition
These operations do not specify a qbyte, it is implicit in the
opcode:
B address Unconditional branch to address
BE address Branch Equal
BNE address Branch Not Equal
BH address Branch High
BNH address Branch Not High
BL address Branch Low
BNL address Branch Not Low
BT address Branch True
BF address Branch False
BP address Branch Plus
BM address Branch Minus
BNP address Branch Not Plus
BNM address Branch Not Minus
BZ address Branch Zero
BNZ address Branch Not Zero
BOZ address Branch Overflow Zoned
BOL address Branch Overflow Logical
BNOZ address Branch No Overflow Zoned
BNOL address Branch No Overflow Logical
NOPB address No - never branch
(substitute J for B above for a set of Jumps -- 1-byte operand (not
2), always jumps forward up to 255 bytes from the address following
the Jump instruction. In this case, 'address' cannot be less than
the current address, nor greater than the current address + 255)
Two-address formats (first address is destination, len is decimal 1-256):
-------------------
MVC address,address,len Move Characters
CLC address,address,len Compare Logical Characters
ALC address,address,len Add Logical Characters
SLC address,address,len Subtract Logical Characters
ED address,address,len Edit
ITC address,address,len Insert and Test Characters
AZ address,address,len Add Zoned Decimal
SZ address,address,len Subtract Zoned Decimal
MNN address,address Move Numeric to Numeric
MNZ address,address Move Numeric to Zone
MZZ address,address Move Zone to Zone
MZN address,address Move Zone to Numeric
I/O Format
----------
In the I/O format, there are always 3 fields:
da - Device Address 0-15 (decimal)
m - Modifier 0-1
n - Function 0-7
The meaning of these is entirely defined by the device addressed.
There may be an optional control byte, or an optional address (based
on the type of instruction).
SNS da,m,n,address Sense I/O
LIO da,m,n,address Load I/O
TIO da,m,n,address Test I/O
SIO da,m,n,cc Start I/O -- cc is a control byte
APL da,m,n Advance Program Level
8 Device Programming.
Note: On a model 15, interrupts are used for all devices. On
other models, interrupts are only used for the printer/keyboard.
This is a summary of the DA, M, N, and CC codes for all supported
devices:
5471 Printer Keyboard
---------------------
The PKB has 2 visible indicators: Proceed and Request
Pending. It has a normal keyboard and 4 special keys:
Request, Return, End, and Cancel.
SIO 1,0,0,XX Start Keyboard Operation, bit masks for XX are:
X'20': Request Pending Indicator On
X'10': Proceed Indicator On
X'04': Request Key Interrupts Enable (1) Disable (0)
X'02': Other Key Interrupts Enable (1) Disable (0)
X'01': Reset request key and other key interrupts
SIO 1,1,0,XX Start Printer Operation, bit masks for XX are:
X'80': Start Printing
X'40': Start Carrier Return
X'04': Printer Interrupt Enable(1) or Disable (0)
X'01': Reset Printer Interrupt
LIO 1,1,0,addr Load Printer Output Character
addr is address of low-order (highest numbered)
byte of two-byte field, and high-order byte
(that is, addr - 1) is loaded into output
register to print. Printing is done one character
at a time.
SNS 1,0,1,addr Sense Status Bytes 0 and 1:
Byte 0 (leftmost) is the character typed in
in EBCDIC.
Byte 1 is status:
X'80': Request key interrupt pending
X'40': End or Cancel key interrupt pending
X'20': Cancel key pressed
X'10': End Key Pressed
X'08': Return or data key interrupt pending
X'04': Return key pressed
SNS 1,0,3,addr Sense Status Bytes 2 and 3: returns 0000 in
this sim.
1442 Reader/Punch
-----------------
SIO 5,0,0,XX Feed Card without reading/punching
XX is stacker select for all functions: 0 = stacker
1 (normal), 1 = stacker 2.
SIO 5,0,1,XX Read Card
SIO 5,0,2,XX Punch and Feed
SIO 5,0,3,XX Read Column Binary
SIO 5,0,4,XX Punch with no feed
TIO 5,0,0,addr Branch to addr if not ready or busy
TIO 5,0,2,addr Branch to addr if busy
TIO 5,0,5,addr (mod 15 only) branch if interrupt pending
APL 5,0,0 Loop (or switch prog levels) if not ready/busy
APL 5,0,2 Loop (or switch) if busy
APL 5,0,5 Loop (or switch) if interrupt pending (mod 15 only)
LIO 5,0,0,addr Load 2-byte field to Length Count Register
LIO 5,0,4,addr Load 2-byte field to Data Address Register
(DAR is incremented by a read/punch operation and must
be reset every card)
SNS 5,0,1,addr Sense CE indicators (0000 returned in this sim)
SNS 5,0,2,addr Sense CE indicators (0000 returned in this sim)
SNS 5,0,3,addr Sense Status Indicators: (only simulated bits shown)
X'8000': Read Check
X'4000': Last Card
X'2000': Punch Check
X'1000': Data Overrun
X'0800': Not Ready
1403 Printer
------------
SIO 14,0,0,XX Line space XX lines (0-3 valid in XX)
SIO 14,0,2,XX Print a line space (0-3 valid in XX)
SIO 14,0,4,XX Skip Only (line number 1-112 in XX)
SIO 14,0,6,XX Print and Skip (line number 0-112 in XX)
TIO 14,0,0,addr Branch to addr if not ready
TIO 14,0,2,addr Branch to addr if buffer busy
TIO 14,0,3,addr Branch to addr if interrupt pending (mod 15 only)
TIO 14,0,4,addr Branch if carriage busy
TIO 14,0,6,addr Branch if printer busy
APL 14,0,0 Loop (or switch prog levels) if not ready/check
APL 14,0,2 Loop (or switch) if buffer busy
APL 14,0,3 Loop (or switch) if interrupt pending (mod 15 only)
APL 14,0,4 Loop (or switch) if carriage busy
APL 14,0,6 Loop (or switch) if printer busy
LIO 14,0,0,addr Load 1 byte to Forms Length Reg at addr-1
LIO 14,0,4,addr Load 2 bytes to Chain Image Address Register
LIO 14,0,6,addr Load 2 bytes to Data Address Register
SNS 14,0,0,addr Sense Character Count
SNS 14,0,4,addr Sense LPIAR (Image Address Register)
SNS 14,0,6,addr Sense LPDAR (data addres register)
5444 Disk Drives
----------------
Each drive has two disks (upper and lower), each disk
has two surfaces (upper and lower), each surface has
24 256-byte sectors, sectors are number 0 thru 23 on
upper surface, 32 thru 55 on lower.
d = drive, 0 is R1/F1, 1 is R2/F2
s = surface, 0 = upper (removable), 1 = lower (fixed)
The Control register points to the leftmost byte of a 4-byte
control field in memory with these bytes:
F - Flag byte (not supported in this sim)
C - Cylinder Address (0-203)
S - Sector Number (0-23, or 32-55) in top 6 bits
N - Number of sectors minus 1
These have meaning for all operations except seek, seek uses
the fields differently.
SIO 1d,s,0,XX Seek, XX not used, control field is used:
F - not used
C - not used
S - high bit is head to be used 0-upper 1-lower
low bit is direction to move 0-back 1-forward
N - number of cylinders to move
SIO 1d,s,1,XX Read, values of XX are as follows:
X'00': Read Data
X'01': Read Identifier (updates control field, no
data is read)
X'02': Read Data Diagnostic
X'03': Verify (does not read, but checks)
SIO 1d,s,2,XX Write, values of XX are as follows:
X'00': Write Data
X'01': Write Identifier (24 sectors with byte at
data address register)
SIO 1d,s,3,XX Scan. All 256 bytes in memory at data
address register are compared to disk
sectors on current track, except those
bytes of X'FF' are not compared. Values of
XX are:
X'00': Scan Equal
X'01': Scan Low or Equal
X'02': Scan High or Equal
LIO 1d,0,4,addr Load Data Address Register
LIO 1d,0,6,addr Load Disk Control Address Register
TIO 1d,0,0,addr Branch if not ready/unit check
TIO 1d,0,2,addr Branch if busy
TIO 1d,0,4,addr Branch if Scan Found
APL 1d,0,0 Loop if not ready/unit check
APL 1d,0,2 Loop if busy
APL 1d,0,4 Loop if scan found
SNS 1d,0,2,addr Sense Status Bytes 0 and 1: (simulated
bits only are shown, otehrs are 0):
X'1000': equipment check
X'0800': data check
X'0400': No record found
X'0100': Seek Check (past cyl 203)
X'0080': Scan equal Hit
X'0040': Cylinder 0
X'0020': End of Cylinder
X'0010': Seek Busy
SNS 1d,0,3,addr Sense bytes 2 and 3 (0000 in this sim)
SNS 1d,0,4,addr Sense Data Address Register
SNS 1d,0,6,addr Sense Control Address Register