HP 3000 Simulator Notes ======================= EDIT subop display: - need two routines 1. called by OPRND trace - prints one subop that byte_address indicates - returns number of bytes consumed 2. called by fprint_sym for -E display - first two words are already in sim_eval [0] and [1] - prints one or two subops; two are required iff starting with the upper byte and only one byte consumed - returns number of words consumed - modifies 'R' switch if next access is to lower byte EXAMINE and trace MUST NOT alter the CPU state, either by bounds violations or illegal memory address interrupts. mem_reads used by these routines also must not add trace statements. Maybe calling mem_read with dptr NULL and class Absolute to indicate? Or using mem_examine? cpu_byte_to_word_ea: - used by MVB, SCW/SCU, MVBW, CMPB - block check by MVB, CMPB only ------------------------------------ Status Register Interrupt Enable Bit ------------------------------------ In hardware, the status register I-bit, reflected as the STATUS 1 signal, qualifies the MODINT and INTREQ signals. Clearing this bit with a SED 0 instruction disables external and module interrupts, and setting the bit with SED 1 enables them. The MCU sets the MOD INT flip-flop to request a module interrupt. The output is ANDed with STATUS 1 to produce the MODINT signal and the CPX1 bit 7 signal. MODINT is used to initiate an interrupt sequence when the NEXT micro-order is executed. So with the I-bit clear, a pending module interrupt is held off, and the cpx1_MODINTR bit in CPX1 is not set. The IOP ANDs the INTREQ signal with STATUS 1, the assertion of which sets the INT POLL flip-flop and initiates an interrupt poll. So with the I-bit clear, polls are not conducted, so a device interface requesting an interrupt does not receive an INTPOLL signal, so it does not return INTACK, so the EXT INT flip-flop does not set, so the EXTINT signal does not assert, so the cpx1_EXTINTR bit in CPX1 is not set, and the interrupt remains pending. When a SED 1 instruction is used to set the I bit, the assertion of the STATUS 1 signal immediately enables the MODINT signal, which is reflected in CPX1 bit 7. It also enables the INTREQ signal to set the INT POLL flip-flop. However, the path from the INTREQ signal to INTPOLL to INTACK to EXTINT passes sequentially through the INT POLL, INT ACK, and EXT INT flip-flops, which are all clocked on the rising edge. Therefore, assuming the interrupting device immediately asserts INTACK in response to INTPOLL, at least three clock periods elapse before the EXTINT signal asserts to initiate the interrupt sequence. Item 11 on page B-7 of the microcode listing manual says that, "Interrupts are checked on the clock cycle following execution of 'NEXT' in RANK2." It appears that after SED 1 enables the I bit, a pending MODINT will be recognized immediately, but a pending INTREQ won't be recognized until the NEXT micro-order is executed for the following instruction, so one instruction after the SED 1 will execute before the external interrupt is recognized. This behavior is verified by the CPU diagnostic. The SED 1 microcode does "SP1 STA IOR STA NEXT" to set the I bit. The STA micro-order in the store field enables a four-bit register on the SSF PCA to store U-bus bits 0-2 on the rising edge of the clock; the outputs present as the STATUS 0, STATUS 1, and STATUS 2 signals. As noted above, the output of the MOD INT flip-flop and the STATUS 1 signal are ANDed and present as the MODINT signal and CPX1 bit 7. MODINT and EXTINT are ORed with other interrupt sources and are clocked into the INTRP flip-flop on the CIR PCA on the rising edge of the clock; the output presents as the INTRP signal. INTRP is ANDed with the output of the NXT+1 flip-flop, which sets on the cycle after the NEXT micro-order is executed, and presents as the INTG signal on the SSF PCA. INTG enables the INTRP->V buffer on the CIR PCA, which forces the ROM address to location 3, which initiates interrupt processing on the next micro-cycle. So in simulation, we must do two things: 1. Inhibit setting the cpx1_EXTINTR and cpx1_MODINTR bits in CPX1 if STATUS_I is clear. 2. Inhibit recognition of EXTINTR (but not MODINTR) for one instruction after the SED 1. This is accomplished by: - Clearing the cpx1_MODINTR bit in the SED 0 executor. - Setting the cpx1_MODINTR bit in the SED 1 executor if the MOD register is non-zero (i.e., if a module interrupt is pending). - Setting the cpx1_MODINTR bit in the CMD executor if STATUS_I is set. - Not calling iop_poll (which sets cpx1_EXTINTR) in the instruction execution loop if STATUS_I is clear or the last instruction was SED 1. ------------------------ SAVE and RESTORE Support ------------------------ On 6/28/16, Mark said, "One of the designed intentions of SAVE/RESTORE data is that it be usable by the same simulator possibly in different places and/or on different host systems." If a SAVE file is to be RESTOREd on a different host platform with a simulator compiled with a different compiler, then simulators: - cannot have pointer state variables at all - cannot have structure state variables unless every field of the structure is referenced in a separate REG entry (and then, no pointer fields) The HP 3000 simulator uses SRDATA to store a structure in a REG field as an array of bytes. But this won't RESTORE properly if a different compilation with a different structure layout is used. The state structures currently in use are: - hp3000_atc.c (DIB) - hp3000_clk.c (DIB) - hp3000_ds.c (DIB, DIAG) - hp3000_lp.c (DIB, VFUREG) - hp3000_mpx.c (DIB) - hp3000_ms.c (DIB) - hp3000_scmb.c (DIB) Every device uses the DIB structure (7 state fields). The DS and MS devices use the disc and tape controller structures (21 and 14 state fields, respectively), although all of the dynamic fields are currently referenced in REG entries. The DS device uses an array of DIAG_ENTRY structures (6 state fields). The LP device uses a REG entry to save the contents of the following REG entry (11 fields) to permit variable-length display of the VFU array contents. The HP 2100 DA device uses a REG field to store an array of four disc controller structures, each having 24 state fields. All of this sounds like far too much trouble to change, compared with a restriction that a SAVEd file may only be RESTOREd on the same system, as working around the structure issues would be a major pain in the neck. A few of the devices use pointers as state variables. These are not saved but are instead recreated from integer state information (for example, a pointer into an array may be recreated from a stored array index). The problem is that there is no specific indication when a RESTORE occurs. However, devices that use external files will receive attach calls to reestablish attachment if that condition existed when the session was SAVEd. Version 4.0 ensures that the simulator state is completely restored before calling the attach routines. Version 3.x restores the device flags, the unit flags, and the device-specific u3 through u6 values before reattaching the files. In particular, memory and registers are NOT restored when the reattach is performed. Therefore, pointers that are recreated from the device or unit flags or the device-specific values can be used with both simulator versions. Pointers that are recreated from register values can only be used with the 4.x version. ------------------------------ Using enums as State Variables ------------------------------ The sizes of enums vary, depending on compiler defaults and options. For example, an enum that defines four states with values 0-3 will occupy an 8-bit location if the gcc compiler option "-fshort-enums" is used and a 32-bit location if the option is not used. Using enums as state variables requires that they be referenced by REG entries for SAVE/RESTORE to work. The problem is that the standard register macros, such as DRDATA, use fixed 32-bit accesses. A better choice would be a new ERDATA macro that initializes the "width" field automatically to "sizeof (loc) * CHAR_BIT" and adds the REG_FIT flag to the "flags" field. This would adjust the access size for the correct allocation size. An issue arises, however, when it is desired to set the display width independently of the allocation width. For instance, the LSB of the state value may have some significance. So a REG entry that displayed this single-bit value would set the "width" field to 1. The problem is that including REG_FIT requires an 8-bit allocation and not including it requires a 32-bit allocation, so REG_FIT inclusion depends on the size of the variable, which in turn depends on the compiler flags. It's possible to define an ERDATA macro that accounts for this by initializing the "flags" field to the logical OR of the supplied flags and this value: sizeof loc != sizeof (int) ? REG_FIT : 0 ...where "loc" is the supplied variable location. The presence of REG_FIT causes the access size to be determined by the width and offset. However, unless the width covers all significant bits in the state variable, the access may be incorrect. Consider an enum defined with two values: 0x0001 and 0x1000. The compiler will allocate either a 16-bit value (with -fshort-enums) or a 32-bit value (without). If we try to represent this value as two one-bit registers, there is a problem. The first register would have "width" = 1 and "offset" = 0; the second would have "width" = 1 and "offset" = 15. Without REG_FIT, both would use 32-bit accesses, which is correct when "-fshort-enums" is omitted. With REG_FIT, the first would use an 8-bit access, and the second would use a 16-bit access. The former is wrong, and no combination of REG field values would make it correct. (The same situation arises when using one-bit registers and integer arrays, where REG_FIT is implied. Using the width and offset values above, the first register requires an array of 8-bit elements, while the second requires the same array to have 16-bit elements.) Finally, it's impossible to specify an array of enums with a small range and a similarly-sized display width. For example, an enum specifying values 1, 2, 4, and 8, wants to be displayed in binary as four bits. Arrays always use REG_FIT rules, so if the enum array is compiled without the "-fshort-enums" switch, the array elements will be 32 bits in size. That will cause the display to have 28 leading zeros, e.g.: 00000000000000000000000000000100 ...which is awkward. What is required is the separation of the display width from the access width. The former is set by the developer; the latter is set automatically by applying the "sizeof" operator to the "loc" value. I haven't looked closely at the new "str_size" field that was added to support specifying arrays of structures, but it may be possible to repurpose this as the access size. Existing macros can be rewritten to add "sizeof loc" as the initializer for this new field. If the field value is zero, that means that initialization was specified explicitly, and the old rules should apply. Otherwise, the field value is used instead of the implicit access rules (including REG_FIT). The enums that are currently used as state varaibles, and therefore are referenced in REG entries, are: - hp_tapelib.h: DRDATA (CSTATE, (cntlr).state, 4), PV_LEFT | REG_RO - hp_disclib.h: ORDATA (OPCODE, (cntlr).opcode, 5), REG_RO ORDATA (CSTATS, (cntlr).status, 5), REG_RO DRDATA (CSTATE, (cntlr).state, 2), PV_LEFT | REG_RO - hp3000_lp.c: DRDATA (SEQSTA, sequencer, 8), PV_LEFT - hp3000_ms.c: DRDATA (CLASS, command_class, 4), PV_LEFT - hp3000_sel.c: DRDATA (SEQ, sequencer, 3) ORDATA (ORDER, order, 4) - hp3000_ds.c: FLDATA (CLEAR, flags, 0) FLDATA (CMRDY, flags, 1) etc. - hp3000_ms.c: YRDATA (FLAGS, flags, 8, PV_RZRO) // this assumes that "width" encompasses the full enum value range #undef ERFIT #undef ERDATA #define ERFIT(loc) (sizeof loc != sizeof (int) ? REG_FIT : 0) #define ERDATA(nm,loc,rdx,wd,off,fl) \ #nm, &(loc), (rdx), (wd), (off), 1, (fl | ERFIT (loc)), 0 ------------- Include Files ------------- include order (required): system files HP 3000 files SIMH files modules: - hp3000_defs.h (general declarations) included by all modules - hp3000_cpu.h (internal CPU declarations) included by CPU, CPU-base, CPU-fp, IOP - hp3000_cpu_ims.h (external CPU declarations) included by CPU, IOP, MPX, and SEL - hp3000_cpu_fp.h (CPU FP declarations) included by CPU-base - hp3000_io.h included by all modules that reference DIBs Global data: - cpu_ccb_table (cpu.c) - cpu_access_name (cpu.c -> iop.c) - odd_parity (sys.c -> iop.c) ---------------- Outbound Signals ---------------- JMPMET is asserted only during CHANSO. Asynchronous signal calls: - INTREQ (iop) - REQ (mpx,sel) - SRn (mpx) - CHANSR (sel) Each takes a DIB pointer, with synchronous calls using "dibptr", and asynchronous calls using "&dev_dib". Asynchronous calls are made from service entries. INTREQ could be called synchronously from: - DSETMASK - DSETINT - DRESETINT REQ could be called synchronously from: - DSTARTIO (but WHICH channel -- sel or mpx?) (could tell from SRNO = unused for MS/DS; but what about SCMB?) SRn could be called synchronously from: - DRESETINT - DSTARTIO In the diagnostic, MS does receive a DSTATSTB in the middle of a channel program, so it returns SRn. But that shouldn't cause mpx_assert_SRn to be called. So maybe condition general SRn on CHANSO, but include SRn explicitly for DRESETINT. >>MS iobus: Received data 000000 with signals DSTATSTB >>MS csrw: Status is ready | 1600 bpi | no error | unit 0 >>MS iobus: Returned data 000516 with signals JMPMET | SRn + Add inbound CHANSO on all channel calls + Add outbound INTREQ and test for it in iop_direct_io, pass to iop_assert_INTREQ + Add test for outbound SRn in iop_direct_io, pass to mpx_assert_SRN ---------------------------------- The TCI and the 12920A Control PCA ---------------------------------- The TCI and the Control PCA controls two lines to the modem and monitors two lines from the modem. The lines are: - C1: Data Terminal Ready (CD to modem) - C2: Request to Send (CA to modem) - S1: Data Set Ready (CC from modem) - S2: Carrier Detect (CF from modem) If a second TCI or Control PCA is present, the lines it uses are: - C1: Secondary Send Data (SA to modem) - C2: Frequency Select (CH to modem) - S1: Secondary Receive Data (SB from modem) - S2: Clear to Send (CB from modem) Control PCA Actions: - RTS is not used - if UNIT_MODEM and DTR dropped, outputs "Line hangup" to port and calls tmxr_reset_ln - DSR is set when the line is connected via tmxr_poll_conn - DSR is reset when the line is disconnected via mux_reset_ln - CD is set if UNIT_MODEM and DTR is set -------------------------------------------------------------------------------- MPE boot through FP trap produces these statement quantities for the indicated debug levels: - CMD : 37,995 - INCO : 91,134 - CSRW : 336,235 - STATE : 1,419,790 - SERV : 1,374,218 - XFER : 1,340,116 - IOBUS : 5,627,592 cntlr; 3,460,530 iface Debug printouts (DS) in increasing order of verbosity: - 1 : controller operations; one line per command (OPS) - Seek to unit 0 cylinder 0 head 2 sector 21 - Read from unit 2 of 6144 words (48 sectors) - Set File Mask to auto-seek | incremental | cylinder mode | retry 4 - Read With Offset using advanced clock | offset +45 - 2 : controller commands (CMDS) - Unit 0 Clear command started - Unit 0 Clear command completed with Normal Completion status - Unit 1 Read command started - Unit 1 Read command waiting for seek completion - Unit 1 Read autoseek to cylinder 4 head 0 sector 0 - Unit 1 Read command completed with Correctable Data Error - Controller polled drives for attention - Controller interface wait timed out - 3 : interface commands (CSRW) - Channel program started - Control is 005000 (Clear) - Status is SIO OK | Normal Completion | unit 0 - Buffer value 000012 set - RUN/STOP switch set to RUN - 4 : controller command phases (STATE) - Controller unit Request Status parameter phase (service/direct?) entry - Unit 0 Seek seek phase entry - Unit 0 Read data phase entry - Unit 0 Initialize intersector phase entry - Controller unit Clear end phase entry (what would be reported for ICD?) - 5 : controller and interface service calls (SERV) - Unit 0 Seek seek phase delay 41000 service scheduled - Controller Clear end phase delay 1 service scheduled ? Unit 0 Seek seek phase service entered ? Controller Recalibrate end phase service entered (these are always followed by controller entry) (maybe combine this with #3) - 6 : controller data transfers (XFER) - Unit 0 Cold Load Read word 117 is 012003 - Unit 1 Write Full Sector word 2047 is 000377 - 7 : interface and controller invocations (IOBUS) - Received data 005000 with signals PCONTSTB - Controller (idle) received data 005000 with flags CMRDY - Controller (busy) returned data 000000 with functions BUSY - Returned data 000000 with signals CHANACK -------------------------------------------------------------------------------- CPU Arithmetic Trap Handling: We do a lot of code like this: if (RA == 0) /* if dividing by zero */ if (STA & STATUS_T) /* and user traps are enabled */ MICRO_ABORT (trap_Integer_Zero_Divide); /* then trap */ else /* otherwise */ STA |= STATUS_O; /* set the overflow flag */ and: if (check == 0 || check == S16_OVFL_MASK) /* if top 17 bits are all zeros or all ones */ STA = STA & ~STATUS_O; /* then clear the overflow flag */ else { /* otherwise */ STA = STA | STATUS_O; /* an overflow occurred */ if ((STA & STATUS_T) == STATUS_T) /* if trap enabled and overflow present */ CPX1 |= cpx1_INTOVFL; /* signal an interrupt */ } In microcode, all user traps abort the instruction in process by jumping to TRP1 (e.g.), which tests the T bit. If it's clear, STATUS_O is set (regardless of the cause), and execution resumes with the next instruction (via NEXT). If it's set, trap processing continues. The user trap handler should be rewritten to do this. That allows a MICRO_ABORT call to be made unilaterally, as it should be, because the instruction is aborted whether or not the trap is enabled. Integer overflow is usually detected by the ALU hardware, which sets STATUS_O, and if T is also set, then sets CPX1.0, which causes an interrupt when the next instruction executes (so the current instruction finishes normally). The interrupt handler checks for CPX1.0 and jumps to TRP1 (via TR1E). Explicit jumps to TRP1, i.e., instruction aborts, occur if integer overflow is detected in FIXT/FIXR handling, as that doesn't cause STATUS_O to set in hardware. This is equivalent to MICRO_ABORT (trap_Integer_Overflow). Simulated hardware overflow could be a macro: OVERFLOW_IF (condition) ...which would expand to the above. Current instruction execution would continue. -------------------------------------------------------------------------------- Control word / status word macro function conventions: - Assumptions are that control words (CN) are received/input and status words (ST) are returned/output. - Parameter words may be either received/input (PI) or returned/output (PO). - Data words may be either received/input (DI) or returned/output (DO). - CN_ITEM() takes a control word and returns an enumeration, i.e., breaks apart a control word - ST_ITEM() takes an enumeration and returns a status word, i.e., assembles a status word - TO_CN_ITEM() takes an enumeration and returns a control word - ST_TO_ITEM() takes a status word and returns an enumeration - PI_ITEM() takes an input parameter and returns an enumeration - PO_ITEM() takes an enumeration and returns an output parameter - TO_PI_ITEM() takes an enumeration and returns an input parameter - PO_TO_ITEM() takes an output parameter and returns an enumeration - CN_FLAG is a single-bit positioned flag, expressed as an octal value - CN_FIELD_MASK is a multi-bit positioned mask, expressed as an octal value - CN_FIELD_SHIFT is a right shift count, expressed as a decimal value - CN_FIELD() is a macro function that takes a multi-use word and returns an enumeration -------------------------------------------------------------------------------- DS diagnostic: 1. Implement fast and real phase times with these properties: - A single set of FAST times should apply to all ops on a given controller. - FAST times should be configurable by the user via REGs. - REAL might be different for different models on the same controller (array). - Implementation should be similar or common to tapelib too. 2. Implement scriptable responses for diagnostic testing. - Use a table of opcode/cyl/head/sector/status-1 entries. - Pointer set in CNTLR points at table when SET DIAG; reset to NULL for NODIAG. - Pointer causes end_read and end_write to check top table entry for a match. - Pointer moves through table at each match, returning status-1 (incl SPD) if matched. - No further matches once pointer reaches end; RESET DS resets pointer to start. - May have to put in "good" entries if bad call dups an earlier good call. - Table: hard-code in interface, use a specified text file, or build from SET DIAG= entries? - Note that the 3000 diag doesn't appear to check the syndrome words, but the 1000 diag does. Maybe SYN command uses entry following to supply displacement (1) and syndrome words (3). script for 3000 diag: step cyl head sector opcode spd status error name ==== === ==== ====== ====== === ====== ================================ 07 1 0 0 WR D 021 Defective_Track 08 1 0 0 RD D 021 Defective_Track 11 1 0 0 WR S 000 Normal_Completion 12 1 0 0 RD S 000 Normal_Completion 15 1 0 0 WR P 000 Normal_Completion 16 1 0 0 RD P 000 Normal_Completion 24 398 1 47 WFS - 000 Normal_Completion (setup) 24 398 1 47 RD - 017 Correctable_Data_Error 24 398 1 47 SYN - 017 Correctable_Data_Error 27 398 1 30 WFS - 000 Normal_Completion (setup) 27 398 1 30 RD - 017 Correctable_Data_Error 27 398 1 30 SYN - 017 Correctable_Data_Error 31 398 1 25 WFS - 000 Normal_Completion (setup) 31 398 1 25 RD - 017 Correctable_Data_Error 31 398 1 25 SYN - 010 Uncorrectable_Data_Error 48 4 1 32 RD - 017 Correctable_Data_Error 50 4 1 32 RD - 017 Correctable_Data_Error 52 4 1 32 RD - 017 Correctable_Data_Error 62 1 1 0 IN S 000 Normal_Completion (setup) 62 1 1 42 RD S 000 Normal_Completion 62 1 1 43 RD P 000 Normal_Completion 62 1 1 44 RD D 021 Defective_Track 66 1 1 42 RD - 017 Correctable_Data_Error (retry 1) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 2) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 3) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 4) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 5) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 6) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 7) 66 1 1 42 RD - 017 Correctable_Data_Error (retry 8) 77 4 0 37 RD - 017 Correctable_Data_Error - start with a fixed-sized table in DS - add the next table entry: SET DS DIAG=;;;;;{;;;;} cyl/head/sec are decimal always, op/spd/status are octal always if opcode SYN and status CDE, three octal syndrome words and one decimal displacement are required if no more room, return SCPE_MEM (Memory exhausted) - reset the pointer to the start of the table after a run: SET DS DIAG - clear the table SET DS NODIAG - The following steps are expected to fail because of unimplemented features: * 07 write to sector of defective track [275] Address Record to cylinder 1 head 0 sector 0 [326] Initialize defective for 6144 words (48 sectors) [344] Write to cylinder 1 head 0 sector 0 (expects D in status + DEFTRK) * 08 read of sector of defective track [365] Read from cylinder 1 head 0 sector 0 (expects D in status + DEFTRK) * 11 write to sector of spare track [508] Address Record to cylinder 1 head 0 sector 0 [559] Initialize spare for 6144 words (48 sectors) [577] Write to cylinder 1 head 0 sector 0 (expects S in status) * 12 read of sector of spare track [598] Read from cylinder 1 head 0 sector 0 (expects S in status) * 15 write to sector of protected track [741] Address Record to cylinder 1 head 0 sector 0 [792] Unit 0 Initialize protected for 6144 words (48 sectors) [810] Unit 0 Write to cylinder 1 head 0 sector 0 (expects P in status) * 16 read of sector of protected track [831] Unit 0 Read from cylinder 1 head 0 sector 0 (expects P in status) * 24 read of sector with correctable data error [...] Seek to cylinder 398 head 1 sector 47 [...] Write to cylinder 398 head 1 sector 47 [...] Read from cylinder 398 head 1 sector 47 [352] Read Full Sector from cylinder 398 head 1 sector 47 [365] Write Full Sector to cylinder 398 head 1 sector 47 (with changed data words) [396] Read from cylinder 398 head 1 sector 47 (expects CDE) [405] Request Syndrome returns unit 0 | Normal Completion | cylinder 398 head 1 sector 47 | syndrome 000000 000000 000000 000000 [...] Write Full Sector to cylinder 398 head 1 sector 47 [...] Write to cylinder 398 head 1 sector 47 [...] Read from cylinder 398 head 1 sector 47 (expects normal) * 27 read of sector with correctable data error [...] Seek to cylinder 398 head 1 sector 30 [...] Write to cylinder 398 head 1 sector 30 [...] Read from cylinder 398 head 1 sector 30 [488] Read Full Sector from cylinder 398 head 1 sector 30 [501] Write Full Sector to cylinder 398 head 1 sector 30 (with changed ECC words) [520] Read from cylinder 398 head 1 sector 30 (expects CDE) [529] Request Syndrome returns unit 0 | Normal Completion | cylinder 398 head 1 sector 31 | syndrome 000000 000000 000000 000000 [...] Write Full Sector to cylinder 398 head 1 sector 30 [...] Write to cylinder 398 head 1 sector 30 [...] Read from cylinder 398 head 1 sector 30 (expects normal) * 31 read of sector with correctable data error [612] Read Full Sector from cylinder 398 head 1 sector 25 [625] Write Full Sector to cylinder 398 head 1 sector 25 (with changed data words) [644] Read from cylinder 398 head 1 sector 25 (expects CDE) [653] Request Syndrome returns unit 0 | Normal Completion | cylinder 398 head 1 sector 26 | syndrome 000000 000000 000000 000000 * 48 read of sector with correctable data error [961] Read Full Sector from cylinder 4 head 1 sector 32 [974] Write Full Sector to cylinder 4 head 1 sector 32 (with changed sector address) [987] Read from cylinder 4 head 1 sector 32 (expects CDE) * 50 read of sector with correctable data error [1027] Write Full Sector to cylinder 4 head 1 sector 32 (with changed head address) [1040] Read from cylinder 4 head 1 sector 32 (expects CDE) * 52 read of sector with correctable data error [1080] Write Full Sector to cylinder 4 head 1 sector 32 (with changed cylinder address) [1093] Read from cylinder 4 head 1 sector 32 (expects CDE) * 62 read of sector on a spare track (no S bit reported) [1842] Address Record to cylinder 1 head 1 sector 0 [1893] Initialize spare for 6144 words (48 sectors) [1902] Address Record to cylinder 1 head 1 sector 42 [1905] Read from cylinder 1 head 1 sector 42 (expects S in status) * 62 read of sector on a protected track (no P bit reported) [1917] Address Record to cylinder 1 head 1 sector 0 [1968] Initialize protected for 6144 words (48 sectors) [1977] Address Record to cylinder 1 head 1 sector 43 [1980] Read from cylinder 1 head 1 sector 43 (expects P in status) * 62 read of sector on a defective track (no D bit reported) [1992] Address Record to cylinder 1 head 1 sector 0 [2043] Initialize defective for 6144 words (48 sectors) [2052] Address Record to cylinder 1 head 1 sector 44 [2055] Read from cylinder 1 head 1 sector 44 (expects D in status) * 66 multiple retries for read of sector with (un)correctable data error [2157] Read Full Sector from cylinder 1 head 1 sector 42 [2170] Write Full Sector to cylinder 1 head 1 sector 42 (with changed data word) [2177] Set File Mask to incremental seek | surface mode | retries 8 [2183] Read from cylinder 1 head 1 sector 42 (expects CDE after 8 retries) * 77 conditional jump occurs on correctable data error [2252] Read Full Sector from cylinder 4 head 0 sector 37 [2265] Write Full Sector to cylinder 4 head 0 sector 37 (with changed data word) [2278] Set File Mask to incremental seek | cylinder mode | autoseek | retries 1 [2284] Read from cylinder 4 head 0 sector 37 (expects CDE and SETJMP) - D419A diagnostic only tests 7905; there is no offline test for 7906/20/25. - D419A diagnostic does not test Cold Load Read, Read With Offset, or Wakeup, despite the manual indicating that it does. - D419A diagnostic does not test Read Without Verify. - Communicator/3000 5951-6113 Jun-1977 p89 says: "The execution of MASTER CLEAR was permanently disabled in hardware on the control board of the 7905 controller by Disc Memory Division in 1976. All MASTER CLEARs were deleted from this diagnostic or replaced by CLEAR commands, depending on the test section." DS delay calculations: (sector latency for 128-word record = 74.16 usec) delta = abs (uptr->CYL - (int32) target_cylinder) seek = seek_one + delta * (seek_full - seek_one) / drive_props [model].cylinders (for FASTTIME, seek_one = seek_full, and seek_full is nominal seek time) current_sector = fmod (sim_gtime() / sector_full, drive_props [model].sectors) delta = fmod (drive_props [model].sectors + cvptr->sector - current_sector, drive_props [model].sectors) rotate = (int32) (delta * sector_full) (for FASTTIME, rotate = sector_full, and sector_full is nominal rotate time) need times for: - start of sector to end of data area for Verify/Rotate_Phase - end of data area to start of ISG for Read+Write/Data_Phase - start of ISG to start of next sector for end_read+end_write/Intersector_Phase preamble: 12 sync + 3 address data: 128 postamble: 1 crc + 6 ecc isg: 12.76 words (27.222 usec) idle_phase: - activate (rotate_phase, sector_latency) rotate_phase: - start_read - activate (data_phase, command_delay) -- should be data_delay * preamble (15 or 12) data_phase: - transfer word to buffer - if done then activate (intersector_phase, sector_delay) -- should be data_delay * postamble (7 or 0) else activate (data_phase, data_delay) intersector_phase: - end_read - activate (rotate_phase, sector_delay) -- should be data_delay * isg partial sector transfer (length > 0 -> remaining words not accounted for) - delay is (data_delay * (length + postamble)) NOTE: Wakeup (mpe.sim) or Invalid (ds.sim) fails with overhead = 10 and IFGTC as idle_phase function. Seems as though delay (5) to WRTIO is too long; a TIO is done before the status is set in the end_phase. That's because IFGTC asserts CHANSR to continue channel program. Worked around by moving WRTIO to idle_phase for Invalid and IFGTC to end_phase for Wakeup. From IFGTC to WRTIO is 5.8 uS for Invalid command and 14 uS for Wakeup. Clear and Set File Mask delay IFGTC to a later state. device_sr: - set for test_mode + PCMD1 + OUTXFER + RQSRV + IFGTC + IFOUT * ~EOD + IFIN * ~EOD - clear for PCONTSTB + PWRITESTB + CHANSO * ~DEVEND + ~sio_busy CHANSR = device_sr + device_end -------------------------------------------------------------------------------- MS diagnostic: - ISR bit 3 set suppresses SIO listings when errors are encountered. (Documentation is Communicator/3000 5951-6113 Feb-1979 p112.) - SSR bit 8 set produces "correct data listings" when errors are encountered. (bit is EXTRA LISTINGS; Communicator/3000 5951-6113 Oct-1979 p105.) - CRCC generation is discussed here: - RBITE microcode (uc p22) - RBITE flowchart (if p4-48) - CRCC flowchart (if p3-30C) - Tape Error should occur if "dropout of two or more adjacent characters is detected during read-after-write". - Section 3 File Mark tests cannot be simulated. Tests check file mark error detection. An NRZI file mark is a record containing %23 and another %23 eight byte times later (the LRCC). A Tape Error occurs if the intervening bytes are not zeros, or if the second %23 does not occur between 8 and 10.2 byte times after the first. An error causes tape motion to stop. The problem is that there is no way to represent a bad tape mark in the tape image. The error can be detected during the Write Record Without Parity command, but there's no means of recording that fact, such that it will be detected when the image file is read. Could add support for bad tape marks (e.g., MTR_ERF | MTR_TMK, a.k.a. 0x80000000). Would need to add sim_tape_wrbadtmk() and MTSE_BADTMK. Arguably, a bad tape mark can occur on NRZI tapes, so having a metadata marker would be reasonable. Actually, could add LOCAL support for private records (WRZ writes and RDC reads), but it's probably not worth the effort. - Cannot run sections 11, 14, and 15 of the diagnostic. All three sections attempt to write a single record for the full length of the tape. - It seems as though the diagnostic is silently skipping some sections. The cause is unknown. Setting the "halt after each step" option and comparing to the list of steps in the manual, the following steps are do not appear: - 114 - 117 - 150 - 157 - 200 - 204 - 207 - 211 - 223 - 224 - 246 However, many steps in section 2 report errors (currently) but do NOT report "END OF STEP" (e.g., 233-251, 256-257, 265-275). Also, might some of these tests only work on an NRZI (7970B) drive? -------------------------------------------------------------------------------- ATC Timing: - from CIO to Transfer Down is 0.5 * 69.4 usec (34.7 usec avg) - from start bit to stop bit is (baud # + 1) * bits-per-char * 69.4 usec - from stop bit to interrupt request is 69.4 usec - echo is synchronous with receive data, i.e., each bit is echoed contemporaneously. -------------------------------------------------------------------------------- General: - 30051-90001 univ i/f has good writeup on I/O starting on p22 - Communicator/3000 5951-6113 Jan-1982 p43 "Microcode Changes for the Series 64" - SLEUTH/3000 01.03 supports 7905/06/20/25 discs (5951-6113 Jun-1978 p135) - Communicator/3000 5955-1770 Jul-1984 p140 "Changes to Pascal/3000" - 32033-90005 (SORM) table 9-1 "System Failure List", table 11-8 "System Halt Numbers" -------------------------------------------------------------------------------- Performance notes: - 3000: 175 ns uinstr; 4.08 usec/instr; mem 525 ns access/1050 ns cycle; mpxch 950 KB/sec; selch 1.9 MB/sec (non-interleaved) - S II: 175 ns uinstr; 2.57 usec/instr; mem 300 ns access/700 ns cycle; mpxch 1038 KB/sec in, 952 KB/sec out; selch 1.9 MB/sec (non-interleaved) - S III: same as S II - Tried using OutputDebugString in hp_debug(), but performance is terrible. With DebugView not running, doing "xatcd" takes about 6 seconds vs. 2 seconds for file logging. With DebugView running, it takes about 34 seconds. With DebugView minimized, it takes 45 seconds. Oddly, hp3000d takes 12 CPU seconds vs. 1 second for file logging, and there's about 35% idle time. -------------------------------------------------------------------------------- 15 unit user flags are available overall: - sim_tape uses 6 - pdp11_tq uses 5 - pdp11_tu uses 3 - i7094_mt uses 1 - hp2100_ms uses 1 - hp_tapelib uses 3 - hp3000_ms uses 0 -------------------------------------------------------------------------------- The SCMB is required for: - CPU diagnostic section 4 steps 40-41. Note that steps 21, 22, 25, 26 use SCMB instead of MS if available. - multiplexer diagnostic section SIOTEST (uses one or two SCMBs) - selector channel diagnostic ------------------------------------ Right-Hand Stack Operation Execution ------------------------------------ The NEXT microorder initiates the next instruction prefetch. Normally, among other operations during the microcycle containing the NEXT order, NIR is stored in CIR, and an RNP is done to initiate a memory read at the current P value (which is one location beyond the next instruction, or two locations beyond the current instruction). During the following microcycle, P is incremented. This sequence is modified in the presence of a pending interrupt, or when a stack operation includes a non-NOP in the right-hand position. The latter modification is necessary because while two NEXT microorders will be executed, one at the conclusion of each of the stack ops in the current instruction, only one instruction will have been executed. This requires that the NIR-to-CIR transfer and the P increment each occur only once during the two NEXT executions. An additional requirement is that a stack instruction must be interruptable between the two stack ops. If an interrupt is present after the left-hand stack operation has been performed, the machine state must be saved and restored such that the right-hand operation is performed upon EXIT from the interrupt service routine. Status register bit 3 reflects whether the current instruction contains a right-hand stack operation other than NOP. To implement this, the NEXT operation that occurs at the end of the current instruction when a right-hand stack operation is present in NIR will transfer NIR to CIR but will not increment P. The subsequent NEXT operation that occurs after the left-hand stack op completes will increment P but will not transfer NIR to CIR. Finally, if the next instruction is not a stack instruction, the NEXT that completes the right-hand stack op reverts to normal operation, i.e., transferring NIR to CIR and incrementing P. If the next instruction is a stack instruction, then NEXT behaves as above to inhibit the P increment. The omitted P increment ensures that the P decrement that occurs during the interrupt handler (to point P at the instruction to execute when the interrupt service routine completes) will return execution to the same stack instruction. Because status register bit 3 will be set upon return, execution will proceed with the right-hand stack op. The NEXT operation is controlled by the BPENDING, INTRP, NIRTOCIR, and INCP signals, and the STATUS 3 and NEXT Inhibit flip-flops (locations C9-C10 on sheet 1 of the SSF PCA). Detection of the right-hand stack operation is performed by gates U18, U28, and U146 at location F3 on sheet 1 of the CIR PCA. The BPENDING signal asserts if NIR bits 0-3 are zero and bits 10-15 are not zero. Note that this sets up BPENDING before the NIR-to-CIR transfer. The NIRTOCIR signal is generated by gate U134. It asserts if the NEXT signal is asserted and the NEXT Inhibit flip-flop is clear. The NEXT Inhibit flip-flop U114 is cleared when NEXT asserts. It toggles when NEXT asserts with BPENDING asserted and STATUS 3 denied. The STATUS 3 flip-flop U114 is also cleared when NEXT asserts. It toggles when NIRTOCIR, BPENDING, and -INTRP1 assert. That is, it sets coincident with the NIR-to-CIR transfer if the instruction in the NIR is a stack op with a non-NOP right-hand operation. Denial of the STATUS 3 and INTRP signals enables the INC P signal during the microcycle following the NEXT order, i.e., the P register is incremented in the microcycle following the NEXT order unless the STATUS 3 flip-flop is set or an interrupt is present. During linear execution, the NEXT Inhibit and STATUS 3 flip-flops set and clear together. Their actions separate during an interrupt return that occurred between two stack ops. In this case, the EXIT or IXIT instruction restores the status register with status bit 3 set. NIR is loaded with the interrupted stack instruction, so BPENDING is asserted. However, the NEXT Inhibit flip-flop is clear, so the NEXT that exits back to the stack instruction asserts NIRTOCIR and toggles STATUS 3. With STATUS 3 clear, the INC P signal is asserted to increment P at NEXT+1. The logic equations are: NEXTINH FF: J = -STATUS 3 * BPENDING * NEXT * -INTRP1 K = NEXT + STSTATUS C = -FCLK NIRTOCIR = -NEXTINH * NEXT STATUS 3 FF: J = NIRTOCIR * BPENDING * -INTRP1 + STSTATUS * U3 K = NEXT * -INTRP1 + STSTATUS * -U3 C = -FCLK INCP = -STA 3 * NEXT+1 * -INTRP Summary of operation: NIR CIR NEXT and NEXT+1 Actions NEXT Inh Status 3 ------- ------- ----------------------- -------- -------- non-stk x NIR = CIR, P = P + 1 0 0 stk A x NIR = CIR, P = P + 1 0 0 stk A/B x NIR = CIR 1 1 non-stk stk A/B P = P + 1 0 0 stk A/B x NIR = CIR 1 1 stk A/B stk A/B P = P + 1 0 0 stk A/B stk A/B NIR = CIR 1 1 non-stk stk A/B P = P + 1 0 0 stk A/B x NIR = CIR 1 1 non-stk stk A/B interrupt 0 0 .. .. ... stk A/B EXIT NIR = CIR 0 1 non-stk stk A/B P = P + 1 0 0 NEXT N B N S N I -> N S N I E P I T T N -> I T T N X E N A O C -> N A O C NIR CIR T N H 3 C P -> H 3 C P CIR Notes ------- ------- ---------------- ---------- ------- -------------- RSW RSW 0 X 0 0 0 0 L L L L RSW J/K both clear RSW RSW 1 0 0 0 1 0 L L L H RSW J clear, K set ADD,NOP RSW 1 0 0 0 1 0 L L L H ADD,NOP J clear, K set RSW ADD,NOP 1 0 0 0 1 0 L L L H RSW J clear, K set RSW RSW 1 0 0 0 1 0 L L L H RSW J clear, K set RSW RSW 1 0 0 0 1 0 L L L H RSW J clear, K set ADD,ADD RSW 1 1 0 0 1 0 H H L L ADD,ADD J/K both set RSW ADD,ADD 1 0 1 1 0 0 L L L H ADD,ADD J clear, K set RSW ADD,ADD 1 0 0 0 1 0 L L L H RSW J clear, K set RSW RSW 1 0 0 0 1 0 L L L H RSW J clear, K set RSW RSW 1 0 0 0 1 0 L L L H RSW J clear, K set ADD,ADD RSW 1 1 0 0 1 0 H H L L ADD,ADD J/K both set SUB,SUB ADD,ADD 1 1 1 1 0 0 L L L H ADD,ADD J clear, K set SUB,SUB ADD,ADD 1 1 0 0 1 0 H H L L SUB,SUB J/K both set RSW SUB,SUB 1 0 1 1 0 0 L L L H SUB,SUB J clear, K set RSW SUB,SUB 1 0 0 0 1 0 L L L H RSW J clear, K set EXIT RSW 1 0 0 0 1 0 L L L H EXIT J clear, K set ADD,ADD EXIT 1 1 0 1 1 0 L L L H ADD,ADD J/K both set RSW ADD,ADD 1 0 0 0 1 0 L L L H RSW J clear, K set RSW RSW 1 0 0 0 1 0 L L L H RSW J clear, K set A straightforward simulation of the NEXT operation would examine the NIR register contents after each instruction in order to set the NEXT Inhibit flip-flop and bit 3 (R Bit) of the status register. The NEXT Inhibit value would then be used to determine whether or not to copy NIR to CIR and increment P. However, this incurs overhead for each instruction executed, whereas the actions are only required for stack instructions containing non-NOP right-hand operations. A better method is to set the NEXT Inhibit flip-flop in the stack_op executor if the right-hand operation is not a NOP. At this point, P will equal *+2, but decrementing P under these conditions will simulate the action of the inhibited INC P signal. The NEXT Inhibit flip-flop would be cleared in the stack_op executor during execution of the right-hand operation and in the interrupt executor. (This action might be combined as an "instruction pending" flag that may be needed for interruptable instructions.) -------------------------- Interruptable Instructions -------------------------- Several instructions read or write multiple words or bytes and so may take a significant time to execute. These instructions test for interrupts during execution: MOVE, MVB, MVBW, CMPB, SCW, SCU, MVBL, MVLB, MABS, MTDS, MFDS, MDS, and LLSH. The design of these instructions is such that execution may be suspended and resumed simply by exiting and restarting the instruction. In microcode, the MVWS (2353) routine executes an eight-line loop to move each word, taking about 1.4 microseconds per transfer. Within the loop, a TEST microorder is used to check for interrupts. TEST skips if the hardware INTRP signal is asserted, which occurs when any run-time interrupt is present. A positive test jumps to IOD (3000), which decrements P before entering the interrupt handler. As the handler decrements P also, this returns P to point at the interrupted instruction, so that returning from the interrupt will reexecute it. Similar tests and jumps are performed for the other instructions after each word or byte processed, except for SCU and SCW, which test after each word (two bytes) are scanned. Simulation of interruptable instructions is required to pass step 23 of section 4 of the CPU diagnostic. However, an implementation must accommodate these conditions: - Interrupts cannot occur within instructions unless a device interface or event service is called. - An interrupt deferral from a SED 1 must expire during the instruction. - A breakpoint set on the instruction must not trip multiple times due to testing but must trip upon return from an interrupt. - A step through the instruction must not stop multiple times due to testing but must stop on the first instruction of an interrupt service routine. - Tracing instruction execution must not print the instruction multiple times due to testing but must print the instruction upon return from an interrupt. At instruction entry, no interrupts will be pending, as the design of the instruction execution loop ensures that all interrupts are handled before any instructions are executed. So, interrupts during instruction execution can only occur by an existing event that times out and calls an event service routine that calls iop_interrupt, or by a channel service that calls a device interface that calls iop_interrupt or schedules an event that eventually calls iop_interrupt. To simulate interruptable instructions therefore requires that simulation events and/or channel polls occur. Therefore, implementation must involve periodic checks within the move/scan loops of the affected instructions. In general, this would invoke the same operations as are performed in the beginning of the instruction simulation loop, i.e.: - decrement sim_interval, - test for sim_interval = 0 and call to sim_process_event if so, - tests and calls sel_poll and mux_poll if needed, - test interrupt_request_set modified by STATUS_I and int_defer, and call iop_intpoll if so, - test CPX1 against CPX1_IRQ to determine if an interrupt condition exists, and exit from the instruction if so. There are several implementation possibilities: 1. Decrement P and exit the instruction after each word transfer. This is the simplest choice, as it lets the normal instruction loop test for interrupts perform the check. However, it also has the most overhead, as the initial range checks performed by the instruction will be repeated for each word transferred, instead of once per invocation. Also, an "instruction pending" flag would be needed to avoid breakpoint/step/debug problems with repeat execution. 2. Decrement sim_interval after each word transfer and exit when the value is equal to 1. This has the least overhead, as it only exits to the main instruction loop when an event timer is scheduled to expire. However, it does not allow channel service, so after any existing event timers expire, nothing further will occur until the instruction ends. Nor is there a guarantee that the event service routine will generate an interrupt, so the same flag as above is required. 3. Decrement sim_interval after each word transfer and exit after decrementing P when the value is equal to 1, or when sel_request_set, mux_request_set, or interrupt_request_set are non-zero. This has a bit more overhead and still requires an "instruction pending" flag to avoid the problems above, but it allows channel service in addition to event service. It causes a new pass through the channel/irq service check in the instruction loop whenever sim_process_event, sel_poll, mux_poll, or iop_intpoll would be called. If an interrupt occurs, then P is set properly to reenter the instruction after IXIT, and the interrupt handler is called, which clears the "pending" state. Note that an interrupt isn't guaranteed...merely that it's guaranteed NOT to occur if these conditions aren't present. If no interrupt occurred, then EXEC_STATE "pending" skips breakpoint/step checks and debug printing the instruction. 4. Perform the same set of tests and calls as in the main instruction loop and exit after calling cpu_run_mode_interrupt if any interrupt bits are set in CPX1. This has slightly less overhead than implementation 3, as the request sets are only tested once rather than twice if one is set. It also eliminates the need for a "instruction pending" flag, as the routine only exits after the interrupt service routine has been set up and is ready to execute the first instruction of the routine. However, it duplicates the tests and calls in the main instruction loop, as these cannot be put in a common routine because the main loop must test for run mode and ignore run-mode interrupts if the machine is halted. In all cases, one ramification of decrementing sim_interval is that a STEP will expire within the instruction. Therefore, it would be necessary to test whether a step is pending at the start of the instruction, cancel the step timer (while saving the step count), and the reactivate it when exiting for instruction completion or when an interrupt will be taken. (There is an SCP routine, sim_cancel_step, that will cancel the STEP timer, but not one to reactivate it. A reactivation routine could be added, along with a function to return the remaining step activation time, as the step unit declaration is local to SCP. Actually, a better solution would be to change the return type of sim_cancel_step to an int32 to return the remaining activation time, or zero if STEP is not active. This is reasonable because sim_cancel, whose return value sim_cancel_stop returns, always returns SCPE_OK, and no call actually tests the return value.) (The LGP simulator calls sim_cancel_step at the start of its instruction loop and explicitly counts down sim_step in the loop. It does this to be able to process events separately from instruction steps, which is exploited when delaying instruction execution. We could do the same.) -------------- System Startup -------------- Machine code line numbers are from mpedebug2.cpu.log. INITIAL.MAINSEG4 (S00) - Master clear on the console: load 7 / load 100000 / CIO 1 (35,644) [07.176532 CIO 1] - Exit to PROGENITOR: ASSEMBLE (DISP) (line 35,751) [07.176607 DISP] PROGENITOR (S09) - note that this involves a lot of absent code segment traps - Start at 00.154477 with SAVE'LOG'INFO := ABSYS'LOGINFO - Initialize system console and system disc: INITIO(1) (4165) [00.154522 LDI 1 / 00.154523 PCAL 37 (3,521,911)] - Checkpoint: MOVE PROCNAME:="INITNLS " (4225) [00.154604 MVB PB,3 (6,883,186)] - Checkpoint: ASSEMBLE(PCAL 0) (4231) [00.154616 PCAL 0 (7,926,451)] - Zero the CPU process clock: TOS := 0 / ASSEMBLE (SCLK) (4245) [00.154621 ZERO,NOP / 00.154622 SCLK (8,342,647)] - Set the date and time: INITDATETIME (4251) [00.154623 PCAL 13 (8,342,653)] HARDRES.INITIO (S55) - Called with FLAG = TRUE PROCEDURE INITIO (FLAG) (5721) [00.035276 ADDS 6 (3,521,929)] - Get console LDEV (= 20): CONSOLE := CONSOL.LDEVF (5752) [00.035304 STOR Q+4 (3,522,047)] - Initialize the system disc: I := SYSDISC / INITDEV (5755) [00.035312 BR P-35 (3,522,068)] - Initialize the system console: I := CONSOLE / INITDEV (5757) [00.035317 BR P-42 (3,522,140)] - Calls ATTACHIO with SPEED = 000300, CONSOLE = 20, TYPE = 10 TOS := ATTACHIO(CONSOLE,0,0,0,24,0,TYPE,SPEED,1) (5761) [00.035341 PCAL 61] Return is RA = 000000, RB = 000004 - Calls ATTACHIO again because RB.(13:3) <> 1 IF TOS.(13:3) <> 1 THEN <> ATTACHIO(CONSOLE,0,0,0,24,0,%37,SPEED,1) [00.035356 PCAL 61] Return is RA = 000000, RB = 000004 ==> SEEMS AS THOUGH TERMTYPE IS WRONG IN BOTH CASES! RETURN CODE 04 = "INVALID REQUEST, FUNCTION OR PARAMETER" SPEED SEEMS TO BE WRONG (SHOULD BE CPS, BUT %300 = 192) >>> IF SPEED IS SET CORRECTLY, DATE AND TIME PROMPTS WORK !!! - Exit is 00.035401 EXIT 1 HARDRES.ATTACHIO (PA8) - Entry at 00.046562 ADDS 20 - Turns off user traps TRAPSOFF [00.046563 PSHR STATUS / TRBC #2 / SETR STATUS] - Expands the stack (but the stack is already big enough) ASMB(ADDS 255; SUBS 255) (2537) [00.046566 ADDS 377 / SUBS 377] - tests for disc processing (is not) - Calls P'ATTACHIO ATTACHIO := P'ATTACHIO(LDEV, QMISC, DSTX, ADDR, FNCT, CNT, P1, P2, FLAGS, EXTBASE, EXTSIZE) (2654) [00.047001 PCAL 62] - Exit at 00.047003 EXIT 11 HARDRES.P'ATTACHIO (PA8) - Entry at 00.047006 PSHR STATUS - Turns off user traps TRAPSOFF (1827) [00.047006 PSHR STATUS / TRBC #2 / SETR STATUS] - Expands the stack (but the stack is already big enough) ASMB(ADDS 255;SUBS 255) (1829) [00.047011 ADDS 377 / SUBS 375] --> a bit strange that the subtraction is %375 and not %377 - Checkpoint: PUSH(DB) (1831) [00.047013 PSHR DB] - Checkpoint: [00.047062 PCAL 73] - Checkpoint: TOS := STACKDST; TOS.STACKFLAG := 1; DSTX := TOS (1875) [00.047103 LOAD Q+10 / TSBC #0 / STOR Q-16] - Checkpoint: PDISABLE (1898) [00.047171 SED 0] - Checkpoint: ASMB( BR *+1,X (1923) [00.047163 BR P+1,X] - Checkpoint: DISABLE (1942) [00.047213 SED 0] - Call AWAKEIO to call the monitor AWAKEIO( *, * ) (2052) [00.047356 PCAL 31] - Call RETURNIOQ RETURNIOQ(Q'ENTRY'INDEX) (2160) [00.047704 PCAL 67] - Exit at 00.047733 EXIT 15 HARDRES.AWAKEIO (PA8) - Entry is 00.040307 PSHR STATUS - Branch to the handler for code 6 ("call monitor") ASMB( BR * +1, X (5564) [00.040320 BR P+1,X] - Calls the device monitor with DITP = 002434 and FLAGS = 010604 CALLMNTR: TOS := @DITP (5596) [00.040373 LOAD Q-5 (3,579,342)] - Exit is 00.040400 EXIT 2 TERMIOM.IOTERM0 (S22) - Entry is [stop] - [stopped investigation here...] HARDRES.INITDEV (S55) - Called with I = 1 - Sets DITP to 002314 (DB-relative) @DITP := LPDT(I&LSL(1)) (5741) [00.035261 STOR Q+5] - The disc driver has no initialization routine IF <> THEN ASSEMBLE(PCAL 0) ELSE DDEL (5747) [00.035274 DDEL,NOP (3,522,122)] - Exit at 00.035275 SXIT 0 HARDRES.INITDEV (S55) - Called with I = 20 - Sets DITP to 002434 (DB-relative) @DITP := LPDT(I&LSL(1)) (5741) [00.035261 STOR Q+5] - The console driver has an initialization routine (label is 132432) IF <> THEN ASSEMBLE(PCAL 0) ELSE DDEL (5747) [00.035272 PCAL 0 (3,522,193)] Calls NRIO.TERMINIT - Exit at 00.035275 SXIT 0 NRIO.TERMINIT (S62) - Entry at 01.014007 LDXI 5 - Sets output speed (= 0) DITP(DSPEED).OUTSPEED := DITP(DLAST).TERMSPEED (691) [01.014032 LDXI 11 (3,576,895)] - Sets terminal type (= 10) DITP(DTYPE).TTYPE := DITP(DLAST).TERMINALTYPE (692) [01.014042 LDXI 7] - Sets the control word (= 000602) DITP(DCNTRL) := TOS&LSL(9)+%602 (698) [01.014066 LSL #9] - calls INITCHANNEL INITCHANNEL(DITP) (709) [01.014130 PCAL 66] - sets up diagnose channels for speed sensing (lines 712-728) does WIO (120413) [1200 baud] and CIO (020002) [channel 16] does WIO (120427) [ 600 baud] and CIO (021002) [channel 17] does WIO (120457) [ 300 baud] and CIO (022002) [channel 18] does WIO (120537) [ 150 baud] and CIO (023002) [channel 19] does WIO (121202) [ 110 baud] and CIO (024002) [channel 20] - Exit at 01.014165 EXIT 1 NRIO.INITCHANNEL (S62) - Entry at 01.014166 ZERO,NOP - calls DSETCONTROL DSETCONTROL(INITDSET,DITP) [01.014170 PCAL 133] - calls MPXCONTROL to initialize the receive channel (ECHOOFF = 0) MPXCONTROL(ECHOOFF,DITP) [01.014173 PCAL 135] does WIO (124405) and CIO (000602) - calls MPXCONTROL to initialize the send channel (WRTCHAN = -1) MPXCONTROL(WRTCHAN,DITP) [01.014176 PCAL 135] does WIO (170405) and CIO (000602) HARDRES.DSETCONTROL (S55) - Entry at 00.063360 ADDS 1 - Loads modem type TOS := (DITP(DMODEM).MTYPE).(14:2) (1902) - Returns if type is zero (= 0) IF = THEN RETURN; << NOT ON A DSET >> - So DSETCONTROL does nothing if not a modem connection. HARDRES.MPXCONTROL (S55) with FUNCTION = 0 (read with echo off) - Entry is 00.063470 LDXI 5 - Sets TOS to parameter corresponding to speed 0, 2400 baud (120405) TOS := SPEED(TOS.OUTSPEED) [00.063513 LOAD P-33,X] - Calls MPXWRITE to send control word (124405) to the ATC MPXWRITE( *, DITP) [00.063545 PCAL 135] HARDRES.MPXWRITE (S55) - Entry is [00.063547 LDXI 5] with a data word and a DITP - Does a WIO to the ATC ASMB( WIO 1 ) [00.063610 WIO 1] - Does a CIO to the ATC ASMB( CIO 1 ) [00.063621 CIO 1] And 00.156764 PCAL 52 should be GENMSG(SYSSET,DATEQUES,,,,,,,,,,,%100000). -------------------------------------------------------------------------------- unsent message to mark: Hi Mark, Given an OS (Windows) that reports a 1 msec timer resolution and a device that establishes a calibrated clock of 1 msec duration, is it possible to have the corresponding CPU idle? When I try this in a new simulator I'm developing, the calibrated clock seems to settle down to about 55,000 instructions per tick during the "stability" period. At the end of the period, the CPU idles successfully for one second. After that, though, sim_idle() reports failure, and the calibrated clock then resets to about 14,000 instructions per tick. Nothing has changed in the instruction loop during this time, which is looping while executing a "wait for interrupt" instruction. If I change only the calibrated clock time to 10 msec duration, idling works as expected, and the instructions per tick before and after idling starts are about the same (at about 550,000 instructions per second, as expected). In both cases, the clock is the only unit in the timer queue. It seems that sim_idle() fails because the clock unit has less than the number of instructions per msec remaining, but I don't understand why the instructions per tick drops precipitously after the stability period expires. I've tried instrumenting the idle and clock service routines to try to understand this, but that affects the timing significantly. Using a debugger is even worse. In general, then, is the idle package compatible with calibrated clocks that are of the same resolution as the system timer resolution?