; > ReportMacro
; Reporter Macros for ObjAsm (with thanks to Fred Graute).
; Version:    0.01 (01 Jun 2013) Initial version
; Version:    0.02 (07 Feb 2017) Changed so ARMv8 friendly (Fred Graute)
;                                Avoids STM r13 & r15 in register list.

;---------------------------------------------------------------------------
; 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!,{R0,R1,R2,R3}; make room for sp,lr,pc,psr         ~v0.02
        STR$cond      R14,[R13,#4]    ; write caller's r14 over r1           +v0.02
        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 BL return address -> Return address entry **offset**    ~v0.02
        ;     r14 + 4 -> flags + msg offset for SWI Report_Registers         ~v0.02
        ;     On stack we have r0,r14,r2,r3 (r14 is caller's r14).           ~v0.02
        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 be: r0-r15,psr.
        ;     Right now we have r0-r12,r0,r14,r2,r3 (r14 is caller's r14).   ~v0.02
        ;     We need to replace r0 with r13, r2 with pc and r3 with psr.    ~v0.02
        ;     (Note FG; PC could be derived from r14+4 (return branch) so    ~v0.02
        ;               it shows the location of the original instruction)   ~v0.02
        SUB     R0,R13,#17*4          ; correct for registers we pushed      +v0.02
        STR     R0,[R13,#13*4]        ; write value of r13 over stacked r0   ~v0.02
        STR     PC,[R13,#15*4]        ; write value of r15 over stacked r2   ~v0.02
        STR     R9,[R13,#16*4]        ; write value of psr over stacked r3   ~v0.02

        ;------ 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
