iz80/
decoder_z80.rs

1use super::cpu::*;
2use super::opcode::*;
3use super::opcode_alu::*;
4use super::opcode_arith::*;
5use super::opcode_io::*;
6use super::opcode_bits::*;
7use super::opcode_jumps::*;
8use super::opcode_ld::*;
9use super::operators::*;
10use super::registers::*;
11use super::environment::*;
12
13/* See
14    http://www.z80.info/decoding.htm
15    http://clrhome.org/table/
16    http://z80-heaven.wikidot.com/instructions-set
17*/
18
19pub struct DecoderZ80 {
20    no_prefix: [Opcode; 256],
21    prefix_cb: [Opcode; 256],
22    prefix_cb_indexed: [Opcode; 256],
23    prefix_ed: [Opcode; 256],
24    has_displacement: [bool; 256],
25}
26
27impl Decoder for DecoderZ80 {
28    fn decode(&self, env: &mut Environment) -> &Opcode {
29        let mut code = env.advance_pc();
30
31        // Process prefixes even if reapeated
32        while code == 0xdd || code == 0xfd {
33            if code == 0xdd {
34                // DD prefix
35                env.set_index(Reg16::IX);
36                code = env.advance_pc();
37            } else {
38                // FD prefix
39                env.set_index(Reg16::IY);
40                code = env.advance_pc();
41            }
42        }
43        
44        match code {
45            0xcb => {
46                if env.is_alt_index() {
47                    env.load_displacement();
48                    &self.prefix_cb_indexed[env.advance_pc() as usize]
49                } else {
50                    &self.prefix_cb[env.advance_pc() as usize]
51                }
52            },
53            0xed => {
54                env.clear_index(); // With ed, the current prefix is ignored
55                &self.prefix_ed[env.advance_pc() as usize]
56            },
57            _ => {
58                if self.has_displacement[code as usize] && env.is_alt_index() {
59                    env.load_displacement();
60                }
61                &self.no_prefix[code as usize]
62            }
63        }
64    }
65}
66
67impl DecoderZ80 {
68    pub fn new() -> DecoderZ80 {
69        DecoderZ80 {
70            no_prefix: no_prefix_opcodes(),
71            prefix_cb: cb_prefix_opcodes(),
72            prefix_cb_indexed: cb_indexed_prefix_opcodes(),
73            prefix_ed: ed_prefix_opcodes(),
74            has_displacement: displacements(),
75        }
76    }
77}
78
79fn no_prefix_opcodes() -> [Opcode;256] {
80    let mut opcodes_vector = Vec::with_capacity(256);
81    for c in 0..=255 {
82        let p = DecodingHelper::parts(c);
83        let mut opcode = match p.x {
84            0 => match p.z {
85                0 => match p.y { // Relative jumps and assorted ops.
86                    0 => build_nop(), // NOP
87                    1 => build_ex_af(), // EX AF, AF'
88                    2 => build_djnz(), // DJNZ d
89                    3 => build_jr_unconditional(), // JR d
90                    _ /*4..=7*/ => build_jr_eq(CC[p.y-4]),
91                },
92                1 => match p.q {
93                    0 => build_ld_rr_nn(RP[p.p]), // LD rr, nn -- 16-bit load add
94                    _ /*1*/ => build_add_hl_rr(RP[p.p]), // ADD HL, rr -- 16-bit add
95                },
96                2 => match p.q {
97                    0 =>  match p.p {
98                        0 => build_ld_prr_a(Reg16::BC), // LD (BC), A
99                        1 => build_ld_prr_a(Reg16::DE), // LD (DE), A
100                        2 => build_ld_pnn_rr(Reg16::HL, true), // LD (nn), HL
101                        _ /*3*/ => build_ld_pnn_a(), // LD (nn), A
102                    },
103                    _ /*1*/ =>  match p.p {
104                        0 => build_ld_a_prr(Reg16::BC), // LD A, (BC)
105                        1 => build_ld_a_prr(Reg16::DE), // LD A, (DE)
106                        2 => build_ld_rr_pnn(Reg16::HL, true), // LD HL, (nn)
107                        _ /*3*/ => build_ld_a_pnn(), // LD A, (nn)
108                    }
109                },
110                3 => match p.q {
111                    0 =>  build_inc_dec_rr(RP[p.p], true), // INC rr -- 16-bit inc
112                    _ /*1*/ =>  build_inc_dec_rr(RP[p.p], false), // DEC rr -- 16-bit dec                      
113                },
114                4 => build_inc_r(R[p.y]), // INC r -- 8 bit inc
115                5 => build_dec_r(R[p.y]), // DEC r -- 8 bit dec
116                6 => build_ld_r_n(R[p.y]), // LD r, n -- 8 bit load imm
117                _ /*7*/ => match p.y {
118                    0..=3 => build_rot_r(Reg8::A, ROT[p.y], true, false), // rotA
119                    4 => build_daa(), // DAA, decimal adjust A
120                    5 => build_cpl(), // CPL, complement adjust A
121                    6 => build_scf(), // SCF, set carry flag
122                    _ /*7*/ => build_ccf(), // CCF, clear carry flag
123                },
124            },
125            1 => match (p.z, p.y) {
126                (6, 6) => build_halt(), // HALT, exception instead of LD (HL), (HL)
127                _ => build_ld_r_r(R[p.y], R[p.z], false), // LD r[y], r[z] -- 8 bit load imm
128            },
129            2 => build_operator_a_r(R[p.z], ALU[p.y]), // alu A, r
130            _ /*3*/ => match p.z {
131                0 => build_ret_eq(CC[p.y]), // RET cc
132                1 => match p.q {
133                    0 => build_pop_rr(RP2[p.p]), // POP rr
134                    _ /*1*/ => match p.p {
135                        0 => build_ret(), // RET
136                        1 => build_exx(), // EXX
137                        2 => build_jp_hl(), // JP HL
138                        _ /*3*/ => build_ld_sp_hl(), // LD SP, HL
139                    },
140                },
141                2 => build_jp_eq(CC[p.y]), // JP cc, nn
142                3 => match p.y {
143                    0 => build_jp_unconditional(), // JP nn
144                    1 => build_not_an_opcode(), // CB prefix
145                    2 => build_out_n_a(),  // OUT (n), A
146                    3 => build_in_a_n(),   // IN A, (n)
147                    4 => build_ex_psp_hl(), // EX (SP), HL
148                    5 => build_ex_de_hl(),  // EX DE, HL
149                    6 => build_disable_interrupts(), // DI
150                    _ /*7*/ => build_enable_interrupts(),  // EI
151                }
152                4 => build_call_eq(CC[p.y]),
153                5 => match p.q {
154                    0 => build_push_rr(RP2[p.p]), // PUSH rr
155                    _ /*1*/ => match p.p {
156                        0 => build_call(), // Call nn
157                        1 => build_not_an_opcode(), // DD prefix
158                        2 => build_not_an_opcode(), // ED prefix
159                        _ /*3*/ => build_not_an_opcode(), // FD prefix
160                    },
161                },
162                6 => build_operator_a_n(ALU[p.y]), // alu A, n
163                _ /*7*/ => build_rst(p.y as u8 * 8), // RST
164            },
165        };
166        opcode.cycles = NO_PREFIX_CYCLES[c as usize];
167        opcode.cycles_conditional = opcode.cycles;
168        opcodes_vector.push(opcode);
169    }
170
171    let mut opcodes = opcodes_vector.try_into().unwrap_or_else(|_| { panic!("missing opcodes")});
172    load_cycle_information_no_prefix(&mut opcodes);
173    opcodes
174}
175
176fn cb_prefix_opcodes() -> [Opcode;256] {
177    let mut opcodes_vector = Vec::with_capacity(256);
178
179    for c in 0..=255 {
180        let p = DecodingHelper::parts(c);
181        let mut opcode = match p.x {
182            0 => build_rot_r(R[p.z], ROT[p.y], false, false), // Shifts
183            1 => build_bit_r(p.y as u8, R[p.z]), // BIT
184            2 => build_set_res_r(p.y as u8, R[p.z], false), // RES
185            _ /*3*/ => build_set_res_r(p.y as u8, R[p.z], true), // SET
186        };
187        opcode.cycles = PREFIX_CB_CYCLES[c as usize];
188        opcode.cycles_conditional = opcode.cycles;
189        opcodes_vector.push(opcode);
190    }
191
192    opcodes_vector.try_into().unwrap_or_else(|_| { panic!("missing opcodes")})
193}
194
195fn cb_indexed_prefix_opcodes() -> [Opcode;256] {
196    let mut opcodes_vector = Vec::with_capacity(256);
197
198    for c in 0..=255 {
199        let p = DecodingHelper::parts(c);
200        let mut opcode = match p.x {
201            0 => build_rot_r(R[p.z], ROT[p.y], false, true), // Shifts
202            1 => build_bit_r(p.y as u8, R[p.z]), // BIT
203            2 => build_indexed_set_res_r(p.y as u8, R[p.z], false), // RES
204            _ /*3*/ => build_indexed_set_res_r(p.y as u8, R[p.z], true), // SET
205        };
206        // 23 cycles except for BIT that is 20
207        opcode.cycles = if (c & 0xc0) == 0x40 {20} else {23};
208        opcode.cycles_conditional = opcode.cycles;
209        opcodes_vector.push(opcode);
210    }
211
212    opcodes_vector.try_into().unwrap_or_else(|_| { panic!("missing opcodes")})
213}
214
215
216fn ed_prefix_opcodes() -> [Opcode;256] {
217    let mut opcodes_vector = Vec::with_capacity(256);
218
219    for c in 0..=255 {
220        let p = DecodingHelper::parts(c);
221        let mut opcode = match p.x {
222            0 | 3 => build_noni_nop(), // Invalid instruction NONI + NOP
223            1 => match p.z {
224                0 => match p.y {
225                    6 => build_in_0_c(), // IN (C)
226                    _ => build_in_r_c(R[p.y]), // IN r, (C)
227                }
228                1 => match p.y {
229                    6 => build_out_c_0(), // OUT (C), 0
230                    _ => build_out_c_r(R[p.y]), // OUT (C), r
231                }
232                2 => match p.q {
233                    0 => build_sbc_hl_rr(RP[p.p]), // SBC HL, rr
234                    _ /*1*/ => build_adc_hl_rr(RP[p.p]), // ADC HL, rr
235                },
236                3 => match p.q {
237                    0 => build_ld_pnn_rr(RP[p.p], false), // LD (nn), rr -- 16 bit loading
238                    _ /*1*/ => build_ld_rr_pnn(RP[p.p], false), // LD rr, (nn) -- 16 bit loading
239                },
240                4 => build_neg(), // NEG
241                5 => match p.y {
242                    1 => build_reti(), // RETI
243                    _ => build_retn()  // RETN
244                }
245                6 => build_im(IM[p.y]), // IM #
246                _ /*7*/ => match p.y {
247                    0 => build_ld_r_r(Reg8::I, Reg8::A, true), // LD I, A
248                    1 => build_ld_r_r(Reg8::R, Reg8::A, true), // LD R, A
249                    2 => build_ld_r_r(Reg8::A, Reg8::I, true), // LD A, I
250                    3 => build_ld_r_r(Reg8::A, Reg8::R, true), // LD A, R
251                    4 => build_rxd(ShiftDir::Right, "RRD"), // RRD
252                    5 => build_rxd(ShiftDir::Left, "RLD"),  // RLD
253                    6 => build_nop(), // NOP
254                    _ /*7*/ => build_nop(), // NOP
255                },
256            },
257            _ /*2*/ => if p.z <= 3 && p.y >= 4 {
258                // Table "bli"
259                match p.z {
260                    0 => build_ld_block( BLI_A[p.y-4]), // Block LDxx
261                    1 => build_cp_block( BLI_A[p.y-4]), // Block CPxx
262                    2 => build_in_block( BLI_A[p.y-4]), // Block INxx
263                    _ /*3*/ => build_out_block(BLI_A[p.y-4]), // Block OUTxx
264                 }
265            } else {
266                 build_noni_nop() // NONI + NOP
267            },
268        };
269        opcode.cycles = PREFIX_ED_CYCLES[c as usize];
270        opcode.cycles_conditional = opcode.cycles;
271        opcodes_vector.push(opcode);
272    }
273
274    let mut opcodes = opcodes_vector.try_into().unwrap_or_else(|_| { panic!("missing opcodes")});
275    load_cycle_information_prefix_ed(&mut opcodes);
276    opcodes
277}
278
279fn displacements() -> [bool; 256] {
280    let mut disps = [false; 256];
281    disps[0x34] = true;
282    disps[0x35] = true;
283    disps[0x36] = true;
284    disps[0x46] = true;
285    disps[0x4e] = true;
286    disps[0x56] = true;
287    disps[0x5e] = true;
288    disps[0x66] = true;
289    disps[0x6e] = true;
290    disps[0x70] = true;
291    disps[0x71] = true;
292    disps[0x72] = true;
293    disps[0x73] = true;
294    disps[0x74] = true;
295    disps[0x75] = true;
296    disps[0x77] = true;
297    disps[0x7e] = true;
298    disps[0x86] = true;
299    disps[0x8e] = true;
300    disps[0x96] = true;
301    disps[0x9e] = true;
302    disps[0xa6] = true;
303    disps[0xae] = true;
304    disps[0xb6] = true;
305    disps[0xbe] = true;
306    disps
307}
308
309fn load_cycle_information_no_prefix(opcodes: &mut [Opcode; 256]) {
310    opcodes[0x10].cycles_conditional =  8;
311    opcodes[0x20].cycles_conditional =  8;
312    opcodes[0x28].cycles_conditional =  8;
313    opcodes[0x30].cycles_conditional =  8;
314    opcodes[0x38].cycles_conditional =  8;
315
316    opcodes[0xc0].cycles_conditional =  5;
317    opcodes[0xc2].cycles_conditional =  7;
318    opcodes[0xc4].cycles_conditional = 10;
319    opcodes[0xc8].cycles_conditional =  5;
320    opcodes[0xca].cycles_conditional =  7;
321    opcodes[0xcc].cycles_conditional = 10;
322
323    opcodes[0xd0].cycles_conditional =  5;
324    opcodes[0xd2].cycles_conditional =  7;
325    opcodes[0xd4].cycles_conditional = 10;
326    opcodes[0xd8].cycles_conditional =  5;
327    opcodes[0xda].cycles_conditional =  7;
328    opcodes[0xdc].cycles_conditional = 10;
329
330    opcodes[0xe0].cycles_conditional =  5;
331    opcodes[0xe2].cycles_conditional =  7;
332    opcodes[0xe4].cycles_conditional = 10;
333    opcodes[0xe8].cycles_conditional =  5;
334    opcodes[0xea].cycles_conditional =  7;
335    opcodes[0xec].cycles_conditional = 10;
336
337    opcodes[0xf0].cycles_conditional =  5;
338    opcodes[0xf2].cycles_conditional =  7;
339    opcodes[0xf4].cycles_conditional = 10;
340    opcodes[0xf8].cycles_conditional =  5;
341    opcodes[0xfa].cycles_conditional =  7;
342    opcodes[0xfc].cycles_conditional = 10;
343}
344
345fn load_cycle_information_prefix_ed(opcodes: &mut [Opcode; 256]) {
346    opcodes[0xb0].cycles_conditional = 16;
347    opcodes[0xb1].cycles_conditional = 16;
348    opcodes[0xb2].cycles_conditional = 16;
349    opcodes[0xb3].cycles_conditional = 16;
350    opcodes[0xb8].cycles_conditional = 16;
351    opcodes[0xb9].cycles_conditional = 16;
352    opcodes[0xba].cycles_conditional = 16;
353    opcodes[0xbb].cycles_conditional = 16;
354}
355
356struct DecodingHelper {
357    // See notation in http://www.z80.info/decoding.htm    
358    x: usize,
359    y: usize,
360    z: usize,
361    p: usize,
362    q: usize
363}
364
365impl DecodingHelper {
366    fn parts(code: u8) -> DecodingHelper {
367        DecodingHelper {
368            x: (code >> 6) as usize,
369            y: ((code >> 3) & 7) as usize,
370            z: (code & 7) as usize,
371            p: ((code >> 4) & 3) as usize,
372            q: ((code >> 3) & 1) as usize,
373        }
374    }
375}
376
377
378const RP:  [Reg16; 4] = [Reg16::BC, Reg16::DE, Reg16::HL, Reg16::SP];
379const RP2: [Reg16; 4] = [Reg16::BC, Reg16::DE, Reg16::HL, Reg16::AF];
380const R:  [Reg8; 8] = [Reg8::B, Reg8::C, Reg8::D, Reg8::E, Reg8::H, Reg8::L, Reg8::_HL, Reg8::A];
381const IM: [u8; 8] = [0, 0, 1, 2, 0, 0, 1, 2];
382
383const CC: [(Flag, bool, &str); 8] = [
384    (Flag::Z, false, "NZ"),
385    (Flag::Z, true,  "Z"),
386    (Flag::C, false, "NC"),
387    (Flag::C, true,  "C"),
388    (Flag::P, false, "PO"),
389    (Flag::P, true,  "PE"),
390    (Flag::S, false, "P"),
391    (Flag::S, true,  "N")
392];
393
394const ROT: [(ShiftDir, ShiftMode, &str); 8] = [
395    (ShiftDir::Left,  ShiftMode::RotateCarry, "RLC"),
396    (ShiftDir::Right, ShiftMode::RotateCarry, "RRC"),
397    (ShiftDir::Left,  ShiftMode::Rotate,      "RL" ),
398    (ShiftDir::Right, ShiftMode::Rotate,      "RR" ),
399    (ShiftDir::Left,  ShiftMode::Arithmetic,  "SLA"),
400    (ShiftDir::Right, ShiftMode::Arithmetic,  "SRA"),
401    (ShiftDir::Left,  ShiftMode::Logical,     "SLL"),
402    (ShiftDir::Right, ShiftMode::Logical,     "SRL"),
403];
404
405const ALU: [(Operator, &str); 8] = [
406    (operator_add, "ADD"),
407    (operator_adc, "ADC"),
408    (operator_sub, "SUB"),
409    (operator_sbc, "SBC"),
410    (operator_and, "AND"),
411    (operator_xor, "XOR"),
412    (operator_or,  "OR"),
413    (operator_cp,  "CP")
414];
415
416const BLI_A: [(bool, bool, &str); 4] = [
417    (true,  false, "I"),
418    (false, false, "D"),
419    (true,  true, "IR"),
420    (false, true, "DR")
421];
422
423
424// From https://spectrumforeveryone.com/technical/z80-processor-instructions/
425const NO_PREFIX_CYCLES: [u8; 256] = [
426     4, 10,  7,  6,  4,  4,  7,  4,  4, 11,  7,  6,  4,  4,  7,  4,
427    13, 10,  7,  6,  4,  4,  7,  4, 12, 11,  7,  6,  4,  4,  7,  4,
428    12, 10, 16,  6,  4,  4,  7,  4, 12, 11, 16,  6,  4,  4,  7,  4,
429    12, 10, 13,  6, 11, 11, 10,  4, 12, 11, 13,  6,  4,  4,  7,  4,
430     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
431     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
432     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
433     7,  7,  7,  7,  7,  7,  4,  7,  4,  4,  4,  4,  4,  4,  7,  4,
434     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
435     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
436     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
437     4,  4,  4,  4,  4,  4,  7,  4,  4,  4,  4,  4,  4,  4,  7,  4,
438    11, 10, 12, 10, 17, 11,  7, 11, 11, 10, 12,  0, 17, 17,  7, 11,
439    11, 10, 12, 11, 17, 11,  7, 11, 11,  4, 12, 11, 17 , 0,  7, 11,
440    11, 10, 12, 19, 17, 11,  7, 11, 11,  4, 12,  4, 17,  0,  7, 11,
441    11, 10, 12,  4, 17, 11,  7, 11, 11,  6, 12,  4, 17,  0,  7, 11,
442];
443
444const PREFIX_CB_CYCLES: [u8; 256] = [
445     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
446     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
447     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
448     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
449     8,  8,  8,  8,  8,  8, 12,  8,  8,  8,  8,  8,  8,  8, 12,  8,
450     8,  8,  8,  8,  8,  8, 12,  8,  8,  8,  8,  8,  8,  8, 12,  8,
451     8,  8,  8,  8,  8,  8, 12,  8,  8,  8,  8,  8,  8,  8, 12,  8,
452     8,  8,  8,  8,  8,  8, 12,  8,  8,  8,  8,  8,  8,  8, 12,  8,
453     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
454     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
455     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
456     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
457     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
458     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
459     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
460     8,  8,  8,  8,  8,  8, 15,  8,  8,  8,  8,  8,  8,  8, 15,  8,
461];
462
463const PREFIX_ED_CYCLES: [u8; 256] = [
464     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
465     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
466     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
467     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
468    12, 12, 15, 20,  8, 14,  8,  9, 12, 12, 15, 20,  8, 14,  8,  9,
469    12, 12, 15, 20,  8, 14,  8,  9, 12, 12, 15, 20,  8, 14,  8,  9,
470    12, 12, 15, 20,  8, 14,  8, 18, 12, 12, 15, 20,  8, 14,  8, 18,
471    12, 12, 15, 20,  8, 14,  8,  0, 12, 12, 15, 20,  8, 14,  8,  0,
472     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
473     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
474    16, 16, 16, 16,  0,  0,  0,  0, 16, 16, 16, 16,  0,  0,  0,  0,
475    21, 21, 21, 21,  0,  0,  0,  0, 21, 21, 21, 21,  0,  0,  0,  0,
476     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
477     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
478     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
479     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
480];