Documentation ¶
Overview ¶
Package cpu emulates the 6507 microprocessor found in the Atari VCS. Like all 8-bit processors of the era, the 6507 executes instructions according to the single byte value read from an address pointed to by the program counter. This single byte is the opcode and is looked up in the instruction table. The instruction definition for that opcode is then used to move execution of the program forward.
The instance of the CPU type require an instance of a bus.CPUBus implementation as the sole argument. The CPUBus interface defines the memory operations required by the CPU. See the bus package for details.
The bread-and-butter of the CPU type is the ExecuteInstruction() function. Its sole argument is a callback function to be called at every cycle boundary of the instruction.
Let's assume mem is an instance of the CPUBus interface loaded 6507 instructions.
mc, _ := cpu.NewCPU(mem) numCycles := 0 numInstructions := 0 for { mc.ExecuteInstruction(func() error { numCycles ++ }) numInstructions ++ }
The above program does nothing interesting except to show how ExecuteInstruction() can be used to pump information to an callback function. The VCS emulation uses this to run the TIA emulation three times for every CPU cycle - the CPU clock runs at 1.19MHz while the TIA clock runs at 3.57Mhz. TIA emulation is discussed more fully in the TIA package.
The CPU type contains some public fields that are worthy of mention. The LastResult field can be probed for information about the last instruction executed, or about the current instruction being executed if accessed from ExecuteInstruction()'s callback function. See the result package for more information. Very useful for debuggers.
The NoFlowControl flag is used by the disassembly package to prevent the CPU from honouring "flow control" functions (ie. JMP, BNE, BEQ, etc.). See instructions package for classifications.
Index ¶
- Constants
- func NilCycleCallback() error
- type CPU
- func (mc *CPU) ExecuteInstruction(cycleCallback func() error) error
- func (mc *CPU) HasReset() bool
- func (mc *CPU) LoadPC(directAddress uint16) error
- func (mc *CPU) LoadPCIndirect(indirectAddress uint16) error
- func (mc *CPU) Plumb(mem cpubus.Memory)
- func (mc *CPU) PredictRTS() uint16
- func (mc *CPU) Reset()
- func (mc *CPU) Snapshot() *CPU
- func (mc *CPU) String() string
Constants ¶
const (
ResetMidInstruction = "cpu: appears to have been reset mid-instruction"
)
Sentinal errors returned by ExecuteInstruction.
Variables ¶
This section is empty.
Functions ¶
func NilCycleCallback ¶ added in v0.19.0
func NilCycleCallback() error
NilCycleCallback can be provided as an argument to ExecuteInstruction(). It's a convenienct do-nothing function.
Types ¶
type CPU ¶
type CPU struct { PC registers.ProgramCounter A registers.Register X registers.Register Y registers.Register SP registers.Register Status registers.StatusRegister // controls whether cpu executes a cycle when it receives a clock tick (pin // 3 of the 6507) RdyFlg bool // last result. the address field is guaranteed to be always valid except // when the CPU has just been reset. we use this fact to help us decide // whether the CPU has just been reset (see HasReset() function) // // note a peculiarity in the current emulation means that LastResult is not // reset unless the RdyFlg is true at the start of the execution. LastResult execution.Result // NoFlowControl sets whether the cpu responds accurately to instructions // that affect the flow of the program (branches, JPS, subroutines and // interrupts). we use this in the disassembly package to make sure we // reach every part of the program. // // note that the alteration of flow as a result of bank switching is still // possible even if NoFlowControl is true. this is because bank switching // is outside of the direct control of the CPU. NoFlowControl bool // Interrupted indicated that the CPU has been put into a state outside of // its normal operation. When true work may be done on the CPU that would // otherwise be considered an error. Resets to false on every call to // ExecuteInstruction() Interrupted bool // Whether the last memory access by the CPU was a phantom access PhantomMemAccess bool // the cpu has encounted a KIL instruction. requires a Reset() Killed bool // contains filtered or unexported fields }
CPU implements the 6507 found as found in the Atari 2600. Register logic is implemented by the Register type in the registers sub-package.
func NewCPU ¶
NewCPU is the preferred method of initialisation for the CPU structure. Note that the CPU will be initialised in a random state.
func (*CPU) ExecuteInstruction ¶
ExecuteInstruction steps CPU forward one instruction. The basic process when executing an instruction is this:
- read opcode and look up instruction definition
- read operands (if any) according to the addressing mode of the instruction
- using the operator as a guide, perform the instruction on the data
All instructions take at least 2 cycle. After each cycle, the cycleCallback() function is run, thereby allowing the rest of the VCS hardware to operate.
The cycleCallback arugment should *never* be nil. Use the NilCycleCallback() function in this package if you want a nil effect.
func (*CPU) LoadPCIndirect ¶
LoadPCIndirect loads the contents of indirectAddress into the PC.
func (*CPU) PredictRTS ¶ added in v0.18.0
PredictRTS returns the PC address that would result if RTS was run at the current moment.
Directories ¶
Path | Synopsis |
---|---|
Package execution tracks the result of instruction execution on the CPU.
|
Package execution tracks the result of instruction execution on the CPU. |
Package instructions defines the table of instruction for the 6507.
|
Package instructions defines the table of instruction for the 6507. |
Package registers implements the three types of registers found in the 6507.
|
Package registers implements the three types of registers found in the 6507. |
test
Package test contains functions useful for testing CPU registers.
|
Package test contains functions useful for testing CPU registers. |