HP3000: Third HP 3000 release from Dave Bryan
This commit is contained in:
parent
9925ba83b8
commit
e370b9e78e
20 changed files with 1632 additions and 519 deletions
|
@ -26,6 +26,9 @@
|
||||||
|
|
||||||
ATCD,ATCC HP 30032B Asynchronous Terminal Controller
|
ATCD,ATCC HP 30032B Asynchronous Terminal Controller
|
||||||
|
|
||||||
|
16-Sep-16 JDB Fixed atcd_detach to skip channel cancel if SIM_SW_REST
|
||||||
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
|
20-Jul-16 JDB Corrected poll_unit "wait" field initializer.
|
||||||
26-Jun-16 JDB Removed tmxr_set_modem_control_passthru call in atcc_reset
|
26-Jun-16 JDB Removed tmxr_set_modem_control_passthru call in atcc_reset
|
||||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||||
16-May-16 JDB Fixed interrupt mask setting
|
16-May-16 JDB Fixed interrupt mask setting
|
||||||
|
@ -895,7 +898,7 @@ static UNIT atcd_unit [UNIT_COUNT] = {
|
||||||
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
||||||
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
||||||
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
||||||
{ UDATA (&poll_service, UNIT_ATTABLE | UNIT_DIS | UNIT_IDLE, POLL_TIME) } /* multiplexer poll unit */
|
{ UDATA (&poll_service, UNIT_ATTABLE | UNIT_DIS | UNIT_IDLE, 0), POLL_TIME } /* multiplexer poll unit */
|
||||||
};
|
};
|
||||||
|
|
||||||
static UNIT atcc_unit [] = { /* a dummy unit to satisfy SCP requirements */
|
static UNIT atcc_unit [] = { /* a dummy unit to satisfy SCP requirements */
|
||||||
|
@ -935,7 +938,8 @@ static REG atcd_reg [] = {
|
||||||
{ BRDATA (SPARM, send_param, 8, 16, SEND_CHAN_COUNT) },
|
{ BRDATA (SPARM, send_param, 8, 16, SEND_CHAN_COUNT) },
|
||||||
{ BRDATA (SBUFR, send_buffer, 8, 16, SEND_CHAN_COUNT), REG_A },
|
{ BRDATA (SBUFR, send_buffer, 8, 16, SEND_CHAN_COUNT), REG_A },
|
||||||
{ FLDATA (POLL, atc_is_polling, 0), REG_HRO },
|
{ FLDATA (POLL, atc_is_polling, 0), REG_HRO },
|
||||||
{ SRDATA (DIB, atcd_dib, REG_HRO) },
|
|
||||||
|
DIB_REGS (atcd_dib),
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -959,7 +963,7 @@ static REG atcc_reg [] = {
|
||||||
{ FBDATA (MS2, cntl_param, 1, TERM_COUNT, PV_RZRO) },
|
{ FBDATA (MS2, cntl_param, 1, TERM_COUNT, PV_RZRO) },
|
||||||
{ FBDATA (MS1, cntl_param, 0, TERM_COUNT, PV_RZRO) },
|
{ FBDATA (MS1, cntl_param, 0, TERM_COUNT, PV_RZRO) },
|
||||||
|
|
||||||
{ SRDATA (DIB, atcc_dib, REG_HRO) },
|
DIB_REGS (atcc_dib),
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -1810,14 +1814,17 @@ return status;
|
||||||
|
|
||||||
Normally, this routine is called by the DETACH ATCD command, which is
|
Normally, this routine is called by the DETACH ATCD command, which is
|
||||||
equivalent to DETACH ATCD0. However, it may be called with other units in
|
equivalent to DETACH ATCD0. However, it may be called with other units in
|
||||||
two cases.
|
three cases.
|
||||||
|
|
||||||
A DETACH ALL command will call us for unit 16 (the poll unit) if it is
|
A DETACH ALL command will call us for unit 16 (the poll unit) if it is
|
||||||
attached. Also, during simulator shutdown, we will be called for units 0-15
|
attached. A RESTORE command also will call us for unit 16 if it is attached.
|
||||||
(detach_all in scp.c calls the detach routines of all units that do NOT have
|
In the latter case, the terminal channels will have already been rescheduled
|
||||||
UNIT_ATTABLE), as well as for unit 16 if it is attached. In both cases, it
|
as appropriate, so canceling them is skipped. Also, during simulator
|
||||||
is imperative that we return SCPE_OK; otherwise any remaining device detaches
|
shutdown, we will be called for units 0-15 (detach_all in scp.c calls the
|
||||||
will not be performed.
|
detach routines of all units that do NOT have UNIT_ATTABLE), as well as for
|
||||||
|
unit 16 if it is attached. In all cases, it is imperative that we not reject
|
||||||
|
the request for unit 16; otherwise any remaining device detaches will not be
|
||||||
|
performed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat atcd_detach (UNIT *uptr)
|
static t_stat atcd_detach (UNIT *uptr)
|
||||||
|
@ -1828,7 +1835,8 @@ t_stat status = SCPE_OK;
|
||||||
if (uptr == line_unit || uptr == &poll_unit) { /* if we're detaching the base unit or poll unit */
|
if (uptr == line_unit || uptr == &poll_unit) { /* if we're detaching the base unit or poll unit */
|
||||||
status = tmxr_detach (&atcd_mdsc, &poll_unit); /* then detach the listening port */
|
status = tmxr_detach (&atcd_mdsc, &poll_unit); /* then detach the listening port */
|
||||||
|
|
||||||
for (channel = 0; channel < TERM_COUNT; channel++) { /* for each terminal channel */
|
if ((sim_switches & SIM_SW_REST) == 0) /* if this is not a RESTORE call */
|
||||||
|
for (channel = 0; channel < TERM_COUNT; channel++) { /* then for each terminal channel */
|
||||||
atcd_ldsc [channel].rcve = FALSE; /* disable reception */
|
atcd_ldsc [channel].rcve = FALSE; /* disable reception */
|
||||||
sim_cancel (&line_unit [channel]); /* and cancel any transfer in progress */
|
sim_cancel (&line_unit [channel]); /* and cancel any transfer in progress */
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@
|
||||||
|
|
||||||
CLK HP 30135A System Clock/Fault Logging Interface
|
CLK HP 30135A System Clock/Fault Logging Interface
|
||||||
|
|
||||||
08-Jul-16 JDB Preset the unit wait field
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
|
11-Jul-16 JDB Change "clk_unit" from a UNIT to an array of one UNIT
|
||||||
|
08-Jul-16 JDB Added REG entry to save the unit wait field
|
||||||
09-Jun-16 JDB Clarified the IRQ FF set code in DRESETINT
|
09-Jun-16 JDB Clarified the IRQ FF set code in DRESETINT
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
21-Mar-16 JDB Changed inbound_value and outbound_value types to HP_WORD
|
21-Mar-16 JDB Changed inbound_value and outbound_value types to HP_WORD
|
||||||
|
@ -392,15 +394,15 @@ static DIB clk_dib = {
|
||||||
|
|
||||||
/* Unit list */
|
/* Unit list */
|
||||||
|
|
||||||
static UNIT clk_unit = {
|
static UNIT clk_unit [] = {
|
||||||
UDATA (&clk_service, UNIT_IDLE | UNIT_CALTIME, 0), mS (1)
|
{ UDATA (&clk_service, UNIT_IDLE | UNIT_CALTIME, 0) }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Register list */
|
/* Register list */
|
||||||
|
|
||||||
static REG clk_reg [] = {
|
static REG clk_reg [] = {
|
||||||
/* Macro Name Location Width Offset Flags */
|
/* Macro Name Location Width Offset Flags */
|
||||||
/* ------ ------ --------------- ----- ------ ------- */
|
/* ------ ------ ----------------- ----- ------ ------------------ */
|
||||||
{ ORDATA (CNTL, control_word, 16) },
|
{ ORDATA (CNTL, control_word, 16) },
|
||||||
{ ORDATA (STAT, status_word, 16) },
|
{ ORDATA (STAT, status_word, 16) },
|
||||||
{ ORDATA (COUNT, count_register, 16) },
|
{ ORDATA (COUNT, count_register, 16) },
|
||||||
|
@ -409,11 +411,15 @@ static REG clk_reg [] = {
|
||||||
{ FLDATA (SYSIRQ, system_irq, 0) },
|
{ FLDATA (SYSIRQ, system_irq, 0) },
|
||||||
{ FLDATA (LIMIRQ, limit_irq, 0) },
|
{ FLDATA (LIMIRQ, limit_irq, 0) },
|
||||||
{ FLDATA (OVFIRQ, lost_tick_irq, 0) },
|
{ FLDATA (OVFIRQ, lost_tick_irq, 0) },
|
||||||
|
|
||||||
{ DRDATA (SCALE, prescaler, 16), REG_HRO },
|
{ DRDATA (SCALE, prescaler, 16), REG_HRO },
|
||||||
{ DRDATA (INCR, increment, 16), REG_HRO },
|
{ DRDATA (INCR, increment, 16), REG_HRO },
|
||||||
{ FLDATA (COSOK, coschedulable, 0), REG_HRO },
|
{ FLDATA (COSOK, coschedulable, 0), REG_HRO },
|
||||||
{ FLDATA (COSCH, coscheduled, 0), REG_HRO },
|
{ FLDATA (COSCH, coscheduled, 0), REG_HRO },
|
||||||
{ SRDATA (DIB, clk_dib, REG_HRO) },
|
{ DRDATA (UWAIT, clk_unit [0].wait, 32), PV_LEFT | REG_HRO },
|
||||||
|
|
||||||
|
DIB_REGS (clk_dib),
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -445,7 +451,7 @@ static DEBTAB clk_deb [] = {
|
||||||
|
|
||||||
DEVICE clk_dev = {
|
DEVICE clk_dev = {
|
||||||
"CLK", /* device name */
|
"CLK", /* device name */
|
||||||
&clk_unit, /* unit array */
|
clk_unit, /* unit array */
|
||||||
clk_reg, /* register array */
|
clk_reg, /* register array */
|
||||||
clk_mod, /* modifier array */
|
clk_mod, /* modifier array */
|
||||||
1, /* number of units */
|
1, /* number of units */
|
||||||
|
@ -494,10 +500,10 @@ void clk_update_counter (void)
|
||||||
int32 elapsed, ticks;
|
int32 elapsed, ticks;
|
||||||
|
|
||||||
if (coscheduled) { /* if the clock is coscheduled, then adjust the count */
|
if (coscheduled) { /* if the clock is coscheduled, then adjust the count */
|
||||||
elapsed = clk_unit.wait /* the elapsed time is the original wait time */
|
elapsed = clk_unit [0].wait /* the elapsed time is the original wait time */
|
||||||
- sim_activate_time (&clk_unit); /* less the time remaining before the next service */
|
- sim_activate_time (&clk_unit [0]); /* less the time remaining before the next service */
|
||||||
|
|
||||||
ticks = (elapsed * CLK_MULTIPLIER) / clk_unit.wait /* the adjustment is the elapsed fraction of the multiplier */
|
ticks = (elapsed * CLK_MULTIPLIER) / clk_unit [0].wait /* the adjustment is the elapsed fraction of the multiplier */
|
||||||
- (CLK_MULTIPLIER - increment); /* less the amount of any adjustment already made */
|
- (CLK_MULTIPLIER - increment); /* less the amount of any adjustment already made */
|
||||||
|
|
||||||
count_register = count_register + ticks & R_MASK; /* update the clock counter with rollover */
|
count_register = count_register + ticks & R_MASK; /* update the clock counter with rollover */
|
||||||
|
@ -568,16 +574,16 @@ while (working_set) {
|
||||||
if (control_word & CN_RESET_LOAD_SEL) { /* if the reset/load selector is set */
|
if (control_word & CN_RESET_LOAD_SEL) { /* if the reset/load selector is set */
|
||||||
rate = CN_RATE (control_word); /* then load the clock rate */
|
rate = CN_RATE (control_word); /* then load the clock rate */
|
||||||
|
|
||||||
if (clk_unit.flags & UNIT_CALTIME) /* if in calibrated timing mode */
|
if (clk_unit [0].flags & UNIT_CALTIME) /* if in calibrated timing mode */
|
||||||
prescaler = scale [rate]; /* then set the prescaler */
|
prescaler = scale [rate]; /* then set the prescaler */
|
||||||
else /* otherwise */
|
else /* otherwise */
|
||||||
prescaler = 1; /* the prescaler isn't used */
|
prescaler = 1; /* the prescaler isn't used */
|
||||||
|
|
||||||
sim_cancel (&clk_unit); /* changing the rate restarts the timing divider */
|
sim_cancel (&clk_unit [0]); /* changing the rate restarts the timing divider */
|
||||||
|
|
||||||
if (rate > 0) { /* if the rate is valid */
|
if (rate > 0) { /* if the rate is valid */
|
||||||
clk_unit.wait = delay [rate]; /* then set the initial service delay */
|
clk_unit [0].wait = delay [rate]; /* then set the initial service delay */
|
||||||
sim_rtcn_init (clk_unit.wait, TMR_CLK); /* initialize the clock */
|
sim_rtcn_init (clk_unit [0].wait, TMR_CLK); /* initialize the clock */
|
||||||
resync_clock (); /* and reschedule the service */
|
resync_clock (); /* and reschedule the service */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -915,22 +921,22 @@ static void resync_clock (void)
|
||||||
coschedulable = (ticks [rate] == 1000 /* the clock can be coscheduled if the rate */
|
coschedulable = (ticks [rate] == 1000 /* the clock can be coscheduled if the rate */
|
||||||
&& limit_register == 100); /* is 1 msec and the limit is 100 ticks */
|
&& limit_register == 100); /* is 1 msec and the limit is 100 ticks */
|
||||||
|
|
||||||
if (clk_unit.flags & UNIT_CALTIME /* if the clock is in calibrated timing mode */
|
if (clk_unit [0].flags & UNIT_CALTIME /* if the clock is in calibrated timing mode */
|
||||||
&& coschedulable /* and may be coscheduled with the process clock */
|
&& coschedulable /* and may be coscheduled with the process clock */
|
||||||
&& cpu_is_calibrated) { /* and the process clock is calibrated */
|
&& cpu_is_calibrated) { /* and the process clock is calibrated */
|
||||||
clk_unit.wait = sim_activate_time (cpu_pclk_uptr); /* then synchronize with it */
|
clk_unit [0].wait = sim_activate_time (cpu_pclk_uptr); /* then synchronize with it */
|
||||||
coscheduled = TRUE; /* the clock is coscheduled with the process clock */
|
coscheduled = TRUE; /* the clock is coscheduled with the process clock */
|
||||||
}
|
}
|
||||||
|
|
||||||
else { /* otherwise */
|
else { /* otherwise */
|
||||||
clk_unit.wait = delay [rate]; /* set up an independent clock */
|
clk_unit [0].wait = delay [rate]; /* set up an independent clock */
|
||||||
coscheduled = FALSE; /* the clock is not coscheduled with the process clock */
|
coscheduled = FALSE; /* the clock is not coscheduled with the process clock */
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf (clk_dev, DEB_PSERV, "Rate %s delay %d service rescheduled\n",
|
dprintf (clk_dev, DEB_PSERV, "Rate %s delay %d service rescheduled\n",
|
||||||
rate_name [rate], clk_unit.wait);
|
rate_name [rate], clk_unit [0].wait);
|
||||||
|
|
||||||
sim_activate_abs (&clk_unit, clk_unit.wait); /* restart the clock */
|
sim_activate_abs (&clk_unit [0], clk_unit [0].wait); /* restart the clock */
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,6 +23,12 @@
|
||||||
in advertising or otherwise to promote the sale, use or other dealings in
|
in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
this Software without prior written authorization from the author.
|
this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
12-Sep-16 JDB Added the PCN_SERIES_II and PCN_SERIES_III constants
|
||||||
|
02-Sep-16 JDB Added the POWER_STATE enumeration type, the UNIT_PFARS
|
||||||
|
flag, and the "cpu_power_state" external declaration
|
||||||
|
24-Aug-16 JDB Fixed the UNIT_CPU_MODEL test macro
|
||||||
|
23-Aug-16 JDB Added the MOD (module control) register
|
||||||
|
12-Jul-16 JDB Renamed "loading" EXEC_STATE to "waiting"
|
||||||
21-Mar-16 JDB Changed cpu_ccb_table type from uint16 to HP_WORD
|
21-Mar-16 JDB Changed cpu_ccb_table type from uint16 to HP_WORD
|
||||||
14-Feb-16 JDB First release version
|
14-Feb-16 JDB First release version
|
||||||
11-Dec-12 JDB Created
|
11-Dec-12 JDB Created
|
||||||
|
@ -73,6 +79,7 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
|
||||||
#define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* the CPU model (1 bit) */
|
#define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* the CPU model (1 bit) */
|
||||||
#define UNIT_EIS_SHIFT (UNIT_V_UF + 1) /* the Extended Instruction Set firmware option */
|
#define UNIT_EIS_SHIFT (UNIT_V_UF + 1) /* the Extended Instruction Set firmware option */
|
||||||
#define UNIT_CALTIME_SHIFT (UNIT_V_UF + 2) /* the process clock timing mode */
|
#define UNIT_CALTIME_SHIFT (UNIT_V_UF + 2) /* the process clock timing mode */
|
||||||
|
#define UNIT_PFARS_SHIFT (UNIT_V_UF + 3) /* the power-fail auto-restart mode */
|
||||||
|
|
||||||
#define UNIT_MODEL_MASK 0000001u /* model ID mask */
|
#define UNIT_MODEL_MASK 0000001u /* model ID mask */
|
||||||
|
|
||||||
|
@ -82,11 +89,14 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
|
||||||
#define UNIT_SERIES_II (1u << UNIT_MODEL_SHIFT) /* the CPU is a Series II */
|
#define UNIT_SERIES_II (1u << UNIT_MODEL_SHIFT) /* the CPU is a Series II */
|
||||||
#define UNIT_EIS (1u << UNIT_EIS_SHIFT) /* the Extended Instruction Set is installed */
|
#define UNIT_EIS (1u << UNIT_EIS_SHIFT) /* the Extended Instruction Set is installed */
|
||||||
#define UNIT_CALTIME (1u << UNIT_CALTIME_SHIFT) /* the process clock is calibrated to wall time */
|
#define UNIT_CALTIME (1u << UNIT_CALTIME_SHIFT) /* the process clock is calibrated to wall time */
|
||||||
|
#define UNIT_PFARS (1u << UNIT_PFARS_SHIFT) /* the system will auto-restart after a power failure */
|
||||||
|
|
||||||
#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK)
|
#define UNIT_CPU_MODEL (cpu_unit [0].flags & UNIT_MODEL)
|
||||||
|
|
||||||
#define CPU_MODEL(f) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK)
|
#define CPU_MODEL(f) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK)
|
||||||
|
|
||||||
|
#define MEMSIZE (cpu_unit [0].capac) /* the current memory size in 16-bit words */
|
||||||
|
|
||||||
|
|
||||||
/* CPU debug flags */
|
/* CPU debug flags */
|
||||||
|
|
||||||
|
@ -108,12 +118,41 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
|
||||||
#define SS_BYPASSED (1u << 31) /* stops are bypassed for this instruction */
|
#define SS_BYPASSED (1u << 31) /* stops are bypassed for this instruction */
|
||||||
|
|
||||||
|
|
||||||
|
/* System power state.
|
||||||
|
|
||||||
|
The HP 3000 power supply uses two signals to indicate its state: PON (power
|
||||||
|
on) and PFW (power-fail warning). PON is asserted when the DC power levels
|
||||||
|
are within their operating ranges. PFW is asserted when AC power is lost.
|
||||||
|
When a power failure occurs, PFW will be asserted at least three milliseconds
|
||||||
|
before PON is denied. When power is restored, PFW denies immediately, but
|
||||||
|
PON does not assert until the DC output voltages have stabilized, and the
|
||||||
|
machine is ready to resume execution.
|
||||||
|
|
||||||
|
In simulation, the four states of these two signals are modeled with
|
||||||
|
enumeration constants, as follows:
|
||||||
|
|
||||||
|
PON PFW State Simulator Action
|
||||||
|
--- --- --------------- ----------------------------
|
||||||
|
1 0 power on executing normally
|
||||||
|
1 1 power failing executing with cpx1_PFINTR
|
||||||
|
0 1 power off will not execute
|
||||||
|
0 0 power returning executing with trap_Power_On
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
power_on,
|
||||||
|
power_failing,
|
||||||
|
power_off,
|
||||||
|
power_returning
|
||||||
|
} POWER_STATE;
|
||||||
|
|
||||||
|
|
||||||
/* Micromachine execution state */
|
/* Micromachine execution state */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
running, /* the micromachine is running */
|
running, /* the micromachine is running */
|
||||||
paused, /* a PAUS instruction has been executed */
|
paused, /* a PAUS instruction has been executed */
|
||||||
loading, /* a COLD LOAD is in progress */
|
waiting, /* a cold load or dump is in progress */
|
||||||
halted /* a programmed or front panel HALT has been executed */
|
halted /* a programmed or front panel HALT has been executed */
|
||||||
} EXEC_STATE;
|
} EXEC_STATE;
|
||||||
|
|
||||||
|
@ -201,7 +240,7 @@ typedef enum {
|
||||||
cpx2_DECRADDR = 0000040u, /* decrement address */
|
cpx2_DECRADDR = 0000040u, /* decrement address */
|
||||||
/* cpx2_UNUSED = 0000020u, unused, always 0 */
|
/* cpx2_UNUSED = 0000020u, unused, always 0 */
|
||||||
/* cpx2_UNUSED = 0000010u, unused, always 0 */
|
/* cpx2_UNUSED = 0000010u, unused, always 0 */
|
||||||
cpx2_INHPFARS = 0000004u, /* inhibit power fail autorestart */
|
cpx2_INHPFARS = 0000004u, /* inhibit power-fail auto-restart */
|
||||||
cpx2_SYSHALT = 0000002u, /* system halt */
|
cpx2_SYSHALT = 0000002u, /* system halt */
|
||||||
cpx2_RUN = 0000001u /* run flip-flop */
|
cpx2_RUN = 0000001u /* run flip-flop */
|
||||||
} CPX2FLAG;
|
} CPX2FLAG;
|
||||||
|
@ -297,7 +336,7 @@ typedef enum {
|
||||||
trap_DS_Absent = 042, /* ucode Absent Data Segment */
|
trap_DS_Absent = 042, /* ucode Absent Data Segment */
|
||||||
trap_Power_On = 043, /* hdwe Power On */
|
trap_Power_On = 043, /* hdwe Power On */
|
||||||
trap_Cold_Load = 044, /* ucode Cold Load */
|
trap_Cold_Load = 044, /* ucode Cold Load */
|
||||||
trap_System_Halt = 045, /* ucode System Halt */
|
trap_System_Halt = 045 /* ucode System Halt */
|
||||||
} TRAP_CLASS;
|
} TRAP_CLASS;
|
||||||
|
|
||||||
#define trap_Integer_Overflow TO_DWORD (001, trap_User)
|
#define trap_Integer_Overflow TO_DWORD (001, trap_User)
|
||||||
|
@ -332,6 +371,50 @@ typedef enum {
|
||||||
#define MICRO_ABORTP(t,p) longjmp (cpu_save_env, TO_DWORD ((p),(t)))
|
#define MICRO_ABORTP(t,p) longjmp (cpu_save_env, TO_DWORD ((p),(t)))
|
||||||
|
|
||||||
|
|
||||||
|
/* Central Data Bus module definitions */
|
||||||
|
|
||||||
|
#define MODULE_MEMORY_LOWER 0 /* lower memory MCL address */
|
||||||
|
#define MODULE_MEMORY_UPPER 2 /* upper memory MCL address */
|
||||||
|
#define MODULE_MEMORY 3 /* upper bound of MCL addresses */
|
||||||
|
#define MODULE_PORT_CNTLR 4 /* selector channel port controller address */
|
||||||
|
#define MODULE_CPU 5 /* CPU MCU address */
|
||||||
|
#define MODULE_UNDEFINED 6 /* addresses 6-7 are unused */
|
||||||
|
|
||||||
|
#define MOP_NOP 0 /* module operation 00 = no operation */
|
||||||
|
#define MOP_WRITE 1 /* module operation 01 = write */
|
||||||
|
#define MOP_READ 2 /* module operation 10 = read */
|
||||||
|
#define MOP_READ_WRITE_ONES 3 /* module operation 11 = read/write ones */
|
||||||
|
|
||||||
|
|
||||||
|
/* Module control register accessors.
|
||||||
|
|
||||||
|
The module control register, MOD, has this format:
|
||||||
|
|
||||||
|
0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15
|
||||||
|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||||
|
| 0 0 | MOP | 0 | FROM | 0 0 0 0 | B | A | 0 0 |
|
||||||
|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||||
|
|
||||||
|
Where:
|
||||||
|
|
||||||
|
MOP = module operation
|
||||||
|
FROM = source module address
|
||||||
|
B = this CPU is CPU #2
|
||||||
|
A = this CPU is CPU #1
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MOD_MOP_MASK 0030000u /* MOD register MOP field mask */
|
||||||
|
#define MOD_FROM_MASK 0003400u /* MOD register FROM field mask */
|
||||||
|
#define MOD_CPU_2 0000010u /* CPU number 2 MCU */
|
||||||
|
#define MOD_CPU_1 0000004u /* CPU number 1 MCU */
|
||||||
|
|
||||||
|
#define MOD_MOP_SHIFT 12 /* MOD register MOP field alignment shift */
|
||||||
|
#define MOD_FROM_SHIFT 8 /* MOD register FROM field alignment shift */
|
||||||
|
|
||||||
|
#define TO_MOD_MOP(v) ((v) << MOD_MOP_SHIFT & MOD_MOP_MASK)
|
||||||
|
#define TO_MOD_FROM(v) ((v) << MOD_FROM_SHIFT & MOD_FROM_MASK)
|
||||||
|
|
||||||
|
|
||||||
/* Status register accessors.
|
/* Status register accessors.
|
||||||
|
|
||||||
The CPU status register, STA, has this format:
|
The CPU status register, STA, has this format:
|
||||||
|
@ -840,6 +923,15 @@ typedef enum {
|
||||||
#define TBX 0054000u /* test and branch, limit in X */
|
#define TBX 0054000u /* test and branch, limit in X */
|
||||||
#define MTBX 0056000u /* modify, test and branch, limit in X */
|
#define MTBX 0056000u /* modify, test and branch, limit in X */
|
||||||
|
|
||||||
|
#define CMD_TO_MASK 0000007u /* CMD command word TO field mask */
|
||||||
|
#define CMD_MOP_MASK 0000060u /* CMD command word MOP field mask */
|
||||||
|
|
||||||
|
#define CMD_TO_SHIFT 0 /* CMD command word TO field alignment shift */
|
||||||
|
#define CMD_MOP_SHIFT 4 /* CMD command word MOP field alignment shift */
|
||||||
|
|
||||||
|
#define CMD_TO(v) (((v) & CMD_TO_MASK) >> CMD_TO_SHIFT)
|
||||||
|
#define CMD_MOP(v) (((v) & CMD_MOP_MASK) >> CMD_MOP_SHIFT)
|
||||||
|
|
||||||
|
|
||||||
/* PSHR/SETR instruction accessors */
|
/* PSHR/SETR instruction accessors */
|
||||||
|
|
||||||
|
@ -858,6 +950,12 @@ typedef enum {
|
||||||
#define PSR_PRIV (PSR_SBANK | PSR_DB_DBANK | PSR_DL | PSR_Z)
|
#define PSR_PRIV (PSR_SBANK | PSR_DB_DBANK | PSR_DL | PSR_Z)
|
||||||
|
|
||||||
|
|
||||||
|
/* PCN instruction result values */
|
||||||
|
|
||||||
|
#define PCN_SERIES_II 1 /* CPU number for the Series II */
|
||||||
|
#define PCN_SERIES_III 2 /* CPU number for the Series III */
|
||||||
|
|
||||||
|
|
||||||
/* Reserved memory addresses */
|
/* Reserved memory addresses */
|
||||||
|
|
||||||
#define CSTB_POINTER 0000000u /* code segment table base pointer */
|
#define CSTB_POINTER 0000000u /* code segment table base pointer */
|
||||||
|
@ -952,6 +1050,7 @@ extern HP_WORD STA; /* Status Register */
|
||||||
extern HP_WORD SWCH; /* Switch Register */
|
extern HP_WORD SWCH; /* Switch Register */
|
||||||
extern HP_WORD CPX1; /* Run-Mode Interrupt Flags Register */
|
extern HP_WORD CPX1; /* Run-Mode Interrupt Flags Register */
|
||||||
extern HP_WORD CPX2; /* Halt-Mode Interrupt Flags Register */
|
extern HP_WORD CPX2; /* Halt-Mode Interrupt Flags Register */
|
||||||
|
extern HP_WORD MOD; /* Module Control Register */
|
||||||
extern HP_WORD PCLK; /* Process Clock Register */
|
extern HP_WORD PCLK; /* Process Clock Register */
|
||||||
extern HP_WORD CNTR; /* Microcode Counter */
|
extern HP_WORD CNTR; /* Microcode Counter */
|
||||||
|
|
||||||
|
@ -967,10 +1066,11 @@ extern HP_WORD CNTR; /* Microcode Counter */
|
||||||
/* CPU state */
|
/* CPU state */
|
||||||
|
|
||||||
extern jmp_buf cpu_save_env; /* saved environment for microcode aborts */
|
extern jmp_buf cpu_save_env; /* saved environment for microcode aborts */
|
||||||
|
extern POWER_STATE cpu_power_state; /* power supply state */
|
||||||
extern EXEC_STATE cpu_micro_state; /* micromachine execution state */
|
extern EXEC_STATE cpu_micro_state; /* micromachine execution state */
|
||||||
extern uint32 cpu_stop_flags; /* set of simulation stop flags */
|
extern uint32 cpu_stop_flags; /* set of simulation stop flags */
|
||||||
extern t_bool cpu_base_changed; /* TRUE if any base register has been changed */
|
extern t_bool cpu_base_changed; /* TRUE if any base register has been changed */
|
||||||
extern UNIT cpu_unit; /* CPU unit structure (needed for memory size) */
|
extern UNIT cpu_unit []; /* CPU unit array (needed for memory size) */
|
||||||
|
|
||||||
|
|
||||||
/* Condition Code B mapping table */
|
/* Condition Code B mapping table */
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
in advertising or otherwise to promote the sale, use or other dealings in
|
in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
this Software without prior written authorization from the author.
|
this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
12-Sep-16 JDB Use the PCN_SERIES_II and PCN_SERIES_III constants
|
||||||
|
23-Aug-16 JDB Implement the CMD instruction and module interrupts
|
||||||
11-Jun-16 JDB Bit mask constants are now unsigned
|
11-Jun-16 JDB Bit mask constants are now unsigned
|
||||||
13-Jan-16 JDB First release version
|
13-Jan-16 JDB First release version
|
||||||
11-Dec-12 JDB Created
|
11-Dec-12 JDB Created
|
||||||
|
@ -2991,7 +2993,7 @@ switch (operation) { /* dispatch the move or
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case 020: /* MVBW (CCB; STUN, STOV, BNDV() */
|
case 020: /* MVBW (CCB; STUN, STOV, BNDV) */
|
||||||
case 021:
|
case 021:
|
||||||
case 022:
|
case 022:
|
||||||
case 023:
|
case 023:
|
||||||
|
@ -3417,10 +3419,10 @@ switch (operation) { /* dispatch the move or
|
||||||
cpu_push (); /* push the stack down */
|
cpu_push (); /* push the stack down */
|
||||||
|
|
||||||
if (UNIT_CPU_MODEL == UNIT_SERIES_II) /* if the CPU is a Series II */
|
if (UNIT_CPU_MODEL == UNIT_SERIES_II) /* if the CPU is a Series II */
|
||||||
RA = 1; /* then the CPU number is 1 */
|
RA = PCN_SERIES_II; /* then the CPU number is 1 */
|
||||||
|
|
||||||
else if (UNIT_CPU_MODEL == UNIT_SERIES_III) /* if the CPU is a Series III */
|
else if (UNIT_CPU_MODEL == UNIT_SERIES_III) /* if the CPU is a Series III */
|
||||||
RA = 2; /* then the CPU number is 2 */
|
RA = PCN_SERIES_III; /* then the CPU number is 2 */
|
||||||
|
|
||||||
else /* if it's anything else */
|
else /* if it's anything else */
|
||||||
status = SCPE_IERR; /* then there's a problem! */
|
status = SCPE_IERR; /* then there's a problem! */
|
||||||
|
@ -3631,6 +3633,21 @@ return status; /* return the execution
|
||||||
simulation, and the UNDEF stop is active, a simulation stop will occur.
|
simulation, and the UNDEF stop is active, a simulation stop will occur.
|
||||||
If the stop is bypassed or not set, then the instruction will execute as
|
If the stop is bypassed or not set, then the instruction will execute as
|
||||||
though the reserved bits were zero.
|
though the reserved bits were zero.
|
||||||
|
|
||||||
|
3. The CMD instruction is simulated by assuming that the addressed module
|
||||||
|
will send a return message to the CPU, causing a module interrupt. If
|
||||||
|
the module is the CPU, then the "return message" is the originating
|
||||||
|
message, including whatever MOP was specified. Memory modules return a
|
||||||
|
no-operation MOP in response to a read or read/write ones MOP. Sending a
|
||||||
|
read/write ones MOP to a Series II memory module sets the addressed
|
||||||
|
location to 177777 before the read value is returned.
|
||||||
|
|
||||||
|
4. The module interrupt signal is qualified by the I-bit of the status
|
||||||
|
register. This is simulated by setting the cpx1_MODINTR bit in the CMD
|
||||||
|
executor if the I-bit is set, by clearing the cpx1_MODINTR bit in the SED
|
||||||
|
0 executor, and by setting the bit in the SED 1 executor if the MOD
|
||||||
|
register is non-zero (indicating a pending module interrupt that has not
|
||||||
|
been serviced).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat io_control (void)
|
static t_stat io_control (void)
|
||||||
|
@ -3640,9 +3657,8 @@ static const uint8 preadjustment [16] = { /* stack preadjustment, indexed
|
||||||
0, 1, 0, 1, 1, 2, 0, 0 /* RIO WIO TIO CIO CMD SST SIN HALT */
|
0, 1, 0, 1, 1, 2, 0, 0 /* RIO WIO TIO CIO CMD SST SIN HALT */
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32 operation;
|
uint32 operation, address, offset, module;
|
||||||
HP_WORD operand, address, offset;
|
HP_WORD operand, command, ics_q, delta_qi, disp_counter;
|
||||||
HP_WORD ics_q, delta_qi, disp_counter;
|
|
||||||
t_stat status = SCPE_OK;
|
t_stat status = SCPE_OK;
|
||||||
|
|
||||||
operation = IOCSUBOP (CIR); /* get the suboperation from the instruction */
|
operation = IOCSUBOP (CIR); /* get the suboperation from the instruction */
|
||||||
|
@ -3663,7 +3679,7 @@ switch (operation) { /* dispatch the I/O or c
|
||||||
|
|
||||||
else /* otherwise */
|
else /* otherwise */
|
||||||
cpu_read_memory (absolute, /* use the specified offset */
|
cpu_read_memory (absolute, /* use the specified offset */
|
||||||
offset + SGT_POINTER & LA_MASK,
|
offset + SGT_POINTER, /* which cannot overflow */
|
||||||
&operand);
|
&operand);
|
||||||
|
|
||||||
if (NPRV) /* if the mode is not privileged */
|
if (NPRV) /* if the mode is not privileged */
|
||||||
|
@ -3701,11 +3717,17 @@ switch (operation) { /* dispatch the I/O or c
|
||||||
&& cpu_stop_flags & SS_UNDEF) /* and the undefined instruction stop is active */
|
&& cpu_stop_flags & SS_UNDEF) /* and the undefined instruction stop is active */
|
||||||
status = STOP_UNIMPL; /* then stop the simulator */
|
status = STOP_UNIMPL; /* then stop the simulator */
|
||||||
|
|
||||||
else if (CIR & 1) /* otherwise if bit 15 of the instruction is 1 */
|
else if (CIR & 1) { /* otherwise if bit 15 of the instruction is 1 */
|
||||||
STA |= STATUS_I; /* then enable interrupts */
|
STA |= STATUS_I; /* then enable interrupts */
|
||||||
|
|
||||||
else /* otherwise */
|
if (MOD != 0) /* if a module interrupt is pending */
|
||||||
STA &= ~STATUS_I; /* disable them */
|
CPX1 |= cpx1_MODINTR; /* then request it now */
|
||||||
|
}
|
||||||
|
|
||||||
|
else { /* otherwise */
|
||||||
|
STA &= ~STATUS_I; /* disable interrupts */
|
||||||
|
CPX1 &= ~cpx1_MODINTR; /* and clear any indicated module interrupt */
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
@ -3953,7 +3975,50 @@ switch (operation) { /* dispatch the I/O or c
|
||||||
if (NPRV) /* if the mode is not privileged */
|
if (NPRV) /* if the mode is not privileged */
|
||||||
MICRO_ABORT (trap_Privilege_Violation); /* then abort with a privilege violation */
|
MICRO_ABORT (trap_Privilege_Violation); /* then abort with a privilege violation */
|
||||||
|
|
||||||
status = STOP_UNIMPL; /* THIS INSTRUCTION IS NOT IMPLEMENTED YET! */
|
address = SM + SR - IO_K (CIR) & LA_MASK; /* get the location of the command word */
|
||||||
|
cpu_read_memory (stack_checked, address, &command); /* and read it from the stack */
|
||||||
|
|
||||||
|
module = CMD_TO (command); /* get the addressed (TO) module number */
|
||||||
|
|
||||||
|
if (module == MODULE_PORT_CNTLR /* if the selector channel port controller */
|
||||||
|
|| module >= MODULE_UNDEFINED) /* or an undefined module is addressed */
|
||||||
|
CPX1 |= cpx1_CPUTIMER; /* then a module timeout occurs */
|
||||||
|
|
||||||
|
else if (module == MODULE_CPU) /* otherwise if the CPU is addressing itself */
|
||||||
|
MOD = MOD_CPU_1 /* then set the MOD register */
|
||||||
|
| TO_MOD_FROM (module) /* FROM field to the TO address */
|
||||||
|
| TO_MOD_MOP (CMD_MOP (command)); /* and include the MOP field value */
|
||||||
|
|
||||||
|
else if (UNIT_CPU_MODEL == UNIT_SERIES_II) /* otherwise if a Series II memory module is addressed */
|
||||||
|
if (module >= MODULE_MEMORY_UPPER /* then if the upper module is addressed */
|
||||||
|
&& MEMSIZE < 128 * 1024) /* but it's not present */
|
||||||
|
CPX1 |= cpx1_CPUTIMER; /* then it will not respond */
|
||||||
|
|
||||||
|
else { /* otherwise the module address is valid */
|
||||||
|
if (CMD_MOP (command) == MOP_READ_WRITE_ONES) { /* if the operation is read/write ones */
|
||||||
|
address = TO_PA (module, RA); /* then get the bank and address */
|
||||||
|
cpu_write_memory (absolute, address, D16_UMAX); /* and set the addressed word to all one bits */
|
||||||
|
}
|
||||||
|
|
||||||
|
MOD = MOD_CPU_1 /* set the MOD register */
|
||||||
|
| TO_MOD_FROM (module) /* FROM field to the TO address */
|
||||||
|
| TO_MOD_MOP (MOP_NOP); /* and the module operation to NOP */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (UNIT_CPU_MODEL == UNIT_SERIES_III) /* otherwise if a Series III memory module is addressed */
|
||||||
|
if (module >= MODULE_MEMORY_UPPER /* then if the upper module is addressed */
|
||||||
|
&& MEMSIZE < 512 * 1024) /* but it's not present */
|
||||||
|
CPX1 |= cpx1_CPUTIMER; /* then it will not respond */
|
||||||
|
|
||||||
|
else /* otherwise the module address is valid */
|
||||||
|
MOD = MOD_CPU_1 /* so set the MOD register */
|
||||||
|
| TO_MOD_FROM (module) /* FROM field to the TO address */
|
||||||
|
| TO_MOD_MOP (MOP_NOP); /* and the module operation to NOP */
|
||||||
|
|
||||||
|
if (MOD != 0 && STA & STATUS_I) /* if a module interrupt is indicated and enabled */
|
||||||
|
CPX1 |= cpx1_MODINTR; /* then request it */
|
||||||
|
|
||||||
|
cpu_pop (); /* delete the TOS */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
@ -3969,7 +4034,7 @@ switch (operation) { /* dispatch the I/O or c
|
||||||
|
|
||||||
else /* otherwise */
|
else /* otherwise */
|
||||||
cpu_read_memory (absolute, /* use the specified offset */
|
cpu_read_memory (absolute, /* use the specified offset */
|
||||||
offset + SGT_POINTER & LA_MASK,
|
offset + SGT_POINTER, /* which cannot overflow */
|
||||||
&operand);
|
&operand);
|
||||||
|
|
||||||
if (NPRV) /* if the mode is not privileged */
|
if (NPRV) /* if the mode is not privileged */
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
in advertising or otherwise to promote the sale, use or other dealings in
|
in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
this Software without prior written authorization from the author.
|
this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
01-Sep-16 JDB Added the cpu_cold_cmd and cpu_power_cmd routines
|
||||||
|
15-Aug-16 JDB Removed obsolete comment mentioning iop_read/write_memory
|
||||||
|
15-Jul-16 JDB Corrected the IOCW_COUNT macro to return the correct value
|
||||||
11-Jun-16 JDB Bit mask constants are now unsigned
|
11-Jun-16 JDB Bit mask constants are now unsigned
|
||||||
05-Sep-15 JDB First release version
|
05-Sep-15 JDB First release version
|
||||||
11-Dec-12 JDB Created
|
11-Dec-12 JDB Created
|
||||||
|
@ -92,7 +95,7 @@ typedef enum {
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. The IOCW_COUNT(w) macro sign-extends the 12-bit two's-complement word
|
1. The IOCW_COUNT(w) macro sign-extends the 12-bit two's-complement word
|
||||||
count in the IOCW for the Read and Write orders.
|
count to a 16-bit value for the Return Residue order.
|
||||||
|
|
||||||
2. The sioWRITE, sioWRITEC, sioREAD, and sioREADC enumeration constants must
|
2. The sioWRITE, sioWRITEC, sioREAD, and sioREADC enumeration constants must
|
||||||
be contiguous and the final four values, so that a ">= sioWRITE" test
|
be contiguous and the final four values, so that a ">= sioWRITE" test
|
||||||
|
@ -117,7 +120,7 @@ typedef enum {
|
||||||
|
|
||||||
#define IOCW_CNTL(w) (((w) & IOCW_CNTL_MASK) >> IOCW_CNTL_SHIFT)
|
#define IOCW_CNTL(w) (((w) & IOCW_CNTL_MASK) >> IOCW_CNTL_SHIFT)
|
||||||
#define IOCW_WCNT(w) (((w) & IOCW_WCNT_MASK) >> IOCW_WCNT_SHIFT)
|
#define IOCW_WCNT(w) (((w) & IOCW_WCNT_MASK) >> IOCW_WCNT_SHIFT)
|
||||||
#define IOCW_COUNT(w) (- (int32) (~(w) + 1 & IOCW_WCNT_MASK))
|
#define IOCW_COUNT(w) ((w) | ~IOCW_WCNT_MASK & D16_MASK)
|
||||||
|
|
||||||
#define IOAW_BANK(w) (((w) & IOAW_BANK_MASK) >> IOAW_BANK_SHIFT)
|
#define IOAW_BANK(w) (((w) & IOAW_BANK_MASK) >> IOAW_BANK_SHIFT)
|
||||||
|
|
||||||
|
@ -139,7 +142,16 @@ typedef enum {
|
||||||
} SIO_ORDER;
|
} SIO_ORDER;
|
||||||
|
|
||||||
|
|
||||||
/* Global CPU routine declarations */
|
/* Global CPU routine declarations.
|
||||||
|
|
||||||
|
cpu_cold_cmd : process the LOAD and DUMP commands
|
||||||
|
cpu_power_cmd : process the POWER commands
|
||||||
|
cpu_read_memory : read a word from main memory
|
||||||
|
cpu_write_memory : write a word to main memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern t_stat cpu_cold_cmd (int32 arg, CONST char *buf);
|
||||||
|
extern t_stat cpu_power_cmd (int32 arg, CONST char *buf);
|
||||||
|
|
||||||
extern t_bool cpu_read_memory (ACCESS_CLASS classification, uint32 offset, HP_WORD *value);
|
extern t_bool cpu_read_memory (ACCESS_CLASS classification, uint32 offset, HP_WORD *value);
|
||||||
extern t_bool cpu_write_memory (ACCESS_CLASS classification, uint32 offset, HP_WORD value);
|
extern t_bool cpu_write_memory (ACCESS_CLASS classification, uint32 offset, HP_WORD value);
|
||||||
|
@ -161,8 +173,6 @@ extern const char *const sio_order_name [];
|
||||||
|
|
||||||
iop_initialize : initialize the I/O processor
|
iop_initialize : initialize the I/O processor
|
||||||
iop_poll : poll the interfaces for an active interrupt request
|
iop_poll : poll the interfaces for an active interrupt request
|
||||||
iop_read_memory : read memory via the module control unit
|
|
||||||
iop_write_memory : write memory via the module control unit
|
|
||||||
iop_direct_io : dispatch an I/O command to an interface
|
iop_direct_io : dispatch an I/O command to an interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
in advertising or otherwise to promote the sale, use or other dealings in
|
in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
this Software without prior written authorization from the author.
|
this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
03-Sep-16 JDB Added the STOP_POWER and STOP_ARSINH codes
|
||||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||||
21-Mar-16 JDB Changed uint16 types to HP_WORD
|
21-Mar-16 JDB Changed uint16 types to HP_WORD
|
||||||
19-Mar-16 JDB Added UNDEFs for the additional register macros
|
19-Mar-16 JDB Added UNDEFs for the additional register macros
|
||||||
|
@ -306,6 +307,8 @@
|
||||||
#define STOP_INFLOOP 7 /* infinite loop stop */
|
#define STOP_INFLOOP 7 /* infinite loop stop */
|
||||||
#define STOP_CLOAD 8 /* cold load complete */
|
#define STOP_CLOAD 8 /* cold load complete */
|
||||||
#define STOP_CDUMP 9 /* cold dump complete */
|
#define STOP_CDUMP 9 /* cold dump complete */
|
||||||
|
#define STOP_ARSINH 10 /* auto-restart inhibited */
|
||||||
|
#define STOP_POWER 11 /* power is off */
|
||||||
|
|
||||||
|
|
||||||
/* Modifier validation identifiers */
|
/* Modifier validation identifiers */
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
SIMH/HP 3000 DIAGNOSTICS PERFORMANCE
|
SIMH/HP 3000 DIAGNOSTICS PERFORMANCE
|
||||||
====================================
|
====================================
|
||||||
Last update: 2016-05-31
|
Last update: 2016-09-07
|
||||||
|
|
||||||
|
|
||||||
The HP 32230 offline diagnostic suite has been run against the SIMH HP 3000
|
The HP 32230 diagnostic suite has been run against the SIMH HP 3000 simulation.
|
||||||
simulation. Diagnostic programs were obtained from two magnetic tapes: HP
|
Diagnostic programs were obtained from two magnetic tapes: HP 30000-11016 Rev.
|
||||||
30000-11016 Rev. 1244 (CPU) and 30000-11017 Rev. 2640 (non-CPU). For each
|
1244 (CPU) and 30000-11017 Rev. 2640 (non-CPU). For each diagnostic, the
|
||||||
diagnostic, the recommended standard tests were selected, plus any available
|
recommended standard tests were selected, plus any available optional tests that
|
||||||
optional tests that broadened the test coverage.
|
broadened the test coverage.
|
||||||
|
|
||||||
Except where noted in the individual diagnostic reports, the test system
|
Except where noted in the individual diagnostic reports, the test system
|
||||||
configuration is the default SIMH configuration with these changes:
|
configuration is the default SIMH configuration with these changes:
|
||||||
|
@ -27,7 +27,7 @@ The results of the diagnostic runs are summarized below:
|
||||||
PD420A CPU Diagnostic Section 1 01.00 Passed
|
PD420A CPU Diagnostic Section 1 01.00 Passed
|
||||||
PD420A1 CPU Diagnostic Section 2 01.00 Passed
|
PD420A1 CPU Diagnostic Section 2 01.00 Passed
|
||||||
PD420A2 CPU Diagnostic Section 3 01.01 Passed
|
PD420A2 CPU Diagnostic Section 3 01.01 Passed
|
||||||
PD420A3 CPU Diagnostic Section 4 01.24 Partial
|
PD420A3 CPU Diagnostic Section 4 01.24 Passed
|
||||||
PD420A4 CPU Diagnostic Section 5 01.00 Passed
|
PD420A4 CPU Diagnostic Section 5 01.00 Passed
|
||||||
PD420A5 CPU Diagnostic Section 6 01.00 Passed
|
PD420A5 CPU Diagnostic Section 6 01.00 Passed
|
||||||
PD420A6 CPU Diagnostic Section 7 01.00 Passed
|
PD420A6 CPU Diagnostic Section 7 01.00 Passed
|
||||||
|
@ -188,7 +188,6 @@ TEST REPORT: Programmed halt, CIR: 030375 (HALT 15), P: 010163 (ZERO,NOP)
|
||||||
|
|
||||||
TEST RESULT: Passed.
|
TEST RESULT: Passed.
|
||||||
|
|
||||||
|
|
||||||
TEST NOTES: The Internal Switch Register (2000) and Section Select Register
|
TEST NOTES: The Internal Switch Register (2000) and Section Select Register
|
||||||
(2001) settings are preconfigured to simplify execution.
|
(2001) settings are preconfigured to simplify execution.
|
||||||
|
|
||||||
|
@ -210,27 +209,29 @@ D420A3 - CPU Section 4
|
||||||
TESTED DEVICE: CPU (hp3000_cpu.c)
|
TESTED DEVICE: CPU (hp3000_cpu.c)
|
||||||
|
|
||||||
CONFIGURATION: sim> deposit 2000 000001
|
CONFIGURATION: sim> deposit 2000 000001
|
||||||
sim> deposit 2001 034160
|
sim> deposit 2001 034170
|
||||||
sim> deposit 010550 120005
|
|
||||||
sim> deposit 015761 051007
|
sim> deposit 015761 051007
|
||||||
sim> set scmb enable
|
sim> set scmb enable
|
||||||
sim> set scmb mx
|
sim> set scmb mx
|
||||||
|
sim> set cpu stop=PAUSE
|
||||||
sim> go
|
sim> go
|
||||||
|
|
||||||
TEST REPORT: Programmed halt, CIR: 030375 (HALT 15), P: 010630 (ZERO,NOP)
|
TEST REPORT: CPU paused, P: 021376 (PAUS 12)
|
||||||
|
|
||||||
TEST RESULT: Partially passed.
|
sim> set cpu nostop=PAUSE
|
||||||
|
sim> power fail
|
||||||
|
|
||||||
|
Programmed halt, CIR: 030374 (HALT 14), P: 011130 (EXIT 0)
|
||||||
|
|
||||||
|
sim> power restore
|
||||||
|
|
||||||
|
Programmed halt, CIR: 030375 (HALT 15), P: 010630 (ZERO,NOP)
|
||||||
|
|
||||||
|
TEST RESULT: Passed.
|
||||||
|
|
||||||
TEST NOTES: The Internal Switch Register (2000) and Section Select Register
|
TEST NOTES: The Internal Switch Register (2000) and Section Select Register
|
||||||
(2001) settings are preconfigured to simplify execution.
|
(2001) settings are preconfigured to simplify execution.
|
||||||
|
|
||||||
Step 17 (module interrupt tests) fails, as this feature is not
|
|
||||||
currently simulated. The step is bypassed by changing the PCAL
|
|
||||||
instruction at location 010550 to an INCM DB+5 instruction.
|
|
||||||
|
|
||||||
Step 20 (power fail tests) is optional and is not selected, as
|
|
||||||
this feature is not currently simulated.
|
|
||||||
|
|
||||||
The "Stand-Alone HP 30003A/B CPU Diagnostic" manual
|
The "Stand-Alone HP 30003A/B CPU Diagnostic" manual
|
||||||
(30003-90001, April 1979) says that step 31 has been "eliminated
|
(30003-90001, April 1979) says that step 31 has been "eliminated
|
||||||
from diagnostic" (the February 1976 manual lists this step as
|
from diagnostic" (the February 1976 manual lists this step as
|
||||||
|
@ -1901,3 +1902,6 @@ TEST REPORT: D1 ONLINE LINE PRINTER VERIFIER (HP D466A.01.06)
|
||||||
END OF PROGRAM
|
END OF PROGRAM
|
||||||
|
|
||||||
TEST RESULT: Passed.
|
TEST RESULT: Passed.
|
||||||
|
|
||||||
|
TEST NOTES: The test was run from the OPERATOR.SYS account on MPE-V/R
|
||||||
|
release E.01.00.
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
DS HP 30229B Cartridge Disc Interface
|
DS HP 30229B Cartridge Disc Interface
|
||||||
|
|
||||||
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
16-May-16 JDB Fixed interrupt mask setting
|
16-May-16 JDB Fixed interrupt mask setting
|
||||||
|
@ -439,7 +440,8 @@ static REG ds_reg [] = {
|
||||||
{ DRDATA (RETRY, retry_counter, 4), REG_FIT | PV_LEFT },
|
{ DRDATA (RETRY, retry_counter, 4), REG_FIT | PV_LEFT },
|
||||||
|
|
||||||
{ SRDATA (DIAG, overrides, REG_HRO) },
|
{ SRDATA (DIAG, overrides, REG_HRO) },
|
||||||
{ SRDATA (DIB, ds_dib, REG_HRO) },
|
|
||||||
|
DIB_REGS (ds_dib),
|
||||||
|
|
||||||
DL_REGS (mac_cntlr, ds_unit, UNIT_COUNT, buffer, fast_times),
|
DL_REGS (mac_cntlr, ds_unit, UNIT_COUNT, buffer, fast_times),
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
in advertising or otherwise to promote the sale, use or other dealings in
|
in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
this Software without prior written authorization from the author.
|
this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
12-Sep-16 JDB Added the DIB_REGS macro
|
||||||
|
02-Sep-16 JDB Added the iop_assert_PFWARN routine
|
||||||
11-Jun-16 JDB Bit mask constants are now unsigned
|
11-Jun-16 JDB Bit mask constants are now unsigned
|
||||||
21-Mar-16 JDB Changed type of inbound_value of CNTLR_INTRF to HP_WORD
|
21-Mar-16 JDB Changed type of inbound_value of CNTLR_INTRF to HP_WORD
|
||||||
20-Jan-16 JDB First release version
|
20-Jan-16 JDB First release version
|
||||||
|
@ -135,7 +137,7 @@ typedef enum { /* --- source of signal --- */
|
||||||
INTPOLLIN = 000040000000, /* IOP interrupt poll */
|
INTPOLLIN = 000040000000, /* IOP interrupt poll */
|
||||||
XFERERROR = 000100000000, /* Multiplexer channel abort */
|
XFERERROR = 000100000000, /* Multiplexer channel abort */
|
||||||
CHANSO = 000200000000, /* Channel service call to interface */
|
CHANSO = 000200000000, /* Channel service call to interface */
|
||||||
PFWARN = 000400000000 /* SET CPU POWERFAIL */
|
PFWARN = 000400000000 /* POWER FAIL command */
|
||||||
/* = 001000000000 (available) */
|
/* = 001000000000 (available) */
|
||||||
/* = 002000000000 (available) */
|
/* = 002000000000 (available) */
|
||||||
/* = 004000000000 (available) */
|
/* = 004000000000 (available) */
|
||||||
|
@ -269,6 +271,12 @@ typedef uint32 SIGNALS_DATA; /* a combined outbound signal se
|
||||||
could be smaller than the defined 32-bit sizes, but IA-32 processors
|
could be smaller than the defined 32-bit sizes, but IA-32 processors
|
||||||
execute instructions with 32-bit operands much faster than those with
|
execute instructions with 32-bit operands much faster than those with
|
||||||
16- or 8-bit operands.
|
16- or 8-bit operands.
|
||||||
|
|
||||||
|
3. The DIB_REGS macro provides hidden register entries needed to save and
|
||||||
|
restore the state of a DIB. Only the potentially variable fields are
|
||||||
|
referenced. In particular, the "io_interface" field must not be saved,
|
||||||
|
as the address of the device's interface routine may change from version
|
||||||
|
to version of the simulator.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEVNO_MAX 127 /* the maximum device number */
|
#define DEVNO_MAX 127 /* the maximum device number */
|
||||||
|
@ -312,6 +320,17 @@ struct dib { /* the Device Information Block
|
||||||
t_bool service_request; /* channel service has been requested */
|
t_bool service_request; /* channel service has been requested */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DIB_REGS(dib) \
|
||||||
|
/* Macro Name Location Width Flags */ \
|
||||||
|
/* ------ ------- -------------------------- ----- ------- */ \
|
||||||
|
{ DRDATA (DIBDN, dib.device_number, 32), REG_HRO }, \
|
||||||
|
{ DRDATA (DIBSRN, dib.service_request_number, 32), REG_HRO }, \
|
||||||
|
{ DRDATA (DIBPRI, dib.interrupt_priority, 32), REG_HRO }, \
|
||||||
|
{ ORDATA (DIBMASK, dib.interrupt_mask, 32), REG_HRO }, \
|
||||||
|
{ ORDATA (DIBIRQ, dib.interrupt_request, 32), REG_HRO }, \
|
||||||
|
{ ORDATA (DIBACT, dib.interrupt_active, 32), REG_HRO }, \
|
||||||
|
{ ORDATA (DIBSR, dib.service_request, 32), REG_HRO }
|
||||||
|
|
||||||
|
|
||||||
/* Calibrated timer numbers */
|
/* Calibrated timer numbers */
|
||||||
|
|
||||||
|
@ -334,13 +353,14 @@ typedef enum {
|
||||||
extern UNIT *cpu_pclk_uptr; /* pointer to the process clock unit */
|
extern UNIT *cpu_pclk_uptr; /* pointer to the process clock unit */
|
||||||
extern t_bool cpu_is_calibrated; /* TRUE if the process clock is calibrated */
|
extern t_bool cpu_is_calibrated; /* TRUE if the process clock is calibrated */
|
||||||
|
|
||||||
extern void cpu_front_panel (HP_WORD switch_reg, /* set the front panel switches as directed */
|
extern void cpu_front_panel (HP_WORD switch_reg, /* set the CPU front panel switches as directed */
|
||||||
PANEL_TYPE request);
|
PANEL_TYPE request);
|
||||||
|
|
||||||
|
|
||||||
/* Global asynchronous signal assertion functions */
|
/* Global asynchronous signal assertion functions */
|
||||||
|
|
||||||
extern void iop_assert_INTREQ (DIB *dib_pointer); /* assert the interrupt request signal */
|
extern void iop_assert_INTREQ (DIB *dib_pointer); /* assert the interrupt request signal */
|
||||||
|
extern void iop_assert_PFWARN (void); /* assert the power failure warning signal */
|
||||||
|
|
||||||
extern void mpx_assert_REQ (DIB *dib_pointer); /* assert the multiplexer channel request signal */
|
extern void mpx_assert_REQ (DIB *dib_pointer); /* assert the multiplexer channel request signal */
|
||||||
extern void mpx_assert_SRn (DIB *dib_pointer); /* assert the multiplexer channel service request signal */
|
extern void mpx_assert_SRn (DIB *dib_pointer); /* assert the multiplexer channel service request signal */
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
IOP HP 3000 Series III I/O Processor
|
IOP HP 3000 Series III I/O Processor
|
||||||
|
|
||||||
|
03-Sep-16 JDB Added "iop_assert_PFWARN" to warn devices of power loss
|
||||||
|
01-Aug-16 JDB Added "iop_reset" to initialize the IOP
|
||||||
30-Jun-16 JDB Changed REG type of filter array to BRDATA
|
30-Jun-16 JDB Changed REG type of filter array to BRDATA
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||||
|
@ -277,6 +279,7 @@ static uint32 filter [4] = { /* filter bitmap for device numb
|
||||||
|
|
||||||
/* IOP local SCP support routines */
|
/* IOP local SCP support routines */
|
||||||
|
|
||||||
|
static t_stat iop_reset (DEVICE *dptr);
|
||||||
static t_stat iop_set_filter (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
|
static t_stat iop_set_filter (UNIT *uptr, int32 value, CONST char *cptr, void *desc);
|
||||||
static t_stat iop_show_filter (FILE *st, UNIT *uptr, int32 value, CONST void *desc);
|
static t_stat iop_show_filter (FILE *st, UNIT *uptr, int32 value, CONST void *desc);
|
||||||
|
|
||||||
|
@ -342,7 +345,7 @@ DEVICE iop_dev = {
|
||||||
DV_WIDTH, /* data width */
|
DV_WIDTH, /* data width */
|
||||||
NULL, /* examine routine */
|
NULL, /* examine routine */
|
||||||
NULL, /* deposit routine */
|
NULL, /* deposit routine */
|
||||||
NULL, /* reset routine */
|
&iop_reset, /* reset routine */
|
||||||
NULL, /* boot routine */
|
NULL, /* boot routine */
|
||||||
NULL, /* attach routine */
|
NULL, /* attach routine */
|
||||||
NULL, /* detach routine */
|
NULL, /* detach routine */
|
||||||
|
@ -372,6 +375,10 @@ DEVICE iop_dev = {
|
||||||
flip-flop values in the device DIBs and clears the external interrupt flag if
|
flip-flop values in the device DIBs and clears the external interrupt flag if
|
||||||
there are no devices with active interrupts (as the user may have set the
|
there are no devices with active interrupts (as the user may have set the
|
||||||
flag or reset the interrupting device during a simulation stop).
|
flag or reset the interrupting device during a simulation stop).
|
||||||
|
|
||||||
|
The value of the IOA register is returned. This is zero unless a device
|
||||||
|
requesting an interrupt has been acknowledged but not yet serviced, in which
|
||||||
|
case the value is the device number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32 iop_initialize (void)
|
uint32 iop_initialize (void)
|
||||||
|
@ -698,11 +705,76 @@ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Warn devices of an impending power failure.
|
||||||
|
|
||||||
|
This routine is called by the POWER FAIL command to send a warning
|
||||||
|
to all devices that power is about to fail. It corresponds in hardware to
|
||||||
|
asserting the PFWARN signal. Devices may process or ignore the signal as
|
||||||
|
appropriate. If the device returns the INTREQ signal, an interrupt is
|
||||||
|
requested.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void iop_assert_PFWARN (void)
|
||||||
|
{
|
||||||
|
uint32 devno;
|
||||||
|
DIB *dibptr;
|
||||||
|
SIGNALS_DATA outbound;
|
||||||
|
|
||||||
|
for (devno = 0; devno <= DEVNO_MAX; devno++) { /* loop through the device number list */
|
||||||
|
dibptr = devs [devno]; /* and get the next device information block pointer */
|
||||||
|
|
||||||
|
if (dibptr != NULL) { /* if this device is defined */
|
||||||
|
outbound = /* then send the PFWARN signal to the device interface */
|
||||||
|
dibptr->io_interface (dibptr, PFWARN, 0);
|
||||||
|
|
||||||
|
if (outbound & INTREQ) /* if the device requested an interrupt */
|
||||||
|
iop_assert_INTREQ (dibptr); /* then set it up */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* IOP local SCP support routines */
|
/* IOP local SCP support routines */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Device reset routine.
|
||||||
|
|
||||||
|
This routine is called for a RESET or RESET IOP command. It is the
|
||||||
|
simulation equivalent of the IORESET signal, which is asserted by the front
|
||||||
|
panel LOAD and DUMP switches.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation notes:
|
||||||
|
|
||||||
|
1. In hardware, IORESET clears flip-flops associated with the state machines
|
||||||
|
that implement the interrupt poll, SO/SI handshake, and multiplexer
|
||||||
|
channel access. In simulation, these are all represented by function
|
||||||
|
calls and, as such, are atomic. Therefore, the only state variable that
|
||||||
|
IORESET clears is the external interrupt flip-flop, which is implemented
|
||||||
|
as its respective bit in the CPX1 register rather than as a separate
|
||||||
|
variable. Setting IOA to 0 and calling iop_initialize clears this bit;
|
||||||
|
it also sets up the devs array, which is used by the POWER FAIL command.
|
||||||
|
|
||||||
|
2. In hardware, IORESET also clears the IOP address parity error, system
|
||||||
|
parity error, and illegal address flip-flops. However, these exist only
|
||||||
|
to assert XFERERROR to devices. In simulation, XFERERROR is sent to a
|
||||||
|
device interface when the initiating condition is detected by the
|
||||||
|
multiplexer channel, so these are not represented by state variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static t_stat iop_reset (DEVICE *dptr)
|
||||||
|
{
|
||||||
|
IOA = 0; /* clear the I/O Address register and initialize */
|
||||||
|
iop_initialize (); /* which clears the external interrupt flip-flop */
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set the trace omission filter.
|
/* Set the trace omission filter.
|
||||||
|
|
||||||
If the "value" parameter is 1, the filter array bits corresponding to the
|
If the "value" parameter is 1, the filter array bits corresponding to the
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
|
|
||||||
LP HP 30209A Line Printer Interface
|
LP HP 30209A Line Printer Interface
|
||||||
|
|
||||||
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
|
03-Sep-16 JDB Added power-fail detection
|
||||||
|
08-Jul-16 JDB Added REG entry to save the transfer unit wait field
|
||||||
|
Extended "lp_show_vfu" to show the VFU channel definitions
|
||||||
01-Jul-16 JDB First release version
|
01-Jul-16 JDB First release version
|
||||||
27-Apr-16 JDB Passes the On-Line HP Line Printers Verification (D466A)
|
27-Apr-16 JDB Passes the On-Line HP Line Printers Verification (D466A)
|
||||||
19-Apr-16 JDB Passes the universal interface diagnostic (D435A)
|
19-Apr-16 JDB Passes the universal interface diagnostic (D435A)
|
||||||
|
@ -391,6 +395,12 @@
|
||||||
condition causes the printer to go offline at the completion of the
|
condition causes the printer to go offline at the completion of the
|
||||||
current line. In simulation, a DETACH is handled as a torn-paper
|
current line. In simulation, a DETACH is handled as a torn-paper
|
||||||
condition.
|
condition.
|
||||||
|
|
||||||
|
5. Slewing in expanded mode is performed by appending CR LF pairs to the
|
||||||
|
character buffer and then writing the combined buffer to the printer
|
||||||
|
output file. The size of the buffer must accommodate the largest print
|
||||||
|
line (136 characters) plus the largest possible slew (144 lines * 2
|
||||||
|
characters per line).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1019,6 +1029,7 @@ static t_bool device_end_in = FALSE; /* external DEV END signal state
|
||||||
/* Diagnostic Hardware Assembly state */
|
/* Diagnostic Hardware Assembly state */
|
||||||
|
|
||||||
static HP_WORD dha_control_word = 0; /* Diagnostic Hardware Assembly control word */
|
static HP_WORD dha_control_word = 0; /* Diagnostic Hardware Assembly control word */
|
||||||
|
static t_bool power_warning = FALSE; /* PFWARN is not asserted to the DHA */
|
||||||
|
|
||||||
|
|
||||||
/* Printer state */
|
/* Printer state */
|
||||||
|
@ -1034,7 +1045,9 @@ static uint32 form_length; /* form length in lines */
|
||||||
static uint8 buffer [BUFFER_SIZE]; /* character and paper advance buffer */
|
static uint8 buffer [BUFFER_SIZE]; /* character and paper advance buffer */
|
||||||
static uint16 VFU [VFU_SIZE]; /* vertical format unit tape */
|
static uint16 VFU [VFU_SIZE]; /* vertical format unit tape */
|
||||||
static char vfu_title [LINE_SIZE]; /* descriptive title of the tape currently in the VFU */
|
static char vfu_title [LINE_SIZE]; /* descriptive title of the tape currently in the VFU */
|
||||||
static REG *vfu_reg; /* pointer to the VFU register entry */
|
|
||||||
|
static int32 punched_char = 'O'; /* character to display if VFU channel is punched */
|
||||||
|
static int32 unpunched_char = '.'; /* character to display if VFU channel is not punched */
|
||||||
|
|
||||||
static const DELAY_PROPS *dlyptr = &fast_times; /* pointer to the event delay times to use */
|
static const DELAY_PROPS *dlyptr = &fast_times; /* pointer to the event delay times to use */
|
||||||
|
|
||||||
|
@ -1126,21 +1139,7 @@ static UNIT lp_unit [] = {
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. The VFU register displays the data currently held in the printer's
|
1. The DHA hardware buffers control word bits 6-10 to LEDs. Inspection and
|
||||||
Vertical Format Unit. For the convenience of the user, the register's
|
|
||||||
width and offset fields are changed with the printer model to reflect the
|
|
||||||
number of VFU channels available, and the depth field is changed by the
|
|
||||||
VFU load routine to reflect the number of lines defined for the current
|
|
||||||
form. This allows an "EXAMINE LP VFU[ALL]" command to display the
|
|
||||||
current number of channels and lines.
|
|
||||||
|
|
||||||
2. The VFUREG register must immediately precede the VFU register. The
|
|
||||||
location field is changed at power-on reset to point at the VFU register
|
|
||||||
entry. This ensures that the full REG structure for the VFU register is
|
|
||||||
SAVEd and RESTOREd properly, which is necessary for the dynamic VFU
|
|
||||||
display to work (SAVE normally saves only a register's depth and value).
|
|
||||||
|
|
||||||
3. The DHA hardware buffers control word bits 6-10 to LEDs. Inspection and
|
|
||||||
user confirmation of the control word state is required by the interface
|
user confirmation of the control word state is required by the interface
|
||||||
diagnostic. In simulation, bits 6-10 of the control word are presented
|
diagnostic. In simulation, bits 6-10 of the control word are presented
|
||||||
as the CNLED register to allow an ASSERT command to test this subrange of
|
as the CNLED register to allow an ASSERT command to test this subrange of
|
||||||
|
@ -1149,7 +1148,7 @@ static UNIT lp_unit [] = {
|
||||||
|
|
||||||
static REG lp_reg [] = {
|
static REG lp_reg [] = {
|
||||||
/* Macro Name Location Radix Width Offset Depth Flags */
|
/* Macro Name Location Radix Width Offset Depth Flags */
|
||||||
/* ------ ------ ------------------------ ----- ------------ ------ ------------- ----------------- */
|
/* ------ ------ ------------------------ ----- ------------ ------ ------------- ------------------ */
|
||||||
{ FLDATA (SIOBSY, sio_busy, 0) },
|
{ FLDATA (SIOBSY, sio_busy, 0) },
|
||||||
{ FLDATA (CHANSR, channel_sr, 0) },
|
{ FLDATA (CHANSR, channel_sr, 0) },
|
||||||
{ FLDATA (DEVSR, device_sr, 0) },
|
{ FLDATA (DEVSR, device_sr, 0) },
|
||||||
|
@ -1178,12 +1177,11 @@ static REG lp_reg [] = {
|
||||||
{ FLDATA (DFIN, device_flag_in, 0) },
|
{ FLDATA (DFIN, device_flag_in, 0) },
|
||||||
{ FLDATA (DENDIN, device_end_in, 0) },
|
{ FLDATA (DENDIN, device_end_in, 0) },
|
||||||
|
|
||||||
{ SRDATA (DIB, lp_dib, REG_HRO) },
|
DIB_REGS (lp_dib),
|
||||||
|
|
||||||
|
|
||||||
{ ORDATA (DIAGCN, dha_control_word, 16), PV_RZRO },
|
{ ORDATA (DIAGCN, dha_control_word, 16), PV_RZRO },
|
||||||
{ GRDATA (CNLED, control_word, 2, 5, 5), PV_RZRO },
|
{ GRDATA (CNLED, control_word, 2, 5, 5), PV_RZRO },
|
||||||
|
{ FLDATA (PFWARN, power_warning, 0) },
|
||||||
|
|
||||||
{ FLDATA (PFAULT, paper_fault, 0) },
|
{ FLDATA (PFAULT, paper_fault, 0) },
|
||||||
{ FLDATA (TFAULT, tape_fault, 0) },
|
{ FLDATA (TFAULT, tape_fault, 0) },
|
||||||
|
@ -1196,13 +1194,15 @@ static REG lp_reg [] = {
|
||||||
|
|
||||||
{ DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO },
|
{ DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO },
|
||||||
{ BRDATA (TITLE, vfu_title, 8, 8, LINE_SIZE), REG_HRO },
|
{ BRDATA (TITLE, vfu_title, 8, 8, LINE_SIZE), REG_HRO },
|
||||||
{ SRDATA (VFUREG, lp_reg [0], REG_HRO) },
|
|
||||||
{ BRDATA (VFU, VFU, 2, VFU_WIDTH, VFU_SIZE), PV_RZRO | REG_RO },
|
{ BRDATA (VFU, VFU, 2, VFU_WIDTH, VFU_SIZE), PV_RZRO | REG_RO },
|
||||||
|
{ ORDATA (PCHR, punched_char, 8), PV_RZRO | REG_A },
|
||||||
|
{ ORDATA (UPCHR, unpunched_char, 8), PV_RZRO | REG_A },
|
||||||
|
|
||||||
{ DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ },
|
{ DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ },
|
||||||
{ DRDATA (PTIME, fast_times.print, 24), PV_LEFT | REG_NZ },
|
{ DRDATA (PTIME, fast_times.print, 24), PV_LEFT | REG_NZ },
|
||||||
{ DRDATA (STIME, fast_times.advance, 24), PV_LEFT | REG_NZ },
|
{ DRDATA (STIME, fast_times.advance, 24), PV_LEFT | REG_NZ },
|
||||||
{ DRDATA (POS, lp_unit [0].pos, T_ADDR_W), PV_LEFT },
|
{ DRDATA (POS, lp_unit [0].pos, T_ADDR_W), PV_LEFT },
|
||||||
|
{ DRDATA (UWAIT, lp_unit [0].wait, 32), PV_LEFT | REG_HRO },
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -1232,7 +1232,7 @@ static MTAB lp_mod [] = {
|
||||||
{ UNIT_EXPAND, 0, "compact output", "COMPACT", NULL, NULL, NULL, },
|
{ UNIT_EXPAND, 0, "compact output", "COMPACT", NULL, NULL, NULL, },
|
||||||
|
|
||||||
/* Entry Flags Value Print String Match String Validation Display Descriptor */
|
/* Entry Flags Value Print String Match String Validation Display Descriptor */
|
||||||
/* ------------------ ----------- ------------ ------------ ------------ ------------- ---------------- */
|
/* ------------------- ----------- ------------ ------------ ------------ ------------- ---------------- */
|
||||||
{ MTAB_XDV, Fast_Time, NULL, "FASTTIME", &lp_set_mode, NULL, NULL },
|
{ MTAB_XDV, Fast_Time, NULL, "FASTTIME", &lp_set_mode, NULL, NULL },
|
||||||
{ MTAB_XDV, Real_Time, NULL, "REALTIME", &lp_set_mode, NULL, NULL },
|
{ MTAB_XDV, Real_Time, NULL, "REALTIME", &lp_set_mode, NULL, NULL },
|
||||||
{ MTAB_XDV, Printer, NULL, "PRINTER", &lp_set_mode, NULL, NULL },
|
{ MTAB_XDV, Printer, NULL, "PRINTER", &lp_set_mode, NULL, NULL },
|
||||||
|
@ -1244,6 +1244,7 @@ static MTAB lp_mod [] = {
|
||||||
{ MTAB_XDV, VAL_INTPRI, "INTPRI", "INTPRI", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
|
{ MTAB_XDV, VAL_INTPRI, "INTPRI", "INTPRI", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
|
||||||
{ MTAB_XDV, VAL_SRNO, "SRNO", "SRNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
|
{ MTAB_XDV, VAL_SRNO, "SRNO", "SRNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
|
||||||
|
|
||||||
|
{ MTAB_XDV | MTAB_NMO, 1, "VFU", NULL, NULL, &lp_show_vfu, NULL },
|
||||||
{ MTAB_XDV | MTAB_NC, 0, "VFU", "VFU", &lp_set_vfu, &lp_show_vfu, NULL },
|
{ MTAB_XDV | MTAB_NC, 0, "VFU", "VFU", &lp_set_vfu, &lp_show_vfu, NULL },
|
||||||
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
|
@ -1343,7 +1344,10 @@ DEVICE lp_dev = {
|
||||||
2. In hardware, the SETJMP signal is ignored, and the JMPMET signal is
|
2. In hardware, the SETJMP signal is ignored, and the JMPMET signal is
|
||||||
asserted continuously when enabled by CHANSO.
|
asserted continuously when enabled by CHANSO.
|
||||||
|
|
||||||
3. Sending a power fail warning to the device is not currently simulated.
|
3. In hardware, a power fail warning (PFWARN) is asserted continuously from
|
||||||
|
detection until power is lost. In simulation, the "power_warning" flag
|
||||||
|
is set by a PFWARN assertion and is cleared by a power-on reset. PFWARN
|
||||||
|
is used only by the DHA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static SIGNALS_DATA ui_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
|
static SIGNALS_DATA ui_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value)
|
||||||
|
@ -1622,7 +1626,8 @@ while (working_set) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case PFWARN: /* not currently simulated */
|
case PFWARN:
|
||||||
|
power_warning = TRUE; /* system power is in the process of failing */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2382,6 +2387,13 @@ return SCPE_OK;
|
||||||
|
|
||||||
2. The DHA transfer service is called with a null pointer to update the
|
2. The DHA transfer service is called with a null pointer to update the
|
||||||
potential change in the flag state.
|
potential change in the flag state.
|
||||||
|
|
||||||
|
3. Setting bit 2 of the DHA control word reflects the current state of the
|
||||||
|
PON and ~PFWARN signals in status bits 9 and 10, respectively. Status 9
|
||||||
|
is always set, as PON is always active while the machine is operating.
|
||||||
|
Status 10 is normally set to indicate that PFWARN is denied. However, if
|
||||||
|
the system power is failing, PFWARN is asserted from detection until
|
||||||
|
power is lost.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static OUTBOUND_SET diag_control (uint32 control_word)
|
static OUTBOUND_SET diag_control (uint32 control_word)
|
||||||
|
@ -2426,7 +2438,10 @@ if (control_word & CN_DHA_FN_ENABLE) /* if the decoder is ena
|
||||||
|
|
||||||
|
|
||||||
if (dha_control_word & DHA_STAT_SEL) { /* if status follows master clear/power on/power fail */
|
if (dha_control_word & DHA_STAT_SEL) { /* if status follows master clear/power on/power fail */
|
||||||
new_status = ST_DHA_PON | ST_DHA_NOT_PF; /* then indicate that power is on and has not failed */
|
new_status = ST_DHA_PON; /* then indicate that power is on */
|
||||||
|
|
||||||
|
if (power_warning == FALSE) /* if we have seen a PFWARN signal */
|
||||||
|
new_status |= ST_DHA_NOT_PF; /* then indicate that power has not failed */
|
||||||
|
|
||||||
if (dha_control_word & DHA_MR) /* if a master reset is requested */
|
if (dha_control_word & DHA_MR) /* if a master reset is requested */
|
||||||
new_status |= ST_DHA_MR; /* then indicate a master clear */
|
new_status |= ST_DHA_MR; /* then indicate a master clear */
|
||||||
|
@ -2535,20 +2550,14 @@ return outbound_signals; /* return INTREQ if any
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. Slewing in expanded mode is performed by appending CR LF pairs to the
|
1. Because attached files are opened in binary mode, newline translation
|
||||||
character buffer and then writing the combined buffer to the file. The
|
|
||||||
size of the buffer must accommodate the largest print line (136
|
|
||||||
characters) plus the largest possible slew (144 lines * 2 characters per
|
|
||||||
line) plus a trailing NUL.
|
|
||||||
|
|
||||||
2. Because attached files are opened in binary mode, newline translation
|
|
||||||
(i.e., from LF to CR LF) is not performed by the host system. Therefore,
|
(i.e., from LF to CR LF) is not performed by the host system. Therefore,
|
||||||
we write explicit CR LF pairs to end lines, even in compact mode, as
|
we write explicit CR LF pairs to end lines, even in compact mode, as
|
||||||
required for fidelity to HP peripherals. If bare LFs are used by the
|
required for fidelity to HP peripherals. If bare LFs are used by the
|
||||||
host system, the printer output file must be postprocessed to remove the
|
host system, the printer output file must be postprocessed to remove the
|
||||||
CRs.
|
CRs.
|
||||||
|
|
||||||
3. Overprinting in expanded mode is simulated by merging the lines in the
|
2. Overprinting in expanded mode is simulated by merging the lines in the
|
||||||
buffer. A format command to suppress spacing resets the buffer index but
|
buffer. A format command to suppress spacing resets the buffer index but
|
||||||
saves the previous buffer length as a "high water mark" that will be
|
saves the previous buffer length as a "high water mark" that will be
|
||||||
extended if the overlaying line is longer. This process may be repeated
|
extended if the overlaying line is longer. This process may be repeated
|
||||||
|
@ -2561,20 +2570,20 @@ return outbound_signals; /* return INTREQ if any
|
||||||
"overprint character" (which defaults to DEL, but can be changed by the
|
"overprint character" (which defaults to DEL, but can be changed by the
|
||||||
user) replaces the character in the buffer.
|
user) replaces the character in the buffer.
|
||||||
|
|
||||||
4. Printers that support 12-channel VFUs treat the VFU format command as
|
3. Printers that support 12-channel VFUs treat the VFU format command as
|
||||||
modulo 16. Printers that support 8-channel VFUs treat the command as
|
modulo 16. Printers that support 8-channel VFUs treat the command as
|
||||||
modulo 8.
|
modulo 8.
|
||||||
|
|
||||||
5. As a convenience to the user, the printer output file is flushed when a
|
4. As a convenience to the user, the printer output file is flushed when a
|
||||||
TOF operation is performed.
|
TOF operation is performed.
|
||||||
|
|
||||||
6. The user may examine the TFAULT and PFAULT registers to determine why the
|
5. The user may examine the TFAULT and PFAULT registers to determine why the
|
||||||
printer went offline.
|
printer went offline.
|
||||||
|
|
||||||
7. The transfer service may be called with a null pointer to update the
|
6. The transfer service may be called with a null pointer to update the
|
||||||
potential change in the flag state.
|
potential change in the flag state.
|
||||||
|
|
||||||
8. If printing is attempted with the printer offline, this routine will be
|
7. If printing is attempted with the printer offline, this routine will be
|
||||||
called with STROBE asserted (device_command_in TRUE) and DEMAND denied
|
called with STROBE asserted (device_command_in TRUE) and DEMAND denied
|
||||||
(device_flag_in TRUE). The printer ignores STROBE if DEMAND is not
|
(device_flag_in TRUE). The printer ignores STROBE if DEMAND is not
|
||||||
asserted, so we simply return in this case. This will hang the handshake
|
asserted, so we simply return in this case. This will hang the handshake
|
||||||
|
@ -2648,9 +2657,6 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
|
||||||
buffer_index++; /* increment the buffer index */
|
buffer_index++; /* increment the buffer index */
|
||||||
|
|
||||||
uptr->wait = dlyptr->buffer_load; /* schedule the buffer load delay */
|
uptr->wait = dlyptr->buffer_load; /* schedule the buffer load delay */
|
||||||
|
|
||||||
dprintf (lp_dev, DEB_XFER, "Character %s sent to printer\n",
|
|
||||||
fmt_char (data_byte));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else { /* otherwise the buffer is full */
|
else { /* otherwise the buffer is full */
|
||||||
|
@ -2678,13 +2684,13 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
|
||||||
buffer [0] = data_byte; /* store the character */
|
buffer [0] = data_byte; /* store the character */
|
||||||
buffer_index = 1; /* in the empty buffer */
|
buffer_index = 1; /* in the empty buffer */
|
||||||
|
|
||||||
dprintf (lp_dev, DEB_XFER, "Character %s sent to printer\n",
|
|
||||||
fmt_char (data_byte));
|
|
||||||
|
|
||||||
uptr->wait = dlyptr->print /* schedule the print delay */
|
uptr->wait = dlyptr->print /* schedule the print delay */
|
||||||
+ dlyptr->advance /* plus the paper advance delay */
|
+ dlyptr->advance /* plus the paper advance delay */
|
||||||
+ dlyptr->buffer_load; /* plus the buffer load delay */
|
+ dlyptr->buffer_load; /* plus the buffer load delay */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dprintf (lp_dev, DEB_XFER, "Character %s sent to printer\n",
|
||||||
|
fmt_char (data_byte));
|
||||||
}
|
}
|
||||||
|
|
||||||
else { /* otherwise this is a print format command */
|
else { /* otherwise this is a print format command */
|
||||||
|
@ -3010,16 +3016,11 @@ return SCPE_OK; /* the mode change succe
|
||||||
This validation routine is called to set the model of the printer. The
|
This validation routine is called to set the model of the printer. The
|
||||||
"value" parameter is one of the UNIT_26nn constants that indicates the new
|
"value" parameter is one of the UNIT_26nn constants that indicates the new
|
||||||
model. Validation isn't necessary, except to detect a model change and alter
|
model. Validation isn't necessary, except to detect a model change and alter
|
||||||
the real-time delays and the VFU display width and offset fields accordingly.
|
the real-time delays accordingly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat lp_set_model (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
|
static t_stat lp_set_model (UNIT *uptr, int32 value, CONST char *cptr, void *desc)
|
||||||
{
|
{
|
||||||
const PRINTER_TYPE model = GET_MODEL (value); /* get the model associated with the value */
|
|
||||||
|
|
||||||
vfu_reg->width = print_props [model].vfu_channels; /* set the number of VFU channels to display */
|
|
||||||
vfu_reg->offset = VFU_WIDTH - vfu_reg->width; /* and the offset to the last channel */
|
|
||||||
|
|
||||||
if (lp_dev.flags & DEV_REALTIME) /* if the printer is in real-time mode */
|
if (lp_dev.flags & DEV_REALTIME) /* if the printer is in real-time mode */
|
||||||
dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* then use the times for the new model */
|
dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* then use the times for the new model */
|
||||||
|
|
||||||
|
@ -3145,17 +3146,61 @@ return SCPE_OK;
|
||||||
|
|
||||||
/* Show the VFU tape.
|
/* Show the VFU tape.
|
||||||
|
|
||||||
This display routine is called to show the title of the tape currently loaded
|
This display routine is called to show the content of the tape currently
|
||||||
in the printer's VFU. The title is taken from the tape image file if a
|
loaded in the printer's VFU. The "value" parameter indicates how the routine
|
||||||
custom tape is loaded. Otherwise, the standard tape title is displayed.
|
was called. It is 0 if a SHOW LP command was given and 1 if a SHOW LP VFU
|
||||||
|
command was issued. For the former, only the VFU title is displayed. The
|
||||||
|
latter displays the VFU title, followed by a header labelling each of the
|
||||||
|
channel columns and then one line for each line of the form consisting of
|
||||||
|
punch and no-punch characters, according to the VFU definition.
|
||||||
|
|
||||||
The output stream is passed in the "st" parameter, and the other parameters
|
The output stream is passed in the "st" parameter, and the "uptr" and "desc"
|
||||||
are ignored.
|
parameters are ignored.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation notes:
|
||||||
|
|
||||||
|
1. Setting the string precision for the header lines trims them to the
|
||||||
|
appropriate number of channels.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, CONST void *desc)
|
static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, CONST void *desc)
|
||||||
{
|
{
|
||||||
fputs (vfu_title, st); /* print the VFU title */
|
static const char header_1 [] = " Ch 1 Ch 2 Ch 3 Ch 4 Ch 5 Ch 6 Ch 7 Ch 8 Ch 9 Ch10 Ch11 Ch12";
|
||||||
|
static const char header_2 [] = " ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----";
|
||||||
|
|
||||||
|
const PRINTER_TYPE model = GET_MODEL (uptr->flags);
|
||||||
|
const uint32 channel_count = print_props [model].vfu_channels;
|
||||||
|
uint32 chan, line, current_channel;
|
||||||
|
|
||||||
|
if (value == 0) /* if we're called for a summary display */
|
||||||
|
fputs (vfu_title, st); /* then output only the VFU title */
|
||||||
|
|
||||||
|
else { /* otherwise the full VFU definition is requested */
|
||||||
|
fprintf (st, "\n%s tape is loaded.\n\n", vfu_title); /* so start by displaying the VFU title */
|
||||||
|
|
||||||
|
fprintf (st, "Line %.*s\n", channel_count * 5, header_1); /* display the */
|
||||||
|
fprintf (st, "---- %.*s\n", channel_count * 5, header_2); /* channel headers */
|
||||||
|
|
||||||
|
for (line = 1; line <= form_length; line++) { /* loop through the VFU array */
|
||||||
|
fprintf (st, "%3d ", line); /* display the current form line number */
|
||||||
|
|
||||||
|
current_channel = VFU_CHANNEL_1; /* start with channel 1 */
|
||||||
|
|
||||||
|
for (chan = 1; chan <= channel_count; chan++) { /* loop through the defined channels */
|
||||||
|
fputs (" ", st); /* add some space */
|
||||||
|
|
||||||
|
if (VFU [line] & current_channel) /* if the current channel is punched for this line */
|
||||||
|
fputc (punched_char, st); /* then display a punched location */
|
||||||
|
else /* otherwise */
|
||||||
|
fputc (unpunched_char, st); /* display an unpunched location */
|
||||||
|
|
||||||
|
current_channel = current_channel >> 1; /* move to the next channel */
|
||||||
|
}
|
||||||
|
|
||||||
|
fputc ('\n', st); /* end the line */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -3191,19 +3236,8 @@ return SCPE_OK;
|
||||||
online).
|
online).
|
||||||
|
|
||||||
In addition, if a power-on reset (RESET -P) is done, the original FASTTIME
|
In addition, if a power-on reset (RESET -P) is done, the original FASTTIME
|
||||||
settings are restored, the pointer to the VFU register is determined, and the
|
settings are restored, the standard VFU tape is loaded, and the power failure
|
||||||
standard VFU tape is loaded.
|
warning is cleared.
|
||||||
|
|
||||||
|
|
||||||
Implementation notes:
|
|
||||||
|
|
||||||
1. Setting the "vfu_reg" pointer at run time accommodates changes in the
|
|
||||||
register order automatically. A fixed setting runs the risk of it not
|
|
||||||
being updated if a change in the register order is made.
|
|
||||||
|
|
||||||
2. The location field of the register entry preceding the VFU register is
|
|
||||||
changed to point at the VFU register. This is required to preserve the
|
|
||||||
dynamic VFU register settings across a SAVE and RESTORE operation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat lp_reset (t_bool programmed_clear)
|
static t_stat lp_reset (t_bool programmed_clear)
|
||||||
|
@ -3217,18 +3251,9 @@ if (! programmed_clear && (sim_switches & SWMASK ('P'))) { /* if this is a comm
|
||||||
fast_times.print = LP_PRINT; /* the print and advance-one-line time, */
|
fast_times.print = LP_PRINT; /* the print and advance-one-line time, */
|
||||||
fast_times.advance = LP_ADVANCE; /* and the slew additional lines time */
|
fast_times.advance = LP_ADVANCE; /* and the slew additional lines time */
|
||||||
|
|
||||||
for (vfu_reg = lp_reg; /* find the VFU register entry */
|
|
||||||
vfu_reg->loc != VFU && vfu_reg->loc != NULL; /* in the register array */
|
|
||||||
vfu_reg++);
|
|
||||||
|
|
||||||
if (vfu_reg == NULL) /* if the VFU register entry is not present */
|
|
||||||
return SCPE_NXREG; /* then there is a serious problem! */
|
|
||||||
else /* otherwise */
|
|
||||||
(vfu_reg - 1)->loc = (void *) vfu_reg; /* point the prior entry's location at the VFU register */
|
|
||||||
|
|
||||||
result = lp_load_vfu (xfer_uptr, NULL); /* load the standard VFU tape */
|
result = lp_load_vfu (xfer_uptr, NULL); /* load the standard VFU tape */
|
||||||
|
|
||||||
lp_set_model (NULL, xfer_unit.flags, NULL, NULL); /* set the VFU register width and offset */
|
power_warning = FALSE; /* clear the power failure warning */
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_index = 0; /* clear the buffer without printing */
|
buffer_index = 0; /* clear the buffer without printing */
|
||||||
|
@ -3436,7 +3461,7 @@ return TRUE;
|
||||||
no-punch character a single character representing a non-punched location
|
no-punch character a single character representing a non-punched location
|
||||||
|
|
||||||
title an optional descriptive string printed by the SHOW LP
|
title an optional descriptive string printed by the SHOW LP
|
||||||
VFU command ("custom VFU" is used by default)
|
VFU command ("Custom VFU" is used by default)
|
||||||
|
|
||||||
If the "VFU" line is missing or not of the correct form, then "Format error"
|
If the "VFU" line is missing or not of the correct form, then "Format error"
|
||||||
status is returned, and the VFU tape is not changed.
|
status is returned, and the VFU tape is not changed.
|
||||||
|
@ -3488,10 +3513,6 @@ return TRUE;
|
||||||
logical OR of all of the other entries and is used during VFU format
|
logical OR of all of the other entries and is used during VFU format
|
||||||
command processing to determine if a punch is present somewhere in a
|
command processing to determine if a punch is present somewhere in a
|
||||||
given channel.
|
given channel.
|
||||||
|
|
||||||
2. The depth field of the VFU register is set to the form length so that an
|
|
||||||
EXAMINE LP VFU[ALL] command will display only the defined VFU.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat lp_load_vfu (UNIT *uptr, FILE *vf)
|
static t_stat lp_load_vfu (UNIT *uptr, FILE *vf)
|
||||||
|
@ -3504,7 +3525,7 @@ char *bptr, *tptr;
|
||||||
uint16 tape [VFU_SIZE] = { 0 };
|
uint16 tape [VFU_SIZE] = { 0 };
|
||||||
|
|
||||||
if (vf == NULL) { /* if the standard VFU is requested */
|
if (vf == NULL) { /* if the standard VFU is requested */
|
||||||
strcpy (vfu_title, "standard VFU"); /* then set the title */
|
strcpy (vfu_title, "Standard VFU"); /* then set the title */
|
||||||
|
|
||||||
tape [ 1] = VFU_CHANNEL_1; /* punch channel 1 for the top of form */
|
tape [ 1] = VFU_CHANNEL_1; /* punch channel 1 for the top of form */
|
||||||
tape [60] = VFU_CHANNEL_2 | VFU_CHANNEL_9; /* punch channels 2 and 9 for the bottom of form */
|
tape [60] = VFU_CHANNEL_2 | VFU_CHANNEL_9; /* punch channels 2 and 9 for the bottom of form */
|
||||||
|
@ -3557,7 +3578,7 @@ else { /* otherwise load a cust
|
||||||
if (tptr != NULL) /* if it's present */
|
if (tptr != NULL) /* if it's present */
|
||||||
strcpy (vfu_title, tptr); /* then save the user's title */
|
strcpy (vfu_title, tptr); /* then save the user's title */
|
||||||
else /* otherwise */
|
else /* otherwise */
|
||||||
strcpy (vfu_title, "custom VFU"); /* use a generic title */
|
strcpy (vfu_title, "Custom VFU"); /* use a generic title */
|
||||||
|
|
||||||
|
|
||||||
for (line = 1; line <= VFU_MAX; line++) { /* load up to the maximum VFU tape length */
|
for (line = 1; line <= VFU_MAX; line++) { /* load up to the maximum VFU tape length */
|
||||||
|
@ -3610,8 +3631,6 @@ if (print_props [model].vfu_channels > 8) { /* if the printer VFU ha
|
||||||
|
|
||||||
set_device_status (ST_VFU_9 | ST_VFU_12, vfu_status); /* set the VFU status */
|
set_device_status (ST_VFU_9 | ST_VFU_12, vfu_status); /* set the VFU status */
|
||||||
|
|
||||||
vfu_reg->depth = form_length + 1; /* set the VFU display depth */
|
|
||||||
|
|
||||||
return SCPE_OK; /* the VFU was successfully loaded */
|
return SCPE_OK; /* the VFU was successfully loaded */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
MPX HP 3000 Series III Multiplexer Channel
|
MPX HP 3000 Series III Multiplexer Channel
|
||||||
|
|
||||||
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
|
15-Jul-16 JDB Fixed the word count display for DREADSTB trace
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
07-Jun-16 JDB Corrected ACKSR assertion in State A for chained orders
|
07-Jun-16 JDB Corrected ACKSR assertion in State A for chained orders
|
||||||
16-May-16 JDB abort_channel parameter is now a pointer-to-constant
|
16-May-16 JDB abort_channel parameter is now a pointer-to-constant
|
||||||
|
@ -732,7 +734,7 @@ static REG mpx_reg [] = {
|
||||||
{ ORDATA (CTRREG, cntr_reg, 16), REG_FIT | REG_HRO },
|
{ ORDATA (CTRREG, cntr_reg, 16), REG_FIT | REG_HRO },
|
||||||
{ ORDATA (ADRREG, addr_reg, 16), REG_FIT | REG_HRO },
|
{ ORDATA (ADRREG, addr_reg, 16), REG_FIT | REG_HRO },
|
||||||
|
|
||||||
{ SRDATA (DIB, mpx_dib, REG_HRO) },
|
DIB_REGS (mpx_dib),
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -1737,7 +1739,7 @@ while (working_set) {
|
||||||
dprintf (mpx_dev, DEB_CSRW, "Order register value %02o (%s) "
|
dprintf (mpx_dev, DEB_CSRW, "Order register value %02o (%s) "
|
||||||
"and counter register value %d returned\n",
|
"and counter register value %d returned\n",
|
||||||
order_reg & ORDER_MASK, sio_order_name [IOCW_ORDER (outbound_value)],
|
order_reg & ORDER_MASK, sio_order_name [IOCW_ORDER (outbound_value)],
|
||||||
IOCW_COUNT (outbound_value));
|
SEXT (IOCW_COUNT (outbound_value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (control_word & CN_ADDR_RAM) { /* if the address register is selected */
|
if (control_word & CN_ADDR_RAM) { /* if the address register is selected */
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
MS HP 30215A Magnetic Tape Controller Interface
|
MS HP 30215A Magnetic Tape Controller Interface
|
||||||
|
|
||||||
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
16-May-16 JDB Fixed interrupt mask setting
|
16-May-16 JDB Fixed interrupt mask setting
|
||||||
|
@ -517,7 +518,8 @@ static REG ms_reg [] = {
|
||||||
{ DRDATA (ATUNIT, attention_unit, 16), REG_FIT | PV_LEFT },
|
{ DRDATA (ATUNIT, attention_unit, 16), REG_FIT | PV_LEFT },
|
||||||
{ DRDATA (CLASS, command_class, 4), PV_LEFT },
|
{ DRDATA (CLASS, command_class, 4), PV_LEFT },
|
||||||
{ YRDATA (FLAGS, flags, 8, PV_RZRO) },
|
{ YRDATA (FLAGS, flags, 8, PV_RZRO) },
|
||||||
{ SRDATA (DIB, ms_dib, REG_HRO) },
|
|
||||||
|
DIB_REGS (ms_dib),
|
||||||
|
|
||||||
TL_REGS (ms_cntlr, ms_unit, DRIVE_COUNT, buffer, fast_times),
|
TL_REGS (ms_cntlr, ms_unit, DRIVE_COUNT, buffer, fast_times),
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
SIMH/HP 3000 RELEASE NOTES
|
SIMH/HP 3000 RELEASE NOTES
|
||||||
==========================
|
==========================
|
||||||
Last update: 2016-07-05
|
Last update: 2016-09-20
|
||||||
|
|
||||||
|
|
||||||
This file documents the release history of the Hewlett-Packard 3000 simulator.
|
This file documents the release history of the Hewlett-Packard 3000 simulator.
|
||||||
|
@ -45,7 +45,7 @@ The simulator has been tested with MPE-V/R version E.01.00. Specifically:
|
||||||
run properly.
|
run properly.
|
||||||
|
|
||||||
- The SYSDUMP program produces a valid tape image, and the system may be
|
- The SYSDUMP program produces a valid tape image, and the system may be
|
||||||
COLDSTARTED from it.
|
COLDSTARTed from it.
|
||||||
|
|
||||||
- The operator and system manager can be logged in and out, and MPE can be
|
- The operator and system manager can be logged in and out, and MPE can be
|
||||||
SHUTDOWN through to a HALT 17.
|
SHUTDOWN through to a HALT 17.
|
||||||
|
@ -158,6 +158,187 @@ the MPE version used:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=====================
|
||||||
|
Release 3, 2016-09-20
|
||||||
|
=====================
|
||||||
|
|
||||||
|
This release of the HP 3000 simulator adds the following features:
|
||||||
|
|
||||||
|
- Cold dump is now available. Entering the DUMP command simulates pressing
|
||||||
|
the ENABLE and DUMP front panel buttons. The contents of main memory are
|
||||||
|
written to an attached magnetic tape in a format suitable for analyzing with
|
||||||
|
the DPAN4 program. The new SET CPU DUMPDEV and SET CPU DUMPCTL options
|
||||||
|
specify the default device number and control byte for the dump.
|
||||||
|
|
||||||
|
- The SHOW LP VFU command now displays the VFU channel definitions in
|
||||||
|
addition to the VFU tape title.
|
||||||
|
|
||||||
|
- The POWER FAIL and POWER RESTORE commands have been added to simulate losing
|
||||||
|
and regaining system power.
|
||||||
|
|
||||||
|
- The SET CPU ARS and SET CPU NOARS options have been added to simulate the
|
||||||
|
power-fail/auto-restart switch on the back of the system front panel.
|
||||||
|
|
||||||
|
- The CMD instruction has been implemented and passes section 4 of the CPU
|
||||||
|
diagnostic.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
Implementation Notes
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- In hardware, MPE execution cannot continue after a DUMP is performed. This
|
||||||
|
is because a cold dump performs an I/O reset before writing the contents of
|
||||||
|
memory to the tape, and this clears the I/O device controllers to their
|
||||||
|
initial power-on states. However, execution can be continued if a SAVE is
|
||||||
|
done to record the simulator state before the dump and a RESTORE is done
|
||||||
|
after the dump completes. This permits taking a "snapshot" of MPE operation
|
||||||
|
without disturbing MPE.
|
||||||
|
|
||||||
|
|
||||||
|
----------
|
||||||
|
Bugs Fixed
|
||||||
|
----------
|
||||||
|
|
||||||
|
1. PROBLEM: An SIO READ or WRITE order with a 4K count displays as zero.
|
||||||
|
|
||||||
|
VERSION: Release 2
|
||||||
|
|
||||||
|
OBSERVATION: SIO READ and WRITE orders define bits 4-15 as the negative
|
||||||
|
word count of the transfer. If bits 4-15 are zero, the transfer is 4096
|
||||||
|
words long. However, an EXAMINE -I command displays the word count as
|
||||||
|
zero.
|
||||||
|
|
||||||
|
CAUSE: The display value is being calculated incorrectly.
|
||||||
|
|
||||||
|
RESOLUTION: Modify "IOCW_COUNT" (hp3000_cpu_ims.h) to sign-extend the
|
||||||
|
12-bit count correctly to 16 bits, and modify "fprint_order" (hp3000_sys.c)
|
||||||
|
to negate the values to display the counts as positive. Also modify
|
||||||
|
"mpx_interface" (hp3000_mpx.c) to display the correct count in the debug
|
||||||
|
trace for the DREADSTB operation.
|
||||||
|
|
||||||
|
STATUS: Fixed in Release 3.
|
||||||
|
|
||||||
|
|
||||||
|
2. PROBLEM: An I/O reset does not clear a pending external interrupt.
|
||||||
|
|
||||||
|
VERSION: Release 2
|
||||||
|
|
||||||
|
OBSERVATION: A cold load begins with a CPU reset and an I/O reset. A cold
|
||||||
|
dump begins with an I/O reset only to preserve the CPU state for the dump
|
||||||
|
operation. The external interrupt flip-flop on the IOP is cleared by an
|
||||||
|
I/O reset, which should clear the external interrupt bit in the CPX1
|
||||||
|
register. However, this does not occur, causing the interrupt generated by
|
||||||
|
placing the tape drive online to be misinterpreted as the SIO program
|
||||||
|
completion interrupt. Because the SIO pointer is not set as expected, the
|
||||||
|
cold dump microcode assumes that a tape error occurred and performs a
|
||||||
|
retry. This writes an erase gap at the beginning of the tape but otherwise
|
||||||
|
produces a valid tape.
|
||||||
|
|
||||||
|
CAUSE: Oversight.
|
||||||
|
|
||||||
|
RESOLUTION: Add a new "iop_reset" routine (hp3000_iop.c) that is called
|
||||||
|
during an I/O reset and that clears the external interrupt bit of the CPX1
|
||||||
|
register.
|
||||||
|
|
||||||
|
STATUS: Fixed in Release 3.
|
||||||
|
|
||||||
|
|
||||||
|
3. PROBLEM: RESTORE of a file SAVEd with a different executable may abort the
|
||||||
|
simulator.
|
||||||
|
|
||||||
|
VERSION: Release 2
|
||||||
|
|
||||||
|
OBSERVATION: Entering SAVE to save the simulator state on an executable
|
||||||
|
compiled with one set of compiler options or compiler version and then
|
||||||
|
entering RESTORE to restore the state on an executable compiled with a
|
||||||
|
different set of compiler options or compiler version succeeds. However,
|
||||||
|
attempting to resume execution results in an access exception.
|
||||||
|
|
||||||
|
CAUSE: The simulator's internal Device Information Blocks contain pointers
|
||||||
|
to the devices' I/O interface handlers, which are saved as part of the DIB
|
||||||
|
structure in the simulator state file. When restoring the state, the
|
||||||
|
interface handler pointers are restored. However, the addresses of one or
|
||||||
|
more routines may have changed, due to differing memory layouts, so the
|
||||||
|
restored values are no longer correct. If they are not, and I/O is
|
||||||
|
performed to the affected device(s), control transfers to an invalid code
|
||||||
|
location.
|
||||||
|
|
||||||
|
RESOLUTION: Modify hp3000_io.h to add a new REG_DIB macro that defines the
|
||||||
|
register entries needed to save the DIB state, and modify hp3000_atc.c,
|
||||||
|
hp3000_clk.c, hp3000_ds.c, hp3000_lp.c, hp3000_mpx.c, hp3000_ms.c, and
|
||||||
|
hp3000_scmb.c to change the REG entries referencing the DIB structures to
|
||||||
|
use the REG_DIB macro.
|
||||||
|
|
||||||
|
STATUS: Fixed in Release 3.
|
||||||
|
|
||||||
|
|
||||||
|
4. PROBLEM: The LOAD command does not report "Cold load complete".
|
||||||
|
|
||||||
|
VERSION: Release 2
|
||||||
|
|
||||||
|
OBSERVATION: The LOAD command should report success after completion of a
|
||||||
|
cold load operation, but it doesn't. Instead, the SCP prompt returns with
|
||||||
|
no indication of whether the command succeeded or failed. Using the
|
||||||
|
equivalent BOOT CPU command does print the expected "Cold load complete"
|
||||||
|
message.
|
||||||
|
|
||||||
|
CAUSE: The "Cold load complete" message is printed by the simulator's
|
||||||
|
"fprint_stopped" routine that is called via the "sim_vm_fprint_stopped"
|
||||||
|
pointer from the "run_cmd_message" routine in SCP. The latter is invoked
|
||||||
|
via the "message" field of the command table. The LOAD, DUMP, and POWER
|
||||||
|
commands all invoke "sim_instr" via "run_cmd" but do not specify routine
|
||||||
|
pointers for their message fields, so no completion messages are reported.
|
||||||
|
|
||||||
|
RESOLUTION: Modify "one_time_init" (hp3000_sys.c) to set the "message"
|
||||||
|
fields of the LOAD, DUMP, and POWER commands to point at the same routine
|
||||||
|
as is used by the system "CONTINUE" command.
|
||||||
|
|
||||||
|
STATUS: Fixed in Release 3.
|
||||||
|
|
||||||
|
|
||||||
|
5. PROBLEM: RESTOREing with the ATCD attached cancels active line services.
|
||||||
|
|
||||||
|
VERSION: Release 2
|
||||||
|
|
||||||
|
OBSERVATION: Doing a SAVE while the ATCD has line services scheduled,
|
||||||
|
e.g., while outputting characters, and then following immediately with a
|
||||||
|
RESTORE cancels the line services. For example, after a SAVE, a SHOW QUEUE
|
||||||
|
command prints:
|
||||||
|
|
||||||
|
HP 3000 event queue status, time = 907247803
|
||||||
|
CLK at 0
|
||||||
|
ATCD unit 0 at 241
|
||||||
|
CPU at 27917
|
||||||
|
ATCD unit 16 at 27918
|
||||||
|
DS unit 8 at 612615
|
||||||
|
|
||||||
|
Entering RESTORE and then SHOW QUEUE prints:
|
||||||
|
|
||||||
|
HP 3000 event queue status, time = 907247803
|
||||||
|
CLK at 0
|
||||||
|
CPU at 27917
|
||||||
|
ATCD unit 16 at 27918
|
||||||
|
DS unit 8 at 612615
|
||||||
|
|
||||||
|
Note that ATCD unit 0 is no longer scheduled.
|
||||||
|
|
||||||
|
CAUSE: The "atcd_detach" routine is called during RESTORE if the listening
|
||||||
|
port is currently attached in preparation for reattaching to the port
|
||||||
|
specified in the SAVE file. The routine detaches the listening port and
|
||||||
|
then cancels each line to terminate any transfers in progress. This is
|
||||||
|
appropriate for DETACH ATCD and DETACH ALL, but not for RESTORE, as the
|
||||||
|
terminal channels have already been rescheduled as indicated in the SAVE
|
||||||
|
file, and canceling them hangs the channels.
|
||||||
|
|
||||||
|
RESOLUTION: Modify "atcd_detach" (hp3000_atc.c) to skip the channel
|
||||||
|
termination loop if the SIM_SW_REST flag is set to indicate a RESTORE in
|
||||||
|
progress.
|
||||||
|
|
||||||
|
STATUS: Fixed in Release 3.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=====================
|
=====================
|
||||||
Release 2, 2016-07-05
|
Release 2, 2016-07-05
|
||||||
=====================
|
=====================
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
SCMB1,SCMB2 HP 30033A Selector Channel Maintenance Board
|
SCMB1,SCMB2 HP 30033A Selector Channel Maintenance Board
|
||||||
|
|
||||||
|
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
|
||||||
11-Jun-16 JDB Bit mask constants are now unsigned
|
11-Jun-16 JDB Bit mask constants are now unsigned
|
||||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||||
21-Mar-16 JDB Changed uint16 types to HP_WORD
|
21-Mar-16 JDB Changed uint16 types to HP_WORD
|
||||||
|
@ -462,7 +463,7 @@ static REG scmb1_reg [] = {
|
||||||
{ FLDATA (DEVEND, scmb [card1].device_end, 0) },
|
{ FLDATA (DEVEND, scmb [card1].device_end, 0) },
|
||||||
{ FLDATA (STOP, scmb [card1].stop_transfer, 0) },
|
{ FLDATA (STOP, scmb [card1].stop_transfer, 0) },
|
||||||
|
|
||||||
{ SRDATA (DIB, scmb_dib [card1], REG_HRO) },
|
DIB_REGS (scmb_dib [card1]),
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -489,7 +490,7 @@ static REG scmb2_reg [] = {
|
||||||
{ FLDATA (DEVEND, scmb [card2].device_end, 0) },
|
{ FLDATA (DEVEND, scmb [card2].device_end, 0) },
|
||||||
{ FLDATA (STOP, scmb [card2].stop_transfer, 0) },
|
{ FLDATA (STOP, scmb [card2].stop_transfer, 0) },
|
||||||
|
|
||||||
{ SRDATA (DIB, scmb_dib [card1], REG_HRO) },
|
DIB_REGS (scmb_dib [card2]),
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
SEL HP 3000 Series III Selector Channel
|
SEL HP 3000 Series III Selector Channel
|
||||||
|
|
||||||
|
11-Jul-16 JDB Change "sel_unit" from a UNIT to an array of one UNIT
|
||||||
30-Jun-16 JDB Reestablish active_dib pointer during sel_initialize
|
30-Jun-16 JDB Reestablish active_dib pointer during sel_initialize
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
16-May-16 JDB abort_channel parameter is now a pointer-to-constant
|
16-May-16 JDB abort_channel parameter is now a pointer-to-constant
|
||||||
|
@ -426,8 +427,8 @@ static void load_address (HP_WORD *value);
|
||||||
|
|
||||||
/* Unit list */
|
/* Unit list */
|
||||||
|
|
||||||
static UNIT sel_unit = {
|
static UNIT sel_unit [] = {
|
||||||
UDATA (&sel_timer, 0, 0), SR_WAIT_TIMER
|
{ UDATA (&sel_timer, 0, 0), SR_WAIT_TIMER }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Register list */
|
/* Register list */
|
||||||
|
@ -476,7 +477,7 @@ static DEBTAB sel_deb [] = {
|
||||||
|
|
||||||
DEVICE sel_dev = {
|
DEVICE sel_dev = {
|
||||||
"SEL", /* device name */
|
"SEL", /* device name */
|
||||||
&sel_unit, /* unit array */
|
sel_unit, /* unit array */
|
||||||
sel_reg, /* register array */
|
sel_reg, /* register array */
|
||||||
NULL, /* modifier array */
|
NULL, /* modifier array */
|
||||||
1, /* number of units */
|
1, /* number of units */
|
||||||
|
@ -608,7 +609,7 @@ else { /* otherwise abort the t
|
||||||
device_number);
|
device_number);
|
||||||
|
|
||||||
end_channel (dibptr); /* idle the channel */
|
end_channel (dibptr); /* idle the channel */
|
||||||
sim_cancel (&sel_unit); /* and cancel the CHANSR timer */
|
sim_cancel (&sel_unit [0]); /* and cancel the CHANSR timer */
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -817,7 +818,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
|
|
||||||
|
|
||||||
case Fetch_Sequence:
|
case Fetch_Sequence:
|
||||||
sim_cancel (&sel_unit); /* cancel the CHANSR timer */
|
sim_cancel (&sel_unit [0]); /* cancel the CHANSR timer */
|
||||||
|
|
||||||
load_control (&control_word); /* load the IOCW */
|
load_control (&control_word); /* load the IOCW */
|
||||||
load_address (&address_word); /* and the IOAW */
|
load_address (&address_word); /* and the IOAW */
|
||||||
|
@ -963,7 +964,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
prefetch_control = FALSE; /* prefetching is not used */
|
prefetch_control = FALSE; /* prefetching is not used */
|
||||||
prefetch_address = FALSE; /* for the Control order */
|
prefetch_address = FALSE; /* for the Control order */
|
||||||
|
|
||||||
sim_activate (&sel_unit, sel_unit.wait); /* start the SR timer */
|
sim_activate (&sel_unit [0], sel_unit [0].wait); /* start the SR timer */
|
||||||
sequencer = Wait_Sequence; /* and check for a timeout */
|
sequencer = Wait_Sequence; /* and check for a timeout */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -972,7 +973,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
prefetch_control = (order == sioWRITEC); /* enable prefetching */
|
prefetch_control = (order == sioWRITEC); /* enable prefetching */
|
||||||
prefetch_address = (order == sioWRITEC); /* if the order is chained */
|
prefetch_address = (order == sioWRITEC); /* if the order is chained */
|
||||||
|
|
||||||
sim_activate (&sel_unit, sel_unit.wait); /* start the SR timer */
|
sim_activate (&sel_unit [0], sel_unit [0].wait); /* start the SR timer */
|
||||||
sequencer = Wait_Sequence; /* and check for a timeout */
|
sequencer = Wait_Sequence; /* and check for a timeout */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -987,7 +988,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
prefetch_control = FALSE; /* mark the job done */
|
prefetch_control = FALSE; /* mark the job done */
|
||||||
}
|
}
|
||||||
|
|
||||||
sim_activate (&sel_unit, sel_unit.wait); /* start the SR timer */
|
sim_activate (&sel_unit [0], sel_unit [0].wait); /* start the SR timer */
|
||||||
sequencer = Wait_Sequence; /* and check for a timeout */
|
sequencer = Wait_Sequence; /* and check for a timeout */
|
||||||
break;
|
break;
|
||||||
} /* end switch */
|
} /* end switch */
|
||||||
|
@ -997,7 +998,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
|
|
||||||
|
|
||||||
case Wait_Sequence:
|
case Wait_Sequence:
|
||||||
sim_cancel (&sel_unit); /* cancel the SR timer */
|
sim_cancel (&sel_unit [0]); /* cancel the SR timer */
|
||||||
|
|
||||||
sequencer = Transfer_Sequence; /* continue with the transfer sequence */
|
sequencer = Transfer_Sequence; /* continue with the transfer sequence */
|
||||||
|
|
||||||
|
@ -1072,7 +1073,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order == sioCNTL) { /* if this is a Control order */
|
if (order == sioCNTL) { /* if this is a Control order */
|
||||||
sim_activate (&sel_unit, sel_unit.wait); /* then start the SR timer */
|
sim_activate (&sel_unit [0], sel_unit [0].wait); /* then start the SR timer */
|
||||||
sequencer = Fetch_Sequence; /* and the next state is Fetch */
|
sequencer = Fetch_Sequence; /* and the next state is Fetch */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1173,7 +1174,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
||||||
active_dib->service_request = FALSE; /* clear the current service request */
|
active_dib->service_request = FALSE; /* clear the current service request */
|
||||||
|
|
||||||
else /* otherwise the channel has stopped */
|
else /* otherwise the channel has stopped */
|
||||||
sim_cancel (&sel_unit); /* so cancel the CHANSR timer */
|
sim_cancel (&sel_unit [0]); /* so cancel the CHANSR timer */
|
||||||
|
|
||||||
} /* end while */
|
} /* end while */
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,13 @@
|
||||||
in advertising or otherwise to promote the sale, use or other dealings in
|
in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
this Software without prior written authorization from the author.
|
this Software without prior written authorization from the author.
|
||||||
|
|
||||||
|
15-Sep-16 JDB Modified "one_time_init" to set aux_cmds "message" field
|
||||||
|
03-Sep-16 JDB Added the STOP_POWER and STOP_ARSINH messages
|
||||||
|
01-Sep-16 JDB Moved the hp_cold_cmd routine to the CPU (as cpu_cold_cmd)
|
||||||
|
Added the POWER command
|
||||||
|
03-Aug-16 JDB Improved "fmt_char" and "fmt_bitset" to allow multiple calls
|
||||||
|
15-Jul-16 JDB Fixed the word count display for SIO read/write orders
|
||||||
|
14-Jul-16 JDB Improved the cold dump invocation
|
||||||
21-Jun-16 JDB Changed fprint_instruction mask type from t_value to uint32
|
21-Jun-16 JDB Changed fprint_instruction mask type from t_value to uint32
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
16-May-16 JDB Prefix in fprint_instruction is now a pointer-to-constant
|
16-May-16 JDB Prefix in fprint_instruction is now a pointer-to-constant
|
||||||
|
@ -756,7 +763,6 @@ static t_bool fprint_stopped (FILE *st, t_stat reason);
|
||||||
static void fprint_addr (FILE *st, DEVICE *dptr, t_addr addr);
|
static void fprint_addr (FILE *st, DEVICE *dptr, t_addr addr);
|
||||||
static t_addr parse_addr (DEVICE *dptr, CONST char *cptr, CONST char **tptr);
|
static t_addr parse_addr (DEVICE *dptr, CONST char *cptr, CONST char **tptr);
|
||||||
|
|
||||||
static t_stat hp_cold_cmd (int32 arg, CONST char *buf);
|
|
||||||
static t_stat hp_exdep_cmd (int32 arg, CONST char *buf);
|
static t_stat hp_exdep_cmd (int32 arg, CONST char *buf);
|
||||||
static t_stat hp_run_cmd (int32 arg, CONST char *buf);
|
static t_stat hp_run_cmd (int32 arg, CONST char *buf);
|
||||||
static t_stat hp_brk_cmd (int32 arg, CONST char *buf);
|
static t_stat hp_brk_cmd (int32 arg, CONST char *buf);
|
||||||
|
@ -888,7 +894,9 @@ const char *sim_stop_messages [] = { /* an array of pointers to the s
|
||||||
"Breakpoint", /* STOP_BRKPNT */
|
"Breakpoint", /* STOP_BRKPNT */
|
||||||
"Infinite loop", /* STOP_INFLOOP */
|
"Infinite loop", /* STOP_INFLOOP */
|
||||||
"Cold load complete", /* STOP_CLOAD */
|
"Cold load complete", /* STOP_CLOAD */
|
||||||
"Cold dump complete" /* STOP_CDUMP */
|
"Cold dump complete", /* STOP_CDUMP */
|
||||||
|
"Auto-restart disabled", /* STOP_ARSINH */
|
||||||
|
"Power is off" /* STOP_POWER */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -936,12 +944,19 @@ static CTAB aux_cmds [] = {
|
||||||
{ "IEXAMINE", &hp_exdep_cmd, 0, NULL },
|
{ "IEXAMINE", &hp_exdep_cmd, 0, NULL },
|
||||||
{ "DEPOSIT", &hp_exdep_cmd, 0, NULL },
|
{ "DEPOSIT", &hp_exdep_cmd, 0, NULL },
|
||||||
{ "IDEPOSIT", &hp_exdep_cmd, 0, NULL },
|
{ "IDEPOSIT", &hp_exdep_cmd, 0, NULL },
|
||||||
|
|
||||||
{ "RUN", &hp_run_cmd, 0, NULL },
|
{ "RUN", &hp_run_cmd, 0, NULL },
|
||||||
{ "GO", &hp_run_cmd, 0, NULL },
|
{ "GO", &hp_run_cmd, 0, NULL },
|
||||||
|
|
||||||
{ "BREAK", &hp_brk_cmd, 0, NULL },
|
{ "BREAK", &hp_brk_cmd, 0, NULL },
|
||||||
{ "NOBREAK", &hp_brk_cmd, 0, NULL },
|
{ "NOBREAK", &hp_brk_cmd, 0, NULL },
|
||||||
{ "LOAD", &hp_cold_cmd, Cold_Load, "l{oad} {cntlword} cold load from a device\n" },
|
|
||||||
{ "DUMP", &hp_cold_cmd, Cold_Dump, "du{mp} {cntlword} cold dump to a device\n" },
|
{ "LOAD", &cpu_cold_cmd, Cold_Load, "l{oad} {cntlword} cold load from a device\n" },
|
||||||
|
{ "DUMP", &cpu_cold_cmd, Cold_Dump, "du{mp} {cntlword} cold dump to a device\n" },
|
||||||
|
|
||||||
|
{ "POWER", &cpu_power_cmd, 0, "p{ower} f{ail} fail the CPU power\n"
|
||||||
|
"p{ower} r{estore} restore the CPU power\n" },
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1675,8 +1690,26 @@ return formatted; /* return a pointer to t
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. The longest string to be returned is a five-character escaped octal
|
1. The longest string to be returned is a five-character escaped string
|
||||||
string, consisting of a backslash, three digits, and a trailing NUL.
|
consisting of a backslash, three octal digits, and a trailing NUL. The
|
||||||
|
end-of-buffer pointer has an allowance to ensure that the string will
|
||||||
|
fit.
|
||||||
|
|
||||||
|
2. The routine returns a pointer to a static buffer containing the printable
|
||||||
|
string. To allow the routine to be called more than once per trace line,
|
||||||
|
the null-terminated format strings are concatenated in the buffer, and
|
||||||
|
each call returns a pointer that is offset into the buffer to point at
|
||||||
|
the latest formatted string.
|
||||||
|
|
||||||
|
3. There is no explicit buffer-free action. Instead, newly formatted
|
||||||
|
strings are appended to the buffer until there is no more space
|
||||||
|
available. At that point, the pointers are reset to the start of the
|
||||||
|
buffer. In effect, this provides a circular buffer, as previously
|
||||||
|
formatted strings are overwritten by subsequent calls.
|
||||||
|
|
||||||
|
4. The buffer is sized to hold the maximum number of concurrent strings
|
||||||
|
needed for a single trace line. If more concurrent strings are used, one
|
||||||
|
or more strings from the earliest calls will be overwritten.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *fmt_char (uint32 charval)
|
const char *fmt_char (uint32 charval)
|
||||||
|
@ -1687,7 +1720,10 @@ static const char *const control [] = {
|
||||||
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
|
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
|
||||||
"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
|
"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
|
||||||
};
|
};
|
||||||
static char printable [5];
|
static char fmt_buffer [64]; /* the return buffer */
|
||||||
|
static char *freeptr = fmt_buffer; /* pointer to the first free character in the buffer */
|
||||||
|
static char *endptr = fmt_buffer + sizeof fmt_buffer - 5; /* pointer to the end of the buffer (less allowance) */
|
||||||
|
const char *fmtptr;
|
||||||
|
|
||||||
if (charval <= '\037') /* if the value is an ASCII control character */
|
if (charval <= '\037') /* if the value is an ASCII control character */
|
||||||
return control [charval]; /* then return a readable representation */
|
return control [charval]; /* then return a readable representation */
|
||||||
|
@ -1695,17 +1731,26 @@ if (charval <= '\037') /* if the value is an AS
|
||||||
else if (charval == '\177') /* otherwise if the value is the delete character */
|
else if (charval == '\177') /* otherwise if the value is the delete character */
|
||||||
return "DEL"; /* then return a readable representation */
|
return "DEL"; /* then return a readable representation */
|
||||||
|
|
||||||
else if (charval > '\177') { /* otherwise if the value is beyond the printable range */
|
else {
|
||||||
sprintf (printable, "\\%03o", charval & D8_MASK); /* then format the value */
|
if (freeptr > endptr) /* if there is not enough room left to append the string */
|
||||||
return printable; /* as an escaped octal code */
|
freeptr = fmt_buffer; /* then reset to point at the start of the buffer */
|
||||||
}
|
|
||||||
|
fmtptr = freeptr; /* initialize the return pointer */
|
||||||
|
*freeptr = '\0'; /* and the format accumulator */
|
||||||
|
|
||||||
|
if (charval > '\177') /* otherwise if the value is beyond the printable range */
|
||||||
|
freeptr = freeptr + sprintf (freeptr, "\\%03o", /* then format the value */
|
||||||
|
charval & D8_MASK); /* and update the free pointer */
|
||||||
|
|
||||||
else { /* otherwise it's a printable character */
|
else { /* otherwise it's a printable character */
|
||||||
printable [0] = '\''; /* so form a representation */
|
*freeptr++ = '\''; /* so form a representation */
|
||||||
printable [1] = (char) charval; /* containing the character */
|
*freeptr++ = (char) charval; /* containing the character */
|
||||||
printable [2] = '\''; /* surrounded by single quotes */
|
*freeptr++ = '\''; /* surrounded by single quotes */
|
||||||
printable [3] = '\0';
|
*freeptr = '\0';
|
||||||
return printable;
|
}
|
||||||
|
|
||||||
|
freeptr = freeptr + 1; /* advance past the NUL terminator */
|
||||||
|
return fmtptr; /* and return the formatted string */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1798,30 +1843,43 @@ else { /* otherwise it's a prin
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. The routine returns a pointer to a static buffer containing the printable
|
1. The routine returns a pointer to a static buffer containing the printable
|
||||||
string, so it cannot be called more than once per trace line, unless the
|
string. To allow the routine to be called more than once per trace line,
|
||||||
buffer contents are copied upon return. In particular, this type of
|
the null-terminated format strings are concatenated in the buffer, and
|
||||||
calling sequence:
|
each call returns a pointer that is offset into the buffer to point at
|
||||||
|
the latest formatted string.
|
||||||
|
|
||||||
dprintf (..., fmt_bitset (...), ..., fmt_bitset (...), ...);
|
2. There is no explicit buffer-free action. Instead, newly formatted
|
||||||
|
strings are appended to the buffer until there is no more space
|
||||||
|
available. At that point, the string currently being assembled is moved
|
||||||
|
to the start of the buffer, and the pointers are reset. In effect, this
|
||||||
|
provides a circular buffer, as previously formatted strings are
|
||||||
|
overwritten by subsequent calls.
|
||||||
|
|
||||||
...will fail, as the buffer will be overwritten by the second call before
|
3. The buffer is sized to hold the maximum number of concurrent strings
|
||||||
the result of the first call is printed.
|
needed for a single trace line. If more concurrent strings are used, one
|
||||||
|
or more strings from the earliest calls will be overwritten. If an
|
||||||
|
attempt is made to format a string larger than the buffer, an error
|
||||||
|
indication string is returned.
|
||||||
|
|
||||||
|
4. The location of the end of the buffer used to determine if the next name
|
||||||
|
will fit includes an allowance for two separators that might be placed on
|
||||||
|
either side of the name and a terminating NUL character.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt)
|
const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt)
|
||||||
{
|
{
|
||||||
static char formatted_set [1024]; /* the return buffer */
|
static const char separator [] = " | "; /* the separator to use between names */
|
||||||
|
static char fmt_buffer [1024]; /* the return buffer */
|
||||||
const char *bnptr;
|
static char *freeptr = fmt_buffer; /* pointer to the first free character in the buffer */
|
||||||
|
static char *endptr = fmt_buffer + sizeof fmt_buffer /* pointer to the end of the buffer */
|
||||||
|
- 2 * (sizeof separator - 1) - 1; /* less allowance for two separators and a terminator */
|
||||||
|
const char *bnptr, *fmtptr;
|
||||||
uint32 test_bit, index, bitmask;
|
uint32 test_bit, index, bitmask;
|
||||||
char *fsptr = formatted_set;
|
size_t name_length;
|
||||||
|
|
||||||
*fsptr = '\0'; /* initialize the format accumulator */
|
if (bitfmt.name_count < D32_WIDTH) /* if the name count is the less than the mask width */
|
||||||
index = 0; /* and the name index */
|
bitmask = (1 << bitfmt.name_count) - 1; /* then create a mask for the name count specified */
|
||||||
|
|
||||||
if (bitfmt.name_count < D32_WIDTH) /* if the bit count is the less than the mask variable width */
|
|
||||||
bitmask = (1 << bitfmt.name_count) - 1; /* then create a mask for the bit count specified */
|
|
||||||
else /* otherwise use a predefined value for the mask */
|
else /* otherwise use a predefined value for the mask */
|
||||||
bitmask = D32_MASK; /* to prevent shifting the bit off the MSB end */
|
bitmask = D32_MASK; /* to prevent shifting the bit off the MSB end */
|
||||||
|
|
||||||
|
@ -1834,7 +1892,12 @@ else /* otherwise */
|
||||||
test_bit = 1 << bitfmt.offset; /* create a test bit for the LSB */
|
test_bit = 1 << bitfmt.offset; /* create a test bit for the LSB */
|
||||||
|
|
||||||
|
|
||||||
while ((bitfmt.alternate || bitset) && index < bitfmt.name_count) { /* while more bits and more names exist */
|
fmtptr = freeptr; /* initialize the return pointer */
|
||||||
|
*freeptr = '\0'; /* and the format accumulator */
|
||||||
|
index = 0; /* and the name index */
|
||||||
|
|
||||||
|
while ((bitfmt.alternate || bitset) /* while more bits */
|
||||||
|
&& index < bitfmt.name_count) { /* and more names exist */
|
||||||
bnptr = bitfmt.names [index]; /* point at the name for the current bit */
|
bnptr = bitfmt.names [index]; /* point at the name for the current bit */
|
||||||
|
|
||||||
if (bnptr) /* if the name is defined */
|
if (bnptr) /* if the name is defined */
|
||||||
|
@ -1849,10 +1912,25 @@ while ((bitfmt.alternate || bitset) && index < bitfmt.name_count) { /* while mor
|
||||||
bnptr = NULL; /* then clear the name pointer */
|
bnptr = NULL; /* then clear the name pointer */
|
||||||
|
|
||||||
if (bnptr) { /* if the name pointer is set */
|
if (bnptr) { /* if the name pointer is set */
|
||||||
if (formatted_set [0] != '\0') /* then if it is not the first one added */
|
name_length = strlen (bnptr); /* then get the length needed */
|
||||||
fsptr = strcat (fsptr, " | "); /* then add a separator to the string */
|
|
||||||
|
|
||||||
strcat (fsptr, bnptr); /* append the bit's mnemonic to the accumulator */
|
if (freeptr + name_length > endptr) { /* if there is not enough room left to append the name */
|
||||||
|
strcpy (fmt_buffer, fmtptr); /* then move the partial string to the start of the buffer */
|
||||||
|
|
||||||
|
freeptr = fmt_buffer + (freeptr - fmtptr); /* point at the new first free character location */
|
||||||
|
fmtptr = fmt_buffer; /* and reset the return pointer */
|
||||||
|
|
||||||
|
if (freeptr + name_length > endptr) /* if there is still not enough room left to append */
|
||||||
|
return "(buffer overflow)"; /* then this call is requires a larger buffer! */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*fmtptr != '\0') { /* if this is not the first name added */
|
||||||
|
strcpy (freeptr, separator); /* then add a separator to the string */
|
||||||
|
freeptr = freeptr + strlen (separator); /* and move the free pointer */
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (freeptr, bnptr); /* append the bit's mnemonic to the accumulator */
|
||||||
|
freeptr = freeptr + name_length; /* and move the free pointer */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitfmt.direction == msb_first) /* if formatting is left-to-right */
|
if (bitfmt.direction == msb_first) /* if formatting is left-to-right */
|
||||||
|
@ -1864,16 +1942,21 @@ while ((bitfmt.alternate || bitset) && index < bitfmt.name_count) { /* while mor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (formatted_set [0] == '\0') /* if the set is empty */
|
if (*fmtptr == '\0') /* if no names were output */
|
||||||
if (bitfmt.bar == append_bar) /* then if concatenating with more information */
|
if (bitfmt.bar == append_bar) /* then if concatenating with more information */
|
||||||
return ""; /* then return an empty string */
|
return ""; /* then return an empty string */
|
||||||
else /* otherwise it's a standalone format */
|
else /* otherwise it's a standalone format */
|
||||||
return "(none)"; /* so return a placeholder */
|
return "(none)"; /* so return a placeholder */
|
||||||
|
|
||||||
else if (bitfmt.bar == append_bar) /* otherwise if a trailing separator is specified */
|
else if (bitfmt.bar == append_bar) { /* otherwise if a trailing separator is specified */
|
||||||
fsptr = strcat (fsptr, " | "); /* then add it to the string */
|
strcpy (freeptr, separator); /* then add a separator to the string */
|
||||||
|
freeptr = freeptr + strlen (separator) + 1; /* and account for it plus the trailing NUL */
|
||||||
|
}
|
||||||
|
|
||||||
return formatted_set; /* return a pointer to the accumulator */
|
else /* otherwise */
|
||||||
|
freeptr = freeptr + 1; /* just account for the trailing NUL */
|
||||||
|
|
||||||
|
return fmtptr; /* return a pointer to the formatted string */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1911,8 +1994,8 @@ return formatted_set; /* return a pointer to t
|
||||||
call parameters.
|
call parameters.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FLAG_SIZE 50 /* sufficiently large to accommodate all flag names */
|
#define FLAG_SIZE 32 /* sufficiently large to accommodate all flag names */
|
||||||
#define FORMAT_SIZE 1000 /* sufficiently large to accommodate all format strings */
|
#define FORMAT_SIZE 1024 /* sufficiently large to accommodate all format strings */
|
||||||
|
|
||||||
void hp_debug (DEVICE *dptr, uint32 flag, ...)
|
void hp_debug (DEVICE *dptr, uint32 flag, ...)
|
||||||
{
|
{
|
||||||
|
@ -1973,7 +2056,9 @@ return;
|
||||||
|
|
||||||
static void one_time_init (void)
|
static void one_time_init (void)
|
||||||
{
|
{
|
||||||
CTAB *systab, *auxtab = aux_cmds;
|
CTAB *contab, *systab, *auxtab = aux_cmds;
|
||||||
|
|
||||||
|
contab = find_cmd ("CONT"); /* find the entry for the CONTINUE command */
|
||||||
|
|
||||||
while (auxtab->name != NULL) { /* loop through the auxiliary command table */
|
while (auxtab->name != NULL) { /* loop through the auxiliary command table */
|
||||||
systab = find_cmd (auxtab->name); /* find the corresponding system command table entry */
|
systab = find_cmd (auxtab->name); /* find the corresponding system command table entry */
|
||||||
|
@ -1992,6 +2077,10 @@ while (auxtab->name != NULL) { /* loop through the auxi
|
||||||
auxtab->message = systab->message; /* as we never override them */
|
auxtab->message = systab->message; /* as we never override them */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auxtab->action == &cpu_cold_cmd /* if this is the LOAD or DUMP command entry */
|
||||||
|
|| auxtab->action == &cpu_power_cmd) /* or the POWER command entry */
|
||||||
|
auxtab->message = contab->message; /* then set the execution completion message routine */
|
||||||
|
|
||||||
auxtab++; /* point at the next table entry */
|
auxtab++; /* point at the next table entry */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2061,7 +2150,8 @@ else if (reason == STOP_CDUMP) { /* otherwise if this is
|
||||||
fprint_val (st, CIR, cpu_dev.dradix, /* and the numeric value */
|
fprint_val (st, CIR, cpu_dev.dradix, /* and the numeric value */
|
||||||
cpu_dev.dwidth, PV_RZRO);
|
cpu_dev.dwidth, PV_RZRO);
|
||||||
|
|
||||||
return FALSE; /* return FALSE to omit the program counter */
|
fputc ('\n', st); /* append an end-of-line character */
|
||||||
|
return FALSE; /* and return FALSE to omit the program counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (reason == STOP_SYSHALT) { /* otherwise if this is a system halt stop */
|
else if (reason == STOP_SYSHALT) { /* otherwise if this is a system halt stop */
|
||||||
|
@ -2197,62 +2287,6 @@ return address; /* return the linear add
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Execute the LOAD and DUMP commands.
|
|
||||||
|
|
||||||
This routine implements the cold load and cold dump commands. The syntax is:
|
|
||||||
|
|
||||||
LOAD { <control/devno> }
|
|
||||||
DUMP { <control/devno> }
|
|
||||||
|
|
||||||
The <control/devno> is a number that is deposited into the SWCH register
|
|
||||||
before invoking the CPU cold load or cold dump facility. The CPU radix is
|
|
||||||
used to interpret the number; it defaults to octal. If the number is
|
|
||||||
omitted, the SWCH register value is not altered before loading or dumping.
|
|
||||||
|
|
||||||
On entry, the "arg" parameter is "Cold_Load" for a LOAD command and
|
|
||||||
"Cold_Dump" for a DUMP command, and "buf" points at the remainder of the
|
|
||||||
command line. If characters exist on the command line, they are parsed,
|
|
||||||
converted to a numeric value, and stored in the SWCH register. Then the
|
|
||||||
CPU's cold load/dump routine is called to set up the CPU state. Finally, the
|
|
||||||
CPU is started to begin the requested action.
|
|
||||||
|
|
||||||
|
|
||||||
Implementation notes:
|
|
||||||
|
|
||||||
1. The run command invocation prepares the simulator for execution, which
|
|
||||||
includes a CPU and I/O reset. However, the cpu_reset routine does not
|
|
||||||
reset the CPU state if the cold dump switch is set. This allows the
|
|
||||||
value of the CPX2 register to be saved as part of the dump.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static t_stat hp_cold_cmd (int32 arg, CONST char *buf)
|
|
||||||
{
|
|
||||||
const char *cptr;
|
|
||||||
char gbuf [CBUFSIZE];
|
|
||||||
t_stat status;
|
|
||||||
HP_WORD value;
|
|
||||||
|
|
||||||
if (*buf != '\0') { /* if more characters exist on the command line */
|
|
||||||
cptr = get_glyph (buf, gbuf, 0); /* then get the next glyph */
|
|
||||||
|
|
||||||
if (*cptr != '\0') /* if that does not exhaust the input */
|
|
||||||
return SCPE_2MARG; /* then report that there are too many arguments */
|
|
||||||
|
|
||||||
value = (HP_WORD) get_uint (gbuf, cpu_dev.dradix, /* get the parameter value */
|
|
||||||
D16_UMAX, &status);
|
|
||||||
|
|
||||||
if (status == SCPE_OK) /* if a valid number was present */
|
|
||||||
SWCH = value; /* then set it into the switch register */
|
|
||||||
else /* otherwise */
|
|
||||||
return status; /* return the error status */
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_front_panel (SWCH, (PANEL_TYPE) arg); /* set up the cold load or dump microcode */
|
|
||||||
|
|
||||||
return run_cmd (RU_RUN, ""); /* reset and execute the halt-mode routine */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Execute the EXAMINE, DEPOSIT, IEXAMINE, and IDEPOSIT commands.
|
/* Execute the EXAMINE, DEPOSIT, IEXAMINE, and IDEPOSIT commands.
|
||||||
|
|
||||||
These commands are intercepted to configure address parsing. The following
|
These commands are intercepted to configure address parsing. The following
|
||||||
|
@ -2438,8 +2472,8 @@ return;
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. The Return Residue value is printed as a positive number, even though
|
1. The Return Residue and Read/Write count values are printed as positive
|
||||||
the value in memory is either negative or zero.
|
numbers, even though the values in memory are negative.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const char *const order_names [] = { /* indexed by SIO_ORDER */
|
static const char *const order_names [] = { /* indexed by SIO_ORDER */
|
||||||
|
@ -2479,7 +2513,7 @@ switch (order) { /* dispatch operand prin
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case sioRTRES: /* print the residue count */
|
case sioRTRES: /* print the residue count */
|
||||||
fprint_value (ofile, - SEXT (ioaw),
|
fprint_value (ofile, NEG16 (ioaw),
|
||||||
(radix ? radix : 10),
|
(radix ? radix : 10),
|
||||||
DV_WIDTH, PV_LEFT);
|
DV_WIDTH, PV_LEFT);
|
||||||
break;
|
break;
|
||||||
|
@ -2516,7 +2550,7 @@ switch (order) { /* dispatch operand prin
|
||||||
case sioWRITEC:
|
case sioWRITEC:
|
||||||
case sioREAD:
|
case sioREAD:
|
||||||
case sioREADC: /* print the count and address */
|
case sioREADC: /* print the count and address */
|
||||||
fprint_value (ofile, - IOCW_COUNT (iocw),
|
fprint_value (ofile, NEG16 (IOCW_COUNT (iocw)),
|
||||||
(radix ? radix : 10), DV_WIDTH, PV_LEFT);
|
(radix ? radix : 10), DV_WIDTH, PV_LEFT);
|
||||||
|
|
||||||
fputc (',', ofile);
|
fputc (',', ofile);
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from the authors.
|
in this Software without prior written authorization from the authors.
|
||||||
|
|
||||||
|
03-Aug-16 JDB "fmt_bitset" now allows multiple concurrent calls
|
||||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||||
16-May-16 JDB DRIVE_PROPS.name is now a pointer-to-constant
|
16-May-16 JDB DRIVE_PROPS.name is now a pointer-to-constant
|
||||||
|
@ -1540,7 +1541,6 @@ uint32 unit;
|
||||||
int32 seek_wait_time;
|
int32 seek_wait_time;
|
||||||
PRPTR props;
|
PRPTR props;
|
||||||
CNTLR_IFN_IBUS outbound;
|
CNTLR_IFN_IBUS outbound;
|
||||||
char s1_buffer [256], s2_buffer [256]; /* formatted bitset buffers for trace logging */
|
|
||||||
DIAG_ENTRY *dop = NULL;
|
DIAG_ENTRY *dop = NULL;
|
||||||
|
|
||||||
wait_timer (cvptr, CLEAR); /* stop the command wait timer */
|
wait_timer (cvptr, CLEAR); /* stop the command wait timer */
|
||||||
|
@ -1694,11 +1694,11 @@ else { /* otherwise the command
|
||||||
|
|
||||||
dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns %sunit %u | %s and %s%s | %s\n",
|
dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns %sunit %u | %s and %s%s | %s\n",
|
||||||
unit, opcode_name [Request_Status],
|
unit, opcode_name [Request_Status],
|
||||||
strcpy (s1_buffer, fmt_bitset (cvptr->spd_unit, status_1_format)),
|
fmt_bitset (cvptr->spd_unit, status_1_format),
|
||||||
CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status),
|
CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status),
|
||||||
(cvptr->buffer [1] & S2_ERROR ? "error | " : ""),
|
(cvptr->buffer [1] & S2_ERROR ? "error | " : ""),
|
||||||
drive_props [S2_TO_DRIVE_TYPE (cvptr->buffer [1])].name,
|
drive_props [S2_TO_DRIVE_TYPE (cvptr->buffer [1])].name,
|
||||||
strcpy (s2_buffer, fmt_bitset (cvptr->buffer [1], status_2_format)));
|
fmt_bitset (cvptr->buffer [1], status_2_format));
|
||||||
|
|
||||||
if (rptr) /* if the referenced unit is valid */
|
if (rptr) /* if the referenced unit is valid */
|
||||||
rptr->STATUS &= ~S2_FIRST_STATUS; /* then clear the First Status bit */
|
rptr->STATUS &= ~S2_FIRST_STATUS; /* then clear the First Status bit */
|
||||||
|
|
Binary file not shown.
Loading…
Add table
Reference in a new issue