; MFM DMA loader.
; (C)William Lunney April 92'.

; This version (7:4:92) reads and decodeds raw MFM data as laid down by the
; Trackdisk.device.  It will check block header checksums, and re-read the
; entire track if an error occured.  It does not bother calculating header
; checksums.
; This version uses the 68000 for decoding.
; NOTE:  Although the system is restored, drive 0 will become unuseable
; until reset.

; Have a nice day!.

; 10-Oct-92:	Started optimising code by using offsets+constant values for
;		frequently used instructions etc, entry params changed to
;		registers rather than memory locations, code made 100%
;		PC relative, start block is now stored in word format rather
;		than LW, loads bytes rather than whole sectors.
; 19-Nov-92:	Multiple drive access possible, init routine added so that
;		buffer locations, track 0 re-seting, & drive selection can be
;		made.
; 20-Nov-92:	Silly intena bug removed, the DSKBLK bit DOSENT have to be
;		active for the interupt to be cheked upon.


		move.b	#1,d0			; Initialise loader
		lea	$60000,a0		; Raw track buffer start
		lea	$70000,a1		; Decoded track start
		bsr	init_loader

		lea	$50000,a0		; Load address
		move	#0,d0			; Start block
		move.l	#$f000,d1		; Bytes to load
		bsr	load_data
		rts
*****************************************************************************
*			LOADER INITIALISATION ROUTINE			    *
*****************************************************************************
; ENTRY: A0=Raw track buffer, A1=Decoded track buffer, D0=drive number

init_loader	lea	raw_track_buffer(pc),a2
		lea	decoded_track_buffer(pc),a3
		lea	which_drive?(pc),a4
		move.l	a0,(a2)				; Raw track buffer
		move.l	a1,(a3)				; Decoded track
		move.b	d0,(a4)				; Drive number
		lea	loader_info_buffer(pc),a4
		lea	$bfd000,a5			; CIA-B register base
		lea	custom_base,a6
		bsr	preserve_system
		bsr	kill_system
		bsr	motor_on
		bsr	find_track0
		bsr	motor_off
		bsr	restore_system
		rts
*****************************************************************************
*		    SYSTEM PRESERVE, RESTORE & KILL ROUTINES		    *
*****************************************************************************
preserve_system	movem.l	a6/a4/d0,-(sp)
		lea	custom_base,a6
		lea	loader_info_buffer(pc),a4
		move	dmaconr(a6),old_dmacon(a4)
		move	intreqr(a6),old_intreq(a4)
		move	intenar(a6),old_intena(a4)
		move	adkconr(a6),old_adkcon(a4)
		move	#%1000000000000000,d0
		or	d0,old_dmacon(a4)
		or	d0,old_intreq(a4)
		or	d0,old_intena(a4)
		or	d0,old_adkcon(a4)
		movem.l	(sp)+,a6/a4/d0
		rts

restore_system	movem.l	a6/a4,-(sp)
		lea	custom_base,a6
		lea	loader_info_buffer(pc),a4
		move	#%0111111111111111,intena(a6)
		move	old_dmacon(a4),dmacon(a6)
		move	old_intreq(a4),intreq(a6)
		move	old_adkcon(a4),adkcon(a6)
		move	old_intena(a4),intena(a6)
		movem.l	(sp)+,a6/a4
		rts

kill_system	move.l	a6,-(sp)
		lea	custom_base,a6
		move	#%0111111111111111,intena(a6)
		move	#%1000001000010000,dmacon(a6)	; Enable disk DMA
		move.l	(sp)+,a6
		rts
*****************************************************************************
*				MFM LOADER				    *
*****************************************************************************
; ENTRY:  A0.l=load address, D0.w=start block, D1.l=bytes to load

sync_mark	equ	$4489
trk_read_len	equ	$9cbe-$400	; $9cbe=OS read len ($98be read len)

		RSRESET
blkhd_ID	rs.b	1			; AmigaDOS sector structure
blkhd_track_no	rs.b	1
blkhd_sect_no	rs.b	1
blkhd_sc_to_gap	rs.b	1
blkhd_hdr_cksum	rs.l	1
blkhd_blk_cksum	rs.l	1

load_data	movem.l	d0-d7/a0-a6,-(sp)	; Preserve regs etc
		bsr	preserve_system
		bsr	kill_system
		lea	custom_base,a6		; Setup constants
		lea	$bfd000,a5		; CIA-B register base
		move.l	#$55555555,d5
		lea	loader_info_buffer(pc),a4
		move.l	a0,load_address(a4)
		andi.l	#$0000ffff,d0
		move	d0,start_block(a4)
		move.l	d1,bytes_to_load(a4)

		bsr	motor_on
;		bsr	find_track0		; Not needed anymore
read_data_loop	moveq	#0,d0
		move	start_block(a4),d0
		divu	#11,d0
		cmp	decoded_track(a4),d0	; Has the track already been
		beq.s	been_decoded		; decoded?.

		move	d0,track_to_load(a4)	; If not, load and decode the
		bsr	read_track		; entire track.
		bsr.s	decode_track

been_decoded	movea.l	decoded_track_buffer(pc),a0	; Xfer data from the
		moveq	#0,d0			; decoded track buffer to the
		move	start_block(a4),d0	; destination address.
		divu	#11,d0
		swap	d0
		andi.l	#$0000ffff,d0		; Mask off remainder
		mulu	#512,d0
		adda.l	d0,a0			; A0=Start of REAL data
		move	#512-1,d7
		movea.l	load_address(a4),a1
trnsfer_loop	move.b	(a0)+,(a1)+		; Xfer 1 byte to destination
		addi.l	#1,load_address(a4)	; Inc by xfered amount
		subi.l	#1,bytes_to_load(a4)
		beq.s	load_complete
		dbf	d7,trnsfer_loop

		addi	#1,start_block(a4)	; next sector
		bra.s	read_data_loop
load_complete	bsr	motor_off
		bsr	restore_system
		movem.l	(sp)+,d0-d7/a0-a6
		rts
*****************************************************************************
*			   DECODE TRACK ROUTINE				    *
*****************************************************************************
decode_track	movea.l	raw_track_buffer(pc),a0	; If the track has an error,
		move	#$10d,d7		; then try re-reading it.
		moveq	#11-1,d6		; 11 sectors to decode
find_2nd_marker	cmpi	#sync_mark,(a0)+
		beq.s	find_2nd_marker
		suba.l	#2,a0			; Lock onto 2nd sync mark
		movea.l	a0,a1

		move	#1024/4,d7		; Length of 1 coded block
		lea	56(a0),a3		; A3=Start of coded datablock
		bsr.s	check_checksum
		move.l	d0,d4			; Checksum into D4
		lea	48(a0),a3		; A3=Block header checksum
		move.l	(a3)+,d0
		move.l	(a3)+,d1
		and.l	d5,d0
		and.l	d5,d1
		lsl.l	#1,d0
		or.l	d1,d0
		cmp.l	d0,d4			; If error, re-read the track.
		beq.s	block_ok
		bsr.s	read_track
		bra.s	decode_track

block_ok	move.l	(a0)+,d0		; Decode the block header.
		move.l	(a0)+,d1
		and.l	d5,d0
		and.l	d5,d1
		lsl.l	#1,d0
		or.l	d0,d1
		move.l	d1,-8(a0)

		movea.l	decoded_track_buffer(pc),a0	; Decode 1 sector
		moveq	#0,d0
		move.b	blkhd_sect_no(a1),d0
		mulu	#512,d0
		adda.l	d0,a0			; A0=Start place in dec buffer
		lea	$38(a1),a2
		moveq	#(512/4)-1,d7
decode_sct_loop	move.l	(a2),d0
		move.l	512(a2),d1
		and.l	d5,d0			; Trash clock bits
		and.l	d5,d1
		lsl.l	#1,d0			; LW1 gets shifted left
		or.l	d0,d1			; and OR'ed with LW2...
		move.l	d1,(a0)+		; and here's the final.
		adda.l	#4,a2
		dbf	d7,decode_sct_loop

find_nxt_sector	cmpi	#sync_mark,(a2)+	; Find start of next sector.
		bne.s	find_nxt_sector
		movea.l	a2,a0
		dbf	d6,find_2nd_marker
		moveq	#0,d0
		move	start_block(a4),d0
		divu	#11,d0
		move	d0,decoded_track(a4)
		rts
*****************************************************************************
*			CHECKSUM CHECKER ROUTINE			    *
*****************************************************************************
; ENTRY: D7=no of LW's to check, A0=buffer start
; EXIT: If error D0=1, else =0.

check_checksum	subq	#1,d7			; No. of longwords -1 for DBF
		moveq	#0,d0
checksum_loop	move.l	(a3)+,d1
		eor.l	d1,d0
		dbf	d7,checksum_loop
		and.l	d5,d0
		rts
*****************************************************************************
*			    READ RAW TRACK ROUTINE			    *
*****************************************************************************
read_track	move	track_to_load(a4),d0
		move	current_track(a4),d1
		andi	#$fe,d0			; Clear side bit
		andi	#$fe,d1
		cmp	d0,d1			; Over correct cylinder ?
		beq.s	on_wnted_clnder
		bgt.s	out_a_track
		bsr	head_in
		bra.s	read_track
out_a_track	bsr	head_out
		bra.s	read_track
on_wnted_clnder	move	track_to_load(a4),d0	; If track no. is even load
		btst	#0,d0			; bottom side, else the top.
		bne.s	select_top_side
		bset	#2,$100(a5)			; $bfd100
		bra.s	rdy_to_read_trk
select_top_side	bclr	#2,$100(a5)
rdy_to_read_trk	move	#%1000001000010000,dmacon(a6)
		move	#%0111111111111111,adkcon(a6)
		move	#%1000010100000000,adkcon(a6)	; Sync on, 2ms
		move	#sync_mark,dsksync(a6)
		move.l	raw_track_buffer(pc),dskpt(a6)
		move	#$4000,dsklen(a6)		; Init DMA op
		move	#trk_read_len,dsklen(a6)
		move	#trk_read_len,dsklen(a6)
trk_read_wait	move	intreqr(a6),d0
		btst	#1,d0
		beq.s	trk_read_wait
		move	#%0000000000000010,intreq(a6)	; ack DSKBLK interupt
		move	#$4000,dsklen(a6)		; Stop disk DMA
		move	track_to_load(a4),d0
		move	d0,track_in_memory(a4)
		rts
*****************************************************************************
*			 DRIVE MOTOR ON, OFF ROUTINES			    *
*****************************************************************************
motor_on	move.b	which_drive?(pc),d0
		addq	#3,d0			; Drive 0 = bit 3
		move.b	#$7d,$100(a5)		; De-select all drives
		nop
		nop
		move.b	#%01111101,d1		; Select drive
		bclr	d0,d1
		move.b	d1,$100(a5)
		bsr	head_wait_delay
		bsr.s	drive_rdy_wait
		rts

motor_off	move.b	which_drive?(pc),d0
		addq	#3,d0
		move.b	#$fd,$100(a5)
		nop
		nop
		move.b	#%11111111,d1
		bclr	d0,d1
		move.b	d1,$100(a5)
		bsr.s	head_wait_delay
		rts


drive_rdy_wait	btst	#5,$bfe001		; Wait 4 motor to reach full
		bne.s	drive_rdy_wait		; speed.
		rts

which_drive?	dc.b	1
raster_counter	dc.b	0
		even
*****************************************************************************
*			     STEP HEAD ROUTINES				    *
*****************************************************************************
lines_to_wait	equ	150

find_track0	bsr.s	motor_on
fnd_trk0_loop	btst	#4,$bfe001		; Put head on track 0
		beq.s	on_track0
		bsr.s	head_out
		bra.s	fnd_trk0_loop
on_track0	clr	current_track(a4)	; Reset internal trak counter
		rts

head_in		bclr	#1,$100(a5)
		bclr	#0,$100(a5)
		bset	#0,$100(a5)
		addi	#2,current_track(a4)
		bsr.s	head_wait_delay
		bsr.s	drive_rdy_wait
		rts

head_out	bset	#1,$100(a5)
		bclr	#0,$100(a5)
		bset	#0,$100(a5)
		subi	#2,current_track(a4)
		bsr.s	head_wait_delay
		bsr.s	drive_rdy_wait
		rts


head_wait_delay	lea	raster_counter(pc),a3
		move.b	#lines_to_wait,(a3)
raster_wait2	move.b	vhposr(a6),d7
newline_wait	cmp.b	vhposr(a6),d7
		bne.s	counter_m1
		bra.s	newline_wait
counter_m1	subi.b	#1,(a3)
		bne.s	raster_wait2
		rts



		RSRESET
current_track	rs.w	1
track_to_load	rs.w	1
track_in_memory	rs.w	1
decoded_track	rs.w	1
start_block	rs.w	1
bytes_to_load	rs.l	1
load_address	rs.l	1
old_dmacon	rs.w	1
old_intreq	rs.w	1
old_intena	rs.w	1
old_adkcon	rs.w	1


loader_info_buffer:
		dc.w	-1		; Internal variables (current track)
		dc.w	-1		; track to load
		dc.w	-1		; track in memory
		dc.w	-1		; decoded track
		dc.w	0		; User variables (start block)
		dc.l	0		; Bytes to load
		dc.l	$50000		; Load address
		dcb.w	4		; System status

raw_track_buffer	dc.l	0
decoded_track_buffer	dc.l	0
;decoded_track_buffer	equ	raw_track_buffer+(2*trk_read_len)
*****************************************************************************
*			HARDWARE EQUATES				    *
*****************************************************************************
potgo	equ	$34
potgor	equ	$16

dmaconr	EQU   $002	;Some hardware register equates.
vhposr	EQU   $006

intenar	EQU   $01C
intreqr	EQU   $01E

copcon	EQU   $02E

aud0vol	equ	$a8
aud0per	equ	$a6
aud0len	equ	$a4
aud0pth	equ	$a0

bltcon0	EQU   $040
bltcon1	EQU   $042
bltafwm	EQU   $044
bltalwm	EQU   $046
bltcpt	EQU   $048
bltcpth	equ	$48
bltcptl	equ	$4a
bltbpt	EQU   $04C
bltbpth	equ	$4c
bltbptl	equ	$4e
bltapt	EQU   $050
bltapth	equ	$50
bltaptl	equ	$52
bltdpt	EQU   $054
bltdpth	equ	$54
bltdptl	equ	$56
bltsize	EQU   $058
bltadat	EQU   $074
joy1dat	EQU   $00C

bltcmod	EQU   $060
bltbmod	EQU   $062
bltamod	EQU   $064
bltdmod	EQU   $066

clxcon	EQU	$098
clxdat	EQU	$00e
cop1lc	EQU   $080
cop2lc	EQU   $084
copjmp1	EQU   $088
copjmp2	EQU   $08A
diwstrt	EQU   $08E
diwstop	EQU   $090
ddfstrt	EQU   $092
ddfstop	EQU   $094
dmacon	EQU   $096
intena	EQU   $09A
intreq	EQU   $09C

bplcon0	EQU   $100
bplcon1	EQU   $102
bplcon2	EQU   $104
bpl1mod	EQU   $108
bpl2mod	EQU   $10A

blitter_busy	equ	14
copper_int	equ	4
mouse		equ	6
fire_button_port1	equ	7
filter		equ	1
execbase	equ	4
custom_base	equ	$dff000

colour00	equ	$180
colour01	equ	$182
colour02	equ	$184
colour03	equ	$186
colour04	equ	$188
colour05	equ	$18a
colour06	equ	$18c
colour07	equ	$18e
colour08	equ	$190
colour09	equ	$192
colour10	equ	$194
colour11	equ	$196
colour12	equ	$198
colour13	equ	$19a
colour14	equ	$19c
colour15	equ	$19e
colour16	equ	$1a0
colour17	equ	$1a2
colour18	equ	$1a4
colour19	equ	$1a6
colour20	equ	$1a8
colour21	equ	$1aa
colour22	equ	$1ac
colour23	equ	$1ae
colour24	equ	$1b0
colour25	equ	$1b2
colour26	equ	$1b4
colour27	equ	$1b6
colour28	equ	$1b8
colour29	equ	$1ba
colour30	equ	$1bc
colour31	equ	$1be

findtask	equ	-294
addport		equ	-354
remport		equ	-360
openlib		equ	-408
closelib	equ	-414
opendev		equ	-444
closedev	equ	-450
doIO		equ	-456

adkcon		equ	$9e
adkconr		equ	$10
dsksync		equ	$7e
dskpt		equ	$20
dsklen		equ	$24
dskdat		equ	$26

