BASIC MACHINE CODE FOR THE ZX81

Discussion about ZX80 / ZX81 Software
David G
Posts: 387
Joined: Thu Jul 17, 2014 7:58 am
Location: 21 North, 156 West

BASIC MACHINE CODE Chapter 5

Post by David G »

BASIC MACHINE CODE FOR THE ZX81 A beginner's series

CHAPTER 5 from SyncWare News Volume 2 Number 5 May-Jun. '85 pages 16-18
BASIL'S COMPENDIUM

Hexadecimal & 256-imal

Basil Wentworth
1413 Elliston Drive
Bloomington, IN 47401

This chapter will introduce the concept of hexadecimal notation, and what I call "256-imal". But first, the "fun" program.

This program will let you find the memory location of the first byte of any line. Just set the cursor at the line you're interested in, tell the computer to PRINT (notice: not RAND) USR 16514, and voila! There's the memory location of the line number. The first digit of the line number, that is--as you'll learn later on, the computer stores the line number in two bytes.

If you want, you can use this program instead of PROGTOP (see chapter 1). Just give the command POKE USR 16514,118.

You'll notice that the instructions for building the "fun" program are getting shorter and shorter. As you get more experience, I'm counting on you to fill in the missing details by yourself. So this time you get only a repeat of the loader program (Figure 5-1) and the final listing of the machine code routine (Figure 5-2).

Code: Select all

FIG 5-1.  THE LOADER PROGRAM

5000 LET F=16513
5010 LET F=F+1
5020 PRINT F;" " ;
5030 IF PEEK F<>27 THEN GOTO 5060
5040 INPUT A
5050 POKE F,A
5060 PRINT PEEK F, CHR$ PEEK F
5070 IF PEEK (F+1)=118 THEN STOP
5080 GOTO 5010
A P file version of THE LOADER can be found in the type-in thread: [Zx81:Type-Ins] "SyncWare News" campaign
By now, you probably feel a little as I did when I started studying the violin--the teacher spent what seemed like hours explaining how to hold the violin properly, when all I wanted to do was make music. I'm sorry about that. But we have one more digression to make before we really get into the business of coding.

If you already know all about hexadecimal notation (referred to indiscriminately as "hexadecimal" and "hex" throughout this series), or if you don't know, but don't mind sitting around trying to look wise when you talk with your computing friends or read a book on computing, then you can skip the first part of this chapter. Right up to the section on 256-imal. When you need to know the hex equivalent for a decimal number, or vice versa, you can always look up the conversion in the ZX81 handbook. Or compute your own conversions with a program like the one Tom Woods presented in Vol. 2 No. 2 of this publication.

But the section on 256-imal is important. Read and digest it.

Code: Select all

FIG 5-2.  THE 1 REM STATEMENT

16514 42  E    LD HL,
16515 10  GR S (16394)
16516 64  RND
16517 235 FOR  EX DE,HL 
16518 33  5    LD HL, 
16519 125 ?    16509
16520 64  RND
16521 35  7    INC HL
16522 62  Y    LD A,
16523 117 ?    117
16524 60  W    INC A
16525 190 D    CP(HL)
16526 32  4    JR NZ,
16527 249 RAND   -7
16528 35  7    INC HL
16529 190 D    CP(HL)
16530 200 COS  RET Z
16531 122 ?    LD A,D
16532 190 D    CP(HL)
16533 32  4    JR NZ,
16534 242 PAUSE  -14
16535 35  7    INC HL
16536 123 ?    LD A,E
16537 190 D    CP(HL)
16538 32  4    JR NZ,
16539 237 GOSUB  -19
16540 43  F    DEC HL
16541 229 FAST PUSH HL 
16542 193 AT   POP BC
16543 201 TAN  RET
This "1 REM" program finds the first address by BASIC line number. Discussion and disassembly are at the [Zx81:Type-Ins] thread
What is Hexadecimal?

You may already be familiar with binary counting. You're certainly familiar with decimal, although you may not have stopped to think how it works. (As Tom Lehrer points out, tongue in cheek, the important thing is to know how the system works--it doesn't matter whether you get the right answer or not.) Just to review, the meanings of the digits of the two systems are as shown in Figures 5-3 and 5-4. By logical extension, hexadecimal, based on 16, works as shown in Figure 5-5.

Code: Select all

FIG 5-3.  DECIMAL NOTATION
1325 IN DECIMAL =
  1 * 10**3 (=1000)
+ 3 * 10**2 (= 300)
+ 2 * 10**1 (=  20)
+ 5 * 10**0 (=   5)
            (=1325)
But, just as binary requires only two symbols (0 and 1) and decimal requires 10 of them (0-9), hex will require 16 separate characters. We already have 0-9; the other six are taken from the alphabet: A=10, B=11, C=12, D=13, E=14, and F=15. So A9 would be (10*16+9)=169; 9A would be

Code: Select all

FIG  5-4.  BINARY NOTATION

1011 IN BINARY =

  1 * 2**3 (= 8d)
+ 0 * 2**2 (= 0d)
+ 1 * 2**1 (= 2d)
+ 1 * 2**0 (= 1d)
           (=lld)
(9*16+10)-154; and so on. And C9, which you’ll soon learn from constant repetition, is our old friend 201, the code for RETURN.

Code: Select all

FIG 5-5.  HEX NOTATION

1A2F IN HEX =

   1 * 16**3 (=4096d)
+ 10 * 16**2 (= 320d)
+  2 * 16**1 (=  32d)
+ 15 * 16**  (=  15d)

             (=4463d)

But Why Use Hex?

To be honest, the most important reason to learn hexadecimal is that "everybody does it." Most published listings of the Z80 chip, for instance, are given in hex. So are large numbers of published programs. Typographically, the use of hex makes for a neater looking page--the fact that each hex byte is expressed in exactly two bytes makes it easier to list a program in a symmetrical fashion. And loader programs for hex are a bit simpler than those expressed in decimal.

However, I never accepted "everybody does it" as an excuse from my kids. And this is, after all, a series for beginners. So we'll be using decimal notation primarily. If there's any chance for confusion, I'll follow the accepted convention of adding an "h" or a "d" after a number, such as:

Code: Select all

      20h=32d  (i.e. 20 hex = 32 dec)
or    20d=14h
One other thing. Hex numbers do not contain the letter "O." Anything that looks like an "O" is bound to be a "0" (zero). On the other hand, any number that is not made up of an even number of digits (usually 2 or 4) can not be hex.


Two-Fifty-Six-imal

That sounds like a made-up word, doesn't it? It should--it's my own invention. There's probably a fancy Greek or Latin derivative to describe this form of notation--or more likely a word with one parent from each language, as is the case with "hexadecimal" but I don't know what it would be. I suppose, by analogy with the abbreviation "hex", it would be called "toof", but I'll let that one go.

Two-fifty-six-imal isn't strictly analogous to decimal and hex, by the way, but is perhaps more like the Binary Coded Decimal notation that you run across from time to time. If it really were analogous to decimal and hex, it would require 256 characters, which would exhaust the Latin, Greek, Hebrew, and Cyrillic alphabets, and then some. Not to mention exhausting our patience.

In the 256-imal system, as used in this series, a number mn usually has the value of (256*m)+n. That is, 256 times the value of the first number, plus the value of the second number. You may recognize this system from the earlier chapter, where BC was 256*B+C. The first number in this case is referred to as the "most significant number", since it has 256 times the weight of the second ("least significant") number.

You can't always count on the most significant number coming first, however. To look ahead a bit, the registers of the Z80 are always NAMED with the most significant byte first. You can remember this by the fact that the HL register originally meant "High-Low." However, the memory usually STORES information with the least significant byte first. So the contents of the memory pair 16388/16389 would be

Code: Select all

PEEK 16388 + 256*PEEK 16389.
Don't ask me why Sir Clive did it that way; he probably wasn't the first to do it.

And to make matters worse, there's an exception to the exception--but we'll get to that in due course.

For the moment, remember that the value of a 256-imal number will always be 256*MSN+LSN, where MSN and LSN stand for Most Significant Number and Least Significant Number, respectively. This fact will never change--the only thing that may change from time to time is whether we print MSN or LSN first.

Code: Select all

FIG 5 -6.  SOME ZX81 ADDRESSES 
           IN 256-IMAL 

NUMBER  NUMBER IN  ZX81 SIGNIFICANCE
IN DEC  256-IMAL   OF THIS ADDRESS
        LSN MSN
16388    4  64      RAMTOP
16389    5  64

16396   12  64      D-FILE
16397   13  64

16400   16  64      VARS
16401   17  64

16404   20  64      E-LINE
16405   21  64

16421   37  64      LAST KEY
16422   38  64       PRESSED 

16507  123  64      SPARE BYTES
16508  124  64       OF MEMORY

16509  125  64      FIRST BYTE
                     OF PROGRAM

16514  130  64      FIRST BYTE
                     OF 1 REM
You will see why we need a system like 256-imal if you recall that each byte in computer memory will handle numbers from 0 to 255. Any number higher than 255 is stored in two successive bytes, in 256-imal.

A typical use of 256-imal would be in storing the values of memory addresses. The addresses that you most often will use are from 16507 on up. Figure 5-6 lists a number of ZX81 addresses that are particularly useful, along with their equivalents in 256-imal. You'll notice that you will be using 64 as the most significant number more often than any other value. For this reason, you might find it useful to memorize the fact that 256*64=16384, so that you can quickly compute in your head the 256-imal value of the most-often used memory addresses.


Problem

What is the largest number that can be expressed in 256-imal? See if you can figure it out for yourself before you read further.


Answer

Remember that the largest number a single byte can store is 255. The largest number in 256-imal, then, is two bytes of 255 each, or 256*255+255, or 65535.

You may recognize this as the equivalent of 256*256-1 (or 256**2-1). This gives the 256-imal system a total capacity of 256*256 numbers (counting 0), just as two digits of binary have a repertoire of 4 values (0-3), while two decimal digits can represent any one of 100 values (0-99).

And that's it for now. There will be more.
MrVertigo
Posts: 105
Joined: Fri May 27, 2022 9:06 pm

Re: BASIC MACHINE CODE FOR THE ZX81

Post by MrVertigo »

How would you enter RUBOUT in the REM line? (The character for ld(hl), a)

Is there any way to do that, or do you have to poke 119 into the relevant address?
User avatar
mrtinb
Posts: 1906
Joined: Fri Nov 06, 2015 5:44 pm
Location: Denmark
Contact:

Re: BASIC MACHINE CODE FOR THE ZX81

Post by mrtinb »

Yes, I think you should POKE it in. And don't edit the line afterwards. I think that would destroy the code.
Martin
https://zx.rtin.be
ZX81, Lambda 8300, Commodore 64, Mac G4 Cube
MrVertigo
Posts: 105
Joined: Fri May 27, 2022 9:06 pm

Re: BASIC MACHINE CODE FOR THE ZX81

Post by MrVertigo »

Thanks!
Post Reply