From 07f99bb8c3afc490112eab17c441f0f09a3a42e0 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 5 Jul 2016 22:09:21 -0700 Subject: [PATCH] HP3000, HP2100: Updated simulators from Dave Bryan - This release of the HP 3000 simulator adds the following device simulation: - 30209A Line Printer Controller with One 2607/13/17/18 Line Printer The simulation supports the use of custom VFU tape images, as well as the built-in HP-standard VFU tape. The simulated device name is "LP". The full set of configurable options is detailed in a new section of the HP 3000 Simulator User's Guide. In addition, the preconfigured MPE-V/R disc image has been updated to add the following features: - The MPE cold load command files attach the line printer to the "lp.txt" output file and specify the "-n" option to clear the file before use. - Preinstalled User-Defined Commands (UDCs) provide access to the COBOL 74 compiler with the MPE-V/E :COBOLII, :COBOLIIPREP, and :COBOLIIGO commands, and to the COBOL 85 compiler with :COBOLIIX, :COBOLIIXPREP, and :COBOLIIXGO. However, see the implementation note below. -------------------- Implementation Notes -------------------- - MPE requires a line printer, so it is recommended that the MPE startup simulator command file include an ATTACH LP command to load paper into the printer before cold loading. If the printer is not attached, it will appear to MPE to be out of paper. - The line printer terminates each print line with an HP-standard CR/LF pair. If the output file is to be retained as a text file on a Unix system, removal of the carriage returns, e.g., via the "dos2unix" utility, may be desirable. - The simulator currently does not provide the HP 32234A COBOL II firmware instructions, so programs generated by the COBOLII compiler will abort at run time with an "ILLEGAL INSTRUCTION" error. Programs generated by the COBOL compiler do not use these instructions and therefore are not affected. ---------- Bugs Fixed ---------- 1. PROBLEM: The effective address of a byte pointer with a negative index is calculated incorrectly. VERSION: Release 1 OBSERVATION: Defining a :WELCOME message in MPE appears to work, but when the next logon attempts to print the message, an infinite number of CRLFs are printed instead. CAUSE: The welcome message is stored in an extra data segment. The format for each message line is a line length stored in the lower byte of the word preceding the message string. The code defines BYTE POINTER NEXTLINE and points NEXTLINE to the first message character. The line length is set with NEXTLINE(-1) := IOCOUNT. This generates a LOAD ; LDXN 1 ; STB ,I,X sequence. In the "cpu_ea" routine, the indexing adds the X register value (-1) to the byte pointer (NEXTLINE). This causes an overflow that is not masked to 16 bits. For a word access, this displacement is added to the base register and then masked to 16 bits, which gives the correct value. However, for byte accesses, the displacement is divided by 2 and then added, and the sum is masked. Dividing by 2 shifts the overflow bit into the MSB, causing the addition result to be off by 32K. The STB goes to the wrong location, the original zero in the length byte location is retained, and when the welcome message is printed, a zero-length line is printed, and the byte pointer is incremented by zero, so the null line is printed forever. RESOLUTION: Modify "cpu_ea" (hp3000_cpu.c) to mask indexed displacements to 16 bits after adding the X register value. STATUS: Fixed in Release 2. 2. PROBLEM: An SMSK instruction may clear the interrupt mask flip-flop of a device that specifies that it is should be "always enabled." VERSION: Release 1 OBSERVATION: If the TOS word is zero, an SMSK instruction will clear the interrupt mask flip-flop of a device whose mask jumper is set to "E" (always enabled). CAUSE: In response to a DSETMASK signal, device interfaces set their interrupt mask flip-flops by "anding" the incoming data word with the interrupt mask jumper setting. The jumper setting value for "always enabled" is %177777, which sets the mask flip-flop in all cases, except when the data word is zero. RESOLUTION: Modify hp3000_atc.c, hp3000_ds.c, and hp3000_ms.c to set their mask flip-flops unconditionally if the jumper setting is "E". STATUS: Fixed in Release 2. 3. PROBLEM: The "SET INTMASK=" command sets the wrong bit in the device interface's interrupt mask jumper setting. VERSION: Release 1 OBSERVATION: The interrupt mask jumper on a device interface is set by specifying the mask bit number in a "SET INTMASK=" command. This sets a bit in the device's interrupt mask jumper word corresponding to the bit number requested. However, the bit numbering is incorrect; setting the jumper for bit 15, for example, sets bit 0 of the jumper word. Therefore, the interface's mask flip-flop is not set as expected when an SMSK instruction is executed. CAUSE: The bit numbers were counted from the wrong end of the word. RESOLUTION: Modify "hp_set_dib" and "hp_show_dib" (hp3000_sys.c) to number the bits from the MSB instead of the LSB. STATUS: Fixed in Release 2. 4. PROBLEM: The Multiplexer Channel is not generating the ACKSR signal correctly. VERSION: Release 1 OBSERVATION: The line printer controller hangs when an SIO chained write is performed. The first programmed write completes normally, but the second does not start. The channel is waiting for a service request that does not occur. CAUSE: The service request from the last write of the first block transfer is being cleared by an ACKSR generated by the Multiplexer Channel when it performs the IOCW fetch in State A for the second write request. The channel should omit this ACKSR when the previous I/O order was a chained read or write. However, the simulator is testing the order just fetched (Write) instead of the order that has just completed (Write Chained). RESOLUTION: Modify "mpx_service" (hp3000_mpx.c) to test the correct I/O order in State A. STATUS: Fixed in Release 2. --- HP2100/hp2100_cpu6.c | 11 +- HP3000/hp3000_atc.c | 343 +-- HP3000/hp3000_clk.c | 128 +- HP3000/hp3000_cpu.c | 37 +- HP3000/hp3000_cpu.h | 345 +-- HP3000/hp3000_cpu_base.c | 7 +- HP3000/hp3000_cpu_fp.c | 11 +- HP3000/hp3000_cpu_fp.h | 9 +- HP3000/hp3000_cpu_ims.h | 13 +- HP3000/hp3000_defs.h | 186 +- HP3000/hp3000_diag.txt | 481 +++- HP3000/hp3000_ds.c | 74 +- HP3000/hp3000_io.h | 28 +- HP3000/hp3000_iop.c | 32 +- HP3000/hp3000_lp.c | 3671 ++++++++++++++++++++++++++ HP3000/hp3000_mpx.c | 253 +- HP3000/hp3000_ms.c | 134 +- HP3000/hp3000_release.txt | 153 +- HP3000/hp3000_scmb.c | 211 +- HP3000/hp3000_sel.c | 93 +- HP3000/hp3000_sys.c | 87 +- HP3000/hp_disclib.c | 299 ++- HP3000/hp_disclib.h | 153 +- HP3000/hp_tapelib.c | 129 +- HP3000/hp_tapelib.h | 93 +- Visual Studio Projects/HP3000.vcproj | 4 + descrip.mms | 1 + doc/hp3000_doc.doc | Bin 299008 -> 354304 bytes makefile | 2 +- 29 files changed, 5719 insertions(+), 1269 deletions(-) create mode 100644 HP3000/hp3000_lp.c diff --git a/HP2100/hp2100_cpu6.c b/HP2100/hp2100_cpu6.c index 1f056046..a26d66a7 100644 --- a/HP2100/hp2100_cpu6.c +++ b/HP2100/hp2100_cpu6.c @@ -1,6 +1,6 @@ /* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions - Copyright (c) 2006-2014, J. David Bryan + Copyright (c) 2006-2016, 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"), @@ -25,6 +25,7 @@ CPU6 RTE-6/VM OS instructions + 17-May-16 JDB Set local variable instead of call parameter for .SIP test 24-Dec-14 JDB Added casts for explicit downward conversions 18-Mar-13 JDB Use MP abort handler declaration in hp2100_cpu.h 09-May-12 JDB Separated assignments from conditional expressions @@ -380,7 +381,7 @@ t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap) t_stat reason = SCPE_OK; OPS op; OP_PAT pattern; -uint32 entry, count, cp, sa, da, i, ma, eqta; +uint32 entry, count, cp, sa, da, i, ma, eqta, irq; uint16 vectors, save_area, priv_fence, eoreg, eqt, key; char test[6], target[6]; jmp_buf mp_handler; @@ -644,16 +645,16 @@ switch (entry) { /* decode IR<3:0> */ case 010: /* .SIP 105350 (OP_N) */ reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ - intrq = calc_int (); /* check for interrupt requests */ + irq = calc_int (); /* check for interrupt requests */ reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ - if (intrq) /* was interrupt pending? */ + if (irq) /* was interrupt pending? */ PC = (PC + 1) & VAMASK; /* P+1 return for pending IRQ */ /* P+0 return for no pending IRQ */ if (debug_print) /* debugging? */ fprintf (sim_deb, /* print return registers */ ", CIR = %02o, return = P+%d", - intrq, PC - (err_PC + 1)); + irq, PC - (err_PC + 1)); break; case 011: /* .YLD 105351 (OP_C) */ diff --git a/HP3000/hp3000_atc.c b/HP3000/hp3000_atc.c index c470f1d7..d864405d 100644 --- a/HP3000/hp3000_atc.c +++ b/HP3000/hp3000_atc.c @@ -26,7 +26,11 @@ ATCD,ATCC HP 30032B Asynchronous Terminal Controller + 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 13-May-16 JDB Modified for revised SCP API function parameter types + 21-Mar-16 JDB Changed uint16 types to HP_WORD 26-Aug-15 JDB First release version 31-Jul-15 JDB Passes the terminal control diagnostic (D438A) 11-Aug-14 JDB Passes the terminal data diagnostic (D427A) @@ -315,7 +319,7 @@ #define NUL '\000' /* null */ #define ENQ '\005' /* enquire */ #define ACK '\006' /* acknowledge */ -#define ASCII_MASK 000177 /* 7-bit ASCII character set mask */ +#define ASCII_MASK 000177u /* 7-bit ASCII character set mask */ #define GEN_ACK (TMXR_VALID | SCPE_KFLAG | ACK) /* a generated ACK character */ @@ -330,14 +334,14 @@ /* Debug flags */ -#define DEB_CSRW (1 << 0) /* trace command initiations and completions */ -#define DEB_XFER (1 << 1) /* trace data receptions and transmissions */ -#define DEB_IOB (1 << 2) /* trace I/O bus signals and data words */ -#define DEB_SERV (1 << 3) /* trace channel service scheduling calls */ -#define DEB_PSERV (1 << 4) /* trace poll service scheduling calls */ +#define DEB_CSRW (1u << 0) /* trace command initiations and completions */ +#define DEB_XFER (1u << 1) /* trace data receptions and transmissions */ +#define DEB_IOB (1u << 2) /* trace I/O bus signals and data words */ +#define DEB_SERV (1u << 3) /* trace channel service scheduling calls */ +#define DEB_PSERV (1u << 4) /* trace poll service scheduling calls */ -/* Per-unit state */ +/* Common per-unit multiplexer channel state variables */ #define recv_time u3 /* realistic receive time in event ticks */ #define send_time u4 /* realistic send time in event ticks */ @@ -349,8 +353,8 @@ #define DEV_DIAG_SHIFT (DEV_V_UF + 0) /* diagnostic loopback */ #define DEV_REALTIME_SHIFT (DEV_V_UF + 1) /* timing mode is realistic */ -#define DEV_DIAG (1 << DEV_DIAG_SHIFT) /* diagnostic mode flag */ -#define DEV_REALTIME (1 << DEV_REALTIME_SHIFT) /* realistic timing flag */ +#define DEV_DIAG (1u << DEV_DIAG_SHIFT) /* diagnostic mode flag */ +#define DEV_REALTIME (1u << DEV_REALTIME_SHIFT) /* realistic timing flag */ /* Unit flags */ @@ -359,9 +363,9 @@ #define UNIT_LOCALACK_SHIFT (TTUF_V_UF + 1) /* local ACK mode */ #define UNIT_MODEM_SHIFT (TTUF_V_UF + 2) /* modem control */ -#define UNIT_CAPSLOCK (1 << UNIT_CAPSLOCK_SHIFT) /* caps lock is down flag */ -#define UNIT_LOCALACK (1 << UNIT_LOCALACK_SHIFT) /* ENQ/ACK mode is local flag */ -#define UNIT_MODEM (1 << UNIT_MODEM_SHIFT) /* channel connects to a data set flag */ +#define UNIT_CAPSLOCK (1u << UNIT_CAPSLOCK_SHIFT) /* caps lock is down flag */ +#define UNIT_LOCALACK (1u << UNIT_LOCALACK_SHIFT) /* ENQ/ACK mode is local flag */ +#define UNIT_MODEM (1u << UNIT_MODEM_SHIFT) /* channel connects to a data set flag */ /* Unit references */ @@ -388,11 +392,11 @@ typedef enum { +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define DCN_MR 0100000 /* (M) master reset */ -#define DCN_IRQ_RESET 0040000 /* (R) interrupt request reset */ -#define DCN_CHAN_MASK 0037000 /* channel number mask */ -#define DCN_ENABLE 0000002 /* (E) enable store of preceding data or parameter word */ -#define DCN_ACKN 0000001 /* (A) acknowledge interrupt */ +#define DCN_MR 0100000u /* (M) master reset */ +#define DCN_IRQ_RESET 0040000u /* (R) interrupt request reset */ +#define DCN_CHAN_MASK 0037000u /* channel number mask */ +#define DCN_ENABLE 0000002u /* (E) enable store of preceding data or parameter word */ +#define DCN_ACKN 0000001u /* (A) acknowledge interrupt */ #define DCN_CHAN_SHIFT 9 /* channel number alignment shift */ @@ -429,13 +433,13 @@ static const BITSET_FORMAT tdi_control_format = /* names, offset, direct +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define DST_DIO_OK 0040000 /* (D) direct I/O OK to use */ -#define DST_IRQ 0020000 /* (I) interrupt requested */ -#define DST_COMPLETE 0004000 /* (C) operation is complete and channel is ready to interrupt */ -#define DST_SEND_IRQ 0002000 /* (R) interrupt request is for character sent */ -#define DST_CHAR_LOST 0001000 /* (L) character was lost */ -#define DST_BREAK 0000400 /* (B) break occurred */ -#define DST_DIAGNOSE 0000000 /* status is from an auxiliary channel (not used on ATC) */ +#define DST_DIO_OK 0040000u /* (D) direct I/O OK to use */ +#define DST_IRQ 0020000u /* (I) interrupt requested */ +#define DST_COMPLETE 0004000u /* (C) operation is complete and channel is ready to interrupt */ +#define DST_SEND_IRQ 0002000u /* (R) interrupt request is for character sent */ +#define DST_CHAR_LOST 0001000u /* (L) character was lost */ +#define DST_BREAK 0000400u /* (B) break occurred */ +#define DST_DIAGNOSE 0000000u /* status is from an auxiliary channel (not used on ATC) */ #define DST_CHAN(n) 0 /* position channel number for status (not used on ATC) */ @@ -480,14 +484,14 @@ static const BITSET_FORMAT tdi_status_format = /* names, offset, direct the number of stop bits from the receive parameter word. */ -#define DPI_IS_PARAM 0100000 /* value is a parameter (always set) */ -#define DPI_IS_SEND 0040000 /* (R) value is a send parameter */ -#define DPI_ENABLE_IRQ 0020000 /* (I) enable interrupt requests */ -#define DPI_ENABLE_PARITY 0010000 /* (E) enable parity for send */ -#define DPI_ENABLE_ECHO 0010000 /* (E) enable echo for receive */ -#define DPI_DIAGNOSE 0004000 /* (D) connect to the auxiliary channels */ -#define DPI_SIZE_MASK 0003400 /* character size mask */ -#define DPI_RATE_MASK 0000377 /* baud rate mask */ +#define DPI_IS_PARAM 0100000u /* value is a parameter (always set) */ +#define DPI_IS_SEND 0040000u /* (R) value is a send parameter */ +#define DPI_ENABLE_IRQ 0020000u /* (I) enable interrupt requests */ +#define DPI_ENABLE_PARITY 0010000u /* (E) enable parity for send */ +#define DPI_ENABLE_ECHO 0010000u /* (E) enable echo for receive */ +#define DPI_DIAGNOSE 0004000u /* (D) connect to the auxiliary channels */ +#define DPI_SIZE_MASK 0003400u /* character size mask */ +#define DPI_RATE_MASK 0000377u /* baud rate mask */ #define DPI_CHAR_CONFIG (DPI_SIZE_MASK | DPI_RATE_MASK) /* character configuration data */ @@ -499,7 +503,7 @@ static const BITSET_FORMAT tdi_status_format = /* names, offset, direct #define BAUD_RATE(p) ((28800 / (DPI_BAUD_RATE (p) + 1) + 1) / 2) -#define PAD_BITS(c) (~((1 << bits_per_char [DPI_CHAR_SIZE (c)] - 2) - 1)) +#define PAD_BITS(c) (~((1u << bits_per_char [DPI_CHAR_SIZE (c)] - 2) - 1)) static const uint32 bits_per_char [8] = { /* bits per character, indexed by DPI_CHAR_SIZE encoding */ @@ -525,10 +529,10 @@ static const BITSET_FORMAT tdi_parameter_format = /* names, offset, direct +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define DDS_IS_SEND 0040000 /* value is a send data word (always set) */ -#define DDS_SYNC 0004000 /* (S) sync */ -#define DDS_DATA_MASK 0003777 /* data value mask */ -#define DDS_PARITY 0000200 /* data parity bit */ +#define DDS_IS_SEND 0040000u /* value is a send data word (always set) */ +#define DDS_SYNC 0004000u /* (S) sync */ +#define DDS_DATA_MASK 0003777u /* data value mask */ +#define DDS_PARITY 0000200u /* data parity bit */ #define DDS_MARK (DDS_SYNC | DDS_DATA_MASK) /* all-mark character */ @@ -554,9 +558,9 @@ static const BITSET_FORMAT tdi_output_data_format = /* names, offset, direct +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define DDR_CHAN_MASK 0174000 /* channel number mask */ -#define DDR_PARITY 0002000 /* (P) computed parity bit */ -#define DDR_DATA_MASK 0001777 /* data value mask */ +#define DDR_CHAN_MASK 0174000u /* channel number mask */ +#define DDR_PARITY 0002000u /* (P) computed parity bit */ +#define DDR_DATA_MASK 0001777u /* data value mask */ #define DDR_CHAN_SHIFT 11 /* channel number alignment shift */ #define DDR_DATA_SHIFT 0 /* data alignment shift */ @@ -584,24 +588,24 @@ static const BITSET_FORMAT tdi_input_data_format = /* names, offset, direct +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CCN_MR 0100000 /* (M) master reset */ -#define CCN_IRQ_RESET 0040000 /* (R) interrupt request reset */ -#define CCN_SCAN 0020000 /* (S) scan enable */ -#define CCN_UPDATE 0010000 /* (U) update enable */ -#define CCN_CHAN_MASK 0007400 /* channel number mask */ -#define CCN_ECX_MASK 0000300 /* control output enable mask */ -#define CCN_EC2 0000200 /* (W) C2 output enable */ -#define CCN_EC1 0000100 /* (X) C1 output enable */ -#define CCN_CX_MASK 0000060 /* output mask */ -#define CCN_C2 0000040 /* (Q) C2 output [RTS] */ -#define CCN_C1 0000020 /* (T) C1 output [DTR] */ -#define CCN_STAT_MASK 0000017 /* status RAM mask */ -#define CCN_ESX_MASK 0000014 /* status interrupt enable mask */ -#define CCN_ES2 0000010 /* (Y) S2 interrupt enable */ -#define CCN_ES1 0000004 /* (Z) S1 interrupt enable */ -#define CCN_SX_MASK 0000003 /* status mask */ -#define CCN_S2 0000002 /* (C) S2 status [DCD]*/ -#define CCN_S1 0000001 /* (D) S1 status [DSR] */ +#define CCN_MR 0100000u /* (M) master reset */ +#define CCN_IRQ_RESET 0040000u /* (R) interrupt request reset */ +#define CCN_SCAN 0020000u /* (S) scan enable */ +#define CCN_UPDATE 0010000u /* (U) update enable */ +#define CCN_CHAN_MASK 0007400u /* channel number mask */ +#define CCN_ECX_MASK 0000300u /* control output enable mask */ +#define CCN_EC2 0000200u /* (W) C2 output enable */ +#define CCN_EC1 0000100u /* (X) C1 output enable */ +#define CCN_CX_MASK 0000060u /* output mask */ +#define CCN_C2 0000040u /* (Q) C2 output [RTS] */ +#define CCN_C1 0000020u /* (T) C1 output [DTR] */ +#define CCN_STAT_MASK 0000017u /* status RAM mask */ +#define CCN_ESX_MASK 0000014u /* status interrupt enable mask */ +#define CCN_ES2 0000010u /* (Y) S2 interrupt enable */ +#define CCN_ES1 0000004u /* (Z) S1 interrupt enable */ +#define CCN_SX_MASK 0000003u /* status mask */ +#define CCN_S2 0000002u /* (C) S2 status [DCD]*/ +#define CCN_S1 0000001u /* (D) S1 status [DSR] */ #define CCN_CHAN_SHIFT 8 /* channel number alignment shift */ #define CCN_CX_SHIFT 4 /* control alignment shift */ @@ -644,19 +648,19 @@ static const BITSET_FORMAT tci_control_format = /* names, offset, direct +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CST_DIO_OK 0040000 /* direct I/O OK to use (always set) */ -#define CST_IRQ 0020000 /* (I) interrupt request */ -#define CST_ON 0010000 /* (always set) */ -#define CST_CHAN_MASK 0007400 /* channel number mask */ -#define CST_IX_MASK 0000060 /* status interrupt mask */ -#define CST_I2 0000040 /* (J) S2 interrupt */ -#define CST_I1 0000020 /* (K) S1 interrupt */ -#define CST_ESX_MASK 0000014 /* status interrupt enable mask */ -#define CST_ES2 0000010 /* (Y) S2 interrupt enable */ -#define CST_ES1 0000004 /* (Z) S1 interrupt enable */ -#define CST_SX_MASK 0000003 /* status mask */ -#define CST_S2 0000002 /* (C) S2 status [DCD] */ -#define CST_S1 0000001 /* (D) S1 status [DSR] */ +#define CST_DIO_OK 0040000u /* direct I/O OK to use (always set) */ +#define CST_IRQ 0020000u /* (I) interrupt request */ +#define CST_ON 0010000u /* (always set) */ +#define CST_CHAN_MASK 0007400u /* channel number mask */ +#define CST_IX_MASK 0000060u /* status interrupt mask */ +#define CST_I2 0000040u /* (J) S2 interrupt */ +#define CST_I1 0000020u /* (K) S1 interrupt */ +#define CST_ESX_MASK 0000014u /* status interrupt enable mask */ +#define CST_ES2 0000010u /* (Y) S2 interrupt enable */ +#define CST_ES1 0000004u /* (Z) S1 interrupt enable */ +#define CST_SX_MASK 0000003u /* status mask */ +#define CST_S2 0000002u /* (C) S2 status [DCD] */ +#define CST_S1 0000001u /* (D) S1 status [DSR] */ #define CST_CHAN_SHIFT 8 /* channel number alignment shift */ #define CST_IX_SHIFT 4 /* status interrupt alignment shift */ @@ -712,12 +716,12 @@ t_bool atc_is_polling = TRUE; /* TRUE if the ATC is polling fo /* TDI interface state */ -static uint16 tdi_control_word = 0; /* control word */ -static uint16 tdi_status_word = 0; /* status word */ -static uint16 tdi_read_word = 0; /* read word */ -static uint16 tdi_write_word = 0; /* write word */ +static HP_WORD tdi_control_word = 0; /* control word */ +static HP_WORD tdi_status_word = 0; /* status word */ +static HP_WORD tdi_read_word = 0; /* read word */ +static HP_WORD tdi_write_word = 0; /* write word */ -static FLIP_FLOP tdi_interrupt_mask = CLEAR; /* interrupt mask flip-flop */ +static FLIP_FLOP tdi_interrupt_mask = SET; /* interrupt mask flip-flop */ static FLIP_FLOP tdi_data_flag = CLEAR; /* data flag */ static int32 fast_data_time = FAST_IO_TIME; /* fast receive/send time */ @@ -725,22 +729,22 @@ static int32 fast_data_time = FAST_IO_TIME; /* fast receive/send time */ /* TDI per-channel state */ -static uint16 recv_status [RECV_CHAN_COUNT]; /* receive status words */ -static uint16 recv_param [RECV_CHAN_COUNT]; /* receive parameter words */ -static uint16 recv_buffer [RECV_CHAN_COUNT]; /* receive character buffers */ +static HP_WORD recv_status [RECV_CHAN_COUNT]; /* receive status words */ +static HP_WORD recv_param [RECV_CHAN_COUNT]; /* receive parameter words */ +static HP_WORD recv_buffer [RECV_CHAN_COUNT]; /* receive character buffers */ -static uint16 send_status [SEND_CHAN_COUNT]; /* send status words */ -static uint16 send_param [SEND_CHAN_COUNT]; /* send parameter words */ -static uint16 send_buffer [SEND_CHAN_COUNT]; /* send character buffers */ +static HP_WORD send_status [SEND_CHAN_COUNT]; /* send status words */ +static HP_WORD send_param [SEND_CHAN_COUNT]; /* send parameter words */ +static HP_WORD send_buffer [SEND_CHAN_COUNT]; /* send character buffers */ /* TCI interface state */ -static uint16 tci_control_word = 0; /* control word */ -static uint16 tci_status_word = 0; /* status word */ -static uint32 tci_cntr = 0; /* channel counter */ +static HP_WORD tci_control_word = 0; /* control word */ +static HP_WORD tci_status_word = 0; /* status word */ +static uint32 tci_cntr = 0; /* channel counter */ -static FLIP_FLOP tci_interrupt_mask = CLEAR; /* interrupt mask flip-flop */ +static FLIP_FLOP tci_interrupt_mask = SET; /* interrupt mask flip-flop */ static FLIP_FLOP tci_scan = CLEAR; /* scanning enabled flip-flop */ @@ -773,15 +777,15 @@ static void tdi_set_interrupt (void); static void tdi_master_reset (void); static void tci_master_reset (void); -static t_stat line_service (UNIT *uptr); -static t_stat poll_service (UNIT *uptr); -static t_stat activate_unit (UNIT *uptr, ACTIVATOR reason); -static uint32 service_time (uint16 control, ACTIVATOR reason); -static void store (uint16 control, uint16 data); -static void receive (int32 channel, int32 data, t_bool loopback); -static void diagnose (uint16 control, int32 data); -static void scan_channels (int32 channel); -static uint16 scan_status (void); +static t_stat line_service (UNIT *uptr); +static t_stat poll_service (UNIT *uptr); +static t_stat activate_unit (UNIT *uptr, ACTIVATOR reason); +static uint32 service_time (HP_WORD control, ACTIVATOR reason); +static void store (HP_WORD control, HP_WORD data); +static void receive (int32 channel, int32 data, t_bool loopback); +static void diagnose (HP_WORD control, int32 data); +static void scan_channels (int32 channel); +static HP_WORD scan_status (void); /* ATC SCP data structures */ @@ -910,8 +914,8 @@ static UNIT atcc_unit [] = { /* a dummy unit to satisfy SCP r Implementation notes: 1. The TCI control and status line register definitions use the VM-defined - FBDATA macro. This macro defines a bit slice longitudinally through an - array. + FBDATA macro. This macro defines a flag that is replicated in the same + bit position in each element of an array. */ static REG atcd_reg [] = { @@ -931,31 +935,31 @@ 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 }, + { SRDATA (DIB, atcd_dib, REG_HRO) }, { NULL } }; static REG atcc_reg [] = { -/* Macro Name Location Width Offset Depth Flags */ -/* ------ ------ ------------------- ----- ------ ---------- ------- */ - { ORDATA (CNTL, tci_control_word, 16), REG_FIT }, - { ORDATA (STAT, tci_status_word, 16), REG_FIT }, - { DRDATA (CNTR, tci_cntr, 4) }, - { FLDATA (SCAN, tci_scan, 0) }, - { FLDATA (MASK, tci_interrupt_mask, 0) }, +/* Macro Name Location Width Offset Depth Flags */ +/* ------ ------ ------------------- ----- ------ ---------- ------- */ + { ORDATA (CNTL, tci_control_word, 16), REG_FIT }, + { ORDATA (STAT, tci_status_word, 16), REG_FIT }, + { DRDATA (CNTR, tci_cntr, 4) }, + { FLDATA (SCAN, tci_scan, 0) }, + { FLDATA (MASK, tci_interrupt_mask, 0) }, - { FBDATA (C2, cntl_status, 5, TERM_COUNT) }, - { FBDATA (C1, cntl_status, 4, TERM_COUNT) }, - { FBDATA (S2, cntl_status, 1, TERM_COUNT) }, - { FBDATA (S1, cntl_status, 0, TERM_COUNT) }, + { FBDATA (C2, cntl_status, 5, TERM_COUNT, PV_RZRO) }, + { FBDATA (C1, cntl_status, 4, TERM_COUNT, PV_RZRO) }, + { FBDATA (S2, cntl_status, 1, TERM_COUNT, PV_RZRO) }, + { FBDATA (S1, cntl_status, 0, TERM_COUNT, PV_RZRO) }, - { FBDATA (ES2, cntl_param, 3, TERM_COUNT) }, - { FBDATA (ES1, cntl_param, 2, TERM_COUNT) }, - { FBDATA (MS2, cntl_param, 1, TERM_COUNT) }, - { FBDATA (MS1, cntl_param, 0, TERM_COUNT) }, + { FBDATA (ES2, cntl_param, 3, TERM_COUNT, PV_RZRO) }, + { FBDATA (ES1, cntl_param, 2, TERM_COUNT, PV_RZRO) }, + { FBDATA (MS2, cntl_param, 1, TERM_COUNT, PV_RZRO) }, + { FBDATA (MS1, cntl_param, 0, TERM_COUNT, PV_RZRO) }, - { SRDATA (DIB, atcc_dib), REG_HRO }, + { SRDATA (DIB, atcc_dib, REG_HRO) }, { NULL } }; @@ -1167,11 +1171,11 @@ DEVICE atcc_dev = { the request. */ -static SIGNALS_DATA atcd_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA atcd_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (atcd_dev, DEB_IOB, "Received data %06o with signals %s\n", @@ -1184,7 +1188,7 @@ while (working_set) { /* while signals remain case DCONTSTB: dprintf (atcd_dev, DEB_CSRW, (inbound_value & DCN_ENABLE - ? "Control is %s | channel %d\n" + ? "Control is %s | channel %u\n" : "Control is %s\n"), fmt_bitset (inbound_value, tdi_control_format), DCN_CHAN (inbound_value)); @@ -1221,7 +1225,7 @@ while (working_set) { /* while signals remain else /* to indicate */ tdi_status_word &= ~DST_COMPLETE; /* whether or not a channel has completed */ - outbound_value = (uint16) tdi_status_word; /* return the status word */ + outbound_value = tdi_status_word; /* return the status word */ dprintf (atcd_dev, DEB_CSRW, "Status is %s\n", fmt_bitset (outbound_value, tdi_status_format)); @@ -1233,7 +1237,7 @@ while (working_set) { /* while signals remain if (DPRINTING (atcd_dev, DEB_CSRW)) if (inbound_value & DPI_IS_PARAM) - hp_debug (&atcd_dev, DEB_CSRW, "Parameter is %s%d bits | %d baud\n", + hp_debug (&atcd_dev, DEB_CSRW, "Parameter is %s%u bits | %u baud\n", fmt_bitset (inbound_value, tdi_parameter_format), bits_per_char [DPI_CHAR_SIZE (inbound_value)], BAUD_RATE (inbound_value)); @@ -1248,7 +1252,7 @@ while (working_set) { /* while signals remain case DREADSTB: outbound_value = tdi_read_word; /* return the data word */ - dprintf (atcd_dev, DEB_CSRW, "Input data is channel %d | %s%04o\n", + dprintf (atcd_dev, DEB_CSRW, "Input data is channel %u | %s%04o\n", DDR_TO_CHAN (outbound_value), fmt_bitset (outbound_value, tdi_input_data_format), DDR_TO_DATA (outbound_value)); @@ -1282,8 +1286,11 @@ while (working_set) { /* while signals remain case DSETMASK: - tdi_interrupt_mask = /* set the mask flip-flop */ - D_FF (dibptr->interrupt_mask & inbound_value); /* from the mask bit and the mask value */ + if (dibptr->interrupt_mask == INTMASK_E) /* if the mask is always enabled */ + tdi_interrupt_mask = SET; /* then set the mask flip-flop */ + else /* otherwise */ + tdi_interrupt_mask = D_FF (dibptr->interrupt_mask /* set the mask flip-flop if the mask bit */ + & inbound_value); /* is present in the mask value */ if (tdi_interrupt_mask && dibptr->interrupt_request) /* if the mask is enabled and a request is pending */ outbound_signals |= INTREQ; /* then assert INTREQ */ @@ -1360,11 +1367,11 @@ return IORETURN (outbound_signals, outbound_value); /* return the outbound s the request. */ -static SIGNALS_DATA atcc_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA atcc_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; int32 set_lines, clear_lines; @@ -1379,7 +1386,7 @@ while (working_set) { /* while signals remain case DCONTSTB: tci_cntr = CCN_CHAN (inbound_value); /* set the counter to the target channel */ - dprintf (atcc_dev, DEB_CSRW, "Control is channel %d | %s\n", + dprintf (atcc_dev, DEB_CSRW, "Control is channel %u | %s\n", tci_cntr, fmt_bitset (inbound_value, tci_control_format)); tci_control_word = inbound_value; /* save the control word */ @@ -1398,7 +1405,7 @@ while (working_set) { /* while signals remain & CCN_ECX (tci_control_word) /* that are enabled */ & tci_control_word; /* in the control word */ - dprintf (atcc_dev, DEB_XFER, "Channel %d line status is %s\n", + dprintf (atcc_dev, DEB_XFER, "Channel %u line status is %s\n", tci_cntr, fmt_bitset (cntl_status [tci_cntr], tci_line_format)); if (atcc_dev.flags & DEV_DIAG) { /* if the interface is in diagnostic mode */ @@ -1406,7 +1413,7 @@ while (working_set) { /* while signals remain cntl_status [tci_cntr ^ 1] & ~CCN_SX_MASK /* back to the alternate channel */ | CCN_CX (cntl_status [tci_cntr]); /* from the selected channel */ - dprintf (atcc_dev, DEB_XFER, "Channel %d line status is %s\n", + dprintf (atcc_dev, DEB_XFER, "Channel %u line status is %s\n", tci_cntr ^ 1, fmt_bitset (cntl_status [tci_cntr ^ 1], tci_line_format)); } @@ -1427,7 +1434,7 @@ while (working_set) { /* while signals remain clear_lines |= TMXR_MDM_DTR; /* set it down */ if (cntl_status [tci_cntr] & DCD) /* setting DTR down will disconnect the channel */ - dprintf (atcc_dev, DEB_CSRW, "Channel %d disconnected by DTR drop\n", + dprintf (atcc_dev, DEB_CSRW, "Channel %u disconnected by DTR drop\n", tci_cntr); } @@ -1458,9 +1465,9 @@ while (working_set) { /* while signals remain if (dibptr->interrupt_request == SET) /* reflect the interrupt request value */ tci_status_word |= CST_IRQ; /* in the status word */ - outbound_value = (uint16) tci_status_word; /* return the status word */ + outbound_value = tci_status_word; /* return the status word */ - dprintf (atcc_dev, DEB_CSRW, "Status is channel %d | %s\n", + dprintf (atcc_dev, DEB_CSRW, "Status is channel %u | %s\n", tci_cntr, fmt_bitset (outbound_value, tci_status_format)); break; @@ -1492,8 +1499,11 @@ while (working_set) { /* while signals remain case DSETMASK: - tci_interrupt_mask = /* set the mask flip-flop */ - D_FF (dibptr->interrupt_mask & inbound_value); /* from the mask bit and the mask value */ + if (dibptr->interrupt_mask == INTMASK_E) /* if the mask is always enabled */ + tci_interrupt_mask = SET; /* then set the mask flip-flop */ + else /* otherwise */ + tci_interrupt_mask = D_FF (dibptr->interrupt_mask /* set the mask flip-flop if the mask bit */ + & inbound_value); /* is present in the mask value */ if (tci_interrupt_mask && dibptr->interrupt_request) /* if the mask is enabled and a request is pending */ outbound_signals |= INTREQ; /* then assert INTREQ */ @@ -1733,8 +1743,8 @@ return SCPE_OK; simulation equivalent of the IORESET signal, which is asserted by the front panel LOAD and DUMP switches. - If a power-on reset (RESET -P) is being done, local modem control is - established, and DTR is set on all channels. This is necessary so that + If a power-on reset (RESET -P) is being done, then local modem control is + established by setting DTR on all channels. This is necessary so that channels not controlled by the TCI will be able to connect (TCI-controlled channels will have their DTR and RTS state set by the MPE TCI initialization routine). @@ -1743,20 +1753,17 @@ return SCPE_OK; static t_stat atcc_reset (DEVICE *dptr) { uint32 channel; -t_stat status = SCPE_OK; tci_master_reset (); /* perform a master reset */ if (sim_switches & SWMASK ('P')) { /* if this is a power-on reset */ - status = tmxr_set_modem_control_passthru (&atcd_mdsc); /* then establish local modem control */ - - for (channel = 0; channel < TERM_COUNT; channel++) /* for each terminal channel */ - tmxr_set_get_modem_bits (&atcd_ldsc [channel], /* set the DTR line on */ - TMXR_MDM_DTR, /* to allow non-TCI channels to connect */ + for (channel = 0; channel < TERM_COUNT; channel++) /* then for each terminal channel */ + tmxr_set_get_modem_bits (&atcd_ldsc [channel], /* set the DTR line on */ + TMXR_MDM_DTR, /* to allow non-TCI channels to connect */ 0, NULL); } -return status; +return SCPE_OK; } @@ -1885,7 +1892,7 @@ atcd_dib.interrupt_active = CLEAR; /* interrupt request * tdi_interrupt_mask = SET; /* set the interrupt mask */ tdi_status_word = 0; /* clear the status word */ -tdi_data_flag = 0; /* and the data flag */ +tdi_data_flag = CLEAR; /* and the data flag */ for (chan = FIRST_TERM; chan <= LAST_TERM; chan++) { /* for each terminal channel */ recv_buffer [chan] = 0; /* clear the receive data buffer */ @@ -2030,9 +2037,9 @@ return; static t_stat line_service (UNIT *uptr) { -const int32 channel = uptr - line_unit; /* channel number */ +const int32 channel = (int32) (uptr - line_unit); /* the channel number */ const int32 alt_channel = channel ^ 1; /* alternate channel number for diagnostic mode */ -const t_bool loopback = (atcd_dev.flags & DEV_DIAG) != 0; /* device is set for diagnostic mode */ +const t_bool loopback = (atcd_dev.flags & DEV_DIAG) != 0; /* TRUE if device is set for diagnostic mode */ int32 recv_data, send_data, char_data, cvtd_data; t_stat result = SCPE_OK; @@ -2236,7 +2243,7 @@ if ((atcc_dev.flags & (DEV_DIAG | DEV_DIS)) == 0) /* if we're not in diagn status = sim_poll_kbd (); /* poll the simulation console keyboard for input */ if (status >= SCPE_KFLAG) { /* if a character was present */ - recv_buffer [0] = (uint16) status; /* then save it for processing */ + recv_buffer [0] = (HP_WORD) status; /* then save it for processing */ status = SCPE_OK; /* and then clear the status */ line_service (&line_unit [0]); /* run the system console's I/O service */ @@ -2278,7 +2285,7 @@ return status; /* return the service st static t_stat activate_unit (UNIT *uptr, ACTIVATOR reason) { -const int32 channel = uptr - line_unit; /* the channel number */ +const int32 channel = (int32) (uptr - line_unit); /* the channel number */ int32 delay = 0; if (atcd_dev.flags & (DEV_DIAG | DEV_REALTIME)) /* if either diagnostic or real-time mode is set */ @@ -2438,7 +2445,7 @@ return sim_activate (uptr, delay); /* activate the unit and "addition" of the receive overhead may actually be a subtraction. */ -static uint32 service_time (uint16 control, ACTIVATOR reason) +static uint32 service_time (HP_WORD control, ACTIVATOR reason) { const double recirc_time = 69.44; /* microseconds per memory recirculation */ const uint32 recirc_per_bit = DPI_BAUD_RATE (control) + 1; /* number of memory recirculations per bit */ @@ -2483,13 +2490,13 @@ return (uint32) (usec_per_char / USEC_PER_EVENT); /* return the service ti from the parameter word. */ -static void store (uint16 control, uint16 data) +static void store (HP_WORD control, HP_WORD data) { const uint32 channel = DCN_CHAN (control); /* current channel number */ if (data & DDS_IS_SEND) /* if this is a send parameter or data */ if (channel > LAST_TERM) /* then report if the channel number is out of range */ - dprintf (atcd_dev, DEB_CSRW, "Send channel %d invalid\n", + dprintf (atcd_dev, DEB_CSRW, "Send channel %u invalid\n", channel); else if (data & DPI_IS_PARAM) { /* otherwise if this is a parameter store */ @@ -2497,7 +2504,7 @@ if (data & DDS_IS_SEND) /* if this is a send par line_unit [channel].send_time = /* and set the service time */ service_time (data, Send); - dprintf (atcd_dev, DEB_CSRW, "Channel %d send parameter %06o stored\n", + dprintf (atcd_dev, DEB_CSRW, "Channel %u send parameter %06o stored\n", channel, data); } @@ -2508,7 +2515,7 @@ if (data & DDS_IS_SEND) /* if this is a send par send_buffer [channel] = data; /* store it in the buffer */ - dprintf (atcd_dev, DEB_CSRW, "Channel %d send data %06o stored\n", + dprintf (atcd_dev, DEB_CSRW, "Channel %u send data %06o stored\n", channel, data); activate_unit (&line_unit [channel], Send); /* schedule the transmission event */ @@ -2516,7 +2523,7 @@ if (data & DDS_IS_SEND) /* if this is a send par else /* otherwise this is a receive parameter */ if (channel >= RECV_CHAN_COUNT) /* report if the channel number is out of range */ - dprintf (atcd_dev, DEB_CSRW, "Receive channel %d invalid\n", + dprintf (atcd_dev, DEB_CSRW, "Receive channel %u invalid\n", channel); else if (data & DPI_IS_PARAM) { /* otherwise this is a parameter store */ @@ -2530,12 +2537,12 @@ else /* otherwise this is a r PAD_BITS (data); } - dprintf (atcd_dev, DEB_CSRW, "Channel %d receive parameter %06o stored\n", + dprintf (atcd_dev, DEB_CSRW, "Channel %u receive parameter %06o stored\n", channel, data); } else /* otherwise a data store to a receive channel is invalid */ - dprintf (atcd_dev, DEB_CSRW, "Channel %d receive output data word %06o invalid\n", + dprintf (atcd_dev, DEB_CSRW, "Channel %u receive output data word %06o invalid\n", channel, data); } @@ -2605,11 +2612,11 @@ else { /* otherwise a normal ch channel); } - recv_buffer [channel] = (uint16) (recv_data | pad); /* save the character and padding in the buffer */ + recv_buffer [channel] = recv_data | pad; /* save the character and padding in the buffer */ - if (loopback) { /* if this channel has a loopback cable installed */ - if (recv_param [channel] & DPI_ENABLE_ECHO) { /* and the channel has echo enabled */ - recv_buffer [channel ^ 1] = (uint16) data; /* then send the data back to the other channel */ + if (loopback) { /* if this channel has a loopback cable installed */ + if (recv_param [channel] & DPI_ENABLE_ECHO) { /* and the channel has echo enabled */ + recv_buffer [channel ^ 1] = data; /* then send the data back to the other channel */ activate_unit (&line_unit [channel ^ 1], Loop); /* schedule the reception */ @@ -2618,10 +2625,10 @@ else { /* otherwise a normal ch } } - else if (channel <= LAST_TERM) { /* otherwise if it's a receive channel */ - if (line_unit [channel].flags & UNIT_CAPSLOCK) { /* then if caps lock is down */ - recv_data = toupper (recv_data); /* then convert to upper case if lower */ - recv_buffer [channel] = (uint16) (recv_data | pad); /* and replace the character in the buffer */ + else if (channel <= LAST_TERM) { /* otherwise if it's a receive channel */ + if (line_unit [channel].flags & UNIT_CAPSLOCK) { /* then if caps lock is down */ + recv_data = toupper (recv_data); /* then convert to upper case if lower */ + recv_buffer [channel] = recv_data | pad; /* and replace the character in the buffer */ } if (recv_param [channel] & DPI_ENABLE_ECHO) { /* if the channel has echo enabled */ @@ -2679,9 +2686,9 @@ return; character only if it is configured for the same baud rate and character size. */ -static void diagnose (uint16 control, int32 data) +static void diagnose (HP_WORD control, int32 data) { -const uint16 config = control & DPI_CHAR_CONFIG; /* main channel character size and baud rate */ +const HP_WORD config = control & DPI_CHAR_CONFIG; /* main channel character size and baud rate */ int32 channel; for (channel = FIRST_AUX; channel <= LAST_AUX; channel++) /* scan the auxiliary channels */ @@ -2812,10 +2819,10 @@ return; /* no channel has co pointing at the interrupting channel. */ -static uint16 scan_status (void) +static HP_WORD scan_status (void) { -uint32 chan_count; -uint16 interrupts; +uint32 chan_count; +HP_WORD interrupts; if (tci_scan) /* if the control interface is scanning */ chan_count = TERM_COUNT; /* then look at all of the channels */ @@ -2835,7 +2842,7 @@ while (chan_count > 0) { /* scan the control tci_scan = CLEAR; /* stop the scan at the current channel */ - dprintf (atcc_dev, DEB_CSRW, "Channel %d interrupt requested\n", + dprintf (atcc_dev, DEB_CSRW, "Channel %u interrupt requested\n", tci_cntr); break; } diff --git a/HP3000/hp3000_clk.c b/HP3000/hp3000_clk.c index 83afa382..05fd0db3 100644 --- a/HP3000/hp3000_clk.c +++ b/HP3000/hp3000_clk.c @@ -25,6 +25,9 @@ CLK HP 30135A System Clock/Fault Logging Interface + 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 08-Jun-15 JDB First release version 12-Aug-14 JDB Passed the system clock diagnostic (D426A) 05-Jul-14 JDB Created @@ -221,14 +224,14 @@ static const int32 scale [8] = { /* prescaler counts per clock ti #define UNIT_CALTIME_SHIFT (UNIT_V_UF + 0) /* calibrated timing mode */ -#define UNIT_CALTIME (1 << UNIT_CALTIME_SHIFT) +#define UNIT_CALTIME (1u << UNIT_CALTIME_SHIFT) /* Debug flags */ -#define DEB_CSRW (1 << 0) /* trace commands received and status returned */ -#define DEB_PSERV (1 << 1) /* trace unit service scheduling calls */ -#define DEB_IOB (1 << 2) /* trace I/O bus signals and data words exchanged */ +#define DEB_CSRW (1u << 0) /* trace commands received and status returned */ +#define DEB_PSERV (1u << 1) /* trace unit service scheduling calls */ +#define DEB_IOB (1u << 2) /* trace I/O bus signals and data words exchanged */ /* Control word. @@ -239,14 +242,14 @@ static const int32 scale [8] = { /* prescaler counts per clock ti +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CN_MR 0100000 /* (M) master reset (if bit 3 = 0) */ -#define CN_RATE_MASK 0160000 /* clock rate selector mask (if bit 3 = 1) */ -#define CN_RESET_LOAD_SEL 0010000 /* (E) select reset/load rate (0/1) */ -#define CN_IRQ_RESET_MASK 0003400 /* interrupt request reset selector mask */ -#define CN_COUNT_RESET 0000200 /* (C) reset count register after LR=CR interrupt */ -#define CN_LIMIT_COUNT_SEL 0000100 /* (L) select limit/count (0/1) register */ -#define CN_IRQ_RESET_ALL 0000040 /* (A) reset all interrupt requests */ -#define CN_IRQ_ENABLE 0000001 /* (I) enable clock interrupts */ +#define CN_MR 0100000u /* (M) master reset (if bit 3 = 0) */ +#define CN_RATE_MASK 0160000u /* clock rate selector mask (if bit 3 = 1) */ +#define CN_RESET_LOAD_SEL 0010000u /* (E) select reset/load rate (0/1) */ +#define CN_IRQ_RESET_MASK 0003400u /* interrupt request reset selector mask */ +#define CN_COUNT_RESET 0000200u /* (C) reset count register after LR=CR interrupt */ +#define CN_LIMIT_COUNT_SEL 0000100u /* (L) select limit/count (0/1) register */ +#define CN_IRQ_RESET_ALL 0000040u /* (A) reset all interrupt requests */ +#define CN_IRQ_ENABLE 0000001u /* (I) enable clock interrupts */ #define CN_RATE_SHIFT 13 /* clock rate alignment shift */ #define CN_IRQ_RESET_SHIFT 8 /* interrupt request reset alignment shift */ @@ -266,14 +269,14 @@ static const char *const rate_name [8] = { /* clock rate selector names */ }; static const char *const irq_reset_name [8] = { /* IRQ reset selector names */ - NULL, /* 000 = none */ - "reset LR = CR irq", /* 001 = LR equal CR */ - "reset LR = CR overflow irq", /* 010 = LR equal CR overflow */ - "reset SIN irq", /* 011 = I/O system */ - NULL, /* 100 = unused */ - NULL, /* 101 = unused */ - NULL, /* 110 = unused */ - NULL, /* 111 = unused */ + "", /* 000 = none */ + " | reset LR = CR irq", /* 001 = LR equal CR */ + " | reset LR = CR overflow irq", /* 010 = LR equal CR overflow */ + " | reset SIN irq", /* 011 = I/O system */ + "", /* 100 = unused */ + "", /* 101 = unused */ + "", /* 110 = unused */ + "" /* 111 = unused */ }; static const BITSET_NAME control_names [] = { /* Control word names */ @@ -307,13 +310,13 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define ST_DIO_OK 0040000 /* (D) direct I/O OK to use */ -#define ST_RATE_MASK 0034000 /* clock rate mask */ -#define ST_LR_EQ_CR 0000040 /* (C) limit register = count register */ -#define ST_LR_EQ_CR_OVFL 0000020 /* (F) limit register = count register overflow */ -#define ST_SYSTEM_IRQ 0000004 /* (I) I/O system interrupt request */ -#define ST_LIMIT_COUNT_SEL 0000002 /* (L) limit/count (0/1) register selected */ -#define ST_COUNT_RESET 0000001 /* (R) count register is reset after LR=CR interrupt */ +#define ST_DIO_OK 0040000u /* (D) direct I/O OK to use */ +#define ST_RATE_MASK 0034000u /* clock rate mask */ +#define ST_LR_EQ_CR 0000040u /* (C) limit register = count register */ +#define ST_LR_EQ_CR_OVFL 0000020u /* (F) limit register = count register overflow */ +#define ST_SYSTEM_IRQ 0000004u /* (I) I/O system interrupt request */ +#define ST_LIMIT_COUNT_SEL 0000002u /* (L) limit/count (0/1) register selected */ +#define ST_COUNT_RESET 0000001u /* (R) count register is reset after LR=CR interrupt */ #define ST_RATE_SHIFT 11 /* clock rate alignment shift */ @@ -349,12 +352,12 @@ static FLIP_FLOP system_irq = CLEAR; /* SIN interrupt request flip-fl static FLIP_FLOP limit_irq = CLEAR; /* limit = count interrupt request flip-flop */ static FLIP_FLOP lost_tick_irq = CLEAR; /* limit = count overflow interrupt request flip-flop */ -static uint32 control_word; /* control word */ -static uint32 status_word; /* status word */ -static uint32 count_register; /* counter register */ -static uint32 limit_register; /* limit register */ -static uint32 rate; /* clock rate */ -static uint32 prescaler; /* clock rate prescaler */ +static HP_WORD control_word; /* control word */ +static HP_WORD status_word; /* status word */ +static HP_WORD count_register; /* counter register */ +static HP_WORD limit_register; /* limit register */ +static uint32 rate; /* clock rate */ +static uint32 prescaler; /* clock rate prescaler */ static uint32 increment = 1; /* count register increment */ static t_bool coschedulable = FALSE; /* TRUE if the clock can be coscheduled with PCLK */ @@ -395,21 +398,21 @@ static UNIT clk_unit = { /* 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) }, - { ORDATA (LIMIT, limit_register, 16) }, - { ORDATA (RATE, rate, 3) }, - { 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 }, +/* Macro Name Location Width Offset Flags */ +/* ------ ------ --------------- ----- ------ ------- */ + { ORDATA (CNTL, control_word, 16) }, + { ORDATA (STAT, status_word, 16) }, + { ORDATA (COUNT, count_register, 16) }, + { ORDATA (LIMIT, limit_register, 16) }, + { ORDATA (RATE, rate, 3) }, + { 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) }, { NULL } }; @@ -543,11 +546,11 @@ return; rate name parameter without printing when the rate is not specified. */ -static SIGNALS_DATA clk_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA clk_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (clk_dev, DEB_IOB, "Received data %06o with signals %s\n", @@ -610,11 +613,12 @@ while (working_set) { if (dibptr->interrupt_active == CLEAR) /* if no interrupt is active */ working_set |= DRESETINT; /* then recalculate interrupt requests */ - dprintf (clk_dev, DEB_CSRW, (control_word & CN_RESET_LOAD_SEL - ? "Control is %s | %s rate\n" - : "Control is %s%.0s\n"), + dprintf (clk_dev, DEB_CSRW, (inbound_value & CN_RESET_LOAD_SEL + ? "Control is %s | %s rate%s\n" + : "Control is %s%.0s%s\n"), fmt_bitset (inbound_value, control_format), - rate_name [CN_RATE (inbound_value)]); + rate_name [CN_RATE (inbound_value)], + irq_reset_name [CN_RESET (inbound_value)]); break; @@ -636,7 +640,7 @@ while (working_set) { if (control_word & CN_COUNT_RESET) /* if the reset-after-interrupt selector is set */ status_word |= ST_COUNT_RESET; /* set the corresponding status bit */ - outbound_value = (uint16) status_word; /* return the status word */ + outbound_value = status_word; /* return the status word */ dprintf (clk_dev, DEB_CSRW, "Status is %s%s rate\n", fmt_bitset (outbound_value, status_format), @@ -648,7 +652,7 @@ while (working_set) { clk_update_counter (); /* update the clock counter register */ outbound_value = LOWER_WORD (count_register); /* and then read it */ - dprintf (clk_dev, DEB_CSRW, "Count register value %d returned\n", + dprintf (clk_dev, DEB_CSRW, "Count register value %u returned\n", count_register); break; @@ -664,7 +668,7 @@ while (working_set) { else { /* otherwise */ limit_register = inbound_value; /* set the limit register to the supplied value */ - dprintf (clk_dev, DEB_CSRW, "Limit register value %d set\n", + dprintf (clk_dev, DEB_CSRW, "Limit register value %u set\n", limit_register); coschedulable = (ticks [rate] == 1000 /* the clock can be coscheduled if the rate */ @@ -684,9 +688,11 @@ while (working_set) { case DRESETINT: dibptr->interrupt_active = CLEAR; /* clear the Interrupt Active flip-flop */ - dibptr->interrupt_request = system_irq /* recalculate the interrupt request signal */ - || control_word & CN_IRQ_ENABLE - && (limit_irq | lost_tick_irq); + if ((limit_irq == SET || lost_tick_irq == SET) /* if the limit or lost tick flip-flops are set */ + && control_word & CN_IRQ_ENABLE) /* and interrupts are enabled */ + dibptr->interrupt_request = SET; /* then set the interrupt request flip-flop */ + else /* otherwise */ + dibptr->interrupt_request = system_irq; /* request an interrupt if the system flip-flop is set */ if (dibptr->interrupt_request) /* if a request is pending */ outbound_signals |= INTREQ; /* then notify the IOP */ @@ -767,7 +773,7 @@ return IORETURN (outbound_signals, outbound_value); /* return the outbound s static t_stat clk_service (UNIT *uptr) { -dprintf (clk_dev, DEB_PSERV, "Service entered with counter %d increment %d limit %d\n", +dprintf (clk_dev, DEB_PSERV, "Service entered with counter %u increment %u limit %u\n", count_register, increment, limit_register); prescaler = prescaler - 1; /* decrement the prescaler count */ diff --git a/HP3000/hp3000_cpu.c b/HP3000/hp3000_cpu.c index a39bbc3e..6bfe21d5 100644 --- a/HP3000/hp3000_cpu.c +++ b/HP3000/hp3000_cpu.c @@ -25,7 +25,11 @@ CPU HP 3000 Series III Central Processing Unit + 08-Jun-16 JDB Corrected %d format to %u for unsigned values + 16-May-16 JDB ACCESS_PROPERTIES.name is now a pointer-to-constant 13-May-16 JDB Modified for revised SCP API function parameter types + 24-Mar-16 JDB Changed memory word type from uint16 to MEMORY_WORD + 21-Mar-16 JDB Changed cpu_ccb_table type from uint16 to HP_WORD 11-Mar-16 JDB Fixed byte EA calculations with negative indexes 22-Dec-15 JDB First release version 01-Apr-15 JDB First successful run of MPE-V/R through account login @@ -73,12 +77,12 @@ Memory protection is accomplished by checking program, data, and stack accesses against segment base and limit registers, which can be set only by - MPE. Bounds violations cause automatic hardware traps to a handler routine + MPE. Bounds violations cause automatic hardware traps to a handler routine within MPE. Some violations may be permitted; for example, a Stack Overflow trap may cause MPE to allocate a larger stack and then restart the interrupted instruction. Almost all memory references are position- independent, so moving segments to accommodate expansion requires only - resetting of the segment registers to point at the new location. Code + resetting of the segment registers to point at the new locations. Code segments are fully reentrant and shareable, and both code and data are virtual, as the hardware supports absent code and data segment traps. @@ -737,7 +741,7 @@ HP_WORD CNTR = 0; /* microcode counter */ condition code appropriate for the supplied operand into the status word. */ -const uint16 cpu_ccb_table [256] = { +const HP_WORD cpu_ccb_table [256] = { CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* NUL SOH STX ETX EOT ENQ ACK BEL */ CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* BS HT LF VT FF CR SO SI */ CFL, CFL, CFL, CFL, CFL, CFL, CFL, CFL, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ @@ -781,7 +785,7 @@ uint32 cpu_stop_flags; /* the simulation stop flag set EXEC_STATE cpu_micro_state = halted; /* the microcode execution state */ t_bool cpu_base_changed = FALSE; /* TRUE if any base register is changed */ t_bool cpu_is_calibrated = TRUE; /* TRUE if the process clock is calibrated */ -UNIT *cpu_pclk_uptr = &cpu_unit; /* a pointer to the process clock unit */ +UNIT *cpu_pclk_uptr = &cpu_unit; /* a (constant) pointer to the process clock unit */ /* CPU local state */ @@ -798,7 +802,7 @@ static uint32 pclk_increment = 1; /* the process clock increment p #define MEMSIZE (cpu_unit.capac) /* the current memory size in 16-bit words */ -static uint16 *M = NULL; /* the pointer to the main memory allocation */ +static MEMORY_WORD *M = NULL; /* the pointer to the main memory allocation */ /* Interrupt classification names */ @@ -900,11 +904,11 @@ static const struct FEATURE_TABLE cpu_features [] = { /* features indexed by C /* Memory access classification table */ typedef struct { - HP_WORD *bank_ptr; /* a pointer to the bank register */ - DEVICE *device_ptr; /* a pointer to the accessing device */ - uint32 debug_flag; /* the debug flag for tracing */ - t_bool irq; /* TRUE if an interrupt is requested on error */ - char *const name; /* the classification name */ + HP_WORD *bank_ptr; /* a pointer to the bank register */ + DEVICE *device_ptr; /* a pointer to the accessing device */ + uint32 debug_flag; /* the debug flag for tracing */ + t_bool irq; /* TRUE if an interrupt is requested on error */ + const char *name; /* the classification name */ } ACCESS_PROPERTIES; @@ -1796,7 +1800,7 @@ else { /* otherwise the access case absolute: case data: case stack: - M [address] = (uint16) value; /* write the value to memory */ + M [address] = (MEMORY_WORD) value; /* write the value to memory */ break; @@ -1804,7 +1808,7 @@ else { /* otherwise the access if (offset > SM && offset <= SM + SR && bank == SBANK) /* if the offset is within the TOS */ TR [SM + SR - offset] = value; /* then write the value to a TOS register */ else /* otherwise */ - M [address] = (uint16) value; /* write the value to memory */ + M [address] = (MEMORY_WORD) value; /* write the value to memory */ break; @@ -1814,7 +1818,7 @@ else { /* otherwise the access TR [SM + SR - offset] = value; /* then write the value to a TOS register */ if (DL <= offset && offset <= SM + SR || PRIV) /* if the offset is within bounds or is privileged */ - M [address] = (uint16) value; /* then write the value to memory */ + M [address] = (MEMORY_WORD) value; /* then write the value to memory */ else /* otherwise */ MICRO_ABORT (trap_Bounds_Violation); /* trap for a bounds violation */ break; @@ -3167,7 +3171,8 @@ return SCPE_OK; /* return the success of static t_stat cpu_reset (DEVICE *dptr) { if (M == NULL) { /* if this is the first call after simulator start */ - M = (uint16 *) calloc (PA_MAX, sizeof (uint16)); /* then allocate the maximum amount of memory needed */ + M = (MEMORY_WORD *) calloc (PA_MAX, /* then allocate the maximum amount of memory needed */ + sizeof (MEMORY_WORD)); if (M == NULL) /* if the allocation failed */ return SCPE_MEM; /* then report the error and abort the simulation */ @@ -3410,7 +3415,7 @@ if (MEMSIZE == 0 /* if this is the initia || MEMSIZE > cpu_features [new_index].maxmem) /* or if the current memory size is unsupported */ new_memsize = cpu_features [new_index].maxmem; /* then set the new size to the maximum supported size */ else /* otherwise the current size is valid for the new model */ - new_memsize = MEMSIZE; /* so leave it unchanged */ + new_memsize = (uint32) MEMSIZE; /* so leave it unchanged */ status = set_size (uptr, new_memsize, NULL, NULL); /* set the new memory size */ @@ -3502,7 +3507,7 @@ return SCPE_OK; /* report the success of static t_stat show_speed (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { -fprintf (st, "Simulation speed = %dx\n", cpu_speed); /* display the current CPU speed */ +fprintf (st, "Simulation speed = %ux\n", cpu_speed); /* display the current CPU speed */ return SCPE_OK; /* and report success */ } diff --git a/HP3000/hp3000_cpu.h b/HP3000/hp3000_cpu.h index bdc6d35a..6a8e3729 100644 --- a/HP3000/hp3000_cpu.h +++ b/HP3000/hp3000_cpu.h @@ -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. + 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 @@ -39,6 +40,28 @@ +/* Architectural constants. + + The type used to represent a main memory word value is defined. An array of + this type is used to simulate the CPU main memory. + + + Implementation notes: + + 1. The MEMORY_WORD type is a 16-bit unsigned type, corresponding with the + 16-bit main memory in the HP 3000. Unlike the general data type, which + is a 32-bit type for speed, main memory does not benefit from the faster + 32-bit execution on IA-32 processors, as only one instruction in the + cpu_read_memory and cpu_write_memory routines has an operand override + that invokes the slower instruction fetch path. There is a negligible + difference in the Memory Pattern Test diagnostic execution speeds for the + uint32 vs. uint16 definition, whereas the VM requirements are doubled for + the former. +*/ + +typedef uint16 MEMORY_WORD; /* HP 16-bit memory word representation */ + + /* Supported breakpoint switches */ #define BP_EXEC (SWMASK ('E')) /* an execution breakpoint */ @@ -51,14 +74,14 @@ #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_MODEL_MASK 0000001 /* model ID mask */ +#define UNIT_MODEL_MASK 0000001u /* model ID mask */ #define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT) -#define UNIT_SERIES_III (0 << UNIT_MODEL_SHIFT) /* the CPU is a Series III */ -#define UNIT_SERIES_II (1 << UNIT_MODEL_SHIFT) /* the CPU is a Series II */ -#define UNIT_EIS (1 << UNIT_EIS_SHIFT) /* the Extended Instruction Set is installed */ -#define UNIT_CALTIME (1 << UNIT_CALTIME_SHIFT) /* the process clock is calibrated to wall time */ +#define UNIT_SERIES_III (0u << UNIT_MODEL_SHIFT) /* the CPU is a Series III */ +#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_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK) @@ -67,11 +90,11 @@ /* CPU debug flags */ -#define DEB_MDATA (1 << 0) /* trace memory data accesses */ -#define DEB_INSTR (1 << 1) /* trace instruction execution */ -#define DEB_FETCH (1 << 2) /* trace instruction fetches */ -#define DEB_REG (1 << 3) /* trace register values */ -#define DEB_PSERV (1 << 4) /* trace PCLK service events */ +#define DEB_MDATA (1u << 0) /* trace memory data accesses */ +#define DEB_INSTR (1u << 1) /* trace instruction execution */ +#define DEB_FETCH (1u << 2) /* trace instruction fetches */ +#define DEB_REG (1u << 3) /* trace register values */ +#define DEB_PSERV (1u << 4) /* trace PCLK service events */ #define BOV_FORMAT "%02o.%06o %06o " /* bank-offset-value trace format string */ @@ -140,22 +163,22 @@ typedef enum { */ typedef enum { - cpx1_INTOVFL = 0100000, /* integer overflow */ - cpx1_BNDVIOL = 0040000, /* bounds violation */ - cpx1_ILLADDR = 0020000, /* illegal address */ - cpx1_CPUTIMER = 0010000, /* CPU timer */ - cpx1_SYSPAR = 0004000, /* system parity error */ - cpx1_ADDRPAR = 0002000, /* address parity error */ - cpx1_DATAPAR = 0001000, /* data parity error */ - cpx1_MODINTR = 0000400, /* module interrupt */ - cpx1_EXTINTR = 0000200, /* external interrupt */ - cpx1_PFINTR = 0000100, /* power fail interrupt */ -/* cpx1_UNUSED = 0000040, unused, always 0 */ - cpx1_ICSFLAG = 0000020, /* ICS flag */ - cpx1_DISPFLAG = 0000010, /* dispatcher-is-active flag */ - cpx1_EMULATOR = 0000004, /* emulator-in-use flag */ - cpx1_IOTIMER = 0000002, /* I/O timeout */ - cpx1_OPTION = 0000001 /* option present */ + cpx1_INTOVFL = 0100000u, /* integer overflow */ + cpx1_BNDVIOL = 0040000u, /* bounds violation */ + cpx1_ILLADDR = 0020000u, /* illegal address */ + cpx1_CPUTIMER = 0010000u, /* CPU timer */ + cpx1_SYSPAR = 0004000u, /* system parity error */ + cpx1_ADDRPAR = 0002000u, /* address parity error */ + cpx1_DATAPAR = 0001000u, /* data parity error */ + cpx1_MODINTR = 0000400u, /* module interrupt */ + cpx1_EXTINTR = 0000200u, /* external interrupt */ + cpx1_PFINTR = 0000100u, /* power fail interrupt */ +/* cpx1_UNUSED = 0000040u, unused, always 0 */ + cpx1_ICSFLAG = 0000020u, /* ICS flag */ + cpx1_DISPFLAG = 0000010u, /* dispatcher-is-active flag */ + cpx1_EMULATOR = 0000004u, /* emulator-in-use flag */ + cpx1_IOTIMER = 0000002u, /* I/O timeout */ + cpx1_OPTION = 0000001u /* option present */ } CPX1FLAG; #define CPX1_IRQ_SET (cpx1_INTOVFL | cpx1_BNDVIOL | \ @@ -165,22 +188,22 @@ typedef enum { cpx1_EXTINTR | cpx1_PFINTR) /* the set of CPX1 interrupt requests */ typedef enum { - cpx2_RUNSWCH = 0100000, /* RUN switch */ - cpx2_DUMPSWCH = 0040000, /* DUMP switch */ - cpx2_LOADSWCH = 0020000, /* LOAD switch */ - cpx2_LOADREG = 0010000, /* load register */ - cpx2_LOADADDR = 0004000, /* load address */ - cpx2_LOADMEM = 0002000, /* load memory */ - cpx2_DISPMEM = 0001000, /* display memory */ - cpx2_SNGLINST = 0000400, /* single instruction */ - cpx2_EXECSWCH = 0000200, /* EXECUTE switch */ - cpx2_INCRADDR = 0000100, /* increment address */ - cpx2_DECRADDR = 0000040, /* decrement address */ -/* cpx2_UNUSED = 0000020, unused, always 0 */ -/* cpx2_UNUSED = 0000010, unused, always 0 */ - cpx2_INHPFARS = 0000004, /* inhibit power fail autorestart */ - cpx2_SYSHALT = 0000002, /* system halt */ - cpx2_RUN = 0000001 /* run flip-flop */ + cpx2_RUNSWCH = 0100000u, /* RUN switch */ + cpx2_DUMPSWCH = 0040000u, /* DUMP switch */ + cpx2_LOADSWCH = 0020000u, /* LOAD switch */ + cpx2_LOADREG = 0010000u, /* load register */ + cpx2_LOADADDR = 0004000u, /* load address */ + cpx2_LOADMEM = 0002000u, /* load memory */ + cpx2_DISPMEM = 0001000u, /* display memory */ + cpx2_SNGLINST = 0000400u, /* single instruction */ + cpx2_EXECSWCH = 0000200u, /* EXECUTE switch */ + cpx2_INCRADDR = 0000100u, /* increment address */ + 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_SYSHALT = 0000002u, /* system halt */ + cpx2_RUN = 0000001u /* run flip-flop */ } CPX2FLAG; #define CPX2_IRQ_SET (cpx2_RUNSWCH | cpx2_DUMPSWCH | \ @@ -335,21 +358,21 @@ typedef enum { 11 = invalid */ -#define STATUS_M 0100000 /* mode flag */ -#define STATUS_I 0040000 /* interrupt flag */ -#define STATUS_T 0020000 /* trap flag */ -#define STATUS_R 0010000 /* right-hand stack op flag */ -#define STATUS_O 0004000 /* overflow flag */ -#define STATUS_C 0002000 /* carry flag */ +#define STATUS_M 0100000u /* mode flag */ +#define STATUS_I 0040000u /* interrupt flag */ +#define STATUS_T 0020000u /* trap flag */ +#define STATUS_R 0010000u /* right-hand stack op flag */ +#define STATUS_O 0004000u /* overflow flag */ +#define STATUS_C 0002000u /* carry flag */ -#define STATUS_CCG 0000000 /* condition code greater than */ -#define STATUS_CCL 0000400 /* condition code less than */ -#define STATUS_CCE 0001000 /* condition code equal to */ +#define STATUS_CCG 0000000u /* condition code greater than */ +#define STATUS_CCL 0000400u /* condition code less than */ +#define STATUS_CCE 0001000u /* condition code equal to */ -#define STATUS_CC_MASK 0001400 /* condition code mask */ +#define STATUS_CC_MASK 0001400u /* condition code mask */ #define STATUS_CC_SHIFT 8 /* condition code alignment */ -#define STATUS_CS_MASK 0000377 /* code segment mask */ +#define STATUS_CS_MASK 0000377u /* code segment mask */ #define STATUS_CS_WIDTH 8 /* code segment mask width */ #define STATUS_OVTRAP (STATUS_T | STATUS_O) @@ -390,9 +413,9 @@ typedef enum { register to a condition code flag. */ -#define CFL 0000400 /* condition code flag less than */ -#define CFE 0001000 /* condition code flag equal to */ -#define CFG 0002000 /* condition code flag greater than */ +#define CFL 0000400u /* condition code flag less than */ +#define CFE 0001000u /* condition code flag equal to */ +#define CFG 0002000u /* condition code flag greater than */ #define TO_CCF(s) ((s) & STATUS_CC_MASK ? (s) & STATUS_CC_MASK : CFG) @@ -615,47 +638,47 @@ typedef enum { /* Machine instruction bit-field accessors */ -#define BITS_0_3_MASK 0170000 /* bits 0-3 mask */ +#define BITS_0_3_MASK 0170000u /* bits 0-3 mask */ #define BITS_0_3_SHIFT 12 /* bits 0-3 alignment shift */ #define BITS_0_3(v) (((v) & BITS_0_3_MASK) >> BITS_0_3_SHIFT) -#define BITS_4_5_MASK 0006000 /* bits 4-5 mask */ +#define BITS_4_5_MASK 0006000u /* bits 4-5 mask */ #define BITS_4_5_SHIFT 10 /* bits 4-5 alignment shift */ #define BITS_4_5(v) (((v) & BITS_4_5_MASK) >> BITS_4_5_SHIFT) -#define BITS_4_7_MASK 0007400 /* bits 4-7 mask */ +#define BITS_4_7_MASK 0007400u /* bits 4-7 mask */ #define BITS_4_7_SHIFT 8 /* bits 4-7 alignment shift */ #define BITS_4_7(v) (((v) & BITS_4_7_MASK) >> BITS_4_7_SHIFT) -#define BITS_4_9_MASK 0007700 /* bits 4-9 mask */ +#define BITS_4_9_MASK 0007700u /* bits 4-9 mask */ #define BITS_4_9_SHIFT 6 /* bits 4-9 alignment shift */ #define BITS_4_9(v) (((v) & BITS_4_9_MASK) >> BITS_4_9_SHIFT) -#define BITS_5_9_MASK 0003700 /* bits 5-9 mask */ +#define BITS_5_9_MASK 0003700u /* bits 5-9 mask */ #define BITS_5_9_SHIFT 6 /* bits 5-9 alignment shift */ #define BITS_5_9(v) (((v) & BITS_5_9_MASK) >> BITS_5_9_SHIFT) -#define BITS_8_11_MASK 0000360 /* bits 8-11 mask */ +#define BITS_8_11_MASK 0000360u /* bits 8-11 mask */ #define BITS_8_11_SHIFT 4 /* bits 8-11 alignment shift */ #define BITS_8_11(v) (((v) & BITS_8_11_MASK) >> BITS_8_11_SHIFT) -#define BITS_8_12_MASK 0000370 /* bits 8-12 mask */ +#define BITS_8_12_MASK 0000370u /* bits 8-12 mask */ #define BITS_8_12_SHIFT 3 /* bits 8-12 alignment shift */ #define BITS_8_12(v) (((v) & BITS_8_12_MASK) >> BITS_8_12_SHIFT) -#define BITS_10_15_MASK 0000077 /* bits 10-15 mask */ +#define BITS_10_15_MASK 0000077u /* bits 10-15 mask */ #define BITS_10_15_SHIFT 0 /* bits 10-15 alignment shift */ #define BITS_10_15(v) (((v) & BITS_10_15_MASK) >> BITS_10_15_SHIFT) -#define BITS_12_15_MASK 0000017 /* bits 12-15 mask */ +#define BITS_12_15_MASK 0000017u /* bits 12-15 mask */ #define BITS_12_15_SHIFT 0 /* bits 12-15 alignment shift */ #define BITS_12_15(v) (((v) & BITS_12_15_MASK) >> BITS_12_15_SHIFT) @@ -718,158 +741,158 @@ typedef enum { /* Specific instruction accessors */ -#define IOOP_K_MASK 0000017 /* I/O K-field mask */ -#define IOOP_K_SHIFT 0000000 /* I/O K-field alignment shift */ +#define IOOP_K_MASK 0000017u /* I/O K-field mask */ +#define IOOP_K_SHIFT 0000000u /* I/O K-field alignment shift */ #define IO_K(v) (((v) & IOOP_K_MASK) >> IOOP_K_SHIFT) -#define X_FLAG 0004000 /* index flag in bit 4 */ -#define I_FLAG_BIT_4 0004000 /* indirect flag in bit 4 */ -#define I_FLAG_BIT_5 0002000 /* indirect flag in bit 5 */ -#define M_FLAG 0001000 /* memory subop flag in bit 6 */ +#define X_FLAG 0004000u /* index flag in bit 4 */ +#define I_FLAG_BIT_4 0004000u /* indirect flag in bit 4 */ +#define I_FLAG_BIT_5 0002000u /* indirect flag in bit 5 */ +#define M_FLAG 0001000u /* memory subop flag in bit 6 */ -#define START_BIT_MASK 0000360 /* start bit mask for bit field instructions */ +#define START_BIT_MASK 0000360u /* start bit mask for bit field instructions */ #define START_BIT_SHIFT 4 /* start bit alignment shift */ #define START_BIT(v) (((v) & START_BIT_MASK) >> START_BIT_SHIFT) -#define BIT_COUNT_MASK 0000017 /* bit count mask for bit field instructions */ +#define BIT_COUNT_MASK 0000017u /* bit count mask for bit field instructions */ #define BIT_COUNT_SHIFT 0 /* bit count alignment shift */ #define BIT_COUNT(v) (((v) & BIT_COUNT_MASK) >> BIT_COUNT_SHIFT) -#define BIT_POSITION_MASK 0000077 /* bit position mask for bit test instructions */ +#define BIT_POSITION_MASK 0000077u /* bit position mask for bit test instructions */ #define BIT_POSITION_SHIFT 0 /* bit position alignment shift */ #define BIT_POSITION(v) (((v) & BIT_POSITION_MASK) >> BIT_POSITION_SHIFT) -#define SHIFT_COUNT_MASK 0000077 /* shift count mask for shift instructions */ +#define SHIFT_COUNT_MASK 0000077u /* shift count mask for shift instructions */ #define SHIFT_COUNT_SHIFT 0 /* shift count alignment shift */ #define SHIFT_COUNT(v) (((v) & SHIFT_COUNT_MASK) >> SHIFT_COUNT_SHIFT) -#define SHIFT_RIGHT_FLAG 0000100 /* shift instructions left/right (0/1) flag */ +#define SHIFT_RIGHT_FLAG 0000100u /* shift instructions left/right (0/1) flag */ -#define MODE_DISP_MASK 0001777 /* memory-reference mode and displacement mask */ -#define MODE_MASK 0001700 /* memory-reference mode mask */ +#define MODE_DISP_MASK 0001777u /* memory-reference mode and displacement mask */ +#define MODE_MASK 0001700u /* memory-reference mode mask */ #define MODE_SHIFT 6 /* memory-reference mode alignment shift */ -#define DISPL_31_SIGN 0000040 /* sign bit for 0-31 displacements */ -#define DISPL_255_SIGN 0000400 /* sign bit for 0-255 displacements */ +#define DISPL_31_SIGN 0000040u /* sign bit for 0-31 displacements */ +#define DISPL_255_SIGN 0000400u /* sign bit for 0-255 displacements */ -#define DISPL_31_MASK 0000037 /* mask for 0-31 displacements */ -#define DISPL_63_MASK 0000077 /* mask for 0-63 displacements */ -#define DISPL_127_MASK 0000177 /* mask for 0-127 displacements */ -#define DISPL_255_MASK 0000377 /* mask for 0-255 displacements */ +#define DISPL_31_MASK 0000037u /* mask for 0-31 displacements */ +#define DISPL_63_MASK 0000077u /* mask for 0-63 displacements */ +#define DISPL_127_MASK 0000177u /* mask for 0-127 displacements */ +#define DISPL_255_MASK 0000377u /* mask for 0-255 displacements */ -#define DISPL_P_FLAG 0001000 /* P-relative displacement flag */ -#define DISPL_DB_FLAG 0000400 /* DB-relative displacement flag */ -#define DISPL_QPOS_FLAG 0000200 /* positive Q-relative displacement flag */ -#define DISPL_QNEG_FLAG 0000100 /* negative Q-relative displacement flag */ +#define DISPL_P_FLAG 0001000u /* P-relative displacement flag */ +#define DISPL_DB_FLAG 0000400u /* DB-relative displacement flag */ +#define DISPL_QPOS_FLAG 0000200u /* positive Q-relative displacement flag */ +#define DISPL_QNEG_FLAG 0000100u /* negative Q-relative displacement flag */ -#define IMMED_MASK 0000377 /* mask for immediate values */ +#define IMMED_MASK 0000377u /* mask for immediate values */ -#define SDEC2_MASK 0000003 /* two-bit S-decrement mask for move instructions */ -#define SDEC3_MASK 0000007 /* three-bit S-decrement mask for move instructions */ +#define SDEC2_MASK 0000003u /* two-bit S-decrement mask for move instructions */ +#define SDEC3_MASK 0000007u /* three-bit S-decrement mask for move instructions */ #define SDEC_SHIFT 0 /* S-decrement alignment shift */ #define SDEC2(v) (((v) & SDEC2_MASK) >> SDEC_SHIFT) #define SDEC3(v) (((v) & SDEC3_MASK) >> SDEC_SHIFT) -#define DB_FLAG 0000020 /* PB/DB base flag */ +#define DB_FLAG 0000020u /* PB/DB base flag */ -#define MVBW_CCF 0000030 /* MVBW condition code flags */ -#define MVBW_N_FLAG 0000020 /* MVBW numeric flag */ -#define MVBW_A_FLAG 0000010 /* MVBW alphabetic flag */ -#define MVBW_S_FLAG 0000004 /* MVBW upshift flag */ +#define MVBW_CCF 0000030u /* MVBW condition code flags */ +#define MVBW_N_FLAG 0000020u /* MVBW numeric flag */ +#define MVBW_A_FLAG 0000010u /* MVBW alphabetic flag */ +#define MVBW_S_FLAG 0000004u /* MVBW upshift flag */ #define MVBW_CCF_SHIFT 6 /* CCF alignment in MVBW instruction */ -#define NABS_FLAG 0000100 /* CVDA negative absolute value flag */ -#define ABS_FLAG 0000040 /* CVDA absolute value flag */ +#define NABS_FLAG 0000100u /* CVDA negative absolute value flag */ +#define ABS_FLAG 0000040u /* CVDA absolute value flag */ #define EIS_SDEC_SHIFT 4 /* EIS S-decrement alignment shift */ /* Explicit instruction opcodes and accessors */ -#define NOP 0000000 /* no operation */ -#define QASR 0015700 /* quadruple arithmetic right shift */ -#define DMUL 0020570 /* double integer multiply */ -#define DDIV 0020571 /* double integer divide */ -#define SED_1 0030041 /* set enable interrupt */ -#define HALT_10 0030370 /* halt 10 */ +#define NOP 0000000u /* no operation */ +#define QASR 0015700u /* quadruple arithmetic right shift */ +#define DMUL 0020570u /* double integer multiply */ +#define DDIV 0020571u /* double integer divide */ +#define SED_1 0030041u /* set enable interrupt */ +#define HALT_10 0030370u /* halt 10 */ -#define MTFDS_MASK 0177730 /* move to/from data segment mask */ -#define MTFDS 0020130 /* move to/from data segment */ +#define MTFDS_MASK 0177730u /* move to/from data segment mask */ +#define MTFDS 0020130u /* move to/from data segment */ -#define EXIT_MASK 0177400 /* exit procedure mask */ -#define EXIT 0031400 /* exit procedure */ +#define EXIT_MASK 0177400u /* exit procedure mask */ +#define EXIT 0031400u /* exit procedure */ -#define PAUS_MASK 0177760 /* pause mask */ -#define PAUS 0030020 /* pause */ +#define PAUS_MASK 0177760u /* pause mask */ +#define PAUS 0030020u /* pause */ -#define BR_MASK 0173000 /* conditional and unconditional branch mask */ -#define BR_DBQS_I 0143000 /* branch unconditionally DB/Q/S-relative indirect */ -#define BCC 0141000 /* branch conditionally */ +#define BR_MASK 0173000u /* conditional and unconditional branch mask */ +#define BR_DBQS_I 0143000u /* branch unconditionally DB/Q/S-relative indirect */ +#define BCC 0141000u /* branch conditionally */ #define BCC_CCF_SHIFT 2 /* CCF alignment in BCC instruction */ -#define LSDX_MASK 0175000 /* load/store double-word indexed mask */ -#define LDD_X 0155000 /* load double-word indexed */ -#define STD_X 0165000 /* store double-word indexed */ +#define LSDX_MASK 0175000u /* load/store double-word indexed mask */ +#define LDD_X 0155000u /* load double-word indexed */ +#define STD_X 0165000u /* store double-word indexed */ -#define TBR_MASK 0177000 /* test and branch mask */ -#define TBA 0050000 /* test and branch, limit in A */ -#define MTBA 0052000 /* modify, test and branch, limit in A */ -#define TBX 0054000 /* test and branch, limit in X */ -#define MTBX 0056000 /* modify, test and branch, limit in X */ +#define TBR_MASK 0177000u /* test and branch mask */ +#define TBA 0050000u /* test and branch, limit in A */ +#define MTBA 0052000u /* modify, test and branch, limit in A */ +#define TBX 0054000u /* test and branch, limit in X */ +#define MTBX 0056000u /* modify, test and branch, limit in X */ /* PSHR/SETR instruction accessors */ -#define PSR_RL_MASK 0000001 /* PSHR/SETR register right-to-left mask */ -#define PSR_LR_MASK 0000200 /* PSHR/SETR register left-to-right mask */ +#define PSR_RL_MASK 0000001u /* PSHR/SETR register right-to-left mask */ +#define PSR_LR_MASK 0000200u /* PSHR/SETR register left-to-right mask */ -#define PSR_SBANK 0000200 /* Stack bank register */ -#define PSR_DB_DBANK 0000100 /* Data base and data bank registers */ -#define PSR_DL 0000040 /* Data limit register */ -#define PSR_Z 0000020 /* Stack limit register */ -#define PSR_STA 0000010 /* Status register */ -#define PSR_X 0000004 /* Index register */ -#define PSR_Q 0000002 /* Frame pointer */ -#define PSR_S 0000001 /* Stack pointer */ +#define PSR_SBANK 0000200u /* Stack bank register */ +#define PSR_DB_DBANK 0000100u /* Data base and data bank registers */ +#define PSR_DL 0000040u /* Data limit register */ +#define PSR_Z 0000020u /* Stack limit register */ +#define PSR_STA 0000010u /* Status register */ +#define PSR_X 0000004u /* Index register */ +#define PSR_Q 0000002u /* Frame pointer */ +#define PSR_S 0000001u /* Stack pointer */ #define PSR_PRIV (PSR_SBANK | PSR_DB_DBANK | PSR_DL | PSR_Z) /* Reserved memory addresses */ -#define CSTB_POINTER 0000000 /* code segment table base pointer */ -#define CSTX_POINTER 0000001 /* code segment table extension pointer */ -#define DST_POINTER 0000002 /* data segment table pointer */ -#define ICS_Q 0000005 /* interrupt control stack marker pointer (QI) */ -#define ICS_Z 0000006 /* interrupt control stack limit (ZI) */ -#define INTERRUPT_MASK 0000007 /* interrupt mask */ -#define SGT_POINTER 0001000 /* system global tables pointer */ +#define CSTB_POINTER 0000000u /* code segment table base pointer */ +#define CSTX_POINTER 0000001u /* code segment table extension pointer */ +#define DST_POINTER 0000002u /* data segment table pointer */ +#define ICS_Q 0000005u /* interrupt control stack marker pointer (QI) */ +#define ICS_Z 0000006u /* interrupt control stack limit (ZI) */ +#define INTERRUPT_MASK 0000007u /* interrupt mask */ +#define SGT_POINTER 0001000u /* system global tables pointer */ /* Code Segment Table accessors */ -#define CST_A_BIT 0100000 /* code segment is absent */ -#define CST_M_BIT 0040000 /* code segment is privileged */ -#define CST_R_BIT 0020000 /* code segment has been referenced flag */ -#define CST_T_BIT 0010000 /* code segment is to be traced */ -#define CST_SEGLEN_MASK 0007777 /* code segment length mask */ -#define CST_BANK_MASK 0000017 /* code segment bank mask */ +#define CST_A_BIT 0100000u /* code segment is absent */ +#define CST_M_BIT 0040000u /* code segment is privileged */ +#define CST_R_BIT 0020000u /* code segment has been referenced flag */ +#define CST_T_BIT 0010000u /* code segment is to be traced */ +#define CST_SEGLEN_MASK 0007777u /* code segment length mask */ +#define CST_BANK_MASK 0000017u /* code segment bank mask */ -#define CST_RESERVED 0000300 /* number of CST entries reserved for the system */ +#define CST_RESERVED 0000300u /* number of CST entries reserved for the system */ /* Data Segment Table accessors */ -#define DST_A_BIT 0100000 /* data segment is absent */ -#define DST_C_BIT 0040000 /* data segment is clean (not modified) */ -#define DST_R_BIT 0020000 /* data segment has been referenced */ -#define DST_SEGLEN_MASK 0017777 /* data segment length mask */ -#define DST_BANK_MASK 0000017 /* data segment bank mask */ +#define DST_A_BIT 0100000u /* data segment is absent */ +#define DST_C_BIT 0040000u /* data segment is clean (not modified) */ +#define DST_R_BIT 0020000u /* data segment has been referenced */ +#define DST_SEGLEN_MASK 0017777u /* data segment length mask */ +#define DST_BANK_MASK 0000017u /* data segment bank mask */ /* Segment Transfer Table accessors */ -#define STT_LENGTH_MASK 0000377 /* STT length mask */ +#define STT_LENGTH_MASK 0000377u /* STT length mask */ #define STT_LENGTH_SHIFT 0 /* STT length alignment shift */ @@ -878,15 +901,15 @@ typedef enum { /* Program label accessors */ -#define LABEL_EXTERNAL 0100000 /* external program label flag */ -#define LABEL_STTN_MASK 0077400 /* external program label STT number mask */ -#define LABEL_SEGMENT_MASK 0000377 /* external program label segment mask */ +#define LABEL_EXTERNAL 0100000u /* external program label flag */ +#define LABEL_STTN_MASK 0077400u /* external program label STT number mask */ +#define LABEL_SEGMENT_MASK 0000377u /* external program label segment mask */ #define LABEL_STTN_SHIFT 8 /* STT number alignment shift */ #define LABEL_SEGMENT_SHIFT 0 /* segment number alignment shift */ -#define LABEL_UNCALLABLE 0040000 /* local program label uncallable flag */ -#define LABEL_ADDRESS_MASK 0037777 /* local program label address mask */ +#define LABEL_UNCALLABLE 0040000u /* local program label uncallable flag */ +#define LABEL_ADDRESS_MASK 0037777u /* local program label address mask */ #define STT_NUMBER(l) (((l) & LABEL_STTN_MASK) >> LABEL_STTN_SHIFT) #define STT_SEGMENT(l) (((l) & LABEL_SEGMENT_MASK) >> LABEL_SEGMENT_SHIFT) @@ -901,10 +924,10 @@ typedef enum { /* Stack marker accessors */ -#define STMK_D 0100000 /* dispatcher flag */ -#define STMK_T 0100000 /* trace flag */ -#define STMK_M 0040000 /* mapped flag */ -#define STMK_RTN_ADDR 0037777 /* PB-relative return address */ +#define STMK_D 0100000u /* dispatcher flag */ +#define STMK_T 0100000u /* trace flag */ +#define STMK_M 0040000u /* mapped flag */ +#define STMK_RTN_ADDR 0037777u /* PB-relative return address */ /* CPU registers */ @@ -952,7 +975,7 @@ extern UNIT cpu_unit; /* CPU unit structure (needed fo /* Condition Code B mapping table */ -extern const uint16 cpu_ccb_table [256]; /* byte-value to condition-code map */ +extern const HP_WORD cpu_ccb_table [256]; /* byte-value to condition-code map */ /* Global CPU functions */ diff --git a/HP3000/hp3000_cpu_base.c b/HP3000/hp3000_cpu_base.c index 1d8305ac..e81c2e1a 100644 --- a/HP3000/hp3000_cpu_base.c +++ b/HP3000/hp3000_cpu_base.c @@ -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. + 11-Jun-16 JDB Bit mask constants are now unsigned 13-Jan-16 JDB First release version 11-Dec-12 JDB Created @@ -76,13 +77,13 @@ extern DEVICE cpu_dev; /* Central Processing Unit */ /* Program constants */ -#define SIO_OK 0100000 /* TIO bit 0 = SIO OK */ -#define DIO_OK 0040000 /* TIO bit 1 = DIO OK */ +#define SIO_OK 0100000u /* TIO bit 0 = SIO OK */ +#define DIO_OK 0040000u /* TIO bit 1 = DIO OK */ #define NORM_BIT (D48_SIGN >> 6) /* triple normalizing examines bit 6 */ #define NORM_MASK (D48_MASK >> 6) /* triple normalizing masks off bits 0-5 */ -#define TO_UPPERCASE(b) ((b) & ~040) /* alphabetic byte upshift */ +#define TO_UPPERCASE(b) ((b) & ~040u) /* alphabetic byte upshift */ /* CPU base set global data structures */ diff --git a/HP3000/hp3000_cpu_fp.c b/HP3000/hp3000_cpu_fp.c index e1080b45..3641da47 100644 --- a/HP3000/hp3000_cpu_fp.c +++ b/HP3000/hp3000_cpu_fp.c @@ -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. + 11-Jun-16 JDB Bit mask constants are now unsigned 03-Feb-16 JDB First release version 25-Aug-15 JDB Fixed FSUB zero subtrahend bug (from Norwin Malmberg) 01-Apr-15 JDB Passes the floating point tests in the CPU diagnostic (D420A1) @@ -112,18 +113,18 @@ #define MIN_EXPONENT -256 /* the smallest representable exponent */ #define MAX_EXPONENT +255 /* the largest representable exponent */ -#define EXPONENT_MASK 0077700 /* the mask to isolate the exponent in the first word */ -#define MANTISSA_MASK 0000077 /* the mask to isolate the mantissa in the first word */ +#define EXPONENT_MASK 0077700u /* the mask to isolate the exponent in the first word */ +#define MANTISSA_MASK 0000077u /* the mask to isolate the mantissa in the first word */ #define EXPONENT_SHIFT 6 /* the exponent alignment shift */ #define MANTISSA_SHIFT 0 /* the mantissa alignment shift */ #define UNPACKED_BITS 54 /* the number of significant bits in the unpacked mantissa */ -#define IMPLIED_BIT ((t_uint64) 1 << UNPACKED_BITS) /* the implied MSB in the mantissa */ -#define CARRY_BIT ((t_uint64) 1 << UNPACKED_BITS + 1) /* the carry from the MSB in the mantissa */ +#define IMPLIED_BIT ((t_uint64) 1uL << UNPACKED_BITS) /* the implied MSB in the mantissa */ +#define CARRY_BIT ((t_uint64) 1uL << UNPACKED_BITS + 1) /* the carry from the MSB in the mantissa */ -#define DELTA_ALIGNMENT (D64_WIDTH - UNPACKED_BITS) /* net shift to align the binary point */ +#define DELTA_ALIGNMENT (D64_WIDTH - UNPACKED_BITS) /* net shift to align the binary point */ /* Floating-point accessors */ diff --git a/HP3000/hp3000_cpu_fp.h b/HP3000/hp3000_cpu_fp.h index a9df9a10..458df128 100644 --- a/HP3000/hp3000_cpu_fp.h +++ b/HP3000/hp3000_cpu_fp.h @@ -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. + 11-Jun-16 JDB Bit mask constants are now unsigned 21-Jan-16 JDB First release version 29-Mar-15 JDB Created @@ -35,10 +36,10 @@ /* Program constants */ -#define SIGN_BIT 0100000 -#define EXPONENT_BITS 0077700 -#define ASSUMED_BIT 0000100 -#define FRACTION_BITS 0000077 +#define SIGN_BIT 0100000u +#define EXPONENT_BITS 0077700u +#define ASSUMED_BIT 0000100u +#define FRACTION_BITS 0000077u /* Operand precisions: diff --git a/HP3000/hp3000_cpu_ims.h b/HP3000/hp3000_cpu_ims.h index 6cb026ba..c1b1ff46 100644 --- a/HP3000/hp3000_cpu_ims.h +++ b/HP3000/hp3000_cpu_ims.h @@ -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. + 11-Jun-16 JDB Bit mask constants are now unsigned 05-Sep-15 JDB First release version 11-Dec-12 JDB Created @@ -98,13 +99,13 @@ typedef enum { identifies all four cases. */ -#define IOCW_DC 0100000 /* data chain */ -#define IOCW_SIO_MASK 0070000 /* general SIO order mask */ -#define IOCW_ORDER_MASK 0174000 /* fully decoded I/O order mask */ -#define IOCW_CNTL_MASK 0007777 /* control word mask */ -#define IOCW_WCNT_MASK 0007777 /* word count mask */ +#define IOCW_DC 0100000u /* data chain */ +#define IOCW_SIO_MASK 0070000u /* general SIO order mask */ +#define IOCW_ORDER_MASK 0174000u /* fully decoded I/O order mask */ +#define IOCW_CNTL_MASK 0007777u /* control word mask */ +#define IOCW_WCNT_MASK 0007777u /* word count mask */ -#define IOAW_BANK_MASK 0000017 /* bank number mask */ +#define IOAW_BANK_MASK 0000017u /* bank number mask */ #define IOCW_ORDER_SHIFT 11 /* I/O order alignment shift */ #define IOCW_CNTL_SHIFT 0 /* control word alignment shift */ diff --git a/HP3000/hp3000_defs.h b/HP3000/hp3000_defs.h index ea78c6f8..c151a54c 100644 --- a/HP3000/hp3000_defs.h +++ b/HP3000/hp3000_defs.h @@ -24,6 +24,8 @@ this Software without prior written authorization from the author. 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 04-Feb-16 JDB First release version 11-Dec-12 JDB Created @@ -33,6 +35,73 @@ The author gratefully acknowledges the help of Frank McConnell in answering questions about the HP 3000. + + + ----------------------------------------------------- + Implementation Note -- Compiling the Simulator as C++ + ----------------------------------------------------- + + Although simulators are written in C, the SIMH project encourages developers + to compile them with a C++ compiler to obtain the more careful type checking + provided. To obtain successful compilations, the simulator must be written + in the subset of C that is also valid C++. Using valid C features beyond + that subset, as the HP 3000 simulator does, will produce C++ compiler errors. + + The standard C features used by the simulator that prevent error-free C++ + compilation are: + + 1. Incomplete types. + + In C, mutually recursive type definitions are allowed by the use of + incomplete type declarations, such as "DEVICE ms_dev;" followed later by + "DEVICE ms_dev {...};". Several HP device simulators use this feature to + place a pointer to the device structure in the "desc" field of an MTAB + array element, typically when the associated validation or display + routine handles multiple devices. As the DEVICE contains a pointer to + the MTAB array, and an MTAB array element contains a pointer to the + DEVICE, the definitions are mutually recursive, and incomplete types are + employed. C++ does not permit incomplete types. + + 2. Implicit conversion of ints to enums. + + In C, enumeration types are compatible with integer types, and its + members are constants having type "int". As such, they are semantically + equivalent to and may be used interchangeably with integers. For the + developer, though, C enumerations have some advantages. In particular, + the compiler may check a "switch" statement to ensure that all of the + enumeration cases are covered. Also, a mathematical set may be modeled + by an enumeration type with disjoint enumerator values, with the bitwise + integer OR and AND operators modeling the set union and intersection + operations. The latter has direct support in the "gdb" debugger, which + will display an enumerated type value as a union of the various + enumerators. The HP simulator makes extensive use of both features to + model hardware signal buses (e.g., INBOUND_SET, OUTBOUND_SET) and so + performs bitwise integer operations on the enumerations to model signal + assertion and denial. In C++, implicit conversion from enumerations to + integers is allowed, but conversion from integers to enumerations is + illegal without explicit casts. Therefore, the idiom employed by the + simulator to assert a signal (e.g., "outbound_signals |= INTREQ") is + rejected by the C++ compiler. + + 3. Implicit increment operations on enums. + + Because enums are compatible with integers in C, no special enumerator + increment operator is provided. To cycle through the range of an + enumeration type, e.g. in a "for" statement, the standard integer + increment operator, "++", is used. In C++, the "++" operator must be + overloaded with a version specific to the enumeration type; applying the + integer "++" to an enumeration is illegal. + + 4. Use of C++ keywords as variable names. + + C++ reserves a number of additional keywords beyond those reserved by C. + Use of any of these keywords as a variable or type name is legal C but + illegal C++. The HP simulator uses variables named "class" and + "operator", which are keywords in C++. + + The HP simulator is written in ISO standard C and will compile cleanly with a + compiler implementing the 1999 C standard. Compilation as C++ is not a goal + of the simulator and cannot work, given the incompatibilities listed above. */ @@ -71,15 +140,16 @@ #elif defined (_MSC_VER) #pragma warning (disable: 4114 4554 4996) + #endif /* Device register display mode flags */ -#define REG_A (1 << REG_V_UF + 0) /* permit any display */ -#define REG_B (1 << REG_V_UF + 1) /* permit binary display */ -#define REG_M (1 << REG_V_UF + 2) /* default to instruction mnemonic display */ -#define REG_S (1 << REG_V_UF + 3) /* default to status mnemonic display */ +#define REG_A (1u << REG_V_UF + 0) /* permit any display */ +#define REG_B (1u << REG_V_UF + 1) /* permit binary display */ +#define REG_M (1u << REG_V_UF + 2) /* default to instruction mnemonic display */ +#define REG_S (1u << REG_V_UF + 3) /* default to status mnemonic display */ /* Register macros. @@ -90,12 +160,12 @@ SRDATA -- an array of bytes large enough to hold a structure YRDATA -- a binary register - The FBDATA macro defines flag bits that are replicated in the same place in - each element of an array; the array element size is assumed to be the minimum - necessary to hold the bit at the given offset. The SRDATA macro is used - solely to SAVE data stored in a structure so that it may be RESTOREd later. - The YRDATA macro extends the functionality of the ORDATA, DRDATA, and HRDATA - macros to registers with binary (base 2) representation. + The FBDATA macro defines a flag that is replicated in the same bit position + in each element of an array; the array element size is assumed to be the + minimum necessary to hold the bit at the given offset. The SRDATA macro is + used solely to SAVE data stored in a structure so that it may be RESTOREd + later. The YRDATA macro extends the functionality of the ORDATA, DRDATA, and + HRDATA macros to registers with binary (base 2) representation. Implementation notes: @@ -107,22 +177,42 @@ offsets 3 and 13 cannot be used, as the first implies 8-bit elements, and the second implies 16-bit elements. - 2. The REG structure for version 4.0 contains two extra fields that are not - present in 3.x versions. + 2. The macro names are UNDEFed to avoid potential name clashes with + sim_def.h macros. + + 3. The REG structure for version 4.0 contains several fields that are not + present in 3.x versions. The 4.x REGDATA macro maps to the REG strcture + in a field-order- and preprocessor-independent manner. There is no + corresponding macro in 3.x, so we must handle standard vs. non-standard + preprocessor differences by creating our own REGMAP macro to handle the + mapping. */ -/* Macro name loc radix width offset depth desc fields */ -/* ---------------------- ---- ------- ----- ----- ------ ---------- ---- ------ */ +#undef FBDATA +#undef SRDATA +#undef YRDATA +#undef REGMAP + #if (SIM_MAJOR >= 4) - #define FBDATA(nm,loc,ofs,dep) #nm, &(loc), 2, 1, (ofs), (dep), NULL, NULL - #define SRDATA(nm,loc) #nm, &(loc), 8, 8, 0, sizeof loc, NULL, NULL - #define YRDATA(nm,loc,wid) #nm, &(loc), 2, (wid), 0, 1, NULL, NULL + #define REGMAP(nm,loc,rdx,wd,off,dep,fl) \ + REGDATA (nm, loc, rdx, wd, off, dep, NULL, NULL, fl, 0, 0) + +#elif defined (__STDC__) || defined (_WIN32) + #define REGMAP(nm,loc,rdx,wd,off,dep,fl) \ + #nm, &(loc), (rdx), (wd), (off), (dep), (fl), 0 + #else - #define FBDATA(nm,loc,ofs,dep) #nm, &(loc), 2, 1, (ofs), (dep) - #define SRDATA(nm,loc) #nm, &(loc), 8, 8, 0, sizeof loc - #define YRDATA(nm,loc,wid) #nm, &(loc), 2, (wid), 0, 1 + #define REGMAP(nm,loc,rdx,wd,off,dep,fl) \ + "nm", &(loc), (rdx), (wd), (off), (dep), (fl), 0 + #endif +/* Macro name loc radix width offset depth flags */ +/* ------------------------- ---- ------ ----- ----- ------ ---------- ----- */ +#define FBDATA(nm,loc,ofs,dep,fl) REGMAP (nm, (loc), 2, 1, (ofs), (dep), (fl) ) +#define SRDATA(nm,loc,fl) REGMAP (nm, (loc), 8, 8, 0, sizeof loc, (fl) ) +#define YRDATA(nm,loc,wid,fl) REGMAP (nm, (loc), 2, (wid), 0, 1, (fl) ) + /* Debugging and console output. @@ -260,13 +350,17 @@ simulator. In addition, masks for 16-bit and 32-bit overflow are defined (an overflow is indicated if the masked bits are not all ones or all zeros). + The HP_WORD type is used to declare variables that represent 16-bit registers + or buses in hardware. + Implementation notes: 1. The HP_WORD type is a 32-bit unsigned type, instead of the more logical - 16-bit unsigned type. This is because IA-32 processors execute - instructions with 32-bit operands much faster than those with 16-bit - operands. + 16-bit unsigned type. There are two reasons for this. First, SCP + requires that scalars referenced by REG (register) entries be 32 bits in + size. Second, IA-32 processors execute instructions with 32-bit operands + much faster than those with 16-bit operands. Using 16-bit operands omits the masking required for 32-bit values. For example, the code generated for the following operations is as follows: @@ -295,7 +389,7 @@ HP 3000 memory diagnostic to run about 10% slower. */ -#define HP_WORD uint32 /* HP 16-bit word representation */ +typedef uint32 HP_WORD; /* HP 16-bit data word representation */ #define R_MASK 0177777u /* 16-bit register mask */ @@ -343,23 +437,23 @@ /* Memory constants */ -#define LA_WIDTH 16 /* logical address bit width */ -#define LA_MASK ((1 << LA_WIDTH) - 1) /* logical address mask (2 ** 16 - 1) */ -#define LA_MAX ((1 << LA_WIDTH) - 1) /* logical address maximum (2 ** 16 - 1) */ +#define LA_WIDTH 16 /* logical address bit width */ +#define LA_MASK ((1u << LA_WIDTH) - 1) /* logical address mask (2 ** 16 - 1) */ +#define LA_MAX ((1u << LA_WIDTH) - 1) /* logical address maximum (2 ** 16 - 1) */ -#define BA_WIDTH 4 /* bank address bit width */ -#define BA_MASK ((1 << BA_WIDTH) - 1) /* bank address mask (2 ** 4 - 1) */ -#define BA_MAX ((1 << BA_WIDTH) - 1) /* bank address maximum (2 ** 4 - 1) */ +#define BA_WIDTH 4 /* bank address bit width */ +#define BA_MASK ((1u << BA_WIDTH) - 1) /* bank address mask (2 ** 4 - 1) */ +#define BA_MAX ((1u << BA_WIDTH) - 1) /* bank address maximum (2 ** 4 - 1) */ -#define PA_WIDTH (LA_WIDTH + BA_WIDTH) /* physical address bit width */ -#define PA_MASK ((1 << PA_WIDTH) - 1) /* physical address mask (2 ** 20 - 1) */ -#define PA_MAX ((1 << PA_WIDTH) - 1) /* physical address maximum (2 ** 20 - 1) */ +#define PA_WIDTH (LA_WIDTH + BA_WIDTH) /* physical address bit width */ +#define PA_MASK ((1u << PA_WIDTH) - 1) /* physical address mask (2 ** 20 - 1) */ +#define PA_MAX ((1u << PA_WIDTH) - 1) /* physical address maximum (2 ** 20 - 1) */ -#define DV_WIDTH 16 /* data value bit width */ -#define DV_MASK ((1 << DV_WIDTH) - 1) /* data value mask (2 ** 16 - 1) */ -#define DV_SIGN (1 << (DV_WIDTH - 1)) /* data value sign (2 ** 15) */ -#define DV_UMAX ((1 << DV_WIDTH) - 1) /* data value unsigned maximum (2 ** 16 - 1) */ -#define DV_SMAX ((1 << (DV_WIDTH - 1)) - 1) /* data value signed maximum (2 ** 15 - 1) */ +#define DV_WIDTH 16 /* data value bit width */ +#define DV_MASK ((1u << DV_WIDTH) - 1) /* data value mask (2 ** 16 - 1) */ +#define DV_SIGN ( 1u << (DV_WIDTH - 1)) /* data value sign (2 ** 15) */ +#define DV_UMAX ((1u << DV_WIDTH) - 1) /* data value unsigned maximum (2 ** 16 - 1) */ +#define DV_SMAX ((1u << (DV_WIDTH - 1)) - 1) /* data value signed maximum (2 ** 15 - 1) */ /* Memory address macros. @@ -372,11 +466,11 @@ - TO_OFFSET -- extract the offset part of a physical address - Implementation notes: + Implementation notes: - 1. The TO_PA offset parameter is not masked to 16 bits, as this value is - almost always derived from a value that is inherently 16 bits in size. In - the few cases where it is not, explicit masking is required. + 1. The TO_PA offset parameter is not masked to 16 bits, as this value is + almost always derived from a value that is inherently 16 bits in size. + In the few cases where it is not, explicit masking is required. */ #define TO_PA(b,o) (((uint32) (b) & BA_MASK) << LA_WIDTH | (uint32) (o)) @@ -465,9 +559,9 @@ typedef enum { SET = 1 /* the flip-flop is set */ } FLIP_FLOP; -#define TOGGLE(ff) ff = (ff ^ 1) /* toggle a flip-flop variable */ +#define TOGGLE(ff) ff = (FLIP_FLOP) (ff ^ 1) /* toggle a flip-flop variable */ -#define D_FF(b) ((b) != 0) /* use a Boolean expression for a D flip-flop */ +#define D_FF(b) (FLIP_FLOP) ((b) != 0) /* use a Boolean expression for a D flip-flop */ /* Bitset formatting. @@ -491,7 +585,7 @@ typedef enum { /* trailing separator */ append_bar /* append a trailing separator */ } BITSET_BAR; -typedef const char *const BITSET_NAME; /* a bit name string pointer */ +typedef const char *const BITSET_NAME; /* a bit name string pointer */ typedef struct { /* bit set format descriptor */ uint32 name_count; /* count of bit names */ @@ -511,7 +605,7 @@ typedef struct { /* bit set format descriptor */ /* System interface global data structures */ -extern const uint16 odd_parity [256]; /* a table of parity bits for odd parity */ +extern const HP_WORD odd_parity [256]; /* a table of parity bits for odd parity */ extern const BITSET_FORMAT inbound_format; /* the inbound signal format structure */ extern const BITSET_FORMAT outbound_format; /* the outbound signal format structure */ diff --git a/HP3000/hp3000_diag.txt b/HP3000/hp3000_diag.txt index 061003e3..ebcf0c9f 100644 --- a/HP3000/hp3000_diag.txt +++ b/HP3000/hp3000_diag.txt @@ -1,6 +1,6 @@ SIMH/HP 3000 DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2016-02-09 + Last update: 2016-05-31 The HP 32230 offline diagnostic suite has been run against the SIMH HP 3000 @@ -57,11 +57,12 @@ The results of the diagnostic runs are summarized below: PD433A 7970B/E Nine-Track Magnetic Tape 01.04 Partial PD434A Synchronous Line Controller 01.03 No simulation PD434B Asynchronous Line Controller 01.04 No simulation - PD435A Universal Interface 01.01 No simulation + PD435A Universal Interface 01.01 Passed PD438A Terminal Control Interface 01.00 Passed PD439A CALCOMP Plotter Interface 01.01 No simulation PD441A COBOL-II A Firmware 00.00 No simulation PD442A COBOL-II B Firmware 00.00 No simulation + PD466A Online Line Printer Verifier 01.06 Passed The "Result" column indicates the level of success in passing the given diagnostic: @@ -92,9 +93,9 @@ Each configuration below presumes that the target diagnostic has been cold loaded from the appropriate magnetic tape. --------------------------------- -D420A - CPU Diagnostic Section 1 --------------------------------- +--------------------- +D420A - CPU Section 1 +--------------------- TESTED DEVICE: CPU (hp3000_cpu.c) @@ -154,9 +155,9 @@ TEST NOTES: The Internal Switch Register (2000) and Section Select Register ---------------------------------- -D420A1 - CPU Diagnostic Section 2 ---------------------------------- +---------------------- +D420A1 - CPU Section 2 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) @@ -173,9 +174,9 @@ TEST NOTES: The Internal Switch Register (2000) and Section Select Register ---------------------------------- -D420A2 - CPU Diagnostic Section 3 ---------------------------------- +---------------------- +D420A2 - CPU Section 3 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) @@ -202,9 +203,9 @@ TEST NOTES: The Internal Switch Register (2000) and Section Select Register ---------------------------------- -D420A3 - CPU Diagnostic Section 4 ---------------------------------- +---------------------- +D420A3 - CPU Section 4 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) @@ -257,9 +258,9 @@ TEST NOTES: The Internal Switch Register (2000) and Section Select Register ---------------------------------- -D420A4 - CPU Diagnostic Section 5 ---------------------------------- +---------------------- +D420A4 - CPU Section 5 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) @@ -276,113 +277,113 @@ TEST NOTES: The Internal Switch Register (2000) and Section Select Register ---------------------------------- -D420A5 - CPU Diagnostic Section 6 ---------------------------------- +---------------------- +D420A5 - CPU Section 6 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010011 (SETR STATUS) +TEST REPORT: System halt 3, P: 010011 (SETR STATUS) TEST RESULT: Passed. ---------------------------------- -D420A6 - CPU Diagnostic Section 7 ---------------------------------- +---------------------- +D420A6 - CPU Section 7 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010011 (SETR STATUS) +TEST REPORT: System halt 33, P: 010011 (SETR STATUS) TEST RESULT: Passed. ---------------------------------- -D420A7 - CPU Diagnostic Section 8 ---------------------------------- +---------------------- +D420A7 - CPU Section 8 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010014 (PCAL 0) +TEST REPORT: System halt 13, P: 010014 (PCAL 0) TEST RESULT: Passed. ---------------------------------- -D420A8 - CPU Diagnostic Section 9 ---------------------------------- +---------------------- +D420A8 - CPU Section 9 +---------------------- TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010016 (PCAL 0) +TEST REPORT: System halt 2, P: 010016 (PCAL 0) TEST RESULT: Passed. ----------------------------------- -D420A9 - CPU Diagnostic Section 10 ----------------------------------- +----------------------- +D420A9 - CPU Section 10 +----------------------- TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010052 (IXIT) +TEST REPORT: System halt 6, P: 010052 (IXIT) TEST RESULT: Passed. ------------------------------------ -D420A10 - CPU Diagnostic Section 11 ------------------------------------ +------------------------ +D420A10 - CPU Section 11 +------------------------ TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010011 (PSEB) +TEST REPORT: System halt 9, P: 010011 (PSEB) TEST RESULT: Passed. ------------------------------------ -D420A11 - CPU Diagnostic Section 12 ------------------------------------ +------------------------ +D420A11 - CPU Section 12 +------------------------ TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010005 (SETR STATUS) +TEST REPORT: System halt 1, P: 010005 (SETR STATUS) TEST RESULT: Passed. ------------------------------------ -D420A12 - CPU Diagnostic Section 13 ------------------------------------ +------------------------ +D420A12 - CPU Section 13 +------------------------ TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010010 (ADDS 0) +TEST REPORT: System halt 4, P: 010010 (ADDS 0) TEST RESULT: Passed. @@ -396,15 +397,15 @@ TESTED DEVICE: CPU (hp3000_cpu.c) CONFIGURATION: sim> go -TEST REPORT: System halt, P: 010003 (LDI 0) +TEST REPORT: System halt 4, P: 010003 (LDI 0) TEST RESULT: Passed. ------------------------------------------- -D419A - 7905A Disc Cartridge (interactive) ------------------------------------------- +----------------------------------------- +D419A - Cartridge Disc (user interaction) +----------------------------------------- TESTED DEVICE: DS (hp3000_ds.c) @@ -582,9 +583,9 @@ TEST NOTES: The diagnostic overrides supply the expected status returns for --------------------------------------------- -D419A - 7905A Disc Cartridge (multiple unit) --------------------------------------------- +-------------------------------------------------- +D419A - Cartridge Disc (multiple unit, short pass) +-------------------------------------------------- TESTED DEVICE: DS (hp3000_ds.c) @@ -665,9 +666,9 @@ TEST NOTES: Section 1 is not selected to avoid specifying diagnostic ----------------------- -D421A - Memory Pattern ----------------------- +-------------------------- +D421 - Memory Pattern Test +-------------------------- TESTED DEVICE: CPU (hp3000_cpu.c) @@ -1128,9 +1129,9 @@ TEST RESULT: Passed. -------------------------------------------------------------- -D433A - 7970B/E Nine-Track Magnetic Tape (7970B, single unit) -------------------------------------------------------------- +---------------------------------------------------- +D433A - 7970B Nine-Track Magnetic Tape (single unit) +---------------------------------------------------- TESTED DEVICE: MS (hp3000_ms.c) @@ -1153,8 +1154,8 @@ TEST REPORT: [CR entered] A'CR'-AUTO, R'CR'-RESTART, M'CR'-MANU, 'CR'-RESUME, YOUR CODE? A D015 PRESENT SECTION REGISTER:%077414 DO YOU WISH TO CHANGE?(YES/NO)YES - D015 UPDATE SECTION REGISTER:%067414 - D015 PRESENT SECTION REGISTER:%067414 DO YOU WISH TO CHANGE?(YES/NO)NO + D015 UPDATE SECTION REGISTER:%067400 + D015 PRESENT SECTION REGISTER:%067400 DO YOU WISH TO CHANGE?(YES/NO)NO Q019 AUTO-PROCESS: ENTER TAPE UNIT(B,E,NO) AT Q020 DRIVE 0? B @@ -1196,9 +1197,9 @@ TEST NOTES: Section 3 (tape mark tests) is not selected, as the simulation ---------------------------------------------------------------- -D433A - 7970B/E Nine-Track Magnetic Tape (7970E, multiple unit) ---------------------------------------------------------------- +------------------------------------------------------ +D433A - 7970E Nine-Track Magnetic Tape (multiple unit) +------------------------------------------------------ TESTED DEVICE: MS (hp3000_ms.c) @@ -1223,7 +1224,9 @@ TEST REPORT: [CR entered] P005 TYPE FOLLOWING CONTROL A'CR'-AUTO, R'CR'-RESTART, M'CR'-MANU, 'CR'-RESUME, YOUR CODE? A - D015 PRESENT SECTION REGISTER:%077414 DO YOU WISH TO CHANGE?(YES/NO)NO + D015 PRESENT SECTION REGISTER:%077414 DO YOU WISH TO CHANGE?(YES/NO)YES + D015 UPDATE SECTION REGISTER:%077400 + D015 PRESENT SECTION REGISTER:%077400 DO YOU WISH TO CHANGE?(YES/NO)NO Q019 AUTO-PROCESS: ENTER TAPE UNIT(B,E,NO) AT Q020 DRIVE 0? E @@ -1264,9 +1267,9 @@ TEST RESULT: Passed. -------------------------------------------------------------- -D433A - 7970B/E Nine-Track Magnetic Tape (7970E, interactive) -------------------------------------------------------------- +--------------------------------------------------------- +D433A - 7970E Nine-Track Magnetic Tape (user interaction) +--------------------------------------------------------- TESTED DEVICE: MS (hp3000_ms.c) @@ -1534,6 +1537,289 @@ TEST RESULT: Passed. +--------------------------- +D435A - Universal Interface +--------------------------- + +TESTED DEVICE: LP (hp3000_lp.c) + +CONFIGURATION: sim> set lp diagnostic,intmask=8 + sim> set clk realtime + sim> go + +TEST REPORT: D100 UNIV. INTERFACE TEST (HP D435A.01.01) + (C)COPYRIGHT HEWLETT PACKARD COMPANY 1976. + ****************** WARNING ****************** + this diagnostic has tests which will produce error + conditions on interface boards which have datecodes + PRIOR TO 1504. + + Q110 DEVICE NUMBER? 14 + Q112 INTERRUPT MASK? 8 + Q113 NEGATIVE TRUE? NO + Q114 CHANGE INTERNAL SWITCH REGISTER? ? YES + P114 INTERNAL SWITCH REGISTER + + Programmed halt, CIR: 030366 (HALT 6), P: 026015 (DDEL,DDEL) + + sim> deposit SWCH 100111 + sim> go + + Q115 SECTION LIST? + Q116 READER-PUNCH INTERFACE ? NO + D102 END SECTION 0 + + D100 UNIV. INTERFACE TEST (HP D435A.01.01) + (C)COPYRIGHT HEWLETT PACKARD COMPANY 1976. + ****************** WARNING ****************** + this diagnostic has tests which will produce error + conditions on interface boards which have datecodes + PRIOR TO 1504. + P120 CONT6 ON, REST OFF + + Programmed halt, CIR: 030367 (HALT 7), P: 022145 (DDEL,DDEL) + + sim> assert LP CONT=10000 + sim> go + + P120 CONT7 ON, REST OFF + + Programmed halt, CIR: 030367 (HALT 7), P: 022145 (DDEL,DDEL) + + sim> assert LP CONT=01000 + sim> go + + P120 CONT8 ON, REST OFF + + Programmed halt, CIR: 030367 (HALT 7), P: 022145 (DDEL,DDEL) + + sim> assert LP CONT=00100 + sim> go + + P120 CONT9 ON, REST OFF + + Programmed halt, CIR: 030367 (HALT 7), P: 022145 (DDEL,DDEL) + + sim> assert LP CONT=00010 + sim> go + + P120 CONT10 ON, REST OFF + + Programmed halt, CIR: 030367 (HALT 7), P: 022145 (DDEL,DDEL) + + sim> assert LP CONT=00001 + sim> go + + P121 JUMPER J2W1 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0000000001 + sim> go + + P121 JUMPER J2W2 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0000000010 + sim> go + + P121 JUMPER J2W3 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0000000100 + sim> go + + P121 JUMPER J2W4 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0000001000 + sim> go + + P121 JUMPER J2W5 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0000010000 + sim> go + + P121 JUMPER J2W6 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0000100000 + sim> go + + P121 JUMPER J2W7 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0001000000 + sim> go + + P121 JUMPER J2W8 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0010000000 + sim> go + + P121 JUMPER J2W9 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=0100000000 + sim> go + + P121 JUMPER J2W10 LOW, REST HIGH + + Programmed halt, CIR: 030370 (HALT 10), P: 022056 (DDEL,DDEL) + + sim> assert LP J2WX=1000000000 + sim> go + + P122 DEVICE END ASSERTED + + Programmed halt, CIR: 030371 (HALT 11), P: 021505 (DDEL,DDEL) + + sim> assert LP DEVEND=1 + sim> go + + P124 BIT 0 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=100000 + sim> go + + P124 BIT 1 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=040000 + sim> go + + P124 BIT 2 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=020000 + sim> go + + P124 BIT 3 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=010000 + sim> go + + P124 BIT 4 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=004000 + sim> go + + P124 BIT 5 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=002000 + sim> go + + P124 BIT 6 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=001000 + sim> go + + P124 BIT 7 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000400 + sim> go + + P124 BIT 8 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000200 + sim> go + + P124 BIT 9 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000100 + sim> go + + P124 BIT 10 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000040 + sim> go + + P124 BIT 11 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000020 + sim> go + + P124 BIT 12 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000010 + sim> go + + P124 BIT 13 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000004 + sim> go + + P124 BIT 14 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000002 + sim> go + + P124 BIT 15 HIGH, REST LOW + + Programmed halt, CIR: 030373 (HALT 13), P: 021407 (DDEL,DDEL) + + sim> assert LP READ=000001 + sim> go + + D102 END SECTION 1 + D102 END SECTION 2 + D102 END SECTION 3 + D102 END SECTION 4 + D102 END SECTION 5 + D102 END SECTION 6 + D102 END SECTION 7 + D102 END SECTION 8 + D102 END SECTION 9 + D102 END SECTION 10 + P103 PASS 1 + + Programmed halt, CIR: 030375 (HALT 15), P: 010265 (DDEL,DDEL) + +TEST RESULT: Passed. + +TEST NOTES: The interrupt mask number is changed from "E" (always enabled) to + a numeric value to allow the mask circuits to be tested. + + + ---------------------------------- D438A - Terminal Control Interface ---------------------------------- @@ -1562,3 +1848,56 @@ TEST REPORT: Programmed halt, CIR: 030366 (HALT 6), P: 010670 (LRA P+4) Programmed halt, CIR: 030375 (HALT 15), P: 010225 (BR P+7) TEST RESULT: Passed. + + + +------------------------------------ +D466A - Online Line Printer Verifier +------------------------------------ + +TESTED DEVICE: LP (hp3000_lp.c) + +CONFIGURATION: :STOPSPOOL 6 + :RUN PD466A.HP32230.SUPPORT + +TEST REPORT: D1 ONLINE LINE PRINTER VERIFIER (HP D466A.01.06) + (C) COPYRIGHT HEWLETT-PACKARD COMPANY 1978. + PRINTER MUST BE SET TO 6 LINES PER INCH + Q1 WHICH MODEL? 2607/08/10/13/14/17/18/19: 2617 + Q2 64/96 CHARACTER SET?96 + Q3 LOGICAL DEVICE ?6 + Q4 FLAGS? + PRESS 'ON/OFF' LINE SWITCH 'ON' THEN 'OFF' + D7 PRESS 'CR' TO CONTINUE + + [CTRL+E] + + Simulation stopped, P: 071144 (PAUS 0) + + sim> set lp offline + sim> go + + 19:44/3/LDEV #6 NOT READY + COMPUTER CONSOLE SHOULD PRINT 'IO/X:XX/LDEV# XXX NOT READY' + PRESS 'ON/OFF' SWITCH 'ON' + D7 PRESS 'CR' TO CONTINUE + + [CTRL+E] + + Simulation stopped, P: 071144 (PAUS 0) + + sim> set lp online + sim> go + + D6 END OF SECTION 1 + D6 END OF SECTION 2 + D6 END OF SECTION 3 + D6 END OF SECTION 4 + D6 END OF SECTION 5 + D6 END OF SECTION 6 + D6 END OF SECTION 7 + LINE PRINTER VERIFIER TEST TERMINATED + + END OF PROGRAM + +TEST RESULT: Passed. diff --git a/HP3000/hp3000_ds.c b/HP3000/hp3000_ds.c index d9ebaf6a..e7b0b405 100644 --- a/HP3000/hp3000_ds.c +++ b/HP3000/hp3000_ds.c @@ -25,7 +25,12 @@ DS HP 30229B Cartridge Disc Interface + 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 13-May-16 JDB Modified for revised SCP API function parameter types + 24-Mar-16 JDB Changed the buffer element type from uint16 to DL_BUFFER + 21-Mar-16 JDB Changed uint16 types to HP_WORD 21-Jul-15 JDB First release version 15-Jun-15 JDB Passes the cartridge disc diagnostic (D419A) 15-Feb-15 JDB Created @@ -237,7 +242,7 @@ /* Debug flags (interface-specific) */ #define DEB_IOB DL_DEB_IOB /* trace I/O bus signals and data words */ -#define DEB_CSRW (1 << DL_DEB_V_UF + 0) /* trace control, status, read, and write commands */ +#define DEB_CSRW (1u << DL_DEB_V_UF + 0) /* trace control, status, read, and write commands */ /* Control word. @@ -252,13 +257,13 @@ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CN_MR 0100000 /* (M) master reset */ -#define CN_RIN 0040000 /* (R) reset interrupt */ -#define CN_TEST 0020000 /* (T) test mode */ +#define CN_MR 0100000u /* (M) master reset */ +#define CN_RIN 0040000u /* (R) reset interrupt */ +#define CN_TEST 0020000u /* (T) test mode */ -#define CN_WAIT 0000001 /* (W) wait for data */ +#define CN_WAIT 0000001u /* (W) wait for data */ -#define CN_OPCODE_MASK 0017400 /* command word opcode mask */ +#define CN_OPCODE_MASK 0017400u /* command word opcode mask */ #define CN_OPCODE_SHIFT 8 /* controller opcode alignment shift */ @@ -282,11 +287,11 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define ST_SIO_OK 0100000 /* (S) SIO OK to use */ -#define ST_TEST 0040000 /* (T) test mode enabled */ -#define ST_INTREQ 0020000 /* (I) interrupt requested */ -#define ST_STATUS_MASK 0017400 /* encoded termination status mask */ -#define ST_UNIT_MASK 0000017 /* unit number mask */ +#define ST_SIO_OK 0100000u /* (S) SIO OK to use */ +#define ST_TEST 0040000u /* (T) test mode enabled */ +#define ST_INTREQ 0020000u /* (I) interrupt requested */ +#define ST_STATUS_MASK 0017400u /* encoded termination status mask */ +#define ST_UNIT_MASK 0000017u /* unit number mask */ #define ST_MASK ~(ST_SIO_OK | ST_TEST | ST_INTREQ) @@ -295,8 +300,8 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt #define ST_STATUS(n) ((n) << ST_STATUS_SHIFT & ST_STATUS_MASK) -#define ST_TO_UNIT(s) (((s) & ST_UNIT_MASK) >> ST_UNIT_SHIFT) -#define ST_TO_STATUS(s) (((s) & ST_STATUS_MASK) >> ST_STATUS_SHIFT) +#define ST_TO_UNIT(s) (((s) & ST_UNIT_MASK) >> ST_UNIT_SHIFT) +#define ST_TO_STATUS(s) (CNTLR_STATUS) (((s) & ST_STATUS_MASK) >> ST_STATUS_SHIFT) static const BITSET_NAME status_names [] = { /* Status word names */ @@ -334,7 +339,7 @@ static FLIP_FLOP sio_busy = CLEAR; /* SIO busy flip-flop */ static FLIP_FLOP device_sr = CLEAR; /* device service request flip-flop */ static FLIP_FLOP input_xfer = CLEAR; /* input transfer flip-flop */ static FLIP_FLOP output_xfer = CLEAR; /* output transfer flip-flop */ -static FLIP_FLOP interrupt_mask = CLEAR; /* interrupt mask flip-flop */ +static FLIP_FLOP interrupt_mask = SET; /* interrupt mask flip-flop */ static FLIP_FLOP jump_met = CLEAR; /* jump met flip-flop */ static FLIP_FLOP device_end = CLEAR; /* device end flip-flop */ static FLIP_FLOP data_overrun = CLEAR; /* data overrun flip-flop */ @@ -342,12 +347,12 @@ static FLIP_FLOP end_of_data = CLEAR; /* end of data flip-flop */ static FLIP_FLOP test_mode = CLEAR; /* test mode flip-flop */ static FLIP_FLOP data_wait = CLEAR; /* wait flip-flop */ -static uint16 status_word = 0; /* status register */ -static uint16 buffer_word = 0; /* data buffer register */ -static uint16 retry_counter = 0; /* retry counter */ -static CNTLR_FLAG_SET flags = 0; /* disc controller interface flag set */ +static HP_WORD status_word = 0; /* status register */ +static HP_WORD buffer_word = 0; /* data buffer register */ +static HP_WORD retry_counter = 0; /* retry counter */ +static CNTLR_FLAG_SET flags = NO_FLAGS; /* disc controller interface flag set */ -static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ +static DL_BUFFER buffer [DL_BUFSIZE]; /* command/status/sector buffer */ DEVICE ds_dev; /* incomplete device structure */ @@ -433,8 +438,8 @@ static REG ds_reg [] = { { ORDATA (STATUS, status_word, 16), REG_FIT | PV_RZRO }, { DRDATA (RETRY, retry_counter, 4), REG_FIT | PV_LEFT }, - { SRDATA (DIAG, overrides), REG_HRO }, - { SRDATA (DIB, ds_dib), REG_HRO }, + { SRDATA (DIAG, overrides, REG_HRO) }, + { SRDATA (DIB, ds_dib, REG_HRO) }, DL_REGS (mac_cntlr, ds_unit, UNIT_COUNT, buffer, fast_times), @@ -581,11 +586,11 @@ DEVICE ds_dev = { the request. */ -static SIGNALS_DATA ds_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA ds_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (ds_dev, DEB_IOB, "Received data %06o with signals %s\n", @@ -614,8 +619,11 @@ while (working_set) { case DSETMASK: - interrupt_mask = (dibptr->interrupt_mask /* set the mask flip-flop */ - & inbound_value) != 0; /* from the mask bit and the mask value */ + if (dibptr->interrupt_mask == INTMASK_E) /* if the mask is always enabled */ + interrupt_mask = SET; /* then set the mask flip-flop */ + else /* otherwise */ + interrupt_mask = D_FF (dibptr->interrupt_mask /* set the mask flip-flop if the mask bit */ + & inbound_value); /* is present in the mask value */ if (interrupt_mask && dibptr->interrupt_request) /* if the mask is enabled and a request is pending */ outbound_signals |= INTREQ; /* then assert the INTREQ signal */ @@ -632,7 +640,7 @@ while (working_set) { if (inbound_value & CN_RIN) /* if the reset interrupt bit is set */ dibptr->interrupt_request = CLEAR; /* then clear the interrupt request */ - test_mode = (inbound_value & CN_TEST) != 0; /* set the test mode flip-flop from the test bit */ + test_mode = D_FF (inbound_value & CN_TEST); /* set the test mode flip-flop from the test bit */ break; @@ -649,7 +657,7 @@ while (working_set) { if (dibptr->interrupt_request == SET) /* if an interrupt request is pending */ outbound_value |= ST_INTREQ; /* then add the IRQ status bit */ - dprintf (ds_dev, DEB_CSRW, "Status is %s%s | unit %d\n", + dprintf (ds_dev, DEB_CSRW, "Status is %s%s | unit %u\n", fmt_bitset (outbound_value, status_format), dl_status_name (ST_TO_STATUS (outbound_value)), ST_TO_UNIT (outbound_value)); @@ -715,7 +723,7 @@ while (working_set) { case PCMD1: - data_wait = inbound_value & CN_WAIT; /* set the wait flip-flop from the supplied value */ + data_wait = D_FF (inbound_value & CN_WAIT); /* set the wait flip-flop from the supplied value */ if (data_wait == SET) /* if the wait flip-flip is set */ flags |= DTRDY; /* then the data ready flag is forced true */ @@ -797,7 +805,7 @@ while (working_set) { if (device_end == SET) { /* if the device end flip-flop is set */ outbound_signals |= DEVEND | CHANSR; /* then assert DEVEND and CHANSR to the channel */ - device_end = input_xfer | output_xfer; /* clear device end if the transfer has stopped */ + device_end = D_FF (input_xfer | output_xfer); /* clear device end if the transfer has stopped */ } else if (device_sr == SET || test_mode == SET) /* if the interface requests service */ @@ -851,7 +859,7 @@ static t_stat ds_service (UNIT *uptr) dprintf (ds_dev, DL_DEB_SERV, (uptr == &ds_cntlr ? "Controller unit service entered\n" : "Unit %d service entered\n"), - uptr - &ds_unit [0]); + (int32) (uptr - &ds_unit [0])); call_controller (uptr); /* call the controller */ @@ -1221,8 +1229,8 @@ else /* otherwise */ do { /* call the controller potentially more than once */ - result = dl_controller (&mac_cntlr, uptr, /* to start or continue a command */ - flag_set, buffer_word); + result = /* to start or continue a command */ + dl_controller (&mac_cntlr, uptr, flag_set, (CNTLR_IBUS) buffer_word); command_set = DLIFN (result) & ~UNUSED_COMMANDS; /* strip the commands we don't use as an efficiency */ @@ -1236,7 +1244,7 @@ do { /* call the controller p data_overrun = SET; /* then this input overruns it */ else { /* otherwise the buffer is empty */ - device_sr = ! end_of_data; /* so request the next word unless EOT */ + device_sr = D_FF (! end_of_data); /* so request the next word unless EOT */ if ((input_xfer == CLEAR /* if not configured to read */ || output_xfer == SET) /* or configured to write */ diff --git a/HP3000/hp3000_io.h b/HP3000/hp3000_io.h index cce06fa1..015234da 100644 --- a/HP3000/hp3000_io.h +++ b/HP3000/hp3000_io.h @@ -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. + 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 11-Dec-12 JDB Created @@ -141,7 +143,7 @@ typedef enum { /* --- source of signal --- */ /* = 020000000000 (available) */ } INBOUND_SIGNAL; -typedef INBOUND_SIGNAL INBOUND_SET; /* a set of INBOUND_SIGNALs */ +typedef INBOUND_SIGNAL INBOUND_SET; /* a set of INBOUND_SIGNALs */ typedef enum { /* --- destination of signal --- */ @@ -163,10 +165,10 @@ typedef enum { /* --- destination of signal --- /* = 020000000000 (available) */ } OUTBOUND_SIGNAL; -typedef OUTBOUND_SIGNAL OUTBOUND_SET; /* a set of OUTBOUND_SIGNALs */ +typedef OUTBOUND_SIGNAL OUTBOUND_SET; /* a set of OUTBOUND_SIGNALs */ -typedef uint32 SIGNALS_DATA; /* a combined outbound signal set and data value */ +typedef uint32 SIGNALS_DATA; /* a combined outbound signal set and data value */ /* I/O macros. @@ -224,11 +226,11 @@ typedef uint32 SIGNALS_DATA; /* a combined outbound signal se #define IOPRIORITY(P) ((P) & ~(P) + 1) #define IONEXTSIG(S) ((INBOUND_SIGNAL) IOPRIORITY (S)) -#define IOCLEARSIG(S,L) S ^= (L) +#define IOCLEARSIG(S,L) S = (INBOUND_SIGNAL) ((S) ^ (L)) #define IORETURN(S,D) ((SIGNALS_DATA) ((S) & ~D16_MASK | (D) & D16_MASK)) #define IOSIGNALS(C) ((OUTBOUND_SET) ((C) & ~D16_MASK)) -#define IODATA(C) ((uint16) ((C) & D16_MASK)) +#define IODATA(C) ((HP_WORD) ((C) & D16_MASK)) /* I/O structures. @@ -270,33 +272,33 @@ typedef uint32 SIGNALS_DATA; /* a combined outbound signal se */ #define DEVNO_MAX 127 /* the maximum device number */ -#define DEVNO_MASK 0177 /* the mask for the device number */ +#define DEVNO_MASK 0177u /* the mask for the device number */ #define DEVNO_BASE 10 /* the radix for the device number */ #define DEVNO_UNUSED D32_UMAX /* the unused device number indicator */ #define INTMASK_MAX 15 /* the maximum interrupt mask number */ -#define INTMASK_MASK 017 /* the mask for the interrupt mask number */ +#define INTMASK_MASK 017u /* the mask for the interrupt mask number */ #define INTMASK_BASE 10 /* the radix for the interrupt mask number */ -#define INTMASK_D 0000000 /* the interrupt mask disabled always value */ -#define INTMASK_E 0177777 /* the interrupt mask enabled always value */ +#define INTMASK_D 0000000u /* the interrupt mask disabled always value */ +#define INTMASK_E 0177777u /* the interrupt mask enabled always value */ #define INTMASK_UNUSED D32_UMAX /* the unused interrupt mask indicator */ #define INTPRI_MAX 31 /* the maximum interrupt priority */ -#define INTPRI_MASK 037 /* the mask for the interrupt priority */ +#define INTPRI_MASK 037u /* the mask for the interrupt priority */ #define INTPRI_BASE 10 /* the radix for the interrupt priority */ #define INTPRI_UNUSED D32_UMAX /* the unused interrupt priority indicator */ #define SRNO_MAX 15 /* the maximum service request number */ -#define SRNO_MASK 017 /* the mask for the service request number */ +#define SRNO_MASK 017u /* the mask for the service request number */ #define SRNO_BASE 10 /* the radix for the service request number */ #define SRNO_UNUSED D32_UMAX /* the unused service request number indicator */ -typedef struct dib DIB; /* an incomplete definition */ +typedef struct dib DIB; /* an incomplete definition */ typedef SIGNALS_DATA CNTLR_INTRF /* the I/O device controller interface function prototype */ (DIB *dibptr, /* a pointer to the device information block */ INBOUND_SET inbound_signals, /* a set of inbound signals */ - uint16 inbound_value); /* a 16-bit inbound value */ + HP_WORD inbound_value); /* a 16-bit inbound value */ struct dib { /* the Device Information Block */ CNTLR_INTRF *io_interface; /* the controller I/O interface function pointer */ diff --git a/HP3000/hp3000_iop.c b/HP3000/hp3000_iop.c index ec34dd24..fb01c932 100644 --- a/HP3000/hp3000_iop.c +++ b/HP3000/hp3000_iop.c @@ -25,6 +25,8 @@ IOP HP 3000 Series III I/O Processor + 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 28-Aug-15 JDB First release version 11-Dec-12 JDB Created @@ -191,10 +193,10 @@ 1. Bit 0 is reserved for the memory data trace flag. */ -#define DEB_DIO (1 << 1) /* trace direct I/O commands */ -#define DEB_IRQ (1 << 2) /* trace interrupt requests */ +#define DEB_DIO (1u << 1) /* trace direct I/O commands */ +#define DEB_IRQ (1u << 2) /* trace interrupt requests */ -#define FILTER(d) (1 << (d) % 32 & filter [(d) / 32]) +#define FILTER(d) (1u << (d) % 32 & filter [(d) / 32]) /* IOP global data structures */ @@ -262,8 +264,8 @@ uint32 iop_interrupt_request_set = 0; /* the set of interfaces request static uint32 IOA = 0; /* I/O Address Register */ static uint32 interrupt_poll_set = 0; /* the set of interfaces breaking the poll chain */ -static DIB *devs [DEVNO_MAX + 1]; /* index by device number for I/O instruction dispatch */ -static DIB *irqs [INTPRI_MAX + 1]; /* index by interrupt priority number for interrupt requests */ +static DIB *devs [DEVNO_MAX + 1]; /* index by device number for I/O instruction dispatch */ +static DIB *irqs [INTPRI_MAX + 1]; /* index by interrupt priority number for interrupt requests */ static uint32 filter [4] = { /* filter bitmap for device numbers 0-127 */ TRACE_ALL, @@ -299,10 +301,10 @@ static UNIT iop_unit [] = { /* a dummy unit to satisfy SCP r */ static REG iop_reg [] = { -/* Macro Name Location Width Flags */ -/* ------ ------ -------- ----- ------- */ - { ORDATA (IOA, IOA, 8), REG_RO }, /* I/O Address Register */ - { SRDATA (FILTER, filter), REG_HRO }, +/* Macro Name Location Radix Width Depth Flags */ +/* ------ ------ -------- ----- ----- ----- ------- */ + { ORDATA (IOA, IOA, 8), REG_RO }, + { BRDATA (FILTER, filter, 2, 32, 4), REG_HRO }, { NULL } }; @@ -530,7 +532,7 @@ if (outbound & INTACK) { /* if the interface ackn CPX1 |= cpx1_EXTINTR; /* and tell the CPU */ dprintf (iop_dev, FILTER (dibptr->device_number) ? DEB_IRQ : 0, - "Device number %d acknowledged interrupt request at priority %d\n", + "Device number %u acknowledged interrupt request at priority %u\n", dibptr->device_number, ipn); } @@ -539,7 +541,7 @@ else if (outbound & INTPOLLOUT) { /* otherwise if the inte interrupt_poll_set &= ~priority_mask; /* and the associated bit in the poll set */ dprintf (iop_dev, FILTER (dibptr->device_number) ? DEB_IRQ : 0, - "Device number %d canceled interrupt request at priority %d\n", + "Device number %u canceled interrupt request at priority %u\n", dibptr->device_number, ipn); } @@ -615,7 +617,7 @@ if (io_cmd == ioSMSK) { /* if the I/O order && dibptr->interrupt_mask != INTMASK_UNUSED) { /* and uses the interrupt mask */ dprintf (iop_dev, FILTER (devno) ? DEB_DIO : 0, - "%s order sent to device number %d\n", + "%s order sent to device number %u\n", io_command_name [io_cmd], devno); outbound = @@ -637,7 +639,7 @@ else { /* otherwise a devic device_number = device_number & DEVNO_MASK; /* restrict the device number to 0-127 */ dprintf (iop_dev, FILTER (device_number) ? DEB_DIO : 0, - "%s order sent to device number %d\n", + "%s order sent to device number %u\n", io_command_name [io_cmd], device_number); dibptr = devs [device_number]; /* get the device information block pointer */ @@ -682,7 +684,7 @@ void iop_assert_INTREQ (DIB *dibptr) uint32 irq; dprintf (iop_dev, FILTER (dibptr->device_number) ? DEB_IRQ : 0, - "Device number %d asserted INTREQ at priority %d\n", + "Device number %u asserted INTREQ at priority %u\n", dibptr->device_number, dibptr->interrupt_priority); if (dibptr->interrupt_priority != INTPRI_UNUSED) { /* if the interrupt priority is valid */ @@ -743,7 +745,7 @@ if (value == 1) { /* if we are setting the if ((cptr == NULL) || (*cptr == '\0')) /* then if a line range was not supplied */ return SCPE_MISVAL; /* then report a "Missing value" error */ - mptr = malloc (strlen (cptr) + 2); /* allocate space for the string, a semicolon, and a NUL */ + mptr = (char *) malloc (strlen (cptr) + 2); /* allocate space for the string, a semicolon, and a NUL */ if (mptr == NULL) /* if the allocation failed */ return SCPE_MEM; /* report memory exhaustion */ diff --git a/HP3000/hp3000_lp.c b/HP3000/hp3000_lp.c new file mode 100644 index 00000000..9d6db35d --- /dev/null +++ b/HP3000/hp3000_lp.c @@ -0,0 +1,3671 @@ +/* hp3000_lp.c: HP 3000 30209A Line Printer Interface simulator + + Copyright (c) 2016, 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 + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be used + in advertising or otherwise to promote the sale, use or other dealings in + this Software without prior written authorization from the author. + + LP HP 30209A Line Printer Interface + + 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) + 24-Mar-16 JDB Created + + References: + - 30051A Universal Interface (Differential) Maintenance Manual + (30051-90001, May 1976) + - Installation and Service Manual for Line Printer Subsystems + (30209-90006, May 1976) + - Line Printer Operating and Programming Manual + (30209-90008, June 1976) + - HP 3000 Series III Engineering Diagrams Set + (30000-90141, April 1980) + + + The HP 30118A, 30127A, 30128A, and 30133A Line Printer Subsystems connect the + 2607A, 2613A, 2618A, and 2617A printers, respectively, to the HP 3000. Each + subsystem consists of a 30209A Line Printer Controller, employing a 30051A + Universal Interface (Differential) and interconnecting cable, and an HP + 2607A (200 lines per minute), HP 2613 (300 lpm), HP 2617 (600 lpm), or HP + 2618 (1250 lpm) line printer. These subsystems employ the Multiplexer + Channel to achieve a 360 KB/second transfer rate from the CPU. + + This module simulates three hardware devices: + + - the HP 30051A Universal Interface (Differential) + - the HP 30049C Diagnostic Hardware Assembly + - the HP 2607A/13A/17A/18A line printer and 30209-60004 printer cable + + Available with either differential or TTL I/O logic levels, the Universal + Interface (UI) provides a 16-bit bidirectional parallel connection between a + device and the HP 3000 system. Both direct and programmed I/O via the + Multiplexer Channel are supported, word or byte transfers may be selected, + and byte packing and unpacking is available. In addition to the 16-bit data + path, a five-bit control word is supplied to the device, and an eight-bit + status word is returned. Flexible configuration of interface operation is + provided via ten jumpers, and eight different interrupt sources are + available. The Universal Interface is also used to connect the paper tape + reader, punch, and card reader to the HP 3000. + + The Diagnostic Hardware Assembly (DHA) connects to the UI device connectors + and provides a programmable loopback and configuration capability. Five LEDs + continuously display the device control word, and test points are provided to + monitor the state of the 16-bit data path, the ten programmable jumper + settings, and the Device Command, Device Flag, and Device End signals. + Enabling the diagnostic mode simulates the installation of the DHA in place + of the printer device cable. + + The interface supports a single line printer. The supported printers are + configured with Option 001, which provides a 128 (2607) or 96 (2613/17/18) + character set. Two output modes are provided: an expanded mode that is + suitable for retaining printer output as a text file, and a compact mode that + is suitable for sending the printer output to a host-connected physical + printer. An 8-channel (2607) or 12-channel (2613/17/18) Vertical Format Unit + is supported, and custom VFU tape images may be loaded from properly + formatted host-system text files. + + The printer supports realistic and optimized (fast) timing modes. Realistic + timing attempts to model the print buffer load and print-and-space operation + delays inherent in the physical hardware. For example, in REALTIME mode, + output of longer lines takes more time than output of shorter lines, and + spacing six lines takes approximately six times longer than spacing one line. + In FASTTIME mode, all timings are reduced to be "just long enough" to satisfy + MPE software driver requirements. + + + In hardware, the ten UI configuration jumpers perform these functions: + + Jumper Interpretation when removed Interpretation when installed + ------ ------------------------------- ------------------------------ + W1 SR set by PCONTSTB SR set by Device Status bit 11 + + W2 Flag asserts on leading edge Flag asserts on trailing edge + + W3 Command uses response mode Command uses pulse mode + + W4 inhibit IRQ on Device Status enable IRQ on Device Status + bit 8 leading edge bit 8 leading edge + + W5 DATA IN latched on Flag DATA IN always transparent + + W6 Flag denies on trailing edge Flag denies on leading edge + + W7 normal byte-mode write transfer test byte-mode write transfer + + W8 inhibit IRQ on Device Status enable IRQ on Device Status + bit 9 leading edge bit 9 leading edge + + W9 inhibit IRQ on Device Status enable IRQ on Device Status + bit 10 trailing edge bit 10 trailing edge + + W10 DEV CMD polarity is normal DEV CMD polarity is inverted + + The line printer cable is wired with this configuration: + + Interface Connection Printer Connection + ---------------------------------------- ------------------ + Data Out bit 15 DATA 1 + Data Out bit 14 DATA 2 + Data Out bit 13 DATA 3 + Data Out bit 12 DATA 4 + Data Out bit 11 DATA 5 + Data Out bit 10 DATA 6 + Data Out bit 9 DATA 7 + Device Command STROBE + Device Flag ~DEMAND + Control Word bit 10 PAPER INSTRUCTION + Device Status bit 9 ONLINE + Device Status bit 10 ONLINE + Device Status bit 11 ~READY + Device Status bit 12 VFU CHANNEL 12 + Device Status bit 13 VFU CHANNEL 9 + Device End ~ONLINE + Set Transfer Error Flip-Flop (no connection) + Master Clear MASTER CLEAR + + Internal Connection Action + ---------------------------------------- -------------------------------- + 300 pF across the Write Delay One-Shot sets 1.2 uS pulse width + 1500 pF across the Master Clear One-Shot sets 5.1 uS pulse width + jumper W4 shorted none (Status 8 is not connected) + jumper W8 shorted enables IRQ when ONLINE asserts + jumper W9 shorted enables IRQ when ONLINE denies + + DEMAND is wired inversely to Device Flag, so DEMAND assertion is Device Flag + denial and vice versa. DEMAND dropping after STROBE assertion corresponds + with Device Flag asserting after Device Command asserts, and DEMAND asserting + after the printer is ready corresponds to Device Flag denying. + + Similarly, ONLINE is wired inversely to Device End, so the printer going + offline asserts Device End, and READY is wired inversely to Device Status bit + 11, so bit 11 is asserted when the printer is not ready (either powered off + or out of paper). + + The READY and ONLINE signals indicate the current state of the printer. + READY asserts when printer power is on, no alarm condition (paper out, tape + format error) exits, and the VFU has been initialized. ONLINE asserts when + READY is asserted and the Online button is pressed. Therefore: + + ~ONLINE * ~READY = paper out or VFU error + ~ONLINE * READY = paper loaded and offline + ONLINE * ~READY = (prohibited) + ONLINE * READY = paper loaded and online + + The printer DEMAND signal asserts when the printer is ready for data and + denies when it is printing or slewing. It also denies when the printer goes + offline. DEMAND is cross-connected to the Device Flag differential input, + so that DEV FLAG is the complement of DEMAND, i.e., it asserts when the + printer is busy and denies when the printer is available. + + The normal sequence starts with DEMAND asserted (i.e., DEV FLAG denied). The + interface asserts STROBE (DEV CMD), the printer denies DEMAND (asserts DEV + FLAG), the interface denies STROBE (DEV CMD), and the printer then asserts + DEMAND (denies DEV FLAG) when the character data is accepted or the print + operation is complete. + + When the ON/OFFLINE button on the printer is pressed, the printer will not go + offline (i.e., deny the ONLINE signal) if there are characters in the print + buffer. Instead, the offline condition is held off until an internal "allow + offline" signal asserts. This occurs when the print buffer is empty and the + print cycle is inactive. When ONLINE denies, DEMAND is inhibited, so the + interface waits at the end of the handshake sequence for DEV FLAG to deny. + Note that this holds off SR to the Multiplexer Channel, so the channel + program waits. When the printer is put back online, DEMAND asserts, so DEV + FLAG denies, the handshake completes, SR asserts, and the interface returns + to the idle condition to await the next command. + + This has implications for the SET OFFLINE and DETACH commands if they are + issued while the print buffer contains data or the printer unit is busy + executing a print action. + + The SET LP OFFLINE and SET LP DETACH commands check for data in the print + buffer or a print operation in progress. If either condition is true, they + set their respective deferred-action flags and display "Command deferred." A + SHOW LP will show that the device is still online and attached. Once + simulation is resumed and the print operation completes, the printer is set + offline or detached as requested. No console message reports this, as it is + assumed that the executing program will detect the condition and report + accordingly. A subsequent SHOW LP will indicate the new status. + + A SET LP ONLINE or ATTACH LP command when the corresponding deferred-action + flag is set simply clears the flag. In particular, an ATTACH LP command must + not specify a new image filename; if one is specified while a deferred detach + is in progress, the routine returns SCPE_NOFNC ("Command not allowed"). + + A RESET LP command also clears the deferred-action flags and so clears any + pending offline or detach. However, it also clears the print buffer and + terminates any print action in progress, so a SET LP OFFLINE or DETACH LP + will succeed if issued subsequently. + + + The Universal Interface responds to both direct I/O and programmed I/O from + the Multiplexer Channel, as follows: + + Control Word Format (CIO and SIO Control word 2): + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | R | irq reset | A | device control | X | S | B | I | T | device + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | R | irq reset | A | function | E | X | S | B | I | T | DHA + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | R | irq reset | A | - - - - | F | X | S | B | I | T | printer + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + Where: + + M = programmed master clear + R = reset interrupts + A = acquire data from device + E = enable diagnostic hardware assembly function + F = printer output character/format (0/1) code + X = enable data transfer interrupt + S = interrupt/device (0/1) status + B = word/byte (0/1) transfer + I = enable interrupts + T = enable transfer timer + + IRQ Reset: + + 000 = none + 001 = transfer timer and transfer error + 010 = I/O system + 011 = clear interface + 100 = data transfer completion + 101 = line ready (device status bit 8) + 110 = ready (device status bit 9) + 111 = not ready (device status bit 10) + + DHA Function: + + 0000 = clear configuration registers (installs jumpers) + 0001 = remove jumper J2W2 + 0010 = assert DEV END + 0011 = remove jumper J2W8 + 0100 = set Transfer Error flip-flop + 0101 = remove jumper J2W4 + 0110 = remove jumper J2W10 + 0111 = remove jumper J2W6 + 1000 = DEV FLAG follows DEV CMD or Control 6 (0/1) + 1001 = remove jumper J2W5 + 1010 = assert CLEAR INTERFACE + 1011 = remove jumper J2W9 + 1100 = Status 8-10 follow Control 6-8 + or master clear, power on, and power fail (0/1) + 1101 = remove jumper J2W1 + 1110 = remove jumper J2W3 + 1111 = remove jumper J2W7 + + Bits 6-10 are the device control bits. For the DHA, control bit 10 enables + the function decoder. The decoder is combinatorial and the registers are + "ones-catching," so the function field must be set and then maintained while + bit 10 is asserted and then denied. For the line printer, control bit 10 + indicates whether character data (0) or format commands (1) will be output. + Programmed control word 1 (IOCW) is not used. + + Setting control bit 15 starts (or restarts) the five-second transfer timer. + Issuing a Reset Transfer Timer and Transfer Error Interrupts, a Master Reset, + or a Reset Interrupts command stops the timer. If the timer expires, a + Transfer Timer interrupt occurs. + + + Status Word Format (TIO and SIO Status): + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | S | D | I | seqct | F | 0 | 0 | dev irq | X | C | Y | E | T | interrupt + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | S | D | I | seqct | F | 1 | 0 | device status | device + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | S | D | I | seqct | F | 1 | 0 | - | L | L | N | V | U | - | - | printer + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + Where: + + S = SIO OK + D = direct I/O OK + I = interrupt pending + F = device flag + X = data transfer interrupt + C = clear interface interrupt + Y = I/O system interrupt + E = transfer error interrupt + T = transfer timer interrupt + L = online + N = not ready + V = VFU channel 12 + U = VFU channel 9 + + Sequence Counter: + + 00 = idle + 10 = request to device issued for word or 1st byte + 11 = device operation started + 01 = request to device issued for 2nd byte + + Device Interrupt Request Bits: + + 8 = device status bit 8 interrupt (not used by the printer) + 9 = device status bit 9 interrupt (printer went online) + 10 = device status bit 10 interrupt (printer went offline) + + Control word bit 12 determines whether the interrupt status word (0) or the + device status word (1) is returned. + + A transfer error occurs when the channel asserts XFERERROR to abort a + transfer for a parity error or memory address out of bounds. Device status + bits assume the logic 1 state with the inputs disconnected (e.g., power off). + + + Output Data Word Format (WIO and SIO Write): + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | - | 1st ASCII character | - | 2nd ASCII character | byte mode + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | - - - - - - - - | - | ASCII character | word mode + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | - - - - - - - - | - | format word | format + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + The printer only uses seven data bits, so the MSB of each byte is ignored. + If the printer's line length is exceeded during write operations, the + buffered line will be printed, the paper will be advanced one line, and the + buffer will be cleared to accept the character causing the overflow. + + + Implementation notes: + + 1. The Clear Interface Logic (CLRIL) signal inhibits SIO OK status. The + Card Reader/Punch Interface version of the UI does not assert the CLRIL + signal in response to external CLEAR INTERFACE assertion; only a transfer + error does. Therefore, the SIO OK signal is not inhibited while the + clear interface interrupt is present. For this version, the external + Clear Interface signal sets the CLR INF flip-flop, which sets the (C) bit + in the status register and generates an interrupt, but otherwise has no + effect on the interface logic. + + The standard version of the UI asserts CLRIL, and therefore inhibits SIO + OK, for both the clear interface and transfer error conditions. + + 2. Because the interface uses differential interface logic, the external + sense of a signal may be inverted by exchanging the + and - connections. + To accommodate this in simulation, separate variables are used for the + internal and external states. For example, "device_command" represents + the internal state, while "device_command_out" represents the external + state (which may be inverted from the internal state if jumper J2W10 is + installed). + + 3. The Universal Interface supports terminating channel transfers by + asserting DEVEND, and the line printer cable connects the ONLINE output + inversely to the Device End input, so that it is asserted when the + printer is offline. However, when the printer goes offline, it holds its + DEMAND line denied, which keeps Device Flag asserted. This hangs the + transfer handshake in the Device_Flag_1/2 state until the printer goes + online again. As the interface recognizes Device End only in the + Device_Command_1/2 state, DEVEND will never be asserted to terminate a + channel transfer. + + 4. In hardware, a paper-out condition is noted, but the line printer does + not go offline until the top of the next form is reached. This ensures + that the current page is completed first. By contrast, a torn-paper + 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. +*/ + + + +#include "hp3000_defs.h" +#include "hp3000_io.h" + + + +/* Interface program constants */ + +#define PULSE_TIME uS (8) /* device command pulse = 8 microseconds */ +#define XFER_TIME S (5) /* transfer timeout = 5 seconds */ + +/* Printer program constants */ + +#define CR '\r' /* carriage return */ +#define LF '\n' /* line feed */ +#define FF '\f' /* form feed */ +#define DEL '\177' /* delete */ + +#define DATA_MASK 0177u /* printer uses only 7 bits for data */ +#define FORMAT_VFU 0100u /* printer VFU selector */ +#define FORMAT_MASK 0117u /* printer format command mask for 12-channel VFU */ +#define FORMAT_VFU_8_MASK 0107u /* printer format command mask for 8-channel VFU */ + +#define FORMAT_SUPPRESS 0000u /* format code to slew 0 lines */ +#define FORMAT_VFU_CHAN_1 0100u /* format code to slew to VFU channel 1 */ +#define FORMAT_VFU_BIAS 0077u /* bias converting from format code to channel number */ + +#define VFU_MAX 144 /* maximum number of VFU form lines */ +#define VFU_SIZE (VFU_MAX + 1) /* size of the VFU array */ +#define LINE_SIZE 256 /* size of the character array used to read the VFU file */ + +#define VFU_WIDTH 12 /* maximum number of VFU channels */ + +#define VFU_CHANNEL_1 04000u /* top of form */ +#define VFU_CHANNEL_2 02000u /* bottom of form */ +#define VFU_CHANNEL_3 01000u /* single space */ +#define VFU_CHANNEL_4 00400u /* double space */ +#define VFU_CHANNEL_5 00200u /* triple space */ +#define VFU_CHANNEL_6 00100u /* half page */ +#define VFU_CHANNEL_7 00040u /* quarter page */ +#define VFU_CHANNEL_8 00020u /* sixth page */ +#define VFU_CHANNEL_9 00010u /* bottom of form */ +#define VFU_CHANNEL_10 00004u /* (unassigned) */ +#define VFU_CHANNEL_11 00002u /* (unassigned) */ +#define VFU_CHANNEL_12 00001u /* (unassigned) */ + +#define CHARS_MAX 136 /* maximum number of characters buffered by the printers */ + +#define BUFFER_SIZE (CHARS_MAX + VFU_MAX * 2) /* max chars + max VFU * 2 (CR LF) */ + +#define PRINTER_JUMPERS (W4 | W8 | W9) /* jumpers J2W4, J2W8, and J2W9 are installed */ + + +/* Debug flags */ + +#define DEB_CMD (1u << 0) /* trace controller commands */ +#define DEB_CSRW (1u << 1) /* trace command initiations and completions */ +#define DEB_STATE (1u << 2) /* trace device handshake state changes */ +#define DEB_SERV (1u << 3) /* trace channel service scheduling calls */ +#define DEB_XFER (1u << 4) /* trace data transmissions */ +#define DEB_IOB (1u << 5) /* trace I/O bus signals and data words */ + + +/* Device flags */ + +#define DEV_DIAG_SHIFT (DEV_V_UF + 0) /* Diagnostic Hardware Assembly is installed */ +#define DEV_REALTIME_SHIFT (DEV_V_UF + 1) /* timing mode is realistic */ + +#define DEV_DIAG (1u << DEV_DIAG_SHIFT) /* diagnostic mode flag */ +#define DEV_REALTIME (1u << DEV_REALTIME_SHIFT) /* realistic timing flag */ + + +/* Printer unit flags */ + +#define UNIT_MODEL_SHIFT (UNIT_V_UF + 0) /* bits 0-2: printer model ID */ +#define UNIT_EXPAND_SHIFT (UNIT_V_UF + 3) /* bits 3-3: printer uses expanded output */ +#define UNIT_OFFLINE_SHIFT (UNIT_V_UF + 4) /* bits 4-4: printer is offline */ + +#define UNIT_MODEL_MASK 0000007u /* model ID mask */ + +#define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT) +#define UNIT_EXPAND (1u << UNIT_EXPAND_SHIFT) +#define UNIT_OFFLINE (1u << UNIT_OFFLINE_SHIFT) +#define UNIT_ONLINE 0 + +#define UNIT_2607 (HP_2607 << UNIT_MODEL_SHIFT) +#define UNIT_2613 (HP_2613 << UNIT_MODEL_SHIFT) +#define UNIT_2617 (HP_2617 << UNIT_MODEL_SHIFT) +#define UNIT_2618 (HP_2618 << UNIT_MODEL_SHIFT) + + +/* Unit flags accessor */ + +#define GET_MODEL(f) ((PRINTER_TYPE) (((f) >> UNIT_MODEL_SHIFT) & UNIT_MODEL_MASK)) + + +/* Unit references */ + +#define xfer_unit lp_unit [0] /* transfer handshake unit */ + +#define xfer_uptr (&lp_unit [0]) /* transfer handshake unit pointer */ +#define pulse_uptr (&lp_unit [1]) /* pulse timer unit pointer */ +#define timer_uptr (&lp_unit [2]) /* transfer timer unit pointer */ + +static const char *const unit_name [] = { /* unit names, indexed by unit number */ + "Transfer", + "Pulse", + "Watchdog" + }; + + +/* Printer types */ + +typedef enum { + HP_2607, /* HP 2607A */ + HP_2613, /* HP 2613A */ + HP_2617, /* HP 2617A */ + HP_2618 /* HP 2618A */ + } PRINTER_TYPE; + + +/* Printer locality states */ + +typedef enum { + Offline, /* printer is going offline */ + Online /* printer is going online */ + } LOCALITY; + + +/* Printer properties table. + + This table contains the characteristics that vary between printer models. + The "char_set" field values reflect printer Option 001, 96/128-character set. +*/ + +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 overprints; /* TRUE if the printer supports overprinting */ + } 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 */ + }; + + +/* Delay properties table. + + To support the realistic timing mode, the delay properties table contains + timing specifications for the supported printers. The times represent the + delays for mechanical and electronic operations. Delay values are in event + tick counts; macros are used to convert from times to ticks. + + + Implementation notes: + + 1. Although all of the printers operate more slowly with a 96/128-character + set than with a 64-character set, the times reflect the smaller set size. + Also, some models provide different print rates, depending on how many + and/or which characters are printed. These variances are not simulated. +*/ + +typedef struct { + int32 buffer_load; /* per-character transfer time */ + int32 print; /* print time */ + int32 advance; /* paper advance time per line */ + } DELAY_PROPS; + +static const DELAY_PROPS real_times [] = { /* real-time delays, indexed by PRINTER_TYPE */ + /* buffer paper */ + /* load print advance */ + /* --------- -------- --------- */ + { uS (12.6), mS (260), mS (40.1) }, /* HP_2607 200 lines per minute */ + { uS (1.75), mS (183), mS (8.33) }, /* HP_2613 300 lines per minute */ + { uS (1.75), mS ( 86), mS (6.67) }, /* HP_2617 600 lines per minute */ + { uS (1.75), mS ( 38), mS (4.76) } /* HP_2618 1250 lines per minute */ + }; + +#define LP_BUFFER_LOAD uS (1) /* fast per-character transfer time */ +#define LP_PRINT mS (1) /* fast print time */ +#define LP_ADVANCE uS (50) /* fast paper advance time per line */ + +static DELAY_PROPS fast_times = /* FASTTIME delays */ + { LP_BUFFER_LOAD, + LP_PRINT, + LP_ADVANCE + }; + + +/* Data transfer handshake sequencer. + + The sequencer controls the handshake that transfers data between the + interface and the device. +*/ + +typedef enum { + Idle, /* the device is idle */ + Device_Command_1, /* device command is asserted for a word or first byte */ + Device_Flag_1, /* device flag is asserted for a word or first byte */ + Device_Command_2, /* device command is asserted for the second byte */ + Device_Flag_2 /* device flag is asserted for the second byte */ + } SEQ_STATE; + +static const char *const state_name [] = { /* sequencer state names, indexed by SEQ_STATE */ + "Idle", + "Device Command 1", + "Device Flag 1", + "Device Command 2", + "Device Flag 2" + }; + + +/* Configuration jumpers. + + Various aspects of interface operation are configured by installing or + removing jumpers contained within the connector hood of the device + interconnection cable. Jumpers are simulated by bits in the "jumper_set" + word, with a 1 value representing "installed" and a 0 value representing + "removed" (although in hardware installing a jumper pulls the corresponding + signal down to 0). + + The Diagnostic Hardware Assembly provides programmatic configuration of the + jumpers. All jumpers are installed by executing a "clear registers" command, + and then individual jumpers may be removed by executing the corresponding + "remove jumper J2Wn" commands. This is simulated by setting all of the bits + in the "jumper_set" word and then selectively ANDing the word with + complemented constants from the "jumper_map" table, thereby clearing + individual bits. + + + Implementation notes: + + 1. In simulation, jumper W5 is not used. The DATA IN signals are always + latched when DEV FLAG asserts. Always-transparent operation is not + provided. + + 2. In hardware, DHA control word bits 6-9 are wired to decoder input bits + 0-3. As the 3000 uses decreasing bit-number significance, while the + decoder chip uses increasing bit-number significance, the order of the + functions in the "jumper_map" table reflect the reversed bit order of the + index. For example, index 0001 contains the function for decoder output + 8 (1000). +*/ + +#define W1 (1u << 0) /* SR set by PCONTSTB/Device Status bit 11 */ +#define W2 (1u << 1) /* +/- edge of Device Flag advances sequence counter from 1 to 2 */ +#define W3 (1u << 2) /* Device Command operates in response/pulse mode */ +#define W4 (1u << 3) /* inhibit/enable interrupt on STAT8 + edge */ +#define W5 (1u << 4) /* Data In latched on sequence count 1 and 3/always transparent */ +#define W6 (1u << 5) /* -/+ edge of Device Flag advances sequence counter from 2 to 3 */ +#define W7 (1u << 6) /* normal/test write transfer */ +#define W8 (1u << 7) /* inhibit/enable interrupt on STAT9 + edge */ +#define W9 (1u << 8) /* inhibit/enable interrupt on STAT10 - edge */ +#define W10 (1u << 9) /* Device Command same/inverted polarity as Data Out */ + +#define J2W1_INSTALLED ((jumper_set & W1) != 0) +#define J2W2_INSTALLED ((jumper_set & W2) != 0) +#define J2W3_INSTALLED ((jumper_set & W3) != 0) +#define J2W4_INSTALLED ((jumper_set & W4) != 0) +#define J2W5_INSTALLED ((jumper_set & W5) != 0) +#define J2W6_INSTALLED ((jumper_set & W6) != 0) +#define J2W7_INSTALLED ((jumper_set & W7) != 0) +#define J2W8_INSTALLED ((jumper_set & W8) != 0) +#define J2W9_INSTALLED ((jumper_set & W9) != 0) +#define J2W10_INSTALLED ((jumper_set & W10) != 0) + +static const uint32 jumper_map [16] = { /* jumper removal map, indexed by CN_DHA_FN */ + 0, /* 0000 = (unaffected) */ + ~W2, /* 0001 = remove jumper J2W2 */ + 0, /* 0010 = (unaffected) */ + ~W8, /* 0011 = remove jumper J2W8 */ + 0, /* 0100 = (unaffected) */ + ~W4, /* 0101 = remove jumper J2W4 */ + ~W10, /* 0110 = remove jumper J2W10 */ + ~W6, /* 0111 = remove jumper J2W6 */ + 0, /* 1000 = (unaffected) */ + ~W5, /* 1001 = remove jumper J2W5 */ + 0, /* 1010 = (unaffected) */ + ~W9, /* 1011 = remove jumper J2W9 */ + 0, /* 1100 = (unaffected) */ + ~W1, /* 1101 = remove jumper J2W1 */ + ~W3, /* 1110 = remove jumper J2W3 */ + ~W7 /* 1111 = remove jumper J2W7 */ + }; + + +/* Diagnostic Hardware Assembly control register. + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | F | S | - - - | jumpers J2W10-J2W1 | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + Where: + + M = master reset has occurred + F = device flag follows device command/control 6 (0/1) + S = status 8-10 follow control 6-8/master clear-power on-power fail (0/1) + + + Implementation notes: + + 1. Jumper bits are defined as 0 = removed and 1 = installed. This is + the opposite of the DHA hardware, for which a zero output "installs" a + jumper. + + 2. Jumpers J2W10-J2W1, which are stored in the "jumpers" array, are mirrored + in the jumper control register to allow the diagnostic to test the full + set of jumpers with single assertions. Otherwise, ten assertions would + be necessary for each test. +*/ + +#define DHA_MR 0100000u /* (M) a master reset has occurred */ +#define DHA_FLAG_SEL 0040000u /* (F) device flag follows control 6 */ +#define DHA_STAT_SEL 0020000u /* (S) status 8-10 follow master clear-power on-power fail */ +#define DHA_JUMPER_MASK 0001777u /* J2Wx jumpers mask */ +#define DHA_CLEAR 0001777u /* control register clear value (all jumpers installed) */ + + +/* Interface control word. + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | R | irq reset | A | device control | X | S | B | I | T | device + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | R | irq reset | A | function | E | X | S | B | I | T | DHA + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +*/ + +#define CN_MR 0100000u /* (M) master reset */ +#define CN_RIN 0040000u /* (R) reset interrupt */ +#define CN_RIN_MASK 0034000u /* reset interrupt request selector mask */ +#define CN_RIN_XFR_TMR 0004000u /* reset watchdog timer and transfer error interrupts */ +#define CN_ACQUIRE 0002000u /* (A) acquire data from device */ +#define CN_DHA_FN_MASK 0001700u /* diagnostic hardware assembly function mask */ +#define CN_DHA_ST_MASK 0001600u /* diagnostic hardware assembly status mask */ +#define CN_DHA_FLAG 0001000u /* diagnostic hardware assembly device flag value */ +#define CN_DHA_FN_ENABLE 0000040u /* (E) enable diagnostic hardware assembly function */ +#define CN_XFR_IRQ_ENABLE 0000020u /* (X) enable data transfer interrupt */ +#define CN_DEVSTAT 0000010u /* (S) interrupt/device (0/1) status */ +#define CN_BYTE_XFER 0000004u /* (B) word/byte (0/1) transfer */ +#define CN_IRQ_ENABLE 0000002u /* (I) enable interrupts */ +#define CN_XFR_TMR_ENABLE 0000001u /* (T) enable data transfer timer */ + +#define CN_RIN_SHIFT 11 /* reset interrupt request alignment shift */ +#define CN_DHA_ST_SHIFT 7 /* diagnostic hardware assembly status alignment shift */ +#define CN_DHA_FN_SHIFT 6 /* diagnostic hardware assembly function alignment shift */ + +#define CN_RESET(c) (((c) & CN_RIN_MASK) >> CN_RIN_SHIFT) +#define CN_DHA_ST(c) (((c) & CN_DHA_ST_MASK) >> CN_DHA_ST_SHIFT) +#define CN_DHA_FN(c) (((c) & CN_DHA_FN_MASK) >> CN_DHA_FN_SHIFT) + +static const char *const dha_fn_name [16] = { /* DHA function names, indexed by CN_DHA_FN */ + "clear registers", /* 0000 = clear registers (installs jumpers) */ + "remove J2W2", /* 0001 = remove jumper J2W2 */ + "assert DEVEND", /* 0010 = assert Device End */ + "remove J2W8", /* 0011 = remove jumper J2W8 */ + "set transfer error", /* 0100 = set Transfer Error flip-flop */ + "remove J2W4", /* 0101 = remove jumper J2W4 */ + "remove J2W10", /* 0110 = remove jumper J2W10 */ + "remove J2W6", /* 0111 = remove jumper J2W6 */ + "control 6 drives device flag", /* 1000 = connect device flag to control bit 6 */ + "remove J2W5", /* 1001 = remove jumper J2W5 */ + "assert CLRIF", /* 1010 = assert Clear Interface */ + "remove J2W9", /* 1011 = remove jumper J2W9 */ + "CLR/PON/PF drive status 8-10", /* 1100 = connect status 8-10 to master clear/power on/power fail */ + "remove J2W1", /* 1101 = remove jumper J2W1 */ + "remove J2W3", /* 1110 = remove jumper J2W3 */ + "remove J2W7" /* 1111 = remove jumper J2W7 */ + }; + +static const char *const reset_irq_name [8] = { /* reset interrupt request names, indexed by CN_RESET */ + "", /* 000 = none */ + " | reset timer/xfer error irq", /* 001 = watchdog timer and transfer error */ + " | reset I/O system irq", /* 010 = I/O system */ + " | reset clear interface irq", /* 011 = clear interface */ + " | reset data xfer irq", /* 100 = data transfer completion */ + " | reset status 8 irq", /* 101 = device status 8 */ + " | reset status 9 irq", /* 110 = device status 9 */ + " | reset status 10 irq" /* 111 = device status 10 */ + }; + +static const BITSET_NAME dha_control_names [] = { /* DHA control word names */ + "master clear", /* bit 0 */ + "clear interrupts", /* bit 1 */ + NULL, /* bit 2 */ + NULL, /* bit 3 */ + NULL, /* bit 4 */ + "acquire data", /* bit 5 */ + "DC6", /* bit 6 */ + "DC7", /* bit 7 */ + "DC8", /* bit 8 */ + "DC9", /* bit 9 */ + "enable function", /* bit 10 */ + "enable data xfer interrupt", /* bit 11 */ + "\1device status\0interrupt status", /* bit 12 */ + "\1byte xfer\0word xfer", /* bit 13 */ + "enable interrupts", /* bit 14 */ + "enable transfer timer" /* bit 15 */ + }; + +static const BITSET_FORMAT dha_control_format = /* names, offset, direction, alternates, bar */ + { FMT_INIT (dha_control_names, 0, msb_first, has_alt, no_bar) }; + + +/* Printer control word. + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | M | R | irq reset | - - - - - | F | X | S | B | I | T | printer + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +*/ + +#define CN_FORMAT 0000040u /* printer output character/format (0/1) code */ + +static const BITSET_NAME prt_control_names [] = { /* Printer control word names */ + "master clear", /* bit 0 */ + "clear interrupts", /* bit 1 */ + NULL, /* bit 2 */ + NULL, /* bit 3 */ + NULL, /* bit 4 */ + "acquire data", /* bit 5 */ + NULL, /* bit 6 */ + NULL, /* bit 7 */ + NULL, /* bit 8 */ + NULL, /* bit 9 */ + "\1format\0character", /* bit 10 */ + "enable data xfer interrupt", /* bit 11 */ + "\1device status\0interrupt status", /* bit 12 */ + "\1byte xfer\0word xfer", /* bit 13 */ + "enable interrupts", /* bit 14 */ + "enable transfer timer" /* bit 15 */ + }; + +static const BITSET_FORMAT prt_control_format = /* names, offset, direction, alternates, bar */ + { FMT_INIT (prt_control_names, 0, msb_first, has_alt, no_bar) }; + + +/* Interface status word. + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | S | D | I | seqct | F | 0 | 0 | dev irq | X | C | Y | E | T | interrupt + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | S | D | I | seqct | F | 1 | 0 | device status | device + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + + + Implementation notes: + + 1. The entry for bit 6 of the interrupt status names formatting array is + given in the alternate form to print the "interrupt status" string when + the bit is zero. +*/ + +#define ST_SIO_OK 0100000u /* (S) SIO OK to use */ +#define ST_DIO_OK 0040000u /* (D) direct I/O OK to use */ +#define ST_IRQ_PENDING 0020000u /* (I) interrupt pending */ +#define ST_SEQ_COUNT_0 0000000u /* sequence count 0 (00) */ +#define ST_SEQ_COUNT_1 0010000u /* sequence count 1 (10) */ +#define ST_SEQ_COUNT_2 0014000u /* sequence count 2 (11) */ +#define ST_SEQ_COUNT_3 0004000u /* sequence count 3 (01) */ +#define ST_DEVFLAG 0002000u /* (F) device flag */ +#define ST_DEVSTAT 0001000u /* interrupt/device (0/1) status */ +#define ST_DEVIRQ_MASK 0000340u /* device interrupt request mask */ +#define ST_ST8_IRQ 0000200u /* device status 8 interrupt */ +#define ST_DHA_MR 0000200u /* diagnostic hardware assembly status 8 (master clear) */ +#define ST_ST9_IRQ 0000100u /* device status 9 interrupt */ +#define ST_DHA_PON 0000100u /* diagnostic hardware assembly status 9 (power on) */ +#define ST_ST10_IRQ 0000040u /* device status 10 interrupt */ +#define ST_DHA_NOT_PF 0000040u /* diagnostic hardware assembly status 10 (~power fail) */ +#define ST_DHA_DEVSTAT_MASK 0000037u /* diagnostic hardware assembly status 11-15 mask */ +#define ST_XFR_IRQ 0000020u /* (X) data transfer interrupt */ +#define ST_ST11_SR 0000020u /* device status 11 service request */ +#define ST_CLRIF_IRQ 0000010u /* (C) clear interface interrupt */ +#define ST_IOSYS_IRQ 0000004u /* (Y) I/O system interrupt */ +#define ST_XFERERR_IRQ 0000002u /* (E) transfer error interrupt */ +#define ST_XFR_TMR_IRQ 0000001u /* (T) transfer timer interrupt */ + +#define ST_DEVIRQ_SHIFT 5 /* device status 8-10 interrupt request alignment shift */ + +#define ST_DEVIRQ(n) ((n) << ST_DEVIRQ_SHIFT & ST_DEVIRQ_MASK) + +#define ST_CLRIL (ST_CLRIF_IRQ | ST_XFERERR_IRQ) /* conditions that assert the CLRIL signal */ + +static const uint32 sequence_counter [] = { /* externally visible sequencer values, indexed by SEQ_STATE */ + ST_SEQ_COUNT_0, /* 00 = Idle */ + ST_SEQ_COUNT_1, /* 10 = Device_Command_1 */ + ST_SEQ_COUNT_2, /* 11 = Device_Flag_1 */ + ST_SEQ_COUNT_3, /* 01 = Device_Command_2 */ + ST_SEQ_COUNT_0 /* 00 = Device_Flag_2 */ + }; + +static const uint32 reset_irq [8] = { /* selective reset irq mask values, indexed by CN_RESET */ + ~0u, /* 000 = none */ + ~(ST_XFR_TMR_IRQ | ST_XFERERR_IRQ), /* 001 = watchdog timer and transfer error */ + ~ST_IOSYS_IRQ, /* 010 = I/O system */ + ~ST_CLRIF_IRQ, /* 011 = clear interface */ + ~ST_XFR_IRQ, /* 100 = data transfer completion */ + ~ST_ST8_IRQ, /* 101 = device status 8 */ + ~ST_ST9_IRQ, /* 110 = device status 9 */ + ~ST_ST10_IRQ /* 111 = device status 10 */ + }; + +static const BITSET_NAME int_status_names [] = { /* Interrupt status word names */ + "SIO OK", /* bit 0 */ + "DIO OK", /* bit 1 */ + "interrupt", /* bit 2 */ + "SEQ 1", /* bit 3 */ + "SEQ 2", /* bit 4 */ + "device flag", /* bit 5 */ + "\1\0interrupt status", /* bit 6 */ + NULL, /* bit 7 */ + "status 8", /* bit 8 */ + "status 9", /* bit 9 */ + "status 10", /* bit 10 */ + "data xfer", /* bit 11 */ + "clear interface", /* bit 12 */ + "system", /* bit 13 */ + "transfer error", /* bit 14 */ + "transfer timeout" /* bit 15 */ + }; + +static const BITSET_NAME dev_status_names [] = { /* Device status word names */ + "SIO OK", /* bit 0 */ + "DIO OK", /* bit 1 */ + "interrupt", /* bit 2 */ + "SEQ 1", /* bit 3 */ + "SEQ 2", /* bit 4 */ + "device flag", /* bit 5 */ + "device status", /* bit 6 */ + NULL, /* bit 7 */ + "DS8", /* bit 8 */ + "DS9", /* bit 9 */ + "DS10", /* bit 10 */ + "DS11", /* bit 11 */ + "DS12", /* bit 12 */ + "DS13", /* bit 13 */ + "DS14", /* bit 14 */ + "DS15" /* bit 15 */ + }; + +static const BITSET_FORMAT int_status_format = /* names, offset, direction, alternates, bar */ + { FMT_INIT (int_status_names, 0, msb_first, has_alt, no_bar) }; + +static const BITSET_FORMAT dev_status_format = /* names, offset, direction, alternates, bar */ + { FMT_INIT (dev_status_names, 0, msb_first, no_alt, no_bar) }; + + +/* Printer status word. + + 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + | S | D | I | seqct | F | 1 | 0 | - | L | L | N | V | U | - | - | printer + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +*/ + +#define ST_ONLINE 0000140u /* online */ +#define ST_NOT_READY 0000020u /* not ready */ +#define ST_VFU_12 0000010u /* VFU channel 12 */ +#define ST_VFU_9 0000004u /* VFU channel 9 */ + +static const BITSET_NAME prt_status_names [] = { /* Printer status word names */ + "SIO OK", /* bit 0 */ + "DIO OK", /* bit 1 */ + "interrupt", /* bit 2 */ + "SEQ 1", /* bit 3 */ + "SEQ 2", /* bit 4 */ + "device flag", /* bit 5 */ + "device status", /* bit 6 */ + NULL, /* bit 7 */ + NULL, /* bit 8 */ + "\1online\0offline", /* bit 9 */ + NULL, /* bit 10 */ + "\1not ready\0ready", /* bit 11 */ + "VFU 12", /* bit 12 */ + "VFU 9" /* bit 13 */ + }; + +static const BITSET_FORMAT prt_status_format = /* names, offset, direction, alternates, bar */ + { FMT_INIT (prt_status_names, 2, msb_first, has_alt, no_bar) }; + + +/* Interface state */ + +static HP_WORD control_word = 0; /* control word */ +static HP_WORD int_status_word = 0; /* interrupt status word (bits 8-15) */ +static HP_WORD dev_status_word = 0; /* device status word (bits 8-15) */ +static HP_WORD read_word = 0; /* read word */ +static HP_WORD write_word = 0; /* write word */ + +static SEQ_STATE sequencer = Idle; /* data transfer handshake sequencer */ +static uint32 jumper_set = PRINTER_JUMPERS; /* set of configuration jumpers */ + +static FLIP_FLOP sio_busy = CLEAR; /* SIO busy flip-flop */ +static FLIP_FLOP channel_sr = CLEAR; /* channel service request flip-flop */ +static FLIP_FLOP device_sr = CLEAR; /* device service request flip-flop */ +static FLIP_FLOP input_xfer = CLEAR; /* input transfer flip-flop */ +static FLIP_FLOP output_xfer = CLEAR; /* output transfer flip-flop */ +static FLIP_FLOP read_xfer = CLEAR; /* read transfer flip-flop */ +static FLIP_FLOP write_xfer = CLEAR; /* write transfer flip-flop */ +static FLIP_FLOP interrupt_mask = SET; /* interrupt mask flip-flop */ + +static FLIP_FLOP device_command = CLEAR; /* device command flip-flop */ +static FLIP_FLOP device_flag = CLEAR; /* device flag flip-flop */ +static FLIP_FLOP device_end = CLEAR; /* device end flip-flop */ + +static HP_WORD data_out = 0; /* external DATA OUT signal bus */ +static t_bool device_command_out = FALSE; /* external DEV CMD signal state */ + +static HP_WORD data_in = 0; /* external DATA IN signal bus */ +static t_bool device_flag_in = FALSE; /* external DEV FLAG signal state */ +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 */ + + +/* Printer state */ + +static t_bool paper_fault = TRUE; /* TRUE if the printer is out of paper */ +static t_bool tape_fault = FALSE; /* TRUE if there is no punch in a VFU channel command */ +static t_bool offline_pending = FALSE; /* TRUE if an offline request is waiting for the printer to finish */ +static uint32 overprint_char = DEL; /* character to use if overprinted */ +static uint32 current_line = 1; /* current form line */ +static uint32 buffer_index = 0; /* current index into the print buffer */ + +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 const DELAY_PROPS *dlyptr = &fast_times; /* pointer to the event delay times to use */ + + +/* Interface local SCP support routines */ + +static CNTLR_INTRF ui_interface; +static t_stat xfer_service (UNIT *uptr); +static t_stat pulse_service (UNIT *uptr); +static t_stat timer_service (UNIT *uptr); +static t_stat ui_reset (DEVICE *dptr); + + +/* Interface local utility routines */ + +static t_stat master_reset (t_bool programmed_clear); +static void clear_interface_logic (void); +static void activate_unit (UNIT *uptr); +static OUTBOUND_SET set_interrupt (uint32 interrupt); +static OUTBOUND_SET set_device_status (uint32 status_mask, uint32 new_status_word); +static OUTBOUND_SET handshake_xfer (void); + + +/* Diagnostic Hardware Assembly local SCP support routines */ + +static t_stat diag_service (UNIT *uptr); + + +/* Diagnostic Hardware Assembly local utility routines */ + +static t_stat diag_reset (t_bool programmed_clear); +static OUTBOUND_SET diag_control (uint32 control_word); + + +/* Printer local SCP support routines */ + +static t_stat lp_service (UNIT *uptr); +static t_stat lp_attach (UNIT *uptr, CONST char *cptr); +static t_stat lp_detach (UNIT *uptr); + +static t_stat lp_set_mode (UNIT *uptr, int32 value, CONST char *cptr, void *desc); +static t_stat lp_set_model (UNIT *uptr, int32 value, CONST char *cptr, void *desc); +static t_stat lp_set_on_offline (UNIT *uptr, int32 value, CONST char *cptr, void *desc); +static t_stat lp_set_vfu (UNIT *uptr, int32 value, CONST char *cptr, void *desc); +static t_stat lp_show_mode (FILE *st, UNIT *uptr, int32 value, CONST void *desc); +static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, CONST void *desc); + + +/* Printer local utility routines */ + +static t_stat lp_reset (t_bool programmed_clear); +static OUTBOUND_SET lp_control (uint32 control_word); +static t_bool lp_set_alarm (UNIT *uptr); +static t_bool lp_set_locality (UNIT *uptr, LOCALITY printer_state); +static t_stat lp_load_vfu (UNIT *uptr, FILE *vf); +static int32 lp_read_line (FILE *vf, char *line, uint32 size); + + +/* Interface SCP data structures */ + + +/* Device information block */ + +static DIB lp_dib = { + &ui_interface, /* device interface */ + 14, /* device number */ + 11, /* service request number */ + 18, /* interrupt priority */ + INTMASK_E /* interrupt mask */ + }; + + +/* Unit list */ + +#define UNIT_FLAGS (UNIT_ATTABLE | UNIT_SEQ | UNIT_EXPAND | UNIT_OFFLINE) + +static UNIT lp_unit [] = { + { UDATA (&xfer_service, UNIT_FLAGS | UNIT_2617, 0), 0 }, + { UDATA (&pulse_service, UNIT_DIS, 0), PULSE_TIME }, + { UDATA (&timer_service, UNIT_DIS, 0), XFER_TIME } + }; + + +/* Register list. + + The list consists of the interface registers followed by the Diagnostic + Hardware Assembly registers and then the printer registers. + + + 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 + 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 + bits with single commands. +*/ + +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) }, + { FLDATA (INXFR, input_xfer, 0) }, + { FLDATA (OUTXFR, output_xfer, 0) }, + { FLDATA (RDXFR, read_xfer, 0) }, + { FLDATA (WRXFR, write_xfer, 0) }, + { FLDATA (INTMSK, interrupt_mask, 0) }, + + { FLDATA (DEVCMD, device_command, 0) }, + { FLDATA (DEVFLG, device_flag, 0) }, + { FLDATA (DEVEND, device_end, 0) }, + + { DRDATA (SEQSTA, sequencer, 8), PV_LEFT }, + { ORDATA (CNTL, control_word, 16), PV_RZRO }, + { ORDATA (ISTAT, int_status_word, 16), PV_RZRO }, + { ORDATA (DSTAT, dev_status_word, 16), PV_RZRO }, + { ORDATA (READ, read_word, 16), PV_RZRO | REG_A }, + { ORDATA (WRITE, write_word, 16), PV_RZRO | REG_A }, + { YRDATA (J2WX, jumper_set, 10, PV_RZRO) }, + + { ORDATA (DATOUT, data_out, 16), PV_RZRO | REG_A }, + { ORDATA (DATIN, data_in, 16), PV_RZRO | REG_A }, + + { FLDATA (DCOUT, device_command_out, 0) }, + { FLDATA (DFIN, device_flag_in, 0) }, + { FLDATA (DENDIN, device_end_in, 0) }, + + { SRDATA (DIB, lp_dib, REG_HRO) }, + + + { ORDATA (DIAGCN, dha_control_word, 16), PV_RZRO }, + { GRDATA (CNLED, control_word, 2, 5, 5), PV_RZRO }, + + + { FLDATA (PFAULT, paper_fault, 0) }, + { FLDATA (TFAULT, tape_fault, 0) }, + { FLDATA (OLPEND, offline_pending, 0) }, + + { DRDATA (PRLINE, current_line, 8), PV_LEFT }, + { DRDATA (BUFIDX, buffer_index, 8), PV_LEFT }, + { BRDATA (PRTBUF, buffer, 8, 8, BUFFER_SIZE), PV_RZRO | REG_A }, + { ORDATA (OVPCHR, overprint_char, 8), PV_RZRO | REG_A }, + + { DRDATA (FORMLN, form_length, 8), PV_LEFT | REG_RO }, + { BRDATA (TITLE, vfu_title, 8, 8, LINE_SIZE), REG_HRO }, + { SRDATA (VFUREG, lp_reg [0], REG_HRO) }, + { BRDATA (VFU, VFU, 2, VFU_WIDTH, VFU_SIZE), PV_RZRO | REG_RO }, + + { DRDATA (BTIME, fast_times.buffer_load, 24), PV_LEFT | REG_NZ }, + { DRDATA (PTIME, fast_times.print, 24), PV_LEFT | REG_NZ }, + { DRDATA (STIME, fast_times.advance, 24), PV_LEFT | REG_NZ }, + { DRDATA (POS, lp_unit [0].pos, T_ADDR_W), PV_LEFT }, + + { NULL } + }; + + +/* Modifier list */ + +typedef enum { /* Device modes */ + Fast_Time, /* use optimized timing */ + Real_Time, /* use realistic timing */ + Printer, /* connect to the printer */ + Diagnostic /* connect to the DHA */ + } DEVICE_MODES; + +static MTAB lp_mod [] = { +/* Mask Value Match Value Print String Match String Validation Display Descriptor */ +/* ------------ ------------ ----------------- ------------ ------------------ ------- ---------- */ + { UNIT_MODEL, UNIT_2607, "2607", "2607", &lp_set_model, NULL, NULL }, + { UNIT_MODEL, UNIT_2613, "2613", "2613", &lp_set_model, NULL, NULL }, + { UNIT_MODEL, UNIT_2617, "2617", "2617", &lp_set_model, NULL, NULL }, + { UNIT_MODEL, UNIT_2618, "2618", "2618", &lp_set_model, NULL, NULL }, + + { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", &lp_set_on_offline, NULL, NULL }, + { UNIT_OFFLINE, 0, "online", "ONLINE", &lp_set_on_offline, NULL, NULL, }, + + { UNIT_EXPAND, UNIT_EXPAND, "expanded output", "EXPAND", NULL, NULL, NULL }, + { 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 }, + { MTAB_XDV, Diagnostic, NULL, "DIAGNOSTIC", &lp_set_mode, NULL, NULL }, + { MTAB_XDV, 0, "MODES", NULL, NULL, &lp_show_mode, NULL }, + + { MTAB_XDV, VAL_DEVNO, "DEVNO", "DEVNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib }, + { MTAB_XDV, VAL_INTMASK, "INTMASK", "INTMASK", &hp_set_dib, &hp_show_dib, (void *) &lp_dib }, + { MTAB_XDV, VAL_INTPRI, "INTPRI", "INTPRI", &hp_set_dib, &hp_show_dib, (void *) &lp_dib }, + { MTAB_XDV, VAL_SRNO, "SRNO", "SRNO", &hp_set_dib, &hp_show_dib, (void *) &lp_dib }, + + { MTAB_XDV | MTAB_NC, 0, "VFU", "VFU", &lp_set_vfu, &lp_show_vfu, NULL }, + + { 0 } + }; + + +/* Debugging trace list */ + +static DEBTAB lp_deb [] = { + { "CMD", DEB_CMD }, /* controller commands */ + { "CSRW", DEB_CSRW }, /* interface control, status, read, and write actions */ + { "SERV", DEB_SERV }, /* controller unit service scheduling calls */ + { "XFER", DEB_XFER }, /* controller data reads and writes */ + { "STATE", DEB_STATE }, /* handshake execution state changes */ + { "IOBUS", DEB_IOB }, /* interface I/O bus signals and data words */ + { NULL, 0 } + }; + + +/* Device descriptor */ + +DEVICE lp_dev = { + "LP", /* device name */ + lp_unit, /* unit array */ + lp_reg, /* register array */ + lp_mod, /* modifier array */ + 3, /* number of units */ + 10, /* address radix */ + 32, /* address width = 4 GB */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &ui_reset, /* reset routine */ + NULL, /* boot routine */ + &lp_attach, /* attach routine */ + &lp_detach, /* detach routine */ + &lp_dib, /* device information block pointer */ + DEV_DISABLE | DEV_DEBUG, /* device flags */ + 0, /* debug control flags */ + lp_deb, /* debug flag name array */ + NULL, /* memory size change routine */ + NULL /* logical device name */ + }; + + + +/* Interface local SCP support routines */ + + + +/* Universal interface. + + The universal interface is installed on the IOP and Multiplexer Channel buses + and receives direct and programmed I/O commands from the IOP and Multiplexer + Channel, respectively. In simulation, the asserted signals on the buses are + represented as bits in the inbound_signals set. Each signal is processed + sequentially in numerical order, and a set of similar outbound_signals is + assembled and returned to the caller, simulating assertion of the + corresponding backplane signals. + + After setting the control mode to establish word or byte mode, SIO data + transfer between the interface and the connected device is initiated by a + PWRITESTB or READNEXTWD order. For direct I/O, a DWRITESTB or a DCONTSTB + with the "acquire" bit set initiates a transfer. + + A sequencer governs the generation of the device handshake signals. The + handshake begins with the assertion of the Device Control signal. In + response, the device asserts the Device Flag signal. The interface then + denies Device Control, and the device denies Device Flag. For a byte + transfer, this sequence repeats automatically for the second byte. Byte + packing and unpacking is provided by the interface. + + Eight interrupt sources are provided and may be individually set by their + associated conditions. A master interrupt enable is provided by setting the + appropriate control word bit, and the requesting sources may be cleared + independently. An interrupt acknowledgement from the IOP clears the master + interrupt enable to prevent multiple sources from interrupting + simultaneously. + + The status word returned by a DSTATSTB or PSTATSTB signal consists of + interface status in the upper byte and either interrupt or device status in + the lower byte, as selected by a control word bit. + + + Implementation notes: + + 1. In a hardware transfer abort, READNEXTWD or PWRITESTB causes the + sequencer to transition to the Device_Command_1 state and set the Device + End flip-flop, which asserts DEVEND to the multiplexer channel, and then + the Device End flip-flop is cleared by ACKSR. In simulation, ACKSR + occurs before the PREADSTB or PWRITESTB that asserts DEVEND, so the state + of the Device End flip-flop is saved in the ACKSR handler and is then + checked in a subsequent PREADSTB or PWRITESTB to assert DEVEND. + + 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. +*/ + +static SIGNALS_DATA ui_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) +{ +INBOUND_SIGNAL signal; +INBOUND_SET working_set = inbound_signals; +HP_WORD outbound_value = 0; +OUTBOUND_SET outbound_signals = NO_SIGNALS; +t_bool abort_transfer = FALSE; + +dprintf (lp_dev, DEB_IOB, "Received data %06o with signals %s\n", + inbound_value, fmt_bitset (inbound_signals, inbound_format)); + +while (working_set) { + signal = IONEXTSIG (working_set); /* isolate the next signal */ + + switch (signal) { /* dispatch an I/O signal */ + + case INTPOLLIN: + if (dibptr->interrupt_request) { /* if a request is pending */ + dibptr->interrupt_request = CLEAR; /* then clear it */ + dibptr->interrupt_active = SET; /* and mark it now active */ + + outbound_signals |= INTACK; /* acknowledge the interrupt */ + outbound_value = dibptr->device_number; /* and return our device number */ + + control_word &= ~(CN_DEVSTAT | CN_IRQ_ENABLE); /* clear the device status and IRQ enable flip-flops */ + } + + else /* otherwise the request has been reset */ + outbound_signals |= INTPOLLOUT; /* so let the IOP know to cancel it */ + break; + + + case SETINT: + case DSETINT: + outbound_signals |= set_interrupt (ST_IOSYS_IRQ); /* set the I/O system interrupt flip-flop */ + break; + + + case DRESETINT: + dibptr->interrupt_active = CLEAR; /* reset the interrupt active flip-flop */ + outbound_signals |= set_interrupt (0); /* and check whether another IRQ is pending */ + break; + + + case DSETMASK: + if (dibptr->interrupt_mask == INTMASK_E) /* if the mask is always enabled */ + interrupt_mask = SET; /* then set the mask flip-flop */ + else /* otherwise */ + interrupt_mask = D_FF (dibptr->interrupt_mask /* set the mask flip-flop if the mask bit */ + & inbound_value); /* is present in the mask value */ + + outbound_signals |= set_interrupt (0); /* check whether an IRQ is pending */ + break; + + + case PCONTSTB: + if (! J2W1_INSTALLED) /* if W1 (SR set by Device Status) is not installed */ + device_sr = SET; /* then set the device service request flip-flop */ + + /* fall into the DCONTSTB case */ + + case DCONTSTB: + dprintf (lp_dev, DEB_CSRW, + (lp_dev.flags & DEV_DIAG && inbound_value & CN_DHA_FN_ENABLE + ? "Control is %s%s | %s\n" + : "Control is %s%s\n"), + fmt_bitset (inbound_value, + (lp_dev.flags & DEV_DIAG + ? dha_control_format + : prt_control_format)), + reset_irq_name [CN_RESET (inbound_value)], + dha_fn_name [CN_DHA_FN (inbound_value)]); + + if (inbound_value & CN_MR) /* if the programmed master reset bit is set */ + master_reset (TRUE); /* then reset the interface and the control word */ + + else if (inbound_value & CN_RIN) { /* otherwise if the reset interrupt bit is set */ + dibptr->interrupt_request = CLEAR; /* then clear the interrupt request */ + int_status_word = 0; /* and all interrupt sources */ + + sim_cancel (timer_uptr); /* cancel the transfer timer */ + control_word = inbound_value; /* and set the control word */ + } + + else { /* otherwise */ + int_status_word &= reset_irq [CN_RESET (inbound_value)]; /* clear the specified IRQ source */ + + if ((inbound_value & CN_RIN_MASK) == CN_RIN_XFR_TMR) /* if the timer interrupt was cleared */ + sim_cancel (timer_uptr); /* then stop the timer too */ + + else if (CN_XFR_TMR_ENABLE /* otherwise if the transfer timer */ + & ~control_word & inbound_value) { /* is enabled with a 0-to-1 transition */ + sim_cancel (timer_uptr); /* then retrigger */ + activate_unit (timer_uptr); /* the timer */ + } + + control_word = inbound_value; /* set the control word */ + } + + if (control_word & CN_ACQUIRE) { /* if the next word is requested */ + device_command = SET; /* then set the device command flip-flop */ + read_xfer = SET; /* and the read transfer flip-flop */ + outbound_signals |= handshake_xfer (); /* and start the device handshake */ + } + + if (lp_dev.flags & DEV_DIAG) /* if the DHA is installed */ + outbound_signals |= diag_control (control_word); /* then process the DHA-specific controls */ + else /* otherwise */ + outbound_signals |= lp_control (control_word); /* process the device-specific controls */ + + break; + + + case PSTATSTB: + case DSTATSTB: + outbound_value = sequence_counter [sequencer]; /* start with the sequence counter value */ + + if (sio_busy == CLEAR /* if the interface is inactive */ + && (int_status_word & ST_CLRIL) == 0) /* and the clear interface logic IRQ is denied */ + outbound_value |= ST_SIO_OK; /* then programmed I/O is enabled */ + + if (sequencer == Idle) /* if the device is inactive */ + outbound_value |= ST_DIO_OK; /* then direct I/O is enabled */ + + if (int_status_word) /* if any interrupt requests are pending */ + outbound_value |= ST_IRQ_PENDING; /* then set the status bit */ + + if (device_flag_in) /* if the device flag is asserted */ + outbound_value |= ST_DEVFLAG; /* then set the status bit */ + + if (control_word & CN_DEVSTAT) /* if the device status flip-flop is set */ + outbound_value |= ST_DEVSTAT | dev_status_word; /* then return the device status */ + else /* otherwise */ + outbound_value |= int_status_word; /* return the interrupt status */ + + dprintf (lp_dev, DEB_CSRW, "Status is %s\n", + fmt_bitset (outbound_value, + (control_word & CN_DEVSTAT + ? (lp_dev.flags & DEV_DIAG + ? dev_status_format + : prt_status_format) + : int_status_format))); + break; + + + case DREADSTB: + outbound_value = (HP_WORD) read_word; /* return the data input register value */ + break; + + + case DWRITESTB: + write_word = (uint32) inbound_value; /* store the value in the data output register */ + + device_command = SET; /* set the device command flip-flop */ + write_xfer = SET; /* and the write transfer flip-flop */ + outbound_signals |= handshake_xfer (); /* and start the device handshake */ + break; + + + case DSTARTIO: + dprintf (lp_dev, DEB_CSRW, "Channel program started\n"); + + sio_busy = SET; /* set the SIO busy flip-flop */ + + mpx_assert_REQ (dibptr); /* request the channel */ + + channel_sr = SET; /* set the service request flip-flop */ + outbound_signals |= SRn; /* and assert a service request */ + break; + + + case ACKSR: + device_sr = CLEAR; /* acknowledge the service request */ + + abort_transfer = (t_bool) device_end; /* TRUE if the transfer is to be aborted */ + device_end = CLEAR; /* clear the device end flip-flop */ + break; + + + case TOGGLESR: + TOGGLE (channel_sr); /* set or clear the channel service request flip-flop */ + break; + + + case TOGGLESIOOK: + TOGGLE (sio_busy); /* set or clear the SIO busy flip-flop */ + + if (sio_busy == CLEAR) + dprintf (lp_dev, DEB_CSRW, "Channel program ended\n"); + break; + + + case TOGGLEINXFER: + TOGGLE (input_xfer); /* set or clear the input transfer flip-flop */ + + device_end_in = FALSE; /* clear the external device end condition */ + break; + + + case TOGGLEOUTXFER: + TOGGLE (output_xfer); /* set or clear the output transfer flip-flop */ + + if (output_xfer == SET) /* if starting an output transfer */ + device_sr = SET; /* request the first word to write */ + + device_end_in = FALSE; /* clear the external device end condition */ + break; + + + case PCMD1: + device_sr = SET; /* request the second control word */ + break; + + + case READNEXTWD: + device_command = SET; /* set the device command flip-flop */ + read_xfer = SET; /* and the read transfer flip-flop */ + outbound_signals |= handshake_xfer (); /* and start the device handshake */ + break; + + + case PREADSTB: + if (abort_transfer) { /* if the transfer has been aborted */ + outbound_value = dibptr->device_number * 4; /* then return the DRT address */ + outbound_signals |= DEVEND; /* and indicate a device abort */ + } + + else /* otherwise the transfer continues */ + outbound_value = (HP_WORD) read_word; /* so return the data input register value */ + break; + + + case PWRITESTB: + if (abort_transfer) { /* if the transfer has been aborted */ + outbound_value = dibptr->device_number * 4; /* then return the DRT address */ + outbound_signals |= DEVEND; /* and indicate a device abort */ + } + + else { /* otherwise the transfer continues */ + write_word = (uint32) inbound_value; /* so store the value in the data output register */ + + device_command = SET; /* set the device command flip-flop */ + write_xfer = SET; /* and the write transfer flip-flop */ + outbound_signals |= handshake_xfer (); /* and start the device handshake */ + } + break; + + + case DEVNODB: + outbound_value = dibptr->device_number * 4; /* return the DRT address */ + break; + + + case XFERERROR: + dprintf (lp_dev, DEB_CSRW, "Channel program aborted\n"); + + clear_interface_logic (); /* clear the interface to abort the transfer */ + + outbound_signals |= set_interrupt (ST_XFERERR_IRQ); /* set the transfer error interrupt flip-flop */ + break; + + + case CHANSO: + if (channel_sr | device_sr) /* if the interface has requested service */ + outbound_signals |= SRn; /* then assert SRn to the channel */ + + outbound_signals |= JMPMET; /* JMPMET is tied active on this interface */ + break; + + + case EOT: + if (inbound_signals & PREADSTB) /* if this is the end of a read transfer */ + device_sr = SET; /* then request channel service */ + break; + + + case PFWARN: /* not currently simulated */ + break; + + + case SETJMP: /* not used by this interface */ + break; + } + + IOCLEARSIG (working_set, signal); /* remove the current signal from the set */ + } + + +dprintf (lp_dev, DEB_IOB, "Returned data %06o with signals %s\n", + outbound_value, fmt_bitset (outbound_signals, outbound_format)); + +return IORETURN (outbound_signals, outbound_value); /* return the outbound signals and value */ +} + + +/* Service the transfer handshake. + + 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. + + 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 + signal from the device used to assert and deny the Device Flag, as follows: + + Jumper Interpretation when removed Interpretation when installed + ------ ----------------------------- ----------------------------- + W10 DEV CMD polarity is normal DEV CMD polarity is inverted + + W2 Flag asserts on leading edge Flag asserts on trailing edge + + W6 Flag denies on trailing edge Flag denies on leading edge + + Note that if jumpers W2 and W6 are not installed or removed in pairs, the + Device Flag asserts and denies on the same edge of the DEV FLAG signal. In + this case, the service routine sets the flag on the first call and clears the + flag on the second call without requiring a change in the incoming signal. + + + Implementation notes: + + 1. The "device_command_out" and "device_flag_in" variables represent the + states of the DEV CMD and DEV FLAG signal lines. Edge detection for the + 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 + 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. + + 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 + indicates that this is not part of the normal handshake sequence. +*/ + +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; + +device_command_out = device_command ^ J2W10_INSTALLED; /* set device command out; invert if W10 is installed */ + +if (lp_dev.flags & DEV_DIAG) /* if the DHA is connected */ + result = diag_service (uptr); /* then service the diagnostic hardware */ +else /* otherwise */ + result = lp_service (uptr); /* service the connected device */ + +if (sequencer == Device_Command_1 /* if Device Command */ + || sequencer == Device_Command_2) { /* is asserted */ + if (device_flag_last != device_flag_in /* then if the flag input has changed */ + && J2W2_INSTALLED ^ device_flag_in) /* and jumper W2 is in and 1 -> 0 or W2 is out and 0 -> 1 */ + device_flag = SET; /* then Device Flag sets */ + } + +else /* otherwise Device Command is denied */ + if (J2W2_INSTALLED != J2W6_INSTALLED /* so if W2 installation differs from W6 installation */ + || (device_flag_last != device_flag_in /* or if the flag input has changed */ + && J2W6_INSTALLED ^ device_flag_last)) /* and jumper W6 is in and 0 -> 1 or W6 is out and 1 -> 0 */ + device_flag = CLEAR; /* then Device Flag clears */ + +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 */ + + 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 */ + } + +return result; /* return the result of the service call */ +} + + +/* Service the device command pulse timer. + + In pulse mode, the DEV CMD signal asserts for 8 microseconds. This service + routine is entered to deny DEV CMD. The transfer service is called directly + to notify it of Device Command clearing, and the handshake sequencer is then + called in case the transfer service altered the Device Flag in response. +*/ + +static t_stat pulse_service (UNIT *uptr) +{ +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 */ +handshake_xfer (); /* and continue the handshake */ + +return SCPE_OK; +} + + +/* Service the transfer timer. + + Setting the appropriate bit in the control word starts the five-second + transfer timer. If it expires, this routine is entered. The transfer timer + interrupt is set, and if interrupts are enabled, INTREQ is asserted to the + IOP. As a convenience to the user, the file attached to the device unit is + flushed. +*/ + +static t_stat timer_service (UNIT *uptr) +{ +dprintf (lp_dev, DEB_SERV, "Watchdog service entered\n"); + +if (set_interrupt (ST_XFR_TMR_IRQ) == INTREQ) /* set the transfer timer interrupt flip-flop */ + iop_assert_INTREQ (&lp_dib); /* and assert the INTREQ signal if enabled */ + +if (xfer_unit.flags & UNIT_ATT) /* if the transfer unit is attached */ + fflush (xfer_unit.fileref); /* then flush any partial output */ + +return SCPE_OK; /* return success */ +} + + +/* Device reset routine. + + This routine is called for a RESET or RESET LP command. It is the simulation + equivalent of the IORESET signal, which is asserted by the front panel LOAD + and DUMP switches. + + For this interface, IORESET is identical to the Programmed Master Clear + invoked by setting bit 0 of the control word. + + + Implementation notes: + + 1. Calling "master_clear" with a FALSE parameter indicates that this is a + commanded reset. This allows the connected device-specific reset + routines to distinguish from a Programmed Master Clear. +*/ + +static t_stat ui_reset (DEVICE *dptr) +{ +return master_reset (FALSE); /* perform a non-programmed master reset */ +} + + + +/* Interface local utility routines */ + + + +/* Master reset. + + A master reset is generated either by an I/O Reset signal or a Programmed + Master Clear (CIO bit 0). It sets the interrupt mask, clears any pending or + active interrupt, clears all interrupt sources, clears the control word, + clears the read and write registers, resets the handshake sequencer to its + idle state, clears the interface logic flip-flops, and cancels all active + event timers. It also calls pulses the MASTER CLEAR signal line to the + device for a preset time. + + + Implementation notes: + + 1. Calling the reset routine for the connected device simulates asserting + the MASTER CLEAR signal. +*/ + +static t_stat master_reset (t_bool programmed_clear) +{ +interrupt_mask = SET; /* set the interrupt mask flip-flop */ + +lp_dib.interrupt_request = CLEAR; /* clear any current */ +lp_dib.interrupt_active = CLEAR; /* interrupt request */ + +int_status_word = 0; /* clear all interrupt request sources */ + +control_word = 0; /* clear the control word */ +write_word = 0; /* and the output data register */ +read_word = 0; /* and the input data register */ + +sequencer = Idle; /* clear the handshake sequencer to the idle state */ + +read_xfer = CLEAR; /* clear the read transfer */ +write_xfer = CLEAR; /* and write transfer flip-flops */ + +device_command = CLEAR; /* clear the device command */ +device_flag = CLEAR; /* and device flag flip-flops */ + +data_out = 0; /* clear the external state */ +data_in = 0; /* of the I/O lines */ +device_end_in = FALSE; /* and the external device end line */ + +clear_interface_logic (); /* clear the interface to abort any transfer in progress */ + +sim_cancel (xfer_uptr); /* cancel */ +sim_cancel (pulse_uptr); /* any pending */ +sim_cancel (timer_uptr); /* event timers */ + +if (lp_dev.flags & DEV_DIAG) /* if the DHA is installed */ + return diag_reset (programmed_clear); /* then reset the diagnostic hardware */ +else /* otherwise */ + return lp_reset (programmed_clear); /* reset the device */ +} + + +/* Clear the interface logic. + + The clear interface logic signal is asserted when the channel indicates a + transfer failure by asserting XFERERROR, or when the device asserts the CLEAR + INTERFACE signal. It clears the SIO Busy, Channel and Device Service + Request, Input Transfer, Output Transfer, and Device End flip-flops. +*/ + +static void clear_interface_logic (void) +{ +sio_busy = CLEAR; /* clear the SIO busy flip-flop */ +channel_sr = CLEAR; /* and the channel service request flip-flop */ +device_sr = CLEAR; /* and the device service request flip-flop */ +input_xfer = CLEAR; /* and the input transfer flip-flop */ +output_xfer = CLEAR; /* and the output transfer flip-flop */ +device_end = CLEAR; /* and the device end flip-flop */ + +return; +} + + +/* Activate a 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. +*/ + +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); + + sim_activate (uptr, uptr->wait); /* then activate the unit */ + } + +else /* otherwise */ + uptr->action (uptr); /* call the event handler directly */ + +return; +} + + +/* Set an interrupt. + + The interrupt bit specified is set in the interrupt status word. If enabled, + INTREQ is returned to request an interrupt. + + The routine is also called with a zero "interrupt" parameter value to check + whether an interrupt should be requested. +*/ + +static OUTBOUND_SET set_interrupt (uint32 interrupt) +{ +int_status_word |= interrupt; /* set the specified interrupt flip-flop */ + +if (int_status_word /* if an interrupt request is present */ + && control_word & CN_IRQ_ENABLE /* and the IRQ enable flip-flop is set */ + && lp_dib.interrupt_active == CLEAR /* and no interrupt is currently active */ + && interrupt_mask == SET) { /* and the interrupt mask is satisfied */ + lp_dib.interrupt_request = SET; /* then request an interrupt */ + return INTREQ; /* and assert the INTREQ signal */ + } + +else /* otherwise an interrupt request */ + return NO_SIGNALS; /* cannot be made at this time */ +} + + +/* Set the device status. + + The device status word is masked with the supplied "status_mask" and then the + corresponding bits of the "new_status_word" are merged in. If enabled by the + associated jumpers and the required edge transitions, interrupts for status + bits 8-10 may be generated. +*/ + +static OUTBOUND_SET set_device_status (uint32 status_mask, uint32 new_status_word) +{ +OUTBOUND_SET outbound_signals = NO_SIGNALS; + +if (status_mask & ST_DEVIRQ_MASK) { /* if a status interrupt is possible */ + if (J2W4_INSTALLED /* then if jumper J4 is installed to enable */ + && ~dev_status_word & new_status_word & ST_ST8_IRQ) /* and a 0 -> 1 transition occurred on status 8 */ + outbound_signals |= set_interrupt (ST_ST8_IRQ); /* then set the status 8 interrupt flip-flop */ + + if (J2W8_INSTALLED /* if jumper J8 is installed to enable */ + && ~dev_status_word & new_status_word & ST_ST9_IRQ) /* and a 0 -> 1 transition occurred on status 9 */ + outbound_signals |= set_interrupt (ST_ST9_IRQ); /* then set the status 9 interrupt flip-flop */ + + if (J2W9_INSTALLED /* if jumper J9 is installed to enable */ + && dev_status_word & ~new_status_word & ST_ST10_IRQ) /* and a 1 -> 0 transition occurred on status 10 */ + outbound_signals |= set_interrupt (ST_ST10_IRQ); /* then set the status 10 interrupt flip-flop */ + } + +dev_status_word = dev_status_word & ~status_mask /* clear the old device status */ + | new_status_word & status_mask; /* and set the new status */ + +return outbound_signals; /* return INTREQ if any interrupts were requested */ +} + + +/* Start or continue the data transfer handshake. + + This routine implements the two-wire data transfer handshake with the device. + For each word or byte transferred, the Device Command signal from the + interface and the Device Flag signal from the device assume these states: + + Command Flag State Next State + State State Action Transition + -------- -------- ---------------- -------------- + denied denied device idle Command sets + asserted denied device started Flag sets + asserted asserted device completed Command clears + denied asserted interface idle Flag clears + + In hardware, a two-bit gray counter implements a four-state sequencer, with + three states assigned as follows for a word transfer: + + Command Flag + State State Action State State Next State Transition + ----- ------------------ -------- -------- --------------------- + 0 0 idle denied denied read or write command + 1 0 word requested asserted denied Flag sets + 1 1 word started denied asserted Flag clears + 0 0 word completed denied denied --- + + For a two-byte transfer, the states are: + + Command Flag + State State Action State State Next State Transition + ----- ------------------ -------- -------- --------------------- + 0 0 idle denied denied read or write command + 1 0 1st byte requested asserted denied Flag sets + 1 1 1st byte started denied asserted Flag clears + 1 0 1st byte completed asserted denied Flag sets + 2nd byte requested + 0 0 2nd byte started denied asserted Flag clears + 0 0 2nd byte completed denied denied --- + + The presence of the asserted Device Flag when the count is 00 differentiates + between the "2nd byte started" and "operation completed" conditions. + + In simulation, these last two conditions are assigned to separate states, as + follows: + + Hdwe Simulation Command Flag + State State State State + ----- ---------------- -------- -------- + 0 0 Idle denied denied + 1 0 Device_Command_1 asserted denied + 1 1 Device_Flag_1 denied asserted + 1 0 Device_Command_2 asserted denied + 0 0 Device_Flag_2 denied asserted + 0 0 Idle denied denied + + To provide the proper values to appear in the Sequence Counter field of the + status word, a mapping array is used to supply the value 00 for the + Device_Flag_2 state. + + 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. + + 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). + + 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 + ---------------- ---------------- ------------------ ------------------- + Device_Command_1 set Flag set Flag wait for Control.6 + Device_Flag_1 wait for service clear Flag wait for Control.6 + Device_Command_2 set Flag set Flag wait for Control.6 + Device_Flag_2 wait for service clear Flag wait for Control.6 + + If the device asserts the DEV END signal in response to Device Command, the + Device End flip-flop is set, and the sequencer is reset back to the Idle + state to abort the transfer. DEV END assertion in any other state is ignored + until Device Command is set. + + If jumper W3 is installed, DEV CMD is pulsed for 8 microseconds by asserting + Device Command and scheduling the pulse timer to deny it when the event timer + expires. + + A DWRITESTB or PWRITESTB signal stores a 16-bit value in the data output + register. In word mode, the value is presented continuously on the 16 DATA + OUT lines. In byte mode, the upper byte in the data output register is + presented on both bytes of the DATA OUT lines until the Device Flag sets to + indicate that the device has accepted the first byte, whereupon the full + 16-bit value is presented on the DATA OUT lines. The result is that the + upper byte and then the lower byte appears on the lower byte of the DATA OUT + lines. + + During byte-mode read cycles, the previously stored full 16-bit output value + is presented on the DATA OUT lines if J2W7 is removed. If J2W7 is installed, + the upper byte and then the lower byte appears on the lower byte. In other + words, a byte read with J2W7 installed causes the DATA OUT lines to assume + the same values in sequence that occur during a byte write. This is used by + the diagnostic to test the DATA OUT multiplexer. + + A read is initiated by the READNEXTWD signal or by setting the Acquire bit in + the control word. Device Command sets in response. While Device Command is + set, the data input register is transparent and passes the value on the Data + In lines through. When Device Flag sets, the value on the DATA IN lines is + latched in the register. A DREADSTB or PREADSTB signal then enables the + register onto the IOP Data bus. With J2W5 installed, the data in register is + always transparent, and a DREADSTB or PREADSTB signal presents the current + value on the DATA IN lines to the IOP Data bus. + + In word mode with J2W5 removed, 16-bit data presented at the DATA IN lines is + passed through the data input register while Device Command is set and is + latched when the Device Flag sets. In byte mode with J2W5 removed, the value + presented on the lower byte of the DATA IN lines is presented to both bytes + of the data input register, passed through while Device Command is set, and + latched into both bytes of the register when the Device Flag sets to indicate + that the device has supplied the first byte. When Device Command sets for + the second byte, the value presented on the lower byte of the DATA IN lines + is presented to the lower byte of the data input register, passed through + while Device Command is set, and latched into the lower byte when the Device + Flag sets to indicate that the device has supplied the second byte. The + result is that the data input register presents the first byte in both bytes + of the register and then the second byte presents as the lower byte of the + register, resulting in a packed 16-bit value. + + + Implementation notes: + + 1. In hardware, the sequencer moves from state 2 through state 3 to state 0 + when the device flag denies at the end of a word transfer. For a packed + byte transfer, the sequencer moves from state 3 to state 0 when the + device flag asserts for the second byte, with logic holding off the + "operation done" signal until the flag denies. + + In simulation, the sequencer moves on flag denial directly from + Device_Flag_1 to Idle for a word transfer and on flag assertion from + Device_Command_2 to Device_Flag_2 and then on flag denial to Idle for a + second byte transfer. The sequence count reported in a status return is + 0 for Device_Flag_2, preserving the appearance of returning to state 0 + while the internal Device_Flag_2 state holds off the "operation done" + signal. + + 2. In hardware, a DEV END signal asserts the Q2 and Q3 qualifiers, enabling + the sequence counter to proceed through the state sequence back to the + idle state. In simulation, the sequencer state is set directly back to + Idle. + + 3. In hardware, with jumper W5 out, the DATA IN latches are transparent in + the Device_Command_1 and Device_Command_2 states and are latched + otherwise, i.e., when Device Flag asserts. With jumper W5 in, the + latches are transparent always, and a read gets the real-time state of + the DATA IN lines. In simulation, the read register is set when Device + Flag asserts; transparency is not simulated. + + 4. The diagnostic tests the byte unpacking and packing multiplexers on the + DATA OUT and DATA IN lines, so we must simulate the multiplexing + accurately with respect to the intermediate values before the handshake + is complete. +*/ + +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 */ +OUTBOUND_SET outbound_signals = NO_SIGNALS; +SEQ_STATE last_state; + +do { /* run the sequencer as long as it advances */ + last_state = sequencer; /* save the last state to see if it changes */ + + if (sequencer < Device_Command_2 /* if this is the first byte */ + && control_word & CN_BYTE_XFER /* of a byte transfer */ + && (J2W7_INSTALLED || write_xfer)) /* and W7 is installed or it's a write transfer */ + data_out = write_word & ~D8_MASK /* then the upper 8 bits appear */ + | UPPER_BYTE (write_word); /* in both bytes */ + else /* otherwise */ + data_out = write_word; /* the full 16 bits appear */ + + + switch (sequencer) { /* dispatch the current state */ + + case Idle: + if (device_command == SET) { /* if device command has been set */ + sequencer = Device_Command_1; /* then proceed to the next state */ + + if (device_end_in /* if external device end asserts */ + && (read_xfer || write_xfer)) /* during a transfer */ + device_command = CLEAR; /* then device command is inhibited */ + + else { /* otherwise */ + if (J2W3_INSTALLED) /* if jumper W3 (pulse mode) is installed */ + activate_unit (pulse_uptr); /* then schedule device command denial */ + + activate_unit (xfer_uptr); /* schedule device flag assertion */ + } + + started = TRUE; /* indicate that the sequencer was started */ + } + break; + + + case Device_Command_1: + if (device_end_in) /* if external device end asserts */ + if (read_xfer || write_xfer) { /* then if a transfer is in progress */ + device_end = SET; /* then set the Device End flip-flop to abort */ + + device_command = CLEAR; /* clear the device command */ + read_xfer = CLEAR; /* and read transfer */ + write_xfer = CLEAR; /* and write transfer flip-flops */ + + sequencer = Idle; /* idle the sequencer */ + device_sr = SET; /* and request channel service */ + break; + } + + else /* otherwise no transfer is in progress */ + device_end_in = FALSE; /* so clear the signal */ + + if (device_flag == SET) { /* if the device flag has been set */ + sequencer = Device_Flag_1; /* then proceed to the next state */ + device_command = CLEAR; /* and deny device command */ + + activate_unit (xfer_uptr); /* schedule device flag denial */ + + if (control_word & CN_BYTE_XFER) /* if this is a byte transfer */ + read_word = TO_WORD (data_in, data_in); /* then the lower 8 bits appear in both bytes */ + else /* otherwise */ + read_word = data_in; /* the full 16 bits appear */ + + if (J2W1_INSTALLED && sio_busy /* if jumper W1 (status drives SR) is installed */ + && dev_status_word & ST_ST11_SR) /* and a transfer is in progress with status 11 set */ + device_sr = SET; /* then request channel service */ + } + break; + + + case Device_Flag_1: + if (device_flag == CLEAR) /* if the device flag has been cleared */ + if (control_word & CN_BYTE_XFER) { /* then if this is a byte transfer */ + sequencer = Device_Command_2; /* then proceed to the next state */ + device_command = SET; /* and assert device command for the second byte */ + + data_out = write_word; /* latch the output word */ + + activate_unit (xfer_uptr); /* schedule device flag assertion */ + } + + else { /* otherwise the transfer is complete */ + read_xfer = CLEAR; /* so clear the read transfer */ + write_xfer = CLEAR; /* and write transfer flip-flops */ + + sequencer = Idle; /* idle the sequencer */ + device_sr = SET; /* and request channel service */ + + if (control_word & CN_XFR_IRQ_ENABLE) /* if a transfer interrupt is requested */ + outbound_signals |= set_interrupt (ST_XFR_IRQ); /* then set the transfer interrupt flip-flop */ + } + break; + + + case Device_Command_2: + if (device_flag == SET || device_end_in) { /* if the device flag or external device end has been set */ + sequencer = Device_Flag_2; /* then proceed to the next state */ + device_command = CLEAR; + + activate_unit (xfer_uptr); /* schedule device flag denial */ + + read_word &= ~D8_MASK; /* clear the lower byte */ + + if (device_end_in == FALSE) /* if the transfer succeeded */ + read_word |= LOWER_BYTE (data_in); /* then merge the received lower byte */ + } + break; + + + case Device_Flag_2: + if (device_flag == CLEAR) { /* if the device flag was cleared */ + read_xfer = CLEAR; /* then clear the read transfer */ + write_xfer = CLEAR; /* and write transfer flip-flops */ + + sequencer = Idle; /* idle the sequencer */ + device_sr = SET; /* and request channel service */ + + if (control_word & CN_XFR_IRQ_ENABLE) /* if a transfer interrupt is requested */ + outbound_signals |= set_interrupt (ST_XFR_IRQ); /* then set the transfer interrupt flip-flop */ + } + break; + } /* end of state dispatching */ + } +while (sequencer != last_state); /* continue as long as the sequence is progressing */ + + +if (DPRINTING (lp_dev, DEB_STATE)) + if (sequencer != entry_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")); + +if (device_sr && sio_busy) /* if the interface has requested service */ + outbound_signals |= SRn; /* then assert SRn to the channel */ + +return outbound_signals; /* return the accumulated signals */ +} + + + +/* Diagnostic Hardware Assembly local SCP support routines */ + + + +/* Service the transfer handshake for the Diagnostic Hardware Assembly. + + The DHA loops the data out lines back to the data in lines, with bits 11-15 + also connecting to bits 11-15 of the status in lines. The DHA also may be + configured to connect either the DEV CMD output or the CONT 6 output to the + DEV FLAG input. + + + Implementation notes: + + 1. The DHA transfer service is called with a null pointer to update the + potential change in the flag state. +*/ + +static t_stat diag_service (UNIT *uptr) +{ +if (uptr) /* trace only if this is a handshake entry */ + dprintf (lp_dev, DEB_SERV, "%s state transfer service entered\n", + state_name [sequencer]); + +if (dha_control_word & DHA_FLAG_SEL) /* if in "flag follows control 6" mode */ + device_flag_in = (control_word & CN_DHA_FLAG) != 0; /* then set the flag from control word bit 6 */ +else /* otherwise */ + device_flag_in = device_command_out; /* device flag is connected to device command */ + +data_in = data_out; /* data in is connected to data out */ + +set_device_status (ST_DHA_DEVSTAT_MASK, data_out); /* status bits 11-15 are connected to data out */ + +return SCPE_OK; +} + + + +/* Diagnostic Hardware Assembly local utility routines */ + + + +/* Diagnostic hardware assembly reset. + + When the MASTER CLEAR signal is asserted to the DHA, the master reset bit in + the DHA control word is set. In addition, the status bits connected to the + DATA OUT lines from the interface are cleared, as the interface has cleared + its output register. + + If this reset was caused by a RESET or RESET LP command, the set of installed + jumpers in the DHA control word is updated. This picks up any jumper changes + made at the user interface. + + + Implementation notes: + + 1. The DHA transfer service is called with a null pointer to update the + potential change in the DEV FLAG state that may have occurred by a change + to the DEV CMD state if the lines are connected. +*/ + +static t_stat diag_reset (t_bool programmed_clear) +{ +if (programmed_clear) { /* if this is a programmed master clear */ + dha_control_word |= DHA_MR; /* then record the master reset */ + + set_device_status (ST_DHA_DEVSTAT_MASK, data_out); /* clear the status bits connected to data out */ + + xfer_service (NULL); /* update the current device flag state */ + } + +else /* otherwise this is a commanded reset */ + dha_control_word = dha_control_word & DHA_JUMPER_MASK /* so refresh the DHA control word */ + | jumper_set; /* from the jumpers */ + +return SCPE_OK; +} + + +/* Process the diagnostic hardware assembly control word. + + This routine is called when a DCONTSTB or PCONTSTB assertion indicates that + the control word is to be set. If bit 10 is set, then bits 6-9 represent an + encoded action to be taken by the DHA. Two of the actions potentially change + the state of the device status lines, which may also generate an interrupt if + properly configured and enabled. In addition, the DEV FLAG signal may + change, depending on the state of the "flag follows control bit 6" action, + which may cause the handshake sequencer to change states. + + + Implementation notes: + + 1. The jumpers part of the DHA control word is "cleared" to all ones, which + corresponds to installing all of the jumpers. + + 2. The DHA transfer service is called with a null pointer to update the + potential change in the flag state. +*/ + +static OUTBOUND_SET diag_control (uint32 control_word) +{ +uint32 new_status; +OUTBOUND_SET outbound_signals = NO_SIGNALS; + +if (control_word & CN_DHA_FN_ENABLE) /* if the decoder is enabled */ + switch (CN_DHA_FN (control_word)) { /* then decode the DHA command */ + + case 0: /* clear the registers */ + dha_control_word = DHA_CLEAR; /* initialize the DHA control word */ + jumper_set = DHA_CLEAR & DHA_JUMPER_MASK; /* and install all of the jumpers */ + break; + + case 2: /* assert the Device End signal */ + device_end_in = TRUE; /* set the external device end line */ + break; + + case 4: /* set the Transfer Error flip-flop */ + outbound_signals = set_interrupt (ST_XFERERR_IRQ); /* set the transfer error interrupt flip-flop */ + break; + + case 8: /* connect the device flag to control bit 6 */ + dha_control_word |= DHA_FLAG_SEL; /* set the "flag follows control 6" bit */ + break; + + case 10: /* assert the Clear Interface signal */ + clear_interface_logic (); /* clear the interface logic */ + outbound_signals = set_interrupt (ST_CLRIF_IRQ); /* and set the clear interface interrupt flip-flop */ + break; + + case 12: /* connect status 8-10 to master clear/power on/power fail */ + dha_control_word |= DHA_STAT_SEL; /* set the "status follows master clear-power on-power fail" bit */ + break; + + default: /* remove a jumper */ + dha_control_word &= jumper_map [CN_DHA_FN (control_word)]; /* clear the specified control register bit */ + jumper_set = dha_control_word & DHA_JUMPER_MASK; /* and remove the indicated jumper */ + break; + } + + +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 */ + + if (dha_control_word & DHA_MR) /* if a master reset is requested */ + new_status |= ST_DHA_MR; /* then indicate a master clear */ + } + +else /* otherwise set the device status */ + new_status = ST_DEVIRQ (CN_DHA_ST (control_word)); /* from the connected DHA control bits */ + +outbound_signals |= set_device_status (ST_DEVIRQ_MASK, new_status); /* set the status and test for IRQs */ + +xfer_service (NULL); /* record the current device flag state */ + +outbound_signals |= handshake_xfer (); /* check for a device handshake transition */ + +return outbound_signals; /* return INTREQ if any interrupts were requested */ +} + + + +/* Printer local SCP support routines */ + + + +/* Service the transfer handshake for the printer. + + The printer transfer service is called to output a character to the printer + buffer or to output a format command that causes the buffered line to be + printed with specified paper movement. + + In hardware, the interface places a character or format code on the lower + seven data out lines and asserts STROBE (DEV CMD) to the printer. The + printer responds by denying DEMAND (asserting DEV FLAG). The interface then + denies STROBE and waits for the printer to reassert DEMAND (deny DEV FLAG) to + 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. + + 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 + data exists in the print buffer or the printer is currently printing a line. + In this case, the action is deferred until the service routine is entered to + complete a print operation. At that point, the printer goes offline with + DEMAND denied. This leaves the transfer handshake incomplete. When the + printer is placed back online, this routine is called to assert DEMAND and + conclude the handshake. + + Control word bit 10 determines whether the code on the data out lines is + interpreted as a character (0) or a format command (1). Character data is + loaded into the buffer; if the line length is exceeded, the printer + automatically prints the buffer contents, advances the paper one line, and + stores the new character in the empty buffer. If a control character is sent + but the printer cannot print it, a space is loaded in its place. + + A format command causes the current buffer to be printed, and then the paper + is advanced by a prescribed amount. Two output modes are provided: compact + and expanded. + + In compact mode, a printed line is terminated by a CR LF pair, but subsequent + line spacing is performed by LFs alone. Also, a top-of-form request will + emit a FF character instead of the number of LFs required to reach the top of + the next form, and overprinting is handled by emitting a lone CR at the end + of the line. This mode is used when the printer output file will be sent to + a physical printer connected to the host. + + In expanded mode, paper advance is handled solely by emitting CR LF pairs. + Overprinting is handled by merging characters in the buffer. This mode is + used where the printer output file will be saved or manipulated as a text + file. + + The format commands recognized by the printer are: + + 0 x x 0 0 0 0 -- slew 0 lines (suppress spacing) after printing + ... + 0 x x 1 1 1 1 -- slew 15 lines after printing + + and: + + 1 x x 0 0 0 0 -- slew to VFU channel 1 after printing + ... + 1 x x 1 0 1 1 -- slew to VFU channel 12 after printing + + A command to slew to a VFU channel that is not punched or to a VFU channel + other than those defined for the printer will cause a tape fault, and the + printer will go offline; setting the printer back online will clear the + fault. Otherwise, LFs or a FF (compact mode) or CR LF pairs (expanded mode) + will be added to the buffer to advance the paper the required number of + lines. + + Not all printers can overprint. A request to suppress spacing on a printer + that cannot (e.g., the HP 2607) is treated as a request for single spacing. + + If the stream write fails, an error message is displayed on the simulation + console, a printer alarm condition is set (which takes the printer offline), + and SCPE_IOERR is returned to cause a simulation stop to give the user the + opportunity to fix the problem. Simulation may then be resumed, either with + the printer set back online if the problem is fixed, or with the printer + remaining offline if the problem is uncorrectable. + + + 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 + (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 + 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 + as many times as desired before issuing a format command that prints the + buffer. + + When overlaying characters, if a space overlays a printing character, a + printing character overlays a space, or a printing character overlays + itself, then the printing character is retained. Otherwise, an + "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 + 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 + TOF operation is performed. + + 6. 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 + potential change in the flag state. + + 8. 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 + until the printer is set online, and we are reentered with DEMAND + asserted. +*/ + +static t_stat lp_service (UNIT *uptr) +{ +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; +uint16 channel; +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 */ + +dprintf (lp_dev, DEB_SERV, "%s state printer service entered\n", + state_name [sequencer]); + +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 */ + + 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 */ + } + + else if (offline_pending) { /* otherwise if a non-alarm offline request is pending */ + lp_set_locality (uptr, Offline); /* then take the printer offline now */ + return SCPE_OK; + } + } + + device_flag_in = FALSE; /* assert DEMAND to complete the handshake */ + uptr->wait = 0; /* and request direct entry when STROBE next asserts */ + } + +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 */ + if (data_byte > '_' /* then if the character is "lowercase" */ + && print_props [model].char_set == 64) /* but the printer doesn't support it */ + data_byte = data_byte - 040; /* then shift it to "uppercase" */ + + if ((data_byte < ' ' || data_byte == DEL) /* if the character is a control character */ + && print_props [model].char_set != 128) /* but the printer doesn't support it */ + data_byte = ' '; /* then substitute a space */ + + if (buffer_index < print_props [model].line_length) { /* if there is room in the buffer */ + if (overprint_index == 0 /* then if not overprinting */ + || buffer_index >= overprint_index /* or past the current buffer limit */ + || buffer [buffer_index] == ' ') /* or overprinting a blank */ + buffer [buffer_index] = data_byte; /* then store the character */ + + else if (data_byte != ' ' /* otherwise if we're overprinting a character */ + && data_byte != buffer [buffer_index]) /* with a different character */ + buffer [buffer_index] = (uint8) overprint_char; /* then substitute the overprint character */ + + 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 */ + dprintf (lp_dev, DEB_CMD, "Buffer overflow printed %u characters on line %u\n", + buffer_index, current_line); + + buffer [buffer_index++] = CR; /* tie off */ + buffer [buffer_index++] = LF; /* the current buffer */ + + 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 */ + + current_line = current_line + 1; /* move the paper one line */ + + if (current_line > form_length) /* if the current line is beyond the end of the form */ + current_line = 1; /* then reset to the top of the next form */ + + dprintf (lp_dev, DEB_CMD, "Printer advanced 1 line to line %u\n", + current_line); + + overprint_index = 0; /* clear any accumulated overprint index */ + + 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 */ + } + } + + else { /* otherwise this is a print format command */ + dprintf (lp_dev, DEB_XFER, "Format code %03o sent to printer\n", + data_byte); + + format_byte = data_byte & FORMAT_MASK; /* format commands ignore bits 10-11 */ + + if (overprint_index > buffer_index) /* if the overprinted line is longer than the current line */ + buffer_index = overprint_index; /* then extend the current buffer index */ + + if (buffer_index > 0 && format_byte != FORMAT_SUPPRESS) /* if printing will occur, then trace it */ + dprintf (lp_dev, DEB_CMD, "Printed %u character%s on line %u\n", + buffer_index, (buffer_index == 1 ? "" : "s"), current_line); + + if (format_byte == FORMAT_SUPPRESS /* if this is a "suppress space" request */ + && print_props [model].overprints) { /* and the printer is capable of overprinting */ + slew_count = 0; /* then do not slew after printing */ + + if (uptr->flags & UNIT_EXPAND) { /* if the printer is in expanded mode */ + if (buffer_index > overprint_index) /* then if the current line is longer than the overprinted line */ + overprint_index = buffer_index; /* then extend the overprinted line */ + + buffer_index = 0; /* reset the buffer index to overprint the next line */ + } + + else /* otherwise the printer is in compact mode */ + buffer [buffer_index++] = CR; /* so overprint by emitting a CR without a LF */ + + dprintf (lp_dev, DEB_CMD, "Printer commanded to suppress spacing on line %u\n", + current_line); + } + + else if (format_byte & FORMAT_VFU) { /* otherwise if this is a VFU command */ + if (print_props [model].vfu_channels == 8) /* then if it's an 8-channel VFU */ + format_byte &= FORMAT_VFU_8_MASK; /* then only three bits are significant */ + + channel = VFU_CHANNEL_1 >> (format_byte - FORMAT_VFU_BIAS - 1); /* set the requested channel */ + + dprintf (lp_dev, DEB_CMD, "Printer commanded to slew to VFU channel %u from line %u\n", + format_byte - FORMAT_VFU_BIAS, current_line); + + tape_fault = (channel & VFU [0]) == 0; /* a tape fault occurs if there is no punch in this channel */ + + slew_count = 0; /* initialize the slew counter */ + + do { /* the VFU always slews at least one line */ + slew_count++; /* increment the slew counter */ + current_line++; /* and the line counter */ + + if (current_line > form_length) /* if the current line is beyond the end of the form */ + current_line = 1; /* then reset to the top of the next form */ + } + while (!tape_fault && (channel & VFU [current_line]) == 0); /* continue until a punch is seen */ + } + + else { /* otherwise it must be a slew command */ + slew_count = format_byte; /* get the number of lines to slew */ + + if (format_byte == FORMAT_SUPPRESS) /* if the printer cannot overprint */ + slew_count = 1; /* then the paper advances after printing */ + + dprintf (lp_dev, DEB_CMD, "Printer commanded to slew %u line%s from line %u\n", + slew_count, (slew_count == 1 ? "" : "s"), current_line); + + current_line = current_line + slew_count; /* move the current line */ + + if (current_line > form_length) /* if the current line is beyond the end of the form */ + current_line = current_line - form_length; /* then it extends onto the next form */ + } + + if (format_byte == FORMAT_VFU_CHAN_1 /* if a TOF was requested */ + && !(uptr->flags & UNIT_EXPAND) /* and the printer is in compact mode */ + && slew_count > 1) { /* and more than one line is needed to reach the TOF */ + if (buffer_index > 0) { /* then if the buffer not empty */ + buffer [buffer_index++] = CR; /* then print */ + buffer [buffer_index++] = LF; /* the current line */ + } + + buffer [buffer_index++] = FF; /* emit a FF to move to the TOF */ + } + + else if (slew_count > 0) { /* otherwise a slew is needed */ + buffer [buffer_index++] = CR; /* then emit a CR LF */ + buffer [buffer_index++] = LF; /* to print the current line */ + + line_count = slew_count; /* get the number of lines to slew */ + + while (--line_count > 0) { /* while movement is needed */ + if (uptr->flags & UNIT_EXPAND) /* if the printer is in expanded mode */ + buffer [buffer_index++] = CR; /* then blank lines are CR LF pairs */ + + buffer [buffer_index++] = LF; /* otherwise just LFs are used */ + } + } + + if (buffer_index > 0) { /* if the buffer is not empty */ + fwrite (buffer, sizeof buffer [0], /* then write it to the printer file */ + buffer_index, uptr->fileref); + + overprint_index = 0; /* clear any existing overprint index */ + } + + vfu_status = 0; /* assume no punches for channels 9 and 12 */ + + if (print_props [model].vfu_channels > 8) { /* if the printer VFU has more than 8 channels */ + if (VFU [current_line] & VFU_CHANNEL_9) /* then if channel 9 is punched for this line */ + vfu_status |= ST_VFU_9; /* then report it in the device status */ + + if (VFU [current_line] & VFU_CHANNEL_12) /* if channel 12 is punched for this line */ + vfu_status |= ST_VFU_12; /* then report it in the device status */ + } + + set_device_status (ST_VFU_9 | ST_VFU_12, vfu_status); /* set the VFU status */ + + if (format_byte == FORMAT_VFU_CHAN_1) /* if a TOF request was performed */ + fflush (uptr->fileref); /* then flush the file buffer for inspection */ + + 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 */ + + if (slew_count > 0) + dprintf (lp_dev, DEB_CMD, "Printer advanced %u line%s to line %u\n", + slew_count, (slew_count == 1 ? "" : "s"), current_line); + } + + if (ferror (uptr->fileref)) { /* if a host file system error occurred */ + cprintf ("%s simulator printer I/O error: %s\n", /* then report the error to the console */ + sim_name, strerror (errno)); + + clearerr (uptr->fileref); /* clear the error */ + + lp_set_alarm (uptr); /* set an alarm condition */ + return SCPE_IOERR; /* and stop the simulator */ + } + } + +return SCPE_OK; /* return event service success */ +} + + +/* Attach the printer image file. + + The specified file is attached to the indicated unit. This is the simulation + equivalent of loading paper into the printer and pressing the ONLINE button. + The transition from offline to online causes an interrupt. + + 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 + 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: + + 1. If we are called during a RESTORE command to reattach a file previously + attached when the simulation was SAVEd, the device status and file + position are not altered. + + 2. The pointer to the appropriate event delay times is set in case we are + being called during a RESTORE command (the assignment is redundant + otherwise). +*/ + +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 */ + + else /* otherwise a filename was specified */ + return SCPE_NOFNC; /* but we can't attach until the previous file detaches */ + +else { /* otherwise no deferral is active */ + result = attach_unit (uptr, cptr); /* so attach the specified printer image file */ + + 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 */ + + current_line = 1; /* reset the line counter to the top of the form */ + + if (sim_switches & SWMASK ('N')) /* if a new (empty) file was requested */ + uptr->pos = 0; /* then position at the start of the file */ + + 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 */ + } + } + +paper_fault = FALSE; /* clear any existing paper fault */ + +if (lp_dev.flags & DEV_REALTIME) /* if the printer is in real-time mode */ + dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* then point at the times for the current model */ +else /* otherwise */ + dlyptr = &fast_times; /* point at the fast times */ + +return result; /* return the result of the attach */ +} + + +/* Detach the printer image file. + + The specified file is detached from the indicated unit. This is the + simulation equivalent to unloading the paper from the printer or the printer + running out of paper. The out-of-paper condition cause a paper fault alarm, + and the printer goes offline. The transition from online to offline causes + 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. + + + Implementation notes: + + 1. During simulator shutdown, this routine is called for all three units, + not just the printer unit. The printer must be detached, even if a + detach has been deferred, to ensure that the file is closed properly. We + do this in response to a detach request with the SIM_SW_SHUT switch + present. + + 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. +*/ + +static t_stat lp_detach (UNIT *uptr) +{ +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 */ + 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 */ + 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 */ + } + +else /* otherwise */ + return SCPE_UNATT; /* we've been called for the wrong unit */ +} + + +/* Set the device modes. + + This validation routine is entered with the "value" parameter set to one of + the DEVICE_MODES values. The device flag implied by the value is set or + cleared. The unit, character, and descriptor pointers are not used. + + + Implementation notes: + + 1. Switching between printer and diagnostic mode sets the configuration + jumpers accordingly. + + 2. Switching between printer and diagnostic mode clears the event delay. + This is necessary in case the command was entered while an event was + queued. +*/ + +static t_stat lp_set_mode (UNIT *uptr, int32 value, CONST char *cptr, void *desc) +{ +switch ((DEVICE_MODES) value) { /* dispatch the mode to set */ + + case Fast_Time: /* entering optimized timing mode */ + lp_dev.flags &= ~DEV_REALTIME; /* so clear the real-time flag */ + dlyptr = &fast_times; /* and point at the fast times */ + break; + + + case Real_Time: /* entering realistic timing mode */ + lp_dev.flags |= DEV_REALTIME; /* so set the real-time flag */ + dlyptr = &real_times [GET_MODEL (uptr->flags)]; /* and point at the times for the current model */ + break; + + + case Printer: /* entering printer mode */ + lp_dev.flags &= ~DEV_DIAG; /* so clear the diagnostic flag */ + xfer_unit.wait = 0; /* and clear any event delay that had been set */ + + jumper_set = PRINTER_JUMPERS; /* set the jumpers for printer operation */ + break; + + + case Diagnostic: /* entering diagnostic mode */ + lp_dev.flags |= DEV_DIAG; /* so set the diagnostic flag */ + xfer_unit.wait = 0; /* and clear any event delay that had been set */ + + jumper_set = dha_control_word & DHA_JUMPER_MASK; /* set the jumpers for DHA operation */ + break; + } + +return SCPE_OK; /* the mode change succeeds */ +} + + +/* Set the printer model. + + 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. +*/ + +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 */ + +return SCPE_OK; /* allow the reassignment to proceed */ +} + + +/* Set the printer online or offline. + + This validation routine is called to set the printer online or offline. The + "value" parameter is UNIT_OFFLINE if the printer is going offline and is zero + if the printer is going online. This simulates pressing the ON/OFFLINE + button on the printer. + + If the printer is being taken offline, the buffer is checked to see if any + characters are present. If they are, or if the printer unit is currently + scheduled (i.e., executing a print operation), the offline request is + 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. + + 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 + is set online, and any tape fault present is cleared. If the sequencer + indicates an incomplete handshake, as would occur if paper ran out while + printing, the transfer service is called to complete the handshake by + asserting DEMAND. Otherwise, DEMAND is asserted explicitly, and DEV END is + denied. + + Transitions between the offline and online state cause interrupts, and INTREQ + is asserted to the IOP if a transition occurred (but not, e.g., for a SET LP + OFFLINE command where the printer is already offline). + + + Implementation notes: + + 1. Because a deferred offline request is not fatal, we return SCPE_OK to + allow command files to continue to execute, but we print a warning to the + user. +*/ + +static t_stat lp_set_on_offline (UNIT *uptr, int32 value, CONST char *cptr, void *desc) +{ +if ((uptr->flags & UNIT_ATT) == 0) /* if the printer is detached */ + 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 */ + +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 */ + dprintf (lp_dev, DEB_CMD, "Offline request deferred until print completes\n"); + } + +return SCPE_OK; /* return operation success */ +} + + +/* Set the VFU tape. + + This validation routine is entered to set up the VFU on the printer. It is + invoked by one of two commands: + + SET LP VFU + SET LP VFU= + + The first form loads the standard 66-line tape into the VFU. The second form + loads the VFU with the tape image specified by the filename. The format of + the tape image is described in the comments for the "lp_load_vfu" routine. + + On entry, "uptr" points at the printer unit, "cptr" points to the first + character after the "VFU" keyword, and the "value" and "desc" parameters are + unused. If "cptr" is NULL, then the first command form was given, and the + "lp_load_vfu" routine is called with a NULL file stream pointer to indicate + that the standard VFU tape should be used. Otherwise, the second command + form was given, and "cptr" points to the supplied filename. The file is + opened, and the "lp_load_vfu" routine is called with the stream pointer to + load the VFU tape image contained therein. +*/ + +static t_stat lp_set_vfu (UNIT *uptr, int32 value, CONST char *cptr, void *desc) +{ +FILE *vfu_stream; +t_stat result; + +if (cptr == NULL) /* if a VFU reset is requested */ + result = lp_load_vfu (uptr, NULL); /* then reload the standard VFU tape */ + +else if (*cptr == '\0') /* otherwise if the filename was omitted */ + return SCPE_MISVAL; /* then report the missing argument */ + +else { /* otherwise the filename was specified */ + vfu_stream = fopen (cptr, "r"); /* so attempt to open it */ + + if (vfu_stream == NULL) /* if the open failed */ + return SCPE_OPENERR; /* then report the error */ + + result = lp_load_vfu (uptr, vfu_stream); /* load the VFU tape from the file */ + + fclose (vfu_stream); /* close the file */ + } + +return result; /* return the result of the load */ +} + + +/* Show the device modes. + + This display routine is called to show the device modes for the printer. The + output stream is passed in the "st" parameter, and the other parameters are + ignored. The timing mode and connection mode are printed. +*/ + +static t_stat lp_show_mode (FILE *st, UNIT *uptr, int32 value, CONST void *desc) +{ +fprintf (st, "%s timing, %s mode", /* print the timing and connection modes */ + (lp_dev.flags & DEV_REALTIME ? "realistic" : "fast"), + (lp_dev.flags & DEV_DIAG ? "diagnostic" : "printer")); + +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. + + The output stream is passed in the "st" parameter, and the other parameters + are ignored. +*/ + +static t_stat lp_show_vfu (FILE *st, UNIT *uptr, int32 value, CONST void *desc) +{ +fputs (vfu_title, st); /* print the VFU title */ + +return SCPE_OK; +} + + + +/* Printer local utility routines */ + + + +/* Printer reset. + + This routine is called when the MASTER CLEAR signal is asserted to the + printer. The "programmed_clear" parameter is TRUE if the routine is called + for a Programmed Master Clear or IORESET assertion, and FALSE if the routine + is called for a RESET or RESET LP command. In the latter case, the presence + of the "-P" switch indicates that this is a power-on reset. In either case, + the interface reset has already been performed; this routine is responsible + for resetting the printer only. + + In hardware, asserting MASTER CLEAR: + + - clears the input buffer without printing + - finishes printing the current line and performs any stored VFU action + - inhibits DEMAND for approximately three milliseconds + + In simulation, the buffer index is reset, a tape fault is cleared, a paper + fault is determined by the paper status, and any deferred offline command is + cleared. Printing is always "complete" at the point of entry, as the actual + file write is instantaneous from the simulation perspective. DEMAND is not + altered, as the printer is "ready" as soon as the command completes. DEV END + is reset to the offline status (asserted if the printer is offline, denied if + 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. +*/ + +static t_stat lp_reset (t_bool programmed_clear) +{ +OUTBOUND_SET signals; +uint32 new_status = 0; +t_stat result = SCPE_OK; + +if (! programmed_clear && (sim_switches & SWMASK ('P'))) { /* if this is a commanded power-on reset */ + fast_times.buffer_load = LP_BUFFER_LOAD; /* then reset the per-character transfer time, */ + 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 */ + } + +buffer_index = 0; /* clear the buffer without printing */ + +offline_pending = FALSE; /* cancel any pending offline request */ + +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 */ + new_status |= ST_NOT_READY; /* then set not-ready status */ + +if (xfer_unit.flags & UNIT_OFFLINE) { /* if the printer is offline */ + device_flag_in = TRUE; /* then DEMAND denies while the printer is not ready */ + device_end_in = TRUE; /* and DEV END asserts while the printer is offline */ + } + +else { /* otherwise the printer is online */ + new_status |= ST_ONLINE; /* so set online status */ + + device_flag_in = FALSE; /* DEMAND asserts when the printer is ready */ + device_end_in = FALSE; /* and DEV END denies when the printer is online */ + } + +xfer_service (NULL); /* tell the data transfer service that signals have changed */ + +signals = set_device_status (ST_ONLINE | ST_NOT_READY, /* set the new device status */ + new_status); + +if (signals & INTREQ) /* if the status change caused an interrupt */ + iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */ + +return result; /* return the result of the reset */ +} + + +/* Process the printer control word. + + This routine is called when a DCONTSTB or PCONTSTB assertion indicates that + the control word is to be set. No direct action is taken by the printer in + response, so the routine simply returns. +*/ + +static OUTBOUND_SET lp_control (uint32 control_word) +{ +return NO_SIGNALS; /* no special control action is needed */ +} + + +/* Set an alarm condition. + + This routine is called when an alarm condition exists. An alarm occurs when + paper is out (paper fault) or a VFU command addresses a channel that does not + contain a punch (tape fault). In response, the printer goes not ready and + offline. + + On entry, the routine attempts to set the printer offline. If this succeeds, + the printer is set not-ready. If it fails (for reasons explained in the + comments for the "lp_set_on_offline" routine), it will be set offline and + not-ready when printing completes. +*/ + +static t_bool lp_set_alarm (UNIT *uptr) +{ +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 */ + } + +else /* otherwise the offline request is pending */ + return FALSE; /* so return deferral status */ +} + + +/* Set the printer locality. + + This routine is called to set the printer online or offline and returns TRUE + if the request succeeded or FALSE if it was deferred. An online request + always succeeds, so it is up to the caller to ensure that going online is + permissible (e.g., that paper is loaded into the printer). An offline + request succeeds only if the printer is idle. If characters are present in + the print buffer, or if the printer is printing or slewing, then the request + is deferred until the current line is complete. + + The printer cable inversely connects DEMAND to the Device Flag input and + ONLINE to the Device End input. As both deny when the printer goes offline + and assert when the printer goes online, Device Flag and Device End assert + and deny, respectively. + + If the printer goes offline with an operation in progress, Device Flag will + remain asserted, and the handshake sequencer will remain in the Device_Flag_1 + or Device_Flag_2 state until the printer is set online again. The transfer + service routine is informed of these state changes, so that the handshake can + complete when the printer is again set online. + + + Implementation notes: + + 1. When called with a NULL parameter, the transfer service routine will + update its internal device flag state but will take no other action. + When called with a unit pointer, the routine continues the handshake + sequence. +*/ + +static t_bool lp_set_locality (UNIT *uptr, LOCALITY printer_state) +{ +OUTBOUND_SET signals; + +if (printer_state == Offline) { /* if the printer is going offline */ + if (buffer_index == 0 /* then if the buffer is empty */ + && 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 */ + + device_flag_in = TRUE; /* DEMAND denies while the printer is offline */ + device_end_in = TRUE; /* DEV END asserts while the printer is offline */ + + xfer_service (NULL); /* inform the service routine of the signal changes */ + } + + else { /* otherwise the request must wait */ + offline_pending = TRUE; /* until the line is printed */ + return FALSE; /* that the command is not complete */ + } + } + +else { /* otherwise the printer is going online */ + uptr->flags &= ~UNIT_OFFLINE; /* so clear the unit flag */ + + paper_fault = FALSE; /* clear any paper fault */ + tape_fault = FALSE; /* and any tape fault */ + + signals = set_device_status (ST_ONLINE | ST_NOT_READY, /* set online status */ + ST_ONLINE); /* and clear not ready status */ + + device_flag_in = FALSE; /* DEMAND asserts when the printer is online */ + device_end_in = FALSE; /* and DEV END denies when the printer is online */ + + if (sequencer != Idle) /* if the transfer handshake is in progress */ + xfer_service (uptr); /* then complete the suspended operation */ + else /* otherwise */ + xfer_service (NULL); /* inform the service routine of the signal changes */ + } + +dprintf (lp_dev, DEB_CMD, "Printer set %s\n", + (printer_state == Offline ? "offline" : "online")); + +if (signals & INTREQ) /* if the transition caused an interrupt */ + iop_assert_INTREQ (&lp_dib); /* then assert the INTREQ signal */ + +offline_pending = FALSE; + +return TRUE; +} + + +/* Load the VFU. + + The printer VFU is loaded either with a custom tape image stored in the file + associated with the stream "vf" or with the standard 66-line tape if the + stream is NULL. The "uptr" parameter points to the printer unit. + + The standard VFU tape (1535-2655 for the 8-channel HP 2607 and 2613-80001 for + the 12-channel HP 2613, 2617, and 2618) defines the channels as: + + Chan Description + ---- -------------- + 1 Top of form + 2 Bottom of form + 3 Single space + 4 Double space + 5 Triple space + 6 Half page + 7 Quarter page + 8 Sixth page + 9 Bottom of form + + ...with channels 10-12 uncommitted. A custom tape must dedicate channel 1 to + the top-of-form, but the other channels may be defined as desired. + + A custom tape file starts with a VFU definition line and then contains one + channel-definition line for each line of the form. The number of lines + establishes the form length. + + A semicolon appearing anywhere on a line begins a comment, and the semicolon + and all following characters are ignored. Zero-length lines, including lines + beginning with a semicolon, are ignored. + + Note that a line containing one or more blanks is not a zero-length line, so, + for example, the line " ; a comment starting in column 2" is not ignored. + + The first (non-ignored) line in the file is a VFU definition line of this + exact form: + + VFU=,{,} + + ...where: + + Parameter Description + ------------------ ------------------------------------------------------- + punch characters a string of one or more characters used interchangeably + to represent a punched location + + 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) + + 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. + + The remaining (non-ignored) lines define the channels punched for each line + of the printed form. The line format consists of a sequence of punch, + no-punch, and "other" characters in channel order. Each punch or no-punch + character defines a channel state, starting with channel 1 and proceeding + left-to-right until all channels for the VFU are defined; if the line + terminates before all channels are defined, the remaining channels are set to + the no-punch state. Any "other" characters (i.e., neither a punch character + nor a no-punch character) are ignored and may be used freely to delineate the + tape channels. + + Examples using the standard 66-line tape definition for an 8-channel VFU: + + + ; the VFU definition | VFU=1234578, ; no-punch is a ' ' + VFU=1,0,a binary tape image | + | 1 ; top of form + ; the channel definitions | 345 ; form line 1 + | 3 ; form line 2 + 10111111 ; top of form | 34 ; form line 3 + 00100000 ; single space | 3 5 ; form line 4 + 0011 ; channels 5-8 no-punch | 34 ; form line 5 + | + -------------------------------------+------------------------------------- + | + VFU=X,-,blanks are "others" | VFU=TO,.,brackets are "others" + | ; 1 2 3 4 5 6 7 8 + X - X X X X X X ; line 1 | ;--- --- --- --- --- --- --- --- + - - X - - - - - ; line 2 | [T] . [O] [O] [O] [O] [O] [O] + - - X X - - - - ; line 3 | . . [O] . . . . . + | . . [O] [O] . . . . + + + On entry, the "vf" parameter determines whether the standard tape or a custom + tape is to be loaded. If "vf" is NULL, a standard 66-line tape is generated + and stored in the tape buffer. Otherwise, a custom tape file is read, + parsed, and assembled VFU entries are stored in the tape buffer. After + generation or a successful tape load, the buffer is copied to the VFU array, + the form length is set, the current line is reset to the top-of-form, and the + state of VFU channels 9 and 12 are set into the device status. + + + Implementation notes: + + 1. VFU array entries 1-n correspond to form print lines 1-n. Entry 0 is the + 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) +{ +const PRINTER_TYPE model = GET_MODEL (uptr->flags); /* get the printer type */ +uint32 line, channel, vfu_status; +int32 len; +char buffer [LINE_SIZE], punch [LINE_SIZE], no_punch; +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 */ + + 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 */ + + for (line = 1; line <= 60; line++) { /* load each of the 60 printable lines */ + tape [line] |= VFU_CHANNEL_3 /* punch channel 3 for single space */ + | (line % 2 == 1 ? VFU_CHANNEL_4 : 0) /* punch channel 4 for double space */ + | (line % 3 == 1 ? VFU_CHANNEL_5 : 0) /* punch channel 5 for triple space */ + | (line % 30 == 1 ? VFU_CHANNEL_6 : 0) /* punch channel 6 for next half page */ + | (line % 15 == 1 ? VFU_CHANNEL_7 : 0) /* punch channel 7 for next quarter page */ + | (line % 10 == 1 ? VFU_CHANNEL_8 : 0); /* punch channel 8 for next sixth page */ + + tape [0] |= tape [line]; /* accumulate the channel punches */ + } + + form_length = 66; /* set the form length */ + } + +else { /* otherwise load a custom VFU from the file */ + len = lp_read_line (vf, buffer, sizeof buffer); /* read the first line */ + + if (len <= 0 /* if there isn't one */ + || strncmp (buffer, "VFU=", strlen ("VFU=")) != 0) { /* or it's not a VFU definition statement */ + cputs ("Missing VFU definition line\n"); /* then complain to the console */ + return SCPE_FMT; /* and fail with a format error */ + } + + bptr = buffer + strlen ("VFU="); /* point at the first control argument */ + + tptr = strtok (bptr, ","); /* parse the punch token */ + + if (tptr == NULL) { /* if it's missing */ + cputs ("Missing punch field in the VFU control line\n"); /* then complain to the console */ + return SCPE_FMT; /* and fail with a format error */ + } + + strcpy (punch, tptr); /* save the set of punch characters */ + + tptr = strtok (NULL, ","); /* parse the no-punch token */ + + if (tptr == NULL){ /* if it's missing */ + cputs ("Missing no-punch field in the VFU control line\n"); /* then complain to the console */ + return SCPE_FMT; /* and fail with a format error */ + } + + no_punch = *tptr; /* save the no-punch character */ + + tptr = strtok (NULL, ","); /* parse the optional title */ + + 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 */ + + + for (line = 1; line <= VFU_MAX; line++) { /* load up to the maximum VFU tape length */ + len = lp_read_line (vf, buffer, sizeof buffer); /* read a tape definition line */ + + if (len <= 0) /* if at the EOF or an error occurred */ + break; /* then the load is complete */ + + tptr = buffer; /* point at the first character of the line */ + + channel = VFU_CHANNEL_1; /* set the channel 1 indicator */ + + while (channel != 0 && *tptr != '\0') { /* loop until the channel or definition is exhausted */ + if (strchr (punch, *tptr) != NULL) { /* if the character is in the punch set */ + tape [line] |= channel; /* then punch the current channel */ + channel = channel >> 1; /* and move to the next one */ + } + + else if (*tptr == no_punch) /* otherwise if the character is the no-punch character */ + channel = channel >> 1; /* then move to the next channel */ + + tptr++; /* otherwise the character is neither, so ignore it */ + } + + tape [0] |= tape [line]; /* accumulate the channel punches */ + } + + + if ((tape [1] & VFU_CHANNEL_1) == 0) { /* if there is no channel 1 punch in the first line */ + cputs ("Missing punch in channel 1 of line 1\n"); /* then complain to the console */ + return SCPE_FMT; /* and fail with a format error */ + } + + form_length = line - 1; /* set the form length */ + } + +memcpy (VFU, tape, sizeof VFU); /* copy the tape buffer to the VFU array */ + +current_line = 1; /* reset the line counter to the top of the form */ + +vfu_status = 0; /* assume no punches for channels 9 and 12 */ + +if (print_props [model].vfu_channels > 8) { /* if the printer VFU has more than 8 channels */ + if (VFU [1] & VFU_CHANNEL_9) /* then if channel 9 is punched for this line */ + vfu_status |= ST_VFU_9; /* then report it in the device status */ + + if (VFU [1] & VFU_CHANNEL_12) /* if channel 12 is punched for this line */ + vfu_status |= ST_VFU_12; /* then report it in the device status */ + } + +set_device_status (ST_VFU_9 | ST_VFU_12, vfu_status); /* set the VFU status */ + +vfu_reg->depth = form_length + 1; /* set the VFU display depth */ + +return SCPE_OK; /* the VFU was successfully loaded */ +} + + +/* Read a line from the VFU file. + + This routine reads a line from the VFU tape image file designated by the file + stream parameter "vf", stores the data in the string buffer pointed to by + "line" and whose size is given by "size", and returns the length of that + string. Comments are stripped from lines that are read, and the routine + continues to read until a non-zero-length line is found. If the end of the + file was reached, the return value is 0. If a file error occurred, the + return value is -1. + + + Implementation notes: + + 1. The routine assumes that the file was opened in text mode, so that + automatic CRLF-to-LF conversion is done if needed. This simplifies + the end-of-line removal. +*/ + +static int32 lp_read_line (FILE *vf, char *line, uint32 size) +{ +char *result; +int32 len = 0; + +while (len == 0) { + result = fgets (line, size, vf); /* get the next line from the file */ + + if (result == NULL) /* if an error occurred */ + if (feof (vf)) /* then if the end of file was seen */ + return 0; /* then return an EOF indication */ + + else { /* otherwise report the error to the console */ + cprintf ("%s simulator line printer I/O error: %s\n", + sim_name, strerror (errno)); + + clearerr (vf); /* clear the error */ + return -1; /* and return an error indication */ + } + + len = strlen (line); /* get the current line length */ + + if (len > 0 && line [len - 1] == '\n') /* if the last character is a newline */ + line [--len] = '\0'; /* then remove it and decrease the length */ + + result = strchr (line, ';'); /* search for a comment indicator */ + + if (result != NULL) { /* if one was found */ + *result = '\0'; /* then truncate the line at that point */ + len = (int32) (result - line); /* and recalculate the line length */ + } + } + +return len; +} diff --git a/HP3000/hp3000_mpx.c b/HP3000/hp3000_mpx.c index 047d8dfc..188f7948 100644 --- a/HP3000/hp3000_mpx.c +++ b/HP3000/hp3000_mpx.c @@ -25,6 +25,10 @@ MPX HP 3000 Series III Multiplexer Channel + 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 + 21-Mar-16 JDB Changed uint16 types to HP_WORD 06-Oct-15 JDB First release version 11-Sep-14 JDB Passes the multiplexer channel diagnostic (D422A) 10-Feb-13 JDB Created @@ -396,11 +400,11 @@ static const uint8 state_parity [16] = { /* State RAM parity */ /* Debug flags */ -#define DEB_CSRW (1 << 0) /* trace diagnostic and channel command initiations and completions */ -#define DEB_PIO (1 << 1) /* trace programmed I/O commands */ -#define DEB_IOB (1 << 2) /* trace I/O bus signals and data words */ -#define DEB_STATE (1 << 3) /* trace state changes */ -#define DEB_SR (1 << 4) /* trace service requests */ +#define DEB_CSRW (1u << 0) /* trace diagnostic and channel command initiations and completions */ +#define DEB_PIO (1u << 1) /* trace programmed I/O commands */ +#define DEB_IOB (1u << 2) /* trace I/O bus signals and data words */ +#define DEB_STATE (1u << 3) /* trace state changes */ +#define DEB_SR (1u << 4) /* trace service requests */ /* Control word. @@ -411,13 +415,13 @@ static const uint8 state_parity [16] = { /* State RAM parity */ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CN_MR 0100000 /* (M) master reset */ -#define CN_RAM_ADDR_MASK 0036000 /* RAM address mask */ -#define CN_ADDR_RAM 0001000 /* (A) select the address RAM and register */ -#define CN_ORDER_RAM 0000400 /* (O) select the order RAM and register */ -#define CN_STATE_RAM 0000200 /* (S) select the state RAM and register */ -#define CN_LOAD_REGS 0000100 /* (L) load registers from RAM */ -#define CN_INCR_REGS 0000040 /* (I) increment registers */ +#define CN_MR 0100000u /* (M) master reset */ +#define CN_RAM_ADDR_MASK 0036000u /* RAM address mask */ +#define CN_ADDR_RAM 0001000u /* (A) select the address RAM and register */ +#define CN_ORDER_RAM 0000400u /* (O) select the order RAM and register */ +#define CN_STATE_RAM 0000200u /* (S) select the state RAM and register */ +#define CN_LOAD_REGS 0000100u /* (L) load registers from RAM */ +#define CN_INCR_REGS 0000040u /* (I) increment registers */ #define CN_RAM_ADDR_SHIFT 10 /* RAM address alignment shift */ @@ -449,9 +453,9 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define ST_DIO_OK 0040000 /* (D) direct I/O OK (always set) */ -#define ST_STATE_PARITY 0010000 /* (E) a state error exists */ -#define ST_RAM_ADDR_MASK 0007400 /* RAM address mask */ +#define ST_DIO_OK 0040000u /* (D) direct I/O OK (always set) */ +#define ST_STATE_PARITY 0010000u /* (E) a state error exists */ +#define ST_RAM_ADDR_MASK 0007400u /* RAM address mask */ #define ST_RAM_ADDR_SHIFT 8 /* RAM address alignment shift */ @@ -481,10 +485,10 @@ static const BITSET_FORMAT status_format = /* names, offset, direction, alt +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define WR_ORDER_MASK 0170000 /* order mask */ -#define WR_COUNT_MASK 0007777 /* word count mask */ -#define WR_STATE_MASK 0036000 /* state mask */ -#define WR_BANK_MASK 0000017 /* bank number mask */ +#define WR_ORDER_MASK 0170000u /* order mask */ +#define WR_COUNT_MASK 0007777u /* word count mask */ +#define WR_STATE_MASK 0036000u /* state mask */ +#define WR_BANK_MASK 0000017u /* bank number mask */ #define WR_ORDER_SHIFT 12 /* order alignment shift */ #define WR_COUNT_SHIFT 0 /* word count alignment shift */ @@ -509,15 +513,15 @@ static const BITSET_FORMAT status_format = /* names, offset, direction, alt +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define RD_ADDR_MASK 0177777 /* address mask */ -#define RD_ORDER_MASK 0170000 /* order mask */ -#define RD_COUNT_MASK 0007777 /* word count mask */ -#define RD_BANK_MASK 0007400 /* bank number mask */ -#define RD_XFER_COMPLETE 0000200 /* (T) transfer complete */ -#define RD_STATE_MASK 0000170 /* (A/B/C/D) state mask */ -#define RD_XFER_END 0000004 /* (E) end of transfer */ -#define RD_ADDR_PARITY 0000002 /* (P) address parity */ -#define RD_STATE_PARITY 0000001 /* (S) state parity */ +#define RD_ADDR_MASK 0177777u /* address mask */ +#define RD_ORDER_MASK 0170000u /* order mask */ +#define RD_COUNT_MASK 0007777u /* word count mask */ +#define RD_BANK_MASK 0007400u /* bank number mask */ +#define RD_XFER_COMPLETE 0000200u /* (T) transfer complete */ +#define RD_STATE_MASK 0000170u /* (A/B/C/D) state mask */ +#define RD_XFER_END 0000004u /* (E) end of transfer */ +#define RD_ADDR_PARITY 0000002u /* (P) address parity */ +#define RD_STATE_PARITY 0000001u /* (S) state parity */ #define RD_ORDER_SHIFT 12 /* order alignment shift */ #define RD_COUNT_SHIFT 0 /* word count alignment shift */ @@ -588,17 +592,17 @@ static const BITSET_FORMAT read_format = /* names, offset, direction, alt +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define AUX_IB 040 /* auxiliary RAM in-block flag */ -#define AUX_TC 020 /* auxiliary RAM terminal count flag */ -#define AUX_BANK_MASK 017 /* auxiliary RAM bank mask */ +#define AUX_IB 040u /* auxiliary RAM in-block flag */ +#define AUX_TC 020u /* auxiliary RAM terminal count flag */ +#define AUX_BANK_MASK 017u /* auxiliary RAM bank mask */ #define AUX_BANK(r) ((r) & AUX_BANK_MASK) -#define ORDER_DC 020 /* order RAM data chain flag */ -#define ORDER_MASK 017 /* order RAM current order mask */ +#define ORDER_DC 020u /* order RAM data chain flag */ +#define ORDER_MASK 017u /* order RAM current order mask */ -#define CNTR_MASK 0007777 /* counter RAM word count mask */ -#define CNTR_MAX 0007777 /* counter RAM word count maximum value */ +#define CNTR_MASK 0007777u /* counter RAM word count mask */ +#define CNTR_MAX 0007777u /* counter RAM word count maximum value */ static const BITSET_NAME aux_names [] = { /* Auxiliary RAM word */ "in block", /* bit 2 */ @@ -667,7 +671,7 @@ static t_stat mpx_reset (DEVICE *dptr); static uint8 next_state (uint8 current_state, SIO_ORDER order, t_bool abort); static void end_channel (DIB *dibptr); -static SIGNALS_DATA abort_channel (DIB *dibptr, char *reason); +static SIGNALS_DATA abort_channel (DIB *dibptr, const char *reason); /* Channel SCP data structures */ @@ -683,12 +687,14 @@ static DIB mpx_dib = { INTMASK_UNUSED /* interrupt mask */ }; + /* Unit list */ static UNIT mpx_unit [] = { /* a dummy unit to satisfy SCP requirements */ { UDATA (NULL, 0, 0) } }; + /* Register list. @@ -703,34 +709,35 @@ static UNIT mpx_unit [] = { /* a dummy unit to satisfy SCP r */ static REG mpx_reg [] = { -/* Macro Name Location Radix Width Depth Flags */ -/* ------ ------ ------------- ----- ----- ----------- ----------------- */ - { FLDATA (IDLE, mpx_is_idle, 0) }, - { DRDATA (COUNT, active_count, 32), PV_LEFT }, - { DRDATA (EXCESS, excess_cycles, 32), PV_LEFT }, +/* Macro Name Location Radix Width Depth Flags */ +/* ------ ------ ------------- ----- ----- ----------- ----------------- */ + { FLDATA (IDLE, mpx_is_idle, 0) }, + { DRDATA (COUNT, active_count, 32), PV_LEFT }, + { DRDATA (EXCESS, excess_cycles, 32), PV_LEFT }, - { ORDATA (CNTL, control_word, 16), REG_FIT }, - { ORDATA (STAT, status_word, 16), REG_FIT }, - { FLDATA (ROLOVR, rollover, 0) }, - { FLDATA (DEVEND, device_end, 0) }, + { ORDATA (CNTL, control_word, 16), REG_FIT }, + { ORDATA (STAT, status_word, 16), REG_FIT }, + { FLDATA (ROLOVR, rollover, 0) }, + { FLDATA (DEVEND, device_end, 0) }, - { BRDATA (STATR, state_ram, 2, 4, INTRF_COUNT) }, - { BRDATA (AUX, aux_ram, 8, 6, INTRF_COUNT) }, - { BRDATA (ORDER, order_ram, 8, 4, INTRF_COUNT) }, - { BRDATA (CNTR, cntr_ram, 8, 12, INTRF_COUNT) }, - { BRDATA (ADDR, addr_ram, 8, 16, INTRF_COUNT) }, + { BRDATA (STATR, state_ram, 2, 4, INTRF_COUNT) }, + { BRDATA (AUX, aux_ram, 8, 6, INTRF_COUNT) }, + { BRDATA (ORDER, order_ram, 8, 4, INTRF_COUNT) }, + { BRDATA (CNTR, cntr_ram, 8, 12, INTRF_COUNT) }, + { BRDATA (ADDR, addr_ram, 8, 16, INTRF_COUNT) }, - { ORDATA (STAREG, state_reg, 8), REG_FIT | REG_HRO }, - { ORDATA (AUXREG, aux_reg, 8), REG_FIT | REG_HRO }, - { ORDATA (ORDREG, order_reg, 8), REG_FIT | REG_HRO }, - { ORDATA (CTRREG, cntr_reg, 16), REG_FIT | REG_HRO }, - { ORDATA (ADRREG, addr_reg, 16), REG_FIT | REG_HRO }, + { ORDATA (STAREG, state_reg, 8), REG_FIT | REG_HRO }, + { ORDATA (AUXREG, aux_reg, 8), REG_FIT | REG_HRO }, + { ORDATA (ORDREG, order_reg, 8), REG_FIT | REG_HRO }, + { ORDATA (CTRREG, cntr_reg, 16), REG_FIT | REG_HRO }, + { ORDATA (ADRREG, addr_reg, 16), REG_FIT | REG_HRO }, - { SRDATA (DIB, mpx_dib), REG_HRO }, + { SRDATA (DIB, mpx_dib, REG_HRO) }, { NULL } }; + /* Modifier list */ static MTAB mpx_mod [] = { @@ -740,6 +747,7 @@ static MTAB mpx_mod [] = { { 0 } }; + /* Debugging trace list */ static DEBTAB mpx_deb [] = { @@ -751,6 +759,7 @@ static DEBTAB mpx_deb [] = { { NULL, 0 } }; + /* Device descriptor */ DEVICE mpx_dev = { @@ -856,7 +865,7 @@ void mpx_assert_REQ (DIB *dibptr) { const uint32 srn = dibptr->service_request_number; /* get the SR number for the RAM index */ -dprintf (mpx_dev, DEB_CSRW, "Device number %d asserted REQ for channel initialization\n", +dprintf (mpx_dev, DEB_CSRW, "Device number %u asserted REQ for channel initialization\n", dibptr->device_number); state_ram [srn] = State_C; /* set up the initial sequencer state */ @@ -893,7 +902,7 @@ return; void mpx_assert_SRn (DIB *dibptr) { if (dibptr->service_request == FALSE) - dprintf (mpx_dev, DEB_SR, "Device number %d asserted SR%d\n", + dprintf (mpx_dev, DEB_SR, "Device number %u asserted SR%u\n", dibptr->device_number, dibptr->service_request_number); dibptr->service_request = TRUE; /* set the service request flag */ @@ -952,7 +961,10 @@ return; All I/O orders except Set Bank, Read, and Write execute states C, A, and B, in that order. The Set Bank order executes state C, A, and D. The Read and Write orders execute states C, A, B, and then one D state for each word - transferred. Some actions are dependent on external signals or conditions. + transferred. Some actions are dependent on external signals (JMPMET or + DEVEND) or internal conditions (terminal count reached [TC] or in a chained + block transfer [IB]). + The actions for the orders are: Jump (sioJUMP) @@ -965,7 +977,7 @@ return; C IOPP write DEVNODB - Jump Conditional (sioJUMPC) + Conditional Jump (sioJUMPC) State Condition Action Signals ----- --------------- ---------- ------------------------------------------ @@ -1012,7 +1024,7 @@ return; ----- --------------- ---------- ------------------------------------------ C IOPP read DEVNODB A IOCW read -- - B IOAW write TOGGLESIOOK | TOGGLESR | PSTATSTB + B IOAW write TOGGLESR | PSTATSTB | TOGGLESIOOK idle @@ -1022,7 +1034,7 @@ return; ----- --------------- ---------- ------------------------------------------ C IOPP read DEVNODB A IOCW read -- - B IOAW write TOGGLESIOOK | TOGGLESR | PSTATSTB | SETINT + B IOAW write TOGGLESR | SETINT | PSTATSTB | TOGGLESIOOK idle @@ -1030,10 +1042,10 @@ return; State Condition Action Signals ----- --------------- ---------- ------------------------------------------ - C IOPP read DEVNODB | ACKSR | TOGGLESR - A IOCW read PCMD1 | TOGGLESR + C IOPP read DEVNODB + A IOCW read TOGGLESR | PCMD1 B IOAW read ACKSR | PCONTSTB - C IOPP read DEVNODB | TOGGLESR + C IOPP read ACKSR | TOGGLESR | DEVNODB Sense (sioSENSE) @@ -1057,11 +1069,12 @@ return; / D ~ TC data write ACKSR | PWRITESTB \ D TC data write ACKSR | PWRITESTB | EOT | TOGGLEOUTXFER - / D DEVEND * ~ TC IOPP read EOT | TOGGLESR | TOGGLEOUTXFER - \ D DEVEND * TC IOPP read TOGGLESR + / D DEVEND * ~ TC IOPP read ACKSR | TOGGLESR | EOT | TOGGLEOUTXFER + \ D DEVEND * TC IOPP read ACKSR | TOGGLESR - / C ~ DEVEND IOPP read ACKSR | DEVNODB | TOGGLESR - \ A DEVEND IOCW read -- + / C ~ DEVEND IOPP read ACKSR | TOGGLESR | DEVNODB + / A ~ DEVEND IOCW read ACKSR + \ A DEVEND IOCW read ACKSR Write Chained (sioWRITEC) @@ -1074,8 +1087,8 @@ return; \ B IB IOAW read TOGGLESR / D ~ TC data write ACKSR | PWRITESTB - \ D TC data write ACKSR | PWRITESTB | EOT | TOGGLESR - / D DEVEND * ~ TC IOPP read EOT | TOGGLESR + \ D TC data write ACKSR | TOGGLESR | PWRITESTB | EOT + / D DEVEND * ~ TC IOPP read ACKSR | EOT | TOGGLESR \ D DEVEND * TC IOPP read -- / C ~ DEVEND IOPP read DEVNODB @@ -1087,17 +1100,18 @@ return; State Condition Action Signals ----- --------------- ---------- ------------------------------------------ C IOPP read DEVNODB - A IOCW read ACKSR - / B ~ IB IOAW read READNEXTWD | TOGGLESR | TOGGLEINXFER - \ B IB IOAW read READNEXTWD | TOGGLESR + A IOCW read -- + / B ~ IB IOAW read TOGGLESR | TOGGLEINXFER | READNEXTWD + \ B IB IOAW read TOGGLESR | READNEXTWD / D ~ TC data write ACKSR | PREADSTB | READNEXTWD \ D TC data write ACKSR | PREADSTB | EOT | TOGGLEINXFER - / D DEVEND * ~ TC IOPP read EOT | TOGGLESR | TOGGLEINXFER - \ D DEVEND * TC IOPP read TOGGLESR + / D DEVEND * ~ TC IOPP read ACKSR | TOGGLESR | EOT | TOGGLEINXFER + \ D DEVEND * TC IOPP read ACKSR | TOGGLESR - / C ~ DEVEND IOPP read ACKSR | DEVNODB | TOGGLESR - \ A DEVEND IOCW read -- + / C ~ DEVEND IOPP read ACKSR | TOGGLESR | DEVNODB + / A ~ DEVEND IOCW read ACKSR + \ A DEVEND IOCW read ACKSR Read Chained (sioREADC) @@ -1106,17 +1120,18 @@ return; ----- --------------- ---------- ------------------------------------------ C IOPP read DEVNODB A IOCW read -- - / B ~ IB IOAW read READNEXTWD | TOGGLESR | TOGGLEINXFER - \ B IB IOAW read READNEXTWD | TOGGLESR + / B ~ IB IOAW read TOGGLESR | TOGGLEINXFER | READNEXTWD + \ B IB IOAW read TOGGLESR | READNEXTWD / D ~ TC data write ACKSR | PREADSTB | READNEXTWD - \ D TC data write ACKSR | PREADSTB | EOT | TOGGLESR - / D DEVEND * ~ TC IOPP read EOT | TOGGLESR + \ D TC data write ACKSR | TOGGLESR | PREADSTB | EOT + / D DEVEND * ~ TC IOPP read ACKSR | TOGGLESR | EOT \ D DEVEND * TC IOPP read -- / C ~ DEVEND IOPP read DEVNODB \ A DEVEND IOCW read -- + Summarizing the State D signals sent to the interface: Normal transfer @@ -1127,9 +1142,9 @@ return; DEVEND asserted after a normal transfer --------------------------------------- - - not the last word and not chained: EOT | TOGGLESR | TOGGLEioXFER - - not the last word and chained: EOT | TOGGLESR - - the last word and not chained: TOGGLESR + - not the last word and not chained: ACKSR | TOGGLESR | EOT | TOGGLEioXFER + - not the last word and chained: ACKSR | TOGGLESR | EOT + - the last word and not chained: ACKSR | TOGGLESR - the last word and chained: (none) In all cases where signals are generated, CHANSO is also included. @@ -1198,15 +1213,21 @@ while (cycles > 0) { /* execute as long as cy cntr_reg = cntr_ram [srn]; addr_reg = addr_ram [srn]; - sio_order = order_reg & ORDER_MASK; /* map the order */ + sio_order = (SIO_ORDER) (order_reg & ORDER_MASK); /* map the order */ } - dprintf (mpx_dev, DEB_STATE, "Channel SR %d entered %s with %d clock cycles remaining\n", + dprintf (mpx_dev, DEB_STATE, "Channel SR %u entered %s with %d clock cycles remaining\n", srn, state_name [state_reg], cycles); switch (state_reg) { /* dispatch based on the multiplexer state */ case State_A: + if (sio_order == sioREAD /* if the previous order */ + || sio_order == sioWRITE) /* was an unchained Read or Write */ + inbound_signals = ACKSR | CHANSO; /* then acknowledge the final service request */ + else /* otherwise */ + inbound_signals = NO_SIGNALS; /* no acknowledgement is needed */ + cpu_read_memory (absolute_iop, addr_reg, &iocw); /* fetch the IOCW from memory */ cycles = cycles - CYCLES_PER_READ; /* and count the memory access */ @@ -1215,22 +1236,20 @@ while (cycles > 0) { /* execute as long as cy if (iocw & IOCW_DC) /* if the data chain bit is set */ order_reg |= ORDER_DC; /* then set the data chain flag */ - sio_order = order_reg & ORDER_MASK; /* isolate the I/O order */ + sio_order = (SIO_ORDER) (order_reg & ORDER_MASK); /* isolate the I/O order */ if (sio_order != sioRTRES) /* if this is not a Return Residue order */ cntr_reg = IOCW_WCNT (iocw); /* then load the word count */ - dprintf (mpx_dev, DEB_PIO, "Channel SR %d loaded IOCW %06o (%s) from address %06o\n", + dprintf (mpx_dev, DEB_PIO, "Channel SR %u loaded IOCW %06o (%s) from address %06o\n", srn, iocw, sio_order_name [sio_order], addr_reg); - if (sio_order == sioCNTL) /* assert the proper signals for a Control order */ - outbound = dibptr->io_interface (dibptr, PCMD1 | TOGGLESR | CHANSO, iocw); + if (sio_order == sioCNTL) /* if this a Control order */ + inbound_signals |= PCMD1 | TOGGLESR | CHANSO; /* then assert the first command strobe */ - else if (sio_order == sioREAD /* otherwise assert the proper signals */ - || sio_order == sioWRITE) /* for an unchained Read or Write order */ - outbound = dibptr->io_interface (dibptr, ACKSR | CHANSO, iocw); - - else /* otherwise no assertion is needed */ + if (inbound_signals) /* call the interface if there are signals to assert */ + outbound = dibptr->io_interface (dibptr, inbound_signals, iocw); + else /* otherwise the interface isn't involved */ outbound = IORETURN (SRn, 0); /* but assert a service request to continue the program */ addr_reg = addr_reg + 1 & R_MASK; /* point at the IOAW program word */ @@ -1309,7 +1328,7 @@ while (cycles > 0) { /* execute as long as cy cpu_read_memory (absolute_iop, addr_reg, &ioaw); /* then load the IOAW from memory */ cycles = cycles - CYCLES_PER_READ; /* and count the memory access */ - dprintf (mpx_dev, DEB_PIO, "Channel SR %d loaded IOAW %06o from address %06o\n", + dprintf (mpx_dev, DEB_PIO, "Channel SR %u loaded IOAW %06o from address %06o\n", srn, ioaw, addr_reg); } @@ -1325,7 +1344,7 @@ while (cycles > 0) { /* execute as long as cy cpu_write_memory (absolute_iop, addr_reg, ioaw); /* and store it in memory */ cycles = cycles - CYCLES_PER_WRITE; /* count the memory access */ - dprintf (mpx_dev, DEB_PIO, "Channel SR %d stored IOAW %06o to address %06o\n", + dprintf (mpx_dev, DEB_PIO, "Channel SR %u stored IOAW %06o to address %06o\n", srn, ioaw, addr_reg); } @@ -1348,7 +1367,7 @@ while (cycles > 0) { /* execute as long as cy case sioENDIN: end_channel (dibptr); /* end the channel program */ - dprintf (mpx_dev, DEB_STATE, "Channel SR %d entered the %s\n", + dprintf (mpx_dev, DEB_STATE, "Channel SR %u entered the %s\n", srn, state_name [State_Idle]); break; @@ -1392,7 +1411,7 @@ while (cycles > 0) { /* execute as long as cy cpu_read_memory (absolute_iop, addr_reg, &ioaw); /* then read the IOAW */ cycles = cycles - CYCLES_PER_READ; /* and count the memory access */ - dprintf (mpx_dev, DEB_PIO, "Channel SR %d loaded IOAW %06o from address %06o\n", + dprintf (mpx_dev, DEB_PIO, "Channel SR %u loaded IOAW %06o from address %06o\n", srn, ioaw, addr_reg); addr_reg = ioaw; /* store the IOAW into the address register */ @@ -1451,14 +1470,14 @@ while (cycles > 0) { /* execute as long as cy addr_reg + 2 & R_MASK); cycles = cycles - CYCLES_PER_READ - CYCLES_PER_WRITE; /* count the two memory accesses */ - if (cntr_reg == CNTR_MAX) /* if the word count is now exhausted */ - if (order_reg & ORDER_DC) /* then if the order is chained */ - inbound_signals = NO_SIGNALS; /* then all required signals have been sent */ - else /* otherwise */ - inbound_signals = TOGGLESR | CHANSO; /* toggle the channel SR flip-flop */ + if (cntr_reg == CNTR_MAX) /* if the word count is now exhausted */ + if (order_reg & ORDER_DC) /* then if the order is chained */ + inbound_signals = NO_SIGNALS; /* then all required signals have been sent */ + else /* otherwise */ + inbound_signals = ACKSR | TOGGLESR | CHANSO; /* toggle the channel SR flip-flop */ - else { /* otherwise the transfer is incomplete */ - inbound_signals = EOT | TOGGLESR | CHANSO; /* so assert EOT and toggle the channel SR flip-flop */ + else { /* otherwise the transfer is incomplete */ + inbound_signals = ACKSR | EOT | TOGGLESR | CHANSO; /* so assert EOT and toggle the channel SR FF */ if (! (order_reg & ORDER_DC)) { /* if the order is not chained */ aux_reg &= ~AUX_IB; /* then clear the in-block bit in RAM */ @@ -1521,7 +1540,7 @@ while (cycles > 0) { /* execute as long as cy priority_mask = 0; /* request SR priority recalculation */ - dprintf (mpx_dev, DEB_SR, "Device number %d denied SR%d\n", + dprintf (mpx_dev, DEB_SR, "Device number %u denied SR%u\n", dibptr->device_number, dibptr->service_request_number); } @@ -1603,13 +1622,13 @@ return; selected registers are enabled to the active-low IOD bus). */ -static SIGNALS_DATA mpx_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA mpx_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { uint32 address; SIO_ORDER sio_order; INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (mpx_dev, DEB_IOB, "Received data %06o with signals %s\n", @@ -1658,7 +1677,7 @@ while (working_set) { if (state_reg == State_B) /* if the current state is State B */ rollover = CLEAR; /* then clear the word count rollover flip-flop */ - dprintf (mpx_dev, DEB_CSRW, "RAM [%d] stored address %06o | %s | " + dprintf (mpx_dev, DEB_CSRW, "RAM [%u] stored address %06o | %s | " "counter %04o | %s | %sbank %02o\n", address, addr_ram [address], sio_order_name [sio_order], cntr_ram [address], state_name [state_ram [address]], @@ -1679,7 +1698,7 @@ while (working_set) { sio_order = RD_SIO_ORDER (order_reg, cntr_reg); /* get the current SIO order */ - dprintf (mpx_dev, DEB_CSRW, "RAM [%d] loaded address %06o | %s | " + dprintf (mpx_dev, DEB_CSRW, "RAM [%u] loaded address %06o | %s | " "counter %04o | %s | %sbank %02o\n", address, addr_reg, sio_order_name [sio_order], cntr_reg, state_name [state_reg], @@ -1755,7 +1774,7 @@ while (working_set) { outbound_value = ST_DIO_OK | status_word; /* get the last state parity error, if any */ dprintf (mpx_dev, DEB_CSRW, (status_word & ST_STATE_PARITY) - ? "Status is %sRAM address %d\n" + ? "Status is %sRAM address %u\n" : "Status is DIO OK\n", fmt_bitset (outbound_value, status_format), ST_TO_RAM_ADDR (outbound_value)); @@ -1768,7 +1787,7 @@ while (working_set) { if (control_word & CN_MR) /* if a master reset is indicated */ mpx_reset (&mpx_dev); /* then perform an IORESET */ - dprintf (mpx_dev, DEB_CSRW, "Control is %sRAM address %d\n", + dprintf (mpx_dev, DEB_CSRW, "Control is %sRAM address %u\n", fmt_bitset (inbound_value, control_format), CN_RAM_ADDR (control_word)); break; @@ -1911,7 +1930,7 @@ static void end_channel (DIB *dibptr) active_count = active_count - 1; /* decrease the reference count */ mpx_is_idle = (active_count == 0); /* and idle the channel if no more work */ -dprintf (mpx_dev, DEB_CSRW, "Channel SR %d program ended\n", +dprintf (mpx_dev, DEB_CSRW, "Channel SR %u program ended\n", dibptr->service_request_number); return; @@ -1926,11 +1945,11 @@ return; internal logic in response. */ -static SIGNALS_DATA abort_channel (DIB *dibptr, char *reason) +static SIGNALS_DATA abort_channel (DIB *dibptr, const char *reason) { SIGNALS_DATA outbound; -dprintf (mpx_dev, DEB_CSRW, "Channel SR %d asserted XFERERROR for %s\n", +dprintf (mpx_dev, DEB_CSRW, "Channel SR %u asserted XFERERROR for %s\n", dibptr->service_request_number, reason); outbound = dibptr->io_interface (dibptr, XFERERROR | CHANSO, 0); /* tell the device that the channel has aborted */ diff --git a/HP3000/hp3000_ms.c b/HP3000/hp3000_ms.c index 1717b5ac..f058b4f2 100644 --- a/HP3000/hp3000_ms.c +++ b/HP3000/hp3000_ms.c @@ -25,7 +25,12 @@ MS HP 30215A Magnetic Tape Controller Interface + 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 13-May-16 JDB Modified for revised SCP API function parameter types + 24-Mar-16 JDB Changed the buffer element type from uint8 to TL_BUFFER + 21-Mar-16 JDB Changed uint16 types to HP_WORD 10-Nov-15 JDB First release version 26-Oct-14 JDB Passes the magnetic tape diagnostic (D433A) 10-Feb-13 JDB Created @@ -265,7 +270,7 @@ #define DEB_IOB TL_DEB_IOB /* trace I/O bus signals and data words */ #define DEB_SERV TL_DEB_SERV /* trace unit service scheduling calls */ -#define DEB_CSRW (1 << TL_DEB_V_UF + 0) /* trace control, status, read, and write actions */ +#define DEB_CSRW (1u << TL_DEB_V_UF + 0) /* trace control, status, read, and write actions */ /* Control word. @@ -280,13 +285,13 @@ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CN_MR 0100000 /* (M) master reset */ -#define CN_RIN 0040000 /* (R) reset interrupt */ -#define CN_UNIT_MASK 0001400 /* unit number mask */ -#define CN_RSVD_MASK 0000360 /* reserved mask */ -#define CN_CMD_MASK 0000017 /* command code mask */ +#define CN_MR 0100000u /* (M) master reset */ +#define CN_RIN 0040000u /* (R) reset interrupt */ +#define CN_UNIT_MASK 0001400u /* unit number mask */ +#define CN_RSVD_MASK 0000360u /* reserved mask */ +#define CN_CMD_MASK 0000017u /* command code mask */ -#define CN_CMD_RDR 0000006 /* Read Record command */ +#define CN_CMD_RDR 0000006u /* Read Record command */ #define CN_UNIT_SHIFT 8 /* unit number alignment shift */ #define CN_CMD_SHIFT 0 /* command code alignment shift */ @@ -320,19 +325,19 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt reporting the controller status. */ -#define ST_SIO_OK 0100000 /* (S) SIO OK to use */ -/* ST_ODD_COUNT 0040000 */ /* (B) byte count is odd (supplied by hp_tapelib) */ -#define ST_INTREQ 0020000 /* (I) interrupt requested */ -#define ST_UNIT_MASK 0014000 /* unit selected mask */ -/* ST_EOT 0002000 */ /* (E) end of tape (supplied by hp_tapelib) */ -/* ST_PROTECTED 0001000 */ /* (P) write protected (supplied by hp_tapelib) */ -/* ST_READY 0000400 */ /* (R) unit ready (supplied by hp_tapelib) */ -/* ST_LOAD_POINT 0000200 */ /* (L) load point (supplied by hp_tapelib) */ -/* ST_DENSITY_1600 0000100 */ /* (D) 1600 bpi density (supplied by hp_tapelib) */ -/* ST_WRITE_STATUS 0000040 */ /* (W) write status (supplied by hp_tapelib) */ -/* ST_TAPE_MARK 0000020 */ /* (M) tape mark (supplied by hp_tapelib) */ -#define ST_ERROR_MASK 0000016 /* encoded error field mask */ -/* ST_7_TRACK 0000001 */ /* (T) 7-track unit (always off) */ +#define ST_SIO_OK 0100000u /* (S) SIO OK to use */ +/* ST_ODD_COUNT 0040000u */ /* (B) byte count is odd (supplied by hp_tapelib) */ +#define ST_INTREQ 0020000u /* (I) interrupt requested */ +#define ST_UNIT_MASK 0014000u /* unit selected mask */ +/* ST_EOT 0002000u */ /* (E) end of tape (supplied by hp_tapelib) */ +/* ST_PROTECTED 0001000u */ /* (P) write protected (supplied by hp_tapelib) */ +/* ST_READY 0000400u */ /* (R) unit ready (supplied by hp_tapelib) */ +/* ST_LOAD_POINT 0000200u */ /* (L) load point (supplied by hp_tapelib) */ +/* ST_DENSITY_1600 0000100u */ /* (D) 1600 bpi density (supplied by hp_tapelib) */ +/* ST_WRITE_STATUS 0000040u */ /* (W) write status (supplied by hp_tapelib) */ +/* ST_TAPE_MARK 0000020u */ /* (M) tape mark (supplied by hp_tapelib) */ +#define ST_ERROR_MASK 0000016u /* encoded error field mask */ +/* ST_7_TRACK 0000001u */ /* (T) 7-track unit (always off) */ #define ST_UNIT_SHIFT 11 /* unit number alignment shift */ #define ST_ERROR_SHIFT 1 /* encoded error alignment shift */ @@ -345,14 +350,14 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt /* Error codes (complements of the values returned) */ -#define ST_UNITIRQ 0000016 /* unit interrupt */ -#define ST_XFER 0000014 /* transfer error */ -/* ST_REJECT 0000012 */ /* command reject (supplied by hp_tapelib) */ -/* ST_RUNAWAY 0000010 */ /* tape runaway (supplied by hp_tapelib) */ -/* ST_TIMING 0000006 */ /* timing error (supplied by hp_tapelib) */ -/* ST_PARITY 0000004 */ /* tape error (supplied by hp_tapelib) */ -/* ST_RESERVED 0000002 */ /* (reserved) */ -/* ST_NOERROR 0000000 */ /* no error */ +#define ST_UNITIRQ 0000016u /* unit interrupt */ +#define ST_XFER 0000014u /* transfer error */ +/* ST_REJECT 0000012u */ /* command reject (supplied by hp_tapelib) */ +/* ST_RUNAWAY 0000010u */ /* tape runaway (supplied by hp_tapelib) */ +/* ST_TIMING 0000006u */ /* timing error (supplied by hp_tapelib) */ +/* ST_PARITY 0000004u */ /* tape error (supplied by hp_tapelib) */ +/* ST_RESERVED 0000002u */ /* (reserved) */ +/* ST_NOERROR 0000000u */ /* no error */ static const BITSET_NAME status_names [] = { /* Status word names */ "SIO OK", /* bit 0 */ @@ -434,17 +439,17 @@ static FLIP_FLOP channel_sr = CLEAR; /* channel service reque static FLIP_FLOP device_sr = CLEAR; /* device service request flip-flop */ static FLIP_FLOP input_xfer = CLEAR; /* input transfer flip-flop */ static FLIP_FLOP output_xfer = CLEAR; /* output transfer flip-flop */ -static FLIP_FLOP interrupt_mask = CLEAR; /* interrupt mask flip-flop */ +static FLIP_FLOP interrupt_mask = SET; /* interrupt mask flip-flop */ static FLIP_FLOP unit_interrupt = CLEAR; /* unit ready flip-flop */ static FLIP_FLOP device_end = CLEAR; /* device end flip-flop */ static FLIP_FLOP xfer_error = CLEAR; /* transfer error flip-flop */ -static uint16 buffer_word = 0; /* data buffer word */ -static uint16 attention_unit = 0; /* number of the unit requesting attention */ +static HP_WORD buffer_word = 0; /* data buffer word */ +static HP_WORD attention_unit = 0; /* number of the unit requesting attention */ static CNTLR_CLASS command_class = Class_Invalid; /* current command classification */ static CNTLR_FLAG_SET flags = INTOK; /* tape controller interface flag set */ -static uint8 buffer [TL_BUFSIZE]; /* the tape record buffer */ +static TL_BUFFER buffer [TL_BUFSIZE]; /* the tape record buffer */ DEVICE ms_dev; /* incomplete device structure */ @@ -497,22 +502,22 @@ static UNIT ms_unit [UNIT_COUNT] = { /* Register list */ static REG ms_reg [] = { -/* Macro Name Location Width Offset Flags */ -/* ------ ------ -------------- ----- ------ ------------------------- */ - { FLDATA (SIOBSY, sio_busy, 0) }, - { FLDATA (CHANSR, channel_sr, 0) }, - { FLDATA (DEVSR, device_sr, 0) }, - { FLDATA (INXFR, input_xfer, 0) }, - { FLDATA (OUTXFR, output_xfer, 0) }, - { FLDATA (INTMSK, interrupt_mask, 0) }, - { FLDATA (UINTRP, unit_interrupt, 0) }, - { FLDATA (DEVEND, device_end, 0) }, - { FLDATA (XFRERR, xfer_error, 0) }, - { ORDATA (BUFWRD, buffer_word, 16), REG_A | REG_FIT | PV_RZRO }, - { DRDATA (ATUNIT, attention_unit, 16), REG_FIT | PV_LEFT }, - { DRDATA (CLASS, command_class, 4), PV_LEFT }, - { YRDATA (FLAGS, flags, 8) }, - { SRDATA (DIB, ms_dib), REG_HRO }, +/* Macro Name Location Width Offset Flags */ +/* ------ ------ -------------- ----- ------ ------------------------- */ + { FLDATA (SIOBSY, sio_busy, 0) }, + { FLDATA (CHANSR, channel_sr, 0) }, + { FLDATA (DEVSR, device_sr, 0) }, + { FLDATA (INXFR, input_xfer, 0) }, + { FLDATA (OUTXFR, output_xfer, 0) }, + { FLDATA (INTMSK, interrupt_mask, 0) }, + { FLDATA (UINTRP, unit_interrupt, 0) }, + { FLDATA (DEVEND, device_end, 0) }, + { FLDATA (XFRERR, xfer_error, 0) }, + { ORDATA (BUFWRD, buffer_word, 16), REG_A | REG_FIT | PV_RZRO }, + { 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) }, TL_REGS (ms_cntlr, ms_unit, DRIVE_COUNT, buffer, fast_times), @@ -679,12 +684,12 @@ DEVICE ms_dev = { JMPMET signal is asserted continuously when enabled by CHANSO. */ -static SIGNALS_DATA ms_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA ms_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { CNTLR_OPCODE opcode; INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (ms_dev, DEB_IOB, "Received data %06o with signals %s\n", @@ -737,10 +742,13 @@ while (working_set) { case DSETMASK: - interrupt_mask = /* set the mask flip-flop */ - D_FF (dibptr->interrupt_mask & inbound_value); /* from the mask bit and the mask value */ + if (dibptr->interrupt_mask == INTMASK_E) /* if the mask is always enabled */ + interrupt_mask = SET; /* then set the mask flip-flop */ + else /* otherwise */ + interrupt_mask = D_FF (dibptr->interrupt_mask /* set the mask flip-flop if the mask bit */ + & inbound_value); /* is present in the mask value */ - if (interrupt_mask & dibptr->interrupt_request) /* if the mask is enabled and a request is pending */ + if (interrupt_mask && dibptr->interrupt_request) /* if the mask is enabled and a request is pending */ outbound_signals |= INTREQ; /* then assert the INTREQ signal */ break; @@ -786,7 +794,7 @@ while (working_set) { if (dibptr->interrupt_request) /* if an interrupt request is pending */ outbound_value |= ST_INTREQ; /* then set the status bit */ - dprintf (ms_dev, DEB_CSRW, "Status is %s%s | unit %d\n", + dprintf (ms_dev, DEB_CSRW, "Status is %s%s | unit %u\n", fmt_bitset (outbound_value, status_format), error_names [ST_TO_ERROR (outbound_value)], ST_TO_UNIT (outbound_value)); @@ -879,9 +887,9 @@ while (working_set) { inbound_value, tl_opcode_name (opcode)); if ((inbound_value & CN_RSVD_MASK) != 0) /* if the reserved bits aren't zero */ - buffer_word = (uint16) Invalid_Opcode; /* then reject the command */ + buffer_word = (HP_WORD) Invalid_Opcode; /* then reject the command */ else /* otherwise */ - buffer_word = (uint16) opcode; /* store the opcode in the data buffer register */ + buffer_word = (HP_WORD) opcode; /* store the opcode in the data buffer register */ flags |= CMRDY | CMXEQ; /* set the command ready and execute flags */ @@ -993,7 +1001,7 @@ static t_stat ms_service (UNIT *uptr) t_stat result; dprintf (ms_dev, DEB_SERV, "%s service entered\n", - tl_unit_name (uptr - ms_unit)); + tl_unit_name ((int32) (uptr - ms_unit))); result = call_controller (uptr); /* call the controller */ @@ -1017,12 +1025,6 @@ return result; static t_stat ms_reset (DEVICE *dptr) { -t_stat status; - -master_reset (); /* perform a master reset */ - -status = tl_reset (&ms_cntlr); /* reset the controller */ - if (sim_switches & SWMASK ('P')) { /* if this is a power-on reset */ fast_times.rewind_start = MS_REW_START; /* then reset the rewind initiation time, */ fast_times.rewind_rate = MS_REW_RATE; /* the rewind time per inch, */ @@ -1032,7 +1034,9 @@ if (sim_switches & SWMASK ('P')) { /* if this is a power-on fast_times.overhead = MS_OVERHEAD; /* and the controller execution overhead */ } -return status; /* return the result of the reset */ +master_reset (); /* perform a master reset */ + +return tl_reset (&ms_cntlr); /* reset the controller and return the result */ } @@ -1261,7 +1265,7 @@ CNTLR_IFN command; t_stat status = SCPE_OK; result = /* call the controller to start or continue a command */ - tl_controller (&ms_cntlr, uptr, flags, buffer_word); + tl_controller (&ms_cntlr, uptr, flags, (CNTLR_IBUS) buffer_word); command_set = TLIFN (result) & ~UNUSED_COMMANDS; /* strip the commands we don't use as an efficiency */ diff --git a/HP3000/hp3000_release.txt b/HP3000/hp3000_release.txt index 5cc75841..29b213c7 100644 --- a/HP3000/hp3000_release.txt +++ b/HP3000/hp3000_release.txt @@ -1,6 +1,6 @@ SIMH/HP 3000 RELEASE NOTES ========================== - Last update: 2016-03-06 + Last update: 2016-07-05 This file documents the release history of the Hewlett-Packard 3000 simulator. @@ -71,8 +71,8 @@ Manuals describing MPE operation are also available from Bitsavers at: http://www.bitsavers.org/pdf/hp/3000/ HP created MPE-V/R-specific manuals. However, very few of them survive. In -general, the MPE-IV manuals will describe a subset of MPE-V/R commands, whereas -the MPE-V/E manuals describe a superset. Relying on the MPE-IV manuals and the +general, the MPE-IV manuals describe a subset of MPE-V/R commands, whereas the +MPE-V/E manuals describe a superset. Relying on the MPE-IV manuals and the online help available within MPE for those commands that do not appear in the manuals is perhaps the best compromise. @@ -158,6 +158,153 @@ the MPE version used: +===================== +Release 2, 2016-07-05 +===================== + +This release of the HP 3000 simulator adds the following device simulation: + + - 30209A Line Printer Controller with One 2607/13/17/18 Line Printer + +The simulation supports the use of custom VFU tape images, as well as the +built-in HP-standard VFU tape. The simulated device name is "LP". The full set +of configurable options is detailed in a new section of the HP 3000 Simulator +User's Guide. + +In addition, the preconfigured MPE-V/R disc image has been updated to add the +following features: + + - The MPE cold load command files attach the line printer to the "lp.txt" + output file and specify the "-n" option to clear the file before use. + + - Preinstalled User-Defined Commands (UDCs) provide access to the COBOL 74 + compiler with the MPE-V/E :COBOLII, :COBOLIIPREP, and :COBOLIIGO commands, + and to the COBOL 85 compiler with :COBOLIIX, :COBOLIIXPREP, and :COBOLIIXGO. + However, see the implementation note below. + + +-------------------- +Implementation Notes +-------------------- + + - MPE requires a line printer, so it is recommended that the MPE startup + simulator command file include an ATTACH LP <filename> command to load paper + into the printer before cold loading. If the printer is not attached, it + will appear to MPE to be out of paper. + + - The line printer terminates each print line with an HP-standard CR/LF pair. + If the output file is to be retained as a text file on a Unix system, removal + of the carriage returns, e.g., via the "dos2unix" utility, may be desirable. + + - The simulator currently does not provide the HP 32234A COBOL II firmware + instructions, so programs generated by the COBOLII compiler will abort at run + time with an "ILLEGAL INSTRUCTION" error. Programs generated by the COBOL + compiler do not use these instructions and therefore are not affected. + + +---------- +Bugs Fixed +---------- + + 1. PROBLEM: The effective address of a byte pointer with a negative index is + calculated incorrectly. + + VERSION: Release 1 + + OBSERVATION: Defining a :WELCOME message in MPE appears to work, but when + the next logon attempts to print the message, an infinite number of CRLFs + are printed instead. + + CAUSE: The welcome message is stored in an extra data segment. The format + for each message line is a line length stored in the lower byte of the word + preceding the message string. The code defines BYTE POINTER NEXTLINE and + points NEXTLINE to the first message character. The line length is set + with NEXTLINE(-1) := IOCOUNT. This generates a LOAD <IOCOUNT> ; LDXN 1 ; + STB <NEXTLINE>,I,X sequence. + + In the "cpu_ea" routine, the indexing adds the X register value (-1) to the + byte pointer (NEXTLINE). This causes an overflow that is not masked to 16 + bits. For a word access, this displacement is added to the base register + and then masked to 16 bits, which gives the correct value. However, for + byte accesses, the displacement is divided by 2 and then added, and the sum + is masked. Dividing by 2 shifts the overflow bit into the MSB, causing the + addition result to be off by 32K. The STB goes to the wrong location, the + original zero in the length byte location is retained, and when the welcome + message is printed, a zero-length line is printed, and the byte pointer is + incremented by zero, so the null line is printed forever. + + RESOLUTION: Modify "cpu_ea" (hp3000_cpu.c) to mask indexed displacements + to 16 bits after adding the X register value. + + STATUS: Fixed in Release 2. + + + 2. PROBLEM: An SMSK instruction may clear the interrupt mask flip-flop of a + device that specifies that it is should be "always enabled." + + VERSION: Release 1 + + OBSERVATION: If the TOS word is zero, an SMSK instruction will clear the + interrupt mask flip-flop of a device whose mask jumper is set to "E" + (always enabled). + + CAUSE: In response to a DSETMASK signal, device interfaces set their + interrupt mask flip-flops by "anding" the incoming data word with the + interrupt mask jumper setting. The jumper setting value for "always + enabled" is %177777, which sets the mask flip-flop in all cases, except + when the data word is zero. + + RESOLUTION: Modify hp3000_atc.c, hp3000_ds.c, and hp3000_ms.c to set their + mask flip-flops unconditionally if the jumper setting is "E". + + STATUS: Fixed in Release 2. + + + 3. PROBLEM: The "SET <dev> INTMASK=<n>" command sets the wrong bit in the + device interface's interrupt mask jumper setting. + + VERSION: Release 1 + + OBSERVATION: The interrupt mask jumper on a device interface is set by + specifying the mask bit number in a "SET <dev> INTMASK=<n>" command. This + sets a bit in the device's interrupt mask jumper word corresponding to the + bit number requested. However, the bit numbering is incorrect; setting the + jumper for bit 15, for example, sets bit 0 of the jumper word. Therefore, + the interface's mask flip-flop is not set as expected when an SMSK + instruction is executed. + + CAUSE: The bit numbers were counted from the wrong end of the word. + + RESOLUTION: Modify "hp_set_dib" and "hp_show_dib" (hp3000_sys.c) to number + the bits from the MSB instead of the LSB. + + STATUS: Fixed in Release 2. + + + 4. PROBLEM: The Multiplexer Channel is not generating the ACKSR signal + correctly. + + VERSION: Release 1 + + OBSERVATION: The line printer controller hangs when an SIO chained write + is performed. The first programmed write completes normally, but the + second does not start. The channel is waiting for a service request that + does not occur. + + CAUSE: The service request from the last write of the first block transfer + is being cleared by an ACKSR generated by the Multiplexer Channel when it + performs the IOCW fetch in State A for the second write request. The + channel should omit this ACKSR when the previous I/O order was a chained + read or write. However, the simulator is testing the order just fetched + (Write) instead of the order that has just completed (Write Chained). + + RESOLUTION: Modify "mpx_service" (hp3000_mpx.c) to test the correct I/O + order in State A. + + STATUS: Fixed in Release 2. + + + ===================== Release 1, 2016-03-07 ===================== diff --git a/HP3000/hp3000_scmb.c b/HP3000/hp3000_scmb.c index 286bd55d..97bee143 100644 --- a/HP3000/hp3000_scmb.c +++ b/HP3000/hp3000_scmb.c @@ -25,7 +25,9 @@ SCMB1,SCMB2 HP 30033A Selector Channel Maintenance Board + 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 21-Sep-15 JDB First release version 27-Jan-15 JDB Passes the selector channel diagnostic (D429A) 12-Jan-15 JDB Passes the SCMB diagnostic (D429A) @@ -87,7 +89,7 @@ N = enable special device number T = terminate on terminal count C = terminate on compare failure - L = enable clear interface on terminate + L = enable device end/clear interface (0/1) on terminate Load: 00 = load the IOAW into the control word @@ -205,7 +207,7 @@ #define UNIT_W1_SHIFT (UNIT_V_UF + 0) /* jumper W1 */ -#define UNIT_W1_SEL (1 << UNIT_W1_SHIFT) +#define UNIT_W1_SEL (1u << UNIT_W1_SHIFT) #define MPX_BUS(card) ((scmb_unit [card].flags & UNIT_W1_SEL) == 0) #define SEL_BUS(card) ((scmb_unit [card].flags & UNIT_W1_SEL) != 0) @@ -213,10 +215,10 @@ /* Debug flags */ -#define DEB_CSRW (1 << 0) /* trace commands received and status returned */ -#define DEB_XFER (1 << 1) /* trace channel data reads and writes */ -#define DEB_SERV (1 << 2) /* trace unit service scheduling calls */ -#define DEB_IOB (1 << 3) /* trace I/O bus signals and data words */ +#define DEB_CSRW (1u << 0) /* trace commands received and status returned */ +#define DEB_XFER (1u << 1) /* trace channel data reads and writes */ +#define DEB_SERV (1u << 2) /* trace unit service scheduling calls */ +#define DEB_IOB (1u << 3) /* trace I/O bus signals and data words */ /* Control word. @@ -227,19 +229,19 @@ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ -#define CN_MR 0100000 /* M = master reset */ -#define CN_IRQ_RESET 0040000 /* R = interrupt reset */ -#define CN_JMPMET 0020000 /* J = set jump met */ -#define CN_DEVEND 0010000 /* V = device end */ -#define CN_NOACK 0004000 /* A = inhibit channel acknowledge */ -#define CN_NOSR 0002000 /* S = inhibit service request */ -#define CN_LOAD_MASK 0001400 /* load operation mask */ -#define CN_HSREQ 0000200 /* H = high speed service request */ -#define CN_DEVNO 0000100 /* N = special device number */ -#define CN_TERM_COUNT 0000040 /* T = terminate on count */ -#define CN_TERM_COMP 0000020 /* C = terminate on miscompare */ -#define CN_CLEAR_IF 0000010 /* L = clear interface */ -#define CN_CNTR_MASK 0000007 /* counter operation mask */ +#define CN_MR 0100000u /* M = master reset */ +#define CN_IRQ_RESET 0040000u /* R = interrupt reset */ +#define CN_JMPMET 0020000u /* J = set jump met */ +#define CN_DEVEND 0010000u /* V = set device end */ +#define CN_NOACK 0004000u /* A = inhibit channel acknowledge */ +#define CN_NOSR 0002000u /* S = inhibit service request */ +#define CN_LOAD_MASK 0001400u /* load operation mask */ +#define CN_HSREQ 0000200u /* H = high speed service request */ +#define CN_DEVNO 0000100u /* N = special device number */ +#define CN_TERM_COUNT 0000040u /* T = terminate on count */ +#define CN_TERM_COMP 0000020u /* C = terminate on miscompare */ +#define CN_CLEAR_IF 0000010u /* L = clear interface */ +#define CN_CNTR_MASK 0000007u /* counter operation mask */ #define CN_LOAD_SHIFT 8 /* load operation alignment shift */ #define CN_CNTR_SHIFT 0 /* counter operation alignment shift */ @@ -280,23 +282,23 @@ static const char *const count_names [8] = { /* indexed by CNTR_OP */ "count PWRITESTB", /* 100 = count PWRITESTB */ "count TOGGLEOUTXFER", /* 101 = count TOGGLEOUTXFER */ "count EOT", /* 110 = count EOT */ - "count CHANSO", /* 111 = count CHANSO */ + "count CHANSO" /* 111 = count CHANSO */ }; -static const BITSET_NAME control_names [] = { /* Control word names */ - "master reset", /* bit 0 */ - "reset interrupt", /* bit 1 */ - "set JMPMET", /* bit 2 */ - "set DEVEND", /* bit 3 */ - "inhibit CHANACK", /* bit 4 */ - "inhibit SR", /* bit 5 */ - NULL, /* bit 6 */ - NULL, /* bit 7 */ - "high speed", /* bit 8 */ - "send DEVNO", /* bit 9 */ - "end on count", /* bit 10 */ - "end on miscompare", /* bit 11 */ - "\1clear interface\0device end", /* bit 12 */ +static const BITSET_NAME control_names [] = { /* Control word names */ + "master reset", /* bit 0 */ + "reset interrupt", /* bit 1 */ + "set JMPMET", /* bit 2 */ + "set DEVEND", /* bit 3 */ + "inhibit CHANACK", /* bit 4 */ + "inhibit SR", /* bit 5 */ + NULL, /* bit 6 */ + NULL, /* bit 7 */ + "high speed", /* bit 8 */ + "send DEVNO", /* bit 9 */ + "end on count", /* bit 10 */ + "end on miscompare", /* bit 11 */ + "\1end with clear interface\0end with device end" /* bit 12 */ }; static const BITSET_FORMAT control_format = /* names, offset, direction, alternates, bar */ @@ -315,19 +317,19 @@ static const BITSET_FORMAT control_format = /* names, offset, direction, alt manual has the correct assignments. */ -#define ST_SIO_OK 0100000 /* S = SIO OK to use */ -#define ST_DIO_OK 0040000 /* D = direct I/O OK to use (always 1) */ -#define ST_INTREQ 0020000 /* R = interrupt requested */ -#define ST_INTACT 0010000 /* A = interrupt active */ -#define ST_XFERERR 0004000 /* X = transfer error is asserted */ -#define ST_SIOENABLED 0002000 /* N = SIO enabled is asserted */ -#define ST_DEVEND 0001000 /* V = device end is asserted */ -#define ST_EOT 0000400 /* E = end of transfer is asserted */ -#define ST_END_MISCMP 0000200 /* C = end on miscompare occurred */ -#define ST_END_COUNT 0000100 /* T = end on terminal count occurred */ -#define ST_INXFER 0000040 /* I = input transfer is asserted */ -#define ST_OUTXFER 0000020 /* O = output transfer is asserted */ -#define ST_CLEAR_IF 0000010 /* L = clear interface is asserted */ +#define ST_SIO_OK 0100000u /* S = SIO OK to use */ +#define ST_DIO_OK 0040000u /* D = direct I/O OK to use (always 1) */ +#define ST_INTREQ 0020000u /* R = interrupt requested */ +#define ST_INTACT 0010000u /* A = interrupt active */ +#define ST_XFERERR 0004000u /* X = transfer error is asserted */ +#define ST_SIOENABLED 0002000u /* N = SIO enabled is asserted */ +#define ST_DEVEND 0001000u /* V = device end is asserted */ +#define ST_EOT 0000400u /* E = end of transfer is asserted */ +#define ST_END_MISCMP 0000200u /* C = end on miscompare occurred */ +#define ST_END_COUNT 0000100u /* T = end on terminal count occurred */ +#define ST_INXFER 0000040u /* I = input transfer is asserted */ +#define ST_OUTXFER 0000020u /* O = output transfer is asserted */ +#define ST_CLEAR_IF 0000010u /* L = clear interface is asserted */ #define END_CONDITION (ST_END_MISCMP | ST_END_COUNT) @@ -359,11 +361,11 @@ typedef enum { } CARD_ID; typedef struct { - uint16 control_word; /* control word register */ - uint16 status_word; /* status word register */ - uint16 counter; /* counter/buffer register */ - uint16 flags; /* status flags */ - uint32 saved_srn; /* saved SR number */ + HP_WORD control_word; /* control word register */ + HP_WORD status_word; /* status word register */ + HP_WORD counter; /* counter/buffer register */ + HP_WORD flags; /* status flags */ + uint32 saved_srn; /* saved SR number */ FLIP_FLOP sio_busy; /* SIO busy flip-flop */ FLIP_FLOP channel_sr; /* channel service request flip-flop */ @@ -439,55 +441,55 @@ static UNIT scmb_unit [] = { /* Register lists */ static REG scmb1_reg [] = { -/* Macro Name Location Width Offset Flags */ -/* ------ ------ -------------------------- ----- ------ ----------------- */ - { ORDATA (CNTL, scmb [card1].control_word, 16), REG_FIT }, - { ORDATA (STAT, scmb [card1].status_word, 16), REG_FIT }, - { ORDATA (CNTR, scmb [card1].counter, 16), REG_FIT }, - { ORDATA (SRSAVE, scmb [card1].saved_srn, 8), REG_HRO }, +/* Macro Name Location Width Offset Flags */ +/* ------ ------ -------------------------- ----- ------ ----------------- */ + { ORDATA (CNTL, scmb [card1].control_word, 16), REG_FIT }, + { ORDATA (STAT, scmb [card1].status_word, 16), REG_FIT }, + { ORDATA (CNTR, scmb [card1].counter, 16), REG_FIT }, + { ORDATA (SRSAVE, scmb [card1].saved_srn, 8), REG_HRO }, - { FLDATA (SIOBSY, scmb [card1].sio_busy, 0) }, - { FLDATA (CHANSR, scmb [card1].channel_sr, 0) }, - { FLDATA (DEVSR, scmb [card1].device_sr, 0) }, - { FLDATA (INXFR, scmb [card1].input_xfer, 0) }, - { FLDATA (OUTXFR, scmb [card1].output_xfer, 0) }, + { FLDATA (SIOBSY, scmb [card1].sio_busy, 0) }, + { FLDATA (CHANSR, scmb [card1].channel_sr, 0) }, + { FLDATA (DEVSR, scmb [card1].device_sr, 0) }, + { FLDATA (INXFR, scmb [card1].input_xfer, 0) }, + { FLDATA (OUTXFR, scmb [card1].output_xfer, 0) }, - { FLDATA (JMPMET, scmb [card1].jump_met, 0) }, - { FLDATA (XFRERR, scmb [card1].flags, 11) }, - { FLDATA (EOT, scmb [card1].flags, 8) }, - { FLDATA (TRMCNT, scmb [card1].flags, 6) }, - { FLDATA (MISCMP, scmb [card1].flags, 7) }, - { FLDATA (DEVEND, scmb [card1].device_end, 0) }, - { FLDATA (STOP, scmb [card1].stop_transfer, 0) }, + { FLDATA (JMPMET, scmb [card1].jump_met, 0) }, + { FLDATA (XFRERR, scmb [card1].flags, 11) }, + { FLDATA (EOT, scmb [card1].flags, 8) }, + { FLDATA (TRMCNT, scmb [card1].flags, 6) }, + { FLDATA (MISCMP, scmb [card1].flags, 7) }, + { FLDATA (DEVEND, scmb [card1].device_end, 0) }, + { FLDATA (STOP, scmb [card1].stop_transfer, 0) }, - { SRDATA (DIB, scmb_dib [card1]), REG_HRO }, + { SRDATA (DIB, scmb_dib [card1], REG_HRO) }, { NULL } }; static REG scmb2_reg [] = { -/* Macro Name Location Width Offset Flags */ -/* ------ ------ -------------------------- ----- ------ ----------------- */ - { ORDATA (CNTL, scmb [card2].control_word, 16), REG_FIT }, - { ORDATA (STAT, scmb [card2].status_word, 16), REG_FIT }, - { ORDATA (CNTR, scmb [card2].counter, 16), REG_FIT }, - { ORDATA (SRSAVE, scmb [card2].saved_srn, 8), REG_HRO }, +/* Macro Name Location Width Offset Flags */ +/* ------ ------ -------------------------- ----- ------ ----------------- */ + { ORDATA (CNTL, scmb [card2].control_word, 16), REG_FIT }, + { ORDATA (STAT, scmb [card2].status_word, 16), REG_FIT }, + { ORDATA (CNTR, scmb [card2].counter, 16), REG_FIT }, + { ORDATA (SRSAVE, scmb [card2].saved_srn, 8), REG_HRO }, - { FLDATA (SIOBSY, scmb [card2].sio_busy, 0) }, - { FLDATA (CHANSR, scmb [card2].channel_sr, 0) }, - { FLDATA (DEVSR, scmb [card2].device_sr, 0) }, - { FLDATA (INXFR, scmb [card2].input_xfer, 0) }, - { FLDATA (OUTXFR, scmb [card2].output_xfer, 0) }, + { FLDATA (SIOBSY, scmb [card2].sio_busy, 0) }, + { FLDATA (CHANSR, scmb [card2].channel_sr, 0) }, + { FLDATA (DEVSR, scmb [card2].device_sr, 0) }, + { FLDATA (INXFR, scmb [card2].input_xfer, 0) }, + { FLDATA (OUTXFR, scmb [card2].output_xfer, 0) }, - { FLDATA (JMPMET, scmb [card2].jump_met, 0) }, - { FLDATA (XFRERR, scmb [card2].flags, 11) }, - { FLDATA (EOT, scmb [card2].flags, 8) }, - { FLDATA (TRMCNT, scmb [card2].flags, 6) }, - { FLDATA (MISCMP, scmb [card2].flags, 7) }, - { FLDATA (DEVEND, scmb [card2].device_end, 0) }, - { FLDATA (STOP, scmb [card2].stop_transfer, 0) }, + { FLDATA (JMPMET, scmb [card2].jump_met, 0) }, + { FLDATA (XFRERR, scmb [card2].flags, 11) }, + { FLDATA (EOT, scmb [card2].flags, 8) }, + { FLDATA (TRMCNT, scmb [card2].flags, 6) }, + { FLDATA (MISCMP, scmb [card2].flags, 7) }, + { FLDATA (DEVEND, scmb [card2].device_end, 0) }, + { FLDATA (STOP, scmb [card2].stop_transfer, 0) }, - { SRDATA (DIB, scmb_dib [card1]), REG_HRO }, + { SRDATA (DIB, scmb_dib [card1], REG_HRO) }, { NULL } }; @@ -694,15 +696,15 @@ DEVICE scmb_dev [] = { use the DIB field to obtain the device number. */ -static SIGNALS_DATA scmb_interface (DIB *dibptr, INBOUND_SET inbound_signals, uint16 inbound_value) +static SIGNALS_DATA scmb_interface (DIB *dibptr, INBOUND_SET inbound_signals, HP_WORD inbound_value) { const CARD_ID card = (CARD_ID) (dibptr->card_index); /* the ID number of the card */ LOAD_OP load_operation; FLIP_FLOP assert_sr; -uint16 saved_devno; +HP_WORD saved_devno; INBOUND_SIGNAL signal; INBOUND_SET working_set = inbound_signals; -uint16 outbound_value = 0; +HP_WORD outbound_value = 0; OUTBOUND_SET outbound_signals = NO_SIGNALS; dprintf (scmb_dev [card], DEB_IOB, "Received data %06o with signals %s\n", @@ -875,7 +877,7 @@ while (working_set) { /* while there are signa scmb [card].flags &= ~ST_EOT; /* then clear the EOT flag */ scmb [card].device_end = /* set or clear device end status depending on */ - (scmb [card].control_word & CN_DEVEND) != 0; /* whether an immediate device end is enabled */ + D_FF (scmb [card].control_word & CN_DEVEND); /* whether an immediate device end is enabled */ } scmb [card].device_sr = SET; /* preset the device SR flip-flop */ @@ -892,7 +894,7 @@ while (working_set) { /* while there are signa scmb [card].flags &= ~ST_EOT; /* then clear the EOT flag */ scmb [card].device_end = /* set or clear device end status depending on */ - (scmb [card].control_word & CN_DEVEND) != 0; /* whether an immediate device end is enabled */ + D_FF (scmb [card].control_word & CN_DEVEND); /* whether an immediate device end is enabled */ } scmb [card].device_sr = SET; /* preset the device SR flip-flop */ @@ -1029,19 +1031,20 @@ if (scmb [card].flags & END_CONDITION) /* if a termination cond outbound_signals |= INTREQ; /* and request the interrupt */ } -if (scmb [card].control_word & CN_HSREQ) /* if high-speed requests are enabled */ - assert_sr = scmb [card].channel_sr | scmb [card].device_sr; /* then assert SR immediately if indicated */ +if (scmb [card].control_word & CN_HSREQ) /* if high-speed requests are enabled */ + assert_sr = D_FF (scmb [card].channel_sr /* then assert SR immediately if indicated */ + | scmb [card].device_sr); -else { /* otherwise assert SR immediately */ - assert_sr = scmb [card].channel_sr; /* only if the channel is requesting service */ +else { /* otherwise assert SR immediately */ + assert_sr = scmb [card].channel_sr; /* only if the channel is requesting service */ - if ((! assert_sr & scmb [card].device_sr) /* if a delayed device SR assertion is requested */ - && (MPX_BUS (card) || outbound_signals & CHANACK) /* and we're on the MPX bus or CHANACK is not inhibited */ - && (scmb [card].control_word & CN_NOSR) == 0) { /* and channel service is not inhibited */ - sim_activate (&scmb_unit [card], /* then schedule SR assertion in 5 microseconds */ + if ((! assert_sr & scmb [card].device_sr) /* if a delayed device SR assertion is requested */ + && (MPX_BUS (card) || outbound_signals & CHANACK) /* and we're on the MPX bus or CHANACK is not inhibited */ + && (scmb [card].control_word & CN_NOSR) == 0) { /* and channel service is not inhibited */ + sim_activate (&scmb_unit [card], /* then schedule SR assertion in 5 microseconds */ scmb_unit [card].wait); - dprintf (scmb_dev [card], DEB_SERV, "Delay %d SR service scheduled\n", + dprintf (scmb_dev [card], DEB_SERV, "Delay %u SR service scheduled\n", scmb_unit [card].wait); } } diff --git a/HP3000/hp3000_sel.c b/HP3000/hp3000_sel.c index 118af108..fd6c3b91 100644 --- a/HP3000/hp3000_sel.c +++ b/HP3000/hp3000_sel.c @@ -25,6 +25,10 @@ SEL HP 3000 Series III Selector Channel + 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 + 21-Mar-16 JDB Changed uint16 types to HP_WORD 23-Sep-15 JDB First release version 27-Jan-15 JDB Passes the selector channel diagnostic (D429A) 10-Feb-13 JDB Created @@ -327,8 +331,8 @@ #define CYCLES_PER_EVENT (uint32) (USEC_PER_EVENT * 1000 / NS_PER_CYCLE) -#define CNTR_MASK 0007777 /* word counter count mask */ -#define CNTR_MAX 0007777 /* word counter maximum value */ +#define CNTR_MASK 0007777u /* word counter count mask */ +#define CNTR_MAX 0007777u /* word counter maximum value */ typedef enum { /* selector channel sequencer state */ @@ -367,10 +371,10 @@ static const char *const action_name [] = { /* indexed by SEQ_STATE */ 1. Bit 0 is reserved for the memory data trace flag. */ -#define DEB_CSRW (1 << 1) /* trace channel command initiations and completions */ -#define DEB_PIO (1 << 2) /* trace programmed I/O commands */ -#define DEB_STATE (1 << 3) /* trace state changes */ -#define DEB_SR (1 << 4) /* trace service requests */ +#define DEB_CSRW (1u << 1) /* trace channel command initiations and completions */ +#define DEB_PIO (1u << 2) /* trace programmed I/O commands */ +#define DEB_STATE (1u << 3) /* trace state changes */ +#define DEB_SR (1u << 4) /* trace service requests */ /* Channel global state */ @@ -384,6 +388,7 @@ t_bool sel_request = FALSE; /* TRUE if the channel sequencer static SEQ_STATE sequencer = Idle_Sequence; /* the current sequencer execution state */ static SIO_ORDER order; /* the current SIO order */ static DIB *active_dib; /* a pointer to the participating interface's DIB */ +static uint32 device_index; /* the index into the device table */ static t_bool prefetch_control; /* TRUE if the IOCW should be prefetched */ static t_bool prefetch_address; /* TRUE if the IOAW should be prefetched */ @@ -410,10 +415,10 @@ static t_stat sel_reset (DEVICE *dptr); /* Channel local utility routines */ -static void end_channel (DIB *dibptr); -static SIGNALS_DATA abort_channel (char *reason); -static void load_control (HP_WORD *value); -static void load_address (HP_WORD *value); +static void end_channel (DIB *dibptr); +static SIGNALS_DATA abort_channel (const char *reason); +static void load_control (HP_WORD *value); +static void load_address (HP_WORD *value); /* Channel SCP data structures */ @@ -428,30 +433,30 @@ static UNIT sel_unit = { /* Register list */ static REG sel_reg [] = { -/* Macro Name Location Width Offset Flags */ -/* ------ ------ --------------- ----- ------ --------------- */ - { FLDATA (IDLE, sel_is_idle, 0) }, - { FLDATA (SREQ, sel_request, 0) }, - { DRDATA (DEVNO, device_number, 8), PV_LEFT }, - { DRDATA (EXCESS, excess_cycles, 32), PV_LEFT }, - { ORDATA (DIB, active_dib, 32), REG_HRO }, +/* Macro Name Location Width Offset Flags */ +/* ------ ------ --------------- ----- ------ ----------------- */ + { FLDATA (IDLE, sel_is_idle, 0) }, + { FLDATA (SREQ, sel_request, 0) }, + { DRDATA (DEVNO, device_number, 8), PV_LEFT }, + { DRDATA (EXCESS, excess_cycles, 32), PV_LEFT }, + { DRDATA (INDEX, device_index, 32), PV_LEFT | REG_HRO }, - { DRDATA (SEQ, sequencer, 3) }, - { ORDATA (ORDER, order, 4) }, - { FLDATA (ROLOVR, rollover, 0) }, - { FLDATA (PFCNTL, prefetch_control, 0) }, - { FLDATA (PFADDR, prefetch_address, 0) }, + { DRDATA (SEQ, sequencer, 3) }, + { ORDATA (ORDER, order, 4) }, + { FLDATA (ROLOVR, rollover, 0) }, + { FLDATA (PFCNTL, prefetch_control, 0) }, + { FLDATA (PFADDR, prefetch_address, 0) }, - { ORDATA (BANK, bank, 4), PV_LEFT }, - { DRDATA (WCOUNT, word_count, 12) }, + { ORDATA (BANK, bank, 4), PV_LEFT }, + { DRDATA (WCOUNT, word_count, 12) }, - { ORDATA (PCNTR, program_counter, 16), REG_FIT }, - { ORDATA (CNTL, control_word, 16), REG_FIT }, - { ORDATA (CNBUF, control_buffer, 16), REG_FIT }, - { ORDATA (ADDR, address_word, 16), REG_FIT }, - { ORDATA (ADBUF, address_buffer, 16), REG_FIT }, - { ORDATA (INBUF, input_buffer, 16), REG_A | REG_FIT }, - { ORDATA (OUTBUF, output_buffer, 16), REG_A | REG_FIT }, + { ORDATA (PCNTR, program_counter, 16), REG_FIT }, + { ORDATA (CNTL, control_word, 16), REG_FIT }, + { ORDATA (CNBUF, control_buffer, 16), REG_FIT }, + { ORDATA (ADDR, address_word, 16), REG_FIT }, + { ORDATA (ADBUF, address_buffer, 16), REG_FIT }, + { ORDATA (INBUF, input_buffer, 16), REG_A | REG_FIT }, + { ORDATA (OUTBUF, output_buffer, 16), REG_A | REG_FIT }, { NULL } }; @@ -509,7 +514,10 @@ DEVICE sel_dev = { Implementation notes: - 1. In simulation, we allow the device number to be changed during a + 1. The active DIB pointer is restored from the device context to support + resuming after a SAVE and RESTORE is performed. + + 2. In simulation, we allow the device number to be changed during a simulation stop, so this routine must recover it from the device. Normally, the device number register would be reset from the device number field in the DIB. However, the SCMB may be spoofing the device @@ -526,7 +534,9 @@ void sel_initialize (void) SIGNALS_DATA outbound; if (sel_is_idle == FALSE) { /* if the channel is controlling a device */ - outbound = active_dib->io_interface (active_dib, DEVNODB, 0); /* then see if it responds to DEVNODB */ + active_dib = (DIB *) sim_devices [device_index]->ctxt; /* then restore the active DIB pointer */ + + outbound = active_dib->io_interface (active_dib, DEVNODB, 0); /* see if the device responds to DEVNODB */ if (IODATA (outbound) > 0) /* if it does (e.g., the SCMB) */ device_number = IODATA (outbound) / 4; /* then use the returned device number */ @@ -568,7 +578,7 @@ return; void sel_assert_REQ (DIB *dibptr) { if (sel_is_idle) { /* if the channel is idle then set it up */ - dprintf (sel_dev, DEB_CSRW, "Device number %d asserted REQ for channel initialization\n", + dprintf (sel_dev, DEB_CSRW, "Device number %u asserted REQ for channel initialization\n", dibptr->device_number); sel_is_idle = FALSE; /* the channel is now busy */ @@ -581,6 +591,11 @@ if (sel_is_idle) { /* if the channel is idl rollover = CLEAR; /* and the word count rollover flip-flop */ excess_cycles = 0; /* clear the excess cycle count */ + device_index = 0; /* find the device index */ + /* corresponding to */ + while ((DIB *) sim_devices [device_index]->ctxt != dibptr) /* the active DIB pointer */ + device_index = device_index + 1; /* to aid later restoration */ + active_dib = dibptr; /* save the interface's DIB pointer */ device_number = dibptr->device_number; /* and set the device number register */ @@ -589,7 +604,7 @@ if (sel_is_idle) { /* if the channel is idl } else { /* otherwise abort the transfer in progress */ - dprintf (sel_dev, DEB_CSRW, "Device number %d asserted REQ for channel abort\n", + dprintf (sel_dev, DEB_CSRW, "Device number %u asserted REQ for channel abort\n", device_number); end_channel (dibptr); /* idle the channel */ @@ -616,7 +631,7 @@ return; void sel_assert_CHANSR (DIB *dibptr) { -dprintf (sel_dev, DEB_SR, "Device number %d asserted CHANSR\n", +dprintf (sel_dev, DEB_SR, "Device number %u asserted CHANSR\n", device_number); dibptr->service_request = TRUE; /* set the service request flag in the interface */ @@ -780,7 +795,7 @@ return; void sel_service (uint32 ticks_elapsed) { -uint16 inbound_data, outbound_data; +HP_WORD inbound_data, outbound_data; INBOUND_SET inbound_signals; SIGNALS_DATA outbound; int32 cycles; @@ -888,7 +903,7 @@ while (sel_request && cycles > 0) { /* execute as long as a control_word); if ((outbound & CHANACK) == NO_SIGNALS) { /* if CHANACK was not returned */ - dprintf (sel_dev, DEB_SR, "Device number %d CHANACK timeout\n", + dprintf (sel_dev, DEB_SR, "Device number %u CHANACK timeout\n", device_number); end_channel (active_dib); /* terminate the channel program */ @@ -1267,7 +1282,7 @@ return; to complete the abort. */ -static SIGNALS_DATA abort_channel (char *reason) +static SIGNALS_DATA abort_channel (const char *reason) { dprintf (sel_dev, DEB_CSRW, "Channel asserted XFERERROR for %s\n", reason); diff --git a/HP3000/hp3000_sys.c b/HP3000/hp3000_sys.c index 6a826032..fb6e6271 100644 --- a/HP3000/hp3000_sys.c +++ b/HP3000/hp3000_sys.c @@ -23,7 +23,14 @@ in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the author. + 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 13-May-16 JDB Modified for revised SCP API function parameter types + 20-Apr-16 JDB Added implementation notes to "fmt_bitset" + 14-Apr-16 JDB Fixed INTMASK setting and display + 24-Mar-16 JDB Added the LP device + 21-Mar-16 JDB Changed uint16 types to HP_WORD 23-Nov-15 JDB First release version 11-Dec-12 JDB Created @@ -63,6 +70,7 @@ extern DEVICE scmb_dev [2]; /* Selector Channel Maintenance extern DEVICE atcd_dev; /* Asynchronous Terminal Controller TDI */ extern DEVICE atcc_dev; /* Asynchronous Terminal Controller TCI */ extern DEVICE clk_dev; /* System Clock */ +extern DEVICE lp_dev; /* Line Printer */ extern DEVICE ds_dev; /* 79xx MAC Disc */ extern DEVICE ms_dev; /* 7970 Magnetic Tape */ @@ -758,7 +766,7 @@ static t_stat hp_brk_cmd (int32 arg, CONST char *buf); static void fprint_value (FILE *ofile, t_value val, uint32 radix, uint32 width, uint32 format); static t_stat fprint_order (FILE *ofile, t_value *val, uint32 radix); static t_stat fprint_instruction (FILE *ofile, const OP_TABLE ops, t_value *instruction, - t_value mask, uint32 shift, uint32 radix); + uint32 mask, uint32 shift, uint32 radix); static t_stat parse_cpu (CONST char *cptr, t_addr address, UNIT *uptr, t_value *value, int32 switches); @@ -773,10 +781,10 @@ static APC_FLAGS parse_config = apcNone; /* address parser configuration /* System interface global data structures */ -#define E 0400 /* parity bit for even parity */ -#define O 0000 /* parity bit for odd parity */ +#define E 0400u /* parity bit for even parity */ +#define O 0000u /* parity bit for odd parity */ -const uint16 odd_parity [256] = { /* odd parity table */ +const HP_WORD odd_parity [256] = { /* odd parity table */ E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 000-017 */ O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 020-037 */ O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 040-067 */ @@ -861,6 +869,7 @@ DEVICE *sim_devices [] = { /* an array of pointers to the s &scmb_dev [0], &scmb_dev [1], /* Selector Channel Maintenance Boards */ &atcd_dev, &atcc_dev, /* Asynchronous Terminal Controller (TDI and TCI) */ &clk_dev, /* System Clock */ + &lp_dev, /* Line Printer */ &ds_dev, /* 7905/06/20/25 MAC Disc Interface */ &ms_dev, /* 7970B/E Magnetic Tape Interface */ NULL /* end of the device list */ @@ -1041,7 +1050,7 @@ uint32 radix_override; if (sw & SWMASK ('A') && (!is_reg || addr & REG_A)) /* if ASCII character display is requested and permitted */ if (val [0] <= D8_SMAX) { /* then if the value is a single character */ - fputs (fmt_char (val [0]), ofile); /* then format and print it */ + fputs (fmt_char ((uint32) val [0]), ofile); /* then format and print it */ return SCPE_OK; } @@ -1212,8 +1221,8 @@ else /* otherwise */ Implementation notes: 1. For a numeric interrupt mask entry value <n>, the value stored in the DIB - is 2^<n>. For mask entry values "D" and "E", the stored values are 0 and - 0177777, respectively. + is 2 ^ <15 - n> to match the HP 3000 bit numbering. For mask entry + values "D" and "E", the stored values are 0 and 0177777, respectively. 2. The SCMB is the only device that may or may not have a service request number, depending on whether or not it is connected to the multiplexer @@ -1252,8 +1261,8 @@ else /* otherwise a value is value = get_uint (cptr, INTMASK_BASE, /* parse the supplied numeric mask value */ INTMASK_MAX, &status); - if (status == SCPE_OK) /* if it is valid */ - dibptr->interrupt_mask = 1 << value; /* then set the corresponding mask bit in the DIB */ + if (status == SCPE_OK) /* if it is valid */ + dibptr->interrupt_mask = D16_SIGN >> value; /* then set the corresponding mask bit in the DIB */ } break; @@ -1308,8 +1317,8 @@ return status; /* return the validation Implementation notes: 1. For a numeric interrupt mask entry value <n>, the value stored in the DIB - is 2^<n>. For mask entry values "D" and "E", the stored values are 0 and - 0177777, respectively. + is 2 ^ <15 - n> to match the HP 3000 bit numbering. For mask entry + values "D" and "E", the stored values are 0 and 0177777, respectively. */ t_stat hp_show_dib (FILE *st, UNIT *uptr, int32 code, CONST void *desc) @@ -1320,7 +1329,7 @@ uint32 mask, value; switch (code) { /* display the requested value */ case VAL_DEVNO: /* show the device number */ - fprintf (st, "DEVNO=%d", dibptr->device_number); + fprintf (st, "DEVNO=%u", dibptr->device_number); break; case VAL_INTMASK: /* show the interrupt mask */ @@ -1335,22 +1344,22 @@ switch (code) { /* display the requested else { /* otherwise */ mask = dibptr->interrupt_mask; /* display a specific mask value */ - for (value = 0; !(mask & 1); value++) /* count the number of mask bit shifts */ - mask = mask >> 1; /* until the correct one is found */ + for (value = 0; !(mask & D16_SIGN); value++) /* count the number of mask bit shifts */ + mask = mask << 1; /* until the correct one is found */ - fprintf (st, "%d", value); /* display the mask bit number */ + fprintf (st, "%u", value); /* display the mask bit number */ } break; case VAL_INTPRI: /* show the interrupt priority */ - fprintf (st, "INTPRI=%d", dibptr->interrupt_priority); + fprintf (st, "INTPRI=%u", dibptr->interrupt_priority); break; case VAL_SRNO: /* show the service request number */ if (dibptr->service_request_number == SRNO_UNUSED) /* if the current setting is "unused" */ fprintf (st, "SRNO not used"); /* then report it */ else /* otherwise report the SR number */ - fprintf (st, "SRNO=%d", dibptr->service_request_number); + fprintf (st, "SRNO=%u", dibptr->service_request_number); break; default: /* if an illegal code was passed */ @@ -1502,7 +1511,7 @@ for (conf = Device; conf <= Service; conf++) { /* check for conflicts f if (conflicts [val] > 1) { /* if a conflict is present for this value */ count = conflicts [val]; /* then get the number of conflicting devices */ - cprintf ("%s %d conflict (", conflict_label [conf], val); + cprintf ("%s %u conflict (", conflict_label [conf], val); dev = 0; /* search for the devices that conflict */ @@ -1784,6 +1793,20 @@ else { /* otherwise it's a prin Processing continues until there are no remaining significant bits (if no alternates are specified), or until there are no remaining names in the array (if alternates are specified). + + + 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: + + dprintf (..., fmt_bitset (...), ..., fmt_bitset (...), ...); + + ...will fail, as the buffer will be overwritten by the second call before + the result of the first call is printed. + */ const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt) @@ -2042,7 +2065,7 @@ else if (reason == STOP_CDUMP) { /* otherwise if this is } else if (reason == STOP_SYSHALT) { /* otherwise if this is a system halt stop */ - fprintf (st, " %d", RA); /* then print the halt reason */ + fprintf (st, " %u", RA); /* then print the halt reason */ return TRUE; /* and return TRUE to append the program counter */ } @@ -2207,7 +2230,7 @@ static t_stat hp_cold_cmd (int32 arg, CONST char *buf) const char *cptr; char gbuf [CBUFSIZE]; t_stat status; -t_value value; +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 */ @@ -2215,8 +2238,8 @@ if (*buf != '\0') { /* if more characters ex if (*cptr != '\0') /* if that does not exhaust the input */ return SCPE_2MARG; /* then report that there are too many arguments */ - value = get_uint (gbuf, cpu_dev.dradix, /* get the parameter value */ - D16_UMAX, &status); + 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 */ @@ -2224,7 +2247,7 @@ if (*buf != '\0') { /* if more characters ex return status; /* return the error status */ } -cpu_front_panel (SWCH, arg); /* set up the cold load or dump microcode */ +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 */ } @@ -2596,17 +2619,17 @@ static const char *const register_name [] = { /* PSHR/SETR register names corr }; static t_stat fprint_instruction (FILE *ofile, const OP_TABLE ops, t_value *instruction, - t_value mask, uint32 shift, uint32 radix) + uint32 mask, uint32 shift, uint32 radix) { -uint32 op_index, op_radix; -int32 reg_index; -t_bool reg_first; -t_value op_value; -char *prefix = NULL; /* base register label to print before the operand */ -t_bool index = FALSE; /* TRUE if the instruction is indexed */ -t_bool indirect = FALSE; /* TRUE if the instruction is indirect */ +uint32 op_index, op_radix; +int32 reg_index; +t_bool reg_first; +t_value op_value; +const char *prefix = NULL; /* base register label to print before the operand */ +t_bool index = FALSE; /* TRUE if the instruction is indexed */ +t_bool indirect = FALSE; /* TRUE if the instruction is indirect */ -op_index = (instruction [0] & mask) >> shift; /* extract the opcode index */ +op_index = ((uint32) instruction [0] & mask) >> shift; /* extract the opcode index */ if (ops [op_index].mnemonic [0]) /* if a primary entry is defined */ fputs (ops [op_index].mnemonic, ofile); /* then print the mnemonic */ diff --git a/HP3000/hp_disclib.c b/HP3000/hp_disclib.c index 8b903d78..db240bdf 100644 --- a/HP3000/hp_disclib.c +++ b/HP3000/hp_disclib.c @@ -24,7 +24,13 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. + 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 13-May-16 JDB Modified for revised SCP API function parameter types + 03-May-16 JDB Added a trace to identify the unit requesting attention + 24-Mar-16 JDB Changed the buffer element type from uint16 to DL_BUFFER + 21-Mar-16 JDB Changed uint16 types to HP_WORD 27-Jul-15 JDB First revised release version 21-Feb-15 JDB Revised for new controller interface model 24-Dec-14 JDB Added casts for explicit downward conversions @@ -391,7 +397,7 @@ /* Unit flags accessor */ -#define GET_MODEL(f) (((f) >> UNIT_MODEL_SHIFT) & UNIT_MODEL_MASK) +#define GET_MODEL(f) (DRIVE_TYPE) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK) /* Controller clear types */ @@ -453,24 +459,24 @@ typedef enum { Form 6 is used by the Cold Load Read command. */ -#define CM_OPCODE_MASK 0017400 /* operation code mask */ -#define CM_UNIT_MASK 0000017 /* unit number mask */ +#define CM_OPCODE_MASK 0017400u /* operation code mask */ +#define CM_UNIT_MASK 0000017u /* unit number mask */ -#define CM_SPARE 0100000 /* spare track */ -#define CM_PROTECTED 0040000 /* protected track */ -#define CM_DEFECTIVE 0020000 /* defective track */ +#define CM_SPARE 0100000u /* spare track */ +#define CM_PROTECTED 0040000u /* protected track */ +#define CM_DEFECTIVE 0020000u /* defective track */ #define CM_SPD_MASK (CM_SPARE | CM_PROTECTED | CM_DEFECTIVE) -#define CM_RETRY_MASK 0000360 /* retry count mask */ -#define CM_FILE_MASK_MASK 0000017 /* file mask mask */ +#define CM_RETRY_MASK 0000360u /* retry count mask */ +#define CM_FILE_MASK_MASK 0000017u /* file mask mask */ -#define CM_DECR_SEEK 0000010 /* 0/1 = incremental/decremental seek */ -#define CM_SPARE_EN 0000004 /* sparing enabled */ -#define CM_CYL_MODE 0000002 /* 0/1 = surface/cylinder mode */ -#define CM_AUTO_SEEK_EN 0000001 /* auto-seek enabled */ +#define CM_DECR_SEEK 0000010u /* 0/1 = incremental/decremental seek */ +#define CM_SPARE_EN 0000004u /* sparing enabled */ +#define CM_CYL_MODE 0000002u /* 0/1 = surface/cylinder mode */ +#define CM_AUTO_SEEK_EN 0000001u /* auto-seek enabled */ -#define CM_HEAD_MASK 0000300 /* cold load read head mask */ -#define CM_SECTOR_MASK 0000077 /* cold load read sector mask */ +#define CM_HEAD_MASK 0000300u /* cold load read head mask */ +#define CM_SECTOR_MASK 0000077u /* cold load read sector mask */ #define CM_OPCODE_SHIFT 8 @@ -485,7 +491,8 @@ typedef enum { #define CM_SPD(c) ((c) & CM_SPD_MASK) -#define CM_OPCODE(c) (((c) & CM_OPCODE_MASK) >> CM_OPCODE_SHIFT) +#define CM_OPCODE(c) (CNTLR_OPCODE) (((c) & CM_OPCODE_MASK) >> CM_OPCODE_SHIFT) + #define CM_UNIT(c) (((c) & CM_UNIT_MASK) >> CM_UNIT_SHIFT) #define CM_RETRY(c) (((c) & CM_RETRY_MASK) >> CM_RETRY_SHIFT) @@ -572,11 +579,11 @@ static const BITSET_FORMAT file_mask_format = /* names, offset, direction, S = sign of cylinder offset */ -#define S1_SPARE 0100000 /* spare track */ -#define S1_PROTECTED 0040000 /* protected track */ -#define S1_DEFECTIVE 0020000 /* defective track */ -#define S1_STATUS_MASK 0017400 /* encoded termination status mask */ -#define S1_UNIT_MASK 0000017 /* unit number mask */ +#define S1_SPARE 0100000u /* spare track */ +#define S1_PROTECTED 0040000u /* protected track */ +#define S1_DEFECTIVE 0020000u /* defective track */ +#define S1_STATUS_MASK 0017400u /* encoded termination status mask */ +#define S1_UNIT_MASK 0000017u /* unit number mask */ #define S1_STATUS_SHIFT 8 #define S1_UNIT_SHIFT 0 @@ -585,16 +592,16 @@ static const BITSET_FORMAT file_mask_format = /* names, offset, direction, #define S1_UNIT(n) ((n) << S1_UNIT_SHIFT & S1_UNIT_MASK) -#define S2_ERROR 0100000 /* any error */ -#define S2_DRIVE_TYPE_MASK 0017000 /* drive type mask */ -#define S2_ATTENTION 0000200 /* attention */ -#define S2_READ_ONLY 0000100 /* read-only */ -#define S2_FORMAT_EN 0000040 /* format enabled */ -#define S2_FAULT 0000020 /* drive fault */ -#define S2_FIRST_STATUS 0000010 /* first status */ -#define S2_SEEK_CHECK 0000004 /* seek check */ -#define S2_NOT_READY 0000002 /* not ready */ -#define S2_BUSY 0000001 /* drive busy */ +#define S2_ERROR 0100000u /* any error */ +#define S2_DRIVE_TYPE_MASK 0017000u /* drive type mask */ +#define S2_ATTENTION 0000200u /* attention */ +#define S2_READ_ONLY 0000100u /* read-only */ +#define S2_FORMAT_EN 0000040u /* format enabled */ +#define S2_FAULT 0000020u /* drive fault */ +#define S2_FIRST_STATUS 0000010u /* first status */ +#define S2_SEEK_CHECK 0000004u /* seek check */ +#define S2_NOT_READY 0000002u /* not ready */ +#define S2_BUSY 0000001u /* drive busy */ #define S2_STOPS (S2_FAULT \ | S2_SEEK_CHECK \ @@ -616,13 +623,13 @@ static const BITSET_FORMAT file_mask_format = /* names, offset, direction, #define S2_TO_DRIVE_TYPE(n) (((n) & S2_DRIVE_TYPE_MASK) >> S2_DRIVE_TYPE_SHIFT) -#define PIO_HEAD_MASK 0017400 /* head mask */ -#define PIO_SECTOR_MASK 0000377 /* sector mask */ +#define PIO_HEAD_MASK 0017400u /* head mask */ +#define PIO_SECTOR_MASK 0000377u /* sector mask */ -#define PI_ADV_CLOCK 0001000 /* advance clock */ -#define PI_DEL_CLOCK 0000400 /* delay clock */ -#define PI_NEG_OFFSET 0000200 /* 0/1 = positive/negative cylinder offset sign */ -#define PI_OFFSET_MASK 0000077 /* cylinder offset mask */ +#define PI_ADV_CLOCK 0001000u /* advance clock */ +#define PI_DEL_CLOCK 0000400u /* delay clock */ +#define PI_NEG_OFFSET 0000200u /* 0/1 = positive/negative cylinder offset sign */ +#define PI_OFFSET_MASK 0000077u /* cylinder offset mask */ #define PIO_HEAD_SHIFT 8 @@ -724,13 +731,13 @@ static const BITSET_FORMAT offset_format = /* names, offset, direction, alt */ typedef struct { - char *name; /* drive name */ - uint32 sectors; /* sectors per head */ - uint32 heads; /* heads per cylinder*/ - uint32 cylinders; /* cylinders per drive */ - uint32 words; /* words per drive */ - uint32 remov_heads; /* number of removable-platter heads */ - uint32 fixed_heads; /* number of fixed-platter heads */ + const char *name; /* drive name */ + uint32 sectors; /* sectors per head */ + uint32 heads; /* heads per cylinder*/ + uint32 cylinders; /* cylinders per drive */ + uint32 words; /* words per drive */ + uint32 remov_heads; /* number of removable-platter heads */ + uint32 fixed_heads; /* number of fixed-platter heads */ } DRIVE_PROPS; static const DRIVE_PROPS drive_props [] = { /* indexed by DRIVE_TYPE */ @@ -1276,12 +1283,12 @@ static void idle_controller (CVPTR cvptr); /* Disc library local utility routines */ -static void set_address (CVPTR cvptr, uint32 index); -static void wait_timer (CVPTR cvptr, FLIP_FLOP action); -static uint16 drive_status (UNIT *uptr); -static t_stat activate_unit (CVPTR cvptr, UNIT *uptr); -static void set_rotation (CVPTR cvptr, UNIT *uptr); -static void set_file_pos (CVPTR cvptr, UNIT *uptr, uint32 model); +static void set_address (CVPTR cvptr, uint32 index); +static void wait_timer (CVPTR cvptr, FLIP_FLOP action); +static HP_WORD drive_status (UNIT *uptr); +static t_stat activate_unit (CVPTR cvptr, UNIT *uptr); +static void set_rotation (CVPTR cvptr, UNIT *uptr); +static void set_file_pos (CVPTR cvptr, UNIT *uptr, uint32 model); @@ -1519,7 +1526,8 @@ return outbound; 6. ECC is not simulated, so the Request Syndrome command always returns zero values for the displacement and patterns and Uncorrectable Data Error for - the status, unless a diagnostic override is in effect. + the status. Correctable Data Error status cannot occur unless a + diagnostic override is in effect. 7. The Wakeup command references a drive unit but is scheduled on the controller unit because it may be issued while the drive is seeking. @@ -1533,6 +1541,7 @@ 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 */ @@ -1566,21 +1575,24 @@ else { /* otherwise this is an cvptr->device->units + cvptr->poll_unit; /* when the controller structure was initialized */ } -dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command started\n", +dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command started\n", unit, opcode_name [cvptr->opcode]); +if (cvptr->dop_index >= 0) /* if the diagnostic override table is defined */ + dop = cvptr->dop_base + cvptr->dop_index; /* then point at the current entry */ -if (cvptr->dop /* if the diagnostic override table is defined */ - && cvptr->dop->cylinder == cvptr->cylinder /* and the cylinder, */ - && cvptr->dop->head == cvptr->head /* head, */ - && cvptr->dop->sector == cvptr->sector /* sector, */ - && cvptr->dop->opcode == cvptr->opcode) { /* and opcode values match the current values */ - cvptr->spd_unit = cvptr->dop->spd | unit; /* then override the Spare/Protected/Defective */ - cvptr->status = cvptr->dop->status; /* and status values from the override entry */ +if (dop /* if the table entry exists */ + && dop->cylinder == cvptr->cylinder /* and the cylinder, */ + && dop->head == cvptr->head /* head, */ + && dop->sector == cvptr->sector /* sector, */ + && dop->opcode == cvptr->opcode) { /* and opcode values match the current values */ + cvptr->spd_unit = dop->spd | unit; /* then override the Spare/Protected/Defective */ + cvptr->status = dop->status; /* and status values from the override entry */ - cvptr->dop++; /* point at the next table entry */ + cvptr->dop_index++; /* point at the */ + dop++; /* next table entry */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d cylinder %d head %d sector %d diagnostic override\n", + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u cylinder %u head %u sector %u diagnostic override\n", unit, cvptr->cylinder, cvptr->head, cvptr->sector); } @@ -1634,13 +1646,13 @@ else { /* otherwise the command if (start_seek (cvptr, duptr) == FALSE) /* start the seek; if it failed */ set_completion (cvptr, cuptr, Status_2_Error); /* then set up the completion status */ - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s from cylinder %d head %d sector %d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s from cylinder %u head %u sector %u\n", unit, opcode_name [Cold_Load_Read], cvptr->cylinder, cvptr->head, cvptr->sector); break; /* wait for seek completion */ case Recalibrate: - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s to cylinder 0\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s to cylinder 0\n", unit, opcode_name [Recalibrate]); if (duptr->PHASE == Seek_Phase) { /* if the unit is currently seeking */ @@ -1649,7 +1661,7 @@ else { /* otherwise the command sim_cancel (duptr); /* cancel the event to allow rescheduling */ duptr->PHASE = Idle_Phase; /* and idle the drive so that the seek succeeds */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command waiting for seek completion\n", + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n", unit, opcode_name [Recalibrate]); } @@ -1667,7 +1679,7 @@ else { /* otherwise the command case Request_Status: - cvptr->buffer [0] = (uint16) (cvptr->spd_unit /* set the Status-1 value */ + cvptr->buffer [0] = (DL_BUFFER) (cvptr->spd_unit /* set the Status-1 value */ | S1_STATUS (cvptr->status)); /* into the buffer */ if (cvptr->type == MAC) /* if this a MAC controller */ @@ -1678,9 +1690,9 @@ else { /* otherwise the command else /* otherwise it is not a MAC controller */ rptr = duptr; /* so the referenced unit is the current unit */ - cvptr->buffer [1] = drive_status (rptr); /* set the Status-2 value into the buffer */ + cvptr->buffer [1] = (DL_BUFFER) drive_status (rptr); /* set the Status-2 value into the buffer */ - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s returns %sunit %d | %s and %s%s | %s\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns %sunit %u | %s and %s%s | %s\n", unit, opcode_name [Request_Status], strcpy (s1_buffer, fmt_bitset (cvptr->spd_unit, status_1_format)), CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status), @@ -1706,9 +1718,9 @@ else { /* otherwise the command else /* otherwise the drive is ready */ cvptr->buffer [0] = /* so calculate the current sector address */ - (uint16) CURRENT_SECTOR (cvptr, duptr); + (DL_BUFFER) CURRENT_SECTOR (cvptr, duptr); - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s returns sector %d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns sector %u\n", unit, opcode_name [Request_Sector_Address], cvptr->buffer [0]); break; @@ -1722,13 +1734,14 @@ else { /* otherwise the command case Request_Syndrome: - if (cvptr->status == Correctable_Data_Error) { /* if we've been called with a correction override */ - cvptr->buffer [3] = (uint16) cvptr->dop->spd; /* then load the displacement */ - cvptr->buffer [4] = (uint16) cvptr->dop->cylinder; /* and three */ - cvptr->buffer [5] = (uint16) cvptr->dop->head; /* syndrome words */ - cvptr->buffer [6] = (uint16) cvptr->dop->sector; /* from the override entry */ + if (cvptr->status == Correctable_Data_Error) { /* if this is a correction override */ + cvptr->buffer [3] = (DL_BUFFER) dop->spd; /* then load the displacement */ + cvptr->buffer [4] = (DL_BUFFER) dop->cylinder; /* and three */ + cvptr->buffer [5] = (DL_BUFFER) dop->head; /* syndrome words */ + cvptr->buffer [6] = (DL_BUFFER) dop->sector; /* from the override entry */ - cvptr->dop++; /* point at the next entry */ + cvptr->dop_index++; /* point at the */ + dop++; /* next table entry */ } else { /* otherwise no correction data was supplied */ @@ -1741,12 +1754,12 @@ else { /* otherwise the command cvptr->status = Uncorrectable_Data_Error; /* then presume that an uncorrectable error occurred */ } - cvptr->buffer [0] = (uint16) (cvptr->spd_unit /* save the Status-1 value */ + cvptr->buffer [0] = (DL_BUFFER) (cvptr->spd_unit /* save the Status-1 value */ | S1_STATUS (cvptr->status)); /* in the buffer */ set_address (cvptr, 1); /* save the CHS values in the buffer */ - dpprintf (cvptr->device, DL_DEB_CMD, "%s returns %sunit %d | %s | cylinder %d head %d sector %d | " + dpprintf (cvptr->device, DL_DEB_CMD, "%s returns %sunit %u | %s | cylinder %u head %u sector %u | " "syndrome %06o %06o %06o %06o\n", opcode_name [Request_Syndrome], fmt_bitset (cvptr->spd_unit, status_1_format), CM_UNIT (cvptr->spd_unit), dl_status_name (cvptr->status), @@ -1765,7 +1778,7 @@ else { /* otherwise the command set_completion (cvptr, cuptr, Normal_Completion); /* schedule the command completion */ - dpprintf (cvptr->device, DL_DEB_CMD, "%s to %sretries %d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "%s to %sretries %u\n", opcode_name [Set_File_Mask], fmt_bitset (cvptr->file_mask, file_mask_format), CM_RETRY (inbound_data)); break; @@ -1774,7 +1787,7 @@ else { /* otherwise the command case Request_Disc_Address: set_address (cvptr, 0); /* set the controller's CHS values into the buffer */ - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s returns cylinder %d head %d sector %d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s returns cylinder %u head %u sector %u\n", unit, opcode_name [Request_Disc_Address], cvptr->cylinder, cvptr->head, cvptr->sector); break; @@ -1789,7 +1802,7 @@ else { /* otherwise the command case Wakeup: set_completion (cvptr, cuptr, Unit_Available); /* schedule the command completion */ - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s\n", unit, opcode_name [Wakeup]); break; @@ -1812,7 +1825,7 @@ else { /* otherwise the command case Write: case Write_Full_Sector: if (duptr->PHASE == Seek_Phase) /* if the unit is currently seeking */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command waiting for seek completion\n", + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n", unit, opcode_name [cvptr->opcode]); else /* otherwise the unit is idle */ @@ -1978,7 +1991,7 @@ return outbound; /* return the data word Implementation notes: - 1. The "%.0d" print specification in the trace call absorbs the zero "unit" + 1. The "%.0u" print specification in the trace call absorbs the zero "unit" value parameter without printing when the controller unit is specified. 2. The Seek command does not check for Access Not Ready before issuing the @@ -2040,10 +2053,11 @@ CNTLR_OPCODE opcode; CNTLR_PHASE phase; CNTLR_IFN_IBUS outbound; t_bool controller_service, controller_was_busy; -uint32 unit, sector_count; +int32 unit; +uint32 sector_count; if (service_entry) { /* if this is an event service entry */ - unit = uptr - cvptr->device->units; /* then get the unit number */ + unit = (int32) (uptr - cvptr->device->units); /* then get the unit number */ controller_service = (uptr == CNTLR_UPTR /* set TRUE if the controller is being serviced */ && cvptr->type == MAC); @@ -2091,7 +2105,7 @@ switch (phase) { /* dispatch the phase */ outbound = NO_FUNCTIONS; /* clear the function set for an idle return */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command aborted with parameter wait timeout\n", + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command aborted with parameter wait timeout\n", CM_UNIT (cvptr->spd_unit), opcode_name [opcode]); } @@ -2115,7 +2129,8 @@ switch (phase) { /* dispatch the phase */ case Seek: /* these commands receive parameters */ case Address_Record: /* from the interface */ - cvptr->buffer [cvptr->index++] = inbound_data; /* save the current one in the buffer */ + cvptr->buffer [cvptr->index++] = /* save the current one in the buffer */ + (DL_BUFFER) inbound_data; cvptr->length = cvptr->length - 1; /* and drop the parameter count */ if (cvptr->length > 0) /* if another parameter is expected */ @@ -2129,7 +2144,7 @@ switch (phase) { /* dispatch the phase */ if (opcode == Address_Record) { /* if this is an Address Record command */ cvptr->eoc = CLEAR; /* then clear the end-of-cylinder flag */ - dpprintf (cvptr->device, DL_DEB_CMD, "%s to cylinder %d head %d sector %d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "%s to cylinder %u head %u sector %u\n", opcode_name [Address_Record], cvptr->cylinder, cvptr->head, cvptr->sector); @@ -2138,7 +2153,7 @@ switch (phase) { /* dispatch the phase */ } else { /* otherwise it's a Seek command */ - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s to cylinder %d head %d sector %d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s to cylinder %u head %u sector %u\n", CM_UNIT (cvptr->spd_unit), opcode_name [Seek], cvptr->cylinder, cvptr->head, cvptr->sector); @@ -2165,7 +2180,7 @@ switch (phase) { /* dispatch the phase */ cvptr->count = sector_count * WORDS_PER_SECTOR; /* convert to the number of words to verify */ - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s %d sector%s\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s %u sector%s\n", CM_UNIT (cvptr->spd_unit), opcode_name [Verify], sector_count, (sector_count == 1 ? "" : "s")); @@ -2177,7 +2192,7 @@ switch (phase) { /* dispatch the phase */ if (uptr->PHASE == Seek_Phase) { /* if a seek is in progress, */ uptr->wait = NO_EVENT; /* then wait for it to complete */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command waiting for seek completion\n", + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n", CM_UNIT (cvptr->spd_unit), opcode_name [Verify]); } @@ -2187,11 +2202,11 @@ switch (phase) { /* dispatch the phase */ case Read_With_Offset: - dpprintf (cvptr->device, DL_DEB_CMD, "Unit %d %s using %soffset %+d\n", + dpprintf (cvptr->device, DL_DEB_CMD, "Unit %u %s using %soffset %+d\n", CM_UNIT (cvptr->spd_unit), opcode_name [Read_With_Offset], fmt_bitset (inbound_data, offset_format), (inbound_data & PI_NEG_OFFSET ? - (int) PI_OFFSET (inbound_data) - : PI_OFFSET (inbound_data))); + : (int) PI_OFFSET (inbound_data))); wait_timer (cvptr, CLEAR); /* stop the parameter timer */ @@ -2201,7 +2216,7 @@ switch (phase) { /* dispatch the phase */ if (uptr->PHASE == Seek_Phase) { /* if a seek is in progress, */ uptr->wait = NO_EVENT; /* then wait for it to complete */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command waiting for seek completion\n", + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command waiting for seek completion\n", CM_UNIT (cvptr->spd_unit), opcode_name [Read_With_Offset]); } @@ -2313,7 +2328,7 @@ switch (phase) { /* dispatch the phase */ cvptr->count = cvptr->count + 1; /* count the */ cvptr->length = cvptr->length - 1; /* transfer */ - dpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %d is %06o\n", + dpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %u is %06o\n", unit, opcode_name [opcode], cvptr->count, DLIBUS (outbound)); } @@ -2333,13 +2348,14 @@ switch (phase) { /* dispatch the phase */ case Write: case Write_Full_Sector: case Initialize: - if ((inbound_flags & EOD) == NO_FLAGS) { /* if the transfer continues */ - cvptr->buffer [cvptr->index++] = inbound_data; /* then store the next word in the buffer */ + if ((inbound_flags & EOD) == NO_FLAGS) { /* if the transfer continues */ + cvptr->buffer [cvptr->index++] = /* then store the next word in the buffer */ + (DL_BUFFER) inbound_data; - cvptr->count = cvptr->count + 1; /* count the */ - cvptr->length = cvptr->length - 1; /* transfer */ + cvptr->count = cvptr->count + 1; /* count the */ + cvptr->length = cvptr->length - 1; /* transfer */ - dpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %d is %06o\n", + dpprintf (cvptr->device, DL_DEB_XFER, "Unit %d %s word %u is %06o\n", unit, opcode_name [opcode], cvptr->count, inbound_data); } @@ -2462,8 +2478,12 @@ for (unit = 0; unit <= DL_MAXDRIVE; unit++) { /* check each unit in tu if (units [cvptr->poll_unit].STATUS & S2_ATTENTION) { /* if the unit is requesting attention, */ units [cvptr->poll_unit].STATUS &= ~S2_ATTENTION; /* clear the Attention status */ - cvptr->spd_unit = cvptr->poll_unit; /* set the controller's unit number */ - cvptr->status = Drive_Attention; /* and status */ + + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u requested attention\n", + cvptr->poll_unit); + + cvptr->spd_unit = cvptr->poll_unit; /* set the controller's unit number */ + cvptr->status = Drive_Attention; /* and status */ cvptr->state = Wait_State; /* set the controller state to waiting */ wait_timer (cvptr, SET); /* start the command wait timer */ @@ -2681,6 +2701,13 @@ else /* otherwise the status The file specified by the supplied filename is attached to the indicated unit. If the attach was successful, the heads are loaded on the drive. + + + Implementation notes: + + 1. The pointer to the appropriate event delay times is set in case we are + being called during a RESTORE command (the assignment is redundant + otherwise). */ t_stat dl_attach (CVPTR cvptr, UNIT *uptr, CONST char *cptr) @@ -2692,6 +2719,10 @@ result = attach_unit (uptr, cptr); /* attach the unit * if (result == SCPE_OK) /* if the attach succeeded */ result = dl_load_unload (cvptr, uptr, TRUE); /* then load the heads */ +dl_set_timing (cvptr->device->units, /* reestablish */ + (cvptr->device->flags & DEV_REALTIME), /* the delay times */ + NULL, (void *) cvptr); /* pointer(s) */ + return result; /* return the command result status */ } @@ -3023,7 +3054,7 @@ else if (value == 0) /* otherwise if this is return SCPE_2MARG; /* then report an error */ else { /* otherwise the command is valid */ - cvptr->dop = NULL; /* so clear the current entry pointer */ + cvptr->dop_index = -1; /* so clear the current entry pointer */ cvptr->dop_base->cylinder = DL_OVEND; /* and mark the first entry as the end */ } @@ -3031,7 +3062,7 @@ else if (cptr == NULL) /* otherwise if DIAG is if (cvptr->dop_base->cylinder == DL_OVEND) /* then if there are no entries in the table */ return SCPE_MISVAL; /* then one must be entered first */ else /* otherwise */ - cvptr->dop = cvptr->dop_base; /* reset the current pointer to the first entry */ + cvptr->dop_index = 0; /* reset the current pointer to the first entry */ else if (*cptr == '\0') /* otherwise if there are no parameters */ return SCPE_MISVAL; /* then report a missing value */ @@ -3123,7 +3154,7 @@ else { /* otherwise at least on entry++; /* point at the next available entry */ entry->cylinder = DL_OVEND; /* and mark it as the end of the list */ - cvptr->dop = cvptr->dop_base; /* reset the current pointer to the start of the list */ + cvptr->dop_index = 0; /* reset the current pointer to the start of the list */ } } @@ -3173,7 +3204,7 @@ DIAG_ENTRY *entry; if (cvptr->dop_base == NULL) /* if the table isn't defined */ return SCPE_NOFNC; /* then the command is illegal */ -else if (cvptr->dop == NULL) { /* otherwise if overrides are currently disabled */ +else if (cvptr->dop_index < 0) { /* otherwise if overrides are currently disabled */ fputs ("override disabled", st); /* then report it */ if (value > 0) /* if we were invoked by a SHOW DIAG command */ @@ -3213,12 +3244,12 @@ return SCPE_OK; This validation routine is called to set the timing mode for the disc subsystem. As this is an extended MTAB call, the "uptr" parameter points to - the unit array of the device. The "value" parameter is set to 1 to use + the unit array of the device. The "value" parameter is set non-zero to use realistic timing and 0 to use fast timing. For a MAC controller, the "desc" parameter is a pointer to the controller. For ICD controllers, the "desc" parameter is a pointer to the first element of the controller array. There must be one controller for each unit defined by the device associated with - the controllers. + the controllers. The "cptr" parameter is not used. If fast timing is selected, the controller's timing pointer is set to the fast timing pointer supplied by the interface when the controller was @@ -3239,7 +3270,7 @@ t_stat dl_set_timing (UNIT *uptr, int32 value, CONST char *cptr, void *desc) { CVPTR cvptr = (CVPTR) desc; /* the controller pointer is supplied */ const DELAY_PROPS *dpptr; -int32 model; +DRIVE_TYPE model; uint32 delay, cntlr_count; if (cvptr->type == MAC) /* if this is a MAC controller */ @@ -3254,7 +3285,7 @@ while (cntlr_count--) { /* set each controller's for (delay = 0; delay < DELAY_COUNT; delay++) /* search for the correct set of times */ if (dpptr->type == cvptr->type /* if the controller types match */ - && (dpptr->drive == HP_All /* and the drive times are identical */ + && (dpptr->drive == HP_All /* and all drive times are the same */ || dpptr->drive == model)) { /* or the drive types match as well */ cvptr->dlyptr = dpptr; /* then use this set of times */ break; @@ -3392,8 +3423,8 @@ else { /* otherwise */ if (cmd_props [cvptr->opcode].transfer_size > 0) dpprintf (cvptr->device, DL_DEB_CMD, (cvptr->opcode == Initialize - ? "Unit %d Initialize %s for %d words (%d sector%s)\n" - : "Unit %d %s for %d words (%d sector%s)\n"), + ? "Unit %u Initialize %s for %u words (%u sector%s)\n" + : "Unit %u %s for %u words (%u sector%s)\n"), CM_UNIT (cvptr->spd_unit), (cvptr->opcode == Initialize ? fmt_bitset (cvptr->spd_unit, initialize_format) @@ -3402,7 +3433,7 @@ if (cmd_props [cvptr->opcode].transfer_size > 0) cvptr->count / cmd_props [cvptr->opcode].transfer_size + (cvptr->length > 0), (cvptr->count <= cmd_props [cvptr->opcode].transfer_size ? "" : "s")); -dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s command completed with %s status\n", +dpprintf (cvptr->device, DL_DEB_INCO, "Unit %u %s command completed with %s status\n", CM_UNIT (cvptr->spd_unit), opcode_name [cvptr->opcode], dl_status_name (cvptr->status)); @@ -3486,13 +3517,13 @@ else /* otherwise it's a norm if (position_sector (cvptr, uptr) == FALSE) /* position the sector; if it was not */ return FALSE; /* then a seek is in progress or an error occurred */ -dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s from cylinder %d head %d sector %d\n", - uptr - cvptr->device->units, opcode_name [opcode], +dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s from cylinder %u head %u sector %u\n", + (int32) (uptr - cvptr->device->units), opcode_name [opcode], uptr->CYL, cvptr->head, cvptr->sector); count = sim_fread (cvptr->buffer + offset, /* read the sector from the image */ - sizeof (uint16), WORDS_PER_SECTOR, /* into the sector buffer */ - uptr->fileref); + sizeof (DL_BUFFER), /* into the sector buffer */ + 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 */ @@ -3657,8 +3688,8 @@ else if (position_sector (cvptr, uptr) == TRUE) { /* otherwise if position cvptr->length = cmd_props [opcode].transfer_size; /* then set the appropriate transfer length */ cvptr->index = 0; /* and reset the data index */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s to cylinder %d head %d sector %d\n", - uptr - cvptr->device->units, opcode_name [opcode], + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s to cylinder %u head %u sector %u\n", + (int32) (uptr - cvptr->device->units), opcode_name [opcode], uptr->CYL, cvptr->head, cvptr->sector); return TRUE; /* the write was successfully started */ @@ -3708,7 +3739,7 @@ return FALSE; /* otherwise an error oc static void end_write (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags) { uint32 count; -uint16 pad; +DL_BUFFER pad; const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE; const uint32 offset = (opcode == Write_Full_Sector ? 3 : 0); @@ -3727,7 +3758,7 @@ if (cvptr->index < WORDS_PER_SECTOR + offset) { /* if a partial sector w cvptr->buffer [count] = pad; /* pad the sector buffer as needed */ } -sim_fwrite (cvptr->buffer + offset, sizeof (uint16), /* write the sector to the file */ +sim_fwrite (cvptr->buffer + offset, sizeof (DL_BUFFER), /* write the sector to the file */ WORDS_PER_SECTOR, uptr->fileref); if (ferror (uptr->fileref)) /* if a host file system error occurred, then report it */ @@ -3810,7 +3841,7 @@ return; static t_bool position_sector (CVPTR cvptr, UNIT *uptr) { -const uint32 model = GET_MODEL (uptr->flags); /* get the drive model */ +const DRIVE_TYPE model = GET_MODEL (uptr->flags); /* get the drive model */ if (cvptr->status != Normal_Completion /* if a diagnostic override is present */ && cvptr->status != Uncorrectable_Data_Error /* and it's not */ @@ -3826,8 +3857,8 @@ else if (cvptr->eoc == SET) /* otherwise if start_seek (cvptr, uptr); /* start the auto-seek */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s autoseek to cylinder %d head %d sector %d\n", - uptr - cvptr->device->units, opcode_name [uptr->OPCODE], + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s autoseek to cylinder %u head %u sector %u\n", + (int32) (uptr - cvptr->device->units), opcode_name [uptr->OPCODE], (uptr->STATUS & S2_SEEK_CHECK ? " seek check on" : ""), cvptr->cylinder, cvptr->head, cvptr->sector); @@ -3845,8 +3876,8 @@ else if (cvptr->verify /* if address verifi && (uint32) uptr->CYL != cvptr->cylinder) { /* and the positioner is on the wrong cylinder */ start_seek (cvptr, uptr); /* then start a seek to the correct cylinder */ - dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s reseek to cylinder %d head %d sector %d\n", - uptr - cvptr->device->units, opcode_name [uptr->OPCODE], + dpprintf (cvptr->device, DL_DEB_INCO, "Unit %d %s%s reseek to cylinder %u head %u sector %u\n", + (int32) (uptr - cvptr->device->units), opcode_name [uptr->OPCODE], (uptr->STATUS & S2_SEEK_CHECK ? " seek check on" : ""), cvptr->cylinder, cvptr->head, cvptr->sector); @@ -3911,7 +3942,7 @@ return FALSE; /* positioning failed or static void next_sector (CVPTR cvptr, UNIT *uptr) { -const uint32 model = GET_MODEL (uptr->flags); /* get the disc model */ +const DRIVE_TYPE model = GET_MODEL (uptr->flags); /* get the disc model */ cvptr->sector = cvptr->sector + 1; /* increment the sector number */ @@ -3995,7 +4026,7 @@ static t_bool start_seek (CVPTR cvptr, UNIT *uptr) { int32 delta; uint32 target_cylinder; -const uint32 model = GET_MODEL (uptr->flags); /* get the drive model */ +const DRIVE_TYPE model = GET_MODEL (uptr->flags); /* get the drive model */ if (uptr->flags & UNIT_UNLOAD) /* if the heads are unloaded */ return FALSE; /* then the seek fails as the drive was not ready */ @@ -4112,10 +4143,10 @@ return; static void set_address (CVPTR cvptr, uint32 index) { cvptr->buffer [index] = /* update the cylinder if EOC is set */ - (uint16) cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0); + (DL_BUFFER) cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0); cvptr->buffer [index + 1] = /* merge the head and sector */ - (uint16) (PO_HEAD (cvptr->head) | PO_SECTOR (cvptr->sector)); + (DL_BUFFER) (PO_HEAD (cvptr->head) | PO_SECTOR (cvptr->sector)); return; } @@ -4153,15 +4184,15 @@ return; respectively, when status is returned. */ -static uint16 drive_status (UNIT *uptr) +static HP_WORD drive_status (UNIT *uptr) { -uint16 status; +HP_WORD status; if (uptr == NULL) /* if the unit is invalid */ return S2_ERROR | S2_NOT_READY; /* then it does not respond */ status = /* start with the drive type and unit status */ - (uint16) (S2_DRIVE_TYPE (GET_MODEL (uptr->flags)) | uptr->STATUS); + S2_DRIVE_TYPE (GET_MODEL (uptr->flags)) | uptr->STATUS; if (uptr->flags & UNIT_FMT) /* if the format switch is enabled */ status |= S2_FORMAT_EN; /* then set the Format status bit */ @@ -4190,14 +4221,14 @@ return status; /* return the unit statu Implementation notes: - 1. The "%.0d" print specification in the trace call absorbs the zero "unit" + 1. The "%.0u" print specification in the trace call absorbs the zero "unit" value parameter without printing when the controller unit is specified. */ static t_stat activate_unit (CVPTR cvptr, UNIT *uptr) { t_stat result; -uint32 unit = uptr - cvptr->device->units; +const int32 unit = (int32) (uptr - cvptr->device->units); /* the unit number */ dpprintf (cvptr->device, DL_DEB_SERV, (unit == CNTLR_UNIT ? "Controller unit%.0d %s %s phase delay %d service scheduled\n" @@ -4292,7 +4323,7 @@ else /* otherwise the + cvptr->head - drive_props [model].remov_heads; /* by the size of the removable platter */ uptr->pos = (track * drive_props [model].sectors + cvptr->sector) /* set the byte offset in the file */ - * WORDS_PER_SECTOR * sizeof (uint16); /* of the CHS target sector */ + * WORDS_PER_SECTOR * sizeof (DL_BUFFER); /* of the CHS target sector */ return; } diff --git a/HP3000/hp_disclib.h b/HP3000/hp_disclib.h index d54634ea..4414ae3a 100644 --- a/HP3000/hp_disclib.h +++ b/HP3000/hp_disclib.h @@ -25,6 +25,8 @@ this Software without prior written authorization from the authors. 13-May-16 JDB Modified for revised SCP API function parameter types + 24-Mar-16 JDB Added the DL_BUFFER type to define the disc buffer array + 21-Mar-16 JDB Changed uint16 types to HP_WORD 27-Jul-15 JDB First revised release version 21-Feb-15 JDB Revised for new controller interface model 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash @@ -44,6 +46,15 @@ +/* Architectural constants. + + The type of the disc buffer element is defined. This must be a 16-bit array + for the file representation to be packed. +*/ + +typedef uint16 DL_BUFFER; /* a buffer containing 16-bit disc data words */ + + /* Program limits */ #define DL_MAXDRIVE 7 /* last valid drive number */ @@ -61,12 +72,12 @@ /* Debug flags */ -#define DL_DEB_CMD (1 << 0) /* trace controller commands */ -#define DL_DEB_INCO (1 << 1) /* trace command initiations and completions */ -#define DL_DEB_STATE (1 << 2) /* trace command execution state changes */ -#define DL_DEB_SERV (1 << 3) /* trace unit service scheduling calls */ -#define DL_DEB_XFER (1 << 4) /* trace data reads and writes */ -#define DL_DEB_IOB (1 << 5) /* trace I/O bus signals and data words */ +#define DL_DEB_CMD (1u << 0) /* trace controller commands */ +#define DL_DEB_INCO (1u << 1) /* trace command initiations and completions */ +#define DL_DEB_STATE (1u << 2) /* trace command execution state changes */ +#define DL_DEB_SERV (1u << 3) /* trace unit service scheduling calls */ +#define DL_DEB_XFER (1u << 4) /* trace data reads and writes */ +#define DL_DEB_IOB (1u << 5) /* trace I/O bus signals and data words */ #define DL_DEB_V_UF 6 /* first free debug flag bit */ @@ -82,7 +93,7 @@ #define DEV_REALTIME_SHIFT (DEV_V_UF + 0) /* bits 0-0: timing mode is realistic */ -#define DEV_REALTIME (1 << DEV_REALTIME_SHIFT) /* realistic timing flag */ +#define DEV_REALTIME (1u << DEV_REALTIME_SHIFT) /* realistic timing flag */ /* Unit flags and accessors */ @@ -93,15 +104,15 @@ #define UNIT_FMT_SHIFT (UNIT_V_UF + 5) /* bits 5-5: format enabled */ #define DL_V_UF (UNIT_V_UF + 6) /* first free unit flag bit */ -#define UNIT_MODEL_MASK 0000003 /* model ID mask */ -#define UNIT_PROT_MASK 0000003 /* head protection mask */ +#define UNIT_MODEL_MASK 0000003u /* model ID mask */ +#define UNIT_PROT_MASK 0000003u /* head protection mask */ #define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT) #define UNIT_PROT (UNIT_PROT_MASK << UNIT_PROT_SHIFT) -#define UNIT_PROT_L (1 << UNIT_PROT_SHIFT + 0) -#define UNIT_PROT_U (1 << UNIT_PROT_SHIFT + 1) -#define UNIT_UNLOAD (1 << UNIT_UNLOAD_SHIFT) -#define UNIT_FMT (1 << UNIT_FMT_SHIFT) +#define UNIT_PROT_L (1u << UNIT_PROT_SHIFT + 0) +#define UNIT_PROT_U (1u << UNIT_PROT_SHIFT + 1) +#define UNIT_UNLOAD (1u << UNIT_UNLOAD_SHIFT) +#define UNIT_FMT (1u << UNIT_FMT_SHIFT) #define UNIT_7905 (HP_7905 << UNIT_MODEL_SHIFT) #define UNIT_7906 (HP_7906 << UNIT_MODEL_SHIFT) @@ -187,35 +198,35 @@ typedef enum { */ typedef enum { /* interface flags */ - CLEARF = 0000001, - CMRDY = 0000002, - DTRDY = 0000004, - EOD = 0000010, - INTOK = 0000020, - OVRUN = 0000040, - XFRNG = 0000100 + CLEARF = 0000001, /* Clear Controller */ + CMRDY = 0000002, /* Command Ready */ + DTRDY = 0000004, /* Data Ready */ + EOD = 0000010, /* End of Data */ + INTOK = 0000020, /* Interrupt OK */ + OVRUN = 0000040, /* Data Overrun */ + XFRNG = 0000100 /* Data Transfer No Good */ } CNTLR_FLAG; -#define NO_FLAGS ((CNTLR_FLAG) 0) /* no flags are asserted */ +#define NO_FLAGS ((CNTLR_FLAG) 0) /* no flags are asserted */ -typedef CNTLR_FLAG CNTLR_FLAG_SET; /* a set of CNTLR_FLAGs */ +typedef CNTLR_FLAG CNTLR_FLAG_SET; /* a set of CNTLR_FLAGs */ typedef enum { /* interface function bus orders */ - BUSY = 000000200000, - DSCIF = 000000400000, - SELIF = 000001000000, - IFIN = 000002000000, - IFOUT = 000004000000, - IFGTC = 000010000000, - IFPRF = 000020000000, - RQSRV = 000040000000, - DVEND = 000100000000, - SRTRY = 000200000000, - STDFL = 000400000000, - STINT = 001000000000, - WRTIO = 002000000000, - FREE = 004000000000 + BUSY = 000000200000, /* Set Interface Busy */ + DSCIF = 000000400000, /* Disconnect Interface */ + SELIF = 000001000000, /* Select Interface */ + IFIN = 000002000000, /* Interface In */ + IFOUT = 000004000000, /* Interface Out */ + IFGTC = 000010000000, /* Interface Get Command */ + IFPRF = 000020000000, /* Interface Prefetch Command */ + RQSRV = 000040000000, /* Request Service */ + DVEND = 000100000000, /* Device End */ + SRTRY = 000200000000, /* Set Retry Counter */ + STDFL = 000400000000, /* Set Data Flag */ + STINT = 001000000000, /* Set Interrupt */ + WRTIO = 002000000000, /* Write TIO Register */ + FREE = 004000000000 /* Set Interface Free */ } CNTLR_IFN; #define NO_FUNCTIONS ((CNTLR_IFN) 0) /* no functions are asserted */ @@ -223,13 +234,13 @@ typedef enum { /* interface function bus orders typedef CNTLR_IFN CNTLR_IFN_SET; /* a set of CNTLR_IFNs */ -typedef uint16 CNTLR_IBUS; /* the interface data bus */ +typedef HP_WORD CNTLR_IBUS; /* the interface data bus */ #undef NO_DATA /* remove winsock definition */ -#define NO_DATA (CNTLR_IBUS) 0 /* no data asserted */ +#define NO_DATA ((CNTLR_IBUS) 0) /* no data asserted */ -typedef uint32 CNTLR_IFN_IBUS; /* a combined interface function set and data bus value */ +typedef uint32 CNTLR_IFN_IBUS; /* a combined interface function set and data bus value */ /* Controller opcodes */ @@ -379,7 +390,7 @@ typedef struct { } DELAY_PROPS; #define DELAY_INIT(sk1,skf,scf,dxfr,isg,ovhd) \ - 0, 0, \ + (CNTLR_TYPE) 0, (DRIVE_TYPE) 0, \ (sk1), (skf), (scf), (dxfr), (isg), (ovhd) @@ -400,16 +411,16 @@ typedef struct { uint32 sector; /* sector address */ uint32 count; /* count of words transferred or to verify */ uint32 poll_unit; /* last unit polled for attention */ - uint16 *buffer; /* data buffer pointer */ + DL_BUFFER *buffer; /* data buffer pointer */ uint32 index; /* data buffer current index */ uint32 length; /* data buffer valid length */ DIAG_ENTRY *dop_base; /* pointer to the diagnostic override array */ - DIAG_ENTRY *dop; /* current diagnostic override entry pointer */ + int32 dop_index; /* current diagnostic override entry index */ DELAY_PROPS *fastptr; /* pointer to the FASTTIME delays */ const DELAY_PROPS *dlyptr; /* current delay property pointer */ } CNTLR_VARS; -typedef CNTLR_VARS *CVPTR; /* pointer to a controller state variable structure */ +typedef CNTLR_VARS *CVPTR; /* pointer to a controller state variable structure */ /* Controller state variable structure initialization. @@ -418,7 +429,7 @@ typedef CNTLR_VARS *CVPTR; /* pointer to a controller state ctype - the type of the controller (CNTLR_TYPE) dev - the device on which the controller operates (DEVICE) - bufptr - a pointer to the data buffer (array of uint16) + bufptr - a pointer to the data buffer (array of DL_BUFFER) doa - a pointer to the diagnostic override array (array of DIAG_ENTRY) or NULL if this facility is not used fast - a pointer to the fast timing values (DELAY_PROPS) @@ -429,52 +440,54 @@ typedef CNTLR_VARS *CVPTR; /* pointer to a controller state CLEAR, FALSE, \ 0, 0, 0, 0, 0, 0, 0, \ (bufptr), 0, 0, \ - (doa), NULL, \ + (doa), -1, \ &(fast), &(fast) /* Disc controller device register definitions. + These definitions should be included AFTER any interface-specific registers. + The supplied parameters are: cntlr - the controller state variable structure (CNTLR_VARS) units - the unit array (array of UNIT) numunits - the number of units in the unit array - buffer - the sector buffer (array of uint16) + buffer - the sector buffer (array of DL_BUFFER) times - the fast timing values structure (DELAY_PROPS) - These definitions should be included AFTER any interface-specific registers. - Implementation notes: - 1. The "CNTLR" register is present to ensure that the entire CNTLR_VARS - structure is saved and restored. + 1. The CNTLR_VARS fields "type", "device", "buffer", "dop_base", "fastptr", + and "dlyptr" do not need to appear in the REG array, as "dlyptr" is reset + by the dl_attach routine during a RESTORE, and the others are static. 2. The fast timing structure does not use the controller and drive type - fields, so they do not need to be SAVEd or RESTOREd, so they do not need - to appear in hidden registers. + fields, so they do not appear in hidden registers, as they need not be + SAVEd or RESTOREd. */ #define DL_REGS(cntlr,units,numunits,buffer,times) \ -/* Macro Name Location Radix Width Depth Flags */ \ -/* ------ -------- ------------------ ----- ----- ----------------- ---------------- */ \ - { ORDATA (OPCODE, (cntlr).opcode, 5), REG_RO }, \ - { ORDATA (CSTATS, (cntlr).status, 5), REG_RO }, \ - { DRDATA (CSTATE, (cntlr).state, 2), PV_LEFT | REG_RO }, \ - { FLDATA (EOC, (cntlr).eoc, 0) }, \ - { FLDATA (VERIFY, (cntlr).verify, 0) }, \ - { ORDATA (SPDU, (cntlr).spd_unit, 16) }, \ - { ORDATA (FLMASK, (cntlr).file_mask, 4) }, \ - { DRDATA (CYL, (cntlr).cylinder, 16), PV_LEFT }, \ - { DRDATA (HEAD, (cntlr).head, 6), PV_LEFT }, \ - { DRDATA (SECTOR, (cntlr).sector, 8), PV_LEFT }, \ - { DRDATA (COUNT, (cntlr).count, 16), PV_LEFT }, \ - { BRDATA (SECBUF, (buffer), 8, 16, DL_BUFSIZE), REG_A }, \ - { DRDATA (INDEX, (cntlr).index, 8), PV_LEFT }, \ - { DRDATA (LENGTH, (cntlr).length, 8), PV_LEFT }, \ - { SRDATA (CNTLR, (cntlr)), REG_HRO }, \ - \ +/* Macro Name Location Radix Width Depth Flags */ \ +/* ------ -------- ------------------ ----- ----- ----------------- ----------------- */ \ + { ORDATA (OPCODE, (cntlr).opcode, 5), REG_RO }, \ + { ORDATA (CSTATS, (cntlr).status, 5), REG_RO }, \ + { DRDATA (CSTATE, (cntlr).state, 2), PV_LEFT | REG_RO }, \ + { FLDATA (EOC, (cntlr).eoc, 0) }, \ + { FLDATA (VERIFY, (cntlr).verify, 0) }, \ + { ORDATA (SPDU, (cntlr).spd_unit, 16) }, \ + { ORDATA (FLMASK, (cntlr).file_mask, 4) }, \ + { DRDATA (CYL, (cntlr).cylinder, 16), PV_LEFT }, \ + { DRDATA (HEAD, (cntlr).head, 6), PV_LEFT }, \ + { DRDATA (SECTOR, (cntlr).sector, 8), PV_LEFT }, \ + { DRDATA (COUNT, (cntlr).count, 16), PV_LEFT }, \ + { BRDATA (SECBUF, (buffer), 8, 16, DL_BUFSIZE), REG_A }, \ + { DRDATA (INDEX, (cntlr).index, 8), PV_LEFT }, \ + { DRDATA (LENGTH, (cntlr).length, 8), PV_LEFT }, \ + { DRDATA (POLLU, (cntlr).poll_unit, 4), REG_HRO }, \ + { DRDATA (DOINDX, (cntlr).dop_index, 16), PV_LEFT | REG_HRO }, \ + \ /* Macro Name Location Width Flags */ \ /* ------ ------ ------------------------ ----- ---------------- */ \ { DRDATA (TTIME, (times).seek_one, 24), PV_LEFT | REG_NZ }, \ diff --git a/HP3000/hp_tapelib.c b/HP3000/hp_tapelib.c index fee40cb0..dda62100 100644 --- a/HP3000/hp_tapelib.c +++ b/HP3000/hp_tapelib.c @@ -24,7 +24,14 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. + 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 + 08-Jun-16 JDB Corrected %d format to %u for unsigned values + 16-May-16 JDB TAPELIB_PROPERTIES.action is now a pointer-to-constant 13-May-16 JDB Modified for revised SCP API function parameter types + 03-May-16 JDB Changed clear/attach/on/offline trace from INCO to CMD + 24-Mar-16 JDB Changed the buffer element type from uint8 to TL_BUFFER + 21-Mar-16 JDB Changed uint16 types to HP_WORD 20-Nov-15 JDB First release version 24-Mar-13 JDB Created tape controller common library from MS simulator @@ -338,7 +345,7 @@ /* Unit flags accessor */ -#define GET_MODEL(f) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK) +#define GET_MODEL(f) (DRIVE_TYPE) ((f) >> UNIT_MODEL_SHIFT & UNIT_MODEL_MASK) /* Per-unit property flags and accessors. @@ -378,10 +385,10 @@ #define PROP_UNIT_SHIFT 10 /* bits 12-10 */ #define PROP_MODEL_SHIFT 13 /* bits 15-13 */ -#define PROP_INDEX_MASK ((1 << PROP_INDEX_WIDTH) - 1 << PROP_INDEX_SHIFT) -#define PROP_REEL_MASK ((1 << PROP_REEL_WIDTH) - 1 << PROP_REEL_SHIFT) -#define PROP_UNIT_MASK ((1 << PROP_UNIT_WIDTH) - 1 << PROP_UNIT_SHIFT) -#define PROP_MODEL_MASK ((1 << PROP_MODEL_WIDTH) - 1 << PROP_MODEL_SHIFT) +#define PROP_INDEX_MASK ((1u << PROP_INDEX_WIDTH) - 1 << PROP_INDEX_SHIFT) +#define PROP_REEL_MASK ((1u << PROP_REEL_WIDTH) - 1 << PROP_REEL_SHIFT) +#define PROP_UNIT_MASK ((1u << PROP_UNIT_WIDTH) - 1 << PROP_UNIT_SHIFT) +#define PROP_MODEL_MASK ((1u << PROP_MODEL_WIDTH) - 1 << PROP_MODEL_SHIFT) #define PROP_INDEX(u) (((u)->PROP & PROP_INDEX_MASK) >> PROP_INDEX_SHIFT) #define PROP_REEL(u) (((u)->PROP & PROP_REEL_MASK) >> PROP_REEL_SHIFT) @@ -758,9 +765,9 @@ typedef enum { typedef struct { - t_bool gap_is_valid; /* call may involve an erase gap */ - t_bool data_is_valid; /* call may involve a data record */ - char *action; /* string describing the call action */ + t_bool gap_is_valid; /* call may involve an erase gap */ + t_bool data_is_valid; /* call may involve a data record */ + const char *action; /* string describing the call action */ } TAPELIB_PROPERTIES; @@ -911,7 +918,7 @@ return outbound; t_stat tl_onoffline (CVPTR cvptr, UNIT *uptr, t_bool online) { -const uint32 unit = uptr - cvptr->device->units; /* the unit number */ +const int32 unit = (int32) (uptr - cvptr->device->units); /* the unit number */ t_stat status = SCPE_OK; if (uptr->flags & UNIT_ATT) { /* if the unit is attached */ @@ -924,7 +931,7 @@ if (uptr->flags & UNIT_ATT) { /* if the unit is attach status = SCPE_INCOMP; /* then it must be called to poll the drives */ } - dpprintf (cvptr->device, TL_DEB_INCO, "Unit %d set %s\n", + dpprintf (cvptr->device, TL_DEB_CMD, "Unit %d set %s\n", unit, (online ? "online" : "offline")); } @@ -985,7 +992,7 @@ return status; busy" status and the complement of the SL signal as "unit local" status. */ -uint16 tl_status (CVPTR cvptr) +HP_WORD tl_status (CVPTR cvptr) { UNIT *const uptr = cvptr->device->units + cvptr->unit_selected; /* a pointer to the selected unit */ uint32 status; @@ -1131,7 +1138,7 @@ for (unit = 0; unit < cvptr->device->numunits; unit++) { /* look for a write if (remaining_time) { /* if the unit is currently active */ if (uptr->flags & UNIT_REWINDING) /* then a clear does not affect a rewind in progress */ dpprintf (cvptr->device, TL_DEB_INCO, - "Unit %d controller clear allowed %s to continue\n", + "Unit %u controller clear allowed %s to continue\n", unit, opcode_names [uptr->OPCODE]); else { /* but all other commands are aborted */ @@ -1147,7 +1154,7 @@ for (unit = 0; unit < cvptr->device->numunits; unit++) { /* look for a write else /* otherwise */ reset_position = cvptr->initial_position + relative_position; /* move toward the EOT */ - cvptr->gaplen -= relative_position; /* reduce the gap length by the amount not traversed */ + cvptr->gaplen -= (t_mtrlnt) relative_position; /* reduce the gap length by the amount not traversed */ while (cvptr->gaplen > sizeof (t_mtrlnt)) { /* align the reset position to a gap marker */ if (sim_fseek (uptr->fileref, /* seek to the reset position */ @@ -1173,13 +1180,13 @@ for (unit = 0; unit < cvptr->device->numunits; unit++) { /* look for a write }; dpprintf (cvptr->device, TL_DEB_INCO, - "Unit %d controller clear stopped tape motion at position %d\n", + "Unit %u controller clear stopped tape motion at position %" T_ADDR_FMT "u\n", unit, uptr->pos); } else /* otherwise FASTTIME mode is selected */ dpprintf (cvptr->device, TL_DEB_INCO, - "Unit %d controller clear aborted %s after partial completion\n", + "Unit %u controller clear aborted %s after partial completion\n", unit, opcode_names [uptr->OPCODE]); if (cmd_props [uptr->OPCODE].class == Class_Write /* if the last command was a write */ @@ -1199,7 +1206,7 @@ for (unit = 0; unit < cvptr->device->numunits; unit++) { /* look for a write if (uptr->OPCODE != Clear_Controller) /* report the abort only if this isn't a clear command */ dpprintf (cvptr->device, TL_DEB_INCO, - "Unit %d controller clear aborted %s after partial completion\n", + "Unit %u controller clear aborted %s after partial completion\n", unit, opcode_names [uptr->OPCODE]); } } @@ -1211,7 +1218,7 @@ cvptr->unit_attention = 0; /* clear any pending uni if (cvptr->type == HP_30215) /* if this is the 3000 controller */ cvptr->unit_selected = 0; /* then a clear selects unit 0 */ -dpprintf (cvptr->device, TL_DEB_INCO, "Controller cleared\n"); +dpprintf (cvptr->device, TL_DEB_CMD, "Controller cleared\n"); return; } @@ -1242,7 +1249,7 @@ else /* otherwise */ unit is invalid, an error string is returned. */ -const char *tl_unit_name (uint32 unit) +const char *tl_unit_name (int32 unit) { if (unit <= TL_CNTLR_UNIT) /* if the unit number is valid */ return unit_names [unit]; /* then return the unit designator */ @@ -1266,6 +1273,7 @@ else /* otherwise */ polled automatically when the current command completes and the controller is idled. + Implementation notes: 1. The support library LOCKED and WRITEENABLED modifiers are not used to @@ -1278,11 +1286,15 @@ else /* otherwise */ 2. If we are called during a RESTORE command, the unit's flags are not changed to avoid upsetting the state that was SAVEd. + + 3. The pointer to the appropriate event delay times is set in case we are + being called during a RESTORE command (the assignment is redundant + otherwise). */ t_stat tl_attach (CVPTR cvptr, UNIT *uptr, CONST char *cptr) { -const uint32 unit = uptr - cvptr->device->units; /* the unit number */ +const int32 unit = (int32) (uptr - cvptr->device->units); /* the unit number */ t_stat result; result = sim_tape_attach (uptr, cptr); /* attach the tape image file to the unit */ @@ -1298,13 +1310,18 @@ if (result == SCPE_OK /* if the attach was suc cvptr->unit_attention |= 1 << unit; /* drive attention sets on tape load */ - dpprintf (cvptr->device, TL_DEB_INCO, "Unit %d tape loaded and set online\n", + dpprintf (cvptr->device, TL_DEB_CMD, "Unit %d tape loaded and set online\n", unit); if (cvptr->state == Idle_State) /* if the controller is idle */ result = SCPE_INCOMP; /* then it must be called to poll the drives */ } +if (cvptr->device->flags & DEV_REALTIME) /* if realistic timing is selected */ + cvptr->dlyptr = &real_times [PROP_INDEX (uptr)]; /* then get the real times pointer for this drive */ +else /* otherwise optimized timing is selected */ + cvptr->dlyptr = cvptr->fastptr; /* so use the fast times pointer */ + return result; /* return the result of the attach */ } @@ -1521,7 +1538,7 @@ return SCPE_OK; t_stat tl_show_density (FILE *st, UNIT *uptr, int32 value, CONST void *desc) { -fprintf (st, "%d bpi", drive_props [PROP_INDEX (uptr)].bpi); +fprintf (st, "%u bpi", drive_props [PROP_INDEX (uptr)].bpi); return SCPE_OK; } @@ -2018,6 +2035,10 @@ return outbound; /* return the functions the unit is online. The status cannot be inferred from the command, as the user may have set the unit offline or online explicitly before the rewind completed. + + 18. The "%.0u" print specification in the trace call absorbs the zero + "length" value parameter without printing when the controller unit is + specified. */ static CNTLR_IFN_IBUS continue_command (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET inbound_flags, CNTLR_IBUS inbound_data) @@ -2025,15 +2046,15 @@ static CNTLR_IFN_IBUS continue_command (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OPCODE; /* the current command opcode */ const CNTLR_PHASE phase = (CNTLR_PHASE) uptr->PHASE; /* the current command phase */ const t_bool service_entry = (phase > Wait_Phase); /* TRUE if entered via unit service */ -uint32 unit; -uint8 data_byte; +int32 unit; +TL_BUFFER data_byte; t_mtrlnt error_flag; BYTE_SELECTOR selector; DRIVE_PROPS const *pptr; CNTLR_IFN_IBUS outbound = NO_ACTION; t_bool complete = FALSE; -unit = uptr - cvptr->device->units; /* get the unit number */ +unit = (int32) (uptr - cvptr->device->units); /* get the unit number */ dpprintf (cvptr->device, TL_DEB_STATE, "%s %s %s phase entered from %s\n", unit_names [unit], opcode_names [opcode], phase_names [phase], @@ -2055,7 +2076,7 @@ switch (phase) { /* dispatch the phase */ uptr->OPCODE = Invalid_Opcode; /* so clear the controller command */ uptr->PHASE = Idle_Phase; /* and idle the unit */ - unit = cvptr->unit_selected; /* get the selected unit number */ + unit = (int32) cvptr->unit_selected; /* get the selected unit number */ uptr = cvptr->device->units + unit; /* and unit pointer */ uptr->PHASE = Start_Phase; /* set up the start phase */ @@ -2070,7 +2091,7 @@ switch (phase) { /* dispatch the phase */ case Start_Phase: - dpprintf (cvptr->device, TL_DEB_INCO, "Unit %d %s started at position %d\n", + dpprintf (cvptr->device, TL_DEB_INCO, "Unit %d %s started at position %" T_ADDR_FMT "u\n", unit, opcode_names [opcode], uptr->pos); pptr = &drive_props [PROP_INDEX (uptr)]; /* get the drive property pointer */ @@ -2204,7 +2225,7 @@ switch (phase) { /* dispatch the phase */ uptr->PHASE = Traverse_Phase; /* and proceed to the rewinding phase */ uptr->wait = /* base the traversal time on the current tape position */ - (uptr->pos * cvptr->dlyptr->rewind_rate) / pptr->bpi; + (int32) ((uptr->pos * cvptr->dlyptr->rewind_rate) / pptr->bpi); } break; @@ -2314,7 +2335,7 @@ switch (phase) { /* dispatch the phase */ outbound = /* then transfer one byte at a time */ cvptr->buffer [cvptr->index++]; /* to the data register */ - dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s byte %d is %03o\n", + dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s byte %u is %03o\n", unit, opcode_names [opcode], cvptr->index, outbound); @@ -2329,7 +2350,7 @@ switch (phase) { /* dispatch the phase */ outbound |= /* then merge in the low byte */ cvptr->buffer [cvptr->index++]; - dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s word %d is %06o\n", + dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s word %u is %06o\n", unit, opcode_names [opcode], (cvptr->index + 1) / 2, outbound); @@ -2361,7 +2382,7 @@ switch (phase) { /* dispatch the phase */ uptr->wait = cvptr->dlyptr->data_xfer; /* schedule the next byte transfer */ - dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s byte %d is %06o\n", + dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s byte %u is %06o\n", unit, opcode_names [opcode], cvptr->index, inbound_data); } @@ -2388,7 +2409,7 @@ switch (phase) { /* dispatch the phase */ uptr->wait = 2 * cvptr->dlyptr->data_xfer; /* schedule the next word transfer */ - dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s word %d is %06o\n", + dpprintf (cvptr->device, TL_DEB_XFER, "Unit %d %s word %u is %06o\n", unit, opcode_names [opcode], (cvptr->index + 1) / 2, inbound_data); } @@ -2536,8 +2557,8 @@ switch (phase) { /* dispatch the phase */ case Rewind: case Rewind_Offline: - if ((uptr->flags & UNIT_OFFLINE) == 0) /* if the unit is online */ - cvptr->unit_attention |= 1 << unit; /* then attention sets on rewind completion */ + if ((uptr->flags & UNIT_OFFLINE) == 0) /* if the unit is online */ + cvptr->unit_attention |= 1u << unit; /* then attention sets on rewind completion */ uptr->flags &= ~UNIT_REWINDING; /* clear rewinding status */ @@ -2586,12 +2607,12 @@ if (uptr->wait != NO_EVENT) /* if the unit has been if (complete) { /* if the command is complete */ dpprintf (cvptr->device, TL_DEB_INCO, /* then report the final tape position */ - "Unit %d %s completed at position %d\n", + "Unit %d %s completed at position %" T_ADDR_FMT "u\n", unit, opcode_names [opcode], uptr->pos); dpprintf (cvptr->device, TL_DEB_CMD, (cvptr->length > 0 - ? "Unit %d %s of %d-byte record %s\n" - : "Unit %d %s %.0d%s\n"), + ? "Unit %d %s of %u-byte record %s\n" + : "Unit %d %s %.0u%s\n"), unit, opcode_names [opcode], cvptr->length, status_name [cvptr->call_status]); } @@ -2660,7 +2681,7 @@ while (cvptr->unit_attention) /* loop through the atte if (cvptr->unit_attention & 1 << unit) { /* looking for the first one set */ cvptr->unit_attention &= ~(1 << unit); /* and then clear it */ - dpprintf (cvptr->device, TL_DEB_INCO, "Unit %d requested attention\n", + dpprintf (cvptr->device, TL_DEB_INCO, "Unit %u requested attention\n", unit); cvptr->unit_selected = unit; /* select the unit requesting attention */ @@ -2761,7 +2782,8 @@ return NO_ACTION; /* no drives are request static CNTLR_IFN_IBUS call_tapelib (CVPTR cvptr, UNIT *uptr, TAPELIB_CALL lib_call, t_mtrlnt parameter) { t_bool do_gap, do_data; -uint32 unit, gap_inches, gap_tenths; +int32 unit; +uint32 gap_inches, gap_tenths; CNTLR_IFN_IBUS result = (CNTLR_IFN_IBUS) NO_FUNCTIONS; /* the expected case */ switch (lib_call) { /* dispatch to the selected routine */ @@ -2806,10 +2828,10 @@ switch (lib_call) { /* dispatch to the selec } -if (cvptr->initial_position < uptr->pos) /* calculate the preliminary gap size */ - cvptr->gaplen = uptr->pos - cvptr->initial_position; /* for either forward motion */ -else /* or */ - cvptr->gaplen = cvptr->initial_position - uptr->pos; /* for reverse motion */ +if (cvptr->initial_position < uptr->pos) /* calculate the preliminary gap size */ + cvptr->gaplen = (t_mtrlnt) (uptr->pos - cvptr->initial_position); /* for either forward motion */ +else /* or */ + cvptr->gaplen = (t_mtrlnt) (cvptr->initial_position - uptr->pos); /* for reverse motion */ switch (cvptr->call_status) { /* dispatch on the call status */ @@ -2911,7 +2933,7 @@ switch (cvptr->call_status) { /* dispatch on the call if (DPPRINTING (cvptr->device, TL_DEB_INCO)) { /* if tracing is enabled */ - unit = uptr - cvptr->device->units; /* then get the unit number */ + unit = (int32) (uptr - cvptr->device->units); /* then get the unit number */ do_data = /* TRUE if the data record length is valid and present */ lib_props [lib_call].data_is_valid && cvptr->length > 0; @@ -2928,7 +2950,7 @@ if (DPPRINTING (cvptr->device, TL_DEB_INCO)) { /* if tracing is enabled if (do_gap && do_data) /* if both gap and data are present */ hp_debug (cvptr->device, TL_DEB_INCO, /* then report both objects */ - "Unit %d %s call of %d.%d-inch erase gap and %d-word record %s\n", + "Unit %d %s call of %u.%u-inch erase gap and %u-word record %s\n", unit, lib_props [lib_call].action, gap_inches, gap_tenths, /* using the movement calculated above */ (cvptr->length + 1) / 2, @@ -2936,14 +2958,14 @@ if (DPPRINTING (cvptr->device, TL_DEB_INCO)) { /* if tracing is enabled else if (do_data) /* otherwise if data only are present */ hp_debug (cvptr->device, TL_DEB_INCO, /* then report the record length */ - "Unit %d %s call of %d-word record %s\n", + "Unit %d %s call of %u-word record %s\n", unit, lib_props [lib_call].action, (cvptr->length + 1) / 2, status_name [cvptr->call_status]); else if (do_gap) /* otherwise if motion only is present */ hp_debug (cvptr->device, TL_DEB_INCO, /* then report it */ - "Unit %d %s call of %d.%d%s %s\n", + "Unit %d %s call of %u.%u%s %s\n", unit, lib_props [lib_call].action, gap_inches, gap_tenths, (lib_call == lib_rewind ? " inches" : "-inch erase gap"), @@ -3002,17 +3024,13 @@ return SCP_STATUS (status); /* with the appropriat static void reject_command (CVPTR cvptr, UNIT *uptr) { -uint32 unit; - if (uptr) /* if a command is currently executing */ uptr->PHASE = Idle_Phase; /* then idle the tape drive */ else /* otherwise a command is attempting to start */ uptr = CNTLR_UPTR; /* so set up action on the controller unit */ -unit = uptr - cvptr->device->units; /* determine the unit number for tracing */ - dpprintf (cvptr->device, TL_DEB_CMD, "%s %s command rejected\n", - unit_names [unit], opcode_names [uptr->OPCODE]); + unit_names [uptr - cvptr->device->units], opcode_names [uptr->OPCODE]); cvptr->status = CST_REJECT; /* set the Command Reject status */ cvptr->state = Error_State; @@ -3067,8 +3085,8 @@ return; static void add_crcc_lrcc (CVPTR cvptr, CNTLR_OPCODE opcode) { -uint32 index; -uint16 byte, crc, lrc; +uint32 index; +HP_WORD byte, crc, lrc; crc = 0; /* initialize the CRC */ lrc = 0; /* and LRC accumulators */ @@ -3126,10 +3144,9 @@ return; static void activate_unit (CVPTR cvptr, UNIT *uptr) { -const uint32 unit = uptr - cvptr->device->units; /* the unit number */ - dpprintf (cvptr->device, TL_DEB_STATE, "%s %s %s phase delay %d service scheduled\n", - unit_names [unit], opcode_names [uptr->OPCODE], phase_names [uptr->PHASE], + unit_names [uptr - cvptr->device->units], + opcode_names [uptr->OPCODE], phase_names [uptr->PHASE], uptr->wait); sim_activate (uptr, uptr->wait); /* activate the unit */ diff --git a/HP3000/hp_tapelib.h b/HP3000/hp_tapelib.h index 17930f59..bc792ad5 100644 --- a/HP3000/hp_tapelib.h +++ b/HP3000/hp_tapelib.h @@ -25,6 +25,8 @@ this Software without prior written authorization from the authors. 13-May-16 JDB Modified for revised SCP API function parameter types + 24-Mar-16 JDB Added the TL_BUFFER type to define the tape buffer array + 21-Mar-16 JDB Changed uint16 types to HP_WORD 11-Nov-15 JDB First release version 24-Mar-13 JDB Created tape controller common library from MS simulator @@ -42,6 +44,15 @@ +/* Architectural constants. + + The type of the tape buffer element is defined. This must be an 8-bit array + for compatibility with the simulator tape support library (sim_tape). +*/ + +typedef uint8 TL_BUFFER; /* a buffer containing 8-bit tape data words */ + + /* Program limits */ #define TL_MAXDRIVE 3 /* last valid drive number */ @@ -54,12 +65,12 @@ /* Debug flags */ -#define TL_DEB_CMD (1 << 0) /* trace controller commands */ -#define TL_DEB_INCO (1 << 1) /* trace command initiations and completions */ -#define TL_DEB_STATE (1 << 2) /* trace command execution state changes */ -#define TL_DEB_SERV (1 << 3) /* trace unit service scheduling calls */ -#define TL_DEB_XFER (1 << 4) /* trace data reads and writes */ -#define TL_DEB_IOB (1 << 5) /* trace I/O bus signals and data words */ +#define TL_DEB_CMD (1u << 0) /* trace controller commands */ +#define TL_DEB_INCO (1u << 1) /* trace command initiations and completions */ +#define TL_DEB_STATE (1u << 2) /* trace command execution state changes */ +#define TL_DEB_SERV (1u << 3) /* trace unit service scheduling calls */ +#define TL_DEB_XFER (1u << 4) /* trace data reads and writes */ +#define TL_DEB_IOB (1u << 5) /* trace I/O bus signals and data words */ #define TL_DEB_V_UF 6 /* first free debug flag bit */ @@ -109,11 +120,11 @@ #define TL_UNIT_V_UF (MTUF_V_UF + 5) /* first free unit flag bit */ -#define UNIT_MODEL_MASK 0000007 /* model ID mask */ +#define UNIT_MODEL_MASK 0000007u /* model ID mask */ #define UNIT_MODEL (UNIT_MODEL_MASK << UNIT_MODEL_SHIFT) -#define UNIT_OFFLINE (1 << UNIT_OFFLINE_SHIFT) -#define UNIT_REWINDING (1 << UNIT_REW_SHIFT) +#define UNIT_OFFLINE (1u << UNIT_OFFLINE_SHIFT) +#define UNIT_REWINDING (1u << UNIT_REW_SHIFT) #define UNIT_7970B (HP_7970B << UNIT_MODEL_SHIFT) #define UNIT_7970E (HP_7970E << UNIT_MODEL_SHIFT) @@ -216,7 +227,7 @@ typedef enum { /* interface function bus orders typedef CNTLR_IFN CNTLR_IFN_SET; /* a set of CNTLR_IFNs */ -typedef uint16 CNTLR_IBUS; /* the interface data bus */ +typedef HP_WORD CNTLR_IBUS; /* the interface data bus */ #undef NO_DATA /* remove winsock definition */ #define NO_DATA (CNTLR_IBUS) 0 /* no data asserted */ @@ -344,7 +355,7 @@ typedef struct { (rstart), (rrate), (rstop), (bot), (ir), (dxfr), (ovhd) -/* Tape controller state variable structure */ +/* Tape controller state */ typedef struct { CNTLR_TYPE type; /* controller type */ @@ -353,7 +364,7 @@ typedef struct { uint32 status; /* controller status */ uint32 unit_selected; /* unit number currently selected */ uint32 unit_attention; /* bitmap of units needing attention */ - uint8 *buffer; /* data buffer pointer */ + TL_BUFFER *buffer; /* data buffer pointer */ t_stat call_status; /* simulator tape support library call status */ t_mtrlnt length; /* data buffer valid length */ t_mtrlnt index; /* data buffer current index */ @@ -372,7 +383,7 @@ typedef CNTLR_VARS *CVPTR; /* a pointer to a controller sta ctype - the type of the controller (CNTLR_TYPE) dev - the device on which the controller operates (DEVICE) - bufptr - a pointer to the data buffer (array of uint8) + bufptr - a pointer to the data buffer (array of TL_BUFFER) fast - a pointer to the fast timing values (DELAY_PROPS) */ @@ -391,31 +402,31 @@ typedef CNTLR_VARS *CVPTR; /* a pointer to a controller sta cntlr -- the controller state variable structure (CNTLR_VARS) units -- the unit array (array of UNIT) numunits -- the number of tape drive units - buffer -- the buffer array (array of uint8) + buffer -- the buffer array (array of TL_BUFFER) times -- the structure containing the fast delay time values (DELAY_PROPS) Implementation notes: - 1. The "CNTLR" register is present to ensure that the entire CNTLR_VARS - structure is saved and restored. + 1. The CNTLR_VARS fields "type", "device", "buffer", "fastptr", and "dlyptr" + do not need to appear in the REG array, as "dlyptr" is reset by the + tl_attach routine during a RESTORE, and the others are static. */ #define TL_REGS(cntlr,units,numunits,buffer,times) \ -/* Macro Name Location Radix Width Depth Flags */ \ -/* ------ ------ ------------------------ ----- -------- --------------- ----------------- */ \ - { DRDATA (CSTATE, (cntlr).state, 4), PV_LEFT | REG_RO }, \ - { ORDATA (STATUS, (cntlr).status, 16), REG_RO }, \ - { DRDATA (USEL, (cntlr).unit_selected, 4), PV_LEFT | REG_RO }, \ - { YRDATA (UATTN, (cntlr).unit_attention, 4) }, \ - { BRDATA (RECBUF, (buffer), 8, 8, TL_BUFSIZE), REG_A }, \ - { DRDATA (LIBSTA, (cntlr).call_status, 16), PV_LEFT }, \ - { DRDATA (LENGTH, (cntlr).length, 24), PV_LEFT }, \ - { DRDATA (INDEX, (cntlr).index, 24), PV_LEFT }, \ - { DRDATA (GAPLEN, (cntlr).gaplen, 32), PV_LEFT }, \ - { DRDATA (INPOS, (cntlr).initial_position, T_ADDR_W), PV_LEFT }, \ - { SRDATA (CNTLR, (cntlr)), REG_HRO }, \ - \ +/* Macro Name Location Radix Width Depth Flags */ \ +/* ------ ------ ------------------------ ----- -------- --------------- ----------------- */ \ + { DRDATA (CSTATE, (cntlr).state, 4), PV_LEFT | REG_RO }, \ + { ORDATA (STATUS, (cntlr).status, 16), REG_RO }, \ + { DRDATA (USEL, (cntlr).unit_selected, 4), PV_LEFT | REG_RO }, \ + { YRDATA (UATTN, (cntlr).unit_attention, 4, PV_RZRO) }, \ + { BRDATA (RECBUF, (buffer), 8, 8, TL_BUFSIZE), REG_A }, \ + { DRDATA (LIBSTA, (cntlr).call_status, 16), PV_LEFT }, \ + { DRDATA (LENGTH, (cntlr).length, 24), PV_LEFT }, \ + { DRDATA (INDEX, (cntlr).index, 24), PV_LEFT }, \ + { DRDATA (GAPLEN, (cntlr).gaplen, 32), PV_LEFT }, \ + { DRDATA (INPOS, (cntlr).initial_position, T_ADDR_W), PV_LEFT }, \ + \ /* Macro Name Location Width Flags */ \ /* ------ ------- -------------------- ----- ---------------- */ \ { DRDATA (RSTART, (times).rewind_start, 24), PV_LEFT | REG_NZ }, \ @@ -462,17 +473,17 @@ typedef CNTLR_VARS *CVPTR; /* a pointer to a controller sta /* Selectable drive type flags */ -#define TL_7970B (1 << HP_7970B) -#define TL_7970E (1 << HP_7970E) -#define TL_7974 (1 << HP_7974) -#define TL_7978 (1 << HP_7978) +#define TL_7970B (1u << HP_7970B) +#define TL_7970E (1u << HP_7970E) +#define TL_7974 (1u << HP_7974) +#define TL_7978 (1u << HP_7978) /* Selectable drive density flags */ #define TL_FIXED 0 -#define TL_800 (1 << MT_DENS_800) -#define TL_1600 (1 << MT_DENS_1600) -#define TL_6250 (1 << MT_DENS_6250) +#define TL_800 (1u << MT_DENS_800) +#define TL_1600 (1u << MT_DENS_1600) +#define TL_6250 (1u << MT_DENS_6250) #define IFTYPE(t,s) (TL_##t & (s) ? #t : NULL), \ (TL_##t & (s) ? #t : NULL) @@ -514,14 +525,14 @@ typedef CNTLR_VARS *CVPTR; /* a pointer to a controller sta extern CNTLR_IFN_IBUS tl_controller (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data); extern t_stat tl_onoffline (CVPTR cvptr, UNIT *uptr, t_bool online); -extern uint16 tl_status (CVPTR cvptr); -extern t_stat tl_reset (CVPTR cvptr); -extern void tl_clear (CVPTR cvptr); +extern HP_WORD tl_status (CVPTR cvptr); +extern t_stat tl_reset (CVPTR cvptr); +extern void tl_clear (CVPTR cvptr); /* Tape library global utility routines */ extern const char *tl_opcode_name (CNTLR_OPCODE opcode); -extern const char *tl_unit_name (uint32 unit); +extern const char *tl_unit_name (int32 unit); /* Tape library global SCP support routines */ diff --git a/Visual Studio Projects/HP3000.vcproj b/Visual Studio Projects/HP3000.vcproj index 6d81a85d..56827769 100644 --- a/Visual Studio Projects/HP3000.vcproj +++ b/Visual Studio Projects/HP3000.vcproj @@ -216,6 +216,10 @@ RelativePath="..\HP3000\hp3000_iop.c" > </File> + <File + RelativePath="..\HP3000\hp3000_lp.c" + > + </File> <File RelativePath="..\HP3000\hp3000_mpx.c" > diff --git a/descrip.mms b/descrip.mms index 48bec0e4..2d60605f 100644 --- a/descrip.mms +++ b/descrip.mms @@ -432,6 +432,7 @@ HP3000_LIB1 = $(LIB_DIR)HP3000L1-$(ARCH).OLB HP3000_SOURCE1 = $(HP3000_DIR)HP3000_ATC.C,$(HP3000_DIR)HP3000_CLK.C,\ $(HP3000_DIR)HP3000_CPU.C,$(HP3000_DIR)HP3000_CPU_BASE.C,\ $(HP3000_DIR)HP3000_CPU_FP.C,$(HP3000_DIR)HP3000_DS.C,\ + $(HP3000_DIR)HP3000_LP.C,\ $(HP3000_DIR)HP3000_IOP.C,$(HP3000_DIR)HP3000_MPX.C,\ $(HP3000_DIR)HP3000_MS.C,$(HP3000_DIR)HP3000_SCMB.C,\ $(HP3000_DIR)HP3000_SEL.C,$(HP3000_DIR)HP3000_SYS.C diff --git a/doc/hp3000_doc.doc b/doc/hp3000_doc.doc index 14baaae066501fe697294150a69bc428b191cbee..832caae497cedc0f4137f7b5edd21ad85bfc3b83 100644 GIT binary patch literal 354304 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�$-zr3`=XA{01(?+8Y4aQ}@X)d+tvAndtbf3Tf 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 literal 299008 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 HVh;QtDtXjw diff --git a/makefile b/makefile index 26d7a658..111e6960 100644 --- a/makefile +++ b/makefile @@ -1206,7 +1206,7 @@ HP3000D = HP3000 HP3000 = ${HP3000D}/hp_disclib.c ${HP3000D}/hp_tapelib.c ${HP3000D}/hp3000_atc.c \ ${HP3000D}/hp3000_clk.c ${HP3000D}/hp3000_cpu.c ${HP3000D}/hp3000_cpu_base.c \ ${HP3000D}/hp3000_cpu_fp.c ${HP3000D}/hp3000_ds.c ${HP3000D}/hp3000_iop.c \ - ${HP3000D}/hp3000_mpx.c ${HP3000D}/hp3000_ms.c \ + ${HP3000D}/hp3000_lp.c ${HP3000D}/hp3000_mpx.c ${HP3000D}/hp3000_ms.c \ ${HP3000D}/hp3000_scmb.c ${HP3000D}/hp3000_sel.c ${HP3000D}/hp3000_sys.c HP3000_OPT = -I ${HP3000D}