]>
Commit | Line | Data |
---|---|---|
7a3f1944 FB |
1 | /* |
2 | SPARC translation | |
3 | ||
4 | Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at> | |
5 | ||
6 | This library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Lesser General Public | |
8 | License as published by the Free Software Foundation; either | |
9 | version 2 of the License, or (at your option) any later version. | |
10 | ||
11 | This library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public | |
17 | License along with this library; if not, write to the Free Software | |
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | /* | |
22 | SPARC has two pitfalls: Delay slots and (a)nullification. | |
23 | This is currently solved as follows: | |
24 | ||
25 | 'call' instructions simply execute the delay slot before the actual | |
26 | control transfer instructions. | |
27 | ||
28 | 'jmpl' instructions execute calculate the destination, then execute | |
29 | the delay slot and then do the control transfer. | |
30 | ||
31 | (conditional) branch instructions are the most difficult ones, as the | |
32 | delay slot may be nullified (ie. not executed). This happens when a | |
33 | conditional branch is not executed (thus no control transfer happens) | |
34 | and the 'anull' bit in the branch instruction opcode is set. This is | |
35 | currently solved by doing a jump after the delay slot instruction. | |
36 | ||
37 | There is also one big (currently unsolved) bug in the branch code: | |
38 | If a delay slot modifies the condition codes then the new condition | |
39 | codes, instead of the old ones will be used. | |
40 | ||
41 | TODO-list: | |
42 | ||
43 | FPU-Instructions | |
44 | Coprocessor-Instructions | |
45 | Fix above bug | |
46 | Check signedness issues | |
47 | Privileged instructions | |
48 | Register window overflow/underflow check | |
49 | Optimize synthetic instructions | |
50 | Optional alignment and privileged instruction check | |
51 | ||
52 | -- TMO, 09/03/03 | |
53 | */ | |
54 | ||
55 | #include <stdarg.h> | |
56 | #include <stdlib.h> | |
57 | #include <stdio.h> | |
58 | #include <string.h> | |
59 | #include <inttypes.h> | |
60 | ||
61 | #include "cpu.h" | |
62 | #include "exec-all.h" | |
63 | #include "disas.h" | |
64 | ||
65 | #define DEBUG_DISAS | |
66 | ||
67 | typedef struct DisasContext { | |
68 | uint8_t *pc; | |
69 | uint8_t *npc; | |
70 | void (*branch) (struct DisasContext *, uint32_t, uint32_t); | |
71 | unsigned int delay_slot:2; | |
72 | uint32_t insn; | |
73 | uint32_t target; | |
74 | int is_br; | |
75 | struct TranslationBlock *tb; | |
76 | } DisasContext; | |
77 | ||
78 | static uint16_t *gen_opc_ptr; | |
79 | static uint32_t *gen_opparam_ptr; | |
80 | extern FILE *logfile; | |
81 | extern int loglevel; | |
82 | ||
83 | enum { | |
84 | #define DEF(s,n,copy_size) INDEX_op_ ## s, | |
85 | #include "opc.h" | |
86 | #undef DEF | |
87 | NB_OPS | |
88 | }; | |
89 | ||
90 | #include "gen-op.h" | |
91 | ||
92 | #define GET_FIELD(X, FROM, TO) \ | |
93 | ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) | |
94 | ||
95 | #define IS_IMM (insn & (1<<13)) | |
96 | ||
97 | static void disas_sparc_insn (DisasContext *dc); | |
98 | ||
99 | typedef void (GenOpFunc)(void); | |
100 | typedef void (GenOpFunc1)(long); | |
101 | typedef void (GenOpFunc2)(long, long); | |
102 | typedef void (GenOpFunc3)(long, long, long); | |
103 | ||
104 | static GenOpFunc *gen_op_movl_TN_reg[2][32] = { | |
105 | { | |
106 | gen_op_movl_g0_T0, | |
107 | gen_op_movl_g1_T0, | |
108 | gen_op_movl_g2_T0, | |
109 | gen_op_movl_g3_T0, | |
110 | gen_op_movl_g4_T0, | |
111 | gen_op_movl_g5_T0, | |
112 | gen_op_movl_g6_T0, | |
113 | gen_op_movl_g7_T0, | |
114 | gen_op_movl_o0_T0, | |
115 | gen_op_movl_o1_T0, | |
116 | gen_op_movl_o2_T0, | |
117 | gen_op_movl_o3_T0, | |
118 | gen_op_movl_o4_T0, | |
119 | gen_op_movl_o5_T0, | |
120 | gen_op_movl_o6_T0, | |
121 | gen_op_movl_o7_T0, | |
122 | gen_op_movl_l0_T0, | |
123 | gen_op_movl_l1_T0, | |
124 | gen_op_movl_l2_T0, | |
125 | gen_op_movl_l3_T0, | |
126 | gen_op_movl_l4_T0, | |
127 | gen_op_movl_l5_T0, | |
128 | gen_op_movl_l6_T0, | |
129 | gen_op_movl_l7_T0, | |
130 | gen_op_movl_i0_T0, | |
131 | gen_op_movl_i1_T0, | |
132 | gen_op_movl_i2_T0, | |
133 | gen_op_movl_i3_T0, | |
134 | gen_op_movl_i4_T0, | |
135 | gen_op_movl_i5_T0, | |
136 | gen_op_movl_i6_T0, | |
137 | gen_op_movl_i7_T0, | |
138 | }, | |
139 | { | |
140 | gen_op_movl_g0_T1, | |
141 | gen_op_movl_g1_T1, | |
142 | gen_op_movl_g2_T1, | |
143 | gen_op_movl_g3_T1, | |
144 | gen_op_movl_g4_T1, | |
145 | gen_op_movl_g5_T1, | |
146 | gen_op_movl_g6_T1, | |
147 | gen_op_movl_g7_T1, | |
148 | gen_op_movl_o0_T1, | |
149 | gen_op_movl_o1_T1, | |
150 | gen_op_movl_o2_T1, | |
151 | gen_op_movl_o3_T1, | |
152 | gen_op_movl_o4_T1, | |
153 | gen_op_movl_o5_T1, | |
154 | gen_op_movl_o6_T1, | |
155 | gen_op_movl_o7_T1, | |
156 | gen_op_movl_l0_T1, | |
157 | gen_op_movl_l1_T1, | |
158 | gen_op_movl_l2_T1, | |
159 | gen_op_movl_l3_T1, | |
160 | gen_op_movl_l4_T1, | |
161 | gen_op_movl_l5_T1, | |
162 | gen_op_movl_l6_T1, | |
163 | gen_op_movl_l7_T1, | |
164 | gen_op_movl_i0_T1, | |
165 | gen_op_movl_i1_T1, | |
166 | gen_op_movl_i2_T1, | |
167 | gen_op_movl_i3_T1, | |
168 | gen_op_movl_i4_T1, | |
169 | gen_op_movl_i5_T1, | |
170 | gen_op_movl_i6_T1, | |
171 | gen_op_movl_i7_T1, | |
172 | } | |
173 | }; | |
174 | ||
175 | static GenOpFunc *gen_op_movl_reg_TN[3][32] = { | |
176 | { | |
177 | gen_op_movl_T0_g0, | |
178 | gen_op_movl_T0_g1, | |
179 | gen_op_movl_T0_g2, | |
180 | gen_op_movl_T0_g3, | |
181 | gen_op_movl_T0_g4, | |
182 | gen_op_movl_T0_g5, | |
183 | gen_op_movl_T0_g6, | |
184 | gen_op_movl_T0_g7, | |
185 | gen_op_movl_T0_o0, | |
186 | gen_op_movl_T0_o1, | |
187 | gen_op_movl_T0_o2, | |
188 | gen_op_movl_T0_o3, | |
189 | gen_op_movl_T0_o4, | |
190 | gen_op_movl_T0_o5, | |
191 | gen_op_movl_T0_o6, | |
192 | gen_op_movl_T0_o7, | |
193 | gen_op_movl_T0_l0, | |
194 | gen_op_movl_T0_l1, | |
195 | gen_op_movl_T0_l2, | |
196 | gen_op_movl_T0_l3, | |
197 | gen_op_movl_T0_l4, | |
198 | gen_op_movl_T0_l5, | |
199 | gen_op_movl_T0_l6, | |
200 | gen_op_movl_T0_l7, | |
201 | gen_op_movl_T0_i0, | |
202 | gen_op_movl_T0_i1, | |
203 | gen_op_movl_T0_i2, | |
204 | gen_op_movl_T0_i3, | |
205 | gen_op_movl_T0_i4, | |
206 | gen_op_movl_T0_i5, | |
207 | gen_op_movl_T0_i6, | |
208 | gen_op_movl_T0_i7, | |
209 | }, | |
210 | { | |
211 | gen_op_movl_T1_g0, | |
212 | gen_op_movl_T1_g1, | |
213 | gen_op_movl_T1_g2, | |
214 | gen_op_movl_T1_g3, | |
215 | gen_op_movl_T1_g4, | |
216 | gen_op_movl_T1_g5, | |
217 | gen_op_movl_T1_g6, | |
218 | gen_op_movl_T1_g7, | |
219 | gen_op_movl_T1_o0, | |
220 | gen_op_movl_T1_o1, | |
221 | gen_op_movl_T1_o2, | |
222 | gen_op_movl_T1_o3, | |
223 | gen_op_movl_T1_o4, | |
224 | gen_op_movl_T1_o5, | |
225 | gen_op_movl_T1_o6, | |
226 | gen_op_movl_T1_o7, | |
227 | gen_op_movl_T1_l0, | |
228 | gen_op_movl_T1_l1, | |
229 | gen_op_movl_T1_l2, | |
230 | gen_op_movl_T1_l3, | |
231 | gen_op_movl_T1_l4, | |
232 | gen_op_movl_T1_l5, | |
233 | gen_op_movl_T1_l6, | |
234 | gen_op_movl_T1_l7, | |
235 | gen_op_movl_T1_i0, | |
236 | gen_op_movl_T1_i1, | |
237 | gen_op_movl_T1_i2, | |
238 | gen_op_movl_T1_i3, | |
239 | gen_op_movl_T1_i4, | |
240 | gen_op_movl_T1_i5, | |
241 | gen_op_movl_T1_i6, | |
242 | gen_op_movl_T1_i7, | |
243 | }, | |
244 | { | |
245 | gen_op_movl_T2_g0, | |
246 | gen_op_movl_T2_g1, | |
247 | gen_op_movl_T2_g2, | |
248 | gen_op_movl_T2_g3, | |
249 | gen_op_movl_T2_g4, | |
250 | gen_op_movl_T2_g5, | |
251 | gen_op_movl_T2_g6, | |
252 | gen_op_movl_T2_g7, | |
253 | gen_op_movl_T2_o0, | |
254 | gen_op_movl_T2_o1, | |
255 | gen_op_movl_T2_o2, | |
256 | gen_op_movl_T2_o3, | |
257 | gen_op_movl_T2_o4, | |
258 | gen_op_movl_T2_o5, | |
259 | gen_op_movl_T2_o6, | |
260 | gen_op_movl_T2_o7, | |
261 | gen_op_movl_T2_l0, | |
262 | gen_op_movl_T2_l1, | |
263 | gen_op_movl_T2_l2, | |
264 | gen_op_movl_T2_l3, | |
265 | gen_op_movl_T2_l4, | |
266 | gen_op_movl_T2_l5, | |
267 | gen_op_movl_T2_l6, | |
268 | gen_op_movl_T2_l7, | |
269 | gen_op_movl_T2_i0, | |
270 | gen_op_movl_T2_i1, | |
271 | gen_op_movl_T2_i2, | |
272 | gen_op_movl_T2_i3, | |
273 | gen_op_movl_T2_i4, | |
274 | gen_op_movl_T2_i5, | |
275 | gen_op_movl_T2_i6, | |
276 | gen_op_movl_T2_i7, | |
277 | } | |
278 | }; | |
279 | ||
280 | static GenOpFunc1 *gen_op_movl_TN_im[3] = { | |
281 | gen_op_movl_T0_im, | |
282 | gen_op_movl_T1_im, | |
283 | gen_op_movl_T2_im | |
284 | }; | |
285 | ||
286 | static inline void gen_movl_imm_TN (int reg, int imm) | |
287 | { | |
288 | gen_op_movl_TN_im[reg](imm); | |
289 | } | |
290 | ||
291 | static inline void gen_movl_imm_T1 (int val) | |
292 | { | |
293 | gen_movl_imm_TN (1, val); | |
294 | } | |
295 | ||
296 | static inline void gen_movl_imm_T0 (int val) | |
297 | { | |
298 | gen_movl_imm_TN (0, val); | |
299 | } | |
300 | ||
301 | static inline void gen_movl_reg_TN (int reg, int t) | |
302 | { | |
303 | if (reg) gen_op_movl_reg_TN[t][reg](); | |
304 | else gen_movl_imm_TN (t, 0); | |
305 | } | |
306 | ||
307 | static inline void gen_movl_reg_T0 (int reg) | |
308 | { | |
309 | gen_movl_reg_TN (reg, 0); | |
310 | } | |
311 | ||
312 | static inline void gen_movl_reg_T1 (int reg) | |
313 | { | |
314 | gen_movl_reg_TN (reg, 1); | |
315 | } | |
316 | ||
317 | static inline void gen_movl_reg_T2 (int reg) | |
318 | { | |
319 | gen_movl_reg_TN (reg, 2); | |
320 | } | |
321 | ||
322 | static inline void gen_movl_TN_reg (int reg, int t) | |
323 | { | |
324 | if (reg) gen_op_movl_TN_reg[t][reg](); | |
325 | } | |
326 | ||
327 | static inline void gen_movl_T0_reg (int reg) | |
328 | { | |
329 | gen_movl_TN_reg (reg, 0); | |
330 | } | |
331 | ||
332 | static inline void gen_movl_T1_reg (int reg) | |
333 | { | |
334 | gen_movl_TN_reg (reg, 1); | |
335 | } | |
336 | ||
337 | static void do_branch (DisasContext *dc, uint32_t target, uint32_t insn) | |
338 | { | |
339 | unsigned int cond = GET_FIELD (insn, 3, 6), a = (insn & (1<<29)), ib = 0; | |
340 | target += (uint32_t) dc->pc-4; | |
341 | if (!a) disas_sparc_insn (dc); | |
342 | switch (cond) { | |
343 | case 0x0: gen_op_movl_T0_0 (); break; | |
344 | case 0x1: gen_op_eval_be (); break; | |
345 | case 0x2: gen_op_eval_ble (); break; | |
346 | case 0x3: gen_op_eval_bl (); break; | |
347 | case 0x4: gen_op_eval_bleu (); break; | |
348 | case 0x5: gen_op_eval_bcs (); break; | |
349 | case 0x6: gen_op_eval_bneg (); break; | |
350 | case 0x7: gen_op_eval_bvs (); break; | |
351 | case 0x8: gen_op_movl_T0_1 (); break; | |
352 | case 0x9: gen_op_eval_bne (); break; | |
353 | case 0xa: gen_op_eval_bg (); break; | |
354 | case 0xb: gen_op_eval_bge (); break; | |
355 | case 0xc: gen_op_eval_bgu (); break; | |
356 | case 0xd: gen_op_eval_bcc (); break; | |
357 | case 0xe: gen_op_eval_bpos (); break; | |
358 | case 0xf: gen_op_eval_bvc (); break; | |
359 | } | |
360 | if (a && ((cond|0x8) != 0x8)) { | |
361 | gen_op_generic_branch_a ((uint32_t) dc->tb, | |
362 | (uint32_t) dc->pc+4, target); | |
363 | disas_sparc_insn (dc); | |
364 | ib = 1; | |
365 | } | |
366 | else | |
367 | if (cond && !a) { | |
368 | gen_op_generic_branch ((uint32_t) dc->tb, (uint32_t) target, | |
369 | (uint32_t) dc->pc); | |
370 | ib = 1; | |
371 | } | |
372 | if (ib) dc->is_br = DISAS_JUMP; | |
373 | } | |
374 | ||
375 | /* target == 0x1 means CALL- else JMPL-instruction */ | |
376 | static void do_jump (DisasContext *dc, uint32_t target, uint32_t rd) | |
377 | { | |
378 | uint32_t orig_pc = (uint32_t) dc->pc-8; | |
379 | if (target != 0x1) | |
380 | gen_op_generic_jmp_1 (orig_pc, target); | |
381 | else | |
382 | gen_op_generic_jmp_2 (orig_pc); | |
383 | gen_movl_T1_reg (rd); | |
384 | dc->is_br = DISAS_JUMP; | |
385 | gen_op_movl_T0_0 (); | |
386 | } | |
387 | ||
388 | #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), b-a) | |
389 | ||
390 | static int | |
391 | sign_extend (x, len) | |
392 | int x, len; | |
393 | { | |
394 | int signbit = (1 << (len - 1)); | |
395 | int mask = (signbit << 1) - 1; | |
396 | return ((x & mask) ^ signbit) - signbit; | |
397 | } | |
398 | ||
399 | static void disas_sparc_insn (DisasContext *dc) | |
400 | { | |
401 | unsigned int insn, opc, rs1, rs2, rd; | |
402 | ||
403 | if (dc->delay_slot == 1) { | |
404 | insn = dc->insn; | |
405 | } else { | |
406 | if (dc->delay_slot) dc->delay_slot--; | |
407 | insn = htonl (*(unsigned int *) (dc->pc)); | |
408 | dc->pc += 4; | |
409 | } | |
410 | ||
411 | opc = GET_FIELD (insn, 0, 1); | |
412 | ||
413 | rd = GET_FIELD (insn, 2, 6); | |
414 | switch (opc) { | |
415 | case 0: /* branches/sethi */ | |
416 | { | |
417 | unsigned int xop = GET_FIELD (insn, 7, 9); | |
418 | int target; | |
419 | target = GET_FIELD (insn, 10, 31); | |
420 | switch (xop) { | |
421 | case 0x0: case 0x1: /* UNIMPL */ | |
422 | printf ("UNIMPLEMENTED: %p\n", dc->pc-4); | |
423 | exit (23); | |
424 | break; | |
425 | case 0x2: /* BN+x */ | |
426 | { | |
427 | target <<= 2; | |
428 | target = sign_extend (target, 22); | |
429 | do_branch (dc, target, insn); | |
430 | break; | |
431 | } | |
432 | case 0x3: /* FBN+x */ | |
433 | break; | |
434 | case 0x4: /* SETHI */ | |
435 | gen_movl_imm_T0 (target<<10); | |
436 | gen_movl_T0_reg (rd); | |
437 | break; | |
438 | case 0x5: /*CBN+x*/ | |
439 | break; | |
440 | } | |
441 | break; | |
442 | } | |
443 | case 1: /*CALL*/ | |
444 | { | |
445 | unsigned int target = GET_FIELDs (insn, 2, 31) << 2; | |
446 | if (dc->delay_slot) { | |
447 | do_jump (dc, target, 15); | |
448 | dc->delay_slot = 0; | |
449 | } else { | |
450 | dc->insn = insn; | |
451 | dc->delay_slot = 2; | |
452 | } | |
453 | break; | |
454 | } | |
455 | case 2: /* FPU & Logical Operations */ | |
456 | { | |
457 | unsigned int xop = GET_FIELD (insn, 7, 12); | |
458 | if (xop == 58) { /* generate trap */ | |
459 | dc->is_br = DISAS_JUMP; | |
460 | gen_op_jmp_im ((uint32_t) dc->pc); | |
461 | if (IS_IMM) gen_op_trap (GET_FIELD (insn, 25, 31)); | |
462 | /* else XXX*/ | |
463 | gen_op_movl_T0_0 (); | |
464 | break; | |
465 | } | |
466 | if (xop == 0x34 || xop == 0x35) { /* FPU Operations */ | |
467 | exit (33); | |
468 | } | |
469 | rs1 = GET_FIELD (insn, 13, 17); | |
470 | gen_movl_reg_T0 (rs1); | |
471 | if (IS_IMM) { /* immediate */ | |
472 | rs2 = GET_FIELDs (insn, 20, 31); | |
473 | gen_movl_imm_T1 (rs2); | |
474 | } else { /* register */ | |
475 | rs2 = GET_FIELD (insn, 27, 31); | |
476 | gen_movl_reg_T1 (rs2); | |
477 | } | |
478 | if (xop < 0x20) { | |
479 | switch (xop &~ 0x10) { | |
480 | case 0x0: | |
481 | gen_op_add_T1_T0 (); | |
482 | break; | |
483 | case 0x1: | |
484 | gen_op_and_T1_T0 (); | |
485 | break; | |
486 | case 0x2: | |
487 | gen_op_or_T1_T0 (); | |
488 | break; | |
489 | case 0x3: | |
490 | gen_op_xor_T1_T0 (); | |
491 | break; | |
492 | case 0x4: | |
493 | gen_op_sub_T1_T0 (); | |
494 | break; | |
495 | case 0x5: | |
496 | gen_op_andn_T1_T0 (); | |
497 | break; | |
498 | case 0x6: | |
499 | gen_op_orn_T1_T0 (); | |
500 | break; | |
501 | case 0x7: | |
502 | gen_op_xnor_T1_T0 (); | |
503 | break; | |
504 | case 0x8: | |
505 | gen_op_addx_T1_T0 (); | |
506 | break; | |
507 | case 0xa: | |
508 | gen_op_umul_T1_T0 (); | |
509 | break; | |
510 | case 0xb: | |
511 | gen_op_smul_T1_T0 (); | |
512 | break; | |
513 | case 0xc: | |
514 | gen_op_subx_T1_T0 (); | |
515 | break; | |
516 | case 0xe: | |
517 | gen_op_udiv_T1_T0 (); | |
518 | break; | |
519 | case 0xf: | |
520 | gen_op_sdiv_T1_T0 (); | |
521 | break; | |
522 | default: | |
523 | exit (17); | |
524 | break; | |
525 | } | |
526 | gen_movl_T0_reg (rd); | |
527 | if (xop & 0x10) { | |
528 | gen_op_set_flags (); | |
529 | } | |
530 | } else { | |
531 | switch (xop) { | |
532 | case 0x25: /* SLL */ | |
533 | gen_op_sll (); | |
534 | break; | |
535 | case 0x26: | |
536 | gen_op_srl (); | |
537 | break; | |
538 | case 0x27: | |
539 | gen_op_sra (); | |
540 | break; | |
541 | case 0x28: case 0x30: | |
542 | { | |
543 | unsigned int rdi = GET_FIELD (insn, 13, 17); | |
544 | if (!rdi) (xop==0x28?gen_op_rdy ():gen_op_wry()); | |
545 | /* else gen_op_su_trap (); */ | |
546 | break; | |
547 | } | |
548 | /* Problem with jmpl: if restore is executed in the delay | |
549 | slot, then the wrong registers are beeing used */ | |
550 | case 0x38: /* jmpl */ | |
551 | { | |
552 | if (dc->delay_slot) { | |
553 | gen_op_add_T1_T0 (); | |
554 | do_jump (dc, 1, rd); | |
555 | dc->delay_slot = 0; | |
556 | } else { | |
557 | gen_op_add_T1_T0 (); | |
558 | gen_op_jmpl (); | |
559 | dc->insn = insn; | |
560 | dc->delay_slot = 2; | |
561 | } | |
562 | break; | |
563 | } | |
564 | case 0x3c: /* save */ | |
565 | gen_op_add_T1_T0 (); | |
566 | gen_op_save (); | |
567 | gen_movl_T0_reg (rd); | |
568 | break; | |
569 | case 0x3d: /* restore */ | |
570 | gen_op_add_T1_T0 (); | |
571 | gen_op_restore (); | |
572 | gen_movl_T0_reg (rd); | |
573 | break; | |
574 | } | |
575 | } | |
576 | break; | |
577 | } | |
578 | case 3: /* load/store instructions */ | |
579 | { | |
580 | unsigned int xop = GET_FIELD (insn, 7, 12); | |
581 | rs1 = GET_FIELD (insn, 13, 17); | |
582 | gen_movl_reg_T0 (rs1); | |
583 | if (IS_IMM) { /* immediate */ | |
584 | rs2 = GET_FIELDs (insn, 20, 31); | |
585 | gen_movl_imm_T1 (rs2); | |
586 | } else { /* register */ | |
587 | rs2 = GET_FIELD (insn, 27, 31); | |
588 | gen_movl_reg_T1 (rs2); | |
589 | } | |
590 | gen_op_add_T1_T0 (); | |
591 | if (xop < 4 || xop > 7) { | |
592 | switch (xop) { | |
593 | case 0x0: /* load word */ | |
594 | gen_op_ld (); | |
595 | break; | |
596 | case 0x1: /* load unsigned byte */ | |
597 | gen_op_ldub (); | |
598 | break; | |
599 | case 0x2: /* load unsigned halfword */ | |
600 | gen_op_lduh (); | |
601 | break; | |
602 | case 0x3: /* load double word */ | |
603 | gen_op_ldd (); | |
604 | gen_movl_T0_reg (rd+1); | |
605 | break; | |
606 | case 0x9: /* load signed byte */ | |
607 | gen_op_ldsb (); | |
608 | break; | |
609 | case 0xa: /* load signed halfword */ | |
610 | gen_op_ldsh (); | |
611 | break; | |
612 | case 0xd: /* ldstub -- XXX: should be atomically */ | |
613 | gen_op_ldstub (); | |
614 | break; | |
615 | case 0x0f: /* swap register with memory. Also atomically */ | |
616 | gen_op_swap (); | |
617 | break; | |
618 | } | |
619 | gen_movl_T1_reg (rd); | |
620 | } else if (xop < 8) { | |
621 | gen_movl_reg_T1 (rd); | |
622 | switch (xop) { | |
623 | case 0x4: | |
624 | gen_op_st (); | |
625 | break; | |
626 | case 0x5: | |
627 | gen_op_stb (); | |
628 | break; | |
629 | case 0x6: | |
630 | gen_op_sth (); | |
631 | break; | |
632 | case 0x7: | |
633 | gen_op_st (); | |
634 | gen_movl_reg_T1 (rd+1); | |
635 | gen_op_st (); | |
636 | break; | |
637 | } | |
638 | } | |
639 | } | |
640 | } | |
641 | } | |
642 | ||
643 | static inline int gen_intermediate_code_internal (TranslationBlock *tb, int spc) | |
644 | { | |
645 | uint8_t *pc_start = (uint8_t *) tb->pc; | |
646 | uint16_t *gen_opc_end; | |
647 | DisasContext dc; | |
648 | ||
649 | memset (&dc, 0, sizeof (dc)); | |
650 | if (spc) { | |
651 | printf ("SearchPC not yet supported\n"); | |
652 | exit (0); | |
653 | } | |
654 | dc.tb = tb; | |
655 | dc.pc = pc_start; | |
656 | ||
657 | gen_opc_ptr = gen_opc_buf; | |
658 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; | |
659 | gen_opparam_ptr = gen_opparam_buf; | |
660 | ||
661 | do { | |
662 | disas_sparc_insn (&dc); | |
663 | } while (!dc.is_br && (gen_opc_ptr < gen_opc_end) && | |
664 | (dc.pc - pc_start) < (TARGET_PAGE_SIZE - 32)); | |
665 | ||
666 | switch (dc.is_br) { | |
667 | case DISAS_JUMP: | |
668 | case DISAS_TB_JUMP: | |
669 | gen_op_exit_tb (); | |
670 | break; | |
671 | } | |
672 | ||
673 | *gen_opc_ptr = INDEX_op_end; | |
674 | #ifdef DEBUG_DISAS | |
675 | if (loglevel) { | |
676 | fprintf (logfile, "--------------\n"); | |
677 | fprintf (logfile, "IN: %s\n", lookup_symbol (pc_start)); | |
678 | disas(logfile, pc_start, dc.pc - pc_start, 0, 0); | |
679 | fprintf(logfile, "\n"); | |
680 | fprintf(logfile, "OP:\n"); | |
681 | dump_ops(gen_opc_buf, gen_opparam_buf); | |
682 | fprintf(logfile, "\n"); | |
683 | } | |
684 | #endif | |
685 | ||
686 | return 0; | |
687 | } | |
688 | ||
689 | int gen_intermediate_code (CPUSPARCState *env, TranslationBlock *tb) | |
690 | { | |
691 | return gen_intermediate_code_internal(tb, 0); | |
692 | } | |
693 | ||
694 | int gen_intermediate_code_pc (CPUSPARCState *env, TranslationBlock *tb) | |
695 | { | |
696 | return gen_intermediate_code_internal(tb, 1); | |
697 | } | |
698 | ||
699 | void *mycpu; | |
700 | ||
701 | CPUSPARCState *cpu_sparc_init (void) | |
702 | { | |
703 | CPUSPARCState *env; | |
704 | ||
705 | cpu_exec_init (); | |
706 | ||
707 | if (!(env = malloc (sizeof(CPUSPARCState)))) | |
708 | return (NULL); | |
709 | memset (env, 0, sizeof (*env)); | |
710 | if (!(env->regwptr = malloc (0x2000))) | |
711 | return (NULL); | |
712 | memset (env->regwptr, 0, 0x2000); | |
713 | env->regwptr += 127; | |
714 | env->user_mode_only = 1; | |
715 | mycpu = env; | |
716 | return (env); | |
717 | } | |
718 | ||
719 | #define GET_FLAG(a,b) ((env->psr & a)?b:'-') | |
720 | ||
721 | void cpu_sparc_dump_state (CPUSPARCState *env, FILE *f, int flags) | |
722 | { | |
723 | int i, x; | |
724 | ||
725 | fprintf (f, "@PC: %p\n", (void *) env->pc); | |
726 | fprintf (f, "General Registers:\n"); | |
727 | for (i=0;i<4;i++) | |
728 | fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]); | |
729 | fprintf (f, "\n"); | |
730 | for (;i<8;i++) | |
731 | fprintf (f, "%%g%c: %%%08x\t", i+'0', env->gregs[i]); | |
732 | fprintf (f, "\nCurrent Register Window:\n"); | |
733 | for (x=0;x<3;x++) { | |
734 | for (i=0;i<4;i++) | |
735 | fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':(x==1?'l':'i')), i, env->regwptr[i+x*8]); | |
736 | fprintf (f, "\n"); | |
737 | for (;i<8;i++) | |
738 | fprintf (f, "%%%c%d: %%%08x\t", (x==0?'o':x==1?'l':'i'), i, env->regwptr[i+x*8]); | |
739 | fprintf (f, "\n"); | |
740 | } | |
741 | fprintf (f, "PSR: %x -> %c%c%c%c\n", env->psr, | |
742 | GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), | |
743 | GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C')); | |
744 | } |