mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-12-21 18:29:45 +00:00
Refactor memory in pages. Addes text, ram and rom pages
This commit is contained in:
parent
139597b0d5
commit
49f2436c7b
@ -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
|
||||
}
|
||||
|
23
execute.go
23
execute.go
@ -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))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
2
main.go
2
main.go
@ -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
|
||||
}
|
||||
|
55
memory.go
55
memory.go
@ -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
73
textPages.go
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user