;*******************************************************************************
; Title:	SwiModule
; Author:	Jens H. Ovesen
; Copyright:	(C) Jens H. Ovesen 1993
; Version:	1.00, 27 May 1993
;
; Updated by:	Philip Ludlam
; Changes:	Converted to ObjAsm source code
;		Made 32-bit compaible
;		Optimised for the XScale.
; Version:	1.02, 11 May 2003
;
;*******************************************************************************
; This program is free software; you can redistribute it and/or modify it
; under the terms of the GNU General Public License as published by the Free
; Software Foundation; either version 2 of the License, or (at your option)
; any later version.
;
; This program is distributed in the hope that it will be useful, but WITHOUT
; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
; FITNESS FOR APARTICULAR PURPOSE. See the GNU General Public License for more
; details.
;
; You should have received a copy of the GNU General Public License along with
; this program; if not, write to the Free Software Foundation, Inc., 59 Temple
; Place - Suite 330, Boston, MA 02111-1307, USA
;
;*******************************************************************************
;
; With thanks to Druck for:
; Armalyser 0.34 (21-Sep-2002) DEEJ Technolgy PLC

		GET	OSLib:oslib.hdr.OS
		GET	OSLib:oslib.hdr.OSModule
		GET	AsmLib2:hdr.RegsBoth
		GET	AsmLib2:hdr.Macros

		AREA	|!!!Module$$Header|, CODE, READONLY

		ENTRY

module_start
		DCD	0			; Start offset
		DCD	0			; Initialisation offset
		DCD	0			; Finalisation offset
		DCD	0			; Service call handler offset
		DCD	module_title		; Title string offset
		DCD	module_help		; Help string offset
		DCD	module_command		; Help and command table
		DCD	0			; SWI chunk base number
		DCD	0			; SWI handler code offset
		DCD	0			; SWI decoding table offset
		DCD	0			; SWI decoding code offset
		DCD	0			; MessageTrans file
		DCD	module_flags		; Module flags offset

module_title
		DCB	"SWIModule", 0
		ALIGN

module_help
		DCB	"SWI Module\t1.00 (27 May 1993)", 0
		ALIGN

module_flags
		DCD	1			; 32-bit compatible

module_command					; Command table:
		DCB	"SWI", 0		; Command
		ALIGN
		DCD	swi_code		; Code offset
		DCD	&20FF0001		; Infomation Word
		DCD	swi_syntax		; Syntax offset
		DCD	swi_help		; Help offset
		DCD	0			; End

swi_code
		STMFD	sp!, {r0-r12, lr}	; Entry Point, Command code
		MOV	r1, r0
		MOV	r0, #OSModule_Alloc	; r0 = 6
		MOV	r3, #&400		; r3 = 1024
		SWI	XOS_Module
		BVS	exit_error_swi_code
		MOV	wp, r2
		MOV	r2, #4
		STR	r2, |L0000023C|		; -> Word array: &00000004
		BL	|L00000134|
		BVS	exit_error_swi_code
		BL	|L000000E0|
		BL	|L00000290|
		BVS	exit_error_swi_code
		BL	|L000000F8|
		BVC	|L000000BC|
		LDR	r2, |L000000CC|		; -> Word: &00000000
		MOVS	r2, r2
		BEQ	exit_error_swi_code
|L000000BC|
		BL	|L0000041C|
		BVS	exit_error_swi_code
		BL	release_allocated_memory
		ClearFlags
		LDMFD	sp!, {r0-wp, pc}

|L000000CC|
		DCD	0

exit_error_swi_code
		BL	release_allocated_memory
		ADD	sp, sp, #4
		SetV
		LDMFD	sp!, {r1-wp, pc}

|L000000E0|					; does not preserve flags
		STMFD	sp!, {r0, r1, lr}	; Function entry
		ANDS	r1, r0, #&20000		; r1 = r0 & 131072
		STR	r1, |L000000CC|		; -> Word: &00000000
		ORREQ	r0, r0, #&20000		; r0 = r0 | 131072
		STR	r0, |L00000168|
		LDMFD	sp!, {r0, r1, pc}

|L000000F8|
		STMFD	sp!, {r0-r8, lr}	; Function entry
		STMFD	sp!, {r10}
		LDR	r10, |L00000168|
		CMP	r0, r0
		ADR	r8, |L00000374|		; -> Word array: &00000000
		LDMIA	r8, {r0-r7}

call_the_swi
		SWI	OS_CallASWI		; Call the SWI

|L0000011C|
		STMIA	r8, {r0-r7}		;~~
		LDMFD	sp!, {r10}
		MOV	r1, pc			; 26-bit: get flags (uses PSR)
		MRS	r1, CPSR		; 32-bit: get flags (uses PSR)
		MOV	r1, r1, LSR #28		; 26&32-bit: rotate down
		STR	r1, |L0000016C|		;~~ -> Word: &E24FE040
		BVS	|L0000011C.exit_error|
		LDMFD	sp!, {r0-r8, pc}	;~~ Function exit if VC

|L0000011C.exit_error|
		ADD	sp, sp, #4		;~~
		LDMFD	sp!, {r1-r8, pc}	;~~ Function exit, Ends

|L00000134|					; does not return flags
		STMFD	sp!, {r2, r3, lr}	; Function entry
		LDRB	r3, [r1, #0]
		BL	|L000003B8|
		BVS	|L00000134.exit|
		MOV	r2, r0
		TEQ	r3, #&22		; =""" (34)
		BEQ	|L0000015C|
		BL	|L00000170|
		MOVVC	r1, r2
		BVC	|L00000134.exit|
|L0000015C|
		SWI	XOS_SWINumberFromString
		MOV	r1, r2
|L00000134.exit|
		LDMFD	sp!, {r2, r3, pc}	; Function exit, Ends

|L00000168|
		DCD	&E1A0100C		; Word r/w (referenced)
|L0000016C|
		DCD	&E24FE040		;~~ Word -/w (referenced)

|L00000170|
		STMFD	sp!, {r1, r2, lr}	; Function entry
		MOV	R0, #&2A, 2
;		MOV	r0, #&80000000A		; base = 10 and the string must terminate with a control character or a space.
		SWI	XOS_ReadUnsigned
		MOV	r0, r2
		LDMFD	sp!, {r1, r2, pc}	; Function exit, Ends

|L00000184|
		STMFD	sp!, {r1-r4, lr}	; Function entry
		MOV	r3, #0
|L0000018C|
		LDRB	r0, [r1, r3]
		ADD	r3, r3, #1
		MOVS	r0, r0
		BNE	|L0000018C|
		MOV	r0, #OSModule_Alloc	; r0 = 6
		SWI	XOS_Module
		BVS	|L00000184.exit|
		ADR	r0, |L0000023C|		; -> Word array: &00000004
		LDR	r4, [r0, #0]
		STR	r2, [r0, r4]
		ADD	r4, r4, #4
		STR	r4, [r0, #0]
		SUB	r3, r3, #1
|L000001C0|
		LDRB	r0, [r1, r3]
		STRB	r0, [r2, r3]
		SUBS	r3, r3, #1
		BGE	|L000001C0|
		MOV	r0, r2
		ClearFlags
|L00000184.exit|
		LDMFD	sp!, {r1-r4, pc}

; is this an array for r0 through to r8?
; however it is r0 to r9 which can be used to pass parameters to SWIs
; but BASIC can only supply r0 to r7.
; hmm.
; for input?
|L0000023C|
		DCD	&00000004		; Word array r/w (referenced)
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-
		DCD	&00000000		;~~ Word array -/-

release_allocated_memory
		STMFD	sp!, {r0-r3, lr}	; Function entry
		ADR	r1, |L0000023C|		; -> Word array: &00000004
		LDR	r3, [r1, #0]
		MOV	r0, #OSModule_Free	; r0 = 7
|L00000270|
		SUBS	r3, r3, #4
		BEQ	|L00000270.eq|
		LDR	r2, [r1, r3]
		SWI	XOS_Module
		B	|L00000270|
|L00000270.eq|
		MOV	r0, #OSModule_Free	; r0 = 7
		MOV	r2, wp
		SWI	XOS_Module
		LDMFD	sp!, {r0-r3, pc}

; does the above code exit for the current use of the SWI command?
; the last thing it does is release the memory pointed to by the module private word
; this is normally a finalisation thing


|L00000290|					; does not preserve flags
		STMFD	sp!, {r0, r2-r5, lr}	; Function entry
		ADR	r2, |L00000374|		; -> Word array: &00000000
		MOV	r4, #8
|L0000029C|
		LDRB	r0, [r1, #-1]
		CMP	r0, #&20		; =" " (32)
		BLT	|L00000310|
		BL	|L00000324|
		BVS	exit_error_2
		BEQ	|L00000310|
		SUB	r1, r1, #1
|L000002B8|
		LDRB	r5, [r1, #1]!
		TEQ	r5, #&20		; =" " (32)
		BEQ	|L000002B8|
		BL	|L000003B8|
		BVS	exit_error_2
		MOV	r3, r0
		TEQ	r5, #&22		; =""" (34)
		BEQ	|L000002F8|
		LDRB	r5, [r1, #0]
		TEQ	r5, #&2D		; ="-" (45)
		ADDEQ	r1, r1, #1
		BL	|L00000170|
		TEQ	r5, #&2D		; ="-" (45)
		SUBEQ	r0, r0, r0, LSL #1
		BVC	|L000002FC|
		SUBEQ	r1, r1, #1
|L000002F8|
		BL	|L00000184|
|L000002FC|
		MOV	r1, r3
		BVS	exit_error_2
		STR	r0, [r2], #4
		SUBS	r4, r4, #1
		BNE	|L0000029C|
|L00000310|
		ClearFlags
		LDMFD	sp!, {r0, r2-r5, pc}

swi_syntax_block
		DCD	0
swi_syntax
		DCB	"Syntax:\n"
		DCB	"  *SWI <expression> [<expression>]^ [TO <variable> [<variable>]^ [;<variable>]]", 0
		ALIGN

exit_error_2
		ADD	sp, sp, #4
		LDMFD	sp!, {r2-r5, pc}	; V already set, so exit

|L00000324|					; does not preserve flags
		STMFD	sp!, {r1-r3, lr}	; Function entry
|L00000328|
		LDRB	r3, [r1], #1
		CMP	r3, #&20		; =" " (32)
		BEQ	|L00000328|
		ORR	r3, r3, #&20		; =" " (32)
		TEQ	r3, #&74		; ="t" (116)
		BNE	|L00000324.exit|
		LDRB	r3, [r1, #0]
		ORR	r3, r3, #&20		; =" " (32)
		TEQ	r3, #&6F		; ="o" (111)
		BNE	|L00000324.exit|
|L00000350|
		LDRB	r3, [r1, #1]!
		CMP	r3, #&20		; =" " (32)
		BEQ	|L00000350|
		BLT	exit_error_syntax_string
		TEQ	r3, r3
|L00000324.exit|
		LDMFD	sp!, {r1-r3, pc}	; Function exit, Ends

exit_error_syntax_string
		ADR	r0, swi_syntax_block
		SetV
		LDMFD	sp!, {r1-r3, pc}

; see L0000023C but for output?
|L00000374|
		DCD	&00000000		; Word array r/- (referenced)
		DCD	&00000000		; Word array r/-
		DCD	&00000000		; Word array r/-
		DCD	&00000000		; Word array r/-
		DCD	&00000000		; Word array r/-
		DCD	&00000000		; Word array r/-
		DCD	&00000000		; Word array r/-
		DCD	&00000000		; Word array r/-

gstrans_error_message
		DCD	0
		DCB	"Unexpected r1=0 in OS_GSTrans", 0
		ALIGN

gstrans_error
		ADR	r0, gstrans_error_message
		SetV
		LDMFD	sp!, {r2, r3, pc}

|L000003B8|					; sets/clears V on exit
		STMFD	sp!, {r2, r3, lr}	; Function entry
		MOV	r4, r1
		MOV	r0, r1			; pointer to source string
		MOV	r1, wp			; pointer to destination buffer
		MOV	r2, #&200		; r2 = 512
		ORR	r2, r2, #&20000000	; flag specifies that a space can be a string terminator
		SWI	XOS_GSTrans
		BVS	|L000003B8.exit.vs|
		TEQ	r1, #0
		BEQ	gstrans_error
		MOV	r3, #0
		STRB	r3, [r1, r2]
		LDRB	r3, [r0, #-1]
		CMP	r3, #&20		; =" " (32)
		BLE	|L000003B8.exit.vc|
		SUB	r0, r0, #1
|L00000400|
		LDRB	r3, [r0, #-1]
		CMP	r3, #&22		; =""" (34)
		BEQ	|L000003B8.exit.vc|
		CMP	r3, #&20		; =" " (32)
		SUBGT	r0, r0, #1
		BGT	|L00000400|
|L000003B8.exit.vc|
		ClearFlags
|L000003B8.exit.vs|
		LDMFD	sp!, {r2, r3, pc}

|L0000041C|
		STMFD	sp!, {r0, r2-r4, lr}	; Function entry
		SUB	r1, r1, #1
|L00000424|
		LDRB	r2, [r1, #1]!
		CMP	r2, #&20		; =" " (32)
		BEQ	|L00000424|
		BLT	|L00000474|
		BL	|L00000324|
		BNE	|L00000474|
		BL	|L000004BC|
		BLT	|L0000041C.exit_error.vc|
		ADR	r2, |L00000374|		; -> Word array: &00000000
		MOV	r4, #8
|L0000044C|
		LDRB	r0, [r1, #0]
		TEQ	r0, #&3B		; =";" (59)
		BEQ	|L00000488|
		BL	|L000004E0|
		BVS	|L0000041C.exit_error.vs|
		ADD	r2, r2, #4
		SUBS	r4, r4, #1
		BEQ	|L00000474|
		BL	|L000004BC|
		BGT	|L0000044C|
|L00000474|
		ClearFlags
		LDMFD	sp!, {r0, r2-r4, pc}
|L0000041C.exit_error.vc|
		SetV
|L0000041C.exit_error.vs|
		ADD	sp, sp, #4
		LDMFD	sp!, {r2-r4, pc}

|L00000488|
		LDRB	r0, [r1, #1]!
		CMP	r0, #&20		; =" " (32)
		BEQ	|L00000488|
		ADRLT	r0, swi_syntax_block
		BLT	|L0000041C.exit_error.vc|
		MOV	r0, r1
		[	:DEF: DEBUG
		ADRL	r1, |L0000016C|		; -> Word: &E24FE040
		|
		ADR	r1, |L0000016C|		; -> Word: &E24FE040
		]
		MOV	r2, #4
		MOV	r3, #0
		MOV	r4, #OS_VartypeNumber	; r4 = 1
		SWI	XOS_SetVarVal
		BVC	|L00000474|
		B	|L0000041C.exit_error.vs| ; Ends

|L000004BC|					; does not preserve flags
		STMFD	sp!, {r0, lr}		; Function entry
|L000004C0|
		LDRB	r0, [r1, #1]!
		CMP	r0, #&20		; =" " (32)
		BGT	|L000004C0|
		BLT	|L000004C0.exit|
|L000004D0|
		LDRB	r0, [r1, #1]!
		CMP	r0, #&20		; =" " (32)
		BEQ	|L000004D0|
|L000004C0.exit|
		LDMFD	sp!, {r0, pc}		; Function exit, Ends

; On Entry:
;   r1 -> variable name on command line
;   r2 = memory address of ?

|L000004E0|					; sets/clears V on exit
		STMFD	sp!, {r0-r5, lr}	; Function entry
		MOV	r0, r1
		MOV	r1, r2
		MOV	r3, r0
		MOV	r4, #1
|L000004F4|
		LDRB	r5, [r3], #1
		CMP	r5, #&24		; ="$" (36)
		MOVEQ	r4, #0
		CMP	r5, #&20		; =" " (32)
		BGT	|L000004F4|
		TEQ	r4, #0

		MOVNE	r2, #4
		BNE	|L000004E0.setvar|

		MOV	r5, r0
		LDR	r1, [r1, #0]
		ADD	r3, wp, #&200		; r3 = wp + 256
|L00000520|
		MOV	r0, r1
		SWI	XOS_ValidateAddress
		ADRCS	r0, invalid_address
		BCS	|L000004E0.exit_error.vc|
		LDRB	r0, [r1], #1
		TEQ	r0, #0
		TEQNE	r0, #&0A		; =10
		TEQNE	r0, #&0D		; =13
		BEQ	|L00000568|
		TEQ	r0, #&3C		; ="<" (60)
		TEQNE	r0, #&7C		; ="|" (124)
		TEQNE	r0, #&22		; =""" (34)
		STRNEB	r0, [r3], #1
		BNE	|L00000520|
		STRB	r0, [r3, #1]
		MOV	r0, #&7C		; ="|" (124)
		STRB	r0, [r3], #2
		B	|L00000520|		; Ends
|L00000568|
		MOV	r0, #&0D		; =13
		STRB	r0, [r3], #1
		MOV	r0, r5
		ADD	r1, wp, #&200		; r1 = wp + 256
		SUB	r2, r3, r1
|L000004E0.setvar|
		MOV	r3, #0
		SWI	XOS_SetVarVal
		BVS	|L000004E0.exit_error.vs|
		LDMFD	sp!, {r0-r5, pc}
|L000004E0.exit_error.vc|
		SetV
|L000004E0.exit_error.vs|
		ADD	sp, sp, #4
		LDMFD	sp!, {r1-r5, lr}

invalid_address
		DCD	0
		DCB	"Not a valid address", 0
		ALIGN

swi_help
		MOV	r11, lr			; copy lr
		ADR	r0, swi_syntax
		SWI	XOS_Write0
		SWI	XOS_NewLine
		ADR	r0, swi_help_full
		MOV	pc, r11

swi_help_full
		DCB	"\r"
		DCB	"<expression> is a string that is OS_GSTrans'ed before it's read. If it has \"\" around it or it can't be read as a number, it's expected to be a string. Otherwise it's read as a number value.\r"
		DCB	"<variable> is a system variable. If a '$' is found in <variable>, the register is expected to be a pointer to a string, and the system variable will be created as a String type from that register, otherwise it will be created as a Number type.\r\r"
		DCB	"Please be aware that the machine may hang up if you don't know what you're doing.\r\r"
		DCB	"Examples:\r"
		DCB	31,31,"*SWI \"OS_ReadLine\" \"12345678901\" 10 32 126 to input$ length\r"
		DCB	31,31,"*SWI XOS_CLI \"cat $.$\" to ;flags\r"
		DCB	31,31,"*SWI <my$swi> <my$param> to my$output ; flags\r\r"
		DCB	"SwiModule was made by Jens H. Ovesen, 27 May 1993, Odense Denmark.\r"
		DCB	"It was made 32-bit compatible by Philip Ludlam, 9 December 2002.\r"
		DCB	"This is version 1.02.\r", 0

licence		DCB	" Jens H. Ovesen, 1993. Licence: GPL."
		ALIGN

		END

;--------------------------------
;Statistics were:
;--------------------------------
;Size in words   :    559  100.0%
;Code            :    281   50.3%
;  surmised      :      6    2.1%
;  uses PSR      :     18    6.4%
;  not ARM2/3    :      0    0.0%
;  not 32 bit    :     17    6.0%
;  unpredictable :      1    0.4%
;Data            :    278   49.7%
;  surmised      :    204   73.4%
;Warnings        :      1    0.4%
;Unidentified    :      0    0.0%
;--------------------------------
;
;--------------------------------
;Statistics are now:
;--------------------------------
;Size in words   :    579  100.0%
;Code            :    287   49.6%
;  surmised      :      9    3.1%
;  uses PSR      :      1    0.3%
;  not ARM2/3    :      1    0.3%
;  not 32 bit    :      0    0.0%
;  unpredictable :      0    0.0%
;Data            :    292   50.4%
;  surmised      :    116   39.7%
;Warnings        :      2    0.7%
;Unidentified    :      0    0.0%
;--------------------------------
