**
* Scout - The Amiga System Monitor
*
*------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* You must not use this source code to gain profit of any kind!
*
*------------------------------------------------------------------
*
* @author Andreas Gelhausen
* @author Richard Körber <rkoerber@gmx.de>
*



        include "OBJECTS/scout_asm.i"


* FUNCDEF macro definition for 'exec/exec_lib.i'

FUNCDEF     MACRO    *function
_LVO\1      EQU      FUNC_CNT
FUNC_CNT    SET      FUNC_CNT-6
            ENDM
FUNC_CNT    SET      5*-6


        FUNCDEF Supervisor
        FUNCDEF ExitIntr
        FUNCDEF Schedule
        FUNCDEF Reschedule
        FUNCDEF Switch
        FUNCDEF Dispatch
        FUNCDEF Exception
        FUNCDEF InitCode
        FUNCDEF InitStruct
        FUNCDEF MakeLibrary
        FUNCDEF MakeFunctions
        FUNCDEF FindResident
        FUNCDEF InitResident
        FUNCDEF Alert
        FUNCDEF Debug
        FUNCDEF Disable
        FUNCDEF Enable
        FUNCDEF Forbid
        FUNCDEF Permit
        FUNCDEF SetSR
        FUNCDEF SuperState
        FUNCDEF UserState
        FUNCDEF SetIntVector
        FUNCDEF AddIntServer
        FUNCDEF RemIntServer
        FUNCDEF Cause
        FUNCDEF Allocate
        FUNCDEF Deallocate
        FUNCDEF AllocMem
        FUNCDEF AllocAbs
        FUNCDEF FreeMem
        FUNCDEF AvailMem
        FUNCDEF AllocEntry
        FUNCDEF FreeEntry
        FUNCDEF Insert
        FUNCDEF AddHead
        FUNCDEF AddTail
        FUNCDEF Remove
        FUNCDEF RemHead
        FUNCDEF RemTail
        FUNCDEF Enqueue
        FUNCDEF FindName
        FUNCDEF AddTask
        FUNCDEF RemTask
        FUNCDEF FindTask
        FUNCDEF SetTaskPri
        FUNCDEF SetSignal
        FUNCDEF SetExcept
        FUNCDEF Wait
        FUNCDEF Signal
        FUNCDEF AllocSignal
        FUNCDEF FreeSignal
        FUNCDEF AllocTrap
        FUNCDEF FreeTrap
        FUNCDEF AddPort
        FUNCDEF RemPort
        FUNCDEF PutMsg
        FUNCDEF GetMsg
        FUNCDEF ReplyMsg
        FUNCDEF WaitPort
        FUNCDEF FindPort
        FUNCDEF AddLibrary
        FUNCDEF RemLibrary
        FUNCDEF OldOpenLibrary
        FUNCDEF CloseLibrary
        FUNCDEF SetFunction
        FUNCDEF SumLibrary
        FUNCDEF AddDevice
        FUNCDEF RemDevice
        FUNCDEF OpenDevice
        FUNCDEF CloseDevice
        FUNCDEF DoIO
        FUNCDEF SendIO
        FUNCDEF CheckIO
        FUNCDEF WaitIO
        FUNCDEF AbortIO
        FUNCDEF AddResource
        FUNCDEF RemResource
        FUNCDEF OpenResource
        FUNCDEF RawIOInit
        FUNCDEF RawMayGetChar
        FUNCDEF RawPutChar
        FUNCDEF RawDoFmt
        FUNCDEF GetCC
        FUNCDEF TypeOfMem
        FUNCDEF Procure
        FUNCDEF Vacate
        FUNCDEF OpenLibrary
        FUNCDEF InitSemaphore
        FUNCDEF ObtainSemaphore
        FUNCDEF ReleaseSemaphore
        FUNCDEF AttemptSemaphore
        FUNCDEF ObtainSemaphoreList
        FUNCDEF ReleaseSemaphoreList
        FUNCDEF FindSemaphore
        FUNCDEF AddSemaphore
        FUNCDEF RemSemaphore
        FUNCDEF SumKickData
        FUNCDEF AddMemList
        FUNCDEF CopyMem
        FUNCDEF CopyMemQuick
        FUNCDEF CacheClearU
        FUNCDEF CacheClearE
        FUNCDEF CacheControl
        FUNCDEF CreateIORequest
        FUNCDEF DeleteIORequest
        FUNCDEF CreateMsgPort
        FUNCDEF DeleteMsgPort
        FUNCDEF ObtainSemaphoreShared
        FUNCDEF AllocVec
        FUNCDEF FreeVec
        FUNCDEF CreatePrivatePool
        FUNCDEF DeletePrivatePool
        FUNCDEF AllocPooled
        FUNCDEF FreePooled
        FUNCDEF AttemptSemaphoreShared
        FUNCDEF ColdReboot
        FUNCDEF StackSwap
        FUNCDEF ChildFree
        FUNCDEF ChildOrphan
        FUNCDEF ChildStatus
        FUNCDEF ChildWait
        FUNCDEF CachePreDMA
        FUNCDEF CachePostDMA
        FUNCDEF ExecReserved01
        FUNCDEF ExecReserved02
        FUNCDEF ExecReserved03
        FUNCDEF ExecReserved04


        SECTION CODE

        xdef _DummyInt
_DummyInt
        dc.l    0,0
        dc.b    2,-127       ;Interrupt
        dc.l    diname
        dc.l    0
        dc.l    dicode
dicode: rts
diname: dc.b  "« Scout's Dummy Int »",0


        xdef _MyCause
_MyCause:
        ;=================================
        ; causes software interrupt
        ;=================================
        ;  > A0: Passed to SoftInt
        ;  > A1: Int-Structure
        ;  < D0: Return Code
        movem.l a0-a6/d1-d7,-(sp)
        move.l  $4.w,a6
        move.l  IS_DATA(a1),a1
        move.l  IS_CODE(a1),a2
        jsr     (a2)
        movem.l (sp)+,a0-a6/d1-d7
        rts


        xdef _NameCopy
_NameCopy:
        ;=================================
        ;copy name (e.g. "euro72.monitor") to buffer, until '.' or null termination
        ;  (also uppercase)
        ;=================================
        ;  > A0: ^Target
        ;  > A1: ^Source
        movem.l a0/a1,-(sp)
copy_loop:
        move.b  (a1)+,d0
        beq     copy_done
        cmp.b   #'.',d0
        beq     copy_done
        cmp.b   #'a',d0                 ;Upper Case
        bcs     copy_ok
        cmp.b   #'z',d0
        bhi     copy_ok
        sub.b   #32,d0
copy_ok:
        move.b  d0,(a0)+
        bra     copy_loop
copy_done:
        move.b  #':',(a0)+
        clr.b   (a0)+
        movem.l (sp)+,a0/a1
        rts



        xdef _GetCACR
_GetCACR:
        ;=================================
        ;return current value of CACR in d0
        ;=================================

        movem.l a5/a6,-(SP)
        moveq.l #0,d0
        move.l  _AbsExecBase,a6
        move.w  AttnFlags(a6),d1
        btst    #AFB_68020,d1
        beq.s   _GetCACR_Exit

        lea     CACR_to_d0(PC),a5
        jsr     _LVOSupervisor(a6)
_GetCACR_Exit:
        movem.l (SP)+,a5/a6
        rts

CACR_to_d0:
        movec.l CACR,D0
        rte


        xdef _GetPCR
_GetPCR:
        ;=================================
        ;return current value of PCR in d0
        ;=================================

        movem.l a5/a6,-(SP)
        moveq.l #0,d0
        move.l  _AbsExecBase,a6
        move.w  AttnFlags(a6),d1
        btst    #AFB_68060,d1
        beq.s   _GetPCR_Exit

        lea     PCR_to_d0(PC),a5
        jsr     _LVOSupervisor(a6)
_GetPCR_Exit:
        movem.l (SP)+,a5/a6
        rts

PCR_to_d0:
        dc.w    $4E7A,$0808             ; movec.l PCR,D0
        rte



        xdef _GetVBR

_GetVBR:
        ;=================================
        ;return current value of VBR in d0
        ;=================================

        movem.l a5/a6,-(SP)
        moveq.l  #0,d0
        move.l  _AbsExecBase,a6
        move.w  AttnFlags(a6),d1
        btst    #AFB_68010,d1
        beq.s    _GetVBR_Exit

        lea        VBR_to_d0(PC),a5
        jsr        _LVOSupervisor(a6)

_GetVBR_Exit:
   movem.l      (SP)+,a5/a6
        rts

VBR_to_d0:
        movec.l VBR,D0
        rte


        xdef _SetVBR

_SetVBR:
        ;=========================
        ;move Value from a0 to VBR
        ;=========================
        movem.l a5/a6,-(SP)
        move.l  _AbsExecBase,a6
        move.w  AttnFlags(a6),d0
        btst    #AFB_68010,d0
        beq.s    _SetVBR_Exit

        move.l  a0,d0                   ; We pass the new VBR in a0, because
                                                ; it is a pointer (and pointers are
                                                 ; put in address registers).
        lea        d0_to_VBR(PC),a5
        jsr        _LVOSupervisor(a6)

_SetVBR_Exit:
        movem.l (SP)+,a5/a6
        rts

d0_to_VBR:
        movec.l D0,VBR
        rte

   xdef _SetPatches
   xref _AbsExecBase

_SetPatches:
        ;=================================
        ;set patch for task switching
        ;=================================
   movem.l  d0-d4/a0-a6,-(sp)
   move.l   _AbsExecBase,a6
   jsr      _LVOForbid(a6)

   move.l   _CodeAddress,a5

   move.w   #-54,d0
   lea      (a5),a0
   exg.l    d0,a0
   move.l   a6,a1
   jsr      _LVOSetFunction(a6)
;   lea      _OldSwitch(pc),a0
;   move.l   d0,(a0)

   move.w   #_LVOAddTask,d0
   lea      _MyAdd-_MySwitch(a5),a0
   exg.l    d0,a0
   move.l   a6,a1
   jsr      _LVOSetFunction(a6)
;   lea      _OldAdd(pc),a0
;   move.l   d0,(a0)

   jsr      _LVOPermit(a6)
   movem.l  (sp)+,d0-d4/a0-a6
   rts


_TaskNumber    EQU 128
_LVOAddTime    EQU -42  
_LVOSubTime    EQU -48  
_LVOCmpTime    EQU -54  
_LVOReadEClock EQU -60  
_LVOGetSysTime EQU -66  


;-----------------------------------------------------------------
; Die hier folgenden Routinen werden vor der Installierung der
;  Patches kopiert!  (bis einschließlich _CodeAddress)
;-----------------------------------------------------------------

        xdef _MySwitch

_MySwitch:
        ;=================================
        ;patch routine for task switching
        ;=================================
   movem.l  d0/a0,-(sp)
   move.b   _SwitchState(pc),d0
   beq      _OldSwitchFunc

swstart:
   movem.l  d1-d3/a1-a4/a6,-(sp)
   lea      _OldTimeVal(pc),a4
   move.l   _MyTVSecs(pc),(a4)+
   move.l   _MyTVMicro(pc),(a4)

   move.l   _AsmTimerBase(pc),a6
   lea      _MyTimeVal(pc),a0
   jsr      _LVOGetSysTime(a6)

   cmp.l    #42,-(a4)
   beq.s    swexit

   lea      _MyTimeVal(pc),a0
   lea      _OldTimeVal(pc),a1
   jsr      _LVOSubTime(a6)

   move.l   _AbsExecBase,a6
   move.l   ThisTask(a6),d0

   move.l   _TaskPtr1(pc),a4
   move.l   #_TaskNumber-1,d3
swloop:
   move.l   (a4),d1
   cmp.l    d0,d1
   beq.s    swfound
   lea      8(a4),a4
   dbf      d3,swloop

   move.l   _TaskPtr1(pc),a4
   move.l   #_TaskNumber-1,d3
swloop2:
   move.l   (a4),d1
   beq.s    swfound     ;Task noch nicht in der Tabelle
   lea      8(a4),a4
   dbf      d3,swloop2
   bra.s    swexit      ;Task konnte nicht mehr in die Tabelle
                        ; aufgenommen werden

swfound:
   move.l   d0,(a4)
   move.l   _MyTVMicro(pc),d0
   add.l    d0,4(a4)
   lea      _TotalMicros1(pc),a0
   add.l    d0,(a0)
   bra.s    swexit
swnext:
   lea      8(a4),a4
   dbf      d3,swloop

swexit:
   lea      _TotalMicros1(pc),a0
   move.l   (a0),d0
   andi.l   #$ff000000,d0
   tst.l    d0
   beq.s    swnoshift
   lsr.l    #8,d0
   lsr.l    #4,d0
   move.l   d0,(a0)

   move.l   _TaskPtr1(pc),a4
   move.l   #_TaskNumber-1,d3
swshift:
   cmp.l    #-2,(a4)
   beq.s    swshiftnext

   move.l   4(a4),d0
   lsr.l    #8,d0
   lsr.l    #4,d0
   move.l   d0,4(a4)
swshiftnext:
   lea      8(a4),a4
   dbf      d3,swshift

swnoshift:
   move.l   _AsmTimerBase(pc),a6
   lea      _MyTimeVal(pc),a0
   jsr      _LVOGetSysTime(a6)
   movem.l  (sp)+,d1-d3/a1-a4/a6

_OldSwitchFunc:
   movem.l  (sp)+,d0/a0
   move.l   _OldSwitch(pc),-(sp)
   rts


_MyTimeVal:
_MyTVSecs:     dc.l  42
_MyTVMicro:    dc.l  0

_OldTimeVal:
_OldTVSecs:    dc.l  0
_OldTVMicro:   dc.l  0


   xdef _SwitchState

_SwitchState:  dc.b  0,0


        xdef _MyAdd

_MyAdd:
        ;=================================
        ;patch routine for task adding
        ;=================================
addstart:
   movem.l  d1/d4/d6/a0/a4/a6,-(sp)
   move.l   a1,d4
   bsr.s    _OldAddFunc

   move.b   _SwitchState(pc),d1
   beq.s    addexit

;   move.l   _AbsExecBase,a6
;   jsr      _LVOForbid(a6)   ;Darf nicht verwendet werden! (Absturz)

   move.l   _TaskPtr1(pc),a4
   move.l   #_TaskNumber-1,d6
addloop:
   move.l   (a4),d1
   bne.s    addnext

addfound:
   move.l   #-2,(a4)    ;added task = -2 
   move.l   d4,4(a4)    ;task address
   bra.s    addexit
addnext:
   lea      8(a4),a4
   dbf      d6,addloop

addexit:
;   jsr      _LVOPermit(a6)
   movem.l  (sp)+,d1/d4/d6/a0/a4/a6
   rts

_OldAddFunc:
   move.l   _OldAdd(pc),-(sp)
   rts


   xdef _SemaphoreName

_SemaphoreName: dc.b  "« Scout's CPU patch »",0


        xdef _ClearTaskData

;-------------------------------------------------------------------
; Die Routine 'ClearTaskData' muß vor der Installierung der Patches
; aufgerufen werden!
;-------------------------------------------------------------------

_ClearTaskData:
   movem.l  d0-d3/a0-a4/a6,-(sp)
   move.b   _TaskPtrState(pc),d0
   bne.s    ctstart

   lea      _TaskPtr1(pc),a4
   jsr      _AllocTaskBuffer

ctstart:
   move.l   _AbsExecBase,a6
   jsr      _LVOForbid(a6)

   lea      _TaskPtr1(pc),a4     ;Pointer austauschen!
   move.l   (a4),d0
   move.l   4(a4),(a4)
   move.l   d0,4(a4)

   lea      _TotalMicros1(pc),a4 ;TotalMicros austauschen!
   move.l   (a4),d0
   move.l   4(a4),(a4)
   move.l   d0,4(a4)

   jsr      _LVOPermit(a6)

   moveq    #0,d0
   move.l   _TaskPtr1(pc),a0
   move.l   #_TaskNumber*2-1,d1
ctloop:
   move.l   d0,(a0)+
   dbf      d1,ctloop

   lea      _TotalMicros1(pc),a0
   move.l   #0,(a0)

ctexit:
   movem.l  (sp)+,d0-d3/a0-a4/a6
   rts


        xdef _GetTaskData

_GetTaskData:
   movem.l  d1-d3/a0,-(sp)
   move.l   d0,d2

   move.l   _TaskPtr2(pc),a0
   move.l   #_TaskNumber-1,d3
   moveq    #0,d0
gtloop:
   move.l   (a0),d1
   cmp.l    d1,d2
   bne.s    gtnext
   move.l   4(a0),d0
;   move.l   d0,d1
;   lsl.l    #3,d1
;   lsl.l    #1,d0
;   add.l    d1,d0
   bra.s    gtexit
gtnext:
   lea      8(a0),a0
   dbf      d3,gtloop
gtexit:
   movem.l  (sp)+,d1-d3/a0
   rts

_TaskPtr1:    dc.l  0     ;Die Reihenfolge dieser drei
_TaskPtr2:    dc.l  0     ; Variablen unbedingt so lassen!
_TaskPtrState: dc.b  0,0


   xdef _TotalMicros1

_TotalMicros1: dc.l  0
_TotalMicros2: dc.l  0


   xdef _OldSwitch

_OldSwitch:    dc.l  0


   xdef _OldAdd

_OldAdd:    dc.l  0


        xdef _GetAddedTask

_GetAddedTask:
   movem.l  d1/d6/a4,-(sp)
   move.l   _TaskPtr2(pc),a4
   move.l   #_TaskNumber-1,d6
   moveq    #0,d0
   move.l   #-2,d1
galoop:
   cmp.l    (a4),d1
   bne.s    ganext

gafound:
   move.l   4(a4),d0
   move.l   #0,(a4)
   move.l   #0,4(a4)
   bra.s    gaexit
ganext:
   lea      8(a4),a4
   dbf      d6,galoop

gaexit:
   movem.l  (sp)+,d1/d6/a4
   rts


   xdef _AsmTimerBase

_AsmTimerBase:    dc.l  0


   xdef _CodeAddress

_CodeAddress:  dc.l  0


;-----------------------------------------------------------------
; Ab hier kommen Dinge, die nicht für die Patches kopiert werden!
;-----------------------------------------------------------------

_AllocTaskBuffer:          ;a4: Adresse von TaskPtr1
   movem.l  d0-d4/a4/a6,-(sp)
   move.l   _AbsExecBase,a6
   move.l   #_TaskNumber*16+8,d0
   move.l   #$10001,d1
   jsr      _LVOAllocMem(a6)
   move.l   d0,d4
   beq.s    atbx

   jsr      _LVOForbid(a6)

   move.l   #_TaskNumber*16+8,d0
   move.l   d4,a1
   jsr      _LVOFreeMem(a6)

   move.l   #_TaskNumber*8+4,d0
   move.l   #$50001,d1
   jsr      _LVOAllocMem(a6)
   move.l   d0,(a4)
   beq.s    atbx

   move.l   #_TaskNumber*8+4,d0
   move.l   #$50001,d1
   jsr      _LVOAllocMem(a6)
   move.l   d0,4(a4)
   beq.s    ftb1
   move.b   #1,8(a4)
atbx:
   jsr      _LVOPermit(a6)
   movem.l  (sp)+,d0-d4/a4/a6
   rts


;_FreeTaskBuffer:
;   movem.l  d0-d4/a4/a6,-(sp)
;   move.l   _AbsExecBase,a6
;;   jsr      _LVOForbid(a6)
;
;   lea      _TaskPtr1(pc),a4
;   move.l   _TaskPtr2(pc),d0
;   beq.s    ftb1
;   move.l   #_TaskNumber*8,a1
;   exg.l    d0,a1
;   jsr      _LVOFreeMem(a6)
;   clr.l    4(a4)
ftb1:
   move.l   _TaskPtr1(pc),d0
   beq.s    ftbx
   move.l   #_TaskNumber*8+4,a1
   exg.l    d0,a1
   jsr      _LVOFreeMem(a6)
   clr.l    (a4)
   move.b   #0,8(a4)
ftbx:
   jsr      _LVOPermit(a6)
   movem.l  (sp)+,d0-d4/a4/a6
   rts


        END
