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