NEW
  AUTO 3,1
*--------------------------------------
* 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15
*
* $0800 : Block 00 ProDOS	(sect 0,2)
* $0A00 : Block 01 SOS		(sect 4,6)
* $0C00 : Block 02 Cat		(sect 8,10)
* $0E00 : Block 03 Cat		(sect 12,14)
* $1000 : Block 04 Cat		(sect 1,3)
* $1200 : Block 05 Cat		(sect 5,7)
*--------------------------------------
ROM.D2.DataBuf	.EQ $26
ROM.D2.Slotn0 	.EQ $2b
ROM.D2.oddbits 	.EQ $3c
ROM.D2.ReqSect	.EQ $3d

BB.RetryCnt		.EQ $40
BB.TargetTrk	.EQ $41

ZP.BLK.CMD		.EQ $42
ZP.BLK.UNIT		.EQ $43
ZP.BLK.BUFPTR	.EQ $44
ZP.BLK.BLKNUM	.EQ $46

ZP.FX2.GoROM	.EQ $48 				device call entry address
ZP.FX2.iBLKLO 	.EQ $4a 				pointer to low page of index block
ZP.FX2.iBLKHI 	.EQ $4c 				pointer to high page of index block
ZP.FX2.iBLKPtr 	.EQ $4e 				index byte pointer

BB.CurrentQTrack	.EQ $50
BB.TargetQTrack		.EQ $51
BB.tmpTrk		.EQ $52
BB.FX2.AddrField	.EQ $53
BB.FX2.AddrField.S	.EQ $54
BB.FX2.AddrField.T	.EQ $55
BB.FX2.AddrField.V	.EQ $56
*--------------------------------------
iobuff 			.EQ $60

nbuf1 			.EQ $300
dnib 			.EQ $2d6

clrscrn 		.EQ $fc58

BB.FX2.CATBLK1	.EQ $c00
*--------------------------------------
*
*	BLOCK 0
*
*--------------------------------------
				.PH $800
BB.FX2.Boot 	.DA #1
				sec 					Apple /// enters $800 'ora $38'
				bcs BB.FX2.Apple2		branch if not apple iii native mode
*--------------------------------------
BB.FX2.Apple3	lda #$9f 				make Apple /// boot using block 1
				pha 					the return address is $a000
				lda #$ff
				pha

				inc
				tax						ldx #0

				inc 					lda #1 (read block 1)

				jmp $f479
*--------------------------------------
BB.FX2.Apple2	stx ZP.BLK.UNIT			save unit number
				cmp #3
				php
				
				txa 					find out if disk ii
				and #$70 				strip drive # if any
				lsr
				lsr						get slot address
				lsr
				lsr
				ora #$c0
				sta ZP.FX2.GoROM+1
				ldy #0
				sty ZP.FX2.GoROM

				plp

				dey						Y=#$ff
				lda (ZP.FX2.GoROM),y 	get device entry addr
				bne BB.FX2.BDEV			branch if not disk ii (16 sector)

				bcs BB.FX2.BDEV			2 sectors read

				lda #3 					make rom read only sector 2
				sta BB.FX2.Boot			to complete block 0
				inc ROM.D2.ReqSect 		was = 1

				lda ZP.FX2.GoROM+1
				pha
				lda #$5b
				pha
				rts
*--------------------------------------
BB.FX2.BDEV		sta ZP.FX2.GoROM		save low adr of device call entry.

				ldy #0
				
				sty iobuff				$0A00
				sty ZP.BLK.BLKNUM+1		$0001

				sty BB.FX2.AddrField.V	tell BB.FX2.SeekReadD2 vol 00
				sty BB.FX2.AddrField.T	tell BB.FX2.SeekReadD2 we are on track 0

				iny						Y=1
				sty ZP.BLK.CMD			set read command.

				sty ZP.BLK.BLKNUM 		to read SOS+directory blocks

				lda #$0A 				1-5 at $A00
				sta iobuff+1			$0A00

.1	 			jsr BB.FX2.ReadBLK
				bcs .9	 				give up on error.

				inc ZP.BLK.BLKNUM
				lda ZP.BLK.BLKNUM		have all directory blocks been read?
				cmp #6
				bcc .1	 				loop if not.
				
				jmp BB.FX2.ScanCat
				
.9				jmp BB.FX2.BootErr				
*--------------------------------------
BB.FX2.ReadBLK	lda iobuff
				sta ZP.BLK.BUFPTR
				lda iobuff+1
				sta ZP.BLK.BUFPTR+1

				inc iobuff+1
				inc iobuff+1

				lda ZP.FX2.GoROM
				beq BB.FX2.ReadD2

				jmp (ZP.FX2.GoROM)
*--------------------------------------
BB.FX2.ReadD2	lda ZP.BLK.BLKNUM		figure out track & sector.
				and #7 					strip track for now.
				cmp #4
				and #3
				php
				asl
				plp
				rol						now we have the first sector of block.
				sta ROM.D2.ReqSect

				lda ZP.BLK.BLKNUM+1 	get high block #
				lsr 					shift hi addr to carry.
				lda ZP.BLK.BLKNUM 		now figure track #
				ror
				lsr
				lsr
				sta BB.TargetTrk
*--------------------------------------
				lda ZP.BLK.BUFPTR+1
				sta ROM.D2.DataBuf+1

				ldx ROM.D2.Slotn0
				lda IO.D2.DrvOn,x

				jsr BB.FX2.SeekReadD2

				inc ROM.D2.DataBuf+1 	bump address
				inc ROM.D2.ReqSect
				inc ROM.D2.ReqSect		and sector #
				bcs .9	 				branch if error.

				jsr BB.FX2.ReadSectD2

.9	 			ldx ROM.D2.Slotn0
				ldy IO.D2.DrvOff,x
				rts 					return error status in carry.
*--------------------------------------
BB.FX2.HeadSelect
				lda BB.FX2.AddrField.V
				beq .8					VOL = 00
				
				asl
				bcc .8					single sided
				
				bmi .8					> 192
				
				lda BB.TargetTrk
				and #1
				lsr
				php

				rol
				rol						A = 0/2
				
				ora ROM.D2.Slotn0
				tay						y = n0/n2
				
				lda IO.D2.Ph0On,y
				lda IO.D2.Ph0On+4,y
				
				lda #1
				jsr BB.Wait100usecA

				lda IO.D2.Ph0Off,y
				lda IO.D2.Ph0Off+4,y 
				
				lsr BB.FX2.AddrField.T
				plp
				rol BB.FX2.AddrField.T
				
.8				rts				
*--------------------------------------
BB.FX2.Trk2Qtrk
				ldy BB.FX2.AddrField.V
				beq .5
				
				cpy #$85
				bcs .5					> 192 ? must be a buggy 254

				sta BB.tmpTrk

				tya
				and #%00000111			stepping
				tay
				
				lda #0
				clc
				
.2				adc BB.tmpTrk
				dey
				bne .2
				
				rts

.5				asl						X4 standard stepping
				asl
				
BB.Trk2Qtrk.RTS rts
*--------------------------------------
BB.FX2.SeekPhOnY
				and #6
				ora ROM.D2.Slotn0
				tay
				lda IO.D2.Ph0On,y
				rts
*--------------------------------------
BB.FX2.SeekReadD2
				jsr BB.FX2.HeadSelect
				
				lda BB.TargetTrk
				jsr BB.FX2.Trk2Qtrk
				sta BB.TargetQTrack

				lda BB.FX2.AddrField.T
				jsr BB.FX2.Trk2Qtrk
				sta BB.CurrentQTrack

				cmp	BB.TargetQTrack
				beq BB.FX2.ReadSectD2

				bit #1					A = Current QT
				beq .2					we are on 0/4 or 2/4 track

				pha

				bcc .1					if CC, C < T, must move in

				inc						move out: X = Ph(N+1)

.1				jsr BB.FX2.SeekPhOnY	move in : X = Ph(N)

				tya
				tax

				pla

				bcs .2					if CS, C > T, must move out

				inc						move in : Y = Ph(N+1)

.2				jsr BB.FX2.SeekPhOnY	move out: Y = Ph(N)

				bra .9					Ph ON to go to 0/4 or 2/4, no wait
*--------------------------------------
.3				bcs	.4					if CS, C > T, must move out

				inc						CC: C < T, ON next PH

				.HS B0					BCS

.4				dec						CS: C > T, ON prev PH

				sta BB.CurrentQTrack

				bit #1
				bne .5					we must go to 1/4 or 3/4

				lda IO.D2.Ph0Off,x		we must go to 0/4 or 2/4 : Off Prev Ph
				bra .8					go wait....

.5				phy						we must go on 1/4 or 3/4
				plx						Y already ON, -> X for Ph0Off,x

				bcs	.6					if CS, C > T, must move out

				inc						CC: C < T, ON next PH

.6				jsr BB.FX2.SeekPhOnY	now X and Y on

.8				lda #IO.D2.SeekTimeB

				jsr BB.Wait100usecA		...wait...

.9				lda BB.CurrentQTrack
				cmp	BB.TargetQTrack
				bne .3

*				lsr						CS if X,Y on

				lda #0
				jsr BB.Wait100usecA

				ldy ROM.D2.Slotn0
				lda IO.D2.Ph0Off,y
				lda IO.D2.Ph0Off+2,y
				lda IO.D2.Ph0Off+4,y
				lda IO.D2.Ph0Off+6,y

*				lda IO.D2.Ph0Off,y

*				bcc .10

*				clc

*				lda IO.D2.Ph0Off,x

*.10
*--------------------------------------
BB.FX2.ReadSectD2
				ldx ROM.D2.Slotn0

				stz BB.RetryCnt
				php

tryread 		plp 					fix stack.

rdhead 			sec 					anticipate error.
				inc BB.RetryCnt			if = 0 then give up!
				beq BB.Trk2Qtrk.RTS		branch if can't fine/read sector.

				clc 					indicate reading header.

				ldy #0					Retry cnt waiting D5

rddata 			php 					carry set if reading DATA.

rd0 			iny
				beq tryread

rd1 			lda IO.D2.RData,x		read a byte from the state machine.
				bpl rd1 				loop until ready.

rd1a 			eor #$d5 				mark 1?
				bne rd0 				branch if not.

rd2 			lda IO.D2.RData,x
				bpl rd2

				cmp #$aa 				mark 2?
				bne rd1a
				nop 					waste a little time.

rd3 			lda IO.D2.RData,x
				bpl rd3

				cmp #$96 				header mark 3?
				beq rdhd1 				branch if it is.

				plp 					were we looking for data mark 3?
				bcc rdhead 				branch if not.

				eor #$ad 				data mark 3?
				beq rddt1 				go read data field if true...

rdhd0 			bne rdhead 				otherwise, start over.

rdhd1 			ldy #3 					read volume,trk,sect

rdhd2 			lda IO.D2.RData,x
				bpl rdhd2

				rol
				sta ROM.D2.oddbits 		save odd bits (7,5,3,1)

rdhd4 			lda IO.D2.RData,x
				bpl rdhd4

				and ROM.D2.oddbits 		combine even and odd to form value.
				sta BB.FX2.AddrField,y
				dey
				bne rdhd2 				ignore Checksum, A=sector

				plp
				cmp ROM.D2.ReqSect		last byte formed is sector#
				bne rdhead 				branch if target sector not found.

				lda BB.FX2.AddrField.T	previous result is track #
				cmp BB.TargetTrk		is desired track found?
				bne goseek 				re-seek if mismatch.

				bcs rddata 				branch if proper track always.
*--------------------------------------
rddt1 			ldy #$56 				read 2 bit groupings first.
rddt1a 			sty ROM.D2.oddbits

rddt2 			ldy IO.D2.RData,x
				bpl rddt2

				eor dnib,y 				denibblize using table left from boot rom.
				ldy ROM.D2.oddbits 		save in nbuf1
				dey
				sta nbuf1,y
				bne rddt1a 				loop until all 86 groups are read.

rddt3 			sty ROM.D2.oddbits 		now count up for 6-bit groups.

rddt4 			ldy IO.D2.RData,x
				bpl rddt4

				eor dnib,y
				ldy ROM.D2.oddbits 		save result to specified buffer.
				sta (ROM.D2.DataBuf),y
				iny
				bne rddt3 				loop for 256 bytes.

rdchk 			ldy IO.D2.RData,x 		now verify checksum...
				bpl rdchk

				eor dnib,y 				must be equal...
				bne rdhd0 				branch if error.

				ldy #0 					make y=0

nxttwo 			ldx #$56 				now combine 2-bit group with 6 bit group

twobit 			dex 					all done with this group?
				bmi nxttwo 				branch if so.

				lda (ROM.D2.DataBuf),y
				lsr nbuf1,x
				rol
				lsr nbuf1,x
				rol
				sta (ROM.D2.DataBuf),y
				iny
				bne twobit

				clc
				rts
*--------------------------------------
goseek 			jmp BB.FX2.SeekReadD2
*--------------------------------------
BB.Wait100usecA	phx						(3)

.1				ldx #19					(2)

.2 				dex 					(2)
				bne .2					(3)

				dec						(2)
				bne .1					(3)

				plx						(4)

				rts						(6)
*--------------------------------------
BB.FX2.BootErr	jsr clrscrn 			clear video
				ldy #BB.MSG.ERR.Len-1

.1	 			lda BB.MSG.ERR,y
				sta $5b6,y
				dey
				bpl .1

				jmp $ff69
*--------------------------------------
BB.MSG.ERR		.AS -"BOOT ERROR"
BB.MSG.ERR.Len	.EQ *-BB.MSG.ERR
*--------------------------------------
*
*	BLOCK 1
*
*--------------------------------------
BB.FX2.ScanCat	ldy #0
				sty ZP.FX2.iBLKLO
				sty ZP.FX2.iBLKHI
				sty ZP.FX2.iBLKPtr

				sta ZP.FX2.iBLKLO+1

				lda #4 					begin look-up with first entry past header.
				.HS 2C					BIT ABS
.1	 			lda ZP.FX2.iBLKLO
		 		clc
				adc BB.FX2.CATBLK1+$23	ENTRY_LEN : bump to next directory entry.
				tay 					save in y for now.
				bcc .2		 			branch if not a page cross.

				inc ZP.FX2.iBLKLO+1
				lda ZP.FX2.iBLKLO+1 	check for new block.
				lsr 					if even then new block.
				bcs .2

				cmp #$a 				have all file names been compared?
				beq BB.FX2.BootErr		branch if no pro.kernel.

				ldy #4 					else, begin at block beginning.

.2		 		sty ZP.FX2.iBLKLO

				ldy #6

.3		 		lda (ZP.FX2.iBLKLO),y 	look for matching name.
				cmp BB.FX2.ProDOS,y
				bne .1	 				branch if no match.

				dey
				bpl .3

*				ldy #$10 				get file type & index block addr.
*				lda (ZP.FX2.iBLKLO),y
*				cmp #S.FI.T.SYS			is it a system file?
*				bne BB.FX2.BootErr
*				iny

				ldy #$11

				lda (ZP.FX2.iBLKLO),y
				sta ZP.BLK.BLKNUM
				iny
				lda (ZP.FX2.iBLKLO),y
				sta ZP.BLK.BLKNUM+1

				stz ZP.FX2.iBLKLO
				stz ZP.FX2.iBLKHI

				ldy #$1e 				read index block at $1e00 and
				sty ZP.FX2.iBLKLO+1 	kernel at $2000
				sty iobuff+1
				iny
				sty ZP.FX2.iBLKHI+1
*--------------------------------------
BB.FX2.LOADSYS	jsr BB.FX2.ReadBLK		read index block.
				bcs BB.FX2.BootErr

				ldy ZP.FX2.iBLKPtr 		get index pointer
				inc ZP.FX2.iBLKPtr 		bump for next time.

				lda (ZP.FX2.iBLKLO),y
				sta ZP.BLK.BLKNUM
				lda (ZP.FX2.iBLKHI),y 	high disk addr.
				sta ZP.BLK.BLKNUM+1

				ora (ZP.FX2.iBLKLO),y 	if both=0 then done.
				bne BB.FX2.LOADSYS		branch if more to read.

				jmp $2000 				go execute kernel code.
*--------------------------------------
BB.FX2.ProDOS 	.DA	#$26				$20 = storage type + 6 = "PRODOS" len
				.AS "PRODOS"
*--------------------------------------
				.LIST ON
BB.FX2.Free		.EQ $C00-*
				.BS BB.FX2.Free
				.LIST OFF
				.EP
*--------------------------------------
MAN
SAVE usr/src/shared/x.bb.fx2.s
LOAD usr/src/lib/libblkdev.s
ASM
