; Linkable debugging routines

                GET             Asm:s.regs
                GET             Asm:s.xswis
                GET             Asm:s.general
                GET             Asm:s.DebugHdr

                ^               &C9840 :OR: XOS_Bit
XRAMPod_Read    #               1
XRAMPod_Write   #               1
XRAMPod_LEDs    #               1
XRAMPod_Clear   #               1
XRAMPod_WriteS  #               1
XRAMPod_WriteN  #               1
XRAMPod_SaveBuffer #            1

                ^               &CF000 :OR: XOS_Bit
;XTracker_Open   #               1
;XTracker_Close  #               1
;XTracker_SetPos #               1
;XTracker_WriteS #               1
;XTracker_CLS    #               1
;XTracker_Simple #               1

                ^               &40500 :OR: XOS_Bit
XIO_Podule      #               1

; Write registers

ORB             *               4 * 0
ORA             *               4 * 1
DDRB            *               4 * 2
DDRA            *               4 * 3
T1CL            *               4 * 4
T1CH            *               4 * 5
T1LL            *               4 * 6
T1LH            *               4 * 7
T2CL            *               4 * 8
T2CH            *               4 * 9
SR              *               4 * 10
ACR             *               4 * 11
PCR             *               4 * 12
IFR             *               4 * 13
IER             *               4 * 14
ORAns           *               4 * 15

; Read registers

IRA             *               ORA
IRB             *               ORB
IRAns           *               ORAns

                AREA            |Debug$$code|, PIC, CODE

                EXPORT          DebugF, DebugFlags, DebugTrapOn, DebugTrapOff
                EXPORT          DebugBacktrace

; Static data

Flags           &               DebugOn :OR: UseTracker
VIA             &               0               ; 0 means not tried, -1 means not available
BaseTime        &               0               ; Relative to OS_MonotonicTime

; General purpose ASCII output.
;
; R0  ==> Char to output

DBChar          STMFD           sp!, {r0-r1, lr}
                LDR             r1, Flags
                TST             r1, #DebugOn
                LDMEQFD         sp!, {r0-r1, pc}^

                TST             r1, #UseVDU
                BLNE            VDUSend

                TST             r1, #UseTracker
                MOVNE           r0, sp
                SWINE           XTracker_Simple
                LDRNE           r0, [sp]

                TST             r1, #UseBeeb
                BLNE            UserSend

                TST             r1, #UseRAM
                BLNE            RAMSend
                LDMFD           sp!, {r0-r1, pc}^

RAMSendBuf      %               80
RAMSendBP       =               0
                ALIGN

RAMSend         STMFD           sp!, {r0-r2, lr}
                TEQ             r0, #&0c
                BNE             RAMSend1
                SWI             XRAMPod_Clear
                MOV             r1, #0
                STRB            r1, RAMSendBP
                LDMFD           sp!, {r0-r2, pc}^

RAMSend1        LDRB            r1, RAMSendBP
                ADR             r2, RAMSendBuf
                STRB            r0, [r2, r1]
                ADD             r1, r1, #1
                TEQ             r0, #&0a
                TEQNE           r0, #&0d
                TEQNE           r1, #80
                BLEQ            RAMSendFlush
                STRB            r1, RAMSendBP
                LDMFD           sp!, {r0-r2, pc}^

RAMSendFlush    STMFD           sp!, {lr}
                ADR             r0, RAMSendBuf
                SWI             XRAMPod_WriteN
                MOV             r1, #0
                LDMFD           sp!, {pc}^ 

VDUSend         STMFD           sp!, {lr}
                TEQ             r0, #&0a
                TEQNE           r0, #&0d
                SWIEQ           XOS_WriteI + &0a
                SWIEQ           XOS_WriteI + &0d
                SWINE           XOS_WriteC
                LDMFD           sp!, {pc}^

UserSend        STMFD           sp!, {r0-r1, lr}
                LDR             r1, VIA
                CMP             r1, #-1
                LDMEQFD         sp!, {r0-r1, pc}^

; Send character

                STRB            r0, [r1, #ORB]
UserSend1       LDRB            r0, [r1, #IFR]
                TST             r0, #2_00010000
                BEQ             UserSend1
                MOV             r0, #&FF
                STRB            r0, [r1, #IFR]
                LDMFD           sp, {r0-r1, pc}^

BinError
DecError
HexError        ADD             r1, r1, #4

BinString
DecString
HexString       STMFD           sp!, {lr}
String1         LDRB            r0, [r1], #1
                TEQ             r0, #0
                BLNE            OutChar
                BNE             String1
                LDMFD           sp!, {pc}^

BinCharacter
DecCharacter
HexCharacter    MOV             r0, r1

OutChar         STMFD           sp!, {r0-r1, lr}
                AND             r1, r0, #&FF
                CMPS            r1, #&7F
                MOVHS           r0, #"|"
                BLHS            DBChar
                MOVEQ           r0, #"?"
                BLEQ            DBChar
                LDMEQFD         sp!, {r0-r1, pc}^
                MOVHI           r0, #"!"
                BLHI            DBChar
                ANDHI           r1, r1, #&7F
                CMPS            r1, #&20
                MOVLO           r0, #"|"
                BLLO            DBChar
                ADDLO           r0, r1, #&40
                MOVHS           r0, r1
                BL              DBChar
                LDMFD           sp!, {r0-r1, pc}^

NewLine         STMFD           sp!, {r0, lr}
                MOV             r0, #&0A
                BL              DBChar
                MOV             r0, #&0D
                BL              DBChar
                LDMFD           sp!, {r0, pc}^

; DebugF output formatted debugging information.
;
; In order to output accurate information about the contents of R14 DebugF
; must be called like this
;
;               STMFD           sp!, {lr, pc}
;               BL              DebugF
;               =               "Hello"
;               LDR             lr, [sp], #8
;
;    % introduces a conversion
;    \ introduces an escape
;
; The general format of conversions is
;
;    %<register>[<radix specifier>]<conversion>
;
;    register is 0..F, or (5.4.93, AA) R|r0..R|r15 | SP | sp | LR | lr | PC | pc
;
;    radix specifier is
;
;       %       binary
;       #       decimal
;
;    conversion is
;
;       s       string
;       w       word
;       h       halfword
;       b       byte
;       c       character

DebugF          STMFD           sp!, {lr}
                STMFD           sp!, {r0-r15}

; r3 will address inline argument string

                BIC             r3, lr, #&FC000003

; Copy lr and pc from outside invocation

                LDR             lr, [sp, #17 * 4]  ; Get lr
                STR             lr, [sp, #14 * 4]
                LDR             lr, [sp, #18 * 4]  ; and pc
                SUB             lr, lr, #8      ; Adjust
                STR             lr, [sp, #15 * 4]

; Keep a copy of the entry mode stack pointer

                MOV             r4, sp

; Force supervisor mode

                MOV             r5, pc
                TST             r5, #3          ; USR mode?
                SWIEQ           XOS_EnterOS
                ORR             r6, r5, #S0_bit :OR: S1_bit :OR: I_bit
                TEQP            r6, #0
                MOV             r6, r6
                STMFD           sp!, {r8, lr}

; Do it

DebugF1         LDRB            r0, [r3], #1
                TEQ             r0, #"%"
                BNE             DebugF6

; Handle possible conversion

                LDRB            r0, [r3], #1
                CMP             r0, #"0"
                RSBHSS          lr, r0, #"9"
                SUBHS           r1, r0, #"0"
                BHS             DebugF2

                CMP             r0, #"A"
                RSBHSS          lr, r0, #"F"
                SUBHS           r1, r0, #"A"-10
                BHS             DebugF2

                CMP             r0, #"a"
                RSBHSS          lr, r0, #"f"
                SUBHS           r1, r0, #"a"-10
                BHS             DebugF2

; Handle register name without corrupting R0 if not found

                BL              WhichReg
                BCS             DebugF5

; Get the value to print (from the caller's stack)

DebugF2         LDR             r1, [r4, r1, LSL #2]

; Get possible radix indicator

                LDRB            r0, [r3], #1
                MOV             r2, #2          ; == Hex
                TEQ             r0, #0
                BEQ             DebugF7

                TEQ             r0, #"%"        ; Binary
                MOVEQ           r2, #0
                LDREQB          r0, [r3], #1
                BEQ             DebugF3

                TEQNE           r0, #"#"        ; Decimal
                MOVEQ           r2, #1
                LDREQB          r0, [r3], #1

; Value in R1, radix in R2, conversion character in R0

DebugF3         ADR             r6, Converts
DebugF4         LDRB            r7, [r6], #4
                TEQ             r7, #0
                BEQ             DebugF7
                TEQ             r7, r0
                ADDNE           r6, r6, #12
                BNE             DebugF4

                MOV             r8, pc
                AND             r8, r8, #&FC000003
                ORR             r6, r6, r8
                MOV             lr, pc
                ADD             pc, r6, r2, LSL #2
                B               DebugF1

; Check for %t or %z

DebugF5         MOV             r2, r0
                TEQ             r2, #"t"
                TEQNE           r2, #"T"
                TEQNE           r2, #"z"
                TEQNE           r2, #"Z"
                BNE             DebugF7
                SWI             XOS_ReadMonotonicTime
                MOV             r1, r0
                TEQ             r2, #"z"
                TEQNE           r2, #"Z"
                STREQ           r0, BaseTime
                LDRNE           r0, BaseTime
                SUB             r1, r1, r0
                BL              DecWord
                B               DebugF1

DebugF6         TEQ             r0, #"\\"
                BNE             DebugF7

                LDRB            r0, [r3], #1

; Carriage return

                TEQ             r0, #"n"
                BLEQ            NewLine
                BEQ             DebugF1

; BELL

                TEQ             r0, #"b"
                MOVEQ           r0, #&07
                BEQ             DebugF7

; Formfeed (CLS)

                TEQ             r0, #"f"
                MOVEQ           r0, #&0C

DebugF7         TEQ             r0, #0
                BLNE            DBChar
                BNE             DebugF1

                LDMFD           sp!, {r8, lr}
                TEQP            r5, #0
                MOV             r5, r5

                LDR             r2, [sp, #16 * 4]
                AND             r2, r2, #&FC000003
                ADD             r3, r3, #3
                BIC             r3, r3, #3
                ORR             r3, r3, r2
                STR             r3, [sp, #16 * 4]

                LDMFD           sp!, {r0-r12}   ; Don't bother with sp, lr, pc
                ADD             sp, sp, #4 * 3
                LDMFD           sp!, {pc}^

; Match a register name, first character in R0, remainder at R3, don't
; corrupt either unless a match is found

WhichReg        STMFD           sp!, {r0, r2-r3, lr}

                ADR             r2, RegTab

WhichReg1       LDR             r3, [sp, #4 * 2]
                LDR             r0, [sp, #4 * 0]

WhichReg2       LDRB            r1, [r2], #1
                CMP             r1, #" "
                BLO             WhichReg4

                CMP             r0, #"a"
                RSBHSS          lr, r0, #"z"
                SUBHS           r0, r0, #"a"-"A"
                TEQ             r0, r1
                LDREQB          r0, [r3], #1
                BEQ             WhichReg2

WhichReg3       LDRB            r1, [r2], #1
                CMP             r1, #" "
                BHS             WhichReg3
                LDRB            r1, [r2]
                TEQ             r1, #0
                BNE             WhichReg1

                LDMFD           sp!, {r0, r2-r3, lr}
                ORRS            pc, lr, #C_bit

WhichReg4       SUB             r3, r3, #1
                STR             r3, [sp, #4 * 2]
                LDMFD           sp!, {r0, r2-r3, lr}
                BICS            pc, lr, #C_bit


RegTab          =               "R8", 8, "R9", 9, "R10", 10, "R11", 11
                =               "R12", 12, "WS", 12, "R13", 13, "SP", 13
                =               "R14", 14, "LR", 14, "R15", 15, "PC", 15
                =               "R0", 0, "R1", 1, "R2", 2, "R3", 3
                =               "R4", 4, "R5", 5, "R6", 6, "R7", 7
                =               0
                ALIGN

                MACRO
$label          CVRT            $char, $routine
$label          =               "$char", 0, 0, 0
                B               Bin$routine
                B               Dec$routine
                B               Hex$routine
                MEND

Converts        CVRT            "s", String
                CVRT            "e", Error
                CVRT            "c", Character
                CVRT            "w", Word
                CVRT            "h", HalfWord
                CVRT            "b", Byte
                CVRT            "p", PC
                =               0
                ALIGN

                MACRO
$label          Converter       $swiname
$label          STMFD           sp!, {r0-r2, lr}
                SUB             sp, sp, #40
                MOV             r0, r1
                MOV             r1, sp
                MOV             r2, #40
                SWI             $swiname
                BL              OutS
                ADD             sp, sp, #40
                LDMFD           sp!, {r0-r2, pc}^
                MEND

OutS            STMFD           sp!, {r0-r1, lr}
                MOV             r1, r0
OutS1           LDRB            r0, [r1], #1
                TEQ             r0, #0
                BLNE            DBChar
                BNE             OutS1
                LDMFD           sp!, {r0-r1, pc}^

DecHalfWord     MOV             r1, r1, LSL #16
                MOV             r1, r1, ASR #16
                B               DecWord

DecByte         MOV             r1, r1, LSL #24
                MOV             r1, r1, ASR #24

DecWord         Converter       XOS_ConvertInteger4

BinWord         Converter       XOS_ConvertBinary4
BinHalfWord     Converter       XOS_ConvertBinary2
BinByte         Converter       XOS_ConvertBinary1

HexWord         Converter       XOS_ConvertHex8
HexHalfWord     Converter       XOS_ConvertHex4
HexByte         Converter       XOS_ConvertHex2

PModes          =               "USR", 0, "FIQ", 0, "IRQ", 0, "SVC", 0
PFlags          =               "NZCVIF", 0

                ALIGN

BinPC
DecPC
HexPC           STMFD           sp!, {r0-r2, lr}
                MOV             r2, r1
                BIC             r1, r1, #&FC000003
                BL              HexWord

                MOV             r0, #" "
                BL              DBChar

                AND             r1, r2, #3
                ADR             r0, PModes
                ADD             r0, r0, r1, LSL #2
                BL              OutS

                MOV             r0, #" "
                BL              DBChar

                ADR             r1, PFlags

HexPC1          LDRB            r0, [r1], #1
                TEQ             r0, #0
                LDMEQFD         sp!, {r0-r2, pc}^
                TST             r2, #1 :SHL: 31
                ADDEQ           r0, r0, #"a"-"A"
                BL              DBChar
                MOV             r2, r2, LSL #1
                B               HexPC1

; flags := (flags AND R1) EOR R0

DebugFlags      STMFD           sp!, {r0-r4, lr}

                MOV             r3, pc
                TST             r3, #3
                SWIEQ           XOS_EnterOS
                ORR             r4, r3, #S0_bit :OR: S1_bit :OR: I_bit
                TEQP            r4, #0
                MOV             r4, r4
                STMFD           sp!, {lr}

; Set the flags

                LDR             r2, Flags
                AND             r1, r1, r2
                EOR             r0, r0, r1
                STR             r0, Flags

; Check for a VIA

                LDR             r1, VIA
                TEQ             r1, #0
                BNE             DebugFlags1
                SWI             XIO_Podule
                MOVVS           r1, #-1
                ADDVC           r1, r1, #&2000
                STR             r1, VIA

; Initialise VIA for our use

                MOVVC           r0, #&FF
                STRVCB          r0, [r1, #DDRB]
                MOVVC           r0, #&40
                STRVCB          r0, [r1, #IER]
                LDRVCB          r0, [r1, #PCR]
                ANDVC           r0, r0, #&0F
                ORRVC           r0, r0, #&80
                STRVCB          r0, [r1, #PCR]

DebugFlags1     LDMFD           sp!, {lr}
                TEQP            r3, #0
                MOV             r3, r3
                LDMFD           sp!, {r0-r4, pc}^

; Static variable which is the most recent stack pointer known to us. 0 is a
; special case which means we haven't been entered properly, and should not
; attempt a stack backtrace. A backtrace will also not be attempted if the
; current stack pointer is either a) above this value, or b) more than 64k
; below it.

DebugMaxSP      &               0, 0, 0, 0

; Old exception handler values

OldUDI          &               0
OldPrAb         &               0
OldDaAb         &               0
OldAdEx         &               0

DebugTrapOn     STMFD           sp!, {r0-r7, lr}

                ADR             lr, DebugMaxSP
                LDMIA           lr, {r1-r3}
                ADD             r0, sp, #4 * 9
                STMIA           lr, {r0-r3}

                TEQ             r1, #0

; Install handlers

                MOVEQ           r0, #0
                MOVEQ           r1, #0
                ADREQ           r4, BadInst
                ADREQ           r5, PrefetchAbt
                ADREQ           r6, DataAbt
                ADREQ           r7, AddrExcp
                SWIEQ           XOS_SetEnv
                ADREQ           lr, OldUDI
                STMEQIA         lr, {r4-r7}

DebugTrapOnX    LDMFD           sp!, {r0-r7, pc}^

DebugTrapOff    STMFD           sp!, {r0-r7, lr}

                ADR             lr, DebugMaxSP
                LDMIB           lr, {r0-r2}
                MOV             r3, #0
                STMIA           lr, {r0-r3}

                TEQ             r0, #0
                ADREQ           lr, OldUDI
                LDMEQIA         lr, {r4-r7}
                MOVEQ           r0, #0
                MOVEQ           r1, #0
                SWIEQ           XOS_SetEnv

                LDMFD           sp!, {r0-r7, pc}^

; Alternative backtrace entry, used by exception handlers

AltBacktrace    STMFD           sp!, {r0-r9, lr}
                LDR             r5, RegSave + 13 * 4
                B               Backtrace1

; Stack unwinding and profiling stuff

DebugBacktrace  STMFD           sp!, {r0-r9, lr}
                MOV             r5, sp
Backtrace1      MOV             r3, pc

                TST             r3, #3
                SWIEQ           XOS_EnterOS
                ORR             r4, r3, #S0_bit :OR: S1_bit :OR: I_bit
                TEQP            r4, #0
                MOV             r4, r4
                STMFD           sp!, {r3, lr}

; Now work up the stack, from r5 + 4 * 6

                LDR             r4, DebugMaxSP
                TEQ             r4, #0
                BEQ             BacktraceX

                SUBS            lr, r4, r5
                BLO             BacktraceX
                CMP             lr, #64 * 1024
                BHI             BacktraceX

; Now get down to it

                LDR             r3, BackWord
Backtrace2      CMP             r5, r4
                BHI             BacktraceX

                LDR             r0, [r5], #4
                TEQ             r0, r3
                BNE             Backtrace2

; Next word is pointer to function name

                LDR             r0, [r5, #4 * 0]
                TST             r0, #&FC000003
                BNE             Backtrace2
                ADD             r1, r0, #32
                SWI             XOS_ValidateAddress
                BCS             Backtrace2

Backtrace3      CMP             r0, r1
                BHS             Backtrace2
                LDRB            r2, [r0], #1
                CMP             r2, #" "
                RSBHSS          lr, r2, #126
                BHS             Backtrace3
                TEQ             r2, #0
                BNE             Backtrace2

; Things are looking OK, so check for STMFD sp!, {...} instruction

                LDR             r6, [r5, #4 * 1]
                LDR             r1, STMFDWord
                LDR             r2, STMFDMask
                AND             r2, r2, r6
                TEQ             r2, r1
                BNE             Backtrace2

; Got bit mask of stacked registers in R6 now, so do a bit of output

                LDR             r1, [r5, #4 * 0]
                BL              BinString       ; Function name

; Now output a dump of the registers

                ADD             r5, r5, #4 * 2  ; Start of stacked registers
                BL              ShowRegs
                ADD             r5, r5, #4 * 16
                B               Backtrace2

BacktraceX      LDMFD           sp!, {r3, lr}
                TEQP            r3, #0
                MOV             r3, r3
                LDMFD           sp!, {r0-r9, pc}^

; Dump a set of registers, stored at R5. The lower 16 bits in R6 represent
; registers 0 to 15 respectively and control whether the name is capitalized
; (as in 'R') or not. If R6 is a STM instruction the register dump will
; reflect the registers which it stacked.

ShowRegs        STMFD           sp!, {r0-r8, lr}

                ADR             r7, RegNames
                MOV             r8, #0          ; Reg. no

ShowRegs1       MOV             r1, #4          ; ccount
ShowRegs2       LDRB            r0, [r7], #1
                TEQ             r0, #"\\"
                BLEQ            NewLine
                MOVEQ           r0, #" "
                CMP             r0, #"A"
                RSBHSS          lr, r0, #"Z"
                BLO             ShowRegs3
                TST             r6, #1
                ADDEQ           r0, r0, #"a"-"A"
ShowRegs3       BL              DBChar
                SUBS            r1, r1, #1
                BNE             ShowRegs2

                ADR             r1, Equals
                BL              BinString
                LDR             r1, [r5, r8, LSL #2]
                CMP             r8, #14
                BLLO            HexWord
                BLHS            HexPC
                MOV             r6, r6, LSR #1
                ADD             r8, r8, #1
                CMP             r8, #16
                BLO             ShowRegs1

                BL              NewLine
                BL              NewLine

                LDMFD           sp!, {r0-r8, pc}^

BackWord        =               "BACK"
STMFDWord       &               &092D0000
STMFDMask       &               &0FFF0000

Equals          =               " = ", 0

RegNames        =               "\\ R0  R1  R2  R3"
                =               "\\ R4  R5  R6  R7"
                =               "\\ R8  R9 R10 R11"
                =               "\\R12  SP\\ LR  PC"

InitSP2         &               &01F0136C
InitSP          &               &01C02000

; Exception handlers and workspace

SaveLR          &               0
RegSave         %               16 * 4

BadInst         TEQP            pc, #I_bit :OR: F_bit :OR: S0_bit :OR: S1_bit
                STR             lr, SaveLR
                ADR             lr, RegSave
                STMIA           lr!, {r0-r7}
                MOV             r0, lr
                BL              Report

                &               &80000000
                =               "Undefined instruction", 0
                ALIGN

PrefetchAbt     TEQP            pc, #I_bit :OR: F_bit :OR: S0_bit :OR: S1_bit
                STR             lr, SaveLR
                ADR             lr, RegSave
                STMIA           lr!, {r0-r7}
                MOV             r0, lr
                BL              Report

                &               &80000001
                =               "Abort on instruction fetch", 0
                ALIGN

DataAbt         TEQP            pc, #I_bit :OR: F_bit :OR: S0_bit :OR: S1_bit
                STR             lr, SaveLR
                ADR             lr, RegSave
                STMIA           lr!, {r0-r7}
                MOV             r0, lr
                BL              Report

                &               &80000002
                =               "Abort on data transfer", 0
                ALIGN

; Save lr (the exception address) at 0

AddrExcp        TEQP            pc, #I_bit :OR: F_bit :OR: S0_bit :OR: S1_bit
                STR             lr, SaveLR
                ADR             lr, RegSave
                STMIA           lr!, {r0-r7}
                MOV             r0, lr
                BL              Report

                &               &80000003
                =               "Address exception", 0
                ALIGN

; Report an exception. On entry, location 0 holds a copy of lr pointing to
; the faulted instruction.
;
; R0  ==> Register save area address for R8-PC (R0-R7 are already saved)
; LR  ==> Return address points to a string describing the problem, (e.g.
;         Address exception)

Report          LDR             r1, SaveLR      ; Get exception LR
                STR             r1, [r0, #4 * 7]  ; Save it as the PC
                TST             r1, #3          ; Was it a non-USR mode?
                STMEQIA         r0, {r8-lr}^    ; If not, save the USR mode registers
                BEQ             Report1

; Exception happened in a non-USR mode

                TST             r1, #1
                TSTNE           r1, #2
                STMNEIA         r0, {r8-lr}
                BNE             Report1

; Exception was in either IRQ or FIQ mode, so go into that mode, save the
; registers then return to SVC mode

                TEQP            r1, #0
                NOP

                STMIA           r0, {r8-lr}
                TEQP            pc, #S0_bit :OR: S1_bit

; Do some funny stuff with IOC

                AND             r1, r1, #3
                EORS            r2, r1, #1
                MOVEQ           r3, #&03200000
                STREQB          r2, [r3, #56]

Report1         LDR             sp, InitSP      ; Need a stack, this one will do

                ADR             r1, RegSave + 10 * 4
                LDMIA           r1, {r10-r12}
                STMFD           sp!, {r10-r12}

                LDR             r1, RegSave + 15 * 4  ; PC
                STMFD           sp!, {r1}

; Address of message

                BIC             r10, lr, #&FC000003

; Put VDU back to screen

                MOV             r0, #&3C
                MOV             r1, #0
                MOV             r2, #0
                MOV             r1, #1
                SWI             XOS_SpriteOp

;                MOV             r0, #DebugOn :OR: UseVDU
;                MOV             r1, #0
;                BL              DebugFlags
;                SWI             XOS_WriteI + 22
;                SWI             XOS_WriteI + 31
;                SWI             XOS_WriteI + "N" - 64

                ADD             r1, r10, #4
                BL              BinString
                ADR             r1, AtStr
                BL              BinString
                LDR             r1, RegSave + 15 * 4
                BL              HexPC

                ADR             r5, RegSave
                MOV             r6, #0
                BL              ShowRegs
                BL              AltBacktrace

; This is just borrowed from the OS; I don't know what is at location 264

                TEQP            pc, #&08000002
                MOV             r1, #0
                STR             r1, [r1, #264]
                LDR             sp, InitSP2
                MOV             r0, r10
                SWI             XOS_GenerateError :AND: (:NOT: XOS_Bit)

AtStr           =               " at &", 0
                ALIGN

                END
