; > ReportMacro
; Reporter Macros for ObjAsm (with thanks to Fred Graute).
; Version:    0.01 (01 Jun 2013) Initial version

;---------------------------------------------------------------------------
; This Macro is used to call static Reporting code at debug points.
        MACRO
$label  FNReport   $msg,$flag
;        [ DEBUG
        LCLS    ccstr                 ; for <cc>
        LCLS    cond                  ; for condition code
        LCLS    strs                  ; for msg string to be used
strs    SETS    "$msg"                ; default string
ccstr   SETS    "$msg" :LEFT: 4       ; get any <cc>
        [ ((ccstr :LEFT: 1) = "<") :LAND: ((ccstr :RIGHT: 1) = ">")
cond    SETS    :UPPERCASE:ccstr :RIGHT: 3 :LEFT: 2 ; MID$(ccstr,2,2)
strs    SETS    "$msg":RIGHT: (:LEN: "$msg"-4)      ; MID$($msg,5)
        ]
        STM$cond.FD   R13,{R12,R13,LR,PC}  ; no r13 writeback to avoid probs
        BL$cond       FNReportGen     ; output format with substitution
        B       %FT01                 ; branch over flags and format str
        DCD     $flag                 ; flags for Report_Registers SWI
        DCB     "$strs"               ; format string (r14 + 8)
        DCB     0
        ALIGN
01
;        ]
        MEND

;---------------------------------------------------------------------------
; This macro generates the static code called by the FNReport Macro
; It should be used once at the end of a program.
        MACRO
$label  FNReportGen
FNReportGen
        ;------ r14 is return address, r14 + 4 points to string to printf
        ;       old r12,r13,r14 are on stack, plus 'pc' above it

        SUB     R13,R13,#4*4          ; adjust r13 for caller's stmfd
        STMFD   R13!,{R0-R12}         ; keep the r0-r12 register values safe

        MRS     R9,CPSR               ; keep 32-bit psr safe (nop on 26-bit)
        MOV     R8,R14                ; return address (+psr if 26-bit)
        TEQ     R0,R0                 ; ready Z-flag for test below
        TEQ     PC,PC                 ; EQ if 32-bit, NE if 26-bit
        BICNE   R8,R14,#&FC000003     ; if 26-bit, remove flags from ptr
        ANDNE   R9,R14,#&FC000003     ; if 26-bit, isolate flags from ptr

        ;------- We need to construct, on the stack, the register save area
        ;        required by Report_Registers.
        ;        This needs to look as follows; r0-r15,psr.
        ;        Right now we have r0-r12,r12-r15 (r12 is pushed twice so
        ;        we have room for the psr).
        ;        We need to move r13-r15 down one word and add the psr at
        ;        the end.

        ADD     R0,R13,#14*4          ; -> r13,lr,pc
        ADD     R1,R13,#13*4          ; -> r12,r13,lr,pc
        LDMIA   R0,{R2-R4}            ; read r13,lr,pc
        STMIA   R1,{R2-R4,R9}         ; write r13,lr,pc,psr

        ;------ Okay we have our register save area we can now call
        ;       Report_Registers

        ADD     R0,R8,#8              ; ptr -> string to printf
        MOV     R1,R13                ; ptr -> register save area
        LDR     R2,[R8,#4]            ; flags, b16 set => no pc/psr line
        SWI     XReport_Registers     ; get Reporter to parse & output string

        ;------ We need to restore the original psr content

        TEQ     R0,R0                 ; ready Z-flag for test below
        TEQ     PC,PC                 ; EQ if 32-bit, NE if 26-bit
        TEQNEP  R9,#&0                ; if 26-bit, restore 26-bit psr
        MSR     CPSR_f,R9             ; restore 32-bit psr (nop on 26-bit)

        ;------ Now restore the registers and return to caller

        STR     R8,[R13,#16*4]        ; overwrite psr with return address
        LDMFD   R13!,{R0-R12}         ; restore the r0-r12 register values
        LDR     R14,[R13,#4]          ; restore the r14 register value
        ADD     R13,R13,#12           ; skip over stacked r13,lr,pc
        LDR     pc,[r13],#4           ; go back to Return Address

        MEND

;---------------------------------------------------------------------------

        END
