mirror of
https://github.com/simh/simh.git
synced 2026-04-24 19:33:40 +00:00
Notes For V2.9-11
1. New Features 1.1 GRI-909 - This is a new simulator for the GRI-909. - It has been hand-tested; so far, no software has been discovered. 1.2 VAX - SET CPU CONHALT will cause a HALT instruction to return to the boot ROM console rather than to SIMH. SET CPU SIMHALT restores the default behavior. - BRB/W self at IPL 1F stops the simulator. This is the default behavior of VMS at exit. 1.3 PDP-18b - ATTACH -A PTR/PTP attaches the reader and punch in ASCII mode. In ASCII mode, the reader automatically sets the high order bit of incoming alphabetic data, and the punch clears the high order bit of outgoing data. 1.4 SCP - DO -V echoes commands from the file as they are executed. - Under Windows, execution priority is set BELOW_NORMAL when the simulator is running. 2. Release Notes 2.1 Bugs Fixed - PDP-11 CPU: fixed updating of MMR0 on a memory management error. - VAX FPA: changed function names to avoid conflict with C math library. - 1401 MT: read end of record generates group mark without word mark. - 1401 DP: fixed address generation and checking. - SCP: an EXIT within a DO command will cause the simulator to exit. 3. In Progress - Interdata 16b/32b: coded, not tested. - SDS 940: coded, not tested. - IBM 1620: coded, not tested. If you would like to help with the debugging of the untested simulators, they can be made available by special request.
This commit is contained in:
committed by
Mark Pizzolato
parent
701f0fe028
commit
df6475181c
@@ -1,6 +1,6 @@
|
||||
/* i1401_cd.c: IBM 1402 card reader/punch
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -35,6 +35,8 @@
|
||||
Cards are represented as ASCII text streams terminated by newlines.
|
||||
This allows cards to be created and edited as normal files.
|
||||
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
30-Jan-02 RMS New zero footprint card bootstrap from Van Snyder
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
13-Apr-01 RMS Revised for register arrays
|
||||
*/
|
||||
@@ -68,7 +70,7 @@ REG cdr_reg[] = {
|
||||
{ FLDATA (ERR, ind[IN_READ], 0) },
|
||||
{ FLDATA (S1, s1sel, 0) },
|
||||
{ FLDATA (S2, s2sel, 0) },
|
||||
{ DRDATA (POS, cdr_unit.pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS, cdr_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },
|
||||
{ BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },
|
||||
{ NULL } };
|
||||
@@ -93,7 +95,7 @@ REG cdp_reg[] = {
|
||||
{ FLDATA (ERR, ind[IN_PNCH], 0) },
|
||||
{ FLDATA (S4, s4sel, 0) },
|
||||
{ FLDATA (S8, s8sel, 0) },
|
||||
{ DRDATA (POS, cdp_unit.pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS, cdp_unit.pos, 32), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE cdp_dev = {
|
||||
@@ -117,10 +119,10 @@ UNIT stack_unit[] = {
|
||||
{ UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } };
|
||||
|
||||
REG stack_reg[] = {
|
||||
{ DRDATA (POS0, stack_unit[0].pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS1, stack_unit[1].pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS28, stack_unit[2].pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS4, stack_unit[4].pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS0, stack_unit[0].pos, 32), PV_LEFT },
|
||||
{ DRDATA (POS1, stack_unit[1].pos, 32), PV_LEFT },
|
||||
{ DRDATA (POS28, stack_unit[2].pos, 32), PV_LEFT },
|
||||
{ DRDATA (POS4, stack_unit[4].pos, 32), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE stack_dev = {
|
||||
@@ -261,14 +263,11 @@ return attach_unit (uptr, cptr);
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 100
|
||||
#define BOOT_START 0
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char))
|
||||
|
||||
static const unsigned char boot_rom[] = {
|
||||
OP_R + WM, /* R */
|
||||
OP_SWM + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* SWM 001 */
|
||||
OP_CS + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* CS 001 111 */
|
||||
BCD_ONE, BCD_ONE, BCD_ONE };
|
||||
OP_R + WM, OP_NOP + WM }; /* R, NOP */
|
||||
|
||||
t_stat cdr_boot (int32 unitno)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* i1401_cpu.c: IBM 1401 CPU simulator
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -23,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.
|
||||
|
||||
03-Jun-03 RMS Added 1311 support
|
||||
22-May-02 RMS Added multiply and divide
|
||||
30-Dec-01 RMS Added old PC queue
|
||||
30-Nov-01 RMS Added extended SET/SHOW support
|
||||
10-Aug-01 RMS Removed register in declarations
|
||||
07-Dec-00 RMS Fixed bugs found by Charles Owen
|
||||
@@ -106,22 +109,33 @@
|
||||
|
||||
#include "i1401_defs.h"
|
||||
|
||||
#define PCQ_SIZE 64 /* must be 2**n */
|
||||
#define PCQ_MASK (PCQ_SIZE - 1)
|
||||
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_IS
|
||||
|
||||
/* These macros validate addresses. If an addresses error is detected,
|
||||
they return an error status to the caller. These macros should only
|
||||
be used in a routine that returns a t_stat value.
|
||||
*/
|
||||
|
||||
#define MM(x) x = x - 1; \
|
||||
if (x < 0) { \
|
||||
x = BA + MAXMEMSIZE - 1; \
|
||||
reason = STOP_WRAP; \
|
||||
break; }
|
||||
break; }
|
||||
|
||||
#define PP(x) x = x + 1; \
|
||||
if (ADDR_ERR (x)) { \
|
||||
x = BA + (x % MAXMEMSIZE); \
|
||||
reason = STOP_WRAP; \
|
||||
break; }
|
||||
|
||||
#define BRANCH if (ADDR_ERR (AS)) { \
|
||||
reason = STOP_INVBR; \
|
||||
break; } \
|
||||
if (cpu_unit.flags & XSA) BS = IS; \
|
||||
else BS = BA + 0; \
|
||||
oldIS = saved_IS; \
|
||||
PCQ_ENTRY; \
|
||||
IS = AS;
|
||||
|
||||
uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */
|
||||
@@ -129,7 +143,9 @@ int32 saved_IS = 0; /* saved IS */
|
||||
int32 AS = 0; /* AS */
|
||||
int32 BS = 0; /* BS */
|
||||
int32 as_err = 0, bs_err = 0; /* error flags */
|
||||
int32 oldIS = 0; /* previous IS */
|
||||
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
|
||||
int32 pcq_p = 0; /* PC queue ptr */
|
||||
REG *pcq_r = NULL; /* PC queue reg ptr */
|
||||
int32 ind[64] = { 0 }; /* indicators */
|
||||
int32 ssa = 1; /* sense switch A */
|
||||
int32 prchk = 0; /* process check stop */
|
||||
@@ -144,6 +160,9 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
int32 store_addr_h (int32 addr);
|
||||
int32 store_addr_t (int32 addr);
|
||||
int32 store_addr_u (int32 addr);
|
||||
int32 div_add (int32 ap, int32 bp, int32 aend);
|
||||
int32 div_sub (int32 ap, int32 bp, int32 aend);
|
||||
void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp);
|
||||
t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr);
|
||||
t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod);
|
||||
|
||||
@@ -154,6 +173,7 @@ extern t_stat carriage_control (int32 mod);
|
||||
extern t_stat write_line (int32 ilnt, int32 mod);
|
||||
extern t_stat inq_io (int32 flag, int32 mod);
|
||||
extern t_stat mt_io (int32 unit, int32 flag, int32 mod);
|
||||
extern t_stat dp_io (int32 fnc, int32 flag, int32 mod);
|
||||
extern t_stat mt_func (int32 unit, int32 mod);
|
||||
extern t_stat sim_activate (UNIT *uptr, int32 delay);
|
||||
|
||||
@@ -188,7 +208,8 @@ REG cpu_reg[] = {
|
||||
{ FLDATA (OVF, ind[IN_OVF], 0) },
|
||||
{ FLDATA (IOCHK, iochk, 0) },
|
||||
{ FLDATA (PRCHK, prchk, 0) },
|
||||
{ DRDATA (OLDIS, oldIS, 14), REG_RO + PV_LEFT },
|
||||
{ BRDATA (ISQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC },
|
||||
{ ORDATA (ISQP, pcq_p, 6), REG_HRO },
|
||||
{ ORDATA (WRU, sim_int_char, 8) },
|
||||
{ NULL } };
|
||||
|
||||
@@ -205,6 +226,8 @@ MTAB cpu_mod[] = {
|
||||
{ MR, 0, "no MR", "NOMR", NULL },
|
||||
{ EPE, EPE, "EPE", "EPE", NULL },
|
||||
{ EPE, 0, "no EPE", "NOEPE", NULL },
|
||||
{ MDV, MDV, "MDV", "MDV", NULL },
|
||||
{ MDV, 0, "no MDV", "NOMDV", NULL },
|
||||
{ UNIT_MSIZE, 4000, NULL, "4K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 8000, NULL, "8K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 12000, NULL, "12K", &cpu_set_size },
|
||||
@@ -217,6 +240,8 @@ DEVICE cpu_dev = {
|
||||
&cpu_ex, &cpu_dep, &cpu_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Tables */
|
||||
|
||||
/* Opcode table - length, dispatch, and option flags. This table is also
|
||||
used by the symbolic input routine to validate instruction lengths */
|
||||
|
||||
@@ -321,10 +346,10 @@ const int32 one_table[64] = {
|
||||
BA+12000, 12001, 12002, 12003, 12004, 12005, 12006, 12007,
|
||||
12008, 12009, 12000, BA+12003, BA+12004, BA+12005, BA+12006, BA+12007 };
|
||||
|
||||
static const int32 bin_to_bcd[16] = {
|
||||
const int32 bin_to_bcd[16] = {
|
||||
10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
static const int32 bcd_to_bin[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 */
|
||||
@@ -358,15 +383,6 @@ char bcd_to_ascii[64] = {
|
||||
'Q', 'R', '!', '$', '*', ']', ';', '_',
|
||||
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||
'H', 'I', '?', '.', ')', '[', '<', '"' };
|
||||
|
||||
t_stat sim_instr (void)
|
||||
{
|
||||
extern int32 sim_interval;
|
||||
int32 IS, D, ilnt, flags;
|
||||
int32 op, xa, t, wm, dev, unit;
|
||||
int32 a, b, i, bsave, carry;
|
||||
int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal;
|
||||
t_stat reason, r1, r2;
|
||||
|
||||
/* Indicator resets - a 1 marks an indicator that resets when tested */
|
||||
|
||||
@@ -392,24 +408,71 @@ static const int32 col_table[64] = {
|
||||
006, 032, 033, 034, 035, 036, 037, 040,
|
||||
041, 042, 031, 001, 002, 003, 004, 005 };
|
||||
|
||||
/* Summing table for two decimal digits, converted back to BCD */
|
||||
/* Summing table for two decimal digits, converted back to BCD
|
||||
Also used for multiplying two decimal digits, converted back to BCD,
|
||||
with carry forward
|
||||
*/
|
||||
|
||||
static const int32 sum_table[20] = {
|
||||
10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
static const int32 sum_table[100] = {
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE,
|
||||
BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR,
|
||||
BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE };
|
||||
|
||||
static const int32 cry_table[100] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
|
||||
|
||||
/* Legal modifier tables */
|
||||
|
||||
static const int32 w_mod[] = { BCD_S, BCD_SQUARE, -1 };
|
||||
static const int32 ss_mod[] = { 1, 2, 4, 8, -1 };
|
||||
static const int32 mtf_mod[] = { BCD_B, BCD_E, BCD_M, BCD_R, BCD_U, -1 };
|
||||
|
||||
|
||||
t_stat sim_instr (void)
|
||||
{
|
||||
extern int32 sim_interval;
|
||||
int32 IS, D, ilnt, flags;
|
||||
int32 op, xa, t, wm, dev, unit;
|
||||
int32 a, b, i, asave, bsave;
|
||||
int32 carry, lowprd, sign, ps;
|
||||
int32 quo, ahigh, qs;
|
||||
int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal;
|
||||
t_stat reason, r1, r2;
|
||||
|
||||
/* Restore saved state */
|
||||
|
||||
IS = saved_IS;
|
||||
if (as_err) AS = AS | BA; /* flag bad addresses */
|
||||
if (bs_err) BS = BS | BA;
|
||||
as_err = bs_err = 0; /* reset error flags */
|
||||
D = 0;
|
||||
reason = 0;
|
||||
|
||||
|
||||
/* Main instruction fetch/decode loop */
|
||||
|
||||
while (reason == 0) { /* loop until halted */
|
||||
@@ -551,6 +614,7 @@ case OP_MSZ: /* move suppress zero */
|
||||
wm = M[AS];
|
||||
MM (AS); MM (BS); } /* decr pointers */
|
||||
while ((wm & WM) == 0); /* stop on A WM */
|
||||
if (reason) break; /* addr err? stop */
|
||||
do { PP (BS); /* adv B */
|
||||
t = M[BS]; /* get B, cant be WM */
|
||||
if ((t == BCD_ZERO) || (t == BCD_COMMA)) {
|
||||
@@ -681,6 +745,7 @@ case OP_A: case OP_S: /* add/sub */
|
||||
else M[BS] = (b & WM) + sum_table[t]; /* normal add */
|
||||
MM (BS); }
|
||||
while ((b & WM) == 0); /* stop on B WM */
|
||||
if (reason) break; /* address err? */
|
||||
if (qsign && (carry == 0)) { /* recompl, no carry? */
|
||||
M[bsave] = M[bsave] ^ ABIT; /* XOR sign */
|
||||
for (carry = 1; bsave != BS; --bsave) { /* rescan */
|
||||
@@ -863,6 +928,7 @@ case OP_MCE: /* edit */
|
||||
MM (BS); } /* decr B pointer */
|
||||
while ((b & WM) == 0); /* stop on B WM */
|
||||
|
||||
if (reason) break; /* address err? */
|
||||
if (!qawm || !qzero) { /* rescan? */
|
||||
if (qdollar) reason = STOP_MCE3; /* error if $ */
|
||||
break; }
|
||||
@@ -913,6 +979,141 @@ case OP_MCE: /* edit */
|
||||
BS--; } /* end for */
|
||||
break; /* done at last! */
|
||||
|
||||
/* Multiply. Comments from the PDP-10 based simulator by Len Fehskens.
|
||||
|
||||
Multiply, with variable length operands, is necessarily done the same
|
||||
way you do it with paper and pencil, except that partial products are
|
||||
added into the incomplete final product as they are computed, rather
|
||||
than at the end. The 1401 multiplier format allows the product to
|
||||
be developed in place, without scratch storage.
|
||||
|
||||
The A field contains the multiplicand, length LD. The B field must be
|
||||
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.
|
||||
*/
|
||||
|
||||
case OP_MUL:
|
||||
asave = AS; bsave = lowprd = BS; /* save AS, BS */
|
||||
do { a = M[AS]; /* get mpcd char */
|
||||
M[BS] = BCD_ZERO; /* zero prod */
|
||||
MM (AS); MM (BS); } /* decr pointers */
|
||||
while ((a & WM) == 0); /* until A WM */
|
||||
if (reason) break; /* address err? */
|
||||
M[BS] = BCD_ZERO; /* zero hi prod */
|
||||
MM (BS); /* addr low mpyr */
|
||||
sign = ((M[asave] & ZONE) == BBIT) ^ ((M[BS] & ZONE) == BBIT);
|
||||
|
||||
/* Outer loop on multiplier (BS) and product digits (ps),
|
||||
inner loop on multiplicand digits (AS).
|
||||
AS and ps cannot produce an address error.
|
||||
*/
|
||||
|
||||
do { ps = bsave; /* ptr to prod */
|
||||
AS = asave; /* ptr to mpcd */
|
||||
carry = 0; /* init carry */
|
||||
b = M[BS]; /* get mpyr char */
|
||||
do { a = M[AS]; /* get mpcd char */
|
||||
t = (bcd_to_bin[a & DIGIT] * /* mpyr * mpcd */
|
||||
bcd_to_bin[b & DIGIT]) + /* + c + partial prod */
|
||||
carry + bcd_to_bin[M[ps] & DIGIT];
|
||||
carry = cry_table[t];
|
||||
M[ps] = (M[ps] & WM) | sum_table[t];
|
||||
MM (AS); ps--; }
|
||||
while ((a & WM) == 0); /* until mpcd done */
|
||||
M[BS] = (M[BS] & WM) | BCD_ZERO; /* zero mpyr just used */
|
||||
t = bcd_to_bin[M[ps] & DIGIT] + carry; /* add carry to prod */
|
||||
M[ps] = (M[ps] & WM) | sum_table[t]; /* store */
|
||||
bsave--; /* adv prod ptr */
|
||||
MM (BS); } /* adv mpyr ptr */
|
||||
while ((b & WM) == 0); /* until mpyr done */
|
||||
M[lowprd] = M[lowprd] | ZONE; /* assume + */
|
||||
if (sign) M[lowprd] = M[lowprd] & ~ABIT; /* if minus, B only */
|
||||
break;
|
||||
|
||||
/* 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
|
||||
pencil and paper; successive subtraction of the divisor from a substring
|
||||
of the dividend while counting up the corresponding quotient digit.
|
||||
|
||||
Let LS be the length of the divisor, LD the length of the dividend:
|
||||
- AS points to the low order divisor digit.
|
||||
- BS points to the high order dividend digit.
|
||||
- The low order dividend digit is identified by sign (zone) bits.
|
||||
- To the left of the dividend is a zero field of length LS + 1.
|
||||
The low quotient is at low dividend - LS - 1. As BS points to the
|
||||
high dividend, the low dividend is at BS + LD - 1, so the low
|
||||
quotient is at BS + LD - LS - 2. The longest possible quotient is
|
||||
LD - LS + 1, so the first possible non-zero quotient bit will be
|
||||
found as BS - 2.
|
||||
|
||||
This pointer calculation assumes that the divisor has no leading zeroes.
|
||||
For each leading zero, the start of the quotient will be one position
|
||||
further left.
|
||||
|
||||
Start by locating the high order non-zero digit of the divisor. This
|
||||
also tests for a divide by zero.
|
||||
*/
|
||||
|
||||
case OP_DIV:
|
||||
asave = AS; ahigh = -1;
|
||||
do { a = M[AS]; /* get dvr char */
|
||||
if ((a & CHAR) != BCD_ZERO) ahigh = AS; /* mark non-zero */
|
||||
MM (AS); }
|
||||
while ((a & WM) == 0);
|
||||
if (reason) break; /* address err? */
|
||||
if (ahigh < 0) { /* div? by zero */
|
||||
ind[IN_OVF] = 1; /* set ovf indic */
|
||||
qs = bsave = BS; /* quo, dividend */
|
||||
do { b = M[bsave]; /* find end divd */
|
||||
PP (bsave); } /* marked by zone */
|
||||
while ((b & ZONE) == 0);
|
||||
if (reason) break; /* address err? */
|
||||
if (ADDR_ERR (qs)) { /* address err? */
|
||||
reason = STOP_WRAP; /* address wrap? */
|
||||
break; }
|
||||
div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */
|
||||
BS = (BS - 2) - (asave - (AS + 1)); /* final bs */
|
||||
break; }
|
||||
bsave = BS + (asave - ahigh); /* end subdivd */
|
||||
qs = (BS - 2) - (ahigh - (AS + 1)); /* quo start */
|
||||
|
||||
/* Divide loop - done with subroutines to keep the code clean.
|
||||
In the loop,
|
||||
|
||||
asave = low order divisor
|
||||
bsave = low order subdividend
|
||||
qs = current quotient digit
|
||||
*/
|
||||
|
||||
do { quo = 0; /* clear quo digit */
|
||||
if (ADDR_ERR (qs) || ADDR_ERR (bsave)) {
|
||||
reason = STOP_WRAP; /* address wrap? */
|
||||
break; }
|
||||
b = M[bsave]; /* save low divd */
|
||||
do { t = div_sub (asave, bsave, ahigh); /* subtract */
|
||||
quo++; } /* incr quo digit */
|
||||
while (t == 0); /* until borrow */
|
||||
div_add (asave, bsave, ahigh); quo--; /* restore */
|
||||
M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */
|
||||
bsave++; qs++; } /* adv divd, quo */
|
||||
while ((b & ZONE) == 0); /* until B sign */
|
||||
if (reason) break; /* address err? */
|
||||
|
||||
/* At this point,
|
||||
|
||||
AS = high order divisor - 1
|
||||
asave = unit position of divisor
|
||||
b = unit character of dividend
|
||||
bsave = unit position of remainder + 1
|
||||
qs = unit position of quotient + 1
|
||||
*/
|
||||
|
||||
div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */
|
||||
BS = qs - 2; /* BS = quo 10's pos */
|
||||
break;
|
||||
|
||||
/* Miscellaneous instructions A check B check
|
||||
|
||||
SWM: set WM on A char and B char fetch fetch
|
||||
@@ -970,14 +1171,17 @@ default:
|
||||
reason = STOP_NXI; /* unimplemented */
|
||||
break; } /* end switch */
|
||||
} /* end while */
|
||||
|
||||
|
||||
/* Simulation halted */
|
||||
|
||||
as_err = (AS > ADDRMASK);
|
||||
bs_err = (BS > ADDRMASK);
|
||||
as_err = ADDR_ERR (AS); /* get addr err flags */
|
||||
bs_err = ADDR_ERR (BS);
|
||||
AS = AS & ADDRMASK; /* clean addresses */
|
||||
BS = BS & ADDRMASK;
|
||||
pcq_r -> qptr = pcq_p; /* update pc q ptr */
|
||||
return reason;
|
||||
} /* end sim_instr */
|
||||
|
||||
|
||||
/* store addr_x - convert address to BCD character in x position
|
||||
|
||||
Inputs:
|
||||
@@ -1006,6 +1210,59 @@ int32 thous;
|
||||
thous = (addr / 1000) & 014;
|
||||
return bin_to_bcd[addr % 10] | (thous << (V_ZONE - 2));
|
||||
}
|
||||
|
||||
/* div_add - add string for divide */
|
||||
|
||||
int32 div_add (int32 ap, int32 bp, int32 aend)
|
||||
{
|
||||
int32 a, b, c, r;
|
||||
|
||||
c = 0; /* init carry */
|
||||
do { a = M[ap]; b = M[bp]; /* get operands */
|
||||
r = bcd_to_bin[b & DIGIT] + /* sum digits + c */
|
||||
bcd_to_bin[a & DIGIT] + c;
|
||||
c = (r >= 10); /* set carry out */
|
||||
M[bp] = sum_table[r]; /* store result */
|
||||
ap--; bp--; }
|
||||
while (ap >= aend);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* div_sub - substract string for divide */
|
||||
|
||||
int32 div_sub (int32 ap, int32 bp, int32 aend)
|
||||
{
|
||||
int32 a, b, c, r;
|
||||
|
||||
c = 0; /* init borrow */
|
||||
do { a = M[ap]; b = M[bp]; /* get operands */
|
||||
r = bcd_to_bin[b & DIGIT] - /* a - b - borrow */
|
||||
bcd_to_bin[a & DIGIT] - c;
|
||||
c = (r < 0); /* set borrow out */
|
||||
M[bp] = sum_table[r + 10]; /* store result */
|
||||
ap--; bp--; }
|
||||
while (ap >= aend);
|
||||
b = M[bp] & CHAR; /* borrow position */
|
||||
if (b != BCD_ZERO) { /* non-zero? */
|
||||
r = bcd_to_bin[b & DIGIT] - c; /* subtract borrow */
|
||||
M[bp] = sum_table[r]; /* store result */
|
||||
return 0; } /* subtract worked */
|
||||
return c; /* return borrow */
|
||||
}
|
||||
|
||||
/* div_sign - set signs for divide */
|
||||
|
||||
void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp)
|
||||
{
|
||||
int32 sign = dvrc & ZONE; /* divisor sign */
|
||||
|
||||
M[rp] = M[rp] | ZONE; /* assume rem pos */
|
||||
if (sign == BBIT) M[rp] = M[rp] & ~ABIT; /* if dvr -, rem - */
|
||||
M[qp] = M[qp] | ZONE; /* assume quo + */
|
||||
if (((dvdc & ZONE) == BBIT) ^ (sign == BBIT)) /* dvr,dvd diff? */
|
||||
M[qp] = M[qp] & ~ABIT; /* make quo - */
|
||||
return;
|
||||
}
|
||||
|
||||
/* iomod - check on I/O modifiers
|
||||
|
||||
@@ -1038,6 +1295,7 @@ return STOP_INVM;
|
||||
t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod)
|
||||
{
|
||||
if (dev == IO_INQ) return inq_io (flag, mod); /* inq terminal? */
|
||||
if (dev == IO_DP) return dp_io (unit, flag, mod); /* disk pack? */
|
||||
if (dev == IO_MT) return mt_io (unit, flag, mod); /* magtape? */
|
||||
if (dev == IO_MTB) { /* binary? */
|
||||
if (flag == MD_WM) return STOP_INVM; /* invalid */
|
||||
@@ -1055,6 +1313,9 @@ for (i = 0; i < 64; i++) ind[i] = 0;
|
||||
ind[IN_UNC] = 1;
|
||||
AS = 0; as_err = 1;
|
||||
BS = 0; bs_err = 1;
|
||||
pcq_r = find_reg ("ISQ", NULL, dptr);
|
||||
if (pcq_r) pcq_r -> qptr = 0;
|
||||
else return SCPE_IERR;
|
||||
sim_brk_types = sim_brk_dflt = SWMASK ('E');
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
32
I1401/i1401_dat.h
Normal file
32
I1401/i1401_dat.h
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
/* 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', '?', '.', ')', '[', '<', '"' };
|
||||
@@ -1,6 +1,6 @@
|
||||
/* i1401_defs.h: IBM 1401 simulator definitions
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -23,6 +23,7 @@
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
03-Jun-03 RMS Added 1311 support
|
||||
14-Apr-99 RMS Converted t_addr to unsigned
|
||||
|
||||
This simulator is based on the 1401 simulator written by Len Fehskens
|
||||
@@ -56,6 +57,15 @@
|
||||
#define STOP_MCE2 19 /* MCE short B field */
|
||||
#define STOP_MCE3 20 /* MCE hanging $ */
|
||||
#define STOP_IOC 21 /* I/O check */
|
||||
#define STOP_INVDSC 22 /* invalid disk sector */
|
||||
#define STOP_INVDCN 23 /* invalid disk count */
|
||||
#define STOP_INVDSK 24 /* invalid disk unit */
|
||||
#define STOP_INVDFN 25 /* invalid disk func */
|
||||
#define STOP_INVDLN 26 /* invalid disk reclen */
|
||||
#define STOP_WRADIS 27 /* write address dis */
|
||||
#define STOP_WRCHKE 28 /* write check error */
|
||||
#define STOP_INVDAD 39 /* invalid disk addr */
|
||||
#define STOP_INVDCY 30 /* invalid direct seek */
|
||||
|
||||
/* Memory and devices */
|
||||
|
||||
@@ -111,7 +121,7 @@
|
||||
#define HLE (1 << (UNIT_V_UF + 6)) /* high/low/equal */
|
||||
#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* fake flag */
|
||||
#define ALLOPT (MDV + MR + XSA + EPE + MA + BBE + HLE)
|
||||
#define STDOPT (MR + XSA + EPE + MA + BBE + HLE)
|
||||
#define STDOPT (MDV + MR + XSA + EPE + MA + BBE + HLE)
|
||||
|
||||
/* Fetch control */
|
||||
|
||||
@@ -238,13 +248,14 @@
|
||||
#define IN_EQU 022 /* equal */
|
||||
#define IN_LOW 023 /* low */
|
||||
#define IN_HGH 024 /* high */
|
||||
#define IN_PAR 025 /* parity check */
|
||||
#define IN_DPW 025 /* parity/compare check */
|
||||
#define IN_LNG 026 /* wrong lnt record */
|
||||
#define IN_UNA 027 /* unequal addr cmp */
|
||||
#define IN_DSK 030 /* disk error */
|
||||
#define IN_OVF 031 /* overflow */
|
||||
#define IN_LPT 032 /* printer error */
|
||||
#define IN_PRO 034 /* process check */
|
||||
#define IN_DBY 036 /* disk busy */
|
||||
#define IN_END 042 /* end indicator */
|
||||
#define IN_TAP 043 /* tape error */
|
||||
#define IN_ACC 045 /* access error */
|
||||
@@ -261,3 +272,5 @@
|
||||
#define IN_SSF 066 /* sense switch F */
|
||||
#define IN_SSG 067 /* sense switch G */
|
||||
#define IN_READ 072 /* reader error */
|
||||
|
||||
#define CRETIOE(f,c) return ((f)? (c): SCPE_OK)
|
||||
@@ -1,14 +1,14 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: IBM 1401 Simulator Usage
|
||||
Date: 1-Dec-01
|
||||
Date: 15-Jun-2002
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2001, written by Robert M Supnik
|
||||
Copyright (c) 1993-2001, Robert M Supnik
|
||||
Original code published in 1993-2002, written by Robert M Supnik
|
||||
Copyright (c) 1993-2002, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -43,8 +43,10 @@ sim/ sim_defs.h
|
||||
|
||||
sim/i1401/ i1401_defs.h
|
||||
i1401_cpu.c
|
||||
i1401_cd.c
|
||||
i1401_iq.c
|
||||
i1401_lp.c
|
||||
i1401_dp.c
|
||||
i1401_mt.c
|
||||
i1401_sys.c
|
||||
|
||||
@@ -59,6 +61,7 @@ CPU IBM 1401 CPU with 16K of memory
|
||||
CDR,CDP IBM 1402 card reader/punch
|
||||
LPT IBM 1403 line printer
|
||||
INQ IBM 1407 inquiry terminal
|
||||
DP IBM 1311 disk pack with five drives
|
||||
MT IBM 729 7-track magnetic tape controller with six drives
|
||||
|
||||
The IBM 1401 simulator implements many unique stop conditions. On almost
|
||||
@@ -83,8 +86,13 @@ any kind of error the simulator stops:
|
||||
single character B field in MCE
|
||||
hanging $ in MCE with EPE enabled
|
||||
I/O check with I/O stop switch set
|
||||
invalid disk drive
|
||||
invalid disk sector address
|
||||
invalid disk sector count
|
||||
invalid disk address compare
|
||||
|
||||
The LOAD and DUMP commands are not implemented.
|
||||
The LOAD command is used to load a line printer carriage-control tape.
|
||||
The DUMP command is not implemented.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
@@ -102,6 +110,8 @@ when memory size is greater than 4K.
|
||||
SET CPU NOMR disable move record
|
||||
SET CPU EPE enable extended print edit special feature
|
||||
SET CPU NOEPE disable extended print edit
|
||||
SET CPU MDV enable multiply/divide special feature
|
||||
SET CPU NOMDV disable multiply/divide
|
||||
SET CPU 4K set memory size = 4K
|
||||
SET CPU 8K set memory size = 8K
|
||||
SET CPU 12K set memory size = 12K
|
||||
@@ -147,7 +157,8 @@ interrupt system.
|
||||
OVF 1 overflow indicator
|
||||
IOCHK 1 I/O check switch
|
||||
PRCHK 1 process check switch
|
||||
OLDIS 1 IS prior to last branch
|
||||
ISQ 1 IS prior to last branch;
|
||||
most recent IS change first
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 1402 Card Reader/Punch (CDR, CDP, STKR)
|
||||
@@ -177,7 +188,7 @@ The reader/punch registers are:
|
||||
ERR 1 error indicator
|
||||
S1 1 stacker 1 select flag
|
||||
S2 1 stacker 2 select flag
|
||||
POS 31 position
|
||||
POS 32 position
|
||||
TIME 24 delay window for stacker select
|
||||
BUF[0:79] 8 reader buffer
|
||||
|
||||
@@ -185,10 +196,10 @@ The reader/punch registers are:
|
||||
S4 1 stacker 4 select flag
|
||||
S8 1 stacker 8 select flag
|
||||
|
||||
STKR POS0 31 position, normal reader stack
|
||||
POS1 31 position, reader stacker 1
|
||||
POS2 31 position, shared stacker 2/8
|
||||
POS4 31 position, punch stacker 4
|
||||
STKR POS0 32 position, normal reader stack
|
||||
POS1 32 position, reader stacker 1
|
||||
POS2 32 position, shared stacker 2/8
|
||||
POS4 32 position, punch stacker 4
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
@@ -245,7 +256,7 @@ The line printer registers are:
|
||||
CCTP 8 carriage control tape pointer
|
||||
CCTL 8 carriage control tape length (read only)
|
||||
ERR 1 error indicator
|
||||
POS 31 position
|
||||
POS 32 position
|
||||
CCT[0:131] 32 carriage control tape array
|
||||
|
||||
Error handling is as follows:
|
||||
@@ -278,18 +289,68 @@ character is typed in. The latter cancels the type-in and sets INC.
|
||||
|
||||
The inquiry terminal has no errors.
|
||||
|
||||
2.5 729 Magnetic Tape (MT)
|
||||
2.5 1311 Disk Pack (DP)
|
||||
|
||||
The disk pack controller supports 5 drives, numbered 0 through 4. Disk
|
||||
pack options include the ability to enable address writing (formatting).
|
||||
|
||||
SET DPn ADDROFF set unit n address enable off
|
||||
SET DPn ADDRON set unit n address enable on
|
||||
|
||||
Units can also be set ONLINE or OFFLINE. Disk data is buffered in
|
||||
memory; IO errors cannot occur.
|
||||
|
||||
Unlike most simulated disks, the 1311 includes explicit representation
|
||||
for sector addresses. This is to support non-standard formats, such as
|
||||
the inclusion of the drive number in the sector address. As a result,
|
||||
1311 sectors are 106 characters long: 6 address characters and 100
|
||||
data characters. If the 1311 has not been formatted, the addresses
|
||||
are blanks and are synthesized, if needed, based on the sector number.
|
||||
|
||||
The 1311 also supports two modes of operation: move mode and load mode.
|
||||
In move mode, word marks are ignored on writes and left untouched on reads,
|
||||
and sectors hold 100 characters. In load mode, word marks are included
|
||||
on writes and stored on reads, and sectors hold 90 characters. No attempt
|
||||
is made to deal with sectors written in load mode and read in move mode,
|
||||
or vice versa; on a real 1401, this causes a fatal parity error.
|
||||
|
||||
The disk pack controller implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
ACC 1 access error indicator
|
||||
PWC 1 parity or write check error indicator
|
||||
WLR 1 wrong length record error indicator
|
||||
UNA 1 unequal address compare error indicator
|
||||
DSK 1 any disk error indicator
|
||||
BSY 1 disk access busy indicator
|
||||
LASTF 3 most recent function
|
||||
TIME 24 seek time
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error processed as
|
||||
|
||||
not attached set DSK indicator
|
||||
if IOCHK set, report error and stop
|
||||
|
||||
The 1311 has a primative overlapped seek capability. If TIME is set
|
||||
non-zero, the 1311 will report itself busy for the specified amount
|
||||
of time following a seek. This allows programs to utilize the seek
|
||||
time for processing.
|
||||
|
||||
2.6 729 Magnetic Tape (MT)
|
||||
|
||||
The magnetic tape controller supports six drives, numbered 1 through 6.
|
||||
Magnetic tape options include the ability to make units write enabled or
|
||||
or write locked.
|
||||
|
||||
SET MTn LOCKED set unit n write locked
|
||||
SET MTn ENABLED set unit n write enabled
|
||||
SET MTn WRITEENABLED set unit n write enabled
|
||||
|
||||
Units can also be REMOVEd or ADDed to the configuration. The magnetic
|
||||
tape simulator supports the BOOT command. BOOT MT reads the first
|
||||
record off tape, starting at location 1, and then branches to it.
|
||||
Units can also be set ONLINE or OFFLINE. The magnetic tape simulator
|
||||
supports the BOOT command. BOOT MT reads the first record off tape,
|
||||
starting at location 1, and then branches to it.
|
||||
|
||||
The magnetic tape controller implements these registers:
|
||||
|
||||
@@ -298,7 +359,7 @@ The magnetic tape controller implements these registers:
|
||||
END 1 end of file indicator
|
||||
ERR 1 error indicator
|
||||
PAR 1 parity error indicator
|
||||
POS1..6 31 position, drives 1..6
|
||||
POS1..6 32 position, drives 1..6
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
@@ -313,7 +374,7 @@ Error handling is as follows:
|
||||
if IOCHK set, report error and stop
|
||||
otherwise, set ERR indicator
|
||||
|
||||
2.6 Symbolic Display and Input
|
||||
2.7 Symbolic Display and Input
|
||||
|
||||
The IBM 1401 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
@@ -324,6 +385,8 @@ controlled by command line switches:
|
||||
(CPU only)
|
||||
-m display instruction mnemonics
|
||||
(CPU only)
|
||||
-d display 50 characters per line, with word
|
||||
marks denoted by "1" on the line below
|
||||
|
||||
In a CPU character display, word marks are denoted by ~.
|
||||
|
||||
|
||||
554
I1401/i1401_dp.c
Normal file
554
I1401/i1401_dp.c
Normal file
@@ -0,0 +1,554 @@
|
||||
/* i1401_dp.c: IBM 1311 disk simulator
|
||||
|
||||
Copyright (c) 2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
dp 1311 disk pack
|
||||
|
||||
15-Jun-02 Reworked address comparison logic
|
||||
|
||||
The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track.
|
||||
Each sector contains 106 characters of information:
|
||||
|
||||
6c sector address
|
||||
100c sector data
|
||||
|
||||
By default, a sector's address field will be '000000', which is illegal.
|
||||
This is interpreted to mean the implied sector number that would be in
|
||||
place if the disk pack had been formatted with sequential sector numbers.
|
||||
|
||||
The sector data can be 100 characters without word marks, or 90 characters
|
||||
with word marks. Load mode transfers 90 characters per sector with
|
||||
word marks, move mode transfers 100 characters per sector without word
|
||||
marks. No attempt is made to catch incompatible writes (eg, load mode
|
||||
write followed by move mode read).
|
||||
*/
|
||||
|
||||
#include "i1401_defs.h"
|
||||
|
||||
#define DP_NUMDR 5 /* #drives */
|
||||
#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */
|
||||
#define UNIT_WAE (1 << UNIT_V_WAE)
|
||||
#define UNIT_W_UF 2 /* #save flags */
|
||||
|
||||
/* Disk format */
|
||||
|
||||
#define DP_ADDR 6 /* address */
|
||||
#define DP_DATA 100 /* data */
|
||||
#define DP_NUMCH (DP_ADDR + DP_DATA)
|
||||
|
||||
#define DP_NUMSC 20 /* #sectors */
|
||||
#define DP_NUMSF 10 /* #surfaces */
|
||||
#define DP_NUMCY 100 /* #cylinders */
|
||||
#define DP_TOTSC (DP_NUMCY*DP_NUMSF*DP_NUMSC)
|
||||
#define DP_SIZE (DP_TOTSC*DP_NUMCH)
|
||||
|
||||
/* Disk control field */
|
||||
|
||||
#define DCF_DRV 0 /* drive select */
|
||||
#define DCF_SEC 1 /* sector addr */
|
||||
#define DCF_SEC_LEN 6
|
||||
#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */
|
||||
#define DCF_CNT_LEN 3
|
||||
#define DCF_LEN (DCF_CNT + DCF_CNT_LEN)
|
||||
#define DCF_DIR 1 /* direct seek */
|
||||
#define DCF_DIR_LEN 4
|
||||
#define DCF_DIR_FL (DCF_DIR + DCF_DIR_LEN) /* direct seek flag */
|
||||
#define DCF_DSEEK 0xB
|
||||
|
||||
/* Functions */
|
||||
|
||||
#define FNC_SEEK 0 /* seek */
|
||||
#define FNC_CHECK 3 /* check */
|
||||
#define FNC_READ 1 /* read sectors */
|
||||
#define FNC_RSCO 5 /* read sec cnt overlay */
|
||||
#define FNC_RTRK 6 /* read track */
|
||||
#define FNC_WOFF 10 /* offset for write */
|
||||
#define FNC_WRITE 11 /* write sectors */
|
||||
#define FNC_WRSCO 15 /* write sec cnt overlay */
|
||||
#define FNC_WRTRK 16 /* write track */
|
||||
|
||||
#define CYL u3 /* current cylinder */
|
||||
|
||||
extern uint8 M[]; /* memory */
|
||||
extern int32 ind[64];
|
||||
extern int32 AS, BS, iochk;
|
||||
extern int32 bcd_to_bin[16];
|
||||
extern int32 bin_to_bcd[16];
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 dp_lastf = 0; /* prior function */
|
||||
int32 dp_time = 0; /* seek time */
|
||||
|
||||
t_stat dp_reset (DEVICE *dptr);
|
||||
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 wchk);
|
||||
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 wchk);
|
||||
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg);
|
||||
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg);
|
||||
int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf, int32 flg);
|
||||
t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf, int32 flg);
|
||||
t_bool dp_zeroad (uint8 *ap);
|
||||
t_bool dp_cmp_ad (uint8 *ap, int32 dcf, int32 flg);
|
||||
int32 dp_trkop (int32 drv, int32 sec);
|
||||
int32 dp_cvt_bcd (int32 ad, int32 len);
|
||||
void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg);
|
||||
int32 dp_get_cnt (int32 dcf);
|
||||
void dp_fill (UNIT *uptr, uint32 da, int32 cnt);
|
||||
|
||||
/* DP data structures
|
||||
|
||||
dp_dev DSK device descriptor
|
||||
dp_unit DSK unit list
|
||||
dp_reg DSK register list
|
||||
dp_mod DSK modifier list
|
||||
*/
|
||||
|
||||
UNIT dp_unit[] = {
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) },
|
||||
{ UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE +
|
||||
UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } };
|
||||
|
||||
REG dp_reg[] = {
|
||||
{ FLDATA (ACC, ind[IN_ACC], 0) },
|
||||
{ FLDATA (PWC, ind[IN_DPW], 0) },
|
||||
{ FLDATA (WLR, ind[IN_LNG], 0) },
|
||||
{ FLDATA (UNA, ind[IN_UNA], 0) },
|
||||
{ FLDATA (ERR, ind[IN_DSK], 0) },
|
||||
{ FLDATA (BSY, ind[IN_DBY], 0) },
|
||||
{ DRDATA (LASTF, dp_lastf, 3) },
|
||||
{ DRDATA (TIME, dp_time, 24), PV_LEFT },
|
||||
{ URDATA (CYL, dp_unit[0].CYL, 10, 8, 0,
|
||||
DP_NUMDR, PV_LEFT + REG_RO) },
|
||||
{ URDATA (FLG, dp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
|
||||
DP_NUMDR, REG_HRO) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB dp_mod[] = {
|
||||
{ UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL },
|
||||
{ UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dp_dev = {
|
||||
"DP", dp_unit, dp_reg, dp_mod,
|
||||
DP_NUMDR, 10, 21, 1, 8, 7,
|
||||
NULL, NULL, &dp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Disk IO routine
|
||||
|
||||
Inputs:
|
||||
fnc = function character
|
||||
flg = load vs move mode
|
||||
mod = modifier character
|
||||
Outputs:
|
||||
status = status
|
||||
*/
|
||||
|
||||
t_stat dp_io (int32 fnc, int32 flg, int32 mod)
|
||||
{
|
||||
int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff;
|
||||
UNIT *uptr;
|
||||
t_stat r = SCPE_OK;
|
||||
|
||||
dcf = BS; /* save DCF addr */
|
||||
qwc = 0; /* not wcheck */
|
||||
ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */
|
||||
ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0;
|
||||
if (sim_is_active (&dp_unit[0])) { /* ctlr busy? */
|
||||
ind[IN_DBY] = ind[IN_DSK] = 1; /* set indicators */
|
||||
return SCPE_OK; } /* done */
|
||||
|
||||
AS = dcf + 6; /* AS for most ops */
|
||||
BS = dcf + DCF_CNT - 1; /* minimum DCF */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */
|
||||
if (M[dcf] & BBIT) drv = M[dcf + DCF_SEC + 1] & 0xE; /* impl sel? cyl 8-4-2 */
|
||||
else drv = M[dcf] & DIGIT; /* get drive sel */
|
||||
if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */
|
||||
return STOP_INVDSK;
|
||||
drv = bcd_to_bin[drv] >> 1; /* convert */
|
||||
uptr = dp_dev.units + drv; /* get unit ptr */
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */
|
||||
ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */
|
||||
CRETIOE (iochk, SCPE_UNATT); }
|
||||
|
||||
if ((fnc == FNC_SEEK) && /* seek and */
|
||||
(M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */
|
||||
diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */
|
||||
if (diff < 0) return STOP_INVDSC; /* error? */
|
||||
diff = diff >> 1; /* diff is *2 */
|
||||
if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT)
|
||||
diff = -diff; /* get sign */
|
||||
uptr -> CYL = uptr -> CYL + diff; /* bound seek */
|
||||
if (uptr -> CYL < 0) uptr -> CYL = 0;
|
||||
else if (uptr -> CYL >= DP_NUMCY) { /* too big? */
|
||||
uptr -> CYL = 0; /* system hangs */
|
||||
return STOP_INVDCY; }
|
||||
sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */
|
||||
return SCPE_OK; } /* done! */
|
||||
|
||||
sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */
|
||||
if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */
|
||||
return STOP_INVDSC;
|
||||
if (fnc == FNC_SEEK) { /* seek? */
|
||||
uptr -> CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */
|
||||
DP_NUMCY;
|
||||
sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */
|
||||
return SCPE_OK; } /* done! */
|
||||
|
||||
BS = dcf + DCF_LEN; /* full DCF */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; /* DCF in memory? */
|
||||
cnt = dp_get_cnt (dcf); /* get count */
|
||||
if (cnt < 0) return STOP_INVDCN; /* bad count? */
|
||||
|
||||
if (fnc >= FNC_WOFF) return STOP_INVDFN; /* invalid func */
|
||||
if (mod == BCD_W) { /* write? */
|
||||
if (fnc == FNC_CHECK) { /* write check? */
|
||||
qwc = 1; /* special read */
|
||||
fnc = dp_lastf; } /* use last func */
|
||||
else { dp_lastf = fnc; /* save func */
|
||||
fnc = fnc + FNC_WOFF; } } /* change to write */
|
||||
else if (mod == BCD_R) dp_lastf = fnc; /* read? save func */
|
||||
else return STOP_INVM; /* other? error */
|
||||
psec = dp_fndsec (uptr, sec, dcf, flg); /* find sector */
|
||||
|
||||
switch (fnc) { /* case on function */
|
||||
case FNC_RSCO: /* read sec cnt ov */
|
||||
BS = dcf + DCF_CNT; /* set count back */
|
||||
/* fall thru */
|
||||
case FNC_READ: /* read */
|
||||
if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */
|
||||
if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read sector */
|
||||
break;
|
||||
cnt = dp_get_cnt (dcf); /* get new count */
|
||||
if (cnt < 0) return STOP_INVDCN; /* bad count? */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
sec++; psec++; /* next sector */
|
||||
dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */
|
||||
if (r = dp_nexsec (uptr, psec, dcf, flg)) break; /* find next */
|
||||
}
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_RTRK: /* read track */
|
||||
AS = dcf + 9; /* special AS */
|
||||
psec = dp_trkop (drv, sec); /* start of track */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */
|
||||
if (r = dp_rdadr (uptr, psec, flg, qwc)) /* read addr */
|
||||
break; /* error? */
|
||||
if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read data */
|
||||
break; /* error? */
|
||||
cnt = dp_get_cnt (dcf); /* get new count */
|
||||
if (cnt < 0) return STOP_INVDCN; /* bad count? */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_WRSCO: /* write sec cnt ov */
|
||||
BS = dcf + DCF_CNT; /* set count back */
|
||||
/* fall through */
|
||||
case FNC_WRITE: /* read */
|
||||
if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* rewr cnt */
|
||||
if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
sec++; psec++; /* next sector */
|
||||
dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */
|
||||
if (r = dp_nexsec (uptr, psec, dcf, flg)) break; /* find next */
|
||||
}
|
||||
break; /* done, clean up */
|
||||
|
||||
case FNC_WRTRK: /* write track */
|
||||
if ((uptr -> flags & UNIT_WAE) == 0) /* enabled? */
|
||||
return STOP_WRADIS;
|
||||
AS = dcf + 9; /* special AS */
|
||||
psec = dp_trkop (drv, sec); /* start of track */
|
||||
for (;;) { /* loop */
|
||||
qzr = (--cnt == 0); /* set zero latch */
|
||||
dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */
|
||||
if (r = dp_wradr (uptr, psec, flg)) break; /* write addr */
|
||||
if (r = dp_wrsec (uptr, psec, flg)) break; /* write data */
|
||||
if (qzr) break; /* zero latch? done */
|
||||
psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); }
|
||||
break; /* done, clean up */
|
||||
|
||||
default: /* unknown */
|
||||
return STOP_INVDFN; }
|
||||
|
||||
if (r == SCPE_OK) { /* normal so far? */
|
||||
BS++; /* advance BS */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; /* address error? */
|
||||
if (M[BS - 1] != (WM + BCD_GRPMRK)) { /* GM + WM at end? */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */
|
||||
r = STOP_INVDLN; } }
|
||||
CRETIOE (iochk || !ind[IN_DSK], r); /* return status */
|
||||
}
|
||||
|
||||
/* Read or compare address with memory */
|
||||
|
||||
t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 qwc)
|
||||
{
|
||||
int32 i;
|
||||
uint8 ac;
|
||||
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */
|
||||
t_bool zad = dp_zeroad (ap); /* zero address */
|
||||
static const int32 dec_tab[DP_ADDR] = /* powers of 10 */
|
||||
{ 100000, 10000, 1000, 100, 10, 1} ;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++) { /* copy address */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (zad) { /* addr zero? */
|
||||
ac = sec / dec_tab[i]; /* get addr digit */
|
||||
sec = sec % dec_tab[i]; /* get remainder */
|
||||
ac = bcd_to_bin[ac]; } /* cvt to BCD */
|
||||
else ac = *ap; /* addr char */
|
||||
if (qwc) { /* wr chk? zad ok */
|
||||
if (!zad && (flg? (M[BS] != *ap): /* L? cmp with WM */
|
||||
((M[BS] & CHAR) != (*ap & CHAR)))) { /* M? cmp w/o WM */
|
||||
ind[IN_DPW] = ind[IN_DSK] = 1;
|
||||
return STOP_WRCHKE; } }
|
||||
else if (flg) M[BS] = *ap & CHAR; /* load mode */
|
||||
else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* move mode */
|
||||
ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Read or compare data with memory */
|
||||
|
||||
t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 qwc)
|
||||
{
|
||||
int32 i, lim;
|
||||
int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr -> filebuf) + da + DP_ADDR; /* buf ptr */
|
||||
|
||||
lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */
|
||||
for (i = 0; i < lim; i++) { /* copy data */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (qwc) { /* write check? */
|
||||
if (flg? (M[BS] != *ap): /* load mode cmp */
|
||||
((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */
|
||||
ind[IN_DPW] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_WRCHKE; } }
|
||||
else if (flg) M[BS] = *ap & (WM | CHAR); /* load mode */
|
||||
else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* word mode */
|
||||
ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write address to disk */
|
||||
|
||||
t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg)
|
||||
{
|
||||
int32 i;
|
||||
uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++) { /* copy address */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (flg) *ap = M[BS] & (WM | CHAR); /* L? copy WM */
|
||||
else *ap = M[BS] & CHAR; /* M? strip WM */
|
||||
if (da >= uptr -> hwmark) uptr -> hwmark = da + 1;
|
||||
da++; ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Write data to disk */
|
||||
|
||||
t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg)
|
||||
{
|
||||
int32 i, lim;
|
||||
uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */
|
||||
|
||||
lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */
|
||||
for (i = 0; i < lim; i++) { /* copy data */
|
||||
if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */
|
||||
dp_fill (uptr, da, DP_DATA - i); /* fill, set err */
|
||||
ind[IN_LNG] = ind[IN_DSK] = 1; /* error */
|
||||
return STOP_INVDLN; }
|
||||
if (flg) *ap = M[BS] & (WM | CHAR); /* load, copy WM */
|
||||
else *ap = M[BS] & CHAR; /* move, strip WM */
|
||||
if (da >= uptr -> hwmark) uptr -> hwmark = da + 1;
|
||||
da++; ap++; BS++; /* adv ptrs */
|
||||
if (ADDR_ERR (BS)) return STOP_WRAP; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Find sector */
|
||||
|
||||
int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf, int32 flg)
|
||||
{
|
||||
int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
|
||||
int32 psec = ((uptr -> CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk;
|
||||
int32 da = psec * DP_NUMCH; /* char number */
|
||||
uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */
|
||||
int32 i;
|
||||
|
||||
if (dp_zeroad (ap)) return psec; /* addr zero? ok */
|
||||
if (dp_cmp_ad (ap, dcf, flg)) return psec; /* addr comp? ok */
|
||||
psec = psec - (psec % DP_NUMSC); /* sector 0 */
|
||||
for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */
|
||||
da = psec * DP_NUMCH; /* char number */
|
||||
ap = ((uint8 *) uptr -> filebuf) + da; /* word pointer */
|
||||
if (dp_zeroad (ap)) continue; /* no implicit match */
|
||||
if (dp_cmp_ad (ap, dcf, flg)) return psec; } /* match? */
|
||||
ind[IN_UNA] = ind[IN_DSK] = 1; /* no match */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find next sector - must be sequential, cannot cross cylinder boundary */
|
||||
|
||||
t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf, int32 flg)
|
||||
{
|
||||
int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */
|
||||
int32 da = psec * DP_NUMCH; /* word number */
|
||||
uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */
|
||||
|
||||
if (ctrk) { /* not trk zero? */
|
||||
if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */
|
||||
if (dp_cmp_ad (ap, dcf, flg)) return SCPE_OK; }/* addr comp? ok */
|
||||
ind[IN_UNA] = ind[IN_DSK] = 1; /* no, error */
|
||||
return STOP_INVDAD;
|
||||
}
|
||||
|
||||
/* Test for zero address */
|
||||
|
||||
t_bool dp_zeroad (uint8 *ap)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
|
||||
if (*ap & CHAR) return FALSE; } /* nonzero? lose */
|
||||
return TRUE; /* all zeroes */
|
||||
}
|
||||
|
||||
/* Compare disk address to memory sector address - always omit word marks */
|
||||
|
||||
t_bool dp_cmp_ad (uint8 *ap, int32 dcf, int32 flg)
|
||||
{
|
||||
int32 i;
|
||||
uint8 c;
|
||||
|
||||
for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */
|
||||
c = M[dcf + DCF_SEC + i]; /* sector addr char */
|
||||
if ((c & CHAR) != (*ap & CHAR)) /* cmp w/o WM */
|
||||
return FALSE; }
|
||||
return TRUE; /* compare ok */
|
||||
}
|
||||
|
||||
/* Track operation setup */
|
||||
|
||||
int32 dp_trkop (int32 drv, int32 sec)
|
||||
{
|
||||
int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF;
|
||||
|
||||
return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) +
|
||||
(ctrk * DP_NUMSC));
|
||||
}
|
||||
|
||||
/* Convert DCF BCD field to binary */
|
||||
|
||||
int32 dp_cvt_bcd (int32 ad, int32 len)
|
||||
{
|
||||
uint8 c;
|
||||
int32 r;
|
||||
|
||||
for (r = 0; len > 0; len--) { /* loop thru char */
|
||||
c = M[ad] & DIGIT; /* get digit */
|
||||
if ((c == 0) || (c > BCD_ZERO)) return -1; /* invalid? */
|
||||
r = (r * 10) + bcd_to_bin[c]; /* cvt to bin */
|
||||
ad++; } /* next digit */
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Convert binary to DCF BCD field */
|
||||
|
||||
void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg)
|
||||
{
|
||||
int32 r;
|
||||
|
||||
for ( ; len > 0; len--) { /* loop thru char */
|
||||
r = val % 10; /* get digit */
|
||||
if (flg) M[ad + len - 1] = bin_to_bcd[r]; /* load mode? */
|
||||
else M[ad + len - 1] = (M[ad + len - 1] & WM) | bin_to_bcd[r];
|
||||
val = val / 10; }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get and validate count */
|
||||
|
||||
int32 dp_get_cnt (int32 dcf)
|
||||
{
|
||||
int32 cnt = dp_cvt_bcd (dcf + DCF_CNT, DCF_CNT_LEN); /* get new count */
|
||||
if (cnt < 0) return -1; /* bad count? */
|
||||
if (cnt == 0) return 1000; /* 0 => 1000 */
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/* Fill sector buffer with blanks */
|
||||
|
||||
void dp_fill (UNIT *uptr, uint32 da, int32 cnt)
|
||||
{
|
||||
while (cnt-- > 0) { /* fill with blanks */
|
||||
*(((uint8 *) uptr -> filebuf) + da) = BCD_BLANK;
|
||||
if (da >= uptr -> hwmark) uptr -> hwmark = da + 1;
|
||||
da++; }
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat dp_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */
|
||||
dp_lastf = 0; /* clear state */
|
||||
ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */
|
||||
ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0;
|
||||
sim_cancel (&dp_unit[0]); /* cancel timer */
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* i1401_iq.c: IBM 1407 inquiry terminal
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* i1401_lp.c: IBM 1403 line printer simulator
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
lpt 1403 line printer
|
||||
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
13-Apr-01 RMS Revised for register arrays
|
||||
*/
|
||||
|
||||
@@ -83,7 +84,7 @@ UNIT lpt_unit = {
|
||||
|
||||
REG lpt_reg[] = {
|
||||
{ FLDATA (ERR, ind[IN_LPT], 0) },
|
||||
{ DRDATA (POS, lpt_unit.pos, 31), PV_LEFT },
|
||||
{ DRDATA (POS, lpt_unit.pos, 32), PV_LEFT },
|
||||
{ BRDATA (CCT, cct, 8, 32, CCT_LNT) },
|
||||
{ DRDATA (LINES, lines, 8), PV_LEFT },
|
||||
{ DRDATA (CCTP, cctptr, 8), PV_LEFT },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* i1401_mt.c: IBM 1401 magnetic tape simulator
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -25,6 +25,13 @@
|
||||
|
||||
mt 7-track magtape
|
||||
|
||||
12-Jun-02 RMS End-of-record on read sets GM without WM
|
||||
(found by Van Snyder)
|
||||
03-Jun-02 RMS Modified for 1311 support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
22-Apr-02 RMS Added protection against bad record lengths
|
||||
30-Jan-02 RMS New zero footprint tape bootstrap from Van Snyder
|
||||
20-Jan-02 RMS Changed write enabled modifier
|
||||
29-Nov-01 RMS Added read only unit support
|
||||
18-Apr-01 RMS Changed to rewind tape before boot
|
||||
07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt
|
||||
@@ -54,12 +61,13 @@
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_W_UF 2 /* #save flags */
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||
#define MT_MAXFR (MAXMEMSIZE * 2) /* max transfer */
|
||||
|
||||
extern uint8 M[]; /* memory */
|
||||
extern int32 ind[64];
|
||||
extern int32 BS, iochk;
|
||||
extern UNIT cpu_unit;
|
||||
unsigned int8 dbuf[MAXMEMSIZE * 2]; /* tape buffer */
|
||||
uint8 dbuf[MT_MAXFR]; /* tape buffer */
|
||||
t_stat mt_reset (DEVICE *dptr);
|
||||
t_stat mt_boot (int32 unitno);
|
||||
UNIT *get_unit (int32 unit);
|
||||
@@ -90,13 +98,12 @@ UNIT mt_unit[] = {
|
||||
REG mt_reg[] = {
|
||||
{ FLDATA (END, ind[IN_END], 0) },
|
||||
{ FLDATA (ERR, ind[IN_TAP], 0) },
|
||||
{ FLDATA (PAR, ind[IN_PAR], 0) },
|
||||
{ DRDATA (POS1, mt_unit[1].pos, 31), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS2, mt_unit[2].pos, 31), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS3, mt_unit[3].pos, 31), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS4, mt_unit[4].pos, 31), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS5, mt_unit[5].pos, 31), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS6, mt_unit[6].pos, 31), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS1, mt_unit[1].pos, 32), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS2, mt_unit[2].pos, 32), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS3, mt_unit[3].pos, 32), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS4, mt_unit[4].pos, 32), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS5, mt_unit[5].pos, 32), PV_LEFT + REG_RO },
|
||||
{ DRDATA (POS6, mt_unit[6].pos, 32), PV_LEFT + REG_RO },
|
||||
{ GRDATA (FLG1, mt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
|
||||
REG_HRO },
|
||||
{ GRDATA (FLG2, mt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
|
||||
@@ -112,7 +119,7 @@ REG mt_reg[] = {
|
||||
{ NULL } };
|
||||
|
||||
MTAB mt_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ 0 } };
|
||||
|
||||
@@ -211,13 +218,20 @@ case BCD_R: /* read */
|
||||
ind[IN_END] = 1; /* set end mark */
|
||||
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
|
||||
break; }
|
||||
tbc = MTRL (tbc); /* ignore error flag */
|
||||
tbc = MTRL (tbc); /* ignore error flag */
|
||||
if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */
|
||||
i = fxread (dbuf, sizeof (int8), tbc, uptr -> fileref);
|
||||
for ( ; i < tbc; i++) dbuf[i] = 0; /* fill with 0's */
|
||||
err = ferror (uptr -> fileref);
|
||||
if (err = ferror (uptr -> fileref)) break; /* I/O error? */
|
||||
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
for (i = 0; (i < tbc) && (M[BS] != (BCD_GRPMRK + WM)); i++) {
|
||||
for (i = 0; i < tbc; i++) { /* loop thru buf */
|
||||
if (M[BS] == (BCD_GRPMRK + WM)) { /* GWM in memory? */
|
||||
BS++; /* incr BS */
|
||||
if (ADDR_ERR (BS)) { /* test for wrap */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; }
|
||||
return SCPE_OK; } /* done */
|
||||
t = dbuf[i]; /* get char */
|
||||
if ((flag != MD_BIN) && (t == BCD_ALT)) t = BCD_BLANK;
|
||||
if (flag == MD_WM) { /* word mk mode? */
|
||||
@@ -226,10 +240,11 @@ case BCD_R: /* read */
|
||||
wm_seen = 0; } }
|
||||
else M[BS] = (M[BS] & WM) | (t & CHAR);
|
||||
if (!wm_seen) BS++;
|
||||
if (ADDR_ERR (BS)) {
|
||||
if (ADDR_ERR (BS)) { /* check next BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_NXM; } }
|
||||
M[BS++] = BCD_GRPMRK + WM; /* end of record */
|
||||
return STOP_WRAP; } }
|
||||
if (flag == MD_WM) M[BS] = BCD_GRPMRK; /* load? clear WM */
|
||||
else M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* move? save WM */
|
||||
break;
|
||||
|
||||
case BCD_W:
|
||||
@@ -241,16 +256,19 @@ case BCD_W:
|
||||
if (((t & CHAR) == BCD_BLANK) && (flag != MD_BIN))
|
||||
dbuf[tbc++] = BCD_ALT;
|
||||
else dbuf[tbc++] = t & CHAR;
|
||||
if (ADDR_ERR (BS)) {
|
||||
if (ADDR_ERR (BS)) { /* check next BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_NXM; } }
|
||||
return STOP_WRAP; } }
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
|
||||
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr -> fileref);
|
||||
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
if (err = ferror (uptr -> fileref)) break; /* I/O error? */
|
||||
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
if (ADDR_ERR (BS)) { /* check final BS */
|
||||
BS = BA | (BS % MAXMEMSIZE);
|
||||
return STOP_WRAP; }
|
||||
break;
|
||||
default:
|
||||
return STOP_INVM; }
|
||||
@@ -258,8 +276,8 @@ default:
|
||||
if (err != 0) { /* I/O error */
|
||||
perror ("MT I/O error");
|
||||
clearerr (uptr -> fileref);
|
||||
if (iochk) return SCPE_IOERR;
|
||||
ind[IN_TAP] = 1; } /* flag error */
|
||||
ind[IN_TAP] = 1; /* flag error */
|
||||
if (iochk) return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -275,29 +293,19 @@ else return mt_dev.units + unit;
|
||||
|
||||
t_stat mt_reset (DEVICE *dptr)
|
||||
{
|
||||
ind[IN_END] = ind[IN_PAR] = ind[IN_TAP] = 0; /* clear indicators */
|
||||
ind[IN_END] = ind[IN_TAP] = 0; /* clear indicators */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 3980
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char))
|
||||
|
||||
static const unsigned char boot_rom[] = {
|
||||
OP_LCA + WM, BCD_PERCNT, BCD_U, BCD_ONE,
|
||||
BCD_ZERO, BCD_ZERO, BCD_ONE, BCD_R, /* LDA %U1 001 R */
|
||||
OP_B + WM, BCD_ZERO, BCD_ZERO, BCD_ONE, /* B 001 */
|
||||
OP_H + WM }; /* HALT */
|
||||
|
||||
t_stat mt_boot (int32 unitno)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_IS;
|
||||
|
||||
mt_unit[unitno].pos = 0;
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
M[BOOT_START + 3] = unitno & 07;
|
||||
saved_IS = BOOT_START;
|
||||
mt_unit[unitno].pos = 0; /* force rewind */
|
||||
BS = 1; /* set BS = 001 */
|
||||
mt_io (unitno, MD_WM, BCD_R); /* LDA %U1 001 R */
|
||||
saved_IS = 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* i1401_sys.c: IBM 1401 simulator interface
|
||||
|
||||
Copyright (c) 1993-2001, Robert M. Supnik
|
||||
Copyright (c) 1993-2002, Robert M. Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -23,6 +23,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.
|
||||
|
||||
03-Jun-02 RMS Added 1311 support
|
||||
18-May-02 RMS Added -D feature from Van Snyder
|
||||
26-Jan-02 RMS Fixed H, NOP with no trailing wm (found by Van Snyder)
|
||||
17-Sep-01 RMS Removed multiconsole support
|
||||
13-Jul-01 RMS Fixed bug in symbolic output (found by Peter Schorn)
|
||||
27-May-01 RMS Added multiconsole support
|
||||
@@ -37,7 +40,7 @@
|
||||
#define LINE_LNT 80
|
||||
extern DEVICE cpu_dev, inq_dev, lpt_dev;
|
||||
extern DEVICE cdr_dev, cdp_dev, stack_dev;
|
||||
extern DEVICE mt_dev;
|
||||
extern DEVICE dp_dev, mt_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern uint8 M[];
|
||||
@@ -63,9 +66,16 @@ REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = LINE_LNT;
|
||||
|
||||
DEVICE *sim_devices[] = { &cpu_dev, &inq_dev,
|
||||
&cdr_dev, &cdp_dev, &stack_dev, &lpt_dev,
|
||||
&mt_dev, NULL };
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&inq_dev,
|
||||
&cdr_dev,
|
||||
&cdp_dev,
|
||||
&stack_dev,
|
||||
&lpt_dev,
|
||||
&mt_dev,
|
||||
&dp_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
@@ -89,7 +99,17 @@ const char *sim_stop_messages[] = {
|
||||
"MCE data field too short",
|
||||
"MCE control field too short",
|
||||
"MCE EPE hanging $",
|
||||
"I/O check" };
|
||||
"I/O check",
|
||||
"Invalid disk sector address",
|
||||
"Invalid disk sector count",
|
||||
"Invalid disk unit",
|
||||
"Invalid disk function",
|
||||
"Invalid disk record length",
|
||||
"Write track while disabled",
|
||||
"Write check error",
|
||||
"Disk address miscompare",
|
||||
"Direct seek cylinder exceeds maximum"
|
||||
};
|
||||
|
||||
/* Binary loader -- load carriage control tape
|
||||
|
||||
@@ -187,6 +207,11 @@ if (sw & SWMASK ('C')) { /* character? */
|
||||
else fprintf (of, FMTASC (t & 0177));
|
||||
return SCPE_OK; }
|
||||
if ((uptr != NULL) && (uptr != &cpu_unit)) return SCPE_ARG; /* CPU? */
|
||||
if (sw & SWMASK ('D')) { /* dump? */
|
||||
for (i = 0; i < 50; i++) fprintf (of, "%c", bcd_to_ascii[val[i]&CHAR]) ;
|
||||
fprintf (of, "\n\t");
|
||||
for (i = 0; i < 50; i++) fprintf (of, (val[i]&WM)? "1": " ") ;
|
||||
return -(i - 1); }
|
||||
if (sw & SWMASK ('S')) { /* string? */
|
||||
i = 0;
|
||||
do { t = val[i++];
|
||||
@@ -199,15 +224,15 @@ if ((val[0] & WM) == 0) return STOP_NOWM; /* WM under op? */
|
||||
op = val[0]& CHAR; /* isolate op */
|
||||
flags = op_table[op]; /* get flags */
|
||||
for (ilnt = 1; ilnt < sim_emax; ilnt++) if (val[ilnt] & WM) break;
|
||||
if (flags & HNOP) ilnt = 1; /* halt, nop? */
|
||||
else if ((flags & NOWM) && (ilnt > 7)) ilnt = 7; /* cs, swm? */
|
||||
if ((flags & (NOWM | HNOP)) && (ilnt > 7)) ilnt = 7; /* cs, swm, h, nop? */
|
||||
else if ((op == OP_B) && (ilnt > 4) && (val[4] == BCD_BLANK)) ilnt = 4;
|
||||
else if (ilnt > 8) ilnt = 8; /* cap length */
|
||||
if ((flags & len_table[ilnt]) == 0) return STOP_INVL; /* legal length? */
|
||||
else if ((ilnt > 8) && (op != OP_NOP)) ilnt = 8; /* cap length */
|
||||
if (((flags & len_table[ilnt]) == 0) && /* valid lnt, */
|
||||
((op != OP_NOP) == 0)) return STOP_INVL; /* nop? */
|
||||
fprintf (of, "%s",opcode[op]); /* print opcode */
|
||||
if (ilnt > 2) { /* A address? */
|
||||
if ((flags & IO) && (val[1] == BCD_PERCNT)) fprintf (of, " %%%c%c",
|
||||
bcd_to_ascii[val[2]], bcd_to_ascii[val[3]]);
|
||||
if (((flags & IO) || (op == OP_NOP)) && (val[1] == BCD_PERCNT))
|
||||
fprintf (of, " %%%c%c", bcd_to_ascii[val[2]], bcd_to_ascii[val[3]]);
|
||||
else fprint_addr (of, &val[1]); }
|
||||
if (ilnt > 5) fprint_addr (of, &val[4]); /* B address? */
|
||||
if ((ilnt == 2) || (ilnt == 5) || (ilnt == 8)) /* d character? */
|
||||
@@ -291,12 +316,12 @@ for (op = 0; op < 64; op++) /* look it up */
|
||||
if (opcode[op] && strcmp (gbuf, opcode[op]) == 0) break;
|
||||
if (op >= 64) return SCPE_ARG; /* successful? */
|
||||
val[0] = op | WM; /* store opcode */
|
||||
cptr = get_glyph (cptr, gbuf, ' '); /* get addr or d */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */
|
||||
if (((op_table[op] && IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) ||
|
||||
(get_addr (gbuf, &val[1]) == SCPE_OK)) {
|
||||
cptr = get_glyph (cptr, gbuf, ' '); /* get addr or d */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */
|
||||
if (get_addr (gbuf, &val[4]) == SCPE_OK) {
|
||||
cptr = get_glyph (cptr, gbuf, ' '); /* get d */
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* get d */
|
||||
ilnt = 7; } /* a and b addresses */
|
||||
else ilnt = 4; } /* a address */
|
||||
else ilnt = 1; /* no addresses */
|
||||
@@ -306,6 +331,7 @@ if ((gbuf[0] == '\'') || (gbuf[0] == '"')) { /* d character? */
|
||||
return SCPE_ARG; /* end and legal? */
|
||||
val[ilnt] = ascii_to_bcd[t]; /* save D char */
|
||||
ilnt = ilnt + 1; }
|
||||
else if (gbuf[0] != 0) return SCPE_ARG; /* not done? */
|
||||
if ((op_table[op] & len_table[ilnt]) == 0) return STOP_INVL;
|
||||
return -(ilnt - 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user