;
; setSlot.s
;
; Set up a WimpSlot
;
;  1995-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's core utilities (coreutils).
;
; Coreutils 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, or (at your option)
; any later version.
;
; Coreutils is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with Coreutils.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

		GET	libs:stream

;----- External dependencies ------------------------------------------------

		IMPORT	version

;----- Main code ------------------------------------------------------------

		AREA	|!!!Util$$Code|,CODE,READONLY

; --- main ---
;
; On entry:	R0 == pointer to command line
;		R1 == pointer to command tail
;		R12 == pointer to workspace
;		R13 == pointer to stack
;
; On exit:	May return an error
;
; Use:		Sets up a wimpslot.

main		ROUT

		; --- Find the command line ---

		STR	R14,[R12,#0]		;Store the link away
		ADR	R0,ss__keys		;Point to key tag definition
		ADD	R2,R12,#256		;Output into workspace
		MOV	R3,#256			;Allow 256 bytes for this
		SWI	XOS_ReadArgs		;Read the arguments
		BVS	ss__error		;If it failed, return error

		; --- Now process the arguments ---

		LDR	R0,[R12,#256+0]		;Load the `-help' switch
		CMP	R0,#0			;Is that set?
		BNE	ss__help		;Yes -- give some help then

		LDR	R0,[R12,#256+4]		;Load the base offset
		CMP	R0,#0			;Is that defined?
		ADREQ	R0,ss__usage		;No -- point to error
		BEQ	ss__error		;And return an error
		BL	ss__read		;Read this number
		MOV	R9,R0			;And look after the result

		LDR	R0,[R12,#256+8]		;Load the heap offset
		CMP	R0,#0			;Is that defined?
		BLNE	ss__read		;Yes -- read the value
		MOV	R10,R0			;And look after that too

		LDR	R0,[R12,#256+12]	;Load the flex offset
		CMP	R0,#0			;Is that defined?
		BLNE	ss__read		;Yes -- read the value
		ADD	R10,R10,R0		;And bump on the heap size

		LDR	R8,[R12,#256+16]	;Load the application name
		CMP	R8,#0			;Is that defined?
		ADREQ	R8,ss__app		;No -- use a default then

		; --- Read the memory limits imposed on me ---

		MOV	R0,#14			;Read application space
		MOV	R1,#0			;Don't provide new value
		SWI	XOS_ChangeEnvironment	;Read the value
		MOV	R7,R1			;Look after that then
		MOV	R0,#0			;Read the memory limit
		MOV	R1,#0			;Don't provide new value
		SWI	XOS_ChangeEnvironment	;Read the value
		MOV	R6,R1			;Look after that too
		CMP	R6,R7			;Are these the same?
		BCS	%f00			;We're OK -- skip onwards

		; --- We're running as a subprogram ---

		SUB	R14,R6,#&8000		;Find how much memory I have
		CMP	R14,R9			;Is there enough for base?
		BCC	ss__badSub		;No -- complain then

		MOV	R1,R7			;Extend the memory limit
		SWI	XOS_ChangeEnvironment	;Now I can extend the slot
		MOV	R0,#-1			;I want to read the size
		MOV	R1,#-1			;Leave next slot alone too
		SWI	XWimp_SlotSize		;Read the current slot size
		MOV	R5,R0			;Remember this value
		ADD	R0,R5,R10		;Add on the heap size
		MOV	R1,#-1			;Leave next slot alone still
		SWI	XWimp_SlotSize		;Try doing that	then
		SUB	R7,R0,R5		;Find how much we added
		MOV	R0,R5			;Restore to old value
		MOV	R1,#-1			;Leave next slot alone too
		SWI	XWimp_SlotSize		;Try doing that	then
		MOV	R0,#0			;Now put the memorylimit back
		MOV	R1,R6			;Get the old memory limit
		SWI	XOS_ChangeEnvironment	;Put that back now

		CMP	R7,R10			;Did we get enough memory?
		BCC	ss__noRoom		;No -- complain bitterly
		B	ss__end			;We finished OK then

		; --- We're in control here ---

00		ADD	R6,R9,R10		;Try to get it all
		MOV	R0,R6			;Get this value
		MOV	R1,#-1			;Don't change next slot
		SWI	XWimp_SlotSize		;Try doing that	then
		CMP	R0,R6			;Did we get enough?
		BCC	ss__noRoom		;No -- complain then
		MOV	R0,R9			;Now set up base slot
		MOV	R1,#-1			;Don't change next slot
		SWI	XWimp_SlotSize		;Try doing that	then
		B	ss__end			;And stop the program

ss__keys	DCB	"help/S,"		;0
		DCB	"base,"			;4
		DCB	"heap,"			;8
		DCB	"flex,"			;12
		DCB	"appName",0		;16

ss__usage	DCD	1
		DCB	"Syntax: SetSlot -base <size>[K|M] "
		DCB	"[-heap <size>[K|M]] [-flex <size>[K|M]] "
		DCB	"[-appName <name>]",0

ss__app		DCB	"Application",0

		LTORG

; --- ss__read ---
;
; On entry:	R0 == pointer to a string
;
; On exit:	R0 == numeric value read from string
;
; Use:		Reads a number represented by a string.  The number may be
;		postfixed by `K' or `M' to indicate that it's shifted left by
;		10 or 20 bits.  The resulting value is then aligned up to
;		the next multiple of the machine's page size.  Scary.

ss__read	ROUT

		STMFD	R13!,{R1,R2,R14}	;Save some registers

		; --- Read the numeric value ---

		MOV	R1,R0			;Point to the string
		MOV	R0,#10			;By default it's base 10
		SWI	XOS_ReadUnsigned	;Read that value
		BVS	ss__error		;Handle a possible error
		LDRB	R14,[R1],#1		;Find the terminating char
		ORR	R0,R14,#&20		;Force it to lowercase
		CMP	R0,#'m'			;Is value in megabytes?
		MOVEQ	R2,R2,LSL #10		;Yes -- shift it then
		CMPNE	R0,#'k'			;Is value in kilobytes?
		MOVEQ	R2,R2,LSL #10		;Yes -- shift it then
		LDREQB	R14,[R1],#1		;And get another byte
		CMP	R14,#&20		;Make sure this is ctrl char
		ADRCS	R0,ss__junk		;No -- point to error
		BCS	ss__error		;And raise the error

		; --- Now align it to size ---

		SWI	XOS_ReadMemMapInfo	;Find out about memory map
		BVS	ss__error		;Handle a possible error
		SUB	R14,R0,#1		;Turn page size into bitmask
		ADD	R0,R2,R14		;And proceed to align
		BIC	R0,R0,R14
		LDMFD	R13!,{R1,R2,PC}^	;Return to caller

ss__junk	DCD	1
		DCB	"Number not recognised",0

		LTORG

; --- ss__badSub ---
;
; On entry:	R9, R10 == memory requirements
;
; On exit:	--
;
; Use:		We didn't have enough memory to start as a subprogram, so
;		we complain to the user.

ss__badSub	ROUT

		ADD	R1,R12,#512		;Point to spare bit of memory
		MOV	R14,#1			;Get an error number
		STR	R14,[R1],#4		;Store at the beginning
		MOV	R0,R8			;Point to application name
		BL	ss__strcpy		;Copy that over
		ADR	R0,ss__badSubErr	;Point to the error
		BL	ss__strcpy		;Copy that too
		MOV	R0,R9,LSR #10		;Get the size in K
		MOV	R2,#256			;And a bogus buffer size
		SWI	XOS_ConvertInteger4	;Write that out too
		ADR	R0,ss__badSubEr2	;Point to rest of the text
		BL	ss__strcpy		;Copy that over
		ADD	R0,R12,#512		;Point to base of error
		B	ss__error		;Complain now

ss__badSubErr	DCB	" must have at least ",0
ss__badSubEr2	DCB	"K left in application space to start up as a "
		DCB	"subprogram",0

		LTORG

; --- ss__noRoom ---
;
; On entry:	R9, R10 == memory requirements
;
; On exit:	--
;
; Use:		We don't have enough memory for the heap or somesuch.

ss__noRoom	ROUT

		ADD	R1,R12,#512		;Point to spare bit of memory
		MOV	R14,#1			;Get an error number
		STR	R14,[R1],#4		;Store at the beginning
		MOV	R0,R8			;Point to application name
		BL	ss__strcpy		;Copy that over
		ADR	R0,ss__noRoomErr	;Point to the error
		BL	ss__strcpy		;Copy that too
		MOV	R0,R9,LSR #10		;Get the size in K
		ADD	R0,R0,R10,LSR #10	;Add on the heap size
		MOV	R2,#256			;And a bogus buffer size
		SWI	XOS_ConvertInteger4	;Write that out too
		ADR	R0,ss__noRoomEr2	;Point to rest of the text
		BL	ss__strcpy		;Copy that over
		ADD	R0,R12,#512		;Point to base of error
		B	ss__error		;Complain now

ss__noRoomErr	DCB	" needs at least ",0
ss__noRoomEr2	DCB	"K of memory available to start up",0

		LTORG

; --- ss__strcpy ---
;
; On entry:	R0 == pointer to source
;		R1 == pointer to destination
;
; On exit:	R1 == pointer to terminating null
;
; Use:		Copies a string.

ss__strcpy	ROUT

		STMFD	R13!,{R14}		;Save a register
00		LDRB	R14,[R0],#1		;Load a byte
		CMP	R14,#&20		;Is this the end?
		MOVCC	R14,#0			;Yes -- null terminate then
		STRB	R14,[R1],#1		;Store it in the output
		BCS	%b00			;Loop back if not done
		SUB	R1,R1,#1		;Point back at the null
		LDMFD	R13!,{PC}^		;And return to caller

		LTORG

; --- ss__help ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Gives help about setSlot.

ss__help	ROUT

		ADR	R0,ss__helpText		;Point to the help text
		MOV	R1,#0			;Use system dictionary
		LDR	R2,=version		;Find the version string
		ADR	R14,main		;Find my base address
		ADD	R2,R14,R2		;And get the string address
		SWI	XOS_PrettyPrint		;Display the text
		B	ss__end			;And return to caller

ss__helpText	DCB	"SetSlot ",27,0,13
		DCB	13
		DCB	"Syntax: SetSlot -base <size>[K|M] "
		DCB	"[-heap <size>[K|M]] [-flex <size>[K|M]] "
		DCB	"[-appName <name>]",13
		DCB	13
		DCB	"Ensures that there is enough memory for an "
		DCB	"application to start up.  The base size is the "
		DCB	"amount of memory for the main image.  The heap "
		DCB	"and flex sizes are added together to give the "
		DCB	"required initial size for the shifting heap.",13
		DCB	0

		LTORG

; --- ss__error ---
;
; On entry:	R0 == pointer to error
;
; On exit:	Doesn't
;
; Use:		Returns to the OS with an error.

ss__error	ROUT

		LDR	R14,[R12,#0]		;Load the return address
		ORRS	PC,R14,#V_flag		;And return

		LTORG

; --- ss__end ---
;
; On entry:	--
;
; On exit:	Doesn't
;
; Use:		Returns to the OS successfully.

ss__end		ROUT

		LDR	R14,[R12,#0]		;Load the return address
		BICS	PC,R14,#V_flag		;And return

		LTORG

;----- That's all, folks ----------------------------------------------------

		END
