summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/arm7/arm7help.h
blob: a62722accfa4cf43f533ca7f80e6c1719b58e050 (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
// license:BSD-3-Clause
// copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz
/* ARM7 core helper Macros / Functions */

/* Macros that need to be defined according to the cpu implementation specific need */
#define ARM7REG(reg)        m_r[reg]
#define ARM7_ICOUNT         m_icount


/***************
 * helper funcs
 ***************/

// TODO LD:
//  - SIGN_BITS_DIFFER = THUMB_SIGN_BITS_DIFFER
//  - do while (0)
//  - HandleALUAddFlags = HandleThumbALUAddFlags except for PC incr
//  - HandleALUSubFlags = HandleThumbALUSubFlags except for PC incr

#define IsNeg(i) ((i) >> 31)
#define IsPos(i) ((~(i)) >> 31)

/* Set NZCV flags for ADDS / SUBS */
#define HandleALUAddFlags(rd, rn, op2)                                                \
	if (insn & INSN_S)                                                                  \
	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                       \
				| (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \
				| (((IsNeg(rn) & IsNeg(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsNeg(op2) & IsPos(rd))) ? C_MASK : 0) \
				| HandleALUNZFlags(rd)));                                               \
	R15 += 4;

#define HandleThumbALUAddFlags(rd, rn, op2)                                                       \
	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                                   \
				| (((!THUMB_SIGN_BITS_DIFFER(rn, op2)) && THUMB_SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \
				| (((~(rn)) < (op2)) << C_BIT)                                                      \
				| HandleALUNZFlags(rd)));                                                           \
	R15 += 2;

#define DRCHandleThumbALUAddFlags(rd, rn, op2)                                                  \
	UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | V_MASK | C_MASK));                   \
	DRCHandleALUNZFlags(rd);                                                                    \
	UML_XOR(block, uml::I1, rn, ~0);                                                            \
	UML_CMP(block, uml::I1, op2);                                                               \
	UML_MOVc(block, uml::COND_B, uml::I1, C_BIT);                                               \
	UML_MOVc(block, uml::COND_AE, uml::I1, 0);                                                  \
	UML_OR(block, uml::I0, uml::I0, uml::I1);                                                   \
	UML_XOR(block, uml::I1, rn, op2);                                                           \
	UML_XOR(block, uml::I2, rn, rd);                                                            \
	UML_AND(block, uml::I1, uml::I1, uml::I2);                                                  \
	UML_TEST(block, uml::I1, 1 << 31);                                                          \
	UML_MOVc(block, uml::COND_NZ, uml::I1, V_BIT);                                              \
	UML_MOVc(block, uml::COND_Z, uml::I1, 0);                                                   \
	UML_OR(block, uml::I0, uml::I0, uml::I1);                                                   \
	UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                                                  \
	UML_ADD(block, DRC_PC, DRC_PC, 2);

#define HandleALUSubFlags(rd, rn, op2)                                                                         \
	if (insn & INSN_S)                                                                                           \
	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                                                \
				| ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) << V_BIT)                             \
				| (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
				| HandleALUNZFlags(rd)));                                                                        \
	R15 += 4;

#define HandleThumbALUSubFlags(rd, rn, op2)                                                                    \
	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                                                \
				| ((THUMB_SIGN_BITS_DIFFER(rn, op2) && THUMB_SIGN_BITS_DIFFER(rn, rd)) << V_BIT)                 \
				| (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
				| HandleALUNZFlags(rd)));                                                                        \
	R15 += 2;

#define DRCHandleThumbALUSubFlags(rd, rn, op2)                                                  \
	UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | V_MASK | C_MASK));                   \
	DRCHandleALUNZFlags(rd);                                                                    \
	UML_XOR(block, uml::I1, rn, op2);                                                           \
	UML_XOR(block, uml::I2, rn, rd);                                                            \
	UML_AND(block, uml::I1, uml::I1, uml::I2);                                                  \
	UML_TEST(block, uml::I1, 1 << 31);                                                          \
	UML_MOVc(block, uml::COND_NZ, uml::I1, V_BIT);                                              \
	UML_MOVc(block, uml::COND_Z, uml::I1, 0);                                                   \
	UML_OR(block, uml::I0, uml::I0, uml::I1);                                                   \
	UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                                                 \
	UML_AND(block, uml::I0, rd, 1 << 31);                                                       \
	UML_AND(block, uml::I1, op2, 1 << 31);                                                      \
	UML_AND(block, uml::I2, rn, 1 << 31);                                                       \
	UML_XOR(block, uml::I2, uml::I2, ~0);                                                       \
	UML_AND(block, uml::I1, uml::I1, uml::I2);                                                  \
	UML_AND(block, uml::I2, uml::I2, uml::I0);                                                  \
	UML_OR(block, uml::I1, uml::I1, uml::I2);                                                   \
	UML_AND(block, uml::I2, op2, 1 << 31);                                                      \
	UML_AND(block, uml::I2, uml::I2, uml::I0);                                                  \
	UML_OR(block, uml::I1, uml::I1, uml::I2);                                                   \
	UML_TEST(block, uml::I1, 1 << 31);                                                          \
	UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK);                                             \
	UML_MOVc(block, uml::COND_Z, uml::I0, 0);                                                   \
	UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                                                 \
	UML_ADD(block, DRC_PC, DRC_PC, 2);

/* Set NZC flags for logical operations. */

// This macro (which I didn't write) - doesn't make it obvious that the SIGN BIT = 31, just as the N Bit does,
// therefore, N is set by default
#define HandleALUNZFlags(rd)               \
	(((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))

#define DRCHandleALUNZFlags(rd)                            \
	UML_AND(block, uml::I0, rd, SIGN_BIT);                 \
	UML_CMP(block, rd, 0);                                 \
	UML_MOVc(block, uml::COND_E, uml::I1, 1);              \
	UML_MOVc(block, uml::COND_NE, uml::I1, 0);             \
	UML_ROLINS(block, uml::I0, uml::I1, Z_BIT, 1 << Z_BIT);

// Long ALU Functions use bit 63
#define HandleLongALUNZFlags(rd)                            \
	((((rd) & ((uint64_t)1 << 63)) >> 32) | ((!(rd)) << Z_BIT))

#define HandleALULogicalFlags(rd, sc)                  \
	if (insn & INSN_S)                                   \
	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | C_MASK)) \
				| HandleALUNZFlags(rd)                   \
				| (((sc) != 0) << C_BIT)));              \
	R15 += 4;

#define DRC_RD      uml::mem(&GetRegister(rd))
#define DRC_RS      uml::mem(&GetRegister(rs))
#define DRC_CPSR    uml::mem(&GET_CPSR)
#define DRC_PC      uml::mem(&R15)
#define DRC_REG(i)  uml::mem(&m_r[(i)])

#define DRCHandleALULogicalFlags(rd, sc)                                \
	if (insn & INSN_S)                                                  \
	{                                                                   \
		UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | C_MASK); \
		DRCHandleALUNZFlags(rd);                                        \
		UML_TEST(block, sc, ~0);                                        \
		UML_MOVc(block, uml::COND_Z, uml::I1, C_BIT);                   \
		UML_MOVc(block, uml::COND_NZ, uml::I1, 0);                      \
		UML_OR(block, uml::I0, uml::I0, uml::I1);                       \
		UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                     \
	}                                                                   \
	UML_ADD(block, DRC_PC, DRC_PC, 4);


// used to be functions, but no longer a need, so we'll use define for better speed.
#define GetRegister(rIndex)        m_r[m_reg_group[rIndex]]
#define SetRegister(rIndex, value) m_r[m_reg_group[rIndex]] = value

#define GetModeRegister(mode, rIndex)        m_r[sRegisterTable[mode][rIndex]]
#define SetModeRegister(mode, rIndex, value) m_r[sRegisterTable[mode][rIndex]] = value


/* Macros that can be re-defined for custom cpu implementations - The core expects these to be defined */
/* In this case, we are using the default arm7 handlers (supplied by the core)
   - but simply changes these and define your own if needed for cpu implementation specific needs */
#define READ8(addr)         arm7_cpu_read8(addr)
#define WRITE8(addr,data)   arm7_cpu_write8(addr,data)
#define READ16(addr)        arm7_cpu_read16(addr)
#define WRITE16(addr,data)  arm7_cpu_write16(addr,data)
#define READ32(addr)        arm7_cpu_read32(addr)
#define WRITE32(addr,data)  arm7_cpu_write32(addr,data)
#define PTR_READ32          &arm7_cpu_read32
#define PTR_WRITE32         &arm7_cpu_write32

#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))))