Files
erkyrath.infocom-zcode-terps/ibm/paging.ezp
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

229 lines
7.5 KiB
Plaintext

SUBTTL PAGING ROUTINES
PAGE +
;NORMALIZE ZPC & GET PROPER PAGE
; NEWZPC HAS BE EXTENDED TO UPDATE THE ZPCSEG VARIABLE. IT SETS THIS
; VARIABLE DIFFERENTLY ACCORDING TO PAGING SCHEME. IF THE GAME FITS IN
; MEMORY, ZPCSEG IS SET ACCORDING TO THE 17TH BIT OF THE ZPC, OTHERWISE
; IT IS SET WHEN CURSEG IS SET BY THE GETPAG ROUTINE INDICATING THAT
; THE CURRENT BLOCK IN THE SECOND ES SEGMENT.
;
PUBLIC NEWZPC,NWZ1$,NWZ2$,NWZ3$,NWZ4$,NWZ5$
NEWZPC PROC
MOV LSTNGD,0 ; (A16) RESET NEXT AND GET BYTES
MOV LSTGGD,0
PUSH SI ;SAVES
PUSH BP
PUSH BX
PUSH CX
PUSH DX
SUB AX,AX ;USE DOUBLE-WORD ARITHMETIC
MOV BX,ZPC1 ;GET BLOCK-POINTER
MOV CX,9 ; (A0) NUMBER OF SHIFTS NECESSARY
NWPC: SHL AX,1 ; (A0) SHIFT LEFT BEFORE ADD WITH CARRY
SHL BX,1
ADC AX,0
LOOP NWPC
MOV SI,ZPC2 ;GET BYTE-OFFSET
XCHG SI,AX ;DOUBLE-WORDIFY IT (MIGHT BE NEGATIVE)
CWD
XCHG SI,AX
ADD BX,SI ;ADD IT TO OTHER DOUBLE WORD
ADC AX,DX
MOV DX,BX
AND DX,1FFH ;EXTRACT BYTE-OFFSET
MOV ZPC2,DX ;SAVE IT
MOV CL,9 ;EXTRACT BLOCK-POINTER
SAR BX,CL
AND BX,7FH
CMP AX,0 ; (A0) BLOCK NUMBER > 2**16
JE NWZ1A$ ;WAS 0
MOV CL,7 ; (A0) OR IN BLOCK PTR BITS FROM AX
SHL AX,CL ; (A0) BY SHIFTING THIS OVER 7 X
OR BX,AX ;WAS 1, SET PROPER BIT IN BLOCK-POINTER
SHR AX,CL ; (A0) AND THEN RESTORE AX FOR BELOW
TEST FITS,1 ;(6) DO WE HAVE ALL OF THE GAME IN MEMORY
JZ NWZ1$ ; (6) BECAUSE PAGES ARE NOT CONTINUOUS
MOV ZPCSEG,AL ; (A0) AL HAS SEGMENT NUMBER
JMP NWZ1$
NWZ1A$: TEST FITS,1 ;(6) SHOULD WE SET THIS HERE
JZ NWZ1$ ;(6) NO
MOV ZPCSEG,0 ;(6) SET SEGMENT TO BASE SEG
NWZ1$: MOV ZPC1,BX ;SAVE IT
TEST ZPCFLG,1 ;(7n) DO WE HAVE THE RIGHT BLOCK
JNZ NWZ1Q$ ;(7n) NO, SKIP THIS SKIP
CMP BX,CURBLK ;HAS IT CHANGED?
JE NWZ5$ ;NO
NWZ1Q$: MOV CURBLK,BX ;YES, REMEMBER NEW BLOCK
MOV AX,CURTAB ;IS OLD PAGE IN PAGING SPACE?
CMP AX,0
JE NWZ2$ ;NO
MOV BP,AX ;YES, STORE CURRENT REF TIME FOR OLD PAGE
MOVM [BP],RTIME1,CX ;(A0) RET TBL TO 4 BYTES
MOVM [BP+2],RTIME2,CX ;(A0) EXPANDED BYTE TO WORD
INC AX
NWZ2$: CMP FITS,1 ;(6) IS THE WHOLE GAME THERE
JZ NWZ3$ ;(6) YES, GO DO WHATEVER
CMP BX,ENDLOD ;NEW PAGE ALREADY IN CORE?
JL NWZ3$ ;YES
MOV AX,BX ;NO, GET NEW PAGE
CALL GETPAG
MOV BL,CURSEG ;(6) SET ZPCSEG TO SAME AS CURSEG
MOV ZPCSEG,BL ;(6) SO THAT NXTBYT WORKS
MOV BX,AX
MOV AX,LPTAB ;GET NEW PAGE TABLE POINTER
ADD AX,2 ; (A0) POINT TO REF SLOT
MOV CURTAB,AX ;SAVE THIS POINTER FOR LATER
MOV BP,AX ;STORE HIGHEST RTIME TO KEEP PAGE FOR US
MOV WORD PTR [BP],-1 ;(A0) ADJUSTED TO WORD PTR
MOV WORD PTR [BP+2],-1 ;(A0) ADJUSTED FOR ABOVE WORD PTR
INC AX
JMP NWZ4$
NWZ3$: MOV CL,9 ;CALCULATE PAGE ADDRESS
SHL BX,CL
TEST FITS,1
JNZ NWZ3A$ ; (7z) SKIP DURING WHOLE MEMORY EDITION
MOV ZPCSEG,0 ; (7z) RESET THIS TO SEG0
NWZ3A$: MOV CURTAB,0 ;CLEARING POINTER MEANS PAGE IS PRELOADED
NWZ4$: MOV CURPAG,BX ;UPDATE PAGE POINTER
NWZ5$: MOV ZPCFLG,0 ; (K3) RESET THIS FLAG
POP DX ;RESTORES
POP CX
POP BX
POP BP
POP SI
RET ;AND RETURN
NEWZPC ENDP
;GET THE PAGE WHOSE NUMBER IS IN AX, RETURN A POINTER TO IT IN AX
; GETPAG AND FINDPG WERE MODIFIED TO ACCOMMODATE THE EXTENDED PAGING
; SCHEMES. SEGEND, CURSEG AND PAGTAB ARE SIGNIFICANT VARIABLES IN THESE
; MODIFICATIONS. SEGEND IS USED TO COMPARE TO THE CURRENT LOCATION IN
; PAGTAB WHICH IN TURN INDICATES IN WHICH SEGMENT THE NEW BLOCK IS LOCATED.
; CURSEG IS SET TO TELL THE OUTSIDE WORLD WHICH SEGMENT THE LAST GETPAG
; TOUCHED. NOTE THAT BEING IN THE SECOND SEGMENT (SEG1) REQUIRES THAT
; ADDRESS CALCULATIONS DO NOT ADD IN PAGES (THE VARIABLE MARKING THE END
; OF PRELOAD). THIS REQUIREMENT IS NECESSARY BECAUSE THERE IS NO PRELOAD
; IN THE SECOND SEGMENT.
;
PUBLIC GETPAG,GTP1$,GTP2$,GTP2A$,GTP2B,GTP2C,GTP3$,GTP4$
GETPAG PROC
CMP AX,LPAGE ;IS THIS THE SAME PAGE AS LAST REFERENCED?
JNE GTP1$ ;NO
MOV AX,LPLOC ;YES, WE ALREADY HAVE LOCATION
RET ;RETURN IT
GTP1$: MOV LPAGE,AX ;SAVE NEW PAGE NUMBER
PUSH CX ;SAVES
PUSH BX
ADD RTIME2,1 ;UPDATE REFERENCE TIME (COUNT)
ADC RTIME1,0
MOV BX,OFFSET PAGTAB;PAGE INFORMATION TABLE
GTP2$: ADD BX,2 ; (A0) ADJUSTED FOR WORD SIZED BLKS
CMP AX,[BX-2] ;(A0) SEARCH FOR DESIRED BLOCK
JNE GTP3$ ;NOT IT
CMP AX,CURBLK ;IS THIS THE CURRENT CODE PAGE?
JE GTP2A$ ;DON'T UPDATE REFERENCE TIME
MOVM [BX],RTIME1,CX ; (A0) FOUND IT, UPDATE ITS REFERENCE TIME
MOVM [BX+2],RTIME2,CX ; (A0) ADJUSTED FOR DWORD REF TIME
GTP2A$: SUB BX,2 ;(A0) BACKUP TO BEGINNING OF TABLE ENTRY
PUSH BX ; (6) SAVE THIS BEFORE SCALING IT
SUB BX,OFFSET PAGTAB;(6) BASIFY THE PAGTABLE ENTRY
MOV AX,BX ; (A0) DON'T WASTE THIS MATH
CMP BX,SEGEND ;(6) CHECK IF PAGE IS IN 2ND SEGMENT
POP BX ; (6) RESTORE BX
JL GTP2B ;(6) NO, FUNCTION AS USUAL
MOV CURSEG,1 ; (A0) INIT SEG HUNT
SUB AX,SEGEND ; (A0) FIND SEG FOR THIS PAGE
MOV CL,TBLSHF ; (A0) DIVIDE RESULT BY TABLE WIDTH (2**X)
SHR AX,CL ; (A0) TO GET BUFFER NUMBER
GTP$: CMP AX,128 ; (A0) SCALE DOWN THE BUFFER NUMBER
JB GTP2C ; (A0) IS IT IN THIS SEG
INC CURSEG ; (A0) BUMP THE SEGMENT POINTER
SUB AX,128 ; (A0) AND LOOK AGAIN
JMP GTP$ ; (A0)
GTP2B: MOV CURSEG,0 ;(6) SET SEGMENT NUMBER TO 0
GTP2C: MOV LPTAB,BX ;SAVE IT
SUB BX,OFFSET PAGTAB;CALCULATE ADDRESS OF PAGE
MOV CL,6 ; (A0) REAL BLK # IF IN SEG OTHER THAN 0
CMP CURSEG,0 ; (A0) DO A DIFFERENT CALC FOR SEG0
JZ GTP2D ;
MOV BX,AX ; (A0) GET BLOCK # FOR CURRENT SEGMENT
MOV CL,9 ; (A0) BLK NOT ALREADY MULTIPLIED BY 2
GTP2D: SHL BX,CL
CMP CURSEG,0 ; (A0) SKIP ADDING IN PAGES IF NOT SEG0
JNZ GTP4$
ADD BX,PAGES
JMP GTP4$ ;AND RETURN PAGE POINTER
GTP3$: ADD BX,6 ;SKIP REFERENCE TIME
CMP WORD PTR [BX],-1;END OF TABLE?
JNE GTP2$ ;NO, CONTINUE SEARCH
CALL FINDPG ;YES, FIND A PAGE TO LOAD INTO
PUSH AX ;PAGE POINTER
MOV LPTAB,BX ;SAVE PAGE TABLE POINTER
MOV AX,LPAGE ;SAVE NEW BLOCK NUMBER
MOV [BX],AX ; (A0) MAKE STORAGE WORD SIZED
MOVM [BX+2],RTIME1,CX; (A0) AND CURRENT REF TIME
MOVM [BX+4],RTIME2,CX; (A0) DOUBLE WORDIFY
POP BX ;PAGE POINTER
CALL GETBLK ;GET THE BLOCK
GTP4$: MOV AX,BX ;RETURN PAGE POINTER
MOV LPLOC,AX ;AND SAVE IT FOR LATER
POP BX ;RESTORES
POP CX
RET
GETPAG ENDP
;FIND A GOOD PAGE, RETURN PAGE POINTER IN AX & PAGTAB POINTER IN BX
; SEE COMMENTS UNDER GETPAG
PUBLIC FINDPG,FNP1$,FNP2$,FNP3$,FNP4$
FINDPG PROC
PUSH CX
MOV BX,OFFSET PAGTAB
MOV CX,-1 ;FAKE BEST-CASE REFERENCE COUNT
MOV DX,CX
ADD BX,2 ; (A0) SKIP BLOCK NUMBER FOR NOW
FNP1$: ADD BX,2 ; (A0) IS THIS REF TIME WORSE THAN CUR
CMP [BX-2],CX ; (A0) WORDIFY
JA FNP3$ ;NO
JB FNP2$ ;YES
CMP [BX],DX ;MAYBE, COMPARE LOW-ORDER WORDS, WORSE?
JAE FNP3$ ;NO
FNP2$: MOV CX,[BX-2] ; (A0) YES, SAVE ITS REF COUNT
MOV DX,[BX]
MOV AX,BX ;AND LOCATION (+2)
FNP3$: ADD BX,6 ; (A0) SKIP SECOND WORD
CMP WORD PTR [BX-2],-1 ; (A0) LOOP UNTIL END OF TABLE (WORD LD2)
JNE FNP1$
INC DX ; (LD2)
JNE FNP8$ ; BOTH MUST BE $FF (LD2)
INC CX ;WAS A PAGE REALLY FOUND?
JE FNP4$ ;NO, GROSS BUG!
FNP8$: SUB AX,4 ; (A0) YES, CALCULATE CORE LOCATION OF PAGE
MOV BX,AX
SUB AX,OFFSET PAGTAB
CMP AX,SEGEND ; (6) CHECK SEGMENT
JL FNP5$ ; (6) IN SEG0, SET CURSEG
MOV CURSEG,1 ; (6) SET CURSEG TO SEG1
SUB AX,SEGEND ; (6) SCALE DOWN THE PAGE PTR
MOV CL,TBLSHF ; (A0) DIVIDE BUFFER ADDR BY 8
SHR AX,CL ; (A0) TO DETERMINE ADDR
MOV CL,9 ; (A0) ASSUME A BLOCK # IN AX
FNP4A$: CMP AX,128 ; (A0) FOUND THE SEG?
JB FNP6$ ; (A0) YUP...
SUB AX,128 ; (A0) LOOK FOR NEXT SEG
INC CURSEG ; (A0) INCREMENT SEGMENT NUMBER
JMP FNP4A$ ; (A0) SEARCH ONWARD
FNP5$: MOV CURSEG,0
MOV CL,6 ; (A0) SHIFT COUNT DEC'ED BY ONE (TBL WIDTH)
FNP6$: SHL AX,CL
CMP CURSEG,0 ; (A0) DON'T ADD IN PAGES IF NOT IN SEG0
JNZ FNP7$
ADD AX,PAGES
FNP7$: POP CX ;RESTORES
RET
FNP4$: FATAL FTL6
FINDPG ENDP