ZX Classroom: Machine Code (Introduction, Part II)
In the previous issue, we briefly explained what an assembler and a disassembler are, but that was a very cursory explanation. It would be best to contact the Kompjuter library, Bate Jankovića 79, 32000 čačak (tel. 032/30-34), for instructions on assembling with GENS. Since we will gradually explain what machine code is, you will not need an assembler for a few more issues, until you have learned the most important things about machine code.
The computer’s memory is easiest to imagine as a long row of compartments, or cells, which can remember only what is put into them.
Each such cell is called a BYTE. One kilobyte contains 1024 bytes, and one megabyte contains 1024 kilobytes, or 1048575 bytes. You may be wondering why we use 1024 instead of the round number 1000, but computers do not work in the decimal number system; they work in the binary system, where 1024 is a perfectly round number. Now you may be asking how I can find the byte I need among the Spectrum’s 65535 bytes. The answer is simple. Every byte has its own label, which lets you find it easily in memory.
That label is called an ADDRESS. In fact, it is a whole number in the range from 0 to 65535. Each byte has a number by which you can find it. So the first byte has the number 0, the second 1, the third 2, the two-thousand-and-sixth byte 2005, and so on. The microprocessor can find any bit in it. Now you may be wondering what a bit is. Each byte consists of eight elementary cells, which we call BITS.
Each bit can be set or reset; that is, if it is set, it contains a one, and if it is reset, a zero. The entire byte can therefore also be understood as a binary number with eight digits. Bit 0 has the lowest weight, while bit 7 has the highest weight.
But let’s return to how—and with what—we can read any bit in memory.
This can be done in BASIC with the PEEK command. To use PEEK, you cannot simply type PEEK 0 and expect the computer to tell you what is in byte 0. First you must type PRINT PEEK 0. The computer will then print the number 243, which means that the first byte of memory contains the value 243.
That does not mean anything to us at the moment, but when we convert that number to binary (hence the BIN command), we get 11110011. This means that the first four bits are set, the fifth and sixth are reset, and the seventh and eighth are set.
Memory is divided into two large blocks. The first 16Kb, from address 0 to 16383, is ROM (Read Only Memory / pronounced “read only memory”). This means that you cannot write anything to these memory locations; they can only be read by the CPU. The manufacturer has stored all the instructions needed for the computer to work properly in ROM, and those instructions remain saved even when the computer is switched off.
Here is another calculation that may help you understand the size of ROM memory: 16x1024=16384. The rest of the memory, starting at address 16384, is called RAM (Random Access Memory). All you need to know about it is that you can write whatever you like to it, at your own risk.
Access to these bytes, from 16383 to 65535 (that is, 48x1024=49152 bytes), is completely unrestricted, but when you switch off the computer, all data in RAM is lost forever.
You can write whatever you like into bytes directly from BASIC, using the POKE N,M command, where N is the byte number and M is the byte’s value.
For example: POKE 23609,255 will produce a sound when you press the keys, and that value in bits is 255=11111111.
It should also be noted that understanding the structure of the computer’s entire memory is essential, because blindly using POKE will most often cause a crash and reset the computer.
MEMORY MAP
address data
0 ROM
16384 Video memory, image content data
ZX Classroom: Machine Code (Part II)
22528 — Information about color, brightness, and flashing.
23926 — Memory used for working with the printer.
23552 — System variables.
23734 — Data for working with the Microdrive.
Address — Data
CHANS — Information about the channels used for exchanging data with peripheral devices.
PROG — BASIC program. This address is usually …
VARS — Variables in the BASIC program.
E LINE — Contents of the editor lines.
WORKSP — Data entered with the INPUT command and data used when adding strings.
STKBOT — The computer stack, temporary memory used in calculations.
STKEND — Free space.
Spare — Machine stack.
— GOSUB stack.
RAMTOP — Data that is not available to the BASIC program begins here.
Finally, I recommend that you read in detail about the system variables at addresses 23552 through 23734 in the Spectrum manual, as they are very important for machine-code programming.
Prepared by:
Žosić Saša
Podgaj 11
71000 Sarajevo
ZX Ideas
a) SCREEN Hunter
b) Days of the Week
a) SCREEN Hunter
Many games contain complete SCREEN$ files that you cannot see while they are loading, but only during the game. If you are curious and would like to see them, or even save them, you can use this program to find them. Press L to load the block in which you expect the SCREEN$. Use keys 1, 2, 9, and 0 to search for the SCREEN$.
Once you find it, you can also see how it is coloured by pressing A.
If the screen colours look strange, press O (the letter O, not zero) and everything will be back to normal. If you have found a SCREEN$ and want to save it, press S, enter the name of the SCREEN, and save it to tape. You can load the saved SCREEN$ with an ordinary LOAD SCREEN$.
Make sure to type the DATA lines in lowercase.
15 CLEAR 40000:PRINT TRENU TAK...
:LET d=65255
20 FOR l=1 TO 35:READ ač:LET k=0
30 FOR a=0 TO 7:GO SUB 100:
POKE d,b:LET k=k+b:LET d= d+1:NEXT a
40 GO SUB 100:LET p=b:GO SUB 100:
LET p=p+b!256:IF p<>k THEN PRINT GRE$KA U LINI JI BROJ ;1000+(l-1)!10' POPRAVI JE I PONOVO START UJ PROGRAM SA RUN :STOP
50 NEXT l
60 CLEAR :PRINT DEKODOVA NJE ZAVR$ENO SNIMI PROGRAM :RANDOMIZE USR 70
STOP
100 LET y=CODE ač-48:LET y= y-39!(y>9):LET z=CODE ač(2)-48:LET z=z-39!(z >9):LET b=16!y+z:LET ač=ač(3 TO ):RETURN
1000 DATA 000000210100cd6e5 d01
1010 DATA 19e521cf07cd6e194
1020 DATA d1cde51921ee0722d
1030 DATA 425c3e0132445cc97
1040 DATA d2ffcd3e08326a5cd c03
1050 DATA afcd0116184f3e013
1060 DATA 8677d2c3ff3f23342
1070 DATA c3c3ff7e160192772
1080 DATA d2c3ff3f2335c3c3b
1090 DATA fffdcb01ae76fdcbb
1100 DATA 016e28f93a085c214 f02
1110 DATA e8fffe3228d9fe314
1120 DATA 28e32bfe3028c7fe5
1130 DATA 3928d0fe532844fee c03
1140 DATA 4c2845fe412816fe3
1150 DATA 4f2828185fed4be73
1160 DATA ff606911004001001 a02
1170 DATA 18edb01855ed4be74
1180 DATA ff6069af110018ed8 d03
1190 DATA 5a11005801c002ed7
1200 DATA 60183f01c0022100e b01
1210 DATA 581101583e3877ed9 c02
1220 DATA b0182fed4be7ffc9d e04
1230 DATA dd21a76111619dafc
1240 DATA d3fe3708cd5905dd1
1250 DATA e5e111a97cafed52e a04
1260 DATA 38e611a861ed53e75 f04
1270 DATA ffc30affaf32085c1
1280 DATA 189b3e16d7afd7af1
1290 DATA d7af11e9ffcd0a0c6
1300 DATA ed4be7ffcd2b2dcd1
1310 DATA e32d3e06d7c330ff1 d04
1320 DATA a861807f204a616e4
1330 DATA 6b6f205354414d457
1340 DATA 4e4f56494316019a3
1350 STOP
2000 LET bc=USR 65290:DIM ač (9):INPUT IME?
LINE ač:LET ač=CHRč 170+ač
2010 SAVE ačCODE bc,6912:RUN
2020 CLEAR 24998:LOAD CODE:RUN
2030 SAVE SCR TRAGAč LINE 2020:SAVE SC.T.CODE CODE 65290,246
Prepared by:
ZX Classroom: Machine Code (Part II)
b) Days of the Week
10 REM ! LLIST ZX-SPECTRUM !
20 DIM Xč(7,10)
30 DATA SUNDAY MONDAY
40 DATA TUESDAY WEDNESDAY THURSDAY
50 DATA FRIDAY SATURDAY
60 FOR I=1 TO 7
70 READ Xč(I)
80 NEXT I:CLS
90 PRINT AT 0,0
100 PRINT "ENTER DATE:"
110 INPUT "YEAR=";G:LET G=INT G
120 PRINT "YEAR=";G
130 INPUT "MONTH=";M:LET M=INT M
140 IF M<1 THEN GO TO 130
150 IF M>12 THEN GO TO 130
160 PRINT "MONTH=";M
170 INPUT "DAY=";D:LET D=INT D
180 IF D<1 THEN GO TO 170
190 IF D>31 THEN GO TO 170
200 PRINT "DAY =";D
210 LET Y=G:LET Q=M
220 IF M>2 THEN GO TO 240
230 LET Y=G-1:LET Q=M+12
240 LET A=INT (Y/100)
250 LET B=2-A+INT (A/4)
260 IF G>1582 THEN GO TO 290
270 IF M>10 THEN GO TO 290
280 IF D<15 THEN LET B=0
290 LET J=INT (365.25*Y)
300 LET J=J+INT (30.6001*(Q+1))
310 LET JD=J+B+D+1720994.5
320 LET I=(JD+2)/7
330 LET I=1+INT (7*(I-INT I))
340 PRINT AT 10,0; "DATE:"
350 PRINT D;"/";M;"/";G; " YEAR"
360 PRINT "OF THE GREGORIAN CALENDAR"
370 PRINT "IS: ";Xč(1)
380 GO TO 90
Prepared by:
Pajović Nenad
V.KaraŠorŠa 22
15004 Jelenča
ZX Curiosities
a) Adding New BASIC Commands
b) Sound Effects
c) TAPPE LOAD ERORR ?
a) Adding New BASIC Commands
This section gives only a brief theoretical overview of how it is possible to add new BASIC commands to the existing ones. To create a new command, you need to know the Z80 processor’s machine language and how the computer’s operating system functions. On most personal computers, the built-in operating system allowed users to create and add their own BASIC commands.
The designers did not provide this facility on the Spectrum. It was only with the Interface 1 operating system that a facility was built in to make it easy to add commands to suit your own needs.
The I-1 has a system variable, VECTOR, responsible for these operations.
When creating a new command, it is important that it causes an error both during syntax checking and during interpretation. Here are a few examples of how this can be done:
-POKE 0,1,2 = unnecessary parameter
-DRAW 10 = omitting a required parameter
-PLOT ,10 = incorrectly specified parameter
-CODE = using a function from E-MODE
-!AUTO = adding a new command
In this last case, type the command one letter at a time. Choose a character that is not a letter for the first character.
After this character, the cursor will move in and you will be able to enter the new command one letter at a time. After the first character (which is not a letter), you can also type existing BASIC keywords; they will then take on a new meaning.
Creating a New Command
To create and add new commands, you need:
- A good knowledge of the Z80 processor’s machine language.
- Knowledge of how the computer’s operating system works and how errors are handled in the additional 8K ROM.
How the BASIC Interpreter Works
This part of the program in the 16K ROM processes every BASIC command twice. The first time, it checks only the syntax; the second time, it executes the command.
For example, if you want to add a program line containing one command to an existing program, you can divide the whole process into three parts:
- The programmer enters the command (e.g.
100 PLOT 0,0) in the lower part of the screen. While the program line is being entered, it is stored in the EDIT BUFFER. Once entry is complete (by pressing ENTER), it is copied from there to the upper part of the screen and inserted into the program.
ZX Classroom: Machine Code (Part II)
- When ENTER is pressed, the interpretation program begins checking the syntax of the line just entered in the EDIT BUFFER. First, it identifies the PLOT command, then looks for two numeric arguments separated by a comma. If it finds them, the line is copied to the upper part of the screen, where it takes the position specified by its line number.
Finally, control returns to the editor, and the computer is ready for a new line to be entered. If no valid command or required argument is found during the syntax check, the appropriate error message is displayed, and the program line is not copied from the EDIT BUFFER. Even if a command is syntactically correct, that does not guarantee that it will execute correctly. For example, the following command is syntactically correct, but will still produce an error if you try to execute it:
100 PLOT 200,200
- A command is executed with RUN or GO TO. The BASIC interpreter now starts identifying the command again, step by step, and executes the appropriate routine in ROM. If an error occurs, execution is stopped and the appropriate error message is displayed.
ERROR CHECKING
If an error occurs while checking syntax or while executing a command, a subroutine at address 0008 in the 16K ROM is called. This call is most often made with the instruction:
RST 8
DEFB -N=error code
When an error is detected during the syntax check, a question mark is displayed at the point where the error most likely occurred; during execution, the appropriate error message is displayed. If an I-1 is also connected to the computer, this error-checking process changes slightly.
Jumping to address 0008 in the 16K ROM causes the ROM to be paged. The old 16K ROM is switched off, the new, additional 8K ROM in the I-1 is switched on, and error checking continues there. First, we check the return address of the routine that caused the jump to address 0008. We load this address into the HL register pair. If the value in HL is zero, then the return is from a 16K ROM routine called by the I-1. If HL = 15FE h, then a search for an I-1 channel has just finished. If the error code is not one of the following three:
NONSENSE IN BASIC
INVALID FILE NAME
INVALID STREAM
then control is returned to the main 16K ROM, which will display the actual error message. However, if the error code is one of those listed above, it may have been caused by one of our new commands. The entire line where the error occurred must therefore be interpreted again.
First, the system saves the address pointer, CH-ADD (5C5D h), in CHADD- (5CCB h), marking how far it has got in interpreting the line, so that it can restore this value later.
The routine that starts at this address restores the value from CHADD- to CH-ADD and continues by displaying the error message in the 16K ROM. This means that we can use our own routine by means of the routine whose address is specified by VECTOR. All we need to do is write the starting address of the routine that will check the syntax and then execute the appropriate routine into VECTOR before executing our command. Make sure your commands do not begin with any command intended for use with the Microdrive and the I-1.
When writing a command’s execution routine, bear the following in mind:
- When making a jump or calling a subroutine, you always remain in the 8K ROM (all addresses refer to the additional ROM, not the main ROM).
- Call a subroutine in the I-1 ROM with the CALL instruction; do not use HOOK CODE.
- While a routine is executing in the 8K ROM, neither the keyboard state nor the internal clock (FRAMES) is read, regardless of whether interrupts are enabled or disabled.
The internal clock cannot be used during this time.
ZX Classroom: Machine Code (Part II)
And you’ll have to take care of reading the keyboard yourself in your program.
- Using the restart routine produces a different effect from the one in the 16K ROM.
Contribution by:
Brada Jožef Bajmočka 18 24220 čantavir
b) SOUND EFFECTS
DARKO from Majdanpek sent us two programs that produce certain sound effects.
Here are the programs:
10 FOR n=50000 TO 50040: READ a: POKE n,a: NEXT n
20 DATA 17,152,2,6,10,197,58,
30 RANDOMIZE USR 50000: IF INKEY$="" THEN GO TO 30
Adding the following line to the previous program produces a buzzing sound:
25 POKE 50000,17: POKE 50001,1: POKE 50002,23
Contribution by:
Radulović Darko O.Š. Debeli Lug 19250 Majdanpek
c) TAPPE LOAD ERORR ?
It must have happened to you: you got a tape with programs (some people call them games), and one of the programs wouldn’t load. Usually, the computer would freeze at startup or later, or perhaps reset itself.
You check the program on your next-door neighbour’s Spectrum, and it works.
You immediately suspect your tape recorder and try adjusting the azimuth, changing the volume, moving the equalizer controls...
But that doesn’t help. Finally, visibly confused and annoyed, you decide to buy a new tape recorder. You sit down impatiently, put the tape in the recorder, press PLAY, and it starts loading. You reach the point where your computer used to freeze with that program, and—to your surprise—the program freezes again.
The fault isn’t in the tape recorder or the program, but in your Spectrum’s ROM. Since there are many Spectrum manufacturers, the ROMs also differed from one manufacturer to another. Some added commands; some entered a name instead of the copyright notice; some translated ERRORS into Serbo-Croatian, others into German, and made similar changes to the ROM (see PNP-electronic in its younger days).
As a result, some areas of your memory don’t match the ROM—that is, the 16Kb machine-code program in the ROM, which is made up of various routines—and can’t communicate properly with the loaded program.
This can also happen when using certain EPROM modules and INTERFACES, made all over our country and EUROPE. Quite simply, your ROM from one manufacturer won’t be able to communicate with an INTERFACE from another manufacturer. The usual solution is to have the ROM replaced at your favourite SERVICE CENTRE. You would normally only do this when connecting to hardware via an interface. After all, 10,000 programs have been released for the Spectrum—games and utility programs (unofficially, around 15,000)—so perhaps ten programs, or about 0.7%, won’t work. That’s not enough to make replacing the ROM worthwhile.
Contribution by:
čanković Srđan XII Voj.ud.brigade 59 25000 Sombor
Press A to repeat; press B to continue
LOADING ZX REVIJA
Share your thoughts about the article