-
Notifications
You must be signed in to change notification settings - Fork 2
/
execution.go
executable file
·144 lines (128 loc) · 3.44 KB
/
execution.go
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package cpu
import (
"fmt"
)
func (cpu *CPU) handleInterrupt() {
if cpu.interrupts.Enabled() {
cpu.interrupts.Disable()
switch {
case cpu.interrupts.VblankPending():
// 0040 Vertical Blank Interrupt Start Address
cpu.rst(0x0040)()
cpu.interrupts.ResetVblank()
case cpu.interrupts.StatPending():
// 0048 LCDC Status Interrupt Start Address
cpu.rst(0x0048)()
cpu.interrupts.ResetStat()
case cpu.interrupts.TimerPending():
// 0050 Timer OverflowInterrupt Start Address
cpu.rst(0x0050)()
cpu.interrupts.ResetTimer()
case cpu.interrupts.SerialPending():
// 0058 Serial Transfer Completion Interrupt Start Address
cpu.rst(0x0058)()
cpu.interrupts.ResetSerial()
case cpu.interrupts.JoypadPending():
// 0060 High-to-Low of P10-P13 Interrupt Start Address
cpu.rst(0x0060)()
cpu.interrupts.ResetJoypad()
}
// Now push the PC
cpu.push(&cpu.m8b)()
cpu.push(&cpu.m8a)()
}
}
func (cpu *CPU) checkInterrupts() []func() {
if cpu.interrupts.Pending() {
if cpu.interrupts.Enabled() {
if cpu.halted {
cpu.halted = false
return longInterrupt
}
return shortInterrupt
} else {
if cpu.halted {
cpu.halted = false
return veryShortInterrupt
}
}
}
return nil
}
func (cpu *CPU) next() bool {
interrupts := cpu.checkInterrupts()
if interrupts != nil {
cpu.currentCycle = 0
cpu.currentSubinstructions = interrupts
cpu.currentIsFinishedEarly = nil
return false
}
if cpu.halted || cpu.stopped {
return true
}
mapper := cpu.mapper
cpu.currentInstruction = mapper.Read(cpu.pc)
if cpu.currentInstruction == 0xcb {
cpu.pc++
cpu.currentInstruction = mapper.Read(cpu.pc)
cpu.currentCycle = 0
cpu.currentMetadata = prefixedInstructionMetadata[cpu.currentInstruction]
cpu.currentSubinstructions = prefix[cpu.currentInstruction]
cpu.currentIsFinishedEarly = nil
} else {
cpu.currentCycle = 0
cpu.currentMetadata = instructionMetadata[cpu.currentInstruction]
cpu.currentSubinstructions = normal[cpu.currentInstruction]
cpu.currentIsFinishedEarly = isFinishedEarlys[cpu.currentInstruction]
}
// Reset any context from previous instructions
cpu.u8a = 0
cpu.u8b = 0
cpu.m8a = 0
cpu.m8b = 0
// Finally increment PC
if !cpu.haltbug {
cpu.pc++
} else {
cpu.haltbug = false
}
if cpu.debugCPU {
metadata := cpu.currentMetadata
var pc uint16
var operandValue string
if cpu.currentMetadata.Prefixed {
pc = cpu.pc - 2
} else {
pc = cpu.pc - 1
switch metadata.Length {
case 2:
u8 := mapper.Read(cpu.pc)
operandValue = fmt.Sprintf("%02x", u8)
case 3:
u16 := uint16(mapper.Read(cpu.pc)) | uint16(mapper.Read(cpu.pc+1))<<8
operandValue = fmt.Sprintf("%04x", u16)
}
}
fmt.Printf("0x%04x: [%02x] %-12s | %-4s | a:%02x b:%02x c:%02x d:%02x e:%02x f:%02x h:%02x l:%02x sp:%04x\n",
pc, cpu.currentInstruction, fmt.Sprintf("%s %s %s", metadata.Mnemonic, metadata.Operand1, metadata.Operand2), operandValue, cpu.a, cpu.b, cpu.c, cpu.d, cpu.e, cpu.f, cpu.h, cpu.l, cpu.sp)
}
return false
}
func (cpu *CPU) isFinished() bool {
if cpu.currentIsFinishedEarly == nil {
return cpu.currentCycle == len(cpu.currentSubinstructions)
}
return cpu.currentIsFinishedEarly(cpu.currentCycle)
}
// ExecuteMachineCycle runs the CPU for one machine cycle
func (cpu *CPU) ExecuteMachineCycle() {
if cpu.isFinished() {
halted := cpu.next()
if halted {
return
}
}
cpu.currentSubinstructions[cpu.currentCycle]()
cpu.oam.Corrupt()
cpu.currentCycle++
}