;* ;* 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+1 LDA #HMEM_ALLOC STA LINK_HMEMALLOC+1 LDA #HMEM_ALLOC_FIXED STA LINK_HMEMALLOCFIXED+1 LDA #HMEM_FREE STA LINK_HMEMFREE+1 LDA #HMEM_LOCK STA LINK_HMEMLOCK+1 LDA #HMEM_UNLOCK STA LINK_HMEMUNLOCK+1 LDA #HMEM_REF_INC STA LINK_HMEMREFINC+1 LDA #HMEM_REF_DEC STA LINK_HMEMREFDEC+1 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 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 ADC #$00 STA MPTR+1 STA (HFREE),Y DEY ; SET FREE MEM SIZE 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 JSR FILE_GETINFO BCC :+ JSR PUTS .ASCIIZ "ERROR GETING VOLUME INFO:" LDA #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 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 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 #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 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 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 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 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 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 : 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 : 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 : 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 ; 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 JSR FILE_CREATE ; BCS SWAPOUTERR LDA #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 JSR PRSTRLN .ENDIF LDY SWAPREF ; ATTEMPT CLEAN-UP BMI :+ JSR FILE_CLOSE : LDA #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 : 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 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_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 #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_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 #HTBL BCC :+ BEQ :+ JMP BADFREE CMP #" 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+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