static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, int r2 , int32_t constant , int32_t offset) { TCGv temp, temp2; int n; switch (opc) { /* SB-format jumps */ case OPC1_16_SB_J: case OPC1_32_B_J: gen_goto_tb(ctx, 0, ctx->pc + offset * 2); break; case OPC1_32_B_CALL: case OPC1_16_SB_CALL: gen_helper_1arg(call, ctx->next_pc); gen_goto_tb(ctx, 0, ctx->pc + offset * 2); break; case OPC1_16_SB_JZ: gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[15], 0, offset); break; case OPC1_16_SB_JNZ: gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[15], 0, offset); break; /* SBC-format jumps */ case OPC1_16_SBC_JEQ: gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[15], constant, offset); break; case OPC1_16_SBC_JNE: gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[15], constant, offset); break; /* SBRN-format jumps */ case OPC1_16_SBRN_JZ_T: temp = tcg_temp_new(); tcg_gen_andi_tl(temp, cpu_gpr_d[15], 0x1u << constant); gen_branch_condi(ctx, TCG_COND_EQ, temp, 0, offset); tcg_temp_free(temp); break; case OPC1_16_SBRN_JNZ_T: temp = tcg_temp_new(); tcg_gen_andi_tl(temp, cpu_gpr_d[15], 0x1u << constant); gen_branch_condi(ctx, TCG_COND_NE, temp, 0, offset); tcg_temp_free(temp); break; /* SBR-format jumps */ case OPC1_16_SBR_JEQ: gen_branch_cond(ctx, TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[15], offset); break; case OPC1_16_SBR_JNE: gen_branch_cond(ctx, TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[15], offset); break; case OPC1_16_SBR_JNZ: gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[r1], 0, offset); break; case OPC1_16_SBR_JNZ_A: gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_a[r1], 0, offset); break; case OPC1_16_SBR_JGEZ: gen_branch_condi(ctx, TCG_COND_GE, cpu_gpr_d[r1], 0, offset); break; case OPC1_16_SBR_JGTZ: gen_branch_condi(ctx, TCG_COND_GT, cpu_gpr_d[r1], 0, offset); break; case OPC1_16_SBR_JLEZ: gen_branch_condi(ctx, TCG_COND_LE, cpu_gpr_d[r1], 0, offset); break; case OPC1_16_SBR_JLTZ: gen_branch_condi(ctx, TCG_COND_LT, cpu_gpr_d[r1], 0, offset); break; case OPC1_16_SBR_JZ: gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[r1], 0, offset); break; case OPC1_16_SBR_JZ_A: gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_a[r1], 0, offset); break; case OPC1_16_SBR_LOOP: gen_loop(ctx, r1, offset * 2 - 32); break; /* SR-format jumps */ case OPC1_16_SR_JI: tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], 0xfffffffe); tcg_gen_exit_tb(0); break; case OPC2_32_SYS_RET: case OPC2_16_SR_RET: gen_helper_ret(cpu_env); tcg_gen_exit_tb(0); break; /* B-format */ case OPC1_32_B_CALLA: gen_helper_1arg(call, ctx->next_pc); gen_goto_tb(ctx, 0, EA_B_ABSOLUT(offset)); break; case OPC1_32_B_JLA: tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc); /* fall through */ case OPC1_32_B_JA: gen_goto_tb(ctx, 0, EA_B_ABSOLUT(offset)); break; case OPC1_32_B_JL: tcg_gen_movi_tl(cpu_gpr_a[11], ctx->next_pc); gen_goto_tb(ctx, 0, ctx->pc + offset * 2); break; /* BOL format */ case OPCM_32_BRC_EQ_NEQ: if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRC_JEQ) { gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_d[r1], constant, offset); } else { gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_d[r1], constant, offset); } break; case OPCM_32_BRC_GE: if (MASK_OP_BRC_OP2(ctx->opcode) == OP2_32_BRC_JGE) { gen_branch_condi(ctx, TCG_COND_GE, cpu_gpr_d[r1], constant, offset); } else { constant = MASK_OP_BRC_CONST4(ctx->opcode); gen_branch_condi(ctx, TCG_COND_GEU, cpu_gpr_d[r1], constant, offset); } break; case OPCM_32_BRC_JLT: if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRC_JLT) { gen_branch_condi(ctx, TCG_COND_LT, cpu_gpr_d[r1], constant, offset); } else { constant = MASK_OP_BRC_CONST4(ctx->opcode); gen_branch_condi(ctx, TCG_COND_LTU, cpu_gpr_d[r1], constant, offset); } break; case OPCM_32_BRC_JNE: temp = tcg_temp_new(); if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRC_JNED) { tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); /* subi is unconditional */ tcg_gen_subi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); gen_branch_condi(ctx, TCG_COND_NE, temp, constant, offset); } else { tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); /* addi is unconditional */ tcg_gen_addi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); gen_branch_condi(ctx, TCG_COND_NE, temp, constant, offset); } tcg_temp_free(temp); break; /* BRN format */ case OPCM_32_BRN_JTT: n = MASK_OP_BRN_N(ctx->opcode); temp = tcg_temp_new(); tcg_gen_andi_tl(temp, cpu_gpr_d[r1], (1 << n)); if (MASK_OP_BRN_OP2(ctx->opcode) == OPC2_32_BRN_JNZ_T) { gen_branch_condi(ctx, TCG_COND_NE, temp, 0, offset); } else { gen_branch_condi(ctx, TCG_COND_EQ, temp, 0, offset); } tcg_temp_free(temp); break; /* BRR Format */ case OPCM_32_BRR_EQ_NEQ: if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JEQ) { gen_branch_cond(ctx, TCG_COND_EQ, cpu_gpr_d[r1], cpu_gpr_d[r2], offset); } else { gen_branch_cond(ctx, TCG_COND_NE, cpu_gpr_d[r1], cpu_gpr_d[r2], offset); } break; case OPCM_32_BRR_ADDR_EQ_NEQ: if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JEQ_A) { gen_branch_cond(ctx, TCG_COND_EQ, cpu_gpr_a[r1], cpu_gpr_a[r2], offset); } else { gen_branch_cond(ctx, TCG_COND_NE, cpu_gpr_a[r1], cpu_gpr_a[r2], offset); } break; case OPCM_32_BRR_GE: if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JGE) { gen_branch_cond(ctx, TCG_COND_GE, cpu_gpr_d[r1], cpu_gpr_d[r2], offset); } else { gen_branch_cond(ctx, TCG_COND_GEU, cpu_gpr_d[r1], cpu_gpr_d[r2], offset); } break; case OPCM_32_BRR_JLT: if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JLT) { gen_branch_cond(ctx, TCG_COND_LT, cpu_gpr_d[r1], cpu_gpr_d[r2], offset); } else { gen_branch_cond(ctx, TCG_COND_LTU, cpu_gpr_d[r1], cpu_gpr_d[r2], offset); } break; case OPCM_32_BRR_LOOP: if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_LOOP) { gen_loop(ctx, r1, offset * 2); } else { /* OPC2_32_BRR_LOOPU */ gen_goto_tb(ctx, 0, ctx->pc + offset * 2); } break; case OPCM_32_BRR_JNE: temp = tcg_temp_new(); temp2 = tcg_temp_new(); if (MASK_OP_BRC_OP2(ctx->opcode) == OPC2_32_BRR_JNED) { tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); /* also save r2, in case of r1 == r2, so r2 is not decremented */ tcg_gen_mov_tl(temp2, cpu_gpr_d[r2]); /* subi is unconditional */ tcg_gen_subi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); gen_branch_cond(ctx, TCG_COND_NE, temp, temp2, offset); } else { tcg_gen_mov_tl(temp, cpu_gpr_d[r1]); /* also save r2, in case of r1 == r2, so r2 is not decremented */ tcg_gen_mov_tl(temp2, cpu_gpr_d[r2]); /* addi is unconditional */ tcg_gen_addi_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 1); gen_branch_cond(ctx, TCG_COND_NE, temp, temp2, offset); } tcg_temp_free(temp); tcg_temp_free(temp2); break; case OPCM_32_BRR_JNZ: if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_JNZ_A) { gen_branch_condi(ctx, TCG_COND_NE, cpu_gpr_a[r1], 0, offset); } else { gen_branch_condi(ctx, TCG_COND_EQ, cpu_gpr_a[r1], 0, offset); } break; default: printf("Branch Error at %x\n", ctx->pc); } ctx->bstate = BS_BRANCH; }