1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-06-06 20:29:34 +00:00
go6502/tests/compare_test.go

190 lines
3.5 KiB
Go

/*
Tests for the 6502 CPU emulator, comparing it with the transistor-level simulation.
*/
package tests
import (
"fmt"
"io/ioutil"
"testing"
"github.com/zellyn/go6502/asm"
"github.com/zellyn/go6502/asm/flavors/scma"
"github.com/zellyn/go6502/asm/lines"
"github.com/zellyn/go6502/asm/opcodes"
"github.com/zellyn/go6502/cpu"
"github.com/zellyn/go6502/visual"
)
// Run the first few thousand steps of Klaus Dormann's comprehensive
// test against the instruction- and gate-level CPU emulations, making
// sure they have the same memory access patterns.
func TestFunctionalTestCompare(t *testing.T) {
_ = []uint16{
0,
4327,
4288,
4253,
4221,
4194,
4171,
4152,
4137,
4105,
4374,
4368,
}
bytes, err := ioutil.ReadFile("6502_functional_test.bin")
if err != nil {
panic("Cannot read file")
}
var m Memorizer
OFFSET := 0xa
copy(m.mem1[OFFSET:len(bytes)+OFFSET], bytes)
copy(m.mem2[OFFSET:len(bytes)+OFFSET], bytes)
// Set the RESET vector to jump to the tests
m.mem1[0xFFFC] = 0x00
m.mem1[0xFFFD] = 0x10
m.mem2[0xFFFC] = 0x00
m.mem2[0xFFFD] = 0x10
v := visual.NewCPU(&m)
v.Reset()
for i := 0; i < 8; i++ {
v.Step()
}
var cc CycleCount
c := cpu.NewCPU(&m, cc.Tick, cpu.VERSION_6502)
c.Reset()
m.Reset(MODE_RECORD)
v.Step()
v.Step()
m.Verify()
c.Step()
if len(m.errors) > 0 {
t.Fatal("Errors on reset", m.errors)
}
for {
m.Record()
for i := 0; i < 1000; i++ {
v.Step()
}
m.Verify()
for len(m.ops) > 7 {
s := status(c, &m.mem2, uint64(cc))
c.Step()
if len(m.errors) > 0 {
t.Fatalf("Error at %v: %v", s, m.errors)
}
if cc%1000 == 0 {
pc := c.PC()
if cc > 20000 || pc == 0x3CC5 {
return
}
}
}
}
}
func getTestProgram() ([]byte, error) {
o := lines.NewTestOpener()
a := asm.NewAssembler(scma.New(opcodes.SetSweet16), o)
o["FILE"] = `
cld
ldx #$ff
txs
lda #$ff
sta $70
lda #$0e
sta $71
ldy #0
adc ($70),Y
ldy #1
clc
adc ($70),Y
sec
adc ($70),Y
ldx #0
inc $3412,X
ldx $ff
clc
inc $3412,X
sec
inc $3412,X
jmp 0
`
if err := a.Load("FILE", 0); err != nil {
return nil, err
}
if err := a.Pass2(); err != nil {
return nil, err
}
bb, err := a.RawBytes()
if err != nil {
return nil, fmt.Errorf("a.RawBytes() failed: %v", err)
}
return bb, nil
}
// Test a custom test program against the instruction- and gate-level
// CPU emulations, making sure they have the same memory access
// patterns.
func TestCustomTestCompare(t *testing.T) {
bytes, err := getTestProgram()
if err != nil {
t.Fatalf("Failed to assemble test program: %v", err)
}
var m Memorizer
START := 0x6000
copy(m.mem1[START:], bytes)
copy(m.mem2[START:], bytes)
// Set the RESET vector to jump to the tests
m.mem1[0xFFFC] = byte(START % 256)
m.mem1[0xFFFD] = byte(START / 256)
m.mem2[0xFFFC] = byte(START % 256)
m.mem2[0xFFFD] = byte(START / 256)
v := visual.NewCPU(&m)
v.Reset()
for i := 0; i < 8; i++ {
v.Step()
}
var cc CycleCount
c := cpu.NewCPU(&m, cc.Tick, cpu.VERSION_6502)
c.Reset()
m.Reset(MODE_RECORD)
v.Step()
v.Step()
m.Verify()
c.Step()
if len(m.errors) > 0 {
t.Fatal("Errors on reset", m.errors)
}
for {
m.Record()
for i := 0; i < 1000; i++ {
v.Step()
}
m.Verify()
for len(m.ops) > 7 {
s := status(c, &m.mem2, uint64(cc))
c.Step()
if len(m.errors) > 0 {
t.Fatalf("Error at %v: %v", s, m.errors)
}
pc := c.PC()
fmt.Printf("%04X\n", pc)
if pc == 0x00 {
return
}
}
}
}