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
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}