mirror of
https://github.com/simh/simh.git
synced 2026-01-25 19:56:25 +00:00
Notes For V3.0-1
RESTRICTION: The FP15 and XVM features of the PDP-15 are only partially debugged. Do NOT enable these features for normal operations. 1. New Features in 3.0-1 1.1 PDP-1 - Added block loader format support to LOAD. - Changed BOOT PTR to allow loading of all of the first bank of memory. 1.2 PDP-18b Family - Added PDP-4 EAE support. - Added PDP-15 FP15 support. - Added PDP-15 XVM support. - Added PDP-15 "re-entrancy ECO". - Added PDP-7, PDP-9, PDP-15 hardware RIM loader support in BOOT PTR. 2. Bugs Fixed in 3.0-1 2.1 PDP-11/VAX - Fixed bug in user disk size (found by Chaskiel M Grundman). 2.2 PDP-1 - Updated CPU, line printer, standard devices to detect indefinite I/O wait. - Fixed incorrect logical, missing activate, break in drum simulator. - Fixed bugs in instruction decoding, overprinting for line printer. 2.3 PDP-10 - Fixed bug in RP read header. 2.4 PDP-18b Family - Fixed bug in PDP-4 line printer overprinting. - Fixed bug in PDP-15 memory protect/skip interaction. - Fixed bug in RF set size routine. - Increased PTP TIME for PDP-15 operating systems. 2.5 PDP-8 - Fixed bug in DF, RF set size routine. 2.6 Nova - Fixed bug in DSK set size routine. 2.7 1401 - Revised fetch to model hardware more closely. 2.8 Ibm1130 - Fixed bugs found by APL 1130. 2.9 Altairz80 - Fixed bug in real-time clock on Windows host. 2.10 HP2100 -- Fixed DR drum sizes. -- Fixed DR variable capacity interaction with SAVE/RESTORE. 3. New Features in 3.0 vs prior releases 3.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support 3.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 3.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 4. Bugs Fixed in 3.0 vs prior releases 4.1 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). 4.2 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. 4.3 Nova - Fixed DSK variable size interaction with restore. 4.4 PDP-1 - Fixed DT variable size interaction with restore. 4.5 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. 4.6 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. 4.7 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. 4.8 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. 4.9 GRI - Fixed bug in SC queue pointer management.
This commit is contained in:
committed by
Mark Pizzolato
parent
4ffd3be790
commit
f9564b81b9
@@ -23,6 +23,9 @@
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
12-Jul-03 RMS Moved ASCII/BCD tables to included file
|
||||
Revised fetch to model hardware
|
||||
Removed length checking in fetch phase
|
||||
16-Mar-03 RMS Fixed mnemonic, instruction lengths, and reverse
|
||||
scan length check bug for MCS
|
||||
Fixed MCE bug, BS off by 1 if zero suppress
|
||||
@@ -114,6 +117,7 @@
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
#include "i1401_dat.h"
|
||||
|
||||
#define PCQ_SIZE 64 /* must be 2**n */
|
||||
#define PCQ_MASK (PCQ_SIZE - 1)
|
||||
@@ -268,7 +272,7 @@ const int32 op_table[64] = {
|
||||
L1, /* punch feed */
|
||||
0, /* illegal */
|
||||
L1 | L4 | L7 | AREQ | BREQ | MA, /* modify address */
|
||||
L7 | AREQ | BREQ | MDV, /* multiply */
|
||||
L1 | L4 | L7 | AREQ | BREQ | MDV, /* multiply */
|
||||
0, /* illegal */
|
||||
0, /* illegal */
|
||||
0, /* illegal */
|
||||
@@ -284,7 +288,7 @@ const int32 op_table[64] = {
|
||||
L1 | L4 | L7 | AREQ | BREQ, /* move supress zero */
|
||||
0, /* illegal */
|
||||
L1 | L4 | L7 | AREQ | BREQ | NOWM, /* set word mark */
|
||||
L7 | AREQ | BREQ | MDV, /* divide */
|
||||
L1 | L4 | L7 | AREQ | BREQ | MDV, /* divide */
|
||||
0, /* illegal */
|
||||
0, /* illegal */
|
||||
0, /* illegal */
|
||||
@@ -293,7 +297,7 @@ const int32 op_table[64] = {
|
||||
L2 | L5, /* select stacker */
|
||||
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* load */
|
||||
L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* move */
|
||||
HNOP | L1 | L4 | L7, /* nop */
|
||||
HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* nop */
|
||||
0, /* illegal */
|
||||
L1 | L4 | L7 | AREQ | BREQ | MR, /* move to record */
|
||||
L1 | L4 | AREQ | MLS, /* 50: store A addr */
|
||||
@@ -315,7 +319,7 @@ const int32 op_table[64] = {
|
||||
L1 | L4 | L7 | AREQ | MLS, /* 70: store B addr */
|
||||
0, /* illegal */
|
||||
L1 | L4 | L7 | AREQ | BREQ, /* zero and add */
|
||||
HNOP | L1 | L4 | L7, /* halt */
|
||||
HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* halt */
|
||||
L1 | L4 | L7 | AREQ | BREQ, /* clear word mark */
|
||||
0, /* illegal */
|
||||
0, /* illegal */
|
||||
@@ -362,38 +366,6 @@ const int32 bin_to_bcd[16] = {
|
||||
const int32 bcd_to_bin[16] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7 };
|
||||
|
||||
/* ASCII to BCD conversion */
|
||||
|
||||
const char ascii_to_bcd[128] = {
|
||||
000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */
|
||||
000, 000, 000, 000, 000, 000, 000, 000,
|
||||
000, 000, 000, 000, 000, 000, 000, 000,
|
||||
000, 000, 000, 000, 000, 000, 000, 000,
|
||||
000, 052, 077, 013, 053, 034, 060, 032, /* 040 - 077 */
|
||||
017, 074, 054, 037, 033, 040, 073, 021,
|
||||
012, 001, 002, 003, 004, 005, 006, 007,
|
||||
010, 011, 015, 056, 076, 035, 016, 072,
|
||||
014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */
|
||||
070, 071, 041, 042, 043, 044, 045, 046,
|
||||
047, 050, 051, 022, 023, 024, 025, 026,
|
||||
027, 030, 031, 075, 036, 055, 020, 057,
|
||||
000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */
|
||||
070, 071, 041, 042, 043, 044, 045, 046,
|
||||
047, 050, 051, 022, 023, 024, 025, 026,
|
||||
027, 030, 031, 000, 000, 000, 000, 000 };
|
||||
|
||||
/* BCD to ASCII conversion - also the "full" print chain */
|
||||
|
||||
char bcd_to_ascii[64] = {
|
||||
' ', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '0', '#', '@', ':', '>', '(',
|
||||
'^', '/', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', '\'', ',', '%', '=', '\\', '+',
|
||||
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', '!', '$', '*', ']', ';', '_',
|
||||
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', '?', '.', ')', '[', '<', '"' };
|
||||
|
||||
/* Indicator resets - a 1 marks an indicator that resets when tested */
|
||||
|
||||
static const int32 ind_table[64] = {
|
||||
@@ -501,9 +473,30 @@ if (sim_brk_summ && sim_brk_test (IS, SWMASK ('E'))) { /* breakpoint? */
|
||||
|
||||
sim_interval = sim_interval - 1;
|
||||
|
||||
/* Instruction fetch */
|
||||
/* Instruction fetch - 1401 fetch works as follows:
|
||||
|
||||
if ((M[IS] & WM) == 0) { /* WM under op? */
|
||||
- Each character fetched enters the B register. This register is not
|
||||
visible; the variable t represents the B register.
|
||||
- Except for the first and last cycles, each character fetched enters
|
||||
the A register. This register is not visible; the variable D represents
|
||||
the A register, because this is the instruction modifier for 2, 5, and 8
|
||||
character instructions.
|
||||
- At the start of the second cycle (first address character), the A-address
|
||||
register and, for most instructions, the B-address register, are cleared
|
||||
to blanks. The simulator represents addresses in binary and creates the
|
||||
effect of blanks (address is bad) if less than three A-address characters
|
||||
are found. Further, the simulator accumulates only the A-address, and
|
||||
replicates it to the B-address at the appropriate point.
|
||||
- At the start of the fifth cycle (fourth address character), the B-address
|
||||
register is cleared to blanks. Again, the simulator creates the effect of
|
||||
blanks (address is bad) if less than three B-address characters are found.
|
||||
|
||||
The 1401 does explicitly check for valid instruction lengths. Most 2,3,5,6
|
||||
character instructions will be invalid because the A-address or B-address
|
||||
(or both) are invalid.
|
||||
*/
|
||||
|
||||
if ((M[IS] & WM) == 0) { /* I-Op: WM under op? */
|
||||
reason = STOP_NOWM; /* no, error */
|
||||
break; }
|
||||
op = M[IS] & CHAR; /* get opcode */
|
||||
@@ -514,25 +507,26 @@ if ((flags == 0) || (flags & ALLOPT & ~cpu_unit.flags)) {
|
||||
if (op == OP_SAR) BS = AS; /* SAR? save ASTAR */
|
||||
PP (IS);
|
||||
|
||||
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 1 char inst */
|
||||
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* I-1: WM? 1 char inst */
|
||||
D = ioind = t; /* could be D char, % */
|
||||
AS = hun_table[t]; /* could be A addr */
|
||||
PP (IS); /* if %xy, BA is set */
|
||||
|
||||
if ((t = M[IS]) & WM) { /* WM? 2 char inst */
|
||||
if ((t = M[IS]) & WM) { /* I-2: WM? 2 char inst */
|
||||
AS = AS | BA; /* ASTAR bad */
|
||||
if (!(flags & MLS)) BS = AS;
|
||||
goto CHECK_LENGTH; }
|
||||
D = dev = t; /* could be D char, dev */
|
||||
AS = AS + ten_table[t]; /* build A addr */
|
||||
dev = t; /* save char as dev */
|
||||
PP (IS);
|
||||
|
||||
if ((t = M[IS]) & WM) { /* WM? 3 char inst */
|
||||
if ((t = M[IS]) & WM) { /* I-3: WM? 3 char inst */
|
||||
AS = AS | BA; /* ASTAR bad */
|
||||
if (!(flags & MLS)) BS = AS;
|
||||
goto CHECK_LENGTH; }
|
||||
D = unit = t; /* could be D char, unit */
|
||||
if (unit == BCD_ZERO) unit = 0; /* convert unit to binary */
|
||||
AS = AS + one_table[t]; /* finish A addr */
|
||||
unit = (t == BCD_ZERO)? 0: t; /* save char as unit */
|
||||
xa = (AS >> V_INDEX) & M_INDEX; /* get index reg */
|
||||
if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */
|
||||
AS = AS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] +
|
||||
@@ -541,21 +535,23 @@ if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */
|
||||
if (!(flags & MLS)) BS = AS; /* not MLS? B = A */
|
||||
PP (IS);
|
||||
|
||||
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 4 char inst */
|
||||
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* I-4: WM? 4 char inst */
|
||||
if ((op == OP_B) && (t == BCD_BLANK)) goto CHECK_LENGTH; /* BR + space? */
|
||||
D = t; /* could be D char */
|
||||
BS = hun_table[t]; /* could be B addr */
|
||||
PP (IS);
|
||||
|
||||
if ((t = M[IS]) & WM) { /* WM? 5 char inst */
|
||||
if ((t = M[IS]) & WM) { /* I-5: WM? 5 char inst */
|
||||
BS = BS | BA; /* BSTAR bad */
|
||||
goto CHECK_LENGTH; }
|
||||
D = t; /* could be D char */
|
||||
BS = BS + ten_table[t]; /* build B addr */
|
||||
PP (IS);
|
||||
|
||||
if ((t = M[IS]) & WM) { /* WM? 6 char inst */
|
||||
if ((t = M[IS]) & WM) { /* I-6: WM? 6 char inst */
|
||||
BS = BS | BA; /* BSTAR bad */
|
||||
goto CHECK_LENGTH; }
|
||||
D = t; /* could be D char */
|
||||
BS = BS + one_table[t]; /* finish B addr */
|
||||
xa = (BS >> V_INDEX) & M_INDEX; /* get index reg */
|
||||
if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
|
||||
@@ -564,39 +560,43 @@ if (xa && (cpu_unit.flags & XSA)) { /* indexed? */
|
||||
BS = (BS & INDEXMASK) % MAXMEMSIZE; }
|
||||
PP (IS);
|
||||
|
||||
if ((M[IS] & WM) || (flags & NOWM)) goto CHECK_LENGTH; /* WM? 7 chr */
|
||||
D = M[IS]; /* last char is D */
|
||||
do { PP (IS); } while ((M[IS] & WM) == 0); /* find word mark */
|
||||
if (flags & NOWM) goto CHECK_LENGTH; /* I-7: SWM? done */
|
||||
if ((t = M[IS]) & WM) goto CHECK_LENGTH; /* WM? 7 char inst */
|
||||
D = t; /* last char is D */
|
||||
for (;;) { /* I-8: repeats until WM */
|
||||
if ((t = M[IS]) & WM) break; /* WM? done */
|
||||
D = t; /* last char is D */
|
||||
PP (IS); }
|
||||
|
||||
CHECK_LENGTH:
|
||||
ilnt = IS - saved_IS; /* get lnt */
|
||||
if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */
|
||||
((flags & HNOP) == 0)) reason = STOP_INVL;
|
||||
//if (((flags & len_table [(ilnt <= 8)? ilnt: 8]) == 0) && /* valid lnt? */
|
||||
// ((flags & HNOP) == 0)) reason = STOP_INVL;
|
||||
if ((flags & BREQ) && ADDR_ERR (BS)) reason = STOP_INVB; /* valid A? */
|
||||
if ((flags & AREQ) && ADDR_ERR (AS)) reason = STOP_INVA; /* valid B? */
|
||||
if (reason) break; /* error in fetch? */
|
||||
switch (op) { /* case on opcode */
|
||||
|
||||
/* Move instructions A check B check
|
||||
/* Move/load character instructions A check B check
|
||||
|
||||
MCW: copy A to B, preserving B WM, here fetch
|
||||
until either A or B WM
|
||||
LCA: copy A to B, overwriting B WM, here fetch
|
||||
until A WM
|
||||
MCM: copy A to B, preserving B WM, fetch fetch
|
||||
until record or group mark
|
||||
MCS: copy A to B, clearing B WM, until A WM; fetch fetch
|
||||
reverse scan and suppress leading zeroes
|
||||
MN: copy A char digit to B char digit, fetch fetch
|
||||
preserving B zone and WM
|
||||
MZ: copy A char zone to B char zone, fetch fetch
|
||||
preserving B digit and WM
|
||||
MCW copy A to B, preserving B WM, here fetch
|
||||
until either A or B WM
|
||||
LCA copy A to B, overwriting B WM, here fetch
|
||||
until A WM
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained A and B
|
||||
2,3 invalid A-address
|
||||
4 chained B address
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + modifier
|
||||
*/
|
||||
|
||||
case OP_MCW: /* move char */
|
||||
if (ilnt >= 8) { /* I/O form? */
|
||||
if (ioind != BCD_PERCNT) reason = STOP_INVL;
|
||||
else reason = iodisp (dev, unit, MD_NORM, D);
|
||||
if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */
|
||||
reason = iodisp (dev, unit, MD_NORM, D); /* dispatch I/O */
|
||||
break; }
|
||||
if (ADDR_ERR (AS)) { /* check A addr */
|
||||
reason = STOP_INVA;
|
||||
@@ -609,9 +609,8 @@ case OP_MCW: /* move char */
|
||||
break;
|
||||
|
||||
case OP_LCA: /* load char */
|
||||
if (ilnt >= 8) { /* I/O form? */
|
||||
if (ioind != BCD_PERCNT) reason = STOP_INVL;
|
||||
else reason = iodisp (dev, unit, MD_WM, D);
|
||||
if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */
|
||||
reason = iodisp (dev, unit, MD_WM, D);
|
||||
break; }
|
||||
if (ADDR_ERR (AS)) { /* check A addr */
|
||||
reason = STOP_INVA;
|
||||
@@ -621,6 +620,27 @@ case OP_LCA: /* load char */
|
||||
MM (AS); MM (BS); } /* decr pointers */
|
||||
while ((wm & WM) == 0); /* stop on A WM */
|
||||
break;
|
||||
|
||||
/* Other move instructions A check B check
|
||||
|
||||
MCM copy A to B, preserving B WM, fetch fetch
|
||||
until record or group mark
|
||||
MCS copy A to B, clearing B WM, until A WM; fetch fetch
|
||||
reverse scan and suppress leading zeroes
|
||||
MN copy A char digit to B char digit, fetch fetch
|
||||
preserving B zone and WM
|
||||
MZ copy A char zone to B char zone, fetch fetch
|
||||
preserving B digit and WM
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 self (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_MCM: /* move to rec/group */
|
||||
do {
|
||||
@@ -662,38 +682,18 @@ case OP_MZ: /* move zone */
|
||||
MM (AS); MM (BS); /* decr pointers */
|
||||
break;
|
||||
|
||||
/* Compare - A and B are checked in fetch */
|
||||
/* Branch instruction A check B check
|
||||
|
||||
case OP_C: /* compare */
|
||||
if (ilnt != 1) { /* if not chained */
|
||||
ind[IN_EQU] = 1; /* clear indicators */
|
||||
ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; }
|
||||
do {
|
||||
a = M[AS]; /* get characters */
|
||||
b = M[BS];
|
||||
wm = a | b; /* get word marks */
|
||||
if ((a & CHAR) != (b & CHAR)) { /* unequal? */
|
||||
ind[IN_EQU] = 0; /* set indicators */
|
||||
ind[IN_UNQ] = 1;
|
||||
ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR];
|
||||
ind[IN_LOW] = ind[IN_HGH] ^ 1; }
|
||||
MM (AS); MM (BS); } /* decr pointers */
|
||||
while ((wm & WM) == 0); /* stop on A, B WM */
|
||||
if ((a & WM) && !(b & WM)) { /* short A field? */
|
||||
ind[IN_EQU] = ind[IN_LOW] = 0;
|
||||
ind[IN_UNQ] = ind[IN_HGH] = 1; }
|
||||
if (!(cpu_unit.flags & HLE)) /* no HLE? */
|
||||
ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0;
|
||||
break;
|
||||
|
||||
/* Branch instructions A check B check
|
||||
Instruction lengths:
|
||||
|
||||
B 1/8 char: branch if B char equals d if branch here
|
||||
B 4 char: unconditional branch if branch
|
||||
B 5 char: branch if indicator[d] is set if branch
|
||||
BWZ: branch if (d<0>: B char WM) if branch here
|
||||
(d<1>: B char zone = d zone)
|
||||
BBE: branch if B char & d non-zero if branch here
|
||||
1 branch if B char equals d, chained if branch here
|
||||
2,3 invalid B-address if branch here
|
||||
4 unconditional branch if branch
|
||||
5 branch if indicator[d] is set if branch
|
||||
6 invalid B-address if branch here
|
||||
7 branch if B char equals d, if branch here
|
||||
d is last character of B-address
|
||||
8 branch if B char equals d if branch here
|
||||
*/
|
||||
|
||||
case OP_B: /* branch */
|
||||
@@ -701,14 +701,29 @@ case OP_B: /* branch */
|
||||
else if (ilnt == 5) { /* branch on ind? */
|
||||
if (ind[D]) { BRANCH; } /* test indicator */
|
||||
if (ind_table[D]) ind[D] = 0; } /* reset if needed */
|
||||
else {
|
||||
if (ADDR_ERR (BS)) { /* branch char eq */
|
||||
reason = STOP_INVB; /* validate B addr */
|
||||
else { /* branch char eq */
|
||||
if (ADDR_ERR (BS)) { /* validate B addr */
|
||||
reason = STOP_INVB;
|
||||
break; }
|
||||
if ((M[BS] & CHAR) == D) { BRANCH; } /* char equal? */
|
||||
else { MM (BS); } }
|
||||
break;
|
||||
|
||||
/* Other branch instructions A check B check
|
||||
|
||||
BWZ branch if (d<0>: B char WM) if branch here
|
||||
(d<1>: B char zone = d zone)
|
||||
BBE branch if B char & d non-zero if branch here
|
||||
|
||||
Instruction lengths:
|
||||
1 chained
|
||||
2,3 invalid A-address and B-address
|
||||
4 self (B-address = A-address, d = last character of A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal, d = last character of B-address
|
||||
8+ normal
|
||||
*/
|
||||
|
||||
case OP_BWZ: /* branch wm or zone */
|
||||
if (((D & 1) && (M[BS] & WM)) || /* d1? test wm */
|
||||
((D & 2) && ((M[BS] & ZONE) == (D & ZONE)))) /* d2? test zone */
|
||||
@@ -721,14 +736,24 @@ case OP_BBE: /* branch if bit eq */
|
||||
else { MM (BS); } /* decr pointer */
|
||||
break;
|
||||
|
||||
/* Arithmetic instructions A check B check
|
||||
/* Arithmetic instructions A check B check
|
||||
|
||||
ZA: move A to B, normalizing A sign, fetch fetch
|
||||
preserving B WM, until B WM
|
||||
ZS: move A to B, complementing A sign, fetch fetch
|
||||
preserving B WM, until B WM
|
||||
A: add A to B fetch fetch
|
||||
S: subtract A from B fetch fetch
|
||||
ZA move A to B, normalizing A sign, fetch fetch
|
||||
preserving B WM, until B WM
|
||||
ZS move A to B, complementing A sign, fetch fetch
|
||||
preserving B WM, until B WM
|
||||
A add A to B fetch fetch
|
||||
S subtract A from B fetch fetch
|
||||
C compare A to B fetch fetch
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 self (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_ZA: case OP_ZS: /* zero and add/sub */
|
||||
@@ -787,42 +812,71 @@ case OP_A: case OP_S: /* add/sub */
|
||||
carry = (t >= 10);
|
||||
M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; } }
|
||||
break;
|
||||
|
||||
/* I/O instructions A check B check
|
||||
|
||||
R: read a card if branch
|
||||
W: write to line printer if branch
|
||||
WR: write and read if branch
|
||||
P: punch a card if branch
|
||||
RP: read and punch if branch
|
||||
WP: write and punch if branch
|
||||
WRP: write read and punch if branch
|
||||
RF: read feed (nop)
|
||||
PF: punch feed (nop)
|
||||
SS: select stacker if branch
|
||||
CC: carriage control if branch
|
||||
MTF: magtape functions
|
||||
case OP_C: /* compare */
|
||||
if (ilnt != 1) { /* if not chained */
|
||||
ind[IN_EQU] = 1; /* clear indicators */
|
||||
ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; }
|
||||
do {
|
||||
a = M[AS]; /* get characters */
|
||||
b = M[BS];
|
||||
wm = a | b; /* get word marks */
|
||||
if ((a & CHAR) != (b & CHAR)) { /* unequal? */
|
||||
ind[IN_EQU] = 0; /* set indicators */
|
||||
ind[IN_UNQ] = 1;
|
||||
ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR];
|
||||
ind[IN_LOW] = ind[IN_HGH] ^ 1; }
|
||||
MM (AS); MM (BS); } /* decr pointers */
|
||||
while ((wm & WM) == 0); /* stop on A, B WM */
|
||||
if ((a & WM) && !(b & WM)) { /* short A field? */
|
||||
ind[IN_EQU] = ind[IN_LOW] = 0;
|
||||
ind[IN_UNQ] = ind[IN_HGH] = 1; }
|
||||
if (!(cpu_unit.flags & HLE)) /* no HLE? */
|
||||
ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0;
|
||||
break;
|
||||
|
||||
/* I/O instructions A check B check
|
||||
|
||||
R read a card if branch
|
||||
W write to line printer if branch
|
||||
WR write and read if branch
|
||||
P punch a card if branch
|
||||
RP read and punch if branch
|
||||
WP : write and punch if branch
|
||||
WRP write read and punch if branch
|
||||
RF read feed (nop)
|
||||
PF punch feed (nop)
|
||||
SS select stacker if branch
|
||||
CC carriage control if branch
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 normal
|
||||
2,3 normal, with modifier
|
||||
4 branch; modifier, if any, is last character of branch address
|
||||
5 branch + modifier
|
||||
6+ normal, with modifier
|
||||
*/
|
||||
|
||||
case OP_R: /* read */
|
||||
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
|
||||
reason = read_card (ilnt, D); /* read card */
|
||||
BS = CDR_BUF + CDR_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
break;
|
||||
|
||||
case OP_W: /* write */
|
||||
if (reason = iomod (ilnt, D, w_mod)) break; /* valid modifier? */
|
||||
reason = write_line (ilnt, D); /* print line */
|
||||
BS = LPT_BUF + LPT_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
break;
|
||||
|
||||
case OP_P: /* punch */
|
||||
if (reason = iomod (ilnt, D, NULL)) break; /* valid modifier? */
|
||||
reason = punch_card (ilnt, D); /* punch card */
|
||||
BS = CDP_BUF + CDP_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
break;
|
||||
|
||||
case OP_WR: /* write and read */
|
||||
@@ -830,7 +884,7 @@ case OP_WR: /* write and read */
|
||||
reason = write_line (ilnt, D); /* print line */
|
||||
r1 = read_card (ilnt, D); /* read card */
|
||||
BS = CDR_BUF + CDR_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
if (reason == SCPE_OK) reason = r1; /* merge errors */
|
||||
break;
|
||||
|
||||
@@ -839,7 +893,7 @@ case OP_WP: /* write and punch */
|
||||
reason = write_line (ilnt, D); /* print line */
|
||||
r1 = punch_card (ilnt, D); /* punch card */
|
||||
BS = CDP_BUF + CDP_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
if (reason == SCPE_OK) reason = r1; /* merge errors */
|
||||
break;
|
||||
|
||||
@@ -848,7 +902,7 @@ case OP_RP: /* read and punch */
|
||||
reason = read_card (ilnt, D); /* read card */
|
||||
r1 = punch_card (ilnt, D); /* punch card */
|
||||
BS = CDP_BUF + CDP_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
if (reason == SCPE_OK) reason = r1; /* merge errors */
|
||||
break;
|
||||
|
||||
@@ -858,24 +912,36 @@ case OP_WRP: /* write, read, punch */
|
||||
r1 = read_card (ilnt, D); /* read card */
|
||||
r2 = punch_card (ilnt, D); /* punch card */
|
||||
BS = CDP_BUF + CDP_WIDTH;
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
if (reason == SCPE_OK) reason = (r1 == SCPE_OK)? r2: r1;
|
||||
break;
|
||||
|
||||
case OP_SS: /* select stacker */
|
||||
if (reason = iomod (ilnt, D, ss_mod)) break; /* valid modifier? */
|
||||
if (reason = select_stack (D)) break; /* sel stack, error? */
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
break;
|
||||
|
||||
case OP_CC: /* carriage control */
|
||||
if (reason = carriage_control (D)) break; /* car ctrl, error? */
|
||||
if (ilnt >= 4) { BRANCH; } /* check for branch */
|
||||
if ((ilnt == 4) || (ilnt == 5)) { BRANCH; } /* check for branch */
|
||||
break;
|
||||
|
||||
/* MTF - magtape functions - must be at least 4 characters
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1-3 invalid I/O address
|
||||
4 normal, d-character is unit
|
||||
5 normal
|
||||
6+ normal, d-character is last character
|
||||
*/
|
||||
|
||||
case OP_MTF: /* magtape function */
|
||||
if (reason = iomod (ilnt, D, mtf_mod)) break; /* valid modifier? */
|
||||
if (reason = mt_func (unit, D)) break; /* mt func, error? */
|
||||
if (ilnt < 4) reason = STOP_INVL; /* too short? */
|
||||
else if (ioind != BCD_PERCNT) reason = STOP_INVA;
|
||||
else if (reason = iomod (ilnt, D, mtf_mod)) break; /* valid modifier? */
|
||||
reason = mt_func (unit, D); /* mt func, error? */
|
||||
break; /* can't branch */
|
||||
|
||||
case OP_RF: case OP_PF: /* read, punch feed */
|
||||
@@ -902,6 +968,15 @@ case OP_RF: case OP_PF: /* read, punch feed */
|
||||
|
||||
The first A field character is masked to its digit part, all others
|
||||
are copied intact
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 self (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_MCE: /* edit */
|
||||
@@ -1040,6 +1115,15 @@ case OP_MCE: /* edit */
|
||||
LD + 1 + length of multiplier. Locate the low order multiplier digit,
|
||||
and at the same time zero out the product field. Then compute the sign
|
||||
of the result.
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 self (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_MUL:
|
||||
@@ -1085,7 +1169,7 @@ case OP_MUL:
|
||||
|
||||
/* Divide. Comments from the PDP-10 based simulator by Len Fehskens.
|
||||
|
||||
Divide is done, like multiply, pretty muchy the same way you do it with
|
||||
Divide is done, like multiply, pretty much the same way you do it with
|
||||
pencil and paper; successive subtraction of the divisor from a substring
|
||||
of the dividend while counting up the corresponding quotient digit.
|
||||
|
||||
@@ -1106,6 +1190,15 @@ case OP_MUL:
|
||||
|
||||
Start by locating the high order non-zero digit of the divisor. This
|
||||
also tests for a divide by zero.
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 self (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_DIV:
|
||||
@@ -1170,16 +1263,19 @@ case OP_DIV:
|
||||
BS = qs - 2; /* BS = quo 10's pos */
|
||||
break;
|
||||
|
||||
/* Miscellaneous instructions A check B check
|
||||
/* Word mark instructions A check B check
|
||||
|
||||
SWM: set WM on A char and B char fetch fetch
|
||||
CWM: clear WM on A char and B char fetch fetch
|
||||
CS: clear from B down to nearest hundreds address if branch fetch
|
||||
MA: add A addr and B addr, store at B addr fetch fetch
|
||||
SAR: store A* at A addr fetch
|
||||
SBR: store B* at A addr fetch
|
||||
NOP: no operation
|
||||
H: halt
|
||||
SWM set WM on A char and B char fetch fetch
|
||||
CWM clear WM on A char and B char fetch fetch
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 one operand (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 two operands (SWM cannot be longer than 7)
|
||||
8+ two operands + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_SWM: /* set word mark */
|
||||
@@ -1194,13 +1290,41 @@ case OP_CWM: /* clear word mark */
|
||||
MM (AS); MM (BS); /* decr pointers */
|
||||
break;
|
||||
|
||||
/* Clear storage instruction A check B check
|
||||
|
||||
CS clear from B down to nearest hundreds if branch fetch
|
||||
address
|
||||
|
||||
Instruction lengths:
|
||||
|
||||
1 chained
|
||||
2,3 invalid A-address and B-address
|
||||
4 one operand (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 branch
|
||||
8+ one operand, branch ignored
|
||||
*/
|
||||
|
||||
case OP_CS: /* clear storage */
|
||||
t = (BS / 100) * 100; /* lower bound */
|
||||
while (BS >= t) M[BS--] = 0; /* clear region */
|
||||
if (BS < 0) BS = BS + MEMSIZE; /* wrap if needed */
|
||||
if (ilnt >= 7) { BRANCH; } /* branch variant? */
|
||||
if (ilnt == 7) { BRANCH; } /* branch variant? */
|
||||
break;
|
||||
|
||||
/* Modify address instruction A check B check
|
||||
|
||||
MA add A addr and B addr, store at B addr fetch fetch
|
||||
|
||||
Instruction lengths:
|
||||
1 chained
|
||||
2,3 invalid A-address and B-address
|
||||
4 self (B-address = A-address)
|
||||
5,6 invalid B-address
|
||||
7 normal
|
||||
8+ normal + ignored modifier
|
||||
*/
|
||||
|
||||
case OP_MA: /* modify address */
|
||||
a = one_table[M[AS] & CHAR]; MM (AS); /* get A address */
|
||||
a = a + ten_table[M[AS] & CHAR]; MM (AS);
|
||||
@@ -1215,15 +1339,32 @@ case OP_MA: /* modify address */
|
||||
if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2; /* carry? */
|
||||
break;
|
||||
|
||||
/* Store address instructions A-check B-check
|
||||
|
||||
SAR store A* at A addr fetch
|
||||
SBR store B* at A addr fetch
|
||||
|
||||
Instruction lengths:
|
||||
1 chained
|
||||
2,3 invalid A-address
|
||||
4 normal
|
||||
5+ B-address overwritten from instruction;
|
||||
invalid address ignored
|
||||
*/
|
||||
|
||||
case OP_SAR: case OP_SBR: /* store A, B reg */
|
||||
M[AS] = (M[AS] & WM) | store_addr_u (BS); MM (AS);
|
||||
M[AS] = (M[AS] & WM) | store_addr_t (BS); MM (AS);
|
||||
M[AS] = (M[AS] & WM) | store_addr_h (BS); MM (AS);
|
||||
break;
|
||||
|
||||
/* NOP - no validity checking, all instructions length ok */
|
||||
|
||||
case OP_NOP: /* nop */
|
||||
break;
|
||||
|
||||
/* HALT - unless length = 4 (branch), no validity checking; all lengths ok */
|
||||
|
||||
case OP_H: /* halt */
|
||||
if (ilnt == 4) hb_pend = 1; /* set pending branch */
|
||||
reason = STOP_HALT; /* stop simulator */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: IBM 1401 Simulator Usage
|
||||
Date: 20-Apr-2003
|
||||
Date: 15-Jul-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
@@ -39,13 +39,16 @@ This memorandum documents the IBM 1401 simulator.
|
||||
sim/ sim_defs.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
sim_tape.h
|
||||
sim_tmxr.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_sock.c
|
||||
sim_tape.c
|
||||
sim_tmxr.c
|
||||
|
||||
sim/i1401/ i1401_defs.h
|
||||
i1401_dat.h
|
||||
i1401_cpu.c
|
||||
i1401_cd.c
|
||||
i1401_iq.c
|
||||
|
||||
Reference in New Issue
Block a user