cpu

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 19, 2024 License: BSD-2-Clause Imports: 3 Imported by: 4

README

go6502/cpu

Initialize a 64KB memory space and load some machine code from a byte slice.

mem := go6502.NewFlatMemory()

// Load a byte slice of machine code at address 0x600
mem.StoreBytes(0x600, []byte{0xa2, 0x05, 0xa1, 0x02, 0xa9, 0x08, 0x8d,
    0x01, 0x02, 0x69, 0xfe, 0x8d, 0x00, 0x02, 0xa9, 0xff, 0xad, 0x00,
    0x02, 0xa2, 0xee, 0x4c, 0x00, 0x06})

Create an emulated CMOS 65c02 CPU and initialize its program counter.

cpu := go6502.NewCPU(go6502.CMOS, mem)
cpu.SetPC(0x600)

Use the Step() function to manually step the CPU one instruction at a time.

for i := 0; i < 20; i++ {
    cpu.Step()
}

Use the go6502/disasm package to disassemble machine code while stepping the CPU.

for i := 0; i < 20; i++ {
    pc := cpu.Reg.PC
    line, _, _ := disasm.Disassemble(cpu.Mem, pc)
    cpu.Step()
    fmt.Printf("%04X-   %-12s  A=%02X X=%02X Y=%02X PS=[%s] SP=%02X PC=%04X Cycles=%d\n",
        pc, line,
        cpu.Reg.A, cpu.Reg.X, cpu.Reg.Y, psString(&cpu.Reg),
        cpu.Reg.SP, cpu.Reg.PC,
        cpu.Cycles)
}

Output:

0600-   LDX #$05      A=00 X=05 Y=00 PS=[------] SP=FF PC=0602 Cycles=2
0602-   LDA ($02,X)   A=00 X=05 Y=00 PS=[-Z----] SP=FF PC=0604 Cycles=8
0604-   LDA #$08      A=08 X=05 Y=00 PS=[------] SP=FF PC=0606 Cycles=10
0606-   STA $0201     A=08 X=05 Y=00 PS=[------] SP=FF PC=0609 Cycles=14
0609-   ADC #$FE      A=06 X=05 Y=00 PS=[C-----] SP=FF PC=060B Cycles=16
060B-   STA $0200     A=06 X=05 Y=00 PS=[C-----] SP=FF PC=060E Cycles=20
060E-   LDA #$FF      A=FF X=05 Y=00 PS=[C----N] SP=FF PC=0610 Cycles=22
0610-   LDA $0200     A=06 X=05 Y=00 PS=[C-----] SP=FF PC=0613 Cycles=26
0613-   LDX #$EE      A=06 X=EE Y=00 PS=[C----N] SP=FF PC=0615 Cycles=28
0615-   JMP $0600     A=06 X=EE Y=00 PS=[C----N] SP=FF PC=0600 Cycles=31
0600-   LDX #$05      A=06 X=05 Y=00 PS=[C-----] SP=FF PC=0602 Cycles=33
0602-   LDA ($02,X)   A=00 X=05 Y=00 PS=[CZ----] SP=FF PC=0604 Cycles=39
0604-   LDA #$08      A=08 X=05 Y=00 PS=[C-----] SP=FF PC=0606 Cycles=41
0606-   STA $0201     A=08 X=05 Y=00 PS=[C-----] SP=FF PC=0609 Cycles=45
0609-   ADC #$FE      A=07 X=05 Y=00 PS=[C-----] SP=FF PC=060B Cycles=47
060B-   STA $0200     A=07 X=05 Y=00 PS=[C-----] SP=FF PC=060E Cycles=51
060E-   LDA #$FF      A=FF X=05 Y=00 PS=[C----N] SP=FF PC=0610 Cycles=53
0610-   LDA $0200     A=07 X=05 Y=00 PS=[C-----] SP=FF PC=0613 Cycles=57
0613-   LDX #$EE      A=07 X=EE Y=00 PS=[C----N] SP=FF PC=0615 Cycles=59
0615-   JMP $0600     A=07 X=EE Y=00 PS=[C----N] SP=FF PC=0600 Cycles=62

Here is the implementation of the helper function psString used in the example:

func psString(r *go6502.Registers) string {
	v := func(bit bool, ch byte) byte {
		if bit {
			return ch
		}
		return '-'
	}
	b := []byte{
		v(r.Carry, 'C'),
		v(r.Zero, 'Z'),
		v(r.InterruptDisable, 'I'),
		v(r.Decimal, 'D'),
		v(r.Overflow, 'O'),
		v(r.Negative, 'N'),
	}
	return string(b)
}

Documentation

Overview

Package cpu implements a 6502 CPU instruction set and emulator.

Index

Constants

View Source
const (
	CarryBit            = 1 << 0
	ZeroBit             = 1 << 1
	InterruptDisableBit = 1 << 2
	DecimalBit          = 1 << 3
	BreakBit            = 1 << 4
	ReservedBit         = 1 << 5
	OverflowBit         = 1 << 6
	SignBit             = 1 << 7
)

Bits assigned to the processor status byte

Variables

View Source
var (
	ErrMemoryOutOfBounds = errors.New("Memory access out of bounds")
)

Errors

Functions

This section is empty.

Types

type Architecture

type Architecture byte

Architecture selects the CPU chip: 6502 or 65c02

const (
	// NMOS 6502 CPU
	NMOS Architecture = iota

	// CMOS 65c02 CPU
	CMOS
)

type Breakpoint

type Breakpoint struct {
	Address  uint16 // address of execution breakpoint
	Disabled bool   // this breakpoint is currently disabled
}

A Breakpoint represents an address that will cause the debugger to stop code execution when the program counter reaches it.

type BreakpointHandler added in v0.2.0

type BreakpointHandler interface {
	OnBreakpoint(cpu *CPU, b *Breakpoint)
	OnDataBreakpoint(cpu *CPU, b *DataBreakpoint)
}

The BreakpointHandler interface should be implemented by any object that wishes to receive debugger breakpoint notifications.

type BrkHandler added in v0.2.0

type BrkHandler interface {
	OnBrk(cpu *CPU)
}

BrkHandler is an interface implemented by types that wish to be notified when a BRK instruction is about to be executed.

type CPU

type CPU struct {
	Arch    Architecture    // CPU architecture
	Reg     Registers       // CPU registers
	Mem     Memory          // assigned memory
	Cycles  uint64          // total executed CPU cycles
	LastPC  uint16          // Previous program counter
	InstSet *InstructionSet // Instruction set used by the CPU
	// contains filtered or unexported fields
}

CPU represents a single 6502 CPU. It contains a pointer to the memory associated with the CPU.

func NewCPU

func NewCPU(arch Architecture, m Memory) *CPU

NewCPU creates an emulated 6502 CPU bound to the specified memory.

func (*CPU) AttachBrkHandler added in v0.2.0

func (cpu *CPU) AttachBrkHandler(handler BrkHandler)

AttachBrkHandler attaches a handler that is called whenever the BRK instruction is executed.

func (*CPU) AttachDebugger

func (cpu *CPU) AttachDebugger(debugger *Debugger)

AttachDebugger attaches a debugger to the CPU. The debugger receives notifications whenever the CPU executes an instruction or stores a byte to memory.

func (*CPU) DetachDebugger

func (cpu *CPU) DetachDebugger()

DetachDebugger detaches the currently debugger from the CPU.

func (*CPU) GetInstruction

func (cpu *CPU) GetInstruction(addr uint16) *Instruction

GetInstruction returns the instruction opcode at the requested address.

func (*CPU) NextAddr added in v0.3.0

func (cpu *CPU) NextAddr(addr uint16) uint16

NextAddr returns the address of the next instruction following the instruction at addr.

func (*CPU) SetPC

func (cpu *CPU) SetPC(addr uint16)

SetPC updates the CPU program counter to 'addr'.

func (*CPU) Step

func (cpu *CPU) Step()

Step the cpu by one instruction.

type DataBreakpoint

type DataBreakpoint struct {
	Address     uint16 // breakpoint triggered by stores to this address
	Disabled    bool   // this breakpoint is currently disabled
	Conditional bool   // this breakpoint is conditional on a certain Value being stored
	Value       byte   // the value that must be stored if the breakpoint is conditional
}

A DataBreakpoint represents an address that will cause the debugger to stop executing code when a byte is stored to it.

type Debugger

type Debugger struct {
	// contains filtered or unexported fields
}

The Debugger interface may be implemented to intercept instructions before and after they are executed on the emulated CPU.

func NewDebugger

func NewDebugger(breakpointHandler BreakpointHandler) *Debugger

NewDebugger creates a new CPU debugger.

func (*Debugger) AddBreakpoint

func (d *Debugger) AddBreakpoint(addr uint16) *Breakpoint

AddBreakpoint adds a new breakpoint address to the debugger. If the breakpoint was already set, the request is ignored.

func (*Debugger) AddConditionalDataBreakpoint

func (d *Debugger) AddConditionalDataBreakpoint(addr uint16, value byte)

AddConditionalDataBreakpoint adds a conditional data breakpoint on the requested address.

func (*Debugger) AddDataBreakpoint

func (d *Debugger) AddDataBreakpoint(addr uint16) *DataBreakpoint

AddDataBreakpoint adds an unconditional data breakpoint on the requested address.

func (*Debugger) GetBreakpoint

func (d *Debugger) GetBreakpoint(addr uint16) *Breakpoint

GetBreakpoint looks up a breakpoint by address and returns it if found. Otherwise it returns nil.

func (*Debugger) GetBreakpoints

func (d *Debugger) GetBreakpoints() []*Breakpoint

GetBreakpoints returns all breakpoints currently set in the debugger.

func (*Debugger) GetDataBreakpoint

func (d *Debugger) GetDataBreakpoint(addr uint16) *DataBreakpoint

GetDataBreakpoint looks up a data breakpoint on the provided address and returns it if found. Otherwise it returns nil.

func (*Debugger) GetDataBreakpoints

func (d *Debugger) GetDataBreakpoints() []*DataBreakpoint

GetDataBreakpoints returns all data breakpoints currently set in the debugger.

func (*Debugger) RemoveBreakpoint

func (d *Debugger) RemoveBreakpoint(addr uint16)

RemoveBreakpoint removes a breakpoint from the debugger.

func (*Debugger) RemoveDataBreakpoint

func (d *Debugger) RemoveDataBreakpoint(addr uint16)

RemoveDataBreakpoint removes a (conditional or unconditional) data breakpoint at the requested address.

type FlatMemory

type FlatMemory struct {
	// contains filtered or unexported fields
}

FlatMemory represents an entire 16-bit address space as a singular 64K buffer.

func NewFlatMemory

func NewFlatMemory() *FlatMemory

NewFlatMemory creates a new 16-bit memory space.

func (*FlatMemory) LoadAddress

func (m *FlatMemory) LoadAddress(addr uint16) uint16

LoadAddress loads a 16-bit address value from the requested address and returns it.

When the address spans 2 pages (i.e., address ends in 0xff), the low byte of the loaded address comes from a page-wrapped address. For example, LoadAddress on $12FF reads the low byte from $12FF and the high byte from $1200. This mimics the behavior of the NMOS 6502.

func (*FlatMemory) LoadByte

func (m *FlatMemory) LoadByte(addr uint16) byte

LoadByte loads a single byte from the address and returns it.

func (*FlatMemory) LoadBytes

func (m *FlatMemory) LoadBytes(addr uint16, b []byte)

LoadBytes loads multiple bytes from the address and returns them.

func (*FlatMemory) StoreAddress

func (m *FlatMemory) StoreAddress(addr uint16, v uint16)

StoreAddress stores a 16-bit address value to the requested address.

func (*FlatMemory) StoreByte

func (m *FlatMemory) StoreByte(addr uint16, v byte)

StoreByte stores a byte at the requested address.

func (*FlatMemory) StoreBytes

func (m *FlatMemory) StoreBytes(addr uint16, b []byte)

StoreBytes stores multiple bytes to the requested address.

type Instruction

type Instruction struct {
	Name     string // all-caps name of the instruction
	Mode     Mode   // addressing mode
	Opcode   byte   // hexadecimal opcode value
	Length   byte   // combined size of opcode and operand, in bytes
	Cycles   byte   // number of CPU cycles to execute the instruction
	BPCycles byte   // additional cycles required if boundary page crossed
	// contains filtered or unexported fields
}

An Instruction describes a CPU instruction, including its name, its addressing mode, its opcode value, its operand size, and its CPU cycle cost.

type InstructionSet

type InstructionSet struct {
	Arch Architecture
	// contains filtered or unexported fields
}

An InstructionSet defines the set of all possible instructions that can run on the emulated CPU.

func GetInstructionSet

func GetInstructionSet(arch Architecture) *InstructionSet

GetInstructionSet returns an instruction set for the requested CPU architecture.

func (*InstructionSet) GetInstructions

func (s *InstructionSet) GetInstructions(name string) []*Instruction

GetInstructions returns all CPU instructions whose name matches the provided string.

func (*InstructionSet) Lookup

func (s *InstructionSet) Lookup(opcode byte) *Instruction

Lookup retrieves a CPU instruction corresponding to the requested opcode.

type Memory

type Memory interface {
	// LoadByte loads a single byte from the address and returns it.
	LoadByte(addr uint16) byte

	// LoadBytes loads multiple bytes from the address and stores them into
	// the buffer 'b'.
	LoadBytes(addr uint16, b []byte)

	// LoadAddress loads a 16-bit address value from the requested address and
	// returns it.
	LoadAddress(addr uint16) uint16

	// StoreByte stores a byte to the requested address.
	StoreByte(addr uint16, v byte)

	// StoreBytes stores multiple bytes to the requested address.
	StoreBytes(addr uint16, b []byte)

	// StoreAddres stores a 16-bit address 'v' to the requested address.
	StoreAddress(addr uint16, v uint16)
}

The Memory interface presents an interface to the CPU through which all memory accesses occur.

type Mode

type Mode byte

Mode describes a memory addressing mode.

const (
	IMM Mode = iota // Immediate
	IMP             // Implied (no operand)
	REL             // Relative
	ZPG             // Zero Page
	ZPX             // Zero Page,X
	ZPY             // Zero Page,Y
	ABS             // Absolute
	ABX             // Absolute,X
	ABY             // Absolute,Y
	IND             // (Indirect)
	IDX             // (Indirect,X)
	IDY             // (Indirect),Y
	ACC             // Accumulator (no operand)
)

All possible memory addressing modes

type Registers

type Registers struct {
	A                byte   // accumulator
	X                byte   // X indexing register
	Y                byte   // Y indexing register
	SP               byte   // stack pointer ($100 + SP = stack memory location)
	PC               uint16 // program counter
	Carry            bool   // PS: Carry bit
	Zero             bool   // PS: Zero bit
	InterruptDisable bool   // PS: Interrupt disable bit
	Decimal          bool   // PS: Decimal bit
	Overflow         bool   // PS: Overflow bit
	Sign             bool   // PS: Sign bit
}

Registers contains the state of all 6502 registers.

func (*Registers) Init

func (r *Registers) Init()

Init initializes all registers. A, X, Y = 0. SP = 0xff. PC = 0. PS = 0.

func (*Registers) RestorePS

func (r *Registers) RestorePS(ps byte)

RestorePS restores the CPU processor status from a byte.

func (*Registers) SavePS

func (r *Registers) SavePS(brk bool) byte

SavePS saves the CPU processor status into a byte value. The break bit is set if requested.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL