1
0
mirror of https://github.com/PDP-10/stacken.git synced 2026-03-02 01:30:40 +00:00
Files
Lars Brinkhoff 6e18f5ebef Extract files from tape images.
Some tapes could not be extracted.
2021-01-29 10:47:33 +01:00

908 lines
32 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Title RX2SER -- RX20 Floppy Diskette Service for KS10s V007
Subttl Timothe Litt 17-FEB-87
Search F,S
$RELOC
$HIGH
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1982,1983,1986,1988.
;ALL RIGHTS RESERVED.
.CPYRT<1982,1988>
VRX2SR==:005 ;For GLOB
ENTRY RX2SER
RX2SER::
;Device dependent bits in S
S.SID1==Z(1B6) ;Set if side 1 selected, clear if side 0
S.OPRA==Z(1B7) ;Set if OPR action requested at interrupt level
S.2SID==1B29 ;Media is 2 sided
S.2DEN==1B28 ;Double density mode
S.PHYS==1B27 ;Use physical I/O (Inhibit interleaving)
S.DELD==1B26 ;Write deleted data/deleted data detected
S.WPS==1B24 ;Use WPS-8 interleave mode
;The RX02 has several funny attributes:
; - It supports 2 densitys, each with a different sector size
; - The sector size is non-standard
; - It is addressed in 2 ways -- Interleaved and Physical
; - The hardware numbers sectors starting with 1, not 0
; - Data is buffered in a silo (FIFO), then NPRed to memory
;
;In physical I/O mode, the RX02 has 77 tracks/side, 26 sectors/track.
;In interleaved-11 mode, the RX02 has 76 tracks/side, 26 sectors/track.
;In interleaved-8 mode, the RX02 has 74 tracks/side, 26 sectors/track.
;
;In single density mode, a sector is 128 (PDP-11) bytes
;In double density mode, a sector is 256 (PDP-11) bytes
;
;Interleaved mode is a software invention, not a hardware function.
;Because the RX02 is so slow, each track is divided into even and
;odd sectors. LBNs are numbered so that for each track, the odd
;sectors are used first, then the even sectors on consecutive
;revolutions. The skipped sectors allow time for the CPU to empty
;the silo, and request the next transfer to be the next higher LBN
;without wasting a whole revolution. In addition, LBNs are skewed
;from 1 track to the next. This skew is to allow for the time needed
;to seek 1 track, without losing a whole revolution. The track-track
;skew is 6 sectors(11 mode), 0 sectors (8 mode).
;Track 0 is reserved to ANSI standardization.
;
;These parameters should not be modified to ensure 11 compatibility.
SUBTTL Table of contents
; TABLE OF CONTENTS FOR RX2SER -- RX20 Service for KS10s
;
;
; SECTION PAGE
; 1. Table of contents..................................... 2
; 2. RX211 Hardware bit definitions........................ 3
; 3. RX20 Device dispatch table............................ 4
; 4. DDB Field definitions................................. 5
; 5. UUOCON interface
; 5.1 Device initialization......................... 6
; 5.2 Obtain buffer size............................ 7
; 5.3 Buffered input................................ 8
; 5.4 Buffered output............................... 9
; 5.5 USETI/USETO & RELEAS UUOs..................... 10
; 5.6 DEVOP. UUO.................................... 11
; 6. Interrupt service..................................... 14
; 7. Interrupt service
; 7.1 Read complete................................. 15
; 7.2 Silo empty.................................... 16
; 7.3 Silo full..................................... 17
; 7.4 Write complete................................ 18
; 7.5 Read extended status complete................. 19
; 7.6 Set density complete.......................... 20
; 7.7 Error processing.............................. 21
; 8. Queued I/O processing
; 8.1 Enqueue DDB for Kontroller.................... 23
; 8.2 Advance queue and start I/O................... 24
; 9. Utility routines
; 9.1 Fill and empty buffer......................... 25
; 9.2 Wait for TR................................... 26
; 9.3 Setup for INPUT and OUTPUT.................... 27
; 9.4 Fixup IOWD for IO mode........................ 28
; 9.5 UBA mapping................................... 29
; 9.6 Set up W and U................................ 30
; 9.7 Sector addressing............................. 31
SUBTTL RX211 Hardware bit definitions
;CSR bits
RX2CS==0 ;Offset of CSR
ERR==100000 ;Error
INIT==40000 ;Initialize ctl
EXAD==30000 ;Extended bus address
EADLSH==-4 ;;Amount to shift address to get EXAD bits
RX02==04000 ;RX02 (rather than RX01) controller
SIDE2==1000 ;Use second side of floppy
DEN==000400 ;Set for double density
TR==0000200 ;Transfer -- RXDB needs data
INTENB==100 ;Interrupt enable
DONE==00040 ;Done
UNIT==00020 ;Use unit 1, not 0
FCNFIL==1 ;;Fill buffer (all FCNs include GO)
FCNMT==03 ;;MT buffer
FCNWR==05 ;;Write sector
FCNRD==07 ;;Read sector
FCNSD==11 ;;Set media density (format)
FCNES==13 ;;Read Error Status
FCNWD==15 ;;Write sector with deleted data mark
FCNXS==17 ;;Read extended status
;RX2ES bits
RX2ES==2 ;Offset of Error and Status A
NXM==04000 ;NXM during NPR
WCOV==2000 ;Word count overflow
USEL==400 ;Unit 1 was selected
RDY==0200 ;Drive ready
DEL==0100 ;Deleted data was read
UDEN==040 ;Unit double density selected
DENERR==020 ;Density error
ACLOW==10 ;Power failing
INTDON==4 ;Init done
%2SIDE==2 ;2 sided media
CRCERR==1 ;CRC error
RX2SA==2 ;Sector Address register offset
;;Values 1-32(8)
RX2TA==2 ;Track Address register offset
;;Values 0-114(8)
RX2WC==2 ;Word Count register offset
;;Values 0-100(8) Single density
;;Values 0-200(8) Double density
RX2BA==2 ;Bus Address register offset
SUBTTL RX20 Device dispatch table
JRST RX2ONL ;(-5) See if on-line
JRST RX2DVP ;(-4) DEVOP. UUO
JRST RX2SIZ ;(-3) Get buffer size
JRST RX2INI ;(-2) Once only
JRST RX2HNG ;(-1) Hung timer expired
RX2DSP::JRST RX2REL ;(0) RELEASE - output
JRST RX2CLS ;(1) CLOSE
JRST RX2OUT ;(2) OUTPUT
JRST RX2INP ;(3) INPUT
JRST RX2ENT ;(4) ENTER
JRST RX2LKP ;(5) LOOKUP
JRST RX2DMO ;(6) Dump mode OUTPUT
JRST RX2DMI ;(7) Dump mode INPUT
JRST RX2USO ;(10) USETO
JRST RX2USI ;(11) USETI
JRST RX2GTF ;(12) UGETF
JRST RX2REN ;(13) RENAME
JRST RX2ICL ;(14) CLOSE input
JRST RX2CLR ;(15) UTPCLR
JRST RX2MTP ;(16) MTAPE
;Temp defns for null routines
RX2ONL==CPOPJ##
RX2HNG==CPOPJ##
RX2CLS==CPOPJ##
RX2ENT==CPOPJ1##
RX2LKP==CPOPJ1##
RX2DMO==CPOPJ##
RX2DMI==CPOPJ##
RX2GTF==CPOPJ##
RX2REN==CPOPJ##
RX2ICL==CPOPJ##
RX2CLR==CPOPJ##
RX2MTP==CPOPJ##
SUBTTL DDB Field definitions
;Define symbolic offsets for DEVRXQ words
QLINK==DEVRXQ##+0 ;LH - Next DDB in KON queue
;RH - Unibus address of start of buffer
QCSR==DEVRXQ##+1 ;LH - CSR for transfer; RH - Data buffer # 1
QFCN==DEVRXQ##+2 ;LH - Data buffer # 2; RH - function & retry
QMAP==DEVRXQ##+3 ;LH - UBA Mapping register # 1; RH - #2
;Byte pointers into the DDB
DEYFCN: POINT 4,QFCN(F),21 ;Function (state) of RX
F..IDL==0 ;;Idle
F..RD== 1 ;;Read
F..WR== 2 ;;Write & write deleted
F..FIL==3 ;;Fill buffer
F..MT== 4 ;;Empty buffer
F..SMD==5 ;;Set media density
F..RES==6 ;;Read error status
F..RXS==7 ;;Read extended status
DEYTRY: POINT 4,QFCN(F),25 ;Retry counter
DEYCSC: POINT 2,QFCN(F),27 ;Number of parameters to stuff in data CSR
DEYSCT: POINT 2,QFCN(F),29 ;Number of sectors left in transfer - 1
DEYUUO: POINT 3,QFCN(F),32 ;Type of UUO in progress
U..IDL==0 ;;Idle (none)
U..BR== 1 ;;Buffered input
U..BW== 2 ;;Buffered output
U..SD== 3 ;;Set density
U..DR== 4 ;;Dump input
U..DW== 5 ;;Dump output
DEYUNT: POINT 1,DEVRXS##(W),18 ;Active unit number
SUBTTL UUOCON interface -- Device initialization
RX2INI: LDB T2,PUNIT## ;Get unit number
JUMPN T2,CPOPJ1## ;If not Kontroller, forget it
HLRZ T1,DEVRXC##(F) ;Get UNIBUS adapter number
MOVEI T2,2 ;Number of mapping registers needed
PUSHJ P,AUTAMR## ;Allocate mapping registers
JRST CPOPJ1## ;Sorry
MOVEM T1,DEVRXM##(F) ;Save initial mapping registers
MOVEM T3,DEVRXE##(F) ;Save initial eleven address
MOVE T1,DEVRXC##(F) ;Get EXP address of control
PUSHJ P,UBGOOD## ;Alive?
JRST CPOPJ1## ;No, forget it
MOVE T1,DEVRXC##(F) ;Get CSR address
RDIO T1,RX2CS(T1) ;Read CSR
TRNN T1,RX02 ;Is it an RX02?
JRST CPOPJ1## ;No, don't set up a vector
;If device is used, CPU will halt with Illegal
;interrupt instruction.
HLRZ T1,DEVRXC##(F) ;Get UNIBUS adapter number
HRRZ T2,DEVRXV##(F) ;Get vector address
PUSHJ P,AUTVIA## ;Compute interrupt instruction address
MOVE T2,DEVRXJ##(F) ;Get interrupt instruction
MOVEM T2,(T1) ;Store in vector table
JRST CPOPJ1## ;Return to SYSINI
SUBTTL UUOCON interface -- Obtain buffer size
;Since UUOCON only calls us on OPEN, and remembers the result,
;a simple user error probably will be to expect WPS mode buffer
;size, but do OPEN with IO.WPS clear.
RX2SIZ: MOVEI T1,<^D128/4> ;Start with size of single density sector
TRNE M,S.2DEN ;If double density mode
ASH T1,1 ; sector is twice as big
TRNE M,S.WPS ;If in WPS mode
JRST [IMULI T1,3 ; we use three sectors of whatever size
AOJA T1,CPOPJ##] ;Account for buffer size word
TRNN M,S.PHYS ;If logical IO (and not WPS)
MOVEI T1,200 ; Must use full size buffer
AOJA T1,CPOPJ## ;Done
SUBTTL UUOCON interface -- Buffered input
RX2INP: TLZ S,IO ;Of course, I think UUOCON should do this...
PUSHJ P,STUWFZ ;Set up U & W and clear retry counter
MOVSI T1,DVOFLN ;Off-line bit
TLZN S,S.OPRA ;Opr action requested at interrupt level?
TDNE T1,DEVCHR(F) ; or off-line?
JRST TELUSR ;Yes, go tell user
RDNXBF: MOVEI T1,@DEVIAD(F) ;Get address of buffer
PUSHJ P,IOWFIX ;Turn buffer address into real IOWD
PUSHJ P,UBAMAP ;Compute UBA mapping
MOVEI T1,U..BR ;Doing a buffered read
DPB T1,DEYUUO ;Store for error recovery
RDNXTB: HRRZ T1,DEVRXI##(F) ;Get next logical block for input
PUSHJ P,TRSET ;Set up for transfer
RDNXTS: HRLM T1,DEVRXI##(F) ;Save sector number for later
MOVEI T2,F..RD ;Get read data function
MOVEI T4,INTENB!FCNRD ;Set up read sector function
WRSET: DPB T2,DEYFCN ;Store as current
PUSHJ P,TRKSEC ;Get track and sector
JRST [TRO S,IOBKTL;Set block too large error
JRST ERRXI1] ;and exit
HRLM T1,QFCN(F) ;Save track
HRL T2,T4 ;Get function bits
LDB T1,PUNIT## ;Get unit number
SKIPE T1 ;If not zero
TLO T2,UNIT ; set unit 1
TRNE S,S.2DEN ;Double density?
TLO T2,DEN ;Yes
TLZE S,S.SID1 ;Use head 1 ?
TLO T2,SIDE2 ;Yes, tell RX02
MOVEM T2,QCSR(F) ;Set up RX2CS and RX2TA
MOVEI T1,2 ;Parameters to load
DPB T1,DEYCSC ;Save for ENQDDB
TRO S,IOACT ;Set IOACT (so we won't move)
MOVEM S,DEVIOS(F) ; ...
PJRST ENQDDB ;Queue DDB and return
TELUSR: MOVEM S,DEVIOS(F) ;Update DDB
PUSHJ P,HNGSTP## ;Bitch, bitch, bitch
TLNN S,IO ;Doing input?
JRST RX2INP ;Yes, try again
JRST RX2OUT ;No, try output
SUBTTL UUOCON interface -- Buffered output
RX2OUT: TLO S,IO ;Do UUOCON's work
PUSHJ P,STUWFZ ;Set up U & W and clear retry counter
MOVSI T1,DVOFLN ;Off-line bit
TLZN S,S.OPRA ;Opr action requested at interrupt level?
TDNE T1,DEVCHR(F) ; or off-line?
JRST TELUSR ;Yes, go tell user
WRNXBF: MOVEI T1,@DEVOAD(F) ;Get address of buffer
PUSHJ P,IOWFIX ;Turn buffer address into real IOWD
PUSHJ P,UBAMAP ;Compute UBA mapping
MOVEI T1,U..BW ;Doing a buffered write
DPB T1,DEYUUO ;Store for error recovery
TRO S,IOACT ;Set IOACT here
MOVEM S,DEVIOS(F) ;So mapping sticks
WRNXTB: HRRZ T1,DEVRXO##(F) ;Get LBN for transfer
PUSHJ P,TRSET ;Set up for transfer
WRNXTS: HRLM T1,DEVRXO##(F) ;Save sector number
HRRZ T1,QLINK(F) ;Get 11 address
LSH T1,EADLSH ;Shift for high bits
ANDI T1,EXAD ;Only those
IORI T1,INTENB!FCNFIL ;Add in the fill buffer
MOVEI T2,F..FIL ;Get fill function
PJRST SETFMT ;Go fill the silo
SUBTTL UUOCON interface -- USETI/USETO & RELEAS UUOs
RX2USI: MOVEI U,DEVRXI##(F) ;Point to input block number
TDZA S,[XWD IOEND,IODEND] ;Zero the EOF bits
RX2USO: MOVEI U,DEVRXO##(F) ;Point to output block number
;PUSHJ P,WAIT1## ;Wait for I/O to stop(UUOCON does this)
HRRM M,0(U) ;Store arg as next block to read/write
PJRST STOIOS## ;Store S in case USETI
RX2REL: ;PUSHJ P,WAIT1## ;Wait for I/O to stop(UUOCON does this)
TLZ S,S.SID1!S.OPRA ;Clear our working bits
SETZM DEVRXI##(F) ;Reset to block 0
SETZM DEVRXO##(F) ;...
SETZM DEVFIL(F) ;Clear any LOOKUP/ENTER info
HRRZS DEVEXT(F)
SETZM DEVPPN(F)
HLLZS QFCN(F) ;Clear unit status
PJRST STOIOS## ;Store S and return
SUBTTL UUOCON interface -- DEVOP. UUO
;Here with F:= DDB, T1:= Function code
RX2DVP: MOVSI T2,-RX2DVL ;Set up AOBJN pointer
RX2DV1: HLRZ T3,RX2DVT(T2) ;Get function code
HRRZ T4,RX2DVT(T2) ;and dispatch address
CAMN T1,T3 ;Do they match?
PJRST (T4) ;Yes, do the function
AOBJN T2,RX2DV1 ;No, check rest of table
PJRST ECOD2## ;Illegal function for RX20
;DEVOP. dispatch table -- XWD Fcn,,Routine
RX2DVT: XWD 1,DVPRXS ;Read extended status
XWD 11,DVPFMT ;Format a disk (using load LP20 RAM fcn!)
RX2DVL==.-RX2DVT ;Size of table
;DEVOP. Read extended status function
;MOVE ac,[Len,,addr]
;DEVOP. ac,
; error return
;Normal return
;
;Addr: EXP .DFRXS (= 1)
; SIXBIT /Device/ (or channel # or UDX)
; BLOCK 2 ;8 bytes of status returned here
;
;The usual DEVOP. errors apply
DVPRXS: PUSHJ P,STUWFZ ;Set up U & W and clear retry counter
TRNE S,IOACT ;Is IO ACTive?
JRST ECOD1## ;Yes, silly user
TLZ S,IO ;This is "input"
TRZ S,IODERR!IODTER ;And errors haven't happened yet
HRRZ T1,M ;Get address -1 of buffer
HRLI T1,-^D<8/4> ;For 8 bytes of status
PUSHJ P,UBAMAP ;Set up mapping for IO
HRLZ T2,QLINK(F) ;Get 11 address of transfer
LSH T2,EADLSH ;Position for CSR
TLZ T2,^-EXAD ;Clear all but high 2 bits
TLO T2,INTENB!FCNXS ;Set the function
HRR T2,QLINK(F) ;First param is low 16 bits
MOVEI T1,U..SD ;Pretend UUO is set density
MOVEI T3,F..RXS ;Interrupt function is read status
JRST DVDOI1 ;Go do the IO
;DEVOP. Format function
;MOVE ac,[Len,,addr]
;DEVOP. ac,
; error return
;Normal return
;
;Addr: EXP .DFFMT (= 11)
; SIXBIT /Device/ (or channel # or UDX)
; SIXBIT /SINGLE/ or SIXBIT /DOUBLE/
;
;The usual DEVOP. errors apply
DVPFMT: PUSHJ P,STUWFZ ;Set up U & W and clear retry counter
MOVSI T1,DVOFLN ;Off-line bit
TLNN S,S.OPRA ;Opr action requested at interrupt level?
TDNE T1,DEVCHR(F) ; or off-line?
JRST ECOD7## ;Yes, return off-line error
PUSHJ P,GETWR1## ;Get next user word (type of format)
PJRST RTM1## ;Address check!
CAME T1,[SIXBIT .SINGLE.] ;Want single density?
CAMN T1,[SIXBIT .DOUBLE.] ;Or double?
CAIA ;Good, continue
PJRST ECOD3## ;Value out of range error
TRNE S,IOACT ;Is I/O active?
JRST ECOD1## ;Yes, return no privs. (Very dumb user!)
TLO S,IO ;This is output
TRZ S,IODERR!IODTER ;No errors so far
CAME T1,[SIXBIT .SINGLE.] ;Single density format?
TROA S,S.2DEN ;No, set double
TRZ S,S.2DEN ;Yes, set single
MOVSI T2,INTENB!FCNSD ;Get function bits
LDB T1,PUNIT## ;Get unit number
SKIPE T1 ;If not zero
TLO T2,UNIT ; set unit 1
TRNE S,S.2DEN ;Double density?
TLO T2,DEN ;Yes
TRO T2,"I" ;Approve the "I"nitialization
SETZM QMAP(F) ;No UBA mapping
MOVEI T1,U..SD ;Get "Set density" state
MOVEI T3,F..SMD ;Set Media Density function
DVDOI1: MOVEM T2,QCSR(F) ;Set up RX2CS and RX2DB
DPB T1,DEYUUO ;Store as current UUO
DPB T3,DEYFCN ;Save as unit status
MOVEI T1,1 ;Parameter to load
DPB T1,DEYCSC ;Save for ENQDDB
DVDOIO: TRO S,IOACT ;Set IOACT so we know when its done
MOVEM S,DEVIOS(F) ; ...
PUSHJ P,ENQDDB ;Queue DDB
;Note that in 7.01 field image, the DEVOP. code doesn't ensure
;that this job has the device INITed. If you don't, you will hang
;in IOW at the call to WAIT1 because SETIOD doesn't have PJOBN set up
PUSHJ P,WAIT1## ;Wait for the I/O to complete
HRRZ T1,S ;Copy the final status (Yes, WAIT1 updates it)
TRNE T1,IODERR!IODTER ;Errors detected?
PJRST ECOD6## ;Yes, "Not initialized" error
PJRST STOTC1## ;No, return S in AC
SUBTTL Interrupt service
RX2INT::MOVE W,F ;Save KON pointer
HLRZ F,DEVRXS##(W) ;Get DDB pointer
SKIPN F ;Paranoia
RX2STP: STOPCD CPOPJ##,STOP,RX2,;++RX2SER fouled up
LDB T3,DEYFCN ;Get function in progress
JUMPE T3,RX2STP ;If none, error
LDB T1,DEYUNT ;Get Kontroller's unit number
LDB T2,PUNIT## ;And that of the DDB
CAME T1,T2 ;They better match
JSP T1,RX2STP ;++ They don't, don't make things worse
MOVE S,DEVIOS(F) ;Set up S
MOVE U,DEVRXC##(W) ;Set up CSR
RDIO T1,RX2CS(U) ;Read CSR
RDIO T2,RX2ES(U) ;and Error register
HRL T1,T2 ;Combine
MOVEM T1,DEVSTS(F) ;Save for analysis
PJRST @[JRST RD.INT ;Dispatch on state
JRST WR.INT
JRST FL.INT
JRST MT.INT
JRST SM.INT
JRST RS.INT
JRST RX.INT]-1(T3) ;As we know it
;**********Temp until use found for fcns
RS.INT==RX2STP ;Read status
SUBTTL Interrupt service -- Read complete
;Here on a Read Complete interrupt
RD.INT: TRNE T1,ERR ;Error detected?
JRST ERROR ;Yes, see if we should retry
TLNE T1,DEL ;Deleted data present?
TROA S,S.DELD ;Yes, remember it
TRZ S,S.DELD ;No, remember that
MOVEM S,DEVIOS(F) ;Tell user
HRRZ T1,QLINK(F) ;Get 11 address
LSH T1,EADLSH ;Shift for high bits
ANDI T1,EXAD ;Only those
IORI T1,INTENB!FCNMT ;Add in Empty buffer
MOVEI T2,F..MT ;Get empty function
PJRST SETFMT ;Setup for empty buffer
SUBTTL Interrupt service -- Silo empty
MT.INT: TRNE T1,ERR ;Error detected?
JRST ERROR ;Yes, see if we can recover
LDB T2,DEYSCT ;Get sectors to go
SOJL T2,RDDONE ;1 fewer
DPB T2,DEYSCT ;Update for next time
HRRZ T1,QCSR(F) ;Get word count from this transfer
ASH T1,1 ;Make into a byte count
ADDM T1,QLINK(F) ;Bump address for next transfer
HLRZ T1,DEVRXI##(F) ;Get last sector transferred
AOJA T1,RDNXTS ;Go read the next one
;Here when read is complete for all sectors of transfer
RDDONE: PUSHJ P,FREKON ;Free the kontroller in case someone else waiting
AOS DEVRXI##(F) ;Bump USETI counter to next block
PUSHJ P,SVEUF## ;Make job addressable
MOVEI T2,^D128/4 ;Number of 10 words/single density sector
TRNE S,S.2DEN ;Double density?
ASH T2,1 ;Yes, double the 10 words
TRNE S,S.PHYS ;If physical IO
JRST RDDON1 ;Use size of a sector
TRNN S,S.WPS ;If not WPS mode
SKIPA T2,[EXP 200] ; use standard logical block size
IMULI T2,3 ;WPS mode, use 3 sectors
RDDON1: MOVEI T1,@DEVIAD(F) ;Get address of buffer control block
EXCTUU <HRRM T2,1(T1)> ;Save actual word count in buffer
PUSHJ P,ADVBFF## ;Advance buffer ring
JRST ERRXI1 ;No more buffers, shut down
PUSHJ P,SETIOD## ;Signal buffer is available
JRST RDNXBF ;And go read next buffer
SUBTTL Interrupt service -- Silo full
FL.INT: TRNE T1,ERR ;Error detected?
JRST ERROR ;Yes, see if we can recover
HLRZ T1,DEVRXO##(F) ;Get sector for transfer
MOVEI T4,INTENB!FCNWR ;Write sector function
TRNE S,S.DELD ;Wants deleted data mark?
MOVEI T4,INTENB!FCNWD ;Yes, give correct command
MOVEI T2,F..WR ;Get write data function
JRST WRSET ;Go start the write
SUBTTL Interrupt service -- Write complete
WR.INT: TRNE T1,ERR ;Error detected?
JRST ERROR ;Yes, see if we can recover
LDB T2,DEYSCT ;Get sectors to go
SOJL T2,WRDONE ;1 fewer
DPB T2,DEYSCT ;Update for next time
MOVEI T1,^D128 ;Get single density byte count
TRNE S,S.2DEN ;Double density?
ASH T1,1 ;Yes, double it
ADDM T1,QLINK(F) ;Bump address for next transfer
HLRZ T1,DEVRXO##(F) ;Get last sector transfered
AOJA T1,WRNXTS ;Go do the next one
;Here when write is complete for all sectors of transfer
WRDONE: PUSHJ P,FREKON ;Free kontroller in case of others
AOS DEVRXO##(F) ;Bump USETO counter to next LBN
PUSHJ P,SVEUF## ;Make the job addressable
PUSHJ P,ADVBFE## ;Advance the buffer ring
JRST ERRXI1 ;No more data, shut down
PUSHJ P,SETIOD## ;Signal a buffer can be refilled
JRST WRNXBF ;And go write the next one
SUBTTL Interrupt service -- Read extended status complete
;Here when extended status interrupt happens
RX.INT: ;PJRST SM.INT ;Treat exactly as set density
SUBTTL Interrupt service -- Set density complete
;Here when Format interrupt happens
SM.INT: TRNN T1,ERR ;Any errors?
PJRST ERRXI1 ;No, restart UUO level code
PUSHJ P,ERRCHK ;Yes, see if retrys left
JRST ERROR2 ;No, record the error
PJRST STRTIO ;OK to retry, just restart I/O
SUBTTL Interrupt service -- Error processing
;Here when the RX has detected an error
;Note that we may be either at interrupt or UUO level
ERROR: MOVE T1,DEVSTS(F) ;Get error status back
PUSHJ P,ERRCHK ;See if retrys left
JRST ERROR1 ;None left, declare hard error
LDB T4,DEYUUO ;Get function in progress
TLNN T1,CRCERR ;CRC error?
TLNN T1,WCOV!DENERR ; No, not WC overflow or density error?
JRST RETRY ;Yes, just retry function
TLNE T1,UDEN ;Is diskette double density?
TROA S,S.2DEN ;Yes, retry that way (and tell user)
TRZ S,S.2DEN ;No, retry in single density
TLNE T1,%2SIDE ;Two sided diskette?
TROA S,S.2SID ;Yes, tell user
TRZ S,S.2SID ;No, tell user
PUSHJ P,SVEUF## ;Must make job addressable
;since buffer size changed
TLNE S,IO ;If output
JRST WRNXBF ;Restart
JRST RDNXBF ;Recompute transfer size & do it all over again
ERROR1: TLNE T1,RDY ;Drive ready?
TLNE T1,ACLOW ;Yes, is subsystem ready?
JRST SETOPR ;No, user ? OPR action requested
ERROR2: TLNE T1,CRCERR ;CRC error?
TROA S,IODTER ;Yes, set data error
ERRXIT: TRO S,IODERR ;No, set device error
ERRXI1: PUSHJ P,SETIOD## ;Restart user
PUSHJ P,CLRACT## ;and clear IOACTive
PJRST FREKON ;Check Kontroller queue and dismiss
SETOPR: MOVSI T1,DVOFLN ;Set offline status
IORM T1,DEVCHR(F) ;for UUOCON
TRO S,IODERR ;Set device error
TLO S,S.OPRA ;and request OPR action
PUSHJ P,DEVERR## ; ... later
PJRST FREKON ;Release the Kontroller and dismiss
;Routine to increment the retry counter
;skips if any left, otherwise returns normally
ERRCHK: MOVEI T2,DEPDER ;Get retry disabled bit
TDNE T2,DEVSTA(F) ;Did user specify no retrys?
POPJ P, ;Yes, don't
LDB T2,DEYTRY ;Get retry counter
SKIPN T2 ;First retry?
AOS DEVHCW(F) ;Yes, count a soft error
AOS T2 ;bump by one
CAILE T2,^D10 ;Done enough?
SETZ T2, ;yes, stop
DPB T2,DEYTRY ;Store new count
JUMPN T2,CPOPJ1## ;If still trying, skip
SOS DEVHCW(F) ;Hard error, count down soft errors
MOVSI T2,1 ;Now, ...
ADDM T2,DEVHCW(F) ;count up the hard ones
POPJ P, ;Return hard error
;Routine to initiate a retry for error recovery
RETRY: LDB T1,DEYUUO ;Get the UUO in progress
JRST @[JRST RX2STP ;;Nothing
JRST RT.BR ;;Buffered read
JRST RT.BW ;;Buffered write
JRST RX2STP ;;Set density
JRST RT.DR ;;Dump read
JRST RT.DW](T1) ;Dump write
RT.BR: HLRZ T1,DEVRXI##(F) ;Get sector to read
JRST RDNXTS ;Re-read it
RT.BW: HLRZ T1,DEVRXO##(F) ;Get sector to write (Must refill silo since
JRST WRNXTS ;power fail in RX could invalidate it)
RT.DR: ;Should delete these 3 lines if not supporting dump io
RT.DW:
STOPCD CPOPJ,DEBUG,RXX ;Unimplimented error recovery
SUBTTL Queued I/O processing -- Enqueue DDB for Kontroller
;Routine to enqueue the current DDB for the Kontroller
;Assumes that we are ready to start IO
ENQDDB: PIOFF ;Prevent races
PUSHJ P,ENQDDI ;Now act as though at interrupt level
JRST ENQDD2 ;Can't start IO now, some one else is there
PION ;Restore PI
PJRST STRTIO ;and start IO
ENQDD2: PION ;Restore PI
POPJ P, ;and return to caller
ENQDDI: HLRZ T1,DEVRXS##(W) ;Get current queue header
CAIN T1,0(F) ;Us?
PJRST CPOPJ1## ;Yes, don't foul the queue
HRRZS QLINK(F) ;Clear previous link
JUMPE T1,[HRLM F,DEVRXS##(W) ;We're first
PJRST CPOPJ1##] ;So start IO now
ENQDD1: HLRZ T2,QLINK(T1) ;Point to next DDB in queue
JUMPE T2,[HRLM F,QLINK(T1) ;Reached end, link this in
POPJ P,] ;I/O is now deferred
MOVE T1,T2 ;Point to next DDB
JRST ENQDD1 ;Loop for end
SUBTTL Queued I/O processing -- Advance queue and start I/O
;Routine to free the Kontroller at end of unit I/O
FREKON: PUSH P,F ;Save F for caller
PUSH P,S
PUSHJ P,QUECHK ;Free up the controller if we had it
POP P,S
PJRST FPOPJ## ; (any pending I/O for other units started)
QUECHK: HLRZ T1,DEVRXS##(W) ;Get queue header
CAIE T1,0(F) ;Are we it?
POPJ P, ;No, don't touch it
HLRZ F,QLINK(F) ;Point to next DDB in queue
HRLM F,DEVRXS##(W) ;It's now the first one
JUMPN F,STRTI0 ;If someone there, start I/O
WRIO F,@DEVRXC##(W) ;Otherwise, disable interrupts
POPJ P, ;and return
;Entry to start IO for current DDB
;requires current DDB to be first on Q
STRTI0: MOVE S,DEVIOS(F) ;Get correct S
STRTIO: TRO S,IOACT ;Set IOACT
PUSHJ P,STOIOS## ; and start hung timer (SETACT clears IOW)
LDB T1,PUNIT## ;Get unit number of this DDB
DPB T1,DEYUNT ;Save as number of active unit
MOVE T1,QMAP(F) ;Get UBA mapping register contents for this XFR
MOVE T2,DEVRXM##(W) ;Get IO address of UBA map
WRIO T1,1(T2) ;Setup map for second page
MOVSS T1 ;Get contents for first page
WRIO T1,0(T2) ;Set it up
HLRZ T1,QCSR(F) ;Get CSR contents for command
WRIO T1,RX2CS(U) ;Give the command
MOVE T4,[POINT 18,QCSR(F),17] ;Set up byte pointer to contents
LDB T3,DEYCSC ;Get CSR count
SETPAR: JUMPE T3,CPOPJ## ;Return if done with parameters
PUSHJ P,TRWAIT ;Wait for signal to TRansfer
JRST [PUSHJ P,ERRCHK ;Any retrys left?
JRST ERRXIT ;No, give up
JRST STRTIO] ;Yes, try again
ILDB T1,T4 ;Get parameter
WRIO T1,RX2BA(U) ;Write it to RX02
SOJA T3,SETPAR ;Loop till done
SUBTTL Utility routines -- Fill and empty buffer
;Routine to do setup for Fill and Empty buffer functions
;Fills in CSR with DENSITY, UNIT bits
;Sets up command queue in DDB
;Starts IO
;expects EXAD bits and INTENB!xxFCN in T1
;expects interrupt dispatch code in T2
SETFMT: TRNE S,S.2DEN ;Double density?
TRO T1,DEN ;Yes, tell RX02
DPB T2,DEYFCN ;Set interrupt dispatch function
LDB T2,PUNIT## ;Get unit number
SKIPE T2 ;If not unit zero
TRO T1,UNIT ; set unit 1
HRLZM T1,QCSR(F) ;Save command in queue
MOVEI T1,^D128/2 ;Word count for single density
TRNE S,S.2DEN ;Double density?
ASH T1,1 ;Yes, double it
HRRM T1,QCSR(F) ;Save WC in queue
HRRZ T1,QLINK(F) ;Get low order 11 address
HRLM T1,QFCN(F) ;Store it in queue too
MOVEI T1,2 ;Get number of parameters
DPB T1,DEYCSC ;Set that in queue
JRST ENQDDB ;Enqueue (for fill) and start the IO
SUBTTL Utility routines -- Wait for TR
;Routine to wait for TR or error
;Call with W:=KON DDB; U:=CSR address
;CPOPJ if error, CPOPJ1 if TR
TRWAIT: MOVEI T2,2000 ;Set timeout, just in case
TRWAT1: RDIO T1,RX2CS(U) ;Read CSR
TRNE T1,TR ;TR set yet?
JRST CPOPJ1## ;Yes, return success
TRNN T1,ERR!DONE ;Error?
SOJG T2,TRWAT1 ;No, keep looking
RDIO T2,RX2ES(U) ;Get error status
HRL T1,T2 ;Combine
MOVEM T1,DEVSTS(F) ;Save for analysis
POPJ P, ;Error or timeout
SUBTTL Utility routines -- Setup for INPUT and OUTPUT
TRSET: MOVEI T2,3 ;Assume 4 sectors/block
TRNE S,S.2DEN ;Unless double density
LSH T2,-1 ;In which case, 2 sectors/block
TRNE S,S.WPS ;WPS uses three sectors/block
MOVEI T2,2 ;Thus
TRNE S,S.PHYS ;But physical I/O
MOVEI T2,0 ;Provides only 1 sector/block
DPB T2,DEYSCT ;Save number of sectors - 1 in transfer
PJRST BLKCVT ;Convert LBN to sector
SUBTTL Utility routines -- Fixup IOWD for IO mode
;Routine to turn a buffer address into an IOWD, allowing for IO mode
IOWFIX: HRLI T1,-<^D128/4> ;Set word count for a single density sector
TRNE S,S.2DEN ;Unless double density
HRLI T1,-<^D256/4> ; in which case use that (10) word count
TRNE S,S.PHYS ;If physical IO, we got it right
AOJA T1,CPOPJ## ;So make real IOWD and return
HRLI T1,-200 ;Logical IO, assume normal size
TRNN S,S.WPS ;WPS mode?
AOJA T1,CPOPJ## ;No, we got it right
HRLI T1,-<^D128/4>*3 ;Yes, assume single density 3 sectors
TRNE S,S.2DEN ;Right?
HRLI T1,-<^D256/4>*3 ;No, double density WPS (!)
AOJA T1,CPOPJ## ;Done
SUBTTL Utility routines -- UBA mapping
;Routine to compute UBA mapping for an IOWD
UBAMAP: HLRE T2,T1 ;Get word count
MOVNS T2 ;Make positive
HRRZI T1,1(T1) ;Point to first address of buffer
PUSHJ P,UADRCK## ;See if it's legal for IO (May call PFH)
EXCTUX <MAP T3,@T1> ;Convert to a physical address
TLNN T3,(1B1) ;Error if hard page fail
TLNN T3,(1B3!1B4) ;OK if modified or writable
JRST ADRERR## ;Not accessible or not writable or hard PF
TLZ T3,777776 ;Clear junk bits
ADDI T1,-1(T2) ;Point T1 to last word in buffer
ROT T3,-^D9 ;Get page number of first page
TRO T3,UNBD18!UNBVBT;Set 16 bit mode, valid
HRLZM T3,QMAP(F) ;This will be the mapping
ROT T3,^D9 ;Get word number back
LSH T3,2 ;Make into byte address
ANDI T3,777B33 ;Byte offset into page only
ADD T3,DEVRXE##(W) ;Compute start of transfer
HRRM T3,QLINK(F) ;Save for STRTIO
PUSHJ P,UADRCK## ;Be sure end of buffer is in low seg
EXCTUX <MAP T1,@T1> ;Find address of end of buffer
TLNN T1,(1B1) ;Error if hard page fail
TLNN T1,(1B3!1B4) ;OK if modified or writable
JRST ADRERR## ;Not accessible or not writable or hard PF
TLZ T1,777776 ;Clear junk
LSH T1,-^D9 ;Get page number
TRO T1,UNBD18!UNBVBT;Set 16 bit mode, valid
HRRM T1,QMAP(F) ;This is the other mapping
POPJ P, ;Done
SUBTTL Utility routines -- Set up W and U
;Coroutine to setup W and U from F
STUWFZ: SETZ T1, ;Get a zero
DPB T1,DEYTRY ;Clear the retry counter
SETUWF: EXCH U,(P) ;Save U, get PC
PUSH P,W ;Save W
MOVEM U,1(P) ;Save PC of caller
MOVEI W,RXADDB## ;Point to first RX02 DDB
SETUW1: MOVE T1,DEVNAM(F) ;Get name of current DDB
XOR T1,DEVNAM(W) ;Compare
TLNE T1,777700 ;At least RX?
JSP T1,RX2STP ;No, die
TLNE T1,77 ;Is controller right?
JRST [HLRZ W,DEVSER(W) ;No, go to next
JRST SETUW1] ;and loop till find it
MOVE U,DEVRXC##(W) ;Point to CSR
PUSHJ P,@1(P) ;Call caller (again)
JRST .+2 ;Pass non-skip along
AOS -2(P) ;Skip
POP P,W ;Restore W
PJRST UPOPJ## ;and U
SUBTTL Utility routines -- Sector addressing
;Subroutine to convert LBNs to logical sector format
;
;Call: T1/ LBN from user
; PUSHJ P,BLKCVT (To convert LBN)
; Only return (T1/logical sector to start I/O with)
BLKCVT: TRNE S,S.PHYS ;Physical I/O?
POPJ P, ;Yes, already a sector number
TRNE S,S.WPS ;WPS mode?
JRST [IMULI T1,3 ;Yes, any sector = 1/3 block
POPJ P,] ;Done
ASH T1,1 ;Logical I/O - Double density sector = 1/2 block
TRNN S,S.2DEN ;Double density?
ASH T1,1 ;No, single density sector is 1/4 block
POPJ P, ;Return first logical sector of block
;Subroutine to convert logical sectors to track/sector format
;
;Call: T1/ logical sector number (Sector # block)
; PUSHJ P,TRKSEC (To convert sector)
; Illegal sector number
; Sector number ok
;
;On success, S has the head select bit set, T1/ Track
;T2/ Sector
;
;Uses T1-3
TRKSEC: IDIVI T1,^D26 ;T1/ Track, T2/ Sector
TRNE S,S.WPS ;If WPS mode
JRST TRKSCW ;This is all different
CAIGE T1,^D76 ;On side 2?
JRST TRKSC2 ;No, must be ok
TRNN S,S.PHYS ;Physical I/O?
JRST [SUBI T1,^D76 ;No, logical uses 76 tracks/side
JRST TRKSC1] ;See if legal
CAIN T1,^D76 ;Exactly 76?
JRST TRKSC2 ;Yes, physical uses 77 tracks/side
SUBI T1,^D77 ;No, convert to side 2 address
TRKSC1: TRNN S,S.2SID ;2 Sided media?
POPJ P, ;No, illegal sector number
TLOA S,S.SID1 ;Yes, use head 1
TRKSC2: TLZ S,S.SID1 ;Here when address is on side 0
TRNE S,S.PHYS ;Physical?
JRST TRKSC3 ;Yes, skip interleave
ASH T2,1 ;Sector _ Sector * 2
CAIL T2,^D<13*2> ;In second 1/2 track?
AOJ T2, ;Yes, use odd sector
MOVE T3,T1 ;Copy track number
IMULI T3,6 ;Compute track-track skew
ADD T2,T3 ;Offset
IDIVI T2,^D26 ;Modulo 26
MOVE T2,T3 ;Skewed and interleaved sector in T2
AOJ T1, ;Logical tracks start with 1 (but not phys...)
TRKSC3: AOJ T2, ;Sectors are always based on 1
CAIG T1,^D77 ;Track too big?
CAILE T2,^D26 ;Or sector too big?
POPJ P, ;Yes, error
JRST CPOPJ1## ;No, all set
;Here for WPS mode conversion
TRKSCW: TRNE S,S.PHYS ;Physical and WPS
POPJ P, ;Is illegal
CAIG T1,^D74-1 ;On side 2?
JRST TRKSW1 ;No
SUBI T1,^D74 ;Yes, adjust for side 1
CAIG T1,^D74-1 ;Still too big?
TRNN S,S.2SID ;No, 2 sided media?
POPJ P, ;Illegal track number
TLOA S,S.SID1 ;Legal, select head 1
TRKSW1: TLZ S,S.SID1 ;Select head 0
IMULI T2,3 ;Interleave by 3 sectors
IDIVI T2,^D26 ;MOD 26
AOS T2,T3 ;Sectors start at one
AOJA T1,CPOPJ1## ;Fix track and skip
END