1#[allow(clippy::wildcard_imports)] 2use super::*; 3use crate::StatusRegister; 4use jgenesis_common::num::U16Ext; 5 6fn adc(operand_l: u8, operand_r: u8, psw: &mut StatusRegister) -> u8 { 7 let existing_carry: u8 = psw.carry.into(); 8 9 let (partial_sum, carry1) = operand_l.overflowing_add(operand_r); 10 let (sum, carry2) = partial_sum.overflowing_add(existing_carry); 11 let carry = carry1 || carry2; 12 13 let bit_6_carry = (operand_l & 0x7F) + (operand_r & 0x7F) + existing_carry >= 0x80; 14 let overflow = bit_6_carry != carry; 15 16 let half_carry = (operand_l & 0x0F) + (operand_r & 0x0F) + existing_carry >= 0x10; 17 18 psw.zero = sum == 0; 19 psw.negative = sum.sign_bit(); 20 psw.carry = carry; 21 psw.half_carry = half_carry; 22 psw.overflow = overflow; 23 24 sum 25} 26 27impl_read_op!( 28 [ 29 immediate -> adc_imm, 30 x_indirect -> adc_xind, 31 direct_page -> adc_dp, 32 direct_page_x -> adc_dpx, 33 absolute -> adc_abs, 34 absolute_x -> adc_absx, 35 absolute_y -> adc_absy, 36 indirect_x -> adc_indx, 37 indirect_y -> adc_indy, 38 ] 39 (|registers, value| { 40 registers.a = adc(registers.a, value, &mut registers.psw); 41 }) 42); 43 44impl_memory_to_memory_op!( 45 [ 46 x_y -> adc_x_y_ind, 47 dp_dp -> adc_dp_dp, 48 dp_imm -> adc_dp_imm, 49 ] 50 (|registers, operand_l, operand_r| { 51 adc(operand_l, operand_r, &mut registers.psw) 52 }) 53); 54 55fn sbc(operand_l: u8, operand_r: u8, psw: &mut StatusRegister) -> u8 { 56 let existing_borrow: u8 = (!psw.carry).into(); 57 58 let (partial_diff, borrow1) = operand_l.overflowing_sub(operand_r); 59 let (difference, borrow2) = partial_diff.overflowing_sub(existing_borrow); 60 let borrow = borrow1 || borrow2; 61 62 let bit_6_borrow = operand_l & 0x7F < (operand_r & 0x7F) + existing_borrow; 63 let overflow = bit_6_borrow != borrow; 64 65 let half_borrow = operand_l & 0x0F < (operand_r & 0x0F) + existing_borrow; 66 67 psw.zero = difference == 0; 68 psw.negative = difference.sign_bit(); 69 psw.carry = !borrow; 70 psw.half_carry = !half_borrow; 71 psw.overflow = overflow; 72 73 difference 74} 75 76impl_read_op!( 77 [ 78 immediate -> sbc_imm, 79 x_indirect -> sbc_xind, 80 direct_page -> sbc_dp, 81 direct_page_x -> sbc_dpx, 82 absolute -> sbc_abs, 83 absolute_x -> sbc_absx, 84 absolute_y -> sbc_absy, 85 indirect_x -> sbc_indx, 86 indirect_y -> sbc_indy, 87 ] 88 (|registers, value| { 89 registers.a = sbc(registers.a, value, &mut registers.psw); 90 }) 91); 92 93impl_memory_to_memory_op!( 94 [ 95 x_y -> sbc_x_y_ind, 96 dp_dp -> sbc_dp_dp, 97 dp_imm -> sbc_dp_imm, 98 ] 99 (|registers, operand_l, operand_r| { 100 sbc(operand_l, operand_r, &mut registers.psw) 101 }) 102); 103 104fn cmp(operand_l: u8, operand_r: u8, psw: &mut StatusRegister) { 105 let (difference, borrow) = operand_l.overflowing_sub(operand_r); 106 psw.zero = difference == 0; 107 psw.negative = difference.sign_bit(); 108 psw.carry = !borrow; 109} 110 111impl_read_op!( 112 [ 113 immediate -> cmp_a_imm, 114 x_indirect -> cmp_a_xind, 115 direct_page -> cmp_a_dp, 116 direct_page_x -> cmp_a_dpx, 117 absolute -> cmp_a_abs, 118 absolute_x -> cmp_a_absx, 119 absolute_y -> cmp_a_absy, 120 indirect_x -> cmp_a_indx, 121 indirect_y -> cmp_a_indy, 122 ] 123 (|registers, value| { 124 cmp(registers.a, value, &mut registers.psw); 125 }) 126); 127 128impl_memory_to_memory_op!( 129 [ 130 x_y_no_write -> cmp_x_y_ind, 131 dp_dp_no_write -> cmp_dp_dp, 132 dp_imm_no_write -> cmp_dp_imm, 133 ] 134 (|registers, operand_l, operand_r| { 135 cmp(operand_l, operand_r, &mut registers.psw); 136 operand_l 137 }) 138); 139 140impl_read_op!( 141 [ 142 immediate -> cmp_x_imm, 143 direct_page -> cmp_x_dp, 144 absolute -> cmp_x_abs, 145 ] 146 (|registers, value| { 147 cmp(registers.x, value, &mut registers.psw); 148 }) 149); 150 151impl_read_op!( 152 [ 153 immediate -> cmp_y_imm, 154 direct_page -> cmp_y_dp, 155 absolute -> cmp_y_abs, 156 ] 157 (|registers, value| { 158 cmp(registers.y, value, &mut registers.psw); 159 }) 160); 161 162impl_read_op!( 163 [ 164 immediate -> and_imm, 165 x_indirect -> and_xind, 166 direct_page -> and_dp, 167 direct_page_x -> and_dpx, 168 absolute -> and_abs, 169 absolute_x -> and_absx, 170 absolute_y -> and_absy, 171 indirect_x -> and_indx, 172 indirect_y -> and_indy, 173 ] 174 (|registers, value| { 175 registers.a &= value; 176 registers.psw.zero = registers.a == 0; 177 registers.psw.negative = registers.a.sign_bit(); 178 }) 179); 180 181impl_memory_to_memory_op!( 182 [ 183 x_y -> and_x_y_ind, 184 dp_dp -> and_dp_dp, 185 dp_imm -> and_dp_imm, 186 ] 187 (|registers, operand_l, operand_r| { 188 let result = operand_l & operand_r; 189 registers.psw.zero = result == 0; 190 registers.psw.negative = result.sign_bit(); 191 result 192 }) 193); 194 195impl_read_op!( 196 [ 197 immediate -> or_imm, 198 x_indirect -> or_xind, 199 direct_page -> or_dp, 200 direct_page_x -> or_dpx, 201 absolute -> or_abs, 202 absolute_x -> or_absx, 203 absolute_y -> or_absy, 204 indirect_x -> or_indx, 205 indirect_y -> or_indy, 206 ] 207 (|registers, value| { 208 registers.a |= value; 209 registers.psw.zero = registers.a == 0; 210 registers.psw.negative = registers.a.sign_bit(); 211 }) 212); 213 214impl_memory_to_memory_op!( 215 [ 216 x_y -> or_x_y_ind, 217 dp_dp -> or_dp_dp, 218 dp_imm -> or_dp_imm, 219 ] 220 (|registers, operand_l, operand_r| { 221 let result = operand_l | operand_r; 222 registers.psw.zero = result == 0; 223 registers.psw.negative = result.sign_bit(); 224 result 225 }) 226); 227 228impl_read_op!( 229 [ 230 immediate -> eor_imm, 231 x_indirect -> eor_xind, 232 direct_page -> eor_dp, 233 direct_page_x -> eor_dpx, 234 absolute -> eor_abs, 235 absolute_x -> eor_absx, 236 absolute_y -> eor_absy, 237 indirect_x -> eor_indx, 238 indirect_y -> eor_indy, 239 ] 240 (|registers, value| { 241 registers.a ^= value; 242 registers.psw.zero = registers.a == 0; 243 registers.psw.negative = registers.a.sign_bit(); 244 }) 245); 246 247impl_memory_to_memory_op!( 248 [ 249 x_y -> eor_x_y_ind, 250 dp_dp -> eor_dp_dp, 251 dp_imm -> eor_dp_imm, 252 ] 253 (|registers, operand_l, operand_r| { 254 let result = operand_l ^ operand_r; 255 registers.psw.zero = result == 0; 256 registers.psw.negative = result.sign_bit(); 257 result 258 }) 259); 260 261impl_modify_op!( 262 [ 263 accumulator -> inc_a, 264 direct_page -> inc_dp, 265 direct_page_x -> inc_dpx, 266 absolute -> inc_abs, 267 ] 268 (|registers, value| { 269 let result = value.wrapping_add(1); 270 registers.psw.zero = result == 0; 271 registers.psw.negative = result.sign_bit(); 272 result 273 }) 274); 275 276impl_modify_op!( 277 [ 278 accumulator -> dec_a, 279 direct_page -> dec_dp, 280 direct_page_x -> dec_dpx, 281 absolute -> dec_abs, 282 ] 283 (|registers, value| { 284 let result = value.wrapping_sub(1); 285 registers.psw.zero = result == 0; 286 registers.psw.negative = result.sign_bit(); 287 result 288 }) 289); 290 291macro_rules! impl_register_increment_op { 292 ($name:ident, $register:ident, $inc_method:ident) => { 293 impl_registers_op!($name, |registers| { 294 let value = registers.$register.$inc_method(1); 295 registers.$register = value; 296 297 registers.psw.zero = value == 0; 298 registers.psw.negative = value.sign_bit(); 299 }); 300 }; 301} 302 303impl_register_increment_op!(inc_x, x, wrapping_add); 304impl_register_increment_op!(inc_y, y, wrapping_add); 305impl_register_increment_op!(dec_x, x, wrapping_sub); 306impl_register_increment_op!(dec_y, y, wrapping_sub); 307 308pub(crate) fn addw<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 309 match cpu.state.cycle { 310 1 => { 311 cpu.state.t0 = fetch_operand(cpu, bus); 312 } 313 2 => { 314 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 315 cpu.state.t1 = bus.read(address); 316 } 317 3 => { 318 bus.idle(); 319 } 320 4 => { 321 cpu.final_cycle(); 322 323 let address_lsb = cpu.state.t0.wrapping_add(1); 324 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 325 let operand_msb = bus.read(address); 326 let operand = u16::from_le_bytes([cpu.state.t1, operand_msb]); 327 328 let ya = cpu.registers.ya(); 329 let (sum, carry) = ya.overflowing_add(operand); 330 331 let bit_14_carry = (ya & 0x7FFF) + (operand & 0x7FFF) >= 0x8000; 332 let overflow = bit_14_carry != carry; 333 334 let half_carry = (ya & 0x0FFF) + (operand & 0x0FFF) >= 0x1000; 335 336 cpu.registers.set_ya(sum); 337 cpu.registers.psw.zero = sum == 0; 338 cpu.registers.psw.negative = sum.sign_bit(); 339 cpu.registers.psw.carry = carry; 340 cpu.registers.psw.half_carry = half_carry; 341 cpu.registers.psw.overflow = overflow; 342 } 343 _ => invalid_cycle!(cpu), 344 } 345} 346 347pub(crate) fn subw<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 348 match cpu.state.cycle { 349 1 => { 350 cpu.state.t0 = fetch_operand(cpu, bus); 351 } 352 2 => { 353 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 354 cpu.state.t1 = bus.read(address); 355 } 356 3 => { 357 bus.idle(); 358 } 359 4 => { 360 cpu.final_cycle(); 361 362 let address_lsb = cpu.state.t0.wrapping_add(1); 363 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 364 let operand_msb = bus.read(address); 365 let operand = u16::from_le_bytes([cpu.state.t1, operand_msb]); 366 367 let ya = cpu.registers.ya(); 368 let (difference, borrow) = ya.overflowing_sub(operand); 369 370 let bit_14_borrow = ya & 0x7FFF < operand & 0x7FFF; 371 let overflow = bit_14_borrow != borrow; 372 373 let half_borrow = ya & 0x0FFF < operand & 0x0FFF; 374 375 cpu.registers.set_ya(difference); 376 cpu.registers.psw.zero = difference == 0; 377 cpu.registers.psw.negative = difference.sign_bit(); 378 cpu.registers.psw.carry = !borrow; 379 cpu.registers.psw.half_carry = !half_borrow; 380 cpu.registers.psw.overflow = overflow; 381 } 382 _ => invalid_cycle!(cpu), 383 } 384} 385 386pub(crate) fn cmpw<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 387 match cpu.state.cycle { 388 1 => { 389 cpu.state.t0 = fetch_operand(cpu, bus); 390 } 391 2 => { 392 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 393 cpu.state.t1 = bus.read(address); 394 } 395 3 => { 396 cpu.final_cycle(); 397 398 let address_lsb = cpu.state.t0.wrapping_add(1); 399 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 400 let operand_msb = bus.read(address); 401 let operand = u16::from_le_bytes([cpu.state.t1, operand_msb]); 402 403 let ya = cpu.registers.ya(); 404 let (difference, borrow) = ya.overflowing_sub(operand); 405 406 cpu.registers.psw.zero = difference == 0; 407 cpu.registers.psw.negative = difference.sign_bit(); 408 cpu.registers.psw.carry = !borrow; 409 } 410 _ => invalid_cycle!(cpu), 411 } 412} 413 414macro_rules! impl_16bit_increment { 415 ($name:ident, $inc_method:ident) => { 416 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 417 match cpu.state.cycle { 418 1 => { 419 cpu.state.t0 = fetch_operand(cpu, bus); 420 } 421 2 => { 422 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 423 cpu.state.t1 = bus.read(address); 424 } 425 3 => { 426 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 427 bus.write(address, cpu.state.t1.$inc_method(1)); 428 } 429 4 => { 430 let address_lsb = cpu.state.t0.wrapping_add(1); 431 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 432 cpu.state.t2 = bus.read(address); 433 } 434 5 => { 435 cpu.final_cycle(); 436 437 let value = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]).$inc_method(1); 438 439 let address_lsb = cpu.state.t0.wrapping_add(1); 440 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 441 bus.write(address, value.msb()); 442 443 cpu.registers.psw.zero = value == 0; 444 cpu.registers.psw.negative = value.sign_bit(); 445 } 446 _ => invalid_cycle!(cpu), 447 } 448 } 449 }; 450} 451 452impl_16bit_increment!(incw, wrapping_add); 453impl_16bit_increment!(decw, wrapping_sub); 454 455pub(crate) fn mul<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 456 // MUL takes 9 cycles, but every cycle is a bus idle cycle except for the opcode fetch 457 match cpu.state.cycle { 458 1..=7 => { 459 bus.idle(); 460 } 461 8 => { 462 cpu.final_cycle(); 463 bus.idle(); 464 465 let result = u16::from(cpu.registers.y) * u16::from(cpu.registers.a); 466 cpu.registers.set_ya(result); 467 468 // Z flag is set based on the MSB (Y), not the full 16-bit result 469 cpu.registers.psw.zero = cpu.registers.y == 0; 470 cpu.registers.psw.negative = cpu.registers.y.sign_bit(); 471 } 472 _ => invalid_cycle!(cpu), 473 } 474} 475 476pub(crate) fn div<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 477 // DIV takes 12 cycles, but every cycle is a bus idle cycle except for the opcode fetch 478 match cpu.state.cycle { 479 1..=10 => { 480 bus.idle(); 481 } 482 11 => { 483 cpu.final_cycle(); 484 bus.idle(); 485 486 // Algorithm from https://board.zsnes.com/phpBB3/viewtopic.php?t=3753 487 488 cpu.registers.psw.overflow = cpu.registers.y >= cpu.registers.x; 489 cpu.registers.psw.half_carry = cpu.registers.y & 0x0F >= cpu.registers.x & 0x0F; 490 491 let x: u16 = cpu.registers.x.into(); 492 let y: u16 = cpu.registers.y.into(); 493 let ya = cpu.registers.ya(); 494 if y < 2 * x { 495 // Normal division 496 cpu.registers.a = (ya / x) as u8; 497 cpu.registers.y = (ya % x) as u8; 498 } else { 499 // Overflow (including divide by zero) 500 cpu.registers.a = (255 - (ya - x * 0x200) / (256 - x)) as u8; 501 cpu.registers.y = (x + (ya - x * 0x200) % (256 - x)) as u8; 502 } 503 504 cpu.registers.psw.zero = cpu.registers.a == 0; 505 cpu.registers.psw.negative = cpu.registers.a.sign_bit(); 506 } 507 _ => invalid_cycle!(cpu), 508 } 509} 510 511pub(crate) fn daa<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 512 match cpu.state.cycle { 513 1 => { 514 bus.idle(); 515 } 516 2 => { 517 cpu.final_cycle(); 518 bus.idle(); 519 520 // Algorithm from https://board.zsnes.com/phpBB3/viewtopic.php?t=3753 521 522 if cpu.registers.psw.carry || cpu.registers.a > 0x99 { 523 cpu.registers.psw.carry = true; 524 cpu.registers.a = cpu.registers.a.wrapping_add(0x60); 525 } 526 527 if cpu.registers.psw.half_carry || (cpu.registers.a & 0x0F) > 0x09 { 528 cpu.registers.a = cpu.registers.a.wrapping_add(0x06); 529 } 530 531 cpu.registers.psw.zero = cpu.registers.a == 0; 532 cpu.registers.psw.negative = cpu.registers.a.sign_bit(); 533 } 534 _ => invalid_cycle!(cpu), 535 } 536} 537 538pub(crate) fn das<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 539 match cpu.state.cycle { 540 1 => { 541 bus.idle(); 542 } 543 2 => { 544 cpu.final_cycle(); 545 bus.idle(); 546 547 // Algorithm from https://board.zsnes.com/phpBB3/viewtopic.php?t=3753 548 549 if !cpu.registers.psw.carry || cpu.registers.a > 0x99 { 550 cpu.registers.psw.carry = false; 551 cpu.registers.a = cpu.registers.a.wrapping_sub(0x60); 552 } 553 554 if !cpu.registers.psw.half_carry || (cpu.registers.a & 0x0F) > 0x09 { 555 cpu.registers.a = cpu.registers.a.wrapping_sub(0x06); 556 } 557 558 cpu.registers.psw.zero = cpu.registers.a == 0; 559 cpu.registers.psw.negative = cpu.registers.a.sign_bit(); 560 } 561 _ => invalid_cycle!(cpu), 562 } 563}