VM02/src/memmgr.s

3096 lines
47 KiB
ArmAsm
Executable File

;*
;* JAVA MEMORY MANAGER FOR 6502
;*
;*
;* HANDLE TABLE IS A TABLE OF POINTERS TO MEMORY BLOCKS
;*
;* THE LOW ORDER 3 BITS ARE STATE BITS FOR THE MEMORY BLOCK
;* 1 (001) = IN USE
;* 3 (011) = FIXED - HAS TO REMAIN IN PLACE
;* 5 (101) = CODE
;* 7 (111) = SWAPPED - NEEDS TO BE RELOADED FROM SOURCE OR SWAP
;*
;*
;* MEMORY BLOCKS ARE ALIGNED ON 64 BIT BOUNDARIES
;*
;*
;* A MEMORY HANDLE IS A POINTER TO THE ENTRY IN THE TABLE
;*
;* AN ALLOCATED MEMORY BLOCK IS ORGANIZED AS:
;* OFFSET SIZE FUNCTION
;* 0 2 SIZE
;* 2 2 REF CNT - MSB = ACCESSED BIT
;* 4 ? DATA
;* A FREE MEMORY BLOCK IS ORGANIZED AS:
;* OFFSET SIZE FUNCTION
;* 0 2 SIZE
;* 2 2 HNEXT
.INCLUDE "global.inc"
.INCLUDE "dvm.inc"
.IMPORT INIT_START,INIT_END,WARM_INIT
.IMPORT PRNTAX,COUT,CROUT,PUTS,PUTSLN,PRBYTE,PRSTR,PRSTRLN,MEMCPY,MEMCLR,KBWAIT
.IMPORT SYSTHROW,THROW_INTERNALERR
.IFDEF SWAPPING
.IMPORT PREFIX_GET,DIR_CREATE,FILE_GETINFO,FILE_CREATE,FILE_DESTROY,FILE_OPEN,FILE_CLOSE
.IMPORT FILE_GETEOF,FILE_READ,FILE_WRITE,FILE_SETBUFFER,FILE_SETAUX,ON_LINE
.EXPORT HMEM_CLRACCESS,HMEM_SWAP_CLEANUP
.ENDIF
.EXPORT HMEM_INIT
.EXPORT HMEM_ALLOC,HMEM_ALLOC_CODE,HMEM_ALLOC_FIXED,HMEM_FREE
.EXPORT HMEM_PTR,HMEM_REF_INC,HMEM_REF_DEC,HMEM_CLR
.EXPORT HMEM_LOCK,HMEM_UNLOCK,HMEM_UNLOCK_CODE,HMEM_GC
.IFDEF IDLE_GC
.EXPORT HMEM_GC_IDLE
.ENDIF
.MACRO CHKAUXLC
.IFDEF DEBUG_MEMMGR
.IFDEF BIGMEM
PHA
LDA $C016
BPL :+
AUXZP_ACCESS_OFF
PERR "AUXZP ENABLED"
BRK
: PLA
.ENDIF
.ENDIF
.ENDMACRO
.MACRO CHKHNDL
.IFDEF DEBUG
CPX #>HTBL
BCS :+
CPX #>HTBL_END
BCC :+
AUXZP_ACCESS_OFF
PERR "BAD HNDL"
BRK
:
.ENDIF
.ENDMACRO
.SEGMENT "INIT"
;*
;* CREATE EXTERNAL LINKEAGE TABLE AT $302
;*
HMEM_INIT: LDA #<HMEM_PTR
STA LINK_HMEMPTR
LDA #>HMEM_PTR
STA LINK_HMEMPTR+1
LDA #<HMEM_ALLOC
STA LINK_HMEMALLOC
LDA #>HMEM_ALLOC
STA LINK_HMEMALLOC+1
LDA #<HMEM_ALLOC_FIXED
STA LINK_HMEMALLOCFIXED
LDA #>HMEM_ALLOC_FIXED
STA LINK_HMEMALLOCFIXED+1
LDA #<HMEM_FREE
STA LINK_HMEMFREE
LDA #>HMEM_FREE
STA LINK_HMEMFREE+1
LDA #<HMEM_LOCK
STA LINK_HMEMLOCK
LDA #>HMEM_LOCK
STA LINK_HMEMLOCK+1
LDA #<HMEM_UNLOCK
STA LINK_HMEMUNLOCK
LDA #>HMEM_UNLOCK
STA LINK_HMEMUNLOCK+1
LDA #<HMEM_REF_INC
STA LINK_HMEMREFINC
LDA #>HMEM_REF_INC
STA LINK_HMEMREFINC+1
LDA #<HMEM_REF_DEC
STA LINK_HMEMREFDEC
LDA #>HMEM_REF_DEC
STA LINK_HMEMREFDEC+1
LDA #<HMEM_GC
STA LINK_GC
LDA #>HMEM_GC
STA LINK_GC+1
.IFDEF BIGMEM
LDA #$00 ; TOP OF FREE MEMORY IN AUX SPACE
STA CODEHEAPTOP
LDA #$BF
STA CODEHEAPTOP+1
.ENDIF
;*
;* INITIALIZE THE HANDLE TABLE
;*
AUXZP_ACCESS_ON
BIT LCBNK2 ; MAKE SURE LCBANK2 SET UP
BIT LCBNK2
LDX #<HTBL
STX HUNUSED
LDA #>HTBL
STA HUNUSED+1
LINK_UNUSED: STX HNDL
STA HNDL+1
LDA HNDL
CLC ; MAKE UNUSED HANDLE LIST
ADC #$02
STA (HNDL),Y
TAX
INY
LDA HNDL+1
ADC #$00
STA (HNDL),Y
DEY
CMP #>HTBL_END
BNE LINK_UNUSED
TYA
STA (HNDL),Y ; NULL OUT LAST IN LIST
INY
STA (HNDL),Y
JSR HMEM_NEW ; GET NEXT AVAIL HANDLE
STA HFREE ; MAKE INITAL FREE BLOCK
STX HFREE+1
.IFDEF DEBUG_MEMMGR
STA HFREEBAK ; MAKE INITAL FREE BLOCK
STX HFREEBAK+1
.ENDIF
LDY #$00 ; SET FREE MEM PTR
LDA #<INIT_START
CLC
ADC #$07
AND #$F8
STA MPTR
STA (HFREE),Y
INY
LDA #>INIT_START
ADC #$00
STA MPTR+1
STA (HFREE),Y
DEY ; SET FREE MEM SIZE
LDA #<TOPOFHEAP
SEC
SBC MPTR
STA (MPTR),Y
INY
LDA #>TOPOFHEAP
SBC MPTR+1
STA (MPTR),Y
INY
LDA #$00 ; NULL OUT NEXT FREE HANDLE
STA (MPTR),Y
INY
STA (MPTR),Y
AUXZP_ACCESS_OFF
LDA WARM_INIT
BNE :+
LDA #'$'
JSR COUT
AUXZP_ACCESS_ON
LDY #$00
LDA (MPTR),Y
INY
TAX
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
PSTRLN " bytes available"
:
.IFDEF DEBUG
AUXZP_ACCESS_ON
LDY #$00
LDA (MPTR),Y
INY
STA RAMAVAIL
LDA (MPTR),Y
STA RAMAVAIL+1
AUXZP_ACCESS_OFF
.ENDIF
.IFDEF DEBUG_MEMMGR
; JSR HMEM_DUMP
; JSR CROUT
.ENDIF
.IFDEF SWAPPING
;
; FIND THE MOST APPROPRIATE SWAP VOLUME
;
.IFDEF DEBUG_SWAP
PSTRLN "SWAPPING ENABLED"
; JSR KBWAIT
.ENDIF
LDX #$0F
FINDBESTVOL: STX VCNT
TXA
AND #$07
BEQ :+
CMP SKIPSLOT
BNE :++
: JMP VOLNXT
: TXA
ASL
ASL
ASL
ASL
TAY
LDX #>CLASSFILE_IO_BUFF
JSR ON_LINE
LDX VCNT
JSR CPYVOL
BCC :+
JMP VOLNXT
: LDA #<SWAPFILE
LDX #>SWAPFILE
JSR FILE_GETINFO
BCC :+
JSR PUTS
.ASCIIZ "ERROR GETING VOLUME INFO:"
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR PRSTRLN
BRK
: STA TMPTR
STX TMPTR+1
LDY #$05
LDA (TMPTR),Y
LDY #$08
SEC
SBC (TMPTR),Y
STA HBEST
LDY #$06
LDA (TMPTR),Y
LDY #$09
SBC (TMPTR),Y
STA HBEST+1
LDA SWAPFILE+2
AND #$7F
CMP #'R'
BNE CHKFREE
LDA SWAPFILE+3
AND #$7F
CMP #'A'
BNE CHKFREE
LDA SWAPFILE+4
AND #$7F
CMP #'M'
BNE CHKFREE
LDY #$00 ; OFFSET FOR BEST RAM VOL
BEQ :+
CHKFREE: LDY #$03 ; OFFSET FOR BEST DEV VOL
: LDA HBEST+1
CMP BESTFREE+1,Y
BCC VOLNXT
BEQ :+
BCS SAVEVOL
: LDA HBEST
CMP BESTFREE,Y
BCC VOLNXT
BEQ VOLNXT
SAVEVOL: LDA HBEST
STA BESTFREE,Y
LDA HBEST+1
STA BESTFREE+1,Y
LDA VCNT
STA BESTVOL,Y
VOLNXT: LDX VCNT
DEX
BEQ :+
JMP FINDBESTVOL
: LDX BESTRAMVOL
LDA BESTRAMFREE+1 ; RAM VOL MUST HAVE AT LEAST 64K FREE
BNE SAVEBESTVOL
LDA BESTRAMFREE
BMI SAVEBESTVOL
LDX BESTDEVVOL
BPL SAVEBESTVOL
LDA SKIPSLOT ; NO WORKABLE DEVICES FOUND, REMOVE SLOT 6 SKIP
BNE :+ ; AND TRY AGAIN
PSTRLN "HALT: NO SWAP VOLUME AVAILABLE!"
BRK
: LDA #$00
STA SKIPSLOT
STA BESTRAMVOL
STA BESTDEVVOL
STA BESTRAMFREE
STA BESTRAMFREE+1
STA BESTDEVFREE
STA BESTDEVFREE+1
LDX #$0F
JMP FINDBESTVOL
SAVEBESTVOL: JSR CPYVOL
INC SWAPFILE
LDX SWAPFILE
LDA #'/'
STA SWAPFILE,X
LDY #$00
CPYSWPDIR: LDA SWAPDIR,Y
BEQ :+
INX
STA SWAPFILE,X
INY
BNE CPYSWPDIR
: STX SWAPFILE
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR DIR_CREATE
LDX SWAPFILE
LDA #'/'
STA SWAPFILE+1,X
;.IFDEF DEBUG_SWAP
INX
STX SWAPFILE
LDA WARM_INIT
BNE :+
JSR PUTS
.ASCIIZ "Swap path:"
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR PRSTRLN
: LDX SWAPFILE
DEX
;.ENDIF
TXA
CLC
ADC #$05 ; ADD SPACE FOR SWAPFILE NAME
STA SWAPFILE
RTS
CPYVOL: TXA
ASL
ASL
ASL
ASL
TAY
LDA CLASSFILE_IO_BUFF,Y
AND #$0F
BNE :+
SEC
RTS
: STA SWAPFILE
TAX
TYA
CLC
ADC SWAPFILE
TAY
INC SWAPFILE
LDA #'/'
STA SWAPFILE+1
: LDA CLASSFILE_IO_BUFF,Y
STA SWAPFILE+1,X
DEY
DEX
BNE :-
CLC
RTS
;*
;* CLEANUP SWAP DIRECTORY
;* CALLED AFTER RELOADING VM02 FOR WARM INIT/RESET
;*
HMEM_SWAP_CLEANUP:
.IFDEF DEBUG_SWAP
JSR PUTSLN
.ASCIIZ "CLEAN UP SWAP FILES"
.ENDIF
LDX #>HTBL
LDA #<HTBL
SWPCLNLP: AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL), Y
AND #$07 ; LOOK FOR SWAPPED BLOCKS
CMP #$07
BNE SWPCLNNXT
LDA HNDL
PHA
LDA HNDL+1
PHA
LDA HNDL
LDX HNDL+1
AUXZP_ACCESS_OFF
JSR SETSWAPFILE
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR FILE_DESTROY ; REMOVE ANY EXISTING FILE
AUXZP_ACCESS_ON
PLA
STA HNDL+1
PLA
STA HNDL
SWPCLNNXT: LDA HNDL
LDX HNDL+1 ; NEXT HANDLE
AUXZP_ACCESS_OFF
CLC
ADC #$02
BCC :+
INX
: CPX #>HTBL_END
BCC SWPCLNLP
LDA SWAPFILE
SEC
SBC #$05
STA SWAPFILE
LDA #<SWAPFILE
LDX #>SWAPFILE
JMP FILE_DESTROY ; REMOVE SWAP DIRECTORY
SWAPDIR: .ASCIIZ "SWAP"
BESTVOL:
BESTRAMVOL: .BYTE $FF
BESTFREE:
BESTRAMFREE: .WORD $0000
BESTDEVVOL: .BYTE $FF
BESTDEVFREE: .WORD $0000
SKIPSLOT: .BYTE $06 ; SKIP SLOT SIX SWAP TEST INITIALLY
.DATA
SWAPHNDL: .WORD $0000
SWAPREF: .BYTE $00
SWPAXED: .BYTE $00 ; MASK FOR ACCESSED TEST
SWPMINSIZE: .BYTE $00
SWPLEN: .WORD $0000
.ELSE
RTS
.ENDIF
;*
;* MEMORY MANAGER
;*
.CODE
;*
;* CONVERT HANDLE TO POINTER
;* ENTRYY: AX = HANDLE
;* EXIT: AX = POINTER
;*
HMEM_PTR: CHKAUXLC
CHKHNDL
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
.IFDEF DEBUG_MEMMGR
JSR HMEM_VALIDATE
.ENDIF
.IFDEF SWAPPING
LDY #$00
LDA (HNDL),Y
.IFDEF DEBUG
LSR
BCS :+
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "HMEM_PTR BEING CALLED ON FREE HANDLE: $"
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
BRK
; JMP THROW_INTERNALERR
: ROL
.ENDIF
AND #$07
CMP #$07
BEQ HMEM_SWAPIN
LDA (HNDL),Y
AND #$F8
STA MPTR
INY
LDA (HNDL),Y
STA MPTR+1
TAX
LDY #$03
LDA (MPTR),Y
ORA #$80 ; SET ACCESSED FLAG
STA (MPTR),Y
LDA MPTR
.ELSE
LDY #$01
LDA (HNDL),Y
DEY
TAX
LDA (HNDL),Y
AND #$F8
.ENDIF
AUXZP_ACCESS_OFF
ORA #$04 ; RETURN POINTER
RTS
.IFDEF SWAPPING
;*
;* SWAP IN HANDLE MEMORY FROM FILE
;* ENTRY: HNDL = HANDLE
;*
HMEM_SWAPIN:
.IFDEF DEBUG_SWAP
AUXZP_ACCESS_OFF
JSR CROUT
JSR PUTS
.ASCIIZ "SWAPPING IN MEMORY HANDLE: "
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
; JSR KBWAIT
AUXZP_ACCESS_ON
.ENDIF
LDA HNDL
STA SWAPHNDL
LDX HNDL+1
STX SWAPHNDL+1
LDY #$00 ; PULL BLOCK SIZE FROM HANDLE
LDA (HNDL),Y
INY
AND #$F8
SEC
.IFDEF DEBUG_MEMMGR
STA SWPLENBAK
LDA (HNDL),Y
STA SWPLENBAK+1
LDA SWPLENBAK
SBC #$06
.ELSE
SBC #$04
.ENDIF
PHA ; AND PUSH IT FOR LATER
STA TMP
LDA (HNDL),Y
SBC #$00
TAX
PHA
LDA TMP
.IFDEF DEBUG_SWAP
PHA
TXA
PHA
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ ", LENGTH: "
AUXZP_ACCESS_ON
PLA
STA TMP+1
PLA
STA TMP
TAX
LDA TMP+1
LDX TMP
AUXZP_ACCESS_OFF
JSR PRNTAX
AUXZP_ACCESS_ON
LDA TMP
LDX TMP+1
LDY #$00
.ENDIF
AUXZP_ACCESS_OFF
JSR HMEM_ALLOC ; ALLOCATE MEMORY
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL),Y
INY
AND #$F8
STA MPTR
LDA (HNDL),Y
STA MPTR+1 ; SAVE POINTER
.IFDEF DEBUG_MEMMGR
LDY #$00
LDA (MPTR),Y
CMP SWPLENBAK
BNE :+
INY
LDA (MPTR),Y
CMP SWPLENBAK+1
BEQ :++
: LDX SWPLENBAK
LDA SWPLENBAK+1
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " SWAPIN SIZE != ALLOC SIZE "
AUXZP_ACCESS_ON
LDY #$00
LDA (MPTR),Y
INY
TAX
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
BRK
SWPLENBAK: .WORD 0
:
.ENDIF
.IFDEF DEBUG_SWAP
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ ", ADDRESS: "
AUXZP_ACCESS_ON
LDA MPTR+1
LDX MPTR
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
LDY #$01
.ENDIF
LDA HUNUSED+1 ; RETURN HANDLE TO UNUSED LIST
STA (HNDL),Y
DEY
LDA HUNUSED
STA (HNDL),Y
LDA HNDL
STA HUNUSED
LDA HNDL+1
STA HUNUSED+1
LDA SWAPHNDL ; ATTACH MEMORY TO SWAPIN HANDLE
STA HNDL
LDX SWAPHNDL+1
STX HNDL+1
JSR SETSWAPFILE
LDY #$00
LDA MPTR
STA (HNDL),Y
INY
LDA MPTR+1
STA (HNDL),Y
AUXZP_ACCESS_OFF
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR FILE_GETINFO
BCS SWAPINERR
AUXZP_ACCESS_ON
STA TMPTR
STX TMPTR+1
LDY #$04 ; READ FILE TYPE
LDA (TMPTR),Y
LDY #$00
AND #$07 ; RESTORE HANDLE TYPE BITS
ORA (HNDL),Y
STA (HNDL),Y
; LDY #$06 ; RESTORE MEMORY BLOCK REF COUNTS
; LDA (TMPTR),Y
; DEY
; TAX
; LDA (TMPTR),Y
; LDY #$02
; STA (MPTR),Y
; INY
; TXA
; ORA #$80 ; SET ACCESSED FLAG
; STA (MPTR),Y
LDY #$03
LDA (MPTR),Y
ORA #$80 ; SET ACCESSED FLAG
STA (MPTR),Y
AUXZP_ACCESS_OFF
LDA #<SWAPFILE
LDX #>SWAPFILE
LDY #>SWAPFILE_IO_BUFF
JSR FILE_OPEN ; READ SWAPFILE
BCS SWAPINERR
STY SWAPREF
AUXZP_ACCESS_ON
LDA MPTR
; ORA #$04
ORA #$02
LDX MPTR+1
JSR FILE_SETBUFFER ; SET DESTINATION FOR READ
PLA ; PULL SIZE
TAX
PLA
AUXZP_ACCESS_OFF
CLC
ADC #$02 ; ADD SIZE OF REF COUNT
BCC :+
INX
: LDY SWAPREF
JSR FILE_READ ; READ IT!
BCS SWAPINERR
LDY SWAPREF
JSR FILE_CLOSE
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR FILE_DESTROY ; REMOVE EXISTING FILE
.IF 0
JSR PUTS
.ASCIIZ "SWAPIN AUX REF COUNT: "
AUXZP_ACCESS_ON
LDY #$02
LDA (MPTR),Y ; GET REFERENCE COUNTS OF MEMORY BLOCK
INY
TAX
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
.ENDIF
AUXZP_ACCESS_ON
.IFDEF DEBUG_MEMMGR
LDA SWAPHNDL
LDX SWAPHNDL+1
JSR HMEM_VALIDATE
.ENDIF
LDA MPTR
ORA #$04
LDX MPTR+1
AUXZP_ACCESS_OFF
RTS
SWAPINERR:
.IFDEF DEBUG_SWAP
AUXZP_ACCESS_OFF
PHA
JSR PUTS
.ASCIIZ "ERROR "
PLA
JSR PRBYTE
JSR PUTS
.ASCIIZ " READING FROM SWAPFILE: "
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR PRSTRLN
.ENDIF
JMP THROW_INTERNALERR
;*
;* SET SWAP FILE NAME BASED ON HANDLE
;* ENTRY: AX = HANDLE
;*
SETSWAPFILE: PHA
TXA
JSR BYTE2ASCII
LDX SWAPFILE ; GET SWAPFILE NAME LENGTH
STA SWAPFILE-3,X
TYA
STA SWAPFILE-2,X
PLA
JSR BYTE2ASCII
STA SWAPFILE-1,X
TYA
STA SWAPFILE-0,X
RTS
;*
;* CONVERT BYTE VALUE TO ASCII REPRESENTATION
;* ENTRY: A = BYTE
;* EXIT: A = ASCII HI NIBBLE
;* Y = ASCII LO NIBBLE
;*
BYTE2ASCII: PHA
AND #$0F
CLC
ADC #'0'
CMP #'9'+1
BCC :+
ADC #'A'-'9'-2
: TAY
PLA
LSR
LSR
LSR
LSR
CLC
ADC #'0'
CMP #'9'+1
BCC :+
ADC #'A'-'9'-2
: RTS
.ENDIF
;*
;* CLEAR MEMORY BLOCK
;* ENTRY: AX = HANDLE
;* EXIT: AX = HANDLE
;*
HMEM_CLR: CHKAUXLC
CHKHNDL
.IFDEF BIGMEM
STA HNDL ; THIS IS SAVED TO MAIN ZP, NOT AUX
STX HNDL+1
.ENDIF
JSR HMEM_PTR
STA DSTADDR
STX DSTADDR+1
AND #$F8 ; POINT BACK TO HEADER
STA MPTR
STX MPTR+1
LDY #$01
LDA (MPTR),Y
DEY
TAX
LDA (MPTR),Y
SEC
.IFDEF DEBUG_MEMMGR
SBC #$06 ; SUBTRACT FENCE+HEADER SIZE
.ELSE
SBC #$04 ; SUBTRACT HEADER SIZE
.ENDIF
BCS :+
DEX
: JSR MEMCLR ; CLEAR BLOCK
LDA HNDL ; RELOAD HANDLE INTO AX
LDX HNDL+1
RTS
;*
;* INCREMENT REFERENCE COUNT
;* ENTRY: AX = HANDLE
;* EXIT: AX = HANDLE
;*
HMEM_REF_INC: CHKAUXLC
CHKHNDL
.IFDEF DEBUG_MEMMGR
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
JSR HMEM_VALIDATE
LDA HNDL
LDX HNDL+1
AUXZP_ACCESS_OFF
.ENDIF
.IF 0
STA HNDL
STX HNDL+1
JSR PUTS
.ASCIIZ "INC REF: $"
LDA HNDL+1
LDX HNDL
JSR PRNTAX
JSR CROUT
LDA HNDL
LDX HNDL+1
.ENDIF
.IFDEF SWAPPING
JSR HMEM_PTR
AUXZP_ACCESS_ON
LDX HNDL+1
LDY #$02
.ELSE
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL),Y
INY
AND #$F8
STA MPTR
LDA (HNDL),Y
INY
STA MPTR+1
.ENDIF
LDA (MPTR),Y
CLC
ADC #$01
STA (MPTR),Y
INY
LDA (MPTR),Y
ADC #$00
.IFDEF SWAPPING
ORA #$80 ; SET ACCESSED FLAG
.ENDIF
STA (MPTR),Y
LDA HNDL
AUXZP_ACCESS_OFF
RTS
;*
;* DECREMENT REFERENCE COUNT
;* ENTRY: AX = HANDLE
;* EXIT: AX = REF COUNT
;*
HMEM_REF_DEC: CHKAUXLC
CHKHNDL
.IFDEF DEBUG_MEMMGR
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
JSR HMEM_VALIDATE
LDA HNDL
LDX HNDL+1
AUXZP_ACCESS_OFF
.ENDIF
.IF 0
STA HNDL
STX HNDL+1
JSR PUTS
.ASCIIZ "DEC REF: $"
LDA HNDL+1
LDX HNDL
JSR PRNTAX
JSR CROUT
LDA HNDL
LDX HNDL+1
.ENDIF
.IFDEF SWAPPING
JSR HMEM_PTR
LDY #$02
AUXZP_ACCESS_ON
.ELSE
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00 ; DEREF HANDLE
LDA (HNDL),Y
INY
AND #$F8
STA MPTR
LDA (HNDL),Y
INY
STA MPTR+1
.ENDIF
LDA (MPTR),Y
SEC ; DEC REF COUNT
SBC #$01
STA (MPTR),Y
INY
PHA
LDA (MPTR),Y
AND #$7F
SBC #$00
TAX
.IFDEF SWAPPING
ORA #$80 ; SET ACCESSED FLAG
.ENDIF
STA (MPTR),Y
PLA
AUXZP_ACCESS_OFF
RTS
;*
;* LOCK MEMORY BLOCK IN PLACE
;* ENTRY: AX = HANDLE
;* EXIT: AX = POINTER
;*
HMEM_LOCK: JSR HMEM_PTR ; MAKE SURE MEM BLOCK PRESENT
.IF 0
JSR PUTS
.ASCIIZ "LOCKING HANDLE: "
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
LDY #$01
LDA (HNDL),Y
DEY
TAX
LDA (HNDL),Y
.ENDIF
LDY #$00
AND #$F8
ORA #$03 ; CHANGE FLAGS TO LOCKED
AUXZP_ACCESS_ON
STA (HNDL),Y ; AND SAVE
AUXZP_ACCESS_OFF
AND #$F8
ORA #$04
RTS
;*
;* UNLOCK MEMORY BLOCK
;* ENTRY: AX = HANDLE
;*
HMEM_UNLOCK: CHKHNDL
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
.IF 0
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "UNLOCKING HANDLE: "
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
LDA HNDL
LDX HNDL+1
.ENDIF
.IFDEF DEBUG_MEMMGR
JSR HMEM_VALIDATE
.ENDIF
LDY #$00
LDA (HNDL),Y
.IFDEF DEBUG_MEMMGR
TAX
AND #$07
CMP #$03
BEQ :+
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "UNLOCKING UNLOCKED HANDLE :"
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
JMP THROW_INTERNALERR
: TXA
LDY #$00
.ENDIF
AND #$F8
.IFDEF SWAPPING
STA MPTR
.ENDIF
ORA #$01
STA (HNDL),Y
AUXZP_ACCESS_OFF
RTS
;*
;* UNLOCK CODE MEMORY BLOCK
;* ENTRY: AX = HANDLE
;*
HMEM_UNLOCK_CODE: JSR HMEM_UNLOCK
LDY #$00
AUXZP_ACCESS_ON
LDA (HNDL),Y
ORA #$04
STA (HNDL),Y
AUXZP_ACCESS_OFF
RTS
;*
;* GET NEXT AVAILABLE HANDLE
;*
HMEM_NEW: LDA HUNUSED
LDX HUNUSED+1
BEQ HNEW_GC
PHA
LDY #$00
LDA (HUNUSED),Y
PHA
INY
LDA (HUNUSED),Y
STA HUNUSED+1
PLA
STA HUNUSED
PLA
CLC
RTS
HNEW_GC: AUXZP_ACCESS_OFF
JSR HMEM_COALESCE ; ATTEMPT EASY FREE SPACE COMBINE
AUXZP_ACCESS_ON
BCC HMEM_NEW
AUXZP_ACCESS_OFF
JSR HMEM_COMPACT ; ATTEMPT FREE SPACE COMPACTION
AUXZP_ACCESS_ON
BCC HNEW_GC
AUXZP_ACCESS_OFF
PERR "OUT OF MEMORY HANDLES"
; JSR HMEM_DUMP
; BRK
JMP THROW_INTERNALERR
;*
;* UNLINK FREE BLOCK FROM LIST
;*
HFREE_UNLINK: CMP HFREE
BNE :+
CPX HFREE+1
BNE :+
LDY #$00
LDA (HFREE),Y
INY
TAX
LDA (HFREE),Y
INY
STX HFREE
STA HFREE+1
.IFDEF DEBUG_MEMMGR
STX HFREEBAK ; SAVE BACKUP
STA HFREEBAK+1
.ENDIF
LDA (HFREE),Y ; UNLINK FROM HEAD-OF-LIST
INY
TAX
LDA (HFREE),Y
STX HFREE
STA HFREE+1
.IFDEF DEBUG_MEMMGR
STX HFREEBAK ; SAVE BACKUP
STA HFREEBAK+1
.ENDIF
RTS
: STA TMP
STX TMP+1
LDA HNDL ; SAVE HANDLE
PHA
LDA HNDL+1
PHA
LDA HFREE
LDX HFREE+1
LOOP_UNLINK: STA HNDL ; STORE HANDLE
STX HNDL+1
LDY #$01 ; DEREF HANDLE FOR POINTER
LDA (HNDL),Y
DEY
TAX
LDA (HNDL),Y
STA HNDL
STX HNDL+1
LDY #$03 ; CHECK NEXT HANDLE
LDA (HNDL),Y
.IFDEF DEBUG_MEMMGR
BNE :+
AUXZP_ACCESS_OFF
PERR "UNLINK FREE BLOCK NOT IN LIST"
JMP THROW_INTERNALERR
:
.ENDIF
DEY
TAX
LDA (HNDL),Y
CMP TMP
BNE LOOP_UNLINK
CPX TMP+1
BNE LOOP_UNLINK
DEY ; HANDLES EQUAL
LDA (TMP),Y ; DEREF TMP
DEY
TAX
LDA (TMP),Y
STA TMPTR
STX TMPTR+1
LDY #$03
LDA (TMPTR),Y ; MOVE NEXT LINK TO PREVIOUS
STA (HNDL),Y
DEY
LDA (TMPTR),Y
STA (HNDL),Y
.IFDEF DEBUG_MEMMGR
JSR HFREE_VALIDATE
.ENDIF
PLA ; RESTORE HNDL
STA HNDL+1
PLA
STA HNDL
RTS
;*
;* ALLOCATE A MEMORY BLOCK
;* ENTRY: AX (LH) = SIZE
;* Y = INITIAL REF COUNT
;* EXIT: AX = HANDLE :: C == 0
;* ERR :: C == 1
;*
HMEM_ALLOC: CHKAUXLC
.IFDEF DEBUG
CPX #$10
BCC :+
STA MLEN
STX MLEN+1
PERR "Big alloc: $"
LDX MLEN
LDA MLEN+1
JSR PRNTAX
JSR CROUT
LDA MLEN
LDX MLEN+1
; JMP THROW_INTERNALERR
:
.ENDIF
AUXZP_ACCESS_ON
STY REFCNT
CLC ; ADD SIZE OF HEADER (4 + 7)
.IFDEF DEBUG_MEMMGR
ADC #$0D ; AND ROUND TO MULTIPLE OF 8 BYTES
.ELSE
ADC #$0B ; AND ROUND TO MULTIPLE OF 8 BYTES
.ENDIF
BCC :+
INX
: AND #$F8
STA MLEN
STX MLEN+1
.IFDEF DEBUG_MEMMGR
STA MLENBAK
STX MLENBAK+1
JMP SEARCH_FREE
MLENBAK: .WORD $0000
.ENDIF
SEARCH_FREE: LDA HFREE ; SEARCH FREE LIST FOR AVAILABLE SPACE
STA HNDL
LDA HFREE+1
STA HNDL+1
BEQ MAKE_FREE_AVAIL
LDA #$00 ; CLEAR OUT BEST MATCH
; STA HBEST
STA HBEST+1
LOOP_FREE: AUXZP_ACCESS_ON
LDY #$01 ; DEREF HANDLE
LDA (HNDL),Y
DEY
STA MPTR+1
LDA (HNDL),Y
STA MPTR
LDA (MPTR),Y
INY
SEC
SBC MLEN
TAX
LDA (MPTR),Y
SBC MLEN+1
BCC NEXT_FREE
BNE :+
CPX #$00
BNE :+
JMP MATCH_FREE
: LDA HBEST+1 ; CHECK FOR EXISTING BEST MATCH
BEQ SAVE_BEST ; SAVE ONE WITH HIGHEST ADDRESS
LDA (HNDL),Y ; COMPARE FREE BLOCK ADDRESSES
CMP (HBEST),Y
BCC NEXT_FREE
BNE SAVE_BEST
DEY
LDA (HNDL),Y
CMP (HBEST),Y
BCC NEXT_FREE
SAVE_BEST: LDA HNDL
STA HBEST
LDA HNDL+1
STA HBEST+1
NEXT_FREE: LDY #$02 ; FOLLOW LINKED FREE LIST
LDA (MPTR),Y
INY
STA HNDL
LDA (MPTR),Y
STA HNDL+1
AUXZP_ACCESS_OFF
BNE LOOP_FREE ; CONTINUE UNTIL NULL NEXT
AUXZP_ACCESS_ON
LDA HBEST+1
BEQ :+
JMP BEST_FREE
:
.IFDEF SWAPPING
LDA #$FF
LDX MLEN+1
BNE :+
LDA MLEN
: STA SWPMINSIZE
.ENDIF
MAKE_FREE_AVAIL: AUXZP_ACCESS_OFF
JSR HMEM_COALESCE ; ATTEMPT EASY FREE SPACE COMBINE
AUXZP_ACCESS_ON
BCS :+
LDA GCMLEN ; ONLY ATTEMPT SEARCH FREE IF COALESCED
CMP MLEN ; BLOCK IS GREATER OR EQUAL TO REQUESTED SIZE
LDA GCMLEN+1
SBC MLEN+1
BCC MAKE_FREE_AVAIL
JMP SEARCH_FREE
:
.IFDEF SWAPPING
SWAPRETRY: AUXZP_ACCESS_OFF
JSR HMEM_SWAPOUT_UNAXED ; ATTEMPT SWAPPING OUT UNACCESSED BLOCKS
BCC :++
: JSR HMEM_COMPACT ; ATTEMPT FREE SPACE COMPACTION
BCC :-
JSR HMEM_SWAPOUT_UNLOCKED ; ATTEMPT SWAPPING OUT UNLOCKED BLOCKS
: AUXZP_ACCESS_ON
BCS :+
LDA SWPLEN ; ONLY ATTEMPT SEARCH FREE IF COALESCED
CMP MLEN ; BLOCK IS GREATER OR EQUAL TO REQUESTED SIZE
LDA SWPLEN+1
SBC MLEN+1
BCC MAKE_FREE_AVAIL
JMP SEARCH_FREE
: LSR SWPMINSIZE
BNE SWAPRETRY
.ELSE
AUXZP_ACCESS_OFF
JSR HMEM_COMPACT ; ATTEMPT FREE SPACE COMPACTION
AUXZP_ACCESS_ON ; ONLY DO THIS AS A LAST RESORT
BCC MAKE_FREE_AVAIL
.ENDIF
JMP ALLOC_ERR
MATCH_FREE: LDA HNDL ; EXACT FIT - USE IT
LDX HNDL+1
JSR HFREE_UNLINK
LDY #$00
LDA (HNDL),Y
ORA #$01 ; SET ALLOCED FLAG
STA (HNDL),Y
LDY #$02 ; SET INITIAL REFERENCE COUNT
LDA REFCNT
.IFDEF DEBUG_MEMMGR
CMP #$02
BCC :+
AUXZP_ACCESS_OFF
PERR "LARGE REFCNT IN MEMALLOC"
JSR KBWAIT
AUXZP_ACCESS_ON
LDY #$02 ; SET INITIAL REFERENCE COUNT
LDA REFCNT
:
.ENDIF
STA (MPTR),Y
INY
.IFDEF SWAPPING
LDA #$80 ; SET ACCESSED FLAG
.ELSE
LDA #$00
.ENDIF
STA (MPTR),Y
.IFDEF DEBUG_MEMMGR
LDA MLEN ; WRITE FENCE
LDX MLEN+1
CMP MLENBAK
BNE :+
CPX MLENBAK+1
BEQ :++
: AUXZP_ACCESS_OFF
PERR "BAD MLEN"
BRK
: SEC
SBC #$02
BCS :+
DEX
: CLC
ADC MPTR
STA MPTR
TXA
ADC MPTR+1
STA MPTR+1
LDY #$00
LDA #$CA
STA (MPTR),Y
INY
LDA #$FE
STA (MPTR),Y
JSR HFREE_VALIDATE
LDA HNDL ; RETURN HANDLE, NO ERR
LDX HNDL+1
JSR HMEM_VALIDATE
.ENDIF
.IFDEF DEBUG
LDA RAMAVAIL ; UPDATE AVAILABLE RAM
SEC
SBC MLEN
STA RAMAVAIL
LDA RAMAVAIL+1
SBC MLEN+1
STA RAMAVAIL+1
JSR PRNTRAM
.ENDIF
LDA HNDL ; RETURN HANDLE, NO ERR
LDX HNDL+1
AUXZP_ACCESS_OFF
CLC
RTS
BEST_FREE: LDY #$00 ; DEREF FREE HANDLE
LDA (HBEST),Y
INY
STA TMPTR
LDA (HBEST),Y
DEY
STA TMPTR+1
LDA (TMPTR),Y
SEC ; SUB MLEN FROM FREE SIZE
SBC MLEN
STA (TMPTR),Y
INY
LDA (TMPTR),Y
SBC MLEN+1
STA (TMPTR),Y
DEY ; CALC ALLOCED POINTER
CLC
LDA TMPTR
ADC (TMPTR),Y
INY
STA MPTR
LDA TMPTR+1
ADC (TMPTR),Y
DEY ; SET LENGTH IN ALLOCED BLOCK
STA MPTR+1
LDA MLEN
STA (MPTR),Y
INY
LDA MLEN+1
STA (MPTR),Y
INY ; SET REFERENCE COUNT
LDA REFCNT
.IFDEF DEBUG_MEMMGR
CMP #$02
BCC :+
AUXZP_ACCESS_OFF
PERR "LARGE REFCNT IN MEMALLOC"
JSR KBWAIT
AUXZP_ACCESS_ON
LDY #$02 ; SET INITIAL REFERENCE COUNT
LDA REFCNT
:
.ENDIF
STA (MPTR),Y
INY
.IFDEF SWAPPING
LDA #$80 ; SET ACCESSED FLAG
.ELSE
LDA #$00
.ENDIF
STA (MPTR),Y
JSR HMEM_NEW ; GET NEW HANDLE
.IFDEF DEBUG_MEMMGR
BCC :+
JMP ALLOC_ERR
:
.ELSE
BCS ALLOC_ERR
.ENDIF
STA HNDL
STX HNDL+1
LDY #$00 ; UPDATE HANDLE POINTERS
LDA MPTR
ORA #$01 ; SET ALLOCED FLAG
STA (HNDL),Y ; SET POINTER IN HANDLE TABLE
INY
LDA MPTR+1
STA (HNDL),Y
.IFDEF DEBUG_MEMMGR
LDA MLEN ; WRITE FENCE
LDX MLEN+1
CMP MLENBAK
BNE :+
CPX MLENBAK+1
BEQ :++
: AUXZP_ACCESS_OFF
PERR "BAD MLEN"
BRK
: SEC
SBC #$02
BCS :+
DEX
: CLC
ADC MPTR
STA MPTR
TXA
ADC MPTR+1
STA MPTR+1
LDY #$00
LDA #$CA
STA (MPTR),Y
INY
LDA #$FE
STA (MPTR),Y
LDA HNDL
LDX HNDL+1
JSR HMEM_VALIDATE
LDX HNDL+1
.ENDIF
.IFDEF DEBUG
LDA RAMAVAIL ; UPDATE AVAILABLE RAM
SEC
SBC MLEN
STA RAMAVAIL
LDA RAMAVAIL+1
SBC MLEN+1
STA RAMAVAIL+1
JSR PRNTRAM
.ENDIF
LDA HNDL ; RETURN HANDLE, NO ERR
AUXZP_ACCESS_OFF
CLC
RTS
ALLOC_ERR:
.IFDEF DEBUG_MEMMGR
AUXZP_ACCESS_OFF
PERR "CANT ALLOC SIZE:"
AUXZP_ACCESS_ON
LDA MLEN+1
LDX MLEN
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
JSR HMEM_DUMP
BRK
.ENDIF
AUXZP_ACCESS_OFF
LDA #4 ; OUT OF MEMORY
JMP SYSTHROW
;*
;* ALLOC CODE MEMORY
;* ENTRY: AX (LH) = SIZE
;* Y = INITIAL REF COUNT
;* EXIT: AX = HANDLE :: C == 0
;* ERR :: C == 1
;*
HMEM_ALLOC_CODE: CHKAUXLC
JSR HMEM_ALLOC
BCS :+
AUXZP_ACCESS_ON
LDY #$00
LDA (HNDL),Y
ORA #$04 ; SET CODE FLAG IN ALLOC BLOCK FLAGS
STA (HNDL),Y
LDA HNDL
AUXZP_ACCESS_OFF
: RTS
;*
;* ALLOCATE A MEMORY BLOCK AT FIXED ADDRESS
;* ENTRY: X = PAGE ADDRESS
;* A = SIZE IN PAGES
;* Y = INITIAL REF COUNT
;* EXIT: AX = HANDLE :: C == 0
;* ERR :: C == 1
;*
HMEM_ALLOC_FIXED: CHKAUXLC
AUXZP_ACCESS_ON
STY REFCNT
STA MEND+1
TXA
CLC
ADC MEND+1
STA MEND+1 ; MEND = END ADDRESS OF BLOCK
.IFDEF DEBUG_MEMMGR
LDA #$08 ; LEAVE ROOM FOR DEBUG FENCE
STA MEND
.ELSE
LDA #$00
STA MEND
.ENDIF
LDA #$F8 ; SUBTRACT 8 BYTE MIN ALIGNED HEADER
DEX
STA MPTR
STX MPTR+1
DVM_BEGIN
LDZPW MEND
LDZPW MPTR
SUBW
STZPW MLEN
SEARCH_FIXED: LDZPW HFREE
LOOP_FIXED: DUPW
STZPW HNDL
BRZW ALLOC_FIXED_ERR
LDZPW MPTR
LDPW (HNDL),0
DUPW
STZPW TMPTR
BRBW NEXT_FIXED ; SKIP IF REQUESTED RANGE STARTS BELOW FREE
LDZPW TMPTR ; FIND END OF FREE BLOCK
LDPW (TMPTR),0
ADDW
LDZPW MEND
SUBW
DUPW
BRPOSW FOUND_FIXED ; THIS FREE BLOCK ENCOMPASSES REQUESTED RANGE
POPW ; RE-ENABLE INTERRUPTS FOR A MOMENT
NEXT_FIXED: LDPW (TMPTR),2
BRNCH LOOP_FIXED
ALLOC_FIXED_ERR: DVM_END
AUXZP_ACCESS_OFF
.IFDEF DEBUG_MEMMGR
; PERR "ALLOC_FIXED PAGES UNAVAILABLE"
; JSR KBWAIT
.ENDIF
SEC ; RETURN WITH ERR
RTS
FOUND_FIXED: DUPW
BRZW FRONT_FREE_FIXED
END_FREE_FIXED: STPW (MEND),0 ; SET SIZE OF NEW FREE END BLOCK
LDZPW HFREE
STPW (MEND),2 ; ADD TO FREE LIST
DVM_END
JSR HMEM_NEW ; GET NEW HANDLE FOR END FREE BLOCK
BCS ALLOC_FIXED_ERR+1
STA HFREE
STX HFREE+1
.IFDEF DEBUG_MEMMGR
STA HFREEBAK ; SAVE BACKUP
STX HFREEBAK+1
.ENDIF
DVM_BEGIN
LDZPW MEND
DUPW
STPW (HFREE),0
FRONT_FREE_FIXED: POPW
LDZPW MPTR
LDZPW TMPTR
SUBW
DUPW
BRZW FRONT_EQUAL_FIXED ; EQUAL START ADDRESSES
STPW (TMPTR),0
DVM_END
JSR HMEM_NEW ; GET NEW HANDLE FOR ALLOCED BLOCK
BCS ALLOC_FIXED_ERR+1
STA HNDL
STX HNDL+1
DVM_BEGIN
LDZPW MPTR
LD3W
ORW ; SET FIXED AND ALLOCED FLAGS
STPW (HNDL),0 ; SAVE POINTER IN NEW HANDLE
BRNCH SET_ALLOC_FIXED
FRONT_EQUAL_FIXED: POPW
DVM_END
LDA HNDL ; SAME START ADDRESS FOR FREE AND ALLOC BLOCK
LDX HNDL+1 ; RE-USE FREE BLOCK
JSR HFREE_UNLINK ; UNLINK FREE BLOCK
DVM_BEGIN
LDPB (HNDL),0
LD3B
ORB ; SET FIXED AND ALLOCED FLAGS
STPB (HNDL),0
SET_ALLOC_FIXED: LDZPW MLEN
STPW (MPTR),0
LDB REFCNT
ZEXTB
STPW (MPTR),2
DVM_END
.IFDEF DEBUG_MEMMGR
LDA MLEN ; WRITE FENCE
LDX MLEN+1
SEC
SBC #$02
BCS :+
DEX
: CLC
ADC MPTR
STA MPTR
TXA
ADC MPTR+1
STA MPTR+1
LDY #$00
LDA #$CA
STA (MPTR),Y
INY
LDA #$FE
STA (MPTR),Y
LDA HNDL ; RETURN HANDLE, NO ERR
LDX HNDL+1
JSR HMEM_VALIDATE
.ENDIF
.IFDEF DEBUG
LDA RAMAVAIL ; UPDATE AVAILABLE RAM
SEC
SBC MLEN
STA RAMAVAIL
LDA RAMAVAIL+1
SBC MLEN+1
STA RAMAVAIL+1
JSR PRNTRAM
.ENDIF
LDA HNDL ; RETURN HANDLE, NO ERR
LDX HNDL+1
AUXZP_ACCESS_OFF
CLC
RTS
.IFDEF SWAPPING
;*
;* INCREMENTALLY CLEAR ACCESSED FLAG ON ALL IN-USE BLOCKS
;* CALLED FROM THREAD_YEILD
;*
CLRACCHNDL: .ADDR HTBL
HMEM_CLRACCESS: CHKAUXLC
LDA CLRACCHNDL
LDX CLRACCHNDL+1
CLC
ADC #$02
BCC :++
INX
CPX #>HTBL_END
BCC :+
LDA #<HTBL
LDX #>HTBL
: STX CLRACCHNDL+1
: STA CLRACCHNDL
CHKHNDL
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL),Y
AND #$03 ; SKIP FREE, FIXED OR SWAPPED BLOCKS
CMP #$01
BNE :+
.IFDEF DEBUG_MEMMGR
LDA HNDL
JSR HNDL_VALIDATE
LDY #$00
.ENDIF
LDA (HNDL),Y ; CLEAR ACCESSED FLAG
INY
AND #$F8
STA MPTR
LDA (HNDL),Y
STA MPTR+1
LDY #$03
LDA (MPTR),Y
AND #$7F
STA (MPTR),Y
: AUXZP_ACCESS_OFF
RTS
;*
;* SWAP OUT UNLOCKED BLOCKS LARGER THAN SWAPMINSIZE
;*
SWPBESTHNDL: .WORD HTBL
HMEM_SWAPOUT_UNLOCKED:
.IFDEF DEBUG_SWAP
JSR PUTSLN
.ASCIIZ "SWAP OUT UNLOCKED BLOCKS"
.ENDIF
LDA #$00
BEQ SWAPOUT_BEST
;*
;* SWAP OUT UNACCESSED BLOCKS
;*
HMEM_SWAPOUT_UNAXED:
.IFDEF DEBUG_SWAP
JSR PUTSLN
.ASCIIZ "SWAP OUT UNACCESSED BLOCKS"
.ENDIF
LDA #$80
SWAPOUT_BEST: STA SWPAXED
LDA SWPBESTHNDL
LDX SWPBESTHNDL+1
CLC
ADC #$02
BCC :++
INX
CPX #>HTBL_END
BCC :+
LDA #<HTBL
LDX #>HTBL
: STX SWPBESTHNDL+1
: STA SWPBESTHNDL
SWPBESTLP: AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL), Y
AND #$03 ; SKIP FREE, FIXED OR SWAPPED BLOCKS
CMP #$01
BNE SWPBESTNXT
LDA (HNDL),Y
INY
AND #$F8
STA MPTR
LDA (HNDL),Y
STA MPTR+1
LDY #$03 ; CHECK ACCESSED BIT
LDA (MPTR),Y
AND SWPAXED ; TEST MASK FOR UNACCESSED VS UNLOCKED
BMI SWPBESTNXT ; SKIP ACCESSED BLOCKS
LDY #$01
LDA (MPTR),Y ; COMPARE BLOCK SIZE FOR > SWAPMINSIZE
BNE SWPBEST
DEY
LDA (MPTR),Y
CMP SWPMINSIZE
BCS SWPBEST
SWPBESTNXT: LDA HNDL
; LDX HNDL+1 ; NEXT HANDLE
AUXZP_ACCESS_OFF
SWPBESTINC: CLC
ADC #$02
BCC :+
INX
CPX #>HTBL_END
BCC :+
LDA #<HTBL
LDX #>HTBL
: CMP SWPBESTHNDL ; EXIT AFTER LOOPING ONCE
BNE SWPBESTLP
CPX SWPBESTHNDL+1
BNE SWPBESTLP
SEC
RTS
SWPBEST: LDA HNDL
STA SWPBESTHNDL
STX SWPBESTHNDL+1
; JMP HMEM_SWAPOUT ; SWAP BLOCK OUT
;*
;* SWAP OUT MEMORY BLOCK TO FILE
;* ENTRY: AX = HANDLE
;*
HMEM_SWAPOUT: AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
.IFDEF DEBUG_SWAP
AUXZP_ACCESS_OFF
JSR CROUT
JSR PUTS
.ASCIIZ "SWAPPING OUT MEMORY HANDLE: "
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
; JSR CROUT
; JSR KBWAIT
AUXZP_ACCESS_ON
LDA HNDL
LDX HNDL+1
.ENDIF
.IFDEF DEBUG_MEMMGR
LDA HNDL
LDX HNDL+1
JSR HMEM_VALIDATE
LDA HNDL
LDX HNDL+1
.ENDIF
; LDY #$FF
; STY SWAPREF
; LDA HNDL
; LDX HNDL+1
JSR SETSWAPFILE
; AUXZP_ACCESS_OFF
; LDA #<SWAPFILE
; LDX #>SWAPFILE
; JSR FILE_DESTROY ; REMOVE ANY EXISTING FILE
; AUXZP_ACCESS_ON
LDY #$00 ; GET POINTER TO MEMORY BLOCK
LDA (HNDL),Y
INY
PHA
AND #$F8
STA MPTR
LDA (HNDL),Y
STA MPTR+1
; LDY #$03
; LDA (MPTR),Y ; GET REFERENCE COUNTS OF MEMORY BLOCK
; DEY
; TAX
; LDA (MPTR),Y
; JSR FILE_SETAUX ; SET AUX TYPE FOR FILE
.IF 0
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "SWAPOUT AUX REF COUNT: "
AUXZP_ACCESS_ON
LDY #$02
LDA (MPTR),Y ; GET REFERENCE COUNTS OF MEMORY BLOCK
INY
TAX
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
.ENDIF
PLA ; GET FILE TYPE BITS FROM BLOCK BITS
TAY
AUXZP_ACCESS_OFF
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR FILE_CREATE
; BCS SWAPOUTERR
LDA #<SWAPFILE
LDX #>SWAPFILE
LDY #>SWAPFILE_IO_BUFF
JSR FILE_OPEN ; OPEN NEWLY CREATED FILE
; DSS BCS SWAPOUTERR
STY SWAPREF
AUXZP_ACCESS_ON
LDX MPTR+1
TXA
PHA
LDA MPTR
PHA
; ORA #$04
ORA #$02
JSR FILE_SETBUFFER
LDY #$01 ; GET SIZE OF BLOCK
LDA (MPTR),Y
DEY
TAX
LDA (MPTR),Y
STA SWPLEN
STX SWPLEN+1
.IFDEF DEBUG_SWAP
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ " LENGTH: "
AUXZP_ACCESS_ON
LDA SWPLEN+1
LDX SWPLEN
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
; JSR KBWAIT
AUXZP_ACCESS_ON
LDA SWPLEN
LDX SWPLEN+1
.ENDIF
SEC ; SUBTRACT OFF BLOCK HEADER SIZE
.IFDEF DEBUG_MEMMGR
; SBC #$06
SBC #$04
.ELSE
; SBC #$04
SBC #$02
.ENDIF
BCS :+
DEX
: AUXZP_ACCESS_OFF
LDY SWAPREF
JSR FILE_WRITE
BCS SWAPOUTERR
LDY SWAPREF
JSR FILE_CLOSE
BCS SWAPOUTERR
AUXZP_ACCESS_ON
LDY #$00
LDA (HNDL),Y
LDA #$07 ; SET SWAPPED BITS FOR HANDLE
ORA SWPLEN ; STICK BLOCK SIZE IN HANDLE DATA
STA (HNDL),Y
INY
LDA SWPLEN+1 ; CLEVER, HUH?
STA (HNDL),Y
JSR HMEM_NEW ; GET NEW HANDLE TO POINT TO OLD MEMORY
STA HNDL
STX HNDL+1
STA COMPGCHNDL ; FOCUS COMPACTOR HERE
STX COMPGCHNDL+1
LDY #$00 ; MOVE BLOCK POINTER TO NEW HANDLE
PLA
ORA #$01
STA (HNDL),Y
INY
PLA
STA (HNDL),Y
.IFDEF DEBUG
LDY #$02 ; ZERO OUT REF COUNT
LDA #$00
STA (MPTR),Y
INY
STA (MPTR),Y
.ENDIF
.IF 0
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "SWAPOUT FREE HANDLE: $"
AUXZP_ACCESS_ON
LDX HNDL
LDA HNDL+1
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
.ENDIF
LDA HNDL
LDX HNDL+1
AUXZP_ACCESS_OFF
;JMP HMEM_FREE ; NOW FREE THE OLD BLOCK AND NEW HANDLE
BNE HMEM_FREE ; NOW FREE THE OLD BLOCK AND NEW HANDLE
SWAPOUTERR:
AUXZP_ACCESS_OFF
.IFDEF DEBUG_SWAP
PHA
JSR PUTS
.ASCIIZ "ERROR "
PLA
JSR PRBYTE
JSR PUTS
.ASCIIZ " WRITING TO SWAPFILE: "
LDA #<SWAPFILE
LDX #>SWAPFILE
JSR PRSTRLN
.ENDIF
LDY SWAPREF ; ATTEMPT CLEAN-UP
BMI :+
JSR FILE_CLOSE
: LDA #<SWAPFILE
LDX #>SWAPFILE
JSR FILE_DESTROY
SEC ; SET CARRY AND EXIT - NO ERROR
RTS
.ENDIF
;*
;* FREE MEMORY BLOCK
;* ENTRY: AX = HANDLE
;* EXIT: C = 0 :: NO ERROR
;*
HMEM_FREE: CHKAUXLC
CHKHNDL
.IF 0
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "FREE HANDLE: "
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
LDA #'-'
JSR COUT
LDA #'>'
JSR COUT
AUXZP_ACCESS_ON
LDY #$00
LDA (HNDL),Y
INY
AND #$F8
TAX
LDA (HNDL),Y
STA $71
STX $70
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ ": LEN:"
AUXZP_ACCESS_ON
LDY #$00
LDA ($70),Y
INY
TAX
LDA ($70),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " REF:"
AUXZP_ACCESS_ON
LDY #$02
LDA ($70),Y
INY
TAX
LDA ($70),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
; JSR KBWAIT
AUXZP_ACCESS_ON
; LDA HNDL
; LDX HNDL+1
; JSR HMEM_VALIDATE
; JSR HFREE_VALIDATE
LDA HNDL
LDX HNDL+1
AUXZP_ACCESS_OFF
.ENDIF
.IFDEF SWAPPING
JSR HMEM_PTR
LDY #$01
STY GCNEEDED
DEY ; FREE ALLOCED MEMORY BLOCK
AUXZP_ACCESS_ON
LDA (HNDL),Y
AND #$F8
STA (HNDL),Y ; CLEAR ALLOCED FLAGS
INY
.ELSE
LDY #$01
STY GCNEEDED
DEY
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDA (HNDL),Y
AND #$F8
STA (HNDL),Y ; CLEAR ALLOCED FLAG
INY
STA MPTR
LDA (HNDL),Y
STA MPTR+1
.ENDIF
INY
.IFDEF DEBUG
LDA (MPTR),Y
BEQ :+
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "FREE NON_ZERO REF COUNT. HANDLE/ADDRESS: $"
AUXZP_ACCESS_ON
LDA HNDL+1
LDX HNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
LDA #$80|'/'
JSR COUT
LDA #$80|'$'
JSR COUT
AUXZP_ACCESS_ON
LDA MPTR+1
LDX MPTR
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
; JMP THROW_INTERNALERR
AUXZP_ACCESS_ON
:
.ENDIF
LDA HFREE ; ADD TO FREE LIST
STA (MPTR),Y
INY
LDA HFREE+1
STA (MPTR),Y
LDA HNDL
LDX HNDL+1
STA HFREE
STX HFREE+1
.IFDEF DEBUG_MEMMGR
STA HFREEBAK ; SAVE BACKUP
STX HFREEBAK+1
.ENDIF
;.IFDEF DEBUG
.IF 0
LDA MPTR ; ZERO OUT MEMORY BLOCK WHEN DEBUGGING
ORA #$04
STA DSTADDR
LDA MPTR+1
STA DSTADDR+1
LDY #$01 ; SUBTRACT HEADER SIZE FROM BLOCK SIZE
LDA (MPTR),Y
DEY
TAX
LDA (MPTR),Y
SEC
.IFDEF DEBUG_MEMMGR
SBC #$06
.ELSE
SBC #$04
.ENDIF
BCS :+
DEX
: JSR MEMCLR
.ENDIF
.IFDEF DEBUG_MEMMGR
JSR HFREE_VALIDATE
.ENDIF
.IFDEF DEBUG
LDY #$00 ; UPDATE AVAILABLE RAM
LDA (MPTR),Y
INY
CLC
ADC RAMAVAIL
STA RAMAVAIL
LDA (MPTR),Y
ADC RAMAVAIL+1
STA RAMAVAIL+1
JSR PRNTRAM
.ENDIF
AUXZP_ACCESS_OFF
CLC
RTS
;*******************************
;*
;* GARBAGE COLLECTION ROUTINES
;*
;*******************************
;*
;* GARBAGE COLLECT
;* ENTRY: AX = MAX ITERATIONS
;* Y = MIN SWAP SIZE
;* EXIT: CFLAG=1, NOTHING COLLECTED; CFLAG=0, GARBAGE COLLECTED
;*
GCCNT: .WORD $0000
HMEM_GC: ADC #$01
INX
STA GCCNT
STX GCCNT+1
.IFDEF DEBUG_GC
JSR PUTSLN
.ASCIIZ "STARTING GARBAGE COLLECTION:"
JSR HMEM_DUMP
JSR KBWAIT
.ENDIF
LDA GCNEEDED
BNE LOOPGC
INC GCNEEDED
LOOPGC: DEC GCCNT
BNE :+
DEC GCCNT+1
BEQ :++
:
.IFDEF SWAPPING
JSR HMEM_CLRACCESS
.ENDIF
JSR HMEM_GC_INCR
BCC LOOPGC
:
.IFDEF DEBUG_GC
JSR PUTSLN
.ASCIIZ "FINISHED GARBAGE COLLECTION:"
JSR HMEM_DUMP
JSR KBWAIT
.ENDIF
EXITGC: RTS
;*
;* GARBAGE COLLECTION CALLED FROM IDLE LOOP
;*
.IFDEF IDLE_GC
HMEM_GC_IDLE:
.ENDIF
;*
;* GARBAGE COLLECT
;* ENTRY:
;* EXIT: CFLAG=1, NOTHING COLLECTED; CFLAG=0, GARBAGE COLLECTED
;*
HMEM_GC_INCR: CHKAUXLC
SEC
LDA GCNEEDED
BEQ EXITGC
CMP #$02
BEQ :+
JSR HMEM_COALESCE ; ATTEMPT EASY FREE SPACE COMBINE
BCC EXITGC
INC GCNEEDED
: JSR HMEM_COMPACT ; ATTEMPT FREE SPACE COMPACTION
.IFDEF SWAPPING
;*
;* SWAP OUT MEMORY BLOCKS WHEN IDLE
;* START FROM BOTTOM AND MOVE TO TOP. THE THEORY BEING IT WILL SWAP OUT OLDER BLOCKS FIRST.
;*
LDA SWPGCHNDL
LDX SWPGCHNDL+1
CLC
ADC #$02
BCC :++
INX
CPX #>HTBL_END
BCC :+
LDA #<HTBL
LDX #>HTBL
: STX SWPGCHNDL+1
: STA SWPGCHNDL
CHKHNDL
AUXZP_ACCESS_ON
STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL),Y
AND #$03 ; SKIP FREE, FIXED OR SWAPPED BLOCKS
CMP #$01
CLC
BNE EXITSWPGC
.IFDEF DEBUG_MEMMGR
LDA HNDL
JSR HNDL_VALIDATE
LDX HNDL+1
LDY #$00
.ENDIF
LDA (HNDL),Y
INY
AND #$F8
STA MPTR
LDA (HNDL),Y
STA MPTR+1
LDY #$03
LDA (MPTR),Y
BMI EXITSWPGC ; LEAVE ACCESSED BLOCKS ALONE
LDA HNDL
AUXZP_ACCESS_OFF
DEC GCNEEDED
JMP HMEM_SWAPOUT ; SWAP OUT UNACCESSED BLOCK
SWPGCHNDL: .ADDR HTBL
EXITSWPGC: AUXZP_ACCESS_OFF
CLC
.ELSE
BCC EXITGC
LDA #$00 ; AND SWAPPING, SO DON'T DO IT WHEN SWAPPING ENABLED
STA GCNEEDED
.ENDIF
RTS
;*
;* COALESCE ADJACENT FREE BLOCKS
;* ENTRY:
;* EXIT: CFLAG=1, NOTHING COALESCED; CFLAG=0, FREE MEM COALESCED
;*
HMEM_COALESCE:
.IFDEF DEBUG_GC
PERR "HMEM_COALESCING..."
.ENDIF
AUXZP_ACCESS_ON
LDA HFREE ; SEARCH FREE LIST FOR BLOCKS TO COMBINE
STA GCHNDL
LDA HFREE+1
STA GCHNDL+1
BEQ NOTGCED
SEARCHCOALESCE: LDY #$01 ; DEREF HANDLE
LDA (GCHNDL),Y
DEY
STA GCMPTR+1
LDA (GCHNDL),Y
STA GCMPTR
CLC
ADC (GCMPTR),Y
INY
STA GCMEND
LDA GCMPTR+1
ADC (GCMPTR),Y
STA GCMEND+1
LDA HFREE
STA GCTMP
LDA HFREE+1
STA GCTMP+1
LOOPCOALESCE: LDY #$00 ; COMPARE THIS FREE BLOCK ADDRESS
AUXZP_ACCESS_ON
LDA (GCTMP),Y ; WITH END OF FREE BLOCK BEING CHECKED
INY
TAX
LDA (GCTMP),Y
CMP GCMEND+1
BNE NEXTCOAL
CPX GCMEND
BEQ MATCHCOALESCE ; A MATCH, COMBINE BLOCKS
NEXTCOAL: INY
STA GCTMP+1 ; GET POINTER TO FREE BLOCK
STX GCTMP
LDA (GCTMP),Y ; GET NEXT FREE BLOCK HANDLE
INY
TAX
LDA (GCTMP),Y
STX GCTMP
STA GCTMP+1
AUXZP_ACCESS_OFF
BNE LOOPCOALESCE ; KEEP CHECKING
AUXZP_ACCESS_ON
LDA (GCMPTR),Y ; NEXT FREE BLOCK TO COMPARE WITH
BEQ NOTGCED
STA GCHNDL+1
DEY
LDA (GCMPTR),Y
STA GCHNDL
JMP SEARCHCOALESCE
NOTGCED: AUXZP_ACCESS_OFF
SEC
RTS
MATCHCOALESCE:
;.IFDEF DEBUG_GC
.IF 0
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "COMBINING "
AUXZP_ACCESS_ON
LDA GCHNDL+1
LDX GCHNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " AND "
AUXZP_ACCESS_ON
LDA GCTMP+1
LDX GCTMP
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
.ENDIF
LDA GCTMP ; UNLINK FREE BLOCK FROM LIST
LDX GCTMP+1
JSR HFREE_UNLINK
LDY #$00 ; RETURN UNREFERENCED HANDLE BACK TO UNUSED LIST
LDA (GCTMP),Y
PHA ; SAVE MEMORY POINTER FOR LATER
LDA HUNUSED
STA (GCTMP),Y
INY
LDA (GCTMP),Y
PHA
LDA HUNUSED+1
STA (GCTMP),Y
DEY
LDA GCTMP
STA HUNUSED
LDA GCTMP+1
STA HUNUSED+1
PLA ; RECOVER MEMORY POINTER
STA GCTMP+1
PLA
STA GCTMP
LDA (GCMPTR),Y ; ADD SIZE OF NEXT FREE BLOCK TO CURRENT
CLC
ADC (GCTMP),Y
STA (GCMPTR),Y
INY
STA GCMLEN
LDA (GCMPTR),Y
ADC (GCTMP),Y
STA (GCMPTR),Y
STA GCMLEN+1
.IFDEF DEBUG_MEMMGR
JSR HFREE_VALIDATE
.ENDIF
AUXZP_ACCESS_OFF
CLC
RTS
;*
;* COMPACT MEMORY BY MOVING ALLOCED BLOCKS TO TOP OF HEAP
;* ENTRY:
;* EXIT: CFLAG=1, NOTHING COMPACTED; CFLAG=0, MEM COMPACTED
;*
COMPGCHNDL: .WORD $0000
RECOMPACT: LDA HFREE
LDX HFREE+1 ; CHECK FOR ANY FREE BLOCKS
STA COMPGCHNDL
STX COMPGCHNDL+1
BEQ NOTGCED ; C = 1
HMEM_COMPACT:
.IFDEF DEBUG_GC
AUXZP_ACCESS_OFF
PERR "HMEM_COMPACTING..."
.ENDIF
LDA COMPGCHNDL
LDX COMPGCHNDL+1
AUXZP_ACCESS_ON
BEQ RECOMPACT
CHKHNDL
STA GCHNDL
STX GCHNDL+1
LDY #$00 ; DEREF HANDLE
LDA (GCHNDL),Y
LSR
BCS RECOMPACT
ASL
INY
STA GCMPTR ; GCMPTR = ADDRESS OF FREE BLOCK
LDA (GCHNDL),Y
STA GCMPTR+1
LDA #<HTBL
LDX #>HTBL
STA GCTMP
STX GCTMP+1
LOOPCOMPACT: LDY #$00
LDA (GCTMP),Y
TAX
AND #$03
CMP #$01 ; CHECK IF FREE, LOCKED OR SWAPPED
BNE NEXTCOMP ; SKIP IF NOT AVAIL
TXA
AND #$F8 ; MASK OFF FLAGS
TAX
INY
LDA (GCTMP),Y ; COMPARE FOR LOWER ADDRESS THAN FREE BLOCK
CMP GCMPTR+1
BNE :+
CPX GCMPTR
: BCS NEXTCOMP
STA GCMEND+1 ; CALC END ADDRESS OF BLOCK
STX GCMEND ; IF IT MATCHES START OF FREE BLOCK
DEY ; THEN IT CAN BE SHIFTED UP
TXA
CLC
ADC (GCMEND),Y
INY
TAX
LDA GCMEND+1
ADC (GCMEND),Y
CMP GCMPTR+1
BNE :+
CPX GCMPTR
BNE :+
LDA GCTMP ; SAVE NEAREST NEIGHBOR
STA GCNEIGHBOR
LDA GCTMP+1
; STA GCNEIGHBOR+1
; BNE NEXTCOMP
BNE SHIFTNEIGHBOR ; MOVE NEXT-DOOR NEIGHBOR UP
: LDA (GCMPTR),Y ; ELSE COMPARE SIZE OF BLOCK TO FREE BLOCK
CMP (GCMEND),Y ; IT MUST BE EQUAL TO SIZE
BNE NEXTCOMP ; OF FREE BLOCK
DEY
LDA (GCMPTR),Y
CMP (GCMEND),Y
BNE NEXTCOMP
LDA GCTMP
STA GCBEST
LDA GCTMP+1
STA GCBEST+1
BNE XCHNGBEST
;CHECKBESTCOMP: LDA GCBEST+1 ; ONLY REPLACE BEST MATCH IF AT A HIGER ADDRESS
; BEQ :+ ; ASSUMING HIGHER ADDRESSES ARE OLDER AND
; INY ; WILL BE FREED LAST
; LDA GCMEND+1
; CMP (GCBEST),Y
; BCC NEXTCOMP ; CURRENT BEST IS HIGHER
; BNE :+
; DEY
; LDA GCMEND
; CMP (GCBEST),Y
; BCC NEXTCOMP ; CURRENT BEST IS HIGER
;: LDA GCTMP
; STA GCBEST
; LDA GCTMP+1
; STA GCBEST+1
NEXTCOMP: LDA GCTMP ; MOVE TO NEXT HANDLE IN TABLE
AUXZP_ACCESS_OFF
CLC
ADC #$02
AUXZP_ACCESS_ON
STA GCTMP
BCC LOOPCOMPACT
INC GCTMP+1
LDX GCTMP+1
CPX #>HTBL_END
BCC LOOPCOMPACT
EXITCOMPACT: AUXZP_ACCESS_OFF
LDY #$02
LDA (GCMPTR),Y
INY
STA COMPGCHNDL
LDA (GCMPTR),Y
STA COMPGCHNDL+1
SEC
RTS
SHIFTNEIGHBOR: STA GCBEST+1
LDA GCNEIGHBOR
STA GCBEST
.IF 0
AUXZP_ACCESS_OFF
LDA #$80|'<'
JSR COUT
AUXZP_ACCESS_ON
.ENDIF
.IFDEF DEBUG_GC
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "SHIFT NGHBR "
AUXZP_ACCESS_ON
LDA GCNEIGHBOR+1
LDX GCNEIGHBOR
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " OVR "
AUXZP_ACCESS_ON
LDA GCHNDL+1
LDX GCHNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
.ENDIF
.IFDEF DEBUG_MEMMGR
LDA GCNEIGHBOR
LDX GCNEIGHBOR+1
JSR HMEM_VALIDATE
LDY #$01
.ENDIF
LDY #$00 ; SET COPY POINTERS
LDA (GCBEST),Y
AND #$F8
STA SRCADDR
CLC ; ADD SIZE OF FREE BLOCK
ADC (GCMPTR),Y ; FOR DESTINATION
STA DSTADDR
INY
LDA (GCBEST),Y
STA SRCADDR+1
ADC (GCMPTR),Y
STA DSTADDR+1
BNE MOVEBLOCKS
XCHNGBEST:
.IFDEF DEBUG_GC
AUXZP_ACCESS_OFF
JSR PUTS
.ASCIIZ "EXCHANGING BEST "
AUXZP_ACCESS_ON
LDA GCBEST+1
LDX GCBEST
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " WITH "
AUXZP_ACCESS_ON
LDA GCHNDL+1
LDX GCHNDL
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
.ENDIF
.IFDEF DEBUG_MEMMGR
LDA GCBEST
LDX GCBEST+1
JSR HMEM_VALIDATE
.ENDIF
.IF 0
AUXZP_ACCESS_OFF
LDA #$80|'^'
JSR COUT
AUXZP_ACCESS_ON
.ENDIF
LDY #$00 ; SET COPY POINTERS
LDA (GCBEST),Y
AND #$F8
STA SRCADDR
LDA GCMPTR
STA DSTADDR
INY
LDA (GCBEST),Y
STA SRCADDR+1
LDA GCMPTR+1
STA DSTADDR+1
MOVEBLOCKS: LDY #$00 ; SAVE FREE BLOCK INFO
: LDA (GCMPTR),Y
PHA
INY
CPY #$04
BNE :-
LDY #$00 ; UPDATE ALLOC BLOCK POINTER
LDA (GCBEST),Y
AND #$07 ; COPY ALLOC FLAGS
ORA DSTADDR
STA (GCBEST),Y
LDA SRCADDR
STA (GCHNDL),Y ; UPDATE FREE BLOCK POINTER
STA GCMPTR
INY
LDA DSTADDR+1
STA (GCBEST),Y
LDA SRCADDR+1
STA (GCHNDL),Y
STA GCMPTR+1
LDA (SRCADDR),Y ; SIZE OF ALLOCED BLOCK TO MOVE
DEY
TAX
LDA (SRCADDR),Y
JSR MEMCPY ; MOVE ALLOCED BLOCK UP
LDY #$03 ; RESTORE FREE BLOCK INFO
: PLA
STA (GCMPTR),Y
DEY
BPL :-
.IFDEF DEBUG_MEMMGR
LDA GCBEST
LDX GCBEST+1
JSR HMEM_VALIDATE
JSR HFREE_VALIDATE
.ENDIF
AUXZP_ACCESS_OFF
CLC
RTS
.IFDEF DEBUG
;*
;* PRINT AVAIL RAM TO SCREEN
;*
PRNTRAM: LDA RAMAVAIL+1
LSR
LSR
LSR
LSR
CLC
ADC #'0'
CMP #'9'+1
BCC :+
ADC #'A'-'9'-2
: ORA #$80
STA $0424
LDA RAMAVAIL+1
AND #$0F
CLC
ADC #'0'
CMP #'9'+1
BCC :+
ADC #'A'-'9'-2
: ORA #$80
STA $0425
LDA RAMAVAIL
LSR
LSR
LSR
LSR
CLC
ADC #'0'
CMP #'9'+1
BCC :+
ADC #'A'-'9'-2
: ORA #$80
STA $0426
LDA RAMAVAIL
AND #$0F
CLC
ADC #'0'
CMP #'9'+1
BCC :+
ADC #'A'-'9'-2
: ORA #$80
STA $0427
RTS
.ENDIF
;*
;* VALIDATE HANDLE/POINTER
;*
.IFDEF DEBUG_MEMMGR
HNDL_SAVE: .WORD $0000
HMEM_VALIDATE: PHA
TXA
PHA
TYA
PHA
LDA HNDL
STA HNDL_SAVE
LDA HNDL+1
STA HNDL_SAVE+1
LDX #>HTBL
LDA #<HTBL
HTBLVLP: STA HNDL
STX HNDL+1
LDY #$00
LDA (HNDL), Y
AND #$01
BEQ :+
LDA HNDL
JSR HNDL_VALIDATE
: LDA HNDL
LDX HNDL+1
CLC
ADC #$02
BCC :+
INX
: CPX #>HTBL_END
BCC HTBLVLP
LDA HNDL_SAVE
STA HNDL
LDA HNDL_SAVE+1
STA HNDL+1
PLA
TAY
PLA
TAX
PLA
RTS
HNDL_VALIDATE:
STA $70
STX $71
CPX #>HTBL
BCC BADHNDL
CPX #>HTBL_END
BCS BADHNDL
LSR
BCS BADHNDL
LDY #$01
LDA ($70),Y
DEY
TAX
LDA ($70),Y
TAY
AND #$07
CMP #$07
BNE :+
RTS ; HANDLE SWAPPED OUT
: TYA
AND #$F8
CPX #>INIT_START
BCC BADHNDL
BNE :+
CMP #<INIT_START
BCC BADHNDL
: CPX #>TOPOFHEAP
BCS BADHNDL
TYA
LSR
BCC BADHNDL
TYA
AND #$F8
STA $72
STX $73
LDY #$01 ; CHECK FENCE
LDA ($72),Y
DEY
TAX
LDA ($72),Y
AND #$07 ; MAKE SURE NO BITS IN 3 LSBS
BNE BADSIZE
LDA ($72),Y
SEC
SBC #$02
BCS :+
DEX
: CLC
ADC $72
STA $72
TXA
ADC $73
STA $73
LDA #$CA
CMP ($72),Y
BNE BADFENCE
INY
LDA #$FE
CMP ($72),Y
BNE BADFENCE
RTS
BADHNDL: AUXZP_ACCESS_OFF
PERR "INVALID MEMORY HANDLE/POINTER:"
JMP PRNTBADHNDL
BADFENCE: AUXZP_ACCESS_OFF
PERR "CORRUPTED FENCE:"
JMP PRNTBADHNDL
BADSIZE: AUXZP_ACCESS_OFF
PERR "INVALID SIZE:"
PRNTBADHNDL: LDA $71
LDX $70
JSR PRNTAX
LDA #'/'
JSR COUT
AUXZP_ACCESS_ON
LDY #$00
LDA ($70),Y
INY
TAX
LDA ($70),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
JSR CHKDBLALLOC
JSR KBWAIT
JSR HMEM_DUMP
LDA BADHNDLBRK ; STOP RECURSIVE BAD HANDLES
BEQ :+
DEC BADHNDLBRK
JMP THROW_INTERNALERR
: BRK
CHKDBLALLOC: LDX #>HTBL ; CHECK FOR DOUBLY LINKED BLOCKS
LDA #<HTBL
AUXZP_ACCESS_ON
CHKDBLALCLP: STA $74
STX $75
LDY #$00
LDA ($74), Y
LSR
BCC CHKDBLALCNXT ; SKIP FREE BLOCKS
AND #$03
CMP #$03 ;SKIP SWAPPED OUT BLOCKS
BEQ CHKDBLALCNXT
LDA ($74), Y ; CHECK FOR SAME BLOCK ADDRESS
AND #$F8
CMP $72
BNE CHKDBLALCNXT
INY
LDA ($74), Y
CMP $73
BNE CHKDBLALCNXT
LDA $70 ; POINTER MATCH, MAKE SURE NOT SAME HANDLE
CMP $74
BEQ :+
JMP DBLALCERR
: LDA $71
CMP $75
BEQ CHKDBLALCNXT
JMP DBLALCERR
CHKDBLALCNXT: LDA $74
LDX $75
CLC
ADC #$02
BCC :+
INX
: CPX #>HTBL_END
BCC CHKDBLALCLP
RTS
DBLALCERR: LDA $71
LDX $70
AUXZP_ACCESS_OFF
JSR PRNTAX
PERR " DOUBLEY ALLOCATED WITH "
AUXZP_ACCESS_ON
LDA $75
LDX $74
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
JMP PRNTBADHNDL
BADHNDLBRK: .BYTE $01
HFREEBAK: .WORD $0000
HFREE_VALIDATE: LDA HFREE
CMP HFREEBAK
BNE BADFREE
STA $70
LDX HFREE+1
CPX HFREEBAK+1
BNE BADFREE
STX $71
VALFREE: CPX #$00
BEQ VALFREEDONE
CPX #>HTBL ; MAKE SURE HANDLE IS IN THE TABLE RANGE
BCC BADFREE
CPX #>HTBL_END
BCS BADFREE
AND #$01 ; CHECK ALLOCATED BIT (LSB)
BNE BADFREE
LDY #$01
LDA ($70),Y
DEY
TAX
LDA ($70),Y
AND #$F8
CPX #>INIT_START ; CHECK MEMORY POINTER IS IN VALID RANGE
BCC BADFREE
BNE :+
CMP #<INIT_START
BCS :+
JMP BADFREE
: CPX #>HTBL
BCC :+
BEQ :+
JMP BADFREE
CMP #<HTBL
BCC :+
JMP BADFREE
: LDY #$01 ; DEREF NEXT HANDLE IN LIST
LDA ($70),Y
DEY
TAX
LDA ($70),Y
STA $72
STX $73
LDY #$03
LDA ($72),Y
DEY
TAX
LDA ($72),Y
STA $70
STX $71
JMP VALFREE
VALFREEDONE: RTS
BADFREE: AUXZP_ACCESS_OFF
PERR "CORRUPTED FREE LIST @:"
AUXZP_ACCESS_ON
LDA $71
LDX $70
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
JSR HMEM_DUMP
AUXZP_ACCESS_OFF
JMP THROW_INTERNALERR
;*
;* PRINT OUT MEMORY MANAGER DETAILS
;*
.EXPORT HMEM_DUMP
HMEM_DUMP: AUXZP_ACCESS_OFF
JSR CROUT
JSR PUTSLN
.ASCIIZ "MEMORY MANAGER STATE"
JSR PUTSLN
.ASCIIZ "===================="
JSR KBWAIT
JSR PUTSLN
.ASCIIZ "FREE LIST"
JSR PUTSLN
.ASCIIZ "---------"
AUXZP_ACCESS_ON
LDA HFREE
STA HNDL
LDA HFREE+1
STA HNDL+1
FREE_DUMP: LDX HNDL
LDA HNDL+1
BNE :+
JMP FREE_DONE
: AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ "->"
AUXZP_ACCESS_ON
LDY #$00
LDA (HNDL),Y
INY
STA MPTR
TAX
LDA (HNDL),Y
STA MPTR+1
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ ": LEN:"
AUXZP_ACCESS_ON
LDY #$00
LDA (MPTR),Y
INY
TAX
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " NEXT:"
AUXZP_ACCESS_ON
LDY #$02
LDA (MPTR),Y
INY
TAX
STA HNDL
LDA (MPTR),Y
STA HNDL+1
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
AUXZP_ACCESS_ON
JMP FREE_DUMP
FREE_DONE: LDA #<HTBL
STA HNDL
LDA #>HTBL
STA HNDL+1
AUXZP_ACCESS_OFF
JSR PUTSLN
.ASCIIZ "ALLOCATED BLOCKS"
JSR PUTSLN
.ASCIIZ "----------------"
AUXZP_ACCESS_ON
LDA #$00
STA MLEN ; ZERO TOTAL ALLOCATED
STA MLEN+1
ALLOC_DUMP: LDY #$00 ; MAKE UNUSED HANDLE LIST
LDA (HNDL),Y
AND #$01
BNE :+
JMP NEXT_ADUMP ; NOT ALLOCATED
: LDX HNDL
LDA HNDL+1
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ "->"
AUXZP_ACCESS_ON
LDY #$00
LDA (HNDL),Y
AND #$07
CMP #$07
BNE :+
JSR PUTSLN
.ASCIIZ "SWAPPED OUT"
JMP NEXT_ADUMP
: LDA (HNDL),Y
INY
TAX
AND #$F8
STA MPTR
LDA (HNDL),Y
STA MPTR+1
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ ": LEN:"
AUXZP_ACCESS_ON
LDY #$00
LDA (MPTR),Y
INY
TAX
CLC ; ADD TO TOTAL
ADC MLEN
STA MLEN
LDA (MPTR),Y
ADC MLEN+1
STA MLEN+1
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR PUTS
.ASCIIZ " REF:"
AUXZP_ACCESS_ON
LDY #$02
LDA (MPTR),Y
INY
TAX
LDA (MPTR),Y
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
NEXT_ADUMP: AUXZP_ACCESS_ON
LDA HNDL
CLC
ADC #$02
STA HNDL
BEQ :+
JMP ALLOC_DUMP
: INC HNDL+1
LDA HNDL+1
CMP #>HTBL_END
BEQ :+
JMP ALLOC_DUMP
: AUXZP_ACCESS_OFF
JSR CROUT
JSR PUTS
.ASCIIZ "TOTAL ALLOCATED:$"
AUXZP_ACCESS_ON
LDA MLEN+1
LDX MLEN
AUXZP_ACCESS_OFF
JSR PRNTAX
JSR CROUT
RTS
.ENDIF