blob: 4068946f400c92a6c6dba0e52a017dfa39a640fd [file] [log] [blame]
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001/*
2 * Xilinx MicroBlaze emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2009 Edgar E. Iglesias.
Peter A. G. Crosthwaitedadc1062012-04-12 14:30:30 +10005 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02006 *
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
Blue Swirl8167ee82009-07-16 20:47:01 +000018 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020019 */
20
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020021#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +020022#include "disas/disas.h"
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020023#include "tcg-op.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070024#include "exec/helper-proto.h"
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020025#include "microblaze-decode.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010026#include "exec/cpu_ldst.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070027#include "exec/helper-gen.h"
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020028
Lluís Vilanovaa7e30d82014-05-30 14:12:25 +020029#include "trace-tcg.h"
30
31
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020032#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;
Edgar E. Iglesias4a536272013-10-23 16:44:08 +020054static TCGv env_res_addr;
Edgar E. Iglesias11a76212013-10-23 16:54:31 +020055static TCGv env_res_val;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020056
Paolo Bonzini022c62c2012-12-17 18:19:49 +010057#include "exec/gen-icount.h"
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020058
59/* This is the state at translation time. */
60typedef struct DisasContext {
Andreas Färber0063ebd2013-09-03 20:02:48 +020061 MicroBlazeCPU *cpu;
Edgar E. Iglesiasa5efa642010-07-25 00:09:41 +020062 target_ulong pc;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020063
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
Edgar E. Iglesias844bab62011-01-14 12:30:26 +010077#define JMP_NOJMP 0
78#define JMP_DIRECT 1
79#define JMP_DIRECT_CC 2
80#define JMP_INDIRECT 3
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020081 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
Juan Quintela38972932009-09-23 01:19:02 +020090static const char *regnames[] =
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020091{
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
Juan Quintela38972932009-09-23 01:19:02 +020098static const char *special_regnames[] =
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +020099{
100 "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7",
101 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
102 "sr16", "sr17", "sr18"
103};
104
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200105static inline void t_sync_flags(DisasContext *dc)
106{
Dong Xu Wang4abf79a2011-11-22 18:06:21 +0800107 /* Synch the tb dependent flags between translator and runtime. */
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200108 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);
Blue Swirl64254eb2012-09-02 08:39:22 +0000120 gen_helper_raise_exception(cpu_env, tmp);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200121 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);
Richard Henderson8cfd0492013-08-20 15:53:10 -0700132 tcg_gen_exit_tb((uintptr_t)tb + n);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200133 } else {
134 tcg_gen_movi_tl(cpu_SR[SR_PC], dest);
135 tcg_gen_exit_tb(0);
136 }
137}
138
Edgar E. Iglesiasee8b2462011-01-22 11:57:19 +0100139static void read_carry(DisasContext *dc, TCGv d)
140{
141 tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31);
142}
143
Edgar E. Iglesias04ec7df2013-10-24 22:31:22 +0200144/*
145 * write_carry sets the carry bits in MSR based on bit 0 of v.
146 * v[31:1] are ignored.
147 */
Edgar E. Iglesiasee8b2462011-01-22 11:57:19 +0100148static 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
Edgar E. Iglesias65ab5eb2013-10-24 12:49:05 +0200160static void write_carryi(DisasContext *dc, bool carry)
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +1000161{
162 TCGv t0 = tcg_temp_new();
Edgar E. Iglesias65ab5eb2013-10-24 12:49:05 +0200163 tcg_gen_movi_tl(t0, carry);
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +1000164 write_carry(dc, t0);
165 tcg_temp_free(t0);
166}
167
Edgar E. Iglesias61204ce2010-07-24 21:24:59 +0200168/* 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200176static 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;
Edgar E. Iglesias40cbf5b2011-01-22 12:02:53 +0100191 TCGv cf;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200192
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
Edgar E. Iglesias40cbf5b2011-01-22 12:02:53 +0100200 /* 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;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200217 }
Edgar E. Iglesias40cbf5b2011-01-22 12:02:53 +0100218
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();
Edgar E. Iglesias5d0bb822011-01-23 03:52:20 +0100230 gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
Edgar E. Iglesias40cbf5b2011-01-22 12:02:53 +0100231 tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
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 {
Edgar E. Iglesias5d0bb822011-01-23 03:52:20 +0100236 gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf);
Edgar E. Iglesias40cbf5b2011-01-22 12:02:53 +0100237 write_carry(dc, cf);
238 }
239 tcg_temp_free(cf);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200240}
241
242static void dec_sub(DisasContext *dc)
243{
244 unsigned int u, cmp, k, c;
Edgar E. Iglesiase0a42eb2011-01-22 12:39:16 +0100245 TCGv cf, na;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200246
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 }
Edgar E. Iglesiase0a42eb2011-01-22 12:39:16 +0100260 return;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200261 }
Edgar E. Iglesiase0a42eb2011-01-22 12:39:16 +0100262
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) {
271 tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
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();
Edgar E. Iglesias5d0bb822011-01-23 03:52:20 +0100300 gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf);
Edgar E. Iglesiase0a42eb2011-01-22 12:39:16 +0100301 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 {
Edgar E. Iglesias5d0bb822011-01-23 03:52:20 +0100306 gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf);
Edgar E. Iglesiase0a42eb2011-01-22 12:39:16 +0100307 write_carry(dc, cf);
308 }
309 tcg_temp_free(cf);
310 tcg_temp_free(na);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200311}
312
313static void dec_pattern(DisasContext *dc)
314{
315 unsigned int mode;
Richard Henderson42a268c2015-02-13 12:51:55 -0800316 TCGLabel *l1;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200317
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200318 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +0200319 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
320 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200321 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
322 t_gen_raise_exception(dc, EXCP_HW_EXCP);
323 }
324
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200325 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:
Andreas Färber0063ebd2013-09-03 20:02:48 +0200362 cpu_abort(CPU(dc->cpu),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200363 "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) {
Edgar E. Iglesiasa2359002013-10-24 18:49:46 +0200384 tcg_gen_andc_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200385 } 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200413static 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{
Edgar E. Iglesias97b833c2011-08-25 16:41:18 +1000420 TCGv t;
421
422 t = tcg_temp_new();
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200423 dc->cpustate_changed = 1;
Edgar E. Iglesias97b833c2011-08-25 16:41:18 +1000424 /* PVR bit is not writable. */
Edgar E. Iglesias8a84fc62011-08-25 16:41:19 +1000425 tcg_gen_andi_tl(t, v, ~MSR_PVR);
426 tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], MSR_PVR);
Edgar E. Iglesias97b833c2011-08-25 16:41:18 +1000427 tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], v);
428 tcg_temp_free(t);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200429}
430
431static void dec_msr(DisasContext *dc)
432{
Andreas Färber0063ebd2013-09-03 20:02:48 +0200433 CPUState *cs = CPU(dc->cpu);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200434 TCGv t0, t1;
435 unsigned int sr, to, rn;
Andreas Färber0063ebd2013-09-03 20:02:48 +0200436 int mem_index = cpu_mmu_index(&dc->cpu->env);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200437
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);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200450
Andreas Färber0063ebd2013-09-03 20:02:48 +0200451 if (!(dc->cpu->env.pvr.regs[2] & PVR2_USE_MSR_INSTR)) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200452 /* 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200463 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
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200484 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200493#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)
Blue Swirl64254eb2012-09-02 08:39:22 +0000499 gen_helper_mmu_write(cpu_env, tcg_const_tl(sr), cpu_R[dc->ra]);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200500 else
Blue Swirl64254eb2012-09-02 08:39:22 +0000501 gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tcg_const_tl(sr));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200502 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:
Edgar E. Iglesias97694c52010-09-09 10:20:17 +0200521 tcg_gen_andi_tl(cpu_SR[SR_FSR], cpu_R[dc->ra], 31);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200522 break;
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100523 case 0x800:
Andreas Färber68cee382012-03-14 01:38:22 +0100524 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, slr));
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100525 break;
526 case 0x802:
Andreas Färber68cee382012-03-14 01:38:22 +0100527 tcg_gen_st_tl(cpu_R[dc->ra], cpu_env, offsetof(CPUMBState, shr));
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100528 break;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200529 default:
Andreas Färber0063ebd2013-09-03 20:02:48 +0200530 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200531 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:
Edgar E. Iglesias97694c52010-09-09 10:20:17 +0200550 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_FSR]);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200551 break;
552 case 0xb:
553 tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]);
554 break;
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100555 case 0x800:
Andreas Färber68cee382012-03-14 01:38:22 +0100556 tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, slr));
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100557 break;
558 case 0x802:
Andreas Färber68cee382012-03-14 01:38:22 +0100559 tcg_gen_ld_tl(cpu_R[dc->rd], cpu_env, offsetof(CPUMBState, shr));
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100560 break;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200561 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],
Andreas Färber68cee382012-03-14 01:38:22 +0100576 cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200577 break;
578 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200579 cpu_abort(cs, "unknown mfs reg %x\n", sr);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200580 break;
581 }
582 }
Edgar E. Iglesiasee7dbcf2009-09-03 11:18:55 +0200583
584 if (dc->rd == 0) {
585 tcg_gen_movi_tl(cpu_R[0], 0);
586 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200587}
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
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200635 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +0200636 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
637 && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_HW_MUL_MASK)) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200638 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200643 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
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200653 /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */
654 if (subcode >= 1 && subcode <= 3
Andreas Färber0063ebd2013-09-03 20:02:48 +0200655 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_MUL64_MASK))) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200656 /* nop??? */
657 }
658
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200659 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:
Andreas Färber0063ebd2013-09-03 20:02:48 +0200677 cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200678 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
Andreas Färber0063ebd2013-09-03 20:02:48 +0200693 if ((dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
694 && !((dc->cpu->env.pvr.regs[0] & PVR0_USE_DIV_MASK))) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200695 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
696 t_gen_raise_exception(dc, EXCP_HW_EXCP);
697 }
698
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200699 if (u)
Blue Swirl64254eb2012-09-02 08:39:22 +0000700 gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
701 cpu_R[dc->ra]);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200702 else
Blue Swirl64254eb2012-09-02 08:39:22 +0000703 gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)),
704 cpu_R[dc->ra]);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200705 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
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200714 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +0200715 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
716 && !(dc->cpu->env.pvr.regs[0] & PVR0_USE_BARREL_MASK)) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200717 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200722 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{
Andreas Färber0063ebd2013-09-03 20:02:48 +0200745 CPUState *cs = CPU(dc->cpu);
Edgar E. Iglesias09b9f112013-10-24 19:18:28 +0200746 TCGv t0;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200747 unsigned int op;
Andreas Färber0063ebd2013-09-03 20:02:48 +0200748 int mem_index = cpu_mmu_index(&dc->cpu->env);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200749
Peter A. G. Crosthwaiteace2e4d2012-05-17 15:37:49 +1000750 op = dc->ir & ((1 << 9) - 1);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200751 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);
Edgar E. Iglesias09b9f112013-10-24 19:18:28 +0200757 tcg_gen_andi_tl(t0, cpu_SR[SR_MSR], MSR_CC);
758 write_carry(dc, cpu_R[dc->ra]);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200759 if (dc->rd) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200760 tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1);
Edgar E. Iglesias09b9f112013-10-24 19:18:28 +0200761 tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t0);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200762 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200763 tcg_temp_free(t0);
764 break;
765
766 case 0x1:
767 case 0x41:
768 /* srl. */
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200769 LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra);
770
Edgar E. Iglesiasbb3cb952013-10-24 19:03:44 +0200771 /* Update carry. Note that write carry only looks at the LSB. */
772 write_carry(dc, cpu_R[dc->ra]);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200773 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:
Edgar E. Iglesiasf062a3c2009-12-13 09:10:08 +0100789 case 0x66:
790 case 0x74:
791 case 0x76:
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200792 /* wdc. */
793 LOG_DIS("wdc r%d\n", dc->ra);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200794 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 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200800 break;
801 case 0x68:
802 /* wic. */
803 LOG_DIS("wic r%d\n", dc->ra);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +0200804 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 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200810 break;
Edgar E. Iglesias48b5e962012-01-10 10:17:21 +0100811 case 0xe0:
812 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +0200813 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
814 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR))) {
Edgar E. Iglesias48b5e962012-01-10 10:17:21 +0100815 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
816 t_gen_raise_exception(dc, EXCP_HW_EXCP);
817 }
Andreas Färber0063ebd2013-09-03 20:02:48 +0200818 if (dc->cpu->env.pvr.regs[2] & PVR2_USE_PCMP_INSTR) {
Edgar E. Iglesias48b5e962012-01-10 10:17:21 +0100819 gen_helper_clz(cpu_R[dc->rd], cpu_R[dc->ra]);
820 }
821 break;
Peter A. G. Crosthwaiteace2e4d2012-05-17 15:37:49 +1000822 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;
Peter Crosthwaiteb8c6a5d2012-11-08 14:01:19 +1000827 case 0x1e2:
Peter A. G. Crosthwaiteace2e4d2012-05-17 15:37:49 +1000828 /*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;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200832 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200833 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);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200835 break;
836 }
837}
838
839static inline void sync_jmpstate(DisasContext *dc)
840{
Edgar E. Iglesias844bab62011-01-14 12:30:26 +0100841 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 }
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +0100845 dc->jmp = JMP_INDIRECT;
846 tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200847 }
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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200858static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t)
859{
860 unsigned int extimm = dc->tb_flags & IMM_FLAG;
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100861 /* Should be set to one if r1 is used by loadstores. */
862 int stackprot = 0;
863
864 /* All load/stores use ra. */
865 if (dc->ra == 1) {
866 stackprot = 1;
867 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200868
Edgar E. Iglesias9ef55352011-01-19 22:48:07 +0100869 /* Treat the common cases first. */
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200870 if (!dc->type_b) {
Edgar E. Iglesias4b5ef0b2010-07-24 23:25:49 +0200871 /* 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
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100878 if (dc->rb == 1) {
879 stackprot = 1;
880 }
881
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200882 *t = tcg_temp_new();
883 tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]);
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100884
885 if (stackprot) {
Blue Swirl64254eb2012-09-02 08:39:22 +0000886 gen_helper_stackprot(cpu_env, *t);
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100887 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200888 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
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100903 if (stackprot) {
Blue Swirl64254eb2012-09-02 08:39:22 +0000904 gen_helper_stackprot(cpu_env, *t);
Edgar E. Iglesias5818dee2012-01-10 10:27:11 +0100905 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200906 return t;
907}
908
909static void dec_load(DisasContext *dc)
910{
Richard Henderson47acdd62013-12-10 15:40:21 -0800911 TCGv t, v, *addr;
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +1000912 unsigned int size, rev = 0, ex = 0;
Richard Henderson47acdd62013-12-10 15:40:21 -0800913 TCGMemOp mop;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200914
Richard Henderson47acdd62013-12-10 15:40:21 -0800915 mop = dc->opcode & 3;
916 size = 1 << mop;
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100917 if (!dc->type_b) {
918 rev = (dc->ir >> 9) & 1;
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +1000919 ex = (dc->ir >> 10) & 1;
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100920 }
Richard Henderson47acdd62013-12-10 15:40:21 -0800921 mop |= MO_TE;
922 if (rev) {
923 mop ^= MO_BSWAP;
924 }
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100925
Edgar E. Iglesias01876882009-09-04 10:38:59 +0200926 if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +0200927 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
Edgar E. Iglesias01876882009-09-04 10:38:59 +0200928 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
929 t_gen_raise_exception(dc, EXCP_HW_EXCP);
930 return;
931 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200932
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +1000933 LOG_DIS("l%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
934 ex ? "x" : "");
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100935
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +0200936 t_sync_flags(dc);
937 addr = compute_ldst_addr(dc, &t);
938
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100939 /*
940 * When doing reverse accesses we need to do two things.
941 *
Stefan Weil4ff97862011-03-13 15:44:02 +0100942 * 1. Reverse the address wrt endianness.
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100943 * 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);
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100967 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:
Andreas Färber0063ebd2013-09-03 20:02:48 +0200985 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +0100986 break;
987 }
988 }
989
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +1000990 /* 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
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001001 /* If we get a fault on a dslot, the jmpstate better be in sync. */
1002 sync_jmpstate(dc);
Edgar E. Iglesias968a40f2009-09-03 12:59:46 +02001003
1004 /* Verify alignment if needed. */
Richard Henderson47acdd62013-12-10 15:40:21 -08001005 /*
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();
Andreas Färber0063ebd2013-09-03 20:02:48 +02001012 tcg_gen_qemu_ld_tl(v, *addr, cpu_mmu_index(&dc->cpu->env), mop);
Richard Henderson47acdd62013-12-10 15:40:21 -08001013
Andreas Färber0063ebd2013-09-03 20:02:48 +02001014 if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
Edgar E. Iglesiasa12f6502009-09-11 10:35:27 +02001015 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
Blue Swirl64254eb2012-09-02 08:39:22 +00001016 gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
Edgar E. Iglesias3aa80982009-09-03 22:28:21 +02001017 tcg_const_tl(0), tcg_const_tl(size - 1));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001018 }
1019
Richard Henderson47acdd62013-12-10 15:40:21 -08001020 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
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001029 if (ex) { /* lwx */
1030 /* no support for for AXI exclusive so always clear C */
1031 write_carryi(dc, 0);
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001032 }
1033
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001034 if (addr == &t)
1035 tcg_temp_free(t);
1036}
1037
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001038static void dec_store(DisasContext *dc)
1039{
Edgar E. Iglesias4a536272013-10-23 16:44:08 +02001040 TCGv t, *addr, swx_addr;
Richard Henderson42a268c2015-02-13 12:51:55 -08001041 TCGLabel *swx_skip = NULL;
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001042 unsigned int size, rev = 0, ex = 0;
Richard Henderson47acdd62013-12-10 15:40:21 -08001043 TCGMemOp mop;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001044
Richard Henderson47acdd62013-12-10 15:40:21 -08001045 mop = dc->opcode & 3;
1046 size = 1 << mop;
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001047 if (!dc->type_b) {
1048 rev = (dc->ir >> 9) & 1;
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001049 ex = (dc->ir >> 10) & 1;
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001050 }
Richard Henderson47acdd62013-12-10 15:40:21 -08001051 mop |= MO_TE;
1052 if (rev) {
1053 mop ^= MO_BSWAP;
1054 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001055
Edgar E. Iglesias01876882009-09-04 10:38:59 +02001056 if (size > 4 && (dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +02001057 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
Edgar E. Iglesias01876882009-09-04 10:38:59 +02001058 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
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001063 LOG_DIS("s%d%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "",
1064 ex ? "x" : "");
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001065 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);
Edgar E. Iglesias968a40f2009-09-03 12:59:46 +02001069
Peter A. G. Crosthwaite083dbf42012-06-05 12:31:04 +10001070 swx_addr = tcg_temp_local_new();
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001071 if (ex) { /* swx */
Edgar E. Iglesias11a76212013-10-23 16:54:31 +02001072 TCGv tval;
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001073
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
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001080 write_carryi(dc, 1);
1081 swx_skip = gen_new_label();
Edgar E. Iglesias4a536272013-10-23 16:44:08 +02001082 tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, swx_addr, swx_skip);
Edgar E. Iglesias11a76212013-10-23 16:54:31 +02001083
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();
Andreas Färber0063ebd2013-09-03 20:02:48 +02001090 tcg_gen_qemu_ld_tl(tval, swx_addr, cpu_mmu_index(&dc->cpu->env),
1091 MO_TEUL);
Edgar E. Iglesias11a76212013-10-23 16:54:31 +02001092 tcg_gen_brcond_tl(TCG_COND_NE, env_res_val, tval, swx_skip);
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001093 write_carryi(dc, 0);
Edgar E. Iglesias11a76212013-10-23 16:54:31 +02001094 tcg_temp_free(tval);
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001095 }
1096
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001097 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);
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001119 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:
Andreas Färber0063ebd2013-09-03 20:02:48 +02001137 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001138 break;
1139 }
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001140 }
Andreas Färber0063ebd2013-09-03 20:02:48 +02001141 tcg_gen_qemu_st_tl(cpu_R[dc->rd], *addr, cpu_mmu_index(&dc->cpu->env), mop);
Edgar E. Iglesiasa12f6502009-09-11 10:35:27 +02001142
Edgar E. Iglesias968a40f2009-09-03 12:59:46 +02001143 /* Verify alignment if needed. */
Andreas Färber0063ebd2013-09-03 20:02:48 +02001144 if ((dc->cpu->env.pvr.regs[2] & PVR2_UNALIGNED_EXC_MASK) && size > 1) {
Edgar E. Iglesiasa12f6502009-09-11 10:35:27 +02001145 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
1146 /* FIXME: if the alignment is wrong, we should restore the value
Dong Xu Wang4abf79a2011-11-22 18:06:21 +08001147 * in memory. One possible way to achieve this is to probe
Edgar E. Iglesias9f8beb62011-01-19 23:18:00 +01001148 * the MMU prior to the memaccess, thay way we could put
1149 * the alignment checks in between the probe and the mem
1150 * access.
Edgar E. Iglesiasa12f6502009-09-11 10:35:27 +02001151 */
Blue Swirl64254eb2012-09-02 08:39:22 +00001152 gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd),
Edgar E. Iglesias3aa80982009-09-03 22:28:21 +02001153 tcg_const_tl(1), tcg_const_tl(size - 1));
Edgar E. Iglesias968a40f2009-09-03 12:59:46 +02001154 }
Peter A. G. Crosthwaite083dbf42012-06-05 12:31:04 +10001155
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001156 if (ex) {
1157 gen_set_label(swx_skip);
Peter A. G. Crosthwaite8cc9b432012-06-01 13:23:28 +10001158 }
Peter A. G. Crosthwaite083dbf42012-06-05 12:31:04 +10001159 tcg_temp_free(swx_addr);
Edgar E. Iglesias968a40f2009-09-03 12:59:46 +02001160
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001161 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{
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001168 switch (cc) {
1169 case CC_EQ:
Edgar E. Iglesiasb2565c62010-07-24 21:51:51 +02001170 tcg_gen_setcond_tl(TCG_COND_EQ, d, a, b);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001171 break;
1172 case CC_NE:
Edgar E. Iglesiasb2565c62010-07-24 21:51:51 +02001173 tcg_gen_setcond_tl(TCG_COND_NE, d, a, b);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001174 break;
1175 case CC_LT:
Edgar E. Iglesiasb2565c62010-07-24 21:51:51 +02001176 tcg_gen_setcond_tl(TCG_COND_LT, d, a, b);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001177 break;
1178 case CC_LE:
Edgar E. Iglesiasb2565c62010-07-24 21:51:51 +02001179 tcg_gen_setcond_tl(TCG_COND_LE, d, a, b);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001180 break;
1181 case CC_GE:
Edgar E. Iglesiasb2565c62010-07-24 21:51:51 +02001182 tcg_gen_setcond_tl(TCG_COND_GE, d, a, b);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001183 break;
1184 case CC_GT:
Edgar E. Iglesiasb2565c62010-07-24 21:51:51 +02001185 tcg_gen_setcond_tl(TCG_COND_GT, d, a, b);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001186 break;
1187 default:
Andreas Färber0063ebd2013-09-03 20:02:48 +02001188 cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001189 break;
1190 }
1191}
1192
1193static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false)
1194{
Richard Henderson42a268c2015-02-13 12:51:55 -08001195 TCGLabel *l1 = gen_new_label();
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001196 /* 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)),
Andreas Färber68cee382012-03-14 01:38:22 +01001217 cpu_env, offsetof(CPUMBState, bimm));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001218 }
1219
Edgar E. Iglesias61204ce2010-07-24 21:24:59 +02001220 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);
Edgar E. Iglesias844bab62011-01-14 12:30:26 +01001224 dc->jmp = JMP_DIRECT_CC;
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001225 dc->jmp_pc = dc->pc + offset;
Edgar E. Iglesias61204ce2010-07-24 21:24:59 +02001226 } else {
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001227 dc->jmp = JMP_INDIRECT;
Edgar E. Iglesias61204ce2010-07-24 21:24:59 +02001228 tcg_gen_movi_tl(env_btarget, dc->pc);
1229 tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
1230 }
Edgar E. Iglesias61204ce2010-07-24 21:24:59 +02001231 eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001232}
1233
1234static void dec_br(DisasContext *dc)
1235{
Edgar E. Iglesias9f6113c2012-01-10 10:33:37 +01001236 unsigned int dslot, link, abs, mbar;
Andreas Färber0063ebd2013-09-03 20:02:48 +02001237 int mem_index = cpu_mmu_index(&dc->cpu->env);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001238
1239 dslot = dc->ir & (1 << 20);
1240 abs = dc->ir & (1 << 19);
1241 link = dc->ir & (1 << 18);
Edgar E. Iglesias9f6113c2012-01-10 10:33:37 +01001242
1243 /* Memory barrier. */
1244 mbar = (dc->ir >> 16) & 31;
1245 if (mbar == 2 && dc->imm == 4) {
Edgar E. Iglesias5d45de92013-03-28 22:59:03 +01001246 /* 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 }
Edgar E. Iglesias9f6113c2012-01-10 10:33:37 +01001263 LOG_DIS("mbar %d\n", dc->rd);
1264 /* Break the TB. */
1265 dc->cpustate_changed = 1;
1266 return;
1267 }
1268
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001269 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)),
Andreas Färber68cee382012-03-14 01:38:22 +01001279 cpu_env, offsetof(CPUMBState, bimm));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001280 }
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)));
Edgar E. Iglesiasff21f702010-02-20 14:04:01 +01001288 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 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001301 } else {
Edgar E. Iglesias61204ce2010-07-24 21:24:59 +02001302 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 {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001306 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)));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001309 }
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;
Andreas Färber0063ebd2013-09-03 20:02:48 +02001369 int mem_index = cpu_mmu_index(&dc->cpu->env);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001370
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)),
Andreas Färber68cee382012-03-14 01:38:22 +01001378 cpu_env, offsetof(CPUMBState, bimm));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001379
1380 if (i_bit) {
1381 LOG_DIS("rtid ir=%x\n", dc->ir);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001382 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 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001387 dc->tb_flags |= DRTI_FLAG;
1388 } else if (b_bit) {
1389 LOG_DIS("rtbd ir=%x\n", dc->ir);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001390 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 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001395 dc->tb_flags |= DRTB_FLAG;
1396 } else if (e_bit) {
1397 LOG_DIS("rted ir=%x\n", dc->ir);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001398 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 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001403 dc->tb_flags |= DRTE_FLAG;
1404 } else
1405 LOG_DIS("rts ir=%x\n", dc->ir);
1406
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001407 dc->jmp = JMP_INDIRECT;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001408 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
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001412static int dec_check_fpuv2(DisasContext *dc)
1413{
1414 int r;
1415
Andreas Färber0063ebd2013-09-03 20:02:48 +02001416 r = dc->cpu->env.pvr.regs[2] & PVR2_USE_FPU2_MASK;
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001417
1418 if (!r && (dc->tb_flags & MSR_EE_FLAG)) {
1419 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_FPU);
1420 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1421 }
1422 return r;
1423}
1424
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001425static void dec_fpu(DisasContext *dc)
1426{
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001427 unsigned int fpu_insn;
1428
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001429 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +02001430 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
1431 && !((dc->cpu->env.pvr.regs[2] & PVR2_USE_FPU_MASK))) {
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001432 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001433 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1434 return;
1435 }
1436
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001437 fpu_insn = (dc->ir >> 7) & 7;
1438
1439 switch (fpu_insn) {
1440 case 0:
Blue Swirl64254eb2012-09-02 08:39:22 +00001441 gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1442 cpu_R[dc->rb]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001443 break;
1444
1445 case 1:
Blue Swirl64254eb2012-09-02 08:39:22 +00001446 gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1447 cpu_R[dc->rb]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001448 break;
1449
1450 case 2:
Blue Swirl64254eb2012-09-02 08:39:22 +00001451 gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1452 cpu_R[dc->rb]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001453 break;
1454
1455 case 3:
Blue Swirl64254eb2012-09-02 08:39:22 +00001456 gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra],
1457 cpu_R[dc->rb]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001458 break;
1459
1460 case 4:
1461 switch ((dc->ir >> 4) & 7) {
1462 case 0:
Blue Swirl64254eb2012-09-02 08:39:22 +00001463 gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001464 cpu_R[dc->ra], cpu_R[dc->rb]);
1465 break;
1466 case 1:
Blue Swirl64254eb2012-09-02 08:39:22 +00001467 gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001468 cpu_R[dc->ra], cpu_R[dc->rb]);
1469 break;
1470 case 2:
Blue Swirl64254eb2012-09-02 08:39:22 +00001471 gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001472 cpu_R[dc->ra], cpu_R[dc->rb]);
1473 break;
1474 case 3:
Blue Swirl64254eb2012-09-02 08:39:22 +00001475 gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001476 cpu_R[dc->ra], cpu_R[dc->rb]);
1477 break;
1478 case 4:
Blue Swirl64254eb2012-09-02 08:39:22 +00001479 gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001480 cpu_R[dc->ra], cpu_R[dc->rb]);
1481 break;
1482 case 5:
Blue Swirl64254eb2012-09-02 08:39:22 +00001483 gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001484 cpu_R[dc->ra], cpu_R[dc->rb]);
1485 break;
1486 case 6:
Blue Swirl64254eb2012-09-02 08:39:22 +00001487 gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env,
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001488 cpu_R[dc->ra], cpu_R[dc->rb]);
1489 break;
1490 default:
Blue Swirl71547a32012-06-03 17:06:07 +00001491 qemu_log_mask(LOG_UNIMP,
1492 "unimplemented fcmp fpu_insn=%x pc=%x"
1493 " opc=%x\n",
1494 fpu_insn, dc->pc, dc->opcode);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001495 dc->abort_at_next_insn = 1;
1496 break;
1497 }
1498 break;
1499
1500 case 5:
1501 if (!dec_check_fpuv2(dc)) {
1502 return;
1503 }
Blue Swirl64254eb2012-09-02 08:39:22 +00001504 gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001505 break;
1506
1507 case 6:
1508 if (!dec_check_fpuv2(dc)) {
1509 return;
1510 }
Blue Swirl64254eb2012-09-02 08:39:22 +00001511 gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001512 break;
1513
1514 case 7:
1515 if (!dec_check_fpuv2(dc)) {
1516 return;
1517 }
Blue Swirl64254eb2012-09-02 08:39:22 +00001518 gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001519 break;
1520
1521 default:
Blue Swirl71547a32012-06-03 17:06:07 +00001522 qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x"
1523 " opc=%x\n",
1524 fpu_insn, dc->pc, dc->opcode);
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001525 dc->abort_at_next_insn = 1;
1526 break;
1527 }
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001528}
1529
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001530static void dec_null(DisasContext *dc)
1531{
Edgar E. Iglesias02b33592009-09-11 10:38:31 +02001532 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +02001533 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)) {
Edgar E. Iglesias02b33592009-09-11 10:38:31 +02001534 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1535 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1536 return;
1537 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001538 qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode);
1539 dc->abort_at_next_insn = 1;
1540}
1541
Edgar E. Iglesias6d76d232011-04-12 00:48:33 +02001542/* Insns connected to FSL or AXI stream attached devices. */
1543static void dec_stream(DisasContext *dc)
1544{
Andreas Färber0063ebd2013-09-03 20:02:48 +02001545 int mem_index = cpu_mmu_index(&dc->cpu->env);
Edgar E. Iglesias6d76d232011-04-12 00:48:33 +02001546 TCGv_i32 t_id, t_ctrl;
1547 int ctrl;
1548
1549 LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put",
1550 dc->type_b ? "" : "d", dc->imm);
1551
1552 if ((dc->tb_flags & MSR_EE_FLAG) && (mem_index == MMU_USER_IDX)) {
1553 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
1554 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1555 return;
1556 }
1557
1558 t_id = tcg_temp_new();
1559 if (dc->type_b) {
1560 tcg_gen_movi_tl(t_id, dc->imm & 0xf);
1561 ctrl = dc->imm >> 10;
1562 } else {
1563 tcg_gen_andi_tl(t_id, cpu_R[dc->rb], 0xf);
1564 ctrl = dc->imm >> 5;
1565 }
1566
1567 t_ctrl = tcg_const_tl(ctrl);
1568
1569 if (dc->rd == 0) {
1570 gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1571 } else {
1572 gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1573 }
1574 tcg_temp_free(t_id);
1575 tcg_temp_free(t_ctrl);
1576}
1577
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001578static struct decoder_info {
1579 struct {
1580 uint32_t bits;
1581 uint32_t mask;
1582 };
1583 void (*dec)(DisasContext *dc);
1584} decinfo[] = {
1585 {DEC_ADD, dec_add},
1586 {DEC_SUB, dec_sub},
1587 {DEC_AND, dec_and},
1588 {DEC_XOR, dec_xor},
1589 {DEC_OR, dec_or},
1590 {DEC_BIT, dec_bit},
1591 {DEC_BARREL, dec_barrel},
1592 {DEC_LD, dec_load},
1593 {DEC_ST, dec_store},
1594 {DEC_IMM, dec_imm},
1595 {DEC_BR, dec_br},
1596 {DEC_BCC, dec_bcc},
1597 {DEC_RTS, dec_rts},
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001598 {DEC_FPU, dec_fpu},
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001599 {DEC_MUL, dec_mul},
1600 {DEC_DIV, dec_div},
1601 {DEC_MSR, dec_msr},
Edgar E. Iglesias6d76d232011-04-12 00:48:33 +02001602 {DEC_STREAM, dec_stream},
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001603 {{0, 0}, dec_null}
1604};
1605
Blue Swirl64254eb2012-09-02 08:39:22 +00001606static inline void decode(DisasContext *dc, uint32_t ir)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001607{
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001608 int i;
1609
Richard Hendersonfdefe512012-09-24 14:55:47 -07001610 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001611 tcg_gen_debug_insn_start(dc->pc);
Richard Hendersonfdefe512012-09-24 14:55:47 -07001612 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001613
Blue Swirl64254eb2012-09-02 08:39:22 +00001614 dc->ir = ir;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001615 LOG_DIS("%8.8x\t", dc->ir);
1616
1617 if (dc->ir)
1618 dc->nr_nops = 0;
1619 else {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001620 if ((dc->tb_flags & MSR_EE_FLAG)
Andreas Färber0063ebd2013-09-03 20:02:48 +02001621 && (dc->cpu->env.pvr.regs[2] & PVR2_ILL_OPCODE_EXC_MASK)
1622 && (dc->cpu->env.pvr.regs[2] & PVR2_OPCODE_0x0_ILL_MASK)) {
Edgar E. Iglesias1567a002009-09-03 11:12:30 +02001623 tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_ILLEGAL_OP);
1624 t_gen_raise_exception(dc, EXCP_HW_EXCP);
1625 return;
1626 }
1627
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001628 LOG_DIS("nr_nops=%d\t", dc->nr_nops);
1629 dc->nr_nops++;
Andreas Färbera47dddd2013-09-03 17:38:47 +02001630 if (dc->nr_nops > 4) {
Andreas Färber0063ebd2013-09-03 20:02:48 +02001631 cpu_abort(CPU(dc->cpu), "fetching nop sequence\n");
Andreas Färbera47dddd2013-09-03 17:38:47 +02001632 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001633 }
1634 /* bit 2 seems to indicate insn type. */
1635 dc->type_b = ir & (1 << 29);
1636
1637 dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1638 dc->rd = EXTRACT_FIELD(ir, 21, 25);
1639 dc->ra = EXTRACT_FIELD(ir, 16, 20);
1640 dc->rb = EXTRACT_FIELD(ir, 11, 15);
1641 dc->imm = EXTRACT_FIELD(ir, 0, 15);
1642
1643 /* Large switch for all insns. */
1644 for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1645 if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1646 decinfo[i].dec(dc);
1647 break;
1648 }
1649 }
1650}
1651
Andreas Färber68cee382012-03-14 01:38:22 +01001652static void check_breakpoint(CPUMBState *env, DisasContext *dc)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001653{
Andreas Färberf0c3c502013-08-26 21:22:53 +02001654 CPUState *cs = CPU(mb_env_get_cpu(env));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001655 CPUBreakpoint *bp;
1656
Andreas Färberf0c3c502013-08-26 21:22:53 +02001657 if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
1658 QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001659 if (bp->pc == dc->pc) {
1660 t_gen_raise_exception(dc, EXCP_DEBUG);
1661 dc->is_jmp = DISAS_UPDATE;
1662 }
1663 }
1664 }
1665}
1666
1667/* generate intermediate code for basic block 'tb'. */
Andreas Färberfd327f42013-07-02 20:03:00 +02001668static inline void
Andreas Färber4a274212013-06-21 22:14:44 +02001669gen_intermediate_code_internal(MicroBlazeCPU *cpu, TranslationBlock *tb,
1670 bool search_pc)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001671{
Andreas Färbered2803d2013-06-21 20:20:45 +02001672 CPUState *cs = CPU(cpu);
Andreas Färber4a274212013-06-21 22:14:44 +02001673 CPUMBState *env = &cpu->env;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001674 uint32_t pc_start;
1675 int j, lj;
1676 struct DisasContext ctx;
1677 struct DisasContext *dc = &ctx;
1678 uint32_t next_page_start, org_flags;
1679 target_ulong npc;
1680 int num_insns;
1681 int max_insns;
1682
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001683 pc_start = tb->pc;
Andreas Färber0063ebd2013-09-03 20:02:48 +02001684 dc->cpu = cpu;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001685 dc->tb = tb;
1686 org_flags = dc->synced_flags = dc->tb_flags = tb->flags;
1687
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001688 dc->is_jmp = DISAS_NEXT;
1689 dc->jmp = 0;
1690 dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001691 if (dc->delayed_branch) {
1692 dc->jmp = JMP_INDIRECT;
1693 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001694 dc->pc = pc_start;
Andreas Färbered2803d2013-06-21 20:20:45 +02001695 dc->singlestep_enabled = cs->singlestep_enabled;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001696 dc->cpustate_changed = 0;
1697 dc->abort_at_next_insn = 0;
1698 dc->nr_nops = 0;
1699
Andreas Färbera47dddd2013-09-03 17:38:47 +02001700 if (pc_start & 3) {
1701 cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start);
1702 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001703
1704 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1705#if !SIM_COMPAT
1706 qemu_log("--------------\n");
Andreas Färbera0762852013-06-16 07:28:50 +02001707 log_cpu_state(CPU(cpu), 0);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001708#endif
1709 }
1710
1711 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
1712 lj = -1;
1713 num_insns = 0;
1714 max_insns = tb->cflags & CF_COUNT_MASK;
1715 if (max_insns == 0)
1716 max_insns = CF_COUNT_MASK;
1717
Paolo Bonzinicd42d5b2014-11-26 13:40:05 +03001718 gen_tb_start(tb);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001719 do
1720 {
1721#if SIM_COMPAT
1722 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1723 tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc);
1724 gen_helper_debug();
1725 }
1726#endif
1727 check_breakpoint(env, dc);
1728
1729 if (search_pc) {
Richard Hendersonfe700ad2014-03-30 15:36:56 -07001730 j = tcg_op_buf_count();
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001731 if (lj < j) {
1732 lj++;
1733 while (lj < j)
Evgeny Voevodinab1103d2012-11-21 11:43:06 +04001734 tcg_ctx.gen_opc_instr_start[lj++] = 0;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001735 }
Evgeny Voevodin25983ca2012-11-21 11:43:04 +04001736 tcg_ctx.gen_opc_pc[lj] = dc->pc;
Evgeny Voevodinab1103d2012-11-21 11:43:06 +04001737 tcg_ctx.gen_opc_instr_start[lj] = 1;
Evgeny Voevodinc9c99c22012-11-21 11:43:05 +04001738 tcg_ctx.gen_opc_icount[lj] = num_insns;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001739 }
1740
1741 /* Pretty disas. */
1742 LOG_DIS("%8.8x:\t", dc->pc);
1743
1744 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
1745 gen_io_start();
1746
1747 dc->clear_imm = 1;
Blue Swirl64254eb2012-09-02 08:39:22 +00001748 decode(dc, cpu_ldl_code(env, dc->pc));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001749 if (dc->clear_imm)
1750 dc->tb_flags &= ~IMM_FLAG;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001751 dc->pc += 4;
1752 num_insns++;
1753
1754 if (dc->delayed_branch) {
1755 dc->delayed_branch--;
1756 if (!dc->delayed_branch) {
1757 if (dc->tb_flags & DRTI_FLAG)
1758 do_rti(dc);
1759 if (dc->tb_flags & DRTB_FLAG)
1760 do_rtb(dc);
1761 if (dc->tb_flags & DRTE_FLAG)
1762 do_rte(dc);
1763 /* Clear the delay slot flag. */
1764 dc->tb_flags &= ~D_FLAG;
1765 /* If it is a direct jump, try direct chaining. */
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001766 if (dc->jmp == JMP_INDIRECT) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001767 eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
1768 dc->is_jmp = DISAS_JUMP;
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001769 } else if (dc->jmp == JMP_DIRECT) {
Edgar E. Iglesias844bab62011-01-14 12:30:26 +01001770 t_sync_flags(dc);
1771 gen_goto_tb(dc, 0, dc->jmp_pc);
1772 dc->is_jmp = DISAS_TB_JUMP;
1773 } else if (dc->jmp == JMP_DIRECT_CC) {
Richard Henderson42a268c2015-02-13 12:51:55 -08001774 TCGLabel *l1 = gen_new_label();
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001775 t_sync_flags(dc);
Edgar E. Iglesias23979dc2011-01-05 02:21:19 +01001776 /* Conditional jmp. */
1777 tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
1778 gen_goto_tb(dc, 1, dc->pc);
1779 gen_set_label(l1);
1780 gen_goto_tb(dc, 0, dc->jmp_pc);
1781
1782 dc->is_jmp = DISAS_TB_JUMP;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001783 }
1784 break;
1785 }
1786 }
Andreas Färbered2803d2013-06-21 20:20:45 +02001787 if (cs->singlestep_enabled) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001788 break;
Andreas Färbered2803d2013-06-21 20:20:45 +02001789 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001790 } while (!dc->is_jmp && !dc->cpustate_changed
Richard Hendersonfe700ad2014-03-30 15:36:56 -07001791 && !tcg_op_buf_full()
1792 && !singlestep
1793 && (dc->pc < next_page_start)
1794 && num_insns < max_insns);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001795
1796 npc = dc->pc;
Edgar E. Iglesias844bab62011-01-14 12:30:26 +01001797 if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001798 if (dc->tb_flags & D_FLAG) {
1799 dc->is_jmp = DISAS_UPDATE;
1800 tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1801 sync_jmpstate(dc);
1802 } else
1803 npc = dc->jmp_pc;
1804 }
1805
1806 if (tb->cflags & CF_LAST_IO)
1807 gen_io_end();
1808 /* Force an update if the per-tb cpu state has changed. */
1809 if (dc->is_jmp == DISAS_NEXT
1810 && (dc->cpustate_changed || org_flags != dc->tb_flags)) {
1811 dc->is_jmp = DISAS_UPDATE;
1812 tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
1813 }
1814 t_sync_flags(dc);
1815
Andreas Färbered2803d2013-06-21 20:20:45 +02001816 if (unlikely(cs->singlestep_enabled)) {
Edgar E. Iglesias6c5f7382011-02-10 00:46:09 +01001817 TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1818
1819 if (dc->is_jmp != DISAS_JUMP) {
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001820 tcg_gen_movi_tl(cpu_SR[SR_PC], npc);
Edgar E. Iglesias6c5f7382011-02-10 00:46:09 +01001821 }
Blue Swirl64254eb2012-09-02 08:39:22 +00001822 gen_helper_raise_exception(cpu_env, tmp);
Edgar E. Iglesias6c5f7382011-02-10 00:46:09 +01001823 tcg_temp_free_i32(tmp);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001824 } else {
1825 switch(dc->is_jmp) {
1826 case DISAS_NEXT:
1827 gen_goto_tb(dc, 1, npc);
1828 break;
1829 default:
1830 case DISAS_JUMP:
1831 case DISAS_UPDATE:
1832 /* indicate that the hash table must be used
1833 to find the next TB */
1834 tcg_gen_exit_tb(0);
1835 break;
1836 case DISAS_TB_JUMP:
1837 /* nothing more to generate */
1838 break;
1839 }
1840 }
Peter Maydell806f3522013-02-22 18:10:05 +00001841 gen_tb_end(tb, num_insns);
Richard Henderson0a7df5d2014-03-30 14:50:30 -07001842
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001843 if (search_pc) {
Richard Hendersonfe700ad2014-03-30 15:36:56 -07001844 j = tcg_op_buf_count();
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001845 lj++;
1846 while (lj <= j)
Evgeny Voevodinab1103d2012-11-21 11:43:06 +04001847 tcg_ctx.gen_opc_instr_start[lj++] = 0;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001848 } else {
1849 tb->size = dc->pc - pc_start;
1850 tb->icount = num_insns;
1851 }
1852
1853#ifdef DEBUG_DISAS
1854#if !SIM_COMPAT
1855 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1856 qemu_log("\n");
1857#if DISAS_GNU
Blue Swirlf4359b92012-09-08 12:40:00 +00001858 log_target_disas(env, pc_start, dc->pc - pc_start, 0);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001859#endif
Richard Hendersonfe700ad2014-03-30 15:36:56 -07001860 qemu_log("\nisize=%d osize=%d\n",
1861 dc->pc - pc_start, tcg_op_buf_count());
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001862 }
1863#endif
1864#endif
1865 assert(!dc->abort_at_next_insn);
1866}
1867
Andreas Färber68cee382012-03-14 01:38:22 +01001868void gen_intermediate_code (CPUMBState *env, struct TranslationBlock *tb)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001869{
Andreas Färber4a274212013-06-21 22:14:44 +02001870 gen_intermediate_code_internal(mb_env_get_cpu(env), tb, false);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001871}
1872
Andreas Färber68cee382012-03-14 01:38:22 +01001873void gen_intermediate_code_pc (CPUMBState *env, struct TranslationBlock *tb)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001874{
Andreas Färber4a274212013-06-21 22:14:44 +02001875 gen_intermediate_code_internal(mb_env_get_cpu(env), tb, true);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001876}
1877
Andreas Färber878096e2013-05-27 01:33:50 +02001878void mb_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
1879 int flags)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001880{
Andreas Färber878096e2013-05-27 01:33:50 +02001881 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1882 CPUMBState *env = &cpu->env;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001883 int i;
1884
1885 if (!env || !f)
1886 return;
1887
1888 cpu_fprintf(f, "IN: PC=%x %s\n",
1889 env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC]));
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001890 cpu_fprintf(f, "rmsr=%x resr=%x rear=%x debug=%x imm=%x iflags=%x fsr=%x\n",
Michal Simek4c24aa02009-12-07 14:12:49 +01001891 env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
Edgar E. Iglesias97694c52010-09-09 10:20:17 +02001892 env->debug, env->imm, env->iflags, env->sregs[SR_FSR]);
Edgar E. Iglesias17c52a42009-12-16 12:52:56 +01001893 cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001894 env->btaken, env->btarget,
1895 (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
Edgar E. Iglesias17c52a42009-12-16 12:52:56 +01001896 (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
1897 (env->sregs[SR_MSR] & MSR_EIP),
1898 (env->sregs[SR_MSR] & MSR_IE));
1899
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001900 for (i = 0; i < 32; i++) {
1901 cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1902 if ((i + 1) % 4 == 0)
1903 cpu_fprintf(f, "\n");
1904 }
1905 cpu_fprintf(f, "\n\n");
1906}
1907
Andreas Färberb33ab1f2012-05-05 12:14:03 +02001908MicroBlazeCPU *cpu_mb_init(const char *cpu_model)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001909{
Andreas Färberb77f98c2012-04-12 02:17:53 +02001910 MicroBlazeCPU *cpu;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001911
Andreas Färberb77f98c2012-04-12 02:17:53 +02001912 cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001913
Andreas Färber746b03b2013-01-05 15:27:31 +01001914 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001915
Andreas Färbercd0c24f2013-01-20 01:10:52 +01001916 return cpu;
1917}
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001918
Andreas Färbercd0c24f2013-01-20 01:10:52 +01001919void mb_tcg_init(void)
1920{
1921 int i;
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001922
1923 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
1924
1925 env_debug = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001926 offsetof(CPUMBState, debug),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001927 "debug0");
1928 env_iflags = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001929 offsetof(CPUMBState, iflags),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001930 "iflags");
1931 env_imm = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001932 offsetof(CPUMBState, imm),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001933 "imm");
1934 env_btarget = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001935 offsetof(CPUMBState, btarget),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001936 "btarget");
1937 env_btaken = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001938 offsetof(CPUMBState, btaken),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001939 "btaken");
Edgar E. Iglesias4a536272013-10-23 16:44:08 +02001940 env_res_addr = tcg_global_mem_new(TCG_AREG0,
1941 offsetof(CPUMBState, res_addr),
1942 "res_addr");
Edgar E. Iglesias11a76212013-10-23 16:54:31 +02001943 env_res_val = tcg_global_mem_new(TCG_AREG0,
1944 offsetof(CPUMBState, res_val),
1945 "res_val");
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001946 for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
1947 cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001948 offsetof(CPUMBState, regs[i]),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001949 regnames[i]);
1950 }
1951 for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) {
1952 cpu_SR[i] = tcg_global_mem_new(TCG_AREG0,
Andreas Färber68cee382012-03-14 01:38:22 +01001953 offsetof(CPUMBState, sregs[i]),
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001954 special_regnames[i]);
1955 }
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001956}
1957
Andreas Färber68cee382012-03-14 01:38:22 +01001958void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos)
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001959{
Evgeny Voevodin25983ca2012-11-21 11:43:04 +04001960 env->sregs[SR_PC] = tcg_ctx.gen_opc_pc[pc_pos];
Edgar E. Iglesias4acb54b2009-05-20 19:37:39 +02001961}