From 922ae7839e2f23f42d83549c9568db339a146a7c Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Fri, 22 Feb 2019 18:00:53 +0100 Subject: [PATCH] Abstract Memory with FlatMemory and PagedMemory implementations --- apple2/apple2.go | 19 +++++++--- apple2/tracePage.go | 18 +++++++++ core6502/6502functional_test.go | 8 ++-- core6502/execute.go | 15 +++++--- core6502/execute_test.go | 8 ++-- core6502/memory.go | 66 +++++++++++---------------------- core6502/pagedMemory.go | 32 ++++++++++++++++ core6502/rxmPage.go | 9 +++-- 8 files changed, 109 insertions(+), 66 deletions(-) create mode 100644 apple2/tracePage.go create mode 100644 core6502/pagedMemory.go diff --git a/apple2/apple2.go b/apple2/apple2.go index 6c191da..5b28f5c 100644 --- a/apple2/apple2.go +++ b/apple2/apple2.go @@ -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) diff --git a/apple2/tracePage.go b/apple2/tracePage.go new file mode 100644 index 0000000..a8bda4d --- /dev/null +++ b/apple2/tracePage.go @@ -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) +} diff --git a/core6502/6502functional_test.go b/core6502/6502functional_test.go index 0f62e40..8243f2d 100644 --- a/core6502/6502functional_test.go +++ b/core6502/6502functional_test.go @@ -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) } } } diff --git a/core6502/execute.go b/core6502/execute.go index 3fca621..d64c624 100644 --- a/core6502/execute.go +++ b/core6502/execute.go @@ -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) } diff --git a/core6502/execute_test.go b/core6502/execute_test.go index d273af8..5e9db1b 100644 --- a/core6502/execute_test.go +++ b/core6502/execute_test.go @@ -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) diff --git a/core6502/memory.go b/core6502/memory.go index fa5634b..1387fb2 100644 --- a/core6502/memory.go +++ b/core6502/memory.go @@ -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") - } -} diff --git a/core6502/pagedMemory.go b/core6502/pagedMemory.go new file mode 100644 index 0000000..896c5a5 --- /dev/null +++ b/core6502/pagedMemory.go @@ -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 +} diff --git a/core6502/rxmPage.go b/core6502/rxmPage.go index 5ba594c..879da01 100644 --- a/core6502/rxmPage.go +++ b/core6502/rxmPage.go @@ -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)) }