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

436 lines
8.7 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
PAGE
STTL "--- Z-STRING HANDLERS ---"
; -----------------------
; POINT TO ZSTRING IN [I]
; -----------------------
SETSTR: LDA I+LO ; WORD-ALIGN THE ADDRESS
ASL A
STA MPCL
LDA I+HI
ROL A
STA MPCM
LDA #0
ROL A
STA MPCH
ASL MPCL ; QUAD-ALIGN ADDRESS!(EZIP)
ROL MPCM
ROL MPCH
JMP VLDMPC
ZSTEX: RTS
; -----------------------
; PRINT Z-STRING AT [MPC]
; -----------------------
PZSTR: LDX #0
STX PSET ; ASSUME PERMANENT CHARSET
STX ZFLAG ; CLEAR BYTE FLAG
DEX ; = $FF
STX TSET ; NO TEMPSET ACTIVE
PZTOP: JSR GETZCH ; GET A Z-CHAR
BCS ZSTEX ; END OF STRING IF CARRY IS SET
STA ZCHAR ; ELSE SAVE CHAR HERE
TAX ; SET FLAGS
BEQ BLANK ; PRINT SPACE IF CHAR = 0
CMP #4 ; IS THIS AN F-WORD?
BCC DOFREQ ; APPARENTLY SO
CMP #6 ; PERHAPS A SHIFT CODE?
BCC NEWSET ; YES, CHANGE CHARSETS
JSR GETSET ; ELSE GET CHARSET
TAX ; SET FLAGS
BNE SET1 ; SKIP IF NOT CHARSET #0
; PRINT A LOWER-CASE CHAR (CHARSET #0)
LDA #$61-6 ; ASCII "a" MINUS Z-OFFSET
TOASC: CLC
ADC ZCHAR ; ADD Z-CHAR INDEX
SHOVE: JSR COUT ; SHOW THE CHAR
JMP PZTOP ; AND GRAB NEXT CHAR
; PRINT AN UPPER-CASE CHAR (CHARSET #1)
SET1: CMP #1 ; MAKE SURE IT'S SET #1
BNE SET2 ; ELSE MUST BE SET #2
LDA #$41-6 ; ASCII "A" MINUS Z-OFFSET
BNE TOASC ; SAME AS SET #0
; PRINT FROM CHARSET #2
SET2: LDA ZCHAR ; RETRIEVE THE Z-CHAR
SEC
SBC #6 ; ZERO-ALIGN IT
BEQ DIRECT ; IF ZERO, IT'S A "DIRECT" ASCII
TAX ; OTHERWISE USE CODE AS AN INDEX
LDA CHRTBL,X ; INTO THE CHARSET TABLE
JMP SHOVE ; AND PRINT THE CHAR
; DECODE A "DIRECT" ASCII CHAR
DIRECT: JSR GETZCH ; FETCH NEXT Z-CHAR
ASL A
ASL A
ASL A
ASL A
ASL A ; SHIFT INTO POSITION
STA ZCHAR ; AND SAVE HERE
JSR GETZCH ; GRAB YET ANOTHER Z-CHAR
ORA ZCHAR ; SUPERIMPOSE THE 2ND BYTE
JMP SHOVE ; AND PRINT THE RESULT
; PRINT A SPACE
BLANK: LDA #SPACE ; ASCII SPACE CHAR
BNE SHOVE
; CHANGE CHARSET
NEWSET: SEC ; CONVERT THE SHIFT CODE
SBC #3 ; TO 1 OR 2
TAY
JSR GETSET ; IS MODE TEMPORARY?
BNE TOPERM ; YES, DO A PERMSHIFT
STY TSET ; ELSE JUST A TEMPSHIFT
JMP PZTOP ; AND CONTINUE
TOPERM: STY PSET ; SET PERM CHARSET
CMP PSET ; SAME AS BEFORE?
BEQ PZTOP ; YES, CONTINUE
LDA #0
STA PSET ; ELSE RESET CHARSET
BEQ PZTOP ; BEFORE LOOPING BACK
; PRINT AN F-WORD
DOFREQ: SEC
SBC #1 ; ZERO-ALIGN THE CODE
ASL A ; AND MULTIPLY TIMES 64
ASL A ; TO OBTAIN THE SEGMENT OFFSET
ASL A ; INTO THE F-WORDS TABLE
ASL A
ASL A
ASL A
STA OFFSET ; SAVE OFFSET FOR LATER
JSR GETZCH ; NOW GET THE F-WORD POINTER
ASL A ; WORD-ALIGN IT
CLC ; AND
ADC OFFSET ; ADD THE SEGMENT OFFSET
TAY ; TO GET THE OFFSET OF THE F-WORD
LDA (FWORDS),Y ; FROM THE START OF THE F-WORDS TABLE
STA I+HI ; SAVE MSB OF F-WORD ADDRESS
INY
LDA (FWORDS),Y ; ALSO SAVE LSB
STA I+LO ; Z-ADDRESS OF F-WORD IS IN [I]
; SAVE THE STATE OF CURRENT Z-STRING
LDA MPCH
PHA
LDA MPCM
PHA
LDA MPCL
PHA
LDA PSET
PHA
LDA ZFLAG
PHA
LDA ZWORD+HI
PHA
LDA ZWORD+LO
PHA
JSR SETFWD ; PRINT THE Z-STRING
JSR PZSTR ; IN [I]
; RESTORE OLD Z-STRING
PLA
STA ZWORD+LO
PLA
STA ZWORD+HI
PLA
STA ZFLAG
PLA
STA PSET
PLA
STA MPCL
PLA
STA MPCM
PLA
STA MPCH
LDX #$FF
STX TSET ; DISABLE TEMP CHARSET
JSR VLDMPC
JMP PZTOP ; CONTINUE INNOCENTLY
; ----------------------
; RETURN CURRENT CHARSET
; ----------------------
GETSET: LDA TSET
BPL GS
LDA PSET
RTS
GS: LDY #$FF
STY TSET
RTS
; -------------------------
; POINT [I] AT FWORD STRING
; -------------------------
SETFWD: LDA I+LO ; WORD-ALIGN THE ADDRESS
ASL A
STA MPCL
LDA I+HI
ROL A
STA MPCM
LDA #0
ROL A
STA MPCH
JMP VLDMPC
; -----------------
; FETCH NEXT Z-CHAR
; -----------------
GETZCH: LDA ZFLAG ; WHICH BYTE IS THIS?
BPL GTZ0 ; $FF = LAST
SEC ; SET CARRY TO INDICATE
RTS ; NO MORE CHARS
GTZ0: BNE GETZ1 ; NOT FIRST CHAR, EITHER
; GET A Z-WORD INTO [ZWORD], RETURN 1ST CHAR IN TRIPLET
INC ZFLAG ; UPDATE CHAR COUNT
JSR GETBYT ; GET TRIPLET AT [MPC]
STA ZWORD+HI ; INTO [ZWORD]
JSR GETBYT
STA ZWORD+LO
LDA ZWORD+HI
LSR A
LSR A ; SHIFT 1ST CHAR INTO PLACE
JMP GTEXIT ; AND RETURN IT
GETZ1: SEC
SBC #1
BNE GETZ2 ; LAST CHAR IN TRIPLET IF ZERO
LDA #2 ; ELSE
STA ZFLAG ; RESET CHAR INDEX
LDA ZWORD+LO ; GET BOTTOM HALF OF TRIPLET
STA I+LO ; MOVE HERE FOR SHIFTING
LDA ZWORD+HI ; GET TOP HALF
ASL I+LO ; SHIFT THE TOP 3 BITS OF LOWER HALF
ROL A ; INTO THE BOTTOM OF THE TOP HALF
ASL I+LO
ROL A
ASL I+LO
ROL A
JMP GTEXIT
GETZ2: LDA #0 ; SET FLAG TO INDICATE
STA ZFLAG ; END OF TRIPLET
LDA ZWORD+HI ; TEST TOP HALF OF TRIPLET
BPL GETZ3 ; CONTINUE IF NOT END OF STRING
LDA #$FF ; ELSE
STA ZFLAG ; INDICATE LAST TRIPLET IN STRING
GETZ3: LDA ZWORD+LO ; GET BOTTOM HALF OF TRIPLET
GTEXIT: AND #%00011111 ; MASK OUT GARBAGE BITS
CLC
RTS
; ---------------------------------
; CONVERT [IN] TO Z-STRING IN [OUT]
; ---------------------------------
CONZST: LDA #$05 ; FILL OUTPUT BUFFER
LDX #$08 ; WITH PAD CHARS ($05)
CZSL: STA OUT,X
DEX
BPL CZSL
LDA #9 ; INIT
STA CONCNT ; CHAR COUNT
LDA #0 ; CLEAR
STA CONIN ; SOURCE AND
STA CONOUT ; OUTPUT INDEXES
CONTOP: LDX CONIN ; FETCH SOURCE INDEX
INC CONIN ; AND UPDATE
LDA IN,X ; GRAB AN ASCII CHAR
STA ZCHAR ; SAVE IT HERE
BNE NEXTZ ; CONTINUE IF CHAR WAS NZ
LDA #5 ; ELSE SHIP OUT
BNE CSHIP ; A PAD CHAR
NEXTZ: LDA ZCHAR
JSR SAYSET ; WHICH CHARSET TO USE?
BEQ CSET0 ; LOWER-CASE IF ZERO
CLC ; ELSE DO A TEMP-SHIFT
ADC #3 ; 4 = CHARSET 1, 5 = CHARSET 2
LDX CONOUT ; FETCH OUTPUT INDEX
STA OUT,X ; SEND THE SHIFT CHAR
INC CONOUT ; UPDATE INDEX
DEC CONCNT ; AND CHAR COUNT
BNE CTEST ; IF OUT OF CHARS
JMP ZCRUSH ; CRUSH 'EM!
CTEST: LDA ZCHAR ; TEST CHAR AGAIN
JSR SAYSET
CMP #2
BEQ CSET2 ; CHARSET #2
; HANDLE CHARSET #1 (UPPER CASE ALPHA)
LDA ZCHAR
SEC
SBC #$41-6 ; CONVERT TO Z-CHAR
BPL CSHIP ; AND SEND TO OUTPUT
; HANDLE CHARSET #0 (LOWER CASE ALPHA)
CSET0: LDA ZCHAR
SEC
SBC #$61-6 ; CONVERT TO Z-CHAR
; SHIP Z-CHAR TO OUTPUT BUFFER
CSHIP: LDX CONOUT ; FETCH OUTPUT INDEX
STA OUT,X
INC CONOUT ; UPDATE INDEX
DEC CONCNT ; DONE 9 CHARS YET?
BNE CONTOP ; NO, LOOP BACK
JMP ZCRUSH ; ELSE CRUSH
; HANDLE CHARSET #2 (MISCELLANEOUS)
CSET2: LDA ZCHAR ; GRAB CHAR
JSR CTABLE ; IS IT IN CHARSET #3 TABLE?
BNE CSHIP ; YES, SEND IT TO OUTPUT
; SEND A "DIRECT" ASCII CHAR
LDA #6 ; ASCII ALERT!
LDX CONOUT
STA OUT,X
INC CONOUT ; UPDATE INDEX
DEC CONCNT ; AND CHAR COUNT
BEQ ZCRUSH ; BUFFER FULL!
; SEND 1ST HALF OF "DIRECT"
LDA ZCHAR
LSR A
LSR A
LSR A
LSR A
LSR A
AND #%00000011 ; MASK GARBAGE
LDX CONOUT
STA OUT,X
INC CONOUT
DEC CONCNT
BEQ ZCRUSH ; BUFFER FULL!
; SEND 2ND HALF OF "DIRECT"
LDA ZCHAR ; GET CHAR YET AGAIN
AND #%00011111 ; MASK JUNK
JMP CSHIP ; AND SHIP IT OUT
; ---------------------
; IS [A] IN CHARSET #3?
; ---------------------
; EXIT: [A] = CHAR CODE IF FOUND, Z-FLAG CLEARED
; Z-FLAG SET IF NOT FOUND
CTABLE: LDX #25
CNL: CMP CHRTBL,X
BEQ CNOK
DEX
BNE CNL
RTS ; Z-FLAG SET IF NO MATCH
CNOK: TXA ; CHAR CODE IS INDEX
CLC
ADC #6 ; PLUS 6
RTS
; -----------------------------
; RETURN CHARSET OF CHAR IN [A]
; -----------------------------
SAYSET: CMP #'a'
BCC SAY1
CMP #'z'+1
BCS SAY1
LDA #0 ; IT'S CHARSET #0
RTS
SAY1: CMP #'A'
BCC SAY2
CMP #'Z'+1
BCS SAY2
LDA #1 ; IT'S CHARSET #1
RTS
SAY2: LDA #2 ; IT'S CHARSET #2
RTS
; ----------------------
; CRUSH Z-CHARS IN [OUT]
; ----------------------
ZCRUSH: LDA OUT+1 ; GET 2ND Z-CHAR
ASL A ; SHIFT BITS INTO POSITION
ASL A
ASL A
ASL A
ROL OUT ; ALONG WITH 1ST Z-CHAR
ASL A
ROL OUT
ORA OUT+2 ; SUPERIMPOSE 3RD Z-CHAR
STA OUT+1
LDA OUT+4 ; GET 5TH Z-CHAR
ASL A ; SHIFT BITS
ASL A
ASL A
ASL A
ROL OUT+3 ; ALONG WITH 4TH Z-CHAR
ASL A
ROL OUT+3
ORA OUT+5 ; SUPERIMPOSE 6TH Z-CHAR
TAX ; SAVE HERE
LDA OUT+3 ; GRAB 4TH Z-CHAR
STA OUT+2 ; MOVE CRUSHED Z-WORD
STX OUT+3 ; INTO PLACE
LDA OUT+7 ; GET 8TH Z-CHAR (EZIP)
ASL A ; SHIFT BITS
ASL A
ASL A
ASL A
ROL OUT+6 ; ALONG WITH 7TH Z-CHAR
ASL A
ROL OUT+6
ORA OUT+8 ; SUPERIMPOSE 9TH Z-CHAR
STA OUT+5 ; SAVE HERE
LDA OUT+6 ; GRAB 7TH Z-CHAR
ORA #%10000000 ; SET HIGH BIT
STA OUT+4 ; MOVE CRUSHED Z-WORD INTO PLACE
RTS
; -----------------------
; CHARSET #2 DECODE TABLE
; -----------------------
CHRTBL: DB 0 ; DUMMY BYTE FOR "DIRECT"
DB $0D ; EOL
DB '0123456789.,!?_#'
DB $27 ; SINGLE QUOTE
DB $22 ; DOUBLE QUOTE
DB '/\-:()'
END