From afaca91d28d3dfc79447543eb80c4f3420f2b70d Mon Sep 17 00:00:00 2001 From: Martin Haye Date: Mon, 30 Dec 2013 11:00:39 -0800 Subject: [PATCH] Centralized some zero-page, I/O, and ROM defines. More memory manager code written. --- Platform/Apple/virtual/src/core/mem.s | 392 +++++++++++++++----- Platform/Apple/virtual/src/include/global.i | 47 +++ Platform/Apple/virtual/src/raycast/render.i | 44 +-- 3 files changed, 353 insertions(+), 130 deletions(-) create mode 100644 Platform/Apple/virtual/src/include/global.i diff --git a/Platform/Apple/virtual/src/core/mem.s b/Platform/Apple/virtual/src/core/mem.s index 77919d7a..d3c15172 100644 --- a/Platform/Apple/virtual/src/core/mem.s +++ b/Platform/Apple/virtual/src/core/mem.s @@ -6,9 +6,9 @@ ; if any, are used there as well as usage flags to mark free, used, or reserved memory. ; ; Memory is marked as used as it is loaded by the loader, but the caller program -; should mark memory as free as soon as the memory is no longer in use. It is -; very possible that the memory will not be reclaimed right away and could be -; reinstated as in-use without a loading penalty. +; should free it as soon as the memory is no longer in use. It is very possible that +; the memory will not be reclaimed right away and could be reinstated as in-use without +; a loading penalty. ; ; Another scenario is that free memory will be relocated to auxiliary banks ; and potentially later restored to active memory at a later time. Depending on the @@ -34,11 +34,9 @@ ; FFFFtttt nnnnnnnn ; F = Flags ; 7 - Active/Inactive -; 6 - Locked (Cannot reclaim for any reason) -; 5 - Primary (1) or Secondary (0) +; 6 - Primary (1) or Secondary (0) ; Memory pages are allocated in chunks, the first page is always primary ; So detecting primary pages means we can clear more than one page at a time -; 4 - Loaded (Memory contains copy of disk-based resource identified below) ; t = Type of resource (1-15, 0 is invalid) ; n = Resource number (1-255, 0 is invalid) ; @@ -58,12 +56,6 @@ mainLoader = $800 auxLoader = $803 -; Monitor routines -setNorm = $FE84 -monInit = $FB2F -setVid = $FE93 -setKbd = $FE89 - ;------------------------------------------------------------------------------ ; Command codes @@ -90,32 +82,36 @@ RESET_MEMORY = $10 ; This command is acted upon and then passed on to chained loaders. ;------------------------------------------------------------------------------ -LOCK_MEMORY = $11 - ; Input: X-reg - page address for start of reservation - ; Y-reg - number of pages to reserve - ; - ; Output: None - ; - ; Reserve a specific area of memory. If it cannot be reserved for any reason, - ; a FATAL_ERROR is triggered. - ; - ; This command is acted upon immediately and chained loaders are not called. - -;------------------------------------------------------------------------------ -REQUEST_MEMORY = $12 +REQUEST_MEMORY = $11 ; Input: X-reg - number of pages to allocate ; - ; Output: X-reg - starting memory page that was allocated + ; Output: A-reg - starting memory page that was allocated ; ; Allocate a number of blocks in the memory space of this loader. If there ; isn't a large enough continguous memory segment available, the system ; will be halted immediately with HALT_MEMORY. ; + ; Normally this command chooses the location of the memory area; if you + ; want to force it to use a particular location, use SET_MEM_TARGET first. + ; ; To allocate main memory, call the main memory loader. To allocate aux ; mem, call that loader instead. ; ; This command is acted upon immediately and chained loaders are not called. +;------------------------------------------------------------------------------ +SET_MEM_TARGET = $12 + ; Input: X-reg - page number target + ; + ; Output: None + ; + ; Sets the target page in memory for the next REQUEST_MEMORY or QUEUE_LOAD + ; command. This will force allocation at a specific location instead + ; allowing the loader to choose. + ; + ; This is a one-shot command, i.e. as soon as an allocation is performed, + ; subsequent allocations will revert to their normal behavior. + ;------------------------------------------------------------------------------ START_LOAD = $13 ; Input: X-reg - disk partition number (0 for boot disk, 1-15 for others) @@ -133,12 +129,15 @@ QUEUE_LOAD = $14 ; Input: X-reg - resource type ; Y-reg - resource number ; - ; Output: X-reg - memory page the load will occur at + ; Output: A-reg - memory page the load will occur at ; ; This is the main entry for loading resources from disk. It queues a load ; request, allocating main memory to hold the entire resource. Note that ; the load is only queued; it will be completed by FINISH_LOAD. ; + ; Normally this command chooses the location of the memory area; if you + ; want to force it to use a particular location, use SET_MEM_TARGET first. + ; ; Note that if the data is already in memory, its former location will ; be returned and no disk access will be queued. ; @@ -168,7 +167,22 @@ FREE_MEMORY = $16 ; reused. This also clears the lock bit! ;------------------------------------------------------------------------------ -FATAL_ERROR = $17 +CHAIN_LOADER = $17 + ; Input: X-reg / Y-reg - pointer to loader (X=lo, Y=hi) to add to chain + ; + ; Output: None + ; + ; Add a loader to the chain just after this loader. The current next + ; loader (if there is one) will be passed to the new loader with another + ; CHAIN_LOADER command. + ; + ; The purpose of a loader chain is to insert faster devices between the + ; main/aux loader (fastest) and the disk loader (slowest). Note that the + ; main mem and aux mem loaders are conceptually one; a chained loader will + ; always be inserted after them, not between them. + +;------------------------------------------------------------------------------ +FATAL_ERROR = $18 ; Input: X-reg / Y-reg: message number or pointer (see below) ; ; Output: Never returns @@ -193,103 +207,136 @@ FATAL_ERROR = $17 ;------------------------------------------------------------------------------ ; code begins here -* = $800 - jmp mainLoader - jmp auxLoader + .org $800 -nextLoaderVec: jmp diskLoader + .include "../include/global.i" -mainLoader: - lda #0 ; incremented after init - bne :+ - jmp init -: cmp #RESET_MEMORY - bne :+ - jmp main_reset -: cmp #LOCK_MEMORY - bne :+ - jmp main_lock + ; zero page + pPageTbl1 = $6 ; length 2 + pPageTbl2 = $8 ; length 2 + + ; Initial vectors + jmp main_dispatch + jmp aux_dispatch + + ; Page tables + main_pageTbl1: .res $C0 + main_pageTbl2: .res $C0 + aux_pageTbl1: .res $C0 + aux_pageTbl2: .res $C0 + +;------------------------------------------------------------------------------ +; Variables +isInitted: + .byte 0 +targetPage: + .byte 0 +nextLoaderVec: + jmp diskLoader + +;------------------------------------------------------------------------------ +main_dispatch: + bit isInitted ; check if initted yet + bmi :+ + jsr init ; init once only : cmp #REQUEST_MEMORY bne :+ - jmp main_req + jmp main_request +: cmp #QUEUE_LOAD + bne shared_dispatch + jmp main_queueLoad +shared_dispatch: + cmp #RESET_MEMORY + bne :+ + jmp main_reset +: cmp #SET_MEM_TARGET + bne :+ + stx targetPage + rts : cmp #FATAL_ERROR bne :+ jmp fatalError -: cmp #START_LOAD - bcc cmdError - cmp #FINISH_LOAD+1 - bcs cmdError -; Found a command that needs to be chained to next loader +; Pass command to next chained loader jmp nextLoaderVec -cmdError: - ldx #LOAD_ERR_INVALID_COMMAND - ldy #0 +;------------------------------------------------------------------------------ +aux_dispatch: + cmp #REQUEST_MEMORY + bne :+ + jmp aux_request +: cmp #QUEUE_LOAD + bne shared_dispatch + jmp aux_queueLoad + +;------------------------------------------------------------------------------ +; Print fatal error message (custom or predefined) and print the +; call stack, then halt. fatalError: - tya - bne customErr -predefErr: + lda #0 ; default start index + cpy #0 ; custom message? + bne printErr ; yes, don't do predef scan + ; note, y is now conveniently 0 +; Find a predefined error message in the table of messages +scanPredef: dex - beq foundErrMsg + beq foundPredef : iny lda errorText,y bne :- - beq predefErr -foundErrMsg: + beq scanPredef +foundPredef: tya - clc - adc #errorText - bcc customErr - iny -customErr: - sty pTmp+1 - stx pTmp -; Set up text mode, print message + ldx #main_pageTbl1 + sta pPageTbl1+1 + lda #main_pageTbl2 + sta pPageTbl2+1 + rts + +;------------------------------------------------------------------------------ +aux_setup: + lda #aux_pageTbl1 + sta pPageTbl1+1 + lda #aux_pageTbl2 + sta pPageTbl2+1 + rts + +;------------------------------------------------------------------------------ +main_reset: + ; Set all pages from end of memory manager up to (but not including) ProDOS + ; system page as "inactive". + ldy #>codeEnd + iny +: lda main_pageTbl1,y + and #$7F ; strip the "active" bit + sta main_pageTbl1,y + iny + cpy #$BF ; stop just before ProDOS sys page + bne :- +aux_reset: + ; Set all pages except zero page and stack to "inactive" + ldy #2 +: lda aux_pageTbl1,y + and #$7F ; strip the "active" bit + sta aux_pageTbl1,y + iny + cpy #$C0 ; stop at end of 48K mem bank + bne :- + jmp nextLoaderVec ; allow chained loaders to reset also + +;------------------------------------------------------------------------------ +main_request: + jsr main_setup +shared_request: + lda targetPage ; see if SET_MEM_TARGET was called + ldy #0 + sty targetPage ; clear it for next time + tay + bne @gotPage ; if SET_MEM_TARGET was called, don't scan + ; need to scan for a block that has enough pages + stx tmp ; save number of pages + ldy #1 ; begin scan at page 2 (1+1) +@blockLoop: + iny ; try next page + sty tmp+1 ; remember starting page of area + ldx #0 ; initialize count of free pages found +@pageLoop: + cpy #$C0 ; stop at end of mem + bcs outOfMemErr + lda (pPageTbl1),y ; is page active? + bmi @blockLoop ; yes active, skip it + iny + inx ; got one more inactive page + cpx tmp ; is it enough? + bcc @pageLoop ; no, keep going +@foundBlock: ; yes, got enough + ldy tmp+1 ; recall starting page +@gotPage: + lda #$C0 ; mark first page as $80 (active) + $40 (primary) +: cpy #$C0 ; all pages from $C0.FF are reserved + bcs reservedErr + pha + lda (pPageTbl1),y ; don't want to reserve same area twice + bne reservedErr + pla + sta (pPageTbl1),y + lda #$80 ; mark subsequent pages as $80 (active) but not primary + iny + dex + bne :- + lda tmp+1 ; return starting page + rts +reservedErr: + ldx #LOAD_ERR_RESERVED_MEM +produceErr: + ldy #0 + lda #FATAL_ERROR + jmp mainLoader +outOfMemErr: + ldx #LOAD_ERR_OUT_OF_MEMORY + bne produceErr ; always taken + +;------------------------------------------------------------------------------ +aux_request: + jsr aux_setup + jmp shared_request + +;------------------------------------------------------------------------------ +main_queueLoad: + jsr main_setup +shared_queueLoad: + stx tmp ; save resource type + sty tmp+1 ; save resource number + ; Scan to see if we already have this resource in memory + ldy #0 +@scanLoop: + lda (pPageTbl1),y + and #$40 ; primary? that is, start of an area? + bcc @skip ; no, skip it + lda (pPageTbl1),y + and #$F ; extract resource type + cmp tmp ; is it the type we're looking for? + bne @skip ; no, skip it + lda (pPageTbl2),y ; get resource number + cmp tmp+1 ; is it the resource # we're looking for? + beq @found ; yes! found what we want. +@skip: + iny ; next page + cpy #$C0 ; end of memory? + bne @scanLoop ; no, keep scanning + ldx tmp ; yes, end of memory. Recall type parameter + ldy tmp+1 ; recall resource number + jmp nextLoaderVec ; call next loader so it can load the resource +@found: + lda (pPageTbl1),y + ora #$80 ; mark this area as active now + sta (pPageTbl1),y + tya ; transfer page num to A-reg for API return + rts + +;------------------------------------------------------------------------------ +aux_queueLoad: + jsr aux_setup + jmp shared_queueLoad + +;------------------------------------------------------------------------------ +; Marker for end of the code, so we can compute its length +codeEnd: + diff --git a/Platform/Apple/virtual/src/include/global.i b/Platform/Apple/virtual/src/include/global.i new file mode 100644 index 00000000..636f43a0 --- /dev/null +++ b/Platform/Apple/virtual/src/include/global.i @@ -0,0 +1,47 @@ +; Shared definitions for all modules + +; Zero page temps +tmp = $2 ; len 2 +pTmp = $4 ; len 2 + +; Zero page monitor locations +a2l = $3E +a2h = $3F + +; Other monitor locations +resetVec = $3F2 + +; I/O locations +kbd = $C000 +clrAuxRd = $C002 +setAuxRd = $C003 +clrAuxWr = $C004 +setAuxWr = $C005 +clrAuxZP = $C008 +setAuxZP = $C009 +kbdStrobe = $C010 +clrText = $C050 +setText = $C051 +clrMixed = $C052 +setMixed = $C053 +page1 = $C054 +page2 = $C055 +clrHires = $C056 +setHires = $C057 + +; ROM routines +prntax = $F941 +textinit = $FB2F +rdkey = $FD0C +getln1 = $FD6F +crout = $FD8E +prbyte = $FDDA +cout = $FDED +setnorm = $FE84 +setkbd = $FE89 +setvid = $FE93 +prerr = $FF2D +bell = $FF3A +monitor = $FF69 +getnum = $FFA7 + diff --git a/Platform/Apple/virtual/src/raycast/render.i b/Platform/Apple/virtual/src/raycast/render.i index da7d1c3d..47700f78 100644 --- a/Platform/Apple/virtual/src/raycast/render.i +++ b/Platform/Apple/virtual/src/raycast/render.i @@ -1,5 +1,7 @@ ; Shared definitions for the rendering code + .include "../include/global.i" + ; Constants TOP_LINE = $2180 ; 24 lines down from top NLINES = 128 @@ -21,15 +23,10 @@ BLIT_OFF6 = 24 BLIT_STRIDE = 29 ; Renderer zero page -playerDir = $3 ; len 1 -playerX = $4 ; len 2 (hi=integer, lo=fraction) -playerY = $6 ; len 2 (hi=integer, lo=fraction) pDst = $8 ; len 2 pTex = $A ; len 2 pixNum = $C ; len 1 byteNum = $D ; len 1 -pTmp = $E ; len 2 -tmp = $10 ; len 2 mapWidth = $12 ; len 1 mapHeight = $13 ; len 1 pRayData = $14 ; len 2 @@ -56,11 +53,9 @@ maxX = $5D ; len 1 minY = $5E ; len 1 maxY = $5F ; len 1 screenCol = $60 ; len 1 - -; Other monitor locations -a2l = $3E -a2h = $3F -resetVec = $3F2 +playerDir = $61 ; len 1 +playerX = $62 ; len 2 (hi=integer, lo=fraction) +playerY = $64 ; len 2 (hi=integer, lo=fraction) ;--------------------------------- ; The following are all in aux mem... @@ -85,35 +80,6 @@ blitRoll = $B000 ; Unrolled blitting code. Size 29*128 = $E80, plus 1 for MLI = $BF00 ; Entry point for ProDOS MLI memMap = $BF58 ; ProDOS memory map -; I/O locations -kbd = $C000 -clrAuxRd = $C002 -setAuxRd = $C003 -clrAuxWr = $C004 -setAuxWr = $C005 -clrAuxZP = $C008 -setAuxZP = $C009 -kbdStrobe = $C010 -clrText = $C050 -setText = $C051 -clrMixed = $C052 -setMixed = $C053 -page1 = $C054 -page2 = $C055 -clrHires = $C056 -setHires = $C057 - -; ROM routines -prntax = $F941 -rdkey = $FD0C -getln1 = $FD6F -crout = $FD8E -prbyte = $FDDA -cout = $FDED -prerr = $FF2D -monitor = $FF69 -getnum = $FFA7 - ; mipmap level offsets MIP_OFFSET_0 = 0 MIP_OFFSET_1 = $400 ; 32*32