HP3000: HP 3000 release 5

See HP3000/hp3000_release.txt for details of the release
This commit is contained in:
Mark Pizzolato 2017-05-01 15:47:57 -07:00
parent 90e9c2f4a0
commit f617f63ae0
10 changed files with 357 additions and 170 deletions

View file

@ -197,7 +197,7 @@ static const int32 delay [8] = { /* clock delays, in event ticks
mS (10), /* 100 = 10 milliseconds */
mS (100), /* 101 = 100 milliseconds */
S (1), /* 110 = 1 second */
S (10), /* 111 = 10 seconds */
S (10) /* 111 = 10 seconds */
};
static const int32 ticks [8] = { /* clock ticks per second */

View file

@ -1,6 +1,6 @@
/* hp3000_cpu_cis.c: HP 32234A COBOL II Instruction Set simulator
Copyright (c) 2016, J. David Bryan
Copyright (c) 2016-2017, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -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.
22-Apr-17 JDB Corrected the significance flag setting in "edit"
29-Dec-16 JDB Disabled interrupt checks pending test generation
19-Oct-16 JDB Passes the COBOL-II firmware "A" diagnostic (D441A)
06-Oct-16 JDB Passes the COBOL-II firmware "B" diagnostic (D442A)
@ -1331,9 +1332,9 @@ return trap; /* return the trap condi
If an interrupt is detected between operations, two words are pushed onto the
stack before the interrupt handler is called. These words hold the current
significance trigger (a flag indicating whether a significant digit has been
seen or zero filling should occur), loop count, float character, and fill
character, in this format:
significance trigger (a flag indicating that a significant digit has been
seen or that zero filling should occur), loop count, float character, and
fill character, in this format:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
@ -1389,6 +1390,12 @@ return trap; /* return the trap condi
the address of the displacement byte. After reading the displacement
byte, the address is incremented to the next location, so the operation
subtracts 1 before adding the displacement value.
3. The significance trigger is represented by the "filling" flag; its value
is the opposite of the trigger, i.e., FALSE if a significant digit has
been seen, TRUE if all leading digits have been zeros, because that more
clearly indicates that it controls leading zero suppression and
replacement.
*/
static t_bool edit (t_stat *status, uint32 *trap)
@ -1406,7 +1413,7 @@ t_bool terminate = FALSE; /* TRUE if the operation
*trap = trap_None; /* and trap condition */
if (RA != 0) { /* if this is a reentry after an interrupt */
filling = ((RB & D16_SIGN) != 0); /* then reset the zero-filling flag */
filling = ((RB & D16_SIGN) == 0); /* then reset the zero-filling flag */
loop_count = LOWER_BYTE (RB); /* and the loop counter */
fill_char = UPPER_BYTE (RC); /* reset the fill */
float_char = LOWER_BYTE (RC); /* and float characters */
@ -1773,8 +1780,8 @@ do { /* process operations wh
RA = D16_UMAX; /* set the resumption flag */
RB = TO_WORD ((filling ? D16_SIGN : 0), loop_count); /* save the significance trigger and loop count */
RC = TO_WORD (fill_char, float_char); /* save the fill and float characters */
RB = (filling ? 0 : D16_SIGN) | loop_count; /* save the significance trigger and loop count */
RC = TO_WORD (fill_char, float_char); /* save the fill and float characters */
mem_update_byte (&target); /* update the last word written */
return FALSE; /* and return with an interrupt set up or a status error */

View file

@ -1,6 +1,6 @@
/* hp3000_lp.c: HP 3000 30209A Line Printer Interface simulator
Copyright (c) 2016, J. David Bryan
Copyright (c) 2016-2017, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -25,6 +25,10 @@
LP HP 30209A Line Printer Interface
26-Apr-17 JDB Fixed "lp_service" return for VFU channel not punched
Restricted auto-print on buffer full to the 2607
Paper fault is now delayed until the TOF for the 2607
Changed "activate_unit" to schedule zero-length delays
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
@ -537,23 +541,30 @@ typedef enum {
This table contains the characteristics that vary between printer models.
The "char_set" field values reflect printer Option 001, 96/128-character set.
The "not_ready" field indicates whether a paper fault sets not-ready status
or simply takes the printer offline. The "fault_at_eol" field indicates
whether a paper fault is reported at the end of any line (TRUE) or only at
the top of the next form (FALSE).
*/
typedef struct {
uint32 line_length; /* the maximum number of print positions */
uint32 char_set; /* the size of the character set */
uint32 vfu_channels; /* the number of VFU channels */
t_bool not_ready; /* TRUE if the printer reports a separate not ready status */
t_bool overprints; /* TRUE if the printer supports overprinting */
t_bool autoprints; /* TRUE if the printer automatically prints on buffer overflow */
t_bool fault_at_eol; /* TRUE if a paper fault is reported at the end of any line */
} PRINTER_PROPS;
static const PRINTER_PROPS print_props [] = { /* printer properties, indexed by PRINTER_TYPE */
/* line char VFU over */
/* length set channels prints */
/* ------ ----- -------- ------ */
{ 132, 128, 8, FALSE }, /* HP_2607 */
{ 136, 96, 12, TRUE }, /* HP_2613 */
{ 136, 96, 12, TRUE }, /* HP_2617 */
{ 132, 96, 12, TRUE } /* HP_2618 */
/* line char VFU not over auto fault */
/* length set channels ready prints prints at EOL */
/* ------ ----- -------- ------ ------ ------ ------ */
{ 132, 128, 8, FALSE, FALSE, TRUE, FALSE }, /* HP_2607 */
{ 136, 96, 12, TRUE, TRUE, FALSE, TRUE }, /* HP_2613 */
{ 136, 96, 12, TRUE, TRUE, FALSE, TRUE }, /* HP_2617 */
{ 132, 96, 12, TRUE, TRUE, FALSE, TRUE } /* HP_2618 */
};
@ -1650,9 +1661,7 @@ return IORETURN (outbound_signals, outbound_value); /* return the outbound s
This service routine is called once for each state of the device transfer
handshake. The handshake sequencer schedules the transfer events with the
appropriate delays. If no delay is required, the service routine is entered
directly from the sequencer. Otherwise, an event is scheduled, and the
routine is entered when the event time expires.
appropriate delays.
Jumper W10 determines the output polarity of the DEV CMD signal to the
device, and jumpers W2 and W6 determine the input edges of the DEV FLAG
@ -1679,10 +1688,9 @@ return IORETURN (outbound_signals, outbound_value); /* return the outbound s
Device Flag is accomplished by comparing the current state to the prior
state.
2. If the routine was entered by event timer expiration, the handshake
2. As the routine was entered by an event timer expiration, the handshake
sequencer must be called explicitly, and any returned backplane signals
must be asserted explicitly. If the routine was called directly, the
sequencer is responsible for asserting backplane signals as required.
must be asserted explicitly.
3. This routine may be called with a NULL "uptr" parameter to update the
saved last state of the "device_flag_in" variable. The NULL value
@ -1692,7 +1700,6 @@ return IORETURN (outbound_signals, outbound_value); /* return the outbound s
static t_stat xfer_service (UNIT *uptr)
{
static t_bool device_flag_last = FALSE;
const t_bool timed_entry = (uptr != NULL && uptr->wait > 0); /* TRUE if entry was by event timer */
t_stat result;
OUTBOUND_SET signals;
@ -1718,15 +1725,13 @@ else /* otherwise Device Comm
device_flag_last = device_flag_in; /* save the current state of the flag */
if (timed_entry) { /* if this is a timed entry */
signals = handshake_xfer (); /* then continue the handshake */
signals = handshake_xfer (); /* continue the handshake */
if (signals & INTREQ) /* if an interrupt request was generated */
iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */
if (signals & INTREQ) /* if an interrupt request was generated */
iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */
if (signals & SRn) /* if a service request was generated */
mpx_assert_SRn (&lp_dib); /* then assert the SRn signal */
}
if (signals & SRn) /* if a service request was generated */
mpx_assert_SRn (&lp_dib); /* then assert the SRn signal */
return result; /* return the result of the service call */
}
@ -1742,14 +1747,16 @@ return result; /* return the result of
static t_stat pulse_service (UNIT *uptr)
{
t_stat status;
dprintf (lp_dev, DEB_SERV, "Pulse service entered\n");
device_command = CLEAR; /* clear the device command flip-flop */
activate_unit (xfer_uptr); /* let the device know that command has denied */
status = xfer_service (xfer_uptr); /* let the device know that command has denied */
handshake_xfer (); /* and continue the handshake */
return SCPE_OK;
return status;
}
@ -1880,23 +1887,25 @@ return;
}
/* Activate a unit.
/* Activate the unit.
The specified unit is added to the event queue if a non-zero event time has
been given. Otherwise, the event handler is called directly.
The specified unit is activated using the unit's "wait" time. If tracing
is enabled, the activation is logged to the debug file.
Implementation notes:
1. A zero-length delay is scheduled, rather than calling the service routine
directly, so that the status return value from the event service routine
is correctly passed back to SCP.
*/
static void activate_unit (UNIT *uptr)
{
if (uptr->wait > 0) { /* if the event time is set */
dprintf (lp_dev, DEB_SERV, "%s delay %u service scheduled\n",
unit_name [uptr - lp_unit], uptr->wait);
dprintf (lp_dev, DEB_SERV, "%s delay %u service scheduled\n",
unit_name [uptr - lp_unit], uptr->wait);
sim_activate (uptr, uptr->wait); /* then activate the unit */
}
else /* otherwise */
uptr->action (uptr); /* call the event handler directly */
sim_activate (uptr, uptr->wait); /* activate the unit */
return;
}
@ -2022,29 +2031,15 @@ return outbound_signals; /* return INTREQ if
The device service is scheduled after each state transition, except the
return to the idle state, to detect the change in the Device Command signal
or to schedule the change in the Device Flag. The device determines whether
the service is entered immediately or after an event time expires.
the service will be entered immediately (at the next poll) or after a delay
time expires.
For the diagnostic device, the service routine is entered immediately for all
transitions. If the DHA is configured for flag-follows-command mode, the
full handshake cycle executes before returning from the routine. If it is
configured for flag-follows-control-6, the routine returns after the Idle-to-
Device_Command_1 state transition to wait for control word bit 6 to be set.
When it is, the routine is reentered, transitions from Device_Command_1 to
Device_Flag_1, and then returns to wait for control word bit 6 to be cleared.
When it is, the routine is entered and completes the transition from
Device_Flag_1 to the Idle state (assuming a word transfer).
transitions. For the printer device, the service routine is entered
immediately for Device Flag assertions, but flag denials are scheduled with a
delay corresponding to the printer operation time. The operations are as
follows:
For the printer device, the service routine is entered immediately for Device
Flag assertions, but flag denials are scheduled with a delay corresponding to
the printer operation time. The initial handshake entry transitions from
Idle to Device_Command_1, calls the service routine, which sets Device Flag,
transitions to Device_Flag_1, schedules the service routine, and returns to
wait for the event timer to expire. When it does, the event service routine
is entered, which clears Device Flag and calls this routine to continue the
handshake. The routine transitions from Device_Flag_1 to Idle to complete
the handshake sequence.
Summarizing:
Diagnostic Service Diagnostic Service
State Printer Service Flag follows Cmd Flag follows cont.6
---------------- ---------------- ------------------ -------------------
@ -2135,12 +2130,17 @@ return outbound_signals; /* return INTREQ if
DATA OUT and DATA IN lines, so we must simulate the multiplexing
accurately with respect to the intermediate values before the handshake
is complete.
5. The sequencer loop is used only during a device end assertion to move
from Idle to Device_Command_1 and back to Idle. All other transitions
involve unit activation and so exit this routine after the sequence state
is changed.
*/
static OUTBOUND_SET handshake_xfer (void)
{
const SEQ_STATE entry_state = sequencer; /* the state of the sequencer at entry */
t_bool started = FALSE; /* TRUE if the sequencer started */
t_bool reset = FALSE; /* TRUE if the sequencer is reset */
OUTBOUND_SET outbound_signals = NO_SIGNALS;
SEQ_STATE last_state;
@ -2172,8 +2172,6 @@ do { /* run the sequencer as
activate_unit (xfer_uptr); /* schedule device flag assertion */
}
started = TRUE; /* indicate that the sequencer was started */
}
break;
@ -2188,7 +2186,9 @@ do { /* run the sequencer as
write_xfer = CLEAR; /* and write transfer flip-flops */
sequencer = Idle; /* idle the sequencer */
device_sr = SET; /* and request channel service */
reset = TRUE; /* and indicate that it was reset */
device_sr = SET; /* request channel service */
break;
}
@ -2274,13 +2274,8 @@ if (DPRINTING (lp_dev, DEB_STATE))
hp_debug (&lp_dev, DEB_STATE, "Sequencer transitioned from the %s state to the %s state\n",
state_name [entry_state], state_name [sequencer]);
else if (started)
if (device_end)
hp_debug (&lp_dev, DEB_STATE, "Sequencer reset by device end\n");
else
hp_debug (&lp_dev, DEB_STATE, "Sequencer executed a full %s-transfer cycle\n",
(control_word & CN_BYTE_XFER ? "byte" : "word"));
else if (reset && device_end)
hp_debug (&lp_dev, DEB_STATE, "Sequencer reset by device end\n");
if (device_sr && sio_busy) /* if the interface has requested service */
outbound_signals |= SRn; /* then assert SRn to the channel */
@ -2478,13 +2473,13 @@ return outbound_signals; /* return INTREQ if any
indicate that the buffer load or print operation is complete.
In simulation, this service routine is called twice for each transfer. It is
called directly with Device Command set and then after a variable delay with
Device Command clear. In response to the former call, the routine sets the
Device Flag, loads the character buffer or prints the buffered line, and then
sets up an event delay corresponding to the operation performed. In response
to the latter call, the routine clears the Device Flag and then clears the
event delay time, so that the routine will be reentered directly when Device
Command sets again.
called immediately with Device Command set and then after a variable delay
with Device Command clear. In response to the former call, the routine sets
the Device Flag, loads the character buffer or prints the buffered line, and
then sets up an event delay corresponding to the operation performed. In
response to the latter call, the routine clears the Device Flag and then
clears the event delay time, so that the routine will be reentered
immediately when Device Command sets again.
If a SET LP OFFLINE command or a DETACH LP command simulating an out-of-paper
condition is given, the printer will not honor the command immediately if
@ -2593,7 +2588,7 @@ return outbound_signals; /* return INTREQ if any
static t_stat lp_service (UNIT *uptr)
{
const t_bool printing = ((control_word & CN_FORMAT) != 0); /* TRUE if a print command was received */
const t_bool printing = ((control_word & CN_FORMAT) != 0); /* TRUE if a print command was received */
static uint32 overprint_index = 0;
PRINTER_TYPE model;
uint8 data_byte, format_byte;
@ -2602,6 +2597,8 @@ uint32 line_count, slew_count, vfu_status;
if (uptr == NULL) /* if we're called for a state update */
return SCPE_OK; /* then return with no other action */
else /* otherwise */
model = GET_MODEL (uptr->flags); /* get the printer type */
dprintf (lp_dev, DEB_SERV, "%s state printer service entered\n",
state_name [sequencer]);
@ -2610,12 +2607,16 @@ if (device_command_out == FALSE) { /* if STROBE has denied
if (printing) { /* then if printing occurred */
buffer_index = 0; /* then clear the buffer */
if (paper_fault) /* if an out-of-paper condition is pending */
return lp_detach (uptr); /* then complete it now with the printer offline */
if (paper_fault) { /* if an out-of-paper condition is pending */
if (print_props [model].fault_at_eol /* then if the printer faults at the end of any line */
|| current_line == 1) /* or the printer is at the top of the form */
return lp_detach (uptr); /* then complete it now with the printer offline */
}
else if (tape_fault) { /* otherwise if a referenced VFU channel was not punched */
dprintf (lp_dev, DEB_CMD, "Commanded VFU channel is not punched\n");
return lp_set_alarm (uptr); /* then take the printer offline now */
lp_set_alarm (uptr); /* then set an alarm condition that takes the printer offline */
return SCPE_OK;
}
else if (offline_pending) { /* otherwise if a non-alarm offline request is pending */
@ -2631,8 +2632,6 @@ if (device_command_out == FALSE) { /* if STROBE has denied
else if (device_flag_in == FALSE) { /* otherwise if STROBE has asserted while DEMAND is asserted */
device_flag_in = TRUE; /* then deny DEMAND */
model = GET_MODEL (uptr->flags); /* get the printer type */
data_byte = (uint8) (data_out & DATA_MASK); /* only the lower 7 bits are connected */
if (printing == FALSE) { /* if loading the print buffer */
@ -2657,9 +2656,12 @@ 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 */
else if (print_props [model].autoprints) { /* otherwise if a buffer overflow auto-prints */
dprintf (lp_dev, DEB_CMD, "Buffer overflow printed %u characters on line %u\n",
buffer_index, current_line);
@ -2669,7 +2671,7 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
fwrite (buffer, sizeof buffer [0], /* write the buffer to the printer file */
buffer_index, uptr->fileref);
uptr->pos = ftell (uptr->fileref); /* update the file position */
uptr->pos = (t_addr) ftell (uptr->fileref); /* update the file position */
current_line = current_line + 1; /* move the paper one line */
@ -2687,10 +2689,17 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
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));
}
dprintf (lp_dev, DEB_XFER, "Character %s sent to printer\n",
fmt_char (data_byte));
else {
uptr->wait = dlyptr->buffer_load; /* schedule the buffer load delay */
dprintf (lp_dev, DEB_CMD, "Buffer overflow discards character %s\n",
fmt_char (data_byte));
}
}
else { /* otherwise this is a print format command */
@ -2812,7 +2821,7 @@ else if (device_flag_in == FALSE) { /* otherwise if STROBE h
uptr->wait = dlyptr->print /* schedule the print delay */
+ slew_count * dlyptr->advance; /* plus the paper advance delay */
uptr->pos = ftell (uptr->fileref); /* update the file position */
uptr->pos = (t_addr) ftell (uptr->fileref); /* update the file position */
if (slew_count > 0)
dprintf (lp_dev, DEB_CMD, "Printer advanced %u line%s to line %u\n",
@ -2842,15 +2851,10 @@ return SCPE_OK; /* return event service
A new image file may be requested by giving the "-N" switch to the attach
command. If an existing file is specified with "-N", it will be cleared; if
specified without "-P", printer output will be appended to the end of the
specified without "-N", printer output will be appended to the end of the
existing file content. In all cases, the paper is positioned at the top of
the form.
As a special case, a detach (out-of-paper condition) that has been deferred
until printing completes may be cancelled by giving an attach command without
a filename, i.e., ATTACH LP. If a filename is given, but the detach is still
pending, the routine returns a "Command not allowed" error.
Implementation notes:
@ -2867,32 +2871,23 @@ static t_stat lp_attach (UNIT *uptr, CONST char *cptr)
{
t_stat result = SCPE_OK;
if (paper_fault && offline_pending) /* if an out-of-paper condition is deferred */
if (cptr == NULL) /* then if an attach command is given without a filename */
offline_pending = FALSE; /* then cancel the request, leaving the file attached */
result = attach_unit (uptr, cptr); /* attach the specified printer image file */
else /* otherwise a filename was specified */
return SCPE_NOFNC; /* but we can't attach until the previous file detaches */
if (result == SCPE_OK /* if the attach was successful */
&& (sim_switches & SIM_SW_REST) == 0) { /* and we are not being called during a RESTORE command */
set_device_status (ST_NOT_READY, 0); /* then clear not-ready status */
else { /* otherwise no deferral is active */
result = attach_unit (uptr, cptr); /* so attach the specified printer image file */
current_line = 1; /* reset the line counter to the top of the form */
if (result == SCPE_OK /* if the attach was successful */
&& (sim_switches & SIM_SW_REST) == 0) { /* and we are not being called during a RESTORE command */
set_device_status (ST_NOT_READY, 0); /* then clear not-ready status */
if (sim_switches & SWMASK ('N')) /* if a new (empty) file was requested */
uptr->pos = 0; /* then position at the start of the file */
current_line = 1; /* reset the line counter to the top of the form */
else if (fseek (uptr->fileref, 0, SEEK_END) == 0) /* otherwise append by seeking to the end of the file */
uptr->pos = (t_addr) ftell (uptr->fileref); /* and repositioning if the seek succeeded */
if (sim_switches & SWMASK ('N')) /* if a new (empty) file was requested */
uptr->pos = 0; /* then position at the start of the file */
dprintf (lp_dev, DEB_CMD, "Printer paper loaded\n");
else if (fseek (uptr->fileref, 0, SEEK_END) == 0) /* otherwise append by seeking to the end of the file */
uptr->pos = (t_addr) ftell (uptr->fileref); /* and repositioning if the seek succeeded */
dprintf (lp_dev, DEB_CMD, "Printer paper loaded\n");
lp_set_locality (uptr, Online); /* set the printer online */
}
lp_set_locality (uptr, Online); /* set the printer online */
}
paper_fault = FALSE; /* clear any existing paper fault */
@ -2915,9 +2910,13 @@ return result; /* return the result of
an interrupt.
When the printer runs out of paper, it will not go offline until characters
present in the buffer are printed and paper motion stops. In simulation,
entering a DETACH LP command while the printer is busy will defer the file
detach until the current print operation completes.
present in the buffer are printed and paper motion stops. In addition, the
2607 printer waits until the paper reaches the top-of-form position before
going offline.
In simulation, entering a DETACH LP command while the printer is busy will
defer the file detach until print operations reach the top of the next form
(2607) or until the current print operation completes (2613/17/18).
Implementation notes:
@ -2931,24 +2930,36 @@ return result; /* return the result of
2. The DETACH ALL command will fail if any detach routine returns a status
other than SCPE_OK. Because a deferred detach is not fatal, we must
return SCPE_OK, but we still want to print a warning to the user.
3. Because the 2607 only paper faults at TOF, we must explicitly set the
offline_pending flag, as lp_set_alarm may not have been called.
*/
static t_stat lp_detach (UNIT *uptr)
{
const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
if (uptr->flags & UNIT_ATTABLE) /* if we're being called for the printer unit */
if ((uptr->flags & UNIT_ATT) == 0) /* then if the unit is not currently attached */
return SCPE_UNATT; /* then report it */
else if (lp_set_alarm (uptr) /* otherwise if a paper alarm is accepted */
|| (sim_switches & SIM_SW_SHUT)) { /* or this is a shutdown call */
paper_fault = TRUE; /* then set the out-of-paper condition */
else if ((print_props [model].fault_at_eol /* otherwise if the printer faults at the end of any line */
|| current_line == 1) /* or the printer is at the top of the form */
&& lp_set_alarm (uptr) /* and a paper alarm is accepted */
|| (sim_switches & SIM_SW_SHUT)) { /* or this is a shutdown call */
paper_fault = TRUE; /* then set the out-of-paper condition */
dprintf (lp_dev, DEB_CMD, "Printer is out of paper\n");
return detach_unit (uptr); /* and detach the unit */
}
else { /* otherwise the alarm was rejected at this time */
paper_fault = TRUE; /* so set the out-of-paper condition now */
paper_fault = TRUE; /* so set the out-of-paper condition */
offline_pending = TRUE; /* but defer the detach */
dprintf (lp_dev, DEB_CMD, "Paper out request deferred until print completes\n");
cputs ("Command deferred\n"); /* but the actual detach must be deferred */
return SCPE_OK; /* until the buffer prints */
}
@ -3041,6 +3052,9 @@ return SCPE_OK; /* allow the reassignmen
deferred until printing completes, and the routine prints "Command deferred"
to inform the user. Otherwise, the unit is set offline, DEMAND is denied,
and DEV END is asserted to indicate that the printer is not ready.
//
As a special case, a detach (out-of-paper condition) that has been deferred
until printing completes may be cancelled by setting the printer online.
If the printer is being put online, the unit must be attached (i.e., paper
must be loaded), or the command is rejected. If paper is present, the unit
@ -3068,7 +3082,13 @@ if ((uptr->flags & UNIT_ATT) == 0) /* if the printer is det
return SCPE_UNATT; /* then it can't be set online or offline */
else if (value == UNIT_ONLINE) /* otherwise if this is an online request */
lp_set_locality (uptr, Online); /* then set the printer online */
if (paper_fault && offline_pending) { /* then if an out-of-paper condition is deferred */
paper_fault = FALSE; /* then cancel the request */
offline_pending = FALSE; /* leaving the file attached */
}
else /* otherwise it's a normal online request */
lp_set_locality (uptr, Online); /* so set the printer online */
else if (lp_set_locality (uptr, Offline) == FALSE) { /* otherwise if it cannot be set offline now */
cputs ("Command deferred\n"); /* then let the user know */
@ -3242,6 +3262,7 @@ return SCPE_OK;
static t_stat lp_reset (t_bool programmed_clear)
{
const PRINTER_TYPE model = GET_MODEL (xfer_unit.flags); /* the printer model number */
OUTBOUND_SET signals;
uint32 new_status = 0;
t_stat result = SCPE_OK;
@ -3263,7 +3284,7 @@ offline_pending = FALSE; /* cancel any pending of
tape_fault = FALSE; /* clear any tape fault */
paper_fault = ! (xfer_unit.flags & UNIT_ATT); /* and set paper fault if out of paper */
if (paper_fault) /* if a paper fault exists */
if (paper_fault && print_props [model].not_ready) /* if paper is out and the printer reports it separately */
new_status |= ST_NOT_READY; /* then set not-ready status */
if (xfer_unit.flags & UNIT_OFFLINE) { /* if the printer is offline */
@ -3318,9 +3339,13 @@ return NO_SIGNALS; /* no special control ac
static t_bool lp_set_alarm (UNIT *uptr)
{
const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* the printer model number */
if (lp_set_locality (uptr, Offline)) { /* if the printer went offline */
set_device_status (ST_NOT_READY, ST_NOT_READY); /* then set the printer not-ready */
return TRUE; /* and return completion success */
if (print_props [model].not_ready) /* then if the printer reports ready status separately */
set_device_status (ST_NOT_READY, ST_NOT_READY); /* then set the printer not-ready */
return TRUE; /* return completion success */
}
else /* otherwise the offline request is pending */
@ -3367,7 +3392,7 @@ if (printer_state == Offline) { /* if the printer is goi
&& sim_is_active (uptr) == FALSE) { /* and the printer is idle */
uptr->flags |= UNIT_OFFLINE; /* then set the printer offline now */
signals = set_device_status (ST_ONLINE, 0); /* then set the printer offline now */
signals = set_device_status (ST_ONLINE, 0); /* update the printer status */
device_flag_in = TRUE; /* DEMAND denies while the printer is offline */
device_end_in = TRUE; /* DEV END asserts while the printer is offline */
@ -3377,7 +3402,7 @@ if (printer_state == Offline) { /* if the printer is goi
else { /* otherwise the request must wait */
offline_pending = TRUE; /* until the line is printed */
return FALSE; /* that the command is not complete */
return FALSE; /* and the command is not complete */
}
}

View file

@ -1,6 +1,6 @@
SIMH/HP 3000 RELEASE NOTES
==========================
Last update: 2017-01-23
Last update: 2017-04-30
This file documents the release history of the Hewlett-Packard 3000 simulator.
@ -176,6 +176,133 @@ the MPE version used:
=====================
Release 5, 2017-04-30
=====================
This release of the HP 3000 simulator does not add any new features.
--------------------
Implementation Notes
--------------------
- The 2607 line printer simulation now defers an out-of-paper alarm until the
paper reaches the top-of-form position, consistent with the hardware
behavior. The 2613/17/18 printers continue to defer only until the current
line is printed.
----------
Bugs Fixed
----------
1. PROBLEM: Host file system seek errors are not caught.
VERSION: Release 4.
OBSERVATION: The MAC/ICD disc library checks for host file system read or
write errors and returns Uncorrectable Data Error status if an error is
indicated. However, host file system seeks are simply assumed to succeed;
no indication of an error is given if a call fails. A failed seek should
be detected, and a Drive Fault (positioner error) should be returned.
CAUSE: Oversight.
RESOLUTION: Modify "position_sector" (hp_disclib.c) to test the
"sim_fseek" call for error status and to simulate a Drive Fault (AGC error)
if the call fails.
STATUS: Fixed in Release 5.
2. PROBLEM: An interrupted EDIT instruction does not resume properly.
VERSION: Release 4.
OBSERVATION: The EDIT instruction is interruptible between operations. If
an interrupt is detected, two words are pushed onto the stack before the
interrupt handler is called. These words hold the current significance
trigger, loop count, float character, and fill character. This allows the
instruction to resume from the point of suspension. However, the
significance trigger is not preserved properly; it is always clear after an
interrupt.
CAUSE: The significance trigger is preserved in the MSB of the upper byte
of the word pushed onto the stack, but a 16-bit value with the MSB set is
used to set the upper byte. As only the lower 8 bits of the value are used
to set the byte, the MSB is lost.
RESOLUTION: Modify "edit" (hp3000_cpu_cis.c) to use the full 16-bit value
when storing the significance trigger.
STATUS: Fixed in Release 5.
3. PROBLEM: Tracing a tape runaway error prints gibberish in the log file.
VERSION: Release 4.
OBSERVATION: Tracing tape controller commands or command initiations and
completions reports the success or failure of calls to the simulator tape
library, e.g., "write failed with no write ring." A call that fails with
Tape Runaway status, such as a read across a long erase gap, should report
that the operation "failed with tape runaway." Instead, it reports
gibberish.
CAUSE: The descriptive lookup table is missing an entry for the MTSE_LEOT
status that precedes MTSE_RUNAWAY. Attempting to look up the description
for MTSE_RUNAWAY indexes beyond the end of the table.
RESOLUTION: Modify the "status_name" array (hp_tapelib.c) to include
descriptions for all of the possible simulator tape library status returns.
STATUS: Fixed in Release 5.
4. PROBLEM: Commanding a VFU channel that is not punched causes a simulator
stop.
VERSION: Release 4.
OBSERVATION: A format command that specifies a slew to a VFU channel that
is not punched causes a tape fault, and the printer goes offline. However,
the simulator then incorrectly stops with a "System halt" message, rather
than reflecting the "not ready" status back to MPE.
CAUSE: The return value from the "lp_set_alarm" routine is being passed
back as the status of the "lp_service" call. However, the return value is
a Boolean and is TRUE if the printer successfully went offline. When
interpreted as a service status return value, TRUE is seen as STOP_SYSHALT
and causes a system halt simulator stop.
RESOLUTION: Modify "lp_service" (hp3000_lp.c) to return SCPE_OK after the
tape fault alarm is set, allowing the simulation to continue.
STATUS: Fixed in Release 5.
5. PROBLEM: The 2613/17/18 printers do not ignore characters exceeding the
line length.
VERSION: Release 4.
OBSERVATION: When characters are output in excess of the defined line
length, the printer performs an automatic print-and-space operation and
prints the excess characters on the following line. This operation is
correct for the 2607 printer but not for the 2613/17/18 printers, which
ignore output that exceeds the line length.
CAUSE: Excess character handling should be, but is not, model-specific.
RESOLUTION: Modify the "print_props" table (hp3000_lp.c) to add a field
for automatic printing, and modify "lp_service" to check the field to
decide if excess characters are printed or ignored.
STATUS: Fixed in Release 5.
=====================
Release 4, 2017-01-08
=====================

View file

@ -1,6 +1,6 @@
/* hp3000_sys.c: HP 3000 system common interface
Copyright (c) 2016, J. David Bryan
Copyright (c) 2016-2017, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -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.
28-Apr-17 JDB Added void cast to "fprint_instruction" call for left stackop
03-Mar-17 JDB Added an implementation note to the "parse_sym" routine
29-Dec-16 JDB Changed the switch for STA format from -S to -T;
changed the status mnemonic flag from REG_S to REG_T
28-Nov-16 JDB hp_device_conflict accumulates names of active traces only
@ -964,7 +966,7 @@ static t_stat parse_cpu (CONST char *cptr, t_addr address, UNIT *uptr,
static size_t device_size = 0; /* maximum device name size */
static size_t flag_size = 0; /* maximum debug flag name size */
static APC_FLAGS parse_config = apcNone; /* address parser configuration */
static APC_FLAGS parse_config = apcNone; /* address parser configuration */
/* System interface global data structures */
@ -1085,7 +1087,7 @@ const char *sim_stop_messages [] = { /* an array of pointers to the s
/* Local command table.
This table defines commands and command behaviors that are specific to this
simulator. No new commands are defined, but several commands are repurposed
simulator. One new command is defined, and several commands are repurposed
or extended. Specifically:
* EXAMINE, DEPOSIT, IEXAMINE, and IDEPOSIT accept bank/offset form, implied
@ -1100,6 +1102,8 @@ const char *sim_stop_messages [] = { /* an array of pointers to the s
* LOAD and DUMP invoke the CPU cold load/cold dump facility, rather than
loading or dumping binary files.
* POWER adds the ability to fail or restore power to the CPU.
The table is initialized with only those fields that differ from the standard
command table. During one-time simulator initialization, the empty fields
are filled in from the corresponding standard command table entries. This
@ -1370,6 +1374,11 @@ else { /* otherwise display
settings are used, even if the unit is a peripheral. For example,
entering disc sector data as CPU instructions uses the CPU's address and
data radix values, rather than the disc's values.
2. The "cptr" post-increments are logically ANDed with the tests for ' and "
so that the increments are performed only if the tests succeed. The
intent is to skip over the leading ' or " character. The increments
themselves always succeed, so they don't affect the outcome of the tests.
*/
t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
@ -1395,7 +1404,6 @@ else if (sw & SWMASK ('C') || *cptr == '"' && cptr++) /* otherwise if a ch
else /* otherwise */
return SCPE_ARG; /* report that the line cannot be parsed */
else /* otherwise */
return parse_cpu (cptr, addr, uptr, val, sw); /* attempt a mnemonic instruction parse */
}
@ -1607,6 +1615,10 @@ return SCPE_OK; /* return the display re
status word is set, and the request is for a simulation stop, the
left-hand opcode will print as dashes to indicate that it has already
been executed.
2. The status return from "fprint_instruction" is always SCPE_OK for the
stack_ops table, which is fully decoded, so the return value from
printing the left stack opcode is not used.
*/
t_stat fprint_cpu (FILE *ofile, t_value *val, uint32 radix, int32 switches)
@ -1622,9 +1634,9 @@ switch (SUBOP (val [0])) { /* dispatch based on
- strlen (stack_ops [STACKOP_A (val [0])].mnemonic), ofile);
else { /* otherwise */
status = fprint_instruction (ofile, stack_ops, /* print the left operation */
val, STACKOP_A_MASK,
STACKOP_A_SHIFT, radix);
(void) fprint_instruction (ofile, stack_ops, /* print the left operation */
val, STACKOP_A_MASK, /* while discarding the status */
STACKOP_A_SHIFT, radix);
fputc (',', ofile); /* add a separator */
}
@ -3172,7 +3184,8 @@ return -(t_stat) (total_bytes_used / 2 - 1); /* return the (biased) n
if the print consumed a single-word value, or the negative number of extra
words (beyond the first) consumed by printing the instruction is returned.
For example, printing a symbol that resulted in two words being consumed
(from val [0] and val [1]) would return SCPE_OK_2_WORDS (= -1).
(from val [0] and val [1]) would return SCPE_OK_2_WORDS (= -1). If the
supplied instruction is not in the table, SCPE_ARG is returned.
The classification table consists of a set of entries that are indexed by
opcode, followed optionally by a set of entries that are searched linearly.

View file

@ -1,6 +1,6 @@
/* hp_disclib.c: HP MAC/ICD disc controller simulator library
Copyright (c) 2011-2016, J. David Bryan
Copyright (c) 2011-2017, J. David Bryan
Copyright (c) 2004-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -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.
22-Apr-17 JDB A failed sim_fseek call now causes a drive fault
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion from "hp_disclib.h"
03-Aug-16 JDB "fmt_bitset" now allows multiple concurrent calls
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
@ -227,9 +228,9 @@
The drive status field contains only a subset of the status maintained by
drives in hardware. Specifically, the Attention, Read-Only, First Status,
and Seek Check bits are stored in the status field. The other bits (Format
Enabled, Not Ready, and Drive Busy) are set dynamically whenever status is
requested (the Drive Fault bit is not simulated).
Fault, and Seek Check bits are stored in the status field. The other bits
(Format Enabled, Not Ready, and Drive Busy) are set dynamically whenever
status is requested.
Per-drive opcode and phase values allow seeks to be overlapped. For example,
a Seek issued to unit 0 may be followed by a Read issued to unit 1. When the
@ -1279,7 +1280,7 @@ static t_bool start_write (CVPTR cvptr, UNIT *uptr);
static void end_write (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags);
static t_bool position_sector (CVPTR cvptr, UNIT *uptr);
static void next_sector (CVPTR cvptr, UNIT *uptr);
static void io_error (CVPTR cvptr, UNIT *uptr);
static void io_error (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
static void set_completion (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status);
static void clear_controller (CVPTR cvptr, CNTLR_CLEAR clear_type);
static void idle_controller (CVPTR cvptr);
@ -3528,7 +3529,7 @@ count = sim_fread (cvptr->buffer + offset, /* read the sector from
WORDS_PER_SECTOR, uptr->fileref);
if (ferror (uptr->fileref)) { /* if a host file system error occurred */
io_error (cvptr, uptr); /* then report it to the simulation console */
io_error (cvptr, uptr, Uncorrectable_Data_Error); /* then report it to the simulation console */
return FALSE; /* and terminate with Uncorrectable Data Error status */
}
@ -3764,7 +3765,7 @@ sim_fwrite (cvptr->buffer + offset, sizeof (DL_BUFFER), /* write the sector to t
WORDS_PER_SECTOR, uptr->fileref);
if (ferror (uptr->fileref)) /* if a host file system error occurred, then report it */
io_error (cvptr, uptr); /* and terminate with Uncorrectable Data Error status */
io_error (cvptr, uptr, Uncorrectable_Data_Error); /* and terminate with Uncorrectable Data Error status */
else if (cvptr->status != Normal_Completion) /* otherwise if a diagnostic override is present */
end_command (cvptr, uptr, cvptr->status); /* then report the indicated status */
@ -3828,9 +3829,12 @@ return;
If the addresses are valid, the drive is checked to ensure that it is ready
for positioning. If it is, the file is positioned to a byte offset in the
image file that is calculated from the CHS address. The data phase is set up
to begin the data transfer, and the routine returns TRUE to indicate that the
file position is set.
image file that is calculated from the CHS address. If positioning succeeds,
the data phase is set up to begin the data transfer, and the routine returns
TRUE to indicate that the file position is set. If positioning fails with a
host file system error, it is reported to the simulation console, and the
routine returns FALSE to indicate that an AGC (drive positioner) fault
occurred.
Implementation notes:
@ -3900,17 +3904,24 @@ else if (uptr->flags & UNIT_UNLOAD) /* otherwise if the driv
else { /* otherwise we are ready to move the heads */
set_file_pos (cvptr, uptr, model); /* so calculate the new position */
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set the image file position */
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the image file position; if it failed */
io_error (cvptr, uptr, Status_2_Error); /* then report it to the simulation console */
uptr->PHASE = Data_Phase; /* set up the data transfer phase */
dl_load_unload (cvptr, uptr, FALSE); /* unload the heads */
uptr->STATUS |= S2_FAULT; /* and set Fault status */
}
if (cvptr->device->flags & DEV_REALTIME) /* if the real time mode is enabled */
uptr->wait = cvptr->dlyptr->data_xfer /* then base the delay on the sector preamble size */
* cmd_props [uptr->OPCODE].preamble_size;
else /* otherwise */
uptr->wait = cvptr->dlyptr->data_xfer; /* start the transfer with a nominal delay */
else { /* otherwise the seek succeeded */
uptr->PHASE = Data_Phase; /* so set up the data transfer phase */
return TRUE; /* report that positioning was accomplished */
if (cvptr->device->flags & DEV_REALTIME) /* if the real time mode is enabled */
uptr->wait = cvptr->dlyptr->data_xfer /* then base the delay on the sector preamble size */
* cmd_props [uptr->OPCODE].preamble_size;
else /* otherwise */
uptr->wait = cvptr->dlyptr->data_xfer; /* start the transfer with a nominal delay */
return TRUE; /* report that positioning was accomplished */
}
}
return FALSE; /* positioning failed or was deferred */
@ -4085,22 +4096,24 @@ return TRUE; /* the seek is underway
}
/* Report an I/O error.
/* Report a stream I/O error.
Errors indicated by the host file system are printed on the simulation
console, and the current command is terminated with an Uncorrectable Data
Error indication from the controller. The target OS will retry the
operation; if it continues to fail, the OS will handle it appropriately.
console, and the current command is terminated with the supplied status
indication. The target OS will respond to the status return appropriately.
*/
static void io_error (CVPTR cvptr, UNIT *uptr)
static void io_error (CVPTR cvptr, UNIT *uptr, CNTLR_STATUS status)
{
cprintf ("%s simulator disc library I/O error: %s\n", /* report the error to the console */
sim_name, strerror (errno));
dpprintf (cvptr->device, cvptr->device->dctrl, "Host system stream I/O call failed: %s\n",
strerror (errno));
clearerr (uptr->fileref); /* clear the error */
end_command (cvptr, uptr, Uncorrectable_Data_Error); /* terminate the command with a bad data error */
end_command (cvptr, uptr, status); /* terminate the command with the supplied status */
return;
}
@ -4174,9 +4187,9 @@ return;
Implementation notes:
1. The Attention, Read-Only, First Status, and Seek Check bits are stored
in the unit status field. The other status bits are determined
dynamically (the Drive Fault bit is not simulated).
1. The Attention, Read-Only, First Status, Fault, and Seek Check bits are
stored in the unit status field. The other status bits are determined
dynamically.
2. The Drive Busy bit is set if the unit is in the seek phase. In hardware,
this bit indicates that the heads are not positioned over a track, i.e.,

View file

@ -1,4 +1,4 @@
/* hp_disclib.h: HP MAC/ICD disc controller simulator library definitions
/* hp_disclib.h: HP MAC/ICD disc controller simulator library declarations
Copyright (c) 2011-2016, J. David Bryan
Copyright (c) 2004-2011, Robert M. Supnik

View file

@ -1,6 +1,6 @@
/* hp_tapelib.c: HP magnetic tape controller simulator library
Copyright (c) 2013-2016, J. David Bryan
Copyright (c) 2013-2017, J. David Bryan
Copyright (c) 2004-2011, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a copy
@ -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.
22-Apr-17 JDB Corrected status_name array element count
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion from "hp_tapelib.h"
01-Jul-16 JDB Changed tl_attach to reset the event delay times pointer
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
@ -801,6 +802,7 @@ static const char *status_name [] = { /* indexed by MTSE value */
"terminated with end of medium seen", /* MTSE_EOM */
"succeeded with data error", /* MTSE_RECE */
"failed with no write ring", /* MTSE_WRP */
"failed with logical end of tape", /* MTSE_LEOT */
"failed with tape runaway" /* MTSE_RUNAWAY */
};

View file

@ -1,4 +1,4 @@
/* hp_tapelib.h: HP magnetic tape controller simulator library definitions
/* hp_tapelib.h: HP magnetic tape controller simulator library declarations
Copyright (c) 2013-2016, J. David Bryan
Copyright (c) 2004-2011, Robert M. Supnik

Binary file not shown.