Add basic Cpu/Bus/Ram architecture.

This commit is contained in:
Ariejan de Vroom 2014-08-13 09:26:33 +02:00
parent f88946a622
commit e96ce1e84a
7 changed files with 259 additions and 3 deletions

85
address_bus.go Normal file
View File

@ -0,0 +1,85 @@
package i6502
import (
"fmt"
)
type AddressBus struct {
addressables []addressable // Different components
}
type addressable struct {
memory Memory // Actual memory
start uint16 // First address in address space
end uint16 // Last address in address space
}
func NewAddressBus() (*AddressBus, error) {
return &AddressBus{addressables: make([]addressable, 0)}, nil
}
func (a *addressable) String() string {
return fmt.Sprintf("\t0x%04X-%04X\n", a.start, a.end)
}
func (a *AddressBus) String() string {
output := "Address Bus:\n"
for _, addressable := range a.addressables {
output += addressable.String()
}
return output
}
func (a *AddressBus) AddressablesCount() int {
return len(a.addressables)
}
func (a *AddressBus) Attach(memory Memory, offset uint16) {
start := offset
end := offset + memory.Size() - 1
addressable := addressable{memory: memory, start: start, end: end}
a.addressables = append(a.addressables, addressable)
}
func (a *AddressBus) addressableForAddress(address uint16) (*addressable, error) {
for _, addressable := range a.addressables {
if addressable.start <= address && addressable.end >= address {
return &addressable, nil
}
}
return nil, fmt.Errorf("No addressable memory found at 0x%04X", address)
}
func (a *AddressBus) Read(address uint16) byte {
addressable, err := a.addressableForAddress(address)
if err != nil {
panic(err)
}
return addressable.memory.Read(address - addressable.start)
}
func (a *AddressBus) Read16(address uint16) uint16 {
lo := uint16(a.Read(address))
hi := uint16(a.Read(address + 1))
return (hi << 8) | lo
}
func (a *AddressBus) Write(address uint16, data byte) {
addressable, err := a.addressableForAddress(address)
if err != nil {
panic(err)
}
addressable.memory.Write(address-addressable.start, data)
}
func (a *AddressBus) Write16(address uint16, data uint16) {
a.Write(address, byte(data))
a.Write(address+1, byte(data>>8))
}

65
address_bus_test.go Normal file
View File

@ -0,0 +1,65 @@
package i6502
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestEmptyAddressBus(t *testing.T) {
assert := assert.New(t)
bus, err := NewAddressBus()
assert.Nil(err)
if assert.NotNil(bus) {
assert.Equal(0, bus.AddressablesCount())
}
}
func TestAttachToAddressBus(t *testing.T) {
assert := assert.New(t)
bus, _ := NewAddressBus()
ram, _ := NewRam(0x10000)
bus.Attach(ram, 0x0000)
assert.Equal(1, bus.AddressablesCount())
}
func TestBusReadWrite(t *testing.T) {
assert := assert.New(t)
bus, _ := NewAddressBus()
ram, _ := NewRam(0x8000)
ram2, _ := NewRam(0x8000)
bus.Attach(ram, 0x0000)
bus.Attach(ram2, 0x8000)
// 8-bit Writing
bus.Write(0x1234, 0xFA)
assert.Equal(0xFA, ram.Read(0x1234))
// 16-bit Writing
bus.Write16(0x1000, 0xAB42)
assert.Equal(0x42, ram.Read(0x1000))
assert.Equal(0xAB, ram.Read(0x1001))
// 8-bit Reading
ram.Write(0x5522, 0xDA)
assert.Equal(0xDA, bus.Read(0x5522))
// 16-bit Reading
ram.Write(0x4440, 0x7F)
ram.Write(0x4441, 0x56)
assert.Equal(0x567F, bus.Read16(0x4440))
//// Test addressing memory not mounted at 0x0000
// Read from relative addressable Ram2: $C123
ram2.Write(0x4123, 0xEF)
assert.Equal(0xEF, bus.Read(0xC123))
bus.Write(0x8001, 0x12)
assert.Equal(0x12, ram2.Read(0x0001))
}

21
cpu.go
View File

@ -1,8 +1,25 @@
package i6502
type Cpu struct {
bus *AddressBus // The address bus
PC uint16 // 16-bit program counter
P byte // Status Register
}
func NewCpu() (*Cpu, error) {
return &Cpu{}, nil
const (
ResetVector = 0xFFFC
)
func NewCpu(bus *AddressBus) (*Cpu, error) {
return &Cpu{bus: bus}, nil
}
func (c *Cpu) HasAddressBus() bool {
return c.bus != nil
}
func (c *Cpu) Reset() {
c.PC = c.bus.Read16(ResetVector)
c.P = 0x34
}

View File

@ -5,9 +5,44 @@ import (
"testing"
)
// Creates a new machine, returning the different parts
func NewRamMachine() (*Cpu, *AddressBus, *Ram) {
ram, _ := NewRam(0x100000) // Full 64kB
bus, _ := NewAddressBus()
bus.Attach(ram, 0x0000)
cpu, _ := NewCpu(bus)
return cpu, bus, ram
}
func TestNewCpu(t *testing.T) {
cpu, err := NewCpu()
cpu, err := NewCpu(nil)
assert.NotNil(t, cpu)
assert.Nil(t, err)
}
func TestCpuAddressBus(t *testing.T) {
assert := assert.New(t)
cpu, _, _ := NewRamMachine()
assert.True(cpu.HasAddressBus())
}
func TestCpuState(t *testing.T) {
assert := assert.New(t)
cpu, _, _ := NewRamMachine()
cpu.bus.Write(0xFFFC, 0x34)
cpu.bus.Write(0xFFFD, 0x12)
cpu.Reset()
// **1101** is specified, but we are satisfied with
// 00110100 here.
assert.Equal(0x34, cpu.P)
// Read PC from $FFFC-FFFD
assert.Equal(0x1234, cpu.PC)
}

7
memory.go Normal file
View File

@ -0,0 +1,7 @@
package i6502
type Memory interface {
Size() uint16
Read(address uint16) byte
Write(address uint16, data byte)
}

21
ram.go Normal file
View File

@ -0,0 +1,21 @@
package i6502
type Ram struct {
data []byte
}
func NewRam(size int) (*Ram, error) {
return &Ram{data: make([]byte, size)}, nil
}
func (r *Ram) Size() uint16 {
return uint16(len(r.data))
}
func (r *Ram) Read(address uint16) byte {
return r.data[address]
}
func (r *Ram) Write(address uint16, data byte) {
r.data[address] = data
}

26
ram_test.go Normal file
View File

@ -0,0 +1,26 @@
package i6502
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestRamSize(t *testing.T) {
assert := assert.New(t)
ram, _ := NewRam(0x8000) // 32 kB
assert.Equal(0x8000, ram.Size())
}
func TestRamReadWrite(t *testing.T) {
assert := assert.New(t)
ram, _ := NewRam(0x8000) // 32 kB
// Ram zeroed out initially
for i := 0; i < 0x8000; i++ {
assert.Equal(0x00, ram.data[i])
}
ram.Write(0x1000, 0x42)
assert.Equal(0x42, ram.Read(0x1000))
}