&typea0 rd ra
&typea rd ra rb
+&typea_br rd rb
&typeb rd ra imm
+&typeb_br rd imm
# Include any IMM prefix in the value reported.
%extimm 0:s16 !function=typeb_imm
# Officially typea, but with rb==0, which is not used.
@typea0 ...... rd:5 ra:5 ................ &typea0
+# Officially typea, but with ra as opcode.
+@typea_br ...... rd:5 ..... rb:5 ........... &typea_br
+
# Officially typeb, but any immediate extension is unused.
@typeb_bs ...... rd:5 ra:5 ..... ...... imm:5 &typeb
+# Officially typeb, but with ra as opcode.
+@typeb_br ...... rd:5 ..... ................ &typeb_br imm=%extimm
+
# For convenience, extract the two imm_w/imm_s fields, then pack
# them back together as "imm". Doing this makes it easiest to
# match the required zero at bit 5.
andn 100011 ..... ..... ..... 000 0000 0000 @typea
andni 101011 ..... ..... ................ @typeb
+brk 100110 ..... 01100 ..... 000 0000 0000 @typea_br
+brki 101110 ..... 01100 ................ @typeb_br
+
bsrl 010001 ..... ..... ..... 000 0000 0000 @typea
bsra 010001 ..... ..... ..... 010 0000 0000 @typea
bsll 010001 ..... ..... ..... 100 0000 0000 @typea
return true;
}
+static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
+{
+ if (trap_userspace(dc, true)) {
+ return true;
+ }
+ tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
+ if (arg->rd) {
+ tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
+ }
+ tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
+ tcg_gen_movi_tl(cpu_res_addr, -1);
+
+ dc->base.is_jmp = DISAS_UPDATE;
+ return true;
+}
+
+static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
+{
+ uint32_t imm = arg->imm;
+
+ if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
+ return true;
+ }
+ tcg_gen_movi_i32(cpu_pc, imm);
+ if (arg->rd) {
+ tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
+ }
+ tcg_gen_movi_tl(cpu_res_addr, -1);
+
+#ifdef CONFIG_USER_ONLY
+ switch (imm) {
+ case 0x8: /* syscall trap */
+ gen_raise_exception_sync(dc, EXCP_SYSCALL);
+ break;
+ case 0x18: /* debug trap */
+ gen_raise_exception_sync(dc, EXCP_DEBUG);
+ break;
+ default: /* eliminated with trap_userspace check */
+ g_assert_not_reached();
+ }
+#else
+ uint32_t msr_to_set = 0;
+
+ if (imm != 0x18) {
+ msr_to_set |= MSR_BIP;
+ }
+ if (imm == 0x8 || imm == 0x18) {
+ /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
+ msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
+ tcg_gen_andi_i32(cpu_msr, cpu_msr,
+ ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
+ }
+ tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
+ dc->base.is_jmp = DISAS_UPDATE;
+#endif
+
+ return true;
+}
+
static bool trans_zero(DisasContext *dc, arg_zero *arg)
{
/* If opcode_0_illegal, trap. */
static void dec_br(DisasContext *dc)
{
unsigned int dslot, link, abs, mbar;
+ uint32_t add_pc;
dslot = dc->ir & (1 << 20);
abs = dc->ir & (1 << 19);
return;
}
- if (abs && link && !dslot) {
- if (dc->type_b) {
- /* BRKI */
- uint32_t imm = dec_alu_typeb_imm(dc);
- if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
- return;
- }
- } else {
- /* BRK */
- if (trap_userspace(dc, true)) {
- return;
- }
- }
- }
-
if (dslot) {
dec_setup_dslot(dc);
}
tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
}
- if (abs) {
- if (dc->type_b) {
- uint32_t dest = dec_alu_typeb_imm(dc);
-
- dc->jmp = JMP_DIRECT;
- dc->jmp_pc = dest;
- tcg_gen_movi_i32(cpu_btarget, dest);
- if (link && !dslot) {
- switch (dest) {
- case 8:
- case 0x18:
- gen_raise_exception_sync(dc, EXCP_BREAK);
- break;
- case 0:
- gen_raise_exception_sync(dc, EXCP_DEBUG);
- break;
- }
- }
- } else {
- dc->jmp = JMP_INDIRECT;
- tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
- if (link && !dslot) {
- gen_raise_exception_sync(dc, EXCP_BREAK);
- }
- }
- } else if (dc->type_b) {
+ add_pc = abs ? 0 : dc->base.pc_next;
+ if (dc->type_b) {
dc->jmp = JMP_DIRECT;
- dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
+ dc->jmp_pc = add_pc + dec_alu_typeb_imm(dc);
tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
} else {
dc->jmp = JMP_INDIRECT;
- tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
+ tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], add_pc);
}
tcg_gen_movi_i32(cpu_btaken, 1);
}