Skip to content

Commit

Permalink
sapemu: DAS is a mess
Browse files Browse the repository at this point in the history
Who could have thought? We also have clear disagreement between sources on whether the carry flag is set or not.

224/256
  • Loading branch information
kleinesfilmroellchen committed Sep 28, 2024
1 parent 9f8962e commit b92b269
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 10 deletions.
8 changes: 5 additions & 3 deletions doc/src/reference/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,19 +329,21 @@ The `DIV` instruction divides the YA register by the X register with unsigned in

## `DAA`

The `DAA` instruction provides binary coded decimal (BCD) support together with the `DAS` instruction. If the half-carry flag H is set, decimal adjust for addition will add 6 to convert the result back to decimal. Note that the H flag is the only required flag to be set correctly for this instruction to work, as opposed to e.g. the Z80 which also requires the normal carry flag.
The `DAA` instruction provides binary coded decimal (BCD) support together with the `DAS` instruction. If the half-carry flag H is set, decimal adjust for addition will add 6 to convert the result back to decimal. This also happens if the lower nibble is greater than 9. If the carry flag C is set, decimal adjust for addition will additionally add $60 for adjustment of the upper nibble. This also happens if the upper nibble is greater than 9.

It is not known whether this instruction sets the carry flag in accordance with addition (and whether `DAS` sets the borrow flag in accordance with subtraction). `SingleStepTests` says no, Mesen also says no, Nocash says yes, general logic would imply yes.

| Operand | Opcode | Total bytes | Cycles | Flags set |
| ------- | ------ | ----------- | ------ | --------- |
| A | DF | 1 | 3 | NZC |

## `DAS`

The `DAS` instruction provides binary coded decimal (BCD) support together with the `DAA` instruction. If the half-carry flag H is set, decimal adjust for subtraction will subtract 6 to convert the result back to decimal. Note that the H flag is the only required flag to be set correctly for this instruction to work, as opposed to e.g. the Z80 which also requires the normal carry flag.
The `DAS` instruction provides binary coded decimal (BCD) support together with the `DAA` instruction. If the half-carry flag H is not set (i.e. the half-borrow flag is set), decimal adjust for subtraction will subtract 6 to convert the result back to decimal. This also happens if the lower nibble is greater than 9. If the carry flag C is not set (i.e. the borrow flat is set), decimal adjust for subtraction will additionally subtract by $60 for adjustment of the upper nibble. This also happens if the upper nibble is greater than 9.

| Operand | Opcode | Total bytes | Cycles | Flags set |
| ------- | ------ | ----------- | ------ | --------- |
| A | BE | 1 | 3 | NZC |
| A | BE | 1 | 3 | NZ |

## `BRA`, `BEQ`, `BNE`, `BCS`, `BCC`, `BVS`, `BVC`, `BMI`, `BPL`

Expand Down
24 changes: 22 additions & 2 deletions sapemu/src/smp/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2301,6 +2301,7 @@ fn sbc_x_y_indirect(
debug_instruction!("sbc (x), (y)", cycle, cpu);

match cycle {
0 => MicroArchAction::Continue(InstructionInternalState::default()),
1 => {
let address = cpu.x as u16 + cpu.direct_page_offset();
let operand = cpu.read(address, memory);
Expand Down Expand Up @@ -2360,9 +2361,11 @@ fn movw_ya_dp(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: Instructi
}
}
fn inc_dp_x(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: InstructionInternalState) -> MicroArchAction {
todo!()
debug_instruction!("inc dp+x", cycle, cpu);
inc_dec_dp_x(cpu, memory, cycle, state, |value| value.wrapping_add(1))
}
fn inc_a(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: InstructionInternalState) -> MicroArchAction {
debug_instruction!("inc a", cycle, cpu);
inc_dec_register::<{ Register::A }>(cpu, cycle, |value| value.wrapping_add(1))
}
fn mov_sp_x(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: InstructionInternalState) -> MicroArchAction {
Expand All @@ -2378,7 +2381,24 @@ fn mov_sp_x(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: Instruction
}
}
fn das(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: InstructionInternalState) -> MicroArchAction {
todo!()
debug_instruction!("das", cycle, cpu);

match cycle {
0 | 1 => MicroArchAction::Continue(InstructionInternalState::default()),
2 => {
if !cpu.psw.contains(ProgramStatusWord::Carry) || cpu.a > 0x99 {
cpu.a = cpu.a.wrapping_sub(0x60);
cpu.set_carry(false);
}
if !cpu.psw.contains(ProgramStatusWord::HalfCarry) || cpu.a & 0xf > 0x9 {
cpu.a = cpu.a.wrapping_sub(6);
}
trace!("decimal adjust => {}", cpu.a);
cpu.set_negative_zero(cpu.a);
MicroArchAction::Next
},
_ => unreachable!(),
}
}
fn mov_a_inc_x(cpu: &mut Smp, memory: &mut Memory, cycle: usize, state: InstructionInternalState) -> MicroArchAction {
todo!()
Expand Down
10 changes: 5 additions & 5 deletions sapemu/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,19 @@ impl ProcessorState {
info.push_str(&format!("expected a = {:02x} but got {:02x}\n", self.a, smp.a));
}
if smp.x != self.x {
info.push_str(&format!("expected a = {:02x} but got {:02x}\n", self.x, smp.x));
info.push_str(&format!("expected x = {:02x} but got {:02x}\n", self.x, smp.x));
}
if smp.y != self.y {
info.push_str(&format!("expected a = {:02x} but got {:02x}\n", self.y, smp.y));
info.push_str(&format!("expected y = {:02x} but got {:02x}\n", self.y, smp.y));
}
if smp.psw.bits() != self.psw {
info.push_str(&format!("expected a = {} but got {}\n", ProgramStatusWord(self.psw), smp.psw));
info.push_str(&format!("expected psw = {} but got {}\n", ProgramStatusWord(self.psw), smp.psw));
}
if smp.sp != self.sp {
info.push_str(&format!("expected a = 01{:02x} but got 01{:02x}\n", self.sp, smp.sp));
info.push_str(&format!("expected sp = 01{:02x} but got 01{:02x}\n", self.sp, smp.sp));
}
if smp.pc != self.pc {
info.push_str(&format!("expected a = {:04x} but got {:04x}\n", self.pc, smp.pc));
info.push_str(&format!("expected pc = {:04x} but got {:04x}\n", self.pc, smp.pc));
}
info
}
Expand Down

0 comments on commit b92b269

Please sign in to comment.