; diskreader.asm - essential functionality for game disk installers.
; © 1998-1999 Kyzer/CSG

	include	devices/trackdisk.i
	include	dos/dos.i
	include	lvo/exec_lib.i
	include	lvo/dos_lib.i

	IFND	FILEMODE
FILEMODE=0
	ENDC
	IFND	TRACKMODE
TRACKMODE=0
	ENDC


DOSTRACKLEN=TD_SECTOR*NUMSECS

MAKEBUF	MACRO	; buffername
	section	trackbuf,bss,chip
\1
__trk	ds.b	$7ffe
	ENDM

FAILURE	MACRO	; [reason]
	IFEQ	NARG
	suba.l	a0,a0
	ELSE
	lea	\1,a0
	ENDC
	bra	__fail
	ENDM

	IFEQ	FILEMODE
WRITE	MACRO	; length
	lea	__trk,a0
	move.l	\1,d0
	bsr	__write
	ENDM
WRITEDOS MACRO	; track
	DOSREAD	\1
	WRITE	#DOSTRACKLEN
	ENDM
	ENDC

SAVEF	MACRO
	lea	\1,a0
	lea	\2,a1
	move.l	\3,d0
	bsr	__write
	ENDM

	IFEQ	TRACKMODE
RESYNC	MACRO	; sync
	lea	__trk,a0
	move.l	\1,d0
	bsr	__sync
	ENDM

RAWREAD	MACRO	; track
	lea	__trk,a0
	move.l	\1,d0
	bsr	__rawrd
	ENDM
	ENDC

DOSREAD	MACRO	; track
	lea	__trk,a0
	move.l	\1,d0
	bsr	__dosrd
	ENDM

;------------------------------------

call	macro
	jsr	_LVO\1(a6)
	endm

initstk	macro	; stack_symbol, stackreg
	link	\2,#\1
	move.l	sp,a0
.clr\@	clr.w	(a0)+
	cmp.l	a0,\2
	bne.s	.clr\@
	endm

stackf	MACRO	; stack_symbol, stackelement_symbol, [size=4]
	IFND	\1
\1	set	0
	ENDC
	IFGE	NARG-3
\1	set	\1-(\3)
	ELSE
\1	set	\1-4
	ENDC
\2	equ	\1
	ENDM

	IFNE	FILEMODE
	IFNE	TRACKMODE

	; filemode on, trackmode on
	stackf	stk, unit
	stackf	stk, device
__args=device
__nargs=2
__tmpl	macro
	dc.b	'DEVICE/A,UNIT/N/A',0
	endm

	ELSE

	; filemode on, trackmode off
	stackf	stk, unit
__args=unit
__nargs=1
__tmpl	macro
	dc.b	'UNIT/N/A',0
	endm

	ENDC
	ELSE
	IFNE	TRACKMODE

	; filemode off, trackmode on
	stackf	stk, unit
	stackf	stk, device
	stackf	stk, output
__args=output
__nargs=3
__tmpl	macro
	dc.b	'DISKFILE/A,DEVICE/A,UNIT/N/A',0
	endm

	ELSE

	; filemode off, trackmode off
	stackf	stk, unit
	stackf	stk, output
__args=output
__nargs=2
__tmpl	macro
	dc.b	'DISKFILE/A,UNIT/N/A',0
	endm

	ENDC
	ENDC

	stackf	stk, rdargs
	stackf	stk, execbase
	stackf	stk, dosbase
	stackf	stk, diskport
	stackf	stk, diskio
	stackf	stk, outfh
	stackf	stk, initsp
	stackf	stk, reason
	stackf	stk, retcode

	section	diskreader,code

	link	a5,#stk
	move.l	4.w,a6
	move.l	a6,execbase(a5)

	moveq	#20,d7		; returncode = 20

	moveq	#37,d0
	lea	dosname(pc),a1
	call	OpenLibrary
	move.l	d0,dosbase(a5)
	beq	.nodos
	move.l	d0,a6

	clr.l	reason(a5)

	lea	templat(pc),a0
	move.l	a0,d1
	lea	__args(a5),a0
	move.l	a0,d2
	REPT	__nargs
	clr.l	(a0)+
	ENDR
	moveq	#0,d3
	call	ReadArgs
	move.l	d0,rdargs(a5)
	IFEQ	FILEMODE
	beq	.noargs
	move.l	output(a5),d1
	move.l	#MODE_NEWFILE,d2
	call	Open
	move.l	d0,outfh(a5)
	beq.s	.nofile
	ELSE
	beq.s	.noargs
	ENDC

	move.l	execbase(a5),a6
	call	CreateMsgPort
	move.l	d0,diskport(a5)
	beq.s	.noport

	move.l	d0,a0
	moveq	#IOTD_SIZE,d0
	call	CreateIORequest
	move.l	d0,diskio(a5)
	beq.s	.noio

	move.l	d0,a1
	move.l	unit(a5),a0
	move.l	(a0),d0
	IFNE	TRACKMODE
	move.l	device(a5),a0
	ELSE
	lea	tdname(pc),a0
	ENDC
	moveq	#0,d1
	call	OpenDevice
	tst.l	d0
	bne.s	.nodev

	bsr	__main

	move.l	diskio(a5),a1
	move.w	#TD_MOTOR,IO_COMMAND(a1)
	clr.l	IO_LENGTH(a1)
	move.l	execbase(a5),a6
	call	DoIO
	
	move.l	diskio(a5),a1
	call	CloseDevice
.nodev	move.l	diskio(a5),a0
	call	DeleteIORequest
.noio	move.l	diskport(a5),a0
	call	DeleteMsgPort
.noport	move.l	outfh(a5),d1
	move.l	dosbase(a5),a6
	IFEQ	FILEMODE
	call	Close
.nofile
	ENDC
	move.l	rdargs(a5),d1
	call	FreeArgs
.noargs
	moveq	#0,d7	 	; returncode = 0
	call	IoErr
	move.l	d0,d1
	beq.s	.nofail
	moveq	#20,d7		; returncode = 20
.nofail	move.l	reason(a5),d2
	call	PrintFault

	move.l	dosbase(a5),a1
	move.l	execbase(a5),a6
	call	CloseLibrary
.nodos	move.l	d7,d0
	unlk	a5
	rts

;------------------------------------
; a0 = buffer, d0 = track
__dosrd	move.l	diskio(a5),a1
	move.w	#CMD_READ,IO_COMMAND(a1)
	move.l	#__trk,IO_DATA(a1)
	move.l	#DOSTRACKLEN,d1
	mulu	d1,d0
	move.l	d0,IO_OFFSET(a1)
	move.l	d1,IO_LENGTH(a1)
	move.l	execbase(a5),a6
	call	DoIO
	lea	errtrk(pc),a0
	tst.l	d0
	bne.s	__fail
	rts

	IFEQ	TRACKMODE
;------------------------------------
; a0 = buffer, d0 = track
__rawrd	move.l	diskio(a5),a1
	move.w	#TD_RAWREAD,IO_COMMAND(a1)
	move.b	#IOTDB_INDEXSYNC,IO_FLAGS(a1)
	move.l	a0,IO_DATA(a1)
	move.l	d0,IO_OFFSET(a1)
	move.l	#$7ffe,IO_LENGTH(a1)
	move.l	execbase(a5),a6
	call	DoIO
	lea	errtrk(pc),a0
	tst.l	d0
	bne.s	__fail
	rts
	ENDC

;------------------------------------
; a0 = failure reason
__fail	move.l	a0,d0
	beq.s	.noreas
	move.l	d0,reason(a5)
	move.l	dosbase(a5),a6
	move.l	#ERROR_NOT_A_DOS_DISK,d1
	call	SetIoErr
.noreas	move.l	initsp(a5),sp
	rts

	IFNE	FILEMODE
;------------------------------------
; a0 = filename, a1 = buffer, d0 = length
__write	movem.l	d2-d4,-(sp)
	move.l	a0,d1
	move.l	a1,d3	; d3 = buffer
	move.l	d0,d4	; d4 = length
	move.l	#MODE_NEWFILE,d2
	move.l	dosbase(a5),a6
	call	Open
	move.l	d0,d1	; d1 = filehandle
	move.l	d3,d2	; d2 = buffer
	move.l	d4,d3	; d3 = length
	move.l	d0,d4	; d4 = filehandle
	beq.s	__fail
	call	Write
	move.l	d0,d3
	move.l	d4,d1
	call	Close
	tst.l	d3
	bmi.s	__fail
	movem.l	(sp)+,d2-d4
	rts

	ELSE
;------------------------------------
; a0 = buffer, d0 = length
__write	movem.l	d2-d3,-(sp)
	move.l	a0,d2
	move.l	d0,d3
	move.l	outfh(a5),d1
	move.l	dosbase(a5),a6
	call	Write
	tst.l	d0
	bmi.s	__fail
	movem.l	(sp)+,d2-d3
	rts
	ENDC

	IFEQ	TRACKMODE
;------------------------------------
; a0 = buffer d0 = sync
__sync	movem.l	d2-d3,-(sp)
	move.l	a0,a1
	move.w	#($7ffe/2)-1,d2
.nxtwrd	moveq	#16-1,d3
.nxtbit	move.l	(a0),d1
	lsr.l	d3,d1
	cmp.w	d0,d1
	beq.s	.synced
	dbra	d3,.nxtbit
	addq.l	#2,a0
	dbra	d2,.nxtwrd
	lea	errsync(pc),a0
	bra.s	__fail	; no sync marker found
.synced	move.l	(a0),d1
	addq.l	#2,a0
	lsr.l	d3,d1
	move.w	d1,(a1)+
	dbra	d2,.synced
	moveq	#0,d0		; succeeded
	movem.l	(sp)+,d2-d3
	rts
errsync	dc.b	"can't find sync mark",0
	ENDC

dosname	DOSNAME
tdname	TD_NAME
templat	__tmpl
errtrk	dc.b	"error reading track",0
	cnop	0,4

;------------------------------------
__main	move.l	sp,initsp(a5)
