.........1.........2.........3.........4.........5.........6.........7.........8

Mastering Machine Code on Your Spectrum
part 1 of 8 - from ZX Computing Oct/Nov'82

Toni Baker, author of "Mastering Machine Code on Your ZX81"
turns her attention to the Spectrum with this article, the
first in a series designed to take you through machine code
from its very beginnings to its ultimate conclusions.


Inside the Spectrum is a tiny little black box mystically
referred to as a "z80A". In fact the Z80A is the only part
of the whole computer that actually does any thinking. To
put it another way, the Z80A is the computer. The ROM is not
a computer - the ROM just contains a computer program. The
Z80A speaks a language we call MACHINE CODE. It does not
speak BASIC. When you RUN a BASIC program, what's really
happening is that the Z80A is running a program in the ROM
which tells it to look at what's written down in the RAM and
then take appropriate action.

Machine code has variables just like in BASIC, but they're
not quite as flexible. The registers are called A, B, C, D,
E, H, and L, and they can only store integers from 0 to 255.
It's easier to work in hexadecimal so I'll do that from the
start - 00 means 0 and FF means 255. In general two symbols
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E or F) written
next to each other means sixteen times the first digit, plus
the second digit - leading zeroes are therefore optional -
however DON'T waste your time converting things back to
decimal all the time - you don't need to. 5A is obviously
bigger than 3E because 5 is bigger than 3. In the same way
D7 is a bigger number than AA.

It is not necessary to change the numbers into decimal first
- it is better to get a kind of "feel" for the size of a
number in hex without actually knowing what it is. After
all, that's all we do in decimal isn't it? I bet you can't
imagine a pile of (exactly) seventy three pennies.

A variable in machine code can therefore hold any number
between 00 and FF. A machine code variable is called a
REGISTER. There are no error traps in machine code, and so
if you try to add up two numbers whose sum is more than FF
you will get the wrong answer (in actual fact it will be 100
(hex) less than the real answer) - the last two digits will
be the only ones that count. Take a look at this little
segment of machine code:

LD A,9A - This is like a LET statement. Register A now holds
the number 9A.

ADD A,88 - In machine code you can only do one thing at a
time - you cannot, eg. say LD A,9A + 88 as you could in
BASIC. What value does the A register now contain? The
answer is 22. Try to do the adding up in hex: A plus 8
equals 2 carry 1; 9 pIus 8 plus the carry is also 2 carry 1;
this carry is "lost".

Registers can also be used in pairs. The only combinations
allowed are BC, DE, and HL. If B contains 61 and C contains
A7 then we say that BC contains 61A7. This is a four digit
hexadecimal number. Its size is intuitively just a bit
bigger than 6000, and a lot less than 7000. Similarly, if HL
contains 1234 we say that H contains 12 and L contains 34.


HOW do we actually USE machine code?

When the ZX83 comes out, hopefully there will be a few
buttons marked with machine code instructions. Until that
happens we unfortunately have to do some translating. Each
machine code instruction has a number - a sort of index.
Instruction number one is LD BC, - something like a LET
statement in BASIC. All the Z80A needs is a list of numbers.
Whenever it comes across the number 01 it knows it has to
carry out the operation LD BC; it also of course expects a
four digit number next so that it knows what to load BC
with. This index number is called a HEX CODE.

The words we use for the instructions are sometimes called
OP CODES (Operation Codes). For every OPcode there is a
HEXcode, and for every HEXcode there is an Opcode.

The computer needs the HEXcodes in its programs. Humans on
the other hand find it easier to use the Opcodes. When
writing down a machine code program on a piece of paper we
usually then write BOTH versions next to each other - like
this:

C9 RET

Here C9 is HEXcode which the computer will understand. RET
is our way of writing it. RET means RETURN; either "Return
to BASIC" as we shall use very shortly, or "Return from a
subroutine" which I shall cover in a later article.

Every machine code program you write, must end with a RET
instruction.


The meaning of USR

USR is a function in BASIC - it's very much like a cross
between a GOSUB statement and user defined (numerical)
function. It looks very much like a functIon in appearance:
USR X has the same "shape" as SIN X or INT X, and can be
used in exactly the same circumstances. But if SIN X equals
the height of a sine wave at position X, and if INT X equals
X with all of its decimals banished, what number does USR X
give us? ANSWER: USR X gives us the value of the BC
register. A machine code program is run every time USR is
used, and the number or variable or whatever after the word
USR must be the address of the start of a program written in
machine code. For example, consider this machine code
program:

010000  LD BC,0000
C9      RET

If X was the address of the "01" in the above, then what
number would USR X give us? RET, remember, means return to
BASIC, and so BC ends up as zero. In this case USR X would
give us a value of zero, so PRINT USR X would print 0, and
LET Y = USR X would assign Y with zero, and so on.

Our next problem is how do we get the machine code into the
computer in the first place? The only way to do it is with a
BASIC program. Take a look at the program in Fig.1. It's
called HEXLD, and I shall explain what it does and how it
works.

- Fig.1 HEXLD - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

  10 DEF FN k(x)=CODE "01234567890000000:;<=>?00000000000000000000000000:;<=>?"(CODE a$(x)-47)-48
  20 LET a$=""
  30 INPUT x
  40 IF a$="" THEN INPUT a$
  50 POKE x,16*FN k(1)+FN k(2)
  55 PRINT a$(TO 2);"  ";
  60 LET a$=a$(3 TO)
  70 LET x=x+1
  80 GO TO 40

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

The first line is a user-defined function which turns a
string character into a number. Its effect is to turn "0"
into 0, "1" into 1, and so on until "9" which becomes 9. In
addition "A" becomes ten, "B" becomes eleven, and so on up
to "F" which becomes fifteen. Small letters are also taken
into account and so "a" also becomes ten, and so on up to
"f" which gives fifteen just as if it were a capital. The
rest of the program is your HEX LOADER.

To use the program type RUN, then input a (decimal) address.
Input 24576 here (for no other reason than the fact that in
hex 24576 is written as 6000). Now all you need to type in
is your machine code. Type in "010000" and then "C9". To
stop the program type in just a newline - this will cause
error code 3. You now have a machine code program. Type
PRINT USR 24576 to see if it gives zero as it should. If you
want to see what you're doing change line 40 to read IF a$
"" THEN INPUT a$: PRINT a$

- Fig.2 The listing of HEXLD3 - - - - - - - - - - - - - - - - - - - - - - - 

  10 PRINT " LIST ";
  20 GO SUB 8000
  30 RANDOMIZE USR 65055
  40 STOP
 100 PRINT "WRITE ";
 110 GO SUB 8000
 120 INPUT a$: PRINT ;
 130 RANDOMIZE USR 65152
 140 PRINT a$
 150 GO TO 120
 200 PRINT "INSERT ";
 210 GO SUB 8000
 220 INPUT a$: PRINT ;
 230 RANDOMIZE USR 65109
 240 PRINT a$
 250 GO TO 220
 300 GO SUB 320
 310 STOP
 320 PRINT " DELETE ";
 330 GO SUB 8000
 340 PRINT "     TO ";
 350 GO SUB 9000
 360 RANDOMIZE USR 65235
 370 RETURN
 400 SAVE "HEXLD3" LINE 460
 410 SAVE "HEXLD3 MC" CODE 65016,353
 420 SAVE " " CODE FN p(65016),FN p(65024)-FN p(65016)+1
 430 VERIFY ""
 440 VERIFY "" CODE
 450 VERIFY "" CODE: STOP
 460 BORDER 0: INK 7: PAPER 0: FLASH 0: BRIGHT 0
 470 CLEAR 65015
 480 LOAD "" CODE: LOAD "" CODE: STOP
 500 PRINT "BEGIN ";
 510 GO SUB 8000
 520 RANDOMIZE USR 65264
 530 STOP
 600 PRINT "REPLACE ";
 610 GO SUB 330
 620 GO TO 220
 700 PRINT " RUN ";
 710 GO SUB 8000
 720 RANDOMIZE USR FN p(65018)
 730 STOP
 800 PRINT " COPY ";: GO SUB 8000
 810 PRINT "      ";: GO SUB 9000
 820 PRINT "   TO ";
 830 INPUT "ADDRESS ";a$
 840 PRINT "ADDRESS ";a$
 850 POKE 65022,16*FN k(a$,3)+FN k(a$,4)
 860 POKE 65023,16*FN k(a$,1)+FN k(a$,2)
 870 RANDOMIZE USR 65275
8000 INPUT "ADDRESS ";a$
8010 PRINT "ADDRESS ";a$
8020 POKE 65018,16*FN k(a$,3)+FN k(a$,4)
8030 POKE 65019,16*FN k(a$,1)+FN k(a$,2)
8040 RETURN
9000 INPUT "ADDRESS ";a$
9010 PRINT "ADDRESS ";a$
9020 POKE 65020,16*FN k(a$,3)+FN k(a$,4)
9030 POKE 65021,16*FN k(a$,1)+FN k(a$,2)
9040 RETURN
9050 DEF FN k(x$,y)=CODE "01234567890000000:;<=>?00000000000000000000000000:;<=>?"(CODE x$(y)-47)-48
9060 DEF FN h(x$)=4096*FN k(x$,1)+256*FN k(x$,2)+16*FN k(x$,3)+FN k(x$,4)
9070 DEF FN k$(x,y)="0123456789ABCDEF"(INT (x/16^y)-16*INT (x/16^(y+1))+1)
9080 DEF FN h$(x)=FN k$(x,3)+FN k$(x,2)+FN k$(x,1)+FN k$(x,0)
9090 DEF FN p(x)=PEEK x+256*PEEK (x+1)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

- Fig.3 The code for HEXLD3 - - - - - - - - - - - - - - - - - - - - - - - - 

FE02: F5     << [This line was missed out in the magazine. JG.]

FE03: E6	FE59: 4E	FEAF: 40	FF05: 44	
FE04: F0	FE5A: 23	FEB0: 38	FF06: 4D	
FE05: 1F	FE5B: 46	FEB1: 04	FF07: 03	
FE06: 1F	FE5C: C8	FEB2: E6	FF08: 2A	
FE07: 1F	FE5D: 28	FEB3: DF	FF09: FE	
FE08: 1F	FE5E: CB	FEB4: D6	FF0A: FD	
FE09: C6	FE5F: 19	FEB5: 07	FF0B: EB	
FE0A: 30	FE60: 20	FEB6: D6	FF0C: A7	
FE0B: FE	FE61: 02	FEB7: 30	FF0D: ED	
FE0C: 3A	FE62: CF	FEB8: 82	FF0E: 52	
FE0D: 38	FE63: 14	FEB9: D1	FF0F: 19	
FE0E: 02	FE64: C5	FEBA: 12	FF10: 38	
FE0F: C6	FE65: 2A	FEBB: 13	FF11: 04	
FE10: 07	FE66: 00	FEBC: ED	FF12: ED	
FE11: D7	FE67: FE	FEBD: 53	FF13: B0	
FE12: F1	FE68: ED	FEBE: FA	FF14: CF	
FE13: E6	FE69: 5B	FEBF: FD	FF15: 08	
FE14: 0F	FE6A: FA	FEC0: E5	FF16: 09	
FE15: C6	FE6B: FD	FEC1: 2A	FF17: 2B	
FE16: 30	FE6C: A7	FEC2: 00	FF18: EB	
FE17: FE	FE6D: ED	FEC3: FE	FF19: 09	
FE18: 3A	FE6E: 52	FEC4: ED	FF1A: 2B	
FE19: 38	FE6F: 23	FEC5: 52	FF1B: EB	
FE1A: 02	FE70: 44	FEC6: E1	FF1C: ED	
FE1B: C6	FE71: 4D	FEC7: 30	FF1D: B8	
FE1C: 07	FE72: E1	FEC8: 04	FF1E: CF	
FE1D: D7	FE73: ED	FEC9: ED	FF1F: 08	
FE1E: C9	FE74: 5B	FECA: 53	FF20: CD	
FE1F: 2A	FE75: 00	FECB: 00	FF21: 02	
FE20: 00	FE76: FE	FECC: FE	FF22: FE	
FE21: FE	FE77: 19	FECD: 0B	FF23: 3E	
FE22: 22	FE78: 22	FECE: 78	FF24: 20	
FE23: FC	FE79: 00	FECF: B1	FF25: D7	
FE24: FD	FE7A: FE	FED0: 20	FF26: 78	
FE25: 54	FE7B: EB	FED1: CA	FF27: CD	
FE26: 5D	FE7C: ED	FED2: C9	FF28: 02	
FE27: 2A	FE7D: B8	FED3: 2A	FF29: FE	
FE28: FA	FE7E: 00	FED4: 00	FF2A: 3E	
FE29: FD	FE7F: 00	FED5: FE	FF2B: 20	
FE2A: A7	FE80: 2A	FED6: ED	FF2C: 47	
FE2B: ED	FE81: 4B	FED7: 5B	FF2D: D7	
FE2C: 52	FE82: 5C	FED8: FC	FF2E: 79	
FE2D: 19	FE83: 23	FED9: FD	FF2F: CD	
FE2E: D0	FE84: 4E	FEDA: D5	FF30: 02	
FE2F: 7C	FE85: 23	FEDB: A7	FF31: FE	
FE30: CD	FE86: 46	FEDC: ED	FF32: 78	
FE31: 02	FE87: CB	FEDD: 52	FF33: D7	
FE32: FE	FE88: 28	FEDE: 44	FF34: 7A	
FE33: 7D	FE89: CB	FEDF: 4D	FF35: CD	
FE34: CD	FE8A: 19	FEE0: 03	FF36: 02	
FE35: 02	FE8B: 28	FEE1: E1	FF37: FE	
FE36: FE	FE8C: D5	FEE2: 23	FF38: 78	
FE37: 3E	FE8D: ED	FEE3: ED	FF39: D7	
FE38: 20	FE8E: 5B	FEE4: 5B	FF3A: 7B	
FE39: D7	FE8F: FA	FEE5: FA	FF3B: CD	
FE3A: 7E	FE90: FD	FEE6: FD	FF3C: 02	
FE3B: CD	FE91: 7A	FEE7: ED	FF3D: FE	
FE3C: 02	FE92: CD	FEE8: B0	FF3E: 78	
FE3D: FE	FE93: 02	FEE9: 1B	FF3F: D7	
FE3E: 3E	FE94: FE	FEEA: 1B	FF40: 7C	
FE3F: 20	FE95: 7B	FEEB: ED	FF41: CD	
FE40: D7	FE96: CD	FEEC: 53	FF42: 02	
FE41: 7E	FE97: 02	FEED: 00	FF43: FE	
FE42: FE	FE98: FE	FEEE: FE	FF44: 78	
FE43: 20	FE99: 3E	FEEF: C9	FF45: D7	
FE44: 38	FE9A: 20	FEF0: 2A	FF46: 7D	
FE45: 05	FE9B: D7	FEF1: FA	FF47: CD	
FE46: FE	FE9C: 23	FEF2: FD	FF48: 02	
FE47: A5	FE9D: 7E	FEF3: 22	FF49: FE	
FE48: 30	FE9E: FE	FEF4: F8	FF4A: 3E	
FE49: 01	FE9F: 40	FEF5: FD	FF4B: 0D	
FE4A: D7	FEA0: 38	FEF6: 2B	FF4C: D7	
FE4B: 3E	FEA1: 04	FEF7: 22	FF4D: E1	
FE4C: 0D	FEA2: E6	FEF8: 00	FF4E: 7C	
FE4D: D7	FEA3: DF	FEF9: FE	FF4F: CD	
FE4E: 23	FEA4: D6	FEFA: C9	FF50: 02	
FE4F: 22	FEA5: 07	FEFB: ED	FF51: FE	
FE50: FA	FEA6: 87	FEFC: 5B	FF52: 7D	
FE51: FD	FEA7: 87	FEFD: FA	FF53: CD	
FE52: 18	FEA8: 87	FEFE: FD	FF54: 02	
FE53: D6	FEA9: 87	FEFF: 2A	FF55: FE	
FE54: 00	FEAA: D5	FF00: FC	FF56: CF	
FE55: 2A	FEAB: 57	FF01: FD	FF57: 14	
FE56: 4B	FEAC: 23	FF02: A7		
FE57: 5C	FEAD: 7E	FF03: ED		
FE58: 23	FEAE: FE	FF04: 52		

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


For advanced programmers ...

Figures 2 and 3 give a machine code editing program called
HEXLD3. You can load it into the computer using HEXLD as
above. Its purpose is to allow you to construct and edit
other programs in machine code. To avoid confusion the hex
given in Fig.3 is called the "object program" - the machine
code you will use it to edit is referred to as the "subject
program". You should not attempt to use HEXLD3 to edit
itself.

If you are using a 16K machine instead of a 48K machine you
must subtract 32768 from each address used in the BASIC, and
you must change each address referred to in the machine code
which begins with F into the corresponding address beginning
with 7.

The features of the program are as follows:

- Fig.4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

The arrangement of the variables and machine code routines of HEXLD3.

16K   48K
---   ---
7DF8  FDF8  BEGIN    Points to the first byte of the subject program.
7DFA  FDFA  ADDRESS )
7DFC  FDFC  ADD2    )Parameters used by HEXLD3.
7DFE  FDFE  ADD3    )
7E00  FE00  LIMIT    Points to the first byte after the subject program.
7E02  FE02  HPRINT   Subroutine to print the contents of the A register
                     in hexadecimal.
7E1F  FE1F  HLIST    List subject program in hexadecimal.
7E55  FE55  INSERT   Inserts additional bytes into subject program.
7E80  FE80  WRITE    Overwrites subject program with new code.
7ED3  FED3  DELETE   Deletes bytes from the subject program.
7EF0  FEF0  BEGINMC  Sets BEGIN and LIMIT ready for creating a new 
                     subject program.
7EFB  FEFB  HCOPY    Overwrites subject program with bytes copied from
                     elsewhere.
7F20  FF20  BREAKP   Break point routine.
7F58  FF58           Next spare byte - user defined graphics may begin here.

I am sorry if there is insufficient space to list the machine code for HEXLD3
in full. You may like to translate it for yourself as an exercise if you are
sufficiently masochistic.

RUN             List machine code in hex from any hex address.
RUN 100         Write your own machine code as in HEXLD above.
RUN 200         Insert bytes of machine code between existing bytes.
RUN 300         Delete bytes of machine code, closing up the gap which they
                occupied.
RUN 400         SAVEs first the BASIC, then the object program, then the
                subject program, then verifies all three.
RUN 500         Initially assigns variables used by this program. RUN 500 must
                be used only if you are creating a new program from scratch.
RUN 600         Equivalent to DELETE followed by INSERT at the same address.
RUN 700         RUN machine code from any address.
RUN 800         Copy blocks of machine code from one address to another.
FN H(string)    Changes hex to decimal; eg. FN H("002A") = 42.
FN H$           Changes decimal to hex; eg. FN H$(42) = "002A".
(number)        [sic. JG.]
FN P (address)  Equivalent to PEEK (address) + 256 * PEEK (address+1)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--
