*  Patch.a  -	Copyright 1990 D.W.Reisig
*
*   #	 date	 by    Comment
*  -- --------- ----- ---------------------
*   0 29-Oct-89	 DWR   Created for Tracksalve
*   1 10-Apr-90  DWR   TrackSalve 1.3, Complete overhaul
*

*		nolist
		ifnd	IFILES
IFILES		set	1
		INCLUDE "Call.i"
		INCLUDE "globdefs.i"
		INCLUDE "ts.i"
		INCLUDE "exec/tasks.i"
		INCLUDE "hardware/custom.i"
		INCLUDE	"hardware/dmabits.i"
		include "graphics/text.i"
		include "graphics/rastport.i"
*		include "intuition/intuitionbase.i"
*		include "intuition/intuition.i"
*		include "intuition/screens.i"
		include "devices/inputevent.i"

		ifnd	INTUITION_INTUITION_I
GADGETUP	equ	$00000040
RAWKEY		equ	$00000400
WINDOWDEPTH	equ	$0004
WINDOWDRAG	equ	$0002
SIMPLE_REFRESH	equ	$0040
NOCAREREFRESH	equ	$00020000
ACTIVATE	equ	$1000
GADGHCOMP	equ	$0000
GADGHBOX	equ	$0001
GADGIMAGE	equ	$0004
GADGHIMAGE	equ	$0002
BOOLGADGET	equ	$0001
REQGADGET	equ	$1000
RELVERIFY	equ	$0001
ENDGADGET	equ	$0004
wd_LeftEdge	equ	4
wd_UserPort	equ	86
im_Class	equ	20
im_Code		equ	24
im_IAddress	equ	28
		endc

		ifnd	INTUITION_SCREENS_I
WBENCHSCREEN	equ	$0001
sc_DetailPen	equ	$14a
		endc

		ifnd	INTUITION_INTUITIONBASE_I
ib_FirstScreen	equ	$3c
		endc

		endc

*		list


*********************************************************
*
*  TSCodeBegin
*
*  Begin of code that extents/replaces Trackdisk code.
*  For (relocation) references inside this section, this must stay the first location of this
*  section.  So do not put any code before TSCodeBegin.
*  TSCodeBegin is made globally known because some routine must copy us from here to an
*  allocated space.  Because all references to the locationcounter until TSCodeEnd are done
*  from within this part or from patched Trackdisk code, none of these locations should be made
*  external available.
*

		SECTION text,code

		Func	TSCodeBegin,_TSCodeBegin

		


*********************************************************
*
*  We jump to these addresses when changing from ROM to TS.  Special inits must be done here.
*
*  Upon entry:	a3	TDU_
*		a6	SysBase
*		(a7)	TDD_

*--	First TrackSalve pc if trackdisk is in the taskloop's single subroutine

FirstPCSub	move.l	#$300,d0			%
		move.l	a6,-(a7)			%
		move.l	TDD_SysBase(a6),a6		%
		LibCall	Wait				%

*--	First TrackSalve pc if Trackdisk is in its taskloop Wait call

FirstPCWait	move.b	#F_RAM,UNIT_pad(a3)		Set flags to executing in RAM and clear all other
		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure
		move.l	a3,UD_BlitNode+TSBN_Unit(a2)	Install Unit pointer in blitnode
		
		;bra.s	TDE_TaskLoop			Continue normal loop


*********************************************************
*
*  Extension of Trackdisks main task loop.
*  We are free to use a2, but its value may have been changed upon entry.
*  A6 contains SysBase and the device pointer must be restored by a pull from the stack.
*  For IO with fast memory buffers we use the fastest possible copy routine.  Our
*  routine is faster than the Exec CopyMem(), unless it is replaced.  Adapt to it.
*  Then we check wether we initiated a terminal state.  If so, we do not check external
*  commands anymore, but continue to finish the special functions and return to ROM-code
*  in the end.  Otherwise we compare the external commands with the already active
*  functions and if they differ, we see that they are initiated/terminated.
*
*  Upon entry:	a3	TDU_
*		a6	SysBase
*		(a7)	TDD_
*
*  Usage:	a2	UD_
*

TDE_TaskLoop	;Inserted by a bra at the end of the taskloop

TL_		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure

*--	Find the most efficent copy routine

		lea.l	CopySectCPU(pc),a0		Asume our dedicated routine to be the best
		move.l	_LVOCopyMem+2(a6),d0		Adress of exec CopyMem function
		sub.l	LN_NAME(a6),d0			Find distance of some address near the begin of Exec
		swap.w	d0				Divide by 65k
		tst.w	d0				Distance less than 65k?
		beq.s	10$				Yes, CopyMem function not replaced
		lea.l	CopySectExec(pc),a0		No, replaced, use replaced CopyMem function
10$		move.l	a0,UD_CopySect(a2)		Store function to use for copy sectors

		move.l	(a7)+,a6			% Perform replaced instruction. Restore device pointer

*--	Check change in TrackSalve functions

		btst	#B_TERM,UNIT_pad(a3)		Change of control?
		bne.s	TL_TermTS			Yes..
		move.b	UD_Cmd1(a2),d0			Command from outside
		cmp.b	UNIT_pad(a3),d0			Same as presently active?
		beq	TD_TaskLoop			AE64 Yes, continue task..

		btst	#B_TERM,d0			Change of control?
		bne	TL_TermTS			Yes..
		bsr	ChkChgReadOnly			Check change of write protection
		move.b	UD_Cmd1(a2),d0			Get commands
		bsr	ChkChgSalve			Check change of readerror handling
		move.b	UD_Cmd1(a2),d0			Get commands
		bsr	ChkChgNoClick			Check change of diskchange detection
		move.b	UD_Cmd1(a2),d0			Get commands
		bsr	ChkChgVerify			Check change of verify function
		move.b	UD_Cmd1(a2),d0			Get commands
		bsr	ChkChgUpdate			Check change of auto update function

		bra	TD_TaskLoop			AE64 Continue task..

*--	Initiate or continue terminal state.  Stay in the taskloop until all functions are switched off.

TL_TermTS	bset.b	#B_TERM,UNIT_pad(a3)		Set status of TS to terminating
		moveq.l #0,d0				Readonly off
		bsr	ChkChgReadOnly			Check change of write protection
		moveq.l #0,d0				Salve off
		bsr	ChkChgSalve			Check change of readerror handling
		moveq.l #0,d0				NoClick off
		bsr	ChkChgNoClick			Check change of diskchange detection
		moveq.l #0,d0				Verify off
		bsr	ChkChgVerify			Check change of verify function
		moveq.l #0,d0				Auto update off
		bsr	ChkChgUpdate			Check change of auto update function
		move.b	UNIT_pad(a3),d0			Current active functions
		and.b	#FUNCTIONS-F_RAM,d0		All extra functions terminated?
		bne	TD_TaskLoop			AE64 No, continue task..

*--	We realy stop here.  The taskloop hereafter continues in ROM-code.  Remove any incompatibilities.

		move.l	TDU_UnitBuf(a3),a0		The only track buffer possible
		tst.w	TB_TrkNo(a0)			Error in track?
		bmi.s	10$				Yes, don't care about it contents format..
		bsr	MFMTrack			No, ensure proper MFM-format
10$
		move.l	a6,-(a7)			Preserve a6 AND undo the already executed "move.l (a7)+,a6"
		move.l	TDD_SysBase(a6),a6		Trackdisk's SysBase
		move.l	UD_ReturnTD(a2),-(a7)		Push ROM-address. With a "rts" we are back in ROM
		movem.l a4/a5,-(a7)
		LibCall Forbid				We do daring things here, like freeing code we are executing!
		move.l	UD_TSControl(a2),a5		Lea the Control structure
		move.l	TSC_TSHook(a5),a4		Lea anchor of all our knowledge
		move.l	a4,a0
		LibCall ObtainSemaphore			We want to be blocked here until others are ready with TSC

		moveq.l #0,d0
		move.b	TDU_UnitNr(a3),d0		Trackdisk unit number
		bclr.b	d0,TSC_InUse(a5)		Tell global structure we stopped using it.
		lsl.l	#2,d0				Scale to pointer-index
		clr.l	TSC_UnitData(a5,d0.l)		Clear UnitData pointer in TSC structure
		move.l	UD_Userdata(a2),TDU_TCB+TC_Userdata(a3) Restore original value in Task control block
		move.b	#0,UNIT_pad(a3)			Back to what it was perhaps
		lea.l	UD_TDReq(a2),a1			Trackdisk IORequest
		cmp.l	IO_UNIT(a1),a3			Our request? (of course it is)
		bne.s	20$				No, skip close..
		LibCall CloseDevice
20$

*--	Return memory of the TSControl structure if there are no other users of it anymore.

		tst.b	TSC_InUse(a5)			Any users left?
		bne.s	40$				Yes, do not free it..
		move.l	TSC_Buffer(a5),d1		The install program allocates this buffer.  Its presence may
								; not yet have been processed
		beq.s	30$				No buffer..
		move.l	d1,a1				Buffer
		move.l	#SB_SIZE,d0			Its size
		LibCall FreeMem				Back to the system
30$		move.l	TSC_IntuBase(a5),a1		Close Intuition
		LibCall CloseLibrary
		move.l	a5,a1				TSControl structure
		move.l	TSC_Size(a5),d0			Its size (about 10k)
		LibCall FreeMem				Free it
		clr.l	TSH_TSControl(a4)		No TSControl structure anymore in TSHook
40$

*--	Maybe the TSControl structure does not exist anymore.  We cannot return from Permit() here, so we jump to it.
*	The return address is already on the stack and points to the correct position in ROM-code.

		move.l	a4,a0				Lea TSHook structure
		LibCall ReleaseSemaphore		We are (almost) ready with the TSControl structure
		movem.l (a7)+,a4/a5
		xref	_LVOPermit
		jmp	_LVOPermit(a6)			Taskswitching on and back to ROM


*-------------------------------------------------------*
*
*  ChkChgSalve
*
*  This routine handles the switch from salve function on and off. If there are no other
*  users of this function left, release the large chip-buffer (about 25k).  If the function
*  is switched on, check the presence of the buffer.  If not there, allocate it.
*
*  Input:	d0	UD_Cmd1
*		a2	UD_
*		a3	TDU_
*		a6	TDD_
*


ChkChgSalve
CS_		move.b	UNIT_pad(a3),d1			Presently active functions
		and.b	#F_SALVE,d0			Select salve-bit in command
		and.b	#F_SALVE,d1			Select salve-bit in active functions
		cmp.b	d0,d1				Salve-action changed?
		bne.s	CS_ChangeSalve			Yes, see that it is done..
		rts

*--	We must protect the allocation, freeing and administration of the salve buffer with the TSC semaphore.

CS_ChangeSalve	movem.l d2/d3/a5/a6,-(a7)
		move.l	d0,d2				Keep salve command
		move.b	TDU_UnitNr(a3),d3		Unit number
		move.l	UD_TSControl(a2),a5		TSControl structure
		move.l	TDD_SysBase(a6),a6		SysBase for Semaphore calls
		move.l	TSC_TSHook(a5),a0		Lea semaphore
		LibCall ObtainSemaphore			We want to be blocked here until others are ready with TSC
		btst	#B_SALVE,d2			Salve requested?
		beq.s	CS_SalveOff			No..

CS_SalveOn	bsr	CheckBufAvail			Check presence and allocate if necessary
		beq.s	CS_Rtn				No success..
		bset.b	#B_SALVE,UNIT_pad(a3)		Set function active
		bset.b	d3,TSC_Salve(a5)		Tell global structure that we use the buffer
		bra.s	CS_Rtn				Done..

CS_SalveOff	move.l	TDU_UnitBuf(a3),a0		Lea trackbuffer.  Salve off; normal error handling
		cmp.b	#SPT,TB_FirstSec(a0)		Error?
		bcs.s	10$				No..
		move.w	#-1,TB_TrkNo(a0)		Yes, invalidate tracknumber
10$		bclr.b	#B_SALVE,UNIT_pad(a3)		Set function off
		bclr.b	d3,TSC_Salve(a5)		We do not use the buffer into global structure
		bsr	CheckBufFree			Deallocate if we were the last users

CS_Rtn		move.l	TSC_TSHook(a5),a0		Lea semaphore
		LibCall ReleaseSemaphore		We are ready with the TSControl structure
		movem.l (a7)+,d2/d3/a5/a6
		rts

*-------------------------------------------------------*
*
*  ChkChgVerify
*
*  Handle the switch from verify function on and off.  If there are no other users of this
*  function left, release the large chip-buffer.  If the function is switched on, check the
*  presence of the buffer.  If not there, allocate it.
*
*  Input:	d0	UD_Cmd1
*		a2	UD_
*		a3	TDU_
*		a6	TDD_
*

ChkChgVerify
CV_		move.b	UNIT_pad(a3),d1			Presently active functions
		and.b	#(F_VERIFY1+F_VERIFY0),d0	Select Verify-bits in command
		and.b	#(F_VERIFY1+F_VERIFY0),d1	Select Verify-bits in active functions
		cmp.b	d0,d1				Verify-action changed?
		bne.s	CV_ChangeVerify			Yes, see that it is done..
		rts

*--	We must protect the allocation, freeing and administration of the salve buffer with the TSC semaphore.

CV_ChangeVerify	movem.l d2/d3/a5/a6,-(a7)
		move.l	d0,d2				Keep Verify command
		move.b	TDU_UnitNr(a3),d3		Unit number
		move.l	UD_TSControl(a2),a5		TSControl structure
		move.l	TDD_SysBase(a6),a6		SysBase for Semaphore calls
		move.l	TSC_TSHook(a5),a0		Lea semaphore
		LibCall ObtainSemaphore			We want to be blocked here until others are ready with TSC
		tst.b	d2				Verify requested?
		beq.s	CV_VerifyOff			No..

CV_VerifyOn	bsr	CheckBufAvail			Check presence and allocate if necessary
		beq.s	CV_Rtn				No success..
		bset.b	d3,TSC_Verify(a5)		Tell global structure that we use the buffer
		and.b	#~(F_VERIFY1+F_VERIFY0),UNIT_pad(a3) Clear present verify bits
		or.b	d2,UNIT_pad(a3)			Set function active with desired bits
		bra.s	CV_Rtn				Done..

CV_VerifyOff	and.b	#~(F_VERIFY1+F_VERIFY0),UNIT_pad(a3) Set function off
		bclr.b	d3,TSC_Verify(a5)		We do not use the buffer into global structure
		bsr	CheckBufFree			Deallocate if we were the last users
		
CV_Rtn		move.l	TSC_TSHook(a5),a0		Lea semaphore
		LibCall ReleaseSemaphore		We are ready with the TSControl structure
		movem.l (a7)+,d2/d3/a5/a6
		rts

*-------------------------------------------------------*
*
*  Local subroutine of ChkChgSalve and ChkChgVerify, allocate and free the large chip buffer
*
*  Input:	a5	TSC_

CheckBufAvail	tst.l	TSC_Buffer(a5)			Is a buffer present?
		bne.s	10$				Yes, skip allocation
		move.l	#SB_SIZE,d0			No, its size
		move.l	#MEMF_CHIP,d1			And type
		LibCall AllocMem			Ask system about 25k chip
		move.l	d0,TSC_Buffer(a5)		Into global structure. This buffer is shared
10$		rts


CheckBufFree	tst.b	TSC_Salve(a5)			Any users left?
		bne.s	10$				Yes, done..
		tst.b	TSC_Verify(a5)			Any users left?
		bne.s	10$				Yes, done..
		move.l	TSC_Buffer(a5),d1		Get buffer
		beq.s	10$				No buffer..
		move.l	d1,a1				Buffer
		move.l	#SB_SIZE,d0			Its size
		LibCall FreeMem				Back to system
		clr.l	TSC_Buffer(a5)			No buffer anymore
10$		rts


*-------------------------------------------------------*
*
*  ChkChgNoClick
*
*  Handle the switch from the NoClick function on and off.
*
*  Input:	d0	UD_Cmd1
*		a2	UD_
*		a3	TDU_
*		a6	TDD_
*

ChkChgNoClick	btst	#B_NOCLICK,d0			Function to be activated?
		beq.s	10$				No..
		bset.b	#B_NOCLICK,UNIT_pad(a3)		Yes function on
		rts
10$		bclr.b	#B_NOCLICK,UNIT_pad(a3)		No function off
		rts

*-------------------------------------------------------*
*
*  ChkChgUpdate
*
*  Handle the switch from the auto update function on and off.
*
*  Input:	d0	UD_Cmd1
*		a2	UD_
*		a3	TDU_
*		a6	TDD_
*

ChkChgUpdate	btst	#B_UPDATE,d0			Function to be activated?
		beq.s	10$				No..
		bset.b	#B_UPDATE,UNIT_pad(a3)		Switch function on, was aready done?
		beq	SetUpdCnt			No, init counter according to present state
		rts
10$		bclr.b	#B_UPDATE,UNIT_pad(a3)		Set function off
		rts

*-------------------------------------------------------*
*
*  ChkChgReadOnly
*
*  Switching ReadOnly on and off must be done a little careful.	 Although we have nothing to
*  do with DOS, (and we do not want too, do we?) it would be inconvenient to switch to
*  readonly when DOS is writing.  There is no way to be sure, but an indication might be the
*  state of the motor.	It is the user who initiates the switch.  He must do it at a quiet
*  moment.  Tell him in the manual!  Again we cannot tell DOS directly that we changed the
*  write protection of the disk, but we simulate a disk-change and a shift of the disk
*  protect tab.  We can skip this if the drive is empty or if the present disk is already
*  write protected by its tab.
*
*  Input:	d0	UD_Cmd1
*		a2	UD_
*		a3	TDU_
*		a6	TDD_
*

ChkChgReadOnly
RO_		btst	#B_READONLY,d0			Is this drive to be protected?
		beq.s	RO_Off				No, check reverse action..
		btst.b	#B_READONLY,UNIT_pad(a3)	Check real bit
		beq.s	RO_CheckChange			We have to change from r/w to ro..
		rts

RO_Off		btst.b	#B_READONLY,UNIT_pad(a3)	Check active function bit
		bne.s	RO_CheckChange			Was set to write-protect, try change to R/W..
		rts

RO_CheckChange	btst.b	#1,TDU_Flags(a3)		Is there a disk in the drive?
		bne.s	RO_ChangeROSec			No, just flip RO-bit..
		btst.b	#4,TDU_Flags(a3)		Is there a protected disk in the drive?
		bne.s	RO_ChangeROSec			Yes, just flip RO-bit..
		btst.b	#CIAB_DSKMOTOR,TDU_CiabPb(a3)	Motor off? (We TRY to avoid change during disk (write) access)
		beq.s	RO_Rtn				No, try again later..
RO_ChangeRO	bchg.b	#B_READONLY,UNIT_pad(a3)	Change real bit. This will be checked before the hardware
*		pea.l	RO_Rtn(pc)			Push return address, now we are inside a subroutine
		movem.l d2/a2,-(a7)			Imitate the disk-presence-check inits
		lea.l	_ciab+ciaprb,a2			CIAB-PRB
		bra	TD_NoDisk			99C2 Continue subroutine handling disk absence..

RO_ChangeROSec	bchg.b	#B_READONLY,UNIT_pad(a3)	Change function bit. This is checked before the hardware is
RO_Rtn		rts


*********************************************************
*
*  MFMTrack
*  
*  This routine is to be called just before a write to disk.
*  Set or clear all non-data bits as required to meet the MFM standard except those
*  of the syncwords.  As source we need a buffer in which all databits are valid.
*
*  Input:	a3	TDU_
*		a6	TDD_
*

MFMTrack
MT_		move.l	TDU_TCB+TC_Userdata(a3),a1	Lea UnitData structure
		lea.l	UD_BlitNode(a1),a1

		move.l	TDU_DiskBuf(a3),a0		Buffer to be MFM updated
		lea.l	TB_Data(a0),a0			
		move.l	a0,TSBN_P0(a1)			Begin of block
		add.w	#SPT*SE_SIZE-2,a0		Add block size to get address of last word
		move.l	a0,TSBN_P1(a1)			Into control structure
		lea.l	BF_MT10(pc),a0
		move.l	a0,bn_function(a1)		First blitter function
		move.l	a6,-(a7)
		move.l	TDD_GfxBase(a6),a6		The graphics library coordinates blitter usage
		LibCall QBlit				Control is returned immedately so we must wait here
		move.l	(a7)+,a6
		bsr	TD_WaitTDPort			A70A Wait for a message we sent to ourself from within Gfx

*--	The syncs are gone.  Restore them.

		move.l	TDU_DiskBuf(a3),a0
		lea.l	TB_Data+SE_Sync(a0),a0		Lea first sync
		move.l	#SYNCSYNC,d1			The sync pattern
		moveq.l #SPT-1,d0			Number of syncs to restore
MT_PutSync	move.l	d1,(a0)				Restore sync
		add.w	#SE_SIZE,a0			Ea of next sync
		dbra	d0,MT_PutSync			Loop..

		rts

*********************************************************
*
*  TDE_FormInit,  TDE_CMD_RW
*
*  Find out what kind of buffers are used for IO.
*
*  Input:	a3	TDU_
*
*  Return:	d6.b	Chip
*


TDE_FormInit	move.l	$28(a4),a5			% Was changed into call to this routine
		move.l	a5,a1				Just loaded IO_DATA in a5, IO buffer
		bra	TestMem				Set memorytype flag d6



*********************************************************
*
*  EncodeSector  EncodeLabel
*
*  Routines to replace the original TD encoding routines.  Because we will validate all
*  non-data bits just before it is written to disk, the encoding just exists of putting
*  the databits into its place in the buffer.  We do so by copiing the data to the
*  upper half of its buffer space, followed by a copy from this upperhalf to the lower half,
*  but*  this time shifted right one bit.  The first copy (512 bytes/128 longs) is done by
*  the blitter if the source is chip, else by some function if non-chip.  The second move
*  and shift is done by the blitter.
*  The encoding of the label is entirely done by the cpu, QBlit has too much overhead
*  to encode 16 bytes.
*
*
*  Input:	a0	Source        Users IO buffer
*		a1	Destination   Sector location in trackdisk's trackbuffer
*		a3	TDU_
*		a6	TDD_
*

		
TDR_EncodeLabel	;Replacing TD-subroutine
		
		move.l	a2,-(a7)
		moveq.l	#TD_LABELSIZE/4-1,d1		Init loop counter
		lea.l	TD_LABELSIZE(a1),a2		Pointer to upper half of labelspace
10$		move.l	(a0)+,d0			Uncoded value
		move.l	d0,(a2)+			Store unshifted in upper space
		lsr.l	#1,d0				Shift right one bit
		move.l	d0,(a1)+			Store shifted in lower space
		dbra	d1,10$				Loop..
		move.l	(a7)+,a2
		rts

		
TDR_EncodeSect	;Replacing TD-subroutine

ES_		movem.l	a2/a5,-(a7)
		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure
		lea.l	UD_BlitNode(a2),a5		Lea extended blitnode

*--	Second move: source is upperhalf of sector space, destination is lowerhalf and shifted one bit right

		move.l	a1,TSBN_P3(a5)			Lowerhalf is destination
		add.w	#TD_SECTOR,a1			Set pointer to upperhalf
		move.l	a1,TSBN_P2(a5)			Upperhalf is  source

*--	First move: Depending on the type of source, we use the blitter or some copy routine to copy into upperhalf

		tst.b	d6				What kind of memory is the source?
		bne.s	10$				It is chip, we use the blitter for copy..

*--	We use the best non-blitter copy routine

		move.l	UD_CopySect(a2),a2		Get copy function
		jsr	(a2)				Copy first the source to upper half of destination
		lea.l	BF_ES20(pc),a0			Shift & copy function
		bra.s	20$

*--	We use the blitter for copy

10$		move.l	a0,TSBN_P0(a5)			Source
		move.l	a1,TSBN_P1(a5)			Upper half is destination
		lea.l	BF_ES10(pc),a0			Copy and shift & copy function

20$		move.l	a0,bn_function(a5)		First blitter function
		move.l	a5,a1				Pointer to our blitnode
		move.l	a6,-(a7)
		move.l	TDD_GfxBase(a6),a6		The graphics library coordinates blitter usage
		LibCall QBlit				Control is returned immedately so we must wait here
		move.l	(a7)+,a6
		bsr	TD_WaitTDPort			A70A Wait for a message we sent to ourself from within Gfx
		movem.l	(a7)+,a2/a5
		rts


*-------------------------------------------------------*
*
*  DecodeLabel  DecodeSect
*
*  These routines replace the TD decode routine just for one reason, the allowence of
*  fast memory as I/O buffers.  Again the label is completely decoded by the CPU for
*  the size of the operation.  The sector is decoded by the blitter into the upper
*  halve of the source.  This does no harm because it is MFM'd again before any writes
*  to disk.  From the upper half it is then copied to the destination buffer.
*
*  Input:	a0	Destination  Users IO buffer
*		a1	Source       Sector location in trackdisk's trackbuffer
*		a3	TDU_
*		a6	TDD_
*

TDR_DecodeLabel	;Replacing TD-subroutine

		movem.l	d2/d3,-(a7)
		move.l	#$55555555,d2			Data mask
		moveq.l	#TD_LABELSIZE/4-1,d3
10$		move.l	TD_LABELSIZE(a1),d1		Unshifted data
		and.l	d2,d1				Mask timing bits away
		move.l	(a1)+,d0			Shifted data
		and.l	d2,d0				Mask timing bits away
		lsl.l	#1,d0				Shift back
		or.l	d1,d0				Fold together
		move.l	d0,(a0)+			Store into destination
		dbra	d3,10$				Loop..
		movem.l	(a7)+,d2/d3
		rts

TDR_DecodeSect	;Replacing TD-subroutine

DS_		movem.l	d2-d3/a2/a5,-(a7)
		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure
		lea.l	UD_BlitNode(a2),a5		Lea extended blitnode

		tst.b	d6				Destination chip memory?
		bne.s	10$				Yes..

*-	Non-chip destination

		add.w	#TD_SECTOR,a1			The sector is decoded into the upper half of the sector location
		move.l	a1,d2				Source of copy to IO buffer is begin of upper half
		move.l	a0,d3				Destination of second copy is IO buffer
		subq.l	#2,a1				Find end of lower half
		move.l	a1,TSBN_P0(a5)			Is pointer for blitter
		add.w	#TD_SECTOR,a1			Find end of upper half
		move.l	a1,TSBN_P1(a5)			Ponter for blitter
		move.l	a1,TSBN_P2(a5)			We decode into the upperhalf
		bra.s	20$

*--	Chip destination, blitter in descendinig mode: end of buffers

10$		add.w	#TD_SECTOR-2,a1			Find end of lower half
		move.l	a1,TSBN_P0(a5)			Source pointer for blitter
		add.w	#TD_SECTOR,a1			Find end of upper half
		move.l	a1,TSBN_P1(a5)			Source pointer for blitter
		add.w	#TD_SECTOR-2,a0			Find end of IO buffer
		move.l	a0,TSBN_P2(a5)			Destination pointer for blitter, decode into IO buffer

20$		lea.l	BF_DS10(pc),a0			Blitter decode function
		move.l	a0,bn_function(a5)		Function into blitnode
		move.l	a5,a1				Pointer to our blitnode
		move.l	a6,-(a7)
		move.l	TDD_GfxBase(a6),a6		The graphics library coordinates blitter usage
		LibCall QBlit				Control is returned immedately so we must wait here
		move.l	(a7)+,a6
		bsr	TD_WaitTDPort			A70A Wait for a message we sent to ourself from within Gfx

		tst.b	d6				Chip destination?
		bne.s	30$				Yes, data already in the IO buffer..

*--	Destination is non chip, use other data copy function
		
		move.l	d2,a0				No, data is in upperhalf of sector location
		move.l	d3,a1				Destination is IO buffer
		move.l	UD_CopySect(a2),a2		Get best copy function
		jsr	(a2)				Copy data into IOBuffer

30$		movem.l	(a7)+,d2-d3/a2/a5
		rts


*-------------------------------------------------------*
*
*  CopySect  Copy one uncoded sector from one place to another using the CPU or the Exec function
*
*	Input:	a0	Source
*		a1	Destination
*		a3	TDU_
*		a6	TDD_
*

		ifne	TD_SECTOR-512
		FAIL	Algorithm not properly adjusted for value of TD_SECTOR		
		endc

CopySectCPU	movem.l	d2-d7/a2-a6,-(a7)		We use as much registers as possible, sort of burst mode
		moveq.l	#9,d0				Init loop counter
10$		movem.l	(a0)+,d1-d7/a2-a6		Load 48 bytes
		movem.l	d1-d7/a2-a6,(a1)		Store 48 bytes
		add.w	#48,a1				With movem no ..,(a1)+ mode
		dbra	d0,10$				Loop..
		movem.l	(a0)+,d1-d7/a2			Still 32 bytes to do
		movem.l	d1-d7/a2,(a1)
		movem.l	(a7)+,d2-d7/a2-a6
		rts

CopySectExec	move.l	#TD_SECTOR,d0			Size of copy
		move.l	a6,-(a7)
		move.l	TDD_SysBase(a6),a6
		LibCall	CopyMem				DMA copy function
		move.l	(a7)+,a6
		rts
		

*********************************************************
*
*  Auto motor off and update extensions
*
*  There are two events that set UD_Update to UPDATECOUNT.  The internal motor on command
*  and a CMD_WRITE to a track.  The set after a write is done in TDE_Actual, a read extension.
*  After the elapse of the taskloop timer this counter is decremented.  If it reaches zero,
*  the changed-bit of the trackbuffer is tested, and if set, the buffer is written to disk.
*  Then the motor is switched off.
*
*  Input:	a3	TDU_
*		a6	TDD_
*
		

SetUpdCnt	move.l	d2,-(a7)			Just adapt to function termination

*--	Set/start update counter when motor is switched on

TDE_SetUpdCnt	;Continuation of the motor switch routine

		btst.b	#CIAB_DSKMOTOR,TDU_CiabPb(a3)	Current motor state (inverted)
		bne.s	10$				Motor is (switched) off..
		move.l	TDU_TCB+TC_Userdata(a3),a0	Lea UnitData structure
		move.w	#UPDATECOUNT,UD_Update(a0)	Init counter with number of iterations before updating
10$		move.l	(a7)+,d2			%
		rts	;				%
		
*--	Decrement update counter and take action upon elapse
		
TDE_CheckUpdate	;Continuation of the taskloop timer

CU_		move.l	(a7)+,a6			%
		btst.b	#B_UPDATE,UNIT_pad(a3)		Function in use?
		beq.s	CU_Rtn30			No..

		movem.l	a2/a4,-(a7)
		move.l	TDU_TCB+TC_Userdata(a3),a4	Lea UnitData structure
		move.w	UD_Update(a4),d0		Down counter
		beq.s	CU_Rtn20			Zero, nothing to do
		subq.w	#1,d0				Decrement, now zero?
		bne.s	CU_Rtn10			No, still nothing to do..
		move.l	TDU_DiskBuf(a3),a2		Yes, current trackbuffer
		btst.b	#0,TB_ChgFlag(a2)		Changed without been written to disk?
		beq.s	CU_MotorOff			No, just switch motor off..
		bsr	TDR_WriteTrack			Yes, write buffer to disk
		tst.l	d0				Error?
		bne.s	CU_MotorOff			Yes, but we don't care, skip clearing update-bit..
		bclr.b	#0,TB_ChgFlag(a2)		Updated now
CU_MotorOff	moveq.l	#0,d0				Switch motor off
		bsr	TD_SwitchMotor			A462
		moveq.l	#0,d0

CU_Rtn10	move.w	d0,UD_Update(a4)		
CU_Rtn20	movem.l	(a7)+,a2/a4
CU_Rtn30	rts	;				%
		

*********************************************************
*
*  NoClick extentions
*
*  Input:	a3	TDU_
*		a6	TDD_
*

TDE_NoClick	;This routine is called instead of "bchg.b #CIAB_DSKDIREC,TDU_CiabPb(a3)"
		
		btst.b	#B_NOCLICK,UNIT_pad(a3)		Do we use this feature?
		bne.s	10$				Yes..
		bchg.b	#CIAB_DSKDIREC,TDU_CiabPb(a3)	No, change direction bit in cia B image
		rts
10$		bset.b	#CIAB_DSKDIREC,TDU_CiabPb(a3)	Set direction bit to outwards in cia B image
		rts


*********************************************************
*
*  ReadOnly extentions
*
*  We can modify here the protect status of the disk
*
*  Input:	a3	TDU_
*		a6	TDD_
*

TDE_WriteProt	;This routine is called instead of "btst.b #CIAB_DSKPROT,_ciaa+ciapra"

WP_		btst.b	#B_READONLY,UNIT_pad(a3)	Is this drive readonly?
		bne.s	WP_ReadOnly			Yes..
		btst.b	#CIAB_DSKPROT,_ciaa+ciapra	No, but perhaps this disk?
		rts

TDE_WriteProt1	;This routine is called instead of "btst.b #CIAB_DSKPROT,d2"

		btst.b	#B_READONLY,UNIT_pad(a3)	Is this drive readonly?
		bne.s	WP_ReadOnly			Yes..
		btst	#CIAB_DSKPROT,d2		No, but perhaps this disk?
		rts

WP_ReadOnly	cmp.l	d0,d0				Set zero bit, meaning write protected
		rts


*********************************************************
*
*  RepairTrack
*
*  We will read the track in a large buffer.  This read is so big that there will be
*  an unbroken track in the buffer.  If we find a valid sector address in this unbroken
*  track, we can calculate the position of the track in the buffer.
*
*  Input:	a2	TD's trackbuffer
*		a3	TDU_
*		a6	TDD_
*
*  Usage:	a4	UD_
*		a5	SB_
*

RepairTrack	;Called from an in place extension of TD's ReadTrack subroutine

RT_		movem.l d3/a4-a5,-(a7)
		move.l	TDU_TCB+TC_Userdata(a3),a4	Lea UnitData structure
		bsr	ObtainBuffer
		move.l	a0,a5				Extra large read buffer
		moveq.l #-1,d0				Motor on
		bsr	TD_SwitchMotor			A462
		lea.l	SB_Data(a5),a0			Begin of data in buffer
		move.l	a0,SB_Begin(a5)
		lea.l	(2*SPT-1)*SE_SIZE+GAPSIZE(a0),a0 Add size we search in for syncs
		move.l	a0,SB_End(a5)
		move.w	#BADTRACKBITS,UD_SavedL(a4)	Init log restored labels
		move.w	#BADTRACKBITS,UD_SavedD(a4)	Init log restored data
		moveq.l #4,d3				Init retry count

RT_SalveLoop	lea.l	SB_Data(a5),a0			Destination for disk-read
		move.l	#2*SPT*SE_SIZE+GAPSIZE,d0	Number of bytes to read
		bsr	TD_ReadDisk			A524 Read d0 bytes into (a0)
		tst.l	d0				DiskChange?
		beq.s	10$				No..
		move.b	d0,TB_FirstSec(a2)		Yes, store error in trackbuffer for TD
		bra.s	RT_Rtn				Leave..
10$		clr.w	SB_CorrectTrk(a5)		Reset counter of headers with good tracknumber
		clr.w	SB_WrongTrk(a5)			Reset counter of headers with wrong tracknumber
		bsr	Salve				Analyse the buffer and save what is possible
		beq.s	RT_Rtn				All sectors and labels salved
		move.w	SB_CorrectTrk(a5),d0		How many times did we encounter good tracknumbers
		cmp.w	SB_WrongTrk(a5),d0		And how many bad?
		bpl.s	20$				More good..
		subq.l	#1,d3				Drive restore: just subtract one
		ble.s	RT_Rtn				Retries completed, quit..
		move.w	#-1,TDU_PTrack(a3)		Set current track to "Unknown"
		moveq.l #0,d0
		move.w	TDU_XTrack(a3),d0		Get track number we want
		bsr	TD_Seek				A3DA Drive restore and seek
		bra.s	RT_SalveLoop			Try again to salve the track
20$		subq.l	#2,d3				No restore, we read the correct track already, subtract two
		bhi.s	RT_SalveLoop			Retries not yet completed, loop..

*
*  We could write a track back to disk if it is completely recovered, but diskcopy or
*  Disksalv can do the job.  We leave the track unchanged so investigation is still possible.  
*  If YOU want to write it back you must build new sectorheaders in the recovered track
*  and mark the track as being changed and remove my name from this program.
*

RT_Rtn		bsr	ReleaseBuffer			Free buffer for usage by other TD tasks and functions
		movem.l (a7)+,d3/a4-a5
		rts

*-------------------------------------------------------*
*
*  Salve
*
*  We search for a sync.  If found we try to get a reliable sector address from the
*  succeeding data.  This address tells us how much and the position of the track preceding
*  this sector.	 We try to recover these sectors if we did not already.	 The area after the
*  found sector is also checked for sector presence, but if no success search will continue
*  from the found sync.
*
*  Input:	a2	TB_
*		a3	TDU_
*		a4	UD_
*		a5	SB_
*
*  Usage:	d2	Scratch
*		d5	SE_      Pointer to sector in imaginary track
*		d6	SE_      Pointer to sector of last detected sync
*		d7	Shiftfactor
*
*  Return:	d0	Pattern of bad labels and sectors
*


Salve
ST_		movem.l d2-d3/d5-d7,-(a7)
		subq.l	#HE_SIZE,a7			Four bytes local storage

*--	Lower priority during Salve

		moveq.l	#-2,d0				Lower than the standard user pri
		bsr	SetTDPri			
		move.b	d0,d3				Keep former priority

		move.l	SB_Begin(a5),d6			Begin of buffer
		subq.l	#8,d6				Undo next instruction

*--	Scan buffer for syncs.	If found, test it for a valid header.

ST_SearchLoop	addq.l	#8,d6				Point to word past previous sync found
		move.l	SB_End(a5),d0			End of search area
		sub.l	d6,d0				Minus begin of search area is search size
		ble	ST_EndSearch			End of buffer reached..
		move.l	d6,a0				Actual begin of search
		bsr	ST_SearchSync			Search next sync on this track
		bmi	ST_EndSearch			No sync found, leave..
		subq.l	#6,a0				Point to begin of potential sector
		move.l	a0,d6				Keep potential sector found
		bsr	ST_GetHeader			Test validity and decode header
		ble.s	ST_SearchLoop			Not valid

*--	We have a sector header.  Figure a track around it.

		move.l	d0,(a7)				Local header for loop control
		moveq.l #SPT,d0				Number of sectors per track
		sub.b	HE_ToGap(a7),d0			Subtract ahead of us, leaves us with number of sectors before us
		sub.b	d0,HE_SecNo(a7)			Set number of first sector, still positive?
		bpl.s	10$				Yes..
		add.b	#SPT,HE_SecNo(a7)		No, wrap
10$		move.b	#SPT,HE_ToGap(a7)		New gap countdown
		mulu	#SE_SIZE,d0			Convert number of sectors to bytes before our position
		move.l	d6,d5				Pointer to present sector
		sub.l	d0,d5				Pointer to first potential sector

*--	Scan imaginary track for storable sectors

ST_TrackLoop	cmp.l	SB_Begin(a5),d5			Are we before begin of the buffer?
		bmi	ST_NextSector			Yes, next sector..
		cmp.l	SB_End(a5),d5			Are we past the end of the buffer?
		bpl.s	ST_SearchLoop			Yes, stop with this track..
		move.b	HE_SecNo(a7),d0			Sector number
		move.l	UD_SavedL(a4),d1		Log of stored labels and sectors
		beq	ST_AllSaved			All stored, leave this routine..
		btst	d0,d1				Is the data of this sector already stored?
		bne.s	ST_SaveSector			No, try to..
		swap	d1				Yes, test the label
		btst	d0,d1				This label aready saved?
		beq	ST_NextSector			Yes, try next sector in our imaginary track..

*--	Try to store as much as possible from the sector d5 is pointing to.

ST_SaveSector	move.l	d5,a0				Ea of present sector
		bsr	ST_GetHeader			Get its header if possible
		bmi	ST_NextSector			Wrong track..
		beq.s	ST_SaveData			No header, perhaps the sector's data is OK
		cmp.l	(a7),d0				This MUST be the same or what?
		bne	ST_VeryBad			Very bad indeed
		move.l	d5,a0				Ea of present sector
		lea.l	SE_SumD(a0),a0			Lea data checksum
		bsr	ST_DecodeLong			Decode it
		move.l	d0,d2				Keep for compare
		move.l	#TD_SECTOR/2,d0			Size of data-part of sector in longs
		bsr	ST_CheckSum			Calculate checksum over data
		cmp.l	d2,d0				Same as found on disk?
		beq.s	ST_CopySector			Yes, save to copy the complete sector..
		move.b	HE_SecNo(a7),d0			No, but we have a valid header, the numbers are ok and if this
		move.w	UD_SavedD(a4),d1			sector is not yet saved, we better still copy it
		btst	d0,d1				Sector already saved?
		beq	ST_SaveLabel			Yes, skip bad sector copy
		bra.s	ST_LabelOK			We copy the sector, but skip the bitclear..
ST_CopySector	move.b	HE_SecNo(a7),d0			Number of this sector
		move.w	UD_SavedD(a4),d1		Data save-log
		bclr	d0,d1				Set data saved
		move.w	d1,UD_SavedD(a4)
ST_LabelOK	move.b	HE_SecNo(a7),d0			Number of this sector
		move.w	UD_SavedL(a4),d1		Label save-log
		bclr	d0,d1				Set label saved
		move.w	d1,UD_SavedL(a4)
		ext.w	d0				Cnv sectornumber byte to word
		mulu	#SE_SIZE,d0			To byte offset
		lea.l	TB_Data(a2),a1			TD's buffer, begin of sectors
		lea.l	SE_Label(a1,d0.l),a1		Lea destination of our data
		move.l	d5,a0				Ea of present source sector
		lea.l	SE_Label(a0),a0			Lea begin of part to copy
		move.w	#((SSIZE/2)<<HSIZEBITS)+1,d0	Size of sector for blitter
		move.w	#SSIZE,d2			Bytesize
		bsr	BlitMove			Copy to TD's buffer
		bra	ST_NextSector			Loop for next sector

ST_SaveData	move.b	HE_SecNo(a7),d0			Sector number
		move.w	UD_SavedD(a4),d1		Saved data log
		btst	d0,d1				Data of this sector already saved?
		beq.s	ST_NextSector			Yes..
		move.l	d5,a0				Ea of present sector
		lea.l	SE_SumD(a0),a0			Lea data checksum
		bsr	ST_DecodeLong			Decode it
		move.l	d0,d2				Keep for compare
		move.l	#TD_SECTOR/2,d0			Size of data-part of sector in longs
		bsr	ST_CheckSum			Calculate checksum over data
		cmp.l	d2,d0				Same as found on disk?
		bne.s	ST_NextSector			No, no header and bad data, skip copy, next perhaps..
		moveq.l #0,d0
		move.b	HE_SecNo(a7),d0			Number of present sector
		move.w	UD_SavedD(a4),d1		Saved data log
		bclr	d0,d1				Set data of this sector saved
		move.w	d1,UD_SavedD(a4)
		mulu	#SE_SIZE,d0			Sector number times sectorsize to find offset in TD's buffer
		lea.l	TB_Data(a2),a1			TD's buffer, begin of sectors
		lea.l	SE_SumD(a1,d0.l),a1		Lea destination of our data
		move.l	d5,a0				Ea of source sector
		lea.l	SE_SumD(a0),a0			Lea Data checksum, begin of copy to TD's buffer
		move.w	#((DSIZE/2)<<HSIZEBITS)+1,d0	Size of datapart and its checksum ready for the blitter
		move.w	#DSIZE,d2			Bytesize of block
		bsr	BlitMove			Copy to TD's buffer
		bra.s	ST_NextSector			Continue loop..


ST_SaveLabel	;move.b HE_SecNo(a7),d0			Present sector number
		move.w	UD_SavedL(a4),d1		Saved labels log
		bclr	d0,d1				We have a good one here
		beq.s	ST_NextSector			Was already saved, continue..
		move.w	d1,UD_SavedL(a4)		Nice, we can save a label
		ext.w	d0
		mulu.w	#SE_SIZE,d0			To byte offset
		lea.l	TB_Data(a2),a1			Lea begin of sectors
		lea.l	SE_Label(a1,d0.l),a1		Lea of label in destination sector in TD's buffer
		move.l	d5,a0				Ea of present sector
		lea.l	SE_Label(a0),a0			Lea label in source sector
		move.w	#((LSIZE/2)<<HSIZEBITS)+1,d0	Size of label ready for the blitter
		moveq.l #LSIZE,d2			Bytesize of block to move
		bsr	BlitMove			Move label to Trackdisks buffer
		;bra.s	ST_NextSector			Continue loop..

*--	Track-scan loop control.

ST_NextSector	move.b	HE_SecNo(a7),d0			Sector number
		addq.b	#1,d0				Next sector
		cmp.b	#SPT,d0				Must we wrap?
		bcs.b	10$				No..
		moveq.l #0,d0				Yes, sector 0
10$		move.b	d0,HE_SecNo(a7)
		add.l	#SE_SIZE,d5			Present sector pointer to next sector
		subq.b	#1,HE_ToGap(a7)			Decrement remaining sectors in our track, any left?
		bhi	ST_TrackLoop			Yes, process it..
		bra	ST_SearchLoop			No, we are ready with our track, try to find a new one..

ST_EndSearch
ST_AllSaved	move.l	UD_SavedL(a4),d0

ST_Rtn		exg.l	d3,d0				Former priority and keep pattern
		bsr	SetTDPri			Reset to original value
		addq.l	#HE_SIZE,a7			Clean up local
		move.l	d3,d0				Return proper condition codes
		movem.l (a7)+,d2-d3/d5-d7
		rts

ST_VeryBad	move.l	#BADTRACKBITS<<16+BADTRACKBITS,d0 Assume all labels and sectors to be unreliable
		move.l	d0,UD_SavedL(a4)
		bra.s	ST_Rtn


*-------------------------------------------------------*
*
*  GetHeader
*
*  Subroutine for Salve.  Test validity of the first part of a Trackdisk sector.  Set sector
*  address in SB_Header and return in d0 if valid.  Update statistics regarding tracknumber.
*  Return wrong track as a special case.
*
*  Input:	d7	Shift factor
*		a0	SE_
*		a2	TB_
*		a5	SB_
*
*  Return:	d0	Header, -1 if track wrong, 0 if other error.
*		a0	Ea of SE_Label
*

ST_GetHeader	addq.l	#SE_Header,a0
		moveq.l #HE_SIZE/2+TD_LABELSIZE/2,d0	Size of checksum area (longs)
		bsr	ST_CheckSum			Calculate checksum
		move.l	d0,-(a7)			Keep checksum
		bsr	ST_DecodeLong			Decode it
		cmp.l	(a7)+,d0			The same?
		bne.s	ST_BadHeader			No..
		add.w	#(SE_Header-SE_SumD),a0		Lea header again
		bsr	ST_DecodeLong
		move.l	d0,(a5)				Make header available
		cmp.b	#DISKFORMAT,(a5)		Our format?
		bne.s	ST_BadHeader			No..
		move.w	TB_TrkNo(a2),d1			Track number under head
		cmp.b	HE_TrkNo(a5),d1			Same as in header?
		bne.s	ST_WrongTrack			No..
		addq.w	#1,SB_CorrectTrk(a5)		Yes, one for us
		rts

ST_WrongTrack	addq.w	#1,SB_WrongTrk(a5)		One for them
		moveq.l #-1,d0				Error (restore?)
		rts

ST_BadHeader	moveq.l #0,d0				Error
		rts

*-------------------------------------------------------*
*
*  DecodeLong
*
*  Get two longwords from shifted memory and decode them into one longword
*
*  Input:	d7	Shift factor
*		a0	Data source
*
*  Return:	d0	Decoded longword
*		a0	Proper aligned for next access
*

ST_DecodeLong	movem.l d2/d3,-(a7)
		moveq.l #16,d3				Shift modulus
		sub.l	d7,d3				Complementary shift number
		move.l	(a0)+,d0			Get 48 bits (long + max shift)
		move.w	(a0),d2
		lsl.l	d7,d0				Shift first 32 bits left
		lsr.w	d3,d2				Shift last 16 bits right
		or.w	d2,d0				Put them together into one longword
		move.l	(a0)+,d1			Get 48 bits (long + max shift)
		move.w	(a0),d2
		lsl.l	d7,d1				Shift first 32 bits left
		lsr.w	d3,d2				Shift last 16 bits right
		or.w	d2,d1				Put them together into one longword
		and.l	#$55555555,d0			Remove MFM bits
		and.l	#$55555555,d1
		lsl.l	#1,d0				Line up
		or.l	d1,d0				Melt
		movem.l (a7)+,d2/d3
		rts


*-------------------------------------------------------*
*
*  CheckSum
*
*  Calculate checksum over shifted memory
*
*  Input:	d0	Length in longs
*		d7	Shift factor
*		a0	Begin of block
*
*  Return:	d0	Checksum
*		a0	Aligned to begin of next block
*

ST_CheckSum	movem.l d2/d3,-(a7)
		moveq.l #-1,d1				Build mask for first access
		lsr.l	d7,d1				Shift mask
		move.l	(a0)+,d2			Get part of first long
		and.l	d1,d2				Mask non-involved bits
		subq.l	#2,d0
10$		move.l	(a0)+,d3			Get longs
		eor.l	d3,d2				Checksum algorithm
		dbra	d0,10$				Loop
		move.l	(a0),d3				Get last part of last long
		not.l	d1				Flip mask
		and.l	d1,d3				Mask non-involved bits
		eor.l	d3,d2				Checksum algorithm
		rol.l	d7,d2				Unshift
		and.l	#$55555555,d2			Select relevant bits
		move.l	d2,d0				Checksum
		movem.l (a7)+,d2/d3
		rts

*-------------------------------------------------------*
*
*  SearchSync
*
*  Search for a Sync. If found, return its address on word boundary and
*  how many bits it is shifted to the right. (max 15)
*
*  Input:	d0.w	Number of bytes to check
*		a0	Start address to search
*
*  Return:	d0.w	Bytes left
*		d7	Bitshift
*		a0	Sync
*

ST_SearchSync	lsr	#1,d0				Bytecount to wordcount
ST_SSLoop	move.w	(a0)+,d1
		cmp.w	#SYNCSYNC>>0,d1
		beq.s	ST_Found0
		cmp.w	#SYNCSYNC>>1,d1
		beq.s	ST_Found1
		cmp.w	#SYNCSYNC>>2,d1
		beq.s	ST_Found2
		cmp.w	#SYNCSYNC>>3,d1
		beq.s	ST_Found3
		cmp.w	#SYNCSYNC>>4,d1
		beq.s	ST_Found4
		cmp.w	#SYNCSYNC>>5,d1
		beq.s	ST_Found5
		cmp.w	#SYNCSYNC>>6,d1
		beq.s	ST_Found6
		cmp.w	#SYNCSYNC>>7,d1
		beq.s	ST_Found7
		cmp.w	#SYNCSYNC>>8,d1
		beq.s	ST_Found8
		cmp.w	#SYNCSYNC>>9,d1
		beq.s	ST_Found9
		cmp.w	#SYNCSYNC>>10,d1
		beq.s	ST_Found10
		cmp.w	#SYNCSYNC>>11,d1
		beq.s	ST_Found11
		cmp.w	#SYNCSYNC>>12,d1
		beq.s	ST_Found12
		cmp.w	#SYNCSYNC>>13,d1
		beq.s	ST_Found13
		cmp.w	#SYNCSYNC>>14,d1
		beq.s	ST_Found14
		cmp.w	#SYNCSYNC>>15,d1
		beq.s	ST_Found15
		dbra	d0,ST_SSLoop			Loop d0 words
ST_SSRtn	subq.l	#2,a0
ST_SSRtn10	lsl.w	#1,d0				Wordcount to bytecount
		rts

ST_Found0	moveq.l #0,d7
		bra.s	ST_SSRtn10
ST_Found1	moveq.l #1,d7
		bra.s	ST_SSRtn
ST_Found2	moveq.l #2,d7
		bra.s	ST_SSRtn
ST_Found3	moveq.l #3,d7
		bra.s	ST_SSRtn
ST_Found4	moveq.l #4,d7
		bra.s	ST_SSRtn
ST_Found5	moveq.l #5,d7
		bra.s	ST_SSRtn
ST_Found6	moveq.l #6,d7
		bra.s	ST_SSRtn
ST_Found7	moveq.l #7,d7
		bra.s	ST_SSRtn
ST_Found8	moveq.l #8,d7
		bra.s	ST_SSRtn
ST_Found9	moveq.l #9,d7
		bra.s	ST_SSRtn
ST_Found10	moveq.l #10,d7
		bra.s	ST_SSRtn
ST_Found11	moveq.l #11,d7
		bra.s	ST_SSRtn
ST_Found12	moveq.l #12,d7
		bra.s	ST_SSRtn
ST_Found13	moveq.l #13,d7
		bra.s	ST_SSRtn
ST_Found14	moveq.l #14,d7
		bra.s	ST_SSRtn
ST_Found15	moveq.l #15,d7
		bra.s	ST_SSRtn


*-------------------------------------------------------*
*
*  BlitMove
*
*  Move a block of data from source to destination and shift it left by some bits.
*
*  Input:	d0.w	Blitsize ready to pass to the blitter
*		d2.w	Bytesize of block to move
*		d7.w	Shift factor: number of bits that memory IS shifted to the right
*		a0	Source
*		a1	Destination
*		a3	TDU_
*		a6	TDD_
*
*  In linear mode the blitter can move at most 2^10 (1024) words. Therefore we use  its
*  rectancular mode. We can set the horizontal size to 1 to 128 words, thus limiting our
*  blit to multiples of these.

BlitMove
BM_		movem.l d3-d5/a2,-(a7)

		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure
		lea.l	UD_BlitNode(a2),a2		Lea extended blitnode

*
*  We use the blitter in ascending mode. Then the blitter performs shifts to the right.
*  Therfore we translate our order to shift left into shift right.  IF we shift, and we
*  stick to our blitsize, we loose some bits. This is because we express in blitsize
*  the size of the track in words instead of bits.  If these bits do not begin on a
*  word-boundary they do not end either.  Because the blitter can move at most 1024
*  blocks of 1 to 128 words, and we do not determine the blocksize (the calling routine is),
*  we take care of this word by hand (the cpu).
*
		move.l	d7,d4				Shiftfactor (to left)
		neg.w	d4				We want 16 minus shift results in requested shift to right, zero?
		beq.s	10$				Yes, no shift..
		subq.l	#2,a1				Destination one word lower
		move.w	(a1),d3				Keep first word to restore after blit
		move.l	-2(a0,d2.w),d5			Get last two words of block (out of reach of the blitter)
		lsl.l	d7,d5				Do the shift of the last word here
		swap.w	d5				D5 holds now the last word
10$		move.w	d0,bn_blitsize(a2)		The calling routine has aready assembled the correct value
		moveq.l #BSHIFTSHIFT,d0			Shift shift factor 12 bits left, thus clearing all other
		lsl.w	d0,d4				bits: no fill, ascending and area mode
		move.w	d4,TSBN_C1(a2)			Prepared blitter command
		move.l	a0,TSBN_P1(a2)			Source
		move.l	a1,TSBN_P2(a2)			Destination
		lea.l	BF_BM10(pc),a0			Lea blitter function
		move.l	a0,bn_function(a2)		Function into blitnode
		move.l	a2,a1				Pointer to our blitnode
		move.l	a6,-(a7)
		move.l	TDD_GfxBase(a6),a6		The graphics library coordinates blitter usage
		LibCall QBlit				Control is returned immedately so we must wait here
		move.l	(a7)+,a6
		bsr	TD_WaitTDPort			A70A Wait for a message we sent to ourself from within Gfx
		tst.w	TSBN_C1(a2)			Shift not zero?: Did we modify the destination pointer?
		beq.s	BM_Rtn				No, blit fitted in word boundary..
		move.l	TSBN_P2(a2),a0			Yes, get destination (pointing one word earlier)
		move.w	d3,(a0)				Restore original value of word before desired destination
		move.w	d5,0(a0,d2.w)			Last word which was out of reach of the blitter
BM_Rtn		movem.l (a7)+,d3-d5/a2
		rts


*********************************************************
*
*  CMD_READ, CMD_WRITE extensions.
*
*  Following extensions are called or jumped to from within the main IO routine
*  in Trackdisk.  This routine must be modified to handle reads from salved tracks,
*  to allow non-chip IO buffers, an additional error check and an adaption for
*  the auto update function.
*

*-------------------------------------------------------*
*
*  TDE_CMD_RW
*
*  Do some additional inits for the main IO routine:
*  Clear UD_Actual valid flag.
*  Extra test for CMD_WRITE to protected disk.
*  Type of memory of IO buffer.
*

TDE_CMD_RW	;Called from somewhere near the begining of the handling of CMD_READ and CMD_WRITE

CRW_		moveq.l	#0,d0
		move.l	d0,IO_ACTUAL(a2)		% Replaced instruction
		moveq.l	#-1,d2				Set Reg_Actual to not valid
		cmp.b	#CMD_WRITE,IO_COMMAND+1(a2)	Is this a write command?
		bne.s	20$				No..
		btst.b	#B_READONLY,UNIT_pad(a3)	Yes, on a simulated readonly drive?
		bne.s	10$				Yes, error..
		btst.b	#4,TDU_Flags(a3)		No, on a protected disk?
		beq.s	20$				No, write alowed..
10$		move.b	#TDERR_WriteProt,IO_ERROR(a2)	Yes, set error
		bra.s	CRW_Rtn				Return non-zero
20$		move.l	IO_DATA(a2),a1			IOBuffer

TestMem		move.l	a6,-(a7)
		move.l	TDD_SysBase(a6),a6
		LibCall	TypeOfMem			What sort of memory is this buffer
		btst	#MEMB_CHIP,d0			Chip?
		sne.b	d6				Set d6 if chip
		move.l	(a7)+,a6
		moveq.l	#0,d0				Return no error
CRW_Rtn		rts

*-------------------------------------------------------*
*
*  TDE_CheckBuf
*
*  There is an error in the track.  If the track is not salved, the tracknumber
*  is set to -1, as TD normally does.  But if the track is salved, the tracknumber
*  must stay valid.
*

TDE_CheckBuf	;Called from "terminate with read error"

		cmp.b	#CMD_WRITE,IO_COMMAND+1(a1)	Write command to bad track?
		beq.s	10$				Yes, error..
		btst.b	#B_SALVE,UNIT_pad(a3)		No, is the track salved?
		bne.s	20$				Yes..
10$		move.b	d0,IO_ERROR(a1)			% Set error in IORequest
		move.w	#-1,TB_TrkNo(a2)		% Invalidate tracknumber
		moveq.l	#0,d0				Return equal, meaning leave IO with error
20$		rts


*-------------------------------------------------------*
*
*  TDE_ReadCheck
*
*  Adapt reads to error handling based on error flags for each sector apart.
*  Trackdisk sets the tracknumber in its trackbuffer to -1, meaning no valid track in
*  the buffer.  TD does this if it finds a TB_FirstSec larger than possible.  We have
*  prevented TD doing so if the salve function was enabled.  Then we check TD_FirstSec
*  each time TD_TrkNo would have been checked.  This enables us to access a faulty
*  trackbuffer.
*  Always copy data, but if bad, set IO_ERROR and remember IO_ACTUAL.
*
		
TDE_ReadCheck	;Bra to here instead of TD_CmdRead

		cmp.b	#SPT,TB_FirstSec(a0)		Error in track?
		bcs	TD_CmdRead			A890 No, proceed..
	
		moveq.l	#0,d0				
		move.b	TDU_IOSector(a3),d0		Current sector number
		tst.l	d2				Reg_Actual, error already processed?
		bpl	TD_CmdRead10			Yes, continue transfers..

		move.l	TDU_TCB+TC_Userdata(a3),a1	No, lea UnitData structure
		move.l	UD_SavedL(a1),d1		Get pattern with bad sectors and labels
		btst	d0,d1				Faulting sector?
		bne.s	10$				Yes, set error..
		btst.b	#0,TDU_Flags(a3)		Label transfer?
		beq	TD_CmdRead10			A8A0 No, no error, continue transfers..
		swap.w	d1				Yes, label transfers, get label log
		btst	d0,d1				Error in label?
		beq	TD_CmdRead10			A8A0 No, continue transfers..
10$		move.l	IO_ACTUAL(a2),d2		Error! Remember number of bytes transferred so far
		move.b	TB_FirstSec(a0),IO_ERROR(a2)	Set error in IORequest
		bra	TD_CmdRead10			A8A0 Continue transfers


*-------------------------------------------------------*
*
*  TDE_ChkActual
*
*  Because all sectors are transferred that are requested, the requesting program
*  must have some way to know how much of its buffer is filled with good data.
*  The size is kept in d2 and if valid (positive) this is passed to the requester.
*  If we handled a write in this command, the track was updated and TrackSalve
*  must be informed for its auto update function.
*  

TDE_ChkActual	;On the way to subroutine Reply IORequest.

		tst.b	IO_ERROR(a1)			Error met during IO?
		beq.s	10$				No..
		tst.l	d2				Is Reg_Actual valid?
		bmi	TD_IOReply			No, continue subroutine Reply IORequest..
		move.l	d2,IO_ACTUAL(a1)		Enter number of transferred bytes until error
		bra	TD_IOReply			Continue subroutine Reply IORequest..
10$		cmp.b	#CMD_WRITE,IO_COMMAND+1(a1)	Was this IO a write?
		bne	TD_IOReply			No..
		move.l	TDU_TCB+TC_Userdata(a3),a0	Yes, lea UnitData structure
		move.w	#UPDATECOUNT,UD_Update(a0)	(Re)set update counter
		bra	TD_IOReply			Continue subroutine Reply IORequest..


*********************************************************
*
*  Write extensions.
*
*  Write Trackdisks buffer to disk and check whether verify is enabled.	 Do not verify if the
*  TD_WriteTrack returned an error.  Get the verify buffer and read the just written track into
*  it.	Tidy the buffer up and compare it with the just written.  In case of some error, display
*  a requester and rewrite if asked for.
*
*  Input:	a3	Trackdisk Unit structure
*		a6	Trackdisk device base
*
*  Return:	d0	Write error
*
*  Usage:	d2	Error
*		a2	Verify buffer
*		a4	Trackdisk buffer written to disk
*

TDR_WriteTrackF ;Inserted/replaced call from Format to write buffer to disk

		clr.b	TB_FirstSec(a0)			Format does not use and set this field

TDR_WriteTrack	;Replaces TD_WriteTrack

WT_		bsr	MFMTrack			Ensure proper MFM-format
WT_Write	bsr	TD_WriteTrack			A958 Normal write track
		move.b	UNIT_pad(a3),d1
		and.w	#(F_VERIFY1+F_VERIFY0),d1	Verify on?
		bne.s	20$				Yes..
10$		rts

20$		tst.l	d0				Did TD_WriteTrack had an error?
		bne.s	10$				Yes, we do not verify..

		movem.l d2/d3/a2/a4,-(a7)
		move.w	d1,d3				Verify bits become read retry counter
		subq.w	#1,d3				Adapt to dbra .. instruction
		bsr	ObtainBuffer			Get buffer to read into from disk
		move.l	a0,a2
30$		move.l	TDU_DiskBuf(a3),a4		The buffer which was written to disk
		move.l	a2,TDU_DiskBuf(a3)		The buffer into we will read from disk
		move.w	(a4),(a2)			Tracknumber
		moveq.l #1,d0				Motor on
		bsr	TD_SwitchMotor			A462
		moveq.l #0,d0
		move.w	(a2),d0				Tracknumber
		bsr	TD_Seek				A3DA Seek to it
		lea.l	TB_Data+4(a2),a0		Position in buffer to begin to read
		move.w	#(SPT+1)*SE_SIZE+GAPSIZE,d0	Size of read
		bsr	TD_ReadDisk			A524 Read from disk
		tst.l	d0				DiskChange?
		bne.s	50$				Yes, that is a verify error..
		move.w	TDU_XTrack(a3),d2		Keep current value
		move.w	(a4),TDU_XTrack(a3)		TD_NormTrack uses this value as the current track
		moveq.l #-1,d0				Tell (modified) TD_NormTrack to skip header revision
		bsr	TD_NormTrack			AFE2 Tidy the track up
		move.w	d2,TDU_XTrack(a3)		Restore original value
		move.l	a4,TDU_DiskBuf(a3)		TD's write buffer back into TD's global
		cmp.b	#SPT,d0				Error?
		bcc.s	40$				Yes..
		move.b	d0,TB_FirstSec(a2)		First sector in the verify buffer
		move.l	a2,a0				Verify buffer
		move.l	a4,a1				Original written buffer
		bsr	CompareTracks			Compare both buffers (they are not exactly the same)
		beq.s	WT_Rtn				No error..
40$		dbra	d3,30$				Read retry?

*--	Let's request. TD has a 512 byte stack. Not enough to call Intuition..	But we have here a buffer of 26k!

50$		moveq.l #0,d0				Motor off during request
		bsr	TD_SwitchMotor			A462
		add.w	#10000,a2			Make a little room for stack
		exg	a2,a7				Set a7 to the buffer
		move.w	TB_TrkNo(a4),d0			Tracknumber
		bsr	VerifyAlert			Display the requester
		move.l	a2,a7				TD's stack again
WT_Rtn		move.l	d0,d2				Answer of user: zero is ignore
		bsr	ReleaseBuffer			We do not need the verify buffer anymore
		move.l	d2,d0				Rewrite?
		movem.l (a7)+,d2/d3/a2/a4
		bne	WT_Write			The user wanted a rewrite..
		rts


*-------------------------------------------------------*
*
*  CompareTracks
*
*  Compare data in two trackbuffers.  A simple compare is not possible.	 The data should be
*  the same but may be arranged differently.
*
*  Input:	a0	TB_ verify
*		a1	TB_ original
*
*  Return:	d0	Zero if buffers are the same, -1 in case of error
*

CompareTracks
CT_		move.l	a2,-(a7)
		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure
		lea.l	UD_BlitNode(a2),a2		Lea extended blitnode

		moveq.l #0,d0				No error
		move.l	d0,TSBN_P3(a2)			Preset blitter return value
		
		sub.b	TB_FirstSec(a1),d0		Subtract first sector of the original buffer
		add.b	TB_FirstSec(a0),d0		Add first sector of the verify buffer
		bpl.s	10$				Positive..
		add.b	#SPT,d0				Wrap
10$		move.w	d0,bn_blitsize(a2)		Number of sectors to compare the first time
		moveq.l	#SPT,d1				Total number of sectors
		sub.l	d0,d1				Number of remaining sectors to compare the second time
		mulu	#SE_SIZE,d1			Size of block to compare the second time

		lea.l	TB_Data(a1),a1			Begin of compare in the original buffer
		move.l	a1,TSBN_P0(a2)			Into blitnode
		lea.l	TB_Data(a0),a0			Begin of second compare in the verify buffer
		move.l	a0,TSBN_P2(a2)			Into blitnode
		add.l	d1,a0				Add size of second compare to find begin of first compare
		move.l	a0,TSBN_P1(a2)			Begin of first compare in the verify buffer into blitnode

		lea.l	BF_CMP10(pc),a0			First blitter compare function
		move.l	a0,bn_function(a2)		Into blitnode
		move.l	a2,a1				Blitnode 
		move.l	a6,-(a7)
		move.l	TDD_GfxBase(a6),a6		The graphics library coordinates blitter usage
		LibCall QBlit				Control is returned immedately so we must wait here
		move.l	(a7)+,a6
		bsr	TD_WaitTDPort			A70A Wait for a message we sent to ourself from within Gfx

		move.l	TSBN_P3(a2),d0			Return value of blitter compare function
		move.l	(a7)+,a2
		rts


*-------------------------------------------------------*
*
*  VerifyAlert	-  Notify user of the verity error and ask him what to do.
*
*  To do so, we use a requester with the choise to ignore the event (inherent in TD) or to
*  rewrite the track.  This is more complicated as it looks at first sight.  It would be
*  nice if an AutoRequest could be used (simple & small), but the idea behind write verify
*  requires an airtight approach.  If there is not enough memory to build the AutoRequest,
*  Intuition defaults to an Alert.  But if there is not enough memory to build the Alert,
*  Intuition simply returns FALSE.  As if the user selected "Ignore".  Useless for our
*  purposes.  So we have to build our own requester.  We have no window open, so we open a
*  window for just one use:  to show the requester.  A requester has the fe. ff feature to
*  block all input to the window.  Intuition permits all kinds of events to penetrate to
*  the SysRequest.  I do not know an easy way (we are patching TD, remember?) to get the same
*  result.  The other approach is to build the gadgets directly in the window.	Then we
*  receive all kind of events, including Left-Amiga-V and Left-Amiga-N.	 Pity that DMouse
*  cannot see that we are requesting.  But otherwise we have no shortcuts.  So?
*
*  Input:	d0	Tracknumber
*		a3	TDU_
*		a6	TDD_
*
*  Return:	d0	TRUE for rewrite, FALSE for ignore
*
*  Usage:	d2	im_IAddress, Window fail and function result flag
*		d3	im_Class
*		d4	im_Code
*		a4	Window structure
*		a5/a6	IntuitionBase/SysBase
*


VerifyAlert
VA_		movem.l d2-d4/a2/a4/a5,-(a7)

*--	Insert head number in requester string

		moveq.l #'0'>>1,d1			Prepare for asci conversion
		lsr.b	#1,d0				Get head number in X-bit
		roxl.b	#1,d1				Make asci zero or one
		lea.l	TXT_HeadNr(pc),a0		Destination
		move.b	d1,(a0)				Store into requester string

*--	D0 now contains the cylinder number.  Convert via BCD to asci and store into string

		move.l	a7,a2				Predecrement pointer to local word
		clr.w	-(a7)				One word local
		moveq.l #7,d1				Binary 2 nibbles to 2 bcd nibbles conversion
10$		move.l	a2,a0				Destination
		move.l	a2,a1				Destination
		lsl.b	#1,d0				Binary shift left
		abcd.b	-(a0),-(a1)			Bcd shift left
		dbra	d1,10$				Loop for eigth bits

		move.w	(a7)+,d1			Get bcd word
		lea.l	TXT_TrackNr(pc),a0		Destination
		move.b	d1,d0				Bcd value
		lsr.b	#4,d1				Next nibble
		or.b	#'0',d1				Convert to asci
		move.b	d1,(a0)+			Store in alert string
		and.b	#$0f,d0				Mask nibble
		or.b	#'0',d0				Convert to asci
		move.b	d0,(a0)				Store in alert string

*--	Unit number in string

		moveq.l #'0',d0				Asci first unit
		add.b	TDU_UnitNr(a3),d0		Unit number
		lea.l	TXT_UnitNr(pc),a0		Position in requester string
		move.b	d0,(a0)				Store unit number

*--	Open a window on the Workbench screen and show a requester in it.

		moveq.l #-1,d2				Set flag to requester failed
		move.l	TDU_TCB+TC_Userdata(a3),a0	Lea UnitData structure
		move.l	UD_TSControl(a0),a0		TSControl structure
		move.l	a6,-(a7)			Trackdisk device base
		move.l	TDD_SysBase(a6),a5		ExecBase
		move.l	TSC_IntuBase(a0),a6		Our starter got IntuitionBase already for us
		LibCall WBenchToFront			We open our window in the WB screen
		move.l	ib_FirstScreen(a6),a0		Get this screen
		move.w	sc_DetailPen(a0),d0		Get both screen pens.
		lea.l	TSCodeBegin(pc),a0		
		move.w	d0,IT_Body0-TSCodeBegin(a0)	Use normal pens for body texts
		move.w	d0,IT_Body1-TSCodeBegin(a0)
		move.b	d0,IMG_ReqOnOff-TSCodeBegin(a0)
		rol.w	#8,d0				Swap pens to get inversed texts
		move.w	d0,IT_Positive-TSCodeBegin(a0)	Use inversed display for gadget texts
		move.w	d0,IT_Negative-TSCodeBegin(a0)
		move.b	d0,IMG_GadOnOff-TSCodeBegin(a0)
		lea.l	NEW_Requester(pc),a0		NewWindow structure
		LibCall OpenWindow
		move.l	d0,a4				Window structure, success?
		beq.s	VA_NoReq			No..

*--	Wait for an answer of the user

		exg.l	a5,a6				SysBase in a6
VA_IDCMP_Loop	move.l	wd_UserPort(a4),a0		IDCMP message port
		LibCall WaitPort			Wait for a message from Intuition
		move.l	wd_UserPort(a4),a0		IDCMP message port
		LibCall GetMsg				Remove message from queue
		move.l	d0,a1
		move.l	im_Class(a1),d3			Keep Class
		move.l	im_IAddress(a1),d2		Keep message initiator
		move.l	im_Code(a1),d4			Keep Code AND Qualifier
		LibCall ReplyMsg			Message back to Intuition

*--	Perhaps the user clicked one of the gadgets

		cmp.l	#GADGETUP,d3			Gadget clicked?
		bne.s	VA_ChkRawkey			No, check keyboard shortcut
		lea.l	GAD_Negative(pc),a0		Get one of both message initiators
		sub.l	a0,d2				Set return value to zero if this gadget was clicked
		beq.s	VA_CloseReq			"Ignore" was clicked..
		moveq.l #1,d2				Not equal, other gadget must have been clicked, return positive
		bra.s	VA_CloseReq

*--	Perhaps the user pressed a 'B' or 'V'

VA_ChkRawkey	cmp.l	#RAWKEY,d3			Keyboard event?
		bne.s	VA_IDCMP_Loop			No, ignore message..
		and.w	#IEQUALIFIER_LCOMMAND,d4	Left-Amiga pressed?
		beq.s	VA_IDCMP_Loop			No, ignore..
		swap.w	d4				Select code field
		moveq.l #0,d2				Returnvalue for "Ignore"
		cmp.w	#$0035,d4			Keycode for 'B'
		beq.s	VA_CloseReq			Same, return ignore..
		moveq.l #1,d2				Returnvalue for "Rewrite"
		cmp.w	#$0034,d4			Keycode for 'V'
		bne.s	VA_IDCMP_Loop			Not what we want, ignore message..

*--	Get present position of the window and close it

VA_CloseReq	exg.l	a5,a6				IntuitionBase again
		lea.l	NEW_Requester(pc),a0		NewWindow structure
		move.l	wd_LeftEdge(a4),(a0)		Install present window position into new window
		move.l	a4,a0				Window structure
		LibCall CloseWindow
VA_NoReq	move.l	a6,a5				IntuitionBase
		move.l	(a7)+,a6			TD base
		move.l	d2,d0				Result
		bpl.s	VA_Rtn				Positive, user replied on requester..

*--	For some reason there was no requester, so bleep screens and blink drive led, return rewrite

		exg	a5,a6				Negative, no requester, get IntuBase
		sub.l	a0,a0				All screens
		LibCall DisplayBeep			Bleep
		exg	a5,a6				TD Base
		moveq.l #6,d2				Blink drive led 3 times
10$		move.l	d2,d0				Get counter
		and.l	#1,d0				Select LSB (toggles)
		bsr.w	TD_SwitchMotor			A462 Motor on and off
		move.l	#200000,d0			Sleep for a while
		bsr.w	TD_Sleep			A4F0
		dbra	d2,10$				Loop
		moveq.l #-1,d0				Set rewrite as result

VA_Rtn		movem.l (a7)+,d2-d4/a2/a4/a5
		rts


*-------------------------------------------------------*
*
*  Requester data structures.
*
*  These structures have pointers to each other.  Therefore we cannot move them without making
*  adaptions.  We can do two things.  Normal relocation followed by an adaption after the move,
*  or not relocate at loadtime and perform complete relocation later.  We choose the latter
*  because this saves relocation info in the exe and the relocation routine is not
*  larger/smaller/easyer/harder.
*  Because the relocation table is not to be included in the resident structure, it is
*  physically placed somewhere at the end of this file.
*  The "Body text" is tied to the "positve text".  This saves us Intuprinting the requester text.
*  Because code is outgrowing already the pan, the font is fixed to topaz 8.  All calculations
*  regarding window size, gadget positions, text postitions are done by hand and here and now.
*
*  This code will be modified, but it contains no CPU instructions.
*

NEW_Requester	dc.w	0,0
		dc.w	242,55
		dc.b	-1,-1
		dc.l	GADGETUP+RAWKEY
		dc.l	WINDOWDEPTH+WINDOWDRAG+SIMPLE_REFRESH+NOCAREREFRESH+ACTIVATE
NEW_ReqGadget	dc.l	GAD_Positive-TSCodeBegin
		dc.l	0
NEW_ReqTitle	dc.l	TXT_VerTitle-TSCodeBegin
		dc.l	0,0
		dc.w	0,0,0,0
		dc.w	WBENCHSCREEN

GAD_Positive	dc.l	GAD_Negative-TSCodeBegin
		dc.w	26,35
		dc.w	82,16
		dc.w	GADGIMAGE+GADGHCOMP
		dc.w	RELVERIFY+ENDGADGET
		dc.w	BOOLGADGET+REQGADGET
GAD_PosRender	dc.l	IMG_Gadgets-TSCodeBegin
		dc.l	0
GAD_PosIText	dc.l	IT_Positive-TSCodeBegin
		dc.l	0
		dc.l	0
		dc.w	0
		dc.l	0

GAD_Negative	dc.l	0
		dc.w	134,35
		dc.w	82,16
		dc.w	GADGIMAGE+GADGHCOMP
		dc.w	RELVERIFY+ENDGADGET
		dc.w	BOOLGADGET+REQGADGET
GAD_NegRender	dc.l	IMG_Request-TSCodeBegin
		dc.l	0
GAD_NegIText	dc.l	IT_Negative-TSCodeBegin
		dc.l	0
		dc.l	0
		dc.w	0
		dc.l	0

IMG_Request	dc.w	-130,-23
		dc.w	234,41,0
		dc.l	0
		dc.b	0
IMG_ReqOnOff	dc.b	0
IMG_ReqNext	dc.l	IMG_Gadgets-TSCodeBegin

IMG_Gadgets	dc.w	0,0
		dc.w	82,16,0
		dc.l	0
		dc.b	0
IMG_GadOnOff	dc.b	0
		dc.l	0

IT_Positive	dc.b	0,0,RP_JAM2,0
		dc.w	13,4
IT_PosFont	dc.l	TA_Topaz8-TSCodeBegin
IT_PosText	dc.l	TXT_Positive-TSCodeBegin
IT_PosNext	dc.l	IT_Body0-TSCodeBegin

IT_Negative	dc.b	0,0,RP_JAM2,0
		dc.w	17,4
IT_NegFont	dc.l	TA_Topaz8-TSCodeBegin
IT_NegText	dc.l	TXT_Negative-TSCodeBegin
		dc.l	0

IT_Body0	dc.b	0,0,RP_JAM2,0
		dc.w	-14,-20				Relative to the positive gadget
IT_B0Font	dc.l	TA_Topaz8-TSCodeBegin
IT_B0Text	dc.l	TXT_Body0-TSCodeBegin
IT_B0Next	dc.l	IT_Body1-TSCodeBegin

IT_Body1	dc.b	0,0,RP_JAM2,0
		dc.w	-14,-11				Relative to the positive gadget
IT_B1Font	dc.l	TA_Topaz8-TSCodeBegin
IT_B1Text	dc.l	TXT_Body1-TSCodeBegin
		dc.l	0

TA_Topaz8	dc.l	TXT_FontName-TSCodeBegin
		dc.w	8
		dc.b	FS_NORMAL,0

TXT_VerTitle	dc.b	' TrackSalve 1.3 ',0,0,0
TXT_FontName	dc.b	'topaz.font',0
TXT_Body0	dc.b	'Write verify error detected',0
TXT_Body1	dc.b	'on unit '
TXT_UnitNr	dc.b		'x, track '
TXT_TrackNr	dc.b			 'xx, head '
TXT_HeadNr	dc.b				  'x',0

TXT_Positive	dc.b	'Rewrite',0
TXT_Negative	dc.b	'Ignore',0

		cnop	0,4
		
		
*********************************************************
*
*  ObtainBuffer  -  ReleaseBuffer
*
*  Handling of permission to use the buffer
*
*  Input:	a3	TDU_
*		a6	TDD_
*
*  Return:	a0	buffer
*

ObtainBuffer	move.l	a2,-(a7)
		move.l	TDU_TCB+TC_Userdata(a3),a2	Lea UnitData structure
		move.l	UD_TSControl(a2),a2		Lea TSControl structure
		lea.l	TSC_OwnBuffer(a2),a0		Lea Semaphore for buffer usage
		move.l	a6,-(a7)
		move.l	TDD_SysBase(a6),a6		Trackdisk's SysBase
		LibCall AttemptSemaphore		Try to lock buffer usage
		move.l	(a7)+,a6
		tst.l	d0				Locked?
		bne.s	10$				Yes..
		moveq.l #0,d0				No, motor off
		bsr	TD_SwitchMotor			A462
		lea.l	TSC_OwnBuffer(a2),a0		Lea Semaphore for buffer usage
		move.l	a6,-(a7)
		move.l	TDD_SysBase(a6),a6		Trackdisk's SysBase
		LibCall ObtainSemaphore			Wait for permission to use it
		move.l	(a7)+,a6
10$		move.l	TSC_Buffer(a2),a0		The buffer itself
		move.l	(a7)+,a2
		rts


ReleaseBuffer	move.l	TDU_TCB+TC_Userdata(a3),a0	Lea UnitData structure
		move.l	UD_TSControl(a0),a0		Lea TSControl structure
		lea.l	TSC_OwnBuffer(a0),a0		Lea Semaphore for buffer usage
		move.l	a6,-(a7)
		move.l	TDD_SysBase(a6),a6		Trackdisk's SysBase
		LibCall ReleaseSemaphore
		move.l	(a7)+,a6
		rts


*********************************************************
*
*  SetTDPri
*
*  Change task priority of this Trackdisk task
*

SetTDPri	lea.l	TDU_TCB(a3),a1			Trackdisk's task structure
		move.l	a6,-(a7)
		move.l	TDD_SysBase(a6),a6
		LibCall	SetTaskPri
		move.l	(a7)+,a6
		rts


*********************************************************
*
*  QBlit functions.  Parameters are passed by the blitnode structure.
*  We have exclusive control over the blitter here.
*  NB!	This code is executed under control of other regimes. Behave well.
*
*  Input:	a0	Pointer to blitter
*		a1	Pointer to blitnode
*
*  Return:	d0	-1, meaning not ready
*

*-------------------------------------------------------*
*
*  Take a (faulting) MFM-word and convert it to BF (My name: Balanced Format):
*
*  Take the data bits (mask $5555), shift them right one bit, invert them,
*  and store them merged with the original databits back into the same
*  location.  Now we have the BF-format.
*

;							     __
BLITLF		set	ABC+ANBC+ANBNC+NANBNC		D=AC+BC
BLITUSE		set	SRCA+SRCB+DEST
SHIFTA		set	0<<ASHIFTSHIFT
SHIFTB		set	1<<BSHIFTSHIFT

CTL0		set	SHIFTA+BLITUSE+BLITLF
CTL1		set	SHIFTB				Ascending, Area

BF_MT10		bsr.s	BF_SetBlitMod
		move.l	TSBN_P0(a1),d1			Begin of block
		move.l	d1,bltapt(a0)			Into A
		move.l	d1,bltbpt(a0)			Into B
		move.l	d1,bltdpt(a0)			Begin of block into D
		move.w	#$5555,bltcdat(a0)		Datamask
		move.l	#CTL0<<16+CTL1,bltcon0(a0)	Instruct blitter its operation
		move.w	#((SE_SIZE/2)<<HSIZEBITS)+SPT,bltsize(a0)	Start blit
		lea.l	BF_MT20(pc),a0
		move.l	a0,bn_function(a1)		Next function	
		;moveq	#-1,d0			
		rts

*-------------------------------------------------------*
*
*  Take a BF word and convert it to MFM:
*
*  Take a BF word, invert it, shift it left one bit, and AND it with
*  the original BF word. Now it is MFM.

;							_
BLITLF		set	NABC+NABNC			AB
BLITUSE		set	SRCA+SRCB+DEST
SHIFTA		set	1<<ASHIFTSHIFT
SHIFTB		set	0<<BSHIFTSHIFT

CTL0		set	SHIFTA+BLITUSE+BLITLF
CTL1		set	SHIFTB+BC1F_DESC		Descending: leftshifts

BF_MT20		move.l	TSBN_P1(a1),d1			End of block
		move.l	d1,bltapt(a0)			All blitter pointers to it
		move.l	d1,bltbpt(a0)		
		move.l	d1,bltdpt(a0)		
		move.l	#CTL0<<16+CTL1,bltcon0(a0)	Instruct blitter its operation
		move.w	#((SE_SIZE/2)<<HSIZEBITS)+SPT,bltsize(a0)	Start blit
		bra.s	BF_QuitBlit
		

*-------------------------------------------------------*
*
*  Copy source direct into destination
*

BLITLF	set	ABC+ABNC+ANBC+ANBNC			D=A
BLITUSE	set	SRCA+DEST
SHIFTA	set	0<<ASHIFTSHIFT
SHIFTB	set	0<<BSHIFTSHIFT

CTL0	set	SHIFTA+BLITUSE+BLITLF
CTL1	set	SHIFTB					Ascending, Area mode

BF_ES10		bsr.s	BF_SetBlitMod
		move.l	TSBN_P0(a1),bltapt(a0)		Source
		move.l	TSBN_P1(a1),bltdpt(a0)		Destination
		move.l	#(CTL0<<16)+CTL1,bltcon0(a0)	Ascending, Area mode
		move.w	#((TD_SECTOR/2)<<HSIZEBITS)+1,bltsize(a0)	Start blit
		lea.l	BF_ES25(pc),a0			Next function
		move.l	a0,bn_function(a1)		
		rts


*-------------------------------------------------------*

BF_SetBlitMod	moveq.l	#0,d0
		move.l	d0,bltcmod(a0)			Clear c and b modulus
		move.l	d0,bltamod(a0)			Clear a and d modulus
		moveq.l	#-1,d0				Build mask
		move.l	d0,bltafwm(a0)			Set first and last word mask
		rts
		
BF_QuitBlit	lea.l	BF_End(pc),a0
		move.l	a0,bn_function(a1)		Next function	
		moveq.l	#-1,d0
		rts
		
		
*-------------------------------------------------------*
*
*  Copy the source block to the destination and shift it right one bit.
*

BLITLF	set	ABC+ABNC+ANBC+ANBNC			D=A
BLITUSE	set	SRCA+DEST				As memory input
SHIFTA	set	1<<ASHIFTSHIFT			
SHIFTB	set	0<<BSHIFTSHIFT

CTL0	set	SHIFTA+BLITUSE+BLITLF
CTL1	set	SHIFTB					Ascending: shift right, Area mode

BF_ES20		bsr.s	BF_SetBlitMod
BF_ES25		move.l	TSBN_P2(a1),bltapt(a0)		Source pointer
		move.l	TSBN_P3(a1),bltdpt(a0)		Destination
		move.l	#CTL0<<16+CTL1,bltcon0(a0)	Instruct blitter its operation
		move.w	#((TD_SECTOR/2)<<HSIZEBITS)+1,bltsize(a0)	Start blit
		bra.s	BF_QuitBlit

*-------------------------------------------------------*
*
*  To decode we mask the first word, shift it left, and OR it with the masked second word.
*  This way we do it with the CPU. The blitter can perform this algorith: Shift the first
*  word by one bit, AND it with the inverted mask and OR it with the second word which is
*  ANDed with the true mask: D=((A>>1).NC)+BC
*

;						        	         _
BLITLF		set	ABC+ABNC+ANBNC+NABC		Results into: D=AC+BC
BLITUSE		set	SRCA+SRCB+DEST			Two sources and one destination
SHIFTA		set	1<<ASHIFTSHIFT			Shift source A by one bit
SHIFTB		set	0<<BSHIFTSHIFT

CTL0		set	SHIFTA+BLITUSE+BLITLF
CTL1		set	SHIFTB+BC1F_DESC		Descending: shift right, Area mode

BF_DS10		bsr.s	BF_SetBlitMod
		move.l	TSBN_P0(a1),bltapt(a0)		Source pointer A
		move.l	TSBN_P1(a1),bltbpt(a0)		Source pointer B
		move.l	TSBN_P2(a1),bltdpt(a0)		Destination
		move.w	#$5555,bltcdat(a0)		Datamask into C data register
		move.l	#CTL0<<16+CTL1,bltcon0(a0)	Instruct blitter its operation
		move.w	#((TD_SECTOR/2)<<HSIZEBITS)+1,bltsize(a0)	Start blit
		bra.s	BF_QuitBlit



*-------------------------------------------------------*
*
*  Shift and move a block from one place to another
*

BLITLF		set	ABC+ABNC+NABC+NABNC		D=B
BLITUSE		set	SRCB+DEST			B is source and D destination
SHIFTA		set	0<<ASHIFTSHIFT			Shift source A by one bit

CTL0		set	SHIFTA+BLITUSE+BLITLF

BF_BM10		bsr.s	BF_SetBlitMod
		move.w	#CTL0,bltcon0(a0)
		move.w	TSBN_C1(a1),bltcon1(a0)		Shift factor into BSH (B-shift) ascending
		move.l	TSBN_P1(a1),bltbpt(a0)		Source into B
		move.l	TSBN_P2(a1),bltdpt(a0)		Destination into D
		move.w	bn_blitsize(a1),bltsize(a0)	Start blit by writing size
		bra.s	BF_QuitBlit

*-------------------------------------------------------*
*
*  Compare two blocks (1)
*
*  We perform a XOR on both blocks.  The result must always be zero.  We do not
*  store the result.  Therefore we use source C, which limits the operation to
*  four ticks.  The next function checks the bltnzero bit in the dmaconr register.
*  

;							   _ _
BLITLF		set	ABNC+NABC			D=AC+AC
BLITUSE		set	SRCA+SRCC
SHIFTA		set	0<<ASHIFTSHIFT
SHIFTB		set	0<<BSHIFTSHIFT

CTL0		set	SHIFTA+BLITUSE+BLITLF
CTL1		set	SHIFTB				Ascending, Area

BF_CMP10	bsr	BF_SetBlitMod
		move.l	#CTL0<<16+CTL1,bltcon0(a0)	Instruct blitter its operation
		move.w	#$FFFF,bltbdat(a0)		Validate AND operation

		move.l	TSBN_P0(a1),bltapt(a0)		Original trackbuffer into A
		move.l	TSBN_P1(a1),bltcpt(a0)		Begin of same sector in verify buffer into C
		move.w	bn_blitsize(a1),d0		Number of sectors of first block to compare
		beq.s	BF_CMP202			Is zero, we go directly to the second compare
		or.w	#((SE_SIZE/2)<<HSIZEBITS),d0	Merge sector size into blitsize word
		move.w	d0,bltsize(a0)			Start blit

		lea.l	BF_CMP20(pc),a0
		move.l	a0,bn_function(a1)		Next function	
		;moveq	#-1,d0			
		rts

*-------------------------------------------------------*
*
*  Compare two blocks (2)
*
*  The second compare starts with a check of the first compare.  Then the second
*  compare is passed to the bitter.
*

BF_CMP20	bsr.s	BF_TestZero			Test result of last compare
		bmi.s	BF_End				Error, no need to continue..

BF_CMP202	moveq.l	#SPT,d0				Total number of sectors
		sub.w	bn_blitsize(a1),d0		Subtract number of sectors already compared
		beq	BF_End				All compared..
		or.w	#((SE_SIZE/2)<<HSIZEBITS),d0	Merge sector size into blitsize word
		move.l	TSBN_P2(a1),bltcpt(a0)		Pointer to second block into C
		move.w	d0,bltsize(a0)			Start blit
		lea.l	BF_CMP30(pc),a0
		move.l	a0,bn_function(a1)		Next function	
		moveq	#-1,d0			
		rts

*-------------------------------------------------------*
*
*  End Compare
*
*  Check the result of the second compare and quit
*

BF_CMP30	bsr.s	BF_TestZero			Set return value of this compare
		bra.s	BF_End				Continue QBlit end function
		
BF_TestZero	move.w	dmaconr(a0),d0			Dma status word
		btst	#DMAB_BLTNZERO,d0		Did blitter had once or more a non-zero result?
		bne.s	10$				No..
		moveq.l	#-1,d0				Yes, -1 means error
		move.l	d0,TSBN_P3(a1)			Set return value
10$		rts		

*-------------------------------------------------------*
*
*  QBlit end function
*
*  Inform task all blitter operations are done and terminate.
*

BF_End		move.l	TSBN_Unit(a1),a1		TD unit pointer
		bsr	TD_Reply			A6F2
		moveq.l #0,d0				Return 0 to stop QBlit
		rts


*********************************************************
*
*  End of code to be copied to the allocated space.  Would this be the allocted space,
*  then the TD-copy would begin here.
*  From here it is allowed again to make the location counter external available.
*

TSCodeEnd
TD

TD_NoDisk	equ	TD+$00DE	99C2
TD_ChkDiskPres	equ	TD+$00FC	99E0
TD_IOReply	equ	TD+$08CC	A1B0
TD_Seek		equ	TD+$0AF6	A3DA
TD_SwitchMotor	equ	TD+$0B7E	A462
TD_Sleep	equ	TD+$0C0C	A4F0
TD_ReadDisk	equ	TD+$0C40	A524
TD_Reply	equ	TD+$0E0E	A6F2
TD_WaitTDPort	equ	TD+$0E26	A70A
TD_CmdCheck	equ	TD+$0F20	A804
TD_CmdWrite	equ	TD+$0F34	A818
TD_CmdRead	equ	TD+$0FAC	A890
TD_CmdRead10	equ	TD+$0FBC	A8A0
TD_EndRW	equ	TD+$103C	A920
TD_WriteTrack	equ	TD+$1074	A958
TD_440b		equ	TD+$109E	A982
TD_ReadTrkRetry equ	TD+$1106	A9EA
TD_ReadTrkRtn	equ	TD+$1114	A9F8
TD_CorrectEdge	equ	TD+$14DA	ADBE
TD_TaskLoop	equ	TD+$1580	AE64
TD_NormTrack	equ	TD+$16FE	AFE2
TD_NormTrackRtn equ	TD+$18F0	B1D4
TD_BadSecID	equ	TD+$1910	B1F4
TD_BadHdrSum	equ	TD+$1914	B1F8


*********************************************************
*
*  This table contains data which will be put into the trackdisk code we copied from ROM.
*  Its location must directly follow TSCodeEnd for offset calculations.  So do not reposition
*  this table without an adaption of the Patch macro.
*  The format of a table entry has following form:
*
*  WORD		OffsetInTD		Offset relative to rt_MatchTag
*  UWORD	PatchSize		Size of patch in words
*  STRUCT	Patch,PatchSize*2	The patch itself
*
*  The Patch table consists of a series of patch structures following each other.  The end
*  of the table is reached when a patch is met with a PatchSize of zero.
*

Patch		MACRO	<Offset in TD>,<Patchsize in bytes>
		dc.w	\1
		dc.w	(\2)/2
TS		set	*-TD-\1
		ENDM

		Func	TSPatchTable,_TSPatchTable

*--	Bug patches

		Patch	$1A38,P000e-P000b		B31C Bug in td_RawWrite
P000b		cmp.l	#$7fff,d0			Now immediate instead of absolute indirect
P000e
		Patch	$00E4,P001e-P001b		99C8 Disk presence check AAAAAAAAARRRRRRRGGGHHHH...
P001b		bne.w	TS+TD_ChkDiskPres		99E0 GetUnit before hardware access patch
P001e

*--	Let toplevel task loop flow through our code

		Patch	$1592,P100e-P100b		AE76 Toplevel task loop
P100b		bra.w	TS+TDE_TaskLoop			Extent taskloop
P100e

*--	Check first with us before clicking

		Patch	$0104,P200e-P200b		99E8 Presence test
P200b		bsr.w	TS+TDE_NoClick			Check function active before clicking
		nop
P200e

*--	Check readonly simutation before writes or returning td_ProtStatus

		Patch	$0D22,P300e-P300b		A606 Write routine
P300b		bsr.w	TS+TDE_WriteProt		Check first our protect bit
		nop
		nop
P300e
		Patch	$1194,P301e-P301b		AA78 Tab-test for td_ProtStatus
P301b		bsr.w	TS+TDE_WriteProt1		Check first our protect bit
P301e

*--	Read/write adaptions to the salve function and type of memory of the IO buffers

		Patch	$0E50,P400e-P400b		A734 
P400b		movem.l	d2/d6/a2-a4,-(a7)		We use d2 as error flag for IO of salved tracks and d6 as memtype
P400e
		Patch	$0E5E,P405e-P405b		A742 Clear IO_ACTUAL
P405b		bsr.w	TS+TDE_CMD_RW			Set d2 to zero, memtype of IO buffers, Write to Prot. disk?
		bne.w	TS+TD_EndRW
P405e
		Patch	$0ECA,P410e-P410b		A7AE Get trackbuffer
P410b		move.l	TDU_UnitBuf(a3),a0
P410e
		Patch	$0F0E,P415e-P415b		A7F2 Error in trackbuffer
P415b		move.l	TDU_IOReq(a3),a1
		bsr	TS+TDE_CheckBuf			Test read or write or salved
		bne.s	TS+TD_CmdCheck			Read salved track..
		bra.w	TS+TD_EndRW			A920 We do not write or track not salved, leave..
P415e
		Patch	$0F30,P420e-P420b		A814 Branch read or write
P420b		bne.w	TS+TDE_ReadCheck		Read, but perhaps the track is salved, special care..
P420e
		Patch	$1040,P425e-P425b		A924 Calling Reply IORequest
P425b		bsr.w	TS+TDE_ChkActual		Check first for updating IO_ACTUAL and the write update counter
P425e
		Patch	$1052,P430e-P430b		A936
P430b		movem.l	(a7)+,d2/d6/a2-a4		Restore d2 and d6
P430e
		Patch	$1058,P435e-P435b		A73C Return buffer if buffer contains track d0
P435b		move.l	TDU_UnitBuf(a3),a0		Get trackdisks own buffer
		;cmp.w	TB_TrkNo(a0),d0			Requested track in buffer?
		cmp.w	(a0),d0				Requested track in buffer?
		bne.s	10$				No..
		cmp.b	#CMD_WRITE,IO_COMMAND+1(a2)	Are we writing?
		bne.s	20$				No, return buffer..
		cmp.b	#SPT,TB_FirstSec(a0)		Salved track?
		bcs.s	20$				No, return buffer..
10$		sub.l	a0,a0				Return null
20$		rts
P435e
		ifgt	P435e-P435b-28
		FAIL	Patch too long, will not fit!
		endc
		
		Patch	$109E,P440e-P440b		A982 Unused area in trackdisk
P440b		btst.b	#B_SALVE,UNIT_pad(a3)		TD stops, are we going to do something about it?
		beq.s	TS+TD_ReadTrkRtn		A9F8 No, function not active, continue TD..
		move.l	TDU_IOReq(a3),a0
		cmp.b	#CMD_WRITE,IO_COMMAND+1(a0)	Are we reading for preparing a write?
		beq.s	TS+TD_ReadTrkRtn		A9F8 Yes, writes are not allowed on salved tracks, continue TD..
		bsr	TS+RepairTrack			No, it is a read, we give it a try..
		bra.s	TS+TD_ReadTrkRtn		A9F8 Continue TD..
P440e		
		ifgt	P440e-P440b-28
		FAIL	Patch too long, will not fit!
		endc

		Patch	$1104,P445e-P445b		A9E8 Read error after normalisation
P445b		bgt.s	TS+TD_440b			A982 Check first with us before giving up
P445e

*--	Change some errors which are meaningless outside Trackdisk

		Patch	$1796,P450e-P450b		B07A Search for a sector in Normalize
P450b		bne.w	TS+TD_BadHdrSum			Was: BadSecHdr
P450e
		Patch	$17AC,P451e-P451b		B090 Search for a sector in Normalize
P451b		bne.w	TS+TD_BadSecID			Was: BadSecHdr
P451e
		Patch	$17B8,P452e-P452b		B09C Search for a sector in Normalize
P452b		bne.w	TS+TD_BadSecID			Was: BadSecHdr
P452e

*--	Verify adaptions to write routines

		Patch	$07C4,P500e-P500b		A0A8 Write updated track to disk in format routine
P500b		bsr	TS+TDR_WriteTrack
P500e
		Patch	$0EDC,P502e-P502b		A7C0 Write updated track to disk in device i/o (before seek)
P502b		bsr	TS+TDR_WriteTrack
P502e
		Patch	$11D6,P503e-P503b		AABA Write updated track to disk in CMD_UPDATE
P503b		bsr	TS+TDR_WriteTrack
P503e
		Patch	$15D2,P504e-P504b		AEB6 Write updated track to disk in close device
P504b		bsr	TS+TDR_WriteTrack
P504e

*--	Verify adaptions to the "raw track to writable track" convert routine

		Patch	$16FE,P520e-P520b		AFE2 Begin of this routine
P520b		movem.l d0/d2-d6/a2,-(a7)		D0 added to list, has become an argument now available on stack
P520e
		Patch	$180A,P521e-P521b		B0EE Replacement of calling CorrectEdge, which is obsolete
P521b		tst.l	20(a7)				TD calls this routine with zero saved here
		bne.w	TS+TD_NormTrackRtn		B1D4 Called by the verify routine, skip header revision..
P521e
		Patch	$18FA,P522e-P522b		B1DE End of this routine
P522b		movem.l (a7)+,d1/d2-d6/a2		D1 added to list as a dummy pull to compensate above
P522e

*--	Verify adaption to Format routine

		Patch	$0864,P541e-P541b		A148  Bring format routine to follow standard write path
P541b		move.w	d2,TB_TrkNo(a0)			Set tracknumber in trackbuffer
		move.l	a0,TDU_DiskBuf(a3)		Trackdisk's buffer is write buffer
		bsr.w	TS+TDR_WriteTrackF		Call (almost) standard write routine
P541e

*--	New coding routines

		Patch	$1462,P600e-P600b		AD46 Encode a longword routine
P600b		move.l	d0,d1				Encode one longword
		lsr.l	#1,d0				Even bits
		move.l	d0,(a0)+			Store even bits
		move.l	d1,(a0)+			Store odd bits
		rts					; We do not care about the timing bits
P600e
		Patch	$0F6A,P601e-P601b		A84E Device write routine, label flag was set
P601b		bsr.w	TS+TDR_EncodeLabel		Encode it simple and with the CPU
P601e
		Patch	$0F90,P602e-P602b		A874 Device write routine, write sector
P602b		bsr.w	TS+TDR_EncodeSect		Replace encoding by our routines
P602e
		Patch	$1248,P603e-P603b		AB2C Build a complete sector for TD_FORMAT
P603b		bsr.w	TS+TDR_EncodeSect		Replace encoding by our routines
P603e

		Patch	$0FDC,P650e-P650b		A8C0 Device read routine, read label
P650b		bsr.w	TS+TDR_DecodeLabel		Replace decoding by our routines
P650e
		Patch	$0FEE,P651e-P651b		A8D2 Device read routine, read sector
P651b		bsr.w	TS+TDR_DecodeSect		Replace decoding by our routines
P651e
*		Patch	$13C2,P652e-P652b		ACA6 -- not used by Trackdisk
*P652b		bsr.w	TS+TDR_DecodeSect		Replace decoding by our routines
*P652e

*--	Type of memory in format routine

		Patch	$0796,P670e-P670b		A07A Begin of format routine
P670b		movem.l	d2-d6/a2/a5,-(a7)		D6 added to list as flag for type of mem
P670e
		Patch	$0804,P672e-P672b		A0E8 Just before encoding loop in format routine
P672b		bsr.w	TS+TDE_FormInit			Find out what kind of memory is used for IO
P672e
		Patch	$0890,P674e-P674b		A174 End of format routine
P674b		movem.l	(a7)+,d2-d6/a2/a5		D6 added to list
P674e

*--	Update routines

		Patch	$0BD6,P700e-P700b		A4BA  Continuation of motor switch
P700b		bra.w	TS+TDE_SetUpdCnt		Set or clear the counter
P700e

*  Setting the counter after a change of the trackbuffer (CMD_WRITE) is done in the Read/Write patches (P4..)

		Patch	$00A4,P702e-P702b		9988  Continuation of disk presence check
P702b		bra.w	TS+TDE_CheckUpdate		Decrement counter and switch the motor off if elapsed
P702e

		
*--	List termination

		Patch	0,0


*********************************************************
*
*  The relocation table of the code between TSCodeBegin and TSCodeEnd.
*

		Func	TSCodeRelocTable

		dc.w	NEW_ReqGadget-TSCodeBegin
		dc.w	NEW_ReqTitle-TSCodeBegin
		dc.w	IMG_ReqNext-TSCodeBegin
		dc.w	GAD_Positive-TSCodeBegin
		dc.w	GAD_PosRender-TSCodeBegin
		dc.w	GAD_PosIText-TSCodeBegin
		dc.w	GAD_NegRender-TSCodeBegin
		dc.w	GAD_NegIText-TSCodeBegin
		dc.w	IT_B0Font-TSCodeBegin
		dc.w	IT_B0Text-TSCodeBegin
		dc.w	IT_B0Next-TSCodeBegin
		dc.w	IT_B1Font-TSCodeBegin
		dc.w	IT_B1Text-TSCodeBegin
		dc.w	IT_PosFont-TSCodeBegin
		dc.w	IT_PosText-TSCodeBegin
		dc.w	IT_PosNext-TSCodeBegin
		dc.w	IT_NegFont-TSCodeBegin
		dc.w	IT_NegText-TSCodeBegin
		dc.w	TA_Topaz8-TSCodeBegin
		dc.w	0


*********************************************************
*
*  The size of the code to be copied is EndTSCode-_TSCode.  The size of the buffer is
*  also assembler laid down.
*  How do we pass these values to a C-module?
*  For now with globals, but constants would be more appropriate..
*

		SECTION __MERGED,data

		gc_l	_TSCodeSize,TSCodeEnd-TSCodeBegin
		gc_l	_BufferSize,SB_SIZE
		gc_l	_PCSubOffset,FirstPCSub-TSCodeBegin
		gc_l	_PCWaitOffset,FirstPCWait-TSCodeBegin

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

		END

