1
0
mirror of https://github.com/simh/simh.git synced 2026-01-26 12:02:14 +00:00

Notes For V3.5-0

The source set has been extensively overhauled.  For correct
viewing, set Visual C++ or Emacs to have tab stops every 4
characters.

1. New Features in 3.4-1

1.1 All Ethernet devices

- Added Windows user-defined adapter names (from Timothe Litt)

1.2 Interdata, SDS, HP, PDP-8, PDP-18b terminal multiplexors

- Added support for SET <unit>n DISCONNECT

1.3 VAX

- Added latent QDSS support
- Revised autoconfigure to handle QDSS

1.4 PDP-11

- Revised autoconfigure to handle more casees

2. Bugs Fixed in 3.4-1

2.1 SCP and libraries

- Trim trailing spaces on all input (for example, attach file names)
- Fixed sim_sock spurious SIGPIPE error in Unix/Linux
- Fixed sim_tape misallocation of TPC map array for 64b simulators

2.2 1401

- Fixed bug, CPU reset was clearing SSB through SSG

2.3 PDP-11

- Fixed bug in VH vector display routine
- Fixed XU runt packet processing (found by Tim Chapman)

2.4 Interdata

- Fixed bug in SHOW PAS CONN/STATS
- Fixed potential integer overflow exception in divide

2.5 SDS

- Fixed bug in SHOW MUX CONN/STATS

2.6 HP

- Fixed bug in SHOW MUX CONN/STATS

2.7 PDP-8

- Fixed bug in SHOW TTIX CONN/STATS
- Fixed bug in SET/SHOW TTOXn LOG

2.8 PDP-18b

- Fixed bug in SHOW TTIX CONN/STATS
- Fixed bug in SET/SHOW TTOXn LOG

2.9 Nova, Eclipse

- Fixed potential integer overflow exception in divide
This commit is contained in:
Bob Supnik
2005-09-09 18:09:00 -07:00
committed by Mark Pizzolato
parent ec60bbf329
commit b7c1eae41f
257 changed files with 107140 additions and 97195 deletions

View File

@@ -1,6 +1,6 @@
/* pdp8_clk.c: PDP-8 real-time clock simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,18 +19,18 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
clk real time clock
clk real time clock
01-Mar-03 RMS Aded SET/SHOW CLK FREQ support
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
05-Mar-01 RMS Added clock calibration support
01-Mar-03 RMS Aded SET/SHOW CLK FREQ support
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
05-Mar-01 RMS Added clock calibration support
Note: includes the IOT's for both the PDP-8/E and PDP-8/A clocks
*/
@@ -39,8 +39,8 @@
extern int32 int_req, int_enable, dev_done, stop_inst;
int32 clk_tps = 60; /* ticks/second */
int32 tmxr_poll = 16000; /* term mux poll */
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);
@@ -50,9 +50,9 @@ t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);
/* CLK data structures
clk_dev CLK device descriptor
clk_unit CLK unit descriptor
clk_reg CLK register list
clk_dev CLK device descriptor
clk_unit CLK unit descriptor
clk_reg CLK register list
*/
DIB clk_dib = { DEV_CLK, 1, { &clk } };
@@ -60,30 +60,33 @@ DIB clk_dib = { DEV_CLK, 1, { &clk } };
UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 };
REG clk_reg[] = {
{ FLDATA (DONE, dev_done, INT_V_CLK) },
{ FLDATA (ENABLE, int_enable, INT_V_CLK) },
{ FLDATA (INT, int_req, INT_V_CLK) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
{ NULL } };
{ FLDATA (DONE, dev_done, INT_V_CLK) },
{ FLDATA (ENABLE, int_enable, INT_V_CLK) },
{ FLDATA (INT, int_req, INT_V_CLK) },
{ DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT },
{ DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
{ NULL }
};
MTAB clk_mod[] = {
{ MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
&clk_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
&clk_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
NULL, &clk_show_freq, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
{ 0 } };
{ MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
&clk_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
&clk_set_freq, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
NULL, &clk_show_freq, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
{ 0 }
};
DEVICE clk_dev = {
"CLK", &clk_unit, clk_reg, clk_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset,
NULL, NULL, NULL,
&clk_dib, 0 };
"CLK", &clk_unit, clk_reg, clk_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &clk_reset,
NULL, NULL, NULL,
&clk_dib, 0
};
/* IOT routine
IOT's 6131-6133 are the PDP-8/E clock
@@ -92,34 +95,43 @@ DEVICE clk_dev = {
int32 clk (int32 IR, int32 AC)
{
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 */
return AC;
case 2: /* CLDI */
int_enable = int_enable & ~INT_CLK; /* disable clk ints */
int_req = int_req & ~INT_CLK; /* update interrupts */
return AC;
case 3: /* CLSC */
if (dev_done & INT_CLK) { /* flag set? */
dev_done = dev_done & ~INT_CLK; /* clear flag */
int_req = int_req & ~INT_CLK; /* clear int req */
return IOT_SKP + AC; }
return AC;
case 5: /* CLLE */
if (AC & 1) int_enable = int_enable | INT_CLK; /* test AC<11> */
else int_enable = int_enable & ~INT_CLK;
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 6: /* CLCL */
dev_done = dev_done & ~INT_CLK; /* clear flag */
int_req = int_req & ~INT_CLK; /* clear int req */
return AC;
case 7: /* CLSK */
return (dev_done & INT_CLK)? IOT_SKP + AC: AC;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
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 */
return AC;
case 2: /* CLDI */
int_enable = int_enable & ~INT_CLK; /* disable clk ints */
int_req = int_req & ~INT_CLK; /* update interrupts */
return AC;
case 3: /* CLSC */
if (dev_done & INT_CLK) { /* flag set? */
dev_done = dev_done & ~INT_CLK; /* clear flag */
int_req = int_req & ~INT_CLK; /* clear int req */
return IOT_SKP + AC;
}
return AC;
case 5: /* CLLE */
if (AC & 1) int_enable = int_enable | INT_CLK; /* test AC<11> */
else int_enable = int_enable & ~INT_CLK;
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 6: /* CLCL */
dev_done = dev_done & ~INT_CLK; /* clear flag */
int_req = int_req & ~INT_CLK; /* clear int req */
return AC;
case 7: /* CLSK */
return (dev_done & INT_CLK)? IOT_SKP + AC: AC;
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
}
/* Unit service */
@@ -128,11 +140,11 @@ t_stat clk_svc (UNIT *uptr)
{
int32 t;
dev_done = dev_done | INT_CLK; /* set done */
int_req = INT_UPDATE; /* update interrupts */
t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
tmxr_poll = t; /* set mux poll */
dev_done = dev_done | INT_CLK; /* set done */
int_req = INT_UPDATE; /* update interrupts */
t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
sim_activate (&clk_unit, t); /* reactivate unit */
tmxr_poll = t; /* set mux poll */
return SCPE_OK;
}
@@ -140,10 +152,10 @@ return SCPE_OK;
t_stat clk_reset (DEVICE *dptr)
{
dev_done = dev_done & ~INT_CLK; /* clear done, int */
dev_done = dev_done & ~INT_CLK; /* clear done, int */
int_req = int_req & ~INT_CLK;
int_enable = int_enable & ~INT_CLK; /* clear enable */
sim_activate (&clk_unit, clk_unit.wait); /* activate unit */
int_enable = int_enable & ~INT_CLK; /* clear enable */
sim_activate (&clk_unit, clk_unit.wait); /* activate unit */
return SCPE_OK;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* pdp8_defs.h: PDP-8 simulator definitions
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,101 +19,102 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
13-Oct-03 RMS Added TSC8-75 support
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
18-Mar-01 RMS Added DF32 support
15-Feb-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
19-Mar-95 RMS Added dynamic memory size
02-May-94 RMS Added non-existent memory handling
13-Oct-03 RMS Added TSC8-75 support
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
18-Mar-01 RMS Added DF32 support
15-Feb-01 RMS Added DECtape support
14-Apr-99 RMS Changed t_addr to unsigned
19-Mar-95 RMS Added dynamic memory size
02-May-94 RMS Added non-existent memory handling
The author gratefully acknowledges the help of Max Burnet, Richie Lary,
and Bill Haygood in resolving questions about the PDP-8
*/
#include "sim_defs.h" /* simulator defns */
#ifndef _PDP8_DEFS_H_
#define _PDP8_DEFS_H_ 0
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_NOTSTD 4 /* non-std devno */
#define STOP_DTOFF 5 /* DECtape off reel */
#define STOP_RSRV 1 /* must be 1 */
#define STOP_HALT 2 /* HALT */
#define STOP_IBKPT 3 /* breakpoint */
#define STOP_NOTSTD 4 /* non-std devno */
#define STOP_DTOFF 5 /* DECtape off reel */
/* Memory */
#define MAXMEMSIZE 32768 /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
#define MAXMEMSIZE 32768 /* max memory size */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
/* IOT subroutine return codes */
#define IOT_V_SKP 12 /* skip */
#define IOT_V_REASON 13 /* reason */
#define IOT_SKP (1 << IOT_V_SKP)
#define IOT_REASON (1 << IOT_V_REASON)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
#define IOT_V_SKP 12 /* skip */
#define IOT_V_REASON 13 /* reason */
#define IOT_SKP (1 << IOT_V_SKP)
#define IOT_REASON (1 << IOT_V_REASON)
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
/* Timers */
#define TMR_CLK 0 /* timer 0 = clock */
#define TMR_TTX 1 /* timer 1 = TTx */
#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 */
#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;
typedef struct {
uint32 dev; /* base dev number */
uint32 num; /* number of slots */
int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat);
} 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_TSC 036
#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 */
#define DEV_TD8E 077 /* TD8E */
#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_TSC 036
#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 */
#define DEV_TD8E 077 /* TD8E */
/* Interrupt flags
The interrupt flags consist of three groups:
1. Devices with individual interrupt enables. These record
their interrupt requests in device_done and their enables
in device_enable, and must occupy the low bit positions.
1. Devices with individual interrupt enables. These record
their interrupt requests in device_done and their enables
in device_enable, and must occupy the low bit positions.
2. Devices without interrupt enables. These record their
interrupt requests directly in int_req, and must occupy
the middle bit positions.
2. Devices without interrupt enables. These record their
interrupt requests directly in int_req, and must occupy
the middle bit positions.
3. Overhead. These exist only in int_req and must occupy the
high bit positions.
3. Overhead. These exist only in int_req and must occupy the
high bit positions.
Because the PDP-8 does not have priority interrupts, the order
of devices within groups does not matter.
@@ -122,73 +123,75 @@ typedef struct pdp8_dib DIB;
to contiguous bits.
*/
#define INT_V_START 0 /* enable start */
#define INT_V_LPT (INT_V_START+0) /* line printer */
#define INT_V_PTP (INT_V_START+1) /* tape punch */
#define INT_V_PTR (INT_V_START+2) /* tape reader */
#define INT_V_TTO (INT_V_START+3) /* terminal */
#define INT_V_TTI (INT_V_START+4) /* keyboard */
#define INT_V_CLK (INT_V_START+5) /* clock */
#define INT_V_TTO1 (INT_V_START+6) /* tto1 */
#define INT_V_TTO2 (INT_V_START+7) /* tto2 */
#define INT_V_TTO3 (INT_V_START+8) /* tto3 */
#define INT_V_TTO4 (INT_V_START+9) /* tto4 */
#define INT_V_TTI1 (INT_V_START+10) /* tti1 */
#define INT_V_TTI2 (INT_V_START+11) /* tti2 */
#define INT_V_TTI3 (INT_V_START+12) /* tti3 */
#define INT_V_TTI4 (INT_V_START+13) /* tti4 */
#define INT_V_DIRECT (INT_V_START+14) /* direct start */
#define INT_V_RX (INT_V_DIRECT+0) /* RX8E */
#define INT_V_RK (INT_V_DIRECT+1) /* RK8E */
#define INT_V_RF (INT_V_DIRECT+2) /* RF08 */
#define INT_V_DF (INT_V_DIRECT+3) /* DF32 */
#define INT_V_MT (INT_V_DIRECT+4) /* TM8E */
#define INT_V_DTA (INT_V_DIRECT+5) /* TC08 */
#define INT_V_RL (INT_V_DIRECT+6) /* RL8A */
#define INT_V_PWR (INT_V_DIRECT+7) /* power int */
#define INT_V_UF (INT_V_DIRECT+8) /* user int */
#define INT_V_TSC (INT_V_DIRECT+9) /* TSC8-75 int */
#define INT_V_OVHD (INT_V_DIRECT+10) /* overhead start */
#define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */
#define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */
#define INT_V_ION (INT_V_OVHD+2) /* interrupts on */
#define INT_V_START 0 /* enable start */
#define INT_V_LPT (INT_V_START+0) /* line printer */
#define INT_V_PTP (INT_V_START+1) /* tape punch */
#define INT_V_PTR (INT_V_START+2) /* tape reader */
#define INT_V_TTO (INT_V_START+3) /* terminal */
#define INT_V_TTI (INT_V_START+4) /* keyboard */
#define INT_V_CLK (INT_V_START+5) /* clock */
#define INT_V_TTO1 (INT_V_START+6) /* tto1 */
#define INT_V_TTO2 (INT_V_START+7) /* tto2 */
#define INT_V_TTO3 (INT_V_START+8) /* tto3 */
#define INT_V_TTO4 (INT_V_START+9) /* tto4 */
#define INT_V_TTI1 (INT_V_START+10) /* tti1 */
#define INT_V_TTI2 (INT_V_START+11) /* tti2 */
#define INT_V_TTI3 (INT_V_START+12) /* tti3 */
#define INT_V_TTI4 (INT_V_START+13) /* tti4 */
#define INT_V_DIRECT (INT_V_START+14) /* direct start */
#define INT_V_RX (INT_V_DIRECT+0) /* RX8E */
#define INT_V_RK (INT_V_DIRECT+1) /* RK8E */
#define INT_V_RF (INT_V_DIRECT+2) /* RF08 */
#define INT_V_DF (INT_V_DIRECT+3) /* DF32 */
#define INT_V_MT (INT_V_DIRECT+4) /* TM8E */
#define INT_V_DTA (INT_V_DIRECT+5) /* TC08 */
#define INT_V_RL (INT_V_DIRECT+6) /* RL8A */
#define INT_V_PWR (INT_V_DIRECT+7) /* power int */
#define INT_V_UF (INT_V_DIRECT+8) /* user int */
#define INT_V_TSC (INT_V_DIRECT+9) /* TSC8-75 int */
#define INT_V_OVHD (INT_V_DIRECT+10) /* overhead start */
#define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */
#define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */
#define INT_V_ION (INT_V_OVHD+2) /* interrupts on */
#define INT_LPT (1 << INT_V_LPT)
#define INT_PTP (1 << INT_V_PTP)
#define INT_PTR (1 << INT_V_PTR)
#define INT_TTO (1 << INT_V_TTO)
#define INT_TTI (1 << INT_V_TTI)
#define INT_CLK (1 << INT_V_CLK)
#define INT_TTO1 (1 << INT_V_TTO1)
#define INT_TTO2 (1 << INT_V_TTO2)
#define INT_TTO3 (1 << INT_V_TTO3)
#define INT_TTO4 (1 << INT_V_TTO4)
#define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTI2 (1 << INT_V_TTI2)
#define INT_TTI3 (1 << INT_V_TTI3)
#define INT_TTI4 (1 << INT_V_TTI4)
#define INT_RX (1 << INT_V_RX)
#define INT_RK (1 << INT_V_RK)
#define INT_RF (1 << INT_V_RF)
#define INT_DF (1 << INT_V_DF)
#define INT_MT (1 << INT_V_MT)
#define INT_DTA (1 << INT_V_DTA)
#define INT_RL (1 << INT_V_RL)
#define INT_PWR (1 << INT_V_PWR)
#define INT_UF (1 << INT_V_UF)
#define INT_TSC (1 << INT_V_TSC)
#define INT_LPT (1 << INT_V_LPT)
#define INT_PTP (1 << INT_V_PTP)
#define INT_PTR (1 << INT_V_PTR)
#define INT_TTO (1 << INT_V_TTO)
#define INT_TTI (1 << INT_V_TTI)
#define INT_CLK (1 << INT_V_CLK)
#define INT_TTO1 (1 << INT_V_TTO1)
#define INT_TTO2 (1 << INT_V_TTO2)
#define INT_TTO3 (1 << INT_V_TTO3)
#define INT_TTO4 (1 << INT_V_TTO4)
#define INT_TTI1 (1 << INT_V_TTI1)
#define INT_TTI2 (1 << INT_V_TTI2)
#define INT_TTI3 (1 << INT_V_TTI3)
#define INT_TTI4 (1 << INT_V_TTI4)
#define INT_RX (1 << INT_V_RX)
#define INT_RK (1 << INT_V_RK)
#define INT_RF (1 << INT_V_RF)
#define INT_DF (1 << INT_V_DF)
#define INT_MT (1 << INT_V_MT)
#define INT_DTA (1 << INT_V_DTA)
#define INT_RL (1 << INT_V_RL)
#define INT_PWR (1 << INT_V_PWR)
#define INT_UF (1 << INT_V_UF)
#define INT_TSC (1 << INT_V_TSC)
#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING)
#define INT_NO_CIF_PENDING (1 << INT_V_NO_CIF_PENDING)
#define INT_ION (1 << INT_V_ION)
#define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */
#define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */
#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \
(INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \
(INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4)
#define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING)
#define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable))
#define INT_ION (1 << INT_V_ION)
#define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */
#define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */
#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \
(INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \
(INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4)
#define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING)
#define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable))
/* Function prototypes */
t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc);
#endif

View File

@@ -1,6 +1,6 @@
/* pdp8_df.c: DF32 fixed head disk simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,90 +19,90 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
df DF32 fixed head disk
df DF32 fixed head disk
04-Jan-04 RMS Changed sim_fsize calling sequence
26-Oct-03 RMS Cleaned up buffer copy code
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing support
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
04-Jan-04 RMS Changed sim_fsize calling sequence
26-Oct-03 RMS Cleaned up buffer copy code
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing support
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
The DF32 is a head-per-track disk. It uses the three cycle data break
facility. To minimize overhead, the entire DF32 is buffered in memory.
Two timing parameters are provided:
df_time Interword timing, must be non-zero
df_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst
df_time Interword timing, must be non-zero
df_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst
*/
#include "pdp8_defs.h"
#include <math.h>
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
#define UNIT_M_PLAT 03
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
#define UNIT_M_PLAT 03
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
/* Constants */
#define DF_NUMWD 2048 /* words/track */
#define DF_NUMTR 16 /* tracks/disk */
#define DF_DKSIZE (DF_NUMTR * DF_NUMWD) /* words/disk */
#define DF_NUMDK 4 /* disks/controller */
#define DF_WC 07750 /* word count */
#define DF_MA 07751 /* mem address */
#define DF_WMASK (DF_NUMWD - 1) /* word mask */
#define DF_NUMWD 2048 /* words/track */
#define DF_NUMTR 16 /* tracks/disk */
#define DF_DKSIZE (DF_NUMTR * DF_NUMWD) /* words/disk */
#define DF_NUMDK 4 /* disks/controller */
#define DF_WC 07750 /* word count */
#define DF_MA 07751 /* mem address */
#define DF_WMASK (DF_NUMWD - 1) /* word mask */
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define DF_READ 2 /* read */
#define DF_WRITE 4 /* write */
#define FUNC u4 /* function */
#define DF_READ 2 /* read */
#define DF_WRITE 4 /* write */
/* Status register */
#define DFS_PCA 04000 /* photocell status */
#define DFS_DEX 03700 /* disk addr extension */
#define DFS_MEX 00070 /* mem addr extension */
#define DFS_DRL 00004 /* data late error */
#define DFS_WLS 00002 /* write lock error */
#define DFS_NXD 00002 /* non-existent disk */
#define DFS_PER 00001 /* parity error */
#define DFS_ERR (DFS_DRL | DFS_WLS | DFS_PER)
#define DFS_V_DEX 6
#define DFS_V_MEX 3
#define DFS_PCA 04000 /* photocell status */
#define DFS_DEX 03700 /* disk addr extension */
#define DFS_MEX 00070 /* mem addr extension */
#define DFS_DRL 00004 /* data late error */
#define DFS_WLS 00002 /* write lock error */
#define DFS_NXD 00002 /* non-existent disk */
#define DFS_PER 00001 /* parity error */
#define DFS_ERR (DFS_DRL | DFS_WLS | DFS_PER)
#define DFS_V_DEX 6
#define DFS_V_MEX 3
#define GET_MEX(x) (((x) & DFS_MEX) << (12 - DFS_V_MEX))
#define GET_DEX(x) (((x) & DFS_DEX) << (12 - DFS_V_DEX))
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DF_NUMWD)))
#define UPDATE_PCELL if (GET_POS (df_time) < 6) df_sta = df_sta | DFS_PCA; \
else df_sta = df_sta & ~DFS_PCA
#define GET_MEX(x) (((x) & DFS_MEX) << (12 - DFS_V_MEX))
#define GET_DEX(x) (((x) & DFS_DEX) << (12 - DFS_V_DEX))
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) DF_NUMWD)))
#define UPDATE_PCELL if (GET_POS (df_time) < 6) df_sta = df_sta | DFS_PCA; \
else df_sta = df_sta & ~DFS_PCA
extern uint16 M[];
extern int32 int_req, stop_inst;
extern UNIT cpu_unit;
int32 df_sta = 0; /* status register */
int32 df_da = 0; /* disk address */
int32 df_done = 0; /* done flag */
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 */
int32 df_sta = 0; /* status register */
int32 df_da = 0; /* disk address */
int32 df_done = 0; /* done flag */
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);
@@ -117,49 +117,53 @@ t_stat df_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
/* DF32 data structures
df_dev RF device descriptor
df_unit RF unit descriptor
pcell_unit photocell timing unit (orphan)
df_reg RF register list
df_dev RF device descriptor
df_unit RF unit descriptor
pcell_unit photocell timing unit (orphan)
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_DKSIZE) };
UNIT df_unit = {
UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
DF_DKSIZE)
};
REG df_reg[] = {
{ ORDATA (STA, df_sta, 12) },
{ ORDATA (DA, df_da, 12) },
{ ORDATA (WC, M[DF_WC], 12) },
{ ORDATA (MA, M[DF_MA], 12) },
{ FLDATA (DONE, df_done, 0) },
{ FLDATA (INT, int_req, INT_V_DF) },
{ ORDATA (WLS, df_wlk, 8) },
{ DRDATA (TIME, df_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (BURST, df_burst, 0) },
{ FLDATA (STOP_IOE, df_stopioe, 0) },
{ DRDATA (CAPAC, df_unit.capac, 18), REG_HRO },
{ ORDATA (DEVNUM, df_dib.dev, 6), REG_HRO },
{ NULL } };
{ ORDATA (STA, df_sta, 12) },
{ ORDATA (DA, df_da, 12) },
{ ORDATA (WC, M[DF_WC], 12) },
{ ORDATA (MA, M[DF_MA], 12) },
{ FLDATA (DONE, df_done, 0) },
{ FLDATA (INT, int_req, INT_V_DF) },
{ ORDATA (WLS, df_wlk, 8) },
{ DRDATA (TIME, df_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (BURST, df_burst, 0) },
{ FLDATA (STOP_IOE, df_stopioe, 0) },
{ DRDATA (CAPAC, df_unit.capac, 18), REG_HRO },
{ ORDATA (DEVNUM, df_dib.dev, 6), REG_HRO },
{ NULL }
};
MTAB df_mod[] = {
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &df_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &df_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &df_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &df_set_size },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &df_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &df_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &df_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &df_set_size },
{ 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, &df_attach, NULL,
&df_dib, DEV_DISABLE };
"DF", &df_unit, df_reg, df_mod,
1, 8, 17, 1, 8, 12,
NULL, NULL, &df_reset,
&df_boot, &df_attach, NULL,
&df_dib, DEV_DISABLE
};
/* IOT routines */
int32 df60 (int32 IR, int32 AC)
@@ -167,30 +171,32 @@ int32 df60 (int32 IR, int32 AC)
int32 t;
int32 pulse = IR & 07;
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DCMA */
df_da = 0; /* clear disk addr */
df_done = 0; /* clear done */
df_sta = df_sta & ~DFS_ERR; /* clear errors */
int_req = int_req & ~INT_DF; } /* clear int req */
if (pulse & 6) { /* DMAR, DMAW */
df_da = df_da | AC; /* disk addr |= AC */
df_unit.FUNC = pulse & ~1; /* save function */
t = (df_da & DF_WMASK) - GET_POS (df_time); /* delta to new loc */
if (t < 0) t = t + DF_NUMWD; /* wrap around? */
sim_activate (&df_unit, t * df_time); /* schedule op */
AC = 0; } /* clear AC */
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DCMA */
df_da = 0; /* clear disk addr */
df_done = 0; /* clear done */
df_sta = df_sta & ~DFS_ERR; /* clear errors */
int_req = int_req & ~INT_DF; /* clear int req */
}
if (pulse & 6) { /* DMAR, DMAW */
df_da = df_da | AC; /* disk addr |= AC */
df_unit.FUNC = pulse & ~1; /* save function */
t = (df_da & DF_WMASK) - GET_POS (df_time); /* delta to new loc */
if (t < 0) t = t + DF_NUMWD; /* wrap around? */
sim_activate (&df_unit, t * df_time); /* schedule op */
AC = 0; /* clear AC */
}
return AC;
}
/* Based on the hardware implementation. DEAL and DEAC work as follows:
6615 pulse 1 = clear df_sta<dex,mex>
pulse 4 = df_sta = df_sta | AC<dex,mex>
AC = AC | old_df_sta
6616 pulse 2 = clear AC, skip if address confirmed
pulse 4 = df_sta = df_sta | AC<dex,mex> = 0 (nop)
AC = AC | old_df_sta
6615 pulse 1 = clear df_sta<dex,mex>
pulse 4 = df_sta = df_sta | AC<dex,mex>
AC = AC | old_df_sta
6616 pulse 2 = clear AC, skip if address confirmed
pulse 4 = df_sta = df_sta | AC<dex,mex> = 0 (nop)
AC = AC | old_df_sta
*/
int32 df61 (int32 IR, int32 AC)
@@ -198,14 +204,15 @@ int32 df61 (int32 IR, int32 AC)
int32 old_df_sta = df_sta;
int32 pulse = IR & 07;
UPDATE_PCELL; /* update photocell */
if (pulse & 1) /* DCEA */
df_sta = df_sta & ~(DFS_DEX | DFS_MEX); /* clear dex, mex */
if (pulse & 2) /* DSAC */
AC = ((df_da & DF_WMASK) == GET_POS (df_time))? IOT_SKP: 0;
UPDATE_PCELL; /* update photocell */
if (pulse & 1) /* DCEA */
df_sta = df_sta & ~(DFS_DEX | DFS_MEX); /* clear dex, mex */
if (pulse & 2) /* DSAC */
AC = ((df_da & DF_WMASK) == GET_POS (df_time))? IOT_SKP: 0;
if (pulse & 4) {
df_sta = df_sta | (AC & (DFS_DEX | DFS_MEX)); /* DEAL */
AC = AC | old_df_sta; } /* DEAC */
df_sta = df_sta | (AC & (DFS_DEX | DFS_MEX)); /* DEAL */
AC = AC | old_df_sta; /* DEAC */
}
return AC;
}
@@ -213,16 +220,18 @@ 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; }
if (pulse & 2) { /* DFSC */
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
else if (df_done) AC = AC | IOT_SKP; }
if (pulse & 4) AC = AC | df_da; /* DMAC */
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DFSE */
if ((df_sta & DFS_ERR) == 0) AC = AC | IOT_SKP;
}
if (pulse & 2) { /* DFSC */
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
else if (df_done) AC = AC | IOT_SKP;
}
if (pulse & 4) AC = AC | df_da; /* DMAC */
return AC;
}
/* Unit service
Note that for reads and writes, memory addresses wrap around in the
@@ -235,77 +244,85 @@ int32 pa, t, mex;
uint32 da;
int16 *fbuf = uptr->filebuf;
UPDATE_PCELL; /* update photocell */
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); }
UPDATE_PCELL; /* update photocell */
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);
}
mex = GET_MEX (df_sta);
da = GET_DEX (df_sta) | df_da; /* form disk addr */
do { if (da >= uptr->capac) { /* nx disk addr? */
df_sta = df_sta | DFS_NXD;
break; }
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) { /* read? */
if (MEM_ADDR_OK (pa)) M[pa] = fbuf[da]; } /* if !nxm, read wd */
else { /* write */
t = (da >> 14) & 07; /* check wr lock */
if ((df_wlk >> t) & 1) /* locked? set err */
df_sta = df_sta | DFS_WLS;
else { /* not locked */
fbuf[da] = M[pa]; /* write word */
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 */
da = GET_DEX (df_sta) | df_da; /* form disk addr */
do {
if (da >= uptr->capac) { /* nx disk addr? */
df_sta = df_sta | DFS_NXD;
break;
}
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) { /* read? */
if (MEM_ADDR_OK (pa)) M[pa] = fbuf[da]; /* if !nxm, read wd */
}
else { /* write */
t = (da >> 14) & 07; /* check wr lock */
if ((df_wlk >> t) & 1) /* locked? set err */
df_sta = df_sta | DFS_WLS;
else { /* not locked */
fbuf[da] = M[pa]; /* write word */
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) && ((df_sta & DFS_ERR) == 0)) /* more to do? */
sim_activate (&df_unit, df_time); /* sched next */
else { if (uptr->FUNC != DF_READ) da = (da - 1) & 0377777;
df_done = 1; /* done */
int_req = int_req | INT_DF; } /* update int req */
if ((M[DF_WC] != 0) && ((df_sta & DFS_ERR) == 0)) /* more to do? */
sim_activate (&df_unit, df_time); /* sched next */
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);
df_da = da & 07777; /* separate disk addr */
df_da = da & 07777; /* separate disk addr */
return SCPE_OK;
}
/* Reset routine */
t_stat df_reset (DEVICE *dptr)
{
df_sta = df_da = 0;
df_done = 1;
int_req = int_req & ~INT_DF; /* clear interrupt */
int_req = int_req & ~INT_DF; /* clear interrupt */
sim_cancel (&df_unit);
return SCPE_OK;
}
/* Bootstrap routine */
#define OS8_START 07750
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
#define DM4_START 00200
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
#define OS8_START 07750
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
#define DM4_START 00200
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
static const uint16 os8_rom[] = {
07600, /* 7750, CLA CLL ; also word count */
06603, /* 7751, DMAR ; also address */
06622, /* 7752, DFSC ; done? */
05352, /* 7753, JMP .-1 ; no */
05752 /* 7754, JMP @.-2 ; enter boot */
};
07600, /* 7750, CLA CLL ; also word count */
06603, /* 7751, DMAR ; also address */
06622, /* 7752, DFSC ; done? */
05352, /* 7753, JMP .-1 ; no */
05752 /* 7754, JMP @.-2 ; enter boot */
};
static const uint16 dm4_rom[] = {
00200, 07600, /* 0200, CLA CLL */
00201, 06603, /* 0201, DMAR ; read */
00202, 06622, /* 0202, DFSC ; done? */
00203, 05202, /* 0203, JMP .-1 ; no */
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
07750, 07576, /* 7750, 7576 ; word count */
07751, 07576 /* 7751, 7576 ; address */
};
00200, 07600, /* 0200, CLA CLL */
00201, 06603, /* 0201, DMAR ; read */
00202, 06622, /* 0202, DFSC ; done? */
00203, 05202, /* 0203, JMP .-1 ; no */
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
07750, 07576, /* 7750, 7576 ; word count */
07751, 07576 /* 7751, 7576 ; address */
};
t_stat df_boot (int32 unitno, DEVICE *dptr)
{
@@ -313,12 +330,15 @@ int32 i;
extern int32 sim_switches, saved_PC;
if (sim_switches & SWMASK ('D')) {
for (i = 0; i < DM4_LEN; i = i + 2)
M[dm4_rom[i]] = dm4_rom[i + 1];
saved_PC = DM4_START; }
else { for (i = 0; i < OS8_LEN; i++)
M[OS8_START + i] = os8_rom[i];
saved_PC = OS8_START; }
for (i = 0; i < DM4_LEN; i = i + 2)
M[dm4_rom[i]] = dm4_rom[i + 1];
saved_PC = DM4_START;
}
else {
for (i = 0; i < OS8_LEN; i++)
M[OS8_START + i] = os8_rom[i];
saved_PC = OS8_START;
}
return SCPE_OK;
}
@@ -333,10 +353,11 @@ t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) {
p = (sz + ds_bytes - 1) / ds_bytes;
if (p >= DF_NUMDK) p = DF_NUMDK - 1;
uptr->flags = (uptr->flags & ~UNIT_PLAT) |
(p << UNIT_V_PLAT); }
p = (sz + ds_bytes - 1) / ds_bytes;
if (p >= DF_NUMDK) p = DF_NUMDK - 1;
uptr->flags = (uptr->flags & ~UNIT_PLAT) |
(p << UNIT_V_PLAT);
}
uptr->capac = UNIT_GETP (uptr->flags) * DF_DKSIZE;
return SCPE_OK;
}

View File

@@ -1,7 +1,7 @@
To: Users
From: Bob Supnik
Subj: PDP-8 Simulator Usage
Date: 15-Feb-2005
Date: 01-Jul-2005
COPYRIGHT NOTICE
@@ -27,8 +27,8 @@ The following copyright notice applies to both the SIMH source and binary:
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This memorandum documents the PDP-8 simulator.
@@ -401,8 +401,7 @@ or a DETACH TTIX command.
The SHOW TTIX CONNECTIONS command displays the current connections to the
extra terminals. The SHOW TTIX STATISTICS command displays statistics for
active connections. The SET TTIX DISCONNECT=linenumber disconnects the
specified line.
active connections. The SET TTIXn DISCONNECT command disconnects line n.
The input device (TTIX) implements these registers:

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* pdp8_lp.c: PDP-8 line printer simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,23 +19,23 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
lpt LP8E line printer
lpt LP8E line printer
25-Apr-03 RMS Revised for extended file support
04-Oct-02 RMS Added DIB, enable/disable, device number support
30-May-02 RMS Widened POS to 32b
25-Apr-03 RMS Revised for extended file support
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 */
int32 lpt_err = 0; /* error flag */
int32 lpt_stopioe = 0; /* stop on error */
DEVICE lpt_dev;
int32 lpt (int32 IR, int32 AC);
@@ -46,88 +46,104 @@ t_stat lpt_detach (UNIT *uptr);
/* LPT data structures
lpt_dev LPT device descriptor
lpt_unit LPT unit descriptor
lpt_reg LPT register list
lpt_dev LPT device descriptor
lpt_unit LPT unit descriptor
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 };
UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
};
REG lpt_reg[] = {
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (ERR, lpt_err, 0) },
{ FLDATA (DONE, dev_done, INT_V_LPT) },
{ FLDATA (ENABLE, int_enable, INT_V_LPT) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), 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 } };
{ ORDATA (BUF, lpt_unit.buf, 8) },
{ FLDATA (ERR, lpt_err, 0) },
{ FLDATA (DONE, dev_done, INT_V_LPT) },
{ FLDATA (ENABLE, int_enable, INT_V_LPT) },
{ FLDATA (INT, int_req, INT_V_LPT) },
{ DRDATA (POS, lpt_unit.pos, T_ADDR_W), 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 } };
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 }
};
DEVICE lpt_dev = {
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, &lpt_detach,
&lpt_dib, DEV_DISABLE };
"LPT", &lpt_unit, lpt_reg, lpt_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lpt_reset,
NULL, &lpt_attach, &lpt_detach,
&lpt_dib, DEV_DISABLE
};
/* IOT routine */
int32 lpt (int32 IR, int32 AC)
{
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* PSKF */
return (dev_done & INT_LPT)? IOT_SKP + AC: AC;
case 2: /* PCLF */
dev_done = dev_done & ~INT_LPT; /* clear flag */
int_req = int_req & ~INT_LPT; /* clear int req */
return AC;
case 3: /* PSKE */
return (lpt_err)? IOT_SKP + AC: AC;
case 6: /* PCLF!PSTB */
dev_done = dev_done & ~INT_LPT; /* clear flag */
int_req = int_req & ~INT_LPT; /* clear int req */
case 4: /* PSTB */
lpt_unit.buf = AC & 0177; /* load buffer */
if ((lpt_unit.buf == 015) || (lpt_unit.buf == 014) ||
(lpt_unit.buf == 012)) {
sim_activate (&lpt_unit, lpt_unit.wait);
return AC; }
return (lpt_svc (&lpt_unit) << IOT_V_REASON) + AC;
case 5: /* PSIE */
int_enable = int_enable | INT_LPT; /* set enable */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 7: /* PCIE */
int_enable = int_enable & ~INT_LPT; /* clear enable */
int_req = int_req & ~INT_LPT; /* clear int req */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* PSKF */
return (dev_done & INT_LPT)? IOT_SKP + AC: AC;
case 2: /* PCLF */
dev_done = dev_done & ~INT_LPT; /* clear flag */
int_req = int_req & ~INT_LPT; /* clear int req */
return AC;
case 3: /* PSKE */
return (lpt_err)? IOT_SKP + AC: AC;
case 6: /* PCLF!PSTB */
dev_done = dev_done & ~INT_LPT; /* clear flag */
int_req = int_req & ~INT_LPT; /* clear int req */
case 4: /* PSTB */
lpt_unit.buf = AC & 0177; /* load buffer */
if ((lpt_unit.buf == 015) || (lpt_unit.buf == 014) ||
(lpt_unit.buf == 012)) {
sim_activate (&lpt_unit, lpt_unit.wait);
return AC;
}
return (lpt_svc (&lpt_unit) << IOT_V_REASON) + AC;
case 5: /* PSIE */
int_enable = int_enable | INT_LPT; /* set enable */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 7: /* PCIE */
int_enable = int_enable & ~INT_LPT; /* clear enable */
int_req = int_req & ~INT_LPT; /* clear int req */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
}
/* Unit service */
t_stat lpt_svc (UNIT *uptr)
{
dev_done = dev_done | INT_LPT; /* set done */
int_req = INT_UPDATE; /* update interrupts */
dev_done = dev_done | INT_LPT; /* set done */
int_req = INT_UPDATE; /* update interrupts */
if ((lpt_unit.flags & UNIT_ATT) == 0) {
lpt_err = 1;
return IORETURN (lpt_stopioe, SCPE_UNATT); }
lpt_err = 1;
return IORETURN (lpt_stopioe, SCPE_UNATT);
}
if (putc (lpt_unit.buf, lpt_unit.fileref) == EOF) {
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR; }
perror ("LPT I/O error");
clearerr (lpt_unit.fileref);
return SCPE_IOERR;
}
lpt_unit.pos = lpt_unit.pos + 1;
return SCPE_OK;
}
@@ -137,11 +153,11 @@ return SCPE_OK;
t_stat lpt_reset (DEVICE *dptr)
{
lpt_unit.buf = 0;
dev_done = dev_done & ~INT_LPT; /* clear done, int */
dev_done = dev_done & ~INT_LPT; /* clear done, int */
int_req = int_req & ~INT_LPT;
int_enable = int_enable | INT_LPT; /* set enable */
int_enable = int_enable | INT_LPT; /* set enable */
lpt_err = (lpt_unit.flags & UNIT_ATT) == 0;
sim_cancel (&lpt_unit); /* deactivate unit */
sim_cancel (&lpt_unit); /* deactivate unit */
return SCPE_OK;
}

View File

@@ -19,42 +19,43 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
mt TM8E/TU10 magtape
mt TM8E/TU10 magtape
18-Mar-05 RMS Added attached test to detach routine
25-Apr-03 RMS Revised for extended file support
29-Mar-03 RMS Added multiformat support
04-Mar-03 RMS Fixed bug in SKTR
01-Mar-03 RMS Fixed interrupt handling
Revised for magtape library
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
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Changed UST, POS, FLG to arrays
25-Apr-01 RMS Added device enable/disable support
04-Oct-98 RMS V2.4 magtape format
22-Jan-97 RMS V2.3 magtape format
01-Jan-96 RMS Rewritten from TM8-E Maintenance Manual
16-Aug-05 RMS Fixed C++ declaration and cast problems
18-Mar-05 RMS Added attached test to detach routine
25-Apr-03 RMS Revised for extended file support
29-Mar-03 RMS Added multiformat support
04-Mar-03 RMS Fixed bug in SKTR
01-Mar-03 RMS Fixed interrupt handling
Revised for magtape library
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
30-Nov-01 RMS Added read only unit, extended SET/SHOW support
24-Nov-01 RMS Changed UST, POS, FLG to arrays
25-Apr-01 RMS Added device enable/disable support
04-Oct-98 RMS V2.4 magtape format
22-Jan-97 RMS V2.3 magtape format
01-Jan-96 RMS Rewritten from TM8-E Maintenance Manual
Magnetic tapes are represented as a series of variable records
of the form:
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32b byte count
32b byte count
byte 0
byte 1
:
byte n-2
byte n-1
32b byte count
If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a byte count of 0.
@@ -63,85 +64,85 @@
#include "pdp8_defs.h"
#include "sim_tape.h"
#define MT_NUMDR 8 /* #drives */
#define USTAT u3 /* unit status */
#define MT_MAXFR (1 << 16) /* max record lnt */
#define WC_SIZE (1 << 12) /* max word count */
#define WC_MASK (WC_SIZE - 1)
#define MT_NUMDR 8 /* #drives */
#define USTAT u3 /* unit status */
#define MT_MAXFR (1 << 16) /* max record lnt */
#define WC_SIZE (1 << 12) /* max word count */
#define WC_MASK (WC_SIZE - 1)
/* Command/unit - mt_cu */
#define CU_V_UNIT 9 /* unit */
#define CU_M_UNIT 07
#define CU_PARITY 00400 /* parity select */
#define CU_IEE 00200 /* error int enable */
#define CU_IED 00100 /* done int enable */
#define CU_V_EMA 3 /* ext mem address */
#define CU_M_EMA 07
#define CU_EMA (CU_M_EMA << CU_V_EMA)
#define CU_DTY 00002 /* drive type */
#define CU_UNPAK 00001 /* 6b vs 8b mode */
#define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
#define GET_EMA(x) (((x) & CU_EMA) << (12 - CU_V_EMA))
#define CU_V_UNIT 9 /* unit */
#define CU_M_UNIT 07
#define CU_PARITY 00400 /* parity select */
#define CU_IEE 00200 /* error int enable */
#define CU_IED 00100 /* done int enable */
#define CU_V_EMA 3 /* ext mem address */
#define CU_M_EMA 07
#define CU_EMA (CU_M_EMA << CU_V_EMA)
#define CU_DTY 00002 /* drive type */
#define CU_UNPAK 00001 /* 6b vs 8b mode */
#define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
#define GET_EMA(x) (((x) & CU_EMA) << (12 - CU_V_EMA))
/* Function - mt_fn */
#define FN_V_FNC 9 /* function */
#define FN_M_FNC 07
#define FN_UNLOAD 00
#define FN_REWIND 01
#define FN_READ 02
#define FN_CMPARE 03
#define FN_WRITE 04
#define FN_WREOF 05
#define FN_SPACEF 06
#define FN_SPACER 07
#define FN_ERASE 00400 /* erase */
#define FN_CRC 00200 /* read CRC */
#define FN_GO 00100 /* go */
#define FN_INC 00040 /* incr mode */
#define FN_RMASK 07700 /* readable bits */
#define GET_FNC(x) (((x) >> FN_V_FNC) & FN_M_FNC)
#define FN_V_FNC 9 /* function */
#define FN_M_FNC 07
#define FN_UNLOAD 00
#define FN_REWIND 01
#define FN_READ 02
#define FN_CMPARE 03
#define FN_WRITE 04
#define FN_WREOF 05
#define FN_SPACEF 06
#define FN_SPACER 07
#define FN_ERASE 00400 /* erase */
#define FN_CRC 00200 /* read CRC */
#define FN_GO 00100 /* go */
#define FN_INC 00040 /* incr mode */
#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 */
#define STA_ERR (04000 << 12) /* error */
#define STA_REW (02000 << 12) /* *rewinding */
#define STA_BOT (01000 << 12) /* *start of tape */
#define STA_REM (00400 << 12) /* *offline */
#define STA_PAR (00200 << 12) /* parity error */
#define STA_EOF (00100 << 12) /* *end of file */
#define STA_RLE (00040 << 12) /* rec lnt error */
#define STA_DLT (00020 << 12) /* data late */
#define STA_EOT (00010 << 12) /* *end of tape */
#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 */
#define STA_LON 00001 /* long par error */
#define STA_ERR (04000 << 12) /* error */
#define STA_REW (02000 << 12) /* *rewinding */
#define STA_BOT (01000 << 12) /* *start of tape */
#define STA_REM (00400 << 12) /* *offline */
#define STA_PAR (00200 << 12) /* parity error */
#define STA_EOF (00100 << 12) /* *end of file */
#define STA_RLE (00040 << 12) /* rec lnt error */
#define STA_DLT (00020 << 12) /* data late */
#define STA_EOT (00010 << 12) /* *end of tape */
#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 */
#define STA_LON 00001 /* long par error */
#define STA_CLR (FN_RMASK | 00020) /* always clear */
#define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \
STA_EOT | STA_WLK) /* kept in USTAT */
#define STA_CLR (FN_RMASK | 00020) /* always clear */
#define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \
STA_EOT | STA_WLK) /* kept in USTAT */
extern uint16 M[];
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 */
int32 mt_wc = 0; /* word count */
int32 mt_sta = 0; /* status register */
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 */
uint8 *mtxb = NULL; /* transfer buffer */
int32 mt_cu = 0; /* command/unit */
int32 mt_fn = 0; /* function */
int32 mt_ca = 0; /* current address */
int32 mt_wc = 0; /* word count */
int32 mt_sta = 0; /* status register */
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 */
uint8 *mtxb = NULL; /* transfer buffer */
DEVICE mt_dev;
int32 mt70 (int32 IR, int32 AC);
@@ -160,58 +161,62 @@ void mt_set_done (void);
/* MT data structures
mt_dev MT device descriptor
mt_unit MT unit list
mt_reg MT register list
mt_mod MT modifier list
mt_dev MT device descriptor
mt_unit MT unit list
mt_reg MT register list
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) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } };
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
{ UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
};
REG mt_reg[] = {
{ ORDATA (CMD, mt_cu, 12) },
{ ORDATA (FNC, mt_fn, 12) },
{ ORDATA (CA, mt_ca, 12) },
{ ORDATA (WC, mt_wc, 12) },
{ ORDATA (DB, mt_db, 12) },
{ GRDATA (STA, mt_sta, 8, 12, 12) },
{ ORDATA (STA2, mt_sta, 6) },
{ FLDATA (DONE, mt_done, 0) },
{ FLDATA (INT, int_req, INT_V_MT) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ DRDATA (TIME, mt_time, 24), PV_LEFT },
{ URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO },
{ NULL } };
{ ORDATA (CMD, mt_cu, 12) },
{ ORDATA (FNC, mt_fn, 12) },
{ ORDATA (CA, mt_ca, 12) },
{ ORDATA (WC, mt_wc, 12) },
{ ORDATA (DB, mt_db, 12) },
{ GRDATA (STA, mt_sta, 8, 12, 12) },
{ ORDATA (STA2, mt_sta, 6) },
{ FLDATA (DONE, mt_done, 0) },
{ FLDATA (INT, int_req, INT_V_MT) },
{ FLDATA (STOP_IOE, mt_stopioe, 0) },
{ DRDATA (TIME, mt_time, 24), PV_LEFT },
{ URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) },
{ URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,
MT_NUMDR, PV_LEFT | REG_RO) },
{ FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO },
{ NULL }
};
MTAB mt_mod[] = {
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mt_vlock },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
{ MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock },
{ MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mt_vlock },
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
{ 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,
&mt_dib, DEV_DISABLE };
"MT", mt_unit, mt_reg, mt_mod,
MT_NUMDR, 10, 31, 1, 8, 8,
NULL, NULL, &mt_reset,
NULL, &mt_attach, &mt_detach,
&mt_dib, DEV_DISABLE
};
/* IOT routines */
int32 mt70 (int32 IR, int32 AC)
@@ -219,113 +224,141 @@ int32 mt70 (int32 IR, int32 AC)
int32 f;
UNIT *uptr;
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* LWCR */
mt_wc = AC; /* load word count */
return 0;
case 2: /* CWCR */
mt_wc = 0; /* clear word count */
return AC;
case 3: /* LCAR */
mt_ca = AC; /* load mem address */
return 0;
case 4: /* CCAR */
mt_ca = 0; /* clear mem address */
return AC;
case 5: /* LCMR */
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
mt_cu = AC; /* load command reg */
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
return 0;
case 6: /* LFGR */
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
mt_fn = AC; /* load function */
if ((mt_fn & FN_GO) == 0) { /* go set? */
mt_updcsta (uptr); /* update status */
return 0; }
f = GET_FNC (mt_fn); /* get function */
if (((uptr->flags & UNIT_ATT) == 0) ||
sim_is_active (uptr) ||
(((f == FN_WRITE) || (f == FN_WREOF)) && sim_tape_wrp (uptr))
|| (((f == FN_SPACER) || (f == FN_REWIND)) && sim_tape_bot (uptr))) {
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal op error */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return 0; }
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 */
mt_set_done (); } /* set done */
else if (f == FN_REWIND) { /* rewind */
uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */
mt_set_done (); } /* set done */
else mt_done = 0; /* clear done */
mt_updcsta (uptr); /* update status */
sim_activate (uptr, mt_time); /* start io */
return 0;
case 7: /* LDBR */
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
mt_db = AC; /* load buffer */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return 0; } /* end switch */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* LWCR */
mt_wc = AC; /* load word count */
return 0;
case 2: /* CWCR */
mt_wc = 0; /* clear word count */
return AC;
case 3: /* LCAR */
mt_ca = AC; /* load mem address */
return 0;
case 4: /* CCAR */
mt_ca = 0; /* clear mem address */
return AC;
case 5: /* LCMR */
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
mt_cu = AC; /* load command reg */
mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
return 0;
case 6: /* LFGR */
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
mt_fn = AC; /* load function */
if ((mt_fn & FN_GO) == 0) { /* go set? */
mt_updcsta (uptr); /* update status */
return 0;
}
f = GET_FNC (mt_fn); /* get function */
if (((uptr->flags & UNIT_ATT) == 0) ||
sim_is_active (uptr) ||
(((f == FN_WRITE) || (f == FN_WREOF)) && sim_tape_wrp (uptr))
|| (((f == FN_SPACER) || (f == FN_REWIND)) && sim_tape_bot (uptr))) {
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal op error */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return 0;
}
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 */
mt_set_done (); /* set done */
}
else if (f == FN_REWIND) { /* rewind */
uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */
mt_set_done (); /* set done */
}
else mt_done = 0; /* clear done */
mt_updcsta (uptr); /* update status */
sim_activate (uptr, mt_time); /* start io */
return 0;
case 7: /* LDBR */
if (mt_busy ()) mt_sta = mt_sta | STA_ILL | STA_ERR; /* busy? illegal op */
mt_db = AC; /* load buffer */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return 0;
} /* end switch */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
}
/* IOTs, continued */
int32 mt71 (int32 IR, int32 AC)
{
UNIT *uptr;
uptr = mt_dev.units + GET_UNIT (mt_cu);
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* RWCR */
return mt_wc; /* read word count */
case 2: /* CLT */
mt_reset (&mt_dev); /* reset everything */
return AC;
case 3: /* RCAR */
return mt_ca; /* read mem address */
case 4: /* RMSR */
return ((mt_updcsta (uptr) >> 12) & 07777); /* read status */
case 5: /* RCMR */
return mt_cu; /* read command */
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 */
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* RWCR */
return mt_wc; /* read word count */
case 2: /* CLT */
mt_reset (&mt_dev); /* reset everything */
return AC;
case 3: /* RCAR */
return mt_ca; /* read mem address */
case 4: /* RMSR */
return ((mt_updcsta (uptr) >> 12) & 07777); /* read status */
case 5: /* RCMR */
return mt_cu; /* read command */
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 */
}
int32 mt72 (int32 IR, int32 AC)
{
UNIT *uptr;
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* SKEF */
return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;
case 2: /* SKCB */
return (!mt_busy ())? IOT_SKP + AC: AC;
case 3: /* SKJD */
return mt_done? IOT_SKP + AC: AC;
case 4: /* SKTR */
return (!sim_is_active (uptr) &&
(uptr->flags & UNIT_ATT))? IOT_SKP + AC: AC;
case 5: /* CLF */
if (!sim_is_active (uptr)) mt_reset (&mt_dev); /* if TUR, zap */
else { /* just ctrl zap */
mt_sta = 0; /* clear status */
mt_done = 0; /* clear done */
mt_updcsta (uptr); } /* update status */
return AC; } /* end switch */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
switch (IR & 07) { /* decode IR<9:11> */
case 1: /* SKEF */
return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;
case 2: /* SKCB */
return (!mt_busy ())? IOT_SKP + AC: AC;
case 3: /* SKJD */
return mt_done? IOT_SKP + AC: AC;
case 4: /* SKTR */
return (!sim_is_active (uptr) &&
(uptr->flags & UNIT_ATT))? IOT_SKP + AC: AC;
case 5: /* CLF */
if (!sim_is_active (uptr)) mt_reset (&mt_dev); /* if TUR, zap */
else { /* just ctrl zap */
mt_sta = 0; /* clear status */
mt_done = 0; /* clear done */
mt_updcsta (uptr); /* update status */
}
return AC;
} /* end switch */
return (stop_inst << IOT_V_REASON) + AC; /* ill inst */
}
/* Unit service
If rewind done, reposition to start of tape, set status
@@ -339,107 +372,115 @@ t_mtrlnt tbc, cbc;
uint16 c, c1, c2;
t_stat st, r = SCPE_OK;
u = uptr - mt_dev.units; /* get unit number */
f = GET_FNC (mt_fn); /* get command */
xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */
wc = WC_SIZE - mt_wc; /* get wc */
u = (int32) (uptr - mt_dev.units); /* get unit number */
f = GET_FNC (mt_fn); /* get command */
xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */
wc = WC_SIZE - mt_wc; /* get wc */
if (uptr->USTAT & STA_REW) { /* rewind? */
sim_tape_rewind (uptr); /* 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->USTAT & STA_REW) { /* rewind? */
sim_tape_rewind (uptr); /* 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 */
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return IORETURN (mt_stopioe, SCPE_UNATT); }
if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */
uptr->USTAT = STA_REM; /* unit off line */
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return IORETURN (mt_stopioe, SCPE_UNATT);
}
switch (f) { /* case on function */
/* Unit service, continued */
switch (f) { /* case on function */
case FN_READ: /* read */
case FN_CMPARE: /* read/compare */
st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */
if (st == MTSE_RECE) mt_sta = mt_sta | STA_PAR | STA_ERR; /* rec in err? */
else if (st != MTSE_OK) { /* other error? */
r = mt_map_err (uptr, st); /* map error */
mt_sta = mt_sta | STA_RLE | STA_ERR; /* err, eof/eom, tmk */
break; }
cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */
if (tbc != cbc) mt_sta = mt_sta | STA_RLE | STA_ERR; /* wrong size? */
if (tbc < cbc) { /* record small? */
cbc = tbc; /* use smaller */
wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 1) / 2; }
for (i = p = 0; i < wc; i++) { /* copy buffer */
xma = mt_ixma (xma); /* increment xma */
mt_wc = (mt_wc + 1) & 07777; /* incr word cnt */
if (mt_cu & CU_UNPAK) c = mtxb[p++];
else {
c1 = mtxb[p++] & 077;
c2 = mtxb[p++] & 077;
c = (c1 << 6) | c2; }
if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
else if ((f == FN_CMPARE) && (M[xma] != c)) {
mt_sta = mt_sta | STA_CPE | STA_ERR;
break; } }
break;
case FN_READ: /* read */
case FN_CMPARE: /* read/compare */
st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */
if (st == MTSE_RECE) mt_sta = mt_sta | STA_PAR | STA_ERR; /* rec in err? */
else if (st != MTSE_OK) { /* other error? */
r = mt_map_err (uptr, st); /* map error */
mt_sta = mt_sta | STA_RLE | STA_ERR; /* err, eof/eom, tmk */
break;
}
cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */
if (tbc != cbc) mt_sta = mt_sta | STA_RLE | STA_ERR; /* wrong size? */
if (tbc < cbc) { /* record small? */
cbc = tbc; /* use smaller */
wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 1) / 2;
}
for (i = p = 0; i < wc; i++) { /* copy buffer */
xma = mt_ixma (xma); /* increment xma */
mt_wc = (mt_wc + 1) & 07777; /* incr word cnt */
if (mt_cu & CU_UNPAK) c = mtxb[p++];
else {
c1 = mtxb[p++] & 077;
c2 = mtxb[p++] & 077;
c = (c1 << 6) | c2;
}
if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
else if ((f == FN_CMPARE) && (M[xma] != c)) {
mt_sta = mt_sta | STA_CPE | STA_ERR;
break;
}
}
break;
case FN_WRITE: /* write */
tbc = (mt_cu & CU_UNPAK)? wc: wc * 2;
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
xma = mt_ixma (xma); /* incr mem addr */
if (mt_cu & CU_UNPAK) mtxb[p++] = M[xma] & 0377;
else {
mtxb[p++] = (M[xma] >> 6) & 077;
mtxb[p++] = M[xma] & 077; } }
if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */
r = mt_map_err (uptr, st); /* map error */
xma = GET_EMA (mt_cu) + mt_ca; } /* restore xma */
else mt_wc = 0; /* ok, clear wc */
break;
/* Unit service, continued */
case FN_WRITE: /* write */
tbc = (mt_cu & CU_UNPAK)? wc: wc * 2;
for (i = p = 0; i < wc; i++) { /* copy buf to tape */
xma = mt_ixma (xma); /* incr mem addr */
if (mt_cu & CU_UNPAK) mtxb[p++] = M[xma] & 0377;
else {
mtxb[p++] = (M[xma] >> 6) & 077;
mtxb[p++] = M[xma] & 077;
}
}
if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */
r = mt_map_err (uptr, st); /* map error */
xma = GET_EMA (mt_cu) + mt_ca; /* restore xma */
}
else mt_wc = 0; /* ok, clear wc */
break;
case FN_WREOF:
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = mt_map_err (uptr, st); /* map error */
break;
case FN_WREOF:
if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */
r = mt_map_err (uptr, st); /* map error */
break;
case FN_SPACEF: /* space forward */
do {
mt_wc = (mt_wc + 1) & 07777; /* incr wc */
if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
r = mt_map_err (uptr, st); /* map error */
break; } /* stop */
}
while (mt_wc != 0);
break;
case FN_SPACEF: /* space forward */
do {
mt_wc = (mt_wc + 1) & 07777; /* incr wc */
if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */
r = mt_map_err (uptr, st); /* map error */
break; /* stop */
}
} while (mt_wc != 0);
break;
case FN_SPACER: /* space reverse */
do {
mt_wc = (mt_wc + 1) & 07777; /* incr wc */
if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
r = mt_map_err (uptr, st); /* map error */
break; } /* stop */
}
while (mt_wc != 0);
break; } /* end case */
case FN_SPACER: /* space reverse */
do {
mt_wc = (mt_wc + 1) & 07777; /* incr wc */
if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */
r = mt_map_err (uptr, st); /* map error */
break; /* stop */
}
} while (mt_wc != 0);
break;
} /* end case */
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 */
mt_ca = xma & 07777; /* update mem addr */
mt_set_done (); /* set done */
mt_updcsta (uptr); /* update status */
return r;
}
/* Update controller status */
int32 mt_updcsta (UNIT *uptr)
@@ -458,23 +499,25 @@ UNIT *mt_busy (void)
int32 u;
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))
return 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))
return uptr;
}
return NULL;
}
/* Increment extended memory address */
int32 mt_ixma (int32 xma) /* incr extended ma */
int32 mt_ixma (int32 xma) /* incr extended ma */
{
int32 v;
v = ((xma + 1) & 07777) | (xma & 070000); /* wrapped incr */
if (mt_fn & FN_INC) { /* increment mode? */
if (xma == 077777) mt_sta = mt_sta | STA_INC | STA_ERR; /* at limit? error */
else v = xma + 1; } /* else 15b incr */
v = ((xma + 1) & 07777) | (xma & 070000); /* wrapped incr */
if (mt_fn & FN_INC) { /* increment mode? */
if (xma == 077777) mt_sta = mt_sta | STA_INC | STA_ERR; /* at limit? error */
else v = xma + 1; /* else 15b incr */
}
return v;
}
@@ -482,8 +525,8 @@ return v;
void mt_set_done (void)
{
mt_done = 1; /* set done */
mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */
mt_done = 1; /* set done */
mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */
return;
}
@@ -492,36 +535,45 @@ return;
t_stat mt_map_err (UNIT *uptr, t_stat st)
{
switch (st) {
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* unattached */
mt_sta = mt_sta | STA_ILL | STA_ERR;
case MTSE_OK: /* no error */
return SCPE_IERR; /* never get here! */
case MTSE_TMK: /* end of file */
uptr->USTAT = uptr->USTAT | STA_EOF; /* set EOF */
mt_sta = mt_sta | STA_ERR;
break;
case MTSE_IOERR: /* IO error */
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
if (mt_stopioe) return SCPE_IOERR;
break;
case MTSE_INVRL: /* invalid rec lnt */
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */
case MTSE_EOM: /* end of medium */
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
break;
case MTSE_BOT: /* reverse into BOT */
uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */
mt_sta = mt_sta | STA_ERR;
break;
case MTSE_WRP: /* write protect */
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
break; }
case MTSE_FMT: /* illegal fmt */
case MTSE_UNATT: /* unattached */
mt_sta = mt_sta | STA_ILL | STA_ERR;
case MTSE_OK: /* no error */
return SCPE_IERR; /* never get here! */
case MTSE_TMK: /* end of file */
uptr->USTAT = uptr->USTAT | STA_EOF; /* set EOF */
mt_sta = mt_sta | STA_ERR;
break;
case MTSE_IOERR: /* IO error */
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
if (mt_stopioe) return SCPE_IOERR;
break;
case MTSE_INVRL: /* invalid rec lnt */
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
return SCPE_MTRLNT;
case MTSE_RECE: /* record in error */
case MTSE_EOM: /* end of medium */
mt_sta = mt_sta | STA_PAR | STA_ERR; /* set par err */
break;
case MTSE_BOT: /* reverse into BOT */
uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */
mt_sta = mt_sta | STA_ERR;
break;
case MTSE_WRP: /* write protect */
mt_sta = mt_sta | STA_ILL | STA_ERR; /* illegal operation */
break;
}
return SCPE_OK;
}
/* Reset routine */
t_stat mt_reset (DEVICE *dptr)
@@ -530,16 +582,17 @@ int32 u;
UNIT *uptr;
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;
sim_cancel (uptr); /* cancel activity */
sim_tape_reset (uptr); /* reset tape */
if (uptr->flags & UNIT_ATT) uptr->USTAT =
(sim_tape_bot (uptr)? STA_BOT: 0) |
(sim_tape_wrp (uptr)? STA_WLK: 0);
else uptr->USTAT = STA_REM; }
if (mtxb == NULL) mtxb = calloc (MT_MAXFR, sizeof (uint8));
int_req = int_req & ~INT_MT; /* clear interrupt */
for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
uptr = mt_dev.units + u;
sim_cancel (uptr); /* cancel activity */
sim_tape_reset (uptr); /* reset tape */
if (uptr->flags & UNIT_ATT) uptr->USTAT =
(sim_tape_bot (uptr)? STA_BOT: 0) |
(sim_tape_wrp (uptr)? STA_WLK: 0);
else uptr->USTAT = STA_REM;
}
if (mtxb == NULL) mtxb = (uint8 *) calloc (MT_MAXFR, sizeof (uint8));
if (mtxb == NULL) return SCPE_MEM;
return SCPE_OK;
}
@@ -549,7 +602,7 @@ return SCPE_OK;
t_stat mt_attach (UNIT *uptr, char *cptr)
{
t_stat r;
int32 u = uptr - mt_dev.units; /* get unit number */
int32 u = uptr - mt_dev.units; /* get unit number */
r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK) return r;
@@ -562,9 +615,9 @@ return r;
t_stat mt_detach (UNIT* uptr)
{
int32 u = uptr - mt_dev.units; /* get unit number */
int32 u = uptr - mt_dev.units; /* get unit number */
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check for attached */
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check for attached */
if (!sim_is_active (uptr)) uptr->USTAT = STA_REM;
if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr);
return sim_tape_detach (uptr);
@@ -574,10 +627,10 @@ return sim_tape_detach (uptr);
t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 u = uptr - mt_dev.units; /* get unit number */
int32 u = uptr - mt_dev.units; /* get unit number */
if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
uptr->USTAT = uptr->USTAT | STA_WLK;
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;

View File

@@ -1,6 +1,6 @@
/* pdp8_pt.c: PDP-8 paper tape reader/punch simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,24 +19,24 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ptr,ptp PC8E paper tape reader/punch
ptr,ptp PC8E paper tape reader/punch
25-Apr-03 RMS Revised for extended file support
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
25-Apr-03 RMS Revised for extended file support
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
*/
#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_stopioe = 0, ptp_stopioe = 0; /* stop on error */
int32 ptr (int32 IR, int32 AC);
int32 ptp (int32 IR, int32 AC);
@@ -45,98 +45,111 @@ t_stat ptp_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);
/* PTR data structures
ptr_dev PTR device descriptor
ptr_unit PTR unit descriptor
ptr_reg PTR register list
ptr_dev PTR device descriptor
ptr_unit PTR unit descriptor
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 };
UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
SERIAL_IN_WAIT
};
REG ptr_reg[] = {
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_PTR) },
{ FLDATA (ENABLE, int_enable, INT_V_PTR) },
{ FLDATA (INT, int_req, INT_V_PTR) },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ NULL } };
{ ORDATA (BUF, ptr_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_PTR) },
{ FLDATA (ENABLE, int_enable, INT_V_PTR) },
{ FLDATA (INT, int_req, INT_V_PTR) },
{ DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptr_stopioe, 0) },
{ NULL }
};
MTAB ptr_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
{ 0 } };
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
{ 0 }
};
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, ptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, NULL, NULL,
&ptr_dib, 0 };
"PTR", &ptr_unit, ptr_reg, ptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
&ptr_boot, NULL, NULL,
&ptr_dib, 0 };
/* PTP data structures
ptp_dev PTP device descriptor
ptp_unit PTP unit descriptor
ptp_reg PTP register list
ptp_dev PTP device descriptor
ptp_unit PTP unit descriptor
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 };
UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
};
REG ptp_reg[] = {
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_PTP) },
{ FLDATA (ENABLE, int_enable, INT_V_PTP) },
{ FLDATA (INT, int_req, INT_V_PTP) },
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ NULL } };
{ ORDATA (BUF, ptp_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_PTP) },
{ FLDATA (ENABLE, int_enable, INT_V_PTP) },
{ FLDATA (INT, int_req, INT_V_PTP) },
{ DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, ptp_stopioe, 0) },
{ NULL }
};
MTAB ptp_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
{ 0 } };
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
{ 0 }
};
DEVICE ptp_dev = {
"PTP", &ptp_unit, ptp_reg, ptp_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL,
&ptp_dib, 0 };
"PTP", &ptp_unit, ptp_reg, ptp_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL,
&ptp_dib, 0
};
/* Paper tape reader: IOT routine */
int32 ptr (int32 IR, int32 AC)
{
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 */
return AC;
case 1: /* RSF */
return (dev_done & INT_PTR)? IOT_SKP + AC: AC;
case 6: /* RFC!RRB */
sim_activate (&ptr_unit, ptr_unit.wait);
case 2: /* RRB */
dev_done = dev_done & ~INT_PTR; /* clear flag */
int_req = int_req & ~INT_PTR; /* clear int req */
return (AC | ptr_unit.buf); /* or data to AC */
case 4: /* RFC */
sim_activate (&ptr_unit, ptr_unit.wait);
dev_done = dev_done & ~INT_PTR; /* clear flag */
int_req = int_req & ~INT_PTR; /* clear int req */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
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 */
return AC;
case 1: /* RSF */
return (dev_done & INT_PTR)? IOT_SKP + AC: AC;
case 6: /* RFC!RRB */
sim_activate (&ptr_unit, ptr_unit.wait);
case 2: /* RRB */
dev_done = dev_done & ~INT_PTR; /* clear flag */
int_req = int_req & ~INT_PTR; /* clear int req */
return (AC | ptr_unit.buf); /* or data to AC */
case 4: /* RFC */
sim_activate (&ptr_unit, ptr_unit.wait);
dev_done = dev_done & ~INT_PTR; /* clear flag */
int_req = int_req & ~INT_PTR; /* clear int req */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
}
/* Unit service */
@@ -145,17 +158,19 @@ t_stat ptr_svc (UNIT *uptr)
{
int32 temp;
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) {
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK; }
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR; }
dev_done = dev_done | INT_PTR; /* set done */
int_req = INT_UPDATE; /* update interrupts */
if (feof (ptr_unit.fileref)) {
if (ptr_stopioe) printf ("PTR end of file\n");
else return SCPE_OK;
}
else perror ("PTR I/O error");
clearerr (ptr_unit.fileref);
return SCPE_IOERR;
}
dev_done = dev_done | INT_PTR; /* set done */
int_req = INT_UPDATE; /* update interrupts */
ptr_unit.buf = temp & 0377;
ptr_unit.pos = ptr_unit.pos + 1;
return SCPE_OK;
@@ -166,51 +181,58 @@ return SCPE_OK;
t_stat ptr_reset (DEVICE *dptr)
{
ptr_unit.buf = 0;
dev_done = dev_done & ~INT_PTR; /* clear done, int */
dev_done = dev_done & ~INT_PTR; /* clear done, int */
int_req = int_req & ~INT_PTR;
int_enable = int_enable | INT_PTR; /* set enable */
sim_cancel (&ptr_unit); /* deactivate unit */
int_enable = int_enable | INT_PTR; /* set enable */
sim_cancel (&ptr_unit); /* deactivate unit */
return SCPE_OK;
}
/* Paper tape punch: IOT routine */
int32 ptp (int32 IR, int32 AC)
{
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 */
return AC;
case 1: /* PSF */
return (dev_done & INT_PTP)? IOT_SKP + AC: AC;
case 2: /* PCF */
dev_done = dev_done & ~INT_PTP; /* clear flag */
int_req = int_req & ~INT_PTP; /* clear int req */
return AC;
case 6: /* PLS */
dev_done = dev_done & ~INT_PTP; /* clear flag */
int_req = int_req & ~INT_PTP; /* clear int req */
case 4: /* PPC */
ptp_unit.buf = AC & 0377; /* load punch buf */
sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
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 */
return AC;
case 1: /* PSF */
return (dev_done & INT_PTP)? IOT_SKP + AC: AC;
case 2: /* PCF */
dev_done = dev_done & ~INT_PTP; /* clear flag */
int_req = int_req & ~INT_PTP; /* clear int req */
return AC;
case 6: /* PLS */
dev_done = dev_done & ~INT_PTP; /* clear flag */
int_req = int_req & ~INT_PTP; /* clear int req */
case 4: /* PPC */
ptp_unit.buf = AC & 0377; /* load punch buf */
sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
}
/* Unit service */
t_stat ptp_svc (UNIT *uptr)
{
dev_done = dev_done | INT_PTP; /* set done */
int_req = INT_UPDATE; /* update interrupts */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
dev_done = dev_done | INT_PTP; /* set done */
int_req = INT_UPDATE; /* update interrupts */
if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */
return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) {
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
return SCPE_IOERR; }
perror ("PTP I/O error");
clearerr (ptp_unit.fileref);
return SCPE_IOERR;
}
ptp_unit.pos = ptp_unit.pos + 1;
return SCPE_OK;
}
@@ -220,10 +242,10 @@ return SCPE_OK;
t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
dev_done = dev_done & ~INT_PTP; /* clear done, int */
dev_done = dev_done & ~INT_PTP; /* clear done, int */
int_req = int_req & ~INT_PTP;
int_enable = int_enable | INT_PTP; /* set enable */
sim_cancel (&ptp_unit); /* deactivate unit */
int_enable = int_enable | INT_PTP; /* set enable */
sim_cancel (&ptp_unit); /* deactivate unit */
return SCPE_OK;
}
@@ -233,25 +255,25 @@ return SCPE_OK;
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
static const uint16 boot_rom[] = {
06014, /* 7756, RFC */
06011, /* 7757, LOOP, RSF */
05357, /* JMP .-1 */
06016, /* RFC RRB */
07106, /* CLL RTL*/
07006, /* RTL */
07510, /* SPA*/
05374, /* JMP 7774 */
07006, /* RTL */
06011, /* RSF */
05367, /* JMP .-1 */
06016, /* RFC RRB */
07420, /* SNL */
03776, /* DCA I 7776 */
03376, /* 7774, DCA 7776 */
05357, /* JMP 7757 */
00000, /* 7776, 0 */
05301 /* 7777, JMP 7701 */
};
06014, /* 7756, RFC */
06011, /* 7757, LOOP, RSF */
05357, /* JMP .-1 */
06016, /* RFC RRB */
07106, /* CLL RTL*/
07006, /* RTL */
07510, /* SPA*/
05374, /* JMP 7774 */
07006, /* RTL */
06011, /* RSF */
05367, /* JMP .-1 */
06016, /* RFC RRB */
07420, /* SNL */
03776, /* DCA I 7776 */
03376, /* 7774, DCA 7776 */
05357, /* JMP 7757 */
00000, /* 7776, 0 */
05301 /* 7777, JMP 7701 */
};
t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
@@ -259,7 +281,7 @@ int32 i;
extern int32 saved_PC;
extern uint16 M[];
if (ptr_dib.dev != DEV_PTR) return STOP_NOTSTD; /* only std devno */
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;

View File

@@ -1,6 +1,6 @@
/* pdp8_rf.c: RF08 fixed head disk simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,99 +19,99 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rf RF08 fixed head disk
rf RF08 fixed head disk
04-Jan-04 RMS Changed sim_fsize calling sequence
26-Oct-03 RMS Cleaned up buffer copy code
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing 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
15-Feb-01 RMS Fixed 3 cycle data break sequence
14-Apr-99 RMS Changed t_addr to unsigned
30-Mar-98 RMS Fixed bug in RF bootstrap
04-Jan-04 RMS Changed sim_fsize calling sequence
26-Oct-03 RMS Cleaned up buffer copy code
26-Jul-03 RMS Fixed bug in set size routine
14-Mar-03 RMS Fixed variable platter interaction with save/restore
03-Mar-03 RMS Fixed autosizing
02-Feb-03 RMS Added variable platter and autosizing 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
15-Feb-01 RMS Fixed 3 cycle data break sequence
14-Apr-99 RMS Changed t_addr to unsigned
30-Mar-98 RMS Fixed bug in RF bootstrap
The RF08 is a head-per-track disk. It uses the three cycle data break
facility. To minimize overhead, the entire RF08 is buffered in memory.
Two timing parameters are provided:
rf_time Interword timing, must be non-zero
rf_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst
rf_time Interword timing, must be non-zero
rf_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
DMA occurs in a burst
*/
#include "pdp8_defs.h"
#include <math.h>
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
#define UNIT_M_PLAT 03
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
#define UNIT_M_PLAT 03
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
/* Constants */
#define RF_NUMWD 2048 /* words/track */
#define RF_NUMTR 128 /* tracks/disk */
#define RF_DKSIZE (RF_NUMTR * RF_NUMWD) /* words/disk */
#define RF_NUMDK 4 /* disks/controller */
#define RF_WC 07750 /* word count */
#define RF_MA 07751 /* mem address */
#define RF_WMASK (RF_NUMWD - 1) /* word mask */
#define RF_NUMWD 2048 /* words/track */
#define RF_NUMTR 128 /* tracks/disk */
#define RF_DKSIZE (RF_NUMTR * RF_NUMWD) /* words/disk */
#define RF_NUMDK 4 /* disks/controller */
#define RF_WC 07750 /* word count */
#define RF_MA 07751 /* mem address */
#define RF_WMASK (RF_NUMWD - 1) /* word mask */
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
#define RF_READ 2 /* read */
#define RF_WRITE 4 /* write */
#define FUNC u4 /* function */
#define RF_READ 2 /* read */
#define RF_WRITE 4 /* write */
/* Status register */
#define RFS_PCA 04000 /* photocell status */
#define RFS_DRE 02000 /* data req enable */
#define RFS_WLS 01000 /* write lock status */
#define RFS_EIE 00400 /* error int enable */
#define RFS_PIE 00200 /* photocell int enb */
#define RFS_CIE 00100 /* done int enable */
#define RFS_MEX 00070 /* memory extension */
#define RFS_DRL 00004 /* data late error */
#define RFS_NXD 00002 /* non-existent disk */
#define RFS_PER 00001 /* parity error */
#define RFS_ERR (RFS_WLS + RFS_DRL + RFS_NXD + RFS_PER)
#define RFS_V_MEX 3
#define RFS_PCA 04000 /* photocell status */
#define RFS_DRE 02000 /* data req enable */
#define RFS_WLS 01000 /* write lock status */
#define RFS_EIE 00400 /* error int enable */
#define RFS_PIE 00200 /* photocell int enb */
#define RFS_CIE 00100 /* done int enable */
#define RFS_MEX 00070 /* memory extension */
#define RFS_DRL 00004 /* data late error */
#define RFS_NXD 00002 /* non-existent disk */
#define RFS_PER 00001 /* parity error */
#define RFS_ERR (RFS_WLS + RFS_DRL + RFS_NXD + RFS_PER)
#define RFS_V_MEX 3
#define GET_MEX(x) (((x) & RFS_MEX) << (12 - RFS_V_MEX))
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) RF_NUMWD)))
#define UPDATE_PCELL if (GET_POS(rf_time) < 6) rf_sta = rf_sta | RFS_PCA; \
else rf_sta = rf_sta & ~RFS_PCA
#define RF_INT_UPDATE if ((rf_done && (rf_sta & RFS_CIE)) || \
((rf_sta & RFS_ERR) && (rf_sta & RFS_EIE)) || \
((rf_sta & RFS_PCA) && (rf_sta & RFS_PIE))) \
int_req = int_req | INT_RF; \
else int_req = int_req & ~INT_RF
#define GET_MEX(x) (((x) & RFS_MEX) << (12 - RFS_V_MEX))
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) RF_NUMWD)))
#define UPDATE_PCELL if (GET_POS(rf_time) < 6) rf_sta = rf_sta | RFS_PCA; \
else rf_sta = rf_sta & ~RFS_PCA
#define RF_INT_UPDATE if ((rf_done && (rf_sta & RFS_CIE)) || \
((rf_sta & RFS_ERR) && (rf_sta & RFS_EIE)) || \
((rf_sta & RFS_PCA) && (rf_sta & RFS_PIE))) \
int_req = int_req | INT_RF; \
else int_req = int_req & ~INT_RF
extern uint16 M[];
extern int32 int_req, stop_inst;
extern UNIT cpu_unit;
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
int32 rf_done = 0; /* done flag */
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 */
int32 rf_sta = 0; /* status register */
int32 rf_da = 0; /* disk address */
int32 rf_done = 0; /* done flag */
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);
@@ -127,52 +127,56 @@ t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
/* RF08 data structures
rf_dev RF device descriptor
rf_unit RF unit descriptor
pcell_unit photocell timing unit (orphan)
rf_reg RF register list
rf_dev RF device descriptor
rf_unit RF unit descriptor
pcell_unit photocell timing unit (orphan)
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_DKSIZE) };
UNIT rf_unit = {
UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+
UNIT_BUFABLE+UNIT_MUSTBUF, RF_DKSIZE)
};
UNIT pcell_unit = { UDATA (&pcell_svc, 0, 0) };
REG rf_reg[] = {
{ ORDATA (STA, rf_sta, 12) },
{ ORDATA (DA, rf_da, 20) },
{ ORDATA (WC, M[RF_WC], 12) },
{ ORDATA (MA, M[RF_MA], 12) },
{ FLDATA (DONE, rf_done, 0) },
{ FLDATA (INT, int_req, INT_V_RF) },
{ ORDATA (WLK, rf_wlk, 32) },
{ DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ DRDATA (CAPAC, rf_unit.capac, 21), REG_HRO },
{ ORDATA (DEVNUM, rf_dib.dev, 6), REG_HRO },
{ NULL } };
{ ORDATA (STA, rf_sta, 12) },
{ ORDATA (DA, rf_da, 20) },
{ ORDATA (WC, M[RF_WC], 12) },
{ ORDATA (MA, M[RF_MA], 12) },
{ FLDATA (DONE, rf_done, 0) },
{ FLDATA (INT, int_req, INT_V_RF) },
{ ORDATA (WLK, rf_wlk, 32) },
{ DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (BURST, rf_burst, 0) },
{ FLDATA (STOP_IOE, rf_stopioe, 0) },
{ DRDATA (CAPAC, rf_unit.capac, 21), REG_HRO },
{ ORDATA (DEVNUM, rf_dib.dev, 6), REG_HRO },
{ NULL }
};
MTAB rf_mod[] = {
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ 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, &rf_attach, NULL,
&rf_dib, DEV_DISABLE | DEV_DIS };
"RF", &rf_unit, rf_reg, rf_mod,
1, 8, 20, 1, 8, 12,
NULL, NULL, &rf_reset,
&rf_boot, &rf_attach, NULL,
&rf_dib, DEV_DISABLE | DEV_DIS
};
/* IOT routines */
int32 rf60 (int32 IR, int32 AC)
@@ -180,19 +184,21 @@ int32 rf60 (int32 IR, int32 AC)
int32 t;
int32 pulse = IR & 07;
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DCMA */
rf_da = rf_da & ~07777; /* clear DAR<8:19> */
rf_done = 0; /* clear done */
rf_sta = rf_sta & ~RFS_ERR; /* clear errors */
RF_INT_UPDATE; } /* update int req */
if (pulse & 6) { /* DMAR, DMAW */
rf_da = rf_da | AC; /* DAR<8:19> |= AC */
rf_unit.FUNC = pulse & ~1; /* save function */
t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new loc */
if (t < 0) t = t + RF_NUMWD; /* wrap around? */
sim_activate (&rf_unit, t * rf_time); /* schedule op */
AC = 0; } /* clear AC */
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DCMA */
rf_da = rf_da & ~07777; /* clear DAR<8:19> */
rf_done = 0; /* clear done */
rf_sta = rf_sta & ~RFS_ERR; /* clear errors */
RF_INT_UPDATE; /* update int req */
}
if (pulse & 6) { /* DMAR, DMAW */
rf_da = rf_da | AC; /* DAR<8:19> |= AC */
rf_unit.FUNC = pulse & ~1; /* save function */
t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new loc */
if (t < 0) t = t + RF_NUMWD; /* wrap around? */
sim_activate (&rf_unit, t * rf_time); /* schedule op */
AC = 0; /* clear AC */
}
return AC;
}
@@ -200,41 +206,47 @@ int32 rf61 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;
UPDATE_PCELL; /* update photocell */
switch (pulse) { /* decode IR<9:11> */
case 1: /* DCIM */
rf_sta = rf_sta & 07007; /* clear STA<3:8> */
int_req = int_req & ~INT_RF; /* clear int req */
sim_cancel (&pcell_unit); /* cancel photocell */
return AC;
case 2: /* DSAC */
return ((rf_da & RF_WMASK) == GET_POS (rf_time))? IOT_SKP: 0;
case 5: /* DIML */
rf_sta = (rf_sta & 07007) | (AC & 0770); /* STA<3:8> <- AC */
if (rf_sta & RFS_PIE) /* photocell int? */
sim_activate (&pcell_unit, (RF_NUMWD - GET_POS (rf_time)) *
rf_time);
else sim_cancel (&pcell_unit);
RF_INT_UPDATE; /* update int req */
return 0; /* clear AC */
case 6: /* DIMA */
return rf_sta; } /* AC <- STA<0:11> */
UPDATE_PCELL; /* update photocell */
switch (pulse) { /* decode IR<9:11> */
case 1: /* DCIM */
rf_sta = rf_sta & 07007; /* clear STA<3:8> */
int_req = int_req & ~INT_RF; /* clear int req */
sim_cancel (&pcell_unit); /* cancel photocell */
return AC;
case 2: /* DSAC */
return ((rf_da & RF_WMASK) == GET_POS (rf_time))? IOT_SKP: 0;
case 5: /* DIML */
rf_sta = (rf_sta & 07007) | (AC & 0770); /* STA<3:8> <- AC */
if (rf_sta & RFS_PIE) /* photocell int? */
sim_activate (&pcell_unit, (RF_NUMWD - GET_POS (rf_time)) *
rf_time);
else sim_cancel (&pcell_unit);
RF_INT_UPDATE; /* update int req */
return 0; /* clear AC */
case 6: /* DIMA */
return rf_sta; /* AC <- STA<0:11> */
}
return AC;
}
/* IOT's, continued */
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; }
if (pulse & 2) { /* DFSC */
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
else if (rf_done) AC = AC | IOT_SKP; }
if (pulse & 4) AC = AC | (rf_da & 07777); /* DMAC */
UPDATE_PCELL; /* update photocell */
if (pulse & 1) { /* DFSE */
if (rf_sta & RFS_ERR) AC = AC | IOT_SKP;
}
if (pulse & 2) { /* DFSC */
if (pulse & 4) AC = AC & ~07777; /* for DMAC */
else if (rf_done) AC = AC | IOT_SKP;
}
if (pulse & 4) AC = AC | (rf_da & 07777); /* DMAC */
return AC;
}
@@ -242,31 +254,37 @@ int32 rf64 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;
UPDATE_PCELL; /* update photocell */
switch (pulse) { /* decode IR<9:11> */
case 1: /* DCXA */
rf_da = rf_da & 07777; /* clear DAR<0:7> */
break;
case 3: /* DXAL */
rf_da = rf_da & 07777; /* clear DAR<0:7> */
case 2: /* DXAL w/o clear */
rf_da = rf_da | ((AC & 0377) << 12); /* DAR<0:7> |= AC */
AC = AC & ~07777; /* clear AC */
break;
case 5: /* DXAC */
AC = AC & ~07777; /* clear AC */
case 4: /* DXAC w/o clear */
AC = AC | ((rf_da >> 12) & 0377); /* AC |= DAR<0:7> */
break;
default:
AC = (stop_inst << IOT_V_REASON) + AC;
break; } /* end switch */
UPDATE_PCELL; /* update photocell */
switch (pulse) { /* decode IR<9:11> */
case 1: /* DCXA */
rf_da = rf_da & 07777; /* clear DAR<0:7> */
break;
case 3: /* DXAL */
rf_da = rf_da & 07777; /* clear DAR<0:7> */
case 2: /* DXAL w/o clear */
rf_da = rf_da | ((AC & 0377) << 12); /* DAR<0:7> |= AC */
AC = 0; /* clear AC */
break;
case 5: /* DXAC */
AC = 0; /* clear AC */
case 4: /* DXAC w/o clear */
AC = AC | ((rf_da >> 12) & 0377); /* AC |= DAR<0:7> */
break;
default:
AC = (stop_inst << IOT_V_REASON) + AC;
break;
} /* end switch */
if ((uint32) rf_da >= rf_unit.capac) rf_sta = rf_sta | RFS_NXD;
else rf_sta = rf_sta & ~RFS_NXD;
RF_INT_UPDATE;
return AC;
}
/* Unit service
Note that for reads and writes, memory addresses wrap around in the
@@ -278,37 +296,45 @@ t_stat rf_svc (UNIT *uptr)
int32 pa, t, mex;
int16 *fbuf = uptr->filebuf;
UPDATE_PCELL; /* update photocell */
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
rf_sta = rf_sta | RFS_NXD;
rf_done = 1;
RF_INT_UPDATE; /* update int req */
return IORETURN (rf_stopioe, SCPE_UNATT); }
UPDATE_PCELL; /* update photocell */
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
rf_sta = rf_sta | RFS_NXD;
rf_done = 1;
RF_INT_UPDATE; /* update int req */
return IORETURN (rf_stopioe, SCPE_UNATT);
}
mex = GET_MEX (rf_sta);
do { if ((uint32) rf_da >= rf_unit.capac) { /* disk overflow? */
rf_sta = rf_sta | RFS_NXD;
break; }
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) { /* read? */
if (MEM_ADDR_OK (pa)) /* if !nxm */
M[pa] = fbuf[rf_da]; } /* read word */
else { /* write */
t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
if ((rf_wlk >> t) & 1) /* write locked? */
rf_sta = rf_sta | RFS_WLS;
else { /* not locked */
fbuf[rf_da] = M[pa]; /* write word */
if (((uint32) 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 */
do {
if ((uint32) rf_da >= rf_unit.capac) { /* disk overflow? */
rf_sta = rf_sta | RFS_NXD;
break;
}
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) { /* read? */
if (MEM_ADDR_OK (pa)) /* if !nxm */
M[pa] = fbuf[rf_da]; /* read word */
}
else { /* write */
t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
if ((rf_wlk >> t) & 1) /* write locked? */
rf_sta = rf_sta | RFS_WLS;
else { /* not locked */
fbuf[rf_da] = M[pa]; /* write word */
if (((uint32) 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 */
if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
sim_activate (&rf_unit, rf_time); /* sched next */
else { rf_done = 1; /* done */
RF_INT_UPDATE; } /* update int req */
if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
sim_activate (&rf_unit, rf_time); /* sched next */
else {
rf_done = 1; /* done */
RF_INT_UPDATE; /* update int req */
}
return SCPE_OK;
}
@@ -316,20 +342,21 @@ return SCPE_OK;
t_stat pcell_svc (UNIT *uptr)
{
rf_sta = rf_sta | RFS_PCA; /* set photocell */
if (rf_sta & RFS_PIE) { /* int enable? */
sim_activate (&pcell_unit, RF_NUMWD * rf_time);
int_req = int_req | INT_RF; }
rf_sta = rf_sta | RFS_PCA; /* set photocell */
if (rf_sta & RFS_PIE) { /* int enable? */
sim_activate (&pcell_unit, RF_NUMWD * rf_time);
int_req = int_req | INT_RF;
}
return SCPE_OK;
}
/* Reset routine */
t_stat rf_reset (DEVICE *dptr)
{
rf_sta = rf_da = 0;
rf_done = 1;
int_req = int_req & ~INT_RF; /* clear interrupt */
int_req = int_req & ~INT_RF; /* clear interrupt */
sim_cancel (&rf_unit);
sim_cancel (&pcell_unit);
return SCPE_OK;
@@ -337,42 +364,45 @@ return SCPE_OK;
/* Bootstrap routine */
#define OS8_START 07750
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
#define DM4_START 00200
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
#define OS8_START 07750
#define OS8_LEN (sizeof (os8_rom) / sizeof (int16))
#define DM4_START 00200
#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16))
static const uint16 os8_rom[] = {
07600, /* 7750, CLA CLL ; also word count */
06603, /* 7751, DMAR ; also address */
06622, /* 7752, DFSC ; done? */
05352, /* 7753, JMP .-1 ; no */
05752 /* 7754, JMP @.-2 ; enter boot */
};
07600, /* 7750, CLA CLL ; also word count */
06603, /* 7751, DMAR ; also address */
06622, /* 7752, DFSC ; done? */
05352, /* 7753, JMP .-1 ; no */
05752 /* 7754, JMP @.-2 ; enter boot */
};
static const uint16 dm4_rom[] = {
00200, 07600, /* 0200, CLA CLL */
00201, 06603, /* 0201, DMAR ; read */
00202, 06622, /* 0202, DFSC ; done? */
00203, 05202, /* 0203, JMP .-1 ; no */
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
07750, 07576, /* 7750, 7576 ; word count */
07751, 07576 /* 7751, 7576 ; address */
};
00200, 07600, /* 0200, CLA CLL */
00201, 06603, /* 0201, DMAR ; read */
00202, 06622, /* 0202, DFSC ; done? */
00203, 05202, /* 0203, JMP .-1 ; no */
00204, 05600, /* 0204, JMP @.-4 ; enter boot */
07750, 07576, /* 7750, 7576 ; word count */
07751, 07576 /* 7751, 7576 ; address */
};
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 (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];
saved_PC = DM4_START; }
else { for (i = 0; i < OS8_LEN; i++)
M[OS8_START + i] = os8_rom[i];
saved_PC = OS8_START; }
for (i = 0; i < DM4_LEN; i = i + 2)
M[dm4_rom[i]] = dm4_rom[i + 1];
saved_PC = DM4_START;
}
else {
for (i = 0; i < OS8_LEN; i++)
M[OS8_START + i] = os8_rom[i];
saved_PC = OS8_START;
}
return SCPE_OK;
}
@@ -387,10 +417,11 @@ t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK) return r;
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize (uptr->fileref))) {
p = (sz + ds_bytes - 1) / ds_bytes;
if (p >= RF_NUMDK) p = RF_NUMDK - 1;
uptr->flags = (uptr->flags & ~UNIT_PLAT) |
(p << UNIT_V_PLAT); }
p = (sz + ds_bytes - 1) / ds_bytes;
if (p >= RF_NUMDK) p = RF_NUMDK - 1;
uptr->flags = (uptr->flags & ~UNIT_PLAT) |
(p << UNIT_V_PLAT);
}
uptr->capac = UNIT_GETP (uptr->flags) * RF_DKSIZE;
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp8_rk.c: RK8E cartridge disk simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,121 +19,121 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rk RK8E/RK05 cartridge disk
rk RK8E/RK05 cartridge disk
25-Apr-03 RMS Revised for extended file support
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
25-Apr-01 RMS Added device enable/disable support
29-Jun-96 RMS Added unit enable/disable support
25-Apr-03 RMS Revised for extended file support
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
25-Apr-01 RMS Added device enable/disable support
29-Jun-96 RMS Added unit enable/disable support
*/
#include "pdp8_defs.h"
/* Constants */
#define RK_NUMSC 16 /* sectors/surface */
#define RK_NUMSF 2 /* surfaces/cylinder */
#define RK_NUMCY 203 /* cylinders/drive */
#define RK_NUMWD 256 /* words/sector */
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */
#define RK_NUMDR 4 /* drives/controller */
#define RK_M_NUMDR 03
#define RK_NUMSC 16 /* sectors/surface */
#define RK_NUMSF 2 /* surfaces/cylinder */
#define RK_NUMCY 203 /* cylinders/drive */
#define RK_NUMWD 256 /* words/sector */
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */
#define RK_NUMDR 4 /* drives/controller */
#define RK_M_NUMDR 03
/* Flags in the unit flags word */
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */
#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 */
#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */
#define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */
#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 */
/* Parameters in the unit descriptor */
#define CYL u3 /* current cylinder */
#define FUNC u4 /* function */
#define CYL u3 /* current cylinder */
#define FUNC u4 /* function */
/* Status register */
#define RKS_DONE 04000 /* transfer done */
#define RKS_HMOV 02000 /* heads moving */
#define RKS_SKFL 00400 /* drive seek fail */
#define RKS_NRDY 00200 /* drive not ready */
#define RKS_BUSY 00100 /* control busy error */
#define RKS_TMO 00040 /* timeout error */
#define RKS_WLK 00020 /* write lock error */
#define RKS_CRC 00010 /* CRC error */
#define RKS_DLT 00004 /* data late error */
#define RKS_STAT 00002 /* drive status error */
#define RKS_CYL 00001 /* cyl address error */
#define RKS_ERR (RKS_BUSY+RKS_TMO+RKS_WLK+RKS_CRC+RKS_DLT+RKS_STAT+RKS_CYL)
#define RKS_DONE 04000 /* transfer done */
#define RKS_HMOV 02000 /* heads moving */
#define RKS_SKFL 00400 /* drive seek fail */
#define RKS_NRDY 00200 /* drive not ready */
#define RKS_BUSY 00100 /* control busy error */
#define RKS_TMO 00040 /* timeout error */
#define RKS_WLK 00020 /* write lock error */
#define RKS_CRC 00010 /* CRC error */
#define RKS_DLT 00004 /* data late error */
#define RKS_STAT 00002 /* drive status error */
#define RKS_CYL 00001 /* cyl address error */
#define RKS_ERR (RKS_BUSY+RKS_TMO+RKS_WLK+RKS_CRC+RKS_DLT+RKS_STAT+RKS_CYL)
/* Command register */
#define RKC_M_FUNC 07 /* function */
#define RKC_READ 0
#define RKC_RALL 1
#define RKC_WLK 2
#define RKC_SEEK 3
#define RKC_WRITE 4
#define RKC_WALL 5
#define RKC_V_FUNC 9
#define RKC_IE 00400 /* interrupt enable */
#define RKC_SKDN 00200 /* set done on seek done */
#define RKC_HALF 00100 /* 128W sector */
#define RKC_MEX 00070 /* memory extension */
#define RKC_V_MEX 3
#define RKC_M_DRV 03 /* drive select */
#define RKC_V_DRV 1
#define RKC_CYHI 00001 /* high cylinder addr */
#define RKC_M_FUNC 07 /* function */
#define RKC_READ 0
#define RKC_RALL 1
#define RKC_WLK 2
#define RKC_SEEK 3
#define RKC_WRITE 4
#define RKC_WALL 5
#define RKC_V_FUNC 9
#define RKC_IE 00400 /* interrupt enable */
#define RKC_SKDN 00200 /* set done on seek done */
#define RKC_HALF 00100 /* 128W sector */
#define RKC_MEX 00070 /* memory extension */
#define RKC_V_MEX 3
#define RKC_M_DRV 03 /* drive select */
#define RKC_V_DRV 1
#define RKC_CYHI 00001 /* high cylinder addr */
#define GET_FUNC(x) (((x) >> RKC_V_FUNC) & RKC_M_FUNC)
#define GET_DRIVE(x) (((x) >> RKC_V_DRV) & RKC_M_DRV)
#define GET_MEX(x) (((x) & RKC_MEX) << (12 - RKC_V_MEX))
#define GET_FUNC(x) (((x) >> RKC_V_FUNC) & RKC_M_FUNC)
#define GET_DRIVE(x) (((x) >> RKC_V_DRV) & RKC_M_DRV)
#define GET_MEX(x) (((x) & RKC_MEX) << (12 - RKC_V_MEX))
/* Disk address */
#define RKD_V_SECT 0 /* sector */
#define RKD_M_SECT 017
#define RKD_V_SUR 4 /* surface */
#define RKD_M_SUR 01
#define RKD_V_CYL 5 /* cylinder */
#define RKD_M_CYL 0177
#define GET_CYL(x,y) ((((x) & RKC_CYHI) << (12-RKD_V_CYL)) | \
(((y) >> RKD_V_CYL) & RKD_M_CYL))
#define GET_DA(x,y) ((((x) & RKC_CYHI) << 12) | y)
#define RKD_V_SECT 0 /* sector */
#define RKD_M_SECT 017
#define RKD_V_SUR 4 /* surface */
#define RKD_M_SUR 01
#define RKD_V_CYL 5 /* cylinder */
#define RKD_M_CYL 0177
#define GET_CYL(x,y) ((((x) & RKC_CYHI) << (12-RKD_V_CYL)) | \
(((y) >> RKD_V_CYL) & RKD_M_CYL))
#define GET_DA(x,y) ((((x) & RKC_CYHI) << 12) | y)
/* Reset commands */
#define RKX_CLS 0 /* clear status */
#define RKX_CLC 1 /* clear control */
#define RKX_CLD 2 /* clear drive */
#define RKX_CLSA 3 /* clear status alt */
#define RKX_CLS 0 /* clear status */
#define RKX_CLC 1 /* clear control */
#define RKX_CLD 2 /* clear drive */
#define RKX_CLSA 3 /* clear status alt */
#define RK_INT_UPDATE \
if (((rk_sta & (RKS_DONE + RKS_ERR)) != 0) && \
((rk_cmd & RKC_IE) != 0)) int_req = int_req | INT_RK; \
else int_req = int_req & ~INT_RK
if (((rk_sta & (RKS_DONE + RKS_ERR)) != 0) && \
((rk_cmd & RKC_IE) != 0)) int_req = int_req | INT_RK; \
else int_req = int_req & ~INT_RK
#define RK_MIN 10
#define MAX(x,y) (((x) > (y))? (x): (y))
extern uint16 M[];
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 */
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 */
int32 rk_busy = 0; /* controller busy */
int32 rk_sta = 0; /* status register */
int32 rk_cmd = 0; /* command register */
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);
@@ -144,51 +144,55 @@ void rk_go (int32 function, int32 cylinder);
/* RK-8E data structures
rk_dev RK device descriptor
rk_unit RK unit list
rk_reg RK register list
rk_mod RK modifiers list
rk_dev RK device descriptor
rk_unit RK unit list
rk_reg RK register list
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) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) } };
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) },
{ UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, RK_SIZE) }
};
REG rk_reg[] = {
{ ORDATA (RKSTA, rk_sta, 12) },
{ ORDATA (RKCMD, rk_cmd, 12) },
{ ORDATA (RKDA, rk_da, 12) },
{ ORDATA (RKMA, rk_ma, 12) },
{ FLDATA (BUSY, rk_busy, 0) },
{ FLDATA (INT, int_req, INT_V_RK) },
{ DRDATA (STIME, rk_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rk_rwait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
{ ORDATA (DEVNUM, rk_dib.dev, 6), REG_HRO },
{ NULL } };
{ ORDATA (RKSTA, rk_sta, 12) },
{ ORDATA (RKCMD, rk_cmd, 12) },
{ ORDATA (RKDA, rk_da, 12) },
{ ORDATA (RKMA, rk_ma, 12) },
{ FLDATA (BUSY, rk_busy, 0) },
{ FLDATA (INT, int_req, INT_V_RK) },
{ DRDATA (STIME, rk_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rk_rwait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, rk_stopioe, 0) },
{ 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, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
{ UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
{ 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_dib, DEV_DISABLE };
"RK", rk_unit, rk_reg, rk_mod,
RK_NUMDR, 8, 24, 1, 8, 12,
NULL, NULL, &rk_reset,
&rk_boot, NULL, NULL,
&rk_dib, DEV_DISABLE
};
/* IOT routine */
int32 rk (int32 IR, int32 AC)
@@ -196,57 +200,73 @@ int32 rk (int32 IR, int32 AC)
int32 i;
UNIT *uptr;
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* unused */
return (stop_inst << IOT_V_REASON) + AC;
case 1: /* DSKP */
return (rk_sta & (RKS_DONE + RKS_ERR))? /* skip on done, err */
IOT_SKP + AC: AC;
case 2: /* DCLR */
rk_sta = 0; /* clear status */
switch (AC & 03) { /* decode AC<10:11> */
case RKX_CLS: /* clear status */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
case RKX_CLSA: /* clear status alt */
break;
case RKX_CLC: /* clear control */
rk_cmd = rk_busy = 0; /* clear registers */
rk_ma = rk_da = 0;
for (i = 0; i < RK_NUMDR; i++) sim_cancel (&rk_unit[i]);
break;
case RKX_CLD: /* reset drive */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else rk_go (RKC_SEEK, 0); /* seek to 0 */
break; } /* end switch AC */
break;
case 3: /* DLAG */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else {
rk_da = AC; /* load disk addr */
rk_go (GET_FUNC (rk_cmd), GET_CYL (rk_cmd, rk_da)); }
break;
case 4: /* DLCA */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else rk_ma = AC; /* load curr addr */
break;
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 (sim_is_active (uptr)) rk_sta = rk_sta | RKS_HMOV;
return rk_sta;
case 6: /* DLDC */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else {
rk_cmd = AC; /* load command */
rk_sta = 0; } /* clear status */
break;
case 7: /* DMAN */
break; } /* end case pulse */
RK_INT_UPDATE; /* update int req */
return 0; /* clear AC */
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* unused */
return (stop_inst << IOT_V_REASON) + AC;
case 1: /* DSKP */
return (rk_sta & (RKS_DONE + RKS_ERR))? /* skip on done, err */
IOT_SKP + AC: AC;
case 2: /* DCLR */
rk_sta = 0; /* clear status */
switch (AC & 03) { /* decode AC<10:11> */
case RKX_CLS: /* clear status */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
case RKX_CLSA: /* clear status alt */
break;
case RKX_CLC: /* clear control */
rk_cmd = rk_busy = 0; /* clear registers */
rk_ma = rk_da = 0;
for (i = 0; i < RK_NUMDR; i++) sim_cancel (&rk_unit[i]);
break;
case RKX_CLD: /* reset drive */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else rk_go (RKC_SEEK, 0); /* seek to 0 */
break;
} /* end switch AC */
break;
case 3: /* DLAG */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else {
rk_da = AC; /* load disk addr */
rk_go (GET_FUNC (rk_cmd), GET_CYL (rk_cmd, rk_da));
}
break;
case 4: /* DLCA */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else rk_ma = AC; /* load curr addr */
break;
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 (sim_is_active (uptr)) rk_sta = rk_sta | RKS_HMOV;
return rk_sta;
case 6: /* DLDC */
if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
else {
rk_cmd = AC; /* load command */
rk_sta = 0; /* clear status */
}
break;
case 7: /* DMAN */
break;
} /* end case pulse */
RK_INT_UPDATE; /* update int req */
return 0; /* clear AC */
}
/* Initiate new function
Called with function, cylinder, to allow recalibrate as well as
@@ -261,33 +281,40 @@ void rk_go (int32 func, int32 cyl)
int32 t;
UNIT *uptr;
if (func == RKC_RALL) func = RKC_READ; /* all? use standard */
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? */
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; }
uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */
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)) {
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
return; }
if (func == RKC_WLK) { /* write lock? */
uptr->flags = uptr->flags | UNIT_SWLK;
rk_sta = rk_sta | RKS_DONE;
return; }
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 */
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
return;
}
if (func == RKC_WLK) { /* write lock? */
uptr->flags = uptr->flags | UNIT_SWLK;
rk_sta = rk_sta | RKS_DONE;
return;
}
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 */
return;
}
/* Unit service
If seek, complete seek command
@@ -305,64 +332,74 @@ t_stat rk_svc (UNIT *uptr)
int32 err, wc, wc1, awc, swc, pa, da;
UNIT *seluptr;
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->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 */
rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
rk_busy = 0;
RK_INT_UPDATE;
return IORETURN (rk_stopioe, SCPE_UNATT); }
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)) {
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
rk_busy = 0;
RK_INT_UPDATE;
return SCPE_OK; }
rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */
rk_busy = 0;
RK_INT_UPDATE;
return SCPE_OK;
}
pa = GET_MEX (rk_cmd) | rk_ma; /* phys address */
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 */
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);
for ( ; awc < wc; awc++) M[pa + awc] = 0; /* fill if eof */
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);
for ( ; awc < wc1; awc++) M[pa + awc] = 0; /* fill if eof */
err = ferror (uptr->fileref); } }
awc = fxread (&M[pa], sizeof (int16), wc, uptr->fileref);
for ( ; awc < wc; awc++) M[pa + awc] = 0; /* fill if eof */
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);
for ( ; awc < wc1; awc++) M[pa + awc] = 0; /* fill if eof */
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); }
if ((rk_cmd & RKC_HALF) && (err == 0)) { /* fill half sector */
fxwrite (fill, sizeof (int16), RK_NUMWD/2, 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);
}
if ((rk_cmd & RKC_HALF) && (err == 0)) { /* fill half sector */
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 */
rk_ma = (rk_ma + swc) & 07777; /* incr mem addr reg */
rk_sta = rk_sta | RKS_DONE; /* set done */
rk_busy = 0;
RK_INT_UPDATE;
if (err != 0) {
perror ("RK I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
perror ("RK I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR;
}
return SCPE_OK;
}
/* Reset routine */
t_stat rk_reset (DEVICE *dptr)
@@ -371,12 +408,13 @@ int32 i;
UNIT *uptr;
rk_cmd = rk_ma = rk_da = rk_sta = rk_busy = 0;
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; }
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;
}
return SCPE_OK;
}
@@ -387,22 +425,22 @@ return SCPE_OK;
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
static const uint16 boot_rom[] = {
06007, /* 23, CAF */
06744, /* 24, DLCA ; addr = 0 */
01032, /* 25, TAD UNIT ; unit no */
06746, /* 26, DLDC ; command, unit */
06743, /* 27, DLAG ; disk addr, go */
01032, /* 30, TAD UNIT ; unit no, for OS */
05031, /* 31, JMP . */
00000 /* UNIT, 0 ; in bits <9:10> */
};
06007, /* 23, CAF */
06744, /* 24, DLCA ; addr = 0 */
01032, /* 25, TAD UNIT ; unit no */
06746, /* 26, DLDC ; command, unit */
06743, /* 27, DLAG ; disk addr, go */
01032, /* 30, TAD UNIT ; unit no, for OS */
05031, /* 31, JMP . */
00000 /* UNIT, 0 ; in bits <9:10> */
};
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 */
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;

View File

@@ -1,6 +1,6 @@
/* pdp8_rl.c: RL8A cartridge disk simulator
/* pdp8_rl.c: RL8A cartridge disk simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,17 +19,18 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
rl RL8A cartridge disk
rl RL8A cartridge disk
04-Jan-04 RMS Changed attach routine to use sim_fsize
25-Apr-03 RMS Revised for extended file support
04-Oct-02 RMS Added DIB, device number support
06-Jan-02 RMS Changed enable/disable support
30-Nov-01 RMS Cloned from RL11
16-Aug-05 RMS Fixed C++ declaration and cast problems
04-Jan-04 RMS Changed attach routine to use sim_fsize
25-Apr-03 RMS Revised for extended file support
04-Oct-02 RMS Added DIB, device number support
06-Jan-02 RMS Changed enable/disable support
30-Nov-01 RMS Cloned from RL11
The RL8A is a four drive cartridge disk subsystem. An RL01 drive
consists of 256 cylinders, each with 2 surfaces containing 40 sectors
@@ -48,128 +49,128 @@
/* Constants */
#define RL_NUMBY 256 /* 8b bytes/sector */
#define RL_NUMSC 40 /* sectors/surface */
#define RL_NUMSF 2 /* surfaces/cylinder */
#define RL_NUMCY 256 /* cylinders/drive */
#define RL_NUMDR 4 /* drives/controller */
#define RL_MAXFR (1 << 12) /* max transfer */
#define RL01_SIZE (RL_NUMCY*RL_NUMSF*RL_NUMSC*RL_NUMBY) /* words/drive */
#define RL02_SIZE (RL01_SIZE * 2) /* words/drive */
#define RL_BBMAP 014 /* sector for bblk map */
#define RL_BBID 0123 /* ID for bblk map */
#define RL_NUMBY 256 /* 8b bytes/sector */
#define RL_NUMSC 40 /* sectors/surface */
#define RL_NUMSF 2 /* surfaces/cylinder */
#define RL_NUMCY 256 /* cylinders/drive */
#define RL_NUMDR 4 /* drives/controller */
#define RL_MAXFR (1 << 12) /* max transfer */
#define RL01_SIZE (RL_NUMCY*RL_NUMSF*RL_NUMSC*RL_NUMBY) /* words/drive */
#define RL02_SIZE (RL01_SIZE * 2) /* words/drive */
#define RL_BBMAP 014 /* sector for bblk map */
#define RL_BBID 0123 /* ID for bblk map */
/* Flags in the unit flags word */
#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)
#define UNIT_AUTO (1u << UNIT_V_AUTO)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
#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)
#define UNIT_AUTO (1u << UNIT_V_AUTO)
#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
/* Parameters in the unit descriptor */
#define TRK u3 /* current cylinder */
#define STAT u4 /* status */
#define TRK u3 /* current cylinder */
#define STAT u4 /* status */
/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */
#define RLDS_LOAD 0 /* no cartridge */
#define RLDS_LOCK 5 /* lock on */
#define RLDS_BHO 0000010 /* brushes home NI */
#define RLDS_HDO 0000020 /* heads out NI */
#define RLDS_CVO 0000040 /* cover open NI */
#define RLDS_HD 0000100 /* head select ^ */
#define RLDS_RL02 0000200 /* RL02 */
#define RLDS_DSE 0000400 /* drv sel err NI */
#define RLDS_VCK 0001000 /* vol check * */
#define RLDS_WGE 0002000 /* wr gate err * */
#define RLDS_SPE 0004000 /* spin err * */
#define RLDS_STO 0010000 /* seek time out NI */
#define RLDS_WLK 0020000 /* wr locked */
#define RLDS_HCE 0040000 /* hd curr err NI */
#define RLDS_WDE 0100000 /* wr data err NI */
#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */
#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */
#define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
RLDS_VCK+RLDS_DSE) /* errors bits */
#define RLDS_LOAD 0 /* no cartridge */
#define RLDS_LOCK 5 /* lock on */
#define RLDS_BHO 0000010 /* brushes home NI */
#define RLDS_HDO 0000020 /* heads out NI */
#define RLDS_CVO 0000040 /* cover open NI */
#define RLDS_HD 0000100 /* head select ^ */
#define RLDS_RL02 0000200 /* RL02 */
#define RLDS_DSE 0000400 /* drv sel err NI */
#define RLDS_VCK 0001000 /* vol check * */
#define RLDS_WGE 0002000 /* wr gate err * */
#define RLDS_SPE 0004000 /* spin err * */
#define RLDS_STO 0010000 /* seek time out NI */
#define RLDS_WLK 0020000 /* wr locked */
#define RLDS_HCE 0040000 /* hd curr err NI */
#define RLDS_WDE 0100000 /* wr data err NI */
#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */
#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */
#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) */
#define RLCSA_DIR 04000 /* direction */
#define RLCSA_HD 02000 /* head select */
#define RLCSA_CYL 00777 /* cyl offset */
#define GET_CYL(x) ((x) & RLCSA_CYL)
#define GET_TRK(x) ((((x) & RLCSA_CYL) * RL_NUMSF) + \
(((x) & RLCSA_HD)? 1: 0))
#define GET_DA(x) ((GET_TRK(x) * RL_NUMSC) + rlsa)
#define RLCSA_DIR 04000 /* direction */
#define RLCSA_HD 02000 /* head select */
#define RLCSA_CYL 00777 /* cyl offset */
#define GET_CYL(x) ((x) & RLCSA_CYL)
#define GET_TRK(x) ((((x) & RLCSA_CYL) * RL_NUMSF) + \
(((x) & RLCSA_HD)? 1: 0))
#define GET_DA(x) ((GET_TRK(x) * RL_NUMSC) + rlsa)
/* RLCSB, function/unit select */
#define RLCSB_V_FUNC 0 /* function */
#define RLCSB_M_FUNC 07
#define RLCSB_MNT 0
#define RLCSB_CLRD 1
#define RLCSB_GSTA 2
#define RLCSB_SEEK 3
#define RLCSB_RHDR 4
#define RLCSB_WRITE 5
#define RLCSB_READ 6
#define RLCSB_RNOHDR 7
#define RLCSB_V_MEX 3 /* memory extension */
#define RLCSB_M_MEX 07
#define RLCSB_V_DRIVE 6 /* drive */
#define RLCSB_M_DRIVE 03
#define RLCSB_V_IE 8 /* int enable */
#define RLCSB_IE (1u << RLCSB_V_IE)
#define RLCSB_8B 01000 /* 12b/8b */
#define RCLS_MNT 02000 /* maint NI */
#define RLCSB_RW 0001777 /* read/write */
#define GET_FUNC(x) (((x) >> RLCSB_V_FUNC) & RLCSB_M_FUNC)
#define GET_MEX(x) (((x) >> RLCSB_V_MEX) & RLCSB_M_MEX)
#define GET_DRIVE(x) (((x) >> RLCSB_V_DRIVE) & RLCSB_M_DRIVE)
#define RLCSB_V_FUNC 0 /* function */
#define RLCSB_M_FUNC 07
#define RLCSB_MNT 0
#define RLCSB_CLRD 1
#define RLCSB_GSTA 2
#define RLCSB_SEEK 3
#define RLCSB_RHDR 4
#define RLCSB_WRITE 5
#define RLCSB_READ 6
#define RLCSB_RNOHDR 7
#define RLCSB_V_MEX 3 /* memory extension */
#define RLCSB_M_MEX 07
#define RLCSB_V_DRIVE 6 /* drive */
#define RLCSB_M_DRIVE 03
#define RLCSB_V_IE 8 /* int enable */
#define RLCSB_IE (1u << RLCSB_V_IE)
#define RLCSB_8B 01000 /* 12b/8b */
#define RCLS_MNT 02000 /* maint NI */
#define RLCSB_RW 0001777 /* read/write */
#define GET_FUNC(x) (((x) >> RLCSB_V_FUNC) & RLCSB_M_FUNC)
#define GET_MEX(x) (((x) >> RLCSB_V_MEX) & RLCSB_M_MEX)
#define GET_DRIVE(x) (((x) >> RLCSB_V_DRIVE) & RLCSB_M_DRIVE)
/* RLSA, disk sector */
#define RLSA_V_SECT 6 /* sector */
#define RLSA_M_SECT 077
#define GET_SECT(x) (((x) >> RLSA_V_SECT) & RLSA_M_SECT)
#define RLSA_V_SECT 6 /* sector */
#define RLSA_M_SECT 077
#define GET_SECT(x) (((x) >> RLSA_V_SECT) & RLSA_M_SECT)
/* RLER, error register */
#define RLER_DRDY 00001 /* drive ready */
#define RLER_DRE 00002 /* drive error */
#define RLER_HDE 01000 /* header error */
#define RLER_INCMP 02000 /* incomplete */
#define RLER_ICRC 04000 /* CRC error */
#define RLER_MASK 07003
#define RLER_DRDY 00001 /* drive ready */
#define RLER_DRE 00002 /* drive error */
#define RLER_HDE 01000 /* header error */
#define RLER_INCMP 02000 /* incomplete */
#define RLER_ICRC 04000 /* CRC error */
#define RLER_MASK 07003
/* RLSI, silo register, used only in read header */
#define RLSI_V_TRK 6 /* track */
#define RLSI_V_TRK 6 /* track */
extern uint16 M[];
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 */
int32 rlma = 0; /* memory address */
int32 rlwc = 0; /* word count */
int32 rlsa = 0; /* sector address */
int32 rler = 0; /* error register */
int32 rlsi = 0, rlsi1 = 0, rlsi2 = 0; /* silo queue */
int32 rl_lft = 0; /* silo left/right */
int32 rl_done = 0; /* done flag */
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 */
uint8 *rlxb = NULL; /* xfer buffer */
int32 rlcsa = 0; /* control/status A */
int32 rlcsb = 0; /* control/status B */
int32 rlma = 0; /* memory address */
int32 rlwc = 0; /* word count */
int32 rlsa = 0; /* sector address */
int32 rler = 0; /* error register */
int32 rlsi = 0, rlsi1 = 0, rlsi2 = 0; /* silo queue */
int32 rl_lft = 0; /* silo left/right */
int32 rl_done = 0; /* done flag */
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);
@@ -184,181 +185,210 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
/* RL8A data structures
rl_dev RL device descriptor
rl_unit RL unit list
rl_reg RL register list
rl_mod RL modifier list
rl_dev RL device descriptor
rl_unit RL unit list
rl_reg RL register list
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) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) } };
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) },
{ UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
UNIT_ROABLE, RL01_SIZE) }
};
REG rl_reg[] = {
{ ORDATA (RLCSA, rlcsa, 12) },
{ ORDATA (RLCSB, rlcsb, 12) },
{ ORDATA (RLMA, rlma, 12) },
{ ORDATA (RLWC, rlwc, 12) },
{ ORDATA (RLSA, rlsa, 6) },
{ ORDATA (RLER, rler, 12) },
{ ORDATA (RLSI, rlsi, 16) },
{ ORDATA (RLSI1, rlsi1, 16) },
{ ORDATA (RLSI2, rlsi2, 16) },
{ FLDATA (RLSIL, rl_lft, 0) },
{ FLDATA (INT, int_req, INT_V_RL) },
{ FLDATA (DONE, rl_done, INT_V_RL) },
{ FLDATA (IE, rlcsb, RLCSB_V_IE) },
{ FLDATA (ERR, rl_erf, 0) },
{ DRDATA (STIME, rl_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
{ URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0,
RL_NUMDR, PV_LEFT + REG_HRO) },
{ FLDATA (STOP_IOE, rl_stopioe, 0) },
{ ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO },
{ NULL } };
{ ORDATA (RLCSA, rlcsa, 12) },
{ ORDATA (RLCSB, rlcsb, 12) },
{ ORDATA (RLMA, rlma, 12) },
{ ORDATA (RLWC, rlwc, 12) },
{ ORDATA (RLSA, rlsa, 6) },
{ ORDATA (RLER, rler, 12) },
{ ORDATA (RLSI, rlsi, 16) },
{ ORDATA (RLSI1, rlsi1, 16) },
{ ORDATA (RLSI2, rlsi2, 16) },
{ FLDATA (RLSIL, rl_lft, 0) },
{ FLDATA (INT, int_req, INT_V_RL) },
{ FLDATA (DONE, rl_done, INT_V_RL) },
{ FLDATA (IE, rlcsb, RLCSB_V_IE) },
{ FLDATA (ERR, rl_erf, 0) },
{ DRDATA (STIME, rl_swait, 24), PV_LEFT },
{ DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
{ URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0,
RL_NUMDR, PV_LEFT + REG_HRO) },
{ FLDATA (STOP_IOE, rl_stopioe, 0) },
{ ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO },
{ NULL }
};
MTAB rl_mod[] = {
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
{ (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
{ (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
{ (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
{ (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
{ 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, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ 0 } };
{ UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
{ UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
{ UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
{ (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
{ (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
{ (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
{ (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
{ (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
{ 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, 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_dib, DEV_DISABLE | DEV_DIS };
/* IOT 60 routine */
"RL", rl_unit, rl_reg, rl_mod,
RL_NUMDR, 8, 24, 1, 8, 8,
NULL, NULL, &rl_reset,
&rl_boot, &rl_attach, NULL,
&rl_dib, DEV_DISABLE | DEV_DIS
};
/* IOT routines */
int32 rl60 (int32 IR, int32 AC)
{
int32 curr, offs, newc, maxc;
UNIT *uptr;
switch (IR & 07) { /* case IR<9:11> */
case 0: /* RLDC */
rl_reset (&rl_dev); /* reset device */
break;
case 1: /* RLSD */
if (rl_done) AC = IOT_SKP; /* skip if done */
else AC = 0;
rl_done = 0; /* clear done */
int_req = int_req & ~INT_RL; /* clear intr */
return AC;
case 2: /* RLMA */
rlma = AC;
break;
case 3: /* RLCA */
rlcsa = AC;
break;
case 4: /* RLCB */
rlcsb = AC;
rl_done = 0; /* clear done */
rler = rl_erf = 0; /* clear errors */
int_req = int_req & ~INT_RL; /* clear intr */
rl_lft = 0; /* clear silo ptr */
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 */
case RLCSB_MNT: /* mnt */
rl_set_done (0);
break;
case RLCSB_SEEK: /* seek */
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)?
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);
sim_activate (uptr, rl_swait * abs (newc - curr));
break;
default: /* data transfer */
sim_activate (uptr, rl_swait); /* activate unit */
break; } /* end switch func */
break;
case 5: /* RLSA */
rlsa = GET_SECT (AC);
break;
case 6: /* spare */
return 0;
case 7: /* RLWC */
rlwc = AC;
break; } /* end switch pulse */
return 0; /* clear AC */
switch (IR & 07) { /* case IR<9:11> */
case 0: /* RLDC */
rl_reset (&rl_dev); /* reset device */
break;
case 1: /* RLSD */
if (rl_done) AC = IOT_SKP; /* skip if done */
else AC = 0;
rl_done = 0; /* clear done */
int_req = int_req & ~INT_RL; /* clear intr */
return AC;
case 2: /* RLMA */
rlma = AC;
break;
case 3: /* RLCA */
rlcsa = AC;
break;
case 4: /* RLCB */
rlcsb = AC;
rl_done = 0; /* clear done */
rler = rl_erf = 0; /* clear errors */
int_req = int_req & ~INT_RL; /* clear intr */
rl_lft = 0; /* clear silo ptr */
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 */
case RLCSB_MNT: /* mnt */
rl_set_done (0);
break;
case RLCSB_SEEK: /* seek */
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)?
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);
sim_activate (uptr, rl_swait * abs (newc - curr));
break;
default: /* data transfer */
sim_activate (uptr, rl_swait); /* activate unit */
break;
} /* end switch func */
break;
case 5: /* RLSA */
rlsa = GET_SECT (AC);
break;
case 6: /* spare */
return 0;
case 7: /* RLWC */
rlwc = AC;
break;
} /* end switch pulse */
return 0; /* clear AC */
}
/* IOT 61 routine */
int32 rl61 (int32 pulse, int32 AC)
{
int32 dat;
UNIT *uptr;
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))
rler = rler | RLER_DRDY;
else rler = rler & ~RLER_DRDY;
dat = rler & RLER_MASK;
break;
case 1: /* RRWC */
dat = rlwc;
break;
case 2: /* RRCA */
dat = rlcsa;
break;
case 3: /* RRCB */
dat = rlcsb;
break;
case 4: /* RRSA */
dat = (rlsa << RLSA_V_SECT) & 07777;
break;
case 5: /* RRSI */
if (rl_lft) { /* silo left? */
dat = (rlsi >> 8) & 0377; /* get left 8b */
rlsi = rlsi1; /* ripple */
rlsi1 = rlsi2; }
else dat = rlsi & 0377; /* get right 8b */
rl_lft = rl_lft ^ 1; /* change side */
break;
case 6: /* spare */
return AC;
case 7: /* RLSE */
if (rl_erf) dat = IOT_SKP | AC; /* skip if err */
else dat = AC;
rl_erf = 0;
break; } /* end switch pulse */
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))
rler = rler | RLER_DRDY;
else rler = rler & ~RLER_DRDY;
dat = rler & RLER_MASK;
break;
case 1: /* RRWC */
dat = rlwc;
break;
case 2: /* RRCA */
dat = rlcsa;
break;
case 3: /* RRCB */
dat = rlcsb;
break;
case 4: /* RRSA */
dat = (rlsa << RLSA_V_SECT) & 07777;
break;
case 5: /* RRSI */
if (rl_lft) { /* silo left? */
dat = (rlsi >> 8) & 0377; /* get left 8b */
rlsi = rlsi1; /* ripple */
rlsi1 = rlsi2;
}
else dat = rlsi & 0377; /* get right 8b */
rl_lft = rl_lft ^ 1; /* change side */
break;
case 6: /* spare */
return AC;
case 7: /* RLSE */
if (rl_erf) dat = IOT_SKP | AC; /* skip if err */
else dat = AC;
rl_erf = 0;
break;
} /* end switch pulse */
return dat;
}
/* Service unit timeout
If seek in progress, complete seek command
@@ -374,106 +404,120 @@ int32 err, wc, maxc;
int32 i, j, func, da, bc, wbc;
uint32 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;
rlsi2 = rlsi1 = rlsi;
rl_set_done (0); /* done */
return SCPE_OK; }
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;
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 */
rl_set_done (RLER_INCMP); /* flag error */
return IORETURN (rl_stopioe, SCPE_UNATT); }
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 */
rl_set_done (RLER_DRE); /* flag error */
return SCPE_OK; }
uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */
rl_set_done (RLER_DRE); /* flag error */
return SCPE_OK;
}
if (func == RLCSB_SEEK) { /* seek? */
rl_set_done (0); /* done */
return SCPE_OK; }
if (func == RLCSB_SEEK) { /* seek? */
rl_set_done (0); /* done */
return SCPE_OK;
}
if (func == RLCSB_RHDR) { /* read header? */
rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa;
rlsi1 = rlsi2 = 0;
rl_set_done (0); /* done */
return SCPE_OK; }
if (func == RLCSB_RHDR) { /* read header? */
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)))
|| (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */
rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */
return SCPE_OK; }
ma = (GET_MEX (rlcsb) << 12) | rlma; /* get mem addr */
da = GET_DA (rlcsa) * RL_NUMBY; /* get disk addr */
wc = 010000 - rlwc; /* get true wc */
if (rlcsb & RLCSB_8B) { /* 8b mode? */
bc = wc; /* bytes to xfr */
maxc = (RL_NUMSC - rlsa) * RL_NUMBY; /* max transfer */
if (bc > maxc) wc = bc = maxc; } /* trk ovrun? limit */
else { bc = ((wc * 3) + 1) / 2; /* 12b mode */
if (bc > RL_NUMBY) { /* > 1 sector */
bc = RL_NUMBY; /* cap xfer */
wc = (RL_NUMBY * 2) / 3; } }
|| (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */
rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */
return SCPE_OK;
}
ma = (GET_MEX (rlcsb) << 12) | rlma; /* get mem addr */
da = GET_DA (rlcsa) * RL_NUMBY; /* get disk addr */
wc = 010000 - rlwc; /* get true wc */
if (rlcsb & RLCSB_8B) { /* 8b mode? */
bc = wc; /* bytes to xfr */
maxc = (RL_NUMSC - rlsa) * RL_NUMBY; /* max transfer */
if (bc > maxc) wc = bc = maxc; /* trk ovrun? limit */
}
else {
bc = ((wc * 3) + 1) / 2; /* 12b mode */
if (bc > RL_NUMBY) { /* > 1 sector */
bc = RL_NUMBY; /* cap xfer */
wc = (RL_NUMBY * 2) / 3;
}
}
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);
for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */
for (i = j = 0; i < wc; i++) { /* store buffer */
if (rlcsb & RLCSB_8B) /* 8b mode? */
M[ma] = rlxb[i] & 0377; /* store */
else if (i & 1) { /* odd wd 12b? */
M[ma] = ((rlxb[j + 1] >> 4) & 017) |
(((uint16) rlxb[j + 2]) << 4);
j = j + 3; }
else M[ma] = rlxb[j] | /* even wd 12b */
((((uint16) rlxb[j + 1]) & 017) << 8);
ma = (ma & 070000) + ((ma + 1) & 07777);
} /* end for */
} /* end if wr */
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);
for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */
for (i = j = 0; i < wc; i++) { /* store buffer */
if (rlcsb & RLCSB_8B) /* 8b mode? */
M[ma] = rlxb[i] & 0377; /* store */
else if (i & 1) { /* odd wd 12b? */
M[ma] = ((rlxb[j + 1] >> 4) & 017) |
(((uint16) rlxb[j + 2]) << 4);
j = j + 3;
}
else M[ma] = rlxb[j] | /* even wd 12b */
((((uint16) rlxb[j + 1]) & 017) << 8);
ma = (ma & 070000) + ((ma + 1) & 07777);
} /* end for */
} /* end if wr */
if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */
for (i = j = 0; i < wc; i++) { /* fetch buffer */
if (rlcsb & RLCSB_8B) /* 8b mode? */
rlxb[i] = M[ma] & 0377; /* fetch */
else if (i & 1) { /* odd wd 12b? */
rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4);
rlxb[j + 2] = ((M[ma] >> 4) & 0377);
j = j + 3; }
else { /* even wd 12b */
rlxb[j] = M[ma] & 0377;
rlxb[j + 1] = (M[ma] >> 8) & 017; }
ma = (ma & 070000) + ((ma + 1) & 07777);
} /* 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);
} /* end write */
if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */
for (i = j = 0; i < wc; i++) { /* fetch buffer */
if (rlcsb & RLCSB_8B) /* 8b mode? */
rlxb[i] = M[ma] & 0377; /* fetch */
else if (i & 1) { /* odd wd 12b? */
rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4);
rlxb[j + 2] = ((M[ma] >> 4) & 0377);
j = j + 3;
}
else { /* even wd 12b */
rlxb[j] = M[ma] & 0377;
rlxb[j + 1] = (M[ma] >> 8) & 017;
}
ma = (ma & 070000) + ((ma + 1) & 07777);
} /* 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);
} /* end write */
rlwc = (rlwc + wc) & 07777; /* final word count */
if (rlwc != 0) rler = rler | RLER_INCMP; /* completed? */
rlma = (rlma + wc) & 07777; /* final word addr */
rlwc = (rlwc + wc) & 07777; /* final word count */
if (rlwc != 0) rler = rler | RLER_INCMP; /* completed? */
rlma = (rlma + wc) & 07777; /* final word addr */
rlsa = rlsa + ((bc + (RL_NUMBY - 1)) / RL_NUMBY);
rl_set_done (0);
if (err != 0) { /* error? */
perror ("RL I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
if (err != 0) { /* error? */
perror ("RL I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR;
}
return SCPE_OK;
}
/* Set done and possibly errors */
void rl_set_done (int32 status)
@@ -504,10 +548,11 @@ rl_done = 0;
rl_erf = 0;
int_req = int_req & ~INT_RL;
for (i = 0; i < RL_NUMDR; i++) {
uptr = rl_dev.units + i;
sim_cancel (uptr);
uptr->STAT = 0; }
if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (uint8));
uptr = rl_dev.units + i;
sim_cancel (uptr);
uptr->STAT = 0;
}
if (rlxb == NULL) rlxb = (uint8 *) calloc (RL_MAXFR, sizeof (uint8));
if (rlxb == NULL) return SCPE_MEM;
return SCPE_OK;
}
@@ -520,19 +565,23 @@ uint32 p;
t_stat r;
uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
r = attach_unit (uptr, cptr); /* attach unit */
if (r != SCPE_OK) return r; /* error? */
uptr->TRK = 0; /* cyl 0 */
uptr->STAT = RLDS_VCK; /* new volume */
if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
if (uptr->flags & UNIT_RO) return SCPE_OK;
return rl_set_bad (uptr, 0, NULL, NULL); }
if ((uptr->flags & UNIT_AUTO) == 0) return r; /* autosize? */
r = attach_unit (uptr, cptr); /* attach unit */
if (r != SCPE_OK) return r; /* error? */
uptr->TRK = 0; /* cyl 0 */
uptr->STAT = RLDS_VCK; /* new volume */
if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
if (uptr->flags & UNIT_RO) return SCPE_OK;
return rl_set_bad (uptr, 0, NULL, NULL);
}
if ((uptr->flags & UNIT_AUTO) == 0) return r; /* autosize? */
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;
}
@@ -549,16 +598,16 @@ return SCPE_OK;
This routine writes the OS/8 specific bad block map in track 0, sector 014 (RL_BBMAP):
words 0 magic number = 0123 (RL_BBID)
words 1-n block numbers
:
words n+1 end of table = 0
words 0 magic number = 0123 (RL_BBID)
words 1-n block numbers
:
words n+1 end of table = 0
Inputs:
uptr = pointer to unit
val = ignored
uptr = pointer to unit
val = ignored
Outputs:
sta = status code
sta = status code
*/
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
@@ -571,48 +620,48 @@ if (!get_yn ("Create bad block table? [N]", FALSE)) return SCPE_OK;
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);
fxwrite (rlxb, sizeof (uint8), RL_NUMBY, uptr->fileref);
if (ferror (uptr->fileref)) return SCPE_IOERR;
return SCPE_OK;
}
/* Bootstrap */
#define BOOT_START 1 /* start */
#define BOOT_UNIT 02006 /* unit number */
#define BOOT_START 1 /* start */
#define BOOT_UNIT 02006 /* unit number */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
static const uint16 boot_rom[] = {
06600, /* BT, RLDC ; reset */
07201, /* 02, CLA IAC ; clr drv = 1 */
04027, /* 03, JMS GO ; do io */
01004, /* 04, TAD 4 ; rd hdr fnc */
04027, /* 05, JMS GO ; do io */
06615, /* 06, RRSI ; rd hdr lo */
07002, /* 07, BSW ; swap */
07012, /* 10, RTR ; lo cyl to L */
06615, /* 11, RRSI ; rd hdr hi */
00025, /* 12, AND 25 ; mask = 377 */
07004, /* 13, RTL ; get cyl */
06603, /* 14, RLCA ; set addr */
07325, /* 15, CLA STL IAC RAL ; seek = 3 */
04027, /* 16, JMS GO ; do io */
07332, /* 17, CLA STL RTR ; dir in = 2000 */
06605, /* 20, RLSA ; sector */
01026, /* 21, TAD (-200) ; one sector */
06607, /* 22, RLWC ; word cnt */
07327, /* 23, CLA STL IAC RTL ; read = 6*/
04027, /* 24, JMS GO ; do io */
00377, /* 25, JMP 377 ; start */
07600, /* 26, -200 ; word cnt */
00000, /* GO, 0 ; subr */
06604, /* 30, RLCB ; load fnc */
06601, /* 31, RLSD ; wait */
05031, /* 32, JMP .-1 ; */
06617, /* 33, RLSE ; error? */
05427, /* 34, JMP I GO ; no, ok */
05001 /* 35, JMP BT ; restart */
};
06600, /* BT, RLDC ; reset */
07201, /* 02, CLA IAC ; clr drv = 1 */
04027, /* 03, JMS GO ; do io */
01004, /* 04, TAD 4 ; rd hdr fnc */
04027, /* 05, JMS GO ; do io */
06615, /* 06, RRSI ; rd hdr lo */
07002, /* 07, BSW ; swap */
07012, /* 10, RTR ; lo cyl to L */
06615, /* 11, RRSI ; rd hdr hi */
00025, /* 12, AND 25 ; mask = 377 */
07004, /* 13, RTL ; get cyl */
06603, /* 14, RLCA ; set addr */
07325, /* 15, CLA STL IAC RAL ; seek = 3 */
04027, /* 16, JMS GO ; do io */
07332, /* 17, CLA STL RTR ; dir in = 2000 */
06605, /* 20, RLSA ; sector */
01026, /* 21, TAD (-200) ; one sector */
06607, /* 22, RLWC ; word cnt */
07327, /* 23, CLA STL IAC RTL ; read = 6*/
04027, /* 24, JMS GO ; do io */
00377, /* 25, JMP 377 ; start */
07600, /* 26, -200 ; word cnt */
00000, /* GO, 0 ; subr */
06604, /* 30, RLCB ; load fnc */
06601, /* 31, RLSD ; wait */
05031, /* 32, JMP .-1 ; */
06617, /* 33, RLSE ; error? */
05427, /* 34, JMP I GO ; no, ok */
05001 /* 35, JMP BT ; restart */
};
t_stat rl_boot (int32 unitno, DEVICE *dptr)
@@ -620,8 +669,8 @@ t_stat rl_boot (int32 unitno, DEVICE *dptr)
int32 i;
extern int32 saved_PC;
if (unitno) return SCPE_ARG; /* only unit 0 */
if (rl_dib.dev != DEV_RL) return STOP_NOTSTD; /* only std devno */
if (unitno) return SCPE_ARG; /* only unit 0 */
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;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* pdp8_sys.c: PDP-8 simulator interface
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,24 +19,24 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message
25-Apr-03 RMS Revised for extended file support
30-Dec-01 RMS Revised for new TTX
26-Nov-01 RMS Added RL8A support
17-Sep-01 RMS Removed multiconsole support
16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support
27-May-01 RMS Added multiconsole support
18-Mar-01 RMS Added DF32 support
14-Mar-01 RMS Added extension detection of RIM binary tapes
15-Feb-01 RMS Added DECtape support
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
10-Apr-98 RMS Added RIM loader support
17-Feb-97 RMS Fixed bug in handling of bin loader fields
17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message
25-Apr-03 RMS Revised for extended file support
30-Dec-01 RMS Revised for new TTX
26-Nov-01 RMS Added RL8A support
17-Sep-01 RMS Removed multiconsole support
16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support
27-May-01 RMS Added multiconsole support
18-Mar-01 RMS Added DF32 support
14-Mar-01 RMS Added extension detection of RIM binary tapes
15-Feb-01 RMS Added DECtape support
30-Oct-00 RMS Added support for examine to file
27-Oct-98 RMS V2.4 load interface
10-Apr-98 RMS Added RIM loader support
17-Feb-97 RMS Fixed bug in handling of bin loader fields
*/
#include "pdp8_defs.h"
@@ -60,13 +60,13 @@ extern int32 sim_switches;
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax maximum number of words for examine/deposit
sim_devices array of pointers to simulated devices
sim_consoles array of pointers to consoles (if more than one)
sim_stop_messages array of pointers to stop messages
sim_load binary loader
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax maximum number of words for examine/deposit
sim_devices array of pointers to simulated devices
sim_consoles array of pointers to consoles (if more than one)
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "PDP-8";
@@ -76,34 +76,36 @@ REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 4;
DEVICE *sim_devices[] = {
&cpu_dev,
&tsc_dev,
&ptr_dev,
&ptp_dev,
&tti_dev,
&tto_dev,
&ttix_dev,
&ttox_dev,
&clk_dev,
&lpt_dev,
&rk_dev,
&rl_dev,
&rx_dev,
&df_dev,
&rf_dev,
&dt_dev,
&td_dev,
&mt_dev,
NULL };
&cpu_dev,
&tsc_dev,
&ptr_dev,
&ptp_dev,
&tti_dev,
&tto_dev,
&ttix_dev,
&ttox_dev,
&clk_dev,
&lpt_dev,
&rk_dev,
&rl_dev,
&rx_dev,
&df_dev,
&rf_dev,
&dt_dev,
&td_dev,
&mt_dev,
NULL
};
const char *sim_stop_messages[] = {
"Unknown error",
"Unimplemented instruction",
"HALT instruction",
"Breakpoint",
"Non-standard device number",
"DECtape off reel" };
"Unknown error",
"Unimplemented instruction",
"HALT instruction",
"Breakpoint",
"Non-standard device number",
"DECtape off reel"
};
/* Binary loader
Two loader formats are supported: RIM loader (-r) and BIN (-b) loader.
@@ -124,89 +126,105 @@ uint32 origin, field;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
rubout = state = field = newf = origin = csum = 0;
if ((sim_switches & SWMASK ('R')) || /* RIM format? */
if ((sim_switches & SWMASK ('R')) || /* RIM format? */
(match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) {
while ((i = getc (fileref)) != EOF) {
switch (state) {
case 0: /* leader */
if ((i != 0) && (i < 0200)) state = 1;
high = i;
break;
case 1: /* low byte */
word = (high << 6) | i; /* form word */
if (word > 07777) origin = word & 07777;
else M[origin] = word;
state = 2;
break;
case 2: /* high byte */
if (i >= 0200) return SCPE_OK; /* end of tape? */
high = i; /* save high */
state = 1;
break; } /* end switch */
} /* end while */
} /* end if */
else { while ((i = getc (fileref)) != EOF) { /* BIN format */
if (rubout) {
rubout = 0;
continue; }
if (i == 0377) {
rubout = 1;
continue; }
if (i > 0200) {
newf = (i & 070) << 9;
continue; }
switch (state) {
case 0: /* leader */
if ((i != 0) && (i != 0200)) state = 1;
high = i; /* save as high */
break;
case 1: /* low byte */
low = i;
state = 2;
break;
case 2: /* high with test */
word = (high << 6) | low;
if (i == 0200) { /* end of tape? */
if ((csum - word) & 07777) return SCPE_CSUM;
return SCPE_OK; }
csum = csum + low + high;
if (word >= 010000) origin = word & 07777;
else {
if ((field | origin) >= MEMSIZE)
return SCPE_NXM;
M[field | origin] = word & 07777;
origin = (origin + 1) & 07777; }
field = newf;
high = i;
state = 1;
break; } /* end switch */
} /* end while */
} /* end else */
return SCPE_FMT; /* eof? error */
while ((i = getc (fileref)) != EOF) {
switch (state) {
case 0: /* leader */
if ((i != 0) && (i < 0200)) state = 1;
high = i;
break;
case 1: /* low byte */
word = (high << 6) | i; /* form word */
if (word > 07777) origin = word & 07777;
else M[origin] = word;
state = 2;
break;
case 2: /* high byte */
if (i >= 0200) return SCPE_OK; /* end of tape? */
high = i; /* save high */
state = 1;
break;
} /* end switch */
} /* end while */
} /* end if */
else {
while ((i = getc (fileref)) != EOF) { /* BIN format */
if (rubout) {
rubout = 0;
continue;
}
if (i == 0377) {
rubout = 1;
continue;
}
if (i > 0200) {
newf = (i & 070) << 9;
continue;
}
switch (state) {
case 0: /* leader */
if ((i != 0) && (i != 0200)) state = 1;
high = i; /* save as high */
break;
case 1: /* low byte */
low = i;
state = 2;
break;
case 2: /* high with test */
word = (high << 6) | low;
if (i == 0200) { /* end of tape? */
if ((csum - word) & 07777) return SCPE_CSUM;
return SCPE_OK;
}
csum = csum + low + high;
if (word >= 010000) origin = word & 07777;
else {
if ((field | origin) >= MEMSIZE)
return SCPE_NXM;
M[field | origin] = word & 07777;
origin = (origin + 1) & 07777;
}
field = newf;
high = i;
state = 1;
break;
} /* end switch */
} /* end while */
} /* end else */
return SCPE_FMT; /* eof? error */
}
/* Symbol tables */
#define I_V_FL 18 /* flag start */
#define I_M_FL 07 /* flag mask */
#define I_V_NPN 0 /* no operand */
#define I_V_FLD 1 /* field change */
#define I_V_MRF 2 /* mem ref */
#define I_V_IOT 3 /* general IOT */
#define I_V_OP1 4 /* operate 1 */
#define I_V_OP2 5 /* operate 2 */
#define I_V_OP3 6 /* operate 3 */
#define I_NPN (I_V_NPN << I_V_FL)
#define I_FLD (I_V_FLD << I_V_FL)
#define I_MRF (I_V_MRF << I_V_FL)
#define I_IOT (I_V_IOT << I_V_FL)
#define I_OP1 (I_V_OP1 << I_V_FL)
#define I_OP2 (I_V_OP2 << I_V_FL)
#define I_OP3 (I_V_OP3 << I_V_FL)
#define I_V_FL 18 /* flag start */
#define I_M_FL 07 /* flag mask */
#define I_V_NPN 0 /* no operand */
#define I_V_FLD 1 /* field change */
#define I_V_MRF 2 /* mem ref */
#define I_V_IOT 3 /* general IOT */
#define I_V_OP1 4 /* operate 1 */
#define I_V_OP2 5 /* operate 2 */
#define I_V_OP3 6 /* operate 3 */
#define I_NPN (I_V_NPN << I_V_FL)
#define I_FLD (I_V_FLD << I_V_FL)
#define I_MRF (I_V_MRF << I_V_FL)
#define I_IOT (I_V_IOT << I_V_FL)
#define I_OP1 (I_V_OP1 << I_V_FL)
#define I_OP2 (I_V_OP2 << I_V_FL)
#define I_OP3 (I_V_OP3 << I_V_FL)
static const int32 masks[] = {
07777, 07707, 07000, 07000,
07416, 07571, 017457 };
07416, 07571, 017457
};
static const char *opcode[] = {
"SKON", "ION", "IOF", "SRQ",
@@ -261,11 +279,12 @@ static const char *opcode[] = {
"ACS", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
"SCA", "DAD", "DST", "SWBA",
"DPSZ", "DPIC", "DCIM", "SAM",
"CLA", "CLL", "CMA", "CML", "IAC", /* encode only */
"CLA", "CLL", "CMA", "CML", "IAC", /* encode only */
"CLA", "OAS", "HLT",
"CLA", "MQA", "MQL",
NULL, NULL, NULL, NULL, /* decode only */
NULL };
NULL, NULL, NULL, NULL, /* decode only */
NULL
};
static const int32 opc_val[] = {
06000+I_NPN, 06001+I_NPN, 06002+I_NPN, 06003+I_NPN,
@@ -328,42 +347,45 @@ static const int32 opc_val[] = {
07600+I_OP2, 07404+I_OP2, 07402+I_OP2,
07601+I_OP3, 07501+I_OP3, 07421+I_OP3,
07000+I_OP1, 07400+I_OP2, 07401+I_OP3, 017401+I_OP3,
-1 };
-1
};
/* Operate decode
Inputs:
*of = output stream
inst = mask bits
class = instruction class code
sp = space needed?
*of = output stream
inst = mask bits
class = instruction class code
sp = space needed?
Outputs:
status = space needed
status = space needed
*/
int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp)
{
int32 i, j;
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1; } }
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((j == class) && (opc_val[i] & inst)) { /* same class? */
inst = inst & ~opc_val[i]; /* mask bit set? */
fprintf (of, (sp? " %s": "%s"), opcode[i]);
sp = 1;
}
}
return sp;
}
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to data
*uptr = pointer to unit
sw = switches
*of = output stream
addr = current PC
*val = pointer to data
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
return = status code
*/
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
@@ -371,79 +393,93 @@ return sp;
#define TSSTOASC(x) ((x) + 040)
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
UNIT *uptr, int32 sw)
{
int32 cflag, i, j, sp, inst, disp;
extern int32 emode;
cflag = (uptr == NULL) || (uptr == &cpu_unit);
inst = val[0];
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
fprintf (of, FMTASC (inst & 0177));
return SCPE_OK; }
if (sw & SWMASK ('C')) { /* characters? */
fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));
fprintf (of, "%c", SIXTOASC (inst & 077));
return SCPE_OK; }
if (sw & SWMASK ('T')) { /* TSS8 packed? */
fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077));
fprintf (of, "%c", TSSTOASC (inst & 077));
return SCPE_OK; }
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
fprintf (of, FMTASC (inst & 0177));
return SCPE_OK;
}
if (sw & SWMASK ('C')) { /* characters? */
fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));
fprintf (of, "%c", SIXTOASC (inst & 077));
return SCPE_OK;
}
if (sw & SWMASK ('T')) { /* TSS8 packed? */
fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077));
fprintf (of, "%c", TSSTOASC (inst & 077));
return SCPE_OK;
}
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
/* Instruction decode */
inst = val[0] | ((emode & 1) << 12); /* include EAE mode */
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 017777) == (inst & masks[j])) { /* match? */
inst = val[0] | ((emode & 1) << 12); /* include EAE mode */
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
if ((opc_val[i] & 017777) == (inst & masks[j])) { /* match? */
switch (j) { /* case on class */
case I_V_NPN: /* no operands */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_FLD: /* field change */
fprintf (of, "%s %-o", opcode[i], (inst >> 3) & 07);
break;
case I_V_MRF: /* mem ref */
disp = inst & 0177; /* displacement */
fprintf (of, "%s%s", opcode[i], ((inst & 00400)? " I ": " "));
if (inst & 0200) { /* current page? */
if (cflag) fprintf (of, "%-o", (addr & 07600) | disp);
else fprintf (of, "C %-o", disp); }
else fprintf (of, "%-o", disp); /* page zero */
break;
case I_V_IOT: /* IOT */
fprintf (of, "%s %-o", opcode[i], inst & 0777);
break;
case I_V_OP1: /* operate group 1 */
sp = fprint_opr (of, inst & 0361, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break;
case I_V_OP2: /* operate group 2 */
if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */
fprint_opr (of, inst & 0206, j, opcode[i] != NULL);
break;
case I_V_OP3: /* operate group 3 */
sp = fprint_opr (of, inst & 0320, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
switch (j) { /* case on class */
case I_V_NPN: /* no operands */
fprintf (of, "%s", opcode[i]); /* opcode */
break;
case I_V_FLD: /* field change */
fprintf (of, "%s %-o", opcode[i], (inst >> 3) & 07);
break;
case I_V_MRF: /* mem ref */
disp = inst & 0177; /* displacement */
fprintf (of, "%s%s", opcode[i], ((inst & 00400)? " I ": " "));
if (inst & 0200) { /* current page? */
if (cflag) fprintf (of, "%-o", (addr & 07600) | disp);
else fprintf (of, "C %-o", disp);
}
else fprintf (of, "%-o", disp); /* page zero */
break;
case I_V_IOT: /* IOT */
fprintf (of, "%s %-o", opcode[i], inst & 0777);
break;
case I_V_OP1: /* operate group 1 */
sp = fprint_opr (of, inst & 0361, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break;
case I_V_OP2: /* operate group 2 */
if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */
fprint_opr (of, inst & 0206, j, opcode[i] != NULL);
break;
case I_V_OP3: /* operate group 3 */
sp = fprint_opr (of, inst & 0320, j, 0);
if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]);
break;
} /* end case */
return SCPE_OK;
} /* end if */
} /* end for */
return SCPE_ARG;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
@@ -453,80 +489,96 @@ t_stat r;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++; /* absorb spaces */
while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cptr[0] | 0200;
return SCPE_OK; }
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cptr[0] | 0200;
return SCPE_OK;
}
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (((t_value) cptr[0] & 077) << 6) |
((t_value) cptr[1] & 077);
return SCPE_OK; }
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (((t_value) cptr[0] & 077) << 6) |
((t_value) cptr[1] & 077);
return SCPE_OK;
}
if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) |
((t_value) (cptr[1] - 040) & 077);
return SCPE_OK; }
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) |
((t_value) (cptr[1] - 040) & 077);
return SCPE_OK;
}
/* Instruction parse */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
val[0] = opc_val[i] & 07777; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
val[0] = opc_val[i] & 07777; /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */
switch (j) { /* case on class */
case I_V_IOT: /* IOT */
cptr = get_glyph (cptr, gbuf, 0); /* get dev+pulse */
d = get_uint (gbuf, 8, 0777, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | d;
break;
case I_V_FLD: /* field */
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] != NULL) {
k = (opc_val[i] >> I_V_FL) & I_M_FL;
if (k != j) return SCPE_ARG;
val[0] = val[0] | (opc_val[i] & 07777); }
else {
d = get_uint (gbuf, 8, 07, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << 3);
break; } }
break;
case I_V_MRF: /* mem ref */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
if (strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | 0400;
cptr = get_glyph (cptr, gbuf, 0); }
if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) {
cptr = get_glyph (cptr, gbuf, 0);
d = get_uint (gbuf, 8, 0177, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | d | (k? 0200: 0); }
else {
d = get_uint (gbuf, 8, 07777, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (d <= 0177) val[0] = val[0] | d;
else if (cflag && (((addr ^ d) & 07600) == 0))
val[0] = val[0] | (d & 0177) | 0200;
else return SCPE_ARG; }
break;
case I_V_NPN: case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
k = opc_val[i] & 07777;
if ((opcode[i] == NULL) || (((k ^ val[0]) & 07000) != 0))
return SCPE_ARG;
val[0] = val[0] | k; }
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
switch (j) { /* case on class */
case I_V_IOT: /* IOT */
cptr = get_glyph (cptr, gbuf, 0); /* get dev+pulse */
d = get_uint (gbuf, 8, 0777, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | d;
break;
case I_V_FLD: /* field */
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] != NULL) {
k = (opc_val[i] >> I_V_FL) & I_M_FL;
if (k != j) return SCPE_ARG;
val[0] = val[0] | (opc_val[i] & 07777);
}
else {
d = get_uint (gbuf, 8, 07, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (d << 3);
break;
}
}
break;
case I_V_MRF: /* mem ref */
cptr = get_glyph (cptr, gbuf, 0); /* get next field */
if (strcmp (gbuf, "I") == 0) { /* indirect? */
val[0] = val[0] | 0400;
cptr = get_glyph (cptr, gbuf, 0);
}
if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) {
cptr = get_glyph (cptr, gbuf, 0);
d = get_uint (gbuf, 8, 0177, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | d | (k? 0200: 0);
}
else {
d = get_uint (gbuf, 8, 07777, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (d <= 0177) val[0] = val[0] | d;
else if (cflag && (((addr ^ d) & 07600) == 0))
val[0] = val[0] | (d & 0177) | 0200;
else return SCPE_ARG;
}
break;
case I_V_NPN: case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */
for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
cptr = get_glyph (cptr, gbuf, 0)) {
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
k = opc_val[i] & 07777;
if ((opcode[i] == NULL) || (((k ^ val[0]) & 07000) != 0))
return SCPE_ARG;
val[0] = val[0] | k;
}
break;
} /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* pdp8_tsc.c: PDP-8 ETOS timesharing option board (TSC8-75)
Copyright (c) 2003-2004, Robert M Supnik
Copyright (c) 2003-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,46 +19,46 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This module is based on Bernhard Baehr's PDP-8/E simulator
PDP-8/E Simulator Source Code
PDP-8/E Simulator Source Code
Copyright ) 2001-2003 Bernhard Baehr
Copyright ) 2001-2003 Bernhard Baehr
TSC8iots.c - IOTs for the TSC8-75 Board plugin
TSC8iots.c - IOTs for the TSC8-75 Board plugin
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
tsc TSC8-75 option board
tsc TSC8-75 option board
*/
#include "pdp8_defs.h"
extern int32 int_req;
extern int32 SF;
extern int32 tsc_ir; /* "ERIOT" */
extern int32 tsc_pc; /* "ERTB" */
extern int32 tsc_cdf; /* "ECDF" */
extern int32 tsc_enb; /* enable */
extern int32 tsc_ir; /* "ERIOT" */
extern int32 tsc_pc; /* "ERTB" */
extern int32 tsc_cdf; /* "ECDF" */
extern int32 tsc_enb; /* enable */
#define UNIT_V_SN699 (UNIT_V_UF + 0) /* SN 699 or above */
#define UNIT_SN699 (1 << UNIT_V_SN699)
#define UNIT_V_SN699 (UNIT_V_UF + 0) /* SN 699 or above */
#define UNIT_SN699 (1 << UNIT_V_SN699)
DEVICE tsc_dev;
int32 tsc (int32 IR, int32 AC);
@@ -66,9 +66,9 @@ t_stat tsc_reset (DEVICE *dptr);
/* TSC data structures
tsc_dev TSC device descriptor
tsc_unit TSC unit descriptor
tsc_reg TSC register list
tsc_dev TSC device descriptor
tsc_unit TSC unit descriptor
tsc_reg TSC register list
*/
DIB tsc_dib = { DEV_TSC, 1, { &tsc } };
@@ -76,57 +76,72 @@ DIB tsc_dib = { DEV_TSC, 1, { &tsc } };
UNIT tsc_unit = { UDATA (NULL, UNIT_SN699, 0) };
REG tsc_reg[] = {
{ ORDATA (IR, tsc_ir, 12) },
{ ORDATA (PC, tsc_pc, 12) },
{ FLDATA (CDF, tsc_cdf, 0) },
{ FLDATA (ENB, tsc_enb, 0) },
{ FLDATA (INT, int_req, INT_V_TSC) },
{ NULL } };
{ ORDATA (IR, tsc_ir, 12) },
{ ORDATA (PC, tsc_pc, 12) },
{ FLDATA (CDF, tsc_cdf, 0) },
{ FLDATA (ENB, tsc_enb, 0) },
{ FLDATA (INT, int_req, INT_V_TSC) },
{ NULL }
};
MTAB tsc_mod[] = {
{ UNIT_SN699, UNIT_SN699, "ESME", "ESME", NULL },
{ UNIT_SN699, 0, "no ESME", "NOESME", NULL },
{ 0 } };
{ UNIT_SN699, UNIT_SN699, "ESME", "ESME", NULL },
{ UNIT_SN699, 0, "no ESME", "NOESME", NULL },
{ 0 }
};
DEVICE tsc_dev = {
"TSC", &tsc_unit, tsc_reg, tsc_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tsc_reset,
NULL, NULL, NULL,
&tsc_dib, DEV_DISABLE | DEV_DIS };
"TSC", &tsc_unit, tsc_reg, tsc_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tsc_reset,
NULL, NULL, NULL,
&tsc_dib, DEV_DISABLE | DEV_DIS
};
/* IOT routine */
int32 tsc (int32 IR, int32 AC)
{
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* ETDS */
tsc_enb = 0; /* disable int req */
int_req = int_req & ~INT_TSC; /* clear flag */
break;
case 1: /* ESKP */
return (int_req & INT_TSC)? IOT_SKP + AC: AC; /* skip on int req */
case 2: /* ECTF */
int_req = int_req & ~INT_TSC; /* clear int req */
break;
case 3: /* ECDF */
AC = AC | ((tsc_ir >> 3) & 07); /* read "ERIOT"<6:8> */
if (tsc_cdf) AC = AC | IOT_SKP; /* if cdf, skip */
tsc_cdf = 0;
break;
case 4: /* ERTB */
return tsc_pc;
case 5: /* ESME */
if (tsc_unit.flags & UNIT_SN699) { /* enabled? */
if (tsc_cdf && ((tsc_ir & 070) >> 3) == (SF & 07)) {
AC = AC | IOT_SKP;
tsc_cdf = 0; } }
break;
case 6: /* ERIOT */
return tsc_ir;
case 7: /* ETEN */
tsc_enb = 1;
break; } /* end switch */
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* ETDS */
tsc_enb = 0; /* disable int req */
int_req = int_req & ~INT_TSC; /* clear flag */
break;
case 1: /* ESKP */
return (int_req & INT_TSC)? IOT_SKP + AC: AC; /* skip on int req */
case 2: /* ECTF */
int_req = int_req & ~INT_TSC; /* clear int req */
break;
case 3: /* ECDF */
AC = AC | ((tsc_ir >> 3) & 07); /* read "ERIOT"<6:8> */
if (tsc_cdf) AC = AC | IOT_SKP; /* if cdf, skip */
tsc_cdf = 0;
break;
case 4: /* ERTB */
return tsc_pc;
case 5: /* ESME */
if (tsc_unit.flags & UNIT_SN699) { /* enabled? */
if (tsc_cdf && ((tsc_ir & 070) >> 3) == (SF & 07)) {
AC = AC | IOT_SKP;
tsc_cdf = 0;
}
}
break;
case 6: /* ERIOT */
return tsc_ir;
case 7: /* ETEN */
tsc_enb = 1;
break;
} /* end switch */
return AC;
}

View File

@@ -1,6 +1,6 @@
/* pdp8_tt.c: PDP-8 console terminal simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,30 +19,30 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
tti,tto KL8E terminal input/output
tti,tto KL8E terminal input/output
28-May-04 RMS Removed SET TTI CTRL-C
29-Dec-03 RMS Added console output backpressure support
25-Apr-03 RMS Revised for extended file support
02-Mar-02 RMS Added SET TTI CTRL-C
22-Dec-02 RMS Added break support
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
28-May-04 RMS Removed SET TTI CTRL-C
29-Dec-03 RMS Added console output backpressure support
25-Apr-03 RMS Revised for extended file support
02-Mar-02 RMS Added SET TTI CTRL-C
22-Dec-02 RMS Added break support
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
*/
#include "pdp8_defs.h"
#include <ctype.h>
#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)
#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;
@@ -53,13 +53,13 @@ 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
tti_dev TTI device descriptor
tti_unit TTI unit descriptor
tti_reg TTI register list
tti_mod TTI modifiers list
tti_dev TTI device descriptor
tti_unit TTI unit descriptor
tti_reg TTI register list
tti_mod TTI modifiers list
*/
DIB tti_dib = { DEV_TTI, 1, { &tti } };
@@ -67,34 +67,37 @@ 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) },
{ FLDATA (DONE, dev_done, INT_V_TTI) },
{ FLDATA (ENABLE, int_enable, INT_V_TTI) },
{ FLDATA (INT, int_req, INT_V_TTI) },
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (UC, tti_unit.flags, UNIT_V_KSR), REG_HRO },
{ NULL } };
{ ORDATA (BUF, tti_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_TTI) },
{ FLDATA (ENABLE, int_enable, INT_V_TTI) },
{ FLDATA (INT, int_req, INT_V_TTI) },
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (UC, tti_unit.flags, UNIT_V_KSR), REG_HRO },
{ NULL }
};
MTAB tti_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, NULL },
{ 0 } };
{ 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, NULL },
{ 0 }
};
DEVICE tti_dev = {
"TTI", &tti_unit, tti_reg, tti_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti_reset,
NULL, NULL, NULL,
&tti_dib, 0 };
"TTI", &tti_unit, tti_reg, tti_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tti_reset,
NULL, NULL, NULL,
&tti_dib, 0
};
/* TTO data structures
tto_dev TTO device descriptor
tto_unit TTO unit descriptor
tto_reg TTO register list
tto_dev TTO device descriptor
tto_unit TTO unit descriptor
tto_reg TTO register list
*/
DIB tto_dib = { DEV_TTO, 1, { &tto } };
@@ -102,56 +105,66 @@ 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) },
{ FLDATA (DONE, dev_done, INT_V_TTO) },
{ FLDATA (ENABLE, int_enable, INT_V_TTO) },
{ FLDATA (INT, int_req, INT_V_TTO) },
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
{ NULL } };
{ ORDATA (BUF, tto_unit.buf, 8) },
{ FLDATA (DONE, dev_done, INT_V_TTO) },
{ FLDATA (ENABLE, int_enable, INT_V_TTO) },
{ FLDATA (INT, int_req, INT_V_TTO) },
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
{ 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 } };
{ 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, tto_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto_reset,
NULL, NULL, NULL,
&tto_dib, 0 };
"TTO", &tto_unit, tto_reg, tto_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &tto_reset,
NULL, NULL, NULL,
&tto_dib, 0
};
/* Terminal input: IOT routine */
int32 tti (int32 IR, int32 AC)
{
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* KCF */
dev_done = dev_done & ~INT_TTI; /* clear flag */
int_req = int_req & ~INT_TTI;
return AC;
case 1: /* KSF */
return (dev_done & INT_TTI)? IOT_SKP + AC: AC;
case 2: /* KCC */
dev_done = dev_done & ~INT_TTI; /* clear flag */
int_req = int_req & ~INT_TTI;
return 0; /* clear AC */
case 4: /* KRS */
return (AC | tti_unit.buf); /* return buffer */
case 5: /* KIE */
if (AC & 1) int_enable = int_enable | (INT_TTI+INT_TTO);
else int_enable = int_enable & ~(INT_TTI+INT_TTO);
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 6: /* KRB */
dev_done = dev_done & ~INT_TTI; /* clear flag */
int_req = int_req & ~INT_TTI;
return (tti_unit.buf); /* return buffer */
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* KCF */
dev_done = dev_done & ~INT_TTI; /* clear flag */
int_req = int_req & ~INT_TTI;
return AC;
case 1: /* KSF */
return (dev_done & INT_TTI)? IOT_SKP + AC: AC;
case 2: /* KCC */
dev_done = dev_done & ~INT_TTI; /* clear flag */
int_req = int_req & ~INT_TTI;
return 0; /* clear AC */
case 4: /* KRS */
return (AC | tti_unit.buf); /* return buffer */
case 5: /* KIE */
if (AC & 1) int_enable = int_enable | (INT_TTI+INT_TTO);
else int_enable = int_enable & ~(INT_TTI+INT_TTO);
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 6: /* KRB */
dev_done = dev_done & ~INT_TTI; /* clear flag */
int_req = int_req & ~INT_TTI;
return (tti_unit.buf); /* return buffer */
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
}
/* Unit service */
@@ -160,17 +173,18 @@ t_stat tti_svc (UNIT *uptr)
{
int32 c;
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
if (c & SCPE_BREAK) tti_unit.buf = 0; /* break? */
else if (tti_unit.flags & UNIT_KSR) { /* KSR? */
c = c & 0177;
if (islower (c)) c = toupper (c);
tti_unit.buf = c | 0200; } /* add TTY bit */
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */
if (c & SCPE_BREAK) tti_unit.buf = 0; /* break? */
else if (tti_unit.flags & UNIT_KSR) { /* KSR? */
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);
tti_unit.pos = tti_unit.pos + 1;
dev_done = dev_done | INT_TTI; /* set done */
int_req = INT_UPDATE; /* update interrupts */
dev_done = dev_done | INT_TTI; /* set done */
int_req = INT_UPDATE; /* update interrupts */
return SCPE_OK;
}
@@ -179,39 +193,46 @@ return SCPE_OK;
t_stat tti_reset (DEVICE *dptr)
{
tti_unit.buf = 0;
dev_done = dev_done & ~INT_TTI; /* clear done, int */
dev_done = dev_done & ~INT_TTI; /* clear done, int */
int_req = int_req & ~INT_TTI;
int_enable = int_enable | INT_TTI; /* set enable */
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
int_enable = int_enable | INT_TTI; /* set enable */
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
return SCPE_OK;
}
/* Terminal output: IOT routine */
int32 tto (int32 IR, int32 AC)
{
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* TLF */
dev_done = dev_done | INT_TTO; /* set flag */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 1: /* TSF */
return (dev_done & INT_TTO)? IOT_SKP + AC: AC;
case 2: /* TCF */
dev_done = dev_done & ~INT_TTO; /* clear flag */
int_req = int_req & ~INT_TTO; /* clear int req */
return AC;
case 5: /* SPI */
return (int_req & (INT_TTI+INT_TTO))? IOT_SKP + AC: AC;
case 6: /* TLS */
dev_done = dev_done & ~INT_TTO; /* clear flag */
int_req = int_req & ~INT_TTO; /* clear int req */
case 4: /* TPC */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
tto_unit.buf = AC; /* load buffer */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
switch (IR & 07) { /* decode IR<9:11> */
case 0: /* TLF */
dev_done = dev_done | INT_TTO; /* set flag */
int_req = INT_UPDATE; /* update interrupts */
return AC;
case 1: /* TSF */
return (dev_done & INT_TTO)? IOT_SKP + AC: AC;
case 2: /* TCF */
dev_done = dev_done & ~INT_TTO; /* clear flag */
int_req = int_req & ~INT_TTO; /* clear int req */
return AC;
case 5: /* SPI */
return (int_req & (INT_TTI+INT_TTO))? IOT_SKP + AC: AC;
case 6: /* TLS */
dev_done = dev_done & ~INT_TTO; /* clear flag */
int_req = int_req & ~INT_TTO; /* clear int req */
case 4: /* TPC */
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
tto_unit.buf = AC; /* load buffer */
return AC;
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
}
/* Unit service */
@@ -221,15 +242,17 @@ t_stat tto_svc (UNIT *uptr)
int32 c;
t_stat r;
if (tto_unit.flags & UNIT_KSR) { /* UC only? */
c = tto_unit.buf & 0177;
if (islower (c)) c = toupper (c); }
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_s (c)) != SCPE_OK) { /* output char; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* if !stall, report */
dev_done = dev_done | INT_TTO; /* set done */
int_req = INT_UPDATE; /* update interrupts */
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output char; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); /* if !stall, report */
}
dev_done = dev_done | INT_TTO; /* set done */
int_req = INT_UPDATE; /* update interrupts */
tto_unit.pos = tto_unit.pos + 1;
return SCPE_OK;
}
@@ -239,10 +262,10 @@ return SCPE_OK;
t_stat tto_reset (DEVICE *dptr)
{
tto_unit.buf = 0;
dev_done = dev_done & ~INT_TTO; /* clear done, int */
dev_done = dev_done & ~INT_TTO; /* clear done, int */
int_req = int_req & ~INT_TTO;
int_enable = int_enable | INT_TTO; /* set enable */
sim_cancel (&tto_unit); /* deactivate unit */
int_enable = int_enable | INT_TTO; /* set enable */
sim_cancel (&tto_unit); /* deactivate unit */
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp8_ttx.c: PDP-8 additional terminals simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -19,22 +19,25 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ttix,ttox PT08/KL8JA terminal input/output
ttix,ttox PT08/KL8JA terminal input/output
05-Jan-04 RMS Revised for tmxr library changes
09-May-03 RMS Added network device flag
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
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
29-Jun-05 RMS Added SET TTOXn DISCONNECT
Fixed bug in SET LOG/NOLOG
21-Jun-05 RMS Fixed bug in SHOW CONN/STATS
05-Jan-04 RMS Revised for tmxr library changes
09-May-03 RMS Added network device flag
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
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
This module implements four individual serial interfaces similar in function
to the console. These interfaces are mapped to Telnet based connections as
@@ -47,23 +50,23 @@
#include "sim_tmxr.h"
#include <ctype.h>
#define TTX_LINES 4
#define TTX_MASK (TTX_LINES - 1)
#define TTX_LINES 4
#define TTX_MASK (TTX_LINES - 1)
#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 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)
#define TTX_GETLN(x) (((x) >> 4) & TTX_MASK)
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 = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */
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 = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */
DEVICE ttix_dev, ttox_dev;
int32 ttix (int32 IR, int32 AC);
@@ -77,121 +80,139 @@ 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
ttix_dev TTIx device descriptor
ttix_unit TTIx unit descriptor
ttix_reg TTIx register list
ttix_mod TTIx modifiers list
ttix_dev TTIx device descriptor
ttix_unit TTIx unit descriptor
ttix_reg TTIx register list
ttix_mod TTIx modifiers list
*/
DIB ttix_dib = { DEV_KJ8, 8,
{ &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } };
{ &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } };
UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT };
REG ttix_reg[] = {
{ BRDATA (BUF, ttix_buf, 8, 8, TTX_LINES) },
{ GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1) },
{ GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1) },
{ 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 },
{ ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },
{ NULL } };
{ BRDATA (BUF, ttix_buf, 8, 8, TTX_LINES) },
{ GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTI1) },
{ GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTI1) },
{ 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 },
{ ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO },
{ NULL }
};
MTAB ttix_mod[] = {
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &ttx_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &ttx_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &ttx_show, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
&set_dev, &show_dev, NULL },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &ttx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &ttx_desc },
{ 0 } };
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &ttx_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &ttx_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &ttx_show, NULL },
{ 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,
&ttix_dib, DEV_NET | DEV_DISABLE };
"TTIX", &ttix_unit, ttix_reg, ttix_mod,
1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &ttix_reset,
NULL, &ttx_attach, &ttx_detach,
&ttix_dib, DEV_NET | DEV_DISABLE
};
/* TTOx data structures
ttox_dev TTOx device descriptor
ttox_unit TTOx unit descriptor
ttox_reg TTOx register list
ttox_dev TTOx device descriptor
ttox_unit TTOx unit descriptor
ttox_reg TTOx register list
*/
UNIT ttox_unit[] = {
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT } };
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }
};
REG ttox_reg[] = {
{ BRDATA (BUF, ttox_buf, 8, 8, TTX_LINES) },
{ GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1) },
{ GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1) },
{ GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) },
{ URDATA (TIME, ttox_unit[0].wait, 10, 24, 0,
TTX_LINES, PV_LEFT) },
{ NULL } };
{ BRDATA (BUF, ttox_buf, 8, 8, TTX_LINES) },
{ GRDATA (DONE, dev_done, 8, TTX_LINES, INT_V_TTO1) },
{ GRDATA (ENABLE, int_enable, 8, TTX_LINES, INT_V_TTO1) },
{ GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) },
{ URDATA (TIME, ttox_unit[0].wait, 10, 24, 0,
TTX_LINES, PV_LEFT) },
{ NULL }
};
MTAB ttox_mod[] = {
{ 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 } };
{ 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 },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &ttx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &ttx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &ttx_desc },
{ 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, DEV_DISABLE };
"TTOX", ttox_unit, ttox_reg, ttox_mod,
4, 10, 31, 1, 8, 8,
NULL, NULL, &ttox_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE
};
/* Terminal input: IOT routine */
int32 ttix (int32 inst, int32 AC)
{
int32 pulse = inst & 07; /* IOT pulse */
int32 ln = TTX_GETLN (inst); /* line # */
int32 itti = (INT_TTI1 << ln); /* rx intr */
int32 itto = (INT_TTO1 << ln); /* tx intr */
int32 pulse = inst & 07; /* IOT pulse */
int32 ln = TTX_GETLN (inst); /* line # */
int32 itti = (INT_TTI1 << ln); /* rx intr */
int32 itto = (INT_TTO1 << ln); /* tx intr */
switch (pulse) { /* case IR<9:11> */
case 0: /* KCF */
dev_done = dev_done & ~itti; /* clear flag */
int_req = int_req & ~itti;
break;
case 1: /* KSF */
return (dev_done & itti)? IOT_SKP + AC: AC;
case 2: /* KCC */
dev_done = dev_done & ~itti; /* clear flag */
int_req = int_req & ~itti;
return 0; /* clear AC */
case 4: /* KRS */
return (AC | ttix_buf[ln]); /* return buf */
case 5: /* KIE */
if (AC & 1) int_enable = int_enable | (itti + itto);
else int_enable = int_enable & ~(itti + itto);
int_req = INT_UPDATE; /* update intr */
break;
case 6: /* KRB */
dev_done = dev_done & ~itti; /* clear flag */
int_req = int_req & ~itti;
return ttix_buf[ln]; /* return buf */
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
switch (pulse) { /* case IR<9:11> */
case 0: /* KCF */
dev_done = dev_done & ~itti; /* clear flag */
int_req = int_req & ~itti;
break;
case 1: /* KSF */
return (dev_done & itti)? IOT_SKP + AC: AC;
case 2: /* KCC */
dev_done = dev_done & ~itti; /* clear flag */
int_req = int_req & ~itti;
return 0; /* clear AC */
case 4: /* KRS */
return (AC | ttix_buf[ln]); /* return buf */
case 5: /* KIE */
if (AC & 1) int_enable = int_enable | (itti + itto);
else int_enable = int_enable & ~(itti + itto);
int_req = INT_UPDATE; /* update intr */
break;
case 6: /* KRB */
dev_done = dev_done & ~itti; /* clear flag */
int_req = int_req & ~itti;
return ttix_buf[ln]; /* return buf */
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
return AC;
}
@@ -201,24 +222,27 @@ t_stat ttix_svc (UNIT *uptr)
{
int32 ln, c, temp;
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); /* 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 */
if (temp & SCPE_BREAK) c = 0; /* break? */
else if (ttox_unit[ln].flags & UNIT_UC) { /* UC? */
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; } } }
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); /* look for connect */
if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enb*/
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 */
if (temp & SCPE_BREAK) c = 0; /* break? */
else if (ttox_unit[ln].flags & UNIT_UC) { /* UC? */
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;
}
}
}
return SCPE_OK;
}
@@ -228,52 +252,63 @@ 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 */
else sim_cancel (&ttix_unit); /* else stop */
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
ttix_buf[ln] = 0; /* clear buf, */
itto = (INT_TTI1 << ln); /* interrupt */
dev_done = dev_done & ~itto; /* clr done, int */
int_req = int_req & ~itto;
int_enable = int_enable | itto; } /* set enable */
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 */
}
}
else sim_cancel (&ttix_unit); /* else stop */
for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */
ttix_buf[ln] = 0; /* clear buf, */
itto = (INT_TTI1 << ln); /* interrupt */
dev_done = dev_done & ~itto; /* clr done, int */
int_req = int_req & ~itto;
int_enable = int_enable | itto; /* set enable */
}
return SCPE_OK;
}
/* Terminal output: IOT routine */
int32 ttox (int32 inst, int32 AC)
{
int32 pulse = inst & 07; /* pulse */
int32 ln = TTX_GETLN (inst); /* line # */
int32 itti = (INT_TTI1 << ln); /* rx intr */
int32 itto = (INT_TTO1 << ln); /* tx intr */
int32 pulse = inst & 07; /* pulse */
int32 ln = TTX_GETLN (inst); /* line # */
int32 itti = (INT_TTI1 << ln); /* rx intr */
int32 itto = (INT_TTO1 << ln); /* tx intr */
switch (pulse) { /* case IR<9:11> */
case 0: /* TLF */
dev_done = dev_done | itto; /* set flag */
int_req = INT_UPDATE; /* update intr */
break;
case 1: /* TSF */
return (dev_done & itto)? IOT_SKP + AC: AC;
case 2: /* TCF */
dev_done = dev_done & ~itto; /* clear flag */
int_req = int_req & ~itto; /* clear intr */
break;
case 5: /* SPI */
return (int_req & (itti | itto))? IOT_SKP + AC: AC;
case 6: /* TLS */
dev_done = dev_done & ~itto; /* clear flag */
int_req = int_req & ~itto; /* clear int req */
case 4: /* TPC */
sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */
ttox_buf[ln] = AC & 0377; /* load buffer */
break;
default:
return (stop_inst << IOT_V_REASON) + AC;
} /* end switch */
switch (pulse) { /* case IR<9:11> */
case 0: /* TLF */
dev_done = dev_done | itto; /* set flag */
int_req = INT_UPDATE; /* update intr */
break;
case 1: /* TSF */
return (dev_done & itto)? IOT_SKP + AC: AC;
case 2: /* TCF */
dev_done = dev_done & ~itto; /* clear flag */
int_req = int_req & ~itto; /* clear intr */
break;
case 5: /* SPI */
return (int_req & (itti | itto))? IOT_SKP + AC: AC;
case 6: /* TLS */
dev_done = dev_done & ~itto; /* clear flag */
int_req = int_req & ~itto; /* clear int req */
case 4: /* TPC */
sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */
ttox_buf[ln] = AC & 0377; /* load buffer */
break;
default:
return (stop_inst << IOT_V_REASON) + AC; } /* end switch */
return AC;
}
@@ -281,23 +316,27 @@ return AC;
t_stat ttox_svc (UNIT *uptr)
{
int32 c, ln = uptr - ttox_unit; /* line # */
int32 c, ln = uptr - ttox_unit; /* line # */
if (ttx_ldsc[ln].conn) { /* connected? */
if (ttx_ldsc[ln].xmte) { /* tx enabled? */
TMLN *lp = &ttx_ldsc[ln]; /* get line */
if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */
c = ttox_buf[ln] & 0177; /* get char */
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 */
if (ttx_ldsc[ln].conn) { /* connected? */
if (ttx_ldsc[ln].xmte) { /* tx enabled? */
TMLN *lp = &ttx_ldsc[ln]; /* get line */
if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */
c = ttox_buf[ln] & 0177; /* get char */
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;
}
@@ -307,17 +346,18 @@ 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 */
dev_done = dev_done & ~itto; /* clr done, int */
int_req = int_req & ~itto;
int_enable = int_enable | itto; /* set enable */
sim_cancel (&ttox_unit[ln]); } /* deactivate */
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 */
dev_done = dev_done & ~itto; /* clr done, int */
int_req = int_req & ~itto;
int_enable = int_enable | itto; /* set enable */
sim_cancel (&ttox_unit[ln]); /* deactivate */
}
return SCPE_OK;
}
/* Attach master unit */
t_stat ttx_attach (UNIT *uptr, char *cptr)
@@ -325,10 +365,10 @@ t_stat ttx_attach (UNIT *uptr, char *cptr)
int32 t;
t_stat r;
r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init calib */
sim_activate (uptr, t); /* start poll */
r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init calib */
sim_activate (uptr, t); /* start poll */
return SCPE_OK;
}
@@ -339,10 +379,11 @@ t_stat ttx_detach (UNIT *uptr)
int32 i;
t_stat r;
r = tmxr_detach (&ttx_desc, uptr); /* detach */
for (i = 0; i < TTX_LINES; i++) { /* all lines, */
ttx_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (&ttox_unit[i]); } /* stop poll */
r = tmxr_detach (&ttx_desc, uptr); /* detach */
for (i = 0; i < TTX_LINES; i++) { /* all lines, */
ttx_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (&ttox_unit[i]); /* stop poll */
}
return r;
}
@@ -362,14 +403,17 @@ return SCPE_OK;
t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i;
int32 i, t;
for (i = 0; (i < TTX_LINES) && (ttx_ldsc[i].conn == 0); i++) ;
if (i < TTX_LINES) {
for (i = 0; i < TTX_LINES; i++) {
if (ttx_ldsc[i].conn)
if (val) tmxr_fconns (st, &ttx_ldsc[i], i);
else tmxr_fstats (st, &ttx_ldsc[i], i); } }
for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);
if (t) {
for (i = 0; i < TTX_LINES; i++) {
if (ttx_ldsc[i].conn) {
if (val) tmxr_fconns (st, &ttx_ldsc[i], i);
else tmxr_fstats (st, &ttx_ldsc[i], i);
}
}
}
else fprintf (st, "all disconnected\n");
return SCPE_OK;
}
@@ -379,9 +423,12 @@ return SCPE_OK;
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; }
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;
}