all repos — mgba @ b6f863be26089bf01fd8cc7277e2cee360556549

mGBA Game Boy Advance Emulator

src/lr35902/lr35902.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/lr35902/lr35902.h>
  7
  8#include <mgba/internal/lr35902/isa-lr35902.h>
  9
 10void LR35902Init(struct LR35902Core* 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 LR35902Deinit(struct LR35902Core* 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 LR35902SetComponents(struct LR35902Core* 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 LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot) {
 40	if (slot >= cpu->numComponents) {
 41		return;
 42	}
 43	cpu->components[slot]->init(cpu, cpu->components[slot]);
 44}
 45
 46void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot) {
 47	if (slot >= cpu->numComponents) {
 48		return;
 49	}
 50	cpu->components[slot]->deinit(cpu->components[slot]);
 51}
 52
 53void LR35902Reset(struct LR35902Core* 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->cycles = 0;
 65	cpu->nextEvent = 0;
 66	cpu->executionState = LR35902_CORE_FETCH;
 67	cpu->halted = 0;
 68
 69	cpu->irqPending = false;
 70	cpu->irqh.reset(cpu);
 71}
 72
 73void LR35902RaiseIRQ(struct LR35902Core* cpu) {
 74	cpu->irqPending = true;
 75}
 76
 77static void _LR35902InstructionIRQStall(struct LR35902Core* cpu) {
 78	cpu->executionState = LR35902_CORE_STALL;
 79}
 80
 81static void _LR35902InstructionIRQFinish(struct LR35902Core* cpu) {
 82	cpu->executionState = LR35902_CORE_OP2;
 83	cpu->instruction = _LR35902InstructionIRQStall;
 84}
 85
 86static void _LR35902InstructionIRQDelay(struct LR35902Core* cpu) {
 87	--cpu->sp;
 88	cpu->index = cpu->sp;
 89	cpu->bus = cpu->pc;
 90	cpu->executionState = LR35902_CORE_MEMORY_STORE;
 91	cpu->instruction = _LR35902InstructionIRQFinish;
 92	cpu->pc = cpu->irqh.irqVector(cpu);
 93	cpu->memory.setActiveRegion(cpu, cpu->pc);
 94}
 95
 96static void _LR35902InstructionIRQ(struct LR35902Core* cpu) {
 97	--cpu->sp;
 98	cpu->index = cpu->sp;
 99	cpu->bus = cpu->pc >> 8;
100	cpu->executionState = LR35902_CORE_MEMORY_STORE;
101	cpu->instruction = _LR35902InstructionIRQDelay;
102}
103
104static void _LR35902Step(struct LR35902Core* cpu) {
105	++cpu->cycles;
106	enum LR35902ExecutionState state = cpu->executionState;
107	cpu->executionState = LR35902_CORE_IDLE_0;
108	switch (state) {
109	case LR35902_CORE_FETCH:
110		if (cpu->irqPending) {
111			cpu->index = cpu->sp;
112			cpu->irqPending = false;
113			cpu->instruction = _LR35902InstructionIRQ;
114			cpu->irqh.setInterrupts(cpu, false);
115			break;
116		}
117		cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc);
118		cpu->instruction = _lr35902InstructionTable[cpu->bus];
119		++cpu->pc;
120		break;
121	case LR35902_CORE_MEMORY_LOAD:
122		cpu->bus = cpu->memory.load8(cpu, cpu->index);
123		break;
124	case LR35902_CORE_MEMORY_STORE:
125		cpu->memory.store8(cpu, cpu->index, cpu->bus);
126		break;
127	case LR35902_CORE_READ_PC:
128		cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc);
129		++cpu->pc;
130		break;
131	case LR35902_CORE_STALL:
132		cpu->instruction = _lr35902InstructionTable[0]; // NOP
133		break;
134	default:
135		break;
136	}
137}
138
139void LR35902Tick(struct LR35902Core* cpu) {
140	while (cpu->cycles >= cpu->nextEvent) {
141		cpu->irqh.processEvents(cpu);
142	}
143	_LR35902Step(cpu);
144	if (cpu->cycles + 2 >= cpu->nextEvent) {
145		int32_t diff = cpu->nextEvent - cpu->cycles;
146		cpu->cycles = cpu->nextEvent;
147		cpu->executionState += diff;
148		cpu->irqh.processEvents(cpu);
149		cpu->cycles += LR35902_CORE_EXECUTE - cpu->executionState;
150	} else {
151		cpu->cycles += 2;
152	}
153	cpu->executionState = LR35902_CORE_FETCH;
154	cpu->instruction(cpu);
155	++cpu->cycles;
156}
157
158void LR35902Run(struct LR35902Core* cpu) {
159	bool running = true;
160	while (running || cpu->executionState != LR35902_CORE_FETCH) {
161		if (cpu->cycles >= cpu->nextEvent) {
162			cpu->irqh.processEvents(cpu);
163			break;
164		}
165		_LR35902Step(cpu);
166		if (cpu->cycles + 2 >= cpu->nextEvent) {
167			int32_t diff = cpu->nextEvent - cpu->cycles;
168			cpu->cycles = cpu->nextEvent;
169			cpu->executionState += diff;
170			cpu->irqh.processEvents(cpu);
171			cpu->cycles += LR35902_CORE_EXECUTE - cpu->executionState;
172			running = false;
173		} else {
174			cpu->cycles += 2;
175		}
176		cpu->executionState = LR35902_CORE_FETCH;
177		cpu->instruction(cpu);
178		++cpu->cycles;
179	}
180}