; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > &.Hdr.NdrDebug
;

OldOpt	SETA	{OPT}
	OPT	OptNoList+OptNoP1List

; ***********************************
; ***	C h a n g e	L i s t	***
; ***********************************

; Date	Name	Description
; ----	----	-----------
;
; 25-Sep-89	NDR	First version written
;  3-May-90	NDR	File debugging added
; 30-Aug-90	NDR	Changed so if file can't be opened, no debugging is output
;  1-Nov-90	NDR	Neil_NewLine flushes data to file
;  6-Nov-90	NDR	Neil_NewLine also puts out end-of-file marker and resets PTR
;  2-Jan-91	NDR	Ensure Debug macro still works if V set on entry
;  3-Jan-91	NDR	Ensure debug_flush deals correctly when no debug output
;  4-Jan-91	NDR	Preserve R2 in Neil_Write0 and Neil_Newline
; 10-Apr-91	OSS	Changed all macros, particularly InsertNDRDebugRoutines,
;			to not put any code in if the debug flag is not set. This
;			is because too many modules are messing things up and
;			are putting debugging code into the ROM!
; 10-Feb-93	BC	Restored OPT correctly
; 27-Apr-93	AMG	Changed the macros to use HostFS SWIs instead of OS_CLI.
;			This stops scratchspace corruption which was affecting
;			Colourtrans_SelectTable debug calls. Added logic flag
;			to allow assembling ColourTrans with the previous version
;			to raise an error.
; 14-Jul-93	SAH	Print *NULL* if DebugS is given a 0 pointer.
;  2-Aug-93	SAH	Increased number of parameters to 10
;  2-Aug-93	SAH	Added conditional versions (DebugIf, DebugaIf, DebugSIf)
; 13-Oct-93	AMG	Merge the two copies of NdrDebug together, and remove
;			the one from hdr - ATTENTION: NdrDebug lives in hdr2 !!!
; 20-Sep-94	SMC	Added support for DebugIt module (set debug_module to true,
;			hostvdu should be false).
; 17-Apr-97	JRC	If debug_file is set, it is a file name which is opened,
;			written to and closed in each call to Debug. Even better
;			than debug_flush!
; 15-Jan-98     KJB     Added support for PDebug module (set pdebug_module to true,
;			hostvdu should be false).
; 21-May-99	BJGA	Added support for debugging null-terminated strings:
;			top-bit-clear characters (other than CR and LF) are effectively
;			reverse-GSTrans'd (set debug_nullterminatedstrings to true).
;			Also added support for DADebug module (set daddebug_module true).
;			hostvdu is now defined, and set false, if not yet defined.
;			Debug_Open and Debug_Close only generate code in cases where the
;			output mechanism needs it, so they no longer need to be
;			bracketed conditionally in the source code.
; 28-May-99	BJGA	Added debug_irqsafe option, which converts a 32-bit number to a
;			string itself, without calling OS_ConvertHex8
; 04-Apr-00	KJB	Made 32-bit compatible (except a few options, which will generate
;			warnings)
; 05-Apr-00     BJGA    debug_nullterminatedstrings also made 32-bit compatible;
;                       32-bit compatibility now complete
; 14-Aug-00     BJGA    Now outputs the value of r13 correctly; No32BitCode-unset variant
;                       now objasm-compatible (uses mymrs macros rather than mrs macros)

	GBLL	debug
	GBLL	debug_flush
	GBLS	debug_file
	GBLL	true
	GBLL	false

; New logical variable for use in sources which suffer from scratchspace
; corruption caused by older version of this header calling OS_CLI instead
; of HostFS by SWI directly. Set it to {FALSE} before incorporating this
; header file to ensure that the new header file is in use. You may also
; need to add a GET for hdr:HostFS

	GBLL	debug_noscratchspace
debug_noscratchspace	SETL	{TRUE}

 [ :LNOT: :DEF: hostvdu
	GBLL	hostvdu				; Use HostFS
hostvdu		SETL	{FALSE}
 ]
	GBLL	debug_module			; Use DebugIt module
debug_module	SETL	{FALSE}

	GBLL	pdebug_module			; Use PDebug module
pdebug_module	SETL	{FALSE}

	GBLL	dadebug_module			; Use DADebug module
dadebug_module	SETL	{FALSE}

	GBLL	debug_nullterminatedstrings	; Print control characters in strings
debug_nullterminatedstrings	SETL	{FALSE}

	GBLL	debug_irqsafe			; Emulate SWI OS_ConvertHex8
debug_irqsafe	SETL	{FALSE}

true		SETL	1=1
false		SETL	1=0

debug_flush	SETL	false	; default - can be altered before InsertNDRDebugRoutines
debug_file	SETS	""	; default - can be altered before InsertNDRDebugRoutines

; NB: All s preserve the flags and all registers.
;	However, they do require the stack to be set up.

	MACRO
$lab	Debug_Open	$filename
$lab
	[ debug :LAND: :LNOT: hostvdu :LAND: :LNOT: debug_module :LAND: :LNOT: pdebug_module
	[	dadebug_module	; this doesn't use $filename
	Push	"R0, LR"
	SWI	&731C0		; XDADebug_GetWriteCAddress
	MOVVS	R0, #0
	ADRL	LR, dadebug_writec
	STR	R0, [LR]
	CLRV
	Pull	"R0, LR"
	|
	[	debug_file = ""
	Push	"R1, LR"
	ADR	R1, %FT00
	BL	Neil_OpenFile
	B	%FT01
00
	DCB	"$filename", 0
	ALIGN
01
	Pull	"R1, LR"
	|
	Debug	"", "------------------------------------------------------------"
	]
	]
	]
	MEND

	MACRO
$lab	Debug_Close
$lab
	[ debug :LAND: :LNOT: hostvdu :LAND: :LNOT: debug_module :LAND: :LNOT: pdebug_module
	[ dadebug_module
	Push	"LR"
	MOV	LR, #0
	STR	LR, dadebug_writec
	Pull	"LR"
	|
	[ debug_file = ""
	Push	"LR"
	BL	Neil_CloseFile
	Pull	"LR"
	]
	]
	]
	MEND

	MACRO
	Debug1	$dbg, $string
	[	debug$dbg
	Debug	$dbg, "$string"
	]
	MEND

	MACRO
	Debug2	$dbg, $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	[	debug$dbg
	Debug	$dbg, "", $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	]
	MEND

	MACRO
	Debug2a	$dbg, $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	[	debug$dbg
	Debuga	$dbg, "", $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	]
	MEND

	MACRO
	DebugS	$dbg, $string, $reg, $max
	[	debug:LAND:debug$dbg
	Push	"R0-R12, LR, PC"
        [ :LNOT:No32bitCode
        mymrs  ,LR, CPSR
        STR     LR, [sp, #14*4]
        ]

	[	debug_file <> ""
	ADR	R1, %FT10
	BL	Neil_OpenFile
	B	%FT11
10
	DCB	"$debug_file", 0
	ALIGN
11
	]
	[	hostvdu
	BL	Neil_HostVdu
	]

	MOV	r0, pc
	BL	Neil_ConvertHex8

	ADR	R0, %FT00
	BL	Neil_Write0
	B	%FT01
00
	DCB	": $dbg, $string", 0
02
	DCB	"*NULL*", 0
	ALIGN
01
	MOV	R0, #" "
	BL	Neil_WriteC
	MOV	R0, #"'"
	BL	Neil_WriteC
	[	$reg > sp
	LDR	R0, [sp, #:INDEX:$reg * 4 - 4]	; R13 is not stacked
	|
	LDR	R0, [sp, #:INDEX:$reg * 4]
	]

	TEQ	R0, #0
	ADREQ	R0, %BT02

	[	"$max"=""
	BL	Neil_Write0
	|
	MOV	R2, #$max
	BL	Neil_Write0_R2max
	]
	MOV	R0, #"'"
	BL	Neil_WriteC
	BL	Neil_NewLine
	[	hostvdu
	BL	Neil_TubeVdu
	]

	[	debug_file <> ""
	BL	Neil_CloseFile
	]
	Pull	"R0-R12"
	LDR	LR, [sp, #4]
        RestPSR LR,,f                   ; restore flags
	LDR	LR, [sp], #8		; correct stack
	]
	MEND

	MACRO
	Debug	$dbg, $string, $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	[	debug:LAND:debug$dbg
	Push	"R0-R12, LR, PC"
        [ :LNOT:No32bitCode
        mymrs  ,LR, CPSR
        STR     LR, [sp, #14*4]
        ]

	[	debug_file <> ""
	ADR	R1, %FT10
	BL	Neil_OpenFile
	B	%FT11
10
	DCB	"$debug_file", 0
	ALIGN
11
	]
	[	hostvdu
	BL	Neil_HostVdu
	]

	MOV	r0, pc
	BL	Neil_ConvertHex8

	ADR	R0, %FT00
	BL	Neil_Write0
	B	%FT01
00
	DCB	": $dbg, $string", 0
	ALIGN
01
	[	"$p1"<>""
	Dreg	$p1
	]
	[	"$p2"<>""
	Dreg	$p2
	]
	[	"$p3"<>""
	Dreg	$p3
	]
	[	"$p4"<>""
	Dreg	$p4
	]
	[	"$p5"<>""
	Dreg	$p5
	]
	[	"$p6"<>""
	Dreg	$p6
	]
	[	"$p7"<>""
	Dreg	$p7
	]
	[	"$p8"<>""
	Dreg	$p8
	]
	[	"$p9"<>""
	Dreg	$p9
	]
	[	"$p10"<>""
	Dreg	$p10
	]
	BL	Neil_NewLine
	[	hostvdu
	BL	Neil_TubeVdu
	]

	[	debug_file <> ""
	BL	Neil_CloseFile
	]

	Pull	"R0-R12"
	LDR	LR, [sp, #4]
        RestPSR LR,,f                   ; restore flags
	LDR	LR, [sp], #8		; correct stack
	]
	MEND

	MACRO
	Debuga	$dbg, $string, $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	[	debug:LAND:debug$dbg
	Push	"R0-R12, LR, PC"
        [ :LNOT:No32bitCode
        mymrs  ,LR, CPSR
        STR     LR, [sp, #14*4]
        ]
	[	hostvdu
	BL	Neil_HostVdu
	]
	ADR	R0, %FT00
	BL	Neil_Write0
	B	%FT01
00
	DCB	"$string", 0
	ALIGN
01
	[	"$p1"<>""
	Dreg	$p1
	]
	[	"$p2"<>""
	Dreg	$p2
	]
	[	"$p3"<>""
	Dreg	$p3
	]
	[	"$p4"<>""
	Dreg	$p4
	]
	[	"$p5"<>""
	Dreg	$p5
	]
	[	"$p6"<>""
	Dreg	$p6
	]
	[	"$p7"<>""
	Dreg	$p7
	]
	[	"$p8"<>""
	Dreg	$p8
	]
	[	"$p9"<>""
	Dreg	$p9
	]
	[	"$p10"<>""
	Dreg	$p10
	]
	[	hostvdu
	BL	Neil_TubeVdu
	]
	Pull	"R0-R12"
	LDR	LR, [sp, #4]
        RestPSR LR,,f                   ; restore flags
	LDR	LR, [sp], #8		; correct stack
	]
	MEND

	MACRO
	Dreg	$reg
	[	debug
	[	"$reg":LEFT:1 = "#"
	LCLS	locn
locn	SETS	"$reg":RIGHT:(:LEN:"$reg"-1)
	[	:BASE:($locn) = sp
	LDR	R0, $locn + 15*4		; allow for 15 stacked registers
	|
	LDR	R0, $locn
	]
	|
	[	$reg > sp
	LDR	R0, [sp, #:INDEX:$reg * 4 - 4]	; R13 is not stacked
	|
	[       $reg = sp
	ADD	R0, sp, #15*4
	|
	LDR	R0, [sp, #:INDEX:$reg * 4]
	]
	]
	]
	BL	Neil_ConvertHex8
	]	; End debug
	MEND

	MACRO
$lab	DebugE	$dbg, $mess
	[	debug:LAND:debug$dbg
$lab	BVC	%ft0
	ADD	R0, R0, #4
	DebugS	$dbg, "$mess", R0
	SUB	R0, R0, #4
0
	]
	MEND
; Conditional versions of some of the above macros

	MACRO
$lab	DebugSIf	$cond, $dbg, $string, $reg, $max
	[	debug:LAND:debug$dbg
$lab	B$cond	%FT99
	B	%FT98
99
	DebugS	$dbg, "$string", "$reg", "$max"
98
	]
	MEND

	MACRO
$lab	DebugaIf	$cond, $dbg, $string, $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	[	debug:LAND:debug$dbg
$lab	B$cond	%FT99
	B	%FT98
99
	Debuga	$dbg, "$string", $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	]
	MEND

	MACRO
$lab	DebugIf	$cond, $dbg, $string, $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
	[	debug:LAND:debug$dbg
$lab	B$cond	%FT99
	B	%FT98
99
	Debug	$dbg, "$string", $p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10
98
	]
	MEND

	MACRO
	InsertNDRDebugRoutines
	[	debug

Neil_ConvertHex8			; prints number in R0
	Push	"R0, LR"
;
	MOV	R0, #" "
	BL	Neil_WriteC
	[ debug_irqsafe
	Pull	"R1"
	MOV	R2, #8
01	MOV	R0, R1, LSR#28
	CMP	R0, #10
	ADDCC	R0, R0, #48
	ADDCS	R0, R0, #55
	BL	Neil_WriteC
	MOV	R1, R1, LSL#4
	SUBS	R2, R2, #1
	BNE	%BT01
	|
	Pull	"R0"
	SUB	sp, sp, #12
	MOV	R1, sp
	MOV	R2, #9			; includes room for terminator
	SWI	XOS_ConvertHex8
	ADDVS	R0, R0, #4		; print error message if there was one
	BL	Neil_Write0
	ADD	sp, sp, #12
	]
;
	Pull	"PC"

	[	hostvdu
Neil_HostVdu
        EntryS

	SWI	XHostFS_HostVdu
	SWI	XOS_WriteI+4		; VDU 4 mode in case no HostVdu

        EXITS

Neil_TubeVdu
        EntryS

	SWI	XHostFS_TubeVdu

        EXITS
	]

Neil_Write0
        EntryS  "R2"
	MOV	R2, #&10000000	; no limit on string length
	BL	Neil_Write0_R2max
        EXITS

Neil_Write0_R2max
        EntryS  "R0"
	MOV	R1, R0		; R1 -> string, R2 = max length (unsigned)
01	LDRB	R0, [R1], #1
	[	debug_nullterminatedstrings
	CMP	R0, #1
	|
	CMP	R0, #32		; terminate on any ctrl-char
	]
	SUBCSS	R2, R2, #1
	BLCS	Neil_WriteC
	BCS	%BT01
02
        EXITS

Neil_WriteC
	[	pdebug_module
        EntryS  "R0-R2"
	|
        EntryS  "R0, R1"
	]
	[	debug_nullterminatedstrings
	CMN	R0, #0		; clear C
	TEQ	R0, #""""	; TEQ without shift preserves C
	TEQNE	R0, #"|"
	TEQNE   R0, #"<"
	EOREQ	R0, R0, #"@"	; these characters don't need converting when prefixed by "|"
	TEQNE	R0, #127
	CMPNE	R0, #32		; CS if >= Space, except ", |, < and Delete
	TEQ	R0, #0
	TEQNE	R0, #10
	TEQNE	R0, #13
	CMPEQ	R0, #0		; now also CS if R0 was 0, 10 or 13
	EORCC	R1, R0, #"@"	; if non line-end control character, generate escaped character
	MOVCC	R0, #"|"	; and prefix with "|"
	BLCC	%FT01		; preserves flags, fortunately
	MOVCC   R0, R1
	B       %FT02
01
        ALTENTRY
02
	]
	LDR	R1, Neil_FileHandle
	CMP	R1, #0		; 0 => writec, -1 => none, >0 => file
	[	debug_module
	SWIEQ	XDebugIt_WriteC
	|
	[	pdebug_module
	MOVEQ	R0,#0
        ADDEQ   R1,R13,#Proc_RegOffset ; yuck :)
	MOVEQ	R2,#1
	SWIEQ	&6F900		; XPDebugM_Send
	|
	[	dadebug_module
	BGT	%FT01
	LDR	LR, dadebug_writec
	CMP	LR, #0		; undefined?
	BEQ	%FT01
	MOV	LR, PC
	LDR	PC, dadebug_writec
	CMP	R0, R0		; ensure not GT
01
	|
	SWIEQ	XOS_WriteC
	]
	]
	]
	SWIGT	XOS_BPut
        EXITS

Neil_NewLine
	ROUT
        EntryS  "R0-R2"
	LDR	R14, Neil_FileHandle
	CMP	R14, #0
	MOVEQ	R0, #13		 ; only write CR if not to a file
	BLEQ	Neil_WriteC
	MOV	R0, #10
	BL	Neil_WriteC
	[	debug_flush
	LDR	R1, Neil_FileHandle	; ensure bytes to the media after each line
	CMP	R1, #0
	BLE	%FT00
	MOV	R0, #"E"
	BL	Neil_WriteC
	MOV	R0, #"O"
	BL	Neil_WriteC
	MOV	R0, #"F"
	BL	Neil_WriteC
	MOV	R0, #255		; ensure bytes to media
	SWI	XOS_Args
	MOV	R0, #0			; read PTR in R2
	SWI	XOS_Args
	SUB	R2, R2, #3
	MOV	R0, #1			; write PTR in R2
	SWI	XOS_Args
00
	]
        EXITS

Neil_OpenFile
	ROUT
        Entry   "R0-R2"
	MOV	r0, #-1
	STR	r0, Neil_FileHandle	; -1 => no file debugging

	MOV	r0, #&C7		; open for update
	SWI	XOS_Find
        EXIT    VS
	TEQ	r0, #0			; object exists?
	BEQ	%20

	;File found---get the extent
	MOV	r1, r0			; file handle
	MOV	r0, #2			; read extent
	SWI	XOS_Args
        EXIT    VS
	;r2 = extent

	;Set the pointer to the extent
	MOV	r0, #1			; write ptr
	;r1 still has file handle
	;r2 still has extent
	SWI	XOS_Args
        EXIT    VS
	B	%30

20	;File not found---open a new one for output
	MOV	r0, #&87		; open for output
	SWI	XOS_Find
        EXIT    VS
	;r0 = file handle
	;r1 -> file name

	;Make it a text file
	Push	"r0"
	MOV	r0, #18
	MOV	r2, #&FF
	ORR	r2, r2, #&F00		; file type text
	SWI	XOS_File
	Pull	"r1"
        EXIT    VS

30	STR	r1, Neil_FileHandle
        EXIT

Neil_CloseFile
	ROUT
        EntryS  "R0-R1"
	MOV	R0, #0			; close file
	LDR	R1, Neil_FileHandle
	CMP	R1, #0
	STRGT	R0, Neil_FileHandle	; back to writec debugging
	SWIGT	XOS_Find
        EXITS

Neil_FileHandle	DCD	0		; default state => writec debugging

	[	dadebug_module
dadebug_writec	DCD	0		; workspace to hold routine pointer
	]

	]	; End debug

	MEND

	OPT	OldOpt

	END