        TTL     => MoreSWIs

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;  SubstituteArgs
;    in:  R0 -> arglist (space delimited args, terminated by 10,13,0)
;               top bit set => don't append unused part of line
;         R1 -> buffer
;         R2 =  bufflen
;         R3 -> string to mangle
;         R4 =  no of chars in $R3
;    out: R2 =  no of chars in buffer

XOS_SubstituteArgs_code ROUT

      TEQP    PC, #SVC_mode     ; enable IRQs

      Push   "R0-R8, lr"
      BIC     r0, r0, #&80000000
      ADD     R8, R4, R3

; try and get parameter positions.
; Items starting with " can have spaces in

      MOV   R6, #0       ; parameter number
      LDR   R12, =MacExStartPtrs
      LDR   R4, =MacExEndPtrs
35    LDRB  R5, [R0], #1
      CMP   R5, #" "
      BEQ   %BT35
      MOV   R2, #" "
      CMP   R5, #""""
      MOVEQ R2, #""""       ; quoted param
      CMP   r6, #10         ; "rest of line" item?
      MOVEQ r2, #-1         ; terminate on EOL only
      SUB   R0, R0, #1
      STR   R0, [R12, R6, LSL #2]
      CMP   r5, #""""
      ADDEQ R0, R0, #1
36    LDRB  R5, [R0], #1
      BL    suba_chktrm
      CMPNE R5, R2
      BNE   %BT36
      CMP   R5, #""""
      LDREQB R5, [R0]
      CMPEQ R5, #""""   ; check for "" in string
      ADDEQ R0, R0, #1
      BEQ   %BT36
      CMP   R2, #""""
      SUBNE R0, R0, #1
      STR   R0, [R4, R6, LSL #2]
      ADD   R6, R6, #1
      CMP   R6, #11           ; Parameters 0-9 and a "rest" set.
      BNE   %BT35

; Keep track of highest param used, so can tack any unused stuff on end.
; R3 points at string to get chars from
; R12 at start ptrs
; R4 at end ptrs

      MOV    R6, #0          ; count.
      MOV    R7, #0          ; highest param used.
      LDR    R2, [stack, #4*2]
37    BL     suba_getchar
      BEQ    %FT41
      CMP    R5, #"%"
      BEQ    %FT44
38    BL     suba_addchar
      B      %BT37

PCnotparm
      ADD    R5, R5, #"0"
      MOV    R11, R5
      MOV    R5, #"%"
      BL     suba_addchar
      MOV    R5, R11
      B      %BT38

44    BL     suba_getchar
      MOVEQ  R5, #"%"
      BEQ    %FT40
      CMP    R5, #"%"
      BEQ    %BT38
      CMP    R5, #"*"
      BEQ    DoStarParams
      SUBS   R5, R5, #"0"
      BMI    PCnotparm
      CMP    R5, #9
      BGT    PCnotparm

; itsa parameter! Get ptrs from R12, R4
      CMP    R5, R7
      ADDGE  R7, R5, #1
      LDR    R11, [R4, R5, LSL #2]
CopyToR11FromParamR5
      LDR    R10, [R12, R5, LSL #2]  ; start ptr
39    LDRB   R5, [R10], #1
      CMP    R10, R11
      BGT    %BT37
      BL     suba_addchar
      B      %BT39

DoStarParams ; had %* : find limits to copy between
      BL     suba_getchar
      BEQ    PCStarTerminates
      SUBS   R5, R5, #"0"
      BMI    PCStarNoDigit
      CMP    R5, #9
      MOVLE  R7, #11                  ; flag * used
      LDRLE  R11, [R4, #10*4]         ; always to EOL
      BLE    CopyToR11FromParamR5
PCStarNoDigit
      ADD    R5, R5, #"0"
      MOV    R11, R5
      MOV    R5, #"%"
      BL     suba_addchar
      MOV    R5, #"*"
      BL     suba_addchar
      MOV    R5, R11
      B      %BT38

PCStarTerminates
      MOV    R5, #"%"
      BL     suba_addchar
      MOV    R5, #"*"
40    BL     suba_addchar
41    CMP    r7, #11
      LDREQ  r12, [r4, #10*4]        ; no more to copy
      BEQ    %FT42
      LDR    r0, [stack]
      CMP    r0, #0
      LDRPL  R12, [R12, R7, LSL #2]  ; ptr to rest of command line : copy
      LDRMI  r12, [r4, #10*4]        ; caller wants no appending.
42    LDRB   R5, [R12], #1
      BL     suba_addchar
      BL     suba_chktrm
      BNE    %BT42

      STR    R6, [stack, #4*2]
      Pull  "R0-R8, lr"
      ExitSWIHandler

suba_addchar
      ADD    R6, R6, #1
      CMP    R6, R2
      STRNEB R5, [R1], #1
      MOVNES PC, lr

      ADRL   R0, ErrorBlock_BuffOverflow
      STR    R0, [stack]
      Pull  "R0-R8, lr"
      B     SLVK_SetV

suba_getchar
      CMP    R3, R8
      LDRNEB R5, [R3], #1
      MOV    PC, lr

suba_chktrm
      CMP   R5, #13
      CMPNE R5, #10
      CMPNE R5, #0
      MOV   PC, lr

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Take R0 as pointer to null-terminated string, print it
; with line breaks before words that won't fit on the current line.
; CR forces a newline. TAB=tab to next column of 8. CHR$31 = hard space
; <27,n> => substitute nth dictionary entry:
;  dictionary is pointed at by r1, consists of a list of null-terminated
;  strings, with preceding length bytes.
; 0th dictentry => use string at r2.

XOS_PrettyPrint_code ROUT

; Inside here, r1 is the current string pointer
;              R3 is the linelength to format to
;              R4 is the current position in the line.
;              r6 is the return addr in word counting
;              r7 is the r1 restore value in reading word length
;              r8 is used in dictionary selection in getbytepp
;              r9 is the stack restoration level for exiting.
;              r11 is the dictionary pointer (0 means use MOS dict)
;              r12 is the special token pointer

          TEQP    PC, #SVC_mode

          Push   "r0-r9, lr"

          BL      ReadWindowWidth    ; read linelength
          MOV     R3, R0
          MOV     R0, #165           ; read output cursor
          SWI     XOS_Byte
          ORR     R4, R1, #&80000000 ; no leading space even if in line.
          LDMFD   stack, {r1, r11, r12}   ; reload strptr, dictptr, tokptr
          CMP     r11, #0
          ADREQL  r11, MOSdictionary
          MOV     r9, stack

; loop over all words
01        BL      getwordlength
          CMP     R2, #0
          BLEQ    getbytepp
          BEQ     %FT21                ; null word - test for done

          CMP     R4, #0
          ADDGT   R2, R2, #1           ; allow for separator
          ADD     R0, R2, R4
          BIC     R0, R0, #&80000000   ; clear R4 flag
          CMP     R0, R3
          BLE     %FT10
          CMP     R4, #0
          SUBGT   R2, R2, #1          ; remove leading space length
          MOV     R4, #0              ; if word too long to fit, do newline
          SWI     XOS_NewLine
          BVS     exitpp

10        CMP     R4, #0
          BIC     R4, R4, #&80000000  ; clear "no leading space" flag
          ADD     R4, R4, R2
          SUBGT   R2, R2, #1
          SWIGT   XOS_WriteI+" "    ; output separator if not 1st on line
          BVS     exitpp
          
04        BL      getbytepp
          CMP     R0, #31           ; hard space?
          MOVEQ   R0, #" "
          SWI     XOS_WriteC
          BVS     exitpp
          SUBS    R2, R2, #1
          BNE     %BT04

21        CMP     R0, #13
          MOVEQ   R4, #0
          SWIEQ   XOS_NewLine
          BVS     exitpp

          CMP     R0, #TAB
          BEQ     %FT20
          CMP     R0, #0
          BNE     %BT01

exitpp    MOV     stack, r9
          STRVS   r0, [stack]
          Pull   "r0-r9,lr"
          B      SLVK_TestV

; TAB had: align to next multiple of 8
20        BIC     R4, R4, #&80000000
   ; first want to get next word length, to see if it's worth doing
          ADD     R5, R4, #8
          BIC     R5, R5, #7
          SUB     R5, R5, R4           ; spaces for this tab

24        BL      getwordlength
          CMP     R2, #0
          BNE     %FT23              ; got the word
          BL      getbytepp
          CMP     R0, #13
          BEQ     %BT21              ; TAB, CR - whalley!
          CMP     R0, #TAB
          SUBNE   R5, R5, #1         ; leading spaces, crap ignored
          ADDEQ   R5, R5, #8         ; multiple tabs OK tho.
          CMP     r0, #0             ; terminator?
          BNE     %BT24              ; only case to allow zero-length word
          SUB     r1, r1, #1         ; we know this rewinds OK

23        ADD     R0, R4, R5
          ADD     R0, R0, R2
          CMP     R0, R3
          MOVGT   R0, #13           ; next tab stop too far : newline
          BGT     %BT21
22        SWI     XOS_WriteI+" "
          BVS     exitpp
          ADD     R4, R4, #1
          SUBS    r5, r5, #1
          BNE     %BT22
          ORR     R4, R4, #&80000000 ; set top bit to disable leading space
          B       %BT01

getwordlength
          MOV     r6, lr
          MOV     r10, r9            ; first copy context
          MOV     r2, stack
          MOV     r7, r1
copycontextpp
          CMP     r9, r2
          LDRNE   r0, [r9, #-4]!
          Push    r0, NE
          BNE     copycontextpp

          MOV     r2, #0             ; word length
02        BL      getbytepp
          CMP     R0, #31
          CMPNE   R0, #" "+1
          ADDGE   r2, r2, #1
          BGE     %BT02
          MOV     r1, r7
          MOV     stack, r9
          MOV     r9, r10
          MOV     pc, r6

getbytepp LDRB    r0, [r1], #1
          CMP     r0, #TokenEscapeChar
          BEQ     gettokenpp
          CMP     r0, #0
          MOVNES  pc, lr
          CMP     stack, r9
          MOVHSS  pc, lr
          Pull    r1                ; back to previous token
          B       getbytepp

gettokenpp
          LDRB    r0, [r1], #1      ; tokno
          Push    r1                ; save context
          CMP     r0, #0
          MOVEQ   r1, r12
          BEQ     getbytepp
          MOV     r1, r11
gtoklp    SUBS    r0, r0, #1
          LDRNEB  r8, [r1]
          ADDNE   r1, r1, r8
          BNE     gtoklp
          ADD     r1, r1, #1
          B       getbytepp

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ReadWindowWidth ROUT    ; read "number of chars printable after Newline
                        ;       before we're on the next line"
        MOV     R0, #VduExt_WindowWidth
ReadVduVarForSam
        Push   "R0, R1, lr"      ; R1 reserves space
        MOV     R0, #-1
        STR     R0, [stack, #4]  ; overwrite R1 value
        MOV     R0, sp
        MOV     R1, sp
        SWI     XOS_ReadVduVariables
        Pull   "R0, R14, PC"

;*****************************************************************************
; R0 -> envstring, R1 -> 5 byte time

WriteEnv_SWICode ROUT ; for debugger use
        CMP     R0, #0
        BEQ     %FT01
        LDR     R10, =EnvString
        MOV     R11, R0
02      LDRB    R12, [R11], #1
        CMP     R12, #" "
        MOVLT   R12, #0
        STRB    R12, [R10], #1
        BGE     %BT02

01      CMP     R1, #0
        ExitSWIHandler EQ
        LDR     R10, =EnvTime
        MOV     R11, #4
03      LDRB    R12, [R1, R11]
        STRB    R12, [R10, R11]
        SUBS    R11, R11, #1
        BPL     %BT03
        ExitSWIHandler

;*****************************************************************************

; LET RdArgs() BE
;  R0 ptr to key defn string
;  R1 ptr to command line to decode
;  R2 ptr to workspace
;  R3 size of workspace
; Returns R3 size left

; Flags used in initial args decoding

AFlag       *  1:SHL:8     ; flags shifted up a byte; avoid looking like chars.
KFlag       *  1:SHL:9
SFlag       *  1:SHL:10
EFlag       *  1:SHL:11
GFlag       *  1:SHL:12
UnsetFlag   *  1:SHL:31
PresentFlag * -1 :AND::NOT:UnsetFlag
AbsentFlag  *  0

; Type flags

EndType     *   0
FlagType    *   1
KeywordType *   2
ItemType    *   3

RdArgs_SWICode ROUT

      TEQP    PC, #SVC_mode

      Push   "R4, R8, R9, lr"
      MOV     R10, R2             ; R10 points at next available word
      MOV     R12, R0
01    MOV     R11, #UnsetFlag
      SUBS    R3, R3, #4
      BMI     %FT99               ; silly bugger given whassock amount of space
      STR     R11, [R10], #4
02    LDRB    R11, [R12], #1
      CMP     R11, #"/"
      BNE     %FT03
      LDRB    R11, [R12], #1
      UpperCase R11, R9
      CMP     R11, #"A"
      MOVEQ   R11, #AFlag
      CMP     R11, #"K"
      MOVEQ   R11, #KFlag
      CMP     R11, #"S"
      MOVEQ   R11, #SFlag
      CMP     R11, #"E"
      MOVEQ   R11, #EFlag
      CMP     R11, #"G"
      MOVEQ   R11, #GFlag
      CMP     R11, #256
      LDRGE   R9, [R10, #-4]
      ORRGE   R9, R11, R9
      STRGE   R9, [R10, #-4]
03
      CMP     R11, #","
      BEQ     %BT01
      CMP     R11, #" "
      BGE     %BT02

; Initialisation complete: all flags set, R10 implies number of args.
      MOV     R8, R10

10    BL      RdItem
      BVS     %FT90
      CMP     R12, #KeywordType
      BNE     %FT11
      ADD     R11, R2, R4, LSL #2           ; keyword ptr
      BL      RdItem
      BVS     %FT90
      CMP     R12, #ItemType
      BNE     %FT98
      BL      SetKeyword
      BVS     %FT90
      B       %BT10

11    CMP     R12, #ItemType
      BNE     %FT12

; next positional arg := itemptr

      MOV     R11, R2
20    CMP     R11, R8
      BEQ     %FT98               ; no more positional args
      LDR     R12, [R11], #4
      TST     R12, #UnsetFlag
      BEQ     %BT20
      TST     R12, #KFlag :OR: SFlag
      BNE     %BT20
      SUB     R11, R11, #4
      BL      SetKeyword
      BVS     %FT90
      B       %BT10

12    CMP     R12, #EndType 
      BNE     %BT10

; postscan to check all /a args set.
      MOV     R12, R2
30    CMP     R12, R8
      BEQ     %FT31
      LDR     R11, [R12], #4
      TST     R11, #UnsetFlag
      BEQ     %BT30
      TST     R11, #AFlag
      BNE     %FT98          ; bum args error
      MOV     R11, #AbsentFlag
      STR     R11, [R12, #-4]     ; force "not present"
      B       %BT30

31
      Pull   "R4, R8, R9, lr"
      ExitSWIHandler

98    ADR     R0, ErrorBlock_BadParameters
      B       %FT90

99    ADRL    R0, ErrorBlock_BuffOverflow
90
      Pull   "R4, R8, R9, lr"
      B      SLVK_SetV

      MakeErrorBlock BadParameters
      MakeErrorBlock ArgRepeated
      ALIGN

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; RdItem: strips next item from command line
; In:  R1 -> cmd line
; Out: R1 updated
;      R12 contains type
;      R4 contains ptr for Item, argno for Flag/Keyword
; VS means buffer full
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

RdItem    ROUT
      Push  "R1, R7, R8, lr"
      MOV    R8, #0              ; not demanding new arg
01    LDRB   R12, [R1], #1
      CMP    R12, #" "
      BEQ    %BT01
      MOVLT  R12, #EndType
      Pull  "R1, R7, R8, lr", LT
      BICLTS PC, lr, #V_bit

      CMP    R12, #""""
      BEQ    ogoditsquotedargumentsagain

      CMP    R12, #"-"      ; options?
      BNE    %FT02          ; nope - boring item
05    BL     GetArg
      LDRVS  R1, [stack]
      BVS    %FT02          ; not recognised - boring item
      STR    R1, [stack]    ; new restore value.
      Push   PC             ; save EQ/NE
      LDR    R12, [R2, R4, LSL #2]
      TST    R12, #UnsetFlag
      ADREQ   R0, ErrorBlock_ArgRepeated
      ADDEQ  stack, stack, #4 ; discard PC
      Pull  "R1, R7, R8, lr", EQ
      ORREQS PC, lr, #V_bit

      ANDS   R12, R12, #SFlag
      MOVEQ  R12, #KeywordType
      ADDEQ  stack, stack, #4 ; discard PC
      Pull  "R1, R7, R8, lr",EQ
      BICEQS PC, lr, #V_bit

      MOV    R12, #PresentFlag
      STR    R12, [R2, R4, LSL #2]

; now deal with flag elision: if nextchar valid keyword char, rescan
      Pull   R12
      TST    R12, #Z_bit
      BEQ    %FT20          ; GetArg returned NE, so not single char abbr
      Push  "R2, R3"
      LDRB   R2, [R1]
      BL     CheckR2OKChar
      Pull  "R2, R3"
      MOVEQ  R8, #1        ; MUST get another arg
      BEQ    %BT05
20    MOV    R12, #FlagType
      Pull  "R1, R7, R8, lr"
      BICS   PC, lr, #V_bit

02    CMP    R8, #0
      ADRNE  R0, ErrorBlock_BadParameters
      Pull  "R1, R7, R8, lr", NE
      ORRNES PC, lr, #V_bit

   ; copy arg until <" "

      MOV    R7, #" "
      SUB    R1, R1, #1
06    MOV    R4, R10
03    LDRB   R12, [R1], #1
      CMP    R12, R7
      CMPNE  R12, #" "-1
      BLE    %FT04
10
      SUBS   R3, R3, #1
      STRPLB R12, [R10], #1
      BPL    %BT03
23
      ADRL   R0, ErrorBlock_BuffOverflow
      Pull  "R1, R7, R8, lr"
      ORRS   PC, lr, #V_bit     ; overflow

04    CMP    R7, #""""
      BNE    %FT07
      CMP    R12, #""""
      BNE    %FT08
      LDRB   R12, [R1], #1
      CMP    R12, #""""
      BEQ    %BT10
07    MOV    R12, #0            ; terminate
      SUBS   R3, R3, #1
      BMI    %BT23
      STRB   R12, [R10], #1
      MOV    R12, #ItemType
      SUB    R1, R1, #1
      STR    R1, [stack]
      Pull  "R1, R7, R8, lr"
      BICS   PC, lr, #V_bit

ogoditsquotedargumentsagain
      MOV    R7, #""""
      B      %BT06

08    ADRL   R0, ErrorBlock_BadString
      Pull  "R1, R7, R8, lr"
      ORRS   PC, lr, #V_bit

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; GetArg
; Look through keys: allow only full match on first pass, then
;  single char abbreviation on second pass
; Return V set if not key, EQ if single letter abbreviation
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

GetArg    ROUT
; In:  R0 ptr to keystring
;      R1 ptr to potential option.
; Out: VS if nomatch or
;      R1 updated
;      R4 argument number

      Push   "R0-R3, R5-R6, lr"
      MOV     R6, #-1             ; pass number
20    MOV     R4, #0

01    LDRB    R2, [R0], #1
      CMP     R2, #" "
      BEQ     %BT01

02    BL      CheckR2OKChar
      BNE     %FT03             ; matched in full
      LDRB    R3, [R1], #1
      UpperCase R2, R5
      UpperCase R3, R5
      CMP     R2, R3
      LDREQB  R2, [R0], #1
      BEQ     %BT02

      CMP     R6, #0
      BLT     %FT04

; 2nd pass: allow abbreviation
; IF single char abbreviation THEN success ELSE skip
      LDR     R2, [stack, #4]
      SUB     R2, R1, R2          ; length of match+1
      CMP     R2, #2
      SUBEQ   R1, R1, #1
      BEQ     %FT13               ; success

; skip to next keyword
04    LDRB    R2, [R0], #1
      CMP     R2, #" "
      BLT     %FT05
      CMP     R2, #","
      ADDEQ   R4, R4, #1
      CMPNE   R2, #"="
      BNE     %BT04
      LDR     R1, [stack, #4]
      B       %BT01

03  ; NE on first pass: check input string terminated OK
      LDRB    R2, [R1]            ; check for end of input word
      BL      CheckR2OKChar
      BNE     %FT13               ; yaay! full & correct match
      SUB     R0, R0, #1
      B       %BT04

05    ADDS    R6, R6, #1
      LDMLEFD stack, {R0, R1}
      BLE     %BT20
      Pull   "R0-R3, R5-R6, lr"
      ORRS    PC, lr, #V_bit      ; back with failure

13    STR     R1, [stack, #4]
      MVN     R0, #V_bit
      TSTP    R0, PC              ; clrV (just)
      Pull   "R0-R3, R5-R6, PC"   ; back with success

CheckR2OKChar ROUT
      CMP     R2, #"A"
      RSBGES  R3, R2, #"Z"
      ORRGES  PC, lr, #Z_bit
      CMP     R2, #"a"
      RSBGES  R3, R2, #"z"
      ORRGES  PC, lr, #Z_bit
      CMP     R2, #"0"
      RSBGES  R3, R2, #"9"
      ORRGES  PC, lr, #Z_bit
      CMP     R2, #"_"
      BICNES  PC, lr, #Z_bit
      ORRS    PC, lr, #Z_bit

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

SetKeyword    ROUT
; R11 ptr at keyword flags
; R4 ptr to value
      Push   "R0-R2, R5, R6, lr"
      LDR     R0, [R11]
      TST     R0, #EFlag :OR: GFlag
      STR     R4, [R11]           ; result will always be here anyway
      BEQ     %FT01
      SUB     R5, R10, R4         ; length of value
      ADD     R3, R3, R5          ; increase free space
      ADD     R2, R5, #11         ; round up to nearest word, then 1
      BIC     R2, R2, #3

      STR     stack, [stack, -R2]! ; reserve stack frame

      ADD     R2, stack, #4        ; input value ptr
03    LDRB    R6, [R4, R5]
      STRB    R6, [R2, R5]
      SUBS    R5, R5, #1
      BPL     %BT03               ; copy the value

      TST     R0, #EFlag
      MOV     R0, R2
      BNE     %FT02
      ADD     R1, R4, #2          ; free space pointer
      SUBS    R3, R3, #2
      MOV     R2, R3
      BMI     %FT04
      ORR     R2, R2, #1:SHL:31
      SWI     XOS_GSTrans
05    SUB     R3, R3, R2
      ADD     R10, R1, R2        ; update freespace pointer
      STRB    R2, [R1, #-2]
      MOV     R2, R2, LSR #8
      STRB    R2, [R1, #-1]
      BCS     %FT04

90    LDR     stack, [stack, #0]  ; unwind frame (and don't let AAsm use
      STRVS   R0, [stack]         ;   postindexed!!!)
      Pull   "R0-R2, R5, R6,lr"
      BICVCS  PC, lr, #V_bit
      ORRS    PC, lr, #V_bit

04    ADRL    R0, ErrorBlock_BuffOverflow
      SETV
      B       %BT90

02    ADD     R1, R4, #3          ; free space pointer
      SUBS    R2, R3, #3
      BMI     %BT04
      SWI     XOS_EvaluateExpression
      BVS     %BT90
      STRB    R1, [R4]
      CMP     R1, #0
      BNE     %BT05
      SUBS    R3, R3, #5
      BMI     %BT04
      STRB    R2, [R4, #1]
      MOV     R2, R2, LSR #8
      STRB    R2, [R4, #2]
      MOV     R2, R2, LSR #8
      STRB    R2, [R4, #3]
      MOV     R2, R2, LSR #8
      STRB    R2, [R4, #4]
      ADD     R10, R4, #5
      B       %BT90

01
      Pull   "R0-R2, R5, R6,lr"
      BICS    PC, lr, #V_bit


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ReadRAMFSLimits
; Return R0 start, R1 end (i.e. 1st byte out of area)

ReadRAMFSLimits_Code ROUT

        MOV     R0, #RAMDiscAddress
        MOV     R1, #0
        LDR     R1, [R1, #RAMDiscSize]
        ADD     R1, R1, R0
        ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; ExitAndDie
; r0-r2 parameters for Exit
; r3 pointer to module name

TerminateAndSodOff ROUT

        Push    "r0-r2"
        MOV     r10, #0
        STR     r10, [r10, #Curr_Active_Object]
        MOV     r1, r3
        MOV     r0, #ModHandReason_Delete
        SWI     XOS_Module
        Pull    "r0-r2"
        SWI     XOS_Exit

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; AddCallBack entry to callback vector
; r0 address to call
; r1 workspace ptr

AddCallBack_Code  ROUT

      Push   "r0-r3, lr"
      MOV     r3, #12
      BL      ClaimSysHeapNode
      BVS     %FT99
      Pull   "r0, r1"
      MOV     r10, #0
      TEQP    PC, #SVC_mode+I_bit       ; IRQs off while holding context.
      LDR     r3, [r10, #CallBack_Vector]
 [ True
      STR     r3, [r2, #0]
      STMIB   r2, {r0, r1}
      STR     r2, [r10, #CallBack_Vector]
      Pull   "r2, r3, lr"
 |
      STR     r3, [r2], #4
      STMIA   r2, {r0, r1}
      SUB     r2, r2, #4
      STR     r2, [r10, #CallBack_Vector]
      Pull   "r2, r3, lr"
      MOV     r10, #0
 ]
      LDRB    r11, [r10, #CallBack_Flag]
      ORR     r11, r11, #CBack_VectorReq
      STRB    r11, [r10, #CallBack_Flag]
      B       SLVK

99      STR     r0, [stack]
        Pull    "r0-r3, lr"
        B       SLVK_SetV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_Confirm

; If pointer visible, change pointer shape and look at mouse keys too.
;                     Flush mouse buffer first.
; Wait until key pressed.
; Returns: (lowercased) character in r0 (if mouse scanned, LH button = 'y',
;                                        other buttons = 'n')
; C set for Escape condition
; EQ set if r0 = 'y'

Confirm_Code ROUT

        TEQP    pc, #SVC_mode  ; enable IRQs

        Push   "r0-r3, lr"
        MOV     r0, #106
        MOV     r1, #255       ; read pointer state
        SWI     XOS_Byte
        BVS     confirm_error
        BIC     r2, r1, #&80
        MOV     r10, r1
        TST     r10, #15        ; any shape?
        BEQ     confirm_waitloop
        ADR     r2, mousepixels
        LDR     r1, =&001F1908 ; active point Y,X; height in rows; width(bytes)
        LDR     r0, =&03000000 ; shape number; 0 ; junk ; junk
        Push   "r0-r2"         ; build osword block
        ADD     r1, stack, #2
        MOV     r0, #21
        SWI     XOS_Word
        ADD     stack, stack, #12 ; discard block
        BVS     confirm_error
        MOV     r0, #106
        AND     r1, r10, #&80
        ORR     r1, r1, #3
        SWI     XOS_Byte
        BVS     confirm_error

        MOV     r0, #21
        MOV     r1, #9
        SWI     XOS_Byte         ; flush mouse buffer

        MOV     r0, #&C4
        MOV     r1, #0
        MOV     r2, #255
        SWI     XOS_Byte         ; read current repeat rate.
        MOV     r0, #0
        LDR     r0, [r0, #MetroGnome]
        ADD     r11, r1, r0      ; time to wait for

confirm_mouserepeat
        SWI     XOS_Mouse
        CMP     r2, #0           ; any buttons down?
        BEQ     confirm_waitloop

        CMP     r3, r11
        BMI     confirm_mouserepeat

confirm_waitloop
        MOV     r0, #129
        MOV     r1, #1
        MOV     r2, #0
        SWI     XOS_Byte
        BVS     confirm_error
        CMP     r2, #255
        BNE     confirm_gotkey

        TST     r10, #15
        BEQ     confirm_waitloop        ; no mouse scan wanted.

        SWI     XOS_Mouse
        BVS     confirm_error
        CMP     r2, #0
        BEQ     confirm_waitloop

        TST     r2, #4      ; LH button?
        MOVNE   r1, #"y"
        MOVEQ   r1, #"n"

confirm_gotkey
        CMP     r2, #&1B                  ; ESCAPE or normal char read ?
        ORREQ   r11, r1, #&100
        MOVNE   r11, r1
        LowerCase r11, r1

        MOV     r0, #106
        MOV     r1, r10
        SWI     XOS_Byte

        Pull   "r0-r3, lr"
        BIC     lr, lr, #C_bit :OR: Z_bit ; SKS. Punter lr has VClear
        AND     r0, r11, #&FF
        TST     r11, #&100                ; ESCAPE condition ? (SKS)
        ORRNE   lr, lr, #C_bit
        CMP     r0, #"y"
        ORREQ   lr, lr, #Z_bit
        B       SLVK

confirm_error
        STR     r0, [stack]
        Pull    "r0-r3, lr"
        B       SLVK_SetV

  MACRO
  munge  $bits
       LCLS   string
string SETS  "$bits"
       LCLS   byte
       LCLS   mbyte
  WHILE "$string" <> ""

mbyte  SETS string :LEFT: 4
string SETS string :RIGHT: (:LEN: string -4)

byte   SETS mbyte :RIGHT: 1
byte   SETS byte :CC: ((mbyte :RIGHT: 2) :LEFT: 1)
byte   SETS byte :CC: ((mbyte :RIGHT: 3) :LEFT: 1)
byte   SETS byte :CC: (mbyte :LEFT: 1)
  =  4_$byte
  WEND
  MEND

mousepixels
  munge   00000000333333333333333333333300
  munge   00000003111111111111111111111130
  munge   00000031111111111111111111111113
  munge   00000031133333313333331333333113
  munge   00000031133333313111131311113113
  munge   00000031133333313111131311113113
  munge   00000031133333313111131311113113
  munge   00000031133333313111131311113113
  munge   00000031133333313111131311113113
  munge   00000031133333313111131311113113
  munge   00000031133333313333331333333113
  munge   00000031111111111111111111111113
  munge   00000031111111111111111111111113
  munge   00000031131113111111111111111113
  munge   00000031131113111111111111111113
  munge   00000031131113111111111111111113
  munge   00000031113131111111111111111113
  munge   00000031111311111111111111111113
  munge   00000031111311111111111111111113
  munge   00000031111311111111111111111113
  munge   00000031111111111111111111111113
  munge   00000031111111111111111111111113
  munge   00000031111111111111111111111113
  munge   00000003111111111111111111111130
  munge   00000000333333333333333333333300

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r0 = continuation crc (0 to start)
;       r1 -> start of core
;       r2 -> end of core
;       r3 = increment (typically 1, 2 or 4), but can be -ve

; Out   r0 = crc so far

CRC_Code ROUT

        [ {TRUE}
        TEQP    pc, #SVC_mode           ; Could take a long time

        Push    "r3, r14"
        MOV     r10, r1
        MOV     r12, #&A000             ; CRC EOR pattern = &A001
        ORR     r12, r12, #&0001
10
        CMP     r10, r2                 ; Finished ?
        BEQ     %FA90                   ; Must be exact end, allows -ve offset

        LDRB    r14, [r10], r3
        EOR     r0, r0, r14             ; EOR the data with current crc lo
        CMP     r10, r2                 ; length might be odd so check again
        MOVEQ   r11, #8                 ; if equal then only do 8 bits
        BEQ     %FT20

        LDRB    r14, [r10], r3
        EOR     r0, r0, r14, LSL #8     ; EOR the data with current crc hi
        MOV     r11, #16                ; do 16 bits

20
        MOVS    r0, r0, LSR #1          ; acc >>= 1; CS/CC
        EORCS   r0, r0, r12             ; CS -> eor, CC -> ok
        SUBS    r11, r11, #1            ; 8 bits per byte
        BNE     %BT20

        B       %BT10

90      Pull    "r3, r14"
        ExitSWIHandler
        |
        TEQP    pc, #SVC_mode           ; Could take a long time

        Push    "r3, r4, lr"
        MOV     r10, r1
        MOV     r12, #&A000             ; CRC EOR pattern = &A001
        ORR     r12, r12, #&0001
        MOV     r14, #1                 ; A single bit to be shifted

10      CMP     r10, r2                 ; Finished ?
        BEQ     %FA90                   ; Must be exact end, allows -ve offset

        LDRB    r4, [r10], r3
        MOV     r11, #0                 ; Go round the bits

20      TST     r4, r14, LSL r11        ; Is data bit = carry ?; NE/EQ
        BEQ     %FT30

        MOVS    r0, r0, LSR #1          ; acc >>= 1; CS/CC
        EORCC   r0, r0, r12             ; NE, CC -> eor, NE, CS -> ok
        B       %FT40

30      MOVS    r0, r0, LSR #1          ; acc >>= 1; CS/CC
        EORCS   r0, r0, r12             ; EQ, CS -> eor, EQ, CC -> ok

40      ADD     r11, r11, #1            ; 8 bits per byte
        CMP     r11, #8
        BLO     %BT20

        B       %BT10

90      Pull    "r3, r4, lr"
        ExitSWIHandler
        ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        LNK     HeapSort
