diff mbox

[v3,08/16] target-or32: Add translation routines

Message ID 1338985632-29597-9-git-send-email-proljc@gmail.com
State New
Headers show

Commit Message

Jia Liu June 6, 2012, 12:27 p.m. UTC
Add OpenRISC translation routines.

Signed-off-by: Jia Liu <proljc@gmail.com>
---
 target-openrisc/translate.c | 1440 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1440 insertions(+)

Comments

Max Filippov June 6, 2012, 4:40 p.m. UTC | #1
Hi Jia,

more comments on remaining issues visible with unaided eye.

On Wed, Jun 6, 2012 at 4:27 PM, Jia Liu <proljc@gmail.com> wrote:
> Add OpenRISC translation routines.
>
> Signed-off-by: Jia Liu <proljc@gmail.com>
> ---

[...]

> +    case 0x0009:
> +        switch (op1) {
> +        case 0x03:   /*l.div*/
> +            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
> +            {
> +                TCGv_i32 sr_ove;
> +                int lab = gen_new_label();
> +                sr_ove = tcg_temp_new();
> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
> +                if (rb == 0) {
> +                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
> +                    gen_exception(dc, EXCP_RANGE);
> +                    gen_set_label(lab);
> +                } else {
> +                    if (ra == 0xffffffff && rb == 0x80000000) {

Cannot do that: ra and rb are register numbers, not the values
contained in these registers.
Hence you need to generate code that will check these combinations of
register values.

> +                        tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
> +                        gen_exception(dc, EXCP_RANGE);
> +                        gen_set_label(lab);
> +                    } else {
> +                        tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
> +                    }
> +                }
> +                tcg_temp_free(sr_ove);
> +            }
> +            break;
> +
> +        default:
> +            gen_illegal_exception(dc);
> +            break;
> +        }
> +        break;
> +
> +    case 0x000a:
> +        switch (op1) {
> +        case 0x03:   /*l.divu*/
> +            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
> +            if (rb == 0) {
> +                TCGv_i32 sr_ove;
> +                int lab = gen_new_label();
> +                sr_ove = tcg_temp_new();
> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
> +                gen_exception(dc, EXCP_RANGE);
> +                gen_set_label(lab);
> +                tcg_temp_free(sr_ove);
> +            } else if (rb != 0) {

'if (rb != 0)' and the following 'else' block are redundant here.

I feel that I repeatedly fail to explain what's wrong with these div/divu
implementations; could you please add testcases for l.div and l.divu
that divide by the register other than r0 that contains 0 value?

> +                tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
> +            } else {
> +                break;
> +            }
> +            break;
> +
> +        default:
> +            gen_illegal_exception(dc);
> +            break;
> +        }
> +        break;
> +
> +    case 0x000b:
> +        switch (op1) {
> +        case 0x03:   /*l.mulu*/
> +            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
> +            if (rb != 0 && ra != 0) {
> +                TCGv result = tcg_temp_new();
> +                TCGv high = tcg_temp_new();
> +                TCGv tra = tcg_temp_new();
> +                TCGv trb = tcg_temp_new();
> +                TCGv_i32 sr_ove = tcg_temp_new();
> +                int lab = gen_new_label();
> +                int lab2 = gen_new_label();
> +                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
> +                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
> +                tcg_gen_mul_tl(result, cpu_R[ra], cpu_R[rb]);

You've calculated tra and trb but haven't uses them here.

> +                tcg_gen_shri_tl(high, result, (sizeof(target_ulong) * 8));

You probably meant result and high to be _i64.

> +                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x0, lab);
> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
> +                gen_exception(dc, EXCP_RANGE);
> +                gen_set_label(lab);
> +                gen_set_label(lab2);

No need to set two labels at one point.

> +                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
> +                tcg_temp_free(result);
> +                tcg_temp_free(high);
> +                tcg_temp_free(sr_ove);
> +                tcg_temp_free(tra);
> +                tcg_temp_free(trb);
> +            } else {
> +                tcg_gen_movi_tl(cpu_R[rd], 0);
> +            }
> +            break;
> +
> +        default:
> +            gen_illegal_exception(dc);
> +            break;
> +        }
> +        break;
> +

[...]

> +    case 0x13:    /*l.maci*/
> +        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
> +        {
> +            TCGv t1 = tcg_temp_new();
> +            TCGv t2 = tcg_temp_new();
> +            TCGv ttmp = tcg_temp_new();   /*  store machi maclo*/
> +            ttmp = tcg_const_tl(tmp);

Leaked previous ttmp temporary.

> +            tcg_gen_mul_tl(t0, cpu_R[ra], ttmp);

What t0?

> +            tcg_gen_ext_i32_i64(t1, t0);
> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
> +            tcg_gen_add_i64(t2, t2, t1);
> +            tcg_gen_trunc_i64_i32(maclo, t2);
> +            tcg_gen_shri_i64(t2, t2, 32);
> +            tcg_gen_trunc_i64_i32(machi, t2);
> +            tcg_temp_free(t0);
> +            tcg_temp_free(t1);
> +            tcg_temp_free(t2);

Leaked ttmp temporary.

> +        }
> +        break;

[...]

> +    case 0x20:   /*l.ld*/
> +        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
> +        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
> +        tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);

Cannot ld64 into _tl register.

[...]

> +    case 0x34:   /*l.sd*/
> +        LOG_DIS("l.sd %d, r%d, r%d, %d\n", I5, ra, rb, I11);
> +        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
> +        tcg_gen_qemu_st64(cpu_R[rb], t0, dc->mem_idx);

Ditto.

[...]

> +static void dec_mac(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
> +{
> +    uint32_t op0;
> +    uint32_t ra, rb;
> +    op0 = field(insn, 0, 4);
> +    ra = field(insn, 16, 5);
> +    rb = field(insn, 11, 5);
> +    TCGv_i64 t0 = tcg_temp_new();
> +    TCGv_i64 t1 = tcg_temp_new();
> +    TCGv_i64 t2 = tcg_temp_new();
> +    switch (op0) {
> +    case 0x0001:   /*l.mac*/
> +        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
> +        {
> +            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
> +            tcg_gen_ext_i32_i64(t1, t0);
> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
> +            tcg_gen_add_i64(t2, t2, t1);
> +            tcg_gen_trunc_i64_i32(maclo, t2);
> +            tcg_gen_shri_i64(t2, t2, 32);
> +            tcg_gen_trunc_i64_i32(machi, t2);
> +            tcg_temp_free(t0);
> +            tcg_temp_free(t1);
> +            tcg_temp_free(t2);

Instead of freeing temporaries repeatedly in some cases (and
leaking them in others) you could free them once after the switch.

> +        }
> +        break;
> +
> +    case 0x0002:   /*l.msb*/
> +        LOG_DIS("l.msb r%d, r%d\n", ra, rb);
> +        {
> +            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
> +            tcg_gen_ext_i32_i64(t1, t0);
> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
> +            tcg_gen_sub_i64(t2, t2, t1);
> +            tcg_gen_trunc_i64_i32(maclo, t2);
> +            tcg_gen_shri_i64(t2, t2, 32);
> +            tcg_gen_trunc_i64_i32(machi, t2);
> +            tcg_temp_free(t0);
> +            tcg_temp_free(t1);
> +            tcg_temp_free(t2);
> +        }
> +        break;
> +
> +    default:
> +        gen_illegal_exception(dc);
> +        break;
> +   }
> +}
Jia Liu June 8, 2012, midnight UTC | #2
Hi Max,

Thank you for your unaided eye look :-)

I've fixed them, and, I think, it will be good if you check them
before I make V4 pacthes.
So, please, use your unaided eye again.

On Thu, Jun 7, 2012 at 12:40 AM, Max Filippov <jcmvbkbc@gmail.com> wrote:
> Hi Jia,
>
> more comments on remaining issues visible with unaided eye.
>
> On Wed, Jun 6, 2012 at 4:27 PM, Jia Liu <proljc@gmail.com> wrote:
>> Add OpenRISC translation routines.
>>
>> Signed-off-by: Jia Liu <proljc@gmail.com>
>> ---
>
> [...]
>
>> +    case 0x0009:
>> +        switch (op1) {
>> +        case 0x03:   /*l.div*/
>> +            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
>> +            {
>> +                TCGv_i32 sr_ove;
>> +                int lab = gen_new_label();
>> +                sr_ove = tcg_temp_new();
>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>> +                if (rb == 0) {
>> +                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>> +                    gen_exception(dc, EXCP_RANGE);
>> +                    gen_set_label(lab);
>> +                } else {
>> +                    if (ra == 0xffffffff && rb == 0x80000000) {
>
> Cannot do that: ra and rb are register numbers, not the values
> contained in these registers.
> Hence you need to generate code that will check these combinations of
> register values.
>

        case 0x03:   /*l.div*/
            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
            {
                int lab0 = gen_new_label();
                int lab1 = gen_new_label();
                int lab2 = gen_new_label();
                TCGv_i32 sr_ove = tcg_temp_new_i32();
                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
                if (rb == 0) {
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
                    gen_exception(dc, EXCP_RANGE);
                    gen_set_label(lab0);
                } else {
                    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb],
                                       0x00000000, lab1);
                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra],
                                       0xffffffff, lab2);
                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
                                       0x80000000, lab2);
                    gen_set_label(lab1);
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
                    gen_exception(dc, EXCP_RANGE);
                    gen_set_label(lab2);
                    tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
                }
                tcg_temp_free_i32(sr_ove);
            }
            break;


is this right?

>> +                        tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>> +                        gen_exception(dc, EXCP_RANGE);
>> +                        gen_set_label(lab);
>> +                    } else {
>> +                        tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>> +                    }
>> +                }
>> +                tcg_temp_free(sr_ove);
>> +            }
>> +            break;
>> +
>> +        default:
>> +            gen_illegal_exception(dc);
>> +            break;
>> +        }
>> +        break;
>> +
>> +    case 0x000a:
>> +        switch (op1) {
>> +        case 0x03:   /*l.divu*/
>> +            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
>> +            if (rb == 0) {
>> +                TCGv_i32 sr_ove;
>> +                int lab = gen_new_label();
>> +                sr_ove = tcg_temp_new();
>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>> +                gen_exception(dc, EXCP_RANGE);
>> +                gen_set_label(lab);
>> +                tcg_temp_free(sr_ove);
>> +            } else if (rb != 0) {
>
> 'if (rb != 0)' and the following 'else' block are redundant here.
>
> I feel that I repeatedly fail to explain what's wrong with these div/divu
> implementations; could you please add testcases for l.div and l.divu
> that divide by the register other than r0 that contains 0 value?
>

and

        case 0x03:   /*l.divu*/
            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
            {
                int lab0 = gen_new_label();
                int lab1 = gen_new_label();
                TCGv_i32 sr_ove = tcg_temp_new();
                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
                if (rb == 0) {
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
                    gen_exception(dc, EXCP_RANGE);
                    gen_set_label(lab0);
                } else {
                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
                                       0x00000000, lab1);
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab1);
                    gen_exception(dc, EXCP_RANGE);
                    gen_set_label(lab1);
                    tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
                }
                tcg_temp_free_i32(sr_ove);
            }
            break;

is this OK?

>> +                tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>> +            } else {
>> +                break;
>> +            }
>> +            break;
>> +
>> +        default:
>> +            gen_illegal_exception(dc);
>> +            break;
>> +        }
>> +        break;
>> +
>> +    case 0x000b:
>> +        switch (op1) {
>> +        case 0x03:   /*l.mulu*/
>> +            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
>> +            if (rb != 0 && ra != 0) {
>> +                TCGv result = tcg_temp_new();
>> +                TCGv high = tcg_temp_new();
>> +                TCGv tra = tcg_temp_new();
>> +                TCGv trb = tcg_temp_new();
>> +                TCGv_i32 sr_ove = tcg_temp_new();
>> +                int lab = gen_new_label();
>> +                int lab2 = gen_new_label();
>> +                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
>> +                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
>> +                tcg_gen_mul_tl(result, cpu_R[ra], cpu_R[rb]);
>
> You've calculated tra and trb but haven't uses them here.
>
>> +                tcg_gen_shri_tl(high, result, (sizeof(target_ulong) * 8));
>
> You probably meant result and high to be _i64.
>
>> +                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x0, lab);
>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
>> +                gen_exception(dc, EXCP_RANGE);
>> +                gen_set_label(lab);
>> +                gen_set_label(lab2);
>
> No need to set two labels at one point.
>

        case 0x03:   /*l.mulu*/
            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
            if (rb != 0 && ra != 0) {
                TCGv_i64 result = tcg_temp_new_i64();
                TCGv_i64 tra = tcg_temp_new_i64();
                TCGv_i64 trb = tcg_temp_new_i64();
                TCGv high = tcg_temp_new();
                TCGv_i32 sr_ove = tcg_temp_new();
                int lab = gen_new_label();
                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
                tcg_gen_mul_i64(result, tra, trb);
                tcg_temp_free(tra);
                tcg_temp_free(trb);
                tcg_gen_shri_i64(high, result, (sizeof(target_ulong) * 8));
                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x00000000, lab);
                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
                gen_exception(dc, EXCP_RANGE);
                gen_set_label(lab);
                tcg_temp_free(high);
                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
                tcg_temp_free(result);
                tcg_temp_free(sr_ove);
            } else {
                tcg_gen_movi_tl(cpu_R[rd], 0);
            }
            break;

is it right this time?

>> +                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
>> +                tcg_temp_free(result);
>> +                tcg_temp_free(high);
>> +                tcg_temp_free(sr_ove);
>> +                tcg_temp_free(tra);
>> +                tcg_temp_free(trb);
>> +            } else {
>> +                tcg_gen_movi_tl(cpu_R[rd], 0);
>> +            }
>> +            break;
>> +
>> +        default:
>> +            gen_illegal_exception(dc);
>> +            break;
>> +        }
>> +        break;
>> +
>
> [...]
>
>> +    case 0x13:    /*l.maci*/
>> +        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
>> +        {
>> +            TCGv t1 = tcg_temp_new();
>> +            TCGv t2 = tcg_temp_new();
>> +            TCGv ttmp = tcg_temp_new();   /*  store machi maclo*/
>> +            ttmp = tcg_const_tl(tmp);
>
> Leaked previous ttmp temporary.
>
>> +            tcg_gen_mul_tl(t0, cpu_R[ra], ttmp);
>
> What t0?
>
>> +            tcg_gen_ext_i32_i64(t1, t0);
>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>> +            tcg_gen_add_i64(t2, t2, t1);
>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>> +            tcg_gen_shri_i64(t2, t2, 32);
>> +            tcg_gen_trunc_i64_i32(machi, t2);
>> +            tcg_temp_free(t0);
>> +            tcg_temp_free(t1);
>> +            tcg_temp_free(t2);
>
> Leaked ttmp temporary.


    case 0x13:    /*l.maci*/
        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
        {
            TCGv t1 = tcg_temp_new();
            TCGv t2 = tcg_temp_new();
            TCGv ttmp = tcg_const_tl(tmp);  /*  store machi maclo*/
            tcg_gen_mul_tl(ttmp, cpu_R[ra], ttmp);
            tcg_gen_ext_i32_i64(t1, ttmp);
            tcg_gen_concat_i32_i64(t2, maclo, machi);
            tcg_gen_add_i64(t2, t2, t1);
            tcg_gen_trunc_i64_i32(maclo, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_i32(machi, t2);
            tcg_temp_free(ttmp);
            tcg_temp_free(t1);
            tcg_temp_free(t2);
        }
        break;


>
>> +        }
>> +        break;
>
> [...]
>
>> +    case 0x20:   /*l.ld*/
>> +        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
>> +        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
>> +        tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
>
> Cannot ld64 into _tl register.
>

    case 0x20:   /*l.ld*/
        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
        {
            check_ob64s(dc);
            TCGv_i64 t0 = tcg_temp_new_i64();
            tcg_gen_addi_i64(t0, cpu_R[ra], sign_extend(I16, 16));
            tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
            tcg_temp_free_i64(t0);
        }
        break;

> [...]
>
>> +    case 0x34:   /*l.sd*/
>> +        LOG_DIS("l.sd %d, r%d, r%d, %d\n", I5, ra, rb, I11);
>> +        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
>> +        tcg_gen_qemu_st64(cpu_R[rb], t0, dc->mem_idx);
>
> Ditto.
>
> [...]
>
>> +static void dec_mac(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
>> +{
>> +    uint32_t op0;
>> +    uint32_t ra, rb;
>> +    op0 = field(insn, 0, 4);
>> +    ra = field(insn, 16, 5);
>> +    rb = field(insn, 11, 5);
>> +    TCGv_i64 t0 = tcg_temp_new();
>> +    TCGv_i64 t1 = tcg_temp_new();
>> +    TCGv_i64 t2 = tcg_temp_new();
>> +    switch (op0) {
>> +    case 0x0001:   /*l.mac*/
>> +        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
>> +        {
>> +            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>> +            tcg_gen_ext_i32_i64(t1, t0);
>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>> +            tcg_gen_add_i64(t2, t2, t1);
>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>> +            tcg_gen_shri_i64(t2, t2, 32);
>> +            tcg_gen_trunc_i64_i32(machi, t2);
>> +            tcg_temp_free(t0);
>> +            tcg_temp_free(t1);
>> +            tcg_temp_free(t2);
>
> Instead of freeing temporaries repeatedly in some cases (and
> leaking them in others) you could free them once after the switch.
>

    case 0x0001:   /*l.mac*/
        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
        {
            TCGv_i64 t0 = tcg_temp_new();
            TCGv_i64 t1 = tcg_temp_new();
            TCGv_i64 t2 = tcg_temp_new();
            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
            tcg_gen_ext_i32_i64(t1, t0);
            tcg_gen_concat_i32_i64(t2, maclo, machi);
            tcg_gen_add_i64(t2, t2, t1);
            tcg_gen_trunc_i64_i32(maclo, t2);
            tcg_gen_shri_i64(t2, t2, 32);
            tcg_gen_trunc_i64_i32(machi, t2);
            tcg_temp_free(t0);
            tcg_temp_free(t1);
            tcg_temp_free(t2);
        }
        break;

I think define use and free them separately make code more clear :-)

>> +        }
>> +        break;
>> +
>> +    case 0x0002:   /*l.msb*/
>> +        LOG_DIS("l.msb r%d, r%d\n", ra, rb);
>> +        {
>> +            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>> +            tcg_gen_ext_i32_i64(t1, t0);
>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>> +            tcg_gen_sub_i64(t2, t2, t1);
>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>> +            tcg_gen_shri_i64(t2, t2, 32);
>> +            tcg_gen_trunc_i64_i32(machi, t2);
>> +            tcg_temp_free(t0);
>> +            tcg_temp_free(t1);
>> +            tcg_temp_free(t2);
>> +        }
>> +        break;
>> +
>> +    default:
>> +        gen_illegal_exception(dc);
>> +        break;
>> +   }
>> +}
>
> --
> Thanks.
> -- Max


Thank you very much, nice man.

Jia.
Richard Henderson June 8, 2012, 12:21 a.m. UTC | #3
On 2012-06-07 17:00, Jia Liu wrote:
>                 TCGv_i32 sr_ove = tcg_temp_new_i32();

You need tcg_temp_local_new_i32 in order to last beyond the branches.

Frankly, it's often easier to handle division and its exceptions via
an out-of-line handler.


r~
Jia Liu June 8, 2012, 2:16 a.m. UTC | #4
Hi Richard,

On Fri, Jun 8, 2012 at 8:21 AM, Richard Henderson <rth@twiddle.net> wrote:
> On 2012-06-07 17:00, Jia Liu wrote:
>>                 TCGv_i32 sr_ove = tcg_temp_new_i32();
>
> You need tcg_temp_local_new_i32 in order to last beyond the branches.
>
> Frankly, it's often easier to handle division and its exceptions via
> an out-of-line handler.
>

Thank you very much, you always teach me new things :-)

And, I've fix them.

>
> r~

Regards,
Jia.
陳韋任 June 8, 2012, 2:58 a.m. UTC | #5
On Thu, Jun 07, 2012 at 05:21:04PM -0700, Richard Henderson wrote:
> On 2012-06-07 17:00, Jia Liu wrote:
> >                 TCGv_i32 sr_ove = tcg_temp_new_i32();
> 
> You need tcg_temp_local_new_i32 in order to last beyond the branches.
> 
> Frankly, it's often easier to handle division and its exceptions via
> an out-of-line handler.
     ^^^^^^^^^^^^^^^^^^^

  I guess you mean helper function?

Regards,
chenwj
Max Filippov June 8, 2012, 12:56 p.m. UTC | #6
Hi Jia.

On Fri, Jun 8, 2012 at 4:00 AM, Jia Liu <proljc@gmail.com> wrote:

[...]

>>> +    case 0x0009:
>>> +        switch (op1) {
>>> +        case 0x03:   /*l.div*/
>>> +            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
>>> +            {
>>> +                TCGv_i32 sr_ove;
>>> +                int lab = gen_new_label();
>>> +                sr_ove = tcg_temp_new();
>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>> +                if (rb == 0) {
>>> +                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>> +                    gen_exception(dc, EXCP_RANGE);
>>> +                    gen_set_label(lab);
>>> +                } else {
>>> +                    if (ra == 0xffffffff && rb == 0x80000000) {
>>
>> Cannot do that: ra and rb are register numbers, not the values
>> contained in these registers.
>> Hence you need to generate code that will check these combinations of
>> register values.
>>
>
>        case 0x03:   /*l.div*/
>            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
>            {
>                int lab0 = gen_new_label();
>                int lab1 = gen_new_label();
>                int lab2 = gen_new_label();
>                TCGv_i32 sr_ove = tcg_temp_new_i32();
>                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>                if (rb == 0) {
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
>                    gen_exception(dc, EXCP_RANGE);
>                    gen_set_label(lab0);
>                } else {
>                    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb],
>                                       0x00000000, lab1);
>                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra],
>                                       0xffffffff, lab2);
>                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
>                                       0x80000000, lab2);
>                    gen_set_label(lab1);
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
>                    gen_exception(dc, EXCP_RANGE);
>                    gen_set_label(lab2);
>                    tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);

You still divide by zero/overflow here in case SR_OVE is not set.
What value goes to the rd register in case of division by 0? Maybe
you should skip the division altogether?

>                }
>                tcg_temp_free_i32(sr_ove);
>            }
>            break;
>
>
> is this right?

Much better now (:

>>> +                        tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>> +                        gen_exception(dc, EXCP_RANGE);
>>> +                        gen_set_label(lab);
>>> +                    } else {
>>> +                        tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>>> +                    }
>>> +                }
>>> +                tcg_temp_free(sr_ove);
>>> +            }
>>> +            break;
>>> +
>>> +        default:
>>> +            gen_illegal_exception(dc);
>>> +            break;
>>> +        }
>>> +        break;
>>> +
>>> +    case 0x000a:
>>> +        switch (op1) {
>>> +        case 0x03:   /*l.divu*/
>>> +            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
>>> +            if (rb == 0) {
>>> +                TCGv_i32 sr_ove;
>>> +                int lab = gen_new_label();
>>> +                sr_ove = tcg_temp_new();
>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>> +                gen_exception(dc, EXCP_RANGE);
>>> +                gen_set_label(lab);
>>> +                tcg_temp_free(sr_ove);
>>> +            } else if (rb != 0) {
>>
>> 'if (rb != 0)' and the following 'else' block are redundant here.
>>
>> I feel that I repeatedly fail to explain what's wrong with these div/divu
>> implementations; could you please add testcases for l.div and l.divu
>> that divide by the register other than r0 that contains 0 value?
>>
>
> and
>
>        case 0x03:   /*l.divu*/
>            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
>            {
>                int lab0 = gen_new_label();
>                int lab1 = gen_new_label();
>                TCGv_i32 sr_ove = tcg_temp_new();
>                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>                if (rb == 0) {
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
>                    gen_exception(dc, EXCP_RANGE);
>                    gen_set_label(lab0);
>                } else {
>                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
>                                       0x00000000, lab1);
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab1);
>                    gen_exception(dc, EXCP_RANGE);
>                    gen_set_label(lab1);
>                    tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);

Ditto.

>                }
>                tcg_temp_free_i32(sr_ove);
>            }
>            break;
>
> is this OK?
>
>>> +                tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>>> +            } else {
>>> +                break;
>>> +            }
>>> +            break;
>>> +
>>> +        default:
>>> +            gen_illegal_exception(dc);
>>> +            break;
>>> +        }
>>> +        break;
>>> +
>>> +    case 0x000b:
>>> +        switch (op1) {
>>> +        case 0x03:   /*l.mulu*/
>>> +            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
>>> +            if (rb != 0 && ra != 0) {
>>> +                TCGv result = tcg_temp_new();
>>> +                TCGv high = tcg_temp_new();
>>> +                TCGv tra = tcg_temp_new();
>>> +                TCGv trb = tcg_temp_new();
>>> +                TCGv_i32 sr_ove = tcg_temp_new();
>>> +                int lab = gen_new_label();
>>> +                int lab2 = gen_new_label();
>>> +                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
>>> +                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
>>> +                tcg_gen_mul_tl(result, cpu_R[ra], cpu_R[rb]);
>>
>> You've calculated tra and trb but haven't uses them here.
>>
>>> +                tcg_gen_shri_tl(high, result, (sizeof(target_ulong) * 8));
>>
>> You probably meant result and high to be _i64.
>>
>>> +                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x0, lab);
>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
>>> +                gen_exception(dc, EXCP_RANGE);
>>> +                gen_set_label(lab);
>>> +                gen_set_label(lab2);
>>
>> No need to set two labels at one point.
>>
>
>        case 0x03:   /*l.mulu*/
>            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
>            if (rb != 0 && ra != 0) {
>                TCGv_i64 result = tcg_temp_new_i64();
>                TCGv_i64 tra = tcg_temp_new_i64();
>                TCGv_i64 trb = tcg_temp_new_i64();
>                TCGv high = tcg_temp_new();
>                TCGv_i32 sr_ove = tcg_temp_new();
>                int lab = gen_new_label();
>                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
>                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
>                tcg_gen_mul_i64(result, tra, trb);
>                tcg_temp_free(tra);
>                tcg_temp_free(trb);
>                tcg_gen_shri_i64(high, result, (sizeof(target_ulong) * 8));

TARGET_LONG_BITS?

>                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x00000000, lab);
>                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);

Not an issue, but you could just tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY | SR_OV);

>                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>                gen_exception(dc, EXCP_RANGE);
>                gen_set_label(lab);
>                tcg_temp_free(high);
>                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
>                tcg_temp_free(result);
>                tcg_temp_free(sr_ove);
>            } else {
>                tcg_gen_movi_tl(cpu_R[rd], 0);
>            }
>            break;
>
> is it right this time?

Looks good to me.

>>> +                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
>>> +                tcg_temp_free(result);
>>> +                tcg_temp_free(high);
>>> +                tcg_temp_free(sr_ove);
>>> +                tcg_temp_free(tra);
>>> +                tcg_temp_free(trb);
>>> +            } else {
>>> +                tcg_gen_movi_tl(cpu_R[rd], 0);
>>> +            }
>>> +            break;
>>> +
>>> +        default:
>>> +            gen_illegal_exception(dc);
>>> +            break;
>>> +        }
>>> +        break;
>>> +
>>
>> [...]
>>
>>> +    case 0x13:    /*l.maci*/
>>> +        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
>>> +        {
>>> +            TCGv t1 = tcg_temp_new();
>>> +            TCGv t2 = tcg_temp_new();
>>> +            TCGv ttmp = tcg_temp_new();   /*  store machi maclo*/
>>> +            ttmp = tcg_const_tl(tmp);
>>
>> Leaked previous ttmp temporary.
>>
>>> +            tcg_gen_mul_tl(t0, cpu_R[ra], ttmp);
>>
>> What t0?
>>
>>> +            tcg_gen_ext_i32_i64(t1, t0);
>>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>>> +            tcg_gen_add_i64(t2, t2, t1);
>>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>>> +            tcg_gen_shri_i64(t2, t2, 32);
>>> +            tcg_gen_trunc_i64_i32(machi, t2);
>>> +            tcg_temp_free(t0);
>>> +            tcg_temp_free(t1);
>>> +            tcg_temp_free(t2);
>>
>> Leaked ttmp temporary.
>
>
>    case 0x13:    /*l.maci*/
>        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
>        {
>            TCGv t1 = tcg_temp_new();
>            TCGv t2 = tcg_temp_new();
>            TCGv ttmp = tcg_const_tl(tmp);  /*  store machi maclo*/
>            tcg_gen_mul_tl(ttmp, cpu_R[ra], ttmp);
>            tcg_gen_ext_i32_i64(t1, ttmp);
>            tcg_gen_concat_i32_i64(t2, maclo, machi);
>            tcg_gen_add_i64(t2, t2, t1);
>            tcg_gen_trunc_i64_i32(maclo, t2);
>            tcg_gen_shri_i64(t2, t2, 32);
>            tcg_gen_trunc_i64_i32(machi, t2);
>            tcg_temp_free(ttmp);
>            tcg_temp_free(t1);
>            tcg_temp_free(t2);
>        }
>        break;
>
>
>>
>>> +        }
>>> +        break;
>>
>> [...]
>>
>>> +    case 0x20:   /*l.ld*/
>>> +        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
>>> +        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
>>> +        tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
>>
>> Cannot ld64 into _tl register.
>>
>
>    case 0x20:   /*l.ld*/
>        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
>        {
>            check_ob64s(dc);

This throws an exception in the 32-bit registers case, right?

>            TCGv_i64 t0 = tcg_temp_new_i64();
>            tcg_gen_addi_i64(t0, cpu_R[ra], sign_extend(I16, 16));
>            tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
>            tcg_temp_free_i64(t0);
>        }
>        break;
>

[...]

>>> +static void dec_mac(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
>>> +{
>>> +    uint32_t op0;
>>> +    uint32_t ra, rb;
>>> +    op0 = field(insn, 0, 4);
>>> +    ra = field(insn, 16, 5);
>>> +    rb = field(insn, 11, 5);
>>> +    TCGv_i64 t0 = tcg_temp_new();
>>> +    TCGv_i64 t1 = tcg_temp_new();
>>> +    TCGv_i64 t2 = tcg_temp_new();
>>> +    switch (op0) {
>>> +    case 0x0001:   /*l.mac*/
>>> +        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
>>> +        {
>>> +            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>>> +            tcg_gen_ext_i32_i64(t1, t0);
>>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>>> +            tcg_gen_add_i64(t2, t2, t1);
>>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>>> +            tcg_gen_shri_i64(t2, t2, 32);
>>> +            tcg_gen_trunc_i64_i32(machi, t2);
>>> +            tcg_temp_free(t0);
>>> +            tcg_temp_free(t1);
>>> +            tcg_temp_free(t2);
>>
>> Instead of freeing temporaries repeatedly in some cases (and
>> leaking them in others) you could free them once after the switch.
>>
>
>    case 0x0001:   /*l.mac*/
>        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
>        {
>            TCGv_i64 t0 = tcg_temp_new();
>            TCGv_i64 t1 = tcg_temp_new();
>            TCGv_i64 t2 = tcg_temp_new();
>            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);

t0 should be _tl according to that.

>            tcg_gen_ext_i32_i64(t1, t0);
>            tcg_gen_concat_i32_i64(t2, maclo, machi);
>            tcg_gen_add_i64(t2, t2, t1);
>            tcg_gen_trunc_i64_i32(maclo, t2);
>            tcg_gen_shri_i64(t2, t2, 32);
>            tcg_gen_trunc_i64_i32(machi, t2);
>            tcg_temp_free(t0);
>            tcg_temp_free(t1);
>            tcg_temp_free(t2);
>        }
>        break;
>
> I think define use and free them separately make code more clear :-)

Ok, at your preference.

Looks like I completely missed temporaries vs local temporaries issue
spotted by Richard, so expect more review rounds.

Jia, is there kernel/rootfs image available for openrisc?
Andreas Färber June 8, 2012, 1:28 p.m. UTC | #7
Am 08.06.2012 14:56, schrieb Max Filippov:
> On Fri, Jun 8, 2012 at 4:00 AM, Jia Liu <proljc@gmail.com> wrote:
> 
>>        {
>>            TCGv_i64 t0 = tcg_temp_new();
>>            TCGv_i64 t1 = tcg_temp_new();
>>            TCGv_i64 t2 = tcg_temp_new();
>>            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
> 
> t0 should be _tl according to that.

You may find these patches helpful for detecting such mismatches:
http://patchwork.ozlabs.org/patch/130511/
http://patchwork.ozlabs.org/patch/130513/
http://patchwork.ozlabs.org/patch/130514/
http://patchwork.ozlabs.org/patch/130512/

Unfortunately there was no agreement at the time on how to proceed with
that feature...

Andreas
Andreas Färber June 8, 2012, 1:31 p.m. UTC | #8
Am 08.06.2012 15:28, schrieb Andreas Färber:
> Am 08.06.2012 14:56, schrieb Max Filippov:
>> On Fri, Jun 8, 2012 at 4:00 AM, Jia Liu <proljc@gmail.com> wrote:
>>
>>>        {
>>>            TCGv_i64 t0 = tcg_temp_new();
>>>            TCGv_i64 t1 = tcg_temp_new();
>>>            TCGv_i64 t2 = tcg_temp_new();
>>>            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>>
>> t0 should be _tl according to that.
> 
> You may find these patches helpful for detecting such mismatches:
> http://patchwork.ozlabs.org/patch/130511/

http://patchwork.ozlabs.org/patch/130566/

> http://patchwork.ozlabs.org/patch/130514/
> http://patchwork.ozlabs.org/patch/130512/
> 
> Unfortunately there was no agreement at the time on how to proceed with
> that feature...
> 
> Andreas
Jia Liu June 8, 2012, 9:59 p.m. UTC | #9
Hi Max,

On Fri, Jun 8, 2012 at 8:56 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
> Hi Jia.
>
> On Fri, Jun 8, 2012 at 4:00 AM, Jia Liu <proljc@gmail.com> wrote:
>
> [...]
>
>>>> +    case 0x0009:
>>>> +        switch (op1) {
>>>> +        case 0x03:   /*l.div*/
>>>> +            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
>>>> +            {
>>>> +                TCGv_i32 sr_ove;
>>>> +                int lab = gen_new_label();
>>>> +                sr_ove = tcg_temp_new();
>>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>>> +                if (rb == 0) {
>>>> +                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>>> +                    gen_exception(dc, EXCP_RANGE);
>>>> +                    gen_set_label(lab);
>>>> +                } else {
>>>> +                    if (ra == 0xffffffff && rb == 0x80000000) {
>>>
>>> Cannot do that: ra and rb are register numbers, not the values
>>> contained in these registers.
>>> Hence you need to generate code that will check these combinations of
>>> register values.
>>>
>>
>>        case 0x03:   /*l.div*/
>>            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
>>            {
>>                int lab0 = gen_new_label();
>>                int lab1 = gen_new_label();
>>                int lab2 = gen_new_label();
>>                TCGv_i32 sr_ove = tcg_temp_new_i32();
>>                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>                if (rb == 0) {
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
>>                    gen_exception(dc, EXCP_RANGE);
>>                    gen_set_label(lab0);
>>                } else {
>>                    tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_R[rb],
>>                                       0x00000000, lab1);
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[ra],
>>                                       0xffffffff, lab2);
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
>>                                       0x80000000, lab2);
>>                    gen_set_label(lab1);
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
>>                    gen_exception(dc, EXCP_RANGE);
>>                    gen_set_label(lab2);
>>                    tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>
> You still divide by zero/overflow here in case SR_OVE is not set.
> What value goes to the rd register in case of division by 0? Maybe
> you should skip the division altogether?
>
>>                }
>>                tcg_temp_free_i32(sr_ove);
>>            }
>>            break;
>>
>>
>> is this right?
>
> Much better now (:
>
>>>> +                        tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>>> +                        gen_exception(dc, EXCP_RANGE);
>>>> +                        gen_set_label(lab);
>>>> +                    } else {
>>>> +                        tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>>>> +                    }
>>>> +                }
>>>> +                tcg_temp_free(sr_ove);
>>>> +            }
>>>> +            break;
>>>> +
>>>> +        default:
>>>> +            gen_illegal_exception(dc);
>>>> +            break;
>>>> +        }
>>>> +        break;
>>>> +
>>>> +    case 0x000a:
>>>> +        switch (op1) {
>>>> +        case 0x03:   /*l.divu*/
>>>> +            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
>>>> +            if (rb == 0) {
>>>> +                TCGv_i32 sr_ove;
>>>> +                int lab = gen_new_label();
>>>> +                sr_ove = tcg_temp_new();
>>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>>> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>>> +                gen_exception(dc, EXCP_RANGE);
>>>> +                gen_set_label(lab);
>>>> +                tcg_temp_free(sr_ove);
>>>> +            } else if (rb != 0) {
>>>
>>> 'if (rb != 0)' and the following 'else' block are redundant here.
>>>
>>> I feel that I repeatedly fail to explain what's wrong with these div/divu
>>> implementations; could you please add testcases for l.div and l.divu
>>> that divide by the register other than r0 that contains 0 value?
>>>
>>
>> and
>>
>>        case 0x03:   /*l.divu*/
>>            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
>>            {
>>                int lab0 = gen_new_label();
>>                int lab1 = gen_new_label();
>>                TCGv_i32 sr_ove = tcg_temp_new();
>>                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>                if (rb == 0) {
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab0);
>>                    gen_exception(dc, EXCP_RANGE);
>>                    gen_set_label(lab0);
>>                } else {
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[rb],
>>                                       0x00000000, lab1);
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>                    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab1);
>>                    gen_exception(dc, EXCP_RANGE);
>>                    gen_set_label(lab1);
>>                    tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>
> Ditto.
>
>>                }
>>                tcg_temp_free_i32(sr_ove);
>>            }
>>            break;
>>
>> is this OK?
>>
>>>> +                tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
>>>> +            } else {
>>>> +                break;
>>>> +            }
>>>> +            break;
>>>> +
>>>> +        default:
>>>> +            gen_illegal_exception(dc);
>>>> +            break;
>>>> +        }
>>>> +        break;
>>>> +
>>>> +    case 0x000b:
>>>> +        switch (op1) {
>>>> +        case 0x03:   /*l.mulu*/
>>>> +            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
>>>> +            if (rb != 0 && ra != 0) {
>>>> +                TCGv result = tcg_temp_new();
>>>> +                TCGv high = tcg_temp_new();
>>>> +                TCGv tra = tcg_temp_new();
>>>> +                TCGv trb = tcg_temp_new();
>>>> +                TCGv_i32 sr_ove = tcg_temp_new();
>>>> +                int lab = gen_new_label();
>>>> +                int lab2 = gen_new_label();
>>>> +                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
>>>> +                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
>>>> +                tcg_gen_mul_tl(result, cpu_R[ra], cpu_R[rb]);
>>>
>>> You've calculated tra and trb but haven't uses them here.
>>>
>>>> +                tcg_gen_shri_tl(high, result, (sizeof(target_ulong) * 8));
>>>
>>> You probably meant result and high to be _i64.
>>>
>>>> +                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x0, lab);
>>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>>> +                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>>>> +                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>>> +                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
>>>> +                gen_exception(dc, EXCP_RANGE);
>>>> +                gen_set_label(lab);
>>>> +                gen_set_label(lab2);
>>>
>>> No need to set two labels at one point.
>>>
>>
>>        case 0x03:   /*l.mulu*/
>>            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
>>            if (rb != 0 && ra != 0) {
>>                TCGv_i64 result = tcg_temp_new_i64();
>>                TCGv_i64 tra = tcg_temp_new_i64();
>>                TCGv_i64 trb = tcg_temp_new_i64();
>>                TCGv high = tcg_temp_new();
>>                TCGv_i32 sr_ove = tcg_temp_new();
>>                int lab = gen_new_label();
>>                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
>>                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
>>                tcg_gen_mul_i64(result, tra, trb);
>>                tcg_temp_free(tra);
>>                tcg_temp_free(trb);
>>                tcg_gen_shri_i64(high, result, (sizeof(target_ulong) * 8));
>
> TARGET_LONG_BITS?
>

yes, thank you, I'll fix them, all.

>>                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x00000000, lab);
>>                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
>>                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
>
> Not an issue, but you could just tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY | SR_OV);
>

all right, thank you, I'll fix them all.

>>                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
>>                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
>>                gen_exception(dc, EXCP_RANGE);
>>                gen_set_label(lab);
>>                tcg_temp_free(high);
>>                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
>>                tcg_temp_free(result);
>>                tcg_temp_free(sr_ove);
>>            } else {
>>                tcg_gen_movi_tl(cpu_R[rd], 0);
>>            }
>>            break;
>>
>> is it right this time?
>
> Looks good to me.
>
>>>> +                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
>>>> +                tcg_temp_free(result);
>>>> +                tcg_temp_free(high);
>>>> +                tcg_temp_free(sr_ove);
>>>> +                tcg_temp_free(tra);
>>>> +                tcg_temp_free(trb);
>>>> +            } else {
>>>> +                tcg_gen_movi_tl(cpu_R[rd], 0);
>>>> +            }
>>>> +            break;
>>>> +
>>>> +        default:
>>>> +            gen_illegal_exception(dc);
>>>> +            break;
>>>> +        }
>>>> +        break;
>>>> +
>>>
>>> [...]
>>>
>>>> +    case 0x13:    /*l.maci*/
>>>> +        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
>>>> +        {
>>>> +            TCGv t1 = tcg_temp_new();
>>>> +            TCGv t2 = tcg_temp_new();
>>>> +            TCGv ttmp = tcg_temp_new();   /*  store machi maclo*/
>>>> +            ttmp = tcg_const_tl(tmp);
>>>
>>> Leaked previous ttmp temporary.
>>>
>>>> +            tcg_gen_mul_tl(t0, cpu_R[ra], ttmp);
>>>
>>> What t0?
>>>
>>>> +            tcg_gen_ext_i32_i64(t1, t0);
>>>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>>>> +            tcg_gen_add_i64(t2, t2, t1);
>>>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>>>> +            tcg_gen_shri_i64(t2, t2, 32);
>>>> +            tcg_gen_trunc_i64_i32(machi, t2);
>>>> +            tcg_temp_free(t0);
>>>> +            tcg_temp_free(t1);
>>>> +            tcg_temp_free(t2);
>>>
>>> Leaked ttmp temporary.
>>
>>
>>    case 0x13:    /*l.maci*/
>>        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
>>        {
>>            TCGv t1 = tcg_temp_new();
>>            TCGv t2 = tcg_temp_new();
>>            TCGv ttmp = tcg_const_tl(tmp);  /*  store machi maclo*/
>>            tcg_gen_mul_tl(ttmp, cpu_R[ra], ttmp);
>>            tcg_gen_ext_i32_i64(t1, ttmp);
>>            tcg_gen_concat_i32_i64(t2, maclo, machi);
>>            tcg_gen_add_i64(t2, t2, t1);
>>            tcg_gen_trunc_i64_i32(maclo, t2);
>>            tcg_gen_shri_i64(t2, t2, 32);
>>            tcg_gen_trunc_i64_i32(machi, t2);
>>            tcg_temp_free(ttmp);
>>            tcg_temp_free(t1);
>>            tcg_temp_free(t2);
>>        }
>>        break;
>>
>>
>>>
>>>> +        }
>>>> +        break;
>>>
>>> [...]
>>>
>>>> +    case 0x20:   /*l.ld*/
>>>> +        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
>>>> +        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
>>>> +        tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
>>>
>>> Cannot ld64 into _tl register.
>>>
>>
>>    case 0x20:   /*l.ld*/
>>        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
>>        {
>>            check_ob64s(dc);
>
> This throws an exception in the 32-bit registers case, right?
>

this is legal check, like MIPS's check_insn();
You will see all of them in v4.

>>            TCGv_i64 t0 = tcg_temp_new_i64();
>>            tcg_gen_addi_i64(t0, cpu_R[ra], sign_extend(I16, 16));
>>            tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
>>            tcg_temp_free_i64(t0);
>>        }
>>        break;
>>
>
> [...]
>
>>>> +static void dec_mac(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
>>>> +{
>>>> +    uint32_t op0;
>>>> +    uint32_t ra, rb;
>>>> +    op0 = field(insn, 0, 4);
>>>> +    ra = field(insn, 16, 5);
>>>> +    rb = field(insn, 11, 5);
>>>> +    TCGv_i64 t0 = tcg_temp_new();
>>>> +    TCGv_i64 t1 = tcg_temp_new();
>>>> +    TCGv_i64 t2 = tcg_temp_new();
>>>> +    switch (op0) {
>>>> +    case 0x0001:   /*l.mac*/
>>>> +        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
>>>> +        {
>>>> +            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>>>> +            tcg_gen_ext_i32_i64(t1, t0);
>>>> +            tcg_gen_concat_i32_i64(t2, maclo, machi);
>>>> +            tcg_gen_add_i64(t2, t2, t1);
>>>> +            tcg_gen_trunc_i64_i32(maclo, t2);
>>>> +            tcg_gen_shri_i64(t2, t2, 32);
>>>> +            tcg_gen_trunc_i64_i32(machi, t2);
>>>> +            tcg_temp_free(t0);
>>>> +            tcg_temp_free(t1);
>>>> +            tcg_temp_free(t2);
>>>
>>> Instead of freeing temporaries repeatedly in some cases (and
>>> leaking them in others) you could free them once after the switch.
>>>
>>
>>    case 0x0001:   /*l.mac*/
>>        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
>>        {
>>            TCGv_i64 t0 = tcg_temp_new();
>>            TCGv_i64 t1 = tcg_temp_new();
>>            TCGv_i64 t2 = tcg_temp_new();
>>            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>
> t0 should be _tl according to that.

Aha, thank you, I'll fix it.

>
>>            tcg_gen_ext_i32_i64(t1, t0);
>>            tcg_gen_concat_i32_i64(t2, maclo, machi);
>>            tcg_gen_add_i64(t2, t2, t1);
>>            tcg_gen_trunc_i64_i32(maclo, t2);
>>            tcg_gen_shri_i64(t2, t2, 32);
>>            tcg_gen_trunc_i64_i32(machi, t2);
>>            tcg_temp_free(t0);
>>            tcg_temp_free(t1);
>>            tcg_temp_free(t2);
>>        }
>>        break;
>>
>> I think define use and free them separately make code more clear :-)
>
> Ok, at your preference.
>
> Looks like I completely missed temporaries vs local temporaries issue
> spotted by Richard, so expect more review rounds.
>

Richard is great!

> Jia, is there kernel/rootfs image available for openrisc?
>

kernel/rootfs image and hello-world in my google drive, I'll send the
URL with v4, and v4 is soon.

> --
> Thanks.
> -- Max

Regards,
Jia
Jia Liu June 8, 2012, 10:12 p.m. UTC | #10
Hi Andreas,

I'll read your patch and try to catch your step.
Thank you very much for reviewing and comments, you make me open my
eyes on QEMU.

On Fri, Jun 8, 2012 at 9:31 PM, Andreas Färber <afaerber@suse.de> wrote:
> Am 08.06.2012 15:28, schrieb Andreas Färber:
>> Am 08.06.2012 14:56, schrieb Max Filippov:
>>> On Fri, Jun 8, 2012 at 4:00 AM, Jia Liu <proljc@gmail.com> wrote:
>>>
>>>>        {
>>>>            TCGv_i64 t0 = tcg_temp_new();
>>>>            TCGv_i64 t1 = tcg_temp_new();
>>>>            TCGv_i64 t2 = tcg_temp_new();
>>>>            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
>>>
>>> t0 should be _tl according to that.
>>
>> You may find these patches helpful for detecting such mismatches:
>> http://patchwork.ozlabs.org/patch/130511/
>
> http://patchwork.ozlabs.org/patch/130566/
>
>> http://patchwork.ozlabs.org/patch/130514/
>> http://patchwork.ozlabs.org/patch/130512/
>>
>> Unfortunately there was no agreement at the time on how to proceed with
>> that feature...
>>
>> Andreas
>
> --
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg


Regards,
Jia.
diff mbox

Patch

diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index 61fb1cf..09898e8 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -26,14 +26,1454 @@ 
 #include "qemu-log.h"
 #include "config.h"
 
+#include "helper.h"
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define OPENRISC_DISAS
+
+#ifdef OPENRISC_DISAS
+#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DIS(...) do { } while (0)
+#endif
+
+typedef struct DisasContext {
+    CPUOpenRISCState *env;
+    TranslationBlock *tb;
+    target_ulong pc, ppc, npc;
+    uint32_t tb_flags, synced_flags;
+    uint32_t is_jmp;
+    uint32_t mem_idx;
+    int singlestep_enabled;
+    uint32_t delayed_branch;
+} DisasContext;
+
+static TCGv_ptr cpu_env;
+static TCGv cpu_sr;
+static TCGv cpu_R[32];
+static TCGv cpu_pc;
+static TCGv jmp_pc;            /* l.jr/l.jalr temp pc */
+static TCGv cpu_npc;
+static TCGv cpu_ppc;
+static TCGv_i32 env_btaken;    /* bf/bnf , F flag taken */
+static TCGv_i32 fpcsr;
+static TCGv machi, maclo;
+static TCGv fpmaddhi, fpmaddlo;
+static TCGv_i32 env_flags;
+#include "gen-icount.h"
+
 void openrisc_translate_init(void)
 {
+    static const char * const regnames[] = {
+        "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+        "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+        "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+        "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+    };
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_sr = tcg_global_mem_new(TCG_AREG0,
+                                offsetof(CPUOpenRISCState, sr), "sr");
+    env_flags = tcg_global_mem_new_i32(TCG_AREG0,
+                                       offsetof(CPUOpenRISCState, flags),
+                                       "flags");
+    cpu_pc = tcg_global_mem_new(TCG_AREG0,
+                                offsetof(CPUOpenRISCState, pc), "pc");
+    cpu_npc = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUOpenRISCState, npc), "npc");
+    cpu_ppc = tcg_global_mem_new(TCG_AREG0,
+                                 offsetof(CPUOpenRISCState, ppc), "ppc");
+    jmp_pc = tcg_global_mem_new(TCG_AREG0,
+                                offsetof(CPUOpenRISCState, jmp_pc), "jmp_pc");
+    env_btaken = tcg_global_mem_new_i32(TCG_AREG0,
+                                        offsetof(CPUOpenRISCState, btaken),
+                                        "btaken");
+    fpcsr = tcg_global_mem_new_i32(TCG_AREG0,
+                                   offsetof(CPUOpenRISCState, fpcsr),
+                                   "fpcsr");
+    machi = tcg_global_mem_new(TCG_AREG0,
+                               offsetof(CPUOpenRISCState, machi),
+                               "machi");
+    maclo = tcg_global_mem_new(TCG_AREG0,
+                               offsetof(CPUOpenRISCState, maclo),
+                               "maclo");
+    fpmaddhi = tcg_global_mem_new(TCG_AREG0,
+                                  offsetof(CPUOpenRISCState, fpmaddhi),
+                                  "fpmaddhi");
+    fpmaddlo = tcg_global_mem_new(TCG_AREG0,
+                                  offsetof(CPUOpenRISCState, fpmaddlo),
+                                  "fpmaddlo");
+    for (i = 0; i < 32; i++) {
+        cpu_R[i] = tcg_global_mem_new(TCG_AREG0,
+                                      offsetof(CPUOpenRISCState, gpr[i]),
+                                      regnames[i]);
+    }
+#define GEN_HELPER 2
+#include "helper.h"
+}
+
+/* Writeback SR_F transaltion-space to execution-space.  */
+static inline void wb_SR_F(void)
+{
+    int label;
+
+    label = gen_new_label();
+    tcg_gen_andi_tl(cpu_sr, cpu_sr, ~SR_F);
+    tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, label);
+    tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_F);
+    gen_set_label(label);
+}
+
+static inline int zero_extend(unsigned int val, int width)
+{
+    return val & ((1 << width) - 1);
+}
+
+static inline int sign_extend(unsigned int val, int width)
+{
+    int sval;
+
+    /* LSL */
+    val <<= TARGET_LONG_BITS - width;
+    sval = val;
+    /* ASR.  */
+    sval >>= TARGET_LONG_BITS - width;
+    return sval;
+}
+
+static inline void gen_sync_flags(DisasContext *dc)
+{
+    /* Sync the tb dependent flag between translate and runtime.  */
+    if (dc->tb_flags != dc->synced_flags) {
+        tcg_gen_movi_tl(env_flags, dc->tb_flags);
+        dc->synced_flags = dc->tb_flags;
+    }
+}
+
+static void gen_exception(DisasContext *dc, unsigned int excp)
+{
+    TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_helper_exception(cpu_env, tmp);
+    tcg_temp_free(tmp);
+}
+
+static void gen_illegal_exception(DisasContext *dc)
+{
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    gen_exception(dc, EXCP_ILLEGAL);
+    dc->is_jmp = DISAS_UPDATE;
+}
+
+static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = dc->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+                                       likely(!dc->singlestep_enabled)) {
+        tcg_gen_movi_tl(cpu_pc, dest);
+        tcg_gen_goto_tb(n);
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_pc, dest);
+        if (dc->singlestep_enabled) {
+            gen_exception(dc, EXCP_DEBUG);
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void gen_jump(DisasContext *dc, uint32_t imm, uint32_t reg, uint32_t op0)
+{
+    target_ulong tmp_pc;
+    int lab = gen_new_label();
+    TCGv sr_f = tcg_temp_new();
+    /* N26, 26bits imm */
+    tmp_pc = sign_extend((imm<<2), 26) + dc->pc;
+    tcg_gen_andi_tl(sr_f, cpu_sr, SR_F);
+
+    if (op0 == 0x00) {    /*l.j*/
+        tcg_gen_movi_tl(jmp_pc, tmp_pc);
+    } else if (op0 == 0x01) {    /*l.jal*/
+        tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8));
+        tcg_gen_movi_tl(jmp_pc, tmp_pc);
+    } else if (op0 == 0x03) {    /*l.bnf*/
+        tcg_gen_movi_tl(jmp_pc, dc->pc+8);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, sr_f, SR_F, lab);
+        tcg_gen_movi_tl(jmp_pc, tmp_pc);
+        gen_set_label(lab);
+    } else if (op0 == 0x04) {    /*l.bf*/
+        tcg_gen_movi_tl(jmp_pc, dc->pc+8);
+        tcg_gen_brcondi_i32(TCG_COND_NE, sr_f, SR_F, lab);
+        tcg_gen_movi_tl(jmp_pc, tmp_pc);
+        gen_set_label(lab);
+    } else if (op0 == 0x11) {    /*l.jr*/
+        tcg_gen_mov_tl(jmp_pc, cpu_R[reg]);
+    } else if (op0 == 0x12) {    /*l.jalr*/
+        tcg_gen_movi_tl(cpu_R[9], (dc->pc + 8));
+        tcg_gen_mov_tl(jmp_pc, cpu_R[reg]);
+    } else {
+        gen_illegal_exception(dc);
+    }
+
+    tcg_temp_free(sr_f);
+    dc->delayed_branch = 2;
+    dc->tb_flags |= D_FLAG;
+    gen_sync_flags(dc);
+}
+
+static inline uint32_t field(uint32_t val, int start, int length)
+{
+    val >>= start;
+    val &= ~(~0 << length);
+    return val;
+}
+
+static void dec_calc(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0, op1, op2;
+    uint32_t ra, rb, rd;
+    op0 = field(insn, 0, 4);
+    op1 = field(insn, 8, 2);
+    op2 = field(insn, 6, 2);
+    ra = field(insn, 16, 5);
+    rb = field(insn, 11, 5);
+    rd = field(insn, 21, 5);
+
+    switch (op0) {
+    case 0x0000:
+        switch (op1) {
+        case 0x00:     /*l.add*/
+            LOG_DIS("l.add r%d, r%d, r%d\n", rd, ra, rb);
+            gen_helper_add(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0001:    /*l.addc*/
+        switch (op1) {
+        case 0x00:
+            LOG_DIS("l.addc r%d, r%d, r%d\n", rd, ra, rb);
+            gen_helper_addc(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0002:    /*l.sub*/
+        switch (op1) {
+        case 0x00:
+            LOG_DIS("l.sub r%d, r%d, r%d\n", rd, ra, rb);
+            gen_helper_sub(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0003:   /*l.and*/
+        switch (op1) {
+        case 0x00:
+            LOG_DIS("l.and r%d, r%d, r%d\n", rd, ra, rb);
+            tcg_gen_and_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0004:   /*l.or*/
+        switch (op1) {
+        case 0x00:
+            LOG_DIS("l.or r%d, r%d, r%d\n", rd, ra, rb);
+            tcg_gen_or_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0005:
+        switch (op1) {
+        case 0x00:   /*l.xor*/
+            LOG_DIS("l.xor r%d, r%d, r%d\n", rd, ra, rb);
+            tcg_gen_xor_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0006:
+        switch (op1) {
+        case 0x03:   /*l.mul*/
+            LOG_DIS("l.mul r%d, r%d, r%d\n", rd, ra, rb);
+            if (ra != 0 && rb != 0) {
+                gen_helper_mul(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+            } else {
+                tcg_gen_movi_tl(cpu_R[rd], 0x0);
+            }
+            break;
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0009:
+        switch (op1) {
+        case 0x03:   /*l.div*/
+            LOG_DIS("l.div r%d, r%d, r%d\n", rd, ra, rb);
+            {
+                TCGv_i32 sr_ove;
+                int lab = gen_new_label();
+                sr_ove = tcg_temp_new();
+                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
+                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
+                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+                if (rb == 0) {
+                    tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
+                    gen_exception(dc, EXCP_RANGE);
+                    gen_set_label(lab);
+                } else {
+                    if (ra == 0xffffffff && rb == 0x80000000) {
+                        tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
+                        gen_exception(dc, EXCP_RANGE);
+                        gen_set_label(lab);
+                    } else {
+                        tcg_gen_div_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+                    }
+                }
+                tcg_temp_free(sr_ove);
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x000a:
+        switch (op1) {
+        case 0x03:   /*l.divu*/
+            LOG_DIS("l.divu r%d, r%d, r%d\n", rd, ra, rb);
+            if (rb == 0) {
+                TCGv_i32 sr_ove;
+                int lab = gen_new_label();
+                sr_ove = tcg_temp_new();
+                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
+                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
+                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab);
+                gen_exception(dc, EXCP_RANGE);
+                gen_set_label(lab);
+                tcg_temp_free(sr_ove);
+            } else if (rb != 0) {
+                tcg_gen_divu_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+            } else {
+                break;
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x000b:
+        switch (op1) {
+        case 0x03:   /*l.mulu*/
+            LOG_DIS("l.mulu r%d, r%d, r%d\n", rd, ra, rb);
+            if (rb != 0 && ra != 0) {
+                TCGv result = tcg_temp_new();
+                TCGv high = tcg_temp_new();
+                TCGv tra = tcg_temp_new();
+                TCGv trb = tcg_temp_new();
+                TCGv_i32 sr_ove = tcg_temp_new();
+                int lab = gen_new_label();
+                int lab2 = gen_new_label();
+                tcg_gen_extu_i32_i64(tra, cpu_R[ra]);
+                tcg_gen_extu_i32_i64(trb, cpu_R[rb]);
+                tcg_gen_mul_tl(result, cpu_R[ra], cpu_R[rb]);
+                tcg_gen_shri_tl(high, result, (sizeof(target_ulong) * 8));
+                tcg_gen_brcondi_tl(TCG_COND_EQ, high, 0x0, lab);
+                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_CY);
+                tcg_gen_ori_tl(cpu_sr, cpu_sr, SR_OV);
+                tcg_gen_andi_tl(sr_ove, cpu_sr, SR_OVE);
+                tcg_gen_brcondi_tl(TCG_COND_NE, sr_ove, SR_OVE, lab2);
+                gen_exception(dc, EXCP_RANGE);
+                gen_set_label(lab);
+                gen_set_label(lab2);
+                tcg_gen_trunc_i64_tl(cpu_R[rd], result);
+                tcg_temp_free(result);
+                tcg_temp_free(high);
+                tcg_temp_free(sr_ove);
+                tcg_temp_free(tra);
+                tcg_temp_free(trb);
+            } else {
+                tcg_gen_movi_tl(cpu_R[rd], 0);
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x000e:
+        switch (op1) {
+        case 0x00:   /*l.cmov*/
+            LOG_DIS("l.cmov r%d, r%d, r%d\n", rd, ra, rb);
+            {
+                int lab = gen_new_label();
+                TCGv res = tcg_temp_new();
+                TCGv sr_f = tcg_temp_new();
+                tcg_gen_andi_tl(sr_f, cpu_sr, SR_F);
+                tcg_gen_mov_tl(res, cpu_R[rb]);
+                tcg_gen_brcondi_tl(TCG_COND_NE, sr_f, SR_F, lab);
+                tcg_gen_mov_tl(res, cpu_R[ra]);
+                gen_set_label(lab);
+                tcg_gen_mov_tl(cpu_R[rd], res);
+                tcg_temp_free(sr_f);
+                tcg_temp_free(res);
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x000f:
+        switch (op1) {
+        case 0x00:   /*l.ff1*/
+            LOG_DIS("l.ff1 r%d, r%d, r%d\n", rd, ra, rb);
+            gen_helper_ff1(cpu_R[rd], cpu_R[ra]);
+            break;
+        case 0x01:   /*l.fl1*/
+            LOG_DIS("l.fl1 r%d, r%d, r%d\n", rd, ra, rb);
+            gen_helper_fl1(cpu_R[rd], cpu_R[ra]);
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x0008:
+        switch (op1) {
+        case 0x00:
+            switch (op2) {
+            case 0x00:   /*l.sll*/
+                LOG_DIS("l.sll r%d, r%d, r%d\n", rd, ra, rb);
+                tcg_gen_shl_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+                break;
+            case 0x01:   /*l.srl*/
+                LOG_DIS("l.srl r%d, r%d, r%d\n", rd, ra, rb);
+                tcg_gen_shr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+                break;
+            case 0x02:   /*l.sra*/
+                LOG_DIS("l.sra r%d, r%d, r%d\n", rd, ra, rb);
+                tcg_gen_sar_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+                break;
+            case 0x03:   /*l.ror*/
+                LOG_DIS("l.ror r%d, r%d, r%d\n", rd, ra, rb);
+                tcg_gen_rotr_tl(cpu_R[rd], cpu_R[ra], cpu_R[rb]);
+                break;
+
+            default:
+                gen_illegal_exception(dc);
+                break;
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x000c:
+        switch (op1) {
+        case 0x00:
+            switch (op2) {
+            case 0x00:   /*l.exths*/
+                LOG_DIS("l.exths r%d, r%d\n", rd, ra);
+                tcg_gen_ext16s_tl(cpu_R[rd], cpu_R[ra]);
+                break;
+            case 0x01:   /*l.extbs*/
+                LOG_DIS("l.extbs r%d, r%d\n", rd, ra);
+                tcg_gen_ext8s_tl(cpu_R[rd], cpu_R[ra]);
+                break;
+            case 0x02:   /*l.exthz*/
+                LOG_DIS("l.exthz r%d, r%d\n", rd, ra);
+                tcg_gen_ext16u_tl(cpu_R[rd], cpu_R[ra]);
+                break;
+            case 0x03:   /*l.extbz*/
+                LOG_DIS("l.extbz r%d, r%d\n", rd, ra);
+                tcg_gen_ext8u_tl(cpu_R[rd], cpu_R[ra]);
+                break;
+
+            default:
+                gen_illegal_exception(dc);
+                break;
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x000d:
+        switch (op1) {
+        case 0x00:
+            switch (op2) {
+            case 0x00:   /*l.extws*/
+                LOG_DIS("l.extws r%d, r%d\n", rd, ra);
+                tcg_gen_ext32s_tl(cpu_R[rd], cpu_R[ra]);
+                break;
+            case 0x01:    /*l.extwz*/
+                LOG_DIS("l.extwz r%d, r%d\n", rd, ra);
+                tcg_gen_ext32u_tl(cpu_R[rd], cpu_R[ra]);
+                break;
+
+            default:
+                gen_illegal_exception(dc);
+                break;
+            }
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+}
+
+static void dec_misc(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0, op1;
+    uint32_t ra, rb, rd;
+    uint32_t /*L6, K5, */I16, I5, I11, N26, tmp;
+    op0 = field(insn, 26, 6);
+    op1 = field(insn, 24, 2);
+    ra = field(insn, 16, 5);
+    rb = field(insn, 11, 5);
+    rd = field(insn, 21, 5);
+    /*L6 = field(insn, 5, 6);
+    K5 = field(insn, 0, 5);*/
+    I16 = field(insn, 0, 16);
+    I5 = field(insn, 21, 5);
+    I11 = field(insn, 0, 11);
+    N26 = field(insn, 0, 26);
+    tmp = (I5<<11) + I11;
+    TCGv t0 = tcg_temp_new();
+
+    switch (op0) {
+    case 0x00:   /*l.j*/
+        LOG_DIS("l.j %d\n", N26);
+    case 0x01:   /*l.jal*/
+        LOG_DIS("l.jal %d\n", N26);
+    case 0x03:   /*l.bnf*/
+        LOG_DIS("l.bnf %d\n", N26);
+    case 0x04:   /*l.bf*/
+        LOG_DIS("l.bf %d\n", N26);
+
+        gen_jump(dc, N26, 0, op0);
+        break;
+
+    case 0x05:
+        switch (op1) {
+        case 0x01:   /*l.nop*/
+            LOG_DIS("l.nop %d\n", I16);
+            break;
+
+        default:
+            gen_illegal_exception(dc);
+            break;
+        }
+        break;
+
+    case 0x11:    /*l.jr*/
+        LOG_DIS("l.jr r%d\n", rb);
+    case 0x12:    /*l.jalr*/
+        LOG_DIS("l.jalr r%d\n", rb);
+
+        gen_jump(dc, 0, rb, op0);
+        break;
+
+    case 0x13:    /*l.maci*/
+        LOG_DIS("l.maci %d, r%d, %d\n", I5, ra, I11);
+        {
+            TCGv t1 = tcg_temp_new();
+            TCGv t2 = tcg_temp_new();
+            TCGv ttmp = tcg_temp_new();   /*  store machi maclo*/
+            ttmp = tcg_const_tl(tmp);
+            tcg_gen_mul_tl(t0, cpu_R[ra], ttmp);
+            tcg_gen_ext_i32_i64(t1, t0);
+            tcg_gen_concat_i32_i64(t2, maclo, machi);
+            tcg_gen_add_i64(t2, t2, t1);
+            tcg_gen_trunc_i64_i32(maclo, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_i32(machi, t2);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+            tcg_temp_free(t2);
+        }
+        break;
+
+    case 0x09:    /*l.rfe*/
+        LOG_DIS("l.rfe\n");
+        {
+            gen_helper_rfe(cpu_env);
+            dc->is_jmp = DISAS_UPDATE;
+        }
+        break;
+
+    case 0x1c:    /*l.cust1*/
+        LOG_DIS("l.cust1\n");
+        break;
+
+    case 0x1d:    /*l.cust2*/
+        LOG_DIS("l.cust2\n");
+        break;
+
+    case 0x1e:    /*l.cust3*/
+        LOG_DIS("l.cust3\n");
+        break;
+
+    case 0x1f:    /*l.cust4*/
+        LOG_DIS("l.cust4\n");
+        break;
+
+    case 0x3c:   /*l.cust5*/
+        /*LOG_DIS("l.cust5 r%d, r%d, r%d, %d, %d\n", rd, ra, rb, L6, K5);*/
+        break;
+
+    case 0x3d:   /*l.cust6*/
+        LOG_DIS("l.cust6\n");
+        break;
+
+    case 0x3e:   /*l.cust7*/
+        LOG_DIS("l.cust7\n");
+        break;
+
+    case 0x3f:   /*l.cust8*/
+        LOG_DIS("l.cust8\n");
+        break;
+
+    case 0x20:   /*l.ld*/
+        LOG_DIS("l.ld r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld64(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x21:   /*l.lwz*/
+        LOG_DIS("l.lwz r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld32u(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x22:   /*l.lws*/
+        LOG_DIS("l.lws r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld32s(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x23:   /*l.lbz*/
+        LOG_DIS("l.lbz r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld8u(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x24:   /*l.lbs*/
+        LOG_DIS("l.lbs r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld8s(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x25:   /*l.lhz*/
+        LOG_DIS("l.lhz r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld16u(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x26:   /*l.lhs*/
+        LOG_DIS("l.lhs r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(I16, 16));
+        tcg_gen_qemu_ld16s(cpu_R[rd], t0, dc->mem_idx);
+        break;
+
+    case 0x27:   /*l.addi*/
+        LOG_DIS("l.addi r%d, r%d, %d\n", rd, ra, I16);
+        {
+            TCGv t0 = tcg_const_tl(sign_extend(I16, 16));
+            gen_helper_add(cpu_R[rd], cpu_env, cpu_R[ra], t0);
+            tcg_temp_free(t0);
+        }
+        break;
+
+    case 0x28:   /*l.addic*/
+        LOG_DIS("l.addic r%d, r%d, %d\n", rd, ra, I16);
+        {
+            TCGv t0 = tcg_const_tl(sign_extend(I16, 16));
+            gen_helper_addc(cpu_R[rd], cpu_env, cpu_R[ra], t0);
+            tcg_temp_free(t0);
+        }
+        break;
+
+    case 0x29:   /*l.andi*/
+        LOG_DIS("l.andi r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_andi_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16));
+        break;
+
+    case 0x2a:   /*l.ori*/
+        LOG_DIS("l.ori r%d, r%d, %d\n", rd, ra, I16;
+        tcg_gen_ori_tl(cpu_R[rd], cpu_R[ra], zero_extend(I16, 16)));
+        break;
+
+    case 0x2b:   /*l.xori*/
+        LOG_DIS("l.xori r%d, r%d, %d\n", rd, ra, I16);
+        tcg_gen_xori_tl(cpu_R[rd], cpu_R[ra], sign_extend(I16, 16));
+        break;
+
+    case 0x2c:   /*l.muli*/
+        LOG_DIS("l.muli r%d, r%d, %d\n", rd, ra, I16);
+        if (ra != 0 && I16 != 0) {
+            TCGv i16 = tcg_const_tl(I16);
+            gen_helper_mul(cpu_R[rd], cpu_env, cpu_R[ra], i16);
+            tcg_temp_free(i16);
+        } else {
+            tcg_gen_movi_tl(cpu_R[rd], 0x0);
+        }
+        break;
+
+    case 0x2d:   /*l.mfspr*/
+        LOG_DIS("l.mfspr r%d, r%d, %d\n", rd, ra, I16);
+        break;
+
+    case 0x30:  /*l.mtspr*/
+        LOG_DIS("l.mtspr %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+        break;
+
+    case 0x34:   /*l.sd*/
+        LOG_DIS("l.sd %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
+        tcg_gen_qemu_st64(cpu_R[rb], t0, dc->mem_idx);
+        break;
+
+    case 0x35:   /*l.sw*/
+        LOG_DIS("l.sw %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
+        tcg_gen_qemu_st32(cpu_R[rb], t0, dc->mem_idx);
+        break;
+
+    case 0x36:   /*l.sb*/
+        LOG_DIS("l.sb %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
+        tcg_gen_qemu_st8(cpu_R[rb], t0, dc->mem_idx);
+        break;
+
+    case 0x37:   /*l.sh*/
+        LOG_DIS("l.sh %d, r%d, r%d, %d\n", I5, ra, rb, I11);
+        tcg_gen_addi_tl(t0, cpu_R[ra], sign_extend(tmp, 16));
+        tcg_gen_qemu_st16(cpu_R[rb], t0, dc->mem_idx);
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+    tcg_temp_free(t0);
+}
+
+static void dec_mac(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    uint32_t ra, rb;
+    op0 = field(insn, 0, 4);
+    ra = field(insn, 16, 5);
+    rb = field(insn, 11, 5);
+    TCGv_i64 t0 = tcg_temp_new();
+    TCGv_i64 t1 = tcg_temp_new();
+    TCGv_i64 t2 = tcg_temp_new();
+    switch (op0) {
+    case 0x0001:   /*l.mac*/
+        LOG_DIS("l.mac r%d, r%d\n", ra, rb);
+        {
+            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
+            tcg_gen_ext_i32_i64(t1, t0);
+            tcg_gen_concat_i32_i64(t2, maclo, machi);
+            tcg_gen_add_i64(t2, t2, t1);
+            tcg_gen_trunc_i64_i32(maclo, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_i32(machi, t2);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+            tcg_temp_free(t2);
+        }
+        break;
+
+    case 0x0002:   /*l.msb*/
+        LOG_DIS("l.msb r%d, r%d\n", ra, rb);
+        {
+            tcg_gen_mul_tl(t0, cpu_R[ra], cpu_R[rb]);
+            tcg_gen_ext_i32_i64(t1, t0);
+            tcg_gen_concat_i32_i64(t2, maclo, machi);
+            tcg_gen_sub_i64(t2, t2, t1);
+            tcg_gen_trunc_i64_i32(maclo, t2);
+            tcg_gen_shri_i64(t2, t2, 32);
+            tcg_gen_trunc_i64_i32(machi, t2);
+            tcg_temp_free(t0);
+            tcg_temp_free(t1);
+            tcg_temp_free(t2);
+        }
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+   }
+}
+
+static void dec_logic(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    uint32_t rd, ra, L6;
+    op0 = field(insn, 6, 2);
+    rd = field(insn, 21, 5);
+    ra = field(insn, 16, 5);
+    L6 = field(insn, 0, 6);
+
+    switch (op0) {
+    case 0x00:    /*l.slli*/
+        LOG_DIS("l.slli r%d, r%d, %d\n", rd, ra, L6);
+        tcg_gen_shli_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f));
+        break;
+
+    case 0x01:    /*l.srli*/
+        LOG_DIS("l.srli r%d, r%d, %d\n", rd, ra, L6);
+        tcg_gen_shri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f));
+        break;
+
+    case 0x02:    /*l.srai*/
+        LOG_DIS("l.srai r%d, r%d, %d\n", rd, ra, L6);
+        tcg_gen_sari_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f)); break;
+
+    case 0x03:    /*l.rori*/
+        LOG_DIS("l.rori r%d, r%d, %d\n", rd, ra, L6);
+        tcg_gen_rotri_tl(cpu_R[rd], cpu_R[ra], (L6 & 0x1f));
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+}
+
+static void dec_M(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    uint32_t rd;
+    uint32_t K16;
+    op0 = field(insn, 16, 1);
+    rd = field(insn, 21, 5);
+    K16 = field(insn, 0, 16);
+
+    switch (op0) {
+    case 0x0:    /*l.movhi*/
+        LOG_DIS("l.movhi  r%d, %d\n", rd, K16);
+        tcg_gen_movi_tl(cpu_R[rd], (K16 << 16));
+        break;
+
+    case 0x1:    /*l.macrc*/
+        LOG_DIS("l.macrc  r%d\n", rd);
+        tcg_gen_mov_tl(cpu_R[rd], maclo);
+        tcg_gen_movi_tl(maclo, 0x0);
+        tcg_gen_movi_tl(machi, 0x0);
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+}
+
+static void dec_comp(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    uint32_t ra, rb;
+
+    op0 = field(insn, 21, 5);
+    ra = field(insn, 16, 5);
+    rb = field(insn, 11, 5);
+
+    tcg_gen_movi_i32(env_btaken, 0x0);
+    /* unsigned integers  */
+    tcg_gen_ext32u_tl(cpu_R[ra], cpu_R[ra]);
+    tcg_gen_ext32u_tl(cpu_R[rb], cpu_R[rb]);
+
+    switch (op0) {
+    case 0x0:    /*l.sfeq*/
+        LOG_DIS("l.sfeq  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x1:    /*l.sfne*/
+        LOG_DIS("l.sfne  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_NE, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x2:    /*l.sfgtu*/
+        LOG_DIS("l.sfgtu  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x3:    /*l.sfgeu*/
+        LOG_DIS("l.sfgeu  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x4:    /*l.sfltu*/
+        LOG_DIS("l.sfltu  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x5:    /*l.sfleu*/
+        LOG_DIS("l.sfleu  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0xa:    /*l.sfgts*/
+        LOG_DIS("l.sfgts  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_GT, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0xb:    /*l.sfges*/
+        LOG_DIS("l.sfges  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_GE, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0xc:    /*l.sflts*/
+        LOG_DIS("l.sflts  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_LT, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0xd:    /*l.sfles*/
+        LOG_DIS("l.sfles  r%d, r%d\n", ra, rb);
+        tcg_gen_setcond_tl(TCG_COND_LE, env_btaken, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+    wb_SR_F();
+}
+
+static void dec_compi(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    uint32_t ra, I16;
+
+    op0 = field(insn, 21, 5);
+    ra = field(insn, 16, 5);
+    I16 = field(insn, 0, 16);
+
+    tcg_gen_movi_i32(env_btaken, 0x0);
+    I16 = sign_extend(I16, 16);
+
+    switch (op0) {
+    case 0x0:    /*l.sfeqi*/
+        LOG_DIS("l.sfeqi  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_EQ, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0x1:    /*l.sfnei*/
+        LOG_DIS("l.sfnei  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_NE, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0x2:    /*l.sfgtui*/
+        LOG_DIS("l.sfgtui  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_GTU, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0x3:    /*l.sfgeui*/
+        LOG_DIS("l.sfgeui  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_GEU, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0x4:    /*l.sfltui*/
+        LOG_DIS("l.sfltui  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_LTU, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0x5:    /*l.sfleui*/
+        LOG_DIS("l.sfleui  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_LEU, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0xa:    /*l.sfgtsi*/
+        LOG_DIS("l.sfgtsi  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_GT, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0xb:    /*l.sfgesi*/
+        LOG_DIS("l.sfgesi  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_GE, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0xc:    /*l.sfltsi*/
+        LOG_DIS("l.sfltsi  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_LT, env_btaken, cpu_R[ra], I16);
+        break;
+
+    case 0xd:    /*l.sflesi*/
+        LOG_DIS("l.sflesi  r%d, %d\n", ra, I16);
+        tcg_gen_setcondi_tl(TCG_COND_LE, env_btaken, cpu_R[ra], I16);
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+    wb_SR_F();
+}
+
+static void dec_sys(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    /*uint32_t K16;*/
+    op0 = field(insn, 16, 8);
+    /*K16 = field(insn, 0, 16);*/
+
+    switch (op0) {
+    case 0x000:  /*l.sys*/
+        /*LOG_DIS("l.sys %d\n", K16);*/
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        gen_exception(dc, EXCP_SYSCALL);
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+
+    case 0x100:  /*l.trap*/
+        /*LOG_DIS("l.trap %d\n", K16);*/
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        gen_exception(dc, EXCP_TRAP);
+        break;
+
+    case 0x300:  /*l.csync*/
+        LOG_DIS("l.csync\n");
+        break;
+
+    case 0x200:  /*l.msync*/
+        LOG_DIS("l.msync\n");
+        break;
+
+    case 0x270:  /*l.psync*/
+        LOG_DIS("l.psync\n");
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+}
+
+static void dec_float(DisasContext *dc, CPUOpenRISCState *env, uint32_t insn)
+{
+    uint32_t op0;
+    uint32_t ra, rb, rd;
+    op0 = field(insn, 0, 8);
+    ra = field(insn, 16, 5);
+    rb = field(insn, 11, 5);
+    rd = field(insn, 21, 5);
+
+    switch (op0) {
+    case 0x10:    /*lf.add.d*/
+        LOG_DIS("lf.add.d r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_add_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x00:    /*lf.add.s*/
+        LOG_DIS("lf.add.s r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_add_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x11:    /*lf.sub.d*/
+        LOG_DIS("lf.sub.d r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_sub_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x01:    /*lf.sub.s*/
+        LOG_DIS("lf.sub.s r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_sub_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x12:    /*lf.mul.d*/
+        LOG_DIS("lf.mul.d r%d, r%d, r%d\n", rd, ra, rb);
+        if (ra != 0 && rb != 0) {
+            gen_helper_float_mul_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        } else {
+            tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF);
+            tcg_gen_movi_i64(cpu_R[rd], 0x0);
+        }
+        break;
+
+    case 0x02:    /*lf.mul.s*/
+        LOG_DIS("lf.mul.s r%d, r%d, r%d\n", rd, ra, rb);
+        if (ra != 0 && rb != 0) {
+            gen_helper_float_mul_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        } else {
+            tcg_gen_ori_tl(fpcsr, fpcsr, FPCSR_ZF);
+            tcg_gen_movi_i32(cpu_R[rd], 0x0);
+        }
+        break;
+
+    case 0x13:    /*lf.div.d*/
+        LOG_DIS("lf.div.d r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_div_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x03:    /*lf.div.s*/
+        LOG_DIS("lf.div.s r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_div_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x14:    /*lf.itof.d*/
+        LOG_DIS("lf.itof r%d, r%d\n", rd, ra);
+        gen_helper_itofd(cpu_R[rd], cpu_env, cpu_R[ra]);
+        break;
+
+    case 0x04:    /*lf.itof.s*/
+        LOG_DIS("lf.itof r%d, r%d\n", rd, ra);
+        gen_helper_itofs(cpu_R[rd], cpu_env, cpu_R[ra]);
+        break;
+
+    case 0x15:    /*lf.ftoi.d*/
+        LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra);
+        gen_helper_ftoid(cpu_R[rd], cpu_env, cpu_R[ra]);
+        break;
+
+    case 0x05:    /*lf.ftoi.s*/
+        LOG_DIS("lf.ftoi r%d, r%d\n", rd, ra);
+        gen_helper_ftois(cpu_R[rd], cpu_env, cpu_R[ra]);
+        break;
+
+    case 0x16:    /*lf.rem.d*/
+        LOG_DIS("lf.rem.d r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_rem_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x06:    /*lf.rem.s*/
+        LOG_DIS("lf.rem.s r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_rem_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x17:    /*lf.madd.d*/
+        LOG_DIS("lf.madd.d r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_muladd_d(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x07:    /*lf.madd.s*/
+        LOG_DIS("lf.madd.s r%d, r%d, r%d\n", rd, ra, rb);
+        gen_helper_float_muladd_s(cpu_R[rd], cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x18:    /*lf.sfeq.d*/
+        LOG_DIS("lf.sfeq.d r%d, r%d\n", ra, rb);
+        gen_helper_float_eq_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x08:    /*lf.sfeq.s*/
+        LOG_DIS("lf.sfeq.s r%d, r%d\n", ra, rb);
+        gen_helper_float_eq_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x19:    /*lf.sfne.d*/
+        LOG_DIS("lf.sfne.d r%d, r%d\n", ra, rb);
+        gen_helper_float_ne_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x09:    /*lf.sfne.s*/
+        LOG_DIS("lf.sfne.s r%d, r%d\n", ra, rb);
+        gen_helper_float_ne_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x1a:    /*lf.sfgt.d*/
+        LOG_DIS("lf.sfgt.d r%d, r%d\n", ra, rb);
+        gen_helper_float_gt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x0a:    /*lf.sfgt.s*/
+        LOG_DIS("lf.sfgt.s r%d, r%d\n", ra, rb);
+        gen_helper_float_gt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x1b:    /*lf.sfge.d*/
+        LOG_DIS("lf.sfge.d r%d, r%d\n", ra, rb);
+        gen_helper_float_ge_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x0b:    /*lf.sfge.s*/
+        LOG_DIS("lf.sfge.s r%d, r%d\n", ra, rb);
+        gen_helper_float_ge_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x1c:    /*lf.sflt.d*/
+        LOG_DIS("lf.sflt.d r%d, r%d\n", ra, rb);
+        gen_helper_float_lt_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x0c:    /*lf.sflt.s*/
+        LOG_DIS("lf.sflt.s r%d, r%d\n", ra, rb);
+        gen_helper_float_lt_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x1d:    /*lf.sfle.d*/
+        LOG_DIS("lf.sfle.d r%d, r%d\n", ra, rb);
+        gen_helper_float_le_d(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    case 0x0d:    /*lf.sfle.s*/
+        LOG_DIS("lf.sfle.s r%d, r%d\n", ra, rb);
+        gen_helper_float_le_s(env_btaken, cpu_env, cpu_R[ra], cpu_R[rb]);
+        break;
+
+    default:
+        gen_illegal_exception(dc);
+        break;
+    }
+    wb_SR_F();
+}
+
+static void disas_openrisc_insn(DisasContext *dc, CPUOpenRISCState *env)
+{
+    uint32_t op0;
+    uint32_t insn;
+    insn = cpu_ldl_code(env, dc->pc);
+    op0 = field(insn, 26, 6);
+
+    switch (op0) {
+    case 0x06:
+        dec_M(dc, env, insn);
+        break;
+
+    case 0x08:
+        dec_sys(dc, env, insn);
+        break;
+
+    case 0x2e:
+        dec_logic(dc, env, insn);
+        break;
+
+    case 0x2f:
+        dec_compi(dc, env, insn);
+        break;
+
+    case 0x31:
+        dec_mac(dc, env, insn);
+        break;
+
+    case 0x32:
+        dec_float(dc, env, insn);
+        break;
+
+    case 0x38:
+        dec_calc(dc, env, insn);
+        break;
+
+    case 0x39:
+        dec_comp(dc, env, insn);
+        break;
+
+    default:
+        dec_misc(dc, env, insn);
+        break;
+    }
+}
+
+static void check_breakpoint(CPUOpenRISCState *env, DisasContext *dc)
+{
+    CPUBreakpoint *bp;
+
+    if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_tl(cpu_pc, dc->pc);
+                gen_exception(dc, EXCP_DEBUG);
+                dc->is_jmp = DISAS_UPDATE;
+            }
+        }
+    }
 }
 
 static inline void gen_intermediate_code_internal(CPUOpenRISCState *env,
                                                   TranslationBlock *tb,
                                                   int search_pc)
 {
+    struct DisasContext ctx, *dc = &ctx;
+    uint16_t *gen_opc_end;
+    uint32_t pc_start;
+    int j, k;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    qemu_log_try_set_file(stderr);
+
+    pc_start = tb->pc;
+    dc->env = env;
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    dc->is_jmp = DISAS_NEXT;
+    dc->ppc = pc_start;
+    dc->pc = pc_start;
+    dc->mem_idx = cpu_mmu_index(env);
+    dc->synced_flags = dc->tb_flags = tb->flags;
+    dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
+    dc->singlestep_enabled = env->singlestep_enabled;
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("-----------------------------------------\n");
+        log_cpu_state(env, 0);
+    }
+
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    k = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+
+    gen_icount_start();
+
+    do {
+        check_breakpoint(env, dc);
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (k < j) {
+                k++;
+                while (k < j) {
+                    gen_opc_instr_start[k++] = 0;
+                }
+            }
+            gen_opc_pc[k] = dc->pc;
+            gen_opc_instr_start[k] = 1;
+            gen_opc_icount[k] = num_insns;
+        }
+
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
+            tcg_gen_debug_insn_start(dc->pc);
+        }
+
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+        dc->ppc = dc->pc - 4;
+        dc->npc = dc->pc + 4;
+        tcg_gen_movi_tl(cpu_ppc, dc->ppc);
+        tcg_gen_movi_tl(cpu_npc, dc->npc);
+        disas_openrisc_insn(dc, env);
+        dc->pc = dc->npc;
+        num_insns++;
+        /* delay slot */
+        if (dc->delayed_branch) {
+            dc->delayed_branch--;
+            if (!dc->delayed_branch) {
+                dc->tb_flags &= ~D_FLAG;
+                gen_sync_flags(dc);
+                tcg_gen_mov_tl(cpu_pc, jmp_pc);
+                tcg_gen_mov_tl(cpu_npc, jmp_pc);
+                tcg_gen_movi_tl(jmp_pc, 0);
+                tcg_gen_exit_tb(0);
+                dc->is_jmp = DISAS_JUMP;
+                break;
+            }
+        }
+    } while (!dc->is_jmp
+             && gen_opc_ptr < gen_opc_end
+             && !env->singlestep_enabled
+             && !singlestep
+             && (dc->pc < next_page_start)
+             && num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+    if (dc->is_jmp == DISAS_NEXT) {
+        dc->is_jmp = DISAS_UPDATE;
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+    }
+    if (unlikely(env->singlestep_enabled)) {
+        if (dc->is_jmp == DISAS_NEXT) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc);
+        }
+        gen_exception(dc, EXCP_DEBUG);
+    } else {
+        switch (dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_goto_tb(dc, 0, dc->pc);
+            break;
+        default:
+        case DISAS_JUMP:
+            break;
+        case DISAS_UPDATE:
+            /* indicate that the hash table must be used
+               to find the next TB */
+            tcg_gen_exit_tb(0);
+            break;
+        case DISAS_TB_JUMP:
+            /* nothing more to generate */
+            break;
+        }
+    }
+
+    gen_icount_end(tb, num_insns);
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        k++;
+        while (k <= j) {
+            gen_opc_instr_start[k++] = 0;
+        }
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("\n");
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\nisize=%d osize=%td\n",
+            dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+    }
+#endif
 }
 
 void gen_intermediate_code(CPUOpenRISCState *env, struct TranslationBlock *tb)