; 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.
;
; Kernel.Messages
;
; This file deals with translating text and errors in an international
; kernel.
;
;
; TranslateError
; Entry:
;       R0 = Pointer to error block (Error number followed by token:default).
; Exit
;       R0 = pointer to error block to use.
;            If the error semaphore is set a pointer to the original block is
;            returned.
;       V Set.
;
TranslateError_VClear  ROUT
        Push    "r4,LR"
        MOV     r4,#0
        BL      TranslateError_UseR4
 [ No26bitCode
        CLRV
        Pull    "r4,PC"
 |
        Pull    "r4,PC",,^
 ]

TranslateError  ROUT
        Push    "r4,LR"
        MOV     r4,#0
        BL      TranslateError_UseR4
        Pull    "r4,PC"

TranslateError_UseR4
        Push    "R8,R9,LR"
        mrs    ,R8,CPSR
        ORR     R8,R8,#V_bit                    ; V set ready :)

        MOV     LR,#0
        LDRB    LR, [LR, #ErrorSemaphore]
        TEQ     LR,#0
        BNE     %FT90

        BIC     R9, R8, #&0F
        ORR     R9, R9, #SVC_mode               ; SVC mode, preserve IRQ state
        msr    ,CPSR_c, R9

        Push    "R0-R7,R8,R9,LR"

        MOV     R5,#0
        MOV     R6,#0
        MOV     R7,#0
        MOV     R1,#-1                          ; We are looking up an error, don't bother
        STRB    R1, [R5, #ErrorSemaphore]       ; translating other errors.

  [ CacheCommonErrors
        BL      CheckCommonErrorCache           ; sets R9 to memory address for cached result
        MOVNE   R1,#0
        BNE     %FT80
        MOV     R2,R9                           ; 0 - or our cached area!
        MOV     R3,#256
  |
        MOV     R2,#0
  ]

        ADR     R1,KernelMessagesBlock+4
        SWI     XMessageTrans_ErrorLookup
        LDR     R14,[R0]
        LDR     R1,[SP]
        LDR     R1,[R1]
        CMP     R14,R1
        STREQ   R0,[SP]

        MOV     R1,#0                           ; To clear the semaphore
  [ CacheCommonErrors
        TEQNE   R9,#0                           ; Did we try to cache this message?
        STRNE   R1,[R9]                         ; blat out the error number
80
  ]
        STRB    R1, [R1 ,#ErrorSemaphore]       ; Clear error semaphore

        Pull    "R0-R7,R8,R9,LR"
90
        msr    ,CPSR_cf, R8                     ; Back to original mode, V set
        Pull    "R8,R9,PC"

  [ CacheCommonErrors
   ; This block MUST not be empty
CommonErrorAddresses
        &       ErrorBlock_BadNumb
        &       ErrorBlock_BuffOverflow
        &       ErrorBlock_VarNoRoom
        &       ErrorBlock_ChDynamNotAllMoved
        &       ErrorBlock_NaffRelease
EndCommonErrorAddresses

        GBLA    ECEACount
ECEACount SETA  (EndCommonErrorAddresses-CommonErrorAddresses)/4
        ASSERT  (EndCommonErrorAddresses <> CommonErrorAddresses)

        ! 0, "Requiring ":CC:(:STR:(ECEACount*256)):CC:" bytes for error cache"
        ! 0, "Cached error block pointer at ":CC::STR:CachedErrorBlocks

; This routine exits with Z clear if it can supply a cached translation; else must set Z
; so that the TranslateError_UseR4 routine continues to function and set R9 to the cache
; block to use for the result (or set R9 to zero to indicate no cacheing for this error)
CheckCommonErrorCache ROUT
        Entry   "r1-r3"
        CMP     r4, #1                      ; is R4 = 0?  If so, clear C for next instruction
        SBCS    r9, r4, r4                  ; R9=0,Z set - if R4 was >0, else R9=-1, Z clear
        EXIT    EQ
        LDR     r9, [r4, #KernelMessagesBlock] ; R4 guaranteed zero from above
        TEQ     r9, #0
        EXIT    EQ                          ; not initialised messages yet!  Exit R9=0, Z set
        LDR     r9, [r4, #CachedErrorBlocks]
        TEQ     r9, #0
        BLEQ    CommonErrorCacheInit
        EXIT    EQ
        ADR     lr, CommonErrorAddresses
        MOV     r2, #ECEACount - 1
10
        LDR     r1, [lr, r2, LSL #2]
        TEQ     r1, r0
        BEQ     %FT20
        SUBS    r2, r2, #1
        BPL     %BT10
        ; Set Z if message not found, set R9 zero to mark we don't want to cache this
        MOVS    r9, #0
        EXIT
20
        LDR     r1, [r9, r2, LSL #8]!
        ; Set Z if we don't have that error cached yet, clear it and copy the cached
        ; block to R0 if we do already have this message
        TEQ     r1, #0
        MOVNE   r0, r9
        EXIT

CommonErrorCacheInit
        Entry   "r0-r9"
        LDR     r3, =ECEACount*256
        BL      ClaimSysHeapNode
        MOVVS   r2, #0
        MOV     r3, #0
        STR     r2, [R3, #CachedErrorBlocks]

        GBLA    CECLoop
CECLoop SETA    0
        WHILE CECLoop < ECEACount
          STRVC r3, [r2, #CECLoop * 256]
CECLoop SETA    CECLoop+1
        WEND

        TEQ     r2, #0
        EXIT
  ]

;----------------------------------------------------------------------------------------
;
;WriteS_Translated
;Entry:
;       R14 -> Token.
;*NOTE*
;      MUST BE TOKEN:DEFAULT
;
;Exit:
;       Message printed
;       Returns to word after end of token.
;
WriteS_Translated       ROUT
 [ No26bitCode
        Push    "r0-r8,LR"
 |
        Push    "r0-r7,LR"
 ]
        MOV     r4,#0
        B       Int_WriteS_Translated_UseR4

WriteS_Translated_UseR4

 [ No26bitCode
        Push    "r0-r8,LR"
 |
        Push    "r0-r7,LR"
 ]

Int_WriteS_Translated_UseR4
 [ No26bitCode
        mrs    ,r8,CPSR
        MOV     r1,LR
 |
        BIC     r1,LR,#ARM_CC_Mask              ; r1 -> Token.
 ]
        MOV     r0,#0
        LDR     r0,[r0,#KernelMessagesBlock]
        CMP     r0,#0                           ; If no messages file, try the global one.
        ADRNE   r0,KernelMessagesBlock+4
        MOV     r2,#0                           ; Use message in place.
        MOV     r3,#0
        MOV     r5,#0
        MOV     r6,#0
        MOV     r7,#0                           ; No arguments.
        SWI     XMessageTrans_Lookup
        BVC     %FT01

        MOV     R2,R1                           ; MessageTrans not present or token not found.
00
        LDRB    r0,[r2],#1                      ; Skip to after ":"
        CMP     r0,#":"
        BNE     %BT00

; Now
; r1 -> terminator
; r2 -> message
; Print the message.

01
        LDRB    r0,[r2],#1                      ; Print all characters of message
        CMP     r0,#" "
        BLT     %FT02
        CMP     r0,#"%"
        SWINE   XOS_WriteC
        BNE     %BT01

        LDRB    r0,[r2],#1                      ; Found a %
        CMP     r0,#" "
        BLT     %FT02                           ; Trailing % sign!
        CMP     r0,#"0"
        SWINE   XOS_WriteI+"%"
        SWINE   XOS_WriteC
        BNE     %BT01                           ; Just in case it isn't %0

        CMP     r4,#0                           ; r4 = original parameter
        BEQ     %BT01

11
        LDRB    R0,[R4],#1
        CMP     R0,#" "
        SWIGE   XOS_WriteC
        BGE     %BT11
        B       %BT01
                                                ; Now skip to end of token.
02
 [ No26bitCode
        LDR     r1,[sp,#9*4]                    ; Get original token pointer
 |
        LDR     r1,[sp,#8*4]                    ; Get original token pointer
        BIC     r1,r1,#ARM_CC_Mask              ; r1 -> Token.
 ]
03
        LDRB    r0,[r1],#1
        CMP     r0,#32
        BGE     %BT03                           ; Skip to control character.
04
        CMP     r0,#0                           ; Print all control characters to terminating 0.
        SWINE   XOS_WriteC
        LDRNEB  r0,[r1],#1
        BNE     %BT04

; r1 now points at byte after end of token.

        ADD     r1,r1,#3                        ; Round up to next word.
        BIC     r1,r1,#3

 [ No26bitCode
        STR     r1,[sp,#9*4]                    ; Store back as return address on stack
        ORRVS   r8,r8,#V_bit
        msr    ,CPSR_f,r8

        Pull    "r0-r8,PC"                       ;Return.
 |
        LDR     r2,[sp,#8*4]
        AND     r2,r2,#ARM_CC_Mask              ; Just the flags and mode bits.
        ORR     r1,r1,r2
        ORRVS   r1,r1,#V_bit
        STR     r1,[sp,#8*4]                    ; Store back as return address on stack

        Pull    "r0-r7,PC",,^                    ;Return.
 ]

;----------------------------------------------------------------------------------------
;
;GSWriteS_Translated
;Entry:
;       R14 -> Token.
;*NOTE*
;      MUST BE TOKEN:DEFAULT
;
;Exit:
;       Message printed
;       Returns to word after end of token.
;
GSWriteS_Translated       ROUT
 [ No26bitCode
        Push    "r0-r8,LR"
 |
        Push    "r0-r7,LR"
 ]
        MOV     r4,#0
        B       Int_GSWriteS_Translated_UseR4

GSWriteS_Translated_UseR4

 [ No26bitCode
        Push    "r0-r8,LR"
 |
        Push    "r0-r7,LR"
 ]

Int_GSWriteS_Translated_UseR4
 [ No26bitCode
        mrs    ,r8,CPSR
        MOV     r1,LR
 |
        BIC     r1,LR,#ARM_CC_Mask              ; r1 -> Token.
 ]
        MOV     r0,#0
        LDR     r0,[r0,#KernelMessagesBlock]
        CMP     r0,#0                           ; If no messages file, try the global one.
        ADRNE   r0,KernelMessagesBlock+4
        LDR     r2,=GeneralMOSBuffer
        MOV     r3,#256
        MOV     r5,#0
        MOV     r6,#0
        MOV     r7,#0                           ; No arguments.
        SWI     XMessageTrans_GSLookup
        BVC     %FT01

        MOV     R2,R1                           ; MessageTrans not present or token not found.
00
        LDRB    r0,[r2],#1                      ; Skip to after ":"
        CMP     r0,#":"
        BNE     %BT00

; Now
; r1 -> terminator
; r2 -> message
; Print the message using OS_PrettyPrint.

01
        LDR     r0, =GeneralMOSBuffer
        MOV     r1, #0
        SWI     XOS_PrettyPrint
                                                ; Now skip to end of token.
02
 [ No26bitCode
        LDR     r1,[sp,#9*4]                    ; Get original token pointer
 |
        LDR     r1,[sp,#8*4]                    ; Get original token pointer
        BIC     r1,r1,#ARM_CC_Mask              ; r1 -> Token.
 ]
03
        LDRB    r0,[r1],#1
        CMP     r0,#0
        BNE     %BT03                           ; Skip to 0.

; r1 now points at byte after end of token.

        ADD     r1,r1,#3                        ; Round up to next word.
        BIC     r1,r1,#3

 [ No26bitCode
        STR     r1,[sp,#9*4]                    ; Store back as return address on stack
        ORRVS   r8,r8,#V_bit
        msr    ,CPSR_f,r8

        Pull    "r0-r8,PC"                       ;Return.
 |
        LDR     r2,[sp,#8*4]
        AND     r2,r2,#ARM_CC_Mask              ; Just the flags and mode bits.
        ORR     r1,r1,r2
        ORRVS   r1,r1,#V_bit
        STR     r1,[sp,#8*4]                    ; Store back as return address on stack

        Pull    "r0-r7,PC",,^                    ;Return.
 ]

;----------------------------------------------------------------------------------------
;FindToken
;
;Entry:
;       R0 -> Token.
;*NOTE*
;      MUST BE TOKEN:DEFAULT
;
;Exit:
;       r0 -> Message, or after the : if MessageTrans is dead.
;
;
FindToken      ROUT
 [ No26bitCode
        Push    "r0-r8,LR"
        mrs    ,r8,CPSR
 |
        Push    "r0-r7,LR"
 ]

        MOV     r1,r0
        MOV     r0,#0
        LDR     r0,[r0,#KernelMessagesBlock]
        CMP     r0,#0                           ; If no messages file, try the global one.
        ADRNE   r0,KernelMessagesBlock+4
        MOV     r2,#0
        MOV     r3,#0
        MOV     r4,#0
        MOV     r5,#0
        MOV     r6,#0
        MOV     r7,#0                           ; No arguments.
        SWI     XMessageTrans_Lookup
        BVC     %FT01

        MOV     R2,R1                           ; MessageTrans not present or token not found.
00
        LDRB    r0,[r2],#1                      ; Skip to after ":"
        CMP     r0,#":"
        BNE     %BT00
01
        STR     r2,[sp]

 [ No26bitCode
        msr    ,CPSR_f,r8
        Pull    "r0-r8,PC"
 |
        Pull    "r0-r7,PC",,^
 ]

;----------------------------------------------------------------------------------------
;Write0_Translated
;
;Entry:
;       R0 -> Token.
;*NOTE*
;      MUST BE TOKEN:DEFAULT
;
;Exit:
;        Message printed, r0->Message.
;
Write0_Translated ROUT
        EntryS  "r0,r1"
        BL      FindToken
        MOV     R1,R0
01
        LDRB    R0,[R1],#1
        CMP     R0,#31
        SWIGT   XOS_WriteC
        STRVS   r0,[SP]
        EXIT    VS
        BGT     %BT01

        EXITS

        END