Fixed ADC and SBC in decimal mode. All tests pass.

This commit is contained in:
Ivan Izaguirre 2019-02-10 23:47:54 +01:00
parent f43150c93c
commit 8bd489522f
3 changed files with 108 additions and 55 deletions

View File

@ -221,43 +221,58 @@ func buildOpLogic(operation func(uint8, uint8) uint8) opFunc {
func opADC(s *state, line []uint8, opcode opcode) { func opADC(s *state, line []uint8, opcode opcode) {
value, _, _ := resolve(s, line, opcode) value, _, _ := resolve(s, line, opcode)
if s.registers.getFlag(flagD) { aValue := s.registers.getA()
// TODO BCD. See http://www.6502.org/tutorials/decimal_mode.html carry := s.registers.getFlagBit(flagC)
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)
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.setA(truncated)
s.registers.updateFlagZN(truncated)
s.registers.updateFlag(flagC, total > 0xFF) 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) { func opSBC(s *state, line []uint8, opcode opcode) {
value, _, _ := resolve(s, line, 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) { if s.registers.getFlag(flagD) {
// TODO BCD totalBcdLo := 10 + int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1
panic("BCD not supported") 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 { } 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.setA(truncated)
s.registers.updateFlagZN(truncated)
s.registers.updateFlag(flagC, total > 0xFF) 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 const stackAddress uint16 = 0x0100

View File

@ -268,30 +268,65 @@ func TestAdd(t *testing.T) {
s.registers.clearFlag(flagC) s.registers.clearFlag(flagC)
executeLine(&s, []uint8{0x69, 0x0B}) executeLine(&s, []uint8{0x69, 0x0B})
if s.registers.getA() != 0xAB { 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) { 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.setA(0xFF)
s.registers.clearFlag(flagC) s.registers.clearFlag(flagC)
executeLine(&s, []uint8{0x69, 0x02}) executeLine(&s, []uint8{0x69, 0x02})
if s.registers.getA() != 0x01 { 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) { 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.setA(0xA0)
s.registers.setFlag(flagC) s.registers.setFlag(flagC)
executeLine(&s, []uint8{0x69, 0x01}) executeLine(&s, []uint8{0x69, 0x01})
if s.registers.getA() != 0xA2 { 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) { 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.setA(0x09)
s.registers.clearFlag(flagC) s.registers.clearFlag(flagC)
executeLine(&s, []uint8{0xE9, 0x05}) executeLine(&s, []uint8{0xE9, 0x05})
if s.registers.getA() != 0x04 { if s.registers.getA() != 0x03 {
t.Errorf("Error in SBC A0 + 0B. %v", s.registers) t.Errorf("Error in SBC. %v", s.registers)
} }
if s.registers.getFlag(flagC) { if !s.registers.getFlag(flagC) {
t.Errorf("Error in carry SBC A0 + 0B. %v", s.registers) t.Errorf("Error in carry SBC. %v", s.registers)
} }
s.registers.setA(0x01) s.registers.setA(0x01)
s.registers.clearFlag(flagC) s.registers.clearFlag(flagC)
executeLine(&s, []uint8{0xE9, 0x02}) executeLine(&s, []uint8{0xE9, 0x02})
if s.registers.getA() != 0xFF { if s.registers.getA() != 0xFE {
t.Errorf("Error in SBC A0 + 0B with carry. %v", s.registers) t.Errorf("Error in SBC with carry. %v", s.registers)
} }
if !s.registers.getFlag(flagC) { if s.registers.getFlag(flagC) {
t.Errorf("Error in carry SBC A0 + 0B with carry. %v", s.registers) t.Errorf("Error in carry SBC with carry. %v", s.registers)
} }
s.registers.setA(0x08) s.registers.setA(0x08)
s.registers.setFlag(flagC) s.registers.setFlag(flagC)
executeLine(&s, []uint8{0xE9, 0x02}) executeLine(&s, []uint8{0xE9, 0x02})
if s.registers.getA() != 0x05 { if s.registers.getA() != 0x06 {
t.Errorf("Error in SBC C + A0 + 0B with carry. %v", s.registers) t.Errorf("Error in carried SBC with carry. %v", s.registers)
} }
if s.registers.getFlag(flagC) { if !s.registers.getFlag(flagC) {
t.Errorf("Error in carry SBC C + A0 + 0B with carry. %v", s.registers) t.Errorf("Error in carry in carried SBC with carry. %v", s.registers)
} }
} }

29
main.go
View File

@ -8,19 +8,22 @@ func main() {
s.registers.setPC(0x0400) s.registers.setPC(0x0400)
for true { for true {
for i := 0; i < 20; i++ { testCase := s.memory[0x0200]
testCase := s.memory[0x0200] if testCase >= 240 {
log := testCase > 41 break
if log { }
fmt.Printf("[ %d ] ", testCase) log := testCase > 43
} if log {
pc := s.registers.getPC() fmt.Printf("[ %d ] ", testCase)
executeInstruction(&s, log) }
if pc == s.registers.getPC() { pc := s.registers.getPC()
s.memory.printPage(0x00) executeInstruction(&s, log)
//s.memory.printPage(0x01) if pc == s.registers.getPC() {
panic("No change in PC") //s.memory.printPage(0x00)
} //s.memory.printPage(0x01)
panic("No change in PC")
} }
} }
fmt.Printf("Test completed\n")
} }