 
* EXAMPLE OF USE!

	move.w #$4000,$dff09a	;Disable Irqs....

	jsr INIT_DISK

go	moveq  #1,d5		;Load from disk named '1'
	move.l #$10000,d6		;Bytes to load
	move.w #880,d7		;Start block
	move.l #loadspace,a6	;Address of load

	jsr BLOCK_LOAD

	tst.w d7			;check for failure
	beq.s end

	move.w #$7fff,d0		;red screen = error
erlp	move.w #$f00,$dff180
	dbf d0,erlp

end	jsr MOTOR_OFF
	move.w #$c000,$dff09a
	rts

loadspace dcb.l $8000,$00

*****************************************************************************

     *     System Independant Multi-Disk Block Loader V1.1 - 26/4/94   *
     *-----------------------------------------------------------------*

                    * By PHIL RUSTON AKA:PHIL!94/LSD *

* You MUST call "INIT_DISK" before loading for the 1st ever time.

* To LOAD A FILE Set:-

* A6 - Destination Address.
* D5 - Disk / Drive Number to load from. (see below).
* D6 - Bytes to load.
* D7 - Starting Block.

* Then call: "BLOCK_LOAD" - All registers preserved except D7

* D7 returns as 00 is load OK. Else one of the following errors:

* 01 = No speed signal from motor   (disk ejected whilst loading)
* 02 = No DMA transfer time out     (no sync / ''            '' )
* 03 = Disk removed from drive      (whilst loading)
* 04 = Can't find that disk block   (disk corrupt)
* 05 = Wrong track marker ID        ('')
* 06 = Checksum error on disk block ('')
* 07 = Block number req'd too big   (you've (in)directly asked for >$6df)
* 08 = Disk requester               (Disk specifified in D5 isnt inserted)
* 09 = No disk in that drive        (Direct drive access failed)
* 0A = That drive is not connected  (''                      '')

* When setting D5, if you want to look for a 'named' disk (see docs on
* naming disks) then just set the Longword as $0-$7f as normal in D5. 
* If you  want to directly access a DRIVE (df0-df3) set the drive number
* to access in D5 and SET the HIGH word to $FFFF. See docs for more info.

* Call "MOTOR_OFF" when finished loading for a while!!

*******************************************************************************

	section loadcode,code

**************
* Initialize *
**************

INIT_DISK	movem.l a0-a6/d0-d7,-(a7)
	move.l #$dff000,a0
	move.l #$bfd000,a1		
	move.l #Variables,a2
	clr.l attempts(a2)
	clr.l tracksides(a2)
	clr.l track_in(a2)
	moveq #-1,d7
	move.l d7,disks_in(a2)
	move.b d7,track_in(a2)
	bsr motor_off

	bset #3,drives_avail(a2)	;df0: assumed always available
	moveq #4,d1

ID_drives	move.b #$7f,$100(a1)	;what externals are connected?
	bclr d1,$100(a1)		
	move.w #100,d7
	bsr cia_wait
	move.b #$ff,$100(a1)		
	bclr d1,$100(a1)
	moveq #$1f,d7
	moveq #0,d0
df1idloop	lsl.l #1,d0
	bclr d1,$100(a1)
	btst #5,$1001(a1)
	beq.s nxtbit
	ori.w #1,d0
nxtbit	bset d1,$100(a1)
	dbf d7,df1idloop
	not.l d0

	cmpi.l #-1,d0		
	bne.s no_drive		
	bset d1,drives_avail(a2)

no_drive	addq.w #1,d1
	cmpi.w #7,d1
	bne.s ID_drives
	bsr motor_off

	moveq #0,d0		;now identify any disks present.
	moveq #3,d1		
id_dsk_lp	btst d1,drives_avail(a2)
	beq.s no_drv

	move.b d0,use_drive(a2)
	move.b #$ff,$100(a1)
	bclr d1,$100(a1)
	bsr stepin
	bsr initialize_drive
	btst #2,$1001(a1)
	beq.s no_drv
	move.b #1,start_motor(a2)
	bsr identify_disk

no_drv	bsr motor_off
	addq.w #1,d1
	addq.w #1,d0
	cmpi.w #4,d0
	bne.s id_dsk_lp
	movem.l (a7)+,a0-a6/d0-d7
	rts

******************
* Construct file *
******************

BLOCK_LOAD

	movem.l d0-d6/a0-a6,-(a7)
	move.l #$dff000,a0
	move.l #$bfd000,a1
	move.l #Variables,a2
	clr.b error(a2)
	clr.b start_motor(a2)
	move.l d7,d4
	subq.l #1,d6
	
	tst.l d5			;Disk or Drive access?
	bpl.s find_disk

*****************************************************************************

	moveq #3,d7		;Direct drive access but is that
	add.w d5,d7		;drive attatched?
	btst d7,drives_avail(a2)
	bne.s drive_ok
	move.b #$a,error(a2)	;Drive not connected - error $a
	bra load_done
drive_ok	
	cmp.b use_drive(a2),d5	;same drive as before?
	beq loader
	bsr motor_off
	move.b d5,use_drive(a2)
	moveq #3,d0
	add.w d5,d0
	bclr d0,$100(a1)
	move.b #1,start_motor(a2)
	bsr wait1msec
	btst #2,$1001(a1)
	bne.s disk_now
	bsr stepcheck
	btst #2,$1001(a1)
	bne.s disk_now2
	move.b #$9,error(a2)
	bra load_done

disk_now2	bsr initialize_drive
	bsr identify_disk		
disk_now	bra loader

*****************************************************************************

find_disk	moveq #0,d0		;Name disk access - is the required
fdisk_lp	cmp.b disks_in(a2,d0.w),d5	;disk already in a drive?
	beq found_disk
	addq.w #1,d0
	cmpi.w #4,d0
	bne.s fdisk_lp
				
disk_gone	bsr motor_off		;no drive contains req'd disk
	moveq #0,d0		;so switch 'em off and see if
	moveq #3,d1		;any drive has had a disk replaced.
fdisk_lp2	btst d1,drives_avail(a2)
	beq.s dsk_n_rem
	move.b #$ff,$100(a1)
	bclr d1,$100(a1)
	bsr wait1msec
	btst #2,$1001(a1)		;disk replaced / ejected?
	bne.s dsk_n_rem
	move.b d0,use_drive(a2)
	bsr stepcheck
	btst #2,$1001(a1)
	beq.s dsk_n_rem
	move.b #1,start_motor(a2)
	bsr initialize_drive
	bsr identify_disk		;here's a new disk to identify
	cmp.b disks_in(a2,d0.w),d5
	beq.s loader
	bsr motor_off

dsk_n_rem	addq.w #1,d1
	addq.w #1,d0
	cmpi.w #4,d0
	bne.s fdisk_lp2
	bsr motor_off
	move.b #$08,error(a2)	;disk request - error 8.
	bra load_done

found_disk
	
	cmp.b use_drive(a2),d0	;is this a load from the same
	beq loader		;drive as the last load?
	bsr motor_off
	move.b d0,use_drive(a2)
	bclr d1,$100(a1)
	move.b #1,start_motor(a2)
	bsr wait1msec	
same_drv	btst #2,$1001(a1)		;this drive had the required disk
	bne loader		;but has it been ejected?
	move.b #$ff,disks_in(a2,d0.w)
	bra disk_gone		;yep - so look else where
	
Loader	move.l d4,d0
Nxt_block	bsr get_block
	tst.b error(a2)
	bne.s Load_done
	tst.l d6			;Byte countdown ended?
	bmi.s load_done
	addq.w #1,d0
	bra.s Nxt_block

load_done	move.b #$ff,track_in(a2)
	tst.b error(a2)
	beq.s no_error
	bsr motor_off
	move.w #1000,d7
	bsr cia_wait
no_error	moveq #0,d7
	move.b error(a2),d7
	movem.l (a7)+,d0-d6/a0-a6
	rts

*************
* Shut down *
*************

MOTOR_OFF	movem.l a1/a2/d7,-(a7)
	move.l #$bfd000,a1
	move.l #Variables,a2
	move.b #$ff,$100(a1)
	move.b #$87,$100(a1)
	bsr wait1msec
	move.b #$ff,$100(a1)
	move.b #$ff,use_drive(a2)
	moveq #100,d7
	bsr cia_wait
	movem.l (a7)+,a1/a2/d7
	rts

*****************************************************************************

*************
* Get Block *
*************

* D0 will equal block number required ($0 - $6df)

Get_block	cmp.w #$6df,d0		;check block is range
	bls.s blockinrange
	move.b #$7,error(a2)
	bra No_reload

Blockinrange

	move.w #$0503,attempts(a2)
	move.l d0,d1		
	divu #11,d1		;what track/side is that on?
	cmp.b track_in(a2),d1	
	beq.s Trksde_in		;no need to load!
	
Reload	bsr Fetch_trackside		;loads MFM track required
	tst.b error(a2)
	bne No_reload

Trksde_in	clr.b error(a2)		;find a sector
	swap d1			;get sector number lo.
	move.l #MFMbuffer,a3
	lea $31fe(a3),a5
find_sync	move.w #$4489,d7
fs_loop	cmp.w (a3)+,d7
	beq.s found_sync
	cmp.l a5,a3
	bls.s fs_loop
	move.b #4,error(a2)		;couldnt find that sector-error 4
	bra MFM_error

found_sync	

	cmp.w (a3),d7		;2 syncs?
	beq.s syncstart
	subq.w #2,a3

syncstart	lea $2a(a3),a4		;Check header checksum.
	bsr decode_lw		
	move.l $2(a3),d3
	move.l $6(a3),d4
	andi.l #$55555555,d3
	andi.l #$55555555,d4
	eor.l d4,d3
	cmp.l d3,d5
	bne.s Not_sector

	lea $2(a3),a4		;Track mark = Head position?
	bsr decode_lw
	move.l d5,d4		
	swap d4
	moveq #0,d7
	move.b use_drive(a2),d7
	cmp.b tracksides(a2,d7.w),d4
	beq.s Track_mark_ok
	move.b #5,error(a2)		;wrong track mark - error 5
	bra MFM_error

Track_mark_ok

	lsr.w #8,d5		;Is this the sector required?
	cmp.b d5,d1
	beq.s Found_block
	
Not_sector

	add.w #$430,a3      	;loop until find correct sector
	bra.s find_sync

Found_Block
	
	moveq #0,d2		;Transfer converted MFM to dest.
	move.l #$55555555,d7
	lea $3a(a3),a4		
	lea $23a(a3),a5
	move.l d6,d1		;back up pointers in case of error.
	move.l a6,a3		
	moveq #$7f,d3

Conv_lw	move.l (a4)+,d5
	move.l (a5)+,d4
	and.l d7,d5
	and.l d7,d4
	eor.l d5,d2		;update checksum
	eor.l d4,d2
	add.l d5,d5
	or.l d4,d5
	subq.l #4,d6
	bmi.s lst_bytes
	move.l d5,(a6)+
nxt_lw	dbf d3,Conv_lw
	bra.s blk_done

Lst_bytes	move.w d6,d4
	addq.w #4,d4		;last bytes
	bmi.s nxt_lw

Lb_loop	rol.l #8,d5
	move.b d5,(a6)+
	dbf d4,Lb_loop
	bra.s nxt_lw
		
blk_done	sub.w #$208,a4		;get data checksum
	bsr decode_lw		
	cmp.l d5,d2
	beq.s no_reload
	move.b #6,error(a2)		;checksum error - error 6
	move.l a3,a6		;restore pointers
	move.l d1,d6

MFM_error	move.l d0,d1		
	divu #11,d1		
	subq.b #1,attempts(a2)
	bne Reload
	bsr initialize_Drive	;reset heads
	move.b #5,attempts(a2)
	subq.b #1,attempts+1(a2)
	bne Reload

No_reload	rts

*****************************************************************************

* MFM Track loader!
* D1 will equal trackside 0 - 159

Fetch_trackside
	
		
	clr.b error(a2)		
	tst.b start_motor(a2)	;motor on already?
	beq.s motor_ok

	clr.b start_motor(a2)
	move.b #$7f,$100(a1)
	moveq #3,d7
	add.b use_drive(a2),d7
	bclr d7,$100(a1)
	move.w #200,d2		;wait for correct motor speed.
wdskrdy	moveq #10,d7
	bsr cia_wait		
	btst #5,$1001(a1)		
	dbeq d2,wdskrdy
	tst.w d2
	bpl.s motor_ok
	move.b #1,error(a2)		;no speed signal - error 1
	btst #2,$1001(a1)				
	bne.s disk_ok
	move.b #3,error(a2)		;disk removed - error 3
disk_ok	bra trackload_end

motor_ok	move.w d1,d3
	lsr.b #1,d3		;select disk side to load from.
	bcc.s head1
	bclr #2,$100(a1)
	bra.s checkhead
head1	bset #2,$100(a1)

checkhead	moveq #0,d7
	move.b use_drive(a2),d7
	move.b tracksides(a2,d7.w),d2	;ensure head is over correct
	lsr.b #1,d2		;track
	cmp.b d2,d3
	beq.s headok
	bls.s seekout
	bsr stepin
	bra.s checkhead 
seekout	bsr stepout	
	bra.s checkhead

headok	moveq #0,d7
	move.b use_drive(a2),d7
	move.b d1,tracksides(a2,d7.w)
	move.w #$2,$9c(a0)		;clear disk block irq
	moveq #18,d7		;settle wait.
	bsr cia_wait

	move.l #mfmbuffer,$20(a0)
	move.w #$4000,$24(a0)	
	move.w #$8010,$96(a0)	;enable dma
	move.w #$6800,$9e(a0)	
	move.w #$9500,$9e(a0)
	move.w #$4489,$7e(a0)	;sync
	move.w #$9900,$24(a0)	
	move.w #$9900,$24(a0)	

	move.w #200,d2
waitdirq	moveq #10,d7
	bsr cia_wait		
	btst #1,$1f(a0)		
	dbne d2,waitdirq
	tst.w d2
	bpl.s read_ok
	move.b #2,error(a2)		;No DMA finish-Time Out-error 2

read_ok	move.b d1,track_in(a2)
	move.w #$4000,$24(a0)	
	move.w #$10,$96(a0)		;disable dma

Trackload_end

	rts

*******************************************************************************

decode_lw	move.l #$55555555,d7	;decode two consec mfm longwords
	move.l (a4),d5		;into d5
	move.l $4(a4),d4	
	and.l d7,d5	
	and.l d7,d4
	add.l d5,d5
	or.l d4,d5		
	rts

stepout	moveq #0,d7
	move.b use_drive(a2),d7
	subq.b #2,tracksides(a2,d7.w)
	bset #1,$100(a1)
	bra.s step

stepin	moveq #0,d7
	move.b use_drive(a2),d7
	addq.b #2,tracksides(a2,d7.w)
	bclr #1,$100(a1)
step	bsr.s shortwait
	bclr #0,$100(a1)
	bsr.s shortwait
	bset #0,$100(a1)
	moveq #4,d7
	bsr cia_wait
	rts

shortwait	nop
	nop
	nop	
	nop	
	rts

initialize_drive

	btst #$4,$1001(a1)		
	beq.s gottrack0
	bsr.s stepout
	bra.s initialize_drive

gottrack0	moveq #0,d7
	move.b use_drive(a2),d7
	clr.b tracksides(a2,d7.w)
	move.w #20,d7
	bsr cia_wait
	rts

Identify_disk

	movem.l a6/d0-d1/d4-d7,-(a7)
	move.l #ID_buffer,a6
	moveq #$c,d6
	moveq #$0,d0
	bsr get_block
	moveq #0,d6
	move.b use_drive(a2),d6
	tst.b error(a2)
	bne.s not_sys

	move.w ID_buffer+8,d7
	cmpi.w #"PR",d7
	beq.s sys_disk
not_sys	moveq #-1,d7
	bra.s what_disk

sys_disk	move.w ID_buffer+$a,d7
what_disk	move.b d7,disks_in(a2,d6.w)
	move.b #$ff,track_in(a2)
	movem.l (a7)+,a6/d0-d1/d4-d7
	rts

stepcheck	moveq #0,d7
	move.b use_drive(a2),d7
	btst #1,tracksides(a2,d7.w)
	bne.s h_odd
	bsr stepin
	bra.s stepdone
h_odd	bsr stepout
stepdone	rts

wait1msec moveq #1,d7

cia_wait	move.b #$08,$f00(a1)	;set one shot / stop timer.
	move.b #$cc,$600(a1)	;set timer lo
	move.b #$02,$700(a1)	;set timer hi (starts counter)
ciawlp2	btst #0,$f00(a1)		;wait for ciab timer b to timeout
	bne.s ciawlp2
	subq.w #1,d7
	bne.s cia_wait		;d7 = milliseconds to wait.
	rts

*******************************************************************************

Attempts     equ $0
Error    	   equ $2
Start_motor  equ $3
Disks_in     equ $4
Tracksides   equ $8
Track_in     equ $c
Drives_avail equ $d
Use_drive    equ $e

variables	dcb.l 4,$0

ID_buffer dcb.l 3,$0

	section chipstuff,data_c

MFMbuffer	dcb.w $1910,$0000

*******************************************************************************


