summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/arm7/arm7core.h
blob: 67e9b918eed7e14742ca3ce18901f9803c22f7c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
/*****************************************************************************
 *
 *   arm7core.h
 *   Portable ARM7TDMI Core Emulator
 *
 *   Copyright Steve Ellenoff, all rights reserved.
 *
 *   - This source code is released as freeware for non-commercial purposes.
 *   - You are free to use and redistribute this code in modified or
 *     unmodified form, provided you list me in the credits.
 *   - If you modify this source code, you must add a notice to each modified
 *     source file that it has been changed.  If you're a nice person, you
 *     will clearly mark each change too.  :)
 *   - If you wish to use this for commercial purposes, please contact me at
 *     sellenoff@hotmail.com
 *   - The author of this copywritten work reserves the right to change the
 *     terms of its usage and license at any time, including retroactively
 *   - This entire notice must remain in the source code.
 *
 *  This work is based on:
 *  #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
 *  #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
 *
 *****************************************************************************

 This file contains everything related to the arm7 core itself, and is presumed
 to be cpu implementation non-specific, ie, applies to only the core.

 ******************************************************************************/

#pragma once

#ifndef __ARM7CORE_H__
#define __ARM7CORE_H__


/****************************************************************************************************
 *  INTERRUPT LINES/EXCEPTIONS
 ***************************************************************************************************/
enum
{
    ARM7_IRQ_LINE=0, ARM7_FIRQ_LINE,
    ARM7_ABORT_EXCEPTION, ARM7_ABORT_PREFETCH_EXCEPTION, ARM7_UNDEFINE_EXCEPTION,
    ARM7_NUM_LINES
};
// Really there's only 1 ABORT Line.. and cpu decides whether it's during data fetch or prefetch, but we let the user specify

/****************************************************************************************************
 *  ARM7 CORE REGISTERS
 ***************************************************************************************************/
enum
{
    ARM7_PC = 0,
    ARM7_R0, ARM7_R1, ARM7_R2, ARM7_R3, ARM7_R4, ARM7_R5, ARM7_R6, ARM7_R7,
    ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15,
    ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14,
    ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR,
    ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR
};

/* There are 36 Unique - 32 bit processor registers */
/* Each mode has 17 registers (except user & system, which have 16) */
/* This is a list of each *unique* register */
enum
{
    /* All modes have the following */
    eR0 = 0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
    eR8, eR9, eR10, eR11, eR12,
    eR13, /* Stack Pointer */
    eR14, /* Link Register (holds return address) */
    eR15, /* Program Counter */
    eCPSR, /* Current Status Program Register */

    /* Fast Interrupt - Bank switched registers */
    eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, eR13_FIQ, eR14_FIQ, eSPSR_FIQ,

    /* IRQ - Bank switched registers */
    eR13_IRQ, eR14_IRQ, eSPSR_IRQ,

    /* Supervisor/Service Mode - Bank switched registers */
    eR13_SVC, eR14_SVC, eSPSR_SVC,

    /* Abort Mode - Bank switched registers */
    eR13_ABT, eR14_ABT, eSPSR_ABT,

    /* Undefined Mode - Bank switched registers */
    eR13_UND, eR14_UND, eSPSR_UND,

    kNumRegisters
};

/* Coprocessor-related macros */
#define COPRO_TLB_BASE      	cpustate->tlbBase
#define COPRO_TLB_BASE_MASK                 0xffffc000
#define COPRO_TLB_VADDR_FLTI_MASK           0xfff00000
#define COPRO_TLB_VADDR_FLTI_MASK_SHIFT     18
#define COPRO_TLB_VADDR_CSLTI_MASK          0x000ff000
#define COPRO_TLB_VADDR_CSLTI_MASK_SHIFT    10
#define COPRO_TLB_VADDR_FSLTI_MASK          0x000ffc00
#define COPRO_TLB_VADDR_FSLTI_MASK_SHIFT    8
#define COPRO_TLB_CFLD_ADDR_MASK            0xfffffc00
#define COPRO_TLB_CFLD_ADDR_MASK_SHIFT      10
#define COPRO_TLB_SECTION_PAGE_MASK         0xfff00000
#define COPRO_TLB_LARGE_PAGE_MASK           0xffff0000
#define COPRO_TLB_SMALL_PAGE_MASK           0xfffff000
#define COPRO_TLB_TINY_PAGE_MASK            0xfffffc00
#define COPRO_TLB_UNMAPPED                  0
#define COPRO_TLB_LARGE_PAGE                1
#define COPRO_TLB_SMALL_PAGE                2
#define COPRO_TLB_TINY_PAGE                 3
#define COPRO_TLB_COARSE_TABLE              1
#define COPRO_TLB_SECTION_TABLE             2
#define COPRO_TLB_FINE_TABLE                3

#define COPRO_CTRL            cpustate->control
#define COPRO_CTRL_MMU_EN                   0x00000001
#define COPRO_CTRL_ADDRFAULT_EN             0x00000002
#define COPRO_CTRL_DCACHE_EN                0x00000004
#define COPRO_CTRL_WRITEBUF_EN              0x00000008
#define COPRO_CTRL_ENDIAN                   0x00000080
#define COPRO_CTRL_SYSTEM                   0x00000100
#define COPRO_CTRL_ROM                      0x00000200
#define COPRO_CTRL_ICACHE_EN                0x00001000
#define COPRO_CTRL_INTVEC_ADJUST            0x00002000
#define COPRO_CTRL_ADDRFAULT_EN_SHIFT       1
#define COPRO_CTRL_DCACHE_EN_SHIFT          2
#define COPRO_CTRL_WRITEBUF_EN_SHIFT        3
#define COPRO_CTRL_ENDIAN_SHIFT             7
#define COPRO_CTRL_SYSTEM_SHIFT             8
#define COPRO_CTRL_ROM_SHIFT                9
#define COPRO_CTRL_ICACHE_EN_SHIFT          12
#define COPRO_CTRL_INTVEC_ADJUST_SHIFT      13
#define COPRO_CTRL_LITTLE_ENDIAN            0
#define COPRO_CTRL_BIG_ENDIAN               1
#define COPRO_CTRL_INTVEC_0                 0
#define COPRO_CTRL_INTVEC_F                 1
#define COPRO_CTRL_MASK                     0x0000338f

/* Coprocessor Registers */
#define ARM7COPRO_REGS \
    UINT32 control; \
    UINT32 tlbBase;

enum
{
	eARM_ARCHFLAGS_T	= 1,		// Thumb present
	eARM_ARCHFLAGS_E	= 2,		// extended DSP operations present (only for v5+)
	eARM_ARCHFLAGS_J	= 4,		// "Jazelle" (direct execution of Java bytecode)
	eARM_ARCHFLAGS_MMU	= 8,		// has on-board MMU (traditional ARM style like the SA1110)
	eARM_ARCHFLAGS_SA	= 16,		// StrongARM extensions (enhanced TLB)
	eARM_ARCHFLAGS_XSCALE	= 32,		// XScale extensions (CP14, enhanced TLB)
};

#define ARM7CORE_REGS                   \
    UINT32 sArmRegister[kNumRegisters]; \
    UINT8 pendingIrq;                   \
    UINT8 pendingFiq;                   \
    UINT8 pendingAbtD;                  \
    UINT8 pendingAbtP;                  \
    UINT8 pendingUnd;                   \
    UINT8 pendingSwi;                   \
    INT32 iCount;			\
    cpu_irq_callback irq_callback;		\
    running_device *device;		\
    const address_space *program;


/* CPU state struct */
typedef struct
{
	ARM7CORE_REGS			// these must be included in your cpu specific register implementation
	ARM7COPRO_REGS

	UINT8 archRev;			// ARM architecture revision (3, 4, and 5 are valid)
	UINT8 archFlags;		// architecture flags

} arm_state;

/****************************************************************************************************
 *  VARIOUS INTERNAL STRUCS/DEFINES/ETC..
 ***************************************************************************************************/
// Mode values come from bit 4-0 of CPSR, but we are ignoring bit 4 here, since bit 4 always = 1 for valid modes
enum
{
    eARM7_MODE_USER = 0x0,      // Bit: 4-0 = 10000
    eARM7_MODE_FIQ  = 0x1,      // Bit: 4-0 = 10001
    eARM7_MODE_IRQ  = 0x2,      // Bit: 4-0 = 10010
    eARM7_MODE_SVC  = 0x3,      // Bit: 4-0 = 10011
    eARM7_MODE_ABT  = 0x7,      // Bit: 4-0 = 10111
    eARM7_MODE_UND  = 0xb,      // Bit: 4-0 = 11011
    eARM7_MODE_SYS  = 0xf       // Bit: 4-0 = 11111
};

#define ARM7_NUM_MODES 0x10

static const int thumbCycles[256] =
{
//  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 1
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 3
    1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // 4
    2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // 5
    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 6
    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 7
    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 8
    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,  // 9
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // a
    1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1,  // b
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,  // c
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,  // d
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // e
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2   // f
};

/* 17 processor registers are visible at any given time,
 * banked depending on processor mode.
 */

static const int sRegisterTable[ARM7_NUM_MODES][18] =
{
    { /* USR */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8, eR9, eR10, eR11, eR12,
        eR13, eR14,
        eR15, eCPSR  // No SPSR in this mode
    },
    { /* FIQ */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ,
        eR13_FIQ, eR14_FIQ,
        eR15, eCPSR, eSPSR_FIQ
    },
    { /* IRQ */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8, eR9, eR10, eR11, eR12,
        eR13_IRQ, eR14_IRQ,
        eR15, eCPSR, eSPSR_IRQ
    },
    { /* SVC */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8, eR9, eR10, eR11, eR12,
        eR13_SVC, eR14_SVC,
        eR15, eCPSR, eSPSR_SVC
    },
    {0}, {0}, {0},        // values for modes 4,5,6 are not valid
    { /* ABT */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8, eR9, eR10, eR11, eR12,
        eR13_ABT, eR14_ABT,
        eR15, eCPSR, eSPSR_ABT
    },
    {0}, {0}, {0},        // values for modes 8,9,a are not valid!
    { /* UND */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8, eR9, eR10, eR11, eR12,
        eR13_UND, eR14_UND,
        eR15, eCPSR, eSPSR_UND
    },
    {0}, {0}, {0},        // values for modes c,d, e are not valid!
    { /* SYS */
        eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7,
        eR8, eR9, eR10, eR11, eR12,
        eR13, eR14,
        eR15, eCPSR  // No SPSR in this mode
    }
};

#define N_BIT   31
#define Z_BIT   30
#define C_BIT   29
#define V_BIT   28
#define Q_BIT   27
#define I_BIT   7
#define F_BIT   6
#define T_BIT   5   // Thumb mode

#define N_MASK  ((UINT32)(1 << N_BIT)) /* Negative flag */
#define Z_MASK  ((UINT32)(1 << Z_BIT)) /* Zero flag */
#define C_MASK  ((UINT32)(1 << C_BIT)) /* Carry flag */
#define V_MASK  ((UINT32)(1 << V_BIT)) /* oVerflow flag */
#define Q_MASK  ((UINT32)(1 << Q_BIT)) /* signed overflow for QADD, MAC */
#define I_MASK  ((UINT32)(1 << I_BIT)) /* Interrupt request disable */
#define F_MASK  ((UINT32)(1 << F_BIT)) /* Fast interrupt request disable */
#define T_MASK  ((UINT32)(1 << T_BIT)) /* Thumb Mode flag */

#define N_IS_SET(pc)    ((pc) & N_MASK)
#define Z_IS_SET(pc)    ((pc) & Z_MASK)
#define C_IS_SET(pc)    ((pc) & C_MASK)
#define V_IS_SET(pc)    ((pc) & V_MASK)
#define Q_IS_SET(pc)    ((pc) & Q_MASK)
#define I_IS_SET(pc)    ((pc) & I_MASK)
#define F_IS_SET(pc)    ((pc) & F_MASK)
#define T_IS_SET(pc)    ((pc) & T_MASK)

#define N_IS_CLEAR(pc)  (!N_IS_SET(pc))
#define Z_IS_CLEAR(pc)  (!Z_IS_SET(pc))
#define C_IS_CLEAR(pc)  (!C_IS_SET(pc))
#define V_IS_CLEAR(pc)  (!V_IS_SET(pc))
#define Q_IS_CLEAR(pc)  (!Q_IS_SET(pc))
#define I_IS_CLEAR(pc)  (!I_IS_SET(pc))
#define F_IS_CLEAR(pc)  (!F_IS_SET(pc))
#define T_IS_CLEAR(pc)  (!T_IS_SET(pc))

/* Deconstructing an instruction */
// todo: use these in all places (including dasm file)
#define INSN_COND           ((UINT32)0xf0000000u)
#define INSN_SDT_L          ((UINT32)0x00100000u)
#define INSN_SDT_W          ((UINT32)0x00200000u)
#define INSN_SDT_B          ((UINT32)0x00400000u)
#define INSN_SDT_U          ((UINT32)0x00800000u)
#define INSN_SDT_P          ((UINT32)0x01000000u)
#define INSN_BDT_L          ((UINT32)0x00100000u)
#define INSN_BDT_W          ((UINT32)0x00200000u)
#define INSN_BDT_S          ((UINT32)0x00400000u)
#define INSN_BDT_U          ((UINT32)0x00800000u)
#define INSN_BDT_P          ((UINT32)0x01000000u)
#define INSN_BDT_REGS       ((UINT32)0x0000ffffu)
#define INSN_SDT_IMM        ((UINT32)0x00000fffu)
#define INSN_MUL_A          ((UINT32)0x00200000u)
#define INSN_MUL_RM         ((UINT32)0x0000000fu)
#define INSN_MUL_RS         ((UINT32)0x00000f00u)
#define INSN_MUL_RN         ((UINT32)0x0000f000u)
#define INSN_MUL_RD         ((UINT32)0x000f0000u)
#define INSN_I              ((UINT32)0x02000000u)
#define INSN_OPCODE         ((UINT32)0x01e00000u)
#define INSN_S              ((UINT32)0x00100000u)
#define INSN_BL             ((UINT32)0x01000000u)
#define INSN_BRANCH         ((UINT32)0x00ffffffu)
#define INSN_SWI            ((UINT32)0x00ffffffu)
#define INSN_RN             ((UINT32)0x000f0000u)
#define INSN_RD             ((UINT32)0x0000f000u)
#define INSN_OP2            ((UINT32)0x00000fffu)
#define INSN_OP2_SHIFT      ((UINT32)0x00000f80u)
#define INSN_OP2_SHIFT_TYPE ((UINT32)0x00000070u)
#define INSN_OP2_RM         ((UINT32)0x0000000fu)
#define INSN_OP2_ROTATE     ((UINT32)0x00000f00u)
#define INSN_OP2_IMM        ((UINT32)0x000000ffu)
#define INSN_OP2_SHIFT_TYPE_SHIFT   4
#define INSN_OP2_SHIFT_SHIFT        7
#define INSN_OP2_ROTATE_SHIFT       8
#define INSN_MUL_RS_SHIFT           8
#define INSN_MUL_RN_SHIFT           12
#define INSN_MUL_RD_SHIFT           16
#define INSN_OPCODE_SHIFT           21
#define INSN_RN_SHIFT               16
#define INSN_RD_SHIFT               12
#define INSN_COND_SHIFT             28

#define INSN_COPRO_N        ((UINT32) 0x00100000u)
#define INSN_COPRO_CREG     ((UINT32) 0x000f0000u)
#define INSN_COPRO_AREG     ((UINT32) 0x0000f000u)
#define INSN_COPRO_CPNUM    ((UINT32) 0x00000f00u)
#define INSN_COPRO_OP2      ((UINT32) 0x000000e0u)
#define INSN_COPRO_OP3      ((UINT32) 0x0000000fu)
#define INSN_COPRO_N_SHIFT          20
#define INSN_COPRO_CREG_SHIFT       16
#define INSN_COPRO_AREG_SHIFT       12
#define INSN_COPRO_CPNUM_SHIFT	    8
#define INSN_COPRO_OP2_SHIFT        5

#define THUMB_INSN_TYPE     ((UINT16)0xf000)
#define THUMB_COND_TYPE     ((UINT16)0x0f00)
#define THUMB_GROUP4_TYPE   ((UINT16)0x0c00)
#define THUMB_GROUP5_TYPE   ((UINT16)0x0e00)
#define THUMB_GROUP5_RM     ((UINT16)0x01c0)
#define THUMB_GROUP5_RN     ((UINT16)0x0038)
#define THUMB_GROUP5_RD     ((UINT16)0x0007)
#define THUMB_ADDSUB_RNIMM  ((UINT16)0x01c0)
#define THUMB_ADDSUB_RS     ((UINT16)0x0038)
#define THUMB_ADDSUB_RD     ((UINT16)0x0007)
#define THUMB_INSN_ADDSUB   ((UINT16)0x0800)
#define THUMB_INSN_CMP      ((UINT16)0x0800)
#define THUMB_INSN_SUB      ((UINT16)0x0800)
#define THUMB_INSN_IMM_RD   ((UINT16)0x0700)
#define THUMB_INSN_IMM_S    ((UINT16)0x0080)
#define THUMB_INSN_IMM      ((UINT16)0x00ff)
#define THUMB_ADDSUB_TYPE   ((UINT16)0x0600)
#define THUMB_HIREG_OP      ((UINT16)0x0300)
#define THUMB_HIREG_H       ((UINT16)0x00c0)
#define THUMB_HIREG_RS      ((UINT16)0x0038)
#define THUMB_HIREG_RD      ((UINT16)0x0007)
#define THUMB_STACKOP_TYPE  ((UINT16)0x0f00)
#define THUMB_STACKOP_L     ((UINT16)0x0800)
#define THUMB_STACKOP_RD    ((UINT16)0x0700)
#define THUMB_ALUOP_TYPE    ((UINT16)0x03c0)
#define THUMB_BLOP_LO       ((UINT16)0x0800)
#define THUMB_BLOP_OFFS     ((UINT16)0x07ff)
#define THUMB_SHIFT_R       ((UINT16)0x0800)
#define THUMB_SHIFT_AMT     ((UINT16)0x07c0)
#define THUMB_HALFOP_L      ((UINT16)0x0800)
#define THUMB_HALFOP_OFFS   ((UINT16)0x07c0)
#define THUMB_BRANCH_OFFS   ((UINT16)0x07ff)
#define THUMB_LSOP_L        ((UINT16)0x0800)
#define THUMB_LSOP_OFFS     ((UINT16)0x07c0)
#define THUMB_MULTLS        ((UINT16)0x0800)
#define THUMB_MULTLS_BASE   ((UINT16)0x0700)
#define THUMB_RELADDR_SP    ((UINT16)0x0800)
#define THUMB_RELADDR_RD    ((UINT16)0x0700)
#define THUMB_INSN_TYPE_SHIFT       12
#define THUMB_COND_TYPE_SHIFT       8
#define THUMB_GROUP4_TYPE_SHIFT     10
#define THUMB_GROUP5_TYPE_SHIFT     9
#define THUMB_ADDSUB_TYPE_SHIFT     9
#define THUMB_INSN_IMM_RD_SHIFT     8
#define THUMB_STACKOP_TYPE_SHIFT    8
#define THUMB_HIREG_OP_SHIFT        8
#define THUMB_STACKOP_RD_SHIFT      8
#define THUMB_MULTLS_BASE_SHIFT     8
#define THUMB_RELADDR_RD_SHIFT      8
#define THUMB_HIREG_H_SHIFT         6
#define THUMB_HIREG_RS_SHIFT        3
#define THUMB_ALUOP_TYPE_SHIFT      6
#define THUMB_SHIFT_AMT_SHIFT       6
#define THUMB_HALFOP_OFFS_SHIFT     6
#define THUMB_LSOP_OFFS_SHIFT       6
#define THUMB_GROUP5_RM_SHIFT       6
#define THUMB_GROUP5_RN_SHIFT       3
#define THUMB_GROUP5_RD_SHIFT       0
#define THUMB_ADDSUB_RNIMM_SHIFT    6
#define THUMB_ADDSUB_RS_SHIFT       3
#define THUMB_ADDSUB_RD_SHIFT       0

enum
{
    OPCODE_AND, /* 0000 */
    OPCODE_EOR, /* 0001 */
    OPCODE_SUB, /* 0010 */
    OPCODE_RSB, /* 0011 */
    OPCODE_ADD, /* 0100 */
    OPCODE_ADC, /* 0101 */
    OPCODE_SBC, /* 0110 */
    OPCODE_RSC, /* 0111 */
    OPCODE_TST, /* 1000 */
    OPCODE_TEQ, /* 1001 */
    OPCODE_CMP, /* 1010 */
    OPCODE_CMN, /* 1011 */
    OPCODE_ORR, /* 1100 */
    OPCODE_MOV, /* 1101 */
    OPCODE_BIC, /* 1110 */
    OPCODE_MVN  /* 1111 */
};

enum
{
    COND_EQ = 0,          /*  Z           equal                   */
    COND_NE,              /* ~Z           not equal               */
    COND_CS, COND_HS = 2, /*  C           unsigned higher or same */
    COND_CC, COND_LO = 3, /* ~C           unsigned lower          */
    COND_MI,              /*  N           negative                */
    COND_PL,              /* ~N           positive or zero        */
    COND_VS,              /*  V           overflow                */
    COND_VC,              /* ~V           no overflow             */
    COND_HI,              /*  C && ~Z     unsigned higher         */
    COND_LS,              /* ~C ||  Z     unsigned lower or same  */
    COND_GE,              /*  N == V      greater or equal        */
    COND_LT,              /*  N != V      less than               */
    COND_GT,              /* ~Z && N == V greater than            */
    COND_LE,              /*  Z || N != V less than or equal      */
    COND_AL,              /*  1           always                  */
    COND_NV               /*  0           never                   */
};

#define LSL(v, s) ((v) << (s))
#define LSR(v, s) ((v) >> (s))
#define ROL(v, s) (LSL((v), (s)) | (LSR((v), 32u - (s))))
#define ROR(v, s) (LSR((v), (s)) | (LSL((v), 32u - (s))))

/* Convenience Macros */
#define R15                     ARM7REG(eR15)
#define SPSR                    17                     // SPSR is always the 18th register in our 0 based array sRegisterTable[][18]
#define GET_CPSR                ARM7REG(eCPSR)
#define SET_CPSR(v)             (GET_CPSR = (v))
#define MODE_FLAG               0xF                    // Mode bits are 4:0 of CPSR, but we ignore bit 4.
#define GET_MODE                (GET_CPSR & MODE_FLAG)
#define SIGN_BIT                ((UINT32)(1 << 31))
#define SIGN_BITS_DIFFER(a, b)  (((a) ^ (b)) >> 31)
/* I really don't know why these were set to 16-bit, the thumb registers are still 32-bit ... */
#define THUMB_SIGN_BIT               ((UINT32)(1 << 31))
#define THUMB_SIGN_BITS_DIFFER(a, b) (((a)^(b)) >> 31)

/* At one point I thought these needed to be cpu implementation specific, but they don't.. */
#define GET_REGISTER(state, reg)       GetRegister(state, reg)
#define SET_REGISTER(state, reg, val)  SetRegister(state, reg, val)
#define ARM7_CHECKIRQ           arm7_check_irq_state(cpustate)

extern write32_device_func arm7_coproc_do_callback;
extern read32_device_func arm7_coproc_rt_r_callback;
extern write32_device_func arm7_coproc_rt_w_callback;
extern void arm7_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr));
extern void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data));

#ifdef UNUSED_DEFINITION
extern char *(*arm7_dasm_cop_dt_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
extern char *(*arm7_dasm_cop_rt_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
extern char *(*arm7_dasm_cop_do_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0);
#endif

#endif /* __ARM7CORE_H__ */