1mod alu; 2mod bits; 3mod disassemble; 4mod flags; 5mod flow; 6mod load; 7 8use crate::core::{InterruptType, Registers, SizeBits, Wdc65816}; 9use crate::traits::BusInterface; 10use jgenesis_common::num::{GetBit, SignBit, U16Ext}; 11 12fn u24_address(bank: u8, address: u16) -> u32 { 13 (u32::from(bank) << 16) | u32::from(address) 14} 15 16fn fetch_operand<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) -> u8 { 17 let operand = bus.read(u24_address(cpu.registers.pbr, cpu.registers.pc)); 18 cpu.registers.pc = cpu.registers.pc.wrapping_add(1); 19 20 log::trace!( 21 "Fetched operand {operand:02X} from PBR {:02X} / PC {:04X}", 22 cpu.registers.pbr, 23 cpu.registers.pc.wrapping_sub(1) 24 ); 25 26 operand 27} 28 29fn poll_interrupt_lines<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 30 let nmi = bus.nmi(); 31 cpu.state.nmi_triggered |= !cpu.state.last_nmi && nmi; 32 cpu.state.last_nmi = nmi; 33 34 let irq = bus.irq(); 35 cpu.state.irq_triggered = !cpu.registers.p.irq_disabled && irq; 36 cpu.state.last_irq = irq; 37} 38 39fn final_cycle<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 40 poll_interrupt_lines(cpu, bus); 41 cpu.state.cycle = 0; 42} 43 44fn ensure_page_1_stack(registers: &mut Registers) { 45 registers.s = 0x0100 | (registers.s & 0x00FF); 46} 47 48macro_rules! invalid_cycle { 49 ($cpu:expr) => { 50 panic!("Invalid cycle for opcode {:02X}: {}", $cpu.state.opcode, $cpu.state.cycle) 51 }; 52} 53 54use invalid_cycle; 55 56macro_rules! impl_read_immediate_u8 { 57 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 58 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 59 final_cycle(cpu, bus); 60 61 let $value = fetch_operand(cpu, bus); 62 let $registers = &mut cpu.registers; 63 $body 64 } 65 }; 66} 67 68use impl_read_immediate_u8; 69 70macro_rules! impl_read_immediate_u16 { 71 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 72 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 73 match cpu.state.cycle { 74 1 => { 75 cpu.state.t0 = fetch_operand(cpu, bus); 76 } 77 2 => { 78 final_cycle(cpu, bus); 79 80 let msb = fetch_operand(cpu, bus); 81 let $value = u16::from_le_bytes([cpu.state.t0, msb]); 82 let $registers = &mut cpu.registers; 83 $body 84 } 85 _ => invalid_cycle!(cpu), 86 } 87 } 88 }; 89} 90 91use impl_read_immediate_u16; 92 93fn check_direct_page_low_byte(cpu: &mut Wdc65816) { 94 // Low byte of D being non-zero causes an extra cycle for direct page access; emulate this by 95 // skipping a cycle if it is zero 96 if cpu.registers.d & 0x00FF == 0 { 97 cpu.state.cycle += 1; 98 } 99} 100 101macro_rules! impl_read_direct_page_u8 { 102 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 103 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 104 match cpu.state.cycle { 105 1 => { 106 cpu.state.t0 = fetch_operand(cpu, bus); 107 check_direct_page_low_byte(cpu); 108 } 109 2 => { 110 // Idle cycle if D LSB is non-zero 111 bus.idle(); 112 } 113 3 => { 114 final_cycle(cpu, bus); 115 116 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 117 let $value = bus.read(address.into()); 118 let $registers = &mut cpu.registers; 119 $body 120 } 121 _ => invalid_cycle!(cpu), 122 } 123 } 124 }; 125} 126 127use impl_read_direct_page_u8; 128 129macro_rules! impl_read_direct_page_u16 { 130 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 131 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 132 match cpu.state.cycle { 133 1 => { 134 cpu.state.t0 = fetch_operand(cpu, bus); 135 check_direct_page_low_byte(cpu); 136 } 137 2 => { 138 // Idle cycle if D LSB is non-zero 139 bus.idle(); 140 } 141 3 => { 142 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 143 cpu.state.t1 = bus.read(address.into()); 144 } 145 4 => { 146 final_cycle(cpu, bus); 147 148 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 149 let value_msb = bus.read(address.wrapping_add(1).into()); 150 let $value = u16::from_le_bytes([cpu.state.t1, value_msb]); 151 let $registers = &mut cpu.registers; 152 $body 153 } 154 _ => invalid_cycle!(cpu), 155 } 156 } 157 }; 158} 159 160use impl_read_direct_page_u16; 161 162fn index_direct_page(cpu: &Wdc65816, operand: u8, index: u16) -> u16 { 163 if cpu.registers.emulation_mode && cpu.registers.d & 0x00FF == 0 { 164 // If in emulation mode with D LSB equal to zero, indexing wraps at page boundary 165 (cpu.registers.d.wrapping_add(operand.into()).wrapping_add(index) & 0x00FF) 166 | (cpu.registers.d & 0xFF00) 167 } else { 168 cpu.registers.d.wrapping_add(operand.into()).wrapping_add(index) 169 } 170} 171 172macro_rules! impl_read_direct_page_indexed_u8 { 173 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 174 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 175 match cpu.state.cycle { 176 1 => { 177 cpu.state.t0 = fetch_operand(cpu, bus); 178 check_direct_page_low_byte(cpu); 179 } 180 2 => { 181 // Idle cycle if D LSB is non-zero 182 bus.idle(); 183 } 184 3 => { 185 // Idle cycle for adding index 186 bus.idle(); 187 } 188 4 => { 189 final_cycle(cpu, bus); 190 191 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 192 let $value = bus.read(address.into()); 193 let $registers = &mut cpu.registers; 194 $body 195 } 196 _ => invalid_cycle!(cpu), 197 } 198 } 199 }; 200} 201 202use impl_read_direct_page_indexed_u8; 203 204macro_rules! impl_read_direct_page_indexed_u16 { 205 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 206 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 207 match cpu.state.cycle { 208 1 => { 209 cpu.state.t0 = fetch_operand(cpu, bus); 210 check_direct_page_low_byte(cpu); 211 } 212 2 => { 213 // Idle cycle if D LSB is non-zero 214 bus.idle(); 215 } 216 3 => { 217 // Idle cycle for adding index 218 bus.idle(); 219 } 220 4 => { 221 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 222 cpu.state.t1 = bus.read(address.into()); 223 } 224 5 => { 225 final_cycle(cpu, bus); 226 227 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 228 let value_msb = bus.read(address.wrapping_add(1).into()); 229 let $value = u16::from_le_bytes([cpu.state.t1, value_msb]); 230 let $registers = &mut cpu.registers; 231 $body 232 } 233 _ => invalid_cycle!(cpu), 234 } 235 } 236 }; 237} 238 239use impl_read_direct_page_indexed_u16; 240 241macro_rules! impl_read_direct_page_indirect_u8 { 242 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 243 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 244 match cpu.state.cycle { 245 1 => { 246 cpu.state.t0 = fetch_operand(cpu, bus); 247 check_direct_page_low_byte(cpu); 248 } 249 2 => { 250 // Idle cycle if D LSB is non-zero 251 bus.idle(); 252 } 253 3 => { 254 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 255 cpu.state.t1 = bus.read(address.into()); 256 } 257 4 => { 258 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 259 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 260 } 261 5 => { 262 final_cycle(cpu, bus); 263 264 let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 265 let $value = bus.read(u24_address(cpu.registers.dbr, address)); 266 let $registers = &mut cpu.registers; 267 $body 268 } 269 _ => invalid_cycle!(cpu), 270 } 271 } 272 }; 273} 274 275use impl_read_direct_page_indirect_u8; 276 277macro_rules! impl_read_direct_page_indirect_u16 { 278 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 279 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 280 match cpu.state.cycle { 281 1 => { 282 cpu.state.t0 = fetch_operand(cpu, bus); 283 check_direct_page_low_byte(cpu); 284 } 285 2 => { 286 // Idle cycle if D LSB is non-zero 287 bus.idle(); 288 } 289 3 => { 290 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 291 cpu.state.t1 = bus.read(address.into()); 292 } 293 4 => { 294 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 295 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 296 } 297 5 => { 298 let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 299 cpu.state.t3 = bus.read(u24_address(cpu.registers.dbr, address)); 300 } 301 6 => { 302 final_cycle(cpu, bus); 303 304 let base_addr = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 305 let address = (u24_address(cpu.registers.dbr, base_addr) + 1) & B::ADDRESS_MASK; 306 let value_msb = bus.read(address); 307 let $value = u16::from_le_bytes([cpu.state.t3, value_msb]); 308 let $registers = &mut cpu.registers; 309 $body 310 } 311 _ => invalid_cycle!(cpu), 312 } 313 } 314 }; 315} 316 317use impl_read_direct_page_indirect_u16; 318 319macro_rules! impl_read_direct_page_indexed_indirect_u8 { 320 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 321 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 322 match cpu.state.cycle { 323 1 => { 324 cpu.state.t0 = fetch_operand(cpu, bus); 325 check_direct_page_low_byte(cpu); 326 } 327 2 => { 328 // Idle cycle if D LSB is non-zero 329 bus.idle(); 330 } 331 3 => { 332 // Idle cycle to add index 333 bus.idle(); 334 } 335 4 => { 336 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.x); 337 cpu.state.t1 = bus.read(address.into()); 338 } 339 5 => { 340 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.x); 341 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 342 } 343 6 => { 344 final_cycle(cpu, bus); 345 346 let base_addr = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 347 let address = u24_address(cpu.registers.dbr, base_addr); 348 let $value = bus.read(address); 349 let $registers = &mut cpu.registers; 350 $body 351 } 352 _ => invalid_cycle!(cpu), 353 } 354 } 355 }; 356} 357 358use impl_read_direct_page_indexed_indirect_u8; 359 360macro_rules! impl_read_direct_page_indexed_indirect_u16 { 361 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 362 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 363 match cpu.state.cycle { 364 1 => { 365 cpu.state.t0 = fetch_operand(cpu, bus); 366 check_direct_page_low_byte(cpu); 367 } 368 2 => { 369 // Idle cycle if D LSB is non-zero 370 bus.idle(); 371 } 372 3 => { 373 // Idle cycle to add index 374 bus.idle(); 375 } 376 4 => { 377 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.x); 378 cpu.state.t1 = bus.read(address.into()); 379 } 380 5 => { 381 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.x); 382 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 383 } 384 6 => { 385 let base_addr = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 386 let address = u24_address(cpu.registers.dbr, base_addr); 387 cpu.state.t3 = bus.read(address); 388 } 389 7 => { 390 final_cycle(cpu, bus); 391 392 let base_addr = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 393 let address = (u24_address(cpu.registers.dbr, base_addr) + 1) & B::ADDRESS_MASK; 394 let value_msb = bus.read(address); 395 let $value = u16::from_le_bytes([cpu.state.t3, value_msb]); 396 let $registers = &mut cpu.registers; 397 $body 398 } 399 _ => invalid_cycle!(cpu), 400 } 401 } 402 }; 403} 404 405use impl_read_direct_page_indexed_indirect_u16; 406 407macro_rules! impl_read_direct_page_indirect_indexed_u8 { 408 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 409 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 410 match cpu.state.cycle { 411 1 => { 412 cpu.state.t0 = fetch_operand(cpu, bus); 413 check_direct_page_low_byte(cpu); 414 } 415 2 => { 416 // Idle cycle if D LSB is non-zero 417 bus.idle(); 418 } 419 3 => { 420 let address = index_direct_page(cpu, cpu.state.t0, 0); 421 cpu.state.t1 = bus.read(address.into()); 422 } 423 4 => { 424 let address = index_direct_page(cpu, cpu.state.t0, 0); 425 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 426 check_absolute_index( 427 cpu, 428 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 429 cpu.registers.y, 430 ); 431 } 432 5 => { 433 // Idle cycle for adding index 434 bus.idle(); 435 } 436 6 => { 437 final_cycle(cpu, bus); 438 439 let base_addr = u24_address( 440 cpu.registers.dbr, 441 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 442 ); 443 let index: u32 = cpu.registers.y.into(); 444 let address = (base_addr + index) & B::ADDRESS_MASK; 445 let $value = bus.read(address); 446 let $registers = &mut cpu.registers; 447 $body 448 } 449 _ => invalid_cycle!(cpu), 450 } 451 } 452 }; 453} 454 455use impl_read_direct_page_indirect_indexed_u8; 456 457macro_rules! impl_read_direct_page_indirect_indexed_u16 { 458 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 459 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 460 match cpu.state.cycle { 461 1 => { 462 cpu.state.t0 = fetch_operand(cpu, bus); 463 check_direct_page_low_byte(cpu); 464 } 465 2 => { 466 // Idle cycle if D LSB is non-zero 467 bus.idle(); 468 } 469 3 => { 470 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 471 cpu.state.t1 = bus.read(address.into()); 472 } 473 4 => { 474 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()).wrapping_add(1); 475 cpu.state.t2 = bus.read(address.into()); 476 check_absolute_index( 477 cpu, 478 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 479 cpu.registers.y, 480 ); 481 } 482 5 => { 483 // Idle cycle for adding index 484 bus.idle(); 485 } 486 6 => { 487 let base_addr = u24_address( 488 cpu.registers.dbr, 489 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 490 ); 491 let index: u32 = cpu.registers.y.into(); 492 let address = (base_addr + index) & B::ADDRESS_MASK; 493 cpu.state.t3 = bus.read(address); 494 } 495 7 => { 496 final_cycle(cpu, bus); 497 498 let base_addr = u24_address( 499 cpu.registers.dbr, 500 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 501 ); 502 let index: u32 = cpu.registers.y.into(); 503 let address = (base_addr + index + 1) & B::ADDRESS_MASK; 504 let value_msb = bus.read(address); 505 let $value = u16::from_le_bytes([cpu.state.t3, value_msb]); 506 let $registers = &mut cpu.registers; 507 $body 508 } 509 _ => invalid_cycle!(cpu), 510 } 511 } 512 }; 513} 514 515use impl_read_direct_page_indirect_indexed_u16; 516 517macro_rules! impl_read_direct_page_indirect_long_u8 { 518 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 519 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 520 match cpu.state.cycle { 521 1 => { 522 cpu.state.t0 = fetch_operand(cpu, bus); 523 check_direct_page_low_byte(cpu); 524 } 525 2 => { 526 // Idle cycle if D LSB is non-zero 527 bus.idle(); 528 } 529 3 => { 530 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 531 cpu.state.t1 = bus.read(address.into()); 532 } 533 4 => { 534 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 535 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 536 } 537 5 => { 538 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 539 cpu.state.t3 = bus.read(address.wrapping_add(2).into()); 540 } 541 6 => { 542 final_cycle(cpu, bus); 543 544 let address = u32::from_le_bytes([cpu.state.t1, cpu.state.t2, cpu.state.t3, 0]); 545 let $value = bus.read(address); 546 let $registers = &mut cpu.registers; 547 $body 548 } 549 _ => invalid_cycle!(cpu), 550 } 551 } 552 }; 553} 554 555use impl_read_direct_page_indirect_long_u8; 556 557macro_rules! impl_read_direct_page_indirect_long_u16 { 558 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 559 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 560 match cpu.state.cycle { 561 1 => { 562 cpu.state.t0 = fetch_operand(cpu, bus); 563 check_direct_page_low_byte(cpu); 564 } 565 2 => { 566 // Idle cycle if D LSB is non-zero 567 bus.idle(); 568 } 569 3 => { 570 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 571 cpu.state.t1 = bus.read(address.into()); 572 } 573 4 => { 574 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 575 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 576 } 577 5 => { 578 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 579 cpu.state.t3 = bus.read(address.wrapping_add(2).into()); 580 } 581 6 => { 582 let address = u32::from_le_bytes([cpu.state.t1, cpu.state.t2, cpu.state.t3, 0]); 583 cpu.state.t4 = bus.read(address); 584 } 585 7 => { 586 final_cycle(cpu, bus); 587 588 let address = u32::from_le_bytes([cpu.state.t1, cpu.state.t2, cpu.state.t3, 0]); 589 let value_msb = bus.read((address + 1) & B::ADDRESS_MASK); 590 let $value = u16::from_le_bytes([cpu.state.t4, value_msb]); 591 let $registers = &mut cpu.registers; 592 $body 593 } 594 _ => invalid_cycle!(cpu), 595 } 596 } 597 }; 598} 599 600use impl_read_direct_page_indirect_long_u16; 601 602macro_rules! impl_read_direct_page_indirect_long_indexed_u8 { 603 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 604 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 605 match cpu.state.cycle { 606 1 => { 607 cpu.state.t0 = fetch_operand(cpu, bus); 608 check_direct_page_low_byte(cpu); 609 } 610 2 => { 611 // Idle cycle if D LSB is non-zero 612 bus.idle(); 613 } 614 3 => { 615 let address = index_direct_page(cpu, cpu.state.t0, 0); 616 cpu.state.t1 = bus.read(address.into()); 617 } 618 4 => { 619 let address = index_direct_page(cpu, cpu.state.t0, 1); 620 cpu.state.t2 = bus.read(address.into()); 621 } 622 5 => { 623 let address = index_direct_page(cpu, cpu.state.t0, 2); 624 cpu.state.t3 = bus.read(address.into()); 625 } 626 6 => { 627 final_cycle(cpu, bus); 628 629 let base_addr = 630 u32::from_le_bytes([cpu.state.t1, cpu.state.t2, cpu.state.t3, 0]); 631 let index: u32 = cpu.registers.y.into(); 632 let address = (base_addr + index) & B::ADDRESS_MASK; 633 let $value = bus.read(address); 634 let $registers = &mut cpu.registers; 635 $body 636 } 637 _ => invalid_cycle!(cpu), 638 } 639 } 640 }; 641} 642 643use impl_read_direct_page_indirect_long_indexed_u8; 644 645macro_rules! impl_read_direct_page_indirect_long_indexed_u16 { 646 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 647 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 648 match cpu.state.cycle { 649 1 => { 650 cpu.state.t0 = fetch_operand(cpu, bus); 651 check_direct_page_low_byte(cpu); 652 } 653 2 => { 654 // Idle cycle if D LSB is non-zero 655 bus.idle(); 656 } 657 3 => { 658 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 659 cpu.state.t1 = bus.read(address.into()); 660 } 661 4 => { 662 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 663 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 664 } 665 5 => { 666 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 667 cpu.state.t3 = bus.read(address.wrapping_add(2).into()); 668 } 669 6 => { 670 let base_addr = 671 u32::from_le_bytes([cpu.state.t1, cpu.state.t2, cpu.state.t3, 0]); 672 let index: u32 = cpu.registers.y.into(); 673 let address = (base_addr + index) & B::ADDRESS_MASK; 674 cpu.state.t4 = bus.read(address); 675 } 676 7 => { 677 final_cycle(cpu, bus); 678 679 let base_addr = 680 u32::from_le_bytes([cpu.state.t1, cpu.state.t2, cpu.state.t3, 0]); 681 let index: u32 = cpu.registers.y.into(); 682 let address = (base_addr + index + 1) & B::ADDRESS_MASK; 683 let value_msb = bus.read(address); 684 let $value = u16::from_le_bytes([cpu.state.t4, value_msb]); 685 let $registers = &mut cpu.registers; 686 $body 687 } 688 _ => invalid_cycle!(cpu), 689 } 690 } 691 }; 692} 693 694use impl_read_direct_page_indirect_long_indexed_u16; 695 696macro_rules! impl_read_absolute_u8 { 697 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 698 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 699 match cpu.state.cycle { 700 1 => { 701 cpu.state.t0 = fetch_operand(cpu, bus); 702 } 703 2 => { 704 cpu.state.t1 = fetch_operand(cpu, bus); 705 } 706 3 => { 707 final_cycle(cpu, bus); 708 709 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 710 let $value = bus.read(u24_address(cpu.registers.dbr, address)); 711 let $registers = &mut cpu.registers; 712 $body 713 } 714 _ => invalid_cycle!(cpu), 715 } 716 } 717 }; 718} 719 720use impl_read_absolute_u8; 721 722macro_rules! impl_read_absolute_u16 { 723 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 724 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 725 match cpu.state.cycle { 726 1 => { 727 cpu.state.t0 = fetch_operand(cpu, bus); 728 } 729 2 => { 730 cpu.state.t1 = fetch_operand(cpu, bus); 731 } 732 3 => { 733 let base_addr = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 734 cpu.state.t2 = bus.read(u24_address(cpu.registers.dbr, base_addr)); 735 } 736 4 => { 737 final_cycle(cpu, bus); 738 739 let base_addr = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 740 let address = (u24_address(cpu.registers.dbr, base_addr) + 1) & B::ADDRESS_MASK; 741 let value_msb = bus.read(address); 742 let $value = u16::from_le_bytes([cpu.state.t2, value_msb]); 743 let $registers = &mut cpu.registers; 744 $body 745 } 746 _ => invalid_cycle!(cpu), 747 } 748 } 749 }; 750} 751 752use impl_read_absolute_u16; 753 754fn check_absolute_index(cpu: &mut Wdc65816, absolute_addr: u16, index: u16) { 755 // Absolute X/Y reads skip the idle cycle if index is 8-bit and indexing does not cross a page 756 // boundary 757 if cpu.registers.p.index_size == SizeBits::Eight 758 && absolute_addr.wrapping_add(index) & 0xFF00 == absolute_addr & 0xFF00 759 { 760 cpu.state.cycle += 1; 761 } 762} 763 764macro_rules! impl_read_absolute_indexed_u8 { 765 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 766 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 767 match cpu.state.cycle { 768 1 => { 769 cpu.state.t0 = fetch_operand(cpu, bus); 770 } 771 2 => { 772 cpu.state.t1 = fetch_operand(cpu, bus); 773 check_absolute_index( 774 cpu, 775 u16::from_le_bytes([cpu.state.t0, cpu.state.t1]), 776 cpu.registers.$index, 777 ); 778 } 779 3 => { 780 // Idle cycle for adding index, taken if either of the following is true: 781 // - x flag is set (8-bit index) and indexing crosses a page boundary 782 // - x flag is not set (16-bit index) 783 bus.idle(); 784 } 785 4 => { 786 final_cycle(cpu, bus); 787 788 let base_addr = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 789 let index: u32 = cpu.registers.$index.into(); 790 let address = 791 (u24_address(cpu.registers.dbr, base_addr) + index) & B::ADDRESS_MASK; 792 let $value = bus.read(address); 793 let $registers = &mut cpu.registers; 794 $body 795 } 796 _ => invalid_cycle!(cpu), 797 } 798 } 799 }; 800} 801 802use impl_read_absolute_indexed_u8; 803 804macro_rules! impl_read_absolute_indexed_u16 { 805 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 806 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 807 match cpu.state.cycle { 808 1 => { 809 cpu.state.t0 = fetch_operand(cpu, bus); 810 } 811 2 => { 812 cpu.state.t1 = fetch_operand(cpu, bus); 813 check_absolute_index( 814 cpu, 815 u16::from_le_bytes([cpu.state.t0, cpu.state.t1]), 816 cpu.registers.$index, 817 ); 818 } 819 3 => { 820 // Idle cycle for adding index 821 bus.idle(); 822 } 823 4 => { 824 let base_addr = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 825 let index: u32 = cpu.registers.$index.into(); 826 let address = 827 (u24_address(cpu.registers.dbr, base_addr) + index) & B::ADDRESS_MASK; 828 cpu.state.t2 = bus.read(address); 829 } 830 5 => { 831 final_cycle(cpu, bus); 832 833 let base_addr = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 834 let index: u32 = cpu.registers.$index.into(); 835 let address = 836 (u24_address(cpu.registers.dbr, base_addr) + index + 1) & B::ADDRESS_MASK; 837 let value_msb = bus.read(address); 838 let $value = u16::from_le_bytes([cpu.state.t2, value_msb]); 839 let $registers = &mut cpu.registers; 840 $body 841 } 842 _ => invalid_cycle!(cpu), 843 } 844 } 845 }; 846} 847 848use impl_read_absolute_indexed_u16; 849 850macro_rules! impl_read_absolute_long_u8 { 851 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 852 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 853 match cpu.state.cycle { 854 1 => { 855 cpu.state.t0 = fetch_operand(cpu, bus); 856 } 857 2 => { 858 cpu.state.t1 = fetch_operand(cpu, bus); 859 } 860 3 => { 861 cpu.state.t2 = fetch_operand(cpu, bus); 862 } 863 4 => { 864 final_cycle(cpu, bus); 865 866 let address = u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.state.t2, 0]); 867 let $value = bus.read(address); 868 let $registers = &mut cpu.registers; 869 $body 870 } 871 _ => invalid_cycle!(cpu), 872 } 873 } 874 }; 875} 876 877use impl_read_absolute_long_u8; 878 879macro_rules! impl_read_absolute_long_u16 { 880 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 881 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 882 match cpu.state.cycle { 883 1 => { 884 cpu.state.t0 = fetch_operand(cpu, bus); 885 } 886 2 => { 887 cpu.state.t1 = fetch_operand(cpu, bus); 888 } 889 3 => { 890 cpu.state.t2 = fetch_operand(cpu, bus); 891 } 892 4 => { 893 let address = u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.state.t2, 0]); 894 cpu.state.t3 = bus.read(address); 895 } 896 5 => { 897 final_cycle(cpu, bus); 898 899 let address = u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.state.t2, 0]); 900 let value_msb = bus.read((address + 1) & B::ADDRESS_MASK); 901 let $value = u16::from_le_bytes([cpu.state.t3, value_msb]); 902 let $registers = &mut cpu.registers; 903 $body 904 } 905 _ => invalid_cycle!(cpu), 906 } 907 } 908 }; 909} 910 911use impl_read_absolute_long_u16; 912 913macro_rules! impl_read_absolute_long_indexed_u8 { 914 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 915 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 916 match cpu.state.cycle { 917 1 => { 918 cpu.state.t0 = fetch_operand(cpu, bus); 919 } 920 2 => { 921 cpu.state.t1 = fetch_operand(cpu, bus); 922 } 923 3 => { 924 cpu.state.t2 = fetch_operand(cpu, bus); 925 } 926 4 => { 927 final_cycle(cpu, bus); 928 929 let base_addr = 930 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.state.t2, 0]); 931 let index: u32 = cpu.registers.$index.into(); 932 let address = (base_addr + index) & B::ADDRESS_MASK; 933 let $value = bus.read(address); 934 let $registers = &mut cpu.registers; 935 $body 936 } 937 _ => invalid_cycle!(cpu), 938 } 939 } 940 }; 941} 942 943use impl_read_absolute_long_indexed_u8; 944 945macro_rules! impl_read_absolute_long_indexed_u16 { 946 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 947 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 948 match cpu.state.cycle { 949 1 => { 950 cpu.state.t0 = fetch_operand(cpu, bus); 951 } 952 2 => { 953 cpu.state.t1 = fetch_operand(cpu, bus); 954 } 955 3 => { 956 cpu.state.t2 = fetch_operand(cpu, bus); 957 } 958 4 => { 959 let base_addr = 960 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.state.t2, 0]); 961 let index: u32 = cpu.registers.$index.into(); 962 let address = (base_addr + index) & B::ADDRESS_MASK; 963 cpu.state.t3 = bus.read(address); 964 } 965 5 => { 966 final_cycle(cpu, bus); 967 968 let base_addr = 969 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.state.t2, 0]); 970 let index: u32 = cpu.registers.$index.into(); 971 let address = (base_addr + index + 1) & B::ADDRESS_MASK; 972 let value_msb = bus.read(address); 973 let $value = u16::from_le_bytes([cpu.state.t3, value_msb]); 974 let $registers = &mut cpu.registers; 975 $body 976 } 977 _ => invalid_cycle!(cpu), 978 } 979 } 980 }; 981} 982 983use impl_read_absolute_long_indexed_u16; 984 985macro_rules! impl_read_stack_relative_u8 { 986 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 987 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 988 match cpu.state.cycle { 989 1 => { 990 cpu.state.t0 = fetch_operand(cpu, bus); 991 } 992 2 => { 993 // Idle cycle for indexing into stack 994 bus.idle(); 995 } 996 3 => { 997 final_cycle(cpu, bus); 998 999 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1000 let $value = bus.read(address.into()); 1001 let $registers = &mut cpu.registers; 1002 $body 1003 } 1004 _ => invalid_cycle!(cpu), 1005 } 1006 } 1007 }; 1008} 1009 1010use impl_read_stack_relative_u8; 1011 1012macro_rules! impl_read_stack_relative_u16 { 1013 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1014 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1015 match cpu.state.cycle { 1016 1 => { 1017 cpu.state.t0 = fetch_operand(cpu, bus); 1018 } 1019 2 => { 1020 // Idle cycle for indexing into stack 1021 bus.idle(); 1022 } 1023 3 => { 1024 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1025 cpu.state.t1 = bus.read(address.into()); 1026 } 1027 4 => { 1028 final_cycle(cpu, bus); 1029 1030 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1031 let value_msb = bus.read(address.wrapping_add(1).into()); 1032 let $value = u16::from_le_bytes([cpu.state.t1, value_msb]); 1033 let $registers = &mut cpu.registers; 1034 $body 1035 } 1036 _ => invalid_cycle!(cpu), 1037 } 1038 } 1039 }; 1040} 1041 1042use impl_read_stack_relative_u16; 1043 1044macro_rules! impl_read_stack_relative_indirect_indexed_u8 { 1045 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1046 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1047 match cpu.state.cycle { 1048 1 => { 1049 cpu.state.t0 = fetch_operand(cpu, bus); 1050 } 1051 2 => { 1052 // Idle cycle for indexing into stack 1053 bus.idle(); 1054 } 1055 3 => { 1056 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1057 cpu.state.t1 = bus.read(address.into()); 1058 } 1059 4 => { 1060 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1061 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 1062 } 1063 5 => { 1064 // Idle cycle for indexing with Y 1065 bus.idle(); 1066 } 1067 6 => { 1068 final_cycle(cpu, bus); 1069 1070 let base_addr = u24_address( 1071 cpu.registers.dbr, 1072 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 1073 ); 1074 let index: u32 = cpu.registers.y.into(); 1075 let address = (base_addr + index) & B::ADDRESS_MASK; 1076 let $value = bus.read(address); 1077 let $registers = &mut cpu.registers; 1078 $body 1079 } 1080 _ => invalid_cycle!(cpu), 1081 } 1082 } 1083 }; 1084} 1085 1086use impl_read_stack_relative_indirect_indexed_u8; 1087 1088macro_rules! impl_read_stack_relative_indirect_indexed_u16 { 1089 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1090 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1091 match cpu.state.cycle { 1092 1 => { 1093 cpu.state.t0 = fetch_operand(cpu, bus); 1094 } 1095 2 => { 1096 // Idle cycle for indexing into stack 1097 bus.idle(); 1098 } 1099 3 => { 1100 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1101 cpu.state.t1 = bus.read(address.into()); 1102 } 1103 4 => { 1104 let address = cpu.registers.s.wrapping_add(cpu.state.t0.into()); 1105 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 1106 } 1107 5 => { 1108 // Idle cycle for indexing with Y 1109 bus.idle(); 1110 } 1111 6 => { 1112 let base_addr = u24_address( 1113 cpu.registers.dbr, 1114 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 1115 ); 1116 let index: u32 = cpu.registers.y.into(); 1117 let address = (base_addr + index) & B::ADDRESS_MASK; 1118 cpu.state.t3 = bus.read(address); 1119 } 1120 7 => { 1121 final_cycle(cpu, bus); 1122 1123 let base_addr = u24_address( 1124 cpu.registers.dbr, 1125 u16::from_le_bytes([cpu.state.t1, cpu.state.t2]), 1126 ); 1127 let index: u32 = cpu.registers.y.into(); 1128 let address = (base_addr + index + 1) & B::ADDRESS_MASK; 1129 let value_msb = bus.read(address); 1130 let $value = u16::from_le_bytes([cpu.state.t3, value_msb]); 1131 let $registers = &mut cpu.registers; 1132 $body 1133 } 1134 _ => invalid_cycle!(cpu), 1135 } 1136 } 1137 }; 1138} 1139 1140use impl_read_stack_relative_indirect_indexed_u16; 1141 1142macro_rules! impl_read_op_u8 { 1143 (@inner immediate, $($rest:tt)*) => { 1144 impl_read_immediate_u8!($($rest)*); 1145 }; 1146 (@inner direct_page, $($rest:tt)*) => { 1147 impl_read_direct_page_u8!($($rest)*); 1148 }; 1149 (@inner direct_page_x, $($rest:tt)*) => { 1150 impl_read_direct_page_indexed_u8!(x, $($rest)*); 1151 }; 1152 (@inner direct_page_y, $($rest:tt)*) => { 1153 impl_read_direct_page_indexed_u8!(y, $($rest)*); 1154 }; 1155 (@inner direct_page_indirect, $($rest:tt)*) => { 1156 impl_read_direct_page_indirect_u8!($($rest)*); 1157 }; 1158 (@inner direct_page_indexed_indirect, $($rest:tt)*) => { 1159 impl_read_direct_page_indexed_indirect_u8!($($rest)*); 1160 }; 1161 (@inner direct_page_indirect_indexed, $($rest:tt)*) => { 1162 impl_read_direct_page_indirect_indexed_u8!($($rest)*); 1163 }; 1164 (@inner direct_page_indirect_long, $($rest:tt)*) => { 1165 impl_read_direct_page_indirect_long_u8!($($rest)*); 1166 }; 1167 (@inner direct_page_indirect_long_indexed, $($rest:tt)*) => { 1168 impl_read_direct_page_indirect_long_indexed_u8!($($rest)*); 1169 }; 1170 (@inner absolute, $($rest:tt)*) => { 1171 impl_read_absolute_u8!($($rest)*); 1172 }; 1173 (@inner absolute_x, $($rest:tt)*) => { 1174 impl_read_absolute_indexed_u8!(x, $($rest)*); 1175 }; 1176 (@inner absolute_y, $($rest:tt)*) => { 1177 impl_read_absolute_indexed_u8!(y, $($rest)*); 1178 }; 1179 (@inner absolute_long, $($rest:tt)*) => { 1180 impl_read_absolute_long_u8!($($rest)*); 1181 }; 1182 (@inner absolute_long_x, $($rest:tt)*) => { 1183 impl_read_absolute_long_indexed_u8!(x, $($rest)*); 1184 }; 1185 (@inner stack_relative, $($rest:tt)*) => { 1186 impl_read_stack_relative_u8!($($rest)*); 1187 }; 1188 (@inner stack_relative_indirect_indexed, $($rest:tt)*) => { 1189 impl_read_stack_relative_indirect_indexed_u8!($($rest)*); 1190 }; 1191 ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => { 1192 $( 1193 impl_read_op_u8!(@inner $am, $name, $rest); 1194 )* 1195 }; 1196} 1197 1198use impl_read_op_u8; 1199 1200macro_rules! impl_read_op_u16 { 1201 (@inner immediate, $($rest:tt)*) => { 1202 impl_read_immediate_u16!($($rest)*); 1203 }; 1204 (@inner direct_page, $($rest:tt)*) => { 1205 impl_read_direct_page_u16!($($rest)*); 1206 }; 1207 (@inner direct_page_x, $($rest:tt)*) => { 1208 impl_read_direct_page_indexed_u16!(x, $($rest)*); 1209 }; 1210 (@inner direct_page_y, $($rest:tt)*) => { 1211 impl_read_direct_page_indexed_u16!(y, $($rest)*); 1212 }; 1213 (@inner direct_page_indirect, $($rest:tt)*) => { 1214 impl_read_direct_page_indirect_u16!($($rest)*); 1215 }; 1216 (@inner direct_page_indexed_indirect, $($rest:tt)*) => { 1217 impl_read_direct_page_indexed_indirect_u16!($($rest)*); 1218 }; 1219 (@inner direct_page_indirect_indexed, $($rest:tt)*) => { 1220 impl_read_direct_page_indirect_indexed_u16!($($rest)*); 1221 }; 1222 (@inner direct_page_indirect_long, $($rest:tt)*) => { 1223 impl_read_direct_page_indirect_long_u16!($($rest)*); 1224 }; 1225 (@inner direct_page_indirect_long_indexed, $($rest:tt)*) => { 1226 impl_read_direct_page_indirect_long_indexed_u16!($($rest)*); 1227 }; 1228 (@inner absolute, $($rest:tt)*) => { 1229 impl_read_absolute_u16!($($rest)*); 1230 }; 1231 (@inner absolute_x, $($rest:tt)*) => { 1232 impl_read_absolute_indexed_u16!(x, $($rest)*); 1233 }; 1234 (@inner absolute_y, $($rest:tt)*) => { 1235 impl_read_absolute_indexed_u16!(y, $($rest)*); 1236 }; 1237 (@inner absolute_long, $($rest:tt)*) => { 1238 impl_read_absolute_long_u16!($($rest)*); 1239 }; 1240 (@inner absolute_long_x, $($rest:tt)*) => { 1241 impl_read_absolute_long_indexed_u16!(x, $($rest)*); 1242 }; 1243 (@inner stack_relative, $($rest:tt)*) => { 1244 impl_read_stack_relative_u16!($($rest)*); 1245 }; 1246 (@inner stack_relative_indirect_indexed, $($rest:tt)*) => { 1247 impl_read_stack_relative_indirect_indexed_u16!($($rest)*); 1248 }; 1249 ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => { 1250 $( 1251 impl_read_op_u16!(@inner $am, $name, $rest); 1252 )* 1253 } 1254} 1255 1256use impl_read_op_u16; 1257 1258macro_rules! impl_modify_accumulator_u8 { 1259 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1260 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1261 final_cycle(cpu, bus); 1262 1263 bus.idle(); 1264 1265 let $value = cpu.registers.a as u8; 1266 let $registers = &mut cpu.registers; 1267 let value = $body; 1268 cpu.registers.a.set_lsb(value); 1269 } 1270 }; 1271} 1272 1273use impl_modify_accumulator_u8; 1274 1275macro_rules! impl_modify_accumulator_u16 { 1276 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1277 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1278 final_cycle(cpu, bus); 1279 1280 bus.idle(); 1281 1282 let $value = cpu.registers.a; 1283 let $registers = &mut cpu.registers; 1284 let value = $body; 1285 cpu.registers.a = value; 1286 } 1287 }; 1288} 1289 1290use impl_modify_accumulator_u16; 1291 1292macro_rules! impl_modify_direct_page_u8 { 1293 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1294 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1295 match cpu.state.cycle { 1296 1 => { 1297 cpu.state.t0 = fetch_operand(cpu, bus); 1298 check_direct_page_low_byte(cpu); 1299 } 1300 2 => { 1301 // Idle cycle if D LSB is non-zero 1302 bus.idle(); 1303 } 1304 3 => { 1305 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1306 cpu.state.t1 = bus.read(address.into()); 1307 } 1308 4 => { 1309 if cpu.registers.emulation_mode { 1310 // Write value back to address 1311 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1312 bus.write(address.into(), cpu.state.t1); 1313 } else { 1314 // Idle cycle for computation 1315 bus.idle(); 1316 } 1317 } 1318 5 => { 1319 final_cycle(cpu, bus); 1320 1321 let $value = cpu.state.t1; 1322 let $registers = &mut cpu.registers; 1323 let value = $body; 1324 1325 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1326 bus.write(address.into(), value); 1327 } 1328 _ => invalid_cycle!(cpu), 1329 } 1330 } 1331 }; 1332} 1333 1334use impl_modify_direct_page_u8; 1335 1336macro_rules! impl_modify_direct_page_u16 { 1337 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1338 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1339 match cpu.state.cycle { 1340 1 => { 1341 cpu.state.t0 = fetch_operand(cpu, bus); 1342 check_direct_page_low_byte(cpu); 1343 } 1344 2 => { 1345 // Idle cycle if D LSB is non-zero 1346 bus.idle(); 1347 } 1348 3 => { 1349 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1350 cpu.state.t1 = bus.read(address.into()); 1351 } 1352 4 => { 1353 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1354 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 1355 } 1356 5 => { 1357 // Idle cycle for computation 1358 bus.idle(); 1359 } 1360 6 => { 1361 let $value = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 1362 let $registers = &mut cpu.registers; 1363 let value = $body; 1364 let [value_lsb, value_msb] = value.to_le_bytes(); 1365 1366 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1367 bus.write(address.wrapping_add(1).into(), value_msb); 1368 cpu.state.t3 = value_lsb; 1369 } 1370 7 => { 1371 final_cycle(cpu, bus); 1372 1373 let address = cpu.registers.d.wrapping_add(cpu.state.t0.into()); 1374 bus.write(address.into(), cpu.state.t3); 1375 } 1376 _ => invalid_cycle!(cpu), 1377 } 1378 } 1379 }; 1380} 1381 1382use impl_modify_direct_page_u16; 1383 1384macro_rules! impl_modify_direct_page_indexed_u8 { 1385 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1386 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1387 match cpu.state.cycle { 1388 1 => { 1389 cpu.state.t0 = fetch_operand(cpu, bus); 1390 check_direct_page_low_byte(cpu); 1391 } 1392 2 => { 1393 // Idle cycle if D LSB is non-zero 1394 bus.idle(); 1395 } 1396 3 => { 1397 // Idle cycle for indexing 1398 bus.idle(); 1399 } 1400 4 => { 1401 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1402 cpu.state.t1 = bus.read(address.into()); 1403 } 1404 5 => { 1405 if cpu.registers.emulation_mode { 1406 // Write value back to address 1407 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1408 bus.write(address.into(), cpu.state.t1); 1409 } else { 1410 // Idle cycle for computation 1411 bus.idle(); 1412 } 1413 } 1414 6 => { 1415 final_cycle(cpu, bus); 1416 1417 let $value = cpu.state.t1; 1418 let $registers = &mut cpu.registers; 1419 let value = $body; 1420 1421 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1422 bus.write(address.into(), value); 1423 } 1424 _ => invalid_cycle!(cpu), 1425 } 1426 } 1427 }; 1428} 1429 1430use impl_modify_direct_page_indexed_u8; 1431 1432macro_rules! impl_modify_direct_page_indexed_u16 { 1433 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1434 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1435 match cpu.state.cycle { 1436 1 => { 1437 cpu.state.t0 = fetch_operand(cpu, bus); 1438 check_direct_page_low_byte(cpu); 1439 } 1440 2 => { 1441 // Idle cycle if D LSB is non-zero 1442 bus.idle(); 1443 } 1444 3 => { 1445 // Idle cycle for indexing 1446 bus.idle(); 1447 } 1448 4 => { 1449 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1450 cpu.state.t1 = bus.read(address.into()); 1451 } 1452 5 => { 1453 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1454 cpu.state.t2 = bus.read(address.wrapping_add(1).into()); 1455 } 1456 6 => { 1457 // Idle cycle for computation 1458 bus.idle(); 1459 } 1460 7 => { 1461 let $value = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 1462 let $registers = &mut cpu.registers; 1463 let value = $body; 1464 let [value_lsb, value_msb] = value.to_le_bytes(); 1465 1466 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1467 bus.write(address.wrapping_add(1).into(), value_msb); 1468 cpu.state.t3 = value_lsb; 1469 } 1470 8 => { 1471 final_cycle(cpu, bus); 1472 1473 let address = index_direct_page(cpu, cpu.state.t0, cpu.registers.$index); 1474 bus.write(address.into(), cpu.state.t3); 1475 } 1476 _ => invalid_cycle!(cpu), 1477 } 1478 } 1479 }; 1480} 1481 1482use impl_modify_direct_page_indexed_u16; 1483 1484macro_rules! impl_modify_absolute_u8 { 1485 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1486 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1487 match cpu.state.cycle { 1488 1 => { 1489 cpu.state.t0 = fetch_operand(cpu, bus); 1490 } 1491 2 => { 1492 cpu.state.t1 = fetch_operand(cpu, bus); 1493 } 1494 3 => { 1495 let address = 1496 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1497 cpu.state.t2 = bus.read(address); 1498 } 1499 4 => { 1500 if cpu.registers.emulation_mode { 1501 // Write back to address 1502 let address = 1503 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1504 bus.write(address, cpu.state.t2); 1505 } else { 1506 // Idle cycle for computation 1507 bus.idle(); 1508 } 1509 } 1510 5 => { 1511 final_cycle(cpu, bus); 1512 1513 let $value = cpu.state.t2; 1514 let $registers = &mut cpu.registers; 1515 let value = $body; 1516 1517 let address = 1518 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1519 bus.write(address, value); 1520 } 1521 _ => invalid_cycle!(cpu), 1522 } 1523 } 1524 }; 1525} 1526 1527use impl_modify_absolute_u8; 1528 1529macro_rules! impl_modify_absolute_u16 { 1530 ($name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1531 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1532 match cpu.state.cycle { 1533 1 => { 1534 cpu.state.t0 = fetch_operand(cpu, bus); 1535 } 1536 2 => { 1537 cpu.state.t1 = fetch_operand(cpu, bus); 1538 } 1539 3 => { 1540 let address = 1541 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1542 cpu.state.t2 = bus.read(address); 1543 } 1544 4 => { 1545 let address = 1546 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1547 cpu.state.t3 = bus.read((address + 1) & B::ADDRESS_MASK); 1548 } 1549 5 => { 1550 // Idle cycle for computation 1551 bus.idle(); 1552 } 1553 6 => { 1554 let $value = u16::from_le_bytes([cpu.state.t2, cpu.state.t3]); 1555 let $registers = &mut cpu.registers; 1556 let value = $body; 1557 let [value_lsb, value_msb] = value.to_le_bytes(); 1558 1559 let address = 1560 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1561 bus.write((address + 1) & B::ADDRESS_MASK, value_msb); 1562 cpu.state.t4 = value_lsb; 1563 } 1564 7 => { 1565 final_cycle(cpu, bus); 1566 1567 let address = 1568 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1569 bus.write(address, cpu.state.t4); 1570 } 1571 _ => invalid_cycle!(cpu), 1572 } 1573 } 1574 }; 1575} 1576 1577use impl_modify_absolute_u16; 1578 1579macro_rules! impl_modify_absolute_indexed_u8 { 1580 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1581 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1582 match cpu.state.cycle { 1583 1 => { 1584 cpu.state.t0 = fetch_operand(cpu, bus); 1585 } 1586 2 => { 1587 cpu.state.t1 = fetch_operand(cpu, bus); 1588 } 1589 3 => { 1590 // Idle cycle for indexing 1591 bus.idle(); 1592 } 1593 4 => { 1594 let base_addr = 1595 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1596 let address = (base_addr + u32::from(cpu.registers.$index)) & B::ADDRESS_MASK; 1597 cpu.state.t2 = bus.read(address); 1598 } 1599 5 => { 1600 if cpu.registers.emulation_mode { 1601 // Write back to address 1602 let base_addr = 1603 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1604 let address = 1605 (base_addr + u32::from(cpu.registers.$index)) & B::ADDRESS_MASK; 1606 bus.write(address, cpu.state.t2); 1607 } else { 1608 // Idle cycle for computation 1609 bus.idle(); 1610 } 1611 } 1612 6 => { 1613 final_cycle(cpu, bus); 1614 1615 let $value = cpu.state.t2; 1616 let $registers = &mut cpu.registers; 1617 let value = $body; 1618 1619 let base_addr = 1620 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1621 let address = (base_addr + u32::from(cpu.registers.$index)) & B::ADDRESS_MASK; 1622 bus.write(address, value); 1623 } 1624 _ => invalid_cycle!(cpu), 1625 } 1626 } 1627 }; 1628} 1629 1630use impl_modify_absolute_indexed_u8; 1631 1632macro_rules! impl_modify_absolute_indexed_u16 { 1633 ($index:ident, $name:ident, (|$registers:ident, $value:ident| $body:block)) => { 1634 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1635 match cpu.state.cycle { 1636 1 => { 1637 cpu.state.t0 = fetch_operand(cpu, bus); 1638 } 1639 2 => { 1640 cpu.state.t1 = fetch_operand(cpu, bus); 1641 } 1642 3 => { 1643 // Idle cycle for indexing 1644 bus.idle(); 1645 } 1646 4 => { 1647 let base_addr = 1648 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1649 let address = (base_addr + u32::from(cpu.registers.$index)) & B::ADDRESS_MASK; 1650 cpu.state.t2 = bus.read(address); 1651 } 1652 5 => { 1653 let base_addr = 1654 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1655 let address = 1656 (base_addr + u32::from(cpu.registers.$index) + 1) & B::ADDRESS_MASK; 1657 cpu.state.t3 = bus.read(address); 1658 } 1659 6 => { 1660 // Idle cycle for computation 1661 bus.idle(); 1662 } 1663 7 => { 1664 let $value = u16::from_le_bytes([cpu.state.t2, cpu.state.t3]); 1665 let $registers = &mut cpu.registers; 1666 let value = $body; 1667 let [value_lsb, value_msb] = value.to_le_bytes(); 1668 1669 let base_addr = 1670 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1671 let address = 1672 (base_addr + u32::from(cpu.registers.$index) + 1) & B::ADDRESS_MASK; 1673 bus.write(address, value_msb); 1674 cpu.state.t4 = value_lsb; 1675 } 1676 8 => { 1677 final_cycle(cpu, bus); 1678 1679 let base_addr = 1680 u32::from_le_bytes([cpu.state.t0, cpu.state.t1, cpu.registers.dbr, 0]); 1681 let address = (base_addr + u32::from(cpu.registers.$index)) & B::ADDRESS_MASK; 1682 bus.write(address, cpu.state.t4); 1683 } 1684 _ => invalid_cycle!(cpu), 1685 } 1686 } 1687 }; 1688} 1689 1690use impl_modify_absolute_indexed_u16; 1691 1692macro_rules! impl_modify_op_u8 { 1693 (@inner accumulator, $($rest:tt)*) => { 1694 impl_modify_accumulator_u8!($($rest)*); 1695 }; 1696 (@inner direct_page, $($rest:tt)*) => { 1697 impl_modify_direct_page_u8!($($rest)*); 1698 }; 1699 (@inner direct_page_x, $($rest:tt)*) => { 1700 impl_modify_direct_page_indexed_u8!(x, $($rest)*); 1701 }; 1702 (@inner absolute, $($rest:tt)*) => { 1703 impl_modify_absolute_u8!($($rest)*); 1704 }; 1705 (@inner absolute_x, $($rest:tt)*) => { 1706 impl_modify_absolute_indexed_u8!(x, $($rest)*); 1707 }; 1708 ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => { 1709 $( 1710 impl_modify_op_u8!(@inner $am, $name, $rest); 1711 )* 1712 } 1713} 1714 1715use impl_modify_op_u8; 1716 1717macro_rules! impl_modify_op_u16 { 1718 (@inner accumulator, $($rest:tt)*) => { 1719 impl_modify_accumulator_u16!($($rest)*); 1720 }; 1721 (@inner direct_page, $($rest:tt)*) => { 1722 impl_modify_direct_page_u16!($($rest)*); 1723 }; 1724 (@inner direct_page_x, $($rest:tt)*) => { 1725 impl_modify_direct_page_indexed_u16!(x, $($rest)*); 1726 }; 1727 (@inner absolute, $($rest:tt)*) => { 1728 impl_modify_absolute_u16!($($rest)*); 1729 }; 1730 (@inner absolute_x, $($rest:tt)*) => { 1731 impl_modify_absolute_indexed_u16!(x, $($rest)*); 1732 }; 1733 ([$($am:tt -> $name:ident),* $(,)?] $rest:tt) => { 1734 $( 1735 impl_modify_op_u16!(@inner $am, $name, $rest); 1736 )* 1737 } 1738} 1739 1740use impl_modify_op_u16; 1741 1742macro_rules! impl_registers_op { 1743 ($name:ident, |$registers:ident| $body:block) => { 1744 pub(crate) fn $name<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1745 final_cycle(cpu, bus); 1746 1747 bus.idle(); 1748 let $registers = &mut cpu.registers; 1749 $body 1750 } 1751 }; 1752} 1753 1754use impl_registers_op; 1755 1756// NOP: No-op 1757impl_registers_op!(nop, |_registers| {}); 1758 1759// WDM: William D. Mensch, Jr. (2-byte no-op) 1760fn wdm<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1761 final_cycle(cpu, bus); 1762 1763 bus.idle(); 1764 1765 cpu.registers.pc = cpu.registers.pc.wrapping_add(1); 1766} 1767 1768pub fn execute<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1769 if cpu.state.cycle != 0 { 1770 // If mid-instruction, continue to execute that instruction 1771 execute_cycle(cpu, bus); 1772 1773 // Increment only if the instruction didn't finish 1774 if cpu.state.cycle != 0 { 1775 cpu.state.cycle += 1; 1776 } 1777 1778 return; 1779 } 1780 1781 // If stopped, the CPU is halted until reset 1782 if cpu.state.stopped { 1783 bus.idle(); 1784 return; 1785 } 1786 1787 // If waiting, the CPU is halted until an NMI or IRQ triggers; check last_irq instead of irq_triggered 1788 // because IRQs will unhalt the CPU even if the I flag is set (though the IRQ won't be handled in that case) 1789 if cpu.state.waiting && !cpu.state.nmi_triggered && !cpu.state.last_irq { 1790 poll_interrupt_lines(cpu, bus); 1791 bus.idle(); 1792 return; 1793 } 1794 cpu.state.waiting = false; 1795 1796 if cpu.state.nmi_triggered { 1797 log::trace!("Handling NMI"); 1798 1799 cpu.state.nmi_triggered = false; 1800 bus.acknowledge_nmi(); 1801 1802 flow::handle_interrupt(cpu, bus, InterruptType::Nmi); 1803 cpu.state.handling_interrupt = Some(InterruptType::Nmi); 1804 cpu.state.cycle = 1; 1805 return; 1806 } 1807 1808 if cpu.state.irq_triggered { 1809 log::trace!("Handling IRQ"); 1810 1811 flow::handle_interrupt(cpu, bus, InterruptType::Irq); 1812 cpu.state.handling_interrupt = Some(InterruptType::Irq); 1813 cpu.state.cycle = 1; 1814 return; 1815 } 1816 1817 // Cycle 0 and not handling an interrupt is always opcode fetch 1818 cpu.state.opcode = fetch_operand(cpu, bus); 1819 cpu.state.cycle = 1; 1820 1821 if log::log_enabled!(log::Level::Trace) { 1822 let instr_name = disassemble::instruction_str(cpu.state.opcode); 1823 log::trace!( 1824 "Fetched opcode from PBR={:02X} / PC={:04X}: {:02X} ({instr_name}); m={}, x={}, e={}, A={:04X}, X={:04X}, Y={:04X}, D={:04X}, S={:04X}, DBR={:02X}", 1825 cpu.registers.pbr, 1826 cpu.registers.pc.wrapping_sub(1), 1827 cpu.state.opcode, 1828 u8::from(cpu.registers.p.accumulator_size == SizeBits::Eight), 1829 u8::from(cpu.registers.p.index_size == SizeBits::Eight), 1830 u8::from(cpu.registers.emulation_mode), 1831 cpu.registers.a, 1832 cpu.registers.x, 1833 cpu.registers.y, 1834 cpu.registers.d, 1835 cpu.registers.s, 1836 cpu.registers.dbr 1837 ); 1838 } 1839} 1840 1841fn execute_cycle<B: BusInterface>(cpu: &mut Wdc65816, bus: &mut B) { 1842 use SizeBits::{Eight, Sixteen}; 1843 1844 if let Some(interrupt) = cpu.state.handling_interrupt { 1845 flow::handle_interrupt(cpu, bus, interrupt); 1846 1847 if cpu.state.cycle == 0 { 1848 cpu.state.handling_interrupt = None; 1849 } 1850 1851 return; 1852 } 1853 1854 match cpu.state.opcode { 1855 0x00 => flow::handle_interrupt(cpu, bus, InterruptType::Breakpoint), 1856 0x01 => match cpu.registers.p.accumulator_size { 1857 Eight => alu::ora_direct_page_indexed_indirect_u8(cpu, bus), 1858 Sixteen => alu::ora_direct_page_indexed_indirect_u16(cpu, bus), 1859 }, 1860 0x02 => flow::handle_interrupt(cpu, bus, InterruptType::Coprocessor), 1861 0x03 => match cpu.registers.p.accumulator_size { 1862 Eight => alu::ora_stack_relative_u8(cpu, bus), 1863 Sixteen => alu::ora_stack_relative_u16(cpu, bus), 1864 }, 1865 0x04 => match cpu.registers.p.accumulator_size { 1866 Eight => bits::tsb_direct_page_u8(cpu, bus), 1867 Sixteen => bits::tsb_direct_page_u16(cpu, bus), 1868 }, 1869 0x05 => match cpu.registers.p.accumulator_size { 1870 Eight => alu::ora_direct_page_u8(cpu, bus), 1871 Sixteen => alu::ora_direct_page_u16(cpu, bus), 1872 }, 1873 0x06 => match cpu.registers.p.accumulator_size { 1874 Eight => bits::asl_direct_page_u8(cpu, bus), 1875 Sixteen => bits::asl_direct_page_u16(cpu, bus), 1876 }, 1877 0x07 => match cpu.registers.p.accumulator_size { 1878 Eight => alu::ora_direct_page_indirect_long_u8(cpu, bus), 1879 Sixteen => alu::ora_direct_page_indirect_long_u16(cpu, bus), 1880 }, 1881 0x08 => load::php(cpu, bus), 1882 0x09 => match cpu.registers.p.accumulator_size { 1883 Eight => alu::ora_immediate_u8(cpu, bus), 1884 Sixteen => alu::ora_immediate_u16(cpu, bus), 1885 }, 1886 0x0A => match cpu.registers.p.accumulator_size { 1887 Eight => bits::asl_accumulator_u8(cpu, bus), 1888 Sixteen => bits::asl_accumulator_u16(cpu, bus), 1889 }, 1890 0x0B => load::phd(cpu, bus), 1891 0x0C => match cpu.registers.p.accumulator_size { 1892 Eight => bits::tsb_absolute_u8(cpu, bus), 1893 Sixteen => bits::tsb_absolute_u16(cpu, bus), 1894 }, 1895 0x0D => match cpu.registers.p.accumulator_size { 1896 Eight => alu::ora_absolute_u8(cpu, bus), 1897 Sixteen => alu::ora_absolute_u16(cpu, bus), 1898 }, 1899 0x0E => match cpu.registers.p.accumulator_size { 1900 Eight => bits::asl_absolute_u8(cpu, bus), 1901 Sixteen => bits::asl_absolute_u16(cpu, bus), 1902 }, 1903 0x0F => match cpu.registers.p.accumulator_size { 1904 Eight => alu::ora_absolute_long_u8(cpu, bus), 1905 Sixteen => alu::ora_absolute_long_u16(cpu, bus), 1906 }, 1907 0x10 => flow::bpl(cpu, bus), 1908 0x11 => match cpu.registers.p.accumulator_size { 1909 Eight => alu::ora_direct_page_indirect_indexed_u8(cpu, bus), 1910 Sixteen => alu::ora_direct_page_indirect_indexed_u16(cpu, bus), 1911 }, 1912 0x12 => match cpu.registers.p.accumulator_size { 1913 Eight => alu::ora_direct_page_indirect_u8(cpu, bus), 1914 Sixteen => alu::ora_direct_page_indirect_u16(cpu, bus), 1915 }, 1916 0x13 => match cpu.registers.p.accumulator_size { 1917 Eight => alu::ora_stack_relative_indirect_indexed_u8(cpu, bus), 1918 Sixteen => alu::ora_stack_relative_indirect_indexed_u16(cpu, bus), 1919 }, 1920 0x14 => match cpu.registers.p.accumulator_size { 1921 Eight => bits::trb_direct_page_u8(cpu, bus), 1922 Sixteen => bits::trb_direct_page_u16(cpu, bus), 1923 }, 1924 0x15 => match cpu.registers.p.accumulator_size { 1925 Eight => alu::ora_direct_page_x_u8(cpu, bus), 1926 Sixteen => alu::ora_direct_page_x_u16(cpu, bus), 1927 }, 1928 0x16 => match cpu.registers.p.accumulator_size { 1929 Eight => bits::asl_direct_page_x_u8(cpu, bus), 1930 Sixteen => bits::asl_direct_page_x_u16(cpu, bus), 1931 }, 1932 0x17 => match cpu.registers.p.accumulator_size { 1933 Eight => alu::ora_direct_page_indirect_long_indexed_u8(cpu, bus), 1934 Sixteen => alu::ora_direct_page_indirect_long_indexed_u16(cpu, bus), 1935 }, 1936 0x18 => flags::clc(cpu, bus), 1937 0x19 => match cpu.registers.p.accumulator_size { 1938 Eight => alu::ora_absolute_y_u8(cpu, bus), 1939 Sixteen => alu::ora_absolute_y_u16(cpu, bus), 1940 }, 1941 0x1A => match cpu.registers.p.accumulator_size { 1942 Eight => alu::inc_accumulator_u8(cpu, bus), 1943 Sixteen => alu::inc_accumulator_u16(cpu, bus), 1944 }, 1945 0x1B => load::tcs(cpu, bus), 1946 0x1C => match cpu.registers.p.accumulator_size { 1947 Eight => bits::trb_absolute_u8(cpu, bus), 1948 Sixteen => bits::trb_absolute_u16(cpu, bus), 1949 }, 1950 0x1D => match cpu.registers.p.accumulator_size { 1951 Eight => alu::ora_absolute_x_u8(cpu, bus), 1952 Sixteen => alu::ora_absolute_x_u16(cpu, bus), 1953 }, 1954 0x1E => match cpu.registers.p.accumulator_size { 1955 Eight => bits::asl_absolute_x_u8(cpu, bus), 1956 Sixteen => bits::asl_absolute_x_u16(cpu, bus), 1957 }, 1958 0x1F => match cpu.registers.p.accumulator_size { 1959 Eight => alu::ora_absolute_long_x_u8(cpu, bus), 1960 Sixteen => alu::ora_absolute_long_x_u16(cpu, bus), 1961 }, 1962 0x20 => flow::jsr_absolute(cpu, bus), 1963 0x21 => match cpu.registers.p.accumulator_size { 1964 Eight => alu::and_direct_page_indexed_indirect_u8(cpu, bus), 1965 Sixteen => alu::and_direct_page_indexed_indirect_u16(cpu, bus), 1966 }, 1967 0x22 => flow::jsl(cpu, bus), 1968 0x23 => match cpu.registers.p.accumulator_size { 1969 Eight => alu::and_stack_relative_u8(cpu, bus), 1970 Sixteen => alu::and_stack_relative_u16(cpu, bus), 1971 }, 1972 0x24 => match cpu.registers.p.accumulator_size { 1973 Eight => bits::bit_direct_page_u8(cpu, bus), 1974 Sixteen => bits::bit_direct_page_u16(cpu, bus), 1975 }, 1976 0x25 => match cpu.registers.p.accumulator_size { 1977 Eight => alu::and_direct_page_u8(cpu, bus), 1978 Sixteen => alu::and_direct_page_u16(cpu, bus), 1979 }, 1980 0x26 => match cpu.registers.p.accumulator_size { 1981 Eight => bits::rol_direct_page_u8(cpu, bus), 1982 Sixteen => bits::rol_direct_page_u16(cpu, bus), 1983 }, 1984 0x27 => match cpu.registers.p.accumulator_size { 1985 Eight => alu::and_direct_page_indirect_long_u8(cpu, bus), 1986 Sixteen => alu::and_direct_page_indirect_long_u16(cpu, bus), 1987 }, 1988 0x28 => load::plp(cpu, bus), 1989 0x29 => match cpu.registers.p.accumulator_size { 1990 Eight => alu::and_immediate_u8(cpu, bus), 1991 Sixteen => alu::and_immediate_u16(cpu, bus), 1992 }, 1993 0x2A => match cpu.registers.p.accumulator_size { 1994 Eight => bits::rol_accumulator_u8(cpu, bus), 1995 Sixteen => bits::rol_accumulator_u16(cpu, bus), 1996 }, 1997 0x2B => load::pld(cpu, bus), 1998 0x2C => match cpu.registers.p.accumulator_size { 1999 Eight => bits::bit_absolute_u8(cpu, bus), 2000 Sixteen => bits::bit_absolute_u16(cpu, bus), 2001 }, 2002 0x2D => match cpu.registers.p.accumulator_size { 2003 Eight => alu::and_absolute_u8(cpu, bus), 2004 Sixteen => alu::and_absolute_u16(cpu, bus), 2005 }, 2006 0x2E => match cpu.registers.p.accumulator_size { 2007 Eight => bits::rol_absolute_u8(cpu, bus), 2008 Sixteen => bits::rol_absolute_u16(cpu, bus), 2009 }, 2010 0x2F => match cpu.registers.p.accumulator_size { 2011 Eight => alu::and_absolute_long_u8(cpu, bus), 2012 Sixteen => alu::and_absolute_long_u16(cpu, bus), 2013 }, 2014 0x30 => flow::bmi(cpu, bus), 2015 0x31 => match cpu.registers.p.accumulator_size { 2016 Eight => alu::and_direct_page_indirect_indexed_u8(cpu, bus), 2017 Sixteen => alu::and_direct_page_indirect_indexed_u16(cpu, bus), 2018 }, 2019 0x32 => match cpu.registers.p.accumulator_size { 2020 Eight => alu::and_direct_page_indirect_u8(cpu, bus), 2021 Sixteen => alu::and_direct_page_indirect_u16(cpu, bus), 2022 }, 2023 0x33 => match cpu.registers.p.accumulator_size { 2024 Eight => alu::and_stack_relative_indirect_indexed_u8(cpu, bus), 2025 Sixteen => alu::and_stack_relative_indirect_indexed_u16(cpu, bus), 2026 }, 2027 0x34 => match cpu.registers.p.accumulator_size { 2028 Eight => bits::bit_direct_page_x_u8(cpu, bus), 2029 Sixteen => bits::bit_direct_page_x_u16(cpu, bus), 2030 }, 2031 0x35 => match cpu.registers.p.accumulator_size { 2032 Eight => alu::and_direct_page_x_u8(cpu, bus), 2033 Sixteen => alu::and_direct_page_x_u16(cpu, bus), 2034 }, 2035 0x36 => match cpu.registers.p.accumulator_size { 2036 Eight => bits::rol_direct_page_x_u8(cpu, bus), 2037 Sixteen => bits::rol_direct_page_x_u16(cpu, bus), 2038 }, 2039 0x37 => match cpu.registers.p.accumulator_size { 2040 Eight => alu::and_direct_page_indirect_long_indexed_u8(cpu, bus), 2041 Sixteen => alu::and_direct_page_indirect_long_indexed_u16(cpu, bus), 2042 }, 2043 0x38 => flags::sec(cpu, bus), 2044 0x39 => match cpu.registers.p.accumulator_size { 2045 Eight => alu::and_absolute_y_u8(cpu, bus), 2046 Sixteen => alu::and_absolute_y_u16(cpu, bus), 2047 }, 2048 0x3A => match cpu.registers.p.accumulator_size { 2049 Eight => alu::dec_accumulator_u8(cpu, bus), 2050 Sixteen => alu::dec_accumulator_u16(cpu, bus), 2051 }, 2052 0x3B => load::tsc(cpu, bus), 2053 0x3C => match cpu.registers.p.accumulator_size { 2054 Eight => bits::bit_absolute_x_u8(cpu, bus), 2055 Sixteen => bits::bit_absolute_x_u16(cpu, bus), 2056 }, 2057 0x3D => match cpu.registers.p.accumulator_size { 2058 Eight => alu::and_absolute_x_u8(cpu, bus), 2059 Sixteen => alu::and_absolute_x_u16(cpu, bus), 2060 }, 2061 0x3E => match cpu.registers.p.accumulator_size { 2062 Eight => bits::rol_absolute_x_u8(cpu, bus), 2063 Sixteen => bits::rol_absolute_x_u16(cpu, bus), 2064 }, 2065 0x3F => match cpu.registers.p.accumulator_size { 2066 Eight => alu::and_absolute_long_x_u8(cpu, bus), 2067 Sixteen => alu::and_absolute_long_x_u16(cpu, bus), 2068 }, 2069 0x40 => flow::rti(cpu, bus), 2070 0x41 => match cpu.registers.p.accumulator_size { 2071 Eight => alu::eor_direct_page_indexed_indirect_u8(cpu, bus), 2072 Sixteen => alu::eor_direct_page_indexed_indirect_u16(cpu, bus), 2073 }, 2074 0x42 => wdm(cpu, bus), 2075 0x43 => match cpu.registers.p.accumulator_size { 2076 Eight => alu::eor_stack_relative_u8(cpu, bus), 2077 Sixteen => alu::eor_stack_relative_u16(cpu, bus), 2078 }, 2079 0x44 => load::mvp(cpu, bus), 2080 0x45 => match cpu.registers.p.accumulator_size { 2081 Eight => alu::eor_direct_page_u8(cpu, bus), 2082 Sixteen => alu::eor_direct_page_u16(cpu, bus), 2083 }, 2084 0x46 => match cpu.registers.p.accumulator_size { 2085 Eight => bits::lsr_direct_page_u8(cpu, bus), 2086 Sixteen => bits::lsr_direct_page_u16(cpu, bus), 2087 }, 2088 0x47 => match cpu.registers.p.accumulator_size { 2089 Eight => alu::eor_direct_page_indirect_long_u8(cpu, bus), 2090 Sixteen => alu::eor_direct_page_indirect_long_u16(cpu, bus), 2091 }, 2092 0x48 => match cpu.registers.p.accumulator_size { 2093 Eight => load::pha_u8(cpu, bus), 2094 Sixteen => load::pha_u16(cpu, bus), 2095 }, 2096 0x49 => match cpu.registers.p.accumulator_size { 2097 Eight => alu::eor_immediate_u8(cpu, bus), 2098 Sixteen => alu::eor_immediate_u16(cpu, bus), 2099 }, 2100 0x4A => match cpu.registers.p.accumulator_size { 2101 Eight => bits::lsr_accumulator_u8(cpu, bus), 2102 Sixteen => bits::lsr_accumulator_u16(cpu, bus), 2103 }, 2104 0x4B => load::phk(cpu, bus), 2105 0x4C => flow::jmp_absolute(cpu, bus), 2106 0x4D => match cpu.registers.p.accumulator_size { 2107 Eight => alu::eor_absolute_u8(cpu, bus), 2108 Sixteen => alu::eor_absolute_u16(cpu, bus), 2109 }, 2110 0x4E => match cpu.registers.p.accumulator_size { 2111 Eight => bits::lsr_absolute_u8(cpu, bus), 2112 Sixteen => bits::lsr_absolute_u16(cpu, bus), 2113 }, 2114 0x4F => match cpu.registers.p.accumulator_size { 2115 Eight => alu::eor_absolute_long_u8(cpu, bus), 2116 Sixteen => alu::eor_absolute_long_u16(cpu, bus), 2117 }, 2118 0x50 => flow::bvc(cpu, bus), 2119 0x51 => match cpu.registers.p.accumulator_size { 2120 Eight => alu::eor_direct_page_indirect_indexed_u8(cpu, bus), 2121 Sixteen => alu::eor_direct_page_indirect_indexed_u16(cpu, bus), 2122 }, 2123 0x52 => match cpu.registers.p.accumulator_size { 2124 Eight => alu::eor_direct_page_indirect_u8(cpu, bus), 2125 Sixteen => alu::eor_direct_page_indirect_u16(cpu, bus), 2126 }, 2127 0x53 => match cpu.registers.p.accumulator_size { 2128 Eight => alu::eor_stack_relative_indirect_indexed_u8(cpu, bus), 2129 Sixteen => alu::eor_stack_relative_indirect_indexed_u16(cpu, bus), 2130 }, 2131 0x54 => load::mvn(cpu, bus), 2132 0x55 => match cpu.registers.p.accumulator_size { 2133 Eight => alu::eor_direct_page_x_u8(cpu, bus), 2134 Sixteen => alu::eor_direct_page_x_u16(cpu, bus), 2135 }, 2136 0x56 => match cpu.registers.p.accumulator_size { 2137 Eight => bits::lsr_direct_page_x_u8(cpu, bus), 2138 Sixteen => bits::lsr_direct_page_x_u16(cpu, bus), 2139 }, 2140 0x57 => match cpu.registers.p.accumulator_size { 2141 Eight => alu::eor_direct_page_indirect_long_indexed_u8(cpu, bus), 2142 Sixteen => alu::eor_direct_page_indirect_long_indexed_u16(cpu, bus), 2143 }, 2144 0x58 => flags::cli(cpu, bus), 2145 0x59 => match cpu.registers.p.accumulator_size { 2146 Eight => alu::eor_absolute_y_u8(cpu, bus), 2147 Sixteen => alu::eor_absolute_y_u16(cpu, bus), 2148 }, 2149 0x5A => match cpu.registers.p.index_size { 2150 Eight => load::phy_u8(cpu, bus), 2151 Sixteen => load::phy_u16(cpu, bus), 2152 }, 2153 0x5B => load::tcd(cpu, bus), 2154 0x5C => flow::jmp_absolute_long(cpu, bus), 2155 0x5D => match cpu.registers.p.accumulator_size { 2156 Eight => alu::eor_absolute_x_u8(cpu, bus), 2157 Sixteen => alu::eor_absolute_x_u16(cpu, bus), 2158 }, 2159 0x5E => match cpu.registers.p.accumulator_size { 2160 Eight => bits::lsr_absolute_x_u8(cpu, bus), 2161 Sixteen => bits::lsr_absolute_x_u16(cpu, bus), 2162 }, 2163 0x5F => match cpu.registers.p.accumulator_size { 2164 Eight => alu::eor_absolute_long_x_u8(cpu, bus), 2165 Sixteen => alu::eor_absolute_long_x_u16(cpu, bus), 2166 }, 2167 0x60 => flow::rts(cpu, bus), 2168 0x61 => match cpu.registers.p.accumulator_size { 2169 Eight => alu::adc_direct_page_indexed_indirect_u8(cpu, bus), 2170 Sixteen => alu::adc_direct_page_indexed_indirect_u16(cpu, bus), 2171 }, 2172 0x62 => flow::per(cpu, bus), 2173 0x63 => match cpu.registers.p.accumulator_size { 2174 Eight => alu::adc_stack_relative_u8(cpu, bus), 2175 Sixteen => alu::adc_stack_relative_u16(cpu, bus), 2176 }, 2177 0x64 => match cpu.registers.p.accumulator_size { 2178 Eight => load::stz_direct_page_u8(cpu, bus), 2179 Sixteen => load::stz_direct_page_u16(cpu, bus), 2180 }, 2181 0x65 => match cpu.registers.p.accumulator_size { 2182 Eight => alu::adc_direct_page_u8(cpu, bus), 2183 Sixteen => alu::adc_direct_page_u16(cpu, bus), 2184 }, 2185 0x66 => match cpu.registers.p.accumulator_size { 2186 Eight => bits::ror_direct_page_u8(cpu, bus), 2187 Sixteen => bits::ror_direct_page_u16(cpu, bus), 2188 }, 2189 0x67 => match cpu.registers.p.accumulator_size { 2190 Eight => alu::adc_direct_page_indirect_long_u8(cpu, bus), 2191 Sixteen => alu::adc_direct_page_indirect_long_u16(cpu, bus), 2192 }, 2193 0x68 => match cpu.registers.p.accumulator_size { 2194 Eight => load::pla_u8(cpu, bus), 2195 Sixteen => load::pla_u16(cpu, bus), 2196 }, 2197 0x69 => match cpu.registers.p.accumulator_size { 2198 Eight => alu::adc_immediate_u8(cpu, bus), 2199 Sixteen => alu::adc_immediate_u16(cpu, bus), 2200 }, 2201 0x6A => match cpu.registers.p.accumulator_size { 2202 Eight => bits::ror_accumulator_u8(cpu, bus), 2203 Sixteen => bits::ror_accumulator_u16(cpu, bus), 2204 }, 2205 0x6B => flow::rtl(cpu, bus), 2206 0x6C => flow::jmp_indirect(cpu, bus), 2207 0x6D => match cpu.registers.p.accumulator_size { 2208 Eight => alu::adc_absolute_u8(cpu, bus), 2209 Sixteen => alu::adc_absolute_u16(cpu, bus), 2210 }, 2211 0x6E => match cpu.registers.p.accumulator_size { 2212 Eight => bits::ror_absolute_u8(cpu, bus), 2213 Sixteen => bits::ror_absolute_u16(cpu, bus), 2214 }, 2215 0x6F => match cpu.registers.p.accumulator_size { 2216 Eight => alu::adc_absolute_long_u8(cpu, bus), 2217 Sixteen => alu::adc_absolute_long_u16(cpu, bus), 2218 }, 2219 0x70 => flow::bvs(cpu, bus), 2220 0x71 => match cpu.registers.p.accumulator_size { 2221 Eight => alu::adc_direct_page_indirect_indexed_u8(cpu, bus), 2222 Sixteen => alu::adc_direct_page_indirect_indexed_u16(cpu, bus), 2223 }, 2224 0x72 => match cpu.registers.p.accumulator_size { 2225 Eight => alu::adc_direct_page_indirect_u8(cpu, bus), 2226 Sixteen => alu::adc_direct_page_indirect_u16(cpu, bus), 2227 }, 2228 0x73 => match cpu.registers.p.accumulator_size { 2229 Eight => alu::adc_stack_relative_indirect_indexed_u8(cpu, bus), 2230 Sixteen => alu::adc_stack_relative_indirect_indexed_u16(cpu, bus), 2231 }, 2232 0x74 => match cpu.registers.p.accumulator_size { 2233 Eight => load::stz_direct_page_x_u8(cpu, bus), 2234 Sixteen => load::stz_direct_page_x_u16(cpu, bus), 2235 }, 2236 0x75 => match cpu.registers.p.accumulator_size { 2237 Eight => alu::adc_direct_page_x_u8(cpu, bus), 2238 Sixteen => alu::adc_direct_page_x_u16(cpu, bus), 2239 }, 2240 0x76 => match cpu.registers.p.accumulator_size { 2241 Eight => bits::ror_direct_page_x_u8(cpu, bus), 2242 Sixteen => bits::ror_direct_page_x_u16(cpu, bus), 2243 }, 2244 0x77 => match cpu.registers.p.accumulator_size { 2245 Eight => alu::adc_direct_page_indirect_long_indexed_u8(cpu, bus), 2246 Sixteen => alu::adc_direct_page_indirect_long_indexed_u16(cpu, bus), 2247 }, 2248 0x78 => flags::sei(cpu, bus), 2249 0x79 => match cpu.registers.p.accumulator_size { 2250 Eight => alu::adc_absolute_y_u8(cpu, bus), 2251 Sixteen => alu::adc_absolute_y_u16(cpu, bus), 2252 }, 2253 0x7A => match cpu.registers.p.index_size { 2254 Eight => load::ply_u8(cpu, bus), 2255 Sixteen => load::ply_u16(cpu, bus), 2256 }, 2257 0x7B => load::tdc(cpu, bus), 2258 0x7C => flow::jmp_indexed_indirect(cpu, bus), 2259 0x7D => match cpu.registers.p.accumulator_size { 2260 Eight => alu::adc_absolute_x_u8(cpu, bus), 2261 Sixteen => alu::adc_absolute_x_u16(cpu, bus), 2262 }, 2263 0x7E => match cpu.registers.p.accumulator_size { 2264 Eight => bits::ror_absolute_x_u8(cpu, bus), 2265 Sixteen => bits::ror_absolute_x_u16(cpu, bus), 2266 }, 2267 0x7F => match cpu.registers.p.accumulator_size { 2268 Eight => alu::adc_absolute_long_x_u8(cpu, bus), 2269 Sixteen => alu::adc_absolute_long_x_u16(cpu, bus), 2270 }, 2271 0x80 => flow::bra(cpu, bus), 2272 0x81 => match cpu.registers.p.accumulator_size { 2273 Eight => load::sta_direct_page_indexed_indirect_u8(cpu, bus), 2274 Sixteen => load::sta_direct_page_indexed_indirect_u16(cpu, bus), 2275 }, 2276 0x82 => flow::brl(cpu, bus), 2277 0x83 => match cpu.registers.p.accumulator_size { 2278 Eight => load::sta_stack_relative_u8(cpu, bus), 2279 Sixteen => load::sta_stack_relative_u16(cpu, bus), 2280 }, 2281 0x84 => match cpu.registers.p.index_size { 2282 Eight => load::sty_direct_page_u8(cpu, bus), 2283 Sixteen => load::sty_direct_page_u16(cpu, bus), 2284 }, 2285 0x85 => match cpu.registers.p.accumulator_size { 2286 Eight => load::sta_direct_page_u8(cpu, bus), 2287 Sixteen => load::sta_direct_page_u16(cpu, bus), 2288 }, 2289 0x86 => match cpu.registers.p.index_size { 2290 Eight => load::stx_direct_page_u8(cpu, bus), 2291 Sixteen => load::stx_direct_page_u16(cpu, bus), 2292 }, 2293 0x87 => match cpu.registers.p.accumulator_size { 2294 Eight => load::sta_direct_page_indirect_long_u8(cpu, bus), 2295 Sixteen => load::sta_direct_page_indirect_long_u16(cpu, bus), 2296 }, 2297 0x88 => match cpu.registers.p.index_size { 2298 Eight => alu::dey_u8(cpu, bus), 2299 Sixteen => alu::dey_u16(cpu, bus), 2300 }, 2301 0x89 => match cpu.registers.p.accumulator_size { 2302 Eight => bits::bit_immediate_u8(cpu, bus), 2303 Sixteen => bits::bit_immediate_u16(cpu, bus), 2304 }, 2305 0x8A => match cpu.registers.p.accumulator_size { 2306 Eight => load::txa_u8(cpu, bus), 2307 Sixteen => load::txa_u16(cpu, bus), 2308 }, 2309 0x8B => load::phb(cpu, bus), 2310 0x8C => match cpu.registers.p.index_size { 2311 Eight => load::sty_absolute_u8(cpu, bus), 2312 Sixteen => load::sty_absolute_u16(cpu, bus), 2313 }, 2314 0x8D => match cpu.registers.p.accumulator_size { 2315 Eight => load::sta_absolute_u8(cpu, bus), 2316 Sixteen => load::sta_absolute_u16(cpu, bus), 2317 }, 2318 0x8E => match cpu.registers.p.index_size { 2319 Eight => load::stx_absolute_u8(cpu, bus), 2320 Sixteen => load::stx_absolute_u16(cpu, bus), 2321 }, 2322 0x8F => match cpu.registers.p.accumulator_size { 2323 Eight => load::sta_absolute_long_u8(cpu, bus), 2324 Sixteen => load::sta_absolute_long_u16(cpu, bus), 2325 }, 2326 0x90 => flow::bcc(cpu, bus), 2327 0x91 => match cpu.registers.p.accumulator_size { 2328 Eight => load::sta_direct_page_indirect_indexed_u8(cpu, bus), 2329 Sixteen => load::sta_direct_page_indirect_indexed_u16(cpu, bus), 2330 }, 2331 0x92 => match cpu.registers.p.accumulator_size { 2332 Eight => load::sta_direct_page_indirect_u8(cpu, bus), 2333 Sixteen => load::sta_direct_page_indirect_u16(cpu, bus), 2334 }, 2335 0x93 => match cpu.registers.p.accumulator_size { 2336 Eight => load::sta_stack_relative_indirect_indexed_u8(cpu, bus), 2337 Sixteen => load::sta_stack_relative_indirect_indexed_u16(cpu, bus), 2338 }, 2339 0x94 => match cpu.registers.p.index_size { 2340 Eight => load::sty_direct_page_x_u8(cpu, bus), 2341 Sixteen => load::sty_direct_page_x_u16(cpu, bus), 2342 }, 2343 0x95 => match cpu.registers.p.accumulator_size { 2344 Eight => load::sta_direct_page_x_u8(cpu, bus), 2345 Sixteen => load::sta_direct_page_x_u16(cpu, bus), 2346 }, 2347 0x96 => match cpu.registers.p.index_size { 2348 Eight => load::stx_direct_page_y_u8(cpu, bus), 2349 Sixteen => load::stx_direct_page_y_u16(cpu, bus), 2350 }, 2351 0x97 => match cpu.registers.p.accumulator_size { 2352 Eight => load::sta_direct_page_indirect_long_indexed_u8(cpu, bus), 2353 Sixteen => load::sta_direct_page_indirect_long_indexed_u16(cpu, bus), 2354 }, 2355 0x98 => match cpu.registers.p.accumulator_size { 2356 Eight => load::tya_u8(cpu, bus), 2357 Sixteen => load::tya_u16(cpu, bus), 2358 }, 2359 0x99 => match cpu.registers.p.accumulator_size { 2360 Eight => load::sta_absolute_y_u8(cpu, bus), 2361 Sixteen => load::sta_absolute_y_u16(cpu, bus), 2362 }, 2363 0x9A => load::txs(cpu, bus), 2364 0x9B => match cpu.registers.p.index_size { 2365 Eight => load::txy_u8(cpu, bus), 2366 Sixteen => load::txy_u16(cpu, bus), 2367 }, 2368 0x9C => match cpu.registers.p.accumulator_size { 2369 Eight => load::stz_absolute_u8(cpu, bus), 2370 Sixteen => load::stz_absolute_u16(cpu, bus), 2371 }, 2372 0x9D => match cpu.registers.p.accumulator_size { 2373 Eight => load::sta_absolute_x_u8(cpu, bus), 2374 Sixteen => load::sta_absolute_x_u16(cpu, bus), 2375 }, 2376 0x9E => match cpu.registers.p.accumulator_size { 2377 Eight => load::stz_absolute_x_u8(cpu, bus), 2378 Sixteen => load::stz_absolute_x_u16(cpu, bus), 2379 }, 2380 0x9F => match cpu.registers.p.accumulator_size { 2381 Eight => load::sta_absolute_long_x_u8(cpu, bus), 2382 Sixteen => load::sta_absolute_long_x_u16(cpu, bus), 2383 }, 2384 0xA0 => match cpu.registers.p.index_size { 2385 Eight => load::ldy_immediate_u8(cpu, bus), 2386 Sixteen => load::ldy_immediate_u16(cpu, bus), 2387 }, 2388 0xA1 => match cpu.registers.p.accumulator_size { 2389 Eight => load::lda_direct_page_indexed_indirect_u8(cpu, bus), 2390 Sixteen => load::lda_direct_page_indexed_indirect_u16(cpu, bus), 2391 }, 2392 0xA2 => match cpu.registers.p.index_size { 2393 Eight => load::ldx_immediate_u8(cpu, bus), 2394 Sixteen => load::ldx_immediate_u16(cpu, bus), 2395 }, 2396 0xA3 => match cpu.registers.p.accumulator_size { 2397 Eight => load::lda_stack_relative_u8(cpu, bus), 2398 Sixteen => load::lda_stack_relative_u16(cpu, bus), 2399 }, 2400 0xA4 => match cpu.registers.p.index_size { 2401 Eight => load::ldy_direct_page_u8(cpu, bus), 2402 Sixteen => load::ldy_direct_page_u16(cpu, bus), 2403 }, 2404 0xA5 => match cpu.registers.p.accumulator_size { 2405 Eight => load::lda_direct_page_u8(cpu, bus), 2406 Sixteen => load::lda_direct_page_u16(cpu, bus), 2407 }, 2408 0xA6 => match cpu.registers.p.index_size { 2409 Eight => load::ldx_direct_page_u8(cpu, bus), 2410 Sixteen => load::ldx_direct_page_u16(cpu, bus), 2411 }, 2412 0xA7 => match cpu.registers.p.accumulator_size { 2413 Eight => load::lda_direct_page_indirect_long_u8(cpu, bus), 2414 Sixteen => load::lda_direct_page_indirect_long_u16(cpu, bus), 2415 }, 2416 0xA8 => match cpu.registers.p.index_size { 2417 Eight => load::tay_u8(cpu, bus), 2418 Sixteen => load::tay_u16(cpu, bus), 2419 }, 2420 0xA9 => match cpu.registers.p.accumulator_size { 2421 Eight => load::lda_immediate_u8(cpu, bus), 2422 Sixteen => load::lda_immediate_u16(cpu, bus), 2423 }, 2424 0xAA => match cpu.registers.p.index_size { 2425 Eight => load::tax_u8(cpu, bus), 2426 Sixteen => load::tax_u16(cpu, bus), 2427 }, 2428 0xAB => load::plb(cpu, bus), 2429 0xAC => match cpu.registers.p.index_size { 2430 Eight => load::ldy_absolute_u8(cpu, bus), 2431 Sixteen => load::ldy_absolute_u16(cpu, bus), 2432 }, 2433 0xAD => match cpu.registers.p.accumulator_size { 2434 Eight => load::lda_absolute_u8(cpu, bus), 2435 Sixteen => load::lda_absolute_u16(cpu, bus), 2436 }, 2437 0xAE => match cpu.registers.p.index_size { 2438 Eight => load::ldx_absolute_u8(cpu, bus), 2439 Sixteen => load::ldx_absolute_u16(cpu, bus), 2440 }, 2441 0xAF => match cpu.registers.p.accumulator_size { 2442 Eight => load::lda_absolute_long_u8(cpu, bus), 2443 Sixteen => load::lda_absolute_long_u16(cpu, bus), 2444 }, 2445 0xB0 => flow::bcs(cpu, bus), 2446 0xB1 => match cpu.registers.p.accumulator_size { 2447 Eight => load::lda_direct_page_indirect_indexed_u8(cpu, bus), 2448 Sixteen => load::lda_direct_page_indirect_indexed_u16(cpu, bus), 2449 }, 2450 0xB2 => match cpu.registers.p.accumulator_size { 2451 Eight => load::lda_direct_page_indirect_u8(cpu, bus), 2452 Sixteen => load::lda_direct_page_indirect_u16(cpu, bus), 2453 }, 2454 0xB3 => match cpu.registers.p.accumulator_size { 2455 Eight => load::lda_stack_relative_indirect_indexed_u8(cpu, bus), 2456 Sixteen => load::lda_stack_relative_indirect_indexed_u16(cpu, bus), 2457 }, 2458 0xB4 => match cpu.registers.p.index_size { 2459 Eight => load::ldy_direct_page_x_u8(cpu, bus), 2460 Sixteen => load::ldy_direct_page_x_u16(cpu, bus), 2461 }, 2462 0xB5 => match cpu.registers.p.accumulator_size { 2463 Eight => load::lda_direct_page_x_u8(cpu, bus), 2464 Sixteen => load::lda_direct_page_x_u16(cpu, bus), 2465 }, 2466 0xB6 => match cpu.registers.p.index_size { 2467 Eight => load::ldx_direct_page_y_u8(cpu, bus), 2468 Sixteen => load::ldx_direct_page_y_u16(cpu, bus), 2469 }, 2470 0xB7 => match cpu.registers.p.accumulator_size { 2471 Eight => load::lda_direct_page_indirect_long_indexed_u8(cpu, bus), 2472 Sixteen => load::lda_direct_page_indirect_long_indexed_u16(cpu, bus), 2473 }, 2474 0xB8 => flags::clv(cpu, bus), 2475 0xB9 => match cpu.registers.p.accumulator_size { 2476 Eight => load::lda_absolute_y_u8(cpu, bus), 2477 Sixteen => load::lda_absolute_y_u16(cpu, bus), 2478 }, 2479 0xBA => match cpu.registers.p.index_size { 2480 Eight => load::tsx_u8(cpu, bus), 2481 Sixteen => load::tsx_u16(cpu, bus), 2482 }, 2483 0xBB => match cpu.registers.p.index_size { 2484 Eight => load::tyx_u8(cpu, bus), 2485 Sixteen => load::tyx_u16(cpu, bus), 2486 }, 2487 0xBC => match cpu.registers.p.index_size { 2488 Eight => load::ldy_absolute_x_u8(cpu, bus), 2489 Sixteen => load::ldy_absolute_x_u16(cpu, bus), 2490 }, 2491 0xBD => match cpu.registers.p.accumulator_size { 2492 Eight => load::lda_absolute_x_u8(cpu, bus), 2493 Sixteen => load::lda_absolute_x_u16(cpu, bus), 2494 }, 2495 0xBE => match cpu.registers.p.index_size { 2496 Eight => load::ldx_absolute_y_u8(cpu, bus), 2497 Sixteen => load::ldx_absolute_y_u16(cpu, bus), 2498 }, 2499 0xBF => match cpu.registers.p.accumulator_size { 2500 Eight => load::lda_absolute_long_x_u8(cpu, bus), 2501 Sixteen => load::lda_absolute_long_x_u16(cpu, bus), 2502 }, 2503 0xC0 => match cpu.registers.p.index_size { 2504 Eight => alu::cpy_immediate_u8(cpu, bus), 2505 Sixteen => alu::cpy_immediate_u16(cpu, bus), 2506 }, 2507 0xC1 => match cpu.registers.p.accumulator_size { 2508 Eight => alu::cmp_direct_page_indexed_indirect_u8(cpu, bus), 2509 Sixteen => alu::cmp_direct_page_indexed_indirect_u16(cpu, bus), 2510 }, 2511 0xC2 => flags::rep(cpu, bus), 2512 0xC3 => match cpu.registers.p.accumulator_size { 2513 Eight => alu::cmp_stack_relative_u8(cpu, bus), 2514 Sixteen => alu::cmp_stack_relative_u16(cpu, bus), 2515 }, 2516 0xC4 => match cpu.registers.p.index_size { 2517 Eight => alu::cpy_direct_page_u8(cpu, bus), 2518 Sixteen => alu::cpy_direct_page_u16(cpu, bus), 2519 }, 2520 0xC5 => match cpu.registers.p.accumulator_size { 2521 Eight => alu::cmp_direct_page_u8(cpu, bus), 2522 Sixteen => alu::cmp_direct_page_u16(cpu, bus), 2523 }, 2524 0xC6 => match cpu.registers.p.accumulator_size { 2525 Eight => alu::dec_direct_page_u8(cpu, bus), 2526 Sixteen => alu::dec_direct_page_u16(cpu, bus), 2527 }, 2528 0xC7 => match cpu.registers.p.accumulator_size { 2529 Eight => alu::cmp_direct_page_indirect_long_u8(cpu, bus), 2530 Sixteen => alu::cmp_direct_page_indirect_long_u16(cpu, bus), 2531 }, 2532 0xC8 => match cpu.registers.p.index_size { 2533 Eight => alu::iny_u8(cpu, bus), 2534 Sixteen => alu::iny_u16(cpu, bus), 2535 }, 2536 0xC9 => match cpu.registers.p.accumulator_size { 2537 Eight => alu::cmp_immediate_u8(cpu, bus), 2538 Sixteen => alu::cmp_immediate_u16(cpu, bus), 2539 }, 2540 0xCA => match cpu.registers.p.index_size { 2541 Eight => alu::dex_u8(cpu, bus), 2542 Sixteen => alu::dex_u16(cpu, bus), 2543 }, 2544 0xCB => flow::wai(cpu, bus), 2545 0xCC => match cpu.registers.p.index_size { 2546 Eight => alu::cpy_absolute_u8(cpu, bus), 2547 Sixteen => alu::cpy_absolute_u16(cpu, bus), 2548 }, 2549 0xCD => match cpu.registers.p.accumulator_size { 2550 Eight => alu::cmp_absolute_u8(cpu, bus), 2551 Sixteen => alu::cmp_absolute_u16(cpu, bus), 2552 }, 2553 0xCE => match cpu.registers.p.accumulator_size { 2554 Eight => alu::dec_absolute_u8(cpu, bus), 2555 Sixteen => alu::dec_absolute_u16(cpu, bus), 2556 }, 2557 0xCF => match cpu.registers.p.accumulator_size { 2558 Eight => alu::cmp_absolute_long_u8(cpu, bus), 2559 Sixteen => alu::cmp_absolute_long_u16(cpu, bus), 2560 }, 2561 0xD0 => flow::bne(cpu, bus), 2562 0xD1 => match cpu.registers.p.accumulator_size { 2563 Eight => alu::cmp_direct_page_indirect_indexed_u8(cpu, bus), 2564 Sixteen => alu::cmp_direct_page_indirect_indexed_u16(cpu, bus), 2565 }, 2566 0xD2 => match cpu.registers.p.accumulator_size { 2567 Eight => alu::cmp_direct_page_indirect_u8(cpu, bus), 2568 Sixteen => alu::cmp_direct_page_indirect_u16(cpu, bus), 2569 }, 2570 0xD3 => match cpu.registers.p.accumulator_size { 2571 Eight => alu::cmp_stack_relative_indirect_indexed_u8(cpu, bus), 2572 Sixteen => alu::cmp_stack_relative_indirect_indexed_u16(cpu, bus), 2573 }, 2574 0xD4 => flow::pei(cpu, bus), 2575 0xD5 => match cpu.registers.p.accumulator_size { 2576 Eight => alu::cmp_direct_page_x_u8(cpu, bus), 2577 Sixteen => alu::cmp_direct_page_x_u16(cpu, bus), 2578 }, 2579 0xD6 => match cpu.registers.p.accumulator_size { 2580 Eight => alu::dec_direct_page_x_u8(cpu, bus), 2581 Sixteen => alu::dec_direct_page_x_u16(cpu, bus), 2582 }, 2583 0xD7 => match cpu.registers.p.accumulator_size { 2584 Eight => alu::cmp_direct_page_indirect_long_indexed_u8(cpu, bus), 2585 Sixteen => alu::cmp_direct_page_indirect_long_indexed_u16(cpu, bus), 2586 }, 2587 0xD8 => flags::cld(cpu, bus), 2588 0xD9 => match cpu.registers.p.accumulator_size { 2589 Eight => alu::cmp_absolute_y_u8(cpu, bus), 2590 Sixteen => alu::cmp_absolute_y_u16(cpu, bus), 2591 }, 2592 0xDA => match cpu.registers.p.index_size { 2593 Eight => load::phx_u8(cpu, bus), 2594 Sixteen => load::phx_u16(cpu, bus), 2595 }, 2596 0xDB => flow::stp(cpu, bus), 2597 0xDC => flow::jmp_indirect_long(cpu, bus), 2598 0xDD => match cpu.registers.p.accumulator_size { 2599 Eight => alu::cmp_absolute_x_u8(cpu, bus), 2600 Sixteen => alu::cmp_absolute_x_u16(cpu, bus), 2601 }, 2602 0xDE => match cpu.registers.p.accumulator_size { 2603 Eight => alu::dec_absolute_x_u8(cpu, bus), 2604 Sixteen => alu::dec_absolute_x_u16(cpu, bus), 2605 }, 2606 0xDF => match cpu.registers.p.accumulator_size { 2607 Eight => alu::cmp_absolute_long_x_u8(cpu, bus), 2608 Sixteen => alu::cmp_absolute_long_x_u16(cpu, bus), 2609 }, 2610 0xE0 => match cpu.registers.p.index_size { 2611 Eight => alu::cpx_immediate_u8(cpu, bus), 2612 Sixteen => alu::cpx_immediate_u16(cpu, bus), 2613 }, 2614 0xE1 => match cpu.registers.p.accumulator_size { 2615 Eight => alu::sbc_direct_page_indexed_indirect_u8(cpu, bus), 2616 Sixteen => alu::sbc_direct_page_indexed_indirect_u16(cpu, bus), 2617 }, 2618 0xE2 => flags::sep(cpu, bus), 2619 0xE3 => match cpu.registers.p.accumulator_size { 2620 Eight => alu::sbc_stack_relative_u8(cpu, bus), 2621 Sixteen => alu::sbc_stack_relative_u16(cpu, bus), 2622 }, 2623 0xE4 => match cpu.registers.p.index_size { 2624 Eight => alu::cpx_direct_page_u8(cpu, bus), 2625 Sixteen => alu::cpx_direct_page_u16(cpu, bus), 2626 }, 2627 0xE5 => match cpu.registers.p.accumulator_size { 2628 Eight => alu::sbc_direct_page_u8(cpu, bus), 2629 Sixteen => alu::sbc_direct_page_u16(cpu, bus), 2630 }, 2631 0xE6 => match cpu.registers.p.accumulator_size { 2632 Eight => alu::inc_direct_page_u8(cpu, bus), 2633 Sixteen => alu::inc_direct_page_u16(cpu, bus), 2634 }, 2635 0xE7 => match cpu.registers.p.accumulator_size { 2636 Eight => alu::sbc_direct_page_indirect_long_u8(cpu, bus), 2637 Sixteen => alu::sbc_direct_page_indirect_long_u16(cpu, bus), 2638 }, 2639 0xE8 => match cpu.registers.p.index_size { 2640 Eight => alu::inx_u8(cpu, bus), 2641 Sixteen => alu::inx_u16(cpu, bus), 2642 }, 2643 0xE9 => match cpu.registers.p.accumulator_size { 2644 Eight => alu::sbc_immediate_u8(cpu, bus), 2645 Sixteen => alu::sbc_immediate_u16(cpu, bus), 2646 }, 2647 0xEA => nop(cpu, bus), 2648 0xEB => load::xba(cpu, bus), 2649 0xEC => match cpu.registers.p.index_size { 2650 Eight => alu::cpx_absolute_u8(cpu, bus), 2651 Sixteen => alu::cpx_absolute_u16(cpu, bus), 2652 }, 2653 0xED => match cpu.registers.p.accumulator_size { 2654 Eight => alu::sbc_absolute_u8(cpu, bus), 2655 Sixteen => alu::sbc_absolute_u16(cpu, bus), 2656 }, 2657 0xEE => match cpu.registers.p.accumulator_size { 2658 Eight => alu::inc_absolute_u8(cpu, bus), 2659 Sixteen => alu::inc_absolute_u16(cpu, bus), 2660 }, 2661 0xEF => match cpu.registers.p.accumulator_size { 2662 Eight => alu::sbc_absolute_long_u8(cpu, bus), 2663 Sixteen => alu::sbc_absolute_long_u16(cpu, bus), 2664 }, 2665 0xF0 => flow::beq(cpu, bus), 2666 0xF1 => match cpu.registers.p.accumulator_size { 2667 Eight => alu::sbc_direct_page_indirect_indexed_u8(cpu, bus), 2668 Sixteen => alu::sbc_direct_page_indirect_indexed_u16(cpu, bus), 2669 }, 2670 0xF2 => match cpu.registers.p.accumulator_size { 2671 Eight => alu::sbc_direct_page_indirect_u8(cpu, bus), 2672 Sixteen => alu::sbc_direct_page_indirect_u16(cpu, bus), 2673 }, 2674 0xF3 => match cpu.registers.p.accumulator_size { 2675 Eight => alu::sbc_stack_relative_indirect_indexed_u8(cpu, bus), 2676 Sixteen => alu::sbc_stack_relative_indirect_indexed_u16(cpu, bus), 2677 }, 2678 0xF4 => flow::pea(cpu, bus), 2679 0xF5 => match cpu.registers.p.accumulator_size { 2680 Eight => alu::sbc_direct_page_x_u8(cpu, bus), 2681 Sixteen => alu::sbc_direct_page_x_u16(cpu, bus), 2682 }, 2683 0xF6 => match cpu.registers.p.accumulator_size { 2684 Eight => alu::inc_direct_page_x_u8(cpu, bus), 2685 Sixteen => alu::inc_direct_page_x_u16(cpu, bus), 2686 }, 2687 0xF7 => match cpu.registers.p.accumulator_size { 2688 Eight => alu::sbc_direct_page_indirect_long_indexed_u8(cpu, bus), 2689 Sixteen => alu::sbc_direct_page_indirect_long_indexed_u16(cpu, bus), 2690 }, 2691 0xF8 => flags::sed(cpu, bus), 2692 0xF9 => match cpu.registers.p.accumulator_size { 2693 Eight => alu::sbc_absolute_y_u8(cpu, bus), 2694 Sixteen => alu::sbc_absolute_y_u16(cpu, bus), 2695 }, 2696 0xFA => match cpu.registers.p.index_size { 2697 Eight => load::plx_u8(cpu, bus), 2698 Sixteen => load::plx_u16(cpu, bus), 2699 }, 2700 0xFB => flags::xce(cpu, bus), 2701 0xFC => flow::jsr_indirect_indexed(cpu, bus), 2702 0xFD => match cpu.registers.p.accumulator_size { 2703 Eight => alu::sbc_absolute_x_u8(cpu, bus), 2704 Sixteen => alu::sbc_absolute_x_u16(cpu, bus), 2705 }, 2706 0xFE => match cpu.registers.p.accumulator_size { 2707 Eight => alu::inc_absolute_x_u8(cpu, bus), 2708 Sixteen => alu::inc_absolute_x_u16(cpu, bus), 2709 }, 2710 0xFF => match cpu.registers.p.accumulator_size { 2711 Eight => alu::sbc_absolute_long_x_u8(cpu, bus), 2712 Sixteen => alu::sbc_absolute_long_x_u16(cpu, bus), 2713 }, 2714 } 2715}