****************************************************************************
*(Amiga)	DISK.S	Example disk access code
****************************************************************************
*	On entry	a6.l = CUSTOM
****************************************************************************
*	Note:	All delays are compatible with NTSC and PAL
****************************************************************************
* These are sample routines from my own amiga disk routine library. They
* should contain enough clues for you to create you own custom routines,
* without giving too much about my own away !
****************************************************************************


	INCLUDE	"c:\headers.s\amiga\hardware\custom.i"
	INCLUDE	"c:\headers.s\amiga\hardware\cia.i"

DISK_OP_BUFFER_SIZE	EQU	20		(longwords)

CUSTOM	EQU	$dff000	hardware addresses
CIAA	EQU	$bfe001
CIAB	EQU	$bfd000

DISKDESELECT	EQU	-1	Disk operation ID's
DISKSELECT	EQU	0
DISKFORMAT	EQU	1
DISKREAD	EQU	2
DISKWRITE	EQU	3

*	Disk operation results:	0 if operation incomplete
*			-ve error code if failed
*			+ve disk ID if successful

DRIVE_EMPTY	EQU	-1	disk operation error codes
DISK_REMOVED	EQU	-2
DISK_PROTECTED	EQU	-3
CANT_SYNC	EQU	-4
CHECKSUM_ERROR	EQU	-5

	OFFSET	0	Disk structure standard offsets
disk_operation	DS.W	1
disk_op_result	DS.L	1
disk_buffer	DS.L	1	pointer to disk buffer (chipmem)
disk_standard_header

	OFFSET	disk_standard_header	Used by select
disk_drive	DS.W	1	drive number (0-4)

	OFFSET	disk_standard_header	Used by format
disk_format_id	DS.L	1

	OFFSET	disk_standard_header	Used by read/write
disk_op_size	DS.L	1	in BYTES, but must be EVEN
disk_address	DS.L	1	must be EVEN
disk_memptr	DS.L	1	must be EVEN

	OFFSET	0	Offsets into buffers
raw_checksum	DS.L	1	8 byte header
raw_disk_id	DS.L	1
raw_data	DS.B	748*8	data (multiple of 8)
*	-------------------------------------------------------------
mfm_header	DS.L	1	storage for $AAAA8944
mfm_data1	DS.B	749*8
mfm_data2	DS.B	749*8
mfm_bugspace	DS.B	2	extra 2 bytes for hardware bug
DISKBUFLENGTH1
*	-------------------------------------------------------------
format_buffer	DS.B	14500
DISKBUFLENGTH2

	TEXT

deselect	lea	CIAB,a1
	move.b	#%11111011,ciaprb(a1)	set all drives high
	move.b	#%10000011,ciaprb(a1)	motors off
	move.b	#%11111011,ciaprb(a1)	set all drives high
	bra	new_operation
*---------------------------------------------------------------------------
select1	move.b	#%11111011,ciaprb(a1)	select bits high
	move.w	disk_drive(a2),d1
	add.w	#3,d1
	bclr.b	d1,ciaprb(a1)			select drive
	addq.l	#4,stage_pointer
	btst.b	#4,ciapra(a0)			Track 0 ?
	beq	step_in			yes, so step in
	bra	step_out			step sets DSKCHANGE
*---------------------------------------------------------------------------
select2	btst.b	#2,ciapra(a0)			Disk in drive ?
	beq	empty_error
	btst.b	#4,ciapra(a0)			Track 0 ?
	bne	step_out			no -step out
*	-------------------------------------------------------------
	clr.w	track			track 0, side 0
	move.b	#%01111001,ciaprb(a1)	upper head,inwards
	move.w	disk_drive(a2),d1
	add.w	#3,d1
	bclr.b	d1,ciaprb(a1)			select drive -motor on
	addq.l	#4,stage_pointer		return to next stage
	move.w	#500,d0			500ms delay
	bra	set_delay
*---------------------------------------------------------------------------
setup_format	clr.w	required_track			track 0, upper side
	move.w	#160,whole_tracks		all tracks
*	-------------------------------------------------------------
	lea	format_buffer(a3),a4
	move.w	#14500/2-5-1,d0
.loop1	move.w	#$AAAA,(a4)+
	dbra	d0,.loop1
	move.l	#$44892AAA,(a4)+	sync marker + adjusted word
	move.l	#$AAAAAAAA,(a4)
*	-------------------------------------------------------------
	move.l	disk_format_id(a2),raw_disk_id(a3)
	lea	raw_data(a3),a4
	move.w	#5992/8-1-1,d0
.loop2	clr.l	(a4)+
	clr.l	(a4)+
	dbra	d0,.loop2
*	-------------------------------------------------------------
	addq.l	#4,stage_pointer
	bra	next_stage
*---------------------------------------------------------------------------
next_format	subq.w	#1,whole_tracks
	beq	.exit
.loop	sub.l	#10*4,stage_pointer
	bra	next_stage
.exit	addq.l	#4,stage_pointer
	bra	next_stage
*
*---------------------------------------------------------------------------
setup_transfer addq.l	#4,stage_pointer
	move.l	disk_memptr(a2),next_memory
	cmp.l	#$200000,next_memory	chip or fastmem ?
	sge	fastmem_flag
	move.l	disk_address(a2),d0
	divu	#748*8,d0			gives start byte/track
*	-------------------------------------------------------------
	lsl.w	#7,d0			move track to top byte
	btst.l	#7,d0			test required side
	sne	d0			side in bottom byte
	move.w	d0,required_track		store required track/side
*	-------------------------------------------------------------
.calcs	swap	d0			start_byte in low word
	move.w	d0,start_byte			store start byte
	ext.l	d0
	neg.l	d0
	add.l	#748*8,d0			748*8-start_byte
	cmp.l	disk_op_size(a2),d0
	bge.s	.onetrack
*	-------------------------------------------------------------
.severaltracks move.w	d0,first_bytes
	neg.l	d0			-(748*8-start_byte)
	add.l	disk_op_size(a2),d0 	+disk_op_size
	divu	#748*8,d0
	move.l	d0,last_bytes		store last_bytes/whole_tracks
	bra	next_stage
*	-------------------------------------------------------------
.onetrack	move.w	disk_op_size+2(a2),first_bytes
	clr.l	last_bytes		clear last_bytes/whole_tracks
	bra	next_stage
*
*---------------------------------------------------------------------------
pre_read	tst.l	last_bytes		any last_bytes/whole_tracks ?
	bne.s	.notonetrack
.onetrack	move.w	first_bytes(pc),last_bytes
	add.l	#15*4,stage_pointer
	bra	next_stage
.notonetrack	addq.l	#4,stage_pointer
	bra	next_stage
*---------------------------------------------------------------------------
read_from_buf1 move.l	next_memory(pc),a4
	lea	raw_data(a3),a5
	add.w	start_byte(pc),a5
	clr.w	start_byte			clear for read_from_buf3
	move.w	first_bytes,d0
*	-------------------------------------------------------------
	tst.w	whole_tracks			any whole tracks ?
	beq.s	.test_last
	addq.l	#4,stage_pointer		whole tracks next
	bra	transfer1
.test_last	tst.w	last_bytes			any last bytes ?
	beq.s	.success_next
	add.l	#8*4,stage_pointer		last bytes next
	bra	transfer1
.success_next	add.l	#14*4,stage_pointer 	success next
	bra	transfer1
*---------------------------------------------------------------------------
read_from_buf2 move.l	next_memory(pc),a4
	lea	raw_data(a3),a5
*	-------------------------------------------------------------
	subq.w	#1,whole_tracks
	beq.s	.test_last
	sub.l	#6*4,stage_pointer		loop
	bra	transfer2
.test_last	tst.w	last_bytes			any last bytes ?
	beq.s	.success_next
	add.l	#4,stage_pointer		last bytes next
	bra	transfer2
.success_next	add.l	#7*4,stage_pointer		success next
	bra	transfer2
*---------------------------------------------------------------------------
read_from_buf3 move.l	next_memory(pc),a4
	lea	raw_data(a3),a5
	add.w	start_byte(pc),a5
	move.w	last_bytes(pc),d0
	addq.l	#4,stage_pointer
	bra	transfer1
*
*---------------------------------------------------------------------------
write_to_buf1	lea	raw_data(a3),a4
	add.w	start_byte(pc),a4
	move.l	next_memory(pc),a5
	move.w	first_bytes,d0
	addq.l	#4,stage_pointer
	bra	transfer1
*---------------------------------------------------------------------------
write_to_buf2	subq.w	#1,whole_tracks
	bmi.s	.test_last
	lea	raw_data(a3),a4
	move.l	next_memory(pc),a5
	sub.l	#10*4,stage_pointer 	loop
	bra	transfer2
.test_last	tst.w	last_bytes			any last bytes ?
	beq.s	.success
	addq.l	#4,stage_pointer		last bytes next
	bra	next_stage
.success	add.l	#14*4,stage_pointer 	success next
	bra	next_stage
*---------------------------------------------------------------------------
write_to_buf3	lea	raw_data(a3),a4
	move.l	next_memory(pc),a5
	move.w	last_bytes(pc),d0
	addq.l	#4,stage_pointer
	bra	transfer1
*---------------------------------------------------------------------------
transfer1	ext.l	d0
	add.l	d0,next_memory	update memory pointer
	move.w	d0,d1
	and.w	#%111,d1	get remainder
	lsr.w	#3,d0	divide by 8 (blit width in bytes)
	beq.s	.remainder
	tst.b	fastmem_flag	chip or fast memory ?
	bne.s	.fastram
*	-------------------------------------------------------------
.chipram	move.l	a5,source+address	setup blit structures
	move.l	a4,dest+address
	lsl.w	#3,d0	restore to bytes
	add.w	d0,a4
	add.w	d0,a5
	bra.s	.next_chiploop
.chiploop	move.b	(a5)+,(a4)+
.next_chiploop dbra	d1,.chiploop
	lea	blit_copy(pc),a0
	lsr.w	#3,d0	divide by 8 (blit width in bytes)
	move.w	d0,height(a0)
	moveq	#DISK_PRI_BLIT,d0
	bsr	_blit
	rts
*	-------------------------------------------------------------
.fastloop1	move.l	(a5)+,(a4)+
	move.l	(a5)+,(a4)+
.fastram	dbra	d0,.fastloop1
	bra.s	.remainder
.fastloop2	move.b	(a5)+,(a4)+
.remainder	dbra	d1,.fastloop2
	bra	next_stage
*
*---------------------------------------------------------------------------
transfer2	add.l	#748*8,next_memory
	tst.b	fastmem_flag		chip or fast memory ?
	bne.s	.fastram
*	-------------------------------------------------------------
.chipram	move.l	a5,source+address
	move.l	a4,dest+address
	lea	blit_copy(pc),a0
	move.w	#748,height(a0)
	moveq	#DISK_PRI_BLIT,d0
	bsr	_blit
	rts
*	-------------------------------------------------------------
.fastram	move.w	#748/4-1,d0
.loop	REPT	8
	move.l	(a5)+,(a4)+
	ENDR
	dbra	d0,.loop
	bra	next_stage
*---------------------------------------------------------------------------
encode1	bsr	calc_checksum			calculate checksum
	move.l	d1,raw_checksum(a3) 	store checksum
	lea	blit_encode(pc),a0
	moveq	#DISK_PRI_BLIT,d0
	bsr	_blit		blitter MFM encode routine
	addq.l	#4,stage_pointer
	rts
*---------------------------------------------------------------------------
encode2	lea	mfm_data1(a3),a4
	btst.b	#6,(a4)		sync mark/checksum boundary
	bne.s	.evenodd
	bset.b	#7,(a4)
.evenodd	lea	mfm_data2(a3),a4	even/odd bit boundary
	btst.b	#0,-1(a4)		last bit of previous byte set ?
	bne.s	.reset_clock
	btst.b	#6,(a4)		test next data bit
	bne.s	.exit
.set_clock	bset.b	#7,(a4)
	bra.s	.exit
.reset_clock	bclr.b	#7,(a4)
.exit	addq.l	#4,stage_pointer
	bra	next_stage
*---------------------------------------------------------------------------
decode1	addq.l	#4,stage_pointer		return to next stage
	lea	blit_decode(pc),a0
	moveq	#DISK_PRI_BLIT,d0
	bsr	_blit		blitter MFM decode routine
	rts
*---------------------------------------------------------------------------
decode2	bsr	calc_checksum
	cmp.l	raw_checksum(a3),d1
	bne	checksum_error
	addq.l	#4,stage_pointer
	bra	next_stage
*---------------------------------------------------------------------------
calc_checksum	lea	raw_disk_id(a3),a4
	move.w	#(4+748*8)/4/3-1,d0 	result is integer
	moveq	#0,d1
calc_loop	add.l	(a4)+,d1
	add.l	(a4)+,d1
	add.l	(a4)+,d1
	dbra	d0,calc_loop
	rts
*
*---------------------------------------------------------------------------
format_track	btst.b	#2,ciapra(a0)			Disk removed ?
	beq	removed_error
	btst.b	#3,ciapra(a0)			Disk protected ?
	beq	protect_error
*	-------------------------------------------------------------
.start_dma	move.w	#%0000010000000000,adkcon(a6)	disable WORDSYNC
	lea	format_buffer(a3),a4
	move.l	a4,dskpt(a6)
	move.w	#(%11<<14)+14500/2,d0
	bra	disk_dma
*---------------------------------------------------------------------------
read_track	btst.b	#2,ciapra(a0)			test DSKCHANGE
	beq	removed_error
*	-------------------------------------------------------------
	move.w	#%1000010000000000,adkcon(a6)	enable WORDSYNC
	move.w	#$8944,dsksync(a6)				set sync marker
	lea	mfm_data1(a3),a4
	move.l	a4,dskpt(a6)
	move.w	#(%10<<14)+5992+1,d0
	bra	disk_dma
*---------------------------------------------------------------------------
write_track	btst.b	#2,ciapra(a0)			Disk removed ?
	beq	removed_error
	btst.b	#3,ciapra(a0)			Disk protected ?
	beq	protect_error
*	-------------------------------------------------------------
	move.w	#%1000010000000000,adkcon(a6)	enable WORDSYNC
	move.w	#$4489,dsksync(a6)				set sync marker
	lea	mfm_header(a3),a4
	move.l	a4,dskpt(a6)
	move.w	#(%11<<14)+(2+5992+1),d0
	bra	disk_dma
*---------------------------------------------------------------------------
disk_dma	move.w	#$4000,dsklen(a6)		disk dma start sequence
	move.w	d0,dsklen(a6)
	move.w	d0,dsklen(a6)
	addq.l	#4,stage_pointer
	move.w	#500,d0		500ms timeout (3 rotations)
	bra	set_delay
*---------------------------------------------------------------------------
check_transfer move.w	#$4000,dsklen(a6)		disable disk dma
	move.b	#%01001000,ciacrb(a1)	stop timeout counter
	move.w	#%10,intreq(a6) 		ensure against 2nd int
	tst.b	timeout			dskblk done or timeout ?
	beq.s	.ok
*	-------------------------------------------------------------
.error	btst.b	#2,ciapra(a0)			disk in drive ?
	beq	removed_error			no
	subq.b	#1,retrys
	beq	sync_error			sync error
	subq.l	#4,stage_pointer
	bra	next_stage			try again
*	-------------------------------------------------------------
.ok	move.b	#4,retrys			reset retrys
	st.b	timeout			not waiting for anything
	addq.l	#4,stage_pointer
	bra	next_stage
*
*---------------------------------------------------------------------------
move_to_track	move.b	required_track,d1		required track
	move.b	track,d2			current track
	cmp.b	d1,d2
	beq.s	.set_side
	bgt.s	.move_out
.move_in	addq.b	#1,track
	bra	step_in
.move_out	subq.b	#1,track
	bra	step_out
*	-------------------------------------------------------------
.set_side	tst.b	required_side			which side do we want ?
	bne.s	.lower_side
.upper_side	bclr.b	#2,ciaprb(a1)			set upper head
	sf.b	side			store current side
	bra.s	.exit
.lower_side	bset.b	#2,ciaprb(a1)			set lower head
	st.b	side			store current side
*	-------------------------------------------------------------
.exit	addq.l	#4,stage_pointer		return to next stage
	move.w	#15,d0			15ms settle time
	bra	set_delay
*---------------------------------------------------------------------------
wait_settle	st.b	timer_force			enable timer to force int
	tst.b	timeout			settle complete ?
	bne	.ok
	rts				no -wait for interrupt
.ok	move.w	#%10,intreq(a6) 		ensure against 2nd int
	addq.l	#4,stage_pointer
	bra	next_stage
*---------------------------------------------------------------------------
autostep	addq.l	#4,stage_pointer
	cmp.w	#$4fff,track			track 79, lower side ?
	beq	next_stage			-yes, don't step further
	clr.b	timer_force			disable timer interrupts
	not.b	side			change_side
	bne.s	.lower_side
.upper_side	addq.b	#1,track			update track
	bclr.b	#2,ciaprb(a1)			set upper head
	bclr.b	#1,ciaprb(a1)			inwards direction
	bclr.b	#0,ciaprb(a1)			pulse DSKSTEP low..
	bset.b	#0,ciaprb(a1)			..then high again
	move.w	#18,d0			18ms (step+settle) delay
	bsr	set_delay
	bra	next_stage
.lower_side	bset.b	#2,ciaprb(a1)			set lower head
	move.w	#1,d0			DSKSIDE stable for >100us
	bsr	set_delay
	bra	next_stage
*---------------------------------------------------------------------------
step_in	bclr.b	#1,ciaprb(a1)
	bclr.b	#0,ciaprb(a1)			pulse DSKSTEP low..
	bset.b	#0,ciaprb(a1)			..then high again
	move.w	#3,d0			3ms delay
	bra	set_delay
*---------------------------------------------------------------------------
step_out	bset.b	#1,ciaprb(a1)
	bclr.b	#0,ciaprb(a1)			pulse DSKSTEP low..
	bset.b	#0,ciaprb(a1)			..then high again
	move.w	#3,d0			3ms delay
	bra	set_delay
*
*---------------------------------------------------------------------------
empty_error	move.l	#DRIVE_EMPTY,disk_op_result(a2)
	bra	new_operation
*---------------------------------------------------------------------------
removed_error	move.l	#DISK_REMOVED,disk_op_result(a2)
	bra	new_operation
*---------------------------------------------------------------------------
protect_error	move.l	#DISK_PROTECTED,disk_op_result(a2)
	bra	new_operation
*---------------------------------------------------------------------------
sync_error	move.b	#4,retrys			reset retrys
	move.l	#CANT_SYNC,disk_op_result(a2)
	bra	new_operation
*---------------------------------------------------------------------------
checksum_error move.l	#CHECKSUM_ERROR,disk_op_result(a2)
	bra	new_operation
*---------------------------------------------------------------------------
success	move.l	raw_disk_id(a3),disk_op_result(a2)
	bra	new_operation
*---------------------------------------------------------------------------
set_delay	clr.b	timeout
	move.b	d0,CIAB+ciatblo 		set timer B
	lsr.w	#8,d0
	move.b	d0,CIAB+ciatbhi 		starts TB automatically
wait	rts

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

current_op	DC.L	-1
stage_pointer	DC.L	0

track	DS.B	1
side	DS.B	1

required_track DS.B	1
required_side	DS.B	1

start_byte	DS.W	1
first_bytes	DS.W	1
last_bytes	DS.W	1	}	must be in this order
whole_tracks	DS.W	1	}

next_memory	DS.L	1
fastmem_flag	DS.B	1

retrys	DC.B	4		Must start as 4

	EVEN
blit_decode	DC.B	BLITMFMDECODE
	DS.B	1		pad byte
	DS.L	1		pointer to disk buffer
blit_encode	DC.B	BLITMFMENCODE
	DS.B	1		pad byte
	DS.L	1		pointer to disk buffer

blit_copy	blit_data	BLIT1,1,LF_COPY,4,0,dest,source
dest	blit_channel	0,0,0,0
source	blit_channel	0,0,0,0

timer_force	DC.B	-1

timeout	DC.B	0
*
* These lists describe the order in which to call the above
* routines to perform a certain operation

selectstages	DC.L	select1,select2
	DC.L	read_track,check_transfer,decode1,decode2
	DC.L	success
*---------------------------------------------------------------------------
formatstages	DC.L	setup_format,encode1,encode2,move_to_track
*	-------------------------------------------------------------
	DC.L	wait_settle,format_track,check_transfer
	DC.L	write_track,check_transfer
	DC.L	read_track,check_transfer,autostep,decode1,decode2
	DC.L	next_format
*	-------------------------------------------------------------
	DC.L	success
*---------------------------------------------------------------------------
readstages	DC.L	setup_transfer,move_to_track,pre_read
*	-------------------------------------------------------------
	DC.L	wait_settle,read_track,check_transfer,autostep
	DC.L	decode1,decode2
	DC.L	read_from_buf1
*	-------------------------------------------------------------
	DC.L	wait_settle,read_track,check_transfer,autostep
	DC.L	decode1,decode2
	DC.L	read_from_buf2
*	-------------------------------------------------------------
	DC.L	wait_settle,read_track,check_transfer
	DC.L	decode1,decode2
	DC.L	read_from_buf3
*	-------------------------------------------------------------
	DC.L	success
*---------------------------------------------------------------------------
writestages	DC.L	setup_transfer,move_to_track
*	-------------------------------------------------------------
	DC.L	wait_settle,read_track,check_transfer
	DC.L	decode1,decode2
	DC.L	write_to_buf1
*	-------------------------------------------------------------
	DC.L	encode1,encode2
	DC.L	wait_settle,write_track,check_transfer
	DC.L	read_track,check_transfer,autostep,decode1,decode2
	DC.L	write_to_buf2
*	-------------------------------------------------------------
	DC.L	read_track,check_transfer,decode1,decode2
	DC.L	write_to_buf3
	DC.L	encode1,encode2,write_track,check_transfer
	DC.L	read_track,check_transfer,decode1,decode2
*	-------------------------------------------------------------
	DC.L	success

	END

