Files
erkyrath.infocom-zcode-terps/apple/zip/zpaging.asm
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

568 lines
11 KiB
NASM

PAGE
SBTTL "--- TIME-STAMP PAGING ROUTINE ---"
; -------------------------
; FETCH NEXT BYTE OF Z-CODE
; -------------------------
; EXIT: BYTE AT [ZPC] IN [A] & [Y]; FLAGS SET
; EXPANDED TO USE ALL AVAILABLE MEMORY
; ASSUMPTION: PAGING STARTS IN LOW MAIN MEMORY
NEXTPC: LDA ZPCFLG ; IS [ZPCPNT] VALID?
BEQ NPC0 ; NO, GO GET NEW Z-PAGE
;SAME PAGE
LDA ZPNTH ; CHECK ABS ADDR TO SEE IF AUX OR MAIN RAM
BEQ NPC4 ; MAIN
LDA ZPNTM ; SET UP FOR AUX READ
LDY ZPCL ; ABS PAGE AND BYTE OFFSET
JMP NPC2
; Z-PAGE HAS CHANGED!
NPC0: LDA ZPCM ; GET TOP
LDY ZPCH ; 9 BITS OF [ZPC]
CPY ZPURE+HI ; CHECK IF BELOW PAGING
BCC NPC3 ; YES
BEQ NPC1 ; MAYBE, CHECK LOW
BCS NPCPG ; ABOVE, PAGE IT IN
NPC1: CMP ZPURE+LO
BCC NPC3 ; BELOW
NPCPG: LDX #0 ; INVALIDATE MPC FLAG
STX MPCFLG
JSR PAGE ; ABOVE, GET PAGE INTO Y/A
STA ZPNTM ; SAVE POINTER
STY ZPNTH
LDY #$FF ; VALIDATE [ZPCPNT]
STY ZPCFLG
INY ; = 0
STY ZPNTL ; 1ST BYTE ON A NEW PAGE
LDY ZPNTH ; IF CLEAR
BEQ NPC4 ; PAGE IS IN MAIN MEMORY
LDY ZPCL ; GET BYTE WANTED NOW FROM AUX MEM
NPC2: JSR BUFBYT ; GET [Y] BYTE IN BUFFER [A] INTO [A]
JMP NPC5 ; GOT IT
NPC3: CLC ; MAKE PAGE ABSOLUTE
ADC ZCODE ; BY ADDING IT TO START OF GAME SPACE
STA ZPNTM ; SAVE HERE FOR USE
LDX #$FF
STX ZPCFLG ; VALIDATE [ZPCPNT]
INX ; = 0
STX ZPNTL ; CLEAR LSB OF POINTER
STX ZPNTH ; AND MSB, MAIN MEMORY
; JSR ALIGN ; GET ABS ADDR. (Y/A = ZPCH/ZPCM)
; BCS NPC2 ; AUX MEM.
; ELSE DROP THRU TO MAIN MEM RTN
NPC4: LDY ZPCL ; FETCH PAGE INDEX
LDA ZPNTM ; CHECK IF LOW OR HIGH MEMORY
CMP #$C0
BCC NPC7 ; LOW
JSR HIBYT ; HIGH
JMP NPC5
NPC7: LDA (ZPCPNT),Y ; GET Z-BYTE (FROM MAIN MEMORY)
NPC5: INC ZPCL ; END OF PAGE YET?
BNE NPC6 ; NO, EXIT
LDY #0
STY ZPCFLG ; ELSE INVALIDATE [ZPCPNT]
INC ZPCM ; POINT [ZPC] TO
BNE NPC6 ; THE NEXT
INC ZPCH ; Z-PAGE
NPC6: TAY ; SET FLAGS
RTS ; AND RETURN
; -------------------------------
; GET NEXT BYTE OF VIRTUAL MEMORY
; -------------------------------
; EXIT: BYTE AT [MPC] IN [A] & [Y]; FLAGS SET
; (ALL DIFFERENT FOR EXPANDED MEMORY USE - TAKEN FROM EZIP)
GETBYT: LDA MPCFLG ; IS [ZPCPNT] VALID?
BEQ GTBT0 ; NO, GO GET NEW Z-PAGE
LDA MPNTH ; CHECK IF AUX OR MAIN RAM
BEQ GTBT4 ; MAIN
LDA MPNTM ; SET UP FOR AUX READ
LDY MPCL
JMP GTBT2
; Z-PAGE HAS CHANGED!
GTBT0: LDA MPCM ; GET TOP
LDY MPCH ; 9 BITS OF [MPC]
PATCH1: EQU $+1 ; PATCH POINT FOR "VERIFY"
CPY ZPURE+HI ; CHECK IF BELOW PAGING
BCC GTBT3 ; YES
BEQ GTBT1 ; MAYBE, CHECK LOW
BCS GETPG ; ABOVE, PAGE IT IN
PATCH2: EQU $+1 ; PATCH POINT FOR "VERIFY"
GTBT1 CMP ZPURE+LO
BCC GTBT3 ; BELOW
GETPG: LDX #0
STX ZPCFLG
JSR PAGE ; ABOVE, GET PAGE INTO Y/A
STA MPNTM ; SAVE POINTER
STY MPNTH
LDY #$FF ; VALIDATE [MPCPNT]
STY MPCFLG
INY ; = 0
STY MPNTL ; 1ST BYTE ON A NEW PAGE
LDY MPNTH ; IF CLEAR
BEQ GTBT4 ; PAGE IS IN MAIN MEMORY
LDY MPCL ; BYTE WE WANT
GTBT2: JSR BUFBYT ; GET [Y] BYTE IN BUFFER [A] INTO [A]
JMP GTBT5 ; GOT IT
GTBT3: CLC ; MAKE PAGE ABSOLUTE
ADC ZCODE ; BY ADDING IT TO START OF GAME SPACE
STA MPNTM ; SAVE HERE FOR USE
LDX #$FF
STX MPCFLG ; VALIDATE [MPCPNT]
INX ; = 0
STX MPNTL ; CLEAR LSB OF POINTER
STX MPNTH ; MARK AS MAIN MEMORY
; JSR ALIGNM ; GET ABS ADDR. (Y/A = ZPCH/ZPCM)
; BCS GTBT2 ; AUX MEM.
; ELSE DROP THRU TO MAIN MEM RTN
GTBT4: LDY MPCL ; FETCH PAGE INDEX
LDA MPNTM ; CHECK IF LOW OR HIGH MEM
CMP #$C0
BCC GTBT7 ; LOW
JSR HIBYT ; HIGH
JMP GTBT5
GTBT7: LDA (MPCPNT),Y ; GET Z-BYTE (FROM MAIN MEMORY)
GTBT5: INC MPCL ; END OF PAGE YET?
BNE GTBT6 ; NO, EXIT
LDY #0
STY MPCFLG ; ELSE INVALIDATE [MPCPNT]
INC MPCM ; POINT [MPC] TO
BNE GTBT6 ; THE NEXT
INC MPCH ; Z-PAGE
GTBT6: TAY ; SET FLAGS
RTS ; AND RETURN
; ------------------------
; LOCATE A SWAPABLE Z-PAGE
; ------------------------
; ENTRY: TARGET Z-PAGE IN [A/Y] (9 BITS)
; EXIT: ABSOLUTE PAGE IN [A]
; DIFF FOR EXPANDED MEMORY USE
PAGE: STA TARGET+LO ; SAVE THE
STY TARGET+HI ; TARGET Z-PAGE HERE
; IS THIS Z-PAGE ALREADY PAGED IN?
LDA PMAX+LO
STA ZPAGE+LO ; MOVE PMAX IN FOR COUNT
STA PR1+LO
LDA PMAX+HI
STA ZPAGE+HI
STA PR1+HI
LDA PR1+LO ; ADD TO PAGTBL ADDR
; SEC ; PMAX ACTUALLY 1 GREATER THAN MAX
; SBC #2 ; SO COME DOWN TO REAL LAST ENTRY
; BCS PG13
; DEC PR1+HI
PG13: CLC
ADC #LOW PTABL
STA PR1+LO
LDA PR1+HI
ADC #HIGH PTABL
STA PR1+HI ; SO PR1 = TOP OF PGING SPACE
; LDX #HI
LDY #0
PG1: LDA TARGET+LO ; CHECK IF TARGET PAGE
CMP (PR1),Y ; ALREADY IN RESIDENCE
BNE PG2 ; NO
LDA TARGET+HI ; CHECK HIGH BYTE
INY
CMP (PR1),Y
BEQ PG4 ; ALREADY THERE
DEY ; RESET FOR NEXT COMPARE
PG2: LDA PR1+LO ; MOVE DOWN TO NEXT ENTRY
SEC
SBC #2
STA PR1+LO
BCS PG3
DEC PR1+HI
PG3: LDA ZPAGE+LO ; DECREMENT COUNTER
SEC
SBC #2
STA ZPAGE+LO
BEQ PG12
BCS PG1 ; NOT DONE YET
PG12: DEC ZPAGE+HI
BPL PG1 ; KEEP LOOKING
; LDX #0
; STX ZPAGE ; START AT BUFFER #0
;
;PG1: CMP PTABL,X ; LSB MATCHED?
; BNE PG2 ; NO, TRY NEXT BUFFER
; TYA ; ELSE CHECK
; CMP PTABH,X ; MSB
; BEQ PG5 ; MATCHED! BUFFER IN [ZPAGE]
; LDA TARGET+LO ; ELSE RESTORE LSB
;PG2: INC ZPAGE ; UPDATE TALLY
; INX
; CPX PMAX ; OUT OF BUFFERS YET?
; BCC PG1 ; NO, KEEP SEARCHING
; SWAP IN THE TARGET PAGE
JSR EARLY ; GET EARLIEST PAGE
LDA SWAP+LO ; INTO [SWAP]
STA ZPAGE+LO ; SAVE FOR LATER
CLC
ADC #LOW PTABL ; ALIGN AT EARLIEST BUFFER
STA PR1+LO
LDA SWAP+HI
STA ZPAGE+HI
ADC #HIGH PTABL
STA PR1+HI
LDY #LO ; PLACE PAGE IN BUFFER
LDA TARGET+LO
STA (PR1),Y
STA DBLOCK+LO ; AND GIVE IT TO ZDOS
LDY #HI
LDA TARGET+HI
STA (PR1),Y
STA DBLOCK+HI
; LDX SWAP ; INTO [SWAP] & [X]
; STX ZPAGE ; SAVE FOR LATER
;
; LDA TARGET+LO ; ASSIGN THE TARGET PAGE
; STA PTABL,X ; TO THE EARLIEST BUFFER
; STA DBLOCK+LO ; ALSO GIVE IT TO ZDOS
;
; LDA TARGET+HI ; SAME FOR TOP BIT
; AND #%00000011 ; USE ONLY BIT 0 (& 1 - EZIP)
; STA PTABH,X
; STA DBLOCK+HI
JSR GETBUF ; GET BUFFER FROM DISK INTO CORRECT PAGE
BCC PG4 ; OK
JMP DKERR ; OOPS
; UPDATE THE TIMESTAMP
PG4: LDA ZPAGE+LO ; ADD BUFFER INDEX TO LRUMAP
CLC
ADC #LOW LRUMAP
STA PR1+LO
LDA ZPAGE+HI
ADC #HIGH LRUMAP
STA PR1+HI
LDY #LO ; CHECK IF SAME AS
LDA (PR1),Y ; CURRENT STAMP
CMP STAMP+LO
BNE PG5 ; NO, GO GET THIS PG A NEW STAMP
LDY #HI
LDA (PR1),Y
CMP STAMP+HI
BEQ PG11 ; YES, EXIT
PG5: INC STAMP+LO ; UPDATE STAMP
BNE PG10 ; CONTINUE IF NO OVERFLOW
LDA STAMP+HI
BNE PG6 ; HANDLE OVERFLOW
INC STAMP+HI ; SET FOR 2ND 256 STAMPS
JMP PG10 ; (512 IN ALL)
;PG5: LDY ZPAGE ; GET THE BUFFER INDEX
; LDA LRUMAP,Y ; GET THIS BUFFER'S STAMP
; CMP STAMP ; SAME AS CURRENT STAMP?
; BEQ PG8 ; YES, EXIT
;
; INC STAMP ; UPDATE STAMP
; BNE PG7 ; CONTINUE IF NO OVERFLOW
; HANDLE STAMP OVERFLOW
PG6: JSR EARLY2 ; GET EARLIEST STAMP INTO [LRU]
LDA #LOW LRUMAP ; SET PR2 TO LRUMAP SO
STA PR2+LO ; CAN HANDLE WHOLE 1K EASILY
LDA #HIGH LRUMAP
STA PR2+HI
; LDX #HI
PG7: LDY #0 ; LOW BYTE
LDA (PR2),Y
INY ; HIGH BYTE
ORA (PR2),Y
BEQ PG8 ; SKIP IT IF ALREADY ZERO
DEY ; RESET
LDA (PR2),Y ; ELSE SUBTRACT OFF
SEC
SBC LRU+LO ; THE EARLIEST TIMESTAMP
STA (PR2),Y ; AND REPLACE THE STAMP
INY ; HI BYTE
LDA (PR2),Y ; (AND THE HIGH BYTE)
SBC LRU+HI
STA (PR2),Y
DEY ; RESET FOR NEXT ENTRY
PG8: CLC ; INC PR2 TO NEXT ENTRY
LDA PR2+LO
ADC #2
STA PR2+LO
BCC PG9
INC PR2+HI
PG9: LDA PR2+HI ; GET OFFSET TO WHERE WE ARE
SEC
SBC #HIGH LRUMAP
CMP PMAX+HI ; HAVE WE CHECKED ALL THE ENTRIES?
BCC PG7 ; NO, KEEP LOOKING
LDA PR2+LO ; CHECK LOW BYTE
SBC #LOW LRUMAP
CMP PMAX+LO
BCC PG7 ; LESS, KEEP LOOKING
; LDX #0 ; INIT INDEX
;PG9: LDA LRUMAP,X ; GET A STAMP READING
; BEQ PG6 ; EXIT IF ALREADY ZERO
; SEC ; ELSE SUBTRACT OFF
; SBC LRU ; THE EARLIEST TIMESTAMP
; STA LRUMAP,X ; AND REPLACE THE STAMP
;PG6: INX
; CPX PMAX ; END OF SWAPPING SPACE?
; BCC PG9 ; LOOP TILL ALL STAMPS FIXED
LDA LRU+HI ; TURN BACK THE CLOCK
EOR #$FF ; TO REFLECT NEW
STA LRU+HI ; STAMP READING
LDA LRU+LO
EOR #$FF
STA LRU+LO
INC LRU+LO
; LDA #0 ; TURN BACK THE CLOCK
; SEC ; TO REFLECT NEW
; SBC LRU ; STAMP READING
; STA STAMP
PG10: LDY #LO ; STAMP TARGET PAGE
LDA STAMP+LO ; WITH NEW STAMP
STA (PR1),Y ; [PR1] STILL SET AT PROPER LOCATION
LDY #HI
LDA STAMP+HI
STA (PR1),Y
;PG7: LDA STAMP ; FETCH STAMP
; STA LRUMAP,Y ; STAMP TARGET PAGE WITH IT
PG11: LSR ZPAGE+HI ; DIVIDE BY 2
ROR ZPAGE+LO ; WORD ALIGNED
LDA ZPAGE+LO ; GET ABS.PAGE
CLC
ADC PAGE0+LO ; (PAGE # + 1ST PG)
PHA
LDA ZPAGE+HI
ADC PAGE0+HI ; PICK UP CARRY
TAY
PLA
RTS ; Y/A (HI/LO) = PAGE TO USE
;PG8: LDA ZPAGE ; GET ABS. PAGE (EZIP)
; CLC
; ADC PAGE0 ; (PAGE # + 1ST PAGE)
; LDY #1 ; MARK IT AUX MEMORY
; RTS ; AND RETURN IT IN [A] AND [Y]
; *** ERROR #14: DRIVE ACCESS ***
DKERR: LDA #14
JMP ZERROR
; -------------------------
; LOCATE EARLIEST TIMESTAMP
; -------------------------
; EXIT: [LRU] - EARLIEST TIMESTAMP
; [SWAP] = WORD ALIGNED INDEX TO EARLIEST BUFFER
EARLY: LDA #LOW LRUMAP ; SET PR3 & PR2 TO LRUMAP
STA PR3+LO
CLC
ADC #2 ; MOVE PR2 TO NEXT ENTRY
STA PR2+LO
LDA #HIGH LRUMAP
STA PR3+HI
ADC #0 ; PICK UP CARRY IF ANY
STA PR2+HI
LDY #1 ; Y TO HIGH
EAR0: LDA (PR3),Y ; CHECK IF PR2 LOCATION
CMP (PR2),Y ; IS EARLIER THAN PR3
BCC EAR1 ; NO
BNE EAR3 ; GREATER
DEY
LDA (PR3),Y ; EQUAL, CHECK LOW BYTE
CMP (PR2),Y
INY ; RESET FOR NEXT ENTRY
BCC EAR1 ; NO, NOT EARLIER
EAR3: LDA PR2+LO ; YES, PICK UP EARLIER
STA PR3+LO
LDA PR2+HI
STA PR3+HI
EAR1: CLC ; INC PR2 TO NEXT ENTRY
LDA PR2+LO
ADC #2
STA PR2+LO
BCC EAR2
INC PR2+HI
EAR2: LDA PR2+HI ; GET OFFSET TO WHERE WE ARE
SEC
SBC #HIGH LRUMAP
CMP PMAX+HI ; HAVE WE CHECKED ALL THE ENTRIES?
BCC EAR0 ; NO, KEEP LOOKING
LDA PR2+LO ; CHECK LOW BYTE
SBC #LOW LRUMAP
CMP PMAX+LO
BCC EAR0 ; LESS, KEEP LOOKING
LDA PR3+LO ; GET INDEX OF PG TO USE
SEC
SBC #LOW LRUMAP
STA SWAP+LO ; SAVE IT IN SWAP FOR LATER
LDA PR3+HI
SBC #HIGH LRUMAP
STA SWAP+HI
LDA (PR3),Y ; GET LRU # TO USE
STA LRU+HI
DEY
LDA (PR3),Y
STA LRU+LO
RTS
; THIS IS FOR OVERFLOW, IGNORES 0 ENTRIES
EARLY2: LDA #LOW LRUMAP ; SET PR3 & PR2 TO LRUMAP
STA PR3+LO
CLC
ADC #2 ; MOVE PR2 TO NEXT ENTRY
STA PR2+LO
LDA #HIGH LRUMAP
STA PR3+HI
ADC #0 ; PICK UP CARRY IF ANY
STA PR2+HI
EAR20: LDY #0
LDA (PR3),Y ; CHECK IF PR2 LOCATION
INY
ORA (PR3),Y ; IS VALUE 0
BEQ EAR23 ; YES, SO PICK THE OTHER
LDA (PR3),Y
CMP (PR2),Y ; IS EARLIER THAN PR3
BCC EAR21 ; NO
BNE EAR23 ; GREATER
DEY
LDA (PR3),Y ; EQUAL, CHECK LOW BYTE
CMP (PR2),Y
BCC EAR21 ; NO, NOT EARLIER
INY
EAR23: LDA (PR2),Y ; MAKE SURE PR2 ISN'T 0
DEY
ORA (PR2),Y
BEQ EAR21 ; DON'T USE 0 ENTRY
LDA PR2+LO ; PR2 EARLIER, PICK IT UP
STA PR3+LO
LDA PR2+HI
STA PR3+HI
EAR21: CLC ; INC PR2 TO NEXT ENTRY
LDA PR2+LO
ADC #2
STA PR2+LO
BCC EAR22
INC PR2+HI
EAR22: LDA PR2+HI ; GET OFFSET TO WHERE WE ARE
SEC
SBC #HIGH LRUMAP
CMP PMAX+HI ; HAVE WE CHECKED ALL THE ENTRIES?
BCC EAR20 ; NO, KEEP LOOKING
LDA PR2+LO ; CHECK LOW BYTE
SBC #LOW LRUMAP
CMP PMAX+LO
BCC EAR20 ; LESS, KEEP LOOKING
LDA PR3+LO ; GET INDEX OF PG TO USE
SEC
SBC #LOW LRUMAP
STA SWAP+LO ; SAVE IT IN SWAP FOR LATER
LDA PR3+HI
SBC #HIGH LRUMAP
STA SWAP+HI
LDY #1
LDA (PR3),Y ; GET LRU # TO USE
STA LRU+HI
DEY
LDA (PR3),Y
STA LRU+LO
RTS
; -------------------------
; POINT [MPC] TO V-ADDR [I]
; -------------------------
SETWRD: LDA I+LO
STA MPCL
LDA I+HI
STA MPCM
LDA #0
STA MPCH ; ZERO TOP BIT
STA MPCFLG ; INVALIDATE [MPC]
RTS
; ----------------------------
; GET Z-WORD AT [MPC] INTO [I]
; ----------------------------
;GETWRD: JSR GETBYT
; STA I+HI
; JSR GETBYT
; STA I+LO
; RTS
END