Автор: Francis O. Ainley
Год: 1982
Издатели: Oxford Computer Publishing
Языки:
Английский
Формат:
TZX лента
Требования:
ZX Spectrum 16K
Ссылки:
Страница на ZXArt
Страница на World Of Spectrum
Страница на Spectrum Computing
Скриншоты:
Описание:
Machine Code Test Tool (MCTT)— это программное обеспечение, разработанное для компьютераSpectrum ZX, специально для его версий 16k и 48k. Разработанное Фрэнсисом О. Эйнли и опубликованное Oxford Computer Publishing в 1982 году, оно служит учебным и отладочным инструментом для программирования на машинном коде. Программа позволяет пользователям вводить и тестировать свои программы на машинном коде, исследуя структуру ROM и RAM памяти ZX Spectrum.
MCTT особенно полезен для тех, кто интересуется пониманием системы шестнадцатеричных чисел и ее применением к памяти и регистрам компьютера. Он предоставляет практические примеры и практический опыт работы с машинным кодом, предлагая всестороннее введение в микропроцессор Zilog Z80, который используется в ZX Spectrum. Инструмент включает команды для преобразования чисел между десятичной и шестнадцатеричной системами и для изменения памяти и установки точек останова.
Пользователи могут загрузить программу на свой Spectrum ZX, введя определенные команды в зависимости от того, имеют ли они машину 16k или 48k. После загрузки заголовок программы появляется кратко, прежде чем экран очистится, и пользователи могут начать вводить инструкции на машинном коде. Инструмент также включает список команд для изменения памяти, преобразования десятичных чисел в шестнадцатеричные и многое другое, что делает его универсальным дополнением к инструментарию любого программиста.
MCTT является ценным ресурсом для тех, кто желает углубиться в программирование на машинном коде на ZX Spectrum. Он поощряет эксперименты и предоставляет структурированную среду для изучения и тестирования кода. С подробным руководством и обширным набором функций, он остается значимым инструментом для понимания тонкостей машинного кода и архитектуры ZX Spectrum.
Год: 1982
Издатели: Oxford Computer Publishing
Языки:
Формат:
Требования:
Ссылки:
Скриншоты:
Описание:
Machine Code Test Tool (MCTT)— это программное обеспечение, разработанное для компьютераSpectrum ZX, специально для его версий 16k и 48k. Разработанное Фрэнсисом О. Эйнли и опубликованное Oxford Computer Publishing в 1982 году, оно служит учебным и отладочным инструментом для программирования на машинном коде. Программа позволяет пользователям вводить и тестировать свои программы на машинном коде, исследуя структуру ROM и RAM памяти ZX Spectrum.
MCTT особенно полезен для тех, кто интересуется пониманием системы шестнадцатеричных чисел и ее применением к памяти и регистрам компьютера. Он предоставляет практические примеры и практический опыт работы с машинным кодом, предлагая всестороннее введение в микропроцессор Zilog Z80, который используется в ZX Spectrum. Инструмент включает команды для преобразования чисел между десятичной и шестнадцатеричной системами и для изменения памяти и установки точек останова.
Пользователи могут загрузить программу на свой Spectrum ZX, введя определенные команды в зависимости от того, имеют ли они машину 16k или 48k. После загрузки заголовок программы появляется кратко, прежде чем экран очистится, и пользователи могут начать вводить инструкции на машинном коде. Инструмент также включает список команд для изменения памяти, преобразования десятичных чисел в шестнадцатеричные и многое другое, что делает его универсальным дополнением к инструментарию любого программиста.
MCTT является ценным ресурсом для тех, кто желает углубиться в программирование на машинном коде на ZX Spectrum. Он поощряет эксперименты и предоставляет структурированную среду для изучения и тестирования кода. С подробным руководством и обширным набором функций, он остается значимым инструментом для понимания тонкостей машинного кода и архитектуры ZX Spectrum.
MACHINE CODE TEST TOOL
Tutor and Debug Program
ZX Spectrum 16k & 48k Edition
F O Ainley
MACHINE CODE TEST TOOL
for the 16k & 48k Spectrum
Edition Two
INTRODUCTION
Welcome to this introduction to machine code. I have prepared this text to
be used in conjunction with the Machine Code Test Tool program (from here on
abbreviated and referred to as MCTT) in order to give you practical examples
and "hands-on" experience ot using machine code. Using the MCTT you can
enter and test your own machine code programs as well as examine the ZX
SPECTRUM ROM and how your BASIC programs are stored in the RAM memory.
Before beginning to read this book I strongly recommend that your read
chapters 24 and 26 of your Sinclair ZX SPECTRUM Basic Programming book
entitled "The memory" and "Using machine code", and Appendix E of the same
book entitled "Binary and Hexadecimal".
It was not my intention to write a complete treatise on the Zilog Z80 (the
microprocessor used in the ZX SPECTRUM) but if, after completing the
exercises in this book, you wish to go deeper into the subject I can
recommend two books which I have found particularly useful. They are:
Z80 Instruction Handbook Understanding your SPECTRUM
Nat Wadsworth Dr. Ian Logan
OCP Box 99 Oxford Melbourne House Publishers
#6.00 Post Free
LOADING
If you have a 16k ZX SPECTRUM
type LOAD "mctt16" ENTER
or
If you have a 48k ZX SPECTRUM
type LOAD "mctt48" ENTER
and load the program in the normal way. There is a 16k version and a 48k
version of the program on each side of the cassette. On side 1 the 16k
version is followed by the 48k version and on side 2 the 48k version is
followed by the 16k version. When the program is loaded its title will
appear for a short period, the screen will blank for a short period, then
the normal K cursor or Sinclair (c) sign will appear.
Please note that 16k program will not load
on a 48k Spectrum or vice versa. If
"mctt 16" appears first on your 16k
machine this will load successfully. If
"mctt 16" appears first and you have a
48k machine, flip the cassette, rewind
and reload which will enter 48k program
first.
For CHARACTER GENERATOR: type
LOAD "udg" ENTER and program will
start automatically.
To use the MCTT type:
1 LET A=USR 30592 ENTER
if you have a 16k ZX SPECTRUM
or
1 LET A=USR 63360 ENTER
if you have a 48k ZX SPECTRUM
From now on whenever you wish to run the MCTT just type:
RUN ENTER
and the MCTT > cursor will appear in the top left-hand corner of
your T.V. screen.
A complete list of MCTT commands is given in the Appendix.
AN IMPORTANT POINT TO REMEMBER WHEN USING THE MCTT IS THAT TYPING ENTER AT
ANY TIME WILL RETURN YOU TO THE COMMAND MODE. Thus, if you make a mistake,
typing DELETE will have no effect and your only option is to type ENTER.
I will begin with a brief explanation of the hexadecimal number system which
explains the way the MCTT displays information contained within the
computer's registers and memory.
THE HEXADECIMAL NUMBER SYSTEM
Our natural number system is decimal, ie. based on the number 10, because
the physical equipment with which we have been endowed consists of 10
fingers. ThiS is our hardware. In this system 1 character can represent any
one of 10 states, which we label 0, 1 ... or 9.
The natural number system of a digital computer is based on 2 because its
hardware consists of a series of electronic switches which can only register
1 of 2 states, which we label 0 or 1. Because it would be very inconvenient
for us humans to represent values using only 0 and 1 we use the hexadecimal
system which has 16 as its base, which is 2 to the power 4, ie 2x2x2x2.
We would naturally count in the hexadecimal system if we had 16 fingers
instead of 10. In that case, of course, we would need 6 extra characters to
represent the 6 extra fingers. To accomplish this, A-F are used in the
hexadecimal system to represent 10-15.
We now have a number system which is based on 16 instead of 10. To represent
any number between 0 and 15 we need use only one character:
0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. But what about numbers greater than 15? The
system works in exactly the same way as the decimal system: with 2 decimal
characters we can represent any 1 of 100 (10x10) different states (00-99);
with 3 decimal characters any 1 of 1000 (10x10x10) different states
(000-999) and so on, ad infinitum.
With 2 hexadecimal characters we can represent any 1 of 256 (16x16)
different states (00-FF); with 3 hexadecimal characters any 1 of 4096
(16x16x16) different states (000-FFF); with 4 hexadecimal characters any 1
of 65536 (16x16x16x16) different states (0000-FFFF) and so on, ad infinitum.
The MCTT contains a command (D) to convert any decimal number in the range
00000-65535 to its hexadecimal equivalent, and another command (H) to
perform the reverse conversion, ie. any hexadecimal number in the range
0000-FFFF to its decimal equivalent.
Let's see how this works by converting a decimal number to its hexadecimal
equivalent. We will start by choosing the decimal value 200 (this value has
no special significance but is just an example).
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|D00200 | |
| | |D00200=H00C8
| |C8 is the hexadecimal |
| |equivalent of decimal |
| |200 |
Now let's convert a hexadecimal number to its decimal equivalent. In this
example we will choose the hexadecimal value 1000.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|H1000 | |
| | |H1000=D04096
| |4096 is the decimal |
| |equivalent of hexadecimal |
| |1000 |
You should now experiment with these 2 commands in order to reach a better
understanding of the hexadecimal number system. One word of warning: if you
enter (using the D command) a decimal value greater than 65535, which is
outside the conversion range of the command, then the words "=OVERFLOW" will
appear on your T.V. screen - try it and see.
From now on we shall follow every hexadecimal value with "h" to distinguish
them from decimal values.
Appendix A of your Sinclair ZX SPECTRUM Basic Programming book contains the
first 256 decimal codes and their corresponding hexadecimal values.
HOW A COMPUTER WORKS.
To understand what machine code is, it is essential to have some idea of
what the "machine", i.e. computer, is. Although we tend to think of anything
connected with computers as being complicated because of the often
complicated nature of the tasks most computers perform, we are lucky in
that, conceptually, a computer is easy to understand.
We can understand that concept more easily if we separate HOW a computer
works from WHAT it does.
We can understand how a computer works by taking just 3 elements.
1. A block of memory
A memory block is divided up into units called BYTES. Each byte (unit) has 2
attributes:
a) every byte is made up of 8 on/off switches, called BITS, and can
contain any 1 of 256 (2 to the power of 8) codes (00-FFh);
b) every byte has a unique numbered location which is called its
ADDRESS.
The addresses of the bytes start from 0 and rise sequentially by 1 to
whatever the largest address permitted by a particular computer may be. For
the Z80 this is 65535 (FFFFh) and for a large IBM machine perhaps 16,777,215
(FFFFFFh).
2. The program counter
This is simply an amount of memory within the computer (the block of memory
described above is external to the computer although of course connected to
it), called a REGISTER, which contains an address of one of the locations
described above. When the ZX SPECTRUM is turned on the program counter
contains 0. All registers are either 1 or 2 bytes long. The program counter
is 2 bytes long, sufficient to hold the address of any one of the ZX
SPECTRUM's 65536 (0-65535) memory locations.
3. The execution unit
This is the part of the computer that carries out instructions. Instructions
alter registers and memory locations in very precisely defined ways which we
shall discuss later. Each computer has its own very particular set of
instructions which it will execute.
Now that we have described the 3 elements we can see how they work together:
1. The program counter contains a memory address. The contents of the byte
indicated by that address (which must be an instruction code, also called an
operation code) are fetched to the execution unit.
2. The length of the instruction just fetched (instructions can be 1, 2, 3
or 4 bytes long) is added to the program counter, thereby forming the
address of the next instruction to be executed.
3. The instruction is executed.
The above cycle of instructions is repeated ad infinitum until the computer
is switched off. This is all the computer ever does and in fact the power of
the computer comes from its ability to repeat this fetch/execute cycle
millions of times per second.
One obvious point which may arise from the above description is "what
happens when the program counter reaches the end of the memory?". The answer
is that it must never be allowed to. This is achieved by making one of the
instructions which is executed by the execution unit a "change program
counter" instruction. This is effectively a "branch" or "goto" instruction.
WHAT DOES A COMPUTER DO?
We have already said that instructions alter registers and memory locations,
and basically this is all that they do. We have already described one
register, the program counter, and below is a diagram of the full internal
register set of the Z80.
.---.---. .---.---.
| A | F | | A'| F'|
| B | C | | B'| C'|
| D | E | | D'| E'|
| H | L | | H'| L'|
.---.---. .---.---.
| I X |
| I Y |
| S P |
| P C |
.---.---.
| R | I |
.---.---.
To see how MCTT displays these registers:
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=xxxx
| | | I=xx R=xx
| | |>
Please note that I have used "x" above, and throughout this book, to denote
a character which is unknown and/or not relevant to our purposes. However,
the first time MCTT is entered the information contained in all these
registers is "0" because this is a display of the information contained in
the registers at the moment that a machine code routine of our own making
has been interrupted, and we have not yet written any such routines - but we
soon will.
Some registers are 2 bytes long, always contain a memory address, and can
only be used in 2 byte chunks. These are the IX, IY, SP, and PC registers
(the PC register is the program counter I have already mentioned).
The BC, DE, and HL register pairs can be used in either 1 or 2 byte
quantities, as is shown in examples below. Thus, for example, the BC
register pair can be accessed as BC, B or C.
The A register, although paired with the F register, is mostly used on its
own. The F register can only be used indirectly as we shall see later. (The
information contained in the register display against the lines beginning
"FLAG" and "BITS" is in fact purely a translation of the information
contained in the F register, which we will also use later).
The R and I registers are for special purposes and are of no interest to
most programmers.
Finally, there is a duplicate set of the AF, BC, DE, and HL register pairs,
(listed in the register display under "ALTERNATE REGISTER SET"). The use of
the HL register pair in this alternate set and of the IY register is not
recommended as the ZX SPECTRUM control program, which is contained in the
ROM and which controls many crucial operations of the computer, uses these
registers as a temporary store.
To fully explore the instruction set of the Z80, a book detailing the
execution of each instruction is necessary, which is beyond the scope of
this general introduction. However, we can now examine the operation of a
number of common instructions to gain a broad understanding of the
microprocessor.
LOAD A REGISTER PAIR FROM MEMORY
We will now enter a machine code instruction into memory at location 6000h
and then execute it. The instruction is "load the BC register pair with the
2 byte value immediately following the operation (instruction) code". In
this case we will choose the value 1122h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| |MCTT A (Alter) |
| |command |
| | |6000 xx >
|01 |operation code |
| | |6000 xx 01
| | |6001 xx >
|22 |the value to go into C |
| | |6001 xx 22
| | |6002 xx >
|11 |the value to go into B |
| | |6002 xx 11
| | |6003 xx >
|ENTER | |
| | |>
|B6003 | |
| |MCTT B (Breakpoint) |
| |command |
| | |B 6003 ? >
|X | |
| | |B 6003 ?X
|G6000 | |>
| |MCTT G (Goto) |
| |command |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6003
| |Our instruction has |>
| |now been executed |
|R | |
| |MCTT R (Register |
| |display) command |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=1122 DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=6003
| | | I=xx R=xx
| | |>
At this point I would like to explain what we have just done. Using the A
(Alter) MCTT command we entered the instruction into memory. Using the B
(Breakpoint) MCTT command we inserted an instruction to jump to the MCTT
when address 6003h was reached, ie. immediately after our ld bc,1122h
instruction was executed. The G (Goto) MCTT command initiated execution of
that instruction.
The last command, R, displayed all of the Z80's registers after our
instruction had been executed. As you can see, these registers now contain
different values. These values represent the contents of the registers when
the program counter reached address 6003h.
From the register display we can see that the BC register pair now contains
the value 1122h. We have just written our first machine code program!
* A list of these instructions or operation codes is given in Appendix A of
your Sinclair ZX SPECTRUM Basic Programming book. For example, in this case,
under the column "HEX", you will find "01". Next to this, under the column
"Z80 Assembler" you will find "ld bc,NN", which is the instruction we are
just about to execute.
LOAD A SINGLE REGISTER FROM MEMORY
There are also instructions to alter individual registers. To demonstrate
this we will enter and execute the instruction "load the B register with the
1 byte value immediately following the operation code". In this case we will
choose the value 33h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |
|A6000 | |
| | |6000 xx >
|06 |operation code |
| | |6000 xx 06
| | |6001 xx >
|33 |value to go into B |
| | |6001 xx 33
| | |6002 xx >
|ENTER | |
| | |>
|B6002 | |
| | |B 6002 ? >
|X | |
| | |B 6002 ?X
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6002
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=3322 DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=6002
| | | I=xx R=xx
| | |>
From the register display we can see that the B register (remember we are
only altering directly the registers in the Main Register Set) now contains
the value 33h while the C register retains the value 22h which we loaded
into it with our ld bc,1122h instruction.
ADD ONE REGISTER PAIR TO ANOTHER
REGISTER PAIR
The Z80 has various instructions to perform addition and subtraction but
none to perform multiplication or division or other mathematical functions.
If you want to do anything other than addition or subtraction in machine
code I'm afraid you'll just have to write a program to do it yourself.
To demonstrate an addition we will load the DE register pair with a value,
load the HL register pair with a value, and add the DE register pair to the
HL register pair, leaving the result in HL. In this case we will choose the
values 1028h for HL and 2002h for DE
ld hl,1028h put 1028h into HL;
ld de,2002h put 2002h into DE;
add hl,de add DE to HL
An important point to bear in mind is that this is hexadecimal, not decimal,
arithmetic.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| | |6000 xx >
|21 |the operation code |
| |ld hl,NN |
| | |6000 xx 21
| | |6001 xx >
|28 |the value to go into L |
| | |6001 xx 28
| | |6002 xx >
|10 |the value to go into H |
| | |6002 xx 10
| | |6003 xx >
|11 |the operation code |
| |ld de,NN |
| | |6003 xx 11
| | |6004 xx >
|02 |the value to go into E |
| | |6004 xx 02
| | |6005 xx >
|20 |the value to go into D |
| | |6005 xx 20
| | |6006 xx >
|19 |the operation code |
| |add hl,de |
| | |6006 xx 19
| | |6007 xx >
|ENTER | |
| | |>
|B6007 | |
| | |B 6007 ? >
|X | |
| | |B 6007 ?X
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6007
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=xxxx DE=2002 HL=302A
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=6007
| | | I=xx R=xx
| | |>
From the register display we can see that DE now contains the value 2002h we
loaded into it, while HL now contains 302Ah, which is the result of the
hexadecimal addition of 2002h and 1028h.
COMPARE AND BRANCH
Now we come to a very important set of instructions - the compare and branch
instructions. In order to be able to make decisions the computer must have a
mechanism for determining if certain conditions have occurred and how to
communicate the fact that those conditions have occurred to other
instructions.
The mechanism to accomplish this is very simple and involves a register set
aside specifically for this purpose. This register is the F (flag) register,
so called because its function is to flag, or signal to other instructions
the results of preceding instructions.
The flag register has 8 bits, the same as any other byte, and 6 of these
bits are used as 6 separate flags, called the S,Z,H,P/V,N and C flags. When
you use the MCTT register display command "R", the hexadecimal value of the
flag register is shown, together with the setting of each bit of the flag
register (next to the words "FLAG" and "BITS"). (When we talk about bit
settings we usually refer to a bit being "set" if = 1, otherwise "reset" if
= 0). To demonstrate their use we shall concentrate on one flag, the Z
(zero) flag.
Most compare instructions use the A register for one half of the comparison.
The operation of a compare between, for example, the A and B registers works
like this: the computer performs an imaginary subtraction of the B register
from the A register, leaving both registers unaltered, and if the result of
that imaginary subtraction would have resulted in the A register containing
0, it sets the Z flag. In all other cases the Z flag is reset; ie. if A>B or
A<B.
After compare instructions there are generally branch instructions which
alter the program counter as a result of the comparison.
To demonstrate this we will enter this short program.
ld a,1 put 1 into A register;
ld b,1 put 1 into B register;
cp b compare A:B
jp z,600Ah branch to address 600Ah if A = B;
ld a,FFh otherwise put FFh into register A.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
| | |6000
|3E |operation code |
| |ld a,N |
| | |6000 xx 3E
| | |6001 xx >
|01 |value to go into A |
| | |6001 xx 01
| | |6002 xx >
|06 |operation code |
| |ld b,N |
| | |6002 xx 06
| | |6003 xx >
|01 |value to go into B |
| | |6003 xx 01
| | |6004 xx >
|B8 |operation code |
| |cp b |
| | |6004 xx B8
| | |6005 xx >
|CA |operation code |
| |jp z,NN |
| | |6005 xx CA
| | |6006 xx >
|0A |second byte of the |
| |branch address |
| | |6006 xx 0A
| | |6007 xx >
|60 |first byte of the |
| |branch address |
| | |6007 xx 60
| | |6008 xx >
|3E |operation code |
| |ld a,N |
| | |6008 xx 3E
| | |6009 xx >
|FF |value to go into A |
| | |6009 xx FF
| | |600A xx >
|ENTER | |
| | |>
|B600A | |
| | |B 600A ? >
|X | |
| | |B 600A ?X >
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 600A
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=0142 BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS 0 1 - 0 - 0 1 0
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=600A
| | | I=xx R=xx
| | |>
From the register display we can see that the Z flag is set; ie. = 1, and
that the A register now contains the value 01h we loaded into it. This means
that the branch instruction skipped around the ld a,FFh instruction before
stopping at location 600Ah because the contents of the A register were equal
to the contents of the B register. If we change the value that is loaded
into B as follows, we can see the result:
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6003 | |
| | |6003 01 >
|02 |change the value |
| |loaded into B |
| | |6003 xx 02 >
| | |6004 xx >
|ENTER | |
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 600A
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=FF93 BC=02xx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS 1 0 - 1 - 0 1 1
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=600A
| | | I=xx R=xx
| | |>
From this we can see that the Z flag is reset to 0 and therefore the
instruction to skip around the ld a,FFh instruction has not been executed
and as a result the A register now contains FFh. It is important to realise
that only some instructions affect the flag register and in this last
example the last instruction to be executed, ld a,FFh, did not affect the
flag register in any way.
We have just seen the operation of a conditional branch instruction. Of
course branch instructions do not have to be conditional and unconditional
branch instructions do exist in the Z80 instruction set and are frequently
used.
CALL & RETURN
A very special version of the jump instruction - call - is one of the most
widely used machine code instructions. The idea behind the call is this: the
execution of one group of instructions may be temporarily interrupted to
execute another group of instructions, generally referred to as a
subroutine.
The mechanism to accomplish this also involves a register set aside
specifically for this purpose. This register is the SP (stack pointer)
register. This is simply a register which points to an area of memory,
called the stack, which is used to store the address following the call
instruction (the return address). When a call is executed the current
contents of the program counter (the return address) are moved to the
address pointed to by the stack pointer, and the stack pointer is
decremented by 2. The address contained in the call instruction is moved to
the program counter and thus the instruction at that address becomes the
next instruction to be executed. When it is desired to return to the
instruction following the call instruction, a return instruction is
executed. This simply reverses the above process: the contents of the
address pointed to by the stack pointer are moved back to the program
counter and the stack pointer is incremented by 2. It is obviously essential
that the contents of the stack pointer are not changed in between these
operations - a common programming error.
The call instruction is best illustrated using the following diagram. When
the call 7000h instruction is executed, control passes to address 7000h and
instruction A at that address becomes the next instruction to be executed.
When the ret (return) instruction is executed, control passes back to
address 6003h and execution of the original routine is resumed with the
execution of instruction B. In this way self-contained routines may be
written to perform specific tasks, thus easing program development and
making possible the logical structuring of large programs.
6000h CALL 7000h ---.
.---> 6003h instr B |
| * * * |
| * * * |
| .--------------------------------.
| |
| .---> 7000h instr A subroutine starts here
| * * *
| * * *
| * * *
.-------------- RET
To demonstrate this we can enter and execute the following program:
address
6000h call 7000h go to address 7000h;
6003h
7000h pop hl put last 2 bytes of stack into HL;
7001h push hl reset stack pointer;
7002h ret return to address 6003h
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| | |6000 xx >
|CD |the operation code |
| |call |
| | |6000 xx CD
| | |6001 xx >
|00 |the second byte of the |
| |call address |
| | |6001 xx 00
| | |6002 xx >
|70 |the first byte of the |
| |call address |
| | |6002 xx 70
| | |6003 xx >
|ENTER | |
| | |>
|A7000 | |
| | |7000 xx >
|E1 |the operation code |
| |pop hl |
| | |7000 xx E1
| | |7001 xx >
|E5 |the operation code |
| |push hl |
| | |7001 xx E5
| | |7002 xx >
|C9 |the operation code |
| |ret |
| | |7002 xx C9
| | |7003 xx >
|ENTER | |
| | |>
|B7002 | |
| | |B 7002 ? >
|X | |
| | |B 7002 ?X >
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 7002
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=6003
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=7002
| | | I=xx R=xx
| | |>
From this register display we can see that the HL register pair now contains
the return address (pop hl put the contents of the stack into HL and
decremented the stack pointer by 2 - push hl incremented the stack pointer
by 2 to restore the status quo).
If we examine the contents of the stack by taking the value of the SP
register, we shall see that the first 2 bytes on the stack are the return
address 6003h in REVERSE order. (In reverse order as all addresses used by
the Z80 stored in memory are in reverse order. Eg. if the contents of these
2 bytes are 0360h the actual address is 6003h.
To examine the stack, note the value of the SP register given under the
"SPECIAL PURPOSE REGISTERS" heading. You will use this address where xxxx is
indicated below. E.g. if the SP contained 7764h you must type P7764.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|Pxxxx | |
| | |a hexadecimal page
If we remove the breakpoint at 7002h and execute the call at 6000h again, we
shall see that the execution sequence will be halted at address 6003h -
showing that the subroutine at 7000h has been executed and control has
returned to address 6003h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|N | |
| | |N 7002
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6003
| | |>
LOAD A MEMORY LOCATION FROM REGISTER
We have already seen how to load a register and register pair from the
memory. We can also do the reverse of course, ie. load a memory location
from a register. Part of the memory is used by the ZX SPECTRUM to store the
information that appears on your T.V. screen, so if we change that memory we
should be able to see the results immediately.
The display memory begins at address 4000h and is in two parts. The first
part has a bit set aside for each dot that appears on the T.V. screen, the
maximum number of bits being 256*192 which is 49152 bits or 6144 (1800h)
bytes (49152/8). This portion of the display memory occupies addresses 4000h
to 57FFh.
The second part of the display memory controls the attributes of the 768
(32*24) blocks that make up the display and is 768 (300h) bytes long. Each
byte controls the flashing, brightness, foreground and background colour
attributes of each of the blocks. This portion of the display memory
occupies addresses 5800h to 5AFFh.
To get an idea of how the information contained in the display memory
relates to what appears on the T.V. screen, try altering the values
contained in the above locations using the MCTT A (Alter) command. At this
point you might like to re-read chapter 24 of your Sinclair ZX SPECTRUM
BASIC programming book entitled "The memory" for additional information.
We can demonstrate the use of the display memory by writing a short program
to completely till each screen dot position.
address
6000h ld bc,1800h put length of display memory
into BC (this will act as a
counter for the number of
times we are going to move
FFh to the display memory);
6003h ld hl,4000h put start address of display
memory into HL;
6006h ld a,FF load FFh into A;
6008h Id (hl),a load the contents of A into
the memory location whose
address is contained in HL;
6009h inc hl point HL to next memory
location;
600Ah dec bc decrement move counter;
600Bh ld a,b if either B or
600Ch or c C are not=0 then
600Dh jp nz,6006h repeat the instructions at
address 6006h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| | |6000 xx >
|01 |the operation code |
| |ld bc,NN |
| | |6000 xx 01
| | |6001 xx >
|00 |the value to go into C |
| | |6001 xx 00
| | |6002 xx >
|18 |the value to go into B |
| | |6002 xx 18
| | |6003 xx >
|21 |the operation code |
| |ld hl,NN |
| | |6003 xx 21
| | |6004 xx >
|00 |the second byte of |
| |address 4000h |
| | |6004 xx 00
| | |6005 xx >
|40 |the first byte of |
| |address 4000h |
| | |6005 xx 40
| | |6006 xx >
|3E |the operation code |
| |ld a,N |
| | |6006 xx 3E
| | |6007 xx >
|FF |the value to go into A |
| | |6007 xx FF
| | |6008 xx >
|77 |the operation code |
| |ld (hl),a |
| | |6008 xx 77
| | |6009 xx >
|23 |the operation code |
| |inc hl |
| | |6009 xx 23
| | |600A xx >
|0B |the operation code |
| |dec bc |
| | |600A xx 0B
| | |600B xx >
|78 |the operation code |
| |ld a,b |
| | |600B xx 78
| | |600C xx >
|B1 |the operation code |
| |or c |
| | |600C xx B1
| | |600D xx >
|C2 |the operation code |
| |jp nz,NN |
| | |600D xx C2
| | |600E xx >
|06 |the second byte of |
| |address 6006h |
| | |600E xx 06
| | |600F xx >
|60 |the first byte of |
| |address 6006h |
| | |600F xx 60
| | |6010 xx >
|ENTER | |
| | |>
|B6010 | |
| | |B 6010 ? >
|X | |
| | |B 6010 ?X
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |a completely black page then
| | |BREAK AT 6010
| | |>
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|M0000 |17FF 4000 |
| | |M 0000 17FF 4000 ?
|X | |
| | |a random bit pattern
|ENTER | |
| | |>
EPILOGUE
As I said in the introduction, should you wish to proceed further you will
almost certainly need additional literature to enable you to reach a fuller
understanding of the Z80 and its operation within the framework of the ZX
SPECTRUM. You have, however, the MCTT, which is a powerful tool in machine
code program development and one with which you should become well
acquainted in order to simplify that development.
In developing machine code programs you might find the following tips of
some use:
1) Write your machine code program down on paper first and try to resolve
any problems at that stage before typing it into the memory.
2) Don't be afraid to experiment; your program may crash and force you to
reload the MCTT but you can't physically damage the ZX SPECTRUM with
software.
3) Try to imagine what is happening in the registers and memory, and what
sequence the instructions are being executed in when things don't work out
as expected; very often you will find that what you expect to happen is not
what is actually happening.
4) Try to isolate the problem; use of the B (breakpoint) MCTT command
enables you to interrupt your machine code programs at pre-specified points
to ensure that any intermediate results are correct.
5) The computer is an absolutely obedient servant; if you make a mistake and
force it to perform nonsense that is exactly what it will do. It is your
task to impose order and logic on its sequence of operations. If you write
in machine code there is no safety net in the shape of a BASIC interpreter
to bail you out if things go wrong.
I hope that this introduction to machine code programming has been
instructive and helped you to a clearer understanding of what machine code
programming is all about. In trying to resolve seemingly intractable
problems I find it very helpful to keep in mind the old IBM motto, THINK.
Good luck!
APPENDIX
The Machine Code Test Tool (MCTT) is a machine code program designed
to run on the Sinclair ZX SPECTRUM with a 16k or 48k RAM. The 16k
version occupies addresses 7780h to 7FFFh; the 48k version occupies
addresses F780h to FFFFh. On loading, RAMTOP is set to 7880h or F780h
respectively. The program is supplied on a cassette containing four
copies of the program, a 16k and 48k version on both sides.
The MCTT will allow you to easily enter machine code instructions and
to test these instructions in operation. Should you wish to save any
machine code programs you write, you should enter them into dummy REM
statements and use the BASIC SAVE statement to save them on cassette
in the normal way.
Loading the MCTT
To load the MCTT type
LOAD "mctt16" ENTER
if you have a 16k ZX SPECTRUM
or LOAD "mctt48" ENTER
if you have a 48k ZX SPECTRUM
and load the program in the normal way. There is a 16k version
and a 48k version
of the program on each side of the cassette. On side 1 the 16k
version is followed
by the 48k version and on side 2 the 48k version is followed by
the 16k version.
When the program is loaded its title will appear for a short
period, the screen will
blank for a short period, then the normal K cursor
will appear. To then use MCTT type:
1 LET A=USR 30592 ENTER
if you have a 16k ZX SPECTRUM
or 1 LET A=USR 63360 ENTER
if you have a 48k ZX SPECTRUM
From now on whenever you wish to run the MCTT just type: RUN ENTER
and the MCTT > cursor will appear in the top left-hand corner of
your T.V. screen.
COMMANDS
A - Alter memory.
A aaaa
This command allows you to alter any RAM byte to any hexadecimal
character desired. At the end of a page this routine will only accept
X, to continue with the next page, or ENTER to return to the command
mode.
B - Breakpoint.
B aaaa?X
This command allows you to insert a breakpoint in any piece of machine
code, in RAM.
The following points should be kept in mind when inserting breakpoints:
Breakpointing works by inserting a call instruction (which is 3 bytes
long) to a routine within MCTT at the address where a breakpoint is
desired. This address must obviously be the first byte of an
instruction - it is not possible to put a breakpoint in the middle of
an instruction. For this reason also, no two breakpoints should be
within less than 3 bytes of each other.
When a breakpoint is reached the message "BREAK AT AAAA" is displayed.
D - Decimal to Hexadecimal conversion.
D ddddd = HHHH
This command converts any decimal value in the range 00000-65535 to
its hexadecimal equivalent. If a value > 65535 is typed in then the
words "= OVERFLOW" will appear.
G - Go to address.
G aaaa?X
This command will allow you to begin executing any machine code
instructions at the address given.
H - Hexadecimal to decimal conversion.
H hhhh = DDDDD
This command converts any hexadecimal value in the range 0000-FFFFh to
its decimal equivalent.
M - Moves memory block.
M aaaa aaaa aaaa
This command moves a block of memory to a RAM location. The parameters
of this command are three addresses. Address 1 is the address of the
start of the block, address 2 is the address of the end of the block.
If this address is less than address 1, ie. an error, no further input
for this command will be accepted and a new command must be typed in.
Address 3 is the address of the location where the block will be moved
to.
N - Nullify breakpoint.
N
This command nullifies the LAST breakpoint inserted and restores the
instructions contained at that address. Each time a breakpoint is
nullified, the address of the breakpoint is displayed. You can have as
many breakpoints active at one time as you like, but if you insert
more than 1 breakpoint, the 3 byte call to the routine within MCTT
discussed above, can never be replaced by your original instructions.
In that case you will have to manually re-enter those instructions
using the A (Alter) command.
P - Page memory display.
P aaaa
This command will display a page of memory. After displaying a page
you can display the next page by typing "X".
R - Register display.
R
All registers saved at the execution of a breakpoint are displayed.
The 2 flag registers are displayed in hexadecimal and bit form. If it
is desired to alter the contents of the first four register pairs then
the A (Alter) command should be used to alter the memory locations
where they are stored and loaded from when the G (Goto) command is
executed. These addresses are 793Ch to 7943h in the 16k version, and
F93CH to F943h in the 48k version.
S - Stop.
S
This command will return you to BASIC.
V - View breakpoint.
V AAAA
This command will display the last breakpoint you entered.
GLOSSARY
aaaa - 4 character (2 byte) hexadecimal address supplied by you.
ddddd - 5 decimal characters supplied by you.
hhhh - 4 hexadecimal characters supplied by you.
AAAA - 4 byte hexadecimal address supplied by MCTT.
DDDDD - 5 decimal characters supplied by MCTT.
HHHH - 4 hexadecimal characters supplied by MCTT.
X - Confirmation character that the command entered is correct. No
other characters besides X and ENTER (to cancel the command)
will be accepted.
? - Prompt character displayed by MCTT to solicit the confirmation
character "X".
ENTER typed at any time will return the control to command mode.
Copyright 1982 F.O. Ainley.
Design: Scott/Kemp Design Ltd.
Produced by Artset Graphics, The Old British School House, East Street,
Chesham, Buckinghamshire. Tel. (0494) 771938.
OTHER ZX PROGRAMS FROM OCP.
1. FULL SCREEN EDITOR/ the latest and most comprehensive Editor/
ASSEMBLER Assembler yet produced. FULL SCREEN 42
(16 & 48k) column input, text editor, assemble to tape,
screen or memory, assemble derivatives DEFM,
DEFS, DEFW, DEFB, DEFL, ORG, EQU, END.
Comprehensive syntax check, binary, octal,
HEX and ASCII constants. Superb fully notated
"SNAKE" demonstration program as well as our
42-page instruction manual complete this
essential piece of software.
This program is co-resident with the MACHINE
CODE TEST TOOL; the two programs create a
powerful and complete machine code
programming environment
#9.95
2. MASTER TOOL KIT: add many new commands and facilities to your
(16 & 48k) ZX Spectrum with this remarkable program.
Re-Number, Auto-Number, Delete/Copy and
Move Block, String Search and Substitute,
Variable Dump, Cross Reference, Trace
Function, Real Time Clock and Alarm,
Operating Program Line Display plus many more
features. Programming will never be the same
after you have purchased MASTER TOOL KIT.
#9.95
3. CHESS THE TURK: a very comprehensive chess program for the 48k
(48k) Spectrum
#8.95
4. ADDRESS MANAGER: a fast machine-coded application program that
(48k) Limited on 16k offers Spectrum owners a professional standard
address/data filing, indexing and retrieval system.
Will store up to 400 full name and addresses in
48k, full screen entry is standard.
#8.95
5. FINANCE MANAGER: a powerful and flexible MENU DRIVEN program
(48k) program for practically all domestic and business
accounting applications. Features include
AUTOMATIC DOUBLE ENTRY, ANALYSIS,
STANDING ORDERS, RECONCILIATION and
FULL SCREEN ENTRY. Available for 48k only.
#8.95
80 COLUMN PRINTOUTS
Items 1, 4 & 5 can be supplied as Plus 80 versions and used in conjunction
with a Centronics Interface. They include software to call up most Centronic
printer routines. Price #19.95.
A V.A.T. Manager in both editions will be available soon.
Tutor and Debug Program
ZX Spectrum 16k & 48k Edition
F O Ainley
MACHINE CODE TEST TOOL
for the 16k & 48k Spectrum
Edition Two
INTRODUCTION
Welcome to this introduction to machine code. I have prepared this text to
be used in conjunction with the Machine Code Test Tool program (from here on
abbreviated and referred to as MCTT) in order to give you practical examples
and "hands-on" experience ot using machine code. Using the MCTT you can
enter and test your own machine code programs as well as examine the ZX
SPECTRUM ROM and how your BASIC programs are stored in the RAM memory.
Before beginning to read this book I strongly recommend that your read
chapters 24 and 26 of your Sinclair ZX SPECTRUM Basic Programming book
entitled "The memory" and "Using machine code", and Appendix E of the same
book entitled "Binary and Hexadecimal".
It was not my intention to write a complete treatise on the Zilog Z80 (the
microprocessor used in the ZX SPECTRUM) but if, after completing the
exercises in this book, you wish to go deeper into the subject I can
recommend two books which I have found particularly useful. They are:
Z80 Instruction Handbook Understanding your SPECTRUM
Nat Wadsworth Dr. Ian Logan
OCP Box 99 Oxford Melbourne House Publishers
#6.00 Post Free
LOADING
If you have a 16k ZX SPECTRUM
type LOAD "mctt16" ENTER
or
If you have a 48k ZX SPECTRUM
type LOAD "mctt48" ENTER
and load the program in the normal way. There is a 16k version and a 48k
version of the program on each side of the cassette. On side 1 the 16k
version is followed by the 48k version and on side 2 the 48k version is
followed by the 16k version. When the program is loaded its title will
appear for a short period, the screen will blank for a short period, then
the normal K cursor or Sinclair (c) sign will appear.
Please note that 16k program will not load
on a 48k Spectrum or vice versa. If
"mctt 16" appears first on your 16k
machine this will load successfully. If
"mctt 16" appears first and you have a
48k machine, flip the cassette, rewind
and reload which will enter 48k program
first.
For CHARACTER GENERATOR: type
LOAD "udg" ENTER and program will
start automatically.
To use the MCTT type:
1 LET A=USR 30592 ENTER
if you have a 16k ZX SPECTRUM
or
1 LET A=USR 63360 ENTER
if you have a 48k ZX SPECTRUM
From now on whenever you wish to run the MCTT just type:
RUN ENTER
and the MCTT > cursor will appear in the top left-hand corner of
your T.V. screen.
A complete list of MCTT commands is given in the Appendix.
AN IMPORTANT POINT TO REMEMBER WHEN USING THE MCTT IS THAT TYPING ENTER AT
ANY TIME WILL RETURN YOU TO THE COMMAND MODE. Thus, if you make a mistake,
typing DELETE will have no effect and your only option is to type ENTER.
I will begin with a brief explanation of the hexadecimal number system which
explains the way the MCTT displays information contained within the
computer's registers and memory.
THE HEXADECIMAL NUMBER SYSTEM
Our natural number system is decimal, ie. based on the number 10, because
the physical equipment with which we have been endowed consists of 10
fingers. ThiS is our hardware. In this system 1 character can represent any
one of 10 states, which we label 0, 1 ... or 9.
The natural number system of a digital computer is based on 2 because its
hardware consists of a series of electronic switches which can only register
1 of 2 states, which we label 0 or 1. Because it would be very inconvenient
for us humans to represent values using only 0 and 1 we use the hexadecimal
system which has 16 as its base, which is 2 to the power 4, ie 2x2x2x2.
We would naturally count in the hexadecimal system if we had 16 fingers
instead of 10. In that case, of course, we would need 6 extra characters to
represent the 6 extra fingers. To accomplish this, A-F are used in the
hexadecimal system to represent 10-15.
We now have a number system which is based on 16 instead of 10. To represent
any number between 0 and 15 we need use only one character:
0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F. But what about numbers greater than 15? The
system works in exactly the same way as the decimal system: with 2 decimal
characters we can represent any 1 of 100 (10x10) different states (00-99);
with 3 decimal characters any 1 of 1000 (10x10x10) different states
(000-999) and so on, ad infinitum.
With 2 hexadecimal characters we can represent any 1 of 256 (16x16)
different states (00-FF); with 3 hexadecimal characters any 1 of 4096
(16x16x16) different states (000-FFF); with 4 hexadecimal characters any 1
of 65536 (16x16x16x16) different states (0000-FFFF) and so on, ad infinitum.
The MCTT contains a command (D) to convert any decimal number in the range
00000-65535 to its hexadecimal equivalent, and another command (H) to
perform the reverse conversion, ie. any hexadecimal number in the range
0000-FFFF to its decimal equivalent.
Let's see how this works by converting a decimal number to its hexadecimal
equivalent. We will start by choosing the decimal value 200 (this value has
no special significance but is just an example).
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|D00200 | |
| | |D00200=H00C8
| |C8 is the hexadecimal |
| |equivalent of decimal |
| |200 |
Now let's convert a hexadecimal number to its decimal equivalent. In this
example we will choose the hexadecimal value 1000.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|H1000 | |
| | |H1000=D04096
| |4096 is the decimal |
| |equivalent of hexadecimal |
| |1000 |
You should now experiment with these 2 commands in order to reach a better
understanding of the hexadecimal number system. One word of warning: if you
enter (using the D command) a decimal value greater than 65535, which is
outside the conversion range of the command, then the words "=OVERFLOW" will
appear on your T.V. screen - try it and see.
From now on we shall follow every hexadecimal value with "h" to distinguish
them from decimal values.
Appendix A of your Sinclair ZX SPECTRUM Basic Programming book contains the
first 256 decimal codes and their corresponding hexadecimal values.
HOW A COMPUTER WORKS.
To understand what machine code is, it is essential to have some idea of
what the "machine", i.e. computer, is. Although we tend to think of anything
connected with computers as being complicated because of the often
complicated nature of the tasks most computers perform, we are lucky in
that, conceptually, a computer is easy to understand.
We can understand that concept more easily if we separate HOW a computer
works from WHAT it does.
We can understand how a computer works by taking just 3 elements.
1. A block of memory
A memory block is divided up into units called BYTES. Each byte (unit) has 2
attributes:
a) every byte is made up of 8 on/off switches, called BITS, and can
contain any 1 of 256 (2 to the power of 8) codes (00-FFh);
b) every byte has a unique numbered location which is called its
ADDRESS.
The addresses of the bytes start from 0 and rise sequentially by 1 to
whatever the largest address permitted by a particular computer may be. For
the Z80 this is 65535 (FFFFh) and for a large IBM machine perhaps 16,777,215
(FFFFFFh).
2. The program counter
This is simply an amount of memory within the computer (the block of memory
described above is external to the computer although of course connected to
it), called a REGISTER, which contains an address of one of the locations
described above. When the ZX SPECTRUM is turned on the program counter
contains 0. All registers are either 1 or 2 bytes long. The program counter
is 2 bytes long, sufficient to hold the address of any one of the ZX
SPECTRUM's 65536 (0-65535) memory locations.
3. The execution unit
This is the part of the computer that carries out instructions. Instructions
alter registers and memory locations in very precisely defined ways which we
shall discuss later. Each computer has its own very particular set of
instructions which it will execute.
Now that we have described the 3 elements we can see how they work together:
1. The program counter contains a memory address. The contents of the byte
indicated by that address (which must be an instruction code, also called an
operation code) are fetched to the execution unit.
2. The length of the instruction just fetched (instructions can be 1, 2, 3
or 4 bytes long) is added to the program counter, thereby forming the
address of the next instruction to be executed.
3. The instruction is executed.
The above cycle of instructions is repeated ad infinitum until the computer
is switched off. This is all the computer ever does and in fact the power of
the computer comes from its ability to repeat this fetch/execute cycle
millions of times per second.
One obvious point which may arise from the above description is "what
happens when the program counter reaches the end of the memory?". The answer
is that it must never be allowed to. This is achieved by making one of the
instructions which is executed by the execution unit a "change program
counter" instruction. This is effectively a "branch" or "goto" instruction.
WHAT DOES A COMPUTER DO?
We have already said that instructions alter registers and memory locations,
and basically this is all that they do. We have already described one
register, the program counter, and below is a diagram of the full internal
register set of the Z80.
.---.---. .---.---.
| A | F | | A'| F'|
| B | C | | B'| C'|
| D | E | | D'| E'|
| H | L | | H'| L'|
.---.---. .---.---.
| I X |
| I Y |
| S P |
| P C |
.---.---.
| R | I |
.---.---.
To see how MCTT displays these registers:
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=xxxx
| | | I=xx R=xx
| | |>
Please note that I have used "x" above, and throughout this book, to denote
a character which is unknown and/or not relevant to our purposes. However,
the first time MCTT is entered the information contained in all these
registers is "0" because this is a display of the information contained in
the registers at the moment that a machine code routine of our own making
has been interrupted, and we have not yet written any such routines - but we
soon will.
Some registers are 2 bytes long, always contain a memory address, and can
only be used in 2 byte chunks. These are the IX, IY, SP, and PC registers
(the PC register is the program counter I have already mentioned).
The BC, DE, and HL register pairs can be used in either 1 or 2 byte
quantities, as is shown in examples below. Thus, for example, the BC
register pair can be accessed as BC, B or C.
The A register, although paired with the F register, is mostly used on its
own. The F register can only be used indirectly as we shall see later. (The
information contained in the register display against the lines beginning
"FLAG" and "BITS" is in fact purely a translation of the information
contained in the F register, which we will also use later).
The R and I registers are for special purposes and are of no interest to
most programmers.
Finally, there is a duplicate set of the AF, BC, DE, and HL register pairs,
(listed in the register display under "ALTERNATE REGISTER SET"). The use of
the HL register pair in this alternate set and of the IY register is not
recommended as the ZX SPECTRUM control program, which is contained in the
ROM and which controls many crucial operations of the computer, uses these
registers as a temporary store.
To fully explore the instruction set of the Z80, a book detailing the
execution of each instruction is necessary, which is beyond the scope of
this general introduction. However, we can now examine the operation of a
number of common instructions to gain a broad understanding of the
microprocessor.
LOAD A REGISTER PAIR FROM MEMORY
We will now enter a machine code instruction into memory at location 6000h
and then execute it. The instruction is "load the BC register pair with the
2 byte value immediately following the operation (instruction) code". In
this case we will choose the value 1122h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| |MCTT A (Alter) |
| |command |
| | |6000 xx >
|01 |operation code |
| | |6000 xx 01
| | |6001 xx >
|22 |the value to go into C |
| | |6001 xx 22
| | |6002 xx >
|11 |the value to go into B |
| | |6002 xx 11
| | |6003 xx >
|ENTER | |
| | |>
|B6003 | |
| |MCTT B (Breakpoint) |
| |command |
| | |B 6003 ? >
|X | |
| | |B 6003 ?X
|G6000 | |>
| |MCTT G (Goto) |
| |command |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6003
| |Our instruction has |>
| |now been executed |
|R | |
| |MCTT R (Register |
| |display) command |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=1122 DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=6003
| | | I=xx R=xx
| | |>
At this point I would like to explain what we have just done. Using the A
(Alter) MCTT command we entered the instruction into memory. Using the B
(Breakpoint) MCTT command we inserted an instruction to jump to the MCTT
when address 6003h was reached, ie. immediately after our ld bc,1122h
instruction was executed. The G (Goto) MCTT command initiated execution of
that instruction.
The last command, R, displayed all of the Z80's registers after our
instruction had been executed. As you can see, these registers now contain
different values. These values represent the contents of the registers when
the program counter reached address 6003h.
From the register display we can see that the BC register pair now contains
the value 1122h. We have just written our first machine code program!
* A list of these instructions or operation codes is given in Appendix A of
your Sinclair ZX SPECTRUM Basic Programming book. For example, in this case,
under the column "HEX", you will find "01". Next to this, under the column
"Z80 Assembler" you will find "ld bc,NN", which is the instruction we are
just about to execute.
LOAD A SINGLE REGISTER FROM MEMORY
There are also instructions to alter individual registers. To demonstrate
this we will enter and execute the instruction "load the B register with the
1 byte value immediately following the operation code". In this case we will
choose the value 33h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |
|A6000 | |
| | |6000 xx >
|06 |operation code |
| | |6000 xx 06
| | |6001 xx >
|33 |value to go into B |
| | |6001 xx 33
| | |6002 xx >
|ENTER | |
| | |>
|B6002 | |
| | |B 6002 ? >
|X | |
| | |B 6002 ?X
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6002
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=3322 DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=6002
| | | I=xx R=xx
| | |>
From the register display we can see that the B register (remember we are
only altering directly the registers in the Main Register Set) now contains
the value 33h while the C register retains the value 22h which we loaded
into it with our ld bc,1122h instruction.
ADD ONE REGISTER PAIR TO ANOTHER
REGISTER PAIR
The Z80 has various instructions to perform addition and subtraction but
none to perform multiplication or division or other mathematical functions.
If you want to do anything other than addition or subtraction in machine
code I'm afraid you'll just have to write a program to do it yourself.
To demonstrate an addition we will load the DE register pair with a value,
load the HL register pair with a value, and add the DE register pair to the
HL register pair, leaving the result in HL. In this case we will choose the
values 1028h for HL and 2002h for DE
ld hl,1028h put 1028h into HL;
ld de,2002h put 2002h into DE;
add hl,de add DE to HL
An important point to bear in mind is that this is hexadecimal, not decimal,
arithmetic.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| | |6000 xx >
|21 |the operation code |
| |ld hl,NN |
| | |6000 xx 21
| | |6001 xx >
|28 |the value to go into L |
| | |6001 xx 28
| | |6002 xx >
|10 |the value to go into H |
| | |6002 xx 10
| | |6003 xx >
|11 |the operation code |
| |ld de,NN |
| | |6003 xx 11
| | |6004 xx >
|02 |the value to go into E |
| | |6004 xx 02
| | |6005 xx >
|20 |the value to go into D |
| | |6005 xx 20
| | |6006 xx >
|19 |the operation code |
| |add hl,de |
| | |6006 xx 19
| | |6007 xx >
|ENTER | |
| | |>
|B6007 | |
| | |B 6007 ? >
|X | |
| | |B 6007 ?X
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6007
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=xxxx DE=2002 HL=302A
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=6007
| | | I=xx R=xx
| | |>
From the register display we can see that DE now contains the value 2002h we
loaded into it, while HL now contains 302Ah, which is the result of the
hexadecimal addition of 2002h and 1028h.
COMPARE AND BRANCH
Now we come to a very important set of instructions - the compare and branch
instructions. In order to be able to make decisions the computer must have a
mechanism for determining if certain conditions have occurred and how to
communicate the fact that those conditions have occurred to other
instructions.
The mechanism to accomplish this is very simple and involves a register set
aside specifically for this purpose. This register is the F (flag) register,
so called because its function is to flag, or signal to other instructions
the results of preceding instructions.
The flag register has 8 bits, the same as any other byte, and 6 of these
bits are used as 6 separate flags, called the S,Z,H,P/V,N and C flags. When
you use the MCTT register display command "R", the hexadecimal value of the
flag register is shown, together with the setting of each bit of the flag
register (next to the words "FLAG" and "BITS"). (When we talk about bit
settings we usually refer to a bit being "set" if = 1, otherwise "reset" if
= 0). To demonstrate their use we shall concentrate on one flag, the Z
(zero) flag.
Most compare instructions use the A register for one half of the comparison.
The operation of a compare between, for example, the A and B registers works
like this: the computer performs an imaginary subtraction of the B register
from the A register, leaving both registers unaltered, and if the result of
that imaginary subtraction would have resulted in the A register containing
0, it sets the Z flag. In all other cases the Z flag is reset; ie. if A>B or
A<B.
After compare instructions there are generally branch instructions which
alter the program counter as a result of the comparison.
To demonstrate this we will enter this short program.
ld a,1 put 1 into A register;
ld b,1 put 1 into B register;
cp b compare A:B
jp z,600Ah branch to address 600Ah if A = B;
ld a,FFh otherwise put FFh into register A.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
| | |6000
|3E |operation code |
| |ld a,N |
| | |6000 xx 3E
| | |6001 xx >
|01 |value to go into A |
| | |6001 xx 01
| | |6002 xx >
|06 |operation code |
| |ld b,N |
| | |6002 xx 06
| | |6003 xx >
|01 |value to go into B |
| | |6003 xx 01
| | |6004 xx >
|B8 |operation code |
| |cp b |
| | |6004 xx B8
| | |6005 xx >
|CA |operation code |
| |jp z,NN |
| | |6005 xx CA
| | |6006 xx >
|0A |second byte of the |
| |branch address |
| | |6006 xx 0A
| | |6007 xx >
|60 |first byte of the |
| |branch address |
| | |6007 xx 60
| | |6008 xx >
|3E |operation code |
| |ld a,N |
| | |6008 xx 3E
| | |6009 xx >
|FF |value to go into A |
| | |6009 xx FF
| | |600A xx >
|ENTER | |
| | |>
|B600A | |
| | |B 600A ? >
|X | |
| | |B 600A ?X >
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 600A
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=0142 BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS 0 1 - 0 - 0 1 0
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=600A
| | | I=xx R=xx
| | |>
From the register display we can see that the Z flag is set; ie. = 1, and
that the A register now contains the value 01h we loaded into it. This means
that the branch instruction skipped around the ld a,FFh instruction before
stopping at location 600Ah because the contents of the A register were equal
to the contents of the B register. If we change the value that is loaded
into B as follows, we can see the result:
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6003 | |
| | |6003 01 >
|02 |change the value |
| |loaded into B |
| | |6003 xx 02 >
| | |6004 xx >
|ENTER | |
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 600A
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=FF93 BC=02xx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS 1 0 - 1 - 0 1 1
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=600A
| | | I=xx R=xx
| | |>
From this we can see that the Z flag is reset to 0 and therefore the
instruction to skip around the ld a,FFh instruction has not been executed
and as a result the A register now contains FFh. It is important to realise
that only some instructions affect the flag register and in this last
example the last instruction to be executed, ld a,FFh, did not affect the
flag register in any way.
We have just seen the operation of a conditional branch instruction. Of
course branch instructions do not have to be conditional and unconditional
branch instructions do exist in the Z80 instruction set and are frequently
used.
CALL & RETURN
A very special version of the jump instruction - call - is one of the most
widely used machine code instructions. The idea behind the call is this: the
execution of one group of instructions may be temporarily interrupted to
execute another group of instructions, generally referred to as a
subroutine.
The mechanism to accomplish this also involves a register set aside
specifically for this purpose. This register is the SP (stack pointer)
register. This is simply a register which points to an area of memory,
called the stack, which is used to store the address following the call
instruction (the return address). When a call is executed the current
contents of the program counter (the return address) are moved to the
address pointed to by the stack pointer, and the stack pointer is
decremented by 2. The address contained in the call instruction is moved to
the program counter and thus the instruction at that address becomes the
next instruction to be executed. When it is desired to return to the
instruction following the call instruction, a return instruction is
executed. This simply reverses the above process: the contents of the
address pointed to by the stack pointer are moved back to the program
counter and the stack pointer is incremented by 2. It is obviously essential
that the contents of the stack pointer are not changed in between these
operations - a common programming error.
The call instruction is best illustrated using the following diagram. When
the call 7000h instruction is executed, control passes to address 7000h and
instruction A at that address becomes the next instruction to be executed.
When the ret (return) instruction is executed, control passes back to
address 6003h and execution of the original routine is resumed with the
execution of instruction B. In this way self-contained routines may be
written to perform specific tasks, thus easing program development and
making possible the logical structuring of large programs.
6000h CALL 7000h ---.
.---> 6003h instr B |
| * * * |
| * * * |
| .--------------------------------.
| |
| .---> 7000h instr A subroutine starts here
| * * *
| * * *
| * * *
.-------------- RET
To demonstrate this we can enter and execute the following program:
address
6000h call 7000h go to address 7000h;
6003h
7000h pop hl put last 2 bytes of stack into HL;
7001h push hl reset stack pointer;
7002h ret return to address 6003h
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| | |6000 xx >
|CD |the operation code |
| |call |
| | |6000 xx CD
| | |6001 xx >
|00 |the second byte of the |
| |call address |
| | |6001 xx 00
| | |6002 xx >
|70 |the first byte of the |
| |call address |
| | |6002 xx 70
| | |6003 xx >
|ENTER | |
| | |>
|A7000 | |
| | |7000 xx >
|E1 |the operation code |
| |pop hl |
| | |7000 xx E1
| | |7001 xx >
|E5 |the operation code |
| |push hl |
| | |7001 xx E5
| | |7002 xx >
|C9 |the operation code |
| |ret |
| | |7002 xx C9
| | |7003 xx >
|ENTER | |
| | |>
|B7002 | |
| | |B 7002 ? >
|X | |
| | |B 7002 ?X >
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 7002
| | |>
|R | |
| | |MAIN REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=6003
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |ALTERNATE REGISTER SET
| | |AF=xxxx BC=xxxx DE=xxxx HL=xxxx
| | |FLAG S Z - H - P/V N C
| | |BITS x x - x - x x x
| | |
| | |SPECIAL PURPOSE REGISTERS
| | |IX=xxxx IY=xxxx SP=xxxx PC=7002
| | | I=xx R=xx
| | |>
From this register display we can see that the HL register pair now contains
the return address (pop hl put the contents of the stack into HL and
decremented the stack pointer by 2 - push hl incremented the stack pointer
by 2 to restore the status quo).
If we examine the contents of the stack by taking the value of the SP
register, we shall see that the first 2 bytes on the stack are the return
address 6003h in REVERSE order. (In reverse order as all addresses used by
the Z80 stored in memory are in reverse order. Eg. if the contents of these
2 bytes are 0360h the actual address is 6003h.
To examine the stack, note the value of the SP register given under the
"SPECIAL PURPOSE REGISTERS" heading. You will use this address where xxxx is
indicated below. E.g. if the SP contained 7764h you must type P7764.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|Pxxxx | |
| | |a hexadecimal page
If we remove the breakpoint at 7002h and execute the call at 6000h again, we
shall see that the execution sequence will be halted at address 6003h -
showing that the subroutine at 7000h has been executed and control has
returned to address 6003h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|N | |
| | |N 7002
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |BREAK AT 6003
| | |>
LOAD A MEMORY LOCATION FROM REGISTER
We have already seen how to load a register and register pair from the
memory. We can also do the reverse of course, ie. load a memory location
from a register. Part of the memory is used by the ZX SPECTRUM to store the
information that appears on your T.V. screen, so if we change that memory we
should be able to see the results immediately.
The display memory begins at address 4000h and is in two parts. The first
part has a bit set aside for each dot that appears on the T.V. screen, the
maximum number of bits being 256*192 which is 49152 bits or 6144 (1800h)
bytes (49152/8). This portion of the display memory occupies addresses 4000h
to 57FFh.
The second part of the display memory controls the attributes of the 768
(32*24) blocks that make up the display and is 768 (300h) bytes long. Each
byte controls the flashing, brightness, foreground and background colour
attributes of each of the blocks. This portion of the display memory
occupies addresses 5800h to 5AFFh.
To get an idea of how the information contained in the display memory
relates to what appears on the T.V. screen, try altering the values
contained in the above locations using the MCTT A (Alter) command. At this
point you might like to re-read chapter 24 of your Sinclair ZX SPECTRUM
BASIC programming book entitled "The memory" for additional information.
We can demonstrate the use of the display memory by writing a short program
to completely till each screen dot position.
address
6000h ld bc,1800h put length of display memory
into BC (this will act as a
counter for the number of
times we are going to move
FFh to the display memory);
6003h ld hl,4000h put start address of display
memory into HL;
6006h ld a,FF load FFh into A;
6008h Id (hl),a load the contents of A into
the memory location whose
address is contained in HL;
6009h inc hl point HL to next memory
location;
600Ah dec bc decrement move counter;
600Bh ld a,b if either B or
600Ch or c C are not=0 then
600Dh jp nz,6006h repeat the instructions at
address 6006h.
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|A6000 | |
| | |6000 xx >
|01 |the operation code |
| |ld bc,NN |
| | |6000 xx 01
| | |6001 xx >
|00 |the value to go into C |
| | |6001 xx 00
| | |6002 xx >
|18 |the value to go into B |
| | |6002 xx 18
| | |6003 xx >
|21 |the operation code |
| |ld hl,NN |
| | |6003 xx 21
| | |6004 xx >
|00 |the second byte of |
| |address 4000h |
| | |6004 xx 00
| | |6005 xx >
|40 |the first byte of |
| |address 4000h |
| | |6005 xx 40
| | |6006 xx >
|3E |the operation code |
| |ld a,N |
| | |6006 xx 3E
| | |6007 xx >
|FF |the value to go into A |
| | |6007 xx FF
| | |6008 xx >
|77 |the operation code |
| |ld (hl),a |
| | |6008 xx 77
| | |6009 xx >
|23 |the operation code |
| |inc hl |
| | |6009 xx 23
| | |600A xx >
|0B |the operation code |
| |dec bc |
| | |600A xx 0B
| | |600B xx >
|78 |the operation code |
| |ld a,b |
| | |600B xx 78
| | |600C xx >
|B1 |the operation code |
| |or c |
| | |600C xx B1
| | |600D xx >
|C2 |the operation code |
| |jp nz,NN |
| | |600D xx C2
| | |600E xx >
|06 |the second byte of |
| |address 6006h |
| | |600E xx 06
| | |600F xx >
|60 |the first byte of |
| |address 6006h |
| | |600F xx 60
| | |6010 xx >
|ENTER | |
| | |>
|B6010 | |
| | |B 6010 ? >
|X | |
| | |B 6010 ?X
| | |>
|G6000 | |
| | |G 6000 ? >
|X | |
| | |a completely black page then
| | |BREAK AT 6010
| | |>
|YOU TYPE|COMMENT |ZX DISPLAYS
| | |>
|M0000 |17FF 4000 |
| | |M 0000 17FF 4000 ?
|X | |
| | |a random bit pattern
|ENTER | |
| | |>
EPILOGUE
As I said in the introduction, should you wish to proceed further you will
almost certainly need additional literature to enable you to reach a fuller
understanding of the Z80 and its operation within the framework of the ZX
SPECTRUM. You have, however, the MCTT, which is a powerful tool in machine
code program development and one with which you should become well
acquainted in order to simplify that development.
In developing machine code programs you might find the following tips of
some use:
1) Write your machine code program down on paper first and try to resolve
any problems at that stage before typing it into the memory.
2) Don't be afraid to experiment; your program may crash and force you to
reload the MCTT but you can't physically damage the ZX SPECTRUM with
software.
3) Try to imagine what is happening in the registers and memory, and what
sequence the instructions are being executed in when things don't work out
as expected; very often you will find that what you expect to happen is not
what is actually happening.
4) Try to isolate the problem; use of the B (breakpoint) MCTT command
enables you to interrupt your machine code programs at pre-specified points
to ensure that any intermediate results are correct.
5) The computer is an absolutely obedient servant; if you make a mistake and
force it to perform nonsense that is exactly what it will do. It is your
task to impose order and logic on its sequence of operations. If you write
in machine code there is no safety net in the shape of a BASIC interpreter
to bail you out if things go wrong.
I hope that this introduction to machine code programming has been
instructive and helped you to a clearer understanding of what machine code
programming is all about. In trying to resolve seemingly intractable
problems I find it very helpful to keep in mind the old IBM motto, THINK.
Good luck!
APPENDIX
The Machine Code Test Tool (MCTT) is a machine code program designed
to run on the Sinclair ZX SPECTRUM with a 16k or 48k RAM. The 16k
version occupies addresses 7780h to 7FFFh; the 48k version occupies
addresses F780h to FFFFh. On loading, RAMTOP is set to 7880h or F780h
respectively. The program is supplied on a cassette containing four
copies of the program, a 16k and 48k version on both sides.
The MCTT will allow you to easily enter machine code instructions and
to test these instructions in operation. Should you wish to save any
machine code programs you write, you should enter them into dummy REM
statements and use the BASIC SAVE statement to save them on cassette
in the normal way.
Loading the MCTT
To load the MCTT type
LOAD "mctt16" ENTER
if you have a 16k ZX SPECTRUM
or LOAD "mctt48" ENTER
if you have a 48k ZX SPECTRUM
and load the program in the normal way. There is a 16k version
and a 48k version
of the program on each side of the cassette. On side 1 the 16k
version is followed
by the 48k version and on side 2 the 48k version is followed by
the 16k version.
When the program is loaded its title will appear for a short
period, the screen will
blank for a short period, then the normal K cursor
will appear. To then use MCTT type:
1 LET A=USR 30592 ENTER
if you have a 16k ZX SPECTRUM
or 1 LET A=USR 63360 ENTER
if you have a 48k ZX SPECTRUM
From now on whenever you wish to run the MCTT just type: RUN ENTER
and the MCTT > cursor will appear in the top left-hand corner of
your T.V. screen.
COMMANDS
A - Alter memory.
A aaaa
This command allows you to alter any RAM byte to any hexadecimal
character desired. At the end of a page this routine will only accept
X, to continue with the next page, or ENTER to return to the command
mode.
B - Breakpoint.
B aaaa?X
This command allows you to insert a breakpoint in any piece of machine
code, in RAM.
The following points should be kept in mind when inserting breakpoints:
Breakpointing works by inserting a call instruction (which is 3 bytes
long) to a routine within MCTT at the address where a breakpoint is
desired. This address must obviously be the first byte of an
instruction - it is not possible to put a breakpoint in the middle of
an instruction. For this reason also, no two breakpoints should be
within less than 3 bytes of each other.
When a breakpoint is reached the message "BREAK AT AAAA" is displayed.
D - Decimal to Hexadecimal conversion.
D ddddd = HHHH
This command converts any decimal value in the range 00000-65535 to
its hexadecimal equivalent. If a value > 65535 is typed in then the
words "= OVERFLOW" will appear.
G - Go to address.
G aaaa?X
This command will allow you to begin executing any machine code
instructions at the address given.
H - Hexadecimal to decimal conversion.
H hhhh = DDDDD
This command converts any hexadecimal value in the range 0000-FFFFh to
its decimal equivalent.
M - Moves memory block.
M aaaa aaaa aaaa
This command moves a block of memory to a RAM location. The parameters
of this command are three addresses. Address 1 is the address of the
start of the block, address 2 is the address of the end of the block.
If this address is less than address 1, ie. an error, no further input
for this command will be accepted and a new command must be typed in.
Address 3 is the address of the location where the block will be moved
to.
N - Nullify breakpoint.
N
This command nullifies the LAST breakpoint inserted and restores the
instructions contained at that address. Each time a breakpoint is
nullified, the address of the breakpoint is displayed. You can have as
many breakpoints active at one time as you like, but if you insert
more than 1 breakpoint, the 3 byte call to the routine within MCTT
discussed above, can never be replaced by your original instructions.
In that case you will have to manually re-enter those instructions
using the A (Alter) command.
P - Page memory display.
P aaaa
This command will display a page of memory. After displaying a page
you can display the next page by typing "X".
R - Register display.
R
All registers saved at the execution of a breakpoint are displayed.
The 2 flag registers are displayed in hexadecimal and bit form. If it
is desired to alter the contents of the first four register pairs then
the A (Alter) command should be used to alter the memory locations
where they are stored and loaded from when the G (Goto) command is
executed. These addresses are 793Ch to 7943h in the 16k version, and
F93CH to F943h in the 48k version.
S - Stop.
S
This command will return you to BASIC.
V - View breakpoint.
V AAAA
This command will display the last breakpoint you entered.
GLOSSARY
aaaa - 4 character (2 byte) hexadecimal address supplied by you.
ddddd - 5 decimal characters supplied by you.
hhhh - 4 hexadecimal characters supplied by you.
AAAA - 4 byte hexadecimal address supplied by MCTT.
DDDDD - 5 decimal characters supplied by MCTT.
HHHH - 4 hexadecimal characters supplied by MCTT.
X - Confirmation character that the command entered is correct. No
other characters besides X and ENTER (to cancel the command)
will be accepted.
? - Prompt character displayed by MCTT to solicit the confirmation
character "X".
ENTER typed at any time will return the control to command mode.
Copyright 1982 F.O. Ainley.
Design: Scott/Kemp Design Ltd.
Produced by Artset Graphics, The Old British School House, East Street,
Chesham, Buckinghamshire. Tel. (0494) 771938.
OTHER ZX PROGRAMS FROM OCP.
1. FULL SCREEN EDITOR/ the latest and most comprehensive Editor/
ASSEMBLER Assembler yet produced. FULL SCREEN 42
(16 & 48k) column input, text editor, assemble to tape,
screen or memory, assemble derivatives DEFM,
DEFS, DEFW, DEFB, DEFL, ORG, EQU, END.
Comprehensive syntax check, binary, octal,
HEX and ASCII constants. Superb fully notated
"SNAKE" demonstration program as well as our
42-page instruction manual complete this
essential piece of software.
This program is co-resident with the MACHINE
CODE TEST TOOL; the two programs create a
powerful and complete machine code
programming environment
#9.95
2. MASTER TOOL KIT: add many new commands and facilities to your
(16 & 48k) ZX Spectrum with this remarkable program.
Re-Number, Auto-Number, Delete/Copy and
Move Block, String Search and Substitute,
Variable Dump, Cross Reference, Trace
Function, Real Time Clock and Alarm,
Operating Program Line Display plus many more
features. Programming will never be the same
after you have purchased MASTER TOOL KIT.
#9.95
3. CHESS THE TURK: a very comprehensive chess program for the 48k
(48k) Spectrum
#8.95
4. ADDRESS MANAGER: a fast machine-coded application program that
(48k) Limited on 16k offers Spectrum owners a professional standard
address/data filing, indexing and retrieval system.
Will store up to 400 full name and addresses in
48k, full screen entry is standard.
#8.95
5. FINANCE MANAGER: a powerful and flexible MENU DRIVEN program
(48k) program for practically all domestic and business
accounting applications. Features include
AUTOMATIC DOUBLE ENTRY, ANALYSIS,
STANDING ORDERS, RECONCILIATION and
FULL SCREEN ENTRY. Available for 48k only.
#8.95
80 COLUMN PRINTOUTS
Items 1, 4 & 5 can be supplied as Plus 80 versions and used in conjunction
with a Centronics Interface. They include software to call up most Centronic
printer routines. Price #19.95.
A V.A.T. Manager in both editions will be available soon.