Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
idapro / opt / ida90 / libexec / idapro / procs / spu.py
Size: Mime:
# SPU (Cell Broadband Engine Synergistic Processor Unit)
# Contributed by Felix Domke

import sys

from ida_bytes import *
from ida_ua import *
from ida_idp import *
from ida_auto import *
from ida_nalt import *
from ida_funcs import *
from ida_lines import *
from ida_problems import *
from ida_offset import *
from ida_segment import *
from ida_name import *
from ida_netnode import *
from ida_xref import *
from ida_idaapi import *
import ida_ida
import ida_frame
import idc

if sys.version_info.major < 3:
  range = xrange

# crap crap crap: IDA doesn't store the real python long/int in Opx.value, but only
# a swig'ed version that's going to be unsigned.
# now, if we need to pass that value as a signed value, we need to convert the u32 value
# into a long again... yay.
def fix_sign_32(l):
    l &= 0xFFFFFFFF
    if l & 0x80000000:
        l -= 0x100000000
    return l

# extract bitfield occupying bits high..low from val (inclusive, start from 0)
def BITS(val, high, low):
    return (val>>low)&((1<<(high-low+1))-1)

# extract one bit
def BIT(val, bit):
    return (val>>bit) & 1

# sign extend b low bits in x
# from "Bit Twiddling Hacks"
def SIGNEXT(x, b):
    m = 1 << (b - 1)
    x = x & ((1 << b) - 1)
    return (x ^ m) - m

# check if operand is register reg
def is_reg(op, reg):
        return op.type == o_reg and op.reg == reg

# check if operand is immediate value val
def is_imm(op, val):
        return op.type == o_imm and op.value == val

# is sp delta fixed by the user?
def is_fixed_spd(ea):
        return (get_aflags(ea) & AFL_FIXEDSPD) != 0

def IBITS(val, high, low):
    return BITS(val, 31-high, 31-low)

def decode_RR(opcode):
    # OP, B, A, T
    return IBITS(opcode, 0, 10), IBITS(opcode, 11, 17), IBITS(opcode, 18, 24), IBITS(opcode, 25, 31)

def decode_RRR(opcode):
    # OP, T, B, A, C
    return IBITS(opcode, 0, 3), IBITS(opcode, 4, 10), IBITS(opcode, 11, 17), IBITS(opcode, 18, 24), IBITS(opcode, 25, 31)

def decode_RI7(opcode):
    # OP I RA RT
    return IBITS(opcode, 0, 10), IBITS(opcode, 11, 17), IBITS(opcode, 18, 24), IBITS(opcode, 25, 31)

def decode_RI8(opcode):
    # OP I RA RT
    return IBITS(opcode, 0, 9), IBITS(opcode, 10, 17), IBITS(opcode, 18, 24), IBITS(opcode, 25, 31)

def decode_RI10(opcode):
    # OP I RA RT
    return IBITS(opcode, 0, 7), IBITS(opcode, 8, 17), IBITS(opcode, 18, 24), IBITS(opcode, 25, 31)

def decode_RI16(opcode):
    # OP I RT
    return IBITS(opcode, 0, 8), IBITS(opcode, 9, 24), IBITS(opcode, 25, 31)

def decode_RI18(opcode):
    # OP I RT
    return IBITS(opcode, 0, 6), IBITS(opcode, 7, 24), IBITS(opcode, 25, 31)

def decode_I16RO(opcode):
    # OP ROH I16 ROL
    return IBITS(opcode, 0, 6), IBITS(opcode, 7, 8), IBITS(opcode, 9, 24), IBITS(opcode, 25, 31)

def decode_STOP(opcode):
    # OP TYPE
    return IBITS(opcode, 0, 10), IBITS(opcode, 18, 31)

class spu_processor_t(processor_t):
    id = PLFM_SPU
    flag = PR_ASSEMBLE | PR_SEGS | PR_DEFSEG32 | PR_USE32 | PRN_HEX | PR_RNAMESOK

    # Number of bits in a byte for code segments (usually 8)
    # IDA supports values up to 32 bits (64 for IDA64)
    cnbits = 8

    # Number of bits in a byte for non-code segments (usually 8)
    # IDA supports values up to 32 bits (64 for IDA64)
    dnbits = 8
    psnames = ['spu']
    plnames = ['SPU']
    segreg_size = 0
    instruc_start = 0
    tbyte_size = 0
    assembler = {
        'flag' : ASH_HEXF3 | AS_COLON | ASB_BINF0 | ASO_OCTF1 | AS_NCMAS,
        'uflag' : 0,
        'name': "GNU assembler",
        'origin': ".org",
        'end': "end",
        'cmnt': ";",
        'ascsep': "\"",
        'accsep': "'",
        'esccodes': "\"'",
        'a_ascii': ".ascii",
        'a_byte': ".byte",
        'a_word': ".short",
        'a_dword': ".int",
        'a_qword': ".quad",
        'a_oword': ".int128",
        'a_float': ".float",
        'a_double': ".double",
        #'a_tbyte': "dt",
        #'a_dups': "#d dup(#v)",
        'a_bss': "dfs %s",
        'a_seg': "seg",
        'a_curip': ".",
        'a_public': "public",
        'a_weak': "weak",
        'a_extrn': ".extrn",
        'a_comdef': "",
        'a_align': ".align",
        'lbrace': "(",
        'rbrace': ")",
        'a_mod': "%",
        'a_band': "&",
        'a_bor': "|",
        'a_xor': "^",
        'a_bnot': "~",
        'a_shl': "<<",
        'a_shr': ">>",
        'a_sizeof_fmt': "size %s",
    }

    FL_SIGNED = 0x01    # value/address is signed; output as such
    FL_D            = 0x02    # d suffix (disable interrupts)
    FL_E            = 0x04    # e suffix (enable interrupts)
    FL_C            = 0x08    # c suffix (syncc - sync channels)
    FL_P            = 0x10    # p suffix (inline prefetching)

    # ----------------------------------------------------------------------
    # Processor module callbacks
    #
    # ----------------------------------------------------------------------
    def ev_get_frame_retsize(self, frsize, pfn):
        # SPU doesn't use stack but the link register
        ida_pro.int_pointer.frompointer(frsize).assign(0)
        return 1

    # ----------------------------------------------------------------------
    def ev_get_autocmt(self, insn):
        if insn.itype in self.comments:
             return self.comments[insn.itype]

    # ----------------------------------------------------------------------
    def ev_is_align_insn(self, ea):
        return 2 if get_word(ea) == 0 else 0

    # ----------------------------------------------------------------------
    def add_stkvar(self, insn, v, n, flag):
        pfn = get_func(insn.ea)
        if pfn and insn.create_stkvar(insn[n], fix_sign_32(v), flag):
            op_stkvar(insn.ea, n)

    # ----------------------------------------------------------------------
    def handle_operand(self, insn, op, isRead):
        flags     = get_flags(insn.ea)
        is_offs   = is_off(flags, op.n)
        dref_flag = dr_R if isRead else dr_W
        def_arg   = is_defarg(flags, op.n)
        optype    = op.type

        if optype == o_imm:
            # create xrefs to valid addresses
            makeoff = False
            if insn.itype == self.itype_ila and is_loaded(op.value):
                makeoff = True
            if makeoff and not def_arg:
                op_plain_offset(insn.ea, op.n, insn.cs)
                is_offs = True
            if is_offs:
                insn.add_off_drefs(op, dr_O, 0)
        elif optype == o_displ:
            # create data xrefs and stack vars
            if is_offs:
                insn.add_off_drefs(op, dref_flag, OOF_ADDR)
            elif may_create_stkvars() and not def_arg and op.reg == self.ireg_sp:
                # var_x(SP)
                self.add_stkvar(insn, op.addr, op.n, STKVAR_VALID_SIZE)
        elif optype == o_mem:
            # create data xrefs
            insn.create_op_data(op.addr, op)
            insn.add_dref(op.addr, op.offb, dref_flag)
        elif optype == o_near:
            # create code xrefs
            if insn.get_canon_feature() & CF_CALL:
                fl = fl_CN
            else:
                fl = fl_JN
            insn.add_cref(op.addr, op.offb, fl)

    # ----------------------------------------------------------------------
    def add_stkpnt(self, pfn, insn, v):
            if pfn:
                    end = insn.ea + insn.size
                    if not is_fixed_spd(end):
                            ida_frame.add_auto_stkpnt(pfn, end, fix_sign_32(v))

    # ----------------------------------------------------------------------
    def trace_sp(self, insn):
        """
        Trace the value of the SP and create an SP change point if the current
        instruction modifies the SP.
        """
        pfn = get_func(insn.ea)
        if not pfn:
                return

        if insn.itype == self.itype_ai and is_reg(insn.Op1, self.ireg_sp) and is_reg(insn.Op2, self.ireg_sp) and insn.Op3.type == o_imm:
            # ai sp, sp, #imm
            spofs = insn.Op3.value
            self.add_stkpnt(pfn, insn, spofs)

    # ----------------------------------------------------------------------
    def ev_emu_insn(self, insn):
        Feature = insn.get_canon_feature()

        if Feature & CF_USE1:
                self.handle_operand(insn, insn.Op1, 1)
        if Feature & CF_CHG1:
                self.handle_operand(insn, insn.Op1, 0)
        if Feature & CF_USE2:
                self.handle_operand(insn, insn.Op2, 1)
        if Feature & CF_CHG2:
                self.handle_operand(insn, insn.Op2, 0)
        if Feature & CF_USE3:
                self.handle_operand(insn, insn.Op3, 1)
        if Feature & CF_CHG3:
                self.handle_operand(insn, insn.Op3, 0)
        if Feature & CF_USE4:
                self.handle_operand(insn, insn.Op4, 1)
        if Feature & CF_CHG4:
                self.handle_operand(insn, insn.Op4, 0)
        if Feature & CF_JUMP:
                remember_problem(PR_JUMP, insn.ea)

        flow = (Feature & CF_STOP == 0)
        if flow:
            add_cref(insn.ea, insn.ea + insn.size, fl_F)

        # create stack vars for ai rd, sp, offs
        # only if rd != sp
        if may_create_stkvars() and insn.itype == self.itype_ai \
                    and is_reg(insn.Op2, self.ireg_sp) and not is_reg(insn.Op1, self.ireg_sp) \
                    and insn.Op3.type == o_imm and not is_defarg(get_flags(insn.ea), 2):
            self.add_stkvar(insn, insn.Op3.value, 2, 0)

        # trace the stack pointer if:
        #     - it is the second analysis pass
        #     - the stack pointer tracing is allowed
        if may_trace_sp():
                if flow:
                        self.trace_sp(insn) # trace modification of SP register
                else:
                        idc.recalc_spd(insn.ea) # recalculate SP register for the next insn

        return True

    # ----------------------------------------------------------------------
    def ev_out_operand(self, ctx, op):
        optype = op.type
        fl = op.specval
        signed = OOF_SIGNED if fl & self.FL_SIGNED != 0 else 0
        if optype == o_reg:
            ctx.out_register(self.reg_names[op.reg])
        elif optype == o_imm:
            ctx.out_value(op, OOFW_IMM | signed | (OOFW_32 if self.PTRSZ == 4 else OOFW_64))
        elif optype in [o_near, o_mem]:
            r = ctx.out_name_expr(op, op.addr, BADADDR)
            if not r:
                ctx.out_tagon(COLOR_ERROR)
                ctx.out_btoa(op.addr, 16)
                ctx.out_tagoff(COLOR_ERROR)
                remember_problem(PR_NONAME, ctx.insn.ea)
        elif optype == o_displ:
            ctx.out_value(op, OOF_ADDR | (OOFW_32 if self.PTRSZ == 4 else OOFW_64) | signed )
            ctx.out_symbol('(')
            ctx.out_register(self.reg_names[op.reg])
            ctx.out_symbol(')')
        return True

    # ----------------------------------------------------------------------
    def ev_out_mnem(self, ctx):
        postfix = ""

        if ctx.insn.auxpref & self.FL_D:
            postfix += "d"

        if ctx.insn.auxpref & self.FL_E:
            postfix += "e"

        if ctx.insn.auxpref & self.FL_P:
            postfix += "p"

        if ctx.insn.auxpref & self.FL_C:
            postfix += "c"

        ctx.out_mnem(15, postfix)
        return 1

    # ----------------------------------------------------------------------
    def ev_out_insn(self, ctx):

        ctx.out_mnemonic()

        ctx.out_one_operand(0)

        for i in range(1, 4):
                op = ctx.insn[i]
                if op.type == o_void:
                        break

                ctx.out_symbol(',')
                ctx.out_char(' ')
                ctx.out_one_operand(i)

        ctx.set_gen_cmt()
        ctx.flush_outbuf()
        return True

    # ----------------------------------------------------------------------
    # replace some instructions by simplified mnemonics
    def simplify(self, insn):
        # ori rt, ra, 0 -> lr ri, ra
        if insn.itype in [self.itype_ori, self.itype_shlqbyi] and insn.Op3.value == 0:
            insn.itype = self.itype_lr
            insn.Op3.type = o_void

    # ----------------------------------------------------------------------
    def ev_ana_insn(self, insn):
        opcode = insn.get_next_dword()
        ins = self.itable[IBITS(opcode, 0, 10)]
        if ins is None:
            return False
        insn.itype = getattr(self, 'itype_' + ins.name)
        for c in insn:
            c.type = o_void
        ins.decode(self, insn, opcode)
        self.simplify(insn)
        return True

    # ----------------------------------------------------------------------
    def init_instructions(self):

        class idef:
            pass

        class idef_RR(idef):
            def __init__(self, name):
                self.name = name
                self.cf = CF_USE1 | CF_CHG1 | CF_USE2 | CF_USE3

            def decode(self, p, insn, opcode):
                _, insn.Op3.reg, insn.Op2.reg, insn.Op1.reg = decode_RR(opcode)
                insn.Op1.type = insn.Op2.type = insn.Op3.type = o_reg

        class idef_ROHROL(idef_RR):
            def __init__(self, name):
                self.name = name
                self.cf = 0

            def decode(self, p, insn, opcode):
                _, roh, insn.Op2.reg, rol = decode_RR(opcode)

                prefetch = roh & 0x40 != 0

                roh &= 3

                val = roh << 7 | rol

                if val & 0x100:
                    val -= 0x200

                val <<= 2

                insn.Op1.type = o_mem
                insn.Op1.addr = val + insn.ea
                insn.Op2.type = o_reg
                if prefetch:
                    insn.auxpref |= spu_processor_t.FL_P
                    if insn.Op2.reg == 0:
                        insn.Op2.type = o_void
                        if val == 0:
                            insn.Op1.type = o_void

        class idef_R(idef_RR):
            def __init__(self, name, noRA = False):
                self.name = name
                self.noRA = noRA
                if noRA:
                    self.cf = CF_CHG1
                else:
                    self.cf = CF_CHG1 | CF_USE2

            def decode(self, p, insn, opcode):
                idef_RR.decode(self, p, insn, opcode)
                insn.Op3.type = o_void
                if self.noRA and insn.Op2.reg == 0:
                    insn.Op2.type = o_void

        class idef_SPR(idef):
            def __init__(self, name, swap = False, offset = 128):
                self.name = name
                self.swap = swap
                self.offset = offset
                self.cf = CF_USE1 | CF_CHG1 | CF_USE2

            def decode(self, p, insn, opcode):
                _, _, insn.Op2.reg, insn.Op1.reg = decode_RR(opcode)
                insn.Op1.type = o_reg
                insn.Op2.type = o_reg
                insn.Op2.reg += self.offset
                if self.swap:
                    (insn.Op1.type, insn.Op1.reg, insn.Op2.type, insn.Op2.reg) = \
                    (insn.Op2.type, insn.Op2.reg, insn.Op1.type, insn.Op1.reg)


        class idef_CH(idef_SPR):
            def __init__(self, name, swap = False):
                idef_SPR.__init__(self, name, swap, 256)

        class idef_noops(idef):
            def __init__(self, name, cbit = False):
                self.name = name
                self.cbit = cbit
                self.cf = 0

            def decode(self, p, insn, opcode):
                _, insn.Op3.reg, insn.Op2.reg, insn.Op1.reg = decode_RR(opcode)
                insn.Op1.type = insn.Op2.type = insn.Op3.type = o_reg
                if self.cbit and insn.Op3.reg & 0x40 != 0:
                    insn.auxpref |= spu_processor_t.FL_C
                    insn.Op3.reg &= ~0x40

                if insn.Op3.reg == 0:
                    insn.Op3.type = o_void
                    if insn.Op2.reg == 0:
                        insn.Op2.type = o_void
                        if insn.Op1.reg == 0:
                            insn.Op1.type = o_void

        class idef_RRR(idef):
            def __init__(self, name):
                self.name = name
                self.cf = CF_USE1 | CF_CHG1 | CF_USE2 | CF_USE3 | CF_USE4

            def decode(self, p, insn, opcode):
                _, insn.Op1.reg, insn.Op3.reg, insn.Op2.reg, insn.Op4.reg = decode_RRR(opcode)
                insn.Op1.type = insn.Op2.type = insn.Op3.type = insn.Op4.type = o_reg

        class idef_Branch(idef_RR):
            def __init__(self, name, no2 = False, uncond = False):
                self.name = name
                self.cf = CF_USE1 | CF_JUMP
                if uncond:
                    self.cf |= CF_STOP
                self.no2 = no2

            def decode(self, p, insn, opcode):
                _, flags, insn.Op2.reg, insn.Op1.reg = decode_RR(opcode)
                insn.Op1.type = insn.Op2.type = o_reg

                if self.no2:
                    insn.Op2.type = o_void
                    insn.Op1.reg = insn.Op2.reg
                if flags & 0x10:
                    insn.auxpref |= spu_processor_t.FL_E
                if flags & 0x20:
                    insn.auxpref |= spu_processor_t.FL_D

        class idef_RI7(idef):
            def __init__(self, name, signed = True):
                self.name = name
                self.signed = signed
                self.cf = CF_USE1 | CF_CHG1 | CF_USE2

            def decode(self, p, insn, opcode):
                _, insn.Op3.value, insn.Op2.reg, insn.Op1.reg = decode_RI7(opcode)
                insn.Op1.type = insn.Op2.type = o_reg
                insn.Op3.type = o_imm
                if self.signed and insn.Op3.value & 0x40:
                    insn.Op3.value -= 0x80
                    insn.Op3.specval |= spu_processor_t.FL_SIGNED

        class idef_RI8(idef):
            def __init__(self, name, bias):
                self.name = name
                self.bias = bias
                self.cf = CF_CHG1 | CF_USE2 | CF_USE3

            def decode(self, p, insn, opcode):
                _, insn.Op3.value, insn.Op2.reg, insn.Op1.reg = decode_RI8(opcode)
                insn.Op1.type = insn.Op2.type = o_reg
                insn.Op3.value = self.bias - insn.Op3.value
                insn.Op3.type = o_imm

        class idef_RI7_ls(idef_RI7):
            def decode(self, p, insn, opcode):
                _, insn.Op2.addr, insn.Op2.reg, insn.Op1.reg = decode_RI7(opcode)
                insn.Op1.type = o_reg
                insn.Op2.type = o_displ
                insn.Op2.dtype = dt_byte16
                if insn.Op2.addr & 0x40:
                    insn.Op2.addr -= 0x80
                    insn.Op2.specval |= spu_processor_t.FL_SIGNED

        class idef_RI10(idef):
            def __init__(self, name, signed = True):
                self.name = name
                self.signed = signed
                self.cf = CF_USE1 | CF_CHG1 | CF_USE2

            def decode(self, p, insn, opcode):
                _, insn.Op3.value, insn.Op2.reg, insn.Op1.reg = decode_RI10(opcode)
                insn.Op1.type = insn.Op2.type = o_reg
                insn.Op3.type = o_imm
                if self.signed:
                    if insn.Op3.value & 0x200:
                        insn.Op3.value -= 0x400
                        insn.Op3.specval |= spu_processor_t.FL_SIGNED

        class idef_RI10_ls(idef_RI10):
            def decode(self, p, insn, opcode):
                _, insn.Op2.addr, insn.Op2.reg, insn.Op1.reg = decode_RI10(opcode)
                insn.Op1.type = o_reg
                insn.Op2.type = o_displ
                insn.Op2.addr <<= 4
                insn.Op2.dtype = dt_byte16
                if insn.Op2.addr & 0x2000:
                    insn.Op2.addr -= 0x4000
                    insn.Op2.specval |= spu_processor_t.FL_SIGNED

        class idef_RI16(idef):
            def __init__(self, name, flags = 0, noRA = False, isBranch = True, signext = False):
                self.name = name
                self.noRA = noRA
                self.isBranch = isBranch
                self.signext = signext

                self.cf = CF_USE1 | CF_CHG1 | CF_USE2 | flags
                if noRA:
                    self.cf &= ~(CF_USE2|CF_CHG2)

            def decode(self, p, insn, opcode):
                _, insn.Op2.value, insn.Op1.reg = decode_RI16(opcode)
                insn.Op1.type = o_reg
                insn.Op2.type = o_imm
                if self.signext and insn.Op2.value & 0x8000:
                    insn.Op2.value -= 0x10000
                    insn.Op2.specval |= spu_processor_t.FL_SIGNED
                self.fixRA(p, insn)

            def fixRA(self, p, insn):
                if self.noRA:
                    insn.Op1.addr, insn.Op1.type, insn.Op2.type = insn.Op2.addr, insn.Op2.type, o_void

        class idef_RI16_abs(idef_RI16):
            def decode(self, p, insn, opcode):
                idef_RI16.decode(self, p, insn, opcode)
                insn.Op2.addr = insn.Op2.value << 2
                self.fixOp2(p, insn)
                self.fixRA(p, insn)

            def fixOp2(self, p, insn):
                if self.isBranch:
                     insn.Op2.type = o_near
                else:
                     # lqr/lqa/stqr/stqa
                     insn.Op2.type = o_mem
                     insn.Op2.dtype = dt_byte16

        class idef_RI16_rel(idef_RI16_abs):
            def decode(self, p, insn, opcode):
                idef_RI16.decode(self, p, insn, opcode)
                insn.Op2.addr = (insn.Op2.value << 2) + insn.ea
                if insn.Op2.addr & 0x40000:
                    insn.Op2.addr &=~0x40000
                self.fixOp2(p, insn)
                self.fixRA(p, insn)

        class idef_RI18(idef):
            def __init__(self, name):
                self.name = name
                self.cf = CF_USE1 | CF_CHG1 | CF_USE2

            def decode(self, p, insn, opcode):
                _, insn.Op2.value, insn.Op1.reg = decode_RI18(opcode)
                insn.Op1.type = o_reg
                insn.Op2.type = o_imm
                insn.Op2.dtype = dt_dword

        class idef_I16RO(idef):
            def __init__(self, name, rel = False):
                self.name = name
                self.cf = 0
                self.rel = rel

            def decode(self, p, insn, opcode):
                _, roh, i16, rol = decode_I16RO(opcode)
                val = (roh << 7) | rol

                if val & 0x200:
                    val -= 0x400

                val <<= 2

                if self.rel:
                    # i16 is signed relative offset
                    if i16 & 0x8000:
                        i16 -= 0x10000
                    i16 = insn.ea + (i16 << 2)
                else:
                    i16 <<= 2

                insn.Op1.type = o_mem
                insn.Op1.addr = val + insn.ea
                insn.Op2.type = o_near
                insn.Op2.addr = i16

        class idef_stop(idef):
            def __init__(self, name):
                self.name = name
                self.cf = CF_STOP | CF_USE1

            def decode(self, p, insn, opcode):
                _, t = decode_STOP(opcode)
                insn.Op1.type = o_imm
                insn.Op1.value = t

        self.itable_RI10 = {
             0x04: idef_RI10("ori"),
             0x05: idef_RI10("orhi"),
             0x06: idef_RI10("orbi"),
             0x0c: idef_RI10("sfi"),
             0x0d: idef_RI10("sfhi"),
             0x14: idef_RI10("andi"),
             0x15: idef_RI10("andhi"),
             0x16: idef_RI10("andbi"),
             0x1c: idef_RI10("ai"),
             0x1d: idef_RI10("ahi"),
             0x24: idef_RI10_ls("stqd"),
             0x34: idef_RI10_ls("lqd"),
             0x44: idef_RI10("xori"),
             0x45: idef_RI10("xorhi"),
             0x46: idef_RI10("xorbi", signed = False),
             0x4c: idef_RI10("cgti"),
             0x4d: idef_RI10("cgthi"),
             0x4e: idef_RI10("cgtbi"),
             0x4f: idef_RI10("hgti"),    # false target
             0x5c: idef_RI10("clgti"),
             0x5d: idef_RI10("clgthi"),
             0x5e: idef_RI10("clgtbi"),
             0x5f: idef_RI10("hlgti"), # false target
             0x74: idef_RI10("mpyi"),
             0x75: idef_RI10("mpyui"),
             0x7c: idef_RI10("ceqi"),
             0x7d: idef_RI10("ceqhi"),
             0x7e: idef_RI10("ceqbi"),
             0x7f: idef_RI10("heqi"),
        }

        # 11-bit opcodes (bits 0:10)
        self.itable_RR = {
            0x000: idef_stop("stop"),
            0x001: idef_noops("lnop"), # no regs
            0x002: idef_noops("sync", cbit = True), # C/#C
            0x003: idef_noops("dsync"), # no regs
            0x00c: idef_SPR("mfspr"), # SA = number
            0x00d: idef_CH("rdch"), # //, CA, RT
            0x00f: idef_CH("rchcnt"), # //, CA, RT
            0x040: idef_RR("sf"),
            0x041: idef_RR("or"),
            0x042: idef_RR("bg"),
            0x048: idef_RR("sfh"),
            0x049: idef_RR("nor"),
            0x053: idef_RR("absdb"),
            0x058: idef_RR("rot"),
            0x059: idef_RR("rotm"),
            0x05a: idef_RR("rotma"),
            0x05b: idef_RR("shl"),
            0x05c: idef_RR("roth"),
            0x05d: idef_RR("rothm"),
            0x05e: idef_RR("rotmah"),
            0x05f: idef_RR("shlh"),
            0x07f: idef_RR("shlhi"),
            0x0c0: idef_RR("a"),
            0x0c1: idef_RR("and"),
            0x0c2: idef_RR("cg"),
            0x0c8: idef_RR("ah"),
            0x0c9: idef_RR("nand"),
            0x0d3: idef_RR("avgb"),
            0x10c: idef_SPR("mtspr", swap=1), # SA = number
            0x10d: idef_CH("wrch", swap=1), # // CA RT
            0x128: idef_Branch("biz"),    # branch
            0x129: idef_Branch("binz"), # branch
            0x12a: idef_Branch("bihz"), # branch
            0x12b: idef_Branch("bihnz"), # branch
            0x140: idef_RR("stopd"),
            0x144: idef_RR("stqx"),
            0x1a8: idef_Branch("bi", no2 = True, uncond = True),     # branch
            0x1a9: idef_Branch("bisl"), # branch
            0x1aa: idef_Branch("iret", no2 = True, uncond = True), # branch
            0x1ab: idef_Branch("bisled"), # branch
            0x1ac: idef_ROHROL("hbr"),     # ROH/ROL form
            0x1b0: idef_R("gb"),        # no first reg
            0x1b1: idef_R("gbh"),     # no first reg
            0x1b2: idef_R("gbb"),     # no first reg
            0x1b4: idef_R("fsm"),     #    no first reg
            0x1b5: idef_R("fsmh"),    # no first reg
            0x1b6: idef_R("fsmb"),    # no first reg
            0x1b8: idef_R("frest"), # no first reg
            0x1b9: idef_R("frsqest"), # no first reg
            0x1c4: idef_RR("lqx"),
            0x1cc: idef_RR("rotqbybi"),
            0x1cd: idef_RR("rotqmbybi"),
            0x1cf: idef_RR("shlqbybi"),
            0x1d4: idef_RR("cbx"),
            0x1d5: idef_RR("chx"),
            0x1d6: idef_RR("cwx"),
            0x1d7: idef_RR("cdx"),
            0x1d8: idef_RR("rotqbi"),
            0x1d9: idef_RR("rotqmbi"),
            0x1db: idef_RR("shlqbi"),
            0x1dc: idef_RR("rotqby"),
            0x1dd: idef_RR("rotqmby"),
            0x1df: idef_RR("shlqby"),
            0x1f0: idef_R("orx"), # no first reg
            0x201: idef_noops("nop"), # no regs
            0x240: idef_RR("cgt"),
            0x241: idef_RR("xor"),
            0x248: idef_RR("cgth"),
            0x249: idef_RR("eqv"),
            0x250: idef_RR("cgtb"),
            0x253: idef_RR("sumb"),
            0x258: idef_RR("hgt"),
            0x2a5: idef_R("clz"), # no first reg
            0x2a6: idef_R("xswd"), # no first reg
            0x2ae: idef_R("xshw"), # no first
            0x2b4: idef_R("cntb"), # no first reg
            0x2b6: idef_R("xsbh"), # no first reg
            0x2c0: idef_RR("clgt"),
            0x2c1: idef_RR("andc"),
            0x2c2: idef_RR("fcgt"),
            0x2c3: idef_RR("dfcgt"),
            0x2c4: idef_RR("fa"),
            0x2c5: idef_RR("fs"),
            0x2c6: idef_RR("fm"),
            0x2c8: idef_RR("clgth"),
            0x2c9: idef_RR("orc"),
            0x2ca: idef_RR("fcmgt"),
            0x2cb: idef_RR("dfcmgt"),
            0x2cc: idef_RR("dfa"),
            0x2cd: idef_RR("dfs"),
            0x2ce: idef_RR("dfm"),
            0x2d0: idef_RR("clgtb"),
            0x2d8: idef_RR("hlgt"), # false target
            0x340: idef_RR("addx"),
            0x341: idef_RR("sfx"),
            0x342: idef_RR("cgx"),
            0x343: idef_RR("bgx"),
            0x346: idef_RR("mpyhha"),
            0x34e: idef_RR("mpyhhau"),
            0x35c: idef_RR("dfma"),
            0x35d: idef_RR("dfms"),
            0x35e: idef_RR("dfnms"),
            0x35f: idef_RR("dfnma"),
            0x398: idef_R("fscrrd", noRA = True), # no first and second
            0x3b8: idef_R("fesd"),     # no first
            0x3b9: idef_R("frds"),     # no first
            0x3ba: idef_R("fscrwr"), # no first, rt is false target
            0x3c0: idef_RR("ceq"),
            0x3c2: idef_RR("fceq"),
            0x3c3: idef_RR("dfceq"),
            0x3c4: idef_RR("mpy"),
            0x3c5: idef_RR("mpyh"),
            0x3c7: idef_RR("mpys"),
            0x3c6: idef_RR("mpyhh"),
            0x3c8: idef_RR("ceqh"),
            0x3ca: idef_RR("fcmeq"),
            0x3cb: idef_RR("dfcmeq"),
            0x3cc: idef_RR("mpyu"),
            0x3ce: idef_RR("mpyhhu"),
            0x3d0: idef_RR("ceqb"),
            0x3d4: idef_RR("fi"),
            0x3d8: idef_RR("heq"), # rt is false target
        }

        # 4-bit opcodes (bits 0:3)
        self.itable_RRR = {
                0x8: idef_RRR("selb"),
                0xb: idef_RRR("shufb"),
                0xc: idef_RRR("mpya"),
                0xd: idef_RRR("fnms"),
                0xe: idef_RRR("fma"),
                0xf: idef_RRR("fms"),
        };

        self.itable_RI16 = {
            0x040: idef_RI16_rel("brz"),
            0x041: idef_RI16_abs("stqa", isBranch = False),
            0x042: idef_RI16_rel("brnz"),
            0x044: idef_RI16_rel("brhz"),
            0x046: idef_RI16_rel("brhnz"),
            0x047: idef_RI16_rel("stqr", isBranch = False),
            0x060: idef_RI16_abs("bra", noRA = True, flags = CF_STOP), # no RA
            0x061: idef_RI16_abs("lqa", isBranch = False),
            0x062: idef_RI16_abs("brasl", flags = CF_CALL),
            0x064: idef_RI16_rel("br", noRA = True, flags = CF_STOP),    # no RA
            0x065: idef_RI16("fsmbi"),
            0x066: idef_RI16_rel("brsl", flags = CF_CALL),
            0x067: idef_RI16_rel("lqr", isBranch = False),
            0x081: idef_RI16("il", signext = True),
            0x082: idef_RI16("ilhu"),
            0x083: idef_RI16("ilh"),
            0x0c1: idef_RI16("iohl"),
        }

        self.itable_RI7 = {
            0x078: idef_RI7("roti"),
            0x079: idef_RI7("rotmi"),
            0x07a: idef_RI7("rotmai"),
            0x07b: idef_RI7("shli"),
            0x07c: idef_RI7("rothi"),
            0x07d: idef_RI7("rothmi"),
            0x07e: idef_RI7("rotmahi"),
            0x1f4: idef_RI7_ls("cbd"),
            0x1f5: idef_RI7_ls("chd"),
            0x1f6: idef_RI7_ls("cwd"),
            0x1f7: idef_RI7_ls("cdd"),
            0x1f8: idef_RI7("rotqbii"),
            0x1f9: idef_RI7("rotqmbii"),
            0x1fb: idef_RI7("shlqbii"),
            0x1fc: idef_RI7("rotqbyi"),
            0x1fd: idef_RI7("rotqmbyi"),
            0x1ff: idef_RI7("shlqbyi"),
            0x3bf: idef_RI7("dftsv", signed = False),
        }

        self.itable_RI18 = {
            0x21: idef_RI18("ila"),
            0x08: idef_I16RO("hbra"), # roh/rol
            0x09: idef_I16RO("hbrr", rel = True), # roh/rol
        }

        # 10-bit opcodes (bits 0:9)
        self.itable_RI8 = {
            0x1d8: idef_RI8("cflts", 173),
            0x1d9: idef_RI8("cfltu", 173),
            0x1da: idef_RI8("csflt", 155),
            0x1db: idef_RI8("cuflt", 155),
        }

        self.itable = [None] * 2048

        for i in range(2048):
            opcode = i << 21
            RR = decode_RR(opcode)
            RRR = decode_RRR(opcode)
            RI7 = decode_RI7(opcode)
            RI8 = decode_RI8(opcode)
            RI10 = decode_RI10(opcode)
            RI16 = decode_RI16(opcode)
            RI18 = decode_RI18(opcode)

            ins = self.itable_RR.get(RR[0])
            ins = self.itable_RRR.get(RRR[0], ins)
            ins = self.itable_RI7.get(RI7[0], ins)
            ins = self.itable_RI8.get(RI8[0], ins)
            ins = self.itable_RI10.get(RI10[0], ins)
            ins = self.itable_RI16.get(RI16[0], ins)
            ins = self.itable_RI18.get(RI18[0], ins)

            if ins:
                self.itable[i] = ins

        # Now create an instruction table compatible with IDA processor module requirements
        Instructions = []
        i = 0
        for x in list(self.itable_RI10.values()) + \
            list(self.itable_RR.values()) + \
            list(self.itable_RRR.values()) + \
            list(self.itable_RI16.values()) + \
            list(self.itable_RI7.values()) + \
            list(self.itable_RI18.values()) + \
            list(self.itable_RI8.values()):
                Instructions.append({'name': x.name, 'feature': x.cf})
                setattr(self, 'itype_' + x.name, i)
                i += 1

        # add simplified mnemonics
        Instructions.append({'name': "lr", 'feature': CF_CHG1 | CF_USE2})
        setattr(self, 'itype_lr', i)
        i += 1

        # icode of the last instruction + 1
        self.instruc_end = len(Instructions)

        # Array of instructions
        self.instruc = Instructions

        # Icode of return instruction. It is ok to give any of possible return
        # instructions
        self.icode_return = self.itype_bi

        self.comments = {}
        for ins, cmt in spu_comments().items():
            nm = "itype_" + ins
            if hasattr(self, nm):
                self.comments[getattr(self, nm)] = cmt
            else:
                print("Warning: instruction %s not found" % ins)

    # ----------------------------------------------------------------------
    def init_registers(self, gnunames = False):
        if gnunames:
            self.reg_names = ["$%d" % d for d in range(0, 128)]
            self.reg_names += ["$sp%d" % d for d in range(0, 128)]
            self.reg_names += ["$ch%d" % d for d in range(0, 128)]
        else:
            self.reg_names = [ "lr", "sp"] + ["r%d" % d for d in range(2, 128)]
            self.reg_names += ["sp%d" % d for d in range(0, 128)]
            self.reg_names += ["ch%d" % d for d in range(0, 128)]

        self.reg_names    += ["CS", "DS"]

        if gnunames:
            for i in range(128):
                setattr(self, 'ireg_r%d'%i, i)
            for i in range(128, 256):
                setattr(self, 'ireg_sp%d' + (i-128), i)
            for i in range(256, 384):
                setattr(self, 'ireg_ch%d' + (i-256), i)
            setattr(self, 'ireg_lr', 0)
            setattr(self, 'ireg_sp', 1)
        else:
            for i in range(len(self.reg_names)):
                setattr(self, 'ireg_' + self.reg_names[i], i)
        self.reg_first_sreg = self.ireg_CS
        self.reg_last_sreg  = self.ireg_DS

        # number of CS register
        self.reg_code_sreg = self.ireg_CS

        # number of DS register
        self.reg_data_sreg = self.ireg_DS

    # ----------------------------------------------------------------------
    def notify_init(self, idp_file):
        # SPU is big endian
        ida_ida.cvar.inf_set_be(True)
        # init returns non-zero on success
        return 1

    # ----------------------------------------------------------------------
    def __init__(self):
        processor_t.__init__(self)
        self.PTRSZ = 4 # Assume PTRSZ = 4 by default
        self.init_instructions()
        self.init_registers()

# ----------------------------------------------------------------------
def spu_comments():
    return {
        "a": "Add Word",
        "absdb": "Absolute Differences of Bytes",
        "addx": "Add Extended",
        "ah": "Add Halfword",
        "ahi": "Add Halfword Immediate",
        "ai": "Add Word Immediate",
        "and": "And",
        "andbi": "And Byte Immediate",
        "andc": "And with Complement",
        "andhi": "And Halfword Immediate",
        "andi": "And Word Immediate",
        "avgb": "Average Bytes",
        "bg": "Borrow Generate",
        "bgx": "Borrow Generate Extended",
        "bi": "Branch Indirect",
        "bihnz": "Branch Indirect If Not Zero Halfword",
        "bihz": "Branch Indirect If Zero Halfword",
        "binz": "Branch Indirect If Not Zero",
        "bisl": "Branch Indirect and Set Link",
        "bisled": "Branch Indirect and Set Link if External Data",
        "biz": "Branch Indirect If Zero",
        "br": "Branch Relative",
        "bra": "Branch Absolute",
        "brasl": "Branch Absolute and Set Link",
        "brhnz": "Branch If Not Zero Halfword",
        "brhz": "Branch If Zero Halfword",
        "brnz": "Branch If Not Zero Word",
        "brsl": "Branch Relative and Set Link",
        "brz": "Branch If Zero Word",
        "cbd": "Generate Controls for Byte Insertion (d-form)",
        "cbx": "Generate Controls for Byte Insertion (x-form)",
        "cdd": "Generate Controls for Doubleword Insertion (d-form)",
        "cdx": "Generate Controls for Doubleword Insertion (x-form)",
        "ceq": "Compare Equal Word",
        "ceqb": "Compare Equal Byte",
        "ceqbi": "Compare Equal Byte Immediate",
        "ceqh": "Compare Equal Halfword",
        "ceqhi": "Compare Equal Halfword Immediate",
        "ceqi": "Compare Equal Word Immediate",
        "cflts": "Convert Floating to Signed Integer",
        "cfltu": "Convert Floating to Unsigned Integer",
        "cg": "Carry Generate",
        "cgt": "Compare Greater Than Word",
        "cgtb": "Compare Greater Than Byte",
        "cgtbi": "Compare Greater Than Byte Immediate",
        "cgth": "Compare Greater Than Halfword",
        "cgthi": "Compare Greater Than Halfword Immediate",
        "cgti": "Compare Greater Than Word Immediate",
        "cgx": "Carry Generate Extended",
        "chd": "Generate Controls for Halfword Insertion (d-form)",
        "chx": "Generate Controls for Halfword Insertion (x-form)",
        "clgt": "Compare Logical Greater Than Word",
        "clgtb": "Compare Logical Greater Than Byte",
        "clgtbi": "Compare Logical Greater Than Byte Immediate",
        "clgth": "Compare Logical Greater Than Halfword",
        "clgthi": "Compare Logical Greater Than Halfword Immediate",
        "clgti": "Compare Logical Greater Than Word Immediate",
        "clz": "Count Leading Zeros",
        "cntb": "Count Ones in Bytes",
        "csflt": "Convert Signed Integer to Floating",
        "cuflt": "Convert Unsigned Integer to Floating",
        "cwd": "Generate Controls for Word Insertion (d-form)",
        "cwx": "Generate Controls for Word Insertion (x-form)",
        "dfa": "Double Floating Add",
        "dfceq": "Double Floating Compare Equal",
        "dfcgt": "Double Floating Compare Greater Than",
        "dfcmeq": "Double Floating Compare Magnitude Equal",
        "dfcmgt": "Double Floating Compare Magnitude Greater Than",
        "dfm": "Double Floating Multiply",
        "dfma": "Double Floating Multiply and Add",
        "dfms": "Double Floating Multiply and Subtract",
        "dfnma": "Double Floating Negative Multiply and Add",
        "dfnms": "Double Floating Multiply and Subtract",
        "dfs": "Double Floating Subtract",
        "dftsv": "Double Floating Test Special Value",
        "dsync": "Synchronize Data",
        "eqv": "Equivalent",
        "fa": "Floating Add",
        "fceq": "Floating Compare Equal",
        "fcgt": "Floating Compare Greater Than",
        "fcmeq": "Floating Compare Magnitude Equal",
        "fcmgt": "Floating Compare Magnitude Greater Than",
        "fesd": "Floating Extend Single to Double",
        "fi": "Floating Interpolate",
        "fm": "Floating Multiply",
        "fma": "Floating Multiply and Add",
        "fms": "Floating Multiply and Subtract",
        "fnms": "Floating Negative Multiply and Subtract",
        "frds": "Floating Round Double to Single",
        "frest": "Floating Reciprocal Estimate",
        "frsqest": "Floating Reciprocal Absolute Square Root Estimate",
        "fs": "Floating Subtract",
        "fscrrd": "Floating-Point Status and Control Register Write",
        "fscrwr": "Floating-Point Status and Control Register Read",
        "fsm": "Form Select Mask for Words",
        "fsmb": "Form Select Mask for Bytes",
        "fsmbi": "Form Select Mask for Bytes Immediate",
        "fsmh": "Form Select Mask for Halfwords",
        "gb": "Gather Bits from Words",
        "gbb": "Gather Bits from Bytes",
        "gbh": "Gather Bits from Halfwords",
        "hbr": "Hint for Branch (r-form)",
        "hbra": "Hint for Branch (a-form)",
        "hbrr": "Hint for Branch Relative",
        "heq": "Halt If Equal",
        "heqi": "Halt If Equal Immediate",
        "hgt": "Halt If Greater Than",
        "hgti": "Halt If Greater Than Immediate",
        "hlgt": "Halt If Logically Greater Than",
        "hlgti": "Halt If Logically Greater Than Immediate",
        "il": "Immediate Load Word",
        "ila": "Immediate Load Address",
        "ilh": "Immediate Load Halfword",
        "ilhu": "Immediate Load Halfword Upper",
        "iohl": "Immediate Or Halfword Lower",
        "iret": "Interrupt Return",
        "lnop": "No Operation (Load)",
        "lqa": "Load Quadword (a-form)",
        "lqd": "Load Quadword (d-form)",
        "lqr": "Load Quadword Instruction Relative (a-form)",
        "lqx": "Load Quadword (x-form)",
        "mfspr": "Move from Special-Purpose Register",
        "mpy": "Multiply",
        "mpya": "Multiply and Add",
        "mpyh": "Multiply High",
        "mpyhh": "Multiply High High",
        "mpyhha": "Multiply High High and Add",
        "mpyhhau": "Multiply High High Unsigned and Add",
        "mpyhhu": "Multiply High High Unsigned",
        "mpyi": "Multiply Immediate",
        "mpys": "Multiply and Shift Right",
        "mpyu": "Multiply Unsigned",
        "mpyui": "Multiply Unsigned Immediate",
        "mtspr": "Move to Special-Purpose Register",
        "nand": "Nand",
        "nop": "No Operation (Execute)",
        "nor": "Nor",
        "or": "Or",
        "orbi": "Or Byte Immediate",
        "orc": "Or with Complement",
        "orhi": "Or Halfword Immediate",
        "ori": "Or Word Immediate",
        "orx": "Or Across",
        "rchcnt": "Read Channel Count",
        "rdch": "Read Channel",
        "rot": "Rotate Word",
        "roth": "Rotate Halfword",
        "rothi": "Rotate Halfword Immediate",
        "rothm": "Rotate and Mask Halfword",
        "rothmi": "Rotate and Mask Halfword Immediate",
        "roti": "Rotate Word Immediate",
        "rotm": "Rotate and Mask Word",
        "rotma": "Rotate and Mask Algebraic Word",
        "rotmah": "Rotate and Mask Algebraic Halfword",
        "rotmahi": "Rotate and Mask Algebraic Halfword Immediate",
        "rotmai": "Rotate and Mask Algebraic Word Immediate",
        "rotmi": "Rotate and Mask Word Immediate",
        "rotqbi": "Rotate Quadword by Bits",
        "rotqbii": "Rotate Quadword by Bits Immediate",
        "rotqby": "Rotate Quadword by Bytes",
        "rotqbybi": "Rotate Quadword by Bytes from Bit Shift Count",
        "rotqbyi": "Rotate Quadword by Bytes Immediate",
        "rotqmbi": "Rotate and Mask Quadword by Bits",
        "rotqmbii": "Rotate and Mask Quadword by Bits Immediate",
        "rotqmby": "Rotate and Mask Quadword by Bytes",
        "rotqmbybi": "Rotate and Mask Quadword Bytes from Bit Shift Count",
        "rotqmbyi": "Rotate and Mask Quadword by Bytes Immediate",
        "selb": "Select Bits",
        "sf": "Subtract from Word",
        "sfh": "Subtract from Halfword",
        "sfhi": "Subtract from Halfword Immediate",
        "sfi": "Subtract from Word Immediate",
        "sfx": "Subtract from Extended",
        "shl": "Shift Left Word",
        "shlh": "Shift Left Halfword",
        "shlhi": "Shift Left Halfword Immediate",
        "shli": "Shift Left Word Immediate",
        "shlqbi": "Shift Left Quadword by Bits",
        "shlqbii": "Shift Left Quadword by Bits Immediate",
        "shlqby": "Shift Left Quadword by Bytes",
        "shlqbybi": "Shift Left Quadword by Bytes from Bit Shift Count",
        "shlqbyi": "Shift Left Quadword by Bytes Immediate",
        "shufb": "Shuffle Bytes",
        "stop": "Stop and Signal",
        "stopd": "Stop and Signal with Dependencies",
        "stqa": "Store Quadword (a-form)",
        "stqd": "Store Quadword (d-form)",
        "stqr": "Store Quadword Instruction Relative (a-form)",
        "stqx": "Store Quadword (x-form)",
        "sumb": "Sum Bytes into Halfwords",
        "sync": "Synchronize",
        "wrch": "Write Channel",
        "xor": "Exclusive Or",
        "xorbi": "Exclusive Or Byte Immediate",
        "xorhi": "Exclusive Or Halfword Immediate",
        "xori": "Exclusive Or Word Immediate",
        "xsbh": "Extend Sign Byte to Halfword",
        "xshw": "Extend Sign Halfword to Word",
        "xswd": "Extend Sign Word to Doubleword",
    }

# ----------------------------------------------------------------------
def PROCESSOR_ENTRY():
    return spu_processor_t()