jevsnes.git / third-party / rust / jgenesis / cpu / z80-emu / src / core / instructions.rs
1mod arithmetic;
2mod bits;
3mod control;
4mod io;
5mod jump;
6mod load;
7mod mnemonics;
8
9use crate::Z80;
10use crate::core::{IndexRegister, InterruptMode, Register8, Register16};
11use crate::debug::BusDebugExt;
12use crate::traits::{BusInterface, InterruptLine};
13use jgenesis_common::num::GetBit;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum BlockMode {
17    Increment,
18    Decrement,
19}
20
21impl BlockMode {
22    fn apply(self, value: u16) -> u16 {
23        match self {
24            Self::Increment => value.wrapping_add(1),
25            Self::Decrement => value.wrapping_sub(1),
26        }
27    }
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31enum InterruptType {
32    Nmi,
33    Int,
34}
35
36fn parse_register_from_opcode(opcode: u8, index: Option<IndexRegister>) -> Option<Register8> {
37    match opcode & 0x07 {
38        0x00 => Some(Register8::B),
39        0x01 => Some(Register8::C),
40        0x02 => Some(Register8::D),
41        0x03 => Some(Register8::E),
42        0x04 => Some(index.map_or(Register8::H, IndexRegister::high_byte)),
43        0x05 => Some(index.map_or(Register8::L, IndexRegister::low_byte)),
44        0x06 => None,
45        0x07 => Some(Register8::A),
46        _ => unreachable!("value & 0x07 is always <= 0x07"),
47    }
48}
49
50fn parse_dd_register(opcode: u8, index: Option<IndexRegister>) -> Register16 {
51    match opcode & 0x30 {
52        0x00 => Register16::BC,
53        0x10 => Register16::DE,
54        0x20 => index.map_or(Register16::HL, IndexRegister::into),
55        0x30 => Register16::SP,
56        _ => unreachable!("value & 0x30 is always 0x00/0x10/0x20/0x30"),
57    }
58}
59
60fn parse_qq_register(opcode: u8, index: Option<IndexRegister>) -> Register16 {
61    match opcode & 0x30 {
62        0x00 => Register16::BC,
63        0x10 => Register16::DE,
64        0x20 => index.map_or(Register16::HL, IndexRegister::into),
65        0x30 => Register16::AF,
66        _ => unreachable!("value & 0x30 is always 0x00/0x10/0x20/0x30"),
67    }
68}
69
70fn sign_flag(value: u8) -> bool {
71    value.bit(7)
72}
73
74fn zero_flag(value: u8) -> bool {
75    value == 0
76}
77
78fn parity_flag(value: u8) -> bool {
79    value.count_ones().is_multiple_of(2)
80}
81
82#[derive(Debug, Clone, Copy)]
83struct ParseResult {
84    opcode: u8,
85    index_prefix: Option<IndexRegister>,
86    index_fetch_t_cycles: u32,
87}
88
89struct InstructionExecutor<'cpu, 'bus, B> {
90    cpu: &'cpu mut Z80,
91    bus: &'bus mut B,
92}
93
94impl<'cpu, 'bus, B: BusInterface> InstructionExecutor<'cpu, 'bus, B> {
95    fn new(cpu: &'cpu mut Z80, bus: &'bus mut B) -> Self {
96        Self { cpu, bus }
97    }
98
99    fn fetch_operand(&mut self) -> u8 {
100        let operand = self.bus.read_memory(self.cpu.registers.pc);
101        self.cpu.registers.pc = self.cpu.registers.pc.wrapping_add(1);
102        operand
103    }
104
105    fn fetch_operand_u16(&mut self) -> u16 {
106        let lsb = self.fetch_operand();
107        let msb = self.fetch_operand();
108        u16::from_le_bytes([lsb, msb])
109    }
110
111    fn parse_opcode(&mut self) -> ParseResult {
112        let mut index = None;
113        let mut t_cycles = 0;
114        loop {
115            // Increment R on every opcode fetch, including DD/FD prefixes
116            self.cpu.registers.increment_r();
117
118            let opcode = self.fetch_operand();
119            match opcode {
120                0xDD => {
121                    index = Some(IndexRegister::IX);
122                    t_cycles += 4;
123                }
124                0xFD => {
125                    index = Some(IndexRegister::IY);
126                    t_cycles += 4;
127                }
128                _ => {
129                    return ParseResult {
130                        opcode,
131                        index_prefix: index,
132                        index_fetch_t_cycles: t_cycles,
133                    };
134                }
135            }
136        }
137    }
138
139    // Replaces (HL) with (IX+d) or (IY+d) if index register is Some
140    fn fetch_indirect_hl_address(&mut self, index: Option<IndexRegister>) -> u16 {
141        match index {
142            Some(index) => {
143                let index = index.read_from(&self.cpu.registers);
144                let offset = self.fetch_operand() as i8;
145                (i32::from(index) + i32::from(offset)) as u16
146            }
147            None => Register16::HL.read_from(&self.cpu.registers),
148        }
149    }
150
151    fn read_memory_u16(&mut self, address: u16) -> u16 {
152        let lsb = self.bus.read_memory_debug(address, self.cpu);
153        let msb = self.bus.read_memory_debug(address.wrapping_add(1), self.cpu);
154        u16::from_le_bytes([lsb, msb])
155    }
156
157    fn write_memory_u16(&mut self, address: u16, value: u16) {
158        let [lsb, msb] = value.to_le_bytes();
159        self.bus.write_memory_debug(address, lsb, self.cpu);
160        self.bus.write_memory_debug(address.wrapping_add(1), msb, self.cpu);
161    }
162
163    fn push_stack(&mut self, value: u16) {
164        let [lsb, msb] = value.to_le_bytes();
165
166        self.cpu.registers.sp = self.cpu.registers.sp.wrapping_sub(1);
167        self.bus.write_memory_debug(self.cpu.registers.sp, msb, self.cpu);
168        self.cpu.registers.sp = self.cpu.registers.sp.wrapping_sub(1);
169        self.bus.write_memory_debug(self.cpu.registers.sp, lsb, self.cpu);
170    }
171
172    fn pop_stack(&mut self) -> u16 {
173        let lsb = self.bus.read_memory_debug(self.cpu.registers.sp, self.cpu);
174        self.cpu.registers.sp = self.cpu.registers.sp.wrapping_add(1);
175        let msb = self.bus.read_memory_debug(self.cpu.registers.sp, self.cpu);
176        self.cpu.registers.sp = self.cpu.registers.sp.wrapping_add(1);
177
178        u16::from_le_bytes([lsb, msb])
179    }
180
181    fn check_pending_interrupt(&self) -> Option<InterruptType> {
182        if self.cpu.registers.interrupt_delay {
183            None
184        } else if self.bus.nmi() == InterruptLine::Low
185            && self.cpu.registers.last_nmi == InterruptLine::High
186        {
187            Some(InterruptType::Nmi)
188        } else if self.cpu.registers.iff1 && self.bus.int() == InterruptLine::Low {
189            Some(InterruptType::Int)
190        } else {
191            None
192        }
193    }
194
195    fn interrupt_service_routine(&mut self, interrupt_type: InterruptType) -> u32 {
196        log::trace!("Executing interrupt service routine for interrupt type {interrupt_type:?}");
197
198        self.cpu.registers.halted = false;
199
200        match interrupt_type {
201            InterruptType::Nmi => {
202                self.push_stack(self.cpu.registers.pc);
203                self.cpu.registers.pc = 0x0066;
204                self.cpu.registers.iff1 = false;
205
206                11
207            }
208            InterruptType::Int => {
209                self.cpu.registers.iff1 = false;
210                self.cpu.registers.iff2 = false;
211
212                #[allow(unreachable_code)]
213                match self.cpu.registers.interrupt_mode {
214                    // Modes 0 and 1 don't actually work the same way in actual hardware, but for
215                    // the purposes of emulating these consoles they do.
216                    // Mode 1 (used exclusively by the overwhelming majority of games) is defined to
217                    // always execute RST $38.
218                    // Mode 0 reads an opcode from the data bus, but on these consoles, the Z80
219                    // will always read $FF (RST $38) if it handles an interrupt while in mode 0.
220                    // Some games depend on this mode 0 behavior, e.g. Blaster Master 2
221                    InterruptMode::Mode0 | InterruptMode::Mode1 => {
222                        self.push_stack(self.cpu.registers.pc);
223                        self.cpu.registers.pc = 0x0038;
224
225                        13
226                    }
227                    InterruptMode::Mode2 => {
228                        log::error!("Interrupt mode 2 is not implemented; treating as mode 1");
229
230                        self.push_stack(self.cpu.registers.pc);
231                        self.cpu.registers.pc = 0x0038;
232
233                        19
234                    }
235                }
236            }
237        }
238    }
239
240    fn execute_cb_prefix(&mut self, index: Option<IndexRegister>) -> u32 {
241        // CB-prefixed instructions increment R an extra time, but only if there's no DD/FD prefix
242        if index.is_none() {
243            self.cpu.registers.increment_r();
244        }
245
246        // For DD+CB and FD+CB instructions, the index offset comes before the last opcode byte
247        let index_with_offset = match index {
248            Some(index) => {
249                let offset = self.fetch_operand() as i8;
250                Some((index, offset))
251            }
252            None => None,
253        };
254
255        let opcode2 = self.fetch_operand();
256
257        log::trace!("CB prefix opcode: {opcode2:02X}");
258
259        match opcode2 {
260            0x00..=0x05 | 0x07 => self.rlc_r(opcode2, index_with_offset),
261            0x06 => self.rlc_hl(index_with_offset),
262            0x08..=0x0D | 0x0F => self.rrc_r(opcode2, index_with_offset),
263            0x0E => self.rrc_hl(index_with_offset),
264            0x10..=0x15 | 0x17 => self.rl_r(opcode2, index_with_offset),
265            0x16 => self.rl_hl(index_with_offset),
266            0x18..=0x1D | 0x1F => self.rr_r(opcode2, index_with_offset),
267            0x1E => self.rr_hl(index_with_offset),
268            0x20..=0x25 | 0x27 => self.sla_r(opcode2, index_with_offset),
269            0x26 => self.sla_hl(index_with_offset),
270            0x28..=0x2D | 0x2F => self.sra_r(opcode2, index_with_offset),
271            0x2E => self.sra_hl(index_with_offset),
272            0x30..=0x35 | 0x37 => self.sll_r(opcode2, index_with_offset),
273            0x36 => self.sll_hl(index_with_offset),
274            0x38..=0x3D | 0x3F => self.srl_r(opcode2, index_with_offset),
275            0x3E => self.srl_hl(index_with_offset),
276            0x40..=0x7F => {
277                if opcode2 & 0x07 == 0x06 {
278                    self.bit_b_hl(opcode2, index_with_offset)
279                } else {
280                    self.bit_b_r(opcode2)
281                }
282            }
283            0x80..=0xBF => {
284                if opcode2 & 0x07 == 0x06 {
285                    self.res_b_hl(opcode2, index_with_offset)
286                } else {
287                    self.res_b_r(opcode2, index_with_offset)
288                }
289            }
290            0xC0..=0xFF => {
291                if opcode2 & 0x07 == 0x06 {
292                    self.set_b_hl(opcode2, index_with_offset)
293                } else {
294                    self.set_b_r(opcode2, index_with_offset)
295                }
296            }
297        }
298    }
299
300    fn execute_ed_prefix(&mut self) -> u32 {
301        // ED-prefixed instructions increment R an extra time for the second opcode fetch
302        self.cpu.registers.increment_r();
303
304        let opcode2 = self.fetch_operand();
305
306        match opcode2 {
307            0x40 | 0x48 | 0x50 | 0x58 | 0x60 | 0x68 | 0x70 | 0x78 => self.in_r_c(opcode2),
308            0x41 | 0x49 | 0x51 | 0x59 | 0x61 | 0x69 | 0x71 | 0x79 => self.out_c_r(opcode2),
309            0x42 | 0x52 | 0x62 | 0x72 => self.sbc_hl_ss(opcode2),
310            0x43 | 0x53 | 0x63 | 0x73 => self.ld_direct_dd(opcode2),
311            0x44 => self.neg(),
312            0x45 | 0x4D => self.reti_retn(),
313            0x46 => self.im(InterruptMode::Mode0),
314            0x47 => self.ld_ir_a(Register8::I),
315            0x4A | 0x5A | 0x6A | 0x7A => self.adc_hl_ss(opcode2),
316            0x4B | 0x5B | 0x6B | 0x7B => self.ld_dd_direct(opcode2),
317            0x4F => self.ld_ir_a(Register8::R),
318            0x56 => self.im(InterruptMode::Mode1),
319            0x57 => self.ld_a_ir(Register8::I),
320            0x5E => self.im(InterruptMode::Mode2),
321            0x5F => self.ld_a_ir(Register8::R),
322            0x67 => self.rrd(),
323            0x6F => self.rld(),
324            0xA0 => self.block_transfer(BlockMode::Increment, false),
325            0xA1 => self.compare_block(BlockMode::Increment, false),
326            0xA2 => self.in_block(BlockMode::Increment, false),
327            0xA3 => self.out_block(BlockMode::Increment, false),
328            0xA8 => self.block_transfer(BlockMode::Decrement, false),
329            0xA9 => self.compare_block(BlockMode::Decrement, false),
330            0xAA => self.in_block(BlockMode::Decrement, false),
331            0xAB => self.out_block(BlockMode::Decrement, false),
332            0xB0 => self.block_transfer(BlockMode::Increment, true),
333            0xB1 => self.compare_block(BlockMode::Increment, true),
334            0xB2 => self.in_block(BlockMode::Increment, true),
335            0xB3 => self.out_block(BlockMode::Increment, true),
336            0xB8 => self.block_transfer(BlockMode::Decrement, true),
337            0xB9 => self.compare_block(BlockMode::Decrement, true),
338            0xBA => self.in_block(BlockMode::Decrement, true),
339            0xBB => self.out_block(BlockMode::Decrement, true),
340            _ => {
341                // Treat unused opcodes as NOPs
342                control::nop()
343            }
344        }
345    }
346
347    fn execute(mut self) -> u32 {
348        let interrupt_type = self.check_pending_interrupt();
349
350        self.cpu.registers.interrupt_delay = false;
351        self.cpu.registers.last_nmi = self.bus.nmi();
352
353        if let Some(interrupt_type) = interrupt_type {
354            self.cpu.registers.increment_r();
355            return self.interrupt_service_routine(interrupt_type);
356        }
357
358        if self.cpu.registers.halted {
359            return control::nop();
360        }
361
362        self.bus.check_execute(self.cpu.registers.pc, self.cpu);
363
364        let ParseResult { opcode, index_prefix: index, index_fetch_t_cycles } = self.parse_opcode();
365
366        log::trace!(
367            "PC={:04X}, opcode={opcode:02X} ({}), index={index:?}, a={:02X}, next={:02X} {:02X}, sp={:04X}, a={:02X}, f={:02X}, b={:02X}, c={:02X}, d={:02X}, e={:02X}, h={:02X}, l={:02X}, ix={:04X}, iy={:04X}, iff1={}",
368            self.cpu.registers.pc.wrapping_sub(1),
369            mnemonics::for_opcode(opcode, self.bus.read_memory(self.cpu.registers.pc)),
370            self.cpu.registers.a,
371            self.bus.read_memory(self.cpu.registers.pc),
372            self.bus.read_memory(self.cpu.registers.pc.wrapping_add(1)),
373            self.cpu.registers.sp,
374            self.cpu.registers.a,
375            u8::from(self.cpu.registers.f),
376            self.cpu.registers.b,
377            self.cpu.registers.c,
378            self.cpu.registers.d,
379            self.cpu.registers.e,
380            self.cpu.registers.h,
381            self.cpu.registers.l,
382            self.cpu.registers.ix,
383            self.cpu.registers.iy,
384            self.cpu.registers.iff1
385        );
386
387        let instruction_t_cycles = match opcode {
388            0x00 => control::nop(),
389            0x01 | 0x11 | 0x21 | 0x31 => self.ld_dd_immediate(opcode, index),
390            0x02 => self.ld_indirect_a(Register16::BC),
391            0x03 | 0x13 | 0x23 | 0x33 => self.inc_ss(opcode, index),
392            0x04 | 0x0C | 0x14 | 0x1C | 0x24 | 0x2C | 0x3C => self.inc_r(opcode, index),
393            0x34 => self.inc_hl(index),
394            0x05 | 0x0D | 0x15 | 0x1D | 0x25 | 0x2D | 0x3D => self.dec_r(opcode, index),
395            0x35 => self.dec_hl(index),
396            0x06 | 0x0E | 0x16 | 0x1E | 0x26 | 0x2E | 0x3E => self.ld_r_immediate(opcode, index),
397            0x36 => self.ld_hl_immediate(index),
398            0x07 => self.rlca(),
399            0x08 => self.exchange_af(),
400            0x09 | 0x19 | 0x29 | 0x39 => self.add_hl_ss(opcode, index),
401            0x0A => self.ld_a_indirect(Register16::BC),
402            0x0B | 0x1B | 0x2B | 0x3B => self.dec_ss(opcode, index),
403            0x0F => self.rrca(),
404            0x10 => self.djnz_e(),
405            0x12 => self.ld_indirect_a(Register16::DE),
406            0x17 => self.rla(),
407            0x18 => self.jr_e(),
408            0x1A => self.ld_a_indirect(Register16::DE),
409            0x1F => self.rra(),
410            0x20 => self.jr_nz_e(),
411            0x22 => self.ld_direct_hl(index),
412            0x27 => self.daa(),
413            0x28 => self.jr_z_e(),
414            0x2A => self.ld_hl_direct(index),
415            0x2F => self.cpl(),
416            0x30 => self.jr_nc_e(),
417            0x32 => self.ld_direct_a(),
418            0x37 => self.scf(),
419            0x38 => self.jr_c_e(),
420            0x3A => self.ld_a_direct(),
421            0x3F => self.ccf(),
422            0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x47 | 0x48 | 0x49 | 0x4A | 0x4B | 0x4C
423            | 0x4D | 0x4F | 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x57 | 0x58 | 0x59 | 0x5A
424            | 0x5B | 0x5C | 0x5D | 0x5F | 0x60 | 0x61 | 0x62 | 0x63 | 0x64 | 0x65 | 0x67 | 0x68
425            | 0x69 | 0x6A | 0x6B | 0x6C | 0x6D | 0x6F | 0x78 | 0x79 | 0x7A | 0x7B | 0x7C | 0x7D
426            | 0x7F => self.ld_r_r(opcode, index),
427            0x46 | 0x4E | 0x56 | 0x5E | 0x66 | 0x6E | 0x7E => self.ld_r_hl(opcode, index),
428            0x70 | 0x71 | 0x72 | 0x73 | 0x74 | 0x75 | 0x77 => self.ld_hl_r(opcode, index),
429            0x76 => self.halt(),
430            0x80 | 0x81 | 0x82 | 0x83 | 0x84 | 0x85 | 0x87 => self.add_a_r(opcode, index, false),
431            0x86 => self.add_a_hl(index, false),
432            0x88 | 0x89 | 0x8A | 0x8B | 0x8C | 0x8D | 0x8F => self.add_a_r(opcode, index, true),
433            0x8E => self.add_a_hl(index, true),
434            0x90 | 0x91 | 0x92 | 0x93 | 0x94 | 0x95 | 0x97 => self.sub_a_r(opcode, index, false),
435            0x96 => self.sub_a_hl(index, false),
436            0x98 | 0x99 | 0x9A | 0x9B | 0x9C | 0x9D | 0x9F => self.sub_a_r(opcode, index, true),
437            0x9E => self.sub_a_hl(index, true),
438            0xA0 | 0xA1 | 0xA2 | 0xA3 | 0xA4 | 0xA5 | 0xA7 => self.and_a_r(opcode, index),
439            0xA6 => self.and_a_hl(index),
440            0xA8 | 0xA9 | 0xAA | 0xAB | 0xAC | 0xAD | 0xAF => self.xor_a_r(opcode, index),
441            0xAE => self.xor_a_hl(index),
442            0xB0 | 0xB1 | 0xB2 | 0xB3 | 0xB4 | 0xB5 | 0xB7 => self.or_a_r(opcode, index),
443            0xB6 => self.or_a_hl(index),
444            0xB8 | 0xB9 | 0xBA | 0xBB | 0xBC | 0xBD | 0xBF => self.cp_a_r(opcode, index),
445            0xBE => self.cp_a_hl(index),
446            0xC0 | 0xC8 | 0xD0 | 0xD8 | 0xE0 | 0xE8 | 0xF0 | 0xF8 => self.ret_cc(opcode),
447            0xC1 | 0xD1 | 0xE1 | 0xF1 => self.pop_qq(opcode, index),
448            0xC2 | 0xCA | 0xD2 | 0xDA | 0xE2 | 0xEA | 0xF2 | 0xFA => self.jp_cc_nn(opcode),
449            0xC3 => self.jp_nn(),
450            0xC4 | 0xCC | 0xD4 | 0xDC | 0xE4 | 0xEC | 0xF4 | 0xFC => self.call_cc_nn(opcode),
451            0xC5 | 0xD5 | 0xE5 | 0xF5 => self.push_qq(opcode, index),
452            0xC6 => self.add_a_immediate(false),
453            0xC7 | 0xCF | 0xD7 | 0xDF | 0xE7 | 0xEF | 0xF7 | 0xFF => self.rst_p(opcode),
454            0xC9 => self.ret(),
455            0xCB => self.execute_cb_prefix(index),
456            0xCD => self.call_nn(),
457            0xCE => self.add_a_immediate(true),
458            0xD3 => self.out_n_a(),
459            0xD6 => self.sub_a_immediate(false),
460            0xD9 => self.exchange_bcdehl(),
461            0xDB => self.in_a_n(),
462            0xDE => self.sub_a_immediate(true),
463            0xE3 => self.exchange_stack_hl(index),
464            0xE6 => self.and_a_immediate(),
465            0xE9 => self.jp_hl(index),
466            0xEB => self.exchange_de_hl(),
467            0xED => self.execute_ed_prefix(),
468            0xEE => self.xor_a_immediate(),
469            0xF3 => self.di(),
470            0xF6 => self.or_a_immediate(),
471            0xF9 => self.ld_sp_hl(index),
472            0xFB => self.ei(),
473            0xFE => self.cp_a_immediate(),
474            0xDD | 0xFD => unreachable!("DD/FD prefixes have already been removed"),
475        };
476
477        index_fetch_t_cycles + instruction_t_cycles
478    }
479}
480
481pub fn execute<B: BusInterface>(cpu: &mut Z80, bus: &mut B) -> u32 {
482    InstructionExecutor::new(cpu, bus).execute()
483}