*******************************************************************
*                                                                 *
*   Hardware-File-Loader-Routine coded by Henning Saul for AFL    *
*                                                                 *
*      and published in Cracker Journal #25 by ALPHA FLIGHT       *
*******************************************************************
* Notes:                                                          *
*        1. The Load-Routine doesn't calc any checksum            *
*        2. The Filename in line 336 MUST look like the real      *
*           filename on the disk (take care of big&small chars!!) *
*        3. In this version the loader only works with drive 0,   *
*           so filenames like 'df1:Anything' won't work
*        4. If there are some lame-coded parts in this source,    *
*           please don't care as I do....                         *
*******************************************************************
* for any LEGAL reason                                            *
*           just call: 04124/2633 (ask for Henning/after 6 pm)    *
*         or write to: Henning Saul                               *
*                      Bgm.-Schinkel-Str. 8                       *
*                      W-2208 Glückstadt                          *
*                      Germany                                    *
*                                                                 *
*******************************************************************

datadest = $70000
jmp  $60000
org  $60000
load $60000

diskbegin:				; real prg-start
lea	$bfd100,a4			; get CIAAPRB
lea	$dff000,a5			; get customchip-baseadr
lea	diskbegin(pc),a6		; get adr of prgstart
;---------- INIT SYSTEM ---------- 
move.w	#$8000,d0			; set bit 15
move.w	$1c(a5),oldint-diskbegin(a6)	; save old intena
or.w	d0,oldint-diskbegin(a6)		; and set bit 15
move.w	$2(a5),olddma-diskbegin(a6)	; save old dma
or.w	d0,olddma-diskbegin(a6)		; and set bit 15
move.w	$10(a5),oldadk-diskbegin(a6)	; save old adk
or.w	d0,oldadk-diskbegin(a6)		; and set bit 15
subq.w	#1,d0				; d0->$7fff = clearword
move.w	d0,$9e(a5)			; clear adk
move.w	d0,$9a(a5)			; forbid interrupts
move.w	d0,$96(a5)			; stop dmas
move.w	#$8250,$96(a5)			; allow required dmas
move.w	#0,$24(a5)		        ; clear dsklen
move.w	#$4489,$7e(a5)			; set standard (DOS) SYNC
move.w	#$9500,$9e(a5)			; set bits for mfm&sync

bsr	initdrive			; init df0: &step to track 0
bsr	gethashtab			; get hash for dir 'DF0:'
lea	filename(pc),a0			; adr of filename to load
lea	datadest,a1			; adr to load filedata to
bsr.s	loadfile			; load desired file

move.w	olddma(pc),$96(a5)		; restore dma-reg
move.w	oldint(pc),$9a(a5)		; restore int-reg
move.w	oldadk(pc),$9e(a5)		; restore adk-reg
rts					; bye bye

;---------- LOAD A FILE FROM "DF0:"----------
;----- returns in d0: <>0 = file not found -----
;----- a0=must contain adr of name/a1=adr to load file to
;----------------------------------------------
loadfile:				; a0 must be adr of filename
bsr	motoron				; aeehh...turn motor on
moveq	#0,d7				; clear work-reg
move.b	(a0)+,d7			; get number of chars
move.l	a0,d6				; save adr of fileNAME
;---------- CALC HASH OF FILE ----------
move.l	d7,d0				; Hash=Length of name
move.l	d0,d1				; get number of chars
subq.b	#1,d1				; one less bcoz of dbra
moveq	#0,d2				; clear work reg
calchashloop:				; let's keep calcin'
mulu	#13,d0				; Hash=Hash*13
move.b	(a0)+,d2			; get a char
cmp.b	#'a',d2				; char < 'a'
blt.s	bigchar				; ok ok
cmp.b	#'z',d2                        	; char > 'z'
bgt.s	bigchar				; ok ok,too
sub.b	#$20,d2				; correct it (->big char)
bigchar:				; char was a big one
add.w	d2,d0				; Hash=Hash+char
and.w	#$7ff,d0			; that's it ?!
dbra	d1,calchashloop			; all chars done ?!
divu	#72,d0				; number of entries
swap	d0				; want rest
;---------- GET FILEHEADER-BLOCK ----------
lsl.w	#2,d0				; mulu #4,d0 bcoz longwords
lea	hashtab(pc),a0			; get hashtab-baseadr
move.l	(a0,d0.w),d0			; get blocknumber
getfileheader:				; is it the right fileheader
divu	#11,d0				; divide blocknumber
bsr	readtrack			; and read track
swap	d0				; get sectornumber
ror.w	#7,d0				; ->mulu #512,d0
lea	databuffer(pc),a0		; get data-baseadr
add.w	d0,a0				; and go to right sectordata
move.l	d6,a2				; get adr of fileNAME
lea	$1b0(a0),a3			; get begin of nameinfo
cmp.b	(a3)+,d7			; test if same namelength
bne.s	wrongfileheader			; no->get another fileheader
testifrightheader:			; otherwise check name
move.b	(a3)+,d0			; get a char
cmp.b	(a2)+,d0			; test if char equal
bne.s	wrongfileheader			; no->get another fileheader
subq.w	#1,d7				; all chars compared
bne.s	testifrightheader		; no->keep comparin'
bra.s	rightfileheader			; yes->load the blocks
wrongfileheader:			; file with same hash
move.l	$1f0(a0),d0			; otherwise next fileheader
bne.s	getfileheader			; <> 0 ->perhaps next header
moveq	#-1,d0				; set signal 'file not fou.'
rts					; bye bye
rightfileheader:			; right fileheader found
move.l	$10(a0),d0			; get fileheader-block
;---------- LOAD BLOCKS OF FILE ----------
loadablock:				; load another block
divu	#11,d0				; divide blocknumber
bsr.s	readtrack			; and read track
swap	d0				; get sectornumber
ror.w	#7,d0				; ->mulu #512,d0
lea	databuffer(pc),a0		; get data-baseadr
add.w	d0,a0				; and go to right sectordata
move.l	$c(a0),d1			; get number of bytes
move.l	$10(a0),d0			; get next blocknumber
lea	$18(a0),a0			; go to real data
copyblockdata:				; copy real data
move.b	(a0)+,(a1)+			; copy a byte
subq.w	#1,d1				; one byte more copied
bne.s	copyblockdata			; all data copied ?
tst.w	d0				; all blocks loaded
bne.s	loadablock			; no->load next one
bsr	motoroff			; aeehh...turn motor off
rts					; file loaded



;---------- SELECT DF0: & STEP TO TRACK 0 ----------
initdrive:				; select df0: and step to 0
;---------- SELECT DRIVE ---------- 
or.b	#%01111000,(a4)			; all drives off
nop					; wait a bit
nop					; wait a bit
and.b	#%11110111,(a4)			; select drive 0 (activelow)
;---------- HEADS ON TRACK 0 ----------
or.b    #%00000010,(a4)			; step outwards
nop					; wait a bit
nop					; wait a bit
searchtrack0loop:			; keep steppin'
btst	#4,$bfe001			; heads at track 0 ?
beq.s	track0found			; yes->fine
and.b   #%11111110,(a4)			; step a bit
nop					; wait a bit
nop					; wait a bit
or.b	#%00000001,(a4)			; stop steppin'
bsr	timer				; let's have a break
bra.s	searchtrack0loop		; keep steppin'
track0found:				; heads at track 0
rts					; everything ready


;---------- LOAD ROOTBLOCK & GET HASH-TAB ----------
gethashtab:				; get 72 hash-entries
bsr	motoron				; aeehh...turn motor on
;---------- LOAD ROOTBLOCK ----------
move.w  #80,d0				; track to read
bsr.s	readtrack			; and read it
;---------- GET "PAGES"-HASHTAB ----------
lea	databuffer+24(pc),a0		; go to hashtab-baseadr
lea	hashtab(pc),a1			; dest for hashtab
moveq	#72-1,d0			; get 72 hashvalues
getahash:				; get another value
move.l	(a0)+,(a1)+			; save a hash
dbra	d0,getahash			; all 72 hashes saved ?
bsr	motoroff				; aeehh...turn motor off
rts					; hashtab for 'DF0:' saved


;---------- LOAD & DECODE A TRACK ----------
readtrack:				; read a track (d0=track)
movem.l	d0-d7/a0-a6,-(a7)		; save regs
move.w	d0,d2				; save desired track
sub.w	track(pc),d2			; calc difference
beq	trackloaded			; old track->don't load it
bgt.s	stepinside			; step to the middle
;---------- STEP OUTWARDS ----------
stepoutside:				; set right step-direction
or.b	#%00000010,(a4)			; first...step outwards
moveq	#-2,d1				; one step=2tracks
bra.s	checkhead			; check if right head
;---------- STEP TO THE MIDDLE ----------
stepinside:				; set right step-direction
and.b	#%11111101,(a4)			; step to the middle
moveq	#2,d1				; one step=2tracks
;---------- SELECT RIGHT HEAD ----------
checkhead:				; change head ?
btst	#0,d2				; test if difference even
beq.s	letsstep			; yes->don't change head
btst	#0,d0				; new track number even ?
beq.s	lowerhead			; yes->select head 0
and.b	#%11111011,(a4)			; otherwise select head 1
addq.w	#1,track-diskbegin(a6)		; ->current track+1
bra.s	letsstep			; and now start stepping
lowerhead:				; new track number even
or.b	#%00000100,(a4)			; select head 0
subq.w	#1,track-diskbegin(a6)		; current track-1
;---------- STEP TO DESIRED TRACK ----------
letsstep:				; step to right track
nop					; wait a bit
nop					; wait a bit
steploop:				; step to wanted track
cmp.w	track(pc),d0			; save new headpos
beq.s	trackfound			; yeah->now turn on drive
and.b	#%11111110,(a4)			; step a bit
nop					; wait a bit
nop					; wait a bit
or.b	#%00000001,(a4)			; stop steppin'
bsr	timer				; let's have a break
add.w	d1,track-diskbegin(a6)		; another step done
bra.s	steploop			; keep steppin'
trackfound:				; on right track now
;---------- TEST IF READY TO LOAD ----------
waitfordrive:				; test if ready for action
btst	#5,$bfe001			; test disk-ready-bit
bne.s	waitfordrive			; set->keep waitin'
;---------- LOAD TRACK ----------
move.w	#0,$24(a5)		        ; clear dsklen
lea	trackbuffer(pc),a0		; get dest adr
move.l	a0,$20(a5)			; and set DSKPT
move.w	#$9a00,$24(a5)			; set amount of words to 
move.w	#$9a00,$24(a5)			; load and enable diskdma
;---------- WAIT TILL TRACK LOADED ----------
waitfordiskdma:				; test if track loaded
btst	#1,$1f(a5)			; test dskblk-reqbit
beq.s	waitfordiskdma			; not set->keep waitin'
move.w	#0,$24(a5)		        ; clear dsklen
move.w	#$0002,$9c(a5)			; clear dskblk-reqbit
;---------- DECODE LOADED DATA ----------
lea	trackbuffer(pc),a0		; get sourceadr
moveq	#11-1,d6			; 11 sectors to decode
decodeasector:				; decode another sector
cmp.w	#$4489,(a0)+			; test if sync
bne.s	decodeasector			; no->keep searchin'
searchnextsync:				; test if any more syncs
cmp.w	#$4489,(a0)			; test if another sync
bne.s	nomoresyncs			; no->get sectornumber
addq.w	#2,a0				; skip sync
bra.s	searchnextsync			; and test if another one
nomoresyncs:				; all syncs skipped
moveq	#0,d1				; clear work-reg
move.b	2(a0),d1			; get sectornumber(odd bits)
move.b	6(a0),d2			; get sectornr (even bits)
and.b	#$55,d1				; only want even bits
and.b	#$55,d2				; (mask tactbits)
add.b	d1,d1				; d1=odd bits of sectornr
or.b	d2,d1				; d1=sectornumber
ror.w	#7,d1				; mulu #512,d1
lea	databuffer+510(pc),a1		; decode-destadr
lea	(a1,d1.w),a1			; go to right sector dest
lea	56(a0),a0			; go to real data
lea	510(a0),a0			; last word of odd bits
lea	512(a0),a3			; last word of even bits
bsr.s	waitblitter			; wait till blitter ready
move.l	#$1dd80002,$40(a5)		; ashift=1;descmode
moveq	#-1,d1				; =$ffffffff
move.l	d1,$44(a5)			; don't mask anythink
moveq	#0,d1				; no modulo
move.w	d1,$60(a5)			; bmod/cmod=0
move.l	d1,$64(a5)			; amod/dmod=0
move.w	#$5555,$70(a5)			; cdat=mask for sourcedata
move.l	a0,$50(a5)			; write source (odd bits)
move.l	a3,$4c(a5)			; write source (even bits)
move.l	a1,$54(a5)			; write dest
move.w	#[256*64]+1,$58(a5)		; decode 256 words
move.l	a3,a0				; get new source
dbra	d6,decodeasector		; all sectors decoded ?
bsr.s	waitblitter			; wait till blitter ready
trackloaded:				; got data
movem.l	(a7)+,d0-d7/a0-a6		; restore regs
rts					; bye bye


;---------- SWITCH ENGINE ON ----------
motoron:				; start rotating
or.b	#%00001000,(a4)			; drive 0 inactive
nop					; wait a bit
nop					; wait a bit
and.b	#%01111111,(a4)			; clear enginebit
nop					; wait a bit
nop					; wait a bit
and.b	#%11110111,(a4)			; drive 0 active->engine on
rts					; motor startin'

;---------- SWITCH ENGINE OFF ----------
motoroff:				; stop rotating
or.b	#%00001000,(a4)			; drive 0 inactive
nop					; wait a bit
nop					; wait a bit
or.b	#%10000000,(a4)			; set enginebit
nop					; wait a bit
nop					; wait a bit
and.b	#%11110111,(a4)			; drive 0 active->engine off
rts					; motor stoppin'

;---------- WAIT TILL BLITTER FINISHED ----------
waitblitter:				; wait till blitter ready
btst	#14,2(a5)			; ready for action
bne.s	waitblitter			; no->keep waintin'
rts					; let's go on
;---------- TIMER-ROUT FOR STEPPING-ACTIONS ----------
timer:					; waits ca. 1/100 sec
move.b	#$00,$bfdf00			; clear CRB
move.b	#$7f,$bfdd00			; clear ICR
move.b	#$00,$bfd600			; timer b lowbyte
move.b	#$1c,$bfd700			; timer b highbyte
move.b	#$09,$bfdf00			; set oneshot/start
waittimer:				; wait about 1/100 sec
btst	#1,$bfdd00			; test tb-bit ->clear ICR
beq.s	waittimer			; not set->wait
rts					; let's go on
;---------- NOW ONLY THE SHITTY REST ----------
oldint: dc.w 0
olddma: dc.w 0
oldadk: dc.w 0
track:  dc.w 0
trackbuffer:
blk.w 6656,0
databuffer:
blk.b 11*512,0
hashtab:
blk.l 72,0
filename:
dc.b    6,"Werner"	     ; number (6) = number of chars of file 
