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 "lr35902.h"
7
8#include "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, uint8_t vector) {
74 cpu->irqPending = true;
75 cpu->irqVector = vector;
76}
77
78static void _LR35902InstructionIRQStall(struct LR35902Core* cpu) {
79 cpu->executionState = LR35902_CORE_STALL;
80}
81
82static void _LR35902InstructionIRQFinish(struct LR35902Core* cpu) {
83 cpu->executionState = LR35902_CORE_OP2;
84 cpu->instruction = _LR35902InstructionIRQStall;
85}
86
87static void _LR35902InstructionIRQDelay(struct LR35902Core* cpu) {
88 cpu->index = cpu->sp + 1;
89 cpu->bus = cpu->pc >> 8;
90 cpu->executionState = LR35902_CORE_MEMORY_STORE;
91 cpu->instruction = _LR35902InstructionIRQFinish;
92 cpu->pc = cpu->irqVector;
93 cpu->memory.setActiveRegion(cpu, cpu->pc);
94}
95
96static void _LR35902InstructionIRQ(struct LR35902Core* cpu) {
97 cpu->sp -= 2; /* TODO: Atomic incrementing? */
98 cpu->index = cpu->sp;
99 cpu->bus = cpu->pc;
100 cpu->executionState = LR35902_CORE_MEMORY_STORE;
101 cpu->instruction = _LR35902InstructionIRQDelay;
102 cpu->irqh.setInterrupts(cpu, false);
103}
104
105static void _LR35902Step(struct LR35902Core* cpu) {
106 ++cpu->cycles;
107 enum LR35902ExecutionState state = cpu->executionState;
108 ++cpu->executionState;
109 cpu->executionState &= 3;
110 switch (state) {
111 case LR35902_CORE_FETCH:
112 if (cpu->irqPending) {
113 cpu->index = cpu->sp;
114 cpu->irqPending = false;
115 cpu->instruction = _LR35902InstructionIRQ;
116 break;
117 }
118 cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc);
119 cpu->instruction = _lr35902InstructionTable[cpu->bus];
120 ++cpu->pc;
121 break;
122 case LR35902_CORE_EXECUTE:
123 cpu->instruction(cpu);
124 break;
125 case LR35902_CORE_MEMORY_LOAD:
126 cpu->bus = cpu->memory.load8(cpu, cpu->index);
127 break;
128 case LR35902_CORE_MEMORY_STORE:
129 cpu->memory.store8(cpu, cpu->index, cpu->bus);
130 break;
131 case LR35902_CORE_READ_PC:
132 cpu->bus = cpu->memory.load8(cpu, cpu->pc);
133 ++cpu->pc;
134 break;
135 case LR35902_CORE_STALL:
136 cpu->instruction = _lr35902InstructionTable[0]; // NOP
137 break;
138 default:
139 break;
140 }
141}
142
143void LR35902Tick(struct LR35902Core* cpu) {
144 _LR35902Step(cpu);
145 if (cpu->cycles >= cpu->nextEvent) {
146 cpu->irqh.processEvents(cpu);
147 }
148}
149
150void LR35902Run(struct LR35902Core* cpu) {
151 while (true) {
152 _LR35902Step(cpu);
153 if (cpu->cycles >= cpu->nextEvent) {
154 break;
155 } else if (cpu->executionState < LR35902_CORE_EXECUTE) {
156 // Silly hack: keep us from calling step if we know the next step is a no-op
157 ++cpu->cycles;
158 ++cpu->executionState;
159 }
160 }
161 cpu->irqh.processEvents(cpu);
162}