Chapter 9
Instructions
This chapter describes how the Z80’s instructions, and the two the R800 adds, are written for TATARA: the forms their operands can take, index registers and displacements, relative jumps, and the messages TATARA gives when an operand is wrong. It does not explain what each instruction does. That is the job of the book or course you learn Z80 programming from; appendix B lists the instructions by class, for reference.
9.1 The instruction set
TATARA accepts the Z80 instructions, written the way Zilog writes them, the undocumented instructions that Zilog never published but that every Z80 runs (section 9.5), and the R800’s MULUB and MULUW (section 9.4): 70 mnemonics in all. The source that chapter 6 described puts the mnemonic in the operation field and its operands, separated by commas, in the operand field.
9.2 Operands
An operand is one of the forms in table 9.1. Which forms an instruction takes is set by the Z80, and your Z80 book lists them. The bytes in the table are the ones TATARA writes for each example.
| Form | Example | Bytes |
| register | ld a,b | 78 |
| immediate value | ld a,5 | 3E 05 |
| ld hl,1234h | 21 34 12 | |
| register indirect | ld a,(hl) | 7E |
| ex (sp),hl | E3 | |
| jp (hl) | E9 | |
| indexed | ld a,(ix+5) | DD 7E 05 |
| ld a,(ix-1) | DD 7E FF | |
| ld a,(iy) | FD 7E 00 | |
| memory address | ld a,(1234h) | 3A 34 12 |
| ld hl,(1234h) | 2A 34 12 | |
| port | in a,(98h) | DB 98 |
| out (c),a | ED 79 | |
| condition | jr nz,$ | 20 FE |
| bit number | set 0,(ix+3) | DD CB 03 C6 |
| fixed value | rst 38h | FF |
| im 1 | ED 56 |
9.2.1 Values and brackets
Wherever an instruction takes a number, an address or a port, the operand can be any expression (chapter 8). An operand without brackets is an immediate value: the number itself goes into the instruction. An operand in brackets is a memory address, or a port for IN and OUT. ld a,5 loads the number 5 into A; ld a,(5) loads the byte stored at address 5.
An immediate value that occupies one byte, as in ld a,5, is the low byte of the expression. TATARA does not check that the value fits: ld a,-1 writes 0FFh, which is what is meant, but ld a,300 writes 2Ch, the low byte of 300, without a message. One byte also cannot hold an address that TANREN still has to finish, so a one-byte value must be absolute (section 8.6). A two-byte value, as in ld hl,msg, can be relocatable or external.
9.2.2 Index registers
An indexed operand is (IX+d) or (IY+d), where d, the displacement, is a signed number from −128 to 127 that is added to the index register. It can be written with + or -, and it can be any absolute expression: (ix-1), (ix+count*2). (IX) alone means (IX+0). A displacement out of range stops TATARA:
DISP.AS(2): ERROR: an index displacement must be -128 to 127.
9.3 Relative jumps
JR and DJNZ are relative jumps: the instruction holds the distance to the target, one signed byte, rather than its address. In the source you still write the target, as with JP, and TATARA works out the distance: jr nz,loop, djnz loop.
The distance is measured from the instruction that follows, and must be from −128 to 127 bytes. jr $, which jumps to itself, is a distance of −2 and assembles to 18 FE. A target further away stops TATARA:
JR.AS(2): ERROR: a JR or DJNZ can only reach -128 to 127.
The target must be in the same segment as the jump, or be an absolute address, because a distance to code that TANREN places elsewhere is not known until the program is linked. Use JP for a target that is too far away or in another module.
9.4 The R800 instructions
The R800, the processor of the MSX turbo R, adds two multiplication instructions to the Z80’s set. Table 9.2 shows the three forms TATARA accepts.
| Instruction | Bytes | What it does |
| mulub a,r | ED C1+8r | A ×r, the result in HL |
| muluw hl,bc | ED C3 | HL × BC, the result in DE:HL |
| muluw hl,sp | ED F3 | HL × SP, the result in DE:HL |
r is an 8-bit register: mulub a,b is ED C1. TATARA accepts any of them, but the R800’s documentation guarantees the result only for B, C, D and E. The first operand must be A for MULUB and HL for MULUW.
Warning. TATARA assembles these instructions on any MSX, but a program that uses them runs correctly only on a turbo R. On a Z80 they do not multiply.
9.4.1 R800 mnemonics
Every instruction is stored as a few bytes. The first byte, or the first two when the instruction has a prefix such as DD or ED, says which instruction it is; this part is the opcode. The rest, if there is any, holds the operand: a number, an address or a displacement. The processor reads only the bytes. A mnemonic, such as LD or DJNZ, is a name that people give to an opcode so that they can write programs without learning the numbers.
Because a mnemonic is only a name, the same opcodes can be given more than one set of names. The R800’s documentation from ASCII, reprinted in the MSX-Datapack, gives the whole instruction set new mnemonics: JP is br (branch), DJNZ is dbnz, EX is xch, RES is clr, LDIR is movem. Register names start with a dot, square brackets stand for memory, and the accumulator is always written out: Zilog’s SUB B is sub .a,.b. Apart from the two multiplications, every R800 instruction has the same opcode as the Z80 instruction it renames, and does the same thing.
Table 9.3 shows a short routine, which clears 256 bytes of memory, written both ways. The bytes are the same.
| Z80 | R800 | Bytes | |
| clear: | ld hl,buffer | ld .hl,buffer | 21 nn nn |
| ld b,0 | ld .b,0 | 06 00 | |
| xor a | xor .a,.a | AF | |
| loop: | ld (hl),a | ld [.hl],.a | 77 |
| inc hl | inc .hl | 23 | |
| djnz loop | dbnz loop | 10 FC | |
| ret | ret | C9 |
ld b,0 makes DJNZ go round 256 times, because B reaches zero only after the 256th decrement.
At the time of writing, TATARA accepts only the Z80 mnemonics. A program written in R800 mnemonics has to be translated to Z80 mnemonics before TATARA can assemble it; the program that results is the same.
9.5 The undocumented instructions
Zilog published the Z80’s instructions, but not all of the opcodes the processor runs. Some of the others do useful things, are the same on every Z80, and have been used in MSX programs for decades. TATARA accepts four groups of them:
- SLL, a shift to the left that sets bit 0;
- the index halves IXH, IXL, IYH and IYL, the high and low bytes of IX and IY used as 8-bit registers;
- IN F,(C), which reads a port and sets the flags without keeping the value;
- OUT (C),0, which writes a fixed value to a port.
Like the R800’s instructions, they are assembled on any MSX, with no option to turn them on. M80 has none of them (appendix J). Table 9.4 shows their forms; appendix B lists all 104 with their bytes.
Form |
Bytes |
sll r, for B, C, D, E, H, L and A |
CB 30+r |
sll (hl) |
CB 36 |
sll (ix+d), sll (iy+d) |
DD CB d 36, FD CB d 36 |
ld x,r and ld r,x, for B, C, D, E and A |
DD for IX, FD for IY, then the byte of the same instruction with H for a high half and L for a low one: ld ixh,b is DD and the 60 of ld h,b |
ld x,y, both halves of the same register |
the same: ld ixh,ixl is DD 65 |
ld x,n |
the same: ld ixl,5 is DD 2E 05 |
inc x, dec x |
the same: inc iyh is FD 24 |
add a,x, adc a,x, sub x, sbc a,x, and x, xor x, or x, cp x |
the same: cp ixl is DD BD |
in f,(c) |
ED 70 |
out (c),0 |
ED 71 |
9.5.1 How the index halves work
There is no opcode for IXH. A DD in front of an instruction makes it use IX where it would use HL, and that applies to the halves too: H becomes IXH and L becomes IXL. ld a,h is 7C, so ld a,ixh is DD 7C. With FD, the same instructions use IY.
The prefix belongs to the whole instruction, not to one operand, and that decides which forms exist (figure 9.1):
- ld h,ixl cannot be written: DD 65 turns both operands into halves, and is ld ixh,ixl.
- ld ixh,iyl cannot be written: an instruction can have only one of the two prefixes.
- ld ixh,(hl) cannot be written: with the prefix, (HL) becomes (IX+d), and DD 66 d is ld h,(ix+d).
The halves are also refused wherever the Z80 has no form for them: in the rotations and shifts, in BIT, SET and RES, in IN and OUT, and next to an indexed address, as in ld (ix+5),ixh. In each case TATARA stops with not a form this instruction has.
9.5.2 What a program may not rely on
Warning. SLL on the MSX turbo R. The R800 runs CB 30 to CB 37, but as SLA: bit 0 is left clear. With B = 81h, sll b leaves 03h on a Z80 and 02h on an R800. The carry is the same on both, so only bit 0 shows the difference. A program that uses SLL does not run the same on a turbo R. The index halves, IN F,(C) and OUT (C),0 work on the R800 as they do on the Z80.
Warning. OUT (C),0 does not always write 0. The NMOS Z80 writes 0; the CMOS Z80 writes 0FFh, and so do both processors in openMSX. A program cannot rely on the value it writes.
IN F,(C) leaves A alone and sets the flags as IN A,(C) would. Its only use is to test a port’s bits with the flags.
9.5.3 Spellings and names
Each of these instructions has one spelling: SLL, not SL1 or SLIA; IXH and the others, not HX, LX, HY or LY; IN F,(C), not IN (C); and OUT (C),0 with the digit 0 itself, not 00h or an expression. The other spellings give the usual messages for a word TATARA does not know.
IXH, IXL, IYH and IYL are registers, so they can no longer be names. M80 allows them as labels, and in TATARA such a label would silently change what ld a,ixh means, so TATARA refuses it, and refuses them in PUBLIC and EXTRN too:
IXHNAM.AS(2): ERROR: IXH, IXL, IYH and IYL are registers, not names.
HX, LX, HY and LY stay ordinary names, so a program that uses them for coordinates assembles as before.
Two other groups of undocumented opcodes are not accepted: the forms such as rlc (ix+2),b, which store the result in a register as well as in memory, and the extra opcodes in the ED group that repeat NEG, RETN and NOP.
9.6 When an operand is wrong
Table 9.5 lists the messages TATARA gives for an operand it cannot use, each with a line that causes it.
| Line | Message |
| ld hl,a | not a form this instruction has. |
| mulub b,c | not a form this instruction has. |
| ld a,(ix+200) | an index displacement must be -128 to 127. |
| jr far | a JR or DJNZ can only reach -128 to 127. |
| rst 5 | RST takes 0, 8, 10h and so on to 38h. |
| im 3 | IM takes 0, 1 or 2. |
| bit 8,a | a bit number must be 0 to 7. |
not a form this instruction has. is the general one: the instruction exists, but not with these operands. ld hl,a is an example, because the Z80 cannot copy an 8-bit register into a 16-bit one. Check the forms the instruction has in your Z80 book, or in appendix B.