Add more documentation

This commit is contained in:
Ariejan de Vroom 2014-08-17 15:53:35 +02:00
parent 22432de785
commit e77a599b10
6 changed files with 56 additions and 34 deletions

47
cpu.go
View File

@ -2,15 +2,25 @@ package i6502
import "fmt" import "fmt"
/*
The Cpu only contains the AddressBus, through which 8-bit values can be read and written
at 16-bit addresses.
The Cpu has an 8-bit accumulator (A) and two 8-bit index registers (X,Y). There is a 16-bit
Program Counter (PC) and an 8-bit Stack Pointer (SP), pointing to addresses in 0x0100-01FF.
The status register (P) contains flags for Zero, Negative, Break, Decimal, IrqDisable,
Carry and Overflow flags.
*/
type Cpu struct { type Cpu struct {
A byte // Accumulator
X byte // Index register X
Y byte // Index register Y
PC uint16 // 16-bit program counter PC uint16 // 16-bit program counter
P byte // Status Register P byte // Status Register
SP byte // Stack Pointer SP byte // Stack Pointer
A byte // Accumulator
X byte // X index register
Y byte // Y index register
Bus *AddressBus // The address bus Bus *AddressBus // The address bus
} }
@ -23,21 +33,27 @@ const (
) )
// Create an new Cpu instance with the specified AddressBus // Create an new Cpu, using the AddressBus for accessing memory.
func NewCpu(bus *AddressBus) (*Cpu, error) { func NewCpu(bus *AddressBus) (*Cpu, error) {
return &Cpu{Bus: bus}, nil return &Cpu{Bus: bus}, nil
} }
// Returns a string containing the current state of the CPU.
func (c *Cpu) String() string { func (c *Cpu) String() string {
str := ">>> CPU [ A ] [ X ] [ Y ] [ SP ] [ PC ] NVxBDIZC\n>>> 0x%02X 0x%02X 0x%02X 0x%02X 0x%04X %08b\n" str := ">>> CPU [ A ] [ X ] [ Y ] [ SP ] [ PC ] NVxBDIZC\n>>> 0x%02X 0x%02X 0x%02X 0x%02X 0x%04X %08b\n"
return fmt.Sprintf(str, c.A, c.X, c.Y, c.SP, c.PC, c.P) return fmt.Sprintf(str, c.A, c.X, c.Y, c.SP, c.PC, c.P)
} }
func (c *Cpu) hasAddressBus() bool { /*
return c.Bus != nil Reset the CPU, emulating the RESB pin.
}
// Reset the CPU, emulating the RESB pin. The status register is reset to a know state (0x34, IrqDisabled set, Decimal unset, Break set).
Then the Program Counter is set to the value read from `ResetVector` (0xFFFC-FFFD).
Normally, no assumptions can be made about registers (A, X, Y) and the
Stack Pointer. For convenience, these are reset to 0x00 (A,X,Y) and 0xFF (SP).
*/
func (c *Cpu) Reset() { func (c *Cpu) Reset() {
c.PC = c.Bus.Read16(ResetVector) c.PC = c.Bus.Read16(ResetVector)
c.P = 0x34 c.P = 0x34
@ -49,11 +65,17 @@ func (c *Cpu) Reset() {
c.SP = 0xFF c.SP = 0xFF
} }
// Simulate the IRQ pin /*
Simulate the IRQ pin.
This will push the current Cpu state to the stack (P + PC) and set the PC
to the address read from the `IrqVector` (0xFFFE-FFFF)
*/
func (c *Cpu) Interrupt() { func (c *Cpu) Interrupt() {
c.handleIrq(c.PC) c.handleIrq(c.PC)
} }
// Handles an interrupt or BRK.
func (c *Cpu) handleIrq(PC uint16) { func (c *Cpu) handleIrq(PC uint16) {
c.stackPush(byte(PC >> 8)) c.stackPush(byte(PC >> 8))
c.stackPush(byte(PC)) c.stackPush(byte(PC))
@ -65,7 +87,7 @@ func (c *Cpu) handleIrq(PC uint16) {
} }
// Load the specified program data at the given memory location // Load the specified program data at the given memory location
// and point the Program Counter to the beginning of the program // and point the Program Counter to the beginning of the program.
func (c *Cpu) LoadProgram(data []byte, location uint16) { func (c *Cpu) LoadProgram(data []byte, location uint16) {
for i, b := range data { for i, b := range data {
c.Bus.Write(location+uint16(i), b) c.Bus.Write(location+uint16(i), b)
@ -74,13 +96,14 @@ func (c *Cpu) LoadProgram(data []byte, location uint16) {
c.PC = location c.PC = location
} }
// Execute the instruction pointed to by the Program Counter (PC) // Read and execute the instruction pointed to by the Program Counter (PC)
func (c *Cpu) Step() { func (c *Cpu) Step() {
instruction := c.readNextInstruction() instruction := c.readNextInstruction()
c.PC += uint16(instruction.Size) c.PC += uint16(instruction.Size)
c.execute(instruction) c.execute(instruction)
} }
// Handle the execution of an instruction
func (c *Cpu) execute(instruction Instruction) { func (c *Cpu) execute(instruction Instruction) {
switch instruction.opcodeId { switch instruction.opcodeId {
case nop: case nop:

View File

@ -76,6 +76,9 @@ func TestCpuReset(t *testing.T) {
// **1101** is specified, but we are satisfied with // **1101** is specified, but we are satisfied with
// 00110100 here. // 00110100 here.
assert.Equal(0x34, cpu.P) assert.Equal(0x34, cpu.P)
assert.True(cpu.getIrqDisable())
assert.False(cpu.getDecimal())
assert.True(cpu.getBreak())
// Read PC from $FFFC-FFFD // Read PC from $FFFC-FFFD
assert.Equal(0x1234, cpu.PC) assert.Equal(0x1234, cpu.PC)

View File

@ -5,19 +5,15 @@ import (
) )
type Instruction struct { type Instruction struct {
// Embed OpType OpType // Embed OpType
OpType
// 8-bit operand for 2-byte instructions Op8 byte // 8-bit operand for 2-byte instructions
Op8 byte Op16 uint16 // 16-bit operand for 3-byte instructions
// 16-bit operand for 3-byte instructions Address uint16 // Address location where this instruction got read, for debugging purposes
Op16 uint16
// Address location where this instruction got read
Address uint16
} }
// Return a string containing debug information about the instruction and operands.
func (i Instruction) String() (output string) { func (i Instruction) String() (output string) {
switch i.Size { switch i.Size {
case 1: case 1:

View File

@ -1,5 +1,9 @@
package i6502 package i6502
/*
Anything implementing the Memory interface can be attached to the AddressBus
and become accessible by the Cpu.
*/
type Memory interface { type Memory interface {
Size() uint16 Size() uint16
Read(address uint16) byte Read(address uint16) byte

View File

@ -160,20 +160,12 @@ var instructionNames = [...]string{
// addressing mode. It also includes some extra information for the // addressing mode. It also includes some extra information for the
// emulator, like number of cycles // emulator, like number of cycles
type OpType struct { type OpType struct {
// The actual Opcode byte read from memory Opcode byte // 65(C)02 Opcode, this includes an instruction and addressing mode
Opcode byte Size uint8 // Size of the entire instruction in bytes
Cycles uint8 // Number of clock cycles required to complete this instruction
// Opcode ID opcodeId uint8 // Decoded opcode Id,
opcodeId uint8 addressingId uint8 // Decoded address mode Id
// Addressing Mode ID
addressingId uint8
// Size of this instruction, either 1, 2 or 3 bytes
Size uint8
// Number of clock cycles this instruction needs
Cycles uint8
} }
var opTypes = map[uint8]OpType{ var opTypes = map[uint8]OpType{

4
ram.go
View File

@ -1,9 +1,13 @@
package i6502 package i6502
/*
Random Access Memory, read/write, can be of any size.
*/
type Ram struct { type Ram struct {
data []byte data []byte
} }
// Create a new Ram component of the given size.
func NewRam(size int) (*Ram, error) { func NewRam(size int) (*Ram, error) {
return &Ram{data: make([]byte, size)}, nil return &Ram{data: make([]byte, size)}, nil
} }