First generalization of LD?
This commit is contained in:
parent
3c77553dcd
commit
925f76394f
90
execute.go
90
execute.go
|
@ -1,40 +1,90 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
type state struct {
|
type state struct {
|
||||||
register r,
|
registers registers
|
||||||
memory m
|
memory memory
|
||||||
}
|
}
|
||||||
|
|
||||||
func step(state *S) {
|
func step(s *state) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const modeNone = -1
|
const modeNone = -1
|
||||||
const modeImmediate = 0
|
const modeImmediate = 0
|
||||||
const modeZeroPage = 1
|
const modeZeroPage = 1
|
||||||
const modeAbsolute = 2
|
const modeZeroPageX = 3
|
||||||
|
const modeAbsolute = 2
|
||||||
type opcode struct {
|
|
||||||
name string
|
|
||||||
code int8
|
|
||||||
bytes int
|
|
||||||
cycles int
|
|
||||||
mode int
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.masswerk.at/6502/6502_instruction_set.html
|
// https://www.masswerk.at/6502/6502_instruction_set.html
|
||||||
|
|
||||||
func opA1LDA(state *, opcode) {
|
func opLDAimm(s *state, line []uint8) {
|
||||||
value := s->memory
|
opLDR(s, line, regA, modeImmediate)
|
||||||
s->register.setRegister(regA, value)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func opLDA(state *s, reg, mode, arg) {
|
func opLDAzpg(s *state, line []uint8) {
|
||||||
|
opLDR(s, line, regA, modeZeroPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
opcodes := []Opcode{
|
func opLDYimm(s *state, line []uint8) {
|
||||||
0: opcode('BRK', 0x0, 1, 7, modeImmediate)
|
opLDR(s, line, regY, modeImmediate)
|
||||||
1:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opLDAzpgX(s *state, line []uint8) {
|
||||||
|
opLDR(s, line, regA, modeZeroPageX)
|
||||||
|
}
|
||||||
|
|
||||||
|
func opLDAabs(s *state, line []uint8) {
|
||||||
|
opLDR(s, line, regA, modeAbsolute)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWordInLine(line []uint8) uint16 {
|
||||||
|
return uint16(line[1]) + 0x100*uint16(line[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
func opLDR(s *state, line []uint8, reg int, mode int) {
|
||||||
|
var value uint8
|
||||||
|
switch mode {
|
||||||
|
case modeImmediate:
|
||||||
|
value = line[1]
|
||||||
|
case modeZeroPage:
|
||||||
|
address := line[1]
|
||||||
|
value = s.memory[address]
|
||||||
|
case modeZeroPageX:
|
||||||
|
address := line[1] + s.registers.getRegister(regX)
|
||||||
|
value = s.memory[address]
|
||||||
|
case modeAbsolute:
|
||||||
|
address := getWordInLine(line)
|
||||||
|
value = s.memory[address]
|
||||||
|
}
|
||||||
|
|
||||||
|
s.registers.setRegister(reg, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
type opFunc func(s *state, line []uint8, opcode opcode)
|
||||||
|
type opcode struct {
|
||||||
|
name string
|
||||||
|
bytes int
|
||||||
|
cycles int
|
||||||
|
mode int
|
||||||
|
reg int
|
||||||
|
action opFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func opNOP(s *state, line []uint8, opcode opcode) {}
|
||||||
|
func opLDRex(s *state, line []uint8, opcode opcode) {
|
||||||
|
opLDR(s, line, opcode.reg, opcode.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var opcodes = [256]opcode{
|
||||||
|
0x00: opcode{"BRK", 1, 7, modeImmediate, regNone, opNOP},
|
||||||
|
0xA0: opcode{"LDY", -1, -1, modeImmediate, regY, opLDRex},
|
||||||
|
0xA5: opcode{"LDA", 2, 3, modeZeroPage, regA, opLDRex},
|
||||||
|
0xB5: opcode{"LDA", 2, 4, modeZeroPageX, regA, opLDRex},
|
||||||
|
0xA9: opcode{"LDA", 2, 2, modeImmediate, regA, opLDRex},
|
||||||
|
0xAD: opcode{"LDA", 3, 4, modeAbsolute, regA, opLDRex},
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeLine(s *state, line []uint8) {
|
||||||
|
opcode := opcodes[line[0]]
|
||||||
|
opcode.action(s, line, opcode)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLDA(t *testing.T) {
|
||||||
|
var s state
|
||||||
|
|
||||||
|
opLDAimm(&s, []uint8{0xA9, 0x42})
|
||||||
|
if s.registers.getA() != 0x42 {
|
||||||
|
t.Error("Error in LDA #")
|
||||||
|
}
|
||||||
|
|
||||||
|
opLDYimm(&s, []uint8{0xA0, 0xFE})
|
||||||
|
if s.registers.getY() != 0xFE {
|
||||||
|
t.Error("Error in LDY #")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x38] = 0x87
|
||||||
|
opLDAzpg(&s, []uint8{0xA5, 0x38})
|
||||||
|
if s.registers.getA() != 0x87 {
|
||||||
|
t.Error("Error in LDA zpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x57] = 0x90
|
||||||
|
s.registers.setX(0x10)
|
||||||
|
opLDAzpgX(&s, []uint8{0xB5, 0x47})
|
||||||
|
if s.registers.getA() != 0x90 {
|
||||||
|
t.Error("Error in LDA zpgX")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x38] = 0x12
|
||||||
|
s.registers.setX(0x89)
|
||||||
|
opLDAzpgX(&s, []uint8{0xB5, 0xAF})
|
||||||
|
if s.registers.getA() != 0x12 {
|
||||||
|
t.Error("Error in LDA zpgX with sero page overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x1234] = 0x67
|
||||||
|
opLDAabs(&s, []uint8{0xAD, 0x34, 0x12})
|
||||||
|
if s.registers.getA() != 0x67 {
|
||||||
|
t.Error("Error in LDA abs")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLDA2(t *testing.T) {
|
||||||
|
var s state
|
||||||
|
|
||||||
|
executeLine(&s, []uint8{0xA9, 0x42})
|
||||||
|
if s.registers.getA() != 0x42 {
|
||||||
|
t.Error("Error in LDA #")
|
||||||
|
}
|
||||||
|
|
||||||
|
executeLine(&s, []uint8{0xA0, 0xFE})
|
||||||
|
if s.registers.getY() != 0xFE {
|
||||||
|
t.Error("Error in LDY #")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x38] = 0x87
|
||||||
|
executeLine(&s, []uint8{0xA5, 0x38})
|
||||||
|
if s.registers.getA() != 0x87 {
|
||||||
|
t.Error("Error in LDA zpg")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x57] = 0x90
|
||||||
|
s.registers.setX(0x10)
|
||||||
|
executeLine(&s, []uint8{0xB5, 0x47})
|
||||||
|
if s.registers.getA() != 0x90 {
|
||||||
|
t.Error("Error in LDA zpgX")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x38] = 0x12
|
||||||
|
s.registers.setX(0x89)
|
||||||
|
executeLine(&s, []uint8{0xB5, 0xAF})
|
||||||
|
if s.registers.getA() != 0x12 {
|
||||||
|
t.Error("Error in LDA zpgX with sero page overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.memory[0x1234] = 0x67
|
||||||
|
executeLine(&s, []uint8{0xAD, 0x34, 0x12})
|
||||||
|
if s.registers.getA() != 0x67 {
|
||||||
|
t.Error("Error in LDA abs")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
type memory [65536]uint8
|
type memory [65536]uint8
|
||||||
|
|
||||||
|
|
44
registers.go
44
registers.go
|
@ -1,41 +1,41 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
const (
|
const (
|
||||||
regA = 0
|
regA = 0
|
||||||
regX = 1
|
regX = 1
|
||||||
regY = 2
|
regY = 2
|
||||||
// empty
|
regP = 4
|
||||||
regP = 4
|
regS = 5
|
||||||
regS = 5
|
regPC = 6 // 2 bytes
|
||||||
regPC = 6 // 2 bytes
|
regNone = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
type registers struct {
|
type registers struct {
|
||||||
data [8]uint8
|
data [8]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r registers) getA() uint8 { return r.data[regA] }
|
func (r *registers) getRegister(i int) uint8 { return r.data[i] }
|
||||||
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) getS() uint8 { return r.data[regS] }
|
|
||||||
|
|
||||||
func (r registers) setRegister(i int, v uint8) registers {
|
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) getS() uint8 { return r.data[regS] }
|
||||||
|
|
||||||
|
func (r *registers) setRegister(i int, v uint8) {
|
||||||
r.data[i] = v
|
r.data[i] = v
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
func (r registers) setA(v uint8) registers { return r.setRegister(regA, v) }
|
func (r *registers) setA(v uint8) { r.setRegister(regA, v) }
|
||||||
func (r registers) setX(v uint8) registers { return r.setRegister(regX, v) }
|
func (r *registers) setX(v uint8) { r.setRegister(regX, v) }
|
||||||
func (r registers) setY(v uint8) registers { return r.setRegister(regY, v) }
|
func (r *registers) setY(v uint8) { r.setRegister(regY, v) }
|
||||||
func (r registers) setP(v uint8) registers { return r.setRegister(regP, v) }
|
func (r *registers) setP(v uint8) { r.setRegister(regP, v) }
|
||||||
func (r registers) setS(v uint8) registers { return r.setRegister(regS, v) }
|
func (r *registers) setS(v uint8) { r.setRegister(regS, 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) registers {
|
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)
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,21 @@ package main
|
||||||
|
|
||||||
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
|
||||||
if r.setA(data).getA() != data {
|
r.setA(data)
|
||||||
|
if r.getA() != data {
|
||||||
t.Error("Error storing and loading A")
|
t.Error("Error storing and loading A")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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
|
||||||
if r.setPC(data).getPC() != data {
|
r.setPC(data)
|
||||||
|
if r.getPC() != data {
|
||||||
t.Error("Error storing and loading PC")
|
t.Error("Error storing and loading PC")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue