-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathharteSuite_test.go
166 lines (140 loc) · 4.09 KB
/
harteSuite_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package iz6502
/*
Tests from https://github.com/TomHarte/ProcessorTests
Know issues:
- 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)
- Test 6502/v1/d3_f4_44 for undocumented opcode DCP (Note 4)
The tests are disabled by default 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"
"io/ioutil"
"testing"
)
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) {
if !ProcessorTestsEnable {
t.Skip("TomHarte/ProcessorTests are not enabled")
}
s := NewNMOS6502(nil) // Use to get the opcodes names
path := ProcessorTestsPath + "6502/v1/"
for i := 0x00; i <= 0xff; i++ {
mnemonic := s.opcodes[i].name
if mnemonic != "" { // Note 2
opcode := fmt.Sprintf("%02x", i)
t.Run(opcode+mnemonic, func(t *testing.T) {
t.Parallel()
m := new(FlatMemory)
s := NewNMOS6502(m)
testOpcode(t, s, path, opcode, mnemonic)
})
}
}
}
func TestHarteCMOS65c02(t *testing.T) {
if !ProcessorTestsEnable {
t.Skip("TomHarte/ProcessorTests are not enabled")
}
s := NewCMOS65c02(nil) // Use to get the opcodes names
path := ProcessorTestsPath + "wdc65c02/v1/"
for i := 0x00; i <= 0xff; i++ {
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, mnemonic string) {
data, err := ioutil.ReadFile(path + opcode + ".json")
if err != nil {
t.Fatal(err)
}
if len(data) == 0 {
return
}
var scenarios []scenario
err = json.Unmarshal(data, &scenarios)
if err != nil {
t.Fatal(err)
}
for _, scenario := range scenarios {
if scenario.Name != "20 55 13" && // Note 1
scenario.Name != "d3 f4 44" { // Note 4
t.Run(scenario.Name, func(t *testing.T) {
testScenario(t, s, &scenario, mnemonic)
})
}
}
}
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)
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)
if s.reg.getFlag(flagD) && (mnemonic == "ADC") {
// Note 3
assertFlags(t, sc, sc.Initial.P, s.reg.getP()&0x7f, sc.Final.P&0x7f)
} 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 {
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)
}
}
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)
}
}