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