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