Category:Z80 Assembly

From Rosetta Code
Language
Z80 Assembly
This programming language may be used to instruct a computer to perform a task.
See Also:


Listed below are all of the tasks on Rosetta Code which have been solved using Z80 Assembly.

Z80 Assembly is an assembly language for the Zilog Z80 processor, which was introduced in 1976 and used in 1980s home computers such as the Sinclair ZX Spectrum and the Amstrad CPC series. In the late 1990s, some TI graphing calculators (e.g. the TI-83 series) were also Z80-based.

The Z80 is binary compatible with the earlier Intel 8080, but the assembly code is different because instead of having several different commands for loading and storing data, there is only one,LD, on the Z80. Therefore, on the assembly level, Z80 code is actually closer to 8086 code when MOV is changed to LD and the different register structure is taken into account.[1]

Today, the Z80 is still widely used in embedded systems and consumer electronics. Several cross assemblers exist for the Z80, e.g. z80asm. Also, some emulators of e.g. the Amstrad CPC feature a built-in assembler.

Registers

The Z80 has a lot of registers compared to other 8-bit hardware like the 6502.

  • A is the accumulator. Most commands can only work with it, so you'll be using it the most. In particular, and,or,xor,cp,cpl, and neg are instructions that technically take two operands but one is forced to be the accumulator at all times.
  • B and C can be used as the 16-bit pair BC, or separately. Instructions that loop often decrement B or BC and repeat until the register equals zero. These include DJNZ, LDIR, and other similar instructions.
  • D and E can be used as the 16-bit pair DE, or separately. Together they often form the destination address for block transfer operations like LDIR (essentially the equivalent of memcpy in the C programming language.)
  • H and L can be used as the 16-bit pair HL, or separately. Together they often form the source address for block transfer operations like LDIR. In addition, HL can do many things that the other register pairs cannot. The tricky part of the Z80 language is knowing what each register can and can't do.
  • IX and IY are your index registers. They are slower to work with and not as easy to use as other commands, because of the way they work behind the scenes. (What actually happens is a prefix is applied to any instruction involving HL, and that prefix turns the instruction into one involving IX or IY instead.) The half-registers are IXH, IXL, IYH, and IYL. The Game Boy doesn't have these.
  • I is the interrupt register, and R is the memory refresh register. They have their uses on occasion but are best left alone for the most part. The Game Boy doesn't even have them.


Flags

The flags, or condition codes, are set or cleared as appropriate by various actions.

  • Zero flag = equals 1 when the last math operation resulted in a 0, and equals 0 if not. Note that loading a zero (or any value really) into a register does NOT affect this flag, which is not the case for every CPU out there.
  • Carry flag = equals 1 if the last math operation generated a carry or borrow (essentially a rollover from $FF to $00 or vice versa.)

For comparisons, if Accumulator < Operand, carry is set. If Accumulator >= operand, carry clear.

  • Parity/Overflow flag = this flag can represent either Bit Parity or Signed Overflow depending on what instruction was executed last. For arithmetic instructions like ADD and SUB, this represents whether a signed overflow occurred (essentially a rollover from $7F to $80 or vice versa.) For bitwise operations, this flag equals 1 if there are an even number of 1s in the byte, and 0 otherwise. The Game Boy does not have this flag.
  • Half-Carry Flag = equals 1 if the last math operation resulted in a half-carry (essentially a rollover from $0F to $10 or vice versa.) The DAA (decimal adjust accumulator) instruction is the only one that uses this for any meaningful purpose.
  • Sign Flag = equals 1 if the last instruction resulted in a negative number (i.e. bit 7 of the byte is set, or bit 15 if 16-bit registers were used.) The Game Boy doesn't have this flag, but you can make up for that by using the BIT instruction to test bit 7 yourself.

This is just an overview of the flags. You'll need to check a hardware manual for a full list of which commands affect the flags and in what ways.

Assembler Syntax

Assembler syntax varies a bit depending on the assembler, but most follow similar conventions:

  • Instructions with two operands have the destination on the left, and the source on the right, separated by a comma. For example, LD C,A loads the contents of the A register into the C register.
  • & or $ represents hexadecimal, and % represents binary.
  • A register or a 16-bit value in parentheses represents a pointer being dereferenced. The size of the data pointed to will be the same as the size of the destination.

<lang z80>LD A,($4000) ;load the BYTE at memory address $4000 into the accumulator. LD HL,($6000) ;load the WORD at memory address $6000 into HL.

             ;Or, more accurately, load the BYTE at $6000 into L and the BYTE at $6001 into H.

LD A,(HL) ;The value stored in HL is treated as a memory address, and the BYTE at that address is loaded into the accumulator.</lang>

Efficient Coding Tricks

Fast Checking for Odd or Even

Suppose you have a byte at some memory location and you want to know if it's odd or even.

You could do the following: <lang z80>LD A,(HL) BIT 0,A JR nz,Odd</lang>

But there's also a few other ways to do it, which are faster and/or take fewer bytes to execute. BIT 0,A takes 2 bytes to encode. So does AND 1 but it's a little faster. It does destroy the accumulator but if you don't care about that, it's better to use AND 1. <lang z80>LD A,(HL) AND 1 JR nz,Odd</lang>

Or is it? There's an even faster way than this that takes only ONE byte to encode: <lang z80>LD A,(HL) RRCA JR c,Odd</lang>

If you don't care about destroying the accumulator (i.e. you only need the result of the test and not the number being tested) then RRCA outperforms AND 1 in every way. AND 1 in this case still has its uses if you need bit 0 to reflect the result of the test. If you don't, use RRCA instead.

Bit Shifting

The Z80 does have bit shifting, but thanks to RLCA and RRCA it's often faster to rotate instead. Compare the following two code snippets: <lang z80>SLA A SLA A SLA A SLA A ;8 bytes total

AND %00001111 RLCA RLCA RLCA RLCA ;6 bytes total</lang>

Not only is the second method shorter, it's also faster.

References

See also

Subcategories

This category has the following 3 subcategories, out of 3 total.

Pages in category "Z80 Assembly"

The following 126 pages are in this category, out of 126 total.