Add qemu 2.4.0
[kvmfornfv.git] / qemu / target-unicore32 / op_helper.c
1 /*
2  *  UniCore32 helper routines
3  *
4  * Copyright (C) 2010-2012 Guan Xuetao
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation, or (at your option) any
9  * later version. See the COPYING file in the top-level directory.
10  */
11 #include "cpu.h"
12 #include "exec/helper-proto.h"
13 #include "exec/cpu_ldst.h"
14
15 #define SIGNBIT (uint32_t)0x80000000
16 #define SIGNBIT64 ((uint64_t)1 << 63)
17
18 void HELPER(exception)(CPUUniCore32State *env, uint32_t excp)
19 {
20     CPUState *cs = CPU(uc32_env_get_cpu(env));
21
22     cs->exception_index = excp;
23     cpu_loop_exit(cs);
24 }
25
26 static target_ulong asr_read(CPUUniCore32State *env)
27 {
28     int ZF;
29     ZF = (env->ZF == 0);
30     return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) |
31         (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
32 }
33
34 target_ulong cpu_asr_read(CPUUniCore32State *env)
35 {
36     return asr_read(env);
37 }
38
39 target_ulong HELPER(asr_read)(CPUUniCore32State *env)
40 {
41     return asr_read(env);
42 }
43
44 static void asr_write(CPUUniCore32State *env, target_ulong val,
45                       target_ulong mask)
46 {
47     if (mask & ASR_NZCV) {
48         env->ZF = (~val) & ASR_Z;
49         env->NF = val;
50         env->CF = (val >> 29) & 1;
51         env->VF = (val << 3) & 0x80000000;
52     }
53
54     if ((env->uncached_asr ^ val) & mask & ASR_M) {
55         switch_mode(env, val & ASR_M);
56     }
57     mask &= ~ASR_NZCV;
58     env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask);
59 }
60
61 void cpu_asr_write(CPUUniCore32State *env, target_ulong val, target_ulong mask)
62 {
63     asr_write(env, val, mask);
64 }
65
66 void HELPER(asr_write)(CPUUniCore32State *env, target_ulong val,
67                        target_ulong mask)
68 {
69     asr_write(env, val, mask);
70 }
71
72 /* Access to user mode registers from privileged modes.  */
73 uint32_t HELPER(get_user_reg)(CPUUniCore32State *env, uint32_t regno)
74 {
75     uint32_t val;
76
77     if (regno == 29) {
78         val = env->banked_r29[0];
79     } else if (regno == 30) {
80         val = env->banked_r30[0];
81     } else {
82         val = env->regs[regno];
83     }
84     return val;
85 }
86
87 void HELPER(set_user_reg)(CPUUniCore32State *env, uint32_t regno, uint32_t val)
88 {
89     if (regno == 29) {
90         env->banked_r29[0] = val;
91     } else if (regno == 30) {
92         env->banked_r30[0] = val;
93     } else {
94         env->regs[regno] = val;
95     }
96 }
97
98 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
99    The only way to do that in TCG is a conditional branch, which clobbers
100    all our temporaries.  For now implement these as helper functions.  */
101
102 uint32_t HELPER(add_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
103 {
104     uint32_t result;
105     result = a + b;
106     env->NF = env->ZF = result;
107     env->CF = result < a;
108     env->VF = (a ^ b ^ -1) & (a ^ result);
109     return result;
110 }
111
112 uint32_t HELPER(adc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
113 {
114     uint32_t result;
115     if (!env->CF) {
116         result = a + b;
117         env->CF = result < a;
118     } else {
119         result = a + b + 1;
120         env->CF = result <= a;
121     }
122     env->VF = (a ^ b ^ -1) & (a ^ result);
123     env->NF = env->ZF = result;
124     return result;
125 }
126
127 uint32_t HELPER(sub_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
128 {
129     uint32_t result;
130     result = a - b;
131     env->NF = env->ZF = result;
132     env->CF = a >= b;
133     env->VF = (a ^ b) & (a ^ result);
134     return result;
135 }
136
137 uint32_t HELPER(sbc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
138 {
139     uint32_t result;
140     if (!env->CF) {
141         result = a - b - 1;
142         env->CF = a > b;
143     } else {
144         result = a - b;
145         env->CF = a >= b;
146     }
147     env->VF = (a ^ b) & (a ^ result);
148     env->NF = env->ZF = result;
149     return result;
150 }
151
152 /* Similarly for variable shift instructions.  */
153
154 uint32_t HELPER(shl)(uint32_t x, uint32_t i)
155 {
156     int shift = i & 0xff;
157     if (shift >= 32) {
158         return 0;
159     }
160     return x << shift;
161 }
162
163 uint32_t HELPER(shr)(uint32_t x, uint32_t i)
164 {
165     int shift = i & 0xff;
166     if (shift >= 32) {
167         return 0;
168     }
169     return (uint32_t)x >> shift;
170 }
171
172 uint32_t HELPER(sar)(uint32_t x, uint32_t i)
173 {
174     int shift = i & 0xff;
175     if (shift >= 32) {
176         shift = 31;
177     }
178     return (int32_t)x >> shift;
179 }
180
181 uint32_t HELPER(shl_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
182 {
183     int shift = i & 0xff;
184     if (shift >= 32) {
185         if (shift == 32) {
186             env->CF = x & 1;
187         } else {
188             env->CF = 0;
189         }
190         return 0;
191     } else if (shift != 0) {
192         env->CF = (x >> (32 - shift)) & 1;
193         return x << shift;
194     }
195     return x;
196 }
197
198 uint32_t HELPER(shr_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
199 {
200     int shift = i & 0xff;
201     if (shift >= 32) {
202         if (shift == 32) {
203             env->CF = (x >> 31) & 1;
204         } else {
205             env->CF = 0;
206         }
207         return 0;
208     } else if (shift != 0) {
209         env->CF = (x >> (shift - 1)) & 1;
210         return x >> shift;
211     }
212     return x;
213 }
214
215 uint32_t HELPER(sar_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
216 {
217     int shift = i & 0xff;
218     if (shift >= 32) {
219         env->CF = (x >> 31) & 1;
220         return (int32_t)x >> 31;
221     } else if (shift != 0) {
222         env->CF = (x >> (shift - 1)) & 1;
223         return (int32_t)x >> shift;
224     }
225     return x;
226 }
227
228 uint32_t HELPER(ror_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
229 {
230     int shift1, shift;
231     shift1 = i & 0xff;
232     shift = shift1 & 0x1f;
233     if (shift == 0) {
234         if (shift1 != 0) {
235             env->CF = (x >> 31) & 1;
236         }
237         return x;
238     } else {
239         env->CF = (x >> (shift - 1)) & 1;
240         return ((uint32_t)x >> shift) | (x << (32 - shift));
241     }
242 }
243
244 #ifndef CONFIG_USER_ONLY
245 void tlb_fill(CPUState *cs, target_ulong addr, int is_write,
246               int mmu_idx, uintptr_t retaddr)
247 {
248     int ret;
249
250     ret = uc32_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
251     if (unlikely(ret)) {
252         if (retaddr) {
253             /* now we have a real cpu fault */
254             cpu_restore_state(cs, retaddr);
255         }
256         cpu_loop_exit(cs);
257     }
258 }
259 #endif