mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-01-12 12:30:07 +00:00
Lots of heap debugging and fixes.
This commit is contained in:
parent
b5eb726b25
commit
1f324ea547
@ -195,7 +195,6 @@ relocate:
|
||||
sta oSBX+1
|
||||
lda #<SBXX
|
||||
sta plasmaXTbl+$70
|
||||
iny
|
||||
lda plasmaXTbl+$71
|
||||
sta oSBX+2
|
||||
lda #>SBXX
|
||||
@ -205,7 +204,6 @@ relocate:
|
||||
sta oSWX+1
|
||||
lda #<SWXX
|
||||
sta plasmaXTbl+$72
|
||||
iny
|
||||
lda plasmaXTbl+$73
|
||||
sta oSWX+2
|
||||
lda #>SWXX
|
||||
@ -388,9 +386,13 @@ LWXX: bit monrts ; set V to denote LWX (not LBX)
|
||||
jsr l_LXXX ; helper function in low memory because it switches us out (we're in main LC)
|
||||
ldy tmp
|
||||
jmp plasmaNextOp
|
||||
.norm bvs oLWX
|
||||
.norm ora evalStkL,x
|
||||
beq nullPtr
|
||||
bvs oLWX
|
||||
oLBX: jmp $1111 ; modified to be addr of original LBX
|
||||
oLWX: jmp $1111 ; modified to be addr of original LWX
|
||||
nullPtr sta clrAuxRd
|
||||
jsr inlineFatal : !text "NullPtr",0
|
||||
|
||||
} ; zone
|
||||
|
||||
@ -402,8 +404,8 @@ SWXX: bit monrts ; set V to denote SWX (not SBX)
|
||||
.shst lda evalStkH+1,x ; get hi byte of pointer to store to
|
||||
cmp #$D0 ; in $0000.CFFF range,
|
||||
bcc .norm ; just do normal store
|
||||
bit setLcRW+lcBank2 ; PLASMA normally write-protects the LC,
|
||||
bit setLcRW+lcBank2 ; but let's allow writing there
|
||||
inc setLcRW+lcBank2 ; PLASMA normally write-protects the LC,
|
||||
inc setLcRW+lcBank2 ; but let's allow writing there. Don't use BIT as it affects V flg.
|
||||
cmp #$E0 ; in $E000.FFFF range do normal store after write-enable
|
||||
bcs .norm
|
||||
sty tmp
|
||||
@ -412,7 +414,9 @@ SWXX: bit monrts ; set V to denote SWX (not SBX)
|
||||
inx
|
||||
inx
|
||||
jmp plasmaNextOp
|
||||
.norm bvs oSWX
|
||||
.norm ora evalStkL+1,x
|
||||
beq nullPtr
|
||||
bvs oSWX
|
||||
oSBX: jmp $1111 ; modified to be addr of original SBX
|
||||
oSWX: jmp $1111 ; modified to be addr of original SWX
|
||||
} ; zone
|
||||
@ -854,7 +858,9 @@ heapClr: !zone
|
||||
; live objects are reachable (and invalid garbage if not reachable from there).
|
||||
;
|
||||
; x=ptr lo, y = ptr hi.
|
||||
; Tbl: type size 01-7F, then (byte) offsets of ptrs 01-7F within type, then 0.
|
||||
; Tbl: type size 01-7F including type byte,
|
||||
; then (byte) offsets of ptrs 01-7F within type,
|
||||
; then 0.
|
||||
heapAddType: !zone
|
||||
tya ; save addr hi
|
||||
ldy nTypes
|
||||
@ -867,6 +873,8 @@ heapAddType: !zone
|
||||
txa ; addr lo
|
||||
sta typeTblL,y
|
||||
.ld lda $1000,x ; self-modified above: fetch length byte
|
||||
sec
|
||||
sbc #1 ; adjust to be like a string, in that it doesn't include type byte itself
|
||||
sta typeLen,y ; save that too
|
||||
inc nTypes ; bump type count
|
||||
rts
|
||||
@ -879,16 +887,13 @@ heapAlloc: !zone
|
||||
sta pTmp
|
||||
lda heapTop+1
|
||||
sta pTmp+1
|
||||
txa
|
||||
ldy #0
|
||||
sta (pTmp),y ; save obj type or len on heap
|
||||
tay ; test hi bit
|
||||
txa
|
||||
sta (pTmp),y ; save obj type or string len on heap
|
||||
bpl .gotlen
|
||||
and #$7F
|
||||
tay
|
||||
lda typeLen,y
|
||||
lda typeLen-$80,x
|
||||
.gotlen ldy pTmp+1
|
||||
sec ; add 1 for type byte
|
||||
sec ; add 1 to include type byte or len byte for strings
|
||||
adc pTmp
|
||||
bcc +
|
||||
iny
|
||||
@ -901,9 +906,11 @@ heapAlloc: !zone
|
||||
rts
|
||||
.needgc jsr inlineFatal : !text "NeedCollect",0
|
||||
|
||||
; Input : Carry set = add if not found, clear = check only, don't add
|
||||
; Check if blk pSrc is in GC hash; optionally add it if not.
|
||||
; Input : pSrc = blk to check/add
|
||||
; Carry set = add if not found, clear = check only, don't add
|
||||
; Output: Y-reg = index
|
||||
; Carry clear = not found (added if requested), set = found
|
||||
; Carry set = found, clear = not found (added if requested)
|
||||
gcHash_chk: !zone
|
||||
lda pSrc
|
||||
eor pSrc+1
|
||||
@ -983,7 +990,7 @@ heapCheck: !zone
|
||||
bne .stlup
|
||||
; advance to next heap block
|
||||
.nxtblk lda tmp ; get length back
|
||||
sec ; add 1 for type byte
|
||||
sec ; add 1 to account for type byte or string len byte
|
||||
adc pTmp ; advance scan ptr
|
||||
sta pTmp
|
||||
bcc .blklup ; go again
|
||||
@ -1010,8 +1017,7 @@ heapCheck: !zone
|
||||
tay
|
||||
iny ; not much we can do to validate lo byte, so skip it
|
||||
cpy tmp ; ensure offset is within type length
|
||||
beq + ; the very end is ok because len doesn't include type byte
|
||||
bcs heapCorrupt ; but beyond end is not ok
|
||||
bcs heapCorrupt ; beyond end is not ok
|
||||
+ lda (pTmp),y ; get hi byte of ptr
|
||||
beq .tscan ; null is ok
|
||||
cmp heapStartPg ; else check if < start of heap
|
||||
@ -1026,15 +1032,15 @@ heapCorrupt:
|
||||
|
||||
; Phase 1 of Garbage Collection: mark accessible heap blocks starting from the root block
|
||||
gc1_mark: !zone
|
||||
ldx #0 ; clear the hash table
|
||||
ldx #0 ; clear the hash table and set pSrc to the global blk
|
||||
stx gcHash_top
|
||||
stx pSrc
|
||||
lda heapStartPg
|
||||
sta pSrc+1
|
||||
txa
|
||||
- sta gcHash_first,x
|
||||
inx
|
||||
bne -
|
||||
stx pSrc ; X is zero'd from loop above
|
||||
lda heapStartPg
|
||||
sta pSrc+1
|
||||
sec ; sec means add if not found
|
||||
jsr gcHash_chk ; seed the hash, and thus our queue, with the global block
|
||||
clv ; clear V flag to mark phase 1
|
||||
@ -1056,6 +1062,7 @@ gc3_fix:
|
||||
lda gcHash_dstHi,x
|
||||
+ sty pTmp ; store object pointer so we can dereference it
|
||||
sta pTmp+1
|
||||
+prWord pTmp
|
||||
ldy #0 ; first byte
|
||||
lda (pTmp),y ; is the type
|
||||
bpl .outer ; or, if not hi bit, just a string so skip (no ptrs)
|
||||
@ -1069,26 +1076,30 @@ gc3_fix:
|
||||
.ldof lda $1111,x ; self-modified above: get offset entry
|
||||
beq .outer ; zero marks end of list -> go to next block
|
||||
tay
|
||||
lda (pTmp),y ; grab pointer at that offset
|
||||
stx tmp+1 ; save index into type entry
|
||||
lda (pTmp),y ; grab pointer at entry offset
|
||||
sta pSrc
|
||||
sty .fix+1 ; save pointer offset for use if fixing pointers in phase 3
|
||||
iny
|
||||
lda (pTmp),y
|
||||
sta pSrc+1
|
||||
stx tmp+1 ; save index into type entry
|
||||
ora pSrc
|
||||
beq .next ; skip null pointer
|
||||
sec ; sec = we want to add to hash if it's not there
|
||||
bvc +
|
||||
clc ; in phase 3, we don't want to add to hash
|
||||
+ jsr gcHash_chk ; go add it to the hash; ignore return flag
|
||||
bvc + ; skip pointer fixing in phase 1
|
||||
+ jsr gcHash_chk ; go add it to the hash
|
||||
bvc .next ; skip pointer fixing in phase 1
|
||||
bcc .corrup ; in phase 3, pointer must be in hash!
|
||||
.fix ldy #11 ; restore pointer offset
|
||||
tya
|
||||
tax ; put block number in X
|
||||
.fix ldy #11 ; restore pointer offset (self-modified above)
|
||||
lda gcHash_dstLo,x ; get new location
|
||||
sta (pTmp),y ; update the pointer
|
||||
iny
|
||||
lda gcHash_dstHi,x ; hi byte too
|
||||
sta (pTmp),y
|
||||
+ ldx tmp+1 ; restore type entry index
|
||||
.next ldx tmp+1 ; restore type entry index
|
||||
inx ; next offset entry
|
||||
bne .ldof ; always taken
|
||||
.done rts
|
||||
@ -1105,13 +1116,19 @@ gc2_sweep: !zone
|
||||
.outer clc ; clc = do not add to hash
|
||||
jsr gcHash_chk ; is this block in hash?
|
||||
; note: next 20 lines or so *must* preserve the carry flag
|
||||
bcc +
|
||||
bcc + ; if not in hash, don't set any dest addr
|
||||
|
||||
+prWord pSrc
|
||||
+prStr : !text "->",0
|
||||
+prWord pDst
|
||||
+crout
|
||||
|
||||
lda pDst
|
||||
sta gcHash_dstLo,x ; record new address
|
||||
sta gcHash_dstLo,y ; record new address
|
||||
eor pSrc
|
||||
sta tmp
|
||||
lda pDst+1
|
||||
sta gcHash_dstHi,x ; in hash table
|
||||
sta gcHash_dstHi,y ; in hash table
|
||||
eor pSrc+1
|
||||
ora tmp
|
||||
sta tmp ; this will be zero iff all 16 bits of pSrc == pDst
|
||||
@ -1123,23 +1140,23 @@ gc2_sweep: !zone
|
||||
lda typeLen,x
|
||||
.gotlen sta reqLen ; save len for later
|
||||
bcc .advSrc ; finally act on carry (hash check flg): if block not in hash, skip block
|
||||
tax ; and in index for copying
|
||||
tax ; and in index for byte-copy count
|
||||
lda tmp ; check for pSrc == pDst
|
||||
beq .advDst ; if equal, no need to copy
|
||||
+ inx ; set up to copy type byte as well
|
||||
inx ; set up to copy type/len byte as well
|
||||
.cplup lda (pSrc),y
|
||||
sta (pDst),y
|
||||
iny
|
||||
dex
|
||||
bne .cplup
|
||||
.advDst lda pDst ; advance dest
|
||||
sec ; +1 for type byte
|
||||
sec ; add 1 for type/len byte
|
||||
adc reqLen
|
||||
sta pDst
|
||||
bcc .advSrc
|
||||
inc pDst+1
|
||||
.advSrc lda pSrc ; advance source
|
||||
sec ; +1 for type byte
|
||||
sec ; add 1 for type/len byte
|
||||
adc reqLen
|
||||
sta pSrc
|
||||
bcc +
|
||||
@ -1147,7 +1164,13 @@ gc2_sweep: !zone
|
||||
+ cmp heapTop ; end of heap yet? (lo byte check)
|
||||
lda pSrc+1
|
||||
sbc heapTop+1 ; (hi byte check)
|
||||
bcc .outer ; if not, loop again
|
||||
bcs .done ; if not, loop again
|
||||
jmp .outer
|
||||
.done lda pDst ; done sweeping, so set new heap top.
|
||||
sta heapTop
|
||||
lda pDst+1
|
||||
sta heapTop+1
|
||||
+prWord heapTop
|
||||
rts
|
||||
|
||||
heapCollect: !zone
|
||||
|
@ -106,8 +106,8 @@ end
|
||||
|
||||
// Table per type, starts with length, then pointer offsets, ending with zero.
|
||||
byte typeTbl_Global[] = Global, players, 0
|
||||
byte typeTbl_Player[] = Player, nextObj, items, 0
|
||||
byte typeTbl_Item[] = Item, nextObj, 0
|
||||
byte typeTbl_Player[] = Player, nextObj, name, items, 0
|
||||
byte typeTbl_Item[] = Item, nextObj, name, 0
|
||||
|
||||
byte typeLengths[10]
|
||||
byte typeCounts[256]
|
||||
@ -437,6 +437,13 @@ asm puts
|
||||
rts
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Get a character from the keyboard
|
||||
asm rdkey
|
||||
+asmPlasm 0
|
||||
jmp rdkey
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Print part of a string, until we hit the end or a '%' code. Return how far we got, or -1 for end.
|
||||
asm partialPrintf
|
||||
@ -801,11 +808,7 @@ end
|
||||
// Get a keystroke and convert it to upper case
|
||||
def getUpperKey()
|
||||
byte key
|
||||
while ^keyboard < 128
|
||||
seed = seed+1
|
||||
loop
|
||||
key = ^keyboard & $7F
|
||||
^keystrobe
|
||||
key = rdkey()
|
||||
if key >= $60
|
||||
key = key - $20
|
||||
fin
|
||||
@ -1497,24 +1500,23 @@ end
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
def freeObj(ptr)
|
||||
byte typeNum
|
||||
printf2(" freeObj ptr=$%x", ptr)
|
||||
if ptr == NULL; return; fin
|
||||
typeNum = ^ptr
|
||||
typeCounts[typeNum] = typeCounts[typeNum] - 1
|
||||
if typeCounts[typeNum] == 0
|
||||
when type
|
||||
is TYPE_GLOBAL
|
||||
fatal("can't free global obj")
|
||||
is TYPE_PLAYER
|
||||
freeObj(ptr:nextObj)
|
||||
freeObj(ptr:name)
|
||||
freeObj(ptr:items)
|
||||
break
|
||||
is TYPE_ITEM
|
||||
freeObj(ptr:nextObj)
|
||||
freeObj(ptr:name)
|
||||
break
|
||||
wend
|
||||
fin
|
||||
when type
|
||||
is TYPE_GLOBAL
|
||||
fatal("can't free global obj")
|
||||
is TYPE_PLAYER
|
||||
freeObj(ptr=>nextObj)
|
||||
freeObj(ptr=>name)
|
||||
freeObj(ptr=>items)
|
||||
break
|
||||
is TYPE_ITEM
|
||||
freeObj(ptr=>nextObj)
|
||||
freeObj(ptr=>name)
|
||||
break
|
||||
wend
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1555,7 +1557,7 @@ def findTestString(len)
|
||||
elsif t < TYPE_GLOBAL or t > TYPE_ITEM
|
||||
fatal("Unknown type in heap")
|
||||
else
|
||||
p = p + typeLengths[t & $7F] + 1
|
||||
p = p + typeLengths[t & $7F]
|
||||
fin
|
||||
loop
|
||||
p = newObj(len)
|
||||
@ -1590,13 +1592,16 @@ def checkHeapCounts()
|
||||
while *p
|
||||
t = ^p
|
||||
printf2(" Type $%x obj at $%x\n", t, p)
|
||||
if p < heapStart or (p-heapStart) >= heapSize
|
||||
fatal("Invalid pointer in heap")
|
||||
fin
|
||||
checkCounts[t] = checkCounts[t] + 1
|
||||
if t < $80
|
||||
p = p + t + 1
|
||||
elsif t < TYPE_GLOBAL or t > TYPE_ITEM
|
||||
fatal("Unknown type in heap")
|
||||
else
|
||||
p = p + typeLengths[t & $7F] + 1
|
||||
p = p + typeLengths[t & $7F]
|
||||
fin
|
||||
loop
|
||||
|
||||
@ -1604,7 +1609,7 @@ def checkHeapCounts()
|
||||
bad = 0
|
||||
for t = 0 to 255
|
||||
if typeCounts[t] <> checkCounts[t]
|
||||
printf3("Count for type $%x should be %d, got %d\n", t, checkCounts[t], typeCounts[t])
|
||||
printf3("Count for type $%x should be %d, got %d\n", t, typeCounts[t], checkCounts[t])
|
||||
bad = bad+1
|
||||
fin
|
||||
next
|
||||
@ -1638,11 +1643,9 @@ def addPlayer()
|
||||
// Create the object, and link it in to the global list
|
||||
puts("Adding player.\n")
|
||||
p = newObj(TYPE_PLAYER)
|
||||
p=>nextObj = global=>players
|
||||
global=>players = p
|
||||
|
||||
// Assign attributes
|
||||
p->name = randomString()
|
||||
p=>name = randomString()
|
||||
p->muscle = rand16()
|
||||
p->quickness = rand16()
|
||||
|
||||
@ -1652,17 +1655,46 @@ def addPlayer()
|
||||
next
|
||||
|
||||
p->health = rand16()
|
||||
|
||||
p=>nextObj = global=>players
|
||||
global=>players = p
|
||||
|
||||
return p
|
||||
end
|
||||
|
||||
def unlinkPlayer(toRemove)
|
||||
word p
|
||||
word prev
|
||||
prev = NULL
|
||||
p = global=>players
|
||||
if p == toRemove
|
||||
global=>players = p=>nextObj
|
||||
p=>nextObj = NULL
|
||||
return
|
||||
fin
|
||||
while p
|
||||
if p == toRemove
|
||||
prev=>nextObj = p=>nextObj
|
||||
p=>nextObj = NULL
|
||||
return
|
||||
fin
|
||||
p = p=>nextObj
|
||||
loop
|
||||
fatal("Obj to unlink not in list")
|
||||
end
|
||||
|
||||
def collect()
|
||||
word nFree
|
||||
puts("Checking heap counts.\n")
|
||||
checkHeapCounts()
|
||||
puts("*** NEED TO DO MEM CHECK SOON\n")
|
||||
// memMgr(MEM_CHECK, 0)
|
||||
puts("Collecting garbage.\n")
|
||||
nFree = mmgr(HEAP_COLLECT, 0)
|
||||
printf1(" heap avail=$%x\n", nFree)
|
||||
getUpperKey()
|
||||
puts("Checking heap counts.\n")
|
||||
checkHeapCounts()
|
||||
puts("*** NEED TO DO MEM CHECK SOON\n")
|
||||
// memMgr(MEM_CHECK, 0)
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1674,6 +1706,19 @@ def testHeap()
|
||||
collect()
|
||||
addPlayer()
|
||||
collect()
|
||||
p = global=>players
|
||||
while p
|
||||
printf1("A player: $%x\n", p)
|
||||
p = p=>nextObj
|
||||
loop
|
||||
p = global=>players
|
||||
p = p=>nextObj
|
||||
printf1("Unlinking player $%x\n", p)
|
||||
unlinkPlayer(p)
|
||||
puts("Freeing player\n")
|
||||
freeObj(p)
|
||||
puts("Collecting.\n")
|
||||
collect()
|
||||
puts("Heap test complete. Hit a key.\n")
|
||||
getUpperKey()
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user