diff mbox

[v2] target-tilegx: Execute _start and reach to __libc_start_main successfully

Message ID BLU436-SMTP260F2B28BEB5B37A4B25D8AB9060@phx.gbl
State New
Headers show

Commit Message

Chen Gang March 12, 2015, 4:06 p.m. UTC
Tilegx Qemu can decode bundle, disassemble code, and generate tcg code
for 1st TB block (__start). Then directly jump to __libc_start_main (2nd
TB block).

Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>
---
 target-tilegx/cpu-qom.h   |    2 +
 target-tilegx/cpu.c       |    4 -
 target-tilegx/cpu.h       |   22 +-
 target-tilegx/translate.c | 1255 ++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 1263 insertions(+), 20 deletions(-)

Comments

Richard Henderson March 13, 2015, 6:20 p.m. UTC | #1
On 03/12/2015 09:06 AM, Chen Gang wrote:
> +#define TILEGX_GEN_SAVE_PREP(rdst) \
> +    dc->tmp_regcur->idx = rdst; \
> +    dc->tmp_regcur->val = tcg_temp_new_i64();
> +
> +#define TILEGX_GEN_SAVE_TMP_1(func, rdst, x1) \
> +    TILEGX_GEN_SAVE_PREP(rdst) \
> +    func(dc->tmp_regcur->val, x1);
> +
> +#define TILEGX_GEN_SAVE_TMP_2(func, rdst, x1, x2) \
> +    TILEGX_GEN_SAVE_PREP(rdst) \
> +    func(dc->tmp_regcur->val, x1, x2);
> +
> +#define TILEGX_GEN_SAVE_TMP_3(func, rdst, x1, x2, x3) \
> +    TILEGX_GEN_SAVE_PREP(rdst) \
> +    func(dc->tmp_regcur->val, x1, x2, x3);

Again, I told you to get rid of all of these macros.  I even suggested how to
do it, using a helper function:

static TCGv dest_gr(DisasContext *dc, uint8_t rdst)
{
    DisasContextTemp *tmp = dc->tmp_regcur;
    tmp->idx = rdst;
    tmp->val = tcg_temp_new_i64();
    return tmp->val;
}

> +static const char *reg_names[] = {

Again, const char * const reg_names.

> +/* This is the state at translation time.  */
> +typedef struct DisasContext {
> +    uint64_t pc;                   /* Current pc */
> +    uint64_t exception;            /* Current exception, 0 means empty */
> +
> +    TCGv zero;                     /* For zero register */
> +
> +    struct {
> +        unsigned char idx;         /* index */
> +        TCGv val;                  /* value */
> +    } *tmp_regcur,                 /* Current temporary registers */
> +    tmp_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; /* All temporary registers */

Again, I told you to name this structure.  See DisasContextTemp above.

> +static void gen_shl16insli(struct DisasContext *dc,
> +                           uint8_t rdst, uint8_t rsrc, uint16_t uimm16)
> +{
> +    TCGv_i64 tmp = tcg_temp_new_i64();
> +
> +    qemu_log("shl16insli r%d, r%d, %llx\n", rdst, rsrc, (long long)uimm16);
> +    tcg_gen_shli_i64(tmp, load_gr(dc, rsrc), 16);
> +    TILEGX_GEN_SAVE_TMP_2(tcg_gen_ori_i64, rdst, tmp, uimm16);
> +    tcg_temp_free_i64(tmp);

Again, you don't need the temporary here, since the one you will have created
with dest_gr is sufficient.

> +static void gen_ld(struct DisasContext *dc, uint8_t rdst, uint8_t rsrc)
> +{
> +    qemu_log("ld r%d, r%d\n", rdst, rsrc);
> +    tcg_gen_qemu_ld_i64(load_gr(dc, rdst), load_gr(dc, rsrc),
> +                        MMU_USER_IDX, MO_LEQ);

You're incorrectly loading into a source temporary.  You need to load into a
temporary created by dest_gr.

> +    /* for tcg_gen_qemu_st_i64, rsrc and rdst are reverted */
> +    tcg_gen_qemu_st_i64(load_gr(dc, rsrc), load_gr(dc, rdst),
> +                        MMU_USER_IDX, MO_LEQ);

Huh?  The address is always the second argument to tcg_gen_qemu_st_i64.
It would also probably be better if you named these arguments properly: there
is no "rdst" for a store instruction.  They're called SrcA and SrcB in the
architecture manual.

> +static void decode_insns_y0_10(struct DisasContext *dc,
> +                               tilegx_bundle_bits bundle)
> +{
> +    uint8_t rsrc, rsrcb, rdst;
> +
> +    if (get_RRROpcodeExtension_Y0(bundle) == 2) {

Use the proper symbol, not the number 2.
Which in this case is OR_RRR_5_OPCODE_Y0.

There is a very simple pattern to the naming in opcode_tilegx.h.
The symbols are very easy to look up.

> +        rdst = (uint8_t)get_Dest_Y0(bundle);
> +        rsrc = (uint8_t)get_SrcA_Y0(bundle);
> +        rsrcb = (uint8_t)get_SrcB_Y0(bundle);
> +        /* move Dest, SrcA */
> +        if (rsrcb == TILEGX_R_ZERO) {
> +            gen_move(dc, rdst, rsrc);
> +            return;
> +        }

I insist that you *not* special case these pseudo instructions from section
4.1.15, at least to start with.  It will be fantastically easier to review if
we see the symbolic opcode name followed by tcg functions bearing the same name.

Compare the code that you wrote with the following:

static void decode_rrr_5_opcode_y0(DisasContext *dc, tilegx_bundle_bits bundle)
{
  unsigned rsrca = get_SrcA_Y0(bundle);
  unsigned rsrcb = get_SrcB_Y0(bundle);
  unsigned rdest = get_Dest_Y0(bundle);
  unsigned ext = get_RRROpcodeExtension_Y0(bundle);

  switch (ext) {
  case OR_RRR_5_OPCODE_Y0:
    gen_or(rdest, rsrca, rsrcb);
    break;

  default:
    qemu_log_mask(LOG_UNIMP, "UNIMP rrr_5_opcode_y0, extension %d\n", ext);
    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
    break;
  }
}

> +static void decode_insns_y1_1(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)
> +{
> +    uint8_t rsrc = (uint8_t)get_SrcA_Y1(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_Y1(bundle);
> +    int8_t imm8 = (int8_t)get_Imm8_Y1(bundle);
> +
> +    gen_addi(dc, rdst, rsrc, imm8);
> +}

I think the naming on these functions should be better.  "y1_1" does not tell
me much.  Better is to name them after the symbol in opcode_tilegx.h.  In this
case the name would be decode_addi_opcode_y1.

> +static void decode_insns_y1_7(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_rrr_1_opcode_y1.

> +{
> +    /* fnop */
> +    if ((get_RRROpcodeExtension_Y1(bundle) == 0x03)

UNARY_RRR_1_OPCODE_Y1

> +        && (get_UnaryOpcodeExtension_Y1(bundle) == 0x08)

FNOP_UNARY_OPCODE_Y1

> +static void decode_insns_x0_1(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_addli_opcode_x0

> +{
> +    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
> +    int16_t imm16 = (int16_t)get_Imm16_X0(bundle);
> +
> +    /* moveli Dest, Imm16 */
> +    if (rsrc == TILEGX_R_ZERO) {

No special case for zero.  Just do tcg_gen_addi_tl.

> +    qemu_log("in x0_1, unimplement %16.16llx\n", bundle);
> +    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
> +}

which means there's nothing unimplemented.  See how much extra work you're
making for yourself?

> +static void decode_insns_x0_4(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_imm8_opcode_x0

> +    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
> +    int8_t imm8 = (int8_t)get_Imm8_X0(bundle);
> +
> +    switch (get_Imm8OpcodeExtension_X0(bundle)) {
> +    /* addi Dest, SrcA, Imm8 */
> +    case 0x01:

ADDI_IMM8_OPCODE_X0.  The comment is then obvious and superfluous.

> +        gen_addi(dc, rdst, rsrc, imm8);
> +        return;
> +    /* andi Dest, SrcA, Imm8 */
> +    case 0x03:

ANDI_IMM8_OPCODE_X0

> +static void decode_insns_x0_5(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_rrr_0_opcode_x0

> +{
> +    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
> +
> +    switch (get_RRROpcodeExtension_X0(bundle)) {
> +    case 0x03:
> +        /* add, Dest, SrcA, SrcB */

ADD_RRR_0_OPCODE_X0

> +        gen_add(dc, rdst, rsrc, (uint8_t)get_SrcB_X0(bundle));
> +        return;
> +    case 0x52:
> +        /* fnop */

UNARY_RRR_0_OPCODE_X0.

> +        if ((get_UnaryOpcodeExtension_X0(bundle) == 0x03) && !rsrc && !rdst) {

FNOP_UNARY_OPCODE_X0.  There are enough of these it's probably worth splitting
out decode of this to its own function.

> +static void decode_insns_x0_7(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_shl16insli_opcode_x0

> +static void decode_insns_x1_0(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_addli_opcode_x1

> +{
> +    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
> +    int16_t imm16 = (int16_t)get_Imm16_X1(bundle);
> +
> +    /* moveli Dest, Imm16 */
> +    if (rsrc == TILEGX_R_ZERO) {
> +        gen_moveli(dc, rdst, imm16);
> +        return;
> +    }
> +    qemu_log("in x1_0, unimplement %16.16llx\n", bundle);
> +    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;

Again, no special case for R_ZERO.  Again, just implement the add.

> +static void decode_insns_x1_3(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_imm8_opcode_x1

> +{
> +    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
> +    int8_t imm8 = (int8_t)get_Imm8_X1(bundle);
> +
> +    /* addi Dest, SrcA, Imm8 */
> +    if (get_Imm8OpcodeExtension_X1(bundle) == 0x01) {

ADDI_IMM8_OPCODE_X1

> +static void decode_insns_x1_5(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_rrr_0_opcode_x1

> +{
> +    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
> +    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
> +
> +    switch (get_RRROpcodeExtension_X1(bundle)) {
> +    case 0x03:
> +        /* add Dest, SrcA, SrcB */

ADD_RRR_0_OPCODE_X1

> +        gen_add(dc, rdst, rsrc, (uint8_t)get_SrcB_X1(bundle));
> +        return;
> +    case 0x35:

UNARY_RRR_0_OPCODE_X1

> +        switch (get_UnaryOpcodeExtension_X1(bundle)) {
> +        case 0x0e:
> +             /* jr SrcA */

JR_UNARY_OPCODE_X1

> +             if (!rdst) {
> +                 gen_jr(dc, rsrc);
> +                 return;
> +             }
> +             break;
> +        case 0x1e:
> +            /* lnk Dest */

LNK_UNARY_OPCODE_X1

> +static void decode_insns_x1_7(struct DisasContext *dc,
> +                              tilegx_bundle_bits bundle)

decode_shl16insli_opcode

> +/* by "grep _OPCODE_X0 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
> +static TileGXDecodeInsn decode_insns_x0[] = {

These tables are both pointless and incorrect.

Note that the Opcode_X0 field is only 3 bits wide.  This should have been your
first hint that having 165 entries in the table could not be right.

> +    decode_insns_x0_1,  /* 1, ADDI_IMM8_OPCODE_X0
> +                              ADDLI_OPCODE_X0
> +                              ADDXSC_RRR_0_OPCODE_X0
> +                              CNTLZ_UNARY_OPCODE_X0
> +                              ROTLI_SHIFT_OPCODE_X0 */

ADDI_IMM8_OPCODE_X0 does not come from get_Opcode_X0, but from
get_Imm8OpcodeExtension_X0.  ADDXSC_RRR_0_OPCODE_X0 does not come from
get_Opcode_X0, but from get_RRROpcodeExtension_X0.  Etc.


> +static void translate_x0(struct DisasContext *dc, tilegx_bundle_bits bundle)
> +{
> +    unsigned int opcode = get_Opcode_X0(bundle);
> +
> +    if (opcode > TILEGX_OPCODE_MAX_X0) {
> +        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
> +        qemu_log("unknown x0 opcode: %u for bundle: %16.16llx\n",
> +                 opcode, bundle);
> +        return;
> +    }
> +    if (!decode_insns_x0[opcode]) {
> +        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
> +        qemu_log("unimplement x0 opcode: %u for bundle: %16.16llx\n",
> +                 opcode, bundle);
> +        return;
> +    }
> +
> +    dc->tmp_regcur = dc->tmp_regs + 0;
> +    decode_insns_x0[opcode](dc, bundle);

Thus I think this function should be written

static void decode_x0(DisasContext *dc, tilegx_bundle_bits bundle)
{
    unsigned int opcode = get_Opcode_X0(bundle);
    switch (opcode) {
    case ADDLI_OPCODE_X0:
        decode_addli_opcode_x0(dc, bundle);
        break;
    case RRR_0_opcode_X0:
        decode_rrr_0_opcode_x0(dc, bundle);
        break;
    ...
    default:
        qemu_log_mask(LOG_UNIMP, "UNIMP x0, opcode %d\n", opcode);
        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
        break;
    }
}

> +static void translate_x1(struct DisasContext *dc, tilegx_bundle_bits bundle)
> +static void translate_y0(struct DisasContext *dc, tilegx_bundle_bits bundle)
> +static void translate_y1(struct DisasContext *dc, tilegx_bundle_bits bundle)
> +static void translate_y2(struct DisasContext *dc, tilegx_bundle_bits bundle)

And similarly for these others.


r~
Chen Gang March 13, 2015, 11:07 p.m. UTC | #2
Firstly, thank you very much for your reviewing, and I shall send patch
v3 within this week end (2015-03-15).


On 3/14/15 02:20, Richard Henderson wrote:
> On 03/12/2015 09:06 AM, Chen Gang wrote:
>> +#define TILEGX_GEN_SAVE_PREP(rdst) \
>> +    dc->tmp_regcur->idx = rdst; \
>> +    dc->tmp_regcur->val = tcg_temp_new_i64();
>> +
>> +#define TILEGX_GEN_SAVE_TMP_1(func, rdst, x1) \
>> +    TILEGX_GEN_SAVE_PREP(rdst) \
>> +    func(dc->tmp_regcur->val, x1);
>> +
>> +#define TILEGX_GEN_SAVE_TMP_2(func, rdst, x1, x2) \
>> +    TILEGX_GEN_SAVE_PREP(rdst) \
>> +    func(dc->tmp_regcur->val, x1, x2);
>> +
>> +#define TILEGX_GEN_SAVE_TMP_3(func, rdst, x1, x2, x3) \
>> +    TILEGX_GEN_SAVE_PREP(rdst) \
>> +    func(dc->tmp_regcur->val, x1, x2, x3);
> 
> Again, I told you to get rid of all of these macros.  I even suggested how to
> do it, using a helper function:
> 
> static TCGv dest_gr(DisasContext *dc, uint8_t rdst)
> {
>     DisasContextTemp *tmp = dc->tmp_regcur;
>     tmp->idx = rdst;
>     tmp->val = tcg_temp_new_i64();
>     return tmp->val;
> }
> 
>> +static const char *reg_names[] = {
> 
> Again, const char * const reg_names.
> 
>> +/* This is the state at translation time.  */
>> +typedef struct DisasContext {
>> +    uint64_t pc;                   /* Current pc */
>> +    uint64_t exception;            /* Current exception, 0 means empty */
>> +
>> +    TCGv zero;                     /* For zero register */
>> +
>> +    struct {
>> +        unsigned char idx;         /* index */
>> +        TCGv val;                  /* value */
>> +    } *tmp_regcur,                 /* Current temporary registers */
>> +    tmp_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; /* All temporary registers */
> 
> Again, I told you to name this structure.  See DisasContextTemp above.
> 
>> +static void gen_shl16insli(struct DisasContext *dc,
>> +                           uint8_t rdst, uint8_t rsrc, uint16_t uimm16)
>> +{
>> +    TCGv_i64 tmp = tcg_temp_new_i64();
>> +
>> +    qemu_log("shl16insli r%d, r%d, %llx\n", rdst, rsrc, (long long)uimm16);
>> +    tcg_gen_shli_i64(tmp, load_gr(dc, rsrc), 16);
>> +    TILEGX_GEN_SAVE_TMP_2(tcg_gen_ori_i64, rdst, tmp, uimm16);
>> +    tcg_temp_free_i64(tmp);
> 
> Again, you don't need the temporary here, since the one you will have created
> with dest_gr is sufficient.
> 

Oh, sorry for my carelessness for the 'Again' above.


>> +static void gen_ld(struct DisasContext *dc, uint8_t rdst, uint8_t rsrc)
>> +{
>> +    qemu_log("ld r%d, r%d\n", rdst, rsrc);
>> +    tcg_gen_qemu_ld_i64(load_gr(dc, rdst), load_gr(dc, rsrc),
>> +                        MMU_USER_IDX, MO_LEQ);
> 
> You're incorrectly loading into a source temporary.  You need to load into a
> temporary created by dest_gr.
> 

OK, thanks.

>> +    /* for tcg_gen_qemu_st_i64, rsrc and rdst are reverted */
>> +    tcg_gen_qemu_st_i64(load_gr(dc, rsrc), load_gr(dc, rdst),
>> +                        MMU_USER_IDX, MO_LEQ);
> 
> Huh?  The address is always the second argument to tcg_gen_qemu_st_i64.
> It would also probably be better if you named these arguments properly: there
> is no "rdst" for a store instruction.  They're called SrcA and SrcB in the
> architecture manual.
> 

OK, thanks. The comments is incorrect (misleading), and I will use SrcA
and SrcB.

>> +static void decode_insns_y0_10(struct DisasContext *dc,
>> +                               tilegx_bundle_bits bundle)
>> +{
>> +    uint8_t rsrc, rsrcb, rdst;
>> +
>> +    if (get_RRROpcodeExtension_Y0(bundle) == 2) {
> 
> Use the proper symbol, not the number 2.
> Which in this case is OR_RRR_5_OPCODE_Y0.
> 
> There is a very simple pattern to the naming in opcode_tilegx.h.
> The symbols are very easy to look up.
> 

OK, thanks.

>> +        rdst = (uint8_t)get_Dest_Y0(bundle);
>> +        rsrc = (uint8_t)get_SrcA_Y0(bundle);
>> +        rsrcb = (uint8_t)get_SrcB_Y0(bundle);
>> +        /* move Dest, SrcA */
>> +        if (rsrcb == TILEGX_R_ZERO) {
>> +            gen_move(dc, rdst, rsrc);
>> +            return;
>> +        }
> 
> I insist that you *not* special case these pseudo instructions from section
> 4.1.15, at least to start with.  It will be fantastically easier to review if
> we see the symbolic opcode name followed by tcg functions bearing the same name.
> 

OK, I will remove all pseudo instructions.

> Compare the code that you wrote with the following:
> 
> static void decode_rrr_5_opcode_y0(DisasContext *dc, tilegx_bundle_bits bundle)
> {
>   unsigned rsrca = get_SrcA_Y0(bundle);
>   unsigned rsrcb = get_SrcB_Y0(bundle);
>   unsigned rdest = get_Dest_Y0(bundle);
>   unsigned ext = get_RRROpcodeExtension_Y0(bundle);
> 
>   switch (ext) {
>   case OR_RRR_5_OPCODE_Y0:
>     gen_or(rdest, rsrca, rsrcb);
>     break;
> 
>   default:
>     qemu_log_mask(LOG_UNIMP, "UNIMP rrr_5_opcode_y0, extension %d\n", ext);
>     dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
>     break;
>   }
> }
>

OK, thank you for your sample above, it is valuable to me.

 
>> +static void decode_insns_y1_1(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
>> +{
>> +    uint8_t rsrc = (uint8_t)get_SrcA_Y1(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_Y1(bundle);
>> +    int8_t imm8 = (int8_t)get_Imm8_Y1(bundle);
>> +
>> +    gen_addi(dc, rdst, rsrc, imm8);
>> +}
> 
> I think the naming on these functions should be better.  "y1_1" does not tell
> me much.  Better is to name them after the symbol in opcode_tilegx.h.  In this
> case the name would be decode_addi_opcode_y1.
> 

OK, thanks.

>> +static void decode_insns_y1_7(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_rrr_1_opcode_y1.
> 
>> +{
>> +    /* fnop */
>> +    if ((get_RRROpcodeExtension_Y1(bundle) == 0x03)
> 
> UNARY_RRR_1_OPCODE_Y1
> 
>> +        && (get_UnaryOpcodeExtension_Y1(bundle) == 0x08)
> 
> FNOP_UNARY_OPCODE_Y1
> 
>> +static void decode_insns_x0_1(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_addli_opcode_x0
> 

OK, thanks

>> +{
>> +    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
>> +    int16_t imm16 = (int16_t)get_Imm16_X0(bundle);
>> +
>> +    /* moveli Dest, Imm16 */
>> +    if (rsrc == TILEGX_R_ZERO) {
> 
> No special case for zero.  Just do tcg_gen_addi_tl.
> 
>> +    qemu_log("in x0_1, unimplement %16.16llx\n", bundle);
>> +    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
>> +}
> 
> which means there's nothing unimplemented.  See how much extra work you're
> making for yourself?
> 

OK, thanks.

>> +static void decode_insns_x0_4(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_imm8_opcode_x0
> 
>> +    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
>> +    int8_t imm8 = (int8_t)get_Imm8_X0(bundle);
>> +
>> +    switch (get_Imm8OpcodeExtension_X0(bundle)) {
>> +    /* addi Dest, SrcA, Imm8 */
>> +    case 0x01:
> 
> ADDI_IMM8_OPCODE_X0.  The comment is then obvious and superfluous.
> 
>> +        gen_addi(dc, rdst, rsrc, imm8);
>> +        return;
>> +    /* andi Dest, SrcA, Imm8 */
>> +    case 0x03:
> 
> ANDI_IMM8_OPCODE_X0
> 
>> +static void decode_insns_x0_5(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_rrr_0_opcode_x0
> 
>> +{
>> +    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
>> +
>> +    switch (get_RRROpcodeExtension_X0(bundle)) {
>> +    case 0x03:
>> +        /* add, Dest, SrcA, SrcB */
> 
> ADD_RRR_0_OPCODE_X0
> 
>> +        gen_add(dc, rdst, rsrc, (uint8_t)get_SrcB_X0(bundle));
>> +        return;
>> +    case 0x52:
>> +        /* fnop */
> 
> UNARY_RRR_0_OPCODE_X0.
> 
>> +        if ((get_UnaryOpcodeExtension_X0(bundle) == 0x03) && !rsrc && !rdst) {
> 
> FNOP_UNARY_OPCODE_X0.

OK, thanks.

>                       There are enough of these it's probably worth splitting
> out decode of this to its own function.
> 

OK, I will add gen_fnop() for it.

>> +static void decode_insns_x0_7(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_shl16insli_opcode_x0
> 
>> +static void decode_insns_x1_0(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_addli_opcode_x1
> 
>> +{
>> +    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
>> +    int16_t imm16 = (int16_t)get_Imm16_X1(bundle);
>> +
>> +    /* moveli Dest, Imm16 */
>> +    if (rsrc == TILEGX_R_ZERO) {
>> +        gen_moveli(dc, rdst, imm16);
>> +        return;
>> +    }
>> +    qemu_log("in x1_0, unimplement %16.16llx\n", bundle);
>> +    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
> 
> Again, no special case for R_ZERO.  Again, just implement the add.
> 
>> +static void decode_insns_x1_3(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_imm8_opcode_x1
> 
>> +{
>> +    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
>> +    int8_t imm8 = (int8_t)get_Imm8_X1(bundle);
>> +
>> +    /* addi Dest, SrcA, Imm8 */
>> +    if (get_Imm8OpcodeExtension_X1(bundle) == 0x01) {
> 
> ADDI_IMM8_OPCODE_X1
> 
>> +static void decode_insns_x1_5(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_rrr_0_opcode_x1
> 
>> +{
>> +    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
>> +    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
>> +
>> +    switch (get_RRROpcodeExtension_X1(bundle)) {
>> +    case 0x03:
>> +        /* add Dest, SrcA, SrcB */
> 
> ADD_RRR_0_OPCODE_X1
> 
>> +        gen_add(dc, rdst, rsrc, (uint8_t)get_SrcB_X1(bundle));
>> +        return;
>> +    case 0x35:
> 
> UNARY_RRR_0_OPCODE_X1
> 
>> +        switch (get_UnaryOpcodeExtension_X1(bundle)) {
>> +        case 0x0e:
>> +             /* jr SrcA */
> 
> JR_UNARY_OPCODE_X1
> 
>> +             if (!rdst) {
>> +                 gen_jr(dc, rsrc);
>> +                 return;
>> +             }
>> +             break;
>> +        case 0x1e:
>> +            /* lnk Dest */
> 
> LNK_UNARY_OPCODE_X1
> 
>> +static void decode_insns_x1_7(struct DisasContext *dc,
>> +                              tilegx_bundle_bits bundle)
> 
> decode_shl16insli_opcode
>

OK, thanks.
 
>> +/* by "grep _OPCODE_X0 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
>> +static TileGXDecodeInsn decode_insns_x0[] = {
> 
> These tables are both pointless and incorrect.
> 
> Note that the Opcode_X0 field is only 3 bits wide.  This should have been your
> first hint that having 165 entries in the table could not be right.
> 

OK, thanks.

>> +    decode_insns_x0_1,  /* 1, ADDI_IMM8_OPCODE_X0
>> +                              ADDLI_OPCODE_X0
>> +                              ADDXSC_RRR_0_OPCODE_X0
>> +                              CNTLZ_UNARY_OPCODE_X0
>> +                              ROTLI_SHIFT_OPCODE_X0 */
> 
> ADDI_IMM8_OPCODE_X0 does not come from get_Opcode_X0, but from
> get_Imm8OpcodeExtension_X0.  ADDXSC_RRR_0_OPCODE_X0 does not come from
> get_Opcode_X0, but from get_RRROpcodeExtension_X0.  Etc.
> 

OK, thanks.

> 
>> +static void translate_x0(struct DisasContext *dc, tilegx_bundle_bits bundle)
>> +{
>> +    unsigned int opcode = get_Opcode_X0(bundle);
>> +
>> +    if (opcode > TILEGX_OPCODE_MAX_X0) {
>> +        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
>> +        qemu_log("unknown x0 opcode: %u for bundle: %16.16llx\n",
>> +                 opcode, bundle);
>> +        return;
>> +    }
>> +    if (!decode_insns_x0[opcode]) {
>> +        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
>> +        qemu_log("unimplement x0 opcode: %u for bundle: %16.16llx\n",
>> +                 opcode, bundle);
>> +        return;
>> +    }
>> +
>> +    dc->tmp_regcur = dc->tmp_regs + 0;
>> +    decode_insns_x0[opcode](dc, bundle);
> 
> Thus I think this function should be written
> 
> static void decode_x0(DisasContext *dc, tilegx_bundle_bits bundle)
> {
>     unsigned int opcode = get_Opcode_X0(bundle);
>     switch (opcode) {
>     case ADDLI_OPCODE_X0:
>         decode_addli_opcode_x0(dc, bundle);
>         break;
>     case RRR_0_opcode_X0:
>         decode_rrr_0_opcode_x0(dc, bundle);
>         break;
>     ...
>     default:
>         qemu_log_mask(LOG_UNIMP, "UNIMP x0, opcode %d\n", opcode);
>         dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENTED;
>         break;
>     }
> }
>

OK, thanks.
 
>> +static void translate_x1(struct DisasContext *dc, tilegx_bundle_bits bundle)
>> +static void translate_y0(struct DisasContext *dc, tilegx_bundle_bits bundle)
>> +static void translate_y1(struct DisasContext *dc, tilegx_bundle_bits bundle)
>> +static void translate_y2(struct DisasContext *dc, tilegx_bundle_bits bundle)
> 
> And similarly for these others.
> 

OK, thanks.


Thanks.
Richard Henderson March 14, 2015, 12:22 a.m. UTC | #3
On 03/13/2015 04:07 PM, Chen Gang wrote:
>> UNARY_RRR_0_OPCODE_X0.
>>
>>> +        if ((get_UnaryOpcodeExtension_X0(bundle) == 0x03) && !rsrc && !rdst) {
>>
>> FNOP_UNARY_OPCODE_X0.
> 
> OK, thanks.
> 
>>                       There are enough of these it's probably worth splitting
>> out decode of this to its own function.
>>
> 
> OK, I will add gen_fnop() for it.

I meant a function for decoding the unary opcodes, not fnop specifically.


r~
Chen Gang March 14, 2015, 2:36 a.m. UTC | #4
On 3/14/15 08:22, Richard Henderson wrote:
> On 03/13/2015 04:07 PM, Chen Gang wrote:
>>> UNARY_RRR_0_OPCODE_X0.
>>>
>>>> +        if ((get_UnaryOpcodeExtension_X0(bundle) == 0x03) && !rsrc && !rdst) {
>>>
>>> FNOP_UNARY_OPCODE_X0.
>>
>> OK, thanks.
>>
>>>                       There are enough of these it's probably worth splitting
>>> out decode of this to its own function.
>>>
>>
>> OK, I will add gen_fnop() for it.
> 
> I meant a function for decoding the unary opcodes, not fnop specifically.
> 

OK, thanks.
diff mbox

Patch

diff --git a/target-tilegx/cpu-qom.h b/target-tilegx/cpu-qom.h
index 4ee11e1..5615c3b 100644
--- a/target-tilegx/cpu-qom.h
+++ b/target-tilegx/cpu-qom.h
@@ -68,4 +68,6 @@  static inline TileGXCPU *tilegx_env_get_cpu(CPUTLGState *env)
 
 #define ENV_GET_CPU(e) CPU(tilegx_env_get_cpu(e))
 
+#define ENV_OFFSET offsetof(TileGXCPU, env)
+
 #endif
diff --git a/target-tilegx/cpu.c b/target-tilegx/cpu.c
index cf46b8b..8255fdc 100644
--- a/target-tilegx/cpu.c
+++ b/target-tilegx/cpu.c
@@ -69,10 +69,6 @@  static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp)
     tcc->parent_realize(dev, errp);
 }
 
-static void tilegx_tcg_init(void)
-{
-}
-
 static void tilegx_cpu_initfn(Object *obj)
 {
     CPUState *cs = CPU(obj);
diff --git a/target-tilegx/cpu.h b/target-tilegx/cpu.h
index 87dc56b..93e16c3 100644
--- a/target-tilegx/cpu.h
+++ b/target-tilegx/cpu.h
@@ -30,16 +30,21 @@ 
 #include "fpu/softfloat.h"
 
 /* TILE-Gx register alias */
-#define TILEGX_R_RE  0   /*  0 register, for function/syscall return value */
-#define TILEGX_R_NR  10  /* 10 register, for syscall number */
-#define TILEGX_R_BP  52  /* 52 register, optional frame pointer */
-#define TILEGX_R_TP  53  /* TP register, thread local storage data */
-#define TILEGX_R_SP  54  /* SP register, stack pointer */
-#define TILEGX_R_LR  55  /* LR register, may save pc, but it is not pc */
+#define TILEGX_R_RE    0   /*  0 register, for function/syscall return value */
+#define TILEGX_R_NR    10  /* 10 register, for syscall number */
+#define TILEGX_R_BP    52  /* 52 register, optional frame pointer */
+#define TILEGX_R_TP    53  /* TP register, thread local storage data */
+#define TILEGX_R_SP    54  /* SP register, stack pointer */
+#define TILEGX_R_LR    55  /* LR register, may save pc, but it is not pc */
+#define TILEGX_R_ZERO  63  /* Zero register, always zero */
+#define TILEGX_R_COUNT 56  /* Only 56 registers are really useful */
+#define TILEGX_R_NOREG 255 /* Invalid register value */
+
 
 typedef struct CPUTLGState {
-    uint64_t regs[56];
-    uint64_t pc;
+    uint64_t regs[TILEGX_R_COUNT]; /* Common used registers by outside */
+    uint64_t pc;                   /* Current pc */
+
     CPU_COMMON
 } CPUTLGState;
 
@@ -54,6 +59,7 @@  typedef struct CPUTLGState {
 
 #include "exec/cpu-all.h"
 
+void tilegx_tcg_init(void);
 int cpu_tilegx_exec(CPUTLGState *s);
 int cpu_tilegx_signal_handler(int host_signum, void *pinfo, void *puc);
 
diff --git a/target-tilegx/translate.c b/target-tilegx/translate.c
index 9aa82a9..ac6e6af 100644
--- a/target-tilegx/translate.c
+++ b/target-tilegx/translate.c
@@ -23,28 +23,1267 @@ 
 #include "disas/disas.h"
 #include "tcg-op.h"
 #include "exec/cpu_ldst.h"
+#include "opcode_tilegx.h"
+
+#define TILEGX_OPCODE_MAX_X0            164  /* include 164 */
+#define TILEGX_OPCODE_MAX_X1            107  /* include 107 */
+#define TILEGX_OPCODE_MAX_Y0             15  /* include 15 */
+#define TILEGX_OPCODE_MAX_Y1             15  /* include 15 */
+#define TILEGX_OPCODE_MAX_Y2              3  /* include 3 */
+
+#define TILEGX_EXCP_OPCODE_UNKNOWN      0x1
+#define TILEGX_EXCP_OPCODE_UNIMPLEMENT  0x2
+#define TILEGX_EXCP_REG_UNSUPPORTED     0x81
+
+#define TILEGX_GEN_SAVE_PREP(rdst) \
+    dc->tmp_regcur->idx = rdst; \
+    dc->tmp_regcur->val = tcg_temp_new_i64();
+
+#define TILEGX_GEN_SAVE_TMP_1(func, rdst, x1) \
+    TILEGX_GEN_SAVE_PREP(rdst) \
+    func(dc->tmp_regcur->val, x1);
+
+#define TILEGX_GEN_SAVE_TMP_2(func, rdst, x1, x2) \
+    TILEGX_GEN_SAVE_PREP(rdst) \
+    func(dc->tmp_regcur->val, x1, x2);
+
+#define TILEGX_GEN_SAVE_TMP_3(func, rdst, x1, x2, x3) \
+    TILEGX_GEN_SAVE_PREP(rdst) \
+    func(dc->tmp_regcur->val, x1, x2, x3);
+
+static TCGv_ptr cpu_env;
+static TCGv_i64 cpu_pc;
+static TCGv_i64 cpu_regs[TILEGX_R_COUNT];
+
+static const char *reg_names[] = {
+     "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",
+    "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+    "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+    "r48", "r49", "r50", "r51",  "bp",  "tp",  "sp",  "lr"
+};
+
+/* This is the state at translation time.  */
+typedef struct DisasContext {
+    uint64_t pc;                   /* Current pc */
+    uint64_t exception;            /* Current exception, 0 means empty */
+
+    TCGv zero;                     /* For zero register */
+
+    struct {
+        unsigned char idx;         /* index */
+        TCGv val;                  /* value */
+    } *tmp_regcur,                 /* Current temporary registers */
+    tmp_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; /* All temporary registers */
+
+    struct {
+        TCGCond cond;              /* Branch condition */
+        TCGv dest;                 /* pc jump destination, if will jump */
+        TCGv val1;                 /* Firt value for condition comparing */
+        TCGv val2;                 /* Second value for condition comparing */
+    } jmp;                         /* Jump object, only once in each TB block */
+} DisasContext;
+
+#include "exec/gen-icount.h"
+
+static TCGv_i64 load_zero(DisasContext *dc)
+{
+    if (TCGV_IS_UNUSED_I64(dc->zero)) {
+        dc->zero = tcg_const_i64(0);
+    }
+    return dc->zero;
+}
+
+static TCGv_i64 load_gr(DisasContext *dc, uint8_t reg)
+{
+    if (likely(reg < TILEGX_R_COUNT)) {
+        return cpu_regs[reg];
+    } else if (reg != TILEGX_R_ZERO) {
+        dc->exception = TILEGX_EXCP_REG_UNSUPPORTED;
+    }
+    return load_zero(dc);
+}
+
+static void gen_move(struct DisasContext *dc, uint8_t rdst, uint8_t rsrc)
+{
+    qemu_log("move r%u, r%u\n", rdst, rsrc);
+    TILEGX_GEN_SAVE_TMP_1(tcg_gen_mov_i64, rdst, load_gr(dc, rsrc));
+}
+
+static void gen_move_imm(struct DisasContext *dc, uint8_t rdst, int64_t imm)
+{
+    TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst, imm);
+}
+
+static void gen_moveli(struct DisasContext *dc, uint8_t rdst, int16_t imm16)
+{
+    qemu_log("moveli r%d, %d\n", rdst, imm16);
+    gen_move_imm(dc, rdst, (int64_t)imm16);
+}
+
+/*
+static void gen_movei(struct DisasContext *dc, uint8_t rdst, int8_t im8)
+{
+    qemu_log("movei r%d, %d\n", rdst, im8);
+    gen_move_imm(dc, rdst, (int64_t)im8);
+}
+*/
+
+static void gen_addimm(struct DisasContext *dc,
+                       uint8_t rdst, uint8_t rsrc, int64_t imm)
+{
+    TILEGX_GEN_SAVE_TMP_2(tcg_gen_addi_i64, rdst, load_gr(dc, rsrc), imm);
+}
+
+static void gen_addi(struct DisasContext *dc,
+                     uint8_t rdst, uint8_t rsrc, char imm8)
+{
+    qemu_log("addi r%d, r%d, %d\n", rdst, rsrc, imm8);
+    gen_addimm(dc, rdst, rsrc, (int64_t)imm8);
+}
+
+/*
+static void gen_addli(struct DisasContext *dc,
+                      uint8_t rdst, uint8_t rsrc, int16_t im16)
+{
+    qemu_log("addli r%d, r%d, %d\n", rdst, rsrc, im16);
+    gen_addimm(dc, rdst, rsrc, (int64_t)im16);
+}
+*/
+
+static void gen_add(struct DisasContext *dc,
+                    uint8_t rdst, uint8_t rsrc, uint8_t rsrcb)
+{
+    qemu_log("add r%d, r%d, r%d\n", rdst, rsrc, rsrcb);
+    TILEGX_GEN_SAVE_TMP_2(tcg_gen_add_i64, rdst,
+                          load_gr(dc, rsrc), load_gr(dc, rsrcb));
+}
+
+static void gen_andimm(struct DisasContext *dc,
+                       uint8_t rdst, uint8_t rsrc, int64_t imm)
+{
+    TILEGX_GEN_SAVE_TMP_2(tcg_gen_andi_i64, rdst, load_gr(dc, rsrc), imm);
+}
+
+static void gen_andi(struct DisasContext *dc,
+                     uint8_t rdst, uint8_t rsrc, char imm8)
+{
+    qemu_log("andi r%d, r%d, %d\n", rdst, rsrc, imm8);
+    gen_andimm(dc, rdst, rsrc, (int64_t)imm8);
+}
+
+static void gen_shl16insli(struct DisasContext *dc,
+                           uint8_t rdst, uint8_t rsrc, uint16_t uimm16)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    qemu_log("shl16insli r%d, r%d, %llx\n", rdst, rsrc, (long long)uimm16);
+    tcg_gen_shli_i64(tmp, load_gr(dc, rsrc), 16);
+    TILEGX_GEN_SAVE_TMP_2(tcg_gen_ori_i64, rdst, tmp, uimm16);
+    tcg_temp_free_i64(tmp);
+}
+
+static void gen_lnk(struct DisasContext *dc, uint8_t rdst)
+{
+    qemu_log("lnk r%d\n", rdst);
+    TILEGX_GEN_SAVE_TMP_1(tcg_gen_movi_i64, rdst,
+                          dc->pc + TILEGX_BUNDLE_SIZE_IN_BYTES);
+}
+
+static void gen_ld(struct DisasContext *dc, uint8_t rdst, uint8_t rsrc)
+{
+    qemu_log("ld r%d, r%d\n", rdst, rsrc);
+    tcg_gen_qemu_ld_i64(load_gr(dc, rdst), load_gr(dc, rsrc),
+                        MMU_USER_IDX, MO_LEQ);
+}
+
+static void gen_st(struct DisasContext *dc, uint8_t rdst, uint8_t rsrc)
+{
+    qemu_log("st r%d, r%d\n", rdst, rsrc);
+    /* for tcg_gen_qemu_st_i64, rsrc and rdst are reverted */
+    tcg_gen_qemu_st_i64(load_gr(dc, rsrc), load_gr(dc, rdst),
+                        MMU_USER_IDX, MO_LEQ);
+}
+
+static int gen_jr(struct DisasContext *dc, uint8_t rsrc)
+{
+    qemu_log("jr r%d\n", rsrc);
+
+    dc->jmp.dest = tcg_temp_new_i64();
+
+    dc->jmp.cond = TCG_COND_ALWAYS;
+    tcg_gen_mov_i64(dc->jmp.dest, load_gr(dc, rsrc));
+    return 0;
+}
+
+static void decode_insns_y0_10(struct DisasContext *dc,
+                               tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc, rsrcb, rdst;
+
+    if (get_RRROpcodeExtension_Y0(bundle) == 2) {
+        rdst = (uint8_t)get_Dest_Y0(bundle);
+        rsrc = (uint8_t)get_SrcA_Y0(bundle);
+        rsrcb = (uint8_t)get_SrcB_Y0(bundle);
+        /* move Dest, SrcA */
+        if (rsrcb == TILEGX_R_ZERO) {
+            gen_move(dc, rdst, rsrc);
+            return;
+        }
+    }
+    qemu_log("in y0_10, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+/* addi Dest, SrcA, Imm8 */
+static void decode_insns_y1_1(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_Y1(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_Y1(bundle);
+    int8_t imm8 = (int8_t)get_Imm8_Y1(bundle);
+
+    gen_addi(dc, rdst, rsrc, imm8);
+}
+
+static void decode_insns_y1_7(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    /* fnop */
+    if ((get_RRROpcodeExtension_Y1(bundle) == 0x03)
+        && (get_UnaryOpcodeExtension_Y1(bundle) == 0x08)
+        && !get_SrcA_Y1(bundle) && !get_Dest_Y1(bundle)) {
+        qemu_log("fnop\n");
+        return;
+    }
+    qemu_log("in y1_7, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+static void decode_insns_y2_3(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrca = (uint8_t)get_SrcA_Y2(bundle);
+    uint8_t rsrcbdst = (uint8_t)get_SrcBDest_Y2(bundle);
+
+    switch (get_Mode(bundle)) {
+    /* ld Dest, Src */
+    case 0x02:
+        gen_ld(dc, rsrcbdst, rsrca);
+        return;
+    /* st Dest, Src */
+    case 0x03:
+        gen_st(dc, rsrca, rsrcbdst);
+        return;
+    default:
+        qemu_log("in y2_3, unimplement %16.16llx\n", bundle);
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+    }
+}
+
+static void decode_insns_x0_1(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
+    int16_t imm16 = (int16_t)get_Imm16_X0(bundle);
+
+    /* moveli Dest, Imm16 */
+    if (rsrc == TILEGX_R_ZERO) {
+        gen_moveli(dc, rdst, imm16);
+        return;
+    }
+    qemu_log("in x0_1, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+static void decode_insns_x0_4(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
+    int8_t imm8 = (int8_t)get_Imm8_X0(bundle);
+
+    switch (get_Imm8OpcodeExtension_X0(bundle)) {
+    /* addi Dest, SrcA, Imm8 */
+    case 0x01:
+        gen_addi(dc, rdst, rsrc, imm8);
+        return;
+    /* andi Dest, SrcA, Imm8 */
+    case 0x03:
+        gen_andi(dc, rdst, rsrc, imm8);
+        return;
+    default:
+        qemu_log("in x0_4, unimplement %16.16llx\n", bundle);
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+    }
+}
+
+static void decode_insns_x0_5(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
+
+    switch (get_RRROpcodeExtension_X0(bundle)) {
+    case 0x03:
+        /* add, Dest, SrcA, SrcB */
+        gen_add(dc, rdst, rsrc, (uint8_t)get_SrcB_X0(bundle));
+        return;
+    case 0x52:
+        /* fnop */
+        if ((get_UnaryOpcodeExtension_X0(bundle) == 0x03) && !rsrc && !rdst) {
+            qemu_log("fnop\n");
+            return;
+        }
+        break;
+    default:
+        break;
+    }
+    qemu_log("in x0_5, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+static void decode_insns_x0_7(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X0(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X0(bundle);
+    uint16_t uimm16 = (uint16_t)get_Imm16_X0(bundle);
+
+    gen_shl16insli(dc, rdst, rsrc, uimm16);
+}
+
+static void decode_insns_x1_0(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
+    int16_t imm16 = (int16_t)get_Imm16_X1(bundle);
+
+    /* moveli Dest, Imm16 */
+    if (rsrc == TILEGX_R_ZERO) {
+        gen_moveli(dc, rdst, imm16);
+        return;
+    }
+    qemu_log("in x1_0, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+static void decode_insns_x1_3(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
+    int8_t imm8 = (int8_t)get_Imm8_X1(bundle);
+
+    /* addi Dest, SrcA, Imm8 */
+    if (get_Imm8OpcodeExtension_X1(bundle) == 0x01) {
+        gen_addi(dc, rdst, rsrc, imm8);
+        return;
+    }
+    qemu_log("in x1_3, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+static void decode_insns_x1_5(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
+
+    switch (get_RRROpcodeExtension_X1(bundle)) {
+    case 0x03:
+        /* add Dest, SrcA, SrcB */
+        gen_add(dc, rdst, rsrc, (uint8_t)get_SrcB_X1(bundle));
+        return;
+    case 0x35:
+        switch (get_UnaryOpcodeExtension_X1(bundle)) {
+        case 0x0e:
+             /* jr SrcA */
+             if (!rdst) {
+                 gen_jr(dc, rsrc);
+                 return;
+             }
+             break;
+        case 0x1e:
+            /* lnk Dest */
+            if (!rsrc) {
+                gen_lnk(dc, (uint8_t) get_Dest_X1(bundle));
+                return;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+    qemu_log("in x1_5, unimplement %16.16llx\n", bundle);
+    dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+}
+
+static void decode_insns_x1_7(struct DisasContext *dc,
+                              tilegx_bundle_bits bundle)
+{
+    uint8_t rsrc = (uint8_t)get_SrcA_X1(bundle);
+    uint8_t rdst = (uint8_t)get_Dest_X1(bundle);
+    uint16_t uimm16 = (uint16_t)get_Imm16_X1(bundle);
+
+    gen_shl16insli(dc, rdst, rsrc, uimm16);
+}
+
+typedef void (*TileGXDecodeInsn)(struct DisasContext *, tilegx_bundle_bits);
+
+/* by "grep _OPCODE_X0 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
+static TileGXDecodeInsn decode_insns_x0[] = {
+    NULL,               /* 0, Nothing */
+    decode_insns_x0_1,  /* 1, ADDI_IMM8_OPCODE_X0
+                              ADDLI_OPCODE_X0
+                              ADDXSC_RRR_0_OPCODE_X0
+                              CNTLZ_UNARY_OPCODE_X0
+                              ROTLI_SHIFT_OPCODE_X0 */
+    NULL,               /* 2, ADDXI_IMM8_OPCODE_X0
+                              ADDXLI_OPCODE_X0
+                              ADDX_RRR_0_OPCODE_X0
+                              CNTTZ_UNARY_OPCODE_X0
+                              SHLI_SHIFT_OPCODE_X0 */
+    NULL,               /* 3, ADD_RRR_0_OPCODE_X0
+                              ANDI_IMM8_OPCODE_X0
+                              BF_OPCODE_X0
+                              FNOP_UNARY_OPCODE_X0
+                              SHLXI_SHIFT_OPCODE_X0 */
+    decode_insns_x0_4,  /* 4, AND_RRR_0_OPCODE_X0
+                              BFEXTS_BF_OPCODE_X0
+                              CMPEQI_IMM8_OPCODE_X0
+                              FSINGLE_PACK1_UNARY_OPCODE_X0
+                              IMM8_OPCODE_X0
+                              SHRSI_SHIFT_OPCODE_X0 */
+    decode_insns_x0_5,  /* 5, BFEXTU_BF_OPCODE_X0
+                              CMOVEQZ_RRR_0_OPCODE_X0
+                              CMPLTSI_IMM8_OPCODE_X0
+                              NOP_UNARY_OPCODE_X0
+                              RRR_0_OPCODE_X0
+                              SHRUI_SHIFT_OPCODE_X0 */
+    NULL,               /* 6, BFINS_BF_OPCODE_X0
+                              CMOVNEZ_RRR_0_OPCODE_X0
+                              CMPLTUI_IMM8_OPCODE_X0
+                              PCNT_UNARY_OPCODE_X0
+                              SHIFT_OPCODE_X0
+                              SHRUXI_SHIFT_OPCODE_X0 */
+    decode_insns_x0_7,  /* 7, CMPEQ_RRR_0_OPCODE_X0
+                              MM_BF_OPCODE_X0
+                              ORI_IMM8_OPCODE_X0
+                              REVBITS_UNARY_OPCODE_X0
+                              SHL16INSLI_OPCODE_X0
+                              V1SHLI_SHIFT_OPCODE_X0 */
+    NULL,               /* 8, CMPLES_RRR_0_OPCODE_X0
+                              REVBYTES_UNARY_OPCODE_X0
+                              V1ADDI_IMM8_OPCODE_X0
+                              V1SHRSI_SHIFT_OPCODE_X0 */
+    NULL,               /* 9, CMPLEU_RRR_0_OPCODE_X0
+                              TBLIDXB0_UNARY_OPCODE_X0
+                              V1CMPEQI_IMM8_OPCODE_X0
+                              V1SHRUI_SHIFT_OPCODE_X0 */
+    NULL,               /* 10, CMPLTS_RRR_0_OPCODE_X0
+                               TBLIDXB1_UNARY_OPCODE_X0
+                               V1CMPLTSI_IMM8_OPCODE_X0
+                               V2SHLI_SHIFT_OPCODE_X0 */
+    NULL,               /* 11, CMPLTU_RRR_0_OPCODE_X0
+                               TBLIDXB2_UNARY_OPCODE_X0
+                               V1CMPLTUI_IMM8_OPCODE_X0
+                               V2SHRSI_SHIFT_OPCODE_X0 */
+    NULL,               /* 12, CMPNE_RRR_0_OPCODE_X0
+                               TBLIDXB3_UNARY_OPCODE_X0
+                               V1MAXUI_IMM8_OPCODE_X0
+                               V2SHRUI_SHIFT_OPCODE_X0 */
+    NULL,               /* 13, CMULAF_RRR_0_OPCODE_X0
+                               V1MINUI_IMM8_OPCODE_X0 */
+    NULL,               /* 14, CMULA_RRR_0_OPCODE_X0
+                               V2ADDI_IMM8_OPCODE_X0 */
+    NULL,               /* 15, CMULFR_RRR_0_OPCODE_X0
+                               V2CMPEQI_IMM8_OPCODE_X0 */
+    NULL,               /* 16, CMULF_RRR_0_OPCODE_X0
+                               V2CMPLTSI_IMM8_OPCODE_X0 */
+    NULL,               /* 17, CMULHR_RRR_0_OPCODE_X0
+                               V2CMPLTUI_IMM8_OPCODE_X0 */
+    NULL,               /* 18, CMULH_RRR_0_OPCODE_X0
+                               V2MAXSI_IMM8_OPCODE_X0 */
+    NULL,               /* 19, CMUL_RRR_0_OPCODE_X0
+                               V2MINSI_IMM8_OPCODE_X0 */
+    NULL,               /* 20, CRC32_32_RRR_0_OPCODE_X0
+                               XORI_IMM8_OPCODE_X0 */
+    NULL,               /* 21, CRC32_8_RRR_0_OPCODE_X0 */
+    NULL,               /* 22, DBLALIGN2_RRR_0_OPCODE_X0 */
+    NULL,               /* 23, DBLALIGN4_RRR_0_OPCODE_X0 */
+    NULL,               /* 24, DBLALIGN6_RRR_0_OPCODE_X0 */
+    NULL,               /* 25, DBLALIGN_RRR_0_OPCODE_X0 */
+    NULL,               /* 26, FDOUBLE_ADDSUB_RRR_0_OPCODE_X0 */
+    NULL,               /* 27, FDOUBLE_ADD_FLAGS_RRR_0_OPCODE_X0 */
+    NULL,               /* 28, FDOUBLE_MUL_FLAGS_RRR_0_OPCODE_X0 */
+    NULL,               /* 29, FDOUBLE_PACK1_RRR_0_OPCODE_X0 */
+    NULL,               /* 30, FDOUBLE_PACK2_RRR_0_OPCODE_X0 */
+    NULL,               /* 31, FDOUBLE_SUB_FLAGS_RRR_0_OPCODE_X0 */
+    NULL,               /* 32, FDOUBLE_UNPACK_MAX_RRR_0_OPCODE_X0 */
+    NULL,               /* 33, FDOUBLE_UNPACK_MIN_RRR_0_OPCODE_X0 */
+    NULL,               /* 34, FSINGLE_ADD1_RRR_0_OPCODE_X0 */
+    NULL,               /* 35, FSINGLE_ADDSUB2_RRR_0_OPCODE_X0 */
+    NULL,               /* 36, FSINGLE_MUL1_RRR_0_OPCODE_X0 */
+    NULL,               /* 37, FSINGLE_MUL2_RRR_0_OPCODE_X0 */
+    NULL,               /* 38, FSINGLE_PACK2_RRR_0_OPCODE_X0 */
+    NULL,               /* 39, FSINGLE_SUB1_RRR_0_OPCODE_X0 */
+    NULL,               /* 40, MNZ_RRR_0_OPCODE_X0 */
+    NULL,               /* 41, MULAX_RRR_0_OPCODE_X0 */
+    NULL,               /* 42, MULA_HS_HS_RRR_0_OPCODE_X0 */
+    NULL,               /* 43, MULA_HS_HU_RRR_0_OPCODE_X0 */
+    NULL,               /* 44, MULA_HS_LS_RRR_0_OPCODE_X0 */
+    NULL,               /* 45, MULA_HS_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 46, MULA_HU_HU_RRR_0_OPCODE_X0 */
+    NULL,               /* 47, MULA_HU_LS_RRR_0_OPCODE_X0 */
+    NULL,               /* 48, MULA_HU_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 49, MULA_LS_LS_RRR_0_OPCODE_X0 */
+    NULL,               /* 50, MULA_LS_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 51, MULA_LU_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 52, MULX_RRR_0_OPCODE_X0 */
+    NULL,               /* 53, MUL_HS_HS_RRR_0_OPCODE_X0 */
+    NULL,               /* 54, MUL_HS_HU_RRR_0_OPCODE_X0 */
+    NULL,               /* 55, MUL_HS_LS_RRR_0_OPCODE_X0 */
+    NULL,               /* 56, MUL_HS_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 57, MUL_HU_HU_RRR_0_OPCODE_X0 */
+    NULL,               /* 58, MUL_HU_LS_RRR_0_OPCODE_X0 */
+    NULL,               /* 59, MUL_HU_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 60, MUL_LS_LS_RRR_0_OPCODE_X0 */
+    NULL,               /* 61, MUL_LS_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 62, MUL_LU_LU_RRR_0_OPCODE_X0 */
+    NULL,               /* 63, MZ_RRR_0_OPCODE_X0 */
+    NULL,               /* 64, NOR_RRR_0_OPCODE_X0 */
+    NULL,               /* 65, OR_RRR_0_OPCODE_X0 */
+    NULL,               /* 66, ROTL_RRR_0_OPCODE_X0 */
+    NULL,               /* 67, SHL1ADDX_RRR_0_OPCODE_X0 */
+    NULL,               /* 68, SHL1ADD_RRR_0_OPCODE_X0 */
+    NULL,               /* 69, SHL2ADDX_RRR_0_OPCODE_X0 */
+    NULL,               /* 70, SHL2ADD_RRR_0_OPCODE_X0 */
+    NULL,               /* 71, SHL3ADDX_RRR_0_OPCODE_X0 */
+    NULL,               /* 72, SHL3ADD_RRR_0_OPCODE_X0 */
+    NULL,               /* 73, SHLX_RRR_0_OPCODE_X0 */
+    NULL,               /* 74, SHL_RRR_0_OPCODE_X0 */
+    NULL,               /* 75, SHRS_RRR_0_OPCODE_X0 */
+    NULL,               /* 76, SHRUX_RRR_0_OPCODE_X0 */
+    NULL,               /* 77, SHRU_RRR_0_OPCODE_X0 */
+    NULL,               /* 78, SHUFFLEBYTES_RRR_0_OPCODE_X0 */
+    NULL,               /* 79, SUBXSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 80, SUBX_RRR_0_OPCODE_X0 */
+    NULL,               /* 81, SUB_RRR_0_OPCODE_X0 */
+    NULL,               /* 82, UNARY_RRR_0_OPCODE_X0 */
+    NULL,               /* 83, V1ADDUC_RRR_0_OPCODE_X0 */
+    NULL,               /* 84, V1ADD_RRR_0_OPCODE_X0 */
+    NULL,               /* 85, V1ADIFFU_RRR_0_OPCODE_X0 */
+    NULL,               /* 86, V1AVGU_RRR_0_OPCODE_X0 */
+    NULL,               /* 87, V1CMPEQ_RRR_0_OPCODE_X0 */
+    NULL,               /* 88, V1CMPLES_RRR_0_OPCODE_X0 */
+    NULL,               /* 89, V1CMPLEU_RRR_0_OPCODE_X0 */
+    NULL,               /* 90, V1CMPLTS_RRR_0_OPCODE_X0 */
+    NULL,               /* 91, V1CMPLTU_RRR_0_OPCODE_X0 */
+    NULL,               /* 92, V1CMPNE_RRR_0_OPCODE_X0 */
+    NULL,               /* 93, V1DDOTPUSA_RRR_0_OPCODE_X0 */
+    NULL,               /* 94, V1DDOTPUS_RRR_0_OPCODE_X0 */
+    NULL,               /* 95, V1DOTPA_RRR_0_OPCODE_X0 */
+    NULL,               /* 96, V1DOTPUSA_RRR_0_OPCODE_X0 */
+    NULL,               /* 97, V1DOTPUS_RRR_0_OPCODE_X0 */
+    NULL,               /* 98, V1DOTP_RRR_0_OPCODE_X0 */
+    NULL,               /* 99, V1INT_H_RRR_0_OPCODE_X0 */
+    NULL,               /* 100, V1INT_L_RRR_0_OPCODE_X0 */
+    NULL,               /* 101, V1MAXU_RRR_0_OPCODE_X0 */
+    NULL,               /* 102, V1MINU_RRR_0_OPCODE_X0 */
+    NULL,               /* 103, V1MNZ_RRR_0_OPCODE_X0 */
+    NULL,               /* 104, V1MULTU_RRR_0_OPCODE_X0 */
+    NULL,               /* 105, V1MULUS_RRR_0_OPCODE_X0 */
+    NULL,               /* 106, V1MULU_RRR_0_OPCODE_X0 */
+    NULL,               /* 107, V1MZ_RRR_0_OPCODE_X0 */
+    NULL,               /* 108, V1SADAU_RRR_0_OPCODE_X0 */
+    NULL,               /* 109, V1SADU_RRR_0_OPCODE_X0 */
+    NULL,               /* 110, V1SHL_RRR_0_OPCODE_X0 */
+    NULL,               /* 111, V1SHRS_RRR_0_OPCODE_X0 */
+    NULL,               /* 112, V1SHRU_RRR_0_OPCODE_X0 */
+    NULL,               /* 113, V1SUBUC_RRR_0_OPCODE_X0 */
+    NULL,               /* 114, V1SUB_RRR_0_OPCODE_X0 */
+    NULL,               /* 115, V2ADDSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 116, V2ADD_RRR_0_OPCODE_X0 */
+    NULL,               /* 117, V2ADIFFS_RRR_0_OPCODE_X0 */
+    NULL,               /* 118, V2AVGS_RRR_0_OPCODE_X0 */
+    NULL,               /* 119, V2CMPEQ_RRR_0_OPCODE_X0 */
+    NULL,               /* 120, V2CMPLES_RRR_0_OPCODE_X0 */
+    NULL,               /* 121, V2CMPLEU_RRR_0_OPCODE_X0 */
+    NULL,               /* 122, V2CMPLTS_RRR_0_OPCODE_X0 */
+    NULL,               /* 123, V2CMPLTU_RRR_0_OPCODE_X0 */
+    NULL,               /* 124, V2CMPNE_RRR_0_OPCODE_X0 */
+    NULL,               /* 125, V2DOTPA_RRR_0_OPCODE_X0 */
+    NULL,               /* 126, V2DOTP_RRR_0_OPCODE_X0 */
+    NULL,               /* 127, V2INT_H_RRR_0_OPCODE_X0 */
+    NULL,               /* 128, V2INT_L_RRR_0_OPCODE_X0 */
+    NULL,               /* 129, V2MAXS_RRR_0_OPCODE_X0 */
+    NULL,               /* 130, V2MINS_RRR_0_OPCODE_X0 */
+    NULL,               /* 131, V2MNZ_RRR_0_OPCODE_X0 */
+    NULL,               /* 132, V2MULFSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 133, V2MULS_RRR_0_OPCODE_X0 */
+    NULL,               /* 134, V2MULTS_RRR_0_OPCODE_X0 */
+    NULL,               /* 135, V2MZ_RRR_0_OPCODE_X0 */
+    NULL,               /* 136, V2PACKH_RRR_0_OPCODE_X0 */
+    NULL,               /* 137, V2PACKL_RRR_0_OPCODE_X0 */
+    NULL,               /* 138, V2PACKUC_RRR_0_OPCODE_X0 */
+    NULL,               /* 139, V2SADAS_RRR_0_OPCODE_X0 */
+    NULL,               /* 140, V2SADAU_RRR_0_OPCODE_X0 */
+    NULL,               /* 141, V2SADS_RRR_0_OPCODE_X0 */
+    NULL,               /* 142, V2SADU_RRR_0_OPCODE_X0 */
+    NULL,               /* 143, V2SHLSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 144, V2SHL_RRR_0_OPCODE_X0 */
+    NULL,               /* 145, V2SHRS_RRR_0_OPCODE_X0 */
+    NULL,               /* 146, V2SHRU_RRR_0_OPCODE_X0 */
+    NULL,               /* 147, V2SUBSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 148, V2SUB_RRR_0_OPCODE_X0 */
+    NULL,               /* 149, V4ADDSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 150, V4ADD_RRR_0_OPCODE_X0 */
+    NULL,               /* 151, V4INT_H_RRR_0_OPCODE_X0 */
+    NULL,               /* 152, V4INT_L_RRR_0_OPCODE_X0 */
+    NULL,               /* 153, V4PACKSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 154, V4SHLSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 155, V4SHL_RRR_0_OPCODE_X0 */
+    NULL,               /* 156, V4SHRS_RRR_0_OPCODE_X0 */
+    NULL,               /* 157, V4SHRU_RRR_0_OPCODE_X0 */
+    NULL,               /* 158, V4SUBSC_RRR_0_OPCODE_X0 */
+    NULL,               /* 159, V4SUB_RRR_0_OPCODE_X0 */
+    NULL,               /* 160, XOR_RRR_0_OPCODE_X0 */
+    NULL,               /* 161, V1DDOTPUA_RRR_0_OPCODE_X0 */
+    NULL,               /* 162, V1DDOTPU_RRR_0_OPCODE_X0 */
+    NULL,               /* 163, V1DOTPUA_RRR_0_OPCODE_X0 */
+    NULL                /* 164, V1DOTPU_RRR_0_OPCODE_X0 */
+};
+
+/* by "grep _OPCODE_X1 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
+static TileGXDecodeInsn decode_insns_x1[] = {
+    decode_insns_x1_0,  /* 0, ADDLI_OPCODE_X1
+                              JAL_JUMP_OPCODE_X1 */
+    NULL,               /* 1, ADDI_IMM8_OPCODE_X1
+                              ADDXLI_OPCODE_X1
+                              ADDXSC_RRR_0_OPCODE_X1
+                              DRAIN_UNARY_OPCODE_X1
+                              J_JUMP_OPCODE_X1
+                              ROTLI_SHIFT_OPCODE_X1 */
+    NULL,               /* 2, ADDXI_IMM8_OPCODE_X1
+                              ADDX_RRR_0_OPCODE_X1
+                              BRANCH_OPCODE_X1
+                              DTLBPR_UNARY_OPCODE_X1
+                              SHLI_SHIFT_OPCODE_X1 */
+    decode_insns_x1_3,  /* 3, ADD_RRR_0_OPCODE_X1
+                              ANDI_IMM8_OPCODE_X1
+                              FINV_UNARY_OPCODE_X1
+                              IMM8_OPCODE_X1
+                              SHLXI_SHIFT_OPCODE_X1 */
+    NULL,               /* 4, AND_RRR_0_OPCODE_X1
+                              CMPEQI_IMM8_OPCODE_X1
+                              FLUSHWB_UNARY_OPCODE_X1
+                              JUMP_OPCODE_X1
+                              SHRSI_SHIFT_OPCODE_X1 */
+    decode_insns_x1_5,  /* 5, CMPEQ_RRR_0_OPCODE_X1
+                              CMPLTSI_IMM8_OPCODE_X1
+                              FLUSH_UNARY_OPCODE_X1
+                              RRR_0_OPCODE_X1
+                              SHRUI_SHIFT_OPCODE_X1 */
+    NULL,               /* 6, CMPEXCH4_RRR_0_OPCODE_X1
+                              CMPLTUI_IMM8_OPCODE_X1
+                              FNOP_UNARY_OPCODE_X1
+                              SHIFT_OPCODE_X1
+                              SHRUXI_SHIFT_OPCODE_X1 */
+    decode_insns_x1_7,  /* 7, CMPEXCH_RRR_0_OPCODE_X1
+                              ICOH_UNARY_OPCODE_X1
+                              LD1S_ADD_IMM8_OPCODE_X1
+                              SHL16INSLI_OPCODE_X1
+                              V1SHLI_SHIFT_OPCODE_X1 */
+    NULL,               /* 8, CMPLES_RRR_0_OPCODE_X1
+                              ILL_UNARY_OPCODE_X1
+                              LD1U_ADD_IMM8_OPCODE_X1
+                              V1SHRSI_SHIFT_OPCODE_X1 */
+    NULL,               /* 9, CMPLEU_RRR_0_OPCODE_X1
+                              INV_UNARY_OPCODE_X1
+                              LD2S_ADD_IMM8_OPCODE_X1
+                              V1SHRUI_SHIFT_OPCODE_X1 */
+    NULL,               /* 10, CMPLTS_RRR_0_OPCODE_X1
+                               IRET_UNARY_OPCODE_X1
+                               LD2U_ADD_IMM8_OPCODE_X1
+                               V2SHLI_SHIFT_OPCODE_X1 */
+    NULL,               /* 11, CMPLTU_RRR_0_OPCODE_X1
+                               JALRP_UNARY_OPCODE_X1
+                               LD4S_ADD_IMM8_OPCODE_X1
+                               V2SHRSI_SHIFT_OPCODE_X1 */
+    NULL,               /* 12, CMPNE_RRR_0_OPCODE_X1
+                               JALR_UNARY_OPCODE_X1
+                               LD4U_ADD_IMM8_OPCODE_X1
+                               V2SHRUI_SHIFT_OPCODE_X1 */
+    NULL,               /* 13, DBLALIGN2_RRR_0_OPCODE_X1
+                               JRP_UNARY_OPCODE_X1
+                               LDNT1S_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 14, DBLALIGN4_RRR_0_OPCODE_X1
+                               JR_UNARY_OPCODE_X1
+                               LDNT1U_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 15, DBLALIGN6_RRR_0_OPCODE_X1
+                               LD1S_UNARY_OPCODE_X1
+                               LDNT2S_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 16, BEQZT_BRANCH_OPCODE_X1
+                               EXCH4_RRR_0_OPCODE_X1
+                               LD1U_UNARY_OPCODE_X1
+                               LDNT2U_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 17, BEQZ_BRANCH_OPCODE_X1
+                               EXCH_RRR_0_OPCODE_X1
+                               LD2S_UNARY_OPCODE_X1
+                               LDNT4S_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 18, BGEZT_BRANCH_OPCODE_X1
+                               FETCHADD4_RRR_0_OPCODE_X1
+                               LD2U_UNARY_OPCODE_X1
+                               LDNT4U_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 19, BGEZ_BRANCH_OPCODE_X1
+                               FETCHADDGEZ4_RRR_0_OPCODE_X1
+                               LD4S_UNARY_OPCODE_X1
+                               LDNT_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 20, BGTZT_BRANCH_OPCODE_X1
+                               FETCHADDGEZ_RRR_0_OPCODE_X1
+                               LD4U_UNARY_OPCODE_X1
+                               LD_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 21, BGTZ_BRANCH_OPCODE_X1
+                               FETCHADD_RRR_0_OPCODE_X1
+                               LDNA_UNARY_OPCODE_X1
+                               LWNA_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 22, BLBCT_BRANCH_OPCODE_X1
+                               FETCHAND4_RRR_0_OPCODE_X1
+                               LDNT1S_UNARY_OPCODE_X1
+                               MFSPR_IMM8_OPCODE_X1 */
+    NULL,               /* 23, BLBC_BRANCH_OPCODE_X1
+                               FETCHAND_RRR_0_OPCODE_X1
+                               LDNT1U_UNARY_OPCODE_X1
+                               MTSPR_IMM8_OPCODE_X1 */
+    NULL,               /* 24, BLBST_BRANCH_OPCODE_X1
+                               FETCHOR4_RRR_0_OPCODE_X1
+                               LDNT2S_UNARY_OPCODE_X1
+                               ORI_IMM8_OPCODE_X1 */
+    NULL,               /* 25, BLBS_BRANCH_OPCODE_X1 25
+                               FETCHOR_RRR_0_OPCODE_X1
+                               LDNT2U_UNARY_OPCODE_X1
+                               ST1_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 26, BLEZT_BRANCH_OPCODE_X1
+                               LDNT4S_UNARY_OPCODE_X1
+                               MNZ_RRR_0_OPCODE_X1
+                               ST2_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 27, BLEZ_BRANCH_OPCODE_X1
+                               LDNT4U_UNARY_OPCODE_X1
+                               MZ_RRR_0_OPCODE_X1
+                               ST4_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 28, BLTZT_BRANCH_OPCODE_X1
+                               LDNT_UNARY_OPCODE_X1
+                               NOR_RRR_0_OPCODE_X1
+                               STNT1_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 29, BLTZ_BRANCH_OPCODE_X1
+                               LD_UNARY_OPCODE_X1
+                               OR_RRR_0_OPCODE_X1
+                               STNT2_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 30, BNEZT_BRANCH_OPCODE_X1
+                               LNK_UNARY_OPCODE_X1
+                               ROTL_RRR_0_OPCODE_X1
+                               STNT4_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 31, BNEZ_BRANCH_OPCODE_X1
+                               MF_UNARY_OPCODE_X1
+                               SHL1ADDX_RRR_0_OPCODE_X1
+                               STNT_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 32, NAP_UNARY_OPCODE_X1
+                               SHL1ADD_RRR_0_OPCODE_X1
+                               ST_ADD_IMM8_OPCODE_X1 */
+    NULL,               /* 33, NOP_UNARY_OPCODE_X1
+                               SHL2ADDX_RRR_0_OPCODE_X1
+                               V1ADDI_IMM8_OPCODE_X1 */
+    NULL,               /* 34, SHL2ADD_RRR_0_OPCODE_X1
+                               SWINT0_UNARY_OPCODE_X1
+                               V1CMPEQI_IMM8_OPCODE_X1 */
+    NULL,               /* 35, SHL3ADDX_RRR_0_OPCODE_X1
+                               SWINT1_UNARY_OPCODE_X1
+                               V1CMPLTSI_IMM8_OPCODE_X1 */
+    NULL,               /* 36, SHL3ADD_RRR_0_OPCODE_X1
+                               SWINT2_UNARY_OPCODE_X1
+                               V1CMPLTUI_IMM8_OPCODE_X1 */
+    NULL,               /* 37, SHLX_RRR_0_OPCODE_X1
+                               SWINT3_UNARY_OPCODE_X1
+                               V1MAXUI_IMM8_OPCODE_X1 */
+    NULL,               /* 38, SHL_RRR_0_OPCODE_X1
+                               V1MINUI_IMM8_OPCODE_X1
+                               WH64_UNARY_OPCODE_X1 */
+    NULL,               /* 39, SHRS_RRR_0_OPCODE_X1
+                               V2ADDI_IMM8_OPCODE_X1 */
+    NULL,               /* 40, SHRUX_RRR_0_OPCODE_X1
+                               V2CMPEQI_IMM8_OPCODE_X1 */
+    NULL,               /* 41, SHRU_RRR_0_OPCODE_X1
+                               V2CMPLTSI_IMM8_OPCODE_X1 */
+    NULL,               /* 42, ST1_RRR_0_OPCODE_X1
+                               V2CMPLTUI_IMM8_OPCODE_X1 */
+    NULL,               /* 43, ST2_RRR_0_OPCODE_X1
+                               V2MAXSI_IMM8_OPCODE_X1 */
+    NULL,               /* 44, ST4_RRR_0_OPCODE_X1
+                               V2MINSI_IMM8_OPCODE_X1 */
+    NULL,               /* 45, STNT1_RRR_0_OPCODE_X1
+                               XORI_IMM8_OPCODE_X1 */
+    NULL,               /* 46, STNT2_RRR_0_OPCODE_X1 */
+    NULL,               /* 47, STNT4_RRR_0_OPCODE_X1 */
+    NULL,               /* 48, STNT_RRR_0_OPCODE_X1 */
+    NULL,               /* 49, ST_RRR_0_OPCODE_X1 */
+    NULL,               /* 50, SUBXSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 51, SUBX_RRR_0_OPCODE_X1 */
+    NULL,               /* 52, SUB_RRR_0_OPCODE_X1 */
+    NULL,               /* 53, UNARY_RRR_0_OPCODE_X1 */
+    NULL,               /* 54, V1ADDUC_RRR_0_OPCODE_X1 */
+    NULL,               /* 55, V1ADD_RRR_0_OPCODE_X1 */
+    NULL,               /* 56, V1CMPEQ_RRR_0_OPCODE_X1 */
+    NULL,               /* 57, V1CMPLES_RRR_0_OPCODE_X1 */
+    NULL,               /* 58, V1CMPLEU_RRR_0_OPCODE_X1 */
+    NULL,               /* 59, V1CMPLTS_RRR_0_OPCODE_X1 */
+    NULL,               /* 60, V1CMPLTU_RRR_0_OPCODE_X1 */
+    NULL,               /* 61, V1CMPNE_RRR_0_OPCODE_X1 */
+    NULL,               /* 62, V1INT_H_RRR_0_OPCODE_X1 */
+    NULL,               /* 63, V1INT_L_RRR_0_OPCODE_X1 */
+    NULL,               /* 64, V1MAXU_RRR_0_OPCODE_X1 */
+    NULL,               /* 65, V1MINU_RRR_0_OPCODE_X1 */
+    NULL,               /* 66, V1MNZ_RRR_0_OPCODE_X1 */
+    NULL,               /* 67, V1MZ_RRR_0_OPCODE_X1 */
+    NULL,               /* 68, V1SHL_RRR_0_OPCODE_X1 */
+    NULL,               /* 69, V1SHRS_RRR_0_OPCODE_X1 */
+    NULL,               /* 70, V1SHRU_RRR_0_OPCODE_X1 */
+    NULL,               /* 71, V1SUBUC_RRR_0_OPCODE_X1 */
+    NULL,               /* 72, V1SUB_RRR_0_OPCODE_X1 */
+    NULL,               /* 73, V2ADDSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 74, V2ADD_RRR_0_OPCODE_X1 */
+    NULL,               /* 75, V2CMPEQ_RRR_0_OPCODE_X1 */
+    NULL,               /* 76, V2CMPLES_RRR_0_OPCODE_X1 */
+    NULL,               /* 77, V2CMPLEU_RRR_0_OPCODE_X1 */
+    NULL,               /* 78, V2CMPLTS_RRR_0_OPCODE_X1 */
+    NULL,               /* 79, V2CMPLTU_RRR_0_OPCODE_X1 */
+    NULL,               /* 80, V2CMPNE_RRR_0_OPCODE_X1 */
+    NULL,               /* 81, V2INT_H_RRR_0_OPCODE_X1 */
+    NULL,               /* 82, V2INT_L_RRR_0_OPCODE_X1 */
+    NULL,               /* 83, V2MAXS_RRR_0_OPCODE_X1 */
+    NULL,               /* 84, V2MINS_RRR_0_OPCODE_X1 */
+    NULL,               /* 85, V2MNZ_RRR_0_OPCODE_X1 */
+    NULL,               /* 86, V2MZ_RRR_0_OPCODE_X1 */
+    NULL,               /* 87, V2PACKH_RRR_0_OPCODE_X1 */
+    NULL,               /* 88, V2PACKL_RRR_0_OPCODE_X1 */
+    NULL,               /* 89, V2PACKUC_RRR_0_OPCODE_X1 */
+    NULL,               /* 90, V2SHLSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 91, V2SHL_RRR_0_OPCODE_X1 */
+    NULL,               /* 92, V2SHRS_RRR_0_OPCODE_X1 */
+    NULL,               /* 93, V2SHRU_RRR_0_OPCODE_X1 */
+    NULL,               /* 94, V2SUBSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 95, V2SUB_RRR_0_OPCODE_X1 */
+    NULL,               /* 96, V4ADDSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 97, V4ADD_RRR_0_OPCODE_X1 */
+    NULL,               /* 98, V4INT_H_RRR_0_OPCODE_X1 */
+    NULL,               /* 99, V4INT_L_RRR_0_OPCODE_X1 */
+    NULL,               /* 100, V4PACKSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 101, V4SHLSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 102, V4SHL_RRR_0_OPCODE_X1 */
+    NULL,               /* 103, V4SHRS_RRR_0_OPCODE_X1 */
+    NULL,               /* 104, V4SHRU_RRR_0_OPCODE_X1 */
+    NULL,               /* 105, V4SUBSC_RRR_0_OPCODE_X1 */
+    NULL,               /* 106, V4SUB_RRR_0_OPCODE_X1 */
+    NULL                /* 107, XOR_RRR_0_OPCODE_X1 */
+};
+
+/* by "grep _OPCODE_Y0 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
+static TileGXDecodeInsn decode_insns_y0[] = {
+    NULL,               /* 0, ADDI_OPCODE_Y0
+                              ADDX_RRR_0_OPCODE_Y0
+                              AND_RRR_5_OPCODE_Y0
+                              CMOVEQZ_RRR_4_OPCODE_Y0
+                              CMPEQ_RRR_3_OPCODE_Y0
+                              CMPLES_RRR_2_OPCODE_Y0
+                              MULA_HS_HS_RRR_9_OPCODE_Y0
+                              MUL_HS_HS_RRR_8_OPCODE_Y0
+                              ROTLI_SHIFT_OPCODE_Y0
+                              ROTL_RRR_6_OPCODE_Y0
+                              SHL1ADD_RRR_1_OPCODE_Y0 */
+    NULL,               /* 1, ADD_RRR_0_OPCODE_Y0
+                              ADDXI_OPCODE_Y0
+                              CMOVNEZ_RRR_4_OPCODE_Y0
+                              CMPLEU_RRR_2_OPCODE_Y0
+                              CMPNE_RRR_3_OPCODE_Y0
+                              CNTLZ_UNARY_OPCODE_Y0
+                              MULA_HU_HU_RRR_9_OPCODE_Y0
+                              MUL_HU_HU_RRR_8_OPCODE_Y0
+                              NOR_RRR_5_OPCODE_Y0
+                              SHL1ADDX_RRR_7_OPCODE_Y0
+                              SHL2ADD_RRR_1_OPCODE_Y0
+                              SHLI_SHIFT_OPCODE_Y0
+                              SHL_RRR_6_OPCODE_Y0 */
+    NULL,               /* 2, ANDI_OPCODE_Y0
+                              CMPLTS_RRR_2_OPCODE_Y0
+                              CNTTZ_UNARY_OPCODE_Y0
+                              MNZ_RRR_4_OPCODE_Y0
+                              MULA_LS_LS_RRR_9_OPCODE_Y0
+                              MULAX_RRR_3_OPCODE_Y0
+                              MUL_LS_LS_RRR_8_OPCODE_Y0
+                              OR_RRR_5_OPCODE_Y0
+                              SHL2ADDX_RRR_7_OPCODE_Y0
+                              SHL3ADD_RRR_1_OPCODE_Y0
+                              SHRSI_SHIFT_OPCODE_Y0
+                              SHRS_RRR_6_OPCODE_Y0
+                              SUBX_RRR_0_OPCODE_Y0 */
+    NULL,               /* 3, CMPEQI_OPCODE_Y0
+                              CMPLTU_RRR_2_OPCODE_Y0
+                              FNOP_UNARY_OPCODE_Y0
+                              MULA_LU_LU_RRR_9_OPCODE_Y0
+                              MUL_LU_LU_RRR_8_OPCODE_Y0
+                              MULX_RRR_3_OPCODE_Y0
+                              MZ_RRR_4_OPCODE_Y0
+                              SHL3ADDX_RRR_7_OPCODE_Y0
+                              SHRUI_SHIFT_OPCODE_Y0
+                              SHRU_RRR_6_OPCODE_Y0
+                              SUB_RRR_0_OPCODE_Y0
+                              UNARY_RRR_1_OPCODE_Y0
+                              XOR_RRR_5_OPCODE_Y0 */
+    NULL,               /* 4, CMPLTSI_OPCODE_Y0
+                              FSINGLE_PACK1_UNARY_OPCODE_Y0 */
+    NULL,               /* 5, NOP_UNARY_OPCODE_Y0
+                              RRR_0_OPCODE_Y0 */
+    NULL,               /* 6, PCNT_UNARY_OPCODE_Y0
+                              RRR_1_OPCODE_Y0 */
+    NULL,               /* 7, REVBITS_UNARY_OPCODE_Y0
+                              RRR_2_OPCODE_Y0 */
+    NULL,               /* 8, REVBYTES_UNARY_OPCODE_Y0
+                              RRR_3_OPCODE_Y0 */
+    NULL,               /* 9, RRR_4_OPCODE_Y0
+                              TBLIDXB0_UNARY_OPCODE_Y0 */
+    decode_insns_y0_10, /* 10, RRR_5_OPCODE_Y0
+                               TBLIDXB1_UNARY_OPCODE_Y0 */
+    NULL,               /* 11, RRR_6_OPCODE_Y0
+                               TBLIDXB2_UNARY_OPCODE_Y0 */
+    NULL,               /* 12, RRR_7_OPCODE_Y0
+                               TBLIDXB3_UNARY_OPCODE_Y0 */
+    NULL,               /* 13, RRR_8_OPCODE_Y0 */
+    NULL,               /* 14, RRR_9_OPCODE_Y0 */
+    NULL                /* 15, SHIFT_OPCODE_Y0 */
+};
+
+/* by "grep _OPCODE_Y1 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
+static TileGXDecodeInsn decode_insns_y1[] = {
+    NULL,               /* 0, ADDX_SPECIAL_0_OPCODE_Y1
+                              AND_RRR_5_OPCODE_Y1
+                              CMPLES_RRR_2_OPCODE_Y1
+                              ROTLI_SHIFT_OPCODE_Y1
+                              ROTL_RRR_6_OPCODE_Y1
+                              SHL1ADD_RRR_1_OPCODE_Y1 */
+    decode_insns_y1_1,  /* 1, ADDI_OPCODE_Y1
+                              ADD_SPECIAL_0_OPCODE_Y1
+                              CMPLEU_RRR_2_OPCODE_Y1
+                              NOR_RRR_5_OPCODE_Y1
+                              SHL1ADDX_RRR_7_OPCODE_Y1
+                              SHL2ADD_RRR_1_OPCODE_Y1
+                              SHLI_SHIFT_OPCODE_Y1
+                              SHL_RRR_6_OPCODE_Y1 */
+    NULL,               /* 2, ADDXI_OPCODE_Y1
+                              CMPEQ_RRR_3_OPCODE_Y1
+                              CMPLTS_RRR_2_OPCODE_Y1
+                              MNZ_RRR_4_OPCODE_Y1
+                              OR_RRR_5_OPCODE_Y1 2
+                              SHL2ADDX_RRR_7_OPCODE_Y1 2
+                              SHL3ADD_RRR_1_OPCODE_Y1
+                              SHRSI_SHIFT_OPCODE_Y1
+                              SHRS_RRR_6_OPCODE_Y1
+                              SUBX_RRR_0_OPCODE_Y1 */
+    NULL,               /* 3, ANDI_OPCODE_Y1
+                              CMPLTU_RRR_2_OPCODE_Y1
+                              CMPNE_RRR_3_OPCODE_Y1
+                              MZ_RRR_4_OPCODE_Y1
+                              SHL3ADDX_RRR_7_OPCODE_Y1
+                              SHRUI_SHIFT_OPCODE_Y1
+                              SHRU_RRR_6_OPCODE_Y1
+                              SUB_RRR_0_OPCODE_Y1
+                              UNARY_RRR_1_OPCODE_Y1
+                              XOR_RRR_5_OPCODE_Y1 */
+    NULL,               /* 4, CMPEQI_OPCODE_Y1 */
+    NULL,               /* 5, CMPLTSI_OPCODE_Y1 */
+    NULL,               /* 6, RRR_0_OPCODE_Y1 */
+    decode_insns_y1_7,  /* 7, RRR_1_OPCODE_Y1 */
+    NULL,               /* 8, FNOP_UNARY_OPCODE_Y1
+                              RRR_2_OPCODE_Y1 */
+    NULL,               /* 9, ILL_UNARY_OPCODE_Y1
+                              RRR_3_OPCODE_Y1 */
+    NULL,               /* 10, JALRP_UNARY_OPCODE_Y1
+                               RRR_4_OPCODE_Y1 */
+    NULL,               /* 11, JALR_UNARY_OPCODE_Y1
+                               RRR_5_OPCODE_Y1 */
+    NULL,               /* 12, JRP_UNARY_OPCODE_Y1
+                               RRR_6_OPCODE_Y1 */
+    NULL,               /* 13, JR_UNARY_OPCODE_Y1
+                               RRR_7_OPCODE_Y1 */
+    NULL,               /* 14, LNK_UNARY_OPCODE_Y1
+                               SHIFT_OPCODE_Y1 */
+    NULL                /* 15, NOP_UNARY_OPCODE_Y1 */
+};
+
+/* by "grep _OPCODE_Y2 opcode_tilegx.h | awk '{print $3, $1}' | sort -n" */
+static TileGXDecodeInsn decode_insns_y2[] = {
+    NULL,               /* 0, LD1S_OPCODE_Y2
+                              ST1_OPCODE_Y2 */
+    NULL,               /* 1, LD1U_OPCODE_Y2
+                              LD4S_OPCODE_Y2
+                              ST2_OPCODE_Y2 */
+    NULL,               /* 2, LD2S_OPCODE_Y2
+                              LD4U_OPCODE_Y2
+                              ST4_OPCODE_Y2 */
+    decode_insns_y2_3   /* 3, LD2U_OPCODE_Y2
+                              LD_OPCODE_Y2
+                              ST_OPCODE_Y2 */
+};
+
+void tilegx_tcg_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    cpu_pc = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUTLGState, pc), "pc");
+    for (i = 0; i < TILEGX_R_COUNT; i++) {
+        cpu_regs[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                             offsetof(CPUTLGState, regs[i]),
+                                             reg_names[i]);
+    }
+}
+
+static void translate_x0(struct DisasContext *dc, tilegx_bundle_bits bundle)
+{
+    unsigned int opcode = get_Opcode_X0(bundle);
+
+    if (opcode > TILEGX_OPCODE_MAX_X0) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
+        qemu_log("unknown x0 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+    if (!decode_insns_x0[opcode]) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+        qemu_log("unimplement x0 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+
+    dc->tmp_regcur = dc->tmp_regs + 0;
+    decode_insns_x0[opcode](dc, bundle);
+}
+
+static void translate_x1(struct DisasContext *dc, tilegx_bundle_bits bundle)
+{
+    unsigned int opcode = get_Opcode_X1(bundle);
+
+    if (opcode > TILEGX_OPCODE_MAX_X1) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
+        qemu_log("unknown x1 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+    if (!decode_insns_x1[opcode]) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+        qemu_log("unimplement x1 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+
+    dc->tmp_regcur = dc->tmp_regs + 1;
+    decode_insns_x1[opcode](dc, bundle);
+}
+
+static void translate_y0(struct DisasContext *dc, tilegx_bundle_bits bundle)
+{
+    unsigned int opcode = get_Opcode_Y0(bundle);
+
+    if (opcode > TILEGX_OPCODE_MAX_Y0) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
+        qemu_log("unknown y0 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+    if (!decode_insns_y0[opcode]) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+        qemu_log("unimplement y0 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+
+    dc->tmp_regcur = dc->tmp_regs + 0;
+    decode_insns_y0[opcode](dc, bundle);
+}
+
+static void translate_y1(struct DisasContext *dc, tilegx_bundle_bits bundle)
+{
+    unsigned int opcode = get_Opcode_Y1(bundle);
+
+    if (opcode > TILEGX_OPCODE_MAX_Y1) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
+        qemu_log("unknown y1 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+    if (!decode_insns_y1[opcode]) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+        qemu_log("unimplement y1 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+
+    dc->tmp_regcur = dc->tmp_regs + 1;
+    decode_insns_y1[opcode](dc, bundle);
+}
+
+static void translate_y2(struct DisasContext *dc, tilegx_bundle_bits bundle)
+{
+    unsigned int opcode = get_Opcode_Y2(bundle);
+
+    if (opcode > TILEGX_OPCODE_MAX_Y2) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNKNOWN;
+        qemu_log("unknown y2 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+    if (!decode_insns_y2[opcode]) {
+        dc->exception = TILEGX_EXCP_OPCODE_UNIMPLEMENT;
+        qemu_log("unimplement y2 opcode: %u for bundle: %16.16llx\n",
+                 opcode, bundle);
+        return;
+    }
+
+    dc->tmp_regcur = dc->tmp_regs + 2;
+    decode_insns_y2[opcode](dc, bundle);
+}
+
+static void translate_one_bundle(struct DisasContext *dc, uint64_t bundle)
+{
+    int i;
+    TCGv tmp;
+
+    for (i = 0; i < TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE; i++) {
+        dc->tmp_regs[i].idx = TILEGX_R_NOREG;
+        TCGV_UNUSED_I64(dc->tmp_regs[i].val);
+    }
+
+    if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
+        tcg_gen_debug_insn_start(dc->pc);
+    }
+
+    if (get_Mode(bundle)) {
+        translate_y0(dc, bundle);
+        translate_y1(dc, bundle);
+        translate_y2(dc, bundle);
+    } else {
+        translate_x0(dc, bundle);
+        translate_x1(dc, bundle);
+    }
+
+    for (i = 0; i < TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE; i++) {
+        if (dc->tmp_regs[i].idx == TILEGX_R_NOREG) {
+            continue;
+        }
+        if (dc->tmp_regs[i].idx < TILEGX_R_COUNT) {
+            tcg_gen_mov_i64(cpu_regs[dc->tmp_regs[i].idx], dc->tmp_regs[i].val);
+        }
+        tcg_temp_free_i64(dc->tmp_regs[i].val);
+    }
+
+    if (dc->jmp.cond != TCG_COND_NEVER) {
+        if (dc->jmp.cond == TCG_COND_ALWAYS) {
+            tcg_gen_mov_i64(cpu_pc, dc->jmp.dest);
+        } else {
+            tmp = tcg_const_i64(dc->pc + TILEGX_BUNDLE_SIZE_IN_BYTES);
+            tcg_gen_movcond_i64(dc->jmp.cond, cpu_pc,
+                                dc->jmp.val1, dc->jmp.val2,
+                                dc->jmp.dest, tmp);
+            tcg_temp_free_i64(dc->jmp.val1);
+            tcg_temp_free_i64(dc->jmp.val2);
+            tcg_temp_free_i64(tmp);
+        }
+        tcg_temp_free_i64(dc->jmp.dest);
+        tcg_gen_exit_tb(0);
+    }
+}
 
 static inline void gen_intermediate_code_internal(TileGXCPU *cpu,
                                                   TranslationBlock *tb,
                                                   bool search_pc)
 {
-    /*
-     * FIXME: after load elf64 tilegx binary successfully, it will quit, at
-     * present, and will implement the related features next.
-     */
-    qemu_log("\nLoaded elf64 tilegx successfully\n");
-    qemu_log("reached code start position: [" TARGET_FMT_lx "] %s\n\n",
-             tb->pc, lookup_symbol(tb->pc));
-    exit(0);
+    DisasContext ctx;
+    DisasContext *dc = &ctx;
+
+    CPUTLGState *env = &cpu->env;
+    uint64_t pc_start = tb->pc;
+    uint64_t next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+    int j, lj = -1;
+    int num_insns = 0;
+    int max_insns = tb->cflags & CF_COUNT_MASK;
+
+    dc->pc = pc_start;
+    dc->exception = 0;
+    dc->jmp.cond = TCG_COND_NEVER;
+    TCGV_UNUSED_I64(dc->jmp.dest);
+    TCGV_UNUSED_I64(dc->jmp.val1);
+    TCGV_UNUSED_I64(dc->jmp.val2);
+
+    if (!max_insns) {
+        max_insns = CF_COUNT_MASK;
+    }
+    gen_tb_start(tb);
+
+    do {
+        TCGV_UNUSED_I64(dc->zero);
+        if (search_pc) {
+            j = tcg_op_buf_count();
+            if (lj < j) {
+                lj++;
+                while (lj < j) {
+                    tcg_ctx.gen_opc_instr_start[lj++] = 0;
+                }
+            }
+            tcg_ctx.gen_opc_pc[lj] = dc->pc;
+            tcg_ctx.gen_opc_instr_start[lj] = 1;
+            tcg_ctx.gen_opc_icount[lj] = num_insns;
+        }
+        translate_one_bundle(dc, cpu_ldq_data(env, dc->pc));
+        if (dc->exception) {
+            exit(-1);
+        }
+        num_insns++;
+        dc->pc += TILEGX_BUNDLE_SIZE_IN_BYTES;
+    } while (dc->jmp.cond == TCG_COND_NEVER
+             && dc->pc < next_page_start
+             && num_insns <= max_insns - TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
+             && !tcg_op_buf_full());
+
+    gen_tb_end(tb, num_insns);
+    if (search_pc) {
+        j = tcg_op_buf_count();
+        lj++;
+        while (lj <= j) {
+            tcg_ctx.gen_opc_instr_start[lj++] = 0;
+        }
+    } else {
+        tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
+    }
+
+    return;
 }
 
 void gen_intermediate_code(CPUTLGState *env, struct TranslationBlock *tb)
 {
+    qemu_log("\ncall gen_intermediate_code()\n");
     gen_intermediate_code_internal(tilegx_env_get_cpu(env), tb, false);
 }
 
 void gen_intermediate_code_pc(CPUTLGState *env, struct TranslationBlock *tb)
 {
+    qemu_log("\ncall gen_intermediate_code_pc()\n");
     gen_intermediate_code_internal(tilegx_env_get_cpu(env), tb, true);
 }