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:
committed by
Mark Pizzolato
parent
df6475181c
commit
2c2dd5ea33
@@ -25,6 +25,7 @@
|
||||
|
||||
clk real time clock
|
||||
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
30-Dec-01 RMS Removed for generalized timers
|
||||
05-Sep-01 RMS Added terminal multiplexor support
|
||||
17-Jul-01 RMS Moved function prototype
|
||||
@@ -36,11 +37,14 @@
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
|
||||
int32 clk_tps = 60; /* ticks/second */
|
||||
int32 tmxr_poll = 16000; /* term mux poll */
|
||||
|
||||
int32 clk (int32 IR, int32 AC);
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat clk_reset (DEVICE *dptr);
|
||||
|
||||
/* CLK data structures
|
||||
|
||||
clk_dev CLK device descriptor
|
||||
@@ -48,6 +52,8 @@ int32 tmxr_poll = 16000; /* term mux poll */
|
||||
clk_reg CLK register list
|
||||
*/
|
||||
|
||||
DIB clk_dib = { DEV_CLK, 1, { &clk } };
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
|
||||
|
||||
REG clk_reg[] = {
|
||||
@@ -58,21 +64,26 @@ 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_dev },
|
||||
{ 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 };
|
||||
|
||||
/* IOT routine
|
||||
|
||||
IOT's 6131-6133 are the PDP-8/E clock
|
||||
IOT's 6135-6137 the PDP-8/A clock
|
||||
IOT's 6135-6137 are the PDP-8/A clock
|
||||
*/
|
||||
|
||||
int32 clk (int32 pulse, int32 AC)
|
||||
int32 clk (int32 IR, int32 AC)
|
||||
{
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 1: /* CLEI */
|
||||
int_enable = int_enable | INT_CLK; /* enable clk ints */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
|
||||
222
PDP8/pdp8_cpu.c
222
PDP8/pdp8_cpu.c
@@ -25,6 +25,7 @@
|
||||
|
||||
cpu central processor
|
||||
|
||||
04-Oct-02 RMS Revamped device dispatching, added device number support
|
||||
06-Jan-02 RMS Added device enable/disable routines
|
||||
30-Dec-01 RMS Added old PC queue
|
||||
16-Dec-01 RMS Fixed bugs in EAE
|
||||
@@ -172,11 +173,10 @@
|
||||
Thus, only writes outside the current field (indirect writes) need
|
||||
be checked against actual memory size.
|
||||
|
||||
3. Adding I/O devices. Three modules must be modified:
|
||||
3. Adding I/O devices. These modules must be modified:
|
||||
|
||||
pdp8_defs.h add interrupt request definition
|
||||
pdp8_cpu.c add IOT dispatch
|
||||
pdp8_sys.c add pointer to data structures to sim_devices
|
||||
pdp8_defs.h add device number and interrupt definitions
|
||||
pdp8_sys.c add sim_devices table entry
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
@@ -208,41 +208,21 @@ REG *pcq_r = NULL; /* PC queue reg ptr */
|
||||
int32 dev_done = 0; /* dev done flags */
|
||||
int32 int_enable = INT_INIT_ENABLE; /* intr enables */
|
||||
int32 int_req = 0; /* intr requests */
|
||||
int32 dev_enb = -1 & ~INT_DF & ~INT_RL; /* device enables */
|
||||
int32 stop_inst = 0; /* trap on ill inst */
|
||||
int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */
|
||||
|
||||
extern int32 sim_interval;
|
||||
extern int32 sim_int_char;
|
||||
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
|
||||
extern DEVICE *sim_devices[];
|
||||
extern FILE *sim_log;
|
||||
extern UNIT clk_unit, ttix_unit;
|
||||
|
||||
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);
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
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 lpt (int32 pulse, int32 AC);
|
||||
extern int32 ttix (int32 inst, int32 AC);
|
||||
extern int32 ttox (int32 inst, int32 AC);
|
||||
extern int32 rk (int32 pulse, int32 AC);
|
||||
extern int32 rx (int32 pulse, int32 AC);
|
||||
extern int32 df60 (int32 pulse, int32 AC);
|
||||
extern int32 df61 (int32 pulse, int32 AC);
|
||||
extern int32 df62 (int32 pulse, int32 AC);
|
||||
extern int32 rf60 (int32 pulse, int32 AC);
|
||||
extern int32 rf61 (int32 pulse, int32 AC);
|
||||
extern int32 rf62 (int32 pulse, int32 AC);
|
||||
extern int32 rf64 (int32 pulse, int32 AC);
|
||||
extern int32 rl60 (int32 pulse, int32 AC);
|
||||
extern int32 rl61 (int32 pulse, int32 AC);
|
||||
extern int32 mt70 (int32 pulse, int32 AC);
|
||||
extern int32 mt71 (int32 pulse, int32 AC);
|
||||
extern int32 mt72 (int32 pulse, int32 AC);
|
||||
extern int32 dt76 (int32 pulse, int32 AC);
|
||||
extern int32 dt77 (int32 pulse, int32 AC);
|
||||
t_bool build_dev_tab (void);
|
||||
|
||||
/* CPU data structures
|
||||
|
||||
@@ -277,12 +257,10 @@ REG cpu_reg[] = {
|
||||
{ ORDATA (INT, int_req, INT_V_ION+1), REG_RO },
|
||||
{ ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO },
|
||||
{ ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO },
|
||||
{ FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO },
|
||||
{ BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC },
|
||||
{ ORDATA (PCQP, pcq_p, 6), REG_HRO },
|
||||
{ FLDATA (STOP_INST, stop_inst, 0) },
|
||||
{ ORDATA (WRU, sim_int_char, 8) },
|
||||
{ ORDATA (DEVENB, dev_enb, 32), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB cpu_mod[] = {
|
||||
@@ -302,7 +280,8 @@ DEVICE cpu_dev = {
|
||||
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
||||
1, 8, 15, 1, 8, 12,
|
||||
&cpu_ex, &cpu_dep, &cpu_reset,
|
||||
NULL, NULL, NULL };
|
||||
NULL, NULL, NULL,
|
||||
NULL, 0 };
|
||||
|
||||
t_stat sim_instr (void)
|
||||
{
|
||||
@@ -313,6 +292,7 @@ t_stat reason;
|
||||
|
||||
/* Restore register state */
|
||||
|
||||
if (build_dev_tab ()) return SCPE_STOP; /* build dev_tab */
|
||||
PC = saved_PC & 007777; /* load local copies */
|
||||
IF = saved_PC & 070000;
|
||||
DF = saved_DF & 070000;
|
||||
@@ -940,7 +920,7 @@ case 030:case 031:case 032:case 033: /* IOT */
|
||||
int_enable = INT_INIT_ENABLE;
|
||||
LAC = 0;
|
||||
break; } /* end switch pulse */
|
||||
continue; /* skip rest of IOT */
|
||||
break; /* end case 0 */
|
||||
|
||||
/* IOT, continued: memory extension */
|
||||
|
||||
@@ -993,7 +973,7 @@ case 030:case 031:case 032:case 033: /* IOT */
|
||||
default:
|
||||
reason = stop_inst;
|
||||
break; } /* end switch pulse */
|
||||
continue; /* skip rest of IOT */
|
||||
break; /* end case 20-27 */
|
||||
|
||||
/* IOT, continued: other special cases */
|
||||
|
||||
@@ -1010,90 +990,16 @@ case 030:case 031:case 032:case 033: /* IOT */
|
||||
default:
|
||||
reason = stop_inst;
|
||||
break; } /* end switch pulse */
|
||||
continue; /* skip rest of IOT */
|
||||
default: /* unknown device */
|
||||
reason = stop_inst; /* stop on flag */
|
||||
continue; /* skip rest of IOT */
|
||||
|
||||
/* IOT, continued: I/O devices */
|
||||
|
||||
case 1: /* PTR */
|
||||
iot_data = ptr (pulse, iot_data);
|
||||
break;
|
||||
case 2: /* PTP */
|
||||
iot_data = ptp (pulse, iot_data);
|
||||
break;
|
||||
case 3: /* TTI */
|
||||
iot_data = tti (pulse, iot_data);
|
||||
break;
|
||||
case 4: /* TTO */
|
||||
iot_data = tto (pulse, iot_data);
|
||||
break;
|
||||
case 013: /* CLK */
|
||||
iot_data = clk (pulse, iot_data);
|
||||
break;
|
||||
case 040: case 042: case 044: case 046: /* KL8JA in */
|
||||
if (dev_enb & INT_TTI1) iot_data = ttix (IR, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 041: case 043: case 045: case 047: /* KL8JA out */
|
||||
if (dev_enb & INT_TTI1) iot_data = ttox (IR, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 060: /* DF32/RF08 */
|
||||
if (dev_enb & INT_DF) iot_data = df60 (pulse, iot_data);
|
||||
else if (dev_enb & INT_RF) iot_data = rf60 (pulse, iot_data);
|
||||
else if (dev_enb & INT_RL) iot_data = rl60 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 061:
|
||||
if (dev_enb & INT_DF) iot_data = df61 (pulse, iot_data);
|
||||
else if (dev_enb & INT_RF) iot_data = rf61 (pulse, iot_data);
|
||||
else if (dev_enb & INT_RL) iot_data = rl61 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 062:
|
||||
if (dev_enb & INT_DF) iot_data = df62 (pulse, iot_data);
|
||||
else if (dev_enb & INT_RF) iot_data = rf62 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 064:
|
||||
if (dev_enb & INT_RF) iot_data = rf64 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 066: /* LPT */
|
||||
iot_data = lpt (pulse, iot_data);
|
||||
break;
|
||||
case 070: /* TM8E */
|
||||
if (dev_enb & INT_MT) iot_data = mt70 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 071:
|
||||
if (dev_enb & INT_MT) iot_data = mt71 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 072:
|
||||
if (dev_enb & INT_MT) iot_data = mt72 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 074: /* RK8E */
|
||||
if (dev_enb & INT_RK) iot_data = rk (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 075: /* RX8E */
|
||||
if (dev_enb & INT_RX) iot_data = rx (pulse, iot_data);
|
||||
break;
|
||||
case 076: /* TC01/TC08 */
|
||||
if (dev_enb & INT_DTA) iot_data = dt76 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break;
|
||||
case 077:
|
||||
if (dev_enb & INT_DTA) iot_data = dt77 (pulse, iot_data);
|
||||
else reason = stop_inst;
|
||||
break; /* end case 10 */
|
||||
default: /* I/O device */
|
||||
if (dev_tab[device]) { /* dev present? */
|
||||
iot_data = dev_tab[device] (IR, iot_data);
|
||||
LAC = (LAC & 010000) | (iot_data & 07777);
|
||||
if (iot_data & IOT_SKP) PC = (PC + 1) & 07777;
|
||||
if (iot_data >= IOT_REASON)
|
||||
reason = iot_data >> IOT_V_REASON; }
|
||||
else reason = stop_inst; /* stop on flag */
|
||||
break; } /* end switch device */
|
||||
LAC = (LAC & 010000) | (iot_data & 07777);
|
||||
if (iot_data & IOT_SKP) PC = (PC + 1) & 07777;
|
||||
if (iot_data >= IOT_REASON) reason = iot_data >> IOT_V_REASON;
|
||||
break; } /* end switch opcode */
|
||||
} /* end while */
|
||||
|
||||
@@ -1103,7 +1009,7 @@ saved_PC = IF | (PC & 07777); /* save copies */
|
||||
saved_DF = DF & 070000;
|
||||
saved_LAC = LAC & 017777;
|
||||
saved_MQ = MQ & 07777;
|
||||
pcq_r -> qptr = pcq_p; /* update pc q ptr */
|
||||
pcq_r->qptr = pcq_p; /* update pc q ptr */
|
||||
return reason;
|
||||
} /* end sim_instr */
|
||||
|
||||
@@ -1115,7 +1021,7 @@ int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING;
|
||||
saved_DF = IB = saved_PC & 070000;
|
||||
UF = UB = gtf = emode = 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;
|
||||
@@ -1156,38 +1062,80 @@ 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_dev (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_dev (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 IR, 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;
|
||||
static const uint8 std_dev[] =
|
||||
{ 000, 010, 020, 021, 022, 023, 024, 025, 026, 027 };
|
||||
|
||||
for (i = 0; i < DEV_MAX; i++) dev_tab[i] = NULL; /* clr table */
|
||||
for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */
|
||||
dev_tab[std_dev[i]] = &bad_dev;
|
||||
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */
|
||||
dibp = (DIB *) dptr->ctxt; /* get DIB */
|
||||
if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
04-Oct-02 RMS Added variable device number support
|
||||
20-Jan-02 RMS Fixed bug in TTx interrupt enable initialization
|
||||
25-Nov-01 RMS Added RL8A support
|
||||
16-Sep-01 RMS Added multiple KL support
|
||||
@@ -43,6 +44,7 @@
|
||||
#define STOP_RSRV 1 /* must be 1 */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_NOTSTD 4 /* non-std devno */
|
||||
|
||||
/* Memory */
|
||||
|
||||
@@ -63,6 +65,36 @@
|
||||
|
||||
#define TMR_CLK 0 /* timer 0 = clock */
|
||||
#define TMR_TTX 1 /* timer 1 = TTx */
|
||||
|
||||
/* Device information block */
|
||||
|
||||
#define DEV_MAXBLK 8 /* max dev block */
|
||||
#define DEV_MAX 64 /* total devices */
|
||||
|
||||
struct pdp8_dib {
|
||||
uint32 dev; /* base dev number */
|
||||
uint32 num; /* number of slots */
|
||||
int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat);
|
||||
};
|
||||
|
||||
typedef struct pdp8_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_CLK 013 /* clock */
|
||||
#define DEV_KJ8 040 /* extra terminals */
|
||||
#define DEV_DF 060 /* DF32 */
|
||||
#define DEV_RF 060 /* RF08 */
|
||||
#define DEV_RL 060 /* RL8A */
|
||||
#define DEV_LPT 066 /* line printer */
|
||||
#define DEV_MT 070 /* TM8E */
|
||||
#define DEV_RK 074 /* RK8E */
|
||||
#define DEV_RX 075 /* RX8E/RX28 */
|
||||
#define DEV_DTA 076 /* TC08 */
|
||||
|
||||
/* Interrupt flags
|
||||
|
||||
@@ -152,5 +184,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_dev (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
df DF32 fixed head disk
|
||||
|
||||
04-Oct-02 RMS Added DIBs, device number support
|
||||
28-Nov-01 RMS Added RL8A support
|
||||
25-Apr-01 RMS Added device enable/disable support
|
||||
|
||||
@@ -77,9 +78,9 @@
|
||||
else df_sta = df_sta & ~DFS_PCA
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, dev_enb, stop_inst;
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
extern int32 rf_devenb;
|
||||
|
||||
int32 df_sta = 0; /* status register */
|
||||
int32 df_da = 0; /* disk address */
|
||||
int32 df_done = 0; /* done flag */
|
||||
@@ -87,10 +88,15 @@ int32 df_wlk = 0; /* write lock */
|
||||
int32 df_time = 10; /* inter-word time */
|
||||
int32 df_burst = 1; /* burst mode flag */
|
||||
int32 df_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE df_dev;
|
||||
int32 df60 (int32 IR, int32 AC);
|
||||
int32 df61 (int32 IR, int32 AC);
|
||||
int32 df62 (int32 IR, int32 AC);
|
||||
t_stat df_svc (UNIT *uptr);
|
||||
t_stat pcell_svc (UNIT *uptr);
|
||||
t_stat df_reset (DEVICE *dptr);
|
||||
t_stat df_boot (int32 unitno);
|
||||
t_stat df_boot (int32 unitno, DEVICE *dptr);
|
||||
|
||||
/* DF32 data structures
|
||||
|
||||
@@ -100,6 +106,8 @@ t_stat df_boot (int32 unitno);
|
||||
df_reg RF register list
|
||||
*/
|
||||
|
||||
DIB df_dib = { DEV_DF, 3, { &df60, &df61, &df62 } };
|
||||
|
||||
UNIT df_unit =
|
||||
{ UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
|
||||
DF_SIZE) };
|
||||
@@ -115,25 +123,27 @@ REG df_reg[] = {
|
||||
{ DRDATA (TIME, df_time, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (BURST, df_burst, 0) },
|
||||
{ FLDATA (STOP_IOE, df_stopioe, 0) },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_DF), REG_HRO },
|
||||
{ ORDATA (DEVNUM, df_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB df_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, INT_DF, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_DF, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE df_dev = {
|
||||
"DF", &df_unit, df_reg, df_mod,
|
||||
1, 8, 17, 1, 8, 12,
|
||||
NULL, NULL, &df_reset,
|
||||
&df_boot, NULL, NULL };
|
||||
&df_boot, NULL, NULL,
|
||||
&df_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 df60 (int32 pulse, int32 AC)
|
||||
int32 df60 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 t;
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DCMA */
|
||||
@@ -161,9 +171,10 @@ return AC;
|
||||
AC = AC | old_df_sta
|
||||
*/
|
||||
|
||||
int32 df61 (int32 pulse, int32 AC)
|
||||
int32 df61 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 old_df_sta = df_sta;
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) /* DCEA */
|
||||
@@ -176,8 +187,10 @@ if (pulse & 4) {
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 df62 (int32 pulse, int32 AC)
|
||||
int32 df62 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DFSE */
|
||||
if ((df_sta & DFS_ERR) == 0) AC = AC | IOT_SKP; }
|
||||
@@ -200,7 +213,7 @@ int32 pa, t, mex;
|
||||
t_addr da;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
df_done = 1;
|
||||
int_req = int_req | INT_DF; /* update int req */
|
||||
return IORETURN (df_stopioe, SCPE_UNATT); }
|
||||
@@ -210,20 +223,20 @@ da = GET_DEX (df_sta) | df_da; /* form disk addr */
|
||||
do { M[DF_WC] = (M[DF_WC] + 1) & 07777; /* incr word count */
|
||||
M[DF_MA] = (M[DF_MA] + 1) & 07777; /* incr mem addr */
|
||||
pa = mex | M[DF_MA]; /* add extension */
|
||||
if (uptr -> FUNC == DF_READ) {
|
||||
if (uptr->FUNC == DF_READ) {
|
||||
if (MEM_ADDR_OK (pa)) /* read, check nxm */
|
||||
M[pa] = *(((int16 *) uptr -> filebuf) + da); }
|
||||
M[pa] = *(((int16 *) uptr->filebuf) + da); }
|
||||
else { t = (da >> 14) & 07;
|
||||
if ((df_wlk >> t) & 1) df_sta = df_sta | DFS_WLS;
|
||||
else { *(((int16 *) uptr -> filebuf) + da) = M[pa];
|
||||
if (da >= uptr -> hwmark)
|
||||
uptr -> hwmark = da + 1; } }
|
||||
else { *(((int16 *) uptr->filebuf) + da) = M[pa];
|
||||
if (da >= uptr->hwmark)
|
||||
uptr->hwmark = da + 1; } }
|
||||
da = (da + 1) & 0377777; } /* incr disk addr */
|
||||
while ((M[DF_WC] != 0) && (df_burst != 0)); /* brk if wc, no brst */
|
||||
|
||||
if (M[DF_WC] != 0) /* more to do? */
|
||||
sim_activate (&df_unit, df_time); /* sched next */
|
||||
else { if (uptr -> FUNC != DF_READ) da = (da - 1) & 0377777;
|
||||
else { if (uptr->FUNC != DF_READ) da = (da - 1) & 0377777;
|
||||
df_done = 1; /* done */
|
||||
int_req = int_req | INT_DF; } /* update int req */
|
||||
df_sta = (df_sta & ~DFS_DEX) | ((da >> (12 - DFS_V_DEX)) & DFS_DEX);
|
||||
@@ -235,8 +248,6 @@ return SCPE_OK;
|
||||
|
||||
t_stat df_reset (DEVICE *dptr)
|
||||
{
|
||||
if (dev_enb & INT_DF) /* DF? no RF or RL */
|
||||
dev_enb = dev_enb & ~(INT_RF | INT_RL);
|
||||
df_sta = df_da = 0;
|
||||
df_done = 1;
|
||||
int_req = int_req & ~INT_DF; /* clear interrupt */
|
||||
@@ -247,11 +258,11 @@ return SCPE_OK;
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define OS8_START 07750
|
||||
#define OS8_LEN (sizeof (os8_rom) / sizeof (int32))
|
||||
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
|
||||
#define DM4_START 00200
|
||||
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int32))
|
||||
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
|
||||
|
||||
static const int32 os8_rom[] = {
|
||||
static const uint16 os8_rom[] = {
|
||||
07600, /* 7750, CLA CLL ; also word count */
|
||||
06603, /* 7751, DMAR ; also address */
|
||||
06622, /* 7752, DFSC ; done? */
|
||||
@@ -259,7 +270,7 @@ static const int32 os8_rom[] = {
|
||||
05752 /* 7754, JMP @.-2 ; enter boot */
|
||||
};
|
||||
|
||||
static const int32 dm4_rom[] = {
|
||||
static const uint16 dm4_rom[] = {
|
||||
00200, 07600, /* 0200, CLA CLL */
|
||||
00201, 06603, /* 0201, DMAR ; read */
|
||||
00202, 06622, /* 0202, DFSC ; done? */
|
||||
@@ -269,7 +280,7 @@ static const int32 dm4_rom[] = {
|
||||
07751, 07576 /* 7751, 7576 ; address */
|
||||
};
|
||||
|
||||
t_stat df_boot (int32 unitno)
|
||||
t_stat df_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 sim_switches, saved_PC;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: PDP-8 Simulator Usage
|
||||
Date: 15-Jun-2002
|
||||
Date: 15-Nov-2002
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
@@ -37,11 +37,11 @@ This memorandum documents the PDP-8 simulator.
|
||||
1. Simulator Files
|
||||
|
||||
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
|
||||
|
||||
@@ -79,18 +79,34 @@ RK RK8E/RK05 cartridge disk controller with four drives
|
||||
RF RF08/RS08 fixed head disk controller with four platters, or
|
||||
DF DF32/DS32 fixed head disk controller with four platters
|
||||
RL RL8A/RL01 cartridge disk controller with four drives
|
||||
RX RX8E/RX01 floppy disk controller with two drives
|
||||
RX RX8E/RX01, RX28/RX02 floppy disk controller with two drives
|
||||
DT TC08/TU56 DECtape controller with eight drives
|
||||
MT TM8E/TU10 magnetic tape controller with eight drives
|
||||
|
||||
The RK, RF, DF, RL, RX, DT, MT, and TTIX/TTOX devices can be set DISABLEd.
|
||||
The PDP-8 can support only one of the set {DF32, RF08, RL8A}, since they
|
||||
use the same IOT's. The simulator defaults to the RF08. To change the
|
||||
disk at device addresses 60-61:
|
||||
Most devices can be disabled or enabled, by the commands:
|
||||
|
||||
SET RF DISABLED disable RF08
|
||||
SET DF ENABLED, or enable DF32
|
||||
SET RL ENABLED enable RL8A
|
||||
SET <dev> DISABLED
|
||||
SET <dev> ENABLED
|
||||
|
||||
The simulator allows most device numbers to be changed, by the command:
|
||||
|
||||
SET <dev> DEV=<number>
|
||||
|
||||
The PDP-8 can support only one of the set {DF32, RF08, RL8A} using the
|
||||
default device numbers, since they all use device numbers 60-61. The
|
||||
default is the RF08. To change the disk at device numbers 60-61:
|
||||
|
||||
sim> SET RF DISABLED disable RF08
|
||||
sim> SET DF ENABLED, or enable DF32
|
||||
sim> SET RL ENABLED enable RL8A
|
||||
|
||||
Alternately, the device conflict can be eliminated by changing device
|
||||
numbers:
|
||||
|
||||
sim> SET RL DEV=50
|
||||
sim> SET RL ENA
|
||||
|
||||
However, devices can only be BOOTed with their default device numbers.
|
||||
|
||||
The PDP-8 simulator implements one unique stop condition: if an undefined
|
||||
instruction (unimplemented IOT or OPR) is decoded, and register STOP_INST
|
||||
@@ -218,11 +234,15 @@ Error handling is as follows:
|
||||
|
||||
2.2.3 KL8E 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. This is required by OS/8 and is on by default.
|
||||
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, and the high order bit is
|
||||
forced to one on input. 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 terminal input implements these registers:
|
||||
The terminal input (TTI) polls the console keyboard for input. It
|
||||
implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
@@ -235,7 +255,7 @@ The terminal input implements these registers:
|
||||
|
||||
2.2.4 KL8E Terminal Output (TTO)
|
||||
|
||||
The terminal output (TTO) writes to the simulator console window. It
|
||||
The terminal output (TTO) writes to the simulator console window. It
|
||||
implements these registers:
|
||||
|
||||
name size comments
|
||||
@@ -302,9 +322,11 @@ command specifies the port to be used:
|
||||
where port is a decimal number between 1 and 65535 that is not being used
|
||||
for other TCP/IP activities.
|
||||
|
||||
The additional terminals have one option, UC; when set, lower case input
|
||||
characters are automatically converted to upper case. This is required
|
||||
by TSS/8 and is on by default for all lines.
|
||||
The additional terminals can be set to one of three modes: UC, 7B, or
|
||||
8B. In KSR mode, lower case input and output characters are converted
|
||||
automatically to upper case. In 7B mode, input and output characters
|
||||
are masked to 7 bits. In 8B mode, characters are not modified. The
|
||||
default mode is UC.
|
||||
|
||||
Once TTIX is attached and the simulator is running, the terminals listen
|
||||
for connections on the specified port. They assume that the incoming
|
||||
@@ -419,26 +441,43 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.4 RX8E/RX01 Floppy Disk (RX)
|
||||
2.4 RX8E/RX01, RX28/RX02 Floppy Disk (RX)
|
||||
|
||||
The RX can be configured as an RX8E with two RX01 drives, or an RX28 with
|
||||
two RX02 drives:
|
||||
|
||||
SET RX RX8E set controller to RX8E/RX01
|
||||
SET RX RX28 set controller to RX28/RX02
|
||||
|
||||
The controller is set to the RX8E by default. The RX28 is not backwards-
|
||||
compatible with the RX8E and will not work with the standard OS/8 V3D floppy
|
||||
disk driver.
|
||||
|
||||
RX8E options include the ability to set units write enabled or write locked:
|
||||
|
||||
SET RXn LOCKED set unit n write locked
|
||||
SET RXn WRITEENABLED set unit n write enabled
|
||||
|
||||
The RX8E supports the BOOT command.
|
||||
RX28 options include, in addition, the ability to set the unit density to
|
||||
single density, double density, or autosized; autosizing is the default:
|
||||
|
||||
The RX8E implements these registers:
|
||||
SET RXn SINGLE set unit n single density
|
||||
SET RXn DOUBLE set unit n double density
|
||||
SET RXn AUTOSIZE set unit n autosize
|
||||
|
||||
The RX8E and RX28 support the BOOT command.
|
||||
|
||||
The RX8E and RX28 implement these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
RXCS 12 status
|
||||
RXDB 12 data buffer
|
||||
RXES 8 error status
|
||||
RXES 12 error status
|
||||
RXTA 8 current track
|
||||
RXSA 8 current sector
|
||||
STAPTR 3 controller state
|
||||
BUFPTR 3 buffer pointer
|
||||
STAPTR 4 controller state
|
||||
BUFPTR 8 buffer pointer
|
||||
INT 1 interrupt pending flag
|
||||
DONE 1 device done flag
|
||||
ENABLE 1 interrupt enable flag
|
||||
@@ -448,7 +487,7 @@ The RX8E implements these registers:
|
||||
STIME 24 seek time, per track
|
||||
XTIME 24 transfer ready delay
|
||||
STOP_IOE 1 stop on I/O error
|
||||
SBUF[0:127] 8 sector buffer array
|
||||
SBUF[0:255] 8 sector buffer array
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
@@ -457,13 +496,13 @@ Error handling is as follows:
|
||||
not attached 1 report error and stop
|
||||
0 disk not ready
|
||||
|
||||
RX01 data files are buffered in memory; therefore, end of file and OS
|
||||
I/O errors cannot occur.
|
||||
RX01 and RX02 data files are buffered in memory; therefore, end of file
|
||||
and OS I/O errors cannot occur.
|
||||
|
||||
2.5 Fixed Head Disks
|
||||
|
||||
Either the RF08 or the DF32 can be present in a configuration, but
|
||||
not both.
|
||||
not both, with default device addressing.
|
||||
|
||||
2.5.1 RF08/RS08 Fixed Head Disk (RF)
|
||||
|
||||
@@ -483,7 +522,7 @@ The RF08 implements these registers:
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
The RF08 supports the BOOT command. The default bootstrap is for OS/8. To
|
||||
bootstrap the 4K Disk Monitor, use the BOOT -D command.
|
||||
bootstrap the 4K Disk Monitor, use the BOOT -D RF command.
|
||||
|
||||
The RF08 is a three-cycle data break device. If BURST = 0, word transfers
|
||||
are scheduled individually; if BURST = 1, the entire transfer occurs in
|
||||
@@ -517,7 +556,7 @@ The DF32 implements these registers:
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
The DF32 supports the BOOT command. The default bootstrap is for OS/8. To
|
||||
bootstrap the 4K Disk Monitor, use the BOOT -D command.
|
||||
bootstrap the 4K Disk Monitor, use the BOOT -D DF command.
|
||||
|
||||
The DF32 is a three-cycle data break device. If BURST = 0, word transfers
|
||||
are scheduled individually; if BURST = 1, the entire transfer occurs in
|
||||
@@ -544,12 +583,13 @@ locked.
|
||||
|
||||
Units can also be set ONLINE or OFFLINE. The TC08 supports the BOOT command.
|
||||
|
||||
The TC08 supports 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 TC08 supports 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-9/11/15) format
|
||||
-n native (PDP-8) 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
|
||||
@@ -616,12 +656,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
|
||||
|
||||
|
||||
323
PDP8/pdp8_dt.c
323
PDP8/pdp8_dt.c
@@ -25,6 +25,9 @@
|
||||
|
||||
dt TC08/TU56 DECtape
|
||||
|
||||
17-Oct-02 RMS Fixed bug in end of reel logic
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
12-Sep-02 RMS Added support for 16b format
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
|
||||
@@ -37,11 +40,14 @@
|
||||
19-Mar-01 RMS Changed bootstrap to support 4k disk monitor
|
||||
15-Mar-01 RMS Added 129th word to PDP-8 format
|
||||
|
||||
PDP-8 DECtapes are represented by fixed length data blocks of 12b words. Two
|
||||
tape formats are supported:
|
||||
PDP-8 DECtapes are represented in memory by fixed length buffer of 16b words.
|
||||
Three file formats are supported:
|
||||
|
||||
12b 129 words per block
|
||||
16b/18b/36b 384 words per block
|
||||
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 18/36bb DECtape file is read in, it is converted to 12b 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
|
||||
@@ -80,10 +86,11 @@
|
||||
|
||||
#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 07754 /* word count */
|
||||
@@ -108,6 +115,7 @@
|
||||
|
||||
#define D18_NBSIZE ((D18_BSIZE * D8_WSIZE) / D18_WSIZE)
|
||||
#define D18_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int32))
|
||||
#define D11_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int16))
|
||||
|
||||
/* 12b DECtape constants */
|
||||
|
||||
@@ -117,6 +125,7 @@
|
||||
#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
|
||||
#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE))
|
||||
#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */
|
||||
#define D8_FILSIZ (D8_CAPAC * sizeof (int16))
|
||||
|
||||
/* This controller */
|
||||
|
||||
@@ -125,18 +134,18 @@
|
||||
|
||||
/* 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 */
|
||||
@@ -214,10 +223,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)
|
||||
|
||||
@@ -239,9 +248,10 @@
|
||||
#define ABS(x) (((x) < 0)? (-(x)): (x))
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, dev_enb;
|
||||
extern int32 int_req;
|
||||
extern UNIT cpu_unit;
|
||||
extern int32 sim_switches;
|
||||
|
||||
int32 dtsa = 0; /* status A */
|
||||
int32 dtsb = 0; /* status B */
|
||||
int32 dt_ltime = 12; /* interline time */
|
||||
@@ -250,11 +260,15 @@ int32 dt_dctime = 72000; /* decel time */
|
||||
int32 dt_substate = 0;
|
||||
int32 dt_log = 0; /* debug */
|
||||
int32 dt_logblk = 0;
|
||||
|
||||
DEVICE dt_dev;
|
||||
int32 dt76 (int32 IR, int32 AC);
|
||||
int32 dt77 (int32 IR, int32 AC);
|
||||
t_stat dt_svc (UNIT *uptr);
|
||||
t_stat dt_reset (DEVICE *dptr);
|
||||
t_stat dt_attach (UNIT *uptr, char *cptr);
|
||||
t_stat dt_detach (UNIT *uptr);
|
||||
t_stat dt_boot (int32 unitno);
|
||||
t_stat dt_boot (int32 unitno, DEVICE *dptr);
|
||||
void dt_deselect (int32 oldf);
|
||||
void dt_newsa (int32 newf);
|
||||
void dt_newfnc (UNIT *uptr, int32 newsta);
|
||||
@@ -274,6 +288,8 @@ extern int32 sim_is_running;
|
||||
dt_mod DT modifier list
|
||||
*/
|
||||
|
||||
DIB dt_dib = { DEV_DTA, 2, { &dt76, &dt77 } };
|
||||
|
||||
UNIT dt_unit[] = {
|
||||
{ UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
|
||||
UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
|
||||
@@ -313,30 +329,31 @@ 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, INT_V_DTA), REG_HRO },
|
||||
{ ORDATA (DEVNUM, 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, INT_DTA, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_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_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE dt_dev = {
|
||||
"DT", dt_unit, dt_reg, dt_mod,
|
||||
DT_NUMDR, 8, 24, 1, 8, 12,
|
||||
NULL, NULL, &dt_reset,
|
||||
&dt_boot, &dt_attach, &dt_detach };
|
||||
&dt_boot, &dt_attach, &dt_detach,
|
||||
&dt_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 dt76 (int32 pulse, int32 AC)
|
||||
int32 dt76 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
int32 old_dtsa = dtsa, fnc;
|
||||
UNIT *uptr;
|
||||
|
||||
@@ -351,18 +368,20 @@ if (pulse & 06) { /* 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_WALL) && (uptr -> flags & UNIT_WPRT)) ||
|
||||
((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT)))
|
||||
((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
|
||||
((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
|
||||
dt_seterr (uptr, DTB_SEL); /* select err */
|
||||
else dt_newsa (dtsa);
|
||||
DT_UPDINT; }
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 dt77 (int32 pulse, int32 AC)
|
||||
int32 dt77 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
if ((pulse & 01) && (dtsb & (DTB_ERF |DTB_DTF))) /* DTSF */
|
||||
AC = IOT_SKP | AC;
|
||||
if (pulse & 02) AC = AC | dtsb; /* DTRB */
|
||||
@@ -378,7 +397,7 @@ 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_mot = DTS_GETMOT (uptr->STATE);
|
||||
|
||||
if (old_mot >= DTS_ATSF) /* at speed? */
|
||||
dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR));
|
||||
@@ -409,19 +428,18 @@ 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 */
|
||||
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? */
|
||||
@@ -487,15 +505,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 */
|
||||
@@ -528,7 +546,7 @@ case FNC_WALL: /* write all */
|
||||
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);
|
||||
@@ -541,7 +559,7 @@ case FNC_WALL: /* write all */
|
||||
default:
|
||||
dt_seterr (uptr, DTB_SEL); /* bad state */
|
||||
return; }
|
||||
sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime);
|
||||
sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -566,13 +584,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;
|
||||
@@ -588,12 +606,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 */
|
||||
@@ -608,10 +626,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);
|
||||
int16 *bptr = uptr -> filebuf;
|
||||
int32 fnc = DTS_GETFNC (uptr->STATE);
|
||||
int16 *bptr = uptr->filebuf;
|
||||
int32 unum = uptr - dt_dev.units;
|
||||
int32 blk, wrd, ma, relpos, dat;
|
||||
t_addr ba;
|
||||
@@ -626,12 +644,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 */
|
||||
@@ -650,7 +668,7 @@ 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 */
|
||||
@@ -668,7 +686,7 @@ case FNC_SRCH: /* search */
|
||||
break;
|
||||
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;
|
||||
|
||||
/* Read has four subcases
|
||||
@@ -685,7 +703,7 @@ case DTS_OFR: /* off reel */
|
||||
*/
|
||||
|
||||
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? */
|
||||
@@ -733,7 +751,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? */
|
||||
@@ -753,7 +771,7 @@ case FNC_WRIT: /* write */
|
||||
dat = dt_substate? 0: M[ma]; /* get word */
|
||||
if (dir) dat = dt_comobv (dat); /* rev? comp obv */
|
||||
bptr[ba] = dat; /* 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);
|
||||
@@ -779,13 +797,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) & 07777; /* incr WC, CA */
|
||||
M[DT_CA] = (M[DT_CA] + 1) & 07777;
|
||||
ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get 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;
|
||||
dat = bptr[ba]; /* get tape word */
|
||||
if (dir) dat = dt_comobv (dat); } /* rev? comp obv */
|
||||
@@ -813,7 +831,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) & 07777; /* incr WC, CA */
|
||||
M[DT_CA] = (M[DT_CA] + 1) & 07777;
|
||||
ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */
|
||||
@@ -821,10 +839,10 @@ case FNC_WALL:
|
||||
(relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
|
||||
dat = M[ma]; /* get mem word */
|
||||
if (dir) dat = dt_comobv (dat);
|
||||
wrd = DT_LIN2WD (uptr -> pos, uptr);
|
||||
wrd = DT_LIN2WD (uptr->pos, uptr);
|
||||
ba = (blk * DTU_BSIZE (uptr)) + wrd;
|
||||
bptr[ba] = dat; /* 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;
|
||||
@@ -907,7 +925,7 @@ return 0;
|
||||
|
||||
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 */
|
||||
@@ -928,7 +946,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;
|
||||
}
|
||||
|
||||
@@ -946,7 +964,7 @@ return dat;
|
||||
|
||||
int32 dt_csum (UNIT *uptr, int32 blk)
|
||||
{
|
||||
int16 *bptr = uptr -> filebuf;
|
||||
int16 *bptr = uptr->filebuf;
|
||||
int32 ba = blk * DTU_BSIZE (uptr);
|
||||
int32 i, csum, wrd;
|
||||
|
||||
@@ -967,7 +985,7 @@ UNIT *uptr;
|
||||
for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */
|
||||
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);
|
||||
@@ -975,8 +993,8 @@ for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */
|
||||
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;
|
||||
@@ -990,9 +1008,9 @@ return SCPE_OK;
|
||||
*/
|
||||
|
||||
#define BOOT_START 0200
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const int32 boot_rom[] = {
|
||||
static const uint16 boot_rom[] = {
|
||||
07600, /* 200, CLA CLL */
|
||||
01216, /* TAD MVB ; move back */
|
||||
04210, /* JMS DO ; action */
|
||||
@@ -1014,12 +1032,13 @@ static const int32 boot_rom[] = {
|
||||
00220 /* RF, 0220 */
|
||||
};
|
||||
|
||||
t_stat dt_boot (int32 unitno)
|
||||
t_stat dt_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (unitno) return SCPE_ARG; /* only unit 0 */
|
||||
if (dt_dib.dev != DEV_DTA) return STOP_NOTSTD; /* only std devno */
|
||||
dt_unit[unitno].pos = DT_EZLIN;
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
@@ -1028,107 +1047,121 @@ return SCPE_OK;
|
||||
|
||||
/* Attach routine
|
||||
|
||||
Determine native or PDP11/15 format
|
||||
Determine 12b, 16b, or 18b/36b format
|
||||
Allocate buffer
|
||||
If native, read data into buffer
|
||||
If PDP9/11/15, convert 18b data to 12b and read into buffer
|
||||
If 16b or 18b, read 16b or 18b format and convert to 12b in buffer
|
||||
If 12b, read data into buffer
|
||||
*/
|
||||
|
||||
t_stat dt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
int32 k, p;
|
||||
int16 *bptr;
|
||||
uint16 pdp11b[D18_NBSIZE], *bptr;
|
||||
int32 i, k, p;
|
||||
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 = F */
|
||||
else if (!(sim_switches & SWMASK ('N'))) { /* autosize? */
|
||||
if ((fseek (uptr -> fileref, 0, SEEK_END) == 0) &&
|
||||
(p = ftell (uptr -> fileref)) &&
|
||||
(p == D18_FILSIZ)) uptr -> flags = uptr -> flags & ~UNIT_8FMT; }
|
||||
uptr -> capac = DTU_CAPAC (uptr); /* set capacity */
|
||||
uptr -> filebuf = calloc (uptr -> capac, sizeof (int16));
|
||||
if (uptr -> filebuf == NULL) { /* can't alloc? */
|
||||
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
|
||||
if (sim_switches & SWMASK ('T')) /* att 18b? */
|
||||
uptr->flags = uptr->flags & ~UNIT_8FMT;
|
||||
else if (sim_switches & SWMASK ('S')) /* att 16b? */
|
||||
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
|
||||
else if (!(sim_switches & SWMASK ('R')) && /* autosize? */
|
||||
(fseek (uptr->fileref, 0, SEEK_END) == 0) &&
|
||||
((p = ftell (uptr->fileref)) > 0)) {
|
||||
if (p == D11_FILSIZ)
|
||||
uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
|
||||
if (p > D8_FILSIZ) uptr->flags = uptr->flags & ~UNIT_8FMT; }
|
||||
uptr->capac = DTU_CAPAC (uptr); /* set capacity */
|
||||
uptr->filebuf = calloc (uptr->capac, sizeof (int16));
|
||||
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 */
|
||||
bptr = uptr -> filebuf; /* file buffer */
|
||||
if (uptr -> flags & UNIT_8FMT) /* PDP8? */
|
||||
uptr -> hwmark = fxread (uptr -> filebuf, sizeof (int16),
|
||||
uptr -> capac, uptr -> fileref);
|
||||
else { /* PDP9/11/15 */
|
||||
for (ba = 0; ba < uptr -> capac; ) { /* loop thru file */
|
||||
k = fxread (pdp18b, sizeof (int32), D18_NBSIZE, uptr -> fileref);
|
||||
if (k == 0) break;
|
||||
for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0;
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */
|
||||
bptr[ba] = (pdp18b[k] >> 6) & 07777;
|
||||
bptr[ba + 1] = ((pdp18b[k] & 077) << 6) |
|
||||
((pdp18b[k + 1] >> 12) & 077);
|
||||
bptr[ba + 2] = pdp18b[k + 1] & 07777;
|
||||
ba = ba + 3; } /* end blk loop */
|
||||
} /* end file loop */
|
||||
uptr -> hwmark = ba; } /* end else */
|
||||
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? */
|
||||
uptr->hwmark = fxread (uptr->filebuf, sizeof (int16),
|
||||
uptr->capac, uptr->fileref);
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->capac; ) { /* loop thru file */
|
||||
if (uptr->flags & UNIT_11FMT) {
|
||||
k = fxread (pdp11b, sizeof (int16), D18_NBSIZE, uptr->fileref);
|
||||
for (i = 0; i < k; i++) pdp18b[i] = pdp11b[i]; }
|
||||
else k = fxread (pdp18b, sizeof (int32), D18_NBSIZE, uptr->fileref);
|
||||
if (k == 0) break;
|
||||
for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0;
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */
|
||||
bptr[ba] = (pdp18b[k] >> 6) & 07777;
|
||||
bptr[ba + 1] = ((pdp18b[k] & 077) << 6) |
|
||||
((pdp18b[k + 1] >> 12) & 077);
|
||||
bptr[ba + 2] = pdp18b[k + 1] & 07777;
|
||||
ba = ba + 3; } /* end blk loop */
|
||||
} /* end file loop */
|
||||
uptr->hwmark = ba; } /* end else */
|
||||
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 native, write buffer to file
|
||||
If PDP9/11/15, convert 12b buffer to 18b and write to file
|
||||
If 12b, write buffer to file
|
||||
If 16b or 18b, convert 12b buffer to 16b or 18b and write to file
|
||||
Deallocate buffer
|
||||
*/
|
||||
|
||||
t_stat dt_detach (UNIT* uptr)
|
||||
{
|
||||
uint32 pdp18b[D18_NBSIZE];
|
||||
int32 k;
|
||||
uint16 pdp11b[D18_NBSIZE], *bptr;
|
||||
int32 i, k;
|
||||
int32 unum = uptr - dt_dev.units;
|
||||
int16 *bptr;
|
||||
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? */
|
||||
dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
|
||||
DT_UPDINT; }
|
||||
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 */
|
||||
bptr = uptr -> filebuf; /* file buffer */
|
||||
if (uptr -> flags & UNIT_8FMT) /* PDP8? */
|
||||
fxwrite (uptr -> filebuf, sizeof (int16), /* write file */
|
||||
uptr -> hwmark, uptr -> fileref);
|
||||
else { /* PDP9/11/15 */
|
||||
for (ba = 0; ba < uptr -> hwmark; ) { /* loop thru buf */
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) {
|
||||
pdp18b[k] = ((uint32) (bptr[ba] & 07777) << 6) |
|
||||
((uint32) (bptr[ba + 1] >> 6) & 077);
|
||||
pdp18b[k + 1] = ((uint32) (bptr[ba + 1] & 077) << 12) |
|
||||
((uint32) (bptr[ba + 2] & 07777));
|
||||
ba = ba + 3; } /* end loop blk */
|
||||
fxwrite (pdp18b, sizeof (int32),
|
||||
D18_NBSIZE, uptr -> fileref);
|
||||
rewind (uptr->fileref); /* start of file */
|
||||
if (uptr->flags & UNIT_8FMT) /* PDP8? */
|
||||
fxwrite (uptr->filebuf, sizeof (int16), /* write file */
|
||||
uptr->hwmark, uptr->fileref);
|
||||
else { /* 16b/18b */
|
||||
for (ba = 0; ba < uptr->hwmark; ) { /* loop thru buf */
|
||||
for (k = 0; k < D18_NBSIZE; k = k + 2) {
|
||||
pdp18b[k] = ((uint32) (bptr[ba] & 07777) << 6) |
|
||||
((uint32) (bptr[ba + 1] >> 6) & 077);
|
||||
pdp18b[k + 1] = ((uint32) (bptr[ba + 1] & 077) << 12) |
|
||||
((uint32) (bptr[ba + 2] & 07777));
|
||||
ba = ba + 3; } /* end loop blk */
|
||||
if (uptr->flags & UNIT_11FMT) { /* 16b? */
|
||||
for (i = 0; i < D18_NBSIZE; i++) pdp11b[i] = pdp18b[i];
|
||||
fxwrite (pdp11b, sizeof (int16),
|
||||
D18_NBSIZE, uptr->fileref); }
|
||||
else fxwrite (pdp18b, sizeof (int32),
|
||||
D18_NBSIZE, uptr->fileref);
|
||||
} /* end loop buf */
|
||||
} /* end else */
|
||||
if (ferror (uptr -> fileref)) perror ("I/O error");
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,19 @@
|
||||
|
||||
lpt LP8E line printer
|
||||
|
||||
04-Oct-02 RMS Added DIB, enable/disable, device number support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 lpt_err = 0; /* error flag */
|
||||
int32 lpt_stopioe = 0; /* stop on error */
|
||||
|
||||
DEVICE lpt_dev;
|
||||
int32 lpt (int32 IR, int32 AC);
|
||||
t_stat lpt_svc (UNIT *uptr);
|
||||
t_stat lpt_reset (DEVICE *dptr);
|
||||
t_stat lpt_attach (UNIT *uptr, char *cptr);
|
||||
@@ -45,6 +50,8 @@ t_stat lpt_detach (UNIT *uptr);
|
||||
lpt_reg LPT register list
|
||||
*/
|
||||
|
||||
DIB lpt_dib = { DEV_LPT, 1, { &lpt } };
|
||||
|
||||
UNIT lpt_unit = {
|
||||
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
@@ -57,19 +64,26 @@ REG lpt_reg[] = {
|
||||
{ DRDATA (POS, lpt_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, lpt_stopioe, 0) },
|
||||
{ ORDATA (DEVNUM, lpt_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB lpt_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
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 };
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 lpt (int32 pulse, int32 AC)
|
||||
int32 lpt (int32 IR, int32 AC)
|
||||
{
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 1: /* PSKF */
|
||||
return (dev_done & INT_LPT)? IOT_SKP + AC: AC;
|
||||
case 2: /* PCLF */
|
||||
|
||||
296
PDP8/pdp8_mt.c
296
PDP8/pdp8_mt.c
@@ -25,6 +25,10 @@
|
||||
|
||||
mt TM8E/TU10 magtape
|
||||
|
||||
30-Oct-02 RMS Revised BOT handling, added error record handling
|
||||
04-Oct-02 RMS Added DIBs, device number support
|
||||
30-Aug-02 RMS Revamped error handling
|
||||
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 Changed enable/disable support
|
||||
@@ -54,10 +58,10 @@
|
||||
|
||||
#define MT_NUMDR 8 /* #drives */
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */
|
||||
#define UNIT_WLK (1 << UNIT_V_WLK)
|
||||
#define UNIT_W_UF 2 /* saved user flags */
|
||||
#define UNIT_PNU (1 << UNIT_V_PNU)
|
||||
#define USTAT u3 /* unit status */
|
||||
#define UNUM u4 /* unit number */
|
||||
#define MT_MAXFR (1 << 16) /* max record lnt */
|
||||
#define DBSIZE (1 << 12) /* max data cmd */
|
||||
#define DBMASK (SBSIZE - 1)
|
||||
@@ -94,10 +98,10 @@
|
||||
#define FN_CRC 00200 /* read CRC */
|
||||
#define FN_GO 00100 /* go */
|
||||
#define FN_INC 00040 /* incr mode */
|
||||
#define FN_RMASK 07740 /* readable bits */
|
||||
#define FN_RMASK 07700 /* readable bits */
|
||||
#define GET_FNC(x) (((x) >> FN_V_FNC) & FN_M_FNC)
|
||||
|
||||
/* Status - stored in mt_sta or (*) uptr -> USTAT */
|
||||
/* Status - stored in mt_sta or (*) uptr->USTAT */
|
||||
|
||||
#define STA_ERR (04000 << 12) /* error */
|
||||
#define STA_REW (02000 << 12) /* *rewinding */
|
||||
@@ -111,6 +115,8 @@
|
||||
#define STA_WLK (00004 << 12) /* *write locked */
|
||||
#define STA_CPE (00002 << 12) /* compare error */
|
||||
#define STA_ILL (00001 << 12) /* illegal */
|
||||
#define STA_9TK 00040 /* 9 track */
|
||||
/* #define STA_BAD 00020 /* bad tape?? */
|
||||
#define STA_INC 00010 /* increment error */
|
||||
#define STA_LAT 00004 /* lateral par error */
|
||||
#define STA_CRC 00002 /* CRC error */
|
||||
@@ -120,13 +126,15 @@
|
||||
#define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \
|
||||
STA_EOT | STA_WLK) /* kept in USTAT */
|
||||
#define STA_EFLGS (STA_BOT | STA_PAR | STA_RLE | STA_DLT | \
|
||||
STA_EOT | STA_CPE | STA_ILL | STA_EOF | STA_INC)
|
||||
STA_EOT | STA_CPE | STA_ILL | STA_EOF | \
|
||||
STA_INC )
|
||||
/* set error */
|
||||
#define TUR(u) (!sim_is_active (u)) /* tape unit ready */
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, dev_enb, stop_inst;
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 mt_cu = 0; /* command/unit */
|
||||
int32 mt_fn = 0; /* function */
|
||||
int32 mt_ca = 0; /* current address */
|
||||
@@ -136,6 +144,11 @@ int32 mt_db = 0; /* data buffer */
|
||||
int32 mt_done = 0; /* mag tape flag */
|
||||
int32 mt_time = 10; /* record latency */
|
||||
int32 mt_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE mt_dev;
|
||||
int32 mt70 (int32 IR, int32 AC);
|
||||
int32 mt71 (int32 IR, int32 AC);
|
||||
int32 mt72 (int32 IR, int32 AC);
|
||||
t_stat mt_svc (UNIT *uptr);
|
||||
t_stat mt_reset (DEVICE *dptr);
|
||||
t_stat mt_attach (UNIT *uptr, char *cptr);
|
||||
@@ -145,6 +158,8 @@ int32 mt_ixma (int32 xma);
|
||||
t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
UNIT *mt_busy (void);
|
||||
void mt_set_done (void);
|
||||
t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
|
||||
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err);
|
||||
|
||||
/* MT data structures
|
||||
|
||||
@@ -154,6 +169,8 @@ void mt_set_done (void);
|
||||
mt_mod MT modifier list
|
||||
*/
|
||||
|
||||
DIB mt_dib = { DEV_MT, 3, { &mt70, &mt71, &mt72 } };
|
||||
|
||||
UNIT mt_unit[] = {
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
|
||||
@@ -179,33 +196,32 @@ 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, INT_V_MT), REG_HRO },
|
||||
{ FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB mt_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mt_vlock },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_MT, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_MT, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 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 routines */
|
||||
|
||||
int32 mt70 (int32 pulse, int32 AC)
|
||||
int32 mt70 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 f;
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 1: /* LWCR */
|
||||
mt_wc = AC; /* load word count */
|
||||
return 0;
|
||||
@@ -223,9 +239,6 @@ case 5: /* LCMR */
|
||||
mt_cu = AC; /* load command reg */
|
||||
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
|
||||
return 0;
|
||||
|
||||
/* MT70, continued */
|
||||
|
||||
case 6: /* LFGR */
|
||||
if (mt_busy ()) mt_sta = mt_sta | STA_ILL; /* busy? illegal op */
|
||||
mt_fn = AC; /* load function */
|
||||
@@ -233,20 +246,20 @@ case 6: /* LFGR */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return 0; }
|
||||
f = GET_FNC (mt_fn); /* get function */
|
||||
if (((uptr -> flags & UNIT_ATT) == 0) || !TUR (uptr) ||
|
||||
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT))
|
||||
|| (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr -> pos == 0))) {
|
||||
if (((uptr->flags & UNIT_ATT) == 0) || !TUR (uptr) ||
|
||||
(((f == FN_WRITE) || (f == FN_WREOF)) && (uptr->flags & UNIT_WPRT))
|
||||
|| (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr->USTAT & STA_BOT))) {
|
||||
mt_sta = mt_sta | STA_ILL; /* illegal op error */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return 0; }
|
||||
uptr -> USTAT = uptr -> USTAT & STA_WLK; /* clear status */
|
||||
uptr->USTAT = uptr->USTAT & STA_WLK; /* clear status */
|
||||
if (f == FN_UNLOAD) { /* unload? */
|
||||
detach_unit (uptr); /* set offline */
|
||||
uptr -> USTAT = STA_REW | STA_REM; /* rewinding, off */
|
||||
uptr->USTAT = STA_REW | STA_REM; /* rewinding, off */
|
||||
mt_set_done (); } /* set done */
|
||||
else if (f == FN_REWIND) { /* rewind */
|
||||
uptr -> USTAT = uptr -> USTAT | STA_REW; /* rewinding */
|
||||
uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */
|
||||
mt_set_done (); } /* set done */
|
||||
else mt_done = 0; /* clear done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
@@ -257,18 +270,18 @@ case 7: /* LDBR */
|
||||
mt_db = AC; /* load buffer */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return 0; } /* end switch */
|
||||
return 0; } /* end switch */
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
}
|
||||
|
||||
/* IOTs, continued */
|
||||
|
||||
int32 mt71 (int32 pulse, int32 AC)
|
||||
int32 mt71 (int32 IR, int32 AC)
|
||||
{
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = mt_dev.units + GET_UNIT (mt_cu);
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 1: /* RWCR */
|
||||
return mt_wc; /* read word count */
|
||||
case 2: /* CLT */
|
||||
@@ -284,16 +297,16 @@ case 6: /* RFSR */
|
||||
return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK))
|
||||
& 07777); /* read function */
|
||||
case 7: /* RDBR */
|
||||
return mt_db; } /* read data buffer */
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
return mt_db; } /* read data buffer */
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
}
|
||||
|
||||
int32 mt72 (int32 pulse, int32 AC)
|
||||
int32 mt72 (int32 IR, int32 AC)
|
||||
{
|
||||
UNIT *uptr;
|
||||
|
||||
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 1: /* SKEF */
|
||||
return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;
|
||||
case 2: /* SKCB */
|
||||
@@ -308,7 +321,7 @@ case 5: /* CLF */
|
||||
mt_done = 0; /* clear done */
|
||||
mt_updcsta (uptr); } /* update status */
|
||||
return AC; } /* end switch */
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
}
|
||||
|
||||
/* Unit service
|
||||
@@ -319,40 +332,41 @@ return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
|
||||
|
||||
t_stat mt_svc (UNIT *uptr)
|
||||
{
|
||||
int32 f, i, p, u, err, wc, xma;
|
||||
t_stat rval;
|
||||
t_mtrlnt tbc, cbc;
|
||||
int32 f, i, p, u, err, wc, xma, pnu;
|
||||
t_mtrlnt abc, tbc, cbc;
|
||||
uint16 c, c1, c2;
|
||||
uint8 dbuf[(2 * 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) /* still on line? */
|
||||
uptr -> USTAT = (uptr -> USTAT & STA_WLK) | STA_BOT;
|
||||
else uptr -> USTAT = STA_REM;
|
||||
err = 0;
|
||||
u = uptr - mt_dev.units; /* get unit number */
|
||||
f = GET_FNC (mt_fn); /* 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) /* still on line? */
|
||||
uptr->USTAT = (uptr->USTAT & STA_WLK) | STA_BOT;
|
||||
else uptr->USTAT = STA_REM;
|
||||
if (u == GET_UNIT (mt_cu)) { /* selected? */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); } /* update status */
|
||||
return SCPE_OK; }
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
|
||||
uptr -> USTAT = STA_REM; /* unit off line */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */
|
||||
uptr->USTAT = STA_REM; /* unit off line */
|
||||
mt_sta = mt_sta | STA_ILL; /* illegal operation */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return IORETURN (mt_stopioe, SCPE_UNATT); }
|
||||
|
||||
f = GET_FNC (mt_fn); /* get command */
|
||||
if (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT)) {
|
||||
if (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr->flags & UNIT_WPRT)) {
|
||||
mt_sta = mt_sta | STA_ILL; /* illegal operation */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return SCPE_OK; }
|
||||
|
||||
err = 0;
|
||||
rval = SCPE_OK;
|
||||
xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */
|
||||
wc = 010000 - mt_wc; /* get wc */
|
||||
switch (f) { /* case on function */
|
||||
@@ -361,26 +375,21 @@ switch (f) { /* case on function */
|
||||
|
||||
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 = uptr -> USTAT | STA_EOT | STA_RLE;
|
||||
if (mt_rdlntf (uptr, &tbc, &err)) { /* read rec lnt */
|
||||
mt_sta = mt_sta | STA_RLE; /* err, eof/eom, tmk */
|
||||
break; }
|
||||
if (tbc == 0) { /* tape mark? */
|
||||
uptr -> USTAT = uptr -> USTAT | STA_EOF | 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? */
|
||||
cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */
|
||||
if (tbc != cbc) mt_sta = mt_sta | STA_RLE; /* wrong size? */
|
||||
if (tbc < cbc) { /* record small? */
|
||||
cbc = tbc; /* use smaller */
|
||||
wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 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 (uint8), cbc, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) { /* error? */
|
||||
mt_sta = mt_sta | STA_RLE; /* set flag */
|
||||
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 */
|
||||
xma = mt_ixma (xma); /* increment xma */
|
||||
if (mt_cu & CU_UNPAK) c = dbuf[p++];
|
||||
@@ -392,94 +401,70 @@ case FN_CMPARE: /* read/compare */
|
||||
mt_sta = mt_sta | STA_CPE;
|
||||
break; } }
|
||||
mt_wc = (mt_wc + wc) & 07777; /* update wc */
|
||||
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + /* update tape pos */
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* update tape pos */
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
break;
|
||||
|
||||
case FN_WRITE: /* write */
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
|
||||
fseek (uptr->fileref, uptr->pos, SEEK_SET);
|
||||
tbc = (mt_cu & CU_UNPAK)? wc: 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 */
|
||||
xma = mt_ixma (xma); /* incr mem addr */
|
||||
if (mt_cu & CU_UNPAK) dbuf[p++] = M[xma] & 0377;
|
||||
else { dbuf[p++] = (M[xma] >> 6) & 077;
|
||||
dbuf[p++] = M[xma] & 077; } }
|
||||
fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr -> fileref);
|
||||
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
mt_wc = 0;
|
||||
uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + /* update tape pos */
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
break;
|
||||
case FN_WREOF:
|
||||
fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
|
||||
fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); /* write eof */
|
||||
err = ferror (uptr -> fileref);
|
||||
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update tape pos */
|
||||
fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr->fileref);
|
||||
fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref);
|
||||
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */
|
||||
else { mt_wc = 0;
|
||||
uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* upd tape 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); /* write eof */
|
||||
if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */
|
||||
else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update tape pos */
|
||||
break;
|
||||
|
||||
case FN_SPACEF: /* space forward */
|
||||
do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */
|
||||
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 = uptr -> USTAT | STA_EOT;
|
||||
break; }
|
||||
if (tbc == 0) { /* zero bc? */
|
||||
uptr -> USTAT = uptr -> USTAT | STA_EOF;
|
||||
uptr -> pos = uptr -> pos + sizeof (t_mtrlnt);
|
||||
break; }
|
||||
uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) +
|
||||
if (mt_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */
|
||||
uptr->pos = uptr->pos + ((tbc + 1) & ~1) +
|
||||
(2 * sizeof (t_mtrlnt)); }
|
||||
while (mt_wc != 0);
|
||||
break;
|
||||
|
||||
case FN_SPACER: /* space reverse */
|
||||
if (uptr -> pos == 0) { /* at BOT? */
|
||||
uptr -> USTAT = uptr -> USTAT | STA_BOT;
|
||||
break; }
|
||||
do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */
|
||||
fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt),
|
||||
SEEK_SET);
|
||||
fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref);
|
||||
if ((err = ferror (uptr -> fileref)) || /* error or eof? */
|
||||
feof (uptr -> fileref)) {
|
||||
uptr -> USTAT = uptr -> USTAT | STA_BOT;
|
||||
uptr -> pos = 0;
|
||||
break; }
|
||||
if (tbc == 0) { /* start of prv file? */
|
||||
uptr -> USTAT = uptr -> USTAT | STA_EOF;
|
||||
uptr -> pos = uptr -> pos - sizeof (t_mtrlnt);
|
||||
break; }
|
||||
uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) -
|
||||
(2 * sizeof (t_mtrlnt));
|
||||
if (uptr -> pos == 0) { /* at BOT? */
|
||||
uptr -> USTAT = uptr -> USTAT | STA_BOT;
|
||||
break; } }
|
||||
if (pnu) pnu = 0; /* pos not upd? */
|
||||
else { if (mt_rdlntr (uptr, &tbc, &err)) break;
|
||||
uptr->pos = uptr->pos - ((tbc + 1) & ~1) -
|
||||
(2 * sizeof (t_mtrlnt)); } }
|
||||
while (mt_wc != 0);
|
||||
break; } /* end case */
|
||||
|
||||
/* Unit service, continued */
|
||||
|
||||
if (err != 0) { /* I/O error */
|
||||
mt_sta = mt_sta | STA_PAR | STA_CRC; /* flag error */
|
||||
perror ("MT I/O error");
|
||||
rval = SCPE_IOERR;
|
||||
clearerr (uptr -> fileref); }
|
||||
if (err != 0) mt_sta = mt_sta | STA_PAR; /* error? set flag */
|
||||
mt_cu = (mt_cu & ~CU_EMA) | ((xma >> (12 - CU_V_EMA)) & CU_EMA);
|
||||
mt_ca = xma & 07777; /* update mem addr */
|
||||
mt_set_done (); /* set done */
|
||||
mt_updcsta (uptr); /* update status */
|
||||
return IORETURN (mt_stopioe, rval);
|
||||
if (err != 0) { /* error? */
|
||||
perror ("MT I/O error");
|
||||
clearerr (uptr->fileref);
|
||||
if (mt_stopioe) return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Update controller status */
|
||||
|
||||
int32 mt_updcsta (UNIT *uptr)
|
||||
{
|
||||
mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | (uptr -> USTAT & STA_DYN);
|
||||
mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | (uptr->USTAT & STA_DYN);
|
||||
if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR;
|
||||
if (((mt_sta & STA_ERR) && (mt_cu & CU_IEE)) ||
|
||||
(mt_done && (mt_cu & CU_IED))) int_req = int_req | INT_MT;
|
||||
@@ -496,7 +481,7 @@ 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;
|
||||
}
|
||||
@@ -522,6 +507,52 @@ mt_done = 1; /* set done */
|
||||
mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read record length forward - return T if error, 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, */
|
||||
feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */
|
||||
mt_sta = mt_sta | STA_PAR; /* parity error */
|
||||
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 T if error, EOM, or EOF */
|
||||
|
||||
t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err)
|
||||
{
|
||||
if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */
|
||||
uptr->USTAT = 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? */
|
||||
feof (uptr->fileref)) { /* end of file? */
|
||||
mt_sta = mt_sta | STA_PAR; /* parity error */
|
||||
return TRUE; }
|
||||
if (*tbc == MTR_EOM) { /* eom? */
|
||||
mt_sta = mt_sta | STA_PAR; /* 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 */
|
||||
|
||||
@@ -534,12 +565,12 @@ mt_cu = mt_fn = mt_wc = mt_ca = mt_db = mt_sta = mt_done = 0;
|
||||
int_req = int_req & ~INT_MT; /* clear interrupt */
|
||||
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
|
||||
uptr = mt_dev.units + u;
|
||||
uptr -> UNUM = u; /* init drive number */
|
||||
sim_cancel (uptr); /* cancel activity */
|
||||
if (uptr -> flags & UNIT_ATT) uptr -> USTAT =
|
||||
((uptr -> pos)? 0: STA_BOT) |
|
||||
((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
|
||||
else uptr -> USTAT = STA_REM; }
|
||||
MT_CLR_PNU (uptr); /* clear pos flag */
|
||||
if (uptr->flags & UNIT_ATT) uptr->USTAT =
|
||||
((uptr->pos)? 0: STA_BOT) |
|
||||
((uptr->flags & UNIT_WPRT)? STA_WLK: 0);
|
||||
else uptr->USTAT = STA_REM; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -548,11 +579,13 @@ return SCPE_OK;
|
||||
t_stat mt_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
int32 u = uptr - mt_dev.units; /* get unit number */
|
||||
|
||||
r = attach_unit (uptr, cptr);
|
||||
if (r != SCPE_OK) return r;
|
||||
uptr -> USTAT = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0);
|
||||
if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
MT_CLR_PNU (uptr);
|
||||
uptr->USTAT = STA_BOT | ((uptr->flags & UNIT_WPRT)? STA_WLK: 0);
|
||||
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -560,8 +593,11 @@ return r;
|
||||
|
||||
t_stat mt_detach (UNIT* uptr)
|
||||
{
|
||||
if (!sim_is_active (uptr)) uptr -> USTAT = STA_REM;
|
||||
if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
int32 u = uptr - mt_dev.units; /* get unit number */
|
||||
|
||||
MT_CLR_PNU (uptr);
|
||||
if (!sim_is_active (uptr)) uptr->USTAT = STA_REM;
|
||||
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
return detach_unit (uptr);
|
||||
}
|
||||
|
||||
@@ -569,8 +605,10 @@ return detach_unit (uptr);
|
||||
|
||||
t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if ((uptr -> flags & UNIT_ATT) && val) uptr -> USTAT = uptr -> USTAT | STA_WLK;
|
||||
else uptr -> USTAT = uptr -> USTAT & ~STA_WLK;
|
||||
if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
int32 u = uptr - mt_dev.units; /* get unit number */
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) && val) uptr->USTAT = uptr->USTAT | STA_WLK;
|
||||
else uptr->USTAT = uptr->USTAT & ~STA_WLK;
|
||||
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
ptr,ptp PC8E paper tape reader/punch
|
||||
|
||||
04-Oct-02 RMS Added DIBs
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
30-Nov-01 RMS Added read only unit support
|
||||
30-Mar-98 RMS Added RIM loader as PTR bootstrap
|
||||
@@ -33,12 +34,16 @@
|
||||
#include "pdp8_defs.h"
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */
|
||||
|
||||
int32 ptr (int32 IR, int32 AC);
|
||||
int32 ptp (int32 IR, int32 AC);
|
||||
t_stat ptr_svc (UNIT *uptr);
|
||||
t_stat ptp_svc (UNIT *uptr);
|
||||
t_stat ptr_reset (DEVICE *dptr);
|
||||
t_stat ptp_reset (DEVICE *dptr);
|
||||
t_stat ptr_boot (int32 unitno);
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
|
||||
|
||||
/* PTR data structures
|
||||
|
||||
@@ -47,6 +52,8 @@ t_stat ptr_boot (int32 unitno);
|
||||
ptr_reg PTR register list
|
||||
*/
|
||||
|
||||
DIB ptr_dib = { DEV_PTR, 1, { &ptr } };
|
||||
|
||||
UNIT ptr_unit = {
|
||||
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
|
||||
SERIAL_IN_WAIT };
|
||||
@@ -61,11 +68,16 @@ REG ptr_reg[] = {
|
||||
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ptr_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 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, NULL, NULL };
|
||||
&ptr_boot, NULL, NULL,
|
||||
&ptr_dib, 0 };
|
||||
|
||||
/* PTP data structures
|
||||
|
||||
@@ -74,6 +86,8 @@ DEVICE ptr_dev = {
|
||||
ptp_reg PTP register list
|
||||
*/
|
||||
|
||||
DIB ptp_dib = { DEV_PTP, 1, { &ptp } };
|
||||
|
||||
UNIT ptp_unit = {
|
||||
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
@@ -87,17 +101,22 @@ REG ptp_reg[] = {
|
||||
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ptp_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 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, NULL, NULL };
|
||||
NULL, NULL, NULL,
|
||||
&ptp_dib, 0 };
|
||||
|
||||
/* Paper tape reader: IOT routine */
|
||||
|
||||
int32 ptr (int32 pulse, int32 AC)
|
||||
int32 ptr (int32 IR, int32 AC)
|
||||
{
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* RPE */
|
||||
int_enable = int_enable | (INT_PTR+INT_PTP); /* set enable */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
@@ -155,9 +174,9 @@ return SCPE_OK;
|
||||
|
||||
/* Paper tape punch: IOT routine */
|
||||
|
||||
int32 ptp (int32 pulse, int32 AC)
|
||||
int32 ptp (int32 IR, int32 AC)
|
||||
{
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* PCE */
|
||||
int_enable = int_enable & ~(INT_PTR+INT_PTP); /* clear enables */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
@@ -210,9 +229,9 @@ return SCPE_OK;
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 07756
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32))
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const int32 boot_rom[] = {
|
||||
static const uint16 boot_rom[] = {
|
||||
06014, /* 7756, RFC */
|
||||
06011, /* 7757, LOOP, RSF */
|
||||
05357, /* JMP .-1 */
|
||||
@@ -230,15 +249,16 @@ static const int32 boot_rom[] = {
|
||||
03376, /* 7774, DCA 7776 */
|
||||
05357, /* JMP 7757 */
|
||||
00000, /* 7776, 0 */
|
||||
05301 /* 7777, JMP 7701 */
|
||||
05301 /* 7777, JMP 7701 */
|
||||
};
|
||||
|
||||
t_stat ptr_boot (int32 unitno)
|
||||
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
extern uint16 M[];
|
||||
|
||||
if (ptr_dib.dev != DEV_PTR) return STOP_NOTSTD; /* only std devno */
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
return SCPE_OK;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
rf RF08 fixed head disk
|
||||
|
||||
06-Nov-02 RMS Changed enable/disable support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
28-Nov-01 RMS Added RL8A support
|
||||
25-Apr-01 RMS Added device enable/disable support
|
||||
19-Mar-01 RMS Added disk monitor bootstrap, fixed IOT decoding
|
||||
@@ -89,9 +89,9 @@
|
||||
else int_req = int_req & ~INT_RF
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, dev_enb, stop_inst;
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
extern int32 df_devenb;
|
||||
|
||||
int32 rf_sta = 0; /* status register */
|
||||
int32 rf_da = 0; /* disk address */
|
||||
int32 rf_done = 0; /* done flag */
|
||||
@@ -99,10 +99,16 @@ int32 rf_wlk = 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 rf60 (int32 IR, int32 AC);
|
||||
int32 rf61 (int32 IR, int32 AC);
|
||||
int32 rf62 (int32 IR, int32 AC);
|
||||
int32 rf64 (int32 IR, int32 AC);
|
||||
t_stat rf_svc (UNIT *uptr);
|
||||
t_stat pcell_svc (UNIT *uptr);
|
||||
t_stat rf_reset (DEVICE *dptr);
|
||||
t_stat rf_boot (int32 unitno);
|
||||
t_stat rf_boot (int32 unitno, DEVICE *dptr);
|
||||
|
||||
/* RF08 data structures
|
||||
|
||||
@@ -112,6 +118,8 @@ t_stat rf_boot (int32 unitno);
|
||||
rf_reg RF register list
|
||||
*/
|
||||
|
||||
DIB rf_dib = { DEV_RF, 5, { &rf60, &rf61, &rf62, NULL, &rf64 } };
|
||||
|
||||
UNIT rf_unit =
|
||||
{ UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
|
||||
RF_SIZE) };
|
||||
@@ -129,25 +137,27 @@ REG rf_reg[] = {
|
||||
{ DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (BURST, rf_burst, 0) },
|
||||
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO },
|
||||
{ ORDATA (DEVNUM, rf_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB rf_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RF, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RF, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE rf_dev = {
|
||||
"RF", &rf_unit, rf_reg, rf_mod,
|
||||
1, 8, 20, 1, 8, 12,
|
||||
NULL, NULL, &rf_reset,
|
||||
&rf_boot, NULL, NULL };
|
||||
&rf_boot, NULL, NULL,
|
||||
&rf_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 rf60 (int32 pulse, int32 AC)
|
||||
int32 rf60 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 t;
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DCMA */
|
||||
@@ -165,8 +175,10 @@ if (pulse & 6) { /* DMAR, DMAW */
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 rf61 (int32 pulse, int32 AC)
|
||||
int32 rf61 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
case 1: /* DCIM */
|
||||
@@ -191,8 +203,10 @@ return AC;
|
||||
|
||||
/* IOT's, continued */
|
||||
|
||||
int32 rf62 (int32 pulse, int32 AC)
|
||||
int32 rf62 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if (pulse & 1) { /* DFSE */
|
||||
if (rf_sta & RFS_ERR) AC = AC | IOT_SKP; }
|
||||
@@ -203,8 +217,10 @@ if (pulse & 4) AC = AC | (rf_da & 07777); /* DMAC */
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 rf64 (int32 pulse, int32 AC)
|
||||
int32 rf64 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 pulse = IR & 07;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
case 1: /* DCXA */
|
||||
@@ -230,7 +246,7 @@ t_stat rf_svc (UNIT *uptr)
|
||||
int32 pa, t, mex;
|
||||
|
||||
UPDATE_PCELL; /* update photocell */
|
||||
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
|
||||
rf_sta = rf_sta | RFS_NXD;
|
||||
rf_done = 1;
|
||||
RF_INT_UPDATE; /* update int req */
|
||||
@@ -240,14 +256,14 @@ mex = GET_MEX (rf_sta);
|
||||
do { M[RF_WC] = (M[RF_WC] + 1) & 07777; /* incr word count */
|
||||
M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */
|
||||
pa = mex | M[RF_MA]; /* add extension */
|
||||
if (uptr -> FUNC == RF_READ) {
|
||||
if (uptr->FUNC == RF_READ) {
|
||||
if (MEM_ADDR_OK (pa)) /* read, check nxm */
|
||||
M[pa] = *(((int16 *) uptr -> filebuf) + rf_da); }
|
||||
M[pa] = *(((int16 *) uptr->filebuf) + rf_da); }
|
||||
else { t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
|
||||
if ((rf_wlk >> t) & 1) rf_sta = rf_sta | RFS_WLS;
|
||||
else { *(((int16 *) uptr -> filebuf) + rf_da) = M[pa];
|
||||
if (((t_addr) rf_da) >= uptr -> hwmark)
|
||||
uptr -> hwmark = rf_da + 1; } }
|
||||
else { *(((int16 *) uptr->filebuf) + rf_da) = M[pa];
|
||||
if (((t_addr) rf_da) >= uptr->hwmark)
|
||||
uptr->hwmark = rf_da + 1; } }
|
||||
rf_da = (rf_da + 1) & 03777777; } /* incr disk addr */
|
||||
while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
|
||||
|
||||
@@ -273,8 +289,6 @@ return SCPE_OK;
|
||||
|
||||
t_stat rf_reset (DEVICE *dptr)
|
||||
{
|
||||
if (dev_enb & INT_RF) /* RF? no DF or RL */
|
||||
dev_enb = dev_enb & ~(INT_DF | INT_RL);
|
||||
rf_sta = rf_da = 0;
|
||||
rf_done = 1;
|
||||
int_req = int_req & ~INT_RF; /* clear interrupt */
|
||||
@@ -286,11 +300,11 @@ return SCPE_OK;
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define OS8_START 07750
|
||||
#define OS8_LEN (sizeof (os8_rom) / sizeof (int32))
|
||||
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
|
||||
#define DM4_START 00200
|
||||
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int32))
|
||||
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
|
||||
|
||||
static const int32 os8_rom[] = {
|
||||
static const uint16 os8_rom[] = {
|
||||
07600, /* 7750, CLA CLL ; also word count */
|
||||
06603, /* 7751, DMAR ; also address */
|
||||
06622, /* 7752, DFSC ; done? */
|
||||
@@ -298,7 +312,7 @@ static const int32 os8_rom[] = {
|
||||
05752 /* 7754, JMP @.-2 ; enter boot */
|
||||
};
|
||||
|
||||
static const int32 dm4_rom[] = {
|
||||
static const uint16 dm4_rom[] = {
|
||||
00200, 07600, /* 0200, CLA CLL */
|
||||
00201, 06603, /* 0201, DMAR ; read */
|
||||
00202, 06622, /* 0202, DFSC ; done? */
|
||||
@@ -308,11 +322,12 @@ static const int32 dm4_rom[] = {
|
||||
07751, 07576 /* 7751, 7576 ; address */
|
||||
};
|
||||
|
||||
t_stat rf_boot (int32 unitno)
|
||||
t_stat rf_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 sim_switches, saved_PC;
|
||||
|
||||
if (rf_dib.dev != DEV_RF) return STOP_NOTSTD; /* only std devno */
|
||||
if (sim_switches & SWMASK ('D')) {
|
||||
for (i = 0; i < DM4_LEN; i = i + 2)
|
||||
M[dm4_rom[i]] = dm4_rom[i + 1];
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
rk RK8E/RK05 cartridge disk
|
||||
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
|
||||
24-Nov-01 RMS Converted FLG to array, made register names consistent
|
||||
@@ -48,7 +49,6 @@
|
||||
|
||||
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
|
||||
#define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */
|
||||
#define UNIT_W_UF 3 /* user flags width */
|
||||
#define UNIT_HWLK (1 << UNIT_V_HWLK)
|
||||
#define UNIT_SWLK (1 << UNIT_V_SWLK)
|
||||
#define UNIT_WPRT (UNIT_HWLK|UNIT_SWLK|UNIT_RO) /* write protect */
|
||||
@@ -123,8 +123,9 @@
|
||||
#define MAX(x,y) (((x) > (y))? (x): (y))
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, dev_enb, stop_inst;
|
||||
extern int32 int_req, stop_inst;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
int32 rk_busy = 0; /* controller busy */
|
||||
int32 rk_sta = 0; /* status register */
|
||||
int32 rk_cmd = 0; /* command register */
|
||||
@@ -132,9 +133,12 @@ int32 rk_da = 0; /* disk address */
|
||||
int32 rk_ma = 0; /* memory address */
|
||||
int32 rk_swait = 10, rk_rwait = 10; /* seek, rotate wait */
|
||||
int32 rk_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE rk_dev;
|
||||
int32 rk (int32 IR, int32 AC);
|
||||
t_stat rk_svc (UNIT *uptr);
|
||||
t_stat rk_reset (DEVICE *dptr);
|
||||
t_stat rk_boot (int32 unitno);
|
||||
t_stat rk_boot (int32 unitno, DEVICE *dptr);
|
||||
void rk_go (int32 function, int32 cylinder);
|
||||
|
||||
/* RK-8E data structures
|
||||
@@ -145,6 +149,8 @@ void rk_go (int32 function, int32 cylinder);
|
||||
rk_mod RK modifiers list
|
||||
*/
|
||||
|
||||
DIB rk_dib = { DEV_RK, 1, { &rk } };
|
||||
|
||||
UNIT rk_unit[] = {
|
||||
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
|
||||
UNIT_ROABLE, RK_SIZE) },
|
||||
@@ -164,33 +170,32 @@ REG rk_reg[] = {
|
||||
{ FLDATA (INT, int_req, INT_V_RK) },
|
||||
{ DRDATA (STIME, rk_swait, 24), PV_LEFT },
|
||||
{ DRDATA (RTIME, rk_rwait, 24), PV_LEFT },
|
||||
{ URDATA (FLG, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
|
||||
RK_NUMDR, REG_HRO) },
|
||||
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_RK), REG_HRO },
|
||||
{ ORDATA (DEVNUM, rk_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB rk_mod[] = {
|
||||
{ UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RK, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RK, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE rk_dev = {
|
||||
"RK", rk_unit, rk_reg, rk_mod,
|
||||
RK_NUMDR, 8, 24, 1, 8, 12,
|
||||
NULL, NULL, &rk_reset,
|
||||
&rk_boot, NULL, NULL };
|
||||
&rk_boot, NULL, NULL,
|
||||
&rk_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 rk (int32 pulse, int32 AC)
|
||||
int32 rk (int32 IR, int32 AC)
|
||||
{
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* unused */
|
||||
return (stop_inst << IOT_V_REASON) + AC;
|
||||
case 1: /* DSKP */
|
||||
@@ -225,7 +230,7 @@ case 4: /* DLCA */
|
||||
case 5: /* DRST */
|
||||
uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */
|
||||
rk_sta = rk_sta & ~(RKS_HMOV + RKS_NRDY); /* clear dynamic */
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) rk_sta = rk_sta | RKS_NRDY;
|
||||
if ((uptr->flags & UNIT_ATT) == 0) rk_sta = rk_sta | RKS_NRDY;
|
||||
if (sim_is_active (uptr)) rk_sta = rk_sta | RKS_HMOV;
|
||||
return rk_sta;
|
||||
case 6: /* DLDC */
|
||||
@@ -256,27 +261,27 @@ UNIT *uptr;
|
||||
if (func == RKC_RALL) func = RKC_READ; /* all? use standard */
|
||||
if (func == RKC_WALL) func = RKC_WRITE;
|
||||
uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
|
||||
return; }
|
||||
if (sim_is_active (uptr) || (cyl >= RK_NUMCY)) { /* busy or bad cyl? */
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_STAT;
|
||||
return; }
|
||||
if ((func == RKC_WRITE) && (uptr -> flags & UNIT_WPRT)) {
|
||||
if ((func == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) {
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
|
||||
return; }
|
||||
if (func == RKC_WLK) { /* write lock? */
|
||||
uptr -> flags = uptr -> flags | UNIT_SWLK;
|
||||
uptr->flags = uptr->flags | UNIT_SWLK;
|
||||
rk_sta = rk_sta | RKS_DONE;
|
||||
return; }
|
||||
t = abs (cyl - uptr -> CYL) * rk_swait; /* seek time */
|
||||
t = abs (cyl - uptr->CYL) * rk_swait; /* seek time */
|
||||
if (func == RKC_SEEK) { /* seek? */
|
||||
sim_activate (uptr, MAX (RK_MIN, t)); /* schedule */
|
||||
rk_sta = rk_sta | RKS_DONE; } /* set done */
|
||||
else { sim_activate (uptr, t + rk_rwait); /* schedule */
|
||||
rk_busy = 1; } /* set busy */
|
||||
uptr -> FUNC = func; /* save func */
|
||||
uptr -> CYL = cyl; /* put on cylinder */
|
||||
uptr->FUNC = func; /* save func */
|
||||
uptr->CYL = cyl; /* put on cylinder */
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -297,20 +302,20 @@ t_stat rk_svc (UNIT *uptr)
|
||||
int32 err, wc, wc1, awc, swc, pa, da;
|
||||
UNIT *seluptr;
|
||||
|
||||
if (uptr -> FUNC == RKC_SEEK) { /* seek? */
|
||||
if (uptr->FUNC == RKC_SEEK) { /* seek? */
|
||||
seluptr = rk_dev.units + GET_DRIVE (rk_cmd); /* see if selected */
|
||||
if ((uptr == seluptr) && ((rk_cmd & RKC_SKDN) != 0)) {
|
||||
rk_sta = rk_sta | RKS_DONE;
|
||||
RK_INT_UPDATE; }
|
||||
return SCPE_OK; }
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) { /* not att? abort */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* not att? abort */
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
|
||||
rk_busy = 0;
|
||||
RK_INT_UPDATE;
|
||||
return IORETURN (rk_stopioe, SCPE_UNATT); }
|
||||
|
||||
if ((uptr -> FUNC == RKC_WRITE) && (uptr -> flags & UNIT_WPRT)) {
|
||||
if ((uptr->FUNC == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) {
|
||||
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
|
||||
rk_busy = 0;
|
||||
RK_INT_UPDATE;
|
||||
@@ -320,28 +325,28 @@ pa = GET_MEX (rk_cmd) | rk_ma; /* phys address */
|
||||
da = GET_DA (rk_cmd, rk_da) * RK_NUMWD * sizeof (int16);/* disk address */
|
||||
swc = wc = (rk_cmd & RKC_HALF)? RK_NUMWD / 2: RK_NUMWD; /* get transfer size */
|
||||
if ((wc1 = ((rk_ma + wc) - 010000)) > 0) wc = wc - wc1; /* if wrap, limit */
|
||||
err = fseek (uptr -> fileref, da, SEEK_SET); /* locate sector */
|
||||
err = fseek (uptr->fileref, da, SEEK_SET); /* locate sector */
|
||||
|
||||
if ((uptr -> FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */
|
||||
awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref);
|
||||
if ((uptr->FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */
|
||||
awc = fxread (&M[pa], sizeof (int16), wc, uptr->fileref);
|
||||
for ( ; awc < wc; awc++) M[pa + awc] = 0; /* fill if eof */
|
||||
err = ferror (uptr -> fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
if ((wc1 > 0) && (err == 0)) { /* field wraparound? */
|
||||
pa = pa & 070000; /* wrap phys addr */
|
||||
awc = fxread (&M[pa], sizeof (int16), wc1, uptr -> fileref);
|
||||
awc = fxread (&M[pa], sizeof (int16), wc1, uptr->fileref);
|
||||
for ( ; awc < wc1; awc++) M[pa + awc] = 0; /* fill if eof */
|
||||
err = ferror (uptr -> fileref); } }
|
||||
err = ferror (uptr->fileref); } }
|
||||
|
||||
if ((uptr -> FUNC == RKC_WRITE) && (err == 0)) { /* write? */
|
||||
fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
if ((uptr->FUNC == RKC_WRITE) && (err == 0)) { /* write? */
|
||||
fxwrite (&M[pa], sizeof (int16), wc, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
if ((wc1 > 0) && (err == 0)) { /* field wraparound? */
|
||||
pa = pa & 070000; /* wrap phys addr */
|
||||
fxwrite (&M[pa], sizeof (int16), wc1, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref); }
|
||||
fxwrite (&M[pa], sizeof (int16), wc1, uptr->fileref);
|
||||
err = ferror (uptr->fileref); }
|
||||
if ((rk_cmd & RKC_HALF) && (err == 0)) { /* fill half sector */
|
||||
fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref); } }
|
||||
fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr->fileref);
|
||||
err = ferror (uptr->fileref); } }
|
||||
|
||||
rk_ma = (rk_ma + swc) & 07777; /* incr mem addr reg */
|
||||
rk_sta = rk_sta | RKS_DONE; /* set done */
|
||||
@@ -350,7 +355,7 @@ RK_INT_UPDATE;
|
||||
|
||||
if (err != 0) {
|
||||
perror ("RK I/O error");
|
||||
clearerr (uptr -> fileref);
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -367,8 +372,8 @@ int_req = int_req & ~INT_RK; /* clear interrupt */
|
||||
for (i = 0; i < RK_NUMDR; i++) { /* stop all units */
|
||||
uptr = rk_dev.units + i;
|
||||
sim_cancel (uptr);
|
||||
uptr -> flags = uptr -> flags & ~UNIT_SWLK;
|
||||
uptr -> CYL = uptr -> FUNC = 0; }
|
||||
uptr->flags = uptr->flags & ~UNIT_SWLK;
|
||||
uptr->CYL = uptr->FUNC = 0; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -376,9 +381,9 @@ return SCPE_OK;
|
||||
|
||||
#define BOOT_START 023
|
||||
#define BOOT_UNIT 032
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const int32 boot_rom[] = {
|
||||
static const uint16 boot_rom[] = {
|
||||
06007, /* 23, CAF */
|
||||
06744, /* 24, DLCA ; addr = 0 */
|
||||
01032, /* 25, TAD UNIT ; unit no */
|
||||
@@ -389,11 +394,12 @@ static const int32 boot_rom[] = {
|
||||
00000 /* UNIT, 0 ; in bits <9:10> */
|
||||
};
|
||||
|
||||
t_stat rk_boot (int32 unitno)
|
||||
t_stat rk_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (rk_dib.dev != DEV_RK) return STOP_NOTSTD; /* only std devno */
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
M[BOOT_UNIT] = (unitno & RK_M_NUMDR) << 1;
|
||||
saved_PC = BOOT_START;
|
||||
|
||||
127
PDP8/pdp8_rl.c
127
PDP8/pdp8_rl.c
@@ -25,6 +25,7 @@
|
||||
|
||||
rl RL8A cartridge disk
|
||||
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Cloned from RL11
|
||||
|
||||
@@ -58,11 +59,10 @@
|
||||
|
||||
/* Flags in the unit flags word */
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF) /* write lock */
|
||||
#define UNIT_V_RL02 (UNIT_V_UF+1) /* RL01 vs RL02 */
|
||||
#define UNIT_V_AUTO (UNIT_V_UF+2) /* autosize enable */
|
||||
#define UNIT_W_UF 4 /* saved flags width */
|
||||
#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write lock */
|
||||
#define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */
|
||||
#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */
|
||||
#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */
|
||||
#define UNIT_DUMMY (1u << UNIT_V_DUMMY)
|
||||
#define UNIT_WLK (1u << UNIT_V_WLK)
|
||||
#define UNIT_RL02 (1u << UNIT_V_RL02)
|
||||
@@ -96,7 +96,7 @@
|
||||
#define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
|
||||
RLDS_VCK+RLDS_DSE) /* errors bits */
|
||||
|
||||
/* RLCSA, seek = offset/rw = address (also uptr -> TRK) */
|
||||
/* RLCSA, seek = offset/rw = address (also uptr->TRK) */
|
||||
|
||||
#define RLCSA_DIR 04000 /* direction */
|
||||
#define RLCSA_HD 02000 /* head select */
|
||||
@@ -151,8 +151,9 @@
|
||||
#define RLSI_V_TRK 6 /* track */
|
||||
|
||||
extern uint16 M[];
|
||||
extern int32 int_req, dev_enb;
|
||||
extern int32 int_req;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
uint8 *rlxb = NULL; /* xfer buffer */
|
||||
int32 rlcsa = 0; /* control/status A */
|
||||
int32 rlcsb = 0; /* control/status B */
|
||||
@@ -167,10 +168,14 @@ int32 rl_erf = 0; /* error flag */
|
||||
int32 rl_swait = 10; /* seek wait */
|
||||
int32 rl_rwait = 10; /* rotate wait */
|
||||
int32 rl_stopioe = 1; /* stop on error */
|
||||
|
||||
DEVICE rl_dev;
|
||||
int32 rl60 (int32 IR, int32 AC);
|
||||
int32 rl61 (int32 IR, int32 AC);
|
||||
t_stat rl_svc (UNIT *uptr);
|
||||
t_stat rl_reset (DEVICE *dptr);
|
||||
void rl_set_done (int32 error);
|
||||
t_stat rl_boot (int32 unitno);
|
||||
t_stat rl_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat rl_attach (UNIT *uptr, char *cptr);
|
||||
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
@@ -183,6 +188,8 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
rl_mod RL modifier list
|
||||
*/
|
||||
|
||||
DIB rl_dib = { DEV_RL, 2, { &rl60, &rl61 } };
|
||||
|
||||
UNIT rl_unit[] = {
|
||||
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
|
||||
UNIT_ROABLE, RL01_SIZE) },
|
||||
@@ -210,12 +217,10 @@ REG rl_reg[] = {
|
||||
{ FLDATA (ERR, rl_erf, 0) },
|
||||
{ DRDATA (STIME, rl_swait, 24), PV_LEFT },
|
||||
{ DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
|
||||
{ URDATA (FLG, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1,
|
||||
RL_NUMDR, REG_HRO) },
|
||||
{ URDATA (CAPAC, rl_unit[0].capac, 10, 31, 0,
|
||||
RL_NUMDR, PV_LEFT + REG_HRO) },
|
||||
{ FLDATA (STOP_IOE, rl_stopioe, 0) },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_RL), REG_HRO },
|
||||
{ ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB rl_mod[] = {
|
||||
@@ -230,24 +235,25 @@ MTAB rl_mod[] = {
|
||||
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
|
||||
{ (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size },
|
||||
{ (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RL, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RL, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE rl_dev = {
|
||||
"RL", rl_unit, rl_reg, rl_mod,
|
||||
RL_NUMDR, 8, 24, 1, 8, 8,
|
||||
NULL, NULL, &rl_reset,
|
||||
&rl_boot, &rl_attach, NULL };
|
||||
&rl_boot, &rl_attach, NULL,
|
||||
&rl_dib, DEV_DISABLE | DEV_DIS };
|
||||
|
||||
/* IOT 60 routine */
|
||||
|
||||
int32 rl60 (int32 pulse, int32 AC)
|
||||
int32 rl60 (int32 IR, int32 AC)
|
||||
{
|
||||
int32 curr, offs, newc, maxc;
|
||||
UNIT *uptr;
|
||||
|
||||
switch (pulse) { /* case IR<9:11> */
|
||||
switch (IR & 07) { /* case IR<9:11> */
|
||||
case 0: /* RLDC */
|
||||
rl_reset (&rl_dev); /* reset device */
|
||||
break;
|
||||
@@ -272,21 +278,21 @@ case 4: /* RLCB */
|
||||
uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
|
||||
switch (GET_FUNC (rlcsb)) { /* case on func */
|
||||
case RLCSB_CLRD: /* clear drive */
|
||||
uptr -> STAT = uptr -> STAT & ~RLDS_ERR; /* clear errors */
|
||||
uptr->STAT = uptr->STAT & ~RLDS_ERR; /* clear errors */
|
||||
case RLCSB_MNT: /* mnt */
|
||||
rl_set_done (0);
|
||||
break;
|
||||
case RLCSB_SEEK: /* seek */
|
||||
curr = GET_CYL (uptr -> TRK); /* current cylinder */
|
||||
curr = GET_CYL (uptr->TRK); /* current cylinder */
|
||||
offs = GET_CYL (rlcsa); /* offset */
|
||||
if (rlcsa & RLCSA_DIR) { /* in or out? */
|
||||
newc = curr + offs; /* out */
|
||||
maxc = (uptr -> flags & UNIT_RL02)?
|
||||
maxc = (uptr->flags & UNIT_RL02)?
|
||||
RL_NUMCY * 2: RL_NUMCY;
|
||||
if (newc >= maxc) newc = maxc - 1; }
|
||||
else { newc = curr - offs; /* in */
|
||||
if (newc < 0) newc = 0; }
|
||||
uptr -> TRK = newc | (rlcsa & RLCSA_HD);
|
||||
uptr->TRK = newc | (rlcsa & RLCSA_HD);
|
||||
sim_activate (uptr, rl_swait * abs (newc - curr));
|
||||
break;
|
||||
default: /* data transfer */
|
||||
@@ -315,7 +321,7 @@ switch (pulse) { /* case IR<9:11> */
|
||||
case 0: /* RRER */
|
||||
uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
|
||||
if (!sim_is_active (uptr) && /* update drdy */
|
||||
(uptr -> flags & UNIT_ATT))
|
||||
(uptr->flags & UNIT_ATT))
|
||||
rler = rler | RLER_DRDY;
|
||||
else rler = rler & ~RLER_DRDY;
|
||||
dat = rler & RLER_MASK;
|
||||
@@ -367,22 +373,22 @@ t_addr ma;
|
||||
|
||||
func = GET_FUNC (rlcsb); /* get function */
|
||||
if (func == RLCSB_GSTA) { /* get status? */
|
||||
rlsi = uptr -> STAT |
|
||||
((uptr -> TRK & RLCSA_HD)? RLDS_HD: 0) |
|
||||
((uptr -> flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
|
||||
if (uptr -> flags & UNIT_RL02) rlsi = rlsi | RLDS_RL02;
|
||||
if (uptr -> flags & UNIT_WPRT) rlsi = rlsi | RLDS_WLK;
|
||||
rlsi = uptr->STAT |
|
||||
((uptr->TRK & RLCSA_HD)? RLDS_HD: 0) |
|
||||
((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
|
||||
if (uptr->flags & UNIT_RL02) rlsi = rlsi | RLDS_RL02;
|
||||
if (uptr->flags & UNIT_WPRT) rlsi = rlsi | RLDS_WLK;
|
||||
rlsi2 = rlsi1 = rlsi;
|
||||
rl_set_done (0); /* done */
|
||||
return SCPE_OK; }
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */
|
||||
uptr -> STAT = uptr -> STAT | RLDS_SPE; /* spin error */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
|
||||
uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */
|
||||
rl_set_done (RLER_INCMP); /* flag error */
|
||||
return IORETURN (rl_stopioe, SCPE_UNATT); }
|
||||
|
||||
if ((func == RLCSB_WRITE) && (uptr -> flags & UNIT_WPRT)) {
|
||||
uptr -> STAT = uptr -> STAT | RLDS_WGE; /* write and locked */
|
||||
if ((func == RLCSB_WRITE) && (uptr->flags & UNIT_WPRT)) {
|
||||
uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */
|
||||
rl_set_done (RLER_DRE); /* flag error */
|
||||
return SCPE_OK; }
|
||||
|
||||
@@ -391,12 +397,12 @@ if (func == RLCSB_SEEK) { /* seek? */
|
||||
return SCPE_OK; }
|
||||
|
||||
if (func == RLCSB_RHDR) { /* read header? */
|
||||
rlsi = (GET_TRK (uptr -> TRK) << RLSI_V_TRK) | rlsa;
|
||||
rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa;
|
||||
rlsi1 = rlsi2 = 0;
|
||||
rl_set_done (0); /* done */
|
||||
return SCPE_OK; }
|
||||
|
||||
if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr -> TRK) != GET_CYL (rlcsa)))
|
||||
if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr->TRK) != GET_CYL (rlcsa)))
|
||||
|| (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */
|
||||
rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */
|
||||
return SCPE_OK; }
|
||||
@@ -413,12 +419,12 @@ else { bc = ((wc * 3) + 1) / 2; /* 12b mode */
|
||||
bc = RL_NUMBY; /* cap xfer */
|
||||
wc = (RL_NUMBY * 2) / 3; } }
|
||||
|
||||
err = fseek (uptr -> fileref, da, SEEK_SET);
|
||||
err = fseek (uptr->fileref, da, SEEK_SET);
|
||||
|
||||
if ((func >= RLCSB_READ) && (err == 0) && /* read (no hdr)? */
|
||||
MEM_ADDR_OK (ma)) { /* valid bank? */
|
||||
i = fxread (rlxb, sizeof (int8), bc, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
i = fxread (rlxb, sizeof (int8), bc, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */
|
||||
for (i = j = 0; i < wc; i++) { /* store buffer */
|
||||
if (rlcsb & RLCSB_8B) /* 8b mode? */
|
||||
@@ -448,8 +454,8 @@ if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */
|
||||
} /* end for */
|
||||
wbc = (bc + (RL_NUMBY - 1)) & ~(RL_NUMBY - 1); /* clr to */
|
||||
for (i = bc; i < wbc; i++) rlxb[i] = 0; /* end of blk */
|
||||
fxwrite (rlxb, sizeof (int8), wbc, uptr -> fileref);
|
||||
err = ferror (uptr -> fileref);
|
||||
fxwrite (rlxb, sizeof (int8), wbc, uptr->fileref);
|
||||
err = ferror (uptr->fileref);
|
||||
} /* end write */
|
||||
|
||||
rlwc = (rlwc + wc) & 07777; /* final word count */
|
||||
@@ -460,7 +466,7 @@ rl_set_done (0);
|
||||
|
||||
if (err != 0) { /* error? */
|
||||
perror ("RL I/O error");
|
||||
clearerr (uptr -> fileref);
|
||||
clearerr (uptr->fileref);
|
||||
return SCPE_IOERR; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -487,8 +493,6 @@ t_stat rl_reset (DEVICE *dptr)
|
||||
int32 i;
|
||||
UNIT *uptr;
|
||||
|
||||
if (dev_enb & INT_RL) /* RL? no DF or RF */
|
||||
dev_enb = dev_enb & ~(INT_DF | INT_RF);
|
||||
rlcsa = rlcsb = rlsa = rler = 0;
|
||||
rlma = rlwc = 0;
|
||||
rlsi = rlsi1 = rlsi2 = 0;
|
||||
@@ -499,7 +503,7 @@ int_req = int_req & ~INT_RL;
|
||||
for (i = 0; i < RL_NUMDR; i++) {
|
||||
uptr = rl_dev.units + i;
|
||||
sim_cancel (uptr);
|
||||
uptr -> STAT = 0; }
|
||||
uptr->STAT = 0; }
|
||||
if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int8));
|
||||
if (rlxb == NULL) return SCPE_MEM;
|
||||
return SCPE_OK;
|
||||
@@ -512,21 +516,21 @@ t_stat rl_attach (UNIT *uptr, char *cptr)
|
||||
int32 p;
|
||||
t_stat r;
|
||||
|
||||
uptr -> capac = (uptr -> flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
|
||||
uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
|
||||
|
||||
r = attach_unit (uptr, cptr);
|
||||
if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r;
|
||||
uptr -> TRK = 0; /* cyl 0 */
|
||||
uptr -> STAT = RLDS_VCK; /* new volume */
|
||||
if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK;
|
||||
if ((p = ftell (uptr -> fileref)) == 0) {
|
||||
if (uptr -> flags & UNIT_RO) return SCPE_OK;
|
||||
if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r;
|
||||
uptr->TRK = 0; /* cyl 0 */
|
||||
uptr->STAT = RLDS_VCK; /* new volume */
|
||||
if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK;
|
||||
if ((p = ftell (uptr->fileref)) == 0) {
|
||||
if (uptr->flags & UNIT_RO) return SCPE_OK;
|
||||
return rl_set_bad (uptr, 0, NULL, NULL); }
|
||||
if (p > (RL01_SIZE * sizeof (int16))) {
|
||||
uptr -> flags = uptr -> flags | UNIT_RL02;
|
||||
uptr -> capac = RL02_SIZE; }
|
||||
else { uptr -> flags = uptr -> flags & ~UNIT_RL02;
|
||||
uptr -> capac = RL01_SIZE; }
|
||||
uptr->flags = uptr->flags | UNIT_RL02;
|
||||
uptr->capac = RL02_SIZE; }
|
||||
else { uptr->flags = uptr->flags & ~UNIT_RL02;
|
||||
uptr->capac = RL01_SIZE; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -534,8 +538,8 @@ return SCPE_OK;
|
||||
|
||||
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
|
||||
uptr -> capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -559,14 +563,14 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i, da = RL_BBMAP * RL_NUMBY;
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
if (uptr -> flags & UNIT_RO) return SCPE_RO;
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
if (uptr->flags & UNIT_RO) return SCPE_RO;
|
||||
if (!get_yn ("Create bad block table? [N]", FALSE)) return SCPE_OK;
|
||||
if (fseek (uptr -> fileref, da, SEEK_SET)) return SCPE_IOERR;
|
||||
if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR;
|
||||
rlxb[0] = RL_BBID;
|
||||
for (i = 1; i < RL_NUMBY; i++) rlxb[i] = 0;
|
||||
fxwrite (rlxb, sizeof (int8), RL_NUMBY, uptr -> fileref);
|
||||
if (ferror (uptr -> fileref)) return SCPE_IOERR;
|
||||
fxwrite (rlxb, sizeof (int8), RL_NUMBY, uptr->fileref);
|
||||
if (ferror (uptr->fileref)) return SCPE_IOERR;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -576,7 +580,7 @@ return SCPE_OK;
|
||||
#define BOOT_UNIT 02006 /* unit number */
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
|
||||
static const int16 boot_rom[] = {
|
||||
static const uint16 boot_rom[] = {
|
||||
06600, /* BT, RLDC ; reset */
|
||||
07201, /* 02, CLA IAC ; clr drv = 1 */
|
||||
04027, /* 03, JMS GO ; do io */
|
||||
@@ -609,12 +613,13 @@ static const int16 boot_rom[] = {
|
||||
};
|
||||
|
||||
|
||||
t_stat rl_boot (int32 unitno)
|
||||
t_stat rl_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
|
||||
if (unitno) return SCPE_ARG;
|
||||
if (rl_dib.dev != DEV_RL) return STOP_NOTSTD; /* only std devno */
|
||||
rl_unit[unitno].TRK = 0;
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
saved_PC = BOOT_START;
|
||||
|
||||
554
PDP8/pdp8_rx.c
554
PDP8/pdp8_rx.c
@@ -1,4 +1,4 @@
|
||||
/* pdp8_rx.c: RX8E/RX01 floppy disk simulator
|
||||
/* pdp8_rx.c: RX8E/RX01, RX28/RX02 floppy disk simulator
|
||||
|
||||
Copyright (c) 1993-2002, Robert M Supnik
|
||||
|
||||
@@ -23,8 +23,11 @@
|
||||
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.
|
||||
|
||||
rx RX8E/RX01 floppy disk
|
||||
rx RX8E/RX01, RX28/RX02 floppy disk
|
||||
|
||||
08-Oct-02 RMS Added DIB, device number support
|
||||
Fixed reset to work with disabled device
|
||||
15-Sep-02 RMS Added RX28/RX02 support
|
||||
06-Jan-02 RMS Changed enable/disable support
|
||||
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
|
||||
24-Nov-01 RMS Converted FLG to array
|
||||
@@ -35,11 +38,13 @@
|
||||
15-Aug-96 RMS Fixed bug in LCD
|
||||
|
||||
An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.
|
||||
Tracks are numbered 0-76, sectors 1-26. The RX8E can store data in
|
||||
8b mode or 12b mode. In 8b mode, the controller reads or writes
|
||||
128 bytes per sector. In 12b mode, the reads or writes 64 12b words
|
||||
per sector. The 12b words are bit packed into the first 96 bytes
|
||||
of the sector; the last 32 bytes are zeroed on writes.
|
||||
An RX02 diskette consists of 77 tracks, each with 26 sectors of 128B
|
||||
(single density) or 256B (double density). Tracks are numbered 0-76,
|
||||
sectors 1-26. The RX8E (RX28) can store data in 8b mode or 12b mode.
|
||||
In 8b mode, the controller reads or writes 128 bytes (128B or 256B)
|
||||
per sector. In 12b mode, it reads or writes 64 (64 or 128) 12b words
|
||||
per sector. The 12b words are bit packed into the first 96 (192) bytes
|
||||
of the sector; the last 32 (64) bytes are zeroed on writes.
|
||||
*/
|
||||
|
||||
#include "pdp8_defs.h"
|
||||
@@ -49,21 +54,32 @@
|
||||
#define RX_NUMSC 26 /* sectors/track */
|
||||
#define RX_M_SECTOR 0177 /* cf Jones!! */
|
||||
#define RX_NUMBY 128 /* bytes/sector */
|
||||
#define RX2_NUMBY 256
|
||||
#define RX_NUMWD (RX_NUMBY / 2) /* words/sector */
|
||||
#define RX2_NUMWD (RX2_NUMBY / 2)
|
||||
#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) /* bytes/disk */
|
||||
#define RX2_SIZE (RX_NUMTR * RX_NUMSC * RX2_NUMBY)
|
||||
#define RX_NUMDR 2 /* drives/controller */
|
||||
#define RX_M_NUMDR 01
|
||||
#define UNIT_V_WLK (UNIT_V_UF) /* write locked */
|
||||
#define UNIT_WLK (1 << UNIT_V_UF)
|
||||
#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
|
||||
#define UNIT_V_DEN (UNIT_V_UF + 1) /* double density */
|
||||
#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */
|
||||
#define UNIT_WLK (1u << UNIT_V_WLK)
|
||||
#define UNIT_DEN (1u << UNIT_V_DEN)
|
||||
#define UNIT_AUTO (1u << UNIT_V_AUTO)
|
||||
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
|
||||
|
||||
#define IDLE 0 /* idle state */
|
||||
#define RWDS 1 /* rw, sect next */
|
||||
#define RWDT 2 /* rw, track next */
|
||||
#define FILL 3 /* fill buffer */
|
||||
#define EMPTY 4 /* empty buffer */
|
||||
#define CMD_COMPLETE 5 /* set done next */
|
||||
#define INIT_COMPLETE 6 /* init compl next */
|
||||
#define CMD8 1 /* 8b cmd, ho next */
|
||||
#define RWDS 2 /* rw, sect next */
|
||||
#define RWDT 3 /* rw, track next */
|
||||
#define RWXFR 4 /* rw, transfer */
|
||||
#define FILL 5 /* fill buffer */
|
||||
#define EMPTY 6 /* empty buffer */
|
||||
#define SDCNF 7 /* set dens, conf next */
|
||||
#define SDXFR 8 /* set dens, transfer */
|
||||
#define CMD_COMPLETE 9 /* set done next */
|
||||
#define INIT_COMPLETE 10 /* init compl next */
|
||||
|
||||
#define RXCS_V_FUNC 1 /* function */
|
||||
#define RXCS_M_FUNC 7
|
||||
@@ -71,25 +87,31 @@
|
||||
#define RXCS_EMPTY 1 /* empty buffer */
|
||||
#define RXCS_WRITE 2 /* write sector */
|
||||
#define RXCS_READ 3 /* read sector */
|
||||
#define RXCS_SDEN 4 /* set density (RX28) */
|
||||
#define RXCS_RXES 5 /* read status */
|
||||
#define RXCS_WRDEL 6 /* write del data */
|
||||
#define RXCS_ECODE 7 /* read error code */
|
||||
#define RXCS_DRV 0020 /* drive */
|
||||
#define RXCS_MODE 0100 /* mode */
|
||||
#define RXCS_MAINT 0200 /* maintenance */
|
||||
#define RXCS_DEN 0400 /* density (RX28) */
|
||||
#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC)
|
||||
|
||||
#define RXES_CRC 0001 /* CRC error */
|
||||
#define RXES_PAR 0002 /* parity error */
|
||||
#define RXES_CRC 0001 /* CRC error NI */
|
||||
#define RXES_ID 0004 /* init done */
|
||||
#define RXES_WLK 0010 /* write protect */
|
||||
#define RXES_RX02 0010 /* RX02 (RX28) */
|
||||
#define RXES_DERR 0020 /* density err (RX28) */
|
||||
#define RXES_DEN 0040 /* density (RX28) */
|
||||
#define RXES_DD 0100 /* deleted data */
|
||||
#define RXES_DRDY 0200 /* drive ready */
|
||||
|
||||
#define TRACK u3 /* current track */
|
||||
#define READ_RXDBR ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr)
|
||||
#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY
|
||||
#define READ_RXDBR ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr)
|
||||
#define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, dev_enb;
|
||||
extern int32 int_req, int_enable, dev_done;
|
||||
|
||||
int32 rx_28 = 0; /* controller type */
|
||||
int32 rx_tr = 0; /* xfer ready flag */
|
||||
int32 rx_err = 0; /* error flag */
|
||||
int32 rx_csr = 0; /* control/status */
|
||||
@@ -102,13 +124,22 @@ int32 rx_state = IDLE; /* controller state */
|
||||
int32 rx_cwait = 100; /* command time */
|
||||
int32 rx_swait = 10; /* seek, per track */
|
||||
int32 rx_xwait = 1; /* tr set time */
|
||||
int32 rx_stopioe = 1; /* stop on error */
|
||||
uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */
|
||||
int32 bufptr = 0; /* buffer pointer */
|
||||
int32 rx_stopioe = 0; /* stop on error */
|
||||
uint8 rx_buf[RX2_NUMBY] = { 0 }; /* sector buffer */
|
||||
static int32 bptr = 0; /* buffer pointer */
|
||||
|
||||
DEVICE rx_dev;
|
||||
int32 rx (int32 IR, int32 AC);
|
||||
t_stat rx_svc (UNIT *uptr);
|
||||
t_stat rx_reset (DEVICE *dptr);
|
||||
t_stat rx_boot (int32 unitno);
|
||||
|
||||
t_stat rx_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat rx_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat rx_attach (UNIT *uptr, char *cptr);
|
||||
void rx_cmd (void);
|
||||
void rx_done (int32 esr_flags, int32 new_ecode);
|
||||
t_stat rx_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
/* RX8E data structures
|
||||
|
||||
rx_dev RX device descriptor
|
||||
@@ -117,6 +148,8 @@ t_stat rx_boot (int32 unitno);
|
||||
rx_mod RX modifier list
|
||||
*/
|
||||
|
||||
DIB rx_dib = { DEV_RX, 1, { &rx } };
|
||||
|
||||
UNIT rx_unit[] = {
|
||||
{ UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+
|
||||
UNIT_ROABLE, RX_SIZE) },
|
||||
@@ -126,12 +159,12 @@ UNIT rx_unit[] = {
|
||||
REG rx_reg[] = {
|
||||
{ ORDATA (RXCS, rx_csr, 12) },
|
||||
{ ORDATA (RXDB, rx_dbr, 12) },
|
||||
{ ORDATA (RXES, rx_esr, 8) },
|
||||
{ ORDATA (RXES, rx_esr, 12) },
|
||||
{ ORDATA (RXERR, rx_ecode, 8) },
|
||||
{ ORDATA (RXTA, rx_track, 8) },
|
||||
{ ORDATA (RXSA, rx_sector, 8) },
|
||||
{ ORDATA (STAPTR, rx_state, 3), REG_RO },
|
||||
{ ORDATA (BUFPTR, bufptr, 7) },
|
||||
{ DRDATA (STAPTR, rx_state, 4), REG_RO },
|
||||
{ DRDATA (BUFPTR, bptr, 8) },
|
||||
{ FLDATA (TR, rx_tr, 0) },
|
||||
{ FLDATA (ERR, rx_err, 0) },
|
||||
{ FLDATA (DONE, dev_done, INT_V_RX) },
|
||||
@@ -140,81 +173,78 @@ REG rx_reg[] = {
|
||||
{ DRDATA (CTIME, rx_cwait, 24), PV_LEFT },
|
||||
{ DRDATA (STIME, rx_swait, 24), PV_LEFT },
|
||||
{ DRDATA (XTIME, rx_xwait, 24), PV_LEFT },
|
||||
{ URDATA (FLG, rx_unit[0].flags, 2, 1, UNIT_V_WLK, RX_NUMDR, REG_HRO) },
|
||||
{ FLDATA (STOP_IOE, rx_stopioe, 0) },
|
||||
{ BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_RX), REG_HRO },
|
||||
{ BRDATA (SBUF, rx_buf, 8, 8, RX2_NUMBY) },
|
||||
{ FLDATA (RX28, rx_28, 0), REG_HRO },
|
||||
{ ORDATA (DEVNUM, rx_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB rx_mod[] = {
|
||||
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
|
||||
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RX, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_RX, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "RX28",
|
||||
&rx_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "RX8E",
|
||||
&rx_settype, NULL, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
|
||||
NULL, &rx_showtype, NULL },
|
||||
{ (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL },
|
||||
{ (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL },
|
||||
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
|
||||
{ UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
|
||||
{ (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &rx_set_size },
|
||||
{ (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &rx_set_size },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE rx_dev = {
|
||||
"RX", rx_unit, rx_reg, rx_mod,
|
||||
RX_NUMDR, 8, 20, 1, 8, 8,
|
||||
NULL, NULL, &rx_reset,
|
||||
&rx_boot, NULL, NULL };
|
||||
&rx_boot, &rx_attach, NULL,
|
||||
&rx_dib, DEV_DISABLE };
|
||||
|
||||
/* IOT routine */
|
||||
|
||||
int32 rx (int32 pulse, int32 AC)
|
||||
int32 rx (int32 IR, int32 AC)
|
||||
{
|
||||
int32 drv;
|
||||
int32 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* get drive number */
|
||||
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* unused */
|
||||
break;
|
||||
case 1: /* LCD */
|
||||
if (rx_state != IDLE) return AC; /* ignore if busy */
|
||||
rx_dbr = rx_csr = AC; /* save new command */
|
||||
dev_done = dev_done & ~INT_RX; /* clear done, int */
|
||||
int_req = int_req & ~INT_RX;
|
||||
rx_tr = rx_err = 0; /* clear flags */
|
||||
bufptr = 0; /* clear buf pointer */
|
||||
switch ((AC >> RXCS_V_FUNC) & RXCS_M_FUNC) { /* decode command */
|
||||
case RXCS_FILL:
|
||||
rx_state = FILL; /* state = fill */
|
||||
bptr = 0; /* clear buf pointer */
|
||||
if (rx_28 && (AC & RXCS_MODE)) { /* RX28 8b mode? */
|
||||
rx_dbr = rx_csr = AC & 0377; /* save 8b */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
break;
|
||||
case RXCS_EMPTY:
|
||||
rx_state = EMPTY; /* state = empty */
|
||||
sim_activate (&rx_unit[0], rx_xwait); /* sched xfer */
|
||||
break;
|
||||
case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
|
||||
rx_state = RWDS; /* state = get sector */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break;
|
||||
default:
|
||||
rx_state = CMD_COMPLETE; /* state = cmd compl */
|
||||
drv = (rx_csr & RXCS_DRV) > 0; /* get drive number */
|
||||
sim_activate (&rx_unit[drv], rx_cwait); /* sched done */
|
||||
break; } /* end switch func */
|
||||
rx_state = CMD8; } /* wait for part 2 */
|
||||
else { rx_dbr = rx_csr = AC; /* save new command */
|
||||
rx_cmd (); } /* issue command */
|
||||
return 0; /* clear AC */
|
||||
case 2: /* XDR */
|
||||
switch (rx_state & 07) { /* case on state */
|
||||
default: /* default */
|
||||
return READ_RXDBR; /* return data reg */
|
||||
switch (rx_state & 017) { /* case on state */
|
||||
case EMPTY: /* emptying buffer */
|
||||
sim_activate (&rx_unit[0], rx_xwait); /* sched xfer */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */
|
||||
return READ_RXDBR; /* return data reg */
|
||||
case RWDS: /* sector */
|
||||
rx_sector = AC & RX_M_SECTOR; /* save sector */
|
||||
case FILL: /* fill */
|
||||
rx_dbr = AC; /* save data */
|
||||
sim_activate (&rx_unit[0], rx_xwait); /* sched xfer */
|
||||
case CMD8: /* waiting for cmd */
|
||||
rx_dbr = AC & 0377;
|
||||
rx_csr = (rx_csr & 0377) | ((AC & 017) << 8);
|
||||
rx_cmd ();
|
||||
break;
|
||||
case RWDT: /* track */
|
||||
rx_track = AC & RX_M_TRACK; /* save track */
|
||||
case RWDS:case RWDT:case FILL:case SDCNF: /* waiting for data */
|
||||
rx_dbr = AC; /* save data */
|
||||
drv = (rx_csr & RXCS_DRV) > 0; /* get drive number */
|
||||
sim_activate (&rx_unit[drv], /* sched done */
|
||||
rx_swait * abs (rx_track - rx_unit[drv].TRACK));
|
||||
break; } /* end switch state */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* schedule */
|
||||
break;
|
||||
default: /* default */
|
||||
return READ_RXDBR; } /* return data reg */
|
||||
break;
|
||||
case 3: /* STR */
|
||||
if (rx_tr != 0) {
|
||||
@@ -242,16 +272,47 @@ case 7: /* INIT */
|
||||
break; } /* end case pulse */
|
||||
return AC;
|
||||
}
|
||||
|
||||
void rx_cmd (void)
|
||||
{
|
||||
int32 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* get drive number */
|
||||
|
||||
switch (RXCS_GETFNC (rx_csr)) { /* decode command */
|
||||
case RXCS_FILL:
|
||||
rx_state = FILL; /* state = fill */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
break;
|
||||
case RXCS_EMPTY:
|
||||
rx_state = EMPTY; /* state = empty */
|
||||
sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */
|
||||
break;
|
||||
case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
|
||||
rx_state = RWDS; /* state = get sector */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
rx_esr = rx_esr & RXES_ID; /* clear errors */
|
||||
break;
|
||||
case RXCS_SDEN:
|
||||
if (rx_28) { /* RX28? */
|
||||
rx_state = SDCNF; /* state = get conf */
|
||||
rx_tr = 1; /* xfer is ready */
|
||||
break; } /* else fall thru */
|
||||
default:
|
||||
rx_state = CMD_COMPLETE; /* state = cmd compl */
|
||||
sim_activate (&rx_unit[drv], rx_cwait); /* sched done */
|
||||
break; } /* end switch func */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unit service; the action to be taken depends on the transfer state:
|
||||
|
||||
IDLE Should never get here, treat as unknown command
|
||||
RWDS Just transferred sector, wait for track, set tr
|
||||
RWDT Just transferred track, do read or write, finish command
|
||||
FILL copy dbr to rx_buf[bufptr], advance ptr
|
||||
if bufptr > max, finish command, else set tr
|
||||
EMPTY if bufptr > max, finish command, else
|
||||
copy rx_buf[bufptr] to dbr, advance ptr, set tr
|
||||
IDLE Should never get here
|
||||
RWDS Save sector, set TR, set RWDT
|
||||
RWDT Save track, set RWXFR
|
||||
RWXFR Read/write buffer
|
||||
FILL copy dbr to rx_buf[bptr], advance ptr
|
||||
if bptr > max, finish command, else set tr
|
||||
EMPTY if bptr > max, finish command, else
|
||||
copy rx_buf[bptr] to dbr, advance ptr, set tr
|
||||
CMD_COMPLETE copy requested data to dbr, finish command
|
||||
INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
|
||||
|
||||
@@ -261,158 +322,267 @@ return AC;
|
||||
|
||||
t_stat rx_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, func, byptr;
|
||||
int32 i, func, byptr, bps, wps;
|
||||
t_addr da;
|
||||
t_stat rval;
|
||||
void rx_done (int32 new_dbr, int32 new_ecode);
|
||||
#define PTR12(x) (((x) + (x) + (x)) >> 1)
|
||||
|
||||
rval = SCPE_OK; /* assume ok */
|
||||
func = (rx_csr >> RXCS_V_FUNC) & RXCS_M_FUNC; /* get function */
|
||||
if (rx_28 && (uptr->flags & UNIT_DEN))
|
||||
bps = RX2_NUMBY;
|
||||
else bps = RX_NUMBY;
|
||||
wps = bps / 2;
|
||||
func = RXCS_GETFNC (rx_csr); /* get function */
|
||||
switch (rx_state) { /* case on state */
|
||||
|
||||
case IDLE: /* idle */
|
||||
rx_done (rx_esr, 0); /* done */
|
||||
break;
|
||||
return SCPE_IERR;
|
||||
|
||||
case EMPTY: /* empty buffer */
|
||||
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
|
||||
if (bufptr >= RX_NUMBY) { /* done? */
|
||||
rx_done (rx_esr, 0); /* set done */
|
||||
break; } /* and exit */
|
||||
rx_dbr = rx_buf[bufptr]; } /* else get data */
|
||||
else { byptr = PTR12 (bufptr); /* 12b xfer */
|
||||
if (bufptr >= RX_NUMWD) { /* done? */
|
||||
rx_done (rx_esr, 0); /* set done */
|
||||
break; } /* and exit */
|
||||
rx_dbr = (bufptr & 1)? /* get data */
|
||||
((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]:
|
||||
(rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017); }
|
||||
bufptr = bufptr + 1;
|
||||
if (bptr >= bps) { /* done? */
|
||||
rx_done (0, 0); /* set done */
|
||||
break; } /* and exit */
|
||||
rx_dbr = rx_buf[bptr]; } /* else get data */
|
||||
else {
|
||||
byptr = PTR12 (bptr); /* 12b xfer */
|
||||
if (bptr >= wps) { /* done? */
|
||||
rx_done (0, 0); /* set done */
|
||||
break; } /* and exit */
|
||||
rx_dbr = (bptr & 1)? /* get data */
|
||||
((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]:
|
||||
(rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017); }
|
||||
bptr = bptr + 1;
|
||||
rx_tr = 1;
|
||||
break;
|
||||
|
||||
case FILL: /* fill buffer */
|
||||
if (rx_csr & RXCS_MODE) { /* 8b xfer? */
|
||||
rx_buf[bufptr] = rx_dbr; /* fill buffer */
|
||||
bufptr = bufptr + 1;
|
||||
if (bufptr < RX_NUMBY) rx_tr = 1; /* if more, set xfer */
|
||||
else rx_done (rx_esr, 0); } /* else done */
|
||||
else { byptr = PTR12 (bufptr); /* 12b xfer */
|
||||
if (bufptr & 1) { /* odd or even? */
|
||||
rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
|
||||
rx_buf[byptr + 1] = rx_dbr & 0377; }
|
||||
else {
|
||||
rx_buf[byptr] = (rx_dbr >> 4) & 0377;
|
||||
rx_buf[byptr + 1] = (rx_dbr & 017) << 4; }
|
||||
bufptr = bufptr + 1;
|
||||
if (bufptr < RX_NUMWD) rx_tr = 1; /* if more, set xfer */
|
||||
else { for (i = PTR12 (RX_NUMWD); i < RX_NUMBY; i++)
|
||||
rx_buf[i] = 0; /* else fill sector */
|
||||
rx_done (rx_esr, 0); } } /* set done */
|
||||
rx_buf[bptr] = rx_dbr; /* fill buffer */
|
||||
bptr = bptr + 1;
|
||||
if (bptr < bps) rx_tr = 1; /* if more, set xfer */
|
||||
else rx_done (0, 0); } /* else done */
|
||||
else {
|
||||
byptr = PTR12 (bptr); /* 12b xfer */
|
||||
if (bptr & 1) { /* odd or even? */
|
||||
rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
|
||||
rx_buf[byptr + 1] = rx_dbr & 0377; }
|
||||
else {
|
||||
rx_buf[byptr] = (rx_dbr >> 4) & 0377;
|
||||
rx_buf[byptr + 1] = (rx_dbr & 017) << 4; }
|
||||
bptr = bptr + 1;
|
||||
if (bptr < wps) rx_tr = 1; /* if more, set xfer */
|
||||
else {
|
||||
for (i = PTR12 (RX_NUMWD); i < RX_NUMBY; i++)
|
||||
rx_buf[i] = 0; /* else fill sector */
|
||||
rx_done (0, 0); } } /* set done */
|
||||
break;
|
||||
|
||||
case RWDS: /* wait for sector */
|
||||
rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */
|
||||
rx_tr = 1; /* set xfer ready */
|
||||
rx_state = RWDT; /* advance state */
|
||||
break;
|
||||
return SCPE_OK;
|
||||
case RWDT: /* wait for track */
|
||||
rx_track = rx_dbr & RX_M_TRACK; /* save track */
|
||||
rx_state = RWXFR;
|
||||
sim_activate (uptr, /* sched done */
|
||||
rx_swait * abs (rx_track - uptr->TRACK));
|
||||
return SCPE_OK;
|
||||
case RWXFR: /* transfer */
|
||||
if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
|
||||
rx_done (0, 0110); /* done, error */
|
||||
return IORETURN (rx_stopioe, SCPE_UNATT); }
|
||||
if (rx_track >= RX_NUMTR) { /* bad track? */
|
||||
rx_done (rx_esr, 0040); /* done, error */
|
||||
break; }
|
||||
uptr -> TRACK = rx_track; /* now on track */
|
||||
rx_done (0, 0040); /* done, error */
|
||||
break; }
|
||||
uptr->TRACK = rx_track; /* now on track */
|
||||
if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */
|
||||
rx_done (rx_esr, 0070); /* done, error */
|
||||
rx_done (0, 0070); /* done, error */
|
||||
break; }
|
||||
if (rx_28 && /* RX28? */
|
||||
(((uptr->flags & UNIT_DEN) != 0) ^
|
||||
((rx_csr & RXCS_DEN) != 0))) { /* densities agree? */
|
||||
rx_done (RXES_DERR, 0240); /* no, error */
|
||||
break; }
|
||||
if ((uptr -> flags & UNIT_BUF) == 0) { /* not buffered? */
|
||||
rx_done (rx_esr, 0110); /* done, error */
|
||||
rval = SCPE_UNATT; /* return error */
|
||||
break; }
|
||||
da = CALC_DA (rx_track, rx_sector); /* get disk address */
|
||||
da = CALC_DA (rx_track, rx_sector, bps); /* get disk address */
|
||||
if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */
|
||||
if (func == RXCS_READ) { /* read? */
|
||||
for (i = 0; i < RX_NUMBY; i++)
|
||||
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); }
|
||||
else { if (uptr -> flags & UNIT_WPRT) { /* write and locked? */
|
||||
rx_esr = rx_esr | RXES_WLK; /* flag error */
|
||||
rx_done (rx_esr, 0100); /* done, error */
|
||||
break; }
|
||||
for (i = 0; i < RX_NUMBY; i++) /* write */
|
||||
*(((int8 *) uptr -> filebuf) + da + i) = rx_buf[i];
|
||||
da = da + RX_NUMBY;
|
||||
if (da > uptr -> hwmark) uptr -> hwmark = da; }
|
||||
rx_done (rx_esr, 0); /* done */
|
||||
for (i = 0; i < bps; i++)
|
||||
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); }
|
||||
else { /* write */
|
||||
if (uptr->flags & UNIT_WPRT) { /* locked? */
|
||||
rx_done (0, 0100); /* done, error */
|
||||
break; }
|
||||
for (i = 0; i < RX_NUMBY; i++) /* write */
|
||||
*(((int8 *) uptr->filebuf) + da + i) = rx_buf[i];
|
||||
da = da + RX_NUMBY;
|
||||
if (da > uptr->hwmark) uptr->hwmark = da; }
|
||||
rx_done (0, 0); /* done */
|
||||
break;
|
||||
|
||||
case SDCNF: /* confirm set density */
|
||||
if ((rx_dbr & 0377) != 0111) { /* confirmed? */
|
||||
rx_done (0, 0250); /* no, error */
|
||||
break; }
|
||||
rx_state = SDXFR; /* next state */
|
||||
sim_activate (uptr, rx_cwait * 100); /* schedule operation */
|
||||
break;
|
||||
case SDXFR: /* erase disk */
|
||||
for (i = 0; i < (int32) uptr->capac; i++)
|
||||
*(((int8 *) uptr->filebuf) + i) = 0;
|
||||
uptr->hwmark = uptr->capac;
|
||||
if (rx_csr & RXCS_DEN) uptr->flags = uptr->flags | UNIT_DEN;
|
||||
else uptr->flags = uptr->flags & ~UNIT_DEN;
|
||||
rx_done (0, 0);
|
||||
break;
|
||||
|
||||
case CMD_COMPLETE: /* command complete */
|
||||
if (func == RXCS_ECODE) rx_done (rx_ecode, 0);
|
||||
else if (uptr -> flags & UNIT_ATT) rx_done (rx_esr | RXES_DRDY, 0);
|
||||
else rx_done (rx_esr, 0);
|
||||
if (func == RXCS_ECODE) { /* read ecode? */
|
||||
rx_dbr = rx_ecode; /* set dbr */
|
||||
rx_done (0, -1); } /* don't update */
|
||||
else rx_done (0, 0);
|
||||
break;
|
||||
|
||||
case INIT_COMPLETE: /* init complete */
|
||||
rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */
|
||||
rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */
|
||||
if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */
|
||||
rx_done (rx_esr | RXES_ID, 0010); /* init done, error */
|
||||
break; }
|
||||
da = CALC_DA (1, 1); /* track 1, sector 1 */
|
||||
for (i = 0; i < RX_NUMBY; i++) /* read sector */
|
||||
rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i);
|
||||
rx_done (rx_esr | RXES_ID | RXES_DRDY, 0); /* set done */
|
||||
rx_done (RXES_ID, 0010); /* init done, error */
|
||||
break; }
|
||||
da = CALC_DA (1, 1, bps); /* track 1, sector 1 */
|
||||
for (i = 0; i < bps; i++) /* read sector */
|
||||
rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i);
|
||||
rx_done (RXES_ID, 0); /* set done */
|
||||
if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;
|
||||
break; } /* end case state */
|
||||
return IORETURN (rx_stopioe, rval);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Command complete. Set done and put final value in interface register,
|
||||
return to IDLE state.
|
||||
*/
|
||||
|
||||
void rx_done (int32 new_dbr, int32 new_ecode)
|
||||
void rx_done (int32 esr_flags, int32 new_ecode)
|
||||
{
|
||||
int32 drv = (rx_csr & RXCS_DRV)? 1: 0;
|
||||
|
||||
rx_state = IDLE; /* now idle */
|
||||
dev_done = dev_done | INT_RX; /* set done */
|
||||
int_req = INT_UPDATE; /* update ints */
|
||||
rx_dbr = new_dbr; /* update buffer */
|
||||
if (new_ecode != 0) { /* test for error */
|
||||
rx_ecode = new_ecode;
|
||||
rx_err = 1; }
|
||||
rx_state = IDLE; /* now idle */
|
||||
rx_esr = (rx_esr | esr_flags) & ~(RXES_DRDY|RXES_RX02|RXES_DEN);
|
||||
if (rx_28) rx_esr = rx_esr | RXES_RX02; /* update estat */
|
||||
if (rx_unit[drv].flags & UNIT_ATT) { /* update drv rdy */
|
||||
rx_esr = rx_esr | RXES_DRDY;
|
||||
if (rx_unit[drv].flags & UNIT_DEN) /* update density */
|
||||
rx_esr = rx_esr | RXES_DEN; }
|
||||
if (new_ecode > 0) rx_err = 1; /* test for error */
|
||||
if (new_ecode < 0) return; /* don't update? */
|
||||
rx_ecode = new_ecode; /* update ecode */
|
||||
rx_dbr = rx_esr; /* update RXDB */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine. The RX is one of the few devices that schedules
|
||||
an I/O transfer as part of its initialization.
|
||||
*/
|
||||
an I/O transfer as part of its initialization */
|
||||
|
||||
t_stat rx_reset (DEVICE *dptr)
|
||||
{
|
||||
rx_dbr = rx_csr = 0; /* 12b mode, drive 0 */
|
||||
rx_esr = rx_ecode = 0; /* clear error */
|
||||
rx_tr = rx_err = 0; /* clear flags */
|
||||
rx_track = rx_sector = 0; /* clear address */
|
||||
rx_state = IDLE; /* ctrl idle */
|
||||
dev_done = dev_done & ~INT_RX; /* clear done, int */
|
||||
int_req = int_req & ~INT_RX;
|
||||
int_enable = int_enable & ~INT_RX;
|
||||
rx_dbr = rx_csr = 0; /* 12b mode, drive 0 */
|
||||
sim_cancel (&rx_unit[1]); /* cancel drive 1 */
|
||||
if (rx_unit[0].flags & UNIT_BUF) { /* attached? */
|
||||
if (dptr->flags & DEV_DIS) sim_cancel (&rx_unit[0]); /* disabled? */
|
||||
else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */
|
||||
rx_state = INIT_COMPLETE; /* yes, sched init */
|
||||
sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK)); }
|
||||
else rx_done (rx_esr | RXES_ID, 0010); /* no, error */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach routine */
|
||||
|
||||
t_stat rx_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
int32 p;
|
||||
t_stat r;
|
||||
|
||||
uptr->capac = (uptr->flags & UNIT_DEN)? RX2_SIZE: RX_SIZE;
|
||||
r = attach_unit (uptr, cptr);
|
||||
if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0) ||
|
||||
(rx_28 == 0)) return r;
|
||||
if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK;
|
||||
if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK;
|
||||
if (p > RX_SIZE) {
|
||||
uptr->flags = uptr->flags | UNIT_DEN;
|
||||
uptr->capac = RX2_SIZE; }
|
||||
else { uptr->flags = uptr->flags & ~UNIT_DEN;
|
||||
uptr->capac = RX_SIZE; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set size routine */
|
||||
|
||||
t_stat rx_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
|
||||
if ((rx_28 == 0) && val) return SCPE_NOFNC; /* not on RX8E */
|
||||
uptr->capac = val? RX2_SIZE: RX_SIZE;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Set controller type */
|
||||
|
||||
t_stat rx_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
|
||||
if (val == rx_28) return SCPE_OK;
|
||||
for (i = 0; i < RX_NUMDR; i++) {
|
||||
if (rx_unit[i].flags & UNIT_ATT) return SCPE_ALATT; }
|
||||
for (i = 0; i < RX_NUMDR; i++) {
|
||||
rx_unit[i].flags = rx_unit[i].flags & ~(UNIT_DEN | UNIT_AUTO);
|
||||
rx_unit[i].capac = RX_SIZE;
|
||||
if (val) rx_unit[i].flags = rx_unit[i].flags | UNIT_AUTO; }
|
||||
rx_28 = val;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Show controller type */
|
||||
|
||||
t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
{
|
||||
if (rx_28) fprintf (st, "RX28");
|
||||
else fprintf (st, "RX8E");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Bootstrap routine */
|
||||
|
||||
#define BOOT_START 022
|
||||
#define BOOT_INST 060
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
|
||||
#define BOOT_START 022
|
||||
#define BOOT_ENTRY 022
|
||||
#define BOOT_INST 060
|
||||
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
|
||||
#define BOOT2_START 020
|
||||
#define BOOT2_ENTRY 033
|
||||
#define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int16))
|
||||
|
||||
static const int32 boot_rom[] = {
|
||||
static const uint16 boot_rom[] = {
|
||||
06755, /* 22, SDN */
|
||||
05022, /* 23, JMP .-1 */
|
||||
07126, /* 24, CLL CML RTL ; read command + */
|
||||
01060, /* 25, TAD UNIT ; unit no */
|
||||
06751, /* 26, LCD ; load read+unit */
|
||||
07201, /* 27, CLL IAC ; AC = 1 */
|
||||
04053, /* 30, JMS 053 ; load sector */
|
||||
04053, /* 31, JMS 053 ; load track */
|
||||
07201, /* 27, CLA IAC ; AC = 1 */
|
||||
04053, /* 30, JMS LOAD ; load sector */
|
||||
04053, /* 31, JMS LOAD ; load track */
|
||||
07104, /* 32, CLL RAL ; AC = 2 */
|
||||
06755, /* 33, SDN */
|
||||
05054, /* 34, JMP 54 */
|
||||
05054, /* 34, JMP LOAD+1 */
|
||||
06754, /* 35, SER */
|
||||
07450, /* 36, SNA ; more to do? */
|
||||
07610, /* 37, CLA SKP ; error */
|
||||
@@ -420,27 +590,69 @@ static const int32 boot_rom[] = {
|
||||
07402, 07402, /* 41-45, HALT ; error */
|
||||
07402, 07402, 07402,
|
||||
06751, /* 46, LCD ; load empty */
|
||||
04053, /* 47, JMS 53 ; get data */
|
||||
04053, /* 47, JMS LOAD ; get data */
|
||||
03002, /* 50, DCA 2 ; store */
|
||||
02050, /* 51, ISZ 50 ; incr store */
|
||||
05047, /* 52, JMP 47 ; loop until done */
|
||||
00000, /* 53, 0 */
|
||||
00000, /* LOAD, 0 */
|
||||
06753, /* 54, STR */
|
||||
05033, /* 55, JMP 33 */
|
||||
06752, /* 56, XDR */
|
||||
05453, /* 57, JMP I 53 */
|
||||
05453, /* 57, JMP I LOAD */
|
||||
07024, /* UNIT, CML RAL ; for unit 1 */
|
||||
06030 /* 61, KCC */
|
||||
};
|
||||
|
||||
t_stat rx_boot (int32 unitno)
|
||||
static const uint16 boot2_rom[] = {
|
||||
01061, /* READ, TAD UNIT ; next unit+den */
|
||||
01046, /* 21, TAD CON360 ; add in 360 */
|
||||
00060, /* 22, AND CON420 ; mask to 420 */
|
||||
03061, /* 23, DCA UNIT ; 400,420,0,20... */
|
||||
07327, /* 24, STL CLA IAC RTL ; AC = 6 = read */
|
||||
01061, /* 25, TAD UNIT ; +unit+den */
|
||||
06751, /* 26, LCD ; load cmd */
|
||||
07201, /* 27, CLA IAC; ; AC = 1 = trksec */
|
||||
04053, /* 30, JMS LOAD ; load trk */
|
||||
04053, /* 31, JMS LOAD ; load sec */
|
||||
07004, /* CN7004, RAL ; AC = 2 = empty */
|
||||
06755, /* START, SDN ; done? */
|
||||
05054, /* 34, JMP LOAD+1 ; check xfr */
|
||||
06754, /* 35, SER ; error? */
|
||||
07450, /* 36, SNA ; AC=0 on start */
|
||||
05020, /* 37, JMP RD ; try next den,un */
|
||||
01061, /* 40, TAD UNIT ; +unit+den */
|
||||
06751, /* 41, LCD ; load cmd */
|
||||
01061, /* 42, TAD UNIT ; set 60 for sec boot */
|
||||
00046, /* 43, AND CON360 ; only density */
|
||||
01032, /* 44, TAD CN7004 ; magic */
|
||||
03060, /* 45, DCA 60 */
|
||||
00360, /* CON360, 360 ; NOP */
|
||||
04053, /* 47, JMS LOAD ; get data */
|
||||
03002, /* 50, DCA 2 ; store */
|
||||
02050, /* 51, ISZ .-1 ; incr store */
|
||||
05047, /* 52, JMP .-3 ; loop until done */
|
||||
00000, /* LOAD, 0 */
|
||||
06753, /* 54, STR ; xfr ready? */
|
||||
05033, /* 55, JMP 33 ; no, chk done */
|
||||
06752, /* 56, XDR ; get word */
|
||||
05453, /* 57, JMP I 53 ; return */
|
||||
00420, /* CON420, 420 ; toggle */
|
||||
00020 /* UNIT, 20 ; unit+density */
|
||||
};
|
||||
|
||||
t_stat rx_boot (int32 unitno, DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
extern int32 saved_PC;
|
||||
extern uint16 M[];
|
||||
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
M[BOOT_INST] = unitno? 07024: 07004;
|
||||
saved_PC = BOOT_START;
|
||||
if (rx_dib.dev != DEV_RX) return STOP_NOTSTD; /* only std devno */
|
||||
if (rx_28) {
|
||||
for (i = 0; i < BOOT2_LEN; i++) M[BOOT2_START + i] = boot2_rom[i];
|
||||
saved_PC = BOOT2_ENTRY; }
|
||||
else {
|
||||
for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
|
||||
M[BOOT_INST] = unitno? 07024: 07004;
|
||||
saved_PC = BOOT_ENTRY; }
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,8 @@ const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented instruction",
|
||||
"HALT instruction",
|
||||
"Breakpoint" };
|
||||
"Breakpoint",
|
||||
"Non-standard device number" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
tti,tto KL8E terminal input/output
|
||||
|
||||
01-Nov-02 RMS Added 7B/8B support
|
||||
04-Oct-02 RMS Added DIBs, device number support
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
07-Sep-01 RMS Moved function prototypes
|
||||
*/
|
||||
@@ -32,13 +34,20 @@
|
||||
#include "pdp8_defs.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_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
int32 tti (int32 IR, int32 AC);
|
||||
int32 tto (int32 IR, int32 AC);
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
/* TTI data structures
|
||||
|
||||
@@ -48,7 +57,9 @@ t_stat tto_reset (DEVICE *dptr);
|
||||
tti_mod TTI modifiers list
|
||||
*/
|
||||
|
||||
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT };
|
||||
DIB tti_dib = { DEV_TTI, 1, { &tti } };
|
||||
|
||||
UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG tti_reg[] = {
|
||||
{ ORDATA (BUF, tti_unit.buf, 8) },
|
||||
@@ -57,19 +68,22 @@ REG tti_reg[] = {
|
||||
{ FLDATA (INT, int_req, INT_V_TTI) },
|
||||
{ DRDATA (POS, tti_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO },
|
||||
{ FLDATA (UC, tti_unit.flags, UNIT_V_KSR), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tti_mod[] = {
|
||||
{ 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 },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 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
|
||||
|
||||
@@ -78,7 +92,9 @@ DEVICE tti_dev = {
|
||||
tto_reg TTO register list
|
||||
*/
|
||||
|
||||
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
|
||||
DIB tto_dib = { DEV_TTO, 1, { &tto } };
|
||||
|
||||
UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG tto_reg[] = {
|
||||
{ ORDATA (BUF, tto_unit.buf, 8) },
|
||||
@@ -89,17 +105,25 @@ REG tto_reg[] = {
|
||||
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tto_mod[] = {
|
||||
{ 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 },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tto_dev = {
|
||||
"TTO", &tto_unit, tto_reg, NULL,
|
||||
"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 };
|
||||
|
||||
/* Terminal input: IOT routine */
|
||||
|
||||
int32 tti (int32 pulse, int32 AC)
|
||||
int32 tti (int32 IR, int32 AC)
|
||||
{
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* KCF */
|
||||
dev_done = dev_done & ~INT_TTI; /* clear flag */
|
||||
int_req = int_req & ~INT_TTI;
|
||||
@@ -129,14 +153,15 @@ default:
|
||||
|
||||
t_stat tti_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
int32 c;
|
||||
|
||||
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
|
||||
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);
|
||||
tti_unit.buf = temp | 0200; /* got char */
|
||||
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
|
||||
if (tti_unit.flags & UNIT_KSR) { /* UC only? */
|
||||
c = c & 0177;
|
||||
if (islower (c)) c = toupper (c);
|
||||
tti_unit.buf = c | 0200; } /* add TTY bit */
|
||||
else tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177);
|
||||
dev_done = dev_done | INT_TTI; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
tti_unit.pos = tti_unit.pos + 1;
|
||||
@@ -157,9 +182,9 @@ return SCPE_OK;
|
||||
|
||||
/* Terminal output: IOT routine */
|
||||
|
||||
int32 tto (int32 pulse, int32 AC)
|
||||
int32 tto (int32 IR, int32 AC)
|
||||
{
|
||||
switch (pulse) { /* decode IR<9:11> */
|
||||
switch (IR & 07) { /* decode IR<9:11> */
|
||||
case 0: /* TLF */
|
||||
dev_done = dev_done | INT_TTO; /* set flag */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
@@ -187,11 +212,16 @@ default:
|
||||
|
||||
t_stat tto_svc (UNIT *uptr)
|
||||
{
|
||||
int32 temp;
|
||||
int32 c;
|
||||
t_stat r;
|
||||
|
||||
dev_done = dev_done | INT_TTO; /* set done */
|
||||
int_req = INT_UPDATE; /* update interrupts */
|
||||
if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp;
|
||||
if (tto_unit.flags & UNIT_KSR) { /* UC only? */
|
||||
c = tto_unit.buf & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177);
|
||||
if ((r = sim_putchar (c)) != SCPE_OK) return r;
|
||||
tto_unit.pos = tto_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -207,3 +237,10 @@ int_enable = int_enable | INT_TTO; /* set enable */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
ttix,ttox PT08/KL8JA terminal input/output
|
||||
|
||||
02-Nov-02 RMS Added 7B/8B support
|
||||
04-Oct-02 RMS Added DIB, device number support
|
||||
22-Aug-02 RMS Updated for changes to sim_tmxr.c
|
||||
06-Jan-02 RMS Added device enable/disable support
|
||||
30-Dec-01 RMS Complete rebuild
|
||||
30-Nov-01 RMS Added extended SET/SHOW support
|
||||
@@ -42,18 +45,26 @@
|
||||
|
||||
#define TTX_LINES 4
|
||||
#define TTX_MASK (TTX_LINES - 1)
|
||||
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
|
||||
|
||||
#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */
|
||||
#define UNIT_V_UC (UNIT_V_UF + 1) /* upper case */
|
||||
#define UNIT_8B (1 << UNIT_V_8B)
|
||||
#define UNIT_UC (1 << UNIT_V_UC)
|
||||
|
||||
#define TTX_GETLN(x) (((x) >> 4) & TTX_MASK)
|
||||
|
||||
extern int32 int_req, int_enable, dev_done, dev_enb, stop_inst;
|
||||
extern int32 int_req, int_enable, dev_done, stop_inst;
|
||||
|
||||
uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */
|
||||
uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */
|
||||
int32 ttx_tps = 100; /* polls per second */
|
||||
TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */
|
||||
TMXR ttx_desc = { /* mux descriptor */
|
||||
TTX_LINES, 0, &ttx_ldsc[0], &ttx_ldsc[1], &ttx_ldsc[2], &ttx_ldsc[3] };
|
||||
TTX_LINES, 0, 0, &ttx_ldsc[0], &ttx_ldsc[1], &ttx_ldsc[2], &ttx_ldsc[3] };
|
||||
|
||||
DEVICE ttix_dev, ttox_dev;
|
||||
int32 ttix (int32 IR, int32 AC);
|
||||
int32 ttox (int32 IR, int32 AC);
|
||||
t_stat ttix_svc (UNIT *uptr);
|
||||
t_stat ttix_reset (DEVICE *dptr);
|
||||
t_stat ttox_svc (UNIT *uptr);
|
||||
@@ -62,6 +73,7 @@ t_stat ttx_attach (UNIT *uptr, char *cptr);
|
||||
t_stat ttx_detach (UNIT *uptr);
|
||||
t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
void ttx_enbdis (int32 dis);
|
||||
|
||||
/* TTIx data structures
|
||||
|
||||
@@ -71,6 +83,9 @@ t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
ttix_mod TTIx modifiers list
|
||||
*/
|
||||
|
||||
DIB ttix_dib = { DEV_KJ8, 8,
|
||||
{ &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } };
|
||||
|
||||
UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG ttix_reg[] = {
|
||||
@@ -80,7 +95,7 @@ REG ttix_reg[] = {
|
||||
{ GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTI1) },
|
||||
{ DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPS, ttx_tps, 10), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_TTI1), REG_HRO },
|
||||
{ ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ttix_mod[] = {
|
||||
@@ -91,15 +106,16 @@ MTAB ttix_mod[] = {
|
||||
NULL, &ttx_show, NULL },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
|
||||
NULL, &ttx_show, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_TTI1, NULL, "ENABLED", &set_enb },
|
||||
{ MTAB_XTD|MTAB_VDV, INT_TTI1, NULL, "DISABLED", &set_dsb },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
&set_dev, &show_dev, NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE ttix_dev = {
|
||||
"TTIX", &ttix_unit, ttix_reg, ttix_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
&tmxr_ex, &tmxr_dep, &ttix_reset,
|
||||
NULL, &ttx_attach, &ttx_detach };
|
||||
NULL, &ttx_attach, &ttx_detach,
|
||||
&ttix_dib, DEV_DISABLE };
|
||||
|
||||
/* TTOx data structures
|
||||
|
||||
@@ -121,21 +137,20 @@ REG ttox_reg[] = {
|
||||
{ GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) },
|
||||
{ URDATA (TIME, ttox_unit[0].wait, 10, 24, 0,
|
||||
TTX_LINES, PV_LEFT) },
|
||||
{ URDATA (FLGS, ttox_unit[0].flags, 8, 1, UNIT_V_UC,
|
||||
TTX_LINES, REG_HRO) },
|
||||
{ FLDATA (*DEVENB, dev_enb, INT_V_TTI1), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB ttox_mod[] = {
|
||||
{ UNIT_UC, 0, "lower case", "LC", NULL },
|
||||
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
|
||||
{ UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", NULL },
|
||||
{ UNIT_UC+UNIT_8B, 0 , "7b" , "7B" , NULL },
|
||||
{ UNIT_UC+UNIT_8B, UNIT_8B , "8b" , "8B" , NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE ttox_dev = {
|
||||
"TTOX", ttox_unit, ttox_reg, ttox_mod,
|
||||
4, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &ttox_reset,
|
||||
NULL, NULL, NULL };
|
||||
NULL, NULL, NULL,
|
||||
NULL, DEV_DISABLE };
|
||||
|
||||
/* Terminal input: IOT routine */
|
||||
|
||||
@@ -179,19 +194,20 @@ t_stat ttix_svc (UNIT *uptr)
|
||||
{
|
||||
int32 ln, c, temp;
|
||||
|
||||
if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
|
||||
temp = sim_rtcn_calb (ttx_tps, TMR_TTX); /* calibrate */
|
||||
sim_activate (uptr, temp); /* continue poll */
|
||||
ln = tmxr_poll_conn (&ttx_desc, uptr); /* look for connect */
|
||||
ln = tmxr_poll_conn (&ttx_desc); /* look for connect */
|
||||
if (ln >= 0) { /* got one? */
|
||||
ttx_ldsc[ln].rcve = 1; } /* rcv enabled */
|
||||
tmxr_poll_rx (&ttx_desc); /* poll for input */
|
||||
for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */
|
||||
if (ttx_ldsc[ln].conn) { /* connected? */
|
||||
if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */
|
||||
c = temp & 0177;
|
||||
if ((ttox_unit[ln].flags & UNIT_UC) && islower (c))
|
||||
c = toupper (c);
|
||||
if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */
|
||||
c = temp & 0177;
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = temp & ((ttox_unit[ln].flags & UNIT_8B)? 0377: 0177);
|
||||
ttix_buf[ln] = c;
|
||||
dev_done = dev_done | (INT_TTI1 << ln);
|
||||
int_req = INT_UPDATE; } } }
|
||||
@@ -204,10 +220,11 @@ t_stat ttix_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 t, ln, itto;
|
||||
|
||||
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
|
||||
if (ttix_unit.flags & UNIT_ATT) { /* if attached, */
|
||||
if (!sim_is_active (&ttix_unit)) {
|
||||
t = sim_rtcn_init (ttix_unit.wait, TMR_TTX);
|
||||
sim_activate (&ttix_unit, t); } } /* activate */
|
||||
t = sim_rtcn_init (ttix_unit.wait, TMR_TTX);
|
||||
sim_activate (&ttix_unit, t); } } /* activate */
|
||||
else sim_cancel (&ttix_unit); /* else stop */
|
||||
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
|
||||
ttix_buf[ln] = 0; /* clear buf, */
|
||||
@@ -258,17 +275,19 @@ t_stat ttox_svc (UNIT *uptr)
|
||||
{
|
||||
int32 c, ln = uptr - ttox_unit; /* line # */
|
||||
|
||||
if (ttx_desc.ldsc[ln] -> conn) { /* connected? */
|
||||
if (ttx_desc.ldsc[ln] -> xmte) { /* tx enabled? */
|
||||
TMLN *lp = ttx_desc.ldsc[ln]; /* get line */
|
||||
if (ttx_desc.ldsc[ln]->conn) { /* connected? */
|
||||
if (ttx_desc.ldsc[ln]->xmte) { /* tx enabled? */
|
||||
TMLN *lp = ttx_desc.ldsc[ln]; /* get line */
|
||||
if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */
|
||||
c = ttox_buf[ln] & 0177; /* get char */
|
||||
if ((ttox_unit[ln].flags & UNIT_UC) && islower (c))
|
||||
c = toupper (c);
|
||||
tmxr_putc_ln (lp, c); /* output char */
|
||||
tmxr_poll_tx (&ttx_desc); } /* poll xmt */
|
||||
else { tmxr_poll_tx (&ttx_desc); /* poll xmt */
|
||||
sim_activate (uptr, ttox_unit[ln].wait); /* wait */
|
||||
return SCPE_OK; } }
|
||||
if (islower (c)) c = toupper (c); }
|
||||
else c = ttox_buf[ln] & ((ttox_unit[ln].flags & UNIT_8B)? 0377: 0177);
|
||||
tmxr_putc_ln (lp, c); /* output char */
|
||||
tmxr_poll_tx (&ttx_desc); } /* poll xmt */
|
||||
else {
|
||||
tmxr_poll_tx (&ttx_desc); /* poll xmt */
|
||||
sim_activate (uptr, ttox_unit[ln].wait); /* wait */
|
||||
return SCPE_OK; } }
|
||||
dev_done = dev_done | (INT_TTO1 << ln); /* set done */
|
||||
int_req = INT_UPDATE; /* update intr */
|
||||
return SCPE_OK;
|
||||
@@ -280,6 +299,7 @@ t_stat ttox_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 ln, itto;
|
||||
|
||||
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
|
||||
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
|
||||
ttox_buf[ln] = 0; /* clear buf */
|
||||
itto = (INT_TTO1 << ln); /* interrupt */
|
||||
@@ -313,9 +333,9 @@ t_stat r;
|
||||
|
||||
r = tmxr_detach (&ttx_desc, uptr); /* detach */
|
||||
for (i = 0; i < TTX_LINES; i++) { /* all lines, */
|
||||
ttx_desc.ldsc[i] -> rcve = 0; /* disable rcv */
|
||||
ttx_desc.ldsc[i]->rcve = 0; /* disable rcv */
|
||||
sim_cancel (&ttox_unit[i]); } /* stop poll */
|
||||
return SCPE_OK;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Show summary processor */
|
||||
@@ -345,3 +365,15 @@ if (i < TTX_LINES) {
|
||||
else fprintf (st, "all disconnected\n");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Enable/disable device */
|
||||
|
||||
void ttx_enbdis (int32 dis)
|
||||
{
|
||||
if (dis) {
|
||||
ttix_dev.flags = ttox_dev.flags | DEV_DIS;
|
||||
ttox_dev.flags = ttox_dev.flags | DEV_DIS; }
|
||||
else { ttix_dev.flags = ttix_dev.flags & ~DEV_DIS;
|
||||
ttox_dev.flags = ttox_dev.flags & ~DEV_DIS; }
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user