home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
392.lha
/
tracksalve_v1.3
/
Source
/
patch.a
< prev
next >
Wrap
Text File
|
1990-07-03
|
84KB
|
2,499 lines
* 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