diff options
Diffstat (limited to 'cpu/cpu.go')
| -rw-r--r-- | cpu/cpu.go | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/cpu/cpu.go b/cpu/cpu.go new file mode 100644 index 0000000..79199a2 --- /dev/null +++ b/cpu/cpu.go @@ -0,0 +1,116 @@ +package cpu + +const ( + vectorNMI uint16 = 0xFFFA + vectorReset uint16 = 0xFFFC + vectorIRQ uint16 = 0xFFFE + + stackBase uint16 = 0x0100 +) + +type CPU struct { + A, X, Y uint8 + SP uint8 // stack pointer + PC uint16 // program counter + Status uint8 // status flags + + Bus Bus + Cycles uint64 + + extraCycles int +} + +func NewCPU(bus Bus) *CPU { + return &CPU{Bus: bus} +} + +func (c *CPU) read(addr uint16) uint8 { + return c.Bus.Read(addr) +} + +func (c *CPU) write(addr uint16, v uint8) { + c.Bus.Write(addr, v) +} + +func (c *CPU) read16(addr uint16) uint16 { + lo := uint16(c.read(addr)) + hi := uint16(c.read(addr + 1)) + return hi<<8 | lo +} + +func (c *CPU) push(v uint8) { + c.write(stackBase+uint16(c.SP), v) + c.SP-- +} + +func (c *CPU) pop() uint8 { + c.SP++ + return c.read(stackBase + uint16(c.SP)) +} + +func (c *CPU) push16(v uint16) { + c.push(uint8(v >> 8)) + c.push(uint8(v)) +} + +func (c *CPU) pop16() uint16 { + lo := uint16(c.pop()) + hi := uint16(c.pop()) + return hi<<8 | lo +} + +func (c *CPU) Reset() { + c.A, c.X, c.Y = 0, 0, 0 + c.SP = 0xFD + c.Status = FlagU | FlagI + c.PC = c.read16(vectorReset) + c.Cycles = 7 +} + +func (c *CPU) IRQ() { + if c.flag(FlagI) { + return + } + c.interrupt(vectorIRQ, false) + c.Cycles += 7 +} + +func (c *CPU) NMI() { + c.interrupt(vectorNMI, false) + c.Cycles += 7 +} + +func (c *CPU) interrupt(vector uint16, brk bool) { + c.push16(c.PC) + status := c.Status | FlagU + if brk { + status |= FlagB + } else { + status &^= FlagB + } + c.push(status) + c.setFlag(FlagI, true) + c.PC = c.read16(vector) +} + +func (c *CPU) Step() int { + before := c.Cycles + + opcode := c.read(c.PC) + c.PC++ + + entry := opcodeTable[opcode] + op := c.resolveOperand(entry.mode) + + c.extraCycles = 0 + entry.exec(c, op) + + cycles := entry.cycles + if entry.pageCrossPenalty && op.pageCrossed { + cycles++ + } + cycles += c.extraCycles + c.Cycles += uint64(cycles) + + return int(c.Cycles - before) +} |