aboutsummaryrefslogtreecommitdiff
path: root/cpu/cpu.go
blob: fb673b751a30f5d28e4fe1c5b32b1422af8699bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
	Jammed bool

	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
	c.Jammed = false
}

func (c *CPU) IRQ() {
	if c.Jammed {
		return
	}
	if c.flag(FlagI) {
		return
	}
	c.interrupt(vectorIRQ, false)
	c.Cycles += 7
}

func (c *CPU) NMI() {
	if c.Jammed {
		return
	}
	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 {
	if c.Jammed {
		c.Cycles++
		return 1
	}
	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)
}