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