mirror of
https://github.com/brouhaha/a2zip.git
synced 2024-12-26 13:31:13 +00:00
Add early reverse-engineering work for Apple II EZIP (Z-Machine architecture v4) interpreters.
This commit is contained in:
parent
d25403a3dd
commit
e25e2b336f
61
Makefile
61
Makefile
@ -2,7 +2,13 @@ all: zip1.lst zip1.bin zip1-check \
|
||||
zip2.lst zip2.bin zip2-check \
|
||||
zip3.lst zip3.bin zip3-check \
|
||||
zip3a.lst zip3a.bin zip3a-check \
|
||||
zip3b.lst zip3b.bin zip3b-check
|
||||
zip3b.lst zip3b.bin zip3b-check \
|
||||
ezip2a.lst ezip2a.bin ezip2a-check \
|
||||
ezip2b.lst ezip2b.bin ezip2b-check \
|
||||
ezip2c.lst ezip2c.bin ezip2c-check \
|
||||
ezip2d.lst ezip2d.bin ezip2d-check \
|
||||
ezip2h.lst ezip2h.bin ezip2h-check
|
||||
|
||||
|
||||
%.p %.lst: %.asm
|
||||
asl $< -o $*.p -L
|
||||
@ -58,8 +64,59 @@ zip3b-check: zip3b.bin
|
||||
echo "98ab866beb68f1d78b978a36106e611fd9196ffe7cd6d2e534c145197be3ebc1 zip3b.bin" | sha256sum -c -
|
||||
|
||||
|
||||
ezip2a.p ezip2a.lst: ezip.asm
|
||||
asl ezip.asm -o ezip2a.p -L -OLIST ezip2a.lst -D iver='$$0201'
|
||||
|
||||
ezip2a.bin: ezip2a.p
|
||||
p2bin -r '$$d000-$$f6ff' ezip2a.p
|
||||
|
||||
ezip2a-check: ezip2a.bin
|
||||
echo "27791a3458d8c37a8db84a07dc74ce38ec902297a42acf578d259485a4b652db ezip2a.bin" | sha256sum -c
|
||||
|
||||
|
||||
ezip2b.p ezip2b.lst: ezip.asm
|
||||
asl ezip.asm -o ezip2b.p -L -OLIST ezip2b.lst -D iver='$$0202'
|
||||
|
||||
ezip2b.bin: ezip2b.p
|
||||
p2bin -r '$$d000-$$f7ff' ezip2b.p
|
||||
|
||||
ezip2b-check: ezip2b.bin
|
||||
echo "86b3cfd5a834f304bdf8094ed56efaab5d75f318291590fdc4594c87c731f701 ezip2b.bin" | sha256sum -c
|
||||
|
||||
|
||||
ezip2c.p ezip2c.lst: ezip.asm
|
||||
asl ezip.asm -o ezip2c.p -L -OLIST ezip2c.lst -D iver='$$0203'
|
||||
|
||||
ezip2c.bin: ezip2c.p
|
||||
p2bin -r '$$d000-$$f7ff' ezip2c.p
|
||||
|
||||
ezip2c-check: ezip2c.bin
|
||||
echo "9fd17f9952a447affc995948ae6356b83f68e828caed50dfaa850826083d5248 ezip2c.bin" | sha256sum -c
|
||||
|
||||
|
||||
ezip2d.p ezip2d.lst: ezip.asm
|
||||
asl ezip.asm -o ezip2d.p -L -OLIST ezip2d.lst -D iver='$$0204'
|
||||
|
||||
ezip2d.bin: ezip2d.p
|
||||
p2bin -r '$$d000-$$f7ff' ezip2d.p
|
||||
|
||||
ezip2d-check: ezip2d.bin
|
||||
echo "2171db824068a23d9291031a20ea81bbbeea7d5af8174e42153adfb282dc99a5 ezip2d.bin" | sha256sum -c
|
||||
|
||||
|
||||
ezip2h.p ezip2h.lst: ezip.asm
|
||||
asl ezip.asm -o ezip2h.p -L -OLIST ezip2h.lst -D iver='$$0208'
|
||||
|
||||
ezip2h.bin: ezip2h.p
|
||||
p2bin -r '$$d000-$$f7ff' ezip2h.p
|
||||
|
||||
ezip2h-check: ezip2h.bin
|
||||
echo "2683ce2f038bce968796540a3a9ce652a9e4120d06a75ee2e80c09cab7c09503 ezip2h.bin" | sha256sum -c
|
||||
|
||||
|
||||
clean:
|
||||
rm -f zip[23].{p,lst,bin}
|
||||
rm -f zip{1,2,3,3a,3b}.{p,lst,bin}
|
||||
rm -f ezip2{a,b,c,d,h}.{p,lst,bin}
|
||||
|
||||
|
||||
.PRECIOUS: %.lst
|
||||
|
77
README.md
77
README.md
@ -1,7 +1,7 @@
|
||||
# a2zip - Infocom ZIP version 1 through 3 interpreters for Apple II, partially reverse-engineered
|
||||
# a2zip - Infocom ZIP interpreters for Apple II, Z-Machine architectures 1 through 4, partially reverse-engineered
|
||||
|
||||
Original code copyright Infocom, Inc.
|
||||
Disassembly including labels and comments copyright 1984 Eric Smith <spacewar@gmail.com>
|
||||
Disassembly including labels and comments copyright 1983-2023 Eric Smith <spacewar@gmail.com>
|
||||
|
||||
z2zip development is hosted at the
|
||||
[a2zip Github repository](https://github.com/brouhaha/a2zip/).
|
||||
@ -10,48 +10,79 @@ z2zip development is hosted at the
|
||||
|
||||
Infocom games are written in ZIL and compiled to Z-code, which is
|
||||
interpreted on a ZIP interpreter. ZIP interpreters were written for
|
||||
many computers, including the Apple II. In 1984 I did reverse-engineered
|
||||
many computers, including the Apple II. In 1983 to 1984 I reverse-engineered
|
||||
a substantial portion of the Apple II version 1 through 3 ZIP interpreters.
|
||||
|
||||
Originally I assembled the code using Microsoft ALDS; the version of the
|
||||
sources for that assembler are in the alds subdirectory.
|
||||
More recently I've partially reverse-engineered a few newer Apple II ZIP and
|
||||
EZIP interpreters.
|
||||
|
||||
The current source code assembles using the Macro Assembler AS:
|
||||
http://john.ccac.rwth-aachen.de:8000/as/
|
||||
## ZIP (Z-Machine architectures v1 through v3)
|
||||
|
||||
ZIP version 1 is only known to have been used for Zork I release 2
|
||||
The Apple II ZIP intepreters for v1, v2, v3, v3 A, and v3B can be built from
|
||||
the source file "zip.asm".
|
||||
|
||||
Z-Machine architectures v1 through v3 have only fairly minor differences. The
|
||||
interpreters for these versions are known as ZIP. The v1 and v2 architectures
|
||||
were only used for early releases of Zork I and Zork II, and were quickly
|
||||
obsolted by v3. which was the most common architecture for Infocom games that
|
||||
did not require more than 128 KiB of virtual machine memory.
|
||||
|
||||
Z-Machine architecture v1 is only known to have been used for Zork I release 2
|
||||
(which might not have been released for the Apple II), and Zork I release 5.
|
||||
Zork I release 5 was provided for the Apple II on a 13-sector disk, while no
|
||||
later releases or other Infocom games were available on 13-sector disks.
|
||||
|
||||
ZIP version 2 is only known to have been used for Zork I release 15
|
||||
Z-Machine architecture v2 is only known to have been used for Zork I release 15
|
||||
and Zork II release 7.
|
||||
|
||||
Later releases of the Zork games, and many other Infocom games, use
|
||||
ZIP version 3. The earliest version 3 interpreter, like the version 1 and
|
||||
version 2 interpreters, did not have any more specific interpreter revision
|
||||
identification. Later version 3 interpreter revisions for the Apple II
|
||||
had a revision letter, with revisions A, B, E, H, K, and M known to exist.
|
||||
Of the lettered revisions, only A and B are currently represented here.
|
||||
The earliest v3 interpreter for the Apple II, like those for v1 and v2, did
|
||||
not have any more specific interpreter revision identification. Later v3
|
||||
interpreter revisions had a revision letter, with revisions A, B, F, H, K,
|
||||
and M known to exist. Of the lettered revisions, only A and B are currently
|
||||
represented here.
|
||||
|
||||
Version 3 revision A added support for the Apple IIe 80-column text mode, with upper
|
||||
Revision A added support for the Apple IIe 80-column text mode, with upper
|
||||
and lower case display, and allowed the user to select a slot number for the
|
||||
printer interface card, which previously was required to be slot 1.
|
||||
|
||||
Version 3 revision B added support for splitting the screen into two windows.
|
||||
Revision B added support for splitting the screen into two windows.
|
||||
|
||||
Changes introduced in later revisions of the version 3 interpreter have not
|
||||
yet been analyzed.
|
||||
Between Revision B and revision F, a substantial rearrangement of the
|
||||
code occurred. These and later changes to the v3 interpreter have not yet
|
||||
been analyzed, and are not currently represented here.
|
||||
|
||||
Eventually game images exceeded the 128KiB limit of ZIP version 3, therefore
|
||||
necessitating new ZIP versions 4, 5, and 6, also known as EZIP, XZIP, and YZIP,
|
||||
respectively. These are not represented here.
|
||||
## EZIP
|
||||
|
||||
Z-Machine architecture v4 doubled the available virtual machine memory size
|
||||
to 256 KiB, allowed a game to have more objects, allowed vocabulary words to
|
||||
have up to nine significant characters, and added some improvements to I/O
|
||||
capabilities. The v4 interpreters are known as EZIP. There were five
|
||||
revisions of the Apple II EZIP interpreter, designated 2A through 2D, and 2H.
|
||||
|
||||
Early work on reverse-engineering these is present in the source file
|
||||
"ezip.asm".
|
||||
|
||||
## XZIP and YZIP
|
||||
|
||||
Eventually Infocom added even more capabilities, resulting in Z-Machine
|
||||
architectures 5 and 6, with interpreters known as XZIP and YZIP.
|
||||
These are not currently represented here.
|
||||
|
||||
## Archive of earliest reverse-engineered source files
|
||||
|
||||
When I originally reverse-engineered the early interpreters in 1983-1984, I
|
||||
assembled the code using Microsoft ALDS, which is not reasily available
|
||||
or easy to use today. The version of the sources for that assembler are in
|
||||
the "alds" subdirectory.
|
||||
|
||||
The current source code assembles using the Macro Assembler AS:
|
||||
http://john.ccac.rwth-aachen.de:8000/as/
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Special thanks to:
|
||||
|
||||
* Richard Turk, for saving the printed listing from the work I did in 1983,
|
||||
* Richard Turk, for saving the printed listing from the work I did in 1983-1984,
|
||||
which was otherwise lost
|
||||
|
||||
* 4am, for preserving disk images of huge amounts of Apple II software,
|
||||
|
54
zip.asm
54
zip.asm
@ -448,9 +448,10 @@ l0917: pha
|
||||
l090a: jsr fatal
|
||||
|
||||
|
||||
; class C instructions (implicit or no operand)
|
||||
; 0OP instructions (no operands, opcodes $80-$bf)
|
||||
|
||||
optab1: fdb oprtnt ; return with TRUE
|
||||
optab_0op:
|
||||
fdb oprtnt ; return with TRUE
|
||||
fdb oprtnf ; return with FALSE
|
||||
fdb oppsi ; print string immediate
|
||||
fdb oppsic ; print string immediate, CRLF, return true
|
||||
@ -474,12 +475,13 @@ optab1: fdb oprtnt ; return with TRUE
|
||||
fdb opcksm ; checksum the program
|
||||
endif
|
||||
|
||||
opmax1 equ (*-optab1)/2
|
||||
opmax_0op equ (*-optab_0op)/2
|
||||
|
||||
|
||||
; class B instructions (single operand)
|
||||
; 1OP instructions (single operand)
|
||||
|
||||
optab2: fdb optstz ; compare ARG1=0 (ARG1<>0)
|
||||
optab_1op:
|
||||
fdb optstz ; compare ARG1=0 (ARG1<>0)
|
||||
fdb opgtsb ; get thing's sibling
|
||||
fdb opgtch ; get thing's child
|
||||
fdb opgtpr ; get thing's parent
|
||||
@ -495,13 +497,13 @@ optab2: fdb optstz ; compare ARG1=0 (ARG1<>0)
|
||||
fdb oppsw ; print string at word address
|
||||
fdb opmove ; move var ARG1 to var
|
||||
fdb opnot ; 1's complement
|
||||
opmax2 equ (*-optab2)/2
|
||||
opmax_1op equ (*-optab_1op)/2
|
||||
|
||||
|
||||
; class A instructions (variable number of operands, may use short form
|
||||
; opcode)
|
||||
; 2OP instructions (two operands, opcodes $00-$7f)
|
||||
|
||||
optab3: fdb opfatl
|
||||
optab_2op:
|
||||
fdb opfatl
|
||||
fdb opmtch ; match ARG1 against ARG2, ARG3, or ARG4
|
||||
fdb l0eb7 ; ??? compare ARG1<=ARG2 (ARG1>ARG2)
|
||||
fdb l0ecf ; ??? compare ARG1>=ARG2 (ARG1<ARG2)
|
||||
@ -529,12 +531,14 @@ optab3: fdb opfatl
|
||||
if iver==iver1
|
||||
fdb oppsbi ; print string at indexed byte address
|
||||
endif
|
||||
opmax3 equ (*-optab3)/2
|
||||
opmax_2op equ (*-optab_2op)/2
|
||||
|
||||
|
||||
; class D instructions (variable number of operands)
|
||||
; EXT instructions (0 to 4 operands) from $e0-$ff
|
||||
; ($c0-$ff dispatch as 2OP)
|
||||
|
||||
optab4: fdb opcall ; call procedure
|
||||
optab_ext:
|
||||
fdb opcall ; call procedure
|
||||
fdb opptwd ; store a word
|
||||
fdb opptby ; store a byte
|
||||
fdb opptp ; store into thing property
|
||||
@ -548,7 +552,7 @@ optab4: fdb opcall ; call procedure
|
||||
fdb x_opsplw ; split widnow
|
||||
fdb x_opsetw ; set window
|
||||
endif
|
||||
opmax4 equ (*-optab4)/2
|
||||
opmax_ext equ (*-optab_ext)/2
|
||||
|
||||
|
||||
mnloop:
|
||||
@ -622,12 +626,12 @@ l09d7: pla ; get operand count back
|
||||
|
||||
jmp l09af ; try for another
|
||||
|
||||
l09ed: dmovi optab4,acc ; assume class D
|
||||
lda opcode ; but if it's $C0-$DF then it's class A
|
||||
l09ed: dmovi optab_ext,acc ; assume EXT $e0-$ff (0-4 operands)
|
||||
lda opcode ; but if it's $C0-$DF then it's the EXT form of a 2OP
|
||||
cmpjl #$e0,l0a98
|
||||
|
||||
sbc #$e0 ; adjust to $00..$1F
|
||||
cmp #opmax4 ; make sure it's not illegal
|
||||
cmp #opmax_ext ; make sure it's not illegal
|
||||
|
||||
if iver<iver3
|
||||
jge opfatl
|
||||
@ -660,10 +664,10 @@ dsptch: jsr dsptch
|
||||
|
||||
endif
|
||||
|
||||
; process opcode group C ($80-$BF)
|
||||
; process 0OP instructions (no operands, opcodes $80-$bf)
|
||||
|
||||
opcgpc: sub ,#$b0 ; adjust to $00..$0F
|
||||
cmp #opmax1 ; make sure it's not illegal
|
||||
cmp #opmax_0op ; make sure it's not illegal
|
||||
|
||||
if iver<iver3
|
||||
jge opfatl
|
||||
@ -672,7 +676,7 @@ opcgpc: sub ,#$b0 ; adjust to $00..$0F
|
||||
endif
|
||||
|
||||
pha ; save it temp.
|
||||
dmovi optab1,acc ; get base address of proper table
|
||||
dmovi optab_0op,acc ; get base address of proper table
|
||||
pla
|
||||
jmp godoit
|
||||
|
||||
@ -681,7 +685,7 @@ l0a2b: jsr fatal ; oops! illegal opcode
|
||||
endif
|
||||
|
||||
|
||||
; process opcode group B ($80-$AF)
|
||||
; process 1OP instructions (single operand, opcodes $80-$AF)
|
||||
|
||||
opcgpb: and #$30 ; mask off operand type bits
|
||||
|
||||
@ -694,7 +698,7 @@ l0a45: mov #$01,argcnt ; one argument
|
||||
|
||||
lda opcode ; adjust opcode to $00..$0F
|
||||
and #$0f
|
||||
cmp #opmax2 ; make sure it's not illegal
|
||||
cmp #opmax_1op ; make sure it's not illegal
|
||||
|
||||
if iver<iver3
|
||||
jge opfatl
|
||||
@ -703,12 +707,12 @@ l0a45: mov #$01,argcnt ; one argument
|
||||
endif
|
||||
|
||||
pha ; save tmep.
|
||||
dmovi optab2,acc ; get appropriate table base addr
|
||||
dmovi optab_1op,acc ; get appropriate table base addr
|
||||
pla
|
||||
jmp godoit ; and go do it!
|
||||
|
||||
|
||||
; process opcode group A ($00-$7F)
|
||||
; process 2OP instructions (two operands, opcodes $00-$7f)
|
||||
|
||||
opcgpa: and #$40 ; get type bit for ARG1
|
||||
jsreq ftprby,l0a73 ; 0: byte immediate
|
||||
@ -725,7 +729,7 @@ l0a8a: dmov acc,arg2 ; save it
|
||||
|
||||
lda opcode ; get opcode back
|
||||
l0a98: and #$1f ; adjust to $00..$1F
|
||||
cmp #opmax3 ; make sure it's not illegal
|
||||
cmp #opmax_2op ; make sure it's not illegal
|
||||
|
||||
if iver<iver3
|
||||
jge opfatl
|
||||
@ -734,7 +738,7 @@ l0a98: and #$1f ; adjust to $00..$1F
|
||||
endif
|
||||
|
||||
pha ; save temp.
|
||||
dmovi optab3,acc ; get base addr of appropriate table
|
||||
dmovi optab_2op,acc ; get base addr of appropriate table
|
||||
pla
|
||||
jmp godoit ; and go do it!
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user