Place Z80 documentation close to the Z80 emulator.

Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian.Conlon 2017-08-07 09:30:04 +01:00
parent 88d773708c
commit ab20fc6107
10 changed files with 3092 additions and 0 deletions

View File

@ -0,0 +1,795 @@
<!-- saved from url=(0032)http://www.z80.info/decoding.htm -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Decoding Z80 Opcodes</title>
<meta name="description" content="An algorithmic approach to decoding z80 instructions stored in memory, for use in disassemblers and emulators.">
<meta name="author" content="Cristian Dinu">
<style type="text/css">
/* General */
BODY {
margin: 0; padding: 1pc 2pc;
background: #f0f0ff; color: black;
font-family: times;
}
A:link, A:active, A:visited {
color: blue;
text-decoration: none;
}
A:hover {
color: red;
text-decoration: underline;
}
H1 {
text-align: center;
font-weight: bold; font-size: 120%;
}
H2 {
color: fuchsia;
text-align: center;
font-weight: bold; font-size: 110%;
}
H3 {
color: blue;
text-align: center;
font-weight: bold; font-size: 110%;
}
H4 {
text-align: left;
font-weight: bold; font-size: 110%;
}
H5 {
text-align: center;
font-size: 90%;
}
P {
text-align: justify;
}
HR {
border: none; border-top: 1px solid gray;
width: 80%;
}
HR.Short {
border: none; border-top: 1px solid gray;
width: 50%;
}
TABLE {
margin: 0;
border-collapse: collapse;
}
TD {
padding: 0;
border: 1px solid black; border: 0;
text-align: justify;
}
OL, UL {
padding: 0; padding-left: 1.5pc;
}
/* Disassembly tables */
TABLE.DissTable8 {
border: 1px solid gray;
margin-bottom: 1em;
width: 100%;
}
TABLE.DissTable8 TD.Left {
padding: 1px;
border: 1px solid gray;
background: #e0e0e0;
font-weight:bold;
width: 12%;
}
TABLE.DissTable8 TD {
padding: 1px;
border: 1px solid gray;
background: white;
font-size: 90%;
text-align:center; vertical-align: middle;
width: 11%;
}
TABLE.DissTable4 {
border: 1px solid gray;
margin-bottom: 1em;
width: 100%;
}
TABLE.DissTable4 TD.Left {
padding: 1px;
border: 1px solid gray;
background: #e0e0e0;
font-weight:bold;
width: 12%;
}
TABLE.DissTable4 TD {
padding: 1px;
border: 1px solid gray;
background: white;
font-size: 90%;
text-align:center; vertical-align: middle;
width: 22%;
}
TABLE.DissTable4x4 {
border: 1px solid gray;
margin-bottom: 1em;
width: 100%;
}
TABLE.DissTable4x4 TD.Fixed {
padding: 1px;
border: 1px solid gray;
background: #e0e0e0;
font-weight:bold;
}
TABLE.DissTable4x4 TD {
padding: 1px;
border: 1px solid gray;
background: white;
font-size: 90%;
text-align:center; vertical-align: middle;
width: 20%;
}
TH.TableName {
padding: 1px;
border: 1px solid gray;
background: #e0e0e0;
text-align:center;
font-weight:bold;
}
TH.TableDesc {
padding: 1px;
border: 1px solid gray;
background: #d0e0f0;
text-align:center;
font-weight:normal; font-size: 75%;
}
/* Figures */
DIV.Figure {
margin:0pc; padding: 0.5pc;
border: 1px solid gray;
background: #ffffff;
float: right;
}
TD.Fig1Text {
font-size:75%;
text-align:center;
}
TD.Fig1Bit {
padding: 0.1pc;
border: 1px solid gray;
font-size:75%;
text-align:center;
width: 1.5pc;
}
TD.Fig1BraceContainer {
padding-left: 2px; padding-right: 2px; padding-top: 0.3pc;
text-align: center;
}
DIV.Fig1Brace {
border: 2px solid black; border-top:0;
font-size: 0px;
height: 0.3pc;
}
SPAN.Fig1ColX {
color: #a00000;
}
SPAN.Fig1ColY {
color: #00a000;
}
SPAN.Fig1ColZ {
color: #0000a0;
}
SPAN.Fig1ColP {
color: #a000a0;
}
SPAN.Fig1ColQ {
color: #00a0a0;
}
/* Instruction table */
TABLE.InsTableZ {
margin-bottom: 1em;
width: 100%;
}
TABLE.InsTableZ TD {
padding: 0.3pc 0.6pc;
border-bottom: 1px solid #80c0a0;
vertical-align: middle;
text-align:justify;
}
TABLE.InsTableZ TD.XHeader {
border-top: 2px solid black; border-bottom: 2px solid black;
background: #e0e0ff; color: #a00000;
font-size: 120%; font-weight:bold;
text-align: center;
}
TABLE.InsTableZ TD.X {
border-right: 1px solid gray;
color: #a00000;
font-weight:bold;
text-align: right;
width: 6%;
}
TABLE.InsTableZ TD.Z {
border-right: 1px solid gray;
color: #0000a0;
font-weight:bold;
text-align: right;
width: 6%;
}
TABLE.InsTableZ TD.YTable {
padding: 0pc;
border-right: 1px solid gray;
width: 54%;
}
TABLE.InsTableZ TD.Comment {
font-size: 90%;
width: 40%;
}
TABLE.InsTableY {
width: 100%;
}
TABLE.InsTableY TD {
border: 0;
padding: 0.3pc 0.6pc;
font-weight: bold;
width: 35%;
}
TABLE.InsTableY TD.Long {
width: 80%;
}
TABLE.InsTableY TD.Q {
color: #00a0a0;
font-weight:bold;
text-align: right;
width: 10%;
}
TABLE.InsTableY TD.P {
color: #a000a0;
font-weight:bold;
text-align: right;
width: 10%;
}
TABLE.InsTableY TD.Y {
color: #00a000;
font-weight:bold;
text-align: right;
width: 10%;
}
SPAN.arg {
font-weight: normal; font-style:italic;
}
DT {
font-weight: bold;
}
DD {
text-align: justify;
}
</style>
</head>
<body>
<h1>DECODING Z80 OPCODES</h1>
<h5>- of use to disassembler and emulator writers -</h5>
<h5>Revision 2</h5>
<p>Document by Cristian Dinu, compiled using various sources of information (see the acknowledgements section). You need a browser that supports Cascading Style Sheets (CSS) to view this file.</p>
<p>For any comments, suggestions, typo/factual error reports, please visit the <a href="http://www.worldofspectrum.org/forums/index.php">World Of Spectrum forums</a> and post a message there for GOC.</p>
<hr>
<h2>CONTENTS</h2>
<table style="width:100%"><tbody><tr>
<td style="width:45%"></td>
<td>
<ol>
<li><a href="http://www.z80.info/decoding.htm#intro">Introduction</a></li>
<li><a href="http://www.z80.info/decoding.htm#upfx">Unprefixed&nbsp;opcodes</a></li>
<li><a href="http://www.z80.info/decoding.htm#cb">CB&#8209;prefixed&nbsp;opcodes</a></li>
<li><a href="http://www.z80.info/decoding.htm#ed">ED&#8209;prefixed&nbsp;opcodes</a></li>
<li><a href="http://www.z80.info/decoding.htm#dd">DD&#8209;prefixed&nbsp;opcodes</a></li>
<li><a href="http://www.z80.info/decoding.htm#fd">FD&#8209;prefixed&nbsp;opcodes</a></li>
<li><a href="http://www.z80.info/decoding.htm#ddcb">DDCB/FDCB&#8209;prefixed&nbsp;opcodes</a></li>
<li><a href="http://www.z80.info/decoding.htm#ack">Acknowledgements</a></li>
<li><a href="http://www.z80.info/decoding.htm#rev">Revision&nbsp;history</a></li>
</ol>
</td>
<td style="width:45%"></td>
</tr></tbody></table>
<hr>
<a name="intro"></a>
<h2>1. INTRODUCTION</h2>
<h4>Instruction format and emulation notes</h4>
<p>Z80 instructions are represented in memory as byte sequences of the form (items in brackets are optional):</p>
<p style="text-align:center">
[<i>prefix byte</i>,]&nbsp;&nbsp;<i>opcode</i>&nbsp;&nbsp;[,<i>displacement byte</i>]&nbsp;&nbsp;[,<i>immediate data</i>]<br>
- OR -<br>
<i>two prefix bytes</i>,&nbsp;&nbsp;<i>displacement byte</i>,&nbsp;&nbsp;<i>opcode</i>
</p>
<p>The <i>opcode</i> (operation code) is a single byte whose bit pattern indicates the operation we need the Z80 to perform (register loading, arithmetic, I/O, etc.). The opcode may also contain information regarding the operation's parameters (operands), e.g. the registers which will be used/affected by the operation.</p>
<p>An optional <i>prefix byte</i> may appear before the opcode, changing its meaning and causing the Z80 to look up the opcode in a different bank of instructions. The prefix byte, if present, may have the values <b>CB</b>, <b>DD</b>, <b>ED</b>, or <b>FD</b> (these are hexadecimal values). Although there are opcodes which have these values too, there is no ambiguity: the first byte in the instruction, if it has one of these values, is <u>always</u> a prefix byte.</p>
<p>The <i>displacement byte</i> is a signed 8-bit integer (-128..+127) used in some instructions to specifiy a displacement added to a given memory address. Its presence or absence depends on the instruction at hand, therefore, after reading the prefix and opcode, one has enough information to figure out whether to expect a displacement byte or not.</p>
<p>Similarly, <i>immediate data</i> consists of zero, one, or two bytes of additional information specifying explicit parameters for certain instructions (memory addresses, arithmetic operands, etc.). Its presence and number of bytes are also completely determined by the instruction at hand.</p>
<p><b>Note</b>: Signed data is stored in 2's complement form. 16-bit data is stored LSB first.</p>
<p>A special class of instructions is accesed by using a <b>DD</b> or <b>FD</b> prefix, and then a <b>CB</b> byte. In this situation, the <b>CB</b> byte is also interpreted as a prefix, a <i>mandatory</i> displacement byte follows, and, finally, the actual opcode occurs. This is the situation that is described by the second byte pattern shown above.</p>
<p>Not all (prefix, opcode) combinations map to valid instructions. However, it is important to note that, unlike some other processors, upon encountering an invalid instruction, the Z80 will not 'crash' or signal an error - it will simply appear to do nothing (as if executing a <b>NOP</b> instruction), and continue with the next byte sequence in memory. There may also be several subtle effects, such as the temporary setting of some internal flags or the prevention of interrupts immediately after the read instruction. Invalid instructions are sometimes used to mark special commands and signals for emulators (e.g. Gerton Lunter's 'Z80' ZX Spectrum emulator).</p>
<p>There may be several combinations of bytes that map to the same instruction. The sequences will usually have different execution times and memory footprints. Additionally, there are many instructions (not necessarily 'invalid') which do virtually nothing meaningful, such as <b>LD A, A</b>, etc., and therefore are reasonable substitutes for <b>NOP</b>.</p>
<p>Some instructions and effects are <i>undocumented</i> in that they usually do not appear in 'official' Z80 references. However, by now, these have all been researched and described in unofficial documents, and they are also used by several programs, so emulator authors should strive to implement these too, with maximal accuracy.</p>
<p>Finally, it is important to note that the disassembly approach described in this document is a rather 'algorithmic one', focused on understanding the functional structure of the instruction matrix, and on how the Z80 figures out what to do upon reading the bytes. If space isn't a concern, it is faster and easier to use complete disassembly tables that cover all possible (prefix, opcode) combinations - with text strings for the instruction display, and microcode sequences for the actual execution.</p>
<h4>Notations used in this document</h4>
<div class="Figure">
<table>
<tbody><tr><td class="Fig1Text" colspan="8">Bits in opcode (MSB &#8594; LSB)</td></tr>
<tr>
<td class="Fig1Bit"><span class="Fig1ColX">7</span></td>
<td class="Fig1Bit"><span class="Fig1ColX">6</span></td>
<td class="Fig1Bit"><span class="Fig1ColY">5</span></td>
<td class="Fig1Bit"><span class="Fig1ColY">4</span></td>
<td class="Fig1Bit"><span class="Fig1ColY">3</span></td>
<td class="Fig1Bit"><span class="Fig1ColZ">2</span></td>
<td class="Fig1Bit"><span class="Fig1ColZ">1</span></td>
<td class="Fig1Bit"><span class="Fig1ColZ">0</span></td>
</tr>
<tr>
<td class="Fig1BraceContainer" colspan="2"><div class="Fig1Brace"></div><span class="Fig1ColX"><i>x</i></span></td>
<td class="Fig1BraceContainer" colspan="3"><div class="Fig1Brace"></div><span class="Fig1ColY"><i>y</i></span></td>
<td class="Fig1BraceContainer" colspan="3"><div class="Fig1Brace"></div><span class="Fig1ColZ"><i>z</i></span></td>
</tr>
<tr>
<td colspan="2"></td>
<td class="Fig1BraceContainer" colspan="2"><div class="Fig1Brace"></div><span class="Fig1ColP"><i>p</i></span></td>
<td class="Fig1BraceContainer" colspan="1"><div class="Fig1Brace"></div><span class="Fig1ColQ"><i>q</i></span></td>
<td colspan="3"></td>
</tr>
</tbody></table>
</div>
<p>Upon establishing the opcode, the Z80's path of action is generally dictated by these values:</p>
<p>
<i>x</i> = the opcode's 1st octal digit (i.e. bits 7-6)<br>
<i>y</i> = the opcode's 2nd octal digit (i.e. bits 5-3)<br>
<i>z</i> = the opcode's 3rd octal digit (i.e. bits 2-0)<br>
<i>p</i> = <i>y</i> rightshifted one position (i.e. bits 5-4)<br>
<i>q</i> = <i>y</i> modulo 2 (i.e. bit 3)
</p>
<p>The following placeholders for instructions and operands are used:</p>
<p>
<i>d</i> = displacement byte (8-bit signed integer)<br>
<i>n</i> = 8-bit immediate operand (unsigned integer)<br>
<i>nn</i> = 16-bit immediate operand (unsigned integer)<br>
<i>tab[x]</i> = whatever is contained in the table named <i>tab</i> at index <i>x</i> (analogous for <i>y</i> and <i>z</i> and other table names)
</p>
<p>Operand data may be interpreted as the programmer desires (either signed or unsigned), but, in disassembly displays, is generally displayed in unsigned integer format.</p>
<p>All instructions with <i>d</i>, <i>n</i> or <i>nn</i> in their expression are generally immediately followed by the displacement/operand (a byte or a word, respectively).</p>
<p>Although relative jump instructions are traditionally shown with a 16-bit address for an operand, here they will take the form <b>JR</b>/<b>DJNZ</b> <i>d</i>, where <i>d</i> is the signed 8-bit displacement that follows (as this is how they are actually stored). The jump's final address is obtained by adding the displacement to the instruction's address plus 2.</p>
<p>In this document, the 'jump to the address contained in HL' instruction is written in its correct form <b>JP HL</b>, as opposed to the traditional <b>JP (HL)</b>.</p>
<p><b>IN (C)</b>/<b>OUT (C)</b> instructions are displayed using the traditional form, although they actually use the full 16-bit port address contained in BC.</p>
<p>In the expression of an instruction, everything in <b>bold</b> should be taken ad literam, everything in <i>italics</i> should be evaluated.</p>
<p>This document makes use of an imaginary instruction with the mnemonic <b>NONI</b> (No Operation No Interrupts). Its interpretation is 'perform a no-operation (wait 4 T-states) and do not allow interrupts to occur immediately after this instruction'. The Z80 may actually do more than just a simple NOP, but the effects are irrelevant assuming normal operation of the processor.</p>
<h4>Disassembly tables</h4>
<p>These tables enable us to represent blocks of similar instructions in a compact form, taking advantage of the many obvious patterns in the Z80's instruction matrix.</p>
<table style="width:100%"><tbody><tr>
<td style="width:20%"></td>
<td>
<table class="DissTable8">
<tbody><tr><th class="TableName" colspan="9">Table "r"</th></tr>
<tr><th class="TableDesc" colspan="9">8-bit registers</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td class="Left">Value</td><td>B</td><td>C</td><td>D</td><td>E</td><td>H</td><td>L</td><td>(HL)</td><td>A</td></tr>
</tbody></table>
<table style="width:100%"><tbody><tr>
<td style="width:47%">
<table class="DissTable4">
<tbody><tr><th class="TableName" colspan="9">Table "rp"</th></tr>
<tr><th class="TableDesc" colspan="9">Register pairs featuring SP</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td></tr>
<tr><td class="Left">Value</td><td>BC</td><td>DE</td><td>HL</td><td>SP</td></tr>
</tbody></table>
</td>
<td style="width:6%"></td>
<td style="width:47%">
<table class="DissTable4">
<tbody><tr><th class="TableName" colspan="9">Table "rp2"</th></tr>
<tr><th class="TableDesc" colspan="9">Register pairs featuring AF</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td></tr>
<tr><td class="Left">Value</td><td>BC</td><td>DE</td><td>HL</td><td>AF</td></tr>
</tbody></table>
</td>
</tr></tbody></table>
<table class="DissTable8">
<tbody><tr><th class="TableName" colspan="9">Table "cc"</th></tr>
<tr><th class="TableDesc" colspan="9">Conditions</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td class="Left">Value</td><td>NZ</td><td>Z</td><td>NC</td><td>C</td><td>PO</td><td>PE</td><td>P</td><td>M</td></tr>
</tbody></table>
<table class="DissTable8">
<tbody><tr><th class="TableName" colspan="9">Table "alu"</th></tr>
<tr><th class="TableDesc" colspan="9">Arithmetic/logic operations</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td class="Left">Value</td><td>ADD A,</td><td>ADC A,</td><td>SUB</td><td>SBC A,</td><td>AND</td><td>XOR</td><td>OR</td><td>CP</td></tr>
</tbody></table>
<table class="DissTable8">
<tbody><tr><th class="TableName" colspan="9">Table "rot"</th></tr>
<tr><th class="TableDesc" colspan="9">Rotation/shift operations</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td class="Left">Value</td><td>RLC</td><td>RRC</td><td>RL</td><td>RR</td><td>SLA</td><td>SRA</td><td>SLL</td><td>SRL</td></tr>
</tbody></table>
<table class="DissTable8">
<tbody><tr><th class="TableName" colspan="9">Table "im"</th></tr>
<tr><th class="TableDesc" colspan="9">Interrupt modes</th></tr>
<tr><td class="Left">Index</td><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr>
<tr><td class="Left">Value</td><td>0</td><td>0/1</td><td>1</td><td>2</td><td>0</td><td>0/1</td><td>1</td><td>2</td></tr>
</tbody></table>
<table style="width:100%"><tbody><tr>
<td style="width:17%"></td>
<td style="width:66%">
<table class="DissTable4x4">
<tbody><tr><th class="TableName" colspan="9">Table "bli"</th></tr>
<tr><th class="TableDesc" colspan="9">Block instructions</th></tr>
<tr><td class="Fixed">Index[a,b]</td><td class="Fixed">b=0</td><td class="Fixed">b=1</td><td class="Fixed">b=2</td><td class="Fixed">b=3</td></tr>
<tr><td class="Fixed">a=4</td><td>LDI</td><td>CPI</td><td>INI</td><td>OUTI</td></tr>
<tr><td class="Fixed">a=5</td><td>LDD</td><td>CPD</td><td>IND</td><td>OUTD</td></tr>
<tr><td class="Fixed">a=6</td><td>LDIR</td><td>CPIR</td><td>INIR</td><td>OTIR</td></tr>
<tr><td class="Fixed">a=7</td><td>LDDR</td><td>CPDR</td><td>INDR</td><td>OTDR</td></tr>
</tbody></table>
</td>
<td style="width:17%"></td>
</tr></tbody></table>
</td>
<td style="width:20%"></td>
</tr></tbody></table>
<hr>
<a name="upfx"></a>
<h2>2. UNPREFIXED OPCODES</h2>
<table class="InsTableZ">
<tbody><tr><td class="XHeader" colspan="3">FOR x=0</td></tr>
<tr>
<td class="Z">z=0</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y=0</td><td>NOP</td><td class="Y">y=2</td><td>DJNZ <span class="arg">d</span></td></tr>
<tr><td class="Q"></td><td class="Y">y=1</td><td>EX AF, AF'</td><td class="Y">y=3</td><td>JR <span class="arg">d</span></td></tr>
<tr><td class="Q"></td><td class="Y"></td><td></td><td class="Y">y=4..7</td><td>JR <span class="arg">cc[y-4]</span>, <span class="arg">d</span></td></tr>
</tbody></table></td>
<td class="Comment">Relative jumps and assorted ops</td>
</tr>
<tr>
<td class="Z">z=1</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="P"></td><td class="Long">LD <span class="arg">rp[p]</span>, <span class="arg">nn</span></td></tr>
<tr><td class="Q">q=1</td><td class="P"></td><td class="Long">ADD HL, <span class="arg">rp[p]</span></td></tr>
</tbody></table></td>
<td class="Comment">16-bit load immediate/add</td>
</tr>
<tr>
<td class="Z">z=2</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="P">p=0</td><td>LD (BC), A</td><td class="P">p=2</td><td>LD (<span class="arg">nn</span>), HL</td></tr>
<tr><td class="Q"></td><td class="P">p=1</td><td>LD (DE), A</td><td class="P">p=3</td><td>LD (<span class="arg">nn</span>), A</td></tr>
<tr><td class="Q">q=1</td><td class="P">p=0</td><td>LD A, (BC)</td><td class="P">p=2</td><td>LD HL, (<span class="arg">nn</span>)</td></tr>
<tr><td class="Q"></td><td class="P">p=1</td><td>LD A, (DE)</td><td class="P">p=3</td><td>LD A, (<span class="arg">nn</span>)</td></tr>
</tbody></table></td>
<td class="Comment">Indirect loading</td>
</tr>
<tr>
<td class="Z">z=3</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="P"></td><td class="Long">INC <span class="arg">rp[p]</span></td></tr>
<tr><td class="Q">q=1</td><td class="P"></td><td class="Long">DEC <span class="arg">rp[p]</span></td></tr>
</tbody></table></td>
<td class="Comment">16-bit INC/DEC</td>
</tr>
<tr>
<td class="Z">z=4</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">INC <span class="arg">r[y]</span></td></tr>
</tbody></table></td>
<td class="Comment">8-bit INC</td>
</tr>
<tr>
<td class="Z">z=5</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">DEC <span class="arg">r[y]</span></td></tr>
</tbody></table></td>
<td class="Comment">8-bit DEC</td>
</tr>
<tr>
<td class="Z">z=6</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">LD <span class="arg">r[y]</span>, <span class="arg">n</span></td></tr>
</tbody></table></td>
<td class="Comment">8-bit load immediate</td>
</tr>
<tr>
<td class="Z">z=7</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y=0</td><td>RLCA</td><td class="Y">y=4</td><td>DAA</td></tr>
<tr><td class="Q"></td><td class="Y">y=1</td><td>RRCA</td><td class="Y">y=5</td><td>CPL</td></tr>
<tr><td class="Q"></td><td class="Y">y=2</td><td>RLA</td><td class="Y">y=6</td><td>SCF</td></tr>
<tr><td class="Q"></td><td class="Y">y=3</td><td>RRA</td><td class="Y">y=7</td><td>CCF</td></tr>
</tbody></table></td>
<td class="Comment">Assorted operations on accumulator/flags</td>
</tr>
<tr><td class="XHeader" colspan="3">FOR x=1</td></tr>
<tr>
<td class="Z"></td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">LD <span class="arg">r[y]</span>, <span class="arg">r[z]</span></td></tr>
</tbody></table></td>
<td class="Comment">8-bit loading</td>
</tr>
<tr>
<td class="Z">z=6</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y=6</td><td class="Long">HALT</td></tr>
</tbody></table></td>
<td class="Comment"><b>Exception</b> (replaces <b>LD (HL), (HL)</b>)</td>
</tr>
<tr><td class="XHeader" colspan="3">FOR x=2</td></tr>
<tr>
<td class="Z"></td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long"><span class="arg">alu[y]</span> <span class="arg">r[z]</span></td></tr>
</tbody></table></td>
<td class="Comment">Operate on accumulator and register/memory location</td>
</tr>
<tr><td class="XHeader" colspan="3">FOR x=3</td></tr>
<tr>
<td class="Z">z=0</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">RET <span class="arg">cc[y]</span></td></tr>
</tbody></table></td>
<td class="Comment">Conditional return</td>
</tr>
<tr>
<td class="Z">z=1</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="P"></td><td class="Long" colspan="3">POP <span class="arg">rp2[p]</span></td></tr>
<tr><td class="Q">q=1</td><td class="P">p=0</td><td>RET</td><td class="P">p=2</td><td>JP HL</td></tr>
<tr><td class="Q"></td><td class="P">p=1</td><td>EXX</td><td class="P">p=3</td><td>LD SP, HL</td></tr>
</tbody></table></td>
<td class="Comment">POP &amp; various ops</td>
</tr>
<tr>
<td class="Z">z=2</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">JP <span class="arg">cc[y]</span>, <span class="arg">nn</span></td></tr>
</tbody></table></td>
<td class="Comment">Conditional jump</td>
</tr>
<tr>
<td class="Z">z=3</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y=0</td><td>JP <span class="arg">nn</span></td><td class="Y">y=4</td><td>EX (SP), HL</td></tr>
<tr><td class="Q"></td><td class="Y">y=1</td><td><span class="arg">(CB prefix)</span></td><td class="Y">y=5</td><td>EX DE, HL</td></tr>
<tr><td class="Q"></td><td class="Y">y=2</td><td>OUT (<span class="arg">n</span>), A</td><td class="Y">y=6</td><td>DI</td></tr>
<tr><td class="Q"></td><td class="Y">y=3</td><td>IN A, (<span class="arg">n</span>)</td><td class="Y">y=7</td><td>EI</td></tr>
</tbody></table></td>
<td class="Comment">Assorted operations</td>
</tr>
<tr>
<td class="Z">z=4</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">CALL <span class="arg">cc[y]</span>, <span class="arg">nn</span></td></tr>
</tbody></table></td>
<td class="Comment">Conditional call</td>
</tr>
<tr>
<td class="Z">z=5</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="P"></td><td class="Long" colspan="3">PUSH <span class="arg">rp2[p]</span></td></tr>
<tr><td class="Q">q=1</td><td class="P">p=0</td><td>CALL <span class="arg">nn</span></td><td class="P">p=2</td><td><span class="arg">(ED prefix)</span></td></tr>
<tr><td class="Q"></td><td class="P">p=1</td><td><span class="arg">(DD prefix)</span></td><td class="P">p=3</td><td><span class="arg">(FD prefix)</span></td></tr>
</tbody></table></td>
<td class="Comment">PUSH &amp; various ops</td>
</tr>
<tr>
<td class="Z">z=6</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long"><span class="arg">alu[y]</span> <span class="arg">n</span></td></tr>
</tbody></table></td>
<td class="Comment">Operate on accumulator and immediate operand</td>
</tr>
<tr>
<td class="Z">z=7</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">RST <span class="arg">y*8</span></td></tr>
</tbody></table></td>
<td class="Comment">Restart</td>
</tr>
<tr><td class="XHeader" colspan="3">&nbsp;</td></tr>
</tbody></table>
<hr>
<a name="cb"></a>
<h2>3. CB-PREFIXED OPCODES</h2>
<table class="InsTableZ">
<tbody><tr><td class="XHeader" colspan="3">&nbsp;</td></tr>
<tr>
<td class="X">x=0</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long"><span class="arg">rot[y]</span> <span class="arg">r[z]</span></td></tr>
</tbody></table></td>
<td class="Comment">Roll/shift register or memory location</td>
</tr>
<tr>
<td class="X">x=1</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">BIT <span class="arg">y</span>, <span class="arg">r[z]</span></td></tr>
</tbody></table></td>
<td class="Comment">Test bit</td>
</tr>
<tr>
<td class="X">x=2</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">RES <span class="arg">y</span>, <span class="arg">r[z]</span></td></tr>
</tbody></table></td>
<td class="Comment">Reset bit</td>
</tr>
<tr>
<td class="X">x=3</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">SET <span class="arg">y</span>, <span class="arg">r[z]</span></td></tr>
</tbody></table></td>
<td class="Comment">Set bit</td>
</tr>
<tr><td class="XHeader" colspan="3">&nbsp;</td></tr>
</tbody></table>
<hr>
<a name="ed"></a>
<h2>4. ED-PREFIXED OPCODES</h2>
<table class="InsTableZ">
<tbody><tr><td class="XHeader" colspan="3">FOR x=0 OR x=3</td></tr>
<tr>
<td class="Z" <="" td="">
</td><td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long"></td></tr>
</tbody></table></td>
<td class="Comment">Invalid instruction, equivalent to <b>NONI</b> followed by <b>NOP</b></td>
</tr>
<tr><td class="XHeader" colspan="3">FOR x=1</td></tr>
<tr>
<td class="Z">z=0</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y&#8800;6</td><td class="Long">IN <span class="arg">r[y]</span>, (C)</td></tr>
<tr><td class="Q"></td><td class="Y">y=6</td><td class="Long">IN (C)</td></tr>
</tbody></table></td>
<td class="Comment">Input from port with 16-bit address</td>
</tr>
<tr>
<td class="Z">z=1</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y&#8800;6</td><td class="Long">OUT (C), <span class="arg">r[y]</span></td></tr>
<tr><td class="Q"></td><td class="Y">y=6</td><td class="Long">OUT (C), 0</td></tr>
</tbody></table></td>
<td class="Comment">Output to port with 16-bit address</td>
</tr>
<tr>
<td class="Z">z=2</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="Y"></td><td class="Long">SBC HL, <span class="arg">rp[p]</span></td></tr>
<tr><td class="Q">q=1</td><td class="Y"></td><td class="Long">ADC HL, <span class="arg">rp[p]</span></td></tr>
</tbody></table></td>
<td class="Comment">16-bit add/subtract with carry</td>
</tr>
<tr>
<td class="Z">z=3</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q">q=0</td><td class="Y"></td><td class="Long">LD (<span class="arg">nn</span>), <span class="arg">rp[p]</span></td></tr>
<tr><td class="Q">q=1</td><td class="Y"></td><td class="Long">LD <span class="arg">rp[p]</span>, (<span class="arg">nn</span>)</td></tr>
</tbody></table></td>
<td class="Comment">Retrieve/store register pair from/to immediate address</td>
</tr>
<tr>
<td class="Z">z=4</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">NEG</td></tr>
</tbody></table></td>
<td class="Comment">Negate accumulator</td>
</tr>
<tr>
<td class="Z">z=5</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y&#8800;1</td><td class="Long">RETN</td></tr>
<tr><td class="Q"></td><td class="Y">y=1</td><td class="Long">RETI</td></tr>
</tbody></table></td>
<td class="Comment">Return from interrupt</td>
</tr>
<tr>
<td class="Z">z=6</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long">IM <span class="arg">im[y]</span></td></tr>
</tbody></table></td>
<td class="Comment">Set interrupt mode</td>
</tr>
<tr>
<td class="Z">z=7</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y=0</td><td>LD I, A</td><td class="Y">y=4</td><td>RRD</td></tr>
<tr><td class="Q"></td><td class="Y">y=1</td><td>LD R, A</td><td class="Y">y=5</td><td>RLD</td></tr>
<tr><td class="Q"></td><td class="Y">y=2</td><td>LD A, I</td><td class="Y">y=6</td><td>NOP</td></tr>
<tr><td class="Q"></td><td class="Y">y=3</td><td>LD A, R</td><td class="Y">y=7</td><td>NOP</td></tr>
</tbody></table></td>
<td class="Comment">Assorted ops</td>
</tr>
<tr><td class="XHeader" colspan="3">FOR x=2</td></tr>
<tr>
<td class="Z">z&#8804;3</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">y&#8805;4</td><td class="Long"><span class="arg">bli[y,z]</span></td></tr>
</tbody></table></td>
<td class="Comment">Block instruction</td>
</tr>
<tr>
<td class="Z"></td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td class="Long"></td></tr>
</tbody></table></td>
<td class="Comment">Otherwise, invalid instruction, equivalent to <b>NONI</b> followed by <b>NOP</b></td>
</tr>
<tr><td class="XHeader" colspan="3">&nbsp;</td></tr>
</tbody></table>
<hr>
<a name="dd"></a>
<h2>5. DD-PREFIXED OPCODES</h2>
<p>If the next byte is a <b>DD</b>, <b>ED</b> or <b>FD</b> prefix, the current <b>DD</b> prefix is ignored (it's equivalent to a <b>NONI</b>) and processing continues with the next byte.</p>
<p>If the next byte is a <b>CB</b> prefix, the instruction will be decoded as stated in section 7, <a href="http://www.z80.info/decoding.htm#ddcb">DDCB-prefixed opcodes</a>.</p>
<p>Otherwise:</p>
<p>If the next opcode makes use of <b>HL</b>, <b>H</b>, <b>L</b>, <i>but not <b>(HL)</b></i>, any occurrence of these will be replaced by <b>IX</b>, <b>IXH</b>, <b>IXL</b> respectively. An exception of this is <b>EX DE, HL</b> which is unaffected.</p>
<p>If the next opcode makes use of <b>(HL)</b>, it will be replaced by <b>(IX+<span class="arg">d</span>)</b>, where <i>d</i> is a signed 8-bit displacement immediately following the opcode (any immediate data, i.e. <i>n</i>, will follow the displacement byte), and any other instances of <b>H</b> and <b>L</b> will be unaffected. Therefore, an instruction like <b>LD IXH, (IX+<span class="arg">d</span>)</b> does not exist, but <b>LD H, (IX+<span class="arg">d</span>)</b> does.</p>
<p>All other instructions are unaffected.</p>
<hr>
<a name="fd"></a>
<h2>6. FD-PREFIXED OPCODES</h2>
<p>The <b>FD</b> prefix acts exactly like the <b>DD</b> prefix, but the <b>IY</b> register is used instead of <b>IX</b>.</p>
<p>Note that there is no way to "mix" prefixes so that we access both <b>IX</b> and <b>IY</b> within the same operation: an instruction like <b>LD IXH, IYH</b> does not exist. As stated previously, if two <b>DD</b>/<b>FD</b> prefixes appear in succession, e.g. <b>FD DD</b> <i>opcode</i>, only the last one will be taken into consideration.</p>
<hr>
<a name="ddcb"></a>
<h2>7. DDCB/FDCB-PREFIXED OPCODES</h2>
<p>These instructions have the following format:</p>
<p><b>DD</b> <i>or</i> <b>FD</b> <i>prefix</i>,&nbsp;&nbsp;<b>CB</b>,&nbsp;&nbsp;<i>displacement byte</i>,&nbsp;&nbsp;<i>opcode</i></p>
<p><b>CB</b> and <i>opcode</i> will form instructions similar to those in the <a href="http://www.z80.info/decoding.htm#cb">CB-prefixed opcodes</a> section above. However, these will now operate on <b>(IX+<span class="arg">d</span>)</b> and, if the instruction isn't <b>BIT</b>, copy the result to the register they would have initially acted upon, unless it was <b>(HL)</b>.</p>
<p>In the case of the <b>DD</b> prefix, the instruction table is thus:</p>
<table class="InsTableZ">
<tbody><tr><td class="XHeader" colspan="3">&nbsp;</td></tr>
<tr>
<td class="X">x=0</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">z&#8800;6</td><td class="Long">LD <span class="arg">r[z]</span>, <span class="arg">rot[y]</span> (IX+<span class="arg">d</span>)</td></tr>
<tr><td class="Q"></td><td class="Y">z=6</td><td class="Long"><span class="arg">rot[y]</span> (IX+<span class="arg">d</span>)</td></tr>
</tbody></table></td>
<td class="Comment">Roll/shift memory location and copy result to register</td>
</tr>
<tr>
<td class="X">x=1</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y"></td><td>BIT <span class="arg">y</span>, <span class="arg">r[z]</span></td><td class="Y"></td><td></td></tr>
</tbody></table></td>
<td class="Comment">Test bit at memory location</td>
</tr>
<tr>
<td class="X">x=2</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">z&#8800;6</td><td class="Long">LD <span class="arg">r[z]</span>, RES <span class="arg">y</span>, (IX+<span class="arg">d</span>)</td></tr>
<tr><td class="Q"></td><td class="Y">z=6</td><td class="Long">RES <span class="arg">y</span>, (IX+<span class="arg">d</span>)</td></tr>
</tbody></table></td>
<td class="Comment">Reset bit and copy result to register</td>
</tr>
<tr>
<td class="X">x=3</td>
<td class="YTable"><table class="InsTableY">
<tbody><tr><td class="Q"></td><td class="Y">z&#8800;6</td><td class="Long">LD <span class="arg">r[z]</span>, SET <span class="arg">y</span>, (IX+<span class="arg">d</span>)</td></tr>
<tr><td class="Q"></td><td class="Y">z=6</td><td class="Long">SET <span class="arg">y</span>, (IX+<span class="arg">d</span>)</td></tr>
</tbody></table></td>
<td class="Comment">Set bit and copy result to register</td>
</tr>
<tr><td class="XHeader" colspan="3">&nbsp;</td></tr>
</tbody></table>
<p>An instruction such as <b>LD </b><i>r</i><b>, RES </b><i>b</i><b>, (IX+</b><i>d</i><b>)</b> should be interpreted as "attempt to reset bit <i>b</i> of the byte at <b>(IX+</b><i>d</i><b>)</b>, and copy the result to register <i>r</i>, <i>even the new byte cannot be written at the said address</i> (e.g. when it points to a ROM location).</p>
<p>Such an instruction is sometimes also represented in this form: <b>RES </b><i>r</i><b>, (IX+</b><i>d</i><b>), </b><i>r</i>.</p>
<hr>
<a name="ack"></a>
<h2>8. ACKNOWLEDGEMENTS</h2>
<p>The 'algorithm' described herein was constructed by studying an "instruction/flags affected/binary form/effect" list in a Romanian book called "Ghidul Programatorului ZX Spectrum" ("The ZX Spectrum Programmer's Guide").</p>
<p>The exact effects and quirks of the CB/DD/ED/FD prefixes, as well as the undocumented ED and CB instructions, were learnt from "The Undocumented Z80 Documented" by Sean Young.</p>
<p>My sincere thanks to all those who have contributed with suggestions or corrections. They are mentioned in the following section.</p>
<hr>
<a name="rev"></a>
<h2>9. REVISION HISTORY</h2>
<dl>
<dt>Revision 1</dt>
<dd>Implemented a better representation for the <b>DDCB</b> instructions (thanks to Ven Reddy) and for certain "invalid" <b>ED</b> instructions, e.g. a more accurate <b>NOP</b>/<b>NONI</b> instead of an 8T <b>NOP</b> (thanks to Dr. Phillip Kendall). Fixed some typos.</dd>
<dt>Revision 2</dt>
<dd>Radically altered the presentation. Added an intro section, some diagrams, more comments and a Revision History section. Fixed some important typos and changed the wording in some places to avoid misunderstandings (thanks to BlueChip for his numerous and helpful suggestions; he also suggested that I add info on the signed number format and byte order).</dd>
</dl>
<hr>
<p style="text-align:center">- EOF -</p>
</body></html>

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
var _gaq=_gaq||[];_gaq.push(['_setAccount','UA-25020274-2']);_gaq.push(['_setDomainName','clrhome.org']);_gaq.push(['_trackPageview']);(function(){var ga=document.createElement('script');ga.type='text/javascript';ga.async=true;ga.src=('https:'==document.location.protocol?'https://ssl':'http://www')+'.google-analytics.com/ga.js';var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(ga,s);})();

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.