1
0
mirror of https://github.com/simh/simh.git synced 2026-04-12 07:05:35 +00:00

Notes For V2.10-2

1. New Features in 2.10-2

The build procedures have changed.  There is only one UNIX makefile.
To compile without Ethernet support, simply type

	gmake {target|all}

To compile with Ethernet support, type

	gmake USE_NETWORK=1 {target|all}

The Mingw batch files require Mingw release 2 and invoke the Unix
makefile.  There are still separate batch files for compilation
with or without Ethernet support.

1.1 SCP and Libraries

- The EVAL command will evaluate a symbolic type-in and display
  it in numeric form.
- The ! command (with no arguments) will launch the host operating
  system command shell.  The ! command (with an argument) executes
  the argument as a host operating system command.  (Code from
  Mark Pizzolato)
- Telnet sessions now recognize BREAK.  How a BREAK is transmitted
  dependent on the particular Telnet client.  (Code from Mark
  Pizzolato)
- The sockets library includes code for active connections as
  well as listening connections.
- The RESTORE command will restore saved memory size, if the
  simulator supports dynamic memory resizing.

1.2 PDP-1

- The PDP-1 supports the Type 24 serial drum (based on recently
  discovered documents).

1.3 18b PDP's

- The PDP-4 supports the Type 24 serial drum (based on recently
  discovered documents).

1.4 PDP-11

- The PDP-11 implements a stub DEUNA/DELUA (XU).  The real XU
  module will be included in a later release.

1.5 PDP-10

- The PDP-10 implements a stub DEUNA/DELUA (XU).  The real XU
  module will be included in a later release.

1.6 HP 2100

- The IOP microinstruction set is supported for the 21MX as well
  as the 2100.
- The HP2100 supports the Access Interprocessor Link (IPL).

1.7 VAX

- If the VAX console is attached to a Telnet session, BREAK is
  interpreted as console halt.
- The SET/SHOW HISTORY commands enable and display a history of
  the most recently executed instructions.  (Code from Mark
  Pizzolato)

1.8 Terminals Multiplexors

- BREAK detection was added to the HP, DEC, and Interdata terminal
  multiplexors.

1.9 Interdata 16b and 32b

- First release.  UNIX is not yet working.

1.10 SDS 940

- First release.

2. Bugs Fixed in 2.10-2

- PDP-11 console must default to 7b for early UNIX compatibility.
- PDP-11/VAX TMSCP emulator was using the wrong packet length for
  read/write end packets.
- Telnet IAC+IAC processing was fixed, both for input and output
  (found by Mark Pizzolato).
- PDP-11/VAX Ethernet setting flag bits wrong for chained
  descriptors (found by Mark Pizzolato).

3. New Features in 2.10 vs prior releases

3.1 SCP and Libraries

- The VT emulation package has been replaced by the capability
  to remote the console to a Telnet session.  Telnet clients
  typically have more complete and robust VT100 emulation.
- Simulated devices may now have statically allocated buffers,
  in addition to dynamically allocated buffers or disk-based
  data stores.
- The DO command now takes substitutable arguments (max 9).
  In command files, %n represents substitutable argument n.
- The initial command line is now interpreted as the command
  name and substitutable arguments for a DO command.  This is
  backward compatible to prior versions.
- The initial command line parses switches.  -Q is interpreted
  as quiet mode; informational messages are suppressed.
- The HELP command now takes an optional argument.  HELP <cmd>
  types help on the specified command.
- Hooks have been added for implementing GUI-based consoles,
  as well as simulator-specific command extensions.  A few
  internal data structures and definitions have changed.
- Two new routines (tmxr_open_master, tmxr_close_master) have
  been added to sim_tmxr.c.  The calling sequence for
  sim_accept_conn has been changed in sim_sock.c.
- The calling sequence for the VM boot routine has been modified
  to add an additional parameter.
- SAVE now saves, and GET now restores, controller and unit flags.
- Library sim_ether.c has been added for Ethernet support.

3.2 VAX

- Non-volatile RAM (NVR) can behave either like a memory or like
  a disk-based peripheral.  If unattached, it behaves like memory
  and is saved and restored by SAVE and RESTORE, respectively.
  If attached, its contents are loaded from disk by ATTACH and
  written back to disk at DETACH and EXIT.
- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape) has been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from vax_stddev.c and
  now references a common implementation file, dec_pt.h.
- Examine and deposit switches now work on all devices, not just
  the CPU.
- Device address conflicts are not detected until simulation starts.

3.3 PDP-11

- SHOW <device> VECTOR displays the device's interrupt vector.
  Most devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk),
  RX211 (double density floppy), and KW11P programmable clock
  have been added.
- The DEQNA/DELQA (Qbus Ethernet controllers) have been added.
- Autoconfiguration support has been added.
- The paper tape reader has been removed from pdp11_stddev.c and
  now references a common implementation file, dec_pt.h.
- Device bootstraps now use the actual CSR specified by the
  SET ADDRESS command, rather than just the default CSR.  Note
  that PDP-11 operating systems may NOT support booting with
  non-standard addresses.
- Specifying more than 256KB of memory, or changing the bus
  configuration, causes all peripherals that are not compatible
  with the current bus configuration to be disabled.
- Device address conflicts are not detected until simulation starts.

3.4 PDP-10

- SHOW <device> VECTOR displays the device's interrupt vector.
  A few devices allow the vector to be changed with SET
  <device> VECTOR=nnn.
- SHOW CPU IOSPACE displays the I/O space address map.
- The RX211 (double density floppy) has been added; it is off
  by default.
- The paper tape now references a common implementation file,
  dec_pt.h.
- Device address conflicts are not detected until simulation starts.

3.5 PDP-1

- DECtape (then known as MicroTape) support has been added.
- The line printer and DECtape can be disabled and enabled.

3.6 PDP-8

- The RX28 (double density floppy) has been added as an option to
  the existing RX8E controller.
- SHOW <device> DEVNO displays the device's device number.  Most
  devices allow the device number to be changed with SET <device>
  DEVNO=nnn.
- Device number conflicts are not detected until simulation starts.

3.7 IBM 1620

- The IBM 1620 simulator has been released.

3.8 AltairZ80

- A hard drive has been added for increased storage.
- Several bugs have been fixed.

3.9 HP 2100

- The 12845A has been added and made the default line printer (LPT).
  The 12653A has been renamed LPS and is off by default.  It also
  supports the diagnostic functions needed to run the DCPC and DMS
  diagnostics.
- The 12557A/13210A disk defaults to the 13210A (7900/7901).
- The 12559A magtape is off by default.
- New CPU options (EAU/NOEAU) enable/disable the extended arithmetic
  instructions for the 2116.  These instructions are standard on
  the 2100 and 21MX.
- New CPU options (MPR/NOMPR) enable/disable memory protect for the
  2100 and 21MX.
- New CPU options (DMS/NODMS) enable/disable the dynamic mapping
  instructions for the 21MX.
- The 12539 timebase generator autocalibrates.

3.10 Simulated Magtapes

- Simulated magtapes recognize end of file and the marker
  0xFFFFFFFF as end of medium.  Only the TMSCP tape simulator
  can generate an end of medium marker.
- The error handling in simulated magtapes was overhauled to be
  consistent through all simulators.

3.11 Simulated DECtapes

- Added support for RT11 image file format (256 x 16b) to DECtapes.

4. Bugs Fixed in 2.10 vs prior releases

- TS11/TSV05 was not simulating the XS0_MOT bit, causing failures
  under VMS.  In addition, two of the CTL options were coded
  interchanged.
- IBM 1401 tape was not setting a word mark under group mark for
  load mode reads.  This caused the diagnostics to crash.
- SCP bugs in ssh_break and set_logon were fixed (found by Dave
  Hittner).
- Numerous bugs in the HP 2100 extended arithmetic, floating point,
  21MX, DMS, and IOP instructions were fixed.  Bugs were also fixed
  in the memory protect and DMS functions.  The moving head disks
  (DP, DQ) were revised to simulate the hardware more accurately.
  Missing functions in DQ (address skip, read address) were added.
- PDP-10 tape wouldn't boot, and then wouldn't read (reported by
  Michael Thompson and Harris Newman, respectively)
- PDP-1 typewriter is half duplex, with only one shift state for
  both input and output (found by Derek Peschel)

5. General Notes

WARNING: V2.10 has reorganized and renamed some of the definition
files for the PDP-10, PDP-11, and VAX.  Be sure to delete all
previous source files before you unpack the Zip archive, or
unpack it into a new directory structure.

WARNING: V2.10 has a new, more comprehensive save file format.
Restoring save files from previous releases will cause 'invalid
register' errors and loss of CPU option flags, device enable/
disable flags, unit online/offline flags, and unit writelock
flags.

WARNING: If you are using Visual Studio .NET through the IDE,
be sure to turn off the /Wp64 flag in the project settings, or
dozens of spurious errors will be generated.

WARNING: Compiling Ethernet support under Windows requires
extra steps; see the Ethernet readme file.  Ethernet support is
currently available only for Windows, Linux, NetBSD, and OpenBSD.
This commit is contained in:
Bob Supnik
2003-01-17 18:35:00 -08:00
committed by Mark Pizzolato
parent 4ea745b3ad
commit 2bcd1e7c4c
206 changed files with 30253 additions and 12114 deletions

View File

@@ -325,36 +325,36 @@ op = IR & 0177; /* IR <6:0> */
for (i = j = 0; (i < MAXOPN) && opntab[op][i]; i++) { /* parse operands */
switch (opntab[op][i]) { /* case on op type */
case R0_DESC:
arg[j++] = R[0];
arg[j++] = R[1];
break;
arg[j++] = R[0];
arg[j++] = R[1];
break;
case R2_DESC:
arg[j++] = R[2];
arg[j++] = R[3];
break;
arg[j++] = R[2];
arg[j++] = R[3];
break;
case R4_DESC:
arg[j++] = R[4];
arg[j++] = R[5];
break;
arg[j++] = R[4];
arg[j++] = R[5];
break;
case R4_ARG:
arg[j++] = R[4];
break;
arg[j++] = R[4];
break;
case IN_DESC:
addr = ReadW (PC | isenable);
PC = (PC + 2) & 0177777;
arg[j++] = ReadW (addr | dsenable);
arg[j++] = ReadW (((addr + 2) & 0177777) | dsenable);
break;
addr = ReadW (PC | isenable);
PC = (PC + 2) & 0177777;
arg[j++] = ReadW (addr | dsenable);
arg[j++] = ReadW (((addr + 2) & 0177777) | dsenable);
break;
case IN_DESC_R0:
addr = ReadW (PC | isenable);
PC = (PC + 2) & 0177777;
R[0] = ReadW (addr | dsenable);
R[1] = ReadW (((addr + 2) & 0177777) | dsenable);
break;
addr = ReadW (PC | isenable);
PC = (PC + 2) & 0177777;
R[0] = ReadW (addr | dsenable);
R[1] = ReadW (((addr + 2) & 0177777) | dsenable);
break;
case IN_ARG:
arg[j++] = ReadW (PC | isenable);
PC = (PC + 2) & 0177777;
break; } /* end case */
arg[j++] = ReadW (PC | isenable);
PC = (PC + 2) & 0177777;
break; } /* end case */
} /* end for */
switch (op) { /* case on opcode */
@@ -387,23 +387,23 @@ switch (op) { /* case on opcode */
case 030: case 032: case 0130: case 0132:
mvlnt = (A1LNT < A2LNT)? A1LNT: A2LNT; /* calc move lnt */
for (i = 0; i < mvlnt; i++) {
movbuf[i] = ReadB (((A1ADR + i) & 0177777) | dsenable); }
movbuf[i] = ReadB (((A1ADR + i) & 0177777) | dsenable); }
for (i = 0; i < mvlnt; i++) {
t = movbuf[i];
if (op & 2) t = ReadB (((A3ADR + t) & 0177777) | dsenable);
WriteB (t, ((A2ADR + i) & 0177777) | dsenable); }
t = movbuf[i];
if (op & 2) t = ReadB (((A3ADR + t) & 0177777) | dsenable);
WriteB (t, ((A2ADR + i) & 0177777) | dsenable); }
fill = A3LNT & 0377; /* do fill, if any */
for (i = mvlnt; i < A2LNT; i++) {
WriteB (fill, ((A2ADR + i) & 0177777) | dsenable); }
WriteB (fill, ((A2ADR + i) & 0177777) | dsenable); }
t = A1LNT - A2LNT; /* src.lnt - dst.lnt */
N = GET_SIGN_W (t); /* set cc's from diff */
Z = GET_Z (t);
V = GET_SIGN_W ((A1LNT ^ A2LNT) & (~A2LNT ^ t));
C = (A1LNT < A2LNT);
if ((op & INLINE) == 0) { /* if reg, set reg */
R[0] = C? 0: t & 0177777;
R[1] = R[2] = R[3] = 0;
R[4] = R[4] & 0377; }
R[0] = C? 0: t & 0177777;
R[1] = R[2] = R[3] = 0;
R[4] = R[4] & 0377; }
return;
/* MOVRC, MOVRCI
@@ -428,22 +428,22 @@ case 031: case 0131:
mvlnt = (A1LNT < A2LNT)? A1LNT: A2LNT; /* calc move lnt */
addr = A1ADR + A1LNT - mvlnt;
for (i = 0; i < mvlnt; i++) {
movbuf[i] = ReadB (((addr + i) & 0177777) | dsenable); }
movbuf[i] = ReadB (((addr + i) & 0177777) | dsenable); }
addr = A2ADR + A2LNT - mvlnt;
for (i = 0; i < mvlnt; i++) {
WriteB (movbuf[i], ((addr + i) & 0177777) | dsenable); }
WriteB (movbuf[i], ((addr + i) & 0177777) | dsenable); }
fill = A3LNT & 0377; /* do fill, if any */
for (i = mvlnt, j = 0; i < A2LNT; i++, j++) {
WriteB (fill, ((A2ADR + j) & 0177777) | dsenable); }
WriteB (fill, ((A2ADR + j) & 0177777) | dsenable); }
t = A1LNT - A2LNT; /* src.lnt - dst.lnt */
N = GET_SIGN_W (t); /* set cc's from diff */
Z = GET_Z (t);
V = GET_SIGN_W ((A1LNT ^ A2LNT) & (~A2LNT ^ t));
C = (A1LNT < A2LNT);
if ((op & INLINE) == 0) { /* if reg, set reg */
R[0] = C? 0: t & 0177777;
R[1] = R[2] = R[3] = 0;
R[4] = R[4] & 0377; }
R[0] = C? 0: t & 0177777;
R[1] = R[2] = R[3] = 0;
R[4] = R[4] & 0377; }
return;
/* Load descriptors - no operands */
@@ -457,9 +457,9 @@ case 064: case 065: case 066: case 067:
t = R[rn];
spc = (rn == 7)? isenable: dsenable;
for (j = 0; j < limit; j = j + 2) { /* loop for 2,3 dscr */
addr = ReadW (((t + j) & 0177777) | spc);
R[j] = ReadW (addr | dsenable);
R[j + 1] = ReadW (((addr + 2) & 0177777) | dsenable); }
addr = ReadW (((t + j) & 0177777) | spc);
R[j] = ReadW (addr | dsenable);
R[j + 1] = ReadW (((addr + 2) & 0177777) | dsenable); }
if (rn >= limit) R[rn] = (R[rn] + limit) & 0177777;
return;
@@ -480,9 +480,9 @@ case 064: case 065: case 066: case 067:
case 040: case 041: case 0140: case 0141:
match = A1LNT & 0377; /* match character */
for ( ; R[0] != 0; R[0]--) { /* loop */
c = ReadB (R[1] | dsenable); /* get char */
if ((c == match) ^ (op & 1)) break; /* = + LOC, != + SKP? */
R[1] = (R[1] + 1) & 0177777; }
c = ReadB (R[1] | dsenable); /* get char */
if ((c == match) ^ (op & 1)) break; /* = + LOC, != + SKP? */
R[1] = (R[1] + 1) & 0177777; }
N = GET_SIGN_W (R[0]);
Z = GET_Z (R[0]);
V = C = 0;
@@ -507,10 +507,10 @@ case 040: case 041: case 0140: case 0141:
case 042: case 043: case 0142: case 0143:
mask = A1LNT & 0377; /* mask character */
for (; R[0] != 0; R[0]--) { /* loop */
t = ReadB (R[1] | dsenable); /* get char as index */
c = ReadB (((A1ADR + t) & 0177777) | dsenable);
if (((c & mask) != 0) ^ (op & 1)) break; /* != + SCN, = + SPN? */
R[1] = (R[1] + 1) & 0177777; }
t = ReadB (R[1] | dsenable); /* get char as index */
c = ReadB (((A1ADR + t) & 0177777) | dsenable);
if (((c & mask) != 0) ^ (op & 1)) break; /* != + SCN, = + SPN? */
R[1] = (R[1] + 1) & 0177777; }
N = GET_SIGN_W (R[0]);
Z = GET_Z (R[0]);
V = C = 0;
@@ -536,24 +536,24 @@ case 042: case 043: case 0142: case 0143:
case 044: case 0144:
c = t = 0;
for (i = 0; i < ((A1LNT > A2LNT)? A1LNT: A2LNT); i++) {
if (i < A1LNT) c = ReadB (((A1ADR + i) & 0177777) | dsenable);
else c = A3LNT & 0377;
if (i < A2LNT) t = ReadB (((A2ADR + i) & 0177777) | dsenable);
else t = A3LNT & 0377;
if (c != t) break; }
if (i < A1LNT) c = ReadB (((A1ADR + i) & 0177777) | dsenable);
else c = A3LNT & 0377;
if (i < A2LNT) t = ReadB (((A2ADR + i) & 0177777) | dsenable);
else t = A3LNT & 0377;
if (c != t) break; }
j = c - t; /* last chars read */
N = GET_SIGN_B (j); /* set cc's */
Z = GET_Z (j);
V = GET_SIGN_B ((c ^ t) & (~t ^ j));
C = (c < t);
if ((op & INLINE) == 0) { /* if reg, set reg */
j = (i > A1LNT)? A1LNT: i; /* #src1 chars used */
k = (i > A2LNT)? A2LNT: i; /* #src2 chars used */
R[0] = A1LNT - j;
R[1] = (A1ADR + j) & 0177777;
R[2] = A2LNT - k;
R[3] = (A2ADR + k) & 0177777;
R[4] = R[4] & 0377; }
j = (i > A1LNT)? A1LNT: i; /* #src1 chars used */
k = (i > A2LNT)? A2LNT: i; /* #src2 chars used */
R[0] = A1LNT - j;
R[1] = (A1ADR + j) & 0177777;
R[2] = A2LNT - k;
R[3] = (A2ADR + k) & 0177777;
R[4] = R[4] & 0377; }
return;
/* MATC, MATCI
@@ -583,15 +583,15 @@ case 044: case 0144:
case 0045: case 0145:
for (match = 0; R[0] >= A1LNT; R[0]--) { /* loop thru string */
for (i = 0, match = 1; match && (i < A1LNT); i++) {
c = ReadB (((R[1] + i) & 0177777) | dsenable);
t = ReadB (((A1ADR + i) & 0177777) | dsenable);
match = (c == t); } /* end for substring */
if (match) break; /* exit if match */
R[1] = (R[1] + 1) & 0177777; } /* end for string */
for (i = 0, match = 1; match && (i < A1LNT); i++) {
c = ReadB (((R[1] + i) & 0177777) | dsenable);
t = ReadB (((A1ADR + i) & 0177777) | dsenable);
match = (c == t); } /* end for substring */
if (match) break; /* exit if match */
R[1] = (R[1] + 1) & 0177777; } /* end for string */
if (!match) { /* if no match */
R[1] = (R[1] + R[0]) & 0177777;
R[0] = 0; }
R[1] = (R[1] + R[0]) & 0177777;
R[0] = 0; }
N = GET_SIGN_W (R[0]);
Z = GET_Z (R[0]);
V = C = 0;
@@ -618,19 +618,20 @@ case 0150: case 0151: case 0170: case 0171:
ReadDstr (A2, &src2, op); /* get source2 */
if (op & 1) src1.sign = src1.sign ^ 1; /* sub? invert sign */
if (src1.sign ^ src2.sign) { /* opp signs? sub */
if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */
SubDstr (&src1, &src2, &dst); /* src2 - src1 */
dst.sign = src2.sign; } /* sign = src2 */
else { SubDstr (&src2, &src1, &dst); /* src1 - src2 */
dst.sign = src1.sign; } /* sign = src1 */
V = 0; } /* can't carry */
if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */
SubDstr (&src1, &src2, &dst); /* src2 - src1 */
dst.sign = src2.sign; } /* sign = src2 */
else {
SubDstr (&src2, &src1, &dst); /* src1 - src2 */
dst.sign = src1.sign; } /* sign = src1 */
V = 0; } /* can't carry */
else { /* addition */
V = AddDstr (&src1, &src2, &dst, 0); /* add magnitudes */
dst.sign = src1.sign; } /* set result sign */
V = AddDstr (&src1, &src2, &dst, 0); /* add magnitudes */
dst.sign = src1.sign; } /* set result sign */
C = 0;
WriteDstr (A3, &dst, op); /* store result */
if ((op & INLINE) == 0) /* if reg, clr reg */
R[0] = R[1] = R[2] = R[3] = 0;
R[0] = R[1] = R[2] = R[3] = 0;
return;
/* MULP, MULPI
@@ -651,17 +652,17 @@ case 0150: case 0151: case 0170: case 0171:
case 074: case 0174:
dst = Dstr0; /* clear result */
if (ReadDstr (A1, &src1, op) && ReadDstr (A2, &src2, op)) {
dst.sign = src1.sign ^ src2.sign; /* sign of result */
accum = Dstr0; /* clear accum */
NibbleRshift (&src1, 1, 0); /* shift out sign */
CreateTable (&src1, mptable); /* create *1, *2, ... */
for (i = 1; i < (DSTRLNT * 8); i++) { /* 31 iterations */
digit = (src2.val[i / 8] >> ((i % 8) * 4)) & 0xF;
if (digit > 0) /* add in digit*mpcnd */
AddDstr (&mptable[digit], &accum, &accum, 0);
nc = NibbleRshift (&accum, 1, 0); /* ac right 4 */
NibbleRshift (&dst, 1, nc); } /* result right 4 */
V = TestDstr (&accum) != 0; } /* if ovflo, set V */
dst.sign = src1.sign ^ src2.sign; /* sign of result */
accum = Dstr0; /* clear accum */
NibbleRshift (&src1, 1, 0); /* shift out sign */
CreateTable (&src1, mptable); /* create *1, *2, ... */
for (i = 1; i < (DSTRLNT * 8); i++) { /* 31 iterations */
digit = (src2.val[i / 8] >> ((i % 8) * 4)) & 0xF;
if (digit > 0) /* add in digit*mpcnd */
AddDstr (&mptable[digit], &accum, &accum, 0);
nc = NibbleRshift (&accum, 1, 0); /* ac right 4 */
NibbleRshift (&dst, 1, nc); } /* result right 4 */
V = TestDstr (&accum) != 0; } /* if ovflo, set V */
else V = 0; /* result = 0 */
C = 0; /* C = 0 */
WriteDstr (A3, &dst, op); /* store result */
@@ -687,8 +688,8 @@ case 074: case 0174:
case 075: case 0175:
ldivr = ReadDstr (A1, &src1, op); /* get divisor */
if (ldivr == 0) { /* divisor = 0? */
V = C = 1; /* set cc's */
return; }
V = C = 1; /* set cc's */
return; }
ldivr = LntDstr (&src1, ldivr); /* get exact length */
ldivd = ReadDstr (A2, &src2, op); /* get dividend */
ldivd = LntDstr (&src2, ldivd); /* get exact length */
@@ -696,24 +697,24 @@ case 075: case 0175:
NibbleRshift (&src1, 1, 0); /* right justify ops */
NibbleRshift (&src2, 1, 0);
if ((t = ldivd - ldivr) >= 0) { /* any divide to do? */
WordLshift (&src1, t / 8); /* align divr to divd */
NibbleLshift (&src1, t % 8, 0);
CreateTable (&src1, mptable); /* create *1, *2, ... */
for (i = 0; i <= t; i++) { /* divide loop */
for (digit = 9; digit > 0; digit--) { /* find digit */
if (CmpDstr (&src2, &mptable[digit]) >= 0) {
SubDstr (&mptable[digit], &src2, &src2);
dst.val[0] = dst.val[0] | digit;
break; } } /* end if, for */
NibbleLshift (&src2, 1, 0); /* shift dividend */
NibbleLshift (&dst, 1, 0); /* shift quotient */
} /* end divide loop */
dst.sign = src1.sign ^ src2.sign; /* calculate sign */
} /* end if */
WordLshift (&src1, t / 8); /* align divr to divd */
NibbleLshift (&src1, t % 8, 0);
CreateTable (&src1, mptable); /* create *1, *2, ... */
for (i = 0; i <= t; i++) { /* divide loop */
for (digit = 9; digit > 0; digit--) { /* find digit */
if (CmpDstr (&src2, &mptable[digit]) >= 0) {
SubDstr (&mptable[digit], &src2, &src2);
dst.val[0] = dst.val[0] | digit;
break; } } /* end if, for */
NibbleLshift (&src2, 1, 0); /* shift dividend */
NibbleLshift (&dst, 1, 0); /* shift quotient */
} /* end divide loop */
dst.sign = src1.sign ^ src2.sign; /* calculate sign */
} /* end if */
V = C = 0;
WriteDstr (A3, &dst, op); /* store result */
if ((op & INLINE) == 0) /* if reg, clr reg */
R[0] = R[1] = R[2] = R[3] = 0;
R[0] = R[1] = R[2] = R[3] = 0;
return;
/* CMPN, CMPP, CMPNI, CMPPI
@@ -735,11 +736,12 @@ case 052: case 072: case 0152: case 0172:
ReadDstr (A2, &src2, op); /* get source2 */
N = Z = V = C = 0;
if (src1.sign != src2.sign) N = src1.sign;
else { t = CmpDstr (&src1, &src2); /* compare strings */
if (t < 0) N = 1;
else if (t == 0) Z = 1; }
else {
t = CmpDstr (&src1, &src2); /* compare strings */
if (t < 0) N = 1;
else if (t == 0) Z = 1; }
if ((op & INLINE) == 0) /* if reg, clr reg */
R[0] = R[1] = R[2] = R[3] = 0;
R[0] = R[1] = R[2] = R[3] = 0;
return;
/* ASHN, ASHP, ASHNI, ASHPI
@@ -763,21 +765,21 @@ case 056: case 076: case 0156: case 0176:
V = C = 0; /* init cc's */
shift = GET_ASHLNT (A3LNT); /* get shift count */
if (shift & ASHSGN) { /* right shift? */
shift = (ASHLNT_M + 1 - shift); /* !shift! */
WordRshift (&src1, shift / 8); /* do word shifts */
NibbleRshift (&src1, shift % 8, 0); /* do nibble shifts */
t = GET_ASHRND (A3LNT); /* get rounding digit */
if ((t + (src1.val[0] & 0xF)) > 9) /* rounding needed? */
AddDstr (&src1, &Dstr1, &src1, 0); /* round */
src1.val[0] = src1.val[0] & ~0xF; /* clear sign */
shift = (ASHLNT_M + 1 - shift); /* !shift! */
WordRshift (&src1, shift / 8); /* do word shifts */
NibbleRshift (&src1, shift % 8, 0); /* do nibble shifts */
t = GET_ASHRND (A3LNT); /* get rounding digit */
if ((t + (src1.val[0] & 0xF)) > 9) /* rounding needed? */
AddDstr (&src1, &Dstr1, &src1, 0); /* round */
src1.val[0] = src1.val[0] & ~0xF; /* clear sign */
} /* end right shift */
else if (shift) { /* left shift? */
if (WordLshift (&src1, shift / 8)) V = 1; /* do word shifts */
if (NibbleLshift (&src1, shift % 8, 0)) V = 1;
if (WordLshift (&src1, shift / 8)) V = 1; /* do word shifts */
if (NibbleLshift (&src1, shift % 8, 0)) V = 1;
} /* end left shift */
WriteDstr (A2, &src1, op); /* store result */
if ((op & INLINE) == 0) /* if reg, clr reg */
R[0] = R[1] = R[4] = 0;
R[0] = R[1] = R[4] = 0;
return;
/* CVTPN, CVTPNI
@@ -841,24 +843,25 @@ case 053: case 073: case 0153: case 0173:
ReadDstr (A1, &src1, op); /* get source */
V = result = 0; /* clear V, result */
for (i = (DSTRLNT * 8) - 1; i > 0; i--) { /* loop thru digits */
digit = (src1.val[i / 8] >> ((i % 8) * 4)) & 0xF;
if (digit || result || V) { /* skip initial 0's */
if (result >= MAXDVAL) V = 1;
result = (result * 10) + digit;
if (result < digit) V = 1; } /* end if */
} /* end for */
digit = (src1.val[i / 8] >> ((i % 8) * 4)) & 0xF;
if (digit || result || V) { /* skip initial 0's */
if (result >= MAXDVAL) V = 1;
result = (result * 10) + digit;
if (result < digit) V = 1; } /* end if */
} /* end for */
if (src1.sign) result = (~result + 1) & 0xFFFFFFFF;
N = GET_SIGN_L (result);
Z = GET_Z (result);
V = V | (N ^ src1.sign); /* overflow if +2**31 */
C = src1.sign && (Z == 0); /* set C based on std */
if (op & INLINE) { /* inline? */
WriteW (result & 0177777, A2LNT | dsenable);
WriteW ((result >> 16) & 0177777,
((A2LNT + 2) & 0177777) | dsenable); }
else { R[0] = R[1] = 0;
R[2] = (result >> 16) & 0177777;
R[3] = result & 0177777; }
WriteW (result & 0177777, A2LNT | dsenable);
WriteW ((result >> 16) & 0177777,
((A2LNT + 2) & 0177777) | dsenable); }
else {
R[0] = R[1] = 0;
R[2] = (result >> 16) & 0177777;
R[3] = result & 0177777; }
return;
/* CVTLN, CVTLP, CVTLNI, CVTLPI
@@ -886,9 +889,9 @@ CVTLx:
dst = Dstr0; /* clear result */
if (dst.sign = GET_SIGN_L (result)) result = (~result + 1) & 0xFFFFFFFF;
for (i = 1; (i < (DSTRLNT * 8)) && result; i++) {
digit = result % 10;
result = result / 10;
dst.val[i / 8] = dst.val[i / 8] | (digit << ((i % 8) * 4)); }
digit = result % 10;
result = result / 10;
dst.val[i / 8] = dst.val[i / 8] | (digit << ((i % 8) * 4)); }
V = C = 0;
WriteDstr (A1, &dst, op); /* write result */
return;
@@ -932,31 +935,31 @@ lnt = GET_DLNT (dscr[0]); /* get string length */
if (flag & PACKED) { /* packed? */
end = lnt / 2; /* last byte */
for (i = 0; i <= end; i++) { /* loop thru string */
c = ReadB (((dscr[1] + end - i) & 0177777) | dsenable);
if (i == 0) t = c & 0xF; /* save sign */
if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF;
if (c >= 0xA0) c = c & 0xF; /* check hi digit */
if ((c & 0xF) >= 0xA) c = c & 0xF0; /* check lo digit */
src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8));
} /* end for */
c = ReadB (((dscr[1] + end - i) & 0177777) | dsenable);
if (i == 0) t = c & 0xF; /* save sign */
if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF;
if (c >= 0xA0) c = c & 0xF; /* check hi digit */
if ((c & 0xF) >= 0xA) c = c & 0xF0; /* check lo digit */
src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8));
} /* end for */
if ((t == 0xB) || (t == 0xD)) src->sign = 1; /* if -, set sign */
src->val[0] = src->val[0] & ~0xF; /* clear sign */
} /* end packed */
else { /* numeric */
if (type >= TS) src->sign = (ReadB ((((type == TS)?
dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable) == '-');
dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable) == '-');
for (i = 1; i <= lnt; i++) { /* loop thru string */
c = ReadB (((dscr[1] + lnt - i) & 0177777) | dsenable);
if ((i == 1) && (type == XZ) && ((c & 0xF0) == 0x70))
src->sign = 1; /* signed zoned */
else if (((i == 1) && (type == TO)) ||
((i == lnt) && (type == LO))) {
c = overbin[c & 0177]; /* get sign and digit */
src->sign = c >> 7; } /* set sign */
c = c & 0xF; /* get digit */
if (c > 9) c = 0; /* range check */
src->val[i / 8] = src->val[i / 8] | (c << ((i % 8) * 4));
} /* end for */
c = ReadB (((dscr[1] + lnt - i) & 0177777) | dsenable);
if ((i == 1) && (type == XZ) && ((c & 0xF0) == 0x70))
src->sign = 1; /* signed zoned */
else if (((i == 1) && (type == TO)) ||
((i == lnt) && (type == LO))) {
c = overbin[c & 0177]; /* get sign and digit */
src->sign = c >> 7; } /* set sign */
c = c & 0xF; /* get digit */
if (c > 9) c = 0; /* range check */
src->val[i / 8] = src->val[i / 8] | (c << ((i % 8) * 4));
} /* end for */
} /* end numeric */
return TestDstr (src); /* clean -0 */
}
@@ -1008,23 +1011,23 @@ if (flag & PACKED) { /* packed? */
if (type == UP) dst->val[0] = dst->val[0] | 0xF;
else dst->val[0] = dst->val[0] | 0xC | dst->sign;
for (i = 0; i <= end; i++) { /* store string */
c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF;
WriteB (c, ((dscr[1] + end - i) & 0177777));
c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF;
WriteB (c, ((dscr[1] + end - i) & 0177777));
} /* end for */
} /* end packed */
else {
if (type >= TS) WriteB (dst->sign? '-': '+', (((type == TS)?
dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable);
dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable);
for (i = 1; i <= lnt; i++) { /* store string */
c = (dst->val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */
if ((i == 1) && (type == XZ) && dst->sign)
c = c | 0x70; /* signed zoned */
else if (((i == 1) && (type == TO)) ||
((i == lnt) && (type == LO)))
c = binover[dst->sign][c]; /* get sign and digit */
else c = c | 0x30; /* default */
WriteB (c, ((dscr[1] + lnt - i) & 0177777));
} /* end for */
c = (dst->val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */
if ((i == 1) && (type == XZ) && dst->sign)
c = c | 0x70; /* signed zoned */
else if (((i == 1) && (type == TO)) ||
((i == lnt) && (type == LO)))
c = binover[dst->sign][c]; /* get sign and digit */
else c = c | 0x30; /* default */
WriteB (c, ((dscr[1] + lnt - i) & 0177777));
} /* end for */
} /* end numeric */
return;
}
@@ -1190,8 +1193,8 @@ int32 i;
if (sc) {
for (i = 0; i < DSTRLNT; i++) {
if ((i + sc) < DSTRLNT) dsrc->val[i] = dsrc->val[i + sc];
else dsrc->val[i] = 0; } }
if ((i + sc) < DSTRLNT) dsrc->val[i] = dsrc->val[i + sc];
else dsrc->val[i] = 0; } }
return;
}
@@ -1209,9 +1212,9 @@ int32 i, c;
c = 0;
if (sc) {
for (i = DSTRMAX; i >= 0; i--) {
if (i > (DSTRMAX - sc)) c = c | dsrc->val[i];
if ((i - sc) >= 0) dsrc->val[i] = dsrc->val[i - sc];
else dsrc->val[i] = 0; } }
if (i > (DSTRMAX - sc)) c = c | dsrc->val[i];
if ((i - sc) >= 0) dsrc->val[i] = dsrc->val[i - sc];
else dsrc->val[i] = 0; } }
return c;
}
@@ -1230,10 +1233,10 @@ int32 i, s, rs, nc;
if (s = sc * 4) {
rs = 32 - s;
for (i = DSTRMAX; i >= 0; i--) {
nc = dsrc->val[i];
dsrc->val[i] = ((dsrc->val[i] >> s) |
(cin << rs)) & 0xFFFFFFFF;
cin = nc; }
nc = dsrc->val[i];
dsrc->val[i] = ((dsrc->val[i] >> s) |
(cin << rs)) & 0xFFFFFFFF;
cin = nc; }
return cin; }
return 0;
}
@@ -1253,10 +1256,10 @@ int32 i, s, rs, nc;
if (s = sc * 4) {
rs = 32 - s;
for (i = 0; i < DSTRLNT; i++) {
nc = dsrc->val[i];
dsrc->val[i] = ((dsrc->val[i] << s) |
(cin >> rs)) & 0xFFFFFFFF;
cin = nc; }
nc = dsrc->val[i];
dsrc->val[i] = ((dsrc->val[i] << s) |
(cin >> rs)) & 0xFFFFFFFF;
cin = nc; }
return cin; }
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
To: Users
From: Bob Supnik
Subj: PDP-11 Simulator Usage
Date: 15-Nov-2002
Date: 15-Jan-2003
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2002, written by Robert M Supnik
Copyright (c) 1993-2002, Robert M Supnik
Original code published in 1993-2003, written by Robert M Supnik
Copyright (c) 1993-2003, 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"),
@@ -73,7 +73,8 @@ sim/pdp11/ pdp11_defs.h
pdp11_tc.c
pdp11_tm.c
pdp11_ts.c
pdp11_xp.c
pdp11_xq.c
pdp11_xu.c
2. PDP-11 Features
@@ -106,10 +107,12 @@ TC TC11/TU56 DECtape controller with eight drives
TM TM11/TU10 magnetic tape controller with eight drives
TS TS11/TSV05 magnetic tape controller with one drive
TQ TQK50 TMSCP magnetic tape controller with four drives
XQ DELQA/DEQNA Ethernet controller
XQ DELQA/DEQNA Qbus Ethernet controller
XU DEUNA/DELUA Unibus Ethernet controller
The DZ, RK, HK, RL, RP, RQ, RQB, RQC, RQD, RX, RY, TC, TM, TS, TQ, and XQ
devices can be set DISABLED. RQB, RQC, RQD, RY, and TS are disabled by default.
The DZ, RK, HK, RL, RP, RQ, RQB, RQC, RQD, RX, RY, TC, TM, TS, TQ, XQ, and XU
devices can be set DISABLED. RQB, RQC, RQD, RY, TS, and XU are disabled by
default.
The PDP-11 simulator implements several unique stop conditions:
@@ -1140,9 +1143,9 @@ Error handling is as follows:
OS I/O error fatal tape error
2.10 DELQA/DEQNA Ethernet Controller (XQ)
2.10 DELQA/DEQNA Qbus Ethernet Controller (XQ)
XQ simulates the DELQA/DEQNA 10Mbps Ethernet controller. Options allow
XQ simulates the DELQA/DEQNA Qbus Ethernet controller. Options allow
control of the MAC address, the controller mode, and the sanity timer.
SET XQ MAC=<mac-address> ex. 08-00-2B-AA-BB-CC
@@ -1209,7 +1212,12 @@ not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers,
nor the 10Mbit/sec of a standard Ethernet. Attach it to a Fast Ethernet
(100 Mbit/sec) card, and "Feel the Power!" :-)
2.11 Symbolic Display and Input
2.11 DEUNA/DELUA Unibus Ethernet Controller (XU)
XU simulates the DEUNA/DELUA Unibus Ethernet controller. THe current
implementation is a stub and is permanently disabled.
2.12 Symbolic Display and Input
The PDP-11 simulator implements symbolic display and input. Display is
controlled by command line switches:

View File

@@ -255,35 +255,35 @@ switch ((IR >> 8) & 017) { /* decode IR<11:8> */
case 0:
switch (ac) { /* decode IR<7:6> */
case 0: /* specials */
if (IR == 0170000) { /* CFCC */
N = (FPS >> PSW_V_N) & 1;
Z = (FPS >> PSW_V_Z) & 1;
V = (FPS >> PSW_V_V) & 1;
C = (FPS >> PSW_V_C) & 1; }
else if (IR == 0170001) /* SETF */
FPS = FPS & ~FPS_D;
else if (IR == 0170002) /* SETI */
FPS = FPS & ~FPS_L;
else if (IR == 0170011) /* SETD */
FPS = FPS | FPS_D;
else if (IR == 0170012) /* SETL */
FPS = FPS | FPS_L;
else fpnotrap (FEC_OP);
break;
if (IR == 0170000) { /* CFCC */
N = (FPS >> PSW_V_N) & 1;
Z = (FPS >> PSW_V_Z) & 1;
V = (FPS >> PSW_V_V) & 1;
C = (FPS >> PSW_V_C) & 1; }
else if (IR == 0170001) /* SETF */
FPS = FPS & ~FPS_D;
else if (IR == 0170002) /* SETI */
FPS = FPS & ~FPS_L;
else if (IR == 0170011) /* SETD */
FPS = FPS | FPS_D;
else if (IR == 0170012) /* SETL */
FPS = FPS | FPS_L;
else fpnotrap (FEC_OP);
break;
case 1: /* LDFPS */
dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
FPS = dst & FPS_RW;
break;
dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaW (dstspec));
FPS = dst & FPS_RW;
break;
case 2: /* STFPS */
FPS = FPS & FPS_RW;
if (dstspec <= 07) R[dstspec] = FPS;
else WriteW (FPS, GeteaW (dstspec));
break;
FPS = FPS & FPS_RW;
if (dstspec <= 07) R[dstspec] = FPS;
else WriteW (FPS, GeteaW (dstspec));
break;
case 3: /* STST */
if (dstspec <= 07) R[dstspec] = FEC;
else WriteI ((FEC << 16) | FEA, GeteaFP (dstspec, LONG),
dstspec, LONG);
break; } /* end switch <7:6> */
if (dstspec <= 07) R[dstspec] = FEC;
else WriteI ((FEC << 16) | FEA, GeteaFP (dstspec, LONG),
dstspec, LONG);
break; } /* end switch <7:6> */
break; /* end case 0 */
/* "Easy" instructions */
@@ -291,27 +291,27 @@ case 0:
case 1:
switch (ac) { /* decode IR<7:6> */
case 0: /* CLRf */
WriteFP (&zero_fac, GeteaFP (dstspec, lenf), dstspec, lenf);
FPS = (FPS & ~FPS_CC) | FPS_Z;
break;
WriteFP (&zero_fac, GeteaFP (dstspec, lenf), dstspec, lenf);
FPS = (FPS & ~FPS_CC) | FPS_Z;
break;
case 1: /* TSTf */
ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
FPS = setfcc (FPS, fsrc.h, 0);
break;
ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
FPS = setfcc (FPS, fsrc.h, 0);
break;
case 2: /* ABSf */
ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
else fsrc.h = fsrc.h & ~FP_SIGN;
WriteFP (&fsrc, ea, dstspec, lenf);
FPS = setfcc (FPS, fsrc.h, 0);
break;
ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
else fsrc.h = fsrc.h & ~FP_SIGN;
WriteFP (&fsrc, ea, dstspec, lenf);
FPS = setfcc (FPS, fsrc.h, 0);
break;
case 3: /* NEGf */
ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
else fsrc.h = fsrc.h ^ FP_SIGN;
WriteFP (&fsrc, ea, dstspec, lenf);
FPS = setfcc (FPS, fsrc.h, 0);
break; } /* end switch <7:6> */
ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf);
if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
else fsrc.h = fsrc.h ^ FP_SIGN;
WriteFP (&fsrc, ea, dstspec, lenf);
FPS = setfcc (FPS, fsrc.h, 0);
break; } /* end switch <7:6> */
break; /* end case 1 */
case 5: /* LDf */
ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf);
@@ -347,13 +347,13 @@ case 7: /* CMPf */
if (GET_EXP (fsrc.h) == 0) fsrc = zero_fac;
if (GET_EXP (fac.h) == 0) fac = zero_fac;
if ((fsrc.h == fac.h) && (fsrc.l == fac.l)) { /* equal? */
FPS = (FPS & ~FPS_CC) | FPS_Z;
if ((fsrc.h | fsrc.l) == 0) { /* zero? */
F_STORE (qdouble, zero_fac, FR[ac]); }
break; }
FPS = (FPS & ~FPS_CC) | FPS_Z;
if ((fsrc.h | fsrc.l) == 0) { /* zero? */
F_STORE (qdouble, zero_fac, FR[ac]); }
break; }
FPS = (FPS & ~FPS_CC) | ((fsrc.h >> (FP_V_SIGN - PSW_V_N)) & FPS_N);
if ((GET_SIGN (fsrc.h ^ fac.h) == 0) && (fac.h != 0) &&
F_LT (fsrc, fac)) FPS = FPS ^ FPS_N;
F_LT (fsrc, fac)) FPS = FPS ^ FPS_N;
break;
/* Load and store exponent instructions */
@@ -364,10 +364,11 @@ case 015: /* LDEXP */
fac.h = (fac.h & ~FP_EXP) | (((dst + FP_BIAS) & FP_M_EXP) << FP_V_EXP);
newV = 0;
if ((dst > 0177) && (dst <= 0177600)) {
if (dst < 0100000) {
if (fpnotrap (FEC_OVFLO)) fac = zero_fac;
newV = FPS_V; }
else { if (fpnotrap (FEC_UNFLO)) fac = zero_fac; } }
if (dst < 0100000) {
if (fpnotrap (FEC_OVFLO)) fac = zero_fac;
newV = FPS_V; }
else {
if (fpnotrap (FEC_UNFLO)) fac = zero_fac; } }
F_STORE (qdouble, fac, FR[ac]);
FPS = setfcc (FPS, fac.h, newV);
break;
@@ -390,13 +391,13 @@ case 016: /* LDCif */
else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni);
fac.h = 0;
if (fac.l) {
if (sign = GET_SIGN_L (fac.l)) fac.l = (fac.l ^ 0xFFFFFFFF) + 1;
for (i = 0; GET_SIGN_L (fac.l) == 0; i++) fac.l = fac.l << 1;
exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i;
fac.h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) |
((fac.l >> (31 - FP_V_HB)) & FP_FRACH);
fac.l = (fac.l << (FP_V_HB + 1)) & FP_FRACL;
if ((FPS & (FPS_D + FPS_T)) == 0) roundfp11 (&fac); }
if (sign = GET_SIGN_L (fac.l)) fac.l = (fac.l ^ 0xFFFFFFFF) + 1;
for (i = 0; GET_SIGN_L (fac.l) == 0; i++) fac.l = fac.l << 1;
exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i;
fac.h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) |
((fac.l >> (31 - FP_V_HB)) & FP_FRACH);
fac.l = (fac.l << (FP_V_HB + 1)) & FP_FRACL;
if ((FPS & (FPS_D + FPS_T)) == 0) roundfp11 (&fac); }
F_STORE (qdouble, fac, FR[ac]);
FPS = setfcc (FPS, fac.h, 0);
break;
@@ -405,28 +406,31 @@ case 013: /* STCfi */
exp = GET_EXP (FR[ac].h); /* exponent, */
F_LOAD_FRAC (qdouble, FR[ac], fac); /* fraction */
if (FPS & FPS_L) {
leni = LONG;
i = FP_BIAS + 32; }
else { leni = WORD;
i = FP_BIAS + 16; }
leni = LONG;
i = FP_BIAS + 32; }
else {
leni = WORD;
i = FP_BIAS + 16; }
C = 0;
if (exp <= FP_BIAS) dst = 0;
else if (exp > i) {
dst = 0;
C = 1; }
else {
F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc);
if (leni == WORD) fsrc.l = fsrc.l & ~0177777;
if (fsrc.l >= i_limit[leni == LONG][sign]) {
dst = 0;
C = 1; }
else { F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc);
if (leni == WORD) fsrc.l = fsrc.l & ~0177777;
if (fsrc.l >= i_limit[leni == LONG][sign]) {
dst = 0;
C = 1; }
else { dst = fsrc.l;
if (sign) dst = -dst; } }
C = 1; }
else {
dst = fsrc.l;
if (sign) dst = -dst; } }
N = GET_SIGN_L (dst);
Z = (dst == 0);
V = 0;
if (C) fpnotrap (FEC_ICVT);
FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) |
(Z << PSW_V_Z) | (C << PSW_V_C);
(Z << PSW_V_Z) | (C << PSW_V_C);
if (dstspec <= 07) R[dstspec] = (dst >> 16) & 0177777;
else WriteI (dst, GeteaFP (dstspec, leni), dstspec, leni);
break;
@@ -513,15 +517,15 @@ case 4: /* -(R) */
adr = R[reg] = (R[reg] - len) & 0177777;
if (update_MM) MMR1 = (((-len) & 037) << 3) | reg;
if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
setTRAP (TRAP_YEL);
setCPUERR (CPUE_YEL); }
setTRAP (TRAP_YEL);
setCPUERR (CPUE_YEL); }
return (adr | ds);
case 5: /* @-(R) */
adr = R[reg] = (R[reg] - 2) & 0177777;
if (update_MM) MMR1 = 0360 | reg;
if ((adr < STKLIM) && (reg == 6) && (cm == KERNEL)) {
setTRAP (TRAP_YEL);
setCPUERR (CPUE_YEL); }
setTRAP (TRAP_YEL);
setCPUERR (CPUE_YEL); }
adr = ReadW (adr | ds);
return (adr | dsenable);
case 6: /* d(r) */
@@ -573,10 +577,10 @@ if (spec == 027) {
fptr->l = 0; }
else { exta = VA & ~0177777;
fptr->h = (ReadW (VA) << FP_V_F0) |
(ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1);
(ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1);
if (len == QUAD) fptr->l =
(ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) |
(ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3);
(ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) |
(ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3);
else fptr->l = 0; }
if ((GET_SIGN (fptr->h) != 0) && (GET_EXP (fptr->h) == 0) &&
(fpnotrap (FEC_UNDFV) == 0)) ABORT (TRAP_INT);
@@ -662,26 +666,26 @@ if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) { /* signs different? */
if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac); } /* sub, shf fsrc */
F_SUB (fsrcfrac, facfrac, facfrac); /* sub fsrc from fac */
if ((facfrac.h | facfrac.l) == 0) { /* result zero? */
*facp = zero_fac; /* no overflow */
return 0; }
*facp = zero_fac; /* no overflow */
return 0; }
if (ediff <= 1) { /* big normalize? */
if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
F_LSH_K (facfrac, 24, facfrac);
facexp = facexp - 24; }
if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
F_LSH_K (facfrac, 12, facfrac);
facexp = facexp - 12; }
if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
F_LSH_K (facfrac, 6, facfrac);
facexp = facexp - 6; } }
if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
F_LSH_K (facfrac, 24, facfrac);
facexp = facexp - 24; }
if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
F_LSH_K (facfrac, 12, facfrac);
facexp = facexp - 12; }
if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
F_LSH_K (facfrac, 6, facfrac);
facexp = facexp - 6; } }
while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
F_LSH_1 (facfrac);
facexp = facexp - 1; } }
F_LSH_1 (facfrac);
facexp = facexp - 1; } }
else { if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac); } /* add, shf fsrc */
F_ADD (fsrcfrac, facfrac, facfrac); /* add fsrc to fac */
if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) {
F_RSH_1 (facfrac); /* carry out, shift */
facexp = facexp + 1; } }
F_RSH_1 (facfrac); /* carry out, shift */
facexp = facexp + 1; } }
return round_and_pack (facp, facexp, &facfrac, 1);
}
@@ -770,30 +774,31 @@ if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
*/
if (facexp <= FP_BIAS) { /* case 1 */
*facp = zero_fac;
return round_and_pack (fracp, facexp, &facfrac, 1); }
*facp = zero_fac;
return round_and_pack (fracp, facexp, &facfrac, 1); }
if (facexp > ((FPS & FPS_D)? FP_BIAS + 56: FP_BIAS + 24)) {
*fracp = zero_fac; /* case 2 */
return round_and_pack (facp, facexp, &facfrac, 0); }
*fracp = zero_fac; /* case 2 */
return round_and_pack (facp, facexp, &facfrac, 0); }
F_RSH_V (fmask_fac, facexp - FP_BIAS, fmask); /* shift mask */
fsrcfrac.l = facfrac.l & fmask.l; /* extract fraction */
fsrcfrac.h = facfrac.h & fmask.h;
if ((fsrcfrac.h | fsrcfrac.l) == 0) *fracp = zero_fac;
else { F_LSH_V (fsrcfrac, facexp - FP_BIAS, fsrcfrac);
fsrcexp = FP_BIAS;
if ((fsrcfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
F_LSH_K (fsrcfrac, 24, fsrcfrac);
fsrcexp = fsrcexp - 24; }
if ((fsrcfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
F_LSH_K (fsrcfrac, 12, fsrcfrac);
fsrcexp = fsrcexp - 12; }
if ((fsrcfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
F_LSH_K (fsrcfrac, 6, fsrcfrac);
fsrcexp = fsrcexp - 6; }
while (GET_BIT (fsrcfrac.h, FP_V_HB + FP_GUARD) == 0) {
F_LSH_1 (fsrcfrac);
fsrcexp = fsrcexp - 1; }
round_and_pack (fracp, fsrcexp, &fsrcfrac, 1); }
else {
F_LSH_V (fsrcfrac, facexp - FP_BIAS, fsrcfrac);
fsrcexp = FP_BIAS;
if ((fsrcfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
F_LSH_K (fsrcfrac, 24, fsrcfrac);
fsrcexp = fsrcexp - 24; }
if ((fsrcfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
F_LSH_K (fsrcfrac, 12, fsrcfrac);
fsrcexp = fsrcexp - 12; }
if ((fsrcfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
F_LSH_K (fsrcfrac, 6, fsrcfrac);
fsrcexp = fsrcexp - 6; }
while (GET_BIT (fsrcfrac.h, FP_V_HB + FP_GUARD) == 0) {
F_LSH_1 (fsrcfrac);
fsrcexp = fsrcexp - 1; }
round_and_pack (fracp, fsrcexp, &fsrcfrac, 1); }
facfrac.l = facfrac.l & ~fmask.l;
facfrac.h = facfrac.h & ~fmask.h;
return round_and_pack (facp, facexp, &facfrac, 0);
@@ -835,18 +840,18 @@ mpc = *f2p;
F_LSH_GUARD (mpc); /* guard multipicand */
if ((mpy.l | mpc.l) == 0) { /* 24b x 24b? */
for (i = 0; i < 24; i++) {
if (mpy.h & 1) result.h = result.h + mpc.h;
F_RSH_1 (result);
mpy.h = mpy.h >> 1; } }
if (mpy.h & 1) result.h = result.h + mpc.h;
F_RSH_1 (result);
mpy.h = mpy.h >> 1; } }
else { if (mpy.l != 0) { /* 24b x 56b? */
for (i = 0; i < 32; i++) {
if (mpy.l & 1) { F_ADD (mpc, result, result); }
F_RSH_1 (result);
mpy.l = mpy.l >> 1; } }
for (i = 0; i < 24; i++) {
if (mpy.h & 1) { F_ADD (mpc, result, result); }
for (i = 0; i < 32; i++) {
if (mpy.l & 1) { F_ADD (mpc, result, result); }
F_RSH_1 (result);
mpy.h = mpy.h >> 1; } }
mpy.l = mpy.l >> 1; } }
for (i = 0; i < 24; i++) {
if (mpy.h & 1) { F_ADD (mpc, result, result); }
F_RSH_1 (result);
mpy.h = mpy.h >> 1; } }
*f1p = result;
return;
}
@@ -886,9 +891,9 @@ quo = zero_fac;
for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) {
F_LSH_1 (quo); /* shift quotient */
if (!F_LT (facfrac, fsrcfrac)) { /* divd >= divr? */
F_SUB (fsrcfrac, facfrac, facfrac); /* divd - divr */
if (qd) quo.l = quo.l | 1; /* double or single? */
else quo.h = quo.h | 1; }
F_SUB (fsrcfrac, facfrac, facfrac); /* divd - divr */
if (qd) quo.l = quo.l | 1; /* double or single? */
else quo.h = quo.h | 1; }
F_LSH_1 (facfrac); } /* shift divd */
if (i > 0) { F_LSH_V (quo, i, quo); } /* early exit? */
@@ -967,8 +972,8 @@ if (r && ((FPS & FPS_T) == 0)) {
if (FPS & FPS_D) { F_ADD (dround_guard_fac, frac, frac); }
else { F_ADD (fround_guard_fac, frac, frac); }
if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) {
F_RSH_1 (frac);
exp = exp + 1; } }
F_RSH_1 (frac);
exp = exp + 1; } }
F_RSH_GUARD (frac);
facp->l = frac.l & FP_FRACL;
facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) |

View File

@@ -478,7 +478,7 @@ case 006: /* HKER */
case 007: /* HKAS */
*data = hkof;
for (i = 0; i < HK_NUMDR; i++)
if (hkds[i] & DS_ATA) *data = *data | (AS_U0 << i);
if (hkds[i] & DS_ATA) *data = *data | (AS_U0 << i);
break;
case 010: /* HKDC */
*data = hkdc = hkdc & ~DC_MBZ;
@@ -526,27 +526,27 @@ if ((hkcs1 & CS1_GO) && /* busy? */
switch (j) { /* decode PA<4:1> */
case 000: /* HKCS1 */
if (data & CS1_CCLR) { /* controller reset? */
hkcs1 = CS1_DONE; /* CS1 = done */
hkcs2 = CS2_IR | CS2_OR; /* CS2 = ready */
hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */
hkda = hkdc = 0;
hkba = hkwc = 0;
hkspr = hkof = 0;
CLR_INT (HK); /* clr int */
for (i = 0; i < HK_NUMDR; i++) { /* stop data xfr */
if (sim_is_active (&hk_unit[i]) &&
((uptr->FNC & CS1_M_FNC) >= FNC_XFER))
sim_cancel (&hk_unit[i]); }
drv = 0;
break; }
hkcs1 = CS1_DONE; /* CS1 = done */
hkcs2 = CS2_IR | CS2_OR; /* CS2 = ready */
hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */
hkda = hkdc = 0;
hkba = hkwc = 0;
hkspr = hkof = 0;
CLR_INT (HK); /* clr int */
for (i = 0; i < HK_NUMDR; i++) { /* stop data xfr */
if (sim_is_active (&hk_unit[i]) &&
((uptr->FNC & CS1_M_FNC) >= FNC_XFER))
sim_cancel (&hk_unit[i]); }
drv = 0;
break; }
if (data & CS1_IE) { /* setting IE? */
if (data & CS1_DONE) SET_INT (HK); } /* write to DONE+IE? */
if (data & CS1_DONE) SET_INT (HK); } /* write to DONE+IE? */
else CLR_INT (HK); /* no, clr intr */
hkcs1 = (hkcs1 & ~CS1_RW) | (data & CS1_RW); /* merge data */
if (SC02C) hkspr = (hkspr & ~CS1_M_UAE) | GET_UAE (hkcs1);
if (hkcs1 & CS1_GO) { /* go? */
if (hkcs1 & CS1_ERR) hkcs1 = hkcs1 & ~CS1_GO;
else hk_go (drv); }
if (hkcs1 & CS1_ERR) hkcs1 = hkcs1 & ~CS1_GO;
else hk_go (drv); }
break;
case 001: /* HKWC */
hkwc = data;
@@ -718,28 +718,30 @@ case FNC_NOP: /* select */
case FNC_OFFSET: /* offset */
if (uptr->FNC & FNC_2ND) { /* 2nd int? */
hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */
update_hkcs (CS1_DI, drv); } /* drive intr */
else { uptr->FNC = uptr->FNC | FNC_2ND; /* second state */
hk_off[drv] = hkof & AS_OF; /* save offset */
sim_activate (uptr, hk_swait * 10); /* wait for compl */
update_hkcs (CS1_DONE, drv); } /* done */
hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */
update_hkcs (CS1_DI, drv); } /* drive intr */
else {
uptr->FNC = uptr->FNC | FNC_2ND; /* second state */
hk_off[drv] = hkof & AS_OF; /* save offset */
sim_activate (uptr, hk_swait * 10); /* wait for compl */
update_hkcs (CS1_DONE, drv); } /* done */
break;
case FNC_RECAL: /* recalibrate */
case FNC_SEEK: /* seek */
if (uptr->FNC & FNC_2ND) { /* 2nd int? */
hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */
update_hkcs (CS1_DI, drv); } /* drive intr */
else { uptr->FNC = uptr->FNC | FNC_2ND; /* second state */
hk_off[drv] = 0; /* clr offset */
dc = (fnc == FNC_SEEK)? hkdc: 0; /* get cyl */
hk_dif[drv] = dc - uptr->CYL; /* cyl diff */
t = abs (hk_dif[drv]); /* |cyl diff| */
if (t == 0) t = 1; /* min time */
uptr->CYL = dc; /* save cyl */
sim_activate (uptr, hk_swait * t); /* schedule */
update_hkcs (CS1_DONE, drv); } /* done */
hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */
update_hkcs (CS1_DI, drv); } /* drive intr */
else {
uptr->FNC = uptr->FNC | FNC_2ND; /* second state */
hk_off[drv] = 0; /* clr offset */
dc = (fnc == FNC_SEEK)? hkdc: 0; /* get cyl */
hk_dif[drv] = dc - uptr->CYL; /* cyl diff */
t = abs (hk_dif[drv]); /* |cyl diff| */
if (t == 0) t = 1; /* min time */
uptr->CYL = dc; /* save cyl */
sim_activate (uptr, hk_swait * t); /* schedule */
update_hkcs (CS1_DONE, drv); } /* done */
break;
/* Data transfer commands only generate one interrupt */
@@ -747,15 +749,15 @@ case FNC_SEEK: /* seek */
case FNC_READH:
hkdb[0] = uptr->CYL << RDH1_V_CYL; /* first word */
hkdb[1] = (GET_SC (hkda) << RDH2_V_SEC) | /* second word */
(1 << (GET_SF (hkda) + RDH2_V_DHA)) | RDH2_GOOD;
(1 << (GET_SF (hkda) + RDH2_V_DHA)) | RDH2_GOOD;
hkdb[2] = hkdb[0] ^ hkdb[1]; /* checksum */
update_hkcs (CS1_DONE, drv); /* done */
break;
case FNC_WRITE: /* write */
if (uptr->flags & UNIT_WPRT) { /* write locked? */
hk_cmderr (ER_WLE, drv); /* command error */
return SCPE_OK; }
hk_cmderr (ER_WLE, drv); /* command error */
return SCPE_OK; }
case FNC_WCHK: /* write check */
case FNC_READ: /* read */
if (SC02C) ba = ((hkspr & XM_MMASK) << 16) | hkba; /* 22b addr? */
@@ -809,11 +811,11 @@ case FNC_READ: /* read */
awc = wc;
for (wc = 0; wc < awc; wc++) { /* loop thru buf */
if (Map_ReadW (ba, 2, &comp, MAP)) { /* read word */
hkcs2 = hkcs2 | CS2_NEM; /* set error */
break; }
hkcs2 = hkcs2 | CS2_NEM; /* set error */
break; }
if (comp != hkxb[wc]) { /* compare wd */
hkcs2 = hkcs2 | CS2_WCE; /* set error */
break; }
hkcs2 = hkcs2 | CS2_WCE; /* set error */
break; }
if ((hkcs2 & CS2_UAI) == 0) ba = ba + 2; }
} /* end else wchk */
@@ -821,7 +823,7 @@ case FNC_READ: /* read */
hkba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */
hkcs1 = PUT_UAE (hkcs1, ba >> 16); /* upper 2b */
if (SC02C) /* SC02C? upper 6b */
hkspr = (hkspr & ~XM_MMASK) | ((ba >> 16) & XM_MMASK);
hkspr = (hkspr & ~XM_MMASK) | ((ba >> 16) & XM_MMASK);
da = da + wc + (HK_NUMWD - 1);
da = da / HK_NUMWD;
hkda = da % HK_NUMSC;
@@ -830,10 +832,10 @@ case FNC_READ: /* read */
hkdc = da / HK_NUMSF;
if (err != 0) { /* error? */
hk_cmderr (ER_PAR, drv); /* set drive error */
perror ("HK I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
hk_cmderr (ER_PAR, drv); /* set drive error */
perror ("HK I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
case FNC_WRITEH: /* write headers stub */
update_hkcs (CS1_DONE, drv); /* set done */
@@ -858,7 +860,7 @@ if (flag & CS1_DONE) hkcs1 = hkcs1 & ~CS1_GO; /* clear go */
if (hkcs1 & CS1_IE) { /* intr enable? */
if (((flag & CS1_DONE) && ((hkcs1 & CS1_DONE) == 0)) ||
((flag & CS1_DI) && (hkcs1 & CS1_DONE))) /* done 0->1 or DI? */
SET_INT (HK); }
SET_INT (HK); }
else CLR_INT (HK);
hkcs1 = (hkcs1 & (CS1_DT|CS1_UAE|CS1_DONE|CS1_IE|CS1_SPA|CS1_FNC|CS1_GO)) | flag;
for (i = 0; i < HK_NUMDR; i++) { /* if ATA, set DI */
@@ -878,11 +880,11 @@ if (hk_unit[drv].flags & UNIT_DIS) { /* disabled? */
hkds[drv] = (hkds[drv] & (DS_VV | DS_PIP | DS_ATA)) | DS_VLD | DS_DRA;
if (hk_unit[drv].flags & UNIT_ATT) { /* attached? */
if (!sim_is_active (&hk_unit[drv])) /* not busy? */
hkds[drv] = hkds[drv] | DS_RDY; /* set RDY */
hkds[drv] = hkds[drv] | DS_RDY; /* set RDY */
if (hker[drv]) hkds[drv] = hkds[drv] | DS_ATA; /* err? set ATA */
if (hk_off[drv]) hkds[drv] = hkds[drv] | DS_OF; /* offset? set OF */
if (hk_unit[drv].flags & UNIT_WPRT) /* write locked? */
hkds[drv] = hkds[drv] | DS_WRL; } /* set WRL */
hkds[drv] = hkds[drv] | DS_WRL; } /* set WRL */
else { hkds[drv] = hkds[drv] & ~(DS_PIP | DS_VV); /* no, clr PIP,VV */
hker[drv] = 0; } /* no errors */
if (hk_unit[drv].flags & UNIT_RK07) hkds[drv] = hkds[drv] | DS_DT;
@@ -1055,7 +1057,7 @@ if (sim_is_active (uptr)) { /* unit active? */
sim_cancel (uptr); /* cancel operation */
hker[drv] = hker[drv] | ER_OPI; /* set drive error */
if ((uptr->FNC & CS1_M_FNC) >= FNC_XFER) /* data transfer? */
hkcs1 = hkcs1 | CS1_DONE | CS1_ERR; } /* set done, err */
hkcs1 = hkcs1 | CS1_DONE | CS1_ERR; } /* set done, err */
update_hkcs (CS1_DI, drv); /* request intr */
return detach_unit (uptr);
}

View File

@@ -90,9 +90,9 @@ t_stat stat;
for (i = 0; dibp = dib_tab[i]; i++ ) {
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
stat = dibp->rd (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
stat = dibp->rd (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
return SCPE_NXM;
}
@@ -105,9 +105,9 @@ t_stat stat;
for (i = 0; dibp = dib_tab[i]; i++ ) {
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
stat = dibp->wr (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
stat = dibp->wr (data, pa, access);
trap_req = calc_ints (ipl, trap_req);
return stat; } }
return SCPE_NXM;
}
@@ -168,12 +168,13 @@ t_stat ubm_wr (int32 data, int32 addr, int32 access)
if (cpu_ubm) {
int32 sc, pg = (addr >> 2) & UBM_M_PN;
if (access == WRITEB) {
sc = (addr & 3) << 3;
ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) |
((data & 0377) << sc); }
else { sc = (addr & 2) << 3;
ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) |
((data & 0177777) << sc); }
sc = (addr & 3) << 3;
ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) |
((data & 0377) << sc); }
else {
sc = (addr & 2) << 3;
ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) |
((data & 0177777) << sc); }
ub_map[pg] = ub_map[pg] & 017777776;
return SCPE_OK; }
return SCPE_NXM;
@@ -191,7 +192,7 @@ if (cpu_bme) { /* bus map on? */
int32 pg = UBM_GETPN (ba); /* map entry */
int32 off = UBM_GETOFF (ba); /* offset */
if (pg != UBM_M_PN) /* last page? */
*ma = (ub_map[pg] + off) & PAMASK; /* no, use map */
*ma = (ub_map[pg] + off) & PAMASK; /* no, use map */
else *ma = (IOPAGEBASE + off) & PAMASK; } /* yes, use fixed */
else *ma = ba; /* else physical */
return TRUE;

View File

@@ -126,7 +126,7 @@ if ((PA & 02) == 0) { /* csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0) CLR_INT (LPT);
else if ((lpt_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
SET_INT (LPT);
SET_INT (LPT);
lpt_csr = (lpt_csr & ~LPTCSR_RW) | (data & LPTCSR_RW); }
else { if ((PA & 1) == 0) lpt_unit.buf = data & 0177; /* buffer */
lpt_csr = lpt_csr & ~CSR_DONE;

View File

@@ -1,6 +1,6 @@
/* pdp11_mscp.h: DEC MSCP and TMSCP definitions
Copyright (c) 2001-2002, Robert M Supnik
Copyright (c) 2001-2003, Robert M Supnik
Derived from work by Stephen F. Shirron
Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,6 +24,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.
09-Jan-03 RMS Tape read/write end pkt is longer than disk read/write
20-Sep-02 RMS Merged TMSCP definitions
*/
@@ -251,21 +252,21 @@
#define ERG_LNT 12
/* Flush - 10 W of status (8 undefined) */
/* Flush - 10 W status (8 undefined) */
#define FLU_LNT 32
/* 8 - 15 /* reserved */
#define FLU_POSL 16 /* position */
#define FLU_POSH 17
/* Write tape mark - 10W of status (8 undefined) */
/* Write tape mark - 10W status (8 undefined) */
#define WTM_LNT 32
/* 8 - 15 /* reserved */
#define WTM_POSL 16 /* position */
#define WTM_POSH 17
/* Get command status packet - 2 W parameter, 4 W of status */
/* Get command status packet - 2 W parameter, 4 W status */
#define GCS_LNT 20
#define GCS_REFL 8 /* ref # */
@@ -386,9 +387,11 @@
#define POS_POSL 16 /* position */
#define POS_POSH 17
/* Data transfer packet - 10 W parameters (disk), 6W parameters (tape), 10 W status */
/* Data transfer packet - 10 W parameters (disk), 6W parameters (tape),
10 W status (disk), 12W status (tape) */
#define RW_LNT 32
#define RW_LNT_D 32
#define RW_LNT_T 36
#define RW_BCL 8 /* byte count */
#define RW_BCH 9
#define RW_BAL 10 /* buff desc */

View File

@@ -219,13 +219,13 @@ case 00: /* CSR */
rv = CSR_GETRATE (pclk_csr); /* new rate */
pclk_unit.wait = xtim[rv]; /* new delay */
if ((pclk_csr & CSR_GO) == 0) { /* stopped? */
sim_cancel (&pclk_unit); /* cancel */
if (data & CSR_FIX) pclk_tick (); } /* fix? tick */
sim_cancel (&pclk_unit); /* cancel */
if (data & CSR_FIX) pclk_tick (); } /* fix? tick */
else if (((old_csr & CSR_GO) == 0) || /* run 0 -> 1? */
(rv != CSR_GETRATE (old_csr))) { /* rate change? */
sim_cancel (&pclk_unit); /* cancel */
sim_activate (&pclk_unit, /* start clock */
sim_rtcn_init (pclk_unit.wait, TMR_PCLK));
sim_cancel (&pclk_unit); /* cancel */
sim_activate (&pclk_unit, /* start clock */
sim_rtcn_init (pclk_unit.wait, TMR_PCLK));
}
break;
case 01: /* buffer */
@@ -247,12 +247,13 @@ if (pclk_csr & CSR_UPDN) /* up or down? */
else pclk_ctr = (pclk_ctr - 1) & DMASK; /* 0 = down */
if (pclk_ctr == 0) { /* reached zero? */
if (pclk_csr & CSR_DONE) /* done already set? */
pclk_csr = pclk_csr | CSR_ERR; /* set error */
pclk_csr = pclk_csr | CSR_ERR; /* set error */
else pclk_csr = pclk_csr | CSR_DONE; /* else set done */
if (pclk_csr & CSR_IE) SET_INT (PCLK); /* if IE, set int */
if (pclk_csr & CSR_MODE) pclk_ctr = pclk_csb; /* if rpt, reload */
else { pclk_csb = 0; /* else clr ctr */
pclk_csr = pclk_csr & ~CSR_GO; } } /* and clr go */
else {
pclk_csb = 0; /* else clr ctr */
pclk_csr = pclk_csr & ~CSR_GO; } } /* and clr go */
return;
}

View File

@@ -284,7 +284,7 @@ UNIT *uptr;
switch ((PA >> 1) & 07) { /* decode PA<3:1> */
case 0: /* RKDS: read only */
rkds = (rkds & RKDS_ID) | RKDS_RK05 | RKDS_SC_OK |
(rand () % RK_NUMSC); /* random sector */
(rand () % RK_NUMSC); /* random sector */
uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */
if (uptr->flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */
if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS; /* idle? */
@@ -325,30 +325,30 @@ case 1: /* RKER: read only */
case 2: /* RKCS */
rkcs = rkcs & RKCS_REAL;
if (access == WRITEB) data = (PA & 1)?
(rkcs & 0377) | (data << 8): (rkcs & ~0377) | data;
(rkcs & 0377) | (data << 8): (rkcs & ~0377) | data;
if ((data & CSR_IE) == 0) { /* int disable? */
rkintq = 0; /* clr int queue */
CLR_INT (RK); } /* clr int request */
rkintq = 0; /* clr int queue */
CLR_INT (RK); } /* clr int request */
else if ((rkcs & (CSR_DONE + CSR_IE)) == CSR_DONE) {
rkintq = rkintq | RK_CTLI; /* queue ctrl int */
SET_INT (RK); } /* set int request */
rkintq = rkintq | RK_CTLI; /* queue ctrl int */
SET_INT (RK); } /* set int request */
rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW);
if ((rkcs & CSR_DONE) && (data & CSR_GO)) rk_go (); /* new function? */
return SCPE_OK;
case 3: /* RKWC */
if (access == WRITEB) data = (PA & 1)?
(rkwc & 0377) | (data << 8): (rkwc & ~0377) | data;
(rkwc & 0377) | (data << 8): (rkwc & ~0377) | data;
rkwc = data;
return SCPE_OK;
case 4: /* RKBA */
if (access == WRITEB) data = (PA & 1)?
(rkba & 0377) | (data << 8): (rkba & ~0377) | data;
(rkba & 0377) | (data << 8): (rkba & ~0377) | data;
rkba = data & RKBA_IMP;
return SCPE_OK;
case 5: /* RKDA */
if ((rkcs & CSR_DONE) == 0) return SCPE_OK;
if (access == WRITEB) data = (PA & 1)?
(rkda & 0377) | (data << 8): (rkda & ~0377) | data;
(rkda & 0377) | (data << 8): (rkda & ~0377) | data;
rkda = data;
return SCPE_OK;
default:
@@ -435,10 +435,11 @@ drv = uptr - rk_dev.units; /* get drv number */
if (uptr->FUNC == RKCS_SEEK) { /* seek */
rkcs = rkcs | RKCS_SCP; /* set seek done */
if (rkcs & CSR_IE) { /* ints enabled? */
rkintq = rkintq | RK_SCPI (drv); /* queue request */
if (rkcs & CSR_DONE) SET_INT (RK); }
else { rkintq = 0; /* clear queue */
CLR_INT (RK); } /* clear interrupt */
rkintq = rkintq | RK_SCPI (drv); /* queue request */
if (rkcs & CSR_DONE) SET_INT (RK); }
else {
rkintq = 0; /* clear queue */
CLR_INT (RK); } /* clear interrupt */
return SCPE_OK; }
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
@@ -455,19 +456,19 @@ if ((uptr->FUNC == RKCS_READ) && (err == 0)) { /* read? */
err = ferror (uptr->fileref);
for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */
if (t = Map_WriteW (ma, wc << 1, rkxb, MAP)) { /* store buf */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */
} /* end read */
if ((uptr->FUNC == RKCS_WRITE) && (err == 0)) { /* write? */
if ((uptr->FUNC == RKCS_WRITE) && (err == 0)) { /* write? */
if (t = Map_ReadW (ma, wc << 1, rkxb, MAP)) { /* get buf */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */
rker = rker | RKER_NXM; /* NXM? set flg */
wc = wc - t; } /* adj wd cnt */
if (wc) { /* any xfer? */
awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */
for (i = wc; i < awc; i++) rkxb[i] = 0; /* end of blk */
fxwrite (rkxb, sizeof (int16), awc, uptr->fileref);
err = ferror (uptr->fileref); }
awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */
for (i = wc; i < awc; i++) rkxb[i] = 0; /* end of blk */
fxwrite (rkxb, sizeof (int16), awc, uptr->fileref);
err = ferror (uptr->fileref); }
} /* end write */
if ((uptr->FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */
@@ -476,12 +477,12 @@ if ((uptr->FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */
for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */
awc = wc; /* save wc */
for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */
if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */
rker = rker | RKER_NXM; /* NXM? set flg */
break; }
if (comp != rkxb[wc]) { /* match to disk? */
rker = rker | RKER_WCE; /* no, err */
if (rkcs & RKCS_SSE) break; } }
if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */
rker = rker | RKER_NXM; /* NXM? set flg */
break; }
if (comp != rkxb[wc]) { /* match to disk? */
rker = rker | RKER_WCE; /* no, err */
if (rkcs & RKCS_SSE) break; } }
} /* end wcheck */
rkwc = (rkwc + wc) & 0177777; /* final word count */
@@ -537,11 +538,11 @@ int32 i;
for (i = 0; i <= RK_NUMDR; i++) { /* loop thru intq */
if (rkintq & (1u << i)) { /* bit i set? */
rkintq = rkintq & ~(1u << i); /* clear bit i */
if (rkintq) SET_INT (RK); /* queue next */
rkds = (rkds & ~RKDS_ID) | /* id drive */
(((i == 0)? last_drv: i - 1) << RKDS_V_ID);
return rk_dib.vec; } } /* return vector */
rkintq = rkintq & ~(1u << i); /* clear bit i */
if (rkintq) SET_INT (RK); /* queue next */
rkds = (rkds & ~RKDS_ID) | /* id drive */
(((i == 0)? last_drv: i - 1) << RKDS_V_ID);
return rk_dib.vec; } } /* return vector */
rkintq = 0; /* clear queue */
return 0; /* passive release */
}

View File

@@ -332,53 +332,54 @@ case 0: /* RLCS */
else rlcs = rlcs | RLCS_DRDY; /* see if ready */
if (access == WRITEB) data = (PA & 1)?
(rlcs & 0377) | (data << 8): (rlcs & ~0377) | data;
(rlcs & 0377) | (data << 8): (rlcs & ~0377) | data;
rlcs = (rlcs & ~RLCS_RW) | (data & RLCS_RW);
rlbae = (rlbae & ~RLCS_M_MEX) | ((rlcs >> RLCS_V_MEX) & RLCS_M_MEX);
if (data & CSR_DONE) { /* ready set? */
if ((data & CSR_IE) == 0) CLR_INT (RL);
else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE)
SET_INT (RL);
return SCPE_OK; }
if ((data & CSR_IE) == 0) CLR_INT (RL);
else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE)
SET_INT (RL);
return SCPE_OK; }
CLR_INT (RL); /* clear interrupt */
rlcs = rlcs & ~RLCS_ALLERR; /* clear errors */
switch (GET_FUNC (rlcs)) { /* case on RLCS<3:1> */
case RLCS_NOP: /* nop */
rl_set_done (0);
break;
rl_set_done (0);
break;
case RLCS_SEEK: /* seek */
curr = GET_CYL (uptr->TRK); /* current cylinder */
offs = GET_CYL (rlda); /* offset */
if (rlda & RLDA_SK_DIR) { /* in or out? */
newc = curr + offs; /* out */
maxc = (uptr->flags & UNIT_RL02)?
RL_NUMCY * 2: RL_NUMCY;
if (newc >= maxc) newc = maxc - 1; }
else { newc = curr - offs; /* in */
if (newc < 0) newc = 0; }
uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */
((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0);
sim_activate (uptr, rl_swait * abs (newc - curr));
break;
curr = GET_CYL (uptr->TRK); /* current cylinder */
offs = GET_CYL (rlda); /* offset */
if (rlda & RLDA_SK_DIR) { /* in or out? */
newc = curr + offs; /* out */
maxc = (uptr->flags & UNIT_RL02)?
RL_NUMCY * 2: RL_NUMCY;
if (newc >= maxc) newc = maxc - 1; }
else {
newc = curr - offs; /* in */
if (newc < 0) newc = 0; }
uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */
((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0);
sim_activate (uptr, rl_swait * abs (newc - curr));
break;
default: /* data transfer */
sim_activate (uptr, rl_swait); /* activate unit */
break; } /* end switch func */
sim_activate (uptr, rl_swait); /* activate unit */
break; } /* end switch func */
break; /* end case RLCS */
case 1: /* RLBA */
if (access == WRITEB) data = (PA & 1)?
(rlba & 0377) | (data << 8): (rlba & ~0377) | data;
(rlba & 0377) | (data << 8): (rlba & ~0377) | data;
rlba = data & RLBA_IMP;
break;
case 2: /* RLDA */
if (access == WRITEB) data = (PA & 1)?
(rlda & 0377) | (data << 8): (rlda & ~0377) | data;
(rlda & 0377) | (data << 8): (rlda & ~0377) | data;
rlda = data;
break;
case 3: /* RLMP */
if (access == WRITEB) data = (PA & 1)?
(rlmp & 0377) | (data << 8): (rlmp & ~0377) | data;
(rlmp & 0377) | (data << 8): (rlmp & ~0377) | data;
rlmp = rlmp1 = rlmp2 = data;
break;
case 4: /* RLBAE */
@@ -410,7 +411,7 @@ func = GET_FUNC (rlcs); /* get function */
if (func == RLCS_GSTA) { /* get status */
if (rlda & RLDA_GS_CLR) uptr->STAT = uptr->STAT & ~RLDS_ERR;
rlmp = uptr->STAT | (uptr->TRK & RLDS_HD) |
((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
if (uptr->flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02;
if (uptr->flags & UNIT_WPRT) rlmp = rlmp | RLDS_WLK;
rlmp2 = rlmp1 = rlmp;
@@ -456,19 +457,19 @@ if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */
err = ferror (uptr->fileref);
for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */
if (t = Map_WriteW (ma, wc << 1, rlxb, MAP)) { /* store buffer */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adjust wc */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adjust wc */
} /* end read */
if ((func == RLCS_WRITE) && (err == 0)) { /* write? */
if (t = Map_ReadW (ma, wc << 1, rlxb, MAP)) { /* fetch buffer */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adj xfer lnt */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
wc = wc - t; } /* adj xfer lnt */
if (wc) { /* any xfer? */
awc = (wc + (RL_NUMWD - 1)) & ~(RL_NUMWD - 1); /* clr to */
for (i = wc; i < awc; i++) rlxb[i] = 0; /* end of blk */
fxwrite (rlxb, sizeof (int16), awc, uptr->fileref);
err = ferror (uptr->fileref); }
awc = (wc + (RL_NUMWD - 1)) & ~(RL_NUMWD - 1); /* clr to */
for (i = wc; i < awc; i++) rlxb[i] = 0; /* end of blk */
fxwrite (rlxb, sizeof (int16), awc, uptr->fileref);
err = ferror (uptr->fileref); }
} /* end write */
if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */
@@ -477,12 +478,12 @@ if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */
for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */
awc = wc; /* save wc */
for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */
if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
break; }
if (comp != rlxb[wc]) /* check to buf */
rlcs = rlcs | RLCS_ERR | RLCS_CRC;
} /* end for */
if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */
rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */
break; }
if (comp != rlxb[wc]) /* check to buf */
rlcs = rlcs | RLCS_ERR | RLCS_CRC;
} /* end for */
} /* end wcheck */
rlmp = (rlmp + wc) & 0177777; /* final word count */

View File

@@ -571,7 +571,7 @@ case 006: /* RPER1 */
case 007: /* RPAS */
*data = 0;
for (i = 0; i < RP_NUMDR; i++)
if (rpds[i] & DS_ATA) *data = *data | (AS_U0 << i);
if (rpds[i] & DS_ATA) *data = *data | (AS_U0 << i);
break;
case 010: /* RPLA */
*data = GET_SECTOR (rp_rwait, dtype) << LA_V_SC;
@@ -646,52 +646,53 @@ switch (j) { /* decode PA<5:1> */
case 000: /* RPCS1 */
if ((access == WRITEB) && (PA & 1)) data = data << 8;
if (data & CS1_TRE) { /* error clear? */
rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1<TRE> */
rpcs2 = rpcs2 & ~CS2_ERR; } /* clr CS2<15:8> */
rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1<TRE> */
rpcs2 = rpcs2 & ~CS2_ERR; } /* clr CS2<15:8> */
if ((access == WRITE) || (PA & 1)) { /* hi byte write? */
if (rpcs1 & CS1_DONE) /* done set? */
rpcs1 = (rpcs1 & ~CS1_UAE) | (data & CS1_UAE); }
if (rpcs1 & CS1_DONE) /* done set? */
rpcs1 = (rpcs1 & ~CS1_UAE) | (data & CS1_UAE); }
if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */
if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */
rpiff = 1; /* set CSTB INTR */
rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE);
if (uptr->flags & UNIT_DIS) { /* nx disk? */
rpcs2 = rpcs2 | CS2_NED; /* set error flag */
cs1f = CS1_SC; } /* req interrupt */
else if (sim_is_active (uptr))
rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */
else if (data & CS1_GO) { /* start op */
uptr->FUNC = GET_FNC (data); /* set func */
if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */
((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */
rpcs2 = rpcs2 | CS2_PGE;
else rp_go (drv, uptr->FUNC); } }
if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */
rpiff = 1; /* set CSTB INTR */
rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE);
if (uptr->flags & UNIT_DIS) { /* nx disk? */
rpcs2 = rpcs2 | CS2_NED; /* set error flag */
cs1f = CS1_SC; } /* req interrupt */
else if (sim_is_active (uptr))
rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */
else if (data & CS1_GO) { /* start op */
uptr->FUNC = GET_FNC (data); /* set func */
if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */
((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */
rpcs2 = rpcs2 | CS2_PGE;
else rp_go (drv, uptr->FUNC); } }
rpcs3 = (rpcs3 & ~CS1_IE) | (rpcs1 & CS1_IE);
rpbae = (rpbae & ~CS1_M_UAE) | ((rpcs1 >> CS1_V_UAE) & CS1_M_UAE);
break;
case 001: /* RPWC */
if (access == WRITEB) data = (PA & 1)?
(rpwc & 0377) | (data << 8): (rpwc & ~0377) | data;
(rpwc & 0377) | (data << 8): (rpwc & ~0377) | data;
rpwc = data;
break;
case 002: /* RPBA */
if (access == WRITEB) data = (PA & 1)?
(rpba & 0377) | (data << 8): (rpba & ~0377) | data;
(rpba & 0377) | (data << 8): (rpba & ~0377) | data;
rpba = data & ~BA_MBZ;
break;
case 003: /* RPDA */
if (access == WRITEB) data = (PA & 1)?
(rpda & 0377) | (data << 8): (rpda & ~0377) | data;
(rpda & 0377) | (data << 8): (rpda & ~0377) | data;
rpda = data & ~DA_MBZ;
break;
case 004: /* RPCS2 */
if ((access == WRITEB) && (PA & 1)) data = data << 8;
if (data & CS2_CLR) rp_reset (&rp_dev); /* init? */
else { if ((data & ~rpcs2) & (CS2_PE | CS2_MXF))
cs1f = CS1_SC; /* diagn intr */
if (access == WRITEB) data = (rpcs2 & /* merge data */
((PA & 1)? 0377: 0177400)) | data;
rpcs2 = (rpcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; }
else {
if ((data & ~rpcs2) & (CS2_PE | CS2_MXF))
cs1f = CS1_SC; /* diagn intr */
if (access == WRITEB) data = (rpcs2 & /* merge data */
((PA & 1)? 0377: 0177400)) | data;
rpcs2 = (rpcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; }
drv = GET_UNIT (rpcs2);
break;
case 006: /* RPER1 */
@@ -701,26 +702,26 @@ case 006: /* RPER1 */
case 007: /* RPAS */
if ((access == WRITEB) && (PA & 1)) break;
for (i = 0; i < RP_NUMDR; i++)
if (data & (AS_U0 << i)) rpds[i] = rpds[i] & ~DS_ATA;
if (data & (AS_U0 << i)) rpds[i] = rpds[i] & ~DS_ATA;
break;
case 011: /* RPDB */
if (access == WRITEB) data = (PA & 1)?
(rpdb & 0377) | (data << 8): (rpdb & ~0377) | data;
(rpdb & 0377) | (data << 8): (rpdb & ~0377) | data;
rpdb = data;
break;
case 012: /* RPMR */
if (access == WRITEB) data = (PA & 1)?
(rpmr & 0377) | (data << 8): (rpmr & ~0377) | data;
(rpmr & 0377) | (data << 8): (rpmr & ~0377) | data;
rpmr = data;
break;
case 015: /* RPOF */
if (access == WRITEB) data = (PA & 1)?
(rpof & 0377) | (data << 8): (rpof & ~0377) | data;
(rpof & 0377) | (data << 8): (rpof & ~0377) | data;
rpof = data & ~OF_MBZ;
break;
case 016: /* RPDC */
if (access == WRITEB) data = (PA & 1)?
(rpdc & 0377) | (data << 8): (rpdc & ~0377) | data;
(rpdc & 0377) | (data << 8): (rpdc & ~0377) | data;
rpdc = data & ~DC_MBZ;
break;
case 024: /* RPBAE */
@@ -796,8 +797,8 @@ case FNC_PACK: /* pack acknowledge */
case FNC_OFFSET: /* offset mode */
case FNC_RETURN:
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
break; }
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
break; }
rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */
sim_activate (uptr, rp_swait); /* time operation */
return;
@@ -808,13 +809,13 @@ case FNC_RECAL: /* recalibrate */
case FNC_SEEK: /* seek */
case FNC_SEARCH: /* search */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
break; }
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
break; }
if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */
(GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */
rper1[drv] = rper1[drv] | ER1_IAE;
break; }
rper1[drv] = rper1[drv] | ER1_IAE;
break; }
rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */
t = abs (dc - uptr->CYL); /* cyl diff */
if (t == 0) t = 1; /* min time */
@@ -828,15 +829,15 @@ case FNC_WCHK: /* write check */
case FNC_READ: /* read */
case FNC_READH: /* read headers */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
break; }
rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */
break; }
rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */
rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE);
if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */
(GET_SF (rpda) >= drv_tab[dtype].surf) || /* bad surface */
(GET_SC (rpda) >= drv_tab[dtype].sect)) { /* or bad sector? */
rper1[drv] = rper1[drv] | ER1_IAE;
break; }
rper1[drv] = rper1[drv] | ER1_IAE;
break; }
rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */
sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL)));
uptr->CYL = dc; /* save cylinder */
@@ -890,9 +891,9 @@ case FNC_SEEK: /* seek */
case FNC_WRITE: /* write */
if (uptr->flags & UNIT_WPRT) { /* write locked? */
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; }
rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
break; }
case FNC_WCHK: /* write check */
case FNC_READ: /* read */
case FNC_READH: /* read headers */
@@ -947,11 +948,11 @@ case FNC_READH: /* read headers */
awc = wc;
for (wc = 0; wc < awc; wc++) { /* loop thru buf */
if (Map_ReadW (ba, 2, &comp, RH)) { /* read word */
rpcs2 = rpcs2 | CS2_NEM; /* set error */
break; }
rpcs2 = rpcs2 | CS2_NEM; /* set error */
break; }
if (comp != rpxb[wc]) { /* compare wd */
rpcs2 = rpcs2 | CS2_WCE; /* set error */
break; }
rpcs2 = rpcs2 | CS2_WCE; /* set error */
break; }
if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; }
} /* end else wchk */
@@ -968,11 +969,11 @@ case FNC_READH: /* read headers */
rpdc = da / drv_tab[dtype].surf;
if (err != 0) { /* error? */
rper1[drv] = rper1[drv] | ER1_PAR; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
perror ("RP I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
rper1[drv] = rper1[drv] | ER1_PAR; /* set drive error */
update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */
perror ("RP I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
case FNC_WRITEH: /* write headers stub */
update_rpcs (CS1_DONE, drv); /* set done */
break; } /* end case func */
@@ -1046,7 +1047,7 @@ for (i = 0; i < RP_NUMDR; i++) {
sim_cancel (uptr);
uptr->CYL = uptr->FUNC = 0;
if (uptr->flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) |
DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);
DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0);
else if (uptr->flags & UNIT_DIS) rpds[i] = 0;
else rpds[i] = DS_DPR;
rper1[i] = 0; }
@@ -1076,7 +1077,7 @@ if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK;
if ((p = ftell (uptr->fileref)) == 0) {
if (uptr->flags & UNIT_RO) return SCPE_OK;
return pdp11_bad_block (uptr,
drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD); }
drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD); }
for (i = 0; drv_tab[i].sect != 0; i++) {
if (p <= (drv_tab[i].size * (int) sizeof (int16))) {
uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
@@ -1098,7 +1099,7 @@ if (sim_is_active (uptr)) { /* unit active? */
sim_cancel (uptr); /* cancel operation */
rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */
if (uptr->FUNC >= FNC_WCHK) /* data transfer? */
rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; } /* set done, err */
rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; } /* set done, err */
update_rpcs (CS1_SC, drv); /* request intr */
return detach_unit (uptr);
}

View File

@@ -1359,7 +1359,7 @@ if (uptr = rq_getucb (cp, lu)) { /* unit exist? */
return OK; } } /* done */
else sts = ST_OFL; /* offline */
cp->pak[pkt].d[RW_BCL] = cp->pak[pkt].d[RW_BCH] = 0; /* bad packet */
rq_putr (cp, pkt, cmd | OP_END, 0, sts, RW_LNT, UQ_TYP_SEQ);
rq_putr (cp, pkt, cmd | OP_END, 0, sts, RW_LNT_D, UQ_TYP_SEQ);
return rq_putpkt (cp, pkt, TRUE);
}
@@ -1517,7 +1517,7 @@ cp->pak[pkt].d[RW_WBCL] = 0;
cp->pak[pkt].d[RW_WBCH] = 0;
cp->pak[pkt].d[RW_WBLL] = 0;
cp->pak[pkt].d[RW_WBLH] = 0;
rq_putr (cp, pkt, cmd | OP_END, flg, sts, RW_LNT, UQ_TYP_SEQ); /* fill pkt */
rq_putr (cp, pkt, cmd | OP_END, flg, sts, RW_LNT_D, UQ_TYP_SEQ); /* fill pkt */
if (!rq_putpkt (cp, pkt, TRUE)) return ERR; /* send pkt */
if (uptr->pktq) /* more to do? */
sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate thread */

View File

@@ -205,8 +205,8 @@ case 0: /* RXCS */
break;
case 1: /* RXDB */
if ((rx_state == EMPTY) && (rx_csr & RXCS_TR)) {/* empty? */
sim_activate (&rx_unit[0], rx_xwait);
rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */
sim_activate (&rx_unit[0], rx_xwait);
rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */
*data = rx_dbr; /* return data */
break; } /* end switch PA */
return SCPE_OK;
@@ -230,36 +230,36 @@ switch ((PA >> 1) & 1) { /* decode PA<1> */
case 0: /* RXCS */
rx_csr = rx_csr & RXCS_IMP; /* clear junk */
if (access == WRITEB) data = (PA & 1)? /* write byte? */
(rx_csr & 0377) | (data << 8): (rx_csr & ~0377) | data;
(rx_csr & 0377) | (data << 8): (rx_csr & ~0377) | data;
if (data & RXCS_INIT) { /* initialize? */
rx_reset (&rx_dev); /* reset device */
return SCPE_OK; } /* end if init */
rx_reset (&rx_dev); /* reset device */
return SCPE_OK; } /* end if init */
if ((data & CSR_GO) && (rx_state == IDLE)) { /* new function? */
rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC);
drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */
bptr = 0; /* clear buf pointer */
switch (RXCS_GETFNC (data)) { /* case on func */
case RXCS_FILL:
rx_state = FILL; /* state = fill */
rx_csr = rx_csr | RXCS_TR; /* xfer is ready */
break;
case RXCS_EMPTY:
rx_state = EMPTY; /* state = empty */
sim_activate (&rx_unit[drv], rx_xwait);
break;
case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
rx_state = RWDS; /* state = get sector */
rx_csr = rx_csr | RXCS_TR; /* xfer is ready */
rx_esr = rx_esr & RXES_ID; /* clear errors */
break;
default:
rx_state = CMD_COMPLETE; /* state = cmd compl */
sim_activate (&rx_unit[drv], rx_cwait);
break; } /* end switch func */
return SCPE_OK; } /* end if GO */
rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC);
drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */
bptr = 0; /* clear buf pointer */
switch (RXCS_GETFNC (data)) { /* case on func */
case RXCS_FILL:
rx_state = FILL; /* state = fill */
rx_csr = rx_csr | RXCS_TR; /* xfer is ready */
break;
case RXCS_EMPTY:
rx_state = EMPTY; /* state = empty */
sim_activate (&rx_unit[drv], rx_xwait);
break;
case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
rx_state = RWDS; /* state = get sector */
rx_csr = rx_csr | RXCS_TR; /* xfer is ready */
rx_esr = rx_esr & RXES_ID; /* clear errors */
break;
default:
rx_state = CMD_COMPLETE; /* state = cmd compl */
sim_activate (&rx_unit[drv], rx_cwait);
break; } /* end switch func */
return SCPE_OK; } /* end if GO */
if ((data & RXCS_IE) == 0) CLR_INT (RX);
else if ((rx_csr & (RXCS_DONE + RXCS_IE)) == RXCS_DONE)
SET_INT (RX);
SET_INT (RX);
rx_csr = (rx_csr & ~RXCS_RW) | (data & RXCS_RW);
break; /* end case RXCS */
@@ -270,12 +270,12 @@ case 0: /* RXCS */
case 1: /* RXDB */
if ((PA & 1) || ((rx_state != IDLE) && ((rx_csr & RXCS_TR) == 0)))
return SCPE_OK; /* if ~IDLE, need tr */
return SCPE_OK; /* if ~IDLE, need tr */
rx_dbr = data & 0377; /* save data */
if ((rx_state != IDLE) && (rx_state != EMPTY)) {
drv = ((rx_csr & RXCS_DRV)? 1: 0); /* select drive */
sim_activate (&rx_unit[drv], rx_xwait); /* sched event */
rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */
drv = ((rx_csr & RXCS_DRV)? 1: 0); /* select drive */
sim_activate (&rx_unit[drv], rx_xwait); /* sched event */
rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */
break; /* end case RXDB */
} /* end switch PA */
return SCPE_OK;
@@ -311,9 +311,10 @@ case IDLE: /* idle */
case EMPTY: /* empty buffer */
if (bptr >= RX_NUMBY) rx_done (0, 0); /* done all? */
else { rx_dbr = rx_buf[bptr]; /* get next */
bptr = bptr + 1;
rx_csr = rx_csr | RXCS_TR; } /* set xfer */
else {
rx_dbr = rx_buf[bptr]; /* get next */
bptr = bptr + 1;
rx_csr = rx_csr | RXCS_TR; } /* set xfer */
break;
case FILL: /* fill buffer */
@@ -336,34 +337,35 @@ case RWDT: /* wait for track */
return SCPE_OK;
case RWXFR:
if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
rx_done (0, 0110); /* done, error */
return IORETURN (rx_stopioe, SCPE_UNATT); }
rx_done (0, 0110); /* done, error */
return IORETURN (rx_stopioe, SCPE_UNATT); }
if (rx_track >= RX_NUMTR) { /* bad track? */
rx_done (0, 0040); /* done, error */
break; }
rx_done (0, 0040); /* done, error */
break; }
uptr->TRACK = rx_track; /* now on track */
if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */
rx_done (0, 0070); /* done, error */
break; }
rx_done (0, 0070); /* done, error */
break; }
da = CALC_DA (rx_track, rx_sector); /* get disk address */
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
if (func == RXCS_READ) { /* read? */
for (i = 0; i < RX_NUMBY; i++)
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); }
else { if (uptr->flags & UNIT_WPRT) { /* write and locked? */
rx_done (RXES_WLK, 0100); /* done, error */
break; }
for (i = 0; i < RX_NUMBY; i++) /* write */
*(((int8 *) uptr->filebuf) + da + i) = rx_buf[i];
da = da + RX_NUMBY;
if (da > uptr->hwmark) uptr->hwmark = da; }
for (i = 0; i < RX_NUMBY; i++)
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); }
else {
if (uptr->flags & UNIT_WPRT) { /* write and locked? */
rx_done (RXES_WLK, 0100); /* done, error */
break; }
for (i = 0; i < RX_NUMBY; i++) /* write */
*(((int8 *) uptr->filebuf) + da + i) = rx_buf[i];
da = da + RX_NUMBY;
if (da > uptr->hwmark) uptr->hwmark = da; }
rx_done (0, 0); /* done */
break;
case CMD_COMPLETE: /* command complete */
if (func == RXCS_ECODE) { /* read ecode? */
rx_dbr = rx_ecode; /* set dbr */
rx_done (0, -1); } /* don't update */
rx_dbr = rx_ecode; /* set dbr */
rx_done (0, -1); } /* don't update */
else rx_done (0, 0);
break;
@@ -371,11 +373,11 @@ case INIT_COMPLETE: /* init complete */
rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */
rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */
if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */
rx_done (RXES_ID, 0010); /* init done, error */
break; }
rx_done (RXES_ID, 0010); /* init done, error */
break; }
da = CALC_DA (1, 1); /* track 1, sector 1 */
for (i = 0; i < RX_NUMBY; i++) /* read sector */
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i);
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i);
rx_done (RXES_ID, 0); /* set done */
if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;
break; } /* end case state */

View File

@@ -26,6 +26,7 @@
tti,tto DL11 terminal input/output
clk KW11L line frequency clock
22-Nov-02 RMS Changed terminal default to 7B for UNIX
01-Nov-02 RMS Added 7B/8B support to terminal
29-Sep-02 RMS Added vector display support
Split out paper tape
@@ -93,7 +94,7 @@ t_stat clk_reset (DEVICE *dptr);
DIB tti_dib = { IOBA_TTI, IOLN_TTI, &tti_rd, &tti_wr,
1, IVCL (TTI), VEC_TTI, { NULL } };
UNIT tti_unit = { UDATA (&tti_svc, UNIT_8B, 0), KBD_POLL_WAIT };
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
REG tti_reg[] = {
{ ORDATA (BUF, tti_unit.buf, 8) },
@@ -132,7 +133,7 @@ DEVICE tti_dev = {
DIB tto_dib = { IOBA_TTO, IOLN_TTO, &tto_rd, &tto_wr,
1, IVCL (TTO), VEC_TTO, { NULL } };
UNIT tto_unit = { UDATA (&tto_svc, UNIT_8B, 0), SERIAL_OUT_WAIT };
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, 8) },
@@ -219,7 +220,7 @@ case 00: /* tti csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0) CLR_INT (TTI);
else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
SET_INT (TTI);
SET_INT (TTI);
tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW);
return SCPE_OK;
case 01: /* tti buf */
@@ -235,7 +236,8 @@ int32 c;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177);
if (c & SCPE_BREAK) tti_unit.buf = 0; /* break? */
else tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177);
tti_unit.pos = tti_unit.pos + 1;
tti_csr = tti_csr | CSR_DONE;
if (tti_csr & CSR_IE) SET_INT (TTI);
@@ -274,7 +276,7 @@ case 00: /* tto csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0) CLR_INT (TTO);
else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
SET_INT (TTO);
SET_INT (TTO);
tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW);
return SCPE_OK;
case 01: /* tto buf */

View File

@@ -1,6 +1,6 @@
/* pdp11_sys.c: PDP-11 simulator interface
Copyright (c) 1993-2002, Robert M Supnik
Copyright (c) 1993-2003, 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.
09-Jan-03 RMS Added DELUA support
17-Oct-02 RMS Fixed bugs in branch, SOB address parsing
09-Oct-02 RMS Added DELQA support
12-Sep-02 RMS Added TMSCP, KW11P, RX211 support, RAD50 examine
@@ -61,7 +62,7 @@ extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
extern DEVICE dt_dev;
extern DEVICE tm_dev, ts_dev;
extern DEVICE tq_dev;
extern DEVICE xq_dev;
extern DEVICE xq_dev, xu_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint16 *M;
@@ -108,6 +109,7 @@ DEVICE *sim_devices[] = {
&ts_dev,
&tq_dev,
&xq_dev,
&xu_dev,
NULL };
const char *sim_stop_messages[] = {

View File

@@ -400,7 +400,7 @@ case 003: /* TCBA */
case 004: /* TCDT */
fnc = DTS_GETFNC (dt_unit[unum].STATE); /* get function */
if (fnc == FNC_RALL) { /* read all? */
DT_CLRDONE; } /* clear done */
DT_CLRDONE; } /* clear done */
*data = tcdt;
break; }
return SCPE_OK;
@@ -420,34 +420,34 @@ case 000: /* TCST */
case 001: /* TCCM */
old_tccm = tccm; /* save prior */
if (access == WRITEB) data = (PA & 1)?
(tccm & 0377) | (data << 8): (tccm & ~0377) | data;
(tccm & 0377) | (data << 8): (tccm & ~0377) | data;
if ((data & CSR_IE) == 0) CLR_INT (DTA);
else if ((((tccm & CSR_IE) == 0) && (tccm & CSR_DONE)) ||
(data & CSR_DONE)) SET_INT (DTA);
(data & CSR_DONE)) SET_INT (DTA);
tccm = (tccm & ~CSR_RW) | (data & CSR_RW);
if ((data & CSR_GO) && (tccm & CSR_DONE)) { /* new cmd? */
tcst = tcst & ~STA_ALLERR; /* clear errors */
tccm = tccm & ~(CSR_ERR | CSR_DONE); /* clear done, err */
CLR_INT (DTA); /* clear int */
if ((old_tccm ^ tccm) & CSR_UNIT) dt_deselect (old_tccm);
unum = CSR_GETUNIT (tccm); /* get drive */
fnc = CSR_GETFNC (tccm); /* get function */
if (fnc == FNC_STOP) { /* stop all? */
sim_activate (&dt_dev.units[DT_TIMER], dt_ctime);
for (i = 0; i < DT_NUMDR; i++)
dt_stopunit (dt_dev.units + i); /* stop unit */
break; }
uptr = dt_dev.units + unum;
if (uptr->flags & UNIT_DIS) /* disabled? */
dt_seterr (uptr, STA_SEL); /* select err */
if ((fnc == FNC_WMRK) || /* write mark? */
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
dt_seterr (uptr, STA_ILO); /* illegal op */
if (!(tccm & CSR_ERR)) dt_newsa (tccm); }
tcst = tcst & ~STA_ALLERR; /* clear errors */
tccm = tccm & ~(CSR_ERR | CSR_DONE); /* clear done, err */
CLR_INT (DTA); /* clear int */
if ((old_tccm ^ tccm) & CSR_UNIT) dt_deselect (old_tccm);
unum = CSR_GETUNIT (tccm); /* get drive */
fnc = CSR_GETFNC (tccm); /* get function */
if (fnc == FNC_STOP) { /* stop all? */
sim_activate (&dt_dev.units[DT_TIMER], dt_ctime);
for (i = 0; i < DT_NUMDR; i++)
dt_stopunit (dt_dev.units + i); /* stop unit */
break; }
uptr = dt_dev.units + unum;
if (uptr->flags & UNIT_DIS) /* disabled? */
dt_seterr (uptr, STA_SEL); /* select err */
if ((fnc == FNC_WMRK) || /* write mark? */
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
dt_seterr (uptr, STA_ILO); /* illegal op */
if (!(tccm & CSR_ERR)) dt_newsa (tccm); }
else if ((tccm & CSR_ERR) == 0) { /* clear err? */
tcst = tcst & ~STA_RWERR;
if (tcst & STA_ALLERR) tccm = tccm | CSR_ERR; }
tcst = tcst & ~STA_RWERR;
if (tcst & STA_ALLERR) tccm = tccm | CSR_ERR; }
break;
case 002: /* TCWC */
tcwc = data; /* word write only! */
@@ -459,7 +459,7 @@ case 004: /* TCDT */
unum = CSR_GETUNIT (tccm); /* get drive */
fnc = DTS_GETFNC (dt_unit[unum].STATE); /* get function */
if (fnc == FNC_WALL) { /* write all? */
DT_CLRDONE; } /* clear done */
DT_CLRDONE; } /* clear done */
tcdt = data; /* word write only! */
break; }
return SCPE_OK;
@@ -587,49 +587,50 @@ case DTS_OFR: /* off reel */
break;
case FNC_SRCH: /* search */
if (dir) newpos = DT_BLK2LN ((DT_QFEZ (uptr)?
DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE;
DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE;
else newpos = DT_BLK2LN ((DT_QREZ (uptr)?
0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1);
0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1);
if (DBG_LOG (LOG_TC_MS)) fprintf (sim_log, ">>DT%d: searching %s\n",
unum, (dir? "backward": "forward"));
unum, (dir? "backward": "forward"));
break;
case FNC_WRIT: /* write */
case FNC_READ: /* read */
if (DT_QEZ (uptr)) { /* in "ok" end zone? */
if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE;
else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1);
break; }
if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE;
else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1);
break; }
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
dt_seterr (uptr, STA_BLKM);
return; }
dt_seterr (uptr, STA_BLKM);
return; }
if (dir) newpos = DT_BLK2LN (((relpos >= (DTU_LPERB (uptr) - DT_HTLIN))?
blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE;
blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE;
else newpos = DT_BLK2LN (((relpos < DT_HTLIN)?
blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1);
blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1);
if (DBG_LOG (LOG_TC_RW) || (DBG_LOG (LOG_TC_BL) && (blk == dt_logblk)))
fprintf (sim_log, ">>DT%d: %s block %d %s\n",
unum, ((fnc == FNC_READ)? "read": "write"),
blk, (dir? "backward": "forward"));
fprintf (sim_log, ">>DT%d: %s block %d %s\n",
unum, ((fnc == FNC_READ)? "read": "write"),
blk, (dir? "backward": "forward"));
break;
case FNC_RALL: /* read all */
case FNC_WALL: /* write all */
if (DT_QEZ (uptr)) { /* in "ok" end zone? */
if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE;
else newpos = DT_EZLIN + (DT_WSIZE - 1); }
else { relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if (dir? (relpos < (DTU_LPERB (uptr) - DT_CSMLN)): /* switch in time? */
(relpos >= DT_CSMLN)) {
dt_seterr (uptr, STA_BLKM);
return; }
if (dir) newpos = DT_BLK2LN (blk + 1, uptr) - DT_CSMLN - DT_WSIZE;
else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); }
if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE;
else newpos = DT_EZLIN + (DT_WSIZE - 1); }
else {
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if (dir? (relpos < (DTU_LPERB (uptr) - DT_CSMLN)): /* switch in time? */
(relpos >= DT_CSMLN)) {
dt_seterr (uptr, STA_BLKM);
return; }
if (dir) newpos = DT_BLK2LN (blk + 1, uptr) - DT_CSMLN - DT_WSIZE;
else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); }
if (fnc == FNC_WALL) sim_activate /* write all? */
(&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */
(&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */
if (DBG_LOG (LOG_TC_RW) || (DBG_LOG (LOG_TC_BL) && (blk == dt_logblk)))
fprintf (sim_log, ">>DT%d: read all block %d %s\n",
unum, blk, (dir? "backward": "forward"));
fprintf (sim_log, ">>DT%d: read all block %d %s\n",
unum, blk, (dir? "backward": "forward"));
break;
default:
dt_seterr (uptr, STA_SEL); /* bad state */
@@ -689,7 +690,7 @@ if (((int32) uptr->pos < 0) ||
uptr->STATE = uptr->pos = 0;
unum = uptr - dt_dev.units;
if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP))
dt_seterr (uptr, STA_SEL); /* error */
dt_seterr (uptr, STA_SEL); /* error */
return TRUE; }
return FALSE;
}
@@ -728,7 +729,7 @@ case DTS_DECF: case DTS_DECR: /* decelerating */
if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
if (uptr->STATE) /* not stopped? */
sim_activate (uptr, dt_actime); /* must be reversing */
sim_activate (uptr, dt_actime); /* must be reversing */
return SCPE_OK;
case DTS_ACCF: case DTS_ACCR: /* accelerating */
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
@@ -774,24 +775,24 @@ case DTS_OFR: /* off reel */
case FNC_READ: /* read */
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
if (!dt_substate) { /* !wc ovf? */
tcwc = tcwc & DMASK; /* incr MA, WC */
tcba = tcba & DMASK;
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (!Map_Addr (ma, &mma) || /* map addr */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM);
break; }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
M[mma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm);
if (tcwc == 0) dt_substate = 1; }
tcwc = tcwc & DMASK; /* incr MA, WC */
tcba = tcba & DMASK;
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (!Map_Addr (ma, &mma) || /* map addr */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM);
break; }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
M[mma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm);
if (tcwc == 0) dt_substate = 1; }
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */
sim_activate (uptr, DT_WSIZE * dt_ltime);
sim_activate (uptr, DT_WSIZE * dt_ltime);
else if (dt_substate) { /* wc ovf? */
dt_schedez (uptr, dir); /* sched end zone */
DT_SETDONE; } /* set done */
dt_schedez (uptr, dir); /* sched end zone */
DT_SETDONE; } /* set done */
else sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime);
break;
@@ -808,24 +809,25 @@ case FNC_READ: /* read */
case FNC_WRIT: /* write */
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
if (dt_substate) tcdt = 0; /* wc ovf? fill */
else { ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (!Map_Addr (ma, &mma) || /* map addr */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM);
break; }
else tcdt = M[mma >> 1]; /* get word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm); }
else {
ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */
if (!Map_Addr (ma, &mma) || /* map addr */
!ADDR_IS_MEM (mma)) { /* nx mem? */
dt_seterr (uptr, STA_NXM);
break; }
else tcdt = M[mma >> 1]; /* get word */
tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */
tcba = (tcba + 2) & DMASK;
if (tcba <= 1) tccm = CSR_INCMEX (tccm); }
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
bptr[ba] = tcdt; /* write word */
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (tcwc == 0) dt_substate = 1;
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */
sim_activate (uptr, DT_WSIZE * dt_ltime);
sim_activate (uptr, DT_WSIZE * dt_ltime);
else if (dt_substate) { /* wc ovf? */
dt_schedez (uptr, dir); /* sched end zone */
DT_SETDONE; }
dt_schedez (uptr, dir); /* sched end zone */
DT_SETDONE; }
else sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime);
break;
@@ -833,14 +835,14 @@ case FNC_WRIT: /* write */
case FNC_RALL:
if (tccm & CSR_DONE) { /* done set? */
dt_seterr (uptr, STA_DATM); /* data miss */
break; }
dt_seterr (uptr, STA_DATM); /* data miss */
break; }
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dat = bptr[ba]; } /* get tape word */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
dat = bptr[ba]; } /* get tape word */
else dat = dt_gethdr (uptr, blk, relpos); /* get hdr */
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
tcdt = dat & DMASK; /* low 16b */
@@ -853,17 +855,17 @@ case FNC_RALL:
case FNC_WALL:
if (tccm & CSR_DONE) { /* done set? */
dt_seterr (uptr, STA_DATM); /* data miss */
break; }
dt_seterr (uptr, STA_DATM); /* data miss */
break; }
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
dat = (STA_GETXD (tcst) << 16) | tcdt; /* get data word */
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
bptr[ba] = dat; /* write word */
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; }
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr->pos, uptr);
dat = (STA_GETXD (tcst) << 16) | tcdt; /* get data word */
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */
bptr[ba] = dat; /* write word */
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; }
/* else /* ignore hdr */
sim_activate (uptr, DT_WSIZE * dt_ltime);
DT_SETDONE; /* set done */
@@ -972,16 +974,17 @@ UNIT *uptr;
for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */
uptr = dt_dev.units + i;
if (sim_is_running) { /* RESET? */
prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */
if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */
if (dt_setpos (uptr)) continue; /* update pos */
sim_cancel (uptr);
sim_activate (uptr, dt_dctime); /* sched decel */
DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
} }
else { sim_cancel (uptr); /* sim reset */
uptr->STATE = 0;
uptr->LASTT = sim_grtime (); } }
prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */
if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */
if (dt_setpos (uptr)) continue; /* update pos */
sim_cancel (uptr);
sim_activate (uptr, dt_dctime); /* sched decel */
DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
} }
else {
sim_cancel (uptr); /* sim reset */
uptr->STATE = 0;
uptr->LASTT = sim_grtime (); } }
tcst = tcwc = tcba = tcdt = 0; /* clear reg */
tccm = CSR_DONE;
CLR_INT (DTA); /* clear int req */
@@ -1077,7 +1080,7 @@ else if (!(sim_switches & SWMASK ('S')) && /* autosize? */
(fseek (uptr->fileref, 0, SEEK_END) == 0) &&
((p = ftell (uptr->fileref)) > D16_FILSIZ)) {
if (p <= D8_FILSIZ)
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
else uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); }
uptr->capac = DTU_CAPAC (uptr); /* set capacity */
uptr->filebuf = calloc (uptr->capac, sizeof (int32));

View File

@@ -284,29 +284,30 @@ case 0: /* MTS: read only */
case 1: /* MTC */
uptr = tm_dev.units + GET_UNIT (tm_cmd); /* select unit */
if ((tm_cmd & MTC_DONE) == 0) tm_sta = tm_sta | STA_ILL;
else { if (access == WRITEB) data = (PA & 1)?
(tm_cmd & 0377) | (data << 8):
(tm_cmd & ~0377) | data;
if (data & MTC_INIT) { /* init? */
tm_reset (&tm_dev); /* reset device */
return SCPE_OK; }
if ((data & MTC_IE) == 0) /* int disable? */
CLR_INT (TM); /* clr int request */
else if ((tm_cmd & (MTC_ERR + MTC_DONE)) && !(tm_cmd & MTC_IE))
SET_INT (TM); /* set int request */
tm_cmd = (tm_cmd & ~MTC_RW) | (data & MTC_RW);
uptr = tm_dev.units + GET_UNIT (tm_cmd); /* new unit */
if (data & MTC_GO) tm_go (uptr); } /* new function? */
else {
if (access == WRITEB) data = (PA & 1)?
(tm_cmd & 0377) | (data << 8):
(tm_cmd & ~0377) | data;
if (data & MTC_INIT) { /* init? */
tm_reset (&tm_dev); /* reset device */
return SCPE_OK; }
if ((data & MTC_IE) == 0) /* int disable? */
CLR_INT (TM); /* clr int request */
else if ((tm_cmd & (MTC_ERR + MTC_DONE)) && !(tm_cmd & MTC_IE))
SET_INT (TM); /* set int request */
tm_cmd = (tm_cmd & ~MTC_RW) | (data & MTC_RW);
uptr = tm_dev.units + GET_UNIT (tm_cmd); /* new unit */
if (data & MTC_GO) tm_go (uptr); } /* new function? */
tm_updcsta (uptr); /* update status */
break;
case 2: /* MTBRC */
if (access == WRITEB) data = (PA & 1)?
(tm_bc & 0377) | (data << 8): (tm_bc & ~0377) | data;
(tm_bc & 0377) | (data << 8): (tm_bc & ~0377) | data;
tm_bc = data;
break;
case 3: /* MTCMA */
if (access == WRITEB) data = (PA & 1)?
(tm_ca & 0377) | (data << 8): (tm_ca & ~0377) | data;
(tm_ca & 0377) | (data << 8): (tm_ca & ~0377) | data;
tm_ca = data;
break;
case 4: /* MTD */
@@ -363,12 +364,12 @@ MT_CLR_PNU (uptr); /* and clear */
if (uptr->USTAT & STA_REW) { /* rewind? */
uptr->pos = 0; /* update position */
if (uptr->flags & UNIT_ATT) /* still on line? */
uptr->USTAT = STA_ONL | STA_BOT |
((uptr->flags & UNIT_WPRT)? STA_WLK: 0);
uptr->USTAT = STA_ONL | STA_BOT |
((uptr->flags & UNIT_WPRT)? STA_WLK: 0);
else uptr->USTAT = 0;
if (u == GET_UNIT (tm_cmd)) { /* selected? */
tm_set_done (); /* set done */
tm_updcsta (uptr); } /* update status */
tm_set_done (); /* set done */
tm_updcsta (uptr); } /* update status */
return SCPE_OK; }
if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */
@@ -400,34 +401,35 @@ case MTC_READ: /* read */
if (tbc < cbc) cbc = tbc; /* use smaller */
abc = fxread (tmxb, sizeof (int8), cbc, uptr->fileref);
if (err = ferror (uptr->fileref)) { /* error? */
MT_SET_PNU (uptr); /* pos not upd */
break; }
MT_SET_PNU (uptr); /* pos not upd */
break; }
for ( ; abc < cbc; abc++) tmxb[abc] = 0; /* fill with 0's */
if (t = Map_WriteB (xma, cbc, tmxb, MAP)) { /* copy buf to mem */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; } /* adj byte cnt */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; } /* adj byte cnt */
xma = (xma + cbc) & 0777777; /* inc bus addr */
tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* upd position */
(2 * sizeof (t_mtrlnt));
(2 * sizeof (t_mtrlnt));
break;
case MTC_WRITE: /* write */
case MTC_WREXT: /* write ext gap */
if (t = Map_ReadB (xma, cbc, tmxb, MAP)) { /* copy mem to buf */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; /* adj byte cnt */
if (cbc == 0) break; } /* no xfr? done */
tm_sta = tm_sta | STA_NXM; /* NXM, set err */
cbc = cbc - t; /* adj byte cnt */
if (cbc == 0) break; } /* no xfr? done */
ebc = (cbc + 1) & ~1; /* force even */
fseek (uptr->fileref, uptr->pos, SEEK_SET);
fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr->fileref);
fxwrite (tmxb, sizeof (int8), ebc, uptr->fileref);
fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr->fileref);
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */
else { xma = (xma + cbc) & 0777777; /* inc bus addr */
tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */
uptr->pos = uptr->pos + ebc + /* upd pos */
(2 * sizeof (t_mtrlnt)); }
else {
xma = (xma + cbc) & 0777777; /* inc bus addr */
tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */
uptr->pos = uptr->pos + ebc + /* upd pos */
(2 * sizeof (t_mtrlnt)); }
break;
/* Unit service, continued */
@@ -440,19 +442,22 @@ case MTC_WREOF:
break;
case MTC_SPACEF: /* space forward */
do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */
if (tm_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
do {
tm_bc = (tm_bc + 1) & 0177777; /* incr wc */
if (tm_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
while (tm_bc != 0);
break;
case MTC_SPACER: /* space reverse */
do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */
if (pnu) pnu = 0; /* pos not upd? */
else { if (tm_rdlntr (uptr, &tbc, &err)) break;
uptr->pos = uptr->pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt)); } }
do {
tm_bc = (tm_bc + 1) & 0177777; /* incr wc */
if (pnu) pnu = 0; /* pos not upd? */
else {
if (tm_rdlntr (uptr, &tbc, &err)) break;
uptr->pos = uptr->pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt)); } }
while (tm_bc != 0);
break; } /* end case */

View File

@@ -1,6 +1,6 @@
/* pdp11_tq.c: TQK50 tape controller simulator
Copyright (c) 2002, Robert M Supnik
Copyright (c) 2002-2003, 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 @@
tq TQK50 tape controller
09-Jan-03 RMS Fixed bug in transfer end packet status
17-Oct-02 RMS Fixed bug in read reverse (found by Hans Pufal)
*/
@@ -548,7 +549,8 @@ if (tq_pip) { /* polling? */
tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL],
tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]);
if (up) fprintf (sim_log, ", pos=%d, obj=%d\n", up->pos, up->objp);
else fprintf (sim_log, "\n"); }
else fprintf (sim_log, "\n");
fflush (sim_log); }
if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */
return tq_fatal (PE_PIE); /* no, term thread */
cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */
@@ -946,7 +948,7 @@ else sts = ST_OFL; /* offline */
PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */
PUTP32 (pkt, RW_POSL, objp); /* set obj pos */
PUTP32 (pkt, RW_RSZL, 0); /* clr rec size */
tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT, UQ_TYP_SEQ);
tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT_T, UQ_TYP_SEQ);
return tq_putpkt (pkt, TRUE);
}
@@ -1139,7 +1141,7 @@ t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz)
{
int32 pkt = uptr->cpkt; /* packet */
uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */
uint32 lnt = RW_LNT; /* assume rw */
uint32 lnt = RW_LNT_T; /* assume rw */
if (cmd == OP_ERG) lnt = ERG_LNT; /* set pkt lnt */
else if (cmd == OP_ERS) lnt = ERS_LNT;
@@ -1148,8 +1150,7 @@ else if (cmd == OP_POS) lnt = POS_LNT;
uptr->cpkt = 0; /* done */
if (lnt > ERG_LNT) { /* xfer cmd? */
PUTP32 (pkt, RW_POSL, uptr->objp); } /* position */
if (lnt > POS_LNT) { /* read or write? */
PUTP32 (pkt, RW_POSL, uptr->objp); /* position */
PUTP32 (pkt, RW_RSZL, rsiz); } /* record size */
tq_putr (pkt, cmd | OP_END, flg | tq_efl (uptr), sts, lnt, UQ_TYP_SEQ);
if (!tq_putpkt (pkt, TRUE)) return ERR; /* send pkt */
@@ -1495,7 +1496,8 @@ if (DBG_LOG (LOG_TQ)) {
fprintf (sim_log, ">>TQ: rsp=%04X, sts=%04X",
tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]);
if (up) fprintf (sim_log, ", pos=%d, obj=%d\n", up->pos, up->objp);
else fprintf (sim_log, "\n"); }
else fprintf (sim_log, "\n");
fflush (sim_log); }
if (!tq_getdesc (&tq_rq, &desc)) return ERR; /* get rsp desc */
if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */
if (qt) tq_enqt (&tq_rspq, pkt); /* normal? q tail */

View File

@@ -383,8 +383,8 @@ t_addr pa;
switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TSDB */
if ((tssr & TSSR_SSR) == 0) { /* ready? */
tssr = tssr | TSSR_RMR; /* no, refuse */
break; }
tssr = tssr | TSSR_RMR; /* no, refuse */
break; }
tsba = ((tsdbx & TSDBX_M_XA) << 18) | /* form pkt addr */
((data & 03) << 16) | (data & 0177774);
tsdbx = 0; /* clr tsdbx */
@@ -393,23 +393,24 @@ case 0: /* TSDB */
msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */
CLR_INT (TS); /* clr int req */
for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
tscmdp[i] = ReadW (pa);
else { ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);
return SCPE_OK; }
tsba = tsba + 2; } /* incr tsba */
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
tscmdp[i] = ReadW (pa);
else {
ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);
return SCPE_OK; }
tsba = tsba + 2; } /* incr tsba */
ts_ownc = ts_ownm = 1; /* tape owns all */
sim_activate (&ts_unit, ts_time); /* activate */
break;
case 1: /* TSSR */
if (PA & 1) { /* TSDBX */
if (UNIBUS) return SCPE_OK; /* not in TS11 */
if (tssr & TSSR_SSR) { /* ready? */
tsdbx = data; /* save */
if (data & TSDBX_BOOT) {
ts_bcmd = 1;
sim_activate (&ts_unit, ts_time); } }
else tssr = tssr | TSSR_RMR; } /* no, err */
if (UNIBUS) return SCPE_OK; /* not in TS11 */
if (tssr & TSSR_SSR) { /* ready? */
tsdbx = data; /* save */
if (data & TSDBX_BOOT) {
ts_bcmd = 1;
sim_activate (&ts_unit, ts_time); } }
else tssr = tssr | TSSR_RMR; } /* no, err */
else if (access == WRITE) ts_reset (&ts_dev); /* reset */
break; }
return SCPE_OK;
@@ -445,7 +446,7 @@ do { fc = (fc - 1) & DMASK; /* decr wc */
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
if (tbc == MTR_TMK) /* tape mark? */
return (XTC (XS0_TMK | XS0_RLS, TC2));
return (XTC (XS0_TMK | XS0_RLS, TC2));
uptr->pos = uptr->pos + ((MTRL (tbc) + 1) & ~1) + sizeof (t_mtrlnt);
}
while (fc != 0);
@@ -463,14 +464,15 @@ if ((uptr->pos == 0) && (wchopt & WCH_ENB)) tmkprv = TRUE;
do { prvp = uptr->pos; /* save cur pos */
tc = ts_spacef (uptr, 0, FALSE); /* space fwd */
if (GET_X (tc) & XS0_TMK) { /* tape mark? */
msgrfc = (msgrfc - 1) & DMASK; /* decr count */
if (tmkprv && (wchopt & WCH_ESS) &&
(uptr->pos - prvp == sizeof (t_mtrlnt)))
return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2));
tmkprv = TRUE; }
else { if (tc) return tc; /* other err? */
tmkprv = FALSE; } }
msgrfc = (msgrfc - 1) & DMASK; /* decr count */
if (tmkprv && (wchopt & WCH_ESS) &&
(uptr->pos - prvp == sizeof (t_mtrlnt)))
return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2));
tmkprv = TRUE; }
else {
if (tc) return tc; /* other err? */
tmkprv = FALSE; } }
while (msgrfc != 0);
return 0;
}
@@ -508,7 +510,7 @@ do { fc = (fc - 1) & DMASK; /* decr wc */
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
if (tbc == MTR_TMK) /* tape mark? */
return (XTC (XS0_TMK | XS0_RLS, TC2));
return (XTC (XS0_TMK | XS0_RLS, TC2));
uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - sizeof (t_mtrlnt);
}
while (fc != 0);
@@ -525,14 +527,15 @@ msgrfc = fc;
do { prvp = uptr->pos; /* save cur pos */
tc = ts_spacer (uptr, 0, FALSE); /* space rev */
if (GET_X (tc) & XS0_TMK) { /* tape mark? */
msgrfc = (msgrfc - 1) & DMASK; /* decr wc */
if (tmkprv && (wchopt & WCH_ESS) &&
(prvp - uptr->pos == sizeof (t_mtrlnt)))
return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2));
tmkprv = TRUE; }
else { if (tc) return tc; /* other err? */
tmkprv = FALSE; } }
msgrfc = (msgrfc - 1) & DMASK; /* decr wc */
if (tmkprv && (wchopt & WCH_ESS) &&
(prvp - uptr->pos == sizeof (t_mtrlnt)))
return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2));
tmkprv = TRUE; }
else {
if (tc) return tc; /* other err? */
tmkprv = FALSE; } }
while (msgrfc != 0);
return 0;
}
@@ -566,9 +569,10 @@ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
for (i = 0; i < wbc; i++) { /* copy buffer */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */
WriteB (pa, tsxb[i]); /* no, store */
else { tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); }
WriteB (pa, tsxb[i]); /* no, store */
else {
tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); }
tsba = tsba + 1;
msgrfc = (msgrfc - 1) & DMASK; }
if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */
@@ -607,9 +611,10 @@ for (i = wbc; i > 0; i--) { /* copy buffer */
tsba = tsba - 1;
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */
WriteB (pa, tsxb[i - 1]); /* no, store */
else { tssr = ts_updtssr (tssr | TSSR_NXM);
return (XTC (XS0_RLS, TC4)); }
WriteB (pa, tsxb[i - 1]); /* no, store */
else {
tssr = ts_updtssr (tssr | TSSR_NXM);
return (XTC (XS0_RLS, TC4)); }
msgrfc = (msgrfc - 1) & DMASK; }
if (msgrfc) return (XTC (XS0_RLS, TC2)); /* buf too big? */
if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */
@@ -628,8 +633,9 @@ for (i = 0; i < fc; i++) { /* copy mem to buf */
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */
tsxb[i] = ReadB (pa); /* no, store */
else { tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; }
else {
tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; }
tsba = tsba + 1; }
ebc = (fc + 1) & ~1; /* force even */
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */
@@ -679,10 +685,10 @@ if (ts_bcmd) { /* boot? */
ts_bcmd = 0; /* clear flag */
uptr->pos = 0; /* rewind */
if (uptr->flags & UNIT_ATT) { /* attached? */
cmdlnt = cmdadh = cmdadl = 0; /* defang rd */
ts_spacef (uptr, 1, FALSE); /* space fwd */
ts_readf (uptr, 512); /* read blk */
tssr = ts_updtssr (tssr | TSSR_SSR); }
cmdlnt = cmdadh = cmdadl = 0; /* defang rd */
ts_spacef (uptr, 1, FALSE); /* space fwd */
ts_readf (uptr, 512); /* read blk */
tssr = ts_updtssr (tssr | TSSR_SSR); }
else tssr = ts_updtssr (tssr | TSSR_SSR | TC3);
if (cmdhdr & CMD_IE) SET_INT (TS);
return SCPE_OK; }
@@ -696,7 +702,7 @@ fnc = GET_FNC (cmdhdr); /* get fnc+mode */
mod = GET_MOD (cmdhdr);
if (DBG_LOG (LOG_TS))
fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, pos=%d\n",
fnc, mod, cmdadl, cmdlnt, ts_unit.pos);
fnc, mod, cmdadl, cmdlnt, ts_unit.pos);
if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */
ts_endcmd (TC3, 0, 0); /* error */
return SCPE_OK; }
@@ -738,112 +744,116 @@ case FNC_GSTA: /* get status */
return SCPE_OK;
case FNC_WCHR: /* write char */
if ((cmdadh & ADDRTEST) || (cmdadl & 1) || (cmdlnt < 6)) {
ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0);
break; }
ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0);
break; }
tsba = (cmdadh << 16) | cmdadl;
for (i = 0; (i < WCH_PLNT) && (i < (cmdlnt / 2)); i++) {
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
tswchp[i] = ReadW (pa);
else { ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0);
return SCPE_OK; }
tsba = tsba + 2; }
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
tswchp[i] = ReadW (pa);
else {
ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0);
return SCPE_OK; }
tsba = tsba + 2; }
if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) ||
(wchadl & 1)) ts_endcmd (TSSR_NBA | TC3, 0, 0);
else { msgxs2 = msgxs2 | XS2_XTF | 1;
tssr = ts_updtssr (tssr & ~TSSR_NBA);
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); }
else {
msgxs2 = msgxs2 | XS2_XTF | 1;
tssr = ts_updtssr (tssr & ~TSSR_NBA);
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); }
return SCPE_OK;
case FNC_CTL: /* control */
switch (mod) { /* case mode */
case 00: /* msg buf rls */
tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */
if (wchopt & WCH_ERI) SET_INT (TS);
ts_ownc = 0; ts_ownm = 1; /* keep msg */
break;
tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */
if (wchopt & WCH_ERI) SET_INT (TS);
ts_ownc = 0; ts_ownm = 1; /* keep msg */
break;
case 01: /* rewind and unload */
if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */
detach_unit (uptr); /* unload */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND);
break;
if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */
detach_unit (uptr); /* unload */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND);
break;
case 02: /* clean */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */
break;
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */
break;
case 03: /* undefined */
ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL);
return SCPE_OK;
ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL);
return SCPE_OK;
case 04: /* rewind */
if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */
uptr->pos = 0;
ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND);
break; }
if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */
uptr->pos = 0;
ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND);
break; }
break;
case FNC_READ: /* read */
switch (mod) { /* case mode */
case 00: /* fwd */
st0 = ts_readf (uptr, cmdlnt); /* read */
break;
st0 = ts_readf (uptr, cmdlnt); /* read */
break;
case 01: /* back */
st0 = ts_readr (uptr, cmdlnt); /* read */
break;
st0 = ts_readr (uptr, cmdlnt); /* read */
break;
case 02: /* reread fwd */
if (cmdhdr & CMD_OPP) { /* opposite? */
st0 = ts_readr (uptr, cmdlnt);
st1 = ts_spacef (uptr, 1, FALSE); }
else { st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_readf (uptr, cmdlnt); }
break;
if (cmdhdr & CMD_OPP) { /* opposite? */
st0 = ts_readr (uptr, cmdlnt);
st1 = ts_spacef (uptr, 1, FALSE); }
else {
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_readf (uptr, cmdlnt); }
break;
case 03: /* reread back */
if (cmdhdr & CMD_OPP) { /* opposite */
st0 = ts_readf (uptr, cmdlnt);
st1 = ts_spacer (uptr, 1, FALSE); }
else { st0 = ts_spacef (uptr, 1, FALSE);
st1 = ts_readr (uptr, cmdlnt); }
break; }
if (cmdhdr & CMD_OPP) { /* opposite */
st0 = ts_readf (uptr, cmdlnt);
st1 = ts_spacer (uptr, 1, FALSE); }
else {
st0 = ts_spacef (uptr, 1, FALSE);
st1 = ts_readr (uptr, cmdlnt); }
break; }
ts_cmpendcmd (st0, st1);
break;
case FNC_WRIT: /* write */
switch (mod) { /* case mode */
case 00: /* write */
st0 = ts_write (uptr, cmdlnt);
break;
st0 = ts_write (uptr, cmdlnt);
break;
case 01: /* rewrite */
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_write (uptr, cmdlnt);
break; }
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_write (uptr, cmdlnt);
break; }
ts_cmpendcmd (st0, st1);
break;
case FNC_FMT: /* format */
switch (mod) { /* case mode */
case 00: /* write tmk */
st0 = ts_wtmk (uptr);
break;
st0 = ts_wtmk (uptr);
break;
case 01: /* erase */
break;
break;
case 02: /* retry tmk */
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_wtmk (uptr);
break; }
st0 = ts_spacer (uptr, 1, FALSE);
st1 = ts_wtmk (uptr);
break; }
ts_cmpendcmd (st0, st1);
break;
case FNC_POS:
switch (mod) { /* case mode */
case 00: /* space fwd */
st0 = ts_spacef (uptr, cmdadl, TRUE);
break;
st0 = ts_spacef (uptr, cmdadl, TRUE);
break;
case 01: /* space rev */
st0 = ts_spacer (uptr, cmdadl, TRUE);
break;
st0 = ts_spacer (uptr, cmdadl, TRUE);
break;
case 02: /* space ffwd */
st0 = ts_skipf (uptr, cmdadl);
break;
st0 = ts_skipf (uptr, cmdadl);
break;
case 03: /* space frev */
st0 = ts_skipr (uptr, cmdadl);
break;
st0 = ts_skipr (uptr, cmdadl);
break;
case 04: /* rewind */
if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */
uptr->pos = 0;
break; }
if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */
uptr->pos = 0;
break; }
ts_cmpendcmd (st0, 0);
break; }
return SCPE_OK;
@@ -901,18 +911,19 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */
msglnt = wchlnt - 4; /* exclude hdr, bc */
tsba = (wchadh << 16) | wchadl;
for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++) {
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
WriteW (pa, tsmsgp[i]);
else { tssr = tssr | TSSR_NXM;
tc = (tc & ~TSSR_TC) | TC4;
break; }
tsba = tsba + 2; } }
if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa))
WriteW (pa, tsmsgp[i]);
else {
tssr = tssr | TSSR_NXM;
tc = (tc & ~TSSR_TC) | TC4;
break; }
tsba = tsba + 2; } }
tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0));
if (cmdhdr & CMD_IE) SET_INT (TS);
ts_ownm = 0; ts_ownc = 0;
if (DBG_LOG (LOG_TS))
fprintf (sim_log, ">>TS: sta=%o, tc=%o, rfc=%d, pos=%d\n",
msgxs0, GET_TC (tssr), msgrfc, ts_unit.pos);
msgxs0, GET_TC (tssr), msgrfc, ts_unit.pos);
return;
}

View File

@@ -26,9 +26,11 @@
------------------------------------------------------------------------------
This DELQA/DEQNA simulation is based on:
This DEQNA/DELQA simulation is based on:
Digital DELQA Users Guide, Part# EK-DELQA-UG-002
Digital DEQNA Users Guide, Part# EK-DEQNA-UG-001
These manuals can be found online at:
http://www.spies.com/~aek/pdf/dec/qbus
Certain adaptations have been made because this is an emulation:
The default MAC address is 08-00-2B-AA-BB-CC unless set otherwise.
@@ -37,17 +39,85 @@
implemented more like an extended Internal Loopback
Time Domain Reflectometry (TDR) numbers are faked
The 10-second approx. hardware/software reset delay does not exist
Some physical ethernet receive events like Runts, Overruns, etc. are never
reported back, since the packet-level driver never sees them
Some physical ethernet receive events like Runts, Overruns, etc. are
never reported back, since the packet-level driver never sees them
Certain advantages are derived from this emulation:
If the real ethernet controller is faster than 10Mbit, the speed is
passed on since there are no minimum response times.
Known Bugs or Unsupported features:
1) DEQNA and DEQNA-LOCK modes not implemented fully [done! 07-Jan-03]
2) Sanity Timer not implemented [done! 16-Oct-02]
3) MOP functionality not implemented
4) Multicast support is weak [done! 22-Oct-02]
5) Promiscuous mode not implemented [done! 22-Oct-02]
6) Cannot VMScluster node [done! 27-Dec-02]
7) Cannot bootstrap module on VAX (>>> B XQA0) [done! 12-Oct-02]
8) PDP11 bootstrap code missing
9) Automatic ID broadcast every 8-10 minutes [done! 30-Dec-02]
10) External loopback packet processing [done! 02-Jan-03]
11) NXM detection/protection [done! 21-Oct-02]
------------------------------------------------------------------------------
Modification history:
16-Jan-03 DTH Merged Mark Pizzolato's enhancements with main source
Corrected PDP11 XQ_DEBUG compilation
15-Jan-03 MP Fixed the number of units in the xq device structure.
13-Jan-03 MP Reworked the timer management logic which initiated
the system id broadcast messages. The original
implementation triggered this on the CSR transition
of Receiver Enabled. This was an issue since the
it seems that at least VMS's XQ driver makes this
transition often and the resulting overhead reduces
the simulated CPU instruction execution thruput by
about 40%. I start the system id timer on device
reset and it fires once a second so that it can
leverage the reasonably recalibrated tmr_poll value.
13-Jan-03 MP Changed the scheduling of xq_svc to leverage the
dynamically computed clock values to achieve an
approximate interval of 100 per second. This is
more than sufficient for normal system behaviour
expecially since we service recieves with every
transmit. The previous fixed value of 2500
attempted to get 200/sec but it was a guess that
didn't adapt. On faster host systems (possibly
most of them) the 2500 number spends too much time
polling.
10-Jan-03 DTH Removed XQ_DEBUG dependency from Borland #pragmas
Added SET XQ BOOTROM command for PDP11s
07-Jan-03 DTH Added pointer to online manuals
02-Jan-03 DTH Added local packet processing
30-Dec-02 DTH Added automatic system id broadcast
27-Dec-02 DTH Merged Mark Pizzolato's enhancements with main source
20-Dec-02 MP Fix bug that caused VMS system crashes when attempting cluster
operations. Added additional conditionally compiled debug
info needed to track down the issue.
17-Dec-02 MP Added SIMH "registers" describing the Ethernet state
so this information can be recorded in a "saved" snapshot.
05-Dec-02 MP Adjusted the rtime value from 100 to 2500 which increased the
available CPU cycles for Instruction execution by almost 100%.
This made sense after the below enhancements which, in general
caused the draining of the received data stream much more
agressively with less overhead.
05-Dec-02 MP Added a call to xq_svc after all successful calls to eth_write
to allow receive processing to happen before the next event
service time.
05-Dec-02 MP Restructured the flow of processing in xq_svc so that eth_read
is called repeatedly until either a packet isn't found or
there is no room for another one in the queue. Once that has
been done, xq_processrdbl is called to pass the queued packets
into the simulated system as space is available there.
xq_process_rdbl is also called at the beginning of xq_svc to
drain the queue into the simulated system, making more room
available in the queue. No processing is done at all in
xq_svc if the receiver is disabled.
04-Dec-02 MP Changed interface and usage to xq_insert_queue to pass
the packet to be inserted by reference. This avoids 3K bytes
of buffer copy operations for each packet received. Now only
copy actual received packet data.
31-Oct-02 DTH Cleaned up pointer warnings (found by Federico Schwindt)
Corrected unattached and no network behavior
Added message when SHOW XQ ETH finds no devices
@@ -60,7 +130,7 @@
Added and debugged Sanity Timer code
Corrected copyright
15-Oct-02 DTH Rollback to known good Beta3 and roll forward; TCP broken
12-Oct-02 DTH Fixed VAX network bootstrap; setup packets must return non-zero TDR
12-Oct-02 DTH Fixed VAX network bootstrap; setup packets must return TDR > 0
11-Oct-02 DTH Added SET/SHOW XQ TYPE and SET/SHOW XQ SANITY commands
10-Oct-02 DTH Beta 3 released; Integrated with 2.10-0b1
Fixed off-by-1 bug on xq.setup.macs[7..13]
@@ -82,32 +152,16 @@
15-Aug-02 DTH Started XQ simulation
------------------------------------------------------------------------------
Known Bugs or Unsupported features:
1) DEQNA and DEQNA-LOCK modes not implemented fully
2) Sanity Timer not implemented [done! 16-Oct-02]
3) MOP functionality not implemented
4) Multicast support is weak [done! 22-Oct-02]
5) Promiscuous mode not implemented [done! 22-Oct-02]
6) Cannot VMScluster node
7) Cannot bootstrap module on VAX (>>> B XQA0)
8) PDP11 bootstrap code missing
9) Automatic ID broadcast every 8-10 minutes
10) External loopback packet processing
11) NXM detection/protection [done! 21-Oct-02]
------------------------------------------------------------------------------
*/
/* compiler directives to help the Author keep the code clean :-) */
#if defined (__BORLANDC__) && defined (XQ_DEBUG)
#if defined (__BORLANDC__)
#pragma warn +8070 /* function should return value */
/* #pragma warn +8071 */ /* conversion may lose significant digits */
/* #pragma warn +8071 *//* conversion may lose significant digits */
#pragma warn +8075 /* suspicious pointer conversion */
#pragma warn +8079 /* mixing different char pointers */
#pragma warn +8080 /* variable declared but not used */
#endif /* __BORLANDC__ && XQ_DEBUG */
#endif /* __BORLANDC__ */
#include <assert.h>
#include "pdp11_xq.h"
@@ -116,7 +170,7 @@ extern int32 int_req[IPL_HLVL];
extern int32 tmr_poll, clk_tps;
struct xq_device xq = {
100, /* rtime */
2500, /* rtime */
{0x08, 0x00, 0x2B, 0xAA, 0xBB, 0xCC}, /* mac */
XQ_T_DELQA, /* type */
{0} /* sanity */
@@ -128,6 +182,7 @@ t_stat xq_rd(int32* data, int32 PA, int32 access);
t_stat xq_wr(int32 data, int32 PA, int32 access);
t_stat xq_svc(UNIT * uptr);
t_stat xq_sansvc(UNIT * uptr);
t_stat xq_idsvc(UNIT * uptr);
t_stat xq_reset (DEVICE * dptr);
t_stat xq_attach (UNIT * uptr, char * cptr);
t_stat xq_detach (UNIT * uptr);
@@ -137,6 +192,8 @@ t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc);
t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc);
t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc);
t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc);
t_stat xq_show_bootrom (FILE* st, UNIT* uptr, int32 val, void* desc);
t_stat xq_set_bootrom (UNIT* uptr, int32 val, char* cptr, void* desc);
t_stat xq_showeth (FILE* st, UNIT* uptr, int32 val, void* desc);
t_stat xq_process_xbdl(void);
t_stat xq_dispatch_xbdl(void);
@@ -148,15 +205,18 @@ t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
void xq_start_santmr(void);
void xq_cancel_santmr(void);
void xq_reset_santmr(void);
t_stat xq_boot_host(void);
void xq_start_idtmr(void);
t_stat xq_system_id(const ETH_MAC dst, uint16 receipt_id);
/* SIMH device structures */
DIB xq_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr,
1, IVCL (XQ), 0, { &xq_inta } };
UNIT xq_unit[] = {
{ UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) },
{ UDATA (&xq_sansvc, UNIT_DIS, 0) } /* sanity timer */
{ UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, /* receive timer */
{ UDATA (&xq_sansvc, UNIT_DIS, 0) }, /* sanity timer */
{ UDATA (&xq_idsvc, UNIT_DIS, 0) } /* system id timer */
};
REG xq_reg[] = {
@@ -170,6 +230,13 @@ REG xq_reg[] = {
{ GRDATA ( XBDL, xq.xbdl, XQ_RDX, 32, 0) },
{ GRDATA ( VAR, xq.var, XQ_RDX, 16, 0) },
{ GRDATA ( CSR, xq.csr, XQ_RDX, 16, 0) },
{ GRDATA ( SETUP_PRM, xq.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_MLT, xq.setup.multicast, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_L1, xq.setup.l1, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_L2, xq.setup.l2, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_L3, xq.setup.l3, XQ_RDX, 32, 0), REG_HRO},
{ GRDATA ( SETUP_SAN, xq.setup.sanity_timer, XQ_RDX, 32, 0), REG_HRO},
{ BRDATA ( SETUP_MACS, &xq.setup.macs, XQ_RDX, 8, sizeof(xq.setup.macs)), REG_HRO},
{ NULL },
};
@@ -177,6 +244,8 @@ MTAB xq_mod[] = {
#if defined (VM_PDP11)
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_NC, 0, "BOOTROM", "BOOTROM",
&xq_set_bootrom, &xq_show_bootrom, NULL },
#else
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL,
NULL, &show_addr, NULL },
@@ -185,24 +254,37 @@ MTAB xq_mod[] = {
NULL, &show_vec, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC",
&xq_setmac, &xq_showmac, &xq.mac },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH",
0, &xq_showeth, 0 },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", NULL,
NULL, &xq_showeth, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE",
&xq_set_type, &xq_show_type, 0 },
{ MTAB_XTD | MTAB_VDV, 0, "SANITY", "SANITY",
&xq_set_sanity, &xq_show_sanity, 0 },
&xq_set_type, &xq_show_type, NULL },
{ MTAB_XTD | MTAB_VDV|MTAB_NMO, 0, "SANITY", "SANITY",
&xq_set_sanity, &xq_show_sanity, NULL },
{ 0 },
};
DEVICE xq_dev = {
"XQ", xq_unit, xq_reg, xq_mod,
2, XQ_RDX, 0, 1, XQ_RDX, 8,
3, XQ_RDX, 0, 1, XQ_RDX, 8,
&xq_ex, &xq_dep, &xq_reset,
NULL, &xq_attach, &xq_detach,
&xq_dib, DEV_DISABLE | DEV_QBUS
};
#ifdef XQ_DEBUG
#if defined(VM_VAX)
extern int32 PSL; /* PSL */
extern int32 fault_PC; /* fault PC */
#endif
const char* const xq_recv_regnames[] = {
"MAC0", "MAC1", "MAC2", "MAC3", "MAC4", "MAC5", "VAR", "CSR"
};
const char* const xq_xmit_regnames[] = {
"", "", "RBDL-Lo", "RBDL-Hi", "XBDL-Lo", "XBDL-Hi", "VAR", "CSR"
};
const char* const xq_csr_bits[] = {
"RE ", "SR ", "NI ", "BD ", "XL ", "RL ", "IE ", "XI ",
"IL ", "EL ", "SE ", "RR ", "OK ", "CA ", "PE ", "RI"
@@ -255,7 +337,7 @@ void xq_remove_queue(struct xq_msg_que* que)
}
}
void xq_insert_queue(struct xq_msg_que* que, int32 type, ETH_PACK packet, int32 status)
void xq_insert_queue(struct xq_msg_que* que, int32 type, ETH_PACK* packet, int32 status)
{
struct xq_msg_itm* item;
@@ -274,12 +356,16 @@ void xq_insert_queue(struct xq_msg_que* que, int32 type, ETH_PACK packet, int32
if (++que->head == XQ_QUE_MAX)
que->head = 0;
que->loss++;
#ifdef XQ_DEBUG
fprintf(stderr, "Packet Lost\n");
#endif
}
/* set information in (new) tail item */
item = &que->item[que->tail];
item->type = type;
item->packet = packet;
item->type = type;
item->packet.len = packet->len;
memcpy(item->packet.msg, packet->msg, packet->len);
item->status = status;
}
@@ -289,13 +375,13 @@ void xq_insert_queue(struct xq_msg_que* que, int32 type, ETH_PACK packet, int32
/* stop simh from reading non-existant unit data stream */
t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
t_stat xq_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw)
{
return SCPE_NOFNC;
}
/* stop simh from writing non-existant unit data stream */
t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
t_stat xq_dep (t_value val, t_addr addr, UNIT* uptr, int32 sw)
{
return SCPE_NOFNC;
}
@@ -432,8 +518,29 @@ t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc)
return SCPE_OK;
}
t_stat xq_show_bootrom (FILE* st, UNIT* uptr, int32 val, void* desc)
{
/* format includes \n for MTAB_NMO compatibility */
fprintf(st, "bootrom=%s\n", xq.bootrom);
return SCPE_OK;
}
t_stat xq_set_bootrom (UNIT* uptr, int32 val, char* cptr, void* desc)
{
size_t len;
if (!cptr) return SCPE_IERR;
len = strlen(cptr) + 1;
if (len > sizeof(xq.bootrom)) return SCPE_ARG;
memcpy(xq.bootrom, cptr, strlen(cptr)+1);
return SCPE_OK;
}
t_stat xq_nxm_error(void)
{
#ifdef XQ_DEBUG
fprintf(stderr,"XQ: Non Existent Memory Error\n");
#endif
/* set NXM and associated bits in CSR */
xq.csr |= (XQ_CSR_NI | XQ_CSR_XI | XQ_CSR_XL | XQ_CSR_RL);
@@ -454,18 +561,16 @@ void xq_write_callback (int status)
const uint16 TDR = 100 + xq.write_buffer.len * 8; /* arbitrary value */
uint16 write_success[2] = {0};
uint16 write_failure[2] = {XQ_DSC_C};
#if 0
write_success[1] = TDR;
write_failure[1] = TDR;
#else
write_success[1] = TDR & 0x03FF; /* Does TDR get set on successful packets ?? */
write_failure[1] = TDR & 0x03FF; /* TSW2<09:00> */
#endif
/* update write status words */
if (status == 0) { /* success */
wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, write_success, NOMAP);
} else { /* failure */
#ifdef XQ_DEBUG
fprintf(stderr, "XQ: Packet Write Error\n");
#endif
wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, write_failure, NOMAP);
}
if (wstatus) {
@@ -492,11 +597,19 @@ void xq_write_callback (int status)
}
/* read registers: */
t_stat xq_rd(int32* data, int32 PA, int32 access)
{
int index = (PA >> 1) & 07; /* word index */
#ifdef XQ_DEBUG
if (index != 7)
#if defined(VM_VAX)
fprintf (stderr,"XQ: %s %08X %08X read: %X\n", xq_recv_regnames[index], fault_PC, PSL, *data);
#else
fprintf (stderr,"XQ: %s read: %X\n", xq_recv_regnames[index], *data);
#endif /* VM_VAX */
#endif
switch (index) {
case 0:
case 1:
@@ -542,7 +655,7 @@ t_stat xq_process_rbdl(void)
struct xq_msg_itm* item;
#ifdef XQ_DEBUG
printf("CSR: Processing read\n");
fprintf(stderr,"XQ: CSR - Processing read\n");
#endif
/* process buffer descriptors */
while(1) {
@@ -612,6 +725,9 @@ t_stat xq_process_rbdl(void)
}
xq.rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF);
if (xq.ReadQ.loss) {
#ifdef XQ_DEBUG
fprintf(stderr, "XQ: ReadQ overflow\n");
#endif
xq.rbdl_buf[4] |= 0x0001; /* set overflow bit */
xq.ReadQ.loss = 0; /* reset loss counter */
}
@@ -647,6 +763,9 @@ t_stat xq_process_mop(void)
struct xq_meb* meb = (struct xq_meb*) &xq.write_buffer.msg[0200];
const struct xq_meb* limit = (struct xq_meb*) &xq.write_buffer.msg[0400];
#ifdef XQ_DEBUG
fprintf(stderr, "XQ: Processing MOP data\n");
#endif
if (xq.type == XQ_T_DEQNA) /* DEQNA's don't MOP */
return SCPE_NOFNC;
@@ -657,7 +776,7 @@ t_stat xq_process_mop(void)
/* MOP stuff here - NOT YET FULLY IMPLEMENTED */
#ifdef XQ_DEBUG
printf("Processing MEB type: %d\n", meb->type);
printf("XQ: Processing MEB type: %d\n", meb->type);
#endif
switch (meb->type) {
case 0: /* MOP Termination */
@@ -701,6 +820,7 @@ t_stat xq_process_setup(void)
ETH_MAC filters[XQ_FILTER_MAX + 1];
/* extract filter addresses from setup packet */
memset(xq.setup.macs, '\0', sizeof(xq.setup.macs));
for (i = 0; i < 7; i++)
for (j = 0; j < 6; j++) {
xq.setup.macs[i] [j] = xq.write_buffer.msg[(i + 01) + (j * 8)];
@@ -756,6 +876,9 @@ t_stat xq_process_setup(void)
if (xq.write_buffer.msg[0])
status = xq_process_mop();
/* mark setup block valid */
xq.setup.valid = 1;
#ifdef XQ_DEBUG
xq_debug_setup();
#endif
@@ -771,7 +894,7 @@ t_stat xq_process_setup(void)
*/
t_stat xq_process_xbdl()
{
const uint16 implicit_chain_status[2] = {XQ_DSC_L | XQ_DSC_C, 0};
const uint16 implicit_chain_status[2] = {XQ_DSC_V | XQ_DSC_C, 1};
const uint16 write_success[2] = {0, 1 /*Non-Zero TDR*/};
uint16 b_length, w_length;
@@ -780,7 +903,7 @@ t_stat xq_process_xbdl()
t_stat status;
#ifdef XQ_DEBUG
printf("CSR: Processing write\n");
fprintf(stderr,"XQ: xq_process_xbdl - Processing write\n");
#endif
/* clear write buffer */
xq.write_buffer.len = 0;
@@ -789,9 +912,9 @@ t_stat xq_process_xbdl()
while (1) {
/* Get transmit bdl from memory */
rstatus = Map_ReadW (xq.xbdl_ba, 12, &xq.xbdl_buf[0], NOMAP);
xq.xbdl_buf[0] = 0xFFFF;
wstatus = Map_WriteW(xq.xbdl_ba, 2, &xq.xbdl_buf[0], NOMAP);
rstatus = Map_ReadW (xq.xbdl_ba + 2, 6, &xq.xbdl_buf[1], NOMAP);
if (rstatus || wstatus) return xq_nxm_error();
/* invalid buffer? */
@@ -799,20 +922,17 @@ t_stat xq_process_xbdl()
xq.csr |= XQ_CSR_XL;
if (xq.csr & XQ_CSR_IE)
SET_INT(XQ);
#ifdef XQ_DEBUG
fprintf(stderr,"XQ: xq_process_xbdl - List Empty - Done Processing write\n");
#endif
return SCPE_OK;
}
/* explicit chain buffer? */
if (xq.xbdl_buf[1] & XQ_DSC_C) {
xq.xbdl_ba = ((xq.xbdl_buf[1] & 0x3F) << 16) | xq.xbdl_buf[2];
continue;
}
/* get status words */
rstatus = Map_ReadW(xq.xbdl_ba + 8, 4, &xq.xbdl_buf[4], NOMAP);
if (rstatus) return xq_nxm_error();
/* get host memory address */
#ifdef XQ_DEBUG
fprintf(stderr,"XQ: xq_process_xbdl: Buffer Descriptor Information: %04X %04X %04X %04X %04X \n",
xq.xbdl_buf[1], xq.xbdl_buf[2], xq.xbdl_buf[3], xq.xbdl_buf[4], xq.xbdl_buf[5]);
#endif
/* compute host memory address */
address = ((xq.xbdl_buf[1] & 0x3F) << 16) | xq.xbdl_buf[2];
/* decode buffer length - two's complement (in words) */
@@ -821,6 +941,15 @@ t_stat xq_process_xbdl()
if (xq.xbdl_buf[1] & XQ_DSC_H) b_length -= 1;
if (xq.xbdl_buf[1] & XQ_DSC_L) b_length -= 1;
/* explicit chain buffer? */
if (xq.xbdl_buf[1] & XQ_DSC_C) {
xq.xbdl_ba = address;
#ifdef XQ_DEBUG
fprintf(stderr,"XQ: xq_process_xbdl: Chained Buffer Encountered: %d\n", b_length);
#endif
continue;
}
/* add to transmit buffer, making sure it's not too big */
if ((xq.write_buffer.len + b_length) > sizeof(xq.write_buffer.msg))
b_length = sizeof(xq.write_buffer.msg) - xq.write_buffer.len;
@@ -836,10 +965,10 @@ t_stat xq_process_xbdl()
status = xq_process_setup();
/* put packet in read buffer */
xq_insert_queue (&xq.ReadQ, 0, xq.write_buffer, status);
xq_insert_queue (&xq.ReadQ, 0, &xq.write_buffer, status);
} else { /* loopback */
/* put packet in read buffer */
xq_insert_queue (&xq.ReadQ, 1, xq.write_buffer, 0);
xq_insert_queue (&xq.ReadQ, 1, &xq.write_buffer, 0);
}
/* update write status */
@@ -866,11 +995,19 @@ t_stat xq_process_xbdl()
status = eth_write(xq.etherface, &xq.write_buffer, &xq_write_callback);
if (status != SCPE_OK) /* not implemented or unattached */
xq_write_callback(1); /* fake failure */
else
xq_svc(&xq_unit[0]); /* service any received data */
#ifdef XQ_DEBUG
fprintf(stderr,"XQ: xq_process_xbdl: Completed Processing write\n");
#endif
return SCPE_OK;
} /* loopback/non-loopback */
} else { /* not at end-of-message */
#ifdef XQ_DEBUG
fprintf(stderr,"XQ: xq_process_xbdl: Processing Implicit Chained Buffer Segment\n");
#endif
/* update bdl status words */
wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, (uint16*) implicit_chain_status, NOMAP);
if(wstatus) return xq_nxm_error();
@@ -889,7 +1026,7 @@ t_stat xq_dispatch_rbdl(void)
t_stat status;
#ifdef XQ_DEBUG
printf("CSR: Dispatching read\n");
fprintf(stderr,"XQ: CSR - Dispatching read\n");
#endif
/* mark receive bdl valid */
xq.csr &= ~XQ_CSR_RL;
@@ -927,7 +1064,7 @@ t_stat xq_dispatch_xbdl()
int i;
t_stat status;
#ifdef XQ_DEBUG
printf("CSR: Dispatching write\n");
fprintf(stderr,"XQ: CSR - Dispatching write\n");
#endif
/* mark transmit bdl valid */
xq.csr &= ~XQ_CSR_XL;
@@ -948,20 +1085,110 @@ t_stat xq_dispatch_xbdl()
return status;
}
t_stat xq_process_loopback(ETH_PACK* pack)
{
ETH_PACK reply;
ETH_MAC physical_address;
t_stat status;
int offset = pack->msg[14] | (pack->msg[15] << 8);
int function = pack->msg[offset] | (pack->msg[offset+1] << 8);
if (function != 2 /*forward*/)
return SCPE_NOFNC;
/* create reply packet */
memcpy (&reply, pack, sizeof(ETH_PACK));
memcpy (physical_address, xq.setup.valid ? xq.setup.macs[0] : xq.mac, sizeof(ETH_MAC));
memcpy (&reply.msg[0], &reply.msg[offset+2], sizeof(ETH_MAC));
memcpy (&reply.msg[6], physical_address, sizeof(ETH_MAC));
memcpy (&reply.msg[offset+2], physical_address, sizeof(ETH_MAC));
reply.msg[offset] = 0x01;
offset += 8;
reply.msg[14] = offset & 0xFF;
reply.msg[15] = (offset >> 8) & 0xFF;
/* send reply packet */
status = eth_write(xq.etherface, &reply, NULL);
return status;
}
t_stat xq_process_remote_console (ETH_PACK* pack)
{
t_stat status;
ETH_MAC source;
uint16 receipt;
int code = pack->msg[16];
switch (code) {
case 0x05: /* request id */
receipt = pack->msg[18] | (pack->msg[19] << 8);
memcpy(source, &pack->msg[6], sizeof(ETH_MAC));
/* send system id to requestor */
status = xq_system_id (source, receipt);
return status;
break;
case 0x06: /* boot */
/*
NOTE: the verification field should be checked here against the
verification value established in the setup packet. If they match the
reboot should occur, otherwise nothing happens, and the packet
is passed on to the host.
Verification is not implemented, since the setup packet processing code
isn't complete yet.
Various values are also passed: processor, control, and software id.
These control the various boot parameters, however SIMH does not
have a mechanism to pass these to the host, so just reboot.
*/
status = xq_boot_host();
return status;
break;
} /* switch */
return SCPE_NOFNC;
}
t_stat xq_process_local (ETH_PACK* pack)
{
/* returns SCPE_OK if local processing occurred,
otherwise returns SCPE_NOFNC or some other code */
int protocol;
/* DEQNA's have no local processing capability */
if (xq.type == XQ_T_DEQNA)
return SCPE_NOFNC;
protocol = pack->msg[12] | (pack->msg[13] << 8);
switch (protocol) {
case 0x0090: /* ethernet loopback */
return xq_process_loopback(pack);
break;
case 0x0260: /* MOP remote console */
return xq_process_remote_console(pack);
break;
}
return SCPE_NOFNC;
}
void xq_read_callback(int status)
{
t_stat rstatus;
if (xq.csr & XQ_CSR_RE) { /* receiver enabled */
/* process any packets locally that can be */
t_stat status = xq_process_local (&xq.read_buffer);
/* add packet to read queue */
xq_insert_queue(&xq.ReadQ, 2, xq.read_buffer, status);
/* process packet if receive list is valid */
if (~xq.csr & XQ_CSR_RL)
rstatus = xq_process_rbdl();
if (status != SCPE_OK)
xq_insert_queue(&xq.ReadQ, 2, &xq.read_buffer, status);
}
#ifdef XQ_DEBUG
else
fprintf(stderr, "XQ: packet received with receiver disabled\n");
#endif
}
void xq_sw_reset(void)
@@ -972,6 +1199,9 @@ void xq_sw_reset(void)
/* disconnect ethernet reception */
sim_cancel(&xq_unit[0]);
/* stop system_id timer */
sim_cancel(&xq_unit[2]);
/* reset csr bits */
xq.csr = XQ_CSR_XL | XQ_CSR_RL;
@@ -982,8 +1212,7 @@ void xq_sw_reset(void)
xq_clear_queue(&xq.ReadQ);
/* clear setup info */
memset (&xq.setup, 0, 6 * XQ_FILTER_MAX);
xq.setup.promiscuous = 0;
memset (&xq.setup, 0, sizeof(xq.setup));
}
@@ -1038,10 +1267,14 @@ t_stat xq_wr_csr(int32 data)
if (data & XQ_CSR_XI) /* clearing XI clears NI too */
xq.csr &= ~XQ_CSR_NI;
/* start receiver when RE transitions to set */
/* start receiver timer when RE transitions to set */
if (~saved_csr & XQ_CSR_RE & data) {
//xq_start_receiver();
sim_activate(&xq_unit[0], xq.rtime);
sim_activate(&xq_unit[0], (clk_tps * tmr_poll)/100);
}
/* stop receiver timer when RE transitions to clear */
if (saved_csr & XQ_CSR_RE & ~data) {
sim_cancel(&xq_unit[0]);
}
return SCPE_OK;
@@ -1050,8 +1283,18 @@ t_stat xq_wr_csr(int32 data)
t_stat xq_wr(int32 data, int32 PA, int32 access)
{
t_stat status;
int index = (PA >> 1) & 07; /* word index */
switch ((PA >> 1) & 07) {
#ifdef XQ_DEBUG
if (index != 7)
#if defined(VM_VAX)
fprintf (stderr,"XQ: %s %08X %08X write: %X\n", xq_xmit_regnames[index], fault_PC, PSL, data);
#else
fprintf (stderr,"XQ: %s write: %X\n", xq_xmit_regnames[index], data);
#endif /* VM_VAX */
#endif
switch (index) {
case 0: /* these should not be written */
case 1:
break;
@@ -1121,6 +1364,7 @@ t_stat xq_reset(DEVICE* dptr)
break;
case XQ_T_DELQA:
/* note that the DELQA in NORMAL mode has no power-on SANITY state! */
xq_start_idtmr();
break;
};
@@ -1134,7 +1378,7 @@ void xq_start_santmr(void)
#if 0
#ifdef XQ_DEBUG
printf("SANITY TIMER: enabled, qsecs: %d, poll:%d\n", xq.sanity.quarter_secs, tmr_poll);
fprintf(stderr,"XQ: SANITY TIMER: enabled, qsecs: %d, poll:%d\n", xq.sanity.quarter_secs, tmr_poll);
#endif
#endif
if (sim_is_active(&xq_unit[1])) /* cancel timer, just in case */
@@ -1149,7 +1393,7 @@ void xq_cancel_santmr(void)
if (sim_is_active(&xq_unit[1]) && !xq.sanity.enabled) {
#if 0
#ifdef XQ_DEBUG
printf("SANITY TIMER: cancelled, qsecs: %d\n", xq.sanity.quarter_secs);
fprintf(stderr,"XQ: SANITY TIMER: cancelled, qsecs: %d\n", xq.sanity.quarter_secs);
#endif
#endif
sim_cancel(&xq_unit[1]);
@@ -1161,7 +1405,7 @@ void xq_reset_santmr(void)
#if 0
#ifdef XQ_DEBUG
ftime(&start);
printf("SANITY TIMER: resetting, qsecs: %d\n", xq.sanity.quarter_secs);
fprintf(stderr,"XQ: SANITY TIMER: resetting, qsecs: %d\n", xq.sanity.quarter_secs);
#endif
#endif
xq.sanity.countdown = xq.sanity.quarter_secs;
@@ -1179,39 +1423,159 @@ t_stat xq_sansvc(UNIT* uptr)
/*
If this section is entered, it means that the sanity timer has expired
without being reset, and the controller must reboot the processor.
The manual says the hardware should force Qbus BDCOK low for
3.6 microseconds, which will cause the host to reboot.
Since the SIMH Qbus emulator does not have this functionality, we call
a special STOP_ code, and let the CPU stop dispatch routine decide
what the appropriate cpu-specific behavior should be.
*/
#if 0
#ifdef XQ_DEBUG
ftime(&finish);
printf("SANITY TIMER: EXPIRED, qsecs: %d, poll: %d, elapsed: %d\n",
fprintf(stderr,"XQ: SANITY TIMER: EXPIRED, qsecs: %d, poll: %d, elapsed: %d\n",
xq.sanity.quarter_secs, tmr_poll, finish.time - start.time);
#endif
#endif
return STOP_SANITY;
xq_boot_host();
}
return SCPE_OK;
}
t_stat xq_boot_host(void)
{
/*
The manual says the hardware should force the Qbus BDCOK low for
3.6 microseconds, which will cause the host to reboot.
Since the SIMH Qbus emulator does not have this functionality, we call
a special STOP_ code, and let the CPU stop dispatch routine decide
what the appropriate cpu-specific behavior should be.
*/
return STOP_SANITY;
}
void xq_start_idtmr(void)
{
/* must be recalculated each time since tmr_poll is a dynamic number */
const int32 one_sec = clk_tps * tmr_poll;
if (sim_is_active(&xq_unit[2])) /* cancel timer, just in case */
sim_cancel(&xq_unit[2]);
xq.id.enabled = 1;
/* every 8-10 minutes (9 in this case) the DELQA broadcasts a system id message */
xq.id.countdown = 9 * 60;
sim_activate(&xq_unit[2], one_sec);
}
t_stat xq_system_id (const ETH_MAC dest, uint16 receipt_id)
{
static uint16 receipt = 0;
ETH_PACK system_id;
uint8* const msg = &system_id.msg[0];
t_stat status;
memset (&system_id, 0, sizeof(system_id));
memcpy (&msg[0], dest, sizeof(ETH_MAC));
memcpy (&msg[6], xq.setup.valid ? xq.setup.macs[0] : xq.mac, sizeof(ETH_MAC));
msg[12] = 0x60; /* type */
msg[13] = 0x02; /* type */
msg[14] = 0x1C; /* character count */
msg[15] = 0x00; /* character count */
msg[16] = 0x07; /* code */
msg[17] = 0x00; /* zero pad */
if (receipt_id) {
msg[18] = receipt_id & 0xFF; /* receipt number */
msg[19] = (receipt_id >> 8) & 0xFF; /* receipt number */
} else {
msg[18] = receipt & 0xFF; /* receipt number */
msg[19] = (receipt++ >> 8) & 0xFF; /* receipt number */
}
/* MOP VERSION */
msg[20] = 0x01; /* type */
msg[21] = 0x00; /* type */
msg[22] = 0x03; /* length */
msg[23] = 0x03; /* version */
msg[24] = 0x01; /* eco */
msg[25] = 0x00; /* user eco */
/* FUNCTION */
msg[26] = 0x02; /* type */
msg[27] = 0x00; /* type */
msg[28] = 0x02; /* length */
msg[29] = 0x00; /* value 1 ??? */
msg[30] = 0x00; /* value 2 */
/* HARDWARE ADDRESS */
msg[31] = 0x07; /* type */
msg[32] = 0x00; /* type */
msg[33] = 0x06; /* length */
memcpy (&msg[34], xq.mac, sizeof(ETH_MAC)); /* ROM address */
/* DEVICE TYPE */
msg[40] = 37; /* type */
msg[41] = 0x00; /* type */
msg[42] = 0x01; /* length */
msg[43] = 0x11; /* value (0x11=DELQA) */
/* write system id */
system_id.len = 60;
status = eth_write(xq.etherface, &system_id, NULL);
return status;
}
t_stat xq_idsvc(UNIT* uptr)
{
/* must be recalculated each time since tmr_poll is a dynamic number */
const int32 one_sec = clk_tps * tmr_poll;
const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00};
/* DEQNAs don't issue system id messages */
if (xq.type == XQ_T_DEQNA)
return SCPE_NOFNC;
if (--xq.id.countdown <= 0) {
/*
If this section is entered, it means that the 9 minute interval has elapsed
so broadcast system id to MOP multicast address
*/
xq_system_id(mop_multicast, 0);
/* every 8-10 minutes (9 in this case) the DELQA broadcasts a system id message */
xq.id.countdown = 9 * 60;
}
/* resubmit - for one second to get a well calibrated value of tmr_poll */
sim_activate(&xq_unit[2], one_sec);
return SCPE_OK;
}
/*
** service routine - used for ethernet reading loop
*/
t_stat xq_svc(UNIT* uptr)
{
t_stat status;
int queue_size;
/* read a packet from the ethernet - processing is via the callback */
status = eth_read (xq.etherface, &xq.read_buffer, &xq_read_callback);
/* Don't try a read if the receiver is disabled */
if (!(xq.csr & XQ_CSR_RE)) return SCPE_OK;
/* First pump any queued packets into the system */
if ((xq.ReadQ.count > 0) && (~xq.csr & XQ_CSR_RL))
status = xq_process_rbdl();
/* Now read and queue packets that have arrived */
/* This is repeated as long as they are available and we have room */
do
{
queue_size = xq.ReadQ.count;
/* read a packet from the ethernet - processing is via the callback */
status = eth_read (xq.etherface, &xq.read_buffer, &xq_read_callback);
} while (queue_size != xq.ReadQ.count);
/* Now pump any still queued packets into the system */
if ((xq.ReadQ.count > 0) && (~xq.csr & XQ_CSR_RL))
status = xq_process_rbdl();
/* resubmit if still receive enabled */
if (xq.csr & XQ_CSR_RE)
sim_activate(&xq_unit[0], xq.rtime);
sim_activate(&xq_unit[0], (clk_tps * tmr_poll)/100);
return SCPE_OK;
}
@@ -1278,8 +1642,10 @@ int32 xq_inta (void)
/=============================================================================*/
#ifdef XQ_DEBUG
void xq_dump_csr (void)
{
static int cnt = 0;
/* tell user what is changing in register */
int i;
int mask = 1;
@@ -1290,7 +1656,12 @@ void xq_dump_csr (void)
if ((csr & mask)) strcat (hi, xq_csr_bits[i]);
if ((~csr & mask)) strcat (lo, xq_csr_bits[i]);
}
printf ("CSR read: %s %s\n", hi, lo);
#if defined (VM_VAX)
printf ("CSR %08X %08X read: %s %s\n", fault_PC, PSL, hi, lo);
#else
if (cnt < 20)
printf ("CSR read[%d]: %s %s\n", cnt++, hi, lo);
#endif /* VM_VAX */
}
void xq_dump_var (void)
@@ -1326,7 +1697,11 @@ void xq_csr_changes (uint16 data)
/* write-one-to-clear bits*/
if (data & XQ_CSR_RI) strcat(lo, "RI ");
if (data & XQ_CSR_XI) strcat(lo, "XI ");
#if defined(VM_VAX)
printf ("CSR %08X %08X write: %s %s\n", fault_PC, PSL, hi, lo);
#else
printf ("CSR write: %s %s\n", hi, lo);
#endif /* VM_VAX */
}
void xq_var_changes (uint16 data)
@@ -1345,9 +1720,11 @@ void xq_var_changes (uint16 data)
if (~var & XQ_VEC_ID & data) strcat (hi, "ID ");
if (var & XQ_VEC_ID & ~data) strcat (lo, "ID ");
if ((var & XQ_VEC_IV) != (data & XQ_VEC_IV))
if ((var & XQ_VEC_IV) != (data & XQ_VEC_IV)) {
vec = (data & XQ_VEC_IV) >> 2;
printf ("VAR write: %s %s - Vec: %d\n", hi, lo, vec);
printf ("VAR write: %s %s - Vec: %d\n", hi, lo, vec);
} else
printf ("VAR write: %s %s\n", hi, lo);
}
void xq_debug_setup(void)
@@ -1369,8 +1746,7 @@ void xq_debug_setup(void)
if (len & XQ_SETUP_PM) strcat(buffer, "PM ");
if (len & XQ_SETUP_LD) strcat(buffer, "LD ");
if (len & XQ_SETUP_ST) strcat(buffer, "ST ");
printf ("Setup: Length [%d] info: %s\n", len, buffer);
printf ("Setup: Length [%d =0x%X, LD:%d, ST:%d] info: %s\n", len, len, (len & XQ_SETUP_LD) >> 2, (len & XQ_SETUP_ST) >> 4, buffer);
}
}
#endif

View File

@@ -28,6 +28,11 @@
Modification history:
15-Jan-03 DTH Merged Mark Pizzolato's changes into main source
13-Jan-03 MP Added xq_id to countdown the triggering of the System Id
multicast packets
10-Jan-03 DTH Added bootrom
30-Dec-02 DTH Added setup valid field
21-Oct-02 DTH Corrected copyright again
15-Oct-02 DTH Fixed copyright, added sanity timer support
10-Oct-02 DTH Added more setup fields and bitmasks
@@ -69,6 +74,11 @@ struct xq_sanity {
int countdown; /* sanity timer countdown in 1/4 seconds */
};
struct xq_id {
int enabled; /* System ID timer enabled ? */
int countdown; /* System ID timer countdown in seconds */
};
struct xq_msg_itm {
int type; /* receive (0=setup, 1=loopback, 2=normal) */
ETH_PACK packet; /* packet */
@@ -84,6 +94,7 @@ struct xq_msg_que {
};
struct xq_setup {
int valid; /* is the setup block valid? */
int promiscuous; /* promiscuous mode enabled */
int multicast; /* enable all multicast addresses */
int l1; /* first diagnostic led state */
@@ -108,6 +119,7 @@ struct xq_device {
ETH_MAC mac; /* MAC address */
enum xq_type type; /* controller type */
struct xq_sanity sanity; /* sanity timer information */
struct xq_id id; /* System ID timer information */
/*- initialized values - DO NOT MOVE */
/* I/O register storage */
@@ -130,6 +142,7 @@ struct xq_device {
ETH_PACK read_buffer;
ETH_PACK write_buffer;
struct xq_msg_que ReadQ;
uint8 bootrom[256];
};
#define XQ_CSR_RI 0x8000 /* Receive Interrupt Request (RI) [RO/W1] */

61
PDP11/pdp11_xu.c Normal file
View File

@@ -0,0 +1,61 @@
/* pdp11_xu.c: DEUNA/DELUA Unibus Ethernet interface (stub)
Copyright (c) 2003, 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.
xu DEUNA/DELUNA Ethernet interface (stub)
*/
#if defined (USE_INT64) /* PDP-10 */
#include "pdp10_defs.h"
#define VM_PDP10 1
extern int32 int_req;
extern int32 int_vec[32];
#else
#include "pdp11_defs.h" /* PDP-11 */
#define VM_PDP11 1
extern int32 int_req[IPL_HLVL];
extern int32 int_vec[IPL_HLVL][32];
#endif
/* XU data structures
xu_dev XU device descriptor
xu_unit XU unit list
xu_reg XU register list
*/
DIB xu_dib = { IOBA_XU, IOLN_XU, NULL, NULL,
1, IVCL (XU), VEC_XU, { NULL } };
UNIT xu_unit = { UDATA (NULL, 0, 0) };
REG xu_reg[] = {
{ NULL } };
DEVICE xu_dev = {
"XU", &xu_unit, xu_reg, NULL,
1, 8, 8, 1, 8, 8,
NULL, NULL, NULL,
NULL, NULL, NULL,
&xu_dib, DEV_DIS | DEV_UBUS };