Abstract Memory with FlatMemory and PagedMemory implementations

This commit is contained in:
Ivan Izaguirre 2019-02-22 18:00:53 +01:00
parent 49ea32b84d
commit 922ae7839e
8 changed files with 109 additions and 66 deletions

View File

@ -6,16 +6,25 @@ import "go6502/core6502"
func Run(romFile string, log bool) {
// Setup the Apple ][ address space
var s core6502.State
s.Mem.InitWithRAM()
s.Mem.LoadRom(romFile)
var m core6502.PagedMemory
m.InitWithRAM()
m.LoadRom(romFile)
var io ioC0Page
s.Mem.SetPage(0xc0, &io)
m.SetPage(0xc0, &io)
var t textPages
for j := 0; j < 4; j++ {
s.Mem.SetPage(uint8(4+j), &(t.pages[j]))
m.SetPage(uint8(4+j), &(t.pages[j]))
}
for j := uint8(0xc1); j < 0xd0; j++ {
var p tracePage
p.page = j
m.SetPage(j, &p)
}
var s core6502.State
s.Mem = &m
var fe ansiConsoleFrontend
io.setKeyboardProvider(&fe)
go fe.textModeGoRoutine(&t)

18
apple2/tracePage.go Normal file
View File

@ -0,0 +1,18 @@
package apple2
import "fmt"
type tracePage struct {
page uint8
}
func (p *tracePage) Peek(address uint8) uint8 {
fmt.Printf("Read on address 0x%02x%02x\n", p.page, address)
panic(address)
return 0xcc
}
func (p *tracePage) Poke(address uint8, value uint8) {
fmt.Printf("Write on address 0x%02x%02x\n", p.page, address)
panic(address)
}

View File

@ -10,8 +10,10 @@ func TestFunctional(t *testing.T) {
//t.SkipNow()
var s State
var m FlatMemory
s.Mem = &m
// Test suite from https://github.com/Klaus2m5/6502_65C02_functional_tests
s.Mem.loadBinary("testdata/6502_functional_test.bin")
m.loadBinary("testdata/6502_functional_test.bin")
s.Reg.setPC(0x0400)
for true {
@ -26,9 +28,7 @@ func TestFunctional(t *testing.T) {
pc := s.Reg.getPC()
ExecuteInstruction(&s, log)
if pc == s.Reg.getPC() {
//s.memory.printPage(0x00)
//s.memory.printPage(0x01)
t.Errorf("Failuse in test %v.", testCase)
t.Errorf("Failure in test %v.", testCase)
}
}
}

View File

@ -26,6 +26,11 @@ const (
modeIndirectIndexedY
)
const (
vectorReset uint16 = 0xfffc
vectorBreak uint16 = 0xfffe
)
// https://www.masswerk.at/6502/6502_instruction_set.html
// http://www.emulator101.com/reference/6502-reference.html
// https://www.csh.rit.edu/~moffitt/docs/6502.html#FLAGS
@ -69,12 +74,12 @@ func resolve(s *State, line []uint8, opcode opcode) (value uint8, address uint16
address = getWordInLine(line) + uint16(s.Reg.getY())
case modeIndexedIndirectX:
addressAddress := uint8(line[1] + s.Reg.getX())
address = s.Mem.getZeroPageWord(addressAddress)
address = getZeroPageWord(s.Mem, addressAddress)
case modeIndirect:
addressAddress := getWordInLine(line)
address = s.Mem.getWord(addressAddress)
address = getWord(s.Mem, addressAddress)
case modeIndirectIndexedY:
address = s.Mem.getZeroPageWord(line[1]) +
address = getZeroPageWord(s.Mem, line[1]) +
uint16(s.Reg.getY())
}
@ -342,7 +347,7 @@ func opBRK(s *State, line []uint8, opcode opcode) {
pushWord(s, s.Reg.getPC()+1)
pushByte(s, s.Reg.getP()|(flagB+flag5))
s.Reg.setFlag(flagI)
s.Reg.setPC(s.Mem.getWord(0xFFFE))
s.Reg.setPC(getWord(s.Mem, vectorBreak))
}
var opcodes = [256]opcode{
@ -550,7 +555,7 @@ func ExecuteInstruction(s *State, log bool) {
// Reset resets the processor state. Moves the program counter to the vector in 0cfffc.
func Reset(s *State) {
startAddress := s.Mem.getWord(0xfffc)
startAddress := getWord(s.Mem, vectorReset)
s.Reg.setPC(startAddress)
}

View File

@ -6,7 +6,7 @@ import (
func TestLoad(t *testing.T) {
var s State
s.Mem.InitWithRAM()
s.Mem = new(FlatMemory)
executeLine(&s, []uint8{0xA9, 0x42})
if s.Reg.getA() != 0x42 {
@ -89,7 +89,7 @@ func TestLoad(t *testing.T) {
func TestStore(t *testing.T) {
var s State
s.Mem.InitWithRAM()
s.Mem = new(FlatMemory)
s.Reg.setA(0x10)
s.Reg.setX(0x40)
s.Reg.setY(0x80)
@ -401,7 +401,7 @@ func TestCompare(t *testing.T) {
}
func TestBit(t *testing.T) {
var s State
s.Mem.InitWithRAM()
s.Mem = new(FlatMemory)
s.Reg.setA(0x0F)
s.Mem.Poke(0x0040, 0xF0)
@ -450,7 +450,7 @@ func TestBranch(t *testing.T) {
func TestStack(t *testing.T) {
var s State
s.Mem.InitWithRAM()
s.Mem = new(FlatMemory)
s.Reg.setSP(0xF0)
s.Reg.setA(0xA0)

View File

@ -2,50 +2,39 @@ package core6502
import (
"bufio"
"fmt"
"os"
)
// MemoryPage is a data page of 256 bytes
type MemoryPage interface {
Peek(uint8) uint8
Poke(uint8, uint8)
}
// Memory represents the addressable space of the processor
type Memory struct {
data [256]MemoryPage
type Memory interface {
Peek(address uint16) uint8
Poke(address uint16, value uint8)
}
// Peek returns the data on the given address
func (m *Memory) Peek(address uint16) uint8 {
hi := uint8(address >> 8)
lo := uint8(address)
return m.data[hi].Peek(lo)
}
// Poke sets the data at the given address
func (m *Memory) Poke(address uint16, value uint8) {
hi := uint8(address >> 8)
lo := uint8(address)
//fmt.Println(hi)
m.data[hi].Poke(lo, value)
}
// SetPage assigns a MemoryPage implementation on the page given
func (m *Memory) SetPage(index uint8, page MemoryPage) {
m.data[index] = page
}
func (m *Memory) getWord(address uint16) uint16 {
func getWord(m Memory, address uint16) uint16 {
return uint16(m.Peek(address)) + 0x100*uint16(m.Peek(address+1))
}
func (m *Memory) getZeroPageWord(address uint8) uint16 {
func getZeroPageWord(m Memory, address uint8) uint16 {
return uint16(m.Peek(uint16(address))) + 0x100*uint16(m.Peek(uint16(address+1)))
}
func (m *Memory) loadBinary(filename string) {
// FlatMemory puts RAM on the 64Kb addeessable by the processor
type FlatMemory struct {
data [65536]uint8
}
// Peek returns the data on the given address
func (m *FlatMemory) Peek(address uint16) uint8 {
return m.data[address]
}
// Poke sets the data at the given address
func (m *FlatMemory) Poke(address uint16, value uint8) {
m.data[address] = value
}
func (m *FlatMemory) loadBinary(filename string) {
// Load file
f, err := os.Open(filename)
if err != nil {
@ -64,20 +53,7 @@ func (m *Memory) loadBinary(filename string) {
buf := bufio.NewReader(f)
buf.Read(bytes)
m.InitWithRAM()
for i, v := range bytes {
m.Poke(uint16(i), uint8(v))
}
}
func (m *Memory) printPage(page uint8) {
address := uint16(page) * 0x100
for i := 0; i < 16; i++ {
fmt.Printf("%#04x: ", address)
for j := 0; j < 16; j++ {
fmt.Printf("%02x ", m.data[address])
address++
}
fmt.Printf("\n")
}
}

32
core6502/pagedMemory.go Normal file
View File

@ -0,0 +1,32 @@
package core6502
// MemoryPage is a data page of 256 bytes
type MemoryPage interface {
Peek(uint8) uint8
Poke(uint8, uint8)
}
// PagedMemory represents the addressable space of the processor
type PagedMemory struct {
data [256]MemoryPage
}
// Peek returns the data on the given address
func (m *PagedMemory) Peek(address uint16) uint8 {
hi := uint8(address >> 8)
lo := uint8(address)
return m.data[hi].Peek(lo)
}
// Poke sets the data at the given address
func (m *PagedMemory) Poke(address uint16, value uint8) {
hi := uint8(address >> 8)
lo := uint8(address)
//fmt.Println(hi)
m.data[hi].Poke(lo, value)
}
// SetPage assigns a MemoryPage implementation on the page given
func (m *PagedMemory) SetPage(index uint8, page MemoryPage) {
m.data[index] = page
}

View File

@ -2,6 +2,7 @@ package core6502
import (
"bufio"
"fmt"
"os"
)
@ -34,14 +35,14 @@ func (p *romPage) burn(address uint8, value uint8) {
}
// InitWithRAM adds RAM memory to all the memory pages
func (m *Memory) InitWithRAM() {
func (m *PagedMemory) InitWithRAM() {
var ramPages [256]ramPage
for i := 0; i < 256; i++ {
m.SetPage(uint8(i), &ramPages[i])
}
}
func (m *Memory) transformToRom(page uint8) {
func (m *PagedMemory) transformToRom(page uint8) {
var romPage romPage
address := uint16(page) << 8
for i := 0; i < 256; i++ {
@ -52,7 +53,7 @@ func (m *Memory) transformToRom(page uint8) {
}
// LoadRom loads a binary file to the top of the memory and makes those pages read only.
func (m *Memory) LoadRom(filename string) {
func (m *PagedMemory) LoadRom(filename string) {
f, err := os.Open(filename)
if err != nil {
panic(err)
@ -71,6 +72,8 @@ func (m *Memory) LoadRom(filename string) {
buf.Read(bytes)
romStart := uint16(0xFFFF - size + 1)
fmt.Printf("ROM start in in 0x%04x\n", romStart)
for i, v := range bytes {
m.Poke(uint16(i)+romStart, uint8(v))
}