all repos — mgba @ 0e4f64088cea1d1cc4722051433de40cad870aa4

mGBA Game Boy Advance Emulator

src/lr35902/isa-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 "isa-lr35902.h"
  7
  8#include "lr35902/emitter-lr35902.h"
  9#include "lr35902/lr35902.h"
 10
 11#define DEFINE_INSTRUCTION_LR35902(NAME, BODY) \
 12	static void _LR35902Instruction ## NAME (struct LR35902Core* cpu) { \
 13		UNUSED(cpu); \
 14		BODY; \
 15	}
 16
 17DEFINE_INSTRUCTION_LR35902(NOP,);
 18
 19#define DEFINE_CONDITIONAL_ONLY_INSTRUCTION_LR35902(NAME) \
 20	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(C, cpu->f.c) \
 21	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(Z, cpu->f.z) \
 22	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(NC, !cpu->f.c) \
 23	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(NZ, !cpu->f.z)
 24
 25#define DEFINE_CONDITIONAL_INSTRUCTION_LR35902(NAME) \
 26	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(, true) \
 27	DEFINE_CONDITIONAL_ONLY_INSTRUCTION_LR35902(NAME)
 28
 29DEFINE_INSTRUCTION_LR35902(JPFinish,
 30	if (cpu->condition) {
 31		cpu->pc = (cpu->bus << 8) | cpu->index;
 32		cpu->memory.setActiveRegion(cpu, cpu->pc);
 33		cpu->executionState = LR35902_CORE_STALL;
 34	})
 35
 36DEFINE_INSTRUCTION_LR35902(JPDelay,
 37	cpu->executionState = LR35902_CORE_READ_PC;
 38	cpu->instruction = _LR35902InstructionJPFinish;
 39	cpu->index = cpu->bus;)
 40
 41#define DEFINE_JP_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
 42	DEFINE_INSTRUCTION_LR35902(JP ## CONDITION_NAME, \
 43		cpu->executionState = LR35902_CORE_READ_PC; \
 44		cpu->instruction = _LR35902InstructionJPDelay; \
 45		cpu->condition = CONDITION;)
 46
 47DEFINE_CONDITIONAL_INSTRUCTION_LR35902(JP);
 48
 49DEFINE_INSTRUCTION_LR35902(JPHL,
 50	cpu->pc = LR35902ReadHL(cpu);
 51	cpu->memory.setActiveRegion(cpu, cpu->pc);)
 52
 53DEFINE_INSTRUCTION_LR35902(JRFinish,
 54	if (cpu->condition) {
 55		cpu->pc += (int8_t) cpu->bus;
 56		cpu->memory.setActiveRegion(cpu, cpu->pc);
 57		cpu->executionState = LR35902_CORE_STALL;
 58	})
 59
 60#define DEFINE_JR_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
 61	DEFINE_INSTRUCTION_LR35902(JR ## CONDITION_NAME, \
 62		cpu->executionState = LR35902_CORE_READ_PC; \
 63		cpu->instruction = _LR35902InstructionJRFinish; \
 64		cpu->condition = CONDITION;)
 65
 66DEFINE_CONDITIONAL_INSTRUCTION_LR35902(JR);
 67
 68DEFINE_INSTRUCTION_LR35902(CALLUpdateSPL,
 69	--cpu->index;
 70	cpu->bus = cpu->sp;
 71	cpu->sp = cpu->index;
 72	cpu->executionState = LR35902_CORE_MEMORY_STORE;
 73	cpu->instruction = _LR35902InstructionNOP;)
 74
 75DEFINE_INSTRUCTION_LR35902(CALLUpdatePCH,
 76	if (cpu->condition) {
 77		int newPc = (cpu->bus << 8) | cpu->index;
 78		cpu->bus = cpu->pc >> 8;
 79		cpu->index = cpu->sp - 1;
 80		cpu->sp = cpu->pc; // GROSS
 81		cpu->pc = newPc;
 82		cpu->memory.setActiveRegion(cpu, cpu->pc);
 83		cpu->executionState = LR35902_CORE_MEMORY_STORE;
 84		cpu->instruction = _LR35902InstructionCALLUpdateSPL;
 85	})
 86
 87DEFINE_INSTRUCTION_LR35902(CALLUpdatePCL,
 88	cpu->executionState = LR35902_CORE_READ_PC;
 89	cpu->index = cpu->bus;
 90	cpu->instruction = _LR35902InstructionCALLUpdatePCH)
 91
 92#define DEFINE_CALL_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
 93	DEFINE_INSTRUCTION_LR35902(CALL ## CONDITION_NAME, \
 94		cpu->condition = CONDITION; \
 95		cpu->executionState = LR35902_CORE_READ_PC; \
 96		cpu->instruction = _LR35902InstructionCALLUpdatePCL;)
 97
 98DEFINE_CONDITIONAL_INSTRUCTION_LR35902(CALL)
 99
100DEFINE_INSTRUCTION_LR35902(RETFinish,
101	cpu->sp += 2;  /* TODO: Atomic incrementing? */
102	cpu->pc |= cpu->bus << 8;
103	cpu->memory.setActiveRegion(cpu, cpu->pc);
104	cpu->executionState = LR35902_CORE_STALL;)
105
106DEFINE_INSTRUCTION_LR35902(RETUpdateSPL,
107	cpu->index = cpu->sp + 1;
108	cpu->pc = cpu->bus;
109	cpu->executionState = LR35902_CORE_MEMORY_LOAD;
110	cpu->instruction = _LR35902InstructionRETFinish;)
111
112DEFINE_INSTRUCTION_LR35902(RETUpdateSPH,
113	if (cpu->condition) {
114		cpu->index = cpu->sp;
115		cpu->executionState = LR35902_CORE_MEMORY_LOAD;
116		cpu->instruction = _LR35902InstructionRETUpdateSPL;
117	})
118
119#define DEFINE_RET_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \
120	DEFINE_INSTRUCTION_LR35902(RET ## CONDITION_NAME, \
121		cpu->condition = CONDITION; \
122		cpu->executionState = LR35902_CORE_OP2; \
123		cpu->instruction = _LR35902InstructionRETUpdateSPH;)
124
125DEFINE_INSTRUCTION_LR35902(RET,
126	cpu->condition = true;
127	_LR35902InstructionRETUpdateSPH(cpu);)
128
129DEFINE_INSTRUCTION_LR35902(RETI,
130	cpu->condition = true;
131	cpu->irqh.setInterrupts(cpu, true);
132	_LR35902InstructionRETUpdateSPH(cpu);)
133
134DEFINE_CONDITIONAL_ONLY_INSTRUCTION_LR35902(RET)
135
136#define DEFINE_AND_INSTRUCTION_LR35902(NAME, OPERAND) \
137	DEFINE_INSTRUCTION_LR35902(AND ## NAME, \
138		cpu->a &= OPERAND; \
139		cpu->f.z = !cpu->a; \
140		cpu->f.n = 0; \
141		cpu->f.c = 0; \
142		cpu->f.h = 1;)
143
144#define DEFINE_XOR_INSTRUCTION_LR35902(NAME, OPERAND) \
145	DEFINE_INSTRUCTION_LR35902(XOR ## NAME, \
146		cpu->a ^= OPERAND; \
147		cpu->f.z = !cpu->a; \
148		cpu->f.n = 0; \
149		cpu->f.c = 0; \
150		cpu->f.h = 0;)
151
152#define DEFINE_OR_INSTRUCTION_LR35902(NAME, OPERAND) \
153	DEFINE_INSTRUCTION_LR35902(OR ## NAME, \
154		cpu->a |= OPERAND; \
155		cpu->f.z = !cpu->a; \
156		cpu->f.n = 0; \
157		cpu->f.c = 0; \
158		cpu->f.h = 0;)
159
160#define DEFINE_CP_INSTRUCTION_LR35902(NAME, OPERAND) \
161	DEFINE_INSTRUCTION_LR35902(CP ## NAME, \
162		int diff = cpu->a - OPERAND; \
163		cpu->f.n = 1; \
164		cpu->f.z = !(diff & 0xFF); \
165		cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) < 0; \
166		cpu->f.c = diff < 0;)
167
168#define DEFINE_LDB__INSTRUCTION_LR35902(NAME, OPERAND) \
169	DEFINE_INSTRUCTION_LR35902(LDB_ ## NAME, \
170		cpu->b = OPERAND;)
171
172#define DEFINE_LDC__INSTRUCTION_LR35902(NAME, OPERAND) \
173	DEFINE_INSTRUCTION_LR35902(LDC_ ## NAME, \
174		cpu->c = OPERAND;)
175
176#define DEFINE_LDD__INSTRUCTION_LR35902(NAME, OPERAND) \
177	DEFINE_INSTRUCTION_LR35902(LDD_ ## NAME, \
178		cpu->d = OPERAND;)
179
180#define DEFINE_LDE__INSTRUCTION_LR35902(NAME, OPERAND) \
181	DEFINE_INSTRUCTION_LR35902(LDE_ ## NAME, \
182		cpu->e = OPERAND;)
183
184#define DEFINE_LDH__INSTRUCTION_LR35902(NAME, OPERAND) \
185	DEFINE_INSTRUCTION_LR35902(LDH_ ## NAME, \
186		cpu->h = OPERAND;)
187
188#define DEFINE_LDL__INSTRUCTION_LR35902(NAME, OPERAND) \
189	DEFINE_INSTRUCTION_LR35902(LDL_ ## NAME, \
190		cpu->l = OPERAND;)
191
192#define DEFINE_LDHL__INSTRUCTION_LR35902(NAME, OPERAND) \
193	DEFINE_INSTRUCTION_LR35902(LDHL_ ## NAME, \
194		cpu->bus = OPERAND; \
195		cpu->index = LR35902ReadHL(cpu); \
196		cpu->executionState = LR35902_CORE_MEMORY_STORE; \
197		cpu->instruction = _LR35902InstructionNOP;)
198
199#define DEFINE_LDA__INSTRUCTION_LR35902(NAME, OPERAND) \
200	DEFINE_INSTRUCTION_LR35902(LDA_ ## NAME, \
201		cpu->a = OPERAND;)
202
203#define DEFINE_ALU_INSTRUCTION_LR35902_NOHL(NAME) \
204	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(A, cpu->a); \
205	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(B, cpu->b); \
206	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(C, cpu->c); \
207	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(D, cpu->d); \
208	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(E, cpu->e); \
209	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(H, cpu->h); \
210	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(L, cpu->l);
211
212DEFINE_INSTRUCTION_LR35902(LDHL_Bus, \
213	cpu->index = LR35902ReadHL(cpu); \
214	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
215	cpu->instruction = _LR35902InstructionNOP;)
216
217DEFINE_INSTRUCTION_LR35902(LDHL_, \
218	cpu->executionState = LR35902_CORE_READ_PC; \
219	cpu->instruction = _LR35902InstructionLDHL_Bus;)
220
221DEFINE_INSTRUCTION_LR35902(LDHL_SPDelay,
222	int diff = (int8_t) cpu->bus;
223	int sum = cpu->sp + diff;
224	LR35902WriteHL(cpu, sum);
225	cpu->executionState = LR35902_CORE_STALL;
226	cpu->f.z = 0;
227	cpu->f.n = 0;
228	cpu->f.c = (diff & 0xFF) + (cpu->sp & 0xFF) >= 0x100;
229	cpu->f.h = (diff & 0xF) + (cpu->sp & 0xF) >= 0x10;)
230
231DEFINE_INSTRUCTION_LR35902(LDHL_SP,
232	cpu->executionState = LR35902_CORE_READ_PC;
233	cpu->instruction = _LR35902InstructionLDHL_SPDelay;)
234
235DEFINE_INSTRUCTION_LR35902(LDSP_HL,
236	cpu->sp = LR35902ReadHL(cpu);
237	cpu->executionState = LR35902_CORE_STALL;)
238
239#define DEFINE_ALU_INSTRUCTION_LR35902_MEM(NAME, REG) \
240	DEFINE_INSTRUCTION_LR35902(NAME ## REG, \
241		cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
242		cpu->index = LR35902Read ## REG (cpu); \
243		cpu->instruction = _LR35902Instruction ## NAME ## Bus;)
244
245#define DEFINE_ALU_INSTRUCTION_LR35902(NAME) \
246	DEFINE_ ## NAME ## _INSTRUCTION_LR35902(Bus, cpu->bus); \
247	DEFINE_ALU_INSTRUCTION_LR35902_MEM(NAME, HL) \
248	DEFINE_INSTRUCTION_LR35902(NAME, \
249		cpu->executionState = LR35902_CORE_READ_PC; \
250		cpu->instruction = _LR35902Instruction ## NAME ## Bus;) \
251	DEFINE_ALU_INSTRUCTION_LR35902_NOHL(NAME)
252
253DEFINE_ALU_INSTRUCTION_LR35902(AND);
254DEFINE_ALU_INSTRUCTION_LR35902(XOR);
255DEFINE_ALU_INSTRUCTION_LR35902(OR);
256DEFINE_ALU_INSTRUCTION_LR35902(CP);
257
258static void _LR35902InstructionLDB_Bus(struct LR35902Core*);
259static void _LR35902InstructionLDC_Bus(struct LR35902Core*);
260static void _LR35902InstructionLDD_Bus(struct LR35902Core*);
261static void _LR35902InstructionLDE_Bus(struct LR35902Core*);
262static void _LR35902InstructionLDH_Bus(struct LR35902Core*);
263static void _LR35902InstructionLDL_Bus(struct LR35902Core*);
264static void _LR35902InstructionLDHL_Bus(struct LR35902Core*);
265static void _LR35902InstructionLDA_Bus(struct LR35902Core*);
266
267#define DEFINE_ADD_INSTRUCTION_LR35902(NAME, OPERAND) \
268	DEFINE_INSTRUCTION_LR35902(ADD ## NAME, \
269		int diff = cpu->a + OPERAND; \
270		cpu->f.n = 0; \
271		cpu->f.h = (cpu->a & 0xF) + (OPERAND & 0xF) >= 0x10; \
272		cpu->f.c = diff >= 0x100; \
273		cpu->a = diff; \
274		cpu->f.z = !cpu->a;)
275
276#define DEFINE_ADC_INSTRUCTION_LR35902(NAME, OPERAND) \
277	DEFINE_INSTRUCTION_LR35902(ADC ## NAME, \
278		int diff = cpu->a + OPERAND + cpu->f.c; \
279		cpu->f.n = 0; \
280		cpu->f.h = (cpu->a & 0xF) + (OPERAND & 0xF) + cpu->f.c >= 0x10; \
281		cpu->f.c = diff >= 0x100; \
282		cpu->a = diff; \
283		cpu->f.z = !cpu->a;)
284
285#define DEFINE_SUB_INSTRUCTION_LR35902(NAME, OPERAND) \
286	DEFINE_INSTRUCTION_LR35902(SUB ## NAME, \
287		int diff = cpu->a - OPERAND; \
288		cpu->f.n = 1; \
289		cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) < 0; \
290		cpu->f.c = diff < 0; \
291		cpu->a = diff; \
292		cpu->f.z = !cpu->a;)
293
294#define DEFINE_SBC_INSTRUCTION_LR35902(NAME, OPERAND) \
295	DEFINE_INSTRUCTION_LR35902(SBC ## NAME, \
296		int diff = cpu->a - OPERAND - cpu->f.c; \
297		cpu->f.n = 1; \
298		cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) - cpu->f.c < 0; \
299		cpu->f.c = diff < 0; \
300		cpu->a = diff; \
301		cpu->f.z = !cpu->a;)
302
303DEFINE_ALU_INSTRUCTION_LR35902(LDB_);
304DEFINE_ALU_INSTRUCTION_LR35902(LDC_);
305DEFINE_ALU_INSTRUCTION_LR35902(LDD_);
306DEFINE_ALU_INSTRUCTION_LR35902(LDE_);
307DEFINE_ALU_INSTRUCTION_LR35902(LDH_);
308DEFINE_ALU_INSTRUCTION_LR35902(LDL_);
309DEFINE_ALU_INSTRUCTION_LR35902_NOHL(LDHL_);
310DEFINE_ALU_INSTRUCTION_LR35902(LDA_);
311DEFINE_ALU_INSTRUCTION_LR35902_MEM(LDA_, BC);
312DEFINE_ALU_INSTRUCTION_LR35902_MEM(LDA_, DE);
313DEFINE_ALU_INSTRUCTION_LR35902(ADD);
314DEFINE_ALU_INSTRUCTION_LR35902(ADC);
315DEFINE_ALU_INSTRUCTION_LR35902(SUB);
316DEFINE_ALU_INSTRUCTION_LR35902(SBC);
317
318DEFINE_INSTRUCTION_LR35902(ADDSPFinish,
319	cpu->sp = cpu->index;
320	cpu->executionState = LR35902_CORE_STALL;)
321
322DEFINE_INSTRUCTION_LR35902(ADDSPDelay,
323	int diff = (int8_t) cpu->bus;
324	int sum = cpu->sp + diff;
325	cpu->index = sum;
326	cpu->executionState = LR35902_CORE_OP2;
327	cpu->instruction = _LR35902InstructionADDSPFinish;
328	cpu->f.z = 0;
329	cpu->f.n = 0;
330	cpu->f.c = (diff & 0xFF) + (cpu->sp & 0xFF) >= 0x100;
331	cpu->f.h = (diff & 0xF) + (cpu->sp & 0xF) >= 0x10;)
332
333DEFINE_INSTRUCTION_LR35902(ADDSP,
334	cpu->executionState = LR35902_CORE_READ_PC;
335	cpu->instruction = _LR35902InstructionADDSPDelay;)
336
337DEFINE_INSTRUCTION_LR35902(LDBCDelay, \
338	cpu->c = cpu->bus; \
339	cpu->executionState = LR35902_CORE_READ_PC; \
340	cpu->instruction = _LR35902InstructionLDB_Bus;)
341
342DEFINE_INSTRUCTION_LR35902(LDBC, \
343	cpu->executionState = LR35902_CORE_READ_PC; \
344	cpu->instruction = _LR35902InstructionLDBCDelay;)
345
346DEFINE_INSTRUCTION_LR35902(LDBC_A, \
347	cpu->index = LR35902ReadBC(cpu); \
348	cpu->bus = cpu->a; \
349	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
350	cpu->instruction = _LR35902InstructionNOP;)
351
352DEFINE_INSTRUCTION_LR35902(LDDEDelay, \
353	cpu->e = cpu->bus; \
354	cpu->executionState = LR35902_CORE_READ_PC; \
355	cpu->instruction = _LR35902InstructionLDD_Bus;)
356
357DEFINE_INSTRUCTION_LR35902(LDDE, \
358	cpu->executionState = LR35902_CORE_READ_PC; \
359	cpu->instruction = _LR35902InstructionLDDEDelay;)
360
361DEFINE_INSTRUCTION_LR35902(LDDE_A, \
362	cpu->index = LR35902ReadDE(cpu); \
363	cpu->bus = cpu->a; \
364	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
365	cpu->instruction = _LR35902InstructionNOP;)
366
367DEFINE_INSTRUCTION_LR35902(LDHLDelay, \
368	cpu->l = cpu->bus; \
369	cpu->executionState = LR35902_CORE_READ_PC; \
370	cpu->instruction = _LR35902InstructionLDH_Bus;)
371
372DEFINE_INSTRUCTION_LR35902(LDHL, \
373	cpu->executionState = LR35902_CORE_READ_PC; \
374	cpu->instruction = _LR35902InstructionLDHLDelay;)
375
376DEFINE_INSTRUCTION_LR35902(LDSPFinish, cpu->sp |= cpu->bus << 8;)
377
378DEFINE_INSTRUCTION_LR35902(LDSPDelay, \
379	cpu->sp = cpu->bus; \
380	cpu->executionState = LR35902_CORE_READ_PC; \
381	cpu->instruction = _LR35902InstructionLDSPFinish;)
382
383DEFINE_INSTRUCTION_LR35902(LDSP, \
384	cpu->executionState = LR35902_CORE_READ_PC; \
385	cpu->instruction = _LR35902InstructionLDSPDelay;)
386
387DEFINE_INSTRUCTION_LR35902(LDIHLA, \
388	cpu->index = LR35902ReadHL(cpu); \
389	LR35902WriteHL(cpu, cpu->index + 1); \
390	cpu->bus = cpu->a; \
391	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
392	cpu->instruction = _LR35902InstructionNOP;)
393
394DEFINE_INSTRUCTION_LR35902(LDDHLA, \
395	cpu->index = LR35902ReadHL(cpu); \
396	LR35902WriteHL(cpu, cpu->index - 1); \
397	cpu->bus = cpu->a; \
398	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
399	cpu->instruction = _LR35902InstructionNOP;)
400
401DEFINE_INSTRUCTION_LR35902(LDA_IHL, \
402	cpu->index = LR35902ReadHL(cpu); \
403	LR35902WriteHL(cpu, cpu->index + 1); \
404	cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
405	cpu->instruction = _LR35902InstructionLDA_Bus;)
406
407DEFINE_INSTRUCTION_LR35902(LDA_DHL, \
408	cpu->index = LR35902ReadHL(cpu); \
409	LR35902WriteHL(cpu, cpu->index - 1); \
410	cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
411	cpu->instruction = _LR35902InstructionLDA_Bus;)
412
413DEFINE_INSTRUCTION_LR35902(LDIAFinish, \
414	cpu->index |= cpu->bus << 8;
415	cpu->bus = cpu->a; \
416	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
417	cpu->instruction = _LR35902InstructionNOP;)
418
419DEFINE_INSTRUCTION_LR35902(LDIADelay, \
420	cpu->index = cpu->bus;
421	cpu->executionState = LR35902_CORE_READ_PC; \
422	cpu->instruction = _LR35902InstructionLDIAFinish;)
423
424DEFINE_INSTRUCTION_LR35902(LDIA, \
425	cpu->executionState = LR35902_CORE_READ_PC; \
426	cpu->instruction = _LR35902InstructionLDIADelay;)
427
428DEFINE_INSTRUCTION_LR35902(LDAIFinish, \
429	cpu->index |= cpu->bus << 8;
430	cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
431	cpu->instruction = _LR35902InstructionLDA_Bus;)
432
433DEFINE_INSTRUCTION_LR35902(LDAIDelay, \
434	cpu->index = cpu->bus;
435	cpu->executionState = LR35902_CORE_READ_PC; \
436	cpu->instruction = _LR35902InstructionLDAIFinish;)
437
438DEFINE_INSTRUCTION_LR35902(LDAI, \
439	cpu->executionState = LR35902_CORE_READ_PC; \
440	cpu->instruction = _LR35902InstructionLDAIDelay;)
441
442DEFINE_INSTRUCTION_LR35902(LDAIOC, \
443	cpu->index = 0xFF00 | cpu->c; \
444	cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
445	cpu->instruction = _LR35902InstructionLDA_Bus;)
446
447DEFINE_INSTRUCTION_LR35902(LDIOCA, \
448	cpu->index = 0xFF00 | cpu->c; \
449	cpu->bus = cpu->a; \
450	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
451	cpu->instruction = _LR35902InstructionNOP;)
452
453DEFINE_INSTRUCTION_LR35902(LDAIODelay, \
454	cpu->index = 0xFF00 | cpu->bus; \
455	cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
456	cpu->instruction = _LR35902InstructionLDA_Bus;)
457
458DEFINE_INSTRUCTION_LR35902(LDAIO, \
459	cpu->executionState = LR35902_CORE_READ_PC; \
460	cpu->instruction = _LR35902InstructionLDAIODelay;)
461
462DEFINE_INSTRUCTION_LR35902(LDIOADelay, \
463	cpu->index = 0xFF00 | cpu->bus; \
464	cpu->bus = cpu->a; \
465	cpu->executionState = LR35902_CORE_MEMORY_STORE; \
466	cpu->instruction = _LR35902InstructionNOP;)
467
468DEFINE_INSTRUCTION_LR35902(LDIOA, \
469	cpu->executionState = LR35902_CORE_READ_PC; \
470	cpu->instruction = _LR35902InstructionLDIOADelay;)
471
472DEFINE_INSTRUCTION_LR35902(LDISPStoreH,
473	++cpu->index;
474	cpu->bus = cpu->sp >> 8;
475	cpu->executionState = LR35902_CORE_MEMORY_STORE;
476	cpu->instruction = _LR35902InstructionNOP;)
477
478DEFINE_INSTRUCTION_LR35902(LDISPStoreL,
479	cpu->index |= cpu->bus << 8;
480	cpu->bus = cpu->sp;
481	cpu->executionState = LR35902_CORE_MEMORY_STORE;
482	cpu->instruction = _LR35902InstructionLDISPStoreH;)
483
484DEFINE_INSTRUCTION_LR35902(LDISPReadAddr,
485	cpu->index = cpu->bus;
486	cpu->executionState = LR35902_CORE_READ_PC;
487	cpu->instruction = _LR35902InstructionLDISPStoreL;)
488
489DEFINE_INSTRUCTION_LR35902(LDISP,
490	cpu->executionState = LR35902_CORE_READ_PC;
491	cpu->instruction = _LR35902InstructionLDISPReadAddr;)
492
493#define DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(REG) \
494	DEFINE_INSTRUCTION_LR35902(INC ## REG, \
495		uint16_t reg = LR35902Read ## REG (cpu); \
496		LR35902Write ## REG (cpu, reg + 1); \
497		cpu->executionState = LR35902_CORE_STALL;) \
498	DEFINE_INSTRUCTION_LR35902(DEC ## REG, \
499		uint16_t reg = LR35902Read ## REG (cpu); \
500		LR35902Write ## REG (cpu, reg - 1); \
501		cpu->executionState = LR35902_CORE_STALL;)
502
503DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(BC);
504DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(DE);
505DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(HL);
506
507#define DEFINE_ADD_HL_INSTRUCTION_LR35902(REG, L, H) \
508	DEFINE_INSTRUCTION_LR35902(ADDHL_ ## REG ## Finish, \
509		int diff = H + cpu->h + cpu->f.c; \
510		cpu->f.n = 0; \
511		cpu->f.h = (H & 0xF) + (cpu->h & 0xF) + cpu->f.c >= 0x10; \
512		cpu->f.c = diff >= 0x100; \
513		cpu->h = diff;) \
514	DEFINE_INSTRUCTION_LR35902(ADDHL_ ## REG, \
515		int diff = L + cpu->l; \
516		cpu->l = diff; \
517		cpu->f.c = diff >= 0x100; \
518		cpu->executionState = LR35902_CORE_OP2; \
519		cpu->instruction = _LR35902InstructionADDHL_ ## REG ## Finish;)
520
521DEFINE_ADD_HL_INSTRUCTION_LR35902(BC, cpu->c, cpu->b);
522DEFINE_ADD_HL_INSTRUCTION_LR35902(DE, cpu->e, cpu->d);
523DEFINE_ADD_HL_INSTRUCTION_LR35902(HL, cpu->l, cpu->h);
524DEFINE_ADD_HL_INSTRUCTION_LR35902(SP, (cpu->sp & 0xFF), (cpu->sp >> 8));
525
526
527#define DEFINE_INC_INSTRUCTION_LR35902(NAME, OPERAND) \
528	DEFINE_INSTRUCTION_LR35902(INC ## NAME, \
529		int diff = OPERAND + 1; \
530		cpu->f.h = (OPERAND & 0xF) == 0xF; \
531		OPERAND = diff; \
532		cpu->f.n = 0; \
533		cpu->f.z = !OPERAND;)
534
535#define DEFINE_DEC_INSTRUCTION_LR35902(NAME, OPERAND) \
536	DEFINE_INSTRUCTION_LR35902(DEC ## NAME, \
537		int diff = OPERAND - 1; \
538		cpu->f.h = (OPERAND & 0xF) == 0x0; \
539		OPERAND = diff; \
540		cpu->f.n = 1; \
541		cpu->f.z = !OPERAND;)
542
543DEFINE_ALU_INSTRUCTION_LR35902_NOHL(INC);
544DEFINE_ALU_INSTRUCTION_LR35902_NOHL(DEC);
545
546DEFINE_INSTRUCTION_LR35902(INC_HLDelay,
547	int diff = cpu->bus + 1;
548	cpu->f.n = 0;
549	cpu->f.h = (cpu->bus & 0xF) == 0xF;
550	cpu->bus = diff;
551	cpu->f.z = !cpu->bus;
552	cpu->instruction = _LR35902InstructionNOP;
553	cpu->executionState = LR35902_CORE_MEMORY_STORE;)
554
555DEFINE_INSTRUCTION_LR35902(INC_HL,
556	cpu->index = LR35902ReadHL(cpu);
557	cpu->instruction = _LR35902InstructionINC_HLDelay;
558	cpu->executionState = LR35902_CORE_MEMORY_LOAD;)
559
560DEFINE_INSTRUCTION_LR35902(DEC_HLDelay,
561	int diff = cpu->bus - 1;
562	cpu->f.n = 1;
563	cpu->f.h = (cpu->bus & 0xF) == 0;
564	cpu->bus = diff;
565	cpu->f.z = !cpu->bus;
566	cpu->instruction = _LR35902InstructionNOP;
567	cpu->executionState = LR35902_CORE_MEMORY_STORE;)
568
569DEFINE_INSTRUCTION_LR35902(DEC_HL,
570	cpu->index = LR35902ReadHL(cpu);
571	cpu->instruction = _LR35902InstructionDEC_HLDelay;
572	cpu->executionState = LR35902_CORE_MEMORY_LOAD;)
573
574DEFINE_INSTRUCTION_LR35902(INCSP,
575	++cpu->sp;
576	cpu->executionState = LR35902_CORE_STALL;)
577
578DEFINE_INSTRUCTION_LR35902(DECSP,
579	--cpu->sp;
580	cpu->executionState = LR35902_CORE_STALL;)
581
582DEFINE_INSTRUCTION_LR35902(SCF,
583	cpu->f.c = 1;
584	cpu->f.h = 0;
585	cpu->f.n = 0;)
586
587DEFINE_INSTRUCTION_LR35902(CCF,
588	cpu->f.c ^= 1;
589	cpu->f.h = 0;
590	cpu->f.n = 0;)
591
592DEFINE_INSTRUCTION_LR35902(CPL_,
593	cpu->a ^= 0xFF;
594	cpu->f.h = 1;
595	cpu->f.n = 1;)
596
597DEFINE_INSTRUCTION_LR35902(DAA,
598	if (cpu->f.n) {
599		if (cpu->f.h) {
600			cpu->a += 0xFA;
601		}
602		if (cpu->f.c) {
603			cpu->a += 0xA0;
604		}
605	} else {
606		int a = cpu->a;
607		if ((cpu->a & 0xF) > 0x9 || cpu->f.h) {
608			a += 0x6;
609		}
610		if ((a & 0x1F0) > 0x90 || cpu->f.c) {
611			a += 0x60;
612			cpu->f.c = 1;
613		} else {
614			cpu->f.c = 0;
615		}
616		cpu->a = a;
617	}
618	cpu->f.h = 0;
619	cpu->f.z = !cpu->a;)
620
621#define DEFINE_POPPUSH_INSTRUCTION_LR35902(REG, HH, H, L) \
622	DEFINE_INSTRUCTION_LR35902(POP ## REG ## Delay, \
623		cpu-> L = cpu->bus; \
624		cpu->f.packed &= 0xF0; \
625		cpu->index = cpu->sp; \
626		++cpu->sp; \
627		cpu->instruction = _LR35902InstructionLD ## HH ## _Bus; \
628		cpu->executionState = LR35902_CORE_MEMORY_LOAD;) \
629	DEFINE_INSTRUCTION_LR35902(POP ## REG, \
630		cpu->index = cpu->sp; \
631		++cpu->sp; \
632		cpu->instruction = _LR35902InstructionPOP ## REG ## Delay; \
633		cpu->executionState = LR35902_CORE_MEMORY_LOAD;) \
634	DEFINE_INSTRUCTION_LR35902(PUSH ## REG ## Finish, \
635		cpu->executionState = LR35902_CORE_STALL;) \
636	DEFINE_INSTRUCTION_LR35902(PUSH ## REG ## Delay, \
637		--cpu->sp; \
638		cpu->index = cpu->sp; \
639		cpu->bus = cpu-> L; \
640		cpu->instruction = _LR35902InstructionPUSH ## REG ## Finish; \
641		cpu->executionState = LR35902_CORE_MEMORY_STORE;) \
642	DEFINE_INSTRUCTION_LR35902(PUSH ## REG, \
643		--cpu->sp; \
644		cpu->index = cpu->sp; \
645		cpu->bus = cpu-> H; \
646		cpu->instruction = _LR35902InstructionPUSH ## REG ## Delay; \
647		cpu->executionState = LR35902_CORE_MEMORY_STORE;)
648
649DEFINE_POPPUSH_INSTRUCTION_LR35902(BC, B, b, c);
650DEFINE_POPPUSH_INSTRUCTION_LR35902(DE, D, d, e);
651DEFINE_POPPUSH_INSTRUCTION_LR35902(HL, H, h, l);
652DEFINE_POPPUSH_INSTRUCTION_LR35902(AF, A, a, f.packed);
653
654#define DEFINE_CB_2_INSTRUCTION_LR35902(NAME, WB, BODY) \
655	DEFINE_INSTRUCTION_LR35902(NAME ## B, uint8_t reg = cpu->b; BODY; cpu->b = reg) \
656	DEFINE_INSTRUCTION_LR35902(NAME ## C, uint8_t reg = cpu->c; BODY; cpu->c = reg) \
657	DEFINE_INSTRUCTION_LR35902(NAME ## D, uint8_t reg = cpu->d; BODY; cpu->d = reg) \
658	DEFINE_INSTRUCTION_LR35902(NAME ## E, uint8_t reg = cpu->e; BODY; cpu->e = reg) \
659	DEFINE_INSTRUCTION_LR35902(NAME ## H, uint8_t reg = cpu->h; BODY; cpu->h = reg) \
660	DEFINE_INSTRUCTION_LR35902(NAME ## L, uint8_t reg = cpu->l; BODY; cpu->l = reg) \
661	DEFINE_INSTRUCTION_LR35902(NAME ## HLDelay, \
662		uint8_t reg = cpu->bus; \
663		BODY; \
664		cpu->bus = reg; \
665		cpu->executionState = WB; \
666		cpu->instruction = _LR35902InstructionNOP;) \
667	DEFINE_INSTRUCTION_LR35902(NAME ## HL, \
668		cpu->index = LR35902ReadHL(cpu); \
669		cpu->executionState = LR35902_CORE_MEMORY_LOAD; \
670		cpu->instruction = _LR35902Instruction ## NAME ## HLDelay;) \
671	DEFINE_INSTRUCTION_LR35902(NAME ## A, uint8_t reg = cpu->a; BODY; cpu->a = reg)
672
673#define DEFINE_CB_INSTRUCTION_LR35902(NAME, WB, BODY) \
674	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 0, WB, uint8_t bit = 1; BODY) \
675	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 1, WB, uint8_t bit = 2; BODY) \
676	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 2, WB, uint8_t bit = 4; BODY) \
677	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 3, WB, uint8_t bit = 8; BODY) \
678	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 4, WB, uint8_t bit = 16; BODY) \
679	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 5, WB, uint8_t bit = 32; BODY) \
680	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 6, WB, uint8_t bit = 64; BODY) \
681	DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 7, WB, uint8_t bit = 128; BODY)
682
683DEFINE_CB_INSTRUCTION_LR35902(BIT, LR35902_CORE_FETCH, cpu->f.n = 0; cpu->f.h = 1; cpu->f.z = !(reg & bit))
684DEFINE_CB_INSTRUCTION_LR35902(RES, LR35902_CORE_MEMORY_STORE, reg &= ~bit)
685DEFINE_CB_INSTRUCTION_LR35902(SET, LR35902_CORE_MEMORY_STORE, reg |= bit)
686
687#define DEFINE_CB_ALU_INSTRUCTION_LR35902(NAME, BODY) \
688	DEFINE_CB_2_INSTRUCTION_LR35902(NAME, LR35902_CORE_MEMORY_STORE, \
689		BODY; \
690		cpu->f.n = 0; \
691		cpu->f.h = 0; \
692		cpu->f.z = !reg;)
693
694DEFINE_CB_ALU_INSTRUCTION_LR35902(RL, int wide = (reg << 1) | cpu->f.c; reg = wide; cpu->f.c = wide >> 8)
695DEFINE_CB_ALU_INSTRUCTION_LR35902(RLC, reg = (reg << 1) | (reg >> 7); cpu->f.c = reg & 1)
696DEFINE_CB_ALU_INSTRUCTION_LR35902(RR, int low = reg & 1; reg = (reg >> 1) | (cpu->f.c << 7); cpu->f.c = low)
697DEFINE_CB_ALU_INSTRUCTION_LR35902(RRC, int low = reg & 1; reg = (reg >> 1) | (low << 7); cpu->f.c = low)
698DEFINE_CB_ALU_INSTRUCTION_LR35902(SLA, cpu->f.c = reg >> 7; reg <<= 1)
699DEFINE_CB_ALU_INSTRUCTION_LR35902(SRA, cpu->f.c = reg & 1; reg = ((int8_t) reg) >> 1)
700DEFINE_CB_ALU_INSTRUCTION_LR35902(SRL, cpu->f.c = reg & 1; reg >>= 1)
701DEFINE_CB_ALU_INSTRUCTION_LR35902(SWAP, reg = (reg << 4) | (reg >> 4); cpu->f.c = 0)
702
703DEFINE_INSTRUCTION_LR35902(RLA_,
704	int wide = (cpu->a << 1) | cpu->f.c;
705	cpu->a = wide;
706	cpu->f.z = 0;
707	cpu->f.h = 0;
708	cpu->f.n = 0;
709	cpu->f.c = wide >> 8;)
710
711DEFINE_INSTRUCTION_LR35902(RLCA_,
712	cpu->a = (cpu->a << 1) | (cpu->a >> 7);
713	cpu->f.z = 0;
714	cpu->f.h = 0;
715	cpu->f.n = 0;
716	cpu->f.c = cpu->a & 1;)
717
718DEFINE_INSTRUCTION_LR35902(RRA_,
719	int low = cpu->a & 1;
720	cpu->a = (cpu->a >> 1) | (cpu->f.c << 7);
721	cpu->f.z = 0;
722	cpu->f.h = 0;
723	cpu->f.n = 0;
724	cpu->f.c = low;)
725
726DEFINE_INSTRUCTION_LR35902(RRCA_,
727	int low = cpu->a & 1;
728	cpu->a = (cpu->a >> 1) | (low << 7);
729	cpu->f.z = 0;
730	cpu->f.h = 0;
731	cpu->f.n = 0;
732	cpu->f.c = low;)
733
734DEFINE_INSTRUCTION_LR35902(DI, cpu->irqh.setInterrupts(cpu, false));
735DEFINE_INSTRUCTION_LR35902(EI, cpu->irqh.setInterrupts(cpu, true));
736DEFINE_INSTRUCTION_LR35902(HALT, cpu->irqh.halt(cpu));
737
738#define DEFINE_RST_INSTRUCTION_LR35902(VEC) \
739	DEFINE_INSTRUCTION_LR35902(RST ## VEC ## UpdateSPL, \
740		cpu->pc = 0x ## VEC; \
741		cpu->executionState = LR35902_CORE_STALL;) \
742	DEFINE_INSTRUCTION_LR35902(RST ## VEC ## UpdateSPH, \
743		cpu->index = cpu->sp + 1; \
744		cpu->bus = cpu->pc >> 8; \
745		cpu->executionState = LR35902_CORE_MEMORY_STORE; \
746		cpu->instruction = _LR35902InstructionRST ## VEC ## UpdateSPL;) \
747	DEFINE_INSTRUCTION_LR35902(RST ## VEC, \
748		cpu->sp -= 2; /* TODO: Atomic incrementing? */ \
749		cpu->index = cpu->sp; \
750		cpu->bus = cpu->pc; \
751		cpu->executionState = LR35902_CORE_MEMORY_STORE; \
752		cpu->instruction = _LR35902InstructionRST ## VEC ## UpdateSPH;)
753
754DEFINE_RST_INSTRUCTION_LR35902(00);
755DEFINE_RST_INSTRUCTION_LR35902(08);
756DEFINE_RST_INSTRUCTION_LR35902(10);
757DEFINE_RST_INSTRUCTION_LR35902(18);
758DEFINE_RST_INSTRUCTION_LR35902(20);
759DEFINE_RST_INSTRUCTION_LR35902(28);
760DEFINE_RST_INSTRUCTION_LR35902(30);
761DEFINE_RST_INSTRUCTION_LR35902(38);
762
763DEFINE_INSTRUCTION_LR35902(ILL, cpu->irqh.hitIllegal(cpu));
764DEFINE_INSTRUCTION_LR35902(STUB, cpu->irqh.hitStub(cpu));
765
766static const LR35902Instruction _lr35902CBInstructionTable[0x100] = {
767	DECLARE_LR35902_CB_EMITTER_BLOCK(_LR35902Instruction)
768};
769
770DEFINE_INSTRUCTION_LR35902(CBDelegate, _lr35902CBInstructionTable[cpu->bus](cpu))
771
772DEFINE_INSTRUCTION_LR35902(CB, \
773	cpu->executionState = LR35902_CORE_READ_PC; \
774	cpu->instruction = _LR35902InstructionCBDelegate;)
775
776const LR35902Instruction _lr35902InstructionTable[0x100] = {
777	DECLARE_LR35902_EMITTER_BLOCK(_LR35902Instruction)
778};