Refactor memory in pages. Addes text, ram and rom pages

This commit is contained in:
Ivan Izaguirre 2019-02-13 00:03:43 +01:00
parent 139597b0d5
commit 49f2436c7b
6 changed files with 167 additions and 38 deletions

View File

@ -7,11 +7,12 @@ import (
func TestFunctional(t *testing.T) {
var s state
// Test suite from https://github.com/Klaus2m5/6502_65C02_functional_tests
s.memory.loadBinary("tests/6502_functional_test.bin")
s.registers.setPC(0x0400)
for true {
testCase := s.memory[0x0200]
testCase := s.memory.peek(0x0200)
if testCase >= 240 {
break
}

View File

@ -82,12 +82,12 @@ func resolve(s *state, line []uint8, opcode opcode) (value uint8, address uint16
}
if hasAddress {
value = s.memory[address]
value = s.memory.peek(address)
}
setValue = func(value uint8) {
if hasAddress {
s.memory[address] = value
s.memory.poke(address, value)
} else if register != regNone {
s.registers.setRegister(register, value)
} else {
@ -99,7 +99,7 @@ func resolve(s *state, line []uint8, opcode opcode) (value uint8, address uint16
type opcode struct {
name string
bytes int8
bytes uint8
cycles int
addressMode int
action opFunc
@ -279,14 +279,14 @@ const stackAddress uint16 = 0x0100
func pushByte(s *state, value uint8) {
adresss := stackAddress + uint16(s.registers.getSP())
s.memory[adresss] = value
s.memory.poke(adresss, value)
s.registers.setSP(s.registers.getSP() - 1)
}
func pullByte(s *state) uint8 {
s.registers.setSP(s.registers.getSP() + 1)
adresss := stackAddress + uint16(s.registers.getSP())
return s.memory[adresss]
return s.memory.peek(adresss)
}
func pushWord(s *state, value uint16) {
@ -530,10 +530,15 @@ func executeLine(s *state, line []uint8) {
func executeInstruction(s *state, log bool) {
pc := s.registers.getPC()
opcode := opcodes[s.memory[pc]]
pcNext := pc + uint16(opcode.bytes)
s.registers.setPC(pcNext)
line := s.memory[pc:pcNext]
opcode := opcodes[s.memory.peek(pc)]
line := make([]uint8, opcode.bytes)
for i := uint8(0); i < opcode.bytes; i++ {
line[i] = s.memory.peek(pc)
pc++
}
s.registers.setPC(pc)
if log {
fmt.Printf("%#04x %-12s: ", pc, lineString(s, line, opcode))
}

View File

@ -6,6 +6,7 @@ import (
func TestLoad(t *testing.T) {
var s state
s.memory.initWithRam()
executeLine(&s, []uint8{0xA9, 0x42})
if s.registers.getA() != 0x42 {
@ -27,59 +28,59 @@ func TestLoad(t *testing.T) {
t.Error("Error in LDY #")
}
s.memory[0x38] = 0x87
s.memory.poke(0x38, 0x87)
executeLine(&s, []uint8{0xA5, 0x38})
if s.registers.getA() != 0x87 {
t.Error("Error in LDA zpg")
}
s.memory[0x57] = 0x90
s.memory.poke(0x57, 0x90)
s.registers.setX(0x10)
executeLine(&s, []uint8{0xB5, 0x47})
if s.registers.getA() != 0x90 {
t.Error("Error in LDA zpg, X")
}
s.memory[0x38] = 0x12
s.memory.poke(0x38, 0x12)
s.registers.setX(0x89)
executeLine(&s, []uint8{0xB5, 0xAF})
if s.registers.getA() != 0x12 {
t.Error("Error in LDA zpgX with sero page overflow")
}
s.memory[0x1234] = 0x67
s.memory.poke(0x1234, 0x67)
executeLine(&s, []uint8{0xAD, 0x34, 0x12})
if s.registers.getA() != 0x67 {
t.Error("Error in LDA abs")
}
s.memory[0xC057] = 0x7E
s.memory.poke(0xC057, 0x7E)
s.registers.setX(0x57)
executeLine(&s, []uint8{0xBD, 0x00, 0xC0})
if s.registers.getA() != 0x7E {
t.Error("Error in LDA abs, X")
}
s.memory[0xD059] = 0x7A
s.memory.poke(0xD059, 0x7A)
s.registers.setY(0x59)
executeLine(&s, []uint8{0xB9, 0x00, 0xD0})
if s.registers.getA() != 0x7A {
t.Error("Error in LDA abs, Y")
}
s.memory[0x24] = 0x74
s.memory[0x25] = 0x20
s.memory.poke(0x24, 0x74)
s.memory.poke(0x25, 0x20)
s.registers.setX(0x04)
s.memory[0x2074] = 0x66
s.memory.poke(0x2074, 0x66)
executeLine(&s, []uint8{0xA1, 0x20})
if s.registers.getA() != 0x66 {
t.Error("Error in LDA (oper,X)")
}
s.memory[0x86] = 0x28
s.memory[0x87] = 0x40
s.memory.poke(0x86, 0x28)
s.memory.poke(0x87, 0x40)
s.registers.setY(0x10)
s.memory[0x4038] = 0x99
s.memory.poke(0x4038, 0x99)
executeLine(&s, []uint8{0xB1, 0x86})
if s.registers.getA() != 0x99 {
t.Error("Error in LDA (oper),Y")
@ -88,32 +89,33 @@ func TestLoad(t *testing.T) {
func TestStore(t *testing.T) {
var s state
s.memory.initWithRam()
s.registers.setA(0x10)
s.registers.setX(0x40)
s.registers.setY(0x80)
executeLine(&s, []uint8{0x85, 0x50})
if s.memory[0x0050] != 0x10 {
if s.memory.peek(0x0050) != 0x10 {
t.Error("Error in STA zpg")
}
executeLine(&s, []uint8{0x86, 0x51})
if s.memory[0x0051] != 0x40 {
if s.memory.peek(0x0051) != 0x40 {
t.Error("Error in STX zpg")
}
executeLine(&s, []uint8{0x84, 0x52})
if s.memory[0x0052] != 0x80 {
if s.memory.peek(0x0052) != 0x80 {
t.Error("Error in STY zpg")
}
executeLine(&s, []uint8{0x8D, 0x20, 0xC0})
if s.memory[0xC020] != 0x10 {
if s.memory.peek(0xC020) != 0x10 {
t.Error("Error in STA abs")
}
executeLine(&s, []uint8{0x9D, 0x08, 0x10})
if s.memory[0x1048] != 0x10 {
if s.memory.peek(0x1048) != 0x10 {
t.Error("Error in STA abs, X")
}
}
@ -399,23 +401,24 @@ func TestCompare(t *testing.T) {
}
func TestBit(t *testing.T) {
var s state
s.memory.initWithRam()
s.registers.setA(0x0F)
s.memory[0x0040] = 0xF0
s.memory.poke(0x0040, 0xF0)
executeLine(&s, []uint8{0x24, 0x40})
if s.registers.getP() != 0xC2 {
t.Errorf("Error in BIT. %v", s.registers)
}
s.registers.setA(0xF0)
s.memory[0x0040] = 0xF0
s.memory.poke(0x0040, 0xF0)
executeLine(&s, []uint8{0x24, 0x40})
if s.registers.getP() != 0xC0 {
t.Errorf("Error in BIT, 2. %v", s.registers)
}
s.registers.setA(0xF0)
s.memory[0x01240] = 0x80
s.memory.poke(0x01240, 0x80)
executeLine(&s, []uint8{0x2C, 0x40, 0x12})
if s.registers.getP() != 0x80 {
t.Errorf("Error in BIT, 2. %v", s.registers)
@ -424,6 +427,7 @@ func TestBit(t *testing.T) {
func TestBranch(t *testing.T) {
var s state
s.registers.setPC(0xC600)
s.registers.setFlag(flagV)
executeLine(&s, []uint8{0x50, 0x20})
@ -446,6 +450,7 @@ func TestBranch(t *testing.T) {
func TestStack(t *testing.T) {
var s state
s.memory.initWithRam()
s.registers.setSP(0xF0)
s.registers.setA(0xA0)
@ -454,7 +459,7 @@ func TestStack(t *testing.T) {
if s.registers.getSP() != 0xEF {
t.Errorf("Error in PHA stack pointer, %v", s.registers)
}
if s.memory[0x01F0] != 0xA0 {
if s.memory.peek(0x01F0) != 0xA0 {
t.Errorf("Error in PHA, %v", s.registers)
}
@ -462,7 +467,7 @@ func TestStack(t *testing.T) {
if s.registers.getSP() != 0xEE {
t.Errorf("Error in PHP stack pointer, %v", s.registers)
}
if s.memory[0x01EF] != 0x3A {
if s.memory.peek(0x01EF) != 0x3A {
t.Errorf("Error in PHP, %v", s.registers)
}

View File

@ -8,7 +8,7 @@ func main() {
s.registers.setPC(0x0400)
for true {
testCase := s.memory[0x0200]
testCase := s.memory.peek(0x0200)
if testCase >= 240 {
break
}

View File

@ -6,18 +6,62 @@ import (
"os"
)
type memory [65536]uint8
type memoryPage interface {
peek(uint8) uint8
poke(uint8, uint8)
}
type ramPage [256]uint8
type romPage [256]uint8
type memory [256]memoryPage
func (p *ramPage) peek(address uint8) uint8 {
return p[address]
}
func (p *ramPage) poke(address uint8, value uint8) {
p[address] = value
}
func (p *romPage) peek(address uint8) uint8 {
return p[address]
}
func (p *romPage) poke(address uint8, value uint8) {
// Do nothing
}
func (m *memory) peek(address uint16) uint8 {
hi := uint8(address >> 8)
lo := uint8(address)
return m[hi].peek(lo)
}
func (m *memory) poke(address uint16, value uint8) {
hi := uint8(address >> 8)
lo := uint8(address)
//fmt.Println(hi)
m[hi].poke(lo, value)
}
func (m *memory) getWord(address uint16) uint16 {
return uint16(m[address]) + 0x100*uint16(m[address+1])
return uint16(m.peek(address)) + 0x100*uint16(m.peek(address+1))
}
func (m *memory) getZeroPageWord(address uint8) uint16 {
return uint16(m[address]) + 0x100*uint16(m[address+1])
// TODO: Does address + 1 wraps around the zero page?
return uint16(m.peek(uint16(address))) + 0x100*uint16(m.peek(uint16(address+1)))
}
func (m *memory) initWithRam() {
var ramPages [256]ramPage
for i := 0; i < 256; i++ {
m[i] = &ramPages[i]
}
}
func (m *memory) loadBinary(filename string) {
// Load file
f, err := os.Open(filename)
if err != nil {
panic(err)
@ -35,8 +79,9 @@ func (m *memory) loadBinary(filename string) {
buf := bufio.NewReader(f)
buf.Read(bytes)
m.initWithRam()
for i, v := range bytes {
m[i] = uint8(v)
m.poke(uint16(i), uint8(v))
}
}

73
textPages.go Normal file
View File

@ -0,0 +1,73 @@
package main
import "fmt"
type textPages struct {
dirty bool
pages *[4]textPage
}
type textPage struct {
textPages *textPages
data [256]uint8
}
func (p *textPage) peek(address uint8) uint8 {
return p.data[address]
}
func (p *textPage) poke(address uint8, value uint8) {
p.data[address] = value
// Note: we could avoid setting dirty on the 16 blocks of 8 hidden bytes
p.textPages.dirty = true
}
func textMemoryByteToString(value uint8) string {
return string(value)
}
func (tp *textPages) dump() {
// See "Understand the Apple II", page 5-10
// http://www.applelogic.org/files/UNDERSTANDINGTHEAII.pdf
var i, j, h uint8
// Top, middle and botton screen
for i = 0; i < 128; i = i + 40 {
// Memory pages
for _, p := range tp.pages {
// The two half pages
for _, h = range []uint8{0, 128} {
line := ""
for j = i + h; j < i+h+40; j++ {
line += string(p.peek(j))
}
fmt.Println(line)
}
}
}
}
func (tp *textPages) dumpIfDirty() {
if !tp.dirty {
return
}
tp.dirty = false
tp.dump()
}
func (tp *textPages) charAddress(column uint8, line uint8) (page uint8, address uint8) {
page = (line / 3) % 4
address = column + (line/8)*40 + (line%2)*128
return
}
func (tp *textPages) read(column uint8, line uint8) uint8 {
page, address := tp.charAddress(column, line)
return tp.pages[page].peek(address)
}
func (tp *textPages) write(column uint8, line uint8, value uint8) {
page, address := tp.charAddress(column, line)
tp.pages[page].poke(address, value)
}