-------------------------------------------------------------------------------- For FASTTIME, the data phase activation was moved from the data phase service to the PREADSTB/PWRITESTB processing. This would synchronize buffer_word transfers with channel service, so overrun could not occur. Then the data phase activation time would simply become the delay between channel transfer and controller pickup and so could be minimal. Without this, the FASTTIME data time is still the synchronous transfer time and so cannot be too fast, or an overrun will occur. As a practical matter, though, the tape controller has the highest MPX priority, so it will always be serviced immediately after SRn is asserted. Here are the original comments from the ms_interface routine (hp3000_ms.c): // THIS IS NO LONGER IMPLEMENTED; DO WE WANT TO REIMPLEMENT? In REALTIME mode, read data phase processing stores the next data word from the tape buffer into the data register, clears the data flag, sets the channel service request, and schedules the next data phase service. PREADSTB returns the data register word to the multiplexer channel and sets the data flag. Channel service must occur before the next controller service; if data phase processing starts with the data flag clear, an overrun (timing) error is indicated. In this mode, as in hardware, the READNEXTWD signal is ignored. In FASTTIME mode, the sequence is the same, except that scheduling the next data phase service is delayed until the READNEXTWD signal is received. As READNEXTWD is asserted concurrently with PREADSTB, the tape data transfer essentially slows down to match the channel data transfer rate, so an overrun cannot occur. This allows the data transfer time to be reduced to as little as one instruction time. Write commands behave similarly. TOGGLEOUTXFER assertion schedules the start phase. PWRITESTB processing stores the channel data word in the data register and sets the data flag. Data phase processing copies the word from the data register to the tape buffer, clears the data flag, and sets the channel service request. In REALTIME mode, the next data phase is scheduled, and an underrun (timing) error occurs if phase processing begins with the data flag set. In FASTTIME mode, data phase scheduling is delayed until PWRITESTB processing, so an underrun cannot occur. // END -------------------------------------------------------------------------------- Phase Wait Times ~~~~~~~~~~~~~~~~ idle -> wait: (not scheduled) idle -> start: overhead (if no drive access) overhead + bot_start (if access at BOT) overhead + ir_start (if access not at BOT) wait -> start: overhead + bot_start (if access at BOT) overhead + ir_start (if access not at BOT) start -> stop ir_start (Clear_Controller) rewind_start (if rewinding at BOT) start -> traverse: gaplen * data_xfer (if gap) rewind_start + (pos * rewind_rate) / bpi (if rewinding) start -> data: 2 * data_xfer (if no gap and not spacing) length * data_xfer (if no gap and spacing) traverse -> data: 2 * data_xfer (if not writing a gap) traverse -> stop: ir_start (if writing a gap or error occurred) rewind_stop (if rewind) traverse -> start: 2 * data_xfer (if spacing and runaway) data -> stop: (length - index) * data_xfer + ir_start (if read) ir_start (otherwise) data -> data: 2 * data_xfer (data transfer) data -> start: 2 * ir_start (FSF, BSF) Rearranged by next state ~~~~~~~~~~~~~~~~~~~~~~~~ idle -> wait: (not scheduled) ***** (any) -> error: ir_start (all failures) ***** idle -> start: overhead (if no drive access) overhead + bot_start (if access at BOT) overhead + ir_start (if access not at BOT) wait -> start: overhead + bot_start (if access at BOT) overhead + ir_start (if access not at BOT) traverse -> start: 2 * data_xfer (if spacing and runaway) data -> start: 2 * ir_start (FSF, BSF) ***** start -> traverse: gaplen * data_xfer (if gap) rewind_start + (pos * rewind_rate) / bpi (if rewinding) ***** start -> data: 2 * data_xfer (if no gap and not spacing) length * data_xfer (if no gap and spacing) traverse -> data: 2 * data_xfer (if not writing a gap) data -> data: 2 * data_xfer (data transfer) ***** start -> stop ir_start (Clear_Controller) rewind_start (if rewinding at BOT) traverse -> stop: ir_start (if writing a gap or error occurred) rewind_stop (if rewind) data -> stop: (length - index) * data_xfer + ir_start (if read) ir_start (otherwise) ==> maybe switch on next_phase with conditions on uptr->PHASE? -------------------------------------------------------------------------------- A master reset is generated either by an I/O Reset signal or a Programmed Master Clear (CIO bit 0). It performs these actions: - asserts CLR to the microprocessor, restarting it from ROM address 0 - clears the PAR ERR, XFER ERROR, INT ACT, and INT REQ flip-flops - clears the unit select flip-flops, selecting unit 0 - sets the MASK flip-flop - clears the SIO OK, INXFER, OUTXFER, SR, and SRB flip-flops (same as CBL, except that ESR is not cleared) -------------------------------------------------------------------------------- static CNTLR_IFN_IBUS check_status (CVPTR cvptr, UNIT *uptr, TAPELIB_CALL lib_call) --> static t_bool call_simlib (CVPTR cvptr, UNIT *uptr, TAPELIB_CALL lib_call, t_mtrlnt parameter, CNTLR_IFN_IBUS *result) use: if (call_simlib (cvptr, uptr, lib_read_fwd, TL_MAXREC, &outbound)) { ... } or maybe: outbound = call_simlib (cvptr, uptr, lib_read_fwd, TL_MAXREC); if ((outbound & SCPE) == NOFLAGS) { ... } ...but "bad but recoverable" returns must have SCPE | SCPE_OK to differentiate from good returns. Then the decl would be: static CNTLR_IFN_IBUS call_simlib (CVPTR cvptr, UNIT *uptr, TAPELIB_CALL lib_call, t_mtrlnt parameter); calls: - sim_tape_rdrecf (uptr, cvptr->buffer, &cvptr->length, TL_MAXREC); - sim_tape_wrgap (uptr, pptr->gap_size); - sim_tape_sprecf (uptr, &cvptr->length); - sim_tape_sprecr (uptr, &cvptr->length); - sim_tape_wrtmk (uptr); - sim_tape_wrrecf (uptr, cvptr->buffer, error_flag | cvptr->length); - sim_tape_rewind (uptr); parameters are: - maximum record length (sim_tape_rdrecf, t_mtrlnt) -- [t_mtrlnt renames uint32] - gap size in tenths (sim_tape_wrgap, uint32) - error flag (sim_tape_wrrecf, t_mtrlnt) other call parameters are inferred -------------------------------------------------------------------------------- WRR: start -> traverse (if initial gap written) -> data -> stop FSF: start -> traverse (if gap present) -> data (no transfer) -> stop -------------------------------------------------------------------------------- confirm sim_tape EOM bug fix: - EOM at byte 0 first read - EOM at byte 0 second read - PEOF at first read - PEOF at second read test XFERERROR in MS -------------------------------------------------------------------------------- Tape library fatal errors: MTSE_FMT: /* illegal format */ result = SCPE_FMT; /* and stop with a Format error */ MTSE_UNATT: /* unit unattached */ result = SCPE_UNATT; /* and stop with Unit not attached */ MTSE_INVRL: /* invalid record length */ result = SCPE_MTRLNT; /* and stop with Invalid magtape record length */ MTSE_IOERR: /* host system I/O error */ result = SCPE_IOERR; /* this is a setting option for hp2100_ms (STOP_IOE) */ MTSE_WRP: /* write protected (should never occur on a library call */ result = SCPE_NO; /* and stop with Read only operation not allowed */ default: /* unanticipated error (e.g., a new error code was added) */ result = SCPE_IERR; /* and stop with an Internal error */ All of these return Tape Error status to abort the channel program. Maybe add an SCPE function to return the error code via the event service call? Resuming will continue into the Error_Phase to return Tape Error Note that the host may retry, so must be prepared to issue the error again! -------------------------------------------------------------------------------- DS controller does: - if uptr OR controller is Busy_State, then continue command if uptr is null AND controller unit phase is Idle_Phase, then exit else process; uptr = controller unit - else if CMRDY, then start command MS controller does: - if uptr OR controller is Busy_State, then continue command always process; if uptr is null, then uptr = controller unit - else if CMRDY or CMXEQ, then start command Maybe: - if uptr OR cvptr->state == Wait_State ? MS call_controller: - [null] DRESETINT and CMRDY and ~IRQ (command held off until IAK) - start ONLY, NOT continue (cntlr may be busy, or selected unit may be rewinding!) - don't call if sio_busy, i.e., ~INTOK - [null] TOGGLESIOOK and ~SIOBUSY (poll drives held off by ~INTOK) - start and poll ONLY, NOT continue (selected unit may be rewinding!) - if sio_busy cleared, then controller can't be busy, although unit might be - [uptr] TOGGLEINXFER and INXFERFF (read command is waiting for channel start) - [uptr] TOGGLEOUTXFER and OUTXFERFF (write command is waiting for channel start) - continue command if selected unit is Wait_Phase, else command reject, NOT start - will enter continue if Wait_Phase because cntlr is busy - if cntlr not busy, must command reject (e.g., Control/SEL0 + Read) - won't enter continue or start; maybe reject if won't enter poll too? - [uptr] READNEXTWD (to abort a chained read that ended with DEVEND) - command reject ONLY (rejects because uptr->PHASE = Idle_Phase) - cntlr will be idle, because Read Record command has completed ==> add a "continue" flag? that plus NULL uptr sets uptr to current unit? - [null] PCONTSTB (start a new command) - start ONLY, NOT continue (selected unit may be rewinding!) - [uptr] ms_service (continue the command, regardless of CMRDY) - continue command ONLY, NOT start, regardless of CMRDY - [OK: will continue] - [null] ms_attach and SCPE_INCOMP (to poll drives ONLY) - [null] ms_set_online and SCPE_INCOMP (to poll drives ONLY) - SCMP_INCOMP sets only if Idle_State - poll ONLY, NOT start, NOT continue (selected unit may be rewinding!) - [OK: will not continue because controller is idle] - poll only if INTOK? ==> INTOK wants to be ~SIOBUSY * ~INTREQ * ~INTACT! won't poll unless SIO OK is true and (INTREQ + INTACT) is false waits in tight loop for (INTREQ + INTACT) to go false -------------------------------------------------------------------------------- Command rejection reasons: reject (1000; occurs on OTA, not STC): - unit not ready for any command requiring tape motion (i.e., other than Clear or Select) - write command with no write ring - Select while the controller is busy - BSR or BSF with tape at load point Reject reasons (3000; 28C from 2, 3, 14, 29, 30) - unit not ready for any command requiring tape motion (i.e., other than Select) - write command with no write ring - illegal command opcode - illegal bits set in control word - TOGGLEOUTXFER without a write data command in process [*] - TOGGLEINXFER without a read data command in process - PCONTSTB with input_xfer or output_xfer set - a command other than Clear while the controller is busy [*] so a WFM Control order followed by a Write order fails! -------------------------------------------------------------------------------- Flags: - CMRDY = command is ready for examination - CMXEQ = command is ready for execution - DTRDY = write data is ready - EOD = the data transfer has ended - INTOK = ? - OVRUN = ? - XFRNG = a channel error terminates the command in process The 1000 interface does CMRDY on OTA and CMXEQ on STC. The 3000 interface does CMRDY | CMXEQ on PCONTSTB. The command is checked for validity with CMRDY and executed with CMXEQ. Functions: - IFIN = read data has been provided - IFOUT = write data has been accepted - IFGTC = the command has started - RQSRV = channel service has been requested - DVEND = a read transfer has ended before the word count expired - STINT = an interrupt has been requested WRTIO won't work, because some of the status is dynamic. -------------------------------------------------------------------------------- HP 3000: 0 | 1 2 3 | 4 5 6 | 7 8 9 |10 11 12 |13 14 15 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | - - - - - - | unit | 0 0 0 0 | command code | PIO word 2 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ HP 1000: 15 |14 13 12 |11 10 9 | 8 7 6 | 5 4 3 | 2 1 0 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | - - - | unit | S | command code | OTx +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Where: S = enable unit select -------------------------------------------------------------------------------- Disc timing uses: typedef struct { CNTLR_TYPE type; /* controller type */ DRIVE_TYPE drive; /* drive type */ int32 seek_one; /* track-to-track seek time */ int32 seek_full; /* full-stroke seek time */ int32 sector_full; /* full sector rotation time */ int32 data_xfer; /* per-word data transfer time */ int32 intersector_gap; /* intersector gap time */ int32 overhead; /* controller execution overhead */ } DELAY_PROPS; ...and: DELAY_PROPS *fastptr; /* pointer to the FASTTIME delays */ const DELAY_PROPS *dlyptr; /* current delay property pointer */ ...in CNTLR_VARS. The controller uses dlyptr exclusively. dl_set_timing sets dlyptr either to fastptr or to point at the desired entry in real_times: static const DELAY_PROPS real_times [CNTLR_COUNT]; This works because all drives on a given controller have the same delay times. That isn't true for the 3000 tape controller, which mixes 7970 B/E units. But we could set dlyptr in start_command, as the tape controller stays connected to a unit until the command completes (or until a rewind is started). Note: disc separates DRIVE_PROPS from DELAY_PROPS. Tape uses: typedef struct { CNTLR_TYPE controller; /* controller model */ DRIVE_TYPE drive; /* tape drive model */ uint32 density; /* tape drive density code */ uint32 bpi; /* recording density in bits per inch */ uint32 gap_size; /* erase gap size in tenths of an inch */ uint32 rewind_ipi; /* rewind speed in time per inch */ int32 cntlr_time; /* controller command start delay time */ int32 rewind_time; /* rewind initiation time */ int32 bot_time; /* beginning of tape gap traverse time */ int32 ir_time; /* interrecord traverse time */ int32 data_time; /* data byte transfer delay time */ } DRIVE_PROPS; The last six fields are the timing values. -------------------------------------------------------------------------------- The 13037 disc controller is a better simulation model than the current tapelib model. The latter requires a lot of knowledge within the interface, whereas the former absracts the operations. We could model the tape controller the same way, i.e., with CNTLR_FLAGs and an IFN_BUS return (these would exist only in simulation, without hardware counterparts). ds is: CNTLR_IFN_IBUS dl_controller (CVPTR cvptr, UNIT *uptr, CNTLR_FLAG_SET flags, CNTLR_IBUS data) ms maybe: uint16 ml_controller (CVPTR cvptr, UNIT *uptr, uint16 data) with: - ml_start_command => (t_bool) ml_controller (cvptr, NULL, opcode) - ml_service_drive => read_data = ml_controller (cvptr, uptr, write_data) - eliminate data_register and data_flag, and add buffer_word to interface but how do we communicate EOT, XFERERROR, etc.? -------------------------------------------------------------------------------- Controller unit: - 3000 needs to delay interrupt (for drive stop time) from command reject e.g., Read issued, but all 4 drives are rewinding - 3000 needs to delay Unit Select (but only if we can't complete immediately) - for non-HPIB, is dev.units [dev.numunits - 1] - for HPIB, is dev.units [cvptr->unit_selected] - MAYBE THIS ISN'T NEEDED (reject delay can be handled locally in MS device) 1000: - crystal osc is 7.2 MHz - OTA/B outputs the command to the interface; STC starts it - Unit Select completes within OTA time (no STC used) - Clear requires STC and completes "almost immediately but does not exceed 10 ms" (13183 page 3-4) - Rewind not at BOT clears interface busy within 560 us (sets command FF) - Rewind at BOT is "ignored" but takes 560 us (1 SCP) to clear interface busy - Command reject sets on OTA; STC is ignored if reject is set, and the flag will not be set - NOTE: CRCC/LRCC diag tests are made on both reads and writes; does LIA DC to pick up CRCC (upper) and LRCC (lower) bytes. Also uses RRR (read reverse) for explicit check for test 23 subtest 3. RRR is not currently supported by MSC. RRR must read the PRECEDING record; but does tape mark, e.g., read the same backward? 3000: - microprocessor clock period is 434 ns - All commands are output and executed with PCONTSTB, including Unit Select - Unit Select typically takes about 4 usec. - Clear isn't a command but rather a signal - Command reject interrupt occurs 8.33 msec (tape stop time) after status is posted DS states: - Idle_Phase - Parameter_Phase - Seek_Phase - Rotate_Phase - Data_Phase - Intersector_Phase - End_Phase MS states [?]: - Idle_Phase - Init_Phase - Start_Phase - Traverse_Phase - Data_Phase - End_Phase -------------------------------------------------------------------------------- The 3000 tape controller microinstruction time is 434 nanoseconds. A Select Unit command executes in about 10 instructions from PCONTSTB to select output and SR assertion, which is about 1-2 CPU instructions. The unit status comprises all fields except SIO OK, Interrupt Request, and the Error Field. Per page 2-15 of the maintenance manual, during the idle state when no SIO program is active, the interface continuously selects one unit after another to look for a change from Not Ready to Ready status. Therefore, the tape unit selected bits will be seen to change continuously. [tested by the diagnostic?] All error codes cause the subsystem to terminate the I/O program in progress (by not issuing an SR) and cause an interrupt. All error codes are cleared to the No Error state whenever a new SIO program is started. => An error termination occurs by not asserting SR and asserting INTREQ. That's effectively what happens when an I/O program executes an End/Interrupt instruction. Rejects and unit ready cause an interrupt. Once an interrupt is asserted, the controller sits in a tight loop waiting for the interrupt to be reset. When it is, the controller returns to the idle loop and looks for the next command. Reject reasons (28C from 2, 3, 14, 29, 30) - illegal command or reserved bits not 0 - unit not ready for any command other than Select - write cmd (WRFWD) with no write ring - INXFER or OUTXFER set when expecting a control order - OUTXFER set after read cmd control order - INXFER set after write cmd control order - control order received after read cmd (order must be Read) - control order received after write cmd (order must be Write) Interrupt conditions (28AA from 7, 24) - a tape unit goes NRDY->RDY (only checked if no SIO program) - tape runaway error - all other "interrupt conditions" (F15 set, i.e., cmd exit with error) INTER routine sets the Interrupt Request FF and sets the "Clear Bus Logic" (-CLRIL) signal. Then the controller sits in a tight loop until the interrupt is reset (the test is Interrupt Request OR Interrupt Active). Once it is, it returns to the Wait loop (stop tape and then go to Continue loop). While the controller is waiting for INTACK, a PCONTSTB will store the control word and will set the CMD ENB flip-flop. So when the INTACK arrives and the controller returns to the main loop, the command will be recognized. when is error status, e.g., Unit Interrupt, cleared? microcode does: - set unit interrupt FF - loop while interrupt_request + interrupt_active - reset unit interrupt FF - go to idle loop so unit interrupt is cleared when IRQREQ and IRQACT are both reset: + master_clear + DCONTSTB with CN_RIN and interrupt_active CLEAR + DRESETINT NOTE: while they're set, the controller is non-responsive to commands. Once an interrupt is requested, the microcode sits in a tight loop until the interrupt status bit is cleared. During this time, a new command will be accepted but will not run until interrupt servicing completes. Reset conditions: 1. "Clear bus logic" 2. "Master reset" A clear bus logic is generated either by a microprocessor D02 (XFACE) output to MB6 or by a master reset. A CBL: - clears the ESR, SIO OK, INXFER, OUTXFER, SR, and SRB flip-flops A master reset is generated either by an I/O Reset signal or a Programmed Master Clear (CIO bit 0). It performs these actions: - clears the PAR ERR, XFER ERROR, INT ACT, and INT REQ flip-flops - clears the unit select flip-flops, selecting unit 0 - sets the MASK flip-flop - asserts CLR to the microprocessor, restarting it from ROM address 0 - clears the SIO OK, INXFER, OUTXFER, SR, and SRB flip-flops (same as CBL, except that ESR is not cleared) The controller start code is entered at power up or after a master reset. It: - clears unit ready flip-flops and bus logic - selects unit 0 - stops tape operations The controller continue loop: - sits in a loop until IRQ is clear The controller main loop: - if INXFER or OUTXFER FF is set, go to Reject (2) - if no PCONSTB, scans a unit for NRDY->RDY change and then loops If an interrupt is to be generated: - sets INTREQ FF - sits in a tight loop until IRQ is clear - stops tape operation - go to Continue loop Once a PCONSTB is seen: - clear status and odd byte FF - if Select: - select indicated unit - assert DSR - go to Continue - if unit not ready, go to Reject (3) - if reserved bits (8:11) are not 0000, go to Reject (3) - if RR, RRC, FSF, or FSR, go to RDFWD (14H) - if WR, GAP, WRZ, or WFM, go to WRFWD (29J) - if cmd = 01-03 (illegal cmd), go to Reject (3) - if BSR or BSF, go to RDBKD (9L) - if Write Status set, erase a bit of tape before continuing - must be REW or RWO; start rewinding and set unit offline if RWO - set DSR to get next command - return to Continue loop Scan loop: - returns to Main if SIO FF set - sits in a loop until IRQ is clear - select next unit in a round-robin fashion - if NRDY->RDY change, set interrupt, else return to main loop Read commands (RDR, RDC): - set DSR - if PCONSTB or OUTXFER, cmd reject else loop while waiting for INXFER - read and transfer data - if data overrun, set timing error but continue through record - if tape mark, set EOF, no error - if word count > record length, set DEVEND, no error Write commands (WR, WRZ, GAP, WFM): - if write protected, reject - if WR or WRZ, set DSR (if PE drive, WRZ decodes as WR) if PCONSTB or INXFER, cmd reject else loop while waiting for OUTXFER - if LP, write initial gap (3.75" NRZI/PE) - if WR or WRZ, read and transfer data - if GAP, write gap (3.75" NRZI/PE) - if WFM, write file mark BSF, BSR commands: - if at LP, ignore, else move Read commands and data chaining: - Control order, RR - Read order must follow; if Write or Control order, cmd reject - at EOR, if word count > record length, sets DEVEND, else sets DSR; returns to continue loop Per page 2-11 of the maintenance manual, if data chaining is active, and a chained read completes with a record shorter than the transfer length, a Command Reject will occur. This is because DEVEND for a chained read leaves INXFER set, and the command wait loop checks for INXFER (or OUTXFER) set and will abort if it is. Hardware does not use EOT. -------------------------------------------------------------------------------- debug logging: DS iobus: Received data 001057 with signals PWRITESTB | TOGGLEOUTXFER | EOT DS csrw: Control is 001000 (Seek) DS state: Controller unit Seek parameter phase interface entry DS ops: Unit 0 Seek to cylinder 410 head 2 sector 47 DS cmds: Unit 0 Seek command completed with Normal Completion status DS serv: Unit 0 Seek seek phase delay 41000 service scheduled DS ops: Unit 0 Initialize of 6144 words (48 sectors) DS xfer: Unit 0 Initialize word 1 is 000000 DS csrw: Status is Normal Completion | unit 0 DS csrw: Channel program ended MS cmds: Channel program started >> csrw: Channel program started MS iobus: Received data 000000 with signals ACKSR | PCONTSTB >> ok MS cmds: Unit 0 control is Write Record >> csrw: Control is master clear >> csrw: Control is Select Unit 2 >> csrw: Control is Write Record | unit 2 MS serv: Unit 0 delay 10 initiation phase service scheduled >> serv: Unit 0 Write Record initiation phase delay 10 service scheduled MS serv: Unit 0 Write Record initiation phase service entered >> state: Unit 0 Write Record initiation phase service entered MS cmds: Unit 0 Write Record tape command started at position 6180 >> cmds: Unit 0 Write Record command started at position 6180 MS new: >> xfer: Unit 0 Write Record word 1 is 041511 MS xfer: Unit 0 write of 12-word record succeeded >> ops: Unit 0 Write Record of 12 words MS cmds: Unit 0 Write Record tape command completed at position 6212 >> cmds: Unit 0 Write Record command completed at position 6212 with No Error status for %s in (func cmd csrw phase serv xfer iobus) do findstr /r /c:"DS *%s:" debug-ds.log > ds-%s.log for %s in (func cmd csrw phase serv xfer iobus) do findstr /r /c:"MS *%s:" debug-ms.log > ms-%s.log -------------------------------------------------------------------------------- 7970 status supplied by the drive: - SL = status online - SR = status ready (selected * online * ~loading * ~rewinding) - SLP = status load point (selected * online * at-load-point) - SD = status density SD2 (200), SD5 (556), SD8 (800), SD16 (1600) bpi (7970E only) - SRW = status rewind (selected * online * rewinding) - SFP = status file protect (selected * online * ~write-ring) - SET = status end-of-tape (selected * online * EOT-seen-forward (reset when EOT-seen-reverse) - SW = status write (selected * online * cmd-set-write * cmd-fwd) - S7 = status 7-track (7970B only) - EOB = end-of-block (7970E only) - TM = tape-mark (7970E only) - MTE = multiple-track-error (7970E only) - STE = single-track-error (7970E only) -------------------------------------------------------------------------------- ANSI X3.22-1973 Recorded Magnetic Tape for Information Interchange (800 bpi NRZI) ANSI X3.39-1973 Recorded Magnetic Tape for Information Interchange (1600 bpi PE) ANSI X3.54-1976 Recorded Magnetic Tape for Information Interchange (6250 bpi GCR) ECMA-36 Data Interchange on 9-track Phase-encoded Magnetic Tape at 63 bits/mm (1600 bpi) ECMA-62 Data Interchange on 12.7mm 9-track Magnetic Tape CRCC calculation: from ECMA-12: ============= accum := 0 buffer (length + 1) := 0 (for write) or CRCC (from read) for next in 1 .. length loop byte := buffer (next) val := byte OR oddparity (byte) SHL 8 temp := val XOR accum accum := (temp SHR 1) OR (temp AND 1 SHL 8) -- 9-bit right rotate if accum AND 8#400 = 1 then accum := accum XOR 8#74 end loop if writing then accum := accum XOR 8#727 from 13181 diag (returns CRCC in upper byte): ============================================= accum := 0 buffer (length + 1) := 0 (for write) or CRCC (from read) for next in 1 .. length loop byte := buffer (next) val := byte OR oddparity (byte) SHL 8 if accum AND 8#400 = 0 then temp := val XOR accum else temp := val XOR accum XOR 8#74 8553 15475 000040 CLE | - | |15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 8556 15476 001500 ERA MOVE BIT 0 TO E | 0 | | - |15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 8557 15477 001727 ALF,ALF SHIFT TO UPPER BYTE | 0 | | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - |15 |14 |13 |12 |11 |10 | 9 | 8558 15500 001522 ERA,RAL INSERT BIT 7 IN PARITY | 9 | | 0 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - |15 |14 |13 |12 |11 |10 | | 9 | | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - |15 |14 |13 |12 |11 |10 | 0 | 8559 15501 001727 ALF,ALF SHIFT TO LOWER BYTE | 9 | | - |15 |14 |13 |12 |11 |10 | 0 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | -- 9-bit right rotate accum := (temp SHR 1) OR (temp AND 1 SHL 8) -- 9-bit right rotate end loop temp = accum XOR 8#753 | - | | o | o | o | o | o | o | o | i | i | i | i | o | i | o | i | i | = OCT 753 | - | |15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 8488 15432 006500 CLB,CLE CLEAR B AND E REG 8490 15433 001727 ALF,ALF MOVE TO UPPER BYTE | - | | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |15 |14 |13 |12 |11 |10 | 9 | 8 | 8491 15434 001640 ELA,CLE DROP OUT PARITY | 7 | | 6 | 5 | 4 | 3 | 2 | 1 | 0 |15 |14 |13 |12 |11 |10 | 9 | 8 | - | | - | | 6 | 5 | 4 | 3 | 2 | 1 | 0 |15 |14 |13 |12 |11 |10 | 9 | 8 | - | 8492 15435 001325 RAR,ERA SAVE BIT 0 | - | | - | 6 | 5 | 4 | 3 | 2 | 1 | 0 |15 |14 |13 |12 |11 |10 | 9 | 8 | | 8 | | - | - | 6 | 5 | 4 | 3 | 2 | 1 | 0 |15 |14 |13 |12 |11 |10 | 9 | 8493 15436 001727 ALF,ALF MOVE TO LOWER BYTE | 8 | | 0 |15 |14 |13 |12 |11 |10 | 9 | - | - | 6 | 5 | 4 | 3 | 2 | 1 | 8494 15437 001226 RAL,ELA INSERT BIT 0 | 8 | |15 |14 |13 |12 |11 |10 | 9 | - | - | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |15 | |14 |13 |12 |11 |10 | 9 | - | - | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 8 | 8495 15440 001727 ALF,ALF SHIFT TO UPPER BYTE |15 | | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 8 |14 |13 |12 |11 |10 | 9 | - | - | 13181 diag routine expects exact match to CRCC from tape (without parity bit). from 30215 microcode: ===================== accum := 0 buffer (length + 1) := 0 (for write) or CRCC (from read) for next in 1 .. length loop byte := buffer (next) val := byte OR oddparity (byte) SHL 8 accum := val XOR accum ROR 1 if accum AND 8#100000 = 0 then accum := accum AND 8#377 else accum := accum AND 8#377 OR 8#400 XOR 8#74 end loop if writing then accum := accum XOR 8#327 -- gens own parity? else accum := accum XOR 8#727 -------------------------------------------------------------------------------- resolution: - cvars has only fast_controller_time, fast_start_time, fast_data_time, and fast_end_time (and fast_rewind_time?) these can be set by the user when FASTTIME; user cannot see or change REALTIME values power-on reset will set these values to defaults - cvars has HRO data_time and end_time - ml_start_command sets wait = controller_delay - start phase entered after controller delay calculates and sets wait = start time calculates and sets data_time, end_time as function of drive type, density, record size, etc. - data phase entered after start time (drive up to speed and positioned after IRG) sets wait = data time or end time if EOD if data, decrements end time by data time - end phase entered after end time (IRG and stop time) simulation action hardware action ----------------------------- ---------------------------------- * ml_start_command PCONTSTB ...wait for controller_time microcode execution time * ml_service (start_phase) tape motor started ...wait for start_time ramp to speed, space over preamble * ml_service (data_phase) <--+ read data bytes ...wait for data_time | space tape to next byte -----------------+ ...wait for end_time space over postamble, ramp to stop * ml_service (end_phase) tape motor stopped - don't want SET 7970E, e.g., in common MTAB, or it'll appear as a choice for the 13181 (ditto for 7974 and the 30115). These MTABs want to be per-simulator, so only applicable choices appear. alternate would be to keep in common MTAB but set "mstring" and "pstring" to NULL during power-up reset if not enabled for the controller. - instead of SET 7974, maybe SET 7974-800 and SET 7974-1600? elim need for separate SET DENSITY=800. alternate would be to use u3 as model-density word. getting props would be easier if each model/density had its own index value unit flags: - scp : 0-15 (16 bits) - user: 16-31 (15 bits) - mt 16-20 ( 5 bits) - ml 21-27 ( 3 bits) offline (1), model (2) - ms 28-31 ( 4 bits) free -------------------------------------------------------------------------------- Delay time derivation: Tape drive specifications: Start Stop R/W Rewind Load Byte Time Time Speed Speed Speed Time Model msec msec in/sec in/sec in/sec usec +-------+-------+-------+------+-------+------+--------+ | 7970B | 8.33 | 8.33 | 45 | 160 | 20 | 27.78 | | 7970E | 8.33 | 8.33 | 45 | 160 | 20 | 13.89 | | 7974A | | | | | | | | 7978A | | | | | | | +-------+-------+-------+------+-------+------+--------+ Controller specifications: Rewind Start Start Init at BOT at IRG Model usec msec msec +-------+--------+--------+--------+ | 13181 | 556 | 102.22 | 8.89 | | 13183 | 556 | 160.00 | 11.11 | | 30215 | | | | | HP-IB | | | | +-------+--------+--------+--------+ 1318x controller times are based on multiple Spacing Clock Pulses (SCPs) of 555.56 microseconds each. 30115 7970B + 7970E, 3.5" gap 13181 7970B, 4.8" gap 13183 7970E, 3.0" gap hp-ib 7970B or 7970E or 7974 or 7978 7970 - start time = 8.33 msec - stop time = 8.33 msec - read/write speed = 45 ips - rewind speed = 160 ips - rewind start/stop time = 0.7 sec - load speed = 20 ips - word xfer time = 55.56 usec (B), 28.78 usec (E) PE - start gap = 3.0 in min (13183 = 7.2"; 30115 = 2.0" id burst + 3.75" erase gap) - interrecord gap = 0.5 in min 0.6 in nom - pre/postamble = 41 bytes - erase gap = 3.75" (13183 = 3.0"; 30115 = 3.75") NRZI - start gap = 0.5 in min (13181 = 4.6"; 30115 = 3.75" erase gap) - interrecord gap = 0.6 in - erase gap = 3.75 in min (13181 = 4.8"; 30115 = 3.75") all times could be controller-dependent EXCEPT for the 30115 30115 is only controller that supports two drive models all others (incl. HP-IB) support only one type of drive times that depend on the drive: - start time (PE has an extra 2.0" to start from BOT) - data xfer (depends on drive density setting) - irg (PE is longer due to pre/postamble) Write time: > cntlr_delay + if BOT then bot_delay (+ idb_time if PE) else start_delay + pre_time (if PE) + data_time * recsize (* 1/2 if PE) + post_time (if PE) + stop_delay 1000 diag timing tests: - rewind init (cmd -> flag set) - write init (cmd -> flag clear @ 1.0x and set @ 1.25x) - clear (cmd -> flag set) - gap (cmd -> unit busy @ 1.0x and not busy @ 1.25x) - irg (read cmd -> flag clear @ 1.0x and set @ 2.0x) - byte time (min/max) defined times: B E - controller delay c c - BOT gap time c c - ID burst time 0 n - start/stop time c c - pre/postamble time 0 n - data time @ 800bpi x x/2 - rewind init time c c 7970 properties: - load point search speed = 20 ips - read/write speed = 45 ips - rewind speed = 160 ips - rewind stop travel = 31" - read/write start/stop travel = 0.187" +/- 0.020" - read/write start/stop time = 6.6 msec nominal 30215 specs: - data xfer rate = 72000 bytes/sec (E) or 36000 bytes/sec (B) - data xfer time = 13.889 usec/byte (E) or 27.778 usec/byte (B) - read start time = 8.33 msec max - write start time = 10.1 msec max - read/write stop time = 8.33 msec max - read start travel = 0.187" nominal - write start travel = 0.267" nominal - read/write stop travel = 0.187" nominal - irg length = 0.5" nominal - PE preamble and postamble length = 41 bytes - NRZI postamble = 8 bytes (CRCC and LRCC) - ID Burst length = 2" (PE) - erase gap length (including initial gap) = 3.75" - PE file mark length = 40 bytes - NRZI file mark length = 8 bytes - nominal IDB time = 44.445 msec = 17,778 instr - remaining IDB time after start = 2.511 msec = 1004 instr - nominal gap time (E) = 83.334 msec = 33,334 instr - nominal start/stop (IRG) time = 9.73 msec = 3892 instr - nominal pre/postamble time = 569.44 usec = 228 instr Note: a minimum of 1.7" of the 2" IDB overlaps the BOT reflective marker. So only a maximum of 0.3" of the IDB appears after Load Point marker is cleared. So the additional time incurred by a BOT start = .113" = 2.511 msec. - bot start time = start + remaining IDB - non-bot start time = start 30215 microcode delays (1 count = 434 nsec): - coast delay after command = 376B counts = 103 usec - read tape start delay = 45400B counts = 8333 usec - write tape start delay = 55400B counts = 10110 usec - tape stop delay = 45400B counts = 8333 usec Hardware timing at 45 IPS 13181 13183 (based on 1580 instr/msec) instr msec SCP instr msec SCP -------------------- -------------------- - BOT start delay : btime = 161512 102.22 184 252800 160.00 288 - motion cmd start delay : ctime = 14044 8.89 16 17556 11.11 20 - GAP traversal time : gtime = 175553 111.11 200 105333 66.67 120 - IRG traversal time : itime = 24885 15.75 - 27387 17.33 - - rewind initiation time : rtime = 878 0.56 1 878 0.56 1 - data xfer time / word : xtime = 88 55.56us - 44 27.78us - NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with "E116 BYTE TIME SHORT" if the correct data transfer time is used for 13181A interface. Set "xtime" to 115 (instructions) to pass that diagnostic. Rev. 2040 of the tape diagnostic fixes this problem and passes with the correct data transfer time. PE bot time is motor start time + ID burst time (PE) + preamble time PE ir time is motor start time + 1/2 IRG time + preamble time NRZI bot time is motor start time NRZI ir time is motor start time for NRZI, an erase gap follows the BOT marker and precedes the first data record rd/wr: start delay = if bot then bot_time else ir_time data delay = data_time end delay = ir_time rwnd: start delay = rew_time; end delay = (byte_pos / bpi) / ips ips = 400000 instr/sec / 160 inches/sec = 2500 instr/inch Commands are grouped into three categories: read forward, read backward, and write (forward). If the current and prior commands are in the same group, tape motion will continue if the new command arrives within 103 microseconds. -------------------------------------------------------------------------------- Next: - create MX device for 1000; use tapelib, check with diag - add RRR for 1000 (call sim_tape_rdrecr but note buffer is fwd, not rev!)