
* EXAMPLE OF USE!

	
	move.w #$4000,$dff09a	;disable irqs

	jsr INIT_DISK		;set up

	move.l #loadspace,a5	;address of load
	move.l #filename,a6		;address of filename
	moveq #0,d7		;load mode set

	jsr LOAD_FILE

	tst.w d7			;check for failure
	beq.s fileok
	move.w #$7fff,d0		;red screen = error
erlp	move.w #$f00,$dff180
	dbf d0,erlp

fileok	jsr MOTOR_OFF

	move.w #$c000,$dff09a
	rts

loadspace dcb.l $8000,$00

filename	dc.b "vegetables/onion",$00

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

      *     System Independant AmigaDos File Loader V1.1 - 26/4/94   *
      *--------------------------------------------------------------*

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

* Call: "INIT_DISK" before you load for the 1st time ever!!!

* To LOAD A FILE Set:-

* A6 - Address of 0 terminated filename (no path/can include directories).
* A5 - Load address.
* D7 - 0 = Load, 1 = Search and Return file length in A5 only.

* Then call: "LOAD_FILE"

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

* A5 returns last byte address of file + 1
* D7 returns 0 is load OK. Or one of the following errors:

* 01 = No speed signal from motor   (disk removed while loading?)
* 02 = No DMA transfer time out     (bad disk/ ''            '')
* 03 = Disk removed from drive      (for you to issue requester)
* 04 = Can't find that disk block   (disk corrupt)
* 05 = Wrong track marker ID        ('')
* 06 = Checksum error on disk block ('')
* 07 = Block requested out of range ('')
* 08 = Not a file                   (Its a directory!)
* 09 = File not found               (obvious!)

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

	section loadcode,code

DRIVE equ 0

INIT_DISK	movem.l d7/a1/a2,-(a7)
	bsr motor_off
	move.l #$bfd000,a1
	move.l #variables,a2
	bclr #drive+3,$100(a1)
	bsr initialize_drive
	bsr motor_off
	movem.l (a7)+,d7/a1/a2
	rts

LOAD_FILE	movem.l d0-d6/a0-a4/a6,-(a7)
	bsr Find_file
	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-a4/a6
	rts

MOTOR_OFF	movem.l d7/a1-a2,-(a7)
	move.l #$bfd000,a1
	move.l #variables,a2
	clr.b motor(a2)
	move.b #$ff,$100(a1)
	move.b #$87,$100(a1)
	bsr wait1msec
	move.b #$ff,$100(a1)
	movem.l (a7)+,d7/a1-a2
	rts

*********************
* Get Main Root Dir *
*********************

Find_file	move.l #$bfd000,a1
	move.l #variables,a2
	move.l a5,load_address(a2)
	clr.b error(a2)
	move.b d7,mode(a2)

	move.l #block_buffer,a0	;get disk's root dir.
	move.w #880,d0
	bsr Get_block
	tst.b error(a2)
	bne file_eror

******************************
* Find File's Root Directory *
******************************

Find_files_root_dir_loop
	
	move.l a6,a4
	moveq #0,d0	

dir_loop	move.b (a4),d7		;find file's root dir
	beq.s root_dir
	cmpi.b #"/",d7		;and get length of subdir name
	beq.s oblique 		;if required.
	addq.w #1,a4
	addq.w #1,d0
	bra dir_loop

oblique	move.w d0,d7		;d0 = dir name length
	move.w d0,d6		
	subq.w #1,d7

	bsr hash_name		;hash dir name into d0

	lsl.w #2,d0
	move.l $18(a0,d0.w),d0	;header block for this hash
	beq file_not_found

get_dir_header

	bsr Get_block
	tst.b error(a2)
	bne file_eror

	bsr compare_names
	tst.w d7
	beq.s next_in_hash_chain
	addq.w #1,a4
	move.l a4,a6
	bra find_files_root_dir_loop

next_in_hash_chain

	move.l $1f0(a0),d0
	bne get_dir_header
	bra file_not_found

**************************
* Locate The File Itself *
**************************

root_dir	move.w d0,d7		;length of file name
	move.w d0,d6
	subq.w #1,d7

	bsr hash_name	

	lsl.w #2,d0
	move.l $18(a0,d0.w),d0	;header block number for this hash
	beq file_not_found

get_header

	bsr Get_block
	tst.b error(a2)
	bne file_eror

	bsr compare_names
	tst.w d7
	bne.s correct_file_header

	move.l $1f0(a0),d0		;any more in hash chain?
	bne get_header
	bra file_not_found

correct_file_header

	cmpi.l #-3,$1fc(a0)		;make sure its a file header
	beq.s file_header
	move.b #8,error(a2)		;not a file header-error 8
	bra file_eror

file_header

	move.l load_address(a2),a5
	move.l $144(a0),d6		;length of file.
	tst.b mode(a2)
	beq.s transfer
	move.l d6,a5
	rts
transfer
	subq.l #1,d6	

transfer_loop

	move.l $10(a0),d0		;next block location
	beq file_not_found

	bsr Get_block
	tst.b error(a2)
	bne file_eror

****************************************
* Download data to file's load address *
****************************************

	lea $18(a0),a3		;1st data longword in dos_block
	moveq #$79,d7
make_file	subq.l #4,d6
	bmi.s last_bytes
	move.l (a3)+,(a5)+	
	dbf d7,make_file
	bra transfer_loop
last_bytes
	addq.w #4,d6
lb_loop	move.b (a3)+,(a5)+	
	dbf d6,lb_loop
	rts

file_not_found

	move.b #9,error(a2)		;file not found-error 8
file_eror	rts

*****************************
* File Load Called Routines *
*****************************

hash_name	move.l a6,a3
hash_loop	moveq #0,d2		;hash file name at a6
	move.b (a3)+,d2		;length-1 in d7.
	cmpi.b #$60,d2
	bls.s capital
	cmpi.b #$7a,d2
	bhi.s capital
	subi.b #$20,d2
capital	mulu #13,d0
	add.l d2,d0
	andi.l #$7ff,d0
	dbf d7,hash_loop
	divu #72,d0
	swap d0			;d0=hash number
	rts

compare_names

	moveq #0,d7
	cmp.b $1b0(a0),d6		;d6=length of name being tested
	bne.s name_fail
	move.w d6,d5
	move.l a6,a3
	lea $1b1(a0),a5
	subq.w #1,d5	
comp_loop	move.b (a3)+,d1		;Case desensitize filename
	move.b (a5)+,d2		;compare.
	andi.b #$df,d1
	andi.b #$df,d2
	cmp.b d1,d2
	dbne d5,comp_loop
	tst.w d5
	bpl.s name_fail
	moveq #1,d7
name_fail	rts


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

****************************
* Get a block into buffer! *
****************************

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

Get_block	movem.l a0-a6/d0-d7,-(a7)
	move.w #$0504,attempts(a2)
	andi.l #$ffff,d0
	cmpi.w #$6df,d0		;check range
	bls blk_in_range
	move.b #7,error(a2)
	bra no_reload

blk_in_range

	move.w d0,d1
	divu #11,d1		;what cylinder is that on?
	tst.b motor(a2)
	beq.s reload

	cmp.b trackside(a2),d1	
	beq.s Trksde_in		;that track is already in.

Reload	bsr Fetch_trackside		;loads track required
	tst.b error(a2)
	bne No_reload

Trksde_in	clr.b error(a2)
	move.l #MFMbuffer,a3
	lea $31fe(a3),a0
find_sync	move.w #$4489,d7
fs_loop	cmp.w (a3)+,d7
	beq found_sync
	cmp.l a0,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
	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 Not_sector

	lea $2(a3),a4		;Track mark = Head position?
	bsr decode_lw
	move.l d5,d4		
	swap d4
	cmp.b trackside(a2),d4
	beq 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?
	move.l d1,d7
	swap d7
	cmp.b d5,d7
	beq.s Found_block
	
Not_sector

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

Found_Block

	moveq #0,d2		;Put converted mfm at dest addr.
	move.l #$55555555,d7
	move.l #block_buffer,a6
	lea $3a(a3),a4		
	lea $23a(a3),a5
	moveq #$7f,d3
	
next_lw	move.l (a4)+,d6
	move.l (a5)+,d5
	and.l d7,d6
	and.l d7,d5
	eor.l d6,d2		;update checksum
	eor.l d5,d2
	add.l d6,d6
	or.l d5,d6
	move.l d6,(a6)+
	dbf d3,next_lw

	sub.w #$208,a4
	bsr decode_lw
	cmp.l d5,d2
	beq.s no_reload
	move.b #6,error(a2)		;checksum error - error 6
	
MFM_error	subq.b #1,attempts(a2)
	bne Reload
	bsr initialize_drive
	move.b #5,attempts(a2)
	subq.b #1,attempts+1(a2)
	bne Reload
	
No_reload	movem.l (a7)+,a0-a6/d0-d7
	rts

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

*********************
* MFM Track loader! *
*********************

* D1 will equal trackside 0 - 159

Fetch_trackside
	
	movem.l a0/d0-d3,-(a7)	
	move.l #$dff000,a0
	clr.b error(a2)		

	tst.b motor(a2)
	bne.s motor_on
	move.b #$ff,$100(a1)
	bclr #drive+3,$100(a1)
	bsr wait1msec
	btst #2,$1001(a1)
	bne.s start_mot
	btst #1,trackside(a2)
	beq.s inchk
	bsr stepout
	bra.s stepchk
inchk	bsr stepin
stepchk	btst #2,$1001(a1)
	beq.s no_disk
	bsr initialize_drive
	
start_mot	move.b #$7f,$100(a1)	;drive selected / motor on.
	bclr #drive+3,$100(a1)
	move.b #1,motor(a2)
	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 motor_on
	move.b #1,error(a2)		;no speed signal - error 1
	bra trackload_end

motor_on	btst #2,$1001(a1)		;disk removed?		
	bne.s disk_in
no_disk	move.b #3,error(a2)
	bra trackload_end

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

checkhead	move.b trackside(a2),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	move.b d1,trackside(a2)
	move.w #$2,$9c(a0)		;clear disk block irq flag
	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.w #$4000,$24(a0)	
	move.w #$10,$96(a0)		;disable dma

Trackload_end

	movem.l (a7)+,a0/d0-d3
	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	subq.b #2,trackside(a2)
	bset #1,$100(a1)
	bra.s step

stepin	addq.b #2,trackside(a2)
	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	clr.b trackside(a2)	
	move.w #20,d7
	bsr cia_wait
	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		;d1 = milliseconds to wait.
	rts

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

trackside    equ $0
error    	   equ $1
motor        equ $2
mode         equ $3
attempts     equ $4
load_address equ $6

variables	dcb.w $5,$0000

block_buffer	

	dcb.w $100,$0000


	section chipstuff,data_c


mfmbuffer	dcb.w $1910,$0000

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

