;+ -to <AAsm$Save>.ExtBas.Debugger -module -quit

	GBLS	VER
VER	SETS	"2.07 (29 May 2000)  Darren Salt"

NumBrkPts	* 16

R0	RN	0
R1	RN	1
R2	RN	2
R3	RN	3
R4	RN	4
R5	RN	5
R6	RN	6
R7	RN	7
R8	RN	8
R9	RN	9
R10	RN	10
R11	RN	11
R12	RN	12
R13	RN	13
R14	RN	14
PC	RN	15

CP15	CP	15
C0	CN	0

	MACRO
$b	Z	$a
$b	=	"$a",0
	MEND

	MACRO
$b	ZA	$a
$b	=	"$a",0
	ALIGN
	MEND

	MACRO
$b	ERR	$n,$m
$b	&	$n
	=	"$m",0
	ALIGN
	MEND

	MACRO
$b	PRINT	$a
$b	SWI	XOS_WriteS
	=	"$a",0
	ALIGN
	MEND

	MACRO
$b	VDU	$a,$c
$b	SWI$c	XOS_WriteI+"$a"
	MEND


XOS_WriteC		* &20000
XOS_WriteS		* &20001
XOS_Write0		* &20002
XOS_NewLine		* &20003
XOS_CLI			* &20005
XOS_Byte		* &20006
XOS_ReadLine		* &2000E
XOS_GetEnv		* &20010
XOS_Exit		* &20011
XOS_EnterOS		* &20016
XOS_Module		* &2001E
XOS_Claim		* &2001F
XOS_Release		* &20020
XOS_ReadUnsigned	* &20021
XOS_BinaryToDecimal	* &20028
XOS_ReadEscapeState	* &2002C
XOS_SWINumberToString	* &20038
XOS_ValidateAddress	* &2003A
XOS_ChangeEnvironment	* &20040
XOS_WriteN		* &20046
XOS_ReadArgs		* &20049
XOS_ReadMemMapInfo	* &20051
XOS_Confirm		* &20059
XOS_ConvertHex2		* &200D1
XOS_ConvertHex4		* &200D2
XOS_ConvertHex6		* &200D3
XOS_ConvertHex8		* &200D4
XOS_ConvertInteger1	* &200D9
XOS_ConvertInteger4	* &200DC
XOS_WriteI		* &20100
XDebugger_Disassemble	* &60380

;	Token	mask, test, token string
;	For instruction templates
	MACRO
$b	Token	$m,$v,$t
$b	& &$m, &$v
	= (:LEN:"$t"+13) :AND: -4
	= "$t", 0
	ALIGN
	MEND

	GBLA	flag__b

	MACRO
$b	FlagBit $bit
 [ "$bit" > ""
flag__b	SETA	$bit
 ]
$b	*	1:SHL:flag__b
flag__b	SETA	flag__b + 1
	MEND

		^	0,R12	; Workspace
prev		#	8
flags		#	4
adrlx		#	4
adrlx_f		#	4
oldxc		#	4
trampoline	#	NumBrkPts*8
tmplncommon	#	20
tmpln_flags	#	4
tmpln_other	#	8
brkpts		#	NumBrkPts*8
buffer		#	256
buffer2		#	256
cpu_default	#	4
xcregs		#	64
size		#	0

buffptr	*	:INDEX:buffer

flag_stack	FlagBit 0
flag_apcs	FlagBit
flag_lfmstack	FlagBit
flag_lfs	FlagBit
flag_quoteswis	FlagBit
flag_usedcd	FlagBit
flag_usevdu	FlagBit
flag_andeqasdcd	FlagBit
flag_useadrl	FlagBit
flag_useadrw	FlagBit
flag_longmul_l	FlagBit
flag_useldrl	FlagBit
flag_usenop	FlagBit
flag_oldpsr	FlagBit
flag_wide	FlagBit
flag_hslo	FlagBit
flag_shift	FlagBit
flag_lower_r	FlagBit

flag_zap	* 1:SHL:23

; Now some actual code...

start	& 0
	& :INDEX:init
	& :INDEX:exit
	& :INDEX:service
	& :INDEX:title
	& :INDEX:help
	& :INDEX:commands
	& &40380
	& :INDEX:swihandler
	& :INDEX:swilist
	& 0
	& 0 ; messages

title	= "Debugger",0

help	= "Debugger Plus",9,"$VER",0

swilist	= "Debugger",0
	= "Disassemble",0
	= "DisassembleThumb",0
	= "Flags",0
	= "CPU",0
	= "DisassemblePlus",0
	= 0

DisassemblerFlags_help
 = "*",27,0," allows you",27,"(set various MemoryI",27,16
 = "Debugger_Disassemble features. Available switches:",13
 = 9,"-FDwithR13",9,"use FD with R13, eg. STMDB R13 -> STMFD R13",13
 = 9,"-APCS",9,9,"use APCS-R register set",13
 = 9,"-LFMstack",9,"use stack nota",27,9," with LFM & SFM where possible"
 = 13
 = 9,"-LFS",9,9,"use LFS",27,16,"SFS in preference",27,"(LFM & SFM",13
 = 9,"-QuoteSWIs",9,"put quotes around SWI ",27,11,"s",13
 = 9,"-UseDCD",9,9,"use DCD instead of 'Undefined instruc",27,9,"'",13
 = 9,"-UseVDU",9,9,"use VDU x instead of SWI OS_WriteI+x",13
 = 9,"-ANDEQasDCD",9,"use DCD instead of 'ANDEQ'",27,16,"similar",13
 = 9,"-UseADRL",9,"use ADRL (ADRX) instead of ADR + ADD/SUB (+ ADD/SUB)",13
 = 9,"-UseADRW",9,"use ADRW, LDRW, STRW for R12m & [R12,#m]",13
 = 9,"-LongMul",9,"append L",27,"(UMUL, SMUL, UMLA, SMLA",13
 = 9,"-UseLDRL",9,"use LDRL instead of ADR/ADD/SUB + LDR",13
 = 9,"-UseNOP",9,9,"use NOP for MOV R0,R0",27,16,"BRK for DCD &x6000010",13
 = 9,"-OldPSR",9,9,"use old CPSR/SPSR ",27,11,"s",13
 = 9,"-Wide",9,9,"disassemble for wide display",13
 = 9,"-HSLO",9,9,"use HS",27,16,"LO instead of CS",27,16,"CC",13
 = 9,"-Shift",9,9,"append comments of",27,2,"form x<<y",13
 = 9,"-Lower",9,9,"use lower case for all register names",13
 = "Each switch takes a ",27,"$: ""0"" or ""N"" (off), or ""1"" or ""Y"" "
 = "(on). Omit",27,2,"switch",27,"(leave it unchanged.",13
 = "Use *",27,0," on its own",27,"(display",27,2,27,5," state.",13
DisassemblerFlags_syn
 = 27,1," [<switches>]",0

Debugger_help
 = "The Debugger Plus module",27,")a complete replacement for",27,2
 = "standard Debugger module, providing an extended disassembler, using",27,2
 = "same SWI,",27,16,"improved debugging commands.",0

BreakClr_help
	= "*",27,0," removes",27,2,"breakpoint at",27,2,"specified address. "
	= "If no address",27,")given then",27,"&breakpoints are removed.",13
BreakClr_syn
	= 27,30,"<addr|reg>]",0

BreakList_help
	= "*",27,0," lists",27,38,27,2,27,5,"ly set breakpoints.",13
BreakList_syn
	= 27,1,0

BreakSet_help
	= "*",27,0," sets a breakpoint at",27,2,"given address.",13
BreakSet_syn
	= 27,14,"addr|reg>",0

Continue_help
	= "*",27,0," restarts execu",27,9," from",27,2,"breakpoint saved "
	= "state.",13
Continue_syn
	= 27,1,0

Debug_help
	= "*",27,0," gives access",27,"(debugging facilities.",13
Debug_syn
	= 27,1,0

InitStore_help
	= "*",27,0," fills user memory with",27,2,"specified data, or",27,2
	= "value &E6000010 (an illegal ARM instruc",27,9,") if no ",27,36
	= 27,")given.",13
InitStore_syn
	= 27,30,"<data|reg>]",0

Memory_help
	= "*",27,0,27,32,27,2,"values in",27,2,"memory in ARM words.",13
Memory_syn
	= 27,30,"A|B] <addr1|reg1> [[+|-] <addr2|reg2> [+ <addr3|reg3>]]",0

MemoryA_help
	= "*",27,0,27,32,27,16,"alters",27,2,"memory contents in bytes or "
	= "words.",13
MemoryA_syn
	= 27,30,"B] <addr|reg1> [<data|reg2>]",0

MemoryI_help
	= "*",27,0," disassembles ARM instruc",27,9,"s.",13
MemoryI_syn
	= 27,14,"addr1|reg1> [[+|-] <addr2|reg2> [+ <addr3|reg3>]]",0

ShowRegs_help
	= "*",27,0,27,32,27,2,"stored ARM registers.",13
ShowRegs_syn
	= 27,1,0

	MACRO
	Command $cmd,$min,$max
	=	"$cmd",0
	ALIGN
 [ "$min">""
	&	:INDEX:$cmd
	=	$min,0,$max,0
	&	:INDEX:$cmd._syn,:INDEX:$cmd._help
 |
	&	0,0,0,:INDEX:$cmd._help
 ]
	MEND


commands
	Command "BreakClr",0,1
	Command "BreakList",0,0
	Command "BreakSet",1,1
	Command "Continue",0,0
	Command "Debug",0,0
	Command "Debugger"
	Command "DisassemblerFlags",0,255
	Command "InitStore",0,1
	Command "Memory",1,6
	Command "MemoryA",1,3
	Command "MemoryI",1,5
	Command "ShowRegs",0,0
	& 0

oneonly
	ERR	0,"Only one instantiation of Debugger is allowed"

init	ROUT
	TEQ	R11,#0
	ADRNE	R0,oneonly
	ORRNES  PC,R14,#1:SHL:28
	STMFD	R13!,{R1-R12,R14}	; Init module
	MOV	R0,#6
	MOV	R3,#:INDEX:size+15 :AND: -16
	SWI	XOS_Module	; Claim workspace
	LDMVSFD R13!,{R1-R12,PC}
	STR	R2,[R12]
	MOV	R12,R2
	MOV	R0,#0		; Initialise workspace
wipe	SUBS	R3,R3,#4
	STRPL	R0,[R12,R3]
	BPL	wipe
	ADR	R1,trampoline_code
	ADR	R2,trampoline
	MOV	R0,#trampoline_end-trampoline_code
0	LDR	R3,[R1],#4
	SUBS	R0,R0,#4
	STR	R3,[R2],#4
	BNE	%BT0
	STR	R12,tmpln_other
	ADRL	R0,breakpt_handler
	STR	R0,tmpln_other+4
	ADR	R1,trampoline
	ADR	R2,tmpln_flags-4
	BL	synccache
	MVN	R0,#0
	ADR	R1,brkpts
	MOV	R2,#NumBrkPts*2
0	STR	R0,[R1],#4
	SUBS	R2,R2,#1
	BPL	%BT0
	BL	claimxcregs
	LDMVSFD R13!,{R1-R12,PC}
	MOV	R0,R10		; Decode parameters passed in by OS_Module
	MOV	R1,#0
	BL	DisassemblerFlags1	; ignoring errors
	MOV	R0,#129
	MOV	R1,#0
	MOV	R2,#255
	SWI	XOS_Byte	; INKEY(-256)
	CMP	R1,#&A5		; On a Risc PC?
	MOVHS	R1,#0
	BHS	notrap		; If so, don't bother with trap...
	MOV	R0,#4		; Which ARM?
	ADR	R2,undefid	; Need to trap undefined instruction
	SUB	R2,R2,#12	; in case ARMv2a
	MOV	R2,R2,LSR #2
	ORR	R2,R2,#&EA000000
	LDR	R1,[R0]
	STR	R2,[R0]		; = SWP R1,R2,[R0]
	MOV	R2,#&2000	; ID = ARM2 if next instruction 'undefined'
notrap	MRC	CP15,0,R2,C0,C0 ; ARM ID
undefid	TEQ	R1,#0
	STRNE	R1,[R0]		; Restore trap (if required)
	LDR	R1,flags
	AND	R2,R2,#&FF00	; Get part type [top 8 bits of if >=ARM6]
	ORR	R1,R1,R2,LSL #16
	STR	R1,flags
	MOV	R1,R1,LSR #24
	STR	R1,cpu_default
	LDMFD	R13!,{R1-R12,PC}

service	TEQ	R1,#&27
	MOVNE	PC,R14
	STMFD	R13!,{R0-R3,R14}
	LDR	R12,[R12]
	BL	release_env
	BL	claimxcregs
	LDMFD	R13!,{R0-R3,PC}^

claimxcregs
	STMFD	R13!,{R14}
	MOV	R0,#13
	ADR	R1,xcregs
	SWI	XOS_ChangeEnvironment
	LDMVSFD R13!,{PC}
	LDR	R14,oldxc
	TEQ	R1,R14
	STRNE	R1,oldxc
	MOV	R0,#&1E ; ChangeEnvironmentV
	ADR	R1,fiddle_env
	MOV	R2,R12
	SWI	XOS_Claim
	LDMFD	R13!,{PC}

release_env
	STMFD	R13!,{R14}
	MOV	R0,#&1E ; ChangeEnvironmentV
	ADR	R1,fiddle_env
	MOV	R2,R12
	SWI	XOS_Release
	LDMFD	R13!,{PC}

exit	STMFD	R13!,{R12,R14}  ; When RMKilled
	LDR	R12,[R12]
	BL	release_env
	BL	exit_brkclr
	MOV	R0,#13
	MOV	R1,#0
	SWI	XOS_ChangeEnvironment
	ADR	R0,xcregs
	TEQ	R0,R1
	MOVEQ	R0,#13
	LDREQ	R1,oldxc
	SWIEQ	XOS_ChangeEnvironment
	LDMFD	R13!,{R12,PC}^

fiddle_env
	; This code seems to be needed to globalise the
	; altered exception registers store...
	STMFD	R13!,{R14}
	TEQ	R0,#13
	LDREQ	R14,oldxc
	TEQEQ	R1,R14
	ADREQ	R1,xcregs
	LDMFD	R13!,{PC}

trampoline_code
	GBLA	n
n	SETA	NumBrkPts
	WHILE	n>0
	 STR	R14,trampoline_end+4+14*4
	 BL	gocommon
n	SETA   n-1
	WEND
gocommon
	STR	R14,trampoline_end+0
	ADR	R14,trampoline_end+4
	STMIA	R14,{R0-R13}
	LDR	R12,trampoline_end+68
	LDR	PC,trampoline_end+72
trampoline_end


swi_flags
	STMFD	R13!,{R14}	; Debugger_63
	LDR	R14,flags	; flags = (flags BIC R0) EOR R1
	BIC	R0,R0,#&FF000000
	BIC	R1,R1,#&FF000000
	BIC	R0,R14,R0
	EOR	R1,R0,R1	; Returns R0 = old flags, R1 = new flags
	STR	R1,flags
	MOV	R0,R14
	LDMFD	R13!,{PC}^


tabi	ROUT
	LDR	R1,flags
	SUB	R0,R8,R12
	TST	R1,#flag_wide
	MOVEQ	R1,#buffptr+28
	MOVNE	R1,#buffptr+48
	SUB	R1,R1,#1
	CMP	R0,#buffptr+8	; Tabulate
	MOVLS	R1,#buffptr+8	; Tab stops set at columns 8 and 27
0	CMP	R0,R1
	ADDGE	R1,R0,#1
	ADD	R1,R1,R12
	MOV	R0,#" "
tabloop	TEQ	R8,R1
	STRNEB  R0,[R8],#1
	BNE	tabloop
	MOVS	PC,R14

tab	LDR	R1,flags
	SUB	R0,R8,R12
	TST	R1,#flag_wide
	MOVEQ	R1,#buffptr+28
	MOVNE	R1,#buffptr+48
	SUB	R1,R1,#1
	B	%BT0

comment_warning
	ZA	"; *** "

copy_warning
	STMFD	R13!,{R0,R14}
	BL	tab
	ADR	R0,comment_warning
	BL	copy
	LDMFD	R13!,{R0,R14}
	; fall through to copy

copy	STMFD	R13!,{R2,R14}	; Copy string, leaving R8 -> null
copy_lp	LDRB	R2,[R0],#1
	STRB	R2,[R8],#1
	TEQ	R2,#0
	BNE	copy_lp
	SUB	R8,R8,#1
	LDMFD	R13!,{R2,PC}^

regno	LDRB	R1,[R8,#-1]	; Register number or constant (0 to 15)
	TEQ	R1,#"R"		; Is it an ARM register?
	TEQNE	R1,#"r"
	BNE	regnotr
	LDR	R1,flags
	TEQ	R0,#15		; Is it R15 (and not APCS-R names)?
	TSTEQ	R1,#flag_apcs
	BEQ	is_pc
	CMP	R0,#8		; Is it in range R8..R14?
	MOVGE	R5,R0		; If so, flag it for later
	TST	R1,#flag_apcs	; Are we using APCS-R names?
	BEQ	regnotr
	ADR	R1,apcs_names	; If so, write register name
	LDR	R0,[R1,R0,LSL #1]!
	STRB	R0,[R8,#-1]	; overwriting the "R" already there
	MOV	R0,R0,LSR #8
	STRB	R0,[R8],#1
	MOVS	PC,R14
apcs_names	= "a1a2a3a4v1v2v3v4v5v6slfpipsplrpc"
regnotr	ADD	R0,R0,#"0"	; Store number
	CMP	R0,#"9"
	MOVGT	R1,#"1"
	STRGTB  R1,[R8],#1
	SUBGT	R0,R0,#10
	STRB	R0,[R8],#1
	MOVS	PC,R14
is_pc	TST	R1,#flag_lower_r
	MOVEQ	R0,#"P"		; Store R15 as PC
	MOVNE	R0,#"p"
	STRB	R0,[R8,#-1]	; overwriting "R" with "P"
	MOVEQ	R0,#"C"
	MOVNE	R0,#"c"
	STRB	R0,[R8],#1
	MOVS	PC,R14

undefined ROUT
	LDR	R1,flags	; Undefined instruction
	TST	R1,#flag_usedcd ; Use "Undefined" or "DCD"?
	ADREQ	R1,undef	; "Undefined"
	MOVEQ	R2,#useofnv-undef
	LDMEQFD R13!,{R0,R3-R12,PC}^
usedcd	ADR	R0,dcd		; "DCD"
0	ADR	R8,buffer
	BL	copy
	MOV	R0,R10
	MOV	R1,R8
	MOV	R2,#9
	SWI	XOS_ConvertHex8
	ADR	R1,buffer
	SUB	R2,R8,R12
	SUB	R2,R2,#buffptr
	LDMFD	R13!,{R0,R3-R12,PC}^

dcd	= "DCD     &",0
undef	= "Undefined instruction",0
useofnv	= "Use of NV",0
not8_14	= "Not R8-R14",0
cdp_swi	= "SWI after CDP",0
	ALIGN

; "append" always means to disassembled string

testnv	ADR	R0,prev		; NV test
	LDMIA	R0,{R2,R3}	; and *some* tests based on previous instr.
	STMIA	R0,{R10,R11}
	MOV	R0,R10,LSR #28
	CMP	R0,#15		; Is NV used?
	ADREQ	R0,useofnv
	BLEQ	copy_warning	; If so, append warning and exit
	BEQ	nomasks
	ADD	R3,R3,#4	; Was last instruction disassembled
	TEQ	R3,R11		; immediately before this one?
	BNE	nomasks		; If not, exit
	CMP	R5,#0
	BEQ	trycdp
	ADR	R9,maskp	; R8..R14 used after TSTP/TEQP/CMPP/CMNP ?
	LDMIA	R9!,{R0,R1}
	AND	R0,R2,R0
	TEQ	R0,R1
	ADREQ	R0,not8_14	; If so, append warning
	BLEQ	copy_warning
trycdp	ADR	R9,maskcdp	; SWI after CDP ?
	LDMIA	R9!,{R0,R1}
	AND	R0,R2,R0
	TEQ	R0,R1
	ANDEQ	R0,R10,#&F000000
	TEQEQ	R0,#&F000000
	ADREQ	R0,cdp_swi	; If so, append warning
	BLEQ	copy_warning
nomasks	ADR	R1,buffer
	SUB	R2,R8,R1
	LDMFD	R13!,{R0,R3-R12,PC}^
maskp	& &D90F000, &110F000	; R8..R14 test
maskcdp	& &F000010, &E000000	; CDP/SWI test

swihandler
	LDR	R12,[R12]
	TEQ	R11,#63
	BEQ	swi_flags
	CMP	R11,#5
	ADDLO	PC,PC,R11,LSL #2
	B	badswi
	B	disasm
	B	disasmThumb
	B	swi_flags
	B	cpu
	B	disasmPlus
badswi	ADR	R0,.+8
	ORRS	PC,R14,#1:SHL:28
	ERR	&110,"SWI value out of range for module Debugger"

disasmThumb
	ADR	R0,.+8
	ORRS	PC,R14,#1:SHL:28
	ERR	&110,"Sorry, Debugger_DisassembleThumb not implemented"

disasmPlus
	STMFD	R13!,{R9,R14}
	LDR	R14,flags
	TST	R2,#&FF000000
	LDREQ	R9,cpu_default
	ORREQ	R2,R2,R9,LSL #24
	STR	R2,flags	; note: writes CPU info!
	STMFD	R13!,{R14}
	BL	disasm
	LDMFD	R13!,{R14}
	STR	R14,flags
	LDMFD	R13!,{R9,PC}


disasm	STMFD	R13!,{R0,R3-R12,R14}
	MOV	R10,R0		; word
	MOV	R11,R1		; address
	LDMIA	R12,{R0,R1}	; Special case for ADRL, ADRX, LDRL
	ADD	R1,R1,#4
	TEQ	R1,R11
	BLEQ	adrlchk
	MOV	R0,#0
	STR	R0,adrlx_f
	MOV	R1,R10,LSL #20  ; Special case for ANDEQ & similar
	MOV	R1,R1,LSR #20
	ANDS	R0,R10,#&FF00000
	TEQNE	R0,#&200000	; trapping AND, EOR, ORR, BIC
	TEQNE	R0,#&1800000	; with same register for both sources
	TEQNE	R0,#&1C00000	; and no shift
	ANDEQ	R9,R10,#&F0000
	TEQEQ	R1,R9,LSR #16
	BEQ	andeq
	TEQ	R0,#&1A00000	; and MOV with same register
	ANDEQ	R9,R10,#&F000	; for both source and destination, no shift
	TEQEQ	R1,R9,LSR #12
	BEQ	moveq
	LDR	R9,flags
	TST	R9,#flag_usenop
	BEQ	gofind
	EOR	R0,R10,#&6000000
	BIC	R0,R0,#&F0000000
	TEQ	R0,#&10
	ADREQ	R8,buffer
	ADREQ	R9,brk
	BEQ	decode
gofind	LDR	R9,flags
	TST	R9,#flag_usevdu ; 'VDU' flag set?
	ADREQL  R9,instructions ; Point to instruction templates list
	ADRNEL  R9,withvdu	; including VDU if selected
find	LDMIA	R9,{R0-R2}	; Search list
	ANDS	R2,R2,#255
	BEQ	undefined	; Undefined instruction if not in list
	AND	R0,R0,R10
	TEQ	R0,R1		; Use mask to see if this is it
	ADDNE	R9,R9,R2
	BNE	find		; If not, try next template
	LDRB	R0,[R9,#9]!	; Is template string = ""?
	TEQ	R0,#0
	BEQ	undefined	; If so, is undefined instruction
godecode
	MOV	R5,#0		; Set R8..R14 flag to FALSE
	MOV	R6,#0		; Set offset flag to 0
	ADR	R8,buffer	; Start of buffer
decode	LDRB	R0,[R9],#1	; Get next char from template string
	STRB	R0,[R8]		; Append
	TEQ	R0,#0
	BEQ	testnv		; End of string? If so, check NV and flags
	TEQ	R0,#32
	BLEQ	tabi		; Space = tab
	BEQ	decode
	SUBS	R1,R0,#""
	ADDMI	R8,R8,#1
	ADDPL	PC,PC,R1,LSL #2
	B	decode
	B	mul_check	; 	MUL - Rd=Rm or Rd=PC ?
	B	minus		; 	sign for load/store instructions
	B	ld_st		; 	LD or ST
	B	psr_user	; 	"^" flag
	B	f_0to2		; 	FP reg
	B	b_21to23	; 	Constant
	B	r_8to11		; 	R reg
	B	byte		; 	"B" flag
	B	condition	; 
	B	r_12to15	; 
	B	precision	; 	FP precision, S/D/E/P
	B	f_12to14	; 
	B	f_16to18	; 	(note: code 173)
	B	f_0to2orconst	; 	FP reg or constant
	B	const		; 	ARM constant for MOV etc.
	B	branch		; 	Address
	B	stack		; 	Stack type
	B	reglist		; 	Register list for stack instructions
	B	r_16to19	; 
	B	offset12	; 	Offset for LDR/STR
	B	pflag		; 	"P" flag
	B	swi		; 	SWI name or number
	B	psr		; 	CPSR/SPSR
	B	sflag		; 	"S" flag
	B	tflag		; 	"T" flag
	B	r_0to3		; 
	B	round		; 	FP rounding, <blank>/P/M/Z
	B	writeback	; 	"!" flag
	B	psr_part	; 	Which part of CPSR/SPSR to update
	B	offset8		; 	Offset for LDF/STF/LDC/STC
	B	shift		; 	LSL/LSR/ASR/ROR/RRX
	B	numregs		; 	Number of registers for LFM/SFM
	B	c_5to7		; 	Constant for CDP/MCR/MRC
	B	pc_offset12	; 	[PC,#offset] -> address for LDR/STR
	B	pc_offset8	; 	[PC,#offset] -> address for LDF etc.
	B	offsetis	; 	; =offset
	B	b_20to23	; 	Constant for CDP
	B	lflag		; 	"L" flag
	B	cache		; 	Cache registers
	B	adr		; 	ADR address
	B	adrl		; 	ADRL/ADRX address
	B	lfm_sfm		; 	LFM/SFM - which format (token string)
	B	lfs_sfs		; 	LFS/SFS reg list
	B	arith		; 	AND/EOR/.../SBC/RSC
	B	test		; 	Compare, move, ORR, BIC
	B	fparith		; 	FP binary (ADF etc)
	B	fparithunary	; 	FP unary (MVF etc)
	B	fptrans		; 	FP/ARM transfer (WFS etc)
	B	fpcompare	; 	FP compare
	B	mull		; 	ARM7 long multiply
	B	armXorlater	; 	ARM type (usage: "2a", "3", etc.)
	B	longmul_check	; 	Long MUL register check
	B	psr_mrs		; 	Append _all if old names selected
	B	char		; 	VDU (OS_WriteI substitute)
	B	r12offset	; 	'W' option validation (1st char only)
	B	adrwoff		; 	ADRW constant
	B	ldrwoff		; 	LDRW/STRW constant
	B	ldrhoff		; 	LDR/STR const (H/SH/SB forms)
	B	ldrhwoff	; 	LDRW/STRW const (H/SH/SB)
	B	pc_ldrhoff	; 	PC rel LDR/STR (H/SH/SB)
	B	lowercase	; 	Lower case option
	B	h_sh_sb		; 	H/SH/SB for LDR/STR
	B	ldct		; 	LDC/STC post-ind without writeback
	B	sa_PCop		; 	R15 and StrongARM
	B	ldrlsrc		; 	LDRL base register
	B	ldrloff		; 	LDRL offset
	B	ldrladr		; 	LDRL address
	B	ldfwoff		; 	LDFW/STFW constant
	B	ldrl_ra		; 	LDRL "{Ra},"
	B	ldrl_comment	; 	; LDRL Rd,[Rm],#c

brk	= "BRK",0
adrl_tmpl	= "ADRL R,&",0
adrx_tmpl	= "ADRX R,&",0
	ALIGN

adrlchk	AND	R9,R10,#&0FF00000
	TEQ	R9,#&02400000
	TEQNE	R9,#&02800000
	BNE	ldrlchk
	AND	R9,R0,#&0FF00000
	TEQ	R9,#&02400000
	TEQNE	R9,#&02800000
	ANDEQ	R1,R10,#&F000
	ANDEQ	R2,R10,#&F0000
	ANDEQ	R9,R0,#&F000
	TEQEQ	R1,R2,LSR #4
	TEQEQ	R1,R9
	MOVEQ	R1,R0,LSR #28
	TEQEQ	R1,R10,LSR #28
	BNE	ldrlchk
	LDR	R9,flags
	TST	R9,#flag_useadrl
	MOVEQS	PC,R14
	LDR	R9,adrlx_f
	CMP	R9,#1
	MOVLOS	PC,R14
	ADREQ	R9,adrl_tmpl
	ADRHI	R9,adrx_tmpl
	B	godecode
ldrlchk	LDR	R9,flags
	TST	R9,#flag_useldrl
	MOVEQS	PC,R14
	AND	R9,R10,#&F0000
	TEQ	R9,#&F0000
	MOVEQS	PC,R14
	AND	R9,R0,#&0FF00000
	TEQ	R9,#&02400000
	TEQNE	R9,#&02800000
	ANDEQ	R9,R10,#&0F000000
	TEQEQ	R9,#&05000000
	MOVEQ	R1,R0,LSR #28
	TEQEQ	R1,R10,LSR #28
	MOVNES	PC,R14
	TST	R10,#&100000	; STRL: Rd!=Rm
	BNE	not_strl
	TST	R10,#&200000	; STRL must have writeback
	ANDNE	R1,R10,#&F000
	ANDNE	R9,R10,#&F0000
	TEQNE	R1,R9,LSR #4
	MOVEQS	PC,R14
not_strl
	TST	R10,#&200000
	BEQ	ldrl_nw
	AND	R1,R10,#&F0000	; Writeback:
	AND	R9,R10,#&F000	; Rd!=Rm [& Rd_prev!=Rm_prev]
	TEQ	R1,R9,LSL #4
	MOVEQS	PC,R14
ldrl_nw	AND	R1,R0,#&F000	; Rm==Rd_prev
	AND	R9,R10,#&F0000
	TEQ	R1,R9,LSR #4
	MOVNES	PC,R14
	TST	R10,#&200000	; LDRL, no writeback: Rd==Rm
	BNE	isldrl
	TST	R10,#&100000
	ANDNE	R1,R10,#&F000
	TEQNE	R1,R9,LSR #4
	MOVNES	PC,R14
isldrl	AND	R9,R0,#&F0000
	TEQ	R9,#&C0000
	TEQNE	R9,#&F0000
	ADRNE	R9,ldrl_tmpl
	BNE	godecode
	TEQ	R9,#&F0000
	ADREQ	R9,ldrlpc_tmpl
	BEQ	godecode
	MOV	R9,R10
	TST	R9,#&100000
	BEQ	ldrlr
	AND	R1,R9,#&F000
	AND	R9,R9,#&F0000
	TEQ	R9,R1,LSL #4
	MOV	R9,R10
	EOREQ	R9,R9,#&200000
ldrlr	TST	R9,#&200000
	MOVEQS	PC,R14
	LDR	R9,flags
	TST	R9,#flag_useadrw
	ADREQ	R9,ldrl_tmpl
	ADRNE	R9,ldrwl_tmpl
	B	godecode
ldrl_tmpl	= "RL R,[R,#]",0
ldrwl_tmpl	= "RWL R,",0
ldrlpc_tmpl	= "RL R,&",0
	ALIGN

ldrl_comment
	LDR	R0,prev+4
	LDR	R1,prev
	ADD	R0,R0,#4
	TEQ	R0,R11
	BNE	decode
	MOV	R0,R1,LSR #28
	TEQ	R0,R10,LSR #28
	ANDEQ	R0,R1,#&0F000000
	TEQEQ	R0,#&04000000
	BNE	decode
	AND	R0,R10,#&0FE00000
	TEQ	R0,#&02400000
	TEQNE	R0,#&02800000
	ANDEQ	R0,R10,#&F0000
	ANDEQ	R7,R10,#&F000
	TEQEQ	R0,R7,LSL #4
	ANDEQ	R7,R1,#&F0000
	TEQEQ	R0,R7
	BNE	decode
	BL	tab
	ADR	R0,ldrl_c1
	BL	copy
	MOV	R0,R7,LSR #16
	BL	regno
	AND	R0,R10,#&FF
	AND	R7,R10,#&F00
	MOV	R7,R7,LSR #7
	MOV	R0,R0,ROR R7
	LDR	R1,prev
	TST	R10,#&800000
	RSBEQ	R0,R0,#0
	MOV	R7,R1,LSL #20
	MOV	R7,R7,LSR #20
	TST	R1,#&800000
	SUBEQ	R7,R0,R7
	ADDNE	R7,R0,R7
	TEQ	R7,#0
	RSBMI	R7,R7,#0
	ADRMI	R0,ldrl_cm
	ADRPL	R0,ldrl_cp
	BL	copy
	MOV	R0,R7
	B	address
ldrl_c1	=	"; R",0
ldrl_cm	=	"-=&",0
ldrl_cp	=	"+=&",0
	ALIGN

moveq	TEQ	R1,#0
	BNE	andeq
	LDR	R9,flags
	TST	R9,#flag_usenop
	ADRNE	R9,nop_tmpl
	BNE	godecode
	B	gofind
andeq	LDR	R9,flags
	TST	R9,#flag_andeqasdcd
	BEQ	gofind
	LDR	R9,movpcpc
	TEQ	R9,R10,LSL #4
	BNE	usedcd
	B	gofind
movpcpc	&	&1A0F00F0	; (MOV PC,PC) :SHL: 4
nop_tmpl
	= "NOP",0
	ALIGN

psr_user
	TST	R10,#1:SHL:22	; "^" flag
	BEQ	chkbase
	MOV	R0,#"^"
	STRB	R0,[R8],#1
	TST	R10,#1:SHL:20
	MOVNE	R1,R10
	BICEQ	R1,R10,#&8000
	AND	R0,R10,#3:SHL:21
	TEQ	R0,#3:SHL:21
	TSTEQ	R1,#1:SHL:15
	ADREQ	R0,wrbk_user	; Append comment if !+^ and (STM or no R15)
	BLEQ	copy_warning
chkbase	AND	R0,R10,#&00300000
	TEQ	R0,#&200000
	BNE	decode		; Ignore if not STM+writeback
	ANDS	R0,R10,#&F0000	; Base register position check
	BEQ	decode		; Not worth checking R0 :-)
	MOV	R0,R0,LSR #16
	MOV	R1,#1
	MOV	R1,R1,LSL R0
	TST	R10,R1
	BEQ	decode		; OK if base not in list
	SUB	R1,R1,#1
	TST	R10,R1
	ADRNE	R0,badbase	; Append comment if base not first in list
	BLNE	copy_warning
	B	decode

wrbk_user	= "! and ^",0
badbase	= "Base not first in list",0
	ALIGN
is_st	= "ST",0,0
is_ld	= "LD",0,0
	ALIGN

ld_st	TST	R10,#1:SHL:20	; LD or ST
	LDREQ	R0,is_st
	LDRNE	R0,is_ld
	STR	R0,[R8],#2	; guaranteed to be word-aligned
	B	decode

f_0to2	AND	R0,R10,#7	; FP register
regno_x	BL	regno
	B	decode

b_21to23
	MOV	R0,R10,LSR #21	; Constant
	AND	R0,R0,#7
	B	regno_x

r_8to11	MOV	R0,R10,LSR #8	; ARM register
	AND	R0,R0,#15
	B	regno_x

byte	TST	R10,#1:SHL:22	; "B" flag
	MOVNE	R0,#"B"
	STRNEB	R0,[R8],#1
	B	decode

condition
	MOV	R0,R10,LSR #28	; Condition code
	TEQ	R0,#&E
	BEQ	decode
	LDR	R1,flags
	TST	R1,#flag_zap
	MOVEQ	R2,#0
	MOVNE	R2,#32
	TST	R1,#flag_hslo
	ADR	R1,conds
	ADDNE	R1,R1,#32
	LDRB	R0,[R1,R0,LSL #1]!
	LDRB	R1,[R1,#1]
	ORR	R0,R0,R2
	ORR	R1,R1,R2
	STRB	R0,[R8],#1
	STRB	R1,[R8],#1
	B	decode
conds	= "EQNECSCCMIPLVSVCHILSGELTGTLEALNV"
	= "EQNEHSLOMIPLVSVCHILSGELTGTLEALNV"

r_12to15
	MOV	R0,R10,LSR #12	; ARM register
	AND	R0,R0,#15
	B	regno_x

precision
	AND	R0,R10,#&F000000
	TEQ	R0,#&E000000	; FP precision
	MOVEQ	R0,R10,LSR #7
	BICEQ	R0,R0,#&FE
	BICEQ	R0,R0,#&F00
	ORREQ	R0,R0,R0,LSR #11
	MOVNE	R0,R10,LSR #15
	BICNE	R0,R0,#&7E
	ORRNE	R0,R0,R0,LSR #6
	AND	R0,R0,#3
	ADR	R1,precs
	LDRB	R0,[R1,R0]
	STRB	R0,[R8],#1
	B	decode
precs	= "SDEP"

f_12to14
	MOV	R0,R10,LSR #12	; FP register
	AND	R0,R0,#7
	B	regno_x

f_16to18
	MOV	R0,R10,LSR #16	; FP register
	AND	R0,R0,#7
	B	regno_x

f_0to2orconst
	LDR	R1,flags
	AND	R0,R10,#7	; FP register or constant
	TST	R1,#flag_lower_r
	MOVEQ	R1,#"F"
	MOVNE	R1,#"f"
	TST	R10,#8
	MOVNE	R1,#"#"
	STRB	R1,[R8],#1
	BEQ	regno_x
	ADR	R1,fpconsts
	ADD	R0,R1,R0,LSL #2
copy_x	BL	copy
	B	decode
fpconsts
	= "0.0",0, "1.0",0, "2.0",0, "3.0",0
	= "4.0",0, "5.0",0, "0.5",0, "10.0",0
	ALIGN

const	ROUT
	AND	R0,R10,#255	; ARM constant for MOV etc.
	MOV	R7,R0
	MOV	R1,R10,LSR #7
	ANDS	R1,R1,#30
	ORREQ	R7,R7,#1
	MOV	R0,R0,ROR R1
vdu_com	CMP	R0,#9		; 0 to 9 : just append digit
	ADDLS	R1,R0,#"0"
	MOVHI	R1,#"&"		; or "&" if > 9
	STRB	R1,[R8],#1
	BLS	chkror
	MOV	R7,R0
	MOV	R1,R8
	MOV	R2,#9
	CMP	R0,#&10000	; >= 65536 - 8 digit hex
	BHS	hex8
	TST	R0,#&FF00	; >= 256 - 4 digit hex
	BNE	hex4
	SWI	XOS_ConvertHex2 ; else	 - 2 digit hex
	MOV	R8,R1
equals	CMP	R7,#8192	; Is const < 8192 ?
	BHS	chkror
	BL	tab		; If so, append comment...
	ADR	R0,comment
	BL	copy
	CMP	R7,#127
	CMPNE	R7,#31
	RSBHIS	R0,R7,#256	; If <256 and is printable, use ; ="<chr>"
	MOVHI	R0,#34
	STRHIB	R0,[R8],#1
	STRHIB	R7,[R8],#1
	STRHIB	R0,[R8],#1
	MOVHI	R0,#32
	STRHIB	R0,[R8],#1
	MOVHI	R0,#40
	STRHIB	R0,[R8],#1
	BL	notchar
	MOVHI	R0,#41
	STRHIB	R0,[R8],#1
chkror	MOV	R0,R10,LSR #7
	AND	R0,R0,#&1E
	AND	R1,R10,#&FF
	MOV	R1,R1,ROR R0
	CMP	R1,#256
	BHS	chkror_big
	TEQ	R0,#0
	BEQ	decode
	B	gotoddror
chkror_big
	TST	R10,#3
	BNE	decode
gotoddror
	BL	tab
	ADR	R0,oddror
	BL	copy
	B	decode
notchar	STMFD	R13!,{R14}
	MOV	R0,R7		; Otherwise use ; =<decimal>
	MOV	R1,R8
	MOV	R2,#9
	SWI	XOS_ConvertInteger4
	MOV	R8,R1
	LDMFD	R13!,{PC}^
comment	= "; =",0
oddror	= "; non-std const",0
	ALIGN
hex4	SWI	XOS_ConvertHex4
	MOV	R8,R1
	B	hexshift
hex8	SWI	XOS_ConvertHex8
	MOV	R8,R1
hexshift
	CMP	R7,#8192
	BLO	equals
	LDR	R1,flags
	TST	R1,#flag_shift
	BEQ	chkror
	TST	R7,#&FC000000
	TSTNE	R7,#&3F
	BNE	chkror
	BL	tab
	ADR	R0,comment
	BL	copy
	MOV	R0,R7
	MOV	R7,#0
0	MOVS	R0,R0,LSR #1
	ADDCC	R7,R7,#1
	BCC	%BT0
	LDR	R1,flags
	ADC	R0,R0,R0
	CMP	R0,#9
	ADDLS	R0,R0,#48
	STRLSB	R0,[R8],#1
	BLS	hs10
	MOV	R1,#"&"
	STRB	R1,[R8],#1
	MOV	R1,R8
	MOV	R2,#3
	SWI	XOS_ConvertHex2
	MOV	R8,R1
hs10	MOV	R0,#"<"
	STRB	R0,[R8],#1
	STRB	R0,[R8],#1
	MOV	R0,R7
	MOV	R1,R8
	MOV	R2,#3
	SWI	XOS_ConvertInteger1
	MOV	R8,R1
	B	chkror

branch	MOV	R0,R10,LSL #8	; Convert branch offset into address
	ADD	R1,R11,#8
	ADD	R0,R1,R0,ASR #6
	BIC	R0,R0,#&FC000003
address	MOV	R1,R8
	MOV	R2,#9
	SWI	XOS_ConvertHex8
	MOV	R8,R1
	B	decode

stack	MOV	R0,R10,LSR #23	; Decode stack type
	LDR	R1,flags
	AND	R0,R0,#3
	TST	R1,#1		; Is the R13 flag set?
	BEQ	noR13
	MOV	R1,R10,LSR #16
	AND	R1,R1,#15
	TEQ	R1,#13		; Is R13 the base register?
	BNE	noR13
	TST	R10,#1:SHL:20
	ADD	R0,R0,#4	; if STM, point to STM stack types
	ADDNE	R0,R0,#4	; similarly for LDM
noR13	ADR	R1,stacks	; Any of R13 conditions false
	LDRB	R0,[R1,R0,LSL #1]!
	LDRB	R1,[R1,#1]
	STRB	R0,[R8],#1	; Append stack type name
	STRB	R1,[R8],#1
	B	decode
stacks	= "DAIADBIB"	; normal
	= "EDEAFDFA"	; STM
	= "FAFDEAED"	; LDM

reglist	MOV	R2,R10,LSL #16	; Register list for LDM/STM
	MOVS	R2,R2,LSR #16	; Output is of the form "R0,R1,R3-R5,PC"
	BEQ	decode
	MOV	R3,#0
regloop	MOVS	R2,R2,LSR #1
	BCC	nextreg
	LDR	R0,flags
	TST	R0,#flag_lower_r
	MOVEQ	R0,#"R"
	MOVNE	R0,#"r"
	STRB	R0,[R8],#1
	MOV	R0,R3
	BL	regno
	TEQ	R2,#0
	BEQ	decode
	AND	R0,R2,#3
	TEQ	R0,#3
	MOVEQ	R0,#"-"
	MOVNE	R0,#","
	STRB	R0,[R8],#1
	BNE	nextreg
range	MOVS	R2,R2,LSR #1
	ADDCS	R3,R3,#1
	BCS	range
	LDR	R0,flags
	MOV	R2,R2,LSL #1
	TST	R0,#flag_lower_r
	MOVEQ	R0,#"R"
	MOVNE	R0,#"r"
	STRB	R0,[R8],#1
	MOV	R0,R3
	BL	regno
	TEQ	R2,#0
	MOVNE	R0,#","
	STRNEB	R0,[R8],#1
nextreg	ADD	R3,R3,#1
	CMP	R3,#16
	BLT	regloop
	B	decode

r_16to19
	MOV	R0,R10,LSR #16	; ARM register
	AND	R0,R0,#15
	B	regno_x

offset12
	MOV	R0,R10,LSL #20	; Offset for LDR/STR
	MOV	R0,R0,LSR #20
offset	CMP	R0,#10		; Common offset code
	ADDLT	R0,R0,#"0"
	STRLTB	R0,[R8],#1	; 0 to 9? Append digit
	BLT	decode
	MOV	R6,R0		; Copy offset to offset flag
	MOV	R1,R8
	MOV	R2,#9		; Else append as hex
	SWI	XOS_ConvertHex4
	MOV	R2,#"&"		; Overwrite first "0" with "&"
	STRB	R2,[R0]		; (we end up with something like &123)
	MOV	R8,R1
	B	decode

pflag	AND	R0,R10,#&F000	; "P" flag
	TEQ	R0,#&F000
	MOVEQ	R0,#"P"
	STREQB	R0,[R8],#1
	B	decode

swi	BIC	R0,R10,#&FF000000
	LDR	R2,flags
	MOV	R1,R8		; SWI name
	TST	R2,#flag_quoteswis
	MOVNE	R2,#34		; Put quote if required
	STRNEB	R2,[R1],#1
	MOV	R2,#224
	MOV	R7,R1
	SWI	XOS_SWINumberToString
	LDRB	R0,[R7]
	MOV	R1,R7
	TEQ	R0,#"X"
	ADDEQ	R1,R1,#1
	ADR	R0,swi_user	; If "User", "OS_Undefined" or their X forms
	BL	compare		; we use the SWI number instead
	ADRNE	R0,swi_undef
	BLNE	compare
	BEQ	swinum
	ADD	R8,R8,R2
	LDR	R2,flags
	TST	R2,#flag_quoteswis
	SUBEQ	R8,R8,#1
	MOVNE	R2,#34
	STRNEB	R2,[R8],#1
	B	decode
swinum	MOV	R0,#"&"		; Use the SWI number instead
	STRB	R0,[R8],#1
	BIC	R0,R10,#&FF000000
	MOV	R1,R8
	MOV	R2,#9
	SWI	XOS_ConvertHex6
	MOV	R8,R1
	B	decode
compare	STMFD	R13!,{R0-R3,R14}	; String comparison (R0, R1)
cploop	LDRB	R2,[R0],#1		; Returns NE or EQ
	LDRB	R3,[R1],#1
	TEQ	R2,R3
	LDMNEFD	R13!,{R0-R3,PC}
	TEQ	R2,#0
	BNE	cploop
	LDMFD	R13!,{R0-R3,PC}

swi_user	= "User",0
swi_undef	= "OS_Undefined",0
cpsr	= "CPSR",0,"cpsr",0
spsr	= "SPSR",0,"spsr",0
	ALIGN

psr	TST	R10,#1:SHL:22	; Which PSR to use for MSR/MRS
	LDR	R1,flags
	ADREQ	R0,cpsr
	ADRNE	R0,spsr
	TST	R1,#flag_lower_r
	ADDNE	R0,R0,#5
	B	copy_x

sflag	TST	R10,#1:SHL:20	; "S" flag
	MOVNE	R0,#"S"
	STRNEB	R0,[R8],#1
	B	decode

tflag	TST	R10,#1:SHL:21	; "T" flag
	MOVNE	R0,#"T"
	STRNEB	R0,[R8],#1
	B	decode

r_0to3	AND	R0,R10,#15	; ARM register
	B	regno_x

round	MOV	R0,R10,LSR #5	; FP rounding type
	ANDS	R0,R0,#3
	ADRNE	R1,rndchr
	LDRNEB	R0,[R1,R0]
	STRNEB	R0,[R8],#1
	B	decode
rndchr	= 0,"PMZ"

writeback
	TST	R10,#1:SHL:21	; "!" flag
	MOVNE	R0,#"!"
	STRNEB	R0,[R8],#1
	B	decode

psr_part ROUT
	MOV	R0,R10,LSR #16	; PSR part to use for MSR/MRS
	AND	R0,R0,#15
	TEQ	R0,#1
	TEQNE	R0,#8
	TEQNE	R0,#9
	BNE	psr_part_new
	LDR	R14,flags
	TST	R14,#flag_oldpsr
	BEQ	psr_part_new
	CMP	R0,#8
	ADRLO	R0,psr_ctl
	ADREQ	R0,psr_flg
	ADRHI	R0,psr_all
	B	copy_x
psr_ctl	=	"_ctl",0
psr_flg	=	"_flg",0
psr_all	=	"_all",0
	ALIGN
psr_chrs	=	"cxsf"
psr_part_new
	ADR	R1,psr_chrs
0	MOVS	R0,R0,LSR #1
	MOVCS	R2,#"_"
	STRCSB	R2,[R8],#1
	LDRB	R2,[R1],#1
	STRCSB	R2,[R8],#1
	BNE	%BT0
	B	decode

psr_mrs	LDR	R14,flags
	TST	R14,#flag_oldpsr
	BEQ	decode
	ADR	R0,psr_all
	B	copy_x

offset8	AND	R0,R10,#255	; Offset for LDF/STF/LDC/STC
	MOV	R0,R0,LSL #2
	B	offset		; Uses common offset code

shift	LDR	R2,flags
	TST	R2,#flag_lower_r
	MOVEQ	R2,#"R"
	MOVNE	R2,#"r"
	TST	R10,#16		; Shifts and rotates
	MOVNE	R3,R10,LSR #8	; Register or immediate?
	ANDNE	R3,R3,#15
	MOVEQ	R2,#"#"
	MOVEQ	R3,R10,LSR #7
	ANDEQS	R3,R3,#31
	MOVEQ	R3,#32		; If immediate and shift by 0, set to 32
	MOV	R1,R10,LSR #5	; Get shift type
	ANDS	R1,R1,#3
	TEQEQ	R2,#"#"
	TEQEQ	R3,#32
	BEQ	decode		; If LSL #0 [LSL #32], ignore it
	TEQ	R1,#3
	TEQEQ	R2,#"#"
	TEQEQ	R3,#32
	MOVEQ	R1,#4		; If ROR #0 [ROR #32], set to RRX
	ADR	R0,shname
	ADD	R0,R0,R1,LSL #2
	ADD	R0,R0,R1,LSL #1
	BL	copy		; Append shift name
	TEQ	R1,#4
	BEQ	decode		; If RRX, don't append register or constant
	STRB	R2,[R8],#1
	MOV	R0,R3
	TEQ	R2,#"#"
	BNE	regno_x		; If register, append register number
	MOV	R1,R8		; else append constant
	MOV	R2,#9
	SWI	XOS_ConvertInteger4
	MOV	R8,R1
	B	decode
shname	= ",LSL ",0, ",LSR ",0, ",ASR ",0, ",ROR ",0, ",RRX",0
	ALIGN

numregs	AND	R0,R10,#1:SHL:15
	MOV	R0,R0,LSR #15	; Number of registers for LFM/SFM
	AND	R1,R10,#1:SHL:22
	ORRS	R0,R0,R1,LSR #21
	MOVEQ	R0,#4
	ADD	R0,R0,#"0"
	STRB	R0,[R8],#1
	B	decode

c_5to7	MOV	R0,R10,LSR #5	; Constant
	ANDS	R0,R0,#7
	MOVNE	R1,#","
	STRNEB	R1,[R8],#1
	BLNE	regno
	B	decode

pc_offset12
	MOV	R0,R10,LSL #20	; [PC,#offset] -> address, for LDR/STR
	MOV	R0,R0,LSR #20
pc_offset
	TST	R10,#1:SHL:23
	SUBEQ	R0,R11,R0
	ADDNE	R0,R11,R0
	ADD	R0,R0,#8
	BIC	R0,R0,#&FC000000
	B	address

pc_offset8
	MOV	R0,R10,LSL #24	; [PC,#offset] -> address, for copro
	MOV	R0,R0,LSR #22
	B	pc_offset

offsetis
	TEQ	R6,#0		; Append comment with offset as decimal
	BEQ	decode		; if > 9
	BL	tab		; (this is because the offset code above
	ADRL	R0,comment	; doesn't set this flag if offset < 10)
	BL	copy
	MOV	R0,R6
	MOV	R1,R8
	MOV	R2,#9
	SWI	XOS_ConvertInteger4
	MOV	R8,R1
	B	decode

b_20to23
	MOV	R0,R10,LSR #20	; Constant
	AND	R0,R0,#15
	B	regno_x

lflag	TST	R10,#1:SHL:22	; "L" flag
	MOVNE	R0,#"L"
	STRNEB	R0,[R8],#1
	B	decode

cache	AND	R0,R10,#&F00	; Append comment for cache control
	TEQ	R0,#&F00	; (if copro 15)
	BNE	decode
	MOV	R2,R10,LSR #16
	AND	R2,R2,#15
	STMFD	R13!,{R9}
	LDR	R9,flags
	MOV	R9,R9,LSR #24
	CMP	R9,#3
	ADRLO	R0,cacheNA
	BLLO	copy_warning
	LDMLOFD	R13!,{R9}
	BLO	decode
	BL	tab
	CMP	R9,#&A0
	ADRLO	R0,cacheNx
	ADRHS	R0,cacheSx
	BL	copy
	CMP	R9,#10
	RSBHSS	R0,R9,#&A0
	MOVHS	R9,R9,LSR #4
	CMP	R9,#10
	ADDLO	R0,R9,#48
	STRLOB	R0,[R8,#-2]
	CMP	R9,#6
	ADRLO	R0,cache3
	BLO	cachex
	TST	R10,#1:SHL:20	; MCR or MRC?
	ADREQ	R0,cache6w
	ADRNE	R0,cache6r
	CMP	R9,#&A0
	ADDHS	R0,R0,#cacheSr-cache6r
cachex	LDRB	R2,[R0,R2]
	ADD	R0,R0,R2
	BL	copy
	LDMFD	R13!,{R9}
	B	decode
cacheNA	= "No cache",0
cacheNx	= "; ARM# ",0
cacheSx	= "; StrongARM ",0
	ALIGN
cache3	= cache30-cache3,cache31-cache3,cache32-cache3,cache33-cache3
	= cache34-cache3,cache35-cache3,cache3u-cache3,cache3u-cache3
	= cache3u-cache3,cache3u-cache3,cache3u-cache3,cache3u-cache3
	= cache3u-cache3,cache3u-cache3,cache3u-cache3,cache3u-cache3
cache6r	= cache60r-cache6r,cache6u -cache6r,cache6u -cache6r,cache6u -cache6r
	= cache6u -cache6r,cache65r-cache6r,cache66r-cache6r,cache6u -cache6r
	= cache6u -cache6r,cache6u -cache6r,cache6u -cache6r,cache6u -cache6r
	= cache6u -cache6r,cache6u -cache6r,cache6u -cache6r,cache6u -cache6r
cache6w	= cache6u -cache6w,cache61w-cache6w,cache62w-cache6w,cache63w-cache6w
	= cache6u -cache6w,cache65w-cache6w,cache66w-cache6w,cache67w-cache6w
	= cache6u -cache6w,cache6u -cache6w,cache6u -cache6w,cache6u -cache6w
	= cache6u -cache6w,cache6u -cache6w,cache6u -cache6w,cache6u -cache6w
cacheSr	= cache60r-cacheSr,cache61w-cacheSr,cache62w-cacheSr,cache63w-cacheSr
	= cache6u -cacheSr,cache65r-cacheSr,cache66r-cacheSr,cache6u -cacheSr
	= cache6u -cacheSr,cache6u -cacheSr,cache6u -cacheSr,cache6u -cacheSr
	= cache6u -cacheSr,cache6u -cacheSr,cache6u -cacheSr,cache6u -cacheSr
cacheSw	= cache6u -cacheSw,cache61w-cacheSw,cache62w-cacheSw,cache63w-cacheSw
	= cache6u -cacheSw,cache65r-cacheSw,cache66r-cacheSw,cacheS7w-cacheSw
	= cacheS8w-cacheSw,cache6u -cacheSw,cache6u -cacheSw,cache6u -cacheSw
	= cache6u -cacheSw,cache6u -cacheSw,cache6u -cacheSw,cacheSfw-cacheSw
cache30
cache60r	= "ID",0
cache32
cache61w	= "control",0
cache33		= "cacheable",0
cache34		= "updateable",0
cache35		= "disruptive",0
cache3u
cache6u		= "- bad reg",0
cache62w	= "MMU base",0
cache63w	= "domains",0
cache65r	= "FSR",0
cache65w	= "TLB flush ctrl",0
cache66r	= "FAR",0
cache66w	= "TLB purge ctrl",0
cache67w	= "IDC "
cache31		= "flush",0
cacheS7w	= "cache ops",0
cacheS8w	= "TLB ops",0
cacheSfw	= "Tst, clk, idle",0
	ALIGN

adr	LDR	R1,flags	; ADR address
	ADD	R2,R11,#8
	TST	R1,#flag_useadrl ; If flag set, then
	MOVNE	R1,#1		; set up ADRL/ADRX flag for poss. ADRL
	MOVEQ	R1,#0
adr_cmn	STR	R1,adrlx_f
	AND	R0,R10,#255	; Base address in R2
	MOV	R1,R10,LSR #7	; Calculate the offset
	AND	R1,R1,#30
	TST	R10,#1:SHL:22	; then the referenced address
	ADDEQ	R0,R2,R0,ROR R1	; (for efficiency we do the rotate NOW!)
	SUBNE	R0,R2,R0,ROR R1
	STR	R0,adrlx
	B	address		; Now append the address

adrl	LDR	R3,prev		; ADRL/ADRX address
	LDR	R1,adrlx_f
	LDR	R2,adrlx	; Get ADR address
	ADD	R1,R1,#1	; Set up for poss. ADRX
	TEQ	R1,#3		; If already ADRX, set up for next ADR
	MOVEQ	R1,#0
	B	adr_cmn		; Now sort out the extra offset

lfm_sfm	LDR	R1,flags	; LFM and SFM - select display format
	TST	R1,#flag_lfmstack + flag_lfs
	BEQ	usefm		; If no special format selected, use standard
	TST	R10,#1:SHL:20
	ADRNE	R9,mload
	ADREQ	R9,mstore
	TST	R1,#flag_lfs	; Try to use LFS/SFS if selected
	ADDNE	R9,R9,#4	; else try stack form of LFM/SFM
	MOV	R0,R10,LSR #15	; Get number of FP registers
	BIC	R0,R0,#&7E
	ORR	R0,R0,R0,LSR #6
	ANDS	R0,R0,#3
	MOVEQ	R0,#4
	ADD	R0,R0,R0,LSL #1	; Multiply by 3
	AND	R2,R10,#255	; Get the offset (div 4)
	AND	R14,R10,#3:SHL:23
	TEQ	R14,#1:SHL:23	; Post-indexed, +ve offset? IA form
	ADDEQ	R9,R9,#1
	BEQ	fmpos
	TEQ	R14,#2:SHL:23	; Pre-indexed, -ve offset? DB form
	BNE	usefm
	TST	R10,#1:SHL:21	; DB form: check writeback
	TEQEQ	R2,#0		; If clear, and offset = 0, use this
	BEQ	usefmsm
	TEQ	R2,R0		; DB form: offset = num of regs?
	BNE	usefm		; If not, use standard form
	B	usefmsm		; else use selected form
fmpos	TEQ	R2,#0		; IA form: offset = 0?
	BICEQ	R10,R10,#1:SHL:21	; if so, no writeback required
	TEQNE	R2,R0		; IA form: offset = num of regs?
	BEQ	usefmsm
usefm	TST	R10,#1:SHL:24	; Use standard form
	ADREQ	R9,fmsmpos
	ADRNE	R9,fmsmpre
	B	decode
usefmsm	TST	R1,#flag_stack	; Use selected form
	BEQ	iadb		; 'Stack' option selected?
	AND	R0,R10,#&F0000	; If so, is R13 used?
	TEQ	R0,#&D0000
	BNE	iadb
	TST	R1,#flag_apcs
	BEQ	fdea
	MOV	R0,R10,LSR #10	; Force DB form for C fn entry
	LDR	R1,c_fn_entry
	TEQ	R1,R0,LSL #10
	BEQ	iadb
fdea	ADD	R9,R9,#2	; If so, use FD/EA form
iadb	LDRB	R9,[R9]
	ADR	R0,iadb
	ADD	R9,R9,R0
	B	decode
mload	= fmdb-iadb, fmia-iadb, fmea-iadb, fmfd-iadb
	= fsdb-iadb, fsia-iadb, fsea-iadb, fsfd-iadb
mstore	= fmdb-iadb, fmia-iadb, fmfd-iadb, fmea-iadb
	= fsdb-iadb, fsia-iadb, fsfd-iadb, fsea-iadb
fmsmpos	= "M F,,[R],#",0		; LFM/SFM normal
fmsmpre	= "M F,,[R,#]",0	; LFM/SFM normal
fmdb	= "MDB F,,[R]",0
fmia	= "MIA F,,[R]",0
fmea	= "MEA F,,[R]",0
fmfd	= "MFD F,,[R]",0
fsdb	= "SDB R,{}",0
fsia	= "SIA R,{}",0
fsea	= "SEA R,{}",0
fsfd	= "SFD R,{}",0
	ALIGN

lfs_sfs	MOV	R0,R10,LSR #15	; Get number of FP registers
	BIC	R0,R0,#&7E
	ORR	R0,R0,R0,LSR #6
	ANDS	R0,R0,#3
	MOVEQ	R0,#4
	LDR	R2,flags
	MOV	R1,R10,LSR #12
	TST	R2,#flag_lower_r
	MOVEQ	R2,#"F"
	MOVNE	R2,#"f"
	SUBS	R0,R0,#1
	STRB	R2,[R8],#1
	AND	R1,R1,#7
	ADD	R1,R1,#"0"
	STRB	R1,[R8],#1
	BEQ	decode
	ADD	R1,R1,R0
	BIC	R1,R1,#8
	TEQ	R0,#1
	MOVEQ	R0,#","
	MOVNE	R0,#"-"
	STRB	R0,[R8],#1
	STRB	R2,[R8],#1
	STRB	R1,[R8],#1
	B	decode

arith	ADR	R0,arithlist
arith_test
	MOV	R1,R10,LSR #21
	AND	R1,R1,#7
arith_test_fp
	LDR	R0,[R0,R1,LSL #2]	; anything jumping here is
	STR	R0,[R8],#3		; guaranteed to be word-aligned
	B	decode
arithlist = "AND",0,"EOR",0,"SUB",0,"RSB",0,"ADD",0,"ADC",0,"SBC",0,"RSC",0

test	ADR	R0,testlist
	B	arith_test
testlist = "TST",0,"TEQ",0,"CMP",0,"CMN",0,"ORR",0,"MOV",0,"BIC",0,"MVN",0

fparith	ADR	R0,fparithlist
fparith_x
	MOV	R1,R10,LSR #20
	AND	R1,R1,#15
	B	arith_test_fp
fparithlist
	= "ADF",0,"MUF",0,"SUF",0,"RSF",0,"DVF",0,"RDF",0,"POW",0,"RPW",0
	= "RMF",0,"FML",0,"FDV",0,"FRD",0,"POL",0;,"F0D",0,"F0E",0,"F0F",0

fparithunary
	ADR	R0,fparithunarylist
	B	fparith_x
fparithunarylist
	= "MVF",0,"MNF",0,"ABS",0,"RND",0,"SQT",0,"LOG",0,"LGN",0,"EXP",0
	= "SIN",0,"COS",0,"TAN",0,"ASN",0,"ACS",0,"ATN",0,"URD",0,"NRM",0

fptrans	ADR	R0,fptranslist
	MOV	R1,R10,LSR #20
	AND	R1,R1,#15
	SUB	R1,R1,#2
	B	arith_test_fp
fptranslist	= "WFS",0,"RFS",0,"WFC",0,"RFC",0

mull	LDR	R0,flags	; guaranteed to be first item & word aligned
	TST	R0,#flag_longmul_l
	ADR	R0,mulllist
	MOV	R1,R10,LSR #21
	AND	R1,R1,#3
	LDR	R0,[R0,R1,LSL #2]
	STR	R0,[R8],#4
	MOVNE	R0,#"L"
	STRNEB	R0,[R8],#1
	B	decode
mulllist = "UMUL","UMLA","SMUL","SMLA"
	ALIGN

fpcompare	; guaranteed to be first item, and therefore word-aligned
	MOV	R1,#"C"
	TST	R10,#1:SHL:21
	ORREQ	R1,R1,#"M":SHL:8
	ORRNE	R1,R1,#"N":SHL:8
	ORR	R1,R1,#"F":SHL:16
	TST	R10,#1:SHL:22
	ORRNE	R1,R1,#"E":SHL:24
	STRNE	R1,[R8],#4
	STREQ	R1,[R8],#3
	B	decode

char	AND	R0,R10,#&FF
	MOV	R10,#0
	B	vdu_com

r12offset
	LDR	R0,flags
	TST	R0,#flag_useadrw
	BEQ	notr12
	AND	R0,R10,#&0FF00000
	TEQ	R0,#&02400000
	TEQNE	R0,#&02800000
	ANDNE	R0,R10,#&0F200000
	TEQNE	R0,#&0D000000
	BEQ	ifr12
	AND	R0,R10,#&90
	TEQ	R0,#&90
	ANDEQ	R0,R10,#&0FE00000
	TEQEQ	R0,#&01C00000
	ANDNE	R0,R10,#&0C200000
	TEQNE	R0,#&04000000
	BNE	notr12
ifr12	AND	R0,R10,#&F000
	TEQ	R0,#&C000	; No W form if R12 is destination register
	BNE	decode
notr12	SUB	R2,R2,#10
	ADD	R9,R9,R2
	B	find

adrwoff	AND	R0,R10,#&FF
	AND	R1,R10,#&F00
	MOV	R1,R1,LSR #7
	MOV	R0,R0,ROR R1
	B	address

ldrwoff	MOV	R0,R10,LSL #20
	MOV	R0,R0,LSR #20
	B	address

ldrhwoff
	BIC	R0,R10,#&F0
	ORR	R0,R0,R0,LSR #4
	AND	R0,R0,#255
	B	address

ldfwoff	AND	R0,R10,#255	; Offset for LDF/STF/LDC/STC
	MOV	R0,R0,LSL #2
	B	address		; Uses common offset code

ldrhoff	BIC	R0,R10,#&F0
	ORR	R0,R0,R0,LSR #4
	AND	R0,R0,#255
	CMP	R0,#10		; Common offset code
	ADDLT	R0,R0,#"0"
	STRLTB	R0,[R8],#1	; 0 to 9? Append digit
	BLT	decode
	MOV	R2,#"&"		; Store &
	STRB	R2,[R8],#1
	MOV	R6,R0		; Copy offset to offset flag
	MOV	R1,R8
	MOV	R2,#3		; Now append as hex
	SWI	XOS_ConvertHex2
	MOV	R8,R1
	B	decode

pc_ldrhoff
	BIC	R0,R10,#&F0
	ORR	R0,R0,R0,LSR #4
	AND	R0,R0,#255
	B	pc_offset

h_sh_sb	TST	R10,#&40	; "S" flag (LDR/STR)
	MOVNE	R0,#"S"
	STRNEB	R0,[R8],#1
	TST	R10,#&20	; "S" flag (LDR/STR)
	MOVEQ	R0,#"B"		; "B" or "H"?
	MOVNE	R0,#"H"
	STRB	R0,[R8],#1
	B	decode

ldct	ADR	R0,ldctmsg
	BL	copy_warning
	B	decode
ldctmsg	= "Writeback not set",0
	ALIGN

sa_PCop	LDR	R1,c_fn_entry
	MOV	R0,R10,LSR #10
	TEQ	R1,R0,LSL #10
	BNE	is_PCop
	LDR	R0,flags
	TST	R0,#flag_apcs
	BNE	decode
is_PCop	ADR	R0,sa_PCopmsg
	BL	copy_warning
	B	decode
sa_PCopmsg
	= "Offset not guaranteed",0
	ALIGN
c_fn_entry
	STMDB	R13!,{R11,R12,R14,PC}	; <- data

mul_check
	AND	R0,R10,#&F	; Check for silly thing like MUL Rx,Rx,Ry
	AND	R1,R10,#&F0000	; or MUL R15,Rx,Ry
	TEQ	R0,R1,LSR #16
	TEQNE	R1,#&F0000
	ADREQ	R0,rdisrm	; Append comment if found
	BLEQ	copy_warning
	B	decode
rdisrm	= "Rd=Rm or Rd=PC",0
	ALIGN

longmul_check
	AND	R1,R10,#&F000
	AND	R2,R10,#&F0000
	TEQ	R1,R2,LSR #4	; RdLo==RdHi?
	ADREQ	R0,rdlisrdh	; Append comment if found
	BLEQ	copy_warning
	AND	R0,R10,#&F
	TEQ	R1,R0,LSL #12	; Rm or PC in Rd?
	TEQNE	R2,R0,LSL #16
	TEQNE	R1,#&F000
	TEQNE	R2,#&F0000
	ADREQ	R0,rdhasrm	; Append comment if found
	BLEQ	copy_warning
	B	decode
rdhasrm	= "RdLo or RdHi = Rm or PC",0
rdlisrdh = "RdLo=RdHi",0
	ALIGN

minus	TST	R10,#1:SHL:23	; Negative offset?
	MOVEQ	R0,#"-"
	STREQB	R0,[R8],#1
	B	decode

ldrlsrc	LDR	R0,prev		; Source reg for LDRL
	MOV	R0,R0,LSR #16
	AND	R0,R0,#15
	B	regno_x

ldrloff	LDR	R0,prev
	AND	R1,R0,#&FF
	TST	R0,#&00800000
	MOV	R0,R0,LSR #7
	AND	R0,R0,#30
	MOV	R1,R1,ROR R0
	RSBEQ	R1,R1,#0
	MOV	R0,R10,LSL #20
	TST	R10,#&00800000
	SUBEQ	R0,R1,R0,LSR #20
	ADDNE	R0,R1,R0,LSR #20
	TST	R0,#1:SHL:31
	RSBNE	R0,R0,#0
	MOVNE	R1,#"-"
	STRNEB	R1,[R8],#1
	MOV	R1,#"&"
	STRB	R1,[R8],#1
	B	address

ldrladr	LDR	R0,prev
	AND	R1,R0,#&FF
	TST	R0,#&00800000
	MOV	R0,R0,LSR #7
	AND	R0,R0,#30
	ADDNE	R1,R11,R1,ROR R0
	SUBEQ	R1,R11,R1,ROR R0
	MOV	R0,R10,LSL #20
	TST	R10,#&00800000
	SUBEQ	R0,R1,R0,LSR #20
	ADDNE	R0,R1,R0,LSR #20
	ADD	R0,R0,#4
	B	address

ldrl_ra	TST	R10,#&200000
	BEQ	decode
	AND	R1,R10,#&F0000
	AND	R0,R10,#&F000
	TEQ	R1,R0,LSL #4
	LDRNE	R0,prev
	ANDNE	R1,R0,#&F0000
	ANDNE	R0,R0,#&F000
	TEQNE	R1,R0,LSL #4
	BEQ	decode
	BIC	R10,R10,#&200000
	MOV	R1,#"{"
	STRB	R1,[R8],#1
	LDR	R1,flags
	TST	R1,#flag_lower_r
	MOVEQ	R1,#"R"
	MOVNE	R1,#"r"
	STRB	R1,[R8],#1
	MOV	R0,R10,LSR #16
	AND	R0,R0,#15
	BL	regno
	MOV	R1,#"}"
	STRB	R1,[R8],#1
	MOV	R1,#","
	STRB	R1,[R8],#1
	B	decode

armXorlater ROUT
	BL	tab		; Append comment "ARMxxx or later"
	ADR	R0,arm
	BL	copy
0	LDRB	R0,[R9],#1
	STRB	R0,[R8],#1
	SUB	R0,R0,#1
	CMP	R0,#160
	BLO	%BT0
	SUB	R9,R9,#1
	SUB	R8,R8,#1
	ADR	R0,orlater
	B	copy_x
arm	= "; ARMv",0
orlater	= " and later",0
	ALIGN

lowercase ROUT
	LDR	R1,flags
	TST	R1,#flag_lower_r
	BEQ	decode
0	LDRB	R0,[R9],#1
	CMP	R0,#"A"
	RSBHSS	R1,R0,#"Z"
	ORRHS	R0,R0,#32
	STRHSB	R0,[R8],#1
	BHS	%BT0
	SUB	R9,R9,#1
	B	decode

; This is the instruction templates list.

; The order in which the tokens appear is important, since the list is
; scanned sequentially.
; Format is:
;	+0	AND mask
;	+4	TEQ value  (instruction AND mask == value)
;	+8	Offset to next token (from one AND mask to the next)
;	+9	Template string, null terminated
;	Nulls appended to ensure word alignment
; If offset to next token = 0, then this is the list terminator, not a token

withvdu
	Token	FFFFF00,F000100,"VDU "
	Token	FFFFF00,F020100,"VDUX "

instructions

	Token	F000000,A000000,"B &"
	Token	F000000,B000000,"BL &"
	Token	F000000,F000000,"SWI "

	Token	FE000F0,0000090,"MUL R,R,R"
	Token	FE000F0,0200090,"MLA R,R,R,R"
	Token	FB000F0,1000090,"SWP R,R,[R]2a"

	Token	F8000F0,0800090,"ҩ R,R,R,R3M"

	Token	FFFFFF0,12FFF10,"BX R4T"

	Token	E0000F0,0000090,""
	Token	E1000F0,00000D0,""
	Token	E1000F0,00000F0,""
	Token	F200090,0200090,"" ; stop T bit

	Token	F7FF0F0,14CF0B0,"STRHW PC,&4"
	Token	F6F00F0,14C00B0,"ףRHW R,&4"

	Token	F50F0F0,040F0B0,"STRH PC,[R],#4"
	Token	F400090,0400090,"R޹ R,[R],#4"
	Token	F7FF0F0,14FF0B0,"STRH PC,&4"
	Token	F6F0090,14F0090,"R޹ R,&4"
	Token	F50F0F0,140F0B0,"STRH PC,[R,#]4"
	Token	F400090,1400090,"R R,[R,#]4"
	Token	F50FFF0,000F0B0,"STRH PC,[R],R4"
	Token	F400F90,0000090,"R޹ R,[R],R4"
	Token	F50FFF0,100F0B0,"STRH PC,[R,R]4"
	Token	F400F90,1000090,"R R,[R,R]4"

	Token	E000090,0000090,""
	Token	E000010,6000010,""

	Token	DBFF000,120F000,""
	Token	FB0F00F,120F00F,"MSR ,PC3"
	Token	FB0F000,120F000,"MSR ,R3"
	Token	FB0F000,320F000,"MSR ,#3"
	Token	FBF0000,10F0000,"MRS R,3"

	Token	FFF0000,24C0000,"ADRW R,-&"
	Token	FFF0000,28C0000,"ADRW R,&"

	Token	FFF0000,24F0000,"ADR R,&"
	Token	FFF0000,28F0000,"ADR R,&"

	Token	F00001F,000001F,"̩ R,R,PC"
	Token	F000000,0000000,"̩ R,R,R"
	Token	F0F0010,00F0010,"̩ R,PC,R"
	Token	F000000,2000000,"̩ R,R,#"


	Token	F90001F,110001F,"ͩ R,R"
	Token	FA0001F,180001F,"ͩ R,R,R"
	Token	FAF0010,18F0010,"ͩ R,R,R"
	Token	FA0001F,1A0001F,"ͩ R,R"

	Token	F900000,1100000,"ͩ R,R"
	Token	F900000,3100000,"ͩ R,#"
	Token	FA00000,1800000,"ͩ R,R,R"
	Token	FA00000,3800000,"ͩ R,R,#"
	Token	FA00000,1A00000,"ͩ R,R"
	Token	FA00000,3A00000,"ͩ R,#"

	Token	F3FF000,50CF000,"STRW PC,&"
	Token	F2F0000,50C0000,"ףRW R,&"

	Token	F10F000,400F000,"STR PC,[R],#"
	Token	F000000,4000000,"R R,[R],#"
	Token	F3FF000,50FF000,"STR PC,&"
	Token	F2F0000,50F0000,"R R,&"
	Token	F10F000,500F000,"STR PC,[R,#]"
	Token	F000000,5000000,"R R,[R,#]"
	Token	F10F000,600F000,"STR PC,[R],R"
	Token	F000000,6000000,"R R,[R],R"
	Token	F10F000,700F000,"STR PC,[R,R]"
	Token	F000000,7000000,"R R,[R,R]"

	Token	E108000,8008000,"STM R,{}"
	Token	E000000,8000000,"M R,{}"

	Token	F2C0F00,D0C0100,"ףFW F,&"

	Token	F200F00,C200100,"F F,[R],#"
	Token	F2F0F00,D0F0100,"F F,&"
	Token	F000F00,D000100,"F F,[R,#]"

	Token	F3F0F00,D0F0200,"SFM F,,&"
	Token	E100F00,C000200,"SF"
	Token	F3F0F00,D1F0200,"LFM F,,&"
	Token	E100F00,C100200,"LF"

	Token	FF08F10,ED00100,"CDP CP,,C,C,C"; mask out F0x
	Token	FE08F10,EE00100,"CDP CP,,C,C,C"

	Token	F008F10,E000100,"Ω F,F,"
	Token	F008F10,E008100,"ϩ F,"

	Token	F90FF10,E90F110,"ѩ F,"

	Token	FF0FF10,E00F110,"FLT F,PC"
	Token	FF00F10,E000110,"FLT F,R"
	Token	FF00F10,E100110,"FIX R,"
	Token	FF0FF10,E20F110,"WFS PC"
	Token	FF0FF10,E40F110,"WFC PC"
	Token	FE00F10,E200110,"Щ R"
	Token	FE00F10,E400110,"Щ R"

	Token	F000010,E000000,"CDP CP,,C,C,C"
	Token	F10F010,E00F010,"MCR CP,,PC,C,C"
	Token	F100010,E000010,"MCR CP,,R,C,C"
	Token	F100010,E100010,"MRC CP,,R,C,C"

	Token	F200000,C000000,"C CP,C,[R],#"
	Token	F000000,C000000,"C CP,C,[R],#"
	Token	F2F0000,D0F0000,"C CP,C,&"
	Token	F000000,D000000,"C CP,C,[R,#]"

	& 0,0,0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: DisassemblerFlags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DisassemblerFlags
	MOV	R1,#1
	LDR	R12,[R12]
DisassemblerFlags1
	STMFD	R13!,{R1-R12,R14}
	MOV	R10,R1
	MOV	R1,R0
	ADR	R0,args
	ADR	R2,buffer
	MOV	R3,#256
	SWI	XOS_ReadArgs
	LDMVSFD	R13!,{R1-R12,PC}
	TEQ	R3,#256-4*flag__b
	TEQEQ	R10,#1
	BEQ	current
	MOV	R2,#1:SHL:(flag__b-1)
	LDR	R3,flags
	ADR	R4,buffer+4*flag__b
flagbit	LDR	R0,[R4,#-4]!
	BL	yesno
	LDMVSFD	R13!,{R1-R12,PC}
	MOVS	R2,R2,LSR #1
	BNE	flagbit
	STR	R3,flags
	LDMFD	R13!,{R1-R12,PC}
notyn_err
	& 220
	= "Bad switch state",0
args	= "fdwithr13=fd,"
	= "apcs,"
	= "lfmstack=sfmstack=lfm=sfm,"
	= "lfs=sfs,"
	= "quoteswis=quote=swi,"
	= "usedcd=dcd,"
	= "usevdu=vdu,"
	= "andeqasdcd=andeq,"
	= "useadrl=adrl,"
	= "useadrw=adrw,"
	= "longmul=mull,"
	= "useldrl=ldrl,"
	= "usenop=nop,"
	= "oldpsr=psr,"
	= "wide,"
	= "hslo=hs=lo,"
	= "shift,"
	= "lower",0
	ALIGN
yesno	TEQ	R0,#0
	MOVEQS	PC,R14
	LDRB	R1,[R0,#1]
	TEQ	R1,#0
	BNE	notyn
	LDRB	R1,[R0]
	TEQ	R1,#"0"
	TEQNE	R1,#"N"
	TEQNE	R1,#"n"
	BICEQ	R3,R3,R2
	MOVEQS	PC,R14
	TEQ	R1,#"1"
	TEQNE	R1,#"Y"
	TEQNE	R1,#"y"
	ORREQ	R3,R3,R2
	MOVEQS	PC,R14
notyn	ADR	R0,notyn_err
	ORRS	PC,R14,#1:SHL:28
current	LDR	R8,flags
	ADR	R0,flagtext
	MOV	R7,#1
showflag
	LDRB	R1,[R0]
	TEQ	R1,#0
	LDMEQFD	R13!,{R1-R12,PC}^
	SWI	XOS_Write0
	LDMVSFD	R13!,{R1-R12,PC}
	TST	R8,R7
	BL	printyesno
	MOVVC	R7,R7,LSL #1
	BVC	showflag
	LDMFD	R13!,{R1-R12,PC}
printyesno
	STMFD	R13!,{R0,R14}
	ADREQ	R0,printno
	ADRNE	R0,printyes
	SWI	XOS_Write0
	SWIVC	XOS_NewLine
	LDMFD	R13!,{R0,PC}
printyes = " Yes",0
printno	= " No",0
flagtext
	= "                   Use FD with R13 :",0
	= "                    Use APCS names :",0
	= "      LFM/SFM stack where possible :",0
	= "LFS/SFS for LFM/SFM where possible :",0
	= "       Put quotes around SWI names :",0
	= "Use DCD for undefined instructions :",0
	= "  Use VDU instead of SWI OS_WriteI :",0
	= "Use DCD instead of ANDEQ & similar :",0
	= "     Use ADRL/X for ADR + ADD/SUBs :",0
	= "  Use ADRW/LDRW for R12m/[R12,#m] :",0
	= "           Long forms of UMULL etc :",0
	= "    Use LDRL for ADR/ADD/SUB + LDR :",0
	= " Use NOP and BRK where appropriate :",0
	= "           Use old CPSR/SPSR names :",0
	= "           Use wide display format :",0
	= "Use HS and LO instead of CS and CC :",0
	= "  Append comments of the form x<<y :",0
	= "         Lower case register names :",0
	= 0
	ALIGN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: ShowRegs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ShowRegs ROUT
	LDR	R12,[R12]
showregs
	STMFD	R13!,{R14}
	PRINT	"Register dump (stored at &"
	ADRVC	R6,xcregs
	MOVVC	R0,R6
	BLVC	writehex8
	LDMVSFD	R13!,{PC}
	PRINT	") is:"
	SWIVC	XOS_NewLine
	LDMVSFD	R13!,{PC}
	MOV	R5,#0
printreg
	LDR	R0,flags
	TST	R0,#flag_apcs
	BNE	p_rAPCS
	VDU	"R"
	LDMVSFD	R13!,{PC}
	CMP	R5,#10
	BHS	p_rnn
	ADD	R0,R5,#48
	SWI	XOS_WriteC
	VDU	" ",VC
	B	p_rval
p_rnn	VDU	"1"
	ADDVC	R0,R5,#38
	SWIVC	XOS_WriteC
	B	p_rval
p_rAPCS	ADRL	R0,apcs_names
	ADD	R0,R0,R5,LSL #1
	MOV	R1,#2
	SWI	XOS_WriteN
p_rval	LDMVSFD	R13!,{PC}
	PRINT	" = "
	LDRVC	R0,[R6],#4
	BLVC	writehex8
	LDMVSFD	R13!,{PC}
	ADD	R5,R5,#1
	TST	R5,#3
	BEQ	p_rlf
	VDU	" "
	B	p_rnext
p_rlf	SWI	XOS_NewLine
p_rnext	LDMVSFD	R13!,{PC}
	TEQ	R5,#16
	BNE	printreg
	PRINT	"Mode "
	LDRVC	R6,[R6,#-4]
	ANDVC	R0,R6,#3
	ADRVC	R1,cpumode
	ADDVC	R0,R1,R0,LSL #2
	SWIVC	XOS_Write0
	LDMVSFD	R13!,{PC}
	PRINT	", flags set: "
	LDMVSFD	R13!,{PC}
	ADR	R5,flagletters
	MOV	R4,#6
0	LDRB	R0,[R5],#1
	MOVS	R6,R6,LSL #1
	BICCS	R0,R0,#32
	SWI	XOS_WriteC
	LDMVSFD	R13!,{PC}
	SUBS	R4,R4,#1
	BNE	%BT0
	SWI	XOS_NewLine
	LDMFD	R13!,{PC}
cpumode	= "USR",0,"FIQ",0,"IRQ",0,"SVC",0
flagletters = "nzcvif"
	ALIGN


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: InitStore
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

InitStore
	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	MOV	R10,R0
	BL	skipspcs
	CMP	R14,#32
	LDRLT	R2,inits_default
	BLGE	eval
	MOVVC	R3,R2
	MOVVC	R4,R2
	MOVVC	R5,R2
	MOVVC	R6,R2
	SWIVC	XOS_GetEnv
	LDMVSFD	R13!,{R6-R12,PC}
	MOV	R0,#&8000
inits_wipe
	CMP	R0,R1
	STMLTIA	R0!,{R3-R6}
	BLT	inits_wipe
	SUB	R2,R1,#4
	MOV	R1,#&8000
	BL	synccache
	PRINT	"Store initialised to &"
	MOVVC	R0,R3
	BLVC	writehex8
	SWIVC	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}
inits_default
	&	&E6000010


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: Debug
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Debug	LDR	R12,[R12]
debug	STMFD	R13!,{R6-R12,R14}
Dbg_l	PRINT	"Debug*"
	ADR	R0,buffer
	ORR	R0,R0,#1:SHL:31
	MOV	R1,#256
	MOV	R2,#32
	MOV	R3,#255
	SWI	XOS_ReadLine
	LDMVSFD	R13!,{R6-R12,PC}
	BCS	escape
	ADR	R0,buffer
	SWI	XOS_CLI
	BVC	Dbg_l
	ADD	R0,R0,#4
	SWI	XOS_Write0
	SWIVC	XOS_NewLine
	BVC	Dbg_l
	LDMFD	R13!,{R6-R12,PC}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: BreakList
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BreakList ROUT
	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	ADR	R4,brkpts-8
	MOV	R3,#NumBrkPts
0	LDR	R1,[R4,#8]!
	TEQ	R1,#0
	BPL	foundbrkpt
	SUBS	R3,R3,#1
	BNE	%BT0
	PRINT	"No breakpoints set"
	SWIVC	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}
foundbrkpt
	PRINT	"Address     Old data"
	SWIVC	XOS_NewLine
	LDMVSFD	R13!,{R6-R12,PC}
	RSB	R3,R3,#NumBrkPts
1	LDMIA	R4!,{R5,R6}
	TEQ	R5,#0
	BMI	nextbrkpt
	MOV	R0,R5
	BL	writehex8
	VDU	" ",VC
	VDU	" ",VC
	VDU	" ",VC
	VDU	" ",VC
	MOV	R0,R6
	BL	writehex8
	MOV	R0,R5
	ADD	R1,R0,#4
	SWI	XOS_ValidateAddress
	BCS	badbrkpt
	MOV	R0,R5
	BL	calc_branch
	LDR	R1,[R5]
	TEQ	R1,R0
	BEQ	brkptOK
	STR	R6,[R5]
badbrkpt
	MVN	R0,#0
	STR	R0,[R4,#-8]
	PRINT	" ; bad breakpoint - cleared"
	LDMVSFD	R13!,{R6-R12,PC}
brkptOK	SWI	XOS_NewLine
	LDMVSFD	R13!,{R6-R12,PC}
nextbrkpt
	ADD	R3,R3,#1
	TEQ	R3,#NumBrkPts
	BNE	%BT1
	LDMFD	R13!,{R6-R12,PC}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: BreakSet
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BreakSet ROUT
	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	MOV	R10,R0
	BL	eval
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	TST	R2,#&FC000003
	BNE	badbrkpt_err
	CMP	R2,#&3000000
	BHS	badbrkpt_err
	MOV	R0,R2
	BL	addrintable
	SUBEQ	R4,R4,#8
	BEQ	cansetbrkpt
	ADR	R4,brkpts-8
	MOV	R3,#0
0	LDR	R1,[R4,#8]!
	TEQ	R1,#0
	BMI	cansetbrkpt
	ADD	R3,R3,#1
	TEQ	R3,#NumBrkPts
	BNE	%BT0
	ADR	R0,brklistfull_msg
	B	retvs
brklistfull_msg
	ERR	&803,"No room in breakpoint table"
badbrkpt_err
	ADR	R0,badbrkpt_msg
	B	retvs
badbrkpt_msg
	ERR	&805,"Bad breakpoint"
brkpt_exists
	MOV	R0,R2
cansetbrkpt
	MOV	R5,R2
	MOV	R0,R2
	ADD	R1,R2,#4
	SWI	XOS_ValidateAddress
	BCS	badbrkpt_err
	LDR	R1,[R5]
	BL	calc_branch
	TEQ	R0,R1
	LDRNE	R6,[R5]
	STMNEIA	R4,{R5,R6}	; new or overwritten breakpoint
	STRNE	R0,[R5]
	STREQ	R5,[R4]		; existing breakpoint
	MOV	R1,R5
	MOV	R2,R5
	BL	synccache
	LDMFD	R13!,{R6-R12,PC}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: BreakClr
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BreakClr ROUT
	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	MOV	R10,R0
	BL	skipspcs
	CMP	R14,#32
	ADR	R4,brkpts
	BLT	confirmclearall
	BL	eval
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	MOV	R3,#0
	SUB	R4,R4,#8
0	LDR	R5,[R4,#8]!
	TEQ	R5,R2
	ADDEQ	R7,R3,#1
	BEQ	dobrkclr
	ADD	R3,R3,#1
	TEQ	R3,#NumBrkPts
	BNE	%BT0
	ADR	R0,brkptnotfound_msg
	B	retvs
brkptnotfound_msg
	ERR	&800,"Breakpoint not found"

confirmclearall
	PRINT	"Clear all breakpoints? [Y/N]"
	SWIVC	XOS_Confirm
	LDMVSFD	R13!,{R6-R12,PC}
	BCS	escape
	BEQ	doclearall
	SWI	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}
doclearall
	SWI	XOS_NewLine
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	"All breakpoints cleared."
	SWIVC	XOS_NewLine
	LDMVSFD	R13!,{R6-R12,PC}
dobrkclrall
	ADR	R4,brkpts
	MOV	R3,#0
	MOV	R7,#NumBrkPts
dobrkclr
	LDMIA	R4!,{R5,R6}
	TEQ	R5,#0
	BMI	brkclr_next
	MOV	R0,R5
	ADD	R1,R0,#4
	SWI	XOS_ValidateAddress
	BCS	brkclr_entryonly
	MOV	R0,R5
	BL	calc_branch
	LDR	R1,[R5]
	TEQ	R1,R0
	STREQ	R6,[R5]
brkclr_entryonly
	MVN	R0,#0
	STR	R0,[R4,#-8]
brkclr_next
	ADD	R3,R3,#1
	TEQ	R3,R7
	BNE	dobrkclr
	LDMFD	R13!,{R6-R12,PC}

exit_brkclr
	STMFD	R13!,{R6-R12,R14}
	B	dobrkclrall


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: Continue
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Continue
	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	LDR	R0,xcregs+60
	BIC	R0,R0,#&FC000003
	BL	addrintable
	ADRNE	R0,xcregs
	BNE	cont_inline
	MOV	R1,R0
	BL	calc_branch
	LDR	R14,[R1]
	TEQ	R14,R0
	BNE	cont_cant
	PRINT	"Continue from breakpoint set at &"
	MOVVC	R0,R1
	BLVC	writehex8
	SWIVC	XOS_NewLine
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	"Execute out of line? [Y/N]"
	SWIVC	XOS_Confirm
	LDMVSFD	R13!,{R6-R12,PC}
	BCS	escape
	BEQ	cont_doit
	SWI	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}
cont_doit
	STMFD	R13!,{R4}
	SWI	XOS_NewLine
	LDMVSFD	R13!,{R4,R6-R12,PC}
	ADR	R8,buffer2
	ADR	R9,xcregs
	LDMIA	R9!,{R0-R7}
	STMIA	R8!,{R0-R7}
	LDMIA	R9!,{R0-R6}
	LDR	R14,[R9]
	ADR	R7,buffer2+64
	AND	R14,R14,#&FC000003
	ORR	R7,R7,R14
	STMIA	R8!,{R0-R7}
	LDMFD	R13!,{R4}
	LDR	R14,[R4,#-4]
	ANDS	R0,R14,#&0E000000
	TEQNE	R0,#&02000000
	BEQ	fiddle_arith
	TEQ	R0,#&0A000000	; fiddle B/BL instructions
	BNE	cont_doinstr
	TST	R14,#&01000000
	LDRNE	R6,[R9]
	ADDNE	R6,R6,#4
	STRNE	R6,[R8,#12]
	LDRNE	R6,ldr14
	ANDNE	R0,R14,#&F0000000
	ORRNE	R6,R6,R0
	STRNE	R6,[R8],#4
	MOV	R14,R14,ROR #24
	ADD	R14,R14,R1,LSL #6
	SUB	R14,R14,R8,LSL #6
	MOV	R14,R14,ROR #8
	BIC	R14,R14,#&01000000
cont_doinstr
	STR	R14,[R8],#4
cont_return
	LDR	R0,xcregs+60
	BIC	R0,R0,#&FC000003
	SUB	R0,R0,#4	; R0+4-R8-8 -> R0-R8-4
	SUB	R2,R0,R8
	MOV	R2,R2,LSL #6
	MOV	R2,R2,LSR #8
	ORR	R2,R2,#&EA000000
	STR	R2,[R8]
	ADR	R1,buffer2+64
	MOV	R2,R8
	BL	synccache
	ADR	R0,buffer2
cont_inline
	LDR	R14,[R0,#60]
	ANDS	R14,R14,#3
	BEQ	cont_usr
	TEQP	R14,#&C000000
	MOV	R0,R0
	LDMIA	R0,{R0-PC}^
cont_usr
	MOV	R14,R0
	LDMIA	R14,{R0-R14}^
	MOV	R0,R0
	LDR	R14,[R14,#60]
	MOVS	PC,R14
ldr14	LDREQ	R14,[PC,#4]

cont_cant
	MVN	R14,#0
	STR	R14,[R4]
	PRINT	"Bad breakpoint at &"
	MOVVC	R0,R1
	BLVC	writehex8
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	"; cleared"
	SWIVC	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}

fiddle_arith
	TST	R14,#&02000000
	ANDEQ	R0,R14,#&90
	TEQEQ	R0,#&90
	BEQ	fiddle_mul
	AND	R0,R14,#&0D800000
	TEQ	R0,#&01000000
	BEQ	cont_doinstr
	MOV	R4,R14,LSR #12
	AND	R4,R4,#15
	MOV	R5,R14,LSR #16
	AND	R5,R5,#15
	BIC	R14,R14,#&FF000
	ORR	R14,R14,#&21000
	TST	R14,#&02000000
	MVN	R6,#0
	MVN	R7,#0
	BNE	fiddle_gotregs
	AND	R6,R14,#15
	BIC	R14,R14,#15
	ORR	R14,R14,#3
	TST	R14,#&10
	MOVNE	R7,R14,LSR #8
	BICNE	R14,R14,#&F00
fiddle_gotregs
	STR	R14,[R8]
	LDR	R0,retR14
	STR	R0,[R8,#4]
	MOV	R1,R8
	ADD	R2,R8,#4
	BL	synccache
	ADR	R9,xcregs
	LDR	R14,[R9,#60]
	MOV	R0,PC
	AND	R14,R14,#&F0000000
	AND	R0,R0,#&0C000003
	ORR	R14,R14,R0
	LDR	R1,[R9,R4,LSL #2]
	TEQ	R4,#15
	ADDEQ	R1,R1,#8
	LDR	R2,[R9,R5,LSL #2]
	TEQ	R5,#15
	ADDEQ	R2,R2,#8
	BICEQ	R2,R2,#&FC000003
	LDR	R3,[R9,R6,LSL #2]
	TEQ	R6,#15
	ADDEQ	R3,R3,#8
	LDR	R0,[R9,R7,LSL #2]
	TEQ	R7,#15
	ADDEQ	R0,R0,#8
	TEQP	R14,#0		; staying in SVC26 mode
	ADR	R14,fiddle_cont
	MOV	PC,R8
fiddle_cont
	MOV	R3,PC
	TEQ	R4,#15
	LDREQ	R9,[R9,#60]
	BICEQ	R1,R1,#&FC000003	; special action if R1='PC'
	ANDEQ	R9,R9,#&FC000003
	ORREQ	R1,R1,R9
	SUB	R9,R8,#64
	STR	R1,[R9,R4,LSL #2]	; store modified register
	LDR	R1,[R9,#60]
	AND	R3,R3,#&F0000000
	BIC	R1,R1,#&F0000000
	ORR	R1,R1,R3
	STR	R1,[R9,#60]		; update flags
	B	cont_return
retR14	MOV	PC,R14

fiddle_mul
	ANDS	R0,R14,#&0FC00000
	BNE	cont_doinstr
	AND	R0,R0,#&F0
	TEQ	R0,#&90
	BNE	cont_doinstr
	MOV	R4,R14,LSR #16
	AND	R4,R4,#15
	TEQ	R4,#15
	MVNEQ	R4,#0		; Rd=R15? Flags only
	AND	R5,R14,#15
	MOV	R6,R14,LSR #8
	AND	R6,R6,#15
	TST	R14,#&00200000
	MVNEQ	R7,#0
	MOVNE	R7,R14,LSR #12
	ANDNE	R7,R7,#15
	ADR	R0,fiddle_mulmask
	LDMIA	R0,{R0,R1}
	BIC	R14,R14,R0
	ORR	R14,R14,R1
	B	fiddle_gotregs
fiddle_mulmask
	&	&000FFF0F,&00010302



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: Memory
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mem_WORD	* 0
mem_BYTE	* 1
mem_ASCII	* 2
mem_CODE	* 3

memory_errmsg
	ERR	220,"Syntax: Memory2 [A|B] <addr1|reg1> [[+|-] <addr2|reg2> [+<addr3|reg3>]]"

Memory	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	MOV	R10,R0
	BL	skipspcs
	BIC	R8,R14,#32
	TEQ	R8,#"A"
	TEQNE	R8,#"B"
	MOVNE	R8,#mem_WORD
	BNE	mem_goeval
	TEQ	R8,#"A"
	MOVEQ	R8,#mem_ASCII
	MOVNE	R8,#mem_BYTE
	LDRB	R14,[R10,#1]
	CMP	R14,#32
	MOVHI	R8,#mem_WORD
	ADDLS	R10,R10,#1
mem_goeval
	BL	mem_eval
	LDMVSFD	R13!,{R6-R12,PC}
	BCC	mem_common
	ADR	R0,memory_errmsg
	B	retvs


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: MemoryI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

memoryi_errmsg
	ERR	220,"Syntax: MemoryI2 <addr1|reg1> [[+|-] <addr2|reg2> [+<addr3|reg3>]]"

MemoryI	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	MOV	R10,R0
	MOV	R8,#mem_CODE
	BL	mem_eval
	LDMVSFD	R13!,{R6-R12,PC}
	ADRCS	R0,memoryi_errmsg
	BCS	retvs
;	B	mem_common	; fall through


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Code common to Memory and MemoryI
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mem_common
	SWI	XOS_ReadMemMapInfo
	MOV	R9,R0
	SUB	R10,R9,#1
	TEQ	R8,#mem_WORD
	TEQNE	R8,#mem_CODE
	BICEQ	R5,R5,#3
	BICEQ	R6,R6,#3
	TEQ	R5,R6
	ADREQ	R7,mem_inc1
	LDREQB	R7,[R7,R8]
	ADDEQ	R6,R6,R7
	MOV	R7,#0
mem_displayloop
	ADR	R1,mem_inc
	LDRB	R1,[R1,R8]
	ADD	R0,R5,R7
	ADD	R1,R0,R1
	MOV	R11,R1
	MOV	R3,R0
	MOV	R4,R1
	BL	validateaddress
	LDMVSFD	R13!,{R6-R12,PC}
	BCC	mem_dodisplay
	BIC	R1,R1,R10
	BL	validateaddress
	LDMVSFD	R13!,{R6-R12,PC}
	MOVCC	R4,R1
	BCC	mem_dodisplay
	MOV	R1,R4
	BIC	R0,R1,R10
	BL	validateaddress
	LDMVSFD	R13!,{R6-R12,PC}
	MOVCS	R4,R3
	MOVCC	R3,R0
mem_dodisplay
	ADR	R0,mem_inc
	LDRB	R0,[R0,R8]
	MOV	R0,R0,LSL #4
	SUB	R0,R0,#1
	TST	R7,R0
	BLEQ	mem_header
	ADDVC	R0,R5,R7
	BLVC	writehex8
	LDMVSFD	R13!,{R6-R12,PC}
	ADD	R0,R5,R7
	TEQ	R8,#mem_CODE
	BNE	mem_colon
	LDR	R14,xcregs+60
	BIC	R14,R14,#&FC000003
	TEQ	R0,R14
	BEQ	mem_atpc
	STMFD	R13!,{R3,R4}
	BL	addrintable
	LDMFD	R13!,{R3,R4}
	BNE	mem_colon
	PRINT	" *"
	B	mem_donecolon
mem_atpc
	PRINT	" <"
	B	mem_donecolon
mem_colon
	TEQ	R8,#mem_ASCII
	BEQ	mem_ascii_only
	PRINT	" :"
mem_donecolon
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R8,#mem_CODE
	VDU	" ",EQ
	LDMVSFD	R13!,{R6-R12,PC}
mem_disp_data
	BL	mem_data
	LDMVSFD	R13!,{R6-R12,PC}
	CMP	R0,R11
	BLT	mem_disp_data
mem_ascii_only
	PRINT	" : "
	ADD	R0,R5,R7
	STMFD	R13!,{R8}
	MOV	R8,#mem_ASCII
mem_disp_ascii
	BL	mem_data
	ADDVS	R13,R13,#4
	LDMVSFD	R13!,{R6-R12,PC}
	CMP	R0,R11
	BLT	mem_disp_ascii
	LDMFD	R13!,{R8}
	TEQ	R8,#mem_CODE
	BNE	mem_display_nextline
	PRINT	" : "
	LDMVSFD	R13!,{R6-R12,PC}
	ADD	R0,R5,R7
	CMP	R0,R3
	BLO	mem_display_nextline
	CMP	R0,R4
	CMPLO	R0,R6
	BHS	mem_display_nextline
	BL	mem_readword
	MOV	R2,R0
	MOV	R0,R1
	MOV	R1,R2
	SWI	XDebugger_Disassemble
	MOVVC	R0,R1
	SWIVC	XOS_Write0
	LDMVSFD	R13!,{R6-R12,PC}
mem_display_nextline
	SWI	XOS_ReadEscapeState
	BCS	escape
	ADR	R0,mem_inc
	LDRB	R0,[R0,R8]
	ADD	R7,R7,R0
	SWI	XOS_NewLine
	LDMVSFD	R13!,{R6-R12,PC}
	CMP	R11,R6
	BLT	mem_displayloop
	LDMFD	R13!,{R6-R12,PC}

mem_inc	=	16,16,64,4
mem_inc1 =	 4, 1, 1,4
mem_mask =	15,15,63,3

validateaddress
	STMFD	R13!,{R14}
	CMP	R0,#&3800000		; ROM?
	RSBHSS	R14,R1,#&4000000
	BHS	isROM
	SWI	XOS_ValidateAddress
	LDMFD	R13!,{PC}
isROM	CMP	R0,R1
	LDMFD	R13!,{PC}

mem_header ROUT
	TEQ	R8,#mem_CODE
	MOVEQ	PC,R14
	STMFD	R13!,{R14}
	SWI	XOS_NewLine
	LDMVSFD	R13!,{PC}
	PRINT	"Address  :"
	LDMVSFD	R13!,{PC}
	ADD	PC,PC,R8,LSL #2
	&	0
	B	mem_hdr_word
	B	mem_hdr_byte
;	B	mem_hdr_ascii
;mem_hdr_ascii
	VDU	" "
	LDMVSFD	R13!,{PC}
	MOV	R2,#64
	AND	R1,R5,#15
	ADD	R0,R1,#48
0	TEQ	R0,#":"
	ADDEQ	R0,R0,#7
	SWI	XOS_WriteC
	LDMVSFD	R13!,{PC}
	ADD	R0,R0,#1
	TEQ	R0,#"G"
	MOVEQ	R0,#"0"
	SUBS	R2,R2,#1
	BNE	%BT0
	SWI	XOS_NewLine
	LDMFD	R13!,{PC}
mem_hdr_word
	MOV	R2,#4
1	;
	VDU	" "
	VDU	" ",VC
	VDU	" ",VC
	VDU	" ",VC
	ADRVC	R0,mem_hdr_word_txt
	ANDVC	R1,R5,#15
	ADDVC	R0,R0,R1,LSL #1
	MOVVC	R1,#8
	SWIVC	XOS_WriteN
	LDMVSFD	R13!,{PC}
	ADD	R5,R5,#4
	SUBS	R2,R2,#1
	BNE	%BT1
	SUB	R5,R5,#16
	B	mem_hdr_asciipart
mem_hdr_word_txt
	=	" 3 2 1 0 7 6 5 4 B A 9 8 F E D C"
mem_hdr_byte
	MOV	R2,#16
	AND	R1,R5,#15
2	ADD	R0,R1,#48
	CMP	R1,#9
	ADDHI	R0,R0,#7
	PRINT	" 0"
	SWIVC	XOS_WriteC
	LDMVSFD	R13!,{PC}
	ADD	R1,R1,#1
	AND	R1,R1,#15
	SUBS	R2,R2,#1
	BNE	%BT2
mem_hdr_asciipart
	PRINT	" :    ASCII Data"
	SWIVC	XOS_NewLine
	LDMFD	R13!,{PC}

mem_data
	STMFD	R13!,{R14}
	ADD	PC,PC,R8,LSL #2
	&	0
	B	mem_data_word
	B	mem_data_byte
	B	mem_data_ascii
;	B	mem_data_code
	VDU	" "
	BVC	mem_data_code
	LDMFD	R13!,{PC}
mem_data_word
	PRINT	"    "
	LDMVSFD	R13!,{PC}
mem_data_code
	ADD	R2,R0,#4
	CMP	R0,R3
	MOV	R1,#8
	BLO	mem_data_skip_dot
	CMP	R0,R6
	BHS	mem_data_skip_spc
	CMP	R0,R4
	BHS	mem_data_skip_dot
	SUB	R0,R2,#4
	BL	mem_readword
	STMFD	R13!,{R2}
	MOV	R0,R1
	BL	writehex8
	LDMVSFD	R13!,{R1,PC}
	LDMFD	R13!,{R0,PC}
mem_data_byte
	VDU	" "
	LDMVSFD	R13!,{PC}
	ADD	R2,R0,#1
	CMP	R0,R3
	MOV	R1,#2
	BLO	mem_data_skip_dot
	CMP	R0,R6
	BHS	mem_data_skip_spc
	CMP	R0,R4
	BHS	mem_data_skip_dot
	SUB	R0,R2,#1
	BL	mem_readbyte
	STMFD	R13!,{R2}
	MOV	R0,R1
	BL	writehex2
	LDMVSFD	R13!,{R1,PC}
	LDMFD	R13!,{R0,PC}
mem_data_ascii
	ADD	R2,R0,#1
	CMP	R0,R3
	MOV	R1,#1
	BLO	mem_data_skip_dot
	CMP	R0,R6
	BHS	mem_data_skip_spc
	CMP	R0,R4
	BHS	mem_data_skip_dot
	SUB	R0,R2,#1
	BL	mem_readbyte
	STMFD	R13!,{R2}
	MOV	R0,R1
	CMP	R0,#127
	CMPNE	R0,#31
	MOVLE	R0,#"."
	SWI	XOS_WriteC
	LDMVSFD	R13!,{R1,PC}
	LDMFD	R13!,{R0,PC}
mem_data_skip_dot
	VDU	"."
	LDMVSFD	R13!,{PC}
	SUBS	R1,R1,#1
	BGT	mem_data_skip_dot
	MOV	R0,R2
	LDMFD	R13!,{PC}
mem_data_skip_spc
	VDU	" "
	LDMVSFD	R13!,{PC}
	SUBS	R1,R1,#1
	BGT	mem_data_skip_spc
	MOV	R0,R2
	LDMFD	R13!,{PC}

mem_readbyte
	STMFD	R13!,{R0,R14}
	BIC	R0,R0,#3
	BL	mem_readword
	LDMFD	R13!,{R0}
	AND	R14,R0,#3
	MOV	R14,R14,LSL #3
	MOV	R1,R1,LSR R14
	AND	R1,R1,#255
	LDMFD	R13!,{PC}

mem_readword ROUT
	STMFD	R13!,{R4,R14}
	ADR	R4,brkpts
	MOV	R14,#NumBrkPts
0	LDR	R1,[R4],#8
	TEQ	R0,R1
	LDREQ	R1,[R4,#-4]
	LDMEQFD	R13!,{R4,PC}
	SUBS	R14,R14,#1
	BNE	%BT0
	LDR	R1,[R0]
	TEQ	R0,#1
	LDMFD	R13!,{R4,PC}


mem_eval
	STMFD	R13!,{R14}
	BL	eval
	LDMVSFD	R13!,{PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	MOV	R5,R2
	BL	skipspcs
	TEQ	R8,#mem_ASCII
	MOVEQ	R6,#256
	MOVNE	R6,#&60
	CMP	R14,#32
	ADDLT	R6,R5,R6
	BLT	mem_evalok
	TEQ	R14,#"+"
	TEQNE	R14,#"-"
	MOVEQ	R7,R14
	ADDEQ	R10,R10,#1
	MOVNE	R7,#0
	BL	eval
	LDMVSFD	R13!,{PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	TEQ	R7,#"+"
	ADDEQ	R6,R5,R2
	TEQ	R7,#"-"
	SUBEQ	R6,R5,R2
	TEQ	R7,#0
	MOVEQ	R6,R2
	CMP	R5,R6
	MOVGT	R0,R5
	MOVGT	R5,R6
	MOVGT	R6,R0
	BL	skipspcs
	CMP	R14,#32
	BLT	mem_evalok
	TEQ	R7,#0
	BEQ	mem_evalerr
	TEQ	R14,#"+"
	BNE	mem_evalerr
	ADD	R10,R10,#1
	TEQ	R7,#"+"
	MOVEQ	R5,R6
	BL	eval
	LDMVSFD	R13!,{PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	ADD	R6,R5,R2
mem_evalok
	LDMFD	R13!,{R14}
	BICS	PC,R14,#1:SHL:29	; clear carry
mem_evalerr
	LDMFD	R13!,{R14}
	ORRS	PC,R14,#1:SHL:29	; set carry


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Command: MemoryA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MemoryA	STMFD	R13!,{R6-R12,R14}
	LDR	R12,[R12]
	MOV	R10,R0
	BL	skipspcs
	BIC	R9,R14,#32
	TEQ	R9,#"B"
	MOVNE	R9,#mem_WORD
	BNE	mema_goeval
	MOV	R9,#mem_BYTE
	LDRB	R14,[R10,#1]
	CMP	R14,#32
	MOVHI	R9,#mem_WORD
	ADDLS	R10,R10,#1
mema_goeval
	BL	eval
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R9,#mem_WORD
	BICEQ	R2,R2,#3
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	MOV	R5,R2
	BL	skipspcs
	CMP	R14,#32
	BLT	mema_interactive
	BL	eval
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	MOV	R0,R5
	TEQ	R9,#mem_BYTE
	ADDEQ	R1,R0,#1
	BICNE	R0,R0,#3
	ADDNE	R1,R0,#4
	SWI	XOS_ValidateAddress
	LDMVSFD	R13!,{R6-R12,PC}
	ADRCS	R0,nowriteable
	BCS	retvs
	TEQ	R9,#mem_BYTE
	BEQ	mema_byte_imm
	BL	mema_readword
	MOV	R7,R1
	STREQ	R2,[R4,#-4]
	BLNE	writeR2word
	PRINT	"Word at &"
	MOVVC	R0,R5
	BLVC	writehex8
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	" was &"
	MOVVC	R0,R7
	BLVC	writehex8
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	" altered to &"
	MOVVC	R0,R2
	BLVC	writehex8
	SWIVC	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}
mema_byte_imm
	BIC	R0,R5,#3
	BL	mema_readword
	BLNE	writeR2byte
	ANDEQ	R2,R2,#255
	ANDEQ	R14,R5,#3
	MOVEQ	R14,R14,LSL #3
	MOVEQ	R7,R1,LSR R14
	MOVEQ	R0,#255
	BICEQ	R1,R1,R0,LSL R14
	ORREQ	R1,R1,R2,LSL R14
	STREQ	R1,[R4,#-4]
	PRINT	"Byte at &"
	MOVVC	R0,R5
	BLVC	writehex8
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	" was &"
	MOVVC	R0,R7
	BLVC	writehex2
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	" altered to &"
	MOVVC	R0,R2
	BLVC	writehex2
	SWIVC	XOS_NewLine
	LDMFD	R13!,{R6-R12,PC}

nowriteable
	ERR	&411,"No writable memory at this address"

noreadable
	ERR	&411,"No readable memory at this address"

mema_interactive
	TEQ	R9,#mem_BYTE
	MOVEQ	R7,#1
	MOVNE	R7,#4
	MOV	R0,R5
	ADDEQ	R1,R0,#1
	BICNE	R0,R0,#3
	ADDNE	R1,R0,#4
	SWI	XOS_ValidateAddress
	LDMVSFD	R13!,{R6-R12,PC}
	ADRCS	R0,noreadable
	BCS	retvs
mema_loop
	MOV	R3,R5
	ADD	R4,R3,#4
	MOV	R6,R4
	CMP	R7,#0
	MOVLT	R0,#"-"
	MOVGE	R0,#"+"
	SWI	XOS_WriteC
	VDU	" ",VC
	MOVVC	R0,R5
	BLVC	writehex8
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	" : "
	MOVVC	R0,R5
	MOVVC	R8,#mem_ASCII
	BLVC	mem_data
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R9,#mem_BYTE
	BEQ	mema_onechar
	BLVC	mem_data
	BLVC	mem_data
	BLVC	mem_data
	LDMVSFD	R13!,{R6-R12,PC}
mema_onechar
	PRINT	" : "
	LDMVSFD	R13!,{R6-R12,PC}
	MOV	R0,R5
	TEQ	R9,#mem_BYTE
	BEQ	mema_pbyte
	BL	mem_readword
	MOV	R0,R1
	BL	writehex8
	LDMVSFD	R13!,{PC}
	PRINT	" : "
	MOVVC	R0,R5
	BLVC	mem_readword
	MOVVC	R0,R1
	MOVVC	R1,R5
	SWIVC	XDebugger_Disassemble
	MOVVC	R0,R1
	SWIVC	XOS_Write0
	SWIVC	XOS_NewLine
	B	mema_getinput
mema_pbyte
	BL	mem_readbyte
	MOV	R0,R1
	BL	writehex2
	LDMVSFD	R13!,{PC}
	PRINT	" : "
	SWIVC	XOS_NewLine
mema_getinput
	LDMVSFD	R13!,{R6-R12,PC}
	PRINT	"  Enter new value: "
	ADRVC	R0,buffer
	ORRVC	R0,R0,#1:SHL:31
	MOVVC	R1,#256
	MOVVC	R2,#32
	MOVVC	R3,#255
	SWIVC	XOS_ReadLine
	LDMVSFD	R13!,{R6-R12,PC}
	BCS	escape
	ADR	R10,buffer
	BL	skipspcs
	TEQ	R14,#"+"
	BEQ	mema_plus
	TEQ	R14,#"-"
	BEQ	mema_minus
	TEQ	R14,#"."
	LDMEQFD	R13!,{R6-R12,PC}
	CMP	R14,#32
	BLT	mema_next
	BL	eval
	LDMVSFD	R13!,{R6-R12,PC}
	TEQ	R0,#15
	BICEQ	R2,R2,#&FC000003
	BIC	R0,R5,#3
	TEQ	R9,#mem_BYTE
	BEQ	mema_writebyte
	BL	mema_readword
	STREQ	R2,[R4,#-4]
	BLNE	writeR2word
	B	mema_loop
mema_writebyte
	BL	mema_readword
	BLNE	writeR2byte
	ANDEQ	R2,R2,#255
	ANDEQ	R14,R5,#3
	MOVEQ	R14,R14,LSL #3
	MOVEQ	R0,#255
	BICEQ	R1,R1,R0,LSL R14
	ORREQ	R1,R1,R2,LSL R14
	STREQ	R1,[R4,#-4]
	B	mema_loop
mema_next
	ADD	R0,R5,R7
	TEQ	R8,#mem_BYTE
	ADDEQ	R1,R0,#1
	ADDNE	R1,R0,#4
	SWI	XOS_ValidateAddress
	LDMVSFD	R13!,{R6-R12,PC}
	ADDCC	R5,R5,R7
	B	mema_loop
mema_plus
	CMP	R7,#0
	RSBLT	R7,R7,#0
	B	mema_loop
mema_minus
	CMP	R7,#0
	RSBGT	R7,R7,#0
	B	mema_loop

mema_readword ROUT
	STMFD	R13!,{R14}
	ADR	R4,brkpts
	MOV	R14,#NumBrkPts
0	LDR	R1,[R4],#8
	TEQ	R0,R1
	LDREQ	R1,[R4,#-4]
	LDMEQFD	R13!,{PC}
	SUBS	R14,R14,#1
	BNE	%BT0
	LDR	R1,[R0]
	TEQ	R0,#1
	LDMFD	R13!,{PC}

writeR2word
	STMFD	R13!,{R6,R7,R11,R14}
	LDRB	R14,flags+3
	CMP	R14,#&60
	RSBHSS	R14,R5,#&1B
	STRLO	R2,[R5]		; don't write to hardware vectors
	LDMLOFD	R13!,{R6,R7,R11,PC}
	MOV	R11,#1
writeR2_protected
	MOV	R6,PC
	&	&E10F7000	;	MRS	R7,CPSR_all
	ORR	R7,R7,#&10	; SVC_32 (this unlocks the hw vectors)
	&	&E129F007	;	MSR	CPSR_all,R7
	BIC	R7,R7,#&10
	TEQ	R11,#0
	STREQB	R2,[R5]
	STRNE	R2,[R5]
	&	&E129F007	;	MSR	CPSR_all,R7
	MOV	R0,R0
	LDMFD	R13!,{R6,R7,R11,PC}^

writeR2byte
	STMFD	R13!,{R6,R7,R11,R14}
	LDRB	R14,flags+3
	CMP	R14,#&60
	RSBHSS	R14,R5,#&1B
	STRLOB	R2,[R5]		; don't write to hardware vectors
	LDMLOFD	R13!,{R6,R7,R11,PC}
	MOV	R11,#0
	B	writeR2_protected

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Generally useful code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

writehex8
	STMFD	R13!,{R1,R2,R14}
	ADR	R1,buffer2
	MOV	R2,#9
	SWI	XOS_ConvertHex8
	SWIVC	XOS_Write0
	LDMFD	R13!,{R1,R2,PC}

writehex2
	STMFD	R13!,{R1,R2,R14}
	ADR	R1,buffer2
	MOV	R2,#3
	SWI	XOS_ConvertHex2
	SWIVC	XOS_Write0
	LDMFD	R13!,{R1,R2,PC}

skipspcs ROUT
	STMFD	R13!,{R14}
	SUB	R10,R10,#1
0	LDRB	R14,[R10,#1]!
	TEQ	R14,#32
	BEQ	%BT0
	LDMFD	R13!,{PC}


eval	STMFD	R13!,{R11,R14}
	BL	skipspcs
	BIC	R14,R14,#32
	TEQ	R14,#"R"
	BEQ	evalreg
	TEQ	R14,#"P"
	BEQ	evalpc
	MOV	R0,#16
	MOV	R1,R10
	SWI	XOS_ReadUnsigned
	BVS	evalbad
	MOV	R10,R1
	MVN	R0,#0
	LDMFD	R13!,{R11,PC}
evalreg	ADD	R10,R10,#1
	MOV	R0,#10:OR:(1:SHL:29)
	MOV	R1,R10
	MOV	R2,#15
	SWI	XOS_ReadUnsigned
	BVS	evalbad
	MOV	R10,R1
evalrOK	MOV	R11,R2
	ADR	R1,xcregs
	LDR	R2,[R1,R11,LSL #2]
	MOV	R0,R11
	LDMFD	R13!,{R11,PC}
evalpc	LDRB	R14,[R10,#1]
	ADD	R10,R10,#2
	TEQ	R14,#"C"
	TEQNE	R14,#"c"
	MOVEQ	R2,#15
	BEQ	evalrOK
evalbad	ADR	R0,evalbad_msg
	LDMFD	R13!,{R11,R14}
	ORRS	PC,R14,#1:SHL:28
evalbad_msg
	ERR	&801,"Invalid value"


escape	; expects R6-R12,R14 on the stack
	MOV	R0,#126
	SWI	XOS_Byte
	ADR	R0,esc_msg
retvs	LDMFD	R13!,{R6-R12,R14}
	ORRS	PC,R14,#1:SHL:28
esc_msg	ERR	17,"Escape"


synccache
	STMFD	R13!,{R12,R14}
	MOV	R0,#1
	SWI	&2006E
	LDMFD	R13!,{R12,PC}^

calc_branch
; R0 = address		-> branch instruction
; R3 = breakpt number
	STMFD	R13!,{R14}
	ADR	R14,trampoline-8
	ADD	R14,R14,R3,LSL #3
	SUB	R14,R14,R0
	MOV	R14,R14,LSL #6
	MOV	R0,#&EA000000
	ORR	R0,R0,R14,LSR #8
	LDMFD	R13!,{PC}

addrintable ROUT
	STMFD	R13!,{R5,R14}
	ADR	R4,brkpts
	MOV	R3,#0
0	LDR	R5,[R4],#8
	TEQ	R5,R0
	LDMEQFD	R13!,{R5,PC}
	ADD	R3,R3,#1
	TEQ	R3,#NumBrkPts
	BNE	%BT0
	TEQ	R3,#0
	LDMFD	R13!,{R5,PC}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Breakpoint handler
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

breakpt_handler
	SWI	XOS_EnterOS
	LDR	R1,tmpln_flags
	AND	R3,R1,#&FC000003
	BIC	R1,R1,R3
	ADR	R0,trampoline+8
	SUB	R0,R1,R0
	ADR	R1,brkpts
	LDR	R10,[R1,R0]
	ORR	R10,R10,R3
	STR	R10,xcregs+60	; store PC
	PRINT	"Stopped at breakpoint set at &"
	BICVC	R0,R10,R3
	BLVC	writehex8
	SWIVC	XOS_NewLine
	BLVC	showregs
	BLVC	debug
	SWI	XOS_NewLine
	SWI	XOS_Exit


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CPU type
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

cpu	ROUT
	STMFD	R13!,{R1-R3,R14}
	TEQ	R0,#0
	BMI	getcpu
	LDREQ	R0,cpu_default
	BEQ	setcpu
	ADR	R1,cpu_in-4
	MOV	R2,#cpu_out-cpu_in
	BL	findcpu
setcpu	STREQB	R0,flags+3
	LDMEQFD	R13!,{R1-R3,PC}
	ADR	R0,unknown_cpu
	LDMFD	R13!,{R1-R3,R14}
	ORRS	PC,R14,#1:SHL:28
getcpu	LDRB	R0,flags+3
	ADR	R1,cpu_out-4
	MOV	R2,#cpu_in-cpu_out
	BL	findcpu
	LDMFD	R13!,{R1-R3,PC}

cpu_in	&	2  ,250,3,  6,  610,7,  700,710,&5A,0
cpu_out	&	&20,&20,&30,&61,&61,&71,&71,&71,&A1,0

findcpu	LDR	R3,[R1,#4]!
	TEQ	R3,#0
	BICEQS	PC,R14,#1:SHL:30
	TEQ	R0,R3
	BNE	findcpu
	LDRB	R0,[R1,R2]
	MOV	PC,R14

unknown_cpu
	ERR	&806, "Unknown CPU type"

	END
