Wizardry re-engineering

3757 views
Skip to first unread message

Didier VALLET

unread,
Mar 26, 2014, 2:00:07 AM3/26/14
to

Hello, i've read a part of Tommy's big work on Wizardry III and i'm interested in looking on the older ones like Wizardry I (also called Sorcellerie in French)

"
Le mardi 10 avril 2012 09:53:17 UTC+2, TommyGoog a écrit :
> Recently I completed a rather interesting project that I'd like to
> share with the Apple][ community. I re-engineered the two main
> executable files, WIZARDRY.CODE and WIZUTIL.CODE, for "Wizardry III,
> Legacy of Llylgamyn" into Pascal code.
"

I saw that there are tools to do it like his Wiz4 or Hyde.
Does anybody know where are tools to work on p-code or can help me to start.
Thanks a lot. Didier

TommyGoog

unread,
Mar 26, 2014, 10:14:45 PM3/26/14
to
On Wednesday, March 26, 2014 1:00:07 AM UTC-5, Didier VALLET wrote:
> Hello, i've read a part of Tommy's big work on Wizardry III and i'm interested in looking on the older ones like Wizardry I (also called Sorcellerie in French)
>
>
>
> I saw that there are tools to do it like his Wiz4 or Hyde.
>
> Does anybody know where are tools to work on p-code or can help me to start.
>
> Thanks a lot. Didier

Hi Didier,

I am still alive. (Last year I suffered a heart attack.)

I have the Wiz4 program that I wrote. It was written in Applesoft Basic. I have it in a ".dsk" image that I used with AppleWin. I also have the source code text of Wiz4 "printed" to a file (".txt").

If you would like the ".dsk" image (or the text file listing), what is the best way to get it (them) to you?

Tommy

TommyGoog

unread,
Mar 29, 2014, 10:27:56 PM3/29/14
to
On Wednesday, March 26, 2014 1:00:07 AM UTC-5, Didier VALLET wrote:
I've replied to an email from Didier and sent him a copy of WIZ4. If anyone else would like a copy of WIZ4 let me know.

I'm now tempted to re-engineer Wizardry I (Proving Grounds). Would anyone besides Didier be interested if I did? I ask this because there didn't seem to be a lot of interest after I re-engineered Wizardry III (see my post 2 years ago: Re-engineered: Wizardry III, Legacy of Llylgamyn).

Tommy



Tommy

Vladimir Ivanov

unread,
Mar 31, 2014, 6:57:25 AM3/31/14
to


On Sat, 29 Mar 2014, TommyGoog wrote:

> I've replied to an email from Didier and sent him a copy of WIZ4. If
> anyone else would like a copy of WIZ4 let me know.

I'd suggest you upload your works and documentation to Asimov.

> I'm now tempted to re-engineer Wizardry I (Proving Grounds). Would
> anyone besides Didier be interested if I did? I ask this because there
> didn't seem to be a lot of interest after I re-engineered Wizardry III
> (see my post 2 years ago: Re-engineered: Wizardry III, Legacy of
> Llylgamyn).

I followed you previous work, which then led me to discovering Hyde's
book. I suppose there are other people like me that don't have interest in
the Wizardry games themselves, but rather in the reverse-engineering
process.

Good luck!

Rob Craig

unread,
Apr 1, 2014, 5:11:33 PM4/1/14
to
Hi Tommy,
Im very interested in you work. Can you send me the things you have discovered. Especially Wizardry 4. A true masterpiece.

I run www.wizardryarchives.com

Cheers,
Rob

sicklittlemonkey

unread,
Apr 1, 2014, 8:14:58 PM4/1/14
to
On Sunday, 30 March 2014 15:27:56 UTC+13, TommyGoog wrote:
> I'm now tempted to re-engineer Wizardry I (Proving Grounds). Would anyone besides Didier be interested if I did? I ask this because there didn't seem to be a lot of interest after I re-engineered Wizardry III (see my post 2 years ago: Re-engineered: Wizardry III, Legacy of Llylgamyn).

<takes off hat>
Wow. You have completed an Epic Hack, Sir. Larger and longer than the games themselves!

Original discussion (which I missed) is here:
https://groups.google.com/d/topic/comp.sys.apple2/2oDJTbQaJWU/discussion

If you did Wizardy I (Proving Grounds) I'd definitely read your report with great interest. I don't know how many people are likely to actually use the source code, but that's not why you did it, is it? ; - ) At least you've overcome the first _decidedly_ non-trivial hurdle should someone else want to port it to another platform. (There are Pascal to JavaScript compilers ...)

Also, serious academic research is being done into gaming history, and some future researcher will likely use what you've done - if it's preserved. I don't know about you, but even being being a footnote in a published paper would make me happy enough.

I'm thinking of places like this:
http://www.icheg.org/research

They have Wizardry in their collection (this is the PC version though):
http://www.thestrong.org/online-collections/nmop/22/52/110.10828

Cheers,
Nick.

Steve Nickolas

unread,
Apr 1, 2014, 11:42:13 PM4/1/14
to
This makes me wonder: if Wizardry is a 48K Pascal program, would it be
possible to modify the 48K Pascal VM it uses to run on top of ProDOS and
use the ProDOS filesystem?

-uso.

TommyGoog

unread,
Apr 2, 2014, 9:14:01 PM4/2/14
to
On Wednesday, March 26, 2014 1:00:07 AM UTC-5, Didier VALLET wrote:
Re-Engineering Wizardry I Proving Grounds. The adventure begins....

In the coming months I (Tommy) will hopefully be re-engineering Wizardry I Proving Grounds. Instead of making the journey alone, I will frequently update this thread with my progress. I encourage anyone with questions to chime in. There will likely be hints and information regarding re-engineering that were not in the thread where I re-engineered Wizardry III (Legacy of Llylgamyn, LOL or LofL).

Review LofL thread.
Get reading materials (Apple Pascal OS 1.1, Apple Pascal Language Ref + Addendum, etc.)
Set up directory (Wizardry1) and files on my WindowsXP pc:
01 EDIT.DSK
SYSTEM.APPLE
SYSTEM.PASCAL
SYSTEM.MISCINFO
SYSTEM.FILER
SYSTEM.EDITOR
SYSTEM.COMPILER
SYSTEM.SWAPDISK
SYSTEM.LIBRARY
02 COMPILE.DSK
SYSTEM.APPLE
SYSTEM.PASCAL
SYSTEM.MISCINFO
SYSTEM.COMPILER
SYSTEM.LINKER
SYSTEM.ASSMBLER
6500.OPCODES
6500.ERRORS
04 APPLE3.1.1.DSK
FORMATTER.CODE
LIBRARY.CODE
05 DECOMPILE.DSK
HELLO
WIZ4
06 WIZ1A.DSK
07 WIZ1B.DSK
08 WIZ1C.DSK
09 WIZ1D.DSK (For 605 ASM code)
10 WIZ1E.DSK (for SYSTEM.STARTUP)
11 MASTER.DSK (DOS Master Disk)
12 PASCAL BLANK.DSK (Init'd using FORMATTER in PASCAL)
13 MAKELIB.DSK (Used when altering SYSTEM.LIBRARY)
14 UnalteredAPPLE1.1.1.DSK
SYSTEM.LIBRARY

Shortcut to my 4-disk enabled AppleWin.exe (Don't even think about using a 2-disk drive system for this.)
pCodeFrenchProvGrndBoot.txt (Using WIZ4)
pCodeProvGrndBoot.txt (Using WIZ4)
Printer.txt (Output from AppleWin.exe execution)
PROVGRNDBOOT.DSK
PROVGRNDSCN.DSK
Shortcut to WinDiff.exe
Wiz1Design.xls (I generally use Excel to record my progress.)

Verified my version of Wizardry 1 from my "box" set of Wizardry I, II, III is same as one at ASIMOV.

From ASIMOV/Sorcellerie:
Ran WIZ4 for Sorcellerie and did a quick eyeball comparison to English version.
Most of code will be identical I think, except for the language differences.

A lot of the code for Wizardry I will be the same as for Wizardry III.

One thought for developing the Wiz1 Pascal code is to first start with Wiz3 and remove the code that is vastly different, then start building up the resulting code.

Copied LofL source code disks to WIZ1A, WIZ1B, WIZ1C, WIZ1D.
Copied SYSTEM.LIBRARY from LofL to EDIT.dsk and COMPILE.dsk.
Modified source code to refer to new volumne name (WIZ1A:, WIZ1B:, WIZ1C:, etc.) on the include statements.

Compiled the code.
Remembered just how tight the space is on the disks. Need to delete WIZARDRY.CODE first, and then make sure output goes to disk with about 200 free blocks.
Made sure that SYSTEM.LIBRARY contained the 6502 code for Wizardry.
Made sure SWAPFILE was present.
Turned on S(WAP option on PASCAL main menu (to edit large files).
Remembered "($S+)" swapping option.

Where to begin?

(We rest after the first hard day of our journey.)

TommyGoog

unread,
Apr 4, 2014, 1:20:16 PM4/4/14
to
....The journey continues....

Let's start by looking at the directory listings for Wizardry I:

WBV2.1:
1 WIZARDRY.CODE
2 RTSTRP.APPLE
3 SYSTEM.PASCAL
4 SYSTEM.LIBRARY
5 SYSTEM.MISCINFO
6 WT
7 SYSTEM.STARTUP


Compare with LOL:

LOLBOOT:
1 WIZARDRY.CODE
2 SYSTEM.CHARSET
3 SYSTEM.STARTUP
4 PICTURE.BITS
5 WIZUTIL.CODE
6 SYSTEM.LIBRARY
7 RTSTRP.APPLE
8 SYSTEM.PASCAL
9 SYSTEM.MISCINFO

Read materials for Apple Pascal OS (EDIT, COMPILE, LINK, SYSTEM.LIBRARY, etc.)
Play with Pascal Editor a bit.
S(et E(nvironment
A(uto indent TRUE
F(illing FALSE
T(oken def FALSE

Note, use AppleWin in APPLE IIe mode for 80 columns.

DeCompiled Wizardry1 (both English and French versions.

I noticed the DeCompiler (Wiz4) generated a few "AN UNKNOWN STANDARD PROCEDURE ?!?!" messages for Wizardry1. This means that Wizardry1 calls an external procedure that I did not encounter in LOL.

I noticed WizUtil from LOL also had 1 "AN UNKNOWN" message. Turns out that one was MEMAVAIL, but I never updated Wiz4.

Note the SEGMENT names in both main programs (WIZARDRY.CODE) are the same:
WIZARDRY
UTILITIE
SHOPS
SPECIALS
COMBAT
CINIT
CUTIL
MELEE
CASTASPE
SWINGASW
CASTLE
ROLLER
CAMP
REWARDS
RUNNER

In LOL, SYSTEM.STARTUP is mostly the "picture" splash screens.
WT is a data file. Perhaps it is the picture bits for Wizardry1.
LOL moved code from Wiz1 SYSTEM.STARTUP to WIZUTIL.CODE, and Wiz1 does not have a WIZUTIL.CODE file.

Let's look at the file SYSTEM.LIBRARY using the LIBMAP utility:

LIBRARY MAP FOR #11:SYSTEM.LIBRARY
$1F Segment #31:
System version = 3.0, code type is P-Code (least sig. 1st)
PASCALIO library unit (LINKED INTRINSIC)
TYPE DECMAX = INTEGER[36];
STUNT = RECORD CASE INTEGER OF
2:(W2:INTEGER[4]);
3:(W3:INTEGER[8]);
4:(W4:INTEGER[12]);
5:(W5:INTEGER[16]);
6:(W6:INTEGER[20]);
7:(W7:INTEGER[24]);
8:(W8:INTEGER[28]);
9:(W9:INTEGER[32]);
10:(W10:INTEGER[36])
END;
PROCEDURE FSEEK(VAR F: FIB; RECNUM: INTEGER);
PROCEDURE FREADREAL(VAR F: FIB; VAR X: REAL);
PROCEDURE FWRITEREAL(VAR F: FIB; X: REAL; W, D: INTEGER);
PROCEDURE FREADDEC(VAR F: FIB; VAR D: STUNT; L: INTEGER);
PROCEDURE FWRITEDEC(VAR F: FIB; D: DECMAX; RLENG: INTEGER);
FUNCTION SUPER_MOD(A,B : INTEGER) : INTEGER;
FUNCTION SUPER_DIV(A,B : INTEGER) : INTEGER;
----------------------------------------------------------------------
$1E Segment #30:
System version = 3.0, code type is 6502
LONGINTI library unit (LINKED INTRINSIC)
TYPE DECMAX = INTEGER[36];
STUNT = RECORD CASE INTEGER OF
2:(W2:INTEGER[4]);
3:(W3:INTEGER[8]);
4:(W4:INTEGER[12]);
5:(W5:INTEGER[16]);
6:(W6:INTEGER[20]);
7:(W7:INTEGER[24]);
8:(W8:INTEGER[28]);
9:(W9:INTEGER[32]);
10:(W10:INTEGER[36])
END;
PROCEDURE FREADDEC(VAR F: FIB; VAR D: STUNT; L: INTEGER);
PROCEDURE FWRITEDEC(VAR F: FIB; D: DECMAX; RLENG: INTEGER);
----------------------------------------------------------------------
$1C Segment #28:
System version = 3.0, code type is P-Code (least sig. 1st)
CHAINSTU library unit (LINKED INTRINSIC)
PROCEDURE SETCHAIN(TYTLE:STRING);
PROCEDURE SETCVAL(VAL:STRING);
PROCEDURE GETCVAL(VAR VAL:STRING);
PROCEDURE SWAPON;
PROCEDURE SWAPOFF;
----------------------------------------------------------------------
$1D Segment #29:
System version = 3.0, code type is P-Code (least sig. 1st)
TRANSCEN library unit (LINKED INTRINSIC)
FUNCTION SIN(X:REAL):REAL;
FUNCTION COS(X:REAL):REAL;
FUNCTION EXP(X:REAL):REAL;
FUNCTION ATAN(X:REAL):REAL;
FUNCTION LN(X:REAL):REAL;
FUNCTION LOG(X:REAL):REAL;
FUNCTION SQRT(X:REAL):REAL;
----------------------------------------------------------------------
$14 Segment #20:
System version = II.1, code type is 6502
TURTLEGR library unit (LINKED INTRINSIC)
TYPE
SCREENCOLOR=(none,white,black,reverse,radar,
black1,green,violet,white1,black2,orange,blue,white2);
PROCEDURE INITTURTLE;
PROCEDURE TURN(ANGLE: INTEGER);
PROCEDURE TURNTO(ANGLE: INTEGER);
PROCEDURE MOVE(DIST: INTEGER);
PROCEDURE MOVETO(X,Y: INTEGER);
PROCEDURE PENCOLOR(PENMODE: SCREENCOLOR);
PROCEDURE TEXTMODE;
PROCEDURE GRAFMODE;
PROCEDURE FILLSCREEN(FILLCOLOR: SCREENCOLOR);
PROCEDURE VIEWPORT(LEFT,RIGHT,BOTTOM,TOP: INTEGER);
FUNCTION TURTLEX: INTEGER;
FUNCTION TURTLEY: INTEGER;
FUNCTION TURTLEANG: INTEGER;
FUNCTION SCREENBIT(X,Y: INTEGER): BOOLEAN;
PROCEDURE DRAWBLOCK(VAR SOURCE; ROWSIZE,XSKIP,YSKIP,WIDTH,HEIGHT,
XSCREEN,YSCREEN,MODE: INTEGER);
PROCEDURE WCHAR(CH: CHAR);
PROCEDURE WSTRING(S: STRING);
PROCEDURE CHARTYPE(MODE: INTEGER);
----------------------------------------------------------------------
$15 Segment #21:
System version = II.1, code type is P-Code (least sig. 1st)
TURTLEGR data segment
----------------------------------------------------------------------
$16 Segment #22:
System version = 3.0, code type is 6502
APPLESTU library unit (LINKED INTRINSIC)
FUNCTION PADDLE(SELECT: INTEGER): INTEGER;
FUNCTION BUTTON(SELECT: INTEGER): BOOLEAN;
PROCEDURE TTLOUT(SELECT: INTEGER; DATA: BOOLEAN);
FUNCTION KEYPRESS: BOOLEAN;
FUNCTION RANDOM: INTEGER;
PROCEDURE RANDOMIZE;
PROCEDURE NOTE(PITCH,DURATION: INTEGER);
----------------------------------------------------------------------


The first program executed on a "turnkey" Pascal system is SYSTEM.STARTUP. I will start by DeCompiling SYSTEM.STARTUP and then later turn my attention to WIZARDRY.CODE.

SYSTEM.STARTUP

SEGMENT: Procedures:
0 WIZBOOT 5
1 UTILS 36
2 TITLELOA 8
3 OPTIONS 1

WIZBOOT lex Start Exit Order Hierarchy
1 0 50CC 50FF 2 7.0.1
2 6502 code 511A 52EA 3
3 6502 code 52F0 54B6 4
4 1 5000 50BA 1 7.0.4
5 6502 code 54BC 5642 5

Every Pascal procedure on a diskette can be identified by a series of 3 numbers (File, Segment, Procedure). This is the information that Wiz4 solicits and is the way that I first name the procedures in the code when I am creating the Pascal code. For example, SYSTEM.STARTUP is file 7 on the disk. Segment 0 is the first segment, and procedure 1 is the main line. I might refer to this as P070001. (File 07, Segment 00, Procedure 01).

Here is the output from Wiz4 (DeCompiler) for P070001 (SYSTEM.STARTUP, SEGMENT 0, Procedure 01):

FILE: 7 SEG: 0 PROC: 1

JTAB FOR SUBROUTINE 1:
DATA SIZE: 12
PARAM SIZE: 4
EXIT AT: 50FF
ENTER AT: 50CC
PROC NUMBER: 1
LEXICAL LEVEL: 0
50CC B9 36 UJP. JUMP TO 5104
50CE CD 1C 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 1C
50D1 CE 04 CLP. CALL CHILD PROCEDURE: 04
50D3 CD 08 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 08
50D6 CD 09 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 09
50D9 EA SLDO. PUSH BASE.03
50DA B9 12 UJP. JUMP TO 50EE
50DC CE 04 CLP. CALL CHILD PROCEDURE: 04
50DE 01 SLDC. PUSH #0001
50DF 01 SLDC. PUSH #0001
50E0 9E 04 EXIT. EXIT FROM PROCEDURE. (TOS)=PROC# (TOS-1)=SEG#
50E2 B9 18 UJP. JUMP TO 50FC
50E4 CD 07 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 07
50E7 B9 13 UJP. JUMP TO 50FC
50E9 CD 08 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 08
50EC B9 0E UJP. JUMP TO 50FC
50EE AC (00)53 00 55 00 B9 06 TABLE: 1A 00 0F 00 16 00
XJP. W1,W2,W3,<TABLE>
50FC 00 SLDC. PUSH #0000
50FD A1 F6 UJP. IF NOT (TOS) THEN JUMP TO 50D6
50FF 1C SLDC. PUSH #001C
5100 9E 16 DUSE. DEC USE CNT FOR SEG #(TOS)
5102 B9 05 UJP. JUMP TO 5109
5104 1C SLDC. PUSH #001C
5105 9E 15 RSEG. READ SEGMENT #(TOS) FROM ACTIVE SEG TABLE
5107 B9 F4 UJP. JUMP TO 50CE
5109 C1 00 RBP. RETURN FROM BASE PROCEDURE.
510B 00 SLDC. PUSH #0000
510C 3E SLDC. PUSH #003E
510D 00 SLDC. PUSH #0000
510E 38 SLDC. PUSH #0038
510F 00 SLDC. PUSH #0000

What is the following? What is #001C? And Procedure 01?
50CC B9 36 UJP. JUMP TO 5104
50CE CD 1C 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 1C

5104 1C SLDC. PUSH #001C
5105 9E 15 RSEG. READ SEGMENT #(TOS) FROM ACTIVE SEG TABLE

Ok, LOL has the same construct. Oh yeah! INTRINSICS.

See Apple Pascal Language, p. 78, "The Initialization Part of a UNIT":
"The resulting code runs automatically when the host program is executed, before the program is run."

In Language Reference Addendum is a discussion about SEGMENT NUMBERS and their assignment:
"The segment number of an Intrinsic UNIT segment....can be found by examining the segment dictionary of the SYSTEM.LIBRARY file with the LIBMAP utility program."

Looking back a the LIBMAP output earlier in this post we see the following:

Segment #28:
System version = 3.0, code type is P-Code (least sig. 1st)
CHAINSTU library unit (LINKED INTRINSIC)
PROCEDURE SETCHAIN(TYTLE:STRING);

Cool! Another mystery solved! (28 = $1C). WIZBOOT therefore uses CHAINSTU (and the procedure SETCHAIN).

Lets look at more p-code:

50D3 CD 08 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 08
50D6 CD 09 01 CXP. CALL EXTERNAL PROCEDURE: 01 IN SEGMENT: 09

Segment 8? Segment 9? I'm lost. There are only 4 segments in SYSTEM.STARTUP.

Time to learn more about Segments....

Apple Pascal Language, p 76-77 has a discussion about File segment numbers compared to the Execution segment numbers.
0 System
1 Program's mainline
2-6 System
7 First declared SEGMENT from program
8 Second declared SEGMENT from program
... Up to 16 (?) of these.

Ok, now we are getting somewhere.
7 = UTILS
8 = TITLELOA
9 = OPTIONS

Hmmm, I see there is 6502 code in SYSTEM.STARTUP. How do we get that code so we can examine it and "de-compile" (disassemble) it into our re-engineered code?

Did I mention this was going to be a long journey?

TommyGoog

unread,
Apr 7, 2014, 3:28:10 PM4/7/14
to
On Friday, April 4, 2014 12:20:16 PM UTC-5, TommyGoog wrote:
> ....The journey continues....

>
> Hmmm, I see there is 6502 code in SYSTEM.STARTUP. How do we get that code so we can examine it and "de-compile" (disassemble) it into our re-engineered code?
>
>
>
> Did I mention this was going to be a long journey?

I use the DeCompiler (Wiz4) to get the procedures that were written in assembly language by the authors of Wizardry. There are other ways to get the code, but this works for me!

----------

PROCESS ALL? N
FILES: 7

1 WIZARDRY.CODE
2 RTSTRP.APPLE
3 SYSTEM.PASCAL
4 SYSTEM.LIBRARY
5 SYSTEM.MISCINFO
6 WT
7 SYSTEM.STARTUP

TYPE A FILE NUMBER (OR -1) 7

SEGMENT T/S = 32/2 --- PASCAL T/S
SEGMENT T/S = 32/13 --- DOS 3.3 T/S

0 WIZBOOT
1 UTILS
2 TITLELOA
3 OPTIONS

TYPE A SEGMENT NUMBER (OR -1)

T/S FOR SEGMENT 34/8 --- PASCAL
T/S FOR SEGMENT 34/7 --- DOS

SEGMENT'S START ADDR($5000):

THERE ARE 5 PROCEDURES.


ENTER PROCEDURE # (OR -1) 2


JTAB FOR SUBROUTINE 2:
DATA SIZE: 72
PARAM SIZE: 8
EXIT AT: 52EA
ENTER AT: 511A
PROC NUMBER: 0
6502 CODE

ENTER PROCEDURE # (OR -1) -1

SEGMENT T/S = 32/2 --- PASCAL T/S
SEGMENT T/S = 32/13 --- DOS 3.3 T/S

0 WIZBOOT
1 UTILS
2 TITLELOA
3 OPTIONS

TYPE A SEGMENT NUMBER (OR -1) -1



TYPE A FILE NUMBER (OR -1) -1


]CALL-151

*511AL

511A- 68 PLA
511B- AA TAX
511C- 68 PLA
511D- A8 TAY
511E- 68 PLA
511F- 85 00 STA $00
5121- 68 PLA
5122- 85 01 STA $01
5124- 68 PLA
5125- 85 02 STA $02
5127- 68 PLA
5128- 85 03 STA $03
512A- 98 TYA
512B- 48 PHA
512C- 8A TXA
512D- 48 PHA
512E- 18 CLC
512F- A5 02 LDA $02
5131- 65 00 ADC $00
5133- 85 02 STA $02
*

----------

The DeCompiler always loads the segment at $5000 (even if you specify a different address). The values in the JTAB displayed for a procedure tells you where that procedure was loaded into memory. Then I simply use the Apple's disassembler to display the information. Since my HELLO program turned on the printer, the text can be found in PRINTER.TXT on my pc thanks to AppleWin.

I compared the code from Wiz1 to my previous 6502 code in LOL. Those routines were:
P050002 COPYPROT
P010024 PRPICCH
P010025 DRAWSCR
P010026 DRAWLINE
P010027 RANDOM
P010028 CHKKEYBD
P010030 SCRNDATA

The code at P070002 ($511A) looks much different from the code in LOL.
The code at P070003 ($52F0) looks like disk handling and might be like COPYPROT.
The code at P070005 ($54BC) is similar to a screen table in LOL at L11E2 in SCRNDATA.

Before working on WIZBOOT (SYSTEM.STARTUP, SEGMENT 0), lets take a peek at Segment UTILS.

I noticed the UTILS segment for Wizardry1 has 36 procedures. Using output from the DeCompiler, I made the following table:

ProvGrnds LofL
7.1.1 5.1.1 UTILS main No "Update" in LOL
7.1.2 5.1.2 GETREC identical
7.1.3 5.1.3 PUTREC identical
7.1.4 5.1.4 GETKEY some variable diffs
7.1.5 5.1.5 FINDFILE identical
7.1.6 5.1.6 GETCR identical
7.1.7 5.1.7 EXITUTIL SYSTEM.PASCAL vs SYSTEM.CHARSET
7.1.8 5.1.8 RDSCNTC2 identical
7.1.9 5.1.9 RDSCNTOC identical
7.1.A 5.1.A GETPASS identical
7.1.B 5.1.B RDCHARAC identical
7.1.C 5.1.C WRCHARAC identical
7.1.D 5.1.D WRICACHE variable stores seem off by 1
7.1.E 5.1.E PRESSRET identical
7.1.F 5.1.F TITLESCR identical
7.1.10 5.1.10 RTNESC identical
7.1.11 5.1.11 CHGNAMES identical
7.1.12 5.1.12 GETNAME identical
7.1.13 5.1.13 BACKUP identical
7.1.14 5.1.14 FRBACKUP identical
7.1.15 5.1.15 TOBACKUP identical
7.1.16 5.1.16 RECOVER identical
7.1.17 5.1.17 TRANSFER "MOVE CHARS BETWEEN SCENARIOS" vs
"MOVE CHARS FROM A SCENARIO"
"TO LEGACY OF LLYLGAMYN ONLY!"
and other differences
7.1.18 5.1.18 REMOVCHR mostly identical, but lots more code at
end in Wiz1
7.1.19 "** CHAR HAS NON-XFERRABLE ITEMS"
7.1.1A 5.1.19 TRANBAD lots of differences in messages/conditions
7.1.1B 5.1.1A TRANGOOD differences in code. More in LOL.

The following procedures are in Wiz1, but don't exist in LOL.

7.1.1C "MAKE NEW SCENARIO DISKETTE"
7.1.1D "ERROR MAKING SCENARIO"
7.1.1E call 1D
7.1.1F "NOT SCENARIO DISK"
7.1.20 "STEP 2 - UPDATE SCENARIO SIDE"
7.1.21 "ERROR DURING UPDATE"
7.1.22 "UPDATING"
7.1.23 Read / Write Volume
7.1.24 "UPDATE DISK"

All of the procedures from 7.1.1C to 7.1.24 are in the MAKESCEN segment for LOL. Since they don't exist in Wiz1, I removed them from the code (recall that I first copied all the LOL code to the disks and I'm removing code that is not in Wiz1.) I also removed the call to MAKESCEN.

I next tried to enter some place holder "dummy" procedures so that UTILS segment would have 36 procedures.

PROCEDURE P07011B;
PROCEDURE P07011C;
PROCEDURE P07011D;
BEGIN
END;
BEGIN
END;

...and so forth.

When I compiled this code I got the message:

ERROR 399

So I looked up that error in the manual:

399: Implementation restriction

That's it! No other information about the error!

After awhile I realized I had placed the "dummy" procedures before some Segment procedures. After I moved the code it compiled cleanly.

Some random notes....

Source files are so large that they must be split so that the editor can load them. This makes it very difficult to do simple things like find and replace text throughout the code. Note also that "included" files cannot be nested.

When working with the DeCompiler, sometimes it helps to transfer the "file.CODE" by itself to a single diskette, and then run the DeCompiler and answer "Y" for all. You can do this for the original Wiz1 file and the re-engineered Wiz1 file and then easily compare the listings using Windiff.

When working with Apple Pascal, I never use the "work" files called SYSTEM.WRK.TEXT or SYSTEM.WRK.CODE. The source files for Wizardry are so large that they need to be on volumes (diskettes) by themselves.

Because of the file size problems, I had to refrain from putting comments in the re-engineered code.

I also use identifier names in the Pascal code that are only 8 characters or fewer. This helps with the file size problem, and also avoids a peculiar scoping problem that can occur in Pascal with variables having the first 8 characters the same.

I make frequent use of the "drag and drop" file to insert a diskette into the AppleWin floppy drive.

I make use of "Scroll Lock" to maximize the speed of AppleWin.

Ok, back to some more coding....

I added SEGMENT TITLELOA(), and also inserted into WIZUTIL the include (*I WIZ1E:TITLELOA *)

I now have the following:

SYSTEM.STARTUP
WIZBOOT 4 procedures
UTILS 36 procedures
TITLELOA 1 procedure
OPTIONS 1 procedure

Note I changed the name from WIZUTIL to SYSTEM.STARTUP to match Wiz1. For compiling I need "#5:SYSTEM.STARTUP." (with the period at end), and for the destination "#5:STARTUP.CODE".

Eventually I changed that to just STARTUP.TEXT and STARTUP.CODE and will make a change at the very end to SYSTEM.STARTUP. It was very confusing using the Pascal system with those other names.

In my next post, I will examine SYSTEM.STARTUP and begin re-engineering starting with the WIZBOOT main line.

Are we there yet?

TommyGoog

unread,
Apr 7, 2014, 7:13:24 PM4/7/14
to
On Monday, April 7, 2014 2:28:10 PM UTC-5, TommyGoog wrote:
> On Friday, April 4, 2014 12:20:16 PM UTC-5, TommyGoog wrote:
>
> > ....The journey continues....

> In my next post, I will examine SYSTEM.STARTUP and begin re-engineering starting with the WIZBOOT main line.

> Are we there yet?

SYSTEM.STARTUP
Segment Procedures
0 WIZBOOT 5
1 UTILS 36
2 TITLELOA 8
3 OPTIONS 1

0 WIZBOOT
proc lex start end order-in-file hierarchy
1 0 7.0.1 50CC 50FF 2 7.0.1
2 6502 7.0.2 511A 52EA 3
3 6502 7.0.3 52F0 54B6 4
4 1 7.0.4 5000 50BA 1 7.0.4
5 6502 7.0.5 54BC 5642 5

I copied SYSTEM.STARTUP from the original Wizardry1 to a blank diskette and ran the DeCompiler and saved the output. I did the same for my STARTUP.CODE that is under construction. I compared the two using Windiff and noticed a lot of the code was the same, but most of the addresses on the left of each line were different. Therefore Windiff reported differences for most almost every line.

This is probably a good place to show a good use for the DeCompiler prompt:

SEGMENT'S START ADDR($5000):

It can be used to help make the output code for the "under construction" version to match more closely with the original. The reason that addresses are different at this point is because I don't have all the code written for the "under construction" version so the addresses relative to the segment load address are smaller than they will be when I have completed the "under construction" version. For example,

Original version:

FILE: 1 SEG: 1 PROC: 1

JTAB FOR SUBROUTINE 1:
DATA SIZE: 1538
PARAM SIZE: 0
EXIT AT: 6B77
ENTER AT: 6A32
PROC NUMBER: 1
LEXICAL LEVEL: 1
6A32 D7 NOP. NOP
6A33 A6 12 57 49 5A 41 52 44 52 59 20 55 54 49 4C 49 54 49 45 53
WIZARDRY UTILITIES
LSA. PUSH #(PC+1) POINTER TO THE STRING
6A47 CE 0F CLP. CALL CHILD PROCEDURE: 0F

Under Construction version:
FILE: 1 SEG: 1 PROC: 1

JTAB FOR SUBROUTINE 1:
DATA SIZE: 1536
PARAM SIZE: 0
EXIT AT: 63DB
ENTER AT: 62A2
PROC NUMBER: 1
LEXICAL LEVEL: 1
62A2 D7 NOP. NOP
62A3 A6 12 57 49 5A 41 52 44 52 59 20 55 54 49 4C 49 54 49 45 53
WIZARDRY UTILITIES
LSA. PUSH #(PC+1) POINTER TO THE STRING
62B7 CE 0F CLP. CALL CHILD PROCEDURE: 0F

The code matches at 6A32 in the original version with that at 62A3. Note the difference is $6A32 - $62A2 = $790. So now when the DeCompiler prompts for "SEGMENT'S START ADDR($5000):" we answer that with "5790" and can see the addresses are the same:

SEGMENT'S START ADDR($5000): 5790

THERE ARE 36 PROCEDURES.


ENTER PROCEDURE # (OR -1) 1


JTAB FOR SUBROUTINE 1:
DATA SIZE: 1536
PARAM SIZE: 0
EXIT AT: 6B6B
ENTER AT: 6A32
PROC NUMBER: 1
LEXICAL LEVEL: 1
6A32 D7 NOP. NOP
6A33 A6 12 57 49 5A 41 52 44 52 59 20 55 54 49 4C 49 54 49 45 53
WIZARDRY UTILITIES
LSA. PUSH #(PC+1) POINTER TO THE STRING
6A47 CE 0F CLP. CALL CHILD PROCEDURE: 0F


By the way, if you don't have something like Windiff, I've found that using Notepad can be used to detect differences in two text files under comparison. You open each ".txt" file in a separate Notepad and maximize both of them. Then you quickly use ALT-TAB to toggle between the two text files and use your eyes to detect any differences. This works great when most of the text is already identical but there might be a few differences. Use the "Page Down" key to advance each one and repeat. Sometimes one will have an extra line in it, so you just adjust that notepad window one line. Rinse and repeat.

A couple more side notes...

My EDIT.DSK can be used to edit or compile code, but not to link or assemble it. The disk COMPILE.DSK can be used to link or assemble code but not to edit.

The "(*$L PRINTER: *)" switch in the source code sends print to the printer when the code is compiled.

In looking at the code for P070001 (WIZBOOT mainline), it becomes clear that the code is something like the following:

STARTUP.TEXT
PROGRAM WIZBOOT;
SEGMENT PROCEDURE UTILS;
SEGMENT PROCEDURE TITLELOA;
SEGMENT PROCEDURE OPTIONS;

PROCEDURE P070002; (* 6502 code *)
PROCEDURE P070003; (* 6502 code *)
PROCEDURE P070004;

BEGIN (* WIZBOOT *)
CALL CHILD 4
CALL PROC 01 SEG 08
REPEAT
CALL PROC 01 SEG 09
50D9
CASE statement
CALL CHILD 4
EXIT PROCEDURE
CALL PROC 01 SEG 07
CALL PROC 01 SEG 08
50EE
UNTIL FALSE;
END.

Let's compare that to the LOL WIZUTIL code:

1230 1 1:0 0 BEGIN (* WIZUTIL *)
1231 1 1:1 0 WRITE( CHR( ESC) );
1232 1 1:1 13 WRITE( CHR( 21) );
1233 1 1:1 21 IF NOT CHKCOPY THEN
1234 1 1:2 28 BEGIN
1235 1 1:3 28 IF NOT CHKCOPY THEN
1236 1 1:4 35 REPEAT UNTIL FALSE
1237 1 1:2 35 END;
1238 1 1:1 38 SVSERIAL;
1239 1 1:1 40 REPEAT
1240 1 1:2 40 OPTIONS;
1241 1 1:2 43 CASE INCHAR OF
1242 1 1:2 46 'S': BEGIN
1243 1 1:4 46 SETCHAIN( 'WIZARDRY');
1244 1 1:4 60 EXIT( WIZBOOT);
1245 1 1:3 64 END;
1246 1 1:3 66
1247 1 1:2 66 'U': BEGIN
1248 1 1:4 66 REPEAT
1249 1 1:5 66 UTILS;
1250 1 1:5 69 IF BASE04 > 0 THEN
1251 1 1:6 74 MAKESCEN
1252 1 1:4 74 UNTIL BASE04 = 0
1253 1 1:3 78 END;
1254 1 1:2 84 END;
1255 1 1:1 98 UNTIL FALSE
1256 1 1:0 98 END.

I will note that in Wizardry1, the range from $53 to $55 on the case statement denotes options "S", "T", and "U".

Wizardry1, P010201 has a SETCHAIN("WIZARDRY"), and is entered by "CALL PROC 01 SEG 08" as shown in the DeCompiler listing.

"CHILD 4" looks like it might be something like "CHKCOPY".

"GLOBAL PROCEDURE: 03" might be "COPYPROT", because the code at 52F0 is definitely accessing the disk drive

5308- A2 60 LDX #$60
530A- BD 8A C0 LDA $C08A,X
530D- BD 89 C0 LDA $C089,X
5310- BD 8E C0 LDA $C08E,X
5313- BD 8C C0 LDA $C08C,X

And now let's just review how Wizardry I actually starts before getting to re-engineering the code.

When booting:

PREPARE YOURSELF
FOR THE ULTIMATE
IN FANTASY GAMES

Then,

Caldron, pipe player, smoke animation, and WIZARDRY logo with sword through it.

At some point there is a check for keypress, so press a key and:

COPYRIGHT @1981...
more legal stuff...
...
VERSION 2.1 of 22-JAN-82 SER: ??????
S)TART GAME U)TILITIES T)ITLE PAGE

[Note, since "SER: ??????" is displayed, clearly not all of my Wizardry disk matches the one at ASIMOV.]

So let's just take a quick stab at the code and see how we do:

CHKCOPY; (* as a PROCEDURE and not as a FUNCTION *)
TITLELOA; (* Load title *)
REPEAT
OPTIONS; (* Get a key *)
CASE INCHAR OF
'S': BEGIN
CHKCOPY; (* CHKCOPY might be bad name as it
does SETCHAIN('WIZARDRY') *)
EXIT( WIZBOOT)
END;
'U': BEGIN
UTILS
END;
'T': BEGIN
TITLELOA
END;
END
UNTIL FALSE


This actually turned out pretty good when I ran the Compiler and then the DeCompiler.
I noticed the DATA SIZE: was 14 instead of 12 (I think BASE04 needs to disappear.)
And I noticed the child procedure displayed by the DeCompiler was 03 and not 04, therefore I need to insert another 6502 External procedure.

Ok, I'm happy with WIZBOOT main line code.

I will tackle CHKCOPY in the next post.


TommyGoog

unread,
Apr 11, 2014, 2:12:32 PM4/11/14
to
> > >I will tackle CHKCOPY in the next post.

Maybe CHKCOPY from LOL will look similar to CHKCOPY for Wiz1.

CHKCOPY from LOL:

BEGIN
UNITREAD( DRIVE1, BUFFER, SIZEOF( BUFFER), SERIALBL, 0);
MOVELEFT( BUFFER, SERIAL, 7);
CHKCOPY := TRUE;
UNITREAD( DRIVE1, BUFFER, SIZEOF( BUFFER), 278, 0);
IF NOT COPYPROT THEN
BEGIN
CHKCOPY := COPYPROT
END
END;

The first part of LOL CHKCOPY is this:

5000 04 SLDC. PUSH #0004
5001 C6 03 LLA. PUSH #MP.03
5003 00 SLDC. PUSH #0000
5004 C7 00 02 LDCI. PUSH #0200
5007 05 SLDC. PUSH #0005
5008 00 SLDC. PUSH #0000
5009 9E 05 READ FROM VOL#

The first part of CHKCOPY( P050003) from Wiz1:

5000 04 SLDC. PUSH #0004
5001 C6 0A LLA. PUSH #MP.0A
5003 00 SLDC. PUSH #0000
5004 C7 00 02 LDCI. PUSH #0200
5007 05 SLDC. PUSH #0005
5008 00 SLDC. PUSH #0000
5009 9E 05 READ FROM VOL#

Clearly this code is generated by a UNITREAD and is similar to LOL. In Wiz1, the buffer is #MP.0A (not #MP.01). This means we need more variables declared before BUFFER in Wiz1. SERIALBL (#0005) is the block on the disk being read. Normally that block is part of a normal PASCAL directory, but for Wizardry it holds the Wizardry "SER: xxxxxx" identifier.

Since SVSERIAL code does not seem to be used, I will remove it for Wiz1.

I insert MP01, MP02, ..., MP05 as INTEGERs into CHKCOPY, and MP06 as ARRAY[ 0..3] OF INTEGER.

The first instruction is decompiled as:

UNITREAD( DRIVE1, BUFFER, SIZEOF( BUFFER), SERIALBL, 0);

The next pcode is:

500B C6 0A LLA. PUSH #MP.0A
500D 00 SLDC. PUSH #0000
500E A5 05 LA0. PUSH #BASE.05
5010 00 SLDC. PUSH #0000
5011 07 SLDC. PUSH #0007
5012 9E 02 MVL. MOVELEFT
5014 1F SLDC. PUSH #001F
5015 CC 04 STL. MP.04 := (TOS)

This converts to:

MOVELEFT( BUFFER, SERIAL, 7);
MP04 := 31;

The next piece of code is a FOR construct:

5017 0A SLDC. PUSH #000A
5018 CC 03 STL. MP.03 := (TOS)
501A 0D SLDC. PUSH #000D
501B CC 81 0A STL. MP.010A := (TOS)
501E DA SLDL. PUSH MP.03
501F CA 81 0A LDL. PUSH MP.010A
5022 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5023 A1 27 UJP. IF NOT (TOS) THEN JUMP TO 504C

5045 DA SLDL. PUSH MP.03
5046 01 SLDC. PUSH #0001
5047 82 ADI. PUSH ((TOS) + (TOS-1))
5048 CC 03 STL. MP.03 := (TOS)
504A B9 F6 UJP. JUMP TO 501E

So let's put it in:

FOR MP03 := 10 to 13 DO
BEGIN
END;

Note the variable MP.010A is automatically generated by the compiler as the FOR loop termination variable. You will see MP.010A re-used later in the code for another FOR loop following this one.

The first instruction in the FOR loop is a MOVELEFT instruction:

5025 C6 0A LLA. PUSH #MP.0A
5027 DB SLDL. PUSH MP.04
5028 C6 06 LLA. PUSH #MP.06
502A DA SLDL. PUSH MP.03
502B 0A SLDC. PUSH #000A
502C 95 SBI. PUSH ((TOS-1) - (TOS))
502D A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
502F 00 SLDC. PUSH #0000
5030 02 SLDC. PUSH #0002
5031 9E 02 MVL. MOVELEFT

Decompiled it is:

MOVELEFT( MP0A[MP04], MP06[MP03-10], 2);

Note, MP0A is a PACKED ARRAY of CHAR. The pcode had me confused at first into thinking there were 4 parameters passed to MOVELEFT, but this is the correct PASCAL code to generate the pcode.

The next sequence of pcode looks intimidating at first. Here it is:

5033 DB SLDL. PUSH MP.04
5034 02 SLDC. PUSH #0002
5035 C6 06 LLA. PUSH #MP.06
5037 DA SLDL. PUSH MP.03
5038 0A SLDC. PUSH #000A
5039 95 SBI. PUSH ((TOS-1) - (TOS))
503A A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
503C F8 SIND. PUSH (TOS)^.0
503D 0D SLDC. PUSH #000D
503E 8E MODI. PUSH ((TOS-1) MOD (TOS))
503F 8F MPI. PUSH ((TOS-1) * (TOS))
5040 82 ADI. PUSH ((TOS) + (TOS-1))
5041 05 SLDC. PUSH #0005
5042 82 ADI. PUSH ((TOS) + (TOS-1))
5043 CC 04 STL. MP.04 := (TOS)

De-Compiled it is:

MP04 := MP04 + 2 * ((MP06[MP03 - 10]) MOD 13) + 5;

This instruction is also within the FOR loop.

This is what the code looks like so far, and I will often compile a PROCEDURE or FUNCTION before it is complete to make sure I am on the right track:


966 1 2:D 3 FUNCTION COPYPROT : BOOLEAN; EXTERNAL; (* P050002 *)
967 1 2:D 3
968 1 2:D 3
969 1 3:D 1 PROCEDURE CHKCOPY; (* P050003 *)
970 1 3:D 1
971 1 3:D 1 VAR
972 1 3:D 1 MP01 : INTEGER;
973 1 3:D 2 MP02 : INTEGER;
974 1 3:D 3 MP03 : INTEGER;
975 1 3:D 4 MP04 : INTEGER;
976 1 3:D 5 MP05 : INTEGER;
977 1 3:D 6 MP06 : ARRAY[0..3] OF INTEGER;
978 1 3:D 10 BUFFER : PACKED ARRAY[ TBLOCKRG] OF CHAR;
979 1 3:D 266
980 1 3:0 0 BEGIN
981 1 3:1 0 UNITREAD( DRIVE1, BUFFER, SIZEOF( BUFFER), SERIALBL, 0);
982 1 3:1 11 MOVELEFT( BUFFER, SERIAL, 7);
983 1 3:1 20 MP04 := 31;
984 1 3:1 23 FOR MP03 := 10 TO 13 DO
985 1 3:2 37 BEGIN
986 1 3:3 37 MOVELEFT( BUFFER[ MP04], MP06[ MP03 - 10], 2);
987 1 3:3 51 MP04 := MP04 + 2 * ((MP06[MP03 - 10]) MOD 13) + 5;
988 1 3:2 69 END;


After the entire routine is completed (and maybe a lot later) I will clean up the variables to something meaningful.

Here is the pcode for the rest of CHKCOPY:

504C 01 SLDC. PUSH #0001
504D CC 02 STL. MP.02 := (TOS)
504F 05 SLDC. PUSH #0005
5050 CC 81 0A STL. MP.010A := (TOS)
5053 D9 SLDL. PUSH MP.02
5054 CA 81 0A LDL. PUSH MP.010A
5057 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5058 A1 5E UJP. IF NOT (TOS) THEN JUMP TO 50B8
505A 01 SLDC. PUSH #0001
505B CC 05 STL. MP.05 := (TOS)
505D 0A SLDC. PUSH #000A
505E CC 03 STL. MP.03 := (TOS)
5060 0D SLDC. PUSH #000D
5061 CC 81 0B STL. MP.010B := (TOS)
5064 DA SLDL. PUSH MP.03
5065 CA 81 0B LDL. PUSH MP.010B
5068 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5069 A1 3F UJP. IF NOT (TOS) THEN JUMP TO 50AA
506B 04 SLDC. PUSH #0004
506C C6 0A LLA. PUSH #MP.0A
506E 00 SLDC. PUSH #0000
506F C7 00 02 LDCI. PUSH #0200
5072 08 SLDC. PUSH #0008
5073 DA SLDL. PUSH MP.03
5074 8F MPI. PUSH ((TOS-1) * (TOS))
5075 00 SLDC. PUSH #0000
5076 9E 05 READ FROM VOL#
5078 C6 04 LLA. PUSH #MP.04
507A CF 03 CGP. CALL GLOBAL PROCEDURE: 03
507C DA SLDL. PUSH MP.03
507D 0A SLDC. PUSH #000A
507E C3 EQUI. PUSH ((TOS-1) = (TOS))
507F A1 0C UJP. IF NOT (TOS) THEN JUMP TO 508D
5081 DB SLDL. PUSH MP.04
5082 C6 06 LLA. PUSH #MP.06
5084 0A SLDC. PUSH #000A
5085 0A SLDC. PUSH #000A
5086 95 SBI. PUSH ((TOS-1) - (TOS))
5087 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5089 F8 SIND. PUSH (TOS)^.0
508A 95 SBI. PUSH ((TOS-1) - (TOS))
508B CC 01 STL. MP.01 := (TOS)
508D DB SLDL. PUSH MP.04
508E D8 SLDL. PUSH MP.01
508F 95 SBI. PUSH ((TOS-1) - (TOS))
5090 CC 04 STL. MP.04 := (TOS)
5092 DC SLDL. PUSH MP.05
5093 DB SLDL. PUSH MP.04
5094 C6 06 LLA. PUSH #MP.06
5096 DA SLDL. PUSH MP.03
5097 0A SLDC. PUSH #000A
5098 95 SBI. PUSH ((TOS-1) - (TOS))
5099 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
509B F8 SIND. PUSH (TOS)^.0
509C 95 SBI. PUSH ((TOS-1) - (TOS))
509D 80 ABI. PUSH ABS( (TOS) ) )
509E 23 SLDC. PUSH #0023
509F C9 LESI. PUSH ((TOS-1) < (TOS))
50A0 84 LAND. PUSH ((TOS-1) AND (TOS))
50A1 CC 05 STL. MP.05 := (TOS)
50A3 DA SLDL. PUSH MP.03
50A4 01 SLDC. PUSH #0001
50A5 82 ADI. PUSH ((TOS) + (TOS-1))
50A6 CC 03 STL. MP.03 := (TOS)
50A8 B9 F4 UJP. JUMP TO 5064
50AA DC SLDL. PUSH MP.05
50AB A1 04 UJP. IF NOT (TOS) THEN JUMP TO 50B1
50AD 01 SLDC. PUSH #0001
50AE 04 SLDC. PUSH #0004
50AF 9E 04 EXIT. EXIT FROM PROCEDURE. (TOS)=PROC# (TOS-1)=SEG#
50B1 D9 SLDL. PUSH MP.02
50B2 01 SLDC. PUSH #0001
50B3 82 ADI. PUSH ((TOS) + (TOS-1))
50B4 CC 02 STL. MP.02 := (TOS)
50B6 B9 F2 UJP. JUMP TO 5053
50B8 9E 27 AN UNKNOWN STANDARD PROCEDURE ?!?!
50BA AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.

Here is the entire decompiled listing:

PROCEDURE CHKCOPY; (* P070004 *)

VAR
MP01 : INTEGER;
MP02 : INTEGER;
MP03 : INTEGER;
MP04 : INTEGER;
MP05 : BOOLEAN;
MP06 : ARRAY[0..3] OF INTEGER;
BUFFER : PACKED ARRAY[ TBLOCKRG] OF CHAR;

BEGIN
UNITREAD( DRIVE1, BUFFER, SIZEOF( BUFFER), SERIALBL, 0);
MOVELEFT( BUFFER, SERIAL, 7);
MP04 := 31;
FOR MP03 := 10 TO 13 DO
BEGIN
MOVELEFT( BUFFER[ MP04], MP06[ MP03 - 10], 2);
MP04 := MP04 + 2 * ((MP06[MP03 - 10]) MOD 13) + 5;
END;
FOR MP02 := 1 TO 5 DO
BEGIN
MP05 := TRUE;
FOR MP03 := 10 TO 13 DO
BEGIN
UNITREAD( DRIVE1, BUFFER, SIZEOF( BUFFER), 8 * MP03, 0);
P070003( MP04); (* CALL GLOBAL PROCEDURE: 03 *)
IF MP03 = 10 THEN
BEGIN
MP01 := MP04 - MP06[ 10 - 10];
END;
MP04 := MP04 - MP01;
MP05 :=MP05 AND (ABS((MP04 - MP06[ MP03 - 10])) < 35);
END;
IF MP05 THEN
BEGIN
EXIT( CHKCOPY);
END;
END;
HALT;
END;


Nothing too remarkable in the rest of that code conversion. You must determine that "CALL GLOBAL PROCEDURE: 03" refers to P070003 and passes MP04.

Also note the sequence of pcode at 5084:

5084 0A SLDC. PUSH #000A
5085 0A SLDC. PUSH #000A
5086 95 SBI. PUSH ((TOS-1) - (TOS))

It looks a bit odd, and the decompiled code I wrote does generate that pcode:

MP01 := MP04 - MP06[ 10 - 10];

Certainly the Wizardry programmers did not write something quite like that ("10 - 10"). I seem to remember sequences like this when doing LOL, and I *think* it has something to do with SCALAR defined constants or subranges, or perhaps something about the "ORD()" function.

I now inserted:

PROCEDURE P070005; EXTERNAL;

following P070004 (CHKCOPY). It needs to be placed there to have the correct number assigned to it by the compiler.

At first I inserted P07003 as this:

PROCEDURE P07003( MP01: INTEGER); EXTERNAL:

It generated the following pcode:

5078 DB SLDL. PUSH MP.04
5079 CF 03 CGP. CALL GLOBAL PROCEDURE: 03

But we really wanted:

5078 C6 04 LLA. PUSH #MP.04
507A CF 03 CGP. CALL GLOBAL PROCEDURE: 03

Therefor the parameter needs to be passed by REFERENCE and not by VALUE. (Put "VAR" before MP01 in declaration.)

I found that the "UNKNOWN" for "9E 27" is the PASCAL "HALT" instruction.

A lot of this code is really confusing to try to understand. I think I looked at it 2.5 years ago. To understand it you need to see at least the sector with the serial number, so here it is (using COPY][+):

00- 06 33 39 31 30 39 30 00 F391090@
08- 00 00 00 01 88 00 00 00 @@@A.@@@
10- 00 00 00 00 00 00 00 00 @@@@@@@@
18- 00 00 00 00 00 00 00 16 @@@@@@@V
20- 12 00 00 00 F0 0C D4 0F R@@@pLTO
28- C7 09 64 16 47 09 47 05 GI$VGIGE
30- 64 16 47 05 F3 06 ED 07 $VGEsFmG
38- 0F 06 12 15 12 31 12 00 OFRUR1R@
40- E5 02 B9 08 12 4B 12 79 eB9HRKR9
48- C6 05 31 13 12 78 17 1B FE1SR8W[
50- 12 06 AB 08 EA 05 12 12 RF+HjERR
58- EE 02 EC 0C 00 00 1C 13 nBlL@@\S
60- 00 12 BE 05 1C 13 E8 05 @R>E\ShE
68- B5 05 00 00 16 09 00 00 5E@@VI@@
70- 00 00 00 00 00 00 00 00 @@@@@@@@
78- 00 00 00 00 00 00 00 00 @@@@@@@@
80- 00 00 00 00 00 00 00 00 @@@@@@@@
88- 00 00 00 00 00 00 00 00 @@@@@@@@
90- 00 00 00 00 00 00 00 00 @@@@@@@@
98- 00 00 00 00 00 00 00 00 @@@@@@@@
A0- 00 00 00 00 00 00 00 00 @@@@@@@@
A8- 00 00 00 00 00 00 00 00 @@@@@@@@
B0- 00 00 00 00 00 00 00 00 @@@@@@@@
B8- 00 00 00 00 00 00 00 00 @@@@@@@@
C0- 00 00 00 00 00 00 00 00 @@@@@@@@
C8- 00 00 00 00 00 00 00 00 @@@@@@@@
D0- 00 00 00 00 00 00 00 00 @@@@@@@@
D8- 00 00 00 00 00 00 00 00 @@@@@@@@
E0- 00 00 00 00 00 00 00 00 @@@@@@@@
E8- 00 00 00 00 00 00 00 00 @@@@@@@@
F0- 00 00 00 00 00 00 00 00 @@@@@@@@
F8- 00 00 00 00 00 00 00 00 @@@@@@@@

Note that MP04 := 31 is looking at $1F. Also note the serial number at the beginning of this sector. This came from my "box" set of Wizardry. The Serial# is: 391090.

One other thing I feel I must mention is the "EXIT" instruction. This is used here (and in LOL) and I think it is generally a bad idea to use this construct. In this routine, EXIT is the "normal" way to return to the caller. YUCK!

Next up is the procedure P070003 which is 6502 assembly code. I need to relearn a bunch more stuff before tackling that.

TommyGoog

unread,
Apr 12, 2014, 4:58:27 PM4/12/14
to

> Next up is the procedure P070003 which is 6502 assembly code. I need to relearn a bunch more stuff before tackling that.

SEGMENT: Procedures:
0 WIZBOOT 5
1 UTILS 36
2 TITLELOA 8
3 OPTIONS 1

WIZBOOT lex Start Exit Order Hierarchy
1 0 50CC 50FF 2 7.0.1
2 6502 code 511A 52EA 3
3 6502 code 52F0 54B6 4
4 1 5000 50BA 1 7.0.4
5 6502 code 54BC 5642 5

There are 3 PROCEDUREs/FUNCTIONs in SEGMENT WIZBOOT that are 6502 code (written in assembler).

I mentioned in an earlier post how to get an Apple "monitor" disassembly for Pascal 6502 procedures.

P070003
52F0- 68 PLA
52F1- 85 00 STA $00
52F3- 68 PLA
52F4- 85 01 STA $01
52F6- 68 PLA
52F7- 85 02 STA $02
52F9- 68 PLA
52FA- 85 03 STA $03
52FC- A5 01 LDA $01
52FE- 48 PHA
52FF- A5 00 LDA $00
5301- 48 PHA
5302- A9 00 LDA #$00
5304- 85 0D STA $0D
5306- 85 0E STA $0E
5308- A2 60 LDX #$60
530A- BD 8A C0 LDA $C08A,X
530D- BD 89 C0 LDA $C089,X
5310- BD 8E C0 LDA $C08E,X
5313- BD 8C C0 LDA $C08C,X
5316- 10 FB BPL $5313
5318- C9 FF CMP #$FF
531A- D0 F7 BNE $5313
531C- BD 8C C0 LDA $C08C,X
531F- 10 FB BPL $531C
5321- C9 FF CMP #$FF
5323- D0 EE BNE $5313
5325- BD 8C C0 LDA $C08C,X
5328- 10 FB BPL $5325
532A- C9 FF CMP #$FF
532C- D0 03 BNE $5331
532E- 4C 35 00 JMP $0035
5331- BD 8C C0 LDA $C08C,X
5334- 10 FB BPL $5331
5336- C9 D5 CMP #$D5
5338- D0 F7 BNE $5331
533A- BD 8C C0 LDA $C08C,X
533D- 10 FB BPL $533A
533F- C9 AA CMP #$AA
5341- D0 EE BNE $5331
5343- BD 8C C0 LDA $C08C,X
5346- 10 FB BPL $5343
5348- C9 96 CMP #$96
534A- D0 E5 BNE $5331
534C- BD 8C C0 LDA $C08C,X
534F- 10 FB BPL $534C
5351- EA NOP
5352- EA NOP
5353- EA NOP
5354- EA NOP
5355- EA NOP
5356- BD 8C C0 LDA $C08C,X
5359- 10 FB BPL $5356
535B- EA NOP
535C- EA NOP
535D- EA NOP
535E- EA NOP
535F- EA NOP
5360- BD 8C C0 LDA $C08C,X
5363- 10 FB BPL $5360
5365- EA NOP
5366- EA NOP
5367- EA NOP
5368- EA NOP
5369- EA NOP
536A- BD 8C C0 LDA $C08C,X
536D- 10 FB BPL $536A
536F- EA NOP
5370- EA NOP
5371- EA NOP
5372- EA NOP
5373- EA NOP
5374- BD 8C C0 LDA $C08C,X
5377- 10 FB BPL $5374
5379- A8 TAY
537A- EA NOP
537B- EA NOP
537C- EA NOP
537D- EA NOP
537E- EA NOP
537F- BD 8C C0 LDA $C08C,X
5382- 10 FB BPL $537F
5384- 85 04 STA $04
5386- 98 TYA
5387- 38 SEC
5388- 2A ROL
5389- 25 04 AND $04
538B- C9 00 CMP #$00
538D- D0 84 BNE $5313
538F- 20 1B 01 JSR $011B
5392- BD 8C C0 LDA $C08C,X
5395- 10 FB BPL $5392
5397- C9 D5 CMP #$D5
5399- F0 09 BEQ $53A4
539B- E6 0D INC $0D
539D- D0 F3 BNE $5392
539F- E6 0E INC $0E
53A1- 4C A2 00 JMP $00A2
53A4- BD 8C C0 LDA $C08C,X
53A7- 10 FB BPL $53A4
53A9- C9 AA CMP #$AA
53AB- D0 E5 BNE $5392
53AD- BD 8C C0 LDA $C08C,X
53B0- 10 FB BPL $53AD
53B2- C9 96 CMP #$96
53B4- D0 DC BNE $5392
53B6- BD 8C C0 LDA $C08C,X
53B9- 10 FB BPL $53B6
53BB- EA NOP
53BC- EA NOP
53BD- EA NOP
53BE- EA NOP
53BF- EA NOP
53C0- BD 8C C0 LDA $C08C,X
53C3- 10 FB BPL $53C0
53C5- EA NOP
53C6- EA NOP
53C7- EA NOP
53C8- EA NOP
53C9- EA NOP
53CA- BD 8C C0 LDA $C08C,X
53CD- 10 FB BPL $53CA
53CF- EA NOP
53D0- EA NOP
53D1- EA NOP
53D2- EA NOP
53D3- EA NOP
53D4- BD 8C C0 LDA $C08C,X
53D7- 10 FB BPL $53D4
53D9- EA NOP
53DA- EA NOP
53DB- EA NOP
53DC- EA NOP
53DD- EA NOP
53DE- BD 8C C0 LDA $C08C,X
53E1- 10 FB BPL $53DE
53E3- A8 TAY
53E4- EA NOP
53E5- EA NOP
53E6- EA NOP
53E7- EA NOP
53E8- EA NOP
53E9- BD 8C C0 LDA $C08C,X
53EC- 10 FB BPL $53E9
53EE- 85 04 STA $04
53F0- 98 TYA
53F1- 38 SEC
53F2- 2A ROL
53F3- 25 04 AND $04
53F5- C9 00 CMP #$00
53F7- F0 03 BEQ $53FC
53F9- 4C A2 00 JMP $00A2
53FC- A0 00 LDY #$00
53FE- A5 0D LDA $0D
5400- 91 02 STA ($02),Y
5402- C8 INY
5403- A5 0E LDA $0E
5405- 91 02 STA ($02),Y
5407- BD 88 C0 LDA $C088,X
540A- 60 RTS

540B- 86 06 STX $06
540D- A0 0C LDY #$0C
540F- 84 07 STY $07
5411- 88 DEY
5412- 88 DEY
5413- 84 08 STY $08
5415- A9 EF LDA #$EF
5417- 85 0B STA $0B
5419- A9 D8 LDA #$D8
541B- 85 0C STA $0C
541D- A9 00 LDA #$00
541F- 85 09 STA $09
5421- A5 08 LDA $08
5423- 85 0A STA $0A
5425- 38 SEC
5426- E5 07 SBC $07
5428- F0 31 BEQ $545B
542A- B0 06 BCS $5432
542C- 49 FF EOR #$FF
542E- E6 08 INC $08
5430- 90 04 BCC $5436
5432- 69 FE ADC #$FE
5434- C6 08 DEC $08
5436- C5 09 CMP $09
5438- 90 02 BCC $543C
543A- A5 09 LDA $09
543C- C9 0C CMP #$0C
543E- B0 01 BCS $5441
5440- A8 TAY
5441- 38 SEC
5442- 20 6F 01 JSR $016F
5445- B9 91 01 LDA $0191,Y
5448- 20 80 01 JSR $0180
544B- A5 0A LDA $0A
544D- 18 CLC
544E- 20 71 01 JSR $0171
5451- B9 9D 01 LDA $019D,Y
5454- 20 80 01 JSR $0180
5457- E6 09 INC $09
5459- D0 C6 BNE $5421
545B- 20 80 01 JSR $0180
545E- 18 CLC
545F- A5 08 LDA $08
5461- 29 03 AND #$03
5463- 2A ROL
5464- 05 06 ORA $06
5466- AA TAX
5467- BD 80 C0 LDA $C080,X
546A- A6 06 LDX $06
546C- 60 RTS

546D- AA TAX
546E- A0 A0 LDY #$A0
5470- A2 11 LDX #$11
5472- CA DEX
5473- D0 FD BNE $5472
5475- E6 0B INC $0B
5477- D0 02 BNE $547B
5479- E6 0C INC $0C
547B- 38 SEC
547C- E9 01 SBC #$01
547E- D0 F0 BNE $5470
5480- 60 RTS

5481- 01 30 ORA ($30,X)
5483- 28 PLP
5484- 20 20 1E JSR $1E20
5487- 1D 1C 1C ORA $1C1C,X
548A- 1C ???
548B- 1C ???
548C- 1C ???
548D- 70 2C BVS $54BB
548F- 26 22 ROL $22
5491- 1F ???
5492- 1E 1D 1C ASL $1C1D,X
5495- 1C ???
5496- 1C ???
5497- 1C ???
5498- 1C ???
5499- 00 BRK
549A- 00 BRK
549B- 00 BRK
549C- 6D 01 0E ADC $0E01
549F- 01 FE ORA ($FE,X)
54A1- 00 BRK
54A2- A8 TAY
54A3- 00 BRK
54A4- 61 00 ADC ($00,X)
54A6- 60 RTS
54A7- 00 BRK
54A8- 5F ???
54A9- 00 BRK
54AA- 5B ???
54AB- 00 BRK
54AC- 5A ???
54AD- 00 BRK
54AE- 59 00 54 EOR $5400,Y
54B1- 00 BRK
54B2- 0B ???
54B3- 00 BRK
54B4- 00 BRK
54B5- 00 BRK
54B6- 00 BRK
54B7- 00 BRK
54B8- C8 INY
54B9- 01 00 ORA ($00,X)
54BB- 00 BRK

This code as loaded at $511A is the code from the Wizardry1 diskette. Note though that it is not yet ready for execution. The Assembler, Linker, and runtime Segment Loader need to coordinate a few things. The Segment Loader can load the segment at different locations in memory. One time it might load it at $5000, and another time at $5502. Therefore a JMP instruction cannot have the same destination address in both places if the JMP is to a location somewhere else in this code.

The Assembler updates the JTAB "Optional Jump Table" for this procedure. (See Apple Pascal Operating System, Operation of P-Machine, P 253). When the Segment Loader loads the segment, it goes through this Jump Table and alters the JMP (and JSR) instructions.

Let's look at an example from the code above for P070003:

545B- 20 80 01 JSR $0180

The JTAB begins at 54BB and is "upside down" as described in the manual.

Also, 2 consecutive addresses are generally grouped in pairs forming a 16 bit value. The lower address of the pair is considered the address of that table entry, and the lower address contains the least significant bits of the 16 bit value ($54B8 is the address with a value of $01C8).

54BB 0
54BA 0 JTAB
54B9 1
54B8 C8 Enter IC
54B7 0
54B6 0
54B5 0
54B4 0
54B3 0
54B2 0B Number of JMP entries in table
54B1 0
54B0 54
54AF 0
54AE 59

Before I get too far, a word about those pointers. They are self-relative pointers. You take the value that is stored there, and subtract it from its address to get the ABSOLUTE address. For example, the Enter IC is at $54B8 and it has the value $01C8. When this segment is loaded at $5000, this is therefore referring to $52F0 ($54B8 - $01C8).

Another example, $54B0 - $0054 = $545C, and we find a JSR instruction there:

545B- 20 80 01 JSR $0180

Ok, so now we see $0180 as the destination. That is a relative pointer using the beginning of the procedure. $5470 ($52F0 + $0180).

For starters we can call the label "L0180, and have JSR L0180.

If there is a data table in the procedure, then the references to it will also need to be ABSOLUTIZED (resolved is probably the proper term to use).

5445- B9 91 01 LDA $0191,Y

$52F0 + $0191 = $5481

Therefore this is " LDA L0191,Y" and the table at $5481 has the label L0191.

Ok, so now we can convert this to source code, but we note that Apple Pascal does have a few differences:

All number must begin with 0 through 9, so "$C08C" must be written as "0C08C".

Some instructions need the operand. ROL must be written as "ROL A".

STA ($02),Y becomes STA @02,Y

I had some problems during my first attempts at Assembling the code, that I thought I'd share with you so that you do not make the same mistakes.

A(ssemble
Assemble what text? #11:P070003
To what codefile? #11:P070003
Output file for assembled listing: #11:P070003.OUT
"bad title, illegal file name"

Don't give the file for output an extension.
And if you try P070003 with no extension you will not be happy. It will overwrite your source file!!

Output file for assembled listing: #11:P07OUT
"no room, insufficient space on disk"

But this is my current disk usage:

#4: 194 unused
#5: 38 unused
#11: 194 unused
#12: 160 unused

Ok, let's try putting the output listing on a different disk:

Output file for assembled listing: #12:POUT
...
Assembly complete: 38 lines
0 Errors flagged on this Assembly

Ok, that worked.

Here is an alternate way of fixing the problem:
Put "size" for Code file:

To what codefile? #11:p070003.CODE[10]
Output file for assembled listing: #11:pout
...
Assembly complete: 38 lines
0 Errors flagged on this Assembly

Now its time to Link P070003.CODE into STARTUP.CODE

L(inking
Host file? #12:STARTUP
Libfile? #11:P070003.CODE
Reading WIZBOOT
Reading P070003
Output file? #11:STARTUP.CODE

Linking UTILS #7
Linking TITLELOA #8
Linking OPTIONS #9
Linking WIZBOOT #1
Proc P070005 undefined
Func COPYPROT undefined

Since there were errors, no .CODE was produced. Therefore, make a dummy P070005 and dummy COPYPROT.

Host file? #12:STARTUP
Libfile?
#11:P070003.CODE
#11:P070005.CODE
#11:COPYPROT.CODE
Output file? #11:STARTUP

In looking at the DeCompiled code for this STARTUP.CODE, I noticed that PROCEDURE 03 started at a smaller address than $52F0, therefore I need to put more data in PROCEDURE 02. Also worth noting is that the order you enter Lib Files is important.

Libfile?
#11:COPYPROT.CODE
#11:P070003.CODE
#11:P070005.CODE

Here is the completed rough draft for P070003

0000| .PROC P070003,1 ; 1 PARAMETER
Current memory available: 8644
0000| 68 PLA
0001| 85 00 STA 00
0003| 68 PLA
0004| 85 01 STA 01
0006| 68 PLA
0007| 85 02 STA 02
0009| 68 PLA
000A| 85 03 STA 03
000C| A5 01 LDA 01
000E| 48 PHA
000F| A5 00 LDA 00
0011| 48 PHA
0012| A9 00 LDA #0
0014| 85 0D STA 0D
0016| 85 0E STA 0E
0018| A2 60 LDX #060
001A| BD 8AC0 LDA 0C08A,X
001D| BD 89C0 LDA 0C089,X
0020| BD 8EC0 LDA 0C08E,X
0023| L5313
0023| BD 8CC0 LDA 0C08C,X
0026| 10FB BPL L5313
0028| C9 FF CMP #0FF
002A| D0F7 BNE L5313
002C| L531C
002C| BD 8CC0 LDA 0C08C,X
002F| 10FB BPL L531C
0031| C9 FF CMP #0FF
0033| D0EE BNE L5313
0035| L0035
0035| BD 8CC0 LDA 0C08C,X
0038| 10FB BPL L0035
003A| C9 FF CMP #0FF
003C| D0** BNE L5331
003E| 4C 3500 JMP L0035
003C* 03
0041| L5331
0041| BD 8CC0 LDA 0C08C,X
0044| 10FB BPL L5331
0046| C9 D5 CMP#0D5
0048| D0F7 BNE L5331
004A| L533A
004A| BD 8CC0 LDA 0C08C,X
004D| 10FB BPL L533A
004F| C9 AA CMP #0AA
0051| D0EE BNE L5331
0053| L5343
0053| BD 8CC0 LDA 0C08C,X
0056| 10FB BPL L5343
0058| C9 96 CMP #096
005A| D0E5 BNE L5331
005C| L534C
005C| BD 8CC0 LDA 0C08C,X
PAGE - 2 P070003 FILE:


005F| 10FB BPL L534C
0061| EA NOP
0062| EA NOP
0063| EA NOP
0064| EA NOP
0065| EA NOP
0066| L5356
0066| BD 8CC0 LDA 0C08C,X
0069| 10FB BPL L5356
006B| EA NOP
006C| EA NOP
006D| EA NOP
006E| EA NOP
006F| EA NOP
0070| L5360
0070| BD 8CC0 LDA 0C08C,X
0073| 10FB BPL L5360
0075| EA NOP
0076| EA NOP
0077| EA NOP
0078| EA NOP
0079| EA NOP
007A| L536A
007A| BD 8CC0 LDA 0C08C,X
007D| 10FB BPL L536A
007F| EA NOP
0080| EA NOP
0081| EA NOP
0082| EA NOP
0083| EA NOP
0084| L5374
0084| BD 8CC0 LDA 0C08C,X
0087| 10FB BPL L5374
0089| A8 TAY
008A| EA NOP
008B| EA NOP
008C| EA NOP
008D| EA NOP
008E| EA NOP
008F| L537F
008F| BD 8CC0 LDA 0C08C,X
0092| 10FB BPL L537F
0094| 85 04 STA 04
0096| 98 TYA
0097| 38 SEC
0098| 2A ROL A
0099| 25 04 AND 04
009B| C9 00 CMP #00
009D| D084 BNE L5313
009F| 20 **** JSR L011B
00A2| L00A2
00A2| L5392
00A2| BD 8CC0 LDA 0C08C,X
00A5| 10FB BPL L5392
00A7| C9 D5 CMP #0D5
PAGE - 3 P070003 FILE:


00A9| F0** BEQ L53A4
00AB| E6 0D INC 0D
00AD| D0F3 BNE L5392
00AF| E6 0E INC 0E
00B1| 4C A200 JMP L00A2
00A9* 09
00B4| L53A4
00B4| BD 8CC0 LDA 0C08C,X
00B7| 10FB BPL L53A4
00B9| C9 AA CMP #0AA
00BB| D0E5 BNE L5392
00BD| L53AD
00BD| BD 8CC0 LDA 0C08C,X
00C0| 10FB BPL L53AD
00C2| C9 96 CMP #096
00C4| D0DC BNE L5392
00C6| L53B6
00C6| BD 8CC0 LDA 0C08C,X
00C9| 10FB BPL L53B6
00CB| EA NOP
00CC| EA NOP
00CD| EA NOP
00CE| EA NOP
00CF| EA NOP
00D0| L53C0
00D0| BD 8CC0 LDA 0C08C,X
00D3| 10FB BPL L53C0
00D5| EA NOP
00D6| EA NOP
00D7| EA NOP
00D8| EA NOP
00D9| EA NOP
00DA| L53CA
00DA| BD 8CC0 LDA 0C08C,X
00DD| 10FB BPL L53CA
00DF| EA NOP
00E0| EA NOP
00E1| EA NOP
00E2| EA NOP
00E3| EA NOP
00E4| L53D4
00E4| BD 8CC0 LDA 0C08C,X
00E7| 10FB BPL L53D4
00E9| EA NOP
00EA| EA NOP
00EB| EA NOP
00EC| EA NOP
00ED| EA NOP
00EE| L53DE
00EE| BD 8CC0 LDA 0C08C,X
00F1| 10FB BPL L53DE
00F3| A8 TAY
00F4| EA NOP
00F5| EA NOP
00F6| EA NOP
PAGE - 4 P070003 FILE:


00F7| EA NOP
00F8| EA NOP
00F9| L53E9
00F9| BD 8CC0 LDA 0C08C,X
00FC| 10FB BPL L53E9
00FE| 85 04 STA 04
0100| 98 TYA
0101| 38 SEC
0102| 2A ROL A
0103| 25 04 AND 04
0105| C9 00 CMP #0
0107| F0** BEQ L53FC
0109| 4C A200 JMP L00A2
0107* 03
010C| L53FC
010C| A0 00 LDY #0
010E| A5 0D LDA 0D
0110| 91 02 STA @02,Y
0112| C8 INY
0113| A5 0E LDA 0E
0115| 91 02 STA @02,Y
0117| BD 88C0 LDA 0C088,X
011A| 60 RTS
011B| ;
00A0* 1B01
011B| L011B
011B| 86 06 STX 06
011D| A0 0C LDY #0C
011F| 84 07 STY 07
0121| 88 DEY
0122| 88 DEY
0123| 84 08 STY 08
0125| A9 EF LDA #0EF
0127| 85 0B STA 0B
0129| A9 D8 LDA #0D8
012B| 85 0C STA 0C
012D| A9 00 LDA #0
012F| 85 09 STA 09
0131| L5421
0131| A5 08 LDA 08
0133| 85 0A STA 0A
0135| 38 SEC
0136| E5 07 SBC 07
0138| F0** BEQ L545B
013A| B0** BCS L5432
013C| 49 FF EOR #0FF
013E| E6 08 INC 08
0140| 90** BCC L5436
013A* 06
0142| L5432
0142| 69 FE ADC #0FE
0144| C6 08 DEC 08
0140* 04
0146| L5436
0146| C5 09 CMP 09
PAGE - 5 P070003 FILE:


0148| 90** BCC L543C
014A| A5 09 LDA 09
0148* 02
014C| L543C
014C| C9 0C CMP #0C
014E| B0** BCS L5441
0150| A8 TAY
014E* 01
0151| L5441
0151| 38 SEC
0152| 20 **** JSR L016F
0155| B9 **** LDA L0191,Y
0158| 20 **** JSR L0180
015B| A5 0A LDA 0A
015D| 18 CLC
015E| 20 **** JSR L0171 ; NOT RESOLVED
0161| B9 **** LDA L019D,Y ; NOT RESOLVED
0164| 20 **** JSR L0180 ; NOT RESOLVED
0167| E6 09 INC 09
0169| D0C6 BNE L5421
0138* 31
016B| L545B
016B| 20 **** JSR L0180 ; NOT RESOLVED
016E| 18 CLC
0153* 6F01
016F| L016F
016F| A5 08 LDA 08
015F* 7101
0171| L0171
0171| 29 03 AND #03
0173| 2A ROL A
0174| 05 06 ORA 06
0176| AA TAX
0177| BD 80C0 LDA 0C080,X
017A| A6 06 LDX 06
017C| 60 RTS
017D| ;
017D| AA TAX
017E| A0 A0 LDY #0A0
016C* 8001
0165* 8001
0159* 8001
0180| L0180
0180| L5470
0180| A2 11 LDX #011
0182| L5472
0182| CA DEX
0183| D0FD BNE L5472
0185| E6 0B INC 0B
0187| D0** BNE L547B
0189| E6 0C INC 0C
0187* 02
018B| L547B
018B| 38 SEC
018C| E9 01 SBC #01
PAGE - 6 P070003 FILE:


018E| D0F0 BNE L5470
0190| 60 RTS
0156* 9101
0191| 01 30 28 20 20 1E 1D L0191 .BYTE 001,030,028,020,020,01E,01D,01C,01C,01C,01C,01C
0198| 1C 1C 1C 1C 1C
0162* 9D01
019D| 70 2C 26 22 1F 1E 1D L019D .BYTE 070,02C,026,022,01F,01E,01D,01C,01C,01C,01C,01C
01A4| 1C 1C 1C 1C 1C
01A9| 00 .BYTE 000
01AA| .END
PAGE - 7 P070003 FILE: SYMBOLTABLE DUMP


AB - Absolute LB - Label UD - Undefined MC - Macro
RF - Ref DF - Def PR - Proc FC - Func
PB - Public PV - Private CS - Consts


L0035 LB 0035| L00A2 LB 00A2| L011B LB 011B| L016F LB 016F| L0171 LB 0171| L0180 LB 0180| L0191 LB 0191
L019D LB 019D| L5313 LB 0023| L531C LB 002C| L5331 LB 0041| L533A LB 004A| L5343 LB 0053| L534C LB 005C
L5356 LB 0066| L5360 LB 0070| L536A LB 007A| L5374 LB 0084| L537F LB 008F| L5392 LB 00A2| L53A4 LB 00B4
L53AD LB 00BD| L53B6 LB 00C6| L53C0 LB 00D0| L53CA LB 00DA| L53D4 LB 00E4| L53DE LB 00EE| L53E9 LB 00F9
L53FC LB 010C| L5421 LB 0131| L5432 LB 0142| L5436 LB 0146| L543C LB 014C| L5441 LB 0151| L545B LB 016B
L5470 LB 0180| L5472 LB 0182| L547B LB 018B| P070003 PR ----|
PAGE - 8 P070003 FILE:


Current minimum space is 8305 words

Assembly complete: 267 lines
0 Errors flagged on this Assembly

I just noticed something a bit unusual in the code. Either I made a mistake or the original coders left some "dead code" in there:

546D- AA TAX
546E- A0 A0 LDY #$A0


Next up is P070002 (COPYPROT)






TommyGoog

unread,
Apr 14, 2014, 10:35:15 PM4/14/14
to

> Next up is P070002 (COPYPROT)

P070002 (COPYPROT)

Right now COPYPROT is just a placeholder routine with " .BLOCK 1C8,2".

I'm not sure what COPYPROT does, so for now I'll rename it to P070002.

Here is how I currently build STARTUP.CODE:

Host file?
#12:STARTUP
Libfile?
#5:P070002.CODE
#5:P070003.CODE
#5:P070005.CODE
Output file?
#5:STARTUP

From the DeCompiler we see:

Start
P070002 $511A
P070003 $52F0

Note, the DeCompiler has a bug if P070002 is not already LINKED into the executable. It displays lots of garbage.

We do the trick with the DeCompiler to get P070002 (from Wiz1 Boot disk) into memory and use Apples monitor to display the code:

]CALL-151

*511ALLLLLLLLLL

511A- 68 PLA
511B- AA TAX
511C- 68 PLA
511D- A8 TAY
511E- 68 PLA
511F- 85 00 STA $00
5121- 68 PLA
5122- 85 01 STA $01
5124- 68 PLA
5125- 85 02 STA $02
5127- 68 PLA
5128- 85 03 STA $03
512A- 98 TYA
512B- 48 PHA
512C- 8A TXA
512D- 48 PHA
512E- 18 CLC
512F- A5 02 LDA $02
5131- 65 00 ADC $00
5133- 85 02 STA $02
5135- A5 03 LDA $03
5137- 65 01 ADC $01
5139- 85 03 STA $03
513B- A2 00 LDX #$00
513D- A9 03 LDA #$03
513F- 0D 1C BF ORA $BF1C
5142- 8D 1C BF STA $BF1C
5145- A1 02 LDA ($02,X)
5147- C9 C0 CMP #$C0
5149- 90 36 BCC $5181
514B- C9 FD CMP #$FD
514D- 90 03 BCC $5152
514F- 4C 32 01 JMP $0132
5152- 38 SEC
5153- E9 C0 SBC #$C0
5155- 85 07 STA $07
5157- A0 02 LDY #$02
5159- B1 02 LDA ($02),Y
515B- 85 06 STA $06
515D- 88 DEY
515E- B1 02 LDA ($02),Y
5160- A8 TAY
5161- B9 BC 04 LDA $04BC,Y
5164- 85 04 STA $04
5166- B9 7C 05 LDA $057C,Y
5169- 85 05 STA $05
516B- A4 07 LDY $07
516D- A5 06 LDA $06
516F- 91 04 STA ($04),Y
5171- 18 CLC
5172- A5 02 LDA $02
5174- 69 03 ADC #$03
5176- 85 02 STA $02
5178- A9 00 LDA #$00
517A- 65 03 ADC $03
517C- 85 03 STA $03
517E- 4C 2B 00 JMP $002B
5181- A8 TAY
5182- B9 BC 04 LDA $04BC,Y
5185- 85 04 STA $04
5187- B9 7C 05 LDA $057C,Y
518A- 85 05 STA $05
518C- A0 01 LDY #$01
518E- B1 02 LDA ($02),Y
5190- 85 06 STA $06
5192- C8 INY
5193- B1 02 LDA ($02),Y
5195- 85 07 STA $07
5197- C8 INY
5198- B1 02 LDA ($02),Y
519A- 85 08 STA $08
519C- C8 INY
519D- B1 02 LDA ($02),Y
519F- 85 09 STA $09
51A1- C8 INY
51A2- B1 02 LDA ($02),Y
51A4- 85 0A STA $0A
51A6- 18 CLC
51A7- A5 02 LDA $02
51A9- 69 06 ADC #$06
51AB- 85 02 STA $02
51AD- A5 03 LDA $03
51AF- 69 00 ADC #$00
51B1- 85 03 STA $03
51B3- A0 00 LDY #$00
51B5- A5 06 LDA $06
51B7- 20 B7 00 JSR $00B7
51BA- A5 07 LDA $07
51BC- 20 B7 00 JSR $00B7
51BF- A5 08 LDA $08
51C1- 20 B7 00 JSR $00B7
51C4- A5 09 LDA $09
51C6- 20 B7 00 JSR $00B7
51C9- A5 0A LDA $0A
51CB- 20 B7 00 JSR $00B7
51CE- 4C 2B 00 JMP $002B
51D1- 85 00 STA $00
51D3- 46 00 LSR $00
51D5- 90 0A BCC $51E1
51D7- A1 02 LDA ($02,X)
51D9- 91 04 STA ($04),Y
51DB- E6 02 INC $02
51DD- D0 02 BNE $51E1
51DF- E6 03 INC $03
51E1- C8 INY
51E2- 46 00 LSR $00
51E4- 90 0A BCC $51F0
51E6- A1 02 LDA ($02,X)
51E8- 91 04 STA ($04),Y
51EA- E6 02 INC $02
51EC- D0 02 BNE $51F0
51EE- E6 03 INC $03
51F0- C8 INY
51F1- 46 00 LSR $00
51F3- 90 0A BCC $51FF
51F5- A1 02 LDA ($02,X)
51F7- 91 04 STA ($04),Y
51F9- E6 02 INC $02
51FB- D0 02 BNE $51FF
51FD- E6 03 INC $03
51FF- C8 INY
5200- 46 00 LSR $00
5202- 90 0A BCC $520E
5204- A1 02 LDA ($02,X)
5206- 91 04 STA ($04),Y
5208- E6 02 INC $02
520A- D0 02 BNE $520E
520C- E6 03 INC $03
520E- C8 INY
520F- 46 00 LSR $00
5211- 90 0A BCC $521D
5213- A1 02 LDA ($02,X)
5215- 91 04 STA ($04),Y
5217- E6 02 INC $02
5219- D0 02 BNE $521D
521B- E6 03 INC $03
521D- C8 INY
521E- 46 00 LSR $00
5220- 90 0A BCC $522C
5222- A1 02 LDA ($02,X)
5224- 91 04 STA ($04),Y
5226- E6 02 INC $02
5228- D0 02 BNE $522C
522A- E6 03 INC $03
522C- C8 INY
522D- 46 00 LSR $00
522F- 90 0A BCC $523B
5231- A1 02 LDA ($02,X)
5233- 91 04 STA ($04),Y
5235- E6 02 INC $02
5237- D0 02 BNE $523B
5239- E6 03 INC $03
523B- C8 INY
523C- 46 00 LSR $00
523E- 90 0A BCC $524A
5240- A1 02 LDA ($02,X)
5242- 91 04 STA ($04),Y
5244- E6 02 INC $02
5246- D0 02 BNE $524A
5248- E6 03 INC $03
524A- C8 INY
524B- 60 RTS
524C- C9 FE CMP #$FE
524E- F0 05 BEQ $5255
5250- C9 FD CMP #$FD
5252- F0 10 BEQ $5264
5254- 60 RTS
5255- A9 30 LDA #$30
5257- 85 09 STA $09
5259- 20 77 01 JSR $0177
525C- C6 09 DEC $09
525E- D0 F9 BNE $5259
5260- 20 77 01 JSR $0177
5263- 60 RTS
5264- A9 30 LDA #$30
5266- 85 09 STA $09
5268- 20 59 01 JSR $0159
526B- C6 09 DEC $09
526D- D0 F9 BNE $5268
526F- 20 59 01 JSR $0159
5272- 60 RTS
5273- A4 09 LDY $09
5275- B9 BC 04 LDA $04BC,Y
5278- 85 04 STA $04
527A- B9 7C 05 LDA $057C,Y
527D- 85 05 STA $05
527F- A0 27 LDY #$27
5281- B1 04 LDA ($04),Y
5283- 49 80 EOR #$80
5285- 91 04 STA ($04),Y
5287- 88 DEY
5288- D0 F7 BNE $5281
528A- B1 04 LDA ($04),Y
528C- 49 80 EOR #$80
528E- 91 04 STA ($04),Y
5290- 60 RTS
5291- 18 CLC
5292- A4 09 LDY $09
5294- B9 BC 04 LDA $04BC,Y
5297- 85 04 STA $04
5299- 69 01 ADC #$01
529B- 85 06 STA $06
529D- B9 7C 05 LDA $057C,Y
52A0- 85 05 STA $05
52A2- 69 00 ADC #$00
52A4- 85 07 STA $07
52A6- A0 00 LDY #$00
52A8- B1 04 LDA ($04),Y
52AA- 85 08 STA $08
52AC- A2 27 LDX #$27
52AE- B1 06 LDA ($06),Y
52B0- 91 04 STA ($04),Y
52B2- C8 INY
52B3- CA DEX
52B4- D0 F8 BNE $52AE
52B6- A5 08 LDA $08
52B8- 91 04 STA ($04),Y
52BA- 60 RTS
52BB- 00 BRK
52BC- 00 BRK
52BD- 00 BRK
52BE- 6E 01 41 ROR $4101
52C1- 01 0A ORA ($0A,X)
52C3- 01 07 ORA ($07,X)
52C5- 01 04 ORA ($04,X)
52C7- 01 01 ORA ($01,X)
52C9- 01 FE ORA ($FE,X)
52CB- 00 BRK
52CC- FD 00 74 SBC $7400,X
52CF- 00 BRK
52D0- 6F ???
52D1- 00 BRK
52D2- 69 00 ADC #$00
52D4- 64 ???
52D5- 00 BRK
52D6- 0C ???
52D7- 00 BRK
52D8- 76 01 ROR $01,X
52DA- 73 ???
52DB- 01 59 ORA ($59,X)
52DD- 01 56 ORA ($56,X)
52DF- 01 6A ORA ($6A,X)
52E1- 00 BRK
52E2- 67 ???
52E3- 00 BRK
52E4- 4F ???
52E5- 00 BRK
52E6- 48 PHA
52E7- 00 BRK
52E8- 08 PHP
52E9- 00 BRK
52EA- 00 BRK
52EB- 00 BRK
52EC- D2 ???
52ED- 01 00 ORA ($00,X)
52EF- 00 BRK

The JTAB begins at the bottom, and we see the self-referencing pointer $01D2 to the start of the code.

This routine has a mystery to solve. Look at:

513F- 0D 1C BF ORA $BF1C

$BF1C? Isn't that part of the Pascal operating system? (Yes!)

Using Google and the internet, I found these references:

Apple II Pascal ATTACH.pdf at ASIMOV (SPCHAR at location BF1C)
Apple II Computer Technical Information
ATTACH-BIOS Documentation for Apple II Pascal 1.1
by Barry Haynes, Apple Computer Inc. -- January 12, 1980

Somewhere in those documents you will find:

BF1C
00 Means do all special character checking
01 Means don't check for Apple screen stuff
02 Means don't check for other screen stuff

3 types of characters:
A. ctrl-A, Z, W, E, K
B. ctrl-S, F
C. ctrl-C, DLE, CR

SPCHAR bit 0 set to 1 === don't look for type A chars
SPCHAR bit 1 set to 1 === don't look for type B chars
When set, special char checking is turned OFF until reboot.

Ok, looks like we will need the following:

SPCHAR .EQU 0BF1C;

On to the next problem:

5161- B9 BC 04 LDA $04BC,Y

Using the Segment load address of $5000 to ABSOLUTIZE this address puts it at $54BC, which isn't in this procedure!

Looking back at my WIZBOOT chart, I think we have our answer:

WIZBOOT
lex Start End Order-in-File
1 0 7.0.1 50CC 50FF 2
2 6502 7.0.2 511A 52EA 3
3 6502 7.0.3 52F0 54B6 4
4 1 7.0.4 5000 50BA 1
5 6502 7.0.5 54BC 5642 5

$54BC is the start of the "code" for P070005.
Earlier I made this observation, and it seems to be true:

"The code at P070005 ($54BC) is similar to a screen table in LOL at L11E2 in SCRNDATA."

To access data in another 6502 procedure, you use the ".REF" instruction:

.REF L04BC, L057C

The JMP and JSR addresses and labels are determined in the same manner as was done with P070003.

I now Assembled and Linked P070005 and got the following errors:

Global L04BC undefined
Global L057c undefined

P070005 will define those 2 labels. P070005 is entirely data.

This is P070005 (Note the ".DEF" instructions to "externalize" those labels.):

.PROC P070005 ; P070003 USES THESE TABLES
;
.DEF L04BC, L057C
;
L54BC
L04BC
.BYTE 000,000,000,000,000,000,000,000
.BYTE 080,080,080,080,080,080,080,080
.BYTE 000,000,000,000,000,000,000,000
.BYTE 080,080,080,080,080,080,080,080
.BYTE 000,000,000,000,000,000,000,000
.BYTE 080,080,080,080,080,080,080,080
.BYTE 000,000,000,000,000,000,000,000
.BYTE 080,080,080,080,080,080,080,080
L54FC
.BYTE 028,028,028,028,028,028,028,028
.BYTE 0A8,0A8,0A8,0A8,0A8,0A8,0A8,0A8
.BYTE 028,028,028,028,028,028,028,028
.BYTE 0A8,0A8,0A8,0A8,0A8,0A8,0A8,0A8
.BYTE 028,028,028,028,028,028,028,028
.BYTE 0A8,0A8,0A8,0A8,0A8,0A8,0A8,0A8
.BYTE 028,028,028,028,028,028,028,028
.BYTE 0A8,0A8,0A8,0A8,0A8,0A8,0A8,0A8
L553C
.BYTE 050,050,050,050,050,050,050,050
.BYTE 0D0,0D0,0D0,0D0,0D0,0D0,0D0,0D0
.BYTE 050,050,050,050,050,050,050,050
.BYTE 0D0,0D0,0D0,0D0,0D0,0D0,0D0,0D0
.BYTE 050,050,050,050,050,050,050,050
.BYTE 0D0,0D0,0D0,0D0,0D0,0D0,0D0,0D0
.BYTE 050,050,050,050,050,050,050,050
.BYTE 0D0,0D0,0D0,0D0,0D0,0D0,0D0,0D0
L557C
L057C
.BYTE 020,024,028,02C,030,034,038,03C
.BYTE 020,024,028,02C,030,034,038,03C
.BYTE 021,025,029,02D,031,035,039,03D
.BYTE 021,025,029,02D,031,035,039,03D
.BYTE 022,026,02A,02E,032,036,03A,03E
.BYTE 022,026,02A,02E,032,036,03A,03E
.BYTE 023,027,02B,02F,033,037,03B,03F
.BYTE 023,027,02B,02F,033,037,03B,03F
L55BC
.BYTE 020,024,028,02C,030,034,038,03C
.BYTE 020,024,028,02C,030,034,038,03C
.BYTE 021,025,029,02D,031,035,039,03D
.BYTE 021,025,029,02D,031,035,039,03D
.BYTE 022,026,02A,02E,032,036,03A,03E
.BYTE 022,026,02A,02E,032,036,03A,03E
.BYTE 023,027,02B,02F,033,037,03B,03F
.BYTE 023,027,02B,02F,033,037,03B,03F
L55FC
.BYTE 020,024,028,02C,030,034,038,03C
.BYTE 020,024,028,02C,030,034,038,03C
.BYTE 021,025,029,02D,031,035,039,03D
.BYTE 021,025,029,02D,031,035,039,03D
.BYTE 022,026,02A,02E,032,036,03A,03E
.BYTE 022,026,02A,02E,032,036,03A,03E
.BYTE 023,027,02B,02F,033,037,03B,03F
.BYTE 023,027,02B,02F,033,037,03B,03F
;
.END

Recall also that hex numbers must begin with 0 - 9. To get them lined up I made each of them 3 digits.

Here is the final rough draft for P070002:

.PROC P070002,2 ; WITH 2 PARAMETERS PASSED INTO (FORMERLY COPYPROT)
;
.REF L04BC, L057C
;
SPCHAR .EQU 0BF1C ; SEE APPLE II COMPUTER TECHNICAL INFORMATION
;
PLA
TAX
PLA
TAY
PLA
STA 00
PLA
STA 01
PLA
STA 02
PLA
STA 03
TYA
PHA
TXA
PHA
CLC
LDA 02
ADC 00
STA 02
LDA 03
ADC 01
STA 03
LDX #00
LDA #03
ORA SPCHAR ;0BF1C ...HMMM....PART OF PASCAL SYSTEM TABLES???
STA SPCHAR ;0BF1C
L5145
L002B
LDA @02,X
CMP #0C0
BCC L5181
CMP #0FD
BCC L5152
JMP L0132 ; L524C
L5152
SEC
SBC #0C0
STA 07
LDY #02
LDA @02,Y
STA 06
DEY
LDA @02,Y
TAY
LDA L04BC,Y ; LOOKS UNRESOLVED ??? MAYBE P070005 STARTS AT $54BC
STA 04
LDA L057C,Y
STA 05
LDY 07
LDA 06
STA @04,Y
CLC
LDA 02
ADC #03
STA 02
LDA #00
ADC 03
STA 03
JMP L002B ; UNRESOLVED L5145 L51D1
L5181
TAY
LDA L04BC,Y ; ???
STA 04
LDA L057C,Y
STA 05
LDY #01
LDA @02,Y
STA 06
INY
LDA @02,Y
STA 07
INY
LDA @02,Y
STA 08
INY
LDA @02,Y
STA 09
INY
LDA @02,Y
STA 0A
CLC
LDA 02
ADC #06
STA 02
LDA 03
ADC #00
STA 03
LDY #00
LDA 06
JSR L00B7 ; UNRESOLVED L51D1
LDA 07
JSR L00B7
LDA 08
JSR L00B7
LDA 09
JSR L00B7
LDA 0A
JSR L00B7
JMP L002B ; UNRESOLVED L5145
L51D1
L00B7
STA 00
LSR 00
BCC L51E1
LDA @02,X
STA @04,Y
INC 02
BNE L51E1
INC 03
L51E1
INY
LSR 00
BCC L51F0
LDA @02,X
STA @04,Y
INC 02
BNE L51F0
INC 03
L51F0
INY
LSR 00
BCC L51FF
LDA @02,X
STA @04,Y
INC 02
BNE L51FF
INC 03
L51FF
INY
LSR 00
BCC L520E
LDA @02,X
STA @04,Y
INC 02
BNE L520E
INC 03
L520E
INY
LSR 00
BCC L521D
LDA @02,X
STA @04,Y
INC 02
BNE L521D
INC 03
L521D
INY
LSR 00
BCC L522C
LDA @02,X
STA @04,Y
INC 02
BNE L522C
INC 03
L522C
INY
LSR 00
BCC L523B
LDA @02,X
STA @04,Y
INC 02
BNE L523B
INC 03
L523B
INY
LSR 00
BCC L524A
LDA @02,X
STA @04,Y
INC 02
BNE L524A
INC 03
L524A
INY
RTS
L524C
L0132
CMP #0FE
BEQ L5255
CMP #0FD
BEQ L5264
RTS
L5255
LDA #030
STA 09
L5259
JSR L0177 ; UNRESOLVED L5291
DEC 09
BNE L5259
JSR L0177 ; UNRESOLVED
RTS
L5264
LDA #030
STA 09
L5268
JSR L0159 ; UNRESOLVED L5273
DEC 09
BNE L5268
JSR L0159 ; UNRESOLVED
RTS
L5273
L0159
LDY 09
LDA L04BC,Y ; ???
STA 04
LDA L057C,Y ; ???
STA 05
LDY #027
L5281
LDA @04,Y
EOR #080
STA @04,Y
DEY
BNE L5281
LDA @04,Y
EOR #080
STA @04,Y
RTS
L5291
L0177
CLC
LDY 09
LDA L04BC,Y ; ???
STA 04
ADC #01
STA 06
LDA L057C,Y ; ???
STA 05
ADC #00
STA 07
LDY #00
LDA @04,Y
STA 08
LDX #027
L52AE
LDA @06,Y
STA @04,Y
INY
DEX
BNE L52AE
LDA 08
STA @04,Y
RTS
;
L52BB ;
;
.END
RTS
.END

I was now able to Compile and Link all of WIZBOOT segment in STARTUP.CODE.

STARTUP.TEXT
Mainline (P070001)
CHKCOPY (P070004)
P070002.TEXT (Check keyboard (?). Accesses BF1C SPCHAR)
P070003.TEXT (Disk I/O, and uses P070005 Screen Data ptrs)
P070005.TEXT (Screen Data ptrs)

Using the Call -151 trick after running DeCompiler, I compared my new WIZBOOT segment with the original and found them to be identical. ($5000 to $
564B).

YAY! I've successfully re-enginneered the first Segment for STARTUP.CODE (SYSTEM.STARTUP)!

(Ok, there's still lots of work to do to clean up variable names, etc.)

Up next is TITLELOA, which is executed from SYSTEM.STARTUP mainline right after CHKCOPY is first called.

TommyGoog

unread,
Apr 15, 2014, 6:50:32 PM4/15/14
to

> Up next is TITLELOA, which is executed from SYSTEM.STARTUP mainline right after CHKCOPY is first called.

TITLELOA FILE: 7 SEG: 2 PROC: 1

lex start end order hierarchy
1 1 7.2.1 531E 5378 8 7.2.1
2 2 7.2.2 5000 500C 1 7.2.2
3 2 7.2.3 5018 504F 2 7.2.3
4 2 7.2.4 50D8 52BD 6 7.2.4
5 3 7.2.5 505C 5077 3 7.2.5
6 3 7.2.6 5086 50A2 4 7.2.6
7 3 7.2.7 50AE 50CC 5 7.2.7
8 2 7.2.8 52DE 530C 7 7.2.8

STARTUP.TEXT
$I WIZUTILB
$I WIZUTILC
$I TITLELOA
$I OPTIONS

Using DeCompiler on Wiz1 Boot diskette:

JTAB FOR SUBROUTINE 1:
DATA SIZE: 9222
PARAM SIZE: 0
EXIT AT: 5378
ENTER AT: 531E
PROC NUMBER: 1
LEXICAL LEVEL: 1
531E D7 NOP. NOP
531F A6 08 57 49 5A 41 52 44 52 59
WIZARDRY
LSA. PUSH #(PC+1) POINTER TO THE STRING
5329 CD 1C 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 1C
532C CE 08 CLP. CALL CHILD PROCEDURE: 08
532E C6 02 LLA. PUSH #MP.02
5330 9E 20 MRK. MARK HEAP. (TOS)^ := NP
5332 C7 00 40 LDCI. PUSH #4000
5335 CC 92 03 STL. MP.1203 := (TOS)
5338 C6 92 03 LLA. PUSH #MP.1203
533B 9E 21 RLS. RELEASE HEAP. NP := (TOS)^
533D C7 FD 00 LDCI. PUSH #00FD
5340 CC 01 STL. MP.01 := (TOS)
5342 CE 04 CLP. CALL CHILD PROCEDURE: 04
5344 D8 SLDL. PUSH MP.01
5345 C7 FD 00 LDCI. PUSH #00FD
5348 C3 EQUI. PUSH ((TOS-1) = (TOS))
5349 A1 07 UJP. IF NOT (TOS) THEN JUMP TO 5352
534B C7 FE 00 LDCI. PUSH #00FE
534E CC 01 STL. MP.01 := (TOS)
5350 B9 05 UJP. JUMP TO 5357
5352 C7 FD 00 LDCI. PUSH #00FD
5355 CC 01 STL. MP.01 := (TOS)
5357 C7 AC 3F LDCI. PUSH #3FAC
535A 91 NGI. PUSH -(TOS) (2'S COMP)
535B CE 02 CLP. CALL CHILD PROCEDURE: 02
535D C7 AF 3F LDCI. PUSH #3FAF
5360 91 NGI. PUSH -(TOS) (2'S COMP)
5361 CE 02 CLP. CALL CHILD PROCEDURE: 02
5363 00 SLDC. PUSH #0000
5364 00 SLDC. PUSH #0000
5365 CE 03 CLP. CALL CHILD PROCEDURE: 03
5367 A1 F6 UJP. IF NOT (TOS) THEN JUMP TO 5342
5369 B6 02 03 LOD. PUSH ACTREC(-02).03
536C 20 SLDC. PUSH #0020
536D 00 SLDC. PUSH #0000
536E CD 00 11 CXP. CALL EXTERNAL PROCEDURE: 11 IN SEGMENT: 00
5371 01 SLDC. PUSH #0001
5372 9E 26 CHECK VOL#
5374 C6 02 LLA. PUSH #MP.02
5376 9E 21 RLS. RELEASE HEAP. NP := (TOS)^
5378 AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.
537A 38 SLDC. PUSH #0038
537B 00 SLDC. PUSH #0000


The first pcode is:

531F A6 08 57 49 5A 41 52 44 52 59
WIZARDRY
LSA. PUSH #(PC+1) POINTER TO THE STRING
5329 CD 1C 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 1C

Recall that "SEGMENT: 1C" is SETCHAIN in the SYSTEM.LIBRARY.

So this converts to:

SETCHAIN( 'WIZARDRY');

Next code is:

532C CE 08 CLP. CALL CHILD PROCEDURE: 08

This converts to:
P070208;

Oh yeah, lets set up dummy procedures for TITLELOA in the hierarchy that I have in the table earlier.

Next I will compile this little bit to make sure we are on the right path. I will then look at it with the DeCompiler.

Do I need to Link in the 6502 code? Can I put those 6502 procedures in SYSTEM.LIBRARY and then always use SYSTEM.LIBRARY instead of knowing the names and order to Link files in? At this time, the 6502 procedures don't seem to be needed for what I am looking at.

Next up:

532E C6 02 LLA. PUSH #MP.02
5330 9E 20 MRK. MARK HEAP. (TOS)^ := NP
5332 C7 00 40 LDCI. PUSH #4000
5335 CC 92 03 STL. MP.1203 := (TOS)
5338 C6 92 03 LLA. PUSH #MP.1203
533B 9E 21 RLS. RELEASE HEAP. NP := (TOS)^

$4000 is the start of Hi-Res page 2, just above page 1. I think this code is protecting Hi-res Page 1 from being used for heap space. I will have a lot more to say about memory management and the heap when looking at the Wizardry main code.

The Pascal code is:

MARK( MP02);
MP1203 := 16384; (* $4000 *)
RELEASE( MP1203);

MP1203 indicates this routine has a lot of memory used for VARiables.

For now I'll try this:

MP01 : INTEGER
MP02 : ^INTEGER;
MP03 : ARRAY[ 1..3000] OF INTEGER;
MP1203 : ^INTEGER;

That failed because MP02 is used as 2 different variable TYPEs: INTEGER and POINTER.

Oh yeah! Time to relearn VARIANT RECORDs.

BYTE = PACKED ARRAY [0..1] OF 0..255;
MAGIC = RECORD CASE BOOLEAN OF
FALSE : (I : INTEGER);
TRUE : (P : ^BYTE);
END;

Here is the completed rough draft:

SEGMENT PROCEDURE TITLELOA;
TYPE

BYTE = PACKED ARRAY [ 0..1] OF 0..255;

MAGIC = RECORD CASE BOOLEAN OF
FALSE : (I : INTEGER);
TRUE : (P : ^BYTE);
END;

VAR

MP01 : INTEGER;
MP02 : ^INTEGER;
MP03 : ARRAY[ 1..4608] OF INTEGER;
MP1203 : MAGIC;

PROCEDURE P070202( MP01 : INTEGER);
BEGIN
END;

FUNCTION P070203 : BOOLEAN;
BEGIN
END;

PROCEDURE P070204;

PROCEDURE P070205;
BEGIN
END;

PROCEDURE P070206;
BEGIN
END;

PROCEDURE P070207;
BEGIN
END;

BEGIN (* P070204 *)
END;

PROCEDURE P070208;
BEGIN
END;

BEGIN (* P070201 MAINLINE *)

SETCHAIN( 'WIZARDRY');
P070208;
MARK( MP02);
MP1203.I := 16384;
RELEASE( MP1203.P);
MP01 := 253;
REPEAT

P070204;
IF MP01 = 253 THEN
BEGIN
MP01 := 254
END
ELSE
BEGIN
MP01 := 253
END;
P070202( -16300);
P070202( -16303);

UNTIL P070203;
WRITE( CHR( 32));
UNITCLEAR( 1);
RELEASE( MP02);
END;

-16300 and -16303
These are soft switches on the Apple II.
-16300 is $C054 and displays primary page 1.
-16303 is $C051 and displays TEXT mode.

How do I know UNITCLEAR( 1) is generates " CHECK VOL#"?

I have a table that I've created to help me with "SEGMENT: 00" and other system calls. I created this table by looking at examples of other Pascal code and using the DeCompiler.

READ() Procedure: 10
EOLN() Procedure: 0B
WRITE() Procedure: 11 WRITE( CHR( 13))
WRITE() Procedure: 13 WRITE( Astr : 20);
WRITELN() Procedure: 13 and 16
WRITELN Procedure: 16
Write() Procedure: 0D WRITE( Anum : 2);
GOTOXY() Procedure: 1D
COPY() Procedure: 19
CONCAT Procedure: 17
RESET() Procedure: 05

VAR x : FILE; Procedure: 03 Declaring the file generates 2 calls.
"03" at the start of the procedure.
The parameter passed to 03 is the
file "type" (REAL, INTEGER, untyped, ...)
VAR x : FILE; Precedure: 06 "06" at the end of the procedure.

UNITREAD() READ FROM VOL# (* DEVICE, BUFF, CNT, BLOCK #, MODE *)
UNITWRITE() WRITE VOL #
UNITCLEAR( 1) CHECK VOL#

USE CHAINSTUFF Procedure: 01 in Segment: 1C
SETCHAIN() Procedure: 02 in Segment: 1C

Note, this is not a completed table yet. As I encounter more "UNKNOWNs" I will need to update it.

UNITCLEAR( 1) flushes the typeahead buffer for CONSOLE: and resets horizontal scrolling to full left.

Before every FUNCTION() call in Pascal, the pcode generates PUSH #0 and PUSH #0.



P070201 is next:

FILE: 7 SEG: 2 PROC: 2

JTAB FOR SUBROUTINE 2:
DATA SIZE: 0
PARAM SIZE: 2
EXIT AT: 500C
ENTER AT: 5000
PROC NUMBER: 2
LEXICAL LEVEL: 2
5000 D8 SLDL. PUSH MP.01
5001 B8 01 92 03 STR. ACTREC(-01).1203 := TOS
5005 B6 01 92 03 LOD. PUSH ACTREC(-01).1203
5009 00 SLDC. PUSH #0000
500A 00 SLDC. PUSH #0000
500B BF STB. (TOS-2)^.(TOS-1) := TOS BYTE
500C AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.

"PARAM SIZE: 2" means the parameter occupies 2 bytes. This could be an INTEGER variable.

When looking at the DeCompiled code, when no parameters are passed, then the first variable declared is referred to as MP.01. When there are parameters, this changes. Now the first parameter is named MP.01 and the declared variables follow that one.

The LEXICAL LEVEL is 2, so this is "nested" beneath TITLELOA.

The ACTREC(-01) refers to the most recent activation record before this procedure is called. ACTREC(-01).1203 therefore refers to a declared variable in TITLELOA.

It is a PROCEDURE an not a FUNCTION, because RNP ($AD) has 00 as its parameter.

PROCEDURE P070202( MP01 : INTEGER);
BEGIN
MP1203 := MP01;
MP1203^ hey MP1203 is an INTEGER, not a pointer!
END;

Hmmm, MP1203 cannot be an INTEGER and a POINTER.
Look at the definition for MP1203. It is a variant record.
Let's try the following:

SEGMENT PROCEDURE TITLELOA;
VAR
MP1203 : MAGIC;

PROCEDURE P070202( MP01 : INTEGER);
BEGIN
MP1203.I := MP01;
MP1203.P^[ 0] := 0
END;

Side rant:

Whomever invented "E" for "EDIT" and "E" for "EXTENDED DIR" should be shot. How many times have I entered the EDITOR when I wanted an EXTENDED DIR? Maybe I should start using "L" for "DIR".

But Nooooo! "L" is for "LINKER"

Continue with P070203 in TITLELOA.

FILE: 7 SEG: 2 PROC: 3

JTAB FOR SUBROUTINE 3:
DATA SIZE: 0
PARAM SIZE: 4
EXIT AT: 504F
ENTER AT: 5018
PROC NUMBER: 3
LEXICAL LEVEL: 2
5018 01 SLDC. PUSH #0001
5019 CC 01 STL. MP.01 := (TOS)
501B C7 00 40 LDCI. PUSH #4000
501E 91 NGI. PUSH -(TOS) (2'S COMP)
501F B8 01 92 03 STR. ACTREC(-01).1203 := TOS
5023 B6 01 92 03 LOD. PUSH ACTREC(-01).1203
5027 00 SLDC. PUSH #0000
5028 BE LDB. PUSH #00, PUSH (TOS-1)^.TOS BYTE
5029 7F SLDC. PUSH #007F
502A C5 GRTI. PUSH ((TOS-1) > (TOS))
502B A1 04 UJP. IF NOT (TOS) THEN JUMP TO 5031
502D 08 SLDC. PUSH #0008
502E 03 SLDC. PUSH #0003
502F 9E 04 EXIT. EXIT FROM PROCEDURE. (TOS)=PROC# (TOS-1)=SEG#
5031 C7 E8 40 LDCI. PUSH #40E8
5034 91 NGI. PUSH -(TOS) (2'S COMP)
5035 B8 01 92 03 STR. ACTREC(-01).1203 := TOS
5039 B6 01 92 03 LOD. PUSH ACTREC(-01).1203
503D 00 SLDC. PUSH #0000
503E BE LDB. PUSH #00, PUSH (TOS-1)^.TOS BYTE
503F B6 01 92 03 LOD. PUSH ACTREC(-01).1203
5043 01 SLDC. PUSH #0001
5044 BE LDB. PUSH #00, PUSH (TOS-1)^.TOS BYTE
5045 CB NEQI. PUSH ((TOS-1) <> (TOS))
5046 A1 04 UJP. IF NOT (TOS) THEN JUMP TO 504C
5048 08 SLDC. PUSH #0008
5049 03 SLDC. PUSH #0003
504A 9E 04 EXIT. EXIT FROM PROCEDURE. (TOS)=PROC# (TOS-1)=SEG#
504C 00 SLDC. PUSH #0000
504D CC 01 STL. MP.01 := (TOS)
504F AD 01 RNP. RETURN FROM NON-BASE PROCEDURE.
5051 00 SLDC. PUSH #0000

PARAM SIZE indicates 2 parameters.
RNP with AD 01 means this is a FUNCTION
MP.01 is value of function returned.
lex level is 2, so same level as P070202.
I already have this returning BOOLEAN. Why? Because of P070201 Mainline with "UNTIL P070203; 0 = FALSE and 1 = TRUE I think.
DATA SIZE 0 means no VARs here.
$4000 is 16384
IF MP1203.P^[0] > #$7F THEN #$7F === 127
EXIT ( SEG 8, PROC 3); SEG 8 PROC 3 === P070203
MP1203.i := -16616 #$40E8 === 16616

I'm not sure, but I think the code is like the following:
IF MP1203.P^[ 0] <> MP1203.P^[ 1] THEN
EXIT (P070203);
P070203 := FALSE;

Well let's throw it into the editor and try to compile it.

941 8 3:D 3 FUNCTION P070203 : BOOLEAN;
942 8 3:0 0 BEGIN
943 8 3:1 0 P070203 := TRUE;
944 8 3:1 3 MP1203.I := -16384; (* -$4000 *)
945 8 3:1 11 IF MP1203.P^[0] > 127 THEN
946 8 3:2 21 EXIT( P070203);
947 8 3:1 25 MP1203.I := -16616;
948 8 3:1 33 IF MP1203.P^[ 0] <> MP1203.P^[ 1] THEN
949 8 3:2 48 EXIT( P070203);
950 8 3:1 52 P070203 := FALSE
951 8 3:0 52 END;

Wow! That actually compiled. I wasn't really sure if the syntax was correct, but apparently it is.

Double Wow! The DeCompiler says it produced the proper code!

Something about a million monkeys and Shakespeare comes to mind.

I have no idea what this code is doing.
$4000 is secondary hi-res screen location.
$40E8 is also on that screen.

Lol (laughing!) -16384 is $C000 (-$4000), so it is the Keyboard Data Latch.

-$4000 -16384 $C000 Keyboard Data
-$40E8 -16616 $BF18 Pascal System stuff (?) SYSCOM (?)
-16368 $C010 Clear Keyboard Strobe

$BF18 (See ATTACH.PDF)

"1. The type ahead buffer is located at $03B1 hex and is $4E hex in length. It is implemented with a read pointer (RPTR at BF18 hex) and a write pointer WPTR at $BF19 hex). At CONSOLE: init time, these should both be set to 0. When a character is detected by CONCK, the WPTR is incremented then compared with $4E. If it is equal to $4E, it is set to $0 (this is a circular buffer). Then the WPTR is compared with RPTR and if they are equal the buffer is full. If the buffer is not full, the character is stored at $03B1+the value in WPTR.

"When removing a character from the type ahead buffer, use the following sequence. Compare the RPTR with WPTR and if they are equal, the buffer is empty and you must wait until a character is available from the keyboard. If they are not equal, increment the RPTR and compair it to $4E. If it equals $4E, set it to $0. Now get the character from location $03B1+the value in RPTR."

(Note the interesting spelling of "compair".)

This routine, P070203 is checking to see if a keystroke has been made, or if it was made and already put into the Pascal keyboard input buffer. Returns TRUE if key was pressed.

This mention of the keyboard input buffer at $3B1 is something I discovered the hard way back in 1990 or 1991.

BEGIN VERY VERY LONG STORY:

I started the Wizardry III journey by working my way through the bootstrap code for the Wizardry III boot diskette. I first copied as much of the diskette that would copy using COPYII+. Next I edited Track 0, Sector 0, and put a BRK instruction (byte value of 0) at the second byte in the sector. This sector gets loaded at $800, and $801 is the first instruction executed after it is loaded. By doing this, I can boot the diskette and it will drop me into the Apple monitor with the code at $800. I can then change the value at $801 and use the monitor commands to begin my bootstrap investigation.

The code at $800 - $8FF will load another bunch of sectors from the diskette and then start to execute that code as the next part of the bootstrap process. So just after those sectors have been read from the diskette, and before executing that code, I find the place on Track 0, Sector 0, and change the instruction to a BRK (and also restore the second byte in this sector to its original value). Now the diskette can be booted and code will be loaded at $800 - $8FF, and then the next chunk of code gets loaded to where it goes, and then the Apple puts me in the monitor so I can examine memory, etc.

Ok, this worked great for awhile, and I got quite far, but somewhere down the road instead of dropping me into the Apple monitor, the machine would just keep rebooting. Ah! Of course! The bytes at $3F2, $3F3, and $3F4 were being cleared to 0 at some point, so the handling of the BRK instruction by the monitor would think the machine was just turned on and go through its boot sequence. Ok, so I managed to patch the code on the diskette so that those bytes at #3F2 - #3F4 were not cleared. And eventually I got a long way into the bootstrap, and into the execution of the Pascal system, and the loading of SYSTEM.STARTUP, and execution of the Wizardry program.

But I was just getting to the hard part.

One way of continuing this process once you get into the Pascal pcode interpreter is to modify the pcode you are interested in. But you cannot put a "BRK" instruction. One way is to put a "HALT" instruction into the pcode where you want it to stop. But you also need to modify the Pascal handler for the HALT instruction by putting a BRK instruction there. Ok, I did all that.

During the execution of SYSTEM.STARTUP, you press a key and it stops the title screen from displaying and displays the first menu to the user. And since I had placed the HALT instruction at the proper place, it put me into the Apples monitor as expected and I could poke around the Pascal Heap stack, etc.

Now sometimes when I was booting this modified diskette, I would press and hold a key down to get to my inserted HALT instruction. But something weird happened. Instead of putting me into the monitor, it rebooted! Ok, so just press one key and then everything would work fine.

And this was ok for awhile. But then after executing a lot of code I wanted to HALT the program at the point where I was just going to enter the maze. And now the HALT instruction caused the Apple to reboot every time. Now obviously there were many keystrokes entered from the time of first booting until actually entering the maze.

And to make a long story short, the reason the Apple was always rebooting is because the keyboard input buffer which starts at #3B1 was filling up and clobbering (as it should) the bytes $3F2, $3F3, $3F4.

Was I at a dead end? No, I simply modified the Pascal runtime system to think the input buffer was shorter than #$4E, so that it would not clobber those magic power on bytes.

Please let me know if you enjoyed this "detour" from our current journey.

END OF VERY VERY LONG STORY

Up next is P070208.

awanderin

unread,
Apr 16, 2014, 12:05:23 AM4/16/14
to

I'm reading every post! Keep them coming, they are quite interesting!
Thanks!


--
Jerry awanderin at gmail dot com

qkumba

unread,
Apr 16, 2014, 12:51:01 AM4/16/14
to
copyprot:

0000-009D - nibble check #1
looks like a patch 009E from 84 to 00 will defeat it.

00A2-011B - nibble check #2
looks like a patch 0107 from F0 to B0 will defeat it.

011B - 01AA - move the drive head (seek track). standard routine.

511A... - looks like LZW decompression routine.

> LDA L04BC,Y ; LOOKS UNRESOLVED ??? MAYBE P070005 STARTS AT $54BC

this is part of a pre-computed line table for the graphics screen ($54BC, as you have it)
--

I am enjoying these posts very much.
Please let me know if I can be of assistance with understanding any particular part of the disassembly.

TommyGoog

unread,
Apr 17, 2014, 2:37:35 AM4/17/14
to
Thank you Jerry (awanderin) and qkumba (and Vladimir Ivanov and Rob Craig and sicklittlemonkey) for your comments. It's good to see I have at least a small audience and not an empty classroom :)

I hope you've all had a chance to read my earlier thread regarding Wizardry III (Legacy of Llylgamyn). There was one thing I never figured out with that decompiling effort. I could never get the order of the PROCEDURES (and FUNCTIONS) to be in the same order in the final ".CODE" file as they did. Normally the PROCEDUREs are placed in the file in the order in which their "END;" statement is compiled. I don't know if there is a Compiler (or Linker) option I am not aware of that could affect that. My guess 2 years ago (and still today) is that they may have had a specialized Linker or perhaps their own "incremental" Linker to put the pieces into the final ".CODE" file. If you'd like to solve a problem I could not, that would be a good one! Note the order for LOL WIZUTIL.CODE was correct, but the order for WIZARDRY.CODE was not. I suspect I may run into this with Wizardry I also.

As far as my understanding and figuring out the code for Wizardry I, if something comes up that I cannot figure out, I'll ask for help or explain what I have. Sometimes I'll leave my early comments like "LOOKS UNRESOLVED ???" in the code even after I've figured it out. It sort of documents what I was thinking during this work-in-progress. At the very end, in the final cleanup phase, I usually remove things might be confusing to the first time reader.

Regarding defeating the "nibble checks" in the code, another way is to just NOP out the call to the copy protection code (provided no residual information is needed), or to just ignore the result of CHKCOPY after the call.

What's that you say? Pascal has a NOP instruction? If so, how do you put a NOP into Pascal code? See p. 284 of Apple Pascal Operating System. Opcode 215 ($D7) is a NOP. In this instance, CHKCOPY( P070004) saves information at SERIAL, so we must at least make the call to CHKCOPY. If you look at the "IF MP05 THEN EXIT( CHKCOPY);" you will see that we can modify this instruction to always take the "EXIT" instead of getting to the "HALT" instruction.

50AB A1 04       UJP.   IF NOT (TOS) THEN JUMP TO 50B1 We can NOP the 50AB and 50AC instructions and the EXIT will always be taken. These are located on the original diskette at: TRACK $22, SECTOR $7, at address $AB and $AC. How did I determine that? From DeCompiler, FILE: 7 SEG: 0 PROC: 4 has P070004 starting at $5000 (what luck! beginning of segment!). The DeCompiler also shows FILE: 7 starting at Track 34 Sector 7 (DOS formatting,and the "34" is a decimal number not hex like it really should be). Use COPYII+ to read TRACK $22, SECTOR $7, move down to AB and change 2 consecutive bytes (from A1 and 04) to D7 and D7.

If you really want to be clever, you could change the UJP instruction to jump to 50AD instead of jumping to 50B1. I think changing 50AC from 04 to 00 will accomplish this. So just a 1 byte change to defeat the copy protection scheme, and it will be obvious to anyone looking at the modified code that this is what was done!

I haven't really begun analyzing the code for LOL yet. Right now its just "get Pascal source to compile to the pcode". Later I will spend more time trying to see what the code does when fixing the names for variables and procedures.

It takes a lot of time to put these postings together which detracts from my time to do the actual work:) I had almost gotten to the point of beginning to post minimal information, but perhaps some of you would still like to see what I'm doing. At some point it will become quite repetitive. After all, there are over 500 PROCEDUREs in this effort.

I've actually been working a bit further ahead than what I've posted. On April 15 I already completed the entire Pascal (and assembly language) code to compile and get the pcode for all of SYSTEM.STARTUP. I think it actually helps to do the work the first time, then get away from it for a few days, and then come back to it and then try to re-figure out what I did so I can explain it to others.

Once again, thanks for your comments and don't be afraid to ask questions.

Tommy





TommyGoog

unread,
Apr 18, 2014, 5:44:38 PM4/18/14
to

> Up next is P070208.

Here is the pcode we want:

FILE: 7 SEG: 2 PROC: 8

JTAB FOR SUBROUTINE 8:
DATA SIZE: 80
PARAM SIZE: 0
EXIT AT: 530C
ENTER AT: 52DE
PROC NUMBER: 8
LEXICAL LEVEL: 2
52DE C6 01 LLA. PUSH #MP.01
52E0 C6 81 2D LLA. PUSH #MP.012D
52E3 C7 01 00 LDCI. PUSH #0001
52E6 91 NGI. PUSH -(TOS) (2'S COMP)
52E7 CD 00 03 CXP. CALL EXTERNAL PROCEDURE: 03 IN SEGMENT: 00
52EA C6 01 LLA. PUSH #MP.01
52EC D7 NOP. NOP
52ED A6 02 57 54
WT
LSA. PUSH #(PC+1) POINTER TO THE STRING
52F1 01 SLDC. PUSH #0001
52F2 00 SLDC. PUSH #0000
52F3 CD 00 05 CXP. CALL EXTERNAL PROCEDURE: 05 IN SEGMENT: 00
52F6 C6 01 LLA. PUSH #MP.01
52F8 B2 01 03 LDA. PUSH #ACTREC(-01).03
52FB 00 SLDC. PUSH #0000
52FC 12 SLDC. PUSH #0012
52FD 00 SLDC. PUSH #0000
52FE 01 SLDC. PUSH #0001
52FF 00 SLDC. PUSH #0000
5300 00 SLDC. PUSH #0000
5301 CD 00 1C CXP. CALL EXTERNAL PROCEDURE: 1C IN SEGMENT: 00
5304 AB 04 SRO. BASE.04 := (TOS)
5306 C6 01 LLA. PUSH #MP.01
5308 00 SLDC. PUSH #0000
5309 CD 00 06 CXP. CALL EXTERNAL PROCEDURE: 06 IN SEGMENT: 00
530C C6 01 LLA. PUSH #MP.01
530E 00 SLDC. PUSH #0000
530F CD 00 06 CXP. CALL EXTERNAL PROCEDURE: 06 IN SEGMENT: 00
5312 AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.


WIZBOOT calls TITLELOA, and TITLELOA then calls P070208 right away.

It is a procedure (see RNP instruction) with no parameters (PARAM SIZE: 0).

I'm confused by the procedure calls in this routine. I'm not familiar with:

EXTERNAL PROCEDURE: 03 in SEGMENT: 00
EXTERNAL PROCEDURE: 05 in SEGMENT: 00
EXTERNAL PROCEDURE: 1C in SEGMENT: 00
EXTERNAL PROCEDURE: 06 in SEGMENT: 00

Segment 00 is part of the Pascal system's standard routines.

In LOL for SYSTEM.STARTUP (something I have not re-engineered into Pascal) I notice there is a CALL EXTERNAL PROCEDURE: 05 in SEGMENT: 00. One of its parameters is "picture.bits".

I see "WT" in Wiz1 as input to PROCEDURE: 05. It would seem "PROCEDURE: 05" has something to do with files. I never encountered "PROCEDURE: 05 in SEGMENT: 00" in the LOL re-engineering.

Time for a little testing.

Here is the test program:

PROGRAM TEST;
VAR F: FILE OF CHAR;

BEGIN
RESET( F)
END.

Here is the pcode:

JTAB FOR SUBROUTINE 1:
DATA SIZE: 602
PARAM SIZE: 4
EXIT AT: 5015
ENTER AT: 5000
PROC NUMBER: 1
LEXICAL LEVEL: 0
5000 D7 NOP. NOP
5001 D7 NOP. NOP
5002 A5 03 LA0. PUSH #BASE.03
5004 A5 81 2F LA0. PUSH #BASE.012F
5007 C7 02 00 LDCI. PUSH #0002
500A 91 NGI. PUSH -(TOS) (2'S COMP)
500B CD 00 03 CXP. CALL EXTERNAL PROCEDURE: 03 IN SEGMENT: 00
500E A5 03 LA0. PUSH #BASE.03
5010 CD 00 04 CXP. CALL EXTERNAL PROCEDURE: 04 IN SEGMENT: 00
5013 9E 00 AN UNKNOWN STANDARD PROCEDURE ?!?!
5015 A5 03 LA0. PUSH #BASE.03
5017 00 SLDC. PUSH #0000
5018 CD 00 06 CXP. CALL EXTERNAL PROCEDURE: 06 IN SEGMENT: 00
501B C1 00 RBP. RETURN FROM BASE PROCEDURE.
501D 00 SLDC. PUSH #0000


Well, I didn't expect that much pcode from such little Pascal code!

We got a "PROCEDURE: 03" and "PROCEDURE: 06", but no PROCEDURE: 05.

Let's try another test. I will add all the compiler options that LOL had (and Wiz1 too), and try with no code, and try putting (INPUT, OUTPUT) in the program header. (I later learned that putting INPUT and OUTPUT in the header for Apple Pascal programs does nothing.)

Program:
(*$S++*)
(*$R-*)
(*$I-*)
(*$V-*)

PROGRAM TEST( INPUT, OUTPUT);

VAR FILE1 : FILE OF INTEGER;

BEGIN
END.

pcode:

DATA SIZE: 602
PARAM SIZE: 4
EXIT AT: 500B
ENTER AT: 5000
PROC NUMBER: 1
LEXICAL LEVEL: 0
5000 D7 NOP. NOP
5001 D7 NOP. NOP
5002 A5 03 LA0. PUSH #BASE.03
5004 A5 81 2F LA0. PUSH #BASE.012F
5007 01 SLDC. PUSH #0001
5008 CD 00 03 CXP. CALL EXTERNAL PROCEDURE: 03 IN SEGMENT: 00
500B A5 03 LA0. PUSH #BASE.03
500D 00 SLDC. PUSH #0000
500E CD 00 06 CXP. CALL EXTERNAL PROCEDURE: 06 IN SEGMENT: 00
5011 C1 00 RBP. RETURN FROM BASE PROCEDURE.
5013 00 SLDC. PUSH #0000

Another big surprise! With no Pascal instructions, there was a bunch of pcode generated. This is coming from the " VAR FILE1" declaration!

Ok, looks like declaring a file in the VAR section generates a call to "PROCEDURE: 03" at the beginning of the procedure, and a "PROCEDURE: 06" at the end. Also notice the input to "PROCEDURE: 03". With "FILE OF CHAR" it was -2, but with "FILE OF INTEGER" it is +1.

We want the input to 03 to be "-1". Time to experiment again. I tried all the following:

FILE OF INTEGER 0001
FILE OF REAL 0002
FILE OF CHAR -0002
FILE OF BOOLEAN 0001
FILE OF INTERACTIVE 012D
FILE OF STRING 0029
FILE OF TEXT 012D

PACKED FILE OF xxxx didn't make any difference

It sometimes takes a lot of energy to re-engineer 1 freaking simple line of code. You can quote me on that!

VAR FILE1 : FILE; (* -0001 *)

Removing the "type" from FILE1 gives us -1 which is what we want!

With a little more experimenting I found how to generate PROCEDURE: 05

RESET( FILE1, 'WT');

This next chunk of pcode looks like a call to BLOCKREAD()

52F6 C6 01 LLA. PUSH #MP.01
52F8 B2 01 03 LDA. PUSH #ACTREC(-01).03
52FB 00 SLDC. PUSH #0000
52FC 12 SLDC. PUSH #0012
52FD 00 SLDC. PUSH #0000
52FE 01 SLDC. PUSH #0001
52FF 00 SLDC. PUSH #0000
5300 00 SLDC. PUSH #0000
5301 CD 00 1C CXP. CALL EXTERNAL PROCEDURE: 1C IN SEGMENT: 00
5304 AB 04 SRO. BASE.04 := (TOS)

BLOCKREAD() is a function that returns a value.
First parameter is the declared filename.
Second parameter is a buffer.

Here #ACTREC(-1).03 refers to the parent procedure that called P070208, and it is referring to P070201 MP03.

Right now, MP03 in P070208 is defined as ARRAY[ 1..4608] OF INTEGER.
I'm not sure if all of that is for MP03, but it makes sense that it is a buffer.

Note, if P070208 had a variable named MP03, then I would need to change the name MP03 in P070201 or MP03 in P070208.

This next chunk looks like CLOSE( FILE1);

5306 C6 01 LLA. PUSH #MP.01
5308 00 SLDC. PUSH #0000
5309 CD 00 06 CXP. CALL EXTERNAL PROCEDURE: 06 IN SEGMENT: 00

Note, this sequence appears twice in the code we want; the second one is because of the declaration of the FILE1.

BASE04 is the name I gave to the variable in LOL that generates pcode with BASE.04. (Actually most variables that I re-engineer start out something like BASE04.) I left that variable as the final name because its real name was probably something like "TEMP". It had many uses in LOL. And also there were a few bugs associated with it, where I think the authors used the wrong variable name in a couple places associated with "TEMP" (or BASE04, or whatever they called it.)

Hmmm, I tried to use BASE04, but now realize I had already removed it. So this means the variable currently defined as RANDNUM is BASE.04. Hmmmm. Its likely that RANDNUM is not the correct name for BASE.04.

To get things to compile right now, I will use the name RANDNUM in P070208.

I think I may have been wrong about removing BASE04 and not removing RANDNUM earlier.

I think there was a bug I discovered in LOL where RANDNUM was never initialized. Maybe they removed this code and forgot to initialize RANDNUM in LOL (?)


After a little trial and error, I have the final (rough draft) version:

970 8 8:D 1 PROCEDURE P070208;
971 8 8:D 1
972 8 8:D 1 VAR
973 8 8:D 1 FILE1 : FILE; (* UNTYPED FILE *)
974 8 8:D 41
975 8 8:D 41
976 8 8:0 0 BEGIN
977 8 8:1 0 RESET( FILE1, 'WT');
978 8 8:1 24 RANDNUM := BLOCKREAD( FILE1, MP03, 18, 0);
979 8 8:1 40 CLOSE( FILE1)
980 8 8:0 46 END;

Note, 18 x 512 = 4608. Looks like MP03 is already defined with the correct size.

P070204 is next. It has 3 child procedures: P070205, P070206, P070207.

Here is the pcode we want:

FILE: 7 SEG: 2 PROC: 4

JTAB FOR SUBROUTINE 4:
DATA SIZE: 14
PARAM SIZE: 0
EXIT AT: 52BD
ENTER AT: 50D8
PROC NUMBER: 4
LEXICAL LEVEL: 2
50D8 B2 01 03 LDA. PUSH #ACTREC(-01).03
50DB 00 SLDC. PUSH #0000
50DC A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
50DE B2 01 03 LDA. PUSH #ACTREC(-01).03
50E1 08 SLDC. PUSH #0008
50E2 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
50E4 F8 SIND. PUSH (TOS)^.0
50E5 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
50E8 C7 00 20 LDCI. PUSH #2000
50EB B8 01 92 03 STR. ACTREC(-01).1203 := TOS
50EF B6 01 92 03 LOD. PUSH ACTREC(-01).1203
50F3 00 SLDC. PUSH #0000
50F4 C7 00 20 LDCI. PUSH #2000
50F7 00 SLDC. PUSH #0000
50F8 9E 0A FLC. FILLCHAR (DST+IDX,LEN,CHR)
50FA B6 03 03 LOD. PUSH ACTREC(-03).03
50FD 0C SLDC. PUSH #000C
50FE 00 SLDC. PUSH #0000
50FF CD 00 11 CXP. CALL EXTERNAL PROCEDURE: 11 IN SEGMENT: 00
5102 0C SLDC. PUSH #000C
5103 0A SLDC. PUSH #000A
5104 CD 00 1D CXP. CALL EXTERNAL PROCEDURE: 1D IN SEGMENT: 00
5107 B6 03 03 LOD. PUSH ACTREC(-03).03
510A D7 NOP. NOP
510B A6 10 50 52 45 50 41 52 45 20 59 4F 55 52 53 45 4C 46
PREPARE YOURSELF
LSA. PUSH #(PC+1) POINTER TO THE STRING
511D 00 SLDC. PUSH #0000
511E CD 00 13 CXP. CALL EXTERNAL PROCEDURE: 13 IN SEGMENT: 00
5121 C7 96 00 LDCI. PUSH #0096
5124 CE 05 CLP. CALL CHILD PROCEDURE: 05
5126 0C SLDC. PUSH #000C
5127 0C SLDC. PUSH #000C
5128 CD 00 1D CXP. CALL EXTERNAL PROCEDURE: 1D IN SEGMENT: 00
512B B6 03 03 LOD. PUSH ACTREC(-03).03
512E D7 NOP. NOP
512F A6 10 46 4F 52 20 54 48 45 20 55 4C 54 49 4D 41 54 45
FOR THE ULTIMATE
LSA. PUSH #(PC+1) POINTER TO THE STRING
5141 00 SLDC. PUSH #0000
5142 CD 00 13 CXP. CALL EXTERNAL PROCEDURE: 13 IN SEGMENT: 00
5145 C7 96 00 LDCI. PUSH #0096
5148 CE 05 CLP. CALL CHILD PROCEDURE: 05
514A 0C SLDC. PUSH #000C
514B 0E SLDC. PUSH #000E
514C CD 00 1D CXP. CALL EXTERNAL PROCEDURE: 1D IN SEGMENT: 00
514F B6 03 03 LOD. PUSH ACTREC(-03).03
5152 D7 NOP. NOP
5153 A6 10 49 4E 20 46 41 4E 54 41 53 59 20 47 41 4D 45 53
IN FANTASY GAMES
LSA. PUSH #(PC+1) POINTER TO THE STRING
5165 00 SLDC. PUSH #0000
5166 CD 00 13 CXP. CALL EXTERNAL PROCEDURE: 13 IN SEGMENT: 00
5169 C7 F4 01 LDCI. PUSH #01F4
516C CE 05 CLP. CALL CHILD PROCEDURE: 05
516E C7 AC 3F LDCI. PUSH #3FAC
5171 91 NGI. PUSH -(TOS) (2'S COMP)
5172 AE 02 CIP. CALL INTERMEDIATE PROCEDURE: 02
5174 C7 A9 3F LDCI. PUSH #3FA9
5177 91 NGI. PUSH -(TOS) (2'S COMP)
5178 AE 02 CIP. CALL INTERMEDIATE PROCEDURE: 02
517A C7 AE 3F LDCI. PUSH #3FAE
517D 91 NGI. PUSH -(TOS) (2'S COMP)
517E AE 02 CIP. CALL INTERMEDIATE PROCEDURE: 02
5180 C7 B0 3F LDCI. PUSH #3FB0
5183 91 NGI. PUSH -(TOS) (2'S COMP)
5184 AE 02 CIP. CALL INTERMEDIATE PROCEDURE: 02
5186 B6 03 03 LOD. PUSH ACTREC(-03).03
5189 0C SLDC. PUSH #000C
518A 00 SLDC. PUSH #0000
518B CD 00 11 CXP. CALL EXTERNAL PROCEDURE: 11 IN SEGMENT: 00
518E 29 SLDC. PUSH #0029
518F 00 SLDC. PUSH #0000
5190 CD 00 1D CXP. CALL EXTERNAL PROCEDURE: 1D IN SEGMENT: 00
5193 B2 01 03 LDA. PUSH #ACTREC(-01).03
5196 00 SLDC. PUSH #0000
5197 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5199 B2 01 03 LDA. PUSH #ACTREC(-01).03
519C 00 SLDC. PUSH #0000
519D A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
519F F8 SIND. PUSH (TOS)^.0
51A0 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
51A3 00 SLDC. PUSH #0000
51A4 CC 04 STL. MP.04 := (TOS)
51A6 04 SLDC. PUSH #0004
51A7 CC 05 STL. MP.05 := (TOS)
51A9 01 SLDC. PUSH #0001
51AA CC 02 STL. MP.02 := (TOS)
51AC 14 SLDC. PUSH #0014
51AD CC 06 STL. MP.06 := (TOS)
51AF D9 SLDL. PUSH MP.02
51B0 DD SLDL. PUSH MP.06
51B1 C8 LEQI. PUSH ((TOS-1) <= (TOS))
51B2 A1 0C UJP. IF NOT (TOS) THEN JUMP TO 51C0
51B4 0F SLDC. PUSH #000F
51B5 CE 05 CLP. CALL CHILD PROCEDURE: 05
51B7 CE 06 CLP. CALL CHILD PROCEDURE: 06
51B9 D9 SLDL. PUSH MP.02
51BA 01 SLDC. PUSH #0001
51BB 82 ADI. PUSH ((TOS) + (TOS-1))
51BC CC 02 STL. MP.02 := (TOS)
51BE B9 F6 UJP. JUMP TO 51AF
51C0 01 SLDC. PUSH #0001
51C1 CC 02 STL. MP.02 := (TOS)
51C3 18 SLDC. PUSH #0018
51C4 CC 06 STL. MP.06 := (TOS)
51C6 D9 SLDL. PUSH MP.02
51C7 DD SLDL. PUSH MP.06
51C8 C8 LEQI. PUSH ((TOS-1) <= (TOS))
51C9 A1 20 UJP. IF NOT (TOS) THEN JUMP TO 51EB
51CB 01 SLDC. PUSH #0001
51CC CC 01 STL. MP.01 := (TOS)
51CE 02 SLDC. PUSH #0002
51CF CC 07 STL. MP.07 := (TOS)
51D1 D8 SLDL. PUSH MP.01
51D2 DE SLDL. PUSH MP.07
51D3 C8 LEQI. PUSH ((TOS-1) <= (TOS))
51D4 A1 0C UJP. IF NOT (TOS) THEN JUMP TO 51E2
51D6 0C SLDC. PUSH #000C
51D7 CE 05 CLP. CALL CHILD PROCEDURE: 05
51D9 CE 06 CLP. CALL CHILD PROCEDURE: 06
51DB D8 SLDL. PUSH MP.01
51DC 01 SLDC. PUSH #0001
51DD 82 ADI. PUSH ((TOS) + (TOS-1))
51DE CC 01 STL. MP.01 := (TOS)
51E0 B9 F4 UJP. JUMP TO 51D1
51E2 CE 07 CLP. CALL CHILD PROCEDURE: 07
51E4 D9 SLDL. PUSH MP.02
51E5 01 SLDC. PUSH #0001
51E6 82 ADI. PUSH ((TOS) + (TOS-1))
51E7 CC 02 STL. MP.02 := (TOS)
51E9 B9 F2 UJP. JUMP TO 51C6
51EB B2 01 03 LDA. PUSH #ACTREC(-01).03
51EE 00 SLDC. PUSH #0000
51EF A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
51F1 B2 01 03 LDA. PUSH #ACTREC(-01).03
51F4 08 SLDC. PUSH #0008
51F5 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
51F7 F8 SIND. PUSH (TOS)^.0
51F8 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
51FB CE 06 CLP. CALL CHILD PROCEDURE: 06
51FD 09 SLDC. PUSH #0009
51FE CC 02 STL. MP.02 := (TOS)
5200 17 SLDC. PUSH #0017
5201 CC 06 STL. MP.06 := (TOS)
5203 D9 SLDL. PUSH MP.02
5204 DD SLDL. PUSH MP.06
5205 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5206 A1 30 UJP. IF NOT (TOS) THEN JUMP TO 5238
5208 01 SLDC. PUSH #0001
5209 CC 01 STL. MP.01 := (TOS)
520B 02 SLDC. PUSH #0002
520C CC 07 STL. MP.07 := (TOS)
520E D8 SLDL. PUSH MP.01
520F DE SLDL. PUSH MP.07
5210 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5211 A1 0E UJP. IF NOT (TOS) THEN JUMP TO 5221
5213 05 SLDC. PUSH #0005
5214 D9 SLDL. PUSH MP.02
5215 82 ADI. PUSH ((TOS) + (TOS-1))
5216 CE 05 CLP. CALL CHILD PROCEDURE: 05
5218 CE 06 CLP. CALL CHILD PROCEDURE: 06
521A D8 SLDL. PUSH MP.01
521B 01 SLDC. PUSH #0001
521C 82 ADI. PUSH ((TOS) + (TOS-1))
521D CC 01 STL. MP.01 := (TOS)
521F B9 F0 UJP. JUMP TO 520E
5221 B2 01 03 LDA. PUSH #ACTREC(-01).03
5224 00 SLDC. PUSH #0000
5225 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5227 B2 01 03 LDA. PUSH #ACTREC(-01).03
522A D9 SLDL. PUSH MP.02
522B A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
522D F8 SIND. PUSH (TOS)^.0
522E CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
5231 D9 SLDL. PUSH MP.02
5232 01 SLDC. PUSH #0001
5233 82 ADI. PUSH ((TOS) + (TOS-1))
5234 CC 02 STL. MP.02 := (TOS)
5236 B9 EE UJP. JUMP TO 5203
5238 18 SLDC. PUSH #0018
5239 CC 02 STL. MP.02 := (TOS)
523B 20 SLDC. PUSH #0020
523C CC 06 STL. MP.06 := (TOS)
523E D9 SLDL. PUSH MP.02
523F DD SLDL. PUSH MP.06
5240 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5241 A1 2E UJP. IF NOT (TOS) THEN JUMP TO 5271
5243 01 SLDC. PUSH #0001
5244 CC 01 STL. MP.01 := (TOS)
5246 04 SLDC. PUSH #0004
5247 CC 07 STL. MP.07 := (TOS)
5249 D8 SLDL. PUSH MP.01
524A DE SLDL. PUSH MP.07
524B C8 LEQI. PUSH ((TOS-1) <= (TOS))
524C A1 0C UJP. IF NOT (TOS) THEN JUMP TO 525A
524E 0A SLDC. PUSH #000A
524F CE 05 CLP. CALL CHILD PROCEDURE: 05
5251 CE 06 CLP. CALL CHILD PROCEDURE: 06
5253 D8 SLDL. PUSH MP.01
5254 01 SLDC. PUSH #0001
5255 82 ADI. PUSH ((TOS) + (TOS-1))
5256 CC 01 STL. MP.01 := (TOS)
5258 B9 EC UJP. JUMP TO 5249
525A B2 01 03 LDA. PUSH #ACTREC(-01).03
525D 00 SLDC. PUSH #0000
525E A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5260 B2 01 03 LDA. PUSH #ACTREC(-01).03
5263 D9 SLDL. PUSH MP.02
5264 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5266 F8 SIND. PUSH (TOS)^.0
5267 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
526A D9 SLDL. PUSH MP.02
526B 01 SLDC. PUSH #0001
526C 82 ADI. PUSH ((TOS) + (TOS-1))
526D CC 02 STL. MP.02 := (TOS)
526F B9 EA UJP. JUMP TO 523E
5271 01 SLDC. PUSH #0001
5272 CC 02 STL. MP.02 := (TOS)
5274 28 SLDC. PUSH #0028
5275 CC 06 STL. MP.06 := (TOS)
5277 D9 SLDL. PUSH MP.02
5278 DD SLDL. PUSH MP.06
5279 C8 LEQI. PUSH ((TOS-1) <= (TOS))
527A A1 0C UJP. IF NOT (TOS) THEN JUMP TO 5288
527C 0C SLDC. PUSH #000C
527D CE 05 CLP. CALL CHILD PROCEDURE: 05
527F CE 06 CLP. CALL CHILD PROCEDURE: 06
5281 D9 SLDL. PUSH MP.02
5282 01 SLDC. PUSH #0001
5283 82 ADI. PUSH ((TOS) + (TOS-1))
5284 CC 02 STL. MP.02 := (TOS)
5286 B9 E8 UJP. JUMP TO 5277
5288 01 SLDC. PUSH #0001
5289 CC 02 STL. MP.02 := (TOS)
528B 50 SLDC. PUSH #0050
528C CC 06 STL. MP.06 := (TOS)
528E D9 SLDL. PUSH MP.02
528F DD SLDL. PUSH MP.06
5290 C8 LEQI. PUSH ((TOS-1) <= (TOS))
5291 A1 13 UJP. IF NOT (TOS) THEN JUMP TO 52A6
5293 B2 01 01 LDA. PUSH #ACTREC(-01).01
5296 00 SLDC. PUSH #0000
5297 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
529A 07 SLDC. PUSH #0007
529B CE 05 CLP. CALL CHILD PROCEDURE: 05
529D CE 06 CLP. CALL CHILD PROCEDURE: 06
529F D9 SLDL. PUSH MP.02
52A0 01 SLDC. PUSH #0001
52A1 82 ADI. PUSH ((TOS) + (TOS-1))
52A2 CC 02 STL. MP.02 := (TOS)
52A4 B9 E6 UJP. JUMP TO 528E
52A6 01 SLDC. PUSH #0001
52A7 CC 02 STL. MP.02 := (TOS)
52A9 28 SLDC. PUSH #0028
52AA CC 06 STL. MP.06 := (TOS)
52AC D9 SLDL. PUSH MP.02
52AD DD SLDL. PUSH MP.06
52AE C8 LEQI. PUSH ((TOS-1) <= (TOS))
52AF A1 0C UJP. IF NOT (TOS) THEN JUMP TO 52BD
52B1 0C SLDC. PUSH #000C
52B2 CE 05 CLP. CALL CHILD PROCEDURE: 05
52B4 CE 06 CLP. CALL CHILD PROCEDURE: 06
52B6 D9 SLDL. PUSH MP.02
52B7 01 SLDC. PUSH #0001
52B8 82 ADI. PUSH ((TOS) + (TOS-1))
52B9 CC 02 STL. MP.02 := (TOS)
52BB B9 E4 UJP. JUMP TO 52AC
52BD AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.
52BF 00 SLDC. PUSH #0000
52C0 14 SLDC. PUSH #0014
52C1 00 SLDC. PUSH #0000
52C2 34 SLDC. PUSH #0034
52C3 00 SLDC. PUSH #0000
52C4 4D SLDC. PUSH #004D
52C5 00 SLDC. PUSH #0000
52C6 88 CHK. IF (TOS-1) <= (TOS-2) <= (TOS) THEN PUSH TOS-2 ELSE ERROR
52C7 00 SLDC. PUSH #0000
52C8 7F SLDC. PUSH #007F
52C9 00 SLDC. PUSH #0000
52CA C7 00 BE LDCI. PUSH #BE00
52CD 00 SLDC. PUSH #0000
52CE 08 SLDC. PUSH #0008
52CF 01 SLDC. PUSH #0001
52D0 FF SIND. PUSH (TOS)^.7
52D1 00 SLDC. PUSH #0000
52D2 23 SLDC. PUSH #0023
52D3 01 SLDC. PUSH #0001


Lets work on this section first:

50D8 B2 01 03 LDA. PUSH #ACTREC(-01).03
50DB 00 SLDC. PUSH #0000
50DC A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
50DE B2 01 03 LDA. PUSH #ACTREC(-01).03
50E1 08 SLDC. PUSH #0008
50E2 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
50E4 F8 SIND. PUSH (TOS)^.0
50E5 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01

#ACTREC(-01).03 is MP03 in P070201. It is a BUFFER of 4608 INTEGERS, enough to hold 18 sectors. I will rename #ACTREC(-01).03 to BUFFER and use that name instead of MP03 in all routines.

I realize now that I misplaced the routines P070002 through P070004. At least P07002 needs to be above TITLELOA segment so that it gets the proper procedure number assigned to it.

SYSTEM.STARTUP
PROGRAM WIZBOOT P070001
$I WIZ1E:WIZUTILB
$I WIZ1E:WIZUTILC
$I WIZ1E:TITLELOA
$I WIZ1E:OPTIONS
FUNCTION P070002 : BOOLEAN; EXTERNAL;
TITLELOA; called by WIZBOOT main P070201

I neglected the parameters passed to P070002. Looks like there are 2.
Now I need to re-assemble P070002 with "2" parameters, and re-link P070002 into STARTUP.CODE. Then I can COMPILE STARTUP and have the P070002( 0, 0) call work properly in P070204.

Procedure: 02 might be a PROCEDURE and not a FUNCTION as in LOL.

This is my first try at the first instruction in P070204:

P070002( BUFFER[ 0], BUFFER[ 8]);

My first attempt at declaring BUFFER was wrong (see 5084 and 5085 below):

BUFFER : ARRAY[ 1..4608] OF CHAR;

5080 B2 01 03 LDA. PUSH #ACTREC(-01).03
5083 00 SLDC. PUSH #0000
5084 01 SLDC. PUSH #0001
5085 95 SBI. PUSH ((TOS-1) - (TOS))
5086 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01

Therefore, I need to start the index for BUFFER at 0, not 1, and of course adjust 4608 to 4607.

This is what it now generates:

5080 B2 01 03 LDA. PUSH #ACTREC(-01).03
5083 00 SLDC. PUSH #0000
5084 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5086 F8 SIND. PUSH (TOS)^.0
5087 B2 01 03 LDA. PUSH #ACTREC(-01).03
508A 08 SLDC. PUSH #0008
508B A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
508D F8 SIND. PUSH (TOS)^.0
508E 00 SLDC. PUSH #0000
508F 00 SLDC. PUSH #0000
5090 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01

But line 5086 is wrong. It is pushing a value from the array onto the stack, but the code we want pushes only the pointer. We don't want line 5086 to be generated at all. Therefore, this is telling me to change the parameter passage to P070002 to be by REFERENCE (VAR) and not by VALUE (no VAR).

Note the second parameter IS passed by value as deteremined by the instruction at 508D above which we want.

The 2 pushes of #0 are extra noise for calling an EXTERNAL procedure.

Since the code we want does not immediately do something with a value after calling PROCEDURE: 02, this is therefore a PROCEDURE and not a FUNCTION.

This code generates the first instruction properly:

141 1 2:D 1 PROCEDURE P070002( VAR A1:INTEGER; A2:INTEGER); EXTERNAL; (* FORMERLY COPYPROT *)
973 8 4:0 0 BEGIN (* P070204 *)
974 8 4:1 0 P070002( BUFFER[ 0], BUFFER[ 8]);
975 8 4:0 16 END;

921 8 1:D 1 SEGMENT PROCEDURE TITLELOA; (* P070201 *)
936 8 1:D 3 BUFFER : ARRAY[ 0..4607] OF INTEGER;

P070002.TEXT:
.PROC P070002,2 ; WITH 2 PARAMETERS PASSED INTO (FORMERLY COPYPROT)


This took a lot more time to fix up than I thought it should. It took me as much time to re-engineer that first instruction as it did for the rest of the entire procedure!

There is an instruction in P070204 that de-compiles and uses MP01 in the calling procedure( P070201). Since P070204 has its own variable named MP01 I have changed MP01 in P070201 to MPXX01 for now.

The rest of this procedure is easy to re-engineer once you realize it is mostly GOTOXY() and WRITE().

Here is the code for P070204:

959 8 4:D 1 PROCEDURE P070204;
960 8 4:D 1
961 8 4:D 1 VAR
962 8 4:D 1 MP01 : INTEGER;
963 8 4:D 2 MP02 : INTEGER;
964 8 4:D 3 MP03 : INTEGER;
965 8 4:D 4 MP04 : INTEGER;
966 8 4:D 5 MP05 : INTEGER;
967 8 4:D 6 MP06 : INTEGER;
968 8 4:D 7 MP07 : INTEGER;
969 8 4:D 8
970 8 4:D 8
971 8 5:D 1 PROCEDURE P070205( MP01 : INTEGER);
972 8 5:0 0 BEGIN
973 8 5:0 0 END;
974 8 5:0 12
975 8 6:D 1 PROCEDURE P070206;
976 8 6:0 0 BEGIN
977 8 6:0 0 END;
978 8 6:0 12
979 8 7:D 1 PROCEDURE P070207;
980 8 7:0 0 BEGIN
981 8 7:0 0 END;
982 8 7:0 12
983 8 4:0 0 BEGIN (* P070204 *)
984 8 4:1 0 P070002( BUFFER[ 0], BUFFER[ 8]);
985 8 4:1 16 MP1203.I := 8192; (* $2000 *)
986 8 4:1 23 FILLCHAR( MP1203.P^, 8192, 0);
987 8 4:1 34 WRITE( CHR(12)); (* LINEFEED (?) *)
988 8 4:1 42 GOTOXY( 12, 10);
989 8 4:1 47 WRITE( 'PREPARE YOURSELF');
990 8 4:1 73 P070205( 150); (* $96 *)
991 8 4:1 78 GOTOXY( 12, 12);
992 8 4:1 83 WRITE( 'FOR THE ULTIMATE');
993 8 4:1 109 P070205( 150); (* $96 *)
994 8 4:1 114 GOTOXY( 12, 14);
995 8 4:1 119 WRITE( 'IN FANTASY GAMES');
996 8 4:1 145 P070205( 500); (* $1F4 *)
997 8 4:1 150
998 8 4:1 150 P070202( -16300); (* $3FAC *)
999 8 4:1 156 P070202( -16297); (* $3FA9 *)
1000 8 4:1 162 P070202( -16302); (* $3FAE *)
1001 8 4:1 168 P070202( -16304); (* $3FB0 *)
1002 8 4:1 174
1003 8 4:1 174 WRITE( CHR( 12));
1004 8 4:1 182 GOTOXY( 41, 0); (* OFF SCREEN *)
1005 8 4:1 187
1006 8 4:1 187 P070002( BUFFER[ 0], BUFFER[ 0]);
1007 8 4:1 203 MP04 := 0;
1008 8 4:1 206 MP05 := 4;
1009 8 4:1 209 MP02 := 1;
1010 8 4:1 212 MP06 := 20;
1011 8 4:1 215
1012 8 4:1 215 WHILE MP02 <= MP06 DO
1013 8 4:2 220 BEGIN
1014 8 4:3 220 P070205( 15);
1015 8 4:3 223 P070206;
1016 8 4:3 225 MP02 := MP02 + 1;
1017 8 4:2 230 END;
1018 8 4:2 232
1019 8 4:1 232 MP02 := 1;
1020 8 4:1 235 MP06 := 24;
1021 8 4:1 238 WHILE MP02 <= MP06 DO
1022 8 4:2 243 BEGIN
1023 8 4:3 243 MP01 := 1;
1024 8 4:3 246 MP07 := 2;
1025 8 4:3 249 WHILE MP01 <= MP07 DO
1026 8 4:4 254 BEGIN
1027 8 4:5 254 P070205( 12);
1028 8 4:5 257 P070206;
1029 8 4:5 259 MP01 := MP01 + 1
1030 8 4:4 260 END;
1031 8 4:3 266 P070207;
1032 8 4:3 268 MP02 := MP02 + 1;
1033 8 4:2 273 END;
1034 8 4:1 275 P070002( BUFFER[ 0], BUFFER[ 8]);
1035 8 4:1 291 P070206;
1036 8 4:1 293 MP02 := 9;
1037 8 4:1 296 MP06 := 23;
1038 8 4:1 299 WHILE MP02 <= MP06 DO
1039 8 4:2 304 BEGIN
1040 8 4:3 304 MP01 := 1;
1041 8 4:3 307 MP07 := 2;
1042 8 4:3 310 WHILE MP01 <= MP07 DO
1043 8 4:4 315 BEGIN
1044 8 4:5 315 P070205( 5 + MP02);
1045 8 4:5 320 P070206;
1046 8 4:5 322 MP01 := MP01 + 1
1047 8 4:4 323 END;
1048 8 4:3 329 P070002( BUFFER[ 0], BUFFER[ MP02]);
1049 8 4:3 345 MP02 := MP02 + 1
1050 8 4:2 346 END;
1051 8 4:1 352 MP02 := 24;
1052 8 4:1 355 MP06 := 32;
1053 8 4:1 358 WHILE MP02 <= MP06 DO
1054 8 4:2 363 BEGIN
1055 8 4:3 363 MP01 := 1;
1056 8 4:3 366 MP07 := 4;
1057 8 4:3 369 WHILE MP01 <= MP07 DO
1058 8 4:4 374 BEGIN
1059 8 4:5 374 P070205( 10);
1060 8 4:5 377 P070206;
1061 8 4:5 379 MP01 := MP01 + 1
1062 8 4:4 380 END;
1063 8 4:3 386 P070002( BUFFER[ 0], BUFFER[ MP02]);
1064 8 4:3 402 MP02 := MP02 + 1
1065 8 4:2 403 END;
1066 8 4:1 409 MP02 := 1;
1067 8 4:1 412 MP06 := 40;
1068 8 4:1 415 WHILE MP02 <= MP06 DO
1069 8 4:2 420 BEGIN
1070 8 4:3 420 P070205( 12);
1071 8 4:3 423 P070206;
1072 8 4:3 425 MP02 := MP02 + 1;
1073 8 4:2 430 END;
1074 8 4:1 432 MP02 := 1;
1075 8 4:1 435 MP06 := 80;
1076 8 4:1 438 WHILE MP02 <= MP06 DO
1077 8 4:2 443 BEGIN
1078 8 4:3 443 P070002( MPXX01, 0);
1079 8 4:3 450 P070205( 7); (* BELL *)
1080 8 4:3 453 P070206;
1081 8 4:3 455 MP02 := MP02 + 1
1082 8 4:2 456 END;
1083 8 4:2 462
1084 8 4:1 462 MP02 := 1;
1085 8 4:1 465 MP06 := 40;
1086 8 4:1 468 WHILE MP02 <= MP06 DO
1087 8 4:2 473 BEGIN
1088 8 4:3 473 P070205( 12);
1089 8 4:3 476 P070206;
1090 8 4:3 478 MP02 := MP02 + 1
1091 8 4:2 479 END
1092 8 4:0 483 END;

The 3 child procedures to P070204 were easy and follow in order:
P070205
P070206
P070207

P070205 Pcode:

FILE: 7 SEG: 2 PROC: 5

JTAB FOR SUBROUTINE 5:
DATA SIZE: 0
PARAM SIZE: 2
EXIT AT: 5077
ENTER AT: 505C
PROC NUMBER: 5
LEXICAL LEVEL: 3
505C 29 SLDC. PUSH #0029
505D 00 SLDC. PUSH #0000
505E CD 00 1D CXP. CALL EXTERNAL PROCEDURE: 1D IN SEGMENT: 00
5061 D8 SLDL. PUSH MP.01
5062 00 SLDC. PUSH #0000
5063 C5 GRTI. PUSH ((TOS-1) > (TOS))
5064 A1 11 UJP. IF NOT (TOS) THEN JUMP TO 5077
5066 00 SLDC. PUSH #0000
5067 00 SLDC. PUSH #0000
5068 AE 03 CIP. CALL INTERMEDIATE PROCEDURE: 03
506A A1 04 UJP. IF NOT (TOS) THEN JUMP TO 5070
506C 08 SLDC. PUSH #0008
506D 04 SLDC. PUSH #0004
506E 9E 04 EXIT. EXIT FROM PROCEDURE. (TOS)=PROC# (TOS-1)=SEG#
5070 D8 SLDL. PUSH MP.01
5071 01 SLDC. PUSH #0001
5072 95 SBI. PUSH ((TOS-1) - (TOS))
5073 CC 01 STL. MP.01 := (TOS)
5075 B9 F6 UJP. JUMP TO 5061
5077 AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.
5079 00 SLDC. PUSH #0000
507A 19 SLDC. PUSH #0019
507B 00 SLDC. PUSH #0000


P070205 Pascal code:

971 8 5:D 1 PROCEDURE P070205( MP01 : INTEGER);
972 8 5:0 0 BEGIN
973 8 5:1 0 GOTOXY( 41, 0);
974 8 5:1 5 WHILE MP01 > 0 DO
975 8 5:2 10 BEGIN
976 8 5:3 10 IF P070203 THEN
977 8 5:4 16 EXIT( P070204);
978 8 5:3 20 MP01 := MP01 - 1;
979 8 5:2 25 END;
980 8 5:0 27 END;


P070206 pcode:

FILE: 7 SEG: 2 PROC: 6

JTAB FOR SUBROUTINE 6:
DATA SIZE: 0
PARAM SIZE: 0
EXIT AT: 50A2
ENTER AT: 5086
PROC NUMBER: 6
LEXICAL LEVEL: 3
5086 01 SLDC. PUSH #0001
5087 B6 01 04 LOD. PUSH ACTREC(-01).04
508A 03 SLDC. PUSH #0003
508B 8E MODI. PUSH ((TOS-1) MOD (TOS))
508C 82 ADI. PUSH ((TOS) + (TOS-1))
508D B8 01 04 STR. ACTREC(-01).04 := TOS
5090 B2 02 03 LDA. PUSH #ACTREC(-02).03
5093 00 SLDC. PUSH #0000
5094 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
5096 B2 02 03 LDA. PUSH #ACTREC(-02).03
5099 B6 01 04 LOD. PUSH ACTREC(-01).04
509C A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
509E F8 SIND. PUSH (TOS)^.0
509F CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
50A2 AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.


P070206 Pascal code:

983 8 6:D 1 PROCEDURE P070206;
984 8 6:D 1
985 8 6:0 0 BEGIN
986 8 6:1 0 MP04 := 1 + (MP04 MOD 3);
987 8 6:1 10 P070002( BUFFER[ 0], BUFFER[ MP04])
988 8 6:0 25 END;


P070207 pcode

FILE: 7 SEG: 2 PROC: 7

JTAB FOR SUBROUTINE 7:
DATA SIZE: 0
PARAM SIZE: 0
EXIT AT: 50CC
ENTER AT: 50AE
PROC NUMBER: 7
LEXICAL LEVEL: 3
50AE 05 SLDC. PUSH #0005
50AF B6 01 05 LOD. PUSH ACTREC(-01).05
50B2 04 SLDC. PUSH #0004
50B3 95 SBI. PUSH ((TOS-1) - (TOS))
50B4 03 SLDC. PUSH #0003
50B5 8E MODI. PUSH ((TOS-1) MOD (TOS))
50B6 82 ADI. PUSH ((TOS) + (TOS-1))
50B7 B8 01 05 STR. ACTREC(-01).05 := TOS
50BA B2 02 03 LDA. PUSH #ACTREC(-02).03
50BD 00 SLDC. PUSH #0000
50BE A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
50C0 B2 02 03 LDA. PUSH #ACTREC(-02).03
50C3 B6 01 05 LOD. PUSH ACTREC(-01).05
50C6 A4 01 IXA. PUSH #((TOS-1)[TOS]). ARRAY SIZE=01
50C8 F8 SIND. PUSH (TOS)^.0
50C9 CD 01 02 CXP. CALL EXTERNAL PROCEDURE: 02 IN SEGMENT: 01
50CC AD 00 RNP. RETURN FROM NON-BASE PROCEDURE.

P070207 Pascal code:

991 8 7:D 1 PROCEDURE P070207;
992 8 7:D 1
993 8 7:0 0 BEGIN
994 8 7:1 0 MP05 := 5 + ((MP05 - 4) MOD 3);
995 8 7:1 12 P070002( BUFFER[ 0], BUFFER[ MP05])
996 8 7:0 27 END;


At this point, all of WIZBOOT and all of TITLELOA are completed.

SYSTEM.STARTUP

Segment: Procedures
0 (1) WIZBOOT 5
1 (7) UTILS 36
2 (8) TITLELOA 8
3 (9) OPTIONS 1

Up next is P070301 (SEGMENT OPTIONS)

TommyGoog

unread,
Apr 19, 2014, 12:22:57 AM4/19/14
to
On Tuesday, April 15, 2014 11:51:01 PM UTC-5, qkumba wrote:

>
> 511A... - looks like LZW decompression routine.
>

Here's something to brighten your day (I hope).

I don't doubt that the code at 511A in Wizardry I is *some* kind of decompression, but there might be a liiiiiittle problem with calling it LZW.

Copyright notice displayed by the software for Wizardry I:

COPYRIGHT (C)1981

LZW described in Wikipedia:

Lempel-Ziv-Welch (LZW) is a universal lossless data compression algorithm created by Abraham Lempel, Jacob Ziv, and Terry Welch. It was published by Welch in 1984 as an improved implementation of the LZ78 algorithm published by Lempel and Ziv in 1978.

The authors of Wizardry were good, but I don't think they were time travelers :)

And I hope by pointing this out I don't discourage you (or anyone else) from participating in this thread!

I'm posting this with a smile!

Tommy

qkumba

unread,
Apr 20, 2014, 6:27:04 PM4/20/14
to
> > 511A... - looks like LZW decompression routine.
> Here's something to brighten your day (I hope).
> I don't doubt that the code at 511A in Wizardry I is *some* kind of
> decompression, but there might be a liiiiiittle problem with calling it LZW.

Yes, I am aware that LZW did not exist at that time.
Originally, I wrote LZ, but then the auto-correct in my brain changed it to LZW, since most everything LZ-like these days is really LZW-based.

> And I hope by pointing this out I don't discourage you (or anyone else) from
> participating in this thread!

:-) No chance of that. I don't mind when people point out that I'm wrong.

Didier VALLET

unread,
Apr 21, 2014, 12:23:35 PM4/21/14