root / target-cris / op_helper.c @ 1f56e32a
History | View | Annotate | Download (13.5 kB)
1 | 81fdc5f8 | ths | /*
|
---|---|---|---|
2 | 81fdc5f8 | ths | * CRIS helper routines
|
3 | 81fdc5f8 | ths | *
|
4 | 81fdc5f8 | ths | * Copyright (c) 2007 AXIS Communications
|
5 | 81fdc5f8 | ths | * Written by Edgar E. Iglesias
|
6 | 81fdc5f8 | ths | *
|
7 | 81fdc5f8 | ths | * This library is free software; you can redistribute it and/or
|
8 | 81fdc5f8 | ths | * modify it under the terms of the GNU Lesser General Public
|
9 | 81fdc5f8 | ths | * License as published by the Free Software Foundation; either
|
10 | 81fdc5f8 | ths | * version 2 of the License, or (at your option) any later version.
|
11 | 81fdc5f8 | ths | *
|
12 | 81fdc5f8 | ths | * This library is distributed in the hope that it will be useful,
|
13 | 81fdc5f8 | ths | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 | 81fdc5f8 | ths | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 | 81fdc5f8 | ths | * Lesser General Public License for more details.
|
16 | 81fdc5f8 | ths | *
|
17 | 81fdc5f8 | ths | * You should have received a copy of the GNU Lesser General Public
|
18 | 8167ee88 | Blue Swirl | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
19 | 81fdc5f8 | ths | */
|
20 | 81fdc5f8 | ths | |
21 | 81fdc5f8 | ths | #include "exec.h" |
22 | 786c02f1 | edgar_igl | #include "mmu.h" |
23 | 30abcfc7 | edgar_igl | #include "helper.h" |
24 | c38ac98d | edgar_igl | #include "host-utils.h" |
25 | 81fdc5f8 | ths | |
26 | d12d51d5 | aliguori | //#define CRIS_OP_HELPER_DEBUG
|
27 | d12d51d5 | aliguori | |
28 | d12d51d5 | aliguori | |
29 | d12d51d5 | aliguori | #ifdef CRIS_OP_HELPER_DEBUG
|
30 | d12d51d5 | aliguori | #define D(x) x
|
31 | 93fcfe39 | aliguori | #define D_LOG(...) qemu_log(__VA__ARGS__)
|
32 | d12d51d5 | aliguori | #else
|
33 | e2eef170 | pbrook | #define D(x)
|
34 | d12d51d5 | aliguori | #define D_LOG(...) do { } while (0) |
35 | d12d51d5 | aliguori | #endif
|
36 | e2eef170 | pbrook | |
37 | e2eef170 | pbrook | #if !defined(CONFIG_USER_ONLY)
|
38 | e2eef170 | pbrook | |
39 | 81fdc5f8 | ths | #define MMUSUFFIX _mmu
|
40 | 81fdc5f8 | ths | |
41 | 81fdc5f8 | ths | #define SHIFT 0 |
42 | 81fdc5f8 | ths | #include "softmmu_template.h" |
43 | 81fdc5f8 | ths | |
44 | 81fdc5f8 | ths | #define SHIFT 1 |
45 | 81fdc5f8 | ths | #include "softmmu_template.h" |
46 | 81fdc5f8 | ths | |
47 | 81fdc5f8 | ths | #define SHIFT 2 |
48 | 81fdc5f8 | ths | #include "softmmu_template.h" |
49 | 81fdc5f8 | ths | |
50 | 81fdc5f8 | ths | #define SHIFT 3 |
51 | 81fdc5f8 | ths | #include "softmmu_template.h" |
52 | 81fdc5f8 | ths | |
53 | 81fdc5f8 | ths | /* Try to fill the TLB and return an exception if error. If retaddr is
|
54 | 81fdc5f8 | ths | NULL, it means that the function was called in C code (i.e. not
|
55 | 81fdc5f8 | ths | from generated code or from helper.c) */
|
56 | 81fdc5f8 | ths | /* XXX: fix it to restore all registers */
|
57 | 6ebbf390 | j_mayer | void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
58 | 81fdc5f8 | ths | { |
59 | 81fdc5f8 | ths | TranslationBlock *tb; |
60 | 81fdc5f8 | ths | CPUState *saved_env; |
61 | 44f8625d | bellard | unsigned long pc; |
62 | 81fdc5f8 | ths | int ret;
|
63 | 81fdc5f8 | ths | |
64 | 81fdc5f8 | ths | /* XXX: hack to restore env in all cases, even if not called from
|
65 | 81fdc5f8 | ths | generated code */
|
66 | 81fdc5f8 | ths | saved_env = env; |
67 | 81fdc5f8 | ths | env = cpu_single_env; |
68 | b41f7df0 | edgar_igl | |
69 | d12d51d5 | aliguori | D_LOG("%s pc=%x tpc=%x ra=%x\n", __func__,
|
70 | d12d51d5 | aliguori | env->pc, env->debug1, retaddr); |
71 | 6ebbf390 | j_mayer | ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
|
72 | 551bd27f | ths | if (unlikely(ret)) {
|
73 | 81fdc5f8 | ths | if (retaddr) {
|
74 | 81fdc5f8 | ths | /* now we have a real cpu fault */
|
75 | 44f8625d | bellard | pc = (unsigned long)retaddr; |
76 | 81fdc5f8 | ths | tb = tb_find_pc(pc); |
77 | 81fdc5f8 | ths | if (tb) {
|
78 | 81fdc5f8 | ths | /* the PC is inside the translated code. It means that we have
|
79 | 81fdc5f8 | ths | a virtual CPU fault */
|
80 | 618ba8e6 | Stefan Weil | cpu_restore_state(tb, env, pc); |
81 | 30abcfc7 | edgar_igl | |
82 | 30abcfc7 | edgar_igl | /* Evaluate flags after retranslation. */
|
83 | 30abcfc7 | edgar_igl | helper_top_evaluate_flags(); |
84 | 81fdc5f8 | ths | } |
85 | 81fdc5f8 | ths | } |
86 | 81fdc5f8 | ths | cpu_loop_exit(); |
87 | 81fdc5f8 | ths | } |
88 | 81fdc5f8 | ths | env = saved_env; |
89 | 81fdc5f8 | ths | } |
90 | 81fdc5f8 | ths | |
91 | e2eef170 | pbrook | #endif
|
92 | e2eef170 | pbrook | |
93 | dceaf394 | edgar_igl | void helper_raise_exception(uint32_t index)
|
94 | 786c02f1 | edgar_igl | { |
95 | dceaf394 | edgar_igl | env->exception_index = index; |
96 | dceaf394 | edgar_igl | cpu_loop_exit(); |
97 | 786c02f1 | edgar_igl | } |
98 | 786c02f1 | edgar_igl | |
99 | cf1d97f0 | edgar_igl | void helper_tlb_flush_pid(uint32_t pid)
|
100 | cf1d97f0 | edgar_igl | { |
101 | cf1d97f0 | edgar_igl | #if !defined(CONFIG_USER_ONLY)
|
102 | 28de16da | edgar_igl | pid &= 0xff;
|
103 | 28de16da | edgar_igl | if (pid != (env->pregs[PR_PID] & 0xff)) |
104 | 28de16da | edgar_igl | cris_mmu_flush_pid(env, env->pregs[PR_PID]); |
105 | cf1d97f0 | edgar_igl | #endif
|
106 | cf1d97f0 | edgar_igl | } |
107 | cf1d97f0 | edgar_igl | |
108 | a1aebcb8 | edgar_igl | void helper_spc_write(uint32_t new_spc)
|
109 | a1aebcb8 | edgar_igl | { |
110 | a1aebcb8 | edgar_igl | #if !defined(CONFIG_USER_ONLY)
|
111 | a1aebcb8 | edgar_igl | tlb_flush_page(env, env->pregs[PR_SPC]); |
112 | a1aebcb8 | edgar_igl | tlb_flush_page(env, new_spc); |
113 | a1aebcb8 | edgar_igl | #endif
|
114 | a1aebcb8 | edgar_igl | } |
115 | a1aebcb8 | edgar_igl | |
116 | 30abcfc7 | edgar_igl | void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2)
|
117 | b41f7df0 | edgar_igl | { |
118 | 93fcfe39 | aliguori | qemu_log("%s: a0=%x a1=%x\n", __func__, a0, a1);
|
119 | b41f7df0 | edgar_igl | } |
120 | b41f7df0 | edgar_igl | |
121 | cf1d97f0 | edgar_igl | /* Used by the tlb decoder. */
|
122 | cf1d97f0 | edgar_igl | #define EXTRACT_FIELD(src, start, end) \
|
123 | cf1d97f0 | edgar_igl | (((src) >> start) & ((1 << (end - start + 1)) - 1)) |
124 | cf1d97f0 | edgar_igl | |
125 | dceaf394 | edgar_igl | void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
|
126 | dceaf394 | edgar_igl | { |
127 | dceaf394 | edgar_igl | uint32_t srs; |
128 | dceaf394 | edgar_igl | srs = env->pregs[PR_SRS]; |
129 | dceaf394 | edgar_igl | srs &= 3;
|
130 | dceaf394 | edgar_igl | env->sregs[srs][sreg] = env->regs[reg]; |
131 | dceaf394 | edgar_igl | |
132 | dceaf394 | edgar_igl | #if !defined(CONFIG_USER_ONLY)
|
133 | dceaf394 | edgar_igl | if (srs == 1 || srs == 2) { |
134 | dceaf394 | edgar_igl | if (sreg == 6) { |
135 | dceaf394 | edgar_igl | /* Writes to tlb-hi write to mm_cause as a side
|
136 | dceaf394 | edgar_igl | effect. */
|
137 | 6913ba56 | edgar_igl | env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg]; |
138 | 6913ba56 | edgar_igl | env->sregs[SFR_R_MM_CAUSE] = env->regs[reg]; |
139 | dceaf394 | edgar_igl | } |
140 | dceaf394 | edgar_igl | else if (sreg == 5) { |
141 | dceaf394 | edgar_igl | uint32_t set; |
142 | dceaf394 | edgar_igl | uint32_t idx; |
143 | dceaf394 | edgar_igl | uint32_t lo, hi; |
144 | dceaf394 | edgar_igl | uint32_t vaddr; |
145 | cf1d97f0 | edgar_igl | int tlb_v;
|
146 | dceaf394 | edgar_igl | |
147 | dceaf394 | edgar_igl | idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; |
148 | dceaf394 | edgar_igl | set >>= 4;
|
149 | dceaf394 | edgar_igl | set &= 3;
|
150 | dceaf394 | edgar_igl | |
151 | dceaf394 | edgar_igl | idx &= 15;
|
152 | dceaf394 | edgar_igl | /* We've just made a write to tlb_lo. */
|
153 | dceaf394 | edgar_igl | lo = env->sregs[SFR_RW_MM_TLB_LO]; |
154 | dceaf394 | edgar_igl | /* Writes are done via r_mm_cause. */
|
155 | dceaf394 | edgar_igl | hi = env->sregs[SFR_R_MM_CAUSE]; |
156 | cf1d97f0 | edgar_igl | |
157 | cf1d97f0 | edgar_igl | vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
|
158 | cf1d97f0 | edgar_igl | 13, 31); |
159 | cf1d97f0 | edgar_igl | vaddr <<= TARGET_PAGE_BITS; |
160 | cf1d97f0 | edgar_igl | tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
|
161 | cf1d97f0 | edgar_igl | 3, 3); |
162 | dceaf394 | edgar_igl | env->tlbsets[srs - 1][set][idx].lo = lo;
|
163 | dceaf394 | edgar_igl | env->tlbsets[srs - 1][set][idx].hi = hi;
|
164 | cf1d97f0 | edgar_igl | |
165 | d12d51d5 | aliguori | D_LOG("tlb flush vaddr=%x v=%d pc=%x\n",
|
166 | d12d51d5 | aliguori | vaddr, tlb_v, env->pc); |
167 | 3e18c6bf | Edgar E. Iglesias | if (tlb_v) {
|
168 | 3e18c6bf | Edgar E. Iglesias | tlb_flush_page(env, vaddr); |
169 | 3e18c6bf | Edgar E. Iglesias | } |
170 | dceaf394 | edgar_igl | } |
171 | dceaf394 | edgar_igl | } |
172 | dceaf394 | edgar_igl | #endif
|
173 | dceaf394 | edgar_igl | } |
174 | dceaf394 | edgar_igl | |
175 | dceaf394 | edgar_igl | void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg)
|
176 | dceaf394 | edgar_igl | { |
177 | dceaf394 | edgar_igl | uint32_t srs; |
178 | dceaf394 | edgar_igl | env->pregs[PR_SRS] &= 3;
|
179 | dceaf394 | edgar_igl | srs = env->pregs[PR_SRS]; |
180 | dceaf394 | edgar_igl | |
181 | dceaf394 | edgar_igl | #if !defined(CONFIG_USER_ONLY)
|
182 | dceaf394 | edgar_igl | if (srs == 1 || srs == 2) |
183 | dceaf394 | edgar_igl | { |
184 | dceaf394 | edgar_igl | uint32_t set; |
185 | dceaf394 | edgar_igl | uint32_t idx; |
186 | dceaf394 | edgar_igl | uint32_t lo, hi; |
187 | dceaf394 | edgar_igl | |
188 | dceaf394 | edgar_igl | idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; |
189 | dceaf394 | edgar_igl | set >>= 4;
|
190 | dceaf394 | edgar_igl | set &= 3;
|
191 | dceaf394 | edgar_igl | idx &= 15;
|
192 | dceaf394 | edgar_igl | |
193 | dceaf394 | edgar_igl | /* Update the mirror regs. */
|
194 | dceaf394 | edgar_igl | hi = env->tlbsets[srs - 1][set][idx].hi;
|
195 | dceaf394 | edgar_igl | lo = env->tlbsets[srs - 1][set][idx].lo;
|
196 | dceaf394 | edgar_igl | env->sregs[SFR_RW_MM_TLB_HI] = hi; |
197 | dceaf394 | edgar_igl | env->sregs[SFR_RW_MM_TLB_LO] = lo; |
198 | dceaf394 | edgar_igl | } |
199 | dceaf394 | edgar_igl | #endif
|
200 | dceaf394 | edgar_igl | env->regs[reg] = env->sregs[srs][sreg]; |
201 | dceaf394 | edgar_igl | } |
202 | dceaf394 | edgar_igl | |
203 | dceaf394 | edgar_igl | static void cris_ccs_rshift(CPUState *env) |
204 | dceaf394 | edgar_igl | { |
205 | dceaf394 | edgar_igl | uint32_t ccs; |
206 | dceaf394 | edgar_igl | |
207 | dceaf394 | edgar_igl | /* Apply the ccs shift. */
|
208 | dceaf394 | edgar_igl | ccs = env->pregs[PR_CCS]; |
209 | dceaf394 | edgar_igl | ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); |
210 | dceaf394 | edgar_igl | if (ccs & U_FLAG)
|
211 | dceaf394 | edgar_igl | { |
212 | dceaf394 | edgar_igl | /* Enter user mode. */
|
213 | dceaf394 | edgar_igl | env->ksp = env->regs[R_SP]; |
214 | dceaf394 | edgar_igl | env->regs[R_SP] = env->pregs[PR_USP]; |
215 | dceaf394 | edgar_igl | } |
216 | dceaf394 | edgar_igl | |
217 | dceaf394 | edgar_igl | env->pregs[PR_CCS] = ccs; |
218 | dceaf394 | edgar_igl | } |
219 | dceaf394 | edgar_igl | |
220 | b41f7df0 | edgar_igl | void helper_rfe(void) |
221 | b41f7df0 | edgar_igl | { |
222 | bf443337 | edgar_igl | int rflag = env->pregs[PR_CCS] & R_FLAG;
|
223 | bf443337 | edgar_igl | |
224 | d12d51d5 | aliguori | D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
|
225 | b41f7df0 | edgar_igl | env->pregs[PR_ERP], env->pregs[PR_PID], |
226 | b41f7df0 | edgar_igl | env->pregs[PR_CCS], |
227 | d12d51d5 | aliguori | env->btarget); |
228 | dceaf394 | edgar_igl | |
229 | dceaf394 | edgar_igl | cris_ccs_rshift(env); |
230 | dceaf394 | edgar_igl | |
231 | dceaf394 | edgar_igl | /* RFE sets the P_FLAG only if the R_FLAG is not set. */
|
232 | bf443337 | edgar_igl | if (!rflag)
|
233 | dceaf394 | edgar_igl | env->pregs[PR_CCS] |= P_FLAG; |
234 | b41f7df0 | edgar_igl | } |
235 | b41f7df0 | edgar_igl | |
236 | 5bf8f1ab | edgar_igl | void helper_rfn(void) |
237 | 5bf8f1ab | edgar_igl | { |
238 | 5bf8f1ab | edgar_igl | int rflag = env->pregs[PR_CCS] & R_FLAG;
|
239 | 5bf8f1ab | edgar_igl | |
240 | d12d51d5 | aliguori | D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n",
|
241 | 5bf8f1ab | edgar_igl | env->pregs[PR_ERP], env->pregs[PR_PID], |
242 | 5bf8f1ab | edgar_igl | env->pregs[PR_CCS], |
243 | d12d51d5 | aliguori | env->btarget); |
244 | 5bf8f1ab | edgar_igl | |
245 | 5bf8f1ab | edgar_igl | cris_ccs_rshift(env); |
246 | 5bf8f1ab | edgar_igl | |
247 | 5bf8f1ab | edgar_igl | /* Set the P_FLAG only if the R_FLAG is not set. */
|
248 | 5bf8f1ab | edgar_igl | if (!rflag)
|
249 | 5bf8f1ab | edgar_igl | env->pregs[PR_CCS] |= P_FLAG; |
250 | 5bf8f1ab | edgar_igl | |
251 | 5bf8f1ab | edgar_igl | /* Always set the M flag. */
|
252 | 5bf8f1ab | edgar_igl | env->pregs[PR_CCS] |= M_FLAG; |
253 | 5bf8f1ab | edgar_igl | } |
254 | 5bf8f1ab | edgar_igl | |
255 | c38ac98d | edgar_igl | uint32_t helper_lz(uint32_t t0) |
256 | c38ac98d | edgar_igl | { |
257 | c38ac98d | edgar_igl | return clz32(t0);
|
258 | c38ac98d | edgar_igl | } |
259 | c38ac98d | edgar_igl | |
260 | abd5c94e | edgar_igl | uint32_t helper_btst(uint32_t t0, uint32_t t1, uint32_t ccs) |
261 | abd5c94e | edgar_igl | { |
262 | abd5c94e | edgar_igl | /* FIXME: clean this up. */
|
263 | abd5c94e | edgar_igl | |
264 | abd5c94e | edgar_igl | /* des ref:
|
265 | abd5c94e | edgar_igl | The N flag is set according to the selected bit in the dest reg.
|
266 | abd5c94e | edgar_igl | The Z flag is set if the selected bit and all bits to the right are
|
267 | abd5c94e | edgar_igl | zero.
|
268 | abd5c94e | edgar_igl | The X flag is cleared.
|
269 | abd5c94e | edgar_igl | Other flags are left untouched.
|
270 | abd5c94e | edgar_igl | The destination reg is not affected.*/
|
271 | abd5c94e | edgar_igl | unsigned int fz, sbit, bset, mask, masked_t0; |
272 | abd5c94e | edgar_igl | |
273 | abd5c94e | edgar_igl | sbit = t1 & 31;
|
274 | abd5c94e | edgar_igl | bset = !!(t0 & (1 << sbit));
|
275 | abd5c94e | edgar_igl | mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1; |
276 | abd5c94e | edgar_igl | masked_t0 = t0 & mask; |
277 | abd5c94e | edgar_igl | fz = !(masked_t0 | bset); |
278 | abd5c94e | edgar_igl | |
279 | abd5c94e | edgar_igl | /* Clear the X, N and Z flags. */
|
280 | abd5c94e | edgar_igl | ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG); |
281 | 95475216 | Edgar E. Iglesias | if (env->pregs[PR_VR] < 32) |
282 | 95475216 | Edgar E. Iglesias | ccs &= ~(V_FLAG | C_FLAG); |
283 | abd5c94e | edgar_igl | /* Set the N and Z flags accordingly. */
|
284 | abd5c94e | edgar_igl | ccs |= (bset << 3) | (fz << 2); |
285 | abd5c94e | edgar_igl | return ccs;
|
286 | abd5c94e | edgar_igl | } |
287 | abd5c94e | edgar_igl | |
288 | 6231868b | edgar_igl | static inline uint32_t evaluate_flags_writeback(uint32_t flags, uint32_t ccs) |
289 | b41f7df0 | edgar_igl | { |
290 | a8cf66bb | edgar_igl | unsigned int x, z, mask; |
291 | b41f7df0 | edgar_igl | |
292 | b41f7df0 | edgar_igl | /* Extended arithmetics, leave the z flag alone. */
|
293 | 30abcfc7 | edgar_igl | x = env->cc_x; |
294 | a8cf66bb | edgar_igl | mask = env->cc_mask | X_FLAG; |
295 | a8cf66bb | edgar_igl | if (x) {
|
296 | a8cf66bb | edgar_igl | z = flags & Z_FLAG; |
297 | a8cf66bb | edgar_igl | mask = mask & ~z; |
298 | a8cf66bb | edgar_igl | } |
299 | a8cf66bb | edgar_igl | flags &= mask; |
300 | b41f7df0 | edgar_igl | |
301 | b41f7df0 | edgar_igl | /* all insn clear the x-flag except setf or clrf. */
|
302 | 6231868b | edgar_igl | ccs &= ~mask; |
303 | 6231868b | edgar_igl | ccs |= flags; |
304 | 6231868b | edgar_igl | return ccs;
|
305 | b41f7df0 | edgar_igl | } |
306 | b41f7df0 | edgar_igl | |
307 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_muls(uint32_t ccs, uint32_t res, uint32_t mof) |
308 | b41f7df0 | edgar_igl | { |
309 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
310 | dceaf394 | edgar_igl | int64_t tmp; |
311 | b41f7df0 | edgar_igl | int dneg;
|
312 | b41f7df0 | edgar_igl | |
313 | b41f7df0 | edgar_igl | dneg = ((int32_t)res) < 0;
|
314 | b41f7df0 | edgar_igl | |
315 | dceaf394 | edgar_igl | tmp = mof; |
316 | dceaf394 | edgar_igl | tmp <<= 32;
|
317 | dceaf394 | edgar_igl | tmp |= res; |
318 | b41f7df0 | edgar_igl | if (tmp == 0) |
319 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
320 | b41f7df0 | edgar_igl | else if (tmp < 0) |
321 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
322 | b41f7df0 | edgar_igl | if ((dneg && mof != -1) |
323 | b41f7df0 | edgar_igl | || (!dneg && mof != 0))
|
324 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
325 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
326 | b41f7df0 | edgar_igl | } |
327 | b41f7df0 | edgar_igl | |
328 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_mulu(uint32_t ccs, uint32_t res, uint32_t mof) |
329 | b41f7df0 | edgar_igl | { |
330 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
331 | dceaf394 | edgar_igl | uint64_t tmp; |
332 | b41f7df0 | edgar_igl | |
333 | dceaf394 | edgar_igl | tmp = mof; |
334 | dceaf394 | edgar_igl | tmp <<= 32;
|
335 | dceaf394 | edgar_igl | tmp |= res; |
336 | b41f7df0 | edgar_igl | if (tmp == 0) |
337 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
338 | b41f7df0 | edgar_igl | else if (tmp >> 63) |
339 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
340 | b41f7df0 | edgar_igl | if (mof)
|
341 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
342 | b41f7df0 | edgar_igl | |
343 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
344 | b41f7df0 | edgar_igl | } |
345 | b41f7df0 | edgar_igl | |
346 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_mcp(uint32_t ccs, |
347 | 6231868b | edgar_igl | uint32_t src, uint32_t dst, uint32_t res) |
348 | b41f7df0 | edgar_igl | { |
349 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
350 | b41f7df0 | edgar_igl | |
351 | 6231868b | edgar_igl | src = src & 0x80000000;
|
352 | 6231868b | edgar_igl | dst = dst & 0x80000000;
|
353 | b41f7df0 | edgar_igl | |
354 | b41f7df0 | edgar_igl | if ((res & 0x80000000L) != 0L) |
355 | b41f7df0 | edgar_igl | { |
356 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
357 | a8cf66bb | edgar_igl | if (!src && !dst)
|
358 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
359 | a8cf66bb | edgar_igl | else if (src & dst) |
360 | b41f7df0 | edgar_igl | flags |= R_FLAG; |
361 | b41f7df0 | edgar_igl | } |
362 | b41f7df0 | edgar_igl | else
|
363 | b41f7df0 | edgar_igl | { |
364 | b41f7df0 | edgar_igl | if (res == 0L) |
365 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
366 | a8cf66bb | edgar_igl | if (src & dst)
|
367 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
368 | a8cf66bb | edgar_igl | if (dst | src)
|
369 | b41f7df0 | edgar_igl | flags |= R_FLAG; |
370 | b41f7df0 | edgar_igl | } |
371 | b41f7df0 | edgar_igl | |
372 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
373 | b41f7df0 | edgar_igl | } |
374 | b41f7df0 | edgar_igl | |
375 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_alu_4(uint32_t ccs, |
376 | 6231868b | edgar_igl | uint32_t src, uint32_t dst, uint32_t res) |
377 | b41f7df0 | edgar_igl | { |
378 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
379 | b41f7df0 | edgar_igl | |
380 | 6231868b | edgar_igl | src = src & 0x80000000;
|
381 | 6231868b | edgar_igl | dst = dst & 0x80000000;
|
382 | 30abcfc7 | edgar_igl | |
383 | a8cf66bb | edgar_igl | if ((res & 0x80000000L) != 0L) |
384 | 30abcfc7 | edgar_igl | { |
385 | a8cf66bb | edgar_igl | flags |= N_FLAG; |
386 | a8cf66bb | edgar_igl | if (!src && !dst)
|
387 | a8cf66bb | edgar_igl | flags |= V_FLAG; |
388 | a8cf66bb | edgar_igl | else if (src & dst) |
389 | a8cf66bb | edgar_igl | flags |= C_FLAG; |
390 | a8cf66bb | edgar_igl | } |
391 | a8cf66bb | edgar_igl | else
|
392 | a8cf66bb | edgar_igl | { |
393 | a8cf66bb | edgar_igl | if (res == 0L) |
394 | a8cf66bb | edgar_igl | flags |= Z_FLAG; |
395 | a8cf66bb | edgar_igl | if (src & dst)
|
396 | a8cf66bb | edgar_igl | flags |= V_FLAG; |
397 | a8cf66bb | edgar_igl | if (dst | src)
|
398 | a8cf66bb | edgar_igl | flags |= C_FLAG; |
399 | 30abcfc7 | edgar_igl | } |
400 | 30abcfc7 | edgar_igl | |
401 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
402 | a8cf66bb | edgar_igl | } |
403 | a8cf66bb | edgar_igl | |
404 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_sub_4(uint32_t ccs, |
405 | 6231868b | edgar_igl | uint32_t src, uint32_t dst, uint32_t res) |
406 | a8cf66bb | edgar_igl | { |
407 | a8cf66bb | edgar_igl | uint32_t flags = 0;
|
408 | a8cf66bb | edgar_igl | |
409 | 6231868b | edgar_igl | src = (~src) & 0x80000000;
|
410 | 6231868b | edgar_igl | dst = dst & 0x80000000;
|
411 | b41f7df0 | edgar_igl | |
412 | b41f7df0 | edgar_igl | if ((res & 0x80000000L) != 0L) |
413 | b41f7df0 | edgar_igl | { |
414 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
415 | a8cf66bb | edgar_igl | if (!src && !dst)
|
416 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
417 | a8cf66bb | edgar_igl | else if (src & dst) |
418 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
419 | b41f7df0 | edgar_igl | } |
420 | b41f7df0 | edgar_igl | else
|
421 | b41f7df0 | edgar_igl | { |
422 | b41f7df0 | edgar_igl | if (res == 0L) |
423 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
424 | a8cf66bb | edgar_igl | if (src & dst)
|
425 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
426 | a8cf66bb | edgar_igl | if (dst | src)
|
427 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
428 | b41f7df0 | edgar_igl | } |
429 | b41f7df0 | edgar_igl | |
430 | a8cf66bb | edgar_igl | flags ^= C_FLAG; |
431 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
432 | b41f7df0 | edgar_igl | } |
433 | b41f7df0 | edgar_igl | |
434 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_move_4(uint32_t ccs, uint32_t res) |
435 | b41f7df0 | edgar_igl | { |
436 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
437 | b41f7df0 | edgar_igl | |
438 | b41f7df0 | edgar_igl | if ((int32_t)res < 0) |
439 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
440 | b41f7df0 | edgar_igl | else if (res == 0L) |
441 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
442 | b41f7df0 | edgar_igl | |
443 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
444 | b41f7df0 | edgar_igl | } |
445 | 6231868b | edgar_igl | uint32_t helper_evaluate_flags_move_2(uint32_t ccs, uint32_t res) |
446 | b41f7df0 | edgar_igl | { |
447 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
448 | b41f7df0 | edgar_igl | |
449 | b41f7df0 | edgar_igl | if ((int16_t)res < 0L) |
450 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
451 | b41f7df0 | edgar_igl | else if (res == 0) |
452 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
453 | b41f7df0 | edgar_igl | |
454 | 6231868b | edgar_igl | return evaluate_flags_writeback(flags, ccs);
|
455 | b41f7df0 | edgar_igl | } |
456 | b41f7df0 | edgar_igl | |
457 | b41f7df0 | edgar_igl | /* TODO: This is expensive. We could split things up and only evaluate part of
|
458 | b41f7df0 | edgar_igl | CCR on a need to know basis. For now, we simply re-evaluate everything. */
|
459 | 6231868b | edgar_igl | void helper_evaluate_flags(void) |
460 | b41f7df0 | edgar_igl | { |
461 | 6231868b | edgar_igl | uint32_t src, dst, res; |
462 | b41f7df0 | edgar_igl | uint32_t flags = 0;
|
463 | b41f7df0 | edgar_igl | |
464 | b41f7df0 | edgar_igl | src = env->cc_src; |
465 | b41f7df0 | edgar_igl | dst = env->cc_dest; |
466 | b41f7df0 | edgar_igl | res = env->cc_result; |
467 | b41f7df0 | edgar_igl | |
468 | 30abcfc7 | edgar_igl | if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
|
469 | 30abcfc7 | edgar_igl | src = ~src; |
470 | b41f7df0 | edgar_igl | |
471 | b41f7df0 | edgar_igl | /* Now, evaluate the flags. This stuff is based on
|
472 | b41f7df0 | edgar_igl | Per Zander's CRISv10 simulator. */
|
473 | b41f7df0 | edgar_igl | switch (env->cc_size)
|
474 | b41f7df0 | edgar_igl | { |
475 | b41f7df0 | edgar_igl | case 1: |
476 | b41f7df0 | edgar_igl | if ((res & 0x80L) != 0L) |
477 | b41f7df0 | edgar_igl | { |
478 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
479 | b41f7df0 | edgar_igl | if (((src & 0x80L) == 0L) |
480 | b41f7df0 | edgar_igl | && ((dst & 0x80L) == 0L)) |
481 | b41f7df0 | edgar_igl | { |
482 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
483 | b41f7df0 | edgar_igl | } |
484 | b41f7df0 | edgar_igl | else if (((src & 0x80L) != 0L) |
485 | b41f7df0 | edgar_igl | && ((dst & 0x80L) != 0L)) |
486 | b41f7df0 | edgar_igl | { |
487 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
488 | b41f7df0 | edgar_igl | } |
489 | b41f7df0 | edgar_igl | } |
490 | b41f7df0 | edgar_igl | else
|
491 | b41f7df0 | edgar_igl | { |
492 | b41f7df0 | edgar_igl | if ((res & 0xFFL) == 0L) |
493 | b41f7df0 | edgar_igl | { |
494 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
495 | b41f7df0 | edgar_igl | } |
496 | b41f7df0 | edgar_igl | if (((src & 0x80L) != 0L) |
497 | b41f7df0 | edgar_igl | && ((dst & 0x80L) != 0L)) |
498 | b41f7df0 | edgar_igl | { |
499 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
500 | b41f7df0 | edgar_igl | } |
501 | b41f7df0 | edgar_igl | if ((dst & 0x80L) != 0L |
502 | b41f7df0 | edgar_igl | || (src & 0x80L) != 0L) |
503 | b41f7df0 | edgar_igl | { |
504 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
505 | b41f7df0 | edgar_igl | } |
506 | b41f7df0 | edgar_igl | } |
507 | b41f7df0 | edgar_igl | break;
|
508 | b41f7df0 | edgar_igl | case 2: |
509 | b41f7df0 | edgar_igl | if ((res & 0x8000L) != 0L) |
510 | b41f7df0 | edgar_igl | { |
511 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
512 | b41f7df0 | edgar_igl | if (((src & 0x8000L) == 0L) |
513 | b41f7df0 | edgar_igl | && ((dst & 0x8000L) == 0L)) |
514 | b41f7df0 | edgar_igl | { |
515 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
516 | b41f7df0 | edgar_igl | } |
517 | b41f7df0 | edgar_igl | else if (((src & 0x8000L) != 0L) |
518 | b41f7df0 | edgar_igl | && ((dst & 0x8000L) != 0L)) |
519 | b41f7df0 | edgar_igl | { |
520 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
521 | b41f7df0 | edgar_igl | } |
522 | b41f7df0 | edgar_igl | } |
523 | b41f7df0 | edgar_igl | else
|
524 | b41f7df0 | edgar_igl | { |
525 | b41f7df0 | edgar_igl | if ((res & 0xFFFFL) == 0L) |
526 | b41f7df0 | edgar_igl | { |
527 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
528 | b41f7df0 | edgar_igl | } |
529 | b41f7df0 | edgar_igl | if (((src & 0x8000L) != 0L) |
530 | b41f7df0 | edgar_igl | && ((dst & 0x8000L) != 0L)) |
531 | b41f7df0 | edgar_igl | { |
532 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
533 | b41f7df0 | edgar_igl | } |
534 | b41f7df0 | edgar_igl | if ((dst & 0x8000L) != 0L |
535 | b41f7df0 | edgar_igl | || (src & 0x8000L) != 0L) |
536 | b41f7df0 | edgar_igl | { |
537 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
538 | b41f7df0 | edgar_igl | } |
539 | b41f7df0 | edgar_igl | } |
540 | b41f7df0 | edgar_igl | break;
|
541 | b41f7df0 | edgar_igl | case 4: |
542 | b41f7df0 | edgar_igl | if ((res & 0x80000000L) != 0L) |
543 | b41f7df0 | edgar_igl | { |
544 | b41f7df0 | edgar_igl | flags |= N_FLAG; |
545 | b41f7df0 | edgar_igl | if (((src & 0x80000000L) == 0L) |
546 | b41f7df0 | edgar_igl | && ((dst & 0x80000000L) == 0L)) |
547 | b41f7df0 | edgar_igl | { |
548 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
549 | b41f7df0 | edgar_igl | } |
550 | b41f7df0 | edgar_igl | else if (((src & 0x80000000L) != 0L) && |
551 | b41f7df0 | edgar_igl | ((dst & 0x80000000L) != 0L)) |
552 | b41f7df0 | edgar_igl | { |
553 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
554 | b41f7df0 | edgar_igl | } |
555 | b41f7df0 | edgar_igl | } |
556 | b41f7df0 | edgar_igl | else
|
557 | b41f7df0 | edgar_igl | { |
558 | b41f7df0 | edgar_igl | if (res == 0L) |
559 | b41f7df0 | edgar_igl | flags |= Z_FLAG; |
560 | b41f7df0 | edgar_igl | if (((src & 0x80000000L) != 0L) |
561 | b41f7df0 | edgar_igl | && ((dst & 0x80000000L) != 0L)) |
562 | b41f7df0 | edgar_igl | flags |= V_FLAG; |
563 | b41f7df0 | edgar_igl | if ((dst & 0x80000000L) != 0L |
564 | b41f7df0 | edgar_igl | || (src & 0x80000000L) != 0L) |
565 | b41f7df0 | edgar_igl | flags |= C_FLAG; |
566 | b41f7df0 | edgar_igl | } |
567 | b41f7df0 | edgar_igl | break;
|
568 | b41f7df0 | edgar_igl | default:
|
569 | b41f7df0 | edgar_igl | break;
|
570 | b41f7df0 | edgar_igl | } |
571 | b41f7df0 | edgar_igl | |
572 | 6231868b | edgar_igl | if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
|
573 | b41f7df0 | edgar_igl | flags ^= C_FLAG; |
574 | 6231868b | edgar_igl | |
575 | 6231868b | edgar_igl | env->pregs[PR_CCS] = evaluate_flags_writeback(flags, env->pregs[PR_CCS]); |
576 | b41f7df0 | edgar_igl | } |
577 | 30abcfc7 | edgar_igl | |
578 | 30abcfc7 | edgar_igl | void helper_top_evaluate_flags(void) |
579 | 30abcfc7 | edgar_igl | { |
580 | 30abcfc7 | edgar_igl | switch (env->cc_op)
|
581 | 30abcfc7 | edgar_igl | { |
582 | 30abcfc7 | edgar_igl | case CC_OP_MCP:
|
583 | 6231868b | edgar_igl | env->pregs[PR_CCS] = helper_evaluate_flags_mcp( |
584 | 6231868b | edgar_igl | env->pregs[PR_CCS], env->cc_src, |
585 | 6231868b | edgar_igl | env->cc_dest, env->cc_result); |
586 | 30abcfc7 | edgar_igl | break;
|
587 | 30abcfc7 | edgar_igl | case CC_OP_MULS:
|
588 | 6231868b | edgar_igl | env->pregs[PR_CCS] = helper_evaluate_flags_muls( |
589 | 6231868b | edgar_igl | env->pregs[PR_CCS], env->cc_result, |
590 | 6231868b | edgar_igl | env->pregs[PR_MOF]); |
591 | 30abcfc7 | edgar_igl | break;
|
592 | 30abcfc7 | edgar_igl | case CC_OP_MULU:
|
593 | 6231868b | edgar_igl | env->pregs[PR_CCS] = helper_evaluate_flags_mulu( |
594 | 6231868b | edgar_igl | env->pregs[PR_CCS], env->cc_result, |
595 | 6231868b | edgar_igl | env->pregs[PR_MOF]); |
596 | 30abcfc7 | edgar_igl | break;
|
597 | 30abcfc7 | edgar_igl | case CC_OP_MOVE:
|
598 | 30abcfc7 | edgar_igl | case CC_OP_AND:
|
599 | 30abcfc7 | edgar_igl | case CC_OP_OR:
|
600 | 30abcfc7 | edgar_igl | case CC_OP_XOR:
|
601 | 30abcfc7 | edgar_igl | case CC_OP_ASR:
|
602 | 30abcfc7 | edgar_igl | case CC_OP_LSR:
|
603 | 30abcfc7 | edgar_igl | case CC_OP_LSL:
|
604 | 6231868b | edgar_igl | switch (env->cc_size)
|
605 | 6231868b | edgar_igl | { |
606 | 6231868b | edgar_igl | case 4: |
607 | 6231868b | edgar_igl | env->pregs[PR_CCS] = |
608 | 6231868b | edgar_igl | helper_evaluate_flags_move_4( |
609 | 6231868b | edgar_igl | env->pregs[PR_CCS], |
610 | 6231868b | edgar_igl | env->cc_result); |
611 | 6231868b | edgar_igl | break;
|
612 | 6231868b | edgar_igl | case 2: |
613 | 6231868b | edgar_igl | env->pregs[PR_CCS] = |
614 | 6231868b | edgar_igl | helper_evaluate_flags_move_2( |
615 | 6231868b | edgar_igl | env->pregs[PR_CCS], |
616 | 6231868b | edgar_igl | env->cc_result); |
617 | 6231868b | edgar_igl | break;
|
618 | 6231868b | edgar_igl | default:
|
619 | 6231868b | edgar_igl | helper_evaluate_flags(); |
620 | 6231868b | edgar_igl | break;
|
621 | 6231868b | edgar_igl | } |
622 | 6231868b | edgar_igl | break;
|
623 | 30abcfc7 | edgar_igl | case CC_OP_FLAGS:
|
624 | 30abcfc7 | edgar_igl | /* live. */
|
625 | 30abcfc7 | edgar_igl | break;
|
626 | a8cf66bb | edgar_igl | case CC_OP_SUB:
|
627 | a8cf66bb | edgar_igl | case CC_OP_CMP:
|
628 | a8cf66bb | edgar_igl | if (env->cc_size == 4) |
629 | 6231868b | edgar_igl | env->pregs[PR_CCS] = |
630 | 6231868b | edgar_igl | helper_evaluate_flags_sub_4( |
631 | 6231868b | edgar_igl | env->pregs[PR_CCS], |
632 | 6231868b | edgar_igl | env->cc_src, env->cc_dest, |
633 | 6231868b | edgar_igl | env->cc_result); |
634 | a8cf66bb | edgar_igl | else
|
635 | a8cf66bb | edgar_igl | helper_evaluate_flags(); |
636 | a8cf66bb | edgar_igl | break;
|
637 | 30abcfc7 | edgar_igl | default:
|
638 | 30abcfc7 | edgar_igl | { |
639 | 30abcfc7 | edgar_igl | switch (env->cc_size)
|
640 | 30abcfc7 | edgar_igl | { |
641 | 6231868b | edgar_igl | case 4: |
642 | 6231868b | edgar_igl | env->pregs[PR_CCS] = |
643 | 6231868b | edgar_igl | helper_evaluate_flags_alu_4( |
644 | 6231868b | edgar_igl | env->pregs[PR_CCS], |
645 | 6231868b | edgar_igl | env->cc_src, env->cc_dest, |
646 | 6231868b | edgar_igl | env->cc_result); |
647 | 6231868b | edgar_igl | break;
|
648 | 6231868b | edgar_igl | default:
|
649 | 6231868b | edgar_igl | helper_evaluate_flags(); |
650 | 6231868b | edgar_igl | break;
|
651 | 30abcfc7 | edgar_igl | } |
652 | 30abcfc7 | edgar_igl | } |
653 | 30abcfc7 | edgar_igl | break;
|
654 | 30abcfc7 | edgar_igl | } |
655 | 30abcfc7 | edgar_igl | } |