1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-06-16 10:29:29 +00:00
go6502/cpu/cpu.go

165 lines
3.0 KiB
Go
Raw Normal View History

2013-02-23 22:25:46 +00:00
package cpu
2013-02-18 05:09:38 +00:00
2013-02-23 22:25:46 +00:00
// BUG(zellyn): Implement IRQ, NMI.
2013-02-18 05:09:38 +00:00
2013-02-23 22:25:46 +00:00
// BUG(zellyn): implement interrupts, and 6502/65C02
// decimal-mode-clearing and BRK-skipping quirks. See
// http://en.wikipedia.org/wiki/MOS_Technology_6502#Bugs_and_quirks.
2013-02-18 05:09:38 +00:00
import (
"fmt"
"github.com/zellyn/go6502/asm"
2013-02-18 05:09:38 +00:00
)
2013-02-23 22:25:46 +00:00
// Chip versions.
2013-03-01 00:33:39 +00:00
type CpuVersion int
2013-02-18 05:09:38 +00:00
const (
2013-03-01 00:33:39 +00:00
VERSION_6502 CpuVersion = iota
VERSION_65C02
2013-02-18 05:09:38 +00:00
)
2013-02-23 22:25:46 +00:00
// Interface for the Cpu type.
2013-02-18 05:09:38 +00:00
type Cpu interface {
Reset()
Step() error
SetPC(uint16)
A() byte
X() byte
Y() byte
PC() uint16
P() byte // [NV-BDIZC]
SP() byte
2013-02-23 22:25:46 +00:00
// BUG(zellyn): Add signaling of interrupts.
Print(bool)
2013-02-18 05:09:38 +00:00
}
2013-02-23 22:25:46 +00:00
// Memory interface, for all memory access.
2013-02-18 05:09:38 +00:00
type Memory interface {
Read(uint16) byte
Write(uint16, byte)
}
2013-02-23 22:25:46 +00:00
// Ticker interface, for keeping track of cycles.
2014-03-05 01:42:51 +00:00
type Ticker func()
2013-02-18 05:09:38 +00:00
2013-02-23 22:25:46 +00:00
// Interrupt vectors.
2013-02-18 05:09:38 +00:00
const (
STACK_BASE = 0x100
IRQ_VECTOR = 0xFFFE
NMI_VECTOR = 0xFFFA
RESET_VECTOR = 0xFFFC
)
2013-02-23 22:25:46 +00:00
// Flag masks.
2013-02-18 05:09:38 +00:00
const (
FLAG_C = 1 << iota
FLAG_Z
FLAG_I
FLAG_D
FLAG_B
FLAG_UNUSED
FLAG_V
FLAG_N
FLAG_NV = FLAG_N | FLAG_V
2013-02-18 05:09:38 +00:00
)
type registers struct {
A byte
X byte
Y byte
PC uint16
P byte // [NV-BDIZC]
SP byte
}
type cpu struct {
m Memory
t Ticker
r registers
oldPC uint16
2013-03-01 00:33:39 +00:00
version CpuVersion
print bool
2013-02-18 05:09:38 +00:00
}
2013-02-23 22:25:46 +00:00
// Create and return a new Cpu object with the given memory, ticker, and of the given version.
2013-03-01 00:33:39 +00:00
func NewCPU(memory Memory, ticker Ticker, version CpuVersion) Cpu {
c := cpu{m: memory, t: ticker, version: version}
c.r.P |= FLAG_UNUSED | FLAG_B // Set unused flag to 1
2013-02-18 05:09:38 +00:00
return &c
}
func (c *cpu) A() byte {
return c.r.A
}
func (c *cpu) X() byte {
return c.r.X
}
func (c *cpu) Y() byte {
return c.r.Y
}
func (c *cpu) PC() uint16 {
return c.r.PC
}
func (c *cpu) P() byte {
return c.r.P
}
func (c *cpu) SP() byte {
return c.r.SP
}
2013-02-23 22:25:46 +00:00
// Helper for reading a word of memory.
2013-02-18 05:09:38 +00:00
func (c *cpu) readWord(address uint16) uint16 {
return uint16(c.m.Read(address)) + (uint16(c.m.Read(address+1)) << 8)
}
2013-02-23 22:25:46 +00:00
// Reset performs a reset.
2013-02-18 05:09:38 +00:00
func (c *cpu) Reset() {
c.r.SP = 0
c.r.PC = c.readWord(RESET_VECTOR)
c.r.P |= FLAG_I // Turn interrupts off
switch c.version {
case VERSION_6502:
// 6502 doesn't CLD on interrupt
2013-02-18 05:09:38 +00:00
c.r.P &^= FLAG_D
case VERSION_65C02:
default:
panic("Unknown chip version")
2013-02-18 05:09:38 +00:00
}
}
// status prints out the current CPU instruction and register status.
func status(c *cpu, m Memory) string {
2016-04-15 15:20:56 +00:00
bytes, text, _ := asm.Disasm(c.PC(), m.Read(c.PC()), m.Read(c.PC()+1), m.Read(c.PC()+2), nil, 3)
2014-08-06 05:18:03 +00:00
return fmt.Sprintf("$%04X: %-8s %-11s A=$%02X X=$%02X Y=$%02X SP=$%02X P=$%08b",
c.PC(), bytes, text, c.A(), c.X(), c.Y(), c.SP(), c.P())
}
2013-02-23 22:25:46 +00:00
// Step takes a single step (which will last several cycles, calling Tick() on the Ticker for each).
2013-02-18 05:09:38 +00:00
func (c *cpu) Step() error {
if c.print {
fmt.Println(status(c, c.m))
}
c.oldPC = c.r.PC
2013-02-18 05:09:38 +00:00
i := c.m.Read(c.r.PC)
c.r.PC++
2014-03-05 01:42:51 +00:00
c.t()
2013-02-18 05:09:38 +00:00
if f, ok := Opcodes[i]; ok {
f(c)
2013-02-18 05:09:38 +00:00
return nil
}
return fmt.Errorf("Unknown opcode at location $%04X: $%02X", c.r.PC, i)
}
2013-02-23 22:25:46 +00:00
// Set the program counter.
2013-02-18 05:09:38 +00:00
func (c *cpu) SetPC(address uint16) {
c.r.PC = address
}
func (c *cpu) Print(print bool) {
c.print = print
}