; 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.
;
; > s.allocate

; handle allocate reason code

; entry:
;     R0 = 0 (reason code 0)
;     R1 = number of pages
;
; exit:
;     R1 = no. of pages actually allocated
;     R2 = handle for allocation, 0 if pages were requested but none could be claimed

allocate
        Push    "R0,R3,R4,LR"

;  Debug AMB,"allocate ",r0,r1

        MOV     R3,#AbsMaxAppSize
        SUB     R3,R3,#ApplicationStart
        MOV     R3,R3,LSR #Log2PageSize   ;R3 = absolute max app pages

        CMP     R1,R3
        MOVGT   R1,R3

;get handle for node
        LDR     R0,AMBNodeHandles
        LDR     R4,[R0]
        CMP     R4,#0            ;any handles available?
        BNE     %FT01

  ; give up
        Pull    "R0,R3,R4,LR"
        ADR     R0,err_nomorehandles
        B       SLVK_SetV

01
;get memory for node - from system heap
        MOV     R3,#(AMBNode_pages - AMBNode_id) ;size excluding page list
        ADD     R3,R3,R1,LSL #2                  ;plus one word per page
        BL      AMB_BlockClaim
        BVS     alloc_done

;remember handle in node
        STR     R4,[R2,#AMBNode_handle]

;init fields of new node
        LDR     R4,=AMBMagicNodeID
        STR     R4,[R2,#AMBNode_id]        ;magic id
        MOV     R4,#0
        STR     R4,[R2,#AMBNode_Npages]    ;number of pages = 0 (so far)
        MOV     R4,#ApplicationStart
        STR     R4,[R2,#AMBNode_startaddr]
        LDR     R4,=ZeroPage+AppSpaceDANode
        LDR     R4,[R4,#DANode_Flags]      ;Get the page flags from the DA.
        LDR     LR,=DynAreaFlags_AccessMask;Note that this is rather academic
        AND     R4,R4,LR                   ;because various bits of code ignore
        STR     R4,[R2,#AMBNode_PPL]       ;or overwrite these flags!

;do the actual MMU page allocation (grow from 0), for R1 pages, using node R2
        BL      growpages
        BVS     alloc_done

        CMP     R1,#0                    ;EQ status if we were asked for 0 pages
        LDR     R1,[R2,#AMBNode_Npages]  ;actual no. of pages we achieved
        BEQ     alloc_ok                 ;if asked for 0, regard as ok

        CMP     R1,#0
        BEQ     alloc_zeropages          ;achieving 0 pages is not ok

;ok, so remove handle from free list
alloc_ok
        LDR     R0,AMBNodeHandles
        LDR     R4,[R2,#AMBNode_handle]
        LDR     R3,[R0,R4,LSL #2]  ;next free handle
        STR     R3,[R0]            ;store as new first free handle
        STR     R2,[R0,R4,LSL #2]  ;and remember node address in handle array

;R2 -> new node - put it on front of list
        ADR     R3,AMBAnchorNode        ; R3 -> ank_node
        LDR     R4,[R3,#AMBNode_next]   ; R4 -> old_node (old front)
        STR     R4,[R2,#AMBNode_next]   ; new_next := old_node
        STR     R2,[R3,#AMBNode_next]   ; ank_next := new_node
        STR     R3,[R2,#AMBNode_prev]   ; new_prev := ank_node
        STR     R2,[R4,#AMBNode_prev]   ; old_prev := new_node

        LDR     R4,AMBNtasks
        ADD     R4,R4,#1
        STR     R4,AMBNtasks

        STR     R2,AMBMappedInNode       ;allocated node is also mapped in
        LDR     R2,[R2,#AMBNode_handle]  ;change address to handle
        CLRV

alloc_done
;  Debug AMB,"<alloc ",r1,r2
        STRVS   R0,[SP]
        Pull    "R0,R3,R4,LR"
        B       SLVK_TestV

;free page table space and return 0 handle
alloc_zeropages
        BL      AMB_BlockFree
        MOV     R1,#0
        MOV     R2,#0
        B       alloc_done

        LTORG

    END