all repos — mgba @ 5cd21c67986f15cb079acd9c022f173f01ec680d

mGBA Game Boy Advance Emulator

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			cpu->irqh.processEvents(cpu);
183			break;
184		}
185		running = _SM83TickInternal(cpu) && running;
186	}
187}