HP3000: Third HP 3000 release from Dave Bryan

This commit is contained in:
Mark Pizzolato 2016-09-20 20:34:22 -07:00
parent 9925ba83b8
commit e370b9e78e
20 changed files with 1632 additions and 519 deletions

View file

@ -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
@ -879,23 +882,23 @@ static DIB atcc_dib = {
*/ */
static UNIT atcd_unit [UNIT_COUNT] = { static UNIT atcd_unit [UNIT_COUNT] = {
{ UDATA (&line_service, TT_MODE_7P | UNIT_LOCALACK | UNIT_CAPSLOCK, 0) }, { UDATA (&line_service, TT_MODE_7P | UNIT_LOCALACK | UNIT_CAPSLOCK, 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 (&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 (&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 (&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 (&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 (&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)
@ -1825,13 +1832,14 @@ static t_stat atcd_detach (UNIT *uptr)
uint32 channel; uint32 channel;
t_stat status = SCPE_OK; 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 */
atcd_ldsc [channel].rcve = FALSE; /* disable reception */ for (channel = 0; channel < TERM_COUNT; channel++) { /* then for each terminal channel */
sim_cancel (&line_unit [channel]); /* and cancel any transfer in progress */ atcd_ldsc [channel].rcve = FALSE; /* disable reception */
} sim_cancel (&line_unit [channel]); /* and cancel any transfer in progress */
}
} }
return status; return status;

View file

@ -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,28 +394,32 @@ 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) },
{ ORDATA (LIMIT, limit_register, 16) }, { ORDATA (LIMIT, limit_register, 16) },
{ ORDATA (RATE, rate, 3) }, { ORDATA (RATE, rate, 3) },
{ 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 (INCR, increment, 16), REG_HRO }, { DRDATA (SCALE, prescaler, 16), REG_HRO },
{ FLDATA (COSOK, coschedulable, 0), REG_HRO }, { DRDATA (INCR, increment, 16), REG_HRO },
{ FLDATA (COSCH, coscheduled, 0), REG_HRO }, { FLDATA (COSOK, coschedulable, 0), REG_HRO },
{ SRDATA (DIB, clk_dib, REG_HRO) }, { FLDATA (COSCH, coscheduled, 0), 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,11 +500,11 @@ 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 */
increment = increment - ticks; /* and reduce the amount remaining to add at service */ increment = increment - ticks; /* and reduce the amount remaining to add at service */
@ -568,17 +574,17 @@ 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

View file

@ -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 */
@ -966,11 +1065,12 @@ 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 EXEC_STATE cpu_micro_state; /* micromachine execution state */ extern POWER_STATE cpu_power_state; /* power supply state */
extern uint32 cpu_stop_flags; /* set of simulation stop flags */ extern EXEC_STATE cpu_micro_state; /* micromachine execution state */
extern t_bool cpu_base_changed; /* TRUE if any base register has been changed */ extern uint32 cpu_stop_flags; /* set of simulation stop flags */
extern UNIT cpu_unit; /* CPU unit structure (needed for memory size) */ extern t_bool cpu_base_changed; /* TRUE if any base register has been changed */
extern UNIT cpu_unit []; /* CPU unit array (needed for memory size) */
/* Condition Code B mapping table */ /* Condition Code B mapping table */

View file

@ -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 */

View file

@ -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
*/ */

View file

@ -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 */
@ -585,7 +588,7 @@ typedef enum { /* trailing separator */
append_bar /* append a trailing separator */ append_bar /* append a trailing separator */
} BITSET_BAR; } BITSET_BAR;
typedef const char *const BITSET_NAME; /* a bit name string pointer */ typedef const char *const BITSET_NAME; /* a bit name string pointer */
typedef struct { /* bit set format descriptor */ typedef struct { /* bit set format descriptor */
uint32 name_count; /* count of bit names */ uint32 name_count; /* count of bit names */

View file

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

View file

@ -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,9 +440,10 @@ 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) },
DL_REGS (mac_cntlr, ds_unit, UNIT_COUNT, buffer, fast_times), DIB_REGS (ds_dib),
DL_REGS (mac_cntlr, ds_unit, UNIT_COUNT, buffer, fast_times),
{ NULL } { NULL }
}; };

View file

@ -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 */

View file

@ -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
@ -120,7 +122,7 @@
memory. memory.
Direct I/O instructions are sent via the IOP Bus to all device interfaces. Direct I/O instructions are sent via the IOP Bus to all device interfaces.
When executing I/O instruc tions, the CPU microcode writes a 16-bit command When executing I/O instructions, the CPU microcode writes a 16-bit command
word to the IOP, which then places bits 5-7 of that word onto the IOP Bus as word to the IOP, which then places bits 5-7 of that word onto the IOP Bus as
IOCMD0-2 as follows: IOCMD0-2 as follows:
@ -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

View file

@ -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
@ -1148,61 +1147,62 @@ 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) },
{ FLDATA (INXFR, input_xfer, 0) }, { FLDATA (INXFR, input_xfer, 0) },
{ FLDATA (OUTXFR, output_xfer, 0) }, { FLDATA (OUTXFR, output_xfer, 0) },
{ FLDATA (RDXFR, read_xfer, 0) }, { FLDATA (RDXFR, read_xfer, 0) },
{ FLDATA (WRXFR, write_xfer, 0) }, { FLDATA (WRXFR, write_xfer, 0) },
{ FLDATA (INTMSK, interrupt_mask, 0) }, { FLDATA (INTMSK, interrupt_mask, 0) },
{ FLDATA (DEVCMD, device_command, 0) }, { FLDATA (DEVCMD, device_command, 0) },
{ FLDATA (DEVFLG, device_flag, 0) }, { FLDATA (DEVFLG, device_flag, 0) },
{ FLDATA (DEVEND, device_end, 0) }, { FLDATA (DEVEND, device_end, 0) },
{ DRDATA (SEQSTA, sequencer, 8), PV_LEFT }, { DRDATA (SEQSTA, sequencer, 8), PV_LEFT },
{ ORDATA (CNTL, control_word, 16), PV_RZRO }, { ORDATA (CNTL, control_word, 16), PV_RZRO },
{ ORDATA (ISTAT, int_status_word, 16), PV_RZRO }, { ORDATA (ISTAT, int_status_word, 16), PV_RZRO },
{ ORDATA (DSTAT, dev_status_word, 16), PV_RZRO }, { ORDATA (DSTAT, dev_status_word, 16), PV_RZRO },
{ ORDATA (READ, read_word, 16), PV_RZRO | REG_A }, { ORDATA (READ, read_word, 16), PV_RZRO | REG_A },
{ ORDATA (WRITE, write_word, 16), PV_RZRO | REG_A }, { ORDATA (WRITE, write_word, 16), PV_RZRO | REG_A },
{ YRDATA (J2WX, jumper_set, 10, PV_RZRO) }, { YRDATA (J2WX, jumper_set, 10, PV_RZRO) },
{ ORDATA (DATOUT, data_out, 16), PV_RZRO | REG_A }, { ORDATA (DATOUT, data_out, 16), PV_RZRO | REG_A },
{ ORDATA (DATIN, data_in, 16), PV_RZRO | REG_A }, { ORDATA (DATIN, data_in, 16), PV_RZRO | REG_A },
{ FLDATA (DCOUT, device_command_out, 0) }, { FLDATA (DCOUT, device_command_out, 0) },
{ 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 },
{ GRDATA (CNLED, control_word, 2, 5, 5), PV_RZRO },
{ FLDATA (PFWARN, power_warning, 0) },
{ ORDATA (DIAGCN, dha_control_word, 16), PV_RZRO }, { FLDATA (PFAULT, paper_fault, 0) },
{ GRDATA (CNLED, control_word, 2, 5, 5), PV_RZRO }, { FLDATA (TFAULT, tape_fault, 0) },
{ FLDATA (OLPEND, offline_pending, 0) },
{ DRDATA (PRLINE, current_line, 8), PV_LEFT },
{ DRDATA (BUFIDX, buffer_index, 8), PV_LEFT },
{ BRDATA (PRTBUF, buffer, 8, 8, BUFFER_SIZE), PV_RZRO | REG_A },
{ ORDATA (OVPCHR, overprint_char, 8), PV_RZRO | REG_A },
{ FLDATA (PFAULT, paper_fault, 0) }, { DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO },
{ FLDATA (TFAULT, tape_fault, 0) }, { BRDATA (TITLE, vfu_title, 8, 8, LINE_SIZE), REG_HRO },
{ FLDATA (OLPEND, offline_pending, 0) }, { 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 (PRLINE, current_line, 8), PV_LEFT }, { DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ },
{ DRDATA (BUFIDX, buffer_index, 8), PV_LEFT }, { DRDATA (PTIME, fast_times.print, 24), PV_LEFT | REG_NZ },
{ BRDATA (PRTBUF, buffer, 8, 8, BUFFER_SIZE), PV_RZRO | REG_A }, { DRDATA (STIME, fast_times.advance, 24), PV_LEFT | REG_NZ },
{ ORDATA (OVPCHR, overprint_char, 8), PV_RZRO | REG_A }, { DRDATA (POS, lp_unit [0].pos, T_ADDR_W), PV_LEFT },
{ DRDATA (UWAIT, lp_unit [0].wait, 32), PV_LEFT | REG_HRO },
{ DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO },
{ 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 },
{ DRDATA (BTIME, fast_times.buffer_load, 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 (POS, lp_unit [0].pos, T_ADDR_W), PV_LEFT },
{ NULL } { NULL }
}; };
@ -1231,20 +1231,21 @@ static MTAB lp_mod [] = {
{ UNIT_EXPAND, UNIT_EXPAND, "expanded output", "EXPAND", NULL, NULL, NULL }, { UNIT_EXPAND, UNIT_EXPAND, "expanded output", "EXPAND", NULL, NULL, NULL },
{ 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 },
{ MTAB_XDV, Diagnostic, NULL, "DIAGNOSTIC", &lp_set_mode, NULL, NULL }, { MTAB_XDV, Diagnostic, NULL, "DIAGNOSTIC", &lp_set_mode, NULL, NULL },
{ MTAB_XDV, 0, "MODES", NULL, NULL, &lp_show_mode, NULL }, { MTAB_XDV, 0, "MODES", NULL, NULL, &lp_show_mode, NULL },
{ MTAB_XDV, VAL_DEVNO, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib }, { MTAB_XDV, VAL_DEVNO, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
{ MTAB_XDV, VAL_INTMASK, "INTMASK", "INTMASK", &hp_set_dib, &hp_show_dib, (void *) &lp_dib }, { MTAB_XDV, VAL_INTMASK, "INTMASK", "INTMASK", &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_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_NC, 0, "VFU", "VFU", &lp_set_vfu, &lp_show_vfu, NULL }, { 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 },
{ 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 */
} }

View file

@ -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 */

View file

@ -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,9 +518,10 @@ 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) },
TL_REGS (ms_cntlr, ms_unit, DRIVE_COUNT, buffer, fast_times), DIB_REGS (ms_dib),
TL_REGS (ms_cntlr, ms_unit, DRIVE_COUNT, buffer, fast_times),
{ NULL } { NULL }
}; };

View file

@ -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
===================== =====================

View file

@ -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 }
}; };

View file

@ -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,8 +964,8 @@ 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;
case sioWRITE: case sioWRITE:
@ -972,8 +973,8 @@ 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;
case sioREAD: case sioREAD:
@ -987,8 +988,8 @@ 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 */
@ -1071,9 +1072,9 @@ while (sel_request && cycles > 0) { /* execute as long as a
prefetch_address = FALSE; /* mark the job done */ prefetch_address = FALSE; /* mark the job done */
} }
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 */
} }
else { /* otherwise it's a Write or Read (Chained) order */ else { /* otherwise it's a Write or Read (Chained) order */
@ -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 */

View file

@ -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 */
}
else { /* otherwise it's a printable character */ fmtptr = freeptr; /* initialize the return pointer */
printable [0] = '\''; /* so form a representation */ *freeptr = '\0'; /* and the format accumulator */
printable [1] = (char) charval; /* containing the character */
printable [2] = '\''; /* surrounded by single quotes */ if (charval > '\177') /* otherwise if the value is beyond the printable range */
printable [3] = '\0'; freeptr = freeptr + sprintf (freeptr, "\\%03o", /* then format the value */
return printable; charval & D8_MASK); /* and update the free pointer */
else { /* otherwise it's a printable character */
*freeptr++ = '\''; /* so form a representation */
*freeptr++ = (char) charval; /* containing the character */
*freeptr++ = '\''; /* surrounded by single quotes */
*freeptr = '\0';
}
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,8 +1892,13 @@ 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 */
bnptr = bitfmt.names [index]; /* point at the name for the current bit */ *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 */
if (bnptr) /* if the name is defined */ if (bnptr) /* if the name is defined */
if (*bnptr == '\1') /* then if this name has an alternate */ if (*bnptr == '\1') /* then if this name has an alternate */
@ -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);

View file

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