mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-01-17 12:32:11 +00:00
Project files organization. Second commit wuth the file changes
This commit is contained in:
parent
a3ca5439a0
commit
33ccf5e4c3
25
apple2/apple2.go
Normal file
25
apple2/apple2.go
Normal file
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package apple2
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
@ -51,21 +51,16 @@ var softSwitches = [256]softSwitch{
|
|||||||
0x5f: softSwitch{ioFlagAnnunciator3, true, false},
|
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)
|
//fmt.Printf("Peek on $C0%02x ", address)
|
||||||
return p.access(address, false, 0)
|
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)
|
//fmt.Printf("Poke on $C0%02x with %02x ", address, value)
|
||||||
p.access(address, true, 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 {
|
func (p *ioC0Page) access(address uint8, isWrite bool, value uint8) uint8 {
|
||||||
|
|
||||||
ss := softSwitches[address]
|
ss := softSwitches[address]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package apple2
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
@ -11,20 +11,16 @@ type textPage struct {
|
|||||||
data [256]uint8
|
data [256]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *textPage) peek(address uint8) uint8 {
|
func (p *textPage) Peek(address uint8) uint8 {
|
||||||
return p.data[address]
|
return p.data[address]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *textPage) poke(address uint8, value uint8) {
|
func (p *textPage) Poke(address uint8, value uint8) {
|
||||||
p.data[address] = value
|
p.data[address] = value
|
||||||
// Note: we could avoid setting dirty on the 16 blocks of 8 hidden bytes
|
// Note: we could avoid setting dirty on the 16 blocks of 8 hidden bytes
|
||||||
p.dirty = true
|
p.dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *textPage) getData() *[256]uint8 {
|
|
||||||
return &p.data
|
|
||||||
}
|
|
||||||
|
|
||||||
func textMemoryByteToString(value uint8) string {
|
func textMemoryByteToString(value uint8) string {
|
||||||
value = value & 0x7F
|
value = value & 0x7F
|
||||||
if value < ' ' {
|
if value < ' ' {
|
||||||
@ -53,7 +49,7 @@ func (tp *textPages) dump() {
|
|||||||
for _, h = range []uint8{0, 128} {
|
for _, h = range []uint8{0, 128} {
|
||||||
line := ""
|
line := ""
|
||||||
for j = i + h; j < i+h+40; j++ {
|
for j = i + h; j < i+h+40; j++ {
|
||||||
line += textMemoryByteToString(p.peek(j))
|
line += textMemoryByteToString(p.Peek(j))
|
||||||
}
|
}
|
||||||
fmt.Printf("| %v |\n", line)
|
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 {
|
func (tp *textPages) read(column uint8, line uint8) uint8 {
|
||||||
page, address := tp.charAddress(column, line)
|
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) {
|
func (tp *textPages) write(column uint8, line uint8, value uint8) {
|
||||||
page, address := tp.charAddress(column, line)
|
page, address := tp.charAddress(column, line)
|
||||||
tp.pages[page].poke(address, value)
|
tp.pages[page].Poke(address, value)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package apple2
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package core6502
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -7,15 +7,15 @@ import (
|
|||||||
|
|
||||||
func TestFunctional(t *testing.T) {
|
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
|
// 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 {
|
for true {
|
||||||
testCase := s.memory.peek(0x0200)
|
testCase := s.Mem.Peek(0x0200)
|
||||||
if testCase >= 240 {
|
if testCase >= 240 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -23,9 +23,9 @@ func TestFunctional(t *testing.T) {
|
|||||||
if log {
|
if log {
|
||||||
fmt.Printf("[ %d ] ", testCase)
|
fmt.Printf("[ %d ] ", testCase)
|
||||||
}
|
}
|
||||||
pc := s.registers.getPC()
|
pc := s.Reg.getPC()
|
||||||
executeInstruction(&s, log)
|
ExecuteInstruction(&s, log)
|
||||||
if pc == s.registers.getPC() {
|
if pc == s.Reg.getPC() {
|
||||||
//s.memory.printPage(0x00)
|
//s.memory.printPage(0x00)
|
||||||
//s.memory.printPage(0x01)
|
//s.memory.printPage(0x01)
|
||||||
t.Errorf("Failuse in test %v.", testCase)
|
t.Errorf("Failuse in test %v.", testCase)
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package main
|
package core6502
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type state struct {
|
// State represents the state of the simulated device
|
||||||
registers registers
|
type State struct {
|
||||||
memory memory
|
Reg Registers
|
||||||
}
|
Mem Memory
|
||||||
|
|
||||||
func step(s *state) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -38,21 +35,21 @@ func getWordInLine(line []uint8) uint16 {
|
|||||||
return uint16(line[1]) + 0x100*uint16(line[2])
|
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
|
hasAddress := true
|
||||||
register := regNone
|
register := regNone
|
||||||
|
|
||||||
switch opcode.addressMode {
|
switch opcode.addressMode {
|
||||||
case modeAccumulator:
|
case modeAccumulator:
|
||||||
value = s.registers.getA()
|
value = s.Reg.getA()
|
||||||
hasAddress = false
|
hasAddress = false
|
||||||
register = regA
|
register = regA
|
||||||
case modeImplicitX:
|
case modeImplicitX:
|
||||||
value = s.registers.getX()
|
value = s.Reg.getX()
|
||||||
hasAddress = false
|
hasAddress = false
|
||||||
register = regX
|
register = regX
|
||||||
case modeImplicitY:
|
case modeImplicitY:
|
||||||
value = s.registers.getY()
|
value = s.Reg.getY()
|
||||||
hasAddress = false
|
hasAddress = false
|
||||||
register = regY
|
register = regY
|
||||||
case modeImmediate:
|
case modeImmediate:
|
||||||
@ -61,35 +58,35 @@ func resolve(s *state, line []uint8, opcode opcode) (value uint8, address uint16
|
|||||||
case modeZeroPage:
|
case modeZeroPage:
|
||||||
address = uint16(line[1])
|
address = uint16(line[1])
|
||||||
case modeZeroPageX:
|
case modeZeroPageX:
|
||||||
address = uint16(line[1] + s.registers.getX())
|
address = uint16(line[1] + s.Reg.getX())
|
||||||
case modeZeroPageY:
|
case modeZeroPageY:
|
||||||
address = uint16(line[1] + s.registers.getY())
|
address = uint16(line[1] + s.Reg.getY())
|
||||||
case modeAbsolute:
|
case modeAbsolute:
|
||||||
address = getWordInLine(line)
|
address = getWordInLine(line)
|
||||||
case modeAbsoluteX:
|
case modeAbsoluteX:
|
||||||
address = getWordInLine(line) + uint16(s.registers.getX())
|
address = getWordInLine(line) + uint16(s.Reg.getX())
|
||||||
case modeAbsoluteY:
|
case modeAbsoluteY:
|
||||||
address = getWordInLine(line) + uint16(s.registers.getY())
|
address = getWordInLine(line) + uint16(s.Reg.getY())
|
||||||
case modeIndexedIndirectX:
|
case modeIndexedIndirectX:
|
||||||
addressAddress := uint8(line[1] + s.registers.getX())
|
addressAddress := uint8(line[1] + s.Reg.getX())
|
||||||
address = s.memory.getZeroPageWord(addressAddress)
|
address = s.Mem.getZeroPageWord(addressAddress)
|
||||||
case modeIndirect:
|
case modeIndirect:
|
||||||
addressAddress := getWordInLine(line)
|
addressAddress := getWordInLine(line)
|
||||||
address = s.memory.getWord(addressAddress)
|
address = s.Mem.getWord(addressAddress)
|
||||||
case modeIndirectIndexedY:
|
case modeIndirectIndexedY:
|
||||||
address = s.memory.getZeroPageWord(line[1]) +
|
address = s.Mem.getZeroPageWord(line[1]) +
|
||||||
uint16(s.registers.getY())
|
uint16(s.Reg.getY())
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasAddress {
|
if hasAddress {
|
||||||
value = s.memory.peek(address)
|
value = s.Mem.Peek(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue = func(value uint8) {
|
setValue = func(value uint8) {
|
||||||
if hasAddress {
|
if hasAddress {
|
||||||
s.memory.poke(address, value)
|
s.Mem.Poke(address, value)
|
||||||
} else if register != regNone {
|
} else if register != regNone {
|
||||||
s.registers.setRegister(register, value)
|
s.Reg.setRegister(register, value)
|
||||||
} else {
|
} else {
|
||||||
// Todo: assert impossible
|
// Todo: assert impossible
|
||||||
}
|
}
|
||||||
@ -105,36 +102,36 @@ type opcode struct {
|
|||||||
action opFunc
|
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 {
|
func buildOpTransfer(regSrc int, regDst int) opFunc {
|
||||||
return func(s *state, line []uint8, opcode opcode) {
|
return func(s *State, line []uint8, opcode opcode) {
|
||||||
value := s.registers.getRegister(regSrc)
|
value := s.Reg.getRegister(regSrc)
|
||||||
s.registers.setRegister(regDst, value)
|
s.Reg.setRegister(regDst, value)
|
||||||
if regDst != regSP {
|
if regDst != regSP {
|
||||||
s.registers.updateFlagZN(value)
|
s.Reg.updateFlagZN(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpIncDec(inc bool) opFunc {
|
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)
|
value, _, setValue := resolve(s, line, opcode)
|
||||||
if inc {
|
if inc {
|
||||||
value++
|
value++
|
||||||
} else {
|
} else {
|
||||||
value--
|
value--
|
||||||
}
|
}
|
||||||
s.registers.updateFlagZN(value)
|
s.Reg.updateFlagZN(value)
|
||||||
setValue(value)
|
setValue(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpShift(isLeft bool, isRotate bool) opFunc {
|
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)
|
value, _, setValue := resolve(s, line, opcode)
|
||||||
|
|
||||||
oldCarry := s.registers.getFlagBit(flagC)
|
oldCarry := s.Reg.getFlagBit(flagC)
|
||||||
var carry bool
|
var carry bool
|
||||||
if isLeft {
|
if isLeft {
|
||||||
carry = (value & 0x80) != 0
|
carry = (value & 0x80) != 0
|
||||||
@ -149,60 +146,60 @@ func buildOpShift(isLeft bool, isRotate bool) opFunc {
|
|||||||
value += oldCarry << 7
|
value += oldCarry << 7
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.registers.updateFlag(flagC, carry)
|
s.Reg.updateFlag(flagC, carry)
|
||||||
s.registers.updateFlagZN(value)
|
s.Reg.updateFlagZN(value)
|
||||||
setValue(value)
|
setValue(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpLoad(regDst int) opFunc {
|
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)
|
value, _, _ := resolve(s, line, opcode)
|
||||||
s.registers.setRegister(regDst, value)
|
s.Reg.setRegister(regDst, value)
|
||||||
s.registers.updateFlagZN(value)
|
s.Reg.updateFlagZN(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpStore(regSrc int) opFunc {
|
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)
|
_, _, setValue := resolve(s, line, opcode)
|
||||||
value := s.registers.getRegister(regSrc)
|
value := s.Reg.getRegister(regSrc)
|
||||||
setValue(value)
|
setValue(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpUpdateFlag(flag uint8, value bool) opFunc {
|
func buildOpUpdateFlag(flag uint8, value bool) opFunc {
|
||||||
return func(s *state, line []uint8, opcode opcode) {
|
return func(s *State, line []uint8, opcode opcode) {
|
||||||
s.registers.updateFlag(flag, value)
|
s.Reg.updateFlag(flag, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpBranch(flag uint8, value bool) opFunc {
|
func buildOpBranch(flag uint8, value bool) opFunc {
|
||||||
return func(s *state, line []uint8, opcode opcode) {
|
return func(s *State, line []uint8, opcode opcode) {
|
||||||
if s.registers.getFlag(flag) == value {
|
if s.Reg.getFlag(flag) == value {
|
||||||
// This assumes that PC is already pointing to the next instruction
|
// This assumes that PC is already pointing to the next instruction
|
||||||
pc := s.registers.getPC()
|
pc := s.Reg.getPC()
|
||||||
pc += uint16(int8(line[1]))
|
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)
|
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.
|
// Future note: The immediate addressing mode (65C02 or 65816 only) does not affect V.
|
||||||
s.registers.updateFlag(flagZ, value&acc == 0)
|
s.Reg.updateFlag(flagZ, value&acc == 0)
|
||||||
s.registers.updateFlag(flagN, value&(1<<7) != 0)
|
s.Reg.updateFlag(flagN, value&(1<<7) != 0)
|
||||||
s.registers.updateFlag(flagV, value&(1<<6) != 0)
|
s.Reg.updateFlag(flagV, value&(1<<6) != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildOpCompare(reg int) opFunc {
|
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)
|
value, _, _ := resolve(s, line, opcode)
|
||||||
reference := s.registers.getRegister(reg)
|
reference := s.Reg.getRegister(reg)
|
||||||
s.registers.updateFlagZN(reference - value)
|
s.Reg.updateFlagZN(reference - value)
|
||||||
s.registers.updateFlag(flagC, 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 operationXor(a uint8, b uint8) uint8 { return a ^ b }
|
||||||
|
|
||||||
func buildOpLogic(operation func(uint8, uint8) uint8) opFunc {
|
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)
|
value, _, _ := resolve(s, line, opcode)
|
||||||
result := operation(value, s.registers.getA())
|
result := operation(value, s.Reg.getA())
|
||||||
s.registers.setA(result)
|
s.Reg.setA(result)
|
||||||
s.registers.updateFlagZN(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)
|
value, _, _ := resolve(s, line, opcode)
|
||||||
aValue := s.registers.getA()
|
aValue := s.Reg.getA()
|
||||||
carry := s.registers.getFlagBit(flagC)
|
carry := s.Reg.getFlagBit(flagC)
|
||||||
|
|
||||||
total := uint16(aValue) + uint16(value) + uint16(carry)
|
total := uint16(aValue) + uint16(value) + uint16(carry)
|
||||||
signedTotal := int16(int8(aValue)) + int16(int8(value)) + int16(carry)
|
signedTotal := int16(int8(aValue)) + int16(int8(value)) + int16(carry)
|
||||||
truncated := uint8(total)
|
truncated := uint8(total)
|
||||||
|
|
||||||
if s.registers.getFlag(flagD) {
|
if s.Reg.getFlag(flagD) {
|
||||||
totalBcdLo := int(aValue&0x0f) + int(value&0x0f) + int(carry)
|
totalBcdLo := int(aValue&0x0f) + int(value&0x0f) + int(carry)
|
||||||
totalBcdHi := int(aValue>>4) + int(value>>4)
|
totalBcdHi := int(aValue>>4) + int(value>>4)
|
||||||
if totalBcdLo >= 10 {
|
if totalBcdLo >= 10 {
|
||||||
totalBcdHi++
|
totalBcdHi++
|
||||||
}
|
}
|
||||||
totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10)
|
totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10)
|
||||||
s.registers.setA(uint8(totalBcd))
|
s.Reg.setA(uint8(totalBcd))
|
||||||
s.registers.updateFlag(flagC, totalBcdHi > 9)
|
s.Reg.updateFlag(flagC, totalBcdHi > 9)
|
||||||
} else {
|
} else {
|
||||||
s.registers.setA(truncated)
|
s.Reg.setA(truncated)
|
||||||
s.registers.updateFlag(flagC, total > 0xFF)
|
s.Reg.updateFlag(flagC, total > 0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZNV flags behave for BCD as if the operation was binary?
|
// ZNV flags behave for BCD as if the operation was binary?
|
||||||
s.registers.updateFlagZN(truncated)
|
s.Reg.updateFlagZN(truncated)
|
||||||
s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127)
|
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)
|
value, _, _ := resolve(s, line, opcode)
|
||||||
aValue := s.registers.getA()
|
aValue := s.Reg.getA()
|
||||||
carry := s.registers.getFlagBit(flagC)
|
carry := s.Reg.getFlagBit(flagC)
|
||||||
|
|
||||||
total := 0x100 + uint16(aValue) - uint16(value) + uint16(carry) - 1
|
total := 0x100 + uint16(aValue) - uint16(value) + uint16(carry) - 1
|
||||||
signedTotal := int16(int8(aValue)) - int16(int8(value)) + int16(carry) - 1
|
signedTotal := int16(int8(aValue)) - int16(int8(value)) + int16(carry) - 1
|
||||||
truncated := uint8(total)
|
truncated := uint8(total)
|
||||||
|
|
||||||
if s.registers.getFlag(flagD) {
|
if s.Reg.getFlag(flagD) {
|
||||||
totalBcdLo := 10 + int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1
|
totalBcdLo := 10 + int(aValue&0x0f) - int(value&0x0f) + int(carry) - 1
|
||||||
totalBcdHi := 10 + int(aValue>>4) - int(value>>4)
|
totalBcdHi := 10 + int(aValue>>4) - int(value>>4)
|
||||||
if totalBcdLo < 10 {
|
if totalBcdLo < 10 {
|
||||||
totalBcdHi--
|
totalBcdHi--
|
||||||
}
|
}
|
||||||
totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10)
|
totalBcd := (totalBcdHi%10)<<4 + (totalBcdLo % 10)
|
||||||
s.registers.setA(uint8(totalBcd))
|
s.Reg.setA(uint8(totalBcd))
|
||||||
s.registers.updateFlag(flagC, totalBcdHi >= 10)
|
s.Reg.updateFlag(flagC, totalBcdHi >= 10)
|
||||||
} else {
|
} else {
|
||||||
s.registers.setA(truncated)
|
s.Reg.setA(truncated)
|
||||||
s.registers.updateFlag(flagC, total > 0xFF)
|
s.Reg.updateFlag(flagC, total > 0xFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZNV flags behave for SBC as if the operation was binary
|
// ZNV flags behave for SBC as if the operation was binary
|
||||||
s.registers.updateFlagZN(truncated)
|
s.Reg.updateFlagZN(truncated)
|
||||||
s.registers.updateFlag(flagV, signedTotal < -128 || signedTotal > 127)
|
s.Reg.updateFlag(flagV, signedTotal < -128 || signedTotal > 127)
|
||||||
}
|
}
|
||||||
|
|
||||||
const stackAddress uint16 = 0x0100
|
const stackAddress uint16 = 0x0100
|
||||||
|
|
||||||
func pushByte(s *state, value uint8) {
|
func pushByte(s *State, value uint8) {
|
||||||
adresss := stackAddress + uint16(s.registers.getSP())
|
adresss := stackAddress + uint16(s.Reg.getSP())
|
||||||
s.memory.poke(adresss, value)
|
s.Mem.Poke(adresss, value)
|
||||||
s.registers.setSP(s.registers.getSP() - 1)
|
s.Reg.setSP(s.Reg.getSP() - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pullByte(s *state) uint8 {
|
func pullByte(s *State) uint8 {
|
||||||
s.registers.setSP(s.registers.getSP() + 1)
|
s.Reg.setSP(s.Reg.getSP() + 1)
|
||||||
adresss := stackAddress + uint16(s.registers.getSP())
|
adresss := stackAddress + uint16(s.Reg.getSP())
|
||||||
return s.memory.peek(adresss)
|
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>>8))
|
||||||
pushByte(s, uint8(value))
|
pushByte(s, uint8(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func pullWord(s *state) uint16 {
|
func pullWord(s *State) uint16 {
|
||||||
return uint16(pullByte(s)) +
|
return uint16(pullByte(s)) +
|
||||||
(uint16(pullByte(s)) << 8)
|
(uint16(pullByte(s)) << 8)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPLA(s *state, line []uint8, opcode opcode) {
|
func opPLA(s *State, line []uint8, opcode opcode) {
|
||||||
value := pullByte(s)
|
value := pullByte(s)
|
||||||
s.registers.setA(value)
|
s.Reg.setA(value)
|
||||||
s.registers.updateFlagZN(value)
|
s.Reg.updateFlagZN(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPLP(s *state, line []uint8, opcode opcode) {
|
func opPLP(s *State, line []uint8, opcode opcode) {
|
||||||
value := pullByte(s)
|
value := pullByte(s)
|
||||||
s.registers.setP(value)
|
s.Reg.setP(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPHA(s *state, line []uint8, opcode opcode) {
|
func opPHA(s *State, line []uint8, opcode opcode) {
|
||||||
pushByte(s, s.registers.getA())
|
pushByte(s, s.Reg.getA())
|
||||||
}
|
}
|
||||||
|
|
||||||
func opPHP(s *state, line []uint8, opcode opcode) {
|
func opPHP(s *State, line []uint8, opcode opcode) {
|
||||||
pushByte(s, s.registers.getP()|(flagB+flag5))
|
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)
|
_, 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) {
|
func opJSR(s *State, line []uint8, opcode opcode) {
|
||||||
pushWord(s, s.registers.getPC()-1)
|
pushWord(s, s.Reg.getPC()-1)
|
||||||
_, address, _ := resolve(s, line, opcode)
|
_, address, _ := resolve(s, line, opcode)
|
||||||
s.registers.setPC(address)
|
s.Reg.setPC(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
func opRTI(s *state, line []uint8, opcode opcode) {
|
func opRTI(s *State, line []uint8, opcode opcode) {
|
||||||
s.registers.setP(pullByte(s))
|
s.Reg.setP(pullByte(s))
|
||||||
s.registers.setPC(pullWord(s))
|
s.Reg.setPC(pullWord(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func opRTS(s *state, line []uint8, opcode opcode) {
|
func opRTS(s *State, line []uint8, opcode opcode) {
|
||||||
s.registers.setPC(pullWord(s) + 1)
|
s.Reg.setPC(pullWord(s) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBRK(s *state, line []uint8, opcode opcode) {
|
func opBRK(s *State, line []uint8, opcode opcode) {
|
||||||
pushWord(s, s.registers.getPC()+1)
|
pushWord(s, s.Reg.getPC()+1)
|
||||||
pushByte(s, s.registers.getP()|(flagB+flag5))
|
pushByte(s, s.Reg.getP()|(flagB+flag5))
|
||||||
s.registers.setFlag(flagI)
|
s.Reg.setFlag(flagI)
|
||||||
s.registers.setPC(s.memory.getWord(0xFFFE))
|
s.Reg.setPC(s.Mem.getWord(0xFFFE))
|
||||||
}
|
}
|
||||||
|
|
||||||
var opcodes = [256]opcode{
|
var opcodes = [256]opcode{
|
||||||
@ -523,21 +520,22 @@ var opcodes = [256]opcode{
|
|||||||
0xEA: opcode{"NOP", 1, 2, modeImplicit, opNOP},
|
0xEA: opcode{"NOP", 1, 2, modeImplicit, opNOP},
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeLine(s *state, line []uint8) {
|
func executeLine(s *State, line []uint8) {
|
||||||
opcode := opcodes[line[0]]
|
opcode := opcodes[line[0]]
|
||||||
opcode.action(s, line, opcode)
|
opcode.action(s, line, opcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeInstruction(s *state, log bool) {
|
// ExecuteInstruction transforms the state given after a single instruction is executed.
|
||||||
pc := s.registers.getPC()
|
func ExecuteInstruction(s *State, log bool) {
|
||||||
opcode := opcodes[s.memory.peek(pc)]
|
pc := s.Reg.getPC()
|
||||||
|
opcode := opcodes[s.Mem.Peek(pc)]
|
||||||
|
|
||||||
line := make([]uint8, opcode.bytes)
|
line := make([]uint8, opcode.bytes)
|
||||||
for i := uint8(0); i < opcode.bytes; i++ {
|
for i := uint8(0); i < opcode.bytes; i++ {
|
||||||
line[i] = s.memory.peek(pc)
|
line[i] = s.Mem.Peek(pc)
|
||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
s.registers.setPC(pc)
|
s.Reg.setPC(pc)
|
||||||
|
|
||||||
if log {
|
if log {
|
||||||
fmt.Printf("%#04x %-12s: ", pc, lineString(s, line, opcode))
|
fmt.Printf("%#04x %-12s: ", pc, lineString(s, line, opcode))
|
||||||
@ -545,11 +543,18 @@ func executeInstruction(s *state, log bool) {
|
|||||||
opcode.action(s, line, opcode)
|
opcode.action(s, line, opcode)
|
||||||
if log {
|
if log {
|
||||||
value, address, _ := resolve(s, line, opcode)
|
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
|
t := opcode.name
|
||||||
switch opcode.addressMode {
|
switch opcode.addressMode {
|
||||||
case modeImplicit:
|
case modeImplicit:
|
||||||
|
@ -1,490 +1,490 @@
|
|||||||
package main
|
package core6502
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoad(t *testing.T) {
|
func TestLoad(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
s.memory.initWithRAM()
|
s.Mem.InitWithRAM()
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xA9, 0x42})
|
executeLine(&s, []uint8{0xA9, 0x42})
|
||||||
if s.registers.getA() != 0x42 {
|
if s.Reg.getA() != 0x42 {
|
||||||
t.Error("Error in LDA #")
|
t.Error("Error in LDA #")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xA9, 0x00})
|
executeLine(&s, []uint8{0xA9, 0x00})
|
||||||
if s.registers.getP() != flagZ {
|
if s.Reg.getP() != flagZ {
|
||||||
t.Error("Error in flags for LDA $0")
|
t.Error("Error in flags for LDA $0")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xA9, 0xF0})
|
executeLine(&s, []uint8{0xA9, 0xF0})
|
||||||
if s.registers.getP() != flagN {
|
if s.Reg.getP() != flagN {
|
||||||
t.Error("Error in flags for LDA $F0")
|
t.Error("Error in flags for LDA $F0")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xA0, 0xFE})
|
executeLine(&s, []uint8{0xA0, 0xFE})
|
||||||
if s.registers.getY() != 0xFE {
|
if s.Reg.getY() != 0xFE {
|
||||||
t.Error("Error in LDY #")
|
t.Error("Error in LDY #")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0x38, 0x87)
|
s.Mem.Poke(0x38, 0x87)
|
||||||
executeLine(&s, []uint8{0xA5, 0x38})
|
executeLine(&s, []uint8{0xA5, 0x38})
|
||||||
if s.registers.getA() != 0x87 {
|
if s.Reg.getA() != 0x87 {
|
||||||
t.Error("Error in LDA zpg")
|
t.Error("Error in LDA zpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0x57, 0x90)
|
s.Mem.Poke(0x57, 0x90)
|
||||||
s.registers.setX(0x10)
|
s.Reg.setX(0x10)
|
||||||
executeLine(&s, []uint8{0xB5, 0x47})
|
executeLine(&s, []uint8{0xB5, 0x47})
|
||||||
if s.registers.getA() != 0x90 {
|
if s.Reg.getA() != 0x90 {
|
||||||
t.Error("Error in LDA zpg, X")
|
t.Error("Error in LDA zpg, X")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0x38, 0x12)
|
s.Mem.Poke(0x38, 0x12)
|
||||||
s.registers.setX(0x89)
|
s.Reg.setX(0x89)
|
||||||
executeLine(&s, []uint8{0xB5, 0xAF})
|
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")
|
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})
|
executeLine(&s, []uint8{0xAD, 0x34, 0x12})
|
||||||
if s.registers.getA() != 0x67 {
|
if s.Reg.getA() != 0x67 {
|
||||||
t.Error("Error in LDA abs")
|
t.Error("Error in LDA abs")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0xC057, 0x7E)
|
s.Mem.Poke(0xC057, 0x7E)
|
||||||
s.registers.setX(0x57)
|
s.Reg.setX(0x57)
|
||||||
executeLine(&s, []uint8{0xBD, 0x00, 0xC0})
|
executeLine(&s, []uint8{0xBD, 0x00, 0xC0})
|
||||||
if s.registers.getA() != 0x7E {
|
if s.Reg.getA() != 0x7E {
|
||||||
t.Error("Error in LDA abs, X")
|
t.Error("Error in LDA abs, X")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0xD059, 0x7A)
|
s.Mem.Poke(0xD059, 0x7A)
|
||||||
s.registers.setY(0x59)
|
s.Reg.setY(0x59)
|
||||||
executeLine(&s, []uint8{0xB9, 0x00, 0xD0})
|
executeLine(&s, []uint8{0xB9, 0x00, 0xD0})
|
||||||
if s.registers.getA() != 0x7A {
|
if s.Reg.getA() != 0x7A {
|
||||||
t.Error("Error in LDA abs, Y")
|
t.Error("Error in LDA abs, Y")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0x24, 0x74)
|
s.Mem.Poke(0x24, 0x74)
|
||||||
s.memory.poke(0x25, 0x20)
|
s.Mem.Poke(0x25, 0x20)
|
||||||
s.registers.setX(0x04)
|
s.Reg.setX(0x04)
|
||||||
s.memory.poke(0x2074, 0x66)
|
s.Mem.Poke(0x2074, 0x66)
|
||||||
executeLine(&s, []uint8{0xA1, 0x20})
|
executeLine(&s, []uint8{0xA1, 0x20})
|
||||||
if s.registers.getA() != 0x66 {
|
if s.Reg.getA() != 0x66 {
|
||||||
t.Error("Error in LDA (oper,X)")
|
t.Error("Error in LDA (oper,X)")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.memory.poke(0x86, 0x28)
|
s.Mem.Poke(0x86, 0x28)
|
||||||
s.memory.poke(0x87, 0x40)
|
s.Mem.Poke(0x87, 0x40)
|
||||||
s.registers.setY(0x10)
|
s.Reg.setY(0x10)
|
||||||
s.memory.poke(0x4038, 0x99)
|
s.Mem.Poke(0x4038, 0x99)
|
||||||
executeLine(&s, []uint8{0xB1, 0x86})
|
executeLine(&s, []uint8{0xB1, 0x86})
|
||||||
if s.registers.getA() != 0x99 {
|
if s.Reg.getA() != 0x99 {
|
||||||
t.Error("Error in LDA (oper),Y")
|
t.Error("Error in LDA (oper),Y")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStore(t *testing.T) {
|
func TestStore(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
s.memory.initWithRAM()
|
s.Mem.InitWithRAM()
|
||||||
s.registers.setA(0x10)
|
s.Reg.setA(0x10)
|
||||||
s.registers.setX(0x40)
|
s.Reg.setX(0x40)
|
||||||
s.registers.setY(0x80)
|
s.Reg.setY(0x80)
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x85, 0x50})
|
executeLine(&s, []uint8{0x85, 0x50})
|
||||||
if s.memory.peek(0x0050) != 0x10 {
|
if s.Mem.Peek(0x0050) != 0x10 {
|
||||||
t.Error("Error in STA zpg")
|
t.Error("Error in STA zpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x86, 0x51})
|
executeLine(&s, []uint8{0x86, 0x51})
|
||||||
if s.memory.peek(0x0051) != 0x40 {
|
if s.Mem.Peek(0x0051) != 0x40 {
|
||||||
t.Error("Error in STX zpg")
|
t.Error("Error in STX zpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x84, 0x52})
|
executeLine(&s, []uint8{0x84, 0x52})
|
||||||
if s.memory.peek(0x0052) != 0x80 {
|
if s.Mem.Peek(0x0052) != 0x80 {
|
||||||
t.Error("Error in STY zpg")
|
t.Error("Error in STY zpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x8D, 0x20, 0xC0})
|
executeLine(&s, []uint8{0x8D, 0x20, 0xC0})
|
||||||
if s.memory.peek(0xC020) != 0x10 {
|
if s.Mem.Peek(0xC020) != 0x10 {
|
||||||
t.Error("Error in STA abs")
|
t.Error("Error in STA abs")
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x9D, 0x08, 0x10})
|
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")
|
t.Error("Error in STA abs, X")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransfer(t *testing.T) {
|
func TestTransfer(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setA(0xB0)
|
s.Reg.setA(0xB0)
|
||||||
executeLine(&s, []uint8{0xAA})
|
executeLine(&s, []uint8{0xAA})
|
||||||
if s.registers.getX() != 0xB0 {
|
if s.Reg.getX() != 0xB0 {
|
||||||
t.Error("Error in TAX")
|
t.Error("Error in TAX")
|
||||||
}
|
}
|
||||||
if s.registers.getP() != flagN {
|
if s.Reg.getP() != flagN {
|
||||||
t.Error("Error in TAX flags")
|
t.Error("Error in TAX flags")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xB1)
|
s.Reg.setA(0xB1)
|
||||||
executeLine(&s, []uint8{0xA8})
|
executeLine(&s, []uint8{0xA8})
|
||||||
if s.registers.getY() != 0xB1 {
|
if s.Reg.getY() != 0xB1 {
|
||||||
t.Error("Error in TAY")
|
t.Error("Error in TAY")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setSP(0xB2)
|
s.Reg.setSP(0xB2)
|
||||||
executeLine(&s, []uint8{0xBA})
|
executeLine(&s, []uint8{0xBA})
|
||||||
if s.registers.getX() != 0xB2 {
|
if s.Reg.getX() != 0xB2 {
|
||||||
t.Error("Error in TSX")
|
t.Error("Error in TSX")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setX(0xB3)
|
s.Reg.setX(0xB3)
|
||||||
executeLine(&s, []uint8{0x8A})
|
executeLine(&s, []uint8{0x8A})
|
||||||
if s.registers.getA() != 0xB3 {
|
if s.Reg.getA() != 0xB3 {
|
||||||
t.Error("Error in TXA")
|
t.Error("Error in TXA")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setX(0xB4)
|
s.Reg.setX(0xB4)
|
||||||
executeLine(&s, []uint8{0x9A})
|
executeLine(&s, []uint8{0x9A})
|
||||||
if s.registers.getSP() != 0xB4 {
|
if s.Reg.getSP() != 0xB4 {
|
||||||
t.Error("Error in TXS")
|
t.Error("Error in TXS")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setY(0xB5)
|
s.Reg.setY(0xB5)
|
||||||
executeLine(&s, []uint8{0x98})
|
executeLine(&s, []uint8{0x98})
|
||||||
if s.registers.getA() != 0xB5 {
|
if s.Reg.getA() != 0xB5 {
|
||||||
t.Error("Error in TYA")
|
t.Error("Error in TYA")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncDec(t *testing.T) {
|
func TestIncDec(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setX(0x7E)
|
s.Reg.setX(0x7E)
|
||||||
executeLine(&s, []uint8{0xE8})
|
executeLine(&s, []uint8{0xE8})
|
||||||
if s.registers.getX() != 0x7F {
|
if s.Reg.getX() != 0x7F {
|
||||||
t.Errorf("Error in INX")
|
t.Errorf("Error in INX")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setY(0xFC)
|
s.Reg.setY(0xFC)
|
||||||
executeLine(&s, []uint8{0x88})
|
executeLine(&s, []uint8{0x88})
|
||||||
if s.registers.getY() != 0xFB {
|
if s.Reg.getY() != 0xFB {
|
||||||
t.Error("Error in DEY")
|
t.Error("Error in DEY")
|
||||||
}
|
}
|
||||||
if s.registers.getP() != flagN {
|
if s.Reg.getP() != flagN {
|
||||||
t.Error("Error in DEY flags")
|
t.Error("Error in DEY flags")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShiftRotate(t *testing.T) {
|
func TestShiftRotate(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setA(0xF0)
|
s.Reg.setA(0xF0)
|
||||||
executeLine(&s, []uint8{0x2A})
|
executeLine(&s, []uint8{0x2A})
|
||||||
if s.registers.getA() != 0xE0 {
|
if s.Reg.getA() != 0xE0 {
|
||||||
t.Errorf("Error in ROL")
|
t.Errorf("Error in ROL")
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in ROL carry. %v", s.registers)
|
t.Errorf("Error in ROL carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setFlag(flagC)
|
s.Reg.setFlag(flagC)
|
||||||
s.registers.setA(0x0F)
|
s.Reg.setA(0x0F)
|
||||||
executeLine(&s, []uint8{0x6A})
|
executeLine(&s, []uint8{0x6A})
|
||||||
if s.registers.getA() != 0x87 {
|
if s.Reg.getA() != 0x87 {
|
||||||
t.Errorf("Error in ROR. %v", s.registers)
|
t.Errorf("Error in ROR. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in ROR carry")
|
t.Errorf("Error in ROR carry")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setFlag(flagC)
|
s.Reg.setFlag(flagC)
|
||||||
s.registers.setA(0x81)
|
s.Reg.setA(0x81)
|
||||||
executeLine(&s, []uint8{0x0A})
|
executeLine(&s, []uint8{0x0A})
|
||||||
if s.registers.getA() != 0x02 {
|
if s.Reg.getA() != 0x02 {
|
||||||
t.Errorf("Error in ASL. %v", s.registers)
|
t.Errorf("Error in ASL. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in ASL carry")
|
t.Errorf("Error in ASL carry")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setFlag(flagC)
|
s.Reg.setFlag(flagC)
|
||||||
s.registers.setA(0x02)
|
s.Reg.setA(0x02)
|
||||||
executeLine(&s, []uint8{0x4A})
|
executeLine(&s, []uint8{0x4A})
|
||||||
if s.registers.getA() != 0x01 {
|
if s.Reg.getA() != 0x01 {
|
||||||
t.Errorf("Error in LSR. %v", s.registers)
|
t.Errorf("Error in LSR. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getFlag(flagC) {
|
if s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in LSR carry")
|
t.Errorf("Error in LSR carry")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClearSetFlag(t *testing.T) {
|
func TestClearSetFlag(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
s.registers.setP(0x00)
|
s.Reg.setP(0x00)
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xF8})
|
executeLine(&s, []uint8{0xF8})
|
||||||
if !s.registers.getFlag(flagD) {
|
if !s.Reg.getFlag(flagD) {
|
||||||
t.Errorf("Error in SED. %v", s.registers)
|
t.Errorf("Error in SED. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xD8})
|
executeLine(&s, []uint8{0xD8})
|
||||||
if s.registers.getFlag(flagD) {
|
if s.Reg.getFlag(flagD) {
|
||||||
t.Errorf("Error in CLD. %v", s.registers)
|
t.Errorf("Error in CLD. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogic(t *testing.T) {
|
func TestLogic(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setA(0xF0)
|
s.Reg.setA(0xF0)
|
||||||
executeLine(&s, []uint8{0x29, 0x1C})
|
executeLine(&s, []uint8{0x29, 0x1C})
|
||||||
if s.registers.getA() != 0x10 {
|
if s.Reg.getA() != 0x10 {
|
||||||
t.Errorf("Error in AND <. %v", s.registers)
|
t.Errorf("Error in AND <. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xF0)
|
s.Reg.setA(0xF0)
|
||||||
executeLine(&s, []uint8{0x49, 0x1C})
|
executeLine(&s, []uint8{0x49, 0x1C})
|
||||||
if s.registers.getA() != 0xEC {
|
if s.Reg.getA() != 0xEC {
|
||||||
t.Errorf("Error in EOR <. %v", s.registers)
|
t.Errorf("Error in EOR <. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xF0)
|
s.Reg.setA(0xF0)
|
||||||
executeLine(&s, []uint8{0x09, 0x0C})
|
executeLine(&s, []uint8{0x09, 0x0C})
|
||||||
if s.registers.getA() != 0xFC {
|
if s.Reg.getA() != 0xFC {
|
||||||
t.Errorf("Error in ORA <. %v", s.registers)
|
t.Errorf("Error in ORA <. %v", s.Reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
func TestAdd(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setA(0xA0)
|
s.Reg.setA(0xA0)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x69, 0x0B})
|
executeLine(&s, []uint8{0x69, 0x0B})
|
||||||
if s.registers.getA() != 0xAB {
|
if s.Reg.getA() != 0xAB {
|
||||||
t.Errorf("Error in ADC. %v", s.registers)
|
t.Errorf("Error in ADC. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getFlag(flagC) {
|
if s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry ADC. %v", s.registers)
|
t.Errorf("Error in carry ADC. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xFF)
|
s.Reg.setA(0xFF)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x69, 0x02})
|
executeLine(&s, []uint8{0x69, 0x02})
|
||||||
if s.registers.getA() != 0x01 {
|
if s.Reg.getA() != 0x01 {
|
||||||
t.Errorf("Error in ADC with carry. %v", s.registers)
|
t.Errorf("Error in ADC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry ADC with carry. %v", s.registers)
|
t.Errorf("Error in carry ADC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xA0)
|
s.Reg.setA(0xA0)
|
||||||
s.registers.setFlag(flagC)
|
s.Reg.setFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x69, 0x01})
|
executeLine(&s, []uint8{0x69, 0x01})
|
||||||
if s.registers.getA() != 0xA2 {
|
if s.Reg.getA() != 0xA2 {
|
||||||
t.Errorf("Error in carried ADC with carry. %v", s.registers)
|
t.Errorf("Error in carried ADC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getFlag(flagC) {
|
if s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry in carried ADC with carry. %v", s.registers)
|
t.Errorf("Error in carry in carried ADC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddDecimal(t *testing.T) {
|
func TestAddDecimal(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
s.registers.setFlag(flagD)
|
s.Reg.setFlag(flagD)
|
||||||
|
|
||||||
s.registers.setA(0x12)
|
s.Reg.setA(0x12)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x69, 0x013})
|
executeLine(&s, []uint8{0x69, 0x013})
|
||||||
if s.registers.getA() != 0x25 {
|
if s.Reg.getA() != 0x25 {
|
||||||
t.Errorf("Error in ADC decimal. %v", s.registers)
|
t.Errorf("Error in ADC decimal. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getFlag(flagC) {
|
if s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry ADC. %v", s.registers)
|
t.Errorf("Error in carry ADC. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0x44)
|
s.Reg.setA(0x44)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x69, 0x68})
|
executeLine(&s, []uint8{0x69, 0x68})
|
||||||
if s.registers.getA() != 0x12 {
|
if s.Reg.getA() != 0x12 {
|
||||||
t.Errorf("Error in ADC decimal with carry. %v", s.registers)
|
t.Errorf("Error in ADC decimal with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry ADC decimal with carry. %v", s.registers)
|
t.Errorf("Error in carry ADC decimal with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0x44)
|
s.Reg.setA(0x44)
|
||||||
s.registers.setFlag(flagC)
|
s.Reg.setFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x69, 0x23})
|
executeLine(&s, []uint8{0x69, 0x23})
|
||||||
if s.registers.getA() != 0x68 {
|
if s.Reg.getA() != 0x68 {
|
||||||
t.Errorf("Error in carried ADC decimal with carry. %v", s.registers)
|
t.Errorf("Error in carried ADC decimal with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getFlag(flagC) {
|
if s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry in carried ADC decimal with carry. %v", s.registers)
|
t.Errorf("Error in carry in carried ADC decimal with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSub(t *testing.T) {
|
func TestSub(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setA(0x09)
|
s.Reg.setA(0x09)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0xE9, 0x05})
|
executeLine(&s, []uint8{0xE9, 0x05})
|
||||||
if s.registers.getA() != 0x03 {
|
if s.Reg.getA() != 0x03 {
|
||||||
t.Errorf("Error in SBC. %v", s.registers)
|
t.Errorf("Error in SBC. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry SBC. %v", s.registers)
|
t.Errorf("Error in carry SBC. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0x01)
|
s.Reg.setA(0x01)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0xE9, 0x02})
|
executeLine(&s, []uint8{0xE9, 0x02})
|
||||||
if s.registers.getA() != 0xFE {
|
if s.Reg.getA() != 0xFE {
|
||||||
t.Errorf("Error in SBC with carry. %v", s.registers)
|
t.Errorf("Error in SBC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getFlag(flagC) {
|
if s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry SBC with carry. %v", s.registers)
|
t.Errorf("Error in carry SBC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0x08)
|
s.Reg.setA(0x08)
|
||||||
s.registers.setFlag(flagC)
|
s.Reg.setFlag(flagC)
|
||||||
executeLine(&s, []uint8{0xE9, 0x02})
|
executeLine(&s, []uint8{0xE9, 0x02})
|
||||||
if s.registers.getA() != 0x06 {
|
if s.Reg.getA() != 0x06 {
|
||||||
t.Errorf("Error in carried SBC with carry. %v", s.registers)
|
t.Errorf("Error in carried SBC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
if !s.registers.getFlag(flagC) {
|
if !s.Reg.getFlag(flagC) {
|
||||||
t.Errorf("Error in carry in carried SBC with carry. %v", s.registers)
|
t.Errorf("Error in carry in carried SBC with carry. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompare(t *testing.T) {
|
func TestCompare(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setA(0x02)
|
s.Reg.setA(0x02)
|
||||||
executeLine(&s, []uint8{0xC9, 0x01})
|
executeLine(&s, []uint8{0xC9, 0x01})
|
||||||
if s.registers.getP() != 0x01 {
|
if s.Reg.getP() != 0x01 {
|
||||||
t.Errorf("Error in CMP <. %v", s.registers)
|
t.Errorf("Error in CMP <. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xC9, 0x02})
|
executeLine(&s, []uint8{0xC9, 0x02})
|
||||||
if s.registers.getP() != 0x03 {
|
if s.Reg.getP() != 0x03 {
|
||||||
t.Errorf("Error in CMP =. %v", s.registers)
|
t.Errorf("Error in CMP =. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0xC9, 0x03})
|
executeLine(&s, []uint8{0xC9, 0x03})
|
||||||
if s.registers.getP() != 0x80 {
|
if s.Reg.getP() != 0x80 {
|
||||||
t.Errorf("Error in CMP >. %v", s.registers)
|
t.Errorf("Error in CMP >. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setX(0x04)
|
s.Reg.setX(0x04)
|
||||||
executeLine(&s, []uint8{0xE0, 0x05})
|
executeLine(&s, []uint8{0xE0, 0x05})
|
||||||
if s.registers.getP() != 0x80 {
|
if s.Reg.getP() != 0x80 {
|
||||||
t.Errorf("Error in CPX >. %v", s.registers)
|
t.Errorf("Error in CPX >. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setY(0x08)
|
s.Reg.setY(0x08)
|
||||||
executeLine(&s, []uint8{0xC0, 0x09})
|
executeLine(&s, []uint8{0xC0, 0x09})
|
||||||
if s.registers.getP() != 0x80 {
|
if s.Reg.getP() != 0x80 {
|
||||||
t.Errorf("Error in CPY >. %v", s.registers)
|
t.Errorf("Error in CPY >. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
func TestBit(t *testing.T) {
|
func TestBit(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
s.memory.initWithRAM()
|
s.Mem.InitWithRAM()
|
||||||
|
|
||||||
s.registers.setA(0x0F)
|
s.Reg.setA(0x0F)
|
||||||
s.memory.poke(0x0040, 0xF0)
|
s.Mem.Poke(0x0040, 0xF0)
|
||||||
executeLine(&s, []uint8{0x24, 0x40})
|
executeLine(&s, []uint8{0x24, 0x40})
|
||||||
if s.registers.getP() != 0xC2 {
|
if s.Reg.getP() != 0xC2 {
|
||||||
t.Errorf("Error in BIT. %v", s.registers)
|
t.Errorf("Error in BIT. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xF0)
|
s.Reg.setA(0xF0)
|
||||||
s.memory.poke(0x0040, 0xF0)
|
s.Mem.Poke(0x0040, 0xF0)
|
||||||
executeLine(&s, []uint8{0x24, 0x40})
|
executeLine(&s, []uint8{0x24, 0x40})
|
||||||
if s.registers.getP() != 0xC0 {
|
if s.Reg.getP() != 0xC0 {
|
||||||
t.Errorf("Error in BIT, 2. %v", s.registers)
|
t.Errorf("Error in BIT, 2. %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setA(0xF0)
|
s.Reg.setA(0xF0)
|
||||||
s.memory.poke(0x01240, 0x80)
|
s.Mem.Poke(0x01240, 0x80)
|
||||||
executeLine(&s, []uint8{0x2C, 0x40, 0x12})
|
executeLine(&s, []uint8{0x2C, 0x40, 0x12})
|
||||||
if s.registers.getP() != 0x80 {
|
if s.Reg.getP() != 0x80 {
|
||||||
t.Errorf("Error in BIT, 2. %v", s.registers)
|
t.Errorf("Error in BIT, 2. %v", s.Reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBranch(t *testing.T) {
|
func TestBranch(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
|
|
||||||
s.registers.setPC(0xC600)
|
s.Reg.setPC(0xC600)
|
||||||
s.registers.setFlag(flagV)
|
s.Reg.setFlag(flagV)
|
||||||
executeLine(&s, []uint8{0x50, 0x20})
|
executeLine(&s, []uint8{0x50, 0x20})
|
||||||
if s.registers.getPC() != 0xC600 {
|
if s.Reg.getPC() != 0xC600 {
|
||||||
t.Errorf("Error in BVC, %v", s.registers)
|
t.Errorf("Error in BVC, %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x70, 0x20})
|
executeLine(&s, []uint8{0x70, 0x20})
|
||||||
if s.registers.getPC() != 0xC620 {
|
if s.Reg.getPC() != 0xC620 {
|
||||||
t.Errorf("Error in BVS, %v", s.registers)
|
t.Errorf("Error in BVS, %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.registers.setPC(0xD600)
|
s.Reg.setPC(0xD600)
|
||||||
s.registers.clearFlag(flagC)
|
s.Reg.clearFlag(flagC)
|
||||||
executeLine(&s, []uint8{0x90, 0xA0})
|
executeLine(&s, []uint8{0x90, 0xA0})
|
||||||
if s.registers.getPC() != 0xD5A0 {
|
if s.Reg.getPC() != 0xD5A0 {
|
||||||
t.Errorf("Error in BCC, %v", s.registers)
|
t.Errorf("Error in BCC, %v", s.Reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStack(t *testing.T) {
|
func TestStack(t *testing.T) {
|
||||||
var s state
|
var s State
|
||||||
s.memory.initWithRAM()
|
s.Mem.InitWithRAM()
|
||||||
|
|
||||||
s.registers.setSP(0xF0)
|
s.Reg.setSP(0xF0)
|
||||||
s.registers.setA(0xA0)
|
s.Reg.setA(0xA0)
|
||||||
s.registers.setP(0x0A)
|
s.Reg.setP(0x0A)
|
||||||
executeLine(&s, []uint8{0x48})
|
executeLine(&s, []uint8{0x48})
|
||||||
if s.registers.getSP() != 0xEF {
|
if s.Reg.getSP() != 0xEF {
|
||||||
t.Errorf("Error in PHA stack pointer, %v", s.registers)
|
t.Errorf("Error in PHA stack pointer, %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.memory.peek(0x01F0) != 0xA0 {
|
if s.Mem.Peek(0x01F0) != 0xA0 {
|
||||||
t.Errorf("Error in PHA, %v", s.registers)
|
t.Errorf("Error in PHA, %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x08})
|
executeLine(&s, []uint8{0x08})
|
||||||
if s.registers.getSP() != 0xEE {
|
if s.Reg.getSP() != 0xEE {
|
||||||
t.Errorf("Error in PHP stack pointer, %v", s.registers)
|
t.Errorf("Error in PHP stack pointer, %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.memory.peek(0x01EF) != 0x3A {
|
if s.Mem.Peek(0x01EF) != 0x3A {
|
||||||
t.Errorf("Error in PHP, %v", s.registers)
|
t.Errorf("Error in PHP, %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x68})
|
executeLine(&s, []uint8{0x68})
|
||||||
if s.registers.getSP() != 0xEF {
|
if s.Reg.getSP() != 0xEF {
|
||||||
t.Errorf("Error in PLA stack pointer, %v", s.registers)
|
t.Errorf("Error in PLA stack pointer, %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getA() != 0x3A {
|
if s.Reg.getA() != 0x3A {
|
||||||
t.Errorf("Error in PLA, %v", s.registers)
|
t.Errorf("Error in PLA, %v", s.Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
executeLine(&s, []uint8{0x28})
|
executeLine(&s, []uint8{0x28})
|
||||||
if s.registers.getSP() != 0xF0 {
|
if s.Reg.getSP() != 0xF0 {
|
||||||
t.Errorf("Error in PLP stack pointer, %v", s.registers)
|
t.Errorf("Error in PLP stack pointer, %v", s.Reg)
|
||||||
}
|
}
|
||||||
if s.registers.getP() != 0xA0 {
|
if s.Reg.getP() != 0xA0 {
|
||||||
t.Errorf("Error in PLP, %v", s.registers)
|
t.Errorf("Error in PLP, %v", s.Reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package core6502
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -6,86 +6,46 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type memoryPage interface {
|
// MemoryPage is a data page of 256 bytes
|
||||||
peek(uint8) uint8
|
type MemoryPage interface {
|
||||||
poke(uint8, uint8)
|
Peek(uint8) uint8
|
||||||
getData() *[256]uint8
|
Poke(uint8, uint8)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ramPage struct {
|
// Memory represents the addressable space of the processor
|
||||||
data [256]uint8
|
type Memory struct {
|
||||||
|
data [256]MemoryPage
|
||||||
}
|
}
|
||||||
|
|
||||||
type romPage struct {
|
// Peek returns the data on the given address
|
||||||
data [256]uint8
|
func (m *Memory) Peek(address uint16) 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 {
|
|
||||||
hi := uint8(address >> 8)
|
hi := uint8(address >> 8)
|
||||||
lo := uint8(address)
|
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)
|
hi := uint8(address >> 8)
|
||||||
lo := uint8(address)
|
lo := uint8(address)
|
||||||
//fmt.Println(hi)
|
//fmt.Println(hi)
|
||||||
m.data[hi].poke(lo, value)
|
m.data[hi].Poke(lo, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memory) getWord(address uint16) uint16 {
|
// SetPage assigns a MemoryPage implementation on the page given
|
||||||
return uint16(m.peek(address)) + 0x100*uint16(m.peek(address+1))
|
func (m *Memory) SetPage(index uint8, page MemoryPage) {
|
||||||
|
m.data[index] = page
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memory) getZeroPageWord(address uint8) uint16 {
|
func (m *Memory) getWord(address uint16) uint16 {
|
||||||
return uint16(m.peek(uint16(address))) + 0x100*uint16(m.peek(uint16(address+1)))
|
return uint16(m.Peek(address)) + 0x100*uint16(m.Peek(address+1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memory) initWithRAM() {
|
func (m *Memory) getZeroPageWord(address uint8) uint16 {
|
||||||
var ramPages [256]ramPage
|
return uint16(m.Peek(uint16(address))) + 0x100*uint16(m.Peek(uint16(address+1)))
|
||||||
for i := 0; i < 256; i++ {
|
|
||||||
m.data[i] = &ramPages[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memory) transformToRom(page uint8) {
|
func (m *Memory) loadBinary(filename string) {
|
||||||
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
|
|
||||||
// Load file
|
// Load file
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -104,48 +64,13 @@ func (m *memory) initWithRomAndText(filename string, textPages *textPages) {
|
|||||||
buf := bufio.NewReader(f)
|
buf := bufio.NewReader(f)
|
||||||
buf.Read(bytes)
|
buf.Read(bytes)
|
||||||
|
|
||||||
m.initWithRAM()
|
m.InitWithRAM()
|
||||||
romStart := uint16(0xFFFF - size + 1)
|
|
||||||
for i, v := range bytes {
|
for i, v := range bytes {
|
||||||
m.poke(uint16(i)+romStart, uint8(v))
|
m.Poke(uint16(i), 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])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memory) loadBinary(filename string) {
|
func (m *Memory) printPage(page uint8) {
|
||||||
// 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) {
|
|
||||||
address := uint16(page) * 0x100
|
address := uint16(page) * 0x100
|
||||||
for i := 0; i < 16; i++ {
|
for i := 0; i < 16; i++ {
|
||||||
fmt.Printf("%#04x: ", address)
|
fmt.Printf("%#04x: ", address)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package core6502
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
@ -23,56 +23,56 @@ const (
|
|||||||
flagC uint8 = 1 << 0
|
flagC uint8 = 1 << 0
|
||||||
)
|
)
|
||||||
|
|
||||||
type registers struct {
|
type Registers struct {
|
||||||
data [8]uint8
|
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) getA() uint8 { return r.data[regA] }
|
||||||
func (r *registers) getX() uint8 { return r.data[regX] }
|
func (r *Registers) getX() uint8 { return r.data[regX] }
|
||||||
func (r *registers) getY() uint8 { return r.data[regY] }
|
func (r *Registers) getY() uint8 { return r.data[regY] }
|
||||||
func (r *registers) getP() uint8 { return r.data[regP] }
|
func (r *Registers) getP() uint8 { return r.data[regP] }
|
||||||
func (r *registers) getSP() uint8 { return r.data[regSP] }
|
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
|
r.data[i] = v
|
||||||
}
|
}
|
||||||
func (r *registers) setA(v uint8) { r.setRegister(regA, v) }
|
func (r *Registers) setA(v uint8) { r.setRegister(regA, v) }
|
||||||
func (r *registers) setX(v uint8) { r.setRegister(regX, v) }
|
func (r *Registers) setX(v uint8) { r.setRegister(regX, v) }
|
||||||
func (r *registers) setY(v uint8) { r.setRegister(regY, v) }
|
func (r *Registers) setY(v uint8) { r.setRegister(regY, v) }
|
||||||
func (r *registers) setP(v uint8) { r.setRegister(regP, v) }
|
func (r *Registers) setP(v uint8) { r.setRegister(regP, v) }
|
||||||
func (r *registers) setSP(v uint8) { r.setRegister(regSP, 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])
|
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] = uint8(v >> 8)
|
||||||
r.data[regPC+1] = uint8(v)
|
r.data[regPC+1] = uint8(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registers) getFlagBit(i uint8) uint8 {
|
func (r *Registers) getFlagBit(i uint8) uint8 {
|
||||||
if r.getFlag(i) {
|
if r.getFlag(i) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registers) getFlag(i uint8) bool {
|
func (r *Registers) getFlag(i uint8) bool {
|
||||||
return (r.data[regP] & i) != 0
|
return (r.data[regP] & i) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registers) setFlag(i uint8) {
|
func (r *Registers) setFlag(i uint8) {
|
||||||
r.data[regP] |= i
|
r.data[regP] |= i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registers) clearFlag(i uint8) {
|
func (r *Registers) clearFlag(i uint8) {
|
||||||
r.data[regP] &^= i
|
r.data[regP] &^= i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *registers) updateFlag(i uint8, v bool) {
|
func (r *Registers) updateFlag(i uint8, v bool) {
|
||||||
if v {
|
if v {
|
||||||
r.setFlag(i)
|
r.setFlag(i)
|
||||||
} else {
|
} 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(flagZ, t == 0)
|
||||||
r.updateFlag(flagN, t >= (1<<7))
|
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",
|
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())
|
r.getA(), r.getX(), r.getY(), r.getSP(), r.getPC(), r.getP(), r.getP())
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package main
|
package core6502
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestRegA(t *testing.T) {
|
func TestRegA(t *testing.T) {
|
||||||
var r registers
|
var r Registers
|
||||||
var data uint8
|
var data uint8
|
||||||
data = 200
|
data = 200
|
||||||
r.setA(data)
|
r.setA(data)
|
||||||
@ -12,7 +12,7 @@ func TestRegA(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestRegPC(t *testing.T) {
|
func TestRegPC(t *testing.T) {
|
||||||
var r registers
|
var r Registers
|
||||||
var data uint16
|
var data uint16
|
||||||
data = 0xc600
|
data = 0xc600
|
||||||
r.setPC(data)
|
r.setPC(data)
|
||||||
@ -22,7 +22,7 @@ func TestRegPC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFlags(t *testing.T) {
|
func TestFlags(t *testing.T) {
|
||||||
var r registers
|
var r Registers
|
||||||
r.setP(0x23)
|
r.setP(0x23)
|
||||||
if r.getP() != 0x23 {
|
if r.getP() != 0x23 {
|
||||||
t.Error("Error storing and loading P")
|
t.Error("Error storing and loading P")
|
||||||
@ -51,7 +51,7 @@ func TestFlags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateFlagZN(t *testing.T) {
|
func TestUpdateFlagZN(t *testing.T) {
|
||||||
var r registers
|
var r Registers
|
||||||
r.updateFlagZN(0)
|
r.updateFlagZN(0)
|
||||||
if r.getP() != flagZ {
|
if r.getP() != flagZ {
|
||||||
t.Error("Error update flags ZN with 0")
|
t.Error("Error update flags ZN with 0")
|
||||||
@ -66,4 +66,4 @@ func TestUpdateFlagZN(t *testing.T) {
|
|||||||
if r.getP() != flagN {
|
if r.getP() != flagN {
|
||||||
t.Error("Error update flags ZN with 0xF2")
|
t.Error("Error update flags ZN with 0xF2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
81
core6502/rxmPage.go
Normal file
81
core6502/rxmPage.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
34
main.go
34
main.go
@ -1,34 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "go6502/apple2"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var s state
|
romFile := "../roms/apple.rom"
|
||||||
var t textPages
|
//romFile := "../roms/APPLE2.ROM"
|
||||||
var io ioC0Page
|
|
||||||
|
|
||||||
/*
|
log := false
|
||||||
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
|
|
||||||
|
|
||||||
startAddress := s.memory.getWord(0xfffc)
|
apple2.Run(romFile, log)
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user