; This source code in this file is licensed to You by Castle Technology
; Limited ("Castle") and its licensors on contractual terms and conditions
; ("Licence") which entitle you freely to modify and/or to distribute this
; source code subject to Your compliance with the terms of the Licence.
; 
; This source code has been made available to You without any warranties
; whatsoever. Consequently, Your use, modification and distribution of this
; source code is entirely at Your own risk and neither Castle, its licensors
; nor any other person who has contributed to this source code shall be
; liable to You for any loss or damage which You may suffer as a result of
; Your use, modification or distribution of this source code.
; 
; Full details of Your rights and obligations are set out in the Licence.
; You should have received a copy of the Licence with this source code file.
; If You have not received a copy, the text of the Licence is available
; online at www.castle-technology.co.uk/riscosbaselicence.htm
; 
        SUBT    Macros for Econet debugging

OldOpt  SETA    {OPT}
        OPT     OptNoList+OptNoP1List

; ***********************************
; ***    C h a n g e   L i s t    ***
; ***********************************
;
; Date       Name          Description
; ----       ----          -----------
; 01-Jul-93  BCockburn     Created from Hdr:EcoMacros
; 29-Mar-94  BCockburn     Moved all Econet specific macros in from Hdr:EcoMacros

ARM_config_cp	CP 15	; coprocessor number for configuration control
ARM_ID_reg	CN 0	; processor ID
ARM8A_cache_reg	CN 7	; cache operations, ARM 8 or StrongARM
C0		CN 0
C5		CN 5
C10		CN 10

        MACRO
        FIQStr  $s
        STR     r4, [ r0, -r0 ]                         ; Save in a known place
        LDR     r4, =DebugTraceRegs                     ; Work area
        STMIA   r4!, { r0-r3 }
        LDMIA   r4!, { r1, r2 }
        STMIA   r4!, { r5 }
        MOV     r5, psr                                 ; Preserve mode
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Set FIQ flag and goto SVC mode
        CMP     r2, #50
        BLT     %FT30
        ADR     r3, %FT20
10
        LDRB    r0, [ r3 ], #1
        STRB    r0, [ r1, #0 ]
        TEQ     r0, #0
        SUBNE   r2, r2, #1
        ADDNE   r1, r1, #1
        BNE     %BT10
        B       %FT30
20
        DCB     $s, 0
        ALIGN
30
        TEQP    r5, #0                                  ; Return to Correct mode
        LDMDB   r4!, { r5 }
        STMDB   r4!, { r1, r2 }
        LDMDB   r4!, { r0-r3 }
        LDR     r4, [ r0, -r0 ]
        MEND

        MACRO
        FIQReg  $r
        STR     r4, [ r0, -r0 ]                         ; Save in a known place
        LDR     r4, =DebugTraceRegs                     ; Work area
        STMIA   r4!, { r0-r3 }
        MOV     r3, psr                                 ; Preserve mode
        [       $r = r4
        LDR     r0, [ r0, -r0 ]
        |
        MOV     r0, $r
        ]
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Set FIQ flag and goto SVC mode
        LDMIA   r4!, { r1, r2 }
        STMIA   r4!, { r14 }                            ; Preserve SVC r14
        SWI     XOS_ConvertHex8
        LDMDB   r4!, { r14 }
        STMDB   r4!, { r1, r2 }
        TEQP    r3, #0                                  ; Return to Correct mode
        LDMDB   r4!, { r0-r3 }
        LDR     r4, [ r0, -r0 ]
        MEND

        MACRO
        Str     $s
        Push    "r0-r4"
        MOV     r4, psr                                 ; Preserve mode
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Set FIQ flag and goto SVC mode
        LDR     r0, =DebugTraceAddr                     ; Work area
        LDMIA   r0, { r1, r2 }
        CMP     r2, #50
        BLT     %FT30
        ADR     r3, %FT20
10
        LDRB    r0, [ r3 ], #1
        STRB    r0, [ r1, #0 ]
        TEQ     r0, #0
        SUBNE   r2, r2, #1
        ADDNE   r1, r1, #1
        BNE     %BT10
        B       %FT30
20
        DCB     $s, 0
        ALIGN
30
        LDR     r0, =DebugTraceAddr                     ; Work area
        STMIA   r0, { r1, r2 }
        TEQP    r4, #0                                  ; Return to Correct mode
        Pull    "r0-r4"
        MEND

        MACRO
        Reg     $r
        Push    "r0-r4"
        MOV     r4, psr                                 ; Preserve mode
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Set FIQ flag and goto SVC mode
        LDR     r0, =DebugTraceAddr                     ; Work area
        LDMIA   r0, { r1, r2 }
        CMP     r2, #50
        BLT     %FT30
        [       $r = r0
        LDR     r0, [ sp, #0 ]
        |
        [       $r = r1
        LDR     r0, [ sp, #4 ]
        |
        [       $r = r2
        LDR     r0, [ sp, #8 ]
        |
        [       $r = r3
        LDR     r0, [ sp, #12 ]
        |
        [       $r = r4
        LDR     r0, [ sp, #16 ]
        |
        MOV     r0, $r
        ]
        ]
        ]
        ]
        ]
        Push    "lr"
        SWI     XOS_ConvertHex8
        Pull    "lr"
30
        LDR     r0, =DebugTraceAddr                     ; Work area
        STMIA   r0, { r1, r2 }
        TEQP    r4, #0                                  ; Return to Correct mode
        Pull    "r0-r4"
        MEND

        MACRO
        DebugStats $Reg,$Id
        STR     r0, [ r0, -r0 ]
        LDR     r0, =DebugRegs
        STMIA   r0, { r1, r2, r3 }
        LDR     r1, =DebugPtr
        LDR     r2, [ r1, #0 ]
        LDR     r3, [ r1, #DebugLimit-DebugPtr ]
        CMP     r3, r2
        ORR     r3, $Reg, #($Id :SHL: 16)
        STMLTDB r2!, { r3 }
        STRLT   r2, [ r1, #0 ]
        LDMIA   r0, { r1, r2, r3 }
        LDR     r0, [ r0, -r0 ]
        MEND

        MACRO
        Load    $reg,$identifier,$c
        ; If the global variable with the same name as "$identifier"
        ; is null then it is assumed that a variable exists and can be
        ; LD'd from, otherwise the global variable is assumed to contain
        ; the text of the value that can be LDR ='d.
        [       $identifier = ""
        LD      $reg, $identifier.Var, $c
        |
        LDR$c   $reg, =$$$identifier
        ]
        MEND

        MACRO
        Stor    $reg,$identifier,$cond
        ; If the global variable with the same name as the identifier
        ; is null then it is assumed that a variable exists and can be
        ; ST'd to, otherwise an error is raised
        [       $identifier = ""
        ST      $reg, $identifier.Var, $cond
        |
        !       0, "Storing to constant value"
        ]
        MEND

        MACRO
$a      SetFIQ  $dest,$rega,$regb,$style,$init,$regc
        ; $dest is the label of the code to jump to
        ; $rega is the register to use for the pointer
        ; $regb is the register to use for the instruction
        ; $regc is an extra register required to preserve the mode during initialisation
        [       "$rega" = "" :LOR: "$regb" = "" :LOR: ("$init" = "Init" :LAND: "$regc" = "")
        !       1,"Syntax is: SetFIQ dest, rega, regb [, long [, init, regc]]"
        ]
        [       "$init" = "Init"
$a
        [       {TRUE} ;                                ; Cope with 32bit CPUs
        mrs     AL, $regc, CPSR_all                     ; Switch to _32 mode with IRQs and FIQs off
        ORR     $regb, $regc, #I32_bit :OR: F32_bit     ; Has to be done in two stages because RISC OS
        msr     AL, CPSR_all, $regb                     ; can't return to a 32bit mode and interrupts
        ORR     $regb, $regb, #2_10000                  ; can occur after the MSR but before the following
        msr     AL, CPSR_all, $regb                     ; instruction.
        ]
        ADR     $rega, FIQVector
        LDR     $regb, =&E51FF004                       ; LDR pc, .+4 = LDR pc, [ pc, #-4 ]
        STR     $regb, [ $rega ], #4
        [       {TRUE} ;                                ; Cope with 32bit CPUs
        ; And switch back
        msr     AL, CPSR_all, $regc
        ]
	[	StrongARM
	; Local version of OS_SynchroniseCodeAreas, because it's far too much hassle
	; calling a SWI in these circumstances
	MRC	ARM_config_cp, 0, $regc, ARM_ID_reg, C0, 0
	AND	$regc,$regc,#&F000
	TEQS	$regc,#&A000
	BNE	%FT01					; not StrongARM
	; We want to clean the (32-byte) data cache line containing
	; the FIQVector word.
	ADR	$regc, FIQVector
	MCR	ARM_config_cp, 0, $regc, ARM8A_cache_reg, C10, 1  ; clean DC entry
	MCR	ARM_config_cp, 0, $regc, ARM8A_cache_reg, C10, 4  ; drain WB
	MCR	ARM_config_cp, 0, $regc, ARM8A_cache_reg, C5, 0   ; flush IC
	; Normally 4 NOPs could be required to make sure the
	; modified instruction wasn't in the pipeline. Fortunately
	; we know that the FIQ vector can't be called within 3
	; instructions of here (and if an FIQ were to go off, the
	; pipeline would be flushed anyway).
1
  [ ARM810support
	SUB	PC,PC,#4	; flushes branch predict on ARM810 (local equivalent of OS_SynchroniseCodeAreas)
  ]
	]
        |
$a      ADR     $rega, FIQVector + 4
        ]
        [       "$style" = "Long"
        ADRL    $regb, $dest
        |
        ADR     $regb, $dest
        ]
        STR     $regb, [ $rega, #0 ]
        MEND

        MACRO
$a      SetJump $dest,$rega,$regb,$style
        ; $dest is the label of the code to jump to
        ; $rega is the register to use for the instruction
        ; $regb is the register to use for the pointer
        [       "$rega" = "" :LOR: "$regb" = ""
        !       1,"Syntax is: SetJump dest, temp, address [, long]"
        ]
        [       "$style" = "Long"
$a      ADRL    $rega, $dest
        |
$a      ADR     $rega, $dest
        ]
        ADR     $regb, NextJump
        STR     $rega, [ $regb, #0 ]
        MEND

        MACRO
$a      PutFIQ  $rega,$regb,$init
        ; $rega is the register with the instruction in it
        ; $regb is the register to use for the pointer
        [       "$rega" = "" :LOR: "$regb" = ""
        !       1,"Syntax is: PutFIQ instruction, address [, init]"
        ]
        [       "$init" = "Init"
	[	StrongARM
	!	1,"PutFIQ Init won't work on StrongARM!"
	]
$a      ADR     $rega, FIQVector
        LDR     $regb, =&E51FF004                       ; LDR pc, .+4 = LDR pc, [ pc, #-4 ]
        STR     $regb, [ $rega ], #4
        |
$a      ADR     $rega, FIQVector + 4
        ]
        ADR     $regb, NextJump
        LDR     $regb, [ $regb, #0 ]
        STR     $regb, [ $rega, #0 ]
        MEND

        MACRO
$a      RTFIQ
$a      SUBS    pc, lr, #4
        MEND

        MACRO
$a      WaitForFIQ  $rega,$regb
        ; rega is the register to use for the instruction
        ; regb is the register to use for the pointer
        [       "$rega" = "" :LOR: "$regb" = ""
        !       1,"Syntax is: WaitForFIQ rega, regb"
        ]
$a      ADR     $rega, FIQVector + 4
        ADR     $regb, %FT10
        STR     $regb, [ $rega, #0 ]
        SUBS    pc, lr, #4
        ALIGN   $Alignment
10
        MEND

        MACRO
        MakeNetError    $cond
        [               Debug
        MOV$cond        r8, pc                          ; Goes into Offset_NetError
        ]
        B$cond          NetError
        MEND

        MACRO
        MakeNetError1   $cond
        [               Debug
        MOV$cond        r8, pc                          ; Goes into Offset_NetError
        ]
        B$cond          NetErrorWithSReg1
        MEND

        MACRO
        MakeNetError2   $cond
        [               Debug
        MOV$cond        r8, pc                          ; Goes into Offset_NetError
        ]
        B$cond          NetErrorWithSReg2
        MEND

        MACRO
        MakeReceptionError $cond
        [               Debug
        MOV$cond        r8, pc                          ; Goes into Offset_NetError
        ]
        B$cond          ReceptionError
        MEND

        MACRO
        MakeReceptionError2 $cond
        [               Debug
        MOV$cond        r8, pc                          ; Goes into Offset_NetError
        ]
        B$cond          ReceptionErrorWithSReg2
        MEND

        MACRO
        TurnAroundDelay $reg1,$reg2,$reg3,$delay
        ADR     r10, IOC
        [               "$delay" = ""                   ; Default case is 40 microseconds
        MOV     $reg1, #80
        |                                               ; Delay value in microseconds
        MOV     $reg1, #(($delay)*2)
        ]
        STRB    $reg1, [ r10, #Timer0LR ]               ; Copies counter to output latch
        LDRB    $reg2, [ r10, #Timer0CL ]               ; Reg2 = low output latch
10                                                      ; loop waiting for 2MHz counter to change
        STRB    $reg1, [ r10, #Timer0LR ]               ; Copies counter to output latch
        LDRB    $reg3, [ r10, #Timer0CL ]               ; Reg3 = low output latch
        TEQS    $reg2, $reg3                            ; Has counter changed?
        BEQ     %BT10                                   ; Else wait for it to change
        ; counter has changed, decrement our count of ticks
        MOV     $reg2, $reg3                            ; Update copy of counter
        SUBS    $reg1, $reg1, #1                        ; Decrement ticks
        BNE     %BT10                                   ; Then continue if not done
; delay has expired
        [       PoduleCapable
        LDR     r10, HardwareAddress
        |
        LDR     r10, =EconetController
        ]
        MEND

        MACRO
        Err     $name
        ALIGN
Error$name
        DCD     ErrorNumber_$name
        DCB     ErrorString_$name
        DCB     0
        ALIGN
        MEND

        OPT OldOpt

        END