Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/interpreter_thumb.cpp
2 views
1
// Meteor - A Nintendo Gameboy Advance emulator
2
// Copyright (C) 2009-2011 Philippe Daouadi
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
#ifndef __INTERPRETER_THUMB_H__
18
#define __INTERPRETER_THUMB_H__
19
20
/*
21
22
- From GBATEK -
23
24
THUMB Binary Opcode Format
25
26
Fo|_15|_14|_13|_12|_11|_10|_9_|_8_|_7_|_6_|_5_|_4_|_3_|_2_|_1_|_0_|
27
_1|_0___0___0_|__Op___|_______Offset______|____Rs_____|____Rd_____|Shifted
28
_2|_0___0___0___1___1_|_I,_Op_|___Rn/nn___|____Rs_____|____Rd_____|ADD/SUB
29
_3|_0___0___1_|__Op___|____Rd_____|_____________Offset____________|Immedi.
30
_4|_0___1___0___0___0___0_|______Op_______|____Rs_____|____Rd_____|AluOp
31
_5|_0___1___0___0___0___1_|__Op___|Hd_|Hs_|____Rs_____|____Rd_____|HiReg/BX
32
_6|_0___1___0___0___1_|____Rd_____|_____________Word______________|LDR PC
33
_7|_0___1___0___1_|__Op___|_0_|___Ro______|____Rb_____|____Rd_____|LDR/STR
34
_8|_0___1___0___1_|__Op___|_1_|___Ro______|____Rb_____|____Rd_____|""H/SB/SH
35
_9|_0___1___1_|__Op___|_______Offset______|____Rb_____|____Rd_____|""{B}
36
10|_1___0___0___0_|Op_|_______Offset______|____Rb_____|____Rd_____|""H
37
11|_1___0___0___1_|Op_|____Rd_____|_____________Word______________|"" SP
38
12|_1___0___1___0_|Op_|____Rd_____|_____________Word______________|ADD PC/SP
39
13|_1___0___1___1___0___0___0___0_|_S_|___________Word____________|ADD SP,nn
40
14|_1___0___1___1_|Op_|_1___0_|_R_|____________Rlist______________|PUSH/POP
41
17|_1___0___1___1___1___1___1___0_|___________User_Data___________|BKPT ARM9
42
15|_1___1___0___0_|Op_|____Rb_____|____________Rlist______________|STM/LDM
43
16|_1___1___0___1_|_____Cond______|_________Signed_Offset_________|B{cond}
44
U_|_1___1___0___1___1___1___1___0_|_____________var_______________|UNDEF ARM9
45
17|_1___1___0___1___1___1___1___1_|___________User_Data___________|SWI
46
18|_1___1___1___0___0_|________________Offset_____________________|B
47
19|_1___1___1___0___1_|_________________________var___________|_0_|BLXsuf ARM9
48
U_|_1___1___1___0___1_|_________________________var___________|_1_|UNDEF ARM9
49
19|_1___1___1___1_|_H_|______________Offset_Low/High______________|BL (BLX ARM9)
50
51
*/
52
53
#include "ameteor/interpreter.hpp"
54
#include "globals.hpp"
55
#include "cpu_globals.hpp"
56
#include "ameteor/memory.hpp"
57
#include "ameteor.hpp"
58
59
#include "debug.hpp"
60
61
#define Rb ((code >> 8) & 0x7)
62
#define Ro ((code >> 6) & 0x7)
63
#define Rs ((code >> 3) & 0x7)
64
#define Rd ((code ) & 0x7)
65
#define Imm (code & 0xFF)
66
#define Off ((code >> 6) & 0x1F)
67
68
//#define HiRs (((code & (0x1 << 6)) >> 3) | Rs)
69
#define HiRs ((code >> 3) & 0xF)
70
#define HiRd (((code & (0x1 << 7)) >> 4) | Rd)
71
72
#ifdef METDEBUG
73
# define NOT_PC(reg) \
74
if (reg == 15) \
75
met_abort("Register is PC")
76
#else
77
# define NOT_PC(reg) {}
78
#endif
79
80
#define THUMB(name) \
81
inline void Interpreter::t##name ()
82
#define NITHUMB(name) \
83
void Interpreter::t##name ()
84
85
namespace AMeteor
86
{
87
// move shifted register
88
THUMB(_Shift)
89
{
90
if ((code >> 13) & 0x7)
91
{
92
met_abort("Bits 13-15 must be 000 for shift instructions");
93
}
94
95
uint8_t off = Off;
96
switch ((code >> 11) & 0x3)
97
{
98
case 0x0: // LSL
99
if (off)
100
{
101
SETF(C, R(Rs) & (0x1 << (32-off)));
102
R(Rd) = R(Rs) << off;
103
FZ(R(Rd));
104
FN(R(Rd));
105
}
106
else
107
{
108
R(Rd) = R(Rs);
109
FZ(R(Rd));
110
FN(R(Rd));
111
}
112
break;
113
case 0x1: // LSR
114
if (off)
115
{
116
SETF(C, R(Rs) & (0x1 << (off-1)));
117
R(Rd) = R(Rs) >> off;
118
FZ(R(Rd));
119
FN(R(Rd));
120
}
121
else
122
{
123
SETF(C, R(Rs) & (0x1 << 31));
124
R(Rd) = 0;
125
FLAG_Z = 1;
126
FLAG_N = 0;
127
}
128
break;
129
case 0x2: // ASR
130
if (off)
131
{
132
SETF(C, (((int32_t)R(Rs)) >> (off - 1)) & 0x1);
133
R(Rd) = ((int32_t)R(Rs)) >> off;
134
FZ(R(Rd));
135
FN(R(Rd));
136
}
137
else
138
{
139
if (R(Rd) & (0x1 << 31))
140
{
141
R(Rd) = 0xFFFFFFFF;
142
FLAG_Z = 0;
143
FLAG_N = 1;
144
FLAG_C = 1;
145
}
146
else
147
{
148
R(Rd) = 0;
149
FLAG_Z = 1;
150
FLAG_N = 0;
151
FLAG_C = 0;
152
}
153
}
154
break;
155
case 0x3: // reserved
156
met_abort("Bits 11-12 must not be 11 for shift instructions");
157
break;
158
}
159
160
CYCLES16Seq(R(15), 1);
161
}
162
163
// add/substract
164
THUMB(ADDSUB)
165
{
166
if (((code >> 11) & 0x1F) != 0x3)
167
{
168
met_abort("Bits 11-15 should be 00011 for add/substract");
169
}
170
171
uint32_t op2;
172
if ((code >> 10) & 0x1) // imm
173
op2 = Ro;
174
else // reg
175
op2 = R(Ro);
176
177
if ((code >> 9) & 0x1) // SUB
178
{
179
#ifdef X86_ASM
180
asm("subl %6, %5\n"
181
"setzb %1\n"
182
"setsb %2\n"
183
"setncb %3\n"
184
"setob %4\n"
185
:"=r"(R(Rd)), "=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
186
:"0"(R(Rs)), "r"(op2));
187
#else
188
uint32_t op1 = R(Rs), res = R(Rd) = op1 - op2;
189
FLAG_Z = !res;
190
FLAG_N = res >> 31;
191
FLAG_C = SUBCARRY(op1, op2, res);
192
FLAG_V = SUBOVERFLOW(op1, op2, res);
193
#endif
194
}
195
else // ADD
196
{
197
#ifdef X86_ASM
198
asm("addl %6, %5\n"
199
"setzb %1\n"
200
"setsb %2\n"
201
"setcb %3\n"
202
"setob %4\n"
203
:"=r"(R(Rd)), "=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
204
:"0"(R(Rs)), "r"(op2));
205
#else
206
uint32_t op1 = R(Rs), res = R(Rd) = op1 + op2;
207
FLAG_Z = !res;
208
FLAG_N = res >> 31;
209
FLAG_C = ADDCARRY(op1, op2, res);
210
FLAG_V = ADDOVERFLOW(op1, op2, res);
211
#endif
212
}
213
214
CYCLES16Seq(R(15), 1);
215
}
216
217
// move/compare/add/substact immediate
218
THUMB(_Imm)
219
{
220
if (((code >> 13) & 0x7) != 0x1)
221
{
222
met_abort("Bits 13-15 must be 001 for immediate instructions");
223
}
224
225
switch ((code >> 11) & 0x3)
226
{
227
case 0x0: // MOV
228
R(Rb) = Imm;
229
FLAG_Z = !Imm;
230
FLAG_N = 0;
231
break;
232
case 0x1: // CMP
233
#ifdef X86_ASM
234
asm("cmpl %5, %4\n"
235
"setzb %0\n"
236
"setsb %1\n"
237
"setncb %2\n"
238
"setob %3\n"
239
:"=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
240
:"r"(R(Rb)), "r"(Imm));
241
#else
242
{
243
uint32_t op1 = R(Rb), op2 = Imm, res = op1 - op2;
244
FLAG_Z = !res;
245
FLAG_N = res >> 31;
246
FLAG_C = SUBCARRY(op1, op2, res);
247
FLAG_V = SUBOVERFLOW(op1, op2, res);
248
}
249
#endif
250
break;
251
case 0x2: // ADD
252
#ifdef X86_ASM
253
asm("addl %6, %5\n"
254
"setzb %1\n"
255
"setsb %2\n"
256
"setcb %3\n"
257
"setob %4\n"
258
:"=r"(R(Rb)), "=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
259
:"0"(R(Rb)), "r"(Imm));
260
#else
261
{
262
uint32_t op1 = R(Rb), op2 = Imm, res = R(Rb) = op1 + op2;
263
FLAG_Z = !res;
264
FLAG_N = res >> 31;
265
FLAG_C = ADDCARRY(op1, op2, res);
266
FLAG_V = ADDOVERFLOW(op1, op2, res);
267
}
268
#endif
269
break;
270
case 0x3: // SUB
271
#ifdef X86_ASM
272
asm("subl %6, %5\n"
273
"setzb %1\n"
274
"setsb %2\n"
275
"setncb %3\n"
276
"setob %4\n"
277
:"=r"(R(Rb)), "=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
278
:"0"(R(Rb)), "r"(Imm));
279
#else
280
{
281
uint32_t op1 = R(Rb), op2 = Imm, res = R(Rb) = op1 - op2;
282
FLAG_Z = !res;
283
FLAG_N = res >> 31;
284
FLAG_C = SUBCARRY(op1, op2, res);
285
FLAG_V = SUBOVERFLOW(op1, op2, res);
286
}
287
#endif
288
break;
289
}
290
291
CYCLES16Seq(R(15), 1);
292
}
293
294
// ALU operations
295
THUMB(_ALU)
296
{
297
if (((code >> 10) & 0x3F) != 0x10)
298
{
299
met_abort("Bits 10-15 must be 010000 for ALU instructions");
300
}
301
302
uint8_t opcode = (code >> 6) & 0xF;
303
// TODO put a ifndef X86_ASM here around this declaration
304
uint32_t res = 0; // to avoid a warning
305
uint8_t shift;
306
307
switch (opcode)
308
{
309
case 0x0: // AND
310
#ifdef X86_ASM
311
asm("andl %4, %3\n"
312
"setzb %1\n"
313
"setsb %2\n"
314
:"=r"(R(Rd)), "=m"(FLAG_Z), "=m"(FLAG_N)
315
:"0"(R(Rd)), "r"(R(Rs)));
316
#else
317
res = R(Rd) &= R(Rs);
318
FLAG_Z = !res;
319
FLAG_N = res >> 31;
320
#endif
321
break;
322
case 0x1: // EOR
323
#ifdef X86_ASM
324
asm("xorl %4, %3\n"
325
"setzb %1\n"
326
"setsb %2\n"
327
:"=r"(R(Rd)), "=m"(FLAG_Z), "=m"(FLAG_N)
328
:"0"(R(Rd)), "r"(R(Rs)));
329
#else
330
res = R(Rd) ^= R(Rs);
331
FLAG_Z = !res;
332
FLAG_N = res >> 31;
333
#endif
334
break;
335
case 0x2: // LSL
336
ICYCLES(1);
337
shift = R(Rs) & 0xFF;
338
if (shift)
339
{
340
if (shift == 32)
341
{
342
SETFB(C, R(Rd) & 0x1);
343
R(Rd) = 0;
344
FLAG_Z = FLAG_N = 0;
345
}
346
else if (shift < 32)
347
{
348
SETFB(C, (R(Rd) >> (32-shift)) & 0x1);
349
res = R(Rd) <<= shift;
350
FLAG_Z = !res;
351
FLAG_N = res >> 31;
352
}
353
else
354
{
355
R(Rd) = 0;
356
FLAG_C = FLAG_Z = FLAG_N = 0;
357
}
358
}
359
else
360
{
361
res = R(Rd);
362
FLAG_Z = !res;
363
FLAG_N = res >> 31;
364
}
365
break;
366
case 0x3: // LSR
367
ICYCLES(1);
368
shift = R(Rs) & 0xFF;
369
if (shift)
370
{
371
if (shift == 32)
372
{
373
SETFB(C, R(Rd) >> 31);
374
R(Rd) = 0;
375
FLAG_Z = FLAG_N = 0;
376
}
377
else if (shift < 32)
378
{
379
SETFB(C, (R(Rd) >> (shift-1)) & 0x1);
380
res = R(Rd) >>= shift;
381
FLAG_Z = !res;
382
FLAG_N = res >> 31;
383
}
384
else
385
{
386
R(Rd) = 0;
387
FLAG_C = FLAG_Z = FLAG_N = 0;
388
}
389
}
390
else
391
{
392
res = R(Rd);
393
FLAG_Z = !res;
394
FLAG_N = res >> 31;
395
}
396
break;
397
case 0x4: // ASR
398
ICYCLES(1);
399
shift = R(Rs) & 0xFF;
400
if (shift)
401
{
402
if (shift >= 32)
403
{
404
R(Rd) = ((int32_t)R(Rs)) >> 31;
405
FLAG_C = FLAG_Z = FLAG_N = R(Rd) & 0x1;
406
}
407
else
408
{
409
SETFB(C, (((int32_t)R(Rd)) >> (shift-1)) & 0x1);
410
res = R(Rd) = ((int32_t)R(Rd)) >> shift;
411
FLAG_Z = !res;
412
FLAG_N = res >> 31;
413
}
414
}
415
else
416
{
417
res = R(Rd);
418
FLAG_Z = !res;
419
FLAG_N = res >> 31;
420
}
421
break;
422
case 0x5: // ADC
423
res = R(Rd) + R(Rs) + FLAG_C;
424
FLAG_C = ADDCARRY(R(Rd), R(Rs), res);
425
FLAG_V = ADDOVERFLOW(R(Rd), R(Rs), res);
426
R(Rd) = res;
427
break;
428
case 0x6: // SBC
429
res = R(Rd) - R(Rs) + FLAG_C - 1;
430
FLAG_C = SUBCARRY(R(Rd), R(Rs), res);
431
FLAG_V = SUBOVERFLOW(R(Rd), R(Rs), res);
432
R(Rd) = res;
433
break;
434
case 0x7: // ROR
435
ICYCLES(1);
436
shift = R(Rs) & 0xFF;
437
if (shift)
438
{
439
shift %= 32;
440
res = R(Rd);
441
SETFB(C, (res >> (shift - 1)) & 0x1);
442
res = R(Rd) = ROR(res, shift);
443
FLAG_Z = !res;
444
FLAG_N = res >> 31;
445
}
446
else
447
{
448
res = R(Rd);
449
FLAG_Z = !res;
450
FLAG_N = res >> 31;
451
}
452
break;
453
case 0x8: // TST
454
#ifdef X86_ASM
455
asm("testl %3, %2\n"
456
"setzb %0\n"
457
"setsb %1\n"
458
:"=m"(FLAG_Z), "=m"(FLAG_N)
459
:"r"(R(Rd)), "r"(R(Rs)));
460
#else
461
res = R(Rd) & R(Rs);
462
FLAG_Z = !res;
463
FLAG_N = res >> 31;
464
#endif
465
break;
466
case 0x9: // NEG
467
#ifdef X86_ASM
468
asm("negl %5\n"
469
"setzb %1\n"
470
"setsb %2\n"
471
"setncb %3\n"
472
"setob %4\n"
473
:"=r"(R(Rd)), "=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
474
:"0"(R(Rs)));
475
#else
476
{
477
uint32_t op2;
478
op2 = R(Rs);
479
res = R(Rd) = -op2;
480
FLAG_Z = !res;
481
FLAG_N = res >> 31;
482
// we overflow only if op2 == INT_MIN
483
FLAG_V = SUBOVERFLOW(0, op2, res);
484
// we have a carry only if op2 == 0
485
FLAG_C = SUBCARRY(0, op2, res);
486
}
487
#endif
488
break;
489
case 0xA: // CMP
490
#ifdef X86_ASM
491
asm("cmpl %5, %4\n"
492
"setzb %0\n"
493
"setsb %1\n"
494
"setncb %2\n"
495
"setob %3\n"
496
:"=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
497
:"r"(R(Rd)), "r"(R(Rs)));
498
#else
499
{
500
uint32_t op1, op2;
501
op1 = R(Rd);
502
op2 = R(Rs);
503
res = op1 - op2;
504
FLAG_Z = !res;
505
FLAG_N = res >> 31;
506
FLAG_C = SUBCARRY(op1, op2, res);
507
FLAG_V = SUBOVERFLOW(op1, op2, res);
508
}
509
#endif
510
break;
511
case 0xB: // CMN
512
#ifdef X86_ASM
513
asm("addl %5, %4\n"
514
"setzb %0\n"
515
"setsb %1\n"
516
"setcb %2\n"
517
"setob %3\n"
518
:"=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
519
:"r"(R(Rd)), "r"(R(Rs))
520
:"4");
521
#else
522
{
523
uint32_t op1, op2;
524
op1 = R(Rd);
525
op2 = R(Rs);
526
res = op1 + op2;
527
FLAG_Z = !res;
528
FLAG_N = res >> 31;
529
FLAG_C = ADDCARRY(op1, op2, res);
530
FLAG_V = ADDOVERFLOW(op1, op2, res);
531
}
532
#endif
533
break;
534
case 0xC: // ORR
535
#ifdef X86_ASM
536
asm("orl %4, %3\n"
537
"setzb %1\n"
538
"setsb %2\n"
539
:"=r"(R(Rd)), "=m"(FLAG_Z), "=m"(FLAG_N)
540
:"0"(R(Rd)), "r"(R(Rs)));
541
#else
542
res = R(Rd) |= R(Rs);
543
FLAG_Z = !res;
544
FLAG_N = res >> 31;
545
#endif
546
break;
547
case 0xD: // MUL
548
MULICYCLES(Rs);
549
res = R(Rd) *= R(Rs);
550
FLAG_Z = !res;
551
FLAG_N = res >> 31;
552
break;
553
case 0xE: // BIC
554
res = R(Rd) &= ~R(Rs);
555
FLAG_Z = !res;
556
FLAG_N = res >> 31;
557
break;
558
case 0xF: // MVN
559
res = R(Rd) = ~R(Rs);
560
FLAG_Z = !res;
561
FLAG_N = res >> 31;
562
break;
563
}
564
565
CYCLES16Seq(R(15), 1);
566
}
567
568
// Hi register operations/branch exchange
569
THUMB(_HiRegOp)
570
{
571
if (((code >> 10) & 0x3F) != 0x11)
572
{
573
met_abort("Bits 10-15 must be 010001 for HiReg instructions");
574
}
575
576
uint8_t rd = HiRd, rs = HiRs;
577
switch ((code >> 8) & 0x3)
578
{
579
case 0x0: // ADD
580
R(rd) += R(rs);
581
if (rd == 15)
582
{
583
R(15) &= 0xFFFFFFFE;
584
CYCLES16NSeq(R(15), 3);
585
R(15) += 2;
586
}
587
else
588
CYCLES16Seq(R(15), 1);
589
break;
590
case 0x1: // CMP
591
#ifdef X86_ASM
592
asm("cmpl %5, %4\n"
593
"setzb %0\n"
594
"setsb %1\n"
595
"setncb %2\n"
596
"setob %3\n"
597
:"=m"(FLAG_Z), "=m"(FLAG_N), "=m"(FLAG_C), "=m"(FLAG_V)
598
:"r"(R(rd)), "r"(R(rs)));
599
#else
600
{
601
uint32_t op1 = R(rd), op2 = R(rs), res = op1 - op2;
602
FLAG_Z = !res;
603
FLAG_N = res >> 31;
604
FLAG_C = SUBCARRY(op1, op2, res);
605
FLAG_V = SUBOVERFLOW(op1, op2, res);
606
}
607
#endif
608
CYCLES16Seq(R(15), 1);
609
break;
610
case 0x2:
611
if (rd != 8 || rs != 8) // MOV
612
{
613
R(rd) = R(rs);
614
if (rd == 15)
615
{
616
R(15) &= 0xFFFFFFFE;
617
CYCLES16NSeq(R(15), 3);
618
R(15) += 2;
619
}
620
else
621
CYCLES16Seq(R(15), 1);
622
}
623
else // NOP
624
CYCLES16Seq(R(15), 1);
625
break;
626
case 0x3:
627
if (Rd)
628
met_abort("Rd must be 0 for BX/BLX instructions");
629
if (code & (0x1 << 7)) // BLX
630
{
631
NOT_PC(rs);
632
met_abort("BLX not implemented");
633
}
634
else // BX
635
{
636
if (R(rs) & 0x1)
637
{
638
R(15) = (R(rs) & 0xFFFFFFFE) + 2;
639
CYCLES16NSeq(R(15), 3);
640
}
641
else
642
{
643
// switch to arm
644
FLAG_T = 0;
645
R(15) = (R(rs) & 0xFFFFFFFC) + 4;
646
CYCLES32NSeq(R(15), 3);
647
}
648
}
649
break;
650
}
651
}
652
653
// load PC-relative
654
THUMB(LDRimm)
655
{
656
if (((code >> 11) & 0x1F) != 0x9)
657
{
658
met_abort("Bits 11-15 must be 01001 for LDR with imm instructions");
659
}
660
661
uint32_t add = (R(15) & 0xFFFFFFFC) + (Imm << 2);
662
R(Rb) = MEM.Read32(add);
663
664
CYCLES32NSeq(add, 1);
665
ICYCLES(1);
666
CYCLES16Seq(R(15), 1);
667
}
668
669
// load/store with register offset
670
// and load/store sign-extended byte/halfword
671
THUMB(STRLDRreg)
672
{
673
if (((code >> 12) & 0xF) != 0x5)
674
{
675
met_abort("Bits 12-15 must be 0101 for LDR/STR with reg instructions");
676
}
677
678
uint32_t add = R(Ro) + R(Rs);
679
switch ((code >> 9) & 0x7)
680
{
681
// load/store with register offset
682
case 0x0: // STR
683
MEM.Write32(add, R(Rd));
684
CYCLES32NSeq(add, 1);
685
CYCLES16NSeq(R(15), 1);
686
break;
687
case 0x2: // STRB
688
MEM.Write8(add, R(Rd));
689
CYCLES16NSeq(add, 1);
690
CYCLES16NSeq(R(15), 1);
691
break;
692
case 0x4: // LDR
693
R(Rd) = MEM.Read32(add);
694
CYCLES32NSeq(add, 1);
695
ICYCLES(1);
696
CYCLES16Seq(R(15), 1);
697
break;
698
case 0x6: // LDRB
699
R(Rd) = MEM.Read8(add);
700
CYCLES16NSeq(add, 1);
701
ICYCLES(1);
702
CYCLES16Seq(R(15), 1);
703
break;
704
705
// load/store sign-extended byte/halfword
706
case 0x1: // STRH
707
MEM.Write16(add, R(Rd));
708
CYCLES16NSeq(add, 1);
709
CYCLES16NSeq(R(15), 1);
710
break;
711
case 0x3: // LDSB
712
R(Rd) = (int8_t)MEM.Read8(add);
713
CYCLES16NSeq(add, 1);
714
ICYCLES(1);
715
CYCLES16Seq(R(15), 1);
716
break;
717
case 0x5: // LDRH
718
R(Rd) = MEM.Read16(add);
719
CYCLES16NSeq(add, 1);
720
ICYCLES(1);
721
CYCLES16Seq(R(15), 1);
722
break;
723
case 0x7: // LDSH
724
R(Rd) = (int16_t)MEM.Read16(add);
725
CYCLES16NSeq(add, 1);
726
ICYCLES(1);
727
CYCLES16Seq(R(15), 1);
728
break;
729
}
730
}
731
732
// load/store with immediate offset
733
THUMB(STRLDRoff)
734
{
735
if (((code >> 13) & 0x7) != 0x3)
736
{
737
met_abort("Bits 13-15 must be 011 for LDR/STR with off instructions");
738
}
739
740
uint32_t add;
741
switch ((code >> 11) & 0x3)
742
{
743
case 0x0: // STR
744
add = R(Rs) + (Off << 2);
745
MEM.Write32(add, R(Rd));
746
CYCLES32NSeq(add, 1);
747
CYCLES16NSeq(R(15), 1);
748
break;
749
case 0x1: // LDR
750
add = R(Rs) + (Off << 2);
751
R(Rd) = MEM.Read32(add);
752
CYCLES32NSeq(add, 1);
753
ICYCLES(1);
754
CYCLES16Seq(R(15), 1);
755
break;
756
case 0x2: // STRB
757
add = R(Rs) + Off;
758
MEM.Write8(add, R(Rd));
759
CYCLES16NSeq(add, 1);
760
CYCLES16NSeq(R(15), 1);
761
break;
762
case 0x3: // LDRB
763
add = R(Rs) + Off;
764
R(Rd) = MEM.Read8(add);
765
CYCLES16NSeq(add, 1);
766
ICYCLES(1);
767
CYCLES16Seq(R(15), 1);
768
break;
769
}
770
}
771
772
// load/store halfword
773
THUMB(LDRHSTRHoff)
774
{
775
if (((code >> 12) & 0xF) != 0x8)
776
{
777
met_abort("Bits 12-15 must be 1000 for LDRH/STRH with off instructions");
778
}
779
780
uint32_t add = R(Rs) + (Off * 2);
781
if (code & (0x1 << 11)) // LDRH
782
{
783
R(Rd) = MEM.Read16(add);
784
CYCLES16NSeq(add, 1);
785
ICYCLES(1);
786
CYCLES16Seq(R(15), 1);
787
}
788
else // STRH
789
{
790
MEM.Write16(add, R(Rd));
791
CYCLES16NSeq(add, 1);
792
CYCLES16NSeq(R(15), 1);
793
}
794
}
795
796
// load/store SP-relative
797
THUMB(STRLDRsp)
798
{
799
if (((code >> 12) & 0xF) != 0x9)
800
{
801
met_abort("Bits 12-15 must be 1001 for LDR/STR SP-relative instructions");
802
}
803
804
uint32_t add = R(13) + (Imm << 2);
805
if (code & (0x1 << 11)) // LDR
806
{
807
R(Rb) = MEM.Read32(add);
808
CYCLES32NSeq(add, 1);
809
ICYCLES(1);
810
CYCLES16Seq(R(15), 1);
811
}
812
else // STR
813
{
814
MEM.Write32(add, R(Rb));
815
CYCLES32NSeq(add, 1);
816
CYCLES16NSeq(R(15), 1);
817
}
818
}
819
820
// get relative address
821
THUMB(ADDpcsp)
822
{
823
if (((code >> 12) & 0xF) != 0xA)
824
{
825
met_abort("Bits 12-15 must be 1010 for ADD relative instructions");
826
}
827
828
if (code & (0x1 << 11)) // with SP
829
{
830
R(Rb) = R(13) + (Imm << 2);
831
}
832
else // with PC
833
{
834
R(Rb) = (R(15) & 0xFFFFFFFC) + (Imm << 2);
835
}
836
837
CYCLES16Seq(R(15), 1);
838
}
839
840
// add offset to stack pointer
841
THUMB(ADDsp)
842
{
843
if (((code >> 8) & 0xFF) != 0xB0)
844
{
845
met_abort("Bits 8-15 must be 10110000 for ADD to SP instructions");
846
}
847
848
if (code & (0x1 << 7)) // substract
849
{
850
R(13) -= ((code & 0x7F) << 2);
851
}
852
else // add
853
{
854
R(13) += ((code & 0x7F) << 2);
855
}
856
857
CYCLES16Seq(R(15), 1);
858
}
859
860
// push/pop registers
861
THUMB(PUSHPOP)
862
{
863
if (((code >> 12) & 0xF) != 0xB)
864
{
865
met_abort("Bits 12-15 must be 1011 for PUSH/POP instructions");
866
}
867
if (((code >> 9) & 0x3) != 0x2)
868
{
869
met_abort("Bits 9-10 must be 10 for PUSH/POP instructions");
870
}
871
872
static const uint8_t NumBits[] =
873
{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
874
875
uint8_t numregs =
876
NumBits[(code >> 4) & 0xF] +
877
NumBits[ code & 0xF];
878
if (code & (0x1 << 8))
879
++numregs;
880
881
uint32_t add, newsp;
882
if (code & (0x1 << 11)) // POP
883
{
884
newsp = R(13) + 4 * numregs;
885
add = R(13) & 0xFFFFFFFC;
886
887
CYCLES32NSeq(add, numregs);
888
ICYCLES(1);
889
890
for (register uint8_t n = 0; n < 8; ++n)
891
if (code & (0x1 << n))
892
{
893
R(n) = MEM.Read32 (add);
894
add += 4;
895
}
896
if (code & (0x1 << 8)) // POP PC
897
{
898
R(15) = (MEM.Read32(add) + 2) & 0xFFFFFFFE;
899
CYCLES16NSeq(R(15), 3);
900
}
901
else
902
CYCLES16Seq(R(15), 1);
903
}
904
else // PUSH
905
{
906
newsp = R(13) - 4 * numregs;
907
add = newsp & 0xFFFFFFFC;
908
909
CYCLES32NSeq(add, numregs);
910
CYCLES16NSeq(R(15), 1);
911
912
for (register uint8_t n = 0; n < 8; ++n)
913
if (code & (0x1 << n))
914
{
915
MEM.Write32 (add, R(n));
916
add += 4;
917
}
918
if (code & (0x1 << 8)) // PUSH LR
919
{
920
MEM.Write32 (add, R(14));
921
}
922
}
923
924
R(13) = newsp;
925
}
926
927
// multiple load/store
928
THUMB(STMLDM)
929
{
930
if (((code >> 12) & 0xF) != 0xC)
931
{
932
met_abort("Bits 12-15 must be 1100 for STM/LDM instructions");
933
}
934
935
static const uint8_t NumBits[] =
936
{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
937
938
uint8_t numregs =
939
NumBits[(code >> 4) & 0xF] +
940
NumBits[ code & 0xF];
941
942
uint32_t add = R(Rb) & 0xFFFFFFFC;
943
944
if (code & (0x1 << 11)) // LDMIA
945
{
946
CYCLES32NSeq(add, numregs);
947
ICYCLES(1);
948
949
for (register uint8_t n = 0; n < 8; ++n)
950
if (code & (0x1 << n))
951
{
952
R(n) = MEM.Read32 (add);
953
add += 4;
954
}
955
956
CYCLES16Seq(R(15), 1);
957
}
958
else // STMIA
959
{
960
CYCLES32NSeq(add, numregs);
961
CYCLES16NSeq(R(15), 1);
962
963
for (register uint8_t n = 0; n < 8; ++n)
964
if (code & (0x1 << n))
965
{
966
MEM.Write32 (add, R(n));
967
add += 4;
968
}
969
}
970
971
if (!(code & (0x1 << Rb)))
972
R(Rb) = R(Rb) + 4 * numregs;
973
}
974
975
// conditional branch
976
THUMB(_CondBranch)
977
{
978
if (((code >> 12) & 0xF) != 0xD)
979
{
980
met_abort("Bits 12-15 must be 1101 for branch on condition instructions");
981
}
982
983
bool branch = false;
984
switch ((code >> 8) & 0xF)
985
{
986
case 0x0: // BEQ
987
if (FLAG_Z)
988
branch = true;
989
break;
990
case 0x1: // BNE
991
if (!FLAG_Z)
992
branch = true;
993
break;
994
case 0x2: // BCS
995
if (FLAG_C)
996
branch = true;
997
break;
998
case 0x3: // BCC
999
if (!FLAG_C)
1000
branch = true;
1001
break;
1002
case 0x4: // BMI
1003
if (FLAG_N)
1004
branch = true;
1005
break;
1006
case 0x5: // BPL
1007
if (!FLAG_N)
1008
branch = true;
1009
break;
1010
case 0x6: // BVS
1011
if (FLAG_V)
1012
branch = true;
1013
break;
1014
case 0x7: // BVC
1015
if (!FLAG_V)
1016
branch = true;
1017
break;
1018
case 0x8: // BHI
1019
if (FLAG_C && !FLAG_Z)
1020
branch = true;
1021
break;
1022
case 0x9: // BLS
1023
if (!FLAG_C || FLAG_Z)
1024
branch = true;
1025
break;
1026
case 0xA: // BGE
1027
if (FLAG_N == FLAG_V)
1028
branch = true;
1029
break;
1030
case 0xB: // BLT
1031
if (FLAG_N != FLAG_V)
1032
branch = true;
1033
break;
1034
case 0xC: // BGT
1035
if (!FLAG_Z && FLAG_N == FLAG_V)
1036
branch = true;
1037
break;
1038
case 0xD: // BLE
1039
if (FLAG_Z || FLAG_N != FLAG_V)
1040
branch = true;
1041
break;
1042
case 0xE: // undefined
1043
met_abort("Undefined branch on condition");
1044
break;
1045
case 0xF: // reserved for SWI instruction
1046
met_abort("Bits 8-11 must not be 1111 for branch instruction");
1047
break;
1048
}
1049
1050
if (branch)
1051
{
1052
R(15) += (((int32_t)(int8_t)Imm) << 1) + 2;
1053
1054
CYCLES16NSeq(R(15), 3);
1055
}
1056
else
1057
CYCLES16Seq(R(15), 1);
1058
}
1059
1060
// software interrupt and breakpoint
1061
THUMB(SWI)
1062
{
1063
CPU.SoftwareInterrupt(code & 0xFF);
1064
1065
// FIXME seems wrong !
1066
CYCLES32NSeq(0, 3);
1067
}
1068
1069
// unconditional branch
1070
THUMB(B)
1071
{
1072
if (((code >> 11) & 0x1F) != 0x1C)
1073
{
1074
met_abort("Bits 11-15 must be 11100 for branch instructions");
1075
}
1076
1077
int32_t off = (code & 0x7FF) << 1;
1078
if (off & 0x800)
1079
off |= 0xFFFFF000; // extends sign bit
1080
R(15) += off + 2;
1081
1082
CYCLES16NSeq(R(15), 3);
1083
}
1084
1085
// long branch with link
1086
THUMB(_BL1)
1087
{
1088
if (((code >> 11) & 0x1F) != 0x1E)
1089
{
1090
met_abort("Bits 11-15 must be 11110 for long branch instructions");
1091
}
1092
1093
if (code & (0x1 << 10)) // negative offset
1094
R(14) = R(15) + (((int32_t)((code & 0x7FF) << 12)) | 0xFF800000);
1095
else
1096
R(14) = R(15) + ((code & 0x7FF) << 12);
1097
1098
CYCLES16Seq(R(15), 1);
1099
}
1100
1101
THUMB(_BL2)
1102
{
1103
// XXX we dont do check here to be sure this instruction is called after
1104
// BL1
1105
uint32_t add = R(14) + ((code & 0x7FF) << 1);
1106
1107
if (code & (0x1 << 11)) // BL
1108
{
1109
R(14) = (R(15)-2) | 0x1;
1110
R(15) = (add & 0xFFFFFFFE) + 2;
1111
}
1112
else // BLX
1113
{
1114
met_abort("BLX not implemented");
1115
if (code & 0x1)
1116
met_abort("BLX with odd address");
1117
FLAG_T = 0;
1118
}
1119
1120
CYCLES16NSeq(R(15), 3);
1121
}
1122
1123
NITHUMB(_Code)
1124
{
1125
switch (code >> 13)
1126
{
1127
case 0: // 000
1128
if ((code & 0x1800) == 0x1800) // 00011
1129
tADDSUB();
1130
else // 000
1131
t_Shift();
1132
break;
1133
case 1: // 001
1134
t_Imm();
1135
break;
1136
case 2: // 010
1137
switch ((code >> 10) & 0x7)
1138
{
1139
case 0: // 010000
1140
t_ALU();
1141
break;
1142
case 1: // 010001
1143
t_HiRegOp();
1144
break;
1145
case 2:
1146
case 3: // 01001x
1147
tLDRimm();
1148
break;
1149
default:
1150
tSTRLDRreg();
1151
break;
1152
}
1153
break;
1154
case 3: // 011
1155
tSTRLDRoff();
1156
break;
1157
case 4: // 100
1158
if (code & (0x1 << 12)) // 1001
1159
tSTRLDRsp();
1160
else // 100
1161
tLDRHSTRHoff();
1162
break;
1163
case 5: // 101
1164
if (code & (0x1 << 12)) // 1011
1165
{
1166
switch (code & 0x0600)
1167
{
1168
case 0x0000: // 1011x00
1169
tADDsp();
1170
break;
1171
case 0x0400: // 1011x10
1172
tPUSHPOP();
1173
break;
1174
default:
1175
met_abort("not implemented or unknown");
1176
break;
1177
}
1178
}
1179
else // 101
1180
tADDpcsp();
1181
break;
1182
case 6: // 110
1183
if (code & (0x1 << 12)) // 1101
1184
{
1185
if ((code & 0x0F00) == 0x0F00) // 11011111
1186
tSWI();
1187
else // 1101xxxx
1188
t_CondBranch();
1189
}
1190
else // 1100
1191
tSTMLDM();
1192
break;
1193
case 7: // 111
1194
switch ((code >> 11) & 0x3)
1195
{
1196
case 0: // 11100
1197
tB();
1198
break;
1199
case 2: // 11110
1200
t_BL1();
1201
break;
1202
case 3: // 11111
1203
t_BL2();
1204
break;
1205
default:
1206
met_abort("not implemented or unknown");
1207
break;
1208
}
1209
break;
1210
}
1211
}
1212
}
1213
1214
#undef Rb
1215
#undef Ro
1216
#undef Rs
1217
#undef Rd
1218
#undef Imm
1219
1220
#undef THUMB
1221
1222
#endif
1223
1224