jevsnes.git / third-party / rust / jgenesis / cpu / huc6280-emu / src / instructions.rs
1mod disassemble;
2
3use crate::bus::{BusInterface, ClockSpeed};
4use crate::{BlockTransferState, BlockTransferStep, Flags, Huc6280, Registers};
5use jgenesis_common::num::GetBit;
6use std::mem;

HuC6280 "zero" page is at logical $2000-$20FF, not $0000-$00FF like on 6502

9const ZERO_PAGE_BASE: u16 = 0x2000;

And stack is at logical $2100-$21FF

12const STACK_BASE: u16 = 0x2100;
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum InterruptType {
16    Irq1,
17    Irq2,
18    Tiq,
19    Brk,
20    // NMI is not connected in PC Engine
21}
22
23impl InterruptType {
24    fn vector_address(self) -> u16 {
25        match self {
26            Self::Irq2 | Self::Brk => 0xFFF6,
27            Self::Irq1 => 0xFFF8,
28            Self::Tiq => 0xFFFA,
29        }
30    }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34enum ReadRegister {
35    A,
36    X,
37    Y,
38    S,
39    Z, // Zero; for STZ instructions
40}
41
42impl ReadRegister {
43    fn get(self, registers: &Registers) -> u8 {
44        match self {
45            Self::A => registers.a,
46            Self::X => registers.x,
47            Self::Y => registers.y,
48            Self::S => registers.s,
49            Self::Z => 0,
50        }
51    }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55enum RwRegister {
56    A,
57    X,
58    Y,
59    S,
60}
61
62impl RwRegister {
63    fn get(self, registers: &Registers) -> u8 {
64        match self {
65            Self::A => registers.a,
66            Self::X => registers.x,
67            Self::Y => registers.y,
68            Self::S => registers.s,
69        }
70    }
71
72    fn set(self, registers: &mut Registers, value: u8) {
73        match self {
74            Self::A => registers.a = value,
75            Self::X => registers.x = value,
76            Self::Y => registers.y = value,
77            Self::S => registers.s = value,
78        }
79    }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83enum IndexRegister {
84    X,
85    Y,
86}
87
88impl IndexRegister {
89    fn get(self, registers: &Registers) -> u8 {
90        match self {
91            Self::X => registers.x,
92            Self::Y => registers.y,
93        }
94    }
95}
96
97macro_rules! impl_read_fn {
98    ($name:ident, $execute_fn:ident($op:ident)) => {
99        fn $name(&mut self) {
100            self.$execute_fn(Self::$op);
101        }
102    };
103}
104
105macro_rules! impl_store_fn {
106    ($name:ident, $execute_fn:ident($register:ident)) => {
107        fn $name(&mut self) {
108            self.$execute_fn(ReadRegister::$register);
109        }
110    };
111}

Same as impl_read_fn, but I think it's clearer for the RMW instructions to invoke a separate macro

114macro_rules! impl_modify_fn {
115    ($name:ident, $execute_fn:ident($op:ident)) => {
116        impl_read_fn!($name, $execute_fn($op));
117    };
118}
120macro_rules! impl_branch {
121    ($name:ident) => {
122        fn $name(&mut self) {
123            self.conditional_branch(true);
124        }
125    };
126    ($name:ident, $field:ident == $value:literal) => {
127        fn $name(&mut self) {
128            self.conditional_branch(self.cpu.registers.p.$field == $value);
129        }
130    };
131}
132
133macro_rules! impl_set_flag {
134    ($name:ident, $flag:ident = $value:literal) => {
135        fn $name(&mut self) {
136            self.bus_idle();
137            self.cpu.registers.p.$flag = $value;
138        }
139    };
140}
141
142pub struct InstructionExecutor<'cpu, 'bus, Bus> {
143    cpu: &'cpu mut Huc6280,
144    bus: &'bus mut Bus,
145}
146
147impl<'cpu, 'bus, Bus> InstructionExecutor<'cpu, 'bus, Bus>
148where
149    Bus: BusInterface,
150{
151    pub fn new(cpu: &'cpu mut Huc6280, bus: &'bus mut Bus) -> Self {
152        Self { cpu, bus }
153    }
154
155    pub fn execute_instruction(mut self) {
156        if self.cpu.state.block_transfer.is_some() {
157            // Interrupts cannot interrupt in-progress block transfers
158            return self.progress_block_transfer();
159        }
160
161        if self.cpu.state.pending_interrupt {
162            self.cpu.state.pending_interrupt = false;
163
164            // TIQ > IRQ1 > IRQ2 in priority
165
166            // TIQ line doesn't seem to get latched in the same way as the others; CPU does not
167            // handle TIQ if it got cleared during the previous CPU cycle
168            //
169            // Without this, D&D: Order of the Griffon's music plays too fast and it has various
170            // graphical glitches. It expects to _not_ handle a TIQ after doing the following:
171            //   cli
172            //   sta $1403  ; acks TIQ during final cycle
173            if self.cpu.state.latched_interrupt_lines.tiq && self.bus.interrupt_lines().tiq {
174                return self.handle_interrupt(InterruptType::Tiq);
175            }
176
177            if self.cpu.state.latched_interrupt_lines.irq1 {
178                return self.handle_interrupt(InterruptType::Irq1);
179            }
180
181            if self.cpu.state.latched_interrupt_lines.irq2 {
182                return self.handle_interrupt(InterruptType::Irq2);
183            }
184        }
185
186        // T bit gets latched and then cleared at the start of every instruction
187        // Interrupts push the T bit onto the stack intact, but it is always clear when pushed
188        // using a PHP or BRK instruction
189        self.cpu.state.memory_op_at_fetch = self.cpu.registers.p.memory_op;
190        self.cpu.registers.p.memory_op = false;
191
192        let opcode = self.fetch_operand();
193
194        if log::log_enabled!(log::Level::Trace) {
195            self.instruction_trace_log(opcode);
196        }
197
198        match opcode {
199            0x00 => self.handle_interrupt(InterruptType::Brk), // BRK
200            0x01 => self.ora_zero_page_indirect_x(),
201            0x02 => self.sxy(),
202            0x03 => self.st0(),
203            0x04 => self.tsb_zero_page(),
204            0x05 => self.ora_zero_page(),
205            0x06 => self.asl_zero_page(),
206            0x07 | 0x17 | 0x27 | 0x37 | 0x47 | 0x57 | 0x67 | 0x77 => self.rmbi(opcode),
207            0x08 => self.php(),
208            0x09 => self.ora_immediate(),
209            0x0A => self.asl_accumulator(),
210            0x0C => self.tsb_absolute(),
211            0x0D => self.ora_absolute(),
212            0x0E => self.asl_absolute(),
213            0x0F | 0x1F | 0x2F | 0x3F | 0x4F | 0x5F | 0x6F | 0x7F => self.bbri(opcode),
214            0x10 => self.bpl(),
215            0x11 => self.ora_zero_page_indirect_y(),
216            0x12 => self.ora_zero_page_indirect(),
217            0x13 => self.st1(),
218            0x14 => self.trb_zero_page(),
219            0x15 => self.ora_zero_page_x(),
220            0x16 => self.asl_zero_page_x(),
221            0x18 => self.clc(),
222            0x19 => self.ora_absolute_y(),
223            0x1A => self.inc_accumulator(),
224            0x1C => self.trb_absolute(),
225            0x1D => self.ora_absolute_x(),
226            0x1E => self.asl_absolute_x(),
227            0x20 => self.jsr(),
228            0x21 => self.and_zero_page_indirect_x(),
229            0x22 => self.sax(),
230            0x23 => self.st2(),
231            0x24 => self.bit_zero_page(),
232            0x25 => self.and_zero_page(),
233            0x26 => self.rol_zero_page(),
234            0x28 => self.plp(),
235            0x29 => self.and_immediate(),
236            0x2A => self.rol_accumulator(),
237            0x2C => self.bit_absolute(),
238            0x2D => self.and_absolute(),
239            0x2E => self.rol_absolute(),
240            0x30 => self.bmi(),
241            0x31 => self.and_zero_page_indirect_y(),
242            0x32 => self.and_zero_page_indirect(),
243            0x34 => self.bit_zero_page_x(),
244            0x35 => self.and_zero_page_x(),
245            0x36 => self.rol_zero_page_x(),
246            0x38 => self.sec(),
247            0x39 => self.and_absolute_y(),
248            0x3A => self.dec_accumulator(),
249            0x3C => self.bit_absolute_x(),
250            0x3D => self.and_absolute_x(),
251            0x3E => self.rol_absolute_x(),
252            0x40 => self.rti(),
253            0x41 => self.eor_zero_page_indirect_x(),
254            0x42 => self.say(),
255            0x43 => self.tma(),
256            0x44 => self.bsr(),
257            0x45 => self.eor_zero_page(),
258            0x46 => self.lsr_zero_page(),
259            0x48 => self.pha(),
260            0x49 => self.eor_immediate(),
261            0x4A => self.lsr_accumulator(),
262            0x4C => self.jmp_absolute(),
263            0x4D => self.eor_absolute(),
264            0x4E => self.lsr_absolute(),
265            0x50 => self.bvc(),
266            0x51 => self.eor_zero_page_indirect_y(),
267            0x52 => self.eor_zero_page_indirect(),
268            0x53 => self.tam(),
269            0x54 => self.csl(),
270            0x55 => self.eor_zero_page_x(),
271            0x56 => self.lsr_zero_page_x(),
272            0x58 => self.cli(),
273            0x59 => self.eor_absolute_y(),
274            0x5A => self.phy(),
275            0x5D => self.eor_absolute_x(),
276            0x5E => self.lsr_absolute_x(),
277            0x60 => self.rts(),
278            0x61 => self.adc_zero_page_indirect_x(),
279            0x62 => self.cla(),
280            0x64 => self.stz_zero_page(),
281            0x65 => self.adc_zero_page(),
282            0x66 => self.ror_zero_page(),
283            0x68 => self.pla(),
284            0x69 => self.adc_immediate(),
285            0x6A => self.ror_accumulator(),
286            0x6C => self.jmp_absolute_indirect(),
287            0x6D => self.adc_absolute(),
288            0x6E => self.ror_absolute(),
289            0x70 => self.bvs(),
290            0x71 => self.adc_zero_page_indirect_y(),
291            0x72 => self.adc_zero_page_indirect(),
292            0x73 => self.tii(),
293            0x74 => self.stz_zero_page_x(),
294            0x75 => self.adc_zero_page_x(),
295            0x76 => self.ror_zero_page_x(),
296            0x78 => self.sei(),
297            0x79 => self.adc_absolute_y(),
298            0x7A => self.ply(),
299            0x7C => self.jmp_absolute_indirect_x(),
300            0x7D => self.adc_absolute_x(),
301            0x7E => self.ror_absolute_x(),
302            0x80 => self.bra(),
303            0x81 => self.sta_zero_page_indirect_x(),
304            0x82 => self.clx(),
305            0x83 => self.tst_zero_page(),
306            0x84 => self.sty_zero_page(),
307            0x85 => self.sta_zero_page(),
308            0x86 => self.stx_zero_page(),
309            0x87 | 0x97 | 0xA7 | 0xB7 | 0xC7 | 0xD7 | 0xE7 | 0xF7 => self.smbi(opcode),
310            0x88 => self.dey(),
311            0x89 => self.bit_immediate(),
312            0x8A => self.txa(),
313            0x8C => self.sty_absolute(),
314            0x8D => self.sta_absolute(),
315            0x8E => self.stx_absolute(),
316            0x8F | 0x9F | 0xAF | 0xBF | 0xCF | 0xDF | 0xEF | 0xFF => self.bbsi(opcode),
317            0x90 => self.bcc(),
318            0x91 => self.sta_zero_page_indirect_y(),
319            0x92 => self.sta_zero_page_indirect(),
320            0x93 => self.tst_absolute(),
321            0x94 => self.sty_zero_page_x(),
322            0x95 => self.sta_zero_page_x(),
323            0x96 => self.stx_zero_page_y(),
324            0x98 => self.tya(),
325            0x99 => self.sta_absolute_y(),
326            0x9A => self.txs(),
327            0x9C => self.stz_absolute(),
328            0x9D => self.sta_absolute_x(),
329            0x9E => self.stz_absolute_x(),
330            0xA0 => self.ldy_immediate(),
331            0xA1 => self.lda_zero_page_indirect_x(),
332            0xA2 => self.ldx_immediate(),
333            0xA3 => self.tst_zero_page_x(),
334            0xA4 => self.ldy_zero_page(),
335            0xA5 => self.lda_zero_page(),
336            0xA6 => self.ldx_zero_page(),
337            0xA8 => self.tay(),
338            0xA9 => self.lda_immediate(),
339            0xAA => self.tax(),
340            0xAC => self.ldy_absolute(),
341            0xAD => self.lda_absolute(),
342            0xAE => self.ldx_absolute(),
343            0xB0 => self.bcs(),
344            0xB1 => self.lda_zero_page_indirect_y(),
345            0xB2 => self.lda_zero_page_indirect(),
346            0xB3 => self.tst_absolute_x(),
347            0xB4 => self.ldy_zero_page_x(),
348            0xB5 => self.lda_zero_page_x(),
349            0xB6 => self.ldx_zero_page_y(),
350            0xB8 => self.clv(),
351            0xB9 => self.lda_absolute_y(),
352            0xBA => self.tsx(),
353            0xBC => self.ldy_absolute_x(),
354            0xBD => self.lda_absolute_x(),
355            0xBE => self.ldx_absolute_y(),
356            0xC0 => self.cpy_immediate(),
357            0xC1 => self.cmp_zero_page_indirect_x(),
358            0xC2 => self.cly(),
359            0xC3 => self.tdd(),
360            0xC4 => self.cpy_zero_page(),
361            0xC5 => self.cmp_zero_page(),
362            0xC6 => self.dec_zero_page(),
363            0xC8 => self.iny(),
364            0xC9 => self.cmp_immediate(),
365            0xCA => self.dex(),
366            0xCC => self.cpy_absolute(),
367            0xCD => self.cmp_absolute(),
368            0xCE => self.dec_absolute(),
369            0xD0 => self.bne(),
370            0xD1 => self.cmp_zero_page_indirect_y(),
371            0xD2 => self.cmp_zero_page_indirect(),
372            0xD3 => self.tin(),
373            0xD4 => self.csh(),
374            0xD5 => self.cmp_zero_page_x(),
375            0xD6 => self.dec_zero_page_x(),
376            0xD8 => self.cld(),
377            0xD9 => self.cmp_absolute_y(),
378            0xDA => self.phx(),
379            0xDD => self.cmp_absolute_x(),
380            0xDE => self.dec_absolute_x(),
381            0xE0 => self.cpx_immediate(),
382            0xE1 => self.sbc_zero_page_indirect_x(),
383            0xE3 => self.tia(),
384            0xE4 => self.cpx_zero_page(),
385            0xE5 => self.sbc_zero_page(),
386            0xE6 => self.inc_zero_page(),
387            0xE8 => self.inx(),
388            0xE9 => self.sbc_immediate(),
389            0xEA => self.nop(),
390            0xEC => self.cpx_absolute(),
391            0xED => self.sbc_absolute(),
392            0xEE => self.inc_absolute(),
393            0xF0 => self.beq(),
394            0xF1 => self.sbc_zero_page_indirect_y(),
395            0xF2 => self.sbc_zero_page_indirect(),
396            0xF3 => self.tai(),
397            0xF4 => self.set(),
398            0xF5 => self.sbc_zero_page_x(),
399            0xF6 => self.inc_zero_page_x(),
400            0xF8 => self.sed(),
401            0xF9 => self.sbc_absolute_y(),
402            0xFA => self.plx(),
403            0xFD => self.sbc_absolute_x(),
404            0xFE => self.inc_absolute_x(),
405            0x0B | 0x1B | 0x2B | 0x33 | 0x3B | 0x4B | 0x5B | 0x5C | 0x63 | 0x6B | 0x7B | 0x8B
406            | 0x9B | 0xAB | 0xBB | 0xCB | 0xDB | 0xDC | 0xE2 | 0xEB | 0xFB | 0xFC => {
407                // Illegal opcodes; supposedly function as NOP?
408                log::warn!("Executed illegal opcode {opcode:02X}");
409                self.nop();
410            }
411        }
412    }
413
414    fn instruction_trace_log(&self, opcode: u8) {
415        log::trace!(
416            "Executing opcode {opcode:02X} at PC={:04X} ({}); A={:02X} X={:02X} Y={:02X} P={:02X} S={:02X} T={} MPR=[{:02X},{:02X},{:02X},{:02X},{:02X},{:02X},{:02X},{:02X}]",
417            self.cpu.registers.pc.wrapping_sub(1),
418            disassemble::disassemble(opcode),
419            self.cpu.registers.a,
420            self.cpu.registers.x,
421            self.cpu.registers.y,
422            self.cpu.registers.p.to_u8_brk(),
423            self.cpu.registers.s,
424            self.cpu.state.memory_op_at_fetch,
425            self.cpu.registers.mpr[0],
426            self.cpu.registers.mpr[1],
427            self.cpu.registers.mpr[2],
428            self.cpu.registers.mpr[3],
429            self.cpu.registers.mpr[4],
430            self.cpu.registers.mpr[5],
431            self.cpu.registers.mpr[6],
432            self.cpu.registers.mpr[7],
433        );
434    }
435
436    // Interrupt lines and the I flag are latched/polled at the beginning of the final cycle of each instruction
437    // For simplicity, latch them at the beginning of every cycle
438    fn poll_interrupt_lines(&mut self) {
439        let interrupt_lines = self.bus.interrupt_lines();
440        self.cpu.state.pending_interrupt =
441            !self.cpu.registers.p.irq_disable && interrupt_lines.any();
442        self.cpu.state.latched_interrupt_lines = interrupt_lines;
443    }
444
445    fn bus_read(&mut self, address: u32) -> u8 {
446        self.poll_interrupt_lines();
447        self.bus.read(address)
448    }
449
450    fn bus_write(&mut self, address: u32, value: u8) {
451        self.poll_interrupt_lines();
452        self.bus.write(address, value);
453    }
454
455    fn bus_idle(&mut self) {
456        self.poll_interrupt_lines();
457        self.bus.idle();
458    }
459
460    // NOP: No operation
461    fn nop(&mut self) {
462        self.bus_idle();
463    }
464
465    fn handle_interrupt(&mut self, interrupt: InterruptType) {
466        log::trace!("Handling interrupt of type {interrupt:?}");
467
468        // Dummy read; BRK advances PC
469        match interrupt {
470            InterruptType::Brk => {
471                self.fetch_operand();
472            }
473            _ => {
474                self.bus_read(self.map_address(self.cpu.registers.pc));
475            }
476        }
477
478        self.push_stack_u16(self.cpu.registers.pc);
479
480        let status = match interrupt {
481            InterruptType::Brk => self.cpu.registers.p.to_u8_brk(),
482            _ => self.cpu.registers.p.to_u8_interrupt(),
483        };
484        self.push_stack(status);
485
486        self.cpu.registers.p.memory_op = false;
487        self.cpu.registers.p.decimal = false;
488        self.cpu.registers.p.irq_disable = true;
489
490        let vector_addr = interrupt.vector_address();
491        let pc_lsb = self.bus_read(self.map_address(vector_addr));
492        let pc_msb = self.bus_read(self.map_address(vector_addr.wrapping_add(1)));
493        self.cpu.registers.pc = u16::from_le_bytes([pc_lsb, pc_msb]);
494
495        self.bus_idle();
496    }
497
498    fn fetch_operand(&mut self) -> u8 {
499        let operand = self.bus_read(self.map_address(self.cpu.registers.pc));
500        self.cpu.registers.pc = self.cpu.registers.pc.wrapping_add(1);
501
502        log::trace!("Fetched {operand:02X}");
503
504        operand
505    }
506
507    fn fetch_operand_u16(&mut self) -> u16 {
508        let operand_lsb = self.fetch_operand();
509        let operand_msb = self.fetch_operand();
510        u16::from_le_bytes([operand_lsb, operand_msb])
511    }
512
513    fn push_stack(&mut self, value: u8) {
514        let stack_addr = STACK_BASE | u16::from(self.cpu.registers.s);
515        self.bus_write(self.map_address(stack_addr), value);
516        self.cpu.registers.s = self.cpu.registers.s.wrapping_sub(1);
517    }
518
519    fn push_stack_u16(&mut self, value: u16) {
520        let [lsb, msb] = value.to_le_bytes();
521        self.push_stack(msb);
522        self.push_stack(lsb);
523    }
524
525    fn pull_stack(&mut self) -> u8 {
526        self.cpu.registers.s = self.cpu.registers.s.wrapping_add(1);
527        let stack_addr = STACK_BASE | u16::from(self.cpu.registers.s);
528        self.bus_read(self.map_address(stack_addr))
529    }
530
531    fn pull_stack_u16(&mut self) -> u16 {
532        let lsb = self.pull_stack();
533        let msb = self.pull_stack();
534        u16::from_le_bytes([lsb, msb])
535    }
536
537    fn map_address(&self, logical_addr: u16) -> u32 {
538        self.cpu.registers.map_address(logical_addr)
539    }
540
541    fn map_zero_page(&self, zero_page_addr: u8) -> u32 {
542        self.map_address(ZERO_PAGE_BASE | u16::from(zero_page_addr))
543    }
544
545    fn read_immediate(&mut self, op: impl FnOnce(&mut Self, u8)) {
546        let operand = self.fetch_operand();
547        op(self, operand);
548    }
549
550    #[inline(always)]
551    fn read_zero_page_indexed(
552        &mut self,
553        index: Option<IndexRegister>,
554        op: impl FnOnce(&mut Self, u8),
555    ) {
556        let zero_page_addr = self.fetch_operand();
557
558        self.bus_idle();
559
560        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
561        let indexed_addr = zero_page_addr.wrapping_add(offset);
562        let operand = self.bus_read(self.map_zero_page(indexed_addr));
563        op(self, operand);
564    }
565
566    fn read_zero_page(&mut self, op: impl FnOnce(&mut Self, u8)) {
567        self.read_zero_page_indexed(None, op);
568    }
569
570    fn read_zero_page_x(&mut self, op: impl FnOnce(&mut Self, u8)) {
571        self.read_zero_page_indexed(Some(IndexRegister::X), op);
572    }
573
574    fn read_zero_page_y(&mut self, op: impl FnOnce(&mut Self, u8)) {
575        self.read_zero_page_indexed(Some(IndexRegister::Y), op);
576    }
577
578    #[inline(always)]
579    fn read_absolute_indexed(
580        &mut self,
581        index: Option<IndexRegister>,
582        op: impl FnOnce(&mut Self, u8),
583    ) {
584        let address = self.fetch_operand_u16();
585
586        self.bus_idle();
587
588        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
589        let indexed_addr = address.wrapping_add(offset.into());
590        let operand = self.bus_read(self.map_address(indexed_addr));
591        op(self, operand);
592    }
593
594    fn read_absolute(&mut self, op: impl FnOnce(&mut Self, u8)) {
595        self.read_absolute_indexed(None, op);
596    }
597
598    fn read_absolute_x(&mut self, op: impl FnOnce(&mut Self, u8)) {
599        self.read_absolute_indexed(Some(IndexRegister::X), op);
600    }
601
602    fn read_absolute_y(&mut self, op: impl FnOnce(&mut Self, u8)) {
603        self.read_absolute_indexed(Some(IndexRegister::Y), op);
604    }
605
606    #[inline(always)]
607    fn read_indirect_indexed(
608        &mut self,
609        index: Option<IndexRegister>,
610        op: impl FnOnce(&mut Self, u8),
611    ) {
612        let mut zero_page_addr = self.fetch_operand();
613        self.bus_idle();
614
615        if index == Some(IndexRegister::X) {
616            // Zero page indexed indirect
617            zero_page_addr = zero_page_addr.wrapping_add(self.cpu.registers.x);
618        }
619
620        let address_lsb = self.bus_read(self.map_zero_page(zero_page_addr));
621        let address_msb = self.bus_read(self.map_zero_page(zero_page_addr.wrapping_add(1)));
622        let mut address = u16::from_le_bytes([address_lsb, address_msb]);
623        self.bus_idle();
624
625        if index == Some(IndexRegister::Y) {
626            // Zero page indirect indexed
627            address = address.wrapping_add(self.cpu.registers.y.into());
628        }
629
630        let operand = self.bus_read(self.map_address(address));
631        op(self, operand);
632    }
633
634    fn read_zero_page_indirect(&mut self, op: impl FnOnce(&mut Self, u8)) {
635        self.read_indirect_indexed(None, op);
636    }
637
638    fn read_zero_page_indirect_x(&mut self, op: impl FnOnce(&mut Self, u8)) {
639        self.read_indirect_indexed(Some(IndexRegister::X), op);
640    }
641
642    fn read_zero_page_indirect_y(&mut self, op: impl FnOnce(&mut Self, u8)) {
643        self.read_indirect_indexed(Some(IndexRegister::Y), op);
644    }
645
646    #[inline(always)]
647    fn load(&mut self, register: RwRegister, operand: u8) {
648        register.set(&mut self.cpu.registers, operand);
649        self.cpu.registers.p.set_zero_negative(operand);
650    }
651
652    // LDA: Load A
653    fn lda(&mut self, operand: u8) {
654        self.load(RwRegister::A, operand);
655    }
656
657    // LDX: Load X
658    fn ldx(&mut self, operand: u8) {
659        self.load(RwRegister::X, operand);
660    }
661
662    // LDY: Load Y
663    fn ldy(&mut self, operand: u8) {
664        self.load(RwRegister::Y, operand);
665    }
666
667    impl_read_fn!(lda_immediate, read_immediate(lda));
668    impl_read_fn!(lda_zero_page, read_zero_page(lda));
669    impl_read_fn!(lda_zero_page_x, read_zero_page_x(lda));
670    impl_read_fn!(lda_absolute, read_absolute(lda));
671    impl_read_fn!(lda_absolute_x, read_absolute_x(lda));
672    impl_read_fn!(lda_absolute_y, read_absolute_y(lda));
673    impl_read_fn!(lda_zero_page_indirect, read_zero_page_indirect(lda));
674    impl_read_fn!(lda_zero_page_indirect_x, read_zero_page_indirect_x(lda));
675    impl_read_fn!(lda_zero_page_indirect_y, read_zero_page_indirect_y(lda));
676
677    impl_read_fn!(ldx_immediate, read_immediate(ldx));
678    impl_read_fn!(ldx_zero_page, read_zero_page(ldx));
679    impl_read_fn!(ldx_zero_page_y, read_zero_page_y(ldx));
680    impl_read_fn!(ldx_absolute, read_absolute(ldx));
681    impl_read_fn!(ldx_absolute_y, read_absolute_y(ldx));
682
683    impl_read_fn!(ldy_immediate, read_immediate(ldy));
684    impl_read_fn!(ldy_zero_page, read_zero_page(ldy));
685    impl_read_fn!(ldy_zero_page_x, read_zero_page_x(ldy));
686    impl_read_fn!(ldy_absolute, read_absolute(ldy));
687    impl_read_fn!(ldy_absolute_x, read_absolute_x(ldy));
688
689    fn add_binary(accumulator: u8, operand: u8, flags: &mut Flags) -> u8 {
690        let existing_carry: u8 = flags.carry.into();
691
692        let (result, carry1) = accumulator.overflowing_add(operand);
693        let (result, carry2) = result.overflowing_add(existing_carry);
694        let new_carry = carry1 || carry2;
695
696        let bit_6_carry = (accumulator & 0x7F) + (operand & 0x7F) + existing_carry >= 0x80;
697        let overflow = new_carry ^ bit_6_carry;
698
699        flags.set_zero_negative(result);
700        flags.overflow = overflow;
701        flags.carry = new_carry;
702
703        result
704    }
705
706    fn add_decimal(accumulator: u8, operand: u8, flags: &mut Flags) -> u8 {
707        // Formulas from http://www.6502.org/tutorials/decimal_mode.html#A
708        // (65C02 versions)
709        let existing_carry: u8 = flags.carry.into();
710
711        let mut al = (accumulator & 0x0F) + (operand & 0x0F) + existing_carry;
712        if al >= 0x0A {
713            al = 0x10 | ((al + 0x06) & 0x0F);
714        }
715
716        let mut a = u16::from(accumulator & 0xF0) + u16::from(operand & 0xF0) + u16::from(al);
717        if a >= 0xA0 {
718            a += 0x60;
719        }
720
721        let result = a as u8;
722
723        flags.set_zero_negative(result);
724        flags.carry = a >= 0x0100;
725        // HuC6280 does not set V in decimal ADC/SBC
726
727        result
728    }
729
730    fn sub_binary(accumulator: u8, operand: u8, flags: &mut Flags) -> u8 {
731        Self::add_binary(accumulator, !operand, flags)
732    }
733
734    fn sub_decimal(accumulator: u8, operand: u8, flags: &mut Flags) -> u8 {
735        // Formulas from http://www.6502.org/tutorials/decimal_mode.html#A
736        // (65C02 versions)
737
738        let existing_carry: i16 = flags.carry.into();
739
740        let al = i16::from(accumulator & 0x0F) - i16::from(operand & 0x0F) + existing_carry - 1;
741        let mut a = i16::from(accumulator) - i16::from(operand) + existing_carry - 1;
742
743        if a < 0 {
744            a -= 0x60;
745        }
746
747        if al < 0 {
748            a -= 0x06;
749        }
750
751        // Carry flag is set based on binary arithmetic
752        let binary_borrow = u16::from(accumulator) < u16::from(operand) + u16::from(!flags.carry);
753
754        let result = a as u8;
755
756        flags.set_zero_negative(result);
757        flags.carry = !binary_borrow;
758        // HuC6280 does not set V in decimal ADC/SBC
759
760        result
761    }
762
763    // ADC: Add with carry
764    fn adc(&mut self, operand: u8) {
765        let accumulator = if self.cpu.state.memory_op_at_fetch {
766            let value = self.bus_read(self.map_zero_page(self.cpu.registers.x));
767            self.bus_idle();
768            value
769        } else {
770            self.cpu.registers.a
771        };
772
773        let result = if self.cpu.registers.p.decimal {
774            self.bus_idle();
775            Self::add_decimal(accumulator, operand, &mut self.cpu.registers.p)
776        } else {
777            Self::add_binary(accumulator, operand, &mut self.cpu.registers.p)
778        };
779
780        if self.cpu.state.memory_op_at_fetch {
781            self.bus_write(self.map_zero_page(self.cpu.registers.x), result);
782        } else {
783            self.cpu.registers.a = result;
784        }
785    }
786
787    impl_read_fn!(adc_immediate, read_immediate(adc));
788    impl_read_fn!(adc_zero_page, read_zero_page(adc));
789    impl_read_fn!(adc_zero_page_x, read_zero_page_x(adc));
790    impl_read_fn!(adc_absolute, read_absolute(adc));
791    impl_read_fn!(adc_absolute_x, read_absolute_x(adc));
792    impl_read_fn!(adc_absolute_y, read_absolute_y(adc));
793    impl_read_fn!(adc_zero_page_indirect, read_zero_page_indirect(adc));
794    impl_read_fn!(adc_zero_page_indirect_x, read_zero_page_indirect_x(adc));
795    impl_read_fn!(adc_zero_page_indirect_y, read_zero_page_indirect_y(adc));
796
797    // SBC: Subtract with carry
798    fn sbc(&mut self, operand: u8) {
799        self.cpu.registers.a = if self.cpu.registers.p.decimal {
800            self.bus_idle();
801            Self::sub_decimal(self.cpu.registers.a, operand, &mut self.cpu.registers.p)
802        } else {
803            Self::sub_binary(self.cpu.registers.a, operand, &mut self.cpu.registers.p)
804        };
805    }
806
807    impl_read_fn!(sbc_immediate, read_immediate(sbc));
808    impl_read_fn!(sbc_zero_page, read_zero_page(sbc));
809    impl_read_fn!(sbc_zero_page_x, read_zero_page_x(sbc));
810    impl_read_fn!(sbc_absolute, read_absolute(sbc));
811    impl_read_fn!(sbc_absolute_x, read_absolute_x(sbc));
812    impl_read_fn!(sbc_absolute_y, read_absolute_y(sbc));
813    impl_read_fn!(sbc_zero_page_indirect, read_zero_page_indirect(sbc));
814    impl_read_fn!(sbc_zero_page_indirect_x, read_zero_page_indirect_x(sbc));
815    impl_read_fn!(sbc_zero_page_indirect_y, read_zero_page_indirect_y(sbc));
816
817    #[inline(always)]
818    fn logical_op(&mut self, operand: u8, op: impl FnOnce(u8, u8) -> u8) {
819        let accumulator = if self.cpu.state.memory_op_at_fetch {
820            let value = self.bus_read(self.map_zero_page(self.cpu.registers.x));
821            self.bus_idle();
822            value
823        } else {
824            self.cpu.registers.a
825        };
826
827        let result = op(accumulator, operand);
828        self.cpu.registers.p.set_zero_negative(result);
829
830        if self.cpu.state.memory_op_at_fetch {
831            self.bus_write(self.map_zero_page(self.cpu.registers.x), result);
832        } else {
833            self.cpu.registers.a = result;
834        }
835    }
836
837    // AND: Logical and
838    fn and(&mut self, operand: u8) {
839        self.logical_op(operand, |a, b| a & b);
840    }
841
842    // EOR: Exclusive or
843    fn eor(&mut self, operand: u8) {
844        self.logical_op(operand, |a, b| a ^ b);
845    }
846
847    // ORA: Logical or
848    fn ora(&mut self, operand: u8) {
849        self.logical_op(operand, |a, b| a | b);
850    }
851
852    impl_read_fn!(and_immediate, read_immediate(and));
853    impl_read_fn!(and_zero_page, read_zero_page(and));
854    impl_read_fn!(and_zero_page_x, read_zero_page_x(and));
855    impl_read_fn!(and_absolute, read_absolute(and));
856    impl_read_fn!(and_absolute_x, read_absolute_x(and));
857    impl_read_fn!(and_absolute_y, read_absolute_y(and));
858    impl_read_fn!(and_zero_page_indirect, read_zero_page_indirect(and));
859    impl_read_fn!(and_zero_page_indirect_x, read_zero_page_indirect_x(and));
860    impl_read_fn!(and_zero_page_indirect_y, read_zero_page_indirect_y(and));
861
862    impl_read_fn!(eor_immediate, read_immediate(eor));
863    impl_read_fn!(eor_zero_page, read_zero_page(eor));
864    impl_read_fn!(eor_zero_page_x, read_zero_page_x(eor));
865    impl_read_fn!(eor_absolute, read_absolute(eor));
866    impl_read_fn!(eor_absolute_x, read_absolute_x(eor));
867    impl_read_fn!(eor_absolute_y, read_absolute_y(eor));
868    impl_read_fn!(eor_zero_page_indirect, read_zero_page_indirect(eor));
869    impl_read_fn!(eor_zero_page_indirect_x, read_zero_page_indirect_x(eor));
870    impl_read_fn!(eor_zero_page_indirect_y, read_zero_page_indirect_y(eor));
871
872    impl_read_fn!(ora_immediate, read_immediate(ora));
873    impl_read_fn!(ora_zero_page, read_zero_page(ora));
874    impl_read_fn!(ora_zero_page_x, read_zero_page_x(ora));
875    impl_read_fn!(ora_absolute, read_absolute(ora));
876    impl_read_fn!(ora_absolute_x, read_absolute_x(ora));
877    impl_read_fn!(ora_absolute_y, read_absolute_y(ora));
878    impl_read_fn!(ora_zero_page_indirect, read_zero_page_indirect(ora));
879    impl_read_fn!(ora_zero_page_indirect_x, read_zero_page_indirect_x(ora));
880    impl_read_fn!(ora_zero_page_indirect_y, read_zero_page_indirect_y(ora));
881
882    // BIT: Bit test
883    fn bit(&mut self, operand: u8) {
884        let result = self.cpu.registers.a & operand;
885
886        self.cpu.registers.p.zero = result == 0;
887        self.cpu.registers.p.overflow = operand.bit(6);
888        self.cpu.registers.p.negative = operand.bit(7);
889    }
890
891    impl_read_fn!(bit_immediate, read_immediate(bit));
892    impl_read_fn!(bit_zero_page, read_zero_page(bit));
893    impl_read_fn!(bit_zero_page_x, read_zero_page_x(bit));
894    impl_read_fn!(bit_absolute, read_absolute(bit));
895    impl_read_fn!(bit_absolute_x, read_absolute_x(bit));
896
897    #[inline(always)]
898    fn compare(&mut self, register: ReadRegister, operand: u8) {
899        let source = register.get(&self.cpu.registers);
900
901        self.cpu.registers.p.negative = source.wrapping_sub(operand).bit(7);
902        self.cpu.registers.p.zero = source == operand;
903        self.cpu.registers.p.carry = source >= operand;
904    }
905
906    // CMP: Compare A with M
907    fn cmp(&mut self, operand: u8) {
908        self.compare(ReadRegister::A, operand);
909    }
910
911    // CPX: Compare X with M
912    fn cpx(&mut self, operand: u8) {
913        self.compare(ReadRegister::X, operand);
914    }
915
916    // CPY: Compare Y with M
917    fn cpy(&mut self, operand: u8) {
918        self.compare(ReadRegister::Y, operand);
919    }
920
921    impl_read_fn!(cmp_immediate, read_immediate(cmp));
922    impl_read_fn!(cmp_zero_page, read_zero_page(cmp));
923    impl_read_fn!(cmp_zero_page_x, read_zero_page_x(cmp));
924    impl_read_fn!(cmp_absolute, read_absolute(cmp));
925    impl_read_fn!(cmp_absolute_x, read_absolute_x(cmp));
926    impl_read_fn!(cmp_absolute_y, read_absolute_y(cmp));
927    impl_read_fn!(cmp_zero_page_indirect, read_zero_page_indirect(cmp));
928    impl_read_fn!(cmp_zero_page_indirect_x, read_zero_page_indirect_x(cmp));
929    impl_read_fn!(cmp_zero_page_indirect_y, read_zero_page_indirect_y(cmp));
930
931    impl_read_fn!(cpx_immediate, read_immediate(cpx));
932    impl_read_fn!(cpx_zero_page, read_zero_page(cpx));
933    impl_read_fn!(cpx_absolute, read_absolute(cpx));
934
935    impl_read_fn!(cpy_immediate, read_immediate(cpy));
936    impl_read_fn!(cpy_zero_page, read_zero_page(cpy));
937    impl_read_fn!(cpy_absolute, read_absolute(cpy));
938
939    #[inline(always)]
940    fn store_zero_page_indexed(&mut self, index: Option<IndexRegister>, register: ReadRegister) {
941        let zero_page_addr = self.fetch_operand();
942        self.bus_idle();
943
944        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
945        let indexed_addr = zero_page_addr.wrapping_add(offset);
946        let value = register.get(&self.cpu.registers);
947        self.bus_write(self.map_zero_page(indexed_addr), value);
948    }
949
950    #[inline(always)]
951    fn store_zero_page(&mut self, register: ReadRegister) {
952        self.store_zero_page_indexed(None, register);
953    }
954
955    #[inline(always)]
956    fn store_zero_page_x(&mut self, register: ReadRegister) {
957        self.store_zero_page_indexed(Some(IndexRegister::X), register);
958    }
959
960    #[inline(always)]
961    fn store_zero_page_y(&mut self, register: ReadRegister) {
962        self.store_zero_page_indexed(Some(IndexRegister::Y), register);
963    }
964
965    #[inline(always)]
966    fn store_absolute_indexed(&mut self, index: Option<IndexRegister>, register: ReadRegister) {
967        let address = self.fetch_operand_u16();
968        self.bus_idle();
969
970        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
971        let indexed_addr = address.wrapping_add(offset.into());
972        let value = register.get(&self.cpu.registers);
973        self.bus_write(self.map_address(indexed_addr), value);
974    }
975
976    #[inline(always)]
977    fn store_absolute(&mut self, register: ReadRegister) {
978        self.store_absolute_indexed(None, register);
979    }
980
981    #[inline(always)]
982    fn store_absolute_x(&mut self, register: ReadRegister) {
983        self.store_absolute_indexed(Some(IndexRegister::X), register);
984    }
985
986    #[inline(always)]
987    fn store_absolute_y(&mut self, register: ReadRegister) {
988        self.store_absolute_indexed(Some(IndexRegister::Y), register);
989    }
990
991    #[inline(always)]
992    fn store_indirect_indexed(&mut self, index: Option<IndexRegister>, register: ReadRegister) {
993        let mut zero_page_addr = self.fetch_operand();
994        self.bus_idle();
995
996        if index == Some(IndexRegister::X) {
997            // Zero page indexed indirect
998            zero_page_addr = zero_page_addr.wrapping_add(self.cpu.registers.x);
999        }
1000
1001        let address_lsb = self.bus_read(self.map_zero_page(zero_page_addr));
1002        let address_msb = self.bus_read(self.map_zero_page(zero_page_addr.wrapping_add(1)));
1003        let mut address = u16::from_le_bytes([address_lsb, address_msb]);
1004        self.bus_idle();
1005
1006        if index == Some(IndexRegister::Y) {
1007            // Zero page indirect indexed
1008            address = address.wrapping_add(self.cpu.registers.y.into());
1009        }
1010
1011        let value = register.get(&self.cpu.registers);
1012        self.bus_write(self.map_address(address), value);
1013    }
1014
1015    #[inline(always)]
1016    fn store_zero_page_indirect(&mut self, register: ReadRegister) {
1017        self.store_indirect_indexed(None, register);
1018    }
1019
1020    #[inline(always)]
1021    fn store_zero_page_indirect_x(&mut self, register: ReadRegister) {
1022        self.store_indirect_indexed(Some(IndexRegister::X), register);
1023    }
1024
1025    #[inline(always)]
1026    fn store_zero_page_indirect_y(&mut self, register: ReadRegister) {
1027        self.store_indirect_indexed(Some(IndexRegister::Y), register);
1028    }
1029
1030    // STA: Store A
1031    impl_store_fn!(sta_zero_page, store_zero_page(A));
1032    impl_store_fn!(sta_zero_page_x, store_zero_page_x(A));
1033    impl_store_fn!(sta_absolute, store_absolute(A));
1034    impl_store_fn!(sta_absolute_x, store_absolute_x(A));
1035    impl_store_fn!(sta_absolute_y, store_absolute_y(A));
1036    impl_store_fn!(sta_zero_page_indirect, store_zero_page_indirect(A));
1037    impl_store_fn!(sta_zero_page_indirect_x, store_zero_page_indirect_x(A));
1038    impl_store_fn!(sta_zero_page_indirect_y, store_zero_page_indirect_y(A));
1039
1040    // STX: Store X
1041    impl_store_fn!(stx_zero_page, store_zero_page(X));
1042    impl_store_fn!(stx_zero_page_y, store_zero_page_y(X));
1043    impl_store_fn!(stx_absolute, store_absolute(X));
1044
1045    // STY: Store Y
1046    impl_store_fn!(sty_zero_page, store_zero_page(Y));
1047    impl_store_fn!(sty_zero_page_x, store_zero_page_x(Y));
1048    impl_store_fn!(sty_absolute, store_absolute(Y));
1049
1050    // STZ: Store zero
1051    impl_store_fn!(stz_zero_page, store_zero_page(Z));
1052    impl_store_fn!(stz_zero_page_x, store_zero_page_x(Z));
1053    impl_store_fn!(stz_absolute, store_absolute(Z));
1054    impl_store_fn!(stz_absolute_x, store_absolute_x(Z));
1055
1056    fn modify_accumulator(&mut self, op: impl FnOnce(&mut Self, u8) -> u8) {
1057        self.bus_idle();
1058
1059        self.cpu.registers.a = op(self, self.cpu.registers.a);
1060    }
1061
1062    #[inline(always)]
1063    fn modify_zero_page_indexed(
1064        &mut self,
1065        index: Option<IndexRegister>,
1066        op: impl FnOnce(&mut Self, u8) -> u8,
1067    ) {
1068        let zero_page_addr = self.fetch_operand();
1069        self.bus_idle();
1070
1071        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
1072        let mapped_addr = self.map_zero_page(zero_page_addr.wrapping_add(offset));
1073        let operand = self.bus_read(mapped_addr);
1074        self.bus_idle();
1075
1076        let result = op(self, operand);
1077        self.bus_write(mapped_addr, result);
1078    }
1079
1080    fn modify_zero_page(&mut self, op: impl FnOnce(&mut Self, u8) -> u8) {
1081        self.modify_zero_page_indexed(None, op);
1082    }
1083
1084    fn modify_zero_page_x(&mut self, op: impl FnOnce(&mut Self, u8) -> u8) {
1085        self.modify_zero_page_indexed(Some(IndexRegister::X), op);
1086    }
1087
1088    #[inline(always)]
1089    fn modify_absolute_indexed(
1090        &mut self,
1091        index: Option<IndexRegister>,
1092        op: impl FnOnce(&mut Self, u8) -> u8,
1093    ) {
1094        let address = self.fetch_operand_u16();
1095        self.bus_idle();
1096
1097        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
1098        let mapped_addr = self.map_address(address.wrapping_add(offset.into()));
1099        let operand = self.bus_read(mapped_addr);
1100        self.bus_idle();
1101
1102        let result = op(self, operand);
1103        self.bus_write(mapped_addr, result);
1104    }
1105
1106    fn modify_absolute(&mut self, op: impl FnOnce(&mut Self, u8) -> u8) {
1107        self.modify_absolute_indexed(None, op);
1108    }
1109
1110    fn modify_absolute_x(&mut self, op: impl FnOnce(&mut Self, u8) -> u8) {
1111        self.modify_absolute_indexed(Some(IndexRegister::X), op);
1112    }
1113
1114    // ASL: Shift left
1115    fn asl(&mut self, operand: u8) -> u8 {
1116        let result = operand << 1;
1117        self.cpu.registers.p.set_zero_negative(result);
1118        self.cpu.registers.p.carry = operand.bit(7);
1119
1120        result
1121    }
1122
1123    impl_modify_fn!(asl_accumulator, modify_accumulator(asl));
1124    impl_modify_fn!(asl_zero_page, modify_zero_page(asl));
1125    impl_modify_fn!(asl_zero_page_x, modify_zero_page_x(asl));
1126    impl_modify_fn!(asl_absolute, modify_absolute(asl));
1127    impl_modify_fn!(asl_absolute_x, modify_absolute_x(asl));
1128
1129    // LSR: Logical shift right
1130    fn lsr(&mut self, operand: u8) -> u8 {
1131        let result = operand >> 1;
1132        self.cpu.registers.p.zero = result == 0;
1133        self.cpu.registers.p.negative = false;
1134        self.cpu.registers.p.carry = operand.bit(0);
1135
1136        result
1137    }
1138
1139    impl_modify_fn!(lsr_accumulator, modify_accumulator(lsr));
1140    impl_modify_fn!(lsr_zero_page, modify_zero_page(lsr));
1141    impl_modify_fn!(lsr_zero_page_x, modify_zero_page_x(lsr));
1142    impl_modify_fn!(lsr_absolute, modify_absolute(lsr));
1143    impl_modify_fn!(lsr_absolute_x, modify_absolute_x(lsr));
1144
1145    // ROL: Rotate left
1146    fn rol(&mut self, operand: u8) -> u8 {
1147        let result = (operand << 1) | u8::from(self.cpu.registers.p.carry);
1148        self.cpu.registers.p.set_zero_negative(result);
1149        self.cpu.registers.p.carry = operand.bit(7);
1150
1151        result
1152    }
1153
1154    impl_modify_fn!(rol_accumulator, modify_accumulator(rol));
1155    impl_modify_fn!(rol_zero_page, modify_zero_page(rol));
1156    impl_modify_fn!(rol_zero_page_x, modify_zero_page_x(rol));
1157    impl_modify_fn!(rol_absolute, modify_absolute(rol));
1158    impl_modify_fn!(rol_absolute_x, modify_absolute_x(rol));
1159
1160    // ROR: Rotate right
1161    fn ror(&mut self, operand: u8) -> u8 {
1162        let result = (operand >> 1) | (u8::from(self.cpu.registers.p.carry) << 7);
1163        self.cpu.registers.p.set_zero_negative(result);
1164        self.cpu.registers.p.carry = operand.bit(0);
1165
1166        result
1167    }
1168
1169    impl_modify_fn!(ror_accumulator, modify_accumulator(ror));
1170    impl_modify_fn!(ror_zero_page, modify_zero_page(ror));
1171    impl_modify_fn!(ror_zero_page_x, modify_zero_page_x(ror));
1172    impl_modify_fn!(ror_absolute, modify_absolute(ror));
1173    impl_modify_fn!(ror_absolute_x, modify_absolute_x(ror));
1174
1175    // INC: Increment
1176    fn inc(&mut self, operand: u8) -> u8 {
1177        let result = operand.wrapping_add(1);
1178        self.cpu.registers.p.set_zero_negative(result);
1179
1180        result
1181    }
1182
1183    impl_modify_fn!(inc_accumulator, modify_accumulator(inc));
1184    impl_modify_fn!(inc_zero_page, modify_zero_page(inc));
1185    impl_modify_fn!(inc_zero_page_x, modify_zero_page_x(inc));
1186    impl_modify_fn!(inc_absolute, modify_absolute(inc));
1187    impl_modify_fn!(inc_absolute_x, modify_absolute_x(inc));
1188
1189    // DEC: Decrement
1190    fn dec(&mut self, operand: u8) -> u8 {
1191        let result = operand.wrapping_sub(1);
1192        self.cpu.registers.p.set_zero_negative(result);
1193
1194        result
1195    }
1196
1197    impl_modify_fn!(dec_accumulator, modify_accumulator(dec));
1198    impl_modify_fn!(dec_zero_page, modify_zero_page(dec));
1199    impl_modify_fn!(dec_zero_page_x, modify_zero_page_x(dec));
1200    impl_modify_fn!(dec_absolute, modify_absolute(dec));
1201    impl_modify_fn!(dec_absolute_x, modify_absolute_x(dec));
1202
1203    #[inline(always)]
1204    fn inc_dec_register<const INCREMENT: bool>(&mut self, register: RwRegister) {
1205        self.bus_idle();
1206
1207        let operand = register.get(&self.cpu.registers);
1208        let result = if INCREMENT { operand.wrapping_add(1) } else { operand.wrapping_sub(1) };
1209        register.set(&mut self.cpu.registers, result);
1210
1211        self.cpu.registers.p.set_zero_negative(result);
1212    }
1213
1214    // INX: Increment X
1215    fn inx(&mut self) {
1216        self.inc_dec_register::<true>(RwRegister::X);
1217    }
1218
1219    // INY: Increment Y
1220    fn iny(&mut self) {
1221        self.inc_dec_register::<true>(RwRegister::Y);
1222    }
1223
1224    // DEX: Decrement X
1225    fn dex(&mut self) {
1226        self.inc_dec_register::<false>(RwRegister::X);
1227    }
1228
1229    // DEY: Decrement Y
1230    fn dey(&mut self) {
1231        self.inc_dec_register::<false>(RwRegister::Y);
1232    }
1233
1234    #[inline(always)]
1235    fn conditional_branch(&mut self, condition: bool) {
1236        let displacement = self.fetch_operand() as i8;
1237
1238        log::trace!(
1239            "  Displacement {displacement} ({:04X})",
1240            self.cpu.registers.pc.wrapping_add_signed(displacement.into())
1241        );
1242
1243        if !condition {
1244            return;
1245        }
1246
1247        self.bus_idle();
1248        self.bus_idle();
1249
1250        self.cpu.registers.pc = self.cpu.registers.pc.wrapping_add_signed(displacement.into());
1251    }
1252
1253    // BRA: Branch always
1254    impl_branch!(bra);
1255
1256    // BCC: Branch on carry clear
1257    // BCS: Branch on carry set
1258    // BEQ: Branch on equal
1259    // BMI: Branch on minus
1260    // BNE: Branch on not equal
1261    // BPL: Branch on plus
1262    // BVC: Branch on overflow clear
1263    // BVS: Branch on overflow set
1264    impl_branch!(bcc, carry == false);
1265    impl_branch!(bcs, carry == true);
1266    impl_branch!(beq, zero == true);
1267    impl_branch!(bmi, negative == true);
1268    impl_branch!(bne, zero == false);
1269    impl_branch!(bpl, negative == false);
1270    impl_branch!(bvc, overflow == false);
1271    impl_branch!(bvs, overflow == true);
1272
1273    // JMP: Jump to new location
1274    fn jmp_absolute(&mut self) {
1275        self.cpu.registers.pc = self.fetch_operand_u16();
1276
1277        self.bus_idle();
1278    }
1279
1280    #[inline(always)]
1281    fn jmp_indirect_indexed(&mut self, index: Option<IndexRegister>) {
1282        let address = self.fetch_operand_u16();
1283        self.bus_idle();
1284
1285        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
1286        let indexed_addr = address.wrapping_add(offset.into());
1287
1288        let pc_lsb = self.bus_read(self.map_address(indexed_addr));
1289        let pc_msb = self.bus_read(self.map_address(indexed_addr.wrapping_add(1)));
1290        self.cpu.registers.pc = u16::from_le_bytes([pc_lsb, pc_msb]);
1291
1292        self.bus_idle();
1293    }
1294
1295    // JMP: Jump to new location
1296    fn jmp_absolute_indirect(&mut self) {
1297        self.jmp_indirect_indexed(None);
1298    }
1299
1300    // JMP: Jump to new location
1301    fn jmp_absolute_indirect_x(&mut self) {
1302        self.jmp_indirect_indexed(Some(IndexRegister::X));
1303    }
1304
1305    // JSR: Jump to subroutine
1306    fn jsr(&mut self) {
1307        let pc_lsb = self.fetch_operand();
1308        self.bus_idle();
1309
1310        self.push_stack_u16(self.cpu.registers.pc);
1311
1312        let pc_msb = self.fetch_operand();
1313        self.cpu.registers.pc = u16::from_le_bytes([pc_lsb, pc_msb]);
1314
1315        self.bus_idle();
1316    }
1317
1318    // BSR: Branch to subroutine
1319    fn bsr(&mut self) {
1320        let displacement = self.fetch_operand() as i8;
1321        self.bus_idle();
1322        self.bus_idle();
1323
1324        self.push_stack_u16(self.cpu.registers.pc.wrapping_sub(1));
1325        self.bus_idle();
1326
1327        self.cpu.registers.pc = self.cpu.registers.pc.wrapping_add_signed(displacement.into());
1328
1329        self.bus_idle();
1330    }
1331
1332    // RTS: Return from subroutine
1333    fn rts(&mut self) {
1334        self.bus_idle();
1335        self.bus_idle();
1336        self.cpu.registers.pc = self.pull_stack_u16();
1337        self.bus_idle();
1338
1339        self.fetch_operand(); // Advance PC
1340    }
1341
1342    // RTI: Return from interrupt
1343    fn rti(&mut self) {
1344        self.bus_idle();
1345        self.cpu.registers.p = self.pull_stack().into();
1346        self.cpu.registers.pc = self.pull_stack_u16();
1347        self.bus_idle();
1348
1349        self.bus_idle();
1350    }
1351
1352    // PHA: Push A
1353    fn pha(&mut self) {
1354        self.bus_idle();
1355        self.push_stack(self.cpu.registers.a);
1356    }
1357
1358    // PHX: Push X
1359    fn phx(&mut self) {
1360        self.bus_idle();
1361        self.push_stack(self.cpu.registers.x);
1362    }
1363
1364    // PHY: Push Y
1365    fn phy(&mut self) {
1366        self.bus_idle();
1367        self.push_stack(self.cpu.registers.y);
1368    }
1369
1370    // PHP: Push P
1371    fn php(&mut self) {
1372        self.bus_idle();
1373
1374        // PHP always pushes P with the B flag set
1375        self.push_stack(self.cpu.registers.p.to_u8_brk());
1376    }
1377
1378    #[inline(always)]
1379    fn pull_register(&mut self, register: RwRegister) {
1380        self.bus_idle();
1381        self.bus_idle();
1382
1383        let value = self.pull_stack();
1384        register.set(&mut self.cpu.registers, value);
1385
1386        self.cpu.registers.p.set_zero_negative(value);
1387    }
1388
1389    // PLA: Pull A
1390    fn pla(&mut self) {
1391        self.pull_register(RwRegister::A);
1392    }
1393
1394    // PLX: Pull X
1395    fn plx(&mut self) {
1396        self.pull_register(RwRegister::X);
1397    }
1398
1399    // PLY: Pull Y
1400    fn ply(&mut self) {
1401        self.pull_register(RwRegister::Y);
1402    }
1403
1404    // PLP: Pull P
1405    fn plp(&mut self) {
1406        self.bus_idle();
1407        self.bus_idle();
1408
1409        self.cpu.registers.p = self.pull_stack().into();
1410    }
1411
1412    #[inline(always)]
1413    fn update_memory_bit<const SET: bool>(&mut self, i: u8) {
1414        let zero_page_addr = self.fetch_operand();
1415        self.bus_idle();
1416
1417        let mapped_addr = self.map_zero_page(zero_page_addr);
1418        let value = self.bus_read(mapped_addr);
1419        self.bus_idle();
1420        self.bus_idle();
1421
1422        let result = if SET { value | (1 << i) } else { value & !(1 << i) };
1423        self.bus_write(mapped_addr, result);
1424    }
1425
1426    // RMBi: Reset memory bit
1427    fn rmbi(&mut self, opcode: u8) {
1428        let i = (opcode >> 4) & 7;
1429        self.update_memory_bit::<false>(i);
1430    }
1431
1432    // SMBi: Set memory bit
1433    fn smbi(&mut self, opcode: u8) {
1434        let i = (opcode >> 4) & 7;
1435        self.update_memory_bit::<true>(i);
1436    }
1437
1438    #[inline(always)]
1439    fn branch_on_bit<const SET: bool>(&mut self, i: u8) {
1440        let zero_page_addr = self.fetch_operand();
1441        let displacement = self.fetch_operand() as i8;
1442        self.bus_idle();
1443
1444        log::trace!(
1445            "  Displacement {displacement} ({:04X})",
1446            self.cpu.registers.pc.wrapping_add_signed(displacement.into())
1447        );
1448
1449        let mapped_addr = self.map_zero_page(zero_page_addr);
1450        let value = self.bus_read(mapped_addr);
1451
1452        self.bus_idle();
1453
1454        if value.bit(i) != SET {
1455            return;
1456        }
1457
1458        self.bus_idle();
1459        self.bus_idle();
1460
1461        self.cpu.registers.pc = self.cpu.registers.pc.wrapping_add_signed(displacement.into());
1462    }
1463
1464    // BBRi: Branch on bit reset
1465    fn bbri(&mut self, opcode: u8) {
1466        let i = (opcode >> 4) & 7;
1467        self.branch_on_bit::<false>(i);
1468    }
1469
1470    // BBSi: Branch on bit set
1471    fn bbsi(&mut self, opcode: u8) {
1472        let i = (opcode >> 4) & 7;
1473        self.branch_on_bit::<true>(i);
1474    }
1475
1476    // CLA: Clear A
1477    fn cla(&mut self) {
1478        self.bus_idle();
1479        self.cpu.registers.a = 0;
1480    }
1481
1482    // CLX: Clear X
1483    fn clx(&mut self) {
1484        self.bus_idle();
1485        self.cpu.registers.x = 0;
1486    }
1487
1488    // CLY: Clear Y
1489    fn cly(&mut self) {
1490        self.bus_idle();
1491        self.cpu.registers.y = 0;
1492    }
1493
1494    // CLC: Clear carry
1495    // CLD: Clear decimal
1496    // CLI: Clear IRQ disable
1497    // CLV: Clear overflow
1498    // SEC: Set carry
1499    // SED: Set deciaml
1500    // SEI: Set IRQ disable
1501    // SET: Set T
1502    impl_set_flag!(clc, carry = false);
1503    impl_set_flag!(cld, decimal = false);
1504    impl_set_flag!(cli, irq_disable = false);
1505    impl_set_flag!(clv, overflow = false);
1506    impl_set_flag!(sec, carry = true);
1507    impl_set_flag!(sed, decimal = true);
1508    impl_set_flag!(sei, irq_disable = true);
1509    impl_set_flag!(set, memory_op = true);
1510
1511    // SAX: Swap A for X
1512    fn sax(&mut self) {
1513        self.bus_idle();
1514        self.bus_idle();
1515
1516        mem::swap(&mut self.cpu.registers.a, &mut self.cpu.registers.x);
1517    }
1518
1519    // SAX: Swap A for Y
1520    fn say(&mut self) {
1521        self.bus_idle();
1522        self.bus_idle();
1523
1524        mem::swap(&mut self.cpu.registers.a, &mut self.cpu.registers.y);
1525    }
1526
1527    // SXY: Swap X for Y
1528    fn sxy(&mut self) {
1529        self.bus_idle();
1530        self.bus_idle();
1531
1532        mem::swap(&mut self.cpu.registers.x, &mut self.cpu.registers.y);
1533    }
1534
1535    #[inline(always)]
1536    fn transfer(&mut self, from: ReadRegister, to: RwRegister) {
1537        self.bus_idle();
1538
1539        let value = from.get(&self.cpu.registers);
1540        to.set(&mut self.cpu.registers, value);
1541
1542        // TXS does not set flags
1543        if to != RwRegister::S {
1544            self.cpu.registers.p.set_zero_negative(value);
1545        }
1546    }
1547
1548    // TAX: Transfer A to X
1549    fn tax(&mut self) {
1550        self.transfer(ReadRegister::A, RwRegister::X);
1551    }
1552
1553    // TAY: Transfer A to Y
1554    fn tay(&mut self) {
1555        self.transfer(ReadRegister::A, RwRegister::Y);
1556    }
1557
1558    // TSX: Transfer S to X
1559    fn tsx(&mut self) {
1560        self.transfer(ReadRegister::S, RwRegister::X);
1561    }
1562
1563    // TXA: Transfer X to A
1564    fn txa(&mut self) {
1565        self.transfer(ReadRegister::X, RwRegister::A);
1566    }
1567
1568    // TXS: Transfer X to S
1569    fn txs(&mut self) {
1570        self.transfer(ReadRegister::X, RwRegister::S);
1571    }
1572
1573    // TYA: Transfer Y to A
1574    fn tya(&mut self) {
1575        self.transfer(ReadRegister::Y, RwRegister::A);
1576    }
1577
1578    // TRB: Test and reset bits
1579    fn trb(&mut self, operand: u8) -> u8 {
1580        self.cpu.registers.p.zero = operand & self.cpu.registers.a == 0;
1581        self.cpu.registers.p.overflow = operand.bit(6);
1582        self.cpu.registers.p.negative = operand.bit(7);
1583
1584        operand & !self.cpu.registers.a
1585    }
1586
1587    impl_modify_fn!(trb_zero_page, modify_zero_page(trb));
1588    impl_modify_fn!(trb_absolute, modify_absolute(trb));
1589
1590    // TSB: Test and set bits
1591    fn tsb(&mut self, operand: u8) -> u8 {
1592        self.cpu.registers.p.zero = operand & self.cpu.registers.a == 0;
1593        self.cpu.registers.p.overflow = operand.bit(6);
1594        self.cpu.registers.p.negative = operand.bit(7);
1595
1596        operand | self.cpu.registers.a
1597    }
1598
1599    impl_modify_fn!(tsb_zero_page, modify_zero_page(tsb));
1600    impl_modify_fn!(tsb_absolute, modify_absolute(tsb));
1601
1602    // TST: Test memory
1603    fn tst(&mut self, memory_value: u8, operand: u8) {
1604        self.cpu.registers.p.zero = memory_value & operand == 0;
1605        self.cpu.registers.p.overflow = memory_value.bit(6);
1606        self.cpu.registers.p.negative = memory_value.bit(7);
1607    }
1608
1609    #[inline(always)]
1610    fn tst_zero_page_indexed(&mut self, index: Option<IndexRegister>) {
1611        let operand = self.fetch_operand();
1612        let zero_page_addr = self.fetch_operand();
1613        self.bus_idle();
1614        self.bus_idle();
1615
1616        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
1617        let indexed_addr = zero_page_addr.wrapping_add(offset);
1618        let memory_value = self.bus_read(self.map_zero_page(indexed_addr));
1619        self.bus_idle();
1620
1621        self.tst(memory_value, operand);
1622    }
1623
1624    #[inline(always)]
1625    fn tst_absolute_indexed(&mut self, index: Option<IndexRegister>) {
1626        let operand = self.fetch_operand();
1627        let address = self.fetch_operand_u16();
1628        self.bus_idle();
1629        self.bus_idle();
1630
1631        let offset = index.map_or(0, |index| index.get(&self.cpu.registers));
1632        let indexed_addr = address.wrapping_add(offset.into());
1633        let memory_value = self.bus_read(self.map_address(indexed_addr));
1634        self.bus_idle();
1635
1636        self.tst(memory_value, operand);
1637    }
1638
1639    fn tst_zero_page(&mut self) {
1640        self.tst_zero_page_indexed(None);
1641    }
1642
1643    fn tst_zero_page_x(&mut self) {
1644        self.tst_zero_page_indexed(Some(IndexRegister::X));
1645    }
1646
1647    fn tst_absolute(&mut self) {
1648        self.tst_absolute_indexed(None);
1649    }
1650
1651    fn tst_absolute_x(&mut self) {
1652        self.tst_absolute_indexed(Some(IndexRegister::X));
1653    }
1654
1655    // ST0/ST1/ST2: Store HuC6270 (VDC)
1656    fn sti<const I: u8>(&mut self) {
1657        assert!(I < 3);
1658
1659        // ST0/ST1/ST2 always write to VDC physical addresses; MPRs are not used
1660        let vdc_address = match I {
1661            0 => 0x1FE000,
1662            1 => 0x1FE002,
1663            2 => 0x1FE003,
1664            _ => unreachable!("I must be less than 3"),
1665        };
1666
1667        let data = self.fetch_operand();
1668        self.bus_idle();
1669        self.bus_write(vdc_address, data);
1670    }
1671
1672    fn st0(&mut self) {
1673        self.sti::<0>();
1674    }
1675
1676    fn st1(&mut self) {
1677        self.sti::<1>();
1678    }
1679
1680    fn st2(&mut self) {
1681        self.sti::<2>();
1682    }
1683
1684    // TAMi: Transfer A to MPR
1685    fn tam(&mut self) {
1686        self.bus_idle();
1687        self.bus_idle();
1688        self.bus_idle();
1689
1690        let bits = self.fetch_operand();
1691        if bits != 0 {
1692            self.cpu.state.mpr_buffer = self.cpu.registers.a;
1693
1694            // If multiple bits are set, A gets copied to each MPR whose bit is set
1695            for i in 0..8 {
1696                if bits.bit(i) {
1697                    self.cpu.registers.mpr[i as usize] = self.cpu.registers.a;
1698                }
1699            }
1700        }
1701    }
1702
1703    // TMAi: Transfer MPR to A
1704    fn tma(&mut self) {
1705        self.bus_idle();
1706        self.bus_idle();
1707
1708        let bits = self.fetch_operand();
1709        self.cpu.registers.a = match bits {
1710            0 => self.cpu.state.mpr_buffer,
1711            _ => {
1712                // If multiple bits are set, the results are "combined" in some way
1713                // Unclear exactly how; this is probably not accurate
1714                let mut value = 0xFF;
1715                for i in 0..8 {
1716                    if bits.bit(i) {
1717                        value &= self.cpu.registers.mpr[i as usize];
1718                    }
1719                }
1720                value
1721            }
1722        };
1723
1724        self.cpu.state.mpr_buffer = self.cpu.registers.a;
1725    }
1726
1727    // CSH: Clock speed high
1728    fn csh(&mut self) {
1729        self.bus_idle();
1730        self.bus.set_clock_speed(ClockSpeed::High);
1731        self.bus_idle();
1732    }
1733
1734    // CSL: Clock speed low
1735    fn csl(&mut self) {
1736        self.bus_idle();
1737        self.bus.set_clock_speed(ClockSpeed::Low);
1738        self.bus_idle();
1739    }
1740
1741    fn start_block_transfer(
1742        &mut self,
1743        source_step: BlockTransferStep,
1744        destination_step: BlockTransferStep,
1745    ) {
1746        self.bus_idle();
1747
1748        self.push_stack(self.cpu.registers.y);
1749        self.push_stack(self.cpu.registers.a);
1750        self.push_stack(self.cpu.registers.x);
1751
1752        self.bus_idle();
1753
1754        let source = self.fetch_operand_u16();
1755        let destination = self.fetch_operand_u16();
1756        let length = self.fetch_operand_u16();
1757
1758        self.bus_idle();
1759
1760        log::trace!(
1761            "Starting block transfer; source={source:04X}, destination={destination:04X}, length={length:04X}"
1762        );
1763
1764        self.cpu.state.block_transfer = Some(BlockTransferState {
1765            source,
1766            destination,
1767            length,
1768            source_step,
1769            destination_step,
1770            count: 0,
1771        });
1772    }
1773
1774    fn progress_block_transfer(&mut self) {
1775        let Some(state) = &mut self.cpu.state.block_transfer else {
1776            panic!("progress_block_transfer() called when block transfer state is None");
1777        };
1778
1779        self.bus.idle();
1780
1781        let source_addr = self.cpu.registers.map_address(state.source);
1782        let value = match source_addr {
1783            0x1FE800..=0x1FF7FF => {
1784                // Block transfer cannot read from non-VDC I/O addresses
1785                self.bus.idle();
1786                0
1787            }
1788            _ => self.bus.read(source_addr),
1789        };
1790
1791        self.bus.idle();
1792
1793        let dest_addr = self.cpu.registers.map_address(state.destination);
1794        self.bus.write(dest_addr, value);
1795
1796        self.bus.idle();
1797        self.bus.idle();
1798
1799        state.source = state.source_step.apply(state.source, state.count);
1800        state.destination = state.destination_step.apply(state.destination, state.count);
1801        state.count = state.count.wrapping_add(1);
1802        state.length = state.length.wrapping_sub(1);
1803
1804        if state.length == 0 {
1805            self.bus.idle();
1806
1807            self.cpu.registers.x = self.pull_stack();
1808            self.cpu.registers.a = self.pull_stack();
1809            self.cpu.registers.y = self.pull_stack();
1810
1811            self.cpu.state.block_transfer = None;
1812
1813            log::trace!("Block transfer complete");
1814        }
1815    }
1816
1817    // TAI: Transfer block data (source alternate, dest increment)
1818    fn tai(&mut self) {
1819        self.start_block_transfer(BlockTransferStep::Alternate, BlockTransferStep::Increment);
1820    }
1821
1822    // TDD: Transfer block data (source decrement, dest decrement)
1823    fn tdd(&mut self) {
1824        self.start_block_transfer(BlockTransferStep::Decrement, BlockTransferStep::Decrement);
1825    }
1826
1827    // TIA: Transfer block data (source increment, dest alternate)
1828    fn tia(&mut self) {
1829        self.start_block_transfer(BlockTransferStep::Increment, BlockTransferStep::Alternate);
1830    }
1831
1832    // TII: Transfer block data (source increment, dest increment)
1833    fn tii(&mut self) {
1834        self.start_block_transfer(BlockTransferStep::Increment, BlockTransferStep::Increment);
1835    }
1836
1837    // TIN: Transfer block data (source increment, dest none)
1838    fn tin(&mut self) {
1839        self.start_block_transfer(BlockTransferStep::Increment, BlockTransferStep::None);
1840    }
1841}