1 | /* |
2 | * Moxie emulation for qemu: main translation routines. |
3 | * |
4 | * Copyright (c) 2009, 2013 Anthony Green |
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 License |
8 | * as published by the Free Software Foundation; either version 2.1 of |
9 | * the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, but |
12 | * 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 License |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | /* For information on the Moxie architecture, see |
21 | * http://moxielogic.org/wiki |
22 | */ |
23 | |
24 | #include "qemu/osdep.h" |
25 | |
26 | #include "cpu.h" |
27 | #include "exec/exec-all.h" |
28 | #include "disas/disas.h" |
29 | #include "tcg-op.h" |
30 | #include "exec/cpu_ldst.h" |
31 | #include "qemu/qemu-print.h" |
32 | |
33 | #include "exec/helper-proto.h" |
34 | #include "exec/helper-gen.h" |
35 | #include "exec/log.h" |
36 | |
37 | /* This is the state at translation time. */ |
38 | typedef struct DisasContext { |
39 | struct TranslationBlock *tb; |
40 | target_ulong pc, saved_pc; |
41 | uint32_t opcode; |
42 | uint32_t fp_status; |
43 | /* Routine used to access memory */ |
44 | int memidx; |
45 | int bstate; |
46 | target_ulong btarget; |
47 | int singlestep_enabled; |
48 | } DisasContext; |
49 | |
50 | enum { |
51 | BS_NONE = 0, /* We go out of the TB without reaching a branch or an |
52 | * exception condition */ |
53 | BS_STOP = 1, /* We want to stop translation for any reason */ |
54 | BS_BRANCH = 2, /* We reached a branch condition */ |
55 | BS_EXCP = 3, /* We reached an exception condition */ |
56 | }; |
57 | |
58 | static TCGv cpu_pc; |
59 | static TCGv cpu_gregs[16]; |
60 | static TCGv cc_a, cc_b; |
61 | |
62 | #include "exec/gen-icount.h" |
63 | |
64 | #define REG(x) (cpu_gregs[x]) |
65 | |
66 | /* Extract the signed 10-bit offset from a 16-bit branch |
67 | instruction. */ |
68 | static int (int opcode) |
69 | { |
70 | return (((signed short)((opcode & ((1 << 10) - 1)) << 6)) >> 6) << 1; |
71 | } |
72 | |
73 | void moxie_cpu_dump_state(CPUState *cs, FILE *f, int flags) |
74 | { |
75 | MoxieCPU *cpu = MOXIE_CPU(cs); |
76 | CPUMoxieState *env = &cpu->env; |
77 | int i; |
78 | qemu_fprintf(f, "pc=0x%08x\n" , env->pc); |
79 | qemu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n" , |
80 | env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); |
81 | for (i = 4; i < 16; i += 4) { |
82 | qemu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n" , |
83 | i - 2, env->gregs[i], i - 1, env->gregs[i + 1], |
84 | i, env->gregs[i + 2], i + 1, env->gregs[i + 3]); |
85 | } |
86 | for (i = 4; i < 16; i += 4) { |
87 | qemu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n" , |
88 | i - 2, env->sregs[i], i - 1, env->sregs[i + 1], |
89 | i, env->sregs[i + 2], i + 1, env->sregs[i + 3]); |
90 | } |
91 | } |
92 | |
93 | void moxie_translate_init(void) |
94 | { |
95 | int i; |
96 | static const char * const gregnames[16] = { |
97 | "$fp" , "$sp" , "$r0" , "$r1" , |
98 | "$r2" , "$r3" , "$r4" , "$r5" , |
99 | "$r6" , "$r7" , "$r8" , "$r9" , |
100 | "$r10" , "$r11" , "$r12" , "$r13" |
101 | }; |
102 | |
103 | cpu_pc = tcg_global_mem_new_i32(cpu_env, |
104 | offsetof(CPUMoxieState, pc), "$pc" ); |
105 | for (i = 0; i < 16; i++) |
106 | cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env, |
107 | offsetof(CPUMoxieState, gregs[i]), |
108 | gregnames[i]); |
109 | |
110 | cc_a = tcg_global_mem_new_i32(cpu_env, |
111 | offsetof(CPUMoxieState, cc_a), "cc_a" ); |
112 | cc_b = tcg_global_mem_new_i32(cpu_env, |
113 | offsetof(CPUMoxieState, cc_b), "cc_b" ); |
114 | } |
115 | |
116 | static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) |
117 | { |
118 | if (unlikely(ctx->singlestep_enabled)) { |
119 | return false; |
120 | } |
121 | |
122 | #ifndef CONFIG_USER_ONLY |
123 | return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); |
124 | #else |
125 | return true; |
126 | #endif |
127 | } |
128 | |
129 | static inline void gen_goto_tb(CPUMoxieState *env, DisasContext *ctx, |
130 | int n, target_ulong dest) |
131 | { |
132 | if (use_goto_tb(ctx, dest)) { |
133 | tcg_gen_goto_tb(n); |
134 | tcg_gen_movi_i32(cpu_pc, dest); |
135 | tcg_gen_exit_tb(ctx->tb, n); |
136 | } else { |
137 | tcg_gen_movi_i32(cpu_pc, dest); |
138 | if (ctx->singlestep_enabled) { |
139 | gen_helper_debug(cpu_env); |
140 | } |
141 | tcg_gen_exit_tb(NULL, 0); |
142 | } |
143 | } |
144 | |
145 | static int decode_opc(MoxieCPU *cpu, DisasContext *ctx) |
146 | { |
147 | CPUMoxieState *env = &cpu->env; |
148 | |
149 | /* Local cache for the instruction opcode. */ |
150 | int opcode; |
151 | /* Set the default instruction length. */ |
152 | int length = 2; |
153 | |
154 | /* Examine the 16-bit opcode. */ |
155 | opcode = ctx->opcode; |
156 | |
157 | /* Decode instruction. */ |
158 | if (opcode & (1 << 15)) { |
159 | if (opcode & (1 << 14)) { |
160 | /* This is a Form 3 instruction. */ |
161 | int inst = (opcode >> 10 & 0xf); |
162 | |
163 | #define BRANCH(cond) \ |
164 | do { \ |
165 | TCGLabel *l1 = gen_new_label(); \ |
166 | tcg_gen_brcond_i32(cond, cc_a, cc_b, l1); \ |
167 | gen_goto_tb(env, ctx, 1, ctx->pc+2); \ |
168 | gen_set_label(l1); \ |
169 | gen_goto_tb(env, ctx, 0, extract_branch_offset(opcode) + ctx->pc+2); \ |
170 | ctx->bstate = BS_BRANCH; \ |
171 | } while (0) |
172 | |
173 | switch (inst) { |
174 | case 0x00: /* beq */ |
175 | BRANCH(TCG_COND_EQ); |
176 | break; |
177 | case 0x01: /* bne */ |
178 | BRANCH(TCG_COND_NE); |
179 | break; |
180 | case 0x02: /* blt */ |
181 | BRANCH(TCG_COND_LT); |
182 | break; |
183 | case 0x03: /* bgt */ |
184 | BRANCH(TCG_COND_GT); |
185 | break; |
186 | case 0x04: /* bltu */ |
187 | BRANCH(TCG_COND_LTU); |
188 | break; |
189 | case 0x05: /* bgtu */ |
190 | BRANCH(TCG_COND_GTU); |
191 | break; |
192 | case 0x06: /* bge */ |
193 | BRANCH(TCG_COND_GE); |
194 | break; |
195 | case 0x07: /* ble */ |
196 | BRANCH(TCG_COND_LE); |
197 | break; |
198 | case 0x08: /* bgeu */ |
199 | BRANCH(TCG_COND_GEU); |
200 | break; |
201 | case 0x09: /* bleu */ |
202 | BRANCH(TCG_COND_LEU); |
203 | break; |
204 | default: |
205 | { |
206 | TCGv temp = tcg_temp_new_i32(); |
207 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
208 | tcg_gen_movi_i32(temp, MOXIE_EX_BAD); |
209 | gen_helper_raise_exception(cpu_env, temp); |
210 | tcg_temp_free_i32(temp); |
211 | } |
212 | break; |
213 | } |
214 | } else { |
215 | /* This is a Form 2 instruction. */ |
216 | int inst = (opcode >> 12 & 0x3); |
217 | switch (inst) { |
218 | case 0x00: /* inc */ |
219 | { |
220 | int a = (opcode >> 8) & 0xf; |
221 | unsigned int v = (opcode & 0xff); |
222 | tcg_gen_addi_i32(REG(a), REG(a), v); |
223 | } |
224 | break; |
225 | case 0x01: /* dec */ |
226 | { |
227 | int a = (opcode >> 8) & 0xf; |
228 | unsigned int v = (opcode & 0xff); |
229 | tcg_gen_subi_i32(REG(a), REG(a), v); |
230 | } |
231 | break; |
232 | case 0x02: /* gsr */ |
233 | { |
234 | int a = (opcode >> 8) & 0xf; |
235 | unsigned v = (opcode & 0xff); |
236 | tcg_gen_ld_i32(REG(a), cpu_env, |
237 | offsetof(CPUMoxieState, sregs[v])); |
238 | } |
239 | break; |
240 | case 0x03: /* ssr */ |
241 | { |
242 | int a = (opcode >> 8) & 0xf; |
243 | unsigned v = (opcode & 0xff); |
244 | tcg_gen_st_i32(REG(a), cpu_env, |
245 | offsetof(CPUMoxieState, sregs[v])); |
246 | } |
247 | break; |
248 | default: |
249 | { |
250 | TCGv temp = tcg_temp_new_i32(); |
251 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
252 | tcg_gen_movi_i32(temp, MOXIE_EX_BAD); |
253 | gen_helper_raise_exception(cpu_env, temp); |
254 | tcg_temp_free_i32(temp); |
255 | } |
256 | break; |
257 | } |
258 | } |
259 | } else { |
260 | /* This is a Form 1 instruction. */ |
261 | int inst = opcode >> 8; |
262 | switch (inst) { |
263 | case 0x00: /* nop */ |
264 | break; |
265 | case 0x01: /* ldi.l (immediate) */ |
266 | { |
267 | int reg = (opcode >> 4) & 0xf; |
268 | int val = cpu_ldl_code(env, ctx->pc+2); |
269 | tcg_gen_movi_i32(REG(reg), val); |
270 | length = 6; |
271 | } |
272 | break; |
273 | case 0x02: /* mov (register-to-register) */ |
274 | { |
275 | int dest = (opcode >> 4) & 0xf; |
276 | int src = opcode & 0xf; |
277 | tcg_gen_mov_i32(REG(dest), REG(src)); |
278 | } |
279 | break; |
280 | case 0x03: /* jsra */ |
281 | { |
282 | TCGv t1 = tcg_temp_new_i32(); |
283 | TCGv t2 = tcg_temp_new_i32(); |
284 | |
285 | tcg_gen_movi_i32(t1, ctx->pc + 6); |
286 | |
287 | /* Make space for the static chain and return address. */ |
288 | tcg_gen_subi_i32(t2, REG(1), 8); |
289 | tcg_gen_mov_i32(REG(1), t2); |
290 | tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); |
291 | |
292 | /* Push the current frame pointer. */ |
293 | tcg_gen_subi_i32(t2, REG(1), 4); |
294 | tcg_gen_mov_i32(REG(1), t2); |
295 | tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); |
296 | |
297 | /* Set the pc and $fp. */ |
298 | tcg_gen_mov_i32(REG(0), REG(1)); |
299 | |
300 | gen_goto_tb(env, ctx, 0, cpu_ldl_code(env, ctx->pc+2)); |
301 | |
302 | tcg_temp_free_i32(t1); |
303 | tcg_temp_free_i32(t2); |
304 | |
305 | ctx->bstate = BS_BRANCH; |
306 | length = 6; |
307 | } |
308 | break; |
309 | case 0x04: /* ret */ |
310 | { |
311 | TCGv t1 = tcg_temp_new_i32(); |
312 | |
313 | /* The new $sp is the old $fp. */ |
314 | tcg_gen_mov_i32(REG(1), REG(0)); |
315 | |
316 | /* Pop the frame pointer. */ |
317 | tcg_gen_qemu_ld32u(REG(0), REG(1), ctx->memidx); |
318 | tcg_gen_addi_i32(t1, REG(1), 4); |
319 | tcg_gen_mov_i32(REG(1), t1); |
320 | |
321 | |
322 | /* Pop the return address and skip over the static chain |
323 | slot. */ |
324 | tcg_gen_qemu_ld32u(cpu_pc, REG(1), ctx->memidx); |
325 | tcg_gen_addi_i32(t1, REG(1), 8); |
326 | tcg_gen_mov_i32(REG(1), t1); |
327 | |
328 | tcg_temp_free_i32(t1); |
329 | |
330 | /* Jump... */ |
331 | tcg_gen_exit_tb(NULL, 0); |
332 | |
333 | ctx->bstate = BS_BRANCH; |
334 | } |
335 | break; |
336 | case 0x05: /* add.l */ |
337 | { |
338 | int a = (opcode >> 4) & 0xf; |
339 | int b = opcode & 0xf; |
340 | |
341 | tcg_gen_add_i32(REG(a), REG(a), REG(b)); |
342 | } |
343 | break; |
344 | case 0x06: /* push */ |
345 | { |
346 | int a = (opcode >> 4) & 0xf; |
347 | int b = opcode & 0xf; |
348 | |
349 | TCGv t1 = tcg_temp_new_i32(); |
350 | tcg_gen_subi_i32(t1, REG(a), 4); |
351 | tcg_gen_mov_i32(REG(a), t1); |
352 | tcg_gen_qemu_st32(REG(b), REG(a), ctx->memidx); |
353 | tcg_temp_free_i32(t1); |
354 | } |
355 | break; |
356 | case 0x07: /* pop */ |
357 | { |
358 | int a = (opcode >> 4) & 0xf; |
359 | int b = opcode & 0xf; |
360 | TCGv t1 = tcg_temp_new_i32(); |
361 | |
362 | tcg_gen_qemu_ld32u(REG(b), REG(a), ctx->memidx); |
363 | tcg_gen_addi_i32(t1, REG(a), 4); |
364 | tcg_gen_mov_i32(REG(a), t1); |
365 | tcg_temp_free_i32(t1); |
366 | } |
367 | break; |
368 | case 0x08: /* lda.l */ |
369 | { |
370 | int reg = (opcode >> 4) & 0xf; |
371 | |
372 | TCGv ptr = tcg_temp_new_i32(); |
373 | tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); |
374 | tcg_gen_qemu_ld32u(REG(reg), ptr, ctx->memidx); |
375 | tcg_temp_free_i32(ptr); |
376 | |
377 | length = 6; |
378 | } |
379 | break; |
380 | case 0x09: /* sta.l */ |
381 | { |
382 | int val = (opcode >> 4) & 0xf; |
383 | |
384 | TCGv ptr = tcg_temp_new_i32(); |
385 | tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); |
386 | tcg_gen_qemu_st32(REG(val), ptr, ctx->memidx); |
387 | tcg_temp_free_i32(ptr); |
388 | |
389 | length = 6; |
390 | } |
391 | break; |
392 | case 0x0a: /* ld.l (register indirect) */ |
393 | { |
394 | int src = opcode & 0xf; |
395 | int dest = (opcode >> 4) & 0xf; |
396 | |
397 | tcg_gen_qemu_ld32u(REG(dest), REG(src), ctx->memidx); |
398 | } |
399 | break; |
400 | case 0x0b: /* st.l */ |
401 | { |
402 | int dest = (opcode >> 4) & 0xf; |
403 | int val = opcode & 0xf; |
404 | |
405 | tcg_gen_qemu_st32(REG(val), REG(dest), ctx->memidx); |
406 | } |
407 | break; |
408 | case 0x0c: /* ldo.l */ |
409 | { |
410 | int a = (opcode >> 4) & 0xf; |
411 | int b = opcode & 0xf; |
412 | |
413 | TCGv t1 = tcg_temp_new_i32(); |
414 | TCGv t2 = tcg_temp_new_i32(); |
415 | tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); |
416 | tcg_gen_qemu_ld32u(t2, t1, ctx->memidx); |
417 | tcg_gen_mov_i32(REG(a), t2); |
418 | |
419 | tcg_temp_free_i32(t1); |
420 | tcg_temp_free_i32(t2); |
421 | |
422 | length = 6; |
423 | } |
424 | break; |
425 | case 0x0d: /* sto.l */ |
426 | { |
427 | int a = (opcode >> 4) & 0xf; |
428 | int b = opcode & 0xf; |
429 | |
430 | TCGv t1 = tcg_temp_new_i32(); |
431 | TCGv t2 = tcg_temp_new_i32(); |
432 | tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); |
433 | tcg_gen_qemu_st32(REG(b), t1, ctx->memidx); |
434 | |
435 | tcg_temp_free_i32(t1); |
436 | tcg_temp_free_i32(t2); |
437 | |
438 | length = 6; |
439 | } |
440 | break; |
441 | case 0x0e: /* cmp */ |
442 | { |
443 | int a = (opcode >> 4) & 0xf; |
444 | int b = opcode & 0xf; |
445 | |
446 | tcg_gen_mov_i32(cc_a, REG(a)); |
447 | tcg_gen_mov_i32(cc_b, REG(b)); |
448 | } |
449 | break; |
450 | case 0x19: /* jsr */ |
451 | { |
452 | int fnreg = (opcode >> 4) & 0xf; |
453 | |
454 | /* Load the stack pointer into T0. */ |
455 | TCGv t1 = tcg_temp_new_i32(); |
456 | TCGv t2 = tcg_temp_new_i32(); |
457 | |
458 | tcg_gen_movi_i32(t1, ctx->pc+2); |
459 | |
460 | /* Make space for the static chain and return address. */ |
461 | tcg_gen_subi_i32(t2, REG(1), 8); |
462 | tcg_gen_mov_i32(REG(1), t2); |
463 | tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); |
464 | |
465 | /* Push the current frame pointer. */ |
466 | tcg_gen_subi_i32(t2, REG(1), 4); |
467 | tcg_gen_mov_i32(REG(1), t2); |
468 | tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); |
469 | |
470 | /* Set the pc and $fp. */ |
471 | tcg_gen_mov_i32(REG(0), REG(1)); |
472 | tcg_gen_mov_i32(cpu_pc, REG(fnreg)); |
473 | tcg_temp_free_i32(t1); |
474 | tcg_temp_free_i32(t2); |
475 | tcg_gen_exit_tb(NULL, 0); |
476 | ctx->bstate = BS_BRANCH; |
477 | } |
478 | break; |
479 | case 0x1a: /* jmpa */ |
480 | { |
481 | tcg_gen_movi_i32(cpu_pc, cpu_ldl_code(env, ctx->pc+2)); |
482 | tcg_gen_exit_tb(NULL, 0); |
483 | ctx->bstate = BS_BRANCH; |
484 | length = 6; |
485 | } |
486 | break; |
487 | case 0x1b: /* ldi.b (immediate) */ |
488 | { |
489 | int reg = (opcode >> 4) & 0xf; |
490 | int val = cpu_ldl_code(env, ctx->pc+2); |
491 | tcg_gen_movi_i32(REG(reg), val); |
492 | length = 6; |
493 | } |
494 | break; |
495 | case 0x1c: /* ld.b (register indirect) */ |
496 | { |
497 | int src = opcode & 0xf; |
498 | int dest = (opcode >> 4) & 0xf; |
499 | |
500 | tcg_gen_qemu_ld8u(REG(dest), REG(src), ctx->memidx); |
501 | } |
502 | break; |
503 | case 0x1d: /* lda.b */ |
504 | { |
505 | int reg = (opcode >> 4) & 0xf; |
506 | |
507 | TCGv ptr = tcg_temp_new_i32(); |
508 | tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); |
509 | tcg_gen_qemu_ld8u(REG(reg), ptr, ctx->memidx); |
510 | tcg_temp_free_i32(ptr); |
511 | |
512 | length = 6; |
513 | } |
514 | break; |
515 | case 0x1e: /* st.b */ |
516 | { |
517 | int dest = (opcode >> 4) & 0xf; |
518 | int val = opcode & 0xf; |
519 | |
520 | tcg_gen_qemu_st8(REG(val), REG(dest), ctx->memidx); |
521 | } |
522 | break; |
523 | case 0x1f: /* sta.b */ |
524 | { |
525 | int val = (opcode >> 4) & 0xf; |
526 | |
527 | TCGv ptr = tcg_temp_new_i32(); |
528 | tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); |
529 | tcg_gen_qemu_st8(REG(val), ptr, ctx->memidx); |
530 | tcg_temp_free_i32(ptr); |
531 | |
532 | length = 6; |
533 | } |
534 | break; |
535 | case 0x20: /* ldi.s (immediate) */ |
536 | { |
537 | int reg = (opcode >> 4) & 0xf; |
538 | int val = cpu_ldl_code(env, ctx->pc+2); |
539 | tcg_gen_movi_i32(REG(reg), val); |
540 | length = 6; |
541 | } |
542 | break; |
543 | case 0x21: /* ld.s (register indirect) */ |
544 | { |
545 | int src = opcode & 0xf; |
546 | int dest = (opcode >> 4) & 0xf; |
547 | |
548 | tcg_gen_qemu_ld16u(REG(dest), REG(src), ctx->memidx); |
549 | } |
550 | break; |
551 | case 0x22: /* lda.s */ |
552 | { |
553 | int reg = (opcode >> 4) & 0xf; |
554 | |
555 | TCGv ptr = tcg_temp_new_i32(); |
556 | tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); |
557 | tcg_gen_qemu_ld16u(REG(reg), ptr, ctx->memidx); |
558 | tcg_temp_free_i32(ptr); |
559 | |
560 | length = 6; |
561 | } |
562 | break; |
563 | case 0x23: /* st.s */ |
564 | { |
565 | int dest = (opcode >> 4) & 0xf; |
566 | int val = opcode & 0xf; |
567 | |
568 | tcg_gen_qemu_st16(REG(val), REG(dest), ctx->memidx); |
569 | } |
570 | break; |
571 | case 0x24: /* sta.s */ |
572 | { |
573 | int val = (opcode >> 4) & 0xf; |
574 | |
575 | TCGv ptr = tcg_temp_new_i32(); |
576 | tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); |
577 | tcg_gen_qemu_st16(REG(val), ptr, ctx->memidx); |
578 | tcg_temp_free_i32(ptr); |
579 | |
580 | length = 6; |
581 | } |
582 | break; |
583 | case 0x25: /* jmp */ |
584 | { |
585 | int reg = (opcode >> 4) & 0xf; |
586 | tcg_gen_mov_i32(cpu_pc, REG(reg)); |
587 | tcg_gen_exit_tb(NULL, 0); |
588 | ctx->bstate = BS_BRANCH; |
589 | } |
590 | break; |
591 | case 0x26: /* and */ |
592 | { |
593 | int a = (opcode >> 4) & 0xf; |
594 | int b = opcode & 0xf; |
595 | |
596 | tcg_gen_and_i32(REG(a), REG(a), REG(b)); |
597 | } |
598 | break; |
599 | case 0x27: /* lshr */ |
600 | { |
601 | int a = (opcode >> 4) & 0xf; |
602 | int b = opcode & 0xf; |
603 | |
604 | TCGv sv = tcg_temp_new_i32(); |
605 | tcg_gen_andi_i32(sv, REG(b), 0x1f); |
606 | tcg_gen_shr_i32(REG(a), REG(a), sv); |
607 | tcg_temp_free_i32(sv); |
608 | } |
609 | break; |
610 | case 0x28: /* ashl */ |
611 | { |
612 | int a = (opcode >> 4) & 0xf; |
613 | int b = opcode & 0xf; |
614 | |
615 | TCGv sv = tcg_temp_new_i32(); |
616 | tcg_gen_andi_i32(sv, REG(b), 0x1f); |
617 | tcg_gen_shl_i32(REG(a), REG(a), sv); |
618 | tcg_temp_free_i32(sv); |
619 | } |
620 | break; |
621 | case 0x29: /* sub.l */ |
622 | { |
623 | int a = (opcode >> 4) & 0xf; |
624 | int b = opcode & 0xf; |
625 | |
626 | tcg_gen_sub_i32(REG(a), REG(a), REG(b)); |
627 | } |
628 | break; |
629 | case 0x2a: /* neg */ |
630 | { |
631 | int a = (opcode >> 4) & 0xf; |
632 | int b = opcode & 0xf; |
633 | |
634 | tcg_gen_neg_i32(REG(a), REG(b)); |
635 | } |
636 | break; |
637 | case 0x2b: /* or */ |
638 | { |
639 | int a = (opcode >> 4) & 0xf; |
640 | int b = opcode & 0xf; |
641 | |
642 | tcg_gen_or_i32(REG(a), REG(a), REG(b)); |
643 | } |
644 | break; |
645 | case 0x2c: /* not */ |
646 | { |
647 | int a = (opcode >> 4) & 0xf; |
648 | int b = opcode & 0xf; |
649 | |
650 | tcg_gen_not_i32(REG(a), REG(b)); |
651 | } |
652 | break; |
653 | case 0x2d: /* ashr */ |
654 | { |
655 | int a = (opcode >> 4) & 0xf; |
656 | int b = opcode & 0xf; |
657 | |
658 | TCGv sv = tcg_temp_new_i32(); |
659 | tcg_gen_andi_i32(sv, REG(b), 0x1f); |
660 | tcg_gen_sar_i32(REG(a), REG(a), sv); |
661 | tcg_temp_free_i32(sv); |
662 | } |
663 | break; |
664 | case 0x2e: /* xor */ |
665 | { |
666 | int a = (opcode >> 4) & 0xf; |
667 | int b = opcode & 0xf; |
668 | |
669 | tcg_gen_xor_i32(REG(a), REG(a), REG(b)); |
670 | } |
671 | break; |
672 | case 0x2f: /* mul.l */ |
673 | { |
674 | int a = (opcode >> 4) & 0xf; |
675 | int b = opcode & 0xf; |
676 | |
677 | tcg_gen_mul_i32(REG(a), REG(a), REG(b)); |
678 | } |
679 | break; |
680 | case 0x30: /* swi */ |
681 | { |
682 | int val = cpu_ldl_code(env, ctx->pc+2); |
683 | |
684 | TCGv temp = tcg_temp_new_i32(); |
685 | tcg_gen_movi_i32(temp, val); |
686 | tcg_gen_st_i32(temp, cpu_env, |
687 | offsetof(CPUMoxieState, sregs[3])); |
688 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
689 | tcg_gen_movi_i32(temp, MOXIE_EX_SWI); |
690 | gen_helper_raise_exception(cpu_env, temp); |
691 | tcg_temp_free_i32(temp); |
692 | |
693 | length = 6; |
694 | } |
695 | break; |
696 | case 0x31: /* div.l */ |
697 | { |
698 | int a = (opcode >> 4) & 0xf; |
699 | int b = opcode & 0xf; |
700 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
701 | gen_helper_div(REG(a), cpu_env, REG(a), REG(b)); |
702 | } |
703 | break; |
704 | case 0x32: /* udiv.l */ |
705 | { |
706 | int a = (opcode >> 4) & 0xf; |
707 | int b = opcode & 0xf; |
708 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
709 | gen_helper_udiv(REG(a), cpu_env, REG(a), REG(b)); |
710 | } |
711 | break; |
712 | case 0x33: /* mod.l */ |
713 | { |
714 | int a = (opcode >> 4) & 0xf; |
715 | int b = opcode & 0xf; |
716 | tcg_gen_rem_i32(REG(a), REG(a), REG(b)); |
717 | } |
718 | break; |
719 | case 0x34: /* umod.l */ |
720 | { |
721 | int a = (opcode >> 4) & 0xf; |
722 | int b = opcode & 0xf; |
723 | tcg_gen_remu_i32(REG(a), REG(a), REG(b)); |
724 | } |
725 | break; |
726 | case 0x35: /* brk */ |
727 | { |
728 | TCGv temp = tcg_temp_new_i32(); |
729 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
730 | tcg_gen_movi_i32(temp, MOXIE_EX_BREAK); |
731 | gen_helper_raise_exception(cpu_env, temp); |
732 | tcg_temp_free_i32(temp); |
733 | } |
734 | break; |
735 | case 0x36: /* ldo.b */ |
736 | { |
737 | int a = (opcode >> 4) & 0xf; |
738 | int b = opcode & 0xf; |
739 | |
740 | TCGv t1 = tcg_temp_new_i32(); |
741 | TCGv t2 = tcg_temp_new_i32(); |
742 | tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); |
743 | tcg_gen_qemu_ld8u(t2, t1, ctx->memidx); |
744 | tcg_gen_mov_i32(REG(a), t2); |
745 | |
746 | tcg_temp_free_i32(t1); |
747 | tcg_temp_free_i32(t2); |
748 | |
749 | length = 6; |
750 | } |
751 | break; |
752 | case 0x37: /* sto.b */ |
753 | { |
754 | int a = (opcode >> 4) & 0xf; |
755 | int b = opcode & 0xf; |
756 | |
757 | TCGv t1 = tcg_temp_new_i32(); |
758 | TCGv t2 = tcg_temp_new_i32(); |
759 | tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); |
760 | tcg_gen_qemu_st8(REG(b), t1, ctx->memidx); |
761 | |
762 | tcg_temp_free_i32(t1); |
763 | tcg_temp_free_i32(t2); |
764 | |
765 | length = 6; |
766 | } |
767 | break; |
768 | case 0x38: /* ldo.s */ |
769 | { |
770 | int a = (opcode >> 4) & 0xf; |
771 | int b = opcode & 0xf; |
772 | |
773 | TCGv t1 = tcg_temp_new_i32(); |
774 | TCGv t2 = tcg_temp_new_i32(); |
775 | tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); |
776 | tcg_gen_qemu_ld16u(t2, t1, ctx->memidx); |
777 | tcg_gen_mov_i32(REG(a), t2); |
778 | |
779 | tcg_temp_free_i32(t1); |
780 | tcg_temp_free_i32(t2); |
781 | |
782 | length = 6; |
783 | } |
784 | break; |
785 | case 0x39: /* sto.s */ |
786 | { |
787 | int a = (opcode >> 4) & 0xf; |
788 | int b = opcode & 0xf; |
789 | |
790 | TCGv t1 = tcg_temp_new_i32(); |
791 | TCGv t2 = tcg_temp_new_i32(); |
792 | tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); |
793 | tcg_gen_qemu_st16(REG(b), t1, ctx->memidx); |
794 | tcg_temp_free_i32(t1); |
795 | tcg_temp_free_i32(t2); |
796 | |
797 | length = 6; |
798 | } |
799 | break; |
800 | default: |
801 | { |
802 | TCGv temp = tcg_temp_new_i32(); |
803 | tcg_gen_movi_i32(cpu_pc, ctx->pc); |
804 | tcg_gen_movi_i32(temp, MOXIE_EX_BAD); |
805 | gen_helper_raise_exception(cpu_env, temp); |
806 | tcg_temp_free_i32(temp); |
807 | } |
808 | break; |
809 | } |
810 | } |
811 | |
812 | return length; |
813 | } |
814 | |
815 | /* generate intermediate code for basic block 'tb'. */ |
816 | void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) |
817 | { |
818 | CPUMoxieState *env = cs->env_ptr; |
819 | MoxieCPU *cpu = env_archcpu(env); |
820 | DisasContext ctx; |
821 | target_ulong pc_start; |
822 | int num_insns; |
823 | |
824 | pc_start = tb->pc; |
825 | ctx.pc = pc_start; |
826 | ctx.saved_pc = -1; |
827 | ctx.tb = tb; |
828 | ctx.memidx = 0; |
829 | ctx.singlestep_enabled = 0; |
830 | ctx.bstate = BS_NONE; |
831 | num_insns = 0; |
832 | |
833 | gen_tb_start(tb); |
834 | do { |
835 | tcg_gen_insn_start(ctx.pc); |
836 | num_insns++; |
837 | |
838 | if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { |
839 | tcg_gen_movi_i32(cpu_pc, ctx.pc); |
840 | gen_helper_debug(cpu_env); |
841 | ctx.bstate = BS_EXCP; |
842 | /* The address covered by the breakpoint must be included in |
843 | [tb->pc, tb->pc + tb->size) in order to for it to be |
844 | properly cleared -- thus we increment the PC here so that |
845 | the logic setting tb->size below does the right thing. */ |
846 | ctx.pc += 2; |
847 | goto done_generating; |
848 | } |
849 | |
850 | ctx.opcode = cpu_lduw_code(env, ctx.pc); |
851 | ctx.pc += decode_opc(cpu, &ctx); |
852 | |
853 | if (num_insns >= max_insns) { |
854 | break; |
855 | } |
856 | if (cs->singlestep_enabled) { |
857 | break; |
858 | } |
859 | if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { |
860 | break; |
861 | } |
862 | } while (ctx.bstate == BS_NONE && !tcg_op_buf_full()); |
863 | |
864 | if (cs->singlestep_enabled) { |
865 | tcg_gen_movi_tl(cpu_pc, ctx.pc); |
866 | gen_helper_debug(cpu_env); |
867 | } else { |
868 | switch (ctx.bstate) { |
869 | case BS_STOP: |
870 | case BS_NONE: |
871 | gen_goto_tb(env, &ctx, 0, ctx.pc); |
872 | break; |
873 | case BS_EXCP: |
874 | tcg_gen_exit_tb(NULL, 0); |
875 | break; |
876 | case BS_BRANCH: |
877 | default: |
878 | break; |
879 | } |
880 | } |
881 | done_generating: |
882 | gen_tb_end(tb, num_insns); |
883 | |
884 | tb->size = ctx.pc - pc_start; |
885 | tb->icount = num_insns; |
886 | } |
887 | |
888 | void restore_state_to_opc(CPUMoxieState *env, TranslationBlock *tb, |
889 | target_ulong *data) |
890 | { |
891 | env->pc = data[0]; |
892 | } |
893 | |