HP3000: Third HP 3000 release from Dave Bryan
This commit is contained in:
parent
9925ba83b8
commit
e370b9e78e
20 changed files with 1632 additions and 519 deletions
|
@ -26,6 +26,9 @@
|
|||
|
||||
ATCD,ATCC HP 30032B Asynchronous Terminal Controller
|
||||
|
||||
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
|
||||
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
|
||||
16-May-16 JDB Fixed interrupt mask setting
|
||||
|
@ -895,7 +898,7 @@ static UNIT atcd_unit [UNIT_COUNT] = {
|
|||
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
||||
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
||||
{ UDATA (&line_service, TT_MODE_7B | UNIT_LOCALACK, 0) },
|
||||
{ UDATA (&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 */
|
||||
|
@ -935,7 +938,8 @@ static REG atcd_reg [] = {
|
|||
{ BRDATA (SPARM, send_param, 8, 16, SEND_CHAN_COUNT) },
|
||||
{ BRDATA (SBUFR, send_buffer, 8, 16, SEND_CHAN_COUNT), REG_A },
|
||||
{ FLDATA (POLL, atc_is_polling, 0), REG_HRO },
|
||||
{ SRDATA (DIB, atcd_dib, REG_HRO) },
|
||||
|
||||
DIB_REGS (atcd_dib),
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -959,7 +963,7 @@ static REG atcc_reg [] = {
|
|||
{ FBDATA (MS2, cntl_param, 1, TERM_COUNT, PV_RZRO) },
|
||||
{ FBDATA (MS1, cntl_param, 0, TERM_COUNT, PV_RZRO) },
|
||||
|
||||
{ SRDATA (DIB, atcc_dib, REG_HRO) },
|
||||
DIB_REGS (atcc_dib),
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -1810,14 +1814,17 @@ return status;
|
|||
|
||||
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
|
||||
two cases.
|
||||
three cases.
|
||||
|
||||
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
|
||||
(detach_all in scp.c calls the detach routines of all units that do NOT have
|
||||
UNIT_ATTABLE), as well as for unit 16 if it is attached. In both cases, it
|
||||
is imperative that we return SCPE_OK; otherwise any remaining device detaches
|
||||
will not be performed.
|
||||
attached. A RESTORE command also will call us for unit 16 if it is attached.
|
||||
In the latter case, the terminal channels will have already been rescheduled
|
||||
as appropriate, so canceling them is skipped. Also, during simulator
|
||||
shutdown, we will be called for units 0-15 (detach_all in scp.c calls the
|
||||
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)
|
||||
|
@ -1828,7 +1835,8 @@ t_stat status = SCPE_OK;
|
|||
if (uptr == line_unit || uptr == &poll_unit) { /* if we're detaching the base unit or poll unit */
|
||||
status = tmxr_detach (&atcd_mdsc, &poll_unit); /* then detach the listening port */
|
||||
|
||||
for (channel = 0; channel < TERM_COUNT; channel++) { /* for each terminal channel */
|
||||
if ((sim_switches & SIM_SW_REST) == 0) /* if this is not a RESTORE call */
|
||||
for (channel = 0; channel < TERM_COUNT; channel++) { /* then for each terminal channel */
|
||||
atcd_ldsc [channel].rcve = FALSE; /* disable reception */
|
||||
sim_cancel (&line_unit [channel]); /* and cancel any transfer in progress */
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
@ -392,15 +394,15 @@ static DIB clk_dib = {
|
|||
|
||||
/* Unit list */
|
||||
|
||||
static UNIT clk_unit = {
|
||||
UDATA (&clk_service, UNIT_IDLE | UNIT_CALTIME, 0), mS (1)
|
||||
static UNIT clk_unit [] = {
|
||||
{ UDATA (&clk_service, UNIT_IDLE | UNIT_CALTIME, 0) }
|
||||
};
|
||||
|
||||
/* Register list */
|
||||
|
||||
static REG clk_reg [] = {
|
||||
/* Macro Name Location Width Offset Flags */
|
||||
/* ------ ------ --------------- ----- ------ ------- */
|
||||
/* ------ ------ ----------------- ----- ------ ------------------ */
|
||||
{ ORDATA (CNTL, control_word, 16) },
|
||||
{ ORDATA (STAT, status_word, 16) },
|
||||
{ ORDATA (COUNT, count_register, 16) },
|
||||
|
@ -409,11 +411,15 @@ static REG clk_reg [] = {
|
|||
{ FLDATA (SYSIRQ, system_irq, 0) },
|
||||
{ FLDATA (LIMIRQ, limit_irq, 0) },
|
||||
{ FLDATA (OVFIRQ, lost_tick_irq, 0) },
|
||||
|
||||
{ DRDATA (SCALE, prescaler, 16), REG_HRO },
|
||||
{ DRDATA (INCR, increment, 16), REG_HRO },
|
||||
{ FLDATA (COSOK, coschedulable, 0), REG_HRO },
|
||||
{ FLDATA (COSCH, coscheduled, 0), REG_HRO },
|
||||
{ SRDATA (DIB, clk_dib, REG_HRO) },
|
||||
{ DRDATA (UWAIT, clk_unit [0].wait, 32), PV_LEFT | REG_HRO },
|
||||
|
||||
DIB_REGS (clk_dib),
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -445,7 +451,7 @@ static DEBTAB clk_deb [] = {
|
|||
|
||||
DEVICE clk_dev = {
|
||||
"CLK", /* device name */
|
||||
&clk_unit, /* unit array */
|
||||
clk_unit, /* unit array */
|
||||
clk_reg, /* register array */
|
||||
clk_mod, /* modifier array */
|
||||
1, /* number of units */
|
||||
|
@ -494,10 +500,10 @@ void clk_update_counter (void)
|
|||
int32 elapsed, ticks;
|
||||
|
||||
if (coscheduled) { /* if the clock is coscheduled, then adjust the count */
|
||||
elapsed = clk_unit.wait /* the elapsed time is the original wait time */
|
||||
- sim_activate_time (&clk_unit); /* less the time remaining before the next service */
|
||||
elapsed = clk_unit [0].wait /* the elapsed time is the original wait time */
|
||||
- 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 */
|
||||
|
||||
count_register = count_register + ticks & R_MASK; /* update the clock counter with rollover */
|
||||
|
@ -568,16 +574,16 @@ while (working_set) {
|
|||
if (control_word & CN_RESET_LOAD_SEL) { /* if the reset/load selector is set */
|
||||
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 */
|
||||
else /* otherwise */
|
||||
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 */
|
||||
clk_unit.wait = delay [rate]; /* then set the initial service delay */
|
||||
sim_rtcn_init (clk_unit.wait, TMR_CLK); /* initialize the clock */
|
||||
clk_unit [0].wait = delay [rate]; /* then set the initial service delay */
|
||||
sim_rtcn_init (clk_unit [0].wait, TMR_CLK); /* initialize the clock */
|
||||
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 */
|
||||
&& 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 */
|
||||
&& 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 */
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,6 +23,12 @@
|
|||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
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
|
||||
14-Feb-16 JDB First release version
|
||||
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_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_PFARS_SHIFT (UNIT_V_UF + 3) /* the power-fail auto-restart mode */
|
||||
|
||||
#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_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_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 MEMSIZE (cpu_unit [0].capac) /* the current memory size in 16-bit words */
|
||||
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
/* 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 */
|
||||
|
||||
typedef enum {
|
||||
running, /* the micromachine is running */
|
||||
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 */
|
||||
} EXEC_STATE;
|
||||
|
||||
|
@ -201,7 +240,7 @@ typedef enum {
|
|||
cpx2_DECRADDR = 0000040u, /* decrement address */
|
||||
/* cpx2_UNUSED = 0000020u, 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_RUN = 0000001u /* run flip-flop */
|
||||
} CPX2FLAG;
|
||||
|
@ -297,7 +336,7 @@ typedef enum {
|
|||
trap_DS_Absent = 042, /* ucode Absent Data Segment */
|
||||
trap_Power_On = 043, /* hdwe Power On */
|
||||
trap_Cold_Load = 044, /* ucode Cold Load */
|
||||
trap_System_Halt = 045, /* ucode System Halt */
|
||||
trap_System_Halt = 045 /* ucode System Halt */
|
||||
} TRAP_CLASS;
|
||||
|
||||
#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)))
|
||||
|
||||
|
||||
/* 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.
|
||||
|
||||
The CPU status register, STA, has this format:
|
||||
|
@ -840,6 +923,15 @@ typedef enum {
|
|||
#define TBX 0054000u /* 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 */
|
||||
|
||||
|
@ -858,6 +950,12 @@ typedef enum {
|
|||
#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 */
|
||||
|
||||
#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 CPX1; /* Run-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 CNTR; /* Microcode Counter */
|
||||
|
||||
|
@ -967,10 +1066,11 @@ extern HP_WORD CNTR; /* Microcode Counter */
|
|||
/* CPU state */
|
||||
|
||||
extern jmp_buf cpu_save_env; /* saved environment for microcode aborts */
|
||||
extern POWER_STATE cpu_power_state; /* power supply state */
|
||||
extern EXEC_STATE cpu_micro_state; /* micromachine execution state */
|
||||
extern uint32 cpu_stop_flags; /* set of simulation stop flags */
|
||||
extern t_bool cpu_base_changed; /* TRUE if any base register has been changed */
|
||||
extern UNIT cpu_unit; /* CPU unit structure (needed for memory size) */
|
||||
extern UNIT cpu_unit []; /* CPU unit array (needed for memory size) */
|
||||
|
||||
|
||||
/* Condition Code B mapping table */
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
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
|
||||
13-Jan-16 JDB First release version
|
||||
11-Dec-12 JDB Created
|
||||
|
@ -2991,7 +2993,7 @@ switch (operation) { /* dispatch the move or
|
|||
break;
|
||||
|
||||
|
||||
case 020: /* MVBW (CCB; STUN, STOV, BNDV() */
|
||||
case 020: /* MVBW (CCB; STUN, STOV, BNDV) */
|
||||
case 021:
|
||||
case 022:
|
||||
case 023:
|
||||
|
@ -3417,10 +3419,10 @@ switch (operation) { /* dispatch the move or
|
|||
cpu_push (); /* push the stack down */
|
||||
|
||||
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 */
|
||||
RA = 2; /* then the CPU number is 2 */
|
||||
RA = PCN_SERIES_III; /* then the CPU number is 2 */
|
||||
|
||||
else /* if it's anything else */
|
||||
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.
|
||||
If the stop is bypassed or not set, then the instruction will execute as
|
||||
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)
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
uint32 operation;
|
||||
HP_WORD operand, address, offset;
|
||||
HP_WORD ics_q, delta_qi, disp_counter;
|
||||
uint32 operation, address, offset, module;
|
||||
HP_WORD operand, command, ics_q, delta_qi, disp_counter;
|
||||
t_stat status = SCPE_OK;
|
||||
|
||||
operation = IOCSUBOP (CIR); /* get the suboperation from the instruction */
|
||||
|
@ -3663,7 +3679,7 @@ switch (operation) { /* dispatch the I/O or c
|
|||
|
||||
else /* otherwise */
|
||||
cpu_read_memory (absolute, /* use the specified offset */
|
||||
offset + SGT_POINTER & LA_MASK,
|
||||
offset + SGT_POINTER, /* which cannot overflow */
|
||||
&operand);
|
||||
|
||||
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 */
|
||||
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 */
|
||||
|
||||
else /* otherwise */
|
||||
STA &= ~STATUS_I; /* disable them */
|
||||
if (MOD != 0) /* if a module interrupt is pending */
|
||||
CPX1 |= cpx1_MODINTR; /* then request it now */
|
||||
}
|
||||
|
||||
else { /* otherwise */
|
||||
STA &= ~STATUS_I; /* disable interrupts */
|
||||
CPX1 &= ~cpx1_MODINTR; /* and clear any indicated module interrupt */
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
@ -3953,7 +3975,50 @@ switch (operation) { /* dispatch the I/O or c
|
|||
if (NPRV) /* if the mode is not privileged */
|
||||
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;
|
||||
|
||||
|
||||
|
@ -3969,7 +4034,7 @@ switch (operation) { /* dispatch the I/O or c
|
|||
|
||||
else /* otherwise */
|
||||
cpu_read_memory (absolute, /* use the specified offset */
|
||||
offset + SGT_POINTER & LA_MASK,
|
||||
offset + SGT_POINTER, /* which cannot overflow */
|
||||
&operand);
|
||||
|
||||
if (NPRV) /* if the mode is not privileged */
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
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
|
||||
05-Sep-15 JDB First release version
|
||||
11-Dec-12 JDB Created
|
||||
|
@ -92,7 +95,7 @@ typedef enum {
|
|||
Implementation notes:
|
||||
|
||||
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
|
||||
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_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)
|
||||
|
||||
|
@ -139,7 +142,16 @@ typedef enum {
|
|||
} 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_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_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
|
||||
*/
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
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
|
||||
21-Mar-16 JDB Changed uint16 types to HP_WORD
|
||||
19-Mar-16 JDB Added UNDEFs for the additional register macros
|
||||
|
@ -306,6 +307,8 @@
|
|||
#define STOP_INFLOOP 7 /* infinite loop stop */
|
||||
#define STOP_CLOAD 8 /* cold load 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 */
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
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
|
||||
simulation. Diagnostic programs were obtained from two magnetic tapes: HP
|
||||
30000-11016 Rev. 1244 (CPU) and 30000-11017 Rev. 2640 (non-CPU). For each
|
||||
diagnostic, the recommended standard tests were selected, plus any available
|
||||
optional tests that broadened the test coverage.
|
||||
The HP 32230 diagnostic suite has been run against the SIMH HP 3000 simulation.
|
||||
Diagnostic programs were obtained from two magnetic tapes: HP 30000-11016 Rev.
|
||||
1244 (CPU) and 30000-11017 Rev. 2640 (non-CPU). For each diagnostic, the
|
||||
recommended standard tests were selected, plus any available optional tests that
|
||||
broadened the test coverage.
|
||||
|
||||
Except where noted in the individual diagnostic reports, the test system
|
||||
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
|
||||
PD420A1 CPU Diagnostic Section 2 01.00 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
|
||||
PD420A5 CPU Diagnostic Section 6 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 NOTES: The Internal Switch Register (2000) and Section Select Register
|
||||
(2001) settings are preconfigured to simplify execution.
|
||||
|
||||
|
@ -210,27 +209,29 @@ D420A3 - CPU Section 4
|
|||
TESTED DEVICE: CPU (hp3000_cpu.c)
|
||||
|
||||
CONFIGURATION: sim> deposit 2000 000001
|
||||
sim> deposit 2001 034160
|
||||
sim> deposit 010550 120005
|
||||
sim> deposit 2001 034170
|
||||
sim> deposit 015761 051007
|
||||
sim> set scmb enable
|
||||
sim> set scmb mx
|
||||
sim> set cpu stop=PAUSE
|
||||
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
|
||||
(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
|
||||
(30003-90001, April 1979) says that step 31 has been "eliminated
|
||||
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
|
||||
|
||||
TEST RESULT: Passed.
|
||||
|
||||
TEST NOTES: The test was run from the OPERATOR.SYS account on MPE-V/R
|
||||
release E.01.00.
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
DS HP 30229B Cartridge Disc Interface
|
||||
|
||||
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
|
||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||
16-May-16 JDB Fixed interrupt mask setting
|
||||
|
@ -439,7 +440,8 @@ static REG ds_reg [] = {
|
|||
{ DRDATA (RETRY, retry_counter, 4), REG_FIT | PV_LEFT },
|
||||
|
||||
{ SRDATA (DIAG, overrides, REG_HRO) },
|
||||
{ SRDATA (DIB, ds_dib, REG_HRO) },
|
||||
|
||||
DIB_REGS (ds_dib),
|
||||
|
||||
DL_REGS (mac_cntlr, ds_unit, UNIT_COUNT, buffer, fast_times),
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
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
|
||||
21-Mar-16 JDB Changed type of inbound_value of CNTLR_INTRF to HP_WORD
|
||||
20-Jan-16 JDB First release version
|
||||
|
@ -135,7 +137,7 @@ typedef enum { /* --- source of signal --- */
|
|||
INTPOLLIN = 000040000000, /* IOP interrupt poll */
|
||||
XFERERROR = 000100000000, /* Multiplexer channel abort */
|
||||
CHANSO = 000200000000, /* Channel service call to interface */
|
||||
PFWARN = 000400000000 /* SET CPU POWERFAIL */
|
||||
PFWARN = 000400000000 /* POWER FAIL command */
|
||||
/* = 001000000000 (available) */
|
||||
/* = 002000000000 (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
|
||||
execute instructions with 32-bit operands much faster than those with
|
||||
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 */
|
||||
|
@ -312,6 +320,17 @@ struct dib { /* the Device Information Block
|
|||
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 */
|
||||
|
||||
|
@ -334,13 +353,14 @@ typedef enum {
|
|||
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 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);
|
||||
|
||||
|
||||
/* Global asynchronous signal assertion functions */
|
||||
|
||||
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_SRn (DIB *dib_pointer); /* assert the multiplexer channel service request signal */
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
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
|
||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||
|
@ -120,7 +122,7 @@
|
|||
memory.
|
||||
|
||||
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
|
||||
IOCMD0-2 as follows:
|
||||
|
||||
|
@ -277,6 +279,7 @@ static uint32 filter [4] = { /* filter bitmap for device numb
|
|||
|
||||
/* 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_show_filter (FILE *st, UNIT *uptr, int32 value, CONST void *desc);
|
||||
|
||||
|
@ -342,7 +345,7 @@ DEVICE iop_dev = {
|
|||
DV_WIDTH, /* data width */
|
||||
NULL, /* examine routine */
|
||||
NULL, /* deposit routine */
|
||||
NULL, /* reset routine */
|
||||
&iop_reset, /* reset routine */
|
||||
NULL, /* boot routine */
|
||||
NULL, /* attach 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
|
||||
there are no devices with active interrupts (as the user may have set the
|
||||
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)
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
||||
/* 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.
|
||||
|
||||
If the "value" parameter is 1, the filter array bits corresponding to the
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
|
||||
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
|
||||
27-Apr-16 JDB Passes the On-Line HP Line Printers Verification (D466A)
|
||||
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
|
||||
current line. In simulation, a DETACH is handled as a torn-paper
|
||||
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 */
|
||||
|
||||
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 */
|
||||
|
@ -1034,7 +1045,9 @@ static uint32 form_length; /* form length in lines */
|
|||
static uint8 buffer [BUFFER_SIZE]; /* character and paper advance buffer */
|
||||
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 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 */
|
||||
|
||||
|
@ -1126,21 +1139,7 @@ static UNIT lp_unit [] = {
|
|||
|
||||
Implementation notes:
|
||||
|
||||
1. The VFU register displays the data currently held in the printer's
|
||||
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
|
||||
1. 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
|
||||
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
|
||||
|
@ -1149,7 +1148,7 @@ static UNIT lp_unit [] = {
|
|||
|
||||
static REG lp_reg [] = {
|
||||
/* Macro Name Location Radix Width Offset Depth Flags */
|
||||
/* ------ ------ ------------------------ ----- ------------ ------ ------------- ----------------- */
|
||||
/* ------ ------ ------------------------ ----- ------------ ------ ------------- ------------------ */
|
||||
{ FLDATA (SIOBSY, sio_busy, 0) },
|
||||
{ FLDATA (CHANSR, channel_sr, 0) },
|
||||
{ FLDATA (DEVSR, device_sr, 0) },
|
||||
|
@ -1178,12 +1177,11 @@ static REG lp_reg [] = {
|
|||
{ FLDATA (DFIN, device_flag_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) },
|
||||
|
||||
{ FLDATA (PFAULT, paper_fault, 0) },
|
||||
{ FLDATA (TFAULT, tape_fault, 0) },
|
||||
|
@ -1196,13 +1194,15 @@ static REG lp_reg [] = {
|
|||
|
||||
{ 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 },
|
||||
{ ORDATA (PCHR, punched_char, 8), PV_RZRO | REG_A },
|
||||
{ ORDATA (UPCHR, unpunched_char, 8), PV_RZRO | REG_A },
|
||||
|
||||
{ DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ },
|
||||
{ DRDATA (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 },
|
||||
{ DRDATA (UWAIT, lp_unit [0].wait, 32), PV_LEFT | REG_HRO },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -1232,7 +1232,7 @@ static MTAB lp_mod [] = {
|
|||
{ UNIT_EXPAND, 0, "compact output", "COMPACT", NULL, NULL, NULL, },
|
||||
|
||||
/* Entry Flags Value Print String Match String Validation Display Descriptor */
|
||||
/* ------------------ ----------- ------------ ------------ ------------ ------------- ---------------- */
|
||||
/* ------------------- ----------- ------------ ------------ ------------ ------------- ---------------- */
|
||||
{ MTAB_XDV, Fast_Time, NULL, "FASTTIME", &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 },
|
||||
|
@ -1244,6 +1244,7 @@ static MTAB lp_mod [] = {
|
|||
{ MTAB_XDV, VAL_INTPRI, "INTPRI", "INTPRI", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
|
||||
{ MTAB_XDV, VAL_SRNO, "SRNO", "SRNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib },
|
||||
|
||||
{ MTAB_XDV | MTAB_NMO, 1, "VFU", NULL, NULL, &lp_show_vfu, NULL },
|
||||
{ MTAB_XDV | MTAB_NC, 0, "VFU", "VFU", &lp_set_vfu, &lp_show_vfu, NULL },
|
||||
|
||||
{ 0 }
|
||||
|
@ -1343,7 +1344,10 @@ DEVICE lp_dev = {
|
|||
2. In hardware, the SETJMP signal is ignored, and the JMPMET signal is
|
||||
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)
|
||||
|
@ -1622,7 +1626,8 @@ while (working_set) {
|
|||
break;
|
||||
|
||||
|
||||
case PFWARN: /* not currently simulated */
|
||||
case PFWARN:
|
||||
power_warning = TRUE; /* system power is in the process of failing */
|
||||
break;
|
||||
|
||||
|
||||
|
@ -2382,6 +2387,13 @@ return SCPE_OK;
|
|||
|
||||
2. The DHA transfer service is called with a null pointer to update the
|
||||
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)
|
||||
|
@ -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 */
|
||||
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 */
|
||||
new_status |= ST_DHA_MR; /* then indicate a master clear */
|
||||
|
@ -2535,20 +2550,14 @@ return outbound_signals; /* return INTREQ if any
|
|||
|
||||
Implementation notes:
|
||||
|
||||
1. Slewing in expanded mode is performed by appending CR LF pairs to the
|
||||
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
|
||||
1. 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,
|
||||
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
|
||||
host system, the printer output file must be postprocessed to remove the
|
||||
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
|
||||
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
|
||||
|
@ -2561,20 +2570,20 @@ return outbound_signals; /* return INTREQ if any
|
|||
"overprint character" (which defaults to DEL, but can be changed by the
|
||||
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 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
(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
|
||||
|
@ -2648,9 +2657,6 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
|
|||
buffer_index++; /* increment the buffer index */
|
||||
|
||||
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 */
|
||||
|
@ -2678,13 +2684,13 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
|
|||
buffer [0] = data_byte; /* store the character */
|
||||
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 */
|
||||
+ dlyptr->advance /* plus the paper advance 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 */
|
||||
|
@ -3010,16 +3016,11 @@ return SCPE_OK; /* the mode change succe
|
|||
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
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
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.
|
||||
|
||||
This display routine is called to show the title of the tape currently loaded
|
||||
in the printer's VFU. The title is taken from the tape image file if a
|
||||
custom tape is loaded. Otherwise, the standard tape title is displayed.
|
||||
This display routine is called to show the content of the tape currently
|
||||
loaded in the printer's VFU. The "value" parameter indicates how the routine
|
||||
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
|
||||
are ignored.
|
||||
The output stream is passed in the "st" parameter, and the "uptr" and "desc"
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -3191,19 +3236,8 @@ return SCPE_OK;
|
|||
online).
|
||||
|
||||
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
|
||||
standard VFU tape is loaded.
|
||||
|
||||
|
||||
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.
|
||||
settings are restored, the standard VFU tape is loaded, and the power failure
|
||||
warning is cleared.
|
||||
*/
|
||||
|
||||
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.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 */
|
||||
|
||||
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 */
|
||||
|
@ -3436,7 +3461,7 @@ return TRUE;
|
|||
no-punch character a single character representing a non-punched location
|
||||
|
||||
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"
|
||||
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
|
||||
command processing to determine if a punch is present somewhere in a
|
||||
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)
|
||||
|
@ -3504,7 +3525,7 @@ char *bptr, *tptr;
|
|||
uint16 tape [VFU_SIZE] = { 0 };
|
||||
|
||||
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 [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 */
|
||||
strcpy (vfu_title, tptr); /* then save the user's title */
|
||||
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 */
|
||||
|
@ -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 */
|
||||
|
||||
vfu_reg->depth = form_length + 1; /* set the VFU display depth */
|
||||
|
||||
return SCPE_OK; /* the VFU was successfully loaded */
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
@ -732,7 +734,7 @@ static REG mpx_reg [] = {
|
|||
{ ORDATA (CTRREG, cntr_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 }
|
||||
};
|
||||
|
@ -1737,7 +1739,7 @@ while (working_set) {
|
|||
dprintf (mpx_dev, DEB_CSRW, "Order register value %02o (%s) "
|
||||
"and counter register value %d returned\n",
|
||||
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 */
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
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
|
||||
08-Jun-16 JDB Corrected %d format to %u for unsigned values
|
||||
16-May-16 JDB Fixed interrupt mask setting
|
||||
|
@ -517,7 +518,8 @@ static REG ms_reg [] = {
|
|||
{ DRDATA (ATUNIT, attention_unit, 16), REG_FIT | PV_LEFT },
|
||||
{ DRDATA (CLASS, command_class, 4), PV_LEFT },
|
||||
{ YRDATA (FLAGS, flags, 8, PV_RZRO) },
|
||||
{ SRDATA (DIB, ms_dib, REG_HRO) },
|
||||
|
||||
DIB_REGS (ms_dib),
|
||||
|
||||
TL_REGS (ms_cntlr, ms_unit, DRIVE_COUNT, buffer, fast_times),
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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.
|
||||
|
@ -45,7 +45,7 @@ The simulator has been tested with MPE-V/R version E.01.00. Specifically:
|
|||
run properly.
|
||||
|
||||
- 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
|
||||
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
|
||||
=====================
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
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
|
||||
13-May-16 JDB Modified for revised SCP API function parameter types
|
||||
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 (STOP, scmb [card1].stop_transfer, 0) },
|
||||
|
||||
{ SRDATA (DIB, scmb_dib [card1], REG_HRO) },
|
||||
DIB_REGS (scmb_dib [card1]),
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -489,7 +490,7 @@ static REG scmb2_reg [] = {
|
|||
{ FLDATA (DEVEND, scmb [card2].device_end, 0) },
|
||||
{ FLDATA (STOP, scmb [card2].stop_transfer, 0) },
|
||||
|
||||
{ SRDATA (DIB, scmb_dib [card1], REG_HRO) },
|
||||
DIB_REGS (scmb_dib [card2]),
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
@ -426,8 +427,8 @@ static void load_address (HP_WORD *value);
|
|||
|
||||
/* Unit list */
|
||||
|
||||
static UNIT sel_unit = {
|
||||
UDATA (&sel_timer, 0, 0), SR_WAIT_TIMER
|
||||
static UNIT sel_unit [] = {
|
||||
{ UDATA (&sel_timer, 0, 0), SR_WAIT_TIMER }
|
||||
};
|
||||
|
||||
/* Register list */
|
||||
|
@ -476,7 +477,7 @@ static DEBTAB sel_deb [] = {
|
|||
|
||||
DEVICE sel_dev = {
|
||||
"SEL", /* device name */
|
||||
&sel_unit, /* unit array */
|
||||
sel_unit, /* unit array */
|
||||
sel_reg, /* register array */
|
||||
NULL, /* modifier array */
|
||||
1, /* number of units */
|
||||
|
@ -608,7 +609,7 @@ else { /* otherwise abort the t
|
|||
device_number);
|
||||
|
||||
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;
|
||||
|
@ -817,7 +818,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
|
||||
|
||||
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_address (&address_word); /* and the IOAW */
|
||||
|
@ -963,7 +964,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
prefetch_control = FALSE; /* prefetching is not used */
|
||||
prefetch_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 */
|
||||
break;
|
||||
|
||||
|
@ -972,7 +973,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
prefetch_control = (order == sioWRITEC); /* enable prefetching */
|
||||
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 */
|
||||
break;
|
||||
|
||||
|
@ -987,7 +988,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
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 */
|
||||
break;
|
||||
} /* end switch */
|
||||
|
@ -997,7 +998,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -1072,7 +1073,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -1173,7 +1174,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
|
|||
active_dib->service_request = FALSE; /* clear the current service request */
|
||||
|
||||
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 */
|
||||
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
in advertising or otherwise to promote the sale, use or other dealings in
|
||||
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
|
||||
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
|
||||
|
@ -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 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_run_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 */
|
||||
"Infinite loop", /* STOP_INFLOOP */
|
||||
"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 },
|
||||
{ "DEPOSIT", &hp_exdep_cmd, 0, NULL },
|
||||
{ "IDEPOSIT", &hp_exdep_cmd, 0, NULL },
|
||||
|
||||
{ "RUN", &hp_run_cmd, 0, NULL },
|
||||
{ "GO", &hp_run_cmd, 0, NULL },
|
||||
|
||||
{ "BREAK", &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 }
|
||||
};
|
||||
|
||||
|
@ -1675,8 +1690,26 @@ return formatted; /* return a pointer to t
|
|||
|
||||
Implementation notes:
|
||||
|
||||
1. The longest string to be returned is a five-character escaped octal
|
||||
string, consisting of a backslash, three digits, and a trailing NUL.
|
||||
1. The longest string to be returned is a five-character escaped string
|
||||
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)
|
||||
|
@ -1687,7 +1720,10 @@ static const char *const control [] = {
|
|||
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
|
||||
"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 */
|
||||
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 */
|
||||
return "DEL"; /* then return a readable representation */
|
||||
|
||||
else if (charval > '\177') { /* otherwise if the value is beyond the printable range */
|
||||
sprintf (printable, "\\%03o", charval & D8_MASK); /* then format the value */
|
||||
return printable; /* as an escaped octal code */
|
||||
else {
|
||||
if (freeptr > endptr) /* if there is not enough room left to append the string */
|
||||
freeptr = fmt_buffer; /* then reset to point at the start of the buffer */
|
||||
|
||||
fmtptr = freeptr; /* initialize the return pointer */
|
||||
*freeptr = '\0'; /* and the format accumulator */
|
||||
|
||||
if (charval > '\177') /* otherwise if the value is beyond the printable range */
|
||||
freeptr = freeptr + sprintf (freeptr, "\\%03o", /* then format the value */
|
||||
charval & D8_MASK); /* and update the free pointer */
|
||||
|
||||
else { /* otherwise it's a printable character */
|
||||
*freeptr++ = '\''; /* so form a representation */
|
||||
*freeptr++ = (char) charval; /* containing the character */
|
||||
*freeptr++ = '\''; /* surrounded by single quotes */
|
||||
*freeptr = '\0';
|
||||
}
|
||||
|
||||
else { /* otherwise it's a printable character */
|
||||
printable [0] = '\''; /* so form a representation */
|
||||
printable [1] = (char) charval; /* containing the character */
|
||||
printable [2] = '\''; /* surrounded by single quotes */
|
||||
printable [3] = '\0';
|
||||
return printable;
|
||||
freeptr = freeptr + 1; /* advance past the NUL terminator */
|
||||
return fmtptr; /* and return the formatted string */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1798,30 +1843,43 @@ else { /* otherwise it's a prin
|
|||
Implementation notes:
|
||||
|
||||
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
|
||||
buffer contents are copied upon return. In particular, this type of
|
||||
calling sequence:
|
||||
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.
|
||||
|
||||
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
|
||||
the result of the first call is printed.
|
||||
3. 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. 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)
|
||||
{
|
||||
static char formatted_set [1024]; /* the return buffer */
|
||||
|
||||
const char *bnptr;
|
||||
static const char separator [] = " | "; /* the separator to use between names */
|
||||
static char fmt_buffer [1024]; /* 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 /* 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;
|
||||
char *fsptr = formatted_set;
|
||||
size_t name_length;
|
||||
|
||||
*fsptr = '\0'; /* initialize the format accumulator */
|
||||
index = 0; /* and the name index */
|
||||
if (bitfmt.name_count < D32_WIDTH) /* if the name count is the less than the mask width */
|
||||
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 */
|
||||
bitmask = D32_MASK; /* to prevent shifting the bit off the MSB end */
|
||||
|
||||
|
@ -1834,7 +1892,12 @@ else /* otherwise */
|
|||
test_bit = 1 << bitfmt.offset; /* create a test bit for the LSB */
|
||||
|
||||
|
||||
while ((bitfmt.alternate || bitset) && index < bitfmt.name_count) { /* while more bits and more names exist */
|
||||
fmtptr = freeptr; /* initialize the return pointer */
|
||||
*freeptr = '\0'; /* and the format accumulator */
|
||||
index = 0; /* and the name index */
|
||||
|
||||
while ((bitfmt.alternate || bitset) /* while more bits */
|
||||
&& index < bitfmt.name_count) { /* and more names exist */
|
||||
bnptr = bitfmt.names [index]; /* point at the name for the current bit */
|
||||
|
||||
if (bnptr) /* if the name is defined */
|
||||
|
@ -1849,10 +1912,25 @@ while ((bitfmt.alternate || bitset) && index < bitfmt.name_count) { /* while mor
|
|||
bnptr = NULL; /* then clear the name pointer */
|
||||
|
||||
if (bnptr) { /* if the name pointer is set */
|
||||
if (formatted_set [0] != '\0') /* then if it is not the first one added */
|
||||
fsptr = strcat (fsptr, " | "); /* then add a separator to the string */
|
||||
name_length = strlen (bnptr); /* then get the length needed */
|
||||
|
||||
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 */
|
||||
|
@ -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 */
|
||||
return ""; /* then return an empty string */
|
||||
else /* otherwise it's a standalone format */
|
||||
return "(none)"; /* so return a placeholder */
|
||||
|
||||
else if (bitfmt.bar == append_bar) /* otherwise if a trailing separator is specified */
|
||||
fsptr = strcat (fsptr, " | "); /* then add it to the string */
|
||||
else if (bitfmt.bar == append_bar) { /* otherwise if a trailing separator is specified */
|
||||
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.
|
||||
*/
|
||||
|
||||
#define FLAG_SIZE 50 /* sufficiently large to accommodate all flag names */
|
||||
#define FORMAT_SIZE 1000 /* sufficiently large to accommodate all format strings */
|
||||
#define FLAG_SIZE 32 /* sufficiently large to accommodate all flag names */
|
||||
#define FORMAT_SIZE 1024 /* sufficiently large to accommodate all format strings */
|
||||
|
||||
void hp_debug (DEVICE *dptr, uint32 flag, ...)
|
||||
{
|
||||
|
@ -1973,7 +2056,9 @@ return;
|
|||
|
||||
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 */
|
||||
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 */
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
|
@ -2061,7 +2150,8 @@ else if (reason == STOP_CDUMP) { /* otherwise if this is
|
|||
fprint_val (st, CIR, cpu_dev.dradix, /* and the numeric value */
|
||||
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 */
|
||||
|
@ -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.
|
||||
|
||||
These commands are intercepted to configure address parsing. The following
|
||||
|
@ -2438,8 +2472,8 @@ return;
|
|||
|
||||
Implementation notes:
|
||||
|
||||
1. The Return Residue value is printed as a positive number, even though
|
||||
the value in memory is either negative or zero.
|
||||
1. The Return Residue and Read/Write count values are printed as positive
|
||||
numbers, even though the values in memory are negative.
|
||||
*/
|
||||
|
||||
static const char *const order_names [] = { /* indexed by SIO_ORDER */
|
||||
|
@ -2479,7 +2513,7 @@ switch (order) { /* dispatch operand prin
|
|||
break;
|
||||
|
||||
case sioRTRES: /* print the residue count */
|
||||
fprint_value (ofile, - SEXT (ioaw),
|
||||
fprint_value (ofile, NEG16 (ioaw),
|
||||
(radix ? radix : 10),
|
||||
DV_WIDTH, PV_LEFT);
|
||||
break;
|
||||
|
@ -2516,7 +2550,7 @@ switch (order) { /* dispatch operand prin
|
|||
case sioWRITEC:
|
||||
case sioREAD:
|
||||
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);
|
||||
|
||||
fputc (',', ofile);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
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
|
||||
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
|
||||
|
@ -1540,7 +1541,6 @@ uint32 unit;
|
|||
int32 seek_wait_time;
|
||||
PRPTR props;
|
||||
CNTLR_IFN_IBUS outbound;
|
||||
char s1_buffer [256], s2_buffer [256]; /* formatted bitset buffers for trace logging */
|
||||
DIAG_ENTRY *dop = NULL;
|
||||
|
||||
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",
|
||||
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),
|
||||
(cvptr->buffer [1] & S2_ERROR ? "error | " : ""),
|
||||
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 */
|
||||
rptr->STATUS &= ~S2_FIRST_STATUS; /* then clear the First Status bit */
|
||||
|
|
Binary file not shown.
Loading…
Add table
Reference in a new issue