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
13pub 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 while code == 0xdd || code == 0xfd {
33 if code == 0xdd {
34 env.set_index(Reg16::IX);
36 code = env.advance_pc();
37 } else {
38 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(); &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 { 0 => build_nop(), 1 => build_ex_af(), 2 => build_djnz(), 3 => build_jr_unconditional(), _ => build_jr_eq(CC[p.y-4]),
91 },
92 1 => match p.q {
93 0 => build_ld_rr_nn(RP[p.p]), _ => build_add_hl_rr(RP[p.p]), },
96 2 => match p.q {
97 0 => match p.p {
98 0 => build_ld_prr_a(Reg16::BC), 1 => build_ld_prr_a(Reg16::DE), 2 => build_ld_pnn_rr(Reg16::HL, true), _ => build_ld_pnn_a(), },
103 _ => match p.p {
104 0 => build_ld_a_prr(Reg16::BC), 1 => build_ld_a_prr(Reg16::DE), 2 => build_ld_rr_pnn(Reg16::HL, true), _ => build_ld_a_pnn(), }
109 },
110 3 => match p.q {
111 0 => build_inc_dec_rr(RP[p.p], true), _ => build_inc_dec_rr(RP[p.p], false), },
114 4 => build_inc_r(R[p.y]), 5 => build_dec_r(R[p.y]), 6 => build_ld_r_n(R[p.y]), _ => match p.y {
118 0..=3 => build_rot_r(Reg8::A, ROT[p.y], true, false), 4 => build_daa(), 5 => build_cpl(), 6 => build_scf(), _ => build_ccf(), },
124 },
125 1 => match (p.z, p.y) {
126 (6, 6) => build_halt(), _ => build_ld_r_r(R[p.y], R[p.z], false), },
129 2 => build_operator_a_r(R[p.z], ALU[p.y]), _ => match p.z {
131 0 => build_ret_eq(CC[p.y]), 1 => match p.q {
133 0 => build_pop_rr(RP2[p.p]), _ => match p.p {
135 0 => build_ret(), 1 => build_exx(), 2 => build_jp_hl(), _ => build_ld_sp_hl(), },
140 },
141 2 => build_jp_eq(CC[p.y]), 3 => match p.y {
143 0 => build_jp_unconditional(), 1 => build_not_an_opcode(), 2 => build_out_n_a(), 3 => build_in_a_n(), 4 => build_ex_psp_hl(), 5 => build_ex_de_hl(), 6 => build_disable_interrupts(), _ => build_enable_interrupts(), }
152 4 => build_call_eq(CC[p.y]),
153 5 => match p.q {
154 0 => build_push_rr(RP2[p.p]), _ => match p.p {
156 0 => build_call(), 1 => build_not_an_opcode(), 2 => build_not_an_opcode(), _ => build_not_an_opcode(), },
161 },
162 6 => build_operator_a_n(ALU[p.y]), _ => build_rst(p.y as u8 * 8), },
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), 1 => build_bit_r(p.y as u8, R[p.z]), 2 => build_set_res_r(p.y as u8, R[p.z], false), _ => build_set_res_r(p.y as u8, R[p.z], true), };
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), 1 => build_bit_r(p.y as u8, R[p.z]), 2 => build_indexed_set_res_r(p.y as u8, R[p.z], false), _ => build_indexed_set_res_r(p.y as u8, R[p.z], true), };
206 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(), 1 => match p.z {
224 0 => match p.y {
225 6 => build_in_0_c(), _ => build_in_r_c(R[p.y]), }
228 1 => match p.y {
229 6 => build_out_c_0(), _ => build_out_c_r(R[p.y]), }
232 2 => match p.q {
233 0 => build_sbc_hl_rr(RP[p.p]), _ => build_adc_hl_rr(RP[p.p]), },
236 3 => match p.q {
237 0 => build_ld_pnn_rr(RP[p.p], false), _ => build_ld_rr_pnn(RP[p.p], false), },
240 4 => build_neg(), 5 => match p.y {
242 1 => build_reti(), _ => build_retn() }
245 6 => build_im(IM[p.y]), _ => match p.y {
247 0 => build_ld_r_r(Reg8::I, Reg8::A, true), 1 => build_ld_r_r(Reg8::R, Reg8::A, true), 2 => build_ld_r_r(Reg8::A, Reg8::I, true), 3 => build_ld_r_r(Reg8::A, Reg8::R, true), 4 => build_rxd(ShiftDir::Right, "RRD"), 5 => build_rxd(ShiftDir::Left, "RLD"), 6 => build_nop(), _ => build_nop(), },
256 },
257 _ => if p.z <= 3 && p.y >= 4 {
258 match p.z {
260 0 => build_ld_block( BLI_A[p.y-4]), 1 => build_cp_block( BLI_A[p.y-4]), 2 => build_in_block( BLI_A[p.y-4]), _ => build_out_block(BLI_A[p.y-4]), }
265 } else {
266 build_noni_nop() },
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 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
424const 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];