Centralized some zero-page, I/O, and ROM defines. More memory manager code written.

This commit is contained in:
Martin Haye 2013-12-30 11:00:39 -08:00
parent 7bc7c94f8b
commit afaca91d28
3 changed files with 353 additions and 130 deletions

View File

@ -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
tax
ldy #>errorText
bcc customErr
iny
customErr:
sty pTmp+1
stx pTmp
; Set up text mode, print message
ldx #<errorText
printErr:
jsr setNorm
jsr monInit
jsr setVid
jsr setKbd
; Set up text mode, print message
pha ; save index
sty pTmp+1 ; save message ptr hi...
stx pTmp ; ...and lo
jsr setnorm ; set up text mode and vectors
jsr textinit
jsr setvid
jsr setkbd
jsr crout ; a couple newlines
jsr crout
jsr crout
ldy #0
pla ; restore message pointer
tay
: lda (pTmp),y
beq :+
jsr cout
iny
bne :-
; Print call stack
jsr crout
tsx
: cpx #$FF
beq :+
inx
lda 100,x
: jsr crout
tsx ; start at current stack pointer
@stackLoop:
lda 101,x ; JSR increments PC twice before pushing it
sec
sbc #2
sta pTmp
lda 101,x
tay
lda 102,x
sbc #0
sta pTmp+1
and #$C0
sta @load+2
and #$C0 ; avoid accidentally grabbing data from the IO area
cmp #$C0
beq :-
ldy #0
lda (pTmp),y
@load:
lda $1000,y ; is there a JSR there?
cmp #$20
bne :-
lda pTmp+1
jsr prByte
lda pTmp
jsr prByte
lda @load+2
jsr prbyte
tya
jsr prbyte
lda #$A0
jsr cout
jmp :-
inx ; work up to...
cpx #$FF ; ...top of stack
bcc @stackLoop
; Beep, and loop forever
: jsr bell
loopForever: jmp loopForever
jsr bell
loopForever:
jmp loopForever
errorText:
.byte "Invalid command", 0
@ -297,3 +344,166 @@ errorText:
.byte "Reserved memory", 0
.byte "Unknown error", 0
.byte 0
;------------------------------------------------------------------------------
init:
; clear the page tables
ldy #0
tya
: sta main_pageTbl1,y
sta main_pageTbl2,y
sta aux_pageTbl1,y
sta aux_pageTbl2,y
iny
cpy #$C0
bne :-
; make sure init won't get called next time
sty isInitted
rts
;------------------------------------------------------------------------------
main_setup:
lda #<main_pageTbl1
sta pPageTbl1
lda #>main_pageTbl1
sta pPageTbl1+1
lda #<main_pageTbl2
sta pPageTbl2
lda #>main_pageTbl2
sta pPageTbl2+1
rts
;------------------------------------------------------------------------------
aux_setup:
lda #<aux_pageTbl1
sta pPageTbl1
lda #>aux_pageTbl1
sta pPageTbl1+1
lda #<aux_pageTbl2
sta pPageTbl2
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:

View File

@ -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

View File

@ -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