mirror of
https://github.com/zellyn/go6502.git
synced 2025-01-14 00:31:39 +00:00
Translate perfect6502 to go.
This commit is contained in:
parent
b268e242f8
commit
9605e2d69f
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/zellyn/go6502/asm"
|
||||
"github.com/zellyn/go6502/cpu"
|
||||
"github.com/zellyn/go6502/visual"
|
||||
)
|
||||
|
||||
// Memory for the tests. Satisfies the cpu.Memory interface.
|
||||
@ -37,14 +38,15 @@ func randomize(k *K64) {
|
||||
}
|
||||
|
||||
// printStatus prints out the current CPU instruction and register status.
|
||||
func printStatus(c cpu.Cpu, m K64, cc CycleCount) {
|
||||
func printStatus(c cpu.Cpu, m K64) {
|
||||
bytes, text, _ := asm.Disasm(c.PC(), m[c.PC()], m[c.PC()+1], m[c.PC()+2])
|
||||
fmt.Printf("$%04X: %s %s A=$%02X X=$%02X Y=$%02X SP=$%02X P=$%08b - %d\n",
|
||||
c.PC(), bytes, text, c.A(), c.X(), c.Y(), c.SP(), c.P(), cc)
|
||||
fmt.Printf("$%04X: %s %s A=$%02X X=$%02X Y=$%02X SP=$%02X P=$%08b\n",
|
||||
c.PC(), bytes, text, c.A(), c.X(), c.Y(), c.SP(), c.P())
|
||||
}
|
||||
|
||||
// Run Klaus Dormann's amazing comprehensive test.
|
||||
func TestFunctionalTest(t *testing.T) {
|
||||
// Run Klaus Dormann's amazing comprehensive test against the
|
||||
// instruction-level CPU emulation.
|
||||
func TestFunctionalTestInstructions(t *testing.T) {
|
||||
unused := map[byte]bool{}
|
||||
for k, _ := range cpu.Opcodes {
|
||||
unused[k] = true
|
||||
@ -74,6 +76,7 @@ func TestFunctionalTest(t *testing.T) {
|
||||
if c.PC() != 0x3CC5 {
|
||||
t.Errorf("Stuck at $%04X: 0x%02X", oldPC, m[oldPC])
|
||||
}
|
||||
fmt.Println(cc, "ticks")
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -84,6 +87,58 @@ func TestFunctionalTest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Run the first few thousand steps of Klaus Dormann's amazing
|
||||
// comprehensive test against the gate-level CPU emulation.
|
||||
func TestFunctionalTestGates(t *testing.T) {
|
||||
expected := []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 K64
|
||||
randomize(&m)
|
||||
OFFSET := 0xa
|
||||
copy(m[OFFSET:len(bytes)+OFFSET], bytes)
|
||||
// Set the RESET vector to jump to the tests
|
||||
m[0xFFFC] = 0x00
|
||||
m[0xFFFD] = 0x10
|
||||
c := visual.NewCPU(&m)
|
||||
c.Reset()
|
||||
count := uint64(0)
|
||||
for {
|
||||
count++
|
||||
if count%1000 == 0 {
|
||||
pc := c.PC()
|
||||
if pc == 0x3CC5 {
|
||||
return
|
||||
}
|
||||
if count/1000 < uint64(len(expected)) {
|
||||
expectedPC := expected[count/1000]
|
||||
if pc != expectedPC {
|
||||
t.Errorf("Expected PC=%d at step %d, got %d", expectedPC, count, pc)
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
// printStatus(c, m)
|
||||
c.Step()
|
||||
}
|
||||
}
|
||||
|
||||
// Run Bruce Clark's decimal test in 6502 mode.
|
||||
func TestDecimalMode6502(t *testing.T) {
|
||||
bytes, err := ioutil.ReadFile("decimal_mode.bin")
|
||||
|
@ -1,6 +1,10 @@
|
||||
/*
|
||||
Package visual provides routines for emulating a 6502 at the
|
||||
transistor level, using data from visual6502.org by way of
|
||||
https://github.com/mist64/perfect6502.
|
||||
transistor level, using data from visual6502.org.
|
||||
|
||||
It started out as an almost token-for-token translation of
|
||||
https://github.com/mist64/perfect6502, and is slowly changing to be a
|
||||
little more go-like, although keeping it fast seems to mean keeping
|
||||
the c-nature.
|
||||
*/
|
||||
package visual
|
||||
|
168
visual/visual.go
168
visual/visual.go
@ -1,26 +1,21 @@
|
||||
package visual
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/willf/bitset"
|
||||
|
||||
"github.com/zellyn/bitset"
|
||||
|
||||
icpu "github.com/zellyn/go6502/cpu"
|
||||
icpu "github.com/zellyn/go6502/cpu" // Just need the interface
|
||||
)
|
||||
|
||||
type cpu struct {
|
||||
m icpu.Memory
|
||||
cycle uint64
|
||||
nodeValues *bitset.BitSet
|
||||
nodePullups *bitset.BitSet
|
||||
nodePulldowns *bitset.BitSet
|
||||
|
||||
m icpu.Memory
|
||||
cycle uint64
|
||||
nodeValues []byte // Bitmask of node values (see const VAL_* below)
|
||||
nodeGateCounts [NODES]uint // the number of transistor gates attached to a node
|
||||
nodeGates [NODES][NODES]uint // the list of transistor indexes attached to a node
|
||||
nodeC1C2Counts [NODES]uint // the number of transistor c1/c2s attached to a node
|
||||
nodeC1C2s [NODES][2 * NODES]uint // the list of transistor c1/c2s attached to a node
|
||||
|
||||
transistorValues *bitset.BitSet
|
||||
transistorValues []bool
|
||||
transistorGates [TRANSISTORS]uint
|
||||
transistorC1s [TRANSISTORS]uint
|
||||
transistorC2s [TRANSISTORS]uint
|
||||
@ -31,11 +26,55 @@ type cpu struct {
|
||||
listIn []uint
|
||||
listOut []uint
|
||||
|
||||
groupList []uint
|
||||
groupSet *bitset.BitSet
|
||||
groupContainsPullup bool
|
||||
groupContainsPulldown bool
|
||||
groupContainsHi bool
|
||||
groupList []uint
|
||||
groupSet *bitset.BitSet
|
||||
groupValue byte
|
||||
}
|
||||
|
||||
// Bitfield for node values.
|
||||
const (
|
||||
VAL_HI = 1 << iota // We count on this being bit 0, so we can mask it out for 0 or 1.
|
||||
VAL_PULLUP
|
||||
VAL_PULLDOWN
|
||||
VAL_VCC
|
||||
VAL_VSS
|
||||
)
|
||||
|
||||
// The lookup table for the group value. If vss is in the group, it's 0, vcc makes it 1, etc.
|
||||
// vss, vcc, pulldown, pullup, hi
|
||||
var GroupValues = [32]byte{
|
||||
0, // 00000 - nothing
|
||||
1, // 00001 - contains at least one hi node
|
||||
1, // 00010 - contains at least one pullup
|
||||
1, // 00011 - contains at least one pullup
|
||||
0, // 00100 - contains at least one pulldown
|
||||
0, // 00101 - contains at least one pulldown
|
||||
0, // 00110 - contains at least one pulldown
|
||||
0, // 00111 - contains at least one pulldown
|
||||
1, // 01000 - contains vcc
|
||||
1, // 01001 - contains vcc
|
||||
1, // 01010 - contains vcc
|
||||
1, // 01011 - contains vcc
|
||||
1, // 01100 - contains vcc
|
||||
1, // 01101 - contains vcc
|
||||
1, // 01110 - contains vcc
|
||||
1, // 01111 - contains vcc
|
||||
0, // 10000- contains vss
|
||||
0, // 10001- contains vss
|
||||
0, // 10010- contains vss
|
||||
0, // 10011- contains vss
|
||||
0, // 10100- contains vss
|
||||
0, // 10101- contains vss
|
||||
0, // 10110- contains vss
|
||||
0, // 10111- contains vss
|
||||
0, // 11000- contains vss
|
||||
0, // 11001- contains vss
|
||||
0, // 11010- contains vss
|
||||
0, // 11011- contains vss
|
||||
0, // 11100- contains vss
|
||||
0, // 11101- contains vss
|
||||
0, // 11110- contains vss
|
||||
0, // 11111- contains vss
|
||||
}
|
||||
|
||||
func NewCPU(memory icpu.Memory) icpu.Cpu {
|
||||
@ -44,6 +83,7 @@ func NewCPU(memory icpu.Memory) icpu.Cpu {
|
||||
return &c
|
||||
}
|
||||
|
||||
// Needed for the interface. Not really practical. I guess we could try changing the nodes directly.
|
||||
func (c *cpu) SetPC(uint16) {
|
||||
panic("Not implemented")
|
||||
}
|
||||
@ -105,10 +145,7 @@ func (c *cpu) PC() uint16 {
|
||||
}
|
||||
|
||||
func (c *cpu) nodeBit(n uint) byte {
|
||||
if c.nodeValues.Test(n) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
return c.nodeValues[n] & VAL_HI // 1
|
||||
}
|
||||
|
||||
func (c *cpu) writeDataBus(d byte) {
|
||||
@ -119,12 +156,16 @@ func (c *cpu) writeDataBus(d byte) {
|
||||
}
|
||||
|
||||
func (c *cpu) Reset() {
|
||||
fmt.Println("Reset called")
|
||||
// All nodes down
|
||||
c.nodeValues.ClearAll()
|
||||
for i := range c.nodeValues {
|
||||
c.nodeValues[i] &^= VAL_HI
|
||||
}
|
||||
|
||||
// All transistors off
|
||||
c.transistorValues.ClearAll()
|
||||
|
||||
for i := range c.transistorValues {
|
||||
c.transistorValues[i] = false
|
||||
}
|
||||
|
||||
c.setNode(NODE_res, false)
|
||||
c.setNode(NODE_clk0, true)
|
||||
@ -137,7 +178,6 @@ func (c *cpu) Reset() {
|
||||
|
||||
// Hold RESET for 8 cycles
|
||||
for i := 0; i < 8; i++ {
|
||||
fmt.Println("Reset step ", i)
|
||||
c.Step()
|
||||
}
|
||||
|
||||
@ -158,16 +198,7 @@ func (c *cpu) addNodeToGroup(n uint) {
|
||||
c.groupSet.Set(n)
|
||||
c.groupList = append(c.groupList, n)
|
||||
|
||||
if c.nodePullups.Test(n) {
|
||||
c.groupContainsPullup = true
|
||||
}
|
||||
if c.nodePulldowns.Test(n) {
|
||||
c.groupContainsPulldown = true
|
||||
}
|
||||
if c.nodeValues.Test(n) {
|
||||
c.groupContainsHi = true
|
||||
}
|
||||
|
||||
c.groupValue |= c.nodeValues[n]
|
||||
if n == NODE_vss || n == NODE_vcc {
|
||||
return
|
||||
}
|
||||
@ -175,7 +206,7 @@ func (c *cpu) addNodeToGroup(n uint) {
|
||||
/* revisit all transistors that are controlled by this node */
|
||||
for t := uint(0); t < c.nodeC1C2Counts[n]; t++ {
|
||||
tn := c.nodeC1C2s[n][t]
|
||||
if c.transistorValues.Test(tn) {
|
||||
if c.transistorValues[tn] {
|
||||
if c.transistorC1s[tn] == n {
|
||||
c.addNodeToGroup(c.transistorC2s[tn])
|
||||
} else {
|
||||
@ -187,30 +218,12 @@ func (c *cpu) addNodeToGroup(n uint) {
|
||||
|
||||
func (c *cpu) addAllNodesToGroup(node uint) {
|
||||
c.groupList = c.groupList[0:0]
|
||||
c.groupValue = 0
|
||||
c.groupSet.ClearAll()
|
||||
c.groupContainsPullup = false
|
||||
c.groupContainsPulldown = false
|
||||
c.groupContainsHi = false
|
||||
|
||||
c.addNodeToGroup(node)
|
||||
}
|
||||
|
||||
func (c *cpu) getGroupValue() bool {
|
||||
if c.groupSet.Test(NODE_vss) {
|
||||
return false
|
||||
}
|
||||
if c.groupSet.Test(NODE_vcc) {
|
||||
return true
|
||||
}
|
||||
if c.groupContainsPulldown {
|
||||
return false
|
||||
}
|
||||
if c.groupContainsPullup {
|
||||
return true
|
||||
}
|
||||
return c.groupContainsHi
|
||||
}
|
||||
|
||||
func (c *cpu) recalcNode(node uint) {
|
||||
/*
|
||||
* get all nodes that are connected through
|
||||
@ -219,7 +232,7 @@ func (c *cpu) recalcNode(node uint) {
|
||||
c.addAllNodesToGroup(node)
|
||||
|
||||
/* get the state of the group */
|
||||
newv := c.getGroupValue()
|
||||
newv := GroupValues[c.groupValue]
|
||||
|
||||
/*
|
||||
* - set all nodes to the group state
|
||||
@ -228,11 +241,11 @@ func (c *cpu) recalcNode(node uint) {
|
||||
* for the next run
|
||||
*/
|
||||
for _, nn := range c.groupList {
|
||||
if c.nodeValues.Test(nn) != newv {
|
||||
c.nodeValues.SetTo(nn, newv)
|
||||
if c.nodeValues[nn]&VAL_HI != newv {
|
||||
c.nodeValues[nn] ^= VAL_HI
|
||||
for t := uint(0); t < c.nodeGateCounts[nn]; t++ {
|
||||
tn := c.nodeGates[nn][t]
|
||||
c.transistorValues.Flip(tn)
|
||||
c.transistorValues[tn] = !c.transistorValues[tn]
|
||||
}
|
||||
c.listOut = append(c.listOut, nn)
|
||||
}
|
||||
@ -287,14 +300,28 @@ func (c *cpu) recalcAllNodes() {
|
||||
/* Node State */
|
||||
/**************/
|
||||
|
||||
// So we don't have to keep re-allocating
|
||||
var oneNode = []uint{0}
|
||||
|
||||
func (c *cpu) setNode(nn uint, state bool) {
|
||||
c.nodePullups.SetTo(nn, state)
|
||||
c.nodePulldowns.SetTo(nn, !state)
|
||||
c.recalcNodeList([]uint{nn})
|
||||
oldState := c.nodeValues[nn]
|
||||
newState := oldState
|
||||
if state {
|
||||
newState &^= VAL_PULLDOWN
|
||||
newState |= VAL_PULLUP
|
||||
} else {
|
||||
newState &^= VAL_PULLUP
|
||||
newState |= VAL_PULLDOWN
|
||||
}
|
||||
if newState != oldState {
|
||||
c.nodeValues[nn] = newState
|
||||
oneNode[0] = nn
|
||||
c.recalcNodeList(oneNode)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cpu) isNodeHigh(n uint) bool {
|
||||
return c.nodeValues.Test(n)
|
||||
return c.nodeValues[n]&VAL_HI > 0
|
||||
}
|
||||
|
||||
// handleMemory is called when clk0 is low, and either reads from or
|
||||
@ -342,18 +369,25 @@ func (c *cpu) addNodeDependant(a, b uint) {
|
||||
func (c *cpu) setupNodesAndTransistors() {
|
||||
|
||||
// Zero out bitsets
|
||||
c.nodeValues = bitset.New(NODES)
|
||||
c.nodePullups = bitset.New(NODES)
|
||||
c.nodePulldowns = bitset.New(NODES)
|
||||
c.transistorValues = bitset.New(TRANSISTORS)
|
||||
c.transistorValues = make([]bool, TRANSISTORS)
|
||||
c.groupSet = bitset.New(NODES)
|
||||
c.groupList = make([]uint, 0, NODES)
|
||||
c.nodeValues = make([]byte, NODES)
|
||||
|
||||
// Copy node data from SegDefs into r/w data structures
|
||||
for i := uint(0); i < NODES; i++ {
|
||||
c.nodePullups.SetTo(i, SegDefs[i])
|
||||
c.nodeGateCounts[i] = 0
|
||||
c.nodeC1C2Counts[i] = 0
|
||||
|
||||
if SegDefs[i] {
|
||||
c.nodeValues[i] = VAL_PULLUP
|
||||
}
|
||||
if i == NODE_vss {
|
||||
c.nodeValues[i] |= VAL_VSS
|
||||
}
|
||||
if i == NODE_vcc {
|
||||
c.nodeValues[i] |= VAL_VCC
|
||||
}
|
||||
}
|
||||
|
||||
// Copy transistor data from TransDefs into r/w data structures
|
||||
|
Loading…
x
Reference in New Issue
Block a user