diff --git a/execute.go b/execute.go index 6f82609..6b98d4b 100644 --- a/execute.go +++ b/execute.go @@ -221,43 +221,58 @@ func buildOpLogic(operation func(uint8, uint8) uint8) opFunc { func opADC(s *state, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - if s.registers.getFlag(flagD) { - // TODO BCD. See http://www.6502.org/tutorials/decimal_mode.html - panic("BCD not supported") - } else { - total := uint16(s.registers.getA()) + - uint16(value) + - uint16(s.registers.getFlagBit(flagC)) - signedTotal := int16(int8(s.registers.getA())) + - int16(int8(value)) + - int16(s.registers.getFlagBit(flagC)) - truncated := uint8(total) + aValue := s.registers.getA() + carry := s.registers.getFlagBit(flagC) + total := uint16(aValue) + uint16(value) + uint16(carry) + signedTotal := int16(int8(aValue)) + int16(int8(value)) + int16(carry) + truncated := uint8(total) + + if s.registers.getFlag(flagD) { + totalBcdLo := int(aValue&0x0f) + int(value&0x0f) + int(carry) + totalBcdHi := int(aValue>>4) + int(value>>4) + if totalBcdLo >= 10 { + totalBcdHi++ + } + totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10) + s.registers.setA(uint8(totalBcd)) + s.registers.updateFlag(flagC, totalBcdHi > 9) + } else { s.registers.setA(truncated) - s.registers.updateFlagZN(truncated) s.registers.updateFlag(flagC, total > 0xFF) - s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) } + + // ZNV flags behave for BCD as if the operation was binary? + s.registers.updateFlagZN(truncated) + s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) } func opSBC(s *state, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) + aValue := s.registers.getA() + carry := s.registers.getFlagBit(flagC) + + total := 0x100 + uint16(aValue) - uint16(value) + uint16(carry) - 1 + signedTotal := int16(int8(aValue)) - int16(int8(value)) + int16(carry) - 1 + truncated := uint8(total) + if s.registers.getFlag(flagD) { - // TODO BCD - panic("BCD not supported") + totalBcdLo := 10 + int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1 + totalBcdHi := 10 + int(aValue>>4) - int(value>>4) + if totalBcdLo < 10 { + totalBcdHi-- + } + totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10) + s.registers.setA(uint8(totalBcd)) + s.registers.updateFlag(flagC, totalBcdHi >= 10) } else { - total := 0x100 + uint16(s.registers.getA()) - - uint16(value) + - uint16(s.registers.getFlagBit(flagC)) - 1 - signedTotal := int16(int8(s.registers.getA())) - - int16(int8(value)) + - int16(s.registers.getFlagBit(flagC)) - 1 - truncated := uint8(total) s.registers.setA(truncated) - s.registers.updateFlagZN(truncated) s.registers.updateFlag(flagC, total > 0xFF) - s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) } + + // ZNV flags behave for SBC as if the operation was binary + s.registers.updateFlagZN(truncated) + s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) } const stackAddress uint16 = 0x0100 diff --git a/execute_test.go b/execute_test.go index 03fe4ea..8e4ba50 100644 --- a/execute_test.go +++ b/execute_test.go @@ -268,30 +268,65 @@ func TestAdd(t *testing.T) { s.registers.clearFlag(flagC) executeLine(&s, []uint8{0x69, 0x0B}) if s.registers.getA() != 0xAB { - t.Errorf("Error in ADC A0 + 0B. %v", s.registers) + t.Errorf("Error in ADC. %v", s.registers) } if s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC A0 + 0B. %v", s.registers) + t.Errorf("Error in carry ADC. %v", s.registers) } s.registers.setA(0xFF) s.registers.clearFlag(flagC) executeLine(&s, []uint8{0x69, 0x02}) if s.registers.getA() != 0x01 { - t.Errorf("Error in ADC A0 + 0B with carry. %v", s.registers) + t.Errorf("Error in ADC with carry. %v", s.registers) } if !s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC A0 + 0B with carry. %v", s.registers) + t.Errorf("Error in carry ADC with carry. %v", s.registers) } s.registers.setA(0xA0) s.registers.setFlag(flagC) executeLine(&s, []uint8{0x69, 0x01}) if s.registers.getA() != 0xA2 { - t.Errorf("Error in ADC C + A0 + 0B with carry. %v", s.registers) + t.Errorf("Error in carried ADC with carry. %v", s.registers) } if s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC C + A0 + 0B with carry. %v", s.registers) + t.Errorf("Error in carry in carried ADC with carry. %v", s.registers) + } +} + +func TestAddDecimal(t *testing.T) { + var s state + s.registers.setFlag(flagD) + + s.registers.setA(0x12) + s.registers.clearFlag(flagC) + executeLine(&s, []uint8{0x69, 0x013}) + if s.registers.getA() != 0x25 { + t.Errorf("Error in ADC decimal. %v", s.registers) + } + if s.registers.getFlag(flagC) { + t.Errorf("Error in carry ADC. %v", s.registers) + } + + s.registers.setA(0x44) + s.registers.clearFlag(flagC) + executeLine(&s, []uint8{0x69, 0x68}) + if s.registers.getA() != 0x12 { + t.Errorf("Error in ADC decimal with carry. %v", s.registers) + } + if !s.registers.getFlag(flagC) { + t.Errorf("Error in carry ADC decimal with carry. %v", s.registers) + } + + s.registers.setA(0x44) + s.registers.setFlag(flagC) + executeLine(&s, []uint8{0x69, 0x23}) + if s.registers.getA() != 0x68 { + t.Errorf("Error in carried ADC decimal with carry. %v", s.registers) + } + if s.registers.getFlag(flagC) { + t.Errorf("Error in carry in carried ADC decimal with carry. %v", s.registers) } } @@ -301,31 +336,31 @@ func TestSub(t *testing.T) { s.registers.setA(0x09) s.registers.clearFlag(flagC) executeLine(&s, []uint8{0xE9, 0x05}) - if s.registers.getA() != 0x04 { - t.Errorf("Error in SBC A0 + 0B. %v", s.registers) + if s.registers.getA() != 0x03 { + t.Errorf("Error in SBC. %v", s.registers) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry SBC A0 + 0B. %v", s.registers) + if !s.registers.getFlag(flagC) { + t.Errorf("Error in carry SBC. %v", s.registers) } s.registers.setA(0x01) s.registers.clearFlag(flagC) executeLine(&s, []uint8{0xE9, 0x02}) - if s.registers.getA() != 0xFF { - t.Errorf("Error in SBC A0 + 0B with carry. %v", s.registers) + if s.registers.getA() != 0xFE { + t.Errorf("Error in SBC with carry. %v", s.registers) } - if !s.registers.getFlag(flagC) { - t.Errorf("Error in carry SBC A0 + 0B with carry. %v", s.registers) + if s.registers.getFlag(flagC) { + t.Errorf("Error in carry SBC with carry. %v", s.registers) } s.registers.setA(0x08) s.registers.setFlag(flagC) executeLine(&s, []uint8{0xE9, 0x02}) - if s.registers.getA() != 0x05 { - t.Errorf("Error in SBC C + A0 + 0B with carry. %v", s.registers) + if s.registers.getA() != 0x06 { + t.Errorf("Error in carried SBC with carry. %v", s.registers) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry SBC C + A0 + 0B with carry. %v", s.registers) + if !s.registers.getFlag(flagC) { + t.Errorf("Error in carry in carried SBC with carry. %v", s.registers) } } diff --git a/main.go b/main.go index e8b60b0..aa8014f 100644 --- a/main.go +++ b/main.go @@ -8,19 +8,22 @@ func main() { s.registers.setPC(0x0400) for true { - for i := 0; i < 20; i++ { - testCase := s.memory[0x0200] - log := testCase > 41 - if log { - fmt.Printf("[ %d ] ", testCase) - } - pc := s.registers.getPC() - executeInstruction(&s, log) - if pc == s.registers.getPC() { - s.memory.printPage(0x00) - //s.memory.printPage(0x01) - panic("No change in PC") - } + testCase := s.memory[0x0200] + if testCase >= 240 { + break + } + log := testCase > 43 + if log { + fmt.Printf("[ %d ] ", testCase) + } + pc := s.registers.getPC() + executeInstruction(&s, log) + if pc == s.registers.getPC() { + //s.memory.printPage(0x00) + //s.memory.printPage(0x01) + panic("No change in PC") } } + + fmt.Printf("Test completed\n") }