]> Git Repo - qemu.git/blame - target-microblaze/translate.c
target-mips: fix ASID synchronisation for MIPS MT
[qemu.git] / target-microblaze / translate.c
CommitLineData
4acb54ba
EI
1/*
2 * Xilinx MicroBlaze emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2009 Edgar E. Iglesias.
dadc1064 5 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
4acb54ba
EI
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
8167ee88 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
4acb54ba
EI
19 */
20
4acb54ba 21#include "cpu.h"
76cad711 22#include "disas/disas.h"
4acb54ba 23#include "tcg-op.h"
2ef6175a 24#include "exec/helper-proto.h"
4acb54ba 25#include "microblaze-decode.h"
f08b6170 26#include "exec/cpu_ldst.h"
2ef6175a 27#include "exec/helper-gen.h"
4acb54ba 28
a7e30d84
LV
29#include "trace-tcg.h"
30
31
4acb54ba
EI
32#define SIM_COMPAT 0
33#define DISAS_GNU 1
34#define DISAS_MB 1
35#if DISAS_MB && !SIM_COMPAT
36# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
37#else
38# define LOG_DIS(...) do { } while (0)
39#endif
40
41#define D(x)
42
43#define EXTRACT_FIELD(src, start, end) \
44 (((src) >> start) & ((1 << (end - start + 1)) - 1))
45
46static TCGv env_debug;
47static TCGv_ptr cpu_env;
48static TCGv cpu_R[32];
49static TCGv cpu_SR[18];
50static TCGv env_imm;
51static TCGv env_btaken;
52static TCGv env_btarget;
53static TCGv env_iflags;
4a536270 54static TCGv env_res_addr;
11a76217 55static TCGv env_res_val;
4acb54ba 56
022c62cb 57#include "exec/gen-icount.h"
4acb54ba
EI
58
59/* This is the state at translation time. */
60typedef struct DisasContext {
0063ebd6 61 MicroBlazeCPU *cpu;
a5efa644 62 target_ulong pc;
4acb54ba
EI
63
64 /* Decoder. */
65 int type_b;
66 uint32_t ir;
67 uint8_t opcode;
68 uint8_t rd, ra, rb;
69 uint16_t imm;
70
71 unsigned int cpustate_changed;
72 unsigned int delayed_branch;
73 unsigned int tb_flags, synced_flags; /* tb dependent flags. */
74 unsigned int clear_imm;
75 int is_jmp;
76
844bab60
EI
77#define JMP_NOJMP 0
78#define JMP_DIRECT 1
79#define JMP_DIRECT_CC 2
80#define JMP_INDIRECT 3
4acb54ba
EI
81 unsigned int jmp;
82 uint32_t jmp_pc;
83
84 int abort_at_next_insn;
85 int nr_nops;
86 struct TranslationBlock *tb;
87 int singlestep_enabled;
88} DisasContext;
89
38972938 90static const char *regnames[] =
4acb54ba
EI
91{
92 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
93 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
94 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
95 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
96};
97
38972938 98static const char *special_regnames[] =
4acb54ba
EI
99{
100 "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
101 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
102 "sr16", "sr17", "sr18"
103};
104
4acb54ba
EI
105static inline void t_sync_flags(DisasContext *dc)
106{
4abf79a4 107 /* Synch the tb dependent flags between translator and runtime. */
4acb54ba
EI
108 if (dc->tb_flags != dc->synced_flags) {
109 tcg_gen_movi_tl(env_iflags, dc->tb_flags);
110 dc->synced_flags = dc->tb_flags;
111 }
112}
113
114static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
115{
116 TCGv_i32 tmp = tcg_const_i32(index);
117
118 t_sync_flags(dc);
119 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
64254eba 120 gen_helper_raise_exception(cpu_env, tmp);
4acb54ba
EI
121 tcg_temp_free_i32(tmp);
122 dc->is_jmp = DISAS_UPDATE;
123}
124
125static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
126{
127 TranslationBlock *tb;
128 tb = dc->tb;
129 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
130 tcg_gen_goto_tb(n);
131 tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
8cfd0495 132 tcg_gen_exit_tb((uintptr_t)tb + n);
4acb54ba
EI
133 } else {
134 tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
135 tcg_gen_exit_tb(0);
136 }
137}
138
ee8b246f
EI
139static void read_carry(DisasContext *dc, TCGv d)
140{
141 tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
142}
143
04ec7df7
EI
144/*
145 * write_carry sets the carry bits in MSR based on bit 0 of v.
146 * v[31:1] are ignored.
147 */
ee8b246f
EI
148static void write_carry(DisasContext *dc, TCGv v)
149{
150 TCGv t0 = tcg_temp_new();
151 tcg_gen_shli_tl(t0, v, 31);
152 tcg_gen_sari_tl(t0, t0, 31);
153 tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC));
154 tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR],
155 ~(MSR_C | MSR_CC));
156 tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0);
157 tcg_temp_free(t0);
158}
159
65ab5eb4 160static void write_carryi(DisasContext *dc, bool carry)
8cc9b43f
PC
161{
162 TCGv t0 = tcg_temp_new();
65ab5eb4 163 tcg_gen_movi_tl(t0, carry);
8cc9b43f
PC
164 write_carry(dc, t0);
165 tcg_temp_free(t0);
166}
167
61204ce8
EI
168/* True if ALU operand b is a small immediate that may deserve
169 faster treatment. */
170static inline int dec_alu_op_b_is_small_imm(DisasContext *dc)
171{
172 /* Immediate insn without the imm prefix ? */
173 return dc->type_b && !(dc->tb_flags & IMM_FLAG);
174}
175
4acb54ba
EI
176static inline TCGv *dec_alu_op_b(DisasContext *dc)
177{
178 if (dc->type_b) {
179 if (dc->tb_flags & IMM_FLAG)
180 tcg_gen_ori_tl(env_imm, env_imm, dc->imm);
181 else
182 tcg_gen_movi_tl(env_imm, (int32_t)((int16_t)dc->imm));
183 return &env_imm;
184 } else
185 return &cpu_R[dc->rb];
186}
187
188static void dec_add(DisasContext *dc)
189{
190 unsigned int k, c;
40cbf5b7 191 TCGv cf;
4acb54ba
EI
192
193 k = dc->opcode & 4;
194 c = dc->opcode & 2;
195
196 LOG_DIS("add%s%s%s r%d r%d r%d\n",
197 dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "",
198 dc->rd, dc->ra, dc->rb);
199
40cbf5b7
EI
200 /* Take care of the easy cases first. */
201 if (k) {
202 /* k - keep carry, no need to update MSR. */
203 /* If rd == r0, it's a nop. */
204 if (dc->rd) {
205 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
206
207 if (c) {
208 /* c - Add carry into the result. */
209 cf = tcg_temp_new();
210
211 read_carry(dc, cf);
212 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
213 tcg_temp_free(cf);
214 }
215 }
216 return;
217 }
218
219 /* From now on, we can assume k is zero. So we need to update MSR. */
220 /* Extract carry. */
221 cf = tcg_temp_new();
222 if (c) {
223 read_carry(dc, cf);
224 } else {
225 tcg_gen_movi_tl(cf, 0);
226 }
227
228 if (dc->rd) {
229 TCGv ncf = tcg_temp_new();
5d0bb823 230 gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
4acb54ba 231 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
40cbf5b7
EI
232 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
233 write_carry(dc, ncf);
234 tcg_temp_free(ncf);
235 } else {
5d0bb823 236 gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
40cbf5b7 237 write_carry(dc, cf);
4acb54ba 238 }
40cbf5b7 239 tcg_temp_free(cf);
4acb54ba
EI
240}
241
242static void dec_sub(DisasContext *dc)
243{
244 unsigned int u, cmp, k, c;
e0a42ebc 245 TCGv cf, na;
4acb54ba
EI
246
247 u = dc->imm & 2;
248 k = dc->opcode & 4;
249 c = dc->opcode & 2;
250 cmp = (dc->imm & 1) && (!dc->type_b) && k;
251
252 if (cmp) {
253 LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir);
254 if (dc->rd) {
255 if (u)
256 gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
257 else
258 gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
259 }
e0a42ebc
EI
260 return;
261 }
262
263 LOG_DIS("sub%s%s r%d, r%d r%d\n",
264 k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
265
266 /* Take care of the easy cases first. */
267 if (k) {
268 /* k - keep carry, no need to update MSR. */
269 /* If rd == r0, it's a nop. */
270 if (dc->rd) {
4acb54ba 271 tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
e0a42ebc
EI
272
273 if (c) {
274 /* c - Add carry into the result. */
275 cf = tcg_temp_new();
276
277 read_carry(dc, cf);
278 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
279 tcg_temp_free(cf);
280 }
281 }
282 return;
283 }
284
285 /* From now on, we can assume k is zero. So we need to update MSR. */
286 /* Extract carry. And complement a into na. */
287 cf = tcg_temp_new();
288 na = tcg_temp_new();
289 if (c) {
290 read_carry(dc, cf);
291 } else {
292 tcg_gen_movi_tl(cf, 1);
293 }
294
295 /* d = b + ~a + c. carry defaults to 1. */
296 tcg_gen_not_tl(na, cpu_R[dc->ra]);
297
298 if (dc->rd) {
299 TCGv ncf = tcg_temp_new();
5d0bb823 300 gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
e0a42ebc
EI
301 tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
302 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
303 write_carry(dc, ncf);
304 tcg_temp_free(ncf);
305 } else {
5d0bb823 306 gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
e0a42ebc 307 write_carry(dc, cf);
4acb54ba 308 }
e0a42ebc
EI
309 tcg_temp_free(cf);
310 tcg_temp_free(na);
4acb54ba
EI
311}
312
313static void dec_pattern(DisasContext *dc)
314{
315 unsigned int mode;
42a268c2 316 TCGLabel *l1;
4acb54ba 317
1567a005 318 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6
AF
319 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
320 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
1567a005
EI
321 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
322 t_gen_raise_exception(dc, EXCP_HW_EXCP);
323 }
324
4acb54ba
EI
325 mode = dc->opcode & 3;
326 switch (mode) {
327 case 0:
328 /* pcmpbf. */
329 LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
330 if (dc->rd)
331 gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
332 break;
333 case 2:
334 LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
335 if (dc->rd) {
336 TCGv t0 = tcg_temp_local_new();
337 l1 = gen_new_label();
338 tcg_gen_movi_tl(t0, 1);
339 tcg_gen_brcond_tl(TCG_COND_EQ,
340 cpu_R[dc->ra], cpu_R[dc->rb], l1);
341 tcg_gen_movi_tl(t0, 0);
342 gen_set_label(l1);
343 tcg_gen_mov_tl(cpu_R[dc->rd], t0);
344 tcg_temp_free(t0);
345 }
346 break;
347 case 3:
348 LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
349 l1 = gen_new_label();
350 if (dc->rd) {
351 TCGv t0 = tcg_temp_local_new();
352 tcg_gen_movi_tl(t0, 1);
353 tcg_gen_brcond_tl(TCG_COND_NE,
354 cpu_R[dc->ra], cpu_R[dc->rb], l1);
355 tcg_gen_movi_tl(t0, 0);
356 gen_set_label(l1);
357 tcg_gen_mov_tl(cpu_R[dc->rd], t0);
358 tcg_temp_free(t0);
359 }
360 break;
361 default:
0063ebd6 362 cpu_abort(CPU(dc->cpu),
4acb54ba
EI
363 "unsupported pattern insn opcode=%x\n", dc->opcode);
364 break;
365 }
366}
367
368static void dec_and(DisasContext *dc)
369{
370 unsigned int not;
371
372 if (!dc->type_b && (dc->imm & (1 << 10))) {
373 dec_pattern(dc);
374 return;
375 }
376
377 not = dc->opcode & (1 << 1);
378 LOG_DIS("and%s\n", not ? "n" : "");
379
380 if (!dc->rd)
381 return;
382
383 if (not) {
a235900e 384 tcg_gen_andc_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
4acb54ba
EI
385 } else
386 tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
387}
388
389static void dec_or(DisasContext *dc)
390{
391 if (!dc->type_b && (dc->imm & (1 << 10))) {
392 dec_pattern(dc);
393 return;
394 }
395
396 LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm);
397 if (dc->rd)
398 tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
399}
400
401static void dec_xor(DisasContext *dc)
402{
403 if (!dc->type_b && (dc->imm & (1 << 10))) {
404 dec_pattern(dc);
405 return;
406 }
407
408 LOG_DIS("xor r%d\n", dc->rd);
409 if (dc->rd)
410 tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
411}
412
4acb54ba
EI
413static inline void msr_read(DisasContext *dc, TCGv d)
414{
415 tcg_gen_mov_tl(d, cpu_SR[SR_MSR]);
416}
417
418static inline void msr_write(DisasContext *dc, TCGv v)
419{
97b833c5
EI
420 TCGv t;
421
422 t = tcg_temp_new();
4acb54ba 423 dc->cpustate_changed = 1;
97b833c5 424 /* PVR bit is not writable. */
8a84fc6b
EI
425 tcg_gen_andi_tl(t, v, ~MSR_PVR);
426 tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
97b833c5
EI
427 tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], v);
428 tcg_temp_free(t);
4acb54ba
EI
429}
430
431static void dec_msr(DisasContext *dc)
432{
0063ebd6 433 CPUState *cs = CPU(dc->cpu);
4acb54ba
EI
434 TCGv t0, t1;
435 unsigned int sr, to, rn;
0063ebd6 436 int mem_index = cpu_mmu_index(&dc->cpu->env);
4acb54ba
EI
437
438 sr = dc->imm & ((1 << 14) - 1);
439 to = dc->imm & (1 << 14);
440 dc->type_b = 1;
441 if (to)
442 dc->cpustate_changed = 1;
443
444 /* msrclr and msrset. */
445 if (!(dc->imm & (1 << 15))) {
446 unsigned int clr = dc->ir & (1 << 16);
447
448 LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set",
449 dc->rd, dc->imm);
1567a005 450
0063ebd6 451 if (!(dc->cpu->env.pvr.regs[2] & PVR2_USE_MSR_INSTR)) {
1567a005
EI
452 /* nop??? */
453 return;
454 }
455
456 if ((dc->tb_flags & MSR_EE_FLAG)
457 && mem_index == MMU_USER_IDX && (dc->imm != 4 && dc->imm != 0)) {
458 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
459 t_gen_raise_exception(dc, EXCP_HW_EXCP);
460 return;
461 }
462
4acb54ba
EI
463 if (dc->rd)
464 msr_read(dc, cpu_R[dc->rd]);
465
466 t0 = tcg_temp_new();
467 t1 = tcg_temp_new();
468 msr_read(dc, t0);
469 tcg_gen_mov_tl(t1, *(dec_alu_op_b(dc)));
470
471 if (clr) {
472 tcg_gen_not_tl(t1, t1);
473 tcg_gen_and_tl(t0, t0, t1);
474 } else
475 tcg_gen_or_tl(t0, t0, t1);
476 msr_write(dc, t0);
477 tcg_temp_free(t0);
478 tcg_temp_free(t1);
479 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
480 dc->is_jmp = DISAS_UPDATE;
481 return;
482 }
483
1567a005
EI
484 if (to) {
485 if ((dc->tb_flags & MSR_EE_FLAG)
486 && mem_index == MMU_USER_IDX) {
487 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
488 t_gen_raise_exception(dc, EXCP_HW_EXCP);
489 return;
490 }
491 }
492
4acb54ba
EI
493#if !defined(CONFIG_USER_ONLY)
494 /* Catch read/writes to the mmu block. */
495 if ((sr & ~0xff) == 0x1000) {
496 sr &= 7;
497 LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
498 if (to)
64254eba 499 gen_helper_mmu_write(cpu_env, tcg_const_tl(sr), cpu_R[dc->ra]);
4acb54ba 500 else
64254eba 501 gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tcg_const_tl(sr));
4acb54ba
EI
502 return;
503 }
504#endif
505
506 if (to) {
507 LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm);
508 switch (sr) {
509 case 0:
510 break;
511 case 1:
512 msr_write(dc, cpu_R[dc->ra]);
513 break;
514 case 0x3:
515 tcg_gen_mov_tl(cpu_SR[SR_EAR], cpu_R[dc->ra]);
516 break;
517 case 0x5:
518 tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]);
519 break;
520 case 0x7:
97694c57 521 tcg_gen_andi_tl(cpu_SR[SR_FSR], cpu_R[dc->ra], 31);
4acb54ba 522 break;
5818dee5 523 case 0x800:
68cee38a 524 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, slr));
5818dee5
EI
525 break;
526 case 0x802:
68cee38a 527 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, shr));
5818dee5 528 break;
4acb54ba 529 default:
0063ebd6 530 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
4acb54ba
EI
531 break;
532 }
533 } else {
534 LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm);
535
536 switch (sr) {
537 case 0:
538 tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
539 break;
540 case 1:
541 msr_read(dc, cpu_R[dc->rd]);
542 break;
543 case 0x3:
544 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_EAR]);
545 break;
546 case 0x5:
547 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]);
548 break;
549 case 0x7:
97694c57 550 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_FSR]);
4acb54ba
EI
551 break;
552 case 0xb:
553 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
554 break;
5818dee5 555 case 0x800:
68cee38a 556 tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, slr));
5818dee5
EI
557 break;
558 case 0x802:
68cee38a 559 tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, shr));
5818dee5 560 break;
4acb54ba
EI
561 case 0x2000:
562 case 0x2001:
563 case 0x2002:
564 case 0x2003:
565 case 0x2004:
566 case 0x2005:
567 case 0x2006:
568 case 0x2007:
569 case 0x2008:
570 case 0x2009:
571 case 0x200a:
572 case 0x200b:
573 case 0x200c:
574 rn = sr & 0xf;
575 tcg_gen_ld_tl(cpu_R[dc->rd],
68cee38a 576 cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
4acb54ba
EI
577 break;
578 default:
a47dddd7 579 cpu_abort(cs, "unknown mfs reg %x\n", sr);
4acb54ba
EI
580 break;
581 }
582 }
ee7dbcf8
EI
583
584 if (dc->rd == 0) {
585 tcg_gen_movi_tl(cpu_R[0], 0);
586 }
4acb54ba
EI
587}
588
589/* 64-bit signed mul, lower result in d and upper in d2. */
590static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b)
591{
592 TCGv_i64 t0, t1;
593
594 t0 = tcg_temp_new_i64();
595 t1 = tcg_temp_new_i64();
596
597 tcg_gen_ext_i32_i64(t0, a);
598 tcg_gen_ext_i32_i64(t1, b);
599 tcg_gen_mul_i64(t0, t0, t1);
600
601 tcg_gen_trunc_i64_i32(d, t0);
602 tcg_gen_shri_i64(t0, t0, 32);
603 tcg_gen_trunc_i64_i32(d2, t0);
604
605 tcg_temp_free_i64(t0);
606 tcg_temp_free_i64(t1);
607}
608
609/* 64-bit unsigned muls, lower result in d and upper in d2. */
610static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b)
611{
612 TCGv_i64 t0, t1;
613
614 t0 = tcg_temp_new_i64();
615 t1 = tcg_temp_new_i64();
616
617 tcg_gen_extu_i32_i64(t0, a);
618 tcg_gen_extu_i32_i64(t1, b);
619 tcg_gen_mul_i64(t0, t0, t1);
620
621 tcg_gen_trunc_i64_i32(d, t0);
622 tcg_gen_shri_i64(t0, t0, 32);
623 tcg_gen_trunc_i64_i32(d2, t0);
624
625 tcg_temp_free_i64(t0);
626 tcg_temp_free_i64(t1);
627}
628
629/* Multiplier unit. */
630static void dec_mul(DisasContext *dc)
631{
632 TCGv d[2];
633 unsigned int subcode;
634
1567a005 635 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6
AF
636 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
637 && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
1567a005
EI
638 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
639 t_gen_raise_exception(dc, EXCP_HW_EXCP);
640 return;
641 }
642
4acb54ba
EI
643 subcode = dc->imm & 3;
644 d[0] = tcg_temp_new();
645 d[1] = tcg_temp_new();
646
647 if (dc->type_b) {
648 LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm);
649 t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
650 goto done;
651 }
652
1567a005
EI
653 /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */
654 if (subcode >= 1 && subcode <= 3
0063ebd6 655 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_MUL64_MASK))) {
1567a005
EI
656 /* nop??? */
657 }
658
4acb54ba
EI
659 switch (subcode) {
660 case 0:
661 LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
662 t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], cpu_R[dc->rb]);
663 break;
664 case 1:
665 LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
666 t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
667 break;
668 case 2:
669 LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
670 t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
671 break;
672 case 3:
673 LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb);
674 t_gen_mulu(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
675 break;
676 default:
0063ebd6 677 cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
4acb54ba
EI
678 break;
679 }
680done:
681 tcg_temp_free(d[0]);
682 tcg_temp_free(d[1]);
683}
684
685/* Div unit. */
686static void dec_div(DisasContext *dc)
687{
688 unsigned int u;
689
690 u = dc->imm & 2;
691 LOG_DIS("div\n");
692
0063ebd6
AF
693 if ((dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
694 && !((dc->cpu->env.pvr.regs[0] & PVR0_USE_DIV_MASK))) {
1567a005
EI
695 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
696 t_gen_raise_exception(dc, EXCP_HW_EXCP);
697 }
698
4acb54ba 699 if (u)
64254eba
BS
700 gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
701 cpu_R[dc->ra]);
4acb54ba 702 else
64254eba
BS
703 gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
704 cpu_R[dc->ra]);
4acb54ba
EI
705 if (!dc->rd)
706 tcg_gen_movi_tl(cpu_R[dc->rd], 0);
707}
708
709static void dec_barrel(DisasContext *dc)
710{
711 TCGv t0;
712 unsigned int s, t;
713
1567a005 714 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6
AF
715 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
716 && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
1567a005
EI
717 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
718 t_gen_raise_exception(dc, EXCP_HW_EXCP);
719 return;
720 }
721
4acb54ba
EI
722 s = dc->imm & (1 << 10);
723 t = dc->imm & (1 << 9);
724
725 LOG_DIS("bs%s%s r%d r%d r%d\n",
726 s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb);
727
728 t0 = tcg_temp_new();
729
730 tcg_gen_mov_tl(t0, *(dec_alu_op_b(dc)));
731 tcg_gen_andi_tl(t0, t0, 31);
732
733 if (s)
734 tcg_gen_shl_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
735 else {
736 if (t)
737 tcg_gen_sar_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
738 else
739 tcg_gen_shr_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0);
740 }
741}
742
743static void dec_bit(DisasContext *dc)
744{
0063ebd6 745 CPUState *cs = CPU(dc->cpu);
09b9f113 746 TCGv t0;
4acb54ba 747 unsigned int op;
0063ebd6 748 int mem_index = cpu_mmu_index(&dc->cpu->env);
4acb54ba 749
ace2e4da 750 op = dc->ir & ((1 << 9) - 1);
4acb54ba
EI
751 switch (op) {
752 case 0x21:
753 /* src. */
754 t0 = tcg_temp_new();
755
756 LOG_DIS("src r%d r%d\n", dc->rd, dc->ra);
09b9f113
EI
757 tcg_gen_andi_tl(t0, cpu_SR[SR_MSR], MSR_CC);
758 write_carry(dc, cpu_R[dc->ra]);
4acb54ba 759 if (dc->rd) {
4acb54ba 760 tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
09b9f113 761 tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t0);
4acb54ba 762 }
4acb54ba
EI
763 tcg_temp_free(t0);
764 break;
765
766 case 0x1:
767 case 0x41:
768 /* srl. */
4acb54ba
EI
769 LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
770
bb3cb951
EI
771 /* Update carry. Note that write carry only looks at the LSB. */
772 write_carry(dc, cpu_R[dc->ra]);
4acb54ba
EI
773 if (dc->rd) {
774 if (op == 0x41)
775 tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
776 else
777 tcg_gen_sari_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
778 }
779 break;
780 case 0x60:
781 LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra);
782 tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
783 break;
784 case 0x61:
785 LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra);
786 tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
787 break;
788 case 0x64:
f062a3c7
EI
789 case 0x66:
790 case 0x74:
791 case 0x76:
4acb54ba
EI
792 /* wdc. */
793 LOG_DIS("wdc r%d\n", dc->ra);
1567a005
EI
794 if ((dc->tb_flags & MSR_EE_FLAG)
795 && mem_index == MMU_USER_IDX) {
796 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
797 t_gen_raise_exception(dc, EXCP_HW_EXCP);
798 return;
799 }
4acb54ba
EI
800 break;
801 case 0x68:
802 /* wic. */
803 LOG_DIS("wic r%d\n", dc->ra);
1567a005
EI
804 if ((dc->tb_flags & MSR_EE_FLAG)
805 && mem_index == MMU_USER_IDX) {
806 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
807 t_gen_raise_exception(dc, EXCP_HW_EXCP);
808 return;
809 }
4acb54ba 810 break;
48b5e96f
EI
811 case 0xe0:
812 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6
AF
813 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
814 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
48b5e96f
EI
815 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
816 t_gen_raise_exception(dc, EXCP_HW_EXCP);
817 }
0063ebd6 818 if (dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR) {
48b5e96f
EI
819 gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]);
820 }
821 break;
ace2e4da
PC
822 case 0x1e0:
823 /* swapb */
824 LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra);
825 tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]);
826 break;
b8c6a5d9 827 case 0x1e2:
ace2e4da
PC
828 /*swaph */
829 LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra);
830 tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16);
831 break;
4acb54ba 832 default:
a47dddd7
AF
833 cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n",
834 dc->pc, op, dc->rd, dc->ra, dc->rb);
4acb54ba
EI
835 break;
836 }
837}
838
839static inline void sync_jmpstate(DisasContext *dc)
840{
844bab60
EI
841 if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
842 if (dc->jmp == JMP_DIRECT) {
843 tcg_gen_movi_tl(env_btaken, 1);
844 }
23979dc5
EI
845 dc->jmp = JMP_INDIRECT;
846 tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
4acb54ba
EI
847 }
848}
849
850static void dec_imm(DisasContext *dc)
851{
852 LOG_DIS("imm %x\n", dc->imm << 16);
853 tcg_gen_movi_tl(env_imm, (dc->imm << 16));
854 dc->tb_flags |= IMM_FLAG;
855 dc->clear_imm = 0;
856}
857
4acb54ba
EI
858static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
859{
860 unsigned int extimm = dc->tb_flags & IMM_FLAG;
5818dee5
EI
861 /* Should be set to one if r1 is used by loadstores. */
862 int stackprot = 0;
863
864 /* All load/stores use ra. */
9aaaa181 865 if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
5818dee5
EI
866 stackprot = 1;
867 }
4acb54ba 868
9ef55357 869 /* Treat the common cases first. */
4acb54ba 870 if (!dc->type_b) {
4b5ef0b5
EI
871 /* If any of the regs is r0, return a ptr to the other. */
872 if (dc->ra == 0) {
873 return &cpu_R[dc->rb];
874 } else if (dc->rb == 0) {
875 return &cpu_R[dc->ra];
876 }
877
9aaaa181 878 if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
5818dee5
EI
879 stackprot = 1;
880 }
881
4acb54ba
EI
882 *t = tcg_temp_new();
883 tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
5818dee5
EI
884
885 if (stackprot) {
64254eba 886 gen_helper_stackprot(cpu_env, *t);
5818dee5 887 }
4acb54ba
EI
888 return t;
889 }
890 /* Immediate. */
891 if (!extimm) {
892 if (dc->imm == 0) {
893 return &cpu_R[dc->ra];
894 }
895 *t = tcg_temp_new();
896 tcg_gen_movi_tl(*t, (int32_t)((int16_t)dc->imm));
897 tcg_gen_add_tl(*t, cpu_R[dc->ra], *t);
898 } else {
899 *t = tcg_temp_new();
900 tcg_gen_add_tl(*t, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
901 }
902
5818dee5 903 if (stackprot) {
64254eba 904 gen_helper_stackprot(cpu_env, *t);
5818dee5 905 }
4acb54ba
EI
906 return t;
907}
908
909static void dec_load(DisasContext *dc)
910{
47acdd63 911 TCGv t, v, *addr;
8cc9b43f 912 unsigned int size, rev = 0, ex = 0;
47acdd63 913 TCGMemOp mop;
4acb54ba 914
47acdd63
RH
915 mop = dc->opcode & 3;
916 size = 1 << mop;
9f8beb66
EI
917 if (!dc->type_b) {
918 rev = (dc->ir >> 9) & 1;
8cc9b43f 919 ex = (dc->ir >> 10) & 1;
9f8beb66 920 }
47acdd63
RH
921 mop |= MO_TE;
922 if (rev) {
923 mop ^= MO_BSWAP;
924 }
9f8beb66 925
0187688f 926 if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
0063ebd6 927 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
0187688f
EI
928 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
929 t_gen_raise_exception(dc, EXCP_HW_EXCP);
930 return;
931 }
4acb54ba 932
8cc9b43f
PC
933 LOG_DIS("l%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
934 ex ? "x" : "");
9f8beb66 935
4acb54ba
EI
936 t_sync_flags(dc);
937 addr = compute_ldst_addr(dc, &t);
938
9f8beb66
EI
939 /*
940 * When doing reverse accesses we need to do two things.
941 *
4ff9786c 942 * 1. Reverse the address wrt endianness.
9f8beb66
EI
943 * 2. Byteswap the data lanes on the way back into the CPU core.
944 */
945 if (rev && size != 4) {
946 /* Endian reverse the address. t is addr. */
947 switch (size) {
948 case 1:
949 {
950 /* 00 -> 11
951 01 -> 10
952 10 -> 10
953 11 -> 00 */
954 TCGv low = tcg_temp_new();
955
956 /* Force addr into the temp. */
957 if (addr != &t) {
958 t = tcg_temp_new();
959 tcg_gen_mov_tl(t, *addr);
960 addr = &t;
961 }
962
963 tcg_gen_andi_tl(low, t, 3);
964 tcg_gen_sub_tl(low, tcg_const_tl(3), low);
965 tcg_gen_andi_tl(t, t, ~3);
966 tcg_gen_or_tl(t, t, low);
9f8beb66
EI
967 tcg_gen_mov_tl(env_imm, t);
968 tcg_temp_free(low);
969 break;
970 }
971
972 case 2:
973 /* 00 -> 10
974 10 -> 00. */
975 /* Force addr into the temp. */
976 if (addr != &t) {
977 t = tcg_temp_new();
978 tcg_gen_xori_tl(t, *addr, 2);
979 addr = &t;
980 } else {
981 tcg_gen_xori_tl(t, t, 2);
982 }
983 break;
984 default:
0063ebd6 985 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
9f8beb66
EI
986 break;
987 }
988 }
989
8cc9b43f
PC
990 /* lwx does not throw unaligned access errors, so force alignment */
991 if (ex) {
992 /* Force addr into the temp. */
993 if (addr != &t) {
994 t = tcg_temp_new();
995 tcg_gen_mov_tl(t, *addr);
996 addr = &t;
997 }
998 tcg_gen_andi_tl(t, t, ~3);
999 }
1000
4acb54ba
EI
1001 /* If we get a fault on a dslot, the jmpstate better be in sync. */
1002 sync_jmpstate(dc);
968a40f6
EI
1003
1004 /* Verify alignment if needed. */
47acdd63
RH
1005 /*
1006 * Microblaze gives MMU faults priority over faults due to
1007 * unaligned addresses. That's why we speculatively do the load
1008 * into v. If the load succeeds, we verify alignment of the
1009 * address and if that succeeds we write into the destination reg.
1010 */
1011 v = tcg_temp_new();
0063ebd6 1012 tcg_gen_qemu_ld_tl(v, *addr, cpu_mmu_index(&dc->cpu->env), mop);
a12f6507 1013
0063ebd6 1014 if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
a12f6507 1015 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
64254eba 1016 gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
3aa80988 1017 tcg_const_tl(0), tcg_const_tl(size - 1));
4acb54ba
EI
1018 }
1019
47acdd63
RH
1020 if (ex) {
1021 tcg_gen_mov_tl(env_res_addr, *addr);
1022 tcg_gen_mov_tl(env_res_val, v);
1023 }
1024 if (dc->rd) {
1025 tcg_gen_mov_tl(cpu_R[dc->rd], v);
1026 }
1027 tcg_temp_free(v);
1028
8cc9b43f
PC
1029 if (ex) { /* lwx */
1030 /* no support for for AXI exclusive so always clear C */
1031 write_carryi(dc, 0);
8cc9b43f
PC
1032 }
1033
4acb54ba
EI
1034 if (addr == &t)
1035 tcg_temp_free(t);
1036}
1037
4acb54ba
EI
1038static void dec_store(DisasContext *dc)
1039{
4a536270 1040 TCGv t, *addr, swx_addr;
42a268c2 1041 TCGLabel *swx_skip = NULL;
8cc9b43f 1042 unsigned int size, rev = 0, ex = 0;
47acdd63 1043 TCGMemOp mop;
4acb54ba 1044
47acdd63
RH
1045 mop = dc->opcode & 3;
1046 size = 1 << mop;
9f8beb66
EI
1047 if (!dc->type_b) {
1048 rev = (dc->ir >> 9) & 1;
8cc9b43f 1049 ex = (dc->ir >> 10) & 1;
9f8beb66 1050 }
47acdd63
RH
1051 mop |= MO_TE;
1052 if (rev) {
1053 mop ^= MO_BSWAP;
1054 }
4acb54ba 1055
0187688f 1056 if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
0063ebd6 1057 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
0187688f
EI
1058 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1059 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1060 return;
1061 }
1062
8cc9b43f
PC
1063 LOG_DIS("s%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
1064 ex ? "x" : "");
4acb54ba
EI
1065 t_sync_flags(dc);
1066 /* If we get a fault on a dslot, the jmpstate better be in sync. */
1067 sync_jmpstate(dc);
1068 addr = compute_ldst_addr(dc, &t);
968a40f6 1069
083dbf48 1070 swx_addr = tcg_temp_local_new();
8cc9b43f 1071 if (ex) { /* swx */
11a76217 1072 TCGv tval;
8cc9b43f
PC
1073
1074 /* Force addr into the swx_addr. */
1075 tcg_gen_mov_tl(swx_addr, *addr);
1076 addr = &swx_addr;
1077 /* swx does not throw unaligned access errors, so force alignment */
1078 tcg_gen_andi_tl(swx_addr, swx_addr, ~3);
1079
8cc9b43f
PC
1080 write_carryi(dc, 1);
1081 swx_skip = gen_new_label();
4a536270 1082 tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, swx_addr, swx_skip);
11a76217
EI
1083
1084 /* Compare the value loaded at lwx with current contents of
1085 the reserved location.
1086 FIXME: This only works for system emulation where we can expect
1087 this compare and the following write to be atomic. For user
1088 emulation we need to add atomicity between threads. */
1089 tval = tcg_temp_new();
0063ebd6
AF
1090 tcg_gen_qemu_ld_tl(tval, swx_addr, cpu_mmu_index(&dc->cpu->env),
1091 MO_TEUL);
11a76217 1092 tcg_gen_brcond_tl(TCG_COND_NE, env_res_val, tval, swx_skip);
8cc9b43f 1093 write_carryi(dc, 0);
11a76217 1094 tcg_temp_free(tval);
8cc9b43f
PC
1095 }
1096
9f8beb66
EI
1097 if (rev && size != 4) {
1098 /* Endian reverse the address. t is addr. */
1099 switch (size) {
1100 case 1:
1101 {
1102 /* 00 -> 11
1103 01 -> 10
1104 10 -> 10
1105 11 -> 00 */
1106 TCGv low = tcg_temp_new();
1107
1108 /* Force addr into the temp. */
1109 if (addr != &t) {
1110 t = tcg_temp_new();
1111 tcg_gen_mov_tl(t, *addr);
1112 addr = &t;
1113 }
1114
1115 tcg_gen_andi_tl(low, t, 3);
1116 tcg_gen_sub_tl(low, tcg_const_tl(3), low);
1117 tcg_gen_andi_tl(t, t, ~3);
1118 tcg_gen_or_tl(t, t, low);
9f8beb66
EI
1119 tcg_gen_mov_tl(env_imm, t);
1120 tcg_temp_free(low);
1121 break;
1122 }
1123
1124 case 2:
1125 /* 00 -> 10
1126 10 -> 00. */
1127 /* Force addr into the temp. */
1128 if (addr != &t) {
1129 t = tcg_temp_new();
1130 tcg_gen_xori_tl(t, *addr, 2);
1131 addr = &t;
1132 } else {
1133 tcg_gen_xori_tl(t, t, 2);
1134 }
1135 break;
1136 default:
0063ebd6 1137 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
9f8beb66
EI
1138 break;
1139 }
9f8beb66 1140 }
0063ebd6 1141 tcg_gen_qemu_st_tl(cpu_R[dc->rd], *addr, cpu_mmu_index(&dc->cpu->env), mop);
a12f6507 1142
968a40f6 1143 /* Verify alignment if needed. */
0063ebd6 1144 if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
a12f6507
EI
1145 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
1146 /* FIXME: if the alignment is wrong, we should restore the value
4abf79a4 1147 * in memory. One possible way to achieve this is to probe
9f8beb66
EI
1148 * the MMU prior to the memaccess, thay way we could put
1149 * the alignment checks in between the probe and the mem
1150 * access.
a12f6507 1151 */
64254eba 1152 gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
3aa80988 1153 tcg_const_tl(1), tcg_const_tl(size - 1));
968a40f6 1154 }
083dbf48 1155
8cc9b43f
PC
1156 if (ex) {
1157 gen_set_label(swx_skip);
8cc9b43f 1158 }
083dbf48 1159 tcg_temp_free(swx_addr);
968a40f6 1160
4acb54ba
EI
1161 if (addr == &t)
1162 tcg_temp_free(t);
1163}
1164
1165static inline void eval_cc(DisasContext *dc, unsigned int cc,
1166 TCGv d, TCGv a, TCGv b)
1167{
4acb54ba
EI
1168 switch (cc) {
1169 case CC_EQ:
b2565c69 1170 tcg_gen_setcond_tl(TCG_COND_EQ, d, a, b);
4acb54ba
EI
1171 break;
1172 case CC_NE:
b2565c69 1173 tcg_gen_setcond_tl(TCG_COND_NE, d, a, b);
4acb54ba
EI
1174 break;
1175 case CC_LT:
b2565c69 1176 tcg_gen_setcond_tl(TCG_COND_LT, d, a, b);
4acb54ba
EI
1177 break;
1178 case CC_LE:
b2565c69 1179 tcg_gen_setcond_tl(TCG_COND_LE, d, a, b);
4acb54ba
EI
1180 break;
1181 case CC_GE:
b2565c69 1182 tcg_gen_setcond_tl(TCG_COND_GE, d, a, b);
4acb54ba
EI
1183 break;
1184 case CC_GT:
b2565c69 1185 tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
4acb54ba
EI
1186 break;
1187 default:
0063ebd6 1188 cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
4acb54ba
EI
1189 break;
1190 }
1191}
1192
1193static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false)
1194{
42a268c2 1195 TCGLabel *l1 = gen_new_label();
4acb54ba
EI
1196 /* Conditional jmp. */
1197 tcg_gen_mov_tl(cpu_SR[SR_PC], pc_false);
1198 tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
1199 tcg_gen_mov_tl(cpu_SR[SR_PC], pc_true);
1200 gen_set_label(l1);
1201}
1202
1203static void dec_bcc(DisasContext *dc)
1204{
1205 unsigned int cc;
1206 unsigned int dslot;
1207
1208 cc = EXTRACT_FIELD(dc->ir, 21, 23);
1209 dslot = dc->ir & (1 << 25);
1210 LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm);
1211
1212 dc->delayed_branch = 1;
1213 if (dslot) {
1214 dc->delayed_branch = 2;
1215 dc->tb_flags |= D_FLAG;
1216 tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
68cee38a 1217 cpu_env, offsetof(CPUMBState, bimm));
4acb54ba
EI
1218 }
1219
61204ce8
EI
1220 if (dec_alu_op_b_is_small_imm(dc)) {
1221 int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */
1222
1223 tcg_gen_movi_tl(env_btarget, dc->pc + offset);
844bab60 1224 dc->jmp = JMP_DIRECT_CC;
23979dc5 1225 dc->jmp_pc = dc->pc + offset;
61204ce8 1226 } else {
23979dc5 1227 dc->jmp = JMP_INDIRECT;
61204ce8
EI
1228 tcg_gen_movi_tl(env_btarget, dc->pc);
1229 tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
1230 }
61204ce8 1231 eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
4acb54ba
EI
1232}
1233
1234static void dec_br(DisasContext *dc)
1235{
9f6113c7 1236 unsigned int dslot, link, abs, mbar;
0063ebd6 1237 int mem_index = cpu_mmu_index(&dc->cpu->env);
4acb54ba
EI
1238
1239 dslot = dc->ir & (1 << 20);
1240 abs = dc->ir & (1 << 19);
1241 link = dc->ir & (1 << 18);
9f6113c7
EI
1242
1243 /* Memory barrier. */
1244 mbar = (dc->ir >> 16) & 31;
1245 if (mbar == 2 && dc->imm == 4) {
5d45de97
EI
1246 /* mbar IMM & 16 decodes to sleep. */
1247 if (dc->rd & 16) {
1248 TCGv_i32 tmp_hlt = tcg_const_i32(EXCP_HLT);
1249 TCGv_i32 tmp_1 = tcg_const_i32(1);
1250
1251 LOG_DIS("sleep\n");
1252
1253 t_sync_flags(dc);
1254 tcg_gen_st_i32(tmp_1, cpu_env,
1255 -offsetof(MicroBlazeCPU, env)
1256 +offsetof(CPUState, halted));
1257 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4);
1258 gen_helper_raise_exception(cpu_env, tmp_hlt);
1259 tcg_temp_free_i32(tmp_hlt);
1260 tcg_temp_free_i32(tmp_1);
1261 return;
1262 }
9f6113c7
EI
1263 LOG_DIS("mbar %d\n", dc->rd);
1264 /* Break the TB. */
1265 dc->cpustate_changed = 1;
1266 return;
1267 }
1268
4acb54ba
EI
1269 LOG_DIS("br%s%s%s%s imm=%x\n",
1270 abs ? "a" : "", link ? "l" : "",
1271 dc->type_b ? "i" : "", dslot ? "d" : "",
1272 dc->imm);
1273
1274 dc->delayed_branch = 1;
1275 if (dslot) {
1276 dc->delayed_branch = 2;
1277 dc->tb_flags |= D_FLAG;
1278 tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
68cee38a 1279 cpu_env, offsetof(CPUMBState, bimm));
4acb54ba
EI
1280 }
1281 if (link && dc->rd)
1282 tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc);
1283
1284 dc->jmp = JMP_INDIRECT;
1285 if (abs) {
1286 tcg_gen_movi_tl(env_btaken, 1);
1287 tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
ff21f70a
EI
1288 if (link && !dslot) {
1289 if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
1290 t_gen_raise_exception(dc, EXCP_BREAK);
1291 if (dc->imm == 0) {
1292 if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
1293 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1294 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1295 return;
1296 }
1297
1298 t_gen_raise_exception(dc, EXCP_DEBUG);
1299 }
1300 }
4acb54ba 1301 } else {
61204ce8
EI
1302 if (dec_alu_op_b_is_small_imm(dc)) {
1303 dc->jmp = JMP_DIRECT;
1304 dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
1305 } else {
4acb54ba
EI
1306 tcg_gen_movi_tl(env_btaken, 1);
1307 tcg_gen_movi_tl(env_btarget, dc->pc);
1308 tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
4acb54ba
EI
1309 }
1310 }
1311}
1312
1313static inline void do_rti(DisasContext *dc)
1314{
1315 TCGv t0, t1;
1316 t0 = tcg_temp_new();
1317 t1 = tcg_temp_new();
1318 tcg_gen_shri_tl(t0, cpu_SR[SR_MSR], 1);
1319 tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_IE);
1320 tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
1321
1322 tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
1323 tcg_gen_or_tl(t1, t1, t0);
1324 msr_write(dc, t1);
1325 tcg_temp_free(t1);
1326 tcg_temp_free(t0);
1327 dc->tb_flags &= ~DRTI_FLAG;
1328}
1329
1330static inline void do_rtb(DisasContext *dc)
1331{
1332 TCGv t0, t1;
1333 t0 = tcg_temp_new();
1334 t1 = tcg_temp_new();
1335 tcg_gen_andi_tl(t1, cpu_SR[SR_MSR], ~MSR_BIP);
1336 tcg_gen_shri_tl(t0, t1, 1);
1337 tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
1338
1339 tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
1340 tcg_gen_or_tl(t1, t1, t0);
1341 msr_write(dc, t1);
1342 tcg_temp_free(t1);
1343 tcg_temp_free(t0);
1344 dc->tb_flags &= ~DRTB_FLAG;
1345}
1346
1347static inline void do_rte(DisasContext *dc)
1348{
1349 TCGv t0, t1;
1350 t0 = tcg_temp_new();
1351 t1 = tcg_temp_new();
1352
1353 tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_EE);
1354 tcg_gen_andi_tl(t1, t1, ~MSR_EIP);
1355 tcg_gen_shri_tl(t0, t1, 1);
1356 tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM));
1357
1358 tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM));
1359 tcg_gen_or_tl(t1, t1, t0);
1360 msr_write(dc, t1);
1361 tcg_temp_free(t1);
1362 tcg_temp_free(t0);
1363 dc->tb_flags &= ~DRTE_FLAG;
1364}
1365
1366static void dec_rts(DisasContext *dc)
1367{
1368 unsigned int b_bit, i_bit, e_bit;
0063ebd6 1369 int mem_index = cpu_mmu_index(&dc->cpu->env);
4acb54ba
EI
1370
1371 i_bit = dc->ir & (1 << 21);
1372 b_bit = dc->ir & (1 << 22);
1373 e_bit = dc->ir & (1 << 23);
1374
1375 dc->delayed_branch = 2;
1376 dc->tb_flags |= D_FLAG;
1377 tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)),
68cee38a 1378 cpu_env, offsetof(CPUMBState, bimm));
4acb54ba
EI
1379
1380 if (i_bit) {
1381 LOG_DIS("rtid ir=%x\n", dc->ir);
1567a005
EI
1382 if ((dc->tb_flags & MSR_EE_FLAG)
1383 && mem_index == MMU_USER_IDX) {
1384 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1385 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1386 }
4acb54ba
EI
1387 dc->tb_flags |= DRTI_FLAG;
1388 } else if (b_bit) {
1389 LOG_DIS("rtbd ir=%x\n", dc->ir);
1567a005
EI
1390 if ((dc->tb_flags & MSR_EE_FLAG)
1391 && mem_index == MMU_USER_IDX) {
1392 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1393 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1394 }
4acb54ba
EI
1395 dc->tb_flags |= DRTB_FLAG;
1396 } else if (e_bit) {
1397 LOG_DIS("rted ir=%x\n", dc->ir);
1567a005
EI
1398 if ((dc->tb_flags & MSR_EE_FLAG)
1399 && mem_index == MMU_USER_IDX) {
1400 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1401 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1402 }
4acb54ba
EI
1403 dc->tb_flags |= DRTE_FLAG;
1404 } else
1405 LOG_DIS("rts ir=%x\n", dc->ir);
1406
23979dc5 1407 dc->jmp = JMP_INDIRECT;
4acb54ba
EI
1408 tcg_gen_movi_tl(env_btaken, 1);
1409 tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
1410}
1411
97694c57
EI
1412static int dec_check_fpuv2(DisasContext *dc)
1413{
be67e9ab 1414 if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) {
97694c57
EI
1415 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
1416 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1417 }
be67e9ab 1418 return (dc->cpu->cfg.use_fpu == 2) ? 0 : PVR2_USE_FPU2_MASK;
97694c57
EI
1419}
1420
1567a005
EI
1421static void dec_fpu(DisasContext *dc)
1422{
97694c57
EI
1423 unsigned int fpu_insn;
1424
1567a005 1425 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6 1426 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
be67e9ab 1427 && (dc->cpu->cfg.use_fpu != 1)) {
97694c57 1428 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1567a005
EI
1429 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1430 return;
1431 }
1432
97694c57
EI
1433 fpu_insn = (dc->ir >> 7) & 7;
1434
1435 switch (fpu_insn) {
1436 case 0:
64254eba
BS
1437 gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1438 cpu_R[dc->rb]);
97694c57
EI
1439 break;
1440
1441 case 1:
64254eba
BS
1442 gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1443 cpu_R[dc->rb]);
97694c57
EI
1444 break;
1445
1446 case 2:
64254eba
BS
1447 gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1448 cpu_R[dc->rb]);
97694c57
EI
1449 break;
1450
1451 case 3:
64254eba
BS
1452 gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1453 cpu_R[dc->rb]);
97694c57
EI
1454 break;
1455
1456 case 4:
1457 switch ((dc->ir >> 4) & 7) {
1458 case 0:
64254eba 1459 gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env,
97694c57
EI
1460 cpu_R[dc->ra], cpu_R[dc->rb]);
1461 break;
1462 case 1:
64254eba 1463 gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env,
97694c57
EI
1464 cpu_R[dc->ra], cpu_R[dc->rb]);
1465 break;
1466 case 2:
64254eba 1467 gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env,
97694c57
EI
1468 cpu_R[dc->ra], cpu_R[dc->rb]);
1469 break;
1470 case 3:
64254eba 1471 gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env,
97694c57
EI
1472 cpu_R[dc->ra], cpu_R[dc->rb]);
1473 break;
1474 case 4:
64254eba 1475 gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env,
97694c57
EI
1476 cpu_R[dc->ra], cpu_R[dc->rb]);
1477 break;
1478 case 5:
64254eba 1479 gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env,
97694c57
EI
1480 cpu_R[dc->ra], cpu_R[dc->rb]);
1481 break;
1482 case 6:
64254eba 1483 gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env,
97694c57
EI
1484 cpu_R[dc->ra], cpu_R[dc->rb]);
1485 break;
1486 default:
71547a3b
BS
1487 qemu_log_mask(LOG_UNIMP,
1488 "unimplemented fcmp fpu_insn=%x pc=%x"
1489 " opc=%x\n",
1490 fpu_insn, dc->pc, dc->opcode);
97694c57
EI
1491 dc->abort_at_next_insn = 1;
1492 break;
1493 }
1494 break;
1495
1496 case 5:
1497 if (!dec_check_fpuv2(dc)) {
1498 return;
1499 }
64254eba 1500 gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
97694c57
EI
1501 break;
1502
1503 case 6:
1504 if (!dec_check_fpuv2(dc)) {
1505 return;
1506 }
64254eba 1507 gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
97694c57
EI
1508 break;
1509
1510 case 7:
1511 if (!dec_check_fpuv2(dc)) {
1512 return;
1513 }
64254eba 1514 gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
97694c57
EI
1515 break;
1516
1517 default:
71547a3b
BS
1518 qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x"
1519 " opc=%x\n",
1520 fpu_insn, dc->pc, dc->opcode);
97694c57
EI
1521 dc->abort_at_next_insn = 1;
1522 break;
1523 }
1567a005
EI
1524}
1525
4acb54ba
EI
1526static void dec_null(DisasContext *dc)
1527{
02b33596 1528 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6 1529 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
02b33596
EI
1530 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1531 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1532 return;
1533 }
4acb54ba
EI
1534 qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
1535 dc->abort_at_next_insn = 1;
1536}
1537
6d76d23e
EI
1538/* Insns connected to FSL or AXI stream attached devices. */
1539static void dec_stream(DisasContext *dc)
1540{
0063ebd6 1541 int mem_index = cpu_mmu_index(&dc->cpu->env);
6d76d23e
EI
1542 TCGv_i32 t_id, t_ctrl;
1543 int ctrl;
1544
1545 LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
1546 dc->type_b ? "" : "d", dc->imm);
1547
1548 if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
1549 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1550 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1551 return;
1552 }
1553
1554 t_id = tcg_temp_new();
1555 if (dc->type_b) {
1556 tcg_gen_movi_tl(t_id, dc->imm & 0xf);
1557 ctrl = dc->imm >> 10;
1558 } else {
1559 tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
1560 ctrl = dc->imm >> 5;
1561 }
1562
1563 t_ctrl = tcg_const_tl(ctrl);
1564
1565 if (dc->rd == 0) {
1566 gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1567 } else {
1568 gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1569 }
1570 tcg_temp_free(t_id);
1571 tcg_temp_free(t_ctrl);
1572}
1573
4acb54ba
EI
1574static struct decoder_info {
1575 struct {
1576 uint32_t bits;
1577 uint32_t mask;
1578 };
1579 void (*dec)(DisasContext *dc);
1580} decinfo[] = {
1581 {DEC_ADD, dec_add},
1582 {DEC_SUB, dec_sub},
1583 {DEC_AND, dec_and},
1584 {DEC_XOR, dec_xor},
1585 {DEC_OR, dec_or},
1586 {DEC_BIT, dec_bit},
1587 {DEC_BARREL, dec_barrel},
1588 {DEC_LD, dec_load},
1589 {DEC_ST, dec_store},
1590 {DEC_IMM, dec_imm},
1591 {DEC_BR, dec_br},
1592 {DEC_BCC, dec_bcc},
1593 {DEC_RTS, dec_rts},
1567a005 1594 {DEC_FPU, dec_fpu},
4acb54ba
EI
1595 {DEC_MUL, dec_mul},
1596 {DEC_DIV, dec_div},
1597 {DEC_MSR, dec_msr},
6d76d23e 1598 {DEC_STREAM, dec_stream},
4acb54ba
EI
1599 {{0, 0}, dec_null}
1600};
1601
64254eba 1602static inline void decode(DisasContext *dc, uint32_t ir)
4acb54ba 1603{
4acb54ba
EI
1604 int i;
1605
fdefe51c 1606 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
4acb54ba 1607 tcg_gen_debug_insn_start(dc->pc);
fdefe51c 1608 }
4acb54ba 1609
64254eba 1610 dc->ir = ir;
4acb54ba
EI
1611 LOG_DIS("%8.8x\t", dc->ir);
1612
1613 if (dc->ir)
1614 dc->nr_nops = 0;
1615 else {
1567a005 1616 if ((dc->tb_flags & MSR_EE_FLAG)
0063ebd6
AF
1617 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
1618 && (dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
1567a005
EI
1619 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1620 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1621 return;
1622 }
1623
4acb54ba
EI
1624 LOG_DIS("nr_nops=%d\t", dc->nr_nops);
1625 dc->nr_nops++;
a47dddd7 1626 if (dc->nr_nops > 4) {
0063ebd6 1627 cpu_abort(CPU(dc->cpu), "fetching nop sequence\n");
a47dddd7 1628 }
4acb54ba
EI
1629 }
1630 /* bit 2 seems to indicate insn type. */
1631 dc->type_b = ir & (1 << 29);
1632
1633 dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1634 dc->rd = EXTRACT_FIELD(ir, 21, 25);
1635 dc->ra = EXTRACT_FIELD(ir, 16, 20);
1636 dc->rb = EXTRACT_FIELD(ir, 11, 15);
1637 dc->imm = EXTRACT_FIELD(ir, 0, 15);
1638
1639 /* Large switch for all insns. */
1640 for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1641 if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1642 decinfo[i].dec(dc);
1643 break;
1644 }
1645 }
1646}
1647
68cee38a 1648static void check_breakpoint(CPUMBState *env, DisasContext *dc)
4acb54ba 1649{
f0c3c505 1650 CPUState *cs = CPU(mb_env_get_cpu(env));
4acb54ba
EI
1651 CPUBreakpoint *bp;
1652
f0c3c505
AF
1653 if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
1654 QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
4acb54ba
EI
1655 if (bp->pc == dc->pc) {
1656 t_gen_raise_exception(dc, EXCP_DEBUG);
1657 dc->is_jmp = DISAS_UPDATE;
1658 }
1659 }
1660 }
1661}
1662
1663/* generate intermediate code for basic block 'tb'. */
fd327f48 1664static inline void
4a274212
AF
1665gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,
1666 bool search_pc)
4acb54ba 1667{
ed2803da 1668 CPUState *cs = CPU(cpu);
4a274212 1669 CPUMBState *env = &cpu->env;
4acb54ba
EI
1670 uint32_t pc_start;
1671 int j, lj;
1672 struct DisasContext ctx;
1673 struct DisasContext *dc = &ctx;
1674 uint32_t next_page_start, org_flags;
1675 target_ulong npc;
1676 int num_insns;
1677 int max_insns;
1678
4acb54ba 1679 pc_start = tb->pc;
0063ebd6 1680 dc->cpu = cpu;
4acb54ba
EI
1681 dc->tb = tb;
1682 org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
1683
4acb54ba
EI
1684 dc->is_jmp = DISAS_NEXT;
1685 dc->jmp = 0;
1686 dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
23979dc5
EI
1687 if (dc->delayed_branch) {
1688 dc->jmp = JMP_INDIRECT;
1689 }
4acb54ba 1690 dc->pc = pc_start;
ed2803da 1691 dc->singlestep_enabled = cs->singlestep_enabled;
4acb54ba
EI
1692 dc->cpustate_changed = 0;
1693 dc->abort_at_next_insn = 0;
1694 dc->nr_nops = 0;
1695
a47dddd7
AF
1696 if (pc_start & 3) {
1697 cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
1698 }
4acb54ba
EI
1699
1700 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1701#if !SIM_COMPAT
1702 qemu_log("--------------\n");
a0762859 1703 log_cpu_state(CPU(cpu), 0);
4acb54ba
EI
1704#endif
1705 }
1706
1707 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
1708 lj = -1;
1709 num_insns = 0;
1710 max_insns = tb->cflags & CF_COUNT_MASK;
1711 if (max_insns == 0)
1712 max_insns = CF_COUNT_MASK;
1713
cd42d5b2 1714 gen_tb_start(tb);
4acb54ba
EI
1715 do
1716 {
1717#if SIM_COMPAT
1718 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1719 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
1720 gen_helper_debug();
1721 }
1722#endif
1723 check_breakpoint(env, dc);
1724
1725 if (search_pc) {
fe700adb 1726 j = tcg_op_buf_count();
4acb54ba
EI
1727 if (lj < j) {
1728 lj++;
1729 while (lj < j)
ab1103de 1730 tcg_ctx.gen_opc_instr_start[lj++] = 0;
4acb54ba 1731 }
25983cad 1732 tcg_ctx.gen_opc_pc[lj] = dc->pc;
ab1103de 1733 tcg_ctx.gen_opc_instr_start[lj] = 1;
c9c99c22 1734 tcg_ctx.gen_opc_icount[lj] = num_insns;
4acb54ba
EI
1735 }
1736
1737 /* Pretty disas. */
1738 LOG_DIS("%8.8x:\t", dc->pc);
1739
1740 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
1741 gen_io_start();
1742
1743 dc->clear_imm = 1;
64254eba 1744 decode(dc, cpu_ldl_code(env, dc->pc));
4acb54ba
EI
1745 if (dc->clear_imm)
1746 dc->tb_flags &= ~IMM_FLAG;
4acb54ba
EI
1747 dc->pc += 4;
1748 num_insns++;
1749
1750 if (dc->delayed_branch) {
1751 dc->delayed_branch--;
1752 if (!dc->delayed_branch) {
1753 if (dc->tb_flags & DRTI_FLAG)
1754 do_rti(dc);
1755 if (dc->tb_flags & DRTB_FLAG)
1756 do_rtb(dc);
1757 if (dc->tb_flags & DRTE_FLAG)
1758 do_rte(dc);
1759 /* Clear the delay slot flag. */
1760 dc->tb_flags &= ~D_FLAG;
1761 /* If it is a direct jump, try direct chaining. */
23979dc5 1762 if (dc->jmp == JMP_INDIRECT) {
4acb54ba
EI
1763 eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
1764 dc->is_jmp = DISAS_JUMP;
23979dc5 1765 } else if (dc->jmp == JMP_DIRECT) {
844bab60
EI
1766 t_sync_flags(dc);
1767 gen_goto_tb(dc, 0, dc->jmp_pc);
1768 dc->is_jmp = DISAS_TB_JUMP;
1769 } else if (dc->jmp == JMP_DIRECT_CC) {
42a268c2 1770 TCGLabel *l1 = gen_new_label();
23979dc5 1771 t_sync_flags(dc);
23979dc5
EI
1772 /* Conditional jmp. */
1773 tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
1774 gen_goto_tb(dc, 1, dc->pc);
1775 gen_set_label(l1);
1776 gen_goto_tb(dc, 0, dc->jmp_pc);
1777
1778 dc->is_jmp = DISAS_TB_JUMP;
4acb54ba
EI
1779 }
1780 break;
1781 }
1782 }
ed2803da 1783 if (cs->singlestep_enabled) {
4acb54ba 1784 break;
ed2803da 1785 }
4acb54ba 1786 } while (!dc->is_jmp && !dc->cpustate_changed
fe700adb
RH
1787 && !tcg_op_buf_full()
1788 && !singlestep
1789 && (dc->pc < next_page_start)
1790 && num_insns < max_insns);
4acb54ba
EI
1791
1792 npc = dc->pc;
844bab60 1793 if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
4acb54ba
EI
1794 if (dc->tb_flags & D_FLAG) {
1795 dc->is_jmp = DISAS_UPDATE;
1796 tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1797 sync_jmpstate(dc);
1798 } else
1799 npc = dc->jmp_pc;
1800 }
1801
1802 if (tb->cflags & CF_LAST_IO)
1803 gen_io_end();
1804 /* Force an update if the per-tb cpu state has changed. */
1805 if (dc->is_jmp == DISAS_NEXT
1806 && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
1807 dc->is_jmp = DISAS_UPDATE;
1808 tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1809 }
1810 t_sync_flags(dc);
1811
ed2803da 1812 if (unlikely(cs->singlestep_enabled)) {
6c5f738d
EI
1813 TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1814
1815 if (dc->is_jmp != DISAS_JUMP) {
4acb54ba 1816 tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
6c5f738d 1817 }
64254eba 1818 gen_helper_raise_exception(cpu_env, tmp);
6c5f738d 1819 tcg_temp_free_i32(tmp);
4acb54ba
EI
1820 } else {
1821 switch(dc->is_jmp) {
1822 case DISAS_NEXT:
1823 gen_goto_tb(dc, 1, npc);
1824 break;
1825 default:
1826 case DISAS_JUMP:
1827 case DISAS_UPDATE:
1828 /* indicate that the hash table must be used
1829 to find the next TB */
1830 tcg_gen_exit_tb(0);
1831 break;
1832 case DISAS_TB_JUMP:
1833 /* nothing more to generate */
1834 break;
1835 }
1836 }
806f352d 1837 gen_tb_end(tb, num_insns);
0a7df5da 1838
4acb54ba 1839 if (search_pc) {
fe700adb 1840 j = tcg_op_buf_count();
4acb54ba
EI
1841 lj++;
1842 while (lj <= j)
ab1103de 1843 tcg_ctx.gen_opc_instr_start[lj++] = 0;
4acb54ba
EI
1844 } else {
1845 tb->size = dc->pc - pc_start;
1846 tb->icount = num_insns;
1847 }
1848
1849#ifdef DEBUG_DISAS
1850#if !SIM_COMPAT
1851 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1852 qemu_log("\n");
1853#if DISAS_GNU
d49190c4 1854 log_target_disas(cs, pc_start, dc->pc - pc_start, 0);
4acb54ba 1855#endif
fe700adb
RH
1856 qemu_log("\nisize=%d osize=%d\n",
1857 dc->pc - pc_start, tcg_op_buf_count());
4acb54ba
EI
1858 }
1859#endif
1860#endif
1861 assert(!dc->abort_at_next_insn);
1862}
1863
68cee38a 1864void gen_intermediate_code (CPUMBState *env, struct TranslationBlock *tb)
4acb54ba 1865{
4a274212 1866 gen_intermediate_code_internal(mb_env_get_cpu(env), tb, false);
4acb54ba
EI
1867}
1868
68cee38a 1869void gen_intermediate_code_pc (CPUMBState *env, struct TranslationBlock *tb)
4acb54ba 1870{
4a274212 1871 gen_intermediate_code_internal(mb_env_get_cpu(env), tb, true);
4acb54ba
EI
1872}
1873
878096ee
AF
1874void mb_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
1875 int flags)
4acb54ba 1876{
878096ee
AF
1877 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1878 CPUMBState *env = &cpu->env;
4acb54ba
EI
1879 int i;
1880
1881 if (!env || !f)
1882 return;
1883
1884 cpu_fprintf(f, "IN: PC=%x %s\n",
1885 env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
97694c57 1886 cpu_fprintf(f, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
4c24aa0a 1887 env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
97694c57 1888 env->debug, env->imm, env->iflags, env->sregs[SR_FSR]);
17c52a43 1889 cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
4acb54ba
EI
1890 env->btaken, env->btarget,
1891 (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
17c52a43
EI
1892 (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
1893 (env->sregs[SR_MSR] & MSR_EIP),
1894 (env->sregs[SR_MSR] & MSR_IE));
1895
4acb54ba
EI
1896 for (i = 0; i < 32; i++) {
1897 cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1898 if ((i + 1) % 4 == 0)
1899 cpu_fprintf(f, "\n");
1900 }
1901 cpu_fprintf(f, "\n\n");
1902}
1903
b33ab1f7 1904MicroBlazeCPU *cpu_mb_init(const char *cpu_model)
4acb54ba 1905{
b77f98ca 1906 MicroBlazeCPU *cpu;
4acb54ba 1907
b77f98ca 1908 cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
4acb54ba 1909
746b03b2 1910 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
4acb54ba 1911
cd0c24f9
AF
1912 return cpu;
1913}
4acb54ba 1914
cd0c24f9
AF
1915void mb_tcg_init(void)
1916{
1917 int i;
4acb54ba
EI
1918
1919 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
1920
1921 env_debug = tcg_global_mem_new(TCG_AREG0,
68cee38a 1922 offsetof(CPUMBState, debug),
4acb54ba
EI
1923 "debug0");
1924 env_iflags = tcg_global_mem_new(TCG_AREG0,
68cee38a 1925 offsetof(CPUMBState, iflags),
4acb54ba
EI
1926 "iflags");
1927 env_imm = tcg_global_mem_new(TCG_AREG0,
68cee38a 1928 offsetof(CPUMBState, imm),
4acb54ba
EI
1929 "imm");
1930 env_btarget = tcg_global_mem_new(TCG_AREG0,
68cee38a 1931 offsetof(CPUMBState, btarget),
4acb54ba
EI
1932 "btarget");
1933 env_btaken = tcg_global_mem_new(TCG_AREG0,
68cee38a 1934 offsetof(CPUMBState, btaken),
4acb54ba 1935 "btaken");
4a536270
EI
1936 env_res_addr = tcg_global_mem_new(TCG_AREG0,
1937 offsetof(CPUMBState, res_addr),
1938 "res_addr");
11a76217
EI
1939 env_res_val = tcg_global_mem_new(TCG_AREG0,
1940 offsetof(CPUMBState, res_val),
1941 "res_val");
4acb54ba
EI
1942 for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
1943 cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
68cee38a 1944 offsetof(CPUMBState, regs[i]),
4acb54ba
EI
1945 regnames[i]);
1946 }
1947 for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
1948 cpu_SR[i] = tcg_global_mem_new(TCG_AREG0,
68cee38a 1949 offsetof(CPUMBState, sregs[i]),
4acb54ba
EI
1950 special_regnames[i]);
1951 }
4acb54ba
EI
1952}
1953
68cee38a 1954void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos)
4acb54ba 1955{
25983cad 1956 env->sregs[SR_PC] = tcg_ctx.gen_opc_pc[pc_pos];
4acb54ba 1957}
This page took 0.907738 seconds and 4 git commands to generate.