
#include "st9.hpp"

enum st9_addressing_modes {
    A_IMPL,         // implied
    A_wrd_wrs,      // rd,rs
    A_wrd_wrsi,     // rd,(rs)
    A_wrdi_wrs,     // (rd),rs
    A_wrdi_grs,     // (rd),Rs
    A_grd_wrsi,     // Rd,(rs)
    A_grd_grs,      // Rd,Rs
    A_grs_grd,      // Rs,Rd
    A_grd_8q,       // Rd,#N  
    A_grpd_grps,    // RRd,RRs
    A_grpd_16q_0,   // RRd,#NN with first byte mask xxxxxxx0
    A_grpd_16q_1,   // RRd,#NN with first byte mask xxxxxxx1
    A_grp_8q,       // RR,#N
    A_grs,          // Rs
    A_grsi,         // (Rs)
    A_grd,          // Rd
    A_grdi,         // (Rd)
    A_grp_0,        // RR with first byte mask xxxxxxx0
    A_grp_1,        // RR with first byte mask xxxxxxx1
    A_grpi,         // (RR)
    A_8q,           // N
    A_16q,          // NN
    A_grps,         // RRs
    A_grpd_0,       // RRd with first byte mask xxxxxxx0
    A_grpd_1,       // RRd with first byte mask xxxxxxx1
    A_grpdi,        // (RRd)
    A_wrpd_wrps,    // rrd,rrs
    A_wrpdi_wrps,   // (rrd),rrs
    A_wrpd_wrpsi,   // rrd,(rrs)
    A_wrpdi_wrpsi,  // (rrd),(rrs)

    A_wrpdip_wrpsip_00,    // (rrd)+,(rrs)+ with first byte mask xxx0xxx0
    A_wrpdip_wrpsip_10,    // (rrd)+,(rrs)+ with first byte mask xxx1xxx0
    A_wrpdip_wrpsip_01,    // (rrd)+,(rrs)+ with first byte mask xxx0xxx1
    A_wrpdip_wrpsip_11,    // (rrd)+,(rrs)+ with first byte mask xxx1xxx1

    A_wrpd_wrs,     // rrd,rs
    A_8qxwrp_16q,   // Nd(rr),#NNs
    A_16qxwrp_16q,  // NNd(rr),#NNs
    A_8qxwrp_gr,    // N(rr),R
    A_16qxwrp_gr,   // NN(rr),R
    A_16q_8q,       // NNd,#Ns
    A_16q_16q,      // NNd,#NNs
    A_wr_wrpxwrp,   // rd,rrs(rrx)
    A_wrpxwrp_wr,   // rrd(rrx),rs
    A_wrp_wrpxwrp,  // rrd,rrs(rrx)
    A_wrpxwrp_wrp,  // rrd(rrx),rrs

    A_gr_wrpi,      // Rd,(rrs)
    A_wrip_gr,      // (rrd),Rs
    A_grpi_wrip,    // (RRd),(rrs)
    A_gri_wrip_01,  // (R),(rr) with first byte mask 0100xxxx
    A_gri_wrip_11,  // (R),(rr) with first byte mask 1100xxxx
    A_gr_8qxwrp,    // Rd,N(rrx)
    A_gr_16qxwrp,   // Rd,NN(rrx)
    A_grp_wrpi,     // RRd,(rrs)

    A_8qxwrp_grp,   // N(rrx),RRs
    A_grp_8qxwrp,   // RRs,N(rrx)
    A_16qxwrp_grp,  // NN(rrx),RRs
    A_grp_16qxwrp,  // RRs,NN(rrx)

    A_8qxgrpi,      // N(RRx)
    A_16qxgrpi,     // NN(RRx)

    A_wrd_wrpsi_8q_0,   // rd,(rrs),N with first byte mask xxx0xxxx
    A_wrd_wrpsi_8q_1,   // rd,(rrs),N with first byte mask xxx1xxxx

    A_grpd_wrsi,    // RRd,(rs)

    A_8qxwr_wrs,    // N(rx),rs
    A_wrs_8qxwr,    // rs,N(rx)
    A_grd_wrpip,    // Rd,(rrs)+
    A_wrpip_grd,    // (rrs)+,Rd
    A_wrd_wrpi,     // rd,(rrs)
    A_wrpi_wrd,     // (rrs),rd

    A_wrpi_grp,     // (rr),RR
    A_wrpi_16q,     // (rr),#NN

    A_grd_wrpim,    // Rd,-(rrs)
    A_wrpim_grd,    // -(rrs),Rd
    A_grpd_wrpim,   // RRd,-(rrs)
    A_wrpim_grpd,   // -(rrs),RRd
    A_16q_wrs,      // NN,rs 
    A_wrd_16q,      // rd,NN 

    A_grpd_wrpip,   // RRd,(rrs)+
    A_wrpip_grpd,   // (rrd)+,RRs

    A_wrip_wrpip,   // (rd)+,(rrs)+
    A_wrpip_wrip,   // (rrs)+,(rd)+

    A_8qxwrip_wrp,  // N(rx),rrs
    A_wrp_8qxwrip,  // rrd,N(rx)

    A_wrp_16q,      // rrd,NN
    A_16q_wrp,      // NN,rrs

    A_wrp_wrp_grp,  // rrh,rrl,RRs
    A_wrdi_grp,     // (rd),RRs
    A_wrpi_8q,      // (rrd),#N

    A_wrb_wrb_10,   // rd.b,rs.b with first word mask xxx1xxxx xxx0xxxx
    A_wrb_wrb_11,   // rd.b,rs.b with first word mask xxx1xxxx xxx1xxxx
    A_wrb_nwrb_10,  // rd.b,!rs.b with first word mask xxx1xxxx xxx0xxxx
    A_wrb_nwrb_11,  // rd.b,!rs.b with first word mask xxx1xxxx xxx1xxxx
    A_wrb,          // rd.b
    A_wrbi,         // (rr).bd
    A_bwr_8q_0,     // b.rd,N with first byte mask xxx0xxxx 
    A_bwr_8q_1,     // b.rd,N with first byte mask xxx1xxxx 
    
    A_seg_16q_01,   // nnnnnn,NN with first byte mask 01xxxxxx
    A_seg_16q_11,   // nnnnnn,NN with first byte mask 11xxxxxx

    A_rwn_000,      // wwwww with first byte mask xxxxx000
    A_rwn_100,      // wwwww with first byte mask xxxxx100
    A_rwn_101,      // wwwww with first byte mask xxxxx101
    A_rpn,          // pppppp
};

struct opcode {
    int code;           // opcode
    int insn;           // insn mnemonic
    int addr;           // addressing mode
};

static const struct opcode opcodes[] = {
    { 0x00,     st9_ei,         A_IMPL          },
    { 0x01,     st9_scf,        A_IMPL          },
    { 0x02,     st9_or,         A_wrd_wrs       },
    { 0x03,     st9_or,         A_wrd_wrsi      },
    { 0x04,     st9_or,         A_grd_grs       },
    { 0x05,     st9_or,         A_grd_8q        },
    { 0x06,     st9_aldw,       A_8qxwrp_16q    },
    { 0x06,     st9_aldw,       A_16qxwrp_16q   },
    { 0x07,     st9_orw,        A_grpd_grps     },
    { 0x07,     st9_orw,        A_grpd_16q_1    },
    { 0x08,     st9_ld,         A_grs           },
    { 0x09,     st9_ld,         A_grd           },
    { 0x0A,     st9_djnz,       A_8q            },
    { 0x0B,     st9_jrcc,       A_8q            },
    { 0x0C,     st9_ld,         A_8q            },
    { 0x0D,     st9_jpcc,       A_16q           },
    { 0x0E,     st9_orw,        A_wrpd_wrps     },
    { 0x0E,     st9_orw,        A_wrpdi_wrps    },
    { 0x0E,     st9_orw,        A_wrpd_wrpsi    },
    { 0x0E,     st9_orw,        A_wrpdi_wrpsi   },
    { 0x0F,     st9_bor,        A_wrb_wrb_10    },
    { 0x0F,     st9_bor,        A_wrb_nwrb_11   },
    { 0x0F,     st9_bset,       A_wrb           },
    { 0x10,     st9_di,         A_IMPL          },
    { 0x11,     st9_rcf,        A_IMPL          },
    { 0x12,     st9_and,        A_wrd_wrs       },
    { 0x13,     st9_and,        A_wrd_wrsi      },
    { 0x14,     st9_and,        A_grd_grs       },
    { 0x15,     st9_and,        A_grd_8q        },
    { 0x16,     st9_xch,        A_grs_grd       },
    { 0x17,     st9_andw,       A_grpd_grps     },
    { 0x17,     st9_andw,       A_grpd_16q_1    },
    { 0x18,     st9_ld,         A_grs           },
    { 0x19,     st9_ld,         A_grd           },
    { 0x1A,     st9_djnz,       A_8q            },
    { 0x1B,     st9_jrcc,       A_8q            },
    { 0x1C,     st9_ld,         A_8q            },
    { 0x1D,     st9_jpcc,       A_16q           },
    { 0x1E,     st9_andw,       A_wrpd_wrps     },
    { 0x1E,     st9_andw,       A_wrpdi_wrps    },
    { 0x1E,     st9_andw,       A_wrpd_wrpsi    },
    { 0x1E,     st9_andw,       A_wrpdi_wrpsi   },
    { 0x1F,     st9_band,       A_wrb_wrb_11    },
    { 0x1F,     st9_band,       A_wrb_nwrb_10   },
    { 0x1F,     st9_bres,       A_wrb           },
    { 0x20,     st9_popu,       A_grd           },
    { 0x21,     st9_popu,       A_grdi          },
    { 0x22,     st9_sbc,        A_wrd_wrs       },
    { 0x23,     st9_sbc,        A_wrd_wrsi      },
    { 0x24,     st9_sbc,        A_grd_grs       },
    { 0x25,     st9_sbc,        A_grd_8q        },
    { 0x26,     st9_ald,        A_8qxwrp_gr     },
    { 0x26,     st9_ald,        A_16qxwrp_gr    },
    { 0x27,     st9_sbcw,       A_grpd_grps     },
    { 0x27,     st9_sbcw,       A_grpd_16q_1    },
    { 0x28,     st9_ld,         A_grs           },
    { 0x29,     st9_ld,         A_grd           },
    { 0x2A,     st9_djnz,       A_8q            },
    { 0x2B,     st9_jrcc,       A_8q            },
    { 0x2C,     st9_ld,         A_8q            },
    { 0x2D,     st9_jpcc,       A_16q           },
    { 0x2E,     st9_sbcw,       A_wrpd_wrps     },
    { 0x2E,     st9_sbcw,       A_wrpdi_wrps    },
    { 0x2E,     st9_sbcw,       A_wrpd_wrpsi    },
    { 0x2E,     st9_sbcw,       A_wrpdi_wrpsi   },
    { 0x2F,     st9_sraw,       A_grp_0         },
    { 0x2F,     st9_ald,        A_16q_8q        },
    { 0x30,     st9_pushu,      A_grd           },
    { 0x31,     st9_pushu,      A_grdi          },
    { 0x32,     st9_adc,        A_wrd_wrs       },
    { 0x33,     st9_adc,        A_wrd_wrsi      },
    { 0x34,     st9_adc,        A_grd_grs       },
    { 0x35,     st9_adc,        A_grd_8q        },
    { 0x36,     st9_rrcw,       A_grp_0         },
    { 0x36,     st9_aldw,       A_16q_16q       },
    { 0x37,     st9_adcw,       A_grpd_grps     },
    { 0x37,     st9_adcw,       A_grpd_16q_1    },
    { 0x38,     st9_ld,         A_grs           },
    { 0x39,     st9_ld,         A_grd           },
    { 0x3A,     st9_djnz,       A_8q            },
    { 0x3B,     st9_jrcc,       A_8q            },
    { 0x3C,     st9_ld,         A_8q            },
    { 0x3D,     st9_jpcc,       A_16q           },
    { 0x3E,     st9_adcw,       A_wrpd_wrps     },
    { 0x3E,     st9_adcw,       A_wrpdi_wrps    },
    { 0x3E,     st9_adcw,       A_wrpd_wrpsi    },
    { 0x3E,     st9_adcw,       A_wrpdi_wrpsi   },
    { 0x3F,     st9_calls,      A_seg_16q_01    },
    { 0x3F,     st9_jps,        A_seg_16q_11    },
    { 0x40,     st9_dec,        A_grd           },
    { 0x41,     st9_dec,        A_grdi          },
    { 0x42,     st9_add,        A_wrd_wrs       },
    { 0x43,     st9_add,        A_wrd_wrsi      },
    { 0x44,     st9_add,        A_grd_grs       },
    { 0x45,     st9_add,        A_grd_8q        },
    { 0x46,     st9_ret,        A_IMPL          },
    { 0x47,     st9_addw,       A_grpd_grps     },
    { 0x47,     st9_addw,       A_grpd_16q_1    },
    { 0x48,     st9_ld,         A_grs           },
    { 0x49,     st9_ld,         A_grd           },
    { 0x4A,     st9_djnz,       A_8q            },
    { 0x4B,     st9_jrcc,       A_8q            },
    { 0x4C,     st9_ld,         A_8q            },
    { 0x4D,     st9_jpcc,       A_16q           },
    { 0x4E,     st9_addw,       A_wrpd_wrps     },
    { 0x4E,     st9_addw,       A_wrpdi_wrps    },
    { 0x4E,     st9_addw,       A_wrpd_wrpsi    },
    { 0x4E,     st9_addw,       A_wrpdi_wrpsi   },
    { 0x4F,     st9_mul,        A_wrpd_wrs      },
    { 0x50,     st9_inc,        A_grd           },
    { 0x51,     st9_inc,        A_grdi          },
    { 0x52,     st9_sub,        A_wrd_wrs       },
    { 0x53,     st9_sub,        A_wrd_wrsi      },
    { 0x54,     st9_sub,        A_grd_grs       },
    { 0x55,     st9_sub,        A_grd_8q        },
    { 0x56,     st9_divws,      A_wrp_wrp_grp   },
    { 0x57,     st9_subw,       A_grpd_grps     },
    { 0x57,     st9_subw,       A_grpd_16q_1    },
    { 0x58,     st9_ld,         A_grs           },
    { 0x59,     st9_ld,         A_grd           },
    { 0x5A,     st9_djnz,       A_8q            },
    { 0x5B,     st9_jrcc,       A_8q            },
    { 0x5C,     st9_ld,         A_8q            },
    { 0x5D,     st9_jpcc,       A_16q           },
    { 0x5E,     st9_subw,       A_wrpd_wrps     },
    { 0x5E,     st9_subw,       A_wrpdi_wrps    },
    { 0x5E,     st9_subw,       A_wrpd_wrpsi    },
    { 0x5E,     st9_subw,       A_wrpdi_wrpsi   },
    { 0x5F,     st9_div,        A_wrpd_wrs      },
    { 0x60,     st9_ald,        A_wr_wrpxwrp    },
    { 0x60,     st9_ald,        A_wrpxwrp_wr    },
    { 0x60,     st9_aldw,       A_wrp_wrpxwrp   },
    { 0x60,     st9_aldw,       A_wrpxwrp_wrp   },
    { 0x61,     st9_ccf,        A_IMPL          },
    { 0x62,     st9_xor,        A_wrd_wrs       },
    { 0x63,     st9_xor,        A_wrd_wrsi      },
    { 0x64,     st9_xor,        A_grd_grs       },
    { 0x65,     st9_xor,        A_grd_8q        },
    { 0x66,     st9_push,       A_grd           },
    { 0x67,     st9_xorw,       A_grpd_grps     },
    { 0x67,     st9_xorw,       A_grpd_16q_1    },
    { 0x68,     st9_ld,         A_grs           },
    { 0x69,     st9_ld,         A_grd           },
    { 0x6A,     st9_djnz,       A_8q            },
    { 0x6B,     st9_jrcc,       A_8q            },
    { 0x6C,     st9_ld,         A_8q            },
    { 0x6D,     st9_jpcc,       A_16q           },
    { 0x6E,     st9_xorw,       A_wrpd_wrps     },
    { 0x6E,     st9_xorw,       A_wrpdi_wrps    },
    { 0x6E,     st9_xorw,       A_wrpd_wrpsi    },
    { 0x6E,     st9_xorw,       A_wrpdi_wrpsi   },
    { 0x6F,     st9_bxor,       A_wrb_wrb_10    },
    { 0x6F,     st9_bxor,       A_wrb_nwrb_11   },    
    { 0x6F,     st9_bcpl,       A_wrb           },
    { 0x70,     st9_da,         A_grd           },
    { 0x71,     st9_da,         A_grdi          },
    { 0x72,     st9_ald,        A_gr_wrpi       },
    { 0x72,     st9_ald,        A_wrip_gr       },
    { 0x73,     st9_calls,      A_gri_wrip_01   },
    { 0x73,     st9_jps,        A_gri_wrip_11   },
    { 0x73,     st9_ald,        A_grpi_wrip     },
    { 0x74,     st9_call,       A_grpdi         },
    { 0x74,     st9_pushw,      A_grps          },
    { 0x75,     st9_popw,       A_grpd_0        },
    { 0x75,     st9_unlink,     A_grpd_1        },
    { 0x76,     st9_pop,        A_grd           },
    { 0x77,     st9_pop,        A_grdi          },
    { 0x78,     st9_ld,         A_grs           },
    { 0x79,     st9_ld,         A_grd           },
    { 0x7A,     st9_djnz,       A_8q            },
    { 0x7B,     st9_jrcc,       A_8q            },
    { 0x7C,     st9_ld,         A_8q            },
    { 0x7D,     st9_jpcc,       A_16q           },
    { 0x7E,     st9_aldw,       A_grp_wrpi      },
    { 0x7F,     st9_ald,        A_gr_8qxwrp     },
    { 0x7F,     st9_ald,        A_gr_16qxwrp    },
    { 0x80,     st9_cpl,        A_grd           },
    { 0x81,     st9_cpl,        A_grdi          },
    { 0x82,     st9_cp,         A_wrd_wrs       },
    { 0x83,     st9_cp,         A_wrd_wrsi      },
    { 0x84,     st9_cp,         A_grd_grs       },
    { 0x85,     st9_cp,         A_grd_8q        },
    { 0x86,     st9_aldw,       A_8qxwrp_grp    },
    { 0x86,     st9_aldw,       A_grp_8qxwrp    },
    { 0x86,     st9_aldw,       A_16qxwrp_grp   },
    { 0x86,     st9_aldw,       A_grp_16qxwrp   },
    { 0x87,     st9_cpw,        A_grpd_grps     },
    { 0x87,     st9_cpw,        A_grpd_16q_1    },
    { 0x88,     st9_ld,         A_grs           },
    { 0x89,     st9_ld,         A_grd           },
    { 0x8A,     st9_djnz,       A_8q            },
    { 0x8B,     st9_jrcc,       A_8q            },
    { 0x8C,     st9_ld,         A_8q            },
    { 0x8D,     st9_jpcc,       A_16q           },
    { 0x8E,     st9_cpw,        A_wrpd_wrps     },
    { 0x8E,     st9_cpw,        A_wrpdi_wrps    },
    { 0x8E,     st9_cpw,        A_wrpd_wrpsi    },
    { 0x8E,     st9_cpw,        A_wrpdi_wrpsi   },
    { 0x8FF1,   st9_push,       A_8q            },
    { 0x8FF3,   st9_pushu,      A_8q            },
    { 0x8FC1,   st9_pushw,      A_16q           },
    { 0x8FC3,   st9_pushuw,     A_16q           },
    { 0x8F01,   st9_pea,        A_8qxgrpi       },
    { 0x8F01,   st9_pea,        A_16qxgrpi      },
    { 0x8F03,   st9_peau,       A_8qxgrpi       },
    { 0x8F03,   st9_peau,       A_16qxgrpi      },
    { 0x8F,     st9_rlcw,       A_grpd_0        },
    { 0x90,     st9_clr,        A_grd           },
    { 0x91,     st9_clr,        A_grdi          },
    { 0x92,     st9_cp,         A_wrd_wrs       },
    { 0x93,     st9_cp,         A_wrd_wrsi      },
    { 0x94,     st9_cp,         A_grd_grs       },
    { 0x95,     st9_cp,         A_grd_8q        },
    { 0x96,     st9_aldw,       A_wrdi_grp      },
    { 0x97,     st9_cpw,        A_grpd_grps     },
    { 0x97,     st9_cpw,        A_grpd_16q_1    },
    { 0x98,     st9_ld,         A_grs           },
    { 0x99,     st9_ld,         A_grd           },
    { 0x9A,     st9_djnz,       A_8q            },
    { 0x9B,     st9_jrcc,       A_8q            },
    { 0x9C,     st9_ld,         A_8q            },
    { 0x9D,     st9_jpcc,       A_16q           },
    { 0x9E,     st9_cpw,        A_wrpd_wrps     },
    { 0x9E,     st9_cpw,        A_wrpdi_wrps    },
    { 0x9E,     st9_cpw,        A_wrpd_wrpsi    },
    { 0x9E,     st9_cpw,        A_wrpdi_wrpsi   },
    { 0x9F,     st9_cpjfi,      A_wrd_wrpsi_8q_0    },
    { 0x9F,     st9_cpjti,      A_wrd_wrpsi_8q_1    },
    { 0xA0,     st9_rol,        A_grd           },
    { 0xA1,     st9_rol,        A_grdi          },
    { 0xA2,     st9_tm,         A_wrd_wrs       },
    { 0xA3,     st9_tm,         A_wrd_wrsi      },
    { 0xA4,     st9_tm,         A_grd_grs       },
    { 0xA5,     st9_tm,         A_grd_8q        },
    { 0xA6,     st9_aldw,       A_grpd_wrsi     },
    { 0xA7,     st9_tmw,        A_grpd_grps     },
    { 0xA7,     st9_tmw,        A_grpd_16q_1    },
    { 0xA8,     st9_ld,         A_grs           },
    { 0xA9,     st9_ld,         A_grd           },
    { 0xAA,     st9_djnz,       A_8q            },
    { 0xAB,     st9_jrcc,       A_8q            },
    { 0xAC,     st9_ld,         A_8q            },
    { 0xAD,     st9_jpcc,       A_16q           },
    { 0xAE,     st9_tmw,        A_wrpd_wrps     },
    { 0xAE,     st9_tmw,        A_wrpdi_wrps    },
    { 0xAE,     st9_tmw,        A_wrpd_wrpsi    },
    { 0xAE,     st9_tmw,        A_wrpdi_wrpsi   },
    { 0xAF,     st9_btjt,       A_bwr_8q_0      },
    { 0xAF,     st9_btjf,       A_bwr_8q_1      },
    { 0xB0,     st9_rlc,        A_grd           },
    { 0xB1,     st9_rlc,        A_grdi          },
    { 0xB2,     st9_ld,         A_8qxwr_wrs     },
    { 0xB3,     st9_ld,         A_wrs_8qxwr     },
    { 0xB4,     st9_ald,        A_grd_wrpip     },
    { 0xB4,     st9_ald,        A_wrpip_grd     },
    { 0xB5,     st9_ld,         A_wrd_wrpi      },
    { 0xB5,     st9_ld,         A_wrpi_wrd      },
    { 0xB6,     st9_pushuw,     A_grp_0         },
    { 0xB6,     st9_linku,      A_grp_8q        },
    { 0xB7,     st9_popuw,      A_grp_0         },
    { 0xB7,     st9_unlinku,    A_grp_1         },
    { 0xB8,     st9_ld,         A_grs           },
    { 0xB9,     st9_ld,         A_grd           },
    { 0xBA,     st9_djnz,       A_8q            },
    { 0xBB,     st9_jrcc,       A_8q            },
    { 0xBC,     st9_ld,         A_8q            },
    { 0xBD,     st9_jpcc,       A_16q           },
    { 0xBE,     st9_aldw,       A_wrpi_grp      },
    { 0xBE,     st9_aldw,       A_wrpi_16q      },
    { 0xBF01,   st9_halt,       A_IMPL          },
    { 0xBF,     st9_ldw,        A_grpd_16q_0    },
    { 0xC0,     st9_ror,        A_grd           },
    { 0xC1,     st9_ror,        A_grdi          },
    { 0xC2,     st9_ald,        A_grd_wrpim     },
    { 0xC2,     st9_ald,        A_wrpim_grd     },
    { 0xC3,     st9_aldw,       A_grpd_wrpim    },      
    { 0xC3,     st9_aldw,       A_wrpim_grpd    },
    { 0xC4,     st9_ald,        A_wrd_16q       },
    { 0xC5,     st9_ald,        A_16q_wrs       },
    { 0xC6,     st9_ext,        A_grp_1         },
    { 0xC6,     st9_dwjnz,      A_grp_8q        },
    { 0xC7,     st9_srp,        A_rwn_000       },
    { 0xC7,     st9_srp0,       A_rwn_100       },
    { 0xC7,     st9_srp1,       A_rwn_101       },
    { 0xC7,     st9_spp,        A_rpn           },
    { 0xC8,     st9_ld,         A_grs           },
    { 0xC9,     st9_ld,         A_grd           },
    { 0xCA,     st9_djnz,       A_8q            },
    { 0xCB,     st9_jrcc,       A_8q            },
    { 0xCC,     st9_ld,         A_8q            },
    { 0xCD,     st9_jpcc,       A_16q           },
    { 0xCE,     st9_etrap,      A_IMPL          },
    { 0xCF,     st9_decw,       A_grpd_0        },
    { 0xD0,     st9_rrc,        A_grd           },
    { 0xD1,     st9_rrc,        A_grdi          },
    { 0xD2,     st9_call,       A_16q           },
    { 0xD3,     st9_iret,       A_IMPL          },
    { 0xD4,     st9_jp,         A_grpi          },
    { 0xD4,     st9_link,       A_grp_8q        },
    { 0xD5,     st9_aldw,       A_grpd_wrpip    },
    { 0xD5,     st9_aldw,       A_wrpip_grpd    },
    { 0xD6,     st9_ldpp,       A_wrpdip_wrpsip_00  },
    { 0xD6,     st9_lddp,       A_wrpdip_wrpsip_10  },
    { 0xD6,     st9_ldpd,       A_wrpdip_wrpsip_01  },
    { 0xD6,     st9_lddd,       A_wrpdip_wrpsip_11  },
    { 0xD7,     st9_ld,         A_wrip_wrpip    },
    { 0xD7,     st9_ld,         A_wrpip_wrip    },
    { 0xD8,     st9_ld,         A_grs           },
    { 0xD9,     st9_ld,         A_grd           },
    { 0xDA,     st9_djnz,       A_8q            },
    { 0xDB,     st9_jrcc,       A_8q            },
    { 0xDC,     st9_ld,         A_8q            },
    { 0xDD,     st9_jpcc,       A_16q           },
    { 0xDE,     st9_ldw,        A_8qxwrip_wrp   },
    { 0xDE,     st9_ldw,        A_wrp_8qxwrip   },
    { 0xDF,     st9_incw,       A_grpd_0        },
    { 0xE0,     st9_sra,        A_grd           },
    { 0xE1,     st9_sra,        A_grdi          },
    { 0xE2,     st9_aldw,       A_wrp_16q       },
    { 0xE2,     st9_aldw,       A_16q_wrp       },
    { 0xE3,     st9_ldw,        A_wrpd_wrps     },
    { 0xE3,     st9_ldw,        A_wrpdi_wrps    },
    { 0xE3,     st9_ldw,        A_wrpd_wrpsi    },
    { 0xE3,     st9_ldw,        A_wrpdi_wrpsi   },
    { 0xE4,     st9_ld,         A_wrd_wrsi      },
    { 0xE5,     st9_ld,         A_wrdi_wrs      },
    { 0xE6,     st9_ald,        A_wrdi_grs      },
    { 0xE7,     st9_ald,        A_grd_wrsi      },
    { 0xE8,     st9_ld,         A_grs           },
    { 0xE9,     st9_ld,         A_grd           },
    { 0xEA,     st9_djnz,       A_8q            },
    { 0xEB,     st9_jrcc,       A_8q            },
    { 0xEC,     st9_ld,         A_8q            },
    { 0xED,     st9_jpcc,       A_16q           },
    { 0xEE,     st9_spm,        A_IMPL          },
    { 0xEF01,   st9_wfi,        A_IMPL          },
    { 0xEF31,   st9_eret,       A_IMPL          },    
    { 0xEF,     st9_ldw,        A_grpd_grps     },
    { 0xF0,     st9_swap,       A_grd           },
    { 0xF1,     st9_swap,       A_grdi          },
    { 0xF2,     st9_bld,        A_wrb_wrb_10    },
    { 0xF2,     st9_bld,        A_wrb_nwrb_11   },
    { 0xF2,     st9_btset,      A_wrb           },
    { 0xF3,     st9_ald,        A_wrpi_8q       },
    { 0xF4,     st9_ld,         A_grd_grs       },
    { 0xF5,     st9_ld,         A_grd_8q        },
    { 0xF601,   st9_rets,       A_IMPL          },
    { 0xF6,     st9_btset,      A_wrbi          },
    { 0xF7,     st9_push,       A_grsi          },
    { 0xF8,     st9_ld,         A_grs           },
    { 0xF9,     st9_ld,         A_grd           },
    { 0xFA,     st9_djnz,       A_8q            },
    { 0xFB,     st9_jrcc,       A_8q            },
    { 0xFC,     st9_ld,         A_8q            },
    { 0xFD,     st9_jpcc,       A_16q           },
    { 0xFE,     st9_sdm,        A_IMPL          },
    { 0xFF,     st9_nop,        A_IMPL          }
};

static const struct opcode *find_opcode(const int _code) {
    for (int i = 0; i < qnumber(opcodes); i++) {

        // is the opcode coded in a word ?
        bool need_another_byte = 
            (((opcodes[i].code & 0xFF00) >> 8) != 0) ? true : false;

        int code = 
            (need_another_byte) ? (_code << 8) | get_byte(cmd.ea + cmd.size) : _code; 

        // opcode is wrong
        if (opcodes[i].code != code)
                continue;

        int next_byte = get_byte(cmd.ea + cmd.size + (need_another_byte ? 1 : 0));
        int mask = 0;
        int value;

        switch (opcodes[i].addr) {

            // 0000000X (X == 0)
            case A_grpd_grps:       
            case A_16qxwrp_16q:     
            case A_16qxwrp_gr:    
            case A_wrip_gr:
            case A_gr_16qxwrp:
            case A_grpd_0:
            case A_grps:      
            case A_wrpip_grd:
            case A_wrd_wrpi:
            case A_grp_0:
            case A_wrpi_16q:
            case A_grpd_16q_0:
            case A_wrpim_grd: 
            case A_wrpim_grpd:    
            case A_grpi:
            case A_wrpip_grpd: 
            case A_wrpip_wrip:  
            case A_wrp_16q:
                mask = 0x01;
                value = 0x00;
                break;

            case A_wrb:
                mask = 0x10;
                value = 0x00;
                break;

            // 0000000X (X == 1)
            case A_grpd_16q_1:        
            case A_8qxwrp_16q:
            case A_8qxwrp_gr:    
            case A_gr_wrpi:
            case A_gr_8qxwrp:    
            case A_grpd_1:
            case A_grpdi:  
            case A_grd_wrpip:    
            case A_wrpi_wrd:    
            case A_grp_1:
            case A_wrpi_grp:
            case A_grd_wrpim: 
            case A_grpd_wrpim:
            case A_grpd_wrpip:   
            case A_wrip_wrpip:  
            case A_16q_wrp:    
                mask = 0x01;
                value = 0x01;
                break;
        
            // 00000XXX (XXX = 000)
            case A_rwn_000: 
                mask = 0x07;
                value = 0x00;
                break;
            
            // 00000XXX (XXX = 100)
            case A_rwn_100: 
                mask = 0x07;
                value = 0x04;
                break;
            
            // 00000XXX (XXX = 101)
            case A_rwn_101:
                mask = 0x07;
                value = 0x05;
                break;

            // XY000000 (XY == 01)
            case A_seg_16q_01:
                mask = 0xC0;
                value = 0x40;
                break;

            // XY000000 (XY == 11)
            case A_seg_16q_11:
                mask = 0xC0;
                value = 0xC0;
                break;
            
            // 000000XY (XY = 10)
            case A_rpn:
                mask = 0x03;
                value = 0x02;
                break;
                
            // 000X0000 (X == 0)    
            case A_wrd_wrpsi_8q_0:
            case A_wrp_8qxwrip:        
            case A_bwr_8q_0:
                mask = 0x10;
                value = 0x00;
                break;

            // 000X0000 (X == 1)    
            case A_wrd_wrpsi_8q_1:
            case A_8qxwrip_wrp:    
            case A_bwr_8q_1:
                mask = 0x10;
                value = 0x10;
                break;
        
            // XXXX0000 (XXXX = 0100)    
            case A_gri_wrip_01:    
                mask = 0xF0;
                value = 0x40;
                break;
                
            // XXXX0000 (XXXX = 1100)    
            case A_gri_wrip_11:    
                mask = 0xF0;
                value = 0xC0;
                break;

            // 000X000Y (X == 0 && Y == 0)
            case A_wrpd_wrps:
            case A_wrpdip_wrpsip_00:
            case A_wrp_wrpxwrp: 
            case A_wrbi:
                mask = 0x11;
                value = 0x00;
                break;

            // 000X000Y (X == 1 && Y == 0)
            case A_wrpdi_wrps:
            case A_wrpdip_wrpsip_10:
            case A_wr_wrpxwrp:
                mask = 0x11;
                value = 0x10;
                break;
            
            // 000X000Y (X == 0 && Y == 1)
            case A_wrpd_wrpsi:
            case A_wrpdip_wrpsip_01:
            case A_wrpxwrp_wrp:
                mask = 0x11;
                value = 0x01;
                break;

            // 000X000Y (X == 1 && Y == 1)
            case A_wrpdi_wrpsi:
            case A_wrpdip_wrpsip_11:
            case A_wrpxwrp_wr: 
                mask = 0x11;
                value = 0x11;
                break;

            // 0000X (X = 0001)
            case A_16q_8q:
            case A_16q_16q:
                mask = 0x0F;
                value = 0x01;
                break;

            // 0000000X (X == 1) && 3th byte MSB == 1
            case A_8qxwrp_grp:
                if ((get_byte(cmd.ea + cmd.size + 2) & 0x01) == 1) {
                    mask = 0x01;
                    value = 0x01;
                }
                else
                    mask = -1;
                break;

            // 0000000X (X == 1) && 3th byte MSB == 0 
            case A_grp_8qxwrp:
                if ((get_byte(cmd.ea + cmd.size + 2) & 0x01) == 0) {
                    mask = 0x01;
                    value = 0x01;
                }
                else
                    mask = -1;
                break;

            // 0000000X (X == 1) && 4th byte MSB == 1 
            case A_16qxwrp_grp:
                if ((get_byte(cmd.ea + cmd.size + 3) & 0x01) == 1) {
                    mask = 0x01;
                    value = 0x00;
                }
                else
                    mask = -1;
                break;

            // 0000000X (X == 1) && 4th byte MSB == 0 
            case A_grp_16qxwrp:
                if ((get_byte(cmd.ea + cmd.size + 3) & 0x01) == 0) {
                    mask = 0x01;
                    value = 0x00;
                }
                else
                    mask = -1;
                break;

            // 2nd byte MSB == 0    
            case A_8qxgrpi:
                if ((get_byte(cmd.ea + cmd.size + 1) & 0x01) != 0) 
                    mask = -1;
                break;

            // 2nd byte MSB == 1    
            case A_16qxgrpi:    
                if ((get_byte(cmd.ea + cmd.size + 1) & 0x01) != 1) 
                    mask = -1;
                break;
           
            // NOTE: it seems that there is an error in the manual : 
            // rd.b,rs.b and rd.b,rs.!b opcodes are inversed !  
                
            // 000X0000 (X == 1) + 0x000Y0000 (Y == 0)
            case A_wrb_wrb_10:
            case A_wrb_nwrb_10:
                if ((get_byte(cmd.ea + cmd.size + 1) & 0x10) == 0) {
                    mask = 0x10;
                    value = 0x10;
                }
                else
                    mask = -1;
                break;
                
            // 000X0000 (X == 1) + 0x000Y0000 (Y == 1)
            case A_wrb_wrb_11:
            case A_wrb_nwrb_11:
                if ((get_byte(cmd.ea + cmd.size + 1) & 0x10) == 0x10) {
                    mask = 0x10;
                    value = 0x10;
                }
                else
                    mask = -1;
                break;
                
        }

        // addr mode is wrong 
        if (mask != 0 && (mask == -1 || (next_byte & mask) != value))
            continue;

        // Yahoo !  
        if (need_another_byte)
            cmd.size++;

        return &opcodes[i];
    }
    return NULL;
}

static int get_condition_code(const int code) {
    switch (code) {
        case 0x0B:      // JR F,N
        case 0x0D:      // JP F,NN
            return cF;

        case 0x1B:      // JR LT,N
        case 0x1D:      // JP LT,NN
            return cLT;

        case 0x2B:      // JR LE,N
        case 0x2D:      // JP LE,NN
            return cLE;

        case 0x3B:      // JR ULE,N
        case 0x3D:      // JP ULE,NN
            return cULE;

        case 0x4B:      // JR OV,N
        case 0x4D:      // JP OV,NN
            return cOV;

        case 0x5B:      // JR MI,N
        case 0x5D:      // JP MI,NN
            return cMI;

        case 0x6B:      // JR EQ,N
        case 0x6D:      // JP EQ,NN
            return cEQ;

        // XXX 
        // According to the manual, 0x7X is related
        // to the UL condition code.
        // JRUL/JPUL cannot be assembled (unknown instruction).
        // objdump9 disassemble 0x7X with the C condition code,
        // therefore we use it instead of UL.
        case 0x7B:      // JR C,N
        case 0x7D:      // JP C,NN
            return cC;

        case 0x8B:      // JR T,N
        case 0x8D:      // JP T,NN
            return cT;

        case 0x9B:      // JR GE,N
        case 0x9D:      // JP GE,NN
            return cGE;

        case 0xAB:      // JR GT,N
        case 0xAD:      // JP GT,NN
            return cGT;

        case 0xBB:      // JR UGT,N
        case 0xBD:      // JP UGT,NN
            return cUGT;

        case 0xCB:      // JR NOV,N
        case 0xCD:      // JP NOV,NN
            return cNOV;

        case 0xDB:      // JR PL,N
        case 0xDD:      // JP PL,NN
            return cPL;

        case 0xEB:      // JR NE,N
        case 0xED:      // JP NE,NN
            return cNE;

        case 0xFB:      // JR NC,N
        case 0xFD:      // JP NC,NN
            return cNC;
    }
    return cUNKNOWN; 
}

static int get_working_register(const int code) {
    int reg_id = (code & 0xF0) >> 4;

    switch (reg_id) {
        case 0:     return rr0;
        case 1:     return rr1;
        case 2:     return rr2;
        case 3:     return rr3;
        case 4:     return rr4;
        case 5:     return rr5;
        case 6:     return rr6;
        case 7:     return rr7;
        case 8:     return rr8;
        case 9:     return rr9;
        case 10:    return rr10;
        case 11:    return rr11;
        case 12:    return rr12;
        case 13:    return rr13;
        case 14:    return rr14;
        case 15:    return rr15;
    }

    return -1;
}

static const int get_alu_insn(const int code) {
    int insn_id = (code & 0xF0) >> 4;

    IDA_ASSERT(cmd.itype == st9_ald || cmd.itype == st9_aldw, "get_alu_insn() not called with ALD/ALDW");
    
    bool long_insn = cmd.itype == st9_aldw;
    
    if (!long_insn) {
        switch (insn_id) {
            case 0x0:     return st9_or;
            case 0x1:     return st9_and;
            case 0x2:     return st9_sbc;
            case 0x3:     return st9_adc;
            case 0x4:     return st9_add;
            case 0x5:     return st9_sub;
            case 0x6:     return st9_xor;
            case 0x8:     return st9_cp;
            case 0x9:     return st9_cp;
            case 0xA:     return st9_tm;
            case 0xF:     return st9_ld;
        }
    }
    else {  
        switch (insn_id) {
            case 0x0:     return st9_orw;
            case 0x1:     return st9_andw;
            case 0x2:     return st9_sbcw;
            case 0x3:     return st9_adcw;
            case 0x4:     return st9_addw;
            case 0x5:     return st9_subw;
            case 0x6:     return st9_xorw;
            case 0x8:     return st9_cpw;
            case 0x9:     return st9_cpw;
            case 0xA:     return st9_tmw;
            case 0xF:     return st9_ldw;
        }
    }
    return st9_null;
}

// fill instruction flag 
static void set_flag(int flag) {
    cmd.auxpref |= flag;
}

// fill operand flag
static void set_flag(op_t &x, int flag) {
    x.specflag1 |= flag;
}

// fill an operand as a register
static void set_reg(op_t &op, const int reg, const int flag = 0) { 
    op.type = o_reg;
    op.reg = reg;
    op.dtyp = dt_byte; 
    if (flag)
        set_flag(op, flag);
}

// fill an operand as an immediate value
static void set_imm(op_t &op, const int val, char d_typ, const int flag = 0) {
    op.type = o_imm;
    op.value = val;
    op.dtyp = d_typ;
    if (flag)
        set_flag(op, flag);
}

// fill an operand as a displacement
static void set_displ(op_t &op, optype_t a1_t, int a1, optype_t a2_t, int a2) {
    op.type = o_displ;
    op.reg = 0;
    switch (a1_t) {
        case o_reg:
            op.reg = a1; 
            break;
        
        case o_mem:
            op.addr = a1; 
            break;

        default:
            IDA_ERROR("Invalid a1_t in set_displ()");
    }
    switch (a2_t) {
        case o_reg:
            if (op.reg == 0) 
                op.reg = a2;
            else 
                IDA_ERROR("set_displ() called with 2 registers");
            break;

        default:
            IDA_ERROR("Invalid a2_t in set_displ()");
    }
    op.dtyp = dt_word;
}

// fill an operand as a phrase
static void set_phrase(op_t &op, enum st9_phrases phrase, const int reg1, const int reg2 = -1) {
    op.type = o_phrase;
    op.reg = reg1;
    op.specflag2 = phrase;
    op.dtyp = dt_byte;
    if (reg2 != -1) {
        op.specflag2 = (reg2 & 0xFF00) >> 8;
        op.specflag3 = (reg2 & 0x00FF);
    }
}

// add a bit number to a register operand
static void set_bit(op_t &op, const int bit, const int flag = 0) {
    op.value = bit;
    if (flag)
        set_flag(op, flag);
}

// fill an operand as an address (data or code)
static void set_addr(op_t &op, optype_t type, int addr) {
    IDA_ASSERT(type == o_mem || type == o_near, "bad optype_t in set_addr()");
    op.type = type;
    op.addr = addr;
    op.dtyp = dt_word;
}

static void fill_cmd(int byte, const struct opcode *op) {
    IDA_ASSERT(op != NULL, "op is NULL in fill_cmd()");
    cmd.itype = op->insn;

    switch (op->addr) {
        // Implied
        case A_IMPL:
            // Nothing to do !
            break;

        // rd,rs
        case A_wrd_wrs:
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + ((byte & 0xF0) >> 4)); 
            set_reg(cmd.Op2, rr0 + (byte & 0x0F)); 
            break;

        // rd,(rs)
        case A_wrd_wrsi:
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + ((byte & 0xF0) >> 4)); 
            set_reg(cmd.Op2, rr0 + (byte & 0x0F), OP_IS_IND); 
            break;

        // (rd),rs
        case A_wrdi_wrs:     
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + ((byte & 0xF0) >> 4), OP_IS_IND); 
            set_reg(cmd.Op2, rr0 + (byte & 0x0F)); 
            break;
    
        // (rd),Rs
        case A_wrdi_grs:     
            if (cmd.itype == st9_ald) {
                set_reg(cmd.Op2, rR0 + ua_next_byte());
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rr0 + (byte & 0x0F), OP_IS_IND);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;
    
        // Rd,(rs)
        case A_grd_wrsi:     
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rr0 + (byte & 0x0F), OP_IS_IND);
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;
        
        // Rs,Rd
        case A_grs_grd:     
        // Rd,Rs
        case A_grd_grs:     
            set_reg(cmd.Op2, rR0 + ua_next_byte());
            set_reg(cmd.Op1, rR0 + ua_next_byte());
            break;
            
        // Rd,#N
        case A_grd_8q: 
            set_reg(cmd.Op1, rR0 + ua_next_byte());
            set_imm(cmd.Op2, ua_next_byte(), dt_byte);
            break;

        // RRd,RRs
        case A_grpd_grps:
            set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));
            set_reg(cmd.Op2, rRR0 + (ua_next_byte() & 0xFE));
            break;

        // RRd,#NN
        case A_grpd_16q_0:
        case A_grpd_16q_1:
            set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));
            set_imm(cmd.Op2, ua_next_word(), dt_word);
            break;

        // RR,N
        case A_grp_8q: 
            {
                byte = ua_next_byte();
                int reg = rRR0 + (byte & 0xFE);
                if (cmd.itype == st9_dwjnz) {
                    set_addr(cmd.Op2, o_near, ua_next_byte());
                    cmd.Op2.addr = (signed char) cmd.Op2.addr + cmd.ip + cmd.size;
                }
                else { // link or linku
                    if ((byte & 0xF0) == 0xD0)
                        reg = rrr0 + (byte & 0x0E);
                    set_imm(cmd.Op2, 0xFF - ua_next_byte(), dt_byte);
                }
                set_reg(cmd.Op1, reg);
            }
            break;

        // Rs
        case A_grs:
            if (cmd.itype == st9_ld) {
                set_reg(cmd.Op1, get_working_register(byte));
                set_reg(cmd.Op2, rR0 + ua_next_byte());
            }
            else
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            break;        

        // Rd
        case A_grd:
            if (cmd.itype == st9_ld) {
                set_reg(cmd.Op2, get_working_register(byte));
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            }
            else
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            break;        

        // (R)
        case A_grdi:
        case A_grsi:
            set_reg(cmd.Op1, rR0 + ua_next_byte(), OP_IS_IND);
            break;

        // RR
        case A_grp_0:
        case A_grp_1:
        case A_grps:
        case A_grpd_0:
        case A_grpd_1:
            {
                byte = ua_next_byte();
                int reg = rRR0 + (byte & 0xFE);
            
                if ((cmd.itype == st9_unlink || cmd.itype == st9_unlinku) && (byte & 0xF0) == 0xD0)
                    reg = rrr0 + (byte & 0x0E);
                        
                set_reg(cmd.Op1, reg);
            }
            break;

        // (RR)
        case A_grpi:
        case A_grpdi: 
            set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE), OP_IS_IND);
            break;

        // N
        case A_8q:
            if (is_jmp_cc(cmd.itype)) {
                set_flag(get_condition_code(byte));
                set_addr(cmd.Op1, o_near, ua_next_byte());
                cmd.Op1.addr = (signed char) cmd.Op1.addr + cmd.ip + cmd.size;
            }
            else if (cmd.itype == st9_djnz) {
                set_reg(cmd.Op1, get_working_register(byte));
                set_addr(cmd.Op2, o_near, ua_next_byte());
                cmd.Op2.addr = (signed char) cmd.Op2.addr + cmd.ip + cmd.size;
            }
            else if (cmd.itype == st9_ld) {
                set_reg(cmd.Op1, get_working_register(byte));
                set_imm(cmd.Op2, ua_next_byte(), dt_byte);
                cmd.Op2.addr = (signed char) cmd.Op2.addr + cmd.ip + cmd.size;
            }
            else if (cmd.itype == st9_push || cmd.itype == st9_pushu || cmd.itype == st9_pushw) {
                set_imm(cmd.Op1, ua_next_byte(), dt_byte);
            }
            else {
                set_addr(cmd.Op1, o_mem, ua_next_byte());
                cmd.Op1.addr = (signed char) cmd.Op1.addr + cmd.ip + cmd.size;
            }
            break;

        // NN    
        case A_16q:
            if (is_jmp_cc(cmd.itype) || cmd.itype == st9_call) { 
                if (is_jmp_cc(cmd.itype)) set_flag(get_condition_code(byte));
                set_addr(cmd.Op1, o_near, ua_next_word());
            }
            else if (cmd.itype == st9_push || cmd.itype == st9_pushu || cmd.itype == st9_pushw || cmd.itype == st9_pushuw) {
                set_imm(cmd.Op1, ua_next_word(), dt_word);
            }
            else
                set_addr(cmd.Op1, o_mem, ua_next_word());
            break;

        // rrd,rrs
        case A_wrpd_wrps:    
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4));
            set_reg(cmd.Op2, rrr0 + (byte & 0x0E));
            break;

        // (rrd),rrs    
        case A_wrpdi_wrps:   
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4), OP_IS_IND);
            set_reg(cmd.Op2, rrr0 + (byte & 0x0E));
            break;
        
        // rrd,(rrs)
        case A_wrpd_wrpsi:   
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4));
            set_reg(cmd.Op2, rrr0 + (byte & 0x0E), OP_IS_IND);
            break;
        
        // (rrd),(rrs)
        case A_wrpdi_wrpsi:  
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4), OP_IS_IND);
            set_reg(cmd.Op2, rrr0 + (byte & 0x0E), OP_IS_IND);
            break;

        // rrd,rs
        case A_wrpd_wrs:
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4));
            set_reg(cmd.Op2, rr0 + (byte & 0x0F));
            break;

        // rd,(rrs)    
        case A_wrd_wrpi:     
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + ((byte & 0xF0) >> 4));
            set_reg(cmd.Op2, rrr0 + (byte & 0x0E), OP_IS_IND);
            break;

        // (rrs),rd    
        case A_wrpi_wrd:     
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + (byte & 0x0E), OP_IS_IND);
            set_reg(cmd.Op2, rr0 + ((byte & 0xF0) >> 4));
            break;

        // Nd(rr),#NNs
        case A_8qxwrp_16q:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op1, o_mem, char(ua_next_byte()), o_reg, rrr0 + (byte & 0x0E));
                set_imm(cmd.Op2, ua_next_word(), dt_word);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */
            break;
        
        // NNd(rr),#NNs
        case A_16qxwrp_16q:  
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op1, o_mem, short(ua_next_word()), o_reg, rrr0 + (byte & 0x0E));
                set_imm(cmd.Op2, ua_next_word(), dt_word);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */
            break;

        // N(rr),R
        case A_8qxwrp_gr:
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op1, o_mem, char(ua_next_byte()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */
            break;
        
        // NN(rr),R    
        case A_16qxwrp_gr:   
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op1, o_mem, short(ua_next_word()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */
            break;

        // NNd,#Ns    
        case A_16q_8q:
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_imm(cmd.Op2, ua_next_byte(), dt_byte);
                set_addr(cmd.Op1, o_mem, ua_next_word());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // NNd,#NNs    
        case A_16q_16q:
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_imm(cmd.Op2, ua_next_word(), dt_word);
                set_addr(cmd.Op1, o_mem, ua_next_word());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // rd,rrs(rrx)    
        case A_wr_wrpxwrp:   
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                set_phrase(cmd.Op2, fDISP, rrr0 + ((byte & 0xE0) >> 4), rrr0 + (byte & 0x0E));
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rr0 + (byte & 0x0F));                
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;
        
        // rrd(rrx),rs    
        case A_wrpxwrp_wr:   
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                set_phrase(cmd.Op1, fDISP, rrr0 + ((byte & 0xE0) >> 4), rrr0 + (byte & 0x0E));
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rr0 + (byte & 0x0F));                
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // rrd,rrs(rrx)    
        case A_wrp_wrpxwrp:  
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                set_phrase(cmd.Op2, fDISP, rrr0 + ((byte & 0xE0) >> 4), rrr0 + (byte & 0x0E));
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rrr0 + (byte & 0x0E));                
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // rrd(rrx),rrs    
        case A_wrpxwrp_wrp:  
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                set_phrase(cmd.Op1, fDISP, rrr0 + ((byte & 0xE0) >> 4), rrr0 + (byte & 0x0E));
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rrr0 + (byte & 0x0E));                
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // Rd,(rrs)    
        case A_gr_wrpi: 
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_reg(cmd.Op1, rR0 + ua_next_byte()); 
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;
   
        // (rrd),Rs    
        case A_wrip_gr:      
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_reg(cmd.Op2, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // (RRd),(rrs)    
        case A_grpi_wrip:    
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE), OP_IS_IND);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // (R),(rr)    
        case A_gri_wrip_01:    
        case A_gri_wrip_11:    
            set_reg(cmd.Op2, rrr0 + (ua_next_byte() & 0x0E), OP_IS_IND);
            set_reg(cmd.Op1, rR0 + ua_next_byte(), OP_IS_IND);
            break;

        // Rd,N(rrx)    
        case A_gr_8qxwrp:    
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op2, o_mem, char(ua_next_byte()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // Rd,NN(rrx)    
        case A_gr_16qxwrp:   
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op2, o_mem, short(ua_next_word()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // RRd,(rrs)    
        case A_grp_wrpi:     
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // N(rrx),RRs    
        case A_8qxwrp_grp:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op1, o_mem, char(ua_next_byte()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rRR0 + (ua_next_byte() & 0xFE));    
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // RRd,N(rrx)    
        case A_grp_8qxwrp:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op2, o_mem, char(ua_next_byte()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));    
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // NN(rrx),RRs    
        case A_16qxwrp_grp:  
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op1, o_mem, short(ua_next_word()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rRR0 + (ua_next_byte() & 0xFE));    
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // RRd,NN(rrx)    
        case A_grp_16qxwrp:  
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_displ(cmd.Op2, o_mem, short(ua_next_word()), o_reg, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));    
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // N(RRx)    
        case A_8qxgrpi:
            byte = ua_next_byte();
            set_displ(cmd.Op1, o_mem, char(ua_next_byte()), o_reg, rRR0 + (byte & 0xFE));
            break;

        // NN(RRx)    
        case A_16qxgrpi:
            byte = ua_next_byte();
            // this word is coded with little endian
            set_displ(cmd.Op1, o_mem, short(ua_next_byte() | (ua_next_byte() << 8)), o_reg, rRR0 + (byte & 0xFE));
            break;

        // rd,(rrs),N    
        case A_wrd_wrpsi_8q_0: 
        case A_wrd_wrpsi_8q_1:
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + (byte & 0x0F));
            set_reg(cmd.Op2, rrr0 + ((byte & 0xE0) >> 4), OP_IS_IND);
            set_imm(cmd.Op3, ua_next_byte(), dt_byte);
            break;

        // RRd,(rs)    
        case A_grpd_wrsi:
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rr0 + (byte & 0x0F), OP_IS_IND);
                set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;
            
        // N(rx),rs    
        case A_8qxwr_wrs:
            byte = ua_next_byte();
            set_reg(cmd.Op2, rr0 + ((byte & 0xF0) >> 4));
            set_displ(cmd.Op1, o_mem, char(ua_next_byte()), o_reg, rr0 + (byte & 0x0F));
            break;

        // rs,N(rx)    
        case A_wrs_8qxwr:    
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + ((byte & 0xF0) >> 4));
            set_displ(cmd.Op2, o_mem, char(ua_next_byte()), o_reg, rr0 + (byte & 0x0F));
            break;

        // Rd,(rrs)+    
        case A_grd_wrpip:    
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op2, fPI, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // (rrs)+,Rd    
        case A_wrpip_grd:    
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op1, fPI, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // (rr),RR    
        case A_wrpi_grp:     
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_reg(cmd.Op2, rRR0 + (ua_next_byte() & 0x0E));
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // (rr),#NN    
        case A_wrpi_16q:     
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_imm(cmd.Op2, ua_next_word(), dt_word);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // Rd,-(rrs)    
        case A_grd_wrpim:    
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op2, fPD, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // -(rrs),Rd
        case A_wrpim_grd:   
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op1, fPD, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // RRd,-(rrs)
        case A_grpd_wrpim:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op2, fPD, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rRR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // -(rrs),RRd
        case A_wrpim_grpd:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op1, fPD, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rRR0 + ua_next_byte());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // NN,rs
        case A_16q_wrs:    
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rr0 + (byte & 0x0F));
                set_addr(cmd.Op1, o_mem, ua_next_word());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

        // rd,NN
        case A_wrd_16q:
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rr0 + (byte & 0x0F));
                set_addr(cmd.Op2, o_mem, ua_next_word());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;
            
        // (rd)+,(rrs)+
        case A_wrip_wrpip:   
            byte = ua_next_byte();
            set_phrase(cmd.Op1, fPI, rr0 + ((byte & 0xE0) >> 4));
            set_phrase(cmd.Op2, fPI, rrr0 + (byte & 0x0E));
            break;

        // (rrs)+,(rd)+    
        case A_wrpip_wrip:   
            byte = ua_next_byte();
            set_phrase(cmd.Op2, fPI, rr0 + ((byte & 0xE0) >> 4));
            set_phrase(cmd.Op1, fPI, rrr0 + (byte & 0x0E));
            break;

        // (rrd)+,(rrs)+    
        case A_wrpdip_wrpsip_00:
        case A_wrpdip_wrpsip_10:
        case A_wrpdip_wrpsip_01:
        case A_wrpdip_wrpsip_11:
            byte = ua_next_byte();
            set_phrase(cmd.Op1, fPI, rrr0 + ((byte & 0xE0) >> 4));
            set_phrase(cmd.Op2, fPI, rrr0 + (byte & 0x0E));
            break;
            
        // RRd,(rrs)+    
        case A_grpd_wrpip:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op2, fPI, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op1, rRR0 + (ua_next_byte() & 0xFE));
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // (rrd)+,RRs
        case A_wrpip_grpd:   
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_phrase(cmd.Op1, fPI, rrr0 + (byte & 0x0E));
                set_reg(cmd.Op2, rRR0 + (ua_next_byte() & 0xFE));
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;
        
        // N(rx),rrs    
        case A_8qxwrip_wrp: 
            byte = ua_next_byte();
            set_displ(cmd.Op1, o_mem, char(ua_next_byte()), o_reg, rr0 + (byte & 0x0F));
            set_reg(cmd.Op2, rrr0 + ((byte & 0xE0) >> 4));
            break;

        // rrd,N(rx)    
        case A_wrp_8qxwrip:  
            byte = ua_next_byte();
            set_displ(cmd.Op2, o_mem, char(ua_next_byte()), o_reg, rr0 + (byte & 0x0F));
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4));
            break;

        // rrd,NN    
        case A_wrp_16q:
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rrr0 + (byte & 0x0E));
                set_addr(cmd.Op2, o_mem, ua_next_word());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // NN,rrs    
        case A_16q_wrp:
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op2, rrr0 + (byte & 0x0E));
                set_addr(cmd.Op1, o_mem, ua_next_word());
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // rrh,rrl,RRs
        case A_wrp_wrp_grp:
            set_reg(cmd.Op3, rRR0 + (ua_next_byte() & 0x0E));
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + ((byte & 0xE0) >> 4));
            set_reg(cmd.Op2, rrr0 + (byte & 0x0E));
            break;

        // (rd),RRs
        case A_wrdi_grp:
            if (cmd.itype == st9_aldw) {
                byte = ua_next_byte();
                set_reg(cmd.Op2, rRR0 + (byte & 0x0E));
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rr0 + (byte & 0x0F), OP_IS_IND);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALDW");
#endif /* __DEBUG__ */            
            break;

        // (rrd),#N
        case A_wrpi_8q:
            if (cmd.itype == st9_ald) {
                byte = ua_next_byte();
                cmd.itype = get_alu_insn(byte);
                set_reg(cmd.Op1, rrr0 + (byte & 0x0E), OP_IS_IND);
                set_imm(cmd.Op2, ua_next_byte(), dt_byte);
            }
#if __DEBUG__
            else
                IDA_ERROR("ana(): should be ALD");
#endif /* __DEBUG__ */            
            break;

#define BIT_OP_1    cmd.itype != st9_bld ? cmd.Op1 : cmd.Op2   
#define BIT_OP_2    cmd.itype != st9_bld ? cmd.Op2 : cmd.Op1   
            
        // rd.b,rs.b
        case A_wrb_wrb_10:
        case A_wrb_wrb_11:
            byte = ua_next_byte();
            set_reg(BIT_OP_1, rr0 + (byte & 0x0F), OP_REG_WITH_BIT);
            set_bit(BIT_OP_1, (byte & 0xE0) >> 5);
            byte = ua_next_byte();
            set_reg(BIT_OP_2, rr0 + (byte & 0x0F), OP_REG_WITH_BIT);
            set_bit(BIT_OP_2, (byte & 0xE0) >> 5);
            break;

        // rd.b,rs.!b
        case A_wrb_nwrb_10:
        case A_wrb_nwrb_11:
            byte = ua_next_byte();
            set_reg(BIT_OP_1, rr0 + (byte & 0x0F), OP_REG_WITH_BIT);
            set_bit(BIT_OP_1, (byte & 0xE0) >> 5, cmd.itype == st9_bld ? OP_BIT_COMPL : 0);
            byte = ua_next_byte();
            set_reg(BIT_OP_2, rr0 + (byte & 0x0F), OP_REG_WITH_BIT);
            set_bit(BIT_OP_2, (byte & 0xE0) >> 5, cmd.itype != st9_bld ? OP_BIT_COMPL : 0);
            break;
        
        // rd.b
        case A_wrb:
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + (byte & 0x0F), OP_REG_WITH_BIT);
            set_bit(cmd.Op1, (byte & 0xE0) >> 5);
            break;

        // (rr).bd
        case A_wrbi:
            byte = ua_next_byte();
            set_reg(cmd.Op1, rrr0 + (byte & 0x0F), OP_REG_WITH_BIT | OP_IS_IND);
            set_bit(cmd.Op1, (byte & 0xE0) >> 5);
            break;
    
        // b.rd,N    
        case A_bwr_8q_0:    
        case A_bwr_8q_1:    
            byte = ua_next_byte();
            set_reg(cmd.Op1, rr0 + (byte & 0x0F), OP_REG_WITH_BIT);
            set_bit(cmd.Op1, (byte & 0xE0) >> 5);
            set_addr(cmd.Op2, o_near, ua_next_byte());
            cmd.Op2.addr = (signed char) cmd.Op2.addr + cmd.ip + cmd.size;
            break;
        
        // nnnnnn,NN
        case A_seg_16q_01:    
        case A_seg_16q_11:    
            set_imm(cmd.Op1, ua_next_byte() & 0x3F, dt_byte, OP_IMM_NO_SHIFT);
            set_addr(cmd.Op2, o_near, ua_next_word());
            break;
    
        // wwwww
        case A_rwn_000: 
        case A_rwn_100: 
        case A_rwn_101:
            set_imm(cmd.Op1, (ua_next_byte() & 0xF8) >> 3, dt_byte);
            break;
            
        // pppppp    
        case A_rpn:
            set_imm(cmd.Op1, (ua_next_byte() & 0xFC) >> 2, dt_byte);
            break;
            
    }
}
        
// analyze an instruction
int ana(void) {
    int byte = ua_next_byte();

    const struct opcode *op = find_opcode(byte);
    if (op == NULL)
        return 0;

    fill_cmd(byte, op);

    return cmd.size;
}

void interr(const char *file, const int line, const char *format, ...) {
    const char *name = NULL;
    char b[200];
    va_list va;

    IDA_ASSERT(file != NULL && format != NULL, "Invalid args in interr()");
    
    va_start(va, format);
    
    if (cmd.itype < st9_last) 
        name = Instructions[cmd.itype].name;
    else 
        cmd.itype = st9_null;
    
    qvsnprintf(b, sizeof b, format, va);

    warning("%s:%d : %a(%s) : internal error => %s", 
        file, line, cmd.ea, name, b);

    va_end(va);
}

