all repos — mgba @ 939c3495337773f6f29019256981e4aedb8ec869

mGBA Game Boy Advance Emulator

src/arm/isa-thumb.c (view raw)

  1#include "isa-thumb.h"
  2
  3#include "isa-inlines.h"
  4#include "emitter-thumb.h"
  5
  6// Instruction definitions
  7// Beware pre-processor insanity
  8
  9#define THUMB_ADDITION_S(M, N, D) \
 10	cpu->cpsr.n = ARM_SIGN(D); \
 11	cpu->cpsr.z = !(D); \
 12	cpu->cpsr.c = ARM_CARRY_FROM(M, N, D); \
 13	cpu->cpsr.v = ARM_V_ADDITION(M, N, D);
 14
 15#define THUMB_SUBTRACTION_S(M, N, D) \
 16	cpu->cpsr.n = ARM_SIGN(D); \
 17	cpu->cpsr.z = !(D); \
 18	cpu->cpsr.c = ARM_BORROW_FROM(M, N, D); \
 19	cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D);
 20
 21#define THUMB_NEUTRAL_S(M, N, D) \
 22	cpu->cpsr.n = ARM_SIGN(D); \
 23	cpu->cpsr.z = !(D);
 24
 25#define THUMB_ADDITION(D, M, N) \
 26	int n = N; \
 27	int m = M; \
 28	D = M + N; \
 29	THUMB_ADDITION_S(m, n, D)
 30
 31#define THUMB_SUBTRACTION(D, M, N) \
 32	int n = N; \
 33	int m = M; \
 34	D = M - N; \
 35	THUMB_SUBTRACTION_S(m, n, D)
 36
 37#define THUMB_PREFETCH_CYCLES (1 + cpu->memory.activeSeqCycles16)
 38
 39#define THUMB_STORE_POST_BODY \
 40	currentCycles += cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16;
 41
 42#define DEFINE_INSTRUCTION_THUMB(NAME, BODY) \
 43	static void _ThumbInstruction ## NAME (struct ARMCore* cpu, uint16_t opcode) {  \
 44		int currentCycles = THUMB_PREFETCH_CYCLES; \
 45		BODY; \
 46		cpu->cycles += currentCycles; \
 47	}
 48
 49#define DEFINE_IMMEDIATE_5_INSTRUCTION_EX_THUMB(NAME, IMMEDIATE, BODY) \
 50	DEFINE_INSTRUCTION_THUMB(NAME, \
 51		int immediate = IMMEDIATE; \
 52		int rd = opcode & 0x0007; \
 53		int rm = (opcode >> 3) & 0x0007; \
 54		BODY;)
 55
 56#define DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(NAME, BODY) \
 57	COUNT_5(DEFINE_IMMEDIATE_5_INSTRUCTION_EX_THUMB, NAME ## _, BODY)
 58
 59DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LSL1,
 60	if (!immediate) {
 61		cpu->gprs[rd] = cpu->gprs[rm];
 62	} else {
 63		cpu->cpsr.c = (cpu->gprs[rm] >> (32 - immediate)) & 1;
 64		cpu->gprs[rd] = cpu->gprs[rm] << immediate;
 65	}
 66	THUMB_NEUTRAL_S( , , cpu->gprs[rd]);)
 67
 68DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LSR1,
 69	if (!immediate) {
 70		cpu->cpsr.c = ARM_SIGN(cpu->gprs[rm]);
 71		cpu->gprs[rd] = 0;
 72	} else {
 73		cpu->cpsr.c = (cpu->gprs[rm] >> (immediate - 1)) & 1;
 74		cpu->gprs[rd] = ((uint32_t) cpu->gprs[rm]) >> immediate;
 75	}
 76	THUMB_NEUTRAL_S( , , cpu->gprs[rd]);)
 77
 78DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(ASR1, 
 79	if (!immediate) {
 80		cpu->cpsr.c = ARM_SIGN(cpu->gprs[rm]);
 81		if (cpu->cpsr.c) {
 82			cpu->gprs[rd] = 0xFFFFFFFF;
 83		} else {
 84			cpu->gprs[rd] = 0;
 85		}
 86	} else {
 87		cpu->cpsr.c = (cpu->gprs[rm] >> (immediate - 1)) & 1;
 88		cpu->gprs[rd] = cpu->gprs[rm] >> immediate;
 89	}
 90	THUMB_NEUTRAL_S( , , cpu->gprs[rd]);)
 91
 92DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LDR1, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[rm] + immediate * 4, &currentCycles))
 93DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LDRB1, cpu->gprs[rd] = cpu->memory.loadU8(cpu, cpu->gprs[rm] + immediate, &currentCycles))
 94DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(LDRH1, cpu->gprs[rd] = cpu->memory.loadU16(cpu, cpu->gprs[rm] + immediate * 2, &currentCycles))
 95DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(STR1, cpu->memory.store32(cpu, cpu->gprs[rm] + immediate * 4, cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
 96DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(STRB1, cpu->memory.store8(cpu, cpu->gprs[rm] + immediate, cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
 97DEFINE_IMMEDIATE_5_INSTRUCTION_THUMB(STRH1, cpu->memory.store16(cpu, cpu->gprs[rm] + immediate * 2, cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
 98
 99#define DEFINE_DATA_FORM_1_INSTRUCTION_EX_THUMB(NAME, RM, BODY) \
100	DEFINE_INSTRUCTION_THUMB(NAME, \
101		int rm = RM; \
102		int rd = opcode & 0x0007; \
103		int rn = (opcode >> 3) & 0x0007; \
104		BODY;)
105
106#define DEFINE_DATA_FORM_1_INSTRUCTION_THUMB(NAME, BODY) \
107	COUNT_3(DEFINE_DATA_FORM_1_INSTRUCTION_EX_THUMB, NAME ## 3_R, BODY)
108
109DEFINE_DATA_FORM_1_INSTRUCTION_THUMB(ADD, THUMB_ADDITION(cpu->gprs[rd], cpu->gprs[rn], cpu->gprs[rm]))
110DEFINE_DATA_FORM_1_INSTRUCTION_THUMB(SUB, THUMB_SUBTRACTION(cpu->gprs[rd], cpu->gprs[rn], cpu->gprs[rm]))
111
112#define DEFINE_DATA_FORM_2_INSTRUCTION_EX_THUMB(NAME, IMMEDIATE, BODY) \
113	DEFINE_INSTRUCTION_THUMB(NAME, \
114		int immediate = IMMEDIATE; \
115		int rd = opcode & 0x0007; \
116		int rn = (opcode >> 3) & 0x0007; \
117		BODY;)
118
119#define DEFINE_DATA_FORM_2_INSTRUCTION_THUMB(NAME, BODY) \
120	COUNT_3(DEFINE_DATA_FORM_2_INSTRUCTION_EX_THUMB, NAME ## 1_, BODY)
121
122DEFINE_DATA_FORM_2_INSTRUCTION_THUMB(ADD, THUMB_ADDITION(cpu->gprs[rd], cpu->gprs[rn], immediate))
123DEFINE_DATA_FORM_2_INSTRUCTION_THUMB(SUB, THUMB_SUBTRACTION(cpu->gprs[rd], cpu->gprs[rn], immediate))
124
125#define DEFINE_DATA_FORM_3_INSTRUCTION_EX_THUMB(NAME, RD, BODY) \
126	DEFINE_INSTRUCTION_THUMB(NAME, \
127		int rd = RD; \
128		int immediate = opcode & 0x00FF; \
129		BODY;)
130
131#define DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(NAME, BODY) \
132	COUNT_3(DEFINE_DATA_FORM_3_INSTRUCTION_EX_THUMB, NAME ## _R, BODY)
133
134DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(ADD2, THUMB_ADDITION(cpu->gprs[rd], cpu->gprs[rd], immediate))
135DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(CMP1, int aluOut = cpu->gprs[rd] - immediate; THUMB_SUBTRACTION_S(cpu->gprs[rd], immediate, aluOut))
136DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(MOV1, cpu->gprs[rd] = immediate; THUMB_NEUTRAL_S(, , cpu->gprs[rd]))
137DEFINE_DATA_FORM_3_INSTRUCTION_THUMB(SUB2, THUMB_SUBTRACTION(cpu->gprs[rd], cpu->gprs[rd], immediate))
138
139#define DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NAME, BODY) \
140	DEFINE_INSTRUCTION_THUMB(NAME, \
141		int rd = opcode & 0x0007; \
142		int rn = (opcode >> 3) & 0x0007; \
143		BODY;)
144
145DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(AND, cpu->gprs[rd] = cpu->gprs[rd] & cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
146DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(EOR, cpu->gprs[rd] = cpu->gprs[rd] ^ cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
147DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSL2,
148	int rs = cpu->gprs[rn] & 0xFF;
149	if (rs) {
150		if (rs < 32) {
151			cpu->cpsr.c = (cpu->gprs[rd] >> (32 - rs)) & 1;
152			cpu->gprs[rd] <<= rs;
153		} else {
154			if (rs > 32) {
155				cpu->cpsr.c = 0;
156			} else {
157				cpu->cpsr.c = cpu->gprs[rd] & 0x00000001;
158			}
159			cpu->gprs[rd] = 0;
160		}
161	}
162	THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
163
164DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(LSR2,
165	int rs = cpu->gprs[rn] & 0xFF;
166	if (rs) {
167		if (rs < 32) {
168			cpu->cpsr.c = (cpu->gprs[rd] >> (rs - 1)) & 1;
169			cpu->gprs[rd] = (uint32_t) cpu->gprs[rd] >> rs;
170		} else {
171			if (rs > 32) {
172				cpu->cpsr.c = 0;
173			} else {
174				cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]);
175			}
176			cpu->gprs[rd] = 0;
177		}
178	}
179	THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
180
181DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ASR2,
182	int rs = cpu->gprs[rn] & 0xFF;
183	if (rs) {
184		if (rs < 32) {
185			cpu->cpsr.c = (cpu->gprs[rd] >> (rs - 1)) & 1;
186			cpu->gprs[rd] >>= rs;
187		} else {
188			cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]);
189			if (cpu->cpsr.c) {
190				cpu->gprs[rd] = 0xFFFFFFFF;
191			} else {
192				cpu->gprs[rd] = 0;
193			}
194		}
195	}
196	THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
197
198DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ADC,
199	int n = cpu->gprs[rn];
200	int d = cpu->gprs[rd];
201	cpu->gprs[rd] = d + n + cpu->cpsr.c;
202	THUMB_ADDITION_S(d, n, cpu->gprs[rd]);)
203
204DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(SBC,
205	int n = cpu->gprs[rn] + !cpu->cpsr.c;
206	int d = cpu->gprs[rd];
207	cpu->gprs[rd] = d - n;
208	THUMB_SUBTRACTION_S(d, n, cpu->gprs[rd]);)
209DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ROR,
210	int rs = cpu->gprs[rn] & 0xFF;
211	if (rs) {
212		int r4 = rs & 0x1F;
213		if (r4 > 0) {
214			cpu->cpsr.c = (cpu->gprs[rd] >> (r4 - 1)) & 1;
215			cpu->gprs[rd] = ARM_ROR(cpu->gprs[rd], r4);
216		} else {
217			cpu->cpsr.c = ARM_SIGN(cpu->gprs[rd]);
218		}
219	}
220	THUMB_NEUTRAL_S( , , cpu->gprs[rd]);)
221DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(TST, int32_t aluOut = cpu->gprs[rd] & cpu->gprs[rn]; THUMB_NEUTRAL_S(cpu->gprs[rd], cpu->gprs[rn], aluOut))
222DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(NEG, THUMB_SUBTRACTION(cpu->gprs[rd], 0, cpu->gprs[rn]))
223DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(CMP2, int32_t aluOut = cpu->gprs[rd] - cpu->gprs[rn]; THUMB_SUBTRACTION_S(cpu->gprs[rd], cpu->gprs[rn], aluOut))
224DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(CMN, int32_t aluOut = cpu->gprs[rd] + cpu->gprs[rn]; THUMB_ADDITION_S(cpu->gprs[rd], cpu->gprs[rn], aluOut))
225DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(ORR, cpu->gprs[rd] = cpu->gprs[rd] | cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
226DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MUL, ARM_WAIT_MUL(cpu->gprs[rn]); cpu->gprs[rd] *= cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
227DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(BIC, cpu->gprs[rd] = cpu->gprs[rd] & ~cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
228DEFINE_DATA_FORM_5_INSTRUCTION_THUMB(MVN, cpu->gprs[rd] = ~cpu->gprs[rn]; THUMB_NEUTRAL_S( , , cpu->gprs[rd]))
229
230#define DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME, H1, H2, BODY) \
231	DEFINE_INSTRUCTION_THUMB(NAME, \
232		int rd = (opcode & 0x0007) | H1; \
233		int rm = ((opcode >> 3) & 0x0007) | H2; \
234		BODY;)
235
236#define DEFINE_INSTRUCTION_WITH_HIGH_THUMB(NAME, BODY) \
237	DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 00, 0, 0, BODY) \
238	DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 01, 0, 8, BODY) \
239	DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 10, 8, 0, BODY) \
240	DEFINE_INSTRUCTION_WITH_HIGH_EX_THUMB(NAME ## 11, 8, 8, BODY)
241
242DEFINE_INSTRUCTION_WITH_HIGH_THUMB(ADD4,
243	cpu->gprs[rd] += cpu->gprs[rm];
244	if (rd == ARM_PC) {
245		THUMB_WRITE_PC;
246	})
247
248DEFINE_INSTRUCTION_WITH_HIGH_THUMB(CMP3, int32_t aluOut = cpu->gprs[rd] - cpu->gprs[rm]; THUMB_SUBTRACTION_S(cpu->gprs[rd], cpu->gprs[rm], aluOut))
249DEFINE_INSTRUCTION_WITH_HIGH_THUMB(MOV3,
250	cpu->gprs[rd] = cpu->gprs[rm];
251	if (rd == ARM_PC) {
252		THUMB_WRITE_PC;
253	})
254
255#define DEFINE_IMMEDIATE_WITH_REGISTER_EX_THUMB(NAME, RD, BODY) \
256	DEFINE_INSTRUCTION_THUMB(NAME, \
257		int rd = RD; \
258		int immediate = (opcode & 0x00FF) << 2; \
259		BODY;)
260
261#define DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(NAME, BODY) \
262	COUNT_3(DEFINE_IMMEDIATE_WITH_REGISTER_EX_THUMB, NAME ## _R, BODY)
263
264DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR3, cpu->gprs[rd] = cpu->memory.load32(cpu, (cpu->gprs[ARM_PC] & 0xFFFFFFFC) + immediate, &currentCycles))
265DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(LDR4, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[ARM_SP] + immediate, &currentCycles))
266DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(STR3, cpu->memory.store32(cpu, cpu->gprs[ARM_SP] + immediate, cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
267
268DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD5, cpu->gprs[rd] = (cpu->gprs[ARM_PC] & 0xFFFFFFFC) + immediate)
269DEFINE_IMMEDIATE_WITH_REGISTER_THUMB(ADD6, cpu->gprs[rd] = cpu->gprs[ARM_SP] + immediate)
270
271#define DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB(NAME, RM, BODY) \
272	DEFINE_INSTRUCTION_THUMB(NAME, \
273		int rm = RM; \
274		int rd = opcode & 0x0007; \
275		int rn = (opcode >> 3) & 0x0007; \
276		BODY;)
277
278#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, BODY) \
279	COUNT_3(DEFINE_LOAD_STORE_WITH_REGISTER_EX_THUMB, NAME ## _R, BODY)
280
281DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[rn] + cpu->gprs[rm], &currentCycles))
282DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, cpu->gprs[rd] = cpu->memory.loadU8(cpu, cpu->gprs[rn] + cpu->gprs[rm], &currentCycles))
283DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, cpu->gprs[rd] = cpu->memory.loadU16(cpu, cpu->gprs[rn] + cpu->gprs[rm], &currentCycles))
284DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, cpu->gprs[rd] = cpu->memory.load8(cpu, cpu->gprs[rn] + cpu->gprs[rm], &currentCycles))
285DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, cpu->gprs[rd] = cpu->memory.load16(cpu, cpu->gprs[rn] + cpu->gprs[rm], &currentCycles))
286DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, cpu->memory.store32(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
287DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, cpu->memory.store8(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
288DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, cpu->memory.store16(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], &currentCycles); THUMB_STORE_POST_BODY;)
289
290#define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, ADDRESS, LOOP, BODY, OP, PRE_BODY, POST_BODY, WRITEBACK) \
291	DEFINE_INSTRUCTION_THUMB(NAME, \
292		int rn = RN; \
293		UNUSED(rn); \
294		int rs = opcode & 0xFF; \
295		int32_t address = ADDRESS; \
296		int m; \
297		int i; \
298		int total = 0; \
299		PRE_BODY; \
300		for LOOP { \
301			if (rs & m) { \
302				BODY; \
303				address OP 4; \
304				++total; \
305			} \
306		} \
307		POST_BODY; \
308		currentCycles += cpu->memory.waitMultiple(cpu, address, total); \
309		WRITEBACK;)
310
311#define DEFINE_LOAD_STORE_MULTIPLE_THUMB(NAME, BODY, WRITEBACK) \
312	COUNT_3(DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB, NAME ## _R, cpu->gprs[rn], (m = 0x01, i = 0; i < 8; m <<= 1, ++i), BODY, +=, , , WRITEBACK)
313
314DEFINE_LOAD_STORE_MULTIPLE_THUMB(LDMIA,
315	cpu->gprs[i] = cpu->memory.load32(cpu, address, 0),
316	if (!((1 << rn) & rs)) {
317		cpu->gprs[rn] = address;
318	})
319
320DEFINE_LOAD_STORE_MULTIPLE_THUMB(STMIA,
321	cpu->memory.store32(cpu, address, cpu->gprs[i], 0),
322	THUMB_STORE_POST_BODY;
323	cpu->gprs[rn] = address;)
324
325#define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
326	DEFINE_INSTRUCTION_THUMB(B ## COND, \
327		if (ARM_COND_ ## COND) { \
328			int8_t immediate = opcode; \
329			cpu->gprs[ARM_PC] += immediate << 1; \
330			THUMB_WRITE_PC; \
331		})
332
333DEFINE_CONDITIONAL_BRANCH_THUMB(EQ)
334DEFINE_CONDITIONAL_BRANCH_THUMB(NE)
335DEFINE_CONDITIONAL_BRANCH_THUMB(CS)
336DEFINE_CONDITIONAL_BRANCH_THUMB(CC)
337DEFINE_CONDITIONAL_BRANCH_THUMB(MI)
338DEFINE_CONDITIONAL_BRANCH_THUMB(PL)
339DEFINE_CONDITIONAL_BRANCH_THUMB(VS)
340DEFINE_CONDITIONAL_BRANCH_THUMB(VC)
341DEFINE_CONDITIONAL_BRANCH_THUMB(LS)
342DEFINE_CONDITIONAL_BRANCH_THUMB(HI)
343DEFINE_CONDITIONAL_BRANCH_THUMB(GE)
344DEFINE_CONDITIONAL_BRANCH_THUMB(LT)
345DEFINE_CONDITIONAL_BRANCH_THUMB(GT)
346DEFINE_CONDITIONAL_BRANCH_THUMB(LE)
347
348DEFINE_INSTRUCTION_THUMB(ADD7, cpu->gprs[ARM_SP] += (opcode & 0x7F) << 2)
349DEFINE_INSTRUCTION_THUMB(SUB4, cpu->gprs[ARM_SP] -= (opcode & 0x7F) << 2)
350
351DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POP,
352	opcode & 0x00FF,
353	cpu->gprs[ARM_SP],
354	(m = 0x01, i = 0; i < 8; m <<= 1, ++i),
355	cpu->gprs[i] = cpu->memory.load32(cpu, address, 0),
356	+=,
357	, ,
358	cpu->gprs[ARM_SP] = address)
359
360DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(POPR,
361	opcode & 0x00FF,
362	cpu->gprs[ARM_SP],
363	(m = 0x01, i = 0; i < 8; m <<= 1, ++i),
364	cpu->gprs[i] = cpu->memory.load32(cpu, address, 0),
365	+=,
366	,
367	cpu->gprs[ARM_PC] = cpu->memory.load32(cpu, address, 0) & 0xFFFFFFFE;
368	address += 4;,
369	cpu->gprs[ARM_SP] = address;
370	THUMB_WRITE_PC;)
371
372DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSH,
373	opcode & 0x00FF,
374	cpu->gprs[ARM_SP] - 4,
375	(m = 0x80, i = 7; m; m >>= 1, --i),
376	cpu->memory.store32(cpu, address, cpu->gprs[i], 0),
377	-=,
378	,
379	THUMB_STORE_POST_BODY,
380	cpu->gprs[ARM_SP] = address + 4)
381
382DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(PUSHR,
383	opcode & 0x00FF,
384	cpu->gprs[ARM_SP] - 4,
385	(m = 0x80, i = 7; m; m >>= 1, --i),
386	cpu->memory.store32(cpu, address, cpu->gprs[i], 0),
387	-=,
388	cpu->memory.store32(cpu, address, cpu->gprs[ARM_LR], 0);
389	address -= 4;,
390	THUMB_STORE_POST_BODY,
391	cpu->gprs[ARM_SP] = address + 4)
392
393DEFINE_INSTRUCTION_THUMB(ILL, ARM_ILL)
394DEFINE_INSTRUCTION_THUMB(BKPT, ARM_STUB)
395DEFINE_INSTRUCTION_THUMB(B,
396	int16_t immediate = (opcode & 0x07FF) << 5;
397	cpu->gprs[ARM_PC] += (((int32_t) immediate) >> 4);
398	THUMB_WRITE_PC;)
399
400DEFINE_INSTRUCTION_THUMB(BL1,
401	int16_t immediate = (opcode & 0x07FF) << 5;
402	cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] + (((int32_t) immediate) << 7);)
403
404DEFINE_INSTRUCTION_THUMB(BL2,
405	uint16_t immediate = (opcode & 0x07FF) << 1;
406	uint32_t pc = cpu->gprs[ARM_PC];
407	cpu->gprs[ARM_PC] = cpu->gprs[ARM_LR] + immediate;
408	cpu->gprs[ARM_LR] = pc - 1;
409	THUMB_WRITE_PC;)
410
411DEFINE_INSTRUCTION_THUMB(BX,
412	int rm = (opcode >> 3) & 0xF;
413	_ARMSetMode(cpu, cpu->gprs[rm] & 0x00000001);
414	int misalign = 0;
415	if (rm == ARM_PC) {
416		misalign = cpu->gprs[rm] & 0x00000002;
417	}
418	cpu->gprs[ARM_PC] = (cpu->gprs[rm] & 0xFFFFFFFE) - misalign;
419	if (cpu->executionMode == MODE_THUMB) {
420		THUMB_WRITE_PC;
421	} else {
422		ARM_WRITE_PC;
423	})
424
425DEFINE_INSTRUCTION_THUMB(SWI, cpu->irqh.swi16(cpu, opcode & 0xFF))
426
427const ThumbInstruction _thumbTable[0x400] = {
428	DECLARE_THUMB_EMITTER_BLOCK(_ThumbInstruction)
429};