NEW
  AUTO 3,1
* disk ii driver. object code = xrw_0

* critical timing requires page bound considerations for code and data.
* virtually the entire 'write' routine must not cross page boundaries.
* critical branches in the 'write', 'read', and 'read adr' subroutines
* which must not cross page boundaries are noted in comments.
* the cld at blockio must be present to determine bank of $D000
* $5300-5A00 moved to language card bank 1 at $D000

				.OR $D000

blockio			cld						$D8 to flag language card bank 1 (main)
				jsr   rsetphse
				lda   q7l,x				turn off write enable
				nop
				nop
				jsr   docheck
				bcs   L5334				branch if block # is out of range
				ldy   #$05
L5310   		asl
				rol	ibtrk
				dey
				bne   L5310
				asl
				bcc   L531C
				ora   #$10			adjust for upper 4 bits of track
L531C   		lsr
				lsr
				lsr
				lsr
				pha				save sector # across call
				jsr   regrwts
				pla
				bcs   L5330			if error
				inc   buf+1
				adc   #$02
				jsr   regrwts			get 2nd half of block
				dec   buf+1
L5330    		lda   ibstat
				rts	
L5334   		lda   #$27			i/o error
				sec
				rts

* read/write a track/sector

regrwts			ldy   #$01			retry count
				sty   seekcnt			only one recalibrate per call
				sta   ibsect
				lda   unitnum			get slot # for this operation
				and   #$70
				sta   A2L

* make sure other drives in other slots are stopped

				jsr   chkprev

* now check if the motor is on, then start it

				jsr   chkdrv
				php				save test results
				lda   #$E8
				sta   montimeh
				lda   unitnum			determine drive 1 or 2.
				cmp   iobpdn                   same drive used before ?
				sta   iobpdn                   save it for next time.
				php                            keep results of compare.
				asl   a                        get drive # into carry.
				lda   motoron,x                turn on the drive.
				bcc   L5362                    branch if drive 1 selected.
				inx                            select drive 2.

L5362   		lda   drv0en,x
				plp                            was it the same drive ?
				beq   L5372                    yes.
				plp                            indicate drive off by setting z-flag.
				ldy   #$07                     150ms delay before stepping.
L536B    		jsr   mswait
				dey
				bne   L536B
				php						now zero flag set.
L5372    		lda   A4L                      make sure this command needs seeking.
				beq   L537C                    branch if status check.
				lda   ibtrk                    get destination track
				jsr   myseek                   and go to it.

* now at desired track. was the motor already on ?

L537C    		plp				was motor on ?
				bne   L538E                    if so, don't wait.

* motor was off, wait for it to speed up

L537F    		lda   #$01			wait 100us for each count in montime
				jsr   mswait
				lda   montimeh
				bmi   L537F                    count up to 0000

* motor should be up to speed,
* if it looks stopped then the drive is not present

				jsr   chkdrv			is drive present ?
				beq   hndlerr                  branch if no drive

* now check: if it is not the format disk command,
* locate the correct sector for this operation

L538E    		lda   A4L			get command #
				beq   L53FD                    if 0 then status command
				lsr   a                        set carry = 1 for read, 0 for write.
				bcs   L5398                    must prenibblize for write
				jsr   prenib16
L5398    		ldy   #$40			64 retries
				sty   retrycnt
L539D    		ldx   A2L                      get slot #.
				jsr   rdadr16			read next address field.
				bcc   L53BE                    branch if read ok.
L53A4    		dec   retrycnt                 one less chance.
				bpl   L539D                    branch to retry.
				lda   #$27                     anticipate a bad drive error.
				dec   seekcnt                  can only recalibrate once.
				bne   hndlerr
				lda   curtrk
				pha                            save track
				asl
				adc   #$10                     pretend track is 8 > curtrk
				ldy   #$40
				sty   retrycnt                 reset retries to 64 max.
				bne   L53CC                    always.

* have now read an address field. make sure this is
* the correct track, sector and volume.

L53BE    		ldy   track			check track
				cpy   curtrk
				beq   L53D5                    ok

* recalibrating from this track

				lda   curtrk			preserve destination track
				pha
				tya
				asl   a
L53CC    		jsr   settrk
				pla
				jsr   myseek
				bcc   L539D			always taken, go recalibrate

* drive is on right track, check volume mismatch

L53D5    		lda   sect			is this the right sector ?
				cmp   ibsect
				bne   L53A4             no, try another sector.
				lda   A4L               read or write ?
				lsr                     the carry will tell.
				bcc   L53F4                    branch if write
				jsr   read16
				bcs   L53A4			if bad read
				
L53E7    		lda   #$00
	dc	h'D0'			bne branch never taken (skip 1 byte)
hndlerr	sec
         sta   ibstat                   error #
         ldx   A2L                      slot offset
         lda   motoroff,x               turn off
         rts
L53F4    jsr   write16			write nibbles
statdne	.EQ	*-ofsD
         bcc   L53E7                    if no errors.
         lda   #$2B                     disk write protected.
         bne   hndlerr                  always
L53FD    ldx   A2L
         lda   q6h,x                    test for write protected
         lda   q7l,x
         rol   a                        write protect-->carry-->bit 0=1
         lda   q6l,x                    keep in read mode
         jmp   statdne
myseek	.EQ	*-ofsD
         asl   a			assume two phase stepper
         sta   track                    save destination track * 2
         jsr   alloff			turn all phases off to be sure.
         jsr   drvindx			get index to previous track
         lda   iobpdn,x                 for current drive.
         sta   curtrk                   current position.
         lda   track                    where to go next.
         sta   iobpdn,x
         jsr   seek			move head there
alloff	.EQ	*-ofsD
         ldy   #$03                     turn off all phases before returning.
L5427    tya                            (send phase in acc)
         jsr   clrphase			carry clear, phases should be turned off
         dey
         bpl   L5427
         lsr   curtrk			divide back down
         clc
         rts

* fast seek subroutine
*
* on entry:
*        x = slot# times $10
*      acc = desired half-track (single phase)
*   curtrk = current halftrack
*
* on exit:
*      a,y = uncertain
*        x = undisturbed
*      curtrk & trkn = final halftrack.
*              prior = prior halftrack if seek was required.
*      montimel,h are incremented by the # of 100us quantums required by
*                 seek for motor on time overlap.
*
* variables used: curtrk, trkn, countn, prior, A2L, montimel, montimeh

seek	.EQ	*-ofsD
         sta   trkn			save target track.
         cmp   curtrk                   on desired track ?
         beq   L5487                    yes, energize phase and return
         lda   #$00
         sta   trkcnt                   half track count.
L5440    lda   curtrk                   save curtrk for delayed turnoff
         sta   prior
         sec
         sbc   trkn                     delta-tracks.
         beq   L5483			branch if curtrk = destination
         bcs   mvout			move out, not in.
         eor   #$FF                     calculate tracks to go.
         inc   curtrk                   increment current track (in).
         bcc   L545A                    always taken.
mvout    adc   #$FE                     calculate tracks to go.
         dec   curtrk                   decrement current track (out).
L545A    cmp   trkcnt
         bcc   L5462                    and 'tracks moved'
         lda   trkcnt
L5462    cmp   #$09
         bcs   L5468                    if trkcnt > 8 then leave y alone (y=8)
         tay				else set acceleration index in y
         sec
L5468    jsr   setphase
         lda   ontable,y		for 'ontime'
         jsr   mswait                   (100us intervals)
         lda   prior
         clc                            for phaseoff
         jsr   clrphase                 turn off prior phase
         lda   offtable,y               then wait 'offtime'
         jsr   mswait                   (100us intervals)
         inc   trkcnt                   count of 'tracks moved'
         bne   L5440                    always taken
L5483    jsr   mswait                   settle 25 msec
         clc                            set for phase off
setphase .EQ	*-ofsD
L5487    lda   curtrk                   get current track
clrphase .EQ	*-ofsD
         and   #$03                     mask for 1 of 4 phases
         rol   a                        double for phaseon/off index
         ora   A2L
         tax
         lda   phaseoff,x		turn on/off one phase
         ldx   A2L                      restore x reg
         rts                            and return

* 7-bit to 6-bit 'deniblize' table (16-sector format)
*
* valid codes are $96 to $FF only. codes with more than one pair of
* adjacent zeroes or with no adjacent ones (except bit 7) are excluded.
*
* nibles in the ranges of $A0-$A3, $C0-$C7, $E0-$E3 are used for
* other tables since no valid nibles are in these ranges.

dnibl	.EQ	*-ofsD			aligned to page boundary minus $96
                .DA #0004FFFF080CFF10'
                .DA #1418'
twobit3	.EQ	*-ofsD			used in fast prenib as lookup for
         dc	h'008040C0FFFF'          2-bit quantities.
                .DA #1C20FFFFFF24282C'
                .DA #3034FFFF383C4044'
                .DA #484CFF5054585C60'
                .DA #6468'
twobit2	.EQ	*-ofsD			used in fast prenib.
         dc	h'00201030'
endmrks	.EQ	*-ofsD			table using 'unused' nibbles:
         dc	h'DEAAEBFF'              ($C4,$C5,$C6,$C7)
                .DA #FFFFFF6CFF70'
                .DA #7478FFFFFF7CFFFF'
                .DA #8084FF888C909498'
                .DA #9CA0'
twobit1	.EQ	*-ofsD			used in fast prenib.
         dc	h'0008040CFFA4'
                .DA #A8ACFFB0B4B8BCC0'
                .DA #C4C8FFFFCCD0D4D8'
                .DA #DCE0FFE4E8ECF0F4'
                .DA #F8FC'

* 6-bit to 2-bit conversion tables:
*
* dnibl2 abcdef-->0000FE
* dnibl3 abcdef-->0000DC
* dnibl4 abcdef-->0000BA

* origin = $D200 (page boundary)
* page align the following tables:

dnibl2	.EQ	*-ofsD
         dc	h'00'
dnibl3	.EQ	*-ofsD
         dc	h'00'
dnibl4	.EQ	*-ofsD
         dc	h'00'

* 6-bit to 7-bit nibl conversion table
*
* codes with more than one pair of adjacent zeroes
* or with no adjacent ones (except B7) are excluded.

nibl	.EQ	*-ofsD
                .DA #960200'
                .DA #00970100009A0300'
                .DA #009B0002009D0202'
                .DA #009E0102009F0302'
                .DA #00A6000100A70201'
                .DA #00AB010100AC0301'
                .DA #00AD000300AE0203'
                .DA #00AF010300B20303'
                .DA #00B3000002B40200'
                .DA #02B5010002B60300'
                .DA #02B7000202B90202'
                .DA #02BA010202BB0302'
                .DA #02BC000102BD0201'
                .DA #02BE010102BF0301'
                .DA #02CB000302CD0203'
                .DA #02CE010302CF0303'
                .DA #02D3000001D60200'
                .DA #01D7010001D90300'
                .DA #01DA000201DB0202'
                .DA #01DC010201DD0302'
                .DA #01DE000101DF0201'
                .DA #01E5010101E60301'
                .DA #01E7000301E90203'
                .DA #01EA010301EB0303'
                .DA #01EC000003ED0200'
                .DA #03EE010003EF0300'
                .DA #03F2000203F30202'
                .DA #03F4010203F50302'
                .DA #03F6000103F70201'
                .DA #03F9010103FA0301'
                .DA #03FB000303FC0203'
                .DA #03FD010303FE0303'
                .DA #03FF'

* nibl buffer 'nbuf2' must be on a page boundary !!!

nbuf2	.EQ	*-ofsD			nibl buffer for read/write of low
	ds	86                       2-bits of each byte.
ibtrk	.EQ	*-ofsD
                .DA #00'
ibsect	.EQ	*-ofsD
         dc	h'00'
ibstat	.EQ	*-ofsD
         dc	h'00'
iobpdn	.EQ	*-ofsD
	dc	h'00'
curtrk	.EQ	*-ofsD
         dc	h'00'
         dc	h'00000000000000'	for slots 1 thru 7
                .DA #00000000000000'        drives 1 & 2
retrycnt .EQ	*-ofsD
         dc	h'00'
seekcnt	.EQ	*-ofsD
         dc	h'00'
trkcnt	.EQ	*-ofsD			halftracks moved count.
countn	.EQ	*-ofsD			'must find' count.
last	.EQ	*-ofsD                   'odd bit' nibls.
         dc	h'00'
csum	.EQ	*-ofsD			used for address header cksum
         dc	h'00'
csstv	.EQ	*-ofsD
                .DA #00'
sect	.EQ	*-ofsD
         dc	h'00'
track	.EQ	*-ofsD
montimel .EQ	*-ofsD
         dc	h'00'
montimeh .EQ	*-ofsD			also 'volume'
         dc	h'00'
prior	.EQ	*-ofsD
         dc	h'00'
trkn	.EQ	*-ofsD
         dc	h'00'

* phase on, off time tables
* in 100 usec intervals (seek)

ontable	.EQ	*-ofsD
	dc	h'013028'
                .DA #24201E1D1C1C'
offtable .EQ	*-ofsD
	dc	h'702C'
                .DA #26221F1E1D1C1C'

* mswait subroutine
*
* delays a specified number of 100 usec intervals for motor timing.
* on entry: acc holds number of 100 usec intervals to delay.
* on exit: acc = 0, x = 0,  y = unchanged, carry set.
* montimel, montimeh are incremented once per 100 usec interval
* for motor on timing.

mswait	.EQ	*-ofsD
L5685    ldx   #$11			delay 86 usec
L5687    dex
         bne   L5687
         inc   montimel
         bne   L5692
         inc   montimeh
L5692    sec
         sbc   #$01
         bne   L5685
         rts

* read address field subroutine (16-sector format)
*
* reads volume, track and sector.
* on entry: x = slot# times $10, read mode (q6l,q7l)
* on exit: carry set if error, else if no error:
*          acc=$AA, y=0, x=unchanged, carry clear,
*          ccstv contains chksum,sector,track & volume read.
* uses temps: count,last,csum & 4 bytes at ccstv
* expects: original 10-sector normal density nibls (4-bit) odd bits then even.
* observe 'no page cross' warnings on some branches !!!

rdadr16	.EQ	*-ofsD
         ldy   #$FC
         sty   countn			'must find' count
L569D    iny
         bne   L56A5                    low order of count.
         inc   countn                   (2k nibles to find address mark
         beq   rderr                     else error)
L56A5    lda   q6l,x			read nibl
         bpl   L56A5                    *** no page cross ***
L56AA    cmp   #$D5                     address mark 1 ?
         bne   L569D
         nop                            nibl delay
L56AF    lda   q6l,x
         bpl   L56AF                    *** no page cross ***
         cmp   #$AA                     address mark 2 ?
         bne   L56AA                    if not, is it address mark 1 ?
         ldy   #$03                     index for 4 byte read
L56BA    lda   q6l,x
         bpl   L56BA                    *** no page cross ***
         cmp   #$96                     address mark 3 ?
         bne   L56AA                    if not, is it address mark 1
         sei                            no interrupts until address is tested.
         lda   #$00                     init checksum
L56C6    sta   csum
L56C9    lda   q6l,x                    read 'odd bit' nibl
         bpl   L56C9                    *** no page cross ***
         rol   a                        align odd bits, '1' into lsb.
         sta   last                     save them.
L56D2    lda   q6l,x                    read 'even bit' nibl
         bpl   L56D2                    *** no page cross ***
         and   last                     merge odd and even bits.
         sta   csstv,y                  store data byte.
         eor   csum
         dey
         bpl   L56C6                    loop on 4 data bytes.
         tay                            if final checksum non-zero,
         bne   rderr                    then error.
L56E6    lda   q6l,x                    first bit-slip nibl
         bpl   L56E6                    *** no page cross ***
         cmp   #$DE
         bne   rderr
         nop                            delay
L56F0    lda   q6l,x                    second bit-slip nible
         bpl   L56F0                    *** no page cross ***
         cmp   #$AA
         bne   rderr
         clc				normal read ok
         rts
rderr    sec
         rts

* read subroutine (16-sector format)
*
* reads encoded bytes into nbuf1 and nbuf2.
* first reads nbuf2 high to low, then nbuf1 low to high.
* on entry: x=slot# times $10, read mode (q6l,q7l)
* on exit: carry set if error, else if no error:
*          acc=$AA, x=unchanged, y=0, carry clear.
* observe 'no page cross' on some branches !!

read16	.EQ	*-ofsD
         txa				get slot #
         ora   #$8C                     prepare mods to read routine.
         sta   rd4+1                    warning: the read routine is
         sta   rd5+1                    self modified !!
         sta   rd6+1
         sta   rd7+1
         sta   rd8+1
         lda   buf                      modify storage addresses also
         ldy   buf+1
         sta   ref3+1
         sty   ref3+2
         sec
         sbc   #$54
         bcs   L571F			branch if no borrow
         dey
L571F    sta   ref2+1
         sty   ref2+2
         sec
         sbc   #$57
         bcs   L572B			branch if no borrow
         dey
L572B    sta   ref1+1
         sty   ref1+2
         ldy   #$20			32 tries to find
L5733    dey
         beq   L576D                    branch if can't find data header marks
L5736    lda   q6l,x
         bpl   L5736
L573B    eor   #$D5                     1st data mark
         bne   L5733
         nop                            delay
L5740    lda   q6l,x
         bpl   L5740
         cmp   #$AA                     2nd data mark.
         bne   L573B                    if not, check for 1st again
         nop
L574A    lda   q6l,x
         bpl   L574A
         cmp   #$AD                     3rd data mark
         bne   L573B                    if not, check for data mark 1 again
         ldy   #$AA
         lda   #$00
L5757    sta   pcl                      use z-page for keeping checksum
rd4	.EQ	*-ofsD
L5759    ldx   q6l+$60                  warning: self modified
         bpl   L5759
         lda   dnibl-$96,x
         sta   nbuf2-$AA,y              save the two-bit groups in nbuf.
         eor   pcl                      update checksum.
         iny                            next position in nbuf.
         bne   L5757                    loop for all $56 two-bit groups.
         ldy   #$AA                     now read directly into user buffer.
         bne   L5772                    always taken.
L576D    sec                            error
         rts
ref1	.EQ	*-ofsD
L576F    sta   $1000,y			warning: self modified
rd5	.EQ	*-ofsD
L5772    ldx   q6l+$60			warning: self modified
         bpl   L5772
         eor   dnibl-$96,x              get actual 6-bit data from dnib table.
         ldx   nbuf2-$AA,y              get associated two-bit pattern
         eor   dnibl2,x                 and combine to form whole byte.
         iny
         bne   L576F                    loop for $56 bytes.
         pha                            save for now, no time to store...
         and   #$FC                     strip low bits.
         ldy   #$AA                     prepare for next $56 bytes
rd6	.EQ	*-ofsD
L5788    ldx   q6l+$60                  warning: self modified
         bpl   L5788
         eor   dnibl-$96,x
         ldx   nbuf2-$AA,y
         eor   dnibl3,x
ref2	.EQ	*-ofsD
         sta   $1000,y			warning: self modified
         iny
         bne   L5788                    loop unil this group of $56 read
rd7	.EQ	*-ofsD
L579C    ldx   q6l+$60                  warning: self modified
         bpl   L579C
         and   #$FC
         ldy   #$AC			last group is $54 long
L57A5    eor   dnibl-$96,x
         ldx   nbuf2-$AC,y
         eor   dnibl4,x                 combine to form full byte
ref3	.EQ	*-ofsD
         sta   $1000,y			warning: self modified
rd8	.EQ	*-ofsD
L57B1    ldx   q6l+$60			warning: self modified
         bpl   L57B1
         iny
         bne   L57A5
         and   #$FC
         eor   dnibl-$96,x              checksum ok ?
         bne   L57CC                    error if not.
         ldx   A2L                      test end marks.
L57C2    lda   q6l,x
         bpl   L57C2
         cmp   #$DE
         clc
         beq   L57CD                    branch if good trailer
L57CC    sec
L57CD    pla                            place last byte into user buffer
         ldy   #$55
         sta   (buf),y
         rts

* set the slot dependent track location

settrk	.EQ	*-ofsD
         jsr   drvindx			get index to drive #
         sta   iobpdn,x
         rts

* determine if motor is stopped
*
* if stopped, controller's shift register will not be changing.
* return y = 0 and zero flag set if it is stopped.

chkdrv	.EQ	*-ofsD
         ldx   A2L
chkdrv0	.EQ	*-ofsD
         ldy   #$00			init loop counter.
L57DE    lda   q6l,x                    read the shift register.
         jsr   ckdrts			delay
         pha
         pla                            more delay.
         cmp   q6l,x                    has shift reg changed ?
         bne   L57F0                    yes, motor is moving.
         lda   #$28                     anticipate error.
         dey                            no, dec retry counter
         bne   L57DE                    and try 256 times.
ckdrts	.EQ	*-ofsD
L57F0    rts
drvindx	.EQ	*-ofsD
         pha                            preserve acc across call
         lda   A4L+1
         lsr   a
         lsr   a
         lsr   a
         lsr   a
         cmp   #$08
         and   #$07
         rol   a
         tax                            index to table.
         pla                            restore acc
         rts

* write subroutine (16 sector format)
*
* writes data from nbuf1 and buf. first nbuf2, high to low then direct
* from (buf), low to high. assumes 1 usec cycle time. self modified code !!
*
* on entry: x = slotnum times 16
*
* on exit: carry set if error (write protect violation).
*          if no error, acc=uncertain, x=unchanged, y=0, carry clear.

write16	.EQ	*-ofsD
         sec				anticipate write protect error
         lda   q6h,x
         lda   q7l,x                    sense write protect flag
         bpl   L580C
         jmp   wexit			exit if write protected

* timing is critical. a one micro-second cycle time is assumed.
* number in () is how many micro-seconds per instruction or subroutine

L580C    lda   nbuf2
         sta   pcl
         lda   #$FF         sync data.
         sta   q7h,x        (5) goto write mode
         ora   q6l,x        (4)
         ldy   #$04         (2) for five nibls
         nop                (2)
         pha                (3)
         pla                (4)
wsync    pha                (3) exact timing.
         pla                (4) exact timing.
         jsr   wnibl7       (13,9,6) write sync.
         dey                (2)
         bne   wsync        (3-) must not cross page !
         lda   #$D5         (2) 1st data mark
         jsr   wnibl9       (15,9,6)
         lda   #$AA         (2) 2nd data mark
         jsr   wnibl9       (15,9,6)
         lda   #$AD         (2) 3rd data mark
         jsr   wnibl9       (15,9,6)
         tya                (2) zero checksum
         ldy   #$56         (2) nbuf2 index
         bne   L583D        (3) branch always

* total time in this write byte loop must = 32us !!!

L583A    lda   nbuf2,y      (4) prior 6-bit nibl
L583D    eor   nbuf2-1,y    (5) xor with current
         tax                (2) index to 7-bit nibl
         lda   nibl,x       (4) must not cross page boundary
         ldx   A2L          (3) restore slot index
         sta   q6h,x        (5) store encoded byte
         lda   q6l,x        (4) handshake
         dey                (2)
         bne   L583A        (3-) must not cross page boundary

* end of write byte loop

         lda   pcl          (3) get prior nibl (from nbuf2)
wrefd1	.EQ	*-ofsD
         ldy   #$00         (2) warning: load value modified by prenib.
wrefa1	.EQ	*-ofsD
L5853    eor   $1000,y      (4) warning: address modified by prenib.
         and   #$FC         (2) strip low 2 bits
         tax                (2) index to nibl table
         lda   nibl,x       (4)
wrefd2	.EQ	*-ofsD
         ldx   #$60         (2) warning: value modified by prenib.
         sta   q6h,x        (5) write nibl
         lda   q6l,x        (4) handshake
wrefa2	.EQ	*-ofsD
         lda   $1000,y      (4) prior nibl. warning: address modified by prenib.
         iny                (2) all done with this page ?
         bne   L5853        (3-) loop until page end.
         lda   pch          (3) get next (precalculated & translated) nibl.
         beq   L58C0        (2+) branch if code written was page aligned.
         lda   A2H          (3) get byte address of last byte to be written.
         beq   L58B3        (2+) branch if only 1 byte left to write.
         lsr   a            (2) test for odd or even last byte (carry set/clear)
         lda   pch          (3) restore nibl to acc.
         sta   q6h,x        (5)
         lda   q6l,x        (4)
         lda   A1L          (3) = byte 0 of 2nd page xor'd with byte 1 if
         nop                (2) above test set carry.
         iny                (2) y=1
         bcs   L5899        (2+) branch if last byte to be odd.
wrefa3	.EQ	*-ofsD
L5881    eor   $1100,y      (4) warning: address modified by prenib.
         and   #$FC         (2) strip low 2 bits.
         tax	             (2) index to nibl table
         lda   nibl,x       (4) get nibl
wrefd3	.EQ	*-ofsD
         ldx   #$60         (2) restore slot index. warning: modified by prenib
         sta   q6h,x        (5)
         lda   q6l,x        (4)
wrefa4	.EQ	*-ofsD
         lda   $1100,y      (4) warning: modified by prenib
         iny                (2) got prior nibl, point to next
wrefa5	.EQ	*-ofsD
         eor   $1100,y      (4) warning: modified by prenib
L5899    cpy   A2H          (3) set carry if this is the last nibl
         and   #$FC         (2) strip low 2 bits
         tax                (2)
         lda   nibl,x       (4)
wrefd4	.EQ	*-ofsD
         ldx   #$60         (2) restore slot. warning: modified by prenib
         sta   q6h,x        (5)
         lda   q6l,x        (4)
wrefa6	.EQ	*-ofsD
         lda   $1100,y      (4) get prior nibl. warning: modified by prenib
         iny                (2)
         bcc   L5881        (3-) branch if not the last.
         bcs   L58B1        (3) waste 3 cycles, branch always.
L58B1    bcs   L58C0        (3) branch always.
L58B3    lda	|pch         (4) absolute reference to zero page
         sta   q6h,x        (5)
         lda   q6l,x        (4)
         pha                (3) waste 14 micro-seconds total
         pla                (4)
         pha                (3)
         pla                (4)
L58C0    ldx   A1H          (3) use last nibl (anded with $FC) for checksum
         lda   nibl,x       (4)
wrefd5	.EQ	*-ofsD
         ldx   #$60         (2) restore slot. warning: modified by prenib
         sta   q6h,x        (5)
         lda   q6l,x        (4)
         ldy   #$00         (2) set y = index end mark table.
         pha                (3) waste another 11 micro-seconds
         pla                (4)
         nop                (2)
         nop                (2)
L58D3    lda   endmrks,y    (4) dm4, dm5, dm6 and turn off byte.
         jsr   wnibl        (15,6) write it
         iny                (2)
         cpy   #$04         (2) have all end marks been written ?
         bne   L58D3        (3) if not.
         clc                (2,9)
wexit	.EQ	*-ofsD
         lda   q7l,x        out of write mode
         lda   q6l,x        to read mode.
         rts                return from write.

* 7-bit nibl write subroutines

wnibl9	.EQ	*-ofsD
         clc	            (2) 9 cycles, then write.
wnibl7	.EQ	*-ofsD
         pha                (3) 7 cycles, then write.
         pla                (4)
wnibl	.EQ	*-ofsD
         sta   q6h,x        (5) nibl write
         ora   q6l,x        (4) clobbers acc, not carry
         rts                (6)

* preniblize subroutine (16 sector format)
*
* converts 256 bytes of user data in (buf) into 6 bit nibls in nbuf2.
* high 6 bits are translated directly by the write routines.
*
* on entry: buf is 2-byte pointer to 256 bytes of user data.
*
* on exit: a,x,y undefined. write routine modified to do direct conversion
*          of high 6 bits of user's buffer data.

prenib16 .EQ	*-ofsD
         lda   buf			self-modify the addresses because of
         ldy   buf+1                    the fast timing required.
         clc                            all offsets are minus $AA.
         adc   #$02                     the highest set is buf+$AC.
         bcc   L58FA			branch if no carry,
         iny                            otherwise add carry to high address.
L58FA    sta   prn3+1                   self mod 3
         sty   prn3+2
         sec
         sbc   #$56			middle set is buf+$56.
         bcs   L5906                    branch if no borrow,
         dey                            otherwise deduct from high.
L5906    sta   prn2+1			self mod 2
         sty   prn2+2
         sec
         sbc   #$56			low set is exactly buf
         bcs   L5912
         dey
L5912    sta   prn1+1			self mod 1
         sty   prn1+2
         ldy   #$AA			count up to 0.
prn1	.EQ	*-ofsD                   get byte from lowest group.
L591A    lda   $1000,y			warning: self modified.
         and   #$03                     strip high 6 bits.
         tax                            index to 2 bit equivalent.
         lda   twobit1,x
         pha                            save pattern
prn2	.EQ	*-ofsD                   get byte from middle group.
         lda   $1056,y			warning: self modified.
         and   #$03
         tax
         pla                            restore pattern.
         ora   twobit2,x                combine 2nd group with 1st.
         pha                            save new pattern.
prn3	.EQ	*-ofsD                   get byte from highest group.
         lda   $10AC,y			warning: self modified.
         and   #$03
         tax
         pla                            restore new pattern
         ora   twobit3,x                and form final nibl.
         pha
         tya
         eor   #$FF
         tax
         pla
         sta   nbuf2,x                  save in nibl buffer.
         iny                            inc to next set.
         bne   L591A                    loop until all $56 nibls formed.
         ldy   buf                      now prepare data bytes for write16 subr.
         dey                            prepare end address.
         sty   A2H
         lda   buf
         sta   wrefd1+1			warning: the following storage addresses
         beq   L595F			starting with 'wref' are refs into code
         eor   #$FF                     space, changed by this routine.
         tay                            index to last byte of page in (buf).
         lda   (buf),y                  pre-niblize the last byte of the page
         iny                            with the first byte of the next page.
         eor   (buf),y
         and   #$FC
         tax
         lda   nibl,x                   get disk 7-bit nible equivalent.
L595F    sta   pch
         beq   L596F                    branch if data to be written is page
         lda   A2H                      aligned. check if last byte is even
         lsr   a                        or odd address. shift even/odd -> carry.
         lda   (buf),y			if even, then leave intact.
         bcc   L596D                    branch if odd.
         iny                            if even, then pre-xor with byte 1.
         eor   (buf),y
L596D    sta   A1L                      save result for write routine.
L596F    ldy   #$FF                     index to last byte of data to write.
         lda   (buf),y                  to be used as a checksum.
         and   #$FC                     strip extra bits
         sta   A1H                      and save it.
         ldy   buf+1			now modify address references to
         sty   wrefa1+2                 user data.
         sty   wrefa2+2
         iny
         sty   wrefa3+2
         sty   wrefa4+2
         sty   wrefa5+2
         sty   wrefa6+2
         ldx   A2L			and lastly, index references to
         stx   wrefd2+1                 controller.
         stx   wrefd3+1
         stx   wrefd4+1
         stx   wrefd5+1
         rts
chkprev	.EQ	*-ofsD
         eor   iobpdn			same slot as last ?
         asl   a
         beq   L59BD
         lda   #$01
         sta   montimeh
L59A6    lda   iobpdn
         and   #$70
         tax
         beq   L59BD                    branch if no previous ever (boot only).
         jsr   chkdrv0                  check if previous drive running.
         beq   L59BD                    branch if stopped.
         lda   #$01                     delay
         jsr   mswait
         lda   montimeh
         bne   L59A6
L59BD    rts
rsetphse .EQ	*-ofsD
         lda   unitnum			get unit number.
         and   #$7F                     mask off high bit.
         tax

* clear all the phases and force read mode

         lda   phaseoff+0,x		make sure all motor phases are off.
         lda   phaseoff+2,x
         lda   phaseoff+4,x
         lda   phaseoff+6,x
         rts
docheck	.EQ	*-ofsD
         lda   A4L			command #.
         cmp   #$04                     is the command allowed ?
         bcs   L59E6                    if not.
         lda   bloknml
         ldx   bloknml+1
         stx   ibtrk                    calculate block's track and sector.
         beq   L59E8                    branch if block # is in range,
         dex                            else test further.
         bne   L59E6                    taken if bad range.
         cmp   #$18                     must be < $118
         bcc   L59E8                    then ok.
L59E6    sec                            error.
         rts
L59E8    clc
         rts				end of obj xrw_0

                .DA #0000'			pad bytes to $D6EC (pathbuf-$14)

* variables used by mli for smartport interface

spstatlist .EQ	*-ofsD			ref pathbuf-$14
	dc	h'00000000'		smartport status list buffer
spunit	.EQ	*-ofsD			ref pathbuf-$10
                .DA #0000000000000000'	smartport unit numbers
                .DA #0000000000000000'

* pathname buffer starts at this page boundary (pathbuf = $D700)
*--------------------------------------
MAN
LOAD USR/SRC/PRODOS.203/PRODOS.S.DISKII
SAVE USR/SRC/PRODOS.203/PRODOS.S
ASM

