1use crate::core::{ 2 AddressRegister, AddressingMode, ConditionCodes, DataRegister, Exception, ExecuteResult, 3 InstructionExecutor, OpSize, ResolvedAddress, 4}; 5use crate::traits::BusInterface; 6use jgenesis_common::num::{GetBit, SignBit}; 7 8macro_rules! impl_extend_op_method { 9 ($name:ident, $read_method:ident, $write_method:ident, $op_fn:ident, $size:expr) => { 10 fn $name(&mut self, source: AddressingMode, dest: AddressingMode) -> ExecuteResult<u32> { 11 let (_, operand_r) = self.$read_method(source)?; 12 let (dest_resolved, operand_l) = self.$read_method(dest)?; 13 14 let (value, carry, overflow) = 15 $op_fn(operand_l, operand_r, self.cpu.registers.ccr.extend); 16 17 self.cpu.registers.ccr = ConditionCodes { 18 carry, 19 overflow, 20 zero: self.cpu.registers.ccr.zero && value == 0, 21 negative: value.sign_bit(), 22 extend: carry, 23 }; 24 25 self.$write_method(dest_resolved, value)?; 26 27 // ADDX and SUBX only support Dx,Dy and -(Ax),-(Ay) 28 Ok(match ($size, source) { 29 (OpSize::Byte | OpSize::Word, AddressingMode::DataDirect(..)) => 4, 30 (OpSize::LongWord, AddressingMode::DataDirect(..)) => 8, 31 (OpSize::Byte | OpSize::Word, _) => 18, 32 (OpSize::LongWord, _) => 30, 33 }) 34 } 35 }; 36} 37 38macro_rules! impl_op_method { 39 ($name:ident, $aname:ident, $xname:ident, $read_method:ident, $read_resolved_method:ident, $write_method:ident, $op_fn:ident, $size:expr) => { 40 pub(super) fn $name( 41 &mut self, 42 source: AddressingMode, 43 dest: AddressingMode, 44 with_extend: bool, 45 ) -> ExecuteResult<u32> { 46 if with_extend { 47 return self.$xname(source, dest); 48 } 49 50 if let AddressingMode::AddressDirect(register) = dest { 51 return self.$aname($size, source, register); 52 } 53 54 let operand_r = self.$read_method(source)?; 55 56 let dest_resolved = self.resolve_address_with_post(dest, $size)?; 57 let operand_l = self.$read_resolved_method(dest_resolved)?; 58 59 let (value, carry, overflow) = $op_fn(operand_l, operand_r, false); 60 61 if !dest.is_address_direct() { 62 self.cpu.registers.ccr = ConditionCodes { 63 carry, 64 overflow, 65 zero: value == 0, 66 negative: value.sign_bit(), 67 extend: carry, 68 }; 69 } 70 71 self.$write_method(dest_resolved, value)?; 72 73 Ok(super::binary_op_cycles($size, source, dest)) 74 } 75 }; 76} 77 78macro_rules! impl_neg { 79 ($name:ident, $read_method:ident, $write_method:ident, $sub_fn:ident, $size:expr) => { 80 pub(super) fn $name( 81 &mut self, 82 dest: AddressingMode, 83 with_extend: bool, 84 ) -> ExecuteResult<u32> { 85 let dest_resolved = self.resolve_address_with_post(dest, $size)?; 86 let operand_r = self.$read_method(dest_resolved)?; 87 let extend = with_extend && self.cpu.registers.ccr.extend; 88 let (difference, carry, overflow) = $sub_fn(0, operand_r, extend); 89 90 self.cpu.registers.ccr = ConditionCodes { 91 carry, 92 overflow, 93 zero: (!with_extend || self.cpu.registers.ccr.zero) && difference == 0, 94 negative: difference.sign_bit(), 95 extend: carry, 96 }; 97 98 self.$write_method(dest_resolved, difference)?; 99 100 Ok(super::unary_op_cycles($size, dest)) 101 } 102 }; 103} 104 105macro_rules! impl_cmp { 106 ($name:ident, $read_method:ident, $cmp_fn:ident, $cycles_fn:ident, $size:expr) => { 107 pub(super) fn $name( 108 &mut self, 109 source: AddressingMode, 110 dest: AddressingMode, 111 ) -> ExecuteResult<u32> { 112 if let AddressingMode::AddressDirect(dest) = dest { 113 return self.cmpa($size, source, dest); 114 } 115 116 let source_operand = self.$read_method(source)?; 117 let dest_operand = self.$read_method(dest)?; 118 119 $cmp_fn(source_operand, dest_operand, &mut self.cpu.registers.ccr); 120 121 let cycles = $cycles_fn(source, dest); 122 Ok(cycles) 123 } 124 }; 125} 126 127macro_rules! impl_cmp_cycles_byte_word { 128 ($name:ident, $size:expr) => { 129 #[inline] 130 pub(super) fn $name(source: AddressingMode, dest: AddressingMode) -> u32 { 131 match (source, dest) { 132 // CMPM.b / CMPM.w 133 ( 134 AddressingMode::AddressIndirectPostincrement(..), 135 AddressingMode::AddressIndirectPostincrement(..), 136 ) => 12, 137 // CMPI.b / CMPI.w 138 (AddressingMode::Immediate, AddressingMode::DataDirect(..)) => 8, 139 (AddressingMode::Immediate, _) => super::binary_op_cycles($size, source, dest) - 4, 140 // CMP 141 _ => super::binary_op_cycles($size, source, dest), 142 } 143 } 144 }; 145} 146 147impl_cmp_cycles_byte_word!(cmp_cycles_byte, OpSize::Byte); 148impl_cmp_cycles_byte_word!(cmp_cycles_word, OpSize::Word); 149 150#[inline] 151pub(super) fn cmp_cycles_long_word(source: AddressingMode, dest: AddressingMode) -> u32 { 152 match (source, dest) { 153 // CMPM.l 154 ( 155 AddressingMode::AddressIndirectPostincrement(..), 156 AddressingMode::AddressIndirectPostincrement(..), 157 ) => 20, 158 // CMPI.l 159 (AddressingMode::Immediate, AddressingMode::DataDirect(..)) => 14, 160 (AddressingMode::Immediate, _) => { 161 super::binary_op_cycles(OpSize::LongWord, source, dest) - 8 162 } 163 // CMP 164 ( 165 AddressingMode::DataDirect(..) | AddressingMode::AddressDirect(..), 166 AddressingMode::DataDirect(..), 167 ) => 6, 168 _ => super::binary_op_cycles(OpSize::LongWord, source, dest), 169 } 170} 171 172impl<B: BusInterface> InstructionExecutor<'_, '_, B> { 173 fn read_byte_for_extend( 174 &mut self, 175 source: AddressingMode, 176 ) -> ExecuteResult<(ResolvedAddress, u8)> { 177 let address = self.resolve_address_with_post(source, OpSize::Byte)?; 178 let byte = self.read_byte_resolved(address); 179 Ok((address, byte)) 180 } 181 182 fn read_word_for_extend( 183 &mut self, 184 source: AddressingMode, 185 ) -> ExecuteResult<(ResolvedAddress, u16)> { 186 let address = self.resolve_address_with_post(source, OpSize::Word)?; 187 let word = self.read_word_resolved(address)?; 188 Ok((address, word)) 189 } 190 191 fn read_long_word_for_extend( 192 &mut self, 193 source: AddressingMode, 194 ) -> ExecuteResult<(ResolvedAddress, u32)> { 195 match source { 196 AddressingMode::AddressIndirectPredecrement(register) => { 197 let address = register.read_from(&self.cpu.registers).wrapping_sub(2); 198 register.write_long_word_to(&mut self.cpu.registers, address); 199 let low_word = self.read_bus_word(address)?; 200 201 let address = address.wrapping_sub(2); 202 register.write_long_word_to(&mut self.cpu.registers, address); 203 let high_word = self.read_bus_word(address)?; 204 205 let value = (u32::from(high_word) << 16) | u32::from(low_word); 206 Ok((ResolvedAddress::Memory(address), value)) 207 } 208 _ => { 209 let address = self.resolve_address_with_post(source, OpSize::LongWord)?; 210 let value = self.read_long_word_resolved(address)?; 211 Ok((address, value)) 212 } 213 } 214 } 215 216 fn read_address_operand(&mut self, size: OpSize, source: AddressingMode) -> ExecuteResult<u32> { 217 let value = match size { 218 OpSize::Word => self.read_word(source)? as i16 as u32, 219 OpSize::LongWord => self.read_long_word(source)?, 220 OpSize::Byte => panic!("ADDA does not support bytes"), 221 }; 222 Ok(value) 223 } 224 225 fn adda( 226 &mut self, 227 size: OpSize, 228 source: AddressingMode, 229 dest: AddressRegister, 230 ) -> ExecuteResult<u32> { 231 let operand_r = self.read_address_operand(size, source)?; 232 let operand_l = dest.read_from(&self.cpu.registers); 233 234 let sum = operand_l.wrapping_add(operand_r); 235 dest.write_long_word_to(&mut self.cpu.registers, sum); 236 237 Ok(super::binary_op_cycles(size, source, AddressingMode::AddressDirect(dest))) 238 } 239 240 impl_extend_op_method!( 241 addx_byte, 242 read_byte_for_extend, 243 write_byte_resolved_as_result, 244 add_bytes, 245 OpSize::Byte 246 ); 247 impl_extend_op_method!( 248 addx_word, 249 read_word_for_extend, 250 write_word_resolved, 251 add_words, 252 OpSize::Word 253 ); 254 impl_extend_op_method!( 255 addx_long_word, 256 read_long_word_for_extend, 257 write_long_word_resolved, 258 add_long_words, 259 OpSize::LongWord 260 ); 261 262 impl_op_method!( 263 add_byte, 264 adda, 265 addx_byte, 266 read_byte, 267 read_byte_resolved_as_result, 268 write_byte_resolved_as_result, 269 add_bytes, 270 OpSize::Byte 271 ); 272 impl_op_method!( 273 add_word, 274 adda, 275 addx_word, 276 read_word, 277 read_word_resolved, 278 write_word_resolved, 279 add_words, 280 OpSize::Word 281 ); 282 impl_op_method!( 283 add_long_word, 284 adda, 285 addx_long_word, 286 read_long_word, 287 read_long_word_resolved, 288 write_long_word_resolved, 289 add_long_words, 290 OpSize::LongWord 291 ); 292 293 fn suba( 294 &mut self, 295 size: OpSize, 296 source: AddressingMode, 297 dest: AddressRegister, 298 ) -> ExecuteResult<u32> { 299 let operand_r = self.read_address_operand(size, source)?; 300 let operand_l = dest.read_from(&self.cpu.registers); 301 302 let difference = operand_l.wrapping_sub(operand_r); 303 dest.write_long_word_to(&mut self.cpu.registers, difference); 304 305 Ok(super::binary_op_cycles(size, source, AddressingMode::AddressDirect(dest))) 306 } 307 308 impl_extend_op_method!( 309 subx_byte, 310 read_byte_for_extend, 311 write_byte_resolved_as_result, 312 sub_bytes, 313 OpSize::Byte 314 ); 315 impl_extend_op_method!( 316 subx_word, 317 read_word_for_extend, 318 write_word_resolved, 319 sub_words, 320 OpSize::Word 321 ); 322 impl_extend_op_method!( 323 subx_long_word, 324 read_long_word_for_extend, 325 write_long_word_resolved, 326 sub_long_words, 327 OpSize::LongWord 328 ); 329 330 impl_op_method!( 331 sub_byte, 332 suba, 333 subx_byte, 334 read_byte, 335 read_byte_resolved_as_result, 336 write_byte_resolved_as_result, 337 sub_bytes, 338 OpSize::Byte 339 ); 340 impl_op_method!( 341 sub_word, 342 suba, 343 subx_word, 344 read_word, 345 read_word_resolved, 346 write_word_resolved, 347 sub_words, 348 OpSize::Word 349 ); 350 impl_op_method!( 351 sub_long_word, 352 suba, 353 subx_long_word, 354 read_long_word, 355 read_long_word_resolved, 356 write_long_word_resolved, 357 sub_long_words, 358 OpSize::LongWord 359 ); 360 361 impl_neg!( 362 neg_byte, 363 read_byte_resolved_as_result, 364 write_byte_resolved_as_result, 365 sub_bytes, 366 OpSize::Byte 367 ); 368 impl_neg!(neg_word, read_word_resolved, write_word_resolved, sub_words, OpSize::Word); 369 impl_neg!( 370 neg_long_word, 371 read_long_word_resolved, 372 write_long_word_resolved, 373 sub_long_words, 374 OpSize::LongWord 375 ); 376 377 impl_cmp!(cmp_byte, read_byte, compare_bytes, cmp_cycles_byte, OpSize::Byte); 378 impl_cmp!(cmp_word, read_word, compare_words, cmp_cycles_word, OpSize::Word); 379 impl_cmp!( 380 cmp_long_word, 381 read_long_word, 382 compare_long_words, 383 cmp_cycles_long_word, 384 OpSize::LongWord 385 ); 386 387 fn cmpa( 388 &mut self, 389 size: OpSize, 390 source: AddressingMode, 391 dest: AddressRegister, 392 ) -> ExecuteResult<u32> { 393 let source_operand = self.read_address_operand(size, source)?; 394 let dest_operand = dest.read_from(&self.cpu.registers); 395 396 compare_long_words(source_operand, dest_operand, &mut self.cpu.registers.ccr); 397 398 Ok(6 + source.address_calculation_cycles(size)) 399 } 400 401 pub(super) fn muls( 402 &mut self, 403 register: DataRegister, 404 source: AddressingMode, 405 ) -> ExecuteResult<u32> { 406 let operand_l = self.read_word(source)? as i16; 407 let operand_r = register.read_from(&self.cpu.registers) as i16; 408 409 let value = (i32::from(operand_l) * i32::from(operand_r)) as u32; 410 register.write_long_word_to(&mut self.cpu.registers, value); 411 412 self.cpu.registers.ccr = ConditionCodes { 413 carry: false, 414 overflow: false, 415 zero: value == 0, 416 negative: value.sign_bit(), 417 ..self.cpu.registers.ccr 418 }; 419 420 let mut last_bit = false; 421 let mut alternating_bits = 0; 422 for i in 0..16 { 423 let bit = operand_l.bit(i); 424 if bit != last_bit { 425 alternating_bits += 1; 426 } 427 last_bit = bit; 428 } 429 430 Ok(38 + 2 * alternating_bits + source.address_calculation_cycles(OpSize::Word)) 431 } 432 433 pub(super) fn mulu( 434 &mut self, 435 register: DataRegister, 436 source: AddressingMode, 437 ) -> ExecuteResult<u32> { 438 let operand_l = self.read_word(source)?; 439 let operand_r = register.read_from(&self.cpu.registers) as u16; 440 441 let value = u32::from(operand_l) * u32::from(operand_r); 442 register.write_long_word_to(&mut self.cpu.registers, value); 443 444 self.cpu.registers.ccr = ConditionCodes { 445 carry: false, 446 overflow: false, 447 zero: value == 0, 448 negative: value.sign_bit(), 449 ..self.cpu.registers.ccr 450 }; 451 452 Ok(38 + 2 * operand_l.count_ones() + source.address_calculation_cycles(OpSize::Word)) 453 } 454 455 fn divide_by_zero_error(&mut self, source: AddressingMode) -> Exception { 456 self.cpu.registers.ccr = ConditionCodes { 457 carry: false, 458 overflow: false, 459 zero: false, 460 negative: false, 461 ..self.cpu.registers.ccr 462 }; 463 464 Exception::DivisionByZero { cycles: source.address_calculation_cycles(OpSize::Word) } 465 } 466 467 pub(super) fn divs( 468 &mut self, 469 register: DataRegister, 470 source: AddressingMode, 471 ) -> ExecuteResult<u32> { 472 let operand_l = register.read_from(&self.cpu.registers) as i32; 473 let operand_r: i32 = (self.read_word(source)? as i16).into(); 474 475 if operand_r == 0 { 476 return Err(self.divide_by_zero_error(source)); 477 } 478 479 let quotient = operand_l / operand_r; 480 let remainder = operand_l % operand_r; 481 482 if quotient > i16::MAX.into() || quotient < i16::MIN.into() { 483 self.cpu.registers.ccr = ConditionCodes { 484 carry: false, 485 overflow: true, 486 zero: false, 487 negative: true, 488 ..self.cpu.registers.ccr 489 }; 490 491 return if operand_l.wrapping_abs() >> 16 >= operand_r.abs() { 492 // Absolute overflows take 16 cycles for non-negative dividend and 18 for negative dividend 493 let base_cycles = 16 + 2 * u32::from(operand_l < 0); 494 Ok(base_cycles + source.address_calculation_cycles(OpSize::Word)) 495 } else { 496 // Signed overflows are not detected early and take the normal number of cycles 497 Ok(divs_cycle_count(operand_l, operand_r, quotient, source)) 498 }; 499 } 500 501 let value = ((quotient as u32) & 0x0000_FFFF) | ((remainder as u32) << 16); 502 register.write_long_word_to(&mut self.cpu.registers, value); 503 504 self.cpu.registers.ccr = ConditionCodes { 505 carry: false, 506 overflow: false, 507 zero: quotient == 0, 508 negative: quotient < 0, 509 ..self.cpu.registers.ccr 510 }; 511 512 Ok(divs_cycle_count(operand_l, operand_r, quotient, source)) 513 } 514 515 pub(super) fn divu( 516 &mut self, 517 register: DataRegister, 518 source: AddressingMode, 519 ) -> ExecuteResult<u32> { 520 let operand_l = register.read_from(&self.cpu.registers); 521 let operand_r: u32 = self.read_word(source)?.into(); 522 523 if operand_r == 0 { 524 return Err(self.divide_by_zero_error(source)); 525 } 526 527 let quotient = operand_l / operand_r; 528 let remainder = operand_l % operand_r; 529 530 if quotient > u16::MAX.into() { 531 self.cpu.registers.ccr = ConditionCodes { 532 carry: false, 533 overflow: true, 534 zero: false, 535 negative: true, 536 ..self.cpu.registers.ccr 537 }; 538 539 // Overflow is always 10 cycles plus the time to read the divisor 540 return Ok(10 + source.address_calculation_cycles(OpSize::Word)); 541 } 542 543 let value = (quotient & 0x0000_FFFF) | (remainder << 16); 544 register.write_long_word_to(&mut self.cpu.registers, value); 545 546 self.cpu.registers.ccr = ConditionCodes { 547 carry: false, 548 overflow: false, 549 zero: quotient == 0, 550 negative: quotient.bit(15), 551 ..self.cpu.registers.ccr 552 }; 553 554 Ok(divu_cycle_count(operand_l, operand_r, source)) 555 } 556 557 pub(super) fn abcd( 558 &mut self, 559 source: AddressingMode, 560 dest: AddressingMode, 561 ) -> ExecuteResult<u32> { 562 let operand_l = self.read_byte(source)?; 563 564 let dest_resolved = self.resolve_address(dest, OpSize::Byte)?; 565 let operand_r = self.read_byte_resolved(dest_resolved); 566 567 let extend: u8 = self.cpu.registers.ccr.extend.into(); 568 569 let (sum, carry) = match operand_l.overflowing_add(operand_r) { 570 (sum, true) => (sum + extend, true), 571 (sum, false) => sum.overflowing_add(extend), 572 }; 573 574 let mut diff = 0; 575 if ((operand_l & 0x0F) + (operand_r & 0x0F) + extend >= 0x10) || (sum & 0x0F > 0x09) { 576 diff += 0x06; 577 } 578 if sum > 0x99 || carry { 579 diff += 0x60; 580 } 581 582 let (corrected_sum, corrected_carry) = sum.overflowing_add(diff); 583 584 let bit_6_carry = (sum & 0x7F) + (diff & 0x7F) >= 0x80; 585 let overflow = bit_6_carry != corrected_carry; 586 587 log::trace!("sum={sum:02X}"); 588 589 let carry = carry || corrected_carry; 590 self.cpu.registers.ccr = ConditionCodes { 591 carry, 592 overflow, 593 zero: self.cpu.registers.ccr.zero && corrected_sum == 0, 594 negative: corrected_sum.sign_bit(), 595 extend: carry, 596 }; 597 598 self.write_byte_resolved(dest_resolved, corrected_sum); 599 600 // ABCD only supports Dx,Dy and -(Ax),-(Ay) 601 Ok(match source { 602 AddressingMode::DataDirect(..) => 6, 603 _ => 18, 604 }) 605 } 606 607 pub(super) fn sbcd( 608 &mut self, 609 source: AddressingMode, 610 dest: AddressingMode, 611 ) -> ExecuteResult<u32> { 612 let operand_r = self.read_byte(source)?; 613 614 let dest_resolved = self.resolve_address(dest, OpSize::Byte)?; 615 let operand_l = self.read_byte_resolved(dest_resolved); 616 617 let difference = self.decimal_subtract(operand_l, operand_r); 618 619 self.write_byte_resolved(dest_resolved, difference); 620 621 // SBCD only supports Dx,Dy and -(Ax),-(Ay) 622 Ok(match source { 623 AddressingMode::DataDirect(..) => 6, 624 _ => 18, 625 }) 626 } 627 628 pub(super) fn nbcd(&mut self, dest: AddressingMode) -> ExecuteResult<u32> { 629 let dest_resolved = self.resolve_address_with_post(dest, OpSize::Byte)?; 630 let operand_r = self.read_byte_resolved(dest_resolved); 631 632 let difference = self.decimal_subtract(0, operand_r); 633 634 self.write_byte_resolved(dest_resolved, difference); 635 636 Ok(if dest.is_data_direct() { 6 } else { super::unary_op_cycles(OpSize::Byte, dest) }) 637 } 638 639 fn decimal_subtract(&mut self, operand_l: u8, operand_r: u8) -> u8 { 640 let extend: u8 = self.cpu.registers.ccr.extend.into(); 641 642 let (difference, borrow) = match operand_l.overflowing_sub(operand_r) { 643 (difference, true) => (difference - extend, true), 644 (difference, false) => difference.overflowing_sub(extend), 645 }; 646 647 let mut diff = 0; 648 if operand_l & 0x0F < (operand_r & 0x0F) + extend { 649 diff += 0x06; 650 } 651 if borrow { 652 diff += 0x60; 653 } 654 655 let (corrected_difference, corrected_borrow) = difference.overflowing_sub(diff); 656 657 let bit_6_borrow = difference & 0x7F < diff & 0x7F; 658 let overflow = bit_6_borrow != corrected_borrow; 659 660 let borrow = borrow || corrected_borrow; 661 self.cpu.registers.ccr = ConditionCodes { 662 carry: borrow, 663 overflow, 664 zero: self.cpu.registers.ccr.zero && corrected_difference == 0, 665 negative: corrected_difference.sign_bit(), 666 extend: borrow, 667 }; 668 669 corrected_difference 670 } 671} 672 673fn divu_cycle_count(dividend: u32, divisor: u32, source: AddressingMode) -> u32 { 674 let shifted_divisor = divisor << 16; 675 let mut dividend = dividend; 676 677 let mut added_cycles = 0; 678 for _ in 0..15 { 679 let prev_msb = dividend.bit(31); 680 dividend <<= 1; 681 682 let negative = dividend < shifted_divisor; 683 if prev_msb || !negative { 684 // Subtract if there was a shift out (borrow) or the subtraction result was non-negative 685 dividend = dividend.wrapping_sub(shifted_divisor); 686 } 687 688 // Add 2 cycles if the bit shifted out was a 0 689 added_cycles += 2 * u32::from(!prev_msb); 690 691 // Add 2 cycles if the bit shifted out was a 0 and the subtraction result was negative 692 added_cycles += 2 * u32::from(!prev_msb && negative); 693 } 694 695 76 + added_cycles + source.address_calculation_cycles(OpSize::Word) 696} 697 698fn divs_cycle_count(dividend: i32, divisor: i32, quotient: i32, source: AddressingMode) -> u32 { 699 // All DIVS instructions take at least 120 cycles for a non-negative dividend and 122 for negative 700 let base_cycles = if dividend < 0 { 122 } else { 120 }; 701 702 let mut added_cycles = 0; 703 704 // Add 2 cycles for each 0 in the quotient's absolute value's most significant 15 bits 705 let mut absolute_quotient = quotient.wrapping_abs() as i16; 706 for _ in 0..15 { 707 added_cycles += 2 * u32::from(absolute_quotient >= 0); 708 absolute_quotient <<= 1; 709 } 710 711 if divisor < 0 { 712 // Add 2 cycles for a negative divisor 713 added_cycles += 2; 714 } else if dividend < 0 { 715 // Add 4 cycles for negative dividend + positive divisor 716 added_cycles += 4; 717 } 718 719 base_cycles + added_cycles + source.address_calculation_cycles(OpSize::Word) 720} 721 722macro_rules! impl_add_fn { 723 ($name:ident, $t:ty, $overflow_mask:expr) => { 724 fn $name(operand_l: $t, operand_r: $t, extend: bool) -> ($t, bool, bool) { 725 let extend_operand = <$t>::from(extend); 726 let (sum, carry) = match operand_l.overflowing_add(operand_r) { 727 (sum, true) => (sum + extend_operand, true), 728 (sum, false) => sum.overflowing_add(extend_operand), 729 }; 730 731 let bit_m1_carry = 732 (operand_l & $overflow_mask) + (operand_r & $overflow_mask) + extend_operand 733 > $overflow_mask; 734 let overflow = bit_m1_carry != carry; 735 736 (sum, carry, overflow) 737 } 738 }; 739} 740 741impl_add_fn!(add_bytes, u8, 0x7F); 742impl_add_fn!(add_words, u16, 0x7FFF); 743impl_add_fn!(add_long_words, u32, 0x7FFF_FFFF); 744 745macro_rules! impl_sub_fn { 746 ($name:ident, $t:ty, $overflow_mask:expr) => { 747 fn $name(operand_l: $t, operand_r: $t, extend: bool) -> ($t, bool, bool) { 748 let extend_operand = <$t>::from(extend); 749 let (difference, borrow) = match operand_l.overflowing_sub(operand_r) { 750 (difference, true) => (difference - extend_operand, true), 751 (difference, false) => difference.overflowing_sub(extend_operand), 752 }; 753 754 let bit_m1_borrow = 755 operand_l & $overflow_mask < (operand_r & $overflow_mask) + extend_operand; 756 let overflow = bit_m1_borrow != borrow; 757 758 (difference, borrow, overflow) 759 } 760 }; 761} 762 763impl_sub_fn!(sub_bytes, u8, 0x7F); 764impl_sub_fn!(sub_words, u16, 0x7FFF); 765impl_sub_fn!(sub_long_words, u32, 0x7FFF_FFFF); 766 767macro_rules! impl_compare_fn { 768 ($name:ident, $t:ty, $overflow_mask:expr) => { 769 fn $name(source: $t, dest: $t, ccr: &mut ConditionCodes) { 770 let (difference, borrow) = dest.overflowing_sub(source); 771 let bit_m1_borrow = dest & $overflow_mask < source & $overflow_mask; 772 let overflow = bit_m1_borrow != borrow; 773 774 *ccr = ConditionCodes { 775 carry: borrow, 776 overflow, 777 zero: difference == 0, 778 negative: difference.sign_bit(), 779 ..*ccr 780 }; 781 } 782 }; 783} 784 785impl_compare_fn!(compare_bytes, u8, 0x7F); 786impl_compare_fn!(compare_words, u16, 0x7FFF); 787impl_compare_fn!(compare_long_words, u32, 0x7FFF_FFFF);