1
0
mirror of https://github.com/simh/simh.git synced 2026-01-25 11:46:37 +00:00

Notes For V2.10-0

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.

1. New Features

1.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.

1.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.

1.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.

1.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.

1.5 PDP-1

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

1.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.

1.7 IBM 1620

- The IBM 1620 simulator has been released.

1.8 AltairZ80

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

1.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.

1.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.

1.11 Simulated DECtapes

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

2. Release Notes

2.1 Bugs Fixed

- 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.

2.2 HP 2100 Debugging

- The HP 2100 CPU nows runs all of the CPU diagnostics.
- The peripherals run most of the peripheral diagnostics.  There
  is still a problem in overlapped seek operation on the disks.
  See the file hp2100_diag.txt for details.

3. In Progress

These simulators are not finished and are available in a separate
Zip archive distribution.

- Interdata 16b/32b: coded, partially tested.  See the file
  id_diag.txt for details.
- SDS 940: coded, partially tested.
This commit is contained in:
Bob Supnik
2002-11-17 15:54:00 -08:00
committed by Mark Pizzolato
parent df6475181c
commit 2c2dd5ea33
218 changed files with 44103 additions and 17112 deletions

View File

@@ -25,6 +25,8 @@
cpu PDP-4/7/9/15 central processor
05-Oct-02 RMS Added DIBs, device number support
25-Jul-02 RMS Added DECtape support for PDP-4
06-Jan-02 RMS Revised enable/disable support
30-Dec-01 RMS Added old PC queue
30-Nov-01 RMS Added extended SET/SHOW support
@@ -242,8 +244,7 @@
4. Adding I/O devices. Three modules must be modified:
pdp18b_defs.h add interrupt request definition
pdp18b_cpu.c add IOT and IORS dispatches
pdp18b_sys.c add pointer to data structures to sim_devices
pdp18b_sys.c add sim_devices table entry
*/
#include "pdp18b_defs.h"
@@ -252,10 +253,10 @@
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
#define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */
#define UNIT_NOEAE (1 << UNIT_V_NOEAE)
#define UNIT_V_NOAPI (UNIT_V_UF+1) /* API absent */
#define UNIT_NOAPI (1 << UNIT_V_NOAPI)
#define UNIT_V_MSIZE (UNIT_V_UF+2) /* dummy mask */
#define UNIT_NOEAE (1 << UNIT_V_NOEAE)
#define UNIT_NOAPI (1 << UNIT_V_NOAPI)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#if defined (PDP4)
@@ -309,10 +310,14 @@ int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
#endif
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
int32 dev_enb = -1; /* device enables */
extern int32 sim_int_char;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern int32 sim_int_char;
extern int32 sim_interval;
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
extern DEVICE *sim_devices[];
extern FILE *sim_log;
t_bool build_dev_tab (void);
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
@@ -320,6 +325,12 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
int32 upd_iors (void);
int32 api_eval (int32 *pend);
extern clk (int32 pulse, int32 AC);
int32 (*dev_tab[DEV_MAX])(int32 pulse, int32 AC); /* device dispatch */
int32 (*dev_iors[DEV_MAX])(void); /* IORS dispatch */
static const int32 api_ffo[256] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
@@ -412,11 +423,8 @@ REG cpu_reg[] = {
{ BRDATA (PCQ, pcq, 8, ADDRSIZE, PCQ_SIZE), REG_RO+REG_CIRC },
{ ORDATA (PCQP, pcq_p, 6), REG_HRO },
{ FLDATA (STOP_INST, stop_inst, 0) },
{ FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO },
{ FLDATA (NOAPI, cpu_unit.flags, UNIT_V_NOAPI), REG_HRO },
{ DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ },
{ ORDATA (WRU, sim_int_char, 8) },
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
{ NULL } };
MTAB cpu_mod[] = {
@@ -457,49 +465,17 @@ DEVICE cpu_dev = {
t_stat sim_instr (void)
{
extern int32 sim_interval;
int32 PC, LAC, MQ;
int32 api_int, api_cycle, skp;
int32 iot_data, device, pulse;
t_stat reason;
extern UNIT clk_unit;
extern int32 tti (int32 pulse, int32 AC);
extern int32 tto (int32 pulse, int32 AC);
extern int32 ptr (int32 pulse, int32 AC);
extern int32 ptp (int32 pulse, int32 AC);
extern int32 clk (int32 pulse, int32 AC);
extern int32 lpt65 (int32 pulse, int32 AC);
extern int32 lpt66 (int32 pulse, int32 AC);
#if defined (DRM)
extern int32 drm60 (int32 pulse, int32 AC);
extern int32 drm61 (int32 pulse, int32 AC);
extern int32 drm62 (int32 pulse, int32 AC);
#endif
#if defined (RF)
extern int32 rf70 (int32 pulse, int32 AC);
extern int32 rf72 (int32 pulse, int32 AC);
#endif
#if defined (RP)
extern int32 rp63 (int32 pulse, int32 AC);
extern int32 rp64 (int32 pulse, int32 AC);
#endif
#if defined (MTA)
extern int32 mt (int32 pulse, int32 AC);
#endif
#if defined (DTA)
extern int32 dt75 (int32 pulse, int32 AC);
extern int32 dt76 (int32 pulse, int32 AC);
#endif
#if defined (TTY1)
extern int32 tti1 (int32 pulse, int32 AC);
extern int32 tto1 (int32 pulse, int32 AC);
#endif
#define JMS_WORD(t) (((LAC & 01000000) >> 1) | ((memm & 1) << 16) | \
(((t) & 1) << 15) | ((PC) & 077777))
#define INCR_ADDR(x) (((x) & epcmask) | (((x) + 1) & damask))
#define SEXT(x) ((int) (((x) & 0400000)? (x) | ~0777777: (x) & 0777777))
/* The following macros implement addressing. They account for autoincrement
addressing, extended addressing, and memory protection, if it exists.
@@ -615,6 +591,7 @@ epcmask = ADDRMASK & ~damask; /* extended PC mask */
#define epcmask (ADDRMASK & ~damask) /* extended PC mask */
#endif
if (build_dev_tab ()) return SCPE_STOP; /* build, chk tables */
PC = saved_PC & ADDRMASK; /* load local copies */
LAC = saved_LAC & 01777777;
MQ = saved_MQ & 0777777;
@@ -1300,7 +1277,7 @@ case 034: /* IOT */
pulse = IR & 067; /* pulse = IR<12:17> */
if (IR & 0000010) LAC = LAC & 01000000; /* clear AC? */
iot_data = LAC & 0777777; /* AC unchanged */
/* PDP-4 system IOT's */
#if defined (PDP4)
@@ -1404,87 +1381,10 @@ case 034: /* IOT */
/* IOT, continued */
case 1: /* PTR */
iot_data = ptr (pulse, iot_data);
break;
case 2: /* PTP */
iot_data = ptp (pulse, iot_data);
break;
case 3: /* TTI */
if (pulse == 004) iot_data = upd_iors ();
else iot_data = tti (pulse, iot_data);
break;
case 4: /* TTO */
iot_data = tto (pulse, iot_data);
break;
#if defined (TTY1)
case 040: /* TTO1 */
if (dev_enb & ENB_TTI1) iot_data = tto1 (pulse, iot_data);
else reason = stop_inst;
break;
case 041: /* TTI1 */
if (dev_enb & ENB_TTI1) iot_data = tti1 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (DRM)
case 060: /* drum */
if (dev_enb & ENB_DRM) iot_data = drm60 (pulse, iot_data);
else reason = stop_inst;
break;
case 061:
if (dev_enb & ENB_DRM) iot_data = drm61 (pulse, iot_data);
else reason = stop_inst;
break;
case 062:
if (dev_enb & ENB_DRM) iot_data = drm62 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (RP)
case 063: /* RP15 */
if (dev_enb & ENB_RP) iot_data = rp63 (pulse, iot_data);
else reason = stop_inst;
break;
case 064:
if (dev_enb & ENB_RP) iot_data = rp64 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
case 065: /* LPT */
iot_data = lpt65 (pulse, iot_data);
break;
case 066:
iot_data = lpt66 (pulse, iot_data);
break;
#if defined (RF)
case 070: /* RF09 */
if (dev_enb & ENB_RF) iot_data = rf70 (pulse, iot_data);
else reason = stop_inst;
break;
case 072:
if (dev_enb & ENB_RF) iot_data = rf72 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (MTA)
case 073: /* TC59 */
if (dev_enb & ENB_MTA) iot_data = mt (pulse, iot_data);
else reason = stop_inst;
break;
#endif
#if defined (DTA)
case 075: /* TC02/TC15 */
if (dev_enb & ENB_DTA) iot_data = dt75 (pulse, iot_data);
else reason = stop_inst;
break;
case 076:
if (dev_enb & ENB_DTA) iot_data = dt76 (pulse, iot_data);
else reason = stop_inst;
break;
#endif
default: /* unknown device */
reason = stop_inst; /* stop on flag */
default: /* devices */
if (dev_tab[device]) /* defined? */
iot_data = dev_tab[device] (pulse, iot_data);
else reason = stop_inst; /* stop on flag */
break; } /* end switch device */
LAC = LAC | (iot_data & 0777777);
if (iot_data & IOT_SKP) PC = INCR_ADDR (PC);
@@ -1504,7 +1404,7 @@ saved_PC = PC & ADDRMASK; /* save copies */
saved_LAC = LAC & 01777777;
saved_MQ = MQ & 0777777;
iors = upd_iors (); /* get IORS */
pcq_r -> qptr = pcq_p; /* update pc q ptr */
pcq_r->qptr = pcq_p; /* update pc q ptr */
return reason;
}
@@ -1530,35 +1430,12 @@ return 0;
int32 upd_iors (void)
{
extern int32 std_iors (void);
extern int32 lpt_iors (void);
#if defined (DRM)
extern int32 drm_iors (void);
#endif
#if defined (RF)
extern int32 rf_iors (void);
#endif
#if defined (RP)
extern int32 rp_iors (void);
#endif
#if defined (MTA)
extern int32 mt_iors (void);
#endif
int32 d, p;
return (ion? IOS_ION: 0) |
#if defined (DRM)
drm_iors () |
#endif
#if defined (RP)
rp_iors () |
#endif
#if defined (RF)
rf_iors () |
#endif
#if defined (MTA)
mt_iors () |
#endif
std_iors () | lpt_iors ();
d = (ion? IOS_ION: 0); /* ION */
for (p = 0; dev_iors[p] != NULL; p++) { /* loop thru table */
d = d | dev_iors[p](); } /* OR in results */
return d;
}
/* Reset routine */
@@ -1576,7 +1453,7 @@ memm = memm_init;
nexm = prvn = trap_pending = 0;
emir_pending = rest_pending = 0;
pcq_r = find_reg ("PCQ", NULL, dptr);
if (pcq_r) pcq_r -> qptr = 0;
if (pcq_r) pcq_r->qptr = 0;
else return SCPE_IERR;
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
@@ -1617,38 +1494,89 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}
/* Device enable routine */
/* Change device number for a device */
t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newdev;
t_stat r;
if (cptr != NULL) return SCPE_ARG;
if ((uptr == NULL) || (val == 0)) return SCPE_IERR;
if (cptr == NULL) return SCPE_ARG;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
dev_enb = dev_enb | val;
if (dptr -> reset) dptr -> reset (dptr);
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */
if ((r != SCPE_OK) || (newdev == dibp->dev)) return r;
dibp->dev = newdev; /* store */
return SCPE_OK;
}
/* Device disable routine */
/* Show device number for a device */
t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i;
DEVICE *dptr;
UNIT *up;
DIB *dibp;
if (cptr != NULL) return SCPE_ARG;
if ((uptr == NULL) || (val == 0)) return SCPE_IERR;
if (uptr == NULL) return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
for (i = 0; i < dptr -> numunits; i++) { /* check units */
up = (dptr -> units) + i;
if ((up -> flags & UNIT_ATT) || sim_is_active (up))
return SCPE_NOFNC; }
dev_enb = dev_enb & ~val;
if (dptr -> reset) dptr -> reset (dptr);
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
fprintf (st, "devno=%02o", dibp->dev);
if (dibp-> num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1);
return SCPE_OK;
}
/* CPU device handler - should never get here! */
int32 bad_dev (int32 pulse, int32 AC)
{
return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */
}
/* Build device dispatch table */
t_bool build_dev_tab (void)
{
DEVICE *dptr;
DIB *dibp;
uint32 i, j, p;
static const uint8 std_dev[] =
#if defined (PDP4)
{ 000 };
#elif defined (PDP7)
{ 000, 033, 077 };
#else
{ 000, 017, 033, 055, 077 };
#endif
for (i = 0; i < DEV_MAX; i++) { /* clr tables */
dev_tab[i] = NULL;
dev_iors[i] = NULL; }
for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */
dev_tab[std_dev[i]] = &bad_dev;
for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */
if (dibp->iors) dev_iors[p++] = dibp->iors; /* if IORS, add */
for (j = 0; j < dibp->num; j++) { /* loop thru disp */
if (dibp->dsp[j]) { /* any dispatch? */
if (dev_tab[dibp->dev + j]) { /* already filled? */
printf ("%s device number conflict at %02o\n",
dptr->name, dibp->dev + j);
if (sim_log) fprintf (sim_log,
"%s device number conflict at %02o\n",
dptr->name, dibp->dev + j);
return TRUE; }
dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */
} /* end if dsp */
} /* end for j */
} /* end if enb */
} /* end for i */
return FALSE;
}

View File

@@ -23,6 +23,8 @@
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.
05-Oct-02 RMS Added DIB structure
25-Jul-02 RMS Added PDP-4 DECtape support
10-Feb-02 RMS Added PDP-7 DECtape support
25-Nov-01 RMS Revised interrupt structure
27-May-01 RMS Added second Teletype support
@@ -48,6 +50,7 @@
Type 75 paper tape punch
integral real time clock
Type 62 line printer (Hollerith)
Type 550/555 DECtape
PDP7 32K Type 177 EAE Type 649 KSR-33 Teletype
Type 148 mem extension Type 444 paper tape reader
@@ -91,6 +94,7 @@
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_XCT 4 /* nested XCT's */
#define STOP_API 5 /* invalid API int */
#define STOP_NONSTD 6 /* non-std dev num */
/* Peripheral configuration */
@@ -98,17 +102,18 @@
#define ADDRSIZE 13
#define KSR28 0 /* Baudot terminal */
#define TYPE62 0 /* Hollerith printer */
#define TYPE550 0 /* DECtape */
#elif defined (PDP7)
#define ADDRSIZE 15
#define TYPE647 0 /* sixbit printer */
#define DTA 0 /* DECtape */
#define TYPE550 0 /* DECtape */
#define DRM 0 /* drum */
#elif defined (PDP9)
#define ADDRSIZE 15
#define TYPE647 0 /* sixbit printer */
#define RF 0 /* fixed head disk */
#define MTA 0 /* magtape */
#define DTA 0 /* DECtape */
#define TC02 0 /* DECtape */
#define TTY1 0 /* second Teletype */
#define BRMASK 0076000 /* bounds mask */
#elif defined (PDP15)
@@ -117,7 +122,7 @@
#define RF 0 /* fixed head disk */
#define RP 0 /* disk pack */
#define MTA 0 /* magtape */
#define DTA 0 /* DECtape */
#define TC02 0 /* DECtape */
#define TTY1 0 /* second Teletype */
#define BRMASK 0377400 /* bounds mask */
#endif
@@ -150,6 +155,35 @@
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* Device information block */
#define DEV_MAXBLK 8 /* max dev block */
#define DEV_MAX 64 /* total devices */
struct pdp18b_dib {
uint32 dev; /* base dev number */
uint32 num; /* number of slots */
int32 (*iors)(void); /* IORS responder */
int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat);
};
typedef struct pdp18b_dib DIB;
/* Standard device numbers */
#define DEV_PTR 001 /* paper tape reader */
#define DEV_PTP 002 /* paper tape punch */
#define DEV_TTI 003 /* console input */
#define DEV_TTO 004 /* console output */
#define DEV_TTI1 041 /* extra terminals */
#define DEV_TTO1 040
#define DEV_DRM 060 /* drum */
#define DEV_RP 063 /* RP15 */
#define DEV_LPT 065 /* line printer */
#define DEV_RF 070 /* RF09 */
#define DEV_MT 073 /* magtape */
#define DEV_DTA 075 /* dectape */
/* Interrupt system
The interrupt system can be modelled on either the flag driven system
@@ -286,22 +320,6 @@
#define SET_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] | INT_##dv
#define CLR_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] & ~INT_##dv
#define TST_INT(dv) (int_hwre[API_##dv] & INT_##dv)
/* Device enable flags are defined in a single 32b word */
#define ENB_V_DTA 0 /* DECtape */
#define ENB_V_MTA 1 /* magtape */
#define ENB_V_DRM 2 /* drum */
#define ENB_V_RF 3 /* fixed head disk */
#define ENB_V_RP 4 /* disk pack */
#define ENB_V_TTI1 5 /* 2nd teletype */
#define ENB_DTA (1u << ENB_V_DTA)
#define ENB_MTA (1u << ENB_V_MTA)
#define ENB_DRM (1u << ENB_V_DRM)
#define ENB_RF (1u << ENB_V_RF)
#define ENB_RP (1u << ENB_V_RP)
#define ENB_TTI1 (1u << ENB_V_TTI1)
/* I/O status flags for the IORS instruction
@@ -358,5 +376,5 @@
/* Function prototypes */
t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc);

View File

@@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: 18b PDP Simulator Usage
Date: 15-Jul-2002
Date: 15-Nov-2002
COPYRIGHT NOTICE
@@ -47,11 +47,11 @@ PDP-15/ PDP15
If no model is specified, the default is the PDP-9.
sim/ sim_defs.h
sim_rev.h
sim_sock.h
sim_tmxr.h
scp.c
scp_tty.c
sim_rev.c
sim_sock.c
sim_tmxr.c
@@ -80,6 +80,7 @@ PDP-4 CPU PDP-4 CPU with 8KW of memory
TTI,TTO KSR28 console terminal (Baudot code)
LPT Type 62 line printer (Hollerith code)
CLK integral real-time clock
DT Type 550/555 DECtape
PDP-7 CPU PDP-7 CPU with 32KW of memory
- Type 177 extended arithmetic element (EAE)
@@ -121,7 +122,16 @@ PDP-15 CPU PDP-15 CPU with 32KW of memory
DT TC15/TU56 DECtape
MT TC59/TU10 magnetic tape
The DRM, RF, RP, DT, and MT devices can be set DISABLED.
Most devices can be disabled or enabled, by the commands:
SET <dev> DISABLED
SET <dev> ENABLED
The simulator allows most device numbers to be changed, by the command:
SET <dev> DEV=<number>
However, devices can only be BOOTed with their default device numbers.
The 18b PDP simulators implement several unique stop conditions:
@@ -134,7 +144,8 @@ The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9
and PDP-15 support both RIM and BIN format tapes. If the file extension
is .RIM, or the -r switch is specified with LOAD, the file is assumed to
be RIM format; if the file extension is not .RIM, or if the -b switch is
specified, the file is assumed to be BIN format.
specified, the file is assumed to be BIN format. RIM loading requires
that the loading address be specified on the command line.
2.1 CPU
@@ -226,7 +237,7 @@ BOOT PTR copies the RIM loader into memory and starts it running, while
BOOT -F PTR copies the funny format binary loader into memory and starts
it running.
The PTR ATTACH command recognizes one switch, -a for ASCII mode. In
The PTR ATTACH command recognizes one switch, -A for ASCII mode. In
ASCII mode, data returned by the read alphabetic command has the high
order bit automatically set to 1. This allows normal text files to be
used as input to the paper tape reader.
@@ -261,7 +272,7 @@ The paper tape punch (PTP) writes data to a disk file. The POS
register specifies the number of the next data item to be written.
Thus, by changing POS, the user can backspace or advance the punch.
The PTP ATTACH command recognizes one switch, -a for ASCII mode. In
The PTP ATTACH command recognizes one switch, -A for ASCII mode. In
ASCII mode, data is punched with the high order bit clear, and NULL and
DEL characters are supressed. This allows punch output to be processed
with normal text editing utilities.
@@ -289,17 +300,20 @@ Error handling is as follows:
2.2.3 Terminal Input (TTI)
The terminal input (TTI) polls the console keyboard for input. The
input side has one option, UC; when set, it automatically converts lower
case input to upper case.
On the PDP-7, PDP-9, and PDP-15, the terminal interfaces (TTI, TTO)
can be set to one of three modes: KSR, 7B, or 8B. In KSR mode, lower
case input and output characters are automatically converted to upper
case, the high order bit is forced to one on input, and printing of
ALTmode characters is supressed. In 7B mode, input and output characters
are masked to 7 bits. In 8B mode, characters are not modified. Changing
the mode of either interface changes both. The default mode is KSR.
The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default,
with local echo. For backward compatibility, on the PDP-9 and PDP-15
the first terminal input has a second option, FDX; when set, it operates
the terminal input without local echo mode. The second terminal does
not offer local echo.
On the PDP-9 and PDP-15, the console terminal operates, by default,
with local echo. For backward compatibility, the terminal input can
be set to FDX (full duplex), which supresses local echo.
The terminal input implements these registers:
The terminal input (TTI) polls the console keyboard for input. It
implements these registers:
name size comments
@@ -311,11 +325,8 @@ The terminal input implements these registers:
2.2.4 Terminal Output (TTO)
The terminal output (TTO) writes to the simulator console window. The
terminal output has one option, UC; when set, it suppresses lower case
output (so that ALTMODE is not echoed as }).
The terminal output implements these registers:
The terminal output (TTO) writes to the simulator console window. It
implements these registers:
name size comments
@@ -331,7 +342,7 @@ The line printer (LPT) writes data to a disk file. The POS register
specifies the number of the next data item to be written. Thus,
by changing POS, the user can backspace or advance the printer.
The PDP-4 used a Type 62 printer controller, with these registers:
The PDP-4 uses a Type 62 printer controller, with these registers:
name size comments
@@ -345,7 +356,7 @@ The PDP-4 used a Type 62 printer controller, with these registers:
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
The PDP-7 and PDP-7 used a Type 647 printer controller, with these
The PDP-7 and PDP-9 use a Type 647 printer controller, with these
registers:
name size comments
@@ -353,7 +364,7 @@ registers:
BUF 8 last data item processed
INT 1 interrupt pending flag
DONE 1 device done flag
ENABLE 1 interrupt enable (PDP-9 only)
ENABLE 1 interrupt enable (PDP-9 only)
ERR 1 error flag
BPTR 7 print buffer pointer
POS 32 position in the output file
@@ -361,14 +372,14 @@ registers:
STOP_IOE 1 stop on I/O error
LBUF[0:119] 8 line buffer
The PDP-15 used an LP15 printer controller, with these registers:
The PDP-15 uses an LP15 printer controller, with these registers:
name size comments
STA 18 status register
MA 18 DMA memory address
INT 1 interrupt pending flag
ENABLE 1 interrupt enable
ENABLE 1 interrupt enable
LCNT 8 line counter
BPTR 7 print buffer pointer
POS 32 position in the output file
@@ -393,7 +404,7 @@ The real-time clock (CLK) implements these registers:
INT 1 interrupt pending flag
DONE 1 device done flag
ENABLE 1 clock enable
ENABLE 1 clock enable
TIME 24 clock frequency
TPS 8 ticks per second (60 or 50)
@@ -417,10 +428,13 @@ for a connection on the specified port. It assumes that the incoming
connection is a Telnet connection. The connection remain opens until
disconnected by the Telnet client, or by a DETACH TTI1 command.
The second terminal input has one option, UC; when set, it automatically
converts lower case input to upper case. The second terminal output also
has one option, UC; when set, it suppresses lower case output (so that
ALTMODE is not echoed as }).
The second terminal (TTI1,TTO1) can be set to one of three modes: KSR, 7B,
or 8B. In KSR mode, lower case input and output characters are converted
automatically to upper case, the high order bit is forced to one on input,
and printing of ALTmode characters is supressed. In 7B mode, input and
output characters are masked to 7 bits. In 8B mode, characters are not
modified. Changing the mode of either device changes both. The default
mode is KSR.
The SHOW TTI1 CONNECTIONS command displays the current connection to TTI1.
The SHOW TTI1 STATISTICS command displays statistics for the current connection.
@@ -537,10 +551,10 @@ I/O errors cannot occur.
2.6 Type 550/555, TC02/TU55, and TC15/TU56 DECtape (DT)
The PDP-7 used the Type 550 DECtape, a programmed I/O controller. The
PDP-9 used the TC02, and the PDP-15 used the TC15. The TC02 and TC15 were
DMA controllers and programmatically identical. PDP-7 DECtape format had
4 18b words in its block headers and trailers; PDP-9/15 DECtape format
The PDP-4 and PDP-7 use the Type 550 DECtape, a programmed I/O controller.
The PDP-9 uses the TC02, and the PDP-15 uses the TC15. The TC02 and TC15
are DMA controllers and programmatically identical. PDP-4/7 DECtape format
had 4 18b words in its block headers and trailers; PDP-9/15 DECtape format
had 5 18b words.
DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0.
@@ -552,12 +566,14 @@ locked.
Units can also be set ONLINE or OFFLINE.
The Type 550, TC02, and TC15 support both PDP-8 format and PDP-9/11/15
format DECtape images. ATTACH tries to determine the tape format from
the DECtape image; the user can force a particular format with switches:
The Type 550, TC02, and TC15 support supports PDP-8 format, PDP-11 format,
and 18b format DECtape images. ATTACH tries to determine the tape
format from the DECtape image; the user can force a particular format
with switches:
-f foreign (PDP-8) format
-n native (PDP-9/11/15) format
-r PDP-8 format
-s PDP-11 format
-t 18b format
The DECtape controller is a data-only simulator; the timing and mark
track, and block header and trailer, are not stored. Thus, the WRITE
@@ -622,12 +638,11 @@ Error handling is as follows:
error processed as
not attached tape not ready
not attached tape not ready; if STOP_IOE, stop
end of file (read or space) end of physical tape
(write) ignored
end of file bad tape
OS I/O error report error and stop
OS I/O error parity error; if STOP_IOE, stop
2.8 Symbolic Display and Input

View File

@@ -26,6 +26,7 @@
drm (PDP-7) Type 24 serial drum
(PDP-9) RM09 serial drum
05-Feb-02 RMS Added DIB, device number support
03-Feb-02 RMS Fixed bug in reset routine (found by Robert Alan Byer)
06-Jan-02 RMS Revised enable/disable support
25-Nov-01 RMS Revised interrupt structure
@@ -57,17 +58,24 @@
((double) DRM_NUMWDT)))
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern int32 int_hwre[API_HLVL+1];
extern UNIT cpu_unit;
int32 drm_da = 0; /* track address */
int32 drm_ma = 0; /* memory address */
int32 drm_err = 0; /* error flag */
int32 drm_wlk = 0; /* write lock */
int32 drm_time = 10; /* inter-word time */
int32 drm_stopioe = 1; /* stop on error */
DEVICE drm_dev;
int32 drm60 (int32 pulse, int32 AC);
int32 drm61 (int32 pulse, int32 AC);
int32 drm62 (int32 pulse, int32 AC);
int32 drm_iors (void);
t_stat drm_svc (UNIT *uptr);
t_stat drm_reset (DEVICE *dptr);
t_stat drm_boot (int32 unitno);
t_stat drm_boot (int32 unitno, DEVICE *dptr);
/* DRM data structures
@@ -76,9 +84,11 @@ t_stat drm_boot (int32 unitno);
drm_reg DRM register list
*/
DIB drm_dib = { DEV_DRM, 3 ,&drm_iors, { &drm60, &drm61, &drm62 } };
UNIT drm_unit =
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
DRM_SIZE) };
DRM_SIZE) };
REG drm_reg[] = {
{ ORDATA (DA, drm_da, 9) },
@@ -89,19 +99,19 @@ REG drm_reg[] = {
{ ORDATA (WLK, drm_wlk, 32) },
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, ENB_V_DRM), REG_HRO },
{ ORDATA (DEVNO, drm_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB drm_mod[] = {
{ MTAB_XTD|MTAB_VDV, ENB_DRM, NULL, "ENABLED", &set_enb },
{ MTAB_XTD|MTAB_VDV, ENB_DRM, NULL, "DISABLED", &set_dsb },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE drm_dev = {
"DRM", &drm_unit, drm_reg, drm_mod,
1, 8, 20, 1, 8, 18,
NULL, NULL, &drm_reset,
&drm_boot, NULL, NULL };
&drm_boot, NULL, NULL,
&drm_dib, DEV_DISABLE };
/* IOT routines */
@@ -155,20 +165,20 @@ t_stat drm_svc (UNIT *uptr)
int32 i;
t_addr da;
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
drm_err = 1; /* set error */
SET_INT (DRM); /* set done */
return IORETURN (drm_stopioe, SCPE_UNATT); }
da = drm_da * DRM_NUMWDS; /* compute dev addr */
for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
if (uptr -> FUNC == DRM_READ) {
if (uptr->FUNC == DRM_READ) {
if (MEM_ADDR_OK (drm_ma)) /* read, check nxm */
M[drm_ma] = *(((int32 *) uptr -> filebuf) + da); }
M[drm_ma] = *(((int32 *) uptr->filebuf) + da); }
else { if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1;
else { *(((int32 *) uptr -> filebuf) + da) = M[drm_ma];
if (da >= uptr -> hwmark)
uptr -> hwmark = da + 1; } }
else { *(((int32 *) uptr->filebuf) + da) = M[drm_ma];
if (da >= uptr->hwmark)
uptr->hwmark = da + 1; } }
drm_ma = (drm_ma + 1) & ADDRMASK; } /* incr mem addr */
drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
SET_INT (DRM); /* set done */
@@ -202,15 +212,16 @@ static const int32 boot_rom[] = {
0706006, /* DRLR ; load ma */
0706106, /* DRSS ; load da, start */
0706101, /* DRSF ; wait for done */
0602003, /* JMP .-1
0602003, /* JMP .-1 */
0600000 /* JMP 0 ; enter boot */
};
t_stat drm_boot (int32 unitno)
t_stat drm_boot (int32 unitno, DEVICE *dptr)
{
int32 i;
extern int32 saved_PC;
if (drm_dib.dev != DEV_DRM) return STOP_NONSTD; /* non-std addr? */
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
saved_PC = BOOT_START;
return SCPE_OK;

View File

@@ -1,4 +1,4 @@
/* pdp18b_dt.c: PDP-7/9/15 DECtape simulator
/* pdp18b_dt.c: 18b DECtape simulator
Copyright (c) 1993-2002, Robert M Supnik
@@ -23,10 +23,15 @@
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.
dt (PDP-7) Type 550/555 DECtape
dt (PDP-4, PDP-7) Type 550/555 DECtape
(PDP-9) TC02/TU55 DECtape
(PDP-15) TC15/TU56 DECtape
17-Oct-02 RMS Fixed bug in end of reel logic
05-Oct-02 RMS Added DIB, device number support
12-Sep-02 RMS Added 16b format support
13-Aug-02 RMS Corrected Type 550 unit select logic
25-Jul-02 RMS Added PDP-4 support
30-May-02 RMS Widened POS to 32b
10-Feb-02 RMS Added PDP-7 support
06-Jan-02 RMS Revised enable/disable support
@@ -39,11 +44,14 @@
26-Apr-01 RMS Added device enable/disable support
15-Mar-01 RMS Added 129th word to PDP-8 format
18b DECtapes are represented by fixed length data blocks of 18b words. Two
tape formats are supported:
18b DECtapes are represented in memory by fixed length buffer of 32b words.
Three file formats are supported:
16b/18b/36b 256 words per block
12b 86 words per block [129 x 12b]
18b/36b 256 words per block [256 x 18b]
16b 256 words per block [256 x 16b]
12b 129 words per block [129 x 12b]
When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format.
DECtape motion is measured in 3b lines. Time between lines is 33.33us.
Tape density is nominally 300 lines per inch. The format of a DECtape is
@@ -57,9 +65,9 @@
A block consists of five 18b header words, a tape-specific number of data
words, and five 18b trailer words. All systems except the PDP-8 use a
standard block length of 256 words; the PDP-8 uses a standard block length
of 86 words (x 18b = 129 words x 12b). [A PDP-7 DECtape has only four 18b
header words; for consistency, the PDP-7 uses the same format as the PDP-9
and PDP-15 but skips the missing header words.]
of 86 words (x 18b = 129 words x 12b). [A PDP-4/7 DECtape has only four 18b
header words; for consistency, the PDP-4/7 uses the same format as the PDP-9/15
but skips the missing header words.]
Because a DECtape file only contains data, the simulator cannot support
write timing and mark track and can only do a limited implementation
@@ -78,16 +86,22 @@
Write all writes only the data words and dumps the interblock words in the
bit bucket.
The Type 550 controller has a 4b unit select field, for units 1-8; the TC02
has a 3b unit select field, with unit 8 being represented as 0. The code
assumes that the GETUNIT macro returns a unit number in the range of 0-7,
with 8 represented as 0, and an invalid unit as -1.
*/
#include "pdp18b_defs.h"
#define DT_NUMDR 8 /* #drives */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */
#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_8FMT (1 << UNIT_V_8FMT)
#define UNIT_W_UF 3 /* saved flag width */
#define UNIT_11FMT (1 << UNIT_V_11FMT)
#define STATE u3 /* unit state */
#define LASTT u4 /* last time update */
#define DT_WC 030 /* word count */
@@ -112,6 +126,7 @@
#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE))
#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */
#define D11_FILSIZ (D18_CAPAC * sizeof (int16))
/* 12b DECtape constants */
@@ -132,23 +147,23 @@
/* Calculated constants, per unit */
#define DTU_BSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
#define DTU_TSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
#define DTU_LPERB(u) (((u) -> flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
#define DTU_FWDEZ(u) (((u) -> flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
#define DTU_CAPAC(u) (((u) -> flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)
#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)
#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u))
#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u))
#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE)
#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN)
#define DT_QREZ(u) (((u) -> pos) < DT_EZLIN)
#define DT_QFEZ(u) (((u) -> pos) >= ((uint32) DTU_FWDEZ (u)))
#define DT_QREZ(u) (((u)->pos) < DT_EZLIN)
#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u)))
#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u))
/* Status register A */
#if defined (PDP9) || defined (PDP15) /* TC02/TC15 */
#if defined (TC02) /* TC02/TC15 */
#define DTA_V_UNIT 15 /* unit select */
#define DTA_M_UNIT 07
#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT)
@@ -174,13 +189,14 @@
#define DTA_CERF (1u << DTA_V_CERF)
#define DTA_CDTF (1u << DTA_V_CDTF)
#define DTA_RW (0777700 & ~(DTA_CERF | DTA_CDTF))
#define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT)
#define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \
SET_INT (DTA); \
else CLR_INT (DTA);
#else /* Type 550 */
#define DTA_V_UNIT 12 /* unit select */
#define DTA_M_UNIT 07
#define DTA_M_UNIT 017
#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT)
#define DTA_V_MOT 4 /* motion */
#define DTA_M_MOT 03
@@ -197,18 +213,18 @@
#define DTA_FWDRV (1u << DTA_V_MOT)
#define DTA_MODE 0 /* not implemented */
#define DTA_RW 077
#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)]
#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \
SET_INT (DTA); \
else CLR_INT (DTA);
#endif
#define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT)
#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT)
#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC)
/* Status register B */
#if defined (PDP9) || defined (PDP15) /* TC02/TC15 */
#if defined (TC02) /* TC02/TC15 */
#define DTB_V_ERF 17 /* error flag */
#define DTB_V_MRK 16 /* mark trk err */
#define DTB_V_END 15 /* end zone err */
@@ -268,10 +284,10 @@
#define DTS_V_2ND 6 /* next state */
#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */
#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC))
#define DTS_SETSTA(y,z) uptr -> STATE = DTS_STA (y, z)
#define DTS_SET2ND(y,z) uptr -> STATE = (uptr -> STATE & 077) | \
#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z)
#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \
((DTS_STA (y, z)) << DTS_V_2ND)
#define DTS_SET3RD(y,z) uptr -> STATE = (uptr -> STATE & 07777) | \
#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \
((DTS_STA (y, z)) << DTS_V_3RD)
#define DTS_NXTSTA(x) (x >> DTS_V_2ND)
@@ -293,6 +309,8 @@ extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern UNIT cpu_unit;
extern int32 sim_switches;
extern int32 sim_is_running;
int32 dtsa = 0; /* status A */
int32 dtsb = 0; /* status B */
int32 dtdb = 0; /* data buffer */
@@ -302,6 +320,14 @@ int32 dt_dctime = 72000; /* decel time */
int32 dt_substate = 0;
int32 dt_log = 0;
int32 dt_logblk = 0;
static const int32 map_unit[16] = { /* Type 550 unit map */
-1, 1, 2, 3, 4, 5, 6, 7,
0, -1, -1, -1, -1, -1, -1, -1 };
DEVICE dt_dev;
int32 dt75 (int32 pulse, int32 AC);
int32 dt76 (int32 pulse, int32 AC);
int32 dt_iors (void);
t_stat dt_svc (UNIT *uptr);
t_stat dt_reset (DEVICE *dptr);
t_stat dt_attach (UNIT *uptr, char *cptr);
@@ -315,7 +341,6 @@ void dt_seterr (UNIT *uptr, int32 e);
int32 dt_comobv (int32 val);
int32 dt_csum (UNIT *uptr, int32 blk);
int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos);
extern int32 sim_is_running;
/* DT data structures
@@ -325,6 +350,8 @@ extern int32 sim_is_running;
dt_mod DT modifier list
*/
DIB dt_dib = { DEV_DTA, 2, &dt_iors, { &dt75, &dt76 } };
UNIT dt_unit[] = {
{ UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DT_CAPAC) },
@@ -356,7 +383,7 @@ REG dt_reg[] = {
{ FLDATA (BEF, dtsb, DTB_V_BEF) },
#endif
{ FLDATA (ERF, dtsb, DTB_V_ERF) },
#if defined (PDP9) || defined (PDP15)
#if defined (TC02) /* TC02/TC15 */
{ ORDATA (WC, M[DT_WC], 18) },
{ ORDATA (CA, M[DT_CA], 18) },
#endif
@@ -372,29 +399,28 @@ REG dt_reg[] = {
DT_NUMDR, REG_RO) },
{ URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
DT_NUMDR, REG_HRO) },
{ URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
DT_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, ENB_V_DTA), REG_HRO },
{ ORDATA (DEVNO, dt_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB dt_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ UNIT_8FMT, 0, "16b/18b", NULL, NULL },
{ UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL },
{ MTAB_XTD|MTAB_VDV, ENB_DTA, NULL, "ENABLED", &set_enb },
{ MTAB_XTD|MTAB_VDV, ENB_DTA, NULL, "DISABLED", &set_dsb },
{ UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
{ UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
{ UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE dt_dev = {
"DT", dt_unit, dt_reg, dt_mod,
DT_NUMDR, 8, 24, 1, 8, 18,
NULL, NULL, &dt_reset,
NULL, &dt_attach, &dt_detach };
NULL, &dt_attach, &dt_detach,
&dt_dib, DEV_DISABLE };
/* IOT routines */
#if defined (PDP9) || defined (PDP15)
#if defined (TC02) /* TC02/TC15 */
int32 dt75 (int32 pulse, int32 AC)
{
int32 old_dtsa = dtsa, fnc;
@@ -410,10 +436,10 @@ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */
if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa);
uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */
fnc = DTA_GETFNC (dtsa); /* get fnc */
if (((uptr -> flags) & UNIT_DIS) || /* disabled? */
if (((uptr->flags) & UNIT_DIS) || /* disabled? */
(fnc >= FNC_WMRK) || /* write mark? */
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT)) ||
((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT)))
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)) ||
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)))
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); /* new func */
DT_UPDINT;
@@ -434,11 +460,9 @@ if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */
return AC;
}
#else
#else /* Type 550 */
int32 dt75 (int32 pulse, int32 AC)
{
int32 old_dtsa = dtsa;
if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */
AC = AC | IOT_SKP;
else if (((pulse & 041) == 041) && (dtsb & DTB_ERF)) /* MMEF */
@@ -455,18 +479,20 @@ return AC;
int32 dt76 (int32 pulse, int32 AC)
{
int32 fnc, mot;
UNIT *uptr;
int32 fnc, mot, unum;
UNIT *uptr = NULL;
uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */
unum = DTA_GETUNIT (dtsa); /* get unit no */
if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */
if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */
AC = AC | IOT_SKP;
if (pulse & 002) { /* MMRS */
dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */
mot = DTS_GETMOT (uptr -> STATE); /* get motion */
if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr -> STATE & 0777700))
dtsb = dtsb | DTB_GO; /* accel? go */
if (uptr) { /* valid unit? */
mot = DTS_GETMOT (uptr->STATE); /* get motion */
if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */
if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700))
dtsb = dtsb | DTB_GO; } /* accel? go */
AC = (AC & ~DMASK) | dtsb; }
if ((pulse & 044) == 044) { /* MMSE */
if ((dtsa ^ AC) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */
@@ -476,10 +502,11 @@ else if ((pulse & 044) == 004) { /* MMLC */
dtsa = (dtsa & ~DTA_RW) | (AC & DTA_RW); /* load dtsa */
dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR);
fnc = DTA_GETFNC (dtsa); /* get fnc */
if (((uptr -> flags) & UNIT_DIS) || /* disabled? */
if ((uptr == NULL) || /* invalid? */
((uptr->flags) & UNIT_DIS) || /* disabled? */
(fnc >= FNC_WMRK) || /* write mark? */
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK)) ||
((fnc == FNC_WALL) && (uptr -> flags & UNIT_WLK)))
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) ||
((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK)))
dt_seterr (uptr, DTB_SEL); /* select err */
else dt_newsa (dtsa); }
DT_UPDINT;
@@ -491,10 +518,13 @@ return AC;
void dt_deselect (int32 oldf)
{
int32 old_unit = DTA_GETUNIT (oldf);
UNIT *uptr = dt_dev.units + old_unit;
int32 old_mot = DTS_GETMOT (uptr -> STATE);
int32 old_unit, old_mot;
UNIT *uptr;
old_unit = DTA_GETUNIT (oldf); /* get unit no */
if (old_unit < 0) return; /* invalid? */
uptr = dt_dev.units + old_unit; /* get unit */
old_mot = DTS_GETMOT (uptr->STATE);
if (old_mot >= DTS_ATSF) /* at speed? */
dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR));
else if (old_mot >= DTS_ACCF) /* accelerating? */
@@ -525,19 +555,19 @@ return;
void dt_newsa (int32 newf)
{
int32 new_unit, prev_mot, prev_fnc, new_fnc;
int32 new_unit, prev_mot, new_fnc;
int32 prev_mving, new_mving, prev_dir, new_dir;
UNIT *uptr;
new_unit = DTA_GETUNIT (newf); /* new, old units */
new_unit = DTA_GETUNIT (newf); /* new unit */
if (new_unit < 0) return; /* invalid? */
uptr = dt_dev.units + new_unit;
if ((uptr -> flags & UNIT_ATT) == 0) { /* new unit attached? */
if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */
dt_seterr (uptr, DTB_SEL); /* no, error */
return; }
prev_mot = DTS_GETMOT (uptr -> STATE); /* previous motion */
prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */
prev_mving = prev_mot != DTS_STOP; /* previous moving? */
prev_dir = prev_mot & DTS_DIR; /* previous dir? */
prev_fnc = DTS_GETFNC (uptr -> STATE); /* prev function? */
new_mving = (newf & DTA_STSTP) != 0; /* new moving? */
new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */
new_fnc = DTA_GETFNC (newf); /* new function? */
@@ -603,15 +633,15 @@ void dt_newfnc (UNIT *uptr, int32 newsta)
int32 fnc, dir, blk, unum, relpos, newpos;
uint32 oldpos;
oldpos = uptr -> pos; /* save old pos */
oldpos = uptr->pos; /* save old pos */
if (dt_setpos (uptr)) return; /* update pos */
uptr -> STATE = newsta; /* update state */
fnc = DTS_GETFNC (uptr -> STATE); /* set variables */
dir = DTS_GETMOT (uptr -> STATE) & DTS_DIR;
uptr->STATE = newsta; /* update state */
fnc = DTS_GETFNC (uptr->STATE); /* set variables */
dir = DTS_GETMOT (uptr->STATE) & DTS_DIR;
unum = uptr - dt_dev.units;
if (oldpos == uptr -> pos) /* bump pos */
uptr -> pos = uptr -> pos + (dir? -1: 1);
blk = DT_LIN2BL (uptr -> pos, uptr);
if (oldpos == uptr->pos) /* bump pos */
uptr->pos = uptr->pos + (dir? -1: 1);
blk = DT_LIN2BL (uptr->pos, uptr);
if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */
dt_seterr (uptr, DTB_END); /* set ez flag, stop */
@@ -638,12 +668,12 @@ case FNC_SRCH: /* search */
break;
case FNC_WRIT: /* write */
case FNC_READ: /* read */
#if defined (PDP9) || defined (PDP15)
#if defined (TC02) /* TC02/TC15 */
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; }
relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */
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, DTB_SEL);
@@ -659,7 +689,7 @@ 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 { newpos = ((uptr -> pos) / DT_WSIZE) * DT_WSIZE;
else { newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE;
if (!dir) newpos = newpos + (DT_WSIZE - 1); }
if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk)))
printf ("[DT%d: read all block %d %s%s\n",
@@ -669,12 +699,12 @@ case FNC_WALL: /* write all */
default:
dt_seterr (uptr, DTB_SEL); /* bad state */
return; }
#if defined (PDP7)
#if defined (TYPE550) /* Type 550 */
if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */
dtsb = dtsb | DTB_DTF; /* set data flag */
DT_UPDINT; }
#endif
sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime);
sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
return;
}
@@ -699,13 +729,13 @@ return;
t_bool dt_setpos (UNIT *uptr)
{
uint32 new_time, ut, ulin, udelt;
int32 mot = DTS_GETMOT (uptr -> STATE);
int32 mot = DTS_GETMOT (uptr->STATE);
int32 unum, delta;
new_time = sim_grtime (); /* current time */
ut = new_time - uptr -> LASTT; /* elapsed time */
ut = new_time - uptr->LASTT; /* elapsed time */
if (ut == 0) return FALSE; /* no time gone? exit */
uptr -> LASTT = new_time; /* update last time */
uptr->LASTT = new_time; /* update last time */
switch (mot & ~DTS_DIR) { /* case on motion */
case DTS_STOP: /* stop */
delta = 0;
@@ -721,12 +751,12 @@ case DTS_ACCF: /* accelerating */
case DTS_ATSF: /* at speed */
delta = ut / (uint32) dt_ltime;
break; }
if (mot & DTS_DIR) uptr -> pos = uptr -> pos - delta; /* update pos */
else uptr -> pos = uptr -> pos + delta;
if ((uptr -> pos < 0) ||
(uptr -> pos > ((uint32) (DTU_FWDEZ (uptr) + DT_EZLIN)))) {
if (mot & DTS_DIR) uptr->pos = uptr->pos - delta; /* update pos */
else uptr->pos = uptr->pos + delta;
if (((int32) uptr->pos < 0) ||
((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
detach_unit (uptr); /* off reel? */
uptr -> STATE = uptr -> pos = 0;
uptr->STATE = uptr->pos = 0;
unum = uptr - dt_dev.units;
if (unum == DTA_GETUNIT (dtsa)) /* if selected, */
dt_seterr (uptr, DTB_SEL); /* error */
@@ -741,10 +771,10 @@ return FALSE;
t_stat dt_svc (UNIT *uptr)
{
int32 mot = DTS_GETMOT (uptr -> STATE);
int32 mot = DTS_GETMOT (uptr->STATE);
int32 dir = mot & DTS_DIR;
int32 fnc = DTS_GETFNC (uptr -> STATE);
int32 *bptr = uptr -> filebuf;
int32 fnc = DTS_GETFNC (uptr->STATE);
int32 *bptr = uptr->filebuf;
int32 unum = uptr - dt_dev.units;
int32 blk, wrd, ma, relpos;
t_addr ba;
@@ -759,12 +789,12 @@ t_addr ba;
switch (mot) {
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? */
uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */
if (uptr->STATE) /* not stopped? */
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 */
dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */
return SCPE_OK;
case DTS_ATSF: case DTS_ATSR: /* at speed */
break; /* check function */
@@ -783,20 +813,20 @@ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */
if (DT_QEZ (uptr)) { /* in end zone? */
dt_seterr (uptr, DTB_END); /* end zone error */
return SCPE_OK; }
blk = DT_LIN2BL (uptr -> pos, uptr); /* get block # */
blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */
switch (fnc) { /* at speed, check fnc */
case FNC_MOVE: /* move */
dt_seterr (uptr, DTB_END); /* end zone error */
return SCPE_OK;
case DTS_OFR: /* off reel */
detach_unit (uptr); /* must be deselected */
uptr -> STATE = uptr -> pos = 0; /* no visible action */
uptr->STATE = uptr->pos = 0; /* no visible action */
break;
/* TC02/TC15 service */
/* Search */
#if defined (PDP9) || defined (PDP15)
#if defined (TC02) /* TC02/TC15 */
case FNC_SRCH: /* search */
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
@@ -823,7 +853,7 @@ case FNC_SRCH: /* search */
*/
case FNC_READ: /* read */
wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
switch (dt_substate) { /* case on substate */
case DTO_SOB: /* start of block */
if (dtsb & DTB_DTF) { /* DTF set? */
@@ -871,7 +901,7 @@ case FNC_READ: /* read */
*/
case FNC_WRIT: /* write */
wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */
wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */
switch (dt_substate) { /* case on substate */
case DTO_SOB: /* start block */
if (dtsb & DTB_DTF) { /* DTF set? */
@@ -891,7 +921,7 @@ case FNC_WRIT: /* write */
dtdb = dt_substate? 0: M[ma]; /* get word */
if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */
bptr[ba] = dtdb; /* write word */
if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1;
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (M[DT_WC] == 0) dt_substate = DTO_WCO;
if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */
sim_activate (uptr, DT_WSIZE * dt_ltime);
@@ -917,13 +947,13 @@ case FNC_RALL:
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK;
ma = M[DT_CA] & ADDRMASK; /* mem addr */
if ((relpos >= DT_HTLIN) && /* in data zone? */
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
wrd = DT_LIN2WD (uptr -> pos, uptr);
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
dtdb = bptr[ba]; } /* get tape word */
else dtdb = dt_gethdr (uptr, blk, relpos); /* get hdr */
@@ -951,7 +981,7 @@ case FNC_WALL:
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */
relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */
M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */
M[DT_CA] = (M[DT_CA] + 1) & DMASK;
ma = M[DT_CA] & ADDRMASK; /* mem addr */
@@ -959,10 +989,10 @@ case FNC_WALL:
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
dtdb = M[ma]; /* get mem word */
if (dir) dtdb = dt_comobv (dtdb);
wrd = DT_LIN2WD (uptr -> pos, uptr);
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
bptr[ba] = dtdb; /* write word */
if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; }
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; }
/* /* ignore hdr */
sim_activate (uptr, DT_WSIZE * dt_ltime);
if (M[DT_WC] == 0) dt_substate = DTO_WCO;
@@ -977,7 +1007,7 @@ case FNC_WALL:
/* Type 550 service */
/* Search */
#else
#else /* Type 550 */
case FNC_SRCH: /* search */
if (dtsb & DTB_DTF) { /* DTF set? */
dt_seterr (uptr, DTB_TIM); /* timing error */
@@ -994,10 +1024,10 @@ case FNC_READ: case FNC_RALL:
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */
relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */
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);
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
dtdb = bptr[ba]; /* get tape word */
dtsb = dtsb | DTB_DTF; } /* set flag */
@@ -1022,14 +1052,14 @@ case FNC_WRIT: case FNC_WALL:
dt_seterr (uptr, DTB_TIM); /* timing error */
return SCPE_OK; }
sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */
relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */
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);
wrd = DT_LIN2WD (uptr->pos, uptr);
ba = (blk * DTU_BSIZE (uptr)) + wrd;
if (dir) bptr[ba] = dt_comobv (dtdb); /* get data word */
else bptr[ba] = dtdb;
if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1;
if (ba >= uptr->hwmark) uptr->hwmark = ba + 1;
if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1))
dtsb = dtsb | DTB_BEF; /* end block */
else dtsb = dtsb | DTB_DTF; } /* else next word */
@@ -1056,7 +1086,7 @@ return SCPE_OK;
void dt_seterr (UNIT *uptr, int32 e)
{
int32 mot = DTS_GETMOT (uptr -> STATE);
int32 mot = DTS_GETMOT (uptr->STATE);
dtsa = dtsa & ~DTA_STSTP; /* clear go */
dtsb = dtsb | DTB_ERF | e; /* set error flag */
@@ -1077,7 +1107,7 @@ int32 newpos;
if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */
else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */
sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime);
sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
return;
}
@@ -1096,17 +1126,17 @@ return dat;
int32 dt_csum (UNIT *uptr, int32 blk)
{
int32 *bptr = uptr -> filebuf;
int32 *bptr = uptr->filebuf;
int32 ba = blk * DTU_BSIZE (uptr);
int32 i, csum, wrd;
#if defined (PDP9) || defined (PDP15)
#if defined (TC02) /* TC02/TC15 */
csum = 077; /* init csum */
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i] ^ 0777777; /* get ~word */
csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; }
return (csum & 077);
#else
#else /* Type 550 */
csum = 0777777;
for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */
wrd = bptr[ba + i]; /* get word */
@@ -1123,14 +1153,14 @@ int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos)
int32 wrd = relpos / DT_WSIZE;
if (wrd == DT_BLKWD) return blk; /* fwd blknum */
#if defined (PDP9) || defined (PDP15)
#if defined (TC02) /* TC02/TC15 */
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk) << 12);
#else
if (wrd == DT_CSMWD) return 0777777; /* rev csum */
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */
return (dt_csum (uptr, blk));
#endif
#endif /* Type 550 */
if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */
return dt_comobv (blk);
return 0; /* all others */
@@ -1146,7 +1176,7 @@ UNIT *uptr;
for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */
uptr = dt_dev.units + i;
if (sim_is_running) { /* CAF? */
prev_mot = DTS_GETMOT (uptr -> STATE); /* get motion */
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);
@@ -1154,8 +1184,8 @@ for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */
DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
} }
else { sim_cancel (uptr); /* sim reset */
uptr -> STATE = 0;
uptr -> LASTT = sim_grtime (); } }
uptr->STATE = 0;
uptr->LASTT = sim_grtime (); } }
dtsa = dtsb = 0; /* clear status */
DT_UPDINT; /* reset interrupt */
return SCPE_OK;
@@ -1174,101 +1204,126 @@ return 0;
/* Attach routine
Determine native or PDP8 format
Determine 12b, 16b, or 18b/36b format
Allocate buffer
If PDP8, read 12b format and convert to 18b in buffer
If native, read data into buffer
If 12b, read 12b format and convert to 18b in buffer
If 16b, read 16b format and convert to 18b in buffer
If 18b/36b, read data into buffer
*/
t_stat dt_attach (UNIT *uptr, char *cptr)
{
uint16 pdp8b[D8_NBSIZE];
int32 k, p, *bptr;
uint16 pdp11b[D18_BSIZE];
uint32 k, p, *bptr;
t_stat r;
t_addr ba;
uptr -> flags = uptr -> flags & ~UNIT_8FMT;
r = attach_unit (uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* fail? */
if (sim_switches & SWMASK ('F')) /* att foreign? */
uptr -> flags = uptr -> flags | UNIT_8FMT; /* PDP8 = T */
else if (!(sim_switches & SWMASK ('N'))) { /* autosize? */
if ((fseek (uptr -> fileref, 0, SEEK_END) == 0) &&
(p = ftell (uptr -> fileref)) &&
(p == D8_FILSIZ)) uptr -> flags = uptr -> flags | UNIT_8FMT; }
uptr -> capac = DTU_CAPAC (uptr); /* set capacity */
uptr -> filebuf = calloc (uptr -> capac, sizeof (int32));
if (uptr -> filebuf == NULL) { /* can't alloc? */
if (r != SCPE_OK) return r; /* error? */
uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default 18b */
if (sim_switches & SWMASK ('R')) /* att 12b? */
uptr->flags = uptr->flags | UNIT_8FMT;
else if (sim_switches & SWMASK ('S')) /* att 16b? */
uptr->flags = uptr->flags | UNIT_11FMT;
else if (!(sim_switches & SWMASK ('T')) && /* autosize? */
(fseek (uptr->fileref, 0, SEEK_END) == 0) &&
((p = ftell (uptr->fileref)) != 0)) {
if (p == D8_FILSIZ) uptr->flags = uptr->flags | UNIT_8FMT;
if (p == D11_FILSIZ) uptr->flags = uptr->flags | UNIT_11FMT; }
uptr->capac = DTU_CAPAC (uptr); /* set capacity */
uptr->filebuf = calloc (uptr->capac, sizeof (int32));
if (uptr->filebuf == NULL) { /* can't alloc? */
detach_unit (uptr);
return SCPE_MEM; }
printf ("%DT: buffering file in memory\n");
rewind (uptr -> fileref); /* start of file */
if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */
bptr = uptr -> filebuf; /* file buffer */
for (ba = 0; ba < uptr -> capac; ) { /* loop thru file */
k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr -> fileref);
if (k == 0) break;
for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0;
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */
bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
((uint32) (pdp8b[k + 1] >> 6) & 077);
bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) |
(pdp8b[k + 2] & 07777);
ba = ba + 2; } /* end blk loop */
} /* end file loop */
uptr -> hwmark = ba; } /* end if */
else uptr -> hwmark = fxread (uptr -> filebuf, sizeof (int32),
uptr -> capac, uptr -> fileref);
uptr -> flags = uptr -> flags | UNIT_BUF; /* set buf flag */
uptr -> pos = DT_EZLIN; /* beyond leader */
uptr -> LASTT = sim_grtime (); /* last pos update */
bptr = uptr->filebuf; /* file buffer */
if (uptr->flags & UNIT_8FMT) printf ("DT: 12b format");
else if (uptr->flags & UNIT_11FMT) printf ("DT: 16b format");
else printf ("DT: 18b/36b format");
printf (", buffering file in memory\n");
rewind (uptr->fileref); /* start of file */
if (uptr->flags & UNIT_8FMT) { /* 12b? */
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref);
if (k == 0) break;
for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0;
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */
bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) |
((uint32) (pdp8b[k + 1] >> 6) & 077);
bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) |
(pdp8b[k + 2] & 07777);
ba = ba + 2; } /* end blk loop */
} /* end file loop */
uptr->hwmark = ba; } /* end if */
else if (uptr->flags & UNIT_11FMT) { /* 16b? */
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
k = fxread (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref);
if (k == 0) break;
for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0;
for (k = 0; k < D18_BSIZE; k++)
bptr[ba++] = pdp11b[k]; }
uptr->hwmark = ba; } /* end elif */
else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32),
uptr->capac, uptr->fileref);
uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */
uptr->pos = DT_EZLIN; /* beyond leader */
uptr->LASTT = sim_grtime (); /* last pos update */
return SCPE_OK;
}
/* Detach routine
Cancel in progress operation
If PDP8, convert 18b buffer to 12b and write to file
If native, write buffer to file
If 12b, convert 18b buffer to 12b and write to file
If 16b, convert 18b buffer to 16b and write to file
If 18b/36b, write buffer to file
Deallocate buffer
*/
t_stat dt_detach (UNIT* uptr)
{
uint16 pdp8b[D8_NBSIZE];
int32 k, *bptr;
uint16 pdp11b[D18_BSIZE];
uint32 k, *bptr;
int32 unum = uptr - dt_dev.units;
t_addr ba;
if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK;
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK;
if (sim_is_active (uptr)) {
sim_cancel (uptr);
if ((unum == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) {
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
DT_UPDINT; }
uptr -> STATE = uptr -> pos = 0; }
if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { /* any data? */
uptr->STATE = uptr->pos = 0; }
bptr = uptr->filebuf; /* file buffer */
if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
printf ("DT: writing buffer to file\n");
rewind (uptr -> fileref); /* start of file */
if (uptr -> flags & UNIT_8FMT) { /* PDP8? */
bptr = uptr -> filebuf; /* file buffer */
for (ba = 0; ba < uptr -> hwmark; ) { /* loop thru buf */
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */
pdp8b[k] = (bptr[ba] >> 6) & 07777;
pdp8b[k + 1] = ((bptr[ba] & 077) << 6) |
((bptr[ba + 1] >> 12) & 077);
pdp8b[k + 2] = bptr[ba + 1] & 07777;
ba = ba + 2; } /* end loop blk */
fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr -> fileref);
if (ferror (uptr -> fileref)) break; } /* end loop file */
} /* end if PDP8 */
else fxwrite (uptr -> filebuf, sizeof (int32), /* write file */
uptr -> hwmark, uptr -> fileref);
if (ferror (uptr -> fileref)) perror ("I/O error"); } /* end if hwmark */
free (uptr -> filebuf); /* release buf */
uptr -> flags = uptr -> flags & ~UNIT_BUF; /* clear buf flag */
uptr -> filebuf = NULL; /* clear buf ptr */
uptr -> flags = uptr -> flags & ~UNIT_8FMT; /* default fmt */
uptr -> capac = DT_CAPAC; /* default size */
rewind (uptr->fileref); /* start of file */
if (uptr->flags & UNIT_8FMT) { /* 12b? */
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */
pdp8b[k] = (bptr[ba] >> 6) & 07777;
pdp8b[k + 1] = ((bptr[ba] & 077) << 6) |
((bptr[ba + 1] >> 12) & 077);
pdp8b[k + 2] = bptr[ba + 1] & 07777;
ba = ba + 2; } /* end loop blk */
fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref);
if (ferror (uptr->fileref)) break; } /* end loop file */
} /* end if 12b */
else if (uptr->flags & UNIT_11FMT) { /* 16b? */
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */
for (k = 0; k < D18_BSIZE; k++) /* loop blk */
pdp11b[k] = bptr[ba++] & 0177777;
fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref);
if (ferror (uptr->fileref)) break; } /* end loop file */
} /* end if 16b */
else fxwrite (uptr->filebuf, sizeof (int32), /* write file */
uptr->hwmark, uptr->fileref);
if (ferror (uptr->fileref)) perror ("I/O error"); } /* end if hwmark */
free (uptr->filebuf); /* release buf */
uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */
uptr->filebuf = NULL; /* clear buf ptr */
uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default fmt */
uptr->capac = DT_CAPAC; /* default size */
return detach_unit (uptr);
}

View File

@@ -27,6 +27,7 @@
(PDP-7,9) Type 647 line printer
(PDP-15) LP15 line printer
05-Oct-02 RMS Added DIB, device number support
30-May-02 RMS Widened POS to 32b
03-Feb-02 RMS Fixed typo (found by Robert Alan Byer)
25-Nov-01 RMS Revised interrupt structure
@@ -40,18 +41,32 @@
#include "pdp18b_defs.h"
DEVICE lpt_dev;
int32 lpt65 (int32 pulse, int32 AC);
int32 lpt66 (int32 pulse, int32 AC);
int32 lpt_iors (void);
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
extern int32 int_hwre[API_HLVL+1];
DIB lpt_dib = { DEV_LPT, 2, &lpt_iors, { &lpt65, &lpt66 } };
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
MTAB lpt_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
#if defined (TYPE62)
#define BPTR_MAX 40 /* pointer max */
#define LPT_BSIZE 120 /* line size */
#define BPTR_MASK 077 /* buf ptr max */
extern int32 int_hwre[API_HLVL+1];
int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
char lpt_buf[LPT_BSIZE + 1] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
/* Type 62 LPT data structures
lpt_dev LPT device descriptor
@@ -59,9 +74,6 @@ t_stat lpt_reset (DEVICE *dptr);
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
@@ -73,13 +85,15 @@ REG lpt_reg[] = {
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ ORDATA (DEVNO, lpt_dib.dev, 6), REG_HRO },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&lpt_dib, DEV_DISABLE };
/* Type 62 line printer: IOT routines */
@@ -97,9 +111,9 @@ if ((pulse & 001) && TST_INT (LPT)) AC = IOT_SKP | AC; /* LPSF */
if ((pulse & 042) == 002) CLR_INT (LPT); /* LPCF */
if (((pulse & 042) == 042) && (bptr < BPTR_MAX)) { /* LPLD */
i = bptr * 3; /* cvt to chr ptr */
lpt_buf[i++] = lpt_trans[(AC >> 12) & 077];
lpt_buf[i++] = lpt_trans[(AC >> 6) & 077];
lpt_buf[i++] = lpt_trans[AC & 077];
lpt_buf[i] = lpt_trans[(AC >> 12) & 077];
lpt_buf[i + 1] = lpt_trans[(AC >> 6) & 077];
lpt_buf[i + 2] = lpt_trans[AC & 077];
bptr = (bptr + 1) & BPTR_MASK; }
if (pulse & 004) { /* LPSE */
sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */
@@ -189,13 +203,10 @@ return (TST_INT (LPT)? IOS_LPT: 0) |
#elif defined (TYPE647)
#define LPT_BSIZE 120 /* line size */
extern int32 int_hwre[API_HLVL+1];
int32 lpt_done = 0, lpt_ie = 1, lpt_err = 0;
int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0;
char lpt_buf[LPT_BSIZE] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, char *cptr);
t_stat lpt_detach (UNIT *uptr);
@@ -206,9 +217,6 @@ t_stat lpt_detach (UNIT *uptr);
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) },
@@ -223,13 +231,15 @@ REG lpt_reg[] = {
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ ORDATA (DEVNO, lpt_dib.dev, 6), REG_HRO },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, &lpt_detach };
NULL, &lpt_attach, &lpt_detach,
&lpt_dib, DEV_DISABLE };
/* Type 647 line printer: IOT routines */
@@ -404,13 +414,10 @@ return detach_unit (uptr);
#define STA_CLR 0003777 /* always clear */
extern int32 M[];
extern int32 int_hwre[API_HLVL+1];
int32 lpt_sta = 0, lpt_ie = 1, lpt_stopioe = 0;
int32 mode = 0, lcnt = 0, bptr = 0;
char lpt_buf[LPT_BSIZE] = { 0 };
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
int32 lpt_updsta (int32 new);
/* LP15 LPT data structures
@@ -420,9 +427,6 @@ int32 lpt_updsta (int32 new);
lpt_reg LPT register list
*/
UNIT lpt_unit = {
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
REG lpt_reg[] = {
{ ORDATA (STA, lpt_sta, 18) },
{ ORDATA (CA, M[LPT_CA], 18) },
@@ -435,13 +439,15 @@ REG lpt_reg[] = {
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
{ BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) },
{ ORDATA (DEVNO, lpt_dib.dev, 6), REG_HRO },
{ NULL } };
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, NULL,
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&lpt_dib, DEV_DISABLE };
/* LP15 line printer: IOT routines */

View File

@@ -26,6 +26,10 @@
mt (PDP-9) TC59 magtape
(PDP-15) TC59D magtape
30-Oct-02 RMS Revised BOT handling, added error record handling
05-Oct-02 RMS Added DIB, device number support
Revamped error recovery
28-Aug-02 RMS Added end of medium support
30-May-02 RMS Widened POS to 32b
22-Apr-02 RMS Added maximum record length test
06-Jan-02 RMS Revised enabled/disable support
@@ -57,10 +61,10 @@
#define MT_NUMDR 8 /* #drives */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_WLK 1 << UNIT_V_WLK
#define UNIT_W_UF 2 /* saved flag width */
#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_PNU (1 << UNIT_V_PNU)
#define USTAT u3 /* unit status */
#define UNUM u4 /* unit number */
#define MT_MAXFR (1 << 16) /* max record length */
#define DBSIZE (1 << 12) /* max word count */
#define DBMASK (DBSIZE - 1)
@@ -94,7 +98,7 @@
#define GET_TYPE(x) (((x) >> CU_V_TYPE) & CU_M_TYPE)
#define PACKED(x) (((x) & CU_DUMP) || (GET_TYPE (x) != TY_9TK))
/* Status - stored in mt_sta or (*) uptr -> USTAT */
/* Status - stored in mt_sta or (*) uptr->USTAT */
#define STA_ERR 0400000 /* error */
#define STA_REW 0200000 /* *rewinding */
@@ -117,17 +121,24 @@
/* error flags */
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern int32 int_hwre[API_HLVL+1];
extern UNIT cpu_unit;
int32 mt_cu = 0; /* command/unit */
int32 mt_sta = 0; /* status register */
int32 mt_time = 10; /* record latency */
int32 mt_stopioe = 1; /* stop on error */
DEVICE mt_dev;
int32 mt (int32 pulse, int32 AC);
int32 mt_iors (void);
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, char *cptr);
t_stat mt_detach (UNIT *uptr);
int32 mt_updcsta (UNIT *uptr, int32 val);
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
UNIT *mt_busy (void);
/* MT data structures
@@ -138,6 +149,8 @@ UNIT *mt_busy (void);
mt_mod MT modifier list
*/
DIB mt_dib = { DEV_MT, 1, &mt_iors, { &mt } };
UNIT mt_unit[] = {
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
@@ -159,23 +172,21 @@ REG mt_reg[] = {
{ URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, 32, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
MT_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, ENB_V_MTA), REG_HRO },
{ ORDATA (DEVNO, mt_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB mt_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VDV, ENB_MTA, NULL, "ENABLED", &set_enb },
{ MTAB_XTD|MTAB_VDV, ENB_MTA, NULL, "DISABLED", &set_dsb },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE mt_dev = {
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &mt_detach };
NULL, &mt_attach, &mt_detach,
&mt_dib, DEV_DISABLE };
/* IOT routine */
@@ -202,12 +213,12 @@ if ((pulse & 064) == 024) /* MTCM, MTLC */
if (pulse == 004) { /* MTGO */
f = GET_CMD (mt_cu); /* get function */
if (mt_busy () || (sim_is_active (uptr)) ||
(((f == FN_SPACER) || (f == FN_REWIND)) & (uptr -> pos == 0)) ||
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT))
|| ((uptr -> flags & UNIT_ATT) == 0) || (f == FN_NOP))
(((f == FN_SPACER) || (f == FN_REWIND)) & (uptr->USTAT & STA_BOT)) ||
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr->flags & UNIT_WPRT))
|| ((uptr->flags & UNIT_ATT) == 0) || (f == FN_NOP))
mt_sta = mt_sta | STA_ILL; /* illegal op flag */
else { if (f == FN_REWIND) uptr -> USTAT = STA_REW; /* rewind? */
else mt_sta = uptr -> USTAT = 0; /* no, clear status */
else { if (f == FN_REWIND) uptr->USTAT = STA_REW; /* rewind? */
else mt_sta = uptr->USTAT = 0; /* no, clear status */
sim_activate (uptr, mt_time); } } /* start io */
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return AC;
@@ -221,53 +232,44 @@ return AC;
t_stat mt_svc (UNIT *uptr)
{
int32 c, c1, c2, c3, f, i, p, u, err;
int32 c, c1, c2, c3, f, i, p, u, err, pnu;
int32 wc, xma;
t_stat rval;
t_mtrlnt tbc, cbc;
t_mtrlnt abc, tbc, cbc;
static uint8 dbuf[(3 * DBSIZE)];
static t_mtrlnt bceof = { 0 };
static t_mtrlnt bceof = MTR_TMK;
u = uptr -> UNUM; /* get unit number */
if (uptr -> USTAT & STA_REW) { /* rewind? */
uptr -> pos = 0; /* update position */
if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
else uptr -> USTAT = 0;
err = 0;
u = uptr - mt_dev.units; /* get unit number */
f = GET_CMD (mt_cu); /* get command */
pnu = MT_TST_PNU (uptr); /* get pos not upd */
MT_CLR_PNU (uptr); /* and clear */
if (uptr->USTAT & STA_REW) { /* rewind? */
uptr->pos = 0; /* update position */
if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_BOT;
else uptr->USTAT = 0;
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr, STA_DON);
return SCPE_OK; }
f = GET_CMD (mt_cu); /* get command */
if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */
mt_updcsta (uptr, STA_ILL); /* illegal operation */
return IORETURN (mt_stopioe, SCPE_UNATT); }
if ((f == FN_WRITE) || (f == FN_WREOF)) { /* write? */
if (uptr -> flags & UNIT_WPRT) { /* write locked? */
if (uptr->flags & UNIT_WPRT) { /* write locked? */
mt_updcsta (uptr, STA_ILL); /* illegal operation */
return SCPE_OK; }
mt_cu = mt_cu & ~CU_ERASE; } /* clear erase flag */
err = 0;
rval = SCPE_OK;
switch (f) { /* case on function */
/* Unit service, continued */
case FN_READ: /* read */
case FN_CMPARE: /* read/compare */
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
(feof (uptr -> fileref))) {
uptr -> USTAT = STA_EOT;
mt_updcsta (uptr, STA_RLE);
if (mt_rdlntf (uptr, &tbc, &err)) { /* read rec lnt, err? */
mt_updcsta (uptr, STA_RLE); /* set RLE flag */
break; }
if (tbc == 0) { /* tape mark? */
uptr -> USTAT = STA_EOF;
mt_updcsta (uptr, STA_RLE);
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
break; }
tbc = MTRL (tbc); /* ignore error flag */
if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */
wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */
cbc = PACKED (mt_cu)? wc * 3: wc * 2; /* expected bc */
@@ -275,9 +277,11 @@ case FN_CMPARE: /* read/compare */
if (tbc < cbc) { /* record small? */
cbc = tbc; /* use smaller */
wc = PACKED (mt_cu)? ((tbc + 2) / 3): ((tbc + 1) / 2); }
i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref);
for ( ; i < cbc; i++) dbuf[i] = 0; /* fill with 0's */
err = ferror (uptr -> fileref);
abc = fxread (dbuf, sizeof (int8), cbc, uptr->fileref);
if (err = ferror (uptr->fileref)) { /* error */
MT_SET_PNU (uptr); /* pos not upd */
break; }
for ( ; abc < cbc; abc++) dbuf[abc] = 0; /* fill with 0's */
for (i = p = 0; i < wc; i++) { /* copy buffer */
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
@@ -295,14 +299,15 @@ case FN_CMPARE: /* read/compare */
(PACKED (mt_cu)? 0777777: 0177777)))) {
mt_updcsta (uptr, STA_CPE);
break; } }
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt));
break;
case FN_WRITE: /* write */
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fseek (uptr->fileref, uptr->pos, SEEK_SET);
wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */
tbc = PACKED (mt_cu)? wc * 3: wc * 2;
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */
M[MT_CA] = (M[MT_CA] + 1) & 0777777;
@@ -313,79 +318,52 @@ case FN_WRITE: /* write */
dbuf[p++] = M[xma] & 077; }
else { dbuf[p++] = (M[xma] >> 8) & 0377;
dbuf[p++] = M[xma] & 0377; } }
fxwrite (dbuf, sizeof (char), (tbc + 1) & ~1, uptr -> fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
err = ferror (uptr -> fileref);
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) +
fxwrite (dbuf, sizeof (char), (tbc + 1) & ~1, uptr->fileref);
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */
else uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* no, upd pos */
(2 * sizeof (t_mtrlnt));
break;
/* Unit service, continued */
case FN_WREOF:
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref);
err = ferror (uptr -> fileref);
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
uptr -> USTAT = STA_EOF;
fseek (uptr->fileref, uptr->pos, SEEK_SET);
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref);
uptr->USTAT = STA_EOF;
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */
else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* no, upd pos */
break;
case FN_SPACEF: /* space forward */
do { fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read bc */
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
feof (uptr -> fileref)) {
uptr -> USTAT = STA_EOT;
break; }
if (tbc == 0) { /* zero bc? */
uptr -> USTAT = STA_EOF;
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
break; }
uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) +
do { if (mt_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
(2 * sizeof (t_mtrlnt)); }
while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
break;
case FN_SPACER: /* space reverse */
if (uptr -> pos == 0) { /* at BOT? */
uptr -> USTAT = STA_BOT;
break; }
do { fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt),
SEEK_SET);
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
tbc = MTRL (tbc); /* ignore error flag */
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
feof (uptr -> fileref)) {
uptr -> USTAT = STA_BOT;
uptr -> pos = 0;
break; }
if (tbc == 0) { /* end of file? */
uptr -> USTAT = STA_EOF;
uptr -> pos = uptr -> pos - sizeof (t_mtrlnt);
break; }
uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt));
if (uptr -> pos == 0) { /* at BOT? */
uptr -> USTAT = STA_BOT;
break; } }
do { if (pnu) pnu = 0; /* pos not upd? */
else { if (mt_rdlntf (uptr, &tbc, &err)) break;
uptr->pos = uptr->pos - ((tbc + 1) & ~1) -
(2 * sizeof (t_mtrlnt)); } }
while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
break; } /* end case */
/* Unit service, continued */
if (err != 0) { /* I/O error */
mt_updcsta (uptr, STA_PAR); /* flag error */
mt_updcsta (uptr, STA_DON | (err? STA_PAR: 0)); /* set done */
if (err != 0) { /* I/O error? */
perror ("MT I/O error");
rval = SCPE_IOERR;
clearerr (uptr -> fileref); }
mt_updcsta (uptr, STA_DON); /* set done */
return IORETURN (mt_stopioe, rval);
clearerr (uptr->fileref);
if (mt_stopioe) return SCPE_IOERR; }
return SCPE_OK;
}
/* Update controller status */
int32 mt_updcsta (UNIT *uptr, int32 new)
int32 mt_updcsta (UNIT *uptr, int32 news)
{
mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) |
(uptr -> USTAT & STA_DYN) | new;
(uptr->USTAT & STA_DYN) | news;
if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR; /* error flag */
if ((mt_sta & (STA_ERR | STA_DON)) && ((mt_cu & CU_IE) == 0))
SET_INT (MTA);
@@ -402,10 +380,61 @@ UNIT *uptr;
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
uptr = mt_dev.units + u;
if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0))
if (sim_is_active (uptr) && ((uptr->USTAT & STA_REW) == 0))
return uptr; }
return NULL;
}
/* Read record length forward - return status flag if err, EOM, or EOF */
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
{
fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */
if (*err = ferror (uptr->fileref)) { /* error? */
mt_sta = mt_sta | STA_PAR; /* set flag */
MT_SET_PNU (uptr); /* pos not upd */
return TRUE; }
if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */
mt_sta = mt_sta | STA_BAD; /* bad tape */
MT_SET_PNU (uptr); /* pos not upd */
return TRUE; }
if (*tbc == MTR_TMK) { /* tape mark? */
uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */
return TRUE; }
if (MTRF (*tbc)) mt_sta = mt_sta | STA_PAR; /* record in error? */
*tbc = MTRL (*tbc); /* clear error flag */
return FALSE;
}
/* Read record length reverse - return status flag if err, EOM, or EOF */
int32 mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
{
if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */
uptr->USTAT = STA_BOT; /* set status */
return TRUE; } /* error */
fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
if (*err = ferror (uptr->fileref)) { /* error? */
mt_sta = mt_sta | STA_PAR; /* set flag */
return TRUE; }
if (feof (uptr->fileref)) { /* eof? */
mt_sta = mt_sta | STA_BAD; /* bad tape */
return TRUE; }
if (*tbc == MTR_EOM) { /* eom? */
mt_sta = mt_sta | STA_BAD; /* bad tape */
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */
return TRUE; }
if (*tbc == MTR_TMK) { /* tape mark? */
uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */
return TRUE; }
if (MTRF (*tbc)) mt_sta = mt_sta | STA_PAR; /* record in error? */
*tbc = MTRL (*tbc); /* clear error flag */
return FALSE;
}
/* Reset routine */
@@ -417,10 +446,10 @@ UNIT *uptr;
mt_cu = mt_sta = 0;
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
uptr = mt_dev.units + u;
uptr -> UNUM = u; /* init drive number */
MT_CLR_PNU (uptr); /* clr pos not upd */
sim_cancel (uptr); /* cancel activity */
if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
else uptr -> USTAT = 0; }
if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_BOT;
else uptr->USTAT = 0; }
mt_updcsta (&mt_unit[0], 0); /* update status */
return SCPE_OK;
}
@@ -440,7 +469,8 @@ t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
uptr -> USTAT = STA_BOT;
MT_CLR_PNU (uptr);
uptr->USTAT = STA_BOT;
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return r;
}
@@ -449,7 +479,8 @@ return r;
t_stat mt_detach (UNIT* uptr)
{
if (!sim_is_active (uptr)) uptr -> USTAT = 0;
MT_CLR_PNU (uptr);
if (!sim_is_active (uptr)) uptr->USTAT = 0;
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
return detach_unit (uptr);
}

View File

@@ -26,6 +26,7 @@
rf (PDP-9) RF09/RF09
(PDP-15) RF15/RS09
05-Oct-02 RMS Added DIB, dev number support
06-Jan-02 RMS Revised enable/disable support
25-Nov-01 RMS Revised interrupt structure
24-Nov-01 RMS Changed WLK to array
@@ -88,8 +89,9 @@
#define RF_BUSY (sim_is_active (&rf_unit))
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern int32 int_hwre[API_HLVL+1];
extern UNIT cpu_unit;
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
int32 rf_dbuf = 0; /* data buffer */
@@ -97,6 +99,11 @@ int32 rf_wlk[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* write lock */
int32 rf_time = 10; /* inter-word time */
int32 rf_burst = 1; /* burst mode flag */
int32 rf_stopioe = 1; /* stop on error */
DEVICE rf_dev;
int32 rf70 (int32 pulse, int32 AC);
int32 rf72 (int32 pulse, int32 AC);
int32 rf_iors (void);
t_stat rf_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr);
int32 rf_updsta (int32 new);
@@ -108,6 +115,8 @@ int32 rf_updsta (int32 new);
rf_reg RF register list
*/
DIB rf_dib = { DEV_RF, 3, &rf_iors, { &rf70, NULL, &rf72 } };
UNIT rf_unit =
{ UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
RF_SIZE) };
@@ -123,19 +132,19 @@ REG rf_reg[] = {
{ DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ FLDATA (*DEVENB, dev_enb, ENB_V_RF), REG_HRO },
{ ORDATA (DEVNO, rf_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB rf_mod[] = {
{ MTAB_XTD|MTAB_VDV, ENB_RF, NULL, "ENABLED", &set_enb },
{ MTAB_XTD|MTAB_VDV, ENB_RF, NULL, "DISABLED", &set_dsb },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE rf_dev = {
"RF", &rf_unit, rf_reg, rf_mod,
1, 8, 21, 1, 8, 18,
NULL, NULL, &rf_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&rf_dib, DEV_DISABLE };
/* IOT routines */
@@ -203,7 +212,7 @@ t_stat rf_svc (UNIT *uptr)
{
int32 f, pa, d, t;
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
rf_updsta (RFS_NED | RFS_DON); /* set nxd, done */
return IORETURN (rf_stopioe, SCPE_UNATT); }
@@ -211,9 +220,9 @@ f = GET_FNC (rf_sta); /* get function */
do { M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */
pa = M[RF_CA] = (M[RF_CA] + 1) & ADDRMASK; /* incr mem addr */
if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */
M[pa] = *(((int32 *) uptr -> filebuf) + rf_da);
M[pa] = *(((int32 *) uptr->filebuf) + rf_da);
if ((f == FN_WCHK) && /* write check? */
(M[pa] != *(((int32 *) uptr -> filebuf) + rf_da))) {
(M[pa] != *(((int32 *) uptr->filebuf) + rf_da))) {
rf_updsta (RFS_WCE); /* flag error */
break; }
if (f == FN_WRITE) { /* write? */
@@ -222,9 +231,9 @@ do { M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */
if ((rf_wlk[d] >> t) & 1) { /* write locked? */
rf_updsta (RFS_WLO);
break; }
else { *(((int32 *) uptr -> filebuf) + rf_da) = M[pa];
if (((t_addr) rf_da) >= uptr -> hwmark)
uptr -> hwmark = rf_da + 1; } }
else { *(((int32 *) uptr->filebuf) + rf_da) = M[pa];
if (((t_addr) rf_da) >= uptr->hwmark)
uptr->hwmark = rf_da + 1; } }
rf_da = rf_da + 1; /* incr disk addr */
if (rf_da > RF_SIZE) { /* disk overflow? */
rf_da = 0;

View File

@@ -25,6 +25,7 @@
rp RP15/RP02 disk pack
05-Oct-02 RMS Added DIB, device number support
06-Jan-02 RMS Revised enable/disable support
29-Nov-01 RMS Added read only unit support
25-Nov-01 RMS Revised interrupt structure
@@ -48,7 +49,6 @@
/* Unit specific flags */
#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_W_UF 2 /* user flags width */
#define UNIT_WLK (1u << UNIT_V_WLK)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
@@ -129,8 +129,9 @@
#define MAX(x,y) (((x) > (y))? (x): (y))
extern int32 M[];
extern int32 int_hwre[API_HLVL+1], dev_enb, nexm;
extern int32 int_hwre[API_HLVL+1], nexm;
extern UNIT cpu_unit;
int32 rp_sta = 0; /* status A */
int32 rp_stb = 0; /* status B */
int32 rp_ma = 0; /* memory address */
@@ -140,6 +141,11 @@ int32 rp_busy = 0; /* busy */
int32 rp_stopioe = 1; /* stop on error */
int32 rp_swait = 10; /* seek time */
int32 rp_rwait = 10; /* rotate time */
DEVICE rp_dev;
int32 rp63 (int32 pulse, int32 AC);
int32 rp64 (int32 pulse, int32 AC);
int32 rp_iors (void);
t_stat rp_svc (UNIT *uptr);
void rp_updsta (int32 newa, int32 newb);
t_stat rp_reset (DEVICE *dptr);
@@ -154,6 +160,8 @@ t_stat rp_detach (UNIT *uptr);
rp_mod RP modifier list
*/
DIB rp_dib = { DEV_RP, 2, &rp_iors, { &rp63, &rp64 } };
UNIT rp_unit[] = {
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
{ UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) },
@@ -175,23 +183,21 @@ REG rp_reg[] = {
{ FLDATA (STOP_IOE, rp_stopioe, 0) },
{ DRDATA (STIME, rp_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rp_rwait, 24), PV_LEFT },
{ URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
RP_NUMDR, REG_HRO) },
{ FLDATA (*DEVENB, dev_enb, ENB_V_RP), REG_HRO },
{ ORDATA (DEVNO, rp_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB rp_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ MTAB_XTD|MTAB_VDV, ENB_RP, NULL, "ENABLED", &set_enb },
{ MTAB_XTD|MTAB_VDV, ENB_RP, NULL, "DISABLED", &set_dsb },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE rp_dev = {
"RP", rp_unit, rp_reg, rp_mod,
RP_NUMDR, 8, 24, 1, 8, 18,
NULL, NULL, &rp_reset,
NULL, &rp_attach, &rp_detach };
NULL, &rp_attach, &rp_detach,
&rp_dib, DEV_DISABLE };
/* IOT routines */
@@ -251,16 +257,16 @@ if (rp_sta & STA_GO) {
u = GET_UNIT (rp_sta); /* get unit num */
uptr = rp_dev.units + u; /* select unit */
if (sim_is_active (uptr)) return AC; /* can't if busy */
f = uptr -> FUNC = GET_FUNC (rp_sta); /* get function */
f = uptr->FUNC = GET_FUNC (rp_sta); /* get function */
rp_busy = 1; /* set ctrl busy */
rp_sta = rp_sta & ~(STA_HNF | STA_DON); /* clear flags */
rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE |
STB_TME | STB_PGE | STB_EOP | (1 << (STB_V_ATT0 - u)));
if (((uptr -> flags & UNIT_ATT) == 0) || (f == FN_IDLE) ||
if (((uptr->flags & UNIT_ATT) == 0) || (f == FN_IDLE) ||
(f == FN_SEEK) || (f == FN_RECAL))
sim_activate (uptr, RP_MIN); /* short delay */
else { c = GET_CYL (rp_da);
c = abs (c - uptr -> CYL) * rp_swait; /* seek time */
c = abs (c - uptr->CYL) * rp_swait; /* seek time */
sim_activate (uptr, MAX (RP_MIN, c + rp_rwait)); } }
rp_updsta (0, 0);
return AC;
@@ -286,7 +292,7 @@ int32 f, u, comp, cyl, sect, surf;
int32 err, pa, da, wc, awc, i;
u = uptr - rp_dev.units; /* get drv number */
f = uptr -> FUNC; /* get function */
f = uptr->FUNC; /* get function */
if (f == FN_IDLE) { /* idle? */
rp_busy = 0; /* clear busy */
return SCPE_OK; }
@@ -294,9 +300,9 @@ if (f == FN_IDLE) { /* idle? */
if ((f == FN_SEEK) || (f == FN_RECAL)) { /* seek or recal? */
rp_busy = 0; /* not busy */
cyl = (f == FN_SEEK)? GET_CYL (rp_da): 0; /* get cylinder */
sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr -> CYL) * rp_swait));
uptr -> CYL = cyl; /* on cylinder */
uptr -> FUNC = FN_SEEK | FN_2ND; /* set second state */
sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr->CYL) * rp_swait));
uptr->CYL = cyl; /* on cylinder */
uptr->FUNC = FN_SEEK | FN_2ND; /* set second state */
rp_updsta (0, 0); /* update status */
return SCPE_OK; }
@@ -304,11 +310,11 @@ if (f == (FN_SEEK | FN_2ND)) { /* seek done? */
rp_updsta (0, rp_stb | (1 << (STB_V_ATT0 - u))); /* set attention */
return SCPE_OK; }
if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */
return IORETURN (rp_stopioe, SCPE_UNATT); }
if ((f == FN_WRITE) && (uptr -> flags & UNIT_WPRT)) { /* write locked? */
if ((f == FN_WRITE) && (uptr->flags & UNIT_WPRT)) { /* write locked? */
rp_updsta (STA_DON | STA_WPE, 0); /* error */
return SCPE_OK; }
@@ -329,26 +335,26 @@ if ((da + wc) > RP_SIZE) { /* disk overrun? */
rp_updsta (0, STB_EOP); /* error */
wc = RP_SIZE - da; } /* limit xfer */
err = fseek (uptr -> fileref, da * sizeof (int), SEEK_SET);
err = fseek (uptr->fileref, da * sizeof (int), SEEK_SET);
if ((f == FN_READ) && (err == 0)) { /* read? */
awc = fxread (&M[pa], sizeof (int32), wc, uptr -> fileref);
awc = fxread (&M[pa], sizeof (int32), wc, uptr->fileref);
for ( ; awc < wc; awc++) M[pa + awc] = 0;
err = ferror (uptr -> fileref); }
err = ferror (uptr->fileref); }
if ((f == FN_WRITE) && (err == 0)) { /* write? */
fxwrite (&M[pa], sizeof (int32), wc, uptr -> fileref);
err = ferror (uptr -> fileref);
fxwrite (&M[pa], sizeof (int32), wc, uptr->fileref);
err = ferror (uptr->fileref);
if ((err == 0) && (i = (wc & (RP_NUMWD - 1)))) {
fxwrite (fill, sizeof (int), i, uptr -> fileref);
err = ferror (uptr -> fileref); } }
fxwrite (fill, sizeof (int), i, uptr->fileref);
err = ferror (uptr->fileref); } }
if ((f == FN_WRCHK) && (err == 0)) { /* write check? */
for (i = 0; (err == 0) && (i < wc); i++) {
awc = fxread (&comp, sizeof (int32), 1, uptr -> fileref);
awc = fxread (&comp, sizeof (int32), 1, uptr->fileref);
if (awc == 0) comp = 0;
if (comp != M[pa + i]) rp_updsta (0, STB_WCE); }
err = ferror (uptr -> fileref); }
err = ferror (uptr->fileref); }
rp_wc = (rp_wc + wc) & 0777777; /* final word count */
rp_ma = (rp_ma + wc) & 0777777; /* final mem addr */
@@ -363,7 +369,7 @@ rp_updsta (STA_DON, 0); /* set done */
if (err != 0) { /* error? */
perror ("RP I/O error");
clearerr (uptr -> fileref);
clearerr (uptr->fileref);
return IORETURN (rp_stopioe, SCPE_IOERR); }
return SCPE_OK;
}
@@ -378,13 +384,13 @@ UNIT *uptr;
uptr = rp_dev.units + GET_UNIT (rp_sta);
rp_sta = (rp_sta & ~(STA_DYN | STA_ERR)) | newa;
rp_stb = (rp_stb & ~STB_DYN) | newb;
if (uptr -> flags & UNIT_WPRT) rp_sta = rp_sta | STA_SUWP;
if ((uptr -> flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR;
if (uptr->flags & UNIT_WPRT) rp_sta = rp_sta | STA_SUWP;
if ((uptr->flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR;
else if (sim_is_active (uptr)) {
f = (uptr -> FUNC) & STA_M_FUNC;
f = (uptr->FUNC) & STA_M_FUNC;
if ((f == FN_SEEK) || (f == FN_RECAL))
rp_stb = rp_stb | STB_SUSU | STB_SUNR; }
else if (uptr -> CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI;
else if (uptr->CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI;
if ((rp_sta & STA_EFLGS) || (rp_stb & STB_EFLGS)) rp_sta = rp_sta | STA_ERR;
if (((rp_sta & (STA_ERR | STA_DON)) && (rp_sta & STA_IED)) ||
((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) SET_INT (RP);
@@ -404,7 +410,7 @@ CLR_INT (RP);
for (i = 0; i < RP_NUMDR; i++) {
uptr = rp_dev.units + i;
sim_cancel (uptr);
uptr -> CYL = uptr -> FUNC = 0; }
uptr->CYL = uptr->FUNC = 0; }
return SCPE_OK;
}

View File

@@ -29,6 +29,8 @@
tto teleprinter
clk clock
01-Nov-02 RMS Added 7B/8B support to terminal
05-Oct-02 RMS Added DIBs, device number support, IORS call
14-Jul-02 RMS Added ASCII reader/punch support (from Hans Pufal)
30-May-02 RMS Widened POS to 32b
29-Nov-01 RMS Added read only unit support
@@ -50,9 +52,9 @@
#include "pdp18b_defs.h"
#include <ctype.h>
#define UNIT_V_RASCII UNIT_V_UF /* reader ASCII */
#define UNIT_V_RASCII (UNIT_V_UF + 0) /* reader ASCII */
#define UNIT_RASCII (1 << UNIT_V_RASCII)
#define UNIT_V_PASCII UNIT_V_UF /* punch ASCII */
#define UNIT_V_PASCII (UNIT_V_UF + 0) /* punch ASCII */
#define UNIT_PASCII (1 << UNIT_V_PASCII)
extern int32 M[];
@@ -68,6 +70,15 @@ int32 tto_state = 0;
int32 clk_tps = 60; /* ticks/second */
int32 tmxr_poll = 16000; /* term mux poll */
int32 ptr (int32 pulse, int32 AC);
int32 ptp (int32 pulse, int32 AC);
int32 tti (int32 pulse, int32 AC);
int32 tto (int32 pulse, int32 AC);
int32 clk_iors (void);
int32 ptr_iors (void);
int32 ptp_iors (void);
int32 tti_iors (void);
int32 tto_iors (void);
t_stat clk_svc (UNIT *uptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
@@ -82,7 +93,10 @@ t_stat ptr_attach (UNIT *uptr, char *cptr);
t_stat ptp_attach (UNIT *uptr, char *cptr);
t_stat ptr_detach (UNIT *uptr);
t_stat ptp_detach (UNIT *uptr);
t_stat ptr_boot (int32 unitno);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
extern int32 upd_iors (void);
/* CLK data structures
@@ -91,6 +105,8 @@ t_stat ptr_boot (int32 unitno);
clk_reg CLK register list
*/
DIB clk_dib = { 0, 0, &clk_iors, { NULL } };
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
@@ -101,11 +117,16 @@ REG clk_reg[] = {
{ DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT },
{ NULL } };
MTAB clk_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
{ 0 } };
DEVICE clk_dev = {
"CLK", &clk_unit, clk_reg, NULL,
"CLK", &clk_unit, clk_reg, clk_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&clk_dib, 0 };
/* PTR data structures
@@ -114,6 +135,8 @@ DEVICE clk_dev = {
ptr_reg PTR register list
*/
DIB ptr_dib = { DEV_PTR, 1, &ptr_iors, { &ptr } };
UNIT ptr_unit = {
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT };
@@ -129,14 +152,18 @@ REG ptr_reg[] = {
{ DRDATA (POS, ptr_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ FLDATA (ASCII, ptr_unit.flags, UNIT_V_RASCII), REG_HRO },
{ NULL } };
MTAB ptr_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
{ 0 } };
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
"PTR", &ptr_unit, ptr_reg, ptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, &ptr_attach, &ptr_detach };
&ptr_boot, &ptr_attach, &ptr_detach,
&ptr_dib, 0 };
/* PTP data structures
@@ -145,6 +172,8 @@ DEVICE ptr_dev = {
ptp_reg PTP register list
*/
DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } };
UNIT ptp_unit = {
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
@@ -158,14 +187,18 @@ REG ptp_reg[] = {
{ DRDATA (POS, ptp_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ FLDATA (ASCII, ptp_unit.flags, UNIT_V_PASCII), REG_HRO },
{ NULL } };
MTAB ptp_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
{ 0 } };
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, NULL,
"PTP", &ptp_unit, ptp_reg, ptp_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, &ptp_attach, &ptp_detach };
NULL, &ptp_attach, &ptp_detach,
&ptp_dib, 0 };
/* TTI data structures
@@ -206,15 +239,19 @@ static const int32 tti_trans[128] = {
#endif
#define TTI_MASK ((1 << TTI_WIDTH) - 1)
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
#define UNIT_V_HDX (UNIT_V_UF + 1) /* half duplex */
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */
#define UNIT_V_HDX (UNIT_V_UF + 2) /* half duplex */
#define UNIT_8B (1 << UNIT_V_8B)
#define UNIT_KSR (1 << UNIT_V_KSR)
#define UNIT_HDX (1 << UNIT_V_HDX)
DIB tti_dib = { DEV_TTI, 1, &tti_iors, { &tti } };
#if defined (PDP4) || defined (PDP7)
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT };
UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT };
#else
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX, 0), KBD_POLL_WAIT };
UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR+UNIT_HDX, 0), KBD_POLL_WAIT };
#endif
REG tti_reg[] = {
@@ -223,9 +260,6 @@ REG tti_reg[] = {
{ FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) },
#if defined (KSR28)
{ ORDATA (TTI_STATE, tti_state, (TTI_WIDTH + 3)), REG_HRO },
#else
{ FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO },
{ FLDATA (HDX, tti_unit.flags, UNIT_V_HDX), REG_HRO },
#endif
{ DRDATA (POS, tti_unit.pos, 32), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
@@ -233,18 +267,21 @@ REG tti_reg[] = {
MTAB tti_mod[] = {
#if !defined (KSR28)
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_HDX, 0, "full duplex", "FDX", NULL },
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode },
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode },
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode },
{ UNIT_HDX, 0 , "full duplex", "FDX", NULL },
{ UNIT_HDX, UNIT_HDX, "half duplex", "HDX", NULL },
#endif
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
{ 0 } };
DEVICE tti_dev = {
"TTI", &tti_unit, tti_reg, tti_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&tti_dib, 0 };
/* TTO data structures
@@ -274,7 +311,9 @@ static const char tto_trans[64] = {
#define TTO_MASK ((1 << TTO_WIDTH) - 1)
UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT };
DIB tto_dib = { DEV_TTO, 1, &tto_iors, { &tto } };
UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT };
REG tto_reg[] = {
{ ORDATA (BUF, tto_unit.buf, TTO_WIDTH) },
@@ -289,16 +328,19 @@ REG tto_reg[] = {
MTAB tto_mod[] = {
#if !defined (KSR28)
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode },
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode },
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode },
#endif
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno },
{ 0 } };
DEVICE tto_dev = {
"TTO", &tto_unit, tto_reg, tto_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&tto_dib, 0 };
/* Clock: IOT routine */
@@ -332,6 +374,13 @@ if (clk_state) { /* clock on? */
return SCPE_OK;
}
/* IORS service */
int32 clk_iors (void)
{
return (TST_INT (CLK)? IOS_CLK: 0);
}
/* Reset routine */
t_stat clk_reset (DEVICE *dptr)
@@ -342,24 +391,6 @@ sim_cancel (&clk_unit); /* stop clock */
tmxr_poll = clk_unit.wait; /* set mux poll */
return SCPE_OK;
}
/* IORS service for all standard devices */
int32 std_iors (void)
{
return ((TST_INT (CLK)? IOS_CLK: 0) |
(TST_INT (PTR)? IOS_PTR: 0) |
(TST_INT (PTP)? IOS_PTP: 0) |
(TST_INT (TTI)? IOS_TTI: 0) |
(TST_INT (TTO)? IOS_TTO: 0) |
#if defined (IOS_PTRERR)
(ptr_err? IOS_PTRERR: 0) |
#endif
#if defined (IOS_PTPERR)
(ptp_err? IOS_PTPERR: 0) |
#endif
(clk_state? IOS_CLKON: 0));
}
/* Paper tape reader: IOT routine */
@@ -423,6 +454,17 @@ ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1;
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
/* IORS service */
int32 ptr_iors (void)
{
return ((TST_INT (PTR)? IOS_PTR: 0)
#if defined (IOS_PTRERR)
| (ptr_err? IOS_PTRERR: 0)
#endif
);
}
/* Attach routine */
@@ -592,11 +634,12 @@ static const int32 boot_rom[] = {
0617771 /* jmp g */
};
t_stat ptr_boot (int32 unitno)
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
int32 i, mask, wd;
extern int32 sim_switches;
if (ptr_dib.dev != DEV_PTR) return STOP_NONSTD; /* non-std addr? */
if (MEMSIZE < 8192) mask = 0767777; /* 4k? */
else mask = 0777777;
for (i = 0; i < BOOT_LEN; i++) {
@@ -611,7 +654,7 @@ return SCPE_OK;
/* PDP-9 and PDP-15 have built-in hardware RIM loaders */
t_stat ptr_boot (int32 unitno)
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
return SCPE_ARG;
}
@@ -653,6 +696,17 @@ if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */
ptp_unit.pos = ptp_unit.pos + 1;
return SCPE_OK;
}
/* IORS service */
int32 ptp_iors (void)
{
return ((TST_INT (PTP)? IOS_PTP: 0)
#if defined (IOS_PTPERR)
| (ptp_err? IOS_PTPERR: 0)
#endif
);
}
/* Reset routine */
@@ -696,6 +750,8 @@ if (pulse & 001) { /* KSF */
if (pulse & 002) { /* KRB */
CLR_INT (TTI); /* clear flag */
AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */
if (pulse & 004) { /* IORS */
AC = AC | upd_iors (); }
return AC;
}
@@ -703,38 +759,52 @@ return AC;
t_stat tti_svc (UNIT *uptr)
{
int32 temp;
#if defined (KSR28) /* Baudot... */
int32 c;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
#if defined (KSR28) /* Baudot... */
if (tti_state & TTI_2ND) { /* char waiting? */
tti_unit.buf = tti_state & TTI_MASK; /* return char */
tti_state = tti_state & ~TTI_2ND; } /* not waiting */
else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp;
temp = tti_trans[temp & 0177]; /* translate char */
if (temp == 0) return SCPE_OK; /* untranslatable? */
if (((temp & TTI_FIGURES) == (tti_state & TTI_FIGURES)) ||
(temp & TTI_BOTH)) tti_unit.buf = temp & TTI_MASK;
else { tti_unit.buf = (temp & TTI_FIGURES)?
else { if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c;
c = tti_trans[c & 0177]; /* translate char */
if (c == 0) return SCPE_OK; /* untranslatable? */
if (((c & TTI_FIGURES) == (tti_state & TTI_FIGURES)) ||
(c & TTI_BOTH)) tti_unit.buf = c & TTI_MASK;
else { tti_unit.buf = (c & TTI_FIGURES)?
BAUDOT_FIGURES: BAUDOT_LETTERS;
tti_state = temp | TTI_2ND; } } /* set 2nd waiting */
tti_state = c | TTI_2ND; } } /* set 2nd waiting */
#else /* ASCII... */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
temp = temp & 0177;
if ((tti_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp);
if ((tti_unit.flags & UNIT_HDX) &&
(!(tto_unit.flags & UNIT_UC) ||
((temp >= 007) && (temp <= 0137)))) {
sim_putchar (temp);
int32 c, out;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
out = c & 0177; /* mask echo to 7b */
if (tti_unit.flags & UNIT_KSR) { /* KSR? */
if (islower (out)) out = toupper (out); /* convert to UC */
c = out | 0200; } /* set TTY bit */
else c = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177); /* no, 7b/8b */
if ((tti_unit.flags & UNIT_HDX) && /* half duplex and */
(!(tto_unit.flags & UNIT_KSR) || /* 7b/8b or */
((out >= 007) && (out <= 0137)))) { /* in range? */
sim_putchar (out); /* echo */
tto_unit.pos = tto_unit.pos + 1; }
tti_unit.buf = temp | 0200; /* got char */
tti_unit.buf = c; /* got char */
#endif
SET_INT (TTI); /* set flag */
tti_unit.pos = tti_unit.pos + 1;
return SCPE_OK;
}
/* IORS service */
int32 tti_iors (void)
{
return (TST_INT (TTI)? IOS_TTI: 0);
}
/* Reset routine */
t_stat tti_reset (DEVICE *dptr)
@@ -763,7 +833,8 @@ return AC;
t_stat tto_svc (UNIT *uptr)
{
int32 out, temp;
int32 c;
t_stat r;
SET_INT (TTO); /* set flag */
#if defined (KSR28) /* Baudot... */
@@ -773,18 +844,26 @@ if (tto_unit.buf == BAUDOT_FIGURES) { /* set figures? */
if (tto_unit.buf == BAUDOT_LETTERS) { /* set letters? */
tto_state = 0;
return SCPE_OK; }
out = tto_trans[tto_unit.buf + tto_state]; /* translate */
c = tto_trans[tto_unit.buf + tto_state]; /* translate */
#else
out = tto_unit.buf & 0177; /* ASCII... */
if (tto_unit.flags & UNIT_KSR) { /* KSR? */
c = tto_unit.buf & 0177;
if (islower (c)) c = toupper (c);
if ((c < 007) || (c > 0137)) return SCPE_OK; }
else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
#endif
if (!(tto_unit.flags & UNIT_UC) ||
((out >= 007) && (out <= 0137))) {
temp = sim_putchar (out);
if (temp != SCPE_OK) return temp;
tto_unit.pos = tto_unit.pos + 1; }
if ((r = sim_putchar (c)) != SCPE_OK) return r;
tto_unit.pos = tto_unit.pos + 1;
return SCPE_OK;
}
/* IORS service */
int32 tto_iors (void)
{
return (TST_INT (TTO)? IOS_TTO: 0);
}
/* Reset routine */
t_stat tto_reset (DEVICE *dptr)
@@ -795,3 +874,10 @@ CLR_INT (TTO); /* clear flag */
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
tti_unit.flags = (tti_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val;
tto_unit.flags = (tto_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val;
return SCPE_OK;
}

View File

@@ -23,6 +23,8 @@
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.
05-Oct-02 RMS Added variable device number support
25-Jul-02 RMS Added PDP-4 DECtape support
10-Feb-02 RMS Added PDP-7 DECtape IOT's
03-Feb-02 RMS Fixed typo (found by Robert Alan Byer)
17-Sep-01 RMS Removed multiconsole support
@@ -47,6 +49,7 @@ extern DEVICE tti_dev, tto_dev;
extern UNIT tti_unit, tto_unit;
extern DEVICE clk_dev;
extern DEVICE lpt_dev;
extern DEVICE dt_dev;
#if defined (DRM)
extern DEVICE drm_dev;
#endif
@@ -59,9 +62,6 @@ extern DEVICE rp_dev;
#if defined (MTA)
extern DEVICE mt_dev;
#endif
#if defined (DTA)
extern DEVICE dt_dev;
#endif
#if defined (TTY1)
extern DEVICE tti1_dev, tto1_dev;
extern UNIT tti1_unit, tto1_unit;
@@ -109,9 +109,7 @@ DEVICE *sim_devices[] = { &cpu_dev,
#if defined (RP)
&rp_dev,
#endif
#if defined (DTA)
&dt_dev,
#endif
#if defined (MTA)
&mt_dev,
#endif
@@ -126,7 +124,8 @@ const char *sim_stop_messages[] = {
"HALT instruction",
"Breakpoint",
"Nested XCT's",
"Invalid API interrupt" };
"Invalid API interrupt",
"Non-standard device number" };
/* Binary loader */
@@ -238,7 +237,7 @@ for (;;) { /* block loop */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
if (val & SIGN) {
if (val != DMASK) saved_PC = val & 077777;
return SCPE_OK; }
break; }
cksum = origin = val; /* save origin */
if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT;
cksum = cksum + val; /* add to cksum */
@@ -250,7 +249,7 @@ for (;;) { /* block loop */
cksum = cksum + val;
if (MEM_ADDR_OK (origin)) M[origin++] = val; }
if ((cksum & DMASK) != 0) return SCPE_CSUM; }
return SCPE_FMT;
return SCPE_OK;
}
#endif
@@ -361,15 +360,13 @@ static const char *opcode[] = {
"MTTR", "MTCR", "MTSF", "MTRC", "MTAF",
"MTRS", "MTGO", "MTCM", "MTLC",
#endif
#if defined (DTA) /* DECtape */
#if defined (PDP7) /* Type 550 */
#if defined (TYPE550) /* Type 550 */
"MMDF", "MMEF", "MMRD", "MMWR",
"MMBF", "MMRS", "MMLC", "MMSE",
#elif defined (PDP9) || defined (PDP15) /* TC02/TC15 */
#elif defined (TC02) /* TC02/TC15 */
"DTCA", "DTRA", "DTXA", "DTLA",
"DTEF", "DTRB", "DTDF",
#endif
#endif
#if defined (TTY1)
"KSF1", "KRB1",
"TSF1", "TCF1", "TLS1", "TCF1!TLS1",
@@ -517,15 +514,13 @@ static const int32 opc_val[] = {
0707301+I_NPI, 0707321+I_NPI, 0707341+I_NPI, 0707312+I_NPN, 0707322+I_NPI,
0707352+I_NPN, 0707304+I_NPI, 0707324+I_NPI, 0707326+I_NPI,
#endif
#if defined (DTA)
#if defined (PDP7) /* Type 550 */
#if defined (TYPE550) /* Type 550 */
0707501+I_NPI, 0707541+I_NPI, 0707512+I_NPN, 0707504+I_NPI,
0707601+I_NPI, 0707612+I_NPN, 0707604+I_NPI, 0707644+I_NPI,
#elif defined (PDP9) || defined (PDP15) /* TC02/TC15 */
#elif defined (TC02) /* TC02/TC15 */
0707541+I_NPI, 0707552+I_NPN, 0707544+I_NPI, 0707545+I_NPI,
0707561+I_NPI, 0707572+I_NPN, 0707601+I_NPI,
#endif
#endif
#if defined (TTY1)
0704101+I_NPI, 0704112+I_NPN,
0704001+I_NPI, 0704002+I_NPI, 0704004+I_NPI, 0704006+I_NPI,
@@ -639,7 +634,6 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
int32 cflag, i, j, k, sp, inst, disp, ma;
inst = val[0];
i = val[1];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
@@ -652,6 +646,7 @@ if (sw & SWMASK ('C')) { /* character? */
return SCPE_OK; }
#if defined (PDP15)
if (sw & SWMASK ('P')) { /* packed ASCII? */
i = val[1];
fprintf (of, "%c", FMTASC ((inst >> 11) & 0177));
fprintf (of, "%c", FMTASC ((inst >> 4) & 0177));
fprintf (of, "%c", FMTASC (((inst << 3) | (i >> 15)) & 0177));

View File

@@ -26,6 +26,9 @@
tti1 keyboard
tto1 teleprinter
02-Nov-02 RMS Added 7B/8B support
05-Oct-02 RMS Added DIB, device number support
22-Aug-02 RMS Updated for changes to sim_tmxr
30-May-02 RMS Widened POS to 32b
06-Jan-02 RMS Added enable/disable support
30-Dec-01 RMS Added show statistics, set disconnect
@@ -42,14 +45,19 @@
#include "sim_tmxr.h"
#include <ctype.h>
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
#define UNIT_UC (1 << UNIT_V_UC)
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */
#define UNIT_8B (1 << UNIT_V_8B)
#define UNIT_KSR (1 << UNIT_V_KSR)
extern int32 int_hwre[API_HLVL+1], dev_enb;
extern int32 tmxr_poll; /* calibrated poll */
TMLN tt1_ldsc = { 0 }; /* line descriptors */
TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */
TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */
DEVICE tti1_dev, tto1_dev;
int32 tti1 (int32 pulse, int32 AC);
int32 tto1 (int32 pulse, int32 AC);
t_stat tti1_svc (UNIT *uptr);
t_stat tto1_svc (UNIT *uptr);
t_stat tti1_reset (DEVICE *dptr);
@@ -58,6 +66,8 @@ t_stat tti1_attach (UNIT *uptr, char *cptr);
t_stat tti1_detach (UNIT *uptr);
t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc);
void tt1_enbdis (int32 dis);
t_stat tt1_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
/* TTI1 data structures
@@ -67,21 +77,23 @@ t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc);
tti1_reg TTI1 register list
*/
UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT };
DIB tti1_dib = { DEV_TTI1, 1, NULL, { &tti1 } };
UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_KSR, 0), KBD_POLL_WAIT };
REG tti1_reg[] = {
{ ORDATA (BUF, tti1_unit.buf, 8) },
{ FLDATA (INT, int_hwre[API_TTI1], INT_V_TTI1) },
{ FLDATA (DONE, int_hwre[API_TTI1], INT_V_TTI1) },
{ FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO },
{ DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT },
{ DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (*DEVENB, dev_enb, ENB_V_TTI1), REG_HRO },
{ ORDATA (DEVNO, tti1_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB tti1_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt1_set_mode },
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt1_set_mode },
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt1_set_mode },
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tti1_summ },
{ MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &tt_desc },
@@ -89,15 +101,15 @@ MTAB tti1_mod[] = {
NULL, &tti1_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tti1_show, NULL },
{ MTAB_XTD|MTAB_VDV, ENB_TTI1, NULL, "ENABLED", &set_enb },
{ MTAB_XTD|MTAB_VDV, ENB_TTI1, NULL, "DISABLED", &set_dsb },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE tti1_dev = {
"TTI1", &tti1_unit, tti1_reg, tti1_mod,
1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &tti1_reset,
NULL, &tti1_attach, &tti1_detach };
NULL, &tti1_attach, &tti1_detach,
&tti1_dib, DEV_DISABLE };
/* TTO1 data structures
@@ -107,7 +119,9 @@ DEVICE tti1_dev = {
tto1_reg TTO1 register list
*/
UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_UC, 0), SERIAL_OUT_WAIT };
DIB tto1_dib = { DEV_TTO1, 1, NULL, { &tto1 } };
UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT };
REG tto1_reg[] = {
{ ORDATA (BUF, tto1_unit.buf, 8) },
@@ -115,19 +129,22 @@ REG tto1_reg[] = {
{ FLDATA (DONE, int_hwre[API_TTO1], INT_V_TTO1) },
{ DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT },
{ DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT },
{ FLDATA (*DEVENB, dev_enb, ENB_V_TTI1), REG_HRO },
{ ORDATA (DEVNO, tto1_dib.dev, 6), REG_HRO },
{ NULL } };
MTAB tto1_mod[] = {
{ UNIT_UC, 0, "lower case", "LC", NULL },
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
{ UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt1_set_mode },
{ UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt1_set_mode },
{ UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt1_set_mode },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno },
{ 0 } };
DEVICE tto1_dev = {
"TTO1", &tto1_unit, tto1_reg, tto1_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto1_reset,
NULL, NULL, NULL };
NULL, NULL, NULL,
&tto1_dib, DEV_DISABLE };
/* Terminal input: IOT routine */
@@ -145,22 +162,23 @@ return AC;
t_stat tti1_svc (UNIT *uptr)
{
int32 temp, newln;
int32 c, newln;
if (tt1_ldsc.conn) { /* connected? */
tmxr_poll_rx (&tt_desc); /* poll for input */
if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */
temp = temp & 0177;
if ((uptr -> flags & UNIT_UC) &&
islower (temp)) temp = toupper (temp);
uptr -> buf = temp | 0200; /* got char */
SET_INT (TTI1); } /* set flag */
sim_activate (uptr, uptr -> wait); } /* continue poll */
if (uptr -> flags & UNIT_ATT) { /* attached? */
newln = tmxr_poll_conn (&tt_desc, uptr); /* poll connect */
if (c = tmxr_getc_ln (&tt1_ldsc)) { /* get char */
if (uptr->flags & UNIT_KSR) { /* KSR? */
c = c & 0177;
if (islower (c)) c = toupper (c);
uptr->buf = c | 0200; } /* got char */
else c = c & ((tti1_unit.flags & UNIT_8B)? 0377: 0177);
SET_INT (TTI1); } /* set flag */
sim_activate (uptr, uptr->wait); } /* continue poll */
if (uptr->flags & UNIT_ATT) { /* attached? */
newln = tmxr_poll_conn (&tt_desc); /* poll connect */
if (newln >= 0) { /* got one? */
sim_activate (&tti1_unit, tti1_unit.wait);
tt1_ldsc.rcve = 1; } /* rcv enabled */
sim_activate (&tti1_unit, tti1_unit.wait);
tt1_ldsc.rcve = 1; } /* rcv enabled */
sim_activate (uptr, tmxr_poll); } /* sched poll */
return SCPE_OK;
}
@@ -169,6 +187,7 @@ return SCPE_OK;
t_stat tti1_reset (DEVICE *dptr)
{
tt1_enbdis (dptr->flags & DEV_DIS); /* sync enables */
tti1_unit.buf = 0; /* clear buffer */
CLR_INT (TTI1); /* clear flag */
if (tt1_ldsc.conn) { /* if conn, */
@@ -197,19 +216,23 @@ return AC;
t_stat tto1_svc (UNIT *uptr)
{
int32 out;
int32 c;
SET_INT (TTO1); /* set flag */
out = tto1_unit.buf & 0177;
c = tto1_unit.buf & 0177;
if (tt1_ldsc.conn) { /* connected? */
if (tt1_ldsc.xmte) { /* tx enabled? */
if (!(tto1_unit.flags & UNIT_UC) ||
((out >= 007) && (out <= 0137)))
tmxr_putc_ln (&tt1_ldsc, out); /* output char */
tmxr_poll_tx (&tt_desc); } /* poll xmt */
else { tmxr_poll_tx (&tt_desc); /* poll xmt */
sim_activate (&tto1_unit, tmxr_poll); /* wait */
return SCPE_OK; } }
if (tto1_unit.flags & UNIT_KSR) { /* KSR? */
c = c & 0177;
if (islower (c)) c = toupper (c);
if ((c < 007) || (c > 0137)) c = 0; }
else c = c & ((tto1_unit.flags & UNIT_8B)? 0377: 0177);
if (c) tmxr_putc_ln (&tt1_ldsc, c); /* output char */
tmxr_poll_tx (&tt_desc); } /* poll xmt */
else {
tmxr_poll_tx (&tt_desc); /* poll xmt */
sim_activate (&tto1_unit, tmxr_poll); /* wait */
return SCPE_OK; } }
return SCPE_OK;
}
@@ -217,6 +240,7 @@ return SCPE_OK;
t_stat tto1_reset (DEVICE *dptr)
{
tt1_enbdis (dptr->flags & DEV_DIS); /* sync enables */
tto1_unit.buf = 0; /* clear buffer */
CLR_INT (TTO1); /* clear flag */
sim_cancel (&tto1_unit); /* deactivate unit */
@@ -264,3 +288,22 @@ if (val) tmxr_fconns (st, &tt1_ldsc, -1);
else tmxr_fstats (st, &tt1_ldsc, -1);
return SCPE_OK;
}
/* Enable/disable device */
void tt1_enbdis (int32 dis)
{
if (dis) {
tti1_dev.flags = tto1_dev.flags | DEV_DIS;
tto1_dev.flags = tto1_dev.flags | DEV_DIS; }
else { tti1_dev.flags = tti1_dev.flags & ~DEV_DIS;
tto1_dev.flags = tto1_dev.flags & ~DEV_DIS; }
return;
}
t_stat tt1_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
tti1_unit.flags = (tti1_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val;
tto1_unit.flags = (tto1_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val;
return SCPE_OK;
}