.........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

--

