izapple2/core6502/harteSuite_test.go

169 lines
4.1 KiB
Go
Raw Normal View History

package core6502
2021-09-26 16:25:11 +00:00
/*
Tests from https://github.com/TomHarte/ProcessorTests
Know issues:
2021-09-26 21:29:11 +00:00
- Test 6502/v1/20_55_13 (Note 1)
- Not implemented undocumented opcodes for NMOS (Note 2)
- Errors on flag N for ADC in BCD mode (Note 3)
2021-09-26 16:25:11 +00:00
The tests are disabled by defaut because they take long to run
and require a huge download.
To enable them, clone the repo https://github.com/TomHarte/ProcessorTests
and change the variables ProcessorTestsEnable and ProcessorTestsPath.
*/
import (
"encoding/json"
"fmt"
2021-09-25 23:43:21 +00:00
"io/ioutil"
"testing"
)
2021-09-26 16:25:11 +00:00
var ProcessorTestsEnable = false
var ProcessorTestsPath = "/home/casa/code/ProcessorTests/"
type scenarioState struct {
Pc uint16
S uint8
A uint8
X uint8
Y uint8
P uint8
Ram [][]uint16
}
type scenario struct {
Name string
Initial scenarioState
Final scenarioState
Cycles [][]interface{}
}
func TestHarteNMOS6502(t *testing.T) {
2021-09-26 16:25:11 +00:00
if !ProcessorTestsEnable {
t.Skip("TomHarte/ProcessorTests are not enabled")
}
s := NewNMOS6502(nil) // Use to get the opcodes names
2021-09-26 16:25:11 +00:00
path := ProcessorTestsPath + "6502/v1/"
for i := 0x00; i <= 0xff; i++ {
2021-09-26 15:32:15 +00:00
mnemonic := s.opcodes[i].name
2021-09-26 21:29:11 +00:00
if mnemonic != "" { // Note 2
opcode := fmt.Sprintf("%02x", i)
2021-09-26 15:32:15 +00:00
t.Run(opcode+mnemonic, func(t *testing.T) {
t.Parallel()
2021-09-25 19:11:15 +00:00
m := new(FlatMemory)
s := NewNMOS6502(m)
2021-09-26 15:32:15 +00:00
testOpcode(t, s, path, opcode, mnemonic)
})
2021-09-26 15:32:15 +00:00
//} else {
// opcode := fmt.Sprintf("%02x", i)
// t.Run(opcode+mnemonic, func(t *testing.T) {
// t.Error("Opcode not implemented")
// })
}
}
}
2021-09-25 19:11:15 +00:00
func TestHarteCMOS65c02(t *testing.T) {
2021-09-26 16:25:11 +00:00
if !ProcessorTestsEnable {
t.Skip("TomHarte/ProcessorTests are not enabled")
}
2021-09-25 19:11:15 +00:00
s := NewCMOS65c02(nil) // Use to get the opcodes names
2021-09-26 16:25:11 +00:00
path := ProcessorTestsPath + "wdc65c02/v1/"
for i := 0x00; i <= 0xff; i++ {
2021-09-26 15:32:15 +00:00
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)
})
2021-09-25 19:11:15 +00:00
}
}
2021-09-26 15:32:15 +00:00
func testOpcode(t *testing.T, s *State, path string, opcode string, mnemonic string) {
2021-09-25 23:43:21 +00:00
data, err := ioutil.ReadFile(path + opcode + ".json")
if err != nil {
t.Fatal(err)
}
2021-09-25 19:11:15 +00:00
if len(data) == 0 {
return
}
var scenarios []scenario
err = json.Unmarshal(data, &scenarios)
if err != nil {
t.Fatal(err)
}
for _, scenario := range scenarios {
2021-09-26 21:29:11 +00:00
if scenario.Name != "20 55 13" { // Note 1
t.Run(scenario.Name, func(t *testing.T) {
2021-09-26 15:32:15 +00:00
testScenario(t, s, &scenario, mnemonic)
})
}
}
}
2021-09-26 15:32:15 +00:00
func testScenario(t *testing.T, s *State, sc *scenario, mnemonic string) {
// Setup CPU
start := s.GetCycles()
s.reg.setPC(sc.Initial.Pc)
s.reg.setSP(sc.Initial.S)
s.reg.setA(sc.Initial.A)
s.reg.setX(sc.Initial.X)
s.reg.setY(sc.Initial.Y)
s.reg.setP(sc.Initial.P)
2021-09-26 15:32:15 +00:00
for _, e := range sc.Initial.Ram {
s.mem.Poke(uint16(e[0]), uint8(e[1]))
}
// Execute instruction
s.ExecuteInstruction()
// Check result
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)
2021-09-26 15:32:15 +00:00
if s.reg.getFlag(flagD) && (mnemonic == "ADC") {
2021-09-26 21:29:11 +00:00
// Note 3
assertFlags(t, sc, sc.Initial.P, s.reg.getP()&0x7f, sc.Final.P&0x7f)
2021-09-26 15:32:15 +00:00
} 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)
cycles := s.GetCycles() - start
if cycles != uint64(len(sc.Cycles)) {
t.Errorf("Took %v cycles, it should be %v for %+v", cycles, len(sc.Cycles), sc)
}
}
func assertReg8(t *testing.T, sc *scenario, name string, actual uint8, wanted uint8) {
if actual != wanted {
2021-09-26 15:32:15 +00:00
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 {
2021-09-26 15:32:15 +00:00
t.Errorf("Register %s is $%04x and should be $%04x for %+v", name, actual, wanted, sc)
}
}
func assertFlags(t *testing.T, sc *scenario, initial uint8, actual uint8, wanted uint8) {
if actual != wanted {
t.Errorf("%08b flag diffs, they are %08b and should be %08b, initial %08b for %+v", actual^wanted, actual, wanted, initial, sc)
}
}