1 // license:BSD-3-Clause
2 // copyright-holders:Steve Ellenoff,R. Belmont,Ryan Holtz
3 /* ARM7 core helper Macros / Functions */
4 
5 /* Macros that need to be defined according to the cpu implementation specific need */
6 #define ARM7REG(reg)        m_r[reg]
7 #define ARM7_ICOUNT         m_icount
8 
9 
10 /***************
11  * helper funcs
12  ***************/
13 
14 // TODO LD:
15 //  - SIGN_BITS_DIFFER = THUMB_SIGN_BITS_DIFFER
16 //  - do while (0)
17 //  - HandleALUAddFlags = HandleThumbALUAddFlags except for PC incr
18 //  - HandleALUSubFlags = HandleThumbALUSubFlags except for PC incr
19 
20 #define IsNeg(i) ((i) >> 31)
21 #define IsPos(i) ((~(i)) >> 31)
22 
23 /* Set NZCV flags for ADDS / SUBS */
24 #define HandleALUAddFlags(rd, rn, op2)                                                \
25 	if (insn & INSN_S)                                                                  \
26 	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                       \
27 				| (((!SIGN_BITS_DIFFER(rn, op2)) && SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \
28 				| (((IsNeg(rn) & IsNeg(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsNeg(op2) & IsPos(rd))) ? C_MASK : 0) \
29 				| HandleALUNZFlags(rd)));                                               \
30 	R15 += 4;
31 
32 #define HandleThumbALUAddFlags(rd, rn, op2)                                                       \
33 	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                                   \
34 				| (((!THUMB_SIGN_BITS_DIFFER(rn, op2)) && THUMB_SIGN_BITS_DIFFER(rn, rd)) << V_BIT) \
35 				| (((~(rn)) < (op2)) << C_BIT)                                                      \
36 				| HandleALUNZFlags(rd)));                                                           \
37 	R15 += 2;
38 
39 #define DRCHandleThumbALUAddFlags(rd, rn, op2)                                                  \
40 	UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | V_MASK | C_MASK));                   \
41 	DRCHandleALUNZFlags(rd);                                                                    \
42 	UML_XOR(block, uml::I1, rn, ~0);                                                            \
43 	UML_CMP(block, uml::I1, op2);                                                               \
44 	UML_MOVc(block, uml::COND_B, uml::I1, C_BIT);                                               \
45 	UML_MOVc(block, uml::COND_AE, uml::I1, 0);                                                  \
46 	UML_OR(block, uml::I0, uml::I0, uml::I1);                                                   \
47 	UML_XOR(block, uml::I1, rn, op2);                                                           \
48 	UML_XOR(block, uml::I2, rn, rd);                                                            \
49 	UML_AND(block, uml::I1, uml::I1, uml::I2);                                                  \
50 	UML_TEST(block, uml::I1, 1 << 31);                                                          \
51 	UML_MOVc(block, uml::COND_NZ, uml::I1, V_BIT);                                              \
52 	UML_MOVc(block, uml::COND_Z, uml::I1, 0);                                                   \
53 	UML_OR(block, uml::I0, uml::I0, uml::I1);                                                   \
54 	UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                                                  \
55 	UML_ADD(block, DRC_PC, DRC_PC, 2);
56 
57 #define HandleALUSubFlags(rd, rn, op2)                                                                         \
58 	if (insn & INSN_S)                                                                                           \
59 	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                                                \
60 				| ((SIGN_BITS_DIFFER(rn, op2) && SIGN_BITS_DIFFER(rn, rd)) << V_BIT)                             \
61 				| (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
62 				| HandleALUNZFlags(rd)));                                                                        \
63 	R15 += 4;
64 
65 #define HandleThumbALUSubFlags(rd, rn, op2)                                                                    \
66 	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | V_MASK | C_MASK))                                                \
67 				| ((THUMB_SIGN_BITS_DIFFER(rn, op2) && THUMB_SIGN_BITS_DIFFER(rn, rd)) << V_BIT)                 \
68 				| (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? C_MASK : 0) \
69 				| HandleALUNZFlags(rd)));                                                                        \
70 	R15 += 2;
71 
72 #define DRCHandleThumbALUSubFlags(rd, rn, op2)                                                  \
73 	UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | V_MASK | C_MASK));                   \
74 	DRCHandleALUNZFlags(rd);                                                                    \
75 	UML_XOR(block, uml::I1, rn, op2);                                                           \
76 	UML_XOR(block, uml::I2, rn, rd);                                                            \
77 	UML_AND(block, uml::I1, uml::I1, uml::I2);                                                  \
78 	UML_TEST(block, uml::I1, 1 << 31);                                                          \
79 	UML_MOVc(block, uml::COND_NZ, uml::I1, V_BIT);                                              \
80 	UML_MOVc(block, uml::COND_Z, uml::I1, 0);                                                   \
81 	UML_OR(block, uml::I0, uml::I0, uml::I1);                                                   \
82 	UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                                                 \
83 	UML_AND(block, uml::I0, rd, 1 << 31);                                                       \
84 	UML_AND(block, uml::I1, op2, 1 << 31);                                                      \
85 	UML_AND(block, uml::I2, rn, 1 << 31);                                                       \
86 	UML_XOR(block, uml::I2, uml::I2, ~0);                                                       \
87 	UML_AND(block, uml::I1, uml::I1, uml::I2);                                                  \
88 	UML_AND(block, uml::I2, uml::I2, uml::I0);                                                  \
89 	UML_OR(block, uml::I1, uml::I1, uml::I2);                                                   \
90 	UML_AND(block, uml::I2, op2, 1 << 31);                                                      \
91 	UML_AND(block, uml::I2, uml::I2, uml::I0);                                                  \
92 	UML_OR(block, uml::I1, uml::I1, uml::I2);                                                   \
93 	UML_TEST(block, uml::I1, 1 << 31);                                                          \
94 	UML_MOVc(block, uml::COND_NZ, uml::I0, C_MASK);                                             \
95 	UML_MOVc(block, uml::COND_Z, uml::I0, 0);                                                   \
96 	UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                                                 \
97 	UML_ADD(block, DRC_PC, DRC_PC, 2);
98 
99 /* Set NZC flags for logical operations. */
100 
101 // This macro (which I didn't write) - doesn't make it obvious that the SIGN BIT = 31, just as the N Bit does,
102 // therefore, N is set by default
103 #define HandleALUNZFlags(rd)               \
104 	(((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))
105 
106 #define DRCHandleALUNZFlags(rd)                            \
107 	UML_AND(block, uml::I0, rd, SIGN_BIT);                 \
108 	UML_CMP(block, rd, 0);                                 \
109 	UML_MOVc(block, uml::COND_E, uml::I1, 1);              \
110 	UML_MOVc(block, uml::COND_NE, uml::I1, 0);             \
111 	UML_ROLINS(block, uml::I0, uml::I1, Z_BIT, 1 << Z_BIT);
112 
113 // Long ALU Functions use bit 63
114 #define HandleLongALUNZFlags(rd)                            \
115 	((((rd) & ((uint64_t)1 << 63)) >> 32) | ((!(rd)) << Z_BIT))
116 
117 #define HandleALULogicalFlags(rd, sc)                  \
118 	if (insn & INSN_S)                                   \
119 	set_cpsr(((GET_CPSR & ~(N_MASK | Z_MASK | C_MASK)) \
120 				| HandleALUNZFlags(rd)                   \
121 				| (((sc) != 0) << C_BIT)));              \
122 	R15 += 4;
123 
124 #define DRC_RD      uml::mem(&GetRegister(rd))
125 #define DRC_RS      uml::mem(&GetRegister(rs))
126 #define DRC_CPSR    uml::mem(&GET_CPSR)
127 #define DRC_PC      uml::mem(&R15)
128 #define DRC_REG(i)  uml::mem(&m_r[(i)])
129 
130 #define DRCHandleALULogicalFlags(rd, sc)                                \
131 	if (insn & INSN_S)                                                  \
132 	{                                                                   \
133 		UML_AND(block, DRC_CPSR, DRC_CPSR, ~(N_MASK | Z_MASK | C_MASK); \
134 		DRCHandleALUNZFlags(rd);                                        \
135 		UML_TEST(block, sc, ~0);                                        \
136 		UML_MOVc(block, uml::COND_Z, uml::I1, C_BIT);                   \
137 		UML_MOVc(block, uml::COND_NZ, uml::I1, 0);                      \
138 		UML_OR(block, uml::I0, uml::I0, uml::I1);                       \
139 		UML_OR(block, DRC_CPSR, DRC_CPSR, uml::I0);                     \
140 	}                                                                   \
141 	UML_ADD(block, DRC_PC, DRC_PC, 4);
142 
143 
144 // used to be functions, but no longer a need, so we'll use define for better speed.
145 #define GetRegister(rIndex)        m_r[m_reg_group[rIndex]]
146 #define SetRegister(rIndex, value) m_r[m_reg_group[rIndex]] = value
147 
148 #define GetModeRegister(mode, rIndex)        m_r[sRegisterTable[mode][rIndex]]
149 #define SetModeRegister(mode, rIndex, value) m_r[sRegisterTable[mode][rIndex]] = value
150 
151 
152 /* Macros that can be re-defined for custom cpu implementations - The core expects these to be defined */
153 /* In this case, we are using the default arm7 handlers (supplied by the core)
154    - but simply changes these and define your own if needed for cpu implementation specific needs */
155 #define READ8(addr)         arm7_cpu_read8(addr)
156 #define WRITE8(addr,data)   arm7_cpu_write8(addr,data)
157 #define READ16(addr)        arm7_cpu_read16(addr)
158 #define WRITE16(addr,data)  arm7_cpu_write16(addr,data)
159 #define READ32(addr)        arm7_cpu_read32(addr)
160 #define WRITE32(addr,data)  arm7_cpu_write32(addr,data)
161 #define PTR_READ32          &arm7_cpu_read32
162 #define PTR_WRITE32         &arm7_cpu_write32
163 
164 #define LSL(v, s) ((v) << (s))
165 #define LSR(v, s) ((v) >> (s))
166 #define ROL(v, s) (LSL((v), (s)) | (LSR((v), 32u - (s))))
167 #define ROR(v, s) (LSR((v), (s)) | (LSL((v), 32u - (s))))
168