; 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.
;
; > ExtraSWIs

;----------------------------------------------------------------------------------------
; ClaimProcVecSWI
;
;       In:     r0 = vector and flags
;                       bit     meaning
;                       0-7     vector number
;                               0 = 'Branch through 0' vector
;                               1 = Undefined instruction
;                               2 = SWI
;                               3 = Prefetch abort
;                               4 = Data abort
;                               5 = Address exception (only on ARM 2 & 3)
;                               6 = IRQ
;                               7+ = reserved for future use
;                       8       0 = release
;                               1 = claim
;                       9-31    reserved (set to 0)
;               r1 = replacement value
;               r2 = value which should currently be on vector (only needed for release)
;
;       Out:    r1 = value which has been replaced (only returned on claim)
;
;       Allows a module to attach itself to one of the processor vectors.
;
ClaimProcVecSWI ROUT
        Entry   "r3-r5"

        AND     r3, r0, #&FF            ; Get vector number.
        CMP     r3, #(ProcVec_End-ProcVec_Start):SHR:2
        ADRCSL  r0, ErrorBlock_BadClaimNum
        BCS     %FT30

        MOV     r4, r1                  ; r4 = replacement value
        LDR     r5, =ZeroPage+ProcVec_Start
        PHPSEI                          ; Disable IRQs while we mess around with vectors.

        TST     r0, #1:SHL:8
        LDRNE   r1, [r5, r3, LSL #2]!   ; If claiming then return current value (r5->vector to replace).
        BNE     %FT10

        LDR     r3, [r5, r3, LSL #2]!   ; Releasing so get current value (r5->vector to replace).
        TEQ     r2, r3                  ; Make sure it's what the caller thinks it is.
        ADRNEL  r0, ErrorBlock_NaffRelease
        BNE     %FT20
10
        STR     r4, [r5]                ; Store replacement value.
        PLP                             ; Restore IRQs.
        PullEnv
        ExitSWIHandler

20
        PLP                             ; Restore IRQs and return error.
30
  [ International
        BL      TranslateError
  ]
        PullEnv
        B       SLVK_SetV


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_UpdateMEMC: Read/write MEMC1 control register

SSETMEMC ROUT

        AND     r10, r0, r1
        LDR     r12, =ZeroPage
        WritePSRc SVC_mode+I_bit+F_bit, r0
        LDR     r0, [r12, #MEMC_CR_SoftCopy] ; return old value
        BIC     r11, r0, r1
        ORR     r11, r11, R10

        ; Force the top 12 bits to &036, on Archimedes hardware this would
        ; be the base address of the MEMC1 control register, with the value
        ; of the register occupying the bottom 20 bits, as the MEMC1 was not
        ; connected to the data bus. Keep doing so for compatibility with
        ; old programs.
        BIC     r11, r11, #&FF000000
        BIC     r11, r11, #&00F00000
        ORR     r11, r11, #&03600000

        STR     r11, [r12, #MEMC_CR_SoftCopy]

; mjs Oct 2000 kernel/HAL split
;
; The kernel itself should now never call this SWI, but grudgingly has
; to maintain at least bit 10 of soft copy
;
; Here, we only mimic action of bit 10 to control video/cursor DMA (eg. for ADFS)
; The whole OS_UpdateMEMC thing would ideally be withdrawn as archaic, but
; unfortunately has not even been deprecated up to now

; for reference, the bits of the MEMC1 control register are:
;
; bits 0,1 => unused
; bits 2,3 => page size, irrelevant since always 4K
; bits 4,5 => low ROM access time (mostly irrelevant but set it up anyway)
; bits 6,7 => hi  ROM access time (definitely irrelevant but set it up anyway)
; bits 8,9 => DRAM refresh control
; bit 10   => Video/cursor DMA enable
; bit 11   => Sound DMA enable
; bit 12   => OS mode

        Push  "r0,r1,r4, r14"
        TST   r11, #(1 :SHL: 10)
        MOVEQ r0, #1             ; blank (video DMA disable)
        MOVNE r0, #0             ; unblank (video DMA enable)
        MOV   r1, #0             ; no funny business with DPMS
        ADD   r4, r12, #VduDriverWorkSpace
        LDR   r4, [r4, #CurrentGraphicsVDriver]
        MOV   r4, r4, LSL #24
        ORR   r4, r4, #GraphicsV_SetBlank
        BL    CallGraphicsV
        Pull  "r0,r1,r4, r14"

        WritePSRc SVC_mode+I_bit, r11
        ExitSWIHandler


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       SWI OS_MMUControl
;
; in:   r0 = 0 (reason code 0, for modify control register)
;       r1 = EOR mask
;       r2 = AND mask
;
;       new control = ((old control AND r2) EOR r1)
;
; out:  r1 = old value
;       r2 = new value
;
; in:   r0 bits 1 to 28 = 0, bit 0 = 1  (reason code 1, for flush request)
;          r0 bit 31 set if cache(s) to be flushed
;          r0 bit 30 set if TLB(s) to be flushed
;          r0 bit 29 set if flush of entry only (else whole flush)
;          r0 bit 28 set if write buffer to be flushed (implied by bit 31)
;       r1 = entry specifier, if r0 bit 29 set
;       (currently, flushing by entry is ignored, and just does full flush)
;
; in:   r0 bits 0-7 = 2: reason code 2, read ARMop
;          r0 bits 15-8 = ARMop index
;
; out:  r0 = ARMop function ptr
;

MMUControlSWI   Entry
        BL      MMUControlSub
        PullEnv
        ORRVS   lr, lr, #V_bit
        ExitSWIHandler

MMUControlSub
        Push    lr
        AND     lr,r0,#&FF
        CMP     lr, #MMUCReason_Unknown
        ADDCC   pc, pc, lr, LSL #2
        B       MMUControl_Unknown
        B       MMUControl_ModifyControl ; -> See $MEMM_Type file
        B       MMUControl_Flush
        B       MMUControl_GetARMop

MMUControl_Unknown
        ADRL    r0, ErrorBlock_HeapBadReason
 [ International
        BL      TranslateError
 |
        SETV
 ]
        Pull    "pc"

MMUControl_Flush
        MOVS    r10, r0
        LDR     r12, =ZeroPage
        ARMop   Cache_CleanInvalidateAll,MI,,r12
        TST     r10,#&40000000
        ARMop   TLB_InvalidateAll,NE,,r12
        TST     r10,#&10000000
        ARMop   DSB_ReadWrite,NE,,r12
        ADDS    r0,r10,#0
        Pull    "pc"

MMUControl_GetARMop
        AND     r0, r0, #&FF00
        CMP     r0, #(ARMopPtrTable_End-ARMopPtrTable):SHL:6
        BHS     MMUControl_Unknown
        ADRL    lr, ARMopPtrTable
        LDR     r0, [lr, r0, LSR #6]
        LDR     r0, [r0]
        Pull    "pc"

;
; ---------------- XOS_SynchroniseCodeAreas implementation ---------------
;

;this SWI effectively implements IMB and IMBrange (Instruction Memory Barrier)
;for newer ARMs

;entry:
;   R0 = flags
;        bit 0 set ->  R1,R2 specify virtual address range to synchronise
;                      R1 = start address (word aligned, inclusive)
;                      R2 = end address (word aligned, inclusive)
;        bit 0 clear   synchronise entire virtual space
;        bits 1..31    reserved
;
;exit:
;   R0-R2 preserved
;
SyncCodeAreasSWI ROUT
        Push    "lr"
        BL      SyncCodeAreas
        Pull    "lr"                    ; no error return possible
        B       SLVK

SyncCodeAreas
        TST     R0,#1                   ; range variant of SWI?
        BEQ     SyncCodeAreasFull

SyncCodeAreasRange
        Push    "r0-r2, lr"
        MOV     r0, r1
        ADD     r1, r2, #4                 ;exclusive end address
        LDR     r2, =ZeroPage
        LDRB    lr, [r2, #DCache_LineLen]
        SUB     lr, lr, #1
        ADD     r1, r1, lr                 ;rounding up end address
        MVN     lr, lr
        AND     r0, r0, lr                 ;cache line aligned
        AND     r1, r1, lr                 ;cache line aligned
        ARMop   IMB_Range,,,r2
        Pull    "r0-r2, pc"

SyncCodeAreasFull
      [ SMP
        Entry   "r0-r2"
        LDR     r2, =ZeroPage
        ARMop   Cache_RangeThreshold,,,r2
        CMP     r0, #-1
        BNE     %FT90
        ; ARMops are in SMP-friendly mode, which means we have no (SMP-friendly) global IMB available
        ; Just clean application space and the RMA?
        LDR     r1, [r2, #AplWorkSize]
        MOV     r0, #32*1024
        ARMop   IMB_Range,,,r2
        MOV     r0, #ChangeDyn_RMA
        SWI     XOS_ReadDynamicArea
        ADD     r1, r1, r0
        ARMop   IMB_Range,,,r2
        EXIT
90
        ARMop   IMB_Full,,,r2
        EXIT
      |
        Entry   "r0"
        LDR     r0, =ZeroPage
        ARMop   IMB_Full,,,r0
        EXIT
      ]

        LTORG

        END