mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-01-10 12:30:17 +00:00
Fixes for ADC and SBC on BCD mode
This commit is contained in:
parent
7143cdc2de
commit
2a7cf020ae
@ -26,6 +26,7 @@ type State struct {
|
||||
|
||||
extraCycleCrossingBoundaries bool
|
||||
extraCycleBranchTaken bool
|
||||
extraCycleBCD bool
|
||||
lineCache []uint8
|
||||
// We cache the allocation of a line to avoid a malloc per instruction. To be used only
|
||||
// by ExecuteInstruction(). 2x speedup on the emulation!!
|
||||
@ -81,6 +82,7 @@ func (s *State) ExecuteInstruction() {
|
||||
opcode.action(s, s.lineCache, opcode)
|
||||
s.cycles += uint64(opcode.cycles)
|
||||
|
||||
// Extra cycles
|
||||
if s.extraCycleBranchTaken {
|
||||
s.cycles++
|
||||
s.extraCycleBranchTaken = false
|
||||
@ -89,6 +91,10 @@ func (s *State) ExecuteInstruction() {
|
||||
s.cycles++
|
||||
s.extraCycleCrossingBoundaries = false
|
||||
}
|
||||
if s.extraCycleBCD {
|
||||
s.cycles++
|
||||
s.extraCycleBCD = false
|
||||
}
|
||||
|
||||
if s.trace {
|
||||
fmt.Printf("%v, [%02x]\n", s.reg, s.lineCache[0:opcode.bytes])
|
||||
|
@ -35,17 +35,20 @@ func TestHarteNMOS6502(t *testing.T) {
|
||||
|
||||
path := "/home/casa/code/ProcessorTests/6502/v1/"
|
||||
for i := 0x00; i <= 0xff; i++ {
|
||||
if s.opcodes[i].name != "ADC" && // Issue with ADC crossing page boundaries
|
||||
s.opcodes[i].name != "SBC" && // Issue with ADC crossing page boundaries
|
||||
s.opcodes[i].name != "" {
|
||||
|
||||
mnemonic := s.opcodes[i].name
|
||||
if mnemonic != "" {
|
||||
opcode := fmt.Sprintf("%02x", i)
|
||||
t.Run(opcode+s.opcodes[i].name, func(t *testing.T) {
|
||||
t.Run(opcode+mnemonic, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := new(FlatMemory)
|
||||
s := NewNMOS6502(m)
|
||||
testOpcode(t, s, path, opcode)
|
||||
testOpcode(t, s, path, opcode, mnemonic)
|
||||
})
|
||||
//} else {
|
||||
// opcode := fmt.Sprintf("%02x", i)
|
||||
// t.Run(opcode+mnemonic, func(t *testing.T) {
|
||||
// t.Error("Opcode not implemented")
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,21 +60,18 @@ func TestHarteCMOS65c02(t *testing.T) {
|
||||
|
||||
path := "/home/casa/code/ProcessorTests/wdc65c02/v1/"
|
||||
for i := 0x00; i <= 0xff; i++ {
|
||||
if s.opcodes[i].name != "ADC" && // Issue with ADC crossing page boundaries
|
||||
s.opcodes[i].name != "SBC" { // Issue with SBC crossing page boundaries
|
||||
|
||||
opcode := fmt.Sprintf("%02x", i)
|
||||
t.Run(opcode+s.opcodes[i].name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := new(FlatMemory)
|
||||
s := NewCMOS65c02(m)
|
||||
testOpcode(t, s, path, opcode)
|
||||
})
|
||||
}
|
||||
mnemonic := s.opcodes[i].name
|
||||
opcode := fmt.Sprintf("%02x", i)
|
||||
t.Run(opcode+mnemonic, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := new(FlatMemory)
|
||||
s := NewCMOS65c02(m)
|
||||
testOpcode(t, s, path, opcode, mnemonic)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testOpcode(t *testing.T, s *State, path string, opcode string) {
|
||||
func testOpcode(t *testing.T, s *State, path string, opcode string, mnemonic string) {
|
||||
data, err := ioutil.ReadFile(path + opcode + ".json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -88,15 +88,15 @@ func testOpcode(t *testing.T, s *State, path string, opcode string) {
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
if scenario.Name != "20 55 13" { // Skip JSR on the stack being modified
|
||||
if scenario.Name != "20 55 13" { // TODO: FIx JSR on the stack being modified
|
||||
t.Run(scenario.Name, func(t *testing.T) {
|
||||
testScenario(t, s, &scenario)
|
||||
testScenario(t, s, &scenario, mnemonic)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testScenario(t *testing.T, s *State, sc *scenario) {
|
||||
func testScenario(t *testing.T, s *State, sc *scenario, mnemonic string) {
|
||||
// Setup CPU
|
||||
start := s.GetCycles()
|
||||
s.reg.setPC(sc.Initial.Pc)
|
||||
@ -105,6 +105,7 @@ func testScenario(t *testing.T, s *State, sc *scenario) {
|
||||
s.reg.setX(sc.Initial.X)
|
||||
s.reg.setY(sc.Initial.Y)
|
||||
s.reg.setP(sc.Initial.P)
|
||||
|
||||
for _, e := range sc.Initial.Ram {
|
||||
s.mem.Poke(uint16(e[0]), uint8(e[1]))
|
||||
}
|
||||
@ -116,7 +117,12 @@ func testScenario(t *testing.T, s *State, sc *scenario) {
|
||||
assertReg8(t, sc, "A", s.reg.getA(), sc.Final.A)
|
||||
assertReg8(t, sc, "X", s.reg.getX(), sc.Final.X)
|
||||
assertReg8(t, sc, "Y", s.reg.getY(), sc.Final.Y)
|
||||
assertFlags(t, sc, sc.Initial.P, s.reg.getP(), sc.Final.P)
|
||||
if s.reg.getFlag(flagD) && (mnemonic == "ADC") {
|
||||
// TODO: fix N and V flags for ADC with BCD
|
||||
assertFlags(t, sc, sc.Initial.P, s.reg.getP()&0x3f, sc.Final.P&0x3f)
|
||||
} else {
|
||||
assertFlags(t, sc, sc.Initial.P, s.reg.getP(), sc.Final.P)
|
||||
}
|
||||
assertReg8(t, sc, "SP", s.reg.getSP(), sc.Final.S)
|
||||
assertReg16(t, sc, "PC", s.reg.getPC(), sc.Final.Pc)
|
||||
|
||||
@ -128,13 +134,13 @@ func testScenario(t *testing.T, s *State, sc *scenario) {
|
||||
|
||||
func assertReg8(t *testing.T, sc *scenario, name string, actual uint8, wanted uint8) {
|
||||
if actual != wanted {
|
||||
t.Errorf("Register %s is %02x and should be %02x for %+v", name, actual, wanted, sc)
|
||||
t.Errorf("Register %s is $%02x and should be $%02x for %+v", name, actual, wanted, sc)
|
||||
}
|
||||
}
|
||||
|
||||
func assertReg16(t *testing.T, sc *scenario, name string, actual uint16, wanted uint16) {
|
||||
if actual != wanted {
|
||||
t.Errorf("Register %s is %04x and should be %04x for %+v", name, actual, wanted, sc)
|
||||
t.Errorf("Register %s is $%04x and should be $%04x for %+v", name, actual, wanted, sc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,23 +170,35 @@ func opADC(s *State, line []uint8, opcode opcode) {
|
||||
totalBcdLo := int(aValue&0x0f) + int(value&0x0f) + int(carry)
|
||||
totalBcdHi := int(aValue>>4) + int(value>>4)
|
||||
if totalBcdLo >= 10 {
|
||||
totalBcdLo -= 10
|
||||
totalBcdHi++
|
||||
}
|
||||
totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10)
|
||||
newCarry := false
|
||||
if totalBcdHi >= 10 {
|
||||
totalBcdHi -= 10
|
||||
newCarry = true
|
||||
}
|
||||
totalBcd := uint8(totalBcdHi)<<4 + (uint8(totalBcdLo) & 0xf)
|
||||
s.reg.setA(uint8(totalBcd))
|
||||
s.reg.updateFlag(flagC, totalBcdHi > 9)
|
||||
s.reg.updateFlag(flagC, newCarry)
|
||||
s.reg.updateFlagZN(truncated)
|
||||
s.reg.updateFlag(flagV, signedTotal < -128 || signedTotal > 127)
|
||||
} else {
|
||||
s.reg.setA(truncated)
|
||||
s.reg.updateFlag(flagC, total > 0xFF)
|
||||
s.reg.updateFlagZN(truncated)
|
||||
s.reg.updateFlag(flagV, signedTotal < -128 || signedTotal > 127)
|
||||
}
|
||||
|
||||
// ZNV flags behave for BCD as if the operation was binary?
|
||||
s.reg.updateFlagZN(truncated)
|
||||
s.reg.updateFlag(flagV, signedTotal < -128 || signedTotal > 127)
|
||||
}
|
||||
|
||||
func opADCAlt(s *State, line []uint8, opcode opcode) {
|
||||
opADC(s, line, opcode)
|
||||
if s.reg.getFlag(flagD) {
|
||||
s.extraCycleBCD = true
|
||||
}
|
||||
|
||||
// The Z and N flags on BCD are fixed in 65c02.
|
||||
s.reg.updateFlagZN(s.reg.getA())
|
||||
}
|
||||
@ -201,14 +213,20 @@ func opSBC(s *State, line []uint8, opcode opcode) {
|
||||
truncated := uint8(total)
|
||||
|
||||
if s.reg.getFlag(flagD) {
|
||||
totalBcdLo := 10 + int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1
|
||||
totalBcdHi := 10 + int(aValue>>4) - int(value>>4)
|
||||
if totalBcdLo < 10 {
|
||||
totalBcdLo := int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1
|
||||
totalBcdHi := int(aValue>>4) - int(value>>4)
|
||||
if totalBcdLo < 0 {
|
||||
totalBcdLo += 10
|
||||
totalBcdHi--
|
||||
}
|
||||
totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10)
|
||||
newCarry := true
|
||||
if totalBcdHi < 0 {
|
||||
totalBcdHi += 10
|
||||
newCarry = false
|
||||
}
|
||||
totalBcd := uint8(totalBcdHi)<<4 + (uint8(totalBcdLo) & 0xf)
|
||||
s.reg.setA(uint8(totalBcd))
|
||||
s.reg.updateFlag(flagC, totalBcdHi >= 10)
|
||||
s.reg.updateFlag(flagC, newCarry)
|
||||
} else {
|
||||
s.reg.setA(truncated)
|
||||
s.reg.updateFlag(flagC, total > 0xFF)
|
||||
@ -221,6 +239,9 @@ func opSBC(s *State, line []uint8, opcode opcode) {
|
||||
|
||||
func opSBCAlt(s *State, line []uint8, opcode opcode) {
|
||||
opSBC(s, line, opcode)
|
||||
if s.reg.getFlag(flagD) {
|
||||
s.extraCycleBCD = true
|
||||
}
|
||||
// The Z and N flags on BCD are fixed in 65c02.
|
||||
s.reg.updateFlagZN(s.reg.getA())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user