;*---------------------------------------------------------------------------
;  :Program.	cmdc.s
;  :Contents.	command c - create
;  :Author.	Bert Jahn
;  :EMail.	wepl@whdload.org
;  :Address.	Franz-Liszt-Straße 16, Rudolstadt, 07404, Germany
;  :Version	$Id: cmdc.s 1.3 2000/08/06 12:23:17 jah Exp jah $
;  :History.	12.06.00 separated from wwarp.asm
;		28.06.00 adapted for _cmdwork
;		06.08.00 inter sector gap check improved
;  :Requires.	OS V37+, MC68020+
;  :Copyright.	©1998-2000 Bert Jahn, All Rights Reserved
;  :Language.	68020 Assembler
;  :Translator.	Barfly V2.9
;  :To Do.
;---------------------------------------------------------------------------*

_cmd_create

	;print announcement
		move.l	#MAXTRACKS-1,d0
		moveq	#0,d1
.pa_0		bftst	(gl_tabarg+wtt_tab,GL){d0:1}
		beq	.pa_1
		addq.l	#1,d1
.pa_1		dbf	d0,.pa_0
		move.l	d1,-(a7)
		move.l	(gl_rd_unit,GL),-(a7)
		pea	(gl_filename,GL)
		lea	(_txt_create),a0
		move.l	a7,a1
		bsr	_PrintArgs
		add.w	#12,a7

	;open the device
		move.l	#IOTDF_INDEXSYNC,d0
		lea	(gl_ioi,GL),a0
		bsr	_OpenDevice
		tst.l	d0
		beq	.nodevice

	;set file header
		lea	(gl_headout+wfh_ctime,GL),a0
		move.l	a0,d1
		move.l	(gl_dosbase,GL),a6
		jsr	(_LVODateStamp,a6)
		
	;main loop
		move.l	#CMDF_OUT,d0		;flags
		sub.l	a0,a0			;cbdata
		lea	.tracktable,a1		;cbtt
		lea	.tracks,a2		;cbt
		bsr	_cmdwork

	;close device
		lea	(gl_ioi,GL),a0
		bsr	_CloseDevice
.nodevice
		rts

.tracktable	lea	(gl_tabarg,GL),a0
		lea	(gl_tabout,GL),a1
		bsr	_copytt
		moveq	#-1,d0
		rts

.tracks		move.l	d0,d6				;D6 = actual track

	;progress output
		lea	(_diskprogress),a0		;output progress
		move.l	d6,-(a7)
		move.l	a7,a1
		bsr	_PrintArgs
		addq.l	#4,a7
		bsr	_FlushOutput

	;read track
		move.l	(gl_rd_retry,GL),d7		;D7 = read retries

.retryloop

	;check CTRL-C pressed
		bsr	_CheckBreak			;check for CTRL-C
		tst.l	d0
		bne	.error

	;read track
		move.l	d6,d0
		bsr	_cmdc_read
		beq	.error
		
		tst.l	(gl_rd_nostd,GL)
		bne	.nonstd
	;try to decode
		move.l	(gl_rd_bpt,GL),d0
		lsl.l	#3,d0
		move.l	d6,d1
		bsr	_cmdc_decode
		move.w	d0,d4				;D4 = type
		beq	.nonstd
		move.l	d1,d5				;D5 = length
		move.w	d2,d3				;D3 = flags
	;progress output decoded
		move.w	d4,(gl_trk+wth_type,GL)
		bsr	_gettt
		move.l	d0,-(a7)
		move.l	a0,-(a7)
		lea	(_decoded),a0
		move.l	a7,a1
		bsr	_PrintArgs
		addq.l	#8,a7
	;write
		bra	.write

.nonstd
	;try to calculate track length
		move.l	(gl_rd_bpt,GL),d0
		bsr	_cmdc_CalcTrackSize
		move.l	d0,d5				;D5 = length
		beq	.nolen
	;progress output raw single
		lea	(_trklens),a0
		move.l	d5,d3
		lsr.l	#3,d3				;bytes
		move.l	d5,d4
		and.l	#7,d4				;bits
		movem.l	d3-d4,-(a7)
		move.l	a7,a1
		bsr	_PrintArgs
		addq.l	#8,a7
	;write
		bfclr	([gl_fastbuf,GL]){d5:7}		;alignment
		move.w	#TT_RAW,d4			;D4 = type
		move.w	#TFF_INDEX|TFF_RAWSINGLE,d3	;D3 = flags
		bra	.write

.nolen		subq	#1,d7
		bmi	.writefull
		bsr	_cmdc_movehead
		bra	.retryloop

.writefull
	;progress output raw
		lea	(_trklen),a0
		clr.l	-(a7)
		move.l	(gl_rd_bpt,GL),d5
		move.l	d5,-(a7)
		lsl.l	#3,d5				;D5 = length
		move.l	a7,a1
		bsr	_PrintArgs
		add.w	#8,a7
	;write
		move.w	#TT_RAW,d4			;D4 = type
		move.w	#TFF_INDEX,d3			;D3 = flags

	;write track
.write		move	d6,(gl_trk+wth_num,GL)
		move	d4,(gl_trk+wth_type,GL)
		move	d3,(gl_trk+wth_flags,GL)
		move.l	d5,(gl_trk+wth_len,GL)
		clr.l	(gl_trk+wth_wlen,GL)
		lea	(gl_trk+wth_sync,GL),a0
		lea	(gl_trk+wth_mask,GL),a1
		move.b	#SYNCLEN-1,d0
.hc		clr.b	(a0)+
		clr.b	(a1)+
		dbf	d0,.hc
		
		moveq	#-1,d0
		rts

.error		moveq	#0,d0
		rts

;----------------------------------------
; read raw mfm track
; IN:	D0 = UWORD track number
; OUT:	D0 = BOOL true on success
;	_fastbuf contains mfm data

_cmdc_read
	;read mfm
		move.l	(gl_ioi,GL),a1
		move.l	(gl_chipbuf,GL),(IO_DATA,a1)
		move.l	d0,(IO_OFFSET,a1)
		move.l	(gl_rd_bpt,GL),(IO_LENGTH,a1)
		move.w	#ETD_RAWREAD,(IO_COMMAND,a1)
		clr.b	(IO_ERROR,a1)
		move.l	(gl_execbase,GL),a6
		jsr	(_LVODoIO,a6)
		move.l	(gl_ioi,GL),a1
		move.b	(IO_ERROR,a1),d0
		bne	.err
	;copy mfm data to fast mem for better performance
		move.l	(gl_chipbuf,GL),a0
		move.l	(gl_fastbuf,GL),a1
		cmp.l	a0,a1
		beq	.ok
		move.l	(gl_rd_bpt,GL),d0
.cp		move.l	(a0)+,(a1)+
		subq.l	#4,d0
		bcc	.cp

.ok		moveq	#-1,d0
		rts

.err		lea	(_readdisk),a0
		bsr	_PrintErrorTD
		moveq	#0,d0
		rts

;----------------------------------------
; try to decode track as known format
; IN:	D0 = ULONG length of raw mfm-data in bits
;	D1 = UWORD track number
;	gl_fastbuf mfm data
; OUT:	D0 = ULONG track type identified
;	D1 = ULONG decoded data length in bits!
;	D2 = ULONG track flags
;	gl_fastbuf contains decoded data

_cmdc_decode	movem.l	d5-d7,-(a7)

		move.l	d0,d7
		move.l	d1,d6
		bsr	_cmdc_d_dos
		tst.l	d0
		bne	.std
		move.l	d7,d0
		move.l	d6,d1
		bsr	_cmdc_d_grem
		tst.l	d0
		bne	.grem
		bra	.no

.std		move.l	#TT_STD,d0		;type
		move.l	#$1600,d1		;length
		moveq	#0,d2			;flags
		bra	.pack

.grem		move.l	#TT_GREM,d0		;type
		move.l	#$1800,d1		;length
		moveq	#0,d2			;flags

.pack
	;all lw's equal
		move.l	(gl_fastbuf,GL),a0
		move.l	d1,d6
		lsr.l	#2,d6
		move.l	(a0)+,d7
.eq		cmp.l	(a0)+,d7
		dbne	d6,.eq
		bne	.neq
		move.l	#4,d1
		or.w	#TFF_LEQ,d2
		bra	.end
.neq

	;each sector with lw's incremented
		cmp.l	#$1600,d1
		bne	.ninc
		move.l	(gl_fastbuf,GL),a0
		lea	($1600,a0),a1
		moveq	#11-1,d5
.inc2		moveq	#$200/4-2,d6
		move.l	(a0)+,d7
		move.l	d7,(a1)+
.inc		addq.l	#1,d7
		cmp.l	(a0)+,d7
		dbne	d6,.inc
		dbne	d5,.inc2
		bne	.ninc
		moveq	#11-1,d5
.inc3		move.l	-(a1),(-$1600,a1)
		dbf	d5,.inc3
		move.l	#4*11,d1
		or.w	#TFF_SLINC,d2		;sector long incremented
		bra	.end
.ninc

.end		lsl.l	#3,d1			;length in bits
		movem.l	(a7)+,d5-d7
		rts

.no		moveq	#0,d0
		bra	.end

;----------------------------------------
; decode standard amigados track
; IN:	D0 = ULONG length of raw mfm-data in bits
;	D1 = UWORD track number
;	_fastbuf mfm data
; OUT:	D0 = BOOL true on success
;	_fastbuf contains decoded data

	NSTRUCTURE	locals,0
		NWORD	lc1_trknum
		NALIGNLONG
		NLABEL	lc1_SIZEOF

_cmdc_d_dos	movem.l	d2-d7,-(a7)
		link	LOC,#lc1_SIZEOF
		
		or.w	#$ff00,d1
		move.w	d1,(lc1_trknum,LOC)

		move.l	d0,d5			;D5 = mfm-length
		moveq	#-1,d4			;D4 = last sync offset

	;search inter sector gap
.search		move.l	d4,d0
		addq.l	#1,d0			;offset
		move.l	d5,d1			;buffer length
		move.l	(gl_fastbuf,GL),a0
		lea	(_syncstd),a1		;44894489...
		bsr	_searchsync
		tst.l	d0
		bmi	.no

		tst.l	d4
		bmi	.sd4
		move.l	d0,d1
		sub.l	d4,d1
		cmp.l	#$440*8,d1		;$440 is standard sector length
		bne	.gap
.sd4		move.l	d0,d4
		bra	.search

.gap
	;d4 = last sector before gap
	;d0 = first sector after gap
		move.l	d0,d6			;D6 = first sector
	
	;check that inter sector gap is set to zeros
		sub.l	d4,d0
		sub.l	#($440-4)*8+33,d0	;length of gap in bits to check
		bmi	.no
		move.l	#$aaaaaaaa,d3
		move.l	(gl_fastbuf,GL),a0
		bra	.cmpin
.cmp		bfextu	(a0){d6:32},d1
		cmp.l	d1,d3
		bne	.no
.cmpin		subq.l	#4,a0
		sub.l	#32,d0
		bcc	.cmp
		bfextu	(a0){d6:32},d1
		neg.l	d0
		lsl.l	d0,d1
		lsl.l	d0,d3
		cmp.l	d1,d3
		bne	.no

	;check that remaining mfm data is sufficent
		sub.l	d6,d5			;in bits
		cmp.l	#11*$440*8,d5
		blo	.no

	;decode track
		move.l	#%11111111111,d4	;D4 = sectors
		move.l	#$55555555,d5		;D5 = mfm decode
		moveq	#11-1,d7		;D7 = sector loop count
		move.l	(gl_fastbuf,GL),a0	;A0 = mfm buffer
		subq.l	#4,a0			;first $aaaaaaaa

.sector		bsr	.getlw
		bclr	#31,d0
		cmp.l	#$2aaaaaaa,d0
		bne	.no
		bsr	.getlw
		cmp.l	#$44894489,d0
		bne	.no
		
		moveq	#0,d3			;D3 = chksum

		bsr	.getlwd			;sector header
		
		subq.b	#1,d0			;num sectors before gap
		cmp.b	d7,d0
		bne	.no
		
		lsr.l	#8,d0			;sector number 0..10
		cmp.b	#10,d0
		bhi	.no
		bclr	d0,d4
		beq	.no			;same sector again
	;	move.b	d0,($1600+gl_tmpbuf.w,GL,d7.w)
		moveq	#0,d1
		move.b	d0,d1
		mulu	#$200,d1
		lea	(gl_tmpbuf.w,GL,d1.l),a1
		
		lsr.l	#8,d0			;track number
		cmp.w	(lc1_trknum,LOC),d0
		bne	.no

		moveq	#3,d2
.label		bfextu	(a0){d6:32},d0
		bfextu	(16,a0){d6:32},d1
		eor.l	d0,d3
		eor.l	d1,d3
		and.l	d5,d0
		bne	.no
		and.l	d5,d1
		bne	.no
		addq.l	#4,a0
		dbf	d2,.label
		add.w	#16,a0

		move.l	d3,d2
		and.l	d5,d2
		bsr	.getlwd			;header chksum
		cmp.l	d2,d0
		bne	.no
		
		bsr	.getlwd			;data chksum
		move.l	d0,d3

		moveq	#$200/4-1,d2
.data		bfextu	(a0){d6:32},d0
		bfextu	($200,a0){d6:32},d1
		eor.l	d0,d3
		and.l	d5,d0
		eor.l	d1,d3
		and.l	d5,d1
		add.l	d0,d0
		addq.l	#4,a0
		or.l	d0,d1
		move.l	d1,(a1)+
		dbf	d2,.data
		add.w	#$200,a0
		
		and.l	d5,d3
		bne	.no
		
		dbf	d7,.sector
		
	;copy buffer
		move.w	#$1600/4-1,d0
		lea	(gl_tmpbuf,GL),a0
		move.l	(gl_fastbuf,GL),a1
.copy		move.l	(a0)+,(a1)+
		dbf	d0,.copy
		
		moveq	#-1,d0
		bra	.quit

.no		moveq	#0,d0

.quit		unlk	LOC
		movem.l	(a7)+,d2-d7
		rts

.getlw		bfextu	(a0){d6:32},d0
		addq.l	#4,a0
		eor.l	d0,d3
		rts

.getlwd		bsr	.getlw
		move.l	d0,d1
		bsr	.getlw
		and.l	d5,d1
		and.l	d5,d0
		add.l	d1,d1
		or.l	d1,d0
		rts

;----------------------------------------
; decode gremlin track (lotus)
; IN:	D0 = ULONG length of raw mfm-data in bits
;	D1 = UWORD track number
;	_fastbuf mfm data
; OUT:	D0 = BOOL true on success
;	_fastbuf contains decoded data

_cmdc_d_grem	movem.l	d2-d7,-(a7)

		move.l	d0,d5			;D5 = mfm-length
		move.w	d1,d4			;D4 = track number

	;search sync
		moveq	#0,d0			;offset
		move.l	d5,d1			;buffer length
		move.l	(gl_fastbuf,GL),a0
		lea	(_syncgrem),a1
		bsr	_searchsync
		tst.l	d0
		bmi	.no

	;skip sync(448944894489) and unknown word(5555)
		add.l	#4*16,d0
		move.l	d0,d6			;offset
		
	;check that remaining mfm data is sufficent
		sub.l	d6,d5			;in bits
		cmp.l	#(2*$1800+4)*8,d5
		blo	.no

	;decode track
		move.l	(gl_fastbuf,GL),a0	;A0 = mfm buffer
		lea	(gl_tmpbuf,GL),a1	;A1 = decoded
		move.w	#$bff,d7
		move.l	#$55555555,d2
		moveq	#0,d3

.loop		bsr	.get
		move.w	d1,(a1)+
		add.w	d1,d3
		dbf	d7,.loop
		
		bsr	.get
		cmp.w	d1,d3
		bne	.no

		bsr	.get
		bchg	#0,d1
		cmp.w	d1,d4
		bne	.no

	;copy buffer
		move.w	#$1800/4-1,d0
		lea	(gl_tmpbuf,GL),a0
		move.l	(gl_fastbuf,GL),a1
.copy		move.l	(a0)+,(a1)+
		dbf	d0,.copy
		
		moveq	#-1,d0
		bra	.quit

.no		moveq	#0,d0

.quit		movem.l	(a7)+,d2-d7
		rts

.get		bfextu	(a0){d6:32},d0
		addq.l	#4,a0
		and.l	d2,d0
		move.w	d0,d1
		swap	d0
		add.w	d1,d1
		add.w	d0,d1
		rts

;----------------------------------------
; calculate track length if possible
; IN:	D0 = ULONG length of raw mfm-data in bytes
;	_fastbuf mfm data
; OUT:	D0 = ULONG size in bits if successful, otherwise 0

_cmdc_CalcTrackSize
		movem.l	d2-d7/a2,-(a7)

		move.l	d0,d5			;D5 = mfm-length
		move.l	(gl_fastbuf,GL),a0	;A0 = buffer start
		move.l	#MINTRACKLEN*8,d0	;D0 = actual offset (track size)

.s		move.l	a0,a1			;A1 = actual p1
		move.l	d0,d1
		lsr.l	#5,d1			;/32
		lsl.l	#2,d1			;*4
		lea	(a1,d1.l),a2
		
.n		bfextu	(a1){d0:32},d7
		cmp.l	(a1)+,d7
		bne	.ne
		cmp.l	a1,a2
		bhi	.n
		move.l	d0,d1
		and.w	#31,d1			;how many bits are left to compare ?
		beq	.eq
		bfextu	(a1){d0:d1},d7
		bfextu	(a1){0:d1},d6
		cmp.l	d6,d7
		bne	.ne
.eq		movem.l	(a7)+,_MOVEMREGS
		rts

.ne		addq.l	#1,d0
		move.l	d0,d1
		add.l	d1,d1			;track must fit two times in the raw buffer
		add.l	#7,d1			;round up
		lsr.l	#3,d1			;in bytes
		cmp.l	d5,d1
		bls	.s

		moveq	#0,d0
		movem.l	(a7)+,_MOVEMREGS
		rts

;----------------------------------------
; move head
; IN:	D6 = ULONG actual track
; OUT:	-

_cmdc_movehead
		move.l	d6,d0
		lsr.l	#1,d0			;cylinder

		lea	(.data),a0
		cmp.w	(a0),d6
		beq	.calc
.init
		move.w	d6,(a0)			;set new track
		clr.w	(2,a0)			;offset
.calc
		move.w	(2,a0),d1		;offset
		addq.w	#2,(2,a0)
		cmp.w	#.liste-.list,d1
		beq	.init
		
		add.w	(4,a0,d1.w),d0
		bpl	.1
		moveq	#1,d0
.1		cmp.w	#MAXTRACKS/2,d0
		blo	.2
		move.w	#MAXTRACKS/2-2,d0
.2

		move.l	d0,-(a7)
	IFD DEBUG
		lea	.s,a0
		move.l	a7,a1
		bsr	_PrintArgs
		bra	.ss
.s		dc.b	"»%ld",0
	EVEN
.ss
	ELSE
		move.l	#"."<<24,-(a7)
		move.l	a7,a0
		bsr	_Print
		addq.l	#4,a7
	ENDC
		bsr	_FlushOutput
		move.l	(a7)+,d0

		mulu	#2*$1600,d0
		add.l	#$1600,d0

		move.l	(gl_ioi,GL),a1
		move.l	d0,(IO_OFFSET,a1)
		move.w	#ETD_SEEK,(IO_COMMAND,a1)
		clr.b	(IO_ERROR,a1)
		move.l	(gl_execbase,GL),a6
		jsr	(_LVODoIO,a6)
		move.l	(gl_ioi,GL),a1
		move.b	(IO_ERROR,a1),d0
		bne	.err

		rts

.err		lea	(_readdisk),a0
		bra	_PrintErrorTD

.data		dc.w	-1		;actual cylinder
		dc.w	0		;offset in list
.list		dc.w	0,0,1,0,0,0,-1,0
.liste

