OpenCores
URL https://opencores.org/ocsvn/rtf65002/rtf65002/trunk

Subversion Repositories rtf65002

[/] [rtf65002/] [trunk/] [software/] [asm/] [memory.asm] - Rev 40

Compare with Previous | Blame | View Log


; ============================================================================
;        __
;   \\__/ o\    (C) 2013, 2014  Robert Finch, Stratford
;    \  __ /    All rights reserved.
;     \/_//     robfinch<remove>@opencores.org
;       ||
;  
;
; This source file is free software: you can redistribute it and/or modify 
; it under the terms of the GNU Lesser General Public License as published 
; by the Free Software Foundation, either version 3 of the License, or     
; (at your option) any later version.                                      
;                                                                          
; This source file 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 this program.  If not, see <http://www.gnu.org/licenses/>.    
;                                                                          
; ============================================================================
;
MAX_VIRTUAL_PAGE        EQU             320
MAX_PHYSICAL_PAGE       EQU             2048
INV_PAGE        EQU     000             ; page number to use for invalid entries

;------------------------------------------------------------------------------
; InitMMU
;
; Initialize the 64 maps of the MMU.
; Initially all the maps are set the same:
; Virtual Page  Physical Page
; 000-319               000 (invalid page marker)
; 320-511               1856-2047
; Note that there are only 512 virtual pages per map, and 2048 real
; physical pages of memory. This limits maps to 32MB.
; This range includes the BIOS assigned stacks for the tasks and tasks
; virtual video buffers.
; Note that physical pages 0 to 1855 are not mapped, but do exist. They may
; be mapped into a task's address space as required.
; If changing the maps the last 192 pages (12MB) of the map should always point
; to the BIOS area. Don't change map entries 320-511 or the system may
; crash. The last 192 pages map the virtual memory to the same physical
; addresses so that the physical and virtual address are the same.
; If the rts at the end of this routine works, then memory was mapped
; successfully.
;
; System Memory Map (Physical Addresses)
; Page
; 0000                  BASIC ROM, scratch memory ( 1 page global)
; 0001-0063             unassigned (4MB - 63 pages)
; 0064-0191             Bitmap video memory (8 MB - 128 pages)
; 0192-0336             DOS usage, disk cache etc. (9.4MB - 145 pages)
; 0337-1855             Heap space (99MB - 1519 pages)
; 1856-1983             Virtual Screen buffers (8MB - 128 pages)
; 1984-2047             BIOS/OS area (4MB - 64 pages)
;       2032-2047               Stacks area (1MB - 16 pages)
; 65535                 BIOS ROM (64kB - 1 Page global)
; 261952-262015         I/O area (4MB - 64 pages global)
;------------------------------------------------------------------------------

        align   8
public InitMMU:
        lda             #1
        sta             MMU_KVMMU+1
        dea
        sta             MMU_KVMMU
immu1:
        sta             MMU_AKEY        ; set access key for map
        ldx             #0
immu2:
        ; set the first 320 pages to invalid page marker
        ; set the last 192 pages to physical page 1856-2047
        ld              r4,#INV_PAGE
        cpx             #320
        blo             immu3
        ld              r4,r2
        add             r4,r4,#1536     ; 1856-320
immu3:
        st              r4,MMU,x
        inx
        cpx             #512
        bne             immu2
        ina
        cmp             #64                     ; 64 MMU maps
        bne             immu1
        stz             MMU_OKEY        ; set operating key to map #0
        lda             #2
        sta             MMU_FUSE        ; set fuse to 2 clocks before mapping starts
        nop
        nop

;------------------------------------------------------------------------------
; Note that when switching the memory map, the stack address should not change
; as the virtual address was mapped to the physical one.
;------------------------------------------------------------------------------
;
        align   8
public EnableMMUMapping:
        pha
        lda             RunningTCB                      ; no need to enable mapping for Monitor/Debugger job
        lda             TCB_hJCB,r1
        cmp             #2
        blo             dmm2
        lda             #12                                     ; is there even an MMU present ?
        bmt             CONFIGREC
        beq             emm1
        lda             RunningTCB
        lda             TCB_hJCB,r1
        sta             MMU_OKEY                        ; select the mmu map for the job
        lda             #2
        sta             MMU_FUSE                        ; set fuse to 2 clocks before mapping starts
        lda             #1
        sta             MMU_MAPEN                       ; set MMU_MAPEN = 1
emm1:
        pla
        rts

public DisableMMUMapping:
        pha
dmm2:
        lda             #12                     ; is there even an MMU present ?
        bmt             CONFIGREC
        beq             dmm1
        stz             MMU_MAPEN
dmm1:
        pla
        rts

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
SetAKEYForCurrentJob:
        pha
        jsr             GetPtrCurrentJCB
        lda             JCB_Map,r1
        sta             MMU_AKEY
        pla
        rts

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
        align   8
public MemInit:
        lda             #1                                      ; initialize memory semaphore
        sta             mem_sema
        lda             #1519
        sta             nPagesFree

        ; Initialize the allocated page map to zero.
        lda             #64                             ; 64*32 = 2048 bits
        ldx             #0
        ldy             #PageMap
        stos
        ; Mark the last 192 pages as used (by the OS)
        ; 6-32 bit words
        lda             #-1
        sta             PageMap+58
        sta             PageMap+59
        sta             PageMap+60
        sta             PageMap+61
        sta             PageMap+62
        sta             PageMap+63
        ; Mark page #0 used
        lda             #1              
        sta             PageMap
        ; Mark 64-336 used (DOS)
        lda             #64
meminit1:
        bms             PageMap
        ina
        cmp             #336
        blo             meminit1
        rts

;------------------------------------------------------------------------------
; Allocate a memory page from the available memory pool.
; Returns a pointer to the page in memory. The address returned is the
; virtual memory address.
;
; Returns:
;       r1 = 0 if no more memory is available or max mapped capacity is reached.
;       r1 = virtual address of allocated memory page
;------------------------------------------------------------------------------
;
        align   8
public AllocMemPage:
        phx
        phy
        ; Search the page bitmap for a free memory page.
        lda             #0
        ldx             #MAX_PHYSICAL_PAGE
        spl             mem_sema + 1
amp2:
        bmt             PageMap
        beq             amp1            ; found a free page ?
        ina
        dex
        bne             amp2
        ; Here all memory pages are already in use. No more memmory is available.
        stz             mem_sema + 1
        ply
        plx
        lda             #0
        rts
        ; Here we found an unallocated memory page. Next find a spot in the MMU
        ; map to place the page.
amp1:
        ; Find unallocated map slot in the MMU
        jsr             SetAKEYForCurrentJob
        ldx             #0
amp4:
        ldy             MMU,x
        cpy             #INV_PAGE
        beq             amp3
        inx
        cpx             #MAX_VIRTUAL_PAGE
        bne             amp4
        ; Here we searched the entire MMU slots and none were available
        stz             mem_sema + 1
        ply
        plx
        lda             #0              ; return NULL pointer
        rts
        ; Here we have both an available page, and available map slot.
amp3:
        bms             PageMap         ; mark page as allocated
        sta             MMU,x           ; put the page# into the map slot
        asl             r1,r2,#14       ; pages are 16kW in size (compute virtual address)
        dec             nPagesFree
        stz             mem_sema + 1
        ply
        plx
        rts

;------------------------------------------------------------------------------
; Parameters:
;       r1 = size of allocation in words
; Returns:
;       r1 = word pointer to memory
; No MMU
;------------------------------------------------------------------------------
;
        align   8
public AllocMemPages:
        php
        phx
        phy
        push    r4
        sei
amp5:
        tay
        lsr             r3,r3,#14       ; convert amount to #pages
        iny                                     ; round up
        cpy             nPagesFree
        bhi             amp11
        tyx                                     ; x = request size in pages
        ; Search for enough free pages to satisfy the request
        lda             #0
amp7:
        bmt             PageMap         ; test for a free page
        bne             amp6            ; not a free page
        cpx             #1                      ; did we find enough free pages ?
        bls             amp8
        dex
amp6:                                   ; keep checking for next free page
        ina
        cmp             #1855           ; did we hit end of map ?
        bhi             amp11           ; can't allocate enough memory
        bra             amp7            ; go back and test for another free page

        ; Insufficient memory, return NULL pointer
amp11:
        lda             #0
        pop             r4
        ply
        plx
        plp
        rts

        ; Mark pages as allocated
amp8:
        tyx             ; x= #pages to allocate
        cpx             #1
        bne             amp9
        txa                                                     ; flag indicates last page
        bra             amp10
amp9:
        lda             #0                                      ; flag indicates middle page
amp10:
        jsr             AllocMemPage            ; allocate first page
        ld              r4,r1                           ; save virtual address of first page allocated
        dex
        beq             amp14
amp13:
        cpx             #1
        bne             amp15
        txa
        bra             amp12
amp15:
        lda             #0
amp12:
        jsr             AllocMemPage
        dex
        bne             amp13
amp14:
        ld              r1,r4                           ; r1 = first virtual address
        pop             r4
        ply
        plx
        plp
        rts

;------------------------------------------------------------------------------
; FreeMemPage:
;
;       Free a single page of memory. This is an internal function called by
; FreeMemPages(). Normally FreeMemPages() will be called to free up the
; entire run of pages. This function both unmarks the memory page in the
; page bitmap and invalidates the page in the MMU.
;
; Parameters:
;       r1 = virtual memory address
;------------------------------------------------------------------------------
;
        align   8
FreeMemPage:
        pha
        php
        phx
        sei
        ; First mark the page as available in the virtual page map.
        pha
        lsr             r1,r1,#14
        and             #$1ff                   ; 512 virtual pages max
        ldx             RunningTCB
        ldx             TCB_mmu_map,x   ; x = map #
        asl             r2,r2,#4                ; 16 words per map
        bmc             VPM_bitmap_b0,x ; clear both bits
        bmc             VPM_bitmap_b1,x
        pla
        ; Mark the page available in the physical page map
        pha
        jsr             VirtToPhys              ; convert to a physical address
        lsr             r1,r1,#14
        and             #$7ff                   ; 2048 physical pages max
        bmc             PageMap
        pla
        ; Now mark the MMU slot as empty
        lsr             r1,r1,#14               ; / 16kW r1 = page # now
        and             #$1ff                   ; 512 pages max
        jsr             SetAKEYForCurrentJob
        tax
        lda             #INV_PAGE
        sta             MMU,x
        inc             nPagesFree
        plx
        plp
        pla
        rts

;------------------------------------------------------------------------------
; FreeMemPages:
;
;       Free up multiple pages of memory. The pages freed are a consecutive
; run of pages. A double-bit bitmap is used to identify where the run of
; pages ends. Bit code 00 indicates a unallocated page, 01 indicates an
; allocated page somewhere in the run, and 11 indicates the end of a run
; of allocated pages.
;
; Parameters:
;       r1 = pointer to memory
;------------------------------------------------------------------------------
;
        align   8
public FreeMemPages:
        cmp             #0x3fff                         ; test for a proper pointer
        bls             fmp5
        pha
        ; Turn the memory pointer into a bit index
        lsr             r1,r1,#14                       ; / 16kW acc = virtual page #
        cmp             #MAX_VIRTUAL_PAGE       ; make sure index is sensible
        bhs             fmp4
        phx
        spl             mem_sema + 1
        ldx             RunningTCB
        ldx             TCB_mmu_map,x
        asl             r2,r2,#4
fmp2:
        bmt             VPM_bitmap_b1,x         ; Test to see if end of allocation
        bne             fmp3
        asl             r1,r1,#14                       ; acc = virtual address
        jsr             FreeMemPage                     ; 
        lsr             r1,r1,#14                       ; acc = virtual page # again
        ina
        cmp             #MAX_VIRTUAL_PAGE       ; last 192 pages aren't freeable
        blo             fmp2
fmp3
        ; Clear the last bit
        asl             r1,r1,#14                       ; acc = virtual address
        jsr             FreeMemPage                     ; 
        lsr             r1,r1,#14                       ; acc = virtual page # again
        bmc             VPM_bitmap_b1,x
        stz             mem_sema + 1
        plx
fmp4:
        pla
fmp5:
        rts

;------------------------------------------------------------------------------
; Convert a virtual address to a physical address.
; Parameters:
;       r1 = virtual address to translate
; Returns:
;       r1 = physical address
;------------------------------------------------------------------------------
;
        align   8
public VirtToPhys:
        cmp             #$3FFF                          ; page #0 is physical page #0
        bls             vtp2
        cmp             #$01FFFFFF                      ; outside of managed address bounds (ROM / IO)
        bhi             vtp2
        phx
        ldx             CONFIGREC                       ; check if there is an MMU present
        bit             r2,#4096                        ; if not, then virtual and physical addresses
        beq             vtp3                            ; will match
        phy
        tay                                                     ; save original address
        and             r3,r3,#$FF803FFF        ; mask off MMU managed address bits
        jsr             SetAKEYForCurrentJob
        lsr             r2,r1,#14                       ; convert to MMU index
        and             r2,r2,#511                      ; 512 mmu pages
        lda             MMU,x                           ; a = physical page#
        beq             vtp1                            ; zero = invalid address translation
        asl             r1,r1,#14                       ; *16kW
        or              r1,r1,r3                        ; put back unmanaged address bits
vtp1:
        ply
vtp3:
        plx
vtp2:
        rts

;------------------------------------------------------------------------------
; PhysToVirt
;
; Convert a physical address to a virtual address. A little more complex
; than converting virtual to physical addresses as the MMU map table must
; be searched for the physical page.
;
; Parameters:
;       r1 = physical address to translate
; Returns:
;       r1 = virtual address
;------------------------------------------------------------------------------
;
        align   8
public PhysToVirt:
        cmp             #$3FFF                          ; first check for direct translations
        bls             ptv3                            ; outside of the MMU managed range
        cmp             #$01FFFFFF
        bhi             ptv3
        phx
        ldx             CONFIGREC                       ; check if there is an MMU present
        bit             r2,#4096                        ; if not, then virtual and physical addresses
        beq             ptv4                            ; will match
        phy
        jsr             SetAKEYForCurrentJob
        tay
        and             r3,r3,#$FF803FFF        ; mask off MMU managed address bits
        lsr             r1,r1,#14                       ; /16k to get index
        and             r1,r1,#$7ff                     ; 2048 pages max
        ldx             #0
ptv2:
        cmp             MMU,x
        beq             ptv1
        inx
        cpx             #512
        bne             ptv2
        ; Return NULL pointer if address translation fails
        ply
        plx
        lda             #0
        rts
ptv1:
        asl             r1,r2,#14       ; * 16k
        or              r1,r1,r3                        ; put back unmanaged address bits
        ply
ptv4:
        plx
ptv3:
        rts

; ============================================================================
; Heap related functions.
;
;       The heap is managed as a doublely linked list of memory blocks.
; ============================================================================

        align   8
public InitHeap:
        lda             RunningTCB
        ldx             TCB_HeapStart,r1
        ldy             TCB_HeapEnd,r1
        lda             #$4D454D20
        sta             MEM_CHK,x
        sta             MEM_FLAG,x
        lda             #$6D656D20              ; mark the last block as allocated
        sta             MEM_CHK,y
        sta             MEM_FLAG,y
        lda             #0
        sta             MEM_PREV,x              ; prev of first MEMHDR
        sty             MEM_NEXT,x
        sta             MEM_NEXT,y
        stx             MEM_PREV,y
        rts

;------------------------------------------------------------------------------
; Allocate memory from the heap.
; Each task has it's own memory heap.
;------------------------------------------------------------------------------
        align   8
public MemAlloc:
        phx
        phy
        push    r4
        ldx             RunningTCB
        ldx             TCB_HeapStart,x
mema4:
        ldy             MEM_FLAG,x              ; Check the flag word to see if this block is available
        cpy             #$4D454D20
        bne             mema1                   ; block not available, go to next block
        ld              r4,MEM_NEXT,x   ; compute the size of this block
        sub             r4,r4,r2
        sub             r4,r4,#4                ; minus size of block header
        cmp             r1,r4                   ; is the block large enough ?
        bmi             mema2                   ; if yes, go allocate
mema1:
        ldx             MEM_NEXT,x              ; go to the next block
        beq             mema3                   ; if no more blocks, out of memory error
        bra             mema4
mema2:
        ldy             #$6D656D20
        sty             MEM_FLAG,x
        sub             r4,r4,r1
        cmp             r4,#4                   ; is the block large enough to split
        bpl             memaSplit
        txa
        add             #4                              ; point to payload area
        pop             r4
        ply
        plx
        rts
mema3:                                          ; insufficient memory
        pop             r4
        ply
        plx
        lda             #0
        rts
memaSplit:
        add             r4,r1,r2
        add             r4,#4
        ldy             #$4D454D20
        sty             (r4)
        sty             MEM_FLAG,r4
        stx             MEM_PREV,r4
        ldy             MEM_NEXT,x
        sty             MEM_NEXT,r4
        st              r4,MEM_PREV,y
        ld              r1,r4
        add             #4
        pop             r4
        ply
        plx
        rts

;------------------------------------------------------------------------------
; Free previously allocated memory. Recombine with next and previous blocks
; if they are free as well.
;------------------------------------------------------------------------------
        align   8
public MemFree:
        cmp             #4                      ; null pointer ?
        blo             memf2
        phx
        phy
        sub             #4                      ; backup to header area
        ldx             MEM_FLAG,r1
        cpx             #$6D656D20      ; is the block allocated ?
        bne             memf1
        ldx             #$4D454D20
        stx             MEM_FLAG,r1     ; mark block as free
        ldx             MEM_PREV,r1     ; is the previous block free ?
        beq             memf3           ; no previous block
        ldy             MEM_FLAG,x
        cpy             #$4D454D20
        bne             memf3           ; the previous block is not free
        ldy             MEM_NEXT,r1
        sty             MEM_NEXT,x
        beq             memf1           ; no next block
        stx             MEM_PREV,y
memf3:
        ldy             MEM_NEXT,r1
        ldx             MEM_FLAG,y
        cpx             #$4D454D20
        bne             memf1           ; next block not free
        ldx             MEM_PREV,r1
        stx             MEM_PREV,y
        beq             memf1           ; no previous block
        sty             MEM_NEXT,x
memf1:
        ply
        plx
memf2:
        rts

;------------------------------------------------------------------------------
; Report the amount of system memory free. Counts up the number of
; unallocated pages in the page bitmap.
;------------------------------------------------------------------------------
;
public ReportMemFree:
        jsr             CRLF
        lda             #' '
        jsr             DisplayChar
        lda             #0
        tay
rmf2:
        bmt             PageMap
        bne             rmf1
        iny
rmf1:
        ina
        cmp             #2048
        blo             rmf2
        tya
        asl             r1,r1,#14               ; 16kW per bit
        ldx             #5
        jsr             PRTNUM
        lea             r1,msgMemFree
        jsr             DisplayStringB
        rts

msgMemFree:
        db      " words free",CR,LF,0
        
;==============================================================================
; Memory Management routines follow.
;==============================================================================

;------------------------------------------------------------------------------
; brk
; Establish a new program break
;
; Parameters:
; r1 = new program break address
;------------------------------------------------------------------------------
;
public _brk:
        phx
        push    r4
        push    r5
        push    r6
        ldx             RunningTCB
        ld              r4,TCB_ASID,x
        st              r4,MMU_AKEY
        ld              r4,TCB_npages,x
        lsr             r1,r1,#14
        add             r1,r1,#1
        cmp             r1,r4
        beq             brk6                    ; allocation isn't changing
        blo             brk1                    ; reducing allocation

        ; Here we're increasing the amount of memory allocated to the program.
        ;
        cmp             r1,#320                 ; max 320 RAM pages
        bhi             brk2
        sub             r1,r1,r4                ; number of new pages
        cmp             r1,mem_pages_free       ; are there enough free pages ?
        bhi             brk2
        ld              r5,mem_pages_free
        sub             r5,r5,r1
        st              r5,mem_pages_free
        ld              r6,r1                   ; r6 = number of pages to allocate
        add             r1,r1,r4                ; get back value of address
        sta             TCB_npages,x
        lda             #0
brk5:
        bmt             PageMap                 ; test if page is free
        bne             brk4                    ; no, go for next page
        bms             PageMap                 ; allocate the page
        sta             MMU,r4                  ; store the page number in the MMU table
        add             r4,#1                   ; move to next MMU entry
        sub             r6,#1                   ; decrement count of needed
        beq             brk6                    ; we're done if count = 0
brk4:
        ina
        cmp             #2048
        blo             brk5

        ; Here there was an OS or hardware error
        ; According to mem_pages_free there should have been enough free pages
        ; to fulfill the request. Something is corrupt.
        ;

        ; Here we are reducing the program break, which means freeing up pages of
        ; memory.
brk1:
        sta             TCB_npages,x
        add             r5,r1,#1                ; move to page after last page
brk7:
        cmp             r5,r4                   ; are we done freeing pages ?
        bhi             brk6
        lda             MMU,r5                  ; get the page to free
        bmc             PageMap                 ; free the page
        inc             mem_pages_free
        add             r5,#1
        bra             brk7

        ; Successful return
brk6:
        pop             r6
        pop             r5
        pop             r4
        plx
        lda             #0
        rts

; Return insufficient memory error
;
brk2:
        lda             #E_NoMem
        sta             TCB_errno,x
        pop             r6
        pop             r5
        pop             r4
        plx
        lda             #-1
        rts

;------------------------------------------------------------------------------
; Parameters:
; r1 = change in memory allocation
;------------------------------------------------------------------------------
public _sbrk:
        phx
        push    r4
        push    r5
        ldx             RunningTCB
        ld              r4,TCB_npages,x         ; get the current memory allocation
        cmp             r1,#0                           ; zero difference = get old brk address
        beq             sbrk2
        asl             r5,r4,#14                       ; convert to words
        add             r1,r1,r5                                ; +/- amount
        jsr             _brk
        cmp             r1,#-1
        bne             sbrk2

; Failure return, return -1
;
        pop             r5
        pop             r4
        plx
        rts

; Successful return, return the old break address
;       
sbrk2:
        ld              r1,r4
        asl             r1,r1,#14
        pop             r5
        pop             r4
        plx
        rts

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.