*  Switch.a  --  TrackSalve
*
*   #    date    by    Comment
*  -- --------- ---- ---------------------
*   0 29-Oct-89  DWR   Created for Tracksalve
*

*               nolist
                INCLUDE "Call.i"
                INCLUDE "ts.i"
                INCLUDE "exec/tasks.i"
                INCLUDE "exec/resident.i"
*               list



                CSECT   text,code,0,1,2                 Any xref's after this are 16-bit reloc

*********************************************************
*
*  PCtoTS
*
*  We need to catch Trackdisk in its highest task-loop.  Otherwise we could lose control
*  after an rts.  This loop is rather small:  7 instuctions.  One of the instructions is a
*  jsr _LVOWait(a6). Trackdisk is waiting here for a timer or an IORequest and will be here
*  most of the time.  If we change the return address to our code, Trackdisk smoothly enters
*  our code.  We change this address only if TD is at this point.
*
*  Input:       a0      UnitData structure
*
*  Output:      d0      0 if caught else E_CATCHTD
*
*  Usage:       d2      PC of TD-task at the point where we want to change it
*               d6      Timeout counter
*               d7      Error
*
*               a2      TSControl structure
*               a3      UnitData structure
*               a5      Task stucture of Trackdisk unit task
*
*  NB!  We are accessing the TSControl structure in a way that needs protection.
*

                Func    PCtoTS,@PCtoTS
                movem.l d2/d3/d6/d7/a2/a3/a5,-(a7)

                moveq.l #0,d7                           No error for now
                move.l  a0,a3                           UnitData structure

                move.l  UD_TDReq+IO_UNIT(a3),a5         Lea Unit structure of the Trackdisk IORequest
                move.b  TDU_UnitNr(a5),d3               Get unit number (to set InUse flag later)
                move.l  MP_SIGTASK(a5),a5               Lea Task control block associated with this port
                move.l  UD_TSControl(a3),a2             Control structure
                move.l  TSC_TDTag(a2),d2                Begin of TD code
                add.l   #$1592,d2                       Add offset of desired return address
                moveq.l #25,d6                          We put a limit here, so we will not hang forever if TD is dead

CheckPC         ExCall  Forbid                          Prevent TD to become active
                move.l  TC_SPUPPER(a5),a0               Initial stackpointer of TD
                cmp.l   WaitRtnPC(a0),d2                Is TD on the desired spot?
                beq.s   ChangePC                        Yes, change the return address..
                LibCall Permit                          No, give TD a chance to change its situation
                moveq.l #10,d1                          We will wait for a fifth of a second
                DOSCall Delay                           Sleeping
                dbra    d6,CheckPC                      And try again..
                moveq.l #E_CATCHTD,d7                   But not forever, so set error
                bra.s   PCtoTSRtn                       Quit..

ChangePC        move.l  d2,UD_ReturnTD(a3)              Save original TD address
                move.l  TSC_TSCode(a2),WaitRtnPC(a0)    Change return addres to adress in our code
                move.l  TC_Userdata(a5),UD_Userdata(a3) Keep original value (although TD does not use it)
                move.l  a3,TC_Userdata(a5)              Make UnitData structure known to TD-task
                bset.b  d3,TSC_InUse(a2)                Set flag to prevent freeing the TSControl structure
                LibCall Permit                          Multitasking on again

PCtoTSRtn       move.l  d7,d0                           Error
                movem.l (a7)+,d2/d3/d6/d7/a2/a3/a5
                rts



*********************************************************
*
*  RelocateTS
*
*  Modify position dependend values in copied TSCode
*
*  Input:       a0      TSControl structure
*

                Func    RelocateTS,@RelocateTS
                move.l  TSC_TSCode(a0),a0
                lea.l   TSCodeRelocTable(pc),a1
10$             move.w  (a1)+,d0
                beq.s   20$
                move.l  a0,d1
                add.l   0(a0,d0.w),d1
                move.l  d1,0(a0,d0.w)
                bra.s   10$
20$             rts

                xref    TSCodeRelocTable


*********************************************************
*
*  RelocateTD
*
*  Modify position dependend values in relocated Trackdisk code versions 33.127 and 34.1
*
*  Input:       a0      TSControl structure
*

                ifd     __stdargs
                Func    _RelocateTD
                move.l  4(a7),a0
                endc

                Func    RelocateTD,@RelocateTD
                move.l  TSC_TSTag(a0),a1                Begin of copy of Trackdisk code
                move.l  TSC_TDTag(a0),d0                Begin of Trackdisk code (in ROM)
*               cmp.l   a1,RT_MATCHTAG(a1)              Does our copy has its self-pointer right?
*               beq.s   RelocateRtn                     Yes, already relocated..
                sub.l   a1,d0                           TD org minus TD copy = relocation value
                lea.l   RelocTable(pc),a0               Table of relative addresses to relocate
                bra.s   Relocate20                      Enter loop..
Relocate10      sub.l   d0,0(a1,d1.w)                   Only Amiga makes it possible!
Relocate20      move.w  (a0)+,d1                        Get offset in TD-code
                bne.s   Relocate10
RelocateRtn     rts



*--     You can obtain this table by comparing version 1.2 and 1.3 and do some editing on the result

RelocTable      dc.w    $0002
                dc.w    $0006
                dc.w    $000E
                dc.w    $0012
                dc.w    $0016
                dc.w    $0324
                dc.w    $032A
                dc.w    $03C0
                dc.w    $091C
                dc.w    $0940
                dc.w    $0966
                dc.w    $0980
                dc.w    $0994
                dc.w    $09B6
                dc.w    $09C4
                dc.w    $09CC
                dc.w    $0A00
                dc.w    $0A04
                dc.w    $0A08
                dc.w    $0A0C
                dc.w    $0A10
                dc.w    $0A14
                dc.w    $0A1C
                dc.w    $0A20
                dc.w    $0A24
                dc.w    $0A28
                dc.w    $0A2C
                dc.w    $0A30
                dc.w    $0A34
                dc.w    $0A38
                dc.w    $0A3C
                dc.w    $0A40
                dc.w    $0A44
                dc.w    $0A48
                dc.w    $0A4C
                dc.w    $0A50
                dc.w    $0A54
                dc.w    $0A58
                dc.w    $0A5C
                dc.w    $0A60
                dc.w    $0A64
                dc.w    $0A68
                dc.w    $0A6C
                dc.w    $0A70
                dc.w    $127E
                dc.w    $12EA
                dc.w    $1316
                dc.w    $1352
                dc.w    $1386
                dc.w    $13E4
                dc.w    $1446
                dc.w    $1690
                dc.w    $16B8
                dc.w    $195A
                dc.w    $19A2
                dc.w    $19B2
                dc.w    0



*********************************************************
*
*  PatchMem
*
*  Change memory according to a table
*
*  Input:       a0      Memory to change
*               a1      Patchtable  (Offset.w, Size.w, Patch.w[Size])
*

                Func    PatchMem,@PatchMem
                movem.l a2,-(a7)
                move.l  a0,a2                           Lea begin of memory

GetNextPatch    move.l  a2,a0                           Begin of memory
                move.w  (a1)+,d0                        Get offset in code to put patch
                add.w   d0,a0                           Lea destination of patch
                move.w  (a1)+,d1                        Get size of patch in words
                beq.s   PatchMemRtn                     No patch, done..
                bra.s   CopyPatch10                     Enter copyloop
CopyPatch       move.w  (a1)+,(a0)+                     Copy word of code
CopyPatch10     dbra    d1,CopyPatch                    Loop ..
                bra.s   GetNextPatch                    Examine next entry in Patchtable

PatchMemRtn     movem.l (a7)+,a2
                rts


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

                END

