mirror of
https://github.com/erkyrath/infocom-zcode-terps.git
synced 2026-02-18 13:27:25 +00:00
229 lines
7.5 KiB
Plaintext
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
|
|
|