MaxZ80 - Chapter 11

In Chapter 7, where we talked about slowing CHICKEN.PAS down, we wrote

"Under Z-System, you can count on address hex 109 to be filled with the
(integer) memory address of the environment record."

In the "old days" of Z-System, you had to install this address in
the .COM file manually by using a program called Z3INS. In this
Z-System, the command processor looks at the .COM file and, if it has
the signature "Z3ENV" in bytes 3 thru 8, where the first byte is called
byte 0, it puts the address of the environment descriptor into address
hex 109 and 10a.

For CHICKEN to be a Z-System program it has to have this 5-letter
signature. How did it get it? A very clever idea that Joe Wright came up
with was used. The Turbo Pascal compiler itself just happens not to use
bytes 3 thru about 21 for any important purpose so an ARUNZ "alias" was
designed to poke "Z3ENV" into memory starting at hex 103 after loading
memory starting at hex 100 with the compiler's .COM file. So, when we
want to run the compiler, instead of typing TURBO, we type TP.

Here's the definition of TP.

tp get 100 turbo.com;poke 103 5a 33 45 4e 56 01 00 00;go

The "alias" (or Extended Command Processor command) TP illustrates
several new ideas. First, it is our first example of a Multiple Command
Line. Second, the commands get, poke and go are commands that are
builtin to either the command processor itself or a Z-System segment
called the Resident Command Package. These commands are always
available, unlike transient commands (.COM files). get loads memory
starting at the supplied hex address with what's in the supplied file
name. poke puts the values of the supplied bytes into memory starting at
the supplied hex address. 5a is the hex code for the ASCII code for Z
etc. go launches whatever instruction is at hex address 100.

To learn what Command Processor Resident Commands and what Resident
Command Package Commands you have, you may issue the H command, which is
itself an RCP command.

8:57 A0:MOUSE>>H

FCP
    IF      AND     OR      ELSE    FI
    IFQ     XIF     ZIF

CPR
    GET     GO      JUMP

RCP-18F
    CLS     ECHO    ERA     H       NOTE
    P       POKE    PORT    R       REG
    SP      TYPE    WHL

8:57 A0:MOUSE>>

We'll talk about the Flow Command Package commands later.

The .COM files generated by the Turbo Pascal compiler inherit the code
that is at the beginning of the compiler itself. So that's how CHICKEN
became a Z-System program.

Although not a generally recommended practice, after some thought that
this would not be a foolish thing to do, I decided to patch TURBO.COM
itself in this way. I used ZP (Z Patcher). See screen shot below.

ZP v1.7    A6/EBC:TURBO.COM          Record: 00001 (0001h) of 00238 (00EEh)
Cache:     Empty
(Type 4 at A346h)
           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F    0123456789ABCDEF
           -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    ----------------
00 0100 -- C3 C9 1F 5A 33 45 4E 56 01 00 00 67 68 74 20 28   <...Z3ENV...ght (>
00 0110 -- 43 29 20 31 39 38 34 20 42 4F 52 4C 41 4E 44 20   
00 0120 -- 49 6E 63 00 26 00 82 41 00 00 00 00 00 00 00 00   
00 0130 -- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   <................>
00 0140 -- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   <................>
00 0150 -- 00 00 00 0D 4D 59 5A 38 30 20 20 20 20 20 20 20   <....MYZ80       >
00 0160 -- 20 20 49 56 00 00 00 00 50 18 00 00 00 00 00 00   <  IV....P.......>
00 0170 -- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   <................>
+-----------------------------------------------------------------------------+
¦  <,   Prev Record       ¦  F    Filename          ¦  E    Edit Record       ¦
¦  >.   Next Record       ¦  A    Address           ¦  K    Record Cache      ¦
¦  T    Top of File       ¦  R    Record            ¦  S    String Search     ¦
¦  B    End of File       ¦  O    Offset            ¦  C    Continue Search   ¦
+-------------------------+-------------------------¦  D    Disk Mode         ¦
¦  ^C   Calculator        ¦  Q    Exit ZP           ¦  M    Memory Mode       ¦
+-----------------------------------------------------------------------------+

This means you don't need to use the "poke and go" alias anymore. Just
run the compiler.

What if the compiler you're using does have important code at its
beginning or what if the .COM files it generates don't inherit the code
at the beginning of the compiler? This is a much more common situation.
The BASCOM compiler is an example. To make BASIC programs Z-System
utilities, we have to write a small assembler language code segment,
assemble it into a .REL and then link it up with the .REL we get when we
compile our BASIC program.

SKUNK.BAS was made Z-System aware in this way. This is a fun game that
displays dice and, on a given turn, you either get the points on the
face or you get SKUNKed, which means you lose your points.

Here's the needed "header" code:

8:39 A4:BASIC>>type z3hdr.mac

  cseg
  defb    'Z3ENV'
  defb    1
  defw    0
  end

and here's the .SUB file:

8:43 A7:MOTYL>>type skunk.sub

BASCOM =SKUNK16C/Z/O
L80 Z3HDR,CMD,SKUNK16C,SKUNK16C/N/E

SKUNK uses many elements of Z-System, in particular, it gets the graphic
characters it uses to draw the dice from the Terminal Capabilities
Segment, the second half of the Environment Descriptor. Also, it
controls the speed of play by knowing the MHz of your PC.

Here's how it gets the address of the Environment Descriptor:

3420 ENV=PEEK(&H109)+256*PEEK(&H10A)
3430 ENV1=PEEK(ENV+&H1B)+256*PEEK(ENV+&H1C)
3440 IF ENV1=ENV THEN 3460
3450 PRINT:PRINT "Environment self-reference error detected":END
3460 RETURN

This is just z3exist, the Pascal function, in BASIC.

Here's how it gets the speed:

4400 MHZ=PEEK(ENV+&H2B):RETURN

Finally, there's a section in the Environment Descriptor which SKUNK
reads called the "External File Control Block." It contains the name of
the .COM file you ran. So if you built SKUNK16C.COM and then renamed it
SKUNK.COM, you'd be shown SKUNK when you ran it.

4310 ' External File Control Block stuff
4320 EFCBA=PEEK(ENV+&H24)+256*PEEK(ENV+&H25)+1
4330 EFCB$=""
4340 IF CHR$(PEEK(EFCBA))<>" " AND LEN(EFCB$)<8 THEN
 EFCB$=EFCB$+CHR$(PEEK(EFCBA)): EFCBA=EFCBA+1:GOTO 4340
4350 RETURN

Give SKUNK a try!

I ran it when I was in C4: and got the error message

9:11 C4>>skunk

File Not Found at address 044B

We talked about "System Files" in Chapter 8 (FATCAT). There are "Public
Files" too. These are identified by setting the high-order bit of the
second letter in their file names. Public Files are called Public
because they will be found by any application that's looking for them
provided they are on the same drive. SKUNK.DAT is a data file that holds
names of people that get randomly picked when you are SKUNKed (or double
SKUNKed).



To get SKUNK to work if you're on drive C:, I put a copy of this file in
C13. Some copy programs don't preserve the "attributes" of files
(Public, System, etc.) I used FA (File Attribute) to make it Public.

9:26 C13>>fa skunk.dat p
  C13:SKUNK   .DAT>  f1off  PUBLC  stamp  f4off  nowhl  r/w  dir  mod
    1 file matched, 1 attribute altered on C13:

Here's a screen shot of SKUNK.