From 33ccf5e4c300a63277b9d324db24dd0c8b7819ad Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Sat, 16 Feb 2019 20:15:41 +0100 Subject: [PATCH] Project files organization. Second commit wuth the file changes --- apple2/apple2.go | 25 ++ apple2/ioC0Page.go | 11 +- apple2/textPages.go | 16 +- apple2/textPages_test.go | 2 +- core6502/6502functional_test.go | 18 +- core6502/execute.go | 249 +++++++++--------- core6502/execute_test.go | 434 ++++++++++++++++---------------- core6502/memory.go | 125 ++------- core6502/registers.go | 46 ++-- core6502/registers_test.go | 12 +- core6502/rxmPage.go | 81 ++++++ main.go | 34 +-- 12 files changed, 529 insertions(+), 524 deletions(-) create mode 100644 apple2/apple2.go create mode 100644 core6502/rxmPage.go diff --git a/apple2/apple2.go b/apple2/apple2.go new file mode 100644 index 0000000..366e4f7 --- /dev/null +++ b/apple2/apple2.go @@ -0,0 +1,25 @@ +package apple2 + +import "go6502/core6502" + +// Run instantiates an apple2 and start emulation +func Run(romFile string, log bool) { + + // Setup the Apple ][ address space + var s core6502.State + s.Mem.InitWithRAM() + s.Mem.LoadRom(romFile) + var io ioC0Page + s.Mem.SetPage(0xc0, &io) + var t textPages + for j := 0; j < 4; j++ { + s.Mem.SetPage(uint8(4+j), &(t.pages[j])) + } + + // Start the processor + core6502.Reset(&s) + for true { + core6502.ExecuteInstruction(&s, log) + t.dumpIfDirty() + } +} diff --git a/apple2/ioC0Page.go b/apple2/ioC0Page.go index 1fae44f..4f4689c 100644 --- a/apple2/ioC0Page.go +++ b/apple2/ioC0Page.go @@ -1,4 +1,4 @@ -package main +package apple2 import "fmt" @@ -51,21 +51,16 @@ var softSwitches = [256]softSwitch{ 0x5f: softSwitch{ioFlagAnnunciator3, true, false}, } -func (p *ioC0Page) peek(address uint8) uint8 { +func (p *ioC0Page) Peek(address uint8) uint8 { //fmt.Printf("Peek on $C0%02x ", address) return p.access(address, false, 0) } -func (p *ioC0Page) poke(address uint8, value uint8) { +func (p *ioC0Page) Poke(address uint8, value uint8) { //fmt.Printf("Poke on $C0%02x with %02x ", address, value) p.access(address, true, value) } -func (p *ioC0Page) getData() *[256]uint8 { - var blankPage [256]uint8 - return &blankPage -} - func (p *ioC0Page) access(address uint8, isWrite bool, value uint8) uint8 { ss := softSwitches[address] diff --git a/apple2/textPages.go b/apple2/textPages.go index 239d2a7..50d5408 100644 --- a/apple2/textPages.go +++ b/apple2/textPages.go @@ -1,4 +1,4 @@ -package main +package apple2 import "fmt" @@ -11,20 +11,16 @@ type textPage struct { data [256]uint8 } -func (p *textPage) peek(address uint8) uint8 { +func (p *textPage) Peek(address uint8) uint8 { return p.data[address] } -func (p *textPage) poke(address uint8, value uint8) { +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.dirty = true } -func (p *textPage) getData() *[256]uint8 { - return &p.data -} - func textMemoryByteToString(value uint8) string { value = value & 0x7F if value < ' ' { @@ -53,7 +49,7 @@ func (tp *textPages) dump() { for _, h = range []uint8{0, 128} { line := "" for j = i + h; j < i+h+40; j++ { - line += textMemoryByteToString(p.peek(j)) + line += textMemoryByteToString(p.Peek(j)) } fmt.Printf("| %v |\n", line) } @@ -87,10 +83,10 @@ func (tp *textPages) charAddress(column uint8, line uint8) (page uint8, address func (tp *textPages) read(column uint8, line uint8) uint8 { page, address := tp.charAddress(column, line) - return tp.pages[page].peek(address) + 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) + tp.pages[page].Poke(address, value) } diff --git a/apple2/textPages_test.go b/apple2/textPages_test.go index ff59dc8..2e5ccad 100644 --- a/apple2/textPages_test.go +++ b/apple2/textPages_test.go @@ -1,4 +1,4 @@ -package main +package apple2 import "testing" diff --git a/core6502/6502functional_test.go b/core6502/6502functional_test.go index 0729ed0..0f62e40 100644 --- a/core6502/6502functional_test.go +++ b/core6502/6502functional_test.go @@ -1,4 +1,4 @@ -package main +package core6502 import ( "fmt" @@ -7,15 +7,15 @@ import ( func TestFunctional(t *testing.T) { - t.SkipNow() + //t.SkipNow() - var s state + var s State // Test suite from https://github.com/Klaus2m5/6502_65C02_functional_tests - s.memory.loadBinary("tests/6502_functional_test.bin") + s.Mem.loadBinary("testdata/6502_functional_test.bin") - s.registers.setPC(0x0400) + s.Reg.setPC(0x0400) for true { - testCase := s.memory.peek(0x0200) + testCase := s.Mem.Peek(0x0200) if testCase >= 240 { break } @@ -23,9 +23,9 @@ func TestFunctional(t *testing.T) { if log { fmt.Printf("[ %d ] ", testCase) } - pc := s.registers.getPC() - executeInstruction(&s, log) - if pc == s.registers.getPC() { + 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) diff --git a/core6502/execute.go b/core6502/execute.go index 89a99c6..5d36c73 100644 --- a/core6502/execute.go +++ b/core6502/execute.go @@ -1,14 +1,11 @@ -package main +package core6502 import "fmt" -type state struct { - registers registers - memory memory -} - -func step(s *state) { - +// State represents the state of the simulated device +type State struct { + Reg Registers + Mem Memory } const ( @@ -38,21 +35,21 @@ func getWordInLine(line []uint8) uint16 { return uint16(line[1]) + 0x100*uint16(line[2]) } -func resolve(s *state, line []uint8, opcode opcode) (value uint8, address uint16, setValue func(uint8)) { +func resolve(s *State, line []uint8, opcode opcode) (value uint8, address uint16, setValue func(uint8)) { hasAddress := true register := regNone switch opcode.addressMode { case modeAccumulator: - value = s.registers.getA() + value = s.Reg.getA() hasAddress = false register = regA case modeImplicitX: - value = s.registers.getX() + value = s.Reg.getX() hasAddress = false register = regX case modeImplicitY: - value = s.registers.getY() + value = s.Reg.getY() hasAddress = false register = regY case modeImmediate: @@ -61,35 +58,35 @@ func resolve(s *state, line []uint8, opcode opcode) (value uint8, address uint16 case modeZeroPage: address = uint16(line[1]) case modeZeroPageX: - address = uint16(line[1] + s.registers.getX()) + address = uint16(line[1] + s.Reg.getX()) case modeZeroPageY: - address = uint16(line[1] + s.registers.getY()) + address = uint16(line[1] + s.Reg.getY()) case modeAbsolute: address = getWordInLine(line) case modeAbsoluteX: - address = getWordInLine(line) + uint16(s.registers.getX()) + address = getWordInLine(line) + uint16(s.Reg.getX()) case modeAbsoluteY: - address = getWordInLine(line) + uint16(s.registers.getY()) + address = getWordInLine(line) + uint16(s.Reg.getY()) case modeIndexedIndirectX: - addressAddress := uint8(line[1] + s.registers.getX()) - address = s.memory.getZeroPageWord(addressAddress) + addressAddress := uint8(line[1] + s.Reg.getX()) + address = s.Mem.getZeroPageWord(addressAddress) case modeIndirect: addressAddress := getWordInLine(line) - address = s.memory.getWord(addressAddress) + address = s.Mem.getWord(addressAddress) case modeIndirectIndexedY: - address = s.memory.getZeroPageWord(line[1]) + - uint16(s.registers.getY()) + address = s.Mem.getZeroPageWord(line[1]) + + uint16(s.Reg.getY()) } if hasAddress { - value = s.memory.peek(address) + value = s.Mem.Peek(address) } setValue = func(value uint8) { if hasAddress { - s.memory.poke(address, value) + s.Mem.Poke(address, value) } else if register != regNone { - s.registers.setRegister(register, value) + s.Reg.setRegister(register, value) } else { // Todo: assert impossible } @@ -105,36 +102,36 @@ type opcode struct { action opFunc } -type opFunc func(s *state, line []uint8, opcode opcode) +type opFunc func(s *State, line []uint8, opcode opcode) func buildOpTransfer(regSrc int, regDst int) opFunc { - return func(s *state, line []uint8, opcode opcode) { - value := s.registers.getRegister(regSrc) - s.registers.setRegister(regDst, value) + return func(s *State, line []uint8, opcode opcode) { + value := s.Reg.getRegister(regSrc) + s.Reg.setRegister(regDst, value) if regDst != regSP { - s.registers.updateFlagZN(value) + s.Reg.updateFlagZN(value) } } } func buildOpIncDec(inc bool) opFunc { - return func(s *state, line []uint8, opcode opcode) { + return func(s *State, line []uint8, opcode opcode) { value, _, setValue := resolve(s, line, opcode) if inc { value++ } else { value-- } - s.registers.updateFlagZN(value) + s.Reg.updateFlagZN(value) setValue(value) } } func buildOpShift(isLeft bool, isRotate bool) opFunc { - return func(s *state, line []uint8, opcode opcode) { + return func(s *State, line []uint8, opcode opcode) { value, _, setValue := resolve(s, line, opcode) - oldCarry := s.registers.getFlagBit(flagC) + oldCarry := s.Reg.getFlagBit(flagC) var carry bool if isLeft { carry = (value & 0x80) != 0 @@ -149,60 +146,60 @@ func buildOpShift(isLeft bool, isRotate bool) opFunc { value += oldCarry << 7 } } - s.registers.updateFlag(flagC, carry) - s.registers.updateFlagZN(value) + s.Reg.updateFlag(flagC, carry) + s.Reg.updateFlagZN(value) setValue(value) } } func buildOpLoad(regDst int) opFunc { - return func(s *state, line []uint8, opcode opcode) { + return func(s *State, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - s.registers.setRegister(regDst, value) - s.registers.updateFlagZN(value) + s.Reg.setRegister(regDst, value) + s.Reg.updateFlagZN(value) } } func buildOpStore(regSrc int) opFunc { - return func(s *state, line []uint8, opcode opcode) { + return func(s *State, line []uint8, opcode opcode) { _, _, setValue := resolve(s, line, opcode) - value := s.registers.getRegister(regSrc) + value := s.Reg.getRegister(regSrc) setValue(value) } } func buildOpUpdateFlag(flag uint8, value bool) opFunc { - return func(s *state, line []uint8, opcode opcode) { - s.registers.updateFlag(flag, value) + return func(s *State, line []uint8, opcode opcode) { + s.Reg.updateFlag(flag, value) } } func buildOpBranch(flag uint8, value bool) opFunc { - return func(s *state, line []uint8, opcode opcode) { - if s.registers.getFlag(flag) == value { + return func(s *State, line []uint8, opcode opcode) { + if s.Reg.getFlag(flag) == value { // This assumes that PC is already pointing to the next instruction - pc := s.registers.getPC() + pc := s.Reg.getPC() pc += uint16(int8(line[1])) - s.registers.setPC(pc) + s.Reg.setPC(pc) } } } -func opBIT(s *state, line []uint8, opcode opcode) { +func opBIT(s *State, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - acc := s.registers.getA() + acc := s.Reg.getA() // Future note: The immediate addressing mode (65C02 or 65816 only) does not affect V. - s.registers.updateFlag(flagZ, value&acc == 0) - s.registers.updateFlag(flagN, value&(1<<7) != 0) - s.registers.updateFlag(flagV, value&(1<<6) != 0) + s.Reg.updateFlag(flagZ, value&acc == 0) + s.Reg.updateFlag(flagN, value&(1<<7) != 0) + s.Reg.updateFlag(flagV, value&(1<<6) != 0) } func buildOpCompare(reg int) opFunc { - return func(s *state, line []uint8, opcode opcode) { + return func(s *State, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - reference := s.registers.getRegister(reg) - s.registers.updateFlagZN(reference - value) - s.registers.updateFlag(flagC, reference >= value) + reference := s.Reg.getRegister(reg) + s.Reg.updateFlagZN(reference - value) + s.Reg.updateFlag(flagC, reference >= value) } } @@ -211,141 +208,141 @@ func operationOr(a uint8, b uint8) uint8 { return a | b } func operationXor(a uint8, b uint8) uint8 { return a ^ b } func buildOpLogic(operation func(uint8, uint8) uint8) opFunc { - return func(s *state, line []uint8, opcode opcode) { + return func(s *State, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - result := operation(value, s.registers.getA()) - s.registers.setA(result) - s.registers.updateFlagZN(result) + result := operation(value, s.Reg.getA()) + s.Reg.setA(result) + s.Reg.updateFlagZN(result) } } -func opADC(s *state, line []uint8, opcode opcode) { +func opADC(s *State, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - aValue := s.registers.getA() - carry := s.registers.getFlagBit(flagC) + aValue := s.Reg.getA() + carry := s.Reg.getFlagBit(flagC) total := uint16(aValue) + uint16(value) + uint16(carry) signedTotal := int16(int8(aValue)) + int16(int8(value)) + int16(carry) truncated := uint8(total) - if s.registers.getFlag(flagD) { + if s.Reg.getFlag(flagD) { totalBcdLo := int(aValue&0x0f) + int(value&0x0f) + int(carry) totalBcdHi := int(aValue>>4) + int(value>>4) if totalBcdLo >= 10 { totalBcdHi++ } totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10) - s.registers.setA(uint8(totalBcd)) - s.registers.updateFlag(flagC, totalBcdHi > 9) + s.Reg.setA(uint8(totalBcd)) + s.Reg.updateFlag(flagC, totalBcdHi > 9) } else { - s.registers.setA(truncated) - s.registers.updateFlag(flagC, total > 0xFF) + s.Reg.setA(truncated) + s.Reg.updateFlag(flagC, total > 0xFF) } // ZNV flags behave for BCD as if the operation was binary? - s.registers.updateFlagZN(truncated) - s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) + s.Reg.updateFlagZN(truncated) + s.Reg.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) } -func opSBC(s *state, line []uint8, opcode opcode) { +func opSBC(s *State, line []uint8, opcode opcode) { value, _, _ := resolve(s, line, opcode) - aValue := s.registers.getA() - carry := s.registers.getFlagBit(flagC) + aValue := s.Reg.getA() + carry := s.Reg.getFlagBit(flagC) total := 0x100 + uint16(aValue) - uint16(value) + uint16(carry) - 1 signedTotal := int16(int8(aValue)) - int16(int8(value)) + int16(carry) - 1 truncated := uint8(total) - if s.registers.getFlag(flagD) { + if s.Reg.getFlag(flagD) { totalBcdLo := 10 + int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1 totalBcdHi := 10 + int(aValue>>4) - int(value>>4) if totalBcdLo < 10 { totalBcdHi-- } totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10) - s.registers.setA(uint8(totalBcd)) - s.registers.updateFlag(flagC, totalBcdHi >= 10) + s.Reg.setA(uint8(totalBcd)) + s.Reg.updateFlag(flagC, totalBcdHi >= 10) } else { - s.registers.setA(truncated) - s.registers.updateFlag(flagC, total > 0xFF) + s.Reg.setA(truncated) + s.Reg.updateFlag(flagC, total > 0xFF) } // ZNV flags behave for SBC as if the operation was binary - s.registers.updateFlagZN(truncated) - s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) + s.Reg.updateFlagZN(truncated) + s.Reg.updateFlag(flagV, signedTotal < -128 || signedTotal > 127) } const stackAddress uint16 = 0x0100 -func pushByte(s *state, value uint8) { - adresss := stackAddress + uint16(s.registers.getSP()) - s.memory.poke(adresss, value) - s.registers.setSP(s.registers.getSP() - 1) +func pushByte(s *State, value uint8) { + adresss := stackAddress + uint16(s.Reg.getSP()) + s.Mem.Poke(adresss, value) + s.Reg.setSP(s.Reg.getSP() - 1) } -func pullByte(s *state) uint8 { - s.registers.setSP(s.registers.getSP() + 1) - adresss := stackAddress + uint16(s.registers.getSP()) - return s.memory.peek(adresss) +func pullByte(s *State) uint8 { + s.Reg.setSP(s.Reg.getSP() + 1) + adresss := stackAddress + uint16(s.Reg.getSP()) + return s.Mem.Peek(adresss) } -func pushWord(s *state, value uint16) { +func pushWord(s *State, value uint16) { pushByte(s, uint8(value>>8)) pushByte(s, uint8(value)) } -func pullWord(s *state) uint16 { +func pullWord(s *State) uint16 { return uint16(pullByte(s)) + (uint16(pullByte(s)) << 8) } -func opPLA(s *state, line []uint8, opcode opcode) { +func opPLA(s *State, line []uint8, opcode opcode) { value := pullByte(s) - s.registers.setA(value) - s.registers.updateFlagZN(value) + s.Reg.setA(value) + s.Reg.updateFlagZN(value) } -func opPLP(s *state, line []uint8, opcode opcode) { +func opPLP(s *State, line []uint8, opcode opcode) { value := pullByte(s) - s.registers.setP(value) + s.Reg.setP(value) } -func opPHA(s *state, line []uint8, opcode opcode) { - pushByte(s, s.registers.getA()) +func opPHA(s *State, line []uint8, opcode opcode) { + pushByte(s, s.Reg.getA()) } -func opPHP(s *state, line []uint8, opcode opcode) { - pushByte(s, s.registers.getP()|(flagB+flag5)) +func opPHP(s *State, line []uint8, opcode opcode) { + pushByte(s, s.Reg.getP()|(flagB+flag5)) } -func opJMP(s *state, line []uint8, opcode opcode) { +func opJMP(s *State, line []uint8, opcode opcode) { _, address, _ := resolve(s, line, opcode) - s.registers.setPC(address) + s.Reg.setPC(address) } -func opNOP(s *state, line []uint8, opcode opcode) {} +func opNOP(s *State, line []uint8, opcode opcode) {} -func opJSR(s *state, line []uint8, opcode opcode) { - pushWord(s, s.registers.getPC()-1) +func opJSR(s *State, line []uint8, opcode opcode) { + pushWord(s, s.Reg.getPC()-1) _, address, _ := resolve(s, line, opcode) - s.registers.setPC(address) + s.Reg.setPC(address) } -func opRTI(s *state, line []uint8, opcode opcode) { - s.registers.setP(pullByte(s)) - s.registers.setPC(pullWord(s)) +func opRTI(s *State, line []uint8, opcode opcode) { + s.Reg.setP(pullByte(s)) + s.Reg.setPC(pullWord(s)) } -func opRTS(s *state, line []uint8, opcode opcode) { - s.registers.setPC(pullWord(s) + 1) +func opRTS(s *State, line []uint8, opcode opcode) { + s.Reg.setPC(pullWord(s) + 1) } -func opBRK(s *state, line []uint8, opcode opcode) { - pushWord(s, s.registers.getPC()+1) - pushByte(s, s.registers.getP()|(flagB+flag5)) - s.registers.setFlag(flagI) - s.registers.setPC(s.memory.getWord(0xFFFE)) +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)) } var opcodes = [256]opcode{ @@ -523,21 +520,22 @@ var opcodes = [256]opcode{ 0xEA: opcode{"NOP", 1, 2, modeImplicit, opNOP}, } -func executeLine(s *state, line []uint8) { +func executeLine(s *State, line []uint8) { opcode := opcodes[line[0]] opcode.action(s, line, opcode) } -func executeInstruction(s *state, log bool) { - pc := s.registers.getPC() - opcode := opcodes[s.memory.peek(pc)] +// ExecuteInstruction transforms the state given after a single instruction is executed. +func ExecuteInstruction(s *State, log bool) { + pc := s.Reg.getPC() + opcode := opcodes[s.Mem.Peek(pc)] line := make([]uint8, opcode.bytes) for i := uint8(0); i < opcode.bytes; i++ { - line[i] = s.memory.peek(pc) + line[i] = s.Mem.Peek(pc) pc++ } - s.registers.setPC(pc) + s.Reg.setPC(pc) if log { fmt.Printf("%#04x %-12s: ", pc, lineString(s, line, opcode)) @@ -545,11 +543,18 @@ func executeInstruction(s *state, log bool) { opcode.action(s, line, opcode) if log { value, address, _ := resolve(s, line, opcode) - fmt.Printf("%v, [%04x:%02x], [%02x]\n", s.registers, address, value, line) + fmt.Printf("%v, [%04x:%02x], [%02x]\n", s.Reg, address, value, line) } } -func lineString(s *state, line []uint8, opcode opcode) string { +// Reset resets the processor state. Moves the program counter to the vector in 0cfffc. +func Reset(s *State) { + startAddress := s.Mem.getWord(0xfffc) + fmt.Println(startAddress) + s.Reg.setPC(startAddress) +} + +func lineString(s *State, line []uint8, opcode opcode) string { t := opcode.name switch opcode.addressMode { case modeImplicit: diff --git a/core6502/execute_test.go b/core6502/execute_test.go index dcd58f3..d273af8 100644 --- a/core6502/execute_test.go +++ b/core6502/execute_test.go @@ -1,490 +1,490 @@ -package main +package core6502 import ( "testing" ) func TestLoad(t *testing.T) { - var s state - s.memory.initWithRAM() + var s State + s.Mem.InitWithRAM() executeLine(&s, []uint8{0xA9, 0x42}) - if s.registers.getA() != 0x42 { + if s.Reg.getA() != 0x42 { t.Error("Error in LDA #") } executeLine(&s, []uint8{0xA9, 0x00}) - if s.registers.getP() != flagZ { + if s.Reg.getP() != flagZ { t.Error("Error in flags for LDA $0") } executeLine(&s, []uint8{0xA9, 0xF0}) - if s.registers.getP() != flagN { + if s.Reg.getP() != flagN { t.Error("Error in flags for LDA $F0") } executeLine(&s, []uint8{0xA0, 0xFE}) - if s.registers.getY() != 0xFE { + if s.Reg.getY() != 0xFE { t.Error("Error in LDY #") } - s.memory.poke(0x38, 0x87) + s.Mem.Poke(0x38, 0x87) executeLine(&s, []uint8{0xA5, 0x38}) - if s.registers.getA() != 0x87 { + if s.Reg.getA() != 0x87 { t.Error("Error in LDA zpg") } - s.memory.poke(0x57, 0x90) - s.registers.setX(0x10) + s.Mem.Poke(0x57, 0x90) + s.Reg.setX(0x10) executeLine(&s, []uint8{0xB5, 0x47}) - if s.registers.getA() != 0x90 { + if s.Reg.getA() != 0x90 { t.Error("Error in LDA zpg, X") } - s.memory.poke(0x38, 0x12) - s.registers.setX(0x89) + s.Mem.Poke(0x38, 0x12) + s.Reg.setX(0x89) executeLine(&s, []uint8{0xB5, 0xAF}) - if s.registers.getA() != 0x12 { + if s.Reg.getA() != 0x12 { t.Error("Error in LDA zpgX with sero page overflow") } - s.memory.poke(0x1234, 0x67) + s.Mem.Poke(0x1234, 0x67) executeLine(&s, []uint8{0xAD, 0x34, 0x12}) - if s.registers.getA() != 0x67 { + if s.Reg.getA() != 0x67 { t.Error("Error in LDA abs") } - s.memory.poke(0xC057, 0x7E) - s.registers.setX(0x57) + s.Mem.Poke(0xC057, 0x7E) + s.Reg.setX(0x57) executeLine(&s, []uint8{0xBD, 0x00, 0xC0}) - if s.registers.getA() != 0x7E { + if s.Reg.getA() != 0x7E { t.Error("Error in LDA abs, X") } - s.memory.poke(0xD059, 0x7A) - s.registers.setY(0x59) + s.Mem.Poke(0xD059, 0x7A) + s.Reg.setY(0x59) executeLine(&s, []uint8{0xB9, 0x00, 0xD0}) - if s.registers.getA() != 0x7A { + if s.Reg.getA() != 0x7A { t.Error("Error in LDA abs, Y") } - s.memory.poke(0x24, 0x74) - s.memory.poke(0x25, 0x20) - s.registers.setX(0x04) - s.memory.poke(0x2074, 0x66) + s.Mem.Poke(0x24, 0x74) + s.Mem.Poke(0x25, 0x20) + s.Reg.setX(0x04) + s.Mem.Poke(0x2074, 0x66) executeLine(&s, []uint8{0xA1, 0x20}) - if s.registers.getA() != 0x66 { + if s.Reg.getA() != 0x66 { t.Error("Error in LDA (oper,X)") } - s.memory.poke(0x86, 0x28) - s.memory.poke(0x87, 0x40) - s.registers.setY(0x10) - s.memory.poke(0x4038, 0x99) + s.Mem.Poke(0x86, 0x28) + s.Mem.Poke(0x87, 0x40) + s.Reg.setY(0x10) + s.Mem.Poke(0x4038, 0x99) executeLine(&s, []uint8{0xB1, 0x86}) - if s.registers.getA() != 0x99 { + if s.Reg.getA() != 0x99 { t.Error("Error in LDA (oper),Y") } } func TestStore(t *testing.T) { - var s state - s.memory.initWithRAM() - s.registers.setA(0x10) - s.registers.setX(0x40) - s.registers.setY(0x80) + var s State + s.Mem.InitWithRAM() + s.Reg.setA(0x10) + s.Reg.setX(0x40) + s.Reg.setY(0x80) executeLine(&s, []uint8{0x85, 0x50}) - if s.memory.peek(0x0050) != 0x10 { + if s.Mem.Peek(0x0050) != 0x10 { t.Error("Error in STA zpg") } executeLine(&s, []uint8{0x86, 0x51}) - if s.memory.peek(0x0051) != 0x40 { + if s.Mem.Peek(0x0051) != 0x40 { t.Error("Error in STX zpg") } executeLine(&s, []uint8{0x84, 0x52}) - if s.memory.peek(0x0052) != 0x80 { + if s.Mem.Peek(0x0052) != 0x80 { t.Error("Error in STY zpg") } executeLine(&s, []uint8{0x8D, 0x20, 0xC0}) - if s.memory.peek(0xC020) != 0x10 { + if s.Mem.Peek(0xC020) != 0x10 { t.Error("Error in STA abs") } executeLine(&s, []uint8{0x9D, 0x08, 0x10}) - if s.memory.peek(0x1048) != 0x10 { + if s.Mem.Peek(0x1048) != 0x10 { t.Error("Error in STA abs, X") } } func TestTransfer(t *testing.T) { - var s state + var s State - s.registers.setA(0xB0) + s.Reg.setA(0xB0) executeLine(&s, []uint8{0xAA}) - if s.registers.getX() != 0xB0 { + if s.Reg.getX() != 0xB0 { t.Error("Error in TAX") } - if s.registers.getP() != flagN { + if s.Reg.getP() != flagN { t.Error("Error in TAX flags") } - s.registers.setA(0xB1) + s.Reg.setA(0xB1) executeLine(&s, []uint8{0xA8}) - if s.registers.getY() != 0xB1 { + if s.Reg.getY() != 0xB1 { t.Error("Error in TAY") } - s.registers.setSP(0xB2) + s.Reg.setSP(0xB2) executeLine(&s, []uint8{0xBA}) - if s.registers.getX() != 0xB2 { + if s.Reg.getX() != 0xB2 { t.Error("Error in TSX") } - s.registers.setX(0xB3) + s.Reg.setX(0xB3) executeLine(&s, []uint8{0x8A}) - if s.registers.getA() != 0xB3 { + if s.Reg.getA() != 0xB3 { t.Error("Error in TXA") } - s.registers.setX(0xB4) + s.Reg.setX(0xB4) executeLine(&s, []uint8{0x9A}) - if s.registers.getSP() != 0xB4 { + if s.Reg.getSP() != 0xB4 { t.Error("Error in TXS") } - s.registers.setY(0xB5) + s.Reg.setY(0xB5) executeLine(&s, []uint8{0x98}) - if s.registers.getA() != 0xB5 { + if s.Reg.getA() != 0xB5 { t.Error("Error in TYA") } } func TestIncDec(t *testing.T) { - var s state + var s State - s.registers.setX(0x7E) + s.Reg.setX(0x7E) executeLine(&s, []uint8{0xE8}) - if s.registers.getX() != 0x7F { + if s.Reg.getX() != 0x7F { t.Errorf("Error in INX") } - s.registers.setY(0xFC) + s.Reg.setY(0xFC) executeLine(&s, []uint8{0x88}) - if s.registers.getY() != 0xFB { + if s.Reg.getY() != 0xFB { t.Error("Error in DEY") } - if s.registers.getP() != flagN { + if s.Reg.getP() != flagN { t.Error("Error in DEY flags") } } func TestShiftRotate(t *testing.T) { - var s state + var s State - s.registers.setA(0xF0) + s.Reg.setA(0xF0) executeLine(&s, []uint8{0x2A}) - if s.registers.getA() != 0xE0 { + if s.Reg.getA() != 0xE0 { t.Errorf("Error in ROL") } - if !s.registers.getFlag(flagC) { - t.Errorf("Error in ROL carry. %v", s.registers) + if !s.Reg.getFlag(flagC) { + t.Errorf("Error in ROL carry. %v", s.Reg) } - s.registers.setFlag(flagC) - s.registers.setA(0x0F) + s.Reg.setFlag(flagC) + s.Reg.setA(0x0F) executeLine(&s, []uint8{0x6A}) - if s.registers.getA() != 0x87 { - t.Errorf("Error in ROR. %v", s.registers) + if s.Reg.getA() != 0x87 { + t.Errorf("Error in ROR. %v", s.Reg) } - if !s.registers.getFlag(flagC) { + if !s.Reg.getFlag(flagC) { t.Errorf("Error in ROR carry") } - s.registers.setFlag(flagC) - s.registers.setA(0x81) + s.Reg.setFlag(flagC) + s.Reg.setA(0x81) executeLine(&s, []uint8{0x0A}) - if s.registers.getA() != 0x02 { - t.Errorf("Error in ASL. %v", s.registers) + if s.Reg.getA() != 0x02 { + t.Errorf("Error in ASL. %v", s.Reg) } - if !s.registers.getFlag(flagC) { + if !s.Reg.getFlag(flagC) { t.Errorf("Error in ASL carry") } - s.registers.setFlag(flagC) - s.registers.setA(0x02) + s.Reg.setFlag(flagC) + s.Reg.setA(0x02) executeLine(&s, []uint8{0x4A}) - if s.registers.getA() != 0x01 { - t.Errorf("Error in LSR. %v", s.registers) + if s.Reg.getA() != 0x01 { + t.Errorf("Error in LSR. %v", s.Reg) } - if s.registers.getFlag(flagC) { + if s.Reg.getFlag(flagC) { t.Errorf("Error in LSR carry") } } func TestClearSetFlag(t *testing.T) { - var s state - s.registers.setP(0x00) + var s State + s.Reg.setP(0x00) executeLine(&s, []uint8{0xF8}) - if !s.registers.getFlag(flagD) { - t.Errorf("Error in SED. %v", s.registers) + if !s.Reg.getFlag(flagD) { + t.Errorf("Error in SED. %v", s.Reg) } executeLine(&s, []uint8{0xD8}) - if s.registers.getFlag(flagD) { - t.Errorf("Error in CLD. %v", s.registers) + if s.Reg.getFlag(flagD) { + t.Errorf("Error in CLD. %v", s.Reg) } } func TestLogic(t *testing.T) { - var s state + var s State - s.registers.setA(0xF0) + s.Reg.setA(0xF0) executeLine(&s, []uint8{0x29, 0x1C}) - if s.registers.getA() != 0x10 { - t.Errorf("Error in AND <. %v", s.registers) + if s.Reg.getA() != 0x10 { + t.Errorf("Error in AND <. %v", s.Reg) } - s.registers.setA(0xF0) + s.Reg.setA(0xF0) executeLine(&s, []uint8{0x49, 0x1C}) - if s.registers.getA() != 0xEC { - t.Errorf("Error in EOR <. %v", s.registers) + if s.Reg.getA() != 0xEC { + t.Errorf("Error in EOR <. %v", s.Reg) } - s.registers.setA(0xF0) + s.Reg.setA(0xF0) executeLine(&s, []uint8{0x09, 0x0C}) - if s.registers.getA() != 0xFC { - t.Errorf("Error in ORA <. %v", s.registers) + if s.Reg.getA() != 0xFC { + t.Errorf("Error in ORA <. %v", s.Reg) } } func TestAdd(t *testing.T) { - var s state + var s State - s.registers.setA(0xA0) - s.registers.clearFlag(flagC) + s.Reg.setA(0xA0) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0x69, 0x0B}) - if s.registers.getA() != 0xAB { - t.Errorf("Error in ADC. %v", s.registers) + if s.Reg.getA() != 0xAB { + t.Errorf("Error in ADC. %v", s.Reg) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC. %v", s.registers) + if s.Reg.getFlag(flagC) { + t.Errorf("Error in carry ADC. %v", s.Reg) } - s.registers.setA(0xFF) - s.registers.clearFlag(flagC) + s.Reg.setA(0xFF) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0x69, 0x02}) - if s.registers.getA() != 0x01 { - t.Errorf("Error in ADC with carry. %v", s.registers) + if s.Reg.getA() != 0x01 { + t.Errorf("Error in ADC with carry. %v", s.Reg) } - if !s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC with carry. %v", s.registers) + if !s.Reg.getFlag(flagC) { + t.Errorf("Error in carry ADC with carry. %v", s.Reg) } - s.registers.setA(0xA0) - s.registers.setFlag(flagC) + s.Reg.setA(0xA0) + s.Reg.setFlag(flagC) executeLine(&s, []uint8{0x69, 0x01}) - if s.registers.getA() != 0xA2 { - t.Errorf("Error in carried ADC with carry. %v", s.registers) + if s.Reg.getA() != 0xA2 { + t.Errorf("Error in carried ADC with carry. %v", s.Reg) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry in carried ADC with carry. %v", s.registers) + if s.Reg.getFlag(flagC) { + t.Errorf("Error in carry in carried ADC with carry. %v", s.Reg) } } func TestAddDecimal(t *testing.T) { - var s state - s.registers.setFlag(flagD) + var s State + s.Reg.setFlag(flagD) - s.registers.setA(0x12) - s.registers.clearFlag(flagC) + s.Reg.setA(0x12) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0x69, 0x013}) - if s.registers.getA() != 0x25 { - t.Errorf("Error in ADC decimal. %v", s.registers) + if s.Reg.getA() != 0x25 { + t.Errorf("Error in ADC decimal. %v", s.Reg) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC. %v", s.registers) + if s.Reg.getFlag(flagC) { + t.Errorf("Error in carry ADC. %v", s.Reg) } - s.registers.setA(0x44) - s.registers.clearFlag(flagC) + s.Reg.setA(0x44) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0x69, 0x68}) - if s.registers.getA() != 0x12 { - t.Errorf("Error in ADC decimal with carry. %v", s.registers) + if s.Reg.getA() != 0x12 { + t.Errorf("Error in ADC decimal with carry. %v", s.Reg) } - if !s.registers.getFlag(flagC) { - t.Errorf("Error in carry ADC decimal with carry. %v", s.registers) + if !s.Reg.getFlag(flagC) { + t.Errorf("Error in carry ADC decimal with carry. %v", s.Reg) } - s.registers.setA(0x44) - s.registers.setFlag(flagC) + s.Reg.setA(0x44) + s.Reg.setFlag(flagC) executeLine(&s, []uint8{0x69, 0x23}) - if s.registers.getA() != 0x68 { - t.Errorf("Error in carried ADC decimal with carry. %v", s.registers) + if s.Reg.getA() != 0x68 { + t.Errorf("Error in carried ADC decimal with carry. %v", s.Reg) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry in carried ADC decimal with carry. %v", s.registers) + if s.Reg.getFlag(flagC) { + t.Errorf("Error in carry in carried ADC decimal with carry. %v", s.Reg) } } func TestSub(t *testing.T) { - var s state + var s State - s.registers.setA(0x09) - s.registers.clearFlag(flagC) + s.Reg.setA(0x09) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0xE9, 0x05}) - if s.registers.getA() != 0x03 { - t.Errorf("Error in SBC. %v", s.registers) + if s.Reg.getA() != 0x03 { + t.Errorf("Error in SBC. %v", s.Reg) } - if !s.registers.getFlag(flagC) { - t.Errorf("Error in carry SBC. %v", s.registers) + if !s.Reg.getFlag(flagC) { + t.Errorf("Error in carry SBC. %v", s.Reg) } - s.registers.setA(0x01) - s.registers.clearFlag(flagC) + s.Reg.setA(0x01) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0xE9, 0x02}) - if s.registers.getA() != 0xFE { - t.Errorf("Error in SBC with carry. %v", s.registers) + if s.Reg.getA() != 0xFE { + t.Errorf("Error in SBC with carry. %v", s.Reg) } - if s.registers.getFlag(flagC) { - t.Errorf("Error in carry SBC with carry. %v", s.registers) + if s.Reg.getFlag(flagC) { + t.Errorf("Error in carry SBC with carry. %v", s.Reg) } - s.registers.setA(0x08) - s.registers.setFlag(flagC) + s.Reg.setA(0x08) + s.Reg.setFlag(flagC) executeLine(&s, []uint8{0xE9, 0x02}) - if s.registers.getA() != 0x06 { - t.Errorf("Error in carried SBC with carry. %v", s.registers) + if s.Reg.getA() != 0x06 { + t.Errorf("Error in carried SBC with carry. %v", s.Reg) } - if !s.registers.getFlag(flagC) { - t.Errorf("Error in carry in carried SBC with carry. %v", s.registers) + if !s.Reg.getFlag(flagC) { + t.Errorf("Error in carry in carried SBC with carry. %v", s.Reg) } } func TestCompare(t *testing.T) { - var s state + var s State - s.registers.setA(0x02) + s.Reg.setA(0x02) executeLine(&s, []uint8{0xC9, 0x01}) - if s.registers.getP() != 0x01 { - t.Errorf("Error in CMP <. %v", s.registers) + if s.Reg.getP() != 0x01 { + t.Errorf("Error in CMP <. %v", s.Reg) } executeLine(&s, []uint8{0xC9, 0x02}) - if s.registers.getP() != 0x03 { - t.Errorf("Error in CMP =. %v", s.registers) + if s.Reg.getP() != 0x03 { + t.Errorf("Error in CMP =. %v", s.Reg) } executeLine(&s, []uint8{0xC9, 0x03}) - if s.registers.getP() != 0x80 { - t.Errorf("Error in CMP >. %v", s.registers) + if s.Reg.getP() != 0x80 { + t.Errorf("Error in CMP >. %v", s.Reg) } - s.registers.setX(0x04) + s.Reg.setX(0x04) executeLine(&s, []uint8{0xE0, 0x05}) - if s.registers.getP() != 0x80 { - t.Errorf("Error in CPX >. %v", s.registers) + if s.Reg.getP() != 0x80 { + t.Errorf("Error in CPX >. %v", s.Reg) } - s.registers.setY(0x08) + s.Reg.setY(0x08) executeLine(&s, []uint8{0xC0, 0x09}) - if s.registers.getP() != 0x80 { - t.Errorf("Error in CPY >. %v", s.registers) + if s.Reg.getP() != 0x80 { + t.Errorf("Error in CPY >. %v", s.Reg) } } func TestBit(t *testing.T) { - var s state - s.memory.initWithRAM() + var s State + s.Mem.InitWithRAM() - s.registers.setA(0x0F) - s.memory.poke(0x0040, 0xF0) + s.Reg.setA(0x0F) + s.Mem.Poke(0x0040, 0xF0) executeLine(&s, []uint8{0x24, 0x40}) - if s.registers.getP() != 0xC2 { - t.Errorf("Error in BIT. %v", s.registers) + if s.Reg.getP() != 0xC2 { + t.Errorf("Error in BIT. %v", s.Reg) } - s.registers.setA(0xF0) - s.memory.poke(0x0040, 0xF0) + s.Reg.setA(0xF0) + s.Mem.Poke(0x0040, 0xF0) executeLine(&s, []uint8{0x24, 0x40}) - if s.registers.getP() != 0xC0 { - t.Errorf("Error in BIT, 2. %v", s.registers) + if s.Reg.getP() != 0xC0 { + t.Errorf("Error in BIT, 2. %v", s.Reg) } - s.registers.setA(0xF0) - s.memory.poke(0x01240, 0x80) + s.Reg.setA(0xF0) + s.Mem.Poke(0x01240, 0x80) executeLine(&s, []uint8{0x2C, 0x40, 0x12}) - if s.registers.getP() != 0x80 { - t.Errorf("Error in BIT, 2. %v", s.registers) + if s.Reg.getP() != 0x80 { + t.Errorf("Error in BIT, 2. %v", s.Reg) } } func TestBranch(t *testing.T) { - var s state + var s State - s.registers.setPC(0xC600) - s.registers.setFlag(flagV) + s.Reg.setPC(0xC600) + s.Reg.setFlag(flagV) executeLine(&s, []uint8{0x50, 0x20}) - if s.registers.getPC() != 0xC600 { - t.Errorf("Error in BVC, %v", s.registers) + if s.Reg.getPC() != 0xC600 { + t.Errorf("Error in BVC, %v", s.Reg) } executeLine(&s, []uint8{0x70, 0x20}) - if s.registers.getPC() != 0xC620 { - t.Errorf("Error in BVS, %v", s.registers) + if s.Reg.getPC() != 0xC620 { + t.Errorf("Error in BVS, %v", s.Reg) } - s.registers.setPC(0xD600) - s.registers.clearFlag(flagC) + s.Reg.setPC(0xD600) + s.Reg.clearFlag(flagC) executeLine(&s, []uint8{0x90, 0xA0}) - if s.registers.getPC() != 0xD5A0 { - t.Errorf("Error in BCC, %v", s.registers) + if s.Reg.getPC() != 0xD5A0 { + t.Errorf("Error in BCC, %v", s.Reg) } } func TestStack(t *testing.T) { - var s state - s.memory.initWithRAM() + var s State + s.Mem.InitWithRAM() - s.registers.setSP(0xF0) - s.registers.setA(0xA0) - s.registers.setP(0x0A) + s.Reg.setSP(0xF0) + s.Reg.setA(0xA0) + s.Reg.setP(0x0A) executeLine(&s, []uint8{0x48}) - if s.registers.getSP() != 0xEF { - t.Errorf("Error in PHA stack pointer, %v", s.registers) + if s.Reg.getSP() != 0xEF { + t.Errorf("Error in PHA stack pointer, %v", s.Reg) } - if s.memory.peek(0x01F0) != 0xA0 { - t.Errorf("Error in PHA, %v", s.registers) + if s.Mem.Peek(0x01F0) != 0xA0 { + t.Errorf("Error in PHA, %v", s.Reg) } executeLine(&s, []uint8{0x08}) - if s.registers.getSP() != 0xEE { - t.Errorf("Error in PHP stack pointer, %v", s.registers) + if s.Reg.getSP() != 0xEE { + t.Errorf("Error in PHP stack pointer, %v", s.Reg) } - if s.memory.peek(0x01EF) != 0x3A { - t.Errorf("Error in PHP, %v", s.registers) + if s.Mem.Peek(0x01EF) != 0x3A { + t.Errorf("Error in PHP, %v", s.Reg) } executeLine(&s, []uint8{0x68}) - if s.registers.getSP() != 0xEF { - t.Errorf("Error in PLA stack pointer, %v", s.registers) + if s.Reg.getSP() != 0xEF { + t.Errorf("Error in PLA stack pointer, %v", s.Reg) } - if s.registers.getA() != 0x3A { - t.Errorf("Error in PLA, %v", s.registers) + if s.Reg.getA() != 0x3A { + t.Errorf("Error in PLA, %v", s.Reg) } executeLine(&s, []uint8{0x28}) - if s.registers.getSP() != 0xF0 { - t.Errorf("Error in PLP stack pointer, %v", s.registers) + if s.Reg.getSP() != 0xF0 { + t.Errorf("Error in PLP stack pointer, %v", s.Reg) } - if s.registers.getP() != 0xA0 { - t.Errorf("Error in PLP, %v", s.registers) + if s.Reg.getP() != 0xA0 { + t.Errorf("Error in PLP, %v", s.Reg) } } diff --git a/core6502/memory.go b/core6502/memory.go index df58413..fa5634b 100644 --- a/core6502/memory.go +++ b/core6502/memory.go @@ -1,4 +1,4 @@ -package main +package core6502 import ( "bufio" @@ -6,86 +6,46 @@ import ( "os" ) -type memoryPage interface { - peek(uint8) uint8 - poke(uint8, uint8) - getData() *[256]uint8 +// MemoryPage is a data page of 256 bytes +type MemoryPage interface { + Peek(uint8) uint8 + Poke(uint8, uint8) } -type ramPage struct { - data [256]uint8 +// Memory represents the addressable space of the processor +type Memory struct { + data [256]MemoryPage } -type romPage struct { - data [256]uint8 -} - -type memory struct { - data [256]memoryPage -} - -func (p *ramPage) peek(address uint8) uint8 { - return p.data[address] -} - -func (p *ramPage) poke(address uint8, value uint8) { - p.data[address] = value -} - -func (p *ramPage) getData() *[256]uint8 { - return &p.data -} - -func (p *romPage) peek(address uint8) uint8 { - return p.data[address] -} - -func (p *romPage) poke(address uint8, value uint8) { - // Do nothing -} - -func (p *romPage) getData() *[256]uint8 { - return &p.data -} - -func (m *memory) peek(address uint16) 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) + return m.data[hi].Peek(lo) } -func (m *memory) poke(address uint16, value uint8) { +// 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) + m.data[hi].Poke(lo, value) } -func (m *memory) getWord(address uint16) uint16 { - return uint16(m.peek(address)) + 0x100*uint16(m.peek(address+1)) +// SetPage assigns a MemoryPage implementation on the page given +func (m *Memory) SetPage(index uint8, page MemoryPage) { + m.data[index] = page } -func (m *memory) getZeroPageWord(address uint8) uint16 { - return uint16(m.peek(uint16(address))) + 0x100*uint16(m.peek(uint16(address+1))) +func (m *Memory) getWord(address uint16) uint16 { + return uint16(m.Peek(address)) + 0x100*uint16(m.Peek(address+1)) } -func (m *memory) initWithRAM() { - var ramPages [256]ramPage - for i := 0; i < 256; i++ { - m.data[i] = &ramPages[i] - } +func (m *Memory) getZeroPageWord(address uint8) uint16 { + return uint16(m.Peek(uint16(address))) + 0x100*uint16(m.Peek(uint16(address+1))) } -func (m *memory) transformToRom(page uint8) { - var romPage romPage - ramPage := m.data[page] - romPage.data = *ramPage.getData() - m.data[page] = &romPage -} - -func (m *memory) initWithRomAndText(filename string, textPages *textPages) { - // Valid for ROMs with size 20480 bytes = 20 KB = 80 pages - // from $B000 to $F000 +func (m *Memory) loadBinary(filename string) { // Load file f, err := os.Open(filename) if err != nil { @@ -104,48 +64,13 @@ func (m *memory) initWithRomAndText(filename string, textPages *textPages) { buf := bufio.NewReader(f) buf.Read(bytes) - m.initWithRAM() - romStart := uint16(0xFFFF - size + 1) + m.InitWithRAM() for i, v := range bytes { - m.poke(uint16(i)+romStart, uint8(v)) - } - - var i uint8 - for i = 217; i != 0; i++ { - m.transformToRom(i) - } - - for j := 0; j < 4; j++ { - m.data[4+j] = &(textPages.pages[j]) + m.Poke(uint16(i), uint8(v)) } } -func (m *memory) loadBinary(filename string) { - // Load file - f, err := os.Open(filename) - if err != nil { - panic(err) - } - defer f.Close() - - stats, statsErr := f.Stat() - if statsErr != nil { - panic(err) - } - - size := stats.Size() - bytes := make([]byte, size) - - 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) { +func (m *Memory) printPage(page uint8) { address := uint16(page) * 0x100 for i := 0; i < 16; i++ { fmt.Printf("%#04x: ", address) diff --git a/core6502/registers.go b/core6502/registers.go index 7c0587c..494a698 100644 --- a/core6502/registers.go +++ b/core6502/registers.go @@ -1,4 +1,4 @@ -package main +package core6502 import "fmt" @@ -23,56 +23,56 @@ const ( flagC uint8 = 1 << 0 ) -type registers struct { +type Registers struct { data [8]uint8 } -func (r *registers) getRegister(i int) uint8 { return r.data[i] } +func (r *Registers) getRegister(i int) uint8 { return r.data[i] } -func (r *registers) getA() uint8 { return r.data[regA] } -func (r *registers) getX() uint8 { return r.data[regX] } -func (r *registers) getY() uint8 { return r.data[regY] } -func (r *registers) getP() uint8 { return r.data[regP] } -func (r *registers) getSP() uint8 { return r.data[regSP] } +func (r *Registers) getA() uint8 { return r.data[regA] } +func (r *Registers) getX() uint8 { return r.data[regX] } +func (r *Registers) getY() uint8 { return r.data[regY] } +func (r *Registers) getP() uint8 { return r.data[regP] } +func (r *Registers) getSP() uint8 { return r.data[regSP] } -func (r *registers) setRegister(i int, v uint8) { +func (r *Registers) setRegister(i int, v uint8) { r.data[i] = v } -func (r *registers) setA(v uint8) { r.setRegister(regA, v) } -func (r *registers) setX(v uint8) { r.setRegister(regX, v) } -func (r *registers) setY(v uint8) { r.setRegister(regY, v) } -func (r *registers) setP(v uint8) { r.setRegister(regP, v) } -func (r *registers) setSP(v uint8) { r.setRegister(regSP, v) } +func (r *Registers) setA(v uint8) { r.setRegister(regA, v) } +func (r *Registers) setX(v uint8) { r.setRegister(regX, v) } +func (r *Registers) setY(v uint8) { r.setRegister(regY, v) } +func (r *Registers) setP(v uint8) { r.setRegister(regP, v) } +func (r *Registers) setSP(v uint8) { r.setRegister(regSP, v) } -func (r *registers) getPC() uint16 { +func (r *Registers) getPC() uint16 { return uint16(r.data[regPC])*256 + uint16(r.data[regPC+1]) } -func (r *registers) setPC(v uint16) { +func (r *Registers) setPC(v uint16) { r.data[regPC] = uint8(v >> 8) r.data[regPC+1] = uint8(v) } -func (r *registers) getFlagBit(i uint8) uint8 { +func (r *Registers) getFlagBit(i uint8) uint8 { if r.getFlag(i) { return 1 } return 0 } -func (r *registers) getFlag(i uint8) bool { +func (r *Registers) getFlag(i uint8) bool { return (r.data[regP] & i) != 0 } -func (r *registers) setFlag(i uint8) { +func (r *Registers) setFlag(i uint8) { r.data[regP] |= i } -func (r *registers) clearFlag(i uint8) { +func (r *Registers) clearFlag(i uint8) { r.data[regP] &^= i } -func (r *registers) updateFlag(i uint8, v bool) { +func (r *Registers) updateFlag(i uint8, v bool) { if v { r.setFlag(i) } else { @@ -80,12 +80,12 @@ func (r *registers) updateFlag(i uint8, v bool) { } } -func (r *registers) updateFlagZN(t uint8) { +func (r *Registers) updateFlagZN(t uint8) { r.updateFlag(flagZ, t == 0) r.updateFlag(flagN, t >= (1<<7)) } -func (r registers) String() string { +func (r Registers) String() string { return fmt.Sprintf("A: %#02x, X: %#02x, Y: %#02x, SP: %#02x, PC: %#04x, P: %#02x, (NV-BDIZC): %08b", r.getA(), r.getX(), r.getY(), r.getSP(), r.getPC(), r.getP(), r.getP()) } diff --git a/core6502/registers_test.go b/core6502/registers_test.go index 45862cf..47e5079 100644 --- a/core6502/registers_test.go +++ b/core6502/registers_test.go @@ -1,9 +1,9 @@ -package main +package core6502 import "testing" func TestRegA(t *testing.T) { - var r registers + var r Registers var data uint8 data = 200 r.setA(data) @@ -12,7 +12,7 @@ func TestRegA(t *testing.T) { } } func TestRegPC(t *testing.T) { - var r registers + var r Registers var data uint16 data = 0xc600 r.setPC(data) @@ -22,7 +22,7 @@ func TestRegPC(t *testing.T) { } func TestFlags(t *testing.T) { - var r registers + var r Registers r.setP(0x23) if r.getP() != 0x23 { t.Error("Error storing and loading P") @@ -51,7 +51,7 @@ func TestFlags(t *testing.T) { } func TestUpdateFlagZN(t *testing.T) { - var r registers + var r Registers r.updateFlagZN(0) if r.getP() != flagZ { t.Error("Error update flags ZN with 0") @@ -66,4 +66,4 @@ func TestUpdateFlagZN(t *testing.T) { if r.getP() != flagN { t.Error("Error update flags ZN with 0xF2") } -} \ No newline at end of file +} diff --git a/core6502/rxmPage.go b/core6502/rxmPage.go new file mode 100644 index 0000000..5ba594c --- /dev/null +++ b/core6502/rxmPage.go @@ -0,0 +1,81 @@ +package core6502 + +import ( + "bufio" + "os" +) + +type ramPage struct { + data [256]uint8 +} + +type romPage struct { + data [256]uint8 +} + +func (p *ramPage) Peek(address uint8) uint8 { + return p.data[address] +} + +func (p *ramPage) Poke(address uint8, value uint8) { + p.data[address] = value +} + +func (p *romPage) Peek(address uint8) uint8 { + return p.data[address] +} + +func (p *romPage) Poke(address uint8, value uint8) { + // Do nothing +} + +func (p *romPage) burn(address uint8, value uint8) { + p.data[address] = value +} + +// InitWithRAM adds RAM memory to all the memory pages +func (m *Memory) InitWithRAM() { + var ramPages [256]ramPage + for i := 0; i < 256; i++ { + m.SetPage(uint8(i), &ramPages[i]) + } +} + +func (m *Memory) transformToRom(page uint8) { + var romPage romPage + address := uint16(page) << 8 + for i := 0; i < 256; i++ { + romPage.burn(uint8(i), m.Peek(address)) + address++ + } + m.SetPage(page, &romPage) +} + +// LoadRom loads a binary file to the top of the memory and makes those pages read only. +func (m *Memory) LoadRom(filename string) { + f, err := os.Open(filename) + if err != nil { + panic(err) + } + defer f.Close() + + stats, statsErr := f.Stat() + if statsErr != nil { + panic(err) + } + + size := stats.Size() + bytes := make([]byte, size) + + buf := bufio.NewReader(f) + buf.Read(bytes) + + romStart := uint16(0xFFFF - size + 1) + for i, v := range bytes { + m.Poke(uint16(i)+romStart, uint8(v)) + } + + for i := uint8(romStart >> 8); i != 0; i++ { + m.transformToRom(i) + } +} diff --git a/main.go b/main.go index dfa9f26..e0b27c2 100644 --- a/main.go +++ b/main.go @@ -1,34 +1,12 @@ package main +import "go6502/apple2" + func main() { - var s state - var t textPages - var io ioC0Page + romFile := "../roms/apple.rom" + //romFile := "../roms/APPLE2.ROM" - /* - for c := uint8(0); c < 40; c++ { - for l := uint8(0); l < 24; l++ { - t.write(c, l, '0'+(c+l)%10) - t.dump() - } - } - */ - //s.memory.initWithRomAndText("../roms/APPLE2.ROM", &t) - s.memory.initWithRomAndText("../roms/apple.rom", &t) - //s.memory.initWithRomAndText("../roms/apple2o.rom", &t) - s.memory.data[0xc0] = &io + log := false - startAddress := s.memory.getWord(0xfffc) - s.registers.setPC(startAddress) - for true { - log := false - pc := s.registers.getPC() - executeInstruction(&s, log) - if pc == s.registers.getPC() { - //s.memory.printPage(0x00) - //s.memory.printPage(0x01) - panic("No change in PC") - } - t.dumpIfDirty() - } + apple2.Run(romFile, log) }