Difference between revisions of "Z80"
(→Internal state) |
(→Chip Variants) |
||
(117 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
[[image:Z80A.jpg|thumb|Zilog Z80A]] | [[image:Z80A.jpg|thumb|Zilog Z80A]] | ||
− | The Z80 is an 8-bit microprocessor designed by Zilog founder and CEO Federico Faggin, first released in July 1976. It is the CPU used in the Amstrad CPC computers. | + | The Z80 is an 8-bit microprocessor designed by Zilog founder and CEO Federico Faggin, first released in July 1976. It is the CPU used in the Amstrad CPC / Plus / PCW computers. |
− | The Z80/Z80A was a very popular microprocessor, used in a wide range of applications, from | + | The Z80/Z80A was a very popular microprocessor, used in a wide range of applications, from gaming consoles like the [[ColecoVision]] or the [[Sega Master System]] to handhelds like the [[Sega GameGear]] or some TI calculators to personal computers like the [[ZX81]], [[ZX Spectrum]], [[MSX]] and [[VG 5000]]. |
− | It was even used in the Sega MegaDrive as the sound CPU and in the Commodore C128 as a secondary processor in order to achieve [[CP/M]] compatibility. | + | It was even used in the [[Sega MegaDrive]] as the sound CPU and in the [[Commodore C128]] as a secondary processor in order to achieve [[CP/M]] compatibility. Similarly, the Acorn Z80 Second Processor expansion for the [[BBC Micro]] enables [[CP/M]] compatibility. |
+ | |||
+ | <br> | ||
+ | |||
+ | == History == | ||
+ | |||
+ | In the early 1970s, Intel developed the 8080, one of the first widely used microprocessors. However, a group of engineers led by Federico Faggin, the originator of the 8080 architecture in early 1972, left Intel to start their own company called Zilog in 1974. | ||
+ | |||
+ | At Zilog, Faggin and his team wanted to create an improved version of the 8080 that would be more efficient, flexible, and easier to use. This led to the development of the Z80, which was designed to be both backward-compatible with the 8080 and more powerful. This compatibility meant that any software written for the 8080 could run on the Z80, making it an attractive upgrade for manufacturers and developers. | ||
+ | |||
+ | The Z80 had several key improvements over the 8080. It featured more registers, block instructions, bitwise ops, indexed addressing, and improved interrupt handling. It also had built-in memory refresh for dynamic RAM, that made it easier to build systems around it. | ||
+ | |||
+ | <br> | ||
== Description == | == Description == | ||
− | The Z80 microprocessor is an 8-bit [[CPU]] with a 4-bit ALU and a 16-bit address bus capable of direct access to 64KB of memory space. The Z80 is a little-endian CPU, meaning it stores 16-bit values with the least significant byte first, followed by the most significant byte | + | The Z80 microprocessor is an 8-bit [[CPU]] with a 4-bit ALU and a 16-bit address bus capable of direct access to 64KB of memory space. The Z80 is a little-endian CPU, meaning it stores 16-bit values with the least significant byte first, followed by the most significant byte. |
− | + | It has a language of 252 root instructions and with the reserved 4 bytes as prefixes, access to an additional 308 instructions. Although it lacks the raw processing power of processors like the Intel 80x86 or the [[Motorola 68000]] series, the Z80 is extremely useful for low cost control applications. | |
− | The Z80 has about 8500 transistors. | + | The Z80 has about 8500 transistors. To put it into perspective, 64KB of DRAM contains 524288 transistors, as 1 bit of DRAM needs 1 transistor. Fun fact: an Amstrad CPC equipped with a 4MB RAM expansion has 32 million transistors dedicated to RAM while the Z80 CPU still has only 8500 transistors. |
+ | |||
+ | The Z80 is mid-1970s technology while the 64KB DRAM is early-1980s technology and the 4MB DRAM is early-1990s technology. | ||
+ | |||
+ | The Z80 comes in a 40-pin DIP package. It has been manufactured in A, B, and C models, differing only in maximum clock speed. It also has been manufactured as a stand-alone microcontroller with various configurations of on-chip RAM and EPROM. | ||
<br> | <br> | ||
Line 18: | Line 34: | ||
== Part numbers used in the Amstrad CPC during its lifetime == | == Part numbers used in the Amstrad CPC during its lifetime == | ||
− | The Z80 CPU has been manufactured by others, and various Z80s have been used in the construction of the CPC during its lifetime. | + | The Z80 CPU has been manufactured by others, and various Z80s have been used in the construction of the CPC during its lifetime: |
+ | * Mostek MK3880N-4 [https://www.cpcwiki.eu/imgs/e/ee/MC0008D_Z70200_LeZone_PCB_Top.jpg Source] | ||
+ | * NEC D780C [https://www.cpcwiki.eu/imgs/c/c6/CPC464_270100_MC0001A_PCB_Top.jpg Source] | ||
+ | * SGS Z8400AB1 [https://www.cpcwiki.eu/imgs/5/52/CPC464_PCB_Top_%28Z70200_MC0002B%29.jpg Source] | ||
+ | * ST Z8400AB1 [https://www.cpcwiki.eu/imgs/8/8e/CPC464_PCB_Top_%28Z80329_MC0099A%29.jpg Source] | ||
+ | * Zilog Z8400APS [https://www.cpcwiki.eu/imgs/9/91/CPC464_PCB_Top_%28Z70100%29_GA40007-4.jpg Source] | ||
+ | * Zilog Z0840004PSC [https://www.cpcwiki.eu/imgs/8/88/CPC464_MC0044B_PCB_Top.jpg Source] | ||
− | + | All the Z80 CPUs that Amstrad used on CPC and Plus machines are NMOS. [https://www.cpcwiki.eu/forum/amstrad-cpc-hardware/z80-cpu-nmos-or-cmos/ Source] | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
<br> | <br> | ||
=== Modern incarnations === | === Modern incarnations === | ||
+ | |||
+ | Zilog ended the production of the Z80 in April 2024. This chip is still available in ample quantities through NOS chip suppliers and can be purchased for 1.20€. [https://thecheshirec.at/2024/11/09/on-va-tester-des-z80-tout-neufs/ Source] | ||
+ | |||
+ | Also, Zilog continues to produce the [[eZ80]] which is a modernized Z80 CPU. | ||
Apart from surplus/new Z80-clones that are quite easy to find, many emulations depend on software implementations of the Z80: | Apart from surplus/new Z80-clones that are quite easy to find, many emulations depend on software implementations of the Z80: | ||
+ | * [https://zxe.io/software/Z80/ libZ80] Ultra accurate ANSI C implementation | ||
* The [[T80]] is a [[VHDL|VHDL]] implementation of the Z80 and Z80A, finished in 2002 on [[OpenCores|OpenCores]] | * The [[T80]] is a [[VHDL|VHDL]] implementation of the Z80 and Z80A, finished in 2002 on [[OpenCores|OpenCores]] | ||
* [[arnold]] uses [[InkZ80]], written in C++ (apart from the author-designed C simulation) | * [[arnold]] uses [[InkZ80]], written in C++ (apart from the author-designed C simulation) | ||
* On OpenCores, there is also a [[Verilog|Verilog]] implementation of the Z80. | * On OpenCores, there is also a [[Verilog|Verilog]] implementation of the Z80. | ||
− | |||
− | |||
<br> | <br> | ||
Line 57: | Line 77: | ||
* bit3 - F3 - Undocumented by Zilog | * bit3 - F3 - Undocumented by Zilog | ||
* bit2 - PF - Parity Flag (also sometimes used for Overflow) | * bit2 - PF - Parity Flag (also sometimes used for Overflow) | ||
− | * bit1 - NF - | + | * bit1 - NF - Negate Flag (last ALU op was subtract or compare) |
* bit0 - CF - Carry Flag | * bit0 - CF - Carry Flag | ||
|| Flags (including F5 and F3) are affected by most operations. | || Flags (including F5 and F3) are affected by most operations. | ||
Line 72: | Line 92: | ||
| I (Interrupt Vector) || 8-bit || Holds base address for interrupt mode 2 || Combined with external data to form an interrupt vector | | I (Interrupt Vector) || 8-bit || Holds base address for interrupt mode 2 || Combined with external data to form an interrupt vector | ||
|- | |- | ||
− | | R (Memory Refresh) || 8-bit || Increments after each M1 cycle (instruction or prefix fetch) to refresh DRAM || Only the lower 7 bits are incremented | + | | R (Memory Refresh) || 8-bit || Increments after each M1 cycle (instruction or prefix fetch) to refresh DRAM || Only the lower 7 bits are incremented. Bit7 can only be changed by writing to the R register. |
|} | |} | ||
Line 83: | Line 103: | ||
|- | |- | ||
| IM (Interrupt Mode) || 2-bit || Specifies the interrupt mode (0, 1, or 2) || Controls how interrupts are handled: | | IM (Interrupt Mode) || 2-bit || Specifies the interrupt mode (0, 1, or 2) || Controls how interrupts are handled: | ||
− | * IM 0: External devices provide an opcode to execute | + | * IM 0: External devices provide an opcode to execute (most likely an RST instruction). This mode was originally implemented in the Intel 8080 CPU |
* IM 1: Fixed vector at 0038h | * IM 1: Fixed vector at 0038h | ||
* IM 2: Vector provided by I register and external data | * IM 2: Vector provided by I register and external data | ||
+ | |||
+ | The NMI vector is fixed at 0066h, regardless of the I register, and of the IM interrupt mode. | ||
|- | |- | ||
− | | IFF1 || 1-bit || Main | + | | IFF1 || 1-bit || Main Interrupt Flip-Flop || Set when interrupts are enabled, cleared on disable. |
When the CPU accepts a maskable interrupt, both IFF1 and IFF2 are automatically cleared, inhibiting further interrupts. | When the CPU accepts a maskable interrupt, both IFF1 and IFF2 are automatically cleared, inhibiting further interrupts. | ||
|- | |- | ||
| IFF2 || 1-bit || Stores the state of IFF1 during Non-Maskable Interrupts (NMI) || When an NMI occurs, the processor clears IFF1 to disable interrupts temporarily. | | IFF2 || 1-bit || Stores the state of IFF1 during Non-Maskable Interrupts (NMI) || When an NMI occurs, the processor clears IFF1 to disable interrupts temporarily. | ||
IFF2 stores the previous state of IFF1 so that after the NMI is handled, IFF1 can be restored to its original state. | IFF2 stores the previous state of IFF1 so that after the NMI is handled, IFF1 can be restored to its original state. | ||
+ | |||
+ | A barebone Amstrad CPC doesn't use NMI. So IFF1 and IFF2 are always the same. However, NMI is used by the [[PlayCity]] and [[Play2CPC]] expansions. | ||
|- | |- | ||
| WZ || 16-bit || Internal temporary register pair. Also known as MEMPTR || Used for memory and address calculations. | | WZ || 16-bit || Internal temporary register pair. Also known as MEMPTR || Used for memory and address calculations. | ||
− | Normally, you never see the content of this register. But it leaks | + | Normally, you never see the content of this register. But it leaks through the flags F5 and F3 in the BIT b,(HL) instruction. [https://zx-pk.ru/attachment.php?attachmentid=2989 Source] |
|- | |- | ||
− | | Q || 8-bit || Internal register where it assembles the new content of the F register, before moving it back to F || On Zilog NMOS Z80, when the instruction doesn't compute new flags, this register is cleared instead. | + | | Q || 8-bit || Internal register where it assembles the new content of the F register, before moving it back to F || |
− | Normally, you never see the content of this register. But it leaks | + | On Zilog NMOS Z80, when the instruction doesn't compute new flags, this register is cleared instead. But not on NEC NMOS Z80. And CMOS Z80 behave in a different way too. |
+ | Normally, you never see the content of this register. But it leaks through F5 and F3 in the SCF/CCF instructions. [https://worldofspectrum.org/forums/discussion/41704 Source] | ||
+ | Emulating Q is not strictly necessary. A 1-bit flag, indicating whether the previous instruction computed flags, is enough to emulate the behaviour of SCF/CCF. [https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags#scfccf Source] | ||
+ | Also note that while POP AF and EX AF,AF' modify F, they do not compute new flag values. | ||
− | + | The explanation above is just an approximation. Latest research on the subject (May 2024) show that '''SCF/CCF instructions are unstable'''. [https://github.com/hoglet67/Z80Decoder/wiki/Unstable-CCF-SCF-Behaviour Source] | |
− | + | ||
− | + | ||
|- | |- | ||
− | | IR (Instruction Register) || 8-bit || Holds the opcode of the currently executing instruction || Internally used, not accessible by the programmer | + | | IR (Instruction Register) || 8-bit || Holds the opcode of the currently executing instruction || Internally used, not accessible by the programmer. Not to be confused with I (Interrupt Vector) and R (Memory Refresh) registers. |
|- | |- | ||
− | | EIP (Extended Instruction Prefix) || 2-bit || Holds the prefix for extended instructions (CB, ED, or none) || Used for extended instruction sets like bitwise ops | + | | EIP (Extended Instruction Prefix) || 2-bit || Holds the prefix for extended instructions (CB, ED, or none) || Used for extended instruction sets like bitwise ops. |
|- | |- | ||
− | | IMP (Indexing Mode Prefix) || 2-bit || Specifies the indexing mode (DD for IX+d, FD for IY+d, or none for HL) || Indicates use of index registers (IX or IY) for memory access | + | | IMP (Indexing Mode Prefix) || 2-bit || Specifies the indexing mode (DD for IX+d, FD for IY+d, or none for HL) || Indicates use of index registers (IX or IY) for memory access. |
|} | |} | ||
+ | |||
+ | Notes: | ||
+ | * EIP and IMP can be fusioned into a 3-bit internal state as there are only 7 possible values for the prefixes (none, ed, dd, fd, cb, ddcb, fdcb). Probably not a win though as it makes everything more confusing. | ||
+ | * IFF1 / IFF2 are called IEF1 / IEF2 (Interrupt Enable Flip-flops) in the Zilog eZ80 manual. | ||
<br> | <br> | ||
Line 173: | Line 202: | ||
* wz = an internal 16-bit register connected to 16-bit operations | * wz = an internal 16-bit register connected to 16-bit operations | ||
* tmp, tmp2 = temporary storage whose value is thrown away after each instruction | * tmp, tmp2 = temporary storage whose value is thrown away after each instruction | ||
− | |||
− | |||
=== Letter A === | === Letter A === | ||
Line 242: | Line 269: | ||
| call A || 11001101 alalalal ahahahah || 5 || 17 (4,3,4,3,3) || - || - || - || - || - || - || - || - || sp -= 2, (sp) := pc, pc := A || Call | | call A || 11001101 alalalal ahahahah || 5 || 17 (4,3,4,3,3) || - || - || - || - || - || - || - || - || sp -= 2, (sp) := pc, pc := A || Call | ||
|- | |- | ||
− | | call C,A || 11ccc100 alalalal ahahahah || 5/3 || 17/10 (4,3,4,3,3/4,3,3) || - || - || - || - || - || - || - || - || if C then sp -= 2, (sp) := pc, pc := A || Conditional Call | + | | call C,A || 11ccc100 alalalal ahahahah || 5/3 || 17/10 (4,3,4,3,3)/(4,3,3) || - || - || - || - || - || - || - || - || if C then sp -= 2, (sp) := pc, pc := A || Conditional Call |
|- | |- | ||
| ccf || 00111111 || 1 || 4 (4) || - || - || A || X || A || - || 0 || X || hf := cf, cf := ~cf || Complement Carry Flag | | ccf || 00111111 || 1 || 4 (4) || - || - || A || X || A || - || 0 || X || hf := cf, cf := ~cf || Complement Carry Flag | ||
Line 260: | Line 287: | ||
|| Compare and Decrement | || Compare and Decrement | ||
|- | |- | ||
− | | cpdr || 11101101 10111001 || 6/4 || 21/16 (4,4,3,5,5/4,4,3,5) || + || + || X || + || X || C || 1 || - || cpd, if bc <> 0 and nz then pc -= 2 || Compare and Decrement, Repeat | + | | cpdr || 11101101 10111001 || 6/4 || 21/16 (4,4,3,5,5)/(4,4,3,5) || + || + || X || + || X || C || 1 || - || cpd, if bc <> 0 and nz then pc -= 2 || Compare and Decrement, Repeat |
|- | |- | ||
| cpi || 11101101 10100001 || 4 || 16 (4,4,3,5)|| + || + || X || + || X || C || 1 || - || tmp := a - (hl) => flags, bc -= 1, hl += 1, | | cpi || 11101101 10100001 || 4 || 16 (4,4,3,5)|| + || + || X || + || X || C || 1 || - || tmp := a - (hl) => flags, bc -= 1, hl += 1, | ||
Line 266: | Line 293: | ||
|| Compare and Increment | || Compare and Increment | ||
|- | |- | ||
− | | cpir || 11101101 10110001 || 6/4 || 21/16 (4,4,3,5,5/4,4,3,5) || + || + || X || + || X || C || 1 || - || cpi, if bc <> 0 and nz then pc -= 2 || Compare and Increment, Repeat | + | | cpir || 11101101 10110001 || 6/4 || 21/16 (4,4,3,5,5)/(4,4,3,5) || + || + || X || + || X || C || 1 || - || cpi, if bc <> 0 and nz then pc -= 2 || Compare and Increment, Repeat |
|- | |- | ||
| cpl || 00101111 || 1 || 4 (4) || - || - || + || 1 || + || - || 1 || - || a := ~a || Complement | | cpl || 00101111 || 1 || 4 (4) || - || - || + || 1 || + || - || 1 || - || a := ~a || Complement | ||
Line 305: | Line 332: | ||
| di || 11110011 || 1 || 4 (4) || - || - || - || - || - || - || - || - || iff1 := 0, iff2 := 0 || Disable Interrupts | | di || 11110011 || 1 || 4 (4) || - || - || - || - || - || - || - || - || iff1 := 0, iff2 := 0 || Disable Interrupts | ||
|- | |- | ||
− | | djnz E || 00010000 dddddddd || 4/3 || 13/8 (5,3,5/5,3) || - || - || - || - || - || - || - || - || b -= 1, if b <> 0 then pc := E || Decrement, Jump Non-Zero | + | | djnz E || 00010000 dddddddd || 4/3 || 13/8 (5,3,5)/(5,3) || - || - || - || - || - || - || - || - || b -= 1, if b <> 0 then pc := E || Decrement, Jump Non-Zero |
|} | |} | ||
Line 376: | Line 403: | ||
|| I/O Input and Decrement | || I/O Input and Decrement | ||
|- | |- | ||
− | | indr || 11101101 10111010 || 6/5 || 21/16 (4,5,3,4,5/4,5,3,4) || + || + || + || X || + || X || X || X || ind, if b <> 0 then pc -= 2 || I/O Input and Decrement, Repeat | + | | indr || 11101101 10111010 || 6/5 || 21/16 (4,5,3,4,5)/(4,5,3,4) || + || + || + || X || + || X || X || X || ind, if b <> 0 then pc -= 2 || I/O Input and Decrement, Repeat |
|- | |- | ||
| ini || 11101101 10100010 || 5 || 16 (4,5,3,4) || + || + || + || X || + || X || X || X || tmp := ((c)), (hl) := tmp, hl += 1, | | ini || 11101101 10100010 || 5 || 16 (4,5,3,4) || + || + || + || X || + || X || X || X || tmp := ((c)), (hl) := tmp, hl += 1, | ||
Line 388: | Line 415: | ||
|| I/O Input and Increment | || I/O Input and Increment | ||
|- | |- | ||
− | | inir || 11101101 10110010 || 6/5 || 21/16 (4,5,3,4,5/4,5,3,4) || + || + || + || X || + || X || X || X || ini, if b <> 0 then pc -= 2 || I/O Input and Increment, Repeat | + | | inir || 11101101 10110010 || 6/5 || 21/16 (4,5,3,4,5)/(4,5,3,4) || + || + || + || X || + || X || X || X || ini, if b <> 0 then pc -= 2 || I/O Input and Increment, Repeat |
|} | |} | ||
Line 407: | Line 434: | ||
| jr E || 00011000 dddddddd || 3 || 12 (4,3,5) || - || - || - || - || - || - || - || - || pc := E || Relative Jump | | jr E || 00011000 dddddddd || 3 || 12 (4,3,5) || - || - || - || - || - || - || - || - || pc := E || Relative Jump | ||
|- | |- | ||
− | | jr nz,E || 00100000 dddddddd || 3/2 || 12/7 (4,3,5/4,3) || - || - || - || - || - || - || - || - || if nz then pc := E ||rowspan=4|Conditional Relative Jump | + | | jr nz,E || 00100000 dddddddd || 3/2 || 12/7 (4,3,5)/(4,3) || - || - || - || - || - || - || - || - || if nz then pc := E ||rowspan=4|Conditional Relative Jump |
|- | |- | ||
− | | jr z,E || 00101000 dddddddd || 3/2 || 12/7 (4,3,5/4,3) || - || - || - || - || - || - || - || - || if zf then pc := E | + | | jr z,E || 00101000 dddddddd || 3/2 || 12/7 (4,3,5)/(4,3) || - || - || - || - || - || - || - || - || if zf then pc := E |
|- | |- | ||
− | | jr nc,E || 00110000 dddddddd || 3/2 || 12/7 (4,3,5/4,3) || - || - || - || - || - || - || - || - || if nc then pc := E | + | | jr nc,E || 00110000 dddddddd || 3/2 || 12/7 (4,3,5)/(4,3) || - || - || - || - || - || - || - || - || if nc then pc := E |
|- | |- | ||
− | | jr c,E || 00111000 dddddddd || 3/2 || 12/7 (4,3,5/4,3) || - || - || - || - || - || - || - || - || if cf then pc := E | + | | jr c,E || 00111000 dddddddd || 3/2 || 12/7 (4,3,5)/(4,3) || - || - || - || - || - || - || - || - || if cf then pc := E |
|} | |} | ||
Line 494: | Line 521: | ||
|| Load and Decrement | || Load and Decrement | ||
|- | |- | ||
− | | lddr || 11101101 10111000 || 6/5 || 21/16 (4,4,3,5,5/4,4,3,5) || - || - || X || 0 || X || C || 0 || - || ldd, if bc <> 0 then pc -= 2 || Load and Decrement, Repeat | + | | lddr || 11101101 10111000 || 6/5 || 21/16 (4,4,3,5,5)/(4,4,3,5) || - || - || X || 0 || X || C || 0 || - || ldd, if bc <> 0 then pc -= 2 || Load and Decrement, Repeat |
|- | |- | ||
| ldi || 11101101 10100000 || 5 || 16 (4,4,3,5) || - || - || X || 0 || X || C || 0 || - || tmp := (hl), (de) := tmp, de += 1, hl += 1, | | ldi || 11101101 10100000 || 5 || 16 (4,4,3,5) || - || - || X || 0 || X || C || 0 || - || tmp := (hl), (de) := tmp, de += 1, hl += 1, | ||
Line 500: | Line 527: | ||
|| Load and Increment | || Load and Increment | ||
|- | |- | ||
− | | ldir || 11101101 10110000 || 6/5 || 21/16 (4,4,3,5,5/4,4,3,5) || - || - || X || 0 || X || C || 0 || - || ldi, if bc <> 0 then pc -= 2 || Load and Increment, Repeat | + | | ldir || 11101101 10110000 || 6/5 || 21/16 (4,4,3,5,5)/(4,4,3,5) || - || - || X || 0 || X || C || 0 || - || ldi, if bc <> 0 then pc -= 2 || Load and Increment, Repeat |
|} | |} | ||
Line 544: | Line 571: | ||
|| I/O Output and Decrement | || I/O Output and Decrement | ||
|- | |- | ||
− | | otdr || 11101101 10111011 || 6/5 || 21/16 (4,5,3,4,5/4,5,3,4) || + || + || + || X || + || X || X || X || outd, if b <> 0 then pc -= 2 || I/O Output and Decrement, Repeat | + | | otdr || 11101101 10111011 || 6/5 || 21/16 (4,5,3,4,5)/(4,5,3,4) || + || + || + || X || + || X || X || X || outd, if b <> 0 then pc -= 2 || I/O Output and Decrement, Repeat |
|- | |- | ||
| outi || 11101101 10100011 || 5 || 16 (4,5,3,4) || + || + || + || X || + || X || X || X || tmp := (hl), ((c)) := tmp, hl += 1, | | outi || 11101101 10100011 || 5 || 16 (4,5,3,4) || + || + || + || X || + || X || X || X || tmp := (hl), ((c)) := tmp, hl += 1, | ||
Line 554: | Line 581: | ||
|| I/O Output and Increment | || I/O Output and Increment | ||
|- | |- | ||
− | | otir || 11101101 10110011 || 6/5 || 21/16 (4,5,3,4,5/4,5,3,4) || + || + || + || X || + || X || X || X || outi, if b <> 0 then pc -= 2 || I/O Output and Increment, Repeat | + | | otir || 11101101 10110011 || 6/5 || 21/16 (4,5,3,4,5)/(4,5,3,4) || + || + || + || X || + || X || X || X || outi, if b <> 0 then pc -= 2 || I/O Output and Increment, Repeat |
|} | |} | ||
Line 588: | Line 615: | ||
| ret || 11001001 || 3 || 10 (4,3,3) || - || - || - || - || - || - || - || - || pc := (sp), sp += 2 || Return | | ret || 11001001 || 3 || 10 (4,3,3) || - || - || - || - || - || - || - || - || pc := (sp), sp += 2 || Return | ||
|- | |- | ||
− | | ret C || 11ccc000 || 4/2 || 11/5 (5,3,3/5)|| - || - || - || - || - || - || - || - || if C then pc := (sp), sp += 2 || Conditional Return | + | | ret C || 11ccc000 || 4/2 || 11/5 (5,3,3)/(5)|| - || - || - || - || - || - || - || - || if C then pc := (sp), sp += 2 || Conditional Return |
|- | |- | ||
| reti || 11101101 01001101 || 4 || 14 (4,4,3,3) || - || - || - || - || - || - || - || - || pc := (sp), sp += 2, iff1 := iff2 || Return from Interrupt | | reti || 11101101 01001101 || 4 || 14 (4,4,3,3) || - || - || - || - || - || - || - || - || pc := (sp), sp += 2, iff1 := iff2 || Return from Interrupt | ||
Line 739: | Line 766: | ||
== Timings == | == Timings == | ||
− | + | On CPC, bus arbitration is done on every CPU bus access. On MSX, bus arbitration only applies to M1 machine cycles but access to VRAM has other limitations. On ZX Spectrum, bus arbitration is done not by using the /WAIT pin but by disabling the CPU clock when needed. | |
− | + | The NOPs column corresponds to CPC timings, which account for the bus arbitration managed by the [[Gate Array]]. The NOP instruction takes 4 cycles. This is the minimum amount of cycles an instruction can take. | |
− | + | Every M-cycle that involves a memory or I/O access will be stretched due to bus arbitration. But beware, some M-cycles are purely internal and don't involve a memory or I/O access. | |
+ | |||
+ | Nevertheless, a few CPC timings can appear surprising at first glance: | ||
+ | |||
+ | * Instructions LD (IX+d),r and LD (IX+d),n take 5 and 6 NOPs respectively, even though they are both listed as 19 (4,4,3,5,3) cycles in the datasheet. This happens because LD (IX+d),r has one less memory access operation to do compared to LD (IX+d),n as it does not have to fetch its operand from memory. | ||
+ | |||
+ | * Instructions IN r,(C) and OUT (C),r take 4 NOPs with CPC timings, even though they are listed as 12 (4,4,4) cycles in the datasheet. This happens because I/O access is not aligned with memory access. On Zilog manual, it is precised that one wait-state TW is automatically inserted after T2 on I/O access. | ||
+ | |||
+ | The CPC timings of some instructions will be altered if an interrupt happens. The interrupt test occurs on the last T-State of the instruction, and if it's low, the Z80 will insert 2 wait states to acknowledge the interrupt. | ||
+ | |||
+ | So, instructions which end in the third or fourth T-State relative to the read alignment for the next instruction fetch will be delayed by an extra 4 T-States. The few instructions which end in the first or second T-State won't since the first instruction fetch/read in the interrupt won't be delayed an extra 4 T-States. [https://www.cpcwiki.eu/forum/programming/interrupt-wait/ Source] | ||
<br> | <br> | ||
Line 749: | Line 786: | ||
== Opcodes == | == Opcodes == | ||
− | + | The Z80 follows a 2-3-3 opcode bit pattern. | |
+ | |||
+ | All CB-prefixed opcodes and half of the standard opcodes (from &40 to &BF) follow a strict uniform layout. The sole exception is the HALT instruction (opcode &76), which replaces the expected LD (HL),(HL) instruction. | ||
− | The rest of the opcode table also | + | The rest of the opcode table is also neatly organised but in an horizontal way instead of vertical. |
Any instruction in bold is undocumented by Zilog. | Any instruction in bold is undocumented by Zilog. | ||
Line 2,282: | Line 2,321: | ||
* The opcode ED70 reads the port indicated by the register C without keeping the result but modifies the register F | * The opcode ED70 reads the port indicated by the register C without keeping the result but modifies the register F | ||
* The opcode ED71 corresponds to the instruction OUT (C),255 on a CMOS Z80 | * The opcode ED71 corresponds to the instruction OUT (C),255 on a CMOS Z80 | ||
+ | * The opcode EDFF is used by Winape (and other emulators) to break into the debugger (a 'break opcode') [https://www.cpcwiki.eu/forum/emulators/shakerland-portal/msg244578/ Source] | ||
=== DD or FD-prefixed opcodes === | === DD or FD-prefixed opcodes === | ||
Line 2,304: | Line 2,344: | ||
If the instruction produces output other than in the flags (i.e. all except BIT), then the result gets placed both into (IX+d) or (IY+d) and into the register one would normally expect to be altered. | If the instruction produces output other than in the flags (i.e. all except BIT), then the result gets placed both into (IX+d) or (IY+d) and into the register one would normally expect to be altered. | ||
− | DDCB and FDCB-prefixed instructions only increment the R register twice. | + | DDCB and FDCB-prefixed instructions only increment the R register twice. [https://stackoverflow.com/questions/8540518/z80-memory-refresh-register#comment25506533_16222002 Source] |
<br> | <br> | ||
Line 2,312: | Line 2,352: | ||
* RETI and RETN are identical instructions [https://floooh.github.io/2021/12/17/cycle-stepped-z80.html#the-ei-di-and-retiretn-instructions Source]. The only reason for RETI is so that some other hardware can detect the specific case of returning from the interrupt, by detecting the RETI opcode on the data bus. | * RETI and RETN are identical instructions [https://floooh.github.io/2021/12/17/cycle-stepped-z80.html#the-ei-di-and-retiretn-instructions Source]. The only reason for RETI is so that some other hardware can detect the specific case of returning from the interrupt, by detecting the RETI opcode on the data bus. | ||
* EI has a 1-instruction delay. It is necessary for doing EI/RETI without any danger of nested interrupt routines. | * EI has a 1-instruction delay. It is necessary for doing EI/RETI without any danger of nested interrupt routines. | ||
+ | * At the end of an NMI service routine, the earliest moment a maskable interrupt will be triggered is at the end of the instruction following RETN. [https://spectrumcomputing.co.uk/forums/viewtopic.php?t=7086 Source] | ||
* RST instructions are just a CALL instruction to a fixed address baked in the instruction itself. | * RST instructions are just a CALL instruction to a fixed address baked in the instruction itself. | ||
* Despite what the syntax of the instructions JP (HL/IX/IY) suggests, PC will be loaded with the contents of the register itself, not the indexed value. Those instructions should be understood as JP HL/IX/IY. | * Despite what the syntax of the instructions JP (HL/IX/IY) suggests, PC will be loaded with the contents of the register itself, not the indexed value. Those instructions should be understood as JP HL/IX/IY. | ||
− | |||
− | |||
* The 16-bit commands ADD HL,ss, ADC HL,ss and SBC HL,ss exist but not the command SUB HL,ss. | * The 16-bit commands ADD HL,ss, ADC HL,ss and SBC HL,ss exist but not the command SUB HL,ss. | ||
+ | * While the syntax of the 8-bit ADD, ADC and SBC instructions all explicitly mention the A register, the SUB instruction does not mention it. On the Zilog eZ80, the SUB instruction explicitly mention the A register. | ||
+ | * IN r,(C) and OUT (C),r instructions syntax is misleading as these instructions actually use the full 16-bit port address contained in BC. On the Zilog eZ80, these instructions are correctly named IN, r,(BC) and OUT (BC),r. | ||
+ | * The Amstrad engineers chose to use the high byte of the address (register B) for chip selection instead of the low byte (register C) in I/O operations. As a result, OTIR / OTDR / INIR / INDR instructions cannot be used on Amstrad CPC for transferring or reading a sequence of values on a port as they use B as a counter. | ||
+ | * INI/IND/INIR/INDR decrease B after storing the byte from the hardware port into memory. And OUTI/OUTD/OTIR/OTDR decrease B before sending the memory byte to the hardware port. [https://www.cpcwiki.eu/forum/programming/z80-documentation-errors/ Source] | ||
+ | * All PUSH and POP instructions utilize a 16-bit operand and the high-order byte is always pushed first and popped last. PUSH HL is PUSH H then L. POP HL is POP L then H. | ||
* When an LDxR / CPxR / INxR / OTxR instruction is interrupted, the interrupt handler sees some flags in a different state. [https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags#interrupted-block-instructions Source] | * When an LDxR / CPxR / INxR / OTxR instruction is interrupted, the interrupt handler sees some flags in a different state. [https://github.com/hoglet67/Z80Decoder/wiki/Undocumented-Flags#interrupted-block-instructions Source] | ||
− | * NMOS Z80 suffers a problem whereby LD A,I and LD A,R record the state of IFF2 after it has been reset if an interrupt is delivered during that instruction. [https://sinclair.wiki.zxnet.co.uk/wiki/Z80#LD_A,I_and_LD_A,R_bug | + | * LD A,I and LD A,R normally copy the state of IFF2 to the Parity flag. NMOS Z80 suffers a problem whereby LD A,I and LD A,R record the state of IFF2 after it has been reset if an interrupt is delivered during that instruction. [https://sinclair.wiki.zxnet.co.uk/wiki/Z80#LD_A,I_and_LD_A,R_bug Source] |
− | + | ||
<br> | <br> | ||
Line 2,332: | Line 2,375: | ||
Note: A reset disables the maskable interrupt, selects interrupt mode 0, zeroes registers I & R and zeroes the program counter (PC). | Note: A reset disables the maskable interrupt, selects interrupt mode 0, zeroes registers I & R and zeroes the program counter (PC). | ||
+ | |||
+ | <br> | ||
+ | |||
+ | == Chip Variants == | ||
+ | |||
+ | The [[GBZ80]] (Sharp SM83) that powers the original [[Nintendo GameBoy]] is an in-between the [[Intel 8080]] and Z80. [https://gbdev.io/pandocs/CPU_Comparison_with_Z80.html Source] | ||
+ | |||
+ | The [[KC Compact]] uses the U880, which is an unlicensed clone of the Z80 manufactured by MME. It was the most widely used microprocessor in the German Democratic Republic. [https://en.wikipedia.org/wiki/U880 Source] | ||
+ | |||
+ | The КМ1582ВМ-0100 is a Soviet clone of the Z80. It is used in the [[Aleste 520EX]] clone of the Amstrad CPC computer. | ||
+ | |||
+ | The ASCII [[R800]] that powers the MSX TurboR is a seriously beefed up version of the Z80: | ||
+ | |||
+ | * The ALU of the R800 is 16-bit instead of 4-bit for the Z80. This change allows instructions that were being executed in 4 cycles to be done in 1 cycle. | ||
+ | |||
+ | * The instruction set of the R800 is almost identical to the Z80. Only 2 instructions have been added: MULUB and MULUW. And many of the undocumented instructions of the Z80 were made official. | ||
+ | |||
+ | [[Zilog]] itself offers the [[eZ80]] processor, a binary-compatible upgrade of the Z80, which runs at up to 50MHz but performs like a 150MHz Z80 due to being 3 times faster at the same clock speed. | ||
<br> | <br> | ||
Line 2,340: | Line 2,401: | ||
* [[Media:Z80 CPU Technical Manual 1977.pdf]] | * [[Media:Z80 CPU Technical Manual 1977.pdf]] | ||
* [[Media:Mostek Z80 Programming Manual.pdf]] | * [[Media:Mostek Z80 Programming Manual.pdf]] | ||
− | * [[Media:Z80-Mostek-Technical-Manual.pdf]] - provides a detailed breakdown of the machine cycles | + | * [[Media:Z80-Mostek-Technical-Manual.pdf]] [http://www.z80.info/z80ins.txt Text version] - provides a detailed breakdown of the machine cycles |
* [[Media:Mostek Z80 Micro-Reference Manual Feb78.pdf]] | * [[Media:Mostek Z80 Micro-Reference Manual Feb78.pdf]] | ||
* [[Media:Z80 CPU Instant Reference Card (Color).pdf]] | * [[Media:Z80 CPU Instant Reference Card (Color).pdf]] | ||
Line 2,362: | Line 2,423: | ||
*[https://baltazarstudios.com/zilog-z80-undocumented-behavior/ Complete list of Z80 instructions and their bus responses and cycles dumped from real hardware] | *[https://baltazarstudios.com/zilog-z80-undocumented-behavior/ Complete list of Z80 instructions and their bus responses and cycles dumped from real hardware] | ||
*[https://floooh.github.io/2021/12/06/z80-instruction-timing.html Detailed look at Z80 instruction timings with the help of a Z80 netlist simulation] | *[https://floooh.github.io/2021/12/06/z80-instruction-timing.html Detailed look at Z80 instruction timings with the help of a Z80 netlist simulation] | ||
− | *[https://floooh.github.io/2021/12/17/cycle-stepped-z80.html Cycle-stepped Z80 emulation how-to] | + | *[https://floooh.github.io/2021/12/17/cycle-stepped-z80.html Cycle-stepped Z80 emulation how-to] |
+ | *[https://github.com/SingleStepTests Tom Harte's SingleStepTests] | ||
[[Category:Hardware]][[Category:Programming]][[Category:Datasheet]][[Category:CPC Internal Components]][[Category:Electronic Component]] | [[Category:Hardware]][[Category:Programming]][[Category:Datasheet]][[Category:CPC Internal Components]][[Category:Electronic Component]] |
Latest revision as of 22:45, 18 November 2024
The Z80 is an 8-bit microprocessor designed by Zilog founder and CEO Federico Faggin, first released in July 1976. It is the CPU used in the Amstrad CPC / Plus / PCW computers.
The Z80/Z80A was a very popular microprocessor, used in a wide range of applications, from gaming consoles like the ColecoVision or the Sega Master System to handhelds like the Sega GameGear or some TI calculators to personal computers like the ZX81, ZX Spectrum, MSX and VG 5000.
It was even used in the Sega MegaDrive as the sound CPU and in the Commodore C128 as a secondary processor in order to achieve CP/M compatibility. Similarly, the Acorn Z80 Second Processor expansion for the BBC Micro enables CP/M compatibility.
Contents
History
In the early 1970s, Intel developed the 8080, one of the first widely used microprocessors. However, a group of engineers led by Federico Faggin, the originator of the 8080 architecture in early 1972, left Intel to start their own company called Zilog in 1974.
At Zilog, Faggin and his team wanted to create an improved version of the 8080 that would be more efficient, flexible, and easier to use. This led to the development of the Z80, which was designed to be both backward-compatible with the 8080 and more powerful. This compatibility meant that any software written for the 8080 could run on the Z80, making it an attractive upgrade for manufacturers and developers.
The Z80 had several key improvements over the 8080. It featured more registers, block instructions, bitwise ops, indexed addressing, and improved interrupt handling. It also had built-in memory refresh for dynamic RAM, that made it easier to build systems around it.
Description
The Z80 microprocessor is an 8-bit CPU with a 4-bit ALU and a 16-bit address bus capable of direct access to 64KB of memory space. The Z80 is a little-endian CPU, meaning it stores 16-bit values with the least significant byte first, followed by the most significant byte.
It has a language of 252 root instructions and with the reserved 4 bytes as prefixes, access to an additional 308 instructions. Although it lacks the raw processing power of processors like the Intel 80x86 or the Motorola 68000 series, the Z80 is extremely useful for low cost control applications.
The Z80 has about 8500 transistors. To put it into perspective, 64KB of DRAM contains 524288 transistors, as 1 bit of DRAM needs 1 transistor. Fun fact: an Amstrad CPC equipped with a 4MB RAM expansion has 32 million transistors dedicated to RAM while the Z80 CPU still has only 8500 transistors.
The Z80 is mid-1970s technology while the 64KB DRAM is early-1980s technology and the 4MB DRAM is early-1990s technology.
The Z80 comes in a 40-pin DIP package. It has been manufactured in A, B, and C models, differing only in maximum clock speed. It also has been manufactured as a stand-alone microcontroller with various configurations of on-chip RAM and EPROM.
Part numbers used in the Amstrad CPC during its lifetime
The Z80 CPU has been manufactured by others, and various Z80s have been used in the construction of the CPC during its lifetime:
- Mostek MK3880N-4 Source
- NEC D780C Source
- SGS Z8400AB1 Source
- ST Z8400AB1 Source
- Zilog Z8400APS Source
- Zilog Z0840004PSC Source
All the Z80 CPUs that Amstrad used on CPC and Plus machines are NMOS. Source
Modern incarnations
Zilog ended the production of the Z80 in April 2024. This chip is still available in ample quantities through NOS chip suppliers and can be purchased for 1.20€. Source
Also, Zilog continues to produce the eZ80 which is a modernized Z80 CPU.
Apart from surplus/new Z80-clones that are quite easy to find, many emulations depend on software implementations of the Z80:
- libZ80 Ultra accurate ANSI C implementation
- The T80 is a VHDL implementation of the Z80 and Z80A, finished in 2002 on OpenCores
- arnold uses InkZ80, written in C++ (apart from the author-designed C simulation)
- On OpenCores, there is also a Verilog implementation of the Z80.
Registers
Register | Size | Description | Notes |
---|---|---|---|
B, C, D, E, H, L | 8-bit | General-purpose registers | Can form 16-bit pairs: BC, DE, HL |
A (Accumulator) | 8-bit | Main register for arithmetic, logic, and data transfer | Most used register |
F (Flags) | 8-bit |
|
Flags (including F5 and F3) are affected by most operations.
HF and NF are used in the DAA algorithm. |
AF', BC', DE', HL' | 16-bit | Alternate register set | Swappable with primary registers for fast context switching |
SP (Stack Pointer) | 16-bit | Points to top of the stack | Used for subroutine calls and interrupt handling |
PC (Program Counter) | 16-bit | Points to the next instruction | Automatically increments as instructions execute |
IX, IY (Index Registers) | 16-bit | Used for indexed addressing | Can be split into IXH/IXL, IYH/IYL for 8-bit access |
I (Interrupt Vector) | 8-bit | Holds base address for interrupt mode 2 | Combined with external data to form an interrupt vector |
R (Memory Refresh) | 8-bit | Increments after each M1 cycle (instruction or prefix fetch) to refresh DRAM | Only the lower 7 bits are incremented. Bit7 can only be changed by writing to the R register. |
Internal state
Register | Size | Description | Notes |
---|---|---|---|
IM (Interrupt Mode) | 2-bit | Specifies the interrupt mode (0, 1, or 2) | Controls how interrupts are handled:
The NMI vector is fixed at 0066h, regardless of the I register, and of the IM interrupt mode. |
IFF1 | 1-bit | Main Interrupt Flip-Flop | Set when interrupts are enabled, cleared on disable.
When the CPU accepts a maskable interrupt, both IFF1 and IFF2 are automatically cleared, inhibiting further interrupts. |
IFF2 | 1-bit | Stores the state of IFF1 during Non-Maskable Interrupts (NMI) | When an NMI occurs, the processor clears IFF1 to disable interrupts temporarily.
IFF2 stores the previous state of IFF1 so that after the NMI is handled, IFF1 can be restored to its original state. A barebone Amstrad CPC doesn't use NMI. So IFF1 and IFF2 are always the same. However, NMI is used by the PlayCity and Play2CPC expansions. |
WZ | 16-bit | Internal temporary register pair. Also known as MEMPTR | Used for memory and address calculations.
Normally, you never see the content of this register. But it leaks through the flags F5 and F3 in the BIT b,(HL) instruction. Source |
Q | 8-bit | Internal register where it assembles the new content of the F register, before moving it back to F |
On Zilog NMOS Z80, when the instruction doesn't compute new flags, this register is cleared instead. But not on NEC NMOS Z80. And CMOS Z80 behave in a different way too. Normally, you never see the content of this register. But it leaks through F5 and F3 in the SCF/CCF instructions. Source Emulating Q is not strictly necessary. A 1-bit flag, indicating whether the previous instruction computed flags, is enough to emulate the behaviour of SCF/CCF. Source Also note that while POP AF and EX AF,AF' modify F, they do not compute new flag values. The explanation above is just an approximation. Latest research on the subject (May 2024) show that SCF/CCF instructions are unstable. Source |
IR (Instruction Register) | 8-bit | Holds the opcode of the currently executing instruction | Internally used, not accessible by the programmer. Not to be confused with I (Interrupt Vector) and R (Memory Refresh) registers. |
EIP (Extended Instruction Prefix) | 2-bit | Holds the prefix for extended instructions (CB, ED, or none) | Used for extended instruction sets like bitwise ops. |
IMP (Indexing Mode Prefix) | 2-bit | Specifies the indexing mode (DD for IX+d, FD for IY+d, or none for HL) | Indicates use of index registers (IX or IY) for memory access. |
Notes:
- EIP and IMP can be fusioned into a 3-bit internal state as there are only 7 possible values for the prefixes (none, ed, dd, fd, cb, ddcb, fdcb). Probably not a win though as it makes everything more confusing.
- IFF1 / IFF2 are called IEF1 / IEF2 (Interrupt Enable Flip-flops) in the Zilog eZ80 manual.
Z80 Instructions
Legend
Notation | Meaning | Respective Opcode Bits |
---|---|---|
A | 16-bit address or immediate | alalalal ahahahah |
B | Bit number (0..7) | bbb = 000..111 |
C | Condition (nz, z, nc, c, po, pe, p, m)
nz: ZF=0, z: ZF=1, nc: CF=0, c: CF=1, po: PF=0, pe: PF=1, p: SF=0, m: SF=1 |
ccc = 000, 001, 010, 011, 100, 101, 110, 111 |
D | 8-bit signed relative offset | dddddddd |
E | 16-bit relative address | dddddddd (E minus address of next instruction) |
I | Index register (ix, iy) | i = 0, 1 |
J | Half index register (ixh, ixl, iyh, iyl) | (i, b) = (0, 0), (0, 1), (1, 0), (1, 1) |
N | 8-bit immediate | nnnnnnnn |
P | 16-bit register pair (bc, de, hl, af) | pp = 00, 01, 10, 11 |
Q | 16-bit register (bc, de, hl/ix/iy, sp) | qq = 00, 01, 10, 11 |
R | 8-bit general purpose register (a, b, c, d, e, h, l) | rrr (or sss) = 111, 000, 001, 010, 011, 100, 101 |
S | Restart address (0x00, 0x08,..., 0x38) | sss = 000, 001,..., 111 |
Flags
- - = no change
- + = change by definition (if noted, by the operation marked with '=> flags', otherwise by the only non-single-bit operation):
* S = sign, bit 7 of the result byte (accumulator or high byte for 16-bit operations) * Z = zero, set if the result is zero (8 or 16-bit value) * 5 = undocumented, bit 5 of the result byte * H = half-carry, the carry (theoretical bit 4) of the low nibble of the result byte * 3 = undocumented, bit 3 of the result byte * P = parity (set if the result byte has an even number of bits set) or overflow (set when crossing the boundary of the signed range); always specified * N = negative, set if the previous operation was a subtraction; always specified * C = carry, the theoretical bit 8 of the result byte
- 0 = always reset
- 1 = always set
- X = change described under Effect
- P = parity (only for the parity flag)
- V = overflow (only for the parity flag)
- A = OR with the respective bit of the accumulator
- C = set if the counter (bc) is nonzero after decrementing
Miscellaneous
- () = indirection
- (()) = I/O port
- [] = operator precedence (to avoid confusion with indirection)
- E.B = the Bth bit of the value of expression E
- * = any bit value (0 or 1)
- wz = an internal 16-bit register connected to 16-bit operations
- tmp, tmp2 = temporary storage whose value is thrown away after each instruction
Letter A
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
adc a,R | 10001rrr | 1 | 4 (4) | + | + | + | + | + | V | 0 | + | a += R + cf | Add with Carry |
adc a,J | 11i11101 1000110b | 2 | 8 (4,4) | + | + | + | + | + | V | 0 | + | a += J + cf | |
adc a,N | 11001110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | + | + | V | 0 | + | a += N + cf | |
adc a,(hl) | 10001110 | 2 | 7 (4,3) | + | + | + | + | + | V | 0 | + | a += (hl) + cf | |
adc a,(I+D) | 11i11101 10001110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | + | + | V | 0 | + | a += (I+D) + cf | |
adc hl,Q | 11101101 01qq1010 | 4 | 15 (4,4,4,3) | + | + | + | + | + | V | 0 | + | hl += Q + cf | |
add a,R | 10000rrr | 1 | 4 (4) | + | + | + | + | + | V | 0 | + | a += R | Add |
add a,J | 11i11101 1000010b | 2 | 8 (4,4) | + | + | + | + | + | V | 0 | + | a += J | |
add a,N | 11000110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | + | + | V | 0 | + | a += N | |
add a,(hl) | 10000110 | 2 | 7 (4,3) | + | + | + | + | + | V | 0 | + | a += (hl) | |
add a,(I+D) | 11i11101 10000110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | + | + | V | 0 | + | a += (I+D) | |
add hl,Q | 00qq1001 | 3 | 11 (4,4,3) | - | - | + | + | + | - | 0 | + | hl += Q | |
add I,Q | 11i11101 00qq1001 | 4 | 15 (4,4,4,3) | - | - | + | + | + | - | 0 | + | I += Q | |
and R | 10100rrr | 1 | 4 (4) | + | + | + | 1 | + | P | 0 | 0 | a := a AND R | Logical AND |
and J | 11i11101 1010010b | 2 | 8 (4,4) | + | + | + | 1 | + | P | 0 | 0 | a := a AND J | |
and N | 11100110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | 1 | + | P | 0 | 0 | a := a AND N | |
and (hl) | 10100110 | 2 | 7 (4,3) | + | + | + | 1 | + | P | 0 | 0 | a := a AND (hl) | |
and (I+D) | 11i11101 10100110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | 1 | + | P | 0 | 0 | a := a AND (I+D) |
Letter B
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
bit B,R | 11001011 01bbbrrr | 2 | 8 (4,4) | + | + | + | 1 | + | P | 0 | - | tmp := R AND [1 << B] | Test Bit |
bit B,(hl) | 11001011 01bbb110 | 3 | 12 (4,4,4) | + | + | X | 1 | X | P | 0 | - | tmp := (hl) AND [1 << B],
f5 := wz.13, f3 := wz.11 | |
bit B,(I+D) | 11i11101 11001011 dddddddd 01bbb*** | 6 | 20 (4,4,3,5,4) | + | + | X | 1 | X | P | 0 | - | tmp := (I+D) AND [1 << B],
f5 := [I+D].13, f3 := [I+D].11 |
Letter C
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
call A | 11001101 alalalal ahahahah | 5 | 17 (4,3,4,3,3) | - | - | - | - | - | - | - | - | sp -= 2, (sp) := pc, pc := A | Call |
call C,A | 11ccc100 alalalal ahahahah | 5/3 | 17/10 (4,3,4,3,3)/(4,3,3) | - | - | - | - | - | - | - | - | if C then sp -= 2, (sp) := pc, pc := A | Conditional Call |
ccf | 00111111 | 1 | 4 (4) | - | - | A | X | A | - | 0 | X | hf := cf, cf := ~cf | Complement Carry Flag |
cp R | 10111rrr | 1 | 4 (4) | + | + | X | + | X | V | 1 | + | tmp := a - R, f5 := R.5, f3 := R.3 | Compare |
cp J | 11i11101 1011110b | 2 | 8 (4,4) | + | + | X | + | X | V | 1 | + | tmp := a - J, f5 := J.5, f3 := J.3 | |
cp N | 11111110 nnnnnnnn | 2 | 7 (4,3) | + | + | X | + | X | V | 1 | + | tmp := a - N, f5 := N.5, f3 := N.3 | |
cp (hl) | 10111110 | 2 | 7 (4,3) | + | + | X | + | X | V | 1 | + | tmp := a - (hl), f5 := (hl).5, f3 := (hl).3 | |
cp (I+D) | 11i11101 10111110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | X | + | X | V | 1 | + | tmp := a - (I+D), f5 := (I+D).5, f3 := (I+D).3 | |
cpd | 11101101 10101001 | 4 | 16 (4,4,3,5) | + | + | X | + | X | C | 1 | - | tmp := a - (hl) => flags, bc -= 1, hl -= 1,
f5 := [tmp - hf].1, f3 = [tmp - hf].3 |
Compare and Decrement |
cpdr | 11101101 10111001 | 6/4 | 21/16 (4,4,3,5,5)/(4,4,3,5) | + | + | X | + | X | C | 1 | - | cpd, if bc <> 0 and nz then pc -= 2 | Compare and Decrement, Repeat |
cpi | 11101101 10100001 | 4 | 16 (4,4,3,5) | + | + | X | + | X | C | 1 | - | tmp := a - (hl) => flags, bc -= 1, hl += 1,
f5 := [tmp - hf].1, f3 = [tmp - hf].3 |
Compare and Increment |
cpir | 11101101 10110001 | 6/4 | 21/16 (4,4,3,5,5)/(4,4,3,5) | + | + | X | + | X | C | 1 | - | cpi, if bc <> 0 and nz then pc -= 2 | Compare and Increment, Repeat |
cpl | 00101111 | 1 | 4 (4) | - | - | + | 1 | + | - | 1 | - | a := ~a | Complement |
Letter D
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
daa | 00100111 | 1 | 4 (4) | + | + | + | X | + | P | - | X | tmp := a,
if nf then if hf or [a AND 0x0f > 9] then tmp -= 0x06 if cf or [a > 0x99] then tmp -= 0x60 else if hf or [a AND 0x0f > 9] then tmp += 0x06 if cf or [a > 0x99] then tmp += 0x60 endif, tmp => flags, cf := cf OR [a > 0x99], hf := a.4 XOR tmp.4, a := tmp |
Decimal Adjust Accumulator |
dec R | 00rrr101 | 1 | 4 (4) | + | + | + | + | + | V | 1 | - | R -= 1 | Decrement |
dec J | 11i11101 0010b101 | 2 | 8 (4,4) | + | + | + | + | + | V | 1 | - | J -= 1 | |
dec (hl) | 00110101 | 3 | 11 (4,4,3) | + | + | + | + | + | V | 1 | - | (hl) -= 1 | |
dec (I+D) | 11i11101 00110101 dddddddd | 6 | 23 (4,4,3,5,4,3) | + | + | + | + | + | V | 1 | - | (I+D) -= 1 | |
dec Q | 00qq1011 | 2 | 6 (6) | - | - | - | - | - | - | - | - | Q -= 1 | |
dec I | 11i11101 00101011 | 3 | 10 (4,6) | - | - | - | - | - | - | - | - | I -= 1 | |
di | 11110011 | 1 | 4 (4) | - | - | - | - | - | - | - | - | iff1 := 0, iff2 := 0 | Disable Interrupts |
djnz E | 00010000 dddddddd | 4/3 | 13/8 (5,3,5)/(5,3) | - | - | - | - | - | - | - | - | b -= 1, if b <> 0 then pc := E | Decrement, Jump Non-Zero |
Letter E
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ei | 11111011 | 1 | 4 (4) | - | - | - | - | - | - | - | - | iff1 := 1, iff2 := 1 after the next instruction | Enable Interrupts |
ex (sp),hl | 11100011 | 6 | 19 (4,3,4,3,5) | - | - | - | - | - | - | - | - | (sp) <=> hl | Exchange |
ex (sp),I | 11i11101 11100011 | 7 | 23 (4,4,3,4,3,5) | - | - | - | - | - | - | - | - | (sp) <=> I | |
ex af,af' | 00001000 | 1 | 4 (4) | X | X | X | X | X | X | X | X | af <=> af' | |
ex de,hl | 11101011 | 1 | 4 (4) | - | - | - | - | - | - | - | - | de <=> hl | |
exx | 11011001 | 1 | 4 (4) | - | - | - | - | - | - | - | - | bc, de, hl <=> bc', de', hl' |
Letter H
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
halt | 01110110 | 1 | 4 (4) | - | - | - | - | - | - | - | - | wait for interrupt | Suspends CPU operation |
Letter I
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
im 0 | 11101101 01*0*110 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | mode 0: execute instruction on bus | Set Interrupt Mode |
im 1 | 11101101 01*10110 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | mode 1: execute rst 38h | |
im 2 | 11101101 01*11110 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | mode 2: call (i * 256 + byte on bus) | |
in a,(N) | 11011011 nnnnnnnn | 3 | 11 (4,3,4) | - | - | - | - | - | - | - | - | a := ((N)) | I/O Input |
in R,(c) | 11101101 01rrr000 | 4 | 12 (4,4,4) | + | + | + | 0 | + | P | 0 | - | R := ((c)) | |
in f,(c) | 11101101 01110000 | 4 | 12 (4,4,4) | + | + | + | 0 | + | P | 0 | - | tmp := ((c)) | |
inc R | 00rrr100 | 1 | 4 (4) | + | + | + | + | + | V | 0 | - | R += 1 | Increment |
inc J | 11i11101 0010b100 | 2 | 8 (4,4) | + | + | + | + | + | V | 0 | - | J += 1 | |
inc (hl) | 00110100 | 3 | 11 (4,4,3) | + | + | + | + | + | V | 0 | - | (hl) += 1 | |
inc (I+D) | 11i11101 00110100 dddddddd | 6 | 23 (4,4,3,5,4,3) | + | + | + | + | + | V | 0 | - | (I+D) += 1 | |
inc Q | 00qq0011 | 2 | 6 (6) | - | - | - | - | - | - | - | - | Q += 1 | |
inc I | 11i11101 00100011 | 3 | 10 (4,6) | - | - | - | - | - | - | - | - | I += 1 | |
ind | 11101101 10101010 | 5 | 16 (4,5,3,4) | + | + | + | X | + | X | X | X | tmp := ((c)), (hl) := tmp, hl -= 1,
b -= 1 => flags, nf := tmp.7, tmp2 = tmp + [[c - 1] AND 0xff], pf := parity of [[tmp2 AND 0x07] XOR b], hf := cf := tmp2 > 255 |
I/O Input and Decrement |
indr | 11101101 10111010 | 6/5 | 21/16 (4,5,3,4,5)/(4,5,3,4) | + | + | + | X | + | X | X | X | ind, if b <> 0 then pc -= 2 | I/O Input and Decrement, Repeat |
ini | 11101101 10100010 | 5 | 16 (4,5,3,4) | + | + | + | X | + | X | X | X | tmp := ((c)), (hl) := tmp, hl += 1,
b -= 1 => flags, nf := tmp.7, tmp2 := tmp + [[c + 1] AND 0xff], pf := parity of [[tmp2 AND 0x07] XOR b], hf := cf := tmp2 > 255 |
I/O Input and Increment |
inir | 11101101 10110010 | 6/5 | 21/16 (4,5,3,4,5)/(4,5,3,4) | + | + | + | X | + | X | X | X | ini, if b <> 0 then pc -= 2 | I/O Input and Increment, Repeat |
Letter J
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
jp A | 11000011 alalalal ahahahah | 3 | 10 (4,3,3) | - | - | - | - | - | - | - | - | pc := A | Jump |
jp (hl) | 11101001 | 1 | 4 (4) | - | - | - | - | - | - | - | - | pc := hl | |
jp (I) | 11i11101 11101001 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | pc := I | |
jp C,A | 11ccc010 alalalal ahahahah | 3 | 10 (4,3,3) | - | - | - | - | - | - | - | - | if C then pc := A | Conditional Jump |
jr E | 00011000 dddddddd | 3 | 12 (4,3,5) | - | - | - | - | - | - | - | - | pc := E | Relative Jump |
jr nz,E | 00100000 dddddddd | 3/2 | 12/7 (4,3,5)/(4,3) | - | - | - | - | - | - | - | - | if nz then pc := E | Conditional Relative Jump |
jr z,E | 00101000 dddddddd | 3/2 | 12/7 (4,3,5)/(4,3) | - | - | - | - | - | - | - | - | if zf then pc := E | |
jr nc,E | 00110000 dddddddd | 3/2 | 12/7 (4,3,5)/(4,3) | - | - | - | - | - | - | - | - | if nc then pc := E | |
jr c,E | 00111000 dddddddd | 3/2 | 12/7 (4,3,5)/(4,3) | - | - | - | - | - | - | - | - | if cf then pc := E |
Letter L
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ld R1,R2 | 01rrrsss | 1 | 4 (4) | - | - | - | - | - | - | - | - | R1 := R2 | Load |
ld R,J | 11i11101 01rrr10b | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | R := J | |
ld J,R | 11i11101 0110brrr | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | J := R | |
ld ixh,ixl | 11011101 01100101 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | ixh := ixl | |
ld ixl,ixh | 11011101 01101100 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | ixl := ixh | |
ld iyh,iyl | 11111101 01100101 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | iyh := iyl | |
ld iyl,iyh | 11111101 01101100 | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | iyl := iyh | |
ld R,N | 00rrr110 nnnnnnnn | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | R := N | |
ld R,(hl) | 01rrr110 | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | R := (hl) | |
ld R,(I+D) | 11i11101 01rrr110 dddddddd | 5 | 19 (4,4,3,5,3) | - | - | - | - | - | - | - | - | R := (I+D) | |
ld (hl),R | 01110rrr | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | (hl) := R | |
ld (hl),N | 00110110 nnnnnnnn | 3 | 10 (4,3,3) | - | - | - | - | - | - | - | - | (hl) := N | |
ld (I+D),R | 11i11101 01110rrr dddddddd | 5 | 19 (4,4,3,5,3) | - | - | - | - | - | - | - | - | (I+D) := R | |
ld (I+D),N | 11i11101 00110110 dddddddd nnnnnnnn | 6 | 19 (4,4,3,5,3) | - | - | - | - | - | - | - | - | (I+D) := N | |
ld a,(bc) | 00001010 | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | a := (bc) | |
ld a,(de) | 00011010 | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | a := (de) | |
ld a,(A) | 00111010 alalalal ahahahah | 4 | 13 (4,3,3,3) | - | - | - | - | - | - | - | - | a := (A) | |
ld (bc),a | 00000010 | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | (bc) := a | |
ld (de),a | 00010010 | 2 | 7 (4,3) | - | - | - | - | - | - | - | - | (de) := a | |
ld (A),a | 00110010 alalalal ahahahah | 4 | 13 (4,3,3,3) | - | - | - | - | - | - | - | - | (A) := a | |
ld i,a | 11101101 01000111 | 3 | 9 (4,5) | - | - | - | - | - | - | - | - | i := a | |
ld r,a | 11101101 01001111 | 3 | 9 (4,5) | - | - | - | - | - | - | - | - | r := a | |
ld a,i | 11101101 01010111 | 3 | 9 (4,5) | + | + | + | 0 | + | X | 0 | - | a := i, pf := iff2 | |
ld a,r | 11101101 01011111 | 3 | 9 (4,5) | + | + | + | 0 | + | X | 0 | - | a := r, pf := iff2 | |
ld Q,A | 00qq0001 alalalal ahahahah | 3 | 10 (4,3,3) | - | - | - | - | - | - | - | - | Q := A | |
ld I,A | 11i11101 00100001 alalalal ahahahah | 4 | 14 (4,4,3,3) | - | - | - | - | - | - | - | - | I := A | |
ld Q,(A) | 11101101 01qq1011 alalalal ahahahah | 6 | 20 (4,4,3,3,3,3) | - | - | - | - | - | - | - | - | Q := (A) | |
ld hl,(A) | 00101010 alalalal ahahahah | 5 | 16 (4,3,3,3,3) | - | - | - | - | - | - | - | - | hl := (A) | |
ld I,(A) | 11i11101 00101010 alalalal ahahahah | 6 | 20 (4,4,3,3,3,3) | - | - | - | - | - | - | - | - | I := (A) | |
ld (A),Q | 11101101 01qq0011 alalalal ahahahah | 6 | 20 (4,4,3,3,3,3) | - | - | - | - | - | - | - | - | (A) := Q | |
ld (A),hl | 00100010 alalalal ahahahah | 5 | 16 (4,3,3,3,3) | - | - | - | - | - | - | - | - | (A) := hl | |
ld (A),I | 11i11101 00100010 alalalal ahahahah | 6 | 20 (4,4,3,3,3,3) | - | - | - | - | - | - | - | - | (A) := I | |
ld sp,hl | 11111001 | 2 | 6 (6) | - | - | - | - | - | - | - | - | sp := hl | |
ld sp,I | 11i11101 11111001 | 3 | 10 (4,6) | - | - | - | - | - | - | - | - | sp := I | |
ldd | 11101101 10101000 | 5 | 16 (4,4,3,5) | - | - | X | 0 | X | C | 0 | - | tmp := (hl), (de) := tmp, de -= 1, hl -= 1,
bc -= 1, f5 := [tmp + a].1, f3 := [tmp + a].3 |
Load and Decrement |
lddr | 11101101 10111000 | 6/5 | 21/16 (4,4,3,5,5)/(4,4,3,5) | - | - | X | 0 | X | C | 0 | - | ldd, if bc <> 0 then pc -= 2 | Load and Decrement, Repeat |
ldi | 11101101 10100000 | 5 | 16 (4,4,3,5) | - | - | X | 0 | X | C | 0 | - | tmp := (hl), (de) := tmp, de += 1, hl += 1,
bc -= 1, f5 := [tmp + a].1, f3 := [tmp + a].3 |
Load and Increment |
ldir | 11101101 10110000 | 6/5 | 21/16 (4,4,3,5,5)/(4,4,3,5) | - | - | X | 0 | X | C | 0 | - | ldi, if bc <> 0 then pc -= 2 | Load and Increment, Repeat |
Letter N
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
neg | 11101101 01***100 | 2 | 8 (4,4) | + | + | + | + | + | V | 1 | + | a := 0 - a | Negate |
nop | 00000000 | 1 | 4 (4) | - | - | - | - | - | - | - | - | nothing | No Operation |
Letter O
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
or R | 10110rrr | 1 | 4 (4) | + | + | + | 0 | + | P | 0 | 0 | a := a OR R | Logical Inclusive OR |
or J | 11i11101 1011010b | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | 0 | a := a OR J | |
or N | 11110110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | 0 | + | P | 0 | 0 | a := a OR N | |
or (hl) | 10110110 | 2 | 7 (4,3) | + | + | + | 0 | + | P | 0 | 0 | a := a OR (hl) | |
or (I+D) | 11i11101 10110110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | 0 | + | P | 0 | 0 | a := a OR (I+D) | |
out (N),a | 11010011 nnnnnnnn | 3 | 11 (4,3,4) | - | - | - | - | - | - | - | - | ((N)) := a | I/O Output |
out (c),R | 11101101 01rrr001 | 4 | 12 (4,4,4) | - | - | - | - | - | - | - | - | ((c)) := R | |
out (c),0 | 11101101 01110001 | 4 | 12 (4,4,4) | - | - | - | - | - | - | - | - | ((c)) := 0 (255 on CMOS CPU) | |
outd | 11101101 10101011 | 5 | 16 (4,5,3,4) | + | + | + | X | + | X | X | X | tmp := (hl), ((c)) := tmp, hl -= 1,
b -= 1 => flags, nf := tmp.7, tmp2 = tmp + l, pf := parity of [[tmp2 AND 0x07] XOR b], hf := cf := tmp2 > 255 |
I/O Output and Decrement |
otdr | 11101101 10111011 | 6/5 | 21/16 (4,5,3,4,5)/(4,5,3,4) | + | + | + | X | + | X | X | X | outd, if b <> 0 then pc -= 2 | I/O Output and Decrement, Repeat |
outi | 11101101 10100011 | 5 | 16 (4,5,3,4) | + | + | + | X | + | X | X | X | tmp := (hl), ((c)) := tmp, hl += 1,
b -= 1 => flags, nf := tmp.7, tmp2 = tmp + l, pf := parity of [[tmp2 AND 0x07] XOR b], hf := cf := tmp2 > 255 |
I/O Output and Increment |
otir | 11101101 10110011 | 6/5 | 21/16 (4,5,3,4,5)/(4,5,3,4) | + | + | + | X | + | X | X | X | outi, if b <> 0 then pc -= 2 | I/O Output and Increment, Repeat |
Letter P
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
pop P | 11pp0001 | 3 | 10 (4,3,3) | - | - | - | - | - | - | - | - | P := (sp), sp += 2 | Pop a value from the stack |
pop I | 11i11101 11100001 | 4 | 14 (4,4,3,3) | - | - | - | - | - | - | - | - | I := (sp), sp += 2 | |
push P | 11pp0101 | 4 | 11 (5,3,3) | - | - | - | - | - | - | - | - | sp -= 2, (sp) := P | Push a value onto the stack |
push I | 11i11101 11100101 | 5 | 15 (4,5,3,3) | - | - | - | - | - | - | - | - | sp -= 2, (sp) := I |
Letter R
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
res B,R | 11001011 10bbbrrr | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | R := R AND ~[1 << B] | Reset Bit |
res B,(hl) | 11001011 10bbb110 | 4 | 15 (4,4,4,3) | - | - | - | - | - | - | - | - | (hl) := (hl) AND ~[1 << B] | |
res B,(I+D) | 11i11101 11001011 dddddddd 10bbb110 | 7 | 23 (4,4,3,5,4,3) | - | - | - | - | - | - | - | - | (I+D) := (I+D) AND ~[1 << B] | |
res B,(I+D)->R | 11i11101 11001011 dddddddd 10bbbrrr | 7 | 23 (4,4,3,5,4,3) | - | - | - | - | - | - | - | - | (I+D) := R := (I+D) AND ~[1 << B] | |
ret | 11001001 | 3 | 10 (4,3,3) | - | - | - | - | - | - | - | - | pc := (sp), sp += 2 | Return |
ret C | 11ccc000 | 4/2 | 11/5 (5,3,3)/(5) | - | - | - | - | - | - | - | - | if C then pc := (sp), sp += 2 | Conditional Return |
reti | 11101101 01001101 | 4 | 14 (4,4,3,3) | - | - | - | - | - | - | - | - | pc := (sp), sp += 2, iff1 := iff2 | Return from Interrupt |
retn | 11101101 01***101 | 4 | 14 (4,4,3,3) | - | - | - | - | - | - | - | - | pc := (sp), sp += 2, iff1 := iff2 | Return from NMI |
rla | 00010111 | 1 | 4 (4) | - | - | + | 0 | + | - | 0 | X | ocf := cf, cf := a.7, a := [a << 1] + ocf | Rotate Left Accumulator |
rl R | 11001011 00010rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := R.7, R := [R << 1] + ocf | Rotate Left |
rl (hl) | 11001011 00010110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := (hl).7, (hl) := [(hl) << 1] + ocf | |
rl (I+D) | 11i11101 11001011 dddddddd 00010110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := (I+D).7, (I+D) := [(I+D) << 1] + ocf | |
rl (I+D)->R | 11i11101 11001011 dddddddd 00010rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := (I+D).7, (I+D) := R := [(I+D) << 1] + ocf | |
rlca | 00000111 | 1 | 4 (4) | - | - | + | 0 | + | - | 0 | X | cf := a.7, a := [a << 1] + cf | Rotate Left Carry Accumulator |
rlc R | 11001011 00000rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | cf := R.7, R := [R << 1] + cf | Rotate Left Carry |
rlc (hl) | 11001011 00000110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (hl).7, (hl) := [(hl) << 1] + cf | |
rlc (I+D) | 11i11101 11001011 dddddddd 00000110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).7, (I+D) := [(I+D) << 1] + cf | |
rlc (I+D)->R | 11i11101 11001011 dddddddd 00000rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).7, (I+D) := R := [(I+D) << 1] + cf | |
rld | 11101101 01101111 | 5 | 18 (4,4,3,4,3) | + | + | + | 0 | + | P | 0 | - | tmp := [(hl) << 4] + [a AND 0x0f], (hl) := tmp,
a := [a AND 0xf0] + [tmp >> 8] => flags |
Rotate Left Decimal |
rra | 00011111 | 1 | 4 (4) | - | - | + | 0 | + | - | 0 | X | ocf := cf, cf := a.0, a := [a >> 1] + [ocf << 7] | Rotate Right Accumulator |
rr R | 11001011 00011rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := R.0, R := [R >> 1] + [ocf << 7] | Rotate Right |
rr (hl) | 11001011 00011110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := (hl).0, (hl) := [(hl) >> 1] + [ocf << 7] | |
rr (I+D) | 11i11101 11001011 dddddddd 00011110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := (I+D).0, (I+D) := [(I+D) >> 1] + [ocf << 7] | |
rr (I+D)->R | 11i11101 11001011 dddddddd 00011rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | ocf := cf, cf := (I+D).0, (I+D) := R := [(I+D) >> 1] + [ocf << 7] | |
rrca | 00001111 | 1 | 4 (4) | - | - | + | 0 | + | - | 0 | X | cf := a.0, a := [a >> 1] + [cf << 7] | Rotate Right Carry Accumulator |
rrc R | 11001011 00001rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | cf := R.0, R := [R >> 1] + [cf << 7] | Rotate Right Carry |
rrc (hl) | 11001011 00001110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (hl).0, (hl) := [(hl) >> 1] + [cf << 7] | |
rrc (I+D) | 11i11101 11001011 dddddddd 00001110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).0, (I+D) := [(I+D) >> 1] + [cf << 7] | |
rrc (I+D)->R | 11i11101 11001011 dddddddd 00001rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).0, (I+D) := R := [(I+D) >> 1] + [cf << 7] | |
rrd | 11101101 01100111 | 5 | 18 (4,4,3,4,3) | + | + | + | 0 | + | P | 0 | - | tmp := (hl), (hl) := [tmp >> 4] + [[a AND 0x0f] << 4],
a := [a AND 0xf0] + [tmp AND 0x0f] => flags |
Rotate Right Decimal |
rst S | 11sss111 | 4 | 11 (5,3,3) | - | - | - | - | - | - | - | - | sp -= 2, (sp) := pc, pc := S | Restart |
Letter S
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
sbc a,R | 10011rrr | 1 | 4 (4) | + | + | + | + | + | V | 1 | + | a -= R + cf | Subtract with Carry |
sbc a,J | 11i11101 1001110b | 2 | 8 (4,4) | + | + | + | + | + | V | 1 | + | a -= J + cf | |
sbc a,N | 11011110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | + | + | V | 1 | + | a -= N + cf | |
sbc a,(hl) | 10011110 | 2 | 7 (4,3) | + | + | + | + | + | V | 1 | + | a -= (hl) + cf | |
sbc a,(I+D) | 11i11101 10011110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | + | + | V | 1 | + | a -= (I+D) + cf | |
sbc hl,Q | 11101101 01qq0010 | 4 | 15 (4,4,4,3) | + | + | + | + | + | V | 1 | + | hl -= Q + cf | |
scf | 00110111 | 1 | 4 (4) | - | - | A | 0 | A | - | 0 | 1 | nothing else | Set Carry Flag |
set B,R | 11001011 11bbbrrr | 2 | 8 (4,4) | - | - | - | - | - | - | - | - | R := R OR [1 << B] | Set Bit |
set B,(hl) | 11001011 11bbb110 | 4 | 15 (4,4,4,3) | - | - | - | - | - | - | - | - | (hl) := (hl) OR [1 << B] | |
set B,(I+D) | 11i11101 11001011 dddddddd 11bbb110 | 7 | 23 (4,4,3,5,4,3) | - | - | - | - | - | - | - | - | (I+D) := (I+D) OR [1 << B] | |
set B,(I+D)->R | 11i11101 11001011 dddddddd 11bbbrrr | 7 | 23 (4,4,3,5,4,3) | - | - | - | - | - | - | - | - | (I+D) := R := (I+D) OR [1 << B] | |
sla R | 11001011 00100rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | cf := R.7, R := R << 1 | Shift Left Arithmetic |
sla (hl) | 11001011 00100110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (hl).7, (hl) := (hl) << 1 | |
sla (I+D) | 11i11101 11001011 dddddddd 00100110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).7, (I+D) := (I+D) << 1 | |
sla (I+D)->R | 11i11101 11001011 dddddddd 00100rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).7, (I+D) := R := (I+D) << 1 | |
sra R | 11001011 00101rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | cf := R.0, R := R >> 1, R.7 := R.6 | Shift Right Arithmetic |
sra (hl) | 11001011 00101110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (hl).0, (hl) := (hl) >> 1, (hl).7 := (hl).6 | |
sra (I+D) | 11i11101 11001011 dddddddd 00101110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).0,
(I+D) := (I+D) >> 1, (I+D).7 := (I+D).6 | |
sra (I+D)->R | 11i11101 11001011 dddddddd 00101rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).0,
tmp := (I+D) >> 1, tmp.7 := tmp.6, (I+D) := R := tmp | |
sll R | 11001011 00110rrr | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | X | cf := R.7, R := [R << 1] + 1 | Shift Left Logical |
sll (hl) | 11001011 00110110 | 4 | 15 (4,4,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (hl).7, (hl) := [(hl) << 1] + 1 | |
sll (I+D) | 11i11101 11001011 dddddddd 00110110 | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).7, (I+D) := [(I+D) << 1] + 1 | |
sll (I+D)->R | 11i11101 11001011 dddddddd 00110rrr | 7 | 23 (4,4,3,5,4,3) | + | + | + | 0 | + | P | 0 | X | cf := (I+D).7, (I+D) := R := [(I+D) << 1] + 1 | |
srl R | 11001011 00111rrr | 2 | 8 (4,4) | 0 | + | + | 0 | + | P | 0 | X | cf := R.0, R := R >> 1 | Shift Right Logical |
srl (hl) | 11001011 00111110 | 4 | 15 (4,4,3) | 0 | + | + | 0 | + | P | 0 | X | cf := (hl).0, (hl) := (hl) >> 1 | |
srl (I+D) | 11i11101 11001011 dddddddd 00111110 | 7 | 23 (4,4,3,5,4,3) | 0 | + | + | 0 | + | P | 0 | X | cf := (I+D).0, (I+D) := (I+D) >> 1 | |
srl (I+D)->R | 11i11101 11001011 dddddddd 00111rrr | 7 | 23 (4,4,3,5,4,3) | 0 | + | + | 0 | + | P | 0 | X | cf := (I+D).0, (I+D) := R := (I+D) >> 1 | |
sub R | 10010rrr | 1 | 4 (4) | + | + | + | + | + | V | 1 | + | a -= R | Subtract |
sub J | 11i11101 1001010b | 2 | 8 (4,4) | + | + | + | + | + | V | 1 | + | a -= J | |
sub N | 11010110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | + | + | V | 1 | + | a -= N | |
sub (hl) | 10010110 | 2 | 7 (4,3) | + | + | + | + | + | V | 1 | + | a -= (hl) | |
sub (I+D) | 11i11101 10010110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | + | + | V | 1 | + | a -= (I+D) |
Letter X
Instruction | Opcode | NOPs | Cycles | S | Z | 5 | H | 3 | P | N | C | Effect | Description |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
xor R | 10101rrr | 1 | 4 (4) | + | + | + | 0 | + | P | 0 | 0 | a := a XOR R | Logical eXclusive OR |
xor J | 11i11101 1010110b | 2 | 8 (4,4) | + | + | + | 0 | + | P | 0 | 0 | a := a XOR J | |
xor N | 11101110 nnnnnnnn | 2 | 7 (4,3) | + | + | + | 0 | + | P | 0 | 0 | a := a XOR N | |
xor (hl) | 10101110 | 2 | 7 (4,3) | + | + | + | 0 | + | P | 0 | 0 | a := a XOR (hl) | |
xor (I+D) | 11i11101 10101110 dddddddd | 5 | 19 (4,4,3,5,3) | + | + | + | 0 | + | P | 0 | 0 | a := a XOR (I+D) |
Timings
On CPC, bus arbitration is done on every CPU bus access. On MSX, bus arbitration only applies to M1 machine cycles but access to VRAM has other limitations. On ZX Spectrum, bus arbitration is done not by using the /WAIT pin but by disabling the CPU clock when needed.
The NOPs column corresponds to CPC timings, which account for the bus arbitration managed by the Gate Array. The NOP instruction takes 4 cycles. This is the minimum amount of cycles an instruction can take.
Every M-cycle that involves a memory or I/O access will be stretched due to bus arbitration. But beware, some M-cycles are purely internal and don't involve a memory or I/O access.
Nevertheless, a few CPC timings can appear surprising at first glance:
- Instructions LD (IX+d),r and LD (IX+d),n take 5 and 6 NOPs respectively, even though they are both listed as 19 (4,4,3,5,3) cycles in the datasheet. This happens because LD (IX+d),r has one less memory access operation to do compared to LD (IX+d),n as it does not have to fetch its operand from memory.
- Instructions IN r,(C) and OUT (C),r take 4 NOPs with CPC timings, even though they are listed as 12 (4,4,4) cycles in the datasheet. This happens because I/O access is not aligned with memory access. On Zilog manual, it is precised that one wait-state TW is automatically inserted after T2 on I/O access.
The CPC timings of some instructions will be altered if an interrupt happens. The interrupt test occurs on the last T-State of the instruction, and if it's low, the Z80 will insert 2 wait states to acknowledge the interrupt.
So, instructions which end in the third or fourth T-State relative to the read alignment for the next instruction fetch will be delayed by an extra 4 T-States. The few instructions which end in the first or second T-State won't since the first instruction fetch/read in the interrupt won't be delayed an extra 4 T-States. Source
Opcodes
The Z80 follows a 2-3-3 opcode bit pattern.
All CB-prefixed opcodes and half of the standard opcodes (from &40 to &BF) follow a strict uniform layout. The sole exception is the HALT instruction (opcode &76), which replaces the expected LD (HL),(HL) instruction.
The rest of the opcode table is also neatly organised but in an horizontal way instead of vertical.
Any instruction in bold is undocumented by Zilog.
Standard opcodes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CB-prefixed opcodes
|
|
|
|
|
|
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
ED-prefixed opcodes
The opcodes that are not mentioned in the following table are EDNOP (ED-prefixed NOP instruction). Thay have no effect but take 8 cycles and increment the register R two times. EDED, EDDD, EDFD and EDCB are also EDNOP instructions.
|
|
|
|
|
|
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
Notes:
- The opcode ED70 reads the port indicated by the register C without keeping the result but modifies the register F
- The opcode ED71 corresponds to the instruction OUT (C),255 on a CMOS Z80
- The opcode EDFF is used by Winape (and other emulators) to break into the debugger (a 'break opcode') Source
DD or FD-prefixed opcodes
If an opcode is prefixed by DD, the instruction is changed as follows:
- HL is replaced by IX
- H is replaced by IXH
- L is replaced by IXL
- (HL) is replaced by (IX+d)
Same for the FD prefix but with IY instead of IX.
There are 3 exceptions:
- In the instruction EX DE,HL, HL will not be replaced with IX or IY. The EXX instruction is not affected either.
- If (HL) and L or H are used in the same instruction, L and H are not replaced with IXL or IXH. For instance LD L,(IX+d) stores the content of (IX+d) into L, not IXL.
- If the next byte is a DD, ED or FD prefix, the current DD or FD prefix is ignored (it's equivalent to a NONI) and processing continues with the next byte. ED-prefixed opcodes cannot be altered by DD or FD prefixes.
DDCB or FDCB-prefixed opcodes
When a DD or FD prefix is followed by a CB byte, the CB acts as a second prefix. A mandatory displacement byte comes next, and then the actual opcode.
If the instruction produces output other than in the flags (i.e. all except BIT), then the result gets placed both into (IX+d) or (IY+d) and into the register one would normally expect to be altered.
DDCB and FDCB-prefixed instructions only increment the R register twice. Source
Oddities
- RETI and RETN are identical instructions Source. The only reason for RETI is so that some other hardware can detect the specific case of returning from the interrupt, by detecting the RETI opcode on the data bus.
- EI has a 1-instruction delay. It is necessary for doing EI/RETI without any danger of nested interrupt routines.
- At the end of an NMI service routine, the earliest moment a maskable interrupt will be triggered is at the end of the instruction following RETN. Source
- RST instructions are just a CALL instruction to a fixed address baked in the instruction itself.
- Despite what the syntax of the instructions JP (HL/IX/IY) suggests, PC will be loaded with the contents of the register itself, not the indexed value. Those instructions should be understood as JP HL/IX/IY.
- The 16-bit commands ADD HL,ss, ADC HL,ss and SBC HL,ss exist but not the command SUB HL,ss.
- While the syntax of the 8-bit ADD, ADC and SBC instructions all explicitly mention the A register, the SUB instruction does not mention it. On the Zilog eZ80, the SUB instruction explicitly mention the A register.
- IN r,(C) and OUT (C),r instructions syntax is misleading as these instructions actually use the full 16-bit port address contained in BC. On the Zilog eZ80, these instructions are correctly named IN, r,(BC) and OUT (BC),r.
- The Amstrad engineers chose to use the high byte of the address (register B) for chip selection instead of the low byte (register C) in I/O operations. As a result, OTIR / OTDR / INIR / INDR instructions cannot be used on Amstrad CPC for transferring or reading a sequence of values on a port as they use B as a counter.
- INI/IND/INIR/INDR decrease B after storing the byte from the hardware port into memory. And OUTI/OUTD/OTIR/OTDR decrease B before sending the memory byte to the hardware port. Source
- All PUSH and POP instructions utilize a 16-bit operand and the high-order byte is always pushed first and popped last. PUSH HL is PUSH H then L. POP HL is POP L then H.
- When an LDxR / CPxR / INxR / OTxR instruction is interrupted, the interrupt handler sees some flags in a different state. Source
- LD A,I and LD A,R normally copy the state of IFF2 to the Parity flag. NMOS Z80 suffers a problem whereby LD A,I and LD A,R record the state of IFF2 after it has been reset if an interrupt is delivered during that instruction. Source
Block Diagram
CPU Pinout
Note: A reset disables the maskable interrupt, selects interrupt mode 0, zeroes registers I & R and zeroes the program counter (PC).
Chip Variants
The GBZ80 (Sharp SM83) that powers the original Nintendo GameBoy is an in-between the Intel 8080 and Z80. Source
The KC Compact uses the U880, which is an unlicensed clone of the Z80 manufactured by MME. It was the most widely used microprocessor in the German Democratic Republic. Source
The КМ1582ВМ-0100 is a Soviet clone of the Z80. It is used in the Aleste 520EX clone of the Amstrad CPC computer.
The ASCII R800 that powers the MSX TurboR is a seriously beefed up version of the Z80:
- The ALU of the R800 is 16-bit instead of 4-bit for the Z80. This change allows instructions that were being executed in 4 cycles to be done in 1 cycle.
- The instruction set of the R800 is almost identical to the Z80. Only 2 instructions have been added: MULUB and MULUW. And many of the undocumented instructions of the Z80 were made official.
Zilog itself offers the eZ80 processor, a binary-compatible upgrade of the Z80, which runs at up to 50MHz but performs like a 150MHz Z80 due to being 3 times faster at the same clock speed.
Manuals
- Official Zilog Z80 CPU user manual (2016)
- Media:Z80 CPU Technical Manual 1977.pdf
- Media:Mostek Z80 Programming Manual.pdf
- Media:Z80-Mostek-Technical-Manual.pdf Text version - provides a detailed breakdown of the machine cycles
- Media:Mostek Z80 Micro-Reference Manual Feb78.pdf
- Media:Z80 CPU Instant Reference Card (Color).pdf
- Media:Z80 CPC Timings cheat sheet.20230709.pdf
- MEMPTR, esoteric register of the Z80 CPU
- The Undocumented Z80 Documented
- Z80 - undocumented opcodes
Weblinks
- Zilog [1]
- Computer Systems based on Z80 Family
- The Z80 processor on Wikipedia
- Z80 article on Sinclair Wiki
- Z80 documentation from Grimware
- Decoding Z80 opcodes
- Interrupt behaviour of the Z80 CPU
- Behaviour of the undocumented flags
- Complete list of Z80 instructions and their bus responses and cycles dumped from real hardware
- Detailed look at Z80 instruction timings with the help of a Z80 netlist simulation
- Cycle-stepped Z80 emulation how-to
- Tom Harte's SingleStepTests