src/sm83/sm83.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include <mgba/internal/sm83/sm83.h>
7
8#include <mgba/internal/sm83/isa-sm83.h>
9
10void SM83Init(struct SM83Core* cpu) {
11 cpu->master->init(cpu, cpu->master);
12 size_t i;
13 for (i = 0; i < cpu->numComponents; ++i) {
14 if (cpu->components[i] && cpu->components[i]->init) {
15 cpu->components[i]->init(cpu, cpu->components[i]);
16 }
17 }
18}
19
20void SM83Deinit(struct SM83Core* cpu) {
21 if (cpu->master->deinit) {
22 cpu->master->deinit(cpu->master);
23 }
24 size_t i;
25 for (i = 0; i < cpu->numComponents; ++i) {
26 if (cpu->components[i] && cpu->components[i]->deinit) {
27 cpu->components[i]->deinit(cpu->components[i]);
28 }
29 }
30}
31
32void SM83SetComponents(struct SM83Core* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras) {
33 cpu->master = master;
34 cpu->numComponents = extra;
35 cpu->components = extras;
36}
37
38
39void SM83HotplugAttach(struct SM83Core* cpu, size_t slot) {
40 if (slot >= cpu->numComponents) {
41 return;
42 }
43 cpu->components[slot]->init(cpu, cpu->components[slot]);
44}
45
46void SM83HotplugDetach(struct SM83Core* cpu, size_t slot) {
47 if (slot >= cpu->numComponents) {
48 return;
49 }
50 cpu->components[slot]->deinit(cpu->components[slot]);
51}
52
53void SM83Reset(struct SM83Core* cpu) {
54 cpu->af = 0;
55 cpu->bc = 0;
56 cpu->de = 0;
57 cpu->hl = 0;
58
59 cpu->sp = 0;
60 cpu->pc = 0;
61
62 cpu->instruction = 0;
63
64 cpu->tMultiplier = 2;
65 cpu->cycles = 0;
66 cpu->nextEvent = 0;
67 cpu->executionState = SM83_CORE_FETCH;
68 cpu->halted = 0;
69
70 cpu->irqPending = false;
71 cpu->irqh.reset(cpu);
72}
73
74void SM83RaiseIRQ(struct SM83Core* cpu) {
75 cpu->irqPending = true;
76}
77
78static void _SM83InstructionIRQStall(struct SM83Core* cpu) {
79 cpu->executionState = SM83_CORE_STALL;
80}
81
82static void _SM83InstructionIRQFinish(struct SM83Core* cpu) {
83 cpu->executionState = SM83_CORE_OP2;
84 cpu->instruction = _SM83InstructionIRQStall;
85}
86
87static void _SM83InstructionIRQDelay(struct SM83Core* cpu) {
88 --cpu->sp;
89 cpu->index = cpu->sp;
90 cpu->bus = cpu->pc;
91 cpu->executionState = SM83_CORE_MEMORY_STORE;
92 cpu->instruction = _SM83InstructionIRQFinish;
93 cpu->pc = cpu->irqh.irqVector(cpu);
94 cpu->memory.setActiveRegion(cpu, cpu->pc);
95}
96
97static void _SM83InstructionIRQ(struct SM83Core* cpu) {
98 --cpu->sp;
99 cpu->index = cpu->sp;
100 cpu->bus = cpu->pc >> 8;
101 cpu->executionState = SM83_CORE_MEMORY_STORE;
102 cpu->instruction = _SM83InstructionIRQDelay;
103}
104
105static void _SM83Step(struct SM83Core* cpu) {
106 cpu->cycles += cpu->tMultiplier;
107 enum SM83ExecutionState state = cpu->executionState;
108 cpu->executionState = SM83_CORE_IDLE_0;
109 switch (state) {
110 case SM83_CORE_FETCH:
111 if (cpu->irqPending) {
112 cpu->index = cpu->sp;
113 cpu->irqPending = false;
114 cpu->instruction = _SM83InstructionIRQ;
115 cpu->irqh.setInterrupts(cpu, false);
116 break;
117 }
118 cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc);
119 cpu->instruction = _sm83InstructionTable[cpu->bus];
120 ++cpu->pc;
121 break;
122 case SM83_CORE_MEMORY_LOAD:
123 cpu->bus = cpu->memory.load8(cpu, cpu->index);
124 break;
125 case SM83_CORE_MEMORY_STORE:
126 cpu->memory.store8(cpu, cpu->index, cpu->bus);
127 break;
128 case SM83_CORE_READ_PC:
129 cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc);
130 ++cpu->pc;
131 break;
132 case SM83_CORE_STALL:
133 cpu->instruction = _sm83InstructionTable[0]; // NOP
134 break;
135 case SM83_CORE_HALT_BUG:
136 if (cpu->irqPending) {
137 cpu->index = cpu->sp;
138 cpu->irqPending = false;
139 cpu->instruction = _SM83InstructionIRQ;
140 cpu->irqh.setInterrupts(cpu, false);
141 break;
142 }
143 cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc);
144 cpu->instruction = _sm83InstructionTable[cpu->bus];
145 break;
146 default:
147 break;
148 }
149}
150
151static inline bool _SM83TickInternal(struct SM83Core* cpu) {
152 bool running = true;
153 _SM83Step(cpu);
154 int t = cpu->tMultiplier;
155 if (cpu->cycles + t * 2 >= cpu->nextEvent) {
156 int32_t diff = cpu->nextEvent - cpu->cycles;
157 cpu->cycles = cpu->nextEvent;
158 cpu->executionState += diff >> (t - 1); // NB: This assumes tMultiplier is either 1 or 2
159 cpu->irqh.processEvents(cpu);
160 cpu->cycles += (SM83_CORE_EXECUTE - cpu->executionState) * t;
161 running = false;
162 } else {
163 cpu->cycles += t * 2;
164 }
165 cpu->executionState = SM83_CORE_FETCH;
166 cpu->instruction(cpu);
167 cpu->cycles += t;
168 return running;
169}
170
171void SM83Tick(struct SM83Core* cpu) {
172 while (cpu->cycles >= cpu->nextEvent) {
173 cpu->irqh.processEvents(cpu);
174 }
175 _SM83TickInternal(cpu);
176}
177
178void SM83Run(struct SM83Core* cpu) {
179 bool running = true;
180 while (running || cpu->executionState != SM83_CORE_FETCH) {
181 if (cpu->cycles < cpu->nextEvent) {
182 running = _SM83TickInternal(cpu) && running;
183 } else {
184 cpu->irqh.processEvents(cpu);
185 running = false;
186 }
187 }
188}